JavaScript中使用的返回函数是什么

JavaScript中使用的返回函数是什么,javascript,Javascript,我有一个非常简单的例子,它在没有返回函数的情况下工作,但失败了: function hello() { alert('hello'); } function hi() { return function() { alert('hi'); } } 我通过做hi()()我能够运行第二个函数,但我很少在代码中看到这一点。如果不这样做,我怎么能做返回函数呢?因为我看到人们总是这样做。返回函数可以缓存第一个调用函数中的一些变量,然后您可以在以后对返回函数执行一

我有一个非常简单的例子,它在没有返回函数的情况下工作,但失败了:

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

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

我通过做
hi()()我能够运行第二个函数,但我很少在代码中看到这一点。如果不这样做,我怎么能做返回函数呢?因为我看到人们总是这样做。

返回函数可以缓存第一个调用函数中的一些变量,然后您可以在以后对返回函数执行一些操作

比如说,

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

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

自执行函数和回调函数都是非常常见的方法

在此处查找工作示例:


为了充分利用它,您必须将三件事放在一起:数据类型、函数执行(或某些源中的调用)以及范围和闭包

我将尝试在这里提出最简单的观点:

首先,您需要了解JavaScript中返回值和数据类型的问题

JavaScript中的任何表达式都计算为以下数据类型之一,并作为另一个表达式的一部分进行进一步计算(我观察到的最常见的表达式被赋给变量,下一个常见的表达式作为函数的返回值返回):
数字
字符串
布尔值
对象
未定义
-和-
函数
。 (也有一些伪类型,比如
Infinity
NaN
,但是现在就离开它,以后用谷歌搜索它)

JavaScript中的每个表达式都有一个返回值每个表达式。真正地有时该值只是
未定义
——但这也是一个返回值。但是,假设每个表达式都有一个返回值,其中包括函数的定义。以下各项之间没有太大区别:

function foo(){}

(为了使答案有用,我将避免讨论这两种形式之间的区别)

这就引出了下一个主题——JavaScript中函数的执行

在上面的示例中,返回的值是一个函数引用,您可以稍后使用
()
操作符执行该引用。是-操作员
()
是一个运算符,它执行引用后面的代码,同时为引用提供一个参数堆栈,其中包含
()
中提供的值

在这种情况下,在声明
foo
函数并在变量
foo
上保持其可用性之后,您以后可以随意调用
foo()
,这是因为
foo
是一个包含函数引用的变量,只要变量
foo
没有被另一个值覆盖或被该名称中更局部的变量隐藏,就可以在以后执行

要强调的是:调用
foo()
首先要评估
foo
的含义,然后将其作为带有空参数堆栈的函数进行操作(因为它是
foo()
,而不仅仅是
foo
) 在这种情况下,您可以评估什么是
foo()
,然后将其作为函数进行操作,就像您最初的示例
foo()()
中那样。你知道吗?您可以继续这样做:
foo()()
foo()()
,但是,请注意,一旦您尝试操作的计算表达式不是函数引用,您将得到一个exeption

这就是为什么你可以看到这样的代码

 obj[ handler ](42);
或者更糟

 obj[ getHandlerName(handler) ] (42);
(简而言之,我只解释第一个)-它将首先计算什么是
obj
,然后假设它是一个对象并计算
obj[handler]
,然后假设它是一个函数并尝试作为
obj[handler](42)
-将其作为单个参数传递42。请注意,handler是一个变量名,可以包含任何值,从这个意义上讲,它将作为字符串进行尝试(或者使用它的toString()方法的返回值-因为[]也是一个运算符,但这是另一篇文章的主题)

此参数堆栈由函数的执行暗示,并且对于提供给函数的参数的数量或类型以及函数实际期望的数量和类型没有限制

在执行过程中传递给函数的所有参数都可以使用隐含参数
arguments
,这是一个伪数组构造-最好简单地描述为参数堆栈。。。 为什么是假的?它不响应数组提供的任何API,除了属性
length
和索引器访问(即参数[0]、参数[1]等等)

函数可以为它希望使用的参数定义变量名,这些变量名将对应于
参数[n]
,与参数变量名中的0索引位置一致

现在,如果函数是数据类型,则可以在以后返回并执行。从这个意义上讲,两者之间没有太大区别

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

事实上,这里最后一个被认为是肮脏的,下一个问题将帮助你理解为什么

第二件事——范围和结束

在JavaScript中,变量的作用域是定义变量的函数。(对于来自其他语言的程序员来说,这是一个令人困惑的问题,因为在这些语言中,变量被限制在定义它们的块中——这个限制不适用于JavaScript。具有作用域含义的块只是函数体)

从这个意义上说,最顶层,即“根”或“主”是定义全局的最高层。这意味着在根上定义的变量和函数可以被执行的所有代码访问,因此充当全局变量

闭包是指函数的执行在其内部定义了其他函数,并通过将它们赋给全局变量或返回函数引用来“公布”其中一个或多个函数,该函数引用随后由调用定义函数的代码保存

现在,如上所述
 obj[ getHandlerName(handler) ] (42);
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;
}
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;
}