0
点赞
收藏
分享

微信扫一扫

面试题:手写 call、apply 及 bind 函数


1. 手写call()函数

实现​​call()​​的大致思路如下:

(1)首先,context是可选的参数,表示执行的上下文,如果不传的话,默认上下文为window

(2)接下来,为context创建一个fn属性,并将值设置为需要调用的函数

(3)由于call可以传入多个参数作为调用函数的参数,所以需要将参数都剥离出来

(4)然后调用函数,并将函数对象的上的函数删除

代码实现:

Function.prototype.myCall = function (context) { //判断调用对象
if (typeof this !== "function") {
console.error("type error");
}
//获取参数
let args = [...arguments].slice(1)
let result = null;
//判断context是否传入,如果未传入则设置为window
context = context || window;
//将调用函数设为对象的方法
context.fn = this;
//调用函数
result = context.fn(...args);
//将属性删除
delete context.fn;
return result;
}

2. 手写apply()函数

实现​​apply()​​的大致思路如下:

(1)首先,context是可选的参数,表示执行的上下文,如果不传的话,默认上下文为window

(2)接下来,为context创建一个fn属性,并将值设置为需要调用的函数

(3)由于call可以传入包含多个参数的数组作为调用函数的参数,所以需要将参数都剥离出来

(4)然后调用函数,并将函数对象的上的函数删除

代码实现:

Function.prototype.myApply = function (context) {
//判断调用对象是否为函数
if (typeof this !== "function") {
throw new TypeError("Error");
let result = null;
//判断context是否存在,如果未传入则为window
context = context || window;
//将函数设为对象的方法
context.fn = this;
//调用方法
if (arguments[1]) {
result = context.fn(...arguments[1]):
} else (
result = context.fn():
}
//将属性删除
delete context.fn;
return result;
}

3. 手写bind()函数

​bind()​​​函数和上面的两个函数稍微复杂一些,因为bind需要返回一个函数,需要判断一些边界的问题,实现​​bind()​​​的大致思路如下:
(1)首先,context是可选的参数,表示执行的上下文,如果不传的话,默认上下文为window

(2) 获取参数

(3) bind会返回一个函数,对于函数有两种的调用方法,一种是直接调用,另一种是通过new的方法调用:

  • 对于直接调用,这里我们用apply的方式来实现,但是对参数,需要注意以下情况:因为bind可能出现类似的代码​​f.bind(obj, 1)(2)​​​,所以我们需要将两边的参数拼接起来,于是就有了这样的实现​​args.concat(...arguments)​
  • 对于通过new调用,这种方式不会通过任何方式来改变this指向,所以对于这种情况,我们要忽略传入的this

代码实现”:

Function.prototype.myBind = function (context) {
if (typeof this !== 'function') {
throw new TypeError('Error')
}
const _this = this
const args = [...arguments].slice(1)
// 返回一个函数
return function F() {
// 因为返回了一个函数,我们可以 new F(),所以需要判断
if (this instanceof F) {
return new _this(...args, ...arguments)
}
return _this.apply(context, args.concat(...arguments))
}
}


举报

相关推荐

手写call、apply、bind

0 条评论