基本引用类型

引用值(或者对象)是某个特定引用类型的实例

Date

Date 对象基于 Unix Time Stamp,即自 1970 年 1 月 1 日(UTC)起经过的毫秒数

new Date(); // 实例化时刻的日期和时间
new Date(value); // value 表示 1970 年 1 月 1 日(UTC)起经过的毫秒数
new Date(dateString); // dateString 表示日期字符串,该字符串应该能被 Date.parse() 正确方法识别
new Date(year, monthIndex [, day [, hours [, minutes [, seconds [, milliseconds]]]]]);
  • Date.now(),返回自 1970-1-1 00:00:00 UTC(世界标准时间)至今所经过的毫秒数
  • Date.parse(),接收一个表示日期的字符串参数,然后尝试根据这个字符串返回相应日期的毫秒数
  • Date.UTC(),接收年份、基于 0 的月份(一月是 0,二月是 1,以此类推)、月中的哪一天(1 到 31)、小时数(0 到 23)、分钟、秒以及毫秒数,返回表示这个日期的毫秒数

继承的方法

  • toLocaleString(),返回与浏览器运行的本地环境相适应的日期和时间
  • toString(),返回带有时区信息的日期和时间
  • valueOf(),返回日期的毫秒表示,故操作符(如 <)可以直接使用它返回的值

日期格式化方法

Date 类型有几个专门用于格式化日期的方法,它们都会返回字符串

  • toDateString(),以特定于实现的格式显示星期几、月、日和年
  • toTimeString(),以特定于实现的格式显示时、分、秒和时区
  • toLocaleDateString(),以特定于实现和地区的格式显示星期几、月、日和年
  • toLocaleTimeString(),以特定于实现和地区的格式显示时、分、秒
  • toUTCString(),以特定于实现的格式完整的 UTC 日期

这些方法的输出与 toLocaleString() 和 toString() 一样,会因浏览器而异,因此不能用于在用户界面上一致的显示日期

日期/时间组件方法open in new window

RegExp

let expression = /pattern/flags;

实例属性open in new window

实例方法open in new window

静态属性open in new window

原始值包装类型

每当用到某个原始值的方法或属性时,后台都会创建一个相应原始包装类型的对象,从而暴露出操作原始值的各种方法

引用类型与原始包装类型的主要区别在于对象的生命周期。在通过 new 实例化引用类型后,得到的实例会在离开作用域时被销毁,而自动创建的原始值包装对象则只存在于访问它的那行代码执行期间。这意味着不能在运行时给原始值添加属性和方法,比如:

let name = 'Nicholas'
name.age = 27
console.log(name.age) // undefined

可以显示地使用 Boolean、Number 和 String 创建原始值包装对象,实例上调用 typeof 会返回 object

原始值和包装对象之间的区别:

  • typeof 操作符对包装对象返回 'object'
  • 包装对象在使用 instanceof 操作符时返回 true,而原始值则不是

Boolean

要创建一个 Boolean 对象,就使用 Boolean 构造函数并传入 true 或 false

let booleanObject = new Boolean(true)
  • valueOf(),返回原始值 true 或 false
  • toString(),返回字符串 'true' 或 'false'

Number

要创建一个 Number 对象,就使用 Number 构造函数并传入数值

let numberObject = new Number(10)

继承的方法:

  • valueOf(),返回原始值
  • toString() / toLocaleString(),返回字符串形式的数值
let num = 10
console.log(num.toString()) // '10'
console.log(num.toString(2)) // '1010'
console.log(num.toString(8)) // '12'
console.log(num.toString(10)) // '10'
console.log(num.toString(16)) // 'a'

格式化数值:

  • toFixed(),按指定的小数位返回数值的字符串表示
  • toExponential(),按指定的小数位返回数值的字符串表示,以科学计数法表示
  • toPrecision(),按指定的有效数位返回数值的字符串表示

isInteger() 方法与安全整数:

  • Number.isInteger(),判断数值是否为整数
    console.log(Number.isInteger(1)) // true
    console.log(Number.isInteger(1.0)) // true
    console.log(Number.isInteger(1.1)) // false
    
  • Number.isSafeInteger(),判断数值是否为安全整数
    console.log(Number.isSafeInteger(Number.MAX_SAFE_INTEGER)) // true
    console.log(Number.isSafeInteger(Number.MAX_SAFE_INTEGER + 1)) // false
    

String

要创建一个 String 对象,就使用 String 构造函数并传入字符串

let stringObject = new String('hello world')

继承的方法:

  • valueOf() / toLocaleString() / toString(),返回原始字符串值

1. JavaScript 字符串

