没有简单直接的方法可以使用构造函数来做到这一点。这是因为当您使用 new 关键字调用构造函数时会发生特殊情况,因此如果您不打算这样做,则必须模拟所有这些特殊情况。它们是:
- 创建一个新的对象实例(您正在这样做)。
- 将该对象的内部原型设置为构造函数的
prototype 属性。
- 设置该对象的
constructor 属性。
- 使用该对象实例作为
this 值调用构造函数(您正在这样做)。
- 处理构造函数的特殊返回值。
我认为就是这样,但值得仔细检查the spec。
因此,如果您可以避免它并直接使用构造函数,我会这样做。 :-) 但是,如果您不能,您仍然可以这样做,这很尴尬并且涉及变通方法。 (另请参阅 StackOverflow 上的 this related answer,尽管我在这里 [以及一些] 涵盖了所有内容。)
您最大的问题是上面的#2:设置对象的内部原型。长期以来,没有标准的方法来做到这一点。一些浏览器支持 __proto__ 属性,所以你可以使用它,如果它在那里。好消息是 ECMAScript 5 引入了一种明确执行此操作的方法:Object.create。因此,像 Chrome 这样的尖端浏览器将拥有它。但是,如果您使用的浏览器既没有Object.create 也没有__proto__,那就有点难看:
1) 定义自定义构造函数。
2) 将其prototype属性设置为真实构造函数的prototype属性
3) 用它来创建一个空白对象实例。
它会为您处理原型。然后你继续:
4) 将该实例上的 constructor 属性替换为真正的构造函数。
5) 通过apply调用真正的构造函数。
6) 如果真正的构造函数的返回值是一个对象,使用它而不是你创建的那个;否则,请使用您创建的那个。
类似这样的东西 (live example):
function applyConstruct(ctor, params) {
var obj, newobj;
// Use a fake constructor function with the target constructor's
// `prototype` property to create the object with the right prototype
function fakeCtor() {
}
fakeCtor.prototype = ctor.prototype;
obj = new fakeCtor();
// Set the object's `constructor`
obj.constructor = ctor;
// Call the constructor function
newobj = ctor.apply(obj, params);
// Use the returned object if there is one.
// Note that we handle the funky edge case of the `Function` constructor,
// thanks to Mike's comment below. Double-checked the spec, that should be
// the lot.
if (newobj !== null
&& (typeof newobj === "object" || typeof newobj === "function")
) {
obj = newobj;
}
// Done
return obj;
}
您可以更进一步,仅在必要时使用假构造函数,查看是否首先支持 Object.create 或 __proto__,如下所示 (live example):
function applyConstruct(ctor, params) {
var obj, newobj;
// Create the object with the desired prototype
if (typeof Object.create === "function") {
// ECMAScript 5
obj = Object.create(ctor.prototype);
}
else if ({}.__proto__) {
// Non-standard __proto__, supported by some browsers
obj = {};
obj.__proto__ = ctor.prototype;
if (obj.__proto__ !== ctor.prototype) {
// Setting it didn't work
obj = makeObjectWithFakeCtor();
}
}
else {
// Fallback
obj = makeObjectWithFakeCtor();
}
// Set the object's constructor
obj.constructor = ctor;
// Apply the constructor function
newobj = ctor.apply(obj, params);
// If a constructor function returns an object, that
// becomes the return value of `new`, so we handle
// that here.
if (typeof newobj === "object") {
obj = newobj;
}
// Done!
return obj;
// Subroutine for building objects with specific prototypes
function makeObjectWithFakeCtor() {
function fakeCtor() {
}
fakeCtor.prototype = ctor.prototype;
return new fakeCtor();
}
}
在 Chrome 6 上,以上使用Object.create;在 Firefox 3.6 和 Opera 上,它使用 __proto__。在 IE8 上,它使用了假构造函数。
以上内容是相当即兴的,但它主要处理我在这方面所知道的问题。