前言
闭包可以说是在学习JavaScript中遇到的第一个难点,此贴是本人在学习闭包时留下的学习笔记。
js运行三部曲
- 语法分析
- 预编译
- 解释执行
js代码编写完并执行时,通常都会有这样的三个步骤。
语法分析:通篇执行 检验代码是否出现非逻辑上的错误
预编译:在JavaScript中存在一种预编译的机制,因为这个预编译的机制,导致了js中变量提升的一些问题。
- 函数声明整体提升
- 变量声明提升(赋值语句不提升)
这两句话大概概括了预编译的过程 但不全面。
imply global 暗示全局变量
即任何变量,如果变量未经声明就赋值,此变量就为全局变量所有。
一切声明的全局变量,全是window对象的属性
var a = 10;
// window {
// a : 10
// }
//
// window.a = 10
- window就是全局的域(global object)
- 预编译发生在函数执行的前一刻
预编译
预编译四部曲:
- 创建AO对象 (Activation Object 执行期上下文)
- 找形参和变量声明,将变量的形参名作为AO属性名,值为undefined
- 将实参值和形参统一
- 在函数里面找函数声明,值赋予函数体
第一步
AO {
}
//生成AO对象
第二步
AO {
形参 : undefined,
变量 : undefined,
}
//找形参和变量声明,将变量的形参名作为AO属性名,值为undefined
第三步
AO {
形参 : 实参,
变量 : undefined,
}
//将实参值和形参统一
第四步
AO {
形参 : 实参,
变量 : undefined,
函数名 : 函数体,
}
//在函数里面找函数声明,值赋予函数体
当这四步完成后程序就会一行一行解释执行
在全局中的预编译
- 生成GO对象(Global Object 全局执行上下文)
GO === window
GO完全等价于window对象
作用域 作用域链
- 作用域 [[scope]] :每个JavaScript函数都是一个对象,对象中有些属性我们可以访问,但有些不可以,这些属性仅供JavaScript引擎存取 [[scope]] 就是其中一个,[[scope]] 指的就是作用域,其中存储了运行期上下文(AO/GO)的集合。
- 作用域链 : [[scope]] 中所存储的执行期上下文对象的集合,这个集合呈链式链接,我们把这种链式链接叫做作用域链。
- 运行期上下文:当函数执行时,会创建一个称为执行期上下文的内部对象。
一个执行期上下文定义了一个函数执行时的环境,函数每次执行时对应的执行期上下文都是独一无二的,所以多次调用一个函数会导致创建了多个执行期上下文,当函数执行完毕,它所产生的执行期上下文会被销毁。 - 查找变量:从作用域链顶端开始查找(栈的工作方式)
function a(){
function b(){
var b = 234;
}
}
var glob = 100;
a ()
当函数a被定义时:
会产生一个全局执行期上下文GO 此时的作用域链为
a.[[scope]] -- > 0 : GO
当函数a执行时
会生成一个a函数的执行期上下文 放在作用域最顶端
a.[[scope]] -- > 0 : AO
1 : GO
当函数b被定义时
会拿到a执行时的作用域链作为自己的作用域链
b.[[scope]] -- > 0 : AO
1 : GO
当函数b执行时
会生成一个b函数的执行期上下文 放在作用域最顶端
b.[[scope]] -- > 0 : AO //b函数的
1 : AO //a函数的
2 : GO
闭包
有了预编译 作用域 作用域链 的基础, 才能够理解闭包的机制。
闭包:
当内部函数被保存到外部时,将会生成闭包,闭包会导致原有作用域链不释放,造成内存泄漏。
闭包的作用:
- 实现共有变量
- 可以做缓存
- 可以实现封装 属性私有化
- 模块化开发
例子:
function a (){
function b (){
var bbb = 234;
document.write(aaa);
}
var aaa = 123;
return b;
}
var demo = a();
demo(); //输出123
正常来说demo是a函数执行后返回的b函数,demo在a函数的外部,应该是访问不到a函数内部声明的bbb变量才对,但是最终输出却是123,这是因为这段程序发生了闭包。原因是 b函数被定义时它的作用域链继承了a函数执行的作用域链,这个作用域链里的AO对象含有bbb的变量,所以当b函数执行时会在它的作用域链中查找变量bbb 当第一层找不到时会接着在下一层寻找,b函数执行完之后会销毁第一层的AO 而变量bbb在第二层的AO中,所以b函数返回到外部之后执行依然能在它的作用域链之中访问到变量bbb的值,这就是我们说的闭包。