Inherited child objects share the same array property in JavaScript? - javascript

> function Parent() {this.arr = [];}
undefined
> function Child() {}
undefined
> Child.prototype = new Parent();
{ arr: [] }
> child1 = new Child();
{}
> child2 = new Child();
{}
> child1.arr.push('From child1');
1
> child2.arr
[ 'From child1' ]
>
Given the above, I would expect child2.arr to be empty as it is its own object. How can I have child1 and child2 contain their own arr? Thanks!

You'll have to make the assignment in your constructor:
function Child() {
this.arr = this.arr ? this.arr.slice(0) : [];
}
That gives each child a copy of the prototype's .arr array, if it exists. (It's just a shallow copy, and that's just a possible example.) Assignments to object properties always involve local ("own") properties of the target object, but references involve the prototype chain.
Also not that for fairly arcane reasons it's not a good idea to initialize a prototype like that. Better to use Object.create:
Child.prototype = Object.create(Parent.prototype);
That gives you a new object that uses the Parent prototype object as its prototype.
Here is a somewhat old but still interesting question on the topic.

Look into inheritance in javascript
Basically if the property is not on the object you are looking into javascript looks into it's prototype and tries to find it there until it reaches the Object.
Your Child does not have property arr but it's prototype new Parent() does and that one is referred from Child1 and Child2.

function Parent() { this.arr = []; }
function Child() { this.parent = new Parent(); }
Child.prototype = new Parent();
var child1 = new Child();
var child2 = new Child();
child1.parent.arr.push('From child1');
alert(child2.parent.arr);

Related

What's the difference between childObj.prototype = Object.create(parentObj.prototype) and childObj.prototype = parentObj.prototype?

I'd like to know the difference between:
childObj.prototype = Object.create(parentObj.prototype)
and
childObj.prototype = parentObj.prototype;
Because both of them I need to call the parent constructor inside the child object to have access to the constructor properties.
I know how Object.create function works, and I notice that the difference is only because It returns a NEW object with the with the parent's prototype. I guess what I'm not understanding is the effect of returning a new object with the parent's prototype.
Your first sample is the correct way to go about it, as it creates a new object with the parentObj.prototype as its [[Prototype]]:
childObj.prototype = Object.create(parentObj.prototype); // { __proto__: parentObj.prototype }
The second one just sets childObj.prototype to the same object as the parentObj.prototype. This causes some problems:
function parentObj() {
}
parentObj.prototype.parentFn = function() { console.log('parent'); };
function childObj() {
}
childObj.prototype = parentObj.prototype;
// here we are writing onto parentObj.prototype as well!!!
childObj.prototype.childFn = function() { console.log('child'); };
var child = new childObj();
var parent = new childObj();
child.parentFn(); // 'parent'
parent.childFn(); // 'child' --- this should not happen!!!
In directly assigning the object, we have written onto the parent .prototype.
Basically Object.create's first parameter is the prototype and second parameter is the property descriptor object. Hence when you are passing the prototype object to the Object.create alone, An object without any own properties would be created and the passed object would be assigned to the __proto__ of the newly created object.
var x = {a:10};
var y = Object.create(x);
console.log(y); //{__proto__:{a:10}}
But when you are assigning the parent's prototype to the child's, simply the references are overlapped. And there will not be any structural change happen in the object.
One difference I can think of is this:
assuming you have
c = new childObj()
p = new parentObj()
in both cases you'll have
c instanceof parentObj === true
but in the second case you'll also have
p instanceof childObj === true
whild in the first case you'll have
p instanceof childObj === false

Javascript: How to create a new instance of the prototype object? [duplicate]

