2014-06-09 57 views
4
function a(callback) { 
    var something = 10; 

    callback(something); 
} 

a(function(blabla) { 
    console.log(blabla); // output 10 
}); 

好吧,我沒有理解這段代碼的問題。回調函數,關閉和執行上下文

我知道「東西」是本地的function a和,但在關閉和事實,即執行上下文的意義創建函數調用時我的預期下也能正常工作:

function a(callback) { 
    var something = 10; 

    callback(); 
} 

a(function() { 
    console.log(something); 
}); 

那麼什麼恰好發生(爲什麼第二個例子不起作用)?
很明顯,所有東西都是垃圾收集,不能在回調函數體中訪問。

+0

那麼究竟發生了什麼(爲什麼第二個例子不工作)? – Srle

回答

1

函數只能引用在任何聲明的變量:

  1. 函數體,
  2. 函數參數(適用於第一個示例),
  3. 聲明函數的範圍。

換句話說,調用範圍沒有考慮在內,所以something被認爲是未定義的。

4

在第二個示例中,本地變量something在回調的主體中不可訪問,這不是因爲它是垃圾回收,而僅僅是因爲它超出了範圍。

考慮這個反例:

function a(callback) { 
    callback(); 
} 

var something = 10; 

a(function() { 
    console.log(something); 
}); 

這裏something在範圍在回調的身體被定義,所以你可以參考它的時間。這樣做會創建一個閉包。

還要考慮這一個:

function foo() { 
    var xyz = 1; 
    bar(); 
} 

function bar() { 
    console.log(xyz); 
} 

這在功能,你有同樣的例子:fooabar是通過作爲callback匿名函數。

爲什麼要調用bar()導致在這裏打印1?該變量在foo之內的本地範圍內,而bar對此一無所知。

1

在閱讀你的問題時,聽起來像這裏主要的困惑是爲什麼你可以在a裏面引用something,但是不在a提供的匿名函數中。

變量something定義在函數a的上下文中,而不在匿名函數內。因此,當您在匿名函數內引用something時,它實際上會引用一個隱式全局變量,在此情況下,該變量未被定義。匿名函數被放置在調用a的參數列表中的事實沒有區別。

function a(callback) { 
    var something = 10; 

    callback(); 
} 

function b() { 
    console.log(something); 
} 

a(b); 

所以,你可以清楚地看到這是兩個完全不相關的功能,用自己的範圍:

或許,如果你認識到,第二個片段是大致相當於它會更清楚。

1

在你的第一個例子: -

function a(callback) { 
    var something = 10; 

    callback(something); 
} 

a(function(blabla) { 
    console.log(blabla); // output 10 
}); 

布拉布拉是一個變量,它可作爲參數傳遞給該匿名函數。所以有些東西傳遞給回調函數作爲函數參數,因此可以在名稱blabla下運行。

但在第二個例子: -

function a(callback) { 
    var something = 10; 

    callback(); 
} 

a(function() { 
    console.log(something); 
}); 

東西是未知的功能它不是一個全局變量/不是一個函數參數。

因此,當您嘗試訪問未定義的變量時,這是一個js錯誤。

所以的東西範圍僅限於功能的,而不是提供給回調函數

0

簡短回答: 第二個示例中由回調創建的閉包將查找不存在的全局變量something

VS.第一個示例在函數a內圍繞變量something創建閉包。如果something的值發生了變異,再次調用a會產生不同的值。

考慮以下不同的方法來傳遞迴調函數:

var something = "Global something"; 

function a(callback) { 
    var something = "Local something"; 
    callback(something); 
} 

a(console.log); // "Local something" 

根據定義,console.log()將接受功能a作爲第一個參數,並把它打印輸出到屏幕上通過了something關閉發生在本地變量上。

a(function() {console.log(something)}); //"Global something" 

當你定義一個函數爲inline它會創建自己的範圍,並參照本地變量something

something通過函數傳遞a由於內聯函數沒有捕獲而被刪除。 在一些更嚴格的語言中,它會拋出一個錯誤,但JS不會。

內聯函數嘗試console.log本地變量something,找不到。搜索全局範圍並找到「全局」並打印出來。 本地變量沒有關閉。

a(function(x) {console.log(x)}); //"Local something" 

內聯函數創建並引用了局部變量x

但是x指向something變量通過函數a傳遞,它又指向「本地某事」,它將被打印。 關閉本地變量。