JavaScript: lexical closure or something else?
Consider this script:
function Obj(prop) {
this.prop = prop;
}
var NS = {
strings: ['first','second','third'],
objs: [],
f1: function() {
for (s in this.strings) {
var obj = new Obj(this.strings[s]);
obj.f2 = function() {
alert(obj.prop);
}
this.objs.push(obj);
}
}
}
NS.f1();
NS.objs[0].f2(); // third
NS.objs[1].f2(); // third
NS.o开发者_开发百科bjs[2].f2(); // third
Not exactly the expected output, however when I update to this:
function Obj(prop) {
this.prop = prop;
}
var NS = {
strings: ['first','second','third'],
objs: [],
f1: function() {
for (s in this.strings) {
var obj = new Obj(this.strings[s]);
this.wire(obj); // replaces previous function def
this.objs.push(obj);
}
},
wire: function(obj) {
obj.f2 = function() {
alert(obj.prop);
} // exact same code and function def as the first example
}
}
NS.f1();
NS.objs[0].f2(); // first
NS.objs[1].f2(); // second
NS.objs[2].f2(); // third
This seems to work, and I've no idea why. Can anybody enlighten me? Thanks
Check out http://jibbering.com/faq/notes/closures/.
It will explain the "something else" and probably all you'll ever want to know about how JavaScript variables and scopes work. JavaScript uses "execution context" closures, not "lexical variable" closures (edit: it is still a lexical binding, just not necessarily as expected -- see below).
In the first example, the same obj
was bound three times or rather, the same obj
property (edit: the specification doesn't require this, but calling it a property is one way to explain it) of the single bound execution context is shared!
var
does not "declare" a variable (edit: it is an annotation that applies to an entire scope and is not affected by {}'s, excepting the following) and function
is how one can introduce new scopes -> new execution contexts (which is why the 2nd example works as expected). New scopes are only introduced with function
(or eval
/similar).
Happy coding.
f1
...only has a single obj in a single closure which is assigned 3 times
f2
...has ultimately 3 objs in three closures (plus the one that f1 also has) which are each assigned once
One funny thing about JS that may help: the following two functions do the same thing:
function a1() {
var a,b,c;
a = 1;
b = 2;
c = 3;
}
function a2() {
a = 1;
b = 2;
c = 3;
var a,b,c;
}
The var
declaration always operates at function-level scope regardless of where in the function or how deeply nested it is in inner blocks.
精彩评论