Bootstrap

【学习笔记】JavaScript的作用域

作用域

作用域(scope)规定了变量能够被访问的“范围”,离开了这个“范围”变量便不能被访问,作用域也可以堆叠成层次结构,子作用域可以访问父作用域,反过来则不行。

JavaScript 的作用域分为:

  • 全局作用域:脚本模式运行所有代码的默认作用域
  • 模块作用域:模块模式中运行代码的作用域
  • 函数作用域:由函数创建的作用域
  • 块级作用域:用一对花括号(一个代码块)创建出来的作用域

全局作用域

定义

<script> 标签 和 .js 文件 的【最外层】就是全局作用域, 全局作用域中的变量可以在整个代码中访问。在此声明的变量在函数内部也可以被访问。

示例

var globalVar = "I am global";

function showGlobal() {
    console.log(globalVar); // 输出: I am global
}

showGlobal();

注意:

  1. 全局变量容易引发命名冲突和难以调试的问题。尽量避免在全局作用域中声明变量。防止全局变量被污染
  2. 全局变量在整个应用程序的生命周期内存在,可能导致内存泄漏。使用后应尽量清理不再需要的全局变量。

模块作用域

定义

ES6 引入了模块(Modules)概念,每个模块都有自己的作用域。模块内部定义的变量和函数默认是私有的,外部无法直接访问,只有通过 export 导出后才能被其他模块使用。

示例

javascript// module.js
let moduleVar = "I am a module variable"; // 模块作用域
export const exportedVar = "I am exported";

// main.js
import { exportedVar } from './module.js';
console.log(exportedVar); // 输出: I am exported
console.log(moduleVar); // ReferenceError: moduleVar is not defined

注意事项

  • 命名导出和默认导出:模块可以有命名导出和默认导出,理解两者的区别非常重要。命名导出可以导出多个,而默认导出只能有一个。
  • 模块依赖:模块之间的依赖关系需要注意,避免循环依赖的问题。

函数作用域

定义

函数作用域是指在函数内部定义的变量和函数只能在该函数内访问。每个函数都有自己的作用域,函数内部可以访问外部的变量,但外部不能访问内部的变量。

示例

javascriptfunction myFunction() {
    const localVar = "I am local";
    console.log(localVar); // 输出: I am local
}

myFunction();
console.log(localVar); // ReferenceError: localVar is not defined

注意事项

  1. 变量提升:使用 var 声明的变量会被提升到函数顶部,可能导致意想不到的行为。
  2. 闭包:在函数内部定义的函数可以访问外部函数的变量,这种特性称为闭包。闭包可以用于创建私有变量,但也可能导致内存泄漏。

总结:

  1. 函数内部声明的变量,在函数外部无法被访问
  2. 函数的参数也是函数内部的局部变量
  3. 不同函数内部声明的变量无法互相访问
  4. 函数执行完毕后,函数内部的变量实际被清空了

块级作用域

定义

块级作用域是指在 {} 大括号内定义的作用域,通常出现在条件语句、循环和其他代码块中。使用 letconst 声明的变量具有块级作用域,而 var 声明的变量不具备块级作用域。

示例

javascript{
    let blockVar = "I am block scoped";
    var blockVar2 = "I am function scoped";
    console.log(blockVar); // 输出: I am block scoped
}

console.log(blockVar); // ReferenceError: blockVar is not defined
console.log(blockVar2); // 输出: I am function scoped

注意事项

  • letconst 的使用:使用 letconst 可以避免变量提升的问题,尽量优先使用这两者。
  • 变量访问:确保在定义变量的块内访问,否则会导致错误。

总结:

  1. let 声明的变量和const 声明的常量会产生块作用域,var 不会产生块作用域
  2. 不同代码块之间的变量无法互相访问
  3. 推荐使用 let 或 const

1.3 作用域链
作用域链本质上是底层的 变量查找机制 。
当 JavaScript 引擎查找变量时,它会按照作用域链的规则进行查找。作用域链是由当前作用域和外部作用域组成的,查找从当前作用域开始,向外层作用域逐层查找,直到全局作用域。

//全局作用域
let a = 1
let c = 1
//局部作用域
function fn1() {
    let b = 2
    let c = 2
    //局部作用域
    function fn2() {
        c = 3
        console.log(a,b,c)
    }
    fn2()
}
fn1()
// 1 2 3

总结:

  1. 嵌套关系的作用域串联起来形成了作用域链
  2. 相同作用域链中按着 从小到大 的规则查找变量
  3. 子作用域能够访问父作用域,父级作用域无法访问子级作用域

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;