Javascript Closures with与返回的函数不兼容

时间:2015-07-24 09:50:05

标签: javascript closures this

我读了How do JavaScript closures work?个问题,并认为我终于理解了封闭。

特别是现在这一点非常混乱:

  

示例7

     

这个最后的例子表明每次调用都会为局部变量创建一个单独的闭包。每个函数声明没有一个闭包。每次调用函数都有一个闭包。   ..........................................

好的,所以示例7显示了这个例子:

function newClosure(someNum, someRef) {
    // Local variables that end up within closure
    var num = someNum;
    var anArray = [1,2,3];
    var ref = someRef;
    return function(x) {
        num += x;
        anArray.push(num);
        document.write('num: ' + num +
            '; anArray: ' + anArray.toString() +
            '; ref.someVar: ' + ref.someVar + "<br>");
      }
}
obj = {someVar: 4};
fn1 = newClosure(4, obj);
fn2 = newClosure(5, obj);
fn1(1); // num: 5; anArray: 1,2,3,5; ref.someVar: 4;
fn2(1); // num: 6; anArray: 1,2,3,6; ref.someVar: 4;
obj.someVar++;
fn1(2); // num: 7; anArray: 1,2,3,5,7; ref.someVar: 5;
fn2(2); // num: 8; anArray: 1,2,3,6,8; ref.someVar: 5;

此示例适用于我。

所以我经历了一点,我真的不明白为什么这段代码不起作用(看起来它甚至没有在函数调用上创建一个新的闭包)

function createCounter(startValue){

    var localCounter;

    this.setCounter = function(firstValue) {
       localCounter = firstValue; 
    }

    this.getValue = function(){return localCounter;};
    this.increment = function(){localCounter++;};
    this.setCounter(startValue);

    return this;
}

var Counter1 = createCounter(1);
document.write(Counter1.getValue()); //1
Counter1.increment();
var Counter1Value = Counter1.getValue(); // 2
var Counter0 =  createCounter(0); //works as it should if i put a "new createCounter(0) here, but why?
document.write("<br >Counter 1 oldValue:" + Counter1Value); //2
document.write("<br >Counter 1 currentValue:" + Counter1.getValue()); //0 (why is the localvariable overwritten?)
document.write("<br >Counter 0 currentValue:" + Counter0.getValue()); // //0

为什么我需要添加“new”关键字来创建第二个闭包,为什么Counter1和Counter0都使用相同的localCounter变量?

1 个答案:

答案 0 :(得分:0)

正如elclanrs所说,这完全是this

当您致电createCounter(1)时,this不变,很可能仍然是全球范围。给定document.write,可以肯定地说全局范围是window。因此,您创建window.setCounter作为一个函数,将localCounter(隐藏在闭包中的变量)和window.getValue设置为读取此隐藏变量的函数;它会将localCounter初始化为1;然后返回window并将其分配给Counter1

然后,Counter1.getValue()调用window.getValue(),返回1。都好。与increment相同。

但是,由于您始终在全局上下文中操作,因此当您执行createCounter(0)时,覆盖 window.getValue(和其他函数)与闭包现在引用不同的隐藏localCounter,此初始化为0。由于Counter0Counter1都指向相同的对象(即window),因此Counter1.getValue()和{{1}并不太牵强也应该返回相同的东西(假设它们都没有副作用)。

这会在Counter0.getValue()关键字中发生巨大变化,这是JavaScript改变new内容的几种方法之一。如果您执行thisvar Counter1 = new createCounter(1),则函数内的var Counter0 = new createCounter(0)在两种情况下都是新对象; this上的Counter1Counter0有不同的闭包。

具体来说,new createCounter(0)将执行类似此伪代码的操作:

var oldThis = this;  // save current context
this = {};           // make a new object
createCounter(0);    // initialize the new object
this = oldThis;      // restore current context

所以你可以看到为什么值保持不同。