I have an extend method that extends objects like you would expect it would in JavaScript:
var objA = {a: true};
var objB = extend({b:false}, objA);
console.log(objB); // {a: true, b: false}
However, I would like to extend the source's (objA) properties onto the target (objB) object by reference so that any changes made to the source are reflected in the target after the fact, like so:
var objA = {a: true};
var objB = extend({b: false}, objA);
console.log(objB); // {a: true, b:false}
objA.a = false;
console.log(objB); // {a: false, b:false}
For instance, when you modify an object (which is always assigned by reference) things are working the way I would like them to:
var objA = {A:{a: true}};
var objB = _.extend({b: false}, objA);
console.log(objB) // {A:{a:true}, b:false};
objA.A.a = false;
console.log(objB); // {A:{a:false}, b:false};
So in other words, when changes are made to objA's non-object literal properties (or any value that isn't assigned by reference) I would like those changes to be reflected in objB.
I'm fairly sure this isn't exactly possible without an additional helper method that would depend on some sort of object watch method that is triggered whenever an object changes.
Thoughts?
Code from my extend method:
(l).extend = (l).merge = function () {
var args = (l).fn.__args(arguments, [{
deep: 'bool'
}, {
'*': 'obj:object'
}
]),
target = (l)._object || args.obj,
keys = [],
obj, objs, copy, key, i, o;
// Collect potential objects to merge
objs = (l).filter(args, function (value, index) {
if (index !== "obj" &&
(l).isPlainObject(value) && !((l).isEqual(target, value))) {
return value;
}
});
// When target object is not selected globally
if (!args.obj) {
target = objs.shift();
}
// When target object is not selected globally and only a single object
// is passed extend the library itself
if (!(l)._global && !objs.length) {
target = this;
objs[0] = args.obj;
}
// When a boolean is passed go deep
if (args.deep) {
// Build property reference used to prevent never ending loops
(l).each(objs, function (index, value) {
keys.push((l).keys(value));
keys = (l).flatten(keys);
});
// Add properties to all nested objects
(l).deep(target, function (depth, index, obj, ref) {
if ((l).indexOf(keys, index) === -1) {
for (i = 0; i < objs.length; i++) {
for (key in objs[i]) {
if ((l).isPlainObject(obj)) {
copy = objs[i][key];
obj[key] = copy;
}
}
}
}
}, "*");
}
// Merge first level properties after going deep
for (i = 0; i < objs.length; i++) {
if ((obj = objs[i]) !== null) {
for (key in obj) {
copy = obj[key];
if (target === copy) {
continue;
}
target[key] = copy;
}
}
}
return (l).fn.__chain(target);
};
What are you mentioned here is exactly the prototypal inheritance of JavaScript:
var objA = {a: false};
var objB = Object.create(objA);
objB.b = false;
console.log(objB.a, objB.b); // true,
objA.a = false;
console.log(objB.a, objB.b); // false, false
Of course if objB overrides the a property, you will lose that link, because JavaScript will found the property a in the object objB, therefore won't look up in the prototype's chain.
Using the ECMAScript 5 methods, you could have your extend function like that:
function extend(properties, proto) {
var object = Object.create(proto);
var descriptor = {};
Object.getOwnPropertyNames(properties).forEach(function(name) {
descriptor[name] = Object.getOwnPropertyDescriptor(properties, name);
});
return Object.defineProperties(object, descriptor);
}
var objA = {a: true};
var objB = extend({b: false}, objA);
console.log(objB.a, objB.b); // true, false
objA.a = false;
console.log(objB.a, objB.b); // false, false
Object.extend= function (properties,obj) {
function F() { };
F.prototype = obj;
var newObj = new F();
for (var prop in properties){
newObj[prop] = properties[prop];
}
return newObj;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With