Heim >Web-Frontend >js-Tutorial >Ändern Sie die Rest- und Spread-Attribute von JavaScript-Objekten

Ändern Sie die Rest- und Spread-Attribute von JavaScript-Objekten

小云云
小云云Original
2018-02-10 10:11:341885Durchsuche

In ES5 wurde _.extend(target, [sources]) in ES2015 mithilfe von Lodashs Object.assign(target, [sources]) (oder anderen Optionen) eingeführt.

Glücklicherweise bietet die spread-Syntax für Objekte (ECMAScript Phase 3-Empfehlungen) eine kurze und leicht verständliche Syntax für die Manipulation von Objekten.

const cat = {  
    legs: 4,
    sound: 'meow'};const dog = {  
    ...cat,
    sound: 'woof'};

console.log(dog);

Ändern Sie die Rest- und Spread-Attribute von JavaScript-Objekten

Im obigen Beispiel kopiert ...cat das cat-Objekt in ein neues dog-Objekt. .soundDer Wert des Attributs woof wird am Ende platziert.

In diesem Artikel lernen wir die rest- und spread-Syntax von Objekten kennen. Sehen wir uns an, wie das Klonen, Zusammenführen, Umschreiben von Attributen usw. von Objekten implementiert wird.

Im Folgenden finden Sie eine kurze Zusammenfassung der aufzählbaren Eigenschaften und der Unterscheidung zwischen eigenen und geerbten Eigenschaften. Dies sind die notwendigen Grundlagen für das Verständnis der Syntax von Objekten spread und rest.

Aufzählungen und eigene Eigenschaften

In JavaScript ist ein Objekt eine Assoziation zwischen einem Schlüssel (key) und einem Wert (value). Der Typ von

key ist normalerweise string oder symbol. Der Wert kann ein primitiver Typ (string, boolean, number, undefined oder null) oder ein object oder function sein.

Die folgenden Objekte verwenden Objektliterale:

const person = {
    name: 'Dave',
    surname: 'Bowman'}

personDas Objekt beschreibt name und surname einer Person.

Aufgezählte Eigenschaften

Eigenschaften (property) verfügen über mehrere Eigenschaften (attribute) zur Beschreibung von Werten sowie beschreibbaren, aufzählbaren und konfigurierbaren Zuständen. Weitere Einzelheiten hierzu finden Sie unter Objekteigenschaften in JavaScript.

Die aufzählbare Eigenschaft ist ein boolescher Wert, der sich darauf bezieht, ob auf die Eigenschaft im aufgezählten Objekt zugegriffen werden kann.

Mit Object.keys() können Sie Objekteigenschaften aufzählen (für den Zugriff auf eigene und aufzählbare Eigenschaften). Sie können auch die for...in-Anweisung verwenden (um alle aufzählbaren Eigenschaften aufzulisten) usw.

Durch Objektliterale {prop1: 'val1', prop2:'val2'} deklarierte Eigenschaften sind aufzählbar. Schauen wir uns die aufzählbaren Eigenschaften an, die das person-Objekt enthält:

const keys = Object.keys(person);  
console.log(keys);

Ändern Sie die Rest- und Spread-Attribute von JavaScript-Objekten

name und surname sind durch die person-Objekteigenschaft aufzählbar.

Hier kommt der lustige Teil. Objektverteilung wird aus der aufzählbaren Quelleigenschaft geklont:

console.log({ ...person })

Ändern Sie die Rest- und Spread-Attribute von JavaScript-Objekten

Jetzt erstellen wir eine nicht aufzählbare Eigenschaft für das person-Objekt age. Schauen Sie sich dann das Object-Verhalten von spread an:

Object.defineProperty(person, 'age', {  
    enumerable: false, // 属性不可枚举
    value: 25});
console.log(person['age']); // => 25const clone = {  
    ...person
};
console.log(clone);

Ändern Sie die Rest- und Spread-Attribute von JavaScript-Objekten

name und surname Aufzählungseigenschaften werden aus dem Quellobjekt person -Objekt, aber das nicht aufzählbare Attribut clone wird nicht hineinkopiert. age

