美文网首页
备忘录和迭代器模式

备忘录和迭代器模式

作者: 小宇cool | 来源:发表于2020-11-07 22:30 被阅读0次

    1. 备忘录模式

    1.1 定义

    备忘录模式(Memeto) : 在不改变对象封装性的前提下,在对象之外捕获并保存该对象内部的状态以便日后使用.

    1.2 作用

    1. 记录并保存对象的内部状态, 实现了对信息的缓存.
    2. 通过对象状态的缓存, 避免重复的去获取状态的操作.
    3. 允许对象能够恢复到原先的状态.可供一个可回滚的操作.

    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 作用

    1. 为不同的数据类型提供一种统一的遍历接口.实现对数据的遍历.
    2. 把遍历的操作交个迭代器, 我们只需要实现出具体的遍历操作.
    3. 简化了遍历对象的操作, 实现我们可以很方便得进行遍历.

    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迭代器的生成函数,所以我们可以很方便的属性对象对象的遍历.

    总结 通过迭代器模式可以实现对各种方式遍历,迭代器分离了集合对象的遍历过程,通过把迭代器抽象出来, 来实现出具体的遍历操作,这样使得可以在不暴露内部结构的情况下, 又可以让外部代码透明的访问集合内部的数据.

    相关文章

      网友评论

          本文标题:备忘录和迭代器模式

          本文链接:https://www.haomeiwen.com/subject/ywtcbktx.html