JavaScript的作用域

简介: JavaScript的作用域

一、前言

作用域、作用域链是JavaScript中重要的组成部分和重点知识,是我们务必要掌握的内容。

如果没有掌握,那么作为重点难点之一的函数的闭包将会难以理解、无从下手。

二、作用域

1. 函数作用域 [[scope]]

规则:

  1. 外部对内部可见
  2. 内部对外部不可见
  3. 内部优先
  4. JS中,只有函数级别的作用域,没有块级作用域。也就是说,只有在进入或者退出函数时,作用域会发生变化。

2. 代码解析

  1. 外部对内部可见
var scope = 'global';
function f() {
    console.log(scope); // 'global'
}
f();
  1. 内部对外部不可见
function f2() {
    var scope2 = 'local2';
}
console.log(scope2); // 报错scope2 is not defined
  1. 都可见时,内部优先
var scope3 = 'global3';
function f3() {
    console.log(scope3); // undefined
    var scope3 = 'local3';
    console.log(scope3); // 'local3'
}
f3();
  1. js作用域都是函数级别的
// 1 if代码块
var scope = 'g';
if(true) {
    var scope = 'l';
    console.log(scope); // 'l'
}
console.log(scope); // 'l'
// 2 for代码块
for(var i = 0; i < 10; i++) {
    console.log(i); // 0 1 2 3 4 5 6 7 8 9
}
// 3 function函数
function fn() {
    aa = 5;
}
fn();
console.log(aa); // 5

三、执行环境和作用域链

1. 执行环境(EC)

执行环境(execution context),也就是执行期上下文,它定义了执行期间可以访问的变量和函数。

  1. 全局执行环境
  • Global Object(Window),即GO
  • 从见到JS代码开始创建
  • 到网页关闭时销毁
  1. 函数执行环境
  • Activation Object(AO)
  • 从函数调用开始创建
  • 到函数调用结束时销毁

2. 作用域链(scope chain)

  1. 作用域链[[scope chain]],每个函数都有
  2. 作用域链是私有属性,只能由JS引擎访问
  3. 作用域链,是AO和GO构成的链
  4. 所谓执行环境就是沿着作用域链依次查找变量和函数
  • 找到即停
  • 全部找完没有结果的话,就报错

3. 生成作用域链

规则1:每个函数在定义(函数声明、函数表达式)时会拷贝其父级函数的作用域链。

规则2:在函数被调用时,生成AO然后将AO压入作用域链的栈顶(数据结构中的栈)。

var g = 'g';
function fa() {
    var a = 'a';
    function fb() {
        var b = 'b';
    }
    fb();
}
fa();

解析:

  1. 首先生成全局执行环境,进行全局环境的预编译,并产生作用域链,在作用域链中存着GO对象。(此时,GO作用域链的引用数为1)
  2. 按照规则1,函数在定义时会首先拷贝其父级函数的作用域链,因此在调用fa函数生成fa函数下的AO对象时,fa的作用域链中必然已经有一个GO对象的作用域链。 另外,fa函数生成的AO对象作用域链将被压入fa函数作用域的栈顶。(此时,GO作用域链的引用数为2,fa函数的AO对象引用数为1)
  3. 接着,当预编译fb函数时,首先按照规则1拷贝了其父级的作用域链,即fa函数的AO作用域链以及全局环境下的GO作用域链。最后将自己生成的AO作用域链压入fb函数作用域链的栈顶。(此时,GO引用数为3,fa的AO引用数为2,fb的AO引用数为1)

1688210819959.png

  1. 当fb函数执行完成后,fb的作用域链消失,fb的AO被回收。此时,fb的AO引用数为0,fa的AO引用数为1,GO引用数为2。
  2. 当fa函数执行完成后,fa的作用域链消失,fa的AO被回收。此时,fa的AO引用数为0,GO引用数为1。
  3. 因此,最后只剩下全局执行环境下的GO对象。

规则3 with中,生成的新的with variable object,放在作用域链表的最顶端

var name = 1;
var person = {name: 'Nancy'};
with (person) {
    console.log(name); // 'Nancy'
}
var person2 = {
    name2: 'Mike',
    age: 18,
    height: 175,
    wife: {
        name2: 'AA',
        age: 21
    }
}
with (person2.wife) {
    console.log(name2); // 'AA'
    console.log(age); // 21
}

4. 作用域链的注意点

  1. 效率:尽量少使用靠上层的变量,多使用自己的局部变量;
  2. 重名容易出错:尽量减少不同层次函数使用相同的变量名,避免函数名与变量名一样;
  3. 闭包:函数执行完成后,AO不一定被释放,利用这个特点可以生成闭包。
function outer() {
    var scope = 'outer';
    function inner() {
        return scope;
    }
    return inner;
}
var fn = outer();
console.log(fn()); // 'outer'

四、本节思维导图

1688210853708.png

目录
相关文章
|
JavaScript 前端开发
js的作用域作用域链
【10月更文挑战第29天】理解JavaScript的作用域和作用域链对于正确理解变量的访问和生命周期、避免变量命名冲突以及编写高质量的JavaScript代码都具有重要意义。在实际开发中,需要合理地利用作用域和作用域链来组织代码结构,提高代码的可读性和可维护性。
|
JavaScript 前端开发
浅谈js作用域
浅谈js作用域
137 0
|
前端开发 JavaScript 数据处理
CSS 变量的作用域和 JavaScript 变量的作用域有什么不同?
【10月更文挑战第28天】CSS变量和JavaScript变量虽然都有各自的作用域概念,但由于它们所属的语言和应用场景不同,其作用域的定义、范围、覆盖规则以及与其他语言特性的交互方式等方面都存在明显的差异。理解这些差异有助于更好地在Web开发中分别运用它们来实现预期的页面效果和功能逻辑。
203 11
|
JavaScript 前端开发
javascript的作用域
【10月更文挑战第19天javascript的作用域
|
JavaScript 前端开发
如何在 JavaScript 中实现块级作用域?
【10月更文挑战第29天】通过使用 `let`、`const` 关键字、立即执行函数表达式以及模块模式等方法,可以在JavaScript中有效地实现块级作用域,更好地控制变量的生命周期和访问权限,提高代码的可维护性和可读性。
|
JavaScript 前端开发
JavaScript 作用域
JavaScript 作用域是指程序中可访问的变量、对象和函数的集合。它分为函数作用域和局部作用域。函数作用域内的变量仅在函数内部可见,而全局作用域的变量在整个网页中均可访问。局部变量在函数执行完毕后会被销毁,而全局变量则在整个脚本生命周期中都存在。未使用 `var` 关键字声明的变量默认为全局变量。
|
JavaScript 前端开发
JavaScript基础知识-作用域(action scope)
关于JavaScript基础知识中作用域的介绍。
174 1
JavaScript基础知识-作用域(action scope)
|
JavaScript 前端开发
js作用域
js作用域
89 1
|
JavaScript 前端开发
js 变量作用域与解构赋值| 22
js 变量作用域与解构赋值| 22
|
缓存 JavaScript 前端开发
了解js基础知识中的作用域和闭包以及闭包的一些应用场景,浅析函数柯里化
该文章详细讲解了JavaScript中的作用域、闭包概念及其应用场景,并简要分析了函数柯里化的使用。
了解js基础知识中的作用域和闭包以及闭包的一些应用场景,浅析函数柯里化

热门文章

最新文章