JavaScript相关(一)——作用域

本篇将从JS的执行上下文开始,去理解:变量提升、 栈式调用、作用域和闭包。

参考:
浏览器工作原理与实践

JS执行上下文

执行上下文是 JavaScript 执行一段代码时的运行环境,比如调用一个函数,就会生成这个函数的执行上下文,确定该函数在执行期间用到的诸如 this、变量环境、词法环境、外部环境引用等。

JS引擎执行JS代码分为两部分,第一部分是编译、第二部分才是执行,在编译阶段,会做变量提升等操作,生成JS执行上下文。
JS执行上下文中包含变量环境,变量提升的变量都存储在这里面,包括用户声明的变量以及函数声明变量,里面还包括指向外部变量环境的引用(作用域链查找)、词法环境,存储块级变量声明,即const\let声明的量,在生成了执行上下文后,才会继续执行JS可执行的代码。

执行时,需要从作用域中查询某个变量,具体查询办法是:沿着词法环境的栈顶向下查询,如果在词法环境中的某个块中查找到了,就直接返回给 JavaScript 引擎,如果没有查找到,那么继续在变量环境中查找。

showName()
console.log(myname)
showName1()var myname = '!!!'
function showName() {console.log('函数showName被执行');
}
var showName1 = function () {console.log('函数showName1被执行');
}// 输出
函数showName被执行
undefined
Error:showName1 is not a function如果showName1声明 var改成const Error:showName1 is not defined

说明:
变量的生成涉及到 声明、赋值两个阶段。在声明阶段JS引擎会把变量和函数的声明提升到代码开头执行,因此showName可以被执行,myname被默认赋值为undefined,但是showName1是一个变量赋值,它一开始只是提升了声明,因此showName1是undefined,会报错not a function。

var的创建和初始化被提升,赋值不会提升。
let的创建被提升,初始化和赋值不会提升。
function的创建、初始化和赋值都被提升。

变量提升,是指在 JavaScript 代码执行过程中,JavaScript 引擎把变量的声明部分和函数的声明部分提升到代码开头的“行为”。变量被提升后,会给变量设置默认值,这个默认值就是我们熟悉的 undefined。变量提升操作并不会直接在代码里显现出来,它是在JS代码的编译阶段完成的。

为什么要引入块级作用域
因为会存在着变量覆盖、无法自动回收全局变量导致占用内存 等设计缺陷,所以 ES6 引入了块级作用域关键字来解决这些问题。

作用域

作用域是指在程序中定义变量的区域,该位置决定了变量的生命周期。通俗地理解,作用域就是变量与函数的可访问范围,即作用域控制着变量和函数的可见性和生命周期
作用域在编码时就确定了, 不会再变化,可以用于隔离变量, 在不同作用域定义同名的变量不冲突。

作用域链:多个嵌套的作用域形成的由内向外的结构, 用于查找变量

分类:
  1. 全局作用域:全局作用域中的对象在代码中的任何地方都能访问,其生命周期伴随着页面的生命周期。
  2. 函数作用域:函数作用域就是在函数内部定义的变量或者函数,并且定义的变量或者函数只能在函数内部被访问。函数执行结束之后,函数内部定义的变量会被销毁。
  3. 块级作用域。
区别作用域与执行上下文

作用域: 静态的, 编码时就确定了(不是在运行时), 一旦确定就不会变化了
执行上下文: 执行代码时在编译阶段动态创建, 当执行结束消失
联系: 执行上下文环境是在对应的作用域中的

作用域链

function bar() {console.log(myName)
}
function foo() {var myName = "极客邦"bar()
}
var myName = "极客时间"
foo()

分析:

答案是会输出:极客时间。

为什么bar查询的作用域链不会指向foo的作用域链,而是指向全局?
因为作用域链的生成由函数声明的位置决定,和调用位置、调用栈无关。

要回答这个问题,你还需要知道什么是词法作用域
这是因为在 JavaScript 执行过程中,其作用域链是由词法作用域决定的。
词法作用域词法作用域就是指作用域是由代码中函数声明的位置来决定的,所以词法作用域是静态的作用域,通过它就能够预测代码在执行过程中如何查找标识符。

