binding member functions

Discussion in 'Javascript' started by Jens Thiele, Apr 13, 2004.

  1. Jens Thiele

    Jens Thiele Guest

    i want to bind a member function
    i hope this example will explain what i want to do
    (it seems my solution works - but is there a better way?)

    // first a simple function variable example
    function foo(){
    print("foo");
    }
    // prints foo and foo
    function simpleTest(){
    foo();
    var x=foo;
    x();
    }
    simpleTest();

    // now i want to bind a member function to a function variable
    // this will not work:
    // x=foo.bar; (since "this" will be wrong)

    function Foo(bar){
    this.b=bar;
    }
    Foo.prototype.bar=function()
    {
    print (this.b);
    }

    function test() {
    var foo=new Foo("bar");
    foo.bar(); // print bar

    // bind method - is there a simpler way ????
    var x=function(y){var z=y;return function(){z.bar();}}(foo);

    x(); // print bar
    }

    test();
    Jens Thiele, Apr 13, 2004
    #1
    1. Advertising

  2. Jens Thiele wrote:

    > i want to bind a member function
    > i hope this example will explain what i want to do
    > (it seems my solution works - but is there a better way?)
    >
    > // first a simple function variable example
    > function foo(){
    > print("foo");
    > }
    > // prints foo and foo
    > function simpleTest(){
    > foo();
    > var x=foo;
    > x();
    > }
    > simpleTest();
    >
    > // now i want to bind a member function to a function variable
    > // this will not work:
    > // x=foo.bar; (since "this" will be wrong)
    >
    > function Foo(bar){
    > this.b=bar;
    > }
    > Foo.prototype.bar=function()
    > {
    > print (this.b);
    > }
    >
    > function test() {
    > var foo=new Foo("bar");
    > foo.bar(); // print bar
    >
    > // bind method - is there a simpler way ????
    > var x=function(y){var z=y;return function(){z.bar();}}(foo);
    >
    > x(); // print bar
    > }
    >
    > test();


    function bind(o, f) {
    if (!isFunction(f)) {
    f = o[f];
    }
    return isFunction(f) ? function () {
    return f.apply(o, arguments);
    } : null;
    }

    var x = bind(foo, 'bar');

    http://www.crockford.com/javascript/remedial.html
    Douglas Crockford, Apr 13, 2004
    #2
    1. Advertising

  3. Jens Thiele wrote:
    <snip>

    So what you want to do is call a function as a method of a particular
    object instance, using a reference to a function.

    > function test() {
    > var foo=new Foo("bar");
    > foo.bar(); // print bar
    >
    > // bind method - is there a simpler way ????
    > var x=function(y){var z=y;return function(){z.bar();}}(foo);

    <snip>

    That is the pattern that works, but could be simpler as function
    parameters act much like local variables (they both exist as named
    properties of the Activation/Variable object belonging to the execution
    context of their containing function call). So the code could be
    simplified to:-

    var x=function(y){return function(){y.bar();}}(foo);

    Or made in to a general external function with a consequent reduction in
    the number of function objects that need to be created during the
    process. For example:-

    function associateObjWithEvent(obj, methodName){
    return (function(e){
    e = e||window.event;
    return obj[methodName](e, this);
    });
    }

    - is a version I use for associating objects with DOM element event
    handlers. It might be called in your context as:-

    var x = associateObjWithEvent(foo, 'bar');

    Though it was designed to have the returned function assigned to an
    event handling property, so normal use would be:-

    elRef.onclick = associateObjWithEvent(foo, 'bar');

    - but you don't seem to want the parameter handling in the method call,
    or the flexibility in method names used. So maybe:-

    function associateObjWithBarCall(obj){
    return (function(){
    obj.bar();
    });
    }

    - used as:-

    var x = associateObjWithBarCall(foo);

    Richard.
    Richard Cornford, Apr 13, 2004
    #3
  4. Jens Thiele

    Jens Thiele Guest

    > That is the pattern that works, but could be simpler as function
    > parameters act much like local variables (they both exist as named
    > properties of the Activation/Variable object belonging to the execution
    > context of their containing function call). So the code could be
    > simplified to:-
    >
    > var x=function(y){return function(){y.bar();}}(foo);


    Ah!
    I still have many misconceptions about the language it seems.
    It is indeed quite similar to scheme. But now I do not understand why
    the following happens.

    x=function(text){return function(){print(text);};}("hello world");
    x(); // will print hello world as expected
    foo={x:1,y:2}
    foo.watch("x",x);
    foo.x=10; // will print undefined and not hello world

    i don't quite understand this
    it seems in the second case the context is different

    i tried the following:
    x=function(text){return
    function(){print("this:"+this);print("this.foomem:"+this.y);print("text:"+text);};}("hello
    world");
    x();
    foo={x:1,foomem:2}
    foo.watch("x",x);
    foo.x=10;

    output:
    this:[object global]
    this.foomem:undefined
    text:hello world
    this:[object Object]
    this.foomem:undefined
    text:undefined

    => the first time this is the global object the second time it is foo
    does it matter?
    text is not in the global object

    I get something wrong here
    any help?
    Jens Thiele, Apr 14, 2004
    #4
  5. Jens Thiele wrote:
    <snip>
    > ... . But now I do not understand why
    > the following happens.
    >
    > x=function(text){return function(){print(text);};}("hello world");
    > x(); // will print hello world as expected
    > foo={x:1,y:2}
    > foo.watch("x",x);


    You have stumbled into a grey area here, the - watch - method of objects
    did not make it into ECMA 262 and so does not have a public formal
    specification. So exactly how it will behave where implemented is
    uncertain.

    My copy of the Netscape JavaScript 1.4 documentation says that -
    obj.watch('propName', handler) - will call the - handler - when an
    assignment is made to the property of - obj - with the specified name.
    Calling it as - handler('propName' oldval, newval) and assigning the
    function's return value to the property of - obj.

    If the handler is an inner function then it should still have the
    Activation/Variable object of its outer function's execution context in
    its scope chain when it is called.

    > foo.x=10; // will print undefined and not hello world
    >
    > i don't quite understand this
    > it seems in the second case the context is different
    >
    > i tried the following:
    > x=function(text){return
    > function(){print("this:"+this);print("this.foomem:"+this.y);
    > print("text:"+text);};}("hello world");
    > x();
    > foo={x:1,foomem:2}
    > foo.watch("x",x);
    > foo.x=10;
    >
    > output:
    > this:[object global]


    So which javascript implementation are you using? I don''t recall the
    toString method of a global object ever returning that particular string
    (not that I look at that string value often).

    > this.foomem:undefined
    > text:hello world


    That all conforms to my expetations.

    > this:[object Object]


    But this is interesting, for the - this - keyword to refer to an object
    the handler must have been called as a method of that object, and the
    Netscape JavaScript 1.4 documentation does not mention that at all, the
    expectation would be that - this - remained a reference to the global
    object.

    > this.foomem:undefined


    However, the object that is being referred to by - this - is not the
    object on which the - watch - method was called, else - this.foomem -
    would not be undefined.

    > text:undefined


    By ECMA specification the only way that the - text - property of the
    Activation/Variable object from the execution context of the outer
    function, on the scope chain of the inner function, could be returning -
    undefined - in the inner function is if an object higher in the scope
    chain for the inner function's execution context had a defined property
    named - text - that had an undefined value, masking the original -
    text - parameter property.

    It is not impossible for an implementation to add objects to the scope
    chain of a function call, it is even common with event handling
    functions generated from HTML attribute strings, but there doesn't seem
    to be any reason for doing so in the context of - watch.

    On the other hand, without a formal specification for - watch - it is
    impossible to say what it should be doing when executing - handler -, it
    could call - handler - as a method of some arbitrary object, and add any
    number of unknown objects to the scope chain for the function call. And
    nobody could say it was wrong for doing so.

    > => the first time this is the global object the second time it is foo


    It is not - foo - else - this.foomem - would return the value 2 rather
    than undefined.

    > does it matter?
    > text is not in the global object
    >
    > I get something wrong here


    You may be wrong to have expectation of methods outside of the ECMA
    specification, though the behaviour of the implementation you are using
    is certainly unexpected.

    > any help?


    There can be no help without knowing what you are trying to achieve.

    Richard.
    Richard Cornford, Apr 15, 2004
    #5
  6. Jens Thiele

    Jens Thiele Guest

    Richard Cornford wrote:
    > You have stumbled into a grey area here, the - watch - method of objects
    > did not make it into ECMA 262 and so does not have a public formal
    > specification. So exactly how it will behave where implemented is
    > uncertain.


    it should get into ECMA - it is really useful ;-)

    > My copy of the Netscape JavaScript 1.4 documentation says that -
    > obj.watch('propName', handler) - will call the - handler - when an
    > assignment is made to the property of - obj - with the specified name.
    > Calling it as - handler('propName' oldval, newval) and assigning the
    > function's return value to the property of - obj.
    >
    > If the handler is an inner function then it should still have the
    > Activation/Variable object of its outer function's execution context in
    > its scope chain when it is called.


    yes this was my problem
    with the example below I tried to understand why it does not work.
    I am using spidermonkey - and this was a bug which is now fixed
    (thanks to brendan)
    see also:
    <>
    and
    http://bugzilla.mozilla.org/show_bug.cgi?id=240577

    >>foo.x=10; // will print undefined and not hello world
    >>
    >>i don't quite understand this
    >>it seems in the second case the context is different
    >>
    >>i tried the following:
    >>x=function(text){return
    >>function(){print("this:"+this);print("this.foomem:"+this.y);


    i had a bug here ^
    this should be this.fooomem and not this.y
    sorry for this one

    > So which javascript implementation are you using? I don''t recall the
    > toString method of a global object ever returning that particular string
    > (not that I look at that string value often).


    I am using spidermonkey and embedding it.

    >>this.foomem:undefined
    >>text:hello world

    >
    >
    > That all conforms to my expetations.


    yep to mine, too


    >>this:[object Object]

    >
    >
    > But this is interesting, for the - this - keyword to refer to an object
    > the handler must have been called as a method of that object, and the
    > Netscape JavaScript 1.4 documentation does not mention that at all, the
    > expectation would be that - this - remained a reference to the global
    > object.
    >
    >
    >>this.foomem:undefined

    >
    >
    > However, the object that is being referred to by - this - is not the
    > object on which the - watch - method was called, else - this.foomem -
    > would not be undefined.


    this was my mistake see above (i do print this.y instead of this.foomem)
    - sorry again


    >>I get something wrong here

    >
    >
    > You may be wrong to have expectation of methods outside of the ECMA
    > specification, though the behaviour of the implementation you are using
    > is certainly unexpected.


    okay with the patch to spidermonkey, everthing works like expected
    for the record (the script without my bug and the output of a fixed
    spidermonkey version):

    // first test
    print ("First test output");
    x=function(text){return function(){print(text);};}("hello world");
    x(); // will print hello world as expected
    foo={x:1,y:2}
    foo.watch("x",x);
    foo.x=10; // now will print hello world

    // second test
    print ("Second test output");
    x=function(text){
    return function(){
    print("this:"+this);
    print("this.foomem:"+this.foomem);
    print("text:"+text);
    };
    }("hello world");
    x();
    foo={x:1,foomem:2}
    foo.watch("x",x);
    foo.x=10;

    First test output
    hello world
    hello world
    Second test output
    this:[object global]
    this.foomem:undefined
    text:hello world
    this:[object Object]
    this.foomem:2
    text:hello world

    thanks
    i am really happy now
    (it works, and more important to me, my expectations were reasonable,
    I thought that I still did not understand some basic language concept)
    Jens Thiele, Apr 15, 2004
    #6
    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. Jordan
    Replies:
    2
    Views:
    2,519
    Jordan
    Feb 10, 2004
  2. Vinay
    Replies:
    4
    Views:
    1,896
    Andrey Tarasevich
    Jul 2, 2004
  3. christopher diggins
    Replies:
    1
    Views:
    383
    Rapscallion
    May 23, 2005
  4. Hicham Mouline
    Replies:
    0
    Views:
    423
    Hicham Mouline
    Apr 23, 2009
  5. Hicham Mouline
    Replies:
    1
    Views:
    405
    Michael DOUBEZ
    Apr 24, 2009
Loading...

Share This Page