JavaScript深入理解(15课)笔记-ES6中新增的两种数据结构:Set、Map【以及WeakSet、WeakMap】

15.await、async等

在ES6之前,我们存储数据的结构主要有两种:数组、对象。
· 在ES6中新增了另外两种数据结构:Set、Map,以及它们的另外形式WeakSet、WeakMap。
Set是一个新增的数据结构,可以用来保存数据,类似于数组,但是和数组的区别是元素不能重复。
· 创建Set我们需要通过Set构造函数(暂时没有字面量创建的方式):

// 1.创建Set结构
const set = new Set()
set.add(10)
set.add(20)
set.add(40)
set.add(333)
set.add(10)

// 2.添加对象时特别注意:
set.add({})
set.add({})  //添加不同对象,{} 会创建一块新内存

const obj= {}
set.add(obj) 
set.add(obj)  //添加同一对象

console.log(set)

// 3.对数组去重(去除重复的元素)
const arr = [33, 10, 26, 30, 33, 26]
const newArr = []
for (const item of arr) {
    if (newArr.index0f(item) !== -1){
        newArr.push(item)
    }
}

或者用 Set
const arrSet = new Set(arr)
const newArr = Array.from(arrSet)  //或者用  [...arrSet]
console.log(newArr)


Set常用的方法:
· add(value):添加某个元素,返回Set对象本身;
· delete(value):从set中删除和这个值相等的元素,返回boolean类型;
· has(value):判断set中是否存在某个元素,返回boolean类型;
· clear():清空set中所有的元素,没有返回值;
· forEach(callback,[,thisArg]):通过forEach遍历set;

另外Set是支持for…of的遍历的。

// 6.对Set进行遍历
arrSet.forEach(item => {
    console.log(item)
})
//或者
for (const item of arrSet) {
    console.log(item)
}


00:29:00
WeakSet使用

和Set类似的另外一个数据结构称之为WeakSet,也是内部元素不能重复的数据结构。
那么和Set有什么区别呢?
· 区别一:WeakSet中只能存放对象类型,不能存放基本数据类型;
· 区别二:WeakSet对元素的引用是弱引用,如果没有其他引用对某个对象进行引用,那么GC可以对该对象进行回收;


【弱引用对于GC(垃圾回收)来说,这个弱引用存在不存在,没有任何关系的。
即使,这个有弱引用存在,而唯一的一个强引用都不存在了,GC该回收还是会回收的。】


示例:
const weakSet = new WeakSet()
// 区别一:只能存放对象类型
// TypeError: Invalid value used in weak set
// weakset.add(10)

// 强引用和弱引用的概念(看图)
// 区别二:对象是一个弱引用
let obj = {
    name: "why"
}

const set = new Set()
//建立的是强用
set.add(obj)

//建立的是弱引用
weakSet.add(obj)

00:49:00
WeakSet常见的方法:
· add(value):添加某个元素,返回WeakSet对象本身;
· delete(value):从WeakSet中删除和这个值相等的元素,返回boolean类型;
· has(value):判断WeakSet中是否存在某个元素,返回boolean类型;


注意:WeakSet不能遍历
· 因为WeakSet只是对对象的弱引用,如果我们遍历获取到其中的元素,那么有可能造成对象不能正常的销毁。
· 所以存储到WeakSet中的对象是没办法获取的;
那么这个东西有什么用呢?
· 事实上这个问题并不好回答,我们来使用一个Stack Overflow上的答案;

// 3.WeakSet的应用场景【这种场景应用的不多】
const personSet= new WeakSet()
class Person {
    constructor() {
        personSet.add(this)
    }
    running() {
        if(!personSet.has(this)) {
            throw new Error("不能通过非构造方法创建出来的对象调用running方法")
        }
        console.log("running~", this)
    }
}

const p = new Person()
p.running()

//我不允许你调用Person里面的running方法的时候,通过非构造方法创建出来的对象,对我进行调用,如下:
p.running.call({name: "why"})  //此时,throw错误!

上面为什么不用 Set 呢?
因为Set是强引用,则 创建出来的 p 对象,也会被强引用一份。如果,我们想销毁 p 对象:p = null ,那么,
personSet这个对象会销毁吗?不会的。因为你也需要清除一下它:personSet.delete(p) 。

01:00:00
Map的基本使用

另外一个新增的数据结构是Map,用于存储映射关系。
但是我们可能会想,在之前我们可以使用对象来存储映射关系,他们有什么区别呢?
· 事实上我们对象存储映射关系只能用字符串(ES6新增了Symbol)作为属性名(key);
· 某些情况下我们可能希望通过其他类型作为key,比如对象,这个时候会自动将对象转成字符串来作为key ;

