We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
参考文章: ★ JavaScript深入之作用域链 你不知道的JavaScript】(三)执行上下文及其生命周期 ★ JavaScript深入之词法作用域和动态作用域
当查找变量的时候,会先从当前上下文的变量对象中查找,如果没有找到,就会从父级(词法层面上的父级)执行上下文的变量对象中查找,一直找到全局上下文的变量对象,也就是全局对象。这样由多个执行上下文的变量对象构成的指针链表就叫做作用域链。
作用域链保存的是指向执行上下文变量对象引用地址的指针,而不是保存变量对象的具体地址。
要了解 JS 的作用域链,首先要知道什么是作用域。
作用域按性质分为两种:
JavaScript 中采用词法作用域。
作用域在 JS 中又分为三种:
词法作用域特点在于:任何变量和函数的作用域范围在书写代码时就被确定。 而动态作用域需要在变量或函数被调用时才能确定。
var value = 1; function foo() { console.log(value); } function bar() { var value = 2; foo(); } bar();
1
bar()
foo()
console.log(value);
value === 1
2
value === 2
相比动态作用域,词法作用域更方便开发者查找分析,我们只需要看调用的函数在代码中定义的位置,即可清晰判断各层的作用域。
函数有一个内部属性 [[scope]](数组),在函数定义时就自动生成,其保存了所有父级及以上层级的变量对象。换句话说,[[scope]] 就是当前函数下所有父变量对象的层级链,但是注意:[[scope]] 并不代表完整的作用域链!因为它没有添加当前执行上下文的变量对象。
[[scope]]
function foo() { function bar() { ... } }
函数创建时,函数各自的[[scope]]为:
foo.[[scope]] = [ globalContext.VO ]; bar.[[scope]] = [ fooContext.AO, globalContext.VO ];
当函数被调用时,JS 引擎开始创建函数执行上下文,该阶段作用域链才真正的生成: 在创建完变量对象后,JS 会将变量对象添加到 [[scope]] 的前端,生成一条作用域链并保存为 Scope。
Scope
Scope = [VO].concat([[scope]])
至此作用域链创建完毕,当进入函数上下文执行阶段时,VO 会被激活为 AO,此时作用域链通过代码可表示为:
Scope = [AO, ...[[scope]]]
The text was updated successfully, but these errors were encountered:
No branches or pull requests
JS深入浅出 - 作用域链
参考文章:
★ JavaScript深入之作用域链
你不知道的JavaScript】(三)执行上下文及其生命周期
★ JavaScript深入之词法作用域和动态作用域
1. 概念
当查找变量的时候,会先从当前上下文的变量对象中查找,如果没有找到,就会从父级(词法层面上的父级)执行上下文的变量对象中查找,一直找到全局上下文的变量对象,也就是全局对象。这样由多个执行上下文的变量对象构成的指针链表就叫做作用域链。
2. 作用域
要了解 JS 的作用域链,首先要知道什么是作用域。
作用域按性质分为两种:
作用域在 JS 中又分为三种:
词法作用域(lexical scoping)
词法作用域特点在于:任何变量和函数的作用域范围在书写代码时就被确定。
而动态作用域需要在变量或函数被调用时才能确定。
1
。过程分析:
首先调用
bar()
,执行内部的foo()
,遇到console.log(value);
语句,由于在foo()
的块级(词法)作用域中没有找到声明变量,因此沿着作用域链向外查找(查找过程后续细讲),此时foo()
的外层(词法)作用域为全局作用域,因此value === 1
。2
。首先调用
bar()
,执行内部的foo()
,遇到console.log(value);
语句,由于在foo()
的块级(动态)作用域中没有找到声明变量,因此沿着作用域链向外查找,此时由于foo()
是在bar()
作用域中调用的,因此foo()
的外层(动态)作用域为bar()
的作用域,因此value === 2
。3. 作用域链的创建
函数定义阶段
函数有一个内部属性
[[scope]]
(数组),在函数定义时就自动生成,其保存了所有父级及以上层级的变量对象。换句话说,[[scope]]
就是当前函数下所有父变量对象的层级链,但是注意:[[scope]]
并不代表完整的作用域链!因为它没有添加当前执行上下文的变量对象。函数创建时,函数各自的[[scope]]为:
函数调用阶段
当函数被调用时,JS 引擎开始创建函数执行上下文,该阶段作用域链才真正的生成:
在创建完变量对象后,JS 会将变量对象添加到
[[scope]]
的前端,生成一条作用域链并保存为Scope
。至此作用域链创建完毕,当进入函数上下文执行阶段时,VO 会被激活为 AO,此时作用域链通过代码可表示为:
The text was updated successfully, but these errors were encountered: