函数


使用call和apply

call和apply是Function的原型方法,它们能够指定函数当作一个方法绑定到指定对象中,并进行调用,具体用法如下
function.call(thisobj, args...)
function.call(thisobj, [args]
其中 function表示要调用的函数参数 thisobj表示绑定对象即this指代的对象参数args表示传递给被调用函数的参数。
call方法能接收多个参数列表,而 apply方法只能接收一个数组或者伪类数组,数组元素将作为参数列表传递给被调用的函数。

  1. function f(x,y){ //定义求和函数
  2. return x+y;
  3. }
  4. console.log( f.apply(null, [3, 4] )); //返回7

实例设计:下面使用apply方法设计一个求最大值的函数。

  1. function max(){ //求最大值函数
  2. var m = Number.NEGATIVE_INFINITY;
  3. //声明一个负无穷大的数值
  4. for( var i = 0; i < arguments.length; i ++ ){
  5. //遍历函数所有的实参
  6. if( arguments[i] > m ) //如果实参值大于变量m,
  7. m = arguments[i]; //则把该实参值赋值给m
  8. }
  9. return m; //返回最大值
  10. }
  11. var a = [23, 45, 2, 46, 62, 45, 56, 63];
  12. //声明并初始化数组
  13. var m = max.apply( Object, a );
  14. //把函数max绑定为Object对象的方法,并动态调用
  15. console.log( m ); //返回63
  16. var a = [23, 45, 2, 46, 62, 45, 56, 63]; //声明并初始化数组
  17. var m = Math.max.apply( Object, a ); //调用系统函数max
  18. console.log( m ); //返回63

在上面的示例中,设计定义一个函数max(),用来计算所有参数中最大值参数。首先,通过apply方法,动态调用max函数,然后,把它绑定为Object对象的一个方法,并把包含多个值的数组传递给它。最后,返回经过max()计算后的最大数组元素。
如果使用call方法,就需要把数组所有元素全部读取出来,再逐一传递给call方法,显然这种做法不是很方便。

  1. //【示例1】下面示例使用call动态调用函数f,并传入参数值3和4,返回运算值。
  2. function f(x,y){ //定义求和函数
  3. return x+y;
  4. }
  5. console.log( f.call(null, 3, 4)); //返回7

提示:
也可以调用Math的max()方法来计算数组的最大值元素。

  1. var a=[23, 45, 2, 46, 62, 45, 56, 63];//声明并初始化数组
  2. var m=Math.max.apply(Object,a);//调用系统函数max
  3. console.log(m);//返回63

使用call和apply方法可以把一个函数转为指定对象的方法,并在这个对象上调用该方法。当函数动态调用之后,这个对象的临时方法也就不存在了

  1. function f() {
  2. return "函数f";
  3. }
  4. var obj = {};
  5. f.call( obj ); //把函数f绑定为obj对象的方法
  6. console.log( obj.f() ); //再次调用该方法,则返回编译错误

apply和call方法的主要功能包括如下

  • 调用函数
  • 修改函数体内的this指代对象。
  • 为对象绑定方法
  • 跨越限制调用不同类型的方法

使用length

  1. function checkArg( a ){ //检测函数实参与形参是否一致
  2. if( a.length != a.callee.length ) //如果实参与形参个数不同,则抛出错误
  3. console.log(a.callee);
  4. console.log(a);
  5. throw new Error( "实参和形参不一致" );
  6. }
  7. function f( a, b){ //求两个数的平均值
  8. checkArg( arguments ); //根据arguments来检测函数实参和形参是否一致
  9. return ((a*1 ? a: 0) + (b*1 ? b: 0) ) / 2; //返回平均值
  10. }
  11. console.log( f( 6) ); //抛出异常。调用函数f,传入1个参数

图片.png


使用arguments

arguments对象表示函数的实参集合,仅能够在函数体内可见,并可以直接访问扫一扫,看视
■知识点
arguments对象是一个伪类数组,不能够继承 Array的原型方法。可以使用数组下标的形式访问每个实
对象的属性,表示函数包含的实参个数。同时, arguments对象可以允许更新其包含的实参值
参,如 arguments[0]表示第1个实参,下标值从0开始,直到 arguments. length—1其中, length是arguments对象的属性,表示函数包含的实参个数,同时,arguments对象可以允许更新其包含的实参值。
■实例设计
使用 arguments对象能够增强函数应用的灵活性。例如,如果函数的参数个数不确定,或者函数参
数的个数很多,而又不想逐一定义每一个形参,则可以省略定义参数,直接在函数体内使用 arguments
对象来访问调用函数的实参值。

  1. //【示例1】下面示例定义一个求平均值的函数,它借助arguments对象来计算函数接收参数的平均值。
  2. function avg(){ //求平均数
  3. var num = 0, l = 0; //声明并初始化临时变量
  4. for(var i = 0; i < arguments.length; i ++ ){ //遍历所有实参
  5. if(typeof arguments[i] != "number") //如果参数不是数值
  6. continue; //则忽略该参数值
  7. num += arguments[i]; //计算参数的数值之和
  8. l ++ ; //计算参与和运算的参数个数
  9. }
  10. num /= l; //求平均值
  11. return num; //返平均值
  12. }
  13. console.log(avg(1, 2, 3, 4)); //返回2.5
  14. console.log(avg(1, 2, "3", 4)); //返回2.3333333333333335

这里我自己写的代码犯了一个错误,我将
var num = 0, l = 0;
声明在了函数体外,作为了全局变量,于是结果变成了
图片.png
后来自己研究一下发现,是自己没搞清楚作用域和变量内存的问题

  1. var num = 0;
  2. var l = 0;
  3. function avg() {
  4. for (var i = 0; i < arguments.length; i++) {
  5. if (typeof arguments[i] != "number")
  6. continue;
  7. console.log(arguments[i]);
  8. num += arguments[i];
  9. console.log(num);
  10. l++;
  11. console.log(l);
  12. }
  13. num /= l;
  14. return num;
  15. }
  16. var a1 = avg(1, 2, 3, 4);
  17. var a2 = avg(1, 2, "3", 4);
  18. console.log(a1);
  19. console.log(a2);

图片.png
恶补了一下变量作用域的知识,局部变量在调用完函数之后内存空间就会被销毁,而全局变量会一直保留原来的内存空间。

Supplement:
关于arguments对象:
https://blog.csdn.net/zjy_android_blog/article/details/80934042
https://www.cnblogs.com/gongyijie/p/9425549.html