Ответ 1
Примечание.. По мнению плохой практики, изменить значение __proto__
. Этому сильно препятствует Брендан Эйх, создатель JavaScript, среди прочих. Фактически свойство __proto__
полностью удалено из нескольких движков JavaScript, таких как Rhino. Если вы хотите знать, почему тогда читайте после комментария от Brendan Eich.
Обновление: Браузеры не собираются удалить свойство __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>