当前位置: 首页 > article >正文

【前端】JavaScript 作用域全面解析


在这里插入图片描述

博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳]
本文专栏: 前端

文章目录

  • 💯前言
  • 💯作用域简介
  • 💯全局作用域与局部作用域示例分析
    • 示例 1: 全局与局部变量
      • 分析:
    • 示例 2: 修改全局变量
      • 分析:
    • 示例 3: 局部变量遮蔽全局变量
      • 分析:
    • 示例 4: 隐式全局变量
      • 分析:
    • 示例 5: 严格模式下的隐式声明
      • 分析:
  • 💯补充
    • 3.1 块级作用域与变量提升
    • 3.2 作用域链与闭包
      • 示例:
    • 3.3 `this` 关键字与作用域
      • 示例:
    • 3.4 `if` 语句中的作用域
      • 示例:
    • 3.5 循环中的块级作用域
      • 示例:
  • 💯小结


在这里插入图片描述


💯前言

  • JavaScript 作为一种功能强大动态的编程语言,其灵活特性在现代前端开发中具有重要的作用。然而,正因为其灵活性,深入理解 JavaScript 中的作用域机制对于开发人员而言至关重要。作用域不仅决定了变量的可见性访问权限,同时也直接影响变量的生命周期。本篇文章将系统性地探讨 JavaScript 的作用域管理,包括全局作用域、函数作用域、块级作用域、以及隐式全局变量的细节分析,借助多个代码示例,以严谨的方式帮助读者深刻理解 JavaScript 中的作用域原理,从而编写出更加健壮可维护的代码。
    JavaScript在这里插入图片描述

💯作用域简介

在这里插入图片描述
在 JavaScript 中,作用域是指代码中变量和函数的可访问范围以及变量的生命周期。通过作用域的管理,我们能够控制哪些部分的代码可以访问某个特定变量,从而有效地避免变量命名冲突和提升代码的可维护性。JavaScript 中的作用域主要包括以下几种类型:

  • 全局作用域(Global Scope):变量声明在函数之外,能够在整个程序中访问和使用。
  • 函数作用域(Function Scope):函数作用域指的是变量只能在函数内部访问,函数作用域的变量通常是通过 var 关键字声明的。
  • 块级作用域(Block Scope):块级作用域是由 {} 包围的代码块,通常通过 letconst 关键字声明。块级作用域适用于控制结构(如 if 语句和 for 循环)等。

理解并掌握这些作用域的特点和用法是开发者编写高质量 JavaScript 代码的基础,尤其在开发规模较大、代码复杂度较高的项目时尤为重要。


💯全局作用域与局部作用域示例分析

在这里插入图片描述


示例 1: 全局与局部变量

在这里插入图片描述

var w = 10;
function fn() {
    var x = 10; // x 属于 fn 这个函数作用域内的变量
    console.log(w);
}
fn();
console.log(x); // 报错,因为 x 是局部变量,作用域只在 fn 内部
console.log(w); // 输出 10

分析:

  1. 全局变量 w

    • var w = 10; 定义了一个全局变量 w,它存在于全局作用域中,可以在代码中的任何地方访问。
  2. 局部变量 x

    • 在函数 fn 内部,var x = 10; 声明了局部变量 x,该变量的作用域仅限于 fn 函数内部。
    • 当函数 fn 执行完毕后,局部变量 x 被销毁,因此在函数外部访问 x 会导致引用错误。
  3. 作用域链

    • 在函数 fn 中调用 console.log(w) 时,JavaScript 引擎会首先查找局部作用域内是否有变量 w,由于没有找到,便继续沿着作用域链向外查找,直到找到全局作用域中的 w,从而输出 10

在这里插入图片描述


示例 2: 修改全局变量

var x = 10;
function fn() {
    x = 20; // 修改全局变量 x
}
fn();
console.log(x); // 输出 20,因为全局变量 x 的值被修改了

在这里插入图片描述


分析:

  1. 全局变量直接修改

    • 这里的 var x = 10; 定义了一个全局变量。
    • 在函数 fn 中,x = 20; 是对全局变量的直接赋值操作,因为在函数内部没有重新声明 x,所以函数内的 x 就是指向全局的 x,结果导致全局变量的值被修改为 20
  2. 没有局部变量

    • 因为在 fn 中没有使用 varletconst 重新声明 x,因此这里的 x 直接引用了全局作用域中的变量 x

