人生不过一场绚烂循环
栏目: JavaScript · 发布时间: 5年前
内容简介:在某个秘密的季节,青春逝去,不复重来。或许它只是残留在清澈阳光下的某一个不经意的思绪碎片,但它依然能让我们的眼睛里泛出淡淡的光来。额,不好意思,走错片场了,今日不谈李易安,且论循环。本文讲的是js的循环遍历并非事件循环机制,立意不深,大神走马观花,众生可抢沙发。
在某个秘密的季节,青春逝去,不复重来。或许它只是残留在清澈阳光下的某一个不经意的思绪碎片,但它依然能让我们的眼睛里泛出淡淡的光来。
额,不好意思,走错片场了,今日不谈李易安,且论循环。
本文讲的是js的循环遍历并非事件循环机制,立意不深,大神走马观花,众生可抢沙发。
一丶原生的JS循环
1.1 while 循环
while语句包括一个循环条件和一段代码块,只要条件为真,就不断循环执行代码块。 先判断后执行
。
var num = 1;//1.声明循环变量 while (num<=10){//2.判断循环条件 document.write(num+" ");//3.执行循环体 num++;//4.跟新循环变量 } 复制代码
1.2 do...while 循环
do...while循环与while循环类似,唯一的区别就是先运行一次循环体,然后判断循环条件。即 先执行后判断
。
var num = 10; do{ document.write(num+" "); num--; }while(num>=0); document.write(num);//-1 复制代码
1.3 for循环
for循环有三个表达式:①声明循环变量;②判断循环条件;③更新循环变量; 先判断后执行
,与while相同。
for(var num=0;num<10;num++){ document.write(num+" "); } 复制代码
1.4 for...in 循环
for...in 循环主要用于遍历对象。
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对象
无规律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); } 复制代码
1.5 for...of 循环
ES6 借鉴 C++、 Java 、C# 和 Python 语言,引入了for...of循环,作为遍历所有数据结构的统一的方法。
一个数据结构只要部署了 Symbol.iterator
属性,就被视为具有 iterator
接口,就可以用for...of循环遍历它的成员。也就是说,for...of循环内部调用的是数据结构的 Symbol.iterator
方法。for...of循环可以使用的范围包括数组、Set和Map结构、某些类似数组的对象(比如 arguments
对象、 DOM NodeList
对象)、后文的 Generator
对象,以及字符串。
下面我们对一些数据结构进行遍历:
1.5.1 数组
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
方法。
1.5.2 Set和Map结构
//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成员的键名和键值。
1.5.3 类似数组的对象
类似数组的对象包括好几类。下面是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} 复制代码
1.6 Map()循环
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同样具有这个功能。
1.7 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()循环例子)。
1.8 filter()过滤循环
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] 复制代码
1.9 some()、every()循环遍历,统计数组是否满足某个条件
这两个方法类似“断言”(assert),返回一个布尔值,表示判断数组成员是否符合某种条件。它们接受一个函数作为参数,所有数组成员依次执行该函数。该函数接受三个参数:当前值、当前下标和数组本身,然后返回一个布尔值。
1.9.1 some()
只要有一个成员满足条件,则整体返回true;反言之,没有任何一个成员满足条件,则整体返回false。
var arr = [1,2,3,4,5]; var newSome = arr.some(function(i){ return i >= 3; }) console.log(newSome);//true 复制代码
1.9.2 every()
所有成员都满足条件,则整体返回true;反言之,只要有一个成员不满足条件,则整体返回false。
var arr = [1,2,3,4,5]; var newEvery = arr.every(function(i){ return i>=3; }) console.log(newEvery);//false 复制代码
1.10 reduce()和reduceRight()
1.10.1 reduce()
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()); 复制代码
打印结果为:
观察打印结果不仅可以明显发现二者区别,还可以发现函数passValue作用可以等同于上面的for循环。
1.10.2 reduceRight()
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 复制代码
1.11 Object.keys()
Object.keys方法的参数是一个对象,返回一个数组。该数组的成员都是该对象自身的(而不是继承的)所有属性名,且只返回可枚举的属性。
var obj = { p1: 123, p2: 456 }; console.log(Object.keys(obj)); // ["p1", "p2"] 复制代码
这个方法是不是有点眼熟,不妨对比一下上面的2.5.1。
1.12 Object.getOwnPropertyNames()
Object.getOwnPropertyNames方法与Object.keys方法类似,也是接受一个对象作为参数,返回一个数组,包含了该对象自身的所有属性名。但它能返回不可枚举的属性。
var a = ['Hello', 'World']; console.log(Object.keys(a) )// ["0", "1"] console.log(Object.getOwnPropertyNames(a)) // ["0", "1", "length"] 复制代码
二丶使用jQuery的遍历
2.1 $.grep()筛选遍历数组
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]); } }) 复制代码
2.2 $.each()筛选遍历数组或json对象
$.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); }); 复制代码
2.3 $.inArray()筛选遍历数组
var anArray = ['a','b','c']; var index = $.inArray('b',anArray); console.log(index,anArray[index]);//1 "b" 复制代码
2.4 $.map()筛选遍历数组
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()循环有返回值。
四丶参考资料
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
JavaScript编程精解
Marijn Haverbeke / 徐涛 / 机械工业出版社华章公司 / 2012-10-1 / 49.00元
如果你只想阅读一本关于JavaScript的图书,那么本书应该是你的首选。本书由世界级JavaScript程序员撰写,JavaScript之父和多位JavaScript专家鼎力推荐。本书适合作为系统学习JavaScript的参考书,它在写作思路上几乎与现有的所有同类书都不同,打破常规,将编程原理与运用规则完美地结合在一起,而且将所有知识点与一个又一个经典的编程故事融合在一起,读者可以在轻松的游戏式......一起来看看 《JavaScript编程精解》 这本书的介绍吧!