一、首先来看一下他们的区别
相同点:
这三个 api 都可以改变 this 的指向
第一个参数都是 this 指向的对象
如果第一个参数是 null undefined ,则函数的 this 不改变
都可以传递参数
不同点:
1、call 和 apply 都可以对函数进行直接调用,bind 方法返回的是一个函数,需要手动调用函数
let obj= {
name:'小米',
print(){
console.log(`${this.name}`)
}
}
let obj1 = {
name:'华为'
}
obj.print.call(obj1)
obj.print.apply(obj1)
obj.print.bind(obj1)()
三种方法都可以将 obj.print 的 this 指向 obj1;打印的结果都是一样的,但是写法上 bind 需要手动调用一下才会执行函数。
2、传参方式不同
let obj= {
name:'小米',
print(a,b){
console.log(`${this.name}参数${a}-${b}`)
}
}
let obj1 = {
name:'华为'
}
obj.print.call(obj1,1,2)
obj.print.apply(obj1,[1,2])
obj.print.bind(obj1,1,2)()
//obj.print.bind(obj1)(1,2)
call 和 bind 传递的参数和 print 方法里面的是一一对应的,而 apply 传递是的一个数组,数组里的元素和 print 方法里面的是一一对应的
bind 还可以在调用的时候进行传参,和上面代码注释掉的那样
二、常见使用
1、将类数组转换成真数组
类数组:有 length 属性和数值下标属性,但是不具有数组的方法,它是一个 Object。
(常见的类数组 querySelectorAll,getElementByclassName,getElementsByTagName,arguments的集合)
let pseudoArr = {
0: 2,
1: 4,
2: 5,
3: 7,
4: 9,
length: 5
}
let arr = [];
arr.push.apply(arr,weiArr);
//arr = [].slice.call(weiArr);
2、无入侵获取无序数组的最大值最小值
let arr = [1,2,3,9,4,12,10];
//获取最大值
let max = Math.max.call(null,...arr);
let max = Math.max.apply(null,arr);
let max = Math.max.bind(null,...arr)();
//获取最小值
let min= Math.min.call(null,...arr);
let min= Math.min.apply(null,arr);
let min= Math.min.bind(null,...arr)();
call、apply、bind 会将数组作为参数传给 Math.min() 方法;
3、合并数组
let arr1 = [1,2,3];
let arr2 = [4,5,6];
Array.prototype.push.apply(arr1,arr2);
//Array.prototype.push.call(arr1,...arr2);
console.log(arr1); // [1,2,3,4,5,6]
4、判断数组是数组
let arr = [1,2,3];
console.log(Object.prototype.toString.cal(arr) == '[object Array]'); //true
三、手动实现
1、call
核心思想:给 obj 设置一个尽量唯一的属性,属性值是要执行的函数(需要改变this的函数),然后执行函数并传入参数,最后删除设置的新属性。
Function.prototype.testCall = function(obj,...params){
//判断obj(目标对象)是否存在,不存在则默认 window
obj = obj || window;
//利用 Symbol 定义一个唯一的属性名 Symbol(KEY)
let key = Symbol('KEY'),result;
//用 this 获取调取 testCall 的函数,并赋值给 obj[key]
obj[key] = this;
//传参给 obj 的 obj[key] 函数并调用
result = obj[key](...params);
delete obj[key];
return result;
}
2、apply
Function.prototype.testApply= function(obj,params){
obj = obj || window;
let key = Symbol('KEY'),result;
obj[key] = this;
if(!params){
result = obj[key]()
}else{
if(!params instanceof Array){
console.log('第二个参数必须是数组!')
}else{
result = obj[key](...params)
}
}
return result;
}
3、bind
Function.prototype.testBind = function(obj,...params){
let that = this;
return function (){
let paramsArr = params.concat(arguments)
that.apply(obj,paramsArr);
//that.call(obj,...paramsArr);
}
}