关于JS中call 、apply 和bind

call()、apply()、bind() 都是用来改变函数运行时的this指向面试

也就是改变函数执行的上下文,被称为改变this指向的三兄弟。数组

先记住如下this的总结,便于如下例子中this指向的理解:markdown

  • 在方法中(该方法不是箭头函数定义的),this表示该方法所属的对象;
  • 如何单独使用,this表示全局对象;
  • 在函数中,this表示全局对象;
  • 在函数中,在严格模式下,this是未定义的(undefined);
  • 在事件中,this表示接受事件的元素;
  • call( )、apply( )能够将this引用到任何对象;

1、call

一、简单理解call

经过一个demo来理解call( )的用法:app

var person = {
  name:'leaf',
  age:26,
  getName:function(){
  console.log(this.name+' '+this.age);
}
}

var person2 = {
  name:'ice',
  age:18
}

person.getName();//leaf 26
person.getName.call(person2);//ice 18
复制代码

getName( )是person这个对象的一个方法,在方法中,this表示该方法所属的对象,因此getName方法中的this指的是person这个对象。函数

call( )能够改变this的指向,它能够把getName方法所属的对象指向person2。oop

因此:ui

call( )容许为不一样的对象分配和调用属于一个对象的函数/方法。this

二、带参数的call

call( )方法能够接受参数,第一个参数是改变上下文的对象,从第二个参数开始以参数列表的形式展现,用逗号隔开。spa

var person = {
  name:'leaf',
  age:26,
  getName: function(country,city){
    console.log(this.name + ' ' + this.age + ' ' + country + ' ' + city);
  }
}

var person2 = {
  name:'ice',
  age:18
}

person.getName.call(person2, '英国','伦敦');//ice 18 英国 伦敦
复制代码

2、apply

一、简单理解apply

var person = {
  name:'leaf',
  age:26,
  getName:function(){
  console.log(this.name+' '+this.age);
}
}

var person2 = {
  name:'ice',
  age:18
}

person.getName();//leaf 26
person.getName.apply(person2);//ice 18
复制代码

二、带参数的apply

apply( )方法接受数组形式的参数。code

var person = {
  name: 'leaf',
  age: 26,
  city: '广西',
  country: '中国',
  getName: function(country,city){
    console.log(this.name + ' ' + this.age + ' ' + country + ' ' + city);
  }
}

var person2 = {
  name: 'ice',
  age: 18
}

person.getName.apply(person2, ['美国','纽约']);//ice 18 美国 纽约
//等价于
// person.getName.call(person2, '英国','伦敦');//ice 18 英国 伦敦
复制代码

总结:

apply( )和call( )方法很类似,那apply( )和call( )的区别主要在于参数的区别:

  • call( )方法接受参数;
  • apply( )方法接受数组形式的参数;

除了接受参数形式不一样以外,call( )和apply( )行为都是一致的。

3、bind

bind() 方法一样也是能够改变this的指向,可是和call、apply不一样的是bind( )返回的是改变上下文的一个函数,而且不会立刻执行,须要用的时候再执行。

var person = {
  name:'leaf',
  age:26,
  getName:function(){
  console.log(this.name+' '+this.age);
}
}

var person2 = {
  name:'ice',
  age:18
}

person.getName.bind(person2)();//ice 18
复制代码

bind( )方法后边多了个()外,结果和call、apply返回的结果都是一致!

总结:

bind方法返回的是一个新函数,必须调用它才会被执行。

4、总结call、apply和bind的用法示例:

一、对比没有参数的状况下:

var name = 'qing',age = 20;
var person = {
  name:'leaf',
  personAge:this.age,
  getName:function(){
  console.log(this.name+' '+this.age);
}
}

var person2 = {
  name:'ice',
  age:18
}

person.getName.call(person2);        //ice 18
person.getName.apply(person2);      //ice 18
person.getName.bind(person2)();     //ice 18
复制代码

二、对比传参的状况下:

var person = {
  name: 'leaf',
  age: 26,
  city: '广西',
  country: '中国',
  getName: function(country,city){
    console.log(this.name + ' ' + this.age + ' ' + country + ' ' + city);
  }
}

var person2 = {
  name: 'ice',
  age: 18
}

person.getName.call(person2, '英国','伦敦');  //ice 18 英国 伦敦
person.getName.apply(person2, ['美国','纽约']); //ice 18 美国 纽约
person.getName.bind(person2, '中国','上海')();  //ice 18 中国 上海
person.getName.bind(person2, ['中国','上海'])();  //ice 18 中国,上海 undefined
复制代码

总结:

  • 不传参的状况下,除bind方法后边多个()外,返回的结果和call、apply都是同样的。

  • 传参的状况下,call、apply、bind第一个参数都是改变this的指向对象,主要差异在第二个参数:

  • ​ call的参数以参数列表的形式直接存放,参数之间用逗号分隔;

  • ​ apply的参数以数组的形式存放,参数必须放置在一个数组里面;

  • ​ bind的参数存放形式和call是同样的,都是以参数列表的形式存放,参数直接用逗号分隔。

5、相关面试题

  1. 如何利用call、apply、bind来求一个数组中的最大或最小值?
var arr = [7, 8, 2, 1, 4, 3, 5, 6, 0];
console.log(Math.max.apply(Math, arr)); //8

console.log(Math.max.call(Math, 7, 8, 2, 1, 4, 3, 5, 6, 0)); //8
console.log(Math.max.bind(Math, 7, 8, 2, 1, 4, 3, 5, 6, 0)()); //8
console.log(Math.max.call(Math, arr)); //NaN
复制代码

求一个数组的最大或最小值,最方便的方法就是使用Math.max.apply方法。

注意:

在上边的代码中,由于不须要this去调用Math方法,apply的第一个参数能够写成null、underfined、window 、document均可以。

console.log(Math.max.apply(null, arr)); //8
复制代码

那你可能会问Math.max( )原本就能够求一组数中的最大值,那为何不直接使用Math.max( )呢?

由于Math.max( )的参数只能是Number类型的参数,若是放置一个数组会报错:

var arr = [7, 8, 2, 1, 4, 3, 5, 6, 0];
console.log(Math.max(arr)); //math is not defined

console.log(Math.max(7, 8, 2, 1, 4, 3, 5, 6, 0)); //8
console.log(Math.max(...arr));//8 也可使用扩展运算符,将数组转换成Number类型的参数
复制代码

而apply( )能够直接接受一个数组,能够将数组参数转换成列表参数传入,从而直接求数组的最大值。

最小值就不讲了,和Math.max同样的,直接Math.min替换Math.max便可。

  1. 如何利用call、apply来作继承
  2. call、apply、bind的区别和主要应用场景
  3. 何时该用call、apply、bind?
相关文章
相关标签/搜索