0

I'm trying to implement prototypal inheritance but I'm not understanding it's behavior.

Consider the following example:

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' );

When I access to yehuda.sex returns male which is correct, but when I try to update the value what actually happens it's the creation of a new property sex on yehuda.

One possible solution is to access directly the prototype property (Object.getPrototypeOf(yehuda).sex = 'female') but that implies that I need to know the property to which object belongs.

Diogo Cardoso
  • 21,637
  • 26
  • 100
  • 138

1 Answers1

1

The idea of using prototypes is that when you try to access a property on an object the interpreter will first try to find that property on the given object.

If the property is not found on the given object then the interpreter will try to find it on the object's prototype and so on until the prototype chain ends in null.

If the property is not found the interpreter returns undefined. Otherwise it returns the property value.

In your case when you are accessing the property sex it's not found on the object but it is found on the object's prototype. Hence it returns male.

Then when you assign a new value to sex it creates a new property on the given object instead of changing the property on the object's prototype because JavaScript is a dynamic language.

This is fine since the new value shadows the old value. That's the way prototypal inheritance works.

If you explicitly want to update the property on the prototype instead of the given object I suggest you create propeties on your objects as follows:

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 should solve your problem. To know more about prototypal inheritance read this answer.

Edit: I suggest you do not try to change the values of the prototype. This is because many objects may have the same prototype. Changing any value on the prototype means that the change will be reflected on all the objects depending on it. Unless that is what you want to achieve I suggest you make do with shadowing properties on the prototypal chain.

Note: You can delete properties on objects. If the property you deleted was shadowing another property then it will shadowed property will be used the next time you access the same property name.

Community
  • 1
  • 1
Aadit M Shah
  • 72,912
  • 30
  • 168
  • 299
  • The most important part of your explanation is flawed. `because JavaScript is a dynamic language`, oh really? I'd like to know more about this, because I'm not getting it either, and "because JS is a dynamic language" definitely doesn't help. – Florian Margaine Jun 11 '12 at 12:53
  • Since JavaScript is a dynamic language it doesn't complain when you add new properties to an object. In the above case when you assign a value to the property `sex` on the object `yehuda` the JavaScript interpreter sees that such a property does not exist on the given object. So it creates a new property called `sex` on the object `yehuda` even though the given property does exist on the prototype of `yehuda`. The new `sex` property shadows the property of the same name on the object's prototype. Does that clear things in your mind? Glad to help. – Aadit M Shah Jun 11 '12 at 12:58
  • We might need to add `object` structures' prototype as well as the param `object` when creating `extendedObject`. Otherwise, the prototype `extendedObject` does not have `object` prototype functions such as `hasOwnProperty` or `toString`. – papillon May 03 '21 at 10:06