call, apply, bind 区别

首先说下前两者的区别。

callapply 都是为了解决改变 this 的指向。作用都是相同的,只是传参的方式不同。

除了第一个参数外,call 可以接收一个参数列表,apply 只接受一个参数数组。

  1. let a = {
  2. value: 1
  3. }
  4. function getValue(name, age) {
  5. console.log(name)
  6. console.log(age)
  7. console.log(this.value)
  8. }
  9. getValue.call(a, 'yck', '24')
  10. getValue.apply(a, ['yck', '24'])

模拟实现 call 和 apply

可以从以下几点来考虑如何实现

  • 不传入第一个参数,那么默认为 window
  • 改变了 this 指向,让新的对象可以执行该函数。那么思路是否可以变成给新的对象添加一个函数,然后在执行完以后删除?
  1. Function.prototype.myCall = function (context) {
  2. var context = context || window
  3. // 给 context 添加一个属性
  4. // getValue.call(a, 'yck', '24') => a.fn = getValue
  5. context.fn = this
  6. // 将 context 后面的参数取出来
  7. var args = [...arguments].slice(1)
  8. // getValue.call(a, 'yck', '24') => a.fn('yck', '24')
  9. var result = context.fn(...args)
  10. // 删除 fn
  11. delete context.fn
  12. return result
  13. }

以上就是 call 的思路,apply 的实现也类似

  1. Function.prototype.myApply = function (context) {
  2. var context = context || window
  3. context.fn = this
  4. var result
  5. // 需要判断是否存储第二个参数
  6. // 如果存在,就将第二个参数展开
  7. if (arguments[1]) {
  8. result = context.fn(...arguments[1])
  9. } else {
  10. result = context.fn()
  11. }
  12. delete context.fn
  13. return result
  14. }

bind 和其他两个方法作用也是一致的,只是该方法会返回一个函数。并且我们可以通过 bind 实现柯里化。

同样的,也来模拟实现下 bind

  1. Function.prototype.myBind = function (context) {
  2. if (typeof this !== 'function') {
  3. throw new TypeError('Error')
  4. }
  5. var _this = this
  6. var args = [...arguments].slice(1)
  7. // 返回一个函数
  8. return function F() {
  9. // 因为返回了一个函数,我们可以 new F(),所以需要判断
  10. if (this instanceof F) {
  11. return new _this(...args, ...arguments)
  12. }
  13. return _this.apply(context, args.concat(...arguments))
  14. }
  15. }