这两天我有个小伙伴二面面b站的时候被面试官问到了这个问题,觉得挺有意思的,分享给大家~
js
中toString
其实不止对象身上的toString
方法,虽然传统上我们一般说的toString
就是对象身上的,也就是Object.prototype.toString
,但其实toString
是有三种的
{}.toString()
返回由"[object
"和class
和']
'组成的字符串[].toString()
返回由数组内部元素以逗号拼接的字符串xx.toString()
直接返回字符串字面量
Object.prototype.toString()
对于普通对象来说,Object
是构造函数,因此此时的toString
就是构造函数原型身上的方法,而我们普通对象去寻找身上的属性就是先去构造函数显示具有的属性中去找,这个显示属性就是构造函数自身的属性,找不到时,就去自己自己的隐式原型身上找,而实例对象的隐式原型(__proto__)
就是构造函数的显示原型(prototype)
,因此才能去调用这个toString
,而这个toString
的作用是用来判断数据类型的
既然是对象,那么就是输出[object Object]

数组也是对象,那数组调用这个toString
,是否就是输出[object Array]
,我们来看下

哦嚯~,居然不是,是个空
注意:不是空字符串,就是空,因为空格也是字符串
如果数组构造函数Array
身上没有写toString
,那么这个输出结果一定不是空,而是[object Array]
,因为他会顺着原型链去找到对象身上的toString
这就是因为官方给数组原型身上已经打造了另一个toString
,或者说是重写了个toString
[].toString()
没错!这就是因为数组身上的toString
方法,数组里面有什么,就以字符串的方式返回出来

xx.toString
好了,既不是数组又不是对象,那么其余的类型就是这个版本的toString
,也就是直接返回字符串字面量
那我写个函数函数表达式,看看这个值输出的字符串字面量长什么样子~

整个函数体都打上了引号,成了个字符串
其余原始类型如下
scss
(123).toString()
'123'
('dolphin').toString()
'dolphin'
(true).toString()
'true'
(Symbol('hello')).toString()
'Symbol(hello)'
(BigInt(11)).toString()
'11'
注意:undefined和null没有这个方法,调用会报错
[] == 1 true还是false

==
和 ===
的区别就是在于前者会进行隐式类型转换,后者是严格相等
==
的比较有很多种情况:带注释的 ES5 --- Annotated ES5
这里就不带大家一一查看了,总之,这里适用的情形如下

对象那一方需要调用 ToPrimitive(x)方法,这个方法我需要单独拿来说下

ToPrimitive(x , hint)
如果hint
是Number
,如下步骤
- 如果是基本类型,不进行转换
- 否则,调用
valueOf
方法,如果得到原始值,则返回 - 否则,调用
toString
方法,如果得到原始值,则返回 - 否则,报错
如果hint
是String
,如下步骤
- 如果是基本类型,不进行转换
- 否则,调用
toString
方法,如果得到原始值,则返回 - 否则,调用
valueOf
方法,如果得到原始值,则返回 - 否则,报错
==
最终都是调用ToNumber
,也就是说调用hint
为Number
的ToPrimitive
,因此套用这个规则,[]是引用类型,走到第三步,去调用valueOf
,我们都清楚,valueOf
的作用是提供包装类,将其转换成原始类型的,因此,走到第三步,调用toString
,[].toString
就是得到一个空,这个空最终再去ToNumber
,空转数字就是0
,因此最终得到0 == 1
,返回false
[] == ![] true还是false

这个目测看肯定以为是false
,但是在v8
眼里,还是需要一步一步来看,首先,取非!的优先级高于==
,因此先执行!,!的执行步骤是两个,现将被执行对象转成布尔,其次才是取非,因此,任何引用类型转布尔都是true
,因此!true
就是false
,因此是[] == false
, 好了,继续看,==
都是要将数据调用ToNumber
的,因此这个false
就是0

现在就是[].ToNumber
了,因为是引用类型转数字,所以最后会调用hint
为数字的ToPrimitive
,因此先valueOf
,后再toString
,valueOf
不走,因为只对包装类起作用,所以就是走toString
,得到一个空,空再去调用ToNumber
,得到0
,因此最终就是0 == 0
,返回true
最后
关于toString
,你一定得搞明白,否则js的隐式类型转换你肯定会云里雾里,要是我被问到我肯定也会有点懵逼
如果你对春招感兴趣,可以加我的个人微信:
Dolphin_Fung
,我和我的小伙伴们有个面试群,可以进群讨论你面试过程中遇到的问题,我们一起解决
另外有不懂之处欢迎在评论区留言,如果觉得文章对你学习有所帮助,还请"点赞+评论+收藏"一键三连,感谢支持!