Pull to refresh

Comments 96

Немного не в тему, но Uncle разве не «дядя», а не «дедушка»? )

Ну и по теме: Для меня особенно ценными стали последние 3 разъяснения, за них особенное «Спасибо»!
Позор мне, непонятно где была моя мысль… Конечно, Дед — это Grandfather. Исправил.
А я все никак не мог понять, почему :)
[u.color, f.color, s.color]
__proto__ — не является стандартом и уже depricated. Не советую использовать.
Поддерживаю. Но множество примеров — в том числе и тут написано с ним — и в итоге многие используют несмотря на все предупреждения.
Автор уже поправил, добавив раздел «Важно» в заключение, просто до этого там был 9 пункт с более скромным упоминание, что __proto__ работает не во всех браузерах.
__proto__ — очень удобно для демонстрации и понимания сути прототипного наследования, тем более в браузерах что-то типа такого и используется. А какой смысл его использовать в реальных приложениях?
«Короткое» прототипное наследование.
3-й блок кода сверху
var p = {x: 10, __proto__: Point};

но так делать плохо ;-)
За this вообще авторов убить мало, назвали бы scope и сразу куча проблем бы отвалилась.

А первый пункт не очень раскрыт, на самом деле. У вас Дедушка (и прочие) означают не конкретную персону, а группу, класс персон. И Дедушка меняет не свой цвет, а цвет своей группы. Это вполне себе можно и в ООП-модели осуществить, нужно лишь изменить класс Дедушка изнутри объекта (о правомерности этого отдельно можно говорить).
здесь опечатка var bar = foo.bar();
должно быть var bar = foo.bar;
Может, я что-то пропустил, но почему после очередного изменения «Деда»

// Смысла нет
Grandfather.prototype.color = 'blue';
console.log([u.color, f.color, s.color]); // ["blue", "green", "green"]


у потомков не изменились свойства?

Разве мы не должны получить, как в предыдущих случаях
// ["blue", "blue", "blue"]
Перед этим переопределили значение у Father на blue — поэтому Father и его потомок Son видят именно blue и поиск свойства не идёт выше по дереву.
Дело в том, что Отец изменил свой прототип (Father.prototype.color = 'green';), а поиск свойства color лежит сперва через прототип отца. Вот так выглядит объект f:
f = {
    __proto__: { // Прототип Father
        color: 'green', // Отец решил вернуть цвет
        __proto__: { // Прототип Grandfather
            color: 'blue', // Дед решил поменять на синий 
            __proto__: Object.prototype
        }
    }
}

При выполнении f.color сначала произойдет поиск в собственных свойствах (не найдено), затем алгоритм будет искать в f.__proto__ — найдено! (color: 'green'). Вобщем до прототипа деда и не дойдет.
Если же отец удалит цвет из своего прототипа, то все опять «телепатически» посинеют, кроме сына у которого есть собственное свойство color.
// Отец решил все вернуть для себя и своего потомства
Father.prototype.color = 'green';
// Хотя мог исделать и так:
// Grandfather.prototype.color = 'green';

console.log([u.color, f.color, s.color]); // ["blue", "green", "green"]


Мне не совсем понятна часть выделенная жирным. Мне кажется, что если бы была вызвана эта строчка, то на выходе было бы ["green", "green", "green"], даже с учётом того, что цвет деда до этого был изменён на синий Grandfather.prototype.color = 'blue';
Да, все верно, было бы ["green", "green", "green"].
Верно-то оно верно, но согласитесь, что закоментированая строчка вводит в некий конфуз, так как задача всё же стояла изменить свойство для себя и своего потомства, а не приплетать ко всему ещё и старенького и больного дедушку =)
который до этого хотел стать голубым… Боги, что я пишу!
Очень познавательно! Хорошо бы ещё поподробней по поводу — что и в каких случаях получит this: «undefined, null или window(global)»?
P.S. Метафоры конечно кстати. Аля Пелевин.
Почему наследование работает по такой хитрой схеме?:

function inherit (object, parent) {
    function F(){};
    F.prototype = parent.prototype;
    object.prototype = new F();
    return object;
}

Что плохого может случиться, если делать например так?:

object.prototype = parent.prototype;

Или так:

object.prototype = parent;

