call()、apply()、bind() 都是用来改变函数运行时的this指向!面试
也就是改变函数执行的上下文,被称为改变this指向的三兄弟。数组
先记住如下this的总结,便于如下例子中this指向的理解:markdown
经过一个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( )方法能够接受参数,第一个参数是改变上下文的对象,从第二个参数开始以参数列表的形式展现,用逗号隔开。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 英国 伦敦
复制代码
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( )方法接受数组形式的参数。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( )行为都是一致的。
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方法返回的是一个新函数,必须调用它才会被执行。
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是同样的,都是以参数列表的形式存放,参数直接用逗号分隔。
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便可。