所有 typeof 返回值为 "object" 的对象(如数组)都包含一个内部属性 [[Class]](我们可以把它看作一个内部的分类,而非 传统的面向对象意义上的类)。这个属性无法直接访问,一般通过 Object.prototype.toString(..) 来查看。例如:
Object.prototype.toString.call( [1,2,3] );
// "[object Array]"
Object.prototype.toString.call( /regex-literal/i );
// "[object RegExp]"
数组的内部[[class]]属性值是"Array",正则表达式是"RegExp",多数情况下,对象的内部[[class]]属性和创建该对象的内建原生构造函数相对应,但并非总是如此.
- 基本数值类型
Object.prototype.toString.call(null); // "[object Null]"
Object.prototype.toString.call(undifined); // "[object Undefined]"
虽然Null()和Undefined()这样的原生构造函数并不存在,但是内部[[class]]属性值仍然是"Null"和"Undefined".
- 其他基本类型值
Object.prototype.toString.call('pat'); // "[object String]"
Object.prototype.toString.call(123); // "[object Number]"
Object.prototype.toString.call(true); // "[object Boolean]"
基本类型值被各自的封装对象自动包装,所以他们的内部[[class]]属性值分别为"String","Number"和"Boolean"
- 但自己创建的类和普通对象不会有这份特殊待遇,toString() 找不到 toStringTag 属性时只好返回默认的 Object 标签:
class myClass {}
Object.prototype.toString.call(new myClass()); // "[object Object]"
const obj = {};
Object.prototype.toString.call(obj); // "[object Object]"
加上 toStringTag 属性,自己定义的类也会有自定义的类型标签了:
class myClass {
get [Symbol.toStringTag]() {
return "myClass1";
}
}
Object.prototype.toString.call(new myClass()); // "[object myClass1]"
const obj = {};
Object.defineProperty(obj,
Symbol.toStringTag,
{ value: 'CustomObject' }); // "[object CustomObject]"