Skip to content Skip to sidebar Skip to footer

Why Does Object.seal Allow User Setters To Still Work, But Disables Native Setters Like __proto__?

For example, in this question, I had assumed that __proto__ being a setter would mean that Object.seal would not change the behavior of the __proto__ setter, but I was mistaken. Bu

Solution 1:

Calling the __proto__ setter makes the engine internally call the SetPrototypeOf procedure. From the spec:

B.2.2.1.2 set Object.prototype.proto

The value of the [[Set]] attribute is a built-in function that takes an argument proto. It performs the following steps:

  1. Let O be RequireObjectCoercible(this value).
  2. ReturnIfAbrupt(O).
  3. If Type(proto) is neither Object nor Null, return undefined.
  4. If Type(O) is not Object, return undefined.
  5. Let status be O.[SetPrototypeOf].
  6. ReturnIfAbrupt(status).
  7. If status is false, throw a TypeError exception.

If the object is sealed, the SetPrototypeOf call returns false, because:

  1. If extensible is false, return false.

Setters which don't attempt to call setPrototypeOf (internally or externally) will not throw an error. Object.seal does not prevent setters from being called, but it prevents setters which actually try to add new properties (or change the object's prototype) from succeeding. Because your custom setter doesn't try to add new properties, no error is thrown; the _foo property is put onto the object before it is sealed.

If you had called the setter for the first time after the object was sealed, before_foo had been added, you would've seen an error in strict mode:

'use strict';
var o = {
  getfoo() {
    returnthis._foo
  },
  setfoo(val) {
    this._foo = val
  },
}

Object.seal(o)

o.foo = 10

In non-strict mode, assigning a new property to a sealed object will fail silently (but trying to change the prototype will throw an error):

var o = {
  getfoo() {
    returnthis._foo
  },
  setfoo(val) {
    this._foo = val
  },
}

Object.seal(o)

o.foo = 10console.log(o.foo);

Solution 2:

Sealing the object locks in the internal [[prototype]] link. You can't change it any more, regardless trough which method:

> Object.setPrototypeOf(Object.seal({}), {})
VM2817:1 Uncaught TypeError: #<Object> is not extensible
    at Function.setPrototypeOf (<anonymous>)
    at <anonymous>:1:8

This has nothing to do with getters/setters.

Post a Comment for "Why Does Object.seal Allow User Setters To Still Work, But Disables Native Setters Like __proto__?"