hoisting怎么读(hoisted怎么读)

hoisting怎么读(hoisted怎么读)

扫码添加渲大师小管家,免费领取渲染插件、素材、模型、教程合集大礼包!

前沿

大家对变量提升(hoisting)一定不陌生了。这篇文章希望可以建立一个系统的规则。以后碰到变量提升。可以重新看这篇文章。根据文中的规则找到答案。最终。我们可以记住这个规则。很自然的理解变量提升。

例子

相信大家对这个例子不陌生了:

a = 2;var a;console.log( a ); /// 2

为什么这段话a 在声明之前就可以赋值了呢?

再看下这个例子:

console.log( a ); //undefinedvar a = 2;

为什么这个又是输出undefined呢?

别担心。看完整个文章你就会知道运用怎样的规则来推断结果了。

作用域浅析

在这里我们对作用域不做详细的讲解。作用域可以想象成可访问对象的集合。

打个通俗的比方。现在有个公寓管理公司。底下有多个公寓。高级管理员A。 他有所有公寓所有房间的钥匙。所以他能打开所有公寓所有房间。并能拿出所有房间的物品。中级管理员B。只有某一栋公寓所有房间的钥匙。他能拿出所有此公寓所有房间的物品。但是不能拿出其他公寓的物品。原因就是管理员B在拿物品时(程序执行代码时)。 并没用其他公寓的信息(其他作用域内信息)。

hoisting怎么读(hoisted怎么读)

为了简单。本篇文章只涉及同一个作用域下。不同作用域的交互之后几篇会讲到

大家可以想像成进入到全局作用域或者某个函数作用域时。引擎会产生一个json object 当作资料库。 之后代码执行的时候会从这个json 中找值。

var pseudoContext = {}

JavaScript解析器

一般来说。大家可能觉得JavaScript解析器会在 run-time 运行时一行一行的来解析代码。

事实上当解释器到达一个作用域后。会先编译代码。然后再一行一行解析。

当JavaScript引擎运行到某个作用域后 ( 在第一个例子中。作用域是 global 全局作用域 )

它会有两个步骤

1. 初始化阶段 ( Creation Stage) [当进入一个作用域。逐行运行代码之前]

+ 创建 var 变量。 function 函数和函数的arguments 参数

2. 代码执行阶段 (Activation/Code Execution Stage)

+ 给变量和函数赋值。以及执行代码

初始化阶段 ( Creation Stage)

在初始化阶段。进入一个作用域时会发生:

1. 如果作用域是函数内部。把函数参数放进前面的context json 中

2. 扫描当前作用域寻找函数:

+ 每发现一个函数。就把名字和函数指针放进前面的json中

+ 如果函数名已经存在。覆盖之前的函数指针 3. 扫描当前作用域寻找变量:

+ 每发现一个变量 var。就把名字放进前面的json中。并把值设>成 undefined

+ 如果变量名已经存在。不会覆盖。忽略然后继续扫描

代码执行阶段 (Activation/Code Execution Stage)

逐行执行代码。并且赋值之前为undefined的变量var

例子1

我们回到之前的例子:

a = 2;var a;console.log( a ); /// 2

我们把之前讲的规则拿来套用:

首先进入全局作用域。初始化一个空的模拟作用域 json逐步执行代码之前。执行初始化阶段作用域不是函数内部。没用函数参数。忽略扫描未发现函数。忽略扫描发现变量var a。 放进json里并设置成undefined此时我们的 json:

pseudoContext = { a = undefined}a = 2

4.扫描完成。逐行执行代码

a = 2

5.扫描我们的作用域。发现pseudoContext里存在a。赋值成2

pseudoContext = { a = 2}

6.下一步:

console.log( a );

7.在作用域pseudoContext 中找到 a。 发现有值。输出2

例子2

console.log( a ); //undefinedvar a = 2;

首先进入全局作用域。初始化一个空的模拟作用域json逐步执行代码之前。执行初始化阶段作用域不是函数内部。没用函数参数。忽略扫描未发现函数。忽略扫描发现变量var a。 放进json里并设置成undefined此时我们的json:

pseudoContext = { variables: { a = undefined }}

4.扫描完成。逐行执行代码

console.log( a );

json里a是undefined。 所以输出undefined

更复杂的例子3

console.log(typeof foo); // function pointerconsole.log(typeof bar); // undefinedvar foo = 'hello'。 bar = function() { return 'world'; };function foo() { return 'hello';}

1.首先进入全局作用域。初始化一个空的模拟作用域json

2.逐步执行代码之前。执行初始化阶段

3.作用域不是函数内部。没用函数参数。忽略

4.扫描发现函数foo(第9行)。 声明并赋值

5.此时的 json:

pseudoContext = { foo = function pointer}

6.扫描发现变量var foo。 因为foo名字已经存在了。依照之前规则 \"如果变量名已经存在。不会覆盖。忽略然后继续扫描\"。 忽略

7.扫描发现变量 var bar。 赋值成undefined

引擎会先函数扫描。再变量扫描

8.此时我们的json:

pseudoContext = { foo = function pointer。 bar = undefined}

扫描完成。逐行执行代码

console.log(typeof foo);

json里foo 是function pointer。返回function

下一步:

console.log(typeof bar);

json里bar是undefined。输出undefined

let 和 const

希望以上讲的大家都能理解。再来说说let和const。这两个和var不同 他们在所谓的 时间静止区 temporal dead zone (TDZ)(不知道谁取的这么中二的名字)。

当进入一个作用域时。我们不会把它加在我们json里一开始get或者set的时候就会报错 ReferenceError逐行执行时。如果有letconst声明。就会在作用域json里创建。如果赋值了。就会在作用域json里赋值

b // Uncaught ReferenceError: b is not definedlet b =2

总结

希望大家看了这篇文章对变量提升有更深的理解。变量提升只是表象。只是一个js解析器和作用域共同产生的一个结果。之后会更加详细的讲解一下作用域

关注我的头条号。分享更多的技术学习文章。我自己是一名从事了多年开发的web前端老程序员。目前辞职在做自己的web前端私人定制课程。今年年初我花了一个月整理了一份最适合2019年学习的web前端学习干货。各种框架都有整理。送给每一位前端小伙伴。想要获取的可以关注我的头条号并在后台私信我:前端。即可免费获取。

分享到 :
相关推荐

wps页眉横线怎么删除(word顶端有一条横线怎样删除)

1、wps页眉横线怎么删除在WPS文档编辑器中,页眉横线是一种常见的装饰元素,可以[...

网页聊天室怎么制作(网页聊天室怎么制作表情包)

1、网页聊天室怎么制作网页聊天室是一个非常有趣和实用的互联网应用,它允许用户通过网[...

三级缓存对性能的影响(16mb和32mb三级缓存区别大吗)

1、三级缓存对性能的影响三级缓存对性能的影响在计算机体系结构中,缓存是提高CP[&h...

向日葵Mac版本可以控制Windows吗

向日葵Mac版本可以控制Windows吗向日葵是一款远程控制软件,它可以帮助用户在[...

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注