一、ES6
1.Set
1.Set的基本使用
- 在ES6之前,我们存储数据的结构主要有两种:数组、对象。
- 在ES6中新增了另外两种数据结构:Set、Map,以及它们的另外形式WeakSet、WeakMap
数据结构:存储数据的方式
-
Set是一个新增的数据结构,可以用来保存数据,类似于数组,但和数组最大的区别是 元素不能重复
- 创建Set我们需要使用Set构造函数(暂时没有字面量创建的方式)
-
应用场景
- 添加的元素希望不重复
- 给数组去重
- new Set(arr)
- 转化为数组
- Array.from()
- 展开运算符
// 10,20,40,333
// * 创建Set结构
let set=new Set();
// * 添加元素
set.add(10)
set.add(20)
set.add(40)
set.add(333)
set.add(10);//重复的元素会被忽略
// * 添加对象的注意点
set.add({});//两个对象是有不同的内存地址
set.add({});//和上面的{}的地址是不同的
const obj={name:"wjy"};
set.add(obj);
set.add(obj); //*重复的内存地址也只会被添加一次
console.log(set);
// * 应用场景:①不想添加的元素重复 ② 给数组去重
const arr=[22,10,20,45,22,10,2];
// * 1.自己写的一个方法
const newArr=[];
for(const item of arr){
if(newArr.indexOf(item)==-1){
newArr.push(item)
}
}
// * 可以使用Set
const arrSet=new Set(arr);
// * 方法1 Array.from
const newArr2=Array.from(arrSet);//* Array.from():对一个类似数组或可迭代对象创建一个新的、浅拷贝的数组实例
console.log(newArr2);
// * 方法2:展开运算符
const newArr3=[...arrSet];
console.log(newArr3);
2.Set常见的属性和方法
2.1 常见的属性
- size:获取set的元素个数
console.log(set.size);
2.2 常见的方法
- add(item):添加指定的元素,如果存在,则不添加
- delete(item):删除指定的元素
- has(item):判断指定的item是否在Set中
- clear():清空Set集合
- 遍历
- forEach遍历
- for...of
/**
* * 常见的方法
* * 1. add(item):添加指定元素
* * 2. delete(item):删除指定元素
* * 3.has(item):判断指定元素是否在Set中,如果有则返回true,否则返回false
* * 4.clear():清空Set集合
*/
set.add("wjy");
console.log(set);
set.delete("wjy");
console.log(set);
console.log(set.has("wjy"));
set.forEach(item=>{
console.log(item);
})
for(const item of set){
console.log(item);
}
set.clear();
console.log(set);
2.WeakSet
和Set类似的另外一个数据结构称之为WeakSet,也是内部元素不能重复的数据结构。
- 那么和Set有什么区别呢?
- 区别一:WeakSet只能存放对象类型,不能存放基本数据类型
- 区别二:WeakSet对元素的引用是弱引用,如果没有其他引用对某个对象进行引用,那么GC可以对该对象进行回收。
强引用指的的是 指向的那条线是生效的。
弱引用指的是指向的那条线存在不存在,没有任何关系。
let obj={name:"why"};
let set=new Set();
set.add(obj);
console.log(set);
image-20220510185545267.png
如果将obj设置为null,set存储的元素也还是会被引用。
obj=null;
console.log(set);
image-20220510185619772.png
但如果是 WeakSet,因为WeakSet对元素的引用是弱引用,所以由weakSet指向那片地址其实没有用的,不算真正的引用,如果初略WeakSet本身实例指向那片地址,没有其他引用引用这个对象的话,这个对象会被GC回收掉。
const weakSet=new WeakSet();
let obj={name:"why"};
weakSet.add(obj);
image-20220510185836514.png
obj=null;
当obj不再引用这片地址空间时,没有其他引用引用了,除了weakSet本身的弱引用(但是这个弱引用是没有用的),这片内存空间会被GC回收掉。
image-20220510190221909.png2.1 WeakSet的常用方法
- add(item):添加某个元素,返回WeakSet对象本身
- delete(item):从WeakSet中删除和这个值相等的元素,返回boolean类型
- has(value):判断WeakSet中是否存在某个元素,返回boolean类型
注意:WeakSet不能遍历
- 因为WeakSset只是对对象的弱引用,如果我们遍历获取到其中的元素,那么有可能造成对象不能正常的销毁
- 所以存储到WeakSet是没办法正常获取的。
2.2 应用场景
我们使用一个Stack Overflow上的答案:只能使用Person实例调用running,相对于Set比较方便,不需要手动是释放内存。
let weak=new WeakSet();
class Person{
constructor(){
weak.add(this);
}
running(){
if(!weak.has(this)) throw new Error("Type Error ,NOT Person")
console.log("running");
}
}
const p=new Person();
p.running.call({name:'wjy'});
3.Map
另外一个新增的数据结构是Map,用于存储映射关系。
但是我们可能会想,在之前我们可以使用对象来存储映射关系,他们有什么区别呢?
- 事实上我们对象存储映射关系只能使用字符串(ES6中新增了Symbol)作为属性名(key)
- 某些情况下我们可能希望通过其他类型作为key,比如key,这个时候会自动将对象转化为字符串来作为key
let obj1={name:"wjy"};
let obj2={name:"hyz"};
let o={
[obj1]:'aaa',
[obj2]:'bbb'
}
//* 因为对象后面被直接转换为 字符串[object Object],所以当同样的key被重复赋值时,只会保留最新的值。
//* []:这个是计算属性
console.log(o);//{ '[object Object]': 'bbb' }
那么我们就可以使用Map:
- new Map() 创建一个Map实例对象
- set(key,value)
// * Map允许对象作为key
let map=new Map();
let obj1={name:"wjy"};
let obj2={name:"hyz"};
map.set(obj1,"aaa");
map.set(obj2,"bbb")
map.set("name","wjy")
console.log(map);
// Map(3) {
// { name: 'wjy' } => 'aaa',
// { name: 'hyz' } => 'bbb',
// 'name' => 'wjy'
// }
let map2=new Map([[obj1,"aaa"],[obj2,"bbb"],["name","wjy"]]);//可以传入数组
console.log(map2);
// Map(3) {
// { name: 'wjy' } => 'aaa',
// { name: 'hyz' } => 'bbb',
// 'name' => 'wjy'
// }
3.1 常用的方法和属性
Map常见的属性:
- size:返回Map的元素的个数
Map常用的方法:
- set(key,value):在Map中添加key和value,并将整个Map对象返回。
- get(key):根据key获取Map中的value。
- has(key):判断是否包含某个key,返回Boolean类型。
- delete(key):根据key删除一个键值对,返回Boolean类型。删除成功,返回true,删除失败,返回false
- clear():清空map
- 遍历
- forEach((value,key)=>{})
- for....of
- 数组类型,第一个元素是key,第二个元素是value
/**
* * 常用属性
* * size:获取Map的元素个数
*/
console.log(map2.size);//3
/**
* * 常用方法
* * set:添加一个key和value,并将整个Map对象返回
* * get:根据key获取Map中的value
* * has:判断是否包含某个key,返回Boolean
* * delete:根据key,删除键值对,删除成功返回true,删除失败返回false
* * clear:清空
*/
console.log(map2.get(obj1));//aaa
console.log(map2.has("name"));//true
console.log(map2.delete("aa"));//false
map2.clear();
console.log(map2);//Map(0) {}
4.WeakMap
和Map类型相似的另外一个数据结构称之为WeakMap,也是以键值对的形式存在的。
那么和Map有什么区别呢?
- WeakMap的key只能使用对象,不能使用基本数据类型
- WeakMap的key对对象的引用是弱引用,如果没有其他引用引用这个对象,那么GC可以回收该对象。
Map是对key的强引用,WeakMap是对key的弱引用(这个引用是没有关系的)
let obj1={name:"obj1"};
const map=new Map();
map.set(obj1,"aaaa");
image-20220510213359653.png
obj1=null
将obj1指向null,不指向那片内存空间,但是由于Map中对key的引用是强引用,所以并不会被回收掉的。
image-20220510213530774.png但如果是WeakMap结果就是不一样的了。
let obj1={name:"obj1"};
const map=new WeakMap();
map.set(obj1,"aaa");
image-20220510214123411.png
obj1=null;
将obj1指向null,不再指向那片空间,由于在weakMap中是弱引用,所以那片空间是可以被GC回收的。
image-20220510214717212.png4.1 常见方法
- set (key,value):向WeakMap中添加key,value值,并将整个WeakMap对象返回
- get(key):根据key返回Map中的value
- has(key):判断是否包含一个key,返回Boolean类型
- delete(key):根据key删除一个键值对,返回Boolean类型
不能遍历
- 没有forEach
- 也不能使用for...of
let obj1={name:"obj1"};
const map=new WeakMap();
map.set(obj1,"aaa");
/**
* * 常见的方法
* * set
* * get
* * delete
* * has
*/
console.log(map.get(obj1));//aaa
console.log(map.has(obj1));//true
console.log(map.delete(obj1));//true
4.2 应用场景
- Vue3响应式应用场景
let obj1={name:"wjy",age:20};
function obj1NameFn1(){
console.log("obj1NameFn1被执行了");
}
function obj1NameFn2(){
console.log("obj1NameFn2被执行了");
}
function obj1AgeFn1(){
console.log("obj1AgeFn1被执行了");
}
function obj1AgeFn2(){
console.log("obj1AgeFn2被执行了");
}
let obj2={
name:"kobe",
height:1.88,
address:"广州市"
}
function obj2NameFn1(){
console.log("obj2NameFn1被执行了");
}
function obj2NameFn2(){
console.log("obj2NameFn2被执行了");
}
// 1. 创建一个WeakMap
let weakMap=new WeakMap();
// 2.1 收集依赖数据结构:对obj1收集的数据结构
const obj1Map=new Map();
obj1Map.set("name",[obj1NameFn1,obj1NameFn2]);
obj1Map.set("age",[obj1AgeFn1,obj1AgeFn2]);
weakMap.set(obj1,obj1Map)
// 2.2.收集依赖数据结构
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())
二、ES7
1.Array Includes
在ES7之前,如果我们想判断一个数组中是否包含某个元素,需要通过indexOf获取结果,并且判断是否为-1
在ES7之后,我们可以通过includes来判断一个数组中是否包含一个指定的元素,根据情况,如果包含则返回true,否则返回false
语法:
Array.includes(item,startIndex)
- item:必需参数
- startIndex:可选,从哪个位置开始查找
const names=["wjy","hyz","tl"];
if(names.indexOf("abc")!==-1){ //阅读性差
console.log("包含");
}
// ES7 Array.includes():判断数组是否包含某个元素
// includes(item,startIndex); startIndex:从哪个位置开始判断
if(names.includes("wjy",0)){
console.log("包含");
}
1.1 Array.includes和Array.indexOf的区别
如果数组中有个元素为NaN,
如果使用indexOf判断NaN是否存在,它会返回-1(找不到NaN这个元素)
如果使用includes判断NaN是否存在,它会返回true(找到了这个NaN元素)
const names=["wjy","hyz","tl",NaN];
if(names.indexOf(NaN)!==-1){ //* 即使数组中有NaN,但还是被判断为不存在
console.log("包含NaN");
}
if(names.includes(NaN)){
console.log("包含NaN");
}
2.指数(乘方运算)
在ES7之前,计算数字的乘方需要使用Math.pow方法来完成。
在ES7中,增加了**运算符,可以对数字来计算乘方。
// 计算3的3次方
// ES7之前
const result1=Math.pow(3,3);
// ES7后
const result2=3**3;
console.log(result1==result2);//true
网友评论