Can someone please help explain why I'm unable to assign this list as an object prototype in the same manner that I can assign a simpler object property? My understanding was that obj_a & obj_b should each get their their own _amount & _list instances.
This returns unique values for each object... as expected:
const Amount = {
_amount: 0,
set_Amount: function (foo) {
this._amount = foo;
},
get_Amount: function () {
return this._amount;
},
};
function func_a() {}
function func_b() {}
const obj_a = new func_a()
const obj_b = new func_b()
Object.assign(func_a.prototype, Amount);
Object.assign(func_b.prototype, Amount);
obj_a.set_Amount(1)
obj_b.set_Amount(2)
console.log(obj_a.get_Amount()) //1
console.log(obj_b.get_Amount()) //2
But the arrays are being consolidated here... so they seem to share the same instance??
const objList = {
_list: [],
add_item: function (foo) {
this._list.push(foo)
},
list: function () {
return this._list;
},
total: function (){
let x = 0;
for (let item in this._list) {
x = Number(x) + Number(this._list[item]);
}
return x;
}
}
function type_a() {}
function type_b() {}
const obj_a = new type_a()
const obj_b = new type_b()
Object.assign(type_a.prototype, objList);
Object.assign(type_b.prototype, objList);
obj_a.add_item(1)
obj_a.add_item(2)
obj_b.add_item(3)
obj_b.add_item(4)
console.log(obj_a.list()) // [1, 2, 3, 4]
console.log(obj_a.total()) // 10
console.log(obj_b.list()) // [1, 2, 3, 4]
console.log(obj_b.total()) // 10
It's because the array is an object, so even when you merge a clone of objList
with Object.assign()
, the nested objects are shallow copied, or copied by reference. This is unlike primitives such as numbers, strings, booleans, etc, which are copied by value.
// Create
const baseObj = {
list: [], // Object
num: 0 // Primitive
}
// Clone
const testA = {...baseObj}
const testB = {...baseObj}
// Mutate
testA.num = 5;
testB.list.push(2);
// Test
console.log('Are Objects copied by reference? ', testA.list === testB.list)
console.log('Are Primitives copied by reference? ', testA.num === testB.num)
We need to deep clone objList
to create completely new instances of everything inside. We can use lodash's cloneDeep()
to do this:
const objList = {
_list: [],
add_item: function (foo) {
this._list.push(foo)
},
list: function () {
return this._list;
},
total: function (){
let x = 0;
for (let item in this._list) {
x = Number(x) + Number(this._list[item]);
}
return x;
}
}
function type_a() {}
function type_b() {}
Object.assign(type_a.prototype, _.cloneDeep(objList));
Object.assign(type_b.prototype, _.cloneDeep(objList));
const obj_a = new type_a()
const obj_b = new type_b()
obj_a.add_item(1)
obj_a.add_item(2)
obj_b.add_item(3)
obj_b.add_item(4)
console.log(obj_a.list())
console.log(obj_a.total())
console.log(obj_b.list())
console.log(obj_b.total())
<script crossorigin src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>