JavaScript(三)集合引用类型

本文最后更新于:8 个月前

集合引用类型(数组Array、Map、Set)。引用类型是把数据和功能组织到一起的结构,引用值(或者对象)是某个特定引用类型的实例。基本类型不存在引用一说

JavaScript(三)集合引用类型

一、数组Array

1.1、创建Array

  • new操作符 + Array构造函数,其中new操作符可选

  • 数组字面量

  • Array.from(),返回一个新数组,浅拷贝的方式。可以将两类对象转换为数组:类数组对象、可遍历对象。任何有length属性的对象,都可以通过Array.from()方法转为数组

    1
    2
    3
    4
    Array.from(object, mapFunction, thisValue)
    object:必需。需转换为数组的对象。
    mapFn: 可选。对数组的每个项目调用的 map 函数。
    thisValue:可选。执行 mapFunction 时用作 this 的值
  • Array.of(),把一组参数转换为数组。**Array(7)** 创建一个长度为 7 的空数组,Array.of(7) 创建一个具有单个元素 7 的数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
let colors = new Array();
let colors = new Array(5); //new的时候指定数组长度
let colors = new Array('red','green','blue'); //new的时候传入初始化元素

const arr = new Array(count).fill(item) //创建指定长度的数组,并用指定item填充数组
const arr = new Array(2).fill( new Array(3).fill(0) ) //[[0,0,0],[0,0,0]]

let colors = ['red','green','blue'];
let colors = [,,'blue']; //缺省的自动补undefined

Array.from('Java'); //['J', 'a', 'v', 'a']
let m = new Map().set(1,2).set(3,4);
Array.from(m); //[[1,2],[3,4]]
let a1 = [1,2,3];
Array.from(a1); //[1, 2, 3],浅拷贝的方式
Array.from(a1,x=>x**2); //[1, 4, 9]

Array.of(1,2,3); //[1, 2, 3]

1.2、Array长度

  • arr.length 获取数组长度,也可以通过arr.length=xx来改变数组长度,多删少补undefined

1.3、实例方法

1.3.1 改变原数组的方法

方法 描述 返回值
sort() 排序,默认按照字符编码排序,(更多细节见下面代码示例) 原数组的引用
reverse() 颠倒数组顺序 原数组的引用
splice(start,num,[item1,…]) 从start位开始,删除num个元素,并在start位置插入item(s),item1外的方括号表示该参数可选
push(item) 向数组末尾添加指定元素,可以一次插入多个item 插入位置的索引值(或者说是数组长度)
pop() 从数组末尾删除一个元素 删除的元素
shift() 从数组头删除一个元素 删除的元素
unshift() 向数组头添加指定元素,可以一次添加多个 数组长度
fill(value,start,end) 在[start,end)之间填充(替换)value 原数组的引用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//sort
//1.默认按照字符编码值排序
var arr = ['a','c','A','b']
arr.sort()
arr //['A', 'a', 'b', 'c']

//2.自定义排序规则
var arr = [1,2,3,23,11]
arr.sort() //[1, 11, 2, 23, 3]
arr.sort((x,y)=>x-y) //[1, 2, 3, 11, 23],升序排序
arr.sort((x,y)=>y-x) //[23, 11, 3, 2, 1],降序排序
// 以下是错误示例,x>y的值范围是1或者0。但是sort排序函数接受的返回值必须是正值和负值,0无效
var arr = [1,2,3,23,11]
arr.sort((x,y)=>{return x>y}) //[1, 2, 3, 23, 11],并没有进行排序


//splice,从第三个参数开始,表示插入的item
var arr = ['a','b','c']
var res = arr.splice(1,2,['d','e'])
res //['b', 'c']
arr //['a', ['d', 'e']]
var res2 = arr.splice(1,0,'f','g')
arr //['a', 'f', 'g', ['d', 'e']]

//fill
var arr = [1,2,3,4,5]
var res = arr.fill(6,1,3)
arr // [1, 6, 6, 4, 5]
res // [1, 6, 6, 4, 5]
arr.fill(7,1) // [1, 7, 7, 7, 7],如果只提供一个索引,则范围为从索引到末尾
arr.fill(8,2,6) // [1, 7, 8, 8, 8],如果索引end超过了数组长度,范围也只能是数组末尾
arr.fill(9) // [9, 9, 9, 9, 9],如果两个索引都没有提供,则表示整个数组替换

1.3.2 不改变原数组的方法

