Javascript关闭令人困惑

时间:2017-11-07 10:02:32

标签: javascript closures

我正在尝试使用Javascript闭包,下面的代码始终保持打印9。但是,当我创建10个闭包时,先前的值不应该持续存在吗?

var arr = [];
function getModule(value){
        return (function (_value) {
              var m_val = _value;

              this.getValue = function () {
                  return m_val;
              };

              return {
                ShowValue: function () {
                    console.log(getValue.call(this));
                }
              };
        })(value);
}
for(var i = 0; i < 10 ; i++){
    arr.push(getModule(i))
}
for(var i = 0; i < 10 ; i++){
    arr[i].ShowValue();
}

请帮助理解这种奇怪的行为。

1 个答案:

答案 0 :(得分:4)

  

但是,因为我创建10个闭包不应该先前持续存在吗?

您正在创建它们,但随后会立即用下一个覆盖它们。匿名函数中的this是对全局对象的引用(在浏览器上也可用作window),因此每个this.getValue = ... 都会覆盖之前的对象。它是对全局对象的引用的原因是,您调用该函数的方式不会设置任何特定的this,因此它默认为全局对象(这是“严格”模式更改;请参阅更多下面)。详细了解this this的工作原理。

只需使用函数声明,而不是分配给function getValue() { return m_val; } 的属性:

this

另请注意,调用它时没有理由设置console.log(getValue.call(this)); ,所以:

console.log(getValue());

变为

var arr = [];
function getModule(value){
        return (function (_value) {
              var m_val = _value;
              
              function getValue() {
                  return m_val;
              }

              return {
                ShowValue: function () {
                    console.log(getValue());
                }
              };
        })(value);
}
for(var i = 0; i < 10 ; i++){
    arr.push(getModule(i))
}
for(var i = 0; i < 10 ; i++){
    arr[i].ShowValue();
}

直播示例:

.as-console-wrapper {
  max-height: 100% !important;
}
getValue

其他一些说明:

  • 根本不需要内部匿名功能,也不需要value;只需直接使用function getModule(value){ return { ShowValue: function () { console.log(value); } }; }

    getModule

    调用value的代码无法改变value中的值; getModule完全属于i及其内容。它具有从i(间接)传递到其中的值的副本,它不是showValue的引用或别名。

  • JavaScript中压倒一切的惯例是非构造函数以小写字母开头,所以ShowValue而不是console.log(即使它们是方法;想想{{1} }或Math.max)。

  • var适用于整个范围(全局范围或特定功能的范围)。代码中的两个var i声明不限于循环,因此第二个声明是不必要的(但语言允许)。 (ES2015 +有letconst 限定为循环,但var不是。)

  • 从ECMAScript第五版(2009年)开始,JavaScript有一个“严格”模式,它改变了语言的某些行为,包括调用的函数中this的内容,而不执行任何操作会设置this。 (this在这种情况下是undefined而不是引用全局对象。)严格模式还有其他好处,例如,如果您不小心使用了未声明的变量,则标记它。要启用它,请将"use strict";放在代码的顶部。有关严格模式的更多信息this question's answers

所以:

"use strict";
var i;
var arr = [];
function getModule(value){
    return {
      showValue: function () {
          console.log(value);
      }
    };
}
for (i = 0; i < 10; i++){
    arr.push(getModule(i))
}
for (i = 0; i < 10; i++){
    arr[i].showValue();
}
.as-console-wrapper {
  max-height: 100% !important;
}