0

我正在尝试实现原型继承,但我不理解它的行为。

考虑以下示例:

var config = {
  writable: true,
  enumerable: true,
  configurable: true
};

var defineProperty = function( obj, name, value ) {
  config.value = value;
  Object.defineProperty( obj, name, config );
}

var man = Object.create( null );
defineProperty( man, 'sex', 'male' );

var yehuda = Object.create( man );
defineProperty( yehuda, 'firstName', 'Yehuda' );
defineProperty( yehuda, 'lastName', 'Katz' );

当我访问正确的yehuda.sex返回male值时,但是当我尝试更新值时实际发生的是sexyehuda.

一种可能的解决方案是直接访问原型属性 ( Object.getPrototypeOf(yehuda).sex = 'female'),但这意味着我需要知道对象所属的属性。

4

1 回答 1

1

使用原型的想法是,当您尝试访问对象上的属性时,解释器将首先尝试在给定对象上找到该属性。

如果在给定对象上找不到该属性,则解释器将尝试在对象的原型上找到它,依此类推,直到原型链以null.

如果未找到该属性,则解释器返回undefined. 否则返回属性值。

在您的情况下,当您访问该属性sex时,它不会在对象上找到,但可以在对象的原型上找到。因此它返回male

然后,当您为其分配新值时sex,会在给定对象上创建一个新属性,而不是更改对象原型上的属性,因为 JavaScript 是一种动态语言。

这很好,因为新值会掩盖旧值。这就是原型继承的工作方式。

如果您明确想要更新原型上的属性而不是给定对象,我建议您在对象上创建属性,如下所示:

function defineProperty(object, name, value) {
    Object.defineProperty(object, name, {
        value: value,
        writable: true,
        enumerable: true
    });
}

function extendObject(object) {
    var extendedObject = Object.create(object);

    Object.keys(object).forEach(function (key) {
        Object.defineProperty(extendedObject, key, {
            set: function (value) {
                object[key] = value;
            },
            enumerable: true
        });
    });

    return extendedObject;
}

var man = Object.create(null);
defineProperty(man, "sex", "male");

var yehuda = extendObject(man);
defineProperty(yehuda, "firstName", "Yehuda");
defineProperty(yehuda, "lastName", "Katz");

这应该可以解决您的问题。要了解有关原型继承的更多信息,请阅读答案。

编辑:我建议您不要尝试更改原型的值。这是因为许多对象可能具有相同的原型。更改原型上的任何值意味着更改将反映在依赖它的所有对象上。除非这是您想要实现的目标,否则我建议您使用原型链上的阴影属性。

注意:您可以删除对象的属性。如果您删除的属性正在遮蔽另一个属性,那么它将在您下次访问相同的属性名称时使用被遮蔽的属性。

于 2012-06-11T12:41:15.243 回答