V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
klion
V2EX  ›  Node.js

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

  •  
  •   klion · 2023-08-21 20:27:40 +08:00 · 2036 次点击
    这是一个创建于 489 天前的主题,其中的信息可能已经有所发展或是发生改变。

    问题描述

    我在学习 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. 为什么每个例子的输出都不相同?
    16 条回复    2023-09-05 11:41:41 +08:00
    Yumwey
        1
    Yumwey  
       2023-08-21 21:15:34 +08:00   ❤️ 1
    1. 主要是块和全局作用域在 es5 的非严格模式下混淆了,你每一步解析一下提升过程,注意块作用域内 console 输出一直都是 a 的赋值,但是声明式的 Function a 在提升后对全局作用域 a 的引用关系才是 3a 结果, var / 声明式 Function 的提升优先级
    2. 加个 'use strict' 就一样了
    3. 其实不太需要考虑这个了,直接用 let, const 就好了
    zhouyg
        2
    zhouyg  
       2023-08-21 21:27:05 +08:00   ❤️ 4
    建议不学这种糟粕
    klion
        3
    klion  
    OP
       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
        4
    mxT52CRuqR6o5  
       2023-08-21 21:42:50 +08:00 via Android
    不要再研究 sloppy mode 的东西了
    我跟你说你这几个 case 在上古浏览器里还有另外不同的表现的
    Rocketer
        5
    Rocketer  
       2023-08-22 00:18:41 +08:00 via iPhone
    研究屎山是为了消除它,而不是让自己适配它。

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

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

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

    拒绝使用 const 关键字,我都写 js 了,还 const const const 。
    c3de3f21
        10
    c3de3f21  
       2023-08-22 11:10:59 +08:00
    @zhouyg 哎,我也是这么认为的,明明有更好的方式来规避这种问题比如 let/const ,可偏偏有公司把这些放到面试题里去。
    zangbianxuegu
        11
    zangbianxuegu  
       2023-08-22 13:42:21 +08:00
    @iOCZ 函数声明在全局也创建了同名变量,声明时改变了全局同名变量
    iOCZ
        12
    iOCZ  
       2023-08-22 15:05:56 +08:00
    只能这么认为了,就是函数声明提升 var a = function(){},然后紧接着是 window.a = a;然后原来声明之前的 a 赋值,都是 window.a 赋值,函数声明之后的都是 a 赋值。这样能符合所有结果。
    liuidetmks
        13
    liuidetmks  
       2023-08-22 18:29:06 +08:00
    boring , i +++++i 等于几?
    humbass
        14
    humbass  
       2023-08-22 21:31:18 +08:00
    es6 给了 let,const ,就是用来解决这些问题体操的。
    Pythoner666666
        15
    Pythoner666666  
       2023-09-01 11:28:21 +08:00
    2023 年了 还在纠结这种问题
    xingguang
        16
    xingguang  
       2023-09-05 11:41:41 +08:00
    我之前看一个视频说 function 的提升有时候很奇怪,规范里都没有定,所以这里是引擎按照自己的理解实现的,所以这样的 function 提升在不同浏览器的结果可能都不一样,所以学习这种提升实在是没必要,面试真遇到了也只能可惜的放弃吧
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2930 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 13:59 · PVG 21:59 · LAX 05:59 · JFK 08:59
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.