Reputation: 755
Lets say I have an object relations like that;
var firstObject = { prop1:"prop1", prop2:"prop2" };
var secondObject = Object.create(firstObject);
secondObject.prop3 = "prop3";
secondObject.prop4 = "prop4";
var thirdObject = Object.create(secondObject);
At the above code when I have created thirdObject it will also inherit firstObject properties which is expected. What I wonder is , are there any elegant (I mean without iterating over secondObject properties with hasOwnProperty property) ways to inherit just secondObject properties while creating thirdObject?
Upvotes: 2
Views: 219
Reputation: 1074138
are there any elegant (I mean without iterating over secondObject properties with hasOwnProperty property) ways to inherit just secondObject properties while creating thirdObject?
No, and in fact, there's no (reasonable*) inelegant way to do it either; making thirdObject
inherit from secondObject
means it will inherit all of secondObject
's properties and the ones from its prototype(s).
If you want thirdObject
not to have firstObject
's properties, thirdObject
shouldn't inherit (indirectly) from firstObject
.
Three options for you (and an "unreasonable" fourth later):
You could use Object.assign
to copy secondObject
's own properties to thirdObject
:
var thirdObject = Object.assign({}, secondObject);
...but it wouldn't be inheritance, just a snapshot. But that might be for the best. (Object.assign
was added in ES2015 [aka "ES6"], but can be polyfilled for older JavaScript engines.)
Alternately, and this does require iterating secondObject
's own properties, you could give thirdObject
matching properties with getters and setters:
var firstObject = { prop1:"prop1", prop2:"prop2" };
var secondObject = Object.create(firstObject);
secondObject.prop3 = "prop3";
secondObject.prop4 = "prop4";
var thirdObject = {};
Object.keys(secondObject).forEach(function(key) {
Object.defineProperty(thirdObject, key, {
get: function() {
return secondObject[key];
},
set: function(value) {
delete this[key]; // Release the getter/setter for this
this[key] = value; // ...and make it an own property
},
configurable: true,
enumerable: true
});
});
console.log("prop1" in firstObject); // true
console.log("prop1" in secondObject); // true
console.log("prop1" in thirdObject); // false
console.log("--");
console.log("prop3" in firstObject); // false
console.log("prop3" in secondObject); // true
console.log("prop3" in thirdObject); // true
console.log("--");
console.log(firstObject.prop1); // prop1
console.log(secondObject.prop1); // prop1
console.log(thirdObject.prop1); // undefined
console.log("--");
console.log(firstObject.prop3); // undefined
console.log(secondObject.prop3); // prop3
console.log(thirdObject.prop3); // prop3
.as-console-wrapper {
max-height: 100% !important;
}
There, we mimic inheritance by having thirdObject
get the value from secondObject
until/unless something assigns a value to it, in which case we make it a standard data property.
Or you could make thirdObject
inherit from an intermediary that defers to secondObject
's own properties instead (a bit simpler, and then the "own" flags are right):
var firstObject = { prop1:"prop1", prop2:"prop2" };
var secondObject = Object.create(firstObject);
secondObject.prop3 = "prop3";
secondObject.prop4 = "prop4";
var thirdProto = {};
Object.keys(secondObject).forEach(function(key) {
Object.defineProperty(thirdProto, key, {
get: function() {
return secondObject[key];
},
configurable: true,
enumerable: true
});
});
var thirdObject = Object.create(thirdProto);
console.log("prop1" in firstObject); // true
console.log("prop1" in secondObject); // true
console.log("prop1" in thirdObject); // false
console.log("--");
console.log("prop3" in firstObject); // false
console.log("prop3" in secondObject); // true
console.log("prop3" in thirdObject); // true
console.log("--");
console.log(firstObject.prop1); // prop1
console.log(secondObject.prop1); // prop1
console.log(thirdObject.prop1); // undefined
console.log("--");
console.log(firstObject.prop3); // undefined
console.log(secondObject.prop3); // prop3
console.log(thirdObject.prop3); // prop3
.as-console-wrapper {
max-height: 100% !important;
}
* The unreasonable way would be to use a Proxy
(ES2015+, not polyfillable):
var firstObject = { prop1:"prop1", prop2:"prop2" };
var secondObject = Object.create(firstObject);
secondObject.prop3 = "prop3";
secondObject.prop4 = "prop4";
var thirdObject = Object.create(new Proxy(secondObject, {
has: function(target, prop) {
return target.hasOwnProperty(prop) || secondObject.hasOwnProperty(prop);
},
get: function(target, prop) {
return target.hasOwnProperty(prop) || secondObject.hasOwnProperty(prop) ? target[prop] : undefined;
},
set: function(target, prop, value) {
target[prop] = value;
return true;
}
}));
console.log("prop1" in firstObject); // true
console.log("prop1" in secondObject); // true
console.log("prop1" in thirdObject); // false
console.log("--");
console.log("prop3" in firstObject); // false
console.log("prop3" in secondObject); // true
console.log("prop3" in thirdObject); // true
console.log("--");
console.log(firstObject.prop1); // prop1
console.log(secondObject.prop1); // prop1
console.log(thirdObject.prop1); // undefined
console.log("--");
console.log(firstObject.prop3); // undefined
console.log(secondObject.prop3); // prop3
console.log(thirdObject.prop3); // prop3
.as-console-wrapper {
max-height: 100% !important;
}
Note: Requires a browser with <code>Proxy</code> support.
...but I can't imagine you want a proxy object in your inheritance chain, not least because of the effect it would have on performance. :-) So I wouldn't do that. (And I'm sure the example above is incomplete.)
Upvotes: 3