美文网首页
改变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