JS手写系列 | 实现call、apply和bind

255 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

前言

今天这篇手写系列也是我自己在复习过程中的一则笔记,能够帮助我更好地理解并掌握call、apply和bind函数的底层逻辑。废话不多说,我们开始。

手写call

根据 MDN关于call的定义call() 方法使用一个指定的this值和单独给出的一个或多个参数来调用一个函数。举一个简单的栗子。

// Function.prototype.call()样例
function fun(arg1, arg2) {
  console.log(this.name)
  console.log(arg1 + arg2)
}
const obj = { name: '小陈同学吗' }
// 接受的是一个参数列表;方法立即执行
fun.call(obj, 1, 2)

// 输出:小陈同学吗 3

下面来实现自己的mycall,需要考虑的地方是,如果第一个参数为null或者undefined的,那么对象就会转变为window

Function.prototype.myCall = function(context) {
    if (typeof context === "undefined" || context === null) {
        context = window
    }
   //context=context||window  和上面的代码一样
    context.fn = this//(因为call的调用方式形如:myFun.call(obj),因此此时call方法的this指向为myFun,因此context.fn = this即为context.fn = myFun)
    const args = [...arguments].slice(1)//第一个参数为context,要去除
    const result = context.fn(...args)
    delete context.fn
    return result
}

手写apply

注意: 该方法的语法和作用与 call()方法类似,只有一个区别,就是 call() 方法接受的是一个参数列表,而 apply() 方法接受的是一个包含多个参数的数组

// Function.prototype.apply()样例
function fun(arg1, arg2) {
  console.log(this.name)
  console.log(arg1 + arg2)
}
const obj = { name: '小陈同学吗' }
// 接受的是一个参数列表;方法立即执行
fun.apply(obj, [1,2])

// 输出:小陈同学吗 3

这个地方我是这样记忆的:Apply开头字母是A,和Array开头一样,因此apply传递数组。

Function.prototype.myApply = function(context) {
    if (typeof this !== 'function') {
        throw new TypeError('Error.....')
    }
    context = context || window
    context.fn = this
    let result
    if (arguments[1]) {
        result = context.fn(...arguments[1])
    } else {
        result = context.fn()
    }
    delete context.fn
    return result
}

手写bind

call()apply()改过this的指向后,会再执行函数,bind()改过this后,不执行函数,会返回一个绑定新this的函数。

bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。

Function.prototype.myBind = function(context) {
    if (typeof this !== 'function') {
        throw new TypeError('Error....')
    }
    //返回一个绑定this的函数,这里我们需要保存this
    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))
    }
}

结语

以上就是本次手写JS的内容,实现了自己的简单版call、apply和bind函数,但还是有瑕疵的地方,需要再深入学习研究。