这个简单的通用模式(我最喜欢的)怎么样?
(function(){ //IIF constructor builder
(this[arguments[0]]= function(/*args*/){ //The constructor
/*constructor payload code*/
}).prototype= { //Methods & Properties to inherit:
method_1: function(){ /*your code*/ } //method 1
, method_2: function(){ /*your code*/ } //method 2
, property_1: /*your code*/ //property 1
, property_2: /*your code*/ //property 2
};
})(/*constructor identifier*/);
this
将引用运行此构建功能的上下文。因此,如果构造函数生成器是针对 运行的window
,那么window
将具有全局函数$elect
。所以你也可以在你的模块化系统中使用这个模式。
更新:
您已经询问过
instanceof
(并且根据您提供的代码判断,您需要它以便
new
在调用构造函数时可以省略)。
这会使事情变得更加棘手。
对我个人而言,'users' !== 'coders' 和 'coders'(编写代码(使用 x 库)供用户使用)应该知道何时使用new
.
虽然在开发过程中可能对 // 错误很有用throw new
,但在最终(最小化console.log
/alert
优化)生产代码中应该不需要这个(除非你的论点是你有很多new
可以省略的语句,所以你的代码可以进一步缩小)。
首先必须决定是否优化
执行速度和使用new
(代码经常运行?):
if(/*called with new*/){
/*constructor payload code*/
} else {
/*error code*/
}
或因缺乏执行速度而最小的文件大小new
(代码只运行几次?):
if(!(/*called with new*/)){ /*error code*/ }
/*constructor payload code*/
请注意,如果您打算要求使用,最后一个选项对于生产代码的注释/删除也可能更实用new
,从而提供最快的执行速度。
该行/*called with new*/
可以替换为this instanceof arguments.callee
虽然arguments.callee
是一个很好的通用解决方案(因为没有任何东西是硬编码/命名的),如果你-mode 它会抛出异常'use strict';
,因为它现在已被弃用(出于某种原因)有利于命名函数表达式(并且根据对 John Resig 来说,将来也可以使用这个表达式this function
)。
MDN 指定函数名只能在函数体中使用,因此对于严格模式,我们可以命名我们的(以前是匿名的)函数(C
在以下示例中)
并检查是否this instanceof C
(而不是this instanceof arguments.callee
):
(function(){ //IIF constructor builder
(this[arguments[0]]= function C(id){ //The constructor
if(!(this instanceof C)){ /*error code*/ } //Catch ID-10-T Error
/*constructor payload code*/
}).prototype= { //Methods & Properties to inherit:
method_1: function(){ /*your code*/ } //method 1
, method_2: function(){ /*your code*/ } //method 2
, property_1: /*your code*/ //property 1
, property_2: /*your code*/ //property 2
};
})('$elect');
如果/*error code*/
仅通过以下方式防止无提示错误://
alert
那么
到目前为止,这种模式(严格和非严格变体)是令人麻木的通用。 console.log
throw new Error
('Error: forgot new')
如果您想通过返回正确的新对象来“修复”调用(除了现在对编码器的可选警告),那么必须考虑传递给构造函数的参数(如果有的话)。
因此,对于不期望参数的构造函数,您/*error code*/
应该包含:
return new arguments.callee();
对于非严格或对于
期望(可选)命名参数
return new C();
的严格构造函数,您应该将它们硬编码为:
/*error code*/
return new arguments.callee(arg_1, arg_2 /*,etc..*/);
return new C(arg_1, arg_2 /*,etc..*/);
例如:
(function(){ //IIF constructor builder
(this[arguments[0]]= function C(id){ //The constructor
if(!(this instanceof C)) return new C(id); //Fix ID-10-T Error
this.elm= document.getElementById(id);
}).prototype= { //Methods & Properties to inherit:
show: function(){ //Method show
this.elm.style.display= '';
}
, hide: function(){ //Method hide
this.elm.style.display= 'none';
}
, toggle: function(){ //Method toggle
this[this.elm.style.display ? 'show' : 'hide']();
}
};
})('$elect');
我目前不知道有一种简单而优雅的方式来传递任何(firefox 最多 256 个)非硬编码未知(预期/可选/命名)参数(缺少一个数组/对象作为第一个参数)。问题是它arguments
是一个数组(类似)对象,因此不能像return new C(arguments);
.apply()
人们认为的那样简单地将它传递给救援,因为它接受一组参数作为第二个参数(不像.call()
我们只是需要逗号分隔的参数试图避免),但是唉:new
和apply
/call
不能一起使用1 , 2 ...(如果您知道适合这种模式的优雅解决方案,请留下评论,谢谢)
最后是上述模式的一个小变化(和可能的应用)。主要区别在于此模式返回一个构造函数(因此您可以简单地命名引用它的变量)(而不是上述直接设置构造函数的模式):
var myLibrary= {
$elect: (function(C){
(C= function(id){
if(!(this instanceof C)) return new C(id);
this.elm= document.getElementById(id);
}).prototype= {
addBorder: function(col){
this.elm.style.border='1px solid '+col;
}
, delBorder: function(){
this.elm.style.border='';
}
}; return C;
})()
, var_foo: 'foo'
, var_bar: 'bar'
};
示例小提琴在这里。
希望这可以帮助!