亚洲日本永久一区二区_国产精品k频道网址导航_首页aⅴ色老汉中文字幕_免费深夜全片观看_9久久9毛片又大又硬又粗_国产精品成亚洲电影_日韩不用播放器的av_欧美特色特黄视频

JavaScript數(shù)據(jù)結(jié)構(gòu)之Object

JavaScript數(shù)據(jù)結(jié)構(gòu)之Object

Object 是 ECMAScript 中最常用的數(shù)據(jù)類型之一,很適合存儲(chǔ)和在應(yīng)用程序之間交互數(shù)據(jù)。Object 定義一組屬性的無序集合,可以將其想象成一張散列表,其中的內(nèi)容就是一組名/值對(duì),值可以是數(shù)據(jù)或者函數(shù)。 而數(shù)組是一個(gè)有序集合,為了保證元素排列有序,相比 Object 來說會(huì)占用更多的內(nèi)存空間

本文將介紹 Object 使用中將用得到的方法。

1. Object.defineProperty

在了解 JavaScript 對(duì)象之前先來了解一下 Object 中的 defineProperty方法是什么。當(dāng)一個(gè)對(duì)象在初始處理過程中由引擎創(chuàng)建時(shí),JavaScript 將基本屬性賦予新創(chuàng)建的對(duì)象,以處理來自外部的請(qǐng)求,例如訪問或刪除屬性。

可以修改或設(shè)置的屬性如下:

  • value : 屬性的值
  • enumerable :如果為 true,則該屬性可通過 for-in 循環(huán)或 Object.keys() 進(jìn)行搜索,默認(rèn)為 false
  • writable :如果為 false,則無法修改該屬性,它在嚴(yán)格模式下引發(fā)錯(cuò)誤,默認(rèn)為 false
  • 可配置 : 如果為 false,則這會(huì)使對(duì)象的屬性不可枚舉、不可寫、不可刪除和不可配置,默認(rèn)為false
  • get : 當(dāng)嘗試訪問該屬性時(shí)提前調(diào)用的函數(shù),默認(rèn)為 undefined
  • set : 當(dāng)嘗試為屬性設(shè)置某個(gè)值時(shí)提前調(diào)用的函數(shù),默認(rèn)為 undefined

下面來看一些簡(jiǎn)單的代碼:

可枚舉

const obj = {};
Object.defineProperty(obj, "a", {
    value: 100,
    enumerable: false,
});
for (const key in obj) {
    console.log(key);
}
// 未定義
Object.keys(obj);
// []

可寫

const obj = {};
Object.defineProperty(obj, "a", {
    value: 100,
    writable: false,
});
obj.a = 200;
obj.a === 100; // 真的
(() => {
    "use strict";
    obj.a = 100;
    // 嚴(yán)格模式下的類型錯(cuò)誤
})();

可配置

const obj = {};
Object.defineProperty(obj, "a", {
    value: 100,
    configurable: false,
});
// 1. non-enumerable
for (const key in obj) {
    console.dir(key);
}
// undefined
Object.keys(obj);
// [
// 2. non-writable
(() => {
    "use strict";
    obj.a = 200;
    // TypeError in the strict mode
})();
// 3. non-deletable
delete obj.a;
obj.a === 100; // true

但是,當(dāng) writableenumerable 為 true 時(shí),將忽略 configure:false

2. Object.freeze()

Object.freeze() 方法可以防止對(duì)象中的數(shù)據(jù)被修改,即凍結(jié)一個(gè)對(duì)象,這樣不能向這個(gè)對(duì)象 添加、更新或刪除屬性。

語(yǔ)法

Object.freeze(obj)
  • obj:要被凍結(jié)的對(duì)象。

返回值

返回被凍結(jié)的對(duì)象。

實(shí)例

const author = {
    name: "Quintion",
    city: "Shenzhen",
    age: 18,
    validation: true,
};

Object.freeze(author);

author.name = "QuintionTang";
author.province = "Guangdong";
delete author.age;
console.log(author); // { name: 'Quintion', city: 'Shenzhen', age: 18, validation: true }

如上面的代碼,更新屬性name、新增屬性province、刪除屬性age,最終對(duì)象都沒有任何改變。

3. Object.seal()

