V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
zhy0216
0D

记 js 的一个小坑

  •  
  •   zhy0216 · Sep 23, 2016 · 6492 views
    This topic created in 3508 days ago, the information mentioned may be changed or developed.
    Supplement 1  ·  Sep 23, 2016
    总结两点: 1. var 的声明会拉到函数顶部. 2. closure 闭包内保留的是变量引用

    确实是忘了第二点了...

    不过还是有点没明白为什么用 let 就解决这个问题了呢?
    Supplement 2  ·  Sep 24, 2016
    其实不仅仅是作用域的问题, 关键是: 引用吓 @wizardforcel 的话, 每个函数在调用时都会有一个帧,局部变量当然是存到帧里面。但是有的帧在函数返回时会销毁, lz 这种情况不会。因为函数中的函数会关联外层函数的帧,这个帧还有函数在用就没法销毁
    41 replies    2016-09-24 20:40:01 +08:00
    swirling
        1
    swirling  
       Sep 23, 2016
    var i = 0;
    for(; i<3; i ++){
    funcList.push(function(){
    console.log(i);
    })
    }

    这样不就好理解了吗。。。
    viko16
        2
    viko16  
       Sep 23, 2016
    执行函数的时候才去读 i 的值
    learnshare
        3
    learnshare  
       Sep 23, 2016
    经典坑 Number 0
    hronro
        4
    hronro  
       Sep 23, 2016 via Android
    for 小括号里面第一个语句,定义的变量 i ,是全局变量 i ,没什么不好理解的吧
    lovedebug
        5
    lovedebug  
       Sep 23, 2016
    JS 在 ES6 之前 for 循环没有块作用域
    loushizan
        6
    loushizan  
       Sep 23, 2016
    var funcs = [];
    for (var i = 0; i < 3; i++) {
    (function(i) {
    funcs.push(function() {
    console.log(i);
    });
    })(i);
    };
    kimown
        7
    kimown  
       Sep 23, 2016
    论 ES6 的巨大进步
    Skyxianbo
        8
    Skyxianbo  
       Sep 23, 2016
    没什么不好理解的, var 定义的 i 是全局的,等你在第二个循环里面调用的时候才去读 i 的值,这个时候的 i 已经经过第一个循环然后变成 3 了。你把 var 换成 let ,这样定义的 i 只在第一个循环里面起效果,就不会出现这样的问题了。可以去看看 ES6 的块级作用域。
    aristotll
        9
    aristotll  
       Sep 23, 2016
    用 let...
    think2011
        10
    think2011  
       Sep 23, 2016
    let let let
    wallax
        11
    wallax  
       Sep 23, 2016
    不用 let 也能解决 只要控制好作用域就行了

    var funclist = [];

    var func = function(a){
    funclist.push(function(){console.log(a)});
    };

    for(var i = 0; i < 3; i++){
    func(i);
    }

    for(var j = 0; j < 3; j++){
    funclist[j]();
    }
    iyangyuan
        12
    iyangyuan  
       Sep 23, 2016
    入门问题
    SuperMild
        13
    SuperMild  
       Sep 23, 2016 via iPad
    如非必要就别用旧标准了, let 已经得到广泛支持。
    js0816
        14
    js0816  
       Sep 23, 2016
    let 替换 var 就 O 了
    prefere
        15
    prefere  
       Sep 23, 2016
    问个小白问题,这个菊部变量 i 存哪了?
    http://imgur.com/KV5NjMA.jpg
    prefere
        16
    prefere  
       Sep 23, 2016   ❤️ 1
    更正: 菊>局
    prefere
        17
    prefere  
       Sep 23, 2016
    zhouyg
        18
    zhouyg  
       Sep 23, 2016
    一点开我就猜是这个问题,😄太经典。
    defia
        19
    defia  
       Sep 23, 2016 via iPhone
    闭包内保留的是变量引用
    cheneydog
        20
    cheneydog  
       Sep 23, 2016
    典型的闭包问题
    FrankFang128
        21
    FrankFang128  
       Sep 23, 2016
    搞不懂 var ,最后去用 let 。
    呵呵。
    wangcansun
        22
    wangcansun  
       Sep 23, 2016
    所以 es6 中使用 let 了
    ianva
        23
    ianva  
       Sep 23, 2016
    ES6 的实现:

    [1,2,3].map( num=>()=>console.log(num) ).forEach(fn=>fn())

    在大部分的情况下 map, filter, reduce, forEach 代替 for 要简单的多
    ianva
        24
    ianva  
       Sep 23, 2016
    再彻底一点:

    [...Array(3).keys()].map( num=>()=>console.log(num) ).forEach(fn=>fn())
    21grams
        25
    21grams  
       Sep 23, 2016
    别再用 var 了,全部用 let
    longear
        26
    longear  
       Sep 23, 2016
    @prefere 嘘。。。 无需更正,了解你了
    fundon
        27
    fundon  
       Sep 23, 2016
    安利下 「 ES6: 快速体验,及实用小贴士」 https://github.com/fundon/ES6-QuickStart-and-Tips
    vwok
        28
    vwok  
       Sep 23, 2016   ❤️ 1
    @prefere ![]( http://imgur.com/Ob8Y855) 看的讲闭包的都没讲到原型结构啊,今天终于知道 closure 是怎么来的了
    sudoz
        29
    sudoz  
       Sep 23, 2016
    入队的时候没有执行 console.log 啊
    hronro
        30
    hronro  
       Sep 23, 2016 via Android
    楼上的各位说用 let 的,现在没人敢直接在生产环境下直接用 let 吧?都是要 babel 编译之后才能用的。如果只是一个小程序的话,上 babel 的成本又太高了
    yhxx
        31
    yhxx  
       Sep 23, 2016
    因为 let 提供了块级作用域
    mingyun
        33
    mingyun  
       Sep 24, 2016
    @magicdawn
    @ianva 卧槽,看不懂

    @fundon 先学习了
    YuJianrong
        34
    YuJianrong  
       Sep 24, 2016 via iPhone
    @hronro 成本高在哪?编译出来大小增加不大啊。
    如果用到一些增强的内置函数需要挂 polyfill ,但这个可以自己挑需要什么啊,即使全部挂上也没多大。
    Bensendbs
        35
    Bensendbs  
       Sep 24, 2016
    用 let...var 有作用域提升的问题..
    winiex
        36
    winiex  
       Sep 24, 2016
    let 的作用于是我们常见意义上的块级作用于,而 var 的作用域则仅适用于 function ,一般意义上的 code block 对它没有作用域的限制意义。从编程语言的角度来看, var 声明的变量的作用域部分是不完整的。建议用 let 。

    [“ let ” keyword vs “ var ” keyword in Javascript]( http://stackoverflow.com/questions/762011/let-keyword-vs-var-keyword-in-javascript)
    zongren
        37
    zongren  
       Sep 24, 2016
    用闭包也能解决吧
    wizardforcel
        38
    wizardforcel  
       Sep 24, 2016
    @prefere 每个函数在调用时都会有一个帧,局部变量当然是存到帧里面。但是有的帧在函数返回时会销毁, lz 这种情况不会。因为函数中的函数会关联外层函数的帧,这个帧还有函数在用就没法销毁。
    poke707
        39
    poke707  
       Sep 24, 2016
    这个可以说是 Javascript 的坑也可以说是 feature 。虽然有意这样写的情况不多见吧。
    重要的是要理解编程语言本身,变量的值和引用啊,作用域啊,语法和表达式啊。
    如果不重视基本功, ES6 照样会踩坑。

    比如 [1,2,3].map(n => {value: n}) 有人觉得会返回他以为的东西,有人觉得会报错(比如我,我都忘了有 label 这回事)。
    但结果是不但不报错还会返回 [undefined, undefined, undefined] 呢。
    neone
        40
    neone  
       Sep 24, 2016
    JS 的经典问题。
    `var` 声明是没有块级作用域的,所以上面的代码等于:
    ```
    var i;

    for (i = 0; i < 3; i++) {
    funcList.push(function() {
    console.log(i);
    });
    }

    ```
    ES5 中可以使用闭包解决, ES6 中直接使用`let`即可。
    `let`声明的变量具有块级作用域,所以 3 次循环会产生 3 个不相同(仅同名)的变量`i`,添加入数组中的函数引用的是不同的变量。事实上你在循环的外部先用`let`定义变量`i`,那么结果也都是 3 3 3 ,如下:
    ```
    let funcList = [];

    let i;
    for (i = 0; i < 3; i++) {
    funcList.push(() => {
    console.log(i);
    });
    }

    for (let j = 0; j < 3; j++) {
    funcList[j]();
    }

    ```
    itisthecon
        41
    itisthecon  
       Sep 24, 2016
    想通了这个基本就能填上变量申明提升的坑了
    > var myvar = 'global value';
    > (function() {console.log(myvar);var myvar='local value';})();
    undefined
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   2500 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 96ms · UTC 02:39 · PVG 10:39 · LAX 19:39 · JFK 22:39
    ♥ Do have faith in what you're doing.