作用域、作用域链
- 运行期上下文(AO):函数执行时会创建一个称为执行期上下文的内部对象
- 一个AO定义了一个函数执行时的环境
- 函数每次执行时创建新的AO,多次调用函数会创建多个AO,
- 函数每次执行时,将新生成的AO放到作用域链的最顶端,函数执行完时被销毁
- 作用域:
- [[scope]]:作用域存储了运行期上下文的集合
- 作用域链:[[scope]]中存储的运行期上下文对象的集合,集合呈链式连接
查找变量:从作用域链顶端依次向下查找
(./demo/js/闭包.html)
<script>
function a() {
console.log(a); // undefined
console.log(b); // function b
function b() {
var b = 234;
console.log(b); //234
}
console.log(b); //function b
var a = 123;
console.log(a); // 123
return b;
}
var glob = 100;
var demo = a();
demo();
</script>
/*
作用域链:
a被定义时“./img/作用域链1.png”, a defined a.[[scope]] --> 0:GO
a被执行时,b被定义
“./img/作用域链2.png”, a activated a.[[scope]] --> 0:aAO
1: GO
b defined b.[[scope]] --> 0:aAO
1: GO
b被执行“./img/作用域链3.png” b activated b.[[scope]] --> 0: bAO
1: aAO
2: GO
*/
- 闭包
- a被执行时,b被定义,同时b被demo保存
- a被销毁时,b仍然存在,“./img/闭包.png”
- 因此可以在外部通过函数demo访问a中的变量
闭包
函数A内申明并保存在外部(被外部变量指向),可通过函数B使用A内部的局部变量或形参。外界对A函数内变量的引用导致其作用域不能被释放,构成一个闭包。
function Counter() {
let num = 0;
return {
add() {
num++;
console.log(num);
}
}
}
let counter = Counter();
Counter.add() // 1
Counder.add() // 2
闭包的作用
- 做缓存(存储结构)
- 模块化开发,防止污染全局变量
- 实现封装
// 封装 类 数据结构
function cache = !() => {
const store = {};
return {
get(key) {
return store[key];
}
set(key, val) {
store[key] = val;
}
remove(key) {
delete store[key];
}
}
}
console.log(cache);
cache.set('name': 'nini');
cache.get('name'); // 'nini'
- 暂存数据
// 将多个函数存储到数组中
function test(){
var arr = [];
for(var i = 0; i < 10; i++) {
(function(j){
arr[j] = function(){
document.write(j+'');
}(i));
}
return arr;
}
var myArr = test();
for(var j = 0; j < 10; j++) {
myArr[j]();
}
闭包的缺点
闭包内存得不到释放,容易造成内存泄漏