2011-05-13 64 views
3

比較這段代碼刪除:有人可以解釋這種行爲

somevar = 5; 
    delete window.somevar; 
    alert(typeof somevar) //=> undefined, so deleted 

這段代碼:第一塊

var somevar = 5; 
    delete window.somevar; 
    alert(typeof somevar) //=> number, so NOT deleted 

See it in action here

現在,somevar是刪除,在第二個塊它不是。唯一的區別是在第二個塊中使用var關鍵字。這兩個塊都在全局範圍內運行。

這可以解釋嗎?

代碼不能在鉻控制檯或螢火中的jsfiddle任一測試,並且不。在這些環境中,所有代碼都是evalled,並且在代碼delete中的任何代碼均適用於eval(請參閱more about that)的結果。無論如何,在IE 是不允許的。

回答

10

你所看到的事實是全局對象(window,在瀏覽器上)是兩個不同事物的混合,除了全局執行上下文外,它們是獨特的。

在第一塊,someVarwindow對象的正常特性。屬性可以通過delete刪除。

在第二塊中,someVar結合對象全局執行上下文  —這也是window可變上下文的性質。您無法刪除綁定對象在其作爲綁定對象的角色中接收的屬性(即使您可以刪除以其他方式接收的屬性)。也就是說,您不能刪除使用var聲明的變量(以及其他一些以相同方式添加的內容)。

(對不起,不是我的術語,它來自the spec,這的確具有一些非常有趣的語言。)

這只是我們有這個概念混爲一談全球執行上下文。其他執行上下文(例如函數調用)的變量綁定對象仍然是一件非常真實的事情(並且對於閉包的正常運行至關重要),但是沒有直接訪問它的程序化方法。然而,在全局執行上下文中,它是全局對象,我們當然可以訪問它。

如果我們先看看函數,然後再看看全局執行上下文,它有助於理解這一點。當你調用一個函數,這些事情發生:

  1. 設置this指向通過調用指定的對象(的this值通常是隱式設置,但有辦法來設置它明確)。
  2. 爲此調用創建一個執行上下文
  3. 創建該執行上下文變量上下文
  4. 該變量上下文創建結合對象
  5. 將函數的名稱(如果有)添加到綁定對象作爲引用該函數的屬性。
  6. arguments屬性添加到綁定對象,參照參數的僞陣列的功能。
  7. 將函數定義中聲明的任何命名參數添加爲綁定對象的屬性,並引用它們在參數中的條目。
  8. 與價值undefined添加的通過var報表(任何地方函數體)作爲綁定對象的屬性聲明的任何變量的名稱,最初。
  9. 如果在函數中聲明瞭命名函數,請將它們的名稱作爲綁定對象的屬性添加,並引用這些函數。
  10. 把綁定對象在範圍鏈(詳見下文)的頂部。

...然後逐步執行函數體內的代碼開始。任何var語句帶有初始值(例如,var a = 5;而不僅僅是var a;被視爲賦值語句(a = 5;)當執行點到達他們。

縱觀上述,只要屬性添加「到綁定對象」,它的加入一個標誌,表明它不能被刪除。這就是爲什麼var S(和聲明的函數等的名稱)不能被刪除。

任何不合格的參考通過作用域鏈擡頭。所以,當您在代碼中引用a時,解釋器看起來的第一個位置是位於頂部的綁定對象範圍鏈。如果它有一個名爲a的屬性,那就是被使用的;如果不是,我們查看範圍鏈中的下一個鏈接,如果我們找到它,則使用該屬性;依此類推,直到我們用盡範圍鏈上的鏈接。全局對象是該鏈最底層的鏈接(這就是全局變量工作的原因)。

那麼全球環境有什麼不同呢?其實,很少。下面是序列(大致):

  1. 爲此調用創建一個執行上下文
  2. 創建該執行上下文變量上下文
  3. 爲該變量上下文創建一個綁定對象
  4. 設置this指向綁定對象;這使其成爲全球性的對象。
  5. 根據環境的定義在該對象上設置一些默認屬性(在瀏覽器中,例如,將屬性window添加到對象中,引用自身)。

...然後我們基本上拿起第8步中的函數的東西:

  • 添加的通過var報表(任何地方在全球範圍內)作爲綁定/全局對象的屬性聲明的任何變量的名稱,最初值爲undefined
  • 如果在全局範圍內聲明瞭命名函數,請將它們的名稱作爲綁定/全局對象的屬性添加,並引用這些函數。
  • 將綁定/全局對象置於範圍鏈(更多下方)的頂部。

...並開始逐步執​​行代碼(同樣使用var初始值設定項成爲賦值)。

+0

謝謝TJ。隨着你的回答,結合ECMA規範,我開始明白,爲什麼'eval'-ed代碼變量可以被刪除。假設這觸及了它:*如果一個VariableDeclaration嵌套在with語句中,並且VariableDeclaration中的標識符是與with語句的對象環境記錄的綁定對象的屬性名稱相同的 ,則步驟4 將賦值給屬性,而不是標識符的變量環境綁定。* – KooiInc 2011-05-13 09:14:49

+0

@KooiInc:LOL,這裏我避免談論'with'語句。順便說一下,我在上面添加了一些進一步的解釋。 – 2011-05-13 09:19:08

+0

確實很有趣。也許我們應該把它歸結爲:*如果你不使用var,我們隱含地假設你的意思是:'with(this){somevar = [assignment];}',相當於'this.somevar = [賦值] '*?無論如何,讓我們先接受你的回答;) – KooiInc 2011-05-13 09:34:01

相關問題