资讯专栏INFORMATION COLUMN

JavaScript iterator 设计模式

CocoaChina / 1346人阅读

摘要:迭代器模式就是按照顺序访问一个对象中元素,而不用暴露该对象的内部组成。迭代器模式就是将这个迭代实现从业务中分离出来。外部迭代器外部迭代器必须显式地请求才会迭代下一个元素。

迭代器模式就是按照顺序访问一个对象中元素,而不用暴露该对象的内部组成。迭代器模式就是将这个迭代实现从业务中分离出来。

但实际开发中我们并不将他当成一个设计模式。

前瞻后顾

说起迭代器,想必对ES6有了解的同学应该不会陌生。我们知道,for ... of 遍历的对象必须是迭代器对象,而普通对象则不能,因为普通对象内部没有实现迭代器,而像数组则内部实现了迭代器,所以可以用for ... of 的语法,而对于一般对象在ES5中有专门的处理方法,for ... in
Object.keys() ,而 for ... in 可遍历所有的的对象,但是它遍历特殊对象,如数组,也会遍历它的length,这并不是我们需要的,有时还会出现不按顺序的遍历。

在我们日常使用中一般是将普通对象转化为特殊对象然后处理的。

仿jQuery迭代器

这里我只简单的实现数组的遍历,至于如何迭代普通对象,我们下面再做介绍。

var $ = {
    each: function (arr, fn) {
        for (var i = 0, len = arr.length; i < len; i++) {
            fn.call(arr[i], i, arr[i])
        }
    }
};

$.each([1, 2, 3, 4, 5, 6], function(i, val) {
    console.log([i, val]);
});
迭代器的分类

迭代器根据实现的位置,我们将它分为内部迭代器和外部迭代器两种。

内部迭代器

内部迭代器对于使用者来说他不用关心迭代器的内部实现,只用关注使用的效果,我们上面仿jQuery的each就是个内部迭代器的实现。

内部迭代器有它的好处但是也有它的不足,比如我们要比较两个数组是否相等,上面的方法就不满足我们的需要,我们就需要写一个新的方法来实现。

var $ = {
    each: function (arr, fn) {
        for (var i = 0, len = arr.length; i < len; i++) {
            fn.call(arr[i], i, arr[i])
        }
    }
};

var compareArray = function(arr, arr2) {
    if( arr.length !== arr2.length) {
        return false;
    }
 
    $.each(arr, function(i, val) {
        if( val !== arr2[i]) {
            return false;
        }
    });
    return true;
};

compareArray([1, 2], [1, 2, 3]); // false
外部迭代器

外部迭代器必须显式地请求才会迭代下一个元素。

外部迭代器虽然增加了使用上的一些麻烦,但是它的灵活性却正是我们需要的。我们可以人为的控制迭代的过程和顺序。

// 迭代器实现
var Iterator = function(obj) {
    var current = 0;
 
    var next = function() {
        current += 1;
    };
 
    var isDone = function() {
        return current >= obj.length;
    };
 
    var getCurrItem = function() {
        return obj[current];
    };

    var len = function() {
        return obj.length;
    }
 
    return {
        next: next,
        isDone: isDone,
        getCurrItem: getCurrItem,
        length: len,
    }
};
// 比较数组
var compareArray = function (iteratorObj, iteratorObj2) {
    if(iteratorObj.length !== iteratorObj2.length) {
        return false;
    }
    while (!iteratorObj.isDone() && !iteratorObj2.isDone()){
        if (iteratorObj.getCurrItem() !== iteratorObj2.getCurrItem()){
            return false;
        }
        iteratorObj.next();
        iteratorObj2.next();
    }
 
    return true;
};

var arr = Iterator([1, 2, 3]); 
var arr2 = Iterator([1, 2, 3]); 
 
compareArray(arr, arr2); // true

这样我们就用ES5实现了迭代器的功能,ES6的实现迭代器相对简单,如果不熟悉的可以参考一下阮一峰老师的 ES6 使用手册

迭代对象

使用ES6迭代器后发现,for ... of 能够遍历的迭代器对象,如: 数组,类数组,Set,Map,arguments等对象它们有一个共同的特性,就是它们都有一个length数组,可以实现对对象用下标进行访问。

因此,要实现对普通对象的的迭代,我们可以参考jQuery的实现如下做:

var isArraylike = function(obj) {
    return Object.prototype.toString.call(obj) === [object Array];
}
$ = {
    each: function(obj, fn) {
        var isArray = isArraylike(obj); // 判断对象是否为数组

        if (isArray) {
            for (var i = 0, len = obj.length ; i < len; i++ ) {
                if (fn.call(obj[i], i, obj[i]) === false) {
                    break;
                }
            }
        } else {
            for (i in obj) {
                if (fn.call(obj[i], i, obj[i]) === false) {
                    break;
                }
            }
        }
    }
}; 

我们再使用ES6处理一般对象时一般使用两种方法,一种是将普通对象转化为迭代器对象,另一种就是上面这种写法。

设计模式周周讲

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/92732.html

相关文章

  • JavaScript 设计模式(五):迭代器模式

    摘要:文章内容分两部分前半部分为迭代器模式概念后半部分为中迭代器上半部分开始迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。下半部分开始的迭代器迭代器等同于遍历器。执行该函数,会返回一个遍历器对象。 showImg(https://segmentfault.com/img/bVbuyaZ?w=800&h=600); 文章内容分两部分: 前半部分为 迭...

    zhou_you 评论0 收藏0
  • JavaScript中常用的设计模式

    摘要:本文已同步到中常见的设计模式如果感觉写的还可以,就给个小星星吧,欢迎和收藏。本文中关于各种设计模式定义都是引用书中的,部分引用自百度百科已标出。下面把我整理出的常用设计模式按类型做个表格整理。 本文已同步到Github JavaScript中常见的设计模式,如果感觉写的还可以,就给个小星星吧,欢迎star和收藏。 最近拜读了曾探大神的《JavaScript设计模式与开发实践》,真是醍醐...

    NSFish 评论0 收藏0
  • 用ES6重写《JavaScript Patterns》中的设计模式

    摘要:所以自己动手用重新实现了一遍里面的设计模式,算是对其的巩固,也算是与大家一起来研究探讨语法的一些最佳实践。 前言 最近在回顾设计模式方式的知识,重新翻阅了《JavaScript模式》(个人感觉也算是一本小有名气的书了哈)一书,读时总有感触:在即将到来的ES6的大潮下,书中的许多模式的代码可用ES6的语法更为优雅简洁的实现,而另一些模式,则已经被ES6原生支持,如模块模式(99页)。所...

    taohonghui 评论0 收藏0
  • 常见设计模式的定义,应用场景和方法

    摘要:命令模式的由来,其实是回调函数的一个面向对象的替代品,命令模式早已融入到了语言之中。 模式是对某情景下,针对某种问题的某种解决方案。而一个设计模式是用来解决一个经常出现的设计问题的经验方法。这么说来,每个模式都可能有着自己的意图,应用场景,使用方法和使用后果。本文的行文思路和目的皆在于了解各个模式的定义,应用场景和用实例说明如何在前端开发中使用。 本文所设计到的概念和实例大多来自《H...

    xuxueli 评论0 收藏0
  • 每个JavaScript开发人员都应该知道的新ES2018功能(译文)

    摘要:为了使程序员能够一次一个地处理集合中的元素,引入了迭代器接口。迭代器使用该方法获取对象属性名称的数组,然后将其分配给常量。迭代器的缺点是它们不适合表示异步数据源。每次循环时,都会调用迭代器的方法,它返回一个。 前言 原文地址:https://css-tricks.com/new-es2018-features-every-javascript-developer-should-kno...

    leonardofed 评论0 收藏0

发表评论

0条评论

CocoaChina

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<