簡體   English   中英

Object.isExtensible()為true,但拋出Object.defineProperty()。為什么?

[英]Object.isExtensible() is true, but Object.defineProperty() throws. Why?

在Firefox和Safari中我看到Object.isExtensible()為true的情況,我可以添加一個帶有常規屬性賦值的新屬性(即ox = y ),但是Object.defineProperty()會拋出“TypeError:Object.defineProperty” (...)不可擴展“。

這種情況發生在類型數組中,也可能是其他類型。 我正在嘗試使用isExtensible()來確保我不嘗試在對象上定義屬性。

我可以將defineProperty放在try / catch中,但我想了解這里發生了什么。 有任何想法嗎?

這是jsfiddle的一個例子: http//jsfiddle.net/justinfagnani/qvgnk/

和代碼:

function addProperty(o, name, value) {
  if (Object.isExtensible(o)) {
    Object.defineProperty(o, name, {'value': value});
    return true;
  }
  return false;
}

console.log(addProperty(new Date(), 'foo', 1));
console.log(addProperty(new ArrayBuffer(), 'foo', 1));

這應該至少為每次調用打印true或false。 在Firefox中,它會拋出ArrayBuffer。

注意:類型化數組現在在ES6 / ES2015規范中,其中ArrayBuffer實際上是可擴展的。 此答案僅供先前參考。


Typed Array規范沒有明確說明這一點,盡管它使用Web IDL來描述創建的對象,其中說明如下:

除非另有說明,否則本節中定義的對象的[[Extensible]]內部屬性值為true

我不確定為什么他們把這個放在規范中,但是為什么他們可能選擇使[[Extensible]]真,即使它不可擴展,也有一些原因包括:

  • 想要允許來自特定功能/路徑的擴展(當它是錯誤時禁止)
  • 允許擴展主機對象(禁止從false更改為true)

根據ECMAScript規范 (JavaScript的“標准”版本),主機對象是否拋出設置變量是依賴於實現的(第8.6.2節 ):

除非另有說明,否則Host對象可以以任何方式實現這些內部方法 ; 例如,一種可能性是特定主機對象的[[Get]][[Put]]確實獲取並存儲屬性值,但[[HasProperty]]始終生成false。 但是,如果實現不支持對宿主對象的內部屬性的任何指定操作,則該操作必須在嘗試時拋出TypeError異常。

規范給出的不變量都不適用於此實例,因此這在技術上是合法的。


需要注意的是:即使[[Extensible]]為真,主機對象的內部函數也不必允許對象進行擴展。 規范僅強制要求在[[Extensible]]為false( 引用 )時不擴展宿主對象:

如果ECMAScript代碼觀察到該主機對象的[[Extensible]]內部屬性為false,則主機對象的[[DefineOwnProperty]]內部方法不允許向主機對象添加新屬性。

表8/9(第8.6.2節 )中的規范中給出的描述本身就是誤導性的,因為它們只涉及本機ECMAScript對象,而不是主機對象 - 這在表8之前的段落中具體說明,主機對象不是主題實現這些表中描述的屬性。

我相信這種行為取決於嚴格模式和JavaScript引擎。

在V8(Chrome)中,如果禁用嚴格模式,則ox = y將成功,但不會向ox分配任何內容,而Object.defineProperty始終拋出異常,無論嚴格模式如何。

在嚴格模式下, ox會拋出異常。

在Rhino中, Object.defineProperty將拋出異常, ox = y將無聲地失敗。

這里有些例子:

/usr/local/Cellar/tomcat6/6.0.37 >rhino -strict
Rhino 1.7 release 4 2012 06 18
js> var o = {a: 132};
js> Object.freeze(o);
[object Object]
js> Object.isExtensible(o);
false
js> o.x = 789;
789
js> o.x;
js> Object.defineProperty(o,'name',{value: 789})
js: uncaught JavaScript runtime exception: TypeError: Cannot add properties to this object because extensible is false.

在V8中

/usr/local/Cellar/tomcat6/6.0.37 >node
> var o = {a: 123}
undefined
> Object.freeze(o)
{ a: 123 }   
> Object.isExtensible(o)
false
> o.x = 13
13
> o.x
undefined
> Object.defineProperty(o,'name',{value:123})
TypeError: Cannot define property:name, object is not extensible.
    at Function.defineProperty (native)
    at repl:1:9
    at REPLServer.self.eval (repl.js:110:21)
    at Interface.<anonymous> (repl.js:239:12)
    at Interface.EventEmitter.emit (events.js:95:17)
    at Interface._onLine (readline.js:202:10)
    at Interface._line (readline.js:531:8)
    at Interface._ttyWrite (readline.js:760:14)
    at ReadStream.onkeypress (readline.js:99:10)
    at ReadStream.EventEmitter.emit (events.js:98:17)

在嚴格的模式

/usr/local/Cellar/tomcat6/6.0.37 >node --use_strict
> var o = {a: 123};
undefined
> Object.freeze(o);
{ a: 123 }
> Object.isExtensible(o);
false
> o.x = 13
TypeError: Can't add property x, object is not extensible
    at repl:1:6
    at REPLServer.self.eval (repl.js:110:21)
    at Interface.<anonymous> (repl.js:239:12)
    at Interface.EventEmitter.emit (events.js:95:17)
    at Interface._onLine (readline.js:202:10)
    at Interface._line (readline.js:531:8)
    at Interface._ttyWrite (readline.js:760:14)
    at ReadStream.onkeypress (readline.js:99:10)
    at ReadStream.EventEmitter.emit (events.js:98:17)
    at emitKey (readline.js:1095:12)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM