开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