LINUX.ORG.RU

Наследование на прототипах не работает?

 


0

2

Столкнулся с такой неприятной особенностью прототипного наследования. Если у объекта-родителя имеется мутабельная переменная (в данном случае v1), то она «расшаривается» между всеми детьми.

В примере ниже изменяем переменную v1 у объекта foo. В результате чего меняется значение v1 у объекта bar.

Как сделать, чтобы у каждого объекта были свои переменные?

function O1(){
  this.v1 = [];
}

O2.prototype = new O1();
O2.prototype.constructor = O2;
function O2(){
  this.v2 = [];
}

var foo = new O2();
var bar = new O2();

foo.v1.push("CHANGE");
foo.v2.push("CHANGE");

console.dir(bar.v1); // ["CHANGE"]
console.dir(bar.v2); // []
★★★★★

Ответ на: комментарий от quest2017

Что-то туплю на ночь глядя. Чтобы

...
function O2(){
  O1.call(this);
  this.v2 = [];
}
...

ЗЫ: То что ты написал - я не распарсил, извини

makoven ★★★★★
() автор топика
Ответ на: комментарий от makoven

Этого ты хочешь?

function O1(){
  this.v1 = [];
}

O2.prototype = new O1();
O2.prototype.constructor = O2;
function O2(){
  this.v1=[]
  this.v2 = [];
}

var foo = new O2();
var bar = new O2();

foo.v1.push("CHANGE");
foo.v2.push("CHANGE");

console.dir(bar.v1); //[]
console.dir(bar.v2); //[]

console.dir(foo.v1); //[ 'CHANGE' ]
console.dir(foo.v2); //[ 'CHANGE' ]

quest2017
()
Ответ на: комментарий от makoven

O1.call(this); this.v2 = [];

Это тоже будет работать, это миксин, ты экстендишь класс тут, чо тебе надо, ты определись уже.

quest2017
()
Ответ на: комментарий от quest2017

Да я уже почитал, разобрался. Твой пример, кстати, не очень универсален

function O1(){
  this.v1 = [];
}

O2.prototype = Object.create(O1.prototype);
O2.prototype.constructor = O2;
function O2(){
  O1.call();
  this.v2;
}
makoven ★★★★★
() автор топика
Ответ на: комментарий от makoven

Да я уже почитал, разобрался

Судя по твоим «вопросам», ты еще долго будешь «читать и разбираться»

function O1(){
  this.v1 = [];
}

O2.prototype = Object.create(O1.prototype);
O2.prototype.constructor = O2;
function O2(){
  O1.call();
  this.v2;
}

Это что вообще за бредятина? Ты хоть что тут пытаешься сделать то?

quest2017
()
Ответ на: комментарий от quest2017

Да забей. Сутки без сна дают о себе знать )

Да, это. Только в реальном коде у O1 в прототипе много функций и конструктор O1 хочет, чтобы его вызвыали с параметрами из конструктора O2 (a'la super(args) из Джавы). Поэтому Object.create(O1.prototype) и O1.call(this)

makoven ★★★★★
() автор топика
Ответ на: комментарий от makoven

O1 в прототипе много функций

если тебе нужны индивидуальные поля для каждого экземпляра, тебе вообще не нужны прототипы. Не используй их, тебе нужно копирование. А что касается конструкторов с параметрами, то это делается


MyFu.apply(this, [arg1, arg2 ...])
MyFu.call(this, arg1, arg2 ...)

quest2017
()
Ответ на: комментарий от quest2017

call или apply, вызванные в скопе конструктора O2 и так уже создают поле v1 в объекте, конструируемом из O2. Так что дополнительно копировать ничего не нужно

makoven ★★★★★
() автор топика
Ответ на: комментарий от makoven

Так это и есть копирование, я про это и говорю. И конструктор тут не при чем, они создают поля в том объекте, к которому применяются, будь то конструктор, х*ктор, что бы то ни было, это не важно.

quest2017
()
Ответ на: комментарий от quest2017

к которому применяются

который принимают в качестве первого параметра, точней

//fixed

quest2017
()
//первый класс
function O1(a) {
  this.v1 = [a];
}
O1.prototype.f1 = function() {};

//второй класс
function O2(a, b) {
  this.superclass.constructor.apply(this, arguments);
  this.v2 = [b];
}
O2.prototype = Object.create(O1.prototype);
O2.prototype.constructor = O2;
O2.prototype.superclass = O1.prototype;
O2.prototype.f2 = function() {};

//поехали
var o1 = new O1(1),
    foo = new O2(2,3),
    bar = new O2(4,5);

console.dir(o1.v1[0]);  //1
console.dir(o1.v2);     //undefined
console.dir(foo.v1[0]); //2
console.dir(foo.v2[0]); //3
console.dir(bar.v1[0]); //4
console.dir(bar.v2[0]); //5

console.dir(o1.f1);  //func...
console.dir(o1.f2);  //undefined
console.dir(foo.f1); //func...
console.dir(foo.f2); //func...

Если лень все это писать есть coffee.

class O1
  constructor: (a)->
    @v1 = [a]

  f1: ->

class O2 extends O1
  constructor: (a, b)->
    super
    @v2 = [b]

  f2: ->

special-k ★★★
()

this is all about 'this'

Ну во первых:

console.log(bar.hasOwnProperty('v2')); //true
console.log(bar.hasOwnProperty('v1')); //false
console.log(bar.__proto__.__proto__.v1 === O1.prototype.v1); //true
Т.е. если нужны уникальные свойства - то нефиг использовать делегированные. Можно было что то вроде такого:
function O1(){
  this.v1 = function () {
   return this.v1 = [];
   }     
}
function O2(){
  this.v2 = [];
}
O2.prototype = new O1();
var foo = new O2();
var bar = new O2();

foo.v1().push("CHANGE for foo");
bar.v1().push("CHANGE for bar");

console.dir(foo.v1); // [ 'CHANGE for foo' ]
console.dir(bar.v1); // [ 'CHANGE for bar' ]
Но это довольно бредово.

invokercd ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.