Extjs 中的容器类MixedCollection 讲解

(转自:http://kaizhongfan.blog.163.com/blog/static/1087082402010216111321463/ )


对于Javascript来讲,数组和对象的概念其实界限其实很模糊。因为Array本身就是一个构造函数,对于Array实例化产生的某个数组便是一个对象。我们可以通过arrayObj[‘key’]这样的方式往数组对象中添加元素。当然,作为javascript的一般的对象而言,通过object[“name”]以及object.name同样都可以获得某个元素。

Javascript的各种框架都会在数组/对象上做一些文章,用来提高对数组或对象的访问效率以及扩展功能。其实,为之努力的不仅仅是一个个javascript的框架,更深入至浏览器,我们下面就举个例子。

在Ext的环境中,打印数组对象的indexOf方法,结果分别是:

FF:

function indexOf() { [native code] }

IE:

function(o, from){

        var len = this.length;

        from = from || 0;

        from += (from < 0) ? len : 0;

        for (; from < len; ++from){

            if(this[from] === o){

                return from;

            }

        }

        return -1;

    }

我们可以看到FF中显示的是原生方法,内部代码不可见,而IE中则打印出了Ext为数组拓展的indexOf方法。为什么会有这样的差异呢?原因在于FF实现了数组的indexOf的原生方法,但是IE没有。而Ext采用applyif的方式对数组的原型prototype进行扩充,因此FF中相应的同名方法不会被覆盖,也就造成了以上的差异。

对于FF到底拓展了哪些浏览器对象方法,我们可以参看:https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects。这个例子不仅告诉我们浏览器之间在原生方法上存在着差异,更告诉我们在处理这种既属于原生又属于框架拓展的方法的时候要倍加小心,否则会出现很多莫名其妙的问题。

好了,回到MixedCollection,看看它是怎么当好集合的管家的。先只看它的构造函数:

Ext.util.MixedCollection = function(allowFunctions, keyFn){

    this.items = [];

    this.map = {};

    this.keys = [];

    this.length = 0;

    this.addEvents(

        /**

         * @event clear

         * Fires when the collection is cleared.

         */

        'clear',

        /**

         * @event add

         * Fires when an item is added to the collection.

         * @param {Number} index The index at which the item was added.

         * @param {Object} o The item added.

         * @param {String} key The key associated with the added item.

         */

        'add',

        /**

         * @event replace

         * Fires when an item is replaced in the collection.

         * @param {String} key he key associated with the new added.

         * @param {Object} old The item being replaced.

         * @param {Object} new The new item.

         */

        'replace',

        /**

         * @event remove

         * Fires when an item is removed from the collection.

         * @param {Object} o The item being removed.

         * @param {String} key (optional) The key associated with the removed item.

         */

        'remove',

        'sort'

    );

    this.allowFunctions = allowFunctions === true;

    if(keyFn){

        this.getKey = keyFn;

    }

    Ext.util.MixedCollection.superclass.constructor.call(this);

};

他有两个参数:

AllowFunctions:确定是否可以包含函数元素;

KeyFn:确定如何获得元素的键值。

这里有三个属性:    this.items = [],this.map = {},this.keys = []。它们分别是用来干什么的呢?我们如下这样建立一个丰富的MixedCollection实例,并打印该实例的items、map和keys三个属性值:

var m = new Ext.util.MixedCollection(truefunction(o){return o.key});

            m.add('a');

            m.add({key: 'b', value: 'bb'});

            m.addAll(['c''d''e']);

            m.addAll([{key: 'c', value: 'cc'}, {key: 'd', value: 'dd'}]);

            console.info(m.items);

            console.info(m.map);

      console.info(m.keys);

PS:

Add方法用来添加单个数据,addAll用来批量添加数据。

打印结果为:

拾起EXT的贝壳之三(MixedCollection) - kai - 小岂的博客

第二项展开为:

拾起EXT的贝壳之三(MixedCollection) - kai - 小岂的博客

所以可以得出如下结论:

Items是用来顺序存储集合中的每个元素;

Map用来存放键值和元素的映射,其中不包括无键值的元素;

Keys用来顺序存放键值,无键值时,存放undefined。

可能有人会问,为什么要冗余一个map属性呢?items和keys完全可以承担数据定位的职能啊?例如,如果我想找到键值为c的元素,完全可以在keys数组中找到其位置(为第6个元素),然后再到items中把它拿出来。

但是,你是否想过。如果存在map,查找键值为c的元素,只需要一步map[‘c’]即可。而且,这样的查找是由浏览器原生实现的,效率肯定要提高非常多,虽然牺牲了一点内存。之所以说一点,是因为这里只保存了对数组的引用。

明白了以上的内容,MixedCollection剩下的就很好理解了。它内部的任何对集合的操作都无外乎是对以上三个属性的操纵。

譬如:

Item方法用来返回item属性数组中对应的值。他可以传键值做为参数,也可以传数字(index)作为参数:

item : function(key){

        var mk = this.map[key],

            item = mk !== undefined ? mk : (typeof key == 'number') ? this.items[key] : undefined;

        return !Ext.isFunction(item) || this.allowFunctions ? item : null// for prototype!

    }

如上,先判断在map中是否有对应的值,如果有则返回。如果没有且参数为数字,则返回items中对应位置的元素。再不然,返回undefined

itemAt方法只用理会数字形式的index,用其来返回items对应位置的元素:

itemAt : function(index){

        return this.items[index];

}

当然,用的最多的还是each

each : function(fn, scope){

         var items = [].concat(this.items); // each safe for removal

         for(var i = 0, len = items.length; i < len; i++){

             if(fn.call(scope || items[i], items[i], i, len) === false){

                break;

             }

         }

    }

它提供了对集合遍历的一种方便方式。

 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值