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

var 和 let 的区别?

  •  2
     
  •   brooky 2016-11-15 23:19:31 +08:00 5770 次点击
    这是一个创建于 3256 天前的主题,其中的信息可能已经有所发展或是发生改变。
    var a = []; for (var i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[6](); // 10 
    var a = []; for (let i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[6](); // 6 

    想不明白了, 谁能帮忙解释下这是为啥呢?

    31 条回复    2016-11-28 22:47:32 +08:00
    JohnLou
        1
    JohnLou  
       2016-11-15 23:29:29 +08:00
    我刚看了这个,因为 var 的作用域只能是函数和全局,而 let 是块,也就是{},所以对于 let , for 循环一次, i 就在那个循环里起作用而已。
    chemzqm
        2
    chemzqm  
       2016-11-15 23:32:43 +08:00
    你或许需要一本 exploring es6
    miketeam
        3
    miketeam  
       2016-11-15 23:38:03 +08:00 via iPhone
    总是喜欢把事情搞得这么复杂,所以一点都不喜欢了 js
    nanxiaobei
        4
    nanxiaobei  
       2016-11-15 23:58:22 +08:00
    用 var ,每个 function 都保存着 i 的同一个变量对象,为 10 。
    用 let ,是块级作用域,每次的 i 是独立的,大概是这样吧。
    brooky
        5
    brooky  
    OP
       2016-11-16 00:02:21 +08:00
    @JohnLou 用 var 声明的话数组里面存的是 [ funciton(){console.log(i)}, funciton(){console.log(i)}...]
    用 let 声明数组里面的即是[ function(){console.log("1")}, function(){console.log("2")} ....]?
    jswh
        6
    jswh  
       2016-11-16 00:09:00 +08:00
    brooky
        7
    brooky  
    OP
       2016-11-16 00:18:21 +08:00
    @jswh 我就是看到这个没有看明白的...
    JohnLou
        8
    JohnLou  
       2016-11-16 00:30:14 +08:00 via iPhone
    @brooky 不是很准确,可以理解为这样[{let i=0;}, {let i =1}], i ++之后就新起一个块。
    SoloCompany
        9
    SoloCompany  
       2016-11-16 01:08:54 +08:00
    你应该这样理解
    本来不应该有 var 和 let 的
    因为他们其实除了作用域以外没有任何区别
    但由于历史原因, var 的作用域泄露的问题被吐槽太多了,又不得不兼容,所以才产生了 let

    js 三种变量声明方式

    x;
    var x;
    let x;

    如果可以用更合适的关键字修饰符的话,就是等同于
    global x; (前提是变量没有在任何作用域中被定义)
    function local x;
    local x;
    ByZHkc3
        10
    ByZHkc3  
       2016-11-16 01:17:10 +08:00
    作用域的区别, let 只在当前循环或函数里有效,这等同于再函数里 var 了一样。
    brooky
        11
    brooky  
    OP
       2016-11-16 01:45:56 +08:00
    ````
    var tmp = new Date();

    function f() {
    console.log(tmp);
    if (false) {
    var tmp = "hello world";
    }
    }

    f(); // undefined
    ````
    又来个问题, 自学真的很不行是不是, 求老司机带带 付费指导
    baconrad
        12
    baconrad  
       2016-11-16 01:56:29 +08:00
    因 var 的量明被提前,
    先理後, 再看就比容易理解.


    ```
    var a = [];
    var i;
    for ( i = 0; i < 10; i++) {
    a[i] = function () {
    console.log(i);
    };
    }
    a[6](); // 10
    ```


    ```
    var tmp = new Date();

    function f() {
    var tmp;
    console.log(tmp);
    if (false) {
    tmp = "hello world";
    }
    }

    f(); // undefined

    ```
    geekaven
        13
    geekaven  
       2016-11-16 02:27:52 +08:00
    作用域,变量提升。
    geekaven
        14
    geekaven  
       2016-11-16 02:28:34 +08:00
    可以看看《你不知道的 Javascript 》 第一卷 1 , 2 , 3 , 4 章
    Sivan
        15
    Sivan  
       2016-11-16 02:32:41 +08:00
    建议楼主先学一下基础知识再去学 ES6 相关改进。
    yyfearth
        16
    yyfearth  
       2016-11-16 06:58:34 +08:00
    @miketeam 其实不是复杂 是由于大量的历史包袱 JS 一开始设计的不好 然后修修改改 导致这样的问题
    yyfearth
        17
    yyfearth  
       2016-11-16 07:00:50 +08:00
    @brooky 所以两者不要混用
    let 是 block scope 和大多数语言一样 所以最近才出现 减少问题的发生
    var 是 function scope 由于历史原因 对于很多人来说 非常容易混淆

    所以你能用 let 的情况下 只用 let
    如果你要考虑浏览器兼容性的情况下 就只用 var
    不要混用 把自己搞糊涂
    kitalphaj
        18
    kitalphaj  
       2016-11-16 07:27:00 +08:00
    难道不是还有一个 const 么。。。。所以一共是四种修饰方式么? var, let, const, 和空。。。
    murmur
        20
    murmur  
       2016-11-16 08:05:13 +08:00
    目前 var 和 let 没任何区别 本来我以为 babel 会把 let 的变量都搞到函数里隔绝作用域 结果如果没重名的话就是把 var 改成 let
    如果有重名就在 let 的变量下家个下划线。。
    ryanzyy
        21
    ryanzyy  
       2016-11-16 08:48:36 +08:00
    for (var i = 0; i < 10; i++) console.log(i);
    i -> 10
    for (let i = 0; i < 10; i++) console.log(i);
    i -> undefined
    misaka19000
        23
    misaka19000  
       2016-11-16 09:09:26 +08:00
    let 这玩意是不是出自 lisp
    ssehacker
        24
    ssehacker  
       2016-11-16 09:22:35 +08:00
    13 楼正解,就这两点。
    4641585
        25
    4641585  
       2016-11-16 09:31:50 +08:00
    @murmur

    实际用下来感觉 var 的变量提升就是一个需要注意的坑,想不到除了作为面试题还有什么场合能用得上…所以 babe 这么做也没什么不对 233
    JohnLou
        26
    JohnLou  
       2016-11-16 11:31:16 +08:00
    补充一下我 8 楼说的,楼主是否明白了呢,执行下下面的代码。

    for(let i = 0;i < 3;i ++) {
    a[i] = function () {console.log(i);}
    setTimeout(function () {i = i * 1000}, 1000);
    }

    a[1]() // 1000
    a[2]() // 2000
    coldsnap
        27
    coldsnap  
       2016-11-16 11:31:33 +08:00
    @murmur
    你把楼主用 let 的语法用 babel 转了试试,通过新建一个 loop 函数的确给了 i 作用域,得到也是期望的结果;改名能避免变量提升带来的问题,这样做没问题。例如:
    { let a = 'a' } console.log(a)
    会被编译成
    { var _a = 'a' } console.log(a)
    你得到的结果和你在支持 let 语法的宿主环境中一样。

    而且有些情况根本不需要编译,例如写 electron 和 node 。准确来说你应该说对你没区别。
    SuperMild
        28
    SuperMild  
       2016-11-16 11:36:28 +08:00
    自从有了 let 之后,好像提倡不要用 var 了,绝大多数情况下用 let 就够了。如果一时之间觉得比较乱,建议不要去管 var ,只管用 let 就好了,没有必要执着于两者的区别(过一段时间回头看很可能会豁然开朗)。
    chnhyg
        29
    chnhyg  
       2016-11-16 11:47:51 +08:00
    var 与 let
    - let 是更完美的 var 。
    - let 声明的变量拥有块级作用域。
    - let 声明的全局变量不是全局对象的属性。
    - 形如 for(let I …) 的循环在每次迭代时都为 I 创建新的绑定。
    - let 声明的变量直到控制流到达该变量被定义的代码行时才会被装载,所以在到达之前使用该变量会触发错误。不可访问的这段时间变量一直处于作用域中,但是尚未装载,它们位于临时死区(Temporal Dead Zone)中。
    - 用 let 重定义变量会抛出一个语法错误。
    vlxer
        30
    vlxer  
       2016-11-16 14:54:20 +08:00
    要理解这个,首先要理解词法作用域。

    * 定义一个函数的时候,函数会保存当前作用域
    * 函数执行的时候,会创建一个新的作用域,用于存放函数参数和局部变量,同时新的作用域指向函数保存的作用域,构成作用域链

    因此,第一个例子中,由于没有块级作用域,循环里的所有函数都是共享同一个作用域的, a[0] == a[1] == ... == a[9] == i == 10 。

    第二个例子中,有块级作用域,等价于:

    ```js
    var a = [];
    for (var i = 0; i < 10; i++) {
    (function(i) {
    a[i] = function() {
    console.log(i);
    };
    })(i);
    }
    a[6](); // 6
    ```

    通过查看 babel 的转换也可以看出:
    http://babeljs.io/repl/#?babili=false&evaluate=true&lineWrap=false&presets=latest%2Creact%2Cstage-2&experimental=false&loose=false&spec=false&code=var%20a%20%3D%20%5B%5D%3B%0Afor%20(let%20i%20%3D%200%3B%20i%20%3C%2010%3B%20i%2B%2B)%20%7B%0A%20%20a%5Bi%5D%20%3D%20function%20()%20%7B%0A%20%20%20%20console.log(i)%3B%0A%20%20%7D%3B%0A%7D%0Aa%5B6%5D()%3B%20%2F%2F%206&playground=true

    不明白问我,付费指导。
    anthozoan77
        31
    anthozoan77  
       2016-11-28 22:47:32 +08:00
    IIFE
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2877 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 14:11 PVG 22:11 LAX 07:11 JFK 10:11
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86