JS的作用域链是静态的,它的取值是在创建阶段而不是调用阶段

2024-01-20 20:52

本文主要是介绍JS的作用域链是静态的,它的取值是在创建阶段而不是调用阶段,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

问题

对于下面这段代码,您觉得会输出什么?

 var x = 10
function fn() {console.log(x)
}
function show(f) {var x = 20;(function () {f() // 10,而不是 20})()
}
show(fn)

由于第8行的f()执行的就是第2行定于你的fn()函数,而第二行的函数fn()的创建是在全局作用域下的,所以无论在哪里调用函数fn()里面输出的x都是读取的是全局的x,在这里就会输出10

前置知识

运行 JavaScript 代码时,当代码执行进入一个环境时,就会为该环境创建一个执行上下文,它会在你运行代码前做一些准备工作。接下来我们就来看一下具体会做哪些准备工作。

具体要做的事,和执行上下文的生命周期有关。

执行上下文的生命周期有两个阶段:

  1. 创建阶段(进入执行上下文):函数被调用时,进入函数环境,为其创建一个执行上下文,此时进入创建阶段。
  2. 执行阶段(代码执行):执行函数中代码时,此时执行上下文进入执行阶段。

创建阶段

创建阶段要做的事情主要如下:

  1. 创建变量对象(VO:variable object

    • 确定函数的形参(并赋值

    • 函数环境会初始化创建 Arguments对象(并赋值

    • 确定普通字面量形式的函数声明(并赋值

    • 变量声明,函数表达式声明(未赋值

  2. 确定 this 指向(this 由调用者确定

  3. 确定作用域(词法环境决定,哪里声明定义,就在哪里确定

这里有必要说一下变量对象。

当处于执行上下文的建立阶段时,我们可以将整个上下文环境看作是一个对象。该对象拥有 3 个属性,如下:

executionContextObj = {variableObject : {}, // 变量对象,里面包含 Arguments 对象,形式参数,函数和局部变量scopeChain : {},// 作用域链,包含内部上下文所有变量对象的列表this : {}// 上下文中 this 的指向对象
}

可以看到,这里执行上下文抽象成为了一个对象,拥有 3 个属性,分别是变量对象作用域链以及 this 指向,这里我们重点来看一下变量对象里面所拥有的东西。

在函数的建立阶段,首先会建立 Arguments 对象。然后确定形式参数,检查当前上下文中的函数声明,每找到一个函数声明,就在 variableObject 下面用函数名建立一个属性,属性值就指向该函数在内存中的地址的一个引用。

如果上述函数名已经存在于 variableObject(简称 VO) 下面,那么对应的属性值会被新的引用给覆盖。

最后,是确定当前上下文中的局部变量,如果遇到和函数名同名的变量,则会忽略该变量。

执行阶段

  1. 变量对象赋值
    • 变量赋值
    • 函数表达式赋值
  2. 调用函数
  3. 顺序执行其它代码

两个阶段要做的事情介绍完毕,接下来我们来通过代码来演示一下这两个阶段做的每一件事以及变量对象是如何变化的。

const foo = function(i){var a = "Hello";var b = function privateB(){};function c(){}
}
foo(10);

首先在建立阶段的变量对象如下:

fooExecutionContext = {variavleObject : {arguments : {0 : 10,length : 1}, // 确定 Arguments 对象i : 10, // 确定形式参数c : pointer to function c(), // 确定函数引用a : undefined, // 局部变量 初始值为 undefinedb : undefined  // 局部变量 初始值为 undefined},scopeChain : {},this : {}
}

由此可见,在建立阶段,除了 Arguments,函数的声明,以及形式参数被赋予了具体的属性值外,其它的变量属性默认的都是 undefined。并且普通形式声明的函数的提升是在变量的上面的。

一旦上述建立阶段结束,引擎就会进入代码执行阶段,这个阶段完成后,上述执行上下文对象如下,变量会被赋上具体的值。

fooExecutionContext = {variavleObject : {arguments : {0 : 10,length : 1},i : 10,c : pointer to function c(),a : "Hello",// a 变量被赋值为 Hellob : pointer to function privateB() // b 变量被赋值为 privateB() 函数},scopeChain : {},this : {}
}

我们看到,只有在代码执行阶段,局部变量才会被赋予具体的值。在建立阶段局部变量的值都是 undefined

这其实也就解释了变量提升的原理。

这篇关于JS的作用域链是静态的,它的取值是在创建阶段而不是调用阶段的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/627307

相关文章

JS常用组件收集

收集了一些平时遇到的前端比较优秀的组件,方便以后开发的时候查找!!! 函数工具: Lodash 页面固定: stickUp、jQuery.Pin 轮播: unslider、swiper 开关: switch 复选框: icheck 气泡: grumble 隐藏元素: Headroom

如何在页面调用utility bar并传递参数至lwc组件

1.在app的utility item中添加lwc组件: 2.调用utility bar api的方式有两种: 方法一,通过lwc调用: import {LightningElement,api ,wire } from 'lwc';import { publish, MessageContext } from 'lightning/messageService';import Ca

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

在JS中的设计模式的单例模式、策略模式、代理模式、原型模式浅讲

1. 单例模式(Singleton Pattern) 确保一个类只有一个实例,并提供一个全局访问点。 示例代码: class Singleton {constructor() {if (Singleton.instance) {return Singleton.instance;}Singleton.instance = this;this.data = [];}addData(value)

在cscode中通过maven创建java项目

在cscode中创建java项目 可以通过博客完成maven的导入 建立maven项目 使用快捷键 Ctrl + Shift + P 建立一个 Maven 项目 1 Ctrl + Shift + P 打开输入框2 输入 "> java create"3 选择 maven4 选择 No Archetype5 输入 域名6 输入项目名称7 建立一个文件目录存放项目,文件名一般为项目名8 确定

Java 创建图形用户界面(GUI)入门指南(Swing库 JFrame 类)概述

概述 基本概念 Java Swing 的架构 Java Swing 是一个为 Java 设计的 GUI 工具包,是 JAVA 基础类的一部分,基于 Java AWT 构建,提供了一系列轻量级、可定制的图形用户界面(GUI)组件。 与 AWT 相比,Swing 提供了许多比 AWT 更好的屏幕显示元素,更加灵活和可定制,具有更好的跨平台性能。 组件和容器 Java Swing 提供了许多

Node.js学习记录(二)

目录 一、express 1、初识express 2、安装express 3、创建并启动web服务器 4、监听 GET&POST 请求、响应内容给客户端 5、获取URL中携带的查询参数 6、获取URL中动态参数 7、静态资源托管 二、工具nodemon 三、express路由 1、express中路由 2、路由的匹配 3、路由模块化 4、路由模块添加前缀 四、中间件

顺序表之创建,判满,插入,输出

文章目录 🍊自我介绍🍊创建一个空的顺序表,为结构体在堆区分配空间🍊插入数据🍊输出数据🍊判断顺序表是否满了,满了返回值1,否则返回0🍊main函数 你的点赞评论就是对博主最大的鼓励 当然喜欢的小伙伴可以:点赞+关注+评论+收藏(一键四连)哦~ 🍊自我介绍   Hello,大家好,我是小珑也要变强(也是小珑),我是易编程·终身成长社群的一名“创始团队·嘉宾”

EasyPlayer.js网页H5 Web js播放器能力合集

最近遇到一个需求,要求做一款播放器,发现能力上跟EasyPlayer.js基本一致,满足要求: 需求 功性能 分类 需求描述 功能 预览 分屏模式 单分屏(单屏/全屏) 多分屏(2*2) 多分屏(3*3) 多分屏(4*4) 播放控制 播放(单个或全部) 暂停(暂停时展示最后一帧画面) 停止(单个或全部) 声音控制(开关/音量调节) 主辅码流切换 辅助功能 屏

Maven创建项目中的groupId, artifactId, 和 version的意思

文章目录 groupIdartifactIdversionname groupId 定义:groupId 是 Maven 项目坐标的第一个部分,它通常表示项目的组织或公司的域名反转写法。例如,如果你为公司 example.com 开发软件,groupId 可能是 com.example。作用:groupId 被用来组织和分组相关的 Maven artifacts,这样可以避免