600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > JavaScript高级程序设计 学习笔记5 - 基本引用类型

JavaScript高级程序设计 学习笔记5 - 基本引用类型

时间:2019-10-27 03:36:14

相关推荐

JavaScript高级程序设计 学习笔记5 - 基本引用类型

内容均摘自JavaScript高级程序设计第四版,仅用于记录学习过程。

第五章 基本引用类型

5.1 理解引用类型5.2 Date5.2.1 常用方法5.2.1.1 Date.parse()5.2.1.2 Date.UTC()5.2.1.3 Date.now() 5.2.2 继承方法5.2.3 日期格式化方法5.2.4 日期/时间组件方法 5.3 RegExp5.3.1 RegExp实例属性5.3.2 RegExp 实例方法5.3.2.1 exec()5.3.2.1.1 全局标记5.3.2.1.2 粘附标记 5.3.2.2 test() 5.3.3 RegExp构造函数属性 5.4 原始值包装类型5.4.1 Boolean5.4.1.1 在布尔表达式中使用Boolean对象5.4.1.2 原始布尔值和布尔对象的区别 5.4.2 Number5.4.2.1 将数值格式化为字符串的方法5.4.2.2 原始数值和数值对象的区别5.4.2.3 isInteger()方法与安全整数 5.4.3 String5.4.3.1 JavaScript 字符5.4.3.2 拼接字符串方法 concat()5.4.3.3 提取子字符串的方法 slice()、substr()、substring()5.4.3.4 定位子字符串位置的方法 indexOf() 、lastIndexOf()5.4.3.5 包含字符串的方法 startsWith()、endsWith()、includes()5.4.3.6 trim() 方法5.4.3.7 repeat() 方法5.4.3.8 padStart() 和 padEnd() 方法5.4.3.9 字符串迭代与解构5.4.3.10 字符串大小写转换5.4.3.11 字符串模式匹配方法5.4.3.12 replace()5.4.3.13 split()5.4.3.14 localeCompare() 5.5 单例内置对象5.5.1 Global5.5.1.1 URL编码方法5.5.1.2 eval()5.5.1.3 Global 对象属性5.5.1.4 获取Global对象 5.5.2 Math5.5.2.1 Math对象的属性5.5.2.2 min() 和 max()5.5.2.3 舍入方法5.5.2.4 random() 方法5.5.2.5 其他方法 5.6 小结

5.1 理解引用类型

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

在ECMAScript 中,引用类型是把数据和功能组织到一起的结构常被人错误地称""引用类型有时也被称为对象定义,因为它们描述了自己的对象应有的属性和方法

新对象通过使用new操作符后跟一个构造函数来创建,构造函数就是用来创建新对象的函数,比如下面这行代码:

let now = new Date();

创建了引用类型Date的一个新实例,并将它保存在变量nowDate()是构造函数,负责创建一个只有默认属性和方法的简单对象

5.2 Date

Date类型将日期保存为1970年1月1日零时至今所经过的毫秒数

创建日期对象,使用new操作符来调用Date构造函数:

let now = new Date();

不给Date构造函数传参数的情况下,创建的对象将保存当前日期和时间若要基于其他日期和时间创建日期对象,必须传入其毫秒表示,ECMAScript 为此提供了两个辅助方法:Date.parse()Date.UTC()

5.2.1 常用方法

5.2.1.1 Date.parse()

Date.parse():接收一个表示日期的字符串参数,尝试将这个字符串转换为表示该日期的毫秒数

支持的日期格式: “月/日/年”,如"5/23/"“月名 日,年”,如"May 23,"“周几 月名 日 年 时:分:秒 时区”,如"Tue May 23 00:00:00 GMT-0700"

若直接把表示日期的字符串传给Date()Date会在后台调用Date.parse()

比如,要创建一个表示"5月23日"的日期对象,可以使用以下代码:

let date = new Date(Date.parse("5/23/"));// 等效于let date = new Date("5/23/");

⚠️:若传的字符串不表示日期,则Date.parse()返回NaN

5.2.1.2 Date.UTC()

Date.UTC()也是返回日期的毫秒数

参数:年、月(以0为起点)、日(1~31)、时(0~23)、分、秒、毫秒

(只有年和月是必需的,日不提供则默认为1,其他不提供则默认为0)

Date.UTC()也会被Date()隐式调用,但隐式调用下创建的是本地日期,不是GMT日期

下面是两个例子:

// GMT时间 2000年 1月 1日 0点let date = new Date(Date.UTC(2000, 0));// 等效于// 本地时间 2000年 1月 1日 0点let date = new Date(2000, 0);

// GMT时间 8月 1日 5点 55分 55秒// 注意这里的月不是8,是7,以0为起点let date = new Date(Date.UTC(, 7, 1, 5, 55, 55));

5.2.1.3 Date.now()

返回表示方法执行时的日期和时间的毫秒数

这个方法可以用在代码分析中:

// 起始时间let start = Date.now();// 调用函数doSomething();// 结束时间let stop = Date.now();// 计算用时result = stop - start;

5.2.2 继承方法

与其他引用类型一样,Date重写了toLocaleString()toString()valueOf()方法

toLocaleString():返回与浏览器运行的本地环境一致的日期和时间,格式中包含AM(上午)PM(下午),但不包含时区信息,具体格式可能因浏览器而不同toString():返回带时区信息的日期和时间

下面给出这两种方法返回的示例:

8月2日零点

// toLocalString()8/2/ 12:00:00 AM// toString()Mon Aug 2 00:00:00 GMT-0800 (Pacific Standard Time)

valueOf():返回日期的毫秒表示

let date1 = new Date(, 0, 1); // 1月1日let date2 = new Date(, 1, 1); // 2月1日console.log(date1 < date2); // true

5.2.3 日期格式化方法

toDateString():显示日期中的周几、月、日、年(格式特定于实现)toTimeString():显示日期中的时、分、秒、时区(格式特定于实现)toLocalDateString():显示日期中的周几、月、日、年(格式特定于实现和地区)toLocaleTimeString():显示时期中的时、分、秒(格式特定于实现和地区)toUTCString():显示完整的UTC日期(格式特定于实现)

这些方法的输出会因浏览器而异,因此不能用于在用户界面上一致地显示日期。

5.2.4 日期/时间组件方法

Date引用类型的其他方法涉及取得设置日期值的特定部分

⚠️:UTC日期指的是没有时区偏移(将日期转换为GMT)时的日期

5.3 RegExp

ECMAScript 通过RegExp类型支持正则表达式

正则表达式的创建:

let expression = /pattern/flags;

pattern(模式)可以是任何正则表达式,包括字符类、限定符、分组、向前查找、反向引用

每个正则表达式可以不带或带多个flags(标记),用于控制正则表达式的行为

匹配模式的标记:

g:全局模式,查找字符串的全部内容,而不是找到第一个匹配的内容就结束I:不区分大小写,查找匹配时忽略大小写m:多行模式,查找到一行文本末尾时会继续查找y:粘附模式,只查找从lastIndex开始及之后的字符串u:Unicode模式,启用Unicode匹配s:dotAll模式,匹配任何字符,包括\n\r

// 匹配字符串中的所有"at"let p1 = /at/g;// 匹配第一个"bat"或"cat",武略大小写let p2 = /[bc]at/i;

元字符在模式中必须转义,因为元字符在正则表达式中都有多种特殊功能,所以要匹配这些字符本身就必须使用反斜杠来转义

包括:

() [] {} \ ^ $ | ? * + .

// 匹配第一个"[bc]at",忽略大小写let p1 = /\[bc\]at/i;// 匹配所有的".at",忽略大小写let p2 = /\.at/gi;

上面例子中的正则表达式都是使用字面量形式定义的

也可以使用RegExp构造函数来创建

接收两个参数:模式字符串和标记字符串

// 匹配第一个"bat"或"cat",忽略大小写let p = /[bc]at/i;// 等效于let p = new RegExp("[bc]at", "i");

因为RegExp引用类型的模式参数是字符串,所以在某些情况下需要二次转义

使用RegExp也可以基于已有的正则表达式实例,并可选择性地修改它们的标记:

const r1 = /cat/g;const r2 = new RegExp(r1);const r3 = new RegExp(r1, "i");console.log(r2); // "/cat/g"console.log(r3); // "/cat/i"

5.3.1 RegExp实例属性

每个 RegExp 实例都有下列属性:

global:布尔值,是否设置了g标记ignoreCase:布尔值,是否设置了i标记unicode:布尔值,是否设置了u标记sticky:布尔值,是否设置了y标记multiline:布尔值,是否设置了m标记dotAll:布尔值,是否设置了s标记lastIndex:整数,在源字符串中下一次搜索的开始位置source:正则表达式的字面量字符串,没有开头和结尾的斜杠flags:正则表达式的标记字符串

通过这些属性可以全面了解正则表达式的信息,不过实际开发中用的不多

5.3.2 RegExp 实例方法

5.3.2.1 exec()

RegExp实例的主要方法是exec(),主要用于配合捕获组使用

只接收一个参数,要作为模式的字符串如果找到了匹配项,返回包含第一个匹配信息的数组如果没找到匹配项,返回null

返回的数组是Array的实例,包含两个额外的属性:indexinput

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 从字符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"

这个例子中,模式包含两个捕获组

最内部的匹配项" and baby"外部的匹配项" and dad"" and dad and baby"

数组的第一个元素是匹配的整个字符串,第二个元素是匹配第一个捕获组的字符串,第三个元素是匹配第二个捕获组的字符串。

5.3.2.1.1 全局标记

如果模式设置了全局标记,则每一次调用exex()都会返回一个匹配的信息,若不设置全局标记,无论调用多少次exex(),也只会返回第一个匹配的信息

看下例:

let text = "cat, bat, sat, fat";let pattern = /.at/;let matches = pattern.exec(text);console.log(matches.index); // 0console.log(matches[0]); // catconsole.log(pattern.lastIndex); // 0matches = pattern.exec(text);console.log(matches.index); // 0console.log(matches[0]); // catconsole.log(pattern.lastIndex); // 0

上面例中的模式没有设置全局标记,因此调用exex()只会返回第一个匹配项("cat")

⚠️:lastIndex在非全局模式下始终不变

lastIndex表示在查找字符串中下一次搜索开始的位置)

如果在这个模式上设置了g标记,则每次调用exec()都会在字符串中向前搜索下一个匹配项

看下例:

let text = "cat, bat, sat, fat";let pattern = /.at/g;let matches = pattern.exec(text);console.log(matches.index); // 0console.log(matches[0]); // catconsole.log(pattern.lastIndex); // 3matches = pattern.exec(text); console.log(matches.index); // 5 console.log(matches[0]); // bat console.log(pattern.lastIndex); // 8...

这次模式设置了全局标记,因此每次调用exec()都会返回字符串中的下一个匹配项,直到搜索到字符串末尾

⚠️:lastIndex在全局模式下每次调用exec()都会更新

lastIndex表示在查找字符串中下一次搜索开始的位置)

5.3.2.1.2 粘附标记

如果模式设置了粘附标记y,则每次调用exec()就只会在lastIndex的位置上寻找匹配项,不会跳过往后查找

粘附标记覆盖全局标记

let text = "cat, bat, sat, fat";let pattern = /.at/y;let matches = pattern.exec(text);console.log(matches.index); // 0console.log(matches[0]); // catconsole.log(pattern.lastIndex); // 3// 索引3对应的字符是",",找不到匹配项,因此返回null // 没找到匹配项,于是将lastIndex设置为0matches = pattern.exec(text);console.log(matches); // nullconsole.log(pattern.lastIndex); // 0// 向前设置lastIndex可以让粘附的模式找到下一个匹配项:pattern.lastIndex = 5;matches = pattern.exec(text);console.log(matches.index); // 5console.log(matches[0]); // batconsole.log(pattern.lastIndex); // 8

5.3.2.2 test()

正则表达式的另一个方法是test()

接收一个字符串参数如果输入的文本模式匹配,则返回true,否则返回false

test()常用于if语句中:

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()都返回正则表达式的字面量表示valueOf()方法返回正则表达式本身

比如:

let pattern = new RegExp("\\[bc\\]at", "gi");console.log(pattern.toString()); // /\[bc\]at/giconsole.log(pattern.toLocaleString()); // /\[bc\]at/giconsole.log(pattern.valueOf()); // /\[bc\]at/gi

5.3.3 RegExp构造函数属性

RegExp构造函数本身也有几个属性(在其他语言中,这种属性被称为静态属性)

这些属性适用于作用域中的所有正则表达式

并且这些属性可以通过两种不同的方式访问(全名和简写)

5.4 原始值包装类型

ECMAScript 提供了 3 种特殊的引用类型:BooleanNumberString

这些类型具有本章介绍的其他引用类型一样的特点,也具有与各自原始类型对应的特殊行为

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

let s1 = "some text";let s2 = s1.substring(2);

变量s1包含一个字符串,它是一个原始值

第二行在变量s1上调用了substring()方法,把结果保存在变量s2

我们知道,原始值本身不是对象,逻辑上不应该有方法,这是因为后台进行了很多处理,从而实现上述操作。

具体来说,当第二行访问变量s1时,是以读模式访问的,也就是要从内存中读取变量s1保存的值在以读模式访问字符串的时候,后台都会执行以下3步: 创建一个String类型的实例调用实例上的特定方法销毁实例

// 上面的3步类似于执行以下代码let s1 = new String("some text");let s2 = s1.substring(2);s1 = null;

这种行为可以让原始值拥有对象的行为

引用类型与原始值包装类型的主要区别在于对象生命周期

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

let s1 = "some text";s1.color = "red";console.log(s1.color);// undefined

这里的第二行代码尝试给s1添加一个color属性,但在第三行代码访问color属性时,它却不见了

原因:第二行代码运行时会临时创建一个String对象,而当第三行代码执行时,这个对象已经被销毁了。实际上,第三行代码在这里创建了自己的String对象,但这个对象没有color属性。

可以显式地使用BooleanNumberString构造函数创建原始值包装对象,确定是必要时再这么做,否则容易让开发者分不清到底它们是原始值还是引用值

Object构造函数作为一个工厂方法,可以根据传入值的类型返回相应原始值包装类型实例

let obj1 = new Object("some text");console.log(obj1 instanceof String); // truelet obj2 = new Object(1);console.log(obj2 instanceof Number); // truelet obj3 = new Object(true);console.log(obj3 instanceof Boolean); // true

⚠️:使用new调用原始包装类型的构造函数,与调用同名的转型函数并不一样

let value = "25";let num1 = Number(value);// 调用转型函数console.log(typeof num1);// "number"let num2 = new Number(value); //.调用原始包装类型的构造函数console.log(typeof num2);// "object"

在本例中,变量num1保存的是一个值为25的原始数值,而变量num2保存的是一个Number的实例

不推荐显式创建原始值包装类型实例,虽然它们对于操作原始值的功能很重要

5.4.1 Boolean

Boolean是布尔值的引用类型

要创建一个Boolean对象,使用Boolean(),并传入truefalse,如下例所示:

let booleanObj = new Boolean(true);

5.4.1.1 在布尔表达式中使用Boolean对象

Boolean对象在布尔表达式中使用时容易引起误会,用得很少:

let falseObj = new Boolean(false);let result = falseObj && true;console.log(result); // truelet falseVal = false;result = falseVal && true;console.log(result); // false

在本例中,第2行对falseObjtrue进行布尔运算,但这个运算是对falseObj对象,而不是对它表示的值false求值,这里就要⚠️:所有对象在布尔表达式中都会自动转换为true

所以true && true当然也为true

5.4.1.2 原始布尔值和布尔对象的区别

原始值和引用值(Boolean对象)还有一些区别:

typeof操作符对原始值返回"boolean",对引用值返回objectinstanceof操作符对原始值返回false,对引用值返回true

console.log(falseObj instanceof Boolean); // trueconsole.log(falseVal instanceof Boolean); // false

理解原始布尔值Boolean对象的区别很重要

强烈建议永远不要使用Boolean对象

5.4.2 Number

Number是数值的引用类型

要创建一个Number对象,使用Number(),并传入 一个数值,如下例所示:

let numberObj = new Number(10);

Number引用类型重写了valueOf()toLocaleString()toString()

valueOf()返回Number对象表示的原始数值toLocaleString()toString()返回数值字符串toString()可以接收一个表示基数的参数

let num = 10;console.log(num.toString()); // "10"console.log(num.toString(2)); // "1010"console.log(num.toString(16)); // "a"

5.4.2.1 将数值格式化为字符串的方法

toFixed():返回包含指定小数点位数的数值字符串,此方法会自动四舍五入

let num = 10;console.log(num.toFixed(2)); // "10.00"

toExponential():返回以科学计数法表示的数值字符串

let num = 10;console.log(num.toExponential(1)); // "1.0e+1"console.log(num.toExponential(3)); // "1.000e+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"

在本例中,第二行:要用1位数字表示9999不能只用1位数字来精确表示,所以这个方法将它舍入为100

本质上,toPrecision()方法会根据数值精度来决定调用toFixed()还是toExponential()

5.4.2.2 原始数值和数值对象的区别

typeof操作符对原始值返回"number",对引用值返回objectinstanceof操作符对原始值返回false,对引用值返回true

let numObj = new Number(10);let numVal = 10;console.log(numObj instanceof Number); // trueconsole.log(numVal instanceof Number); // false

理解原始数值Number对象的区别很重要

同样建议不要使用Number对象

5.4.2.3 isInteger()方法与安全整数

ES6新增了Number.isInteger()方法,用于辨别一个数值是否保存为整数

console.log(Number.isInteger(1)); // trueconsole.log(Number.isInteger(1.00)); // true

Number.MIN_SAFE_INTERGER(-253 + 1)到Number.MAX_SAFE_INTERGER(253 - 1)范围内,二进制值可以表示为一个整数

超出此范围的数值,即使尝试保存为整数,IEEE 754 编码格式也意味着二进制值可能会表示一个完全不同的数值

可以使用Number.isSageInteger()鉴别整数是否在这个范围内

console.log(Number.isSafeInteger(-1 * (2 ** 53)));// falseconsole.log(Number.isSafeInteger(-1 * (2 ** 53) + 1)); // true

5.4.3 String

String是字符串的引用类型

要创建一个String对象,使用String(),并传入 一个字符串,如下例所示:

let stringObj = new String("hello world");

String对象的方法可以在所有的字符串原始值上调用,3个继承的方法valueOf()toLocaleString()toString()都返回对象的原始字符串值

length属性表示字符串中字符的数量,需要⚠️:即使字符串中包含双字节字符,也仍然会按单字符来计数

String类型提供了很多方法来解析和操作字符串:

5.4.3.1 JavaScript 字符

字符串由16位码元组成,对多数字符来说,每16位码元对应1个字符。

也就是说length属性表示字符串包含多少16位码元

let message = "abc";console.log(message.length); // 3

charAt()方法返回给定索引位置的字符,具体来说,这个方法查找指定索引位置的16位码元,并返回该码元对应的字符:

let message = "abc";console.log(message.charAt(2)); // "c"

5.4.3.2 拼接字符串方法 concat()

concat():用于将一个或多个字符串拼接成一个新字符串

let stringVal = "hello ";let result = stringVal.concat("world");console.log(result);// "hello world"console.log(stringValue); // "hello"

⚠️:stringVal的值是不变的

concat()也可以接收任意多个参数,可以一次性拼接多个字符串:

let stringVal = "hello ";let result = stringVal.concat("world","!","hahaha");console.log(result); // "hello world!hahaha"

(但更常用的还是+拼接多个字符串)

5.4.3.3 提取子字符串的方法 slice()、substr()、substring()

slice()substr()substring()都会返回调用它们的字符串的一个子字符串,都接收1或2个参数,都不会修改原字符串

第一个参数:表示子字符串开始的位置第二个参数: 对slice()substring()而言,表示提取结束的位置(该位置之前的字符会被提取)substr()而言,表示提取的子字符串的长度

(若省略第二个参数,默认提取到字符串末尾

⚠️:接收两个参数时,以较小的那个参数作为起点,较大的参数作为终点

let stringVal = "hello world";console.log(stringVal.slice(3)); // "lo world"console.log(stringVal.slice(3,7)); // "lo w" 下标7字符之前,下标3字符之后的字符console.log(stringVal.substring(3,7)); // "lo w" console.log(stringVal.substr(3,7)); // "lo worl" 要返回的子字符串长度为7,从下标3字符开始提取

当某个参数负数时:

slice():将所有负数参数都当成字符串长度+负数值

let stringVal = "hello world";console.log(stringVal.slice(-3)); // "rld" -3参数会被转换为长度11+(-3)=8 console.log(stringVal.slice(3, -4)); // "lo w" -4参数会被转换为长度11+(-4)=7,相当于slice(3,7)

substring():将所有负数参数都当成0

let stringVal = "hello world";console.log(stringVal.substring(-3)); // "hello world" -3参数会被转换为0console.log(stringVal.substring(3, -4)); // "hel" -4参数会被转换为0,相当于substring(3,0),这又等价于substring(0,3)

substr():将第个负参数值当成字符串长度+此值,第个负参数值当成0

let stringVal = "hello world";console.log(stringVal.substr(-3)); // "rld" -3参数会被转换成长度11+(-3)=8console.log(stringVal.substr(3, -4)); // "" 空字符串,因为-4参数被转换成0,也就是提取的字符串长度为0

5.4.3.4 定位子字符串位置的方法 indexOf() 、lastIndexOf()

indexOf()lastIndexOf()从字符串中搜索传入的字符串,并返回位置

(如果没找到,则返回-1)

区别在于:

indexOf()从字符串开头开始查找子字符串lastIndexOf()从字符串末尾开始查找子字符串

let stringVal = "hello world";console.log(stringVal.indexOf("o")); // 4console.log(stringVal.lastIndexOf("o")); // 7

indexOf()lastIndexOf()都接收可选的第二个参数,表示开始搜索的位置

像这样使用第二个参数并循环调用indexOf()lastIndexOf(),可以在字符串中找到所有的目标子字符串,如下所示:

let stringVal = "Pain makes us stronger";let positions = [];let pos = stringVal.indexOf("s");while(pos != -1) {positions.push(pos);pos = stringVal.indexOf("s", pos+1);}console.log(positions); // [9,12,14]

本例中,首先取得第一个"s"的位置,然后进入循环,将上一次的位置+1再传给indexOf()

将每一个"s"的位置都保存在positions数组中

5.4.3.5 包含字符串的方法 startsWith()、endsWith()、includes()

ES6新增了3个用于判断字符串中是否包含另一个字符串的方法:

这些方法都会从字符串中搜索传入的字符串,并返回一个表示是否包含布尔值

区别在于:

startsWith():检查开始于索引0的匹配项endsWith():检查开始于索引string.length - substring.length的匹配项includes():检查整个字符串

let message = "foobarbaz";console.log(message.startsWith("foo")); // trueconsole.log(message.startsWith("bar")); // falseconsole.log(message.endsWith("baz")); // trueconsole.log(message.endsWith("bar")); // falseconsole.log(message.includes("bar")); // trueconsole.log(message.includes("qux")); // false

startsWith()includes()接收可选的第二个参数,表示开始搜索的位置,这两方法会从指定位置向字符串末尾搜索,忽略该位置前的所有字符endsWith()接收可选的第二个参数,表示应该当作字符串末尾的位置

let message = "foobarbaz";console.log(message.endsWith("bar", 6)); // true

5.4.3.6 trim() 方法

trim()方法会创建字符串的一个副本,删除前后所有空格符,再返回结果

let stringVal = " hello world ";let trimmedStringVal = stringVal.trim();console.log(stringVal); // " hello world "console.log(trimmedStringVal); // "hello world"

还有trimLeft():从字符串开始清理空格符

trimRight():从字符串末尾清理空格符

5.4.3.7 repeat() 方法

repeat()接收一个整数参数,表示要将字符串复制多少次,然后返回拼接所有副本后的结果

let stringVal = "ha ";console.log(stringVal.repeat(5)); // "ha ha ha ha ha "

5.4.3.8 padStart() 和 padEnd() 方法

padStart()padEnd()复制字符串,如果小于指定长度,则在相应一边填充字符,直至满足长度条件

这两个方法接收两个参数

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

let stringVal = "foo";console.log(stringVal.padStart(6)); // " foo"console.log(stringVal.padStart(9,"!")); // "!!!!!!foo"console.log(stringVal.padEnd(9,"!")); // "foo!!!!!!"

第二个参数并不限于一个字符,可提供多个字符的字符串,则会将其拼接截断匹配指定长度

如果长度小于等于字符串长度,则会返回原始字符串

let stringVal = "foo";console.log(stringVal.padStart(8, "bar")); // "barbafoo"console.log(stringVal.padStart(2)); // "foo"

5.4.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 letter of "abc") {console.log(letter);}// a// b// c

有了这个迭代器之后,字符串就可以通过解构操作符来解构了,比如更方便地把字符串分割为字符数组:

let message = "abc";console.log([...message]); // ["a", "b", "c"]

5.4.3.10 字符串大小写转换

toLowerCase()

toLocaleLowerCase()

toUpperCase()

toLocaleUpperCase()

let stringValue = "hello world";console.log(stringValue.toLocaleUpperCase()); // "HELLO WORLD" console.log(stringValue.toUpperCase()); // "HELLO WORLD" console.log(stringValue.toLocaleLowerCase()); // "hello world" console.log(stringValue.toLowerCase()); // "hello world"

toLocaleLowerCase()toLocaleUpperCase()方法旨在基于特定地区实现

在很多地区,地区特定的方法与通用的方法是一样的。但在少数语言中(如土耳其语),要使用地区特定的方法才能实现正确转换

5.4.3.11 字符串模式匹配方法

String类型为在字符串中实现模式匹配提供了几个方法

match():本质上跟RegExp对象的exec()方法相同match()方法接收一个参数,可以是一个正则表达式字符串,也可以是一个RegExp对象

let text = "cat, bat, sat, fat";let pattern = /.at/;let matches = text.match(pattern); console.log(matches.index); // 0 console.log(matches[0]); // "cat" console.log(pattern.lastIndex); // 0

match()返回的数组exec()返回的数组是一样的:第个元素是与整个模式匹配字符串,其余元素则是与表达式中的捕获组匹配的字符串(如果有的话)

search():接收唯一的参数,可以是一个正则表达式字符串,也可以是一个RegExp对象 返回模式第一个匹配的位置索引,没找到返回-1search()始终从字符串开头向后匹配模式

let text = "cat, bat, sat, fat";let pos = text.search(/at/);console.log(pos); // 1 即"at"的第一个字符在字符串中的位置

5.4.3.12 replace()

为简化子字符串替换操作,ECMAScript 提供了replace()方法

接收两个参数第一个参数可以是一个RegExp 对象或一个字符串(这个字符串不会转换为正则表达式)第二个参数可以是一个字符串一个函数

let text = "cat, bat, sat, fat";let result = text.replace("at", "ond");console.log(result); // "cond, bat, sat, fat"

如果第个参数是字符串,那只会替换第一个子字符串

要想替换所有子字符串,第个参数必须为正则表达式并且带全局标记

let text = "cat, bat, sat, fat";let result = text.replace(/at/g, "ond");console.log(result); // "cond, bond, sond, fond"

5.4.3.13 split()

最后一个与模式匹配相关的字符串方法是split()

这个方法会根据传入的分隔符将字符串分成数组

接收两个参数第一个参数作为分隔符,可以是字符串,也可以是RegExp对象第二个可选参数是数组的大小,确保返回的数组不会超过指定大小

let colorTxt = "red, blue, green";let color1 = colorTxt.split(","); // ["red", "blue", "green"]let color2 = colorTxt.split(",", 2); // ["red", "blue"] 这里限制了数组长度为2

5.4.3.14 localeCompare()

localeCompare()比较两个字符串,返回如下3个值中的一个

如果按照字母表顺序,字符串应该排在字符串参数前面,则返回负值(通常是-1)如果字符串与字符串参数相等,则返回0如果按照字母表顺序􏰁,字符串应该排在字符串参数后面,则返回正值(通常是1)

let stringValue = "yellow";console.log(stringValue.localeCompare("brick")); // 1console.log(stringValue.localeCompare("yellow")); // 0console.log(stringValue.localeCompare("zoo")); // -1

"brick"按字母表顺序􏰁应该排在"yellow"前头,因此localeCompare()返回 1

5.5 单例内置对象

ECMA-262 对内置对象的定义是:

“任何由 ECMAScript 实现提供、与宿主环境无关,并在 ECMAScript 程序开始执行时存在的对象”

这意味着:开发者不用显式地实例化内置对象,因为它们已经实例化好了

前面我们已经解除了大部分内置对象,包括ObjectArrayString

