1. 备忘录模式
1.1 定义
备忘录模式(Memeto) : 在不改变对象封装性的前提下,在对象之外捕获并保存该对象内部的状态以便日后使用.
1.2 作用
- 记录并保存对象的内部状态, 实现了对信息的缓存.
- 通过对象状态的缓存, 避免重复的去获取状态的操作.
- 允许对象能够恢复到原先的状态.可供一个可回滚的操作.
1.3应用场景
假设当我们通过一个点击按钮发送ajax请求拿到了后端返回的结果,当我们重复点击时会重复的发送ajax请求, 假设每次拿到的数据都是一样的,此时我们其实没必要每次点击都发送ajax请求, 因为这样会增加服务器的压力, 我们可以将第一次请求的结果保存起来,下次请求先进行判断是否已经得到过数据,在决定是否使用ajax.
很多分页的按钮原理都是一样的, 点击下一页, 发送请求拿到数据,在点上一页就没必要发送请求了, 因为数据已经展示过了, 保存起来用现成的数据就可以了,减少请求也是优化的关键.
let btn = document.querySelector('#btn');
let request = function(key){
// 缓存数据
let cache = {};
return async function(){
/*如果缓存里面没有数据其
发送请求成功后处理数据并放入数据
*/
if(!cache[key]){
const url = 'http://localhost:3000/goods';
const response = await fetch(url);
data = await response.json();
// 处理数据
result(data)
//缓存数据
cache[key] = data;
}else{
// 当缓存中有数据 直接处理
result(cache[key])
}
}
}
//处理数据的函数
function result(data){}
btn.onclick = request(1)
总结 备忘录模式通常用来记录一个对象的内部状态, 给用户提供了一种恢复状态的机制, 可以使用户可以比较方便的回到某个历史的状态,实现了对象信息的缓存, 当缓存中有对应的数据时, 可以直接从缓存中去,避免重复去获取数据.
2. 迭代器模式
2.1 定义
迭代器模式(Iterator): 在不暴露对象内部结构的同时, 可以顺序地访问集合对象内部的各个元素.
看名字我们就可以发现, 其实JavaScript内中有很很多的迭代器了, 比如forEach, every, map,some,reduce,等等, 在ES6中迭代器的概念更加明显, 很多功能都是基于迭代器实现的.
2.2 作用
- 为不同的数据类型提供一种统一的遍历接口.实现对数据的遍历.
- 把遍历的操作交个迭代器, 我们只需要实现出具体的遍历操作.
- 简化了遍历对象的操作, 实现我们可以很方便得进行遍历.
2.3 应用场景
- 内部迭代器
迭代的过程在方法内部完成, 也就是说我们不需要管迭代的进度,也没法管, 比如forEach
let list = document.getElementsByTagName('p');
[...list].forEach(item =>{
console.log(item)
})
由于通过getElementsByTagName获取的DOM节点数据类型为HTMLCollection, 它是一个类数组对象, 不是数组对象, 所以它原型上并没有forEach方法, 我们通过spread运算符将其类型隐式转换了数组类型, 实现了对象集合对象的遍历.
用于forEach不兼容IE, 我们可以自己来简单实现
Array.prototype.forEach = function(callback){
for(let i =0,len =this.length;i < len; i++){
callback(item,i,this)
}
}
- 外部迭代器
需要我们手动操作, 才会进行下一次的遍历, ES6里面已经原生的实现了这个功能,通过.next()来操控迭代器对象:
let arr = [34,5,545];
let iterator = arr[Symbol.iterator]();
console.log(iterator.next())
// {value:34, done:false}
console.log(iterator.next())
// {value:5, done:false}
console.log(iterator.next())
// {value:545, done:false}
console.log(iterator.next())
// {value:undefined, done:true}
ES6内部在数组类型的数据上部署了Symbol.Iterator接口, 通过调用这个函数我们就可以返回一个迭代器对象, 通过调用迭代器对象的next方法我们可以从头到尾获取到数据的每一项数据, next方法返回一个对象 其中value属性为当前指向的数据,done表示是否已经完成了遍历.
自身实现一个外部迭代器
function MyIterator(arr) {
let currentIndex = 0,
length = arr.length;
return {
next() {
return currentIndex > length
? { value: undefined, done: true }
: { value: arr[currentIndex++], done: false };
}
}
}
利用这个遍历器和循环我们可以属性对数组每项数据的读取
function each(arr,callback){
let iterator = MyIterator(arr);
let result = iterator.next(),
index = 0;// 用来当前遍历的下标
// 当result的done不为true继续调用next方法
while (!result.done) {
callback(result.value,index++,arr);
result = iterator.next();
}
}
each([34,,4,54],(item) =>{
console.log(item)
})
- 对象相关的迭代器与迭代器函数
ES6定义了Object.keys,Object.values,Object.entries等相关的方法, 让我们能方便的遍历对象的属性名或者属性值.同时也定义了for..of循环,ES6规定只要对象上部署了Symbol.Iterator遍历器生成方法, 就可以使用for...of循环.
let obj = { name: '张三', age: 43 };
for (let key of Object.keys(obj)){
console.log(key)// name age
}
for (let val of Object.values(obj)) {
console.log(val)// 张三 43
}
for(let [key,val] of Object.entries(obj)){
console.log([key,val])
// ["name",'张三'] ["age": 43]
}
上面的代码我们通过Object.keys,Object.values等方法实现了对对象的键名,键值,键值对的遍历, 因为这几个方法内部已经部署了Symbol.Iterator迭代器的生成函数,所以我们可以很方便的属性对象对象的遍历.
总结 通过迭代器模式可以实现对各种方式遍历,迭代器分离了集合对象的遍历过程,通过把迭代器抽象出来, 来实现出具体的遍历操作,这样使得可以在不暴露内部结构的情况下, 又可以让外部代码透明的访问集合内部的数据.
网友评论