经常被面试官问道的 JavaScript 数据类型知识你真的懂吗?
前言
之前面试了几个开发者,他们确实做过不少项目,能力也是不错的,但是发现 js 基础不扎实, 于是决定写一下这篇 javascrip 数据类型相关的基础文章,其实也不仅仅是因为面试了他们,之前自己在面试的时候,也曾经被虐过,面试官说过的最深刻的一句话我到现在都记得。
基础很重要,只有基础好才会很少出
bug
,大多数的bug
都是基础不扎实造成的。
作者简介:koala,专注完整的 Node.js 技术栈分享,从 JavaScript 到 Node.js,再到后端数据库,祝您成为优秀的高级 Node.js 工程师。【程序员成长指北】作者,Github 博客开源项目 https://github.com/koala-coding/goodBlog
这里给出两道我们公司数据类型基础相关的面试题和答案,如果都能做对并且知道为什么(可以选择忽略本文章):
本篇文章会以一个面试官问问题的角度来进行分析讲解
js 中的数据类型
面试官:说一说
javascript
中有哪些数据类型?
JavaScript
中共有七种内置数据类型,包括基本类型和*对象类型*。
基本类型
基本类型分为以下六种:
string(字符串)
boolean(布尔值)
number(数字)
symbol(符号)
null(空值)
undefined(未定义)
注意:
string
、number
、boolean
和null
undefined
这五种类型统称为原始类型(Primitive),表示不能再细分下去的基本类型;
symbol
是 ES6 中新增的数据类型,symbol
表示独一无二的值,通过Symbol
函数调用生成,由于生成的 symbol 值为原始类型,所以Symbol
函数不能使用new
调用;
null
和undefined
通常被认为是特殊值,这两种类型的值唯一,就是其本身。
对象类型
对象类型也叫引用类型,array
和function
是对象的子类型。对象在逻辑上是属性的无序集合,是存放各种值的容器。对象值存储的是引用地址,所以和基本类型值不可变的特性不同,对象值是可变的。
js 弱类型语言
面试官:说说你对
javascript
是弱类型语言的理解?
JavaScript
是弱类型语言,而且JavaScript
声明变量的时候并没有预先确定的类型,变量的类型就是其值的类型,也就是说变量当前的类型由其值所决定,夸张点说上一秒种的String
,下一秒可能就是个Number
类型了,这个过程可能就进行了某些操作发生了强制类型转换。虽然弱类型的这种不需要预先确定类型的特性给我们带来了便利,同时也会给我们带来困扰,为了能充分利用该特性就必须掌握类型转换的原理。
js 中的强制转换规则
面试官:
javascript
中强制类型转换是一个非常易出现bug
的点,知道强制转换时候的规则吗?
注:规则最好配合下面什么时候发生转换使用这些规则看效果更佳。
`ToPrimitive`(转换为原始值)
ToPrimitive
对原始类型不发生转换处理,只针对引用类型(object)的,其目的是将引用类型(object)转换为非对象类型,也就是原始类型。
ToPrimitive
运算符接受一个值,和一个可选的期望类型作参数。ToPrimitive
运算符将值转换为非对象类型,如果对象有能力被转换为不止一种原语类型,可以使用可选的 期望类型 来暗示那个类型。
转换后的结果原始类型是由期望类型决定的,期望类型其实就是我们传递的type
。直接看下面比较清楚。
ToPrimitive
方法大概长这么个样子具体如下。
type 不同值的说明
type 为
string
:
先调用
obj
的toString
方法,如果为原始值,则return
,否则进行第 2 步调用
obj
的valueOf
方法,如果为原始值,则return
,否则进行第 3 步抛出
TypeError
异常
type 为
number
:
先调用
obj
的valueOf
方法,如果为原始值,则return
,否则进行第 2 步调用
obj
的toString
方法,如果为原始值,则return
,否则第 3 步抛出
TypeError
异常
type 参数为空
该对象为
Date
,则 type 被设置为String
否则,type 被设置为
Number
Date 数据类型特殊说明:
对于Date
数据类型,我们更多期望获得的是其转为时间后的字符串,而非毫秒值(时间戳),如果为number
,则会取到对应的毫秒值,显然字符串使用更多。
其他类型对象按照取值的类型操作即可。
`ToPrimitive`总结
ToPrimitive
转成何种原始类型,取决于 type,type 参数可选,若指定,则按照指定类型转换,若不指定,默认根据实用情况分两种情况,Date
为string
,其余对象为number
。那么什么时候会指定 type 类型呢,那就要看下面两种转换方式了。
toString
Object.prototype.toString()
toString()
方法返回一个表示该对象的字符串。
每个对象都有一个 toString()
方法,当对象被表示为文本值时或者当以期望字符串的方式引用对象时,该方法被自动调用。
这里先记住,valueOf()
和 toString()
在特定的场合下会自行调用。
valueOf
Object.prototype.valueOf()
方法返回指定对象的原始值。
JavaScript
调用 valueOf()
方法用来把对象转换成原始类型的值(数值、字符串和布尔值)。但是我们很少需要自己调用此函数,valueOf
方法一般都会被 JavaScript
自动调用。
不同内置对象的valueOf
实现:
String => 返回字符串值
Number => 返回数字值
Date => 返回一个数字,即时间值,字符串中内容是依赖于具体实现的
Boolean => 返回 Boolean 的 this 值
Object => 返回 this
对照代码会更清晰一些:
Number
Number
运算符转换规则:
null
转换为 0undefined
转换为NaN
true
转换为 1,false
转换为 0字符串转换时遵循数字常量规则,转换失败返回
NaN
注意:对象这里要先转换为原始值,调用
ToPrimitive
转换,type 指定为number
了,继续回到ToPrimitive
进行转换。
String
String
运算符转换规则
null
转换为'null'
undefined
转换为undefined
true
转换为'true'
,false
转换为'false'
数字转换遵循通用规则,极大极小的数字使用指数形式
注意:对象这里要先转换为原始值,调用
ToPrimitive
转换,type
就指定为string
了,继续回到ToPrimitive
进行转换(上面有将到ToPrimitive
的转换规则)。
Boolean
ToBoolean
运算符转换规则
除了下述 6 个值转换结果为 false
,其他全部为 true
:
undefined
null
-0
0 或+0
NaN
''(空字符串)
假值以外的值都是真值。其中包括所有对象(包括空对象)的转换结果都是true
,甚至连false
对应的布尔对象new Boolean(false)
也是true
js 转换规则不同场景应用
面试官问:知道了具体转换成什么的规则,但是都在什么情况下发生什么样的转换呢?
什么时候自动转换为 string 类型
在没有对象的前提下
字符串的自动转换,主要发生在字符串的加法运算时。当一个值为字符串,另一个值为非字符串,则后者转为字符串。
当有对象且与对象
+
时候
对下面'2'+obj2
详细举例说明如下:
左边为
string
,ToPrimitive
原始值转换后不发生变化右边转化时同样按照
ToPrimitive
进行原始值转换,由于指定的 type 是number
,进行ToPrimitive
转化调用obj2.valueof()
,得到的不是原始值,进行第三步调用
toString()
return 'a'
符号两边存在
string
,而且是+
号运算符则都采用String
规则转换为string
类型进行拼接输出结果
2a
对下面'2'+obj1
详细举例说明如下:
左边为
string
,ToPrimitive
转换为原始值后不发生变化右边转化时同样按照
ToPrimitive
进行原始值转换,由于指定的 type 是number
,进行ToPrimitive
转化调用obj2.valueof()
,得到{ a: 1, b: 2 }
调用
toString()
return [object Object]
符号两边存在
string
,而且是+号运算符则都采用String
规则转换为string
类型进行拼接输出结果
2[object Object]
代码中几种特殊对象的转换规则基本相同,就不一一说明,大家可以想一下流程。
注意:不管是对象还不是对象,都有一个转换为原始值的过程,也就是ToPrimitive
转换,只不过原始类型转换后不发生变化,对象类型才会发生具体转换。
string 类型转换开发过程中可能出错的点:
预期输出结果 120 实际输出结果 10020
什么时候自动转换为 Number 类型
有加法运算符,但是无
String
类型的时候,都会优先转换为Number
类型
例子:
```javascript
true + 0 // 1
true + true // 2
true + false //1
```
除了加法运算符,其他运算符都会把运算自动转成数值。
例子:
```javascript
'5' - '2' // 3
'5' * '2' // 10
true - 1 // 0
false - 1 // -1
'1' - 1 // 0
'5' * [] // 0
false / '5' // 0
'abc' - 1 // NaN
null + 1 // 1
undefined + 1 // NaN
//一元运算符(注意点)
+'abc' // NaN
-'abc' // NaN
+true // 1
-false // 0
```
注意:
null
转为数值时为 0,而undefined
转为数值时为NaN
。
判断等号也放在`Number`里面特殊说明
== 抽象相等比较与+运算符不同,不再是String
优先,而是Number
优先。
下面列举x == y
的例子
如果
x
,y
均为number
,直接比较
没什么可解释的了
如果存在对象,
ToPrimitive()
type 为number
进行转换,再进行后面比较
存在
boolean
,按照ToNumber
将boolean
转换为 1 或者 0,再进行后面比较
4.如果x
为string
,y
为number
,x
转成number
进行比较
什么时候进行布尔转换
- 布尔比较时
- if(obj)
, while(obj)
等判断时或者 三元运算符只能够包含布尔值
条件部分的每个值都相当于false
,使用否定运算符后,就变成了true
js 中的数据类型判断
面试官问:如何判断数据类型?怎么判断一个值到底是数组类型还是对象?
三种方式,分别为 typeof
、instanceof
和 Object.prototype.toString()
typeof
通过 typeof
操作符来判断一个值属于哪种基本类型。
上面代码的输出结果可以看出,
null
的判定有误差,得到的结果
如果使用 typeof
,null
得到的结果是object
操作符对对象类型及其子类型,例如函数(可调用对象)、数组(有序索引对象)等进行判定,则除了函数都会得到
object
的结果。
综上可以看出typeOf
对于判断类型还有一些不足,在对象的子类型和null
情况下。
instanceof
通过 instanceof
操作符也可以对对象类型进行判定,其原理就是测试构造函数的 prototype
是否出现在被检测对象的原型链上。
复制代码注意:instanceof
也不是万能的。
举个例子:
在这个例子中,arr
数组相当于 new Array()
出的一个实例,所以 arr.__proto__ === Array.prototype
,又因为 Array
属于 Object
子类型,即 Array.prototype.__proto__ === Object.prototype
,因此 Object
构造函数在 arr
的原型链上。所以 instanceof
仍然无法优雅的判断一个值到底属于数组还是普通对象。
还有一点需要说明下,有些开发者会说 Object.prototype.__proto__ === null
,岂不是说 arr instanceof null
也应该为 true
,这个语句其实会报错提示右侧参数应该为对象,这也印证 typeof null
的结果为 object
真的只是javascript
中的一个 bug
。
Object.prototype.toString()
可以说是判定 JavaScript
中数据类型的终极解决方法了,具体用法请看以下代码:
我们可以发现该方法在传入任何类型的值都能返回对应准确的对象类型。用法虽简单明了,但其中有几个点需要理解清楚:
该方法本质就是依托
Object.prototype.toString()
方法得到对象内部属性[[Class]]
传入原始类型却能够判定出结果是因为对值进行了包装
null
和undefined
能够输出结果是内部实现有做处理
NaN 相关总结
`NaN`的概念
NaN
是一个全局对象的属性,NaN
是一个全局对象的属性,NaN
是一种特殊的Number
类型。
什么时候返回 NaN (开篇第二道题也得到解决)
无穷大除以无穷大
给任意负数做开方运算
算数运算符与不是数字或无法转换为数字的操作数一起使用
字符串解析成数字
一些例子:
误区
`toString`和`String`的区别
toString
toString()
可以将数据都转为字符串,但是null
和undefined
不可以转换。
```javascript
console.log(null.toString())
//报错 TypeError: Cannot read property 'toString' of null
console.log(undefined.toString())
//报错 TypeError: Cannot read property 'toString' of undefined
```
toString()
括号中可以写数字,代表进制
二进制:.toString(2);
八进制:.toString(8);
十进制:.toString(10);
十六进制:.toString(16);
String
String()
可以将null
和undefined
转换为字符串,但是没法转进制字符串
```javascript
console.log(String(null));
// null
console.log(String(undefined));
// undefined
```
# 交流
关注公众号:『程序员成长指北』, 获取更多精选文章
#### 个人公众号技术栈
公众号二维码
版权声明: 本文为 InfoQ 作者【koala】的原创文章。
原文链接:【http://xie.infoq.cn/article/491ebd10f6ec07823664d9486】。未经作者许可,禁止转载。
评论