这里要介绍另外两个单例内置对象:GlobalMath

5.5.1 Global

Global对象最特别,因为代码不会显式地访问它

全局作用域中定义的变量和函数都会变成Global对象的属性,前面介绍的函数包括isNaN()isFinite()parseInt()等,实际上都是Global对象的方法

Global对象上还有一些其他方法:

5.5.1.1 URL编码方法

encodeURI()encodeURIComponent()

用于编码统一资源标识符(URI),以传给浏览器

有效的URI不能包含某些字符,比如空格

encodeURI():对整个URI进行编码,比如"/illegal value.js"encodeURIComponent():对URI单独的组件进行编码,比如前面URL中的"illegal value.js"

区别在于:

encodeURI()不会编码属于URL组件的特殊字符,比如冒号斜杠问号并号encodeURIComponent()会编码它发现的所有非标准字符

let uri = "/illegal value.js#start";console.log(encodeURI(uri));// "/illegal%20value.js#start"console.log(encodeURIComponent(uri));// "http%3A%2F%%2Fillegal%20value.js%23start"

本例中,使用encodeURI()编码,只有空格被替换为%20,而使用encodeURIComponent()编码,所有非字母字符都替换成了相应的编码形式

encodeURI()encodeURIComponent()相对的是decodeURI()decodeURIComponent()

decodeURI()只对使用encodeURI()编码过的字符解码decodeURIComponent()解码所有被encodeURIComponent()编码的字符,基本上就是解码所有特殊值

5.5.1.2 eval()

eval()是一个完整的ECMAScript解释器

接收一个参数,即要执行的JavaScript字符串

eval("console.log('hi')");// 等效于console.log('hi');

解释器发现eval()调用时,会将参数解释为实际的 ECMAScript 语句,然后将其插入到该位置

5.5.1.3 Global 对象属性

5.5.1.4 获取Global对象

通过window对象,

浏览器将window对象实现为Global对象的代理,因此所有全局作用域中声明的变量和函数都变成了window的属性另一种获取Global对象的方式:

let global = function() {return this;}();

这段代码创建了一个立即调用的函数,返回了this的值

当一个函数在没有明确成为某个对象的方法,或通过call() / apply() 指定this值的情况下执行的时候,this值就是Global对象

5.5.2 Math

5.5.2.1 Math对象的属性

5.5.2.2 min() 和 max()

min()max()用于确定一组数值中的最小值最大值

接收任意多个参数

let max = Math.max(3, 54, 32, 16);console.log(max); // 54let 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(...val);

5.5.2.3 舍入方法

把小数值舍入为整数:

Math.ceil():始终向舍入为最接近整数Math.floor():始终向舍入为最接近整数Math.round():四舍五入Math.fround():返回数值最接近的单精度(32 位)浮点值表示

5.5.2.4 random() 方法

Math.random()方法返回一个0~1范围内的随机数包含0但不包含1

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

number = Math.floor(Math.random() * totalNumber + minVal)

totalNumber为可选的总数,minVal为最小的可能值

这里使用了Math.floor()方法,因为Math.random()始终返回小数

因此,如果想从1~10范围内随机选择一个数:

可选的总数有10个值,最小的可能值为1

let num = Math.floor(Math.random() * 10 + 1);

5.5.2.5 其他方法

5.6 小结

js中的对象称为引用值,几种内置的引用类型可用于创建特定类型对象

引用类型相似,但实现不同Date引用类型提供关于日期和时间的信息RegExp引用类型是支持正则表达式的接口

js比较独特的一点是:函数实际上是Function类型的实例,也就是说函数也是对象。因

为函数也是对象,所以函数也有方法,可以用于增强其能力。

由于原始值包装类型,js中的原始值可以被当成对象使用,有3种原始值包装类型

BooleanNumberString每种包装类型都映射到同名的原始类型以读模式访问原始值时,后台会实例化一个原始值包装类型的对象,借助这个对象可以操作响应的数据涉及原始值的语句执行完毕后,包装对象就会被销毁

当代码开始执行时,全局上下文中会存在两个内置对象:GlobalMath

Global对象无法直接访问,但浏览器将其实现为window对象,所有全局变量和函数都是Global对象的属性

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。