文章目录
1. Map 和 Object 的不同
API 不同
// 初始化const m =newMap([['key1','hello'],['key2',100],['key3',{x:10}]])// 新增
m.set('name','双越')// 删除
m.delete('key1')// 判断
m.has('key2')// 遍历
m.forEach((value, key)=> console.log(key, value))// 长度(Map 是有序的,下文会讲,所有有长度概念)
m.size
以任意类型为 key
const m =newMap()const o ={p:'Hello World'}
m.set(o,'content')
m.get(o)// "content"
m.has(o)// true
m.delete(o)// true
m.has(o)// false
Map 是有序结构
Object key 不能按照既定顺序输出
// Object keys 是无序的const data1 ={'1':'aaa','2':'bbb','3':'ccc','测试':'000'}
Object.keys(data1)// ["1", "2", "3", "测试"]const data2 ={'测试':'000','1':'aaa','3':'ccc','2':'bbb'};
Object.keys(data2);// ["1", "2", "3", "测试"]
Map key 可以按照既定顺序输出
const m1 =newMap([['1','aaa'],['2','bbb'],['3','ccc'],['测试','000']])
m1.forEach((val, key)=>{ console.log(key, val)})const m2 =newMap([['测试','000'],['1','aaa'],['3','ccc'],['2','bbb']])
m2.forEach((val, key)=>{ console.log(key, val)})
Map 很快
Map 作为纯净的 key-value 数据结构,它比 Object 承载了更少的功能。
Map 虽然有序,但操作很快,和 Object 效率相当。
// Mapconst m =newMap()for(let i =0; i <1000*10000; i++){
m.set(i +'', i)}
console.time('map find')
m.has('2000000')
console.timeEnd('map find')
console.time('map delete')
m.delete('2000000')
console.timeEnd('map delete')
// Objectconst obj ={}for(let i =0; i <1000*10000; i++){
obj[i +'']= i
}
console.time('obj find')
obj['200000']
console.timeEnd('obj find')
console.time('obj delete')delete obj['200000']
console.timeEnd('obj delete')
另外,Map 有序,指的是 key 能按照构架顺序输出,并不是说它像数组一样是一个有序结构 —— 否则就不会这么快了
但这就足够满足我们的需求了。
WeakMap
WeakMap 也是弱引用。但是,WeakMap 弱引用的只是键名 key ,而不是键值 value。
// 函数执行完,obj 会被销毁,因为外面的 WeakMap 是“弱引用”,不算在内const wMap =newWeakMap()functionfn(){const obj ={name:'zhangsan'}// 注意,WeakMap 专门做弱引用的,因此 WeakMap 只接受对象作为键名(`null`除外),不接受其他类型的值作为键名。其他的无意义
wMap.set(obj,100)}fn()// 代码执行完毕之后,obj 会被销毁,wMap 中也不再存在。但我们无法第一时间看到效果。因为:// 内存的垃圾回收机制,不是实时的,而且是 JS 代码控制不了的,因此这里不一定能直接看到效果。
另外,WeakMap 没有
forEach
和
size
,只能
add
delete
has
。因为弱引用,其中的 key 说不定啥时候就被销毁了,不能遍历。
WeakMap 可以做两个对象的关联关系,而不至于循环引用,例如:
const userInfo ={name:'双越'}const cityInfo ={city:'北京'}// // 常规关联,可能会造成循环引用// userInfo.city = cityInfo// cityInfo.user = userInfo// 使用 WeakMap 做关联,则无任何副作用const user_to_city =newWeakMap()
user_to_city.set(userInfo, cityInfo)
总结
- key 可以是任意数据类型
- key 会按照构建顺序输出
- 很快
- WeakMap 弱引用
2. Set 和数组的区别
Set 元素不能重复
const arr =[10,20,30,30,40]const set =newSet([10,20,30,30,40])// 会去重
console.log(set)// Set(4) {10, 20, 30, 40}
// 数组去重functionunique(arr){const set =newSet(arr)return[...set]}unique([10,20,30,30,40])
API 不一样
// 初始化const set =newSet([10,20,30,30,40])// 新增(没有 push unshift ,因为 Set 是无序的,下文会讲)
set.add(50)// 删除
set.delete(10)// 判断
set.has(20)// 长度
set.size
// 遍历
set.forEach(val=> console.log(val))// set 没有 index ,因为是无序的
Set 是无序的,而数组是有序的 —— 这一点很少有人提到,却很关键!!!
先看几个测试
- 数组:前面插入元素 vs 后面插入元素
- 数组插入元素 vs Set 插入元素
- 数组寻找元素 vs Set 寻找元素
// 构造一个大数组const arr =[]for(let i =0; i <1000000; i++){
arr.push(i)}// 数组 前面插入一个元素
console.time('arr unshift')
arr.unshift('a')
console.timeEnd('arr unshift')// unshift 非常慢// 数组 后面插入一个元素
console.time('arr push')
arr.push('a')
console.timeEnd('arr push')// push 很快// 构造一个大 setconst set =newSet()for(let i =0; i <1000000; i++){
set.add(i)}// set 插入一个元素
console.time('set test')
set.add('a')
console.timeEnd('set test')// add 很快// 最后,同时在 set 和数组中,寻找一个元素
console.time('set find')
set.has(490000)
console.timeEnd('set find')// set 寻找非常快
console.time('arr find')
arr.includes(490000)
console.timeEnd('arr find')// arr 寻找较慢
什么是无序,什么是有序?参考
x1-有序和无序.md
- 无序:插入、查找更快
- 有序:插入、查找更慢
因此,如果没有强有序的需求,请用 Set ,会让你更快更爽!
WeakSet
WeekSet 和 Set 类似,区别在于 —— 它不会对元素进行引用计数,更不容易造成内存泄漏。
// 函数执行完,obj 就会被 gc 销毁functionfn(){const obj ={name:'zhangsan'}}fn()
// 函数执行完,obj 不会被销毁,因为一直被外面的 arr 引用着const arr =[]functionfn(){const obj ={name:'zhangsan'}
arr.push(obj)}fn()
// 函数执行完,obj 会被销毁,因为外面的 WeakSet 是“弱引用”,不算在内const wSet =newWeakSet()functionfn(){const obj ={name:'zhangsan'}
wSet.add(obj)// 注意,WeakSet 就是为了做弱引用的,因此不能 add 值类型!!!无意义}fn()
【注意】内存的垃圾回收机制,不是实时的,而且是 JS 代码控制不了的,因此这里不一定能直接看到效果。
WeekSet 没有
forEach
和
size
,只能
add
delete
和
has
。因为垃圾回收机制不可控(js 引擎看时机做垃圾回收),那其中的成员也就不可控。
总结
- Set 值不能重复
- Set 是无序结构
- WeakSet 对元素若引用
3. 数组求和
传统方式
functionsum(arr){let res =0
arr.forEach(n=> res = res + n)return res
}const arr =[10,20,30]
console.log(sum(arr))
reduce 方法的使用
// 累加器const arr1 =[10,20,30,40,50]const arr1Sum = arr1.reduce((sum, curVal, index, arr)=>{
console.log('reduce function ......')
console.log('sum', sum)
console.log('curVal', curVal)
console.log('index', index)
console.log('arr', arr)return sum + curVal // 返回值,会作为下一次执行的 sum},0)
console.log('arr1Sum', arr1Sum)
reduce 的其他用法
// 计数functioncount(arr, value){// 计算 arr 中有几个和 value 相等的数return arr.reduce((c, item)=>{return item === value ? c +1: c
},0)}const arr2 =[10,20,30,40,50,10,20,10]
console.log(count(arr2,20))
// 数组输出字符串const arr3 =[{name:'xialuo',number:'100'},{name:'madongmei',number:'101'},{name:'zhangyang',number:'102'}]// // 普通做法 1(需要声明变量,不好)// let arr3Str = ''// arr3.forEach(item => {// arr3Str += `${item.name} - ${item.number}\n`// })// console.log(arr3Str)// // 普通做法 2(map 生成数组,再进行 join 计算)// console.log(// arr3.map(item => {// return `${item.name} - ${item.number}`// }).join('\n')// )// reduce 做法(只遍历一次,即可返回结果)
console.log(
arr3.reduce((str, item)=>{return`${str}${item.name} - ${item.number}\n`},''))
版权归原作者 ~black- 所有, 如有侵权,请联系我们删除。