【问题标题】:Is it possible to export a custom javascript object in different formats like the Date object can?是否可以像 Date 对象那样以不同的格式导出自定义 javascript 对象?
【发布时间】:2016-10-21 15:30:25
【问题描述】:

例如,假设我有一个这样的自定义对象:

function MyObject(a, b){
    this.prop = a;
    this.name = b;
    this.doSomething = function(){
        return "something";
    }
}
var a = new MyObject(4, 'name');

我希望能够将此对象导出为字符串、整数或调用它的函数会自动保证的任何格式,类似于 Date 对象的行为方式,即:

console.log(b);
// "name"
console.log(2*a);
// 8
console.log(a.doSomething());
// "something"

我尝试过使用:

MyObject.prototype.toString = function(){ ... }

但这似乎不是我想要的,因为我仍然需要调用“a.toString()”

有什么想法吗?

【问题讨论】:

    标签: javascript oop object


    【解决方案1】:

    答案会根据你使用的是 ES5 及更早版本,还是 ES2015 及更高版本而有所不同。

    在 ES2015 及更高版本中

    是的,您可以在原型上实现Symbol.toPrimitive 方法,并使用它收到的提示作为其第一个参数:

    // (There's a more thoroughly ES2015+ version below, keeping
    // this fairly ES5-like for comparison with the ES5 version)
    function MyObject(num, name) {
      this.num = num;
      this.name = name;
    }
    MyObject.prototype[Symbol.toPrimitive] = function(hint) {
      return hint === "number" ? this.num : this.name;
    };
    
    var a = new MyObject(21, "half the answer");
    console.log(a * 2);                       // 42
    console.log("It says it's " + a);         // It says it's half the answer

    我相当肯定这在真正的 ES5 JavaScript 引擎上不会工作,即使是转译...

    请注意,我保留了上面的代码,非常类似于 ES5,因此很容易与之前的 ES5 下的示例进行比较。但在 ES2015 中我们可能会这样写:

    class MyObject {
      constructor(num, name) {
        this.num = num;
        this.name = name;
      }
      [Symbol.toPrimitive](hint) {
        return hint === "number" ? this.num : this.name;
      }
    }
    
    let a = new MyObject(21, "half the answer");
    console.log(a * 2);               // 42
    console.log("It says it's " + a); // It says it's half the answer

    在 ES5 及更早版本中

    你不能像 JavaScript 本身那样拥有那么多的控制权,它使用抽象 ToPrimitive 操作上的“提示”来选择 valueOftoString,以一种特殊的方式为 Date

    但是你可以通过实现valueOftoString 来接近。当你的对象被强制为一个数字时,valueOf 将被使用。强制为字符串时,将使用toString

    但是,请注意+ 将使用valueOf,即使另一个操作数是字符串:

    例子:

    function MyObject(num, name) {
      this.num = num;
      this.name = name;
    }
    MyObject.prototype.valueOf = function() {
      return this.num;
    };
    MyObject.prototype.toString = function() {
      return this.name;
    };
    
    var a = new MyObject(21, "half the answer");
    console.log(a * 2);                       // 42
    console.log("It says it's " + a);         // It says it's 21
    console.log("It says it's " + String(a)); // It says it's half the answer

    如果你没有实现valueOf,通过已经完成的有些复杂的处理,即使在+ 的情况下,它最终也会使用toString(有关血腥细节,请参阅上面的ToPrimitive 链接;基本上,最终它执行 OrdinaryToPrimitive 并调用 Object.prototype.valueOf,它返回一个对象,因此它忽略该对象并改为使用 toString

    【讨论】:

    • ...当字符串化为 JSON 时,toJSON 将被调用。 :)
    • 值得注意的是,如果没有valueOf 实现,它将使用toString() 进行字符串连接。
    • 那么有什么办法可以避免使用:“String(a)”吗?例如,对于 Date 方法,如果我要将它记录到控制台,它会给我一个日期字符串,并且只有在我编写类似 console.log(1*d);的东西时才会强制转换为整数>
    • @MadaraUchiha:是的,是的,通过相当复杂的逻辑。我在最后添加了一条注释。
    • @renegadeds:您可以在 ES2015 及更高版本中使用。你不能在 ES5 和更早的版本中。我已将 ES2015 添加到答案中。
    猜你喜欢
    • 2014-09-19
    • 1970-01-01
    • 2012-04-24
    • 1970-01-01
    • 1970-01-01
    • 2014-02-20
    • 2014-05-13
    • 1970-01-01
    • 2011-10-01
    相关资源
    最近更新 更多