Javascript 创建对象时选择性继承

Javascript selective inheritance while object creation

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

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 属性) 方法迭代 secondObject 属性 创建 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?

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

如果您希望 thirdObject 没有 firstObject 的属性,thirdObject 不应(间接)继承自 firstObject

三个选项供您选择("unreasonable" 第四个选项):

复制属性

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

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

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

模拟继承 getters/setters

或者,这确实需要迭代 secondObject 自己的属性,您可以使用 getter 和 setter 给 thirdObject 匹配的属性:

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 获取值来模拟继承 until/unless 某物为其赋值,在这种情况下我们将其设为标准数据 属性.

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

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

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


* 不合理的 方法是使用 Proxy(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.

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