Skip to content
A Powerful Collections Framework in JavaScript
JavaScript HTML CSS
Find file
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.
demo
requirejs
seajs
test
LICENSE
README.md
jcollections.js
jcollections.util.js

README.md

演示地址

jcollections

jcollections是一个可以简化数据操作、提高开发效率的集合类框架,接口简单,容易上手;在API方面,它汲取了Java集合中优秀的设计思想,同时也增添了一些新的特性,最大程度上方便开发人员的使用。

该框架由两部分组成:

jcollections.js:集合类,提供了几种常用的集合类,这个库文件可直接引入到页面,也可作为一个独立的模块按需加载, 支持RequireJSSea.jsNode.js环境。

jcollections.util.js:工具库,提供了基于集合框架的模板操作类和本地存储类, 它依赖于jcollections.js

引入集合函数库

1.页面单独引入:

<script type="text/javascript" src="jcollections.js"></script>

2.作为模块引入:

在Sea.js或RequireJS中作为模块按需加载,都需要require函数。

Sea.js中:

define(function(require, exports, module) {
    var jcollections = require('./jcollections');
    //todo
});

RequireJS中略有不同:

require(['./jcollections'], function(jcollections) {
    //todo
});

3.在Node.js中引入:

首先使用npm命令在线安装jcollections模块:

npm install jcollections

然后使用require指令,把模块包含进来:

var jcollections = require('jcollections');
//todo

创建实例

所有集合类都封装在jcollections包内,创建类实例时需要加包名:

var list = new jcollections.ArrayList();

为了简化开发人员的工作,避免每次都输入多余的包名,jcollections提供了exports机制,将集合类引出到全局范围:

jcollections.exports('*');                              //导出所有集合类
//or
jcollections.exports('ArrayList'[, 'LinkedList'[, ...]]);//导出一到多个集合类

然后可以直接创建实例:

var list = new ArrayList();

这种方式在简单的应用中比较实用,如果是大型项目不推荐使用,这会污染全局变量, 更好的方式是调用run方法,这里推荐使用下面两种方式:

第一种方式,使用this代替包名:

jcollections.run(function() {
    var aryList = new this.ArrayList([1, 2, 3]);
    console.log(aryList + '');
    var lnkList = new this.LinkedList(aryList);
    console.log(lnkList + '');
});

第二种方式,类型前面不用加任何前缀,不同的是,需要在函数参数列表中事先声明类型,run方法会根据依赖注入所需要的类型对象:

jcollections.run(function(ArrayList, LinkedList) {
    var aryList = new ArrayList(['hello', 'world']);
    console.log(aryList + '');

    var lnkList = new LinkedList(aryList);
    console.log(lnkList + '');
});

上面这种方式非常不错,但是如果在发布时代码需要压缩,为了确保代码可以正确运行,就需要在run方法后面追加几个类型名称的参数,就像下面这样:

jcollections.run(function(ArrayList, LinkedList) {
    var aryList = new ArrayList(['hello', 'world']);
    console.log(aryList + '');

    var lnkList = new LinkedList(aryList);
    console.log(lnkList + '');
}, 'ArrayList', 'LinkedList');

使用第二种方式时,可在参数列表里随意声明一到多个类型,也不用考虑声明顺序,只要声明的类型存在于jcollections包内,就可以正确运行。

另外,每个集合类都提供了一个静态方法,用于创建实例,所以也可以这样写:

var aryList = ArrayList.create();//or ArrayList.create([1, 2, 3]);
var lnkList = LinkedList.create();//or LinkedList.create(aryList);

create方法可以完成和构造函数相同的功能,在提示功能较好的IDE中,这样也许会很方便。

下面是整体结构图:

整体结构图

API介绍

ArrayList:

ArrayList是一种具有数组存储结构的集合,它是一种List类型,它的最上层是Collection类。

构造函数---可以创建一个空集合,或者传递一个数组,创建一个含有指定数组元素的集合,也可以传递一个Collection类型的集合对象,创建一个含有指定集合元素的新实例 (这里的Collection类型对象指的是ArrayListLinkedListHashSet类型实例,下同):

