JS中的变量提升总结

article/2025/9/16 19:25:03

1.JS代码执行顺序

我们直觉上会认为JS的代码在执行时是由上到下一行一行执行的,但实际并不完全正确,下面的例子会证明:

a = 'haha'
var a
console.log(a)

上面的代码会输出什么呢?

如果按照我们认为的由上到下一行一行执行,那么应该输出undefined,但是实际结果是'haha'

接着再看一个代码:

console.log(a)
var a = 'haha'

那这个输出的是什么?

鉴于上面代码表现出来的非自上而下的特点,有可能认为是’haha’。或者有认为变量a没有声明,所以会报错,但实际结果是undefined

为什么会是这样呢?到底发生什么?让我们带着这个问题看下去

2.变量提升

2.1 编译

我们要知道,引擎在解释JS代码之前首先要对代码进行编译,在编译阶段中有一部分工作就是找到所有的声明,并用合适的作用域将他们关联起来。

JS执行的流程图大致如下:
在这里插入图片描述

所以总结来说,包括变量和函数在内的所有声明在编译阶段都会首先被处理,然后才是代码被执行的阶段

当我们看到var a = 'haha'时候认为它是一个声明,但其实在JS中它会被看做两个声明,var aa = 'haha'var a是定义声明,是在编译阶段进行;a = 'haha'是赋值声明,会留在原地等待执行阶段。

2.2 解释上面问题

接着我们再看回第一个例子:

a = 'haha'
var a
console.log(a)

通过上面说明,可以知道会先处理定义声明,所以整个代码会以如下形式进行处理:

var a //在编译阶段进行变量提升
a = 'haha'
console.log(a)

第二个例子也是相同处理

console.log(a)
var a = 'haha'

在这个例子中也会进行变量提升,所以整个代码会以如下形式进行处理:

var a 
console.log(a)
a = 'haha'

3.函数提升

3.1 基础用法

看完变量提升,再看一下函数声明如何进行提升

foo()
function foo() {console.log('haha')
}

看完上面的例子,我想大家也能猜到了结果,就是’haha’。
因为foo函数的声明被提升了,所以第一行中的调用可以正常执行。

3.2 作用域提升

接下来再看一个例子

foo()
function foo() {console.log(a)var a = 'haha'
}

这个会输出什么呢?
答案是:undefined

在这个例子中,不只有函数提升,还有变量提升。要注意的是,每个作用域都会进行提升操作,所以foo()函数自身也会在内部对var a进行提升,但是只能在这个作用域中进行提升,并不能提升到整个代码的最上方。

因此这段代码会以如下形式进行处理:

function foo() {var aconsole.log(a)a = 'haha'
}
foo()

3.3 函数表达式

foo()
var foo = function bar() {console.log('haha')
}

这个代码执行结果是:TypeError: foo is not a function

这是因为变量标识foo被提升并分配给所在作用域,所以不会出现ReferenceError的错误,但是foo此时没有赋值,也就是此时foo是undefined,所以执行foo()是对undefined值进行函数调用,因此结果为TypeError。

这个例子证明了:函数声明会被提升,但是函数表达式不会被提升

3.4 具名函数表达式

foo()
bar()
var foo = function bar() {console.log('haha')
}

从上面我们知道,执行foo()会是typeError,那执行bara()呢?
答案是:ReferenceError: bar is not defined

这是因为:即使是具名的函数表达式,名称标识符在赋值之前也无法在所在作用域中使用

因此这段代码会以如下形式进行处理:

var foofoo() //typeErrorbar() //ReferenceErrorfoo = function bar() {console.log('haha')}

4. 函数优先

函数声明和变量声明都会提升,但是在处理声明中是 函数首先被提升,然后才是变量

foo()
var foo 
function foo() {console.log(1)   
}
foo = function () {console.log(2)
}

这个例子的结果是1。
这个代码会以近似如下形式进行处理:

function foo() {console.log(1)   
}
foo()
foo = function () {console.log(2)
}

注意:var foo虽然会出现在foo()之前,但是因为重复的声明,所以被忽略了。

5.实战练习

经过上面说明,应该对变量提升有了大致了解,那么让我们再看几个例子,看看是否真正理解

