闭包
-
闭包指的是有权访问另一个函数作用域中的变量的函数
函数a返回函数b时,如果函数b引用了函数a的局部变量,实际的返回值就变成了函数b的函数体和一个闭包,闭包里是函数b用到的全部变量
创建函数:
- 创建作用域链
- 将作用域链保存在函数内部属性
[[scope]]
中
调用函数:
- 创建执行环境
- 复制
[[scope]]
属性中的作用域链
补充:变量对象与活动对象
- 变量对象
- 变量对象就是执行环境中包含了所有变量和函数的对象
- 变量对象是后台的,保存在内存中的,代码无法直接访问的。
- 活动对象
- 函数调用了,函数中才会有活动对象,否则只有“处于静止状态”的变量对象,当然也没有创建执行环境。
- 活动对象就是作用域链上正在被执行和引用的变量对象
function closure(propertyName) { return function(obj) { //定义并返回一个闭包 return obj[propertyName]; }; }; let person = {name: "Shaw", age: 19}; let sayName = closure("name"); let sayAge = closure("age"); console.log(sayName(person), sayAge(person))
第二行在
closure
函数执行完毕以后,它的活动对象propertyName
有没有被销毁,因为匿名函数的作用域链仍然在引用这个活动对象;即外部函数返回后,其执行环境的作用域链会被销毁,但活动对象仍存在于内存中;直到匿名函数被销毁后,外部函数的活动对象才会被销毁。function createFunctions() { var result = new Array(); for(var i = 0; i < 10; i++) { result[i] = function() { return i; } } return result; } for(let i = 0; i < 10; i++) { console.log(createFunctions()[i]()); }
在声明函数
createFunctions()
时,给每个result[i]
分配了一个函数定义,这个函数是一个匿名函数在倒数第二行对每个
result[i]
执行这个匿名函数时,return i
时会在这个匿名函数的作用域链中查找变量i
的值,由于在定义函数时,i
的值已经循环到了10
,则返回值均为10