你来说说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' 避免意外全局变量。
相关推荐
八角丶1 小时前
Node 网络编程 —— TLS 模块
javascript·后端·node.js
倔强的石头1061 小时前
【Linux指南】动静态库系列(七):符号表与重定位:链接器如何把函数调用接起来
linux·前端·javascript
图扑软件2 小时前
中篇・运笔|统一 DataModel 底座,HT UI 组件万物同源
javascript·低代码·ui·性能优化·数据可视化
小小尚@3 小时前
WebGIS/ECharts 地图开发|MapLand 在线行政区划边界一键下载 GeoJSON 工具
前端·javascript·echarts
葡萄城技术团队3 小时前
工业数据可视化:使用活字格 AIcoding + Three.js 构建轻量化三维设备监控大屏
开发语言·javascript·信息可视化
默_笙4 小时前
🚍 一条 Todo 的奇幻漂流:TypeScript 全栈类型安全的"护照检查"
前端·javascript
weixin_422555425 小时前
el-menu子菜单点击就被激活,恢复之前的激活状态
javascript·vue.js·elementui
Tanjia_kiki7 小时前
谷歌浏览器中F12编辑并重发请求
开发语言·前端·javascript
honkun67 小时前
vue 表格组件 vxe-table 实现拖拽列字段自动生成透视表汇总
前端·javascript·vue.js
IMPYLH8 小时前
HTML 的 <p> 元素
前端·javascript·html