函数可以作为一个构造函数来创造一个对象,也可以作为一个普通函数来调用
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
this.fullName = `${firstName} ${lastName}`;
}
const p1 = new Person("袁", "进");
console.log(p1) //Person {firstName: "袁", lastName: "进", fullName: "袁 进"}
const p2 = Person("袁", "进");
console.log(p2); //undefined
第二种方式运行无效,(并且this指向了Window)
所以需要判断是不是用new的方式调用函数
过去的判断方式
function Person(firstName, lastName) {
if (!(this instanceof Person)) {
throw new Error("该函数没有使用new来调用")
}
this.firstName = firstName;
this.lastName = lastName;
this.fullName = `${firstName} ${lastName}`;
}
但是如果这样呢
const p3 = Person.call(p1, "袁", "进")
console.log(p3); //undefined
这段代码只是说明这种判断拦截方式还是可能被绕开,而错误执行的。
es6提供了一个特殊的API,可以使用该API在函数内部,判断该函数是否使用了new来调用
new.target 该表达式得到的是:如果没有使用new来调用函数,则返回undefined;如果使用new调用函数,则得到的是new关键字后面的函数本身
function Person(firstName, lastName) {
console.log(new.target)
this.firstName = firstName;
this.lastName = lastName;
this.fullName = `${firstName} ${lastName}`;
}
使用new调用,普通函数调用,用call那种方式的调用,我们来看一下new.target 的输出。
三次调用函数,输出三次new.target的值正如前述,使用new调用的返回new关键字后面的函数本身,没有使用new调用的,包括那种用call绑定this指向绕过以前那种判断方式的调用也返回undefined
这样就可以完美的判断是否使用了new调用。
所以该构造函数可以写做:
function Person(firstName, lastName) {
if (new.target === undefined) {
throw new Error("该函数没有使用new来调用")
}
this.firstName = firstName;
this.lastName = lastName;
this.fullName = `${firstName} ${lastName}`;
}
在写了构造函数以后, 担心别人乱用这个构造函数时,可以使用它。
它是从语法层面来判断是否使用了new来调用,而不是通过this指向间接的有缺陷的判断