/* * E5.1 Section 10.5, step 5.e. * * The global may have an implementation dependent internal prototype. * For us, the prototype is now Object.prototype directly. * * The conflicting property in step 5.e may be present in an ancestor, * as is the case when do: * * function toString() { ... } * * The global object does not contain toString(), but Object.prototype.toString() * will conflict; in other words step 5.c will yield funcAlreadyDeclared = true. * * In this case, step 5.e will look at the existing property descriptor found in * the ancestor and will declare a new property in the global object; the ancestor * will never be modified. * * Here we test for this case, declaring conflicting functions/values first in * Object.prototype. */ var tmp; Object.defineProperties(Object.prototype, { test_configurable_function: { value: function() { print('original') }, writable: false, enumerable: false, configurable: true }, test_configurable_value: { value: 123, writable: false, enumerable: false, configurable: true }, test_configurable_accessor: { get: function() { print('getter') }, set: function() { print('setter') }, enumerable: false, configurable: true }, test_nonconfigurable_compatible_value: { // non-configurable, but is not an accessor, and is writable and enumerable // (steps 5.e.iii - 5.e.iv) value: 321, writable: true, enumerable: true, configurable: false }, test_nonconfigurable_incompatible_value1: { value: 1001, writable: false, enumerable: true, configurable: false }, test_nonconfigurable_incompatible_value2: { value: 1002, writable: true, enumerable: false, configurable: false }, test_nonconfigurable_accessor: { get: function() { print('getter') }, set: function() { print('setter') }, enumerable: false, configurable: false } }); /*=== replacement original replacement 123 replacement getter setter ===*/ /* Configurable plain value or accessor: allow redeclaration */ try { eval("function test_configurable_function() { print('replacement'); }"); test_configurable_function(); Object.prototype.test_configurable_function(); } catch (e) { print(e.name); } try { eval("function test_configurable_value() { print('replacement'); }"); test_configurable_value(); print(Object.prototype.test_configurable_value); } catch (e) { print(e.name); } try { eval("function test_configurable_accessor() { print('replacement'); }"); test_configurable_accessor(); tmp = Object.prototype.test_configurable_accessor; Object.prototype.test_configurable_accessor = 1; } catch (e) { print(e.name); } /*=== replacement 321 ===*/ /* Non-configurable compatible value: must be a plain value, and be writable * and enumerable. */ try { eval("function test_nonconfigurable_compatible_value() { print('replacement'); }"); test_nonconfigurable_compatible_value(); print(Object.prototype.test_nonconfigurable_compatible_value); } catch (e) { print(e.name); } /*=== TypeError TypeError TypeError undefined undefined undefined 1001 1002 getter setter ===*/ /* Non-configurable incompatible values: TypeError and no modification */ try { eval("function test_nonconfigurable_incompatible_value1() { print('replacement'); }"); print('never here'); } catch (e) { print(e.name); } try { eval("function test_nonconfigurable_incompatible_value2() { print('replacement'); }"); print('never here'); } catch (e) { print(e.name); } try { eval("function test_nonconfigurable_accessor() { print('replacement'); }"); print('never here'); } catch (e) { print(e.name); } // verify that nothing was declared in the global object print(Object.getOwnPropertyDescriptor(this, 'test_nonconfigurable_incompatible_value1')); print(Object.getOwnPropertyDescriptor(this, 'test_nonconfigurable_incompatible_value2')); print(Object.getOwnPropertyDescriptor(this, 'test_nonconfigurable_accessor')); // and that nothing changed in the ancestor print(Object.prototype.test_nonconfigurable_incompatible_value1); print(Object.prototype.test_nonconfigurable_incompatible_value2); tmp = Object.prototype.test_nonconfigurable_accessor; Object.prototype.test_nonconfigurable_accessor = 1;