天天看點

JS避坑-如何優雅地周遊對象

雲栖号資訊:【 點選檢視更多行業資訊

在這裡您可以找到不同行業的第一手的上雲資訊,還在等什麼,快來!

雖然已知for...in會周遊對象原型鍊上的屬性,但心想用于字面量建立的對象應該沒有什麼大問題,于是便棄hasOwnProperty于不顧,最終被工單教做人了。在修複中總結了幾個可以讓周遊對象更加優雅的方法。

for...in踩坑複盤

能不能去掉hasOwnProperty?

for...in常用于周遊對象或者數組,比如

const obj = {
    a: 1,
    b: 2
};

for (const key in obj) {
    console.log(key, obj[key]);
}

// 輸出
// a 1
// b 2           

我們都知道for...in會周遊原型鍊上的屬性,是以一般會結合hasOwnProperty來判斷屬性是否在對象自身上,而不是在原型鍊上。

for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
        console.log(key, obj[key]);
    }
}           

可每次都要多增加一行代碼,多一個縮進,實在麻煩,能不能偷懶不加hasOwnProperty?

于是我動起了小心思,使用字面量建立的對象或者數組,不是類的執行個體,原型鍊上幹幹淨淨的,那周遊的時候也沒必要判斷了吧。于是就在周遊字面量對象時放心大膽地把hasOwnProperty抛棄了。

工單打臉

我負責的産品是API,使用者在自己的頁面應用中引入使用。某天,有使用者回報若同時引入我家API和另一個腳本庫就會引發報錯:

JS避坑-如何優雅地周遊對象

調試發現報錯發生在:

JS避坑-如何優雅地周遊對象

renderLayers是一個數組,這裡原本是周遊可渲染圖層進行操作,而圖層對象都有isHidden方法,為何報錯呢?原因是使用者另引入的腳本對Object、Array、String等基礎引用類型的原型鍊做了擴充,加入了一些方法。是以在for...in周遊renderLayers時,也周遊到了addRange、clear這些屬性,layer則指派為一個function,而不是圖層對象。

for(var prop in source) {
        if(replace == false && dest[prop] != null) { continue; }
        dest[prop] = source[prop];
    }
    return dest;
};

Object.extend(Array.prototype, {
    addRange: function(items) {
        if(items.length > 0) {
            for(var i=0; i < items.length; i++) {
                this.push(items[i]);
            }
        }
    },
    clear: function() {
        this.length = 0;
        return this;
    },
    // ...
}, false);           

避坑指南

如上所述,隻能開始内部大清理,所有使用for...in而沒有帶hasOwnProperty的地方都需要進行改造。除了加上hasOwnProperty進行判斷之外,視具體情況還可以使用以下方法,讓你的代碼更加優雅:

1. 數組盡量使用forEach進行周遊

比如引發報錯的這一段,renderLayers是一個數組,直接使用forEach進行周遊即可:

JS避坑-如何優雅地周遊對象

2. 對象深拷貝盡量使用解構指派

for...in可周遊對象屬性實作一一指派完成簡單的對象深拷貝,這種操作可以用解構指派來實作,更簡單。

return {...obj};
}

const obj = {
    a: 1
};
const objCopy = copy(obj);
console.log(objCopy);
// 輸出:{a: 1}           

3. 周遊鍵值可以結合Object.entries()和forEach

Object.entries()傳回對象所有鍵值對組成的數組,再結合forEach即可完成周遊。若隻是周遊對象的鍵或者值,可以使用Object.keys()和Object.values()。

在改造過程中,可以抽象出一個forIn方法作為工具函數,這樣多處調用就可以省掉不少備援代碼啦~

Object.entries(obj).forEach(entry => {
        callback(...entry);
    });
}

const obj = {
    a: 1
};
forIn(obj, (key, value) => {
    console.log(key, value);
});
// 輸出:a 1           

4. 若要使用break、return提前結束循環,需結合for...of

方法3雖好,但使用forEach沒辦法中斷循環,這時候可以使用for...of,也是非常簡潔的。

a: 1,
    b: 2
};
for (let [key, value] of Object.entries(obj)) {
    if (value > 1) {
        break;
    }
    console.log(key, value);
}
// 輸出:a 1           

【雲栖号線上課堂】每天都有産品技術專家分享!

課程位址:

https://yqh.aliyun.com/live

立即加入社群,與專家面對面,及時了解課程最新動态!

【雲栖号線上課堂 社群】

https://c.tb.cn/F3.Z8gvnK

原文釋出時間:2020-06-03

本文作者:多多洛愛學習

本文來自:“

掘金

”,了解相關資訊可以關注“掘金”

繼續閱讀