By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,963 Members | 1,033 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,963 IT Pros & Developers. It's quick & easy.

acces object vars form event handler (how?)

P: n/a
Hi

I don't understand why it's not working:

function schedule(imTop){
this.tdImagesTop = imTop;
}

schedule.prototype.selectEl = function() {
alert(this.tdImagesTop);
}

sched = new schedule(tdImagesTop);

//Attaching event to contDiv where sched.selectEl is a event handler function

EventUI.addEventHandler(document.getElementById('c ontDiv'), 'mousedown', sched.selectEl);
Now when I click on the contDiv I get alert that this.tdImagesTop is undefined. But when I call
function directly:

sched.selectEl();

Everything is OK. It's showing me the table I have initialized object with.

Why it's like this? How can I repair it?

Thank you
--
Ralph
Jan 14 '07 #1
Share this Question
Share on Google+
2 Replies


P: n/a
Ralph wrote:
I don't understand why it's not working:
When you have code that is "working" do you then understand why it is
"working" ('working' being a subjective assessment as this code most
certainly is doing what it was programmed to do)? That is, could you
explain what the code is doing to someone else?
function schedule(imTop){
this.tdImagesTop = imTop;
}

schedule.prototype.selectEl = function() {
alert(this.tdImagesTop);
}

sched = new schedule(tdImagesTop);

//Attaching event to contDiv where sched.selectEl is a
event handler function

EventUI.addEventHandler(document.getElementById('c ontDiv'),
'mousedown', sched.selectEl);
Now when I click on the contDiv I get alert that
this.tdImagesTop is undefined. But when I call function
directly:

sched.selectEl();

Everything is OK. It's showing me the table I have
initialized object with.

Why it's like this?
The mechanism that javascript uses to determine which value is to be
used as the - this - value is based entirely upon how a function is
called. This differs from what may be expected by those who's experience
comes from other languages (such as, for example, Java, where a method
knows its relationship with the instances of the class in which it is
defined), and it follows from the fact that in javascript functions are
objects that have individual identity.

It is not practical for an object to keep track of which objects have
properties that refer to it, and in javascript your - sched.selectEl -
is a reference to function object held in a 'selectEl' property of an
object referred to by - sched -. The function object has no idea that it
is referred to by a property of - schedule - instance referred to by -
sched -, in the same way as it has no idea that it is referred to by the
'selectEl' property of - schedule.prototype -. And as a result there is
no way that when the function object is called could know which of -
sched -, - schedule.prototype -, or any other instance of - schedule -,
would be the object instance that may be associated with the - this -
keyword for that call.

The rules for the assignment of a value to the - this - keyword are
applied at the point of calling the function object, based upon how it
is called. The language specification (ECMA 262, 3rd Ed.) employees an
internal "Reference" type to define the required behaviour. The
"Reference" type is an internal, and intermediate, object that is used
explain the behaviour of javascript and a Reference type object has a
'base' property which is a reference to an object (or null) and a
'propertyName' property which is a string.

Two constructs in javascript evaluate into a Reference type; an
Identifier and a property accessor.

An expression consisting of an Identifier is evaluated 'against the
scope chain', by examining first the object at the top of the scope
chain to see if it has a property with a name that corresponds with the
Identifier (that is, that the name of the property consists of the same
sequence of characters as make up the Identifier) (this text effectively
encompasses the prototypes of objects on the scope chain). If that first
object does not have such a property then the same test is applied to
the next object in the scope chain, and so on until an object is
discovered on the chain that does have a property with the corresponding
name, or the scope chain is exhausted. If an object on the scope chain
is found with a property of the corresponding name then the Identifier
evaluates as a Reference type with its 'base' property set to a
reference to that object and its 'propertyName' property set to a string
that corresponds with the Identifier. If no object was found then the
resulting Reference type has its 'base' property set to null (but still
has the Identifier's string equivalent assigned to its 'propertyName'
property).

This intermediate type makes sense when you consider that an Identifier
may be used as the source of a value or as the destination to which a
value will be assigned. When reading the 'value' of an identifier the
value is read from the property named by 'propertyName' of the object
referred to by the 'base' property of the Reference type (and a runtime
error results from a null 'base' property). When writing the value is
set on the property named by 'propertyName' of the object referred to by
the 'base' property of the Reference type (but in the case of writing a
value a null 'base' property is substituted with the global object, thus
assigning a value to an Identifier cannot produce a runtime error).

An expression consisting of a property accessor (either dot notation or
bracket notation) is evaluated in stages. First everything to the left
of the dot, or opening square bracket, is evaluated into a value. For
example, as simple dot notation property accessor such as:-

sched.selectEl

- must first evaluate the Identifier - sched - and, as an Identifier,
the result is itself a Reference type, with the global object as its
'base' property and the string "selectEl" as its 'propertyName'
property. However, a property accessor operates upon an object so this
intermediate reference type is subject to the internal - GetValue -
function, which returns the value of the property named by
'propertyName' of the object referred to by the 'base' property of the
Reference type (in this case a reference to your instance of -
schedule -). The next step is to use the internal - ToObject - function
on the value returned by - GetValue -. This would imply automatic
type-conversion if the value was a primitive (non-object) type (and a
runtime error if the type had been of the Null or Undefined primitive
types, as they cannot be type-converted into objects). As the - sched -
Identifier was referring to an object instance no such type-conversion
is necessary. The Property accessor expression can now evaluate into its
Reference type, as the object resulting form the - ToObject - call
becomes the 'base' property of the Reference type, and the
'propertyName' property is assigned the string value "selectEl" (note
that at this stage it does not matter whether the - sched - object has a
property named "selectEl", or what value that property may have if it
does exist).

