在JavaScript中更新prototype属性

时间:2012-06-11 12:12:08

标签: javascript jquery inheritance prototype

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

考虑以下示例:

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这是正确的,但当我尝试更新实际发生的值时,就会在{{1}上创建新属性sex }。

一种可能的解决方案是直接访问prototype属性(yehuda),但这意味着我需要知道对象所属的属性。

1 个答案:

答案 0 :(得分:0)

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

如果在给定对象上找不到该属性,则解释器将尝试在对象的原型上找到它,依此类推,直到原型链在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");

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

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

注意:您可以删除对象的属性。如果您删除的属性是遮蔽另一个属性,则下次访问相同的属性名时将使用shadowed属性。