通过调用prototype.constructor.apply来实例化JavaScript对象

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (20)

让我先从我想要做的一个具体例子开始。

我在窗体中有一组年,月,日,小时,分,秒和毫秒组件[ 2008, 10, 8, 00, 16, 34, 254 ]。我想用下面的标准构造函数实例化一个Date对象:

new Date(year, month, date [, hour, minute, second, millisecond ])

我如何将我的数组传递给此构造函数以获取新的Date实例?[ 更新:我的问题实际上超出了这个具体的例子。我想要一个内置JavaScript类(如Date,Array,RegExp等)的通用解决方案,这些类的构造函数是我无法实现的。]

我正在尝试执行以下操作:

var comps = [ 2008, 10, 8, 00, 16, 34, 254 ];
var d = Date.prototype.constructor.apply(this, comps);

我可能new在某处需要一个“ ”。上面只是返回当前时间,就好像我已经调用过“ (new Date()).toString()”。我也承认,我可能完全用错误的方向与上述:)

注意:请不要eval(),也不要逐一访问数组项目。我很确定我应该能够按原样使用数组。

进一步的实验

由于还没有人能够提出一个可行的答案,我已经做了更多的工作。这是一个新发现。

我可以用我自己的班级做到这一点:

function Foo(a, b) {
    this.a = a;
    this.b = b;

    this.toString = function () {
        return this.a + this.b;
    };
}

var foo = new Foo(1, 2);
Foo.prototype.constructor.apply(foo, [4, 8]);
document.write(foo); // Returns 12 -- yay!

但它不适用于内部Date类:

var d = new Date();
Date.prototype.constructor.call(d, 1000);
document.write(d); // Still returns current time :(

它也不适用于数字:

var n = new Number(42);
Number.prototype.constructor.call(n, 666);
document.write(n); // Returns 42

也许这对内在物体是不可能的?我正在用BTW测试。

提问于
用户回答回答于

我对自己做了更多的调查,并得出这样的结论:由于Date类的实现方式,这是不可能的壮举

我检查了SpiderMonkey源代码,看看Date如何实现。我认为这一切归结于以下几行:

static JSBool
Date(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
    jsdouble *date;
    JSString *str;
    jsdouble d;

    /* Date called as function. */
    if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
        int64 us, ms, us2ms;
        jsdouble msec_time;

        /* NSPR 2.0 docs say 'We do not support PRMJ_NowMS and PRMJ_NowS',
         * so compute ms from PRMJ_Now.
         */
        us = PRMJ_Now();
        JSLL_UI2L(us2ms, PRMJ_USEC_PER_MSEC);
        JSLL_DIV(ms, us, us2ms);
        JSLL_L2D(msec_time, ms);

        return date_format(cx, msec_time, FORMATSPEC_FULL, rval);
    }

    /* Date called as constructor. */
    // ... (from here on it checks the arg count to decide how to create the date)

当Date被用作一个函数(或者是,Date()或者Date.prototype.constructor()是完全一样的东西)时,它默认将当前时间作为一个字符串以区域设置格式返回。这与任何传入的参数无关:

alert(Date()); // Returns "Thu Oct 09 2008 23:15:54 ..."
alert(typeof Date()); // Returns "string"

alert(Date(42)); // Same thing, "Thu Oct 09 2008 23:15:54 ..."
alert(Date(2008, 10, 10)); // Ditto
alert(Date(null)); // Just doesn't care

我不认为在JS层面上有什么可以做的来规避这一点。这可能是我在这个主题中追求的结束。

我还注意到一些有趣的事情:

    /* Set the value of the Date.prototype date to NaN */
    proto_date = date_constructor(cx, proto);
    if (!proto_date)
        return NULL;
    *proto_date = *cx->runtime->jsNaN;

Date.prototype是具有内部值的Date实例NaN,因此,

alert(Date.prototype); // Always returns "Invalid Date"
                       // on Firefox, Opera, Safari, Chrome
                       // but not Internet Explorer

IE并没有让我们失望。它做的事情有点不同,可能会设置内部值,-1以便Date.prototype始终在时期之前返回一个日期。

我终于深入ECMA-262本身,事实证明,我试图实现(与Date对象)是 - 根据定义 - 不可能:

15.9.2作为函数调用的Date构造函数 当Date被调用为函数而不是构造函数时,它将返回一个表示当前时间(UTC)的字符串。 注意函数调用 与具有相同参数Date(…)的对象创建表达式new Date(…)不同。 15.9.2.1日期([年份[,月份[,日期[,小时[,分钟[,秒[,毫秒]]]]]]]) 所有的参数都是可选的; 提供的任何参数都被接受,但完全被忽略。字符串被创建并返回,就像通过表达式一样(new Date()).toString()

用户回答回答于

我几乎没有称这个优雅,但在我的测试(FF3,Saf4,IE8)它的工作原理:

var arr = [ 2009, 6, 22, 10, 30, 9 ];

取而代之的是:

var d = new Date( arr[0], arr[1], arr[2], arr[3], arr[4], arr[5] );

尝试这个:

var d = new Date( Date.UTC.apply( window, arr ) + ( (new Date()).getTimezoneOffset() * 60000 ) );

扫码关注云+社区