Javascript 闭包不适用于返回的函数

Javascript Closures with doesn't work with returned function

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

特别是这一点现在很迷惑:

Example 7

This final example shows that each call creates a separate closure for the local variables. There is not a single closure per function declaration. There is a closure for each call to a function. ..........................................

好的,所以示例 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 变量?

正如 elclanrs 所说,一切都是关于 this:

当您调用 createCounter(1) 时,this 没有变化,很可能仍然是全局范围。鉴于 document.write,可以安全地说全局范围是 window。因此,您将 window.setCounter 创建为一个函数,它将设置 localCounter,一个隐藏在闭包中的变量,并将 window.getValue 设置为读取此隐藏变量的函数;它将 localCounter 初始化为 1;然后它 returns window 并将其分配给 Counter1.

然后,Counter1.getValue() 调用 window.getValue(),return 调用 1。都好。与 increment.

相同

但是,由于您一直在全局上下文中进行操作,因此当您执行 createCounter(0) 时,您正在 覆盖 window.getValue(以及其他函数) 带有一个 new 闭包,现在引用一个 different 隐藏 localCounter,这个被初始化为 0。由于 Counter0Counter1 都指向 相同的 对象(即 window),因此 Counter1.getValue()Counter0.getValue() 也应该 return 同样的事情(假设它们都没有副作用)。

使用 new 关键字,这会发生巨大变化,这是 JavaScript 中改变 this 的几种方法之一。如果你做 var 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

因此您可以了解为什么值保持不同。