块级作用域
function bar() {var myName = "极客世界"let test1 = 100if (1) {let myName = "Chrome浏览器"console.log(test)}
}
function foo() {var myName = "极客邦"let test = 2{let test = 3bar()}
}
var myName = "极客时间"
let myAge = 10
let test = 1
foo()

分析:
顺序由图中所示

可以由图里知道,一个变量 作用域链会先查词法环境、再查变量环境,接下来顺着外部引用,依次查询词法环境、变量环境。
因此会输出:1

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

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

相关文章

『运维备忘录』之 Ansible 自动化运维工具

一、简介 Ansible是基于Python开发,集合了众多运维工具(puppet、cfengine、chef、func、fabric)的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能的自动化运维工具,广泛用于配置管理、应用部署以及任务协…

ES节点故障的容错方案

ES节点故障的容错方案 1. es启动加载逻辑1.1 segment和translg组成和分析1.2 es节点启动流程1.3 es集群的初始化和启动过程 2. master高可用2.1 选主逻辑2.1.1 过滤选主的节点列表2.1.2 Bully算法2.1.2 类Raft协议2.1.3 元数据合并 2.2 HA切换 3. 分片高可用3.1 集群分片汇报3.…

不同进制之间的转换

目录 前言进制转换10进制转2进制方法1方法2 2进制转10进制10进制转n进制n进制转10进制2进制与8进制和16进制之间的快速转换 代码实现10进制转n进制CPython n进制转10进制CPython 结尾 本文由Jzwalliser原创,发布在CSDN平台上,遵循CC 4.0 BY-SA协议。 因此…

DoWhy:Python 中的因果推断库

DoWhy:Python 中的因果推断库 DoWhy 是一个强大的 Python 库,用于因果推断和因果推断分析。本文将介绍 DoWhy 的基本概念、主要功能和使用方法,帮助读者了解如何利用该库进行因果推断,并解决因果关系的相关问题。 什么是DoWhy&…

MySQL-管理

一、系统数据库 MySQL数据库安装完成后,自带了一下四个数据库,具体作用如下: 数据库含义mysql存储MySQL服务器正常运行所需要的各种信息(时区、主从、用户、权限等)information_schema提供了访问数据库元数据的各种表…

containerd中文翻译系列(十三)流处理器

处理器 API 处理器是一种二进制 API,可通过内容流工作。 传入的内容流将通过 STDIN 理程序,而流处理程序将在 STDOUT "上输出处理后的数据流。 如果遇到错误,必须通过 STDERR 返回错误信息,同时返回非零退出状态。 可以通…

备战蓝桥杯---动态规划(理论基础)

目录 动态规划的概念: 解决多阶段决策过程最优化的一种方法 阶段: 状态: 决策: 策略: 状态转移方程: 适用的基本条件 1.具有相同的子问题 2.满足最优子结构 3.满足无后效性 动态规划的实现方式…

2024年【R2移动式压力容器充装】考试内容及R2移动式压力容器充装免费试题

题库来源:安全生产模拟考试一点通公众号小程序 R2移动式压力容器充装考试内容参考答案及R2移动式压力容器充装考试试题解析是安全生产模拟考试一点通题库老师及R2移动式压力容器充装操作证已考过的学员汇总,相对有效帮助R2移动式压力容器充装免费试题学…

【Java八股面试系列】JVM-内存区域

目录 Java内存区域 运行时数据区域 线程独享区域 程序计数器 Java 虚拟机栈 StackFlowError&OOM 本地方法栈 线程共享区域 堆 GCR-分代回收算法 字符串常量池 方法区 运行时常量池 HotSpot 虚拟机对象探秘 对象的创建 对象的内存布局 句柄 Java内存区域 运…

网络套件字(理论知识)

一、源IP地址和目的IP地址 上次说到IP地址是为了是为了让信息正确的从原主机传送到目的主机,而原IP地址和目的IP地址就是用于标识两个主机的,既然叫做地址必然有着路径规划的作用,而路径规划最重要的就是,从哪来到哪去&#xff0…

