JS 执行上下文和作用域

news2024/9/20 19:24:20

与JS 中的作用域一同出现的还有一个执行上下文(execution context)的概念,这两个概念容易混淆,今天就来聊聊他们。

作用域

作用域是指程序源代码中定义变量、函数的区域,它规定了变量和函数可以访问哪些数据以及他们的行为。简单来说就和我们的行政划分是一样的,假如我在湖北省,那么在湖南省就找不到我的信息。

作用域本质上是一个对象, 作用域中的变量、函数可以理解为是该对象的成员,并且 JS 是词法作用域,函数的作用域在函数定义的时候就决定了,也就是说 JS 中函数的作用域在代码编写阶段就确定了。
在这里插入图片描述

有一个内部属性 [[scope]](仅供 JS 引擎调用),它是一个数组,当函数创建的时候,就会保存所有父级变量对象到其中,这就是所谓的 作用域链

下面这段代码打印的是 123,充分说明了函数的作用域是在声明函数时就确定了的,否则如果在运行时才确定,那么 fn 所在就是 show 函数,继而在 test 函数作用域内,输出的就应该是 345 了。

var b = 123;
function fn() {
  console.log(b);
}
function test(fn) {
  let b = 345;
  function show() {
    fn();
  };
  show();
}
test(fn);

JS 中有全局作用域和函数作用域,全局作用域浏览器中就是 window 下(红色框),函数作用域就是函数内部(黄色框),ES6 新增了块级作用域(蓝色框),一对 {} 会生成一个新的作用域。作用与内部的成员不能被其父级作用域访问但可以被子级作用域访问。

在 Web 浏览器中,全局作用域被认为是 window 对象,因此所有全局变量和函数都是作为 window 对象的属性和方法创建的。
在 Node环境中,全局作用域是 global 对象。

在这里插入图片描述

作用域的作用

安全:变量只能在特定的区域内才能被访问,外部环境不能访问内部环境的任何变量和函数,可以避免在程序其它位置意外对某个变量做出修改导致程序发生事故。
减轻命名的压力:可以在不同的作用域内定义相同的变量名,并且这些变量名不会产生冲突。

执行上下文

前端的朋友都知道 JS 代码是从上到下顺序执行的,下面这段代码就会顺序在控制台打印 1 2 3

console.log(1);
console.log(2);
console.log(3);

你可能会以为 JS 引擎会一行一行地编译并执行程序,其实不然 JS 代码是按块执行的,块的划分标准就是:全局代码、函数代码、eval代码。在分析执行的时候就按照全局代码、函数代码···这样一块一块的执行。在执行一块代码的时候就会创建执行上下文。

执行上下文有一个特点:当函数执行的时候创建执行上下文,函数执行完毕就销毁该执行上下文。

三个重要属性

在这里插入图片描述

  • 变量对象:
    每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。我们编写的代码无法访问。只有当进入一个执行环境时,这个执行上下文的变量对象才会被激活,此时成为活动对象,只有活动对象上的属性才能被访问。
  • 作用域链:
    当代码在一个环境中执行时,会创建变量对象的一个作用域链。保证对执行环境有权访问的所有变量和函数的有序访问。
  • this

执行上下栈

我们在执行一个 JS 程序的时候肯定会有函数之间的调用关系之类的,那就说明,同一时刻会创建多个执行上下文,JS 此时就会创建执行上下文栈结构来管理所有的执行上下文。

看下面这段代码及分析。在执行 JS 代码时,最先遇到全局代码,首先创建全局执行上下文,并将全局上下文压入执行上文栈中,又遇到 test 函数调用,所以又创建函数上下文并压入栈中,函数代码执行完后再把函数执行上下文从栈中弹出销毁,继续执行全局代码发现也执行完毕,就将全局执行上下文从栈中弹出销毁,结束。这里我们可以发现全局执行上下文永远是第一个被创建压栈,最后一个弹栈销毁

var a = 123;
function test() {
  let b = 345;
}
test();

执行上下文的细节

说了这么多执行上下文,那么它到底是个什么东西呢?JS 引擎在它创建到销毁又会做些什么工作呢?

创建

此时还没有执行代码,根据函数的[[scope]]属性创建作用域链,用 arguments 创建活动对象并初始化,形参为传入的值,内部变量声明后均为 undefined ,函数声明。如下例子

function test() {
  let b = 345;
  function me() { };
  if (b > 200) {
    console.log('b大于200')
  }
}
test();

