function Person(name) {
this.name = name;
}
let person1 = new Person('test001');
let person2 = Person('test002');
console.log(person1); //Person {name: 'test001'}
//name: "test001"
//[[Prototype]]: Object
console.log(person2); // undefined
在这段代码中,person1是通过new关键字来调用Person(),而person2没有通过new关键字调用则返回的是undefined,在JavaScript的函数机制中,本身的内部存在两个不同的方法,一个是[[Call]]
,另一个是[[Construct]]
,通过new关键字调用函数时,会先调用[[Construct]]
来创建一个实例对象,再去执行函数体,将this绑定在这个实例上,如果没有使用new关键字,那么会执行[[Call]]
函数,从而直接执行函数体。
在ES5中想要判断一个函数是否是通过new关键字被调用的,也就是说想要得知这个函数是否通过new去执行了construct()构造函数,最简便的方法便是通过instanceof
去判断。
function Person(name) {
if(this instanceof Person) {
this.name = name;
console.log('success...')
} else {
throw new Error('未通过new执行construct函数...');
}
}
可以看出,首先会检查this的指向是否是属于Person构造出去的实例,如果是的,那么才会进行初始化赋值,否则,就会抛出异常。但是这种方法一般书本上也不会去推荐使用,因为,javascript中存在可以修改this指向的方法,比如:Call()
function Person(name) {
if(this instanceof Person) {
this.name = name;
console.log('success...')
} else {
throw new Error('未通过new执行construct函数...');
}
}
let person1 = new Person('test001'); // success...
let person2 = Person.call(person1,'test002'); // success...
调用Person.call(),将第一个变量person传入作为第一个参数,相当于Person函数里面将this指向了person1实例,而函数本身是无法区分Person.call()和new Person()的。
ES6中引入了new.target元属性来解决这一问题,元属性指的是非对象的属性,可以提供非对象目标的补充信息,当调用函数的[[Construct]]时,new.target被赋值为new操作符的目标,通常是新创建的对象实例,如果调用的[[Call]]时,则new.target的值为undefined,通过这个元属性,便可以检测是否通过new构造出来的对象。
function Person(name) {
if(typeof new.target !== 'undefined') {
this.name = name;
console.log('success...')
} else {
throw new Error('未通过new执行construct函数...');
}
}
let person1 = new Person('test001');
let person2 = Person.call(person1,'test002');
console.log(person1);
console.log(person2);
也可以检查new.target是否被某个特定的构造函数所调用
function Person(name) {
console.log(new.target);
if(typeof new.target !== 'undefined') {
this.name = name;
console.log('success...')
} else {
throw new Error('未通过new执行construct函数...');
}
}
function Thing(name){
debugger
console.log(this);
Person.call(this,name);
}
let person1 = new Person('test001');
let thing1 = new Thing('car');
console.log(person1);
console.log(thing1);