深入浅出JS—05 浅实现个call、apply、bind函数

在JavaScript语法中,call,apply和bind可以为函数显式绑定this
实际上是用C++实现的,但是我们可以用JS代码写一个自己的call,apply和bind函数,实现相同功能


一、call函数的实现

function fn(){
	console.log('fn')
}

fn.call(thisArg, ...args) //第一参数为函数fn执行时绑定的this,之后参数为传入fn的参数
fn.myCall(thisArg, ...args)  //自己实现call方法

1. 思考三个问题:

  • 如何给函数对象绑定myCall方法
    每个函数对象都继承了JS中的Function类,可以在原型上绑定方法,那么每个实例就都继承了该方法
// 将方法定义在原型上
Function.prototype.myCall(thisArg, ...args){ }
// 函数实例可以调用
fn1.myCall();
fn2.myCall();
  • 如何在myCall函数内部执行fn
    在函数原型上绑定方法后,任何一个函数实例都会继承到该方法。myCall函数是通过fn来调用,所以对于myCall而言,内部this隐式绑定fn,由此可以在myCall内部拿到fn
Function.prototype.myCall(thisArg, arg1, arg2, ...){
  const fn = this
}
  • 如何给函数fn绑定this
    采用隐式绑定的方法,将fn作为thisArg的方法来调用
thisArg.fn(arg1, arg2, ...)

2. myCall函数实现

Function.prototype.myCall(thisArg, ...args) { 
	const fn = this; // 获取调用myCall的函数
	thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window; // Object(thisArg)即使thisArg为字符串或者数字或者布尔类型,依然将其转换为对象
	
    const symFn = Symbol('fn'); // 将fn作为thisArg的方法调用,为了防止thisArg本身有同名方法,采用ES6的Symbol类型定义属性
    thisArg[symFn] = fn;
    const results = thisArg[symFn](...args);

	delete thisArgs[symFn]; // 调用完之后删除属性
	return results;    
}

二、apply函数的实现

apply函数的用法:fn.apply(thisArg, [arg1, arg2, arg3,...])
与call函数的区别在于参数是以数组形式传递的

Function.prototype.myApply(thisArg, args) { 
	const fn = this;
	thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window; 
	
    const symFn = Symbol('fn'); 
    thisArg[symFn] = fn;
	args = args || []; // 注意:若没传参数, args是undefined,那么...args会报错,因为undefined不具有迭代器,无法展开
    const results = thisArg[symFn](...args);

	delete thisArgs[symFn]; 
	return results;    
}

三、bind函数的实现

bind函数用法:

const foo = fn.bind(thisArg, ...bindArgs);
foo(...restArgs);

call和apply是在内部执行了函数,而bind不是,bind是返回一个函数,之后再执行

思考一个问题:

  • 如何保证foo函数执行时,fn是绑定thisArg的
    foo执行,内部fn依然是作为thisArg的方法来调用的就可以

bind函数实现

Function.prototype.myApply(thisArg, ...bindArgs) { 
	const fn = this;
	thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window; 
	
	function foo(...restArgs){
		const symFn = Symbol('fn'); 
   		thisArg[symFn] = fn;
    	const results = thisArg[symFn](...bindArgs, ...restArgs);
    	delete thisArgs[symFn]; 
	}
	return foo;    
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值