明确函数的双重作用(Clarifying the Dual Purpose of Functions)
在ES5及更早的ES版本中,函数调用时是否使用new会有不同的作用。当使用new时,函数内的this指向一个新对象并且函数会返回这个对象。看下面的代码:
function Person(name) {
this.name = name;
} var person = new Person("Zakas");
var notAPerson = Person("Zakas"); console.log(person); // [Object object]
console.log(notAPerson); // undefined
一个自然的问题就是:如何判断函数调用时有没有使用new。在ES5中使用instanceof来判断:
function Person(name) {
if (this instanceof Person) {
this.name = name;
} else {
throw new Error("You must use new with Person");
}
} var person = new Person("Zakas");
var notAPerson = Person("Zakas"); // throws an error
上面的代码会判断this是不是Person的实例,如果是那么继续执行,否则抛出错误。这个方法不可靠,因为即使不使用new,this也可以是Person的实例:
function Person(name) {
if (this instanceof Person) {
this.name = name;
} else {
throw new Error("You must use new with Person");
}
} var person = new Person("Zakas");
var notAPerson = Person.call(person, "Zakas");
Person.call的第一个参数是person,它是一个Person实例。所以this也是一个Person实例。也就是说用instanceof没办法判断函数调用时是否使用new。为了解决这个问题,ES6中引入了new.traget:
function Person(name) {
if (typeof new.target !== "undefined") {
this.name = name;
} else {
throw new Error("You must use new with Person");
}
} var person = new Person("Zakas");
var notAPerson = Person("Zakas"); // throws an error
当Person调用时使用new,new.target指向Person,上面的判断语句实际上可以写成new.traget === Person。再看一个例子:
function Person(name) {
if (typeof new.target !== "undefined") {
this.name = name;
} else {
throw new Error("You must use new with Person");
}
} function AnotherPerson(name) {
Person.call(this, name);
} var person = new Person("Zakas");
var notAPerson = new AnotherPerson("Zakas"); // throws an error
上面的代码会报错,因为并没有在调用Person时使用new,new.traget并不指向Person。
注意:new.target只能在函数内部使用,否则会报错的。可以看到,通过使用new.target我们可以判断函数调用时是否使用new。