javascript中的作用域链

news2024/9/22 7:03:31

在 JavaScript 中,作用域链 是一种用于解析变量的机制,它决定了在不同的上下文(或作用域)中如何查找和访问变量。作用域链与 JavaScript 的函数作用域、块级作用域紧密相关,是理解变量可见性和访问权限的关键。

1. 作用域链的基本概念

作用域
  • 作用域(Scope) 指的是代码中变量、函数和对象的可访问范围。
  • JavaScript 主要有三种作用域:
    • 全局作用域:在全局上下文中声明的变量或函数,可以在任何地方访问。
    • 函数作用域:在函数内声明的变量和函数,只能在该函数内访问。
    • 块级作用域:用 letconst 声明的变量具有块级作用域,只在 {} 代码块内有效。
作用域链的定义
  • 作用域链(Scope Chain) 是指当 JavaScript 引擎在函数中查找变量时,如果在当前作用域找不到,它会沿着作用域链向上一级作用域查找,直到找到这个变量或者到达全局作用域为止。
  • 作用域链的查找顺序是从内到外的,即由当前作用域逐层向上查找,直到全局作用域。如果在作用域链中找不到对应的变量,最终会返回 undefined 或抛出错误(如果是严格模式)。

2. 作用域链的形成

  • 当函数被创建时,其作用域链就会确定。作用域链的形成是因为函数在定义时记录了所在上下文的作用域。
  • 每个函数都会有自己的作用域,但函数可以访问父级作用域中的变量,这就是作用域链的关键。

3. 作用域链的查找机制

当 JavaScript 引擎需要查找一个变量时,它会遵循以下步骤:

  1. 当前作用域:首先,JavaScript 会从当前作用域查找变量。
  2. 父级作用域:如果当前作用域没有找到变量,它会沿着作用域链向父级作用域查找。
  3. 全局作用域:如果在所有父级作用域中都找不到变量,它会最终在全局作用域中查找。
  4. 未找到:如果在作用域链中都未找到该变量,则根据是否启用严格模式,返回 undefined 或抛出 ReferenceError

4. 作用域链的案例

4.1 简单函数作用域链
let globalVar = 'I am global';

function outerFunction() {
  let outerVar = 'I am in outerFunction';
  
  function innerFunction() {
    let innerVar = 'I am in innerFunction';
    
    // 依次查找变量,作用域链的顺序是:innerFunction -> outerFunction -> global scope
    console.log(innerVar);  // I am in innerFunction
    console.log(outerVar);  // I am in outerFunction
    console.log(globalVar); // I am global
  }
  
  innerFunction();
}

outerFunction();

解释

  • innerFunction 执行时,它的作用域链是从 innerFunction 本身开始的。
  • 如果 innerVarinnerFunction 内找到,则使用该变量。
  • 如果 outerVar 不在 innerFunction 内定义,JavaScript 会向上查找 outerFunction 的作用域,直到找到。
  • 如果没有找到 outerVar,再继续查找全局作用域中的变量 globalVar
4.2 函数嵌套与作用域链
let a = 10;

function first() {
  let b = 20;
  
  function second() {
    let c = 30;
    
    console.log(a); // 查找顺序:second -> first -> global,输出 10
    console.log(b); // 查找顺序:second -> first,输出 20
    console.log(c); // 查找顺序:second,输出 30
  }
  
  second();
}

first();

解释

  • second 函数内部定义了变量 c,但当它访问 ab 时,需要沿着作用域链向上查找。
  • second 函数的作用域链包含了它自己的作用域和 first 函数的作用域,以及全局作用域。
4.3 块级作用域与作用域链
let globalVar = 'global';

function checkScope() {
  let functionScopeVar = 'function scope';
  
  if (true) {
    let blockScopeVar = 'block scope';
    console.log(blockScopeVar); // block scope
    console.log(functionScopeVar); // function scope
    console.log(globalVar); // global
  }

  // 块级作用域外访问 blockScopeVar 会报错
  // console.log(blockScopeVar); // ReferenceError: blockScopeVar is not defined
}

checkScope();

解释

  • blockScopeVar 是通过 let 定义的块级作用域变量,因此只能在 if 块内访问。
  • blockScopeVar 被查找时,它首先会在块内找到。
  • functionScopeVar 在整个 checkScope 函数内都是可访问的,因为它是在函数作用域中定义的。
  • globalVar 是全局变量,因此可以在任何地方访问。