var list = new ArrayList();
//or
var list = new ArrayList([...]); 
//or
var list = new ArrayList(Collection);

add方法,向集合中添加一到多个元素:

list.add('hello');
list.add('JavaScript', 'world');

addAll方法,添加指定集合对象中的所有元素:

list.addAll(Collection);

clear方法,移除集合中所有元素:

list.clear();

contains方法,返回一个布尔值,表示集合中是否存在指定元素:

var isContains = list.contains('hello');

get方法,返回指定位置的元素:

var elem = list.get(0);

indexOf,返回指定元素第一次出现在集合中的位置索引,如果元素不存在则返回-1:

var index = list.indexOf('JavaScript');

insert方法,向集合中指定位置插入一到多个元素:

list.insert(1, 'a');
list.insert(2, 'really', 'powerful');

insertAll方法,向集合中指定位置插入指定集合对象中的所有元素:

list.insertAll(3, Collection);

isEmpty方法,返回一个布尔值,表示集合是否为空:

var isEmpty = list.isEmpty();

iterator方法,返回一个迭代器对象,可以选择性地传递一个索引值,表示从指定位置开始迭代:

var iter = list.iterator();
//or
var iter = list.iterator(3);            //从索引为3的位置开始迭代

while (iter.hasNext()) {
    var elem = iter.next();             //获取当前元素
    if (elem === 'world') {
        iter.remove();                  //移除当前元素
    } else if (elem === 'JavaScript') {
        iter.set('JAVASCRIPT');         //重置当前元素
    }
}

lastIndexOf方法,返回指定元素最后一次出现在集合中的位置索引,如果元素不存在则返回-1:

var lastIndex = list.lastIndexOf('JavaScript');

removeAt方法,移除指定位置的元素并返回这个元素:

var elem = list.removeAt(0);

removeElement方法,移除集合中第一次出现的指定元素,返回一个布尔值,表示是否移除成功:

var success = list.removeElement('hello');

removeRange方法,移除指定的开始位置到指定的结束位置的所有元素,包括开始位置,但不包括结束位置,该方法返回移除元素组成的数组:

var ary = list.removeRange(1, 3);

set方法,重新设置指定位置的元素,并返回替换前的旧值:

var old = list.set(3, 'js');

size方法,返回集合元素的个数:

var size = list.size();

toArray方法,返回含有集合数据的数组:

var ary = list.toArray();

toString方法,返回含有集合数据的字符串:

var str = list.toString();

最后,一个特殊的defineEquals方法:

在上面的containsindexOflastIndexOf方法中,涉及到了元素的比较,默认是比较基本类型的值或对象类型的引用,也可以自定义比较函数,例如集合中添加的是person对象元素,如果名称相同则认为是同一个人,就可以定义比较函数并且应用:

list.defineEquals(function(person0, person1) {
    return person0.name === person1.name;
});

list.add({name:'bill'});
list.add({name:'steve'});
list.add({name:'scott'});

var isContains = list.contains({name:'scott'});

LinkedList:

LinkedList是一种具有双向链表存储结构的集合,它也是一种List类型,它的最上层是Collection类。

构造函数---可以创建一个空链表,也可以选择传递一个Collection类型对象, 创建一个含有指定集合元素的链表:

var list = new LinkedList();
//or
var list = new LinkedList(Collection);

一些与ArrayList功能相同的方法:

addaddAllclearcontainsdefineEqualsgetindexOfinsertinsertAllisEmptylastIndexOfremoveAtremoveElementsetsizetoArraytoString

对于这些方法,将不再介绍,这里主要介绍LinkedList特有的方法。

addFirst方法,在链表头部添加一个指定元素:

list.addFirst(3);

addLast方法,在链表尾部添加一个指定元素:

list.addLast(5);

getFirst方法,返回链表头部元素:

var elem = list.getFirst();

getLast方法,返回链表尾部元素:

var elem = list.getLast();

removeFirst方法,移除链表头部元素并返回已移除的元素:

var elem = list.removeFirst();

removeLast方法,移除链表尾部元素并返回已移除的元素:

