引子:

我们可以发现 for in 在vscode的代码片段是这样的:

for (const key in object) {
    if (object.hasOwnProperty(key)) {
        const element = object[key];
        
    }
}
os: 用for in 循环的时候是要有这个判断,vscode真严谨,真🐂🍺

但是为什么要有hasOwnProperty的这一层判断呢?
很多人都会脱口而出:因为会循环这个对象的所有属性影响效率

实验一:

let obj = {mood: 'happy'}; 
for(let key in obj){
    console.log(key)//mood
}

//可以看到并没有打印出obj对象原型链上的那些属性: constructor、isPrototypeOf、toString、propertyIsEnumerable等
os: 貌似根本用不到hasOwnProterty这一层判断啊

实验二:

Object.prototype.level=666
for(let key in obj){
    console.log(key)//mood、level
}
Object.keys(obj)//["mood"]

实验三:

Object.defineProperties(Object.prototype,{
    isSuper: {
        value: true,
        enumerable: true
    },
    isNormal: {
        value: true,
        enumerable: false
    }
});
Object.defineProperties(obj,{
    color:{
        value: 'yellow',
        enumerable: true
    },
    num: {
        value: 2,
        enumerable: false
    }
});

for(let key in obj){
    console.log(key)//mood、color、level、isSuper
}
Object.keys(obj)//["mood", "color"]

mdn里for...in的定义

for...in语句以任意顺序遍历一个对象的除Symbol以外的可枚举属性。循环将遍历对象本身的所有可枚举属性,以及对象从其构造函数原型中继承的属性(就是原型链上)

1、这里的‘任意顺序’其实是(从自身对象遍历到原型链)这样的顺序。

2、constructor、isPrototypeOf、toString、propertyIsEnumerable这些Object原型对象上的属性默认是不可枚举的所以for in 循环不出来:

Object.getOwnPropertyDescriptor(Object.prototype, 'toString')
//查看toString这个属性的描述
{value:ƒ,writable:true,enumerable:false,configurable:true}

3、Object.keys()方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和使用for...in循环遍历该对象时返回的顺序一致


结论:

Object.keys: 对象自身可枚举的属性
Object.getOwnPropertyNames: 对象自身属性
for in: 循环对象包括原型链上可枚举属性
hasOwnProperty(): 判断对象自身是否有这个属性

for in + hasOwnProperty 就是循环遍历一个对象的自身可枚举键 => Object.keys()


番外篇:for in的性能

let arr = [],
    n = 10000
for (let index = 0; index < n; index++) {
    arr.push(index)
}
function forin() {
    let temp = []
    console.time(`for_in(${n}):`)
    for (const key in arr) {
        temp.push(arr[key])
    }
    console.timeEnd(`for_in(${n}):`)
}

function forinOwn() {
    let temp = []
    console.time(`for_in_own(${n}):`)
    for (const key in arr) {
        if (arr.hasOwnProperty) {
            temp.push(arr[key])
        }
    }
    console.timeEnd(`for_in_own(${n}):`)
}

function forof() {
    let temp = []
    console.time(`for_of(${n}):`)
    for (const item of arr) {
        if (arr.hasOwnProperty) {
            temp.push(item)
        }
    }
    console.timeEnd(`for_of(${n}):`)
}

console.log('数组长度:' + n)
forin()
forinOwn()
forof()

数组长度:10000
for_in(10000):: 2.251ms
for_in_own(10000):: 4.474ms
for_of(10000):: 2.246ms


数组长度:1000000
for_in(1000000):: 187.626ms
for_in_own(1000000):: 254.605ms
for_of(1000000):: 65.449ms


数组长度:10000000
for_in(10000000):: 2588.375ms
for_in_own(10000000):: 2500.013ms
for_of(10000000):: 1025.442ms


1亿就炸了。。

JavaScript heap out of memory
<--- Last few GCs --->

[53665:0x104000000]     1966 ms: Mark-sweep 577.3 (585.0) -> 577.3 (582.0) MB, 64.3 / 0.0 ms  (average mu = 0.459, current mu = 0.001) last resort GC in old space requested
[53665:0x104000000]     2031 ms: Mark-sweep 577.3 (582.0) -> 577.3 (582.0) MB, 65.1 / 0.0 ms  (average mu = 0.314, current mu = 0.000) last resort GC in old space requested

数组长度:20000000
for_in(20000000):: 6390.817ms
for_in_own(20000000):: 5915.073ms
for_of(20000000):: 979.788ms

结论:for of效率的确高很多

测试公式: $$x*y=z$$
测试公式: $2^32$ 内联???

test

baidu

  • 比如今年我们与 Arm 中国建立了战略合作,通过我们的能力协助 Arm 中国一起构建了 AIoT 的开发者社区——极术社区

湖人总冠军
514 声望721 粉丝

菜鸟与孤鹜齐飞