Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!

// Смысла нет
Grandfather.prototype.color = 'blue';
console.log([u.color, f.color, s.color]); // ["blue", "green", "green"]// ["blue", "blue", "blue"]Father.prototype.color = 'green';), а поиск свойства color лежит сперва через прототип отца. Вот так выглядит объект f:f = {
__proto__: { // Прототип Father
color: 'green', // Отец решил вернуть цвет
__proto__: { // Прототип Grandfather
color: 'blue', // Дед решил поменять на синий
__proto__: Object.prototype
}
}
}f.__proto__ — найдено! (color: 'green'). Вобщем до прототипа деда и не дойдет.// Отец решил все вернуть для себя и своего потомства
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"].
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? Из каких соображений выбран такой дизайн?(foo.bar = foo.bar)(); // this === global (3)
(false || foo.bar)(); // this === global (3)
(foo.bar, foo.bar)(); // this === global (3)

getProperty(p, 'print').call(p). Разберем что тут происходит: var p_print = p.print)inherit(Father, 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;
}Конструктор Grandfather не будет выполнен. Если нам все-такие необходимо выполнить конструктор Grandfather, то вызываем его с помошью call или appy
var Father = function () { // Конструктор Father 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;
__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__ изначально было скрыто. Потом кто-то стал его открывать минуя стандарт. В ECMAScript [[Prototype]] — внутреннее свойство. es5.github.com/#x8.6.2 es5.github.com/#x13.2.2 В 6-й версии ECMAScript будет сахар — class (который на самом деле делает не class-ы, а строит цепочку прототипов).Father.prototype.class = Grandfather.prototype;
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;
}
}
Father.call(this); // Делаем "наследование" через call
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 и поэтому утекло в глобалы — значит «сам дурак»к клиентскому коду, то почему оно не распространяется на код ваших объектов?
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но зато быстрее работать будетНапример, Хром оптимизирует рыскание по цепочке прототипов и каждый раз прозрачно создает новый объект (вобщем все свойства косвенно own). Раз это кэш, то расходуется дополнительная память, зато снижается время. Сейчас все оптимизации «по времени», так что это нормально (контр оптимизация — «по памяти»).
А на сколько существенны недостатки классического прототипирования в программировании?
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 сам становится «жертвой» прототипного наследования: пока конструкторы не будут определены, это не работает.
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/* 1 */ console.log(a.constructor === Object); // trueb.constructor.prototype = {f: 4};b.constructor.prototype.d = 5;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
a = {x: 1}
b = 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
c = Object.create(b) // a.x === 2, b.x === 3, c.x === 3
// c.__proto__ == b, b.__proto__ = a, a.__proto__ = Object.prototype
После этого видно, что конструкторы костыль
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, тоже верно

Основы и заблуждения насчет JavaScript