
JavaScript 的类型系统
当前 ECMAScript 标准定义了 8 种数据类型,包括 7 个原始(primary)类型,还有一个是对象类型。
Null 和 Undefined 类型
据说在最初设计 JavaScript 时,像 Java 一样,只设置了 null 表示“无”。根据 C 语言的传统,null 可以自动转为 0。
但是,JavaScript 的设计者 Brendan Eich,觉得这样做还不够。首先,Brendan Eich 觉得表示“无”的值最好不是对象。其次,那时的 JavaScript 不包括错误处理机制,Brendan Eich 觉得,如果 null 自动转为 0,很不容易发现错误。
因此,他又设计了一个 undefined。区别是这样的:null 是一个表示“空”的对象,转为数值时为 0;undefined 是一个表示"此处无定义"的原始值,转为数值时为 NaN。
Number 类型
存储结构
在 JavaScript 内部,所有数字都是以 64 位浮点数形式储存,即使整数也是如此。
因此 1 与 1.0 是相同的,是同一个数
字面量
数值字面量支持十进制、八进制、十六进制以及科学计数法。
前缀 0 表示八进制,处理时很容易造成混乱。ES5 的严格模式和 ES6,已经废除了这种表示法。
特殊数值
NaN
NaN 表示“非数字”(not a number),主要用在将字符串解析成数值出错等场合。
Infinity
Infinity 表示“无穷”,用来表示两种场景。一种是一个正的数值太大,或一个负的数值太小,无法表示;另一种是非 0 数值除以 0,得到 Infinity。
Infinity 有正负之分,Infinity 表示正的无穷,-Infinity 表示负的无穷。
Bigint 类型
JavaScript 所有数字都保存成 64 位浮点数,这给数值的表示带来了两大限制。一是数值的精度只能到 53 个二进制位(相当于 16 个十进制位),大于这个范围的整数,JavaScript 是无法精确表示的,这使得 JavaScript 不适合进行科学和金融方面的精确计算。二是大于或等于 2 的 1024 次方的数值,JavaScript 无法表示,会返回 Infinity。
ES2020 引入了一种新的数据类型 BigInt(大整数),来解决这个问题,这是 ECMAScript 的第八种数据类型。BigInt 只用来表示整数,没有位数的限制,任何位数的整数都可以精确表示。
为了与 Number 类型区别,BigInt 类型的数据必须添加后缀 n。
String 类型
字符串是包含零个或多个字符的序列。
字面量
模板字符串
使用 + 号可以将多个字符串拼接起来。但是如果有很多变量时,使用 + 就比较麻烦了。
因此,ES6 引入了模板字符串。模板字符串(template string)是增强版的字符串,用反引号(`)标识,可以使用 ${} 嵌入变量或表达式。
转义
对于那些有特殊含义的字符(比如单引号)或者没有字符实体(比如换行符)的字符,可以采用下面两种方法来表示:
- 转义符(反斜杠)+ 普通字符
- 转义符 + Unicode 码点
转义符 + Unicode 码点的形式同样可以表示其他普通字符。
另外,Unicode 码点也可以使用三位八进制(000 到 377)或者两位十六进制(00 到 FF)表示。但这两种方法只能表示 256 个字符。
字符串与数组
字符串可以被视为字符数组,因此可以使用数组的方括号运算符,用来返回某个位置的字符(位置编号从 0 开始)。但是,无法改变或者删除字符串内的单个字符。
字符串长度
length 属性返回字符串的长度,该属性也是无法改变的。
字符集
JavaScript 使用 Unicode 字符集。每个字符在 JavaScript 内部都是以 16 位(即 2 个字节)的 UTF-16 格式储存。
Symbol 类型
ES5 的对象属性名都是字符串,这容易造成属性名的冲突。比如,你使用了一个他人提供的对象,但又想为这个对象添加新的方法,新方法的名字就有可能与现有方法产生冲突。为了从根本上防止属性名的冲突,ES6 引入了 Symbol 类型。
Symbol 类型是一种新的原始数据类型,它表示独一无二的值。Symbol 值可以用作对象的属性名
Symbol 值通过 Symbol 函数生成。该值不是对象,因此 Symbol 函数前不能使用 new 命令,否则会报错。
Symbol 函数可以接受一个字符串作为参数,表示对 Symbol 实例的描述,主要是为了在控制台显示,或者转为字符串时,比较容易区分。该参数可以是原始类型,也可以是对象,并且不会对 Symbol 值产生影响。
Symbol 值可以显式转为字符串或者布尔值:
Symbol 值作为对象属性名时,不能用点运算符,只能使用方括号。
Object 类型
简单的说,在 JavaScript 中对象就是一组属性(property)的集合。
属性包含属性名(key)和属性值(value)以及属性的一些特征(比如:属性是否可被修改、属性是否可被遍历等)组成。
对象字面量
对象的字面量由一组键值对和 {} 构成,其中键和值之间由冒号(:)分隔。
对象的所有键名都是字符串(ES6 又引入了 Symbol 值也可以作为键名),所以加不加引号都可以。如果键名是数值,会被自动转为字符串。
构造函数
JavaScript 语言使用构造函数(constructor)作为对象的模板,通过 new 命令执行构造函数来生成实例对象。比如:Object 就是一个构造函数。
Class(类)
ES6 引入了 Class(类)这个概念,作为对象的模板,通过 class 关键字,可以定义类。
对象的分类
ECMAScript 规范明确定义了各种对象的类别,包括:
- 常规对象(ordinary object)拥有 JavaScript 对象所有的默认行为。
- 特异对象(exotic object)的某些内部行为和默认的有所差异。
- 标准对象(standard object)是 ECMAScript 6 中定义的对象,例如 Array, Date 等,它们既可能是常规也可能是特异对象。
- 内置对象(built-in object)指 JavaScript 执行环境开始运行时已存在的对象。标准对象均为内置对象。
数据类型判断
使用 typeof 运算符可以判断一个值的数据类型。
null 的类型是 object,这是由于历史原因造成的。1995 年的 JavaScript 语言第一版,只设计了五种数据类型(对象、整数、浮点数、字符串和布尔值),没考虑 null,只把它当作 object 的一种特殊值。后来 null 独立出来,作为一种单独的数据类型,为了兼容以前的代码,typeof null 返回 object 就没法改变了。
相关资料
《JavaScript 语言精髓与编程实践》
JavaScript 全栈教程
JavaScript 教程
ES6 入门教程
Understanding ECMAScript 6(简体中文版)
ECMAScript® 2020 Language Specification
作者:lingyundu
