Javascript 在对象创建时选择性继承

标签 javascript prototypal-inheritance

假设我有这样的对象关系;

var firstObject = {     prop1:"prop1",  prop2:"prop2" };

var secondObject = Object.create(firstObject);

secondObject.prop3 = "prop3";

secondObject.prop4 = "prop4";

var thirdObject =  Object.create(secondObject);

在上面的代码中,当我创建thirdObject时,它也会继承预期的firstObject属性。我想知道的是,有没有优雅的(我的意思是没有 使用 hasOwnProperty 属性迭代 secondaryObject 属性)的方法 创建 ThirdObject 时仅继承 SecondObject 属性?

最佳答案

are there any elegant (I mean without iterating over secondObject properties with hasOwnProperty property) ways to inherit just secondObject properties while creating thirdObject?

不,事实上,也没有(合理*)不优雅的方法来做到这一点;让 thirdObject 继承 from secondObject 意味着它将继承 secondObject 的所有属性及其原型(prototype)中的属性( s)。

如果您希望 thirdObject 不具有 firstObject 的属性,则 thirdObject 不应从 firstObject< 继承(间接)/.

给你的三个选择(以及后面的“不合理”的第四个选择):

复制属性

您可以使用Object.assignsecondObject自己的属性复制thirdObject:

var thirdObject = Object.assign({}, secondObject);

...但它不是继承,只是一个快照。但这可能是最好的。 (Object.assign 是在 ES2015 [又名“ES6”] 中添加的,但可以为较旧的 JavaScript 引擎进行填充。)

使用 getter/setter 模拟继承

或者,这确实需要迭代 secondObject 自己的属性,您可以为 thirdObject 提供具有 getter 和 setter 的匹配属性:

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;
}

在那里,我们通过让 thirdObjectsecondObject 获取值来模拟继承,直到/除非有东西给它赋值,在这种情况下,我们将其设为标准数据属性.

通过带有 getter 的中介使用继承

或者你可以让thirdObject从一个遵循secondObject自己的属性的中介继承(更简单一点,然后“自己的”标志是正确的) :

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;
}


* 不合理的方法是使用代理(ES2015+,不可填充):

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.

...但是我无法想象您想要在继承链中使用代理对象,尤其是因为它会对性能产生影响。 :-) 所以我不会这样做。 (我确信上面的例子是不完整的。)

关于Javascript 在对象创建时选择性继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42716659/

相关文章:

java - 使用 ajax 将 javascript 变量传递给 servlet

Javascript Engine V8 快速属性访问

javascript - 语法错误 : Unexpected token N in chrome console from angularjs

javascript - 从基本提供者继承时如何防止直接访问属性?

javascript - John Resig 简单继承属性的奇怪问题

javascript - Object.create 与直接原型(prototype)继承

javascript - 对于更简单的用例来说 angular.js 是否被认为太大

javascript - Phonegap/Cordova getDirectory 在 BlackBerry 上失败

JavaScript 原型(prototype)继承显示父对象名称

javascript继承模式比较