请考虑以下代码:
<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.foo,foo)应该总是输出相同的数字(i)。
但是单击div会输出3行(对于每个console.log调用):
2 0
2 1
2 2
似乎_this.foo
总是指最后this.foo
。为什么会这样?
答案 0 :(得分:3)
在函数wtf
中,变量foo
中捕获的值是标量 - 实际数值。因为它在创建函数时捕获标量值,所以该函数正在关闭值0,1,2等。这就是它似乎递增的原因。
然而,当_this被捕获时,它被捕获为对具有名为foo的字段的单个实例的引用。因此,使用_this.foo,您指的是同一实例上的字段。
总而言之,像整数这样的值类型是通过它们的值捕获的,而对象是通过它的引用捕获的。
答案 1 :(得分:2)
运行test()时,this
是对您的三个test()调用中每个window
的引用,因此当您分配给{{{}时,实际上是在更新window.foo
1}}并在_this.foo
中引用window.foo
。
然后,当调用console.log
时,每个wtf()
闭包中的_this
个变量都相同 - 它们都指向wtf()
请参阅此jsfiddle:http://jsfiddle.net/8cyHm/
我在console.log中添加了一些额外的参数来显示正在发生的事情
答案 2 :(得分:1)
这是一个棘手的问题,:)
您必须要了解的首要事项是,您调用的test
函数没有new
前缀,这使得函数内的this
指针引用{ {1}}对象
window
(plz阅读代码中的注释部分)
现在,当您点击<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>
时,其实际上有3个函数正在侦听其click事件(div
函数内的3个内联wtf
函数)(每次调用{ {1}}函数创建一个新的test
内联函数)。这些内联函数中的每一个都在局部变量test
上读取它们,每个变量分别具有值wtf
。
答案 3 :(得分:1)
所以,这就是它的工作原理:
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
局部变量。这些变量中的每一个都在调用i
函数时捕获test
变量的值。因此,这三个foo
变量的值为0
,1
和2
。这些变量由三个wtf
函数(分别)通过闭包捕获。 (第一个wtf
函数捕获第一个foo
变量,依此类推。)
但是,与foo
变量不同,只有一个 foo
全局属性。因此,在每次调用test
函数之后,foo
全局属性会递增。因此,在test
被调用三次后,_this.foo
的值为2
。 (这是之前点击DIV。)
现在,当单击DIV时,将执行三个wtf
函数。这些函数中的每一个都将打印_this.foo
的{{1}}值。但是,每个2
函数都通过闭包捕获了一个不同的 wtf
变量。这三个foo
变量的值分别为foo
,0
和1
。
答案 4 :(得分:-2)
如果您在Chrome中进行测试,可能会遇到console.log中的错误。 请参阅:Javascript Funky array mishap
尝试更改为:
console.log(_this.foo + ' = ' + foo);