Почему instanceOf сравнивает obj.__proto__ и constructor.prototype, а не obj.__proto__ и constructor? Из каких соображений выбран такой дизайн?
Потому что если вы напишите object.prototype = parent.prototype, изменения в прототипе потомка будут влиять на свойства родителя. В случае примера с дедушкой, отцом и сыном, если отец изменит свой цвет, то это отразится и на дедушке.
Потому что, создатели Javascript-а недостаточно смелы были, чтоб оставить чистое прототипное наследование и добавили классоподобие.
Поясните пожалуйста момент с:

(foo.bar = foo.bar)(); // this === global (3)
(false || foo.bar)(); // this === global (3)
(foo.bar, foo.bar)(); // this === global (3)

Не понимаю, почему в этом случае this — глобальный объект.
Потому, что правила 1 и 2 применяются если слева стоит ссылка, а не значение. Во всех этих случаях слева — значение. Возможно тут будет понятнее.
Ух! «Неделя» javascript на хабре радует!
void, конечно оператор, но void 0 и void(0) работают одинаково, и при use strict в том числе
> но void 0 и void(0) работают одинаково
Потому, что во втором случае скобки — оператор группировки
Верно Son.prototype.__proto__ === Father.prototype и т.д.
Автор, интересно также, что по поводу других способов создания объектов и наследования между ними? Речь идет о всяких фабриках, клонирований и т.д.

Для чего люди их придумали, и стоит ли овчинка выделки?
Область применение фабрики одинакова во всех ЯП. Обертки с Class и другие создают для упрощения работы и приближения кода JavaScript к коду других ЯП.
TheShock собирался написать статью про паттерны и их применение, не буду спойлить
Объясните, плиз, зачем функцию getProperty необходимо было вызывать именно с указанием контекста (через call)? Просто там this внутри нигде не используется. Или я что-то неправильно понимаю?
А! Там же вызывается print(), которая и содержит вывод переменных через this. То есть, нужно указывать контекст, верно. В общем, моя невнимательность. Прошу прощения )
Код getProperty(p, 'print').call(p). Разберем что тут происходит:
1. getProperty(p, 'print') возвратит функцию (это как сделать var p_print = p.print)
2. Если функцию вызвать напрямую, то мы получим в качестве this — window и ничего не напечатается.
3. Чтобы предотвратить это мы вызываем функцию, которую возвратит getProperty с помощью явного указания this
Не совсем понял полезность этой идеи:
inherit(Father, Grandfather); // Это лучше

Вместо прямого указания, что прототипом конструктора Father, является экземпляр конструктора Grandfather, мы указываем пустой подставной объект. А прототип этого подставного объекта является прототипом конструктора Grandfather. То есть, если убрать подставной объект, получается что-то вроде
Father.prototype = Grandfather.prototype;
, что совсем не эквивалентно
Father.prototype = new Grandfather();
, так как если Grandfather это «самый верхний» объект в дереве, то его прототипом является Object.

Или я что-то не так понял?
В подтверждение следующий код:
function inherit (object, parent) {
    function F(){}; // Подставной конструктор
    F.prototype = parent.prototype; // Подсовываем прототип реального конструктора
    object.prototype = new F(); // Теперь реальный конструктор не будет выполнен
    return object; // Можно и не возвращать
};
function Grandfather() {
    this.color = "red";
}
function Father() {
    this.number = 1;
}
inherit(Father, Grandfather);
father = new Father();
console.log(father.number); // 1
console.log(father.color); // undefined
Если добавить в конструктор одну строку
function Father() {
    Grandfather.call(this); // Вот эту
    this.number = 1;
}

То father получит own property — color. Обычно во всех ЯП если происходит ореррайд метода, то по умолчанию предыдущий метод «не наследуется», пока разработчик не прописал его явно.

Я про это писал
Конструктор Grandfather не будет выполнен. Если нам все-такие необходимо выполнить конструктор Grandfather, то вызываем его с помошью call или appy
var Father = function () { // Конструктор Father
    Grandfather.call(this);    
};
В вашей статье вы об этом не писали. Вы просто показали «более правильный» метод наследования, который, как я показал, не работает. Объект father не унаследовал свойство color, которое біло обїявлено в конструкторе Grandfather.

Кстати, вариант с Grandfather.call(this); в конструкторе тоже имеет недостатки, так как он скопирует методы родителя, вместо того, чтобы унаследовать их через прототип.
Сорри за украинские буквы, все время путаю раскладки на клавиатуре :)
Кстати, вариант с Grandfather.call(this); в конструкторе тоже имеет недостатки, так как он скопирует методы родителя, вместо того, чтобы унаследовать их через прототип.

