是否可以以不同的格式导出自定义javascript对象,如Date对象可以?

ren*_*eds 3 javascript oop object

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

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

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

console.log(b);
// "name"
console.log(2*a);
// 8
console.log(a.doSomething());
// "something"
Run Code Online (Sandbox Code Playgroud)

我尝试过使用:

MyObject.prototype.toString = function(){ ... }
Run Code Online (Sandbox Code Playgroud)

但它似乎不是我正在寻找的东西,因为我仍然需要调用"a.toString()"

有任何想法吗?

T.J*_*der 8

答案的变化取决于您使用的是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
Run Code Online (Sandbox Code Playgroud)

我相当肯定这不会对真正的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
Run Code Online (Sandbox Code Playgroud)

在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
Run Code Online (Sandbox Code Playgroud)

如果你没有实现valueOf,通过稍微复杂的处理,toString即使在这种+情况下它也会最终使用(参见ToPrimitive上面的链接了解血腥细节;基本上,它最终会执行OrdinaryToPrimitive并调用Object.prototype.valueOf,它会返回一个对象,所以它忽略了这一点,toString而是使用).