var elem = list.removeLast();

removeFirstOccurrence方法,移除链表中第一次出现的指定元素:

var success = list.removeFirstOccurrence('hello');

removeLastOccurrence方法,移除链表中最后一次出现的指定元素:

var success = list.removeLastOccurrence('hello');

LinkedList中的iterator方法比较特殊,它还可以倒序迭代:

var iter = list.iterator(list.size());
while (iter.hasPrevious()) {
    var elem = iter.previous();
    if (elem === 'hello') {
        iter.set('world');
    }
    if (elem === 'js') {
        iter.remove();
    }
}

HashSet:

HashSet是一种无重复元素的无序集合,它是一种Set类型,它的最上层是Collection类。

构造函数---可以创建一个空的无序集合,也可以选择传递一个Collection类型对象, 创建一个含有指定集合元素的无序集合:

var set = new HashSet();
//or
var set = new HashSet(Collection);

一些与ArrayList功能相同的方法:

addaddAllclearcontainsisEmptysizetoArraytoStringiterator

对于这些方法,这里也不再介绍了。

remove方法,移除指定元素:

var success = set.remove('hello');

在HashSet中,defineEquals方法比较重要, 如果定义了比较规则,在向集合中添加元素时,集合会根据这个规则判定是否重复:

list.defineEquals(function(person0, person1) {
    return person0.name === person1.name;
});

list.add({name:'bill'});
list.add({name:'steve'});
list.add({name:'scott'});

list.add({name:'scott'});//元素重复,添加失败

HashMap:

HashMap是一种具有键值对映射关系的映射表,它是一种Map类型。

构造函数---可以创建一个空的映射表,也可以传递一个Map类型的对象, 创建一个含有指定映射表元素的新实例:

var map = new HashMap();
//or
var map = new HashMap(Map);

clearisEmptysizetoString,这几个方法也不再介绍。

containsKey方法,返回一个布尔值,表示映射表中是否包含指定键:

var isContainsKey = map.containsKey('hello');

containsValue方法,返回一个布尔值,表示映射表中是否包含指定值:

var isContainsValue = map.containsValue('world');

entrySet方法,返回映射表键值对组成的无序集合:

var set = map.entrySet();

var iter = set.iterator();
while (iter.hasNext()) {
    var entry = iter.next(),
        key = entry.getKey(),
        value = entry.getValue();
    if (key === 'hello') {
        entry.setValue('WORLD');
    }
}

get方法,返回指定键对应的值:

var value = map.get('hello');

keySet方法,返回映射表键组成的无序集合:

var set = map.keySet();

var iter = set.iterator();
while (iter.hasNext()) {
    var key = iter.next();
    console.log(map.get(key));
}

put方法,向映射表中添加一个键值对:

map.put('hello', 'world');
map.put(3, 'three');
map.put('3', 'different three');
map.put({id:007, name:'scott'}, {fullName:'scott liu', info:'hello world', addr:'...'});

putAll方法,将指定映射表中的元素合并进当前表中:

map.putAll(Map);

remove方法,移除指定键所对应的键值对:

map.remove('hello');

Arrays:

Arrays是一个操作数组的工具类,包含以下几个方法:

asList方法,将指定的数组或一到多个值转变为ArrayList实例:

var aryList = Arrays.asList(['hello', 'world']);
//or
var aryList = Arrays.asList('hello', 'world');

binarySearch方法,对指定有序数组进行二分查找,调用时需传入数组及查找目标, 如果数组中是复杂对象,还需要传入对象比较函数:

var objAry = [
    {id:1, name:'bill'},
    {id:2, name:'steve'},
    {id:3, name:'scott'},
    {id:4, name:'john'},
    {id:5, name:'tom'}
];
var position = Arrays.binarySearch(objAry, {id:4, name:'john'}, function(a, b) {
    return a.id - b.id;
});

binarySearchRange方法,对指定有序数组指定范围进行二分查找,需传入起始位置和结束位置, 包括起始位置,不包括结束位置:

var position = Arrays.binarySearch(objAry, 1, 4, {id:4, name:'john'}, function(a, b) {
    return a.id - b.id;
});

