概述
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 后面接该数值就可以了,如
typeof 123 // "number"typeof '123' // "string"typeof false // "boolean"
数值(number)
写法
- 整数:1
- 小数:0.1
- 科学计数法:1.23e4
- 八进制(比较少用):0123 or 00123 or 0o123
- 十六进制写法:0x3F or 0X3F
- 二进制写法:0b11 or 0B11
还可以进行类型转换,number => string
String(n)n + ''
特殊值
正零和负零
//0分正零(+1)和负零(-1),但是这两个零都等于0,大部分情况下是一样的:-0 === +0 //true0 === -0 //true0 === +0 //true//除了这情况:1/+0 等于 +Infinity1/-0 等于 -Infinity-Infinity === +Infinity //false
整数和浮点数
JavaScript其实是没有整数的,因为在JS中,所有数字都是以64位浮点数形式存储,也就是说,1和1.0其实是一样的。
1 === 1.0 //true
注意,浮点数不是精确的值,所有涉及到的浮点数运算和比较都需要注意,如
0.1 + 0.2 === 0.3 //false0.3 / 0.1 // 2.9999999999999996
如果想要正确的比较方法,需要如下:
console.log( Math.abs(0.1 + 0.2 - 0.3) <= Number.EPSILON ) //true
NaN(不是一个数)
表示“非数字”(Not a Number),实验可以得出 NaN 的有:
0/0 //NaN
更神奇的是, NaN 虽然表示不是一个数,但 NaN 确实属于数值:
typeof NaN // NaN
在运算方面,任何跟 NaN 运算的数值,都等于 NaN ,并且 NaN 不等于 NaN ,想想都知道:
NaN + 32 // NaNNaN - 32 // NaNNaN * 32 // NaNNaN / 32 // NaN0 * Infinity // NaNInfinity - Infinity // NaNInfinity / Infinity // NaN//并且 NaN 不等于 NaNNaN === NaN // false
数值范围
根据标准,64位浮点数的指数部分的长度是11个二进制位,意味着指数部分的最大值是2047(2的11次方减1)。 也就是说,64位浮点数的指数部分的值最大为2047,分出一半表示负数,则 JavaScript 能够表示的数值范围为21024到2-1023(开区间),超出这个范围的数无法表示(即+Infinity或-Infinity)。
—-网道JavaScript
Number.MAX_VALUE // 1.7976931348623157e+308 表示最大值是多少Number.MIN_VALUE // 5e-324 表示最小值是多少
字符串(string)
类型转换:string => number
Number(s)parseInt(s)/parseFloat(s)s - 0
其他类型转字符串:x => string
String(x)x.toString()
写法
- 单引号 ‘你好’
- 双引号 “你好”
- 反引号
你好
注意:引号不属于字符串的一部分,就好像书名号不属于书名一样。
转义
可以用单引号括双引号,双引号括单引号,但是不可以括相同的引号:
"我想说:'你好!'" //合法'我想说:"你好!"' //合法`我想说:'你好!'` //合法`我想说:"你好!"` //合法"我想说:"你好!"" //错误的写法,单引号同理
可我就是要一样怎么办?
可以选择用转义的方法:
"我想说:\"你好!\"" //在想要包括在括号里面的字符的前面加一个反斜杠即可。'it\'s OK'
转义有很多用途,如
//字符串默认只能写一行,不可以多行,以下是属于不合法的字符串:'abc'//但我就是想要多行怎么办?可以用转义的方式:'a\b\c'//或者用反引号`abc`//'a b c'写代码时虽然是多行,但输出的时候还是一行。
除了这个方式,还有很多特殊用途:
\0:null(\u0000)\n:换行符(\u000A)\r:回车键(\u000D)\t:制表符(\u0009)\':单引号(\u0027)\":双引号(\u0022)\\:反斜杠(\u005C)\uFFFF表示对应的Unicode字符\xFF表示前256个Unicode字符
字符串与数组
字符串可以被视为字符数组,因此可以使用数组的方括号运算符,用来返回某个位置的字符(位置编号从0开始)。
var s = 'hello';s[0] // "h"s[1] // "e"s[4] // "o"// 直接对字符串使用方括号运算符'hello'[1] // "e"
而且不可以单个字符更改或删除,浏览器不会报错但默默的失败
var s = 'hello';delete s[0];s // "hello"s[1] = 'a';s // "hello"
【问】字符串有最大长度吗?
【答】有,长度为2^53 - 1,但这个长度不是字符数!
实际上字符是以Unicode的方式表示,而一个Unicode的码点表示一个字符,常见的编码有 UTF8 和 UTF16 。在JS中,字符串并不是意义上的 String,而是编码 UTF16,字符串的操作 charAt、charCodeAt、length等方法都是针对UTF16编码。所以说,字符串长度取决于编码长度。
布尔(boolean)
只有 true 和 false 两个值,注意大小写。
通过比较、运算就可以得出布尔值。通常需要配合判断真假语句 if(value){...}else{...} 。
问题来了,value如果不是比较和运算得出来的bool值怎么办?这时候就可以通过该value是否是falsy值了。
falsy值是什么东西?
falsy就相当于false但又不是false的值,分别是:
undefinednullfalse0NaN""或''(空字符串,里面如果有空格就不是空字符串了," "和' ')
除了falsy值,其他的均为true!
类型转换:x => bool
Boolean(x)!!x
undefined 和 null
【问】这两种都代表空类型,为什么有两个空?
【答】undefined表示未定义,它的值只有undefined。而null表示已定义但是为空,值同样只有一个null 。
一般情况下:
- 这两个类型没有本质区别。
- 任何一个声明变量后,在没赋值前,值都为undefined。
- 一个函数,如果没有写return,那么默认return undefined,而不是null。
- 前端习惯上,把非对象的空值写为undefined,把对象的空值写为null。当然这个习惯可以打破。
【问】为什么有的编程规范要求用void 0代替undefined?
【补充】void运算可以把任意一个表达式变成undefined,void 0与undefined是等价的,即使这两个相互判断也为true。
【答】因为undefined不是关键字(null是关键字),而是一个变量(设计失误),为了避免被篡改,而选择使用void 0。
因为变量在没赋值之前的值为undefined,所以在编写代码的时候,不会赋值undefined而是赋值null,这样就保证在整个项目里的nudefined不是赋值的。
Symbol
作用是可以生成全局唯一的值。不支持new方法。
在规范里,对象的属性键除了是字符串外,还可以是Symbol,只有这两种类型。
具体创建及使用如下:
let id = Symbol();
或者添加描述:
let id = Symbol('id')//里面的描述“id”相当与是注释,与Symbol本身作用没什么关系,但方便调试。
保证全局唯一,即使里面的描述是一样的,Symbol的值也是不一样的。例如:
let id1 = Symbol("id")let id2 = Symbol("id")console.log(id1 === id2) //false
使用场景1:“隐藏”对象属性
如下:
let id = Symbol("id")let user = {name: "John",[id]: 123 // 而不是 "id":123};
对象里面的[id],不会被for...in..遍历到。并且也不会被别的脚本直接访问到,因为另一个脚本没有这个脚本的Symbol。因此,该属性将受到保护,防止被意外修改或重写。
JSON.stringify也会直接忽略Symbol。
但是,也不是100%隐藏,可以使用 Object.getOwnPropertySymbols(obj),允许获取所有的Symbol。还有个可以返回一个对象的所有键Reflect.ownKeys(obj)。
使用场景2:系统Symbol
JS有许多系统Symbol,可以使用Symbol.*来访问使用。例如:
- Symbol.iterator
- Symbol.toPrimitive
- 等。。。
