$.each(o, function(i, ele){ if(this=="linda"){//我们随机选取第一个属性 console.log(this,this==ele); $.each(this, function(e, ele2) { console.log(e, ele2); }); } }); //String {0: "l", 1: "i", 2: "n", 3: "d", 4: "a", length: 5, [[PrimitiveValue]]: "linda"} true //0 "l" //1 "i" //2 "n" //3 "d" //4 "a"
我们发现, this对象等于回调函数的第二个形参. 且它的 length 属性和 [[PrimitiveValue]] 属性并没有被打印出来, 为此我们来查看下length的内部属性.
$.each(o, function(i, ele){ if(this=="linda")//我们还是随机选取第一个属性(这还是随机吗?) console.log(Object.getOwnPropertyDescriptor(this, 'length')); }); //Object {value: 5, writable: false, enumerable: false, configurable: false}
可见, this对象的length属性的 enumerable 属性被设置成了false, 这表示该对象不能被列举或遍历, 同时还不能被配置(configurable: false) , 也不能被赋值(writable: false) .
此时, 前面遍历 o 对象时,它的 length 属性没有被打印出来的疑问似乎有解了. 让我们来看看 o.length 的内部属性吧.
console.log(Object.getOwnPropertyDescriptor(o, 'length')); //Object {value: 3, writable: true, enumerable: true, configurable: true}
o.length 值为3, 可赋值, 可列举, 可配置. 这可不对, 刚刚不是说 enumerable 属性被设置成了false 才不会被遍历吗. 现在该值为 true, 并且还不可遍历. 这不合常理, 自然该有别的原因. 我们接着往下看.
var o = {0:"linda",1:"style",2:"nick",length:1}; // 试着改变length的值 $.each(o, function(i, ele){//再遍历一次 console.log(i,ele); }); //0 "linda" var o = {0:"linda",1:"style",2:"nick",length:5}; // 坚持改变length的值 $.each(o, function(i, ele){//再遍历一次 console.log(i,ele); }); // 0 linda // 1 style // 2 nick // length 5 var o = {0:"linda",1:"style",2:"nick"}; // 试试去掉length属性 $.each(o, function(i, ele){//再遍历一次 console.log(i,ele); }); // 0 linda // 1 style // 2 nick
现象明了, 结合jquery源码, 当对象中存在length属性时, $.each 内部使用for循环去遍历对象, 否则它将使用for in循环去遍历, 因此$.each遍历对象遵循如下规律:
如果对象中存在 length 属性, 遍历深度以length属性为准, 即length多大, 遍历多少个元素.
如果对象中不存在 length 属性, 遍历深度以实际内部属性个数为准.
不仅如此, $.each的具体使用过程中还有以下几点需要注意:
使用 return 或者 return true 为跳过一个元素,继续执行后面的循环;
使用 return false 为终止循环的执行, 这是因为在 jquery.each 中, 若返回值指定为false, 才跳出循环, 如果感兴趣请翻看 jquery.each 源码;
无法使用 break 与 continue 来跳过循环.
$(selecter).each
语法: $(selecter|array|o).each(function(i, ele){}) 支持数组和对象, 该方法基本上与$.each方法相同.
$('div').each(function(i,ele){ console.log(this,i,this == ele); }); //dom... 0 dom.... true $(array).each(function(i,ele){//处理数组 if(this == "领袖") console.log(this,i,this == ele); }); //String {0: "领", 1: "袖", length: 2, [[PrimitiveValue]]: "领袖"} 2 true $(o).each(function(i,ele){//处理对象 if(this == "nick") console.log(this,i,this == ele); }); //String {0: "n", 1: "i", 2: "c", 3: "k", length: 4, [[PrimitiveValue]]: "nick"} 2 true
dom表示div元素, 由于this恒等ele, 说明this也表示div元素, 所以this并不是jquery对象, 而是普通的DOM对象(可以在this上随意使用DOM方法). 使用$(selecter).each方法,请注意以下几点:
i: 即序列值 ele: 表示当前被遍历的DOM元素
this 表示当前被遍历的DOM元素,不能调用jQuery方法, 如需调用jquery方法需要用$符号包裹.如, $(this)
map
即 Array.prototype.map,该方法只支持数组
语法: array.map(callback[,thisArg]) map方法使用其提供函数的每次返回结果生成一个新的数组.
var array = [1, 4, 9]; var roots = array.map(Math.sqrt);//map包裹方法名 // roots is now [1, 2, 3], array is still [1, 4, 9] var array = [1, 4, 9]; var doubles = array.map(function(num) {//map包裹方法实体 return num * 2; }); // doubles is now [2, 8, 18]. array is still [1, 4, 9]
实际上,由于map方法被设计成支持 [鸭式辨型][] , 该方法也可以用来处理形似数组的对象, 例如 NodeList.
var elems = document.querySelectorAll('select option:checked'); var values = Array.prototype.map.call(elems, function(obj) { return obj.value; });
甚至还可以用来处理字符串, 如下:
var map = Array.prototype.map; var array = map.call('Hello 中国', function(x) { return x.charCodeAt(0); }); console.log(array); //[72, 101, 108, 108, 111, 32, 20013, 22269]
map处理字符串的方式多种多样, 例如 反转等.
var str = '12345'; var output = Array.prototype.map.call(str, function(x) { return x; }).reverse().join(''); console.log(output);//54321
例如 将字符串数组转换为数字数组, 只需一条语句, 如下:
console.log(['1', '2', '3'].map(Number));//[1,2,3]
目前map方法被大部分浏览器支持, 除了IE 6,7,8.
every
即 Array.prototype.every, 该方法同上述map方法也只支持数组
语法: arr.every(callback[, thisArg]) every 方法用于检验数组中的每一项是否符合某个条件, 若符合则放回true, 反之则返回false.
function isBigEnough(element, index, array) { return element >= 10; } [12, 5, 8, 130, 44].every(isBigEnough); // false [12, 54, 18, 130, 44].every(isBigEnough); // true
该方法还有简写方式, 如下:
[12, 5, 8, 130, 44].every(elem => elem >= 10); // false [12, 54, 18, 130, 44].every(elem => elem >= 10); // true
以上, 遍历数组和对象的8种方法简单的介绍完, 小结如下:
for in , $.each , $().each 既支持对象也支持数组遍历;
for , do/while , forEach 只支持数组;
Array.prototype.map, Array.prototype.every 只支持数组和形似数组的对象;
forEach不能退出循环,只能通过return来进入到下一个元素的遍历中(相当于for循环的continue), 且在IE没有实现该方法;
$.each和$().each循环只能通过return false 来退出循环, 使用return 或 return true 将跳过一个元素, 继续执行后面的循环.
测试各方法效率
下面我们来测试下上述方法的效率.