在某个秘密的季节,青春逝去,不复重来。或许它只是残留在清澈阳光下的某一个不经意的思绪碎片,但它依然能让咱们的眼睛里泛出淡淡的光来。javascript
额,很差意思,走错片场了,今日不谈李易安,且论循环。html
本文讲的是js的循环遍历并不是事件循环机制,立意不深,大神蜻蜓点水,众生可抢沙发。java
while语句包括一个循环条件和一段代码块,只要条件为真,就不断循环执行代码块。先判断后执行
。es6
var num = 1;//1.声明循环变量
while (num<=10){//2.判断循环条件
document.write(num+" ");//3.执行循环体
num++;//4.跟新循环变量
}
复制代码
do...while循环与while循环相似,惟一的区别就是先运行一次循环体,而后判断循环条件。即先执行后判断
。json
var num = 10;
do{
document.write(num+" ");
num--;
}while(num>=0);
document.write(num);//-1
复制代码
for循环有三个表达式:①声明循环变量;②判断循环条件;③更新循环变量;先判断后执行
,与while相同。数组
for(var num=0;num<10;num++){
document.write(num+" ");
}
复制代码
for...in 循环主要用于遍历对象。bash
var obj = {a:1,b:2,c:3};
for(var i in obj){
console.log('键名:'+i);
console.log('键值:'+obj[i]);
}
复制代码
for...in 循环,遍历时不只能读取对象自身上面的成员属性,也能延续原型链遍历出对象的原型属性,可使用hasOwnProperty
判断一个属性是否是对象自身上的属性。obj.hasOwnProperty(keys)==true
表示这个属性是对象的成员属性,而不是原型属性。数据结构
var person = {name:'小夏'};
for(var key in person){
if(person.hasOwnProperty(key)){
console.log(key);//name
}
}
复制代码
再聊一点:遍历json对象app
无规律json数组:函数
var json = [{qwer:'姚姚',a:'is',b:1}, {ob:'da',tp:'sb'}];
for(var i=0,l=json.length;i<l;i++){//此处长度用变量保存下来可节约资源的消耗
for(var key in json[i]){
alert(key+':'+json[i][key]);
}
}
复制代码
有规律json数组:
var packJson = [
{"name": "nikita", "password": "1111"},
{"name": "tony", "password": "2222"}
];
for (var p in packJson) {//遍历json数组时,这么写p为索引,0,1
alert(packJson[p].name + " " + packJson[p].password);
}
复制代码
ES6 借鉴 C++、Java、C# 和 Python 语言,引入了for...of循环,做为遍历全部数据结构的统一的方法。
一个数据结构只要部署了
Symbol.iterator
属性,就被视为具备iterator
接口,就能够用for...of循环遍历它的成员。也就是说,for...of循环内部调用的是数据结构的Symbol.iterator
方法。for...of循环可使用的范围包括数组、Set和Map结构、某些相似数组的对象(好比arguments
对象、DOM NodeList
对象)、后文的Generator
对象,以及字符串。
下面咱们对一些数据结构进行遍历:
var arr = ['a','b','c','d'];
for(let i in arr){
console.log(i);//0 1 2 3
}
for(let j of arr){
console.log(j);//a b c d
}
var iterator = arr.entries();
for(let j of iterator){
console.log(j);//[0,"a"] [1,"b"] [2,"c"] [3,"d"]
}
var iterator = arr.keys();
console.log(iterator);
for(let j of iterator){
console.log(j);//0 1 2 3
}
复制代码
上面代码代表,for...in循环读取键名,for...of循环读取键值。若是要经过for...of循环,获取数组的索引,能够借助数组实例的entries
方法和keys
方法。
//Set 结构
var newSet = new Set(["a","b","c","c"]);
for(var e of newSet){
console.log(e);//a b c
}
// Map结构
var es6 = new Map();
console.log(es6);
es6.set('yaoyao',1);
es6.set('bubu','2');
es6.set('fengfeng','last');
for(var [name,value] of es6){//用name和value接受键名和键值
console.log(name+':'+value);//yaoyao:1 bubu:2 fengfeng:last
}
复制代码
上面代码演示了如何遍历 Set结构和Map结构。值得注意的地方有两个,首先,遍历的顺序是按照各个成员被添加进数据结构的顺序。其次,Set结构遍历时,返回的是一个值,而Map结构遍历时,返回的是一个数组,该数组的两个成员分别为当前Map成员的键名和键值。
相似数组的对象包括好几类。下面是for...of循环用于字符串、DOM NodeList 对象、arguments对象的例子。
// 字符串
var str = 'GREAT';
for(let s of str){
console.log(s);//G R E A T
}
// DOM NodeList对象
let paras = document.querySelectorAll('p');
for(let p of paras){
console.log(p);//打印出全部p标签
p.classList.add('addClass');
}
// arguments对象
function printArgs(){
for(let x of arguments){
console.log(x);
}
}
printArgs([1,2],"1",{"a":3});//[1,2] "1" {"a":3}
复制代码
map方法将数组的全部成员依次传入参数函数,而后把每一次的执行结果组成一个新数组返回,而且不会改变原数组。
var numbers = [1,2,3];
var newNumbers = numbers.map(function(i){
return i+1;
})
console.log(newNumbers);//[2,3,4]
console.log(numbers);//[1,2,3]
复制代码
map方法接受一个函数做为参数,该函数调用时,map方法向它传入三个参数:当前值,当前下标和数组自己。
var newMap = [2,3,4].map(function(item,index,arr){
return item*index;
})
console.log(newMap);//[0,3,8]
复制代码
此外,map方法还能够接受第二个参数,用来绑定回调函数内部的this变量,将回调函数内部的this对象,指向第二个参数,间接操做这个参数(通常是数组)。
var arr = ['a','b','c','d'];
var newArgs = [1,2].map(function(i){
return this[i];
},arr);
console.log(newArgs);//["b","c"]
复制代码
上面代码经过map方法的第二个参数,将回调函数内部的this对象,指向arr数组。间接操做了数组arr;接下来说的forEach一样具备这个功能。
forEach方法与map方法很类似,也是对数组的全部成员依次执行参数函数。可是,forEach方法不返回值,只用来操做数据。也就是说,若是数组遍历的目的是为了获得返回值,那么使用map方法,不然使用forEach方法。forEach的用法与map方法一致,参数是一个函数,该函数一样接受三个参数:当前值、当前下标、数组自己。
[4,5,6].forEach(function(ele,index,arr){
console.log(index+':'+ele);//0:4 1:5 2:5
})
复制代码
此外,forEach循环和map循环同样也能够用绑定回调函数内部的this变量,间接操做其它变量(参考上面的map()循环例子)。
filter方法用于过滤数组成员,知足条件的成员组成一个新数组返回。它的参数是一个函数,全部数组成员依次执行该函数,返回结果为true的成员组成一个新数组返回。该方法不会改变原数组。
var newFilter = [1,2,3,4,5,6].filter(function(i){
return i>2
})
console.log(newFilter);//[3,4,5,6]
var arr = [0,1,'a',false,null,undefined];
var arrFilter = arr.filter(Boolean);
console.log(arrFilter);//[1,"a"]
复制代码
看起来和Map()循环没什么区别,那么比较一下能够发现map方法内部使用判断语句时知足返回true,不知足返回false。
var newFilter = [1,2,3,4,5,6].map(function(i){
return i>2
})
console.log(newFilter);//[false, false, true, true, true, true]
复制代码
filter方法的参数函数也能够接受三个参数:当前值,当前下标和数组自己。
var allFilter = [1,2,3,4,5].filter(function(ele,index,arr){
return index % 2 === 0;
})
console.log(allFilter);//[1,3,5]
复制代码
filter方法也能够接受第二个参数,用来绑定参数函数内部的this变量。
var obj = {MAX:3};
var myFilter = function(item){
return item > this.MAX;
}
var arr = [2,8,3,4,1,3,2,9];
var newFilter = arr.filter(myFilter,obj);
console.log(newFilter);//[8,4,9]
复制代码
这两个方法相似“断言”(assert),返回一个布尔值,表示判断数组成员是否符合某种条件。它们接受一个函数做为参数,全部数组成员依次执行该函数。该函数接受三个参数:当前值、当前下标和数组自己,而后返回一个布尔值。
只要有一个成员知足条件,则总体返回true;反言之,没有任何一个成员知足条件,则总体返回false。
var arr = [1,2,3,4,5];
var newSome = arr.some(function(i){
return i >= 3;
})
console.log(newSome);//true
复制代码
全部成员都知足条件,则总体返回true;反言之,只要有一个成员不知足条件,则总体返回false。
var arr = [1,2,3,4,5];
var newEvery = arr.every(function(i){
return i>=3;
})
console.log(newEvery);//false
复制代码
reduce()方法接收一个函数做为累加器,数组中的每一个值(从左到右)开始缩减,最终计算为一个值。
[1, 2, 3, 4, 5].reduce(function (a, b) {
console.log(a, b);
return a + b;
})
// 1 2
// 3 3
// 6 4
// 10 5
//最后结果:15
复制代码
场景: 统计一个数组中有多少个不重复的单词
使用for循环
var arr = ['apple','orange','apple','orange','pear','orange'];
function getWordCnt(){
var obj = {};
for(var i=0,l=arr.length;i<l;i++){
var item = arr[i];
obj[item] = (obj[item]+1)||1;
//第一次遍历obj.apple是undefined,因此obj.apple取1;
//第二次遍历obj.orange是undefined,因此obj.orange取1;
//第三次遍历obj.apple已是1了,因此obj.apple = 1+1;······
}
return obj;
}
console.log(getWordCnt());//{apple: 2, orange: 3, pear: 1}
复制代码
reduce(callback, initialValue)会传入两个变量。回调函数(callback)和初始值(initialValue)。假设函数它有个传入参数,prev和next,index和array。prev和next是必填项,index和array是选填项。通常来说prev是从数组中第一个元素开始的,next是第二个元素。可是当你传入初始值(initialValue)后,第一个prev将是initivalValue,next将是数组中的第一个元素。
var arr = ['apple','orange','apple'];
function noPassValue(){
return arr.reduce(function(prev,next){
console.log('prev:',prev);
console.log('next:',next);
return prev+' '+next;
})
}
console.log(noPassValue());
console.log('------------------------------');
function passValue(){
return arr.reduce(function(prev,next){
console.log('prev:',prev);
console.log('next:',next);
prev[next] = (prev[next]+1)||1;
return prev;
},{})
}
console.log(passValue());
复制代码
打印结果为:
reduceRight的语法以及回调函数的规则和reduce方法是同样的,区别就是在与reduce是升序,即角标从0开始,而reduceRight是降序,即角标从arr.length-1开始。
反转字符串:
var word = 'ilovexx';
function AppendToArray(previousValue,currentValue){
return previousValue + currentValue;
}
var result = [].reduceRight.call(word,AppendToArray,"the ");
console.log(result);//the xxevoli
复制代码
Object.keys方法的参数是一个对象,返回一个数组。该数组的成员都是该对象自身的(而不是继承的)全部属性名,且只返回可枚举的属性。
var obj = {
p1: 123,
p2: 456
};
console.log(Object.keys(obj)); // ["p1", "p2"]
复制代码
这个方法是否是有点眼熟,不妨对比一下上面的2.5.1。
Object.getOwnPropertyNames方法与Object.keys方法相似,也是接受一个对象做为参数,返回一个数组,包含了该对象自身的全部属性名。但它能返回不可枚举的属性。
var a = ['Hello', 'World'];
console.log(Object.keys(a) )// ["0", "1"]
console.log(Object.getOwnPropertyNames(a)) // ["0", "1", "length"]
复制代码
grep()循环可以遍历数组,并筛选符合条件的元素,组成新的数组,并返回。
$(function(){
var array = [1,2,3,4,5,6,7,8,9];
var filterarray = $.grep(array,function(value){
return value > 5;//筛选出大于5的
});
console.log(filterarray);//[6,7,8,9]
for(var i=0;i<filterarray.length;i++){
alert(filterarray[i]);
}
for (key in filterarray){
alert(filterarray[key]);
}
})
复制代码
$.each(anObject,function(name,value) {
console.log(name);
console.log(value);
});
var anArray = ['one','two','three'];
$.each(anArray,function(n,value){
console.log(n);
console.log(value);
});
复制代码
var anArray = ['a','b','c'];
var index = $.inArray('b',anArray);
console.log(index,anArray[index]);//1 "b"
复制代码
var strings = ['0','1','2','3','4','5','6'];
var values = $.map(strings,function(val){
var result = new Number(val);
return isNaN(result)?null:result
})
for(var key in values){
console.log(values[key]);
}
复制代码
jQuery的遍历方法在平常使用中仍是比较少的,由于这几种方法在js原生中都能找到对应的方法。写了这么多发现实战中仍是for循环用的最多,哈哈哈哈哈。。。。。。不过学了这些以后起码往后遇到循环问题有更多的解决方案,何乐不为呢。
其实大多数类似方法的对比在文中就已经谈过了,此处将map()、forEach()、filter()三个单独拎出来作个比较:
相同之处:
1.三种循环中途都是没法中止的,老是会将全部成员遍历完。
2.他们均可以接受第二个参数,用来绑定回调函数内部的this变量,将回调函数内部的this对象,指向第二个参数,间接操做这个参数(通常是数组)。
不一样之处:
forEach()循环没有返回值;map(),filter()循环有返回值。
你还在用for循环大法麽?
js的15种循环遍历,你掌握了几种?
深刻了解 JavaScript 中的 for 循环
JS中的循环---最全的循环总结