Вы ошибаетесь. Будет только вызван конструктор родительского объекта. Методы будут унаследованы через прототип.
Вы ошибаетесь. Будет только вызван конструктор родительского объекта. Методы будут унаследованы через прототип.
И снова неправда. И снова кусок кода, в качестве подтверждения моих слов:
// Объект-конструктор "Отец"
function Father() {
    this.returnRed = function() {
      return "red";
    };
}
// Объект конструктор "Сын"
function Son() {
    this.number = 1;
    Father.call(this); // Делаем "наследование" через call
}
// Объект конструктор "Дочь"
function Daughter() {
    this.number = 2;
}
father = new Father(); // Создаем экземпляр отца
Daughter.prototype = father; // Дочь наследует метод отца через прототип
son = new Son(); // Создаем экземпляр сына
daughter = new Daughter(); // Создаем экземпляр дочери

console.log(daughter.returnRed()); // red — метод унаследован
console.log(son.returnRed()); // red — неужели тоже унаследован?

// Изменяем метод в прототипе.
Daughter.prototype.returnRed = function() {
  return "blue"
};
Son.prototype.returnRed = function() {
  return "blue"
};

console.log(daughter.returnRed()); // blue — изменилось корректно
console.log(son.returnRed()); // red — опа! А метод то берется не из прототипа. Он просто скопировался в наш объект.
Вы намешали и прототипы с собственными свойствами. Не пойму чему вы удивляетесь :) son.returnRed() returnRed — own property, очевидно, что до прототипа не дойдет. Вы показываете несуществующие проблемы.
Разве это мой комментарий? Они будут унаследованы через прототип, если в конструкторе нет одноименного метода/свойства. Ваш вышеположенный код — несуществующая проблема. Или проблема для тех, кто не понимает сути прототипного делегирующего наследования.
Мне все больше начинает казаться, что вы меня тонко тролите :)
Упс, почему-то подумал что ваш.
Если бы троллил, то просто написал бы, что это все херня, а я — ромашка :)
Просто интересно поспорить. Если я прав, то смогу что-то доказать. Если неправ — узнаю что-то новое.
Ниразу не тролинг. Я тоже не понимаю этого:
/* SonsSon <- Son <---- Father <- Grandfather <-- Object <-- null */
console.log(ss.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__ === null); 


Если всё так просто, то зачем такое сложное наследование через создание объекта?
Father.prototype. = new Grandfather();


А это не проще ли?
Father.prototype.__proto__ = Grandfather.prototype;

Результатом будет как раз такая последовательность:
ss.__proto__.__proto__.__proto__.__…
В некоторых браузерах свойство __proto__ скрыто. Его дописать можно, но толку от этого не будет. Поэтому создаем цепочку прототипов через new.
function operatorNew (Constructor, args) {
/*1*/  var n = {'__proto__': Constructor.prototype}; // Движок JS в  браузере может переписать [[proto]]
/*2*/  F.apply(n, args);
/*3*/  return n;
}
Это я понимаю. Но зачем его скрыли? Ведь с ним, наследование было бы проще пареной репы! А сейчас для нативного наследования нужно породить объект! Какая логика в такой конструкции: «для наследования необходимо породить объект»? Как надо было обкурится, что бы придумать такое?

Естественно, порождать объекты никому не нравится и появляются костыли типа:
inherit (object, parent)

А затем ещё тонны библиотек для не нативного ООП. Зачем было так усложнять язык закрывая свойство __proto__? При этом prototype оставили открытым и это нормально.
__proto__ изначально было скрыто. Потом кто-то стал его открывать минуя стандарт. В ECMAScript [[Prototype]] — внутреннее свойство. es5.github.com/#x8.6.2 es5.github.com/#x13.2.2 В 6-й версии ECMAScript будет сахар — class (который на самом деле делает не class-ы, а строит цепочку прототипов).
Т.е. я мыслю в правильном направлении и в следующей версии будет то о чём я написал сначала?
Father.prototype.class = Grandfather.prototype;

Или class — это совсем не то?
class Monster extends Character {
  constructor(x, y, name) {
    super(x, y);
    this.name = name;
    this.health_ = 100;
  }

  attack(character) {
    super.attack(character);
  }

  get isAlive() { return this.health > 0; }
  get health() { return this.health_; }
  set health(value) {
    if (value < 0) throw new Error('Health must be non-negative.');
    this.health_ = value;
  }
}

