《前端实战总结》之迭代器模式的N+1种应用场景

徐小夕 等级 585 0 0

眼看12月就来了,抓住今年的尾巴,好好总结一下前端的不足与收获。这篇文章是笔者写设计模式专题的第二篇文章,也是基于工作中的总结和提炼,在实际应用场景中都会大量使用,至于为什么要写设计模式,主要是为了提高团队代码质量和可维护性,后续会继续推出设计模式相关的文章,供大家参考和学习。

你将学到

  • 迭代器模式的含义
  • 实现一个数组迭代器
  • 实现一个对象迭代器
  • 实现路径查找/赋值迭代器
  • 如何用迭代器的思想解决分支循环嵌套问题
  • 实现一个图片播放器

《前端实战总结》之迭代器模式的N+1种应用场景

正文

1.迭代器的含义

迭代器模式主要的思想就是在不暴露对象内部结构的同时可以按照一定顺序访问对象内部的元素。

其实javascript中的很多方法都运用了迭代器的思想,比如数组的forEach,every,find,some,map,entries等等,这些操作极大的简化了我们的逻辑操作,接下来我们就来看看它的具体应用吧。

2.实现一个数组迭代器

我们都知道javascript中数组的forEach方法,那么不用这个方法,我们能自己实现一个吗?

// 数组迭代器
let eachArr = function(arr, fn) {
    let i = 0,
    len = arr.length;
    for(; i < len; i++) {
        if(fn.call(arr[i], i, arr[i]) === false) {
            break;
        }
    }
}

// 使用
eachArr([1,2,3,4], (index, value) => { console.log(index, value) })

3.实现一个对象迭代器

对象迭代器和数组迭代器类似, 只是传参不同,如下:

// 对象迭代器
let eachObj = function(obj, fn) {
    for(let key in obj) {
        if(fn.call(obj[key], key, obj[key]) === false) {
            break;
        }
    }
}

// 使用
eachObj({a: 11, b: 12}, (key, value) => { console.log(key, value) })

4.实现路径查找/赋值迭代器

有时候我们操作对象的某些属性时,我们不知道服务器端是否将该属性或者该属性的上级属性正确的返回给我们,这个时候我们直接通过点语法或者[]语法直接访问会导致代码报错,因此需要我们每一层操作都要做安全校验,这样会产生大量臃肿代码,比如:

let obj = {};
// 获取 obj.num.titNum
let titNum = obj.num.titNum;    // 报错
let titNum = obj && obj.num && obj.num.titNum;   // 正确

我们通过迭代器可以极大的减少这种校验,实现更健壮的代码模式:

let findObjAttr = function(obj, key){
    if(!obj || !key) {
        return undefined
    }
    let result = obj;
    key = key.split('.');
    for(let i =0; len = key.length; i< len; i++) {
        if(result[key[i]] !== undefined) {
            result = result[key[i]]
        }else {
            return undefined
        }
    }
    return result
}
// 使用
let a = { b: { c: { d: 1 } } };
findObjAttr(a, 'a.b.c.d')     // 1

这种方式是不是有点类似于lodash的对象/数组查找器呢?同理,我们也可以实现路径赋值器,如下所示:

let setObjAttr = function(obj, key, value){
    if(!obj) {
        return false
    }
    let result = obj,
    key = key.split('.');
    for(let i =0, len = key.length; i< len - 1; i++){
        if(result[key[i]] === undefined) {
            result[key[i]] = {};
        }

        if(!(result[key[i]] instanceof Object)){
            // 如果第i层对应的不是一个对象,则剖出错误
            throw new Error('is not Object')
            return false
        }

        result = result[key[i]]
    }
    return result[key[i]] = val
}

// 使用
setObjAttr(obj, 'a.b.c.d', 'xuxi')

5.如何用迭代器的思想解决分支循环嵌套问题

分支循环嵌套的问题主要是指在循环体中还需要进行额外的判断,如果判断条件变多,将会造成严重的性能开销问题,如下面的例子:

 // 数据分组
 function group(name, num) {
     let data = [];
     for(let i = 0; i < num; i++){
         switch(name) {
             case 'header':
                data[i][0] = 0;
                data[i][1] = 1;
                break;
            case 'content':
                data[i][0] = 2;
                data[i][1] = 3;
                break;
            case 'footer':
                data[i][0] = 4;
                data[i][1] = 532;
                break;
            default:
                break;
         }
     }
     return data
 }