JavaScript 字符串由 16 位码元(code unit)组成。对于大多数字符,每个码元对应一个字符

  • length 属性表示字符串中码元的个数
  • charAt() 方法返回指定位置的码元,如果没有指定位置,则默认为 0
  • charCodeAt() 方法返回指定位置的码元的数值,如果没有指定位置,则默认为 0
  • fromCharCode() 方法接收一或多个码元值,然后将它们转换成字符串

对于 U+0000~U+FFFF 范围内的字符,上面的属性和方法返回的结果都跟预期是一样的

16 位只能唯一表示 2^16 个字符,这对于大多数语言字符集是足够了,在 Unicode 中称为基本多语言平面(BMP)

为了表示更多的字符,Unicode 采用了一个策略,即每个字符使用另外 16 位去选择一个增补平面。这种每个字符使用两个 16 位码元的策略称为代理对(surrogate pair)

在涉及增补平面的字符时,前面讨论的字符串方法和属性就会出问题

// "smiling face with smiling eyes" 表情符号的码点是 U+1F60A
// 0x1F60A === 128522
let message = 'ab😊de'
console.log(message.length) // 6
console.log(message.charAt(1)) // 'b'
console.log(message.charAt(2)) // '�'
console.log(message.charAt(3)) // '�'
console.log(message.charAt(4)) // 'd'

console.log(message.charCodeAt(1)) // 98
console.log(message.charCodeAt(2)) // 55357
console.log(message.charCodeAt(3)) // 56842
console.log(message.charCodeAt(4)) // 100

console.log(String.fromCharCode(0x1f60a)) // '�'
console.log(String.fromCodePoint(0x1f60a)) // '😊'
console.log(String.fromCharCode(97, 98, 55357, 56842, 100, 101)) // 'ab😊de'

码点是 Unicode 中一个字符的完整标识

迭代字符串可以智能地识别代理对的码点:

console.log([...'ab😊de']) // ['a', 'b', '😊', 'd', 'e']
  • codePointAt() 方法返回指定位置的码点,如果传入的码元索引并非代理对的开头,就会返回错误的码点
  • fromCodePoint() 方法接收一个或多个码点,然后将它们转换成字符串

2. normalize() 方法

某些 Unicode 字符可以有多种编码方式,多种形式间使用 === 的结果为 false。为解决这个问题,ES6 提供了 normalize() 方法,用于将字符的不同表示方法统一为同样的形式,使用时需要传入表示哪种形式的字符串:"NFC"、"NFD"、"NFKC"、"NFKD"

3. 字符串操作方法

  • concat(),拼接字符串
  • 从字符串中提取子字符串,省略第二个参数即提取到末尾
    • slice(),接收两个参数,返回从第一个参数指定位置开始到第二个参数指定位置结束的子字符串。将所有负值参数都当成字符串长度加上负值参数
    • substr(),接收两个参数,返回从第一个参数指定位置开始到第二个参数指定的长度结束的子字符串。第二个负值参数会被转换为 0
    • substring(),与 slice() 类似,但所有负值参数值都会转换为 0

4. 字符串位置方法

  • 从字符串中搜索传入的字符串,并返回位置(如果没找到则返回 -1)。可以接收第二个参数,表示开始搜素的位置
    • indexOf(),从开头开始查找子字符串
    • lastIndexOf(),从末尾开始查找子字符串

5. 字符串包含方法

  • 判断字符串中是否包含另一个字符串,从字符串中搜索传入的字符串,并返回一个是否包含的布尔值
    • startsWith()
      • 判断字符串是否以另一个字符串开头,检查开始于索引 0 的匹配项
      • 接收第二个参数,表示开始搜素的位置
    • endsWith()
      • 判断字符串是否以另一个字符串结尾,检查开始于索引 length - searchStr.length 的匹配项
      • 接收第二个参数,表示应该当作字符串末尾的位置(正则 $ 匹配的位置)
    • includes()
      • 判断字符串是否包含另一个字符串,检查整个字符串
      • 接收第二个参数,表示开始搜素的位置

6. trim() 方法

去除字符串两端的空格,返回新字符串

trimLeft() / trimRight(),去除字符串左边 / 右边的空格,返回新字符串

7. repeat() 方法

接收一个整数参数,表示将原字符串重复多少次,返回新字符串

8. padStart() / padEnd() 方法

两个方法会复制字符串,如果小于指定长度,则在相应一边填充字符,直至满足长度条件

第一个参数是长度,第二个参数是可选的填充字符,默认为空格

9. 字符串迭代与解构

字符串的原型上暴露了一个 @@iterator 方法,表示可迭代字符串中的每个字符

手动使用迭代器:

let message = 'ab😊de'
let iterator = message[Symbol.iterator]()
console.log(iterator.next()) // { value: 'a', done: false }
console.log(iterator.next()) // { value: 'b', done: false }
console.log(iterator.next()) // { value: '😊', done: false }
console.log(iterator.next()) // { value: 'd', done: false }
console.log(iterator.next()) // { value: 'e', done: false }
console.log(iterator.next()) // { value: undefined, done: true }