在这里插入图片描述


示例 3: 局部变量遮蔽全局变量

var x = 10;
function fn() {
    var x = 20; // 局部变量 x,遮蔽了全局变量 x
}
fn();
console.log(x); // 输出 10,全局变量未被修改

在这里插入图片描述


分析:

  1. 局部变量遮蔽

    • 在函数 fn 中,var x = 20; 声明了一个新的局部变量 x,它只在 fn 函数内部有效,并且在函数内遮蔽了同名的全局变量。
    • 这种遮蔽意味着在函数内部对 x 的引用指向的是局部变量,而不是全局变量。
  2. 函数外部访问

    • 当函数执行完毕后,局部变量 x 被销毁,作用域回到全局。因此,console.log(x) 输出的仍然是全局变量的值 10,而非局部变量的值。

在这里插入图片描述


示例 4: 隐式全局变量

function fn() {
    x = 10; // 隐式全局变量(未声明)
}
fn();
console.log(x); // 输出 10

在这里插入图片描述


分析:

  1. 隐式全局变量

    • 在函数 fn 中,x = 10; 没有使用 varletconst 关键字进行声明,因此 JavaScript 会将 x 视为一个隐式的全局变量。
    • 这种隐式声明的方式容易导致意外的作用域污染,特别是在大型项目中,可能会导致难以调试的错误。
  2. 最佳实践

    • 始终显式声明变量,使用 letconstvar,避免创建隐式全局变量。

在这里插入图片描述


示例 5: 严格模式下的隐式声明

'use strict';
function fn() {
    x = 10; // 报错:x is not defined
}
fn();

在这里插入图片描述


分析:

  1. 严格模式
    • 使用 'use strict'; 启用严格模式,严格模式下禁止使用未声明的变量,从而防止隐式全局变量的创建。
    • 在严格模式下,未声明的变量会导致运行时错误,这样可以强制开发者在代码中明确声明所有变量,从而提升代码的可读性和安全性。

在这里插入图片描述


💯补充

在这里插入图片描述


3.1 块级作用域与变量提升

在 ES6 之前,JavaScript 中只有全局作用域和函数作用域,没有块级作用域。块级作用域是通过 letconst 引入的,这使得变量声明更加灵活。

  • letconst 的块级作用域

    • 通过 letconst 声明的变量具有块级作用域,只在所在的 {} 内有效。
    • 块级作用域可以有效避免变量冲突,特别是在循环和条件语句中。
  • 变量提升

    • var 声明的变量会被提升到作用域的顶部,但 letconst 不会被提升,因此它们在声明之前不能被访问。
    • 变量提升可能导致未定义行为(如访问未初始化的变量),使用 letconst 可以避免这种情况,从而增强代码的可维护性。

在这里插入图片描述


3.2 作用域链与闭包

作用域链是指在嵌套的函数中,内部函数可以访问外部函数的变量,甚至是全局变量。当一个函数内部引用了外部作用域中的变量时,就形成了闭包。闭包是 JavaScript 中非常重要的概念。
在这里插入图片描述

示例:

function outer() {
    var outerVar = "I am outer";
    function inner() {
        console.log(outerVar); // 输出 "I am outer"
    }
    return inner;
}
const innerFn = outer();
innerFn(); // 输出 "I am outer"

在这里插入图片描述
在这个例子中,inner 函数是 outer 函数的内部函数。即使 outer 执行结束,inner 函数依然保留对 outerVar 的访问权,这就是闭包的体现。

闭包的应用场景:闭包广泛用于创建私有变量、实现函数柯里化、以及工厂函数的设计模式中,可以有效减少全局变量的使用,提升代码的封装性和安全性。


3.3 this 关键字与作用域

this 关键字的值取决于函数的调用方式,而不是其声明位置。不同的调用方式可能导致 this 指向不同的对象。

  • 在全局作用域中,this 通常指向全局对象(在浏览器中是 window)。
  • 在函数中,严格模式下 thisundefined,而非严格模式下指向全局对象。
  • 在对象方法中调用时,this 指向调用该方法的对象。
    在这里插入图片描述

