bind、call、apply 的区别、使用及实现

一、首先来看一下他们的区别

相同点:

这三个 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);
	}
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值