2015-06-09 21 views
4

這些是兩個相同的代碼;但第一個正常工作:`setTimeout`,通過字符串傳遞,返回錯誤

function dismiss(obj) {setTimeout(function() {obj.style.display = "none";}, 20);} 

,而第二個返回error: obj is not defined

function dismiss(obj) {setTimeout('obj.style.display = "none"', 20);} 

爲什麼會這樣呢?
P.S:An example

+1

我猜是因爲它沒有捕獲閉包並在全局範圍內執行。 –

+2

_Why爲什麼這麼做?_ - 因爲在第一個版本中,匿名函數創建一個閉包,因此在本地作用域中保留對「obj」的引用,而第二個在全局對象的作用域中運行。 – CBroe

+0

其實這兩個工作適用於我在Firefox 38.0.5 – AlliterativeAlice

回答

4

答案在於closures,or more in depth

在第一個示例中,創建匿名函數時將捕獲obj變量。當運行該功能時,捕獲的obj參考用於訪問style,該工作正常。

在第二

然而,沒有閉合,因爲字符串是通過eval運行內部setTimeout其上Mozilla documentation如所述的,將全局上下文內執行:

字符串文本中被評估全局上下文,因此setTimeout()被調用的上下文中的局部符號在字符串被評估爲代碼時將不可用。

在全球範圍內不包含obj變量,這導致了「沒有定義」錯誤。

+0

閉包的更詳細解釋:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures –

+0

@FelixKling,謝謝,認爲應該有更詳細的解釋。 – crazyhatfish

+0

不錯。比我的答案更清楚。 – Lambart

2

obj只存在於dismiss()功能在它的範圍和一切。第一條語句定義了一個函數,所以它可以引用它。第二個語句在該範圍之外執行,不能引用它。

-6

正確的代碼應該是這樣的:

function dismiss(obj) {setTimeout(obj.style.display = "none", 20);} 

因爲你在第一個和最後的obj.style.display = "none"添加'因此,它將成爲一個字符串。

+1

這並不回答這個問題這是錯誤的。像那些未包含在函數中的語句會立即執行或評估。 – Xufox

+1

此外,這就像是傳遞''none''作爲第一個參數。然而,'none'不是一個函數或沒有定義。 – Xufox

1

documentation

Code executed by setTimeout() is run in a separate execution context to the function from which it was called. As a consequence, the this keyword for the called function will be set to the window (or global) object; it will not be the same as the this value for the function that called setTimeout.

在兩個示例中,超時碼的範圍是全球範圍內,或window

在第一個示例中,上下文無關緊要,因爲obj.style.display在觸發超時之前不進行評估。那時候,obj有最初傳遞給dismiss的任何值,並且一切正常。

在第二個示例中,代碼立即執行,其中在全局window範圍內的obj未定義(或者如果已定義,則此時不是您所期望的),因此您已生成此代碼代碼:

function dismiss(obj) {setTimeout(function() { undefined = "none" }, 20);}