//1.JavaScript中对象中是不能使用对象来作为key的
const obj1 = { name: "why"}
const obj2 = { name: "kobe"}
const info = {
    [obj1]: "aaa",
    [obj2]: "bbb"
}
console.log(info) //{"[object Object]": "bbb"}    【相当于把对象转为string值"[object Object]",再作为key】

//2.Map就是允许我们对象类型来作为key的
const map = new Map()
map.set(obj1, "aaa")
map.set(obj2, "bbb")
map.set(1, "ccc")
console.log(map)

const map2 = new Map([obj1, "aaa"], [obj2, "bbb"], [2, "ddd"])
console.log(map2)

// 3.常见的属性和方法
console.log(map2.size)
// set
map2.set("why", "eee")
console.log(map2)
// get (key)
console.log(map2.get("why"))
// has(key)
console.log(map2.has("why"))
// delete(key)
map2.delete("why") //删除成功返回true,失败false
console.log(map2)
// clear
map2.clear()
console.log(map2)
// 4.遍历map
map2.forEach(item => {
    console.log(item)
}
for (const item of map2) {
    console.log(item)
}

for (const item of map2){
    console.log(item[0], item[1])
}
//既然是数组,可以解构一下
for (const [key, value] of map2) {
    console.log(key, value)
}


和Map类型相似的另外一个数据结构称之为WeakMap,也是以键值对的形式存在的。
那么和Map有什么区别呢?
· 区别一:WeakMap的key只能使用对象,不接受其他的类型作为key ;
· 区别二:WeakMap的key对对象想的引用是弱引用,如果没有其他引用引用这个对象,那么GC可以回收该对象;

const obj = {name: "obj1"}
// 1.WeakMap和Map的区别二:
const map =new Map()
map.set(obj, "aaa")

const weakMap = new WeakMap()
weakMap.set(obj, "aaa")
// 2.区别一:不能使用基本数据类型
weakMap.set(1, "ccc")  //报错

// 3.常见方法,WeakMap没有size方法/forEach即不能遍历
// get方法
console.log(weakMap.get(obj))
// has方法
console.log(weakMap.has(obj))
console.log(weakMap)  // WeakMap { <items unknown> }  因为不能遍历,所以字符串显示一样
// delete方法
console.log(weakMap.delete(obj))

示例:
// 4.应用场景(vue3响应式原理)
const obj1 = {
    name: "why",
    age:18
}
function obj1NameFn1() {
    console.log("obj1NameFn1被执行")
}
function obj1NameFn2() {
    console.log("obj1NameFn2被执行")
}
function obj1AgeFn1() {
    console.log("obj1AgeFn1")
}
function obj1AgeFn2() {
    console.log("obj1AgeFn2")
}
const obj2 = {
    name: "kobe",
    height:1.88,
    address:"广州市"
}
function obj2NameFn1() {
    console.log("obj1NameFn1被执行")
}
function obj2NameFn2() {
    console.log("obj1NameFn2被执行")
}

// 1.创建WeakMap
const weakMap = new WeakMap()

// 2.收集依赖结构
// 2.1.对obj1收集的数据结构
const obj1Map = new Map()
obj1Map.set("name", [obj1NameFn1, obj1NameFn2])
obj1Map.set("age", [obj1AgeFn1, obj1AgeFn2])
weakMap.set(obj1, obj1Map)
// 2.2.对obj2收集的数据结构
const obj2Map = new Map()
obj2Map.set("name", [obj2NameFn1, obj2NameFn2])
weakMap.set(obj2, obj2Map)
// 3.如果obj1.name发生了改变
// Proxy/Object.defineProperty 监听改变
obj1.name = "james"
const targetMap = weakMap.get(obj1)
const fns = targetMap.get("name")
fns.forEach(item => item())

【输出如下】:
obj1NameFn1被执行
obj1NameFn2被执行

02:06:00
在ES7之前,如果我们想判断一个数组中是否包含某个元素,需要通过indexOf获取结果,并且判断是否为-1。
在ES7中,我们可以通过includes来判断一个数组中是否包含一个指定的元素,根据情况,如果包含则返回true,否则返回false。

const names = ["abc", "cba", "nba", "mba", NaN]
if (names.index0f("cba") !== -1) {
    console.log("包含abc元素")
}
// ES7 ES2016
if (names.includes("cba")) {
    console.log("包含abc元素")
}
if (names.index0f(NaN) !== -1) { //无法判断NaN
    console.log("包含NaN")
}
if (names.includes(NaN)) { //可以判断NaN
    console.log("包含NaN")
}


指数的运算方法,比如3的3次方【乘方】
const result1 = Math.pow(3, 3)
// ES7: **
const result2 = 3 ** 3
console.log(result1, result2)


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值