有没有对JS了解比较深的朋友

@Ta 2021-05-11发布,2021-05-11修改 16159点击

1.jpg

2.jpg

上面两个输出为什么会不一样? 我这里猜想是与LexicalEnvironment(词法环境)和VariableEnvironment(变量环境)有关系,所以根据这篇文章的内容: https://zhuanlan.zhihu.com/p/53135129 第二张图的结果很容易能推出来,那第一张的结果就属于完全无法理解了,在我的理解中它的词法环境变量环境在预编译后会有两个相同的属性a,此时应该报SyntaxError: Identifier 'a' has already been declared的错误才对。

红米K30 Pro 变焦版

回复列表(42|隐藏机器人聊天)
  • @Ta / 2021-05-12 / /

    @Curtion,只有进入严格模式才会报错。

    "use strict";
    

    非严格模式使用未定义变量都不会报错,所以……

  • @Ta / 2021-05-12 / /

    最近正在系统学习JS,等我学成归来为你解惑,也许2,3年。等我兄弟!
    小米8(白)

  • @Ta / 2021-05-12 / /

    @老虎会游泳
    我的猜想是报重复定义的错误,不是报未定义变量的错误,但是却没有报错,还直接出结果了,我只是不知道为什么是这个结果。对了,es6是默认严格模式
    红米K30 Pro 变焦版

  • @Ta / 2021-05-12 / /

    @艾木友尔尔巴,那我倾向于你去学一门正常的语言,c++,java,go都行
    红米K30 Pro 变焦版

  • @Ta / 2021-05-12 / /

    @老虎会游泳,疑点在于两个图只是把let改成var,但是结果却不同了,如果结合知乎的文章做参考,那个只能解释var的情况,大概意思是这个。
    红米K30 Pro 变焦版

  • @Ta / 2021-05-12 / /

    看的我更迷惑了...
    人生若只如初见

  • @Ta / 2021-05-12 / /

    @Curtion,你不在严格模式。

    图片.png

  • @Ta / 2021-05-12 / /

    @Curtion,只有ES6模块才会处于自动严格模式。但是你的文件只是一个js,并不是ES6模块,所以并没有自动严格模式。

  • @Ta / 2021-05-12 / /

    @Curtion,很遗憾,node的严格模式依然不会对此报错。
    图片.png

    我发现只有在浏览器内逐条执行语句时,它才会报重复定义错误。如果一次性执行,就不会报错。
    图片.png图片.png

  • @Ta / 2021-05-12 / /

    @Curtion,我觉得问题的关键是,在js中这到底是什么:

    {
       xxx;
    }
    

    代码块?
    函数定义?
    闭包?
    对象?
    如果它只是产生了一个对象,并没有立即执行里面的代码,那么当然不会报错。
    而在浏览器逐行执行的时候,就会对每行的返回结果进行求值(因为浏览器要打印返回结果),所以才会触发报错。

  • @Ta / 2021-05-12 / /

    看起来它确实是立即执行的代码块。
    那么let的作用域问题就令人迷惑了。

    图片.png

  • @Ta / 2021-05-12 / /

    @老虎会游泳@Curtion
    主要还是函数变量提升和let块级作用域的问题吧

    我来完善一下等价代码 就比较容易看了:

    let a = 0;
    {
      var A = undefined;
      A = 1;
      function 1(){};
    }
    
    console.log(a);
    
    var a = undefined;
    
    var a = 0;
    //{
      a = 1;
      function 1(){};
    //}
    
    console.log(a);
    

    file-hash-png-1c09f8765ca335e631889592b6586ea2400767.png
    小米MIX2s(白)

  • @Ta / 2021-05-12 / /

    @Curtion@水木易安,原来如此,如果把function a() {};删掉,结果就是1了。

    图片.png

  • @Ta / 2021-05-12 / /

    @水木易安@Curtion,实际上最有趣的一点在于,以下代码输出1

    {
            a = 1;
            function a() {};
            console.log(a);
    };
    

    所以它实际上相当于:

    {
            function a() {};
            a = 1;
            console.log(a);
    };
    

    执行时似乎发生了“函数提升”,函数定义被放在了最前面。

    图片.png图片.png

  • @Ta / 2021-05-12 / /

    @老虎会游泳,是的.
    js存在变量提升和函数提升

    经过你的提醒 我发现我的function a(){}理解错了 似乎的确是全部提升了

    而我在浏览器debug的时候发现这个:

    image.png

    小米MIX2s(白)
  • @Ta / 2021-05-12 / /

    @水木易安@老虎会游泳

    {
            a = 1;
            function a() {};
    }
    
    

    实际上是这样的:

    var a1 = undefined
    {
        let a2 = funcrtion a() {}
        a2 = a
        a1 = a2
    }
    

    a1和a2是方便理解的东西,在实际上它们都是a,但是程序处理时是当成两个东西来处理的。

    举个例子:

    var a = 0;
    {
      a = 123;
      function a() {}
      a = 456;
      console.log(a);
    }
    console.log(a);
    

    这段代码实际上输出的是456,123 ,如果是@水木易安,的理解,那么应该输出456,456才对
    红米K30 Pro 变焦版

  • @Ta / 2021-05-12 / /

    @Curtion
    小米MIX2s(白)

  • @Ta / 2021-05-12 / /

    @水木易安@老虎会游泳, 这里有一个回答: https://stackoverflow.com/questions/31419897/what-are-the-precise-semantics-of-block-level-functions-in-es6) 再结合知乎的文章,我推测

    var a1 = undefined
    {
        let a2 = funcrtion a() {}
        a2 = a
        a1 = a2
    }
    

    这段代码中的 a1就是VariableEnvironment(变量环境),a2就是LexicalEnvironment(词法环境)。这样理解那这段代码逻辑是可以说清楚的,但是当第一行的var变成let后,两个a都在LexicalEnvironment(词法环境)了,我的理解应该会报错,但是实际上直接输出了0
    红米K30 Pro 变焦版

  • @Ta / 2021-05-12 / /
    就是var和let定义的变量作用域不同;
    - -,代码看过去很明显了
添加新回复
回复需要登录