我正在尝试使用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();
}
请帮助理解这种奇怪的行为。
答案 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 +有let
和const
将限定为循环,但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;
}