如何实现call,apply,bind方法?

很久前写过一篇call,apply,bind的作用,最近学习的过程中看了一篇手写这三个方法的文章。才想起这么多年其实一直知其然不知所以然,还是要更深入原理才好,接下来整理一下我自己的写法。

实现call

首先我们看call的用法,比如fn.call(obj,a,b,...)。从中可以看书,call是函数的一个方法,所以我们把它加在Function.prototype上,传入上下文context,首先判断this是否是function,不是就提示错误。另外当context不传时默认为window。然后再处理传入的参数即可,代码如下:

Function.prototype.myCall = (context = window, ...args) {
	if(typeOf this !== 'function') {
		throw new TypeError('Error');
	}
	// 我们需要暂时将this挂载在context上
	// 为了确保不因为属性名冲突而污染context对象
	// 我们使用Symble来获取独一无二的值fn
	const fn = Symble('fn');
	// 然后挂载
	context[fn] = this;
	const result = context.fn(...args);
	// 执行完删掉fn,保证context跟原来一样
	delete context[fn];
	// 返回结果
  	return result;
}

实现apply

实现了call方法之后,apply方法就很简单了,他俩的区别只在于参数而已,代码如下:

Function.prototype.myApply = (context = window, args) {
	if(typeOf this !== 'function') {
		throw new TypeError('Error');
	}
	const fn = Symble('fn');
	context[fn] = this;
	let result = args ? context.fn(...args) : context.fn();
	delete context[fn];
  	return result;
}

实现bind

bind和之前两者的区别在于,他不会立即执行,只是绑定了上下文

  • 前几步和之前的实现大相径庭,就不赘述了
  • bind 返回了一个函数,对于函数来说有两种方式调用,一种是直接调用,一种是通过 new 的方式,我们先来说直接调用的方式
  • 对于直接调用来说,这里选择了 apply 的方式实现,但是对于参数需要注意以下情况:因为 bind 可以实现类似这样的代码f.bind(obj, 1)(2),所以我们需要将两边的参数拼接起来,于是就有了这样的实现args.concat(...arguments)
  • 最后来说通过 new 的方式,在之前的章节中我们学习过如何判断 this,对于 new 的情况来说,不会被任何方式改变 this,所以对于这种情况我们需要忽略传入的 this

所以代码如下:

Function.prototype.myBind = (context, ...args) {
	if(typeOf this !== 'function') {
		throw new TypeError('Error');
	}
	const fn = this
  	return function F() {
		// 因为返回了一个函数,我们可以 new F(),所以需要判断
	    if (this instanceof F) {
	    	// F在this的原型链上,所以是new出来的
	    	// new 出来的新函数,他的this定在new的时候,此时忽略这个context
	    	return new fn(...args, ...arguments);
	    }
	    // 正常调用bind的时候,再给他apply返回
	    return fn.apply(context, args.concat(...arguments));
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值