2011-04-23 80 views
3

我有這個令人難以置信的簡單的例子,如果沒有回報功能的工作原理和失敗,它:是做什麼用回用JavaScript語言

function hello() { 
    alert('hello'); 
} 

function hi() { 
    return function() { 
     alert('hi'); 
    } 
} 

我知道,做hi()();我能夠運行第二個功能,但我很少在代碼中看到這一點。我怎麼能做到沒有這樣做的回報功能,因爲我看到人們一直這樣做。

+1

你究竟想在這裏完成什麼? 'hi()'函數工作得很好,它返回一個完全按照它設計的函數。你可以用'hi()()'直接執行返回的函數,或者你可以用返回的函數做其他事情(就像函數返回的任何值一樣)。你的問題到底是什麼? – David 2011-04-23 11:53:00

+0

我想知道如何在不執行()()的情況下返回此函數;因爲我看到人們總是這樣做。 – 0x499602D2 2011-04-23 11:56:01

+1

您已經在返回該功能。這就是爲什麼'hi()()'做它的功能。 'hi()'返回一個函數。 'hi()()'返回並隨後執行一個函數。您可以使用該返回的函數執行任何操作,包括執行它。如果你只是想在不立即執行的情況下返回它,只需調用'hi()'並將返回的值賦給一個變量。 – David 2011-04-23 11:59:13

回答

5

爲了它的最好的,你必須放在一起三兩件事:數據類型,函數的執行(或調用在一些消息來源),和範圍&關閉。

我將在這裏把最簡單的觀點:

首先 - 你需要了解的是JavaScript中返回的值和數據類型的問題。

JavaScript中的任何表達式都計算爲下列其中一種數據類型,併成爲用於進一步計算的另一個表達式的一部分(其中,最常見的觀察值被分配到變量中,下一個常量返回爲函數的返回值): number,string,boolean,objectundefined - 和 - function。 (也有一些僞類型 - 如InfinityNaN,但現在放棄它,稍後再google)。

JavaScript中的每個表達式都有一個返回值。 的表達。真。有時候這個值只是undefined - 但這也是一個返回值。但是,每個表達式都有一個返回值 - 這包括函數的定義。沒有太大的區別:

function foo(){} 

foo = function(){} 

(並隨時回答有用,我會避免討論這兩種形式之間的差異)。

這導致下一個主題 - 在JavaScript中執行函數。

在上面的例子中,返回的值是一個函數引用,您可以稍後使用()運算符執行。是 - 運營商()是一個運算符,它執行引用後面的代碼,同時爲其提供參數堆棧,其參數值爲()中提供的值。

在這種SENCE,宣告foo功能,並保持它現有的變量foo後 - 你可以再打foo()就像你喜歡的 - 那是因爲foo是保存到函數的引用一個變量,它可以稍後執行 - 只要變量foo未被另一個值覆蓋或被該名稱中的更多局部變量隱藏。

要強調的是:打電話foo()首先評估什麼foo手段,然後運行它作爲空參數函數棧(因爲它是foo(),而不僅僅是foo) 在這種SENCE,你能評價一下foo()是什麼,然後把它作爲一個函數來運行 - 就像你原來的例子foo()()一樣。你知道嗎?您可以繼續:foo()()()foo()()(),但是 - 請注意,一旦您嘗試操作的評估表達式()不是函數引用,您將獲得豁免。

這就是爲什麼你可以看到像

obj[ handler ](42); 

或者更糟

obj[ getHandlerName(handler) ] (42); 

(保持短我會解釋只有第一)代碼 - 這將首先評估哪些obj是,再假設它是一個對象並評估obj[ handler ],然後假定它是一個函數並嘗試執行它作爲obj[ handler ](42) - 將它作爲單個參數傳遞給42。請注意,handler是一個變量名,可以包含任何值,在這個意義上,它將作爲字符串嘗試(或使用它的toString()方法的返回值 - 因爲[]也是一個運算符,但這是一個主題一個不同的職位)。

該參數堆棧由函數的執行所隱含,並且對函數提供的參數的數量或類型以及函數實際期望的數量和類型沒有限制。

在執行過程中傳遞給函數的所有參數都可以使用隱含的參數arguments來訪問,該參數是一個僞數組結構 - 最好僅作爲參數堆棧進行描述... 爲什麼僞?除了屬性length以及索引器訪問(即參數[0],參數[1]等)之外,它不回答Array提供的任何API。

一個函數可以爲它希望使用的參數定義變量名稱,這些將根據參數變量名稱中的0-索引位置對應於arguments[n]

現在,如果一個函數是一個數據類型,它可以被返回並在以後執行。在這種SENCE,沒有

function a(){ 
    return function b(){} 
} 

function a(){ 
    function b(){} 
    return b; //pay attention - no braces = don't execute b, return the func-ref. 
} 

function a(){ 
    var b = function(){} 
    return b; 
} 

其實,最後在這裏太大differene被認爲是骯髒的,接下來的問題將幫助你明白爲什麼。

第二件事 - 範圍和結束。

在JavaScript中,變量的作用域是定義它們的函數。 (對於來自其他語言的程序員而言,變量是有限的,變量被限制在它們被定義的塊中 - 這個限制不適用於JavaScript。範圍僅限於函數體)。

從這個意義上說,最高級別AKA「root」或「main」 - 是定義全局變量的最高級別。這意味着在根上定義的變量和函數可以被執行的所有代碼訪問,因此可以充當全局變量。

當一個函數的執行在其內部定義了其他函數並「公佈」它們中的一個或多個時 - 通過將它們分配給一個全局變量或通過返回一個函數引用它首先調用了定義函數。

現在,由於如上所述 - 函數的每次執行都定義了至少一個名爲arguments的變量 - 除了變量名稱之外,它還被定義爲 - 變量名稱可由任何函數的任何代碼訪問在其中定義 - 或通過執行定義的函數來定義(或通過執行由執行定義的函數來定義的函數來定義,或者通過執行...來定義)你明白了)。

這意味着:

var G = "global" 
function a(x,y){ 
    var h = "local to closure a" 
    , z = function(){ 
       var k = "local to this function" 
       //code here can access G 
       //code here can access k 
       // - and x and y - and - h and z! 
      } 
    ; 
    return z; 
} 

這非常有趣的用法打開空間 - 這樣可以訪問其保存從檢索回調ž傳給而參數定義的私有狀態的局部變量的回調函數它。

我希望它把一些東西放在一起就夠了:)

12

返回函數可以緩存來自第一個被調用函數的一些變量,然後您可以稍後在返回函數中執行某些操作。

例如,

function hi(lastName) { 
    return function(firstName) { 
     alert('hi ' + firstName + lastName); 
    } 
} 

var chen = hi("Chen"); 
chen("Jumper"); 
chen("Dennis"); 
+0

+1這就是爲什麼返回函數有用。 – Flash 2011-04-23 12:00:03

+0

+1緩存功能非常有用 – ezmilhouse 2011-04-23 12:06:42

+0

是的,我們在我們的框架中使用了很多。 (ZK) – jumperchen 2011-04-23 12:08:05

1

自我執行和回調函數都是很常見的做法。

查找工作樣本這裏: http://jsfiddle.net/ezmilhouse/9BbGC/

// self executing 

function hi(text) { 
    return (function(text) { 
     alert(text); 
    })(text); 
} 

hi('ho'); 

// callback 

function ho(callback){ 
    callback(); 
} 

ho(function(){ 
    alert('ha'); 
});