JavaScript中的bind()、call()和apply()这几个方法使得函数在特定的作用域中执行,三者都能改变函数内this的指向。
它们的第一个参数都是this要指向的对象,也都可以进行后续的传参。
那么,它们的作用和区别在哪里?看下面的代码。
var obj={
name:"zhangsan",
age:"25"
}
var person={
name:"lisi",
age:"20",
say:function(){
console.log(this.name);
}
}
person.say(); // 输出‘lisi’
如果想要输出的是‘zhangsan’,应该怎么做?
第一想到的是当然可以使用闭包,将想要访问的外部this对象保存到闭包能访问到的变量中。
var obj={
name:"zhangsan",
age:"25"
}
var person={
name:"lisi",
age:"20",
say:function(){
return function(){
var that=this;
console.log(that.obj.name);
}()
}
}
person.say(); // 输出‘zhangsan’
其次,还可以使用提到的这三种方法。
person.say.call(obj); // 输出‘zhangsan’
person.say.apply(obj); // 输出‘zhangsan’
person.say.bind(obj)(); // 输出‘zhangsan’
注意
- call和apply可以对函数直接调用,直接执行。
- 而bind只是改变this的指向,预处理this,不是立即执行的,返回值是一个改变this指向的函数,需要跟上()才能立即执行。IE6-8不支持bind。
- fn.call(null) 第一个参数传null/undefined/不传,在非严格模式下this为window;严格模式下传递的this是谁指向谁,不传this就是undefined。
- call是逐个传参,apply可以传数组或者类数组。
var obj={
name:"zhangsan"
}
var person={
name:"lisi",
age:"20",
say:function(age,sex){
console.log(this.name+','+age+','+sex);
}
}
person.say.apply(obj,['25','男']); // 输出 zhangsan,25,男
var obj={
name:"zhangsan"
}
var person={
name:"lisi",
age:"20",
say:function(age,sex){
console.log(this.name+','+age+','+sex);
}
}
person.say.call(obj,'25','男'); // 输出 zhangsan,25,男
补充用法
- 当目标函数有n个参数列表,不接收数组的形式,可以使用apply将一个数组装换为一个个参数传递给方法。
获取数组最小项
let minNumber = Math.min.apply(null, array); // Math.max参数不支持传数组形式的参数
也可以用Math.min(…array)
获取数组最大项
let maxNumber = Math.max.apply(null, array);
数组合并(不能push一个数组,push(param1,param2,…paramN))
Array.prototype.push.apply(arr1,arr2); // arr1调用push方法
- 伪数组转化为真数组
伪数组:包含length属性,但没有数组的方法,arguments/dom元素/包含length属性的对象等
Array.prototype.slice.call(arguments)
[].slice.call(arguments)
// 其他方法
const args = Array.from(arguments);
const args = […arguments];
Array.apply(null,arguments);
- 对象继承Function.apply(obj,arguments)
apply方法能够劫持另一个对象的方法,继承另一个对象的属性。
// 类的继承apply
function Person(name, age) { //定义一个类,人类
this.name = name;
this.age = age;
this.say = function () {
alert(name + ' is ' + age + ' years old');
}
}
function Student(name, age) {
Person.apply(this, arguments);
// Person.call(this, name, age);
console.log(arguments) //对象,访问name、age等实参参数
}
var s1 = new Student('zs', 26);
s1.say();
- 判断数据类型 数组/对象
Object.prototype.toString.call(arr) === '[object Array]'
Object.prototype.toString.call(arr) === '[object Object]'
Object.prototype.toString.call(arr) === '[object String]'
Object.prototype.toString.call(arr) === '[object Null]'