天天看點

10 個在 JavaScript 中處理對象的實用函數

10 個在 JavaScript 中處理對象的實用函數

英文 | 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 中處理對象的一些最重要的實用函數。如果您覺得它對您有所幫助,請記得給我點贊,同時,也請您分享給您身邊做開發的朋友。

學習更多技能

請點選下方公衆号