一、实现call

函数call调用方式:

1
2
3
4
5
function foo(name, age) {
  console.log(this, name, age)
}

foo.call({ name: "mocha" }, 20)  // {name: 'mocha'} 'mocha' 20

手写call:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
function foo(name, age) {
  console.log(this, name, age)
}

Function.prototype.moCall = function (thisArg, ...otherArgs) {
  // this -> 指向当前调用的函数对象
  // thisArg -> 传入的第一个参数,是要绑定的this

  // 确保thisArg是对象类型
  thisArg = (thisArg === null || thisArg === undefined) ? window : Object(thisArg)

  Object.defineProperty(thisArg, "fn", {
    configurable: true,
    value: this
  })
    
  thisArg.fn(...otherArgs)

  delete thisArg.fn
}

foo.moCall({ name: "mocha" }, 20)  // {name: 'mocha', fn: ƒ} 'mocha' 20

二、实现apply

函数apply调用方式:

1
2
3
4
5
function foo(name, age) {
  console.log(this, name, age)
}

foo.apply({ name: "mocha" }, [20])  // {name: 'mocha'} 'mocha' 20

手写apply:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
function foo(age) {
  console.log(this, this.name, age)
}

Function.prototype.moApply = function (thisArg, otherArgs) {
  // this -> 指向当前调用的函数对象
  // thisArg -> 传入的第一个参数,是要绑定的this

  // 确保thisArg是对象类型
  thisArg = (thisArg === null || thisArg === undefined) ? window : Object(thisArg)

  Object.defineProperty(thisArg, "fn", {
    configurable: true,
    value: this
  })

  thisArg.fn(...otherArgs)

  delete thisArg.fn
}

foo.moApply({ name: "mocha" }, [20])  // // {name: 'mocha', fn: ƒ} 'mocha' 20

三、实现bind

函数bind调用方式:

1
2
3
4
5
6
7
function foo(age) {
  console.log(this, this.name, age)
}

var newfoo = foo.bind({ name: "mocha" }, 20)

newfoo()  //  {name: 'mocha'} 'mocha' 20

手写bind:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
function foo(age, height) {
  console.log(this, this.name, age, height)
}

Function.prototype.moBind = function (thisArg, ...otherArgs) {
  thisArg = (thisArg === null || thisArg === undefined) ? window : Object(thisArg)

  Object.defineProperty(thisArg, "fn", {
    configurable: true,
    enumerable: false,
    writable: false,
    value: this
  })
    
  return (...newArgs) => {
    thisArg.fn(...otherArgs, ...newArgs)
  }
}

var newFoo = foo.moBind({ name: "mocha" }, "gmi")

newFoo(1.88)  // {name: 'mocha', fn: ƒ} 'mocha' 'gmi' 1.88