乐趣区

关于javascript:JS系列-ES6新增的数据结构

本章波及:
理解 ES6 新增的数据结构 Set、WeakSet、Map、WeakMap
理解 JS 中的强利用和弱利用
理解 entries 构造

​ 在 ES6 以前,JavaScript 中就只有两种数据结构:数组 对象 。精确的来说, 对象 还不是一种数据结构,它的底层是 hashTable 实现的(不晓得对不对,听他人说的)。

​ ES6 中 新增了 4 中数据结构:SetWeakSetMapWeakMap。接下来,就顺次的认识一下。

依据 MDN 作为根据

Set

Set 对象容许你存储任何类型的惟一值,无论是原始值或者是对象援用。

Set对象是 的汇合,你能够依照插入的程序迭代它的元素。Set 中的元素只会 呈现一次,即 Set 中的元素是惟一的。

Set中没有索引值

set 中值的唯一性

唯一性,就示意 根本数据类型的值要相等,援用数据类型的地址要相等

然而呢?还是有几个特地要留神的几个值:

  • 针对 0 的解决
// +0 和 -0
console.log(+0 === -0)   // true

const set = new Set()
set.add(+0)
set.add(-0)
console.log(set)  // Set(1) {0}
  • 针对 NaN 的解决
console.log(NaN === NaN)  // false

const set = new Set()
set.add(NaN)
set.add(NaN)
console.log(set)  // Set(1) {NaN}

在 Set 中也视为相等。

Set 常见的办法和属性

constructor: 承受 无参 或者 一个迭代器 的参数,创立一个 Set 实例。

Set.prototype.size: 返回 set 中的元素个数。

Set.prototype.add(value): 在 Set 对象尾部增加一个元素。返回该 Set 对象。

Set.prototype.clear(): 移除 Set 对象内的所有元素, 没有返回值。

Set.prototype.delete(value): 从 set 中删除和这个值相等的元素,返回 boolean 类型

Set.prototype.has(value): 判断 set 中是否存在某个元素,返回 boolean 类型

遍历

entries: 放弃跟 Map 返回的格局一样,key 与 value 的值雷同

forEach: 遍历 Set 中的每个元素

keys: 与 values() 办法雷同,返回一个新的迭代器对象。

values: 与下面一样

代码演示

const arr = [4, 3, 2, 1, 5]
// constructor
const set = new Set(arr)
// size
console.log(set.size) // 5
// add
console.log(set.add(6)) // Set(6) {4, 3, 2, 1, 5, 6}
// delete
console.log(set.delete(1)) // true
// has
console.log(set.has(1)) // false
// clear
console.log(set.clear()) // undefined

遍历的话,就不敲了。

WeakSet

WeakSet 对象容许你将 弱放弃对象 存储在一个汇合中,也是外部不能反复。

下面概念中提到了一个 弱放弃,怎么了解呢?

请看最上面的 JavaScript 中的强援用和弱援用。

WeakSet 和 Set 的区别

  • WeakSet 中只能寄存对象类型,不能寄存根本数据类型;
  • WeakSet 对元素的援用是弱援用,如果没有其余援用对某个对象进行援用,那么 GC 能够对该对象进行回收;
  • 不能够被枚举。

WeakSet 的常见办法

  • WeakSet.prototype.add(value):增加某个元素,返回 WeakSet 对象自身;
  • WeakSet.prototype.delete(value):从 WeakSet 中删除和这个值相等的元素,返回 boolean 类型;
  • WeakSet.prototype.has(value):判断 WeakSet 中是否存在某个元素,返回 boolean 类型;

不能被遍历。

应用场景,很少很少(代码量少,可能没遇到过)。

Map

Map 对象保留键值对,并且可能记住键的原始插入程序。任何值(对象或者原始值)都能够作为一个键或一个值。

在 map 以前,只有想着键值对的模式,必定想到 对象。对,不可拥护。

