JavaScript函数式编程(0):函数基础 arguments、this、apply()、call()

1 函数参数

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

2 arguments和this

全部的函数调用都会传递两个隐式参数:arguments和this。
实际上,在函数体内能够经过 arguments对象来访问这个参数数组,从而获取传递给函数的每个参数。arguments 对象只是与数组相似(它并非 Array 的实例),由于可使用方括号语法访问它的每个元素(arguments[0]、argumetns[1]…),也使用 length 属性来肯定传递进来多少个参数。数组

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

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())来扩充做用域的最大好处,就是对象不须要与方法有任何耦合关系。
图片描述this

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

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()内部验证当前元素是不是上下文。code

4 没有重载(overloading)

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

相关文章
相关标签/搜索