前端面试题:手写call,apply和bind

前段时间一朋友面试,被要求手写call,apply和bind,发现自己也不会写,所以就私底下去看了一下这方面的东西,后来发现这个还是挺容易实现的,现在也是分享出来,一方面方便自己查看复习,另一方面希望可以给需要的朋友一点帮助。

正式开始之前也是先去了解一下call,apply,bind。其实呢这三兄弟都是为了改变函数的上下文而存在的,或者可以简单点说就是用来改变this指向的。但是呢这三兄弟的用法还是有区别的。

1、apply和call会让当前函数立即执行,而bind会返回一个函数,后续需要的时候再调用执行

2、apply最多只能有两个参数,而call,bind可以有多个参数,第一个参数和apply一样,是用来替换的对象,后边是参数列表

在实现手写方法之前,我们还有一些问题需要考虑,比如说函数定义的位置,接受的参数,或者说是如何显式的绑定this,怎么拿到参数,或者说没有参数的时候怎么办???都是我们需要考虑的问题。

因为我们需要让所有的地方都可以去访问到,所以我们把自定义的函数写在Function的原型上,因为所有的函数 instanceof Function都是会返回true的,所以定义在Function的prototype上,想要了解原型的,可以去我的上一篇博客前端面试题:原型和原型链去详细了解。call和bind我们接收第二个以后的参数,所以可能会用到slice方法,而apply直接接受第二个参数就行了。那么如何显式的绑定this呢,如果调用者函数,被某一个对象所拥有,那么该函数在调用时,内部的this指向该对象。拿取参数的话,我们还是用最简单的方式arguments,没有参数的情况下我们就直接将函数无参返回,如果没有传入对象的话直接指向window,这样的话我们的手写函数就和原来的call,apply和bind没什么两样了。

也算是差不多了,就这样,盘他,盘他,盘他。。

Function.prototype.MyCall = function(context){
//直接将函数放在Function的prototype上,方便调用
		const ctx = context || window;
//这里是将传入对象存到ctx里边,如果没有传入的话就指向window,因为原来的call也是这样的
		ctx.func = this;
//改变this的指向,换句话说相当于是把这个函数直接给到传入的对象
		const args = Array.from(arguments).slice(1);
//这里就是要去拿到函数的参数,把类数组转为数组之后,减去第一个,给到args备用
		const res = arguments.length > 1 ? ctx.func(...args) : ctx.func();
//就是说如果有参数,把args解构传进去,没有的话就不传了
		delete ctx.func;
//这个时候的func已经没有用了,直接返回res
		return res
//一步一注释应该是简单易懂的
	}

apply跟call是一样的,只是参数的处理简单一点,就不一步一注释了。

Function.prototype.MyApply = function(context){
	const ctx = context || window;
	ctx.func = this;
	const res = arguments[1] ? ctx.func(...arguments[1]):ctx.func();
	delete ctx.func;
	return res
}

bind有所不同,bind函数返回一个绑定函数,最终调用需要传入函数实参和绑定函数的实参。如果调用者函数,被某一个对象所拥有,那么该函数在调用时,内部的this指向该对象。

Function.prototype.MyBind = function(context){
	console cxt = JSOn.parse(JSON.stringify(context)) || window;
	cxt.func = this;
	const args = Array.from(arguments).slice(1);
	return function(){
		const allArgs = args.concat(Array.from(arguments));
		return allArgs.length > 0 ? cxt.func(...allArgs):cxt.func();
	}
}

 

你可能感兴趣的:(三大基础,面试题库,个人总结,javascript,bind,es6)