JavaScript - Type
基本类型
JavaScript 的每一个
值
都属于某一种数据类型
Undefined
Null
- Boolean
- String
- Number
Symbol
– ES6Object
Undefined + Null
Undefined
编程规范:使用
void 0
代替undefined
- Undefined 代表
未定义
,只有一个值undefined
undefined
为全局变量
,但并非关键字
– 语言设计缺陷
- 任何变量在
赋值前
的类型为是Undefined
,值为undefined
void
运算可以将任意表达式
变成undefined
值
1 | console.log(void 0 === undefined) // true |
Null
Null 代表
定义了但为空
,只有一个值null
,null 是关键字
Boolean
Boolean 只有两个值,
true
和false
,且均为关键字
String
Unicode + UTF
- Unicode 为
字符集
,每一个 Unicode 码点表示一个字符U+???
- 基本字符区域(BMP):
U+0000 ~ U+FFFF
- UTF 为 Unicode 的
编码方式
:规定码点在计算机中的表示方式
,常见为UTF-8
和UTF-16
String
- String 的最大长度为
2^53-1
(编码
长度) - String 为
值类型
,永远无法变更
- String 把每个
UTF-16
单元当作一个字符
来处理 –From Java
Number
对应数学中的
有理数
,但在计算机中,有一定的精度限制
NaN
:占用特定数字Infinity
:无穷大;-Infinity
:负无穷大1/0
==>Infinity
1/-0
==>-Infinity
- 浮点数存在
精度误差
1 | console.log(0.1 + 0.2 == 0.3) // false |
Symbol
ES6 引入,是一切
非字符串的对象Key的集合
,整个对象系统
被 Symbol 重塑
Symbol()
函数前不能使用new
,因为生成的 Symbol 是一个原始类型的值,不是对象
Symbol
值不是对象,所以也不能添加属性,类似于字符串的值类型
1 | let a1 = Symbol('A'); |
样例:使用
Symbol.iterator
来定义for...of
在对象
上的行为
1 | let o = {} |
如果
Symbol
的参数是一个对象
,会调用该对象的toString()
方法,将其转换为字符串,然后生成一个 Symbol 值
1 | const obj = { |
Symbol()
函数的参数只是表示对当前 Symbol 值的描述
,相同参数的 Symbol 函数的返回值是不相等
的
1 | let s1 = Symbol(); |
Symbol 不能与其他类型的值进行运算
1 | let s = Symbol(); |
Symbol 可以显式转成
字符串
1 | let s = Symbol('A'); |
Symbol 可以转成
布尔值
1 | let s = Symbol('A'); |
Object
对象的定义为
属性的集合
,属性分为数据属性
和访问器属性
,都是KV
结构,Key
可以为String
或者Symbol
JavaScript 是
无法自定义类型
的,『类』
仅仅只是运行时对象
的一个私有属性
Number
、String
和Boolean
,这三个构造器
是两用的
- 与
new
搭配:产生对象
直接调用
:表示强制类型转换
1 | console.log(typeof 3) // number |
Symbol 如果与 new 搭配,会直接报错
1 | // console.log(typeof new Symbol('A')) // Uncaught TypeError: Symbol is not a constructor |
JavaScript 试图模糊
对象
和基本类型
之间的关系:可以在基本类型上使用对象的方法
-装箱转换
1 | let s = 'abc' |
可以在原型上添加方法,并应用于基本类型
1 | Symbol.prototype.hello = () => console.log('hello js') |
根因:
.
运算符提供了装箱
操作,会根据基础类型
构造一个临时对象
,使得能在基础类型上调用对应对象的方法
类型转换
JavaScript 为
弱类型动态语言
,发生类型转换
非常频繁
==
语言设计缺陷:试图实现
跨类型
的比较,规则非常复杂
最佳实践:进行
显式
地类型转换
后,再使用===
进行比较
StringToNumber
大多数情况下,
Number
是比parseInt
和parseFloat
更好的选择
1 | // 十进制、二进制、八进制、十六进制 |
parseInt
默认只支持16 进制
,且会忽略非数字字符
,也不支持科学计数法
1 | console.log(parseInt('0xFF')) // 255 |
parseFloat
直接把字符串作为十进制
来解析,不会引入其它进制
1 | console.log(parseFloat('123.45')) // 123.45 |
NumberToString
当 Number 的绝对值较大或者较小的时候,将使用
科学计数法
表示(保证产生的字符串不会过长
)
1 | console.log(String(1e256)) // 1e+256 |
装箱转换
- 每一种基本类型
Number
、String
、Boolean
、Symbol
在对象中都有对应的类
- 装箱转换:将
基本类型
转换为对应的对象
装箱机制
会频繁产生临时对象
,在高性能场景,应该尽量避免对基本类型
做装箱转换
Symbol
1 | let s = (function () { |
通过内置的
Object
函数,可以显式调用装箱能力
1 | let o = Object(Symbol('A')) |
每一类
装箱对象
都有私有的Class
属性,可以通过Object.prototype.toString
来获取
在 JavaScript 中,无法更改私有的 Class 属性
,比instanceof
本身更准确
call
本身会产生装箱操作
,需要配合typeof
来区分基本类型
还是对象类型
1 | let o = Object(Symbol('A')) |
拆箱转换
ToPrimitive
:对象类型 -> 基础类型
对象
到String
和Number
的转换:先拆箱再转换
(对象 -> 基本类型 -> String/Number)
拆箱转换会尝试调用
valueOf
和toString
来获得拆箱后的基本类型
如果valueOf
和toString
都不存在,或者没有返回基本类型
,会产生类型错误TypeError
valueOf -> toString
1 | let o = { |
toString -> valueOf
1 | let o = { |
在 ES6 之后,允许对象通过显式指定
@@toPrimitive Symbol
来覆盖
原有的拆箱行为
1 | let o = { |
typeof
同样为
语言的设计缺陷
:typeof 的运算结果,与运行时数据类型
有较多不一致
的地方
示例表达式 | typeof 结果 | 运行时类型 |
---|---|---|
null |
object |
Null |
(function(){}) |
function |
Object |
void 0 |
undefined |
Undefined |
Symbol("A") |
symbol |
Symbol |
{} | object | Object |
3 | number | Number |
“ok” | string | String |
true | boolean | Boolean |