三个 JavaScript 例子中的函数提升为何导致不同的输出?

2023-08-21 20:27:40 +08:00
 klion

问题描述

我在学习 JavaScript 的函数提升( hoisting )时,遇到了三个看似相似但输出不同的例子。根据函数提升的原理,这三个例子的输出应该是相同的,越想越觉得奇怪啊

例子 1

var a = 0;
console.log("1 a:", a);
if(true){
    a = 1;
    function a() {}
    a = 5;
    console.log("2 a:", a);
}
console.log("3 a:", a);

经过验证,输出结果为:

1 a: 0
2 a: 5
3 a: 1

例子 2

var a = 0;
console.log("1 a:", a);
if(true){
    a = 1;
    a = 5;
    console.log("2 a:", a);
    function a() {}
}
console.log("3 a:", a);

经过验证,输出结果为:

1 a: 0
2 a: 5
3 a: 5

例子 3

var a = 0;
console.log("1 a:", a);
if(true){
    function a() {}
    a = 1;
    a = 5;
    console.log("2 a:", a);
}
console.log("3 a:", a);

经过验证,输出结果为:

1 a: 0
2 a: 5
3 a: f a() {}

问题

  1. 这几个例子在函数提升方面有何不同?
  2. 为什么每个例子的输出都不相同?
2046 次点击
所在节点    Node.js
16 条回复
Yumwey
2023-08-21 21:15:34 +08:00
1. 主要是块和全局作用域在 es5 的非严格模式下混淆了,你每一步解析一下提升过程,注意块作用域内 console 输出一直都是 a 的赋值,但是声明式的 Function a 在提升后对全局作用域 a 的引用关系才是 3a 结果, var / 声明式 Function 的提升优先级
2. 加个 'use strict' 就一样了
3. 其实不太需要考虑这个了,直接用 let, const 就好了
zhouyg
2023-08-21 21:27:05 +08:00
建议不学这种糟粕
klion
2023-08-21 21:29:34 +08:00
@zhouyg 原因是以前一同学想测试 GPT4 的能力,结果 GPT4 答不上来,我越看也越觉得怪,就上论坛发帖了。stackoverflow 上都说是历史遗留问题,https://stackoverflow.com/questions/58619924/function-declaration-in-block-moving-temporary-value-outside-of-block
mxT52CRuqR6o5
2023-08-21 21:42:50 +08:00
不要再研究 sloppy mode 的东西了
我跟你说你这几个 case 在上古浏览器里还有另外不同的表现的
Rocketer
2023-08-22 00:18:41 +08:00
研究屎山是为了消除它,而不是让自己适配它。

对于已经消除的屎山,还拿他做题玩嘛呢?有公司面试题出这个我都直接怼回去,也没耽误我拿 offer
LUO12826
2023-08-22 01:46:49 +08:00
欢迎使用 Safari ,Safari 里三者输出是一样的。在块作用域内定义用 function 定义函数是 JS 中的标准未定义行为,取决于 JS 引擎的实现
iOCZ
2023-08-22 09:13:02 +08:00
例子三怎么解释啊?
stillsilly
2023-08-22 10:16:05 +08:00
吃饱了撑的
xiangyuecn
2023-08-22 10:27:34 +08:00
你编写的奇怪的代码正在以奇怪的方式运行。

第一行放个 'use strict' 确实能解决不少麻烦。

同一个作用域下不要使用重名的变量,减轻自己的负担。

拒绝使用 const 关键字,我都写 js 了,还 const const const 。
c3de3f21
2023-08-22 11:10:59 +08:00
@zhouyg 哎,我也是这么认为的,明明有更好的方式来规避这种问题比如 let/const ,可偏偏有公司把这些放到面试题里去。
zangbianxuegu
2023-08-22 13:42:21 +08:00
@iOCZ 函数声明在全局也创建了同名变量,声明时改变了全局同名变量
iOCZ
2023-08-22 15:05:56 +08:00
只能这么认为了,就是函数声明提升 var a = function(){},然后紧接着是 window.a = a;然后原来声明之前的 a 赋值,都是 window.a 赋值,函数声明之后的都是 a 赋值。这样能符合所有结果。
liuidetmks
2023-08-22 18:29:06 +08:00
boring , i +++++i 等于几?
humbass
2023-08-22 21:31:18 +08:00
es6 给了 let,const ,就是用来解决这些问题体操的。
Pythoner666666
2023-09-01 11:28:21 +08:00
2023 年了 还在纠结这种问题
xingguang
2023-09-05 11:41:41 +08:00
我之前看一个视频说 function 的提升有时候很奇怪,规范里都没有定,所以这里是引擎按照自己的理解实现的,所以这样的 function 提升在不同浏览器的结果可能都不一样,所以学习这种提升实在是没必要,面试真遇到了也只能可惜的放弃吧

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/967183

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX