(转自:http://kaizhongfan.blog.163.com/blog/static/1087082402010216111321463/ )
对于Javas
Javas
在Ext的环境中,打印数组对象的indexOf方法,结果分别是:
FF:
function indexOf() { [native co
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_JavaS
好了,回到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(true, function(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用来批量添加数据。
打印结果为:
所以可以得出如下结论:
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;
}
}
}
它提供了对集合遍历的一种方便方式。