copyOf方法,从指定数组起始位置开始,复制指定长度的元素:

var subAry = Arrays.copyOf(ary, 3);

copyOfRange方法,复制指定数组内指定范围的元素,需要指定起始位置和结束位置, 返回的结果集中包括起始位置元素,但不包括结束位置元素:

var subAry = Arrays.copyOfRange(ary, 1, 3);

equals方法,比较两个指定数组是否相等,需要指定两个数组,如果数组内是复杂对象, 还需要传入对象equals函数:

var objAry0 = [
    {id:1, name:'bill'},
    {id:2, name:'steve'},
    {id:3, name:'scott'}
];
var objAry1 = [
    {id:1, name:'bill'},
    {id:2, name:'steve'},
    {id:3, name:'scott'}
];
var isEquals = Arrays.equals(objAry0, objAry1, function(a, b) {
    return a.id === b.id && a.name === b.name;
});

fill方法,用指定元素填充指定数组:

Arrays.fill(ary, 'hello');

fillRange方法,用指定元素填充指定数组的指定范围,包括起始位置,不包括结束位置:

Arrays.fillRange(ary, 1, 3, 'hello');

sort方法,对指定数组排序,如果数组内是复杂对象,需要传入对象比较函数:

var objAry = [
    {id:1, name:'bill', toString: function() {return '1:bill';}},
    {id:4, name:'john', toString: function() {return '4:john';}},
    {id:2, name:'steve', toString: function() {return '2:steve';}},
    {id:5, name:'tom', toString: function() {return '5:tom';}},
    {id:3, name:'scott', toString: function() {return '3:scott';}}
];
var sortedAry = Arrays.sort(objAry, function(a, b) {//按id正序
    return a.id - b.id;
});
//or
var sortedAry = Arrays.sort(objAry, function(a, b) {//按id逆序
    return b.id - a.id;
});

sortRange方法,对指定数组指定范围排序,包括起始位置,不包括结束位置:

var sortedAry = Arrays.sort(objAry, 1, 4, function(a, b) {
    return a.id - b.id;
});

Collections:

Collections是一个操作集合对象的工具类,包含以下几个方法:

max方法,返回指定集合中最大的元素,如果集合中是复杂对象,还需要传入对象比较函数:

var list = new ArrayList();
list.add({id:1, name:'soctt', toString:function() {return '1:scott';}});
list.add({id:3, name:'steve', toString:function() {return '3:steve';}});
list.add({id:4, name:'john', toString:function() {return '4:john';}});
list.add({id:2, name:'bill', toString:function() {return '2:bill';}});

var max = Collections.max(list, function(a, b) {
    return a.id - b.id;
});//4:john

min方法,返回指定集合中最小的元素,如果集合中是复杂对象,还需要传入对象比较函数:

var min = Collections.min(list, function(a, b) {
    return a.id - b.id;
});//1:scott

sort方法,对List进行排序,如果List中是复杂对象,还需要传入对象比较函数:

Collections.sort(list, function(a, b) {
    return a.id - b.id;
});

binarySearch方法,对有序List进行二分查找,如果List中是复杂对象,还需要传入对象比较函数:

var index = Collections.binarySearch(list, {id:3, name:'steve'}, function(a, b) {
    return a.id - b.id;
});

replaceAll方法,将List中的指定元素全部替换为新元素:

list.defineEquals(function(a, b) {
    return a.id === b.id && a.name === b.name;
});
var oldElem = {id:4, name:'john', toString:function() {return '4:john';}};
var newElem = {id:0, name:'tom', toString:function() {return '0:tom';}};

Collections.replaceAll(list, oldElem, newElem);

reverse方法,将List元素反转:

Collections.reverse(list);

Template:

Template是一个集合模板类,包含在jcollections.util.js中,依赖于jcollections.js。

创建实例---可选择传入模板组件id或模板字符串内容:

var tpl = new Template();
//or
var tpl = new Template('tpl');
//or
var tpl = Template.create();
//or
var tpl = Template.create('tpl');

read方法,如果创建实例时没有指定组件id或模板字符串内容,调用此方法可读取指定模板:

