概述

JavaScript的数据类型共有8种(大小写无所谓):

  • 数值(number)
  • 字符串(string)
  • 布尔值(boolean)
  • undefined
  • null
  • 对象(object,并且object叫做复杂类型,上面六种叫简单类型)
  • Symbol(很少用,可以看方方老师写的博客
  • BigInt(2020年出的数据类型,现在用得很少,先了解一下)

注意以下不是数据类型:

  • 数组、函数、日期
  • 它们都属于object

编程语言为什么需要类型

需要分清楚 数字1字符串1 ?即 1 和 "1" !

  • 功能上不同
    • 数字是数字,字符串是字符串,必须严谨。
    • 数字可以加减乘除,字符串不可以。
    • 字符串可以表示电话号码,数字不行。(注意,电话号码可不单只有数字,有些国家的电话号码有英文字母与数字组合或者纯字母表示,所以只能是字符串。)
  • 储存形式不同(还记得JS的内存图吗?)
    • 在JS中,数字用64位浮点数的形式存储。
    • 字符串用类似UTF8形式存储的(UCS-2),总之存字符串就是编号,然后存编号。

typeof 运算符

如何判断 是什么类型的数值?
直接用 typeof 后面接该数值就可以了,如

  1. typeof 123 // "number"
  2. typeof '123' // "string"
  3. typeof false // "boolean"

数值(number)

写法

  • 整数:1
  • 小数:0.1
  • 科学计数法:1.23e4
  • 八进制(比较少用):0123 or 00123 or 0o123
  • 十六进制写法:0x3F or 0X3F
  • 二进制写法:0b11 or 0B11

还可以进行类型转换,number => string

  1. String(n)
  2. n + ''

特殊值

正零和负零

  1. //0分正零(+1)和负零(-1),但是这两个零都等于0,大部分情况下是一样的:
  2. -0 === +0 //true
  3. 0 === -0 //true
  4. 0 === +0 //true
  5. //除了这情况:
  6. 1/+0 等于 +Infinity
  7. 1/-0 等于 -Infinity
  8. -Infinity === +Infinity //false

整数和浮点数

JavaScript其实是没有整数的,因为在JS中,所有数字都是以64位浮点数形式存储,也就是说,1和1.0其实是一样的。

  1. 1 === 1.0 //true

注意,浮点数不是精确的值,所有涉及到的浮点数运算和比较都需要注意,如

  1. 0.1 + 0.2 === 0.3 //false
  2. 0.3 / 0.1 // 2.9999999999999996

如果想要正确的比较方法,需要如下:

  1. console.log( Math.abs(0.1 + 0.2 - 0.3) <= Number.EPSILON ) //true

NaN(不是一个数)

表示“非数字”(Not a Number),实验可以得出 NaN 的有:

  1. 0/0 //NaN

更神奇的是, NaN 虽然表示不是一个数,但 NaN 确实属于数值:

  1. typeof NaN // NaN

在运算方面,任何跟 NaN 运算的数值,都等于 NaN ,并且 NaN 不等于 NaN ,想想都知道:

  1. NaN + 32 // NaN
  2. NaN - 32 // NaN
  3. NaN * 32 // NaN
  4. NaN / 32 // NaN
  5. 0 * Infinity // NaN
  6. Infinity - Infinity // NaN
  7. Infinity / Infinity // NaN
  8. //并且 NaN 不等于 NaN
  9. NaN === NaN // false

数值范围

根据标准,64位浮点数的指数部分的长度是11个二进制位,意味着指数部分的最大值是2047(2的11次方减1)。 也就是说,64位浮点数的指数部分的值最大为2047,分出一半表示负数,则 JavaScript 能够表示的数值范围为21024到2-1023(开区间),超出这个范围的数无法表示(即+Infinity或-Infinity)。
—-网道JavaScript

  1. Number.MAX_VALUE // 1.7976931348623157e+308 表示最大值是多少
  2. Number.MIN_VALUE // 5e-324 表示最小值是多少

字符串(string)

类型转换:string => number

  1. Number(s)
  2. parseInt(s)/parseFloat(s)
  3. s - 0

其他类型转字符串:x => string

  1. String(x)
  2. x.toString()

写法

  • 单引号 ‘你好’
  • 双引号 “你好”
  • 反引号 你好

注意:引号不属于字符串的一部分,就好像书名号不属于书名一样。

转义

可以用单引号括双引号,双引号括单引号,但是不可以括相同的引号:

  1. "我想说:'你好!'" //合法
  2. '我想说:"你好!"' //合法
  3. `我想说:'你好!'` //合法
  4. `我想说:"你好!"` //合法
  5. "我想说:"你好!"" //错误的写法,单引号同理

可我就是要一样怎么办?
可以选择用转义的方法:

  1. "我想说:\"你好!\"" //在想要包括在括号里面的字符的前面加一个反斜杠即可。
  2. 'it\'s OK'

转义有很多用途,如

  1. //字符串默认只能写一行,不可以多行,以下是属于不合法的字符串:
  2. 'a
  3. b
  4. c'
  5. //但我就是想要多行怎么办?可以用转义的方式:
  6. 'a\
  7. b\
  8. c'//或者用反引号
  9. `a
  10. b
  11. c`
  12. //'a b c'写代码时虽然是多行,但输出的时候还是一行。

除了这个方式,还有很多特殊用途:

  • \0 :null(\u0000
  • \n :换行符(\u000A
  • \r :回车键(\u000D
  • \t :制表符(\u0009
  • \' :单引号(\u0027
  • \" :双引号(\u0022
  • \\ :反斜杠(\u005C
  • \uFFFF 表示对应的Unicode字符
  • \xFF 表示前256个Unicode字符

字符串与数组

字符串可以被视为字符数组,因此可以使用数组的方括号运算符,用来返回某个位置的字符(位置编号从0开始)。

  1. var s = 'hello';
  2. s[0] // "h"
  3. s[1] // "e"
  4. s[4] // "o"
  5. // 直接对字符串使用方括号运算符
  6. 'hello'[1] // "e"

而且不可以单个字符更改或删除,浏览器不会报错但默默的失败

  1. var s = 'hello';
  2. delete s[0];
  3. s // "hello"
  4. s[1] = 'a';
  5. s // "hello"

【问】字符串有最大长度吗?
【答】有,长度为2^53 - 1,但这个长度不是字符数!

实际上字符是以Unicode的方式表示,而一个Unicode的码点表示一个字符,常见的编码有 UTF8 和 UTF16 。在JS中,字符串并不是意义上的 String,而是编码 UTF16,字符串的操作 charAt、charCodeAt、length等方法都是针对UTF16编码。所以说,字符串长度取决于编码长度。

布尔(boolean)

只有 truefalse 两个值,注意大小写。

通过比较、运算就可以得出布尔值。通常需要配合判断真假语句 if(value){...}else{...}

问题来了,value如果不是比较和运算得出来的bool值怎么办?这时候就可以通过该value是否是falsy值了。

falsy值是什么东西?

falsy就相当于false但又不是false的值,分别是:

  • undefined
  • null
  • false
  • 0
  • NaN
  • ""'' (空字符串,里面如果有空格就不是空字符串了, " "' '

除了falsy值,其他的均为true!

类型转换:x => bool

  1. Boolean(x)
  2. !!x

undefined 和 null

【问】这两种都代表空类型,为什么有两个空?
【答】undefined表示未定义,它的值只有undefined。而null表示已定义但是为空,值同样只有一个null

一般情况下:

  • 这两个类型没有本质区别。
  • 任何一个声明变量后,在没赋值前,值都为undefined。
  • 一个函数,如果没有写return,那么默认return undefined,而不是null。
  • 前端习惯上,把非对象的空值写为undefined,把对象的空值写为null。当然这个习惯可以打破。

【问】为什么有的编程规范要求用void 0代替undefined
【补充】void运算可以把任意一个表达式变成undefined,void 0undefined是等价的,即使这两个相互判断也为true。
【答】因为undefined不是关键字(null是关键字),而是一个变量(设计失误),为了避免被篡改,而选择使用void 0

因为变量在没赋值之前的值为undefined,所以在编写代码的时候,不会赋值undefined而是赋值null,这样就保证在整个项目里的nudefined不是赋值的。

Symbol

作用是可以生成全局唯一的值。不支持new方法。

在规范里,对象的属性键除了是字符串外,还可以是Symbol,只有这两种类型。

具体创建及使用如下:

  1. let id = Symbol();

或者添加描述:

  1. let id = Symbol('id')
  2. //里面的描述“id”相当与是注释,与Symbol本身作用没什么关系,但方便调试。

保证全局唯一,即使里面的描述是一样的,Symbol的值也是不一样的。例如:

  1. let id1 = Symbol("id")
  2. let id2 = Symbol("id")
  3. console.log(id1 === id2) //false

使用场景1:“隐藏”对象属性

如下:

  1. let id = Symbol("id")
  2. let user = {
  3. name: "John",
  4. [id]: 123 // 而不是 "id":123
  5. };

对象里面的[id],不会被for...in..遍历到。并且也不会被别的脚本直接访问到,因为另一个脚本没有这个脚本的Symbol。因此,该属性将受到保护,防止被意外修改或重写。

JSON.stringify也会直接忽略Symbol。

但是,也不是100%隐藏,可以使用 Object.getOwnPropertySymbols(obj),允许获取所有的Symbol。还有个可以返回一个对象的所有键Reflect.ownKeys(obj)

使用场景2:系统Symbol

JS有许多系统Symbol,可以使用Symbol.*来访问使用。例如:

  • Symbol.iterator
  • Symbol.toPrimitive
  • 等。。。