2011-04-23 45 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'); 
});