Object.preventExtensions действительно позволяет изменять __proto__?

Я просматривал 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)?


person pimvdb    schedule 08.06.2011    source источник


Ответы (2)


Нет, 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
person davin    schedule 08.06.2011

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

В 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';
person Christian C. Salvadó    schedule 08.06.2011