【C++】友元:友元函数与友元类

一、友元 友元&#xff08;friend&#xff09;是C中的一种特殊关系&#xff0c;用于在类之间共享访问权限。通过将一个函数或类声明为另一个类的友元&#xff0c;我们可以允许友元访问声明类的非公有成员。 二、友元函数 问题&#xff1a;现在尝试去重载operator<<&am…

机器人学、机器视觉与控制 上机笔记(第一版译文版 2.1章节)

机器人学、机器视觉与控制 上机笔记&#xff08;第一版译文版 2.1章节&#xff09; 1、前言2、本篇内容3、代码记录3.1、新建se23.2、生成坐标系3.3、将T1表示的变换绘制3.4、完整绘制代码3.5、获取点*在坐标系1下的表示3.6、相对坐标获取完整代码 4、结语 1、前言 工作需要&a…

简单说网络:TCP+UDP

TCP和UPD: (1)都工作在传输层 (2)目的都是在程序之中传输数据 (3)数据可以是文本、视频或者图片(对TCP和UDP来说都是一堆二进制数没有太大区别) 一、区别:一个基于连接一个基于非连接 将人与人之间的通信比喻为进程和进程之前的通信:基本上有两种方式(1)写信;(2)打电话;这…

Docker容器化K8s集群部署教程(一键部署sheel脚本)

本文通过脚本&#xff0c;可以快速地部署和配置Kubernetes环境&#xff0c;省去了各插件手动部署、配置的繁琐过程。 先看最终结果&#xff1a; [rootlocalhost home]# kubectl get node NAME STATUS ROLES AGE VERSION k8smaster Ready control-p…

LlamaIndex 入门实战

文章目录 LlamaIndex 入门实战1. 基本概念2. 优劣势分析3. 简单代码示例4. Index持久化5. 使用场景6. 总结 LlamaIndex 入门实战 LlamaIndex是一个连接大型语言模型&#xff08;LLMs&#xff09;与外部数据的工具&#xff0c;它通过构建索引和提供查询接口&#xff0c;使得大模…

Java学习17-- super类

重点&#xff1a;super类 & 方法重写 super类 super指的是本级的上一级&#xff0c;即father class父类 很好理解&#xff0c;比如Person class>Student class 当前在Student class执行&#xff0c;那么就写this.xxx 需要在Student程序里面调用Person&#xff0c;那就…

HarmonyOS应用/服务发布:打造多设备生态的关键一步

目前 前言HarmonyOS 应用/服务发布的重要性使用HarmonyOS 构建跨设备的应用生态前期准备工作简述发布流程生成签名文件配置签名信息编译构建.app文件上架.app文件到AGC结束语 前言 随着智能设备的快速普及和多样化&#xff0c;以及编程语言的迅猛发展&#xff0c;构建一个无缝…

UMLChina公众号精选(20240207更新)

UMLChina服务 如何选择UMLChina服务 《软件方法》分步改进指南 做对《软件方法》强化自测题获得“软件方法建模师”称号 建模示范视频 [EA-029/石油钻井管理平台]35套UML/SysMLEA/StarUML的建模示范视频-全程字幕 UMLChina连EA经销商都不是&#xff0c;EA水平靠谱嘛&#xff1f…

大数据 - Spark系列《四》- Spark分布式运行原理

Spark系列文章&#xff1a; 大数据 - Spark系列《一》- 从Hadoop到Spark&#xff1a;大数据计算引擎的演进-CSDN博客 大数据 - Spark系列《二》- 关于Spark在Idea中的一些常用配置-CSDN博客 大数据 - Spark系列《三》- 加载各种数据源创建RDD-CSDN博客 目录 &#x1f360;…

jmeter-06常用的几种断言方式

文章目录 一、jmeter常用的几种断言二、响应断言1.设置介绍1.1apply to1.2测试字段1.3模糊匹配1.4 测试模式2.举例二、json断言1、响应数据2、断言设置2、postman对比3、断言成功与断言失败的结果图四、持续时间断言1、为什么要做持续时间断言?2、举例