此时的活动对象为

AO = {
    arguments: {
        length: 0
    },
    b: undefined,
    me: reference to function me(){},
}

再将活动对象插到作用域链的首部。

执行代码

此时的活动对象为

AO = {
    arguments: {
        length: 0
    },
    b: 345,
    me: reference to function me(){},
}

变量查找

在执行console.log(b)这一行代码时,会先从作用域链的首部开始查找即当前函数的活动对象,找到就输出值,找不到就在后边一个作用域(即父级作用域)中找,如果已经到了全局作用域,仍然找不到该变量,就会直接报错。

var b = 123;
function fn() {
  console.log(b);
}
function test(fn) {
  let b = 345;
  function show() {
    fn();
  };
  show();
}
test(fn);

此时我们再来分析一下这段代码:

  1. 函数声明后:
    • fn.[[scope]]:[全局变量对象]
    • test.[[scope]]:[全局变量对象]
    • show.[[scope]]:[test 变量对象,全局变量对象]
  2. 开始运行后
    • fn 作用域链:[fn 函数活动对象,全局活动对象]
    • test 作用域链:[test 函数活动对象,全局活动对象]
    • show 作用域链:[show 函数活动对象,test 函数活动对象,全局活动对象]
  3. 执行console.log(b);时:从 fn 函数的作用域链首部(fn 函数活动对象)开始查找变量 b,没找到,在全局活动对象中查找变量 b,找到了,打印。

销毁

test 函数执行完毕,将执行上下文弹栈销毁。

我是孤城浪人,一名正在前端路上摸爬滚打的菜鸟,欢迎你的关注。

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

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

相关文章

C语言和汇编语言混合编程

ATPCS ATPCS的全称是ARM-Thumb Procedure Call Standard,其核心内容就是定义了ARM子程序调用的基本规则及堆栈的使用约定等。如ATPCS规定了ARM程序要使用满递减堆栈,入栈/出栈操作要使用STMFD/LDMFD指令,只要所有的程序都遵循这个约定&#…

前端开发环境部署问题

很多开发者到了一家新公司,公司发了一台新电脑,对环境安装比较困惑。今天带大家还原,拿到公司电脑,如何安装你需要的各种环境。 一、node按装 官网下载地址: http://nodejs.cn/download/ 根据自己需要下载对应的版本…

深度 | Web 3.0时代去中心化IM 的挑战与思考

前言 Web3.0时代的重要特点: 1、数据主权 用户将拥有自己的数据主权,用户所创造的数字内容,所有权和控制权都归属于用户,用户所创造的价值可以由用户自主支配。对于IM业务,就是用户的好友列表,聊天消息等…

windowXP系统无法正常访问vue3网页

开发完的vue3项目需要在XP系统环境使用 由于在立项时采用了开发成本较低速度较快的vue3技术栈,并没有考虑到工厂的设备仍然在试用二十年前的机器,导致项目上线后有部分人员打开页面展示白屏。 经过排查,发现由于vue3使用ES6的Proxy代理实现响…

Linux-目录结构及文件基本操作

目录1、Linux目录结构1.1 FHS标准1.2 目录路径2、Linux文件的基本操作2.1 新建2.2 复制2.3 删除2.4 移动文件与文件重命名2.5 查看文件2.6 查看文件类型2.7 编辑文件1、Linux目录结构 Linux的目录结构和Windows的目录结构在实现上是完全不同的 Windows以存储介质为主&#xff…

Vue-Cli 脚手架 搭建 Vue项目

本篇目开始进行Vue基于项目中的介绍,Vue-cli 是官方提高用于搭建基于 Vue、Webpack、ES6 项目目的脚手架工具,可以前往在线官网查看:—— 官方文档 | Vue CLI 。 安装npm 1. 检测是否安装了Node.js ,未安装请前往下载;…

【内网安全-隧道搭建】内网穿透_Ngrok上线(美版、国版二开)

目录 一、准备 1、意义: 2、项目: 二、内网穿透 1、简介: 三、Ngrok(入门上线) 1、简述: 2、Ngrok入门上线(国版二开) 3、相关工具: 2、Ngrok入门上线&#xff…

低代码开发平台|SRM-招投标管理搭建指南

