renegadeds renegadeds - 1 month ago 3
Javascript Question

Is it possible to export a custom javascript object in different formats like the Date object can?

For example, let's say I have a custom object like this:

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


I want to be able to export this object as a string, or an integer, or whatever format the function calling it would warrant automatically in a similar way to how the Date object behaves, ie:

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


I have tried using:

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


But it doesn't seem to be what I'm looking for as I still have to call "a.toString()"

Any ideas?

Answer

The answer changes depending on whether you use ES5 and earlier, or ES2015 and later.

In ES2015 and later

Yes, you can implement the Symbol.toPrimitive method on your prototype and use the hint that it receives as its first argument:

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

I'm fairly certain this won't work on a truly ES5 JavaScript engine even with transpiling...

In ES5 and earlier

You can't have quite as much control as JavaScript itself does, where it uses the "hint" on the abstract ToPrimitive operation to choose valueOf or toString in a special way for Date.

But you can get close by implementing valueOf and toString. When your object is coerced to a number, valueOf will be used. When coerced to string, toString will be used.

But, note that + will use valueOf even if the other operand is a string:

Example:

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

If you didn't implement valueOf, through the somewhat convoluted processing that's done, it would end up using toString even in the + case (see the ToPrimitive link above for the gory details; basically, eventually it does OrdinaryToPrimitive and calls Object.prototype.valueOf, which returns an object, and so it disregards that and uses toString instead).

Comments