5.1 例子1:

var getName = function () { console.log('4');
};
function getName() { console.log(5);
}
getName();    

想想这个结果是什么?

让我们分析一下这个提升过程,这个代码会以近似如下形式进行处理:

function getName() { console.log(5);
}var getName //被忽略getName = function () { console.log('4');
};getName(); 
  1. getName函数和变量getName被提升
  2. 然后var getName因为重复声明被忽略
  3. 最后函数表达式getName会覆盖函数getName

所以最后实际执行的是函数表达式getName = function () { console.log('4'); };,结果为’4’

5.2 例子2

function showName() {console.log('name1');
}
showName();
function showName() {console.log('name2');
}
showName(); 

想想这个结果是什么?

有了上面经验,这个就更好理解了,这个代码会以近似如下形式进行处理:

function showName() {console.log('name1');
}
function showName() {console.log('name2');
}
showName();
showName();

所以结果一目了然,结果为 name2 name2

6.总结

通过上面的内容,我们可以进行一个简单的总结:

  1. 变量提升,是指在 JavaScript 代码执行过程中,JavaScript 引擎把变量的声明部分和函数的声明部分提升到代码开头的“行为”。变量被提升后,会给变量设置默认值,这个默认值就是我们熟悉的 undefined。
  2. JS的代码执行顺序是先进行声明处理,然后进行赋值等其他操作。
  3. 提升的过程就像是把变量和函数声明从他们在代码中出现的位置“移动”到了最上面。另外只有定义的声明本身会被提升,而赋值或其他运行逻辑会留在原地
  4. 函数声明和变量声明在一起时,函数首先被提升,然后才是变量

http://chatgpt.dhexx.cn/article/My0wi16s.shtml

相关文章

Flink Table 和 DataStream 转换

文章目录 Flink Table 和 DataStream 转换1. 表(Table) 转换为 流(DataStream)1.1 处理(仅插入)流1.1.1 fromDataStream()方法:1.1.1.1 fromDataStream(DataStream var1)1.1.1.2 fromDataStream(DataStream var1, Expression... var2)1.1.1.3…

数据流—DataStreamAPI

