handsome-and-SKINNY
handsome-and-SKINNY

Reputation: 99

Why does Object.prototype.toString return constructor function name on some objects?

Let's say we do this:

function Dog(name, breed) {
  this.name = name;
  this.breed = breed;

}

var date = new Date();
var dog = new Dog("YOU'RE", "READING");

var zehbi = Object.prototype.toString.call(date);
var zehbi2 = Object.prototype.toString.call(dog);

console.log(zehbi);
console.log(zehbi2);

Why does zehbi return the name of its constructor function "Date" but zehbi2 doesn't return the name of it's constructor function "Dog" but returns "Object" instead?

Upvotes: 1

Views: 221

Answers (2)

t.niese
t.niese

Reputation: 40872

Because it is defined that way in the specification:

20.1.3.6 Object.prototype.toString ( )
When the toString toString method is called, the following steps are taken:

  1. If the this value is undefined, return "[object Undefined]".
  2. If the this value is null, return "[object Null]".
  3. Let O be ! ToObject(this value).
  4. Let isArray be ? IsArray(O).
  5. If isArray is true, let builtinTag be "Array".
  6. Else if O has a [[ParameterMap]] internal slot, let builtinTag be "Arguments".
  7. Else if O has a [[Call]] internal method, let builtinTag be "Function".
  8. Else if O has an [[ErrorData]] internal slot, let builtinTag be "Error"`.
  9. Else if O has a [[BooleanData]] internal slot, let builtinTag be "Boolean".
  10. Else if O has a [[NumberData]] internal slot, let builtinTag be "Number".
  11. Else if O has a [[StringData]] internal slot, let builtinTag be "String".
  12. Else if O has a [[DateValue]] internal slot, let builtinTag be "Date".
  13. Else if O has a [[RegExpMatcher]] internal slot, let builtinTag be "RegExp".
  14. Else, let builtinTag be "Object"
  15. Let tag be ? Get(O, @@toStringTag).
  16. If Type(tag) is not String, set tag to builtinTag.
  17. Return the string-concatenation of "[object ", tag, and "]".

And for Date the point 12. is true because it has an [[DateValue]] internal slot, your Dog does not match any of the 5. to 13. so 14. is used. After that 15. checks for the existence of @@toStringTag which does not return a string for Dog or Date, so the tag becomes the builtinTag given by one of the 5. to 14..

Upvotes: 1

VLAZ
VLAZ

Reputation: 29088

The result of Object.prototype.toString() is determined by two things:

  • The type of built-in object it is executed against. The specification determine what built-ins will be identified as and a Date will say "[object Date]".
  • As of ES6 - the well-known symbol @@toStringTag.

For the normal objects, prior to ES6 the default toString() would only produce "[object Object]" while post ES6 the result is the string "[object @@toStringTag]" by using the value of the symbol. By default the value for the symbol is "Object".

You can override it for a custom class:

function Dog(name, breed) {
  this.name = name;
  this.breed = breed;
}

Dog.prototype[Symbol.toStringTag] = "Dog";

var dog = new Dog("YOU'RE", "READING");

var zehbi2 = Object.prototype.toString.call(dog);

console.log(zehbi2);

Or any object:

var obj = { 
  [Symbol.toStringTag]: "Custom" 
}

console.log(Object.prototype.toString.call(obj));
console.log(obj.toString());

You can even override it for built-in objects:

var obj = new Date()

obj[Symbol.toStringTag] = "Custom";

console.log(Object.prototype.toString.call(obj));

Upvotes: 1

Related Questions