Object.seal()方法有點(diǎn)類似于 Object.freeze() 。阻止向?qū)ο筇砑有碌膶傩院蛣h除屬性,但允許更改和更新現(xiàn)有屬性。

語(yǔ)法

Object.seal(obj)
  • obj:將要被密封的對(duì)象。

返回值

返回被密封的對(duì)象。

實(shí)例

const author = {
    name: "Quintion",
    city: "Shenzhen",
    age: 18,
    validation: true,
};

Object.seal(author);

author.name = "QuintionTang";
author.province = "Guangdong";
delete author.age;
console.log(author); // { name: 'QuintionTang', city: 'Shenzhen', age: 18, validation: true }

從上面代碼可以看到,新增屬性和刪除屬性都無效,只有更新屬性name生效了。

Object.Seal() 和 Object.freeze()

談到 Object.sealObject.freeze 就不得不談到數(shù)據(jù)的可變性,數(shù)據(jù)不變性在編程語(yǔ)言中一直非常重要,在 JavaScript 中也是如此。Object.freezeObject.seal 方法可以部分保證數(shù)據(jù)的不變性。

上面已經(jīng)介紹了這兩個(gè)方法的使用,這里就從代碼的結(jié)果來對(duì)比一下其區(qū)別。來看下面的 Object.seal 例子:

Object.seal 的解析

const obj = { author: "DevPoint" };
console.log(Object.getOwnPropertyDescriptors(obj));
/*
{
    author: {
      value: 'DevPoint',
      writable: true,
      enumerable: true,
      configurable: true
    }
}
*/
Object.seal(obj);
console.log(Object.getOwnPropertyDescriptors(obj));
/*
{
    author: {
      value: 'DevPoint',
      writable: true,
      enumerable: true,
      configurable: false
    }
}
*/
obj.author = "天行無忌";
console.log(obj.author); // 天行無忌
delete obj.author;
console.log(obj.author); // 天行無忌
obj.city = "Shenzhen";
console.log(obj.city); // undefined

上面代碼定義了一個(gè)對(duì)象 obj 有一個(gè)屬性 author ,其中的值為 DevPoint,初始的描述屬性如下:

{
    author: {
      value: 'DevPoint',
      writable: true,
      enumerable: true,
      configurable: true
    }
}

然后用 Object.seal 密封了對(duì)象,再次查看哪些描述符發(fā)生了變化,哪些沒有,從結(jié)果看只有可配置的更改為 false

{
    author: {
      value: 'DevPoint',
      writable: true,
      enumerable: true,
      configurable: false
    }
}
obj.author = "天行無忌";

盡管 Object.seal 后的可配置現(xiàn)在為 false,但還是通過代碼改變其屬性值為 天行無忌 ,正如之前所解釋的,將可配置設(shè)置為 false 會(huì)使屬性不可寫,但是如果 writable 明確為 true ,則它不起作用。當(dāng)創(chuàng)建一個(gè)對(duì)象并設(shè)置一個(gè)新屬性時(shí),它默認(rèn)為 writable:true

delete obj.author;

Object.seal 會(huì)使每個(gè)屬性都不可配置,從而防止被刪除。從上面的代碼看,對(duì)對(duì)象執(zhí)行 Object.seal 后,delete obj.author; 將變得無效。

obj.city = "Shenzhen";

Object.freeze 的解析

同樣先來看一下代碼,如下:

const obj = { author: "DevPoint" };
console.log(Object.getOwnPropertyDescriptors(obj));
/*
{
    author: {
      value: 'DevPoint',
      writable: true,
      enumerable: true,
      configurable: true
    }
}
*/
Object.freeze(obj);
console.log(Object.getOwnPropertyDescriptors(obj));
/*
{
    author: {
      value: 'DevPoint',
      writable: false,
      enumerable: true,
      configurable: false
    }
}
*/
obj.author = "天行無忌";
console.log(obj.author); // DevPoint
delete obj.author;
console.log(obj.author); // DevPoint
obj.city = "Shenzhen";
console.log(obj.city); // undefined

從上面代碼結(jié)果看,與 Object.seal 的區(qū)別在于 writable 在執(zhí)行 Object.freeze 后屬性值也變?yōu)?false 。因此后續(xù)代碼對(duì)其屬性進(jìn)行更新都無效。同樣與 Object.seal 一樣,Object.freeze 也使對(duì)象不可配置,這使得對(duì)象的每個(gè)屬性都不可刪除。