方法 描述 返回值
forEach(fn) 遍历数组,将函数fn作用到每个元素上
fn的参数依次为:item,index,array,元素、下标,数组引用,后两者可选
map(fn) 接受函数作为参数,为每个元素应用函数,并将结果返回为一个新数组
(更多细节另外进行探究)
新数组
reduce(fn,initalVal) 参数一,函数fn,将函数fn累加作用到所有元素上
参数二,初始值,可选。(更多细节另外进行探究)
一个结果(值)
filter(fn) 接受函数作为参数,筛选出所有符合条件的元素组成新的数组 新数组
slice(start,end) 数组切片,如果不给参数返回整个数组,如果只给一个参数表示起始索引。可以用来浅拷贝 指定范围的新数组
concat(item1,…) 接受不定数量的参数,将所有参数拼接到调用concat的数组组成一个新数组(如果参数是数组,会拆开一层,示例如下)
如果不指定参数,可以用来浅拷贝数组
拼接后的新数组
join(char) 接受一个字符串参数,缺省默认为, 拼接后的字符串
every(fn) 检测Array中是否每个元素都符合指定条件(在fn中设置) 布尔值
some(fn) 检测Array中是否有元素符合指定条件(在fn中设置) 布尔值
includes(item) 判断是否在Array中找到一个与指定item匹配的元素 布尔值
find(fn) 返回数组中满足提供的测试函数的第一个元素的值,否则返回undefined 值或undefined
findIndex(fn) 返回数组中满足提供的测试函数的第一个元素的索引,否则返回undefined 索引值或undefined
indexOf(item, start) 参数一:要查找的元素,查找该元素在Array中的第一个下标,如果不存在返回-1。
参数二:查找起点,不设置默认从0开始查找
索引值
lastIndexOf() 接受一个参数,由后向前寻找,返回第一个匹配的元素下标,如果不存在返回-1 索引值
1
2
3
//filter
var arr = [1,2,3,4,5]
var res = arr.filter((item,index,arr)=>{return item>3}) //[4, 5]
1
2
3
4
5
6
7
8
//concat,不改变原数组,参数如果是数组,会拆开一层数组
var arr = [1,2,3]
var res = arr.concat(4,5,[6,7],[[8,9]])
res //[1, 2, 3, 4, 5, 6, 7, [8,9]]

// 利用concat执行浅拷贝
var arr1 = arr.concat()
arr1 //[1,2,3],是对arr的浅拷贝
1
2
3
4
5
6
7
8
9
10
11
12
// 注意:当concat只有一个参数,而调用的数组又恰好为空数组时,不会拆开数组
var arr = []
var res = arr.concat([1,2])
res //[1,2]

var arr = []
var res = arr.concat(1,[2,3])
res // [1, 2, 3]

var arr = [1]
var res = arr.concat([2,3])
res //[1, 2, 3]
1
2
3
4
5
//join
var arr = ['h','e','l','l','o']
var res = arr.join() //'h,e,l,l,o',参数缺省时默认以,连接
var res = arr.join('') //'hello'arr
var res = arr.join('--') //'h--e--l--l--o',接受的是字符串,并非只能是单个字符
1
2
3
4
//find
var arr = [5,11,6,20]
var res = arr.find(x=>x>10) //11
var res = arr.findIndex(x=>x>10) //1
1
2
3
//map
var arr = [1,2,3]
var res = arr.map(x=>{return x*2}) //[2, 4, 6],map的回调函数是需要return值的,由return的值组成新数组

1.3.3 forEach和map比较

使用场景:

  • forEach,需要遍历获取数组元素的操作
  • map,需要对原数组的所有元素做出一些修改的操作

定义:

  • forEach,对数组的每个元素执行一次给定的函数
  • map,创建一个新数组,这个新数组由原数组中的每个元素都调用一次提供的函数后的返回值组成(因此map的回调函数必须返回值)

参数:两者参数一致

1
2
3
4
function(currentValue,index,arr)
//currentValue:必须。当前元素的值
//index:可选。当前元素的索引值
//arr:可选。所遍历数组的引用

对原数组的影响:

直接调用时都不改变原数组,但是可以通过函数参数的 数组引用 修改原数组

1
2
3
4
5
//有一种特殊情况,如果item元素是object对象,可以通过item修改对象的属性(但是无法改变item的指针)
var arr = [{a:1},{a:2},{a:3}]
arr.forEach(item=>{item.a = 6}) //arr[{a:6},{a:6},{a:6}]
var arr = [{a:1},{a:2},{a:3}]
arr3 = arr.map(item=>item.a = 6) //arr[{a:6},{a:6},{a:6}] arr3[6, 6, 6]

遍历时的特殊情况:

  • forEach遍历的范围在第一次调用 callback 前就会确定,调用forEach后添加的元素不会被访问。如果已访问的元素在迭代时被删除了(例如使用pop()),之后的一个元素将被跳过。
  • 调用forEach之后、访问到该元素之前,该元素被删除,它将不会被访问到。并且不访问未初始化的值。
1
2
3
4
5
6
7
8
9
10
let arr = [1,2,3,4]
arr.forEach(word=>{
console.log(word);
if(word==2){arr.shift();}
})
//输出 1 2 4
//3被跳过,原因:当遍历到2时,整个数组的第一个项被移除了,导致所有剩下的元素上移一个位置
//扩展:只要把未曾遍历的部分删除掉,整个数组都会往前移动一个位置,那么会有一个元素被跳过
//如果最后一行 shift换成pop,那么输出将变成1 2 3
//换言之,删除后面的元素不会导致正在遍历的数组向前移动
  • mapcallback 方法第一次调用之前就已经确定了,调用map后才追加的元素不会被访问。如果现存的数组元素被改变,callback访问的是当前实际的值。
  • 调用map之后、访问到该元素之前,该元素被删除,它将不会被访问到,返回的数组和原数组长度一致,如果有需要用undefined填充
1
2
3
4
5
6
let arr = [1,2,3,4]
let res = arr.map(x=>{
if(x==2) arr.shift()
return x
})
res //[1, 2, 4, 空],和forEach一样,如果已访问的元素被删除,之后的一个元素被跳过

1.4、判断是否Array类型

  • arr instanceof Array
  • Array.isArray(arr)
  • arr.constructor === Array
  • Array.prototype.isPrototypeOf(arr), isPrototypeOf() 用于测试一个对象是否存在于另一个对象的原型链上
  • Object.getPrototypeOf(arr) === Array.prototype,getPrototypeOf方法返回指定对象的原型

二、Map

对象Object的属性值只能为字符串。为了突破这个限制,ES6新增了Map对象,Map 结构提供了“值—值”的对应,并且能够记住键的原始插入顺序,任何值(对象或者原始值) 都可以作为一个键或一个值

2.1、创建Map实例

1
2
3
4
5
6
var m = new Map([['Mike',80],[1,90]])	//{'Mike' => 80, 1 => 90}

var m = new Map()
m.set('Mike',80)
m.set(1,90)
var m = new Map().set('Mike',80).set(1,90) //set可以连续调用,说明set()返回的是Map实例的引用

创建Map实例,可以不用在构造器函数后面加上()

1
2
3
var m = new Map
m.set('Mike',80)
m //Map(1) {'Mike' => 80}

2.2、实例方法

1
2
3
4
m.get('Mike'); 		//80
m.has('Mike'); //true
m.delete('Mike');
m.get(1); //undefined,对于没有定义过的key,返回undefined

2.3、遍历Map

  • entries()方法,或者Symbol.iterator属性(实际上它也是引用entries())
1
2
3
4
5
6
7
8
9
let m = new Map([['Mike',80],['Jode',90]]);
for(let pair of m.entries()){
console.log(pair);
}
for(let pair of m[Symbol.iterator]()){
console.log(pair);
}
// ['Mike', 80]
// ['Jode', 90]
  • values()方法,只遍历值
1
2
3
4
5
6
let m = new Map([['Mike',80],['Jode',90]]);
for(let value of m.values()){
console.log(value);
}
//80
//90

2.4、WeakMap

  • WeakMap和Map的区别在于,Map的键值可以是任意JavaScript类型,但WeakMap的键类型只能是Object或者继承自Object的类型。这些键不属于正式的引用,所以不影响垃圾回收,这也是使用WeakMap的意义。
  • 因为WeakMap的元素随时可能会被回收,所以它不支持迭代。
1
2
3
const wm = new WeakMap();
const loginButton = document.querySelector('#login');
wm.set(loginButton,{disabled:true});

三、Set

3.1、创建Set实例

1
2
3
4
5
6
7
8
//方式一,直接定义
var s = new Set([1,2,'3']);

//方式二,先创建实例,再用add方法添加
var s = new Set();
s.add(1);
s.add('3');
var s = new Set().add(1).add('3'); //add()方法可以连续调用

3.2、实例方法

1
2
3
s.delete('3');	//返回一个boolean值,表示是否存在要删除的值
s.has(2); //返回boolean值
s.size //获取set的长度

3.3、遍历Set

1
2
3
4
5
6
7
var s = new Set([1,2,'3']);
for(let value of s.values()){
console.log(value); //1,2,3
}
for(let value of s[Symbol.iterator]()){
alert(value); //1,2,3
}
1
2
3
4
5
6
7
8
9
const s1 = new Set(["val1"]);
for(let value of s1.values()){
value = "val2"; //这里无法改变s1实例内部的值
console.log(value); //val2
console.log(s1.has('val1')); //true
}
for(let value of s1.values()){
console.log(value); //val1
}

3.4、合并Set

1
const set3 = new Set([...set1, ...set2])

3.5、WeakSet

  • WeakSet中的“weak”(弱),描述的是JavaScript垃圾回收程序对待“弱集合”中值的方式
  • 弱集合中的值只能是Object类型或者继承自Object的类型,尝试使用非对象设置值会抛出TypeError
  • 不可迭代值

JavaScript(三)集合引用类型
http://timegogo.top/2023/01/31/JavaScript/JavaScript(三)集合引用类型/
作者
丘智聪
发布于
2023年1月31日
更新于
2023年7月16日
许可协议