This question already has answers here:
B extends A, but B.add populates A.prototype.property
(2 answers)
Closed 9 years ago.
The prototype is an object that is inherited? by all instances of the object, like child in my following example.
It has to be an instance of the parent, else parent's prototype will not get inherited?
In this case, the goal is to create a separate array, which is inherited from parent, for each instance of child.
I am unsure how to achieve that exactly. I know of extend.
Is the extend method simply copying prototypes over to a new object and applying the new methods onto it as well?
My code example + jsfiddle:
function parent(){
}
parent.prototype.arr = [];
parent.prototype.add = function(item){
this.arr.push(item);
}
parent.prototype.show = function(){
for(var i = 0; i < this.arr.length; ++i){
$('body').append(this.arr[i]);
}
}
function child(childname){
this.add(childname);
}
child.prototype = new parent();
var child1 = new child('child1');
var child2 = new child('child2');
child2.show();//this should only show child2?
To give each instance its own array, don't use the prototype to hold the array because it is shared among all instances. You can initialize a new array in the constructor of parent and then in the child class make sure you call the parent's constructor:
function parent(){
this.arr = [];
}
function child() {
parent.call(this); // call parent constructor
}
child.prototype = Object.create(parent.prototype);
child.prototype.constructor = child;
Now every parent object will have its own copy of the array including the ones that are part of the child descendants.
See this MDN article for a good explanation: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create

Why does this javascript inheritance cause references to share array? [duplicate]

This question already has answers here:
Javascript "OOP" and prototypes with multiple-level inheritance
(3 answers)
Closed 9 years ago.
i have a base class
function Base(){
this.children = new Array();
}
Base.prototype.Add = function(child){
this.children.push(child)
}
function Sub1(){...}
Sub1.prototype = new Base();
function Sub2(){...}
Sub2.prototype = new Base();
so how come when i do
var S1_1 = new Sub1();
var S1_2 = new Sub1();
S1_1.Add(new Sub2());
S1_2 for some reason also has 1 child and contains the same information as the child i added to S1_1?
It's because that's how prototypal inheritance works. All your Sub1 objects inherit from a common Base object. Because the Base object holds the Array, all Sub1 instances share that Array.
In other words, when you ask for the .children property of each Sub1 object, they will see that they don't own such a property, and will therefore look for it on the prototype from which they inherit. Since they inherit from the same prototype object, they use the same Array.
For each Sub1 to have its own Array, you should define it in the Sub1 constructor.
function Base(){
this.children = new Array();
}
Base.prototype.Add = function(child){
this.children.push(child); // `this` will be whatever object invoked the method
}
function Sub1(){
this.children = [];
}
Sub1.prototype = new Base();
function Sub2(){
this.children = [];
}
Sub2.prototype = new Base();
You didn't take ownership/copy of the Base variables defined with this when creating a sub, you can do so with:
function Sub1(){
Base.call(this);
}
What that code does is calling Base with the Sub1 instance as the this context.
More on prototype behavior can be found here: Prototypical inheritance - writing up

Why do I need to set constructor for a extend function?

I'm trying to fully understand how 'extend' works in javascript.
Here's a simple extend function I found on google
function extend(child, parent) {
var f = function() {}
f.prototype = parent.prototype;
var i;
for( i in parent.prototype ) {
child.prototype[i] = parent.prototype[i];
}
child.prototype.constructor = child;
child.parent = parent;
}
it works, but I don't understand "child.prototype.constructor = child" part. The function still works without it.
What's the purpose of the line?
No. Where did you find that? It mixes two approaches:
The classical prototype inheritance
function inherit(child, parent) {
var f = function() {}
f.prototype = parent.prototype;
child.prototype = new f();
child.prototype.constructor = child;
}
This function creates a new object that inherits directly from the prototype object of the parent function. It is an old-style synonym for Object.create(). With that, a prototype chain is set up - all instances of child inherit from the parent.prototype as well. Because a new object is generated to overwrite child.prototype, the "constrcutor" property needs to be updated.
The mixin inheritance
This function just loops over all properties of the parent's prototype object, and copies them onto the child's prototype object. This is quite what the common helper function extend does. It does not reset the "prototype" property of the child function, but it also does not set up a inheritance chain.
function extend(child, parent) {
for (var i in parent.prototype ) {
child.prototype[i] = parent.prototype[i];
}
}
You are right, the line
child.prototype.constructor = child;
is quite useless here - the "constructor" property is not enumerable and will not be affected by the extend.
Also, your function sets a "parent" property of the child function object to the parent function, which is not required:
child.parent = parent;
It appears to me that the 'child.prototype.constructor' is a base/vanilla implementation of the object, it allows other objects to extend from it without inheriting the same parent. Hence why it is declared prior to 'child.parent = parent'.
This may not directly answer your question, but I would like to reccomend you to use the extend implementation of John Resig:
Simple JavaScript Inheritance
It allows you to create a constructor named init, like this:
var MyClass = Class.extend({
init: function() {
console.log("Running a constructor");
}
});
and instanciate objects like this (normal):
var obj = new MyClass();
This example shows how to inherit a class in javascript
var a = function(){
// class a constructor
this.a_priviligiate_var = 1;
}
a.prototype.a_public_var = 2;
var b = function(){
// class b constructor
// super call of class a constructor
// this line makes b class to inherit all privileged vars
b.prototype.constructor.call(this)
this.b_priviligiate_var = 3;
}
b.prototype.b_public_var = 4;
b.prototype = new a();
var c = new b();
Defining a claas:
var a = function(){
// class a constructor
this.a_priviligiate_var = 1;
}
a.prototype.a_public_var = 2;
Defining another class:
var b = function(){
// class b constructor
// super call of class a constructor
// this line makes b class to inherit all privileged vars
b.prototype.constructor.call(this)
this.b_priviligiate_var = 3;
}
b.prototype.b_public_var = 4;
Setting the super(parent) class. This line copies all b.prototype
b.prototype = new a();
Creating a instance of c
var c = new b();

