众所周知,javascript种的函数由两种调用方式,那么一个函数被调用的时候如何知道自己是以何种方式被使用的呢? 下面介绍两种方法,并且受到这两种方法的启发,在最后实现了【强制以new方式调用函数】
方法一:使用instanceof校验this
原理:如果以new方式调用函数则this是Foo的实例对象;而如果是非new调用,this指向调用者
function Foo (name) {
if(!(this instanceof arguments.callee)){
throw new Error(`Foo can only be used with new!`)
}
this.name = name;
}
const f1 = new Foo('zs'); // Foo {name: 'zs'}
const f2 = Foo('ls'); // Uncaught Error: Foo can only be used with new!
方法二:检测new.target的存在性
原理:如果以new方式调用函数则new.target的值为函数本身,在下面的例子中new.target可能等于Bar;而如果是非new调用,则为undefined
function Bar (name) {
if(typeof new.target === "undefined"){
throw new Error(`Foo can only be used with new!`)
}
this.name = name;
}
const b1 = new Bar('ww'); // Bar {name: 'ww'}
const b2 = Bar('zl'); // Uncaught Error: Foo can only be used with new!
对比一下:
- 两种方式中,前者使用的arguments,现在已经不被推荐使用了;
- 而后者则是ES6中才引入的,可能会有兼容性问题!
强制new方式调用
通过上面的两种方式可以实现强制以构造方式使用函数,从而实现调用函数的时候加不加new结果都一样的效果。
function Baz (name) {
if(!(this instanceof arguments.callee)){
return new arguments.callee(...arguments)
}
// if(typeof new.target === "undefined"){
// return new new.target(...arguments)
// }
this.name = name;
}
const z1 = new Baz('shl'); // Baz {name: 'shl'}
const z2 = Baz('mdm'); // Baz {name: 'mdm'}