var tpl = tpl.read('tpl');
//or
var tpl = tpl.read('<div><#= title #></div>');

一个模板组件一般包含在一个script标签内:

<script id="tpl" type="text/template">
    <#= title #>:
    <ol>
        <# for (var i = 0; i < list.size(); i++) { #>
                <# var person = list.get(i); #>
                <li>
                    <#= person.name + ' : ' + person.age + ' years old' #>
                </li>
        <# } #>
    </ol>
</script>

compile方法,将指定数据集和模板集合,转译成HTML组件:

var data = new HashMap();
data.put('title', 'students');          //put title
var list = new ArrayList();
list.add({id:0, name:'scott', age:15});
list.add({id:1, name:'bill', age:16});
list.add({id:2, name:'jobs', age:17});
data.put('list', list);                 //put list

var tpl = tpl.compile(data);

getHtml方法,返回转译后的HTML内容:

var html = tpl.getHtml();

render方法,将HTML内容渲染到指定的视图中:

tpl.render('viewId');

Template支持链式调用,所以可以像下面这样使用:

var html = Template.create('tpl')
                    .compile(data)
                    .getHtml();
//or
Template.create('tpl')
        .compile(data)
        .render('viewId');

Storage:

Storage是一个本地存储类,包含在jcollections.util.js中,依赖于jcollections.js。

首先是几个静态属性或方法:

isSupported属性,一个布尔值,表示是否支持本地存储:

var isSupported = Storage.isSupported;

turnSessionMode方法,转换为sessionStorage存储模式(默认是localStorage模式):

Storage.turnSessionMode();

turnLocalMode方法,转换为localStorage存储模式:

Storage.turnLocalMode();

saveItem方法,存储一个键值对:

Storage.saveItem('hello', 'world');

getItem方法,根据指定键获取其值:

var value = Storage.getItem('hello');

hasItem方法,返回一个布尔值,表示是否存在指定键所对应的值:

var has = Storage.hasItem('hello');

delItem方法,移除指定键对应的值:

Storage.delItem('hello');

delItems方法,根据过滤函数移除多个键值对 (该方法内部有容错机制,过滤函数只需针对指定结构进行逻辑处理,无需考虑无关的数据结构):

Storage.delItems(function(key, value) {
    return Storage.fromJSON(value).name === 'jack';
});

clear方法,清空本地存储:

Storage.clear();

toJSON方法,将对象转为JSON字符串:

var json = Storage.toJSON({id:1, name:'jack'});

fromJSON方法,将JSON字符串转为对象:

var obj = Storage.fromJSON('{"id":1, "name":"jack"}');

isJSONFormat方法,传入一个字符串,返回一个布尔值,表示该字符串是否为JSON格式:

var isJSON = Storage.isJSONFormat('{"id":1, "name":"jack"}');

下面是实例方法:

首先是创建实例:

var store = new Storage();
//or
var store = Storage.create();

defineToStore方法,定义存储数据时的转换规则:

store.defineToStore(function(value) {
    return Storage.toJSON(value);
});

defineFromStore方法,定义获取数据时的转换规则:

store.defineFromStore(function(json) {
    return Storage.fromJSON(json);
});

saveItems方法,保存多项数据:

var data = new HashMap();
data.put('coder', {name:'jack', age:'30', salary:300});
data.put('guarder', {name:'tom', age:'40', salary:200});
data.put('cleaner', {name:'john', age:'45', salary:100});
store.saveItems(data);

getItems方法,根据过滤函数获取多条数据 (同样的,这里只需关心要获取的数据特定的数据结构,无关的数据结构都会被过滤掉):

var resultMap = store.getItems(function(key, value) {
    return Storage.fromJSON(value).age > 30;
});

//修改数据然后存储
var iter = resultMap.entrySet().iterator();
while (iter.hasNext()) {
    var entry = iter.next();
    var record = entry.getValue();
    record.salary += 50;
    console.log('age: ' + record.age + ', current salary: ' + record.salary);
}
store.saveItems(resultMap);
Something went wrong with that request. Please try again.