2015-03-19 58 views
1

有人能爲我澄清這一點嗎?JavaScript關閉和回調函數

JavaScript中我最喜歡的兩個特性是閉包和函數是第一類對象的事實。

如果我想利用閉包,比如回調函數,那麼函數必須始終是一個內部函數。例如:

doNested(); 
function doNested() { 
    var message='Hello'; 
    window.setTimeout(inner, 3000); 
    function inner() { 
     alert(message); 
    } 
} 

我無法將參數傳遞給外部回調函數。例如:

doSeparated(); 
function doSeparated() { 
    var message='Goodbye'; 
    window.setTimeout(outer,3000); 
} 
function outer() { 
    alert(message); 
} 

當然這不起作用。

問題是,有沒有辦法將內部變量傳遞給這樣一個外部函數,而不是將它們添加到參數列表中?

感謝

+0

將數據作爲參數傳遞給函數是很常見的。 – zerkms 2015-03-19 07:17:29

回答

1

如果我想利用封閉的,比方說,一個回調函數,則該函數必須始終是一個內部函數。

這是正確的。 JavaScript中的每個函數只能訪問這些變量,這些變量既可以在其自己的作用域中定義,也可以在父範圍中定義,即。因此,你的第一個例子工作,而你的第二個例子不工作。

問題是,有沒有辦法將內部變量傳遞給像這樣的外部函數,而不是將它們添加到參數列表中?

不,沒有辦法做到這一點。那麼,從技術上講,你可以將你的內部變量添加到一個對象,然後bind對象的外部函數,然後你可以訪問外部函數的this上下文中的內部變量,但這並不比將變量傳遞給函數更好直。

doSeparated(); 
 

 
function doSeparated() { 
 
    var message = "Goodbye"; 
 

 
    setTimeout(outer.bind({ 
 
     message: message 
 
    }), 3000); 
 
} 
 

 
function outer() { 
 
    alert(this.message); 
 
}

由於您使用setTimeout,你可以通過額外的參數給setTimeout將被提供給回調函數。這擺脫了討厭的bind的:

doSeparated(); 
 

 
function doSeparated() { 
 
    var message = "Goodbye"; 
 
    setTimeout(outer, 3000, message); 
 
} 
 

 
function outer(message) { 
 
    alert(message); 
 
}

注意的setTimeoutbind和額外的參數並不在舊版本的IE瀏覽器的工作。在這種情況下,你可以使用鑽營,而不是(在我的愚見是從原始的嵌套解決方案預留了最好的解決方案):

doSeparated(); 
 

 
function doSeparated() { 
 
    var message = "Goodbye"; 
 
    setTimeout(outer(message), 3000); 
 
} 
 

 
function outer(message) { 
 
    return function() { 
 
     alert(message); 
 
    }; 
 
}

除了這些以外,有沒有其他好的解決方案,我能想到。最好的解決方案是您的原始嵌套解決方案。


函數沒有訪問在子域中定義的任何變量,否則你將能夠從全球範圍內訪問的每一個變量。