Object spread vs. Object.assign
For reference object rest/spread is finalised in ECMAScript 2018 as a stage 4. The proposal can be found here.
For the most part object assign and spread work the same way, the key difference is that spread defines properties, whilst Object.assign() sets them. This means Object.assign() triggers setters.
It's worth remembering that other than this, object rest/spread 1:1 maps to Object.assign() and acts differently to array (iterable) spread. For example, when spreading an array null values are spread. However using object spread null values are silently spread to nothing.
Array (Iterable) Spread Example
const x = [1, 2, null , 3];
const y = [...x, 4, 5];
const z = null;
console.log(y); // [1, 2, null, 3, 4, 5];
console.log([...z]); // TypeError
Object Spread Example
const x = null;
const y = {a: 1, b: 2};
const z = {...x, ...y};
console.log(z); //{a: 1, b: 2}
This is consistent with how Object.assign() would work, both silently exclude the null value with no error.
const x = null;
const y = {a: 1, b: 2};
const z = Object.assign({}, x, y);
console.log(z); //{a: 1, b: 2}
Object.assign vs object spread operator
TLDR: for small objects, i think they perform similarly
I did some small test using jest.
these all my codes
example are from JSON Data set example
// example 4
const optionsA = {
"id": "0001",
"type": "donut",
"name": "Cake",
"ppu": 0.55,
"batters":
{
"batter":
[
{ "id": "1001", "type": "Regular" },
{ "id": "1002", "type": "Chocolate" },
{ "id": "1003", "type": "Blueberry" },
{ "id": "1004", "type": "Devil's Food" }
]
},
"topping":
[
{ "id": "5001", "type": "None" },
{ "id": "5002", "type": "Glazed" },
{ "id": "5005", "type": "Sugar" },
{ "id": "5007", "type": "Powdered Sugar" },
{ "id": "5006", "type": "Chocolate with Sprinkles" },
{ "id": "5003", "type": "Chocolate" },
{ "id": "5004", "type": "Maple" }
]
}
// example 8
const optionsB = {
"items":
{
"item":
[
{
"id": "0001",
"type": "donut",
"name": "Cake",
"ppu": 0.55,
"batters":
{
"batter":
[
{ "id": "1001", "type": "Regular" },
{ "id": "1002", "type": "Chocolate" },
{ "id": "1003", "type": "Blueberry" },
{ "id": "1004", "type": "Devil's Food" }
]
},
"topping":
[
{ "id": "5001", "type": "None" },
{ "id": "5002", "type": "Glazed" },
{ "id": "5005", "type": "Sugar" },
{ "id": "5007", "type": "Powdered Sugar" },
{ "id": "5006", "type": "Chocolate with Sprinkles" },
{ "id": "5003", "type": "Chocolate" },
{ "id": "5004", "type": "Maple" }
]
}
]
}
}
module.exports = {optionsA, optionsB}
this is Assign.test.js
const { optionsA, optionsB } = require("./Options");
test('jest assign test', () => {
let options = Object.assign({}, optionsA,optionsB);
expect(options).toEqual({
"id": "0001",
"type": "donut",
"name": "Cake",
"ppu": 0.55,
"batters":
{
"batter":
[
{ "id": "1001", "type": "Regular" },
{ "id": "1002", "type": "Chocolate" },
{ "id": "1003", "type": "Blueberry" },
{ "id": "1004", "type": "Devil's Food" }
]
},
"topping":
[
{ "id": "5001", "type": "None" },
{ "id": "5002", "type": "Glazed" },
{ "id": "5005", "type": "Sugar" },
{ "id": "5007", "type": "Powdered Sugar" },
{ "id": "5006", "type": "Chocolate with Sprinkles" },
{ "id": "5003", "type": "Chocolate" },
{ "id": "5004", "type": "Maple" }
],
"items":
{
"item":
[
{
"id": "0001",
"type": "donut",
"name": "Cake",
"ppu": 0.55,
"batters":
{
"batter":
[
{ "id": "1001", "type": "Regular" },
{ "id": "1002", "type": "Chocolate" },
{ "id": "1003", "type": "Blueberry" },
{ "id": "1004", "type": "Devil's Food" }
]
},
"topping":
[
{ "id": "5001", "type": "None" },
{ "id": "5002", "type": "Glazed" },
{ "id": "5005", "type": "Sugar" },
{ "id": "5007", "type": "Powdered Sugar" },
{ "id": "5006", "type": "Chocolate with Sprinkles" },
{ "id": "5003", "type": "Chocolate" },
{ "id": "5004", "type": "Maple" }
]
}
]
}
})
})
this is Spread.test.js
const { optionsA, optionsB } = require("./Options");
test('jest spread test', () => {
let options = {...optionsA,...optionsB};
expect(options).toEqual({
"id": "0001",
"type": "donut",
"name": "Cake",
"ppu": 0.55,
"batters":
{
"batter":
[
{ "id": "1001", "type": "Regular" },
{ "id": "1002", "type": "Chocolate" },
{ "id": "1003", "type": "Blueberry" },
{ "id": "1004", "type": "Devil's Food" }
]
},
"topping":
[
{ "id": "5001", "type": "None" },
{ "id": "5002", "type": "Glazed" },
{ "id": "5005", "type": "Sugar" },
{ "id": "5007", "type": "Powdered Sugar" },
{ "id": "5006", "type": "Chocolate with Sprinkles" },
{ "id": "5003", "type": "Chocolate" },
{ "id": "5004", "type": "Maple" }
],
"items":
{
"item":
[
{
"id": "0001",
"type": "donut",
"name": "Cake",
"ppu": 0.55,
"batters":
{
"batter":
[
{ "id": "1001", "type": "Regular" },
{ "id": "1002", "type": "Chocolate" },
{ "id": "1003", "type": "Blueberry" },
{ "id": "1004", "type": "Devil's Food" }
]
},
"topping":
[
{ "id": "5001", "type": "None" },
{ "id": "5002", "type": "Glazed" },
{ "id": "5005", "type": "Sugar" },
{ "id": "5007", "type": "Powdered Sugar" },
{ "id": "5006", "type": "Chocolate with Sprinkles" },
{ "id": "5003", "type": "Chocolate" },
{ "id": "5004", "type": "Maple" }
]
}
]
}
})
})
And when i do these test, they have similar time doing the work:
Difference between Object.assign and object spread
The difference is that when using a spread you are always creating a new object:
const a = { name: 'Joe Bloggs' }const b = { ...a, age: 27 };
console.log(a === b) //=> false
Difference between Object.assign and object spread (using [...] syntax)?
In your particular case they are not the same.
The reason is that you have an array, not an object.
Doing ...
on an array will spread out all the elements in the array (but not the properties)
Doing Object.assign
expects an object so it will treat an array as an object and copy all enumerable own properties into it, not just the elements:
const a = [1, 2, 3];a.test = 'example';
const one = [...a] // [1, 2, 3];const two = Object.assign([], a); // { '0': 1, '1': 2, '2': 3, 'test': 'example' }
console.log('\none');for (let prop in one) { console.log(prop);}
console.log('\ntwo');for (let prop in two) { console.log(prop);}
Why does object spread fail but Object.assign succeeds when updating a DOM element's style attribute?
Why does this happen?
style
is a read-only property, and cannot be assigned to a new value.
element.style = { ...element.style, backgroundColor: 'green' };
Creates a shallow copy of element.style
, adds/updates the property backgroundColor
and assigns the copy back to element.style
. For this reason it fails, because you cannot assign element.style
a new value.
Object.assign(element.style, { backgroundColor: 'green' });
Assigns each property/value pair in the second argument to element.style
. It does not create a copy of element.style
, but mutates the element.style
object.
Is there a way to replicate
Object.assign
's desired behaviour with object spread?
No, object spread is used only in object literals, which will always result in a new object being created. You cannot update an existing object using object spread.
Object.assign vs assignment (=)
Assignment only creates another reference to the exact same object in memory. If you assign, then change by referencing one of the variable names, the other one will have changed too, since they're the same thing.
Object.assign
will assign all enumerable own properties of the second (and further) parameters to the first parameter, and will return the first parameter. So
const obj3 = Object.assign(obj2, obj1);
is a bit like
for (const prop in obj1) {
obj2[prop] = obj1[prop]
}
obj3 = obj2;
(with plain objects - skipping the own aspect)
They're quite different.
What purpose does spread syntax inside an object literal ({...object}) serve?
It's not the same object. It makes a shallow copy of the object's own, enumerable properties (like Object.assign({}, object)
(MDN). You use it when you want...a copy, with the object's own, enumerable properties. :-D
For example, with any of several MVC or similar libraries, you might use it when updating state, since state shouldn't be modified directly:
this.setState(oldState => ({...oldState, prop: "new value"}));
What is the time complexity of object spread operator in Javascript?
It's O(n)
. Object spread iterates through all enumerable own properties and assigns them to a new object, and property assignment is an O(1)
process. If there are N keys to iterate through, there are around N such operations to perform.
That said, this here will not be a bottleneck in 99.9% of actual code, so it's not worth worrying about.
Use Object.assign or Spread Operator in React/Redux? Which is a better practise
Redux docs recommends you to use the spread operator approach instead of the Object.assign
As per the docs:
An alternative approach is to use the object spread syntax proposed
for the next versions of JavaScript which lets you use the spread
(...) operator to copy enumerable properties from one object to
another in a more succinct way. The object spread operator is
conceptually similar to the ES6 array spread operator
The advantage of using the object spread syntax becomes more apparent when you're composing complex objects
Using the Spread operator syntax
export const selectDiameter = (scaleData,size) => {
return {
type: SELECT_DIAMETER,
payload: {...scaleData,
diameter: {
...scaleData.diameter,
selectedTube: size,
isClicked: true,
audio: {
...scaleData.diameter.audio,
isPlayed: true
}
}
}
}
}
It still uses ES6. See the Redux docs for more info on configuring your code for the same
However when you are dealing with the nested data. I prefer to use immutability-helpers
For your code it will be like
import update from 'immutability-helpers';
export const selectDiameter = (scaleData,size) => {
return {
type: SELECT_DIAMETER,
payload: update(scaleData, {
diameter: {
selectedTube: { $set: size},
isClicked: { $set: true},
audio: {
isPlayed: {$set: true}
}
}
})
}
}
add new elements to object just using spread
Try this
const stateObject = {
missouri: ["springfield", "rolla"],
nevada: ["carlin", "vegas"],
}
const addState = (...states) => {
states.forEach(state => stateObject[state] = []);
}
const addCity = (state, ...cities) => {
stateObject[state] = [...stateObject[state], ...cities];
}
// test
addState('California', 'Texas')
addCity('California', 'Los Angeles')
addCity('Texas', 'Austin', 'Houston')
console.log(stateObject)
Related Topics
What's the Significant Use of Unary Plus and Minus Operators
How to Fire and Forget a Promise in Nodejs (Es7)
Using "Object.Create" Instead of "New"
Youtube Iframe API: How to Control an Iframe Player That's Already in the HTML
Pass Props to Parent Component in React.Js
Why Was the Arguments.Callee.Caller Property Deprecated in JavaScript
Difference Between Settimeout with and Without Quotes and Parentheses
Allow Google Chrome to Use Xmlhttprequest to Load a Url from a Local File
How to Check If a Checkbox Is Checked
How to Access Iframe Elements with JavaScript
Prevent Execution of Parent Event Handler
Javascript: How to Join/Combine Two Arrays to Concatenate into One Array
Why Don't We Just Use Element Ids as Identifiers in JavaScript
How to Deal with Big Numbers in JavaScript
Why Doesn't a JavaScript Return Statement Work When the Return Value Is on a New Line
What Do These JavaScript Bitwise Operators Do