一篇吃透Object、Map、WeekMap和Set

Object

JavaScript中的对象是一种特殊的数据类型,它可以存储多个键值对,并且可以包含其他对象、数组、函数等。以下是关于JavaScript对象的详细解释:

  1. 创建对象:可以使用字面量语法来创建一个对象,语法如下:
let obj = {
  key1: value1,
  key2: value2,
  //...
}

或者使用构造函数来创建对象:

let obj = new Object();
obj.key1 = value1;
obj.key2 = value2;
  • 属性和方法:对象的键值对中的键被称为属性,值被称为属性值。对象的属性值可以是任何数据类型,包括其他对象、数组、函数等。对象的属性也可以是一个方法,即一个函数作为属性值。
  • 访问对象属性和方法:可以通过点号(.)或者方括号([])来访问对象的属性和方法。示例:
obj.key1; // 通过点号访问属性
obj['key1']; // 通过方括号访问属性
obj.method(); // 调用对象的方法
  • 原型链:JavaScript中的对象是基于原型链的,每个对象都有一个指向一个原型对象的内部链接。当访问一个对象的属性或方法时,如果该对象没有该属性或方法,JavaScript会沿着原型链向上查找,直到找到为止。
  • 构造函数和原型:可以使用构造函数和原型来创建对象的模板,所有使用该构造函数创建的对象都会共享原型对象的属性和方法。示例:
function Person(name, age) {
  this.name = name;
  this.age = age;
}

Person.prototype.sayHello = function() {
  console.log('Hello, my name is ' + this.name);
}

let person1 = new Person('Alice', 20);
let person2 = new Person('Bob', 25);
  1. JSON对象:JavaScript对象表示法(JSON)是一种轻量级的数据交换格式,它基于JavaScript对象语法,但是不同于JavaScript对象。JSON对象通常用于通过网络传输数据。

Map

map本质上就是键值对的集合,但是普通的Object中的键值对中的键只能是字符串。而ES6提供的Map数据结构类似于对象,但是它的键不限制范围,可以是任意类型,是一种更加完善的Hash结构。如果Map的键是一个原始数据类型,只要两个键严格相同,就视为是同一个键。

const map = [
     ["name","张三"],
     ["age",18],
]

 

Map数据结构有以下操作方法:

  • sizemap.size 返回Map结构的成员总数。

  • set(key,value) :设置键名key对应的键值value,然后返回整个Map结构,如果key已经有值,则键值会被更新,否则就新生成该键。(因为返回的是当前Map对象,所以可以链式调用)

  • get(key) :该方法读取key对应的键值,如果找不到key,返回undefined。

  • has(key) :该方法返回一个布尔值,表示某个键是否在当前Map对象中。

  • delete(key) :该方法删除某个键,返回true,如果删除失败,返回false。

  • clear() :map.clear()清除所有成员,没有返回值。

Map结构原生提供是三个遍历器生成函数和一个遍历方法

  • keys():返回键名的遍历器。
  • values():返回键值的遍历器。
  • entries():返回所有成员的遍历器。
  • forEach():遍历Map的所有成员。
const map = new Map([
     ["foo",1],
     ["bar",2],
])
for(let key of map.keys()){
    console.log(key);  // foo bar
}
for(let value of map.values()){
     console.log(value); // 1 2
}
for(let items of map.entries()){
    console.log(items);  // ["foo",1]  ["bar",2]
}
map.forEach( (value,key,map) => {
     console.log(key,value); // foo 1    bar 2
})

 

存储原理:

map是一种用于存储键值对数据的数据结构。它的原理是使用哈希表来存储键值对。哈希表是一种利用哈希函数来计算索引位置的数据结构,可以实现快速的插入、删除和查找操作。

当向map中添加键值对时,首先会通过哈希函数计算出键的哈希值,然后再将哈希值映射到存储空间的索引位置。这样就可以快速地定位到对应的存储位置,从而实现快速的存取操作。

在map中,不同的键可能会产生相同的哈希值,这就会产生哈希冲突。为了解决哈希冲突,map通常会采用一些策略,如开放寻址法或链表法来处理冲突。

Map和Object对比

MapObject
Map默认情况不包含任何键,只包含显式插入的键。Object 有一个原型, 原型链上的键名有可能和自己在对象上的设置的键名产生冲突。
Map的键可以是任意值,包括函数、对象或任意基本类型。Object 的键必须是 String 或是Symbol。
Map 中的 key 是有序的。因此,当迭代的时候, Map 对象以插入的顺序返回键值。Object 的键是无序的
Map 的键值对个数可以轻易地通过size 属性获取Object 的键值对个数只能手动计算
Map 是 iterable 的,所以可以直接被迭代。迭代Object需要以某种方式获取它的键然后才能迭代。
在频繁增删键值对的场景下表现更好。在频繁添加和删除键值对的场景下未作出优化。

WeakMap

WeakMap 对象也是一组键值对的集合,其中的键是弱引用的。其键必须是对象,原始数据类型不能作为key值,而值可以是任意的。

该对象也有以下几种方法:

  • set(key,value) :设置键名key对应的键值value,然后返回整个Map结构,如果key已经有值,则键值会被更新,否则就新生成该键。(因为返回的是当前Map对象,所以可以链式调用)
  • get(key) :该方法读取key对应的键值,如果找不到key,返回undefined。
  • has(key) :该方法返回一个布尔值,表示某个键是否在当前Map对象中。
  • delete(key) :该方法删除某个键,返回true,如果删除失败,返回false。

其clear()方法已经被弃用,所以可以通过创建一个空的WeakMap并替换原对象来实现清除。 WeakMap的设计目的在于,有时想在某个对象上面存放一些数据,但是这会形成对于这个对象的引用。一旦不再需要这两个对象,就必须手动删除这个引用,否则垃圾回收机制就不会释放对象占用的内存。