共同點(diǎn)

  1. 執(zhí)行后的對(duì)象變得不可擴(kuò)展,這意味著對(duì)象將無法添加新屬性。
  2. 執(zhí)行后的對(duì)象中的每個(gè)元素都變得不可配置,這意味著無法刪除屬性。
  3. 如果在“使用嚴(yán)格”模式下調(diào)用操作,則兩種方法都可能引發(fā)錯(cuò)誤,例如在嚴(yán)格模式下執(zhí)行 obj.author = "天行無忌" 會(huì)出現(xiàn)錯(cuò)誤。

不同

對(duì)象執(zhí)行 Object.seal 后允許修改屬性,而執(zhí)行 Object.freeze 則不允許。

不足

Object.freezeObject.seal 在“實(shí)用性”方面存在不足,它們都只是對(duì)對(duì)象的第一層有效。

const obj = { author: "DevPoint", detail: { view: 100 } };
console.log(Object.getOwnPropertyDescriptors(obj.detail));
/*
{
  view: { value: 100, writable: true, enumerable: true, configurable: true }
}
*/
Object.seal(obj);
console.log(Object.getOwnPropertyDescriptors(obj.detail));
/*
{
  view: { value: 100, writable: true, enumerable: true, configurable: true }
}
*/

obj.detail.view = 500;
console.log(obj.detail.view); // 500
delete obj.detail.view;
console.log(obj.detail); // {}
obj.detail.hits = 666;
console.log(obj.detail.hits); // 666

Object.freeze(obj);
console.log(Object.getOwnPropertyDescriptors(obj.detail));
/*
{
  view: { value: 100, writable: true, enumerable: true, configurable: true }
}
*/

如果希望避免對(duì)更深層次的對(duì)象屬性有效,需要像深拷貝一樣,需要寫一些代碼來實(shí)現(xiàn)(deepFreeze):

const obj = { author: "DevPoint", detail: { view: 100 } };
console.log(Object.getOwnPropertyDescriptors(obj.detail));
/*
{
  view: { value: 100, writable: true, enumerable: true, configurable: true }
}
*/
const deepFreeze = (object) => {
    const propNames = Object.getOwnPropertyNames(object);

    for (const name of propNames) {
        const value = object[name];
        if (value && typeof value === "object") {
            deepFreeze(value);
        }
    }
    return Object.freeze(object);
};
const freezeObj = deepFreeze(obj);
console.log(Object.getOwnPropertyDescriptors(freezeObj.detail));
/*
{
  view: { value: 100, writable: false, enumerable: true, configurable: false }
}
*/

obj.detail.view = 500;
console.log(obj.detail.view); // 100
delete obj.detail.view;
console.log(obj.detail); // {view:100}
obj.detail.hits = 666;
console.log(obj.detail.hits); // undefined

如果希望對(duì)嵌套對(duì)象實(shí)現(xiàn) Object.seal 效果,同樣需要編寫代碼來實(shí)現(xiàn)(deepSeal):

const obj = { author: "DevPoint", detail: { view: 100 } };
console.log(Object.getOwnPropertyDescriptors(obj.detail));
/*
{
  view: { value: 100, writable: true, enumerable: true, configurable: true }
}
*/
const deepSeal = (object) => {
    const propNames = Object.getOwnPropertyNames(object);

    for (const name of propNames) {
        const value = object[name];
        if (value && typeof value === "object") {
            deepSeal(value);
        }
    }
    return Object.seal(object);
};
const freezeObj = deepSeal(obj);
console.log(Object.getOwnPropertyDescriptors(freezeObj.detail));
/*
{
  view: { value: 100, writable: true, enumerable: true, configurable: false }
}
*/

obj.detail.view = 500;
console.log(obj.detail.view); // 500
delete obj.detail.view;
console.log(obj.detail); // {view:500}
obj.detail.hits = 666;
console.log(obj.detail.hits); // undefined

4. Object.keys()

Object.keys() 方法會(huì)返回一個(gè)數(shù)組,該數(shù)組包含參數(shù)對(duì)象的所有鍵的名稱,數(shù)組中屬性名的排列順序和正常循環(huán)遍歷該對(duì)象時(shí)返回的順序一致 。

