4. call apply bind函数的执行

call 和apply都可以执行函数

一 call和apply

call将函数中this的指向改变为这里带入的第一个参数obj
函数中如果没有this,call就没有任何意义了,和普通的执行函数概念一样
apply和call一样都是改变this的指向为第一个参数obj

function fn(){
     this.a=10;
     this.b=20;
 }
 var obj={};

  //apply和call一样都是改变this的指向为第一个参数obj
 fn.call(obj);
 //fn.apply(obj);
 console.log(obj);//{a:10,b:20}

call和apply的区别

call 执行函数,并且将该函数中this指向call的第一个参数,如果该函数有参数,那么call的第二个参数开始一一带入所有参数
apply 执行函数,并且将该函数中this指向call的第一个参数,如果该函数有参数,那么apply的第二个参数是这个函数的所有参数组成数组

function fn(_a,_b){
        this.a=_a;
        this.b=_b;
    }
 var obj={};
 //fn.call(obj,3,5);
 fn.apply(obj,[3,5]);
 console.log(obj);//{a:3,b:20}

call将函数中this的指向改变为这里带入的第一个参数o

var obj={
       abc:function(_a,_b){
          this.a=_a;
          this.b=_b;
       }
   }
   //obj.abc(3,5);//obj对象的a属性变为3,b属性变为5
   var o1={};
   obj.abc.call(o1,3,5);//call将函数中this的指向改变为这里带入的第一个参数obj
   console.log(obj,o1);//  {abc()}    {a:3,b:5}

如果使用call或者apply,第一个参数是null,就意味着将函数中this重定向到window

var obj={
       abc:function(_a,_b){
          this.a=_a;
          this.b=_b;
       }
   }
   var o1={};
   obj.abc.call(null,3,5);//相当于obj.abc.call(window,3,5);
   console.log(a,b);//  3,5  window上的属性

因为Math.max没有this,null,传入以后并没有任何作用,目的是传参时传入的是数组

var arr=[1,3,5,6]
var max=Math.max.apply(null,arr);

/* //重构
        var Math={
            max:function(){
                if(arguments.length===0) return;
                var max=arguments[0];
                if(arguments.length===1) return max;
                for(var i=1;i<arguments.length;i++){
                    max=max>arguments[i] ? max : arguments[i];
                }
                return max;
            }
        } */

属性和方法 动态属性,实例属性,该类的原型属性,实例化的原型链属性
动态属性 其实相对static 静态来说的
实例属性,该属性是通过new 构造函数来实例化对象以后调用的
该类的原型属性 站在类的立场上,类.prototype.属性 ES5中的方式
实例化的原型链属性 站在实例对象的的立场上,ES5中,对象中原型链上的方法和属性

<div></div>
<div></div>
<div></div>
var arr=Array.prototype.slice.call(divs);
var arr=[].slice.call(divs);//实例属性
console.log(arr);

//实现一个slice
class Array1{
      constructor(){

      }
      slice(start,end){
          // ES6中实例方法中的this就是该类实例化的对象
          // console.log("aaa")
          console.log(this);
          start=Number(start);
          end=Number(end);
          if(isNaN(start)) start=0;
          if(isNaN(end)) end=this.length;
          if(start<0) start=this.length+start;
          if(end<0) end=this.length+end;
          var arr=[];
          for(var i=start;i<end;i++){
              arr.push(this[i]);
          }
          return arr;
      }
 }
 var arr=new Array1();
 //arr.slice();//slice方法中的this就是这个arr
 // Array1.prototype.slice();//this是Array1.prototype 有错误的,类的原型
 arr.slice.call(divs);//this是divs
 //Array1.prototype.slice.call(divs);//等同于arr.slice.call(divs)



二 bind

当需要在回调函数中重新执行回调函数中的this,就需要是用bind来指向对象

function fn1(fn){
     fn(3);
 }
 function fn2(_a){
     this.a=_a;
 }
 var obj={};
 fn1(fn2.bind(obj));//把fn2函数中的this指向obj,并且返回这个被指向this后新的函数
 console.log(obj);//{a:3}
 
 var fns=fn2.bind(obj);
 console.log(fns)//这里创建了一个新的函数
 console.log(fns===fn2);//false

bind的实现

function fn1(fn){
     fn(3);
 }
 function fn2(_a){
     this.a=_a;
 }
 var obj={};
function bind(fn,obj){
      var fn1=function(){
          fn.apply(obj,Array.from(arguments));
      }
      return fn1;
  }

var fns=bind(fn2,obj);
fn1(fns);
console.log(obj);
var obj={
	    b:2,
	    a:function(){
	        setTimeout(function(){
	            console.log(this.b);//this指向window
	        },100)
	        setTimeout((function(){
	            console.log(this.b)//this指向bind绑定的this
	        }).bind(this),100)     //bind绑定的this是obj
	      }
}
        obj.a();  //2

var obj={
       b:2,
       a:function(){
           document.addEventListener("click",this.clickHandler.bind(this));
       },
       clickHandler:function(e){
           console.log(this.b);
           document.removeEventListener("click",this.clickHandler.bind(this));//删不掉,因为this绑定会得到一个新函数
       }
   }

   obj.a();

------------------------
var obj={
       b:2,
       a:function(){
           this.bindHandler=this.clickHandler.bind(this)//先把绑定的函数存储起来,然后指向一个this.bindHandler,这样就可以可以删除
           document.addEventListener("click",this.bindHandler);
       },
       clickHandler:function(e){
           console.log(this.b);
           document.removeEventListener("click",this.bindHandler);//删
       }
   }

   obj.a();

猜你喜欢

转载自blog.csdn.net/weixin_44157964/article/details/104358361