Objects Contain Same Values But Shouldn't
Solution 1:
objects contain same values but shouldn't
They should, because you haven't changed the options
property on variation
, so it still points at the same object that the original.options
points to.
When you do this:
var original = {
options: {
value: null,
factor: 13
},
init: function (container) {
this.options.value = container.getAttribute('data-value');
}
};
Here's what you get in memory (some details omitted):
+−−−−−−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−+ +−−−>| (Object.prototype) |<−+ original−−−>| (object) | | +−−−−−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−−+ | | | __proto__ |−−−+ +−−−−−−−−−−−−−+ | | options |−−−−−−−>| (object) | | | init |−−−+ +−−−−−−−−−−−−−+ | +−−−−−−−−−−−−+ | | __proto__ |−−−−−−−−−+ | | value: null | | | factor: 13 | | +−−−−−−−−−−−−−+ | | +−−−−−−−−−−−−+ +−−−−| (function) | +−−−−−−−−−−−−+
...where __proto__
is a pseudo-property showing what the object's prototype is (specifically, the value of what the spec calls the object's internal [[Proto]]
property). (On browsers, in ES2015, there is actually a __proto__
accessor, but it shouldn't be used.)
Then when you do this:
var variation = Object.create(original);
You have:
+−−−−−−−−−−−−+ variation−−>| (object) | +−−−−−−−−−−−−+ | __proto__ |−−+ +−−−−−−−−−−−−+ | | +−−−−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−+ | +−>| (Object.prototype) |<−+ \ +−−−−−−−−−−−−+ | +−−−−−−−−−−−−−−−−−−−−+ | original−−−>| (object) | | | +−−−−−−−−−−−−+ | | | __proto__ |−−−−−+ +−−−−−−−−−−−−−+ | | options |−−−−−−−>| (object) | | | init |−−−+ +−−−−−−−−−−−−−+ | +−−−−−−−−−−−−+ | | __proto__ |−−−−−−−−−+ | | value: null | | | factor: 13 | | +−−−−−−−−−−−−−+ | | +−−−−−−−−−−−−+ +−−−−| (function) | +−−−−−−−−−−−−+
You can see how both original
and variation
are still pointing at the same options object.
If you want separate options objects, you have to create a new object. You could make variation.options
use original.options
as its prototype:
var variation = Object.create(original);
variation.options = Object.create(original.options);
...but then you'd have to do it again for firstDiv
and secondDiv
:
var firstDiv = Object.create(variation);
firstDiv.options = Object.create(variation.options);
var secondDiv = Object.create(variation);
secondDiv.options = Object.create(variation.options);
...which suggests we need to do something different.
You could have a function you use to do it:
functioncreateVariation(source) {
var v = Object.create(source);
v.options = Object.create(source.options);
return v;
}
var variation = createVariation(original);
var firstDiv = createVariation(variation);
var secondDiv = createVariation(variation);
...but you might look at constructor functions or maker functions, and a fairly typical pattern called the "extend" function (such as jQuery's or Underscore's).
Solution 2:
Neither firstDiv
nor secondDiv
has its own options
property. Both inherit options
from original
. You can test this by observing that all of the expressions below are false
:
variation.hasOwnProperty("options") // false
firstDiv.hasOwnProperty("options") // false
secondDiv.hasOwnProperty("options") // false
Your init
function does this.options.value = ...
, but consider for a moment only the expression this.options
. You never create another options
object, so when you ask for firstDiv
or secondDiv
for its options
object, that escalates the this.options
lookup to the original
prototype object.
Thus, when you access the options
property of either firstDiv
or secondDiv
, you are causing the property lookup to escalate to original
(the first object in the prototype chain that really has an options
property). This means that firstDiv.options
and secondDiv.options
are the exact same object (namely, original.options
). Therefore, it follows that when you set secondDiv.options.value
, you are also setting firstDiv.options.value
.
The solution here is to ensure that firstDiv
and secondDiv
explicitly have their own options
property. However, you also want that options
value to itself inherit from variation.options
, and you want variation
to have its own options
value as well, which inherits from original.options
. T.J. Crowder's answer addresses this in detail with his createVariation
method:
functioncreateVariation(source) {
var v = Object.create(source);
v.options = Object.create(source.options);
return v;
}
var variation = createVariation(original);
var firstDiv = createVariation(variation);
var secondDiv = createVariation(variation);
Post a Comment for "Objects Contain Same Values But Shouldn't"