Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   JavaScript Классическое наследование (https://javascript.ru/forum/misc/4652-javascript-klassicheskoe-nasledovanie.html)

zzz 11.08.2009 10:37

JavaScript Классическое наследование
 
Этот день настал... Впервые за 2 месяца обучения я вижу код на JavaScript который не понял после тщательного разбора каждой строки, не понял вообще как он работает. Это функции созданные для имитации классического наследования. Что такое классическое наследование я вроде знаю их PhP это когда создатся класс и обьекты созданые этим классом наследуют его свойства и методы.
Вот код, сообщения типо код отстойный надо поправить (хотя вратли так кто-нибудь скажет ведь это код самого Дугласа Крокфорда (сообщение чё эт за тип тоже не писать)) постить не надо. Даже если есть код в 100 раз легче но с таким же результатом мне пофиг. Так как мне надо именно разобратся в этом коду.
//Простой вспомогательный метод, метод позволяющий привязать новую функцию к прототипу обьекта
Function.prototype.method = function(name, func) {
	this.prototype[name]=func;
	return this;
	};
//Довольно сложная функция, позволяющая весьма изящно наследовать функции обьектов и сохранять возможность вызова функции "родительского окнаЭ обьекта
Function.method("inherits", function(parent) {
	//Отслеживание, на каком уровне глубины в родительских функциях мы находимся
	var depth=0;
	var proto = this.parent = new parent();
	//Создание новой "привилегированной" функции под названием "uber", которая при вызове выполняет любую функцию вписанную в наследование
	this.method("uber", function uber(name) {
		var func;//Исполняемая функция
		var ret;//Возвращение значения функции
		var v = parent.prototype;//родительский прототип
		//Если мы уже находимся внутри другой функции "uber"
		if(depth){
		    //Спуск на необходимую глубину для поиска исходного прототипа
			for(var i=d; i > 0; i+= 1) {
				v = v.constructor.prototype;
				}
				//И получение функции из прототипа
	        func=v[name];
	        //А если это первый вызов "uber"
	     } else {
	     //Переход вместо этого к родительскому прототипу
	        func=proto[name];     
	        //Если функция была частью этого прототипа
	        if(func==this[name]) {  
	          //Переход вместо этого к родительскому прототипу
	          func=v[name];
	          }
	       }
	       //Отслеживание глубины. На которой мы находимся в стеке наследования
	       depth +=1;
	       //Вызов исполняемой функции со всеми аргументми, кроме первого (в котором хранится имя исполняемой функции)
	      ret = func.apply(this. Array.prototype.slice.apply(arguments, [1]));
	      //Сброс глубины стека
	      depth -=1;
	      //Возвращение значения, возвращаемого исполняемой функцией
	      return ret;
	      });
	      return this;
	      });

Привожу с комментами из книги(они мне не оч помогли) Если есть возможность то можно обьяснить через аську. Помимио общего вопрос как это работает есть пара вопрос с синтаксической точки зрения (зря курил)
Function.prototype.method = function(name, func) {

Function.prototype.method это название функции? Если да то оно что-нибудь значит или просто названо так для удобства.

//Отслеживание, на каком уровне глубины в родительских функциях мы находимся
Что ещё за глубина?

var proto = this.parent = new parent();
Что за парент? Вообще когда одна функция наследует метода обьекта (или наоборот(поправте как правильно)) что является родителем и связано это как-то с передаваемым параметром функции
function(parent) {


if(depth){
Что за Если depth то есть если depth что. Звучит как например Если Вася а должно например Если Вася==1 Если Вася существует

И можно поподробней про метод Apply (ответ что метод Apply похож на call не писать(про него тоже можно расказать)).
Вроде всё.

Riim 11.08.2009 10:49

Первое что попалось на глаза это inhertis вместо inherits. Смотрю дальше, вроде что-то интересное.

zzz 11.08.2009 10:51

Цитата:

Сообщение от Riim (Сообщение 26443)
Первое что попалось на глаза это inhertis вместо inherits. Смотрю дальше, вроде что-то интересное.

подправил.

Kolyaj 11.08.2009 10:59

Цитата:

Сообщение от zzz
Function.prototype.method это название функции?

Цитата:

Сообщение от zzz
Что за Если depth то есть если depth что.

Цитата:

Сообщение от zzz
И можно поподробней про метод Apply

Рановато вы за наследование взялись, тут местами не то что основы JavaScript, а основы программирования.

http://javascript.ru/tutorial/object это читали?

zzz 11.08.2009 11:01

Цитата:

Сообщение от Kolyaj (Сообщение 26445)
Рановато вы за наследование взялись, тут местами не то что основы JavaScript, а основы программирования.

http://javascript.ru/tutorial/object это читали?

Именно эту статью не читал но про объекты и ООП читал

Riim 11.08.2009 11:05

После радости от конструкции:
Function.prototype.method = function(name, func) {
    this.prototype[name] = func;
    return this;
};
Function.method("inherits", function(parent) {/*...*/});


сразу пришел в ужас от: var proto = this.parent = new parent();
Либо это что-то очень гениальное, либо книгу пора выкидывать.

zzz 11.08.2009 11:11

Код написан Дугласом Крокфордом создателем библеотеки JSON как замену XML
Дуглас Крокфорд. это главный архитектор по JavaScript в Yahoo. но и без этого, имно, ему можно ставить памятник уже за один только вот этот кусок кода:

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

его сайт http://javascript.crockford.com/
Так что скорее гениальное)

Прочитал что...
В javascript нельзя проверить существование глобальной переменной простым if:

if (x) { ... }


Если x не определен, то конструкция if (x) вызовет ошибку javascript.

Так почему работает
if(depth){

Kolyaj 11.08.2009 11:18

Цитата:

Сообщение от zzz
Так почему работает

if(depth){

потому что depth существующая локальная переменная.

Цитата:

Сообщение от Riim
сразу пришел в ужас от: var proto = this.parent = new parent();
Либо это что-то очень гениальное, либо книгу пора выкидывать.

А что тут не так?

zzz 11.08.2009 11:20

Цитата:

Сообщение от Kolyaj
if(depth){

Ещё вопрос как она может не существовать если она указана в родительской функции?

Riim 11.08.2009 11:21

Цитата:

Сообщение от zzz
ему можно ставить памятник уже за один только вот этот кусок кода

Приписывать здесь кому-либо авторство не совсем правильно, но если уж кто и автор, то это создатели javascript-а, но никак не архитектор из Yahoo.

zzz 11.08.2009 11:23

Цитата:

Сообщение от Riim (Сообщение 26458)
Приписывать здесь кому-либо авторство не совсем правильно, но если уж кто и автор, то это создатели javascript-а, но никак не архитектор из Yahoo.

А он и есть один из создателей ЯваСкрипта

Riim 11.08.2009 11:42

Цитата:

Сообщение от zzz
А он и есть один из создателей ЯваСкрипта

И он концепцию прототипирования продумывал?

zzz 11.08.2009 11:43

Цитата:

Сообщение от Riim (Сообщение 26462)
И он концепцию прототипирования продумывал?

Кто там конкретно что придумывал я не знаю

Kolyaj 11.08.2009 11:43

Цитата:

Сообщение от zzz
Ещё вопрос как она может не существовать если она указана в родительской функции?

А кто говорил, что она может не существовать?

zzz 11.08.2009 11:43

Цитата:

Сообщение от Kolyaj (Сообщение 26464)
А кто говорил, что она может не существовать?

А зачем тогда проверка?

Riim 11.08.2009 11:48

Цитата:

Сообщение от zzz
Кто там конкретно что придумывал я не знаю

Тогда не нужно и авторство всем подряд лепить.

Riim 11.08.2009 12:00

Вот здесь:
ret = func.apply(this.Array.prototype.slice.apply(arguments, [1]));


this лишний, должно быть так:
ret = func.apply(Array.prototype.slice.apply(arguments, [1]));


this ссылается на экземпляр дочернего класса, а не на window.

Kolyaj 11.08.2009 12:00

Цитата:

Сообщение от zzz
А зачем тогда проверка?

Ну так попробуйте, браузер-то у вас есть наверно.
var a = 0;
if (a) {
    alert(1);
}

zzz 11.08.2009 12:02

Цитата:

Сообщение от Riim (Сообщение 26470)
Вот здесь:
ret = func.apply(this.Array.prototype.slice.apply(arguments, [1]));


this лишний, должно быть так:
ret = func.apply(Array.prototype.slice.apply(arguments, [1]));


this ссылается на экземпляр дочернего класса, а не на window.

Ну давайте тягатся с создателми языка. И решать что там лишнее а что нет

zzz 11.08.2009 12:03

Цитата:

Сообщение от Kolyaj (Сообщение 26471)
Ну так попробуйте, браузер-то у вас есть наверно.
var a = 0;
if (a) {
    alert(1);
}

Да но там ещё есть оператор else получается он некогда не сработает?

Kolyaj 11.08.2009 12:09

Цитата:

Сообщение от zzz
Да но там ещё есть оператор else получается он некогда не сработает?

Ну уж не знаю, это не мой код, а Дугласа наше все Крокфорда :)

Riim 11.08.2009 12:11

Цитата:

Сообщение от zzz
Ну давайте тягатся с создателми языка. И решать что там лишнее а что нет

this ссылается на экземпляр дочернего класса, а не на window. В экземпляре дочернего класса метод Array не определялся.

zzz 11.08.2009 12:14

Зайдя на сайт Крокфорда я нашёл такой код
Function.method('inherits', function (parent) {
    var d = {}, p = (this.prototype = new parent());
    this.method('uber', function uber(name) {
        if (!(name in d)) {
            d[name] = 0;
        }        
        var f, r, t = d[name], v = parent.prototype;
        if (t) {
            while (t) {
                v = v.constructor.prototype;
                t -= 1;
            }
            f = v[name];
        } else {
            f = p[name];
            if (f == this[name]) {
                f = v[name];
            }
        }
        d[name] += 1;
        r = f.apply(this, Array.prototype.slice.apply(arguments, [1]));
        d[name] -= 1;
        return r;
    });
    return this;
});

А тот код я взял не из книги Крокфорда а из книги Джона Рейсига может он там курнул и решил его подкоректировать. Как вам этот код?

Riim 11.08.2009 12:20

Цитата:

Сообщение от zzz
Как вам этот код?

Так лучше.

zzz 11.08.2009 12:22

Не знаю бывало с вами такое вроде смутно понимаю как это работает. Как будто ответ где-то рядом но найти не могу.
может постваите комменты к коду мне в помощь?

zzz 11.08.2009 12:55

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

Riim 11.08.2009 13:44

Цитата:

Сообщение от zzz
Зайдя на сайт Крокфорда я нашёл такой код

Дай ссылку на страницу где этот код.

zzz 11.08.2009 13:53

http://javascript.crockford.com/inheritance.html

Riim 11.08.2009 14:04

Цитата:


I have been writing JavaScript for 8 years now, and I have never once found need to use an uber function. The super idea is fairly important in the classical pattern, but it appears to be unnecessary in the prototypal and functional patterns. I now see my early attempts to support the classical model in JavaScript as a mistake.

Я плохо понимаю английский, но вроде он признался, что все это ошибка.

zzz 11.08.2009 14:13

И всё таки мне интересно как работает этот код моно коменты к нему?

Kolyaj 11.08.2009 14:27

Классическое наследование в JavaScript невозможно, а эмуляция его вредна.

Цитата:

Сообщение от zzz
И всё таки мне интересно как работает этот код моно коменты к нему?

А что непонятно-то?

zzz 11.08.2009 14:29

Непонятно как код вообще работает. Если вам понятно то раскажите пожалуйста

Kolyaj 11.08.2009 14:36

Мне непонятно, что вам непонятно, и, соответственно, непонятно, что рассказывать. Если вам непонятно все, то и спрашивайте это все по пунктам.

Riim 11.08.2009 15:00

Необычность в следующем:
У всех классов, что от кого-то наследуют, создается метод uber, который запомнил замыканием ссылку на родителя и его экземпляр. При вызове он получает имя, по которому ищет в запомненном экземпляре нужный метод и вызывает его, передавая все параметры кроме имени.
Нужно это на тот случай если и родительский и дочерний класс будут содержать метод с одинаковым именем, т. е. метод дочернего класса экранирует одноименный метод в родительском классе, а значит вызвать экранированный метод из родителя через this.method() не получится и тут как раз пригодится uber.

В остальном стандартная, криворукая(нынче) реализация наследования, что применялась еще в 90-х. Ее минусы неплохо расписаны в статье, ссылка на которую ниже.


Цитата:

Сообщение от Kolyaj
Цитата:

Сообщение от Riim
сразу пришел в ужас от: var proto = this.parent = new parent();
Либо это что-то очень гениальное, либо книгу пора выкидывать.

А что тут не так?

При наследовании вызывается конструктор родителя. Такого не должно происходить, по крайней мере ни в одном другом языке я такого наследования не видел. Что такое хорошо и что такое плохо, внятно объясняется в этой статье: Решение проблемы холостого вызова функции-конструктора надкласса

zzz, это четвертая часть, точно не помню, но вроде в первых трех есть про call и apply

upd: книгу лучше сжечь.

zzz 11.08.2009 15:06

Цитата:

Сообщение от Kolyaj (Сообщение 26526)
Мне непонятно, что вам непонятно, и, соответственно, непонятно, что рассказывать. Если вам непонятно все, то и спрашивайте это все по пунктам.

Непонятно какой кусок кода что делает. Вот я и прошу поставить комменты.

Kolyaj 11.08.2009 15:09

Цитата:

Сообщение от Riim
При наследовании вызывается конструктор родителя.

А, ну это да.

Kolyaj 11.08.2009 15:10

zzz,
если вам лень задать конкретные вопросы, всем остальным тем более лень комментировать код.

zzz 11.08.2009 15:12

Что значит конкретные вопросы мне что перепесать каждуб строку кода или каждое слова кода и везде поставить вопрос А что это делает??? Повторяю я понимаю что этот код должен сделать но я не понимаю как он это делает.

Riim 11.08.2009 15:13

Цитата:

Сообщение от zzz
я понимаю что этот код должен сделать но я не понимаю как он это делает.

zzz, ты же сам написал, что знаешь основы.

zzz 11.08.2009 15:16

Уффф... как же обьяснить я понимаю все эти операторты, функции, обьекты но я не понимаю как всё это вместе выдаёт такой результат. Это всё равно что знать цифры и буквы но не понимаать как решается ленейное уровнение


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