Typescript 凭什么可以和 JavaScript 并肩作战(6)—聊一聊 this 的问题

662 阅读2分钟

这是我参与8月更文挑战的第28天,活动详情查看:8月更文挑战

在 JavaScript 有关 this 问题,一直以来也是面试官喜欢问的一个问题,特别是 this 的指向问题,所以今天我们就聊一聊在 TypeScript 中类和方法中 this 指向问题。

重要的是要记住,TypeScript 并没有改变 JavaScript 的运行时行为,而 JavaScript 因为有一些独特的运行时行为。

class MyClass {
    name = "MyClass";
    getName() {
      return this.name;
    }
  }
  const c = new MyClass();
  const obj = {
    name: "obj",
    getName: c.getName,
  };
   
  // Prints "obj", not "MyClass"
  console.log(obj.getName());

长话短说,默认情况下,函数内this 具体表示什么值是取决于函数的调用方式。在这个例子中,因为函数是通过obj 引用调用的,所以 this值是obj而不是类实例。这很少是你希望发生的事情! TypeScript提供了一些方法来减轻或防止这种错误。

箭头函数

如何经常会遇到这种情况,调用函数时丢失了函数的 ·this 这个上下文对象,为了 this 丢失可以通过箭头函数来代替普通函数来解决这个问题。

callapplybind方法不适合箭头函数,因为它们被设计为允许方法在不同的作用域内执行。因为箭头函数根据箭头函数定义的作用域来定义 this

class MyClass {
    name = "MyClass";
    getName = () => {
        return this.name;
    }
}
const c = new MyClass();
const obj = {
    name: "obj",
    getName: c.getName,
};

// Prints "obj", not "MyClass"
console.log(obj.getName());

需要做一些权衡

  • 即使在没有 TpyeScript 对代码进行检测情况下,在运行时也需要保证this值保证正确地使用
  • 这将占用更多的内存,因为类每一个实例都会拥有这种方式定义的方法的副本
  • 无法在子类中使用super.getName,因为在原型链中没有条目可以获取基类方法

在类中,一个叫做this的特殊类型动态地指向当前类的类型。接下来,下面的例子中可以看到modelType 类型为 Model3

class Car{
    model:string = ""
    set(model:string){
        this.model = model
        return this
    }
}

class Model3 extends Car{
    clear(){
        this.model = ""
    }
}

const model_3 = new Model3()
const modelType = model_3.set("model 3") // Model3

this 也可以作为类方法的参数的类型使用

class Rect{
    width:number;
    height:number;

    constructor(w:number,h:number){
        this.width = w;
        this.height = h;
    }

    compareWith(other:this){
        
    }

}

这与写其他不同。Rect 的子类 Square 的 compareWith 方法现只接受的子类只是继承没否实现自己方法或定义自己的属性,例如length:number = 0 这是实例上调用 compareWith 方法就无法接受 Rect 的实例来作为参数

class Square extends Rect{
    length:number = 0
}

const rect = new Rect(12,15)

const square = new Square(12,12)

console.log(square.compareWith(rect))