JavaScript函数式编程:函数基础 argumentsthisapply()call()

Posted homehtml

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript函数式编程:函数基础 argumentsthisapply()call()相关的知识,希望对你有一定的参考价值。

1 函数参数

函数的实参和形参个数可以不等,之所以会这样,原因是 ECMAScript 中的参数在内部是用一个数组来表示的。函数接收到的始终都是这个数组,而不关心数组中包含哪些参数(如果有参数的话)。如果实参个数大于形参个数,多余的实参不传递值,但是在arguments中可以访问;如果形参个数大于实参,没有传递值的实参将自动被赋予 undefined 值。

2 arguments和this

所有的函数调用都会传递两个隐式参数:arguments和this。
实际上,在函数体内可以通过 arguments对象来访问这个参数数组,从而获取传递给函数的每一个参数。arguments 对象只是与数组类似(它并不是 Array 的实例),因为可以使用方括号语法访问它的每一个元素(arguments[0]、argumetns[1]…),也使用 length 属性来确定传递进来多少个参数。

arguments对象的值永远与对应命名参数的值保持同步:

function doAdd(num1, num2) {
    arguments[1] = 10;
    alert(arguments[0] + num2);
}

因为 arguments对象中的值会自动反映到对应的命名参数,所以修改 arguments[1],也就修改了 num2,结果它们的值都会变成 10。不过,这并不是说读取这两个值会访问相同的内存空间;它们的内存空间是独立的,但它们的值会同步。另外还要记住,如果只传入了一个参数,那么为 arguments[1]设置的值不会反应到命名参数中(num2保持undefined)。这是因为 arguments 对象的长度是由传入的参数个数决定的,不是由定义函数时的命名参数的个数决定的。

this参数引用函数的上下文,函数上下文来自于Java等面向对象语言,Java中的this依赖于函数声明。但是和Java不同,JavaScript中的this依赖于函数的调用方式,因此把this称为调用上下文很合适。一般函数有四种调用方式:简单函数调用;对象方法调用;作为构造函数调用;通过apply()和call()调用。这四种方式的主要区别就在于调用上下文不同:简单函数调用的上下文是window对象,方法调用的上下文是对象,构造函数的上下文是是新创建的对象实例。这些调用中函数的this指向都是固定的,但是只有apply()和call()调用可以自主定义上下文。

3 apply()/call():在特定的作用域中调用函数。

区别在于接收参数的方式不同:apply(argu1,argu2),argu1是函数运行的作用域(this),argu2是参数数组,可以传入arguments 对象或者参数数组;call(argu1,argu2), argu1是this,argu2是逐个列出的函数参数。
如果你打算直接传入 arguments 对象,或者包含函数中先接收到的也是一个数组,那么使用 apply()肯定更方便;否则,选择 call()可能更合适。(在不给函数传递参数的情况下,使用哪个方法都无所谓。)
传递参数并非 apply()和 call()真正的用武之地;它们真正强大的地方是能够扩充函数赖以运行的作用域。使用 call()(或 apply())来扩充作用域的最大好处,就是对象不需要与方法有任何耦合关系。
技术图片

当需要为函数指定上下文时,就有必要使用apply()和 call()了,一个具体的例子就是回调函数。假如对数组中的每个元素进行一次操作,命令式编程方式一般使用for循环遍历数组元素,但是函数式编程是编写一个函数,然后对每个数组元素运行该函数,区别在于函数式编程更有利于代码复用。对每个数组元素运行该函数有两种思路,一种是把数组元素作为参数传入,一种是把数组参数作为函数运行的上下文,这时就可以用到apply()和 call()。

function forEach(list, callback){
for(var n=0; n<list.length; n++){
    callback.call(list[n], n);
    }
}
var colors = ["blue", "red","green"]; 
var res = [];
forEach(colors, function(index){
    res[index] = (this == colors[index]);
    return res;//true,true,true
});
alert(res);

使用callback回调函数的call方法,将当前数组元素作为第一个参数传入,将当前数组索引作为第二个参数传入,这使得当前元素变为函数上下文,索引值作为callback()的参数。在callback()内部验证当前元素是否是上下文。

4 没有重载(overloading)

ECMAScirpt函数没有签名,因为其参数是由包含零或多个值的数组来表示的。而没有函数签名,真正的重载是不可能做到的。如果在 ECMAScript 中定义了两个名字相同的函数,则该名字只属于后定义的函数。
函数重载定义:重载函数是函数的一种特殊情况,为方便使用,C++允许在同一范围中声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同,也就是说用同一个运算符完成不同的运算功能。这就是重载函数。重载函数常用来实现功能类似而所处理的数据类型不同的问题。

以上是关于JavaScript函数式编程:函数基础 argumentsthisapply()call()的主要内容,如果未能解决你的问题,请参考以下文章

翻译连载 | JavaScript 轻量级函数式编程-第2章:函数基础 |《你不知道的JS》姊妹篇

《JavaScript函数式编程思想》——列表

第1719期简明 JavaScript 函数式编程-入门篇

javascript进阶笔记

前端基础进阶:函数与函数式编程

为什么要在 JavaScript 中学习函数式编程?