Object.preventExtensions фактически допускает мутацию __proto__? - PullRequest
4 голосов
/ 08 июня 2011

Я просматривал MDC о новых функциях, добавленных в Object. Считается, что один из них, Object.preventExtensions, предотвращает мутации в прототипе объекта, которые можно получить с помощью Object.getPrototypeOf или __proto__.

Однако в Chrome, похоже, просто допускаются мутации в прототипе объекта. Это можно подтвердить, просто выполнив код на соответствующей странице :

// EXTENSION (only works in engines supporting __proto__
// (which is deprecated. Use Object.getPrototypeOf instead)):
// A non-extensible object's prototype is immutable.

var fixed = Object.preventExtensions({});
fixed.__proto__ = { oh: "hai" }; // throws a TypeError

Я не получаю это TypeError и fixed.__proto__.oh === 'hai', поэтому оно было установлено, даже если оно должно быть запрещено. Я также могу добавить его при кодировании как Object.getPrototypeOf(fixed).oh = 'hai'.

Значит ли это, что Chrome по-разному интерпретирует эту функцию? Как можно предотвратить расширение прототипа объекта (в Chrome)?

Ответы [ 2 ]

5 голосов
/ 08 июня 2011

Нет, Chrome и Mozilla реализуют стандартную часть спецификации одинаково.Читайте внимательно:

Object.preventExtensions только предотвращает добавление собственных свойств.Свойства все еще могут быть добавлены к прототипу объекта.

Все, что связано с .__proto__, является нестандартным, и Chrome может реализовать это по-другому.Вы показали только, что Chrome реализует детали с .__proto__ по-разному, и, на мой взгляд, более интуитивно: спецификация говорит, что прототип все еще расширяем , поэтому имеет смысл, что вы все равно сможете его мутировать,Тогда возникает вопрос, почему Mozilla реализовала это таким образом ?

Например, следующий код работает одинаково и на Chrome, и на FF:

var fixed = Object.preventExtensions({});
Object.getPrototypeOf(fixed).p = 99;
fixed.p; // 99

Ясно, чтоПрототип все еще изменчив.Это имеет смысл с реализацией Chrome .__proto__.

. Поэтому, чтобы предотвратить расширения прототипа, сделайте это отдельно:

var fixed = Object.preventExtensions({});
Object.preventExtensions(Object.getPrototypeOf(fixed));
Object.getPrototypeOf(fixed).p = 99; // TypeError: Can't add property p, object is not extensible
2 голосов
/ 08 июня 2011

В ECMAScript 5 объекты имеют логическое внутреннее свойство с именем [[Extensible]], это свойство устанавливается на false при вызове метода Object.preventExtensions, а после этогок этому объекту нельзя добавить новые собственные свойства .

В Chrome 14.0.786.0 присвоение __proto__ вызывает TypeError, как и ожидалось.

Но помните, что расширение __proto__ является нестандартным , поэтому его поведение может изменяться, конечно, синтаксически это «назначение свойства», но внутренне оно не «добавляет собственное свойство»,он мутирует прототип объекта, что невозможно сделать ни одним стандартным методом.

О примере метода Object.getPrototypeOf, который вы нам показываете, он просто извлекает прототип объекта, в случае вашего fixed объект, это Object.prototype объект:

Object.getPrototypeOf(fixed) === Object.prototype; // true

Итак, ваш пример:

Object.getPrototypeOf(fixed).oh = 'hai'

Эквивалентно:

Object.prototype.oh === 'hai';
...