Eigene Eigenschaften

JavaScript-Prototypen können vererbt werden. Daher können die Objekteigenschaften Ihre eigenen oder geerbten sein.

Die vom Objektliteral explizit deklarierten Eigenschaften sind seine eigenen, aber die Eigenschaften, die das Objekt vom Prototyp erhält, werden geerbt.

Als nächstes erstellen Sie ein

-Objekt und setzen seine Eigenschaften auf personB: Das person

const personB = Object.create(person, {  
    profession: {        value: 'Astronaut',        enumerable: true
    }
});

console.log(personB.hasOwnProperty('profession')); // => true  console.log(personB.hasOwnProperty('name'));       // => false  console.log(personB.hasOwnProperty('surname'));    // => false

-Objekt hat seine eigenen Eigenschaften personB und von professionDas person und name Attribute, die vom Attribut geerbt wurden. surname

Wenn Object Spread von seinen eigenen Quelleigenschaften kopiert, ignoriert es geerbte Eigenschaften. Das

const cloneB = {  
    ...personB
};
console.log(cloneB); // => { profession: 'Astronaut' }

-Objekt kopiert nur seine eigenen Eigenschaften ...personB vom Quellobjekt personB, ignoriert jedoch vererbbare profession- und name-Eigenschaften. surname

Object Spread kann seine eigenen und aufzählbaren Eigenschaften aus dem Quellobjekt kopieren. Dasselbe wie

. Object.keys()

Objekteigenschaften verteilen

Objektverteilung im Objektzeichen kann die eigenen und aufzählbaren Eigenschaften des Quellobjekts kopieren und auf das Zielobjekt kopieren.

const targetObject = {  
    ...sourceObject,
    property: 'Value'};
Übrigens ist die Objektverteilung in vielerlei Hinsicht äquivalent zu

. Der obige Code kann auch wie folgt implementiert werden: Object.assign()

const targetObject = Object.assign(  
    { }, 
    sourceObject,
    { property: 'Value' }
);
Ein Objektliteral kann mehrere Objektverbreitungen haben, und jede Kombination kann mithilfe von Regelattributen deklariert werden:

const targetObject = {  
    ...sourceObject1,
    property1: 'Value 1',
    ...sourceObject2,
    ...sourceObject3,
    property2: 'Value 2'};

Object spread规则:最后属性获胜

当多个对象被传播,有一些属性具有相同的键时,那么是如何计算最终的值呢?规则很简单:后者扩展属性覆盖具有相同键的早期属性

来看几个示例。下面的对象字面符实例化了一只猫:

const cat = {
    sound: 'meow',
    legs: 4}

让我们扮演Frankenstein博士,把这只猫变成一只狗。注意它的sound属性值:

const dog = {  
    ...cat,
    ...{
        sound: &#39;woof&#39; // <----- 覆盖 cat.sound
    }
};console.log(dog);  // => { sound: &#39;woof&#39;, legs: 4 }

后面的属性值woof覆盖了前面的属性值meow(来自cat对象的sound的值)。这符合使用相同的键值时,后一个属性值将覆盖最早的属性值的规则。

同样的规则也适用于对象初始化的规则属性:

