Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Тонкости создания прототипов (https://javascript.ru/forum/misc/63521-tonkosti-sozdaniya-prototipov.html)

pomidor_makaronus 12.06.2016 22:42

Тонкости создания прототипов
 
Друзья, подскажите, почему этот вариант прототипа не делает доступной функцию getTags, а тот который закомментирован - да?
function Element(){

			if( typeof Element.getTags !== "function"){
				//Element.prototype.getTags = function( elem ){ console.log( elem );}

				Element.prototype = {
					constructor: Element,
					getTags : function( elem ){ console.log( elem );}

				}
			}
		}
 	
		var el  = new Element();
		el.getTags();

Яростный Меч 13.06.2016 00:42

к моменту выполнения кода внутри функции Element() у создаваемого объекта уже установлен старый прототип. Закомментированный код добавляет функцию в этот прототип, а нерабочий вариант просто заменяет Element.prototype, что никак не сказывается на прототипе объекта - он остается прежним.

pomidor_makaronus 13.06.2016 02:06

Cпасибо! звучит логично, но вот в книге Фленагана, алгоритм создания
нового объекта, как-то не похож:

Для создания экземпляров Person используется оператор new. В результате выполняются
четыре действия:
1. Создание объекта.
2. Назначение нового объекта переменной t h i s конструктора (после чего t h i s
указывает н а новый объект).
3. Выполнение кода внутри конструктора (добавление свойств к новому объекту).
4. Возвращение нового объекта.

Пытаюсь сопоставить ваш ответ с этим алгоритмом и напрашивается только один ответ: ссылка на прототип объекта возвращается вновь созданному объекту раньше чем происходит его инициализация! Пожалуйста дайте ссылку на материал, где можно это уточнить. Дело в том что пункты 3 и 4 очень уж смущают

aklis 13.06.2016 02:29

Ну в этом алгоритме про прототипы ничего не вижу.

aklis 13.06.2016 02:38

мне кажется или когда Element работает в режиме конструктора код ТС просто игнорируется? Я имею в виду что если исполнить снаружи функции, код меняющий прототип, то работать он таки будет.

aklis 13.06.2016 02:41

function Element(){
 
            if( typeof Element.getTags !== "function"){
                //Element.prototype.getTags = function( elem ){ console.log( elem );}
                Element.prototype = {
                    constructor: Element,
                    getTags : function( elem ){ console.log( elem );}
                }
            }
        }
        Element(); // или просто вызвать ее как обычную функцию, чтобы записать прототип
        var el  = new Element();
        el.getTags();

Уже размышляю насчет поспать, так что не проверял как это работает, все это просто мои мысли из разряда "а что если..." . Всем неспящим до завтра ;)

aklis 13.06.2016 10:49

Проверил, и правда так работает. Видимо конструктор работает в особом режиме, в котором код ТС игнорируется. Я вроде где-то про это читал (про особый режим работы конструкторов), не помню где только.

pomidor_makaronus 13.06.2016 11:24

Что такое код TC, что-то не могу расшифровать абривиатуру?
Мне кажется не то чтобы код игнорировался просто: получается что когда
выполняется строчка
var el  = new Element();

первым делом объект var el получает ссылку на прототип, а уже потом запускается алгоритм Фланагана?... И инфу не могу найти. Может чего не дочитал еще... Товарищи делитесь соображениями.

aklis 13.06.2016 11:35

ТС - topic starter.

var el - это переменная, тобишь именованная область памяти, куда мы записываем данные - это не сам объект. Ей присваивается ссылка на уже готовый объект.

Яростный Меч 13.06.2016 11:36

Цитата:

Сообщение от pomidor_makaronus (Сообщение 419238)
Мне кажется не то чтобы код игнорировался просто: получается что когда
выполняется строчка
var el  = new Element();

первым делом объект var el получает ссылку на прототип, а уже потом запускается алгоритм Фланагана?....

Это происходит в п.1 алгоритма

pomidor_makaronus 13.06.2016 11:36

прошу прощения алгоритм описывается в книге Николаса Закаса: JavaScript для профессиональных веб-разработчиков.

aklis 13.06.2016 11:39

var a = {
c:1,
a:3
}
var b = a;

b.c = 0;
alert(a.c);


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

Яростный Меч 13.06.2016 11:39

Точнее, в том первом пункте создаётся пустой объект и ему присваивается прототип. А в переменную el это попадает после 4 пункта

aklis 13.06.2016 11:41

Цитата:

Сообщение от Яростный Меч
Точнее, в том первом пункте создаётся пустой объект и ему присваивается прототип. А в переменную el это попадает после 4 пункта

