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

【前端】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.mrgr.cn/news/77981.html

相关文章:

  • NuGet如何支持HTTP源
  • SpringBoot+SpringCloud面试题整理附答案
  • 深度学习笔记之BERT(二)BERT精简变体:ALBERT
  • 数据结构 (8)线性表的应用——一元多项式的表示及应用
  • 如何在 Ubuntu 22 04 上安装和配置 Ansible 自动化平台
  • 大数据新视界 -- Hive 数据分区:精细化管理的艺术与实践(上)(7/ 30)
  • 编程中的快捷操作
  • 运维Tips:Docker或K8s集群拉取Harbor私有容器镜像仓库配置指南
  • .net core MVC入门(一)
  • 三汇&网易|认知实习报告
  • 【CSP CCF记录】201812-2第15次认证 小明放学
  • 华为昇腾 acl_pytorch
  • Node教程和实战
  • MCU(一) 时钟详解 —— 以 GD32E103 时钟树结构为例
  • C++设计模式-模板模式,Template Method
  • Vue 中 data 属性为函数的深度剖析:原理、区别与实践
  • aws服务--机密数据存储KMS(1)介绍和使用
  • 16:(标准库)ADC三:使用外部触发启动ADC/模拟看门狗
  • [OpenHarmony5.0][环境][教程]OpenHarmony 5.0源码在WSL2 Ubuntu22.04 编译环境搭建教程
  • C++设计模式-策略模式-StrategyMethod
  • 分割一切2.0,SAM2详解
  • 接口性能优化宝典:解决性能瓶颈的策略与实践
  • java 二分查找 方法 详解
  • 虚幻引擎---术语篇
  • 4.SynchronousMethodHandler
  • Spring Boot 动态数据源切换