語(yǔ)法

Object.keys(obj)
  • obj:要返回其枚舉自身屬性的對(duì)象。

返回值

一個(gè)表示給定對(duì)象的所有可枚舉屬性的字符串?dāng)?shù)組。

實(shí)例

看看下面的代碼:

const author = {
    name: "Quintion",
    city: "Shenzhen",
    age: 18,
    validation: true,
};

console.log(Object.keys(author)); // [ 'name', 'city', 'age', 'validation' ]

可以看到上面的代碼中打印的結(jié)果是一個(gè)包含鍵作為輸出的數(shù)組。輸出的結(jié)果可以使用數(shù)組的方法進(jìn)行處理或者迭代。

console.log(Object.keys(author).length); // 4

5. Object.values()

Object.values()Object.keys() 類似,不過Object.values() 是獲取對(duì)象內(nèi)素有屬性的值,返回值組成的數(shù)組。

語(yǔ)法

Object.values(obj)
  • obj:被返回可枚舉屬性值的對(duì)象。

返回值

一個(gè)包含對(duì)象自身的所有可枚舉屬性值的數(shù)組。

實(shí)例

const author = {
    name: "Quintion",
    city: "Shenzhen",
    age: 18,
    validation: true,
};

console.log(Object.values(author)); // [ 'Quintion', 'Shenzhen', 18, true ]

6. Object.create()

Object.create() 基于現(xiàn)有對(duì)象的原型__proto__創(chuàng)建一個(gè)新對(duì)象,先來看下面代碼:

語(yǔ)法

Object.create(proto,[propertiesObject])
  • proto:新創(chuàng)建對(duì)象的原型對(duì)象。
  • propertiesObject:可選,需要傳入一個(gè)對(duì)象,該對(duì)象的屬性類型參照Object.defineProperties()的第二個(gè)參數(shù)。如果該參數(shù)被指定且不為 undefined,該傳入對(duì)象的自有可枚舉屬性(即其自身定義的屬性,而不是其原型鏈上的枚舉屬性)將為新創(chuàng)建的對(duì)象添加指定的屬性值和對(duì)應(yīng)的屬性描述符。

返回值

一個(gè)新對(duì)象,帶著指定的原型對(duì)象和屬性。

實(shí)例

const author = {
    firstName: "Quintion",
    lastName: "Tang",
    fullName() {
        return `${this.firstName} ${this.lastName}`;
    },
};

const newAuthor = Object.create(author);
console.log(newAuthor); // {}
newAuthor.firstName = "Ronb";
newAuthor.lastName = "Joy";
console.log(newAuthor.fullName()); // Ronb Joy

在上面的代碼中,使用object. create()創(chuàng)建一個(gè)具有author對(duì)象原型的新對(duì)象newAuthor。這樣在新對(duì)象newAuthor中可以像改變author對(duì)象所擁有的屬性值一樣改變相應(yīng)的屬性值,這個(gè)看起來是不有點(diǎn)像繼承,沒錯(cuò), 使用 Object.create 可以實(shí)現(xiàn)類式繼承。

7. Object.entries()

Object.entries() 允許獲取對(duì)象的鍵和值,返回一個(gè)多維數(shù)組,其中每一維包含每個(gè)鍵和值,如[鍵 , 值]

語(yǔ)法

Object.entries(obj)
  • obj:可以返回其可枚舉屬性的鍵值對(duì)的對(duì)象。

返回值

給定對(duì)象自身可枚舉屬性的鍵值對(duì)數(shù)組。

實(shí)例

const author = {
    firstName: "Quintion",
    lastName: "Tang",
    fullName() {
        return `${this.firstName} ${this.lastName}`;
    },
};

console.log(Object.entries(author));

輸出的結(jié)果如下:

[
  [ 'firstName', 'Quintion' ],
  [ 'lastName', 'Tang' ],
  [ 'fullName', [Function: fullName] ]
]

8. Object.assign()

Object.assign() 方法用于將所有可枚舉屬性的值從一個(gè)或多個(gè)源對(duì)象復(fù)制到目標(biāo)對(duì)象。它將返回目標(biāo)對(duì)象。

語(yǔ)法

