js是松散类型,本篇主要整理ECMAScript中的数据类型,包括5种简单数据类型与1中复杂数据类型。

typeof操作符

首先,我们可以根据typeof操作符检测给定变量的数据类型。typeof的返回值主要为:

1
2
3
4
5
6
undefined 该值未定义
boolean 布尔值
string 字符串
number 数值
object 对象
function 函数

需要注意的是,以上返回值中,function并不是js的数据类型,function似乎应该归于object类型。

少了的那个数据类型为null,在现代化浏览器中,typeof null返回object,因为浏览器将null作为空对象的引用。想一想好像确实是这样。

(其实functionobject还是有不同的,比如参数啥的)
(不太常见的旧浏览器中,typeof null返回的是function

Undefined类型

Undefined类型只有一个值undefined,当声明的变量未初始化时,该变量的值即为undefined。

判断一个变量是否为Undefined类型,可以使用等于直接与undefined比较:

1
2
3
var aaa;
console.log(aaa === undefined);
> true

需要注意的是,未初始化的变量与未声明的变量是两个概念:

1
2
3
4
5
6
var aaa;
> undefined
aaa
> undefined
bbb
> VM136:1 Uncaught ReferenceError: bbb is not defined

可以看到,未初始化的变量直接使用会返回undefined,而未声明的变量会报错。

更需要注意的是:

1
2
3
4
typeof aaa
> "undefined"
typeof bbb
> "undefined"

未初始化与未声明的变量使用typeof操作符检测都返回undefined

再次提示未声明的变量不可直接使用:

1
2
3
4
console.log(aaa === undefined);
> true
console.log(bbb === undefined);
> Uncaught ReferenceError: bbb is not defined

Null类型

Null类型只有一个值:nullnull看起来似乎很奇怪,它表示的是一个空对象指针,使用typeof操作符返回的是object

null作为空对象指针也很实用,在准备用一个变量保存对象时,可以先将该对象初始化/赋值为null,将空对象赋值为null的操作是很优良的习惯:

1
var apple = null;

这样在判断一个变量是否保存了对象的引用(即本身不再为null)时,可以这样判断:

1
2
3
4
5
6
7
apple === null;
> true
apple = new Object();
apple === null;
> false
apple !== null;
> true

需要注意的是:

1
2
3
4
var banana = null;
console.log(banana === null)
console.log(banana === undefined)
console.log(banana == undefined)

思考5s……

以上输出分别为:

1
2
3
true
false
true

关于==(相等)与===(全等)的关系会在后面“操作符篇”进行说明,现在先解释一下为何console.log(banana == undefined)会成立。因为undefined是派生自null值,因此undefined == null

(注意上面一句话中提到了派生,因为js是支持继承的,这是一个很深入的话题,后面应该会有一篇“继承篇”来整理这个绝对算得上很核心的话题)

Boolean类型

值为truefalse,记得千万不要写成TrueFalse(尤其是一边写python一边写js的时候-_-!)

其他类型与Boolean类型转化是值得学习的点:

1
2
3
4
5
6
7
8
9
10
11
true的情况:
String类型:任何非空字符串
Number类型:任何非零数字值(包括无穷大)
Object类型:任何非空对象
Undefined:n/a(即不适用)

false的情况
String类型:""空字符串
Number类型:0NaN
Object类型:null
Undefined:undefined

Number类型

与java等类似,有十进制、八进制(0开头)、十六进制(0x开头)这些。

浮点数也是Number类型的一部分,只是浮点数占用的内存空间是整数值的两倍,所以js会不失时机的将浮点数转化为整数值:

1
2
ccc = 1.0
> 1

可以使用e表示的科学技术法

数值范围

Number类型表示的范围通常不会太注意,但是在大数据量的情况下,往往会一不留神就会掉入Infinity(正无穷)中(也许会掉到(-Infinity)负无穷中)。Number表示的范围可以使用Number.MIN_VALUENumber.MAX_VALUE查看:

1
2
3
4
Number.MIN_VALUE
> 5e-324
Number.MAX_VALUE
> 1.7976931348623157e+308

(可以用IsFinite()函数来检查一个数值是否处于最小、最大之间)

NaN(not a number)

需要注意如何判断一个操作数返回值是否为NaN(比如在用一个数值除以一个非数值的操作):

1
2
3
4
5
6
7
8
错误示范:
NaN == NaN
> false
因为NaN与任何值都不相等
正确示范:
isNaN(NaN)
如果启用了ESLint,在ES6中最好使用:
Number.isNaN(NaN)

数值转化

主要涉及到三个函数Number()parseInt()parseFloat(),还有一个很XX的操作符+

Number()

1
2
3
Boolean->true:0 false:1
null:0
undefined:NaN

字符串类型的比较有意思:

1
2
3
4
5
6
只包含数字的(包括+、-、进制表示与浮点数),直接转化为数字
字符串为空:0
字符串包含其他字符:NaN
var ddd = '123aaa';
Number(ddd);
> NaN

parseInt()

在ESLint中,更推荐使用parseInt(),与Number()比:

1
2
1、支持转换时传入基数(进制)参数。强烈建议在转化时指定基数
2、若字符串开头为数字,则对字符串进行最大解析。若开头不为数值,则与Number()转化一致

第二条规则样例:

1
2
3
4
5
var ddd = '123aaa';
Number(ddd);
> NaN
parseInt(ddd);
> 123

parseFloat()

只需要注意它支持十进制

+操作符

这个操作符其实跟Number()是一样的效果。

String类型

与java比较类似,字符串是不可变的。
对字符串做加法,基本会经历:
1、创建一个新的字符串
2、将原字符串与待加入字符串填充到新字符串中
3、销毁原字符串(浏览器后台自行销毁)

对于字符串拼接,相较于旧浏览器,现代浏览器会做优化。

字符串转化

主要有toString()方法与String()方法,也有一个很XX的+操作符(这次得需要与空字符串联合使用)。

toString()方法与String()方法区别在于nullundefined由于没有toString()方法,所以只能使用String()
String()在执行非nullundefined参数时也是调用的toString()

通过空字符串与+操作符结合变量,与变量直接使用toString()一致

Object类型

创建方式为:

1
var obj = new Object(); // 虽然括号可以省略,但没必要

作为对象,有一些自己的基础方法:

1
2
3
4
5
6
7
constructor:构造函数
hasOwnProperty(propertyName):分析属性是否存在于当前实例,而不是原型中
isPrototypeOf(object):分析传入的对象是否为当前实例的原型
propertyIsEnumerable(propertyName):分析属性是否为可枚举属性
toLocaleString():返回对象字符串表示,与执行环境地区对应
toString():返回对象的字符串表示
valueOf():返回对象的字符串、数值或布尔值表示。通常与toString()返回结果一致

涉及到的实例与原型的概念,应该会在后面的“继承篇”里总结。

Object转化为String

一般会使用JSON进行Object与String的互转:

1
2
3
var obj = {a: 1};
var targetStr = JSON.stringify(obj);
var targetObj = JSON.parse(targetStr);

Object转化为Number

对象转化为Number,可以调用Number()或者parseInt()方法,或者是一元加法(就是上面那个很XX的+操作符),转化流程主要为:

1
2
1、调用valueOf()方法,将对象转化为字符串、数值或布尔值,再根据字符串、数值、布尔值的相应的规则转化为Number
2、若valueOf()方法返回NaN,则调用对象的toString()方法,将对象转化为字符串,再转化为Number