【问题标题】:Javascript Closures with doesn't work with returned functionJavascript闭包不适用于返回的函数
【发布时间】:2015-07-24 09:50:04
【问题描述】:

我阅读了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 变量?

【问题讨论】:

  • 这与 new 的关系比闭包更多。我建议阅读this 的工作原理。

标签: javascript closures this


【解决方案1】:

正如 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(和其他功能)new em> 闭包现在引用了一个不同隐藏的localCounter,这个闭包初始化为0。由于Counter0Counter1 都指向同一个 对象(即window),所以Counter1.getValue()Counter0.getValue() 也应该返回相同的东西并不太牵强(假设它们都没有副作用)。

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

这样您就可以看到为什么这些值保持不同。

【讨论】:

  • 非常感谢,您的解释对我很有帮助。
  • 还有一件小事:按照惯例,作为构造函数的函数(即那些应该创建新对象并用new调用的函数)用TitleCase名词短语命名(因此, Counter)。其他变量在camelCase 中(因此,counter0counter1setCounter...)。 (除了伪装成常量的变量,它们在UPPER_CASE 中)。约定使代码对所有相关人员都更具可读性。
猜你喜欢
  • 2013-01-16
  • 1970-01-01
  • 1970-01-01
  • 2015-04-16
  • 1970-01-01
  • 2012-10-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-07
相关资源
最近更新 更多