前情提要
ES5及早期版本中函数具有多重功能,可以结合new使用,函数内的this值将指向一个新对象,在ES6中,函数混乱的双重身份有一些改变。
Javascript函数有两个不同的内部方法:[[Call]]和[[Construct]],当遇到通过new关键字调用函数时,执行的是[[Construct]]函数,它负责创建一个通常被称作实例的新对象,然后再执行函数体,将this绑定到实例上。否则将执行[[Call]]函数,从而直接执行代码中的函数体。具有[[Construct]]方法的函数被统称为构造函数。
注:不是所有函数都有construct方法,例如箭头函数,所以也不是所有方法都可以通过new来调用。
ES5判断函数被调用的方法
在ES5中要想确定一个函数是否通过new关键字被调用,最流行的方式是使用instanceof
function Person (name) {
if(this instanceof Person){
this.name = name
} else {
throw new Error('未通过new调用')
}
}
//var person1 = new Person('Hello') //正常
var person2 = Person('Hello') //抛出异常
由于construct方法会创建一个Person实例,并将this绑定到新实例上,所以可以通过检查this值是否是构造函数的实例,如果是则代码可以正常运行,如果不是则抛出异常。
但这种方法并不是可靠的,再看一个例子
function Person (name) {
if(this instanceof Person){
this.name = name
} else {
throw new Error('未通过new调用')
}
}
var person1 = new Person('Hello')
var person2 = Person.call(person1,'Hello') //正常执行
使用call方法将this设为person1的实例,对于函数本身,无法通过区分Person.call还是new关键字得到Person的实例。
ES6判断函数被调用的方法
ES6引入了new.target这个元属性。原属性是指非对象的属性。
描述:通常"new."的作用是提供属性访问的上下文,但这里"new."其实不是一个真正的对象。不过在构造方法调用中,new.target指向被new调用的构造函数,所以"new."成为了一个虚拟上下文。
当调用函数construct方法时,new.target被赋值为new操作符的目标,通常是新创建对象的实例。如果调用call方法,则new.target的值是Undefined。
function Person(name) {
if(typeof new.target !== 'undefined') {
this.name = name;
} else {
throw new Error('未通过new关键字调用')
}
}
var person = new Person('Hello')
var Notperson = new Person.call('Hello') //抛出错误
也可以使用new.target是否被某个特定构造函数所调用
function Person(name) {
if(new.target === Person)
{
this.name = name;
} else {
throw new Error('未使用new关键字调用')
}
}
function AnotherPerson(name) {
Person.call(this, name)
}
var person = new Person('Hello')
var anotherPerson = new AnotherPerson('Hello')
注:在函数外使用new.target是一个语法错误。
更多推荐
【Javascript】判断函数被调用的方法
发布评论