zoukankan      html  css  js  c++  java
  • [Effective JavaScript 笔记]第21条:使用apply方法通过不同数量的参数调用函数

    apply()方法定义

    函数的apply()方法和call方法作用相同,区别在于接收的参数的方式不同。
    apply()方法接收两个参数,一个是对象,一个是参数数组。

    apply()作用

    1、用于延长函数的作用域

    示例:

    var color='red';
    var o={color:'blue'};
    function sayColor(){
        console.log(this.color);
    }
    sayColor();//"red"
    sayColor.apply(o);//"blue"
    

     这里通过apply()方法把函数动态绑定到了对象o上了,这时this指向o对象,得到结果"blue"。

    2、对象不需要与方法有任何耦合关系

    下面举个耦合的例子,看如何通过apply来解决这种耦合。

    var color='red';
    var o={color:'blue'};
    function sayColor(){
          console.log(this.color);
    }
    o.sayColor=sayColor;
    o.sayColor();//"blue"
    

    这里先将函数放到了对象o中,这里对象和方法就紧耦合到一起了,方法的调用必须通过对象o。

    没有使用apply()和call()方法那样灵活。
    重构上面代码,得到前例中的代码。

    var color='red';
    var o={color:'blue'};
    function sayColor(){
          console.log(this.color);
    }
    sayColor();//"red"
    sayColor.apply(o);//"blue"
    

    这里对象并没有绑定任何方法,只是在需要使用的时候,利用函数的apply或call方法来动态绑定。

    对象和方法之间没有耦合在一起。这里还可以通过ES5提供的bind()方法来完成

    3、实现可变参数函数传参

    下面一个计算任意数量数字平均值的函数

    average(1,2,3);
    average(1);
    average(3,1,2,3,5,6,7,8,9);
    average(1,2,3,5,2,1,5,6,1,10);
    

     average函数是一个称为可变参数或可变元函数(函数的元数是指其期望的参数个数)的例子。

    当然这个函数也可以写成一个接收数组的形式。

    averageOfArray([1,2,3]);
    averageOfArray([1]);
    averageOfArray([3,1,2,3,5,6,7,8,9]);
    averageOfArray([1,2,3,5,2,1,5,6,1,10]);
    

    使用可变参数的函数更简洁、优雅。可变参数函数具有便捷的语法,至少让调用者预先明确地知道提供了多少个参数。

    如果我有这样一个数组

    var scores=getAllScores();
    

    如何使用average函数计算平均值呢?

    1.可变参数函数版本。
    这时就可以和apply()方法配合使用,这里因为函数并没用引用this变量,因此第一个参数我们传入一个null。代码如下:

    var scores=getAllScores();
    average.apply(null,scores);
    

    2.直接参数为数组的形式

    这里可以直接传入数组参数。

    var scores=getAllScores();
    averageOfArray(scores);
    

    以上两种形式,个人觉得都是可以,反而第二种更简单。多知道一种方法,对于遇到别人写的函数时,可以轻松应对,不需要重构代码。这个好处反而更多。

    4、实现可变参数方法的传值

    示例:buffer对象包含一个可变参数的append方法,该方法添加元素到函数内部的state数组中。

    var buffer={
        state:[],
        append:function(){
            for(var i=0,n=arguments.length;i<n;i++){
                this.state.push(arguments[i]);
            }
        }
    };
    

    这时append方法可以接受任意多个参数。

    buffer.append('Hello,');
    buffer.append('firtName',' ','lastName','!');
    buffer.append('newLine');
    

    形式如

    buffer.append(arg1,arg2,arg3,...)
    

    借助apply方法的this参数,我们可以指定一个可计算的数组调用append方法

    buffer.append.apply(buffer,getInputStrings());
    

    注意:这里的buffer很重要,如果传递不同的对象,则append方法将尝试修改该错误对象的state属性。

    提示

    • 使用apply方法指定一个可计算的参数数组来调用可变参数的函数
    • 使用apply方法的第一个参数给可变参数的方法提供一个接收者

    附录一

    average函数

    function average(){
        var args=[].slice.call(arguments);
        var sum=args.reduce(function(prev,cur){
            return prev+cur;
        });
        return parseInt(sum/args.length,10);
    }
    

    averageOfArray函数

    function averageOfArray(arr){    
        var sum=arr.reduce(function(prev,cur){
            return prev+cur;
        });
        return parseInt(sum/arr.length,10);
    }

    ES5 bind()方法

    这个方法创建一个函数的实例,其this值会被绑定到传给bind()函数的值。
    例如
    var color='red';
    var o={color:'blue'};
    function sayColor(){
        console.log(this.color);
    }
    var oSayColor=sayColor.bind(o);
    oSayColor();//"blue"
    

    兼容低版本,参考使用下面的版本

    if (!Function.prototype.bind) {
      Function.prototype.bind = function(oThis) {
        if (typeof this !== 'function') {
          // closest thing possible to the ECMAScript 5
          // internal IsCallable function
          throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
        }
    
        var aArgs   = [].slice.call(arguments, 1),
            fToBind = this,
            fNOP    = function() {},
            fBound  = function() {
              return fToBind.apply(this instanceof fNOP? this: oThis,
                     aArgs.concat(Array.prototype.slice.call(arguments)));
            };
    
        if (this.prototype) {
          // Function.prototype doesn't have a prototype property
          fNOP.prototype = this.prototype; 
        }
        fBound.prototype = new fNOP();
    
        return fBound;
      };
    }
    

      

  • 相关阅读:
    121孤荷凌寒自学第0207天_区块链第121天NFT018
    120孤荷凌寒自学第0206天_区块链第120天NFT017
    IOS雕虫小技
    Github-素材篇
    黑马程序员_ Objective-c 之Foundation之NSNumber ,NSValue, NSDate
    黑马程序员_ Objective-c 之block、protocol学习笔记
    黑马程序员_ Objective-c 之Foundation笔记(二)
    黑马程序员_ Objective-c 之Foundation笔记(一)
    黑马程序员_ Objective-c 内存管理笔记
    黑马程序员_ Objective-c 面向对象笔记详解
  • 原文地址:https://www.cnblogs.com/wengxuesong/p/5545281.html
Copyright © 2011-2022 走看看