Hello Flink 1:构建一个典型的Flink流式应用需要一下几步: 1:设置执行环境。 2:从数据源中读取一条或多条流 3:通过一系列流式转换来实现应用逻辑。 4:选择性的将结果输出到一个或多个数据汇(用…

【Flink】DataStream API使用之转换算子(Transformation)

转换算子(Transformation) 数据源读入数据之后,就是各种转换算子的操作,将一个或者多个DataSream转换为新的DataSteam,并且Flink可以针对一条流进行转换处理,也可以进行分流或者河流等多流转换操作&#xf…

Flink-DataStream执行环境和数据读取

​编辑执行环境 创建执行环境 执行模式 触发程序执行 源算子(Source) 读取有界数据流 读取无界数据 读取自定义数据源(源算子) DataStream是一个 Flink 程序,其实就是对 DataStream 的各种转换。具体来说&#xff0c…

Flink数据流类型之间的转换(WindowedStream、DataStream、KeyedStream、AllWindowStream之间的转换)

Flink提供了一些流API,其中包括WindowedStream、DataStream、KeyedStream和AllWindowStream。 🍊WindowedStream是一种特殊的流,其中数据已按时间或数据元素的键进行分组,并且每个分组的数据都在窗口中按时间划分。这意味着&…

DataStream API

目录 原算子 准备工作,环境搭建 读取数据 从文件中读取数据 从集合中读取数据 从元素中读取数据 从source文件中读取数据 从kafka中读取数据 自定义source类型输出 转换算子 map转换 Filter转换 FlatMap转换 原算子 准备工作,环境搭建 为…

Flink学习——DataStream API

一个flink程序,其实就是对DataStream的各种转换。具体可以分成以下几个部分: 获取执行环境(Execution Environment)读取数据源(Source)定义基于数据的转换操作(Transformations)定义…

大数据开发-Flink-数据流DataStream和DataSet

文章目录 一、DataStream的三种流处理Api1.1 DataSource1.2 Transformation1.3 Sink 二、DataSet的常用Api2.1 DataSource2.2 Transformation2.3 Sink Flink主要用来处理数据流,所以从抽象上来看就是对数据流的处理,正如前面大数据开发-Flink-体系结构 &…

Flink DataStream API 介绍

Flink DataStream API 介绍 StreamExecutionEnvironment #mermaid-svg-JKeWa22W2vWA4zBS {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-JKeWa22W2vWA4zBS .error-icon{fill:#552222;}#mermaid-svg-JKeWa22W2vWA4z…

DataStream API介绍与使用(一)

详细API参考官网 DataStream编程模型 在Flink整个系统架构中,对流计算的支持是其最重要的功能之一,Flink基于Google提出的DataFlow模型,实现了支持原生数据流处理的计算引擎。Flink中定义了DataStream API让用户灵活且高效地编写Flink流式应…

DataStream API(一)

Flink 有非常灵活的分层 API 设计,其中的核心层就是 DataStream/DataSet API。由于新版 本已经实现了流批一体, DataSet API 将被弃用,官方推荐统一使用 DataStream API 处理流数 据和批数据。由于内容较多,我们将会用几章的篇幅来…

DataStream(二)

目录 5.3.2 聚合算子(Aggregation) 5.3.3 用户自定义函数(UDF) 3. 扁平映射(flatMap) flatMap 操作又称为扁平映射,主要是将数据流中的整体(一般是集合类型)拆分成一个 …

Flink DataStream API

Flink DataStream API 编程指南 概览前言什么是DataStreamFlink程序剖析程序样例 Data SourcesDataStream Transformations算子数据流转换算子物理分区算子链和资源组 Data Sinks迭代执行参数 概览 前言 Flink中的DataStream程序是常规程序,可对数据流进行转换&am…

DataStream API(三)

目录 5.3.4 物理分区(Physical Partitioning) 5.4 输出算子(Sink) 5.4.1 连接到外部系统 5.4.2 输出到文件 5.4.3 输出到 Kafka 5.4.4 输出到 MySQL(JDBC) 5.4.5 自定义 Sink 输出 5.5 本章总结 5.3.…

流式数据采集和计算(十):Flink的DataStream学习笔记

Flink的DataStream学习笔记.. 1 Flink 基础.. 3 Flink特性.. 3 Flink和Spark对比.. 3 设计思路.. 3 状态管理.. 3 Flink 初探.. 4 设计架构.. 4 Flink on yarn. 5 流程分析.. 6 DataStream. 7 API程序结构.. 7 DataSource 8 Transformation. 9 Sink. 13 Time 14…

DataStream API(基础篇) 完整使用 (第五章)

DataStream API基础篇 一、执行环境(Execution Environment)1、创建执行环境1. getExecutionEnvironment2. createLocalEnvironment3. createRemoteEnvironment 二、执行模式(Execution Mode)1. BATCH模式的配置方法(1)通过命令行…

DataStream API 四 之 Flink DataStream编程

DataStream API 四 之 Flink DataStream编程 1.分布式流处理基本模型2.流应用开发步骤3.数据类型4. Connector5. Execution environment6. 参数传递7.配置并⾏度8.Watermark9.Checkpoint10.State11. Data Source11.111.2 自定义Source 12.Transformations13.Window13.1窗⼝处理…

Flink的DataStream介绍

1|0一:流式处理基本概念 流处理系统本身有很多自己的特点。一般来说,由于需要支持无限数据集的处理,流处理系统一般采用一种数据驱动的处理方式。它会提前设置一些算子,然后等到数据到达后对数据进行处理。 为了表达复杂的逻辑&am…

Flink DataStream API(基础版)

概述 DataStream(数据流)本身是 Flink 中一个用来表示数据集合的类(Class),我们编写的 Flink 代码其实就是基于这种数据类型的处理,所以这套核心API 就以DataStream 命名。对于批处理和流处理,我…

node.js上开启服务,在同一局域网下的另一客户端访问

选择的服务是我之前做的案例:链接 1.在本机上开启服务: 2.本机上用浏览器访问验证无误: 3.运行cmd使用命令ipconfig查看本机ip地址 4.在另一台局域网下的机子,要求可以ping到。 浏览器访问ip地址:3000即可。&#…