本文探讨如何通过封装JavaScript的new操作符来优化对象创建过程。针对Class.create模式中实例化后遗留的initialize方法问题,文章提出一种替代方案,通过自定义New函数在实例化后自动删除该代理方法,从而避免for...in遍历时的干扰,并实现更干净的对象结构。
封装JavaScript的new操作符以优化对象初始化
首先观察以下示例代码。
代码如下:
var Class = {
create : function () {
return function () {
this.initialize.apply(this, arguments);
}
}
}
var A = Class.create();
A.prototype = {
initialize:function(){
//todo
}
test:"abc"
}
var a = new A(); 这是许多JavaScript开发者构建类和实例化对象时的常见流程。细心的读者会发现,通过这种方式创建的实例a会多出一个initialize方法。initialize在实例化过程中仅作为代理存在,实例化完成后便不再具有实际意义,甚至可能引发不必要的麻烦。例如,在使用for...in语句遍历实例a时,会将这个多余的initialize方法也遍历出来。
起初,我考虑使用之前博文中提到的Class.js来实现,这样可以保持代码的整洁。然而,Class.js中的继承机制存在某些缺陷。在不侵入原型且不生成额外属性的前提下,实现接口变得异常困难。因此,我想到通过封装new操作符来解决这一问题。这样做的好处在于,可以先修改原型,然后在封装new的方法中实现继承和接口,并去除那些多余的属性。
我们首先对new操作符进行简单的封装实现:
代码如下:
function New(){//new是关键字,所以要区别一下
var as = [],args = arguments;
for(var i=1;i<args.length;i++){
as.push('args['+i+']');
}
nobj = eval("new args[0]("+as.join(",")+");");
return nobj;
}
接下来进行测试:
function A(n){ this.name = n;}
var a1 = new A('ts');
alert(a1.name);//ts
var a2 = New(A,'tangoboy');
alert(a2.name);//tangoboy
测试结果显示成功,现在的New方法基本可以替代原生new操作符来实例化对象。
随后,解决文章开头提到的initialize问题就变得非常简单了:
function New(){
var as = [],args = arguments;
for(var i=1;i<args.length;i++){
as.push('args['+i+']');
}
nobj = eval("new args[0]("+as.join(",")+");");
delete nobj.initialize;//删除实例化对象的方法
return nobj;
} 下一节将开始丰富New方法的功能。