那么 Map对象 之间有什么区别呢?

对象的 key 值只能是 字符串 ,以及前面新增的symbol 类型。然而,Map 反对所有类型。

对象 解决对象作为 key 的场景

let obj1 = {name: 'copyer'}
let obj2 = {name: 'copyer'}

const a = {[obj1]: 'aaa',
  [obj2]: 'bbb'
}

console.log(a)  // {'[object Object]': 'bbb' }

看进去,对象会先被转化为字符串[object Object], 字符串作为 key 值。

Map 中的属性和办法

constructor: 承受 无参 或者 entries 构造 的参数,创立一个 Set 实例。(了解 entries 构造,看上面的了解 entries 构造)。

Map.prototype.size:返回 Map 对象中的键值对数量。

Map.prototype.clear():移除 Map 对象中所有的键值对。

Map.prototype.delete(key):移除 Map 对象中指定的键值对,如果键值对存在,返回 true,否则返回 false

Map.prototype.get(key):返回与 key 关联的值,若不存在关联的值,则返回 undefined

Map.prototype.has(key):返回一个布尔值,用来表明 Map 对象中是否存在与 key 关联的值。

Map.prototype.set(key, value):在 Map 对象中设置与指定的键 key 关联的值 value,并返回 Map 对象。

遍历

for...of..

keys

values

entries

forEach

代码演示

const map = new Map([["name", "copyer"]]);

// size
console.log(map.size); // 1

// set
map.set(1, "我是数字");

// get
console.log(map.get(1)); // 我是数字

// has
console.log(map.has(1)); // true

// delete
console.log(map.delete(1)); // true

// clear
// console.log(map.clear());

// forEach
map.forEach((value, key) => {console.log(value, key) // copyer name
})

// for...of...
for (const [key, value] of map) {console.log(key, value) // name copyer
}

Map 对象 的比拟

借鉴于 MDN 的比照

Map Object
意外的键 Map 默认状况不蕴含任何键。只蕴含显式插入的键。 一个 Object 有一个原型, 原型链上的键名有可能和你本人在对象上的设置的键名产生抵触。
键的类型 一个 Map 的键能够是 任意值,包含函数、对象或任意根本类型。 一个 Object 的键必须是一个 String 或是 Symbol
键的程序 Map 中的 key 是有序的。因而,当迭代的时候,一个 Map 对象以插入的程序返回键值。 尽管 Object 的键目前是有序的,但并不总是这样,而且这个程序是简单的。因而,最好不要依赖属性的程序。
Size Map 的键值对个数能够轻易地通过 size 属性获取。 Object 的键值对个数只能手动计算.
迭代 Map是可迭代的的,所以能够间接被迭代。 Object 没有实现 可迭代协定,所以应用 JavaSctipt 的 for…of 表达式并不能间接迭代对象。
性能 在频繁增删键值对的场景下体现更好。 在频繁增加和删除键值对的场景下未作出优化。
序列化和解析 没有元素的序列化和解析的反对。 原生的由 Object 到 JSON 的序列化反对,应用 JSON.stringify()。原生的由 JSON 到 Object 的解析反对,应用 JSON.parse()

其实通过下面的比拟,map大部分是优先于 对象 的,然而在开发过程中,还是基本上都是应用对象(可能是开发的级别不够)

Map 和 数组的转化

const kvArray = [["key1", "value1"], ["key2", "value2"]];

// 应用惯例的 Map 构造函数能够将一个二维键值对数组转换成一个 Map 对象
const myMap = new Map(kvArray);

myMap.get("key1"); // 返回值为 "value1"

// 应用 Array.from 函数能够将一个 Map 对象转换成一个二维键值对数组
console.log(Array.from(myMap)); // 输入和 kvArray 雷同的数组

// 更简洁的办法来做如上同样的事件,应用开展运算符
console.log([...myMap]);