harmony:classes
Фигово, это уже совсем не то. Из отличной локаничной идеи состоящей всего из трёх конструкций («function», «new», «prototype») и при этом позволяющей делать всё что угодно (классы, конструкторы, наследования, примеси и многое другое...); теперь вместо этого будет монстр со всеми этими конструкциями: class, constructor, extends, super, static, public/private, const, get/set.
Потом будут появлятся: interface, abstract, traits.
Вы мало того, что путаетесь в своих примерах, так ещё и обвиняете меня во лжи)))
Наследование через конструктор — это какая-то чужеродная глупость, которую фиг знает кто и зачем придумал.
Father.call(this); // Делаем "наследование" через call

Это ошибка. Мы не делаем наследование, а вызываем родительский конструктор. Я просто перепишу ваш пример на PHP)

class Father {
	function __construct () {
		$this->returnRed = function () {
			return 'red';
		};
	}
}

class Son {
	function __construct () {
		$this->number = 1;
		parent::__construct();
	}
}

Правда странно смотрится? И теперь поняли, что это совсем не наследование? ;)
А теперь как надо было сделать:

class Father {
	function __construct () {
		// Father construct
	}

	function returnRed () {
		return 'red';
	}
}

class Son {
	function __construct () {
		$this->number = 1;
		parent::__construct();
	}
}
А я уже думал что эта ветвь обсуждения исчерпана.
Я прекрасно понимаю, что это не наследование. Это вызов конструктора другого объекта (не называю его родительским, так как наследования нет), с подменой контекста текущим объектом. При этом все свойства/методы не наследуются через прототип, а копируются.
Именно поэтому слово «наследование» я написал в кавычках.
Father.prototype = Grandfather.prototype;
И в итоге все унаследуют от Grandfather
Или я что-то не так понял?
Если в конструкторе Grandfather будет alert или подобное добро, то как вы думаете сработает ли он в Father.prototype = new Grandfather();? ;-)
И в итоге все унаследуют от Grandfather
Нет. В итоге Father унаследует все от прототипа Grandfater, в нашем случае — Object. То есть не унаследует вообще ничего. Это я показал на примере в своем комментарии выше.
Если в конструкторе Grandfather будет alert или подобное добро, то как вы думаете сработает ли он в Father.prototype = new Grandfather();? ;-)
Если вы написали в конструкторе alert, то вы плохой программист. Если вы придерживаетесь следующего правила:
Я предпочитаю основываться на соглашениях и не проверяю this внутри конструктора — вызвал конструктор без new и поэтому утекло в глобалы — значит «сам дурак»
к клиентскому коду, то почему оно не распространяется на код ваших объектов?
Вообще при чем тут это правило?! Алерт я показал для примера. Не важно что там будет alert ещё какой-то метод. Зачем нам их вызывать?

Father.prototype = Grandfather.prototype и получим вот такое «прекрасное наследованние»…
Father = function (){};
Grandfather = function (){};

Grandfather.prototype.pewpew = 1; 
Father.prototype = Grandfather.prototype;

Father.prototype.pewpew = 2;

console.log(new Father().pewpew, new Grandfather().pewpew); // отлично унаследовал! 2, 2

В этом примере вы изменив дочерний объект, изменили и родительский (точнее не объекты-экземпляры, а объекты-прототипы).

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

Вызывать конструктор или нет — должен решать разработчик. Во всех ЯП при оверрайде метода старый метод убивается и только тот, кто переписывает этот метод решает стоит ли его вызывать в новом методе.
Черт, я уже теряюсь в двух ветках комментариев.
На счет конструкторов — согласен. Но все же на ряду со случаями, когда их можно не вызывать есть и случаи когда это действительно стоит сделать.
UFO just landed and posted this here
Во всех языках, основанных на прототипах (Self, JavaScript), ссылка __proto__ скрытая, но Mozilla её отрыла. Использование __proto__ ломает всю концепцию и выглядит странно, поэтому хотят убрать.
Взамен дают Object.isPrototypeOf и Object.getPrototypeOf

Тут проблема описана подробнее: What is the difference between __proto__ and prototype
Только не дают «setPrototypeOf» =))
UFO just landed and posted this here
А на сколько существенны недостатки классического прототипирования в программировании? Нужно побольше памяти, чтоб полностью клонировать объекты, но зато быстрее работать будет. А что касается невозможности делегирования свойств и логики – это было бы неудобным, как думаете?
но зато быстрее работать будет
Например, Хром оптимизирует рыскание по цепочке прототипов и каждый раз прозрачно создает новый объект (вобщем все свойства косвенно own). Раз это кэш, то расходуется дополнительная память, зато снижается время. Сейчас все оптимизации «по времени», так что это нормально (контр оптимизация — «по памяти»).

