简体   繁体   中英

JavaScript inherit object as property

What I currently have is an object, say b, that inherits an other object, say a. In object a I have an object as property(value). To clear things up:

var a = (function(){});

a.prototype.value = {
    val : "value a"
};

var b = (function(){
    this.value.val = "b";
    alert("object b: " + this.value.val);
});

b.prototype = Object.create(a.prototype);
b.prototype.constructor = a;

new b();  // alerts "object b: b"

http://jsfiddle.net/qqmtb846/

So far, so good. In object b I set the 'val' property of the 'value' object to another value. As expected the value is set(value is now 'b').

When I create another object, lets say c, I would expect that I get the original value('value a').

This is not the case. I'm sure this is due object reference.

var a = (function(){});

a.prototype.value = {
    val : "value a"
};

var b = (function(){
    this.value.val = "b";
    alert("object b: " + this.value.val);
});

var c = (function(){
    alert("object c: " + this.value.val);
});

b.prototype = Object.create(a.prototype);
b.prototype.constructor = a;

c.prototype = Object.create(a.prototype);
c.prototype.constructor = a;

var ObjectB = new b(); // alerts "object b: b"
var ObjectC = new c(); // alerts "object c: b", I want that "object b: value a" is displayed

http://jsfiddle.net/eb6dsgv9/1/

I want to use an object as property in the super class because most of the values will be the same, but sometimes they have to change. There is still a referance despite it's a new instance.

1) Is this some kind of design weakness of JavaScript? 2) How can I resolve this?

This is expected behavior. In your constructor, this.value refers to the same object as a.prototype.value . You can overwrite this.value with a new value (which will leave a.prototype and its properties unchanged), but if you modify this.value.val you are modifying the val property of a.prototype.value .

I don't know what you mean by "design weakness" so I can't answer (1). This is simply the way JavaScript's prototypal inheritance works.

As for how to resolve it, I think you need to show us a more concrete example, as I don't think there's a simple one-size-fits-all solution to this. It could be resolved by using a deep copy instead of Object.create (though depending on how you do the deep copy you could lose any methods on the prototype, if it has any). To put it simply, if you need to modify the properties of the prototype's properties, you are going to run into a situation like this.

Probably a better solution is to have a separate set of data values for each instance. Having all your instances share the same set of data values is creating a mess in your situation.

Initialize the properties in a 's constructor:

var a = function () {
    this.value = {
        val: "value a"
    };
};

And then you can call that constructor from b and c 's constructor:

var b = function () {
    b.prototype.constructor.call(this);
    this.value.val = "b";
    console.log("object b: " + this.value.val);
};

var c = function () {
    c.prototype.constructor.call(this);
    console.log("object c: " + this.value.val);
};

http://jsfiddle.net/eb6dsgv9/6/

To add to JLRishe answer, you can make it work this way:

http://jsfiddle.net/eb6dsgv9/3/

var a = (function(){
    this.value = {
        val : "value a"
    }
});

var b = (function(){
    a.call(this);
    this.value.val = "b";
    alert("object b: " + this.value.val);
});

var c = (function(){
    a.call(this);
    alert("object c: " + this.value.val);
});

var ObjectB = new b();
var ObjectC = new c();

Here, 'value' is property of 'a', not a.prototype. In 'a' and 'c' constructors you create new, separate 'a', so you get a fresh 'value a' each time. The downside of it is you spend more memory for all 'a' instances.

I based my answer on this: Javascript property inheritance

Object.create(a.prototype) creates a brand new object with it's [prototype] pointing to a.prototype . Your new ObjectB and ObjectC are brand new objects with their [prototype] pointing to c.prototype resp. b.prototype which is your above new empty object with [prototype] pointing to a.prototype .

In your b constructor you try set the property value.val to "b" but ObjectB does not have such a property value . javascript than looks into b prototype which is again empty object but has the link in it's [prototype] to another object which is a.prototype . that object has property value so it is set value.val = "b" .

In case of ObjectC the linking is the same, the only difference is that you are looking for property value . Javascript looks in every objects in the [prototype] chain until it finds the value property which is in your a.prototype object.

It is not design weakness of javascript it is it's strength actually. javascript is not OOP language.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM