原题:Arrays Made Easy
原文链接: http://dojotoolkit.org/documentation/tutorials/1.6/arrays/
作者: Bran Forbes
译者: feijia (tiimfei@gmail.com)
在本教程中你将会学到如何使用dojo提供的跨平台的JavaScript数组操作
难度:初学者
适用Dojo版本:1.6
访问并操作数组是开发Web应用中的重要部分。JavaScript语言设计时就考虑到了这种需求,因此在语言层面已经加入了一些针对数组操作的方法来简化这一工作。遗憾的是不是所有浏览器都实现了同样的JavaScript标准。Dojo作为一个跨浏览器平台的框架提供了一系列数组操作方法,来弥补这一缺憾。
在数组中查找某个对象的位置
常用的数组操作之一就是在一个数组中查找某个元素,dojo为此提供了两个方法: dojo.indexOf 和dojo.lastIndexOf. dojo.indexOf 方法从前至后挨个的搜索数组中的元素,dojo.lastIndexOf则从后向前逐个搜索。 两个方法的参数是一样的,被搜索的数组,以及要查找的元素,还有一个可选的参数,即从何处开始搜索。
下面我们来看一个例子:
@H_301_18@var arr1 = [1,2,3,4,1,1];
dojo.indexOf(arr1,2); // returns 1
dojo.indexOf(arr1,2); // returns 5
dojo.lastIndexOf(arr1,2); // returns 11
如果某元素没有找到,两个方法都会返回-1. 要注意这两个方法在搜索时都使用严格的比较操作(===),所以你除了可以查找简单数据类型(primitive),你还可以查找对象
@H_301_18@var obj1 = { id: 1 },arr2 = [{ id: 0 },obj1,{ id: 2 },{ id: 3 }];
// 返回1, 因为obj1 就是数组的第2个元素
// in the array.
dojo.indexOf(arr2,obj1);
// 返回-1, 虽然查找的对象属性相似,但是它和obj1 是两个完全不同的对象,
dojo.indexOf(arr2,{ id: 1 });
遍历,循环
另一个常用的数组操作是循环遍历所有数组元素。使用传统的JavaScript代码通常可以写成这样
var item;
for(var i = 0; i < arr.length; i++){
item = arr[i];
// 对item进行操作
}
这样写的一个缺点是,如果你在一个事件处理函数中去访问item,你没法取到的你想要的作用域。(参考后面的例子)
使用dojo.forEach,它提供了一个标准的方法来循环遍历数组,并且在作用域链查找时保留了元素。 它基本遵守Array.prototype.forEach的行为,只有两处不同:
1. dojo.forEach会遍历那些未定义的值:即便数组中存在一些未定义的值,它仍然会对该值执行操作。
2. dojo.forEach会在数组对象上直接遍历,而浏览器的forEach会在一个数组的拷贝上执行。 所以如果你在dojo.forEach 中对数组本身做了修改,这一修改将会生效。
下面让我们看一个例子
@H_301_18@//先定义一个包含4个元素的数组
var arr = ["one","two","three","four"],list1 = dojo.byId("list1");
// 跳过底5个元素,而直接设定第六个元素
arr[5] = "six";
dojo.forEach(arr,function(item,index){
// 本函数将会在数组的每个元素上执行
if(index == 3){
// 在本函数中,修改了数组本身,因此第六次调用时,访问到的item将是"seven"
arr[5] = "seven";
}
dojo.create("li",{
innerHTML: item + " (" + index + ")"
},list1);
});
dojo.forEach 接受3个参数:被遍历的数组,回调函数(遍历的数组时,每个元素包括未定义的元素将作为参数传递给该回调函数), 以及一个可选的作用域对象,用来规定执行该回调函数时所用的作用域。
回调函数将会被反复执行,直到数组中最后一个有值的位置。 回调函数被调用时将会被传入3个参数,数组当前位置上的元素(可能是一个对象或一个原始值),当前位置的序号,以及一个数组的引用. 回调函数将会在指定的作用域中执行,如果forEach省略了第三个参数没有指定作用域,那么回调函数将会在全局的作用域中执行。
让我们在来看一下dojo.forEach的作用域参数究竟有什么好处
@H_301_18@var list2 = dojo.byId("list2"),myObject = {
prefix: "ITEM: ",formatItem: function(item,index){
return this.prefix + item + " (" + index + ")";
},outputItems: function(arr,node){
dojo.forEach(arr,index){
dojo.create("li",{
//如果forEach的第三个参数没有把myObject传入的话,这里的this 就不能定位到正确的scope,也就不可能找到formatItem
innerHTML: this.formatItem(item,index)
},node);
},this);
}
};
myObject.outputItems(arr,list2);
通过设定回调函数的作用域对象,使得回调函数能够在正确的作用域中被调用。 这种模式在对dojo widget编程时经常会用到,请牢记。
数组元素操作
Dojo 已经将数组的遍历简化了许多,接下来我们如果要想对数组中的元素做一些修改那该如何做呢?
假设我们有一个字符串数组,我们希望把其中的字符串转化成一组对象,并且每个对象的“name“属性就是字符串数组中的对应字符串。
根据我们前面已经学过的,我们可能写出如下代码
@H_301_18@var original = ["one","four","five"],transformed = [];
dojo.forEach(original,index){
transformed.push({
id: index * 100,text: item
});
});
//得到的transformed对象内容是 [ { id: 0,text: "one" },{ id: 100,text: "two" },... ]
这样写当然没有错,不过现在新版的JavaScript和Dojo.map方法可以让代码进一步简化:
@H_301_18@var mapped = dojo.map(original,index){
return {
id: index * 100,text: item
};
}); // [ { id: 0,... ]
dojo.map的参数和forEach是一样的。 两者的区别是:dojo.map中回调函数的返回值将会被按顺序存储在一个新的数组中。而这个新数组就是dojo.map的返回值
另一个Dojo提供的常用转换功能是 dojo.filter。 顾名思义,它允许你在原有数组元素中根据一定规则和条件过滤出某些元素。当然,你也可以用forEach来写,但是使用dojo.filter 会将这一过程大大简化。
@H_301_18@var filtered = dojo.filter(mapped,//dojo.filter 的回调函数返回一个布尔值,当其值为true时,该item将会被加入dojo.filter 返回的数组中,反之则跳过该item
function(item,index){
return item.id > 50 && item.id < 350;
}); // [ { id: 100,{ id: 200,text: "three" },// { id: 300,text: "four" } ]
查看示例
匹配
在程序中我们有时需要判断数组中的某元素是否满足某些条件:例如你想知道其中是否有某些元素定义了error属性,或者你想确定是否数组中每个元素都定义了text属性。 这时就可以使用dojo.some 或dojo.every 方法。
这两个函数的签名和dojo.filter 完全一样,使用的回调函数也是一个返回布尔值的函数。 不过dojo.some 和dojo.every 两个函数本身不返回一个新数组,而是返回布尔值:dojo.every返回true表示,对数组中每个元素回调函数的都返回true,而dojo.some 返回true表示,数组中至少存在一个函数,对其调用回调函数时返回了true
@H_301_18@var arr1 = [1,5],arr2 = [1,1];
//判断是否每个元素都为1
dojo.every(arr1,function(item){ return item == 1; }); // returns false
//判断是否至少拥有一个1
dojo.some(arr1,function(item){ return item == 1; }); // returns true
dojo.every(arr2,function(item){ return item == 1; }); // returns true
dojo.some(arr2,function(item){ return item == 2; }); // returns false
dojo.some(arr2,function(item){ return item == 2; }); // returns false
小结
JavaScript规范提供了一系列强大的数组遍历和操作方法,但是不是所有的浏览器和运行时环境都能支持这些新规范中的方法。Dojo提供了跨平台的方案来弥补这一空缺,使用这些方法,可以减少代码行数,提升执行效率。