5. 作用域链的特点

  1. 词法作用域(静态作用域)

    • JavaScript 使用词法作用域,即函数的作用域在函数定义时就已经决定,而不是在函数调用时。
    • 因此,作用域链是基于函数的定义位置,而不是调用位置。
  2. 作用域链的层次结构

    • 每个函数调用时,都会有一个自己的作用域。
    • 如果作用域中没有找到某个变量,就会通过作用域链逐级向上查找,直到找到变量或到达全局作用域。
  3. 嵌套作用域

    • 函数可以在其内部定义其他函数,形成嵌套作用域。内层函数可以访问外层函数的变量,但外层函数不能访问内层函数的变量。
  4. 闭包与作用域链

    • 闭包是依赖于作用域链的。闭包是指一个函数能够记住并访问它的词法作用域,即使这个函数在词法作用域之外被调用。

    闭包案例

    function outer() {
      let outerVar = 'I am outer';
      return function inner() {
        console.log(outerVar); // 闭包机制:inner 函数访问 outer 的变量
      };
    }
    
    const innerFunc = outer();
    innerFunc(); // 输出: I am outer
    

    解释inner 函数可以记住并访问 outer 函数的 outerVar,即使 outer 函数已经执行结束。这是因为 inner 函数在定义时创建了一个闭包,保留了对其词法作用域的引用。

6. 作用域链的使用场景

  • 变量的可见性控制:通过不同的作用域,开发者可以限制某些变量的可见性,从而避免全局变量污染,保证代码的模块化。

  • 闭包应用:利用作用域链可以实现闭包,闭包在很多场景中(如回调函数、事件处理、数据封装等)都有广泛应用。

  • 模块化开发:在模块化开发中,通过作用域链可以实现变量的封装和私有化,避免全局变量的冲突。

7. 总结

  • 作用域链 是一种变量解析机制,决定了 JavaScript 如何在多层嵌套的函数和块中查找变量。
  • 作用域链的查找顺序是由内到外的,最终会查找到全局作用域。
  • 通过作用域链,可以在内层函数中访问外层函数的变量,而闭包是作用域链的一个重要应用场景。
  • 使用作用域链,可以更好地控制变量的可见性和生命周期,从而编写出更模块化、更健壮的代码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2154509.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++ | Leetcode C++题解之第423题从英文中重建数字

题目&#xff1a; 题解&#xff1a; class Solution { public:string originalDigits(string s) {unordered_map<char, int> c;for (char ch: s) {c[ch];}vector<int> cnt(10);cnt[0] c[z];cnt[2] c[w];cnt[4] c[u];cnt[6] c[x];cnt[8] c[g];cnt[3] c[h] - …

JavaScript使用leaflet库显示信息窗口

前言 我们可千万不能忘记我们之前花的流程图哦&#xff0c;我们所有的计划都按照我们的流程图来去构建&#xff1b; 我们已经完成了&#xff0c;页面的加载&#xff0c;也已经完成获取用户当前的位置坐标&#xff0c;并且我们通过地图的API将当前的位置在地图中渲染出来&…

【每日刷题】Day128

【每日刷题】Day128 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. 606. 根据二叉树创建字符串 - 力扣&#xff08;LeetCode&#xff09; 2. LCR 194. 二叉树的最近公…

TryHackMe 第3天 | Pre Security (中)

该学习路径讲解了网络安全入门的必备技术知识&#xff0c;比如计算机网络、网络协议、Linux命令、Windows设置等内容。上一篇中简短介绍了计算机网络相关的知识&#xff0c;本篇博客将记录 网络协议 部分。 How the web works? DNS in detail DNS (Domain name system&…

【数据结构】排序算法系列——快速排序(附源码+图解)

快速排序 接下来我们将要介绍的是排序中最为重要的算法之一——快速排序。 快速排序&#xff08;英语&#xff1a;Quicksort&#xff09;&#xff0c;又称分区交换排序&#xff08;partition-exchange sort&#xff09;&#xff0c;最早由东尼霍尔提出。快速排序通常明显比其…

XXL-JOB环境搭建

2.快速入门 2.1 下载源码 a.源码下载地址: github地址 gitee地址 2.2.环境搭建&#xff1a; a.初始化调度数据库: 1.请下载项目源码并解压&#xff0c;获取 “调度数据库初始化SQL脚本” 并执行即可 b.编译源码: 1.解压源码,按照maven格式将源码导入IDE, 使用maven进行…

【Python】使用国内镜像安装conda并创建python环境

conda介绍&#xff1a; Conda 是一个开源的包管理系统和环境管理系统&#xff0c;由 Continuum Analytics 开发。它的主要作用是简化科学计算中软件包和依赖的安装和升级&#xff0c;并允许用户轻松地在不同的环境中切换。Conda 的设计初衷是为了简化 Python 环境的搭建和管理&…

