1.Iterator遍历器;
1.1 for...of为什么遍历object对象;
let obj = {
name: '张三'
};
for (let v of obj) {
console.log(v); //obj is not iterable
}
报错原因是obj不是一个迭代器。
要想能够被for...of正常遍历的,都需要实现一个遍历器Iterator,而数组,Set和Map结构,早就内置好了遍历器Iterator,
他们的原型中都有一个Symbol.iterator方法,而Object对象没有这个接口,所以不能遍历。
console.log(Array.prototype[Symbol.iterator]); //ƒ values() { [native code] }
console.log(String.prototype[Symbol.iterator]); //ƒ [Symbol.iterator]() { [native code] }
console.log(Set.prototype[Symbol.iterator]); //ƒ values() { [native code] }
console.log(Map.prototype[Symbol.iterator]); //ƒ entries() { [native code] }
console.log(Object.prototype[Symbol.iterator]); //undefined
Object原型里面没有iterator迭代器的。
1.2Iterator迭代器原理
let arr = [1, 2, 3, 4];
let iter = arr[Symbol.iterator]();
console.log(iter);
console.log(iter.next()); //{value: 1, done: false}
console.log(iter.next()); //{value: 2, done: false}
console.log(iter.next()); //{value: 3, done: false}
console.log(iter.next()); //{value: 4, done: false}
console.log(iter.next()); //{value: undefined, done: true}
当可遍历对象被for...of遍历的时候,[Symbol.iterator]()就会被调用,返回一个iterator对象,其中里面有一个next()方法,
会返回一个对象,返回的对象里面有两个参数:value,done,每调用一次next方法,value就会遍历一次可遍历对象里面的属性值,done表示遍历的状态,没有遍历完成的时候,done为false,遍历完成之后done为true,value为undefined;
1.3自定义遍历器
let obj = {
0: '我是0',
1: '我是1',
2: '我是2',
3: '我是3',
length: 4,
[Symbol.iterator]: function() {
let index = 0;
return {
next: () => {
let value = index;
let done = index >= this.length; //当done为true的时候,遍历结束
index++
return {
value,
done
}
}
}
}
}
for (let v of obj) {
console.log(v);
//0 1 2 3
}
此案例较为简单,因为obj里面的属性名为0 1 2 3 对应index,如果属性名不这么简单,那么就需要用Object.keys()方法了。
let obj = {
'name': '我是0',
'age': '我是1',
'sex': '我是2',
[Symbol.iterator]: function() {
let index = 0;
return {
next: () => {
let value = Object.keys(obj)[index];
let done = index >= Object.keys(obj).length; //当done为true的时候,遍历结束
index++
return {
value,
done
}
}
}
}
}
for (let v of obj) {
console.log(v);
//name age sex
}
2.Generator函数
2.1 声明Generator函数
function* Hello(name){
yield `我的名字是${name}`;
yield `how are you`;
yield `怎么样`;
}
声明的Generator函数与声明普通函数时候的区别:Generator函数在function后面加*号,返回不用return,而是用yield,可以返回多次;
2.2 Generator函数的调用
function* Hello(name) {
yield `我的名字是${name}`;
yield `how are you`;
yield `怎么样`;
}
let gen = Hello('张三');
console.log(gen.next()); //{value: "我的名字是张三", done: false}
console.log(gen.next()); //{value: "how are you", done: false}
console.log(gen.next()); //{value: "怎么样", done: false}
console.log(gen.next()); //{value: undefined, done: true}
返回的结果是一个对象,里面有next()方法;使用方法和迭代器一样;
2.3 next方法接收参数
next()方法可以接受一个参数,它的参数会作为上一个yield的返回值;
function* Hello() {
let res = yield `hello`;
yield res;
}
let iter = Hello();
console.log(iter.next()); //{value: "hello", done: false}
console.log(iter.next('张三')); //{value: "张三", done: false}
console.log(iter.next('lisi')); //{value: undefined, done: true}
第一次调用next方法,没有传递参数,res是yield返回的hello,又返回res,所以第一次返回的是hello,第二次传参,‘张三',
作为上一个yield的返回值,’张三‘替代了’hello‘,此时res就变成了’张三‘,第三次的参数作为第二次的返回值,把第二次的res替代,但是没有第三次的yield,打印第三次的时候,done的状态为true。
2.4 yield关键字,在Generator函数里面,如果我们想要调用另一个Generator函数,就需要用到关键字yield*;
function* fn1() {
yield 'fn1开始';
yield 'fn1结束';
}
function* fn2() {
yield 'fn2开始';
yield 'fn2结束'
}
function* start() {
yield 'start';
yield* fn1();
yield* fn2();
yield 'end';
}
let ite = start();
console.log(ite.next()); //{value: "start", done: false}
console.log(ite.next()); //{value: "fn1开始", done: false}
console.log(ite.next()); //{value: "fn1结束", done: false}
console.log(ite.next()); //{value: "fn2开始", done: false}
console.log(ite.next()); //{value: "fn2结束", done: false}
console.log(ite.next()); //{value: "end", done: false}
console.log(ite.next()); //{value: undefined, done: true}
-
Set和WeakSet用法
什么是Set是一种新的数据结构,可以理解为值的集合,它的值不会有重复项;(可以用于数组去重)3.1 Set的基本用法:
let s = new Set();
console.log(s); //是一个构造函数 Set{}
let s = new Set([1, 2, 3, 4, 5]);
console.log(s); // {1, 2, 3, 4, 5}
3.2 成员值得唯一性
let s = new Set();
s.add(1);
s.add(1);
console.log(s); //{1}
3.3 size属性:获取成员个数
let s = new Set([1, 2, 3, 4, 5]);
console.log(s); // {1, 2, 3, 4, 5}
console.log(s.size); //5
3.4 delete属性
delete()方法:用户删除Set结构中的指定值,删除成功返回:true,删除失败返回:false。
let s = new Set([1, 2, 3, 4, 5]);
console.log(s); // {1, 2, 3, 4, 5}
console.log(s.delete(2)); //true
console.log(s.delete(8)); //false
console.log(s); // {1, 3, 5}
3.5 clear方法
clear()方法:清除所有成员;
let s = new Set([1, 2, 3, 4, 5]);
s.clear();
console.log(s); //{}
3.6 has()方法:判断set结构中是否含有指定的值。如果有,返回true,如果没有,返回false;
let s = new Set([1, 2, 3, 4, 5]);
console.log(s.has(1)); //true
console.log(s.has(7)); //false
3.7 enteries方法
返回一个键值对的遍历器
let s = new Set([1, 2, 3, 4, 5]);
console.log(s.entries()); //SetIterator {1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5}
需要注意的是,返回的键名和键值都是同一个值;
3.8 keys和values方法
keys()方法:返回键名的遍历器;
values()方法:返回键值的遍历器;
let s = new Set([1, 2, 3, 4, 5]);
console.log(s.keys()); //SetIterator {1, 2, 3, 4, 5}
console.log(s.values()); //SetIterator {1, 2, 3, 4, 5}
let s = new Set([1, 2, 3, 4, 5]);
for (let [i, v] of s.entries()) {
console.log(i);
console.log(v);
}
3.7 foreach方法:遍历每一个成员;
let s = new Set([1, 2, 3, 4, 5]);
s.forEach(function(value, index) {
console.log(value, index);
// 1 1
// 2 2
// 3 3
// 4 4
// 5 5
})
Set用途1:数组去重
function removal(arr) {
return Array.from(new Set(arr));
}
console.log(removal([1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 8, 8, 9])); //[1, 2, 3, 4, 5, 6, 8, 9]
4.Weakset结构:Weakset结构同样不会存储重复的值,不同的是,他的成员必须是对象类型的值
let ws = new WeakSet([{
'name': '张三',
'age': 12
}]);
console.log(ws); //返回一个WeakSet实例化对象
let ws1 = new WeakSet({
'name': '李四',
'age': 24
});
console.log(ws1); //报错
Weakset结构不能遍历,因为它的成员都是对象的弱类型,随时都会被回收机制回收,成员消失,所以Weakset结构不会有keys(),values(),entries(),forEach()等方法和size属性
5.Map的用法;
Map和对象类似,不过对象的属性名是字符串类型的,Map的属性名不再局限于字符串类型,可以是其他类型的;
let m = new Map();
console.log(m); //Map(0) {}
let m1 = new Map([
['name', '张三'],
['age', 12]
]);
console.log(m1); //Map(2) {"name" => "张三", "age" => 12}
5.1 set方法
let m = new Map();
console.log(m);
let m1 = new Map([
['name', '张三'],
['age', 12]
]);
console.log(m1);
m1.set(1, 2)
console.log(m1); //Map(3) {"name" => "张三", "age" => 12, 1 => 2}
5.2get方法
let m = new Map();
console.log(m);
let m1 = new Map([
['name', '张三'],
['age', 12]
]);
console.log(m1.get('name')); //张三
5.3 delete方法:删除指定的键值对,删除成功返回:true,删除失败,返回:false;
let m = new Map();
console.log(m);
let m1 = new Map([
['name', '张三'],
['age', 12]
]);
console.log(m1.delete('name')); //ture
5.4 clear方法():删除Map里面所有的键值对;
5.5 has():查找是否含有指定的键值对,有就返回true,没有就返回false;
let m = new Map();
console.log(m);
let m1 = new Map([
['name', '张三'],
['age', 12]
]);
console.log(m1.delete('name')); //ture
console.log(m1.has('name')); //false delete方法已经删除了name
console.log(m1.has('age')); //true
5.6 entries方法:返回实例的键值对遍历器;
let m = new Map();
console.log(m);
let m1 = new Map([
['name', '张三'],
['age', 12]
]);
console.log(m1.entries()); //MapIterator {"name" => "张三", "age" => 12}
5.7 keys()和values()方法;
keys():返回实例所有键名的遍历器;
values():返回实例所有键值的遍历器;
let m = new Map();
console.log(m);
let m1 = new Map([
['name', '张三'],
['age', 12]
]);
for (let key of m1.keys()) {
console.log(key); //name age
}
for (let value of m1.values()) {
console.log(value); //张三 12
}
5.8 forEach()方法:遍历每一个键值对
let m = new Map();
console.log(m);
let m1 = new Map([
['name', '张三'],
['age', 12]
]);
m1.forEach(function(value, key) {
console.log(value + ':' + key);
}) //name:张三 age:12
5.9 size属性:获取实例的成员数;
6.WeakMap的基本用法:WeakMap结构的键名只支持引用类型的数据;
let wm = new WeakMap();
// console.log(wm.set(1, 2)); //报错
wm.set({
'name': '张三',
'age': 12
}, 2);
console.log(wm); //WeakMap {{…} => 2}
WeakMap和Map的区别:WeakMap结构的键名不能是基本数据类型的,而是引用数据类型的,Map结构的键名可以是基本数据类型的。WeakMap都含有get,has,delete方法,但是WeakMap不支持clear方法,不支持遍历,没有keys,values,entries,forEach这四个方法,也没有属性size.