# call、apply、bind、new、instance

# 什么是this

  • 函数的执行上下文
  • 可以通过apply, call, bind改变this的指向
  • 匿名函数&直接调用的函数: this指向全局上下文
  • 箭头函数: 在哪里声明, this就指向哪里
  • 其余函数: 谁调用它, this就指向谁
  • new 关键字:指向new出来的对象

# call、apply、bind

  • 目的:改变this的指向
  • 参数不同,(bind返回一个函数,可以实现柯里化)

# 实现一个call函数

function.call(thisArg, arg1, arg2, ...)

    Function.prototype.myCall = function (context) {
      if (typeof context !== 'function') {
        throw new TypeError('error')
      }
      context = context || window;
      context.fn = this; // Cat.fn=Animal
      const args=[...arguments].slice(1)
      const result=context.fn(args) // Animal(args)
      delete context.fn
      return result
    }
1
2
3
4
5
6
7
8
9
10
11

# 实现一个apply函数

func.apply(thisArg, [argsArray])

    Function.prototype.myApply = function (context) {
      if (typeof context !== 'function') {
        throw new TypeError('error')
      }
      context = context || window;
      context.fn = this; // Cat.fn=Animal
      let result;
      if(arguments[1]){
        result=context.fn(...arguments[1])
      }else{
        result=context.fn()
      }
      delete context.fn
      return result
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 实现一个bind函数

function.bind(thisArg[, arg1[, arg2[, ...]]])

    Function.prototype.myBind = function (context) {
      if (typeof context !== 'function') {
        throw new TypeError('error')
      }
      const _this = this
      const args = [...arguments]
      return function F() {
        // new方式
        if (this instanceof F) {
          return new _this(...args, ...arguments)
        }
        // 直接调用方式
        return _this.apply(context, args.concat(...arguments)) // 如f.bind(obj, 1)(2),需要将两边的参数拼接起来
      }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 实现new功能

new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。new 关键字会进行如下的操作:

  1. 创建一个空的简单JavaScript对象(即{});
  2. 链接该对象(即设置该对象的构造函数)到另一个对象 ;
  3. 将步骤1新创建的对象作为this的上下文 ;
  4. 如果该函数没有返回对象,则返回this。
function create(fn,...args){//fn是要new的函数,args是函数的参数
  // 创建一个空对象obj,然后将fn的原型链接到obj的原型上
  let obj = Object.create(fn.prototype);
  // 绑定 this 实现继承,obj 可以访问到构造函数中的属性
  let res = fn.apply(obj,args);
  // 优先返回构造函数返回的对象,object/array/function优先返回,如果是其他类型则返回obj
  return res instanceof Object ? res : obj;
}
1
2
3
4
5
6
7
8

# instanceof

instanceof 可以正确的判断对象的类型,因为内部机制是通过判断对象的原型链中是不是能找到类型的 prototype

function instanceof(left, right) {
    // 获得类型的原型
    let prototype = right.prototype
    // 获得对象的原型
    left = left.__proto__
    // 判断对象的类型是否等于类型的原型
    while (true) {
    	if (left === null)
    		return false
    	if (prototype === left)
    		return true
    	left = left.__proto__
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14