Capture `this`!
JavaScript woes:
function C() {
var _this = this;
this.foo = function () {
return _this === this;
};
this.bar = function () {
return this.foo;
};
return this;
}
var c = new C();
What is the value of c.foo()
? What is the value of c.bar()()
? Both are true
. But let:
var foo = c.bar();
What is the value of foo()
?
If you thought it was true
, you're wrong. This doesn't make much sense at all. Either this
is captured by a dot, or it isn't. Looking at the inner call to c.bar
, it's syntactically obvious that the call to bar
has this = c
. But why is that preserved when evaluating it within an outer expression, but not when we split the expression into two statements?
I'm sure this has been seen before, but I'll probably show it to Dave Herman anyway. If I remember correctly, Python gets this right. Between this and a prototype aliasing bug I had yesterday, I'm irritated.
As an aside, I was speaking with Arjun Guha last night, and none of the conventional type theory would have helped me with these problems. In fact, I get almost no type errors in JavaScript -- only grotesque object model problems.
Dan Stowell (dstowell@gmail.com)
OpenLaszlo gets this wronger (but perhaps more consistently):c.foo() true c.bar()() false foo() false
Michael Greenberg (mike@weaselhat.com)
Are you sure you're running in the latest Firefox? Dave Herman said that it's an EC4 feature; it might only be in the latest versions of Spidermonkey.Dan Stowell (dstowell@gmail.com)
I compiled your test code to ActionScript with the OpenLaszlo compiler - the results are actually from Flash 8, though I'll have to track down the code our compiler emits to see whose fault it is.Dan Stowell (dstowell@gmail.com)
The OL compiler doesn't touch that bit of script, so the results I gave in the first comment are how ActionScript behaves. So c.bar() returns a function closed over a different \`this\`?Dave Herman (dherman@ccs.neu.edu)
I'm looking at this again and I'm confused now. What is the problem with this example? All three major browsers agree on the behavior.The binding of `this' in JS is determined by the syntax of the function call. When you said `c.bar()' you invoked `bar' as a method of `c', so it bound `this' to `c' for the evaluation of the body of `bar'. But when you then called `foo' as a naked function, it bound `this' to the global object.
That's the stated, specified behavior of JavaScript. Are you claiming there's an inconsistency between browsers/implementations of JS, or just that the specified behavior is weird? (If it's the latter, you'll get no disagreement from me.)
Dave Herman (dherman@ccs.neu.edu)
D'oh! I missed the part where they disagree: \`foo.bar()()'. Sorry I posted too soon before I read more carefully.I still need to double-check where this divergence in behavior comes from.
Dave Herman (dherman@ccs.neu.edu)
I think I found it. Look athttp://developer.mozilla.org/es4/proposals/bug_fixes.html
and search for "[THIS.PROPAGATES]".
Dave Herman (dherman@ccs.neu.edu)
Okay, it turns out I was wrong and this has nothing to do with the new behavior of \`this' in ES4 -- Mozilla has not implemented that yet.Brendan Eich informs me that it's a bug that's been fixed in alpha versions of Firefox/SpiderMonkey:
" changed behavior from Firefox 2 (the mozilla 1.8 branch) to Minefield (alpha Firefox 3, the 1.9 cvs trunk). My trunk js shell gives false, my 1.8 branch shell gives true in agreement with Firefox 2.0.0.x.
This looks like a bug fix due to Igor's work in https://bugzilla.mozilla.org/show_bug.cgi?id=363530."
He's referring to `c.bar()()' returning true or false, BTW. It should return `false'.
Michael Greenberg (mike@weaselhat.com)
Ah. That's a relief that it's a bug. I think the behavior itself is weird, and that dotting should either always or never capture this.Thanks for looking back into this!