javascript 中的一个令人讨厌的问题是忘记在要实例化的函数上调用 new
,导致 this
被绑定(bind)到不同的对象(通常是全局对象)一个新鲜的。我读到的一种解决方法是使用以下惯用语在函数构造函数中明确检查它:
function SomeConstructor(x, y, ...) {
// check if `this` is created with new
if ( !(this instanceof arguments.callee) )
return new SomeConstructor(x, y, ...);
// normal initialization code follows
现在 new SomeConstructor(...)
和 SomeConstructor(...)
是等价的。
我想通过创建一个包装函数 factory(fn)
来简化它,它执行前两行,然后委托(delegate)给包装函数 fn
。这将像这样使用:
SomeConstructor = factory(function (x, y, ...) {
// normal initialization code follows
})
我的第一次尝试是:
function factory(fn) {
return function() {
if ( !(this instanceof arguments.callee) ) {
return new arguments.callee.apply(this, arguments);
}
fn.apply(this, arguments);
}
}
但失败并显示“Function.prototype.apply called on incompatible [object Object]”。第二次尝试是:
function factory(fn) {
return function() {
if ( !(this instanceof arguments.callee) ) {
var tmp = new arguments.callee();
arguments.callee.apply(tmp, arguments);
return tmp;
}
fn.apply(this, arguments);
}
}
这种方法可行,但它可能会调用包装函数两次:一次不带参数(创建新实例),一次带参数进行实际初始化。显然这是脆弱且低效的,但我无法想出一种方法来通过一次调用来完成。这可能吗?
编辑:基于 bobince 的方法,这是一个类似的方法:
function factory(init) {
var run_init = true;
function constr() {
if ( !(this instanceof constr) ) {
run_init = false;
var tmp = new constr();
run_init = true;
init.apply(tmp, arguments);
return tmp;
}
if (run_init)
init.apply(this, arguments);
}
return constr;
}
至于这是否应该被鼓励,这是值得商榷的。我来自 Python 背景,我认为 new
只是噪音 (Java) 或疣 (Javascript),但我可能遗漏了一些东西。
最佳答案
这只会助长一种捷径的坏习惯,即过于依赖类的实现来“修复”调用代码。
如果这是一个问题,不要让它滑动,抛出错误消息。
关于javascript - 删除对 "new"的需要,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1977629/