POV
POV

Reputation: 12015

Does spread operator return new object after operation?

As I know spread operator return a new object after operation:

let a = {a:1};
let b = {a: 2}
let a = {...a,...b}

So, last a is not referenced to a, it is a new object in memory.

Is it possible to use spread operator without changing initial object, I mean a reference in memory?

Upvotes: 2

Views: 579

Answers (2)

Branchverse
Branchverse

Reputation: 1397

Spread operator only works on primitive types.

Here an example with primitive datatypes:

let x = {
  number: 1
}
let y = { ...x
}
x.number++
  console.log(x)
console.log(y)

Non Primitive:

let x1 = {
  numbers: {
    number: 1
  }
}
let y1 = { ...x1
}
x1.numbers.number++
  console.log(x1)
console.log(y1)

As you can see, the 2nd version still uses references, to bypass this use a deep clone function like this:

let x1 = {
  numbers: {
    number: 1
  }
}
let y1 = copy(x1)
x1.numbers.number++
  console.log(x1)
console.log(y1)

function copy(aObject) { // Deep Clone Object from https://stackoverflow.com/a/34624648/16642626
  if (!aObject) {
    return aObject;
  }

  let v;
  let bObject = Array.isArray(aObject) ? [] : {};
  for (const k in aObject) {
    v = aObject[k];
    bObject[k] = (typeof v === "object") ? copy(v) : v;
  }

  return bObject;
}

So if u truly want to keept the reference, you could nest the a and b in ur example so that the spread operator is not able to see the primitive types on the first layer

Upvotes: 1

zerkms
zerkms

Reputation: 255015

It's guaranteed by the 12.2.6.7 Runtime Semantics: Evaluation and 12.2.6.8 Runtime Semantics: PropertyDefinitionEvaluation that the object returned from an object literal with "spread syntax" is always a new object.

Relevant parts of the spec:

  1. Let obj be ObjectCreate(%ObjectPrototype%).

and

PropertyDefinition:...AssignmentExpression
1. Let exprValue be the result of evaluating AssignmentExpression.
2. Let fromValue be ? GetValue(exprValue).
3. Let excludedNames be a new empty List.
4. Return ? CopyDataProperties(object, fromValue, excludedNames).

There is currently no other way to mutate the object other than just assigning its properties directly.

As @Heretic Monkey noted in the comments: the question is tagged as typescript while I'm answering about javascript. The thing is that TS compiler must retain the native js runtime semantics, so in this very case it's okay to refer to the ES2018 standard.

Upvotes: 3

Related Questions