每个JavaScript函数都是一个对象,对象中有属性,可以访问如:
function text(){}
console.log(text.name) // text
还有一些属性是我们访问不了的如:
function text(){}
console.log(text.[[scope]]) //报错
[[scope]]是函数的属性,但是是一种隐式的属性,我们访问不了,而他代表的就是函数产生的作用域,存储了执行期上下文的集合。它既然用不了,那它还有作用吗?有的虽然我们用不了,但是系统是可以使用的(只许州官放火不许百姓点灯)。
执行期上下文:当函数执行前,会创建一个执行期上下文的对象,执行期上下文定义了一个函数执行时的环境(我也不知道该怎么解释这句,就是这个函数会依赖这个环境去执行,,,大家试着去理解就可以),函数每次执行时对应的执行期上下文都是独一无二的,所以多次调用一个函数会产生多个执行期上下文,但是这么多执行期上下文放着也没用,还占内存,所以函数执行完毕以后就会销毁它自己产生的执行期上下文。
function text(){} //函数创建产生AO{}
text(); // 函数执行 销毁AO对象,尽显渣男本色
作用域链: [[scope]]中所存的执行期上下文对象的集合,这个集合成链式链接,我们把这中链式链接叫做作用域链。
好了看天书环节过去了,可以看代码说问题了:
var c = 10;
function a(){ // 在a函数刚刚被定义的时候,它就有了自己的[[scope]]属性 里面第一位放着全局对象GO
console.log(c) // 10 ,在AO里找不到c变量,就到GO里找到c 打印10
function b(){ //在b函数刚刚被定义的时候,它就有了自己的[[scope]]属性 里面第一位放着a函数创建时的AO,第二位放着全局对象GO
var b = 234;
}
var a = 123;
b();//函数执行时在[[scope]]属性里面把自己创建的AO放在作用域链的顶端,AO和GO向下移一位。
}
var glob = 100;
a(); //函数执行时在[[scope]]属性里面把自己创建的AO放在作用域链的顶端,GO向下移一位。
a,b函数定义和执行时他们能访问到的作用域及访问先后顺序
a 定义 a.[[scope]] ---------------- 0 : GO
a 执行 a.[[scope]] ---------------- 0 : aAO
1 : GO
b 定义 b.[[scope]] ---------------- 0 : aAO
1 : Go
b 执行 b.[[scope]] ---------------- 0 : bAO
1 : aAO
2 : GO
函数在执行时,会产生AO,当它访问变量时,先去找AO,再去找GO,这其实说明这样他们之间有一种联系,即作用域链。而自己创建的AO永远放在作用域链的顶端。
最后当b函数执行完毕,b函数销毁自己的AO对象,保留a函数的AO和全局的GO,处于定义阶段,等待执行,截止a函数也执行完毕时,a函数销毁自己的AO对象,保留全局GO对象,等待执行,但是注意一点,a函数的AO对象中,是有b函数的定义的,a函数的AO也保留在b函数的定义中,所以a函数的AO没有被真正意义上的销毁。
还有一点:a函数执行创建一个自己的AO,内部的b函数也可以访问这个AO,哪两个AO有什么关系呢?是复制了一个,还是大家用的同一个呢?看代码:
function a() {
var cc = 0;
function b() {
cc = 10;
}
b();
console.log(cc) // 10 打印出了10,这说明b函数访问的AO对象和a函数创建的AO对象是同一个。
}
a();
入职不久的小前端从今以后开始自己的技术分享之旅,欢迎建议和批评。