const anotherDog = {  
    ...cat,
    sound: &#39;woof&#39; // <---- Overwrites cat.sound};console.log(anotherDog); // => { sound: &#39;woof&#39;, legs: 4 }

sound: 'woof'规则最终获胜,那是因为他在最后。

现在如果你交换传播对象的相对位置,结果是不同的:

const stillCat = {  
    ...{
        sound: &#39;woof&#39; // <---- Is overwritten by cat.sound
    },    ...cat};console.log(stillCat); // => { sound: &#39;meow&#39;, legs: 4 }

猫仍然是猫。尽管第一个源对象提供了sound属性的值为woof,但它还是被后面的cat对象的sound的属性值meow覆盖了。

Object spread的位置和正则性质很重要。这种语法允许实现诸如对象克隆、合并和填充默认值之类的。

下面我们来看看。

对象克隆

使用Object Spread语法可以用一个简短而富有表现力的方式来克隆一个对象。下面的例子克隆了bird对象:

const bird = {  
    type: &#39;pigeon&#39;,
    color: &#39;white&#39;};const birdClone = {  
    ...bird
};

console.log(birdClone); // => { type: &#39;pigeon&#39;, color: &#39;white&#39; }  console.log(bird === birdClone); // => false

.bird在字符符上复制了bird自己和可枚举的属性,并传给了birdClone目标。因此birdClonebird的克隆。

虽然克隆对象技术乍一看似乎很简单,但有一些细节的差异还是需要注意的。

浅拷贝

Object Spread只会做一个对象的浅拷贝。只有对象本身是克隆的,而嵌套的实例不是克隆的。

laptop有一个嵌套的对象screen。如果克隆laptop对象,看看对其嵌套的对象有何影响:

const laptop = {  
    name: &#39;MacBook Pro&#39;,
    screen: {
        size: 17,
        isRetina: true
    }
};const laptopClone = {  
    ...laptop
};

console.log(laptop === laptopClone);               // => false  console.log(laptop.screen === laptopClone.screen); // => true

首先比较laptop === laptopClone,其值是false。主对象被正确克隆。

然而,laptop.screen === laptopClone.screen值是true。这意味着,laptop.screenlaptopClone.screen引用相同的嵌套对象,但没有复制。

其实,你可以在任何级别上做传播。只需稍加努力,就可以克隆嵌套的对象:

const laptopDeepClone = {  
    ...laptop,    screen: {
        ...laptop.screen
    }
};

console.log(laptop === laptopDeepClone);               // => false  console.log(laptop.screen === laptopDeepClone.screen); // => false

一个额外的...laptop.screen就确保了嵌套对象也被克隆了。现在,laptopDeepClone完整的克隆了laptop对象。

Ändern Sie die Rest- und Spread-Attribute von JavaScript-Objekten

原型丢失

下面的代码片段声明了一个Game的类,并用这个类创建了一个例实例doom

class Game {  
    constructor(name) {        this.name = name;
    }

    getMessage() {        return `I like ${this.name}!`;
    }
}const doom = new Game(&#39;Doom&#39;);  
console.log(doom instanceof Game); // => true  console.log(doom.name);            // => "Doom"  console.log(doom.getMessage());    // => "I like Doom!"

现在,让我们来克隆一个调用构造函数创建的doom实例。这可能会给你带来一个惊喜:

const doomClone = {  
...doom
};

console.log(doomClone instanceof Game); // => false  console.log(doomClone.name);            // => "Doom"  console.log(doomClone.getMessage());    // => TypeError: doomClone.getMessage is not a function

...doom只将自己的属性name复制到doomClone而已。

doomClone是一个普通的JavaScript对象,其原型是Object.prototype,而不是Game.prototype,这是可以预期的。Object Spread不保存源对象的原型

因此,调用doomClone.getMessage()会抛出一个TypeError错误,那是因为doomClone不会继承getMessage()方法。

要修复丢失的原型,需要手动使用__proto__

const doomFullClone = {  
    ...doom,
    __proto__: Game.prototype
};

console.log(doomFullClone instanceof Game); // => true  console.log(doomFullClone.name);            // => "Doom"  console.log(doomFullClone.getMessage());    // => "I like Doom!"

对象字面符上的__proto__确保了doomFullCloneGame.prototype原型。

不赞成使用__proto__,这里只是用来做演示。

对象传播滞后于调用构造函数创建的实例,因为它不保存原型。其意图是用来浅拷贝源对象自己和可枚举的属性。因此忽略原型的方法似乎也是合理的。

顺便说一下,使用Object.assign()可以更合理的克隆doom

const doomFullClone = Object.assign(new Game(), doom);

console.log(doomFullClone instanceof Game); // => true  console.log(doomFullClone.name);            // => "Doom"  console.log(doomFullClone.getMessage());    // => "I like Doom!"

我保证,使用这种方法,原型也会克隆过来。

更新不可变对象

当一个对象在应用程序的多个地方共用时,直接修改这个对象可能会带来意想不到的副作用。而且跟踪这些修改也是极为蛋疼的事情。

更好的方法是使用操作不可变。不可变能更好的控制对象的修改,有利于编写纯函数。即使在一些复杂的场景中,也更容易确定对象更新的源和原因,因为数据流到一个单一的方向。

Object Spread方便以不可变的方式来修改对象。所设你有一个对象描述了一本书的版本信息:

const book = {  
    name: &#39;JavaScript: The Definitive Guide&#39;,
    author: &#39;David Flanagan&#39;,
    edition: 5,
    year: 2008};

然后这本书的第六版本出来了。Object Spread让我们可以以不可变的方式对这个场景进行编程:

const newerBook = {  
    ...book,
    edition: 6,  // <----- Overwrites book.edition
    year: 2011   // <----- Overwrites book.year};

console.log(newerBook);

Ändern Sie die Rest- und Spread-Attribute von JavaScript-Objekten

...book复制了book对象的属性。然后手动添加edition:6year:2011来更新属性值。

在最后指定重要的属性值,因为相同的键值,后面的会覆盖前面的。

newBook是一个具有更新属性的新对象。与此同时,原来的book对象仍然完好无损。达到我们的不变性需求。

合并对象

合并对象很简单,因为你可以扩展对象任意数量的属性。

让我们来合并三个对象:

const part1 = {  
    color: &#39;white&#39;};const part2 = {  
    model: &#39;Honda&#39;};const part3 = {  
    year: 2005};const car = {  
    ...part1,
    ...part2,
    ...part3
};
console.log(car); // { color: &#39;white&#39;, model: &#39;Honda&#39;, year: 2005 }

car对象的创建是由part1part2part3三个对象合并而来。

不要忘记,后者会覆盖前者的规则。它给出了合并多个具有相同键对象的理由。

让我们改变一下前面的例子。现在part1part3具有一个新的属性configuration

const part1 = {  
    color: &#39;white&#39;,
    configuration: &#39;sedan&#39;};const part2 = {  
    model: &#39;Honda&#39;};const part3 = {  
    year: 2005,
    configuration: &#39;hatchback&#39;};const car = {  
    ...part1,
    ...part2,
    ...part3 // <--- part3.configuration overwrites part1.configuration};
console.log(car);

Ändern Sie die Rest- und Spread-Attribute von JavaScript-Objekten

首先...part1设置了configuration的值为sedan,但是后面的...part3configuration设置的hatchback覆盖了前面的。

使用默认值填充对象

对象可以在运行时拥有不同的属性集。一些属性可以被设置,另一些可能会丢失。

这种情况可能发生在配置对象的情况下。用户只能指定配置的重要属性,但未能指从默认中提取的属性。

让我们实现一个multiline(str, config)函数,通过给定的宽度,将 str分成多个行。

config对象可能会接受下面几个参数:

  • width:要断开的字符数。默认为10

  • newLine:在行尾添加字符串。默认为\n

  • indent:打算的行。默认值为' '

multiline()函数几个示例:

multiline(&#39;Hello World!&#39;);  
// => &#39;Hello Worl\nd!&#39;multiline(&#39;Hello World!&#39;, { width: 6 });  
// => &#39;Hello \nWorld!&#39;multiline(&#39;Hello World!&#39;, { width: 6, newLine: &#39;*&#39; });  
// => &#39;Hello *World!&#39;multiline(&#39;Hello World!&#39;, { width: 6, newLine: &#39;*&#39;, indent: &#39;_&#39; });  
// => &#39;_Hello *_World!&#39;

config参数接受不同的属性集:你可以表示123个属性,甚至没有属性。

使用Object Spread会非常简单,可以用默认值填充config对象。在对象字面符中首先展开默认对象,然后是config对象:

function multiline(str, config = {}) {  
    const defaultConfig = {
        width: 10,
        newLine: &#39;\n&#39;,
        indent: &#39;&#39;
    };    const safeConfig = {
        ...defaultConfig,
        ...config
    };    let result = &#39;&#39;;    // Implementation of multiline() using    // safeConfig.width, safeConfig.newLine, safeConfig.indent    // ...    return result;
}

让我们管理safeConfig对象字面量。

...defaultConfig从默认值中提取属性,然后...config配置将会覆盖以前的默认值和自定义属性值。

因此,safeConfig具有multiline()函数可以使用的全部属性。无论输入的配置是否会遗漏一些属性,safeConfig都会具备必要的值。

Object Spread能非常直观的使用默认值。

我们需要更进一步

Object Spread非常酷的地方在于可以在嵌套对象上使用。当更新一个大对象时,这是一个很好的优势,具有很好的可读性。但还是推荐使用Object.assign()来替代。

下面的box对象定义了box的标签:

const box = {  
    color: &#39;red&#39;,
    size: {
        width: 200, 
        height: 100 
    },
    items: [&#39;pencil&#39;, &#39;notebook&#39;]
};

box.size描述了box的尺寸,以及box.items中包含了box中可枚举的item

通过增加box.size.height使box变高。只需要在嵌套对象上扩展height属性:

const biggerBox = {  
    ...box,
    size: {
        ...box.size,
        height: 200
    }
};
console.log(biggerBox);

...box可以确保biggerBox接收来自box源的属性。

更新嵌套对象box.sizeheight,只需要额外的一个对象字面量{...box.size, height:200}。这样一来,box.sizeheight属性就得到了一个新值,其值更新为200

我喜欢通过一个语句执行多个更新的可能性。

如何将颜色改为黑色,将宽度增加到400,并添加一个新的项目ruleritems中(使用扩展数组)?这很简单:

const blackBox = {  
    ...box,
    color: &#39;black&#39;,
    size: {
        ...box.size,
        width: 400
    },
    items: [
        ...box.items,        &#39;ruler&#39;
    ]
};
console.log(blackBox);

Ändern Sie die Rest- und Spread-Attribute von JavaScript-Objekten

传播undefinednull和原始值

当扩展undefinednull或原始值时,不会提取任何属性,也不会抛出任何错误。中会返回一个空的对象:

const nothing = undefined;  
const missingObject = null;  
const two = 2;

console.log({ ...nothing });       // => { }  console.log({ ...missingObject }); // => { }  console.log({ ...two });           // => { }

nothingmissingObjecttwo中,Object Spread没有扩展任何属性。当然,没有理由在原始值上使用Object Spread。

Object rest属性

使用结构赋值将对象的属性提取到变量之后,剩余的属性可以被收集到rest对象中。

这就是对象rest属性的好处:

const style = {  
    width: 300,
    marginLeft: 10,
    marginRight: 30};const { width, ...margin } = style;

console.log(width);  // => 300  console.log(margin); // => { marginLeft: 10, marginRight: 30 }

使用结构性赋值定义了一个新的变量width,并将其值设置为style.width...margin只会收集marginLeftmarginRight属性。

Object rest只收集自己的和可枚举的属性。

注意,Object rest必须是结构性赋值中的最后一个元素。因此const { ...margin , width } = style将会报错:SyntaxError: Rest element must be last element

总结

Object spread有一些规则要记住:

  • 它从源对象中提取自己的和可枚举的属性

  • 扩展的属性具有相同键的,后者会覆盖前者

与此同时,Object spread是简短而且富有表现力的,同时在嵌套对象上也能很好的工作,同时也保持更新的不变性。它可以轻松的实现对象克隆、合并和填充默认属性。

在结构性赋值中使用Object rest语法,可以收集剩余的属性。

实际上,Object rest和Object spread是JavaScript的重要补充。

相关推荐:

了解JavaScript,函数中的 Rest 参数

Das obige ist der detaillierte Inhalt vonÄndern Sie die Rest- und Spread-Attribute von JavaScript-Objekten. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn