🐸简单明了一文教你手写bind、call、apply

167 阅读2分钟

🐸简单明了一文教你手写bind、call、apply

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情

修改JS中this的指向是面试中老生常谈的问题了,实际开发中我们也会遇到他们的使用场景,今天带大家手写这三个方法。

1. 使用方法

首先创建两个对象:

const ObjA = {
  name: 'ObjA',
  say(words: string = 'Hello', words2: string = '') {
    console.log(`${this.name} 说:${words}${words2}`)
  }
}

const ObjB = {
  name: 'ObjB',
  say(words: string = 'Hello', words2: string = '') {
    console.log(`${this.name} 说:${words}${words2}`)
  }
}
ObjA.say()
ObjB.say()

这时候打印出来的肯定就是他们各自的打印效果:

ObjA 说:Hello
ObjB 说:Hello

1.1 bind 方法

会修改this的指向,但是不会立即执行,原函数所需要的参数在调用时传入即可。

// this指向ObjA
ObjB.say.bind(ObjA)()
ObjB.say.bind(ObjA)('Hello World', '!')

输出:

ObjA 说:Hello
ObjA 说:Hello World

1.2 call 方法

会修改this的指向,会立即执行,原函数所需要的参数在第2、3、...(以此类推)位置。

ObjB.say.call(ObjA)
ObjB.say.call(ObjA, 'Hello World', '!')

输出:

ObjA 说:Hello
ObjA 说:Hello World

1.3 apply 方法

会修改this的指向,会立即执行,原函数所需要的参数需要放进一个数组里面,然后放在第二个位置。

ObjB.say.apply(ObjA)
ObjB.say.apply(ObjA, ['Hello World', '!'])

输出:

ObjA 说:Hello
ObjA 说:Hello World

2. 手写实现

2.1 手写bind

Function.prototype.myBind = function(context, ...args) {
  context = (context === undefined || context === null) ? window : context
	let self = this
  return function(...args2) {
  	context._Fn = self
    let result = context._Fn(...[...args, ...args2])
    delete context._Fn
    return result
  }
}
  • 首先判空,处理传入的对象为null或者undefined
  • 先保存当前调用函数的this
  • 隐式绑定,当前函数的this指向了context
  • 因为bind不会立即执行,所以要返回一个函数result

2.2 手写call

call方法和bind方法唯一不同就是,bind不会立即执行,call是立即执行,因此我们不需要创建一个新的函数去返回。

Function.prototype.myCall = function(context, ...args) {
  context = (context === undefined || context === null) ? window : context
	context._Fn = this
  let result = context._Fn(...args)
  delete context._Fn
  return result
}
  • 判空,处理传入的对象为null或者undefined
  • 隐式绑定,当前函数的this指向了context
  • 直接返回result

2.2 手写apply

apply方法和call方法差不多,只不过是apply用一个数组来接受其他参数。

// 第二个参数无需解构,因为他是一个数组
Function.prototype.myApply = function(context, args) {
  context = (context === undefined || context === null) ? window : context
	context._Fn = this
  let result = context._Fn(...args)
  delete context._Fn
  return result
}
  • 判空,处理传入的对象为null或者undefined
  • 隐式绑定,当前函数的this指向了context
  • 直接返回result

上面只是简单实现了几种改变this的方法,主要是提供一个思路,大家后面也可以想想如何解决一些复杂的改变this指向情况。