![]() |
acces object vars form event handler (how?)
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 |
Re: acces object vars form event handler (how?)
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. |
Re: acces object vars form event handler (how?)
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 |
| All times are GMT. The time now is 08:38 AM. |
Powered by vBulletin®. Copyright ©2000 - 2013, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.