js中call,apply,bind方法的简单总结

一、作用 

  1. call、apply、bind作用是改变函数执行时的上下文,简而言之就是改变函数运行时的this指向
  2. call、apply、bind是Function.prototype下的方法,都是用于改变函数运行时上下文,最终的返回值是你调用的方法的返回值,若该方法没有返回值,则返回undefined。

二、区别

      最主要的区别是call()、apply()方法是立即调用当前函数,而bind()是返回一个改变了this指向的新函数,并不立即调用。

  call(),bind()的参数是依次传参,一一对应传递的。

  apply() 需要把多个参数放在一个数组中,作为第二个参数传递


三、说明

(一)、call()

     用法: call(newThis,arg1,arg2。。。)

      call 的第一个参数就是 this 所要指向的那个对象,后面的参数则是函数调用时所需的参数。

     1、 newThis包括以下类型:

        (1) 传null,undefined或不传, 函数中的this指向window对象。
   (2) 传递另一个函数的函数名,函数中的this指向这个函数的引用,则就指向函数体。
   (3) 传递字符串、数值或布尔类型等基础类型,函数中的this指向其对应的包装对象,如 String、Number、Boolean等。
      (4) 传递一个对象,函数中的this指向这个对象。

      2、args是将会传入被绑定函数的参数,被绑定函数的执行时参数顺序为:newThis,args,原参数

扫描二维码关注公众号,回复: 15177857 查看本文章

  列子:

var fan = {
    user:"dragon",
    fun:function(age,sex){
        console.log(this.user); //dragon

        console.log(this.user,age,sex)  //dragon 男 学习
    }
}
var b = fan.fun;
b.call(fan,'男','学习');  
b.call(fan);             //传递函数名. this指向这个函数的引用
function fan1(){  
  console.log(this);    //输出函数a中的this对象
}      
 
function fan2(){}      
 
var fan3={name:"dragon"};//定义对象fan3
 
fan1.call();           //window     不传, 函数中的this指向window对象。
fan1.call(null);       //window     传null, 函数中的this指向window对象。
fan1.call(undefined);  //window     传undefined, 函数中的this指向window对象。
fan1.call(1);          //Number     Number {1}     传递数值   
fan1.call('');         //String     String {''}    传递字符串
fan1.call(true);       //Boolean    Boolean {true} 传递布尔
fan1.call(fan2);       //function fan2(){}  //传递函数名. this指向这个函数的引用但无引用就指向函数体。
fan1.call(fan3);       //Object  {name: 'dragon'}
 

call实现分析:

// 传参默认是指向window
Function.prototype.myCall = function(context = window){ 
  
  context.fan = this;                 //为对象添加方法(this指向调用myCall的函数)
  let args = [...arguments].slice(1); // 剩余的参数
  let res = context.fan(...args);     // 调用该方法,该方法this指向context
  delete context.fan;                 //删除添加的方法
  return res;
} 

 还有就是对象继承中的组合继承

//临时中转函数
function obj(o) {

    function F() {
    }

    F.prototype = o;

    return new F();

}

//寄生函数
function create(subType, superType){
    // var protoType = Object.create(superType.prototype);    //创建对象
    var protoType = obj(superType.prototype);            //创建对象
    protoType.constructor = subType;                    //增强对象
    subType.prototype = protoType;                        //指定对象
}
function Sup(name, age) {

    this.name = name;

    this.age = age;

}

Sup.prototype.run = function () {

    return this.name + " " + this.age + " running..."

}

function Sub(name, age) {

    Sup.call(this, name);
    this.age = age;

}

create(Sub,Sup);              //替代D.prototype=new B();
Sub.prototype.sayAge = function(){
    return this.name + " " + this.age + " Sub..."
}
var d= new Sub('dragon',100);
console.log(d.run());        //dragon 100 running...
console.log(d.sayAge());      //dragon 100 Sub...

 (二)、apply() 

               用法;apply(newThis,[arrArg])    

              apply和call类似,它接受两个参数,第一个参数是this的指向,第二个参数是函数接受的参数,以数组的形式传入。

var fan = {
    user:"dragon",
    fun:function(age,sex){
        console.log(this.user); //dragon

        console.log(this.user,age,sex)  //dragon 男 学习
    }
}
var b = fan.fun;
b.apply(fan,['男','学习']);  
b.apply(fan);             //传递函数名. this指向这个函数的引用

function fan1(){  
  console.log(this);    //输出函数a中的this对象
}      
 
function fan2(){}      
 
var fan3={name:"dragon"};//定义对象fan3
 