Плюсы прототипного наследования в том, что «создатель копии может менять её, не опасаясь побочных эффектов среди других потомков», впрочем, это является её минусом — «модификация прототипа не влечёт за собой немедленное и автоматическое изменение всех его потомков»
Извиняюсь, что не по теме Javascript. А если вручную и по необходимости выполнять обновление потомков или сделать признак у объектов, брать ли автоматом обновления предка? Например, как с обновлением программного обеспечения, хочешь — обновляйся :) Применимо ли это на уровне программного кода?
Можно все свойства «предков» перекрыть собственными свойствами, приравненными к undefined — получим фактически скрытие прототипа, разве что hasOwnProperty будет выдавать.
Да, верно. За основу лучше брать модель делегирования. Её легко для конкретных задач превратить в классическое прототипирование.
Так что всё хорошо в Javascript с этим :)
А на сколько существенны недостатки классического прототипирования в программировании?

Простите, а что вы в данном случае имеете в виду?
Дублирование свойств и логики, если порожденный объект не отличается от прототипа. И невозможность прототипу повлиять на своих потомков.
Не понятно, почему используется много раз слово «заблуждение»?
Как будто на каждом углу встречаются статьи рассказывающие о противоположном, а вы один глаза людям открываете.
Вы не поверите, но так оно и есть. Есть куча людей, которые не понимают или неправильно понимают, что такое this, что такое прототипы и т.д.
А вот почему все стараются избежать __proto__, в то время как это — то же самое, что .constructor.prototype? От которого не убежишь, а делает выражение только длиннее. Это вопрос. Может быть, кто-то знает ответ?
UFO just landed and posted this here
Ну вот частично ответ нашёл по ссылке выше — What is the difference between __proto__ and prototype, но не убедило. Автор говорит в самом конце, что __proto__ и prototype вместе с ним нехорошо по причине:
The original idea was that you could get the kind of thing that __proto__ referred to by taking an object and getting .constructor.prototype. But .constructor itself succumbs to prototypal inheritance, so unless the object's constructor set itself up to be that value, that wouldn't work. And nobody did that, so it's mostly broken.
. Что можно перевести как "[Проблема в том, что] .constructor сам становится «жертвой» прототипного наследования: пока конструкторы не будут определены, это не работает.

Видимо, при анонимных конструкторах какие-то проблемы?

Пробуем сделать анонимный конструктор.

abc = new ( function(){} )();

Сделаем ему прототип.

abc.constructor.prototype.c =115;

Смотрим прототип через объект.

console.log(abc.constructor.prototype, abc.constructor);

Всё видим, и конструктор (анонимную функцию), и прототип, присвоенный через потомка.

Или что имел автор в виду, говоря, что прототипы без конструкторов не работают? Нельзя сразу вписать abc.prototype?

> Возможно по той причине, что __proto__ можно поменять неосознанно…
--Но и .constructor.prototype можно поменять неосознанно. Нет, тут имеют какой-то смысл процитированные рассуждения автора выше.
Возможно по той причине, что __proto__ можно поменять неосознанно. Читал я где-то такое. Шанс невелик, но есть.
UFO just landed and posted this here
Но это очевидное следствие предоставленной свободы чехарды с прототипами.
Все-таки разница в них есть
delete Object.prototype.pewpew1;
delete Object.prototype.pewpew2;

var a = {}, 
    b = {};

/* 1 */ console.log(a.__proto__ === Object.prototype); // true

a.__proto__ = {"pewpew2": 1};
b.constructor.prototype = {"pewpew1": 1};

/* 2 */ console.log(b.pewpew1); // undefined - мы не переписали прототип

b.constructor.prototype.pewpew1 = 1;

/* 3 */ console.log(b.pewpew1); // 1
/* 4 */ console.log(({}).pewpew1); // 1
/* 5 */ console.log(({}).pewpew2); // undefined
/* 6 */ console.log(b.constructor.prototype === Object.prototype); // true
/* 7 */ console.log(a.__proto__ === Object.prototype); // false
Наверное, это тот случай, когда не определён конструктор объекта Object. Хотя он показывает какую-то нативную функцию, но даёт неверное первое равенство. Остальное — следствия.

