Codelet Keep code simple stupid

JavaScript构造函数检查

在JavaScript之中,构造函数和普通函数并没有本质区别,因此对构造函数的检查只能在函数调用时进行, 即相当于判断函数是否是以new的方式调用的。

总结一下大致有下面几种方式:

  1. instanceof
function Base () {
  if (!(this instanceof Base)) {
    throw new TypeError("Cannot call a class as a function");
  }
}

这种做法是最常见的,一般情况下足够了,不足是不能检测出Base.call(instance)这样的调用

  1. new.target

ES6之后新增了new.target语法,用于在new调用时指向构造函数,可以防止通过call/apply的 方式绑定this,从而绕过检查

function Base () {
  if (new.target === undefined) {
    throw new TypeError("Cannot call a class as a function");
  }
}
  1. constructor

instanceof类似,还可以借助constructor属性来判断this是否是实例对象,缺点也很明显, 不能防止call/apply调用,并且这样还会阻止子类的初始化,因为子类的constructor会指向子类 的构造函数,而不是基类,事实上这种方式常用来终止类的继承,模拟Java中的 final class

function Base () {
  if (!(this && this.constructor === Base)) {
    throw new TypeError("Cannot call a class as a function");
  }
}