РЕДАКТИРОВАТЬ Февраль 2012 г .: приведенный ниже ответ больше не точен. __proto__ добавляется в ECMAScript 6 как «нормативный необязательный», что означает, что его не нужно реализовывать, но если это так, он должен соответствовать заданному набору правил. В настоящее время этот вопрос не решен, но, по крайней мере, он будет официально включен в спецификацию JavaScript.
Этот вопрос намного сложнее, чем кажется на первый взгляд, и выходит за рамки уровня оплаты труда большинства людей в отношении знания внутреннего устройства Javascript.
prototype
Свойство объекта используется при создании новых дочерних объектов этого объекта. Его изменение не отражается на самом объекте, скорее, оно отражается, когда этот объект используется в качестве конструктора для других объектов, и не имеет смысла изменять прототип существующего объекта.
function myFactory(){};
myFactory.prototype = someOtherObject;
var newChild = new myFactory;
newChild.__proto__ === myFactory.prototype === someOtherObject; //true
У объектов есть внутреннее свойство [[prototype]], которое указывает на текущий прототип. Это работает так: всякий раз, когда вызывается свойство объекта, оно начинается с объекта, а затем идет вверх по цепочке [[prototype]], пока не найдет совпадение или не завершится ошибкой после корневого прототипа объекта. Вот как Javascript позволяет создавать и изменять объекты во время выполнения; у него есть план поиска того, что ему нужно.
Это __proto__
свойство существует в некоторых реализациях (сейчас их много): в любой реализации Mozilla, во всех известных мне webkit и некоторых других. Это свойство указывает на внутреннее свойство [[prototype]] и позволяет изменять объекты после создания. Любые свойства и функции мгновенно переключаются в соответствии с прототипом благодаря этому поиску по цепочке.
Эта функция, хотя сейчас и стандартизирована, по-прежнему не является обязательной частью JavaScript, и на языках, поддерживающих ее, существует высокая вероятность того, что ваш код попадет в категорию «неоптимизированных». JS-движки должны делать все возможное, чтобы классифицировать код, особенно «горячий» код, к которому обращаются очень часто, и если вы делаете что-то необычное, например, модифицируйте __proto__
, они вообще не оптимизируют ваш код.
В этой публикации https://bugzilla.mozilla.org/show_bug.cgi?id=607863 конкретно обсуждаются текущие реализации __proto__
и различия между ними. Каждая реализация делает это по-своему, потому что это сложная и нерешенная проблема. Все в Javascript изменяемо, кроме a.) Синтаксиса b.) Объектов хоста (DOM технически существует вне Javascript) и c.) __proto__
. Остальное полностью в ваших руках и в руках любого другого разработчика, так что вы можете понять, почему __proto__
торчит, как больной палец.
Есть одна вещь, которая __proto__
позволяет сделать это иначе: обозначение прототипа объекта во время выполнения отдельно от его конструктора. Это важный вариант использования, и это одна из основных причин, по __proto__
которой он еще не умер. Достаточно важно, чтобы он стал предметом серьезного обсуждения при формулировке Harmony или вскоре станет известен как ECMAScript 6. Возможность указывать прототип объекта во время создания будет частью следующей версии Javascript, и это будет колокол, указывающий __proto__
на то, что дни официально пронумерованы.
В краткосрочной перспективе вы можете использовать, __proto__
если ориентируетесь на браузеры, которые его поддерживают (не IE, и никакой IE никогда не будет). Вероятно, он будет работать в webkit и moz в течение следующих 10 лет, поскольку ES6 не будет доработан до 2013 года.
Брендан Эйх - re: Подход новых методов Object в ES5 :
Извините, ... но настраиваемый __proto__
, помимо варианта использования инициализатора объекта (т.е. для нового объекта, который еще не доступен, аналогично Object.create в ES5), - ужасная идея. Я пишу это, разработав и реализовав settable __proto__
более 12 лет назад.
... отсутствие расслоения является проблемой (рассмотрим данные JSON с ключом "__proto__"
). И что еще хуже, изменчивость означает, что реализации должны проверять циклические цепочки прототипов, чтобы избежать ошибок. [требуются постоянные проверки на бесконечную рекурсию]
Наконец, изменение __proto__
существующего объекта может привести к поломке неуниверсальных методов в новом объекте-прототипе, которые не могут работать с объектом-получателем (прямым), __proto__
который устанавливается. Это просто плохая практика, форма намеренного смешения типов в целом.