js中的delete機制3

來源:互聯網
上載者:User

標題: 轉:理解javascript中的delete機制(3)
- 小小蘇 2010-05-17 10:16 閱讀:17
- 評論:0 | 發表評論 | 返回 ↓

IE bugs

整個章節僅僅為了IE中的bug,想不到吧!

在IE瀏覽器中(至少是IE6-IE8),下面的運算式拋出錯誤(在全域代碼中執行):

this.x = 1; 
delete x; // TypeError: Object doesn't support this action

 

這個也是一樣,但異常不同,只是更有趣:

var x = 1; 
delete this.x; // TypeError: Cannot delete 'this.x'

IE中看起來好像在全域代碼中聲明變數不能在全域對象中建立屬性。通過賦值建立屬性(this.x = 1),然後通過delete刪除x將拋出錯誤。通過聲明建立建立屬性(var x = 1),然後通過delete this.x刪除將拋出另外一個錯誤。

但這還沒完。實際上通過明確的賦值建立的屬性在刪除時始終引發錯誤。這不僅是一個錯誤,而且建立的屬性似乎設定了DontDelete特性,這當然不應該有:

代碼

1 this.x = 1; 
2 delete this.x; // TypeError: Object doesn't support this action 
3 typeof x; // "number" (still exists, wasn't deleted as it should have been!) 
4 delete x; // TypeError: Object doesn't support this action 
5 typeof x; // "number" (wasn't deleted again)

與我們思考的相反,未聲明的變數(應該在一個全域對象中建立屬性)在IE中建立了可刪除屬性。

x = 1; 
delete x; // true 
typeof x; // "undefined"

但是,如果您嘗試通過“this”引用在全域代碼中刪除它(delete this.x ),一個熟悉的錯誤彈出:

x = 1; 
delete this.x; // TypeError: Cannot delete 'this.x'

 

 

如果我們總結這些行為,從全域代碼中delete this.x 似乎是不成功的。當涉及到的屬性是通過顯式聲明(this.x = 1 )來建立的,delete 將拋出一個錯誤。當屬性是通過未聲明的賦值(x = 1 )或聲明(var x = 1 )來建立屬性時,delete 將拋出另一個錯誤。

另一方面,當涉及到的屬性是通過顯式聲明(this.x = 1 )建立時,delete x 拋出錯誤。如果一個屬性是通過聲明(var x = 1 )來建立的,刪除根本不會發生,並返回正確的false。如果屬性是通過未聲明的方式(x = 1)建立,刪除操作將按預期進行。

去年九月我正在思考這個問題,Garrett Smith 建議“在IE中全域可變對象作為一個JScript對象,全域對象有宿主執行”。Garrett 引用Eric Lippert’s blog entry ,我們可以通過一些測實驗證這些理論。請注意,thiswindow似乎引用同一對象(如果我們相信“===”運算子),但可變對象(在一個聲明的函數中的對象)不同於這一點。

 

代碼

1 /* in Global code */
2 function getBase(){ return this; } 
3   
4 getBase() === this.getBase(); // false 
5 this.getBase() === this.getBase(); // true 
6 window.getBase() === this.getBase(); // true 7.window.getBase() === getBase(); // false 

 

 

誤區

理解事物為什麼那麼工作是一種難以言說的美,我在網上已經看到了與delete運算子誤解相關的誤區。例如,在關於棧溢出的回答(評分出其不意的效果高)中,它自信的解釋道:“delete is supposed to be no-op when target isn’t an object property ”。現在,我們已經理解了delete 行為的核心,很清楚這個答案是不準確的。delete 不區分變數和屬性(事實上,對於刪除,這些都是引用),真正的只關心的是DontDelete特性(和屬性存在)。

非常有意思的看到這個誤解如何相互影響,在同樣一個線程中,有人首先提出要直接刪除變數(除非它是在eval中聲明,否則不會生效),接著另外一個人提出一種錯誤的糾正方法--在全域中可能刪除變數,但在函數內不行。

在網站上解釋Javascript 最好小心,最好總是抓住問題的核心。

‘delete’和宿主對象

