前提
想起来之前面试,被问了一道题目:
(function a(){
function b(){}
})()
问我这个是不是闭包。我觉得不是,然后引发了一些思考。
1、作用域 scope
作用域就是指函数可访问的范围,决定了代码区块中变量和其他资源的可见性。举个例子:
var name = 'google';
function foo(){
console.log.log(name)
}
function bar(){
var name = 'baidu';
foo()
}
bar() // 'google'
这说明了js的作用域是在函数被定义的时候确定的。
2、上下文 context
上下文通常就是指函数中this 的值。
var name = 'google'
function foo(){
var name = 'baidu';
console.log(this.name);
}
foo() // 'google'
函数执行时他的上下文默认指向window(严格模式为undefined),最终指向调用这个函数的对象,可以通过call、apply、bind改变上下文。
3、执行期上下文
在函数执行的时候(或者说执行前一刻)会创建一个名为执行期上下文的内部对象,它定义了一个函数执行时的环境。函数执行完毕,上下文销毁。
我的理解,执行期上下文跟作用域链是一样的东西
4、作用域链
作用域链 scope chain当中储存了执行其上下文的集合,这个集合呈链式链接,称作作用域链。举个例子:
function a(){
var a = 123
function b(){
var b =234
}
b()
}
var global = 100;
a()
/*
·函数a 被定义时,他的作用域链的第0位,就是一个GO:
a.[[scope]] -- > [{
this: window,
window: (Object),
document:(object),
a: (function),
global: 100
}]
·a执行时,创建自己的AO:
{
this: window,
arguments: [],
a: 123,
b: (function)
}
放到作用域链的最顶端:
a.[[scope]] --> [
{
this: window,
arguments: [],
a: 123,
b: (function)
},
{
this: window,
window: (Object),
document:(object),
a: (function),
global: 100
}
]
·然后创建函数b,函数n 作用域链的第0为就是GO,也就是函数a的作用域链:
b.[[scope]] -- >[
a.[[scope]]
]
·b函数执行的时候,再创建自己的AO:放到作用域链最顶端
b.[[scope]] --> [
{
b: 234
},
a.[[scope]]
]
*/
由此,我们可以解释为什么作用域中那道题会输出'google'了。因为函数b被定义的时候作用域链已经形成,不管他在何处被调用。
总结
闭包的定义:函数的执行会形成一个私有的执行期上下文,如果上下文中有些内容(一般是指堆内存地址)被上下文以外的事物所占用,则当前上下文不能被出栈释放。
所以现在再回头去看开头的那道题,函数 b 的作用域链是[b.AO,a.[[scope]] ],可是当立即执行函数执行完毕,他的作用域链就已经被销毁了,连带函数b也被销毁了。没有任何内容被占用,所以我觉得不是闭包。
最后
这是我的第一篇博文,肯定有很多错谬的地方,希望大佬们不要喷我而是指出我错误地方,感谢!