而WeakMap的键名所引用的对象都是弱引用,即垃圾回收机制不将该引用考虑在内。因此,只要所引用的对象的其他引用都被清除,垃圾回收机制就会释放该对象所占用的内存。也就是说,一旦不再需要,WeakMap 里面的键名对象和所对应的键值对会自动消失,不用手动删除引用

设计目的再理解:

在普通的 Map 对象中,如果一个键引用的对象被销毁了,但是该键仍然存在于 Map 对象中,那么这个对象将始终存在于内存中,直到该键被从 Map 对象中删除。这可能导致内存泄漏,因为该对象无法被垃圾回收。

WeakMap 对象解决了这个问题,它中存储的键是“弱引用”,意味着如果键引用的对象被销毁了,那么该键也会被自动从 WeakMap 对象中删除,从而避免了内存泄漏问题。

因此,WeakMap 的设计目的主要是为了提供一种存储键值对的数据结构,同时避免了可能引发内存泄漏的问题,特别适用于存储动态创建的对象,并且这些对象可能会在后续的执行过程中被销毁的情况下。

Set

Set 对象允许你存储任何类型的值,无论是原始值或者是对象引用。它类似于数组,但是成员的值都是唯一的,没有重复的值

Set 本身是一个构造函数,用来生成Set 数据结构Set函数可以接受一个数组(或者具有 iterable 接口的其他数据结构)作为参数,用来初始化。

Set中的特殊值:

Set 对象存储的值总是唯一的,所以需要判断两个值是否恒等。有几个特殊值需要特殊对待:

  • +0 与 -0 在存储判断唯一性的时候是恒等的,所以不重复
  • undefined 与 undefined 是恒等的,所以不重复
  • NaN 与 NaN 是不恒等的,但是在 Set 中认为NaN与NaN相等,所有只能存在一个,不重复。
  • {} {} 两个空对象的指针不一样,所以会重复
Set实例对象的属性:
  • size:返回Set实例的成员总数。
Set实例对象的方法:
  • add(value):添加某个值,返回 Set 结构本身(可以链式调用)。
  • delete(value):删除某个值,删除成功返回true,否则返回false。
  • has(value):返回一个布尔值,表示该值是否为Set的成员。
  • clear():清除所有成员,没有返回值。
const mySet = new Set(['a', 'a', 'b', 11, 22, 11])
console.log(mySet)  // {'a', 'b', 11, 22}
myset.add('c').add({'a': 1})
console.log(mySet) // {'a', 'b', 11, 22, 'c', {a: 1}}
console.log(mySet.size) // 6

mySet.has(22) // true

遍历方法
 - keys():返回键名的遍历器。
 - values():返回键值的遍历器。
 - entries():返回键值对的遍历器。
 - forEach():使用回调函数遍历每个成员。
 
由于Set结构没有键名,只有键值(**或者说键名和键值是同一个值**),所以keys方法和values方法的行为完全一致。

const set = new Set(['a', 'b', 'c'])

for (let item of set.keys()) {
  console.log(item)
}
// a
// b
// c

for (let item of set.values()) {
  console.log(item)
}
// a
// b
// c

for (let item of set.entries()) {
  console.log(item)
}
// ["a", "a"]
// ["b", "b"]
// ["c", "c"]

// 直接遍历set实例,等同于遍历set实例的values方法
for (let i of set) {
  console.log(i)
}
// a
// b
// c

set.forEach((value, key) => console.log(key + ' : ' + value))

// a: a
// b: b
// c: c
Set 对象作用:
  • 数组去重(利用扩展运算符)
const mySet = new Set([1, 2, 3, 4, 4])
[...mySet] // [1, 2, 3, 4]
合并两个set对象:
let a = new Set([1, 2, 3])
let b = new Set([4, 3, 2])
let union = new Set([...a, ...b]) // {1, 2, 3, 4}

  • 交集
let a = new Set([1, 2, 3]) 
let b = new Set([2, 3, 6]) 
let intersect = new Set([...a].filter(x => b.has(x))) // {2, 3} 利用数组的filter方法。
  • 差集
let a = new Set([1, 2, 3])
let b = new Set([4, 3, 2])
let difference = new Set([...a].filter(x => !b.has(x))) //  {1} 

 

存储原理:

Set存储原理也是基于哈希表的数据结构来实现的。在set中,元素作为键存储在哈希表中,具有唯一性,不允许重复元素存在。

当要向set中插入元素时,先对元素进行哈希函数计算,得到其哈希值,然后根据哈希值确定插入的位置。如果该位置已经有元素存在,就发生了哈希冲突,可以通过开放定址法或链地址法等解决方法来处理。在查找元素时,同样先计算哈希值,然后通过哈希表直接定位元素位置,以此快速找到目标元素。

通过哈希表的实现,set能够实现高效的插入、删除和查找操作,时间复杂度通常为O(1),使得set成为一种高效的存储结构

总结:

  • 对象是一种非常灵活的数据类型,它可以存储各种数据,并且可以方便地进行操作和访问。对于熟练掌握对象的使用和原型链的理解对于深入理解JavaScript语言非常重要。
  • Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。
  • WeakMap 结构与 Map 结构类似,也是用于生成键值对的集合。但是 WeakMap 只接受对象作为键名( null 除外),不接受其他类型的值作为键名。而且 WeakMap 的键名所指向的对象,不计入垃圾回收机制。
  • Set是值的集合,值是唯一的可以做数组去重,可以认为只有一个数据,并且set中元素不可以重复且自动排序。

文章转自:https://juejin.cn/post/7376936392620720147
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值