// 或者在键或者值的迭代器上应用 Array.from,进而失去只含有键或者值的数组
console.log(Array.from(myMap.keys())); // 输入 ["key1", "key2"]

WeakMap

WeakMap 对象是一组键 / 值对的汇合,其中的键是 弱援用 的。其键必须是对象,而值能够是任意的。

WeakMap 和 Map 的区别

  • WeakMap 的 key 值只能是对象,不能其余类型;
  • WeakSet 对元素的援用是弱援用,如果没有其余援用对某个对象进行援用,那么 GC 能够对该对象进行回收;
  • 不能够被枚举。

WeakMap 罕用的办法

constructor: 承受 无参 或者 entries 构造 的参数,创立一个 Set 实例。(了解 entries 构造,看上面的了解 entries 构造)。

WeakMap.prototype.delete(key):移除 WeakMap 对象中指定的键值对,如果键值对存在,返回 true,否则返回 false

WeakMap.prototype.get(key):返回与 key 关联的值,若不存在关联的值,则返回 undefined

WeakMap.prototype.has(key):返回一个布尔值,用来表明 WeakMap 对象中是否存在与 key 关联的值。

WeakMap.prototype.set(key, value):在 WeakMap 对象中设置与指定的键 key 关联的值 value,并返回 Map 对象。

应用场景

在 Vue3 响应式拦挡中,是应用了 WeakMap。

了解 JavaScript 中的强援用和弱援用

JavaScript 中的对象,只有没有被援用,就会被垃圾回收机制回收。

强援用

先看代码

let obj = {name: "copyer", age: 23};
const newObj = obj;
obj = null;
console.log(obj); // null
console.log(newObj); // {name: 'copyer', age: 23}

下面的代码应该很简略吧。简略一个对象 obj,把 obj 的援用赋值给另外一个变量 newObj, 而后清空 obj,打印两者。那么内存的表现形式呢?为什么 obj 为 null, newObj 还有值的存在呢?

  • 创立 Obj 对象,在 heap 中生成一个内存地址 0x100, stack 中的 obj 的值:0x100
  • 把援用赋值给 newObj,那么它的值也是 0x100
  • 当执行 obj = null,只是断开了 obj 与 heap 内存的连贯,并没有断开 newObj 的连贯,所以 obj 为 null,然而 newObj 是有值的。

当内存中开拓的地址,只有又被其余所指向,就不会被垃圾回收机制所回收。这就是 强援用。(强势的一面)

弱援用

从字面上来说,就是出于弱势的一面,即便指向某一个援用,然而垃圾回收机制看不起你,你太弱了,强行把内存发出掉。

WeakSet 和 WeakMap 就是 弱援用。

WeakMap 实例:

let obj = {name: "copyer", age: 23};
let weakMap = new WeakMap([[obj, obj]])
console.log(weakMap.get(obj)) // {name: "copyer", age: 23}

// 如果
obj = null
console.log(weakMap.get(obj)) // undefined

定义一个 obj 对象,在内存中会开拓一块地址,在 WeakMap 的传参中,是援用了 obj 内存中所指向的地址。

然而呢,obj = null 时, 断开了连贯,按理说,还有其余的中央在援用,是不会被回收的。然而如果是弱援用,那么内存中的地址一样的会被回收,那么WeakMap 参数援用 就没有指向了,所以是undefined

总结

强援用:只有有援用指向,就不会被回收。

弱援用:即便有援用指向,也是会被回收的。(WeakSet 和 WeakMap 是 JS 弱援用的体现)

了解 entries 构造

其实何为 entries 构造, 调用一下 Object.entries() 办法就晓得了。

const obj = {
  name: 'copyer',
  age: 23,
  height: 180
}

console.log(Object.entries(obj)) // [['name', 'copyer'], ['age', 23], ['height', 180] ]

Object.entries()办法返回一个给定对象本身可枚举属性的键值对数组。(像一个二维数组)

其格局:

[[key, value], [key, value] ... ]

退出移动版