美文网首页
改变This指向的三个小兄弟bind,apply,call

改变This指向的三个小兄弟bind,apply,call

作者: icessun | 来源:发表于2017-07-23 22:25 被阅读54次
    • apply()

      • 参数:运行函数的作用域(必须传入),参数数组(arguments对象或者Array实例)
    • call()

      • 参数:运行函数的作用域(必须传入),参数必须逐个列举出来
    • 这两种方法没有什么不同,就是取决你给函数传递的参数的方式,真正的作用是扩充函数运行的作用域,对象不需要与方法有任何的耦合关系。

      window.color='red';
      var o={color:'blue'}
      function sayColor(){
            alert(this.color)
       }
       sayColor();  // red
       sayColor.call(this);  // red
       sayColor.call(o);  // blue
    
    • bind()
      • 创建一个函数的实例,其this值会绑定到传给bind()函数的值。
      • 即使在全局作用域调用这个函数,函数里面的this也是指向绑定的函数的this
       window.color='red';
    var o={color:'blue'}
    function sayColor(){
          alert(this.color)
     }
    var objectS=sayColor.bind(o);
    objectS();  // blue  全局调用也是执行o对象中的this
    

    bind()

    预处理机制,就是先把函数中的this和参数都改变,然后返回一个改好的函数,不会立即执行;在需要用的时候,调用

    简单使用bind()

    var oDiv=document.getElementById('div');
    var obj={};
    function fn(n,m){
        console.log(this,(n+m));  // object{}  5
    }
    oDiv.onclick=fn.bind(obj,2,3)
    

    上面的代码说明了bind()的预处理机制,首先bind()是函数Function身上原型上面的方法,可以提供给实例调用;当我们直接调用的fn(2,3)的时候,所打印的值是window 5,可见原先的函数里面的this是指向window的,调用bind(),把函数中的this改为obj,并且为函数传递了两个参数,此时改好的函数已经赋值给了点击事件,等待点击事件的触发,来执行函数,即不会立即执行。

    封装bind()

    前面说过,bind()是函数原型上面的方法,可以提供给函数实例使用,封装一个方法,首先是为了解决兼容性问题,其次是希望实例对象拿来就使用,最好是封装在原型上面,成为一个公共的方法;既然是改变this执行,那么bind()中第一个参数是必须传递的,使改变后的this指向谁

    // 这个方法的主要目的是改变this指向
    Function.prototype.myBind=function(thisArg){
    // 获取除thisarg的其余参数,返回数组
    // 首先使call前面的函数整体中的this指向arguments集合,接着使用slice方法截取索引值为1到agreement集合末尾的所有数据,组成一个数组赋值给outArg
      var outArg=Array.prototype.slice.call(arguments,1);
    
    // 判断支持bind方法的浏览器和不支持的浏览器
    if('bind' in Function.prototype ){
          // 如果bind属性在原型对象上面
    return this.bind.apply(this,[thisArg].concat(outArg));
       }
    // 不支持bind属性方法在原型上面
    var _this=this;
      return function(e){
    //arguments:用来接收实参的
             var innerArg=arguments.length==0?window.event||e;//innerArg用来拿的是事件对象;
          _this.apply(thisArg,outArg.concat(innerArg));
    //把一个已经改好this指向和参数的函数立即执行了:注意:只有匿名函数被调用,_this.apply这个函数才会立即执行;
       }
    };
    
    • 使用bind来求出鼠标点击的位置,bind的使用

    注意点

    • 考虑bind封装在哪里:Function.prototype.自定义的函数名
    • bind中this的指向:实例
    • bind中的参数问题:第一个参数是必须传递的;改变this的指向的
    • bind的返回值:已经改好的this和传好的匿名函数
      concat()是数组的方法,要对象转为数组:[object]==array
    var oDiv=document.getElementById('div');
    Function.prototype.myBind=function(thisArg){
        // 拿到除了this之外的其他参数;返回一个数组,只有数组有slice方法,所以使用了数组的原型来获取slice方法
        //arguments的个数是按照传递参数个数来计算的
        // 先把call前面函数中的this改为arguments,然后传递参数1,
        // 接着slice方法把arguments中的类数组截取除this后面的数组返回给outArg
        var outArg=Array.prototype.slice.call(arguments,1);
    // 浏览器支持bind方法,就使用浏览器的方法,不行就自己封装
     if('bind' in Function.prototype){
           return this.bind.apply(this,[thisArg].concat(outArg));
       }
    
     // 处理不支持bind方法的浏览器
     var _this=this;
     return function(e){
     // 注意this的指向
         var innerArg=argumrnts.length==0?window.event||e;
         // 改变这个匿名函数的this指向
         _this.apply(thisArg,outArg.concat(innerArg));// 传递的参数:2,3,event事件对象
       }
     };
    function fn(n,m){
    // 获取了事件对象 arguments中包括 2,3 event
       var e=arguments[2];
         console.log(e.clientX, e.clientY)
          console.log(this, (n+m)) //obj{} 5
     }
      var obj={};
      // 把fn中的this改为obj{}
    oDiv.onclick=fn.myBind(obj,2,3);
    

    相关文章

      网友评论

          本文标题:改变This指向的三个小兄弟bind,apply,call

          本文链接:https://www.haomeiwen.com/subject/woqvkxtx.html