返回函数的函数


110

我坚持“返回函数的函数”的概念。我指的是Stoyan Stefanov的《面向对象的Javascript》一书。

片段一:

    function a() {
      
        alert('A!');
    
        function b(){
            alert('B!'); 
        }
    
        return b();
    }
    
    var s = a();
    alert('break');
    s();

输出:

A!
B!
break

片段二

function a() {
  
    alert('A!');

    function b(){
        alert('B!'); 
    }

    return b;
}

var s = a();
alert('break');
s();
输出:

A!
break
B!

有人可以告诉我返回之间的差异b,并b()在上面的片断?


2
您会注意到第一个代码段在s()上给出了错误;
weirdalsuperfan '18

Answers:


122

向函数分配变量(不带括号)会将引用复制到该函数。将括号放在函数名称的末尾,将调用函数,并返回函数的返回值。

演示版

function a() {
    alert('A');
}
//alerts 'A', returns undefined

function b() {
    alert('B');
    return a;
}
//alerts 'B', returns function a

function c() {
    alert('C');
    return a();
}
//alerts 'C', alerts 'A', returns undefined

alert("Function 'a' returns " + a());
alert("Function 'b' returns " + b());
alert("Function 'c' returns " + c());

在您的示例中,您还在函数中定义函数。如:

function d() {
    function e() {
        alert('E');
    }
    return e;
}
d()();
//alerts 'E'

该函数仍可调用。它仍然存在。JavaScript一直在使用它。函数可以绕过只是像其他值。考虑以下:

function counter() {
    var count = 0;
    return function() {
        alert(count++);
    }
}
var count = counter();
count();
count();
count();

函数计数可以保留在其外部定义的变量。这称为关闭。它在JavaScript中也使用了很多。


片段一:var hero = {name:'Rafaelo',sayName:function(){return hero.name; },nayName:hero.sayName} hero.nayName(); 片段二:var hero = {name:'Rafaelo',sayName:function(){return hero.name; },nayName:this.sayName} hero.nayName(); 第一个代码段为我提供了正确的输出,而第二个代码段则没有给我正确的输出。为什么?问候。
Cafecorridor 2011年

this仅表示函数体内的某些内容,否则表示全局。您要说的this.sayName是想要sayName不存在的全局变量,它是未定义的,因此不可调用。
2011年

7
d()()使我感到困惑;首先但后来意识到,第一个()调用d,第二个()调用d的返回值,即e。
skud 2014年

1
八年后,这仍然有意义!
布拉德·范德

45

返回不带名称的函数名称()将返回对该函数的引用,您可以像使用那样进行分配var s = a()s现在包含对函数的引用b(),调用s()在功能上等同于调用b()

// Return a reference to the function b().
// In your example, the reference is assigned to var s
return b;

()在return语句中调用函数将执行该函数,并返回该函数返回的任何值。它类似于调用var x = b();,但不是分配您的返回值,b()而是从调用函数返回它a()。如果函数b()本身未返回值,undefined则在通过完成其他工作之后,调用将返回b()

// Execute function b() and return its value
return b();
// If b() has no return value, this is equivalent to calling b(), followed by
// return undefined;

1
在所有答案中,由于其简单性,我更喜欢您的答案。
阿纳·哈利洛夫

说得好!这个答案很容易理解。
AndrewSteinheiser '18 -10-15

感谢您验证有关该函数是否不返回值的位,该调用返回未定义。我最近发现了这种混乱:即使函数显式返回null,如果将返回的值赋给变量,它将是未定义的,而不是null。我想这会在某些代码库中引起很多奇怪的问题,因为null和undefined与===并非绝对等效。
本杰明

37

return b(); 调用函数b(),并返回其结果。

return b; 返回对函数b的引用,您可以将其存储在变量中以供以后调用。


17

返回b是返回一个函数对象。在Javascript中,函数就是对象,就像其他任何对象一样。如果发现没有帮助,只需将“对象”一词替换为“事物”。您可以从函数返回任何对象。您可以返回true / false值。整数(1,2,3,4 ...)。您可以返回一个字符串。您可以返回具有多个属性的复杂对象。您可以返回一个函数。功能只是一回事。

在您的情况下,返回b返回事物,该事物是一个可调用的函数。返回b()值返回可调用函数返回的值。

考虑以下代码:

function b() {
   return 42;
}

使用上面的定义,return b();返回值42。另一方面,return b;返回一个函数,该函数本身返回值42。它们是两个不同的东西。


4
它应该返回42;)
c69 2011年

4

当您返回时b,它仅是对函数b的引用,但此时未执行。

当您返回时b(),您正在执行该函数并返回其值。

尝试alert荷兰国际集团typeof(s)在您的例子。片段b将为您提供“功能”。摘要会给您带来什么?


第一个给出“未定义”。这是否意味着return b()完全没有用?同样,在第二个片段中,函数b是私有的。那么我们如何能够在函数外部访问引用?请提供给我一个链接,如果可能的话,可以清楚地解释这个概念。谢谢!
Cafecorridor 2011年

我得到了第一个答案。在函数b()中返回1 + 2,typeof显示数字。谢谢。
Cafecorridor 2011年

