7.1 作用域链
作用域产生于程序源代码中定义变量的区域,在程序编码阶段就确定了。javascript 中分为全局作用域(Global context: window / global)和局部作用域(Local Scope , 又称为函数作用域 Function context)。简单讲作用域就是当前函数的生成环境或者上下文,包含了当前函数内定义的变量以及对外层作用域的引用。JS 中作用域是可访问变量、对象、函数的集合。
7.11作用域
函数作用域[[scope]]
外部对内部可见
意思简单点就是 函数里面的变量可以调用函数外面的值,看个例子:
1
2
3
4
5
6
7
8var scope='g';
function t(){
console.log(scope);//undefined
var scope='1';
console.log(scope);//1
}
t();而如果我们把 第四行语句去掉,结果就不一样了,结果值分别是 g , g 。这就是所谓的外部对内部不可见。
内部对外部不可见
示例:
1
2
3
4
5
6
7function t(){
var scope='1';
}
t();
console.log(scope);运行结果是报错的,因为没有找到 scope 这个变量。
内部优先
这里声明一下,在 c 和 c++ 里面,控制作用域的一般叫做块,块就是用一个大括号括起来的,大括号里面作用域存在,大括号没有,作用域消失。而JS 中只有函数级别的作用域,没有块级别的作用域;换句话来说,只有在进入或者退出函数的时候,作用域会发生变化。
js 的作用域都是函数级别的,例如:
1 | var scope='g'; |
7.12 执行环境和作用域链
执行环境
执行环境(execution context),定义了执行期间可以访问的变量和函数。
知识点:
- 作用域[[scope]] ,每个函数都有;
- 作用域是私有属性,只能由 JS 引擎访问;
- 作用域链,是 AO 和 GO 构成的链
- 所谓的执行环境,就是根据作用域链依次查找变量和函数:
- 找到即停
- 全部找完无果,报错。
- 作用域链每个函数都要
生成作用域链
- 每个函数在定义(函数声明\函数表达式)时会拷贝其父亲函数的作用域链;
- 在函数被调用时,生成 AO 然后将 AO 压入作用域链的栈顶。
在这边,有个容易混同的概念:
- 函数多次调用时,是产生相同的 AO 还是不同的 AO ?
- 函数递归调用时,是产生相同的 AO 还是不同的 AO ?
函数每次调用都会产生一个属于自己的 AO ,一个函数被不同的调用就会产生不同的 AO ,这个函数出去的话,如果计数器变为 0,则这个 AO 就被摧毁。递归调用产生的 AO 也是不同的,在递归调用过程中,每个 scope chair 拷贝的不是他自己的函数,而是拷贝定义它的函数。这是与
c 和 c++ 不一样的,c 和 c++如果递归调用的话,只有一个栈,这个时候,函数调用自己的话是全部压在栈里边的。如果一个函数递归调用五次的话,那么实际上栈里面压着前4次它们的栈信息。这是与 JavaScript 不一样的地方。
示例:
1 | function fa(){ |
问个问题,在这边,三次调用 fa() 是使用同一个 AO ,还是不同的 AO ?这个呢,是每次产生不同的 AO ,三次返回结果都是 undefined ,并不会自加,下面是大致解题思路:
1 | /*栈内存 |
第三次 fa() 函数调用与前面两次一样,就不再详写。
全局执行环境
- Global Object(window)
- 从见到 JS 代码开始创建
- 到网页关闭时销毁
函数执行环境
- Activation Object
- 从函数调用开始创建
- 到函数调用结束时销毁