Internal [[Class]]
Values that are typeof
"object"
(such as an array) are additionally tagged with an internal [[Class]]
property (think of this more as an internal classification rather than related to classes from traditional class-oriented coding). This property cannot be accessed directly, but can generally be revealed indirectly by borrowing the default Object.prototype.toString(..)
method called against the value. For example:
Object.prototype.toString.call( [1,2,3] ); // "[object Array]"
Object.prototype.toString.call( /regex-literal/i ); // "[object RegExp]"
So, for the array in this example, the internal [[Class]]
value is "Array"
, and for the regular expression, it’s "RegExp"
. In most cases, this internal [[Class]]
value corresponds to the built-in native constructor (see below) that’s related to the value, but that’s not always the case.
What about primitive values? First, null
and undefined
:
Object.prototype.toString.call( null ); // "[object Null]"
Object.prototype.toString.call( undefined ); // "[object Undefined]"
You’ll note that there are no Null()
or Undefined()
native constructors, but nevertheless the "Null"
and "Undefined"
are the internal [[Class]]
values exposed.
But for the other simple primitives like string
, number
, and boolean
, another behavior actually kicks in, which is usually called “boxing” (see “Boxing Wrappers” section next):
Object.prototype.toString.call( "abc" ); // "[object String]"
Object.prototype.toString.call( 42 ); // "[object Number]"
Object.prototype.toString.call( true ); // "[object Boolean]"
In this snippet, each of the simple primitives are automatically boxed by their respective object wrappers, which is why "String"
, "Number"
, and "Boolean"
are revealed as the respective internal [[Class]]
values.
Note: The behavior of toString()
and [[Class]]
as illustrated here has changed a bit from ES5 to ES6, but we cover those details in the ES6 & Beyond title of this series.