Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Вопрос о наследовании (https://javascript.ru/forum/misc/51980-vopros-o-nasledovanii.html)

javacrypt 28.11.2014 16:02

Вопрос о наследовании
 
Изучаю js, пытаюсь понять наследование.
function Product(name) {
	this.name = name;
}
	
Product.prototype = {
	getName: function() {
		return this.name;
	}
}

function Apple(name) {
	Product.call(this, name);
}
       
extend(Apple.prototype, Product.prototype);
	
function extend(child, parent) {
	for (var i in parent) { 
		child[i] = parent[i]; 
	}
}

var apple = new Apple("яблоко");
console.log(apple.getName());


Что плохого в использовании extend? То, что это копирование метода из одного прототипа в другой? То есть скопированный метод getName будет ссылаться не на Product.prototype, а на Apple.prototype? В этом проблема или в чём? Поясните, плз.

Erolast 28.11.2014 17:08

Проблема в том, что это копирование, а не наследование. Это разные вещи. Если в Apple.prototype и Product.prototype будут одноименные методы, копирование перезапишет метод ребенка методом предка, наследование - нет. Наследование реализуется так:
function extend(Child, Parent) {
  Child.prototype = Object.create(Parent.prototype, {
    constructor: {
      value: Child,
      enumerable: false,
      writable: true,
      configurable: true
    }
  });
};

То есть, в итоге должно получиться, что (new Child()).__proto__.__proto__ == (new Parent()).__proto__

krutoy 28.11.2014 17:34

Твой вариант будет работать, но он кривой:) надо хотя бы так
function Product() {}

Product.prototype = {
    getName: function() {
        return this.name;
    }
}
 
function Apple(name) {
    this.name=name
}

Apple.prototype=Object.create(Product.prototype)
        
var apple = new Apple("apple");
alert(apple.getName());

Но лучше восстановить связи:
function Product() {}

Product.prototype.getName=function() {
        return this.name;
    }
 
function Apple(name) {
    this.name=name
}

Apple.prototype=Object.create(Product.prototype)
Apple.prototype.constructor=Apple
        
var apple = new Apple("apple");
alert(apple.getName())
alert(apple.constructor);

Тут, собчтвенно, класс product вообще не нужен. Ну ладно, пусть будет:)
По сабжу. В копировании плохо то, что оно засирает память, и, в некотором смысле, нарушает модульность.

tsigel 28.11.2014 17:42

krutoy,
Опять забыл восстановить ребенку ссылку на его конструктор. Ну и вариант от Erolast ничем не кривой.

Еще в копировании плохо то что мы не сможем проверять принадлежность к классу через instaceof

krutoy 28.11.2014 17:53

Цитата:

Сообщение от tsigel
Ну и вариант от Erolast ничем не кривой.

Я про вариант ТС'а говорил. Он тоже рабочий, в принципе. но кривоватый, да:)

krutoy 28.11.2014 18:01

tsigel,
Кстати, вариант того клоуна тоже крив, потому что он избыточен. Вся эта параша, которую он подает вторым параметром Object.create -- не нужна. А пишет эту всю парашу поциэнт, потому что он джаваскрипт не понимает, а этот говнопаттерн где-то увидел и копирует бездумно. Из песни слов не выкинешь, боится клоун, что-то изменить, боится, что-нибудь сломается в коде.:)

javacrypt 28.11.2014 18:05

То есть выходит, что все экземпляры "класса" Apple будут иметь свой личный метод getName, в то время как если наследовать через прототип все экземпляры будут ссылаться на один и тот же прототип . Теперь стало понятно. Спасибо всем

tsigel 28.11.2014 18:05

krutoy,
Вторым аргументом он восстанавливает ссылку на конструктор.

krutoy 28.11.2014 18:12

javacrypt,
Кстати, можно и изящней написать, с сахарком:)
function Product() {}
Object.defineProperty(Product.prototype, "name", {get: function(){return this.name_}})
 
