Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/xslt/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
需要帮助理解JavaScript中的函数调用吗_Javascript - Fatal编程技术网

需要帮助理解JavaScript中的函数调用吗

需要帮助理解JavaScript中的函数调用吗,javascript,Javascript,我很难理解书中的一些示例代码(在线版免费) 示例代码是用于计算给定直径的周长的函数。它显示了用名称绑定值的不同方法。根据这本书,一种方法是: ( (diameter) => ((PI) => diameter * PI)(3.14159265) )(2); // calculates circumference given diameter 2 它还指出: 嗯,这样做的缺点是,调用函数通常比计算表达式要昂贵得多。每次调用外部函数时,我们都会调用内部函数。我们可以通过写作来解决

我很难理解书中的一些示例代码(在线版免费)

示例代码是用于计算给定直径的周长的函数。它显示了用名称绑定值的不同方法。根据这本书,一种方法是:

(
 (diameter) =>
  ((PI) => diameter * PI)(3.14159265)
)(2);
// calculates circumference given diameter 2
它还指出:

嗯,这样做的缺点是,调用函数通常比计算表达式要昂贵得多。每次调用外部函数时,我们都会调用内部函数。我们可以通过写作来解决这个问题

我无法理解它是如何通过调用两个函数来避免这种情况的,这两个示例中不是都有两个函数调用吗?
它们之间有什么区别?

这本书可能会建议JavaScript编译器更可能在第二种方法中使用PI函数。但这只有在我们使用不同的动态直径多次调用这些方法时才有意义。否则,编译器也可能内联diameter函数

归根结底,从性能角度看,真正重要的是JavaScript引擎到底在用这些函数做什么

下面的测试表明,这两种方法几乎没有任何区别。至少在我的盒子上

您可能希望执行更多的迭代,但请注意,这显然是非常缓慢的

//这是一个热身,以确保两个方法都通过
//即时(JIT)编译,适用于以这种方式进行编译的浏览器。
试验1(1E5);
试验2(1E5);
//进行实际测试
log('Method#1:'+test1(1E6).toFixed(2)+'ms');
log('Method#2:'+test2(1E6).toFixed(2)+'ms');
功能测试1(iter){
var res,n,ts=performance.now();
对于(n=0;n((圆周率)=>直径*圆周率)(3.14159265)
)(Math.random()*10);
}
返回性能。now()-ts;
}
功能测试2(iter){
var res,n,ts=performance.now();
对于(n=0;n(直径)=>直径*圆周率)(3.14159265)
)(Math.random()*10);
}
返回性能。now()-ts;

}
这看起来可能有点让人困惑,因为我认为它解释得不太清楚。或者,更确切地说,我不认为它是用典型的JavaScript方式解释的

让我们把这些例子分解一下

第一个例子 崩溃 这样安排的话,如果你调用这个代码

  • 通过直径(例如,2)
  • 创建了一个新函数,该函数将
    PI
    作为参数,并使用它来计算周长。此函数立即被调用
  • 该函数使用当前的两个变量进行计算
  • 除了浪费计算(两次调用)之外,这个例子也没有很好的理由令人费解。内部函数是毫无意义的,不会给您带来任何好处。这可能是示例失去了很多清晰性的地方——似乎让示例保持原样的唯一原因是为第二个示例设置

    第二个例子 论咖喱 在讨论这个例子之前,这本书似乎没有提到它到底是如何工作的。第二个示例利用了函数式编程中使用的一种称为
    curry
    的技术——它并不特定于JavaScript,但在JavaScript世界中仍被广泛称为该名称。对咖喱的简要概述

    //non-curried
    function add(a, b) { // or, in ES6: (a, b) => a + b;
        return a + b;
    }
    
    //curried
    function curryAdd(a) { //or in ES6: (a) => (b) => a + b;
        return function(b) {
            return a + b;
        }
    }
    
    //invocation
    add(2, 3); // 5
    curryAdd(2)(3); // 5
    
    我将不详细介绍,但本质上,一个接受多个参数的curried函数可以传递得更少,它将返回一个可以接受其余参数的新函数。当所有参数都满足时,您将得到结果-在形式表示法中,
    curryAdd
    函数将表示为
    curryAdd::Number->Number->Number
    -这是一个函数,它接受一个数字并返回另一个函数,该函数接受一个数字,最后返回另一个数字。关于你为什么要这样做,这里有一个例子——虽然很琐碎,但它的要点是:

    //add5:: Number -> Number
    add5 = curryAdd(5);
    
    add5(3); // 8
    add5(10); // 15
    [1, 2, 3].map(add5); // [6, 7, 8]
    
    Currying有点像函数的部分分配,但是

    崩溃 话虽如此,我们来看第二个例子:

    //curryMultiply :: Float -> Float -> Float
    (PI) => (diameter) => diameter * PI
    //another way to write it:
    //(a) => (b) => a * b
    
    希望这能澄清一下到底发生了什么。我将把示例的其余部分重新写入实际发生的情况:

    // calculateCircumference :: Float -> Float
    var calculateCircumference = curryMultiply(3.14159265);
    
    calculateCircumference(2); //6.2831853
    
    第二个示例的代码与上面的代码相同。它避免了调用函数两次,因为外部函数(我称之为curryMultiply)只被调用一次-无论何时调用
    calculateCircumference
    函数,您都只是在计算内部函数。

    您应该看看(IIFE);那是一个

    基本上:您声明一个函数并立即调用它。。。这有时被用作创建词法范围的权宜之计,只是为了避免全局变量

    //我们自信的方式。。。
    函数logFoo(){console.log(1,'FOO');}
    logFoo();
    //使用和生活
    (function(){console.log(2,'FOO');}());
    //或者为了更好的可读性
    
    (function(){console.log(2,'FOO');})()我认为重点放在短语“每次调用外部函数…”上,这确实令人困惑,因为外部函数在示例中只调用一次(作为IEFE)。通过这个例子,人们应该能够更好地理解差异:

    const circumference = (diameter) => 
      ((PI) =>
        diameter * PI
      )(3.14159265);
    console.log(circumference(2));
    console.log(circumference(5));
    

    但显然,作者不想在这里引入变量声明,所以可能会编写它

    ((circumference) => {
      console.log(circumference(2));
      console.log(circumference(5));
    })(((PI) =>
      (diameter) =>
        diameter * PI
    )(3.14159265));
    

    同样的效果:-)

    我可能弄错了,但据我所知,他们只是改变了函数的顺序,实际上并没有在性能方面节省任何东西。说一个比另一个“贵得多”有些误导。除了一小部分例外,这根本没有实际意义。我不会相信一本作者似乎不知道的书
    const circumference = (diameter) => 
      ((PI) =>
        diameter * PI
      )(3.14159265);
    console.log(circumference(2));
    console.log(circumference(5));
    
    const circumference = ((PI) =>
      (diameter) =>
        diameter * PI
    )(3.14159265);
    console.log(circumference(2));
    console.log(circumference(5));
    
    ((circumference) => {
      console.log(circumference(2));
      console.log(circumference(5));
    })(((PI) =>
      (diameter) =>
        diameter * PI
    )(3.14159265));