警告:这是一篇冗长的文章。
让我们保持简单。我想避免每次在JavaScript中调用构造函数时都必须给新运算符添加前缀。这是因为我倾向于忘记它,并且我的代码严重搞砸了。
解决这个问题的简单方法是...
function Make(x) {
if ( !(this instanceof arguments.callee) )
return new arguments.callee(x);
// do your stuff...
}
但是,我需要接受变量号。这样的论点...
m1 = Make();
m2 = Make(1,2,3);
m3 = Make('apple', 'banana');
第一个直接的解决方案似乎是这样的“应用”方法...
function Make() {
if ( !(this instanceof arguments.callee) )
return new arguments.callee.apply(null, arguments);
// do your stuff
}
但是,这是错误的-新对象将传递给apply
方法,而不是传递给我们的构造函数arguments.callee
。
现在,我提出了三种解决方案。我的简单问题是:哪个似乎最好。或者,如果您有更好的方法,请告诉它。
首先 –用于eval()
动态创建调用构造函数的JavaScript代码。
function Make(/* ... */) {
if ( !(this instanceof arguments.callee) ) {
// collect all the arguments
var arr = [];
for ( var i = 0; arguments[i]; i++ )
arr.push( 'arguments[' + i + ']' );
// create code
var code = 'new arguments.callee(' + arr.join(',') + ');';
// call it
return eval( code );
}
// do your stuff with variable arguments...
}
第二 –每个对象都有__proto__
属性,该属性是与其原型对象的“秘密”链接。幸运的是,该属性是可写的。
function Make(/* ... */) {
var obj = {};
// do your stuff on 'obj' just like you'd do on 'this'
// use the variable arguments here
// now do the __proto__ magic
// by 'mutating' obj to make it a different object
obj.__proto__ = arguments.callee.prototype;
// must return obj
return obj;
}
第三 –这类似于第二种解决方案。
function Make(/* ... */) {
// we'll set '_construct' outside
var obj = new arguments.callee._construct();
// now do your stuff on 'obj' just like you'd do on 'this'
// use the variable arguments here
// you have to return obj
return obj;
}
// now first set the _construct property to an empty function
Make._construct = function() {};
// and then mutate the prototype of _construct
Make._construct.prototype = Make.prototype;
eval
解决方案似乎笨拙,并伴随着“邪恶评估”的所有问题。__proto__
解决方案是非标准的,并且“ mIsERY的出色浏览器”不兑现它。第三种解决方案似乎过于复杂。
但是使用以上三种解决方案,我们都可以做这样的事情,否则我们将无法避免……
m1 = Make();
m2 = Make(1,2,3);
m3 = Make('apple', 'banana');
m1 instanceof Make; // true
m2 instanceof Make; // true
m3 instanceof Make; // true
Make.prototype.fire = function() {
// ...
};
m1.fire();
m2.fire();
m3.fire();
因此,上述解决方案有效地为我们提供了接受变量编号的“真实”构造函数。的论点,不需要new
。您对此有何看法。
-更新-
有些人说“只是抛出一个错误”。我的回答是:我们正在使用10个以上的构造函数来制作一个繁重的应用程序,我认为如果每个构造函数都可以“聪明地”处理该错误而又不会在控制台上抛出错误消息,那将更加令人费解。
Make()
不new
这样做,它将警告您,因为Make是大写的,因此它假定它是构造函数
new
?因为如果是后者,则可能是您在错误的网站上提问。如果是前者,则可能不希望很快放弃使用新错误和检测错误的建议...如果您的应用程序确实“繁重”,那么您想要的最后一件事就是过度劳累的构造机制来减慢它的运行速度。new
,尽管有很多漏洞,但速度非常快。