由以上分析可知,上面的代码还有很多优化空间,因为每一次遍历都要进行一次分支判断,那么如果num变成100000,且name的种类有100种,那么我们就要做100000*100种无用的分支判断,这样无疑会让你的代码在大数据下卡死。不过我们可以通过以下这种方式优化它:

 // 数据分组
 function group(name, num) {
     let data = [];
     let strategy = function() {
         let deal = {
             'default': function(i){
                 return
             },
             'header': function(i){
                data[i][0] = 0;
                data[i][1] = 1;
             },
            'content': function(i){
                data[i][0] = 2;
                data[i][1] = 3;
             }, 
             //...
         }
         return function(name) {
             return deal[name] || deal['default']
         }
     }();
     // 迭代器处理数据
     function _each(fn) {
        for(let i = 0; i < num; i++){
         fn(i)
        }
     }

     _each(strategy(name))

     return data
 }

这样我们就能避免分支判断,极大的提高了代码效率和性能。

6.实现一个图片播放器

《前端实战总结》之迭代器模式的N+1种应用场景 图片播放器主要有以上几个功能,上一页,下一页,首页,尾页,自动播放按钮,停止按钮。具体组件的设计机构可以参考我写的demo:

// 图片播放器
let imgPlayer = function(imgData, box) {
    let container = box && document.querySelector(box) || document,
    img = container.querySelector('img'),
    // 获取图片长度
    len = imgData.length,
    // 当前索引值
    index = 0;
    // 初始化图片
    img.src = imgData[0];

    var timer = null;

    return {
        // 获取第一个图片
        first: function() {
            index = 0
            img.src = imgData[index]
        },
        // 获取最后一个图片
        last: function() {
            index = len - 1
            img.src = imgData[index]
        },
        // 切换到前一张图片
        pre: function() {
            if(--index > 0) {
                img.src = imgData[index]
            }else {
                index = 0
                img.src = imgData[index]
            }
        },
        // 切换到后一张图片
        next: function() {
            if(++index < len) {
                img.src = imgData[index]
            }else {
                index = len - 1
                img.src = imgData[index]
            }
        },
        // 自动播放图片
        play: function() {
            timer = setInterval(() => {
                if(index > len - 1) {
                    index = 0
                }
                img.src = imgData[index]
                index++
            }, 5000)
        },
        // 停止播放图片
        stop: function() {
            clearInterval(timer)
        }
    }
}

// 使用
let player = new imgPlayer(imgData, '#box')

总之,迭代器思想和其他设计模式的组合,可以设计出各种各样高度配置的组件,所以说学好并理解javascript设计模式的精髓,决定了我们的高度和态度。

最后

如果想了解更多webpack,node,gulp,css3,javascript,nodeJS,canvas等前端知识和实战,欢迎在公众号《趣谈前端》加入我们一起学习讨论,共同探索前端的边界。

《前端实战总结》之迭代器模式的N+1种应用场景

更多推荐

收藏
评论区

相关推荐