示例:

const obj = {
    value: 42,
    showValue: function() {
        console.log(this.value);
    }
};
obj.showValue(); // 输出 42

在这里插入图片描述
在这个例子中,showValue 方法中的 this 指向调用该方法的对象 obj,因此 console.log(this.value) 输出 42


3.4 if 语句中的作用域

if 语句中使用 var 声明的变量会被提升到函数或全局作用域,而使用 letconst 则会创建块级作用域。

在这里插入图片描述

示例:

if (true) {
    var x = 10;
    let y = 20;
    const z = 30;
}
console.log(x); // 输出 10
console.log(y); // 报错:y is not defined
console.log(z); // 报错:z is not defined

在这个例子中,x 是通过 var 声明的,因此它被提升到全局作用域,而 yz 则被限制在 if 块中。

在这里插入图片描述


3.5 循环中的块级作用域

在循环中使用 let 可以创建块级作用域,从而避免变量污染的问题,而 var 则会使变量在整个函数中都有效。

在这里插入图片描述


示例:

for (var i = 0; i < 3; i++) {
    setTimeout(() => console.log(i), 1000); // 输出 3, 3, 3
}

for (let j = 0; j < 3; j++) {
    setTimeout(() => console.log(j), 1000); // 输出 0, 1, 2
}

在上面的代码中,var i 会在全局作用域中被提升,因此当 setTimeout 执行时,i 的值已经变成了 3。而 let j 的作用域被限制在每次循环的块中,因此输出 0, 1, 2

在这里插入图片描述


💯小结

  • 在这里插入图片描述JavaScript 中的作用域是控制变量可访问性生命周期的核心机制。对作用域的深入理解能够帮助开发者更加高效地管理代码中的变量,从而避免常见的作用域污染变量冲突隐式全局变量等问题。
  1. 始终使用 letconst:避免使用 var,以便获得块级作用域,减少变量提升带来的不确定性。
  2. 启用严格模式:使用 'use strict' 强制执行严格的变量声明规则,避免隐式全局变量。
  3. 避免全局变量:尽量将变量限制在局部作用域内,减少全局变量带来的冲突风险。
  4. 显式声明变量:不要省略变量的声明,避免隐式创建全局变量。
  5. 使用闭包保持对外部变量的引用:闭包可以在函数执行结束后保留对外部变量的引用,是一种非常有用的特性。
  6. 慎用 this 关键字:理解 this 的行为,确保其指向正确的对象,避免由于调用方式不同而导致的错误。

在这里插入图片描述



http://www.kler.cn/a/408267.html

相关文章:

  • [面试]-golang基础面试题总结
  • 镁光MT25QU01GXXX norflash调试笔记
  • 银河麒麟v10 二进制kubeadm+containerd搭建k8s集群(证书100年)—— 筑梦之路
  • 分类算法——基于heart数据集实现
  • Mac 修改默认jdk版本
  • IDEA 2024.3 版本更新主要功能介绍
  • 【动态规划】“好数组”计数问题
  • y1重定义问题
  • 力扣刷题-excel表名称序列相转换
  • MyBatis---代理Dao方式的CRUD、MyBatis参数详解、MyBatis的配置文件
  • Tri Mode Ethernet MAC IP核详解
  • 摆烂仙君传——深度学习秘境奇缘
  • 网络爬虫总结与未来方向
  • maven传递性依赖的原则
  • Photino:通过.NET Core构建跨平台桌面应用程序,.net国产系统
  • C++ 中的模板特化和偏特化
  • R虚拟环境中安装ncdf4库包编译库问题
  • 骑砍2霸主MOD开发(29)-顶点动画
  • # DBeaver 连接hive数仓
  • 标贝科技大模型声音复刻 快速获取高品质专属AI声音
  • 【Rhino】【Python】Create a series of Blocks according to Value of object Property
  • 【042C】基于51RFID门禁系统(LCD12864显示)【Proteus仿真+Keil程序+报告+原理图】
  • Java基础:日期时间相关类
  • python基础导包
  • springmvc-04-Controller及RestFul
  • cocos creator 3.8 3D模型、天空盒、雾 6