Интересно, есть ли другие регулярные случаи ошибок? Например, если вместо {} ставишь new function(){this.a = 118;} или function(){}, то всё в порядке.

А var a = new Object(3), b = new Object(4); даёт ещё более интересные эффекты, однако есть сомнения, что это изъян идеологии, а не кривость реализации конкретно базового объекта Object, который давно уже советуют никогда не использовать с параметром, а теперь видно, что и для перегрузки свойств его не нужно использовать.
/*1*/ — переусложнённое равенство. Чуть упростив, получаем абсолютно очевидное:
/* 1 */ console.log(a.constructor === Object); // true


Далее, видим, где происходит сбой (не записывается прототип Qbject === Object.prototype):
b.constructor.prototype = {f: 4};

А здесь — нет:
b.constructor.prototype.d = 5;

Можно догадаться, что связано с тем, что неявно вызывается конструктор того же Object и что-то мешает записать прототип на нативном уровне. Реализация через __proto__ проходит без сбоев, а через .constructor.prototype — сбоит. Что говорит об этом история? Действительно сбой или «так и должно быть»?

Да так и должно быть. Посмотрим что же нам говорит Object.getOwnPropertyDescriptor:
Object.getOwnPropertyDescriptor(Object, "prototype");
// {"writable":false, "enumerable":false, "configurable":false}

Object.getOwnPropertyDescriptor({}, "__proto__");
// {"writable":true, "enumerable":false, "configurable":false}

// Хотя оба они
Object.isExtensible(({}).__proto__); // true
Object.isExtensible(Object.prototype); // true

Все меняет флаг writable, который запрещает перезапись (подвержены все прототипы базовых классов), но подмешать свойство мы можем, ибо оба объекта Extensible.
Автору стоило бы начать с того или хотя бы упомянуть, что в Javascript-е есть и чистое прототипное наследование без конструкторов:
= {x: 1}
= Object.create(a) // a.x === 1, b.x === 1
a.x = 2              // a.x === 2, b.x === 2
b.x = 3              // a.x === 2, b.x === 3
= Object.create(b) // a.x === 2, b.x === 3, c.x === 3
// c.__proto__ == b, b.__proto__ = a, a.__proto__ = Object.prototype


После этого видно, что конструкторы костыль
UFO just landed and posted this here
Да и до сих пор не поддерживается оперой… И создает объекты всреднем в 2 раза медленнее, чем new пруф.
@Suor, оцените потенциальную аудиторию статьи нужна ли им ещё одна заморочка?
Это не заморочка, это как раз простейший вариант прототипного наследования. Заморочки с конструкторами и new как раз выглядят странно на фоне такой стройной концепции. Начало статьи страдает от этого — пример с дедом, отцом и сыном непонятен и не совсем верен.

> И вдруг Дед решил: «надоело мне ходить зеленым — хочу стать сними», смутировал (изменил прототип своего класса)
Какого класса? В js нет классов. И, вообще, мы тут про прототипное наследование говорим, вроде )

Стройно так — дед меняет себя и так как он прототип отца, а отец прототип сына, то эти двое тоже меняются и т.д.
> Какого класса?
Ни я ли писал про это в самом начале статьи?! :) Да, забыл поставить «класса» в кавычки.

> И, вообще, мы тут про прототипное наследование говорим, вроде
В статье я говорю о «прототипном делегирующем наследовании». В вашей ветке обсуждения о «прототипном наследовании» две разные вещи
И ещё, особо смущающая вещь:
function F(){}
F.prototype = {x: 1}; // прототип F здесь не присваивается
Вторая строчка не присваивает прототип объекта F (функции). Она означает какой прототип будет у объектов созданных с помощью new F().
Почему не присваивается? Проверяем:
function F(){}
F.prototype = {x: 1};
console.log("F.prototype: ", F.prototype); //F.prototype: Object(x:1) (Хром, FF)
console.log((new F()).x); //1, тоже верно

Прототип объекта — это тот объект, от которого он наследуется.
F.prototype — не прототип F, прототип F — Function.prototype. Прототип (new F) — F.prototype.
Правда, запутанно?

С непривычки да. Все пошло с языка Self. Да и prototype должно быть и есть по умолчанию только у функции-конструктора.
Не хватает иллюстраций, типа: image
А так +100500. Наследование понял именно благодаря вам.
Sign up to leave a comment.

Articles