Воот, в переменную попадает ссылка на уже готовый объект.

pomidor_makaronus 13.06.2016 11:41

Цитата:

Сообщение от Яростный Меч (Сообщение 419240)
Это происходит в п.1 алгоритма

Тогда какая разница между 1-м и 4 пунктом?

aklis 13.06.2016 11:47

1 {} - создание объекта, свойств нет.
2 this конструктора равен этому обьекту.
3 выполняем код конструктора к примеру this.a = 0 ;
в результате наш обьект уже не пуст {a:0};
4 конструктор завершает работу, и мы наконец передаем ссылку на него в переменную.

Както так, незнаю уж насколько понятно изложил.

pomidor_makaronus 13.06.2016 11:49

Спасибо врубился т.е под созданием объекта (п. 1) подразумевается наполнение его стандартными свойствами javascript в том числе и свойством prototype вместе с его значением на момент создания объекта. А (п. 4) подразумевает просто присвоение переменной el ссылки на
этот объект!?

aklis 13.06.2016 11:52

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

pomidor_makaronus 13.06.2016 11:53

Спасибо aklis,
Яростный Меч! Вы мне очень помогли.

pomidor_makaronus 13.06.2016 12:39

Ой, ссори поспешил. Все равно не пойму: Вот я
1. создал объект
2. дал ему ссылку на прототип
3. выполнил код внутри функции Element которая перезаписала ссылку на
прототип, причем до обращения к этому объекту извне.
4. вернул ссылку на Element переменной var el
Т.е. основной вопрос попрежнему остается почему у меня нет доступа к
этому прототипу ?

aklis 13.06.2016 12:58

Я ж говорю не исполняется код этот в режиме конструктора.
Обратите внимание на сообщение номер 6 этой темы. Строка 11. Если вызвать этот конструктор как обычную функцию, до того как используем Element как конструктор, тогда все сработает. Но в режиме конструктора весь ваш код из Element игнорируется. Честно говоря Element вообще не конструктор, она не назначает свойств объекту.

pomidor_makaronus 13.06.2016 13:05

Кажется понял ответ как всегда на следующей странице):
Хотя свойства и методы, добавленные в прототип, немедленно становятся доступны
во всех экземплярах объектов, при перезаписи всего прототипа наблюдается другое
поведение. Указатель [[ Prototype ]] задается при вызове конструктора, поэтому
изменение прототипа на другой объект нарушает связь между конструктором
и оригинальным прототипом. П омните, у экземпляра есть указатель только на
прототип, но не на конструктор. Рассмотрим следующий пример:

function Person ( ) {
}
var friend = new Person() ;
Person . p rototype = {
constructor : Person ,
name : "Nicholas" ,
age : 2 9 ,
job : " Software Engineer " ,
sayName : function(){
alert ( this.name ) ;
}
} ;
friend.sayName();// ошибка


После этого попробовал
var el = new Element();
			el = new Element();
			el.getTags("div");

Теперь понял эту тонкость. что кстати подтверждает 6-е сообщение. Спасибо!

aklis 13.06.2016 13:05

А нет, попробовал - не игнорируется код. Надо думать тогда.

aklis 13.06.2016 13:08

Вот оно что :)

pomidor_makaronus 13.06.2016 13:11

Просто получается, что перезапись происходит не у __proto__ который взял ссылку у prototype на момент первого создания
а именно у свойства prototype функции Element.

aklis 13.06.2016 13:17

Я кстати разницу так до конца и не понял между __proto__ и prototype.

Вроде как __proto__ это конкретно свойство уже существующего объекта, а prototype это свойство конструктора которое влияет на __proto__ в будущем созданных объектов?

pomidor_makaronus 13.06.2016 13:20

Да я мыслю его также. теперь просто стало понятнее как оно инициализируется.

pomidor_makaronus 13.06.2016 13:29

Цитата:

Сообщение от aklis (Сообщение 419258)
Честно говоря Element вообще не конструктор, она не назначает свойств объекту.

Полностью с этим согласен. никаких this нету.
Да уместнее говорить не о prototype конструктора, а о prototype функции
Element

pomidor_makaronus 13.06.2016 13:41

А вот и картинка поясняющая этот момент Здесь [[ Prototype ]] означает __proto__:

aklis 13.06.2016 14:09

Цитата:

Сообщение от pomidor_makaronus
Здесь [[ Prototype ]] означает __proto__:

В спецификации так же.

pomidor_makaronus 13.06.2016 14:11

Цитата:

Сообщение от aklis (Сообщение 419268)
В спецификации так же.

Это я на всякий случай может кто еще тему поднимет.


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