萬物皆對象之:for in 引出的 hasOwnProperty

引子:

咱們能夠發現 for in 在vscode的代碼片斷是這樣的:數組

for (const key in object) {
    if (object.hasOwnProperty(key)) {
        const element = object[key];
        
    }
}
os: 用for in 循環的時候是要有這個判斷,vscode真嚴謹,真🐂🍺

可是爲何要有hasOwnProperty的這一層判斷呢?
不少人都會脫口而出:由於會循環這個對象的全部屬性影響效率app

實驗一:

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之外的 可枚舉屬性。循環將遍歷對象自己的全部可枚舉屬性,以及對象從其構造函數原型中繼承的屬性(就是原型鏈上)

一、這裏的‘任意順序’實際上是(從自身對象遍歷到原型鏈)這樣的順序。性能

二、constructor、isPrototypeOf、toString、propertyIsEnumerable這些Object原型對象上的屬性默認是不可枚舉的因此for in 循環不出來:spa

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

三、Object.keys()方法會返回一個由一個給定對象的自身可枚舉屬性組成的數組,數組中屬性名的排列順序和使用for...in循環遍歷該對象時返回的順序一致prototype


結論:

Object.keys: 對象自身可枚舉的屬性
Object.getOwnPropertyNames: 對象自身屬性
for in: 循環對象包括原型鏈上可枚舉屬性
hasOwnProperty(): 判斷對象自身是否有這個屬性code

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.246msorm


數組長度: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效率的確高不少

相關文章
相關標籤/搜索