While Identifiers and property accessors always evaluate into Reference
types the only other expression in javascript that may evaluate into a
reference type is an Identifier or property accessor _directly_ wrapped
in parentheses, that is:-

(sched.selectEl)

- should evaluate into exactly the same Reference type as:-

sched.selectEl

All other expressions do not result in Reference types, they results in
direct values (which are references to object in the case of 'the values
of' objects (including function objects)).

Getting back to function calls and the - this - keyword:

If the expression to the left of the 'call operator' (the set of
parentheses that may (optionally) contain the arguments list for the
function call) evaluates as a Reference type (as opposed to the value of
a function object (which is a reference to the function object)) then it
is possible that the - this - keyword will be assigned a value that is a
reference to the object referred to by the 'base' property of the
Reference type, is a set of conditions is met:-

1. The 'base' property is not null.
2. The object referred to by the 'base' property
is not an "Activation" object (see ECMA 262,
3rd Ed. Section 10.1.6 for details of
"Activation" objects).

If these conditions are not met for a Reference type, or the expression
to the left of 'call operator' did not evaluate as a Reference type,
then the - this - value for the function call is set to (defaulted to) a
reference to the global object. (Note that because the - this - value is
defaulted to the global object whenever it cannot be set to any other
object there are no circumstances in javascript where the - this - value
does not refer to _an_ object.)

So, returning to your specific question; when you call:-

sched.selectEl();

- the code inside the function body successfully references -
this.tdImagesTop - as the property of your - schedule - insistence
because the property accessor - sched.selectEl - evaluated as a
Reference type that has the - sched - object instance as its 'base'
property. Thus the - this - value referred to the desired object
instance.

However, -

EventUI.addEventHandler(
document.getElementById('contDiv'),
'mousedown',
sched.selectEl
);

- is much more problematic. Although the - sched.selectEl - in the
arguments list to the - addEventHandler - function call is a property
accessor, and so does evaluate as a Reference type, the evaluation of an
Arguments list requires the application of the internal - GetValue -
function to each argument expression. Thus the Reference type that -
sched.selectEl - evaluated to is used to retrieve the actual value of
the - selectEl - property of the - sched - object. That value is just a
reference to a function object, and that function object has no
knowledge of its having been referred to by "selectEl" properties of
object, or which objects they may have been.

The next problem is you don't show how that function object is going to
be called, so I cannot tell you what value the - this - keyword will
refer to in that context. It is likely that the function object is
either doing to be assigned as an 'intrinsic event' handling property of
the DOM Element passed as the fist argument to - addEventHandler -, or
used with the DOM standard - addEventListener -, or Microsoft DOM -
AttachEvent - methods of the Element. Which of these, or some indirect
alternative, will define what the - this - value for the function call
actually will be, though it is certain that it cannot be the - sched -
object as all associations with that object were lost when the arguments
list was evaluated.
How can I repair it?
As the code is doing precisely what you programmed it to do there is
little sense in talking of '"repair", as nothing is broken.

If you mean 'how can I associate an object instance with the execution
of a function object (possibly independently of how that function is
called, and so independently of the - this - value)?" then there are
three answers:-

1. Create a unique global reference to each object instance and then
create separate function objects that use that global reference. This
technique is most applicable when the function objects are created with
stirrings defining their function bodies (so most applicable if you were
using - document.wirte - to write out HTML that included event handling
attributes that you wanted to refer to particular object instances). The
particular scheme goes something like:-

function AnObject(){
this.index = AnObject.insts.length;
AnObject.insts[this.index] = this; // Assign a reference to this
// object instance to a globally
// accessible location.
this.forEvents = new Function(
'e',
'AnObject.insts['+this.index+'].someMethod(e);'
); // Create a function object that calls a method
// of the object instance through the globally
// accessible reference to it.
}
AnObject.insts = [];
AnObject.prototype.someMethod = function(e){
... // function body.
};

2. Assign a reference to the individual object instance to another
object that the execution of the function will be associated with. That
is, if you knew that the function would be called as an intrinsic event
handler (where the browser calls the function as a method of the DOM
Element, and the - this - value is then set to a reference to the DOM
element) you could assign a reference to the object instance to a
property of the DOM Element and have the event handler call a method of
the object instance through the property of the DOM element. In this
case you would be relying upon the - this - reference referring to an
object in particular (the DOM element) when the function is called.

3. Employ a closure to keep a reference to an individual object instance
on the scope chain of a unique function object. See:-

<URL: http://jibbering.com/faq/faq_notes/closures.html >

(And observe the section on IE memory leaks on that page, as all three
of these techniques can form the type of circular references that may
result in memory leaks (though none of them need to)).

Richard.
Jan 14 '07 #2

P: n/a
Richard Cornford wrote:

[cut]

Thank you for this very in deep explanation. Of course you are right the code I have presented was
not broken it was doing exactly what it suppose to do :)

Thank you again.
--

Ralph
Jan 14 '07 #3

This discussion thread is closed

Replies have been disabled for this discussion.