JavaScript闭包丢失了这个引用
JavaScript closure loses this reference?
考虑以下代码:
<script>
var i = 0;
function test() {
var _this = this;
// foo and _this.foo are set to the same number
var foo = _this.foo = i++;
function wtf() {
console.log(_this.foo, foo);
}
$("#thediv").click(wtf);
};
test();
test();
test();
</script>
似乎console.log(_this. log)Foo, Foo)应该总是输出相等的数字(i)。
但是点击div输出3行(对于每个console.log调用):
2 0
2 1
2 2
似乎_this.foo
总是指最后一个this.foo
。为什么会这样呢?
在您的函数wtf
中,在变量foo
中捕获的值是一个标量-实际数值。由于它在创建函数时捕获标量值,因此该函数在值0,1,2等处关闭。这就是为什么它似乎在增加。
总结一下,像整数这样的值类型是由它们的值捕获的,而对象是由它的引用捕获的。
当test()运行时,this
是对您的三个test()调用中的每个window
的引用,因此当您分配给_this.foo
并在console.log
中引用window.foo
时,您实际上正在更新window.foo
。
然后,当调用wtf()
时,每个wtf()
闭包中的_this
变量都是相同的——它们都指向window
查看这个jsfiddle: http://jsfiddle.net/8cyHm/
我在console.log中添加了一些额外的参数来显示正在发生的事情
这是一个棘手的问题,:)
您必须理解的第一件事是,您正在调用没有new
前缀的test
函数,这使得函数内部的this
指针指向window
对象
<script>
var i = 0;
function test() {
var _this = this; //** this referes to the window object
var foo = _this.foo = i++; //** incrementing the global var and assigning that to a local var and a window.foo var
function wtf() {
console.log(_this.foo, foo); //** reads window.foo and its local var foo
}
$("#thediv").click(wtf); //** creates a new lister every time the test function gets called
};
//** calling without the new keyword
test(); //** creates foo-1, and wft-1 in memory, assigns foo-1=0; window.foo=0
test(); //** creates foo-2, and wft-2 in memory, assigns foo-2=1; window.foo=1
test(); //** creates foo-3, and wft-3 in memory, assigns foo-3=2; window.foo=2
</script>
(请阅读代码中的注释部分)
现在,当您单击div
时,它实际上有3个函数侦听其单击事件(test
函数内的3个内联wtf
函数)(每次调用test
函数都会创建一个新的wtf
内联函数)。这些内联函数中的每一个都在本地变量foo
上读取其值,然后每个函数分别具有1,2,3
的值。
所以,它是这样工作的:
test
函数被调用三次。每次创建一个不同的 wtf
函数对象并将其绑定到DIV作为其单击处理程序。这意味着在执行上述代码之后,将有三个单击处理程序绑定到DIV。然后单击DIV时,按顺序调用这三个处理程序。
var _this = this;
仅仅将全局对象存储到局部变量_this
中。如果在严格模式环境中调用函数test
,则this
将是undefined
,代码将抛出错误。然而,由于它不是严格模式,this
值指的是全局对象。
顺便说一句,i
变量是在全局代码中声明的,这使它成为一个全局变量(全局属性)。
var foo = _this.foo = i++;
将i
的当前值赋给本地变量foo
和_this.foo
。由于_this
是对全局对象的引用,所以属性foo
是一个全局属性(就像i
一样)。
现在,由于我们调用了test
函数三次,所以也有三个单独的foo
局部变量。这些变量中的每一个都在调用test
函数时捕获i
变量的值。因此,这三个foo
变量的值是0
、1
和2
。这些变量(分别)由三个wtf
函数通过闭包捕获。(第一个wtf
函数捕获第一个foo
变量,依此类推)
但是,与foo
变量不同的是,只有一个 foo
全局属性。因此,每次调用test
函数之后,foo
全局属性都会增加。因此,调用test
三次后,_this.foo
的值为2
。(这是在 DIV被点击之前的)
现在,当单击DIV时,将执行三个wtf
函数。每个函数都将输出_this.foo
的值,即2
。然而,这些wtf
函数中的每一个都通过闭包捕获了一个不同的 foo
变量。"foo
"的值分别为"0
"、"1
"、"2
"。
如果你在Chrome中测试,你可能会在console.log中遇到一个bug。参见:Javascript Funky array mishap
尝试更改为:
console.log(_this.foo + ' = ' + foo);
- 使用闭包创建原型中引用的私有属性
- 将函数引用传递给嵌套闭包
- Javascript-匿名函数中使用参数引用全局函数的闭包-我如何使用preventDefault
- JavaScript闭包和变量引用
- Jquery 和闭包或函数引用不起作用
- 闭包中变量引用的意外行为
- 如何使用字符串引用闭包,就像我在不使用 eval 的情况下使用成员函数一样
- 闭包而不是引用的副本
- navigator.useragent引用在闭包编译的js中丢失
- JavaScript:闭包是否可以通过值访问封闭范围中的变量,而不是像PHP中那样通过引用访问
- 此模式是否会导致闭包中出现循环引用
- Javascript 构造函数,使用引用其他变量的外部变量进行闭包
- 我以为我有一个this引用传递到Javascript闭包中的私有函数,我想错了
- 是什么导致了这种行为?(闭包,引用)
- 在Angular中,在闭包中引用服务属性/方法最合适的方式是什么?
- JavaScript闭包丢失了这个引用
- 我可以在匿名范围内更改Javascript闭包中引用的函数吗?
- 解引用变量的闭包有用吗?
- 我们是否需要手动清理闭包中未引用的变量
- Javascript闭包:原始行为与引用行为