Путаница в установке чего-то. Prototype.__ proto__

В коде для модуля Express для Node.js я наткнулся на эту строку, установив наследование для сервера:

Server.prototype.__proto__ = connect.HTTPServer.prototype;

Я не уверен, что это делает - документы MDC (https://developer.mozilla.org/en/JavaScript/Guide/Inheritance_Revisited#prototype_and_ proto), похоже, говорят, что я мог просто выполните:

Server.prototype = connect.HTTPServer.prototype;

Действительно, я сделал это испытание:

var parent = function(){}
parent.prototype = {
    test: function(){console.log('test')};
}

var child1 = function(){};
child1.prototype = parent.prototype;
var instance1 = new child1();
instance1.test();     // 'test'

var child2 = function(){};
child2.prototype.__proto__ = parent.prototype;
var instance2 = new child2();
instance2.test();     // 'test'

Кажется, что то же самое? Итак, да, мне интересно, какой параметр object.prototype.__ proto для. Спасибо!

Ответ 1

Посмотрите на диаграмму на этой странице (mckoss.com), которая показывает отношения prototype, constructor, __proto__ для небольшой иерархии, Также код ниже диаграммы достаточно хорошо описывает отношение.

Когда у вас есть функция Base и задан прототип объекта функции, оператор Derived.prototype = new Base; автоматически устанавливает __proto__ (фактически внутренний [[prototype]]) Derived.prototype в Base.prototype make Производит сам класс, из которого вы можете создавать объекты. Кажется, это более стандартный способ определения производного класса.

Из того, что я читаю, __proto__ является нестандартным способом доступа к внутреннему [[prototype]] объекта. Кажется, это хорошо поддерживается, но я не уверен, что ему следует доверять.

В любом случае ваш пример Server.prototype.__proto__ = connect.HTTPServer.prototype;, похоже, делает вывод наоборот: сначала определите объект, Server, определив конструктор и прото, а затем вручную подключите внутренний [[prototype]] к морфию это в класс, полученный из HTTPServer.

Что касается предложенной вами альтернативы, Server.prototype = connect.HTTPServer.prototype;: это плохая идея. Здесь вы устанавливаете прототип Server для того же объекта, что и прототип HTTPServer. Поэтому любые изменения, внесенные вами в класс Server, будут непосредственно отражены в HTTPServer и будут доступны из других производных классов HTTPServer. Вы можете изобразить хаос, если два класса, полученные из HTTPServer, попытаются определить один и тот же элемент.

Ответ 2

Нестандартное свойство __proto__ позволяет вам установить прототип существующего объекта.

В вашем примере обе версии достигнут того же эффекта, но есть разница:

Прототип

child1 такой же, как прототип parent, тогда как прототип child2 - пустой объект, и этот прототип пустого объекта совпадает с прототипом parent.

Конечно, как child2, а его прототип не имеет метода test, этот метод будет рассмотрен далее в цепочке прототипов.

Также рассмотрим следующее:

Вы хотите создать только один объект, который должен наследовать от другого объекта. Теперь вы можете написать конструктор, но JavaScript имеет объектную нотацию для создания объектов напрямую и вы хотите использовать его.

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

Очевидно, это не работает для объектных литералов. Но в Firefox вы можете использовать __proto__ для его установки:

var server = {
    __proto__: connect.HTTPServer.prototype,
    other: properties
};

Поскольку это свойство не является стандартным, его следует избегать.