fan1.apply();           //window     不传, 函数中的this指向window对象。
fan1.apply(null);       //window     传null, 函数中的this指向window对象。
fan1.apply(undefined);  //window     传undefined, 函数中的this指向window对象。
fan1.apply(1);          //Number     Number {1}     传递数值   
fan1.apply('');         //String     String {''}    传递字符串
fan1.apply(true);       //Boolean    Boolean {true} 传递布尔
fan1.apply(fan2);       //function fan2(){}  //传递函数名. this指向这个函数的引用但无引用就指向函数体。
fan1.apply(fan3);       //Object  {name: 'dragon'} 

apply实现分析:

// 传参默认是指向window
Function.prototype.myApply = function(context = window){ 
  context.fan = this;                  //为对象添加方法(this指向调用myCall的函数)
  let res;
  if(arguments[1]){                    //判断是否有第二个参数
    res = context.fan(...arguments[1]);// 调用该方法,该方法this指向context
  }else{
    res = context.fan();               // 调用该方法,该方法this指向context
  }
  delete context.fan;                  //删除添加的方法
  return res;
} 

(三)、结合call、apply操作数组或对象

         1、找出数组的最大值、最小值

var dragon = [11, 21, 4, 55, 19,88,22,33];
Math.max.apply(null, dragon) // 88 最大值
Math.max.call(null, ...dragon) // 88 最大值
 
Math.min.apply(null, dragon) // 4 最小值
Math.min.call(null, ...dragon) // 4 最小值

         2、转换类似数组的对象

Array.prototype.slice.apply({0: 66,1: 88, length: 2}) // [66,88]
Array.prototype.slice.call({0: 66,1: 88, length: 2})  // [66,88]
Array.prototype.slice.apply({0: 66,1: 88, length: 3}) // [66, 88, undefined]
Array.prototype.slice.call({0: 66,1: 88, length: 3})  // [66, 88, undefined]
Array.prototype.slice.apply({0: 66})                  // []
Array.prototype.slice.call({0: 66})                   // []

     为什么通过 Array.prototype.slice.call(arrayLike) 可以转换类数组为数组? 

  大概具体是这样的:   

Array.prototype.mySlice = function(start=0, end) {
    const array = this;
    const end = end === undefined ? array.length : end;
    
    const resultArray = [];
    if (array.length === 0) return resultArray;
    for (let index = start; index < end; index++) {
        resultArray.push(array[index]);
    }
    return resultArray;
}

          3、将数组的空元素变为 undefined

Array.apply(null, ['aaa', ,'bbb']); // [ 'aaa', undefined, 'bbb' ]
Array.call(null, ...['aaa', ,'bbb']); // [ 'aaa', undefined, 'bbb' ]

          4、合并数组

var arr1=new Array("1","2","3","4","5");  
var arr2=new Array("6","7","8","9","10");  
  
Array.prototype.push.apply(arr1,arr2); 

console.log(arr1) //['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']

(四)bind()

bind()函数会创建一个新的绑定函数,这个绑定函数包装了原函数的对象。调用绑定函数通常会执行包装函数。
绑定函数内部属性:

1 、包装的函数对象

2、在调用包装函数时始终作为this传递的值

3、在对包装函数做任何调用时都会优先用列表元素填充参数列表。

var user="winDragon";
var fan = {
    user:"dragon",
    fun:function(age,sex){
        console.log(this.user); //dragon

        console.log(this.user,age,sex)  
    }
}
var b = fan.fun;
b();                          //winDragon  没bind前this指向window
var c = b.bind(fan);
console.log(c());             //dragon     bind后this指向对象中的user 
b.bind(fan,'男','学习')();     //dragon     男 学习

b.bind(fan,['男','学习'])();   //dragon     ['男', '学习'] undefined




 bind实现分析: 

// 传参默认是指向window
Function.prototype.myBind = function(context = window){
  let fan = this;                       // 调用bind的函数
  let args = [...arguments].slice(1);   // myBind的参数
  let bind = function(){
    let args1 = [...arguments].slice(); // bind的参数
    return fan.apply(context,args.concat(args1));
  }
  return bind;
} 

四、总结

  

1、apply 、call、bind 三者都是用来改变函数的 this 对象的指向的;

2、apply、call、bind 三者第一个参数都是 this 要指向的对象;

3、apply、call、bind 三者都可以利用后续参数传参;

4、bind 是返回对应函数,便于稍后调用;apply 、call 则是立即调用 。


 

猜你喜欢

转载自blog.csdn.net/qq_35404844/article/details/129927234