为什么Object.seal允许用户设置器继续工作,但禁用诸如__proto__之类的本地设置器?

时间:2019-04-14 19:23:52

标签: javascript

例如,在this question中,我假设__proto__是设置者将意味着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)

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

问题是,__proto__(等等)是否有特殊情况?

2 个答案:

答案 0 :(得分:0)

调用__proto__设置程序会使引擎内部调用SetPrototypeOf过程。来自spec

  

B.2.2.1.2设置Object.prototype。 proto

     

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

     
      
  1. 让O成为RequireObjectCoercible(此值)。
  2.   
  3. ReturnIfAbrupt(O)。
  4.   
  5. 如果Type(proto)既不是Object也不是Null,则返回undefined。
  6.   
  7. 如果Type(O)不是Object,则返回undefined。
  8.   
  9. 让状态为O。[SetPrototypeOf]。
  10.   
  11. ReturnIfAbrupt(状态)。
  12.   
  13. 如果状态为false,则引发TypeError异常。
  14.   

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

  
      
  1. 如果extensible为false,则返回false。
  2.   

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

如果您是在密封对象之后 第一次调用设置方法,则在 _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);

答案 1 :(得分:0)

密封对象会锁定在内部 [[prototype]] 链接中。无论采用哪种方法,您都无法再对其进行更改:

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

这与getters / setter无关。