重学JS-3-一图掌握JS容器

272 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第18天,点击查看活动详情

前端开发的第三年,突然发现,对于JS,我还有很多不懂的地方,趁着最近需求少,不如静下心来,从头把JS再学一遍,查漏补缺。

本系列以廖雪峰的《JavaScript教程》和《现代 JavaScript 教程》两个电子书作为线索,对其中需要进一步了解的知识,会阅读更多的文章,并作为扩展知识记录下来。

新手建议先阅读上面两个电子书,本系列更适合用来复习旧知识查漏补缺

通过下面的思维导图,我们先对JavaScript的容器有一些基本的了解。

思维导图

《JavaScript教程-容器》思维导图

容器

定义:与数据类型无关的数据结构

容器的类型

顺序容器

  • vector:向量
  • list:双端列表
  • stack:栈
  • queue:队列

关联容器

map:映射

set:有序集

顺序容器

vector、list、queue看起来很容易混淆,其在C++中的区别,主要是在内存中的存储方式和支持的操作不同。

  1. vector和C++数组的区别在与,vector不需要程序员自己去分配内存空间。
  2. vector和queue是连续存储,list是非连续存储(双链表)。
  3. queue支持在队头队尾插入元素,vector只支持在队尾插入元素。
  4. list支持高效的插入删除,但是随机访问的效率低下。
  5. 堆(heap 优先队列)和栈(stack)的区别是,先进先出(FIFO)和先进后出(FILO)。

这些顺序容器,在JavaScript中是Array这个内置对象(js是基于对象的语言)。

其支持的方法看这个文档

developer.mozilla.org/zh-CN/docs/…

下面来简单总结一下:

JavaScript数组对象

forEach:遍历

array.forEach(function(item, index, array) {
  console.log(item, index)
})

push:添加元素到数组的末尾

let newLength = array.push('Orange')

pop:删除数组末尾的元素

let last = array.pop()

shift:删除数组头部元素

let first = array.shift()

unshift:添加元素到数组的头部

let newLength = array.unshift('Strawberry')

indexOf/lastIndexOf:找出某个元素在数组中的索引

let pos = fruits.indexOf('Banana')
//lastIndexOf :最后一个的索引
let pos = fruits.lastIndexOf('Banana')

splice:通过索引删除某个元素

let removedItem = array.splice(pos, 1)
//从一个索引位置删除多个元素
let removedItem = array.splice(pos, n)
//复制一个数组
let shallowCopy = fruits.slice() //begin和end的默认值是0和结尾

concat:合并数组

const array3 = array1.concat(array2);

find/findIndex:查找符合条件的元素

const found = array1.find(element => element > 10);
//findIndex返回索引
const isLargeNumberIndex = array1.findIndex(element => element > 13);

flat:拍扁数组

const arr1 = [0, 1, 2, [3, 4]];

console.log(arr1.flat());
// expected output: [0, 1, 2, 3, 4]

const arr2 = [0, 1, 2, [[[3, 4]]]];

console.log(arr2.flat(2));
// expected output: [0, 1, 2, [3, 4]]

map:映射/flatMap:映射并拍平数组

let arr1 = ["it's Sunny in", "", "California"];

arr1.map(x => x.split(" "));
// [["it's","Sunny","in"],[""],["California"]]

arr1.flatMap(x => x.split(" "));
// ["it's","Sunny","in", "", "California"]
//相当于map和flat(1)一起用,但效率高一些
arr1.map(x => x.split(" ")).flat(1);
// ["it's","Sunny","in", "", "California"]

includes:是否包含某个值

array.includes('cat')

join:连接成字符串

const elements = ['Fire', 'Air', 'Water'];

console.log(elements.join('-'));
// expected output: "Fire-Air-Water"

reduce: 递推对元素执行函数,并返回值/reduceRight:从右开始执行

const array1 = [1, 2, 3, 4];
const reducer = (previousValue, currentValue) => previousValue + currentValue;

// 1 + 2 + 3 + 4
console.log(array1.reduce(reducer));
// expected output: 10

// 5 + 1 + 2 + 3 + 4
console.log(array1.reduce(reducer, 5));
// expected output: 15

reverse:返回倒序数组,原数组也会改变

const reversed = array1.reverse();

some:判断是否存在符合条件的元素

array.some(element => element % 2 === 0)

关联容器

js中,MapSet是ES6标准新增的数据类型,参考廖雪峰老师的教程

www.liaoxuefeng.com/wiki/102291…

JavaScript中的Map

var m = new Map([['Michael', 95], ['Bob', 75], ['Tracy', 85]]);
m.get('Michael'); // 95
var m = new Map(); // 空Map
m.set('Adam', 67); // 添加新的key-value
m.set('Bob', 59);
m.has('Adam'); // 是否存在key 'Adam': true
m.get('Adam'); // 67
m.delete('Adam'); // 删除key 'Adam'
m.get('Adam'); // undefined

JavaScript中的Set

var s1 = new Set(); // 空Set
var s2 = new Set([1, 2, 3]); // 含1, 2, 3
s.add(4);
s; // Set {1, 2, 3, 4}
s.delete(3);
s; // Set {1, 2, 4}
s.has(1); //true
s.clear(); //清空set

WeakMap and WeakSet(弱映射和弱集合)

弱容器有下面三个特点:

  • WeakMapkey只能是对象,WeakSet只能添加对象。
  • 弱容器不可迭代,同样也不支持clearsizekeysvalues
  • 弱容器中的对象,只有其在某个地方能被访问的时候,才能留在容器中。

第三点,参考下面这个例子。

let john = { name: "John" };

let weakMap = new WeakMap();
weakMap.set(john, "...");

john = null; // 覆盖引用

// john 被从内存中删除了!

WeakMap的一个常见使用案例,缓存。

// 📁 cache.js
let cache = new WeakMap();

// 计算并记结果
function process(obj) {
  if (!cache.has(obj)) {
    let result = /* calculate the result for */ obj;

    cache.set(obj, result);
  }

  return cache.get(obj);
}

// 📁 main.js
let obj = {/* some object */};

let result1 = process(obj);
let result2 = process(obj);

// ……稍后,我们不再需要这个对象时:
obj = null;

// 无法获取 cache.size,因为它是一个 WeakMap,
// 要么是 0,或即将变为 0
// 当 obj 被垃圾回收,缓存的数据也会被清除