acces object vars form event handler (how?)

Discussion in 'Javascript' started by Ralph, Jan 13, 2007.

  1. Ralph

    Ralph Guest

    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('contDiv'), '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
    Ralph, Jan 13, 2007
    #1
    1. Advertising

  2. 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('contDiv'),
    > '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.
    Richard Cornford, Jan 14, 2007
    #2
    1. Advertising

  3. Ralph

    Ralph Guest

    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
    Ralph, Jan 14, 2007
    #3
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Jon

    app vars and cache vars

    Jon, Dec 14, 2004, in forum: ASP .Net
    Replies:
    3
    Views:
    381
  2. Replies:
    1
    Views:
    686
    Damien
    Feb 22, 2007
  3. Rahul
    Replies:
    2
    Views:
    531
    James Kanze
    Jul 18, 2008
  4. Linuxguy123
    Replies:
    7
    Views:
    670
    Paddy O'Loughlin
    Feb 20, 2009
  5. caccolangrifata
    Replies:
    18
    Views:
    385
    Chris Torek
    Jul 22, 2011
Loading...

Share This Page