揭秘 JS 之 call、apply、bind

定义

call()apply()bind() 都是用来重定义this 这个对象的。

var name = 'jay'
var obj = {
  name: 'bob',
  say: function (a, b) {
    console.log(this.name)
    console.log(a, b)
  }
}

var obj2 = {
  name : 'mary'
}

obj.say.apply(null) // jay 指向window
obj.say.apply(obj2) // mary
obj.say.call(obj2) // mary
obj.say.bind(obj2)() // mary  返回函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

以上bind 方法后面多了个()外,结果返回都一致。 由此得出结论,applycall都是直接执行指定的函数,bind 是返回一个新的函数,你必须重新调用才会被执行。

call apply bind 传参对比

obj.say.call(obj2, 'a', 'b') // a, b
obj.say.apply(obj2, [1, 2]) // 1, 2
obj.say.bind(obj2, 1, 2)() // 1, 2
obj.say.bind(obj2, [1, 2]])()// [1, 2] undefined
1
2
3
4

源码

如何实现call

Function.prototype.MyCall = function (context) {
  var newContext = context || window // 缺省指向window
  newContext.fn = this // this 指向调用它的函数
  var args = [...arguments].slice(1) // 截取除去第一个对象以外的参数
  var result = newContext.fn(...args) // 执行函数方法
  delete newContext.fn // 执行完毕后,删除函数
  return result  // 返回函数return的值
}
1
2
3
4
5
6
7
8

如何实现apply

Function.prototype.MyApply = function (context, array) {
  var newContext = context || window // 缺省指向window
  newContext.fn = this
  var result 
  if (Object.prototype.toString.call(array) === '[object Array]') {
    result = context.fn(...array)
    delete context.fn
    return result
  } else {
    result = context.fn();
  }
  delete context.fn
  return result
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

如何实现bind

Function.prototype.MyBind = function (context) {
  context.fn = this
  var args = [...arguments].slice(1)
  return function () {
    var result = context.fn(...args)
    delete context.fn
    return result
  }
}

obj.say.MyBind(obj2, 1, 2)() // 1, 2
obj.say.MyBind(obj2, [1, 2])() // [1, 2], undefined
1
2
3
4
5
6
7
8
9
10
11
12
最后更新时间: 11/8/2019, 11:24:52 AM