What are the side effects of breaking the prototype chain in javascript?

We write a lot of JavaScript code to run our automated testing using a tool called TestComplete. In several cases I've set up inheritance trees using the following syntax:
function Parent()
{
...
//some inline code here executes on object creation
}
Child.prototype = Parent;
Child.prototype.constructor = Child;
function Child()
{
Parent.call(this);
...
}
The reason I've used
Child.prototype = Parent;
instead of
Child.prototype = new Parent();
is because there is code that is executed on the creation of a new object in the parent in some cases. Setting the prototype this way has never been an issue, in that I've always been able to call all the functions defined in the Parent after having created a Child.
I suspect, however, I've actually broken the prototype chain in doing this and I've been saved by the fact that all the methods we define are defined inline (ie. inside the constructor function) and not using the object.prototype.method = ... syntax, and so the fact the chain is broken has gone unnoticed.
So I have two questions; have I broken the chain, and what are the side effects of breaking the prototype chain in JavaScript?
When you "break" the prototype chain like this, you cannot access Parent.prototype.* methods and properties in Child instances and the instanceof operator does not work (new Child() instanceof Parent === false).
I understand why you don't want to use the new keyword for the inheritance. There is, however, a little trick to inherit the parent's prototype whilst not executing the parent's constructor:
var Parent = function () { ... };
var Child = function () {
Parent.call(this);
...
};
var Fn = function () {};
Fn.prototype = Parent.prototype;
Child.prototype = new Fn();
Child.prototype.constructor = Child;
Ok, this code will run for you and allows access to the prototype. It involves making the parent an object literal and you can call a prototype method in your child's "constructor"
var Parent = {
testMethod1 : function() {
alert('testMethod1');
}
}
Parent.testMethod2 = function() {alert('testMethod2');}
Child.prototype = Parent;
//Child.prototype.constructor = Child;
function Child()
{
alert('im ready');
Child.prototype.testMethod1();
}
var child1 = new Child();
child1.testMethod1();
child1.testMethod2();
Parent.testMethod3 = function() {alert('testMethod3');}
child1.testMethod3();
and if you wanted to do away with 'new' you could use Object.create()
var Parent = {
testMethod1 : function() {
alert('testMethod1');
}
}
Parent.testMethod2 = function() {alert('testMethod2');}
var child1 = Object.create(Parent);
child1.testMethod1();
child1.testMethod2();
Parent.testMethod3 = function() {alert('testMethod3');}
child1.testMethod3();
Object.create = function (o) {
function F() {}
F.prototype = o;
return new F();
};
In the second case you would need to call a function as your "constructor" after you create()'d the object, but it's true protototypal inheritance.

Categories

Resources