delete 的演算法大概是這樣:

  1. 如果操作不是一個引用,返回true
  2. 如果一個對象沒有直接的屬性,返回true;(我們知道,對象可以是啟用物件,可以是全域象);
  3. 如果一個屬性存在並有DontDelete特性,返回false
  4. 否則,刪除屬性並返回true

但是,宿主對象的delete 運算子的行為難以預測。實際上並沒有錯:除了少數幾個,宿主對象是允許執行任何類型的運算行為的(按規範),如read(內部的[get]方法)、write(內部的[put]方法)或delete(內部的[delete]方法)。這個定製的[[Delete]]行為使得宿主對象如此混亂。

在IE中我們已經看到一些古怪的行為,如果刪除某些對象(明顯作為宿主對象來執行)將拋出錯誤。Firefox的一些版本在嘗試刪除window.location時將拋出錯誤。當涉及到宿主對象時,你不能信任delete返回的任何值。看看在Firefox會有什麼發生:

1 /* "alert" is a direct property of `window` (if we were to believe `hasOwnProperty`) */ 
2 window.hasOwnProperty('alert'); // true 
3 delete window.alert; // true 
4 typeof window.alert; // "function" 

 

 

刪除window.alert 返回true,雖然這個屬性什麼也沒有,它應該導致這個結果。它保留了一個引用(因此在第一步中不應該返回true),它是視窗對象的直接屬性(因此第二步中不能返回true)。唯一的辦法讓delete返回true是在第四步之後真正刪除屬性。但是,屬性是永遠不會被刪除的。

這個故事的寓意在於永遠不要相信宿主對象

ES5strict 模式

那麼,ECMAScript 5th edition 的strict 模式可以拿到檯面上來了。一些限制正被引入,當delete運算子是一個變數、函數參數或函數標識符的直接引用時將拋出SyntaxError。另外,如果屬性內部有[[Configurable]] == false,將拋出TypeError。

 

代碼

 1 (function(foo){ 
 2    "use strict"; // enable strict mode within this function 
 3     var bar; 
 4     function baz(){} 
 5     delete foo; // SyntaxError (when deleting argument) 
 6     delete bar; // SyntaxError (when deleting variable) 
 7     delete baz; // SyntaxError (when deleting variable created with function declaration) 
 8     /* `length` of function instances has { [[Configurable]] : false } */ 
 9     delete (function(){}).length; // TypeError 
10 })(); 

 

另外,刪除未聲明的變數(換句話說,沒有找到的引用)也拋出SyntaxError。

"use strict"; 
delete i_dont_exist; // SyntaxError 

 

正如你所理解的那樣,考慮到刪除變數、函式宣告和參數會導致如此多得混淆,所有這些限制就有點意義。與不聲不響的忽略刪除行為相反,strict 模式應該採取更積極的、更具有描述性的措施。

 

總結

這篇文章是冗長的,我打算去討論用delete刪除數組選項和它的含義。你可以隨時參考MDC 的文章瞭解具體的解釋(或閱讀規範,自己實驗)。

這是Javascript中delete運算子工作的簡短概要:

  • 變數和函式宣告要麼是啟用物件的屬性,要麼是全域對象的屬性;
  • 屬性有一些特性,其中之一就是DontDelete,它決定一個屬性是否能刪除;
  • 在Global 和Function code 中的變數和函式宣告總是有DontDelete特性;
  • 函數參數也是啟用物件的屬性,具有DontDelete特性;
  • 在Eval代碼中的變數和函式宣告總是建立沒有DontDelete特性的屬性;
  • 新的屬性總是帶有空的特性(因此沒有DontDelete特性);
  • 宿主對象允許對刪除作出反應,無論它們是否願意如此;

如果你想瞭解更多這裡這裡描述的東西,請參閱ECMA-262 3rd edition specification。

我希望你喜歡這篇綜述,並能學到新東西。任何疑問、建議、更正,一律歡迎。

相關閱讀:

  • delete Operator
  • delete Operator (Windows Scripting – JScript)

原文地址:Understanding delete
轉載地址:http://www.denisdeng.com/?p=858

 

發表評論
返回頂部 | 返回首頁
上一篇:轉:理解javascript中的delete機制(2)
下一篇:在 .NET Framework 2.0 中未處理的異常導致基於 ASP.NET 的應用程式意外退出
完整模式(顯示圖片和代碼)
查看原文

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.