在 for-of 循环中可以通过这个迭代器按序访问每个字符:

let message = 'ab😊de'
for (let c of message) {
	console.log(c)
}
// 'a'
// 'b'
// '😊'
// 'd'
// 'e'

字符串也可以通过解构赋值的方式进行迭代:

let message = 'ab😊de'
let [a, b, c, d, e] = message
console.log(a, b, c, d, e) // 'a' 'b' '😊' 'd' 'e'

10. 字符串大小写转换

如果不知道代码涉及什么语言,则最好使用地区特定的转换方法

  • toLowerCase(),将字符串转换为小写形式
  • toUpperCase(),将字符串转换为大写形式
  • toLocaleLowerCase(),将字符串转换为小写形式,基于特定地区实现
  • toLocaleUpperCase(),将字符串转换为大写形式,基于特定地区实现

11. 字符串模式匹配方法

String 类型专门为在字符串中实现模式匹配设计了几个方法

  • match(),本质跟 RegExp 的 exec() 方法相同
  • search(),返回模式第一个匹配的位置索引,如果没有找到则返回 -1
  • replace()

12. localeCompare() 方法

因为返回的具体值可能因具体实现而异,所以最好像这样使用:

function determineOrder(value) {
	let result = str1.localeCompare(value)
	if (result < 0) {
		console.log('str1 comes before ' + value)
	} else if (result > 0) {
		console.log('str1 comes after ' + value)
	} else {
		console.log('str1 is equal to ' + value)
	}
}

localeCompare() 的独特之处在于,实现所在的地区(国家和语言)决定了这个方法如何比较字符串

单例内置对象

ECMA-262 对内置对象的定义是“任何由 ECMAScript 实现提供、与宿主环境无关,并在 ECMAScript 程序开始执行时就存在的对象”,如前面接触的 Object、Array、String、Function、Date、RegExp、Error、Boolean、Number,包括接下来介绍的两个单例内置对象 Math、Global

Global

ECMA-262 规定 Global 对象为一种兜底对象,它所针对的是不属于任何对象的属性和方法。在全局作用域中定义的变量和函数都会变成 Global 对象的属性。isNaN()、isFinite()、parseInt() 和 parseFloat() 都是 Global 对象的方法,除了这些 ECMAScript 还为 Global 对象定义了其他方法

1. URL 编码方法

有效的 URI 不能包含某些字符,比如空格。使用 URI 编码方法可以让浏览器理解它们,同时又以特殊的 UTF-8 编码替换所有无效字符,比如空格会被替换成 %20

encodeURI()、encodeURIComponent()、decodeURI()、decodeURIComponent(),用于对 统一资源标识符(URI)进行编码和解码

  • encodeURI(),主要用于整个 URI,不会对本身属于 URI 的特殊字符进行编码,比如冒号、正斜杠、问号和井号
  • encodeURIComponent(),主要用于对 URI 中的某一段进行编码,会对它发现的任何非标准字符进行编码

2. eval() 方法

这个方法就是一个完整的 ECMAScript 解释器,它接收一个参数,即要执行的 ECMAScript(或 JavaScript)字符串

eval('console.log("hi")') // 'hi'

3. Global 对象的属性

  • undefined、NaN、Infinity 等特殊值
  • 原生引用类型构造函数,比如 Object、Array、String 等

4. window 对象

虽然 ECMA-262 没有规定直接访问 Global 对象的方式,但浏览器将 window 对象实现为 Global 对象的代理

另一种获取 Global 对象的方式:

var global = (function () {
	return this
})()

Math

ECMAScript 提供了 Math 对象作为保存数学公式、信息和计算的地方。Math 对象提供了一些辅助计算的属性和方法

1. Math 对象属性

  • Math.E,自然对数的底数,即常量 e 的值
  • Math.LN10,10 为底的自然对数
  • Math.LN2,2 为底的自然对数
  • Math.LOG2E,以 2 为底 e 的对数
  • Math.LOG10E,以 10 为底 e 的对数
  • Math.PI,π 的值
  • Math.SQRT1_2,1/2 的平方根
  • Math.SQRT2,2 的平方根

2. min() 和 max() 方法

接收任意多个参数

3. 舍入方法

  • Math.ceil(),向上取整
  • Math.floor(),向下取整
  • Math.floor(),四舍五入
  • Math.fround(),返回最接近参数的 32 位单精度浮点值表示

4. random 方法

返回大于等于 0 小于 1 的一个随机数

可以基于如下公式使用 Math.random() 从一组整数中随机选择一个整数:

Math.floor(Math.random() * 可能值的总数 + 第一个可能的值)

5. 其他方法

Math 的方法open in new window

Last Updated: