Ian Bicking: the old part of his blog

Re: Prototype.js and Object.prototype

The answer you're looking for is that foo.bar() is special syntax in JavaScript. Run the following in a browser:

foo = {
    'bar': function () {
        alert(this);
    },
    'toString': function () {
        return 'foo';
    }
};
foo.bar();
(foo.bar)();
(foo.bar || null)();
bar = foo.bar; bar();

The first call, foo.bar() is the "call with this" syntax, so you should get an alert with "foo".

The second call, (foo.bar)() is technically "just call" syntax, but some JavaScript interpreters will interpret it as the same AST as the first one. For example, Safari will still say "foo" here, but Firefox will say "[object Window]".

The third call is unambiguously "just call" syntax, so you will get "[object Window]" here. I suppose if Safari gets any smarter, it might give the wrong answer here someday ;)

And the fourth is really really unambiguous "just call" syntax, so you will get "[object Window]" here as well.

Comment on Prototype.js and Object.prototype
by Bob Ippolito

Comments:

That's what I was figuring, even if it's very hard for me to parse all of obj.func() at once, without thinking about any intermediate expressions. A bit of unlearning to be done.

But it still doesn't really explain why the final version of extend works... what's different about this[property] = object[property] from ob1[property] = ob2[property]? The only reason I thought to do that is that it mimicked the original Object.prototype.extend method.

# Ian Bicking

There shouldn't be any difference at all unless you pass null or undefined as ob1. They seem to do the same thing here, you didn't give enough information to reproduce any difference in behavior.

# Bob Ippolito

applay() not only simply replace 'this' with the assigned object,it also provides the executing enviroment for the function which is applied.

var obj1={
value:1,
foo:function(){
alert(this.value);

System Message: WARNING/2 (<string>, line 7)

Definition list ends without a blank line; unexpected unindent.

}

System Message: WARNING/2 (<string>, line 8)

Definition list ends without a blank line; unexpected unindent.

}

var obj2={

value:2, setFoo:function(foo){

System Message: ERROR/3 (<string>, line 13)

Unexpected indentation.
this.foo = foo;

System Message: WARNING/2 (<string>, line 14)

Block quote ends without a blank line; unexpected unindent.

}

System Message: WARNING/2 (<string>, line 15)

Definition list ends without a blank line; unexpected unindent.

}

setFoo(foo){
this.foo = foo;

System Message: WARNING/2 (<string>, line 19)

Definition list ends without a blank line; unexpected unindent.

}

setFoo.apply(obj2,[obj1.foo]) in fact equals obj2.setFoo(obj1.foo)

obj2.setFoo(obj1.foo) means setFoo will be evaluated in the obj2 scope while the expression obj1.foo = obj2.foo will be evaluted in global scope.

# wl_tony