Javascript 中的高阶函数

IT技术 javascript function higher-order-functions
2021-02-08 16:25:06

我正在阅读 Eloquent JavaScript(新版),我读到了关于高阶函数的部分,但我对以下代码中发生的事情感到困惑。

function noisy(f) {
  return function(arg) {
    console.log("calling with", arg);
    var val = f(arg);
    console.log("called with", arg, "- got", val);
    return val;
  };
}
noisy(Boolean)(0);
// → calling with 0
// → called with 0 - got false
  1. 为什么对函数的调用会像这样嘈杂?(Boolean) 是演员表吗?演员表干什么?返回值?还是论点?为什么不是 (Boolean)noisy(0) 如果它的返回值。如果参数是被转换的参数,则为noise((Boolean) 0)。

    noisy(Boolean)(0)
    
  2. 这条线发生了什么?f() 在哪里定义?

    var val = f(arg);
    
5个回答
  1. Boolean是一个函数。这是您通过 间接调用的函数noisy我知道这有点令人困惑,因为它看起来像一个类型的名称。但是在 JavaScript 中,那些最初被限制的东西(BooleanNumberString等)是函数当您调用Boolean(使用new) 时,它会尝试将您提供的参数转换为boolean原始值并返回结果。(请参阅规范中的第15.6.1 节。)

  2. fnoisy函数中参数的名称

JavaScript 中的函数是一流的对象。您可以将它们作为参数传递给其他函数,就像任何其他对象一样。

当你做

noisy(Boolean)(0)

有两件事正在发生。第一的:

// (In effect, we're not really creating a variable...)
var x = noisy(Boolean);

这给了我们一个函数,当被调用时,它将Boolean使用我们给它的参数调用,同时执行这些console.log语句。这是您在noisy( return function(arg)...)中创建的函数

然后我们调用该函数:

x(0);

这就是您看到控制台输出的时候。由于Boolean(0)is false,您会看到Boolean返回该值。

这是一个更简单的例子:

function foo(bar) {
    bar();
}
function testing() {
    alert("testing got called");
}
foo(testing);

在那里,我将函数传递testingfoo. 我在其中使用的参数名称foobar. 该行bar();调用该函数。

@ShirgillAnsari:规范中有详细说明var x = Number(5). 您将函数Number作为函数调用(而不是作为构造函数)。规范,当你这样做时,它会在必要时将它的参数转换为一个数字(更好的例子:)var x = Number("42")关于您的第二个警报,您为什么希望x成为一个函数?
2021-03-16 16:25:06
哦,我明白了,既然它已经被转换成一个原始的布尔值,这就是为什么你说为什么我希望 x 是一个函数?这是你的意思吗?
2021-03-19 16:25:06
@Crowder:但是如果那些最初被限制的东西(布尔值、数字、字符串等)是函数,为什么 var x = Number(5); 警报(x 类型);// 数字; 警报(x 函数实例);// 错误的
2021-03-25 16:25:06
@Crowder:哦,对不起,我犯了一个愚蠢的错误。因为我也在浏览你的回答(不是评论),所以我脑子里有布尔值旋转。
2021-03-28 16:25:06
@ShirgillAnsari:x从来不是函数,也不是布尔值。是号码5
2021-04-01 16:25:06

没有 () 的函数才是真正的函数。带有 () 的函数是对该函数的调用。还要记住,JavaScript 是一种松散类型的语言,因此您不要声明变量类型。我在您的示例中添加了一些注释以尝试提供帮助。

// We define a function named noisy that takes in an argument named f. We are expecting f to be a function but this isn't enforced till the interpreter throws an error. 
function noisy(f) {
// Noisy returns a single item, an anonymous function. That anonymous function takes in an argument named arg
  return function(arg) {
    console.log("calling with", arg);
// Our anonymous function then takes f (It can use f because its defined inside noisy, see closures for more details) and invokes it with the argument arg and stores the result in a variable named val. 
    var val = f(arg);
    console.log("called with", arg, "- got", val);
// It now returns val
    return val;
  };
}

那么noise(Boolean)(0) 的工作方式是这样的

f 是函数布尔值

嘈杂的返回这样的函数

function(arg) {
  var val = Boolean(arg);
  return val;
}

所以现在我们有

我们返回的函数(0)

它像正常一样执行成为

function(0) {
  var val = Boolean(0); // false
  return val;
}

我对 JS 比较陌生,我也刚刚阅读了 Eloquent Javascript,一旦我理解了函数的调用,我发现它更容易理解(回答你的第 1 点):

noisy(Boolean)(0);

Thenoisy(Boolean)创建一个新函数,然后在(0)它之后,因为它被作为参数传递给那个新函数。如果您参考大于示例:

function greaterThan(n) {
  return function(m) { return m > n; };
}
var greaterThan10 = greaterThan(10);
console.log(greaterThan10(11));

也可以这样调用:

greaterThan(10)(11);

我希望能澄清您关于为什么这样称呼它的第一个问题。

对于第二个问题。f在:

var val = f(arg);

输入Boolean传入函数然后它被用作嘈杂函数中的参数。我也没有意识到 Boolean 本身可以是一个函数,而不仅仅是一种数据类型。正如其他人所说 - 它将您提供的参数转换为布尔值并返回结果。noisynoisy(Boolean)

因此val成为Boolean(arg)which 成为Boolean(0)which 评估为false如果您尝试调用,noisy(Boolean)(1);您会看到它返回trueconsole.log("called with", arg, "- got", val);简单地记录(在此情况下0)参数和评价它(假)的结果。

实际上,它已将布尔函数更改为记录参数和结果并返回结果的函数。

我希望这有帮助。只是写它有助于我自己的理解。

Javascript 变量没有静态数据类型。也可以为它们分配不同数据类型的变量。

JS 中没有类型转换的概念,如 JAVA 等。

() 中的函数调用对应于函数的调用。

在这里,Boolean 似乎是一个高阶函数,它作为参数传递给有噪声的函数。噪声函数的结果将是

function(arg) {
  console.log("calling with", arg);
  var val = f(arg);
  console.log("called with", arg, "- got", val);
  return val;
};

带有 0 的第二个括号用于调用此结果。

在这里,在上面的函数中,注意下面的行。

var val = f(arg);

这里,f 对应于之前传递的布尔函数。arg 对应于 0。

由于返回了 val,因此表达式的结果将是 Booelan(0) 的结果。

如果你仍然有这个问题,这就是我的理解(它也让我头疼..)

function noisy(f) {
    return function(arg) {
        console.log("calling with", arg);
        var val = f(arg);
        console.log("called with", arg, "- got", val);
        return val;
    };
}

noisy(Boolean)(0)

函数只是一个常规值。上一句话是理解这里发生的事情的关键。

我们的 noise(f) 函数是一个值。这就是它返回的内容。

noise(f) 返回一个带有参数 (arg) 的函数。

noise(f) 也接受一个参数 (f)。内部函数(从函数内部调用的函数)可以访问传递给外部函数的变量和参数。

我们正在调用我们的外部函数并将参数布尔值传递给它。我们的外部函数返回它的内部函数,它接受一个参数 (0)。通过理解上面的内容,应该很清楚 Noise(Boolean(0)) 只会将一个参数传递给我们的外部函数,而不会将任何内容传递给我们的外部函数返回的内部函数。

真的很简单。现在我们理解了它,很难相信它让我们开始如此头疼...... */`