new.target

ES6 提供了一个特殊的 API new.target,可以使用该 API 在函数内部,判断该函数是否使用了 new 来调用。

  1. new.target

new.target 有两个可能的值:

  1. undefined:该函数没有使用 new 关键字来调用;
  2. 函数本身:该函数是使用 new 关键字调用的;

虽然我们都知道,首字母大写的函数是构造函数,我们应当使用 new 关键字来调用。但是,若我们不使用 new 来调用,它也并不会报错。不过这样做的话,并不是我们所想看到的,并且无法的到我们所想要的结果。所以对于这样 错误调用的情况,我们想让它抛出错误。为了实现这样的需求,我们就需要知道:如何判断一个函数是否有使用 new 关键字来调用。

其实咋们在后面学习了 class 后,很可能就不再使用传统的构造函数来创建实例对象了,而是使用 class 的语法。而 class 恰恰有一个特点,如果我们不使用 new 关键字调用它,那么会报错,也就是说,它已经帮我们做好了校验,即: 如果使用 class 来创建实例对象的话,new.target 就没必要使用了。

应用场景:也许只有在开发内部协调相对比较频繁的系统,才会涉及到该需求。

codes

  • 1.js
  1. function Person(firstName, lastName) {
  2. this.firstName = firstName;
  3. this.lastName = lastName;
  4. this.fullName = `${firstName} ${lastName}`;
  5. }
  6. // 正确的调用方式:
  7. const p1 = new Person('da', 'huyou');
  8. // 错误的调用方式:
  9. const p2 = Person('da', 'huyou');
  10. /*
  11. 第二种错误的调用方式,相当于给 window 对象身上信新增了三个属性:firstName、lastName、fullName
  12. */

image.png

  • 2.js
  1. /*
  2. 需求:若使用调用普通函数的方式来调用一个构造函数,应该报错。
  3. ES6 之前的处理方式:!(this instanceof Person)
  4. 若 this 的原型链上没有构造函数 Person 的原型 Person.prototype 那么抛出错误。
  5. 使用这种方式来实现,旧存在弊端,我们可以通过 call、apply、bind 来强行令 this 的原型链上有构造函数 Person 的原型 Person.prototype。但是我们依旧没有使用 new 关键字来调用。
  6. */
  7. function Person(firstName, lastName) {
  8. if (!(this instanceof Person)) {
  9. throw new Error('没有使用 new 来调用 Person');
  10. }
  11. this.firstName = firstName;
  12. this.lastName = lastName;
  13. this.fullName = `${firstName} ${lastName}`;
  14. }
  15. // 正确的调用:
  16. const p1 = new Person('da', 'huyou');
  17. // 错误的调用:
  18. const p2 = Person('da', 'huyou'); // Uncaught Error: 没有使用 new 来调用 Person
  19. const p3 = Person.call(p1, 'Da', 'huyou'); // 还把 p1 给改了...
  20. /*
  21. 后面两次调用,都是错误的调用,但是使用 call 改变 this 指向之后的调用,并没有像我们预期的那样抛出错误。
  22. instanceof
  23. 对象 instanceof 构造函数
  24. true ==> 对象的原型链上 存在 构造函数的原型
  25. false ==> 对象的原型链上 不存在 构造函数的原型
  26. */

image.png

  • 3.js
  1. function Person(firstName, lastName) {
  2. if (new.target === undefined) { // 当没有使用 new 来调用 Person 构造函数时 那么 new.target 的值为 undefined
  3. throw new Error('没有使用 new 来调用 Person');
  4. }
  5. // new.target === Person; 表示Person函数通过 new 来调用
  6. this.firstName = firstName;
  7. this.lastName = lastName;
  8. this.fullName = `${firstName} ${lastName}`;
  9. }
  10. const p1 = new Person('da', 'huyou');
  11. const p2 = Person('da', 'huyou'); // Uncaught Error: 没有使用 new 来调用 Person
  12. const p3 = Person.call(p1, 'Da', 'huyou'); // Uncaught Error: 没有使用 new 来调用 Person