1、简介1.1、案例简介本文将介绍,如何搭建SRM-招投标管理。1.2、应用场景企业根据采购需求创建招投标需求,选择供应商进行邀标,供应商报名再投标,投标结束评标人员对投标项目进行评估。2、设置方法2.1、表单搭建1)新建…

Python build Exe 使用PyInstaller创建可执行的Python脚本

在本指南中,您将看到如何使用PyInstaller创建Python脚本的可执行文件? 下面是在Windows中实现这一目标的完整步骤。 使用PyInstaller创建可执行文件的步骤 步骤1:添加Python到Windows路径 首先,您可能想要将Python添加到Windows路径。 将Python添加到…

Spring Boot整合Redis笔记

文章目录前言Java 操作 RedisJedis 操作-测试Jedis 实例-手机验证码Redis与Spring Boot整合整合步骤Redis 的事务操作Redis的事务定义Multi、Exec、discard 基本命令事务冲突的问题为什么要做成事务悲观锁乐观锁WATCH key [key ... ]Redis事务三特性Redis事务秒杀案例解决计数器…

分布式定时任务-XXL-JOB-教程+实战

一.定时任务概述 1.定时任务认识 1.1.什么是定时任务 定时任务是按照指定时间周期运行任务。使用场景为在某个固定时间点执行,或者周期性的去执行某个任务,比如:每天晚上24点做数据汇总,定时发送短信等。 1.2.常见定时任务方案…

docker-compose容器编排部署

docker-compose部署微服务1、Docker-Compose是什么?2、应用场景3、docker-compose部署SpringBoot项目3.1 编写Dockfile3.2 编写docker-compose.yaml3.3 修改工程配置3.4 将相关文件上传到服务器3.5 执行docker-compose up本文是对DockerNginx打包部署前后端分离项目…

E5061B矢量网络分析仪VNA概念

矢量网络分析仪VNA是一种测试仪器,它可以将网络的响应测量成矢量:实参数和虚参数,从而表征其性能。矢量网络分析仪VNA是射频设计实验室和许多制造和服务领域的重要测试仪器。虽然矢量网络分析仪主要侧重于研究和开发,但它也可以为所有类型的R…

2月3日 读书笔记

我们将程序改善一下,让程序在按下一个键后不结束,而是把所按键的编码在画面上显示出来,这样就可以切实完成中断处理程序了。 所谓中断处理,基本上就是打断CPU本来的工作,加塞要求进行处理。而且处理中断期间不再接收别…

创业30载,百亿市值奥瑞金未来可期

1994年,关玉香在海南文昌破土兴建海南奥瑞金包装实业有限公司(原名:文昌奥瑞金制罐公司),与儿子周云杰一起带领着16名工人进入了金属包装行业,从0到如今的百亿市值,就此拉开了一路“封神”的序幕…

字符串(一)BF算法与KMP算法

给一个主串s,在给一个子串substr,判断substr是否为s的子串 一、BF 暴力搜索 暴力,依次逐个比较字符,先从主串和模式串的第一个字符开始,如果相等一起比较下一个字符,如果不相等,那么重新回到模…

PTA L1-032 Left-pad(详解)

前言:本期是关于L1-032 Left-pad的详解,内容包括四大模块:题目,代码实现,大致思路,代码解读,今天你c了吗? 题目: 根据新浪微博上的消息,有一位开发者不满NPM…

SpringCloud Alibaba—— 微服务网关GateWay

目录 1、GateWay网关概述 1.1、什么是GateWay? 1.2、为什么要使用微服务网关? 1.3、Zuul与GateWay网关的区别? 2、快速入门 2.1、创建项目 2.2、配置yml文件 2.3、controller层 2.4、启动类 2.5、启动整体项目 2.6、配置全局过滤器…

代码随想录算法训练营第十七天 | 110.平衡二叉树,257. 二叉树的所有路径,404.左叶子之和

一、昨日回顾与补充今天看了Day16讲解的视频,对于求二叉树最大深度、最小深度以及求完全二叉树的节点个数有了新的理解,总结如下:1.深度和高度的区别(之前就看看定义忽略了)二叉树节点的深度:指从根节点到该…

jvm垃圾收集器有哪些

Serial收集器 Serial收集器是最基本,发展最悠久的收集器,在JDK1.3.1之前是虚拟机新生代垃圾回收的唯一选择。这个收集器是一个单线程的。它的单线程的意义并不仅仅说明它只会使用一个CPU或者一条收集线程去完成收集工作,最重要的是&#xff…