第5章 原生对象
本章主要内容
● Object对象
● Math对象
● 字符串对象
● 数组对象
● 日期对象
● 正则
● Set数据结构
● Map数据结构
对象分为内置对象(如Math)、本地对象(如String、Array)和宿主对象(BOM和DOM),本章将对这些内容进行详细介绍。
5.1 Object对象
Object是JavaScript 中常用的一个数据类型,并且在JavaScript 中所有的对象都是继承自 Object 对象。在对象一章中只是简单地用Object 结合new 构造函数来创建一个对象,并没有过多地使用。但是Object对象其实包含了很多有用的属性和方法。因此,本节将从最基本的开始详细介绍Object对象常用的方法以及应用。
5.1.1 Object的常用方法
1.Object.create()
在ECMAScript 5 中定义了名为Object.creat()的方法,该方法可以创建一个拥有指定原型和若干个指定属性的对象。其中第一个参数是要继承的原型,如果不是一个子函数,则可以传入一个null,第二个参数是对象的属性描述符,这个参数是可选的。
Object.create()是一个静态函数,而不是提供给某个对象调用的方法,只需传入所需的原型对象和属性描述即可。
在JavaScript中,属性有两种类型,分别是数据属性和访问器属性。
(1)数据属性
数据属性可以理解为平时定义对象时赋予的属性,它可以进行读和写。但是,ES5中定义了一些特性,这些特性用来描述属性的各种特征,特性是内部值,不能直接访问到。属性的特性会有一些默认值,要修改特性的默认值,必须使用ES5定义的新方法(Object.defineProperty方法)来修改。下面具体介绍每个特性。
1)writable:表示属性值是否可修改,默认为true。
2)value:表示属性的值,默认为undefined。
示例:
说明:上述示例中,通过value 这个特性,可以设定对象的默认值,且当writable 属性设置为false时,对象的属性值是不可以修改的。
3)configurable:该特性表示是否能够通过delete操作符删除属性,默认值为true。
示例:
说明:在上述示例中,创建一个对象obj,并且给它添加属性name,通过delete操作符删除name属性后,就访问不到name属性了。
示例:
说明:在上述示例中,创建了一个拥有指定原型 obj 的newObj 对象,并且设置configurable特性为false,最后发现依然能访问到name属性。
4)enumerable:表示是否能用for in 枚举出属性,默认值为true。
示例:
说明:在上述示例中,可以通过for in 语句枚举obj对象的属性。
示例:
说明:在上述示例中创建了一个拥有指定原型obj的newObj对象,并且设置enumerable特性为false,发现通过for in 语句不能枚举newObj对象的属性,但当设置为true时则可以。
(2)访问属性
1)get():表示访问。
2)set():表示设置。
示例:
说明:在上述示例中通过方法Object.creat()创建了一个拥有指定原型 obj 的对象newObj,通过设置不同的属性描述符,可以实现不同的操作,得到不同的结果。
2.Object.is()
它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致,不同之处只有两个:一是+0不等于-0,二是NaN等于自身。
示例:
3.Object.assign()
Object.assign 方法用于对象的合并,将原、源对象(source)的所有可枚举属性复制到目标对象(target)上。
Object.assign方法的第一个参数是目标对象,后面的参数都是源对象。
示例:
如果目标对象与源对象具有同名属性,或多个源对象具有同名属性,则后面的属性会覆盖前面的属性。
示例:
如果只有一个参数,Object.assign方法会直接返回该参数。
示例:
如果该参数不是对象,则会先转成对象,然后返回。
示例:
由于undefined和null无法转成对象,因此如果它们作为参数,就会报错。
示例:
Object.assign方法执行的是浅复制,而不是深复制。
示例:
4.Object.getOwnPropertyDescriptors()
此方法用于返回某个对象属性的描述对象。
示例:
5.1.2 属性的遍历(Object对象方法的使用)
1. 属性的可枚举性
对象的每个属性都有一个描述对象(Descriptor)用来控制该属性的行为。Object.getOwnPropertyDescriptor方法可以获取该属性的描述对象。
描述对象的enumerable 属性,称为“可枚举性”,如果该属性为false,则表示某些操作会忽略当前属性。
1)for...in循环:只遍历对象自身的和继承的可枚举的属性。
2)Object.keys():返回对象自身的所有可枚举的属性的键名。
3)JSON.stringify():只串行化对象自身的可枚举的属性。
4)Object.assign():只复制对象自身的可枚举的属性。
2. 遍历的方式
ES6中一共有5种方法可以遍历对象的属性。
(1)for...in
for...in循环遍历对象自身的和继承的可枚举属性(不含Symbol属性)。
(2)Object.keys(obj)
Object.keys 返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含Symbol属性)。
(3)Object.getOwnPropertyNames(obj)
Object.getOwnPropertyNames返回一个数组,包含对象自身的所有属性(不含Symbol属性,但是包括不可枚举属性)。
(4)Object.getOwnPropertySymbols(obj)
Object.getOwnPropertySymbols返回一个数组,包含对象自身的所有Symbol属性。
(5)Reflect.ownKeys(obj)
Reflect.ownKeys 返回一个数组,包含对象自身的所有属性,不管是属性名或Symbol 或字符串,也不管是否可枚举。
通过以上5种方法遍历对象的属性,都遵守同样的属性遍历的次序规则,具体如下:
1)首先遍历所有属性名为数值的属性,按照数字排序。
2)其次遍历所有属性名为字符串的属性,按照生成时间排序。
3)最后遍历所有属性名为Symbol值的属性,按照生成时间排序。
5.2 Math对象
JavaScript 自身有很多内置的对象,Math 就是其中之一,但是相比较其他的内置对象,Math对象可以用于执行数学任务,如获取一个随机数、画一个圆等。
Math是JavaScript本来就存在的对象,即内置对象,它具有数学常数和函数的属性与方法。Math 对象不像Date 和String 是对象的类,因此没有构造函数,也不需要实例化,它所有的属性和方法都是静态的,只需把Math作为对象使用即可。
5.2.1 Math对象的属性
1)Math.PI:圆周率。
2)Math.E:返回欧拉常数e的值。
3)Math.LN2:返回2的自然数对数。
5.2.2 Math对象的方法
Math对象的方法具体见表5-1。
表5-1
(1)abs()
abs()用于返回一个数的绝对值。
示例:
(2)round()、floor()、ceil()和trunc()
1)round()用于对一个数进行四舍五入。
2)floor()用于对一个数进行向下取整。
3)ceil()用于对一个数进行向上取整。
4)trunc()用于返回一个数的整数部分,去除小数。
示例:
如果参数是一个正数,则trunc()相当于floor();否则trunc() 相当于ceil()。
(3)max()和min()
max()和min()用于取一组数中的最大值和最小值。
示例:
(4)random()
random()用于取一个随机数。
示例:
(5)pow(x,y)和sqrt()
pow(x,y)用于取x的y次幂,sqrt()用于获取一个数的平方根。
示例:
(6)sin()、cos()、tan()、asin()、acos()和atan()
使用时,需要将角度转化为弧度才能进行计算,在JavaScript中,用Math.PI表示π,转换公式为1deg=Math.PI/180。
示例:
5.3 字符串对象
String 对象也是JavaScript 内置对象之一。当操作的数据是文本形式的数据时,用字符串对象处理再合适不过了。下面介绍有关字符串对象的创建,以及其具有的属性和方法。
5.3.1 创建String对象
创建String对象的语法格式如下:
通过构造函数会返回一个新创建的String对象,用来存放字符串s:
不通过构造函数调用String()时,它只把s转换成原始的字符串,并返回转换后的值。
5.3.2 字符串对象的属性
1)constructor:用于返回构造函数的引用。
2)length:用于计算字符串的长度。
示例:
说明:在上述示例中,通过调用String对象的length属性,可以很方便地获得该字符串的长度。
5.3.3 字符串对象的方法
字符串对象的方法可以大致分为获取、查找、截取、转换4种类型。接下来将一一进行介绍。
获取类型有以下3种:
(1)mystr.charAt(index);
charAt方法用来返回指定索引位置(index)的字符串,若是超出有效范围的索引值,将返回空字符串。
示例:
说明:需要注意index下标的有效范围是从0开始到str.length-1。
(2)mystr.charCodeAt(index);
charCodeAt方法返回指定位置字符的Unicode编码。
示例:
(3)String.fromCharCode(code1 [,code2...]);
fromCharCode是一个静态方法,它存储在内存的静态区中,一直存在,直接使用即可。
fromCharCode方法接收一个(或多个)指定的Unicode 值,然后返回一个(或多个)对应的字符串。
示例:
查找类型有以下5种:
(1)mystr.indexOf(str [,startIndex]);
indexOf方法返回指定字符在字符串中第一次出现的位置。如果字符不存在,则返回-1。
示例:
说明:当指定startIndex 的值时,会从指定位置开始起查找指定的字符串,否则从字符串的开始位置查找。
(2)mystr.lastIndexOf(str [,startIndex]);
lastIndexOf 方法返回指定字符在字符串中最后一次出现的位置。如果字符串不存在,则返回-1。
示例:
说明:若指定了startIndex的值,则作用与indexOf方法一样。
(3)mystr.match(str);
match 方法用于在字符串内检测指定的值,或查找一个或多个正则表达式的匹配,该方法类似于indexOf和lastIndexOf方法,但是返回指定的值,没有则返回null,而不是返回字符串的位置。
示例:
(4)mystr.search(reExp);
search方法返回与正则表达式查找内容相匹配的第一个字符串的位置,只能用于正则。
示例:
说明:reExp包含正则表达式模式和可用标志的正则表达式对象。
(5)mystr.replace(str/regExp,replacement);
replace方法用于将字符串中的一些字符替换成另外的字符,或替换一个与正则表达式匹配的字符串。返回结果为新字符串,不影响原字符串。
示例:
截取类型有以下3种:
(1)mystr.slice(start [,end]);
slice方法返回从指定位置开始截取,到指定位置结束(不包括)的字符串;start下标从0开始;如果没有指定结束位置,则从指定位置开始截取,到末尾结束;它可以接收负值,-1表示字符串的结尾。
示例:
(2)mystr.substring(start,end);
substring 方法返回从指定位置开始截取,到指定位置结束的字符串(不包括);如果没有指定结束位置,则从指定位置开始截取,到末尾结束;它接收到的负值会自动转换为0。
示例:
(3)mystr.substr(start [,length]);
substr方法返回从指定位置开始截取指定长度的字符串,如果没有指定长度,则从指定位置截取,到末尾结束;不支持负数。
示例:
说明:在上述示例中,当指定length字符个数时,会从指定的位置开始输出一定个数的字符。
转换类型有以下7种:
(1)mystr.split("以什么分割"[,limit]);
split方法将一个字符串分割成数组,limit用来限制返回数组中元素的个数。
示例:
(2)toLowerCase();
toLowerCase方法用于把字符串中的字母转换为小写,并返回一个字符串。
示例:
(3)toUpperCase();
toUpperCase方法用于将字符串中的字母转换为大写,并返回一个字符串。
示例:
(4)trim();
trim方法用于删除字符串两边的空格。
示例:
(5)charCodeAt();与codePointAt();
在JavaScript 内部,字符以UTF-16 的格式储存,每个字符固定为两个字节。对于那些需要4 个字节储存的字符(Unicode 码点大于0xFFFF 的字符),JavaScript 会认为它们是两个字符。
示例:
说明:上述示例中,汉字“吉”不是吉利的“吉”,是“吉”的异体字,码点为0x20BB7。需要4 个字节的字符存储。通过方法charCodeAt()分别返回了前两个字节和后两个字节的值。
ES6提供了codePointAt方法,能够正确处理4个字节储存的字符,返回一个字符的码点。
上述示例中,codePointAt方法正确返回了汉字“吉”的码点。
因此,对于32位的UTF-16字符的码点,通过codePointAt方法能够正确返回。对于常规的两个字节存储的字符,codePointAt方法和charCodeAt方法相同。
(6)String.fromCharCode();与String.fromCodePoint();
ES6提供了String.fromCodePoint方法,它与ES5中的String.fromCharCode方法一样,用于从码点返回对应的字符。不同之处在于,String.fromCodePoint 方法可以识别 0xFFFF 的字符,弥补了String.fromCharCode方法的不足。在作用上,正好与codePointAt方法相反。
示例:
示例输出结果如图5-1所示。
图5-1
如果String.fromCodePoint方法有多个参数,则它们会被合并成一个字符串返回。
(7)repeat();
repeat方法返回一个新字符串,表示将原字符串重复n次。
示例:
5.4 数组对象
Array 数组对象也是JavaScript 的内置对象之一,常用于在单个变量中存储多个值,且允许数组中含有不同数据类型的元素,即数组元素可以是对象或其他的数组。
5.4.1 数组对象的属性
1)length:返回或设置数组元素的个数。因为数组的索引总是从0开始,所以一个数组的下标范围是从0到length-1。再次注意,JavaScript数组的length属性是可变的。
示例:
2)prototype属性:返回对象类型原型的引用。
示例:
3)constructor属性:表示创建对象的函数。
示例:
5.4.2 数组对象的方法
在数组中有很多预定义的方法,接下来按照分类一一进行介绍。
添加或删除类有以下5种:
(1)myarr.push(元素1,元素2,…);
push方法用来向数组的末尾添加元素,返回值为新数组的长度;一次可以添加多个元素。
示例:
说明:通过push 方法返回的是新数组的长度,当再次访问数组时返回的是添加后的结果,说明push方法会影响原数组。
(2)myarr.unshift(元素1,元素2,…);
unshift 方法用来向数组的开头添加元素,返回值为新数组的长度;一次可以添加多个元素。
示例:
说明:在上述示例中,返回一个新的数组,说明unshift方法也会影响原数组。
(3)myarr.pop();
pop方法用来删除数组中的最后一个元素,返回值为删除的元素。
示例:
说明:在上述示例中,返回来一个新的数组,说明pop方法也会影响原数组。
(4)myarr.shift();
shift方法用来删除数组的第一个元素,返回值为删除的元素。
示例:
说明:在上述示例中,说明shift方法也会影响原数组。
(5)myarr.splice(index,数量,item1,item2...);
splice方法用来删除、添加或替换数组中的元素,是个“万能”的方法。
index:表示从哪里开始删除或添加,必须是数值类型的(从0开始计算)。
数量:规定了删除的个数,如果为0,则表示不删除,否则表示添加。
示例:
说明:当用splice 方法删除或替换元素时,会返回被删除的元素;当用splice 方法插入元素时,会返回一个空数组。
数组的转换方法如下:
join 方法用于将数组按照指定的分隔符转换为字符串,如果没有分隔符,则默认为以“,”来分隔。返回值为组成的字符串。
示例:
说明:在上述示例中,使用了不同的分隔符。
数组的截取方法如下:
slice 方法从已有的数组中返回选定的元素,即从指定位置开始截取,到指定位置(不包括)结束。如果没有指定结束位置,则从指定位置开始,到末尾结束。支持负数(从-1 开始),返回值为新数组,不会破坏原数组。
示例:
说明:在上述示例中,当操作后再次返回数组arr时,还是原数组,表明slice方法不会影响原数组。
数组的连接方法如下:
concat方法用于连接两个或更多个数组,并返回新数组。该方法不会影响原数组。
示例:
数组的排序方法如下:
sort方法用于对数组中的元素进行排序。排序顺序可以按照字母顺序或数字顺序,并按升序或降序排列。如果没有参数,则从字符的编码开始按照顺序排列。
如果有参数,则这个参数必须是一个函数(回调函数)。这个回调函数有两个参数,即a、b。
示例:
说明:在上述示例中,sort 排序默认为升序。当元素为字符串时,会比较每个元素对应的Unicode编码大小并进行排序。
示例:
说明:在上述示例中,通过回调函数来设置数组排序的规则是升序还是降序。
数组的过滤方法如下:
filter方法会创建一个新数组,新数组中的元素为通过检查指定数组中符合条件的所有元素。在回调函数中定义判断条件,返回值为所有判断结果为真的值组成的新数组。
示例:
数组的映射方法如下:
map 方法会返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值,即在回调函数中返回新值。
示例:
说明:在上述示例中,在回调函数中返回了新值,map 方法的返回值为回调函数中返回的新值组成的新数组。
数组的查找有以下两种方法:
(1)indexOf(item)
indexOf 用来返回数组中某个指定的字符串值第一次出现的位置,从指定位置起从前向后搜素。若没有找到,则返回-1。
如果没有指定起始位置,将从字符串的开始位置查找。
indexOf 方法最基本的思想还是先循环整个数组,将每次循环出来的结果与要查找的元素进行匹配,最终返回我们想要的结果。接下来先从for循环入手,实现元素的查找。
示例:
万变不离其宗,indexOf方法还是基于for循环的思想,只不过使用起来更加方便。下面再用indexOf方法实现上个示例。
示例:
说明:在上述示例中,indexOf方法实现的原理机制和for循环机制一样。
(2)lastIndexOf(item)
lastIndexOf 方法返回数组中某个指定的字符串值最后一次出现的位置,和indexOf 方法正好相反。
示例:
说明:在上述示例中,通过lastIndexOf方法从头到尾地检索,看数组中是否包含1,如果找到,则返回1在数组中最后一次出现的位置。
数组的判断有以下两种方法:
(1)every()
every 方法用来检测数组中的每一项元素是否符合条件,即在回调函数中进行判断,如果有一个元素不满足条件,则整个表达式返回false,且其他元素将不再进行判断;如果所有元素都满足条件,则返回true。注意,every方法不会对空数组进行检测。
既然 every 方法是检测数组中的每一个元素,那么此处还是先用for 循环来切入,方便大家理解记忆。
示例:
接下来再用every方法实现一下:
说明:通过以上两个示例可以发现,every方法的实现原理还是for循环。
(2)some(function(item,index){})
some 方法用于检测数组中的每一个元素是否满足指定的条件,即在回调函数中对每个元素依次进行判断,如果有一个元素满足条件,则表达式将返回true,且其他元素将不再进行判断;如果没有满足条件的元素,则返回false。注意,some 方法不会对空数组进行检测。
同理,此处读者也可以尝试用for循环先实现一下。
用some方法实现,示例如下:
说明:在上述示例中,通过some 方法可以检测数组中是否有元素小于3,并不会改变原始数组。
数组的转换有以下两种方法:
(1)Array.from()
Array.from 方法用于将两个类对象转换为真正的数组,即类似数组的对象(array-like object)和可遍历(iterable)的对象。
示例:
Array.from方法可以处理NodeList对象和arguments对象。
示例:
(2)Array.of()
Array.of方法用于将一组值转换为数组。
示例:
这个方法的主要目的是弥补数组构造函数Array()的不足。
示例:
5.4.3 数组对象的构造函数的方法
1)Array.from 方法用于将两类对象转换为真正的数组,即类似数组的对象和可遍历的对象。
示例:
2)Array.of 方法用于将一组值转换为数组。Array.of 方法总是返回参数值组成的数组。如果没有参数,则返回一个空数组。
示例:
3)Array.isArray方法用于判断某个值是否为数组,返回的值为布尔类型。
示例:
5.5 日期对象
现如今,无论是网页中还是一个游戏中,都会涉及对时间的处理,JavaScript 专门提供了日期对象。
Date对象是JavaScript提供的日期和时间的接口操作,在JavaScript中DATE使用UTC(国际协调时间),它能够表示的时间范围是1970年1月1日00:00:00前后的各一亿天,之前为负,之后为正,取值范围为285616年。
日期也是JavaScript 的一个内置对象,若想对日期进行获取和操作,就必须实例化对象。
5.5.1 定义日期对象
使用关键字new来定义一个Date对象,语法格式如下:
说明:日期对象会自动获取当前的日期和时间作为初始值,包括年、月、日、时、分、秒、星期、时区。
当传入参数时,即得到时间参数。可传入的参数格式如下:
"时:分:秒 月/日/年"或"月/日/年时:分:秒"或字符串。
年,月,日,时,分,秒,不能加""。
不传参会得到当前时间的信息。
Date对象可以作为普通函数直接调用,返回一个代表当前时间的字符串。
示例:
5.5.2 获取日期信息的方法
一般在项目中会获取一下时间相关的信息,表5-2所示是常用的获取日期信息的方法。
表5-2
(续)
5.5.3 设置日期的方法
设置日期的方法见表5-3。
表5-3
表5-2 和表5-3 列出了常用的操作日期的方法,通过Date 对象可以很方便地对日期进行操作,下面通过示例深入理解日期对象的用法。
在下面的示例中,通过setFullYear方法设置一个日期对象为指定的日期。
示例:
日期是可以进行比较的,下面获取当天的日期,与之前设置的日期进行比较。
示例:
下面对于日期对象的获取方法来展示一个示例:
对于日期对象的应用,在后续章节中将通过一些示例来更好地阐述。
5.6 正则
本节将重点介绍正则表达式,简单地说,正则表达式就是一个文本模式的匹配工具,在JavaScript 中,正则表达式一般被用来匹配字符串中的字符组合。但是为什么非得用正则表达式呢?下面通过一个示例来了解正则表达式在实际项目中的应用。
示例:
从上述示例中可知,如果不使用正则表达式,判断会比较麻烦,使用正则表达式则简单很多。
正则表达式虽然用起来比较简单,但是它的规则很多。
5.6.1 正则表达式的概念
正则表达式是一个描述字符模式的对象。简单地说,是一个用来描述或者匹配一系列符合某个语法规则的字符串的语言。在很多文本编辑器或其他工具里,正则表达式通常被用来检索、替换或拆分那些符合某个模式的文本内容。许多程序设计语言都支持利用正则表达式进行字符串操作。
5.6.2 应用场合
在实际项目开发中有很多场合都需要使用正则表达式,那么哪些场合下会用到正则呢?
1)数据验证。
2)文本替换。
3)内容检索。
4)过滤内容。执行字符串函数无法完成的特殊的匹配、拆分、替换功能等。
5.6.3 创建正则表达式
在JavaScript中,正则表达式是通过对象的方式来创建的,它有自己的方法。
1. 通过构造函数创建
通过构造函数创建表达式又称为显示的创建,即通过构造函数RegExp()来实现。语法格式如下:
构造函数RegExp()有两个参数要传,第一个参数为正则表达式,第二个参数是一个可选项,即模式修饰符。各个修饰符的含义如下:
1)g表示全局匹配,即匹配字符串中出现的所有模式。
2)i表示忽略字母大小写,即在匹配字符串时不区分字母大小写。
3)m表示进行多行匹配。
如下示例中都是有效的正则表达式。
通常将正则表达式字符串放在/RegExp/中间,//称为定界符。
匹配边界有以下两种情况:
(1)字符边界
1)^ 匹配字符串的开始。
2)$ 匹配字符串的结束,忽略换行符。
(2)单词边界限制
1)\b 匹配单词的边界。
2)\B 匹配除单词边界以外的部分。
2. 通过字面量方式创建
通过字面量方式创建又称为隐式创建,即将文字量的正则表达式赋值给一个变量。语法格式如下:
其中,正则表达式为指定的匹配模式,模式修饰符是可选项。
5.6.4 正则表达式的模式
1. 原子
原子是正则表达式中最小的元素,包括英文、标点符号等。每个原子都有自己特殊的含义,具体如下:
\d——匹配任意一个数字。
\D——与除了数字以外的任何一个字符匹配。
\w——与任意一个英文字母,数字或下画线匹配。
\W——除了字母,数字、下画线外,与任何一个字符匹配。
\s——与任意一个空白字符匹配。
\n——换行字符。
\f——换页字符。
\r——回车字符。
\t——制表符。
\v——垂直制表符。
\S——与除了空白符以外任意一个字符匹配。
2. 原子表
方括号可用于查找某个范围内的字符,具体如下:
[]——只匹配其中的一个原子。
[^]——匹配除了当前原子表中定义的原子外的字符。
[0-9]——匹配0~9中的任意一个数字。
[a-z]——匹配小写a~z中的任意一个字母。
[A-Z]——匹配大写A~Z中的任意一个字母。
3. 元字符
在正则表达式中有一些特殊字符,代表着特殊意义,叫作元字符。
. 代表除换行符以外的任何一个字符。
| 代表或的意思,匹配其中一项就代表匹配。
4. 原子分组
匹配多个字符时用()分组,分组代表一个原子集合或一个大原子,并压入堆栈(内存)用于调用。组号是从左到右计数的,调用时如果是字面量形式,则用\1;如果是构造函数方式,则用\1,这种方式称为反向引用。
示例:
5. 取消反向引用
使用形如(?:pattern)的正则就可以避免保存括号内的匹配结果,反向引用也将失效。
6. 量词
可以使用一些元字符,重复表示一些元子或元字符,具体如下:
*——重复零次或更多次。
+——重复一次或更多次。
?——重复零次或一次。
{n}——重复n次。
{n,}——重复n次或更多次。
{n,m}——重复n到m次。
7. 贪婪和吝啬
正则匹配是贪婪的,但并不意味着禁用,具体如下:
*?——重复任意次,但尽可能少重复。
+?——重复1次或更多次,但尽可能少重复。
??——重复0次或1次,但尽可能少重复。
{n,m}?——重复n到m次,但尽可能少重复。
{n,}?——重复n次以上,但尽可能少重复。
模式匹配的顺序(从高到低)见表5-4。
表5-4
5.6.5 正则方法
正则表达式对象RegExp提供了两个可用的方法:test()和exec()。
1.RegExp.test()
方法test()用来测试字符串中是否包含了匹配该正则表达式的子串,如果包含,则返回true,否则返回false。
示例:
说明:在上述示例中,使用正则表达式/uek/i 来检测str 字符串中是否包含匹配的子串,且匹配时不区分字母大小写。最终得到的结果是true,所以会返回并显示“找到了指定字符串”。
2.RegExp.exec()
方法exec()功能非常强大,是一个通用的方法,用来在字符串中匹配正则,并将结果保存在一个数组中即成功返回,失败返回null。
返回的数组包含特殊属性:
1)input表示被查找字符串。
2)index表示子字符串位置。
如果正则表达式没有设置g,那么exec方法不会对正则表达式有任何的影响。如果设置了g,那么exec执行后会更新正则表达式的lastIndex属性,表示本次匹配后所匹配的字符串的下一个字符的索引,下一次再用这个正则表达式匹配字符串时就会从上次的lastIndex属性开始匹配。
示例:
说明:方法exec()返回的数组对象还有一个扩展的属性,且这个属性在普通的数组中是没有的,这个属性是index,它返回的是匹配字符串的开始位置,除此之外,还有其他的扩展属性,示例如下:
说明:在上述示例中,通过方法exec()返回的数组对象扩展的属性可以获取更多详细的信息,最终返回结果为:“字符串长度为1;被搜索的字符串为abc de fg de;起始位置为4”。
5.6.6 字符串中用到正则的函数
在JavaScript中,正则表达式通常用于以下字符串方法:search()、replace()和split(),在字符串对象一节中也有提到过。
(1)search(regexp)
regexp 为正则表达式,返回索引位置,不支持全局索引(即g修饰符无效),找到即停止搜索。
示例:
说明:使用正则表达式搜索字符串Regexp,且不区分字母大小写。最终返回搜索字符串的起始位置7。
(2)replace(正则或字符串,替换内容)
支持全局g修饰符,如果模式不是全局,则当匹配到一个以后将不会继续匹配,反之则会继续往下匹配。
示例:
说明:在上述示例中,使用正则表达式且不区分字母大小写,将字符串中的Regexp 替换为UEK,最终返回的结果就是替换后的字符串“search UEK”。
(3)split 方法
split 方法用于拆分字符串,参数可以为字符串或正则表达式。
示例:
5.7 Set数据结构
5.7.1 Set基本用法
Set数据结构类似于数组,但是它的成员都是唯一的。
示例:
在函数Set()中可以传入一个数组类型的参数。
示例:
在Set 中判断是否重复,使用的是“Same-value equality”,类似于“===”,但是有例外,其中NaN不等于NaN。
示例:
5.7.2 Set属性和方法
1. 属性
1)Set.prototype.constructor:构造函数,默认是Set 函数。
2)Set.prototype.size:返回Set 实例的成员总数。
2. 方法
1)add(value):添加某个值,返回Set结构本身。
2)delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
3)has(value):返回一个布尔值,表示该值是否为Set的成员。
4)clear():清除所有成员,没有返回值。
示例:
5.7.3 Set遍历方法
Set 的遍历顺序就是插入顺序。
1)keys():返回键名的遍历器。
2)values():返回键值的遍历器。
由于Set 结构没有键名,只有键值(或者说键名和键值是同一个值),因此keys 方法和values方法完全一致。
3)entries():返回键值对的遍历器。
4)forEach():使用回调函数遍历每个成员。
示例:
5.7.4 WeakSet
WeakSet的成员只能是对象,不能是其他类型的值。
WeakSet 中的对象都是弱引用,垃圾回收机制不考虑 WeakSet 对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象是否还存在于WeakSet 中。这意味着,无法引用WeakSet 的成员,因此WeakSet是不可遍历的。
5.8 Map数据结构
JavaScript对象本质上是键值对的集合。之前,只能用字符串当作键。
Map 数据结构类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。
Object 结构提供了“字符串—值”的对应,Map结构提供了“值—值”的对应,是一种更完善的Hash结构实现。
所以需要“键值对”的数据结构时,Map比Object更合适。
5.8.1 Map 基本用法
1)Map 作为一个构造函数,可以接受一个数组当作参数。
2)Map 结构中,字符串“true”和布尔值true 是两个不同的键值。
示例:
只有对同一个对象的引用,Map结构才将其视为同一个键。所以下例中,set和get中的[1]不是同一个键。
虽然NaN不严格相等于自身,但Map将其视为同一个键。
示例:
5.8.2 Map 属性和方法
1. 属性
size属性用于返回Map结构的成员个数。
示例:
2. 方法
1)方法set()返回的是Map本身,因此也可以采用链式写法。
示例:
2)方法get()读取对应的键值,如果找不到传入的键值,则返回undefined。
示例:
3)方法has()返回一个布尔值,表示该键值是否在Map 结构中。
示例:
4)方法delete()用于删除某个键,删除成功,则返回true;如果删除失败,则返回false。
示例:
5)方法clear()用于清除所有成员,没有返回值。
示例:
5.8.3 Map 遍历方法
1)keys():返回键名的遍历器。
2)values():返回键值的遍历器。
3)entries():返回所有成员的遍历器。
示例:
5.8.4 Map与数组对象的转换
(1)Map转换为数组
示例:
(2)数组转换为Map
示例:
(3)Map转换为对象
如果所有Map的键都是字符串,则它可以转换为对象。
示例:
(4)对象转换为Map
示例:
5.8.5 WeakMap
WeakMap 结构与Map 结构基本类似,唯一的区别是它只接受对象作为键名(null 除外),不接受其他类型的值作为键名。
键名所指向的对象,不进入垃圾回收机制。
示例: