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 来调用 Person
const 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 的值为 undefined
throw 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 来调用 Person
const p3 = Person.call(p1, 'Da', 'huyou'); // Uncaught Error: 没有使用 new 来调用 Person