恭喜你弄明白了!至于私有函数:在第二个示例中,它并不是真正私有的,因为您已经返回了它。实际上,它已分配给s。尝试return this而不是return b……但是您可以做到s.b();)
vzwick 2011年

我一定会尝试的。尚未在Javascript中达到这个概念。也许过几天。谢谢!:)
Cafecorridor 2011年

函数a(){alert(“ A!”); 函数b(){alert(“ B!”); } return b; } var s = a(); 删除 s(); ----结束---- Javascript中的引用概念是否与Java中的相同?在这里,我删除了函数a(),但对s()的调用执行了b()。所以我可以说s包含b的副本并且没有指向a()中定义的b()吗?
Cafecorridor 2011年

2

将函数想象为类型,例如int。您可以在函数中返回整数。您也可以返回函数,它们是“函数”类型的对象。

现在的语法问题是:由于函数返回值,您如何才能返回函数而不是返回值?

通过省略括号!因为没有括号,该功能将无法执行!所以:

return b;

将返回“函数”(想象一下,就像您要返回一个数字一样),而:

return b();

首先执行该函数,然后返回通过执行该函数获得的值,这是很大的不同!


在第二个片段中,函数b是私有的。那么我们如何能够在函数外部访问引用?是否有任何规范相同的规则?
Cafecorridor 2011年

如果您共享JavaScript,则JavaScript中的对象(包括函数)将不再是私有的。
2011年

@Cafecorridor:如果私有函数由某个东西(一个公共函数)返回或被分配给一个公共变量(可以通过应用程序访问的变量),则可以轻松地执行yourvariable();,否则将返回的函数分配给变量,然后再次执行yourvariable();。
Francesco Belladonna

2

创建一个变量

var thing1 = undefined;

声明功能

function something1 () {
    return "Hi there, I'm number 1!";
}

警报的thing1(我们的第一个变量):

alert(thing1); // Outputs: "undefined".

现在,如果我们想thing1成为一个参考的作用something1,这意味着它会是同样的事情,我们创建的函数,我们会做:

thing1 = something1;

但是,如果我们需要函数的return ,则必须为它分配执行函数的返回值。您可以通过使用括号执行该函数:

thing1 = something1(); // Value of thing1: "Hi there, I'm number 1!" 

-1

片段一:

function a() {
  
    alert('A!');

    function b(){
        alert('B!'); 
    }

    return b(); //return nothing here as b not defined a return value
}

var s = a(); //s got nothing assigned as b() and thus a() return nothing.
alert('break');
s(); // s equals nothing so nothing will be executed, JavaScript interpreter will complain

语句“ b()”表示执行名为“ b”的函数,该函数显示带有文本“ B!”的对话框

语句“ return b();” 表示执行名为“ b”的函数,然后返回“ b”返回的函数。但是'b'不返回任何内容,因此该语句'return b()'也不返回任何内容。如果b()返回一个数字,那么“ return b()”也是一个数字。

现在,为's'分配了'a()'返回值的值,该值返回'b()',它什么都不是,所以's'无关紧要(在JavaScript中,这实际上是一件事,它是“未定义”。)当您要求JavaScript解释“ s”是什么数据类型时,JavaScript解释器会告诉您“ s”是未定义的。)由于“ s”是未定义的,因此当您要求JavaScript执行此语句“ s()”时,您要让JavaScript执行名为“ s”的函数,但是这里的“ s”是“未定义”而不是函数,因此JavaScript会抱怨:“嘿,s不是函数,我不知道如何与“ s”有关,那么JavaScript将显示“ Uncaught TypeError:s is a function”错误消息(在Firefox和Chrome中测试)


片段二

function a() {
  
    alert('A!');

    function b(){
        alert('B!'); 
    }

    return b; //return pointer to function b here
}

var s = a();  //s get the value of pointer to b
alert('break');
s(); // b() function is executed

现在,函数“ a”返回指向名为“ b”的函数的指针/别名。因此,当执行's = a()'时,'s'将获得指向b的值,即's'现在是'b'的别名,调用's'等于调用'b'。即's'现在是一个函数。执行's()'意味着运行函数'b'(与执行'b()'相同),显示“ B!”的对话框 将会出现(即运行'alert('B!');函数'b'中的语句)


-2

这在现实生活中超级有用。

使用Express.js

因此,您的常规express路线如下所示:

function itWorksHandler( req, res, next ) {
  res.send("It works!");
}

router.get("/check/works", itWorksHandler );

但是,如果您需要添加一些包装器,错误处理程序或smth怎么办?

然后,通过包装器调用函数。

function loggingWrapper( req, res, next, yourFunction ) {
  try {
    yourFunction( req, res );
  } catch ( err ) {
    console.error( err );
    next( err );
  }
}

router.get("/check/works", function( req, res, next ) {
  loggingWrapper( req, res, next, itWorksHandler );
});

看起来复杂吗?好吧,这呢:

function function loggingWrapper( yourFunction ) => ( req, res, next ) {
  try {
    yourFunction( req, res, next );
  } catch ( err ) {
    console.error( err );
    next( err );
  }
}

router.get("/check/works", loggingWrapper( itWorksHandler ) );

最后,您将传递一个loggingWrapper具有一个参数的函数作为另一个函数itWorksHandler,然后loggingWrapper返回一个以req, res, next参数为参数的新函数。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.