js中call、apply、bind有什么区别?原理是什么?bind函数返回的方法为什么不能再修改this?

最近在工作中突然想到bind函数返回的新函数为什么不能再修改this?于是详细去了解下三个方法的区别,原理。

1、call、apply、bind区别

call方法中接收的是一个参数列表,第一个参数指向this,参数列表在函数执行时都会作为函数形参传入函数。

fn.call(this, arg1, arg2, ...);

apply方法与call方法是一样的、实现方式也基本一样、只是接收的是一个参数数组

fn.call(this, arg1, arg2, ...);

bind与call、apply的区别,call与apply在改变this的时,就会立马执行,而bind绑定this后并不会立马执行,而是返回一个改变了this指向的新函数。

let obj = {}
let fn = function(){
	return this === obj
}
let fn1 = fn.bind(obj);
console.log(fn()) // false
console.log(fn1()) // true

2、call、apply、bind方法的实现。

call实现

function myCall(context){
	const arg = [...arguments].slice(1) // 获取形参
	const _this = this // 保存方法的原this
	context = context ? Object(context) : window  // object转换防止原始类型
	context.fn = _this // 原this赋值fn
	const result = context.fn(...arg)
	delete context.fn // 执行完成 删除新增属性
	return result // 将结果返回 
}

apply实现方式与call基本相同

function myApply(context){
	const arg = arguments[1]
	if(!(arg instanceof Array)){  // 第二个参数不为数组抛出错误
		throw new Error('CreateListFromArrayLike called on non-object')
	}
	const target = this
	context = context ? Object(context) : window
	context.fn = target
	const result = context.fn(...arg)
	delete context.fn
	return result
}

bind实现

function myBind(context){
	 const bindArg = [...arguments].slice(1)  // 获取形参
     const _this = this // 保存方法的原this
	 return function(){
		_this.myApply(context,[...arguments].concat(bindArg ))
	}
}

3、bind函数返回的方法为什么不能再修改this?

const obj = {};
const fn = function() {
  console.log('test bind');
};
console.log({ fn: fn.bind(obj) });

尝试打印bind返回的新函数fn,可以看到它并不是一个普通的function,而是一个bound function,简称绑定函数:
在这里插入图片描述

它的TargetFunction指向了bind前的函数,BoundThis就是绑定的this指向,BoundArgs便是传入的其它参数了。

我们可以得出一个结论,当执行绑定函数时,this指向与形参在bind方法执行时已经确定了,无法改变。

换个思路理解,当执行fn1时,本质上等于window.fn1(),如果this还能被改变,那this岂不是得指向window,那bind方法就没太大意义了。

4、应用

我们都知道Math.max()方法能取到一组数字中的最大值,比如:

Math.max(1, 10); //10
Math.min(1, 10); //1

那我们如何利用此方法求数组中最大最小呢,这里就可以利用apply的特性了:

Math.max.apply(null, [1, 2, 10]); //10
Math.min.apply(null, [1, 2, 10]); //1

在非严格模式下,当我们让this指向null,或者undefined时,this本质上会指向window,不过这里的null就是一个摆设,我们真正想处理的其实是后面的数组。

还记得万能的属性判断方法吗?Object.prototype.toString()结合call方法:

let a = [];
let b = function () {};
Object.prototype.toString.call(a) === "[object Array]" //true
Object.prototype.toString.call(b) === "[object Function]" //true
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值