【问题标题】:Dynamic JavaScript object property value动态 JavaScript 对象属性值
【发布时间】:2012-04-15 08:38:34
【问题描述】:

我试图弄清楚是否有一种方法可以在其原型中将对象属性定义为动态值,该动态值可以在每次创建对象实例时更改。这是我能描述它的最好方式;我做了一个小提琴来展示我正在尝试做的事情(尽管它不起作用)。

var Response = {
    LCID: 321
};


Date.prototype.LCID = Number(0);
Date.prototype.LCID.valueOf = function() { return Response.LCID; };


document.write((new Date()).LCID);
Response.LCID = 456;
document.write((new Date()).LCID);

http://jsfiddle.net/tx2fW/2/

我想要实现的是Response.LCID 可以在代码的整个生命周期内发生变化,正如您稍后在代码中更改它的值所看到的那样。每当我创建一个Date 对象时,我希望(new Date()).LCID 的值是Response.LCID 的当前值,而不仅仅是我第一次创建Date.prototype.LCID 时的值。

有什么办法可以做到吗?最大的限制是它必须在 JavaScript 1.5 中工作......虽然我很想知道它是否可以在最近的版本中完成。

【问题讨论】:

    标签: javascript asp-classic jscript


    【解决方案1】:

    Number(0) === 0。修改原始值上的.valueOf.toString 无效。

    执行此操作的正确方法是使用new operator 传递Number 构造函数的实例

    var Response = {
        LCID: 321
    };
    Date.prototype.LCID = new Number();   // <-- Use the "new" operator
    Date.prototype.LCID.valueOf = function() { return Response.LCID; };
    

    带注释的演示和注释:http://jsfiddle.net/tx2fW/7/

    • LCID 是一个对象。 typeof new Date().LCID === 'object'
    • LCIDNumber 的真实实例。 new Date().LCID instanceof Number === true
    • LCID 等于 321:(new Date().LCID == 321) === true
    • LCID 与 321 不同:(new Date().LCID === 321) === false
      (因为 LCID 是一个对象,而 321 是一个原始数值)。

    附言。如果您不熟悉 =====,请参阅 Which equals operator (== vs ===) should be used in JavaScript comparisons?

    【讨论】:

    • +1 以获得正确答案并在此处发布代码。但是没有人应该弄乱内置原型。似乎你有一个驱动器-1。
    • @RobG 关于修改原型:他没有详细说明他的申请,所以我无法判断他的决定是否可以。经验法则:添加的属性是否与Date 构造函数直接相关?如果不是:不要扩展原型。
    • 谢谢你 - 我之前实际上已经尝试过,并一直尝试其他方式,因为如果 JavaScript 不必将 LCID 属性强制转换/强制转换为另一种类型,你的代码就会失败。您的代码之所以有效,是因为它被转换为用于连接的字符串。尝试输出 just (new Date()).LCID 看看会发生什么(你得到一个零)。
    • @EliSand 我在注释中解释了:它是一个对象。一个字符可以使该方法在所有(古代)浏览器中按预期运行:+(new Date).LCID(注意一元+),另请参见Comparison between all number-conversion methodss和t点。跨度>
    • 哦,完全了解 == 和 ===,以及何时以及为何扩展对象原型。这确实与对象直接相关;我正在为 Date 对象创建一个语言环境 ID。这适用于 Classic ASP 中的服务器端 JavaScript(Response.LCID 是一个 ASP 对象)。
    【解决方案2】:

    好的,这是使用 __defineGetter__ 方法完成的,但是我不确定它在所有浏览器上的表现如何,但我能找到实现您想要的唯一方法(我认为这一次就是您想要的)

    http://jsfiddle.net/tx2fW/6/ 工作示例。

    var Response = {
        LCID: 321
    };
    
    var d = Date.prototype;
    
    d._LCID = Number(0);
    d.getLCID = function() {
        if (d._LCID != Response.LCID) d._LCID = Response.LCID;
        return d._LCID ;
    };
    d.__defineGetter__("LCID", function() {
        return this.getLCID();
    });
    
    document.write((new Date()).LCID);
    Response.LCID = 456;
    document.write((new Date()).LCID);​
    

    有关__defineGetter__ 的替代方案,请参阅this post

    【讨论】:

    • 不,我特别希望 Response.LCID 发生变化,并将其变化反映在新的 Date 对象中。我不想更改Date.prototype.LCID
    • 那么需要您自己的 Date 包装器,否则您所要求的将无法完成jsfiddle.net/tx2fW/4
    • 不幸的是,使用自定义日期对象也不是一种选择。我最终想要实现的是能够将语言环境 ID 附加到对象,无论是内置对象还是自定义对象。如果我不能为内置对象做到这一点,那么我就失去了意义,因为我必须让其他程序员知道要使用的所有自定义对象而不是内置对象。
    • 是的,我明白你想要达到的目标。可以做到的唯一方法是修改 Date 对象构造函数我猜,但我不认为你可以在 JS 中做到这一点(需要玩它看看)。这样一来,它就会为创造设定自己的价值。
    • Internet Explorer JScript 不支持__defineGetter__
    【解决方案3】:

    经过更多的研究和实验,我能够真正解决这个问题。我曾尝试使用 Date 构造函数等,但我在最初的试验中运气不佳 - 显然是因为我忽略了 Date 对象是独一无二的这一事实,因为它的功能取决于它的调用方式(如一个函数或对象构造函数)。这意味着您不能只执行Date.prototype.constructor.apply(this, arguments),因为您将得到的只是一个字符串(Date 对象被作为函数调用)。

    在找到this thread 并阅读它之后,我想出了以下代码,它创建了一个实际的 Date 对象(或作为函数调用的字符串)并完美地模仿了内置的 Date 对象(就我的测试而言无论如何显示)。每次创建新的 Date 对象时,它都会获取在对象创建期间动态生成的 LCID 属性,这正是我所需要的。

    Date = (function(orig) {
        var date = function(a, b, c, d, e, f, g) {
            var object = (this instanceof Object ? (arguments.length < 1 ? new orig() : (arguments.length < 2 ? new orig(a) : (arguments.length < 4 ? new orig(a, b || 0, c || 1) : new orig(a, b, c, d || 0, e || 0, f || 0, g || 0)))) : orig());
            object.LCID = Response.LCID;
    
            return object;
        };
        date.prototype = orig.prototype;
    
        return date;
    })(Date);
    

    我还创建了一堆测试用例,以确保与内置的 Date 对象没有区别,或者使用此代码(注释掉此代码以查看使用内置 Date 对象的结果并进行比较)。

    var Response = { 'LCID': 123 };
    
    
    Date = (function(orig) {
        var date = function(a, b, c, d, e, f, g) {
            var object = (this instanceof Object ? (arguments.length < 1 ? new orig() : (arguments.length < 2 ? new orig(a) : (arguments.length < 4 ? new orig(a, b || 0, c || 1) : new orig(a, b, c, d || 0, e || 0, f || 0, g || 0)))) : orig());
            object.LCID = Response.LCID;
            return object;
        };
        date.prototype = orig.prototype;
        return date;
    })(Date);
    
    
    var x = new Date();
    document.writeln(x);
    document.writeln(x.LCID);
    document.writeln(x.getFullYear());
    document.writeln(typeof x);
    document.writeln(Object.prototype.toString.call(x));
    document.writeln(x instanceof Date);
    document.writeln("<br/>");
    
    Response.LCID = 456;
    
    var y = new Date();
    document.writeln(y);
    document.writeln(y.LCID);
    document.writeln(y.getFullYear());
    document.writeln(typeof y);
    document.writeln(Object.prototype.toString.call(y));
    document.writeln(y instanceof Date);
    document.writeln("<br/>");
    
    document.writeln(Date());
    document.writeln(new Date());
    document.writeln(new Date(2012));
    document.writeln(new Date(2012, 7));
    document.writeln(new Date(2012, 7, 14));
    document.writeln(new Date(2012, 7, 14, 9));
    document.writeln(new Date(2012, 7, 14, 9, 45));
    document.writeln(new Date(2012, 7, 14, 9, 45, 27));
    document.writeln(new Date(2012, 7, 14, 9, 45, 27, 687));
    

    这也可以作为更新的小提琴提供:http://jsfiddle.net/tx2fW/9/

    【讨论】:

      猜你喜欢
      • 2020-05-25
      • 2021-09-26
      • 2013-07-21
      • 2020-07-08
      • 2019-03-20
      • 1970-01-01
      • 1970-01-01
      • 2010-10-07
      相关资源
      最近更新 更多