本文探讨JavaScript中构造函数调用时是否使用new关键字的行为差异。通过对比RegExp、String、Number和Boolean等内置对象,发现RegExp在有无new时均返回正则对象,而原始包装类在省略new时会执行类型转换并返回原始值。对于自定义构造函数,直接调用默认返回undefined,但可通过检测this指向实现兼容两种调用方式的写法。
构造函数基础与RegExp的特殊行为
首先展示一个基础的构造函数定义示例。
具体代码实现如下:
function Person(name, age) {
this.name = name;
this.age = age;
}
var p = new Person('lily', 20); 在查阅某些库的代码时,发现创建正则表达式对象时并未使用new关键字,这引发了疑问。示例如下:
相关代码如下:
var reg = RegExp('^he$'); 经过测试验证,无论是否使用new关键字,最终返回的都是正则表达式对象,且通过typeof运算符检查,两者的类型均为“object”。
对比测试代码如下:
var reg1 = new RegExp('^he$');
var reg2 = RegExp('^he$');
reg1.test('he'); // true
reg2.test('he'); // true
console.log(typeof reg1); // object
console.log(typeof reg2); // object 从测试结果来看,代码运行正常,功能符合预期。
原始包装类的类型转换机制
既然这样,是否可以省略new关键字以简化代码?其他类型是否也具备这一特性?接下来尝试对String、Number和Boolean类型进行验证。
测试代码如下:
var str1 = new String(1);
var str2 = String(1);
var num1 = new Number('1');
var num2 = Number('1');
var boo1 = new Boolean(1);
var boo2 = Boolean(1);
console.log(typeof str1); // object
console.log(typeof str2); // string
console.log(typeof num1); // object
console.log(typeof num2); // number
console.log(typeof boo1); // object
console.log(typeof boo2); // boolean 观察结果可知,这与RegExp的情况存在显著不同。对于RegExp,无论是否使用new,typeof的结果始终是object。
然而,对于String、Number和Boolean类型,使用new关键字时typeof返回“object”,而不使用new时,typeof则分别返回“string”、“number”和“boolean”。
这意味着,在不适用new的情况下,这些构造函数实际上执行了类型转换操作,将参数分别转换为字符串、数字和布尔值。
自定义构造函数的兼容处理方案
回到文章开头的Person类,我们需要确认:自定义的类是否可以不使用new操作符来生成对象?
相关代码如下:
function Person(name, age) {
this.name = name;
this.age = age;
}
var p = Person('lily', 20);
console.log(p); // undefined 执行结果显示返回值为undefined,这表明直接调用自定义构造函数无法直接生成实例对象。因此,期望在不使用new的情况下直接创建Person实例是不现实的。
如果必须实现这种功能,可以通过以下方式进行改造:
修改后的代码如下:
function Person(name, age) {
this.name = name;
this.age = age;
if (this===window) {
return new Person(name, age);
}
}
var p = Person('lily', 20); // object 上述代码对Person类进行了微调,核心逻辑在于内部区分了Person是作为构造函数还是普通函数执行。当this指向window(即全局对象)时,表明未使用new调用,此时手动返回new Person的实例。