推荐关注
› Meteor
› JSLint - a JavaScript code quality tool
› jsFiddle
› D3.js
› WebStorm
推荐书目
› JavaScript 权威指南第 5 版
› Closure: The Definitive Guide
zhy0216

记 js 的一个小坑

  •  
  •   zhy0216 · Sep 23, 2016 · 7392 views
    This topic created in 3698 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
    swirling
    Sep 23, 2016
    1
    var i = 0;
    for(; i<3; i ++){
    funcList.push(function(){
    console.log(i);
    })
    }

    这样不就好理解了吗。。。
    viko16
    viko16
    Sep 23, 2016
    2
    执行函数的时候才去读 i 的值
    learnshare
    learnshare
    Sep 23, 2016
    3
    经典坑 Number 0
    hronro
    hronro
    Sep 23, 2016 via Android
    4
    for 小括号里面第一个语句,定义的变量 i ,是全局变量 i ,没什么不好理解的吧
    lovedebug
    lovedebug
    Sep 23, 2016
    5
    JS 在 ES6 之前 for 循环没有块作用域
    loushizan
    loushizan
    Sep 23, 2016
    6
    var funcs = [];
    for (var i = 0; i < 3; i++) {
    (function(i) {
    funcs.push(function() {
    console.log(i);
    });
    })(i);
    };
    kimown
    kimown
    Sep 23, 2016
    7
    论 ES6 的巨大进步
    Skyxianbo
    Skyxianbo
    Sep 23, 2016
    8
    没什么不好理解的, var 定义的 i 是全局的,等你在第二个循环里面调用的时候才去读 i 的值,这个时候的 i 已经经过第一个循环然后变成 3 了。你把 var 换成 let ,这样定义的 i 只在第一个循环里面起效果,就不会出现这样的问题了。可以去看看 ES6 的块级作用域。
    aristotll
    aristotll
    Sep 23, 2016
    9
    用 let...
    think2011
    think2011
    Sep 23, 2016
    10
    let let let
    wallax
    wallax
    Sep 23, 2016
    11
    不用 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
    iyangyuan
    Sep 23, 2016
    12
    入门问题
    SuperMild
    SuperMild
    Sep 23, 2016 via iPad
    13
    如非必要就别用旧标准了, let 已经得到广泛支持。
    js0816
    js0816
    Sep 23, 2016
    14
    let 替换 var 就 O 了
    prefere
    prefere
    Sep 23, 2016
    15
    问个小白问题,这个菊部变量 i 存哪了?
    http://imgur.com/KV5NjMA.jpg
    prefere
    prefere
    Sep 23, 2016❤️1
    16
    更正: 菊>局
    prefere
    prefere
    Sep 23, 2016
    17
    zhouyg
    zhouyg
    Sep 23, 2016
    18
    一点开我就猜是这个问题,😄太经典。
    defia
    defia
    Sep 23, 2016 via iPhone
    19
    闭包内保留的是变量引用
    cheneydog
    cheneydog
    Sep 23, 2016
    20
    典型的闭包问题
    FrankFang128
    FrankFang128
    Sep 23, 2016
    21
    搞不懂 var ,最后去用 let 。
    呵呵。
    wangcansun
    wangcansun
    Sep 23, 2016
    22
    所以 es6 中使用 let 了
    ianva
    ianva
    Sep 23, 2016
    23
    ES6 的实现:

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

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

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

    @fundon 先学习了
    YuJianrong
    YuJianrong
    Sep 24, 2016 via iPhone
    34
    @hronro 成本高在哪?编译出来大小增加不大啊。
    如果用到一些增强的内置函数需要挂 polyfill ,但这个可以自己挑需要什么啊,即使全部挂上也没多大。
    Bensendbs
    Bensendbs
    Sep 24, 2016
    35
    用 let...var 有作用域提升的问题..
    winiex
    winiex
    Sep 24, 2016
    36
    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
    zongren
    Sep 24, 2016
    37
    用闭包也能解决吧
    wizardforcel
    wizardforcel
    Sep 24, 2016
    38
    @prefere 每个函数在调用时都会有一个帧,局部变量当然是存到帧里面。但是有的帧在函数返回时会销毁, lz 这种情况不会。因为函数中的函数会关联外层函数的帧,这个帧还有函数在用就没法销毁。
    poke707
    poke707
    Sep 24, 2016
    39
    这个可以说是 Javascript 的坑也可以说是 feature 。虽然有意这样写的情况不多见吧。
    重要的是要理解编程语言本身,变量的值和引用啊,作用域啊,语法和表达式啊。
    如果不重视基本功, ES6 照样会踩坑。

    比如 [1,2,3].map(n => {value: n}) 有人觉得会返回他以为的东西,有人觉得会报错(比如我,我都忘了有 label 这回事)。
    但结果是不但不报错还会返回 [undefined, undefined, undefined] 呢。
    neone
    neone
    Sep 24, 2016
    40
    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
    itisthecon
    Sep 24, 2016
    41
    想通了这个基本就能填上变量申明提升的坑了
    > var myvar = 'global value';
    > (function() {console.log(myvar);var myvar='local value';})();
    undefined
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   3503 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 97ms · UTC 03:55 · PVG 11:55 · LAX 19:55 · JFK 22:55
    ♥ Do have faith in what you're doing.