new.target
ES6 提供了一个特殊的 API new.target,可以使用该 API 在函数内部,判断该函数是否使用了 new 来调用。
new.target
new.target 有两个可能的值:
- undefined:该函数没有使用 new 关键字来调用;
- 函数本身:该函数是使用 new 关键字调用的;
虽然我们都知道,首字母大写的函数是构造函数,我们应当使用 new 关键字来调用。但是,若我们不使用 new 来调用,它也并不会报错。不过这样做的话,并不是我们所想看到的,并且无法的到我们所想要的结果。所以对于这样 错误调用的情况,我们想让它抛出错误。为了实现这样的需求,我们就需要知道:如何判断一个函数是否有使用 new 关键字来调用。
其实咋们在后面学习了 class 后,很可能就不再使用传统的构造函数来创建实例对象了,而是使用 class 的语法。而 class 恰恰有一个特点,如果我们不使用 new 关键字调用它,那么会报错,也就是说,它已经帮我们做好了校验,即: 如果使用 class 来创建实例对象的话,new.target 就没必要使用了。
应用场景:也许只有在开发内部协调相对比较频繁的系统,才会涉及到该需求。
codes
- 1.js
function Person(firstName, lastName) {this.firstName = firstName;this.lastName = lastName;this.fullName = `${firstName} ${lastName}`;}// 正确的调用方式:const p1 = new Person('da', 'huyou');// 错误的调用方式:const p2 = Person('da', 'huyou');/*第二种错误的调用方式,相当于给 window 对象身上信新增了三个属性:firstName、lastName、fullName*/

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

- 3.js
function Person(firstName, lastName) {if (new.target === undefined) { // 当没有使用 new 来调用 Person 构造函数时 那么 new.target 的值为 undefinedthrow new Error('没有使用 new 来调用 Person');}// new.target === Person; 表示Person函数通过 new 来调用this.firstName = firstName;this.lastName = lastName;this.fullName = `${firstName} ${lastName}`;}const p1 = new Person('da', 'huyou');const p2 = Person('da', 'huyou'); // Uncaught Error: 没有使用 new 来调用 Personconst p3 = Person.call(p1, 'Da', 'huyou'); // Uncaught Error: 没有使用 new 来调用 Person
