代码如下:
js
var div = $('#appendHere'); $('#clickMe').on('click', function () { var that = this; div.append(checkForWindow(this)); setTimeout(function () { div.append(checkForWindow(this)); div.append('<strong>that</strong> is the ' + that.tagName + '<br/>'); }, 300); }); function checkForWindow(elm) { if (elm instanceof Window) { return 'this is the Window<br/>'; } else if (elm.tagName) { return ('this is the ' + elm.tagName + '<br/>'); } else { return ('this is ' + elm + '<br/>'); } }
输出结果:(另见:http://jsfiddle.net/dposin/okjr81ev/light/)
this is the BUTTON
this is the Window
that is the BUTTON
问题来了,setTimeout中的 checkForWindow(this)
为什么没有形成闭包,而 that
又形成闭包了呢?
这样写就能形成闭包?
本来我以为是要这样写的:
js
for (var i = 0; i < 10; i++) { setTimeout((function(i) { console.log(i); })(i), 0); }
这两种写法有区别吗?
注:我又理解了一下,发现两种都是闭包,只不过所处的上下文环境不一样。但是checkForWindow(this)
中的 this 不是取闭包中的 this ,而是取了 window 呢?也是闭包啊,闭包中上下文也有 this 啊,为什么就要取你 setTimeout 中的上下文 this 呢?
=======================================
好文链接:
setTimeout:
https://developer.mozilla.org/zh-CN/docs/Web/API/Window/setTimeout
闭包:
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures
http://www.zhihu.com/question/20019257
其实JS中的所有function均为(lexical) closure,所以直接理解了函数的定义与执行过程自然就理解closure的特点了。
function在定义的时候(就是生成Function Object的)会将当前EC的Scope Chain作为自身的[[Scope]]的属性值,其中that变量位于当前EC的AO中,因此自然也在settimeout延迟执行函数的[[Scope]]属性中。
然后在settimeout的延迟执行函数执行时会先构建自己的EC,新EC中的Scope Chain = AO + [[Scope]],然后在延迟函数中访问that时则在Scope Chain解析这个引用,那自然能找到之前设置的值。
而this是关键字,跟变量是不同的,因此不会在Scope Chain上解析。在EC中有一个Context Object的属性,我们访问this其实就是访问EC的Context Object,这个属性是根据函数的调用方式来决定的(暂且这样理解吧,其实底层有一套比较难理解的规范的)
上面可以理解为this就是指向函数调用时的所属对象,如果没有所属对象则指向全局对象(window)。下面示例就只能理解底层原理后才能理解透了,先留个坑吧