为您提供一些选项,全部使用Object.create:
选项 1:
function User(first, last){
var rv;
if ( !(this instanceof User) ) {
// They called us without `new`: Create an object backed by `User.prototype`:
rv = Object.create(User.prototype);
// Now, call this function applying the arguments
User.apply(rv, arguments);
// Return the object
return rv;
}
// Normal constructor stuff
this.name = first + " " + last;
}
当然,不必为您创建的每个构造函数重复所有这些逻辑,您可以使用辅助函数:
function constructWith(obj, ctor, args) {
if (obj instanceof ctor) {
return null;
}
obj = Object.create(ctor.prototype);
ctor.apply(obj, args);
return obj;
}
然后
function User(first, last){
var rv;
if ((rv = constructWith(this, User, arguments)) != null) {
return rv;
}
// Normal constructor stuff
this.name = first + " " + last;
}
选项 2:不要使用 this 太多:
function User(first, last){
var rv;
if (this instanceof User) {
// They (probably) used `new`, all is good, use `this`
rv = this;
} else {
// They didn't use `new`, create an object backed by `User.prototype`
rv = Object.create(User.prototype);
}
// ...use `rv`, not `this`, from here on
rv.name = first + " " + last;
// This is important for the case where they didn't use `new`, and harmless
// in the case where they did.
return rv;
}
如您所见,这要简单得多,但如果您真的喜欢语法突出显示(说真的,我有一个客户,this 跳出来对他来说真的很重要)等等...
当然,您可以将其封装在一个助手中:
function useOrConstruct(obj, ctor) {
return obj instanceof ctor ? obj : Object.create(ctor.prototype);
}
然后
function User(first, last){
var rv = useOrConstruct(this, User);
// ...use `rv`, not `this`, from here on
rv.name = first + " " + last;
// This is important for the case where they didn't use `new`, and harmless
// in the case where they did.
return rv;
}
选项 3:constructOMatic
当然,如果我们要定义助手,也许我们应该全力以赴:
function User() {
return constructOMatic(this, User, arguments, function(first, last) {
this.name = first + " " + last;
});
}
...constructOMatic 是:
function constructOMatic(obj, ctor, args, callback) {
var rv;
if (!(obj instanceof ctor)) {
obj = Object.create(ctor.prototype);
}
rv = callback.apply(obj, args);
return rv !== null && typeof rv === "object" ? rv : obj;
}
现在,您可以在回调中使用this 来满足您的需求。最后在return 中摆弄rv 与obj 是为了模拟new 的行为(new 表达式的结果是由new 运算符创建的对象 除非构造函数返回非null对象引用,在这种情况下优先)。
Object.create 是所有现代浏览器上的 ES5 功能,但上面使用的单参数版本可以为过时的浏览器填充:
if (!Object.create) {
Object.create = function(proto, props) {
if (typeof props !== "undefined") {
throw "The two-argument version of Object.create cannot be shimmed.";
}
function ctor() { }
ctor.prototype = proto;
return new ctor; // Yes, you really don't need () (but put them on if you prefer)
};
}