1

例如,在这个问题中,我认为__proto__作为一个 setter 意味着Object.seal不会改变__proto__setter 的行为,但我错了。

但是,这不适用于常规设置器,例如:

var o = {
	get foo() { return this._foo },
	set foo(val) { this._foo = val },
}

o.foo = 5

Object.seal(o)

o.foo = 10 // it still works!

console.log(o.foo)
console.log(o._foo)

// but this doesn't work:
o.__proto__ = { n: 5 }

console.log(o.n)

编写 setter 的用户是否希望检查密封/冻结/可扩展状态?在实践中似乎没有多少人这样做。不应该 Object.seal 然后禁用设置器,就像它一样__proto__

所以,问题是,__proto__(等)有特殊情况吗?

4

2 回答 2

0

密封对象锁定在内部[[prototype]]链接中。无论通过哪种方法,您都无法再更改它:

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

这与 getter/setter 无关。

于 2019-04-14T20:45:26.227 回答
0

调用__proto__setter 会使引擎在内部调用该SetPrototypeOf过程。从规格

B.2.2.1.2 设置 Object.prototype。原型

[[Set]] 属性的值是一个带有参数 proto 的内置函数。它执行以下步骤:

  1. 令 O 为 RequireObjectCoercible(此值)。
  2. 返回IfAbrupt(O)。
  3. 如果 Type(proto) 既不是 Object 也不是 Null,则返回 undefined。
  4. 如果 Type(O) 不是 Object,则返回 undefined。
  5. 让状态为 O.[SetPrototypeOf]。
  6. ReturnIfAbrupt(状态)。
  7. 如果 status 为 false,则抛出 TypeError 异常。

如果对象是密封的,则SetPrototypeOf调用返回 false,因为

  1. 如果可扩展为假,则返回假。

不尝试调用(内部或外部)的设置器不会setPrototypeOf抛出错误。Object.seal不会阻止调用 setter,但会阻止实际尝试添加新属性(或更改对象的原型)的 setter 成功。因为您的自定义设置器不会尝试添加新属性,所以不会引发错误;在密封之前_foo属性放在对象上。

如果你在对象被密封之后第一次调用 setter ,在添加之前 _foo,你会在严格模式下看到一个错误:

'use strict';
var o = {
  get foo() {
    return this._foo
  },
  set foo(val) {
    this._foo = val
  },
}

Object.seal(o)

o.foo = 10

在非严格模式下,将新属性分配给密封对象将静默失败(但尝试更改原型会引发错误):

var o = {
  get foo() {
    return this._foo
  },
  set foo(val) {
    this._foo = val
  },
}

Object.seal(o)

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

于 2019-04-14T19:34:03.227 回答