apply和call

  这里推荐一本设计模式的javascript书. 《JavaScript设计模式与开发实践》。作者是腾讯大牛曾探。

  我每天都会在里面抽出我受到的理解,作为我的读书笔记。今天就昨天讲的this里面涉及到的call和apply进行书中的讲解。

     Function.prototype.call 和 Function.prototype.apply 都是非常常用的方法。它们的作用一模 一样,区别仅在于传入参数形式的不同。 

  1.apply

    apply 接受两个参数,第一个参数指定了函数体内 this 对象的指向,第二个参数为一个带下 标的集合,这个集合可以为数组,也可以为类数组,apply 方法把这个集合中的          元素作为参数传 递给被调用的函数。

          For Example:

    var func = function( a, b, c ){

      alert ( [ a, b, c ] ); // 输出 [ 1, 2, 3 ]

      };
    func.apply( null, [ 1, 2, 3 ] );

    //参数123放进数组里面作为参数传入func,对应的参数分别 a b c

     2.call 

  call 传入的参数数量不固定,跟 apply 相同的是,第一个参数也是代表函数体内的 this 指向, 从第二个参数开始往后,每个参数被依次传入函数: 

     For Example: 

  var func = function( a, b, c ){

    alert ( [ a, b, c ] ); // 输出 [ 1, 2, 3 ]

  };
  func.call( null, 1, 2, 3 );

 

 

     当调用一个函数时,JavaScript 的解释器并不会计较形参和实参在数量、类型以及顺序上的 区别,JavaScript的参数在内部就是用一个数组来表示的。从这个意义上说,apply 比 call 的使用 率更高,我们不必关心具体有多少参数被传入函数,只要用 apply 一股脑地推过去就可以了。   

  call 是包装在 apply 上面的一颗语法糖,如果我们明确地知道函数接受多少个参数,而且想 一目了然地表达形参和实参的对应关系,那么也可以用 call 来传送参数。

  当使用 call 或者 apply 的时候,如果我们传入的第一个参数为 null,函数体内的 this 会指 向默认的宿主对象,在浏览器中则是 window:

  For Example:

  var func = function( a, b, c ){    

     alert ( this === window );    // 输出 true 

  };
  func.apply( null, [ 1, 2, 3 ] );  

  但如果是在严格模式下,函数体内的 this 还是为 null:

  For Example:
  var func = function( a, b, c ){

         "use strict";     alert ( this === null );     // 输出 true

  }  
  func.apply( null, [ 1, 2, 3 ] );  

  有时候我们使用 call 或者 apply 的目的不在于指定 this 指向,而是另有用途,比如借用其 他对象的方法。那么我们可以传入 null 来代替某个具体的对象:

  For Example:
  Math.max.apply( null, [ 1, 2, 5, 3, 4 ] )    // 输出:5

     那call和apply具体怎么怎么用的呢?

  1.改变this的指向

      call 这个函数呢,可以理解它本没有任何资产(属性方法),就借助别人的方法。别人好好的调用自己的方法,它横空一脚,自己在人家后面加上 .call,然后传入自己想要的处理的对象。这样,这个对象就用了别人的方法。省事不少,据说,杜鹃鸟就是这样干的,它不孵化小鸟,把蛋放在别的鸟窝里,让别人代为孵化。

  For Example:

    var obj1 = {

   name: "adou1",

    getName: function(){

      console.log(this.name);//adou2

    }

  }

  var obj2 = {

    name: "adou2"

  } 

  window.name = "window_adou";

      var GetName = function(){

    console.log(this.name);//

  }

  obj1.getName.call(obj2);

     GetName();//window_adou;

  GetName.call(obj1);//adou1;

  GetName.call(obj2);//adou2

     在举一个用call修正this的例子:

    document.getElementById("blog").onclick=function(){

    console.log(this.id);//blog

  }//这我们都知道

  假如在一个事件函数中有一个内部函数,在事件内部调用这个函数的时候,this就指向了 window,如下

    

   document.getElementById("blog").onclick=function(){

    console.log(this.id);//blog

    var func = function (){

      console.log(this.id);//undefined

      //为甚指向的是undefined ,上一篇介绍的this的指向的时候,其中一个普通函数的调用,指向的就是全局 ,ES5中定义,这样的指向为undefined

    }

    func();

  }

  修正过来如下:就是把func()换成 func.call(this);//因为func还是在 onclick函数里调用的,this还是指向的是当前的点击对象

  For Example:     

  document.getElementById = (function( func ){

    return function(){

      return func.apply( document, arguments );

     }

  })( document.getElementById );
    var getId = document.getElementById;

    var div = getId( 'div1' );

    alert ( div.id );    // 输出: div1

  2. Function.prototype.bind 

       For Example:  

    Function.prototype.bind = function(){

      var self = this, // 保存原函数

       context = [].shift.call( arguments ), // 需要绑定的 this 上下文

      args = [].slice.call( arguments ); // 剩余的参数转成数组

      return function(){ // 返回一个新的函数

         return self.apply( context, [].concat.call( args, [].slice.call( arguments ) ) ); // 执行新的函数的时候,会把之前传入的 context 当作新函数体内的           this // 并且组合两次分别传入的参数,作为新函数的参数 } };
        var obj = {     name: 'sven' };  
        var func = function( a, b, c, d ){

               alert ( this.name );        // 输出:sven

                  alert ( [ a, b, c, d ] )}

              .bind( obj, 1, 2 );  
        func( 3, 4 );//  输出:[ 1, 2, 3, 4 ] 

  3.借用其他对象的方法 (用的更多点)

  这个具体的案例前面已经有讲:再讲一个通过原型添加对象的方法,然后调用的例子

  var A = function (name){

    this.name = name;

  };

  var B = function(){

    A.apply(this,arguments);

    //调用A的时候返回了 name

  };

  B.prototype.getName = function(){

    return this.name;

  };

     var b = new B("adou");

     console.log(b.getName());//adou

   

 

上一篇:箭头函数与普通函数的区别


下一篇:HTML Minifier - 灵活的在线 HTML 压缩工具