
英文 | https://medium.com/dailyjs/10-utility-functions-for-working-with-objects-in-javascript-a5ee53ef8809
翻譯 | 楊小愛
本文将着眼于在 JavaScript 中處理對象的最重要的實用函數。
01、Object.freeze
Object.freeze() 當機一個對象。無法再更改當機的對象。它傳回傳入的相同對象。
這是通過在建立時當機對象來實作 JavaScript 不變性的最簡單方法。
const game = Object.freeze({
name: 'Warcraft'
});
game.developer = 'Blizzard';
//TypeError: Cannot add property developer, object is not extensible
唯一需要注意的是 Object.freeze() 隻當機對象的直接屬性,執行所謂的“淺當機”。稍後我們将使用遞歸和其他對象效用函數來實作深度當機函數。
02、Object.isFrozen
Object.isFrozen() 檢測對象是否被當機。
console.log(Object.isFrozen(game));
//true
03、Object.keys
Object.keys() 給出一個包含所有擁有的屬性鍵的數組。檢查下面的代碼,将遊戲對象的所有鍵檢索到一個新的字元串數組中。
const game = {
name: 'Warcraft',
developer: 'Blizzard'
};
const keys = Object.keys(game);
console.log(keys);
// ["name", "developer"]
一旦我們有了鍵數組,我們就可以開始在它上面使用數組方法了,比如 forEach。
Object
.keys(game)
.forEach(key => console.log(key));
04、Object.values()
Object.values() 傳回一個包含所有擁有的屬性值的數組。
const values = Object.values(game);
console.log(values);
// ["Warcraft", "Blizzard"]
05、Object.entries
Object.entries() 傳回一個對象所有屬性的 [key, value] 對數組。
const game = {
name: 'Warcraft',
developer: 'Blizzard'
};
const keyValuePairs = Object.entries(game);
console.log(keyValuePairs);
// [
// ["name", "Warcraft"],
// ["developer", "Blizzard"]
// ]
請注意,條目是一個具有兩個值 [key, value] 的數組。結果是一組數組。
一旦我們在數組中擁有所有 [key, value] 對,我們使用數組方法。
Object
.entries(game)
.forEach(([key, value]) => console.log(key, value));
//name Warcraft
//developer Blizzard
建立一個深度當機工具
現在讓我們嘗試使用 Object.entries 和 Object.freeze 實用程式建立一個深度當機實用程式。
請記住 Object.freeze 會進行淺度當機。考慮下面的遊戲對象,developer 屬性在其中存儲了一個對象,而不是一個字元串。
即使我們當機遊戲對象,我們也可以更改開發者對象的名稱。
const game = {
name: 'Overwatch',
developer: {
name: 'Blizzard'
}
};
Object.freeze(game);
game.developer.name = 'Activision Blizzard';
console.log(game);
//{
// developer: {name: "Activision Blizzard"},
// name: "Overwatch"
//}
以下是我們如何使用遞歸實作 deepFreeze 函數。首先,我們将所有條目作為 [key, value] 對的數組擷取。
然後我們使用 forEach 數組方法周遊所有這些屬性,并對作為對象的值再次調用 deepFreeze。
最後,我們當機并傳回目前對象。
function deepFreeze(object) {
Object
.entries(object)
.forEach(([name, value]) => {
if (value && typeof value === 'object') {
deepFreeze(value);
}
});
return Object.freeze(object);
}
現在,如果我們嘗試更改内部對象的屬性,則會出現錯誤。
deepFreeze(game);
game.developer.name = 'Activision Blizzard';
//Cannot assign to read only property 'name' of object
将對象轉換為地圖
我們可以使用 Object.entries 和 Map 構造函數将對象轉換為地圖。這是一個例子。
const game = {
name: 'Warcraft',
developer: 'Blizzard'
};
const map = new Map(Object.entries(game));
console.log(map);
//Map(2) {"name" => "Warcraft", "developer" => "Blizzard"}
06、Object.fromEntries
我們執行相反的操作并使用 Object.fromEntries 實用程式将 [key, value] 對數組轉換為對象。
考慮下面的代碼。
const keyValuePairs = [
["name", "Warcraft"],
["developer", "Blizzard"]
];
const game = Object.fromEntries(keyValuePairs);
console.log(game);
//{name: "Warcraft", developer: "Blizzard"}
07、Object.create()
Object.create() 使用另一個對象作為新對象的原型建立一個新對象。
這是一個具有 toString 方法的原型對象。
const gamePrototype = {
toString : function(){
return `${this.name}, developed by ${this.developer}`;
}
};
然後我們使用之前的原型來建立一個引用它的新對象。
const game = Object.create(gamePrototype);
game.name = "Overwatch";
game.developer = "Blizzard";
console.log(game.toString());
//'Overwatch, developed by Blizzard'
08、Object.getPrototypeOf
Object.getPrototypeOf() 傳回指定對象的原型。
Object.getPrototypeOf(game) === gamePrototype;
//true
即使是空的對象字面量也有一個原型,即 Object.prototype。
const obj = {};
Object.getPrototypeOf(obj) === Object.prototype;
//true
09、Object.assign()
Object.assign() 将擁有的屬性從一個或多個源對象複制到目标對象。然後它傳回目标對象。
下面是我們将 gameMethods 對象中的屬性複制到遊戲對象中的示例。
const gameMethods = {
toString : function(){
return `${this.name}, developed by ${this.developer}`;
}
};
const game = {
name: 'Diablo',
developer: 'Blizzard'
};
Object.assign(game, gameMethods);
console.log(game.toString());
//'Diablo, developed by Blizzard'
我們可以避免修改現有的遊戲對象,而是建立一個包含來自現有遊戲和 gameMethods 對象的屬性的新對象。
我們可以通過将它們的屬性複制到一個空對象來做到這一點。
const anotherGame = Object.assign({}, game, gameMethods);
console.log(anotherGame.toString());
//'Diablo, developed by Blizzard'
如您所見,我們能夠使用 Object.assign 和 Object.create 将 toString 方法添加到遊戲對象中。
不同之處在于 Object.assign 将屬性添加到每個新建立的對象中。Object.create 僅向新建立的對象添加對現有原型的引用。
它不會複制所有可重用的屬性。隻有在建構數千個對象時才能注意到這種差異。
Object.assign() 也可用于克隆普通對象。
const game = {
name: 'Starcraft'
};
const anotherGame = Object.assign({}, game);
console.log(anotherGame);
//{name: "Starcraft"}
console.log(game === anotherGame);
//false
10、Object.defineProperty
Object.defineProperty 實用程式修改現有屬性或在對象上定義新屬性。它改變并傳回修改後的對象。
Object.defineProperty 主要用于設定特定的屬性描述符,如可枚舉性或定義隻讀屬性。
考慮以下對象。
const game = {
name: 'Fornite',
developer: 'Epic Games',
toString: function(){
return `${this.name}, developed by ${this.developer}`;
}
};
Object.keys(game);
//["name", "developer", "toString"]
預設情況下,所有新屬性都是可枚舉的。如您所見,調用 Object.key 實用程式時還傳回了 toString 屬性名稱。
如果我們不希望 toString 成為可枚舉屬性,我們可以使用 Object.defineProperty 實用程式将其标記為可枚舉屬性。
Object.defineProperty(game, 'toString', {
enumerable: false
});
console.log(Object.keys(game));
//["name", "developer"]
盡管如此,我們可以根據需要更改 toString 屬性。
game.toString = undefined;
我們通過将 toString 屬性上的可寫描述符設定為 false 來避免這種行為。
Object.defineProperty(game, 'toString', {
enumerable: false,
writable: false
});
game.toString = undefined;
//Cannot assign to read only property 'toString' of object
Object.defineProperty 實用程式可用于添加動态 getter 和 setter。
下面是向遊戲對象添加動态 getter 的示例。僅當使用者有權通路時,getter 才傳回屬性的值,否則會引發錯誤。
const game = {
name: 'Fornite',
developer: 'Epic Games',
};
const hasRight = false;
const propName = "name";
Object.defineProperty(game, propName, {
get : function () {
if(hasRight){
return game[propName];
} else {
throw `${propName} no access`;
}
}
});
console.log(game.name);
//name no access
重點說明
- 我們擁有用于當機和檢測當機對象的實用程式。(Object.freeze / Object.isFrozen)
- 其他實用程式幫助我們在新數組中提取對象的所有屬性,進而使我們能夠通路強大的數組方法。(Object.keys / Object.values / Object.entries)
- 我們可以建立一個繼承自現有原型的新對象,然後使用另一個實用程式函數來檢查給定對象的原型。(Object.create/Object.getPrototypeOf)
- 使用 Object.entries 和 Object.fromEntries 助手将對象轉換為 [key, value] 對數組,然後再轉換回對象變得簡單。這使得在地圖和對象之間轉換變得容易。
- Object.assign() 幫助我們克隆對象或将多個對象的屬性複制到一個新對象中。
- Object.defineProperty 實用程式修改現有屬性或定義新屬性。它主要用于更改屬性描述符。
總結
以上這些内容就是 JavaScript 中處理對象的一些最重要的實用函數。如果您覺得它對您有所幫助,請記得給我點贊,同時,也請您分享給您身邊做開發的朋友。
學習更多技能
請點選下方公衆号