After all these great Answers, there is not really more to say, so heres an explanation based on the ECMAScript 5 specification.
Also a deepclone function at the end of the Answer.
As defined in the ES5 specification,
11.13.1 Simple Assignment ( = )
The production AssignmentExpression : LeftHandSideExpression = AssignmentExpression is evaluated as follows:
- Let lref be the result of evaluating LeftHandSideExpression.
- Let rref be the result of evaluating AssignmentExpression.
- Let rval be
GetValue(rref)
.
- Throw a SyntaxError exception if the following conditions are all true:
- Type(lref) is Reference is true
- IsStrictReference(lref) is true
- Type(GetBase(lref)) is Environment Record
- GetReferencedName(lref) is either "eval" or "arguments"
- Call
PutValue(lref, rval)
.
- Return rval.
So whats happening when we reach point 3 and rref
is an Object, is
§8.7.1 (section 4b of In GetValue(V) //V==rref
is the interesting point)
4.
If IsPropertyReference(V), then
- (b) Return the result of calling the get internal method using base as its this value, and passing GetReferencedName(V) for the argument.
Now at this point rval
holds the reference to the Object, which then gets put in at 5.
Where §8.7.2 (again 4b of PutValue(V,W) //V==lref , W==rval
is the interesting part) comes into play.
Note: W is atm the reference to the Object you want to assign and not the value
4.
Else if IsPropertyReference(V), then
- (b) Call the put internal method using base as its this value, and passing GetReferencedName(V) for the property name, W for the value, and IsStrictReference(V) for the Throw flag.
As you can see in your case the value of b
which is atm a reference to the Object [6, 7, 8]
gets replaced with the result of, so to speak GetValue(rref)
, which is a reference to [1, 2, 3];
However
Apparently you are looking for a deep clone function
Here is one.
Object.defineProperty(Object.prototype, "clone", {
value: function (deep) {
var type = Object.prototype.toString.call(this).match(/^\[object (.+?)\]$/)[1];
if (type !== "Object") {
return this.valueOf;
}
var clone = {};
if (!deep) {
for (var prp in this) {
clone[prp] = this[prp];
}
} else {
for (var prop in this) {
if (typeof this[prop] !== "undefined" && this[prop] !== null)
clone[prop] = (typeof this[prop] !== "object" ? this[prop] : this[prop].clone((typeof deep == "boolean" ? deep : (deep - 1))));
else
clone[prop] = "";
}
}
return clone;
},
enumerable: false
});
Object.defineProperty(Array.prototype, "clone", {
value: function (deep) {
var clone = [];
if (!deep) clone = this.concat();
else this.forEach(function (e) {
if (typeof e !== "undefined" && e !== null)
clone.push((typeof e !== "object" ? e : e.clone((deep - 1))));
else
clone.push("");
});
return clone;
},
enumerable: false
});
var a = [1, [2, { a: 3 } ], 4];
var b = a.clone(Infinity);
a[1][1]["a"] = "cloned";
console.log(a[1][1]["a"], b[1][1]["a"]); //"cloned" , 3
And a Demo on JSBin
To use it just call .clone(levelOfDeepness)
on an Object or Array
Note: I used the Objects prototype for simplicities sake as i can call directly .clone
of Object and Array elements while cloning them (gives a performance boost over the type checking variant in a single function)