海洋大地测量基准与水下导航系列之二国外海底大地测量基准和海底观测网络发展现状(上)

海底大地控制网建设构想最先由美国斯克里普斯海洋研究所(Scripps Institution of Oceanography,SIO)提出&#xff0c;目前仅有少数发达国家具备相应技术条件。美国、日本、俄罗斯和欧盟等发达国家通过布测先进的海底大地控制网&#xff0c;不断完善海洋大地测量基准基础设施&am…

go 运行报错missing go.sum entry for module providing package

运行&#xff1a; #清理go.mod中不再需要的模块&#xff0c;并且会添加缺失的模块条目到go.sum中 go mod tidy

【全网最全】2024华为杯数学建模C题高质量成品查看论文!【附带全套代码+数据】

题 目&#xff1a; ___基于数据驱动下磁性元件的磁芯损耗建模 完整版获取&#xff1a; 点击链接加入群聊【2024华为杯数学建模助攻资料】&#xff1a;http://qm.qq.com/cgi-bin/qm/qr?_wv1027&kxtS4vwn3gcv8oCYYyrqd0BvFc7tNfhV7&authKeyedQFZne%2BzvEfLEVg2v8FOm%…

线段树优化dp,CF 413E - Maze 2D

目录 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 二、解题报告 1、思路分析 2、复杂度 3、代码详解 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 413E - Maze 2D 二、解题报告 1、思路分析 对于(li, l) -> (ri, r) …

nginx upstream转发连接错误情况研究

本次测试用到3台服务器&#xff1a; 192.168.10.115&#xff1a;转发服务器A 192.168.10.209&#xff1a;upstream下服务器1 192.168.10.210&#xff1a;upstream下服务器2 1台客户端&#xff1a;192.168.10.112 服务器A中nginx主要配置如下&#xff1a; log_format main…

接口加解密及数据加解密

目录 一、 加解密方式介绍 1.1 Hash算法加密 1.2. 对称加密 1.3 非对称加密 二、 我们要讲什么&#xff1f; 三、 接口加解密 四、 数据加解密 一、 加解密方式介绍 所有的加密方式我们可以分为三类&#xff1a;对称加密、非对称加密、Hash算法加密。 算法内部的具体实现…

Mysql高级篇(中)—— SQL优化之查询截取分析

SQL优化之查询截取分析 一、慢查询日志&#xff08;1&#xff09;简述&#xff08;2&#xff09;如何开启&#xff08;3&#xff09;慢查询日志分析工具介绍(了解)&#xff08;4&#xff09;官方工具 mysqldumpslow简述如何使用 二、SHOW PROCESSLIST三、&#xff08;了解&…

网络安全详解

目录 引言 一、网络安全概述 1.1 什么是网络安全 1.2 网络安全的重要性 二、网络安全面临的威胁 2.1 恶意软件&#xff08;Malware&#xff09; 2.2 网络钓鱼&#xff08;Phishing&#xff09; 2.3 中间人攻击&#xff08;Man-in-the-Middle Attack&#xff09; 2.4 拒…

让C#程序在linux环境运行

今晚花一些时间&#xff0c;总结net程序如何在linux环境运行的一些技术路线。 1、采用.Net Core框架 NET Core 使用了 .NET Core Runtime&#xff0c;它可以在 Windows、Linux 和 macOS 等多个操作系统上运行。可以采用Visual Studio生成Linux版本的dll。 在Linux系统中&…

救生圈检测系统源码分享

救生圈检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Visio…

Python基础学习(3)

目录 一&#xff0c;函数 1&#xff0c;函数的定义 2&#xff0c;函数的参数 1&#xff0c;默认值 2&#xff0c;传参 3&#xff0c;返回值 4&#xff0c;变量的作用域 5&#xff0c;函数的调用 二&#xff0c;常用数据结构 1&#xff0c;列表 列表的定义 列表的特性…

机器学习的应用领域

机器学习在许多领域有广泛的应用&#xff0c;下面列出了一些主要的应用领域及其典型应用&#xff1a; 1. 图像识别 人脸识别&#xff1a;用于解锁手机、自动标记照片、监控安全系统。物体识别&#xff1a;应用于自动驾驶汽车、机器人、医疗影像分析中&#xff0c;帮助机器理解…

vue3 TagInput 实现

效果 要实现类似于下面这种效果 大致原理 其实是很简单的,我们可以利用 element-plus 组件库里的 el-tag 组件来实现 这里我们可以将其抽离成一个公共的组件,那么现在有一个问题就是通讯问题 这里我们可以利用父子组件之间的通讯,利用 v-model 来实现,父组件传值,子组…