Object.assign(target, ...sources)
  • 參數(shù):
    • target:目標(biāo)對(duì)象。
    • sources:源對(duì)象。
  • 返回值:目標(biāo)對(duì)象。
  • 描述:
    如果目標(biāo)對(duì)象中的屬性具有相同的鍵,則屬性將被源中的屬性覆蓋。后來的源的屬性將類似地覆蓋早先的屬性。

注意

Object.assign方法只會(huì)拷貝源對(duì)象自身的并且可枚舉的屬性到目標(biāo)對(duì)象。

拷貝過程中將調(diào)用源對(duì)象的 getter 方法,并在 target 對(duì)象上使用setter 方法實(shí)現(xiàn)目標(biāo)對(duì)象的拷貝。因此,它分配屬性,而不僅僅是復(fù)制或定義新的屬性。

如果合并源包含getter,這可能使其不適合將新屬性合并到原型中。

  • String類型和 Symbol 類型的屬性都會(huì)被拷貝。

  • 在出現(xiàn)錯(cuò)誤的情況下,例如,如果屬性不可寫,會(huì)引發(fā)TypeError,如果在引發(fā)錯(cuò)誤之前添加了任何屬性,則可以更改target對(duì)象。

  • Object.assign會(huì)跳過那些值為 null 或 undefined 的源對(duì)象。

實(shí)例

  • 復(fù)制一個(gè)對(duì)象
const obj = {name:"devpoint"};
const copy = Object.assign({}, obj);
console.log(copy); //{name:"devpoint"}
  • 深度拷貝問題: 針對(duì)深拷貝,需要使用其他方法,Object.assign拷貝的是屬性值。假如源對(duì)象的屬性值是一個(gè)指向?qū)ο蟮囊茫仓豢截惸莻€(gè)引用值。
function test() {
    let obj1 = { name: "devpoint1", address: { city: "Shenzhen1" } };
    let obj2 = Object.assign({}, obj1);
    console.log(JSON.stringify(obj2)); // {"name":"devpoint1","address":{"city":"Shenzhen1"}}

    obj1.name = "devpoint2";
    console.log(JSON.stringify(obj1)); // {"name":"devpoint2","address":{"city":"Shenzhen1"}}
    console.log(JSON.stringify(obj2)); // {"name":"devpoint1","address":{"city":"Shenzhen1"}}

    obj2.name = "devpoint3";
    console.log(JSON.stringify(obj1)); // {"name":"devpoint2","address":{"city":"Shenzhen1"}}
    console.log(JSON.stringify(obj2)); // {"name":"devpoint3","address":{"city":"Shenzhen1"}}

    obj2.address.city = "Shenzhen3";
    console.log(JSON.stringify(obj1)); // {"name":"devpoint2","address":{"city":"Shenzhen3"}}
    console.log(JSON.stringify(obj2)); // {"name":"devpoint3","address":{"city":"Shenzhen3"}}

    // Deep Clone
    obj1 = { name: "devpoint1", address: { city: "Shenzhen1" } };
    let obj3 = JSON.parse(JSON.stringify(obj1));
    obj1.name = "devpoint4";
    obj1.address.city = "Shenzhen4";
    console.log(JSON.stringify(obj3)); // {"name":"devpoint1","address":{"city":"Shenzhen1"}}
}
test();
  • 忽略 null 和 undefined:JavaScript 的 Object.assign() 方法在復(fù)制對(duì)象時(shí)會(huì)忽略 nullundefined。請(qǐng)看下面列出的代碼:
const obj1 = {
    title: "devpoint",
};

const obj2 = Object.assign({}, obj1, null, undefined, { city: "Shenzhen" });
console.log(obj2); // { title: 'devpoint', city: 'Shenzhen' }

總結(jié)

本文對(duì)對(duì)象常見的方法做了簡(jiǎn)單的介紹,并提供了相應(yīng)的示例代碼,在實(shí)際編碼處理對(duì)象的過程中,使用上面的方法可以讓代碼變得更加優(yōu)雅。當(dāng)只需要簡(jiǎn)單的結(jié)構(gòu)來存儲(chǔ)數(shù)據(jù)并且知道所有鍵都是字符串或整數(shù)(或符號(hào))時(shí),對(duì)象是很好的選擇。