函数
使用call和apply
call和apply是Function的原型方法,它们能够指定函数当作一个方法绑定到指定对象中,并进行调用,具体用法如下function.call(thisobj, args...)function.call(thisobj, [args]
其中 function表示要调用的函数参数 thisobj表示绑定对象即this指代的对象参数args表示传递给被调用函数的参数。
call方法能接收多个参数列表,而 apply方法只能接收一个数组或者伪类数组,数组元素将作为参数列表传递给被调用的函数。
function f(x,y){ //定义求和函数return x+y;}console.log( f.apply(null, [3, 4] )); //返回7
实例设计:下面使用apply方法设计一个求最大值的函数。
function max(){ //求最大值函数var m = Number.NEGATIVE_INFINITY;//声明一个负无穷大的数值for( var i = 0; i < arguments.length; i ++ ){//遍历函数所有的实参if( arguments[i] > m ) //如果实参值大于变量m,m = arguments[i]; //则把该实参值赋值给m}return m; //返回最大值}var a = [23, 45, 2, 46, 62, 45, 56, 63];//声明并初始化数组var m = max.apply( Object, a );//把函数max绑定为Object对象的方法,并动态调用console.log( m ); //返回63var a = [23, 45, 2, 46, 62, 45, 56, 63]; //声明并初始化数组var m = Math.max.apply( Object, a ); //调用系统函数maxconsole.log( m ); //返回63
在上面的示例中,设计定义一个函数max(),用来计算所有参数中最大值参数。首先,通过apply方法,动态调用max函数,然后,把它绑定为Object对象的一个方法,并把包含多个值的数组传递给它。最后,返回经过max()计算后的最大数组元素。
如果使用call方法,就需要把数组所有元素全部读取出来,再逐一传递给call方法,显然这种做法不是很方便。
//【示例1】下面示例使用call动态调用函数f,并传入参数值3和4,返回运算值。function f(x,y){ //定义求和函数return x+y;}console.log( f.call(null, 3, 4)); //返回7
提示:
也可以调用Math的max()方法来计算数组的最大值元素。
var a=[23, 45, 2, 46, 62, 45, 56, 63];//声明并初始化数组var m=Math.max.apply(Object,a);//调用系统函数maxconsole.log(m);//返回63
使用call和apply方法可以把一个函数转为指定对象的方法,并在这个对象上调用该方法。当函数动态调用之后,这个对象的临时方法也就不存在了
function f() {return "函数f";}var obj = {};f.call( obj ); //把函数f绑定为obj对象的方法console.log( obj.f() ); //再次调用该方法,则返回编译错误
apply和call方法的主要功能包括如下
- 调用函数
- 修改函数体内的this指代对象。
- 为对象绑定方法
- 跨越限制调用不同类型的方法
使用length
function checkArg( a ){ //检测函数实参与形参是否一致if( a.length != a.callee.length ) //如果实参与形参个数不同,则抛出错误console.log(a.callee);console.log(a);throw new Error( "实参和形参不一致" );}function f( a, b){ //求两个数的平均值checkArg( arguments ); //根据arguments来检测函数实参和形参是否一致return ((a*1 ? a: 0) + (b*1 ? b: 0) ) / 2; //返回平均值}console.log( f( 6) ); //抛出异常。调用函数f,传入1个参数
使用arguments
arguments对象表示函数的实参集合,仅能够在函数体内可见,并可以直接访问扫一扫,看视
■知识点
arguments对象是一个伪类数组,不能够继承 Array的原型方法。可以使用数组下标的形式访问每个实
对象的属性,表示函数包含的实参个数。同时, arguments对象可以允许更新其包含的实参值
参,如 arguments[0]表示第1个实参,下标值从0开始,直到 arguments. length—1其中, length是arguments对象的属性,表示函数包含的实参个数,同时,arguments对象可以允许更新其包含的实参值。
■实例设计
使用 arguments对象能够增强函数应用的灵活性。例如,如果函数的参数个数不确定,或者函数参
数的个数很多,而又不想逐一定义每一个形参,则可以省略定义参数,直接在函数体内使用 arguments
对象来访问调用函数的实参值。
//【示例1】下面示例定义一个求平均值的函数,它借助arguments对象来计算函数接收参数的平均值。function avg(){ //求平均数var num = 0, l = 0; //声明并初始化临时变量for(var i = 0; i < arguments.length; i ++ ){ //遍历所有实参if(typeof arguments[i] != "number") //如果参数不是数值continue; //则忽略该参数值num += arguments[i]; //计算参数的数值之和l ++ ; //计算参与和运算的参数个数}num /= l; //求平均值return num; //返平均值}console.log(avg(1, 2, 3, 4)); //返回2.5console.log(avg(1, 2, "3", 4)); //返回2.3333333333333335
这里我自己写的代码犯了一个错误,我将var num = 0, l = 0;
声明在了函数体外,作为了全局变量,于是结果变成了
后来自己研究一下发现,是自己没搞清楚作用域和变量内存的问题
var num = 0;var l = 0;function avg() {for (var i = 0; i < arguments.length; i++) {if (typeof arguments[i] != "number")continue;console.log(arguments[i]);num += arguments[i];console.log(num);l++;console.log(l);}num /= l;return num;}var a1 = avg(1, 2, 3, 4);var a2 = avg(1, 2, "3", 4);console.log(a1);console.log(a2);

恶补了一下变量作用域的知识,局部变量在调用完函数之后内存空间就会被销毁,而全局变量会一直保留原来的内存空间。
Supplement:
关于arguments对象:
https://blog.csdn.net/zjy_android_blog/article/details/80934042
https://www.cnblogs.com/gongyijie/p/9425549.html