function Apple(name) {
    this.name_=name
}
Apple.prototype=Object.create(Product.prototype)
Apple.prototype.constructor=Apple
        
var apple = new Apple("apple");
alert(apple.name)

krutoy 28.11.2014 18:15

Цитата:

Сообщение от tsigel
Вторым аргументом он восстанавливает ссылку на конструктор.

чтобы это сделать, достаточно
Apple.prototype.constructor=Apple

А он написал невнятную, нечитаемую, и непонятно зачем нужную парашу.

tsigel 28.11.2014 18:19

krutoy,
Он написал код описаный в стандартах и спецификациях языка. Конечно дескрипторы мало имеют аналогов в других языках программирования и в связи с этим многие их не любят. Но люди которые позиционируют себя как JavaScript программисты должны знать о них и для них эта конструкция будет вполне понятна, лаконична и обычна.

krutoy 28.11.2014 18:20

Цитата:

Сообщение от javacrypt
То есть выходит, что все экземпляры "класса" Apple будут иметь свой личный метод getName

Не, не совсем. Свой личный они имели бы, если бы ты написал
Apple=function(name){
   this.name=name
   this.getName=function(){...}
}

А так -- он был бы вс равно общий, разница в том, наследуется ли он от своего класса, или от суперкласса.

krutoy 28.11.2014 18:22

tsigel,
Я не имею ничего против дескрипторов, только там, где они нужны. А где не нужны -- там не нужны, все просто. Он преопределят то, что и так уже есть, это тупость.

javacrypt 28.11.2014 18:34

Цитата:

Сообщение от krutoy
Не, не совсем. Свой личный они имели бы, если бы ты написал

Цитата:

Сообщение от krutoy
А так -- он был бы вс равно общий, разница в том, наследуется ли он от своего класса, или от суперкласса.

А чем тогда засоряется память? Не улавливаю.

krutoy 28.11.2014 18:36

Цитата:

Сообщение от javacrypt
А чем тогда засоряется память? Не улавливаю.

Ну, у тебя же может быть не один дочерний класс Product. Все дочерни классы, типа Apple будут дублировать прототип Product. А если он один, то в суперклассе Product смысла вобще нет.

krutoy 28.11.2014 18:44

javacrypt,
В твоем коде, как-бы предполагается, что метод getName, будут иметь не только экзмпляры класса Аpple, но и экземземпляры классов Grape, Cherry, Cranberies и тп

javacrypt 28.11.2014 18:49

Перефразирую себя:
выходит, что все экземпляры "класса" Apple будут дублировать метод getName у себя в прототипе, вместо того, что брать его по ссылке из Product.prototype? Так?
Класс Product - абстрактный, у него не будет экземпляров. Все категории продуктов будут иметь общие методы унаследованные от него.

krutoy 28.11.2014 18:54

Цитата:

Сообщение от javacrypt
будут дублировать метод getName у себя в прототипе

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

Сообщение от javacrypt
Класс Product - абстрактный, у него не будет экземпляров.

Ну, я имею в виду, что категории продуктов, как классы, наследуют от него, да.

Erolast 28.11.2014 19:01

Цитата:

То есть выходит, что все экземпляры "класса" Apple будут иметь свой личный метод getName, в то время как если наследовать через прототип все экземпляры будут ссылаться на один и тот же прототип . Теперь стало понятно.
Нет, в JS копируются не объекты, а ссылки на них, то есть, дублироваться будут ссылки, а не методы (функции - тоже объекты). Засорения памяти как раз не произойдет. Дело в том, что копирование и наследование - это разные концепции, я же говорил:
Цитата:

Сообщение от Erolast
Если в Apple.prototype и Product.prototype будут одноименные методы, копирование перезапишет метод ребенка методом предка, наследование - нет.

И лучше не слушать крутого, он долбоёб тролль, обрати внимание на карму.