《前端实战总结》之使用解释器模式实现获取元素Xpath路径的算法
前端领域里基于javascript的设计模式和算法有很多,在很多复杂应用中也扮演着很重要的角色,接下来就介绍一下javascript设计模式中的解释器模式,并用它来实现一个获取元素Xpath路径的算法。 上期回顾 《前端实战总结》之迭代器模式的N1种应用场景(https://juejin.im/post/6844904008616771591)
js-Answers一
JavaScript的组成 JavaScript 由以下三部分组成: 1. ECMAScript(核心):JavaScript 语言基础 2. DOM(文档对象模型):规定了访问HTML和XML的接口 3. BOM(浏览器对象模型):提供了浏览器窗口之间进行交互的对象和方法 JS的基本数据类型和引用数据类型
javascript实践教程-01-javascript介绍
本节目标1. 了解javascript是什么。2. 了解javascript能干什么。 内容摘要本篇介绍了javascript是什么,为什么要用javascript,ECMAScript标准是什么等。阅读时间大约510分钟。 javascript是什么?javascript是世界上最流行的脚本语言,因为你在电脑、手机、平板上浏览的所有的网页,以及无数基于HT
Java scirpt 简介
### javascript简介:   JavaScript一种直译式脚本语言,是一种动态类型、弱类型、基于原型的语言,内置支持类型。它的解释器被称为JavaScript引擎,为浏览器的一部分,广泛用于客户端的脚本语言,最早是在HTML(标准通用标记语言下的一个应用)网页上使用,用来给HTML网页增加动态功能。 ### 基本特点:   JavaScri
Java乱码
1.Javascript传参乱码: 在浏览器端对要传递的中文参数进行编码处理.代码如下: xmlhttp.open("POST",url,true); //请求参数初始化 xmlhttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); //因为请求方式为PO
AJAX与Django
AJAX ---- #### 什么是AJAX? AJAX不是JavaScript的规范,它的缩写:Asynchronous JavaScript and XML,意思就是用JavaScript执行异步网络请求。提交任务之后,不原地等待,直接执行下一行代码,任务的返回通过回调机制。 局部刷新,不整体刷新,而是界面莫个地方局部刷新 #### AJAX原理
JavaScript的入门简介
#### 什么是 JavaScript JavaScript,我们一般简称为 JS,是一种具有函数优先的轻量级,解释型或即时编译型的编程语言。 JavaScript 现在已经被用到了很多非浏览器环境中,JavaScript 基于原型编程、多范式的动态脚本语言,并支持面向对象、命令式和声明式风格。 HTML、CSS、JavaScript三者不同的功能:
Javascript 中的神器——Promise
_摘要:_ 回调函数真正的问题在于他剥夺了我们使用 return 和 throw 这些关键字的能力。而 Promise 很好地解决了这一切 回调函数真正的问题在于他剥夺了我们使用 return 和 throw 这些关键字的能力。而 Promise 很好地解决了这一切 Promise概念 --------- 所谓 Promise,就是ES6原生提供的一个
Javascript 中的装饰器
![](https://oscimg.oschina.net/oscnet/bc7efa18b4ee8ec5542856d21245a74da0b.jpg) 前言 -- 在 ES6 中增加了对类对象的相关定义和操作(比如 `class` 和 `extends` ),这就使得我们在多个不同类之间共享或者扩展一些方法或者行为的时候,变得并不是那么优雅。这个时
Javascript解析机制 执行机制
HTML5学堂:在学习JavaScript过程中,我们需要了解事件的机制是怎么执行的?本文将会提到JavaScript事件机制的解析,希望对大家有帮助! javascript解析的过程主要分为两个阶段,分别是编译与执行阶段。 在编译期,javascript解释器将完成对javascript代码的预处理,即将javascript代码转换为字节码。 在执行
Node.js 简单学习
明白 JavaScript 语言,你就会用 Node.js 了。最常见的运行 JavaScript 语言的地方就是用户的浏览器,几乎所有的浏览器上都有个 JavaScript 引擎,这个引擎负责运行在页面中嵌入的 JavaScript 代码。代码是在用户的浏览器上运行的,用户那头叫前端(Frontend),服务器这头叫后端(Backend)。Node.js
Node.js简介及如何学习Node.js
本文介绍Node.js的诞生史以及如何学习Node.js。 Node.js简史 --------- 从Node.js的命名上可以看到,Node.js的官方开发语言是JavaScript。之所以选择使用JavaScript,显然与JavaScript的开发人员多有关。总所周知,JavaScript是伴随着互联网的发展而火爆起来的,JavaScript也是前
PHP serialize & JSON 解析
对于JSON(JavaScript Object Notation)大家应该不陌生,它是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于[JavaScript Programming Language](https://www.oschina.net/action/GoToLink?url=http%3A%2F%2Fwww.cro
Springmvc异步上传文件
<script src="js/jquery.js" type="text/javascript"></script><script src="js/jquery.ext.js" type="text/javascript"></script><script src="js/jquery.form.js" type="text/javascript"
Typescript 和 Javascript之间的区别
JavaScript 和 TypeScript 的概要介绍 ============================= **JavaScript** -------------- JavaScript 是一种轻量级的解释性脚本语言,可嵌入到 HTML 页面中,在浏览器端执行,能够实现浏览器端丰富的交互功能,为用户带来流畅多样的用户体验。 JavaScr