JavaScript高级程序设计4 第六章 集合引用类型
Object
创建Object实例的方式有两种:一种是使用new操作符和Object构造函数,另一种是使用对象字面量表示法。
属性名可以是字符串或数值。
属性可以通过点语法或中括号来存取。
Array
数组中每个槽位可以存储任意类型的数据。
使用数组字面量初始化数组时,可以使用一串逗号来创建空位
数组length属性独特之处在于他不是只读的,通过修改length属性,可以从数组末尾删除或添加元素。
通过Array.isArray()方法来检测一个值是否为数组。
keys()返回数组索引的迭代器,values()返回数组元素的迭代器,而entries()返回索引/值对的迭代器
创建数组
- 使用Array构造函数
- 如果知道数组中元素数量,可以给构造函数传入一个数值,然后length属性就会被自动创建并设置为这个值。
- 使用数组字面量表示法,使用数组字面量表示法创建数组不会调用Array构造函数
- 使用from()将类数组结构转换为数组实例
- Array.from()的第一个参数是一个类数组对象,即任何可迭代的机构,或者有一个length属性和可索引元素的结构。
- Array.from()可对现有数组执行浅复制
- Array.from()还可接收第二个可选的映射函数参数,这个函数可以增强新数组的值
- Array.of()可以把一组参数转换为数组
复制和填充方法
fill()方法可以向一个已有的数组中插入全部或部分相同的值。开始索引用于指定开始填充的位置,它是可选的。如果不提供结束索引,则一直填充到数组末尾。
copyWithin()按照指定范围浅复制数组中的部分内容,然后将他们插入到指定索引开始的位置。参数一表示插入到当前索引位置,参数二表示从当前索引开始复制,参数三表示复制到当前索引
转换方法
toString()返回由数组中每个值的等效字符串拼接而成的一个逗号分隔的字符串。也就是说对数组中每个值都会调用其toString()方法。
join()方法接收一个参数,即字符串分隔符,返回包含所有项的字符串
如果数组中某一项是null或undefined,则在join()、toLocaleString()、toString()和valueOf()返回的结果中会以空字符表示。
栈方法
push()方法接收任意数量的参数,并将他们添加到数组末尾,返回数组的最新长度
pop()方法则用于删除数组的最后一项,同时减少数组的length值,返回被删除的项
队列方法
shift(),他会删除数组的第一项并返回他,然后数组长度减一
unshift()在数组开头添加任意多个值,然后返回新的数组长度
排序方法
reverse()将数组元素位置反转
sort()默认会按照升序重新排列数组元素,即最小的值在前面,最大的值在后面。为此sort()会在每一项上调用String()转型函数,然后比较字符串来决定顺序,即使元素都是数值,也会先把数组转换为字符串再比较、排序。sort()方法可以接收一个比较函数,用于判断哪个值应该排在前面。比较函数接收两个参数,如果第一个参数应该排在第二个参数前面,就返回负值;如果两个参数相等,就返回0;如果第一个参数应该排在第二个参数后面,就返回正值。
reverse()和sort()都返回调用他们的数组的引用。
操作方法
concat()方法可以在现有数组全部元素基础上创建一个新数组。他首先会创建一个当前数组的副本,然后再把它的参数添加到副本末尾,最后返回这个新数组。concat()方法可以把参数数组打平,打平数组参数的行为可以重写,方法是在参数数组上指定一个特殊符号:Symbol.isConcatSpreadable。这个符号能阻止concat()打平参数数组。
slice()用于创建一个包含原有数组中一个或多个元素的新数组。slice()方法可以接收一个或两个参数:返回元素的开始索引和结束索引。如果只有一个参数,则返回该索引到数组末尾的所有元素。如果有两个参数,则返回从开始索引到结束索引对应的所有元素,其中不包含结束索引对应的元素。 这个操作不影响原始数组。
splice()的只要目的是在数组中间插入元素
- 删除,需要给splice()传入2个参数:要删除的第一个元素的位置和要删除的元素数量,可以从数组中删除任意多个元素。
- 插入。需要给splice()传3个参数:开始位置、0(要删除的元素数量)和要插入的元素,可以在数组中指定的位置插入元素。
- 替换。splice()在删除元素的同时可以在指定位置插入新元素,同样要传入3个参数:开始位置、要删除元素的数量和要插入的任意多个元素。
搜索和位置方法
indexOf()和lastIndexOf()都返回要查找的元素在数组中的位置,如果没有找到则返回-1。includes()返回布尔值。在比较第一个参数跟数组每一项时,会使用全等(===)比较,也就是说两项必须严格相等。
find()和findIndex()方法使用了断言函数。这两个方法都是从数组的最小索引开始。find()返回第一个匹配的元素,findIndex()返回第一个匹配元素的索引。这两个方法也都接收第二个可选参数,用于指定断言函数内部this的值。
迭代方法
- every():对数组每一项都运行传入的函数,如果对每一项函数都返回true,则这个方法返回true
- filter():对数组每一项都运行传入的函数,函数返回true的项会组成数组之后返回
- forEach():对数组中的每一项都运行传入的函数,没有返回值
- map():对数组中每一项都运行传入的函数,返回由每次函数调用结果构成的数组
- some():对数组每一项都运行传入的函数,如果有一项函数返回true,则这个方法返回true
归并方法
reduce()和reduceRight(),两个方法都会迭代数组中的所有项,并在此基础上构建一个最终返回值。
Map
使用new关键字和Map构造函数可以创建一个空映射,如果想在创建的同时初始化实例,可以给Map构造函数传入一个可迭代对象,需要包含健/值对数组。
使用set()为现有实例添加健/值对,使用get()和has()进行查询,通过size属性获取映射中的健/值对的数量,使用delete()和clear()删除值。
set()方法返回映射实例,可以把多个操作连缀起来
Map可以使用任何JavaScript数据类型作为健。
顺序与迭代
Map实例会维护健值对的插入顺序,因此可以根据插入顺序执行迭代操作
遍历过程中健值可修改,但不会影响Map实例本身
选择Object还是Map
-
内存占用
给定固定大小的内存,Map大约可以比Object多存储50%的健/值对。
-
插入性能
向Object和Map中插入新健/值对的消耗大致相当,不过插入Map在所有浏览器中一般会稍微快一点。
-
查找速度
大型Object和Map中查找健/值对的性能差异极小,只包含少量健/值对,则Object有时候速度更快。把Object当成数组使用的情况下(比如使用连续整数作为属性),浏览器引擎可以进行优化,在内存中使用更高效的布局。
-
删除性能
Map的删除性能更好。
WeakMap
弱引用,即垃圾回收机制不考虑 WeakMap 对该对象的引用,如果没有其他的变量或属性引用这个对象值,则这个对象将会被垃圾回收掉(不考虑该对象还存在于 WeakMap 中),所以,WeakMap 对象里有多少个成员元素,取决于垃圾回收机制有没有运行,运行前后成员个数可能不一致,遍历结束之后,有的成员可能取不到了(被垃圾回收了)
弱映射中的健只能是Object或者继承自Object的类型,尝试使用非对象设置健会抛出TypeError。值得类型没有限制。
因为WeakMap中的健/值对任何时候都可能被销毁,所有实例无法迭代。
WeakMap实例之所以限制只能用对象作为健,是为了保证只有通过健对象的引用才能取得值。如果允许原始值,那就没办法区分初始化时使用的字符串字面量和初始化之后使用的一个相等的字符串了
Set
使用new关键字和Set构造函数创建,如果想在创建的同时初始化实例,可以给Set构造函数传入一个可迭代对象,其中需要包含插入到新集合实例的元素。
使用add()增加值,使用has()查询,通过size取得元素数量,使用delete()和clear()删除元素。
Set可以包含任何JavaScript数据类型作为值。