Примечание: Считается неправильной практикой, чтобы изменить значение __proto__
. Этому сильно препятствует Брендан Эйх, создатель JavaScript, среди прочих. Фактически свойство __proto__
было полностью удалено из нескольких движков JavaScript, таких как Rhino. Если вы хотите знать, зачем тогда читать following comment Брендан Эйх.
Обновление: Браузеры не собираются удалить объект __proto__
. Фактически, ECMAScript Harmony теперь стандартизовал как свойство __proto__
, так и функцию setPrototypeOf
. Свойство __proto__
поддерживается только по наследству. Вам настоятельно рекомендуется использовать setPrototypeOf
и getPrototypeOf
вместо __proto__
.
Предупреждение: Хотя setPrototypeOf
теперь является стандартным, вы по-прежнему не рекомендуется использовать его, потому что мутирует прототип объекта неизменно убивает оптимизаций и делает ваш код медленнее. Кроме того, использование setPrototypeOf
обычно является показателем низкого качества кода.
Вам не нужно беспокоиться о том, что существующий код не работает в один прекрасный день. Объект __proto__
находится здесь.
Теперь вопрос под рукой. Мы хотим сделать что-то похожее на это в соответствии с требованиями стандарта образом:
var a = {
b: "ok"
};
a.__proto__ = {
a: "test"
};
alert(a.a); // alerts test
alert(a.b); // alerts ok
Очевидно, что вы не можете использовать Object.create
для достижения этой цели, так как мы не создаем новый объект. Мы просто пытаемся изменить внутреннее свойство [[proto]]
данного объекта. Проблема в том, что невозможно изменить внутреннее свойство [[proto]]
объекта после его создания (за исключением использования __proto__
, которого мы пытаемся избежать).
Итак, чтобы решить эту проблему, я написал простую функцию (обратите внимание, что он работает для всех объектов, за исключением функций):
function setPrototypeOf(obj, proto) {
var result = Object.create(proto);
var names = Object.getOwnPropertyNames(obj);
var getProp = Object.getOwnPropertyDescriptor;
var setProp = Object.defineProperty;
var length = names.length;
var index = 0;
while (index < length) {
var name = names[index++];
setProp(result, name, getProp(obj, name));
}
return result;
}
Таким образом, мы можем теперь изменить прототип любого объекта после его создания следующим образом (обратите внимание, что мы фактически не изменяя внутреннюю [[proto]]
свойства объекта, но вместо того, чтобы создать новый объект с теми же свойствами данного объекта и который наследует от данного прототипа):
var a = {
b: "ok"
};
a = setPrototypeOf(a, {
a: "test"
});
alert(a.a); // alerts test
alert(a.b); // alerts ok
<script>
function setPrototypeOf(obj, proto) {
var result = Object.create(proto);
var names = Object.getOwnPropertyNames(obj);
var getProp = Object.getOwnPropertyDescriptor;
var setProp = Object.defineProperty;
var length = names.length;
var index = 0;
while (index < length) {
var name = names[index++];
setProp(result, name, getProp(obj, name));
}
return result;
}
</script>
Простой и эффективный (и мы не использовали свойство __proto__
).
Похоже, что '__proto__' может быть стандартизован в следующем ECMAScript. Не может быть абсолютно уверен, пока не будет завершена. http://wiki.ecmascript.org/doku.php?id=harmony:specification_drafts ... по крайней мере, это указано в текущем проекте в Приложении B «Дополнительные функции для веб-браузеров». –