1.0.1 • Published 11 years ago

jcollections v1.0.1

Weekly downloads
4
License
-
Repository
github
Last release
11 years ago

演示地址

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);