V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
liberty1900
V2EX  ›  JavaScript

发现了 var 和 let/const 的一个细微差别

  •  
  •   liberty1900 · 2023-08-30 17:33:15 +08:00 · 1486 次点击
    这是一个创建于 395 天前的主题,其中的信息可能已经有所发展或是发生改变。

    大多数前端开发者都知道在浏览器里全局对象是 window,这点可以用 Object.is(globalThis, window) 来验证

    如果在浏览器的全局环境下定义一个变量,那么它将被自动挂载到 window 对象上

    var name = "Mike";
    
    console.log(window.name)
    

    但 let 和 const 却不会这样

      let age = 10;
      const sex = "Male";
      console.log(window.age, window.sex)
    
    thinkershare
        1
    thinkershare  
       2023-08-30 17:34:16 +08:00   ❤️ 1
    不要用 var 这种垃圾。
    hsfzxjy
        2
    hsfzxjy  
       2023-08-30 17:35:23 +08:00 via Android
    是这样的,而且不只这个差别
    rrfeng
        3
    rrfeng  
       2023-08-30 17:39:50 +08:00
    var 就是全局变量,千万别用。
    liberty1900
        4
    liberty1900  
    OP
       2023-08-30 17:47:44 +08:00
    用惯了了 VS Code ,里面 Cmd + Enter 是 Insert Line Below ,V 站这里直接给我发帖了。。。
    Jirajine
        5
    Jirajine  
       2023-08-30 17:49:17 +08:00 via Android   ❤️ 1
    你不用管它有什么区别,你只需要记住 var 是 deprecated ,永远不要使用就行了。
    liberty1900
        6
    liberty1900  
    OP
       2023-08-30 17:53:59 +08:00
    let/const 是 block scope 的,我以前理解所谓 block scope 就是用花括号形成的 scope 比如:

    ```javascript
    {
    let age = 10;
    console.log(age); // 10
    }
    console.log(age) // undefined
    ```

    如果我没有显示套上大括号,也就没有了 block scope 但是变量总得有个 scope ,那这个 scope 是不是 global scope 呢?看来我理解错了
    HelloWorld556
        7
    HelloWorld556  
       2023-08-30 17:54:25 +08:00   ❤️ 1
    chengxy
        8
    chengxy  
       2023-08-30 17:58:10 +08:00
    继续往下,学学 let 和 const 的区别
    Adicwu
        9
    Adicwu  
       2023-08-30 18:01:12 +08:00
    这你就得问问变量提升了
    liberty1900
        10
    liberty1900  
    OP
       2023-08-30 18:04:29 +08:00
    @liberty1900 一种合理的解释是 let/const 一定是 block scope 的,即使没有显式用花括号声明也是 block scope, 只是这种 scope 是隐式的,而且和 global scope 有区别,不能混为一谈
    liberty1900
        11
    liberty1900  
    OP
       2023-08-30 18:06:56 +08:00
    @chengxy 我知道 let 和 const 的区别,也知道 const 的局限性以及如何用 Object.create/Object.definedProperties/Object.seal/Object.freeze 来实现不同程度的不可变
    cmdOptionKana
        12
    cmdOptionKana  
       2023-08-30 18:11:06 +08:00
    年轻人真幸福啊,没经历过只有 var 的年代。
    NerbraskaGuy
        13
    NerbraskaGuy  
       2023-08-30 18:31:18 +08:00
    这个不算细微吧,let 和 const 被造出来基本就是为了解决 var 这个痛点的
    chnwillliu
        14
    chnwillliu  
       2023-09-04 11:03:33 +08:00 via Android   ❤️ 1
    Spec 都定义好了,参见 Execution Context 的 LexicalEnvironment 和 VariableEnvironment 。他俩都是 Environment Record ,但是装的东西不一样,一个负责 let const 声明的东西,一个负责 variable statement ,hoisting 还有 with block 的差异处理都在这里规定好了。

    不光这样,全局还有个特殊的 Environment Record 叫 Global Environment Records, 全局 var 和 function 会变成 global object 的属性的行为就是在这里定义的。
    chnwillliu
        15
    chnwillliu  
       2023-09-04 19:15:37 +08:00
    仔细翻了下 Spec ,还是要纠正一下,无论 let const 还是 var ,或者是 function declaration ,class declaration ,这些 identifier 都会在 LexicalEnvironment 中记录,要查找 identifier 也只要查找 LexicalEnvironment 。而 VariableEnvironment 是专门用来管理 variable statement 的,相当于额外放一份,用来处理一些老旧 feature 比如 eval 。

    let/const 和 var 的区别在于在初始进入一个 function 或者 script 的时候,只有 top level 的 let/const 会被加入到 LexicalEnvironment ,而 variable statement 声明的 identifier 和 hoistable declaration 声明的 identifier 比如 function 声明,是会在最开始就全部加入到 LexicalEnvironment 中。

    实例化一个 block declaration 后,需要创建一个新的 LexicalEnvironment 给到当前的 execution context ,后续的 let/const 是加入到这个 LexicalEnvironment 中了的。比如 for ( let i=0; i<10; i++) { let j; } 这里其实创建了 11 个临时 LexicalEnvironment ,for 语句给 i 创建了一个,每次循环会创建另一个新的,放一个 j (然后销毁)。而 var 是不存在这种考量的,无论几个 for 嵌套,都会在最开始就放入顶层的 LexicalEnvironment 。

    不光在开始执行一个 function 会这样处理,在新的 script element ,module 或者 worker 开始执行,都是类似处理。这个顶层 scope 或者说 LexicalEnvironment , 就是 Global Environment ,Module Environment 和 Function Environment 。

    Global Environment 在每个 realm 中只有一个,在 user land 和 globalThis 是等价的,而 var 变量 和 function declaration 的 identifier 能用 globalThis 直接当属性访问也是 Global Environment Record 做的特殊处理,参见 CreateGlobalVarBinding 和 CreateGlobalFunctionBinding 。

    Function Environment 在每次 call 一个 function 的时候都会创建,module 同理,在第一次 import 时创建。

    一个有趣的例子,这个 early error 是如何产生的呢?

    ```
    (function(){

    {

    {
    {
    {
    var b
    }
    }

    let b;
    }
    }

    })()
    ```
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   4986 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 07:22 · PVG 15:22 · LAX 00:22 · JFK 03:22
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.