详解|作用域和作用域链

119 阅读4分钟
<SCRIPT LANGUAGE="JavaScript">
var bb = 1;
function aa(bb) {
    bb = 2;
    alert(bb);
};
aa(bb);
alert(bb);
</SCRIPT>

输出:2,1。

这段代码考察了以下几个关键的 JavaScript 知识点:

1. 变量作用域(Scope)

  • 全局变量与局部变量

    • 代码中的 var bb = 1; 声明了一个全局变量 bb,它在整个脚本的范围内都可以访问。
    • 在函数 aa 中,bb 被当作函数参数传入,这个 bb 变量是局部变量,函数内部的 bb 与全局变量 bb 是相互独立的。即使局部变量的名字和全局变量相同,它们还是在不同的作用域中,不会相互干扰。

2. 参数传递(Pass by Value)

  • 按值传递

    • 在 JavaScript 中,基本类型(如数字、字符串、布尔值等)的函数参数是按值传递的。这意味着当你将一个变量传递给函数时,传递的是该变量值的副本。
    • 在这段代码中,aa(bb) 调用时,全局变量 bb 的值 1 被复制并传递给函数 aa。因此,aa 函数内的 bb 是这个副本,与全局变量 bb 无关。
    • 当函数内部修改 bb 时,只是修改了副本,而不影响全局作用域的 bb

3. 函数作用域与变量遮蔽(Shadowing)

  • 变量遮蔽

    • 当函数的参数名与外部作用域(如全局作用域)中的变量名相同时,函数内的局部变量会“遮蔽”外部变量,导致在函数内部无法直接访问外部变量。
    • 在这段代码中,函数参数 bb 与全局变量 bb 名字相同,函数内对 bb 的操作只影响函数内部的 bb(即参数的副本),而不会影响全局的 bb

作用域链 是 JavaScript 中的一种机制,用于解析变量的访问顺序。它定义了在不同的作用域(scope)中,变量和函数的可访问性及查找顺序。

作用域和作用域链的基本概念

  1. 作用域(Scope)

    • 作用域是指程序中变量、函数等标识符的可访问范围。在 JavaScript 中,作用域主要分为以下几种:

      • 全局作用域:在代码的任何地方都能访问的作用域,通常是最外层定义的变量或在 window 对象上定义的变量。
      • 函数作用域:在函数内部定义的变量和函数只能在该函数内部访问。
      • 块级作用域:使用 letconst 等在块级(如 {})中定义的变量,只能在该块级作用域内访问。
  2. 作用域链(Scope Chain)

    • 作用域链是一个指向变量对象的指针列表,当 JavaScript 引擎尝试查找一个变量时,它会从当前作用域开始查找。如果找不到,它会沿着作用域链向上查找,直到找到该变量或到达全局作用域。
    • 这种从当前作用域到全局作用域逐级向上查找的过程,就是作用域链的工作机制。

作用域链的工作原理

当你在代码中访问一个变量时,JavaScript 引擎会按照以下顺序查找变量:

  1. 当前作用域:首先引擎会在当前作用域中查找变量。
  2. 上级作用域:如果当前作用域没有找到该变量,查找会继续在上一级作用域进行。
  3. 全局作用域:如果上级作用域中仍未找到变量,查找最终会到达全局作用域。
  4. 未找到:如果在全局作用域中也找不到该变量,JavaScript 引擎会抛出 ReferenceError 错误。

示例代码

let globalVar = "global";

function outerFunction() {
    let outerVar = "outer";

    function innerFunction() {
        let innerVar = "inner";

        console.log(innerVar);   // 输出 "inner"
        console.log(outerVar);   // 输出 "outer"
        console.log(globalVar);  // 输出 "global"
    }

    innerFunction();
}

outerFunction();

在这个例子中:

  1. innerFunction 函数首先在其自身作用域内查找 innerVar,找到了并输出 "inner"。
  2. 对于 outerVarinnerFunction 在其自身作用域内未找到,于是沿着作用域链查找到了 outerFunction 的作用域,并成功找到了 outerVar,输出 "outer"。
  3. 对于 globalVarinnerFunction 沿着作用域链找到了全局作用域中的变量 globalVar,输出 "global"。

作用域链的意义

  • 变量遮蔽(变量隐藏) :如果在当前作用域中定义了一个与上级作用域同名的变量,那么上级作用域中的变量在当前作用域中将被遮蔽。即,当前作用域中的同名变量将优先被访问。
  • 闭包:JavaScript 中的闭包利用了作用域链的机制,使得内部函数可以访问其外部函数作用域中的变量。

总结

  • 作用域链 是 JavaScript 中的一种变量解析机制,它决定了变量在不同作用域中的可访问性。
  • 查找变量时,JavaScript 引擎会从当前作用域开始,沿着作用域链向上查找,直到找到变量或到达全局作用域。
  • 作用域链确保了代码的结构性和可预测性,使得变量查找有序进行