V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
fulvaz
V2EX  ›  问与答

为什么不要使用 for...in

  •  
  •   fulvaz · 2018-05-24 19:02:37 +08:00 · 3664 次点击
    这是一个创建于 2160 天前的主题,其中的信息可能已经有所发展或是发生改变。

    吃完晚饭休息, 随便发点东西

    之前半夜无聊发了点东西, 关于如何优雅地遍历对象 /t/456374

    楼下说使用 for...in 遍历对象的 key

    然而 for...in 的前提是, 你需要保证 Array 的原型没有被改变过.

    为啥? 因为 for...in 会遍历所指定对象全部 enumerable, 如果说你使用的某个库重写了 Array 的原型, 那么遍历的结果就会很奇怪了, 比如说

    Array.prototype.val = 123;
    
    obj = {1: 'a', 2: 'b'}
    
    for (const key in Object.keys(obj)) {
    	console.log(key);
    }
    
    

    上面代码的结果是 0, 1, val, 所以使用 for...in 必须要加 hasOwnProperty.

    不然就乖乖用 forEach.

    多说一句, 正常情况自己是不会重写 Array 的原型的, 但是你不能保证你用的第三方库没使用这种黑魔法.

    再多说一句, 如果重写某个非 enumerable 的属性, 那么该属性还是 enumerable 的, 如 Array.forEach = something, for...in 还是无法遍历的.

    第 1 条附言  ·  2018-05-24 20:48:58 +08:00
    大意了!!! 业务写迷糊了

    准确的 demo 是

    ```
    Object.prototype.val = 123;

    obj = {1: 'a', 2: 'b'}

    for (const key in obj) {
    console.log(key);
    }
    ```

    原文也应该是, 不知道啥库把 Object 的原型给改了

    嗨呀, 好气, 装逼失败
    15 条回复    2018-05-25 09:02:34 +08:00
    iloahz
        1
    iloahz  
       2018-05-24 19:35:00 +08:00 via Android
    不应该是不要改原生类型的原型么。。。
    murmur
        2
    murmur  
       2018-05-24 19:46:02 +08:00
    我也在想,动不动搞自己类数组出来是图个啥
    fulvaz
        3
    fulvaz  
    OP
       2018-05-24 19:47:33 +08:00
    @iloahz 你不能保证你用的库不改呀
    Pastsong
        4
    Pastsong  
       2018-05-24 19:48:36 +08:00   ❤️ 1
    @fulvaz 可以保证这种库我不用
    murmur
        5
    murmur  
       2018-05-24 19:49:04 +08:00
    看错了,不过我记得 array.prototype 扩展的方法被遍历出来是 IE 专属错误?

    Array.prototype.val = 123;

    obj = {1: 'a', 2: 'b'}

    for (var key in obj) {
    console.log(key);
    }

    这个输出 1 2 没有 val

    看来会的越多越容易出麻烦 当然写 var 是在 ie 做兼容写顺手了 没用 object.keys 而已
    yushiro
        6
    yushiro  
       2018-05-24 19:50:05 +08:00 via iPhone
    ES6 里面用 for of,专门解决这个问题的
    broker
        7
    broker  
       2018-05-24 20:04:44 +08:00
    for in 和 in operator 在一起时候会报错~

    for (let a = b in c; false;); // does not parse

    for (let a = (b in c); false;); // parses fine

    另一个就是定义 enumerable

    Boolean.prototype.foo = 'bar';

    for (let a in ('' in {})) {
    console.log(a);
    } // prints 'foo'
    des
        8
    des  
       2018-05-24 20:14:07 +08:00 via Android
    for (const key in Object.keys(obj))

    ???
    写错了吧?
    Biwood
        9
    Biwood  
       2018-05-24 20:53:28 +08:00 via Android
    假如需要用 return 中断循环操作怎么办? forEach 无法中断吧。另外,修改原生对象的原型这种问题应该在调试的时候就能被发现,出现几率较低,可以忽略。
    des
        10
    des  
       2018-05-24 21:29:53 +08:00 via Android
    @Biwood 可以用 catch,2333
    Garwih
        11
    Garwih  
       2018-05-24 21:36:31 +08:00
    @Biwood #9 可以用 every()
    tommyZZM
        12
    tommyZZM  
       2018-05-24 23:43:31 +08:00
    DOLLOR
        13
    DOLLOR  
       2018-05-25 07:57:24 +08:00 via Android
    @Biwood
    some()、every()
    wengjin456123
        14
    wengjin456123  
       2018-05-25 09:01:47 +08:00
    是因为会遍历到原型链上的?
    wengjin456123
        15
    wengjin456123  
       2018-05-25 09:02:34 +08:00
    一般考虑清楚就可以自由选择了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5370 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 08:52 · PVG 16:52 · LAX 01:52 · JFK 04:52
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.