En detaljert sammenligning av JavaScripts Object.assign og spredningsoperatoren for objektmanipulering, inkludert ytelsesbenchmarks og praktiske brukseksempler.
JavaScript Object.assign vs Spread: Ytelsessammenligning og Bruksområder
JavaScript tilbyr flere måter å manipulere objekter på. To vanlige metoder er Object.assign()
og spredningsoperatoren (...
). Begge lar deg kopiere egenskaper fra ett eller flere kildeobjekter til et målobjekt. De er imidlertid forskjellige i syntaks, ytelse og underliggende mekanismer. Denne artikkelen gir en omfattende sammenligning for å hjelpe deg med å velge riktig verktøy for ditt spesifikke bruksområde.
Forstå Object.assign()
Object.assign()
er en metode som kopierer alle oppregnelige egne egenskaper fra ett eller flere kildeobjekter til et målobjekt. Den endrer målobjektet direkte og returnerer det. Den grunnleggende syntaksen er:
Object.assign(target, ...sources)
target
: Målobjektet som egenskaper skal kopieres til. Dette objektet vil bli endret.sources
: Ett eller flere kildeobjekter som egenskaper skal kopieres fra.
Eksempel:
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
const returnedTarget = Object.assign(target, source);
console.log(target); // Output: { a: 1, b: 4, c: 5 }
console.log(returnedTarget === target); // Output: true
I dette eksemplet kopieres egenskapene til source
til target
. Merk at b
-egenskapen overskrives, og returnedTarget
er det samme objektet som target
.
Forstå spredningsoperatoren
Spredningsoperatoren (...
) lar deg utvide en iterable (som en array eller et objekt) til individuelle elementer. Når den brukes med objekter, oppretter den en overfladisk kopi av objektets egenskaper til et nytt objekt. Syntaksen er enkel:
const newObject = { ...sourceObject };
Eksempel:
const source = { a: 1, b: 2 };
const newObject = { ...source };
console.log(newObject); // Output: { a: 1, b: 2 }
console.log(newObject === source); // Output: false
Her inneholder newObject
en kopi av egenskapene til source
. Viktig er at newObject
er et *nytt* objekt, forskjellig fra source
.
Viktige forskjeller
Mens både Object.assign()
og spredningsoperatoren oppnår lignende resultater (kopiering av objektegenskaper), har de avgjørende forskjeller:
- Uforanderlighet: Spredningsoperatoren oppretter et nytt objekt, og lar det opprinnelige objektet være uendret (uforanderlig).
Object.assign()
endrer målobjektet direkte (foranderlig). - Håndtering av målobjekt:
Object.assign()
lar deg spesifisere et målobjekt, mens spredningsoperatoren alltid oppretter et nytt. - Egenskapsoppregnelighet: Begge metoder kopierer oppregnelige egenskaper. Ikke-oppregnelige egenskaper kopieres ikke.
- Arvede egenskaper: Ingen av metodene kopierer arvede egenskaper fra prototypekjeden.
- Setters:
Object.assign()
påkaller setters på målobjektet. Spredningsoperatoren gjør ikke det; den tilordner verdier direkte. - Udefinerte eller null-kilder:
Object.assign()
hopper overnull
ogundefined
kildeobjekter. Spredning avnull
ellerundefined
vil kaste en feil.
Ytelsessammenligning
Ytelse er en kritisk vurdering, spesielt når du arbeider med store objekter eller hyppige operasjoner. Mikrobenchmarks viser konsekvent at spredningsoperatoren generelt er raskere ennObject.assign()
. Forskjellen stammer fra deres underliggende implementeringer.
Hvorfor er spredningsoperatoren raskere?
Spredningsoperatoren drar ofte nytte av optimaliserte interne implementeringer i JavaScript-motorer. Den er spesielt designet for objekt- og arrayopprettelse, slik at motorer kan utføre optimaliseringer som ikke er mulig med den mer generelle Object.assign()
. Object.assign()
må håndtere forskjellige tilfeller, inkludert setters og forskjellige egenskapsdeskriptorer, noe som gjør den iboende mer kompleks.
Benchmark-eksempel (illustrativt):
// Forenklet eksempel (faktiske benchmarks krever flere iterasjoner og robust testing)
const object1 = { a: 1, b: 2, c: 3, d: 4, e: 5 };
const object2 = { f: 6, g: 7, h: 8, i: 9, j: 10 };
// Bruke Object.assign()
console.time('Object.assign');
for (let i = 0; i < 1000000; i++) {
Object.assign({}, object1, object2);
}
console.timeEnd('Object.assign');
// Bruke spredningsoperator
console.time('Spread Operator');
for (let i = 0; i < 1000000; i++) {
({...object1, ...object2 });
}
console.timeEnd('Spread Operator');
Merk: Dette er et grunnleggende eksempel for illustrasjonsformål. Virkelige benchmarks bør bruke dedikerte benchmark-biblioteker (som Benchmark.js) for nøyaktige og pålitelige resultater. Størrelsen på ytelsesforskjellen kan variere basert på JavaScript-motoren, objektstørrelsen og de spesifikke operasjonene som utføres.
Bruksområder: Object.assign()
Til tross for ytelsesfordelen med spredningsoperatoren, er Object.assign()
fortsatt verdifull i spesifikke scenarier:
- Endre et eksisterende objekt: Når du trenger å oppdatere et objekt på plass (mutasjon) i stedet for å opprette et nytt. Dette er vanlig når du arbeider med mutable state management-biblioteker, eller når ytelsen er absolutt kritisk, og du har profilert koden din for å bekrefte at det er verdt å unngå en ny objektallokering.
- Slå sammen flere objekter til et enkelt mål:
Object.assign()
kan effektivt slå sammen egenskaper fra flere kildeobjekter til et enkelt mål. - Arbeide med eldre JavaScript-miljøer: Spredningsoperatoren er en ES6-funksjon. Hvis du trenger å støtte eldre nettlesere eller miljøer som ikke støtter ES6, gir
Object.assign()
et kompatibelt alternativ (selv om du kanskje trenger å polyfille det). - Påkalle Setters: Hvis du trenger å utløse setters definert på målobjektet under egenskaps tildeling, er
Object.assign()
det riktige valget.
Eksempel: Oppdatere tilstand på en mutabel måte
let state = { name: 'Alice', age: 30 };
function updateName(newName) {
Object.assign(state, { name: newName }); // Mutates the 'state' object
}
updateName('Bob');
console.log(state); // Output: { name: 'Bob', age: 30 }
Bruksområder: Spredningsoperator
Spredningsoperatoren foretrekkes generelt for sine uforanderlighets- og ytelsesfordeler i de fleste moderne JavaScript-utviklinger:
- Opprette nye objekter med eksisterende egenskaper: Når du vil opprette et nytt objekt med en kopi av egenskaper fra et annet objekt, ofte med noen endringer.
- Funksjonell programmering: Spredningsoperatoren stemmer godt overens med funksjonelle programmeringsprinsipper, som understreker uforanderlighet og unngåelse av bivirkninger.
- React-tilstandsoppdateringer: I React brukes spredningsoperatoren ofte til å opprette nye tilstandsobjekter når komponenttilstanden oppdateres uforanderlig.
- Redux Reducers: Redux-reducers bruker ofte spredningsoperatoren for å returnere nye tilstandsobjekter basert på handlinger.
Eksempel: Oppdatere React-tilstand uforanderlig
import React, { useState } from 'react';
function MyComponent() {
const [state, setState] = useState({ name: 'Charlie', age: 35 });
const updateAge = (newAge) => {
setState({ ...state, age: newAge }); // Creates a new state object
};
return (
<div>
<p>Name: {state.name}</p>
<p>Age: {state.age}</p>
<button onClick={() => updateAge(36)}>Increment Age</button>
</div>
);
}
export default MyComponent;
Overfladisk kopi vs. Dyp kopi
Det er viktig å forstå at både Object.assign()
og spredningsoperatoren utfører en *overfladisk* kopi. Dette betyr at bare egenskaper på toppnivå kopieres. Hvis et objekt inneholder nestede objekter eller arrayer, kopieres bare referansene til disse nestede strukturene, ikke selve de nestede strukturene.
Eksempel på overfladisk kopi:
const original = { a: 1, b: { c: 2 } };
const copy = { ...original };
copy.a = 3; // Modifies 'copy.a', but 'original.a' remains unchanged
copy.b.c = 4; // Modifies 'original.b.c' because 'copy.b' and 'original.b' point to the same object
console.log(original); // Output: { a: 1, b: { c: 4 } }
console.log(copy); // Output: { a: 3, b: { c: 4 } }
For å opprette en *dyp* kopi (der nestede objekter også kopieres), må du bruke teknikker som:
JSON.parse(JSON.stringify(object))
: Dette er en enkel, men potensielt treg metode. Den fungerer ikke med funksjoner, datoer eller sirkulære referanser.- Lodashs
_.cloneDeep()
: En verktøyfunksjon levert av Lodash-biblioteket. - En tilpasset rekursiv funksjon: Mer kompleks, men gir mest kontroll over den dype kopieringsprosessen.
- Strukturert kloning: Bruker
window.structuredClone()
for nettlesere ellerstructuredClone
-pakken for Node.js for å dypt kopiere objekter.
Beste praksis
- Foretrekk spredningsoperatoren for uforanderlighet: I de fleste moderne JavaScript-applikasjoner, foretrekk spredningsoperatoren for å opprette nye objekter uforanderlig, spesielt når du arbeider med tilstandshåndtering eller funksjonell programmering.
- Bruk Object.assign() for å mutere eksisterende objekter: Velg
Object.assign()
når du spesifikt trenger å endre et eksisterende objekt på plass. - Forstå overfladisk vs. dyp kopi: Vær oppmerksom på at begge metodene utfører overfladiske kopier. Bruk passende teknikker for dyp kopiering når det er nødvendig.
- Benchmark når ytelsen er kritisk: Hvis ytelsen er avgjørende, utfør grundige benchmarks for å sammenligne ytelsen til
Object.assign()
og spredningsoperatoren i ditt spesifikke bruksområde. - Vurder kodelesbarhet: Velg metoden som resulterer i den mest lesbare og vedlikeholdbare koden for teamet ditt.
Internasjonale hensyn
Oppførselen til Object.assign()
og spredningsoperatoren er generelt konsistent på tvers av forskjellige JavaScript-miljøer over hele verden. Det er imidlertid verdt å merke seg følgende potensielle hensyn:
- Tegn koding: Forsikre deg om at koden din håndterer tegnkoding riktig, spesielt når du arbeider med strenger som inneholder tegn fra forskjellige språk. Begge metodene kopierer stringegenskaper riktig, men kodingsproblemer kan oppstå når du behandler eller viser disse strengene.
- Dato- og tidsformater: Når du kopierer objekter som inneholder datoer, må du være oppmerksom på tidssoner og datoformater. Hvis du trenger å serialisere eller deserialisere datoer, bruk passende metoder for å sikre konsistens på tvers av forskjellige regioner.
- Nummerformatering: Ulike regioner bruker forskjellige konvensjoner for nummerformatering (f.eks. desimalskilletegn, tusenskilletegn). Vær oppmerksom på disse forskjellene når du kopierer eller manipulerer objekter som inneholder numeriske data som kan vises til brukere i forskjellige lokasjoner.
Konklusjon
Object.assign()
og spredningsoperatoren er verdifulle verktøy for objektmanipulering i JavaScript. Spredningsoperatoren gir generelt bedre ytelse og fremmer uforanderlighet, noe som gjør den til et foretrukket valg i mange moderne JavaScript-applikasjoner. Imidlertid er Object.assign()
fortsatt nyttig for å mutere eksisterende objekter og støtte eldre miljøer. Å forstå forskjellene og bruksområdene deres vil hjelpe deg med å skrive mer effektiv, vedlikeholdbar og robust JavaScript-kode.