基础知识
您可能不知道,但在 JavaScript 中,每当我们与字符串、数字或布尔基元交互时,我们都会进入一个隐藏的对象阴影和强制世界。
字符串、数字、布尔值、null、未定义和符号。
在 JavaScript 中有 7 种基本类型:undefined、null、boolean、string、number、bigint 和 symbol。其他一切都是对象。基本类型boolean、string 和number 可以被它们的对应对象包装。这些对象分别是Boolean、String 和Number 构造函数的实例。
typeof true; //"boolean"
typeof new Boolean(true); //"object"
typeof "this is a string"; //"string"
typeof new String("this is a string"); //"object"
typeof 123; //"number"
typeof new Number(123); //"object"
如果原语没有属性,为什么"this is a string".length 会返回一个值?
因为 JavaScript 很容易在原语和对象之间进行强制转换。在这种情况下,字符串值被强制转换为字符串对象,以便访问属性长度。字符串对象只使用了几分之一秒,之后它就被献给了垃圾收集之神——但本着电视发现节目的精神,我们将困住这个难以捉摸的生物并将其保存下来以供进一步分析……
为了进一步证明这一点,请考虑以下示例,其中我们向 String 构造函数原型添加了一个新属性。
String.prototype.sampleProperty = 5;
var str = "this is a string";
str.sampleProperty; // 5
通过这种方式,基元可以访问由它们各自的对象构造函数定义的所有属性(包括方法)。
所以我们看到原始类型会在需要时适当地强制转换为对应的对象。
toString()方法解析
考虑下面的代码
var myObj = {lhs: 3, rhs: 2};
var myFunc = function(){}
var myString = "This is a sample String";
var myNumber = 4;
var myArray = [2, 3, 5];
myObj.toString(); // "[object Object]"
myFunc.toString(); // "function(){}"
myString.toString(); // "This is a sample String"
myNumber.toString(); // "4"
myArray.toString(); // "2,3,5"
如上所述,真正发生的情况是,当我们在原始类型上调用 toString() 方法时,必须先将其强制转换为对应的对象,然后才能调用该方法。
即myNumber.toString() 等价于Number.prototype.toString.call(myNumber) 和其他原始类型类似。
但是,如果我们不是将原始类型传递给对应的 Object 构造函数对应的 toString() 方法,而是强制将原始类型作为参数传递给 Object 函数构造函数 (Object.prototype.toString.call(x)) 的 toString() 方法,那会怎样?
仔细看看 Object.prototype.toString()
根据documentation,
当调用toString方法时,会采取以下步骤:
- 如果
this 的值为undefined,则返回"[object Undefined]"。
- 如果
this 的值为null,则返回"[object Null]"。
- 如果此值不是上述任何一个,则设
O 为调用toObject 并传递this 值作为参数的结果。
- 让 class 为
O 的 [[Class]] 内部属性的值。
- 返回三个字符串
"[object "、class 和"]" 连接的结果字符串值。
从下面的例子中理解这一点
var myObj = {lhs: 3, rhs: 2};
var myFunc = function(){}
var myString = "This is a sample String";
var myNumber = 4;
var myArray = [2, 3, 5];
var myUndefined = undefined;
var myNull = null;
Object.prototype.toString.call(myObj); // "[object Object]"
Object.prototype.toString.call(myFunc); // "[object Function]"
Object.prototype.toString.call(myString); // "[object String]"
Object.prototype.toString.call(myNumber); // "[object Number]"
Object.prototype.toString.call(myArray); // "[object Array]"
Object.prototype.toString.call(myUndefined); // "[object Undefined]"
Object.prototype.toString.call(myNull); // "[object Null]"
参考资料:
https://es5.github.io/x15.2.html#x15.2.4.2
https://es5.github.io/x9.html#x9.9
https://javascriptweblog.wordpress.com/2010/09/27/the-secret-life-of-javascript-primitives/