krutoy 28.11.2014 19:09

javacrypt,
Тот дегенерат, который отписался выше, слабо представляет какой понос он выблевывает. Естественно, в js ничего вообще не копируетя, все создается и наполняется ссылками. Но это н значит, что объект с тысячью ссылок весит столько же, сколько пустой объект. А если бы было так, LOL, программы на JS вобще не потребляли бы память, на*й она нужна, ведь все что у нас есть -- объекты со ссылками. Зацени масштаб бредятины, ты в желтом доме такого не услышишь, цени момент:)

javacrypt 28.11.2014 19:26

Теперь я кажется понял. Совсем забыл про ссылки на объекты в js. Спасибо. Я вас понял обоих.

nerv_ 28.11.2014 22:56

Erolast, krutoy,
1. мне надо вызвать конструктор родительского класса - как?
2. мне надо вызвать супер метод - как?
:)

krutoy 28.11.2014 23:49

nerv_,
В чем проблема? Ты не можешь вызвать функцию?
проще всего так
function Super(){alert("Hello!")}
function F(){}
F.prototype=Object.create(Super.prototype)
F.prototype.constructor=F
o=new F

o.__proto__.__proto__.constructor()

я думаю.

krutoy 29.11.2014 00:02

Цитата:

Сообщение от nerv_
мне надо вызвать супер метод - как?

А суперметод ты вообще вызываешь обычно, он же наследуется
childObject.supermethod()

danik.js 29.11.2014 06:39

Цитата:

Сообщение от krutoy
А суперметод ты вообще вызываешь обычно, он же наследуется

А если ты его перекрыл своим?

krutoy 29.11.2014 07:32

Цитата:

Сообщение от danik.js
А если ты его перекрыл своим?

function Super(){alert("Hello!")}
Super.prototype.onceAgain=function(){alert("Hello again!!!")}
function F(){}
F.prototype=Object.create(Super.prototype)
F.prototype.constructor=F
F.prototype.onceAgain=function(){alert(2)}
o=new F
o.onceAgain=function(){alert(1)}

o.onceAgain()
o.__proto__.onceAgain()
o.constructor.prototype.onceAgain()

o.__proto__.__proto__.onceAgain()
o.__proto__.__proto__.constructor.prototype.onceAgain()

Erolast 29.11.2014 08:16

Цитата:

Сообщение от nerv_ (Сообщение 343360)
Erolast, krutoy,
1. мне надо вызвать конструктор родительского класса - как?
2. мне надо вызвать супер метод - как?
:)

Есть три варианта:
  1. В функции extend устанавливать ребенку в свойство ссылку на родителя.
    function extend(Child, Parent) {
      ...
      Child.Parent = Parent;
    }
    
  2. Добираться до родительского класса через .prototype.__proto__ ребенка или __proto__.__proto__ инстанса ребенка. Можно оформить в функцию:
    function getParent(Class) {
      return Class.prototype.__proto__;
    }
    
  3. Не париться и использовать ES6, в котором внутри методов класса доступно ключевое слово super, ссылающееся на родительский класс. Лучший вариант, если хочется нормального ООП.

nerv_ 29.11.2014 12:33

Erolast, за неимением ES6 в браузере, тебе не кажется, что будет логичным всегда устанавливать ссылку на супер-класс?

Давайте не будем изобретать велосипедов, а просто использовать node.js inherits, благо она кросс-платформенная (клиент/сервер).
http://javascript.ru/forum/misc/5188...tml#post342727

krutoy, то, что ты пишешь, вообще ад :)

Erolast 29.11.2014 13:10

Цитата:

Erolast, за неимением ES6 в браузере, тебе не кажется, что будет логичным всегда устанавливать ссылку на супер-класс?
Не кажется. Компиляторы пошто? Тык, тык, тык.


Часовой пояс GMT +3, время: 17:47.