5.1 前言
引用值(或者对象)是某个特定引用类型的实例,有时候也被称为对象定义,因为它们描述了自己的对象应有的属性和方法。
对象被认为是某个特定引用类型的实例。新对象通过使用 new 操作符后跟一个构造函数(constructor)来创建。
函数也是一种引用类型
5.2 MIND
5.3 Date
Date 类型将日期保存为自协调世界时(UTC,Universal Time Coordinated)时间 1970 年 1 月 1 日午夜(零时)至今所经过的毫秒数。使用这种存储格式,Date 类型可以精确表示 1970 年 1 月 1 日之前及之后 285 616 年的日期。
ECMAScript 在创建日期对象时,不给 Date 构造函数传参数的情况下,创建的对象将保存当前日期和时间。传参的情况下,提供了两个辅助方法(Date.parse() 和 Date.UTC())来创建基于其他日期和时间的日期对象。
5.3.1 继承的方法
与其他类型一样,Date 类型重写了 toLocaleString()、toString() 和 valueOf() 方法。
- toLocaleString() 方法返回与浏览器运行的本地环境一致的日期和时间。
- toString() 方法通常返回带时区信息的日期和时间,而时间也是以 24 小时制(0~23)表示的。
- valueOf() 方法根本就不返回字符串,而是日期的毫秒数值。
5.3.2 日期格式化方法
- toDateString():显示日期中的周几、月、日、年
- toTimeString():显示日期中的时、分、秒和时区
- toLocaleDateString():显示日期中的周几、月、日、年(本地)
- toLocaleTimeString():显示日期中的时、分、秒(本地)
- toUTCString():显示完整的 UTC 日期
还有一个方法叫 toGMTString(),跟 toUTCString() 一样的为了向后兼容(规范建议新代码使用 toUTCString())
5.3.2 日期 / 时间组件方法
| 方法 | 说明 |
|---|---|
| getTime() | 返回日期的毫秒表示;与 valueOf()相同 |
| setTime(milliseconds) | 设置日期的毫秒表示,从而修改整个日期 |
| getFullYear() | 返回 4 位数年(即 2019 而不是 19) |
| getUTCFullYear() | 返回 UTC 日期的 4 位数年 |
| setFullYear(year) | 设置日期的年(year 必须是 4 位数) |
| setUTCFullYear(year) | 设置 UTC 日期的年(year 必须是 4 位数) |
| getMonth() | 返回日期的月(0 表示 1 月,11 表示 12 月) |
| getUTCMonth() | 返回 UTC 日期的月(0 表示 1 月,11 表示 12 月) |
| setMonth(month) | 设置日期的月(month 为大于 0 的数值,大于 11 加年) |
| setUTCMonth(month) | 设置 UTC 日期的月(month 为大于 0 的数值,大于 11 加年) |
| getDate() | 返回日期中的日(1~31) |
| getUTCDate() | 返回 UTC 日期中的日(1~31) |
| setDate(date) | 设置日期中的日(如果 date 大于该月天数,则加月) |
| setUTCDate(date) | 设置 UTC 日期中的日(如果 date 大于该月天数,则加月) |
| getDay() | 返回日期中表示周几的数值(0 表示周日,6 表示周六) |
| getUTCDay() | 返回 UTC 日期中表示周几的数值(0 表示周日,6 表示周六) |
| getHours() | 返回日期中的时(0~23) |
| getUTCHours() | 返回 UTC 日期中的时(0~23) |
| setHours(hours) | 设置日期中的时(如果 hours 大于 23,则加日) |
| setUTCHours(hours) | 设置 UTC 日期中的时(如果 hours 大于 23,则加日) |
| getMinutes() | 返回日期中的分(0~59) |
| getUTCMinutes() | 返回 UTC 日期中的分(0~59) |
| setMinutes(minutes) | 设置日期中的分(如果 minutes 大于 59,则加时) |
| setUTCMinutes(minutes) | 设置 UTC 日期中的分(如果 minutes 大于 59,则加时) |
| getSeconds() | 返回日期中的秒(0~59) |
| getUTCSeconds() | 返回 UTC 日期中的秒(0~59) |
| setSeconds(seconds) | 设置日期中的秒(如果 seconds 大于 59,则加分) |
| setUTCSeconds(seconds) | 设置 UTC 日期中的秒(如果 seconds 大于 59,则加分) |
| getMilliseconds() | 返回日期中的毫秒 |
| getUTCMilliseconds() | 返回 UTC 日期中的毫秒 |
| setMilliseconds(milliseconds) | 设置日期中的毫秒 |
| setUTCMilliseconds(milliseconds) | 设置 UTC 日期中的毫秒 |
| getTimezoneOffset() | 返回以分钟计的 UTC 与本地时区的偏移量(如美国 EST 即“东部标准时间” 返回 300,进入夏令时的地区可能有所差异) |
5.4 RegExp
RegExp 类型支持正则表达式,格式形如:
let expression = /pattern/flags;
pattern:模式,包括任何简单或复杂的正则表达式,包括字符类、限定符、分组、向前查找和反向引用
flags:标记,控制正则表达式的行为
- g:全局模式,表示查找字符串的全部内容,而不是找到第一个匹配的内容就结束。
- i:不区分大小写,表示在查找匹配时忽略 pattern 和字符串的大小写。
- m:多行模式,表示查找到一行文本末尾时会继续查找。
- y:粘附模式,表示只查找从 lastIndex 开始及之后的字符串。
- u:Unicode 模式,启用 Unicode 匹配。
- s:dotAll 模式,表示元字符.匹配任何字符(包括\n 或\r)。
匹配第一个"bat"或"cat",忽略大小写的正则表达式可以表示为如下:
// 字面量形式
let pattern1 = /[bc]at/i;
// RegExp 构造函数
let pattern2 = new RegExp("[bc]at", "i");
5.4.1 RegExp 实例属性
- global:布尔值,表示是否设置了 g 标记。
- ignoreCase:布尔值,表示是否设置了 i 标记。
- unicode:布尔值,表示是否设置了 u 标记。
- sticky:布尔值,表示是否设置了 y 标记。
- lastIndex:整数,表示在源字符串中下一次搜索的开始位置,始终从 0 开始。
- multiline:布尔值,表示是否设置了 m 标记。
- dotAll:布尔值,表示是否设置了 s 标记。
- source:正则表达式的字面量字符串(不是传给构造函数的模式字符串),没有开头和结尾的斜杠。
- flags:正则表达式的标记字符串。始终以字面量而非传入构造函数的字符串模式形式返回(没有前后斜杠)。
5.4.2 RegExp 实例方法
exec()
主要用于配合捕获组使用。返回数据包括两个属性:index 和 input。
index 是字符串中匹配模式的起始位置,input 是要查找的字符串。数组的第一个元素是匹配整个模式的字符串, 其他元素是与表达式中的捕获组匹配的字符串。如果模式中没有捕获组,则数组只包含一个元素。
案例:
let text = "mom and dad and baby";
let pattern = /mom( and dad( and baby)?)?/gi;
let matches = pattern.exec(text);
console.log(matches.index); // 0
console.log(matches.input); // "mom and dad and baby"
console.log(matches[0]); // "mom and dad and baby"
console.log(matches[1]); // " and dad and baby"
console.log(matches[2]); // " and baby"
设置全局标记 g,每次调用 exec() 都会在字符串中向前搜索下一个匹配项。案例如下:
let text = "cat, bat, sat, fat";
let pattern = /.at/g;
let matches = pattern.exec(text);
console.log(matches.index); // 0
console.log(matches[0]); // cat
console.log(pattern.lastIndex); // 3
matches = pattern.exec(text);
console.log(matches.index); //5
console.log(matches[0]); // bat
console.log(pattern.lastIndex); // 8
matches = pattern.exec(text);
console.log(matches.index); // 10
console.log(matches[0]); // sat
console.log(pattern.lastIndex); // 13
设置粘附标记 y,每次调用 exec() 只会在 lastIndex 的位置上寻找匹配项。案例如下:
let text = "cat, bat, sat, fat";
let pattern = /.at/y;
let matches = pattern.exec(text);
console.log(matches.index); // 0
console.log(matches[0]); // cat
console.log(pattern.lastIndex); // 3
// 以索引3对应的字符开头找不到匹配项,因此exec()返回null
// exec()没找到匹配项,于是将lastIndex设置为0
matches = pattern.exec(text);
console.log(matches); // null
console.log(pattern.lastIndex); // 0
// 向前设置lastIndex可以让粘附的模式通过exec()找到下一个匹配项:
pattern.lastIndex = 5;
matches = pattern.exec(text);
console.log(matches.index); // 5
console.log(matches[0]); // bat
console.log(pattern.lastIndex); // 8
test()
该方法适用于只想测试模式是否匹配,而不需要实际匹配内容的情况。
案例:
let text = "000-00-0000";
let pattern = /\d{3}-\d{2}-\d{4}/;
if (pattern.test(text)) {
console.log("The pattern was matched.");
}
toLocaleString() 和 toString()
都返回正则表达式的字面量表示。
案例:
let pattern = new RegExp("\\[bc\\]at", "gi");
console.log(pattern.toString()); // /\[bc\]at/gi
console.log(pattern.toLocaleString()); // /\[bc\]at/gi
此处 pattern.toLocaleString() === pattern.toString()
valueOf()
返回正则表达式本身。
案例:
let pattern = new RegExp("\\[bc\\]at", "gi");
console.log(pattern.valueOf()); // /\[bc\]at/gi
// 或者
let pattern = /\[bc\]at/gi;
console.log(pattern.valueOf()); // /\[bc\]at/gi
此处 pattern.valueOf() == pattern.toString() 且 pattern.valueOf() !== pattern.toString()
5.4.3 RegExp 构造函数属性
RegExp 构造函数的所有属性都没有任何 Web 标准出处,因此不要在生产环境中使 用它们。
RegExp 构造函数本身有几个属性(在其他语言中被称为静态属性),这些属性的特点如下:
- 适用于作用域中的所有正则表达式
- 会根据最后执行的正则表达式操作而变化
- 可以通过两种不同的方式访问它们(每个属性都有一个全名和一个简写)
具体属性如下:
| 全名 | 简写 | 说明 |
|---|---|---|
| input | $_ | 最后搜索的字符串(非标准特性) |
| lastMatch | $& | 最后匹配的文本 |
| lastParen | $+ | 最后匹配的捕获组(非标准特性) |
| leftContext | $` | input 字符串中出现在 lastMatch 前面的文本 |
| rightContext | $' | input 字符串中出现在 lastMatch 后面的文本 |
案例:
let text = "this has been a short summer";
let pattern = /(.)hort/g;
if (pattern.test(text)) {
console.log(RegExp.input); // this has been a short summer
console.log(RegExp.leftContext); // this has been a
console.log(RegExp.rightContext); // summer
console.log(RegExp.lastMatch); // short
console.log(RegExp.lastParen); // s
}
// 或者
if (pattern.test(text)) {
console.log(RegExp.$_); // this has been a short summer
console.log(RegExp["$`"]); // this has been a
console.log(RegExp["$'"]); // summer
console.log(RegExp["$&"]); // short
console.log(RegExp["$+"]); // s
}
其他几个构造函数属性,具体表示为如下
RegExp.$1 ~ RegExp.$9
可以存储最多 9 个捕获组的匹配项,分别包含第 1~9 个捕获组的匹配项
案例:
let text = "this has been a short summer";
let pattern = /(..)or(.)/g;
if (pattern.test(text)) {
console.log(RegExp.$1); // sh
console.log(RegExp.$2); // t
}
5.4.4 模式局限
ECMAScript 正则表达式暂未支持的特性:
- \A 和\Z 锚(分别匹配字符串的开始和末尾)
- 联合及交叉类
- 原子组
- x(忽略空格)匹配模式
- 条件式匹配
- 正则表达式注释
更多信息参考 Regular-Expressions.info 网站
5.5 原始值包装类型
ECMAScript 提供了 3 种特殊的引用类型:Boolean、Number 和 String。这些类型具有其他引用类型一样的特点,也具有与各自原始类型对应的特殊行为。每当用 到某个原始值的方法或属性时,后台都会创建一个相应原始包装类型的对象,从而暴露出操作原始值的各种方法。
案例:
let s1 = "some text";
let s2 = s1.substring(2);
s1 是一个原始值,原始值本身不是对象,因此逻辑上不应该有方法。但这里却运行了substring()方法,这是因为后台进行了相关处理。
此处针对字符串原始值的处理主要如下:
- 创建一个 String 类型的实例
- 调用实例上的特定方法
- 销毁实例
对布尔值和数值而言,以上 3 步也会在后台发生,只不过使用的是 Boolean 和 Number 包装类型而已。
5.5.1 Boolean
Boolean 是对应布尔值的引用类型。
// 创建 Boolean 实例
let booleanObject = new Boolean(true);
实例方法:
- valueOf():返回一个原始值 true 或 false
- toString() 与 toLocalString():返回字符串"true"或"false"
注意 Boolean 对象特殊情况:
let falseObject = new Boolean(false);
let result = falseObject && true;
console.log(result); // true
由于 falseObject 是对象,对象在布尔表达式中都会自动转换为 true(逻辑与操作时,如果第一个操作数是对象,则返回第二个操作数,此处第二个操作数值为 true)
5.5.2 Number
Number 是对应数值的引用类型。
// 创建 Number 实例
let numberObject = new Number(10);
实例方法:
- valueOf():返回一个原始数值
- toString() 与 toLocalString():数值字符串
toString() 方法可接收一个表示基数的参数,并返回相应基数形式的数值字符串
- toFixed():返回包含指定小数点位数的数值字符串
- toExponential():返回以科学记数法(也称为指数记数法)表示的数值字符串
let num = 10; console.log(num.toExponential(1)); // "1.0e+1" - toPrecision():根据情况返回最合理的输出结果,可能是固定长度,也可能是科学记数法 形式
这个方法接收一个参数,表示结果中数字的总位数(不包含指数)。 案例:
let num = 99; console.log(num.toPrecision(1)); // "1e+2" console.log(num.toPrecision(2)); // "99" console.log(num.toPrecision(3)); // "99.0"
isInteger() 方法与安全整数
- isInteger():ES6 新增了 Number.isInteger()方法,用于辨别一个数值是否保存为整数
console.log(Number.isInteger(1)); // true console.log(Number.isInteger(1.00)); // true console.log(Number.isInteger(1.01)); // false - 安全整数:IEEE 754 数值格式有一个特殊的数值范围,在这个范围内二进制值可以表示一个整数值。
范围:Number.MIN_SAFE_INTEGER(-2 ^ 53 + 1) 到 Number.MAX_SAFE_INTEGER(2 ^ 53 - 1)。
- 安全整数范围的的鉴别:可以使用 Number.isSafeInteger()方法
console.log(Number.isSafeInteger(-1 * (2 ** 53))); // false console.log(Number.isSafeInteger(-1 * (2 ** 53) + 1)); // true console.log(Number.isSafeInteger(2 ** 53)); // false console.log(Number.isSafeInteger((2 ** 53) - 1)); // true
5.5.3 String
String 是对应字符串的引用类型。
// 创建 String 实例
let stringObject = new String("hello world");
特性:
- String 对象的方法可以在所有字符串原始值上调用。3 个继承的方法 valueOf()、toLocaleString() 和 toString() 都返回对象的原始字符串值。
- 每个 String 对象都有一个 length 属性
5.5.3.1 JavaScript 字符
- 由 16 位码元(code unit)组成
- charAt():返回给定索引位置的字符
- charCodeAt():查看指定码元的字符编码
console.log("abcde".charCodeAt(2)); // 99 - fromCharCode():根据给定的 UTF-16 码元创建字符串中的字符
console.log(String.fromCharCode(0x61, 0x62, 0x63, 0x64, 0x65)); // "abcde" - Unicode 代理对策略:每个字符使用两个 16 位码元的策略(每个字符使用另外 16 位去选择一个增补平面)
// "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.fromCodePoint(0x1F60A)); // 😊 console.log(String.fromCharCode(97, 98, 55357, 56842, 100, 101)); // ab😊de - codePointAt():解析既包含单码元字符又包含代理对字符的字符串
let message = "ab😊de"; console.log(message.codePointAt(1)); // 98 console.log(message.codePointAt(2)); // 128522 console.log(message.codePointAt(3)); // 56842 console.log(message.codePointAt(4)); // 100 - fromCodePoint():接收任意数量的码点,返回对应字符拼接起来的字符串
console.log(String.fromCharCode(97, 98, 55357, 56842, 100, 101)); // ab😊de console.log(String.fromCodePoint(97, 98, 128522, 100, 101)); // ab😊de
5.5.3.2 normalize() 方法
案例:
let a1 = String.fromCharCode(0x00C5), // Å 上面带圆圈的大写拉丁字母A
a2 = String.fromCharCode(0x212B), // Å 长度单位“埃”
a3 = String.fromCharCode(0x0041, 0x030A); // Å U+004:大写拉丁字母A U+030A:上面加个圆圈
console.log(a1, a2, a3); // Å Å Å
console.log(a1 === a2); // false
console.log(a1 === a3); // false
console.log(a2 === a3); // false
案例中三个字符串看起来相同,实际不相等。为解决这个问题,Unicode 提供了 4 种规范化形式,可以将类似上面的字符规范化为一致的格式。
4 种规范化形式:
- NFD(Normalization Form D)
- NFC(Normalization Form C)
- NFKD(Normalization Form KD)
- NFKC(Normalization Form KC)
通过比较字符串与其调用 normalize() 的返回值,就可以知道该字符串是否已经规范化了:
let a1 = String.fromCharCode(0x00C5),
a2 = String.fromCharCode(0x212B),
a3 = String.fromCharCode(0x0041, 0x030A);
// U+00C5 是对 0+212B 进行 NFC/NFKC 规范化之后的结果
console.log(a1 === a1.normalize("NFD")); // false
console.log(a1 === a1.normalize("NFC")); // true
console.log(a1 === a1.normalize("NFKD")); // false
console.log(a1 === a1.normalize("NFKC")); // true
// U+212B 是未规范化的
console.log(a2 === a2.normalize("NFD")); // false
console.log(a2 === a2.normalize("NFC")); // false
console.log(a2 === a2.normalize("NFKD")); // false
console.log(a2 === a2.normalize("NFKC")); // false
// U+0041/U+030A 是对 0+212B 进行 NFD/NFKD 规范化之后的结果
console.log(a3 === a3.normalize("NFD")); // true
console.log(a3 === a3.normalize("NFC")); // false
console.log(a3 === a3.normalize("NFKD")); // true
console.log(a3 === a3.normalize("NFKC")); // false
选择同一种规范化形式可以让比较操作符返回正确的结果:
let a1 = String.fromCharCode(0x00C5),
a2 = String.fromCharCode(0x212B),
a3 = String.fromCharCode(0x0041, 0x030A);
console.log(a1.normalize("NFD") === a2.normalize("NFD")); // true
console.log(a2.normalize("NFKC") === a3.normalize("NFKC")); // true
console.log(a1.normalize("NFC") === a3.normalize("NFC")); // true
5.5.3.3 字符串操作方法
- concat():将一个或多个字符串拼接成一个新字符串
- slice()、substr()和 substring():返回调用它们的字符串的一个子字符串(允许2个参数,第一个参数都表示开始的位置)
- slice() 和 substring() 第二个参数是提取结束的位置(即该位置之前的字符会被提取出来)\
- substr() 第二个参数表示返回的子字符串数量 \
- 参数为复数的情况下:
- slice() 将所有负值参数都当成字符串长度加上负参数值
- substr() 将第一个负参数值当成字符串长度加上该值,将第二个负参数值转换为 0
- substring() 将所有负参数值都转换为 0
案例:
let stringValue = "hello world";
console.log(stringValue.slice(3)); // "lo world"
console.log(stringValue.substring(3)); // "lo world"
console.log(stringValue.substr(3)); // "lo world"
console.log(stringValue.slice(3, 7)); // "lo w"
console.log(stringValue.substring(3,7)); // "lo w"
console.log(stringValue.substr(3, 7)); // "lo worl"
5.5.3.4 字符串位置方法
- indexOf():从字符串开头开始查找子字符串
- lastIndexOf():从字符串末尾开始查找子字符串
参数 searchvalue,fromindex,其中第二个参数非必传,表示从哪个位置开始。
5.5.3.5 字符串包含方法
- startsWith():检查开始于索引 0 的匹配项
- endsWith():检查开始于索引(string.length - substring.length)的匹配项
- includes():检查整个字符串
- startsWith() 和 includes() 方法接收可选的第二个参数,表示开始搜索的位置
- endsWidth() 参数 searchString [, length ],其中 length 为非必传,表示匹配项的长度
5.5.3.6 trim() 方法
所有字符串都拥有 trim() 方法。
- 这个方法会创建字符串的一个副本(原始字符串不变),删除前、后所有空格符,再返回结果。
- trimLeft()和 trimRight()方法分别用于从字符串开始和末尾清理空格符。
5.5.3.7 repeat() 方法
所有字符串都拥有 repeat() 方法。
这个方法接收一个整数参数,表示要将字符串复制多少次,然后返回拼接所有副本后的结果。
5.5.3.8 padStart() 和 padEnd() 方法
可填充的复制字符串。
- 如果小于指定长度,则在相应一边填充字符,直至满足长度条件。
- 这两个方法的第一个参数是长度,第二个参数是可选的填充字符串,默认为空格 (U+0020)。
- 第二个参数并不限于一个字符。如果提供了多个字符的字符串,则会将其拼接并截断以匹配 指定长度。
- 如果长度小于或等于字符串长度,则会返回原始字符串。
案例:
let stringValue = "foo";
console.log(stringValue.padStart(6)); // " foo"
console.log(stringValue.padStart(9, ".")); // "......foo"
console.log(stringValue.padEnd(6)); // "foo "
console.log(stringValue.padEnd(9, ".")); // "foo......"
let stringValue = "foo";
console.log(stringValue.padStart(8, "bar")); // "barbafoo"
console.log(stringValue.padStart(2)); // "foo"
console.log(stringValue.padEnd(8, "bar")); // "foobarba"
console.log(stringValue.padEnd(2)); // "foo"
5.5.3.9 字符串迭代与解构
字符串的原型上暴露了一个 @@iterator 方法,表示可以迭代字符串的每个字符。
案例:
let message = "abc";
let stringIterator = message[Symbol.iterator]();
console.log(stringIterator.next()); // {value: "a", done: false}
console.log(stringIterator.next()); // {value: "b", done: false}
console.log(stringIterator.next()); // {value: "c", done: false}
console.log(stringIterator.next()); // {value: undefined, done: true}
for-of 循环:
for (const c of "abcde") {
console.log(c);
}
// a
// b
// c
// d
// e
字符串解构:
let message = "abcde";
console.log([...message]); // ["a", "b", "c", "d", "e"]
5.5.3.10 字符串大小写转换
包括 4 个方法:toLowerCase()、toLocaleLowerCase()、toUpperCase()和 toLocaleUpperCase()。
如果不知道代码涉及什么语言,则最好使用地区特定的转换方法。
5.5.3.11 字符串模式匹配方法
- match():法接收一个参数,可以是一个正则表达式字符串,也可以是一个 RegExp 对象(本质上跟 RegExp 对象的 exec() 方法相同)
let text = "cat, bat, sat, fat"; let pattern = /.at/; // 等价于pattern.exec(text) let matches = text.match(pattern); console.log(matches.index); // 0 console.log(matches[0]); // "cat" console.log(pattern.lastIndex); // 0 - search():唯一的参数与 match() 方法一样:正则表达式字符串或 RegExp 对象。返回模式第一个匹配的位置索引,如果没找到则返回 -1。
let text = "cat, bat, sat, fat"; let pos = text.search(/at/); console.log(pos); // 1 - replace():简化子字符串替换操作。两个参数,第一个参数可以是一个 RegExp 对象或一个字符串(这个字符串不会转换为正则表达式),第二个参数可以是一个字符串或一个函数。
如果第一个参数是字符串,那么只会替换第一个子字符串。要想替换所有子字符串,第一个参数必须为正则表达式并且带全局标记
let text = "cat, bat, sat, fat"; let result = text.replace("at", "ond"); console.log(result); // "cond, bat, sat, fat" result = text.replace(/at/g, "ond"); console.log(result); // "cond, bond, sond, fond"
5.5.3.12 localeCompare() 方法
比较两个字符串,返回如下 3 个值中的一个:
- 如果按照字母表顺序,字符串应该排在字符串参数前头,则返回负值。(通常是-1,具体还要看与实际值相关的实现)
- 如果字符串与字符串参数相等,则返回 0。
- 如果按照字母表顺序,字符串应该排在字符串参数后头,则返回正值。(通常是 1,具体还要看与实际值相关的实现)
案例:
let stringValue = "yellow";
console.log(stringValue.localeCompare("brick")); // 1
console.log(stringValue.localeCompare("yellow")); // 0
console.log(stringValue.localeCompare("zoo")); // -1
localeCompare()区分大小写,大写字母排在小写字母前面。
5.5.3.13 HTML 方法
| 方法 | 输出 |
|---|---|
| anchor(name) | <a name="name">string</a> |
| big() | <big>string</big> |
| bold() | <b>string</b> |
| fixed() | <tt>string</tt> |
| fontcolor(color) | <font color="color">string</font> |
| fontsize(size) | <font size="size">string</font> |
| italics() | <i>string</i> |
| link(url) | <a href="url">string</a> |
| small() | <small>string</small> |
| strike() | <strike>string</strike> |
| sub() | <sub>string</sub> |
| sup() | <sup>string</sup> |
早期浏览器增加了辅助生成 HTML 标签的方法,不过现在基本上已经没有人使用了。
5.6 单例内置对象
内置对象:任何由 ECMAScript 实现提供、与宿主环境无关,并在 ECMAScript 程序开始执行时就存在的对象。
不用显式地实例化内置对象,因为它们已经实例化好了。
5.6.1 Global
- Global 对象是 ECMAScript 中最特别的对象,因为代码不会显式地访问它
- Global 对象是一种兜底对象,它所针对的是不属于任何对象的属性和方法
- 所谓的全局函数与变量其实都是 Global 对象的属性
前面介绍的 isNaN()、isFinite()、parseInt() 和 parseFloat()方法都是 Global 对象的方法,其他方法如下:
5.6.1.1 URL 编码方法
- encodeURI() 和 encodeURIComponent():用于编码统一资源标识符(URI),以便传给浏览器。
- ecnodeURI():用于对整个 URI 进行编码,且不会编码属于 URL 组件的特殊字符,比如冒号、斜杠、问号、井号。
- encodeURIComponent():用于编码 URI 中单独的组件,且会编码所有的非标准字符。 案例:
let uri = "http://www.wrox.com/illegal value.js#start"; // "http://www.wrox.com/illegal%20value.js#start" console.log(encodeURI(uri)); // "http%3A%2F%2Fwww.wrox.com%2Fillegal%20value.js%23start" console.log(encodeURIComponent(uri)); - decodeURI()和 decodeURIComponent():针对 decodeURI() 和 decodeURIComponent() 编码方法的解码方法。
- decodeURI():解码所有被 encodeURI() 编码的字符。
- decodeURIComponent():解码所有被 encodeURIComponent() 编码的字符。 案例:
let uri = "http%3A%2F%2Fwww.wrox.com%2Fillegal%20value.js%23start"; // http%3A%2F%2Fwww.wrox.com%2Fillegal value.js%23start console.log(decodeURI(uri)); // http:// www.wrox.com/illegal value.js#start console.log(decodeURIComponent(uri));
5.6.1.2 eval() 方法
一个完整的 ECMAScript 解释器。
接收一个参数,即一个要执行的 ECMAScript(JavaScript) 字符串
案例:
eval("console.log('hi')");
// 等价于运行 console.log("hi");
通过 eval() 执行的代码属于该调用所在上下文,被执行的代码与该上下文拥有相同的作用域链,意味着定义在包含上下文中的变量可以在 eval() 调用内部被引用:
let msg = "hello world";
eval("console.log(msg)"); // "hello world"
类似地,可以在 eval() 内部定义一个函数或变量,然后在外部代码中引用:
eval("function sayHi() { console.log('hi'); }");
sayHi(); // hi
- 通过 eval() 定义的任何变量和函数都不会被提升,这是因为在解析代码的时候,它们是被包含在一个字符串中的。它们只是在 eval()执行的时候才会被创建。
- 在严格模式下,eval() 内部创建的变量和函数无法被外部访问。同样,在严格模式下,赋值给 eval 也会导致错误。
5.6.1.3 Global 对象属性
- undefined、NaN 和 Infinity 等特殊值都是 Global 对象的属性。
- 所有原生引用类型构造函数,比如 Object 和 Function 也都是 Global 对象的属性。
| 属性 | 说明 |
|---|---|
| undefined | 特殊值 undefined |
| NaN | 特殊值 NaN |
| Infinity | 特殊值 Infinity |
| Object | Object 的构造函数 |
| Array | Array 的构造函数 |
| Function | Function 的构造函数 |
| Boolean | Boolean 的构造函数 |
| String | String 的构造函数 |
| Number | Number 的构造函数 |
| Date | Date 的构造函数 |
| RegExp | RegExp 的构造函数 |
| Symbol | Symbol 的伪构造函数 |
| Error | Error 的构造函数 |
| EvalError | EvalError 的构造函数 |
| RangeError | RangeError 的构造函数 |
| ReferenceError | ReferenceError 的构造函数 |
| SyntaxError | SyntaxError 的构造函数 |
| TypeError | TypeError 的构造函数 |
| URIError | URIError 的构造函数 |
5.6.1.4 window 对象
- ECMA-262 没有规定直接访问 Global 对象的方式,但浏览器将 window 对象实现为 Global 对象的代理。
- 所有全局作用域中声明的变量和函数都变成了 window 的属性。
案例:
var color = "red";
function sayColor() {
console.log(window.color);
}
window.sayColor(); // "red"
另一种获取 Global 对象的方式:
let global = function() {
return this;
}();
当一个函数在没有明确(通过成为某个对象的方法,或者通过 call()/apply())指定 this 值的情况下执行时,this 值等于 Global 对象。
5.6.2 Math
ECMAScript 提供了 Math 对象作为保存数学公式、信息和计算的地方。
Math对象上提供的计算要比直接在JavaScript实现的快得多
5.6.2.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 的平方根 |
5.6.2.2 min() 和 max() 方法
用于确定一组数值中的最小值和最大值。(两个方法都可以接收任意多个参数)
案例:
let max = Math.max(3, 54, 32, 16);
console.log(max); // 54
let min = Math.min(3, 54, 32, 16);
console.log(min); // 3
求一个数组中最大的数值:
let values = [1, 2, 3, 4, 5, 6, 7, 8];
let max = Math.max(...values);
console.log(max);
5.6.2.3 舍入方法
把小数值舍入为整数的 4 个方法:Math.ceil()、Math.floor()、Math.round() 和 Math.fround()。
- Math.ceil():向上取整
- Math.floor():向下取整
- Math.round():四舍五入
- Math.fround():最接近的单精度(32 位)浮点值
案例:
console.log(Math.ceil(25.9)); // 26
console.log(Math.ceil(25.5)); // 26
console.log(Math.ceil(25.1)); // 26
console.log(Math.floor(25.9)); // 25
console.log(Math.floor(25.5)); // 25
console.log(Math.floor(25.1)); // 25
console.log(Math.round(25.9)); // 26
console.log(Math.round(25.5)); // 26
console.log(Math.round(25.1)); // 25
console.log(Math.fround(0.4)); // 0.4000000059604645
console.log(Math.fround(0.5)); // 0.5
console.log(Math.fround(25.9)); // 25.899999618530273
5.6.2.4 random() 方法
返回一个 0~1 范围内的随机数(其中包含 0 但不包含 1,即范围 [0, 1))。
如果为了加密而需要生成随机数(传给生成器的输入需要较高的不确定性),建议使用 window.crypto.getRandomValues()。
5.6.2.5 其他方法
| 方法 | 说明 |
|---|---|
| Math.abs(x) | 返回 x 的绝对值 |
| Math.exp(x) | 返回 Math.E 的 x 次幂 |
| Math.expm1(x) | 等于 Math.exp(x) - 1 |
| Math.log(x) | 返回 x 的自然对数 |
| Math.log1p(x) | 等于 1 + Math.log(x) |
| Math.pow(x, power) | 返回x的power次幂 |
| Math.hypot(...nums) | 返回 nums 中每个数平方和的平方根 |
| Math.clz32(x) | 返回 32 位整数 x 的前置零的数量 |
| Math.sign(x) | 返回表示 x 符号的 1、0、-0 或 -1 |
| Math.trunc(x) | 返回 x 的整数部分,删除所有小数 |
| Math.sqrt(x) | 返回 x 的平方根 |
| Math.cbrt(x) | 返回 x 的立方根 |
| Math.acos(x) | 返回 x 的反余弦 |
| Math.acosh(x) | 返回 x 的反双曲余弦 |
| Math.asin(x) | 返回 x 的反正弦 |
| Math.asinh(x) | 返回 x 的反双曲正弦 |
| Math.atan(x) | 返回 x 的反正切 |
| Math.atanh(x) | 返回 x 的反双曲正切 |
| Math.atan2(y, x) | 返回 y/x 的反正切 |
| Math.cos(x) | 返回x的余弦 |
| Math.sin(x) | 返回x的正弦 |
| Math.tan(x) | 返回x的正切 |
即便这些方法都是由 ECMA-262 定义的,对正弦、余弦、正切等计算的实现仍然取决于浏览器,因为计算这些值的方式有很多种。结果,这些方法的精度可能因实现而异。
5.7 小结
-
JavaScript 中的对象称为引用值,几种内置的引用类型可用于创建特定类型的对象。
- 引用值与传统面向对象编程语言中的类相似,但实现不同。
- Date 类型提供关于日期和时间的信息,包括当前日期、时间及相关计算。
- RegExp 类型是 ECMAScript 支持正则表达式的接口,提供了大多数基础的和部分高级的正则表达式功能。
-
JavaScript 中的原始值可以被当成对象来使用,3 种原始值包装类型:Boolean、Number 和 String。
- 每种包装类型都映射到同名的原始类型。
- 以读模式访问原始值时,后台会实例化一个原始值包装类型的对象,借助这个对象可以操作相应的数据。
- 涉及原始值的语句执行完毕后,包装对象就会被销毁。
-
全局上下文中的两个内置对象:Global 和 Math。
- Global 对象在大多数 ECMAScript 实现中无法直接访问。不过,浏览器将其实现为 window 对象,所有全局变量和函数都是 Global 对象的属性。
- Math 对象包含辅助完成复杂计算的属性和方法。