Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recursive prototypal inheritance in javascript?

Object.create = function (o) {
    function F() {}
    F.prototype = o;
    return new F();
};

From Prototypal Inheritance in JavaScript

I've been using this code for a while to create new objects inheriting from previous ones. However I ran across a little surprise.

a = {
    foo: [1,2,3]
}

b = Object.create(a);
// b.foo -> [1,2,3]
b.foo = "test";
// b.foo -> "test"
// a.foo -> [1,2,3]

c = Object.create(a);
// c.foo -> [1,2,3]
c.foo[0] = 'test';
// c.foo -> ["test",2,3]
// a.foo -> ["test",2,3]

In trying to change c.foo I changed a.foo instead, c.foo showing the change because it's inheriting from a. The only solution I see right now is to only modify direct properties of b:

d = Object.create(a);
d.foo = Object.create(a.foo);
d.foo[0] = 'text';

I'm sure there's a better solution I'm missing! How can I create new objects from old objects without risking modifying the original?

like image 557
AnnanFay Avatar asked May 27 '11 03:05

AnnanFay


People also ask

What is prototypal inheritance JavaScript?

The Prototypal Inheritance is a feature in javascript used to add methods and properties in objects. It is a method by which an object can inherit the properties and methods of another object. Traditionally, in order to get and set the [[Prototype]] of an object, we use Object. getPrototypeOf and Object.

Why is prototypal inherited?

Prototypical inheritance allows us to reuse the properties or methods from one JavaScript object to another through a reference pointer function. All JavaScript objects inherit properties and methods from a prototype: Date objects inherit from Date.

Does JavaScript support multi level inheritance?

JavaScript does not support multiple inheritance. Inheritance of property values occurs at run time by JavaScript searching the prototype chain of an object to find a value.

How prototypal inheritance is different from classical inheritance in JavaScript?

Classical inheritance is limited to classes inheriting from other classes. However prototypal inheritance includes not only prototypes inheriting from other prototypes but also objects inheriting from prototypes.


2 Answers

+1 for referencing Crockford =D

I think arrays are always passed by reference, and the array is never copied. I think Array.slice would copy it, but that's a fringe case...

The create function is mostly used to copy functions and such. I don't ever use that method, as I just create a constructor function:

function a() {
    this.foo = [0, 1, 2];
}

This way, you'll always get a new array for each call. Just do b = new a(); It works for me...

I try to avoid inheritance, because there's always problems with it. I would just use the constructor, then assign new variables to it (not the prototype). Multiple inheritance gets tricky though...

like image 134
beatgammit Avatar answered Oct 21 '22 12:10

beatgammit


When you create a new object from a prototype no copying is done. Not even the property is copied:

function F() {}
F.prototype.a = 1
new F().hasOwnProperty("a") // => false
new F().a // => 1

If you do

var f = new F();
f.a = 2;

Then you are not changing the property in F.protoype, you are adding a new property to f:

var f = new F();
f.a = 2;
f.a // => 2;
delete f.a;
f.a // => 1

So this applies to every value you assign a property. If you want to clone a value you have to do it explicitly, simplest way is to just set a new property in the constructor:

function F() {
  this.a = [];
}
var f = new F();
var g = new F();
f.a === g.a // => false

This problem only arises when the prototype contains mutable values, other values can not be modified (the properties can change values instead).

And if you want to "subclass" F, remember to call it from the new constructor:

function F() { this.a = []; }
function G() { F.call(this); }
G.prototype = new F();
like image 32
Adam Bergmark Avatar answered Oct 21 '22 13:10

Adam Bergmark