你来说说JavaScript作用域

大家好,我是有一点想法的thinkmars,目前在准备面试与工作,借着间隙时间学习复习,写一点基础文章,欢迎想找工作的人与我一起学习,一起讨饭吃~


在 JavaScript 中,作用域(Scope)是决定变量和函数可访问性的核心机制。

一、作用域核心概念

  1. 定义

    作用域是变量和函数的可访问范围,决定了代码中哪些部分可以访问某个标识符。

  2. 词法作用域 vs 动态作用域

    • 词法作用域(Lexical Scope):JS 采用词法作用域,作用域在代码书写时确定(如函数定义的位置)。
    • 动态作用域 :作用域在代码运行时确定(如 this 的绑定)。

二、作用域类型

1. 全局作用域(Global Scope)

  • 在函数或代码块外声明的变量,全局可访问。
  • 浏览器中,全局对象是 window;Node.js 中是 global
javascript 复制代码
var globalVar = "I'm global";
console.log(window.globalVar); // 浏览器输出: "I'm global"

2. 函数作用域(Function Scope)

  • var 声明的变量具有函数作用域。
  • 在函数内部声明的变量,外部无法访问。
javascript 复制代码
function foo() {
  var localVar = "I'm local";
}
console.log(localVar); // 报错:localVar未定义

3. 块级作用域(Block Scope)

  • ES6 引入 letconst,支持块级作用域({} 内有效)。
javascript 复制代码
if (true) {
  let blockVar = "I'm block-scoped";
  const PI = 3.14;
}
console.log(blockVar); // 报错:blockVar未定义

三、作用域链(Scope Chain)

  1. 定义

    函数执行时,会从当前作用域逐层向外查找变量,形成作用域链。

  2. 创建过程

    • 函数定义时,会保存其外层作用域的引用(即 [[Scopes]] 属性)。
    • 执行时,将当前变量对象添加到作用域链前端。
    javascript 复制代码
    function outer() {
      let a = 1;
      function inner() {
        console.log(a); // 通过作用域链找到 outer 中的 a
      }
      inner();
    }
    outer(); // 输出 1

四、闭包(Closure)

  1. 定义

    函数与其词法环境的引用捆绑,即使函数在其词法作用域外执行,仍能访问外部变量。

  2. 经典面试题

    javascript 复制代码
    for (var i = 0; i < 5; i++) {
      setTimeout(() => console.log(i), 100); // 输出 5 五次
    }
    // 解决方案:使用 let 或闭包
    for (let i = 0; i < 5; i++) {
      setTimeout(() => console.log(i), 100); // 输出 0,1,2,3,4
    }

五、变量提升(Hoisting)

  1. var 的变量提升
    var 声明会被提升到作用域顶部,赋值保留在原地。

    javascript 复制代码
    console.log(hoistedVar); // undefined
    var hoistedVar = "Hoisted!";
  2. let/const 的暂时性死区(TDZ)
    letconst 存在暂时性死区,声明前访问会报错。

    javascript 复制代码
    console.log(tdzVar); // 报错:Cannot access 'tdzVar' before initialization
    let tdzVar = "TDZ!";

六、面试高频问题

  1. 解释以下代码的输出:

    javascript 复制代码
    let a = 1;
    function outer() {
      console.log(a);
      let a = 2;
    }
    outer(); // 报错:Cannot access 'a' before initialization

    答案 :块级作用域内 let 声明导致暂时性死区。

  2. 如何用闭包实现私有变量?

    javascript 复制代码
    function Counter() {
      let count = 0;
      return {
        increment: () => count++,
        getCount: () => count
      };
    }
    const counter = Counter();
    counter.increment();
    console.log(counter.getCount()); // 1

七、总结与注意事项

  1. 优先使用 let/const:避免变量提升和全局污染。
  2. 闭包内存泄漏:及时解除不再使用的闭包引用。
  3. 严格模式 :使用 'use strict' 避免意外全局变量。
相关推荐
tangdou36909865543 分钟前
AI真好玩系列-2分钟快速了解DeepAgents | Quick Guide to DeepAgents in 2 Minutes
前端·javascript·后端
张元清44 分钟前
React useIntersectionObserver Hook:懒加载与可见性检测(2026)
javascript·react.js
彭于晏爱编程1 小时前
纯 JS + Node,一个下午手搓了能读懂公司代码的 AI 助手,老板以为我转行了
前端·javascript
妙码生花2 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(十四):眨眼小人登录页制作
前端·javascript·ai编程
妙码生花2 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(十三):前端路由初始化
前端·javascript·ai编程
PBitW2 小时前
GPT训练我的第四天,被打惨了!!!😭😭😭
前端·javascript·面试
DarkLONGLOVE2 小时前
快速上手 Pinia!Vue3 极简状态管理使用教程
javascript·vue.js
mackbob2 小时前
.eslintrc.js详细配置说明
javascript
用户298698530144 小时前
在 React 中使用 JavaScript 将 Excel 转换为 PDF
javascript·react.js·webassembly
用户938515635076 小时前
从 Prompt 到 Harness:AI 工程化的三年跃迁与实战解码
javascript·人工智能