// 作用域
function a(){
function b(){
var bbb = 234;
}
var aaa = 123;
b();
}
var glob = 100;
a();
//首先在定义a fun的时候,a有一个[[scope]]装作用域链,作用域链0位,创建一个全局GO
//a defined a.[[scope]]------->0:GO {}
// GO包含 GO:{
// this:window,
// window:(object),
// document:(object),
// a:(function),
// glob:100
// }
//a执行之前,[[scope]]创建一个a的AO,处于作用域链顶端0,GO就推至1位
//a doing a.[[scope]]------->0:aAO
// 1:GO
// aAO包含 AO:{
// this:window,
// arguments:[],
// aaa:123,
// b:(function)
// }
//a执行,定义b,b的[[scope]] b不会创建GO 首先继承a原有的GO 跟AO
//b defined b.[[scope]]------->0:aAO
// 1:GO
//b执行之前,[[scope]]创建一个b的AO,处于作用域链顶端0,aAO GO就后退
//a doing a.[[scope]]------->0:bAO
// 1:aAO
// 2:GO
// bAO包含 bAO:{
// this:window,
// arguments:[],
// bbb:234
// }
//当要从某个func里面找变量,从作用域顶端依次往下找
//如:从b内找变量,先找bAO aAO GO
小练习
// 练习
function a(){
var aaa = 123;
function b(){
console.log(aaa);
}
return b;
}
var demo = a();
demo();
//答案 demo();打印出123
//解析:1、定义a --->a.[[scope]]-->GO
// 2、demo=a();执行前a.[[scope]]-->aAO GO --->aAO{aaa:123,b:function}
// 3、定义b;b.[[scope]]-->aAO GO aAO{aaa:123;b:function}
// 4、return b;将b复制给demo后,a执行完毕,销毁自身的aAO
// 5、demo();执行demo,也就是b。执行前,demo依旧demo.[[scope]]-->demoAO还保留有aAO GO
// 6、虽然a执行完毕销毁了自己的aAO,但是b依旧保留有aAO{aaa:123;b:function}
// 7、所以仍旧能打印出aaa=123
//答案 demo();打印出123
//解析:1、定义a --->a.[[scope]]-->GO
// 2、demo=a();执行前a.[[scope]]-->aAO GO --->aAO{aaa:123,b:function}
// 3、定义b;b.[[scope]]-->aAO GO aAO{aaa:123;b:function}
// 4、return b;将b复制给demo后,a执行完毕,销毁自身的aAO
// 5、demo();执行demo,也就是b。执行前,demo依旧demo.[[scope]]-->demoAO还保留有aAO GO
// 6、虽然a执行完毕销毁了自己的aAO,但是b依旧保留有aAO{aaa:123;b:function}
// 7、所以仍旧能打印出aaa=123
// 练习2
function a(){
var num = 100;
function b(){
num++;
console.log(num);
}
return b;
}
var demo = a();
demo();
demo();
//答案 demo();依次打印出101 102
//解析:1、定义a --->a.[[scope]]-->GO
// 2、demo=a();执行a前 a.[[scope]]-->aAO GO --->aAO{num:undefined,b:function}
// 3、执行时:
// (1)、aAO{num:100,b:function}
// (2)、定义b;b.[[scope]]-->aAO GO aAO{num:100;b:function}
// 4、return b;将b复制给demo后,a执行完毕,销毁自身的aAO
// 5、demo();执行demo,也就是b。执行前,demo依旧demo.[[scope]]-->demoAO还保留有aAO GO
// 6、虽然a执行完毕销毁了自己的aAO,但是b依旧保留有aAO{num:100;b:function}
// 7、第一次执行demo,也就是b,num++,在aAO中,num++变为aAO{num:101;b:function}
// 打印 num为101。执行完毕后销毁demo的[[scope]]。但依旧还保留有aAO GO
// 8、第二次执行demo,num++,在aAO中,num++变为aAO{num:102;b:function},打印num为102
//答案 demo();依次打印出101 102
//解析:1、定义a --->a.[[scope]]-->GO
// 2、demo=a();执行a前 a.[[scope]]-->aAO GO --->aAO{num:undefined,b:function}
// 3、执行时:
// (1)、aAO{num:100,b:function}
// (2)、定义b;b.[[scope]]-->aAO GO aAO{num:100;b:function}
// 4、return b;将b复制给demo后,a执行完毕,销毁自身的aAO
// 5、demo();执行demo,也就是b。执行前,demo依旧demo.[[scope]]-->demoAO还保留有aAO GO
// 6、虽然a执行完毕销毁了自己的aAO,但是b依旧保留有aAO{num:100;b:function}
// 7、第一次执行demo,也就是b,num++,在aAO中,num++变为aAO{num:101;b:function}
// 打印 num为101。执行完毕后销毁demo的[[scope]]。但依旧还保留有aAO GO
// 8、第二次执行demo,num++,在aAO中,num++变为aAO{num:102;b:function},打印num为102
// 注意:当内部函数被保存到外部时,将会生成闭包。
闭包会导致原油作用域链不释放,造成内存泄漏。
//return b;就是一个闭包,
//这个闭包导致a执行完销毁了自己的AO,但是b仍旧留着a的AO,并且永远不会销毁。
function test(){
var num = 100;
function a(){
num++;
console.log(num);
}
function b(){
num--;
console.log(num);
}
return [a,b];
}
var myArr = test();
myArr[0]();//101
myArr[1]();//100
// a跟b所指向的test的AO是同一个AO,所有修改的是同一个AO