JavaScript 开发必须掌握技能(三)- 更好的使用for循环方法
版权声明:本文转载至CSDN博主「诗人与黑客」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_41899174/article/details/82797089
感谢博主,感谢分享,对于for循环咋们不能遇到数组、对象等打印别一上来就常规循环for(var i=0;i<arr.length;i++){...},还是让自己编写的代码动起来,可读性好起来,代码数量简洁些。原计划做一份自己的for循环方法总结,在网上搜索下for循环的介绍很多很多,我觉得该文挺全面的,自己做不一定做的这么详细,所幸直接转载博主的文章,分享保留。自己能够灵活的去使用这才是最好的。这也是在工作后开始写博客,觉得意义挺大的,因为在工作中一些基础的方法都还需要去找百度,没能对知识做一个沉淀。通过博客笔记本随时翻阅,对自己很定是极大的帮助的,毕竟自己的笔记和别人的笔记是有区别的。不多说,干就完了。
有的方法我们在前面的随笔中也曾提及过,这里当做在次巩固吧!
方式一: 原生的 js 循环
1.while 循环:
While语句包括一个循环条件和一段代码块,只要条件为真,就不断循环执行代码块。
while (条件) 语句; // 或者 while (条件) 语句; //举例: var i = 0; while (i < 100) { console.log('i 当前为:' + i); i = i + 1; }
2. do……while循环
do...while循环与while循环类似,唯一的区别就是先运行一次循环体,然后判断循环条件。
do 语句 while (条件) // 或者 do { 语句 } while (条件); //举例: var x = 3; var i = 0; do { console.log(i); i++; } while(i < x);
3.for循环:
for(var i=0;i<filterarray.length;i++){ alert(filterarray[i]); }
4.增强for…in循环:
var obj = {a: 1, b: 2, c: 3}; for (var i in obj) { console.log('键名:', i); console.log('键值:', obj[i]); } // 键名: a
// 键值: 1
// 键名: b
// 键值: 2
// 其中 obj为循环的对象, i 为对象中的“键名”。如果对象是数组,那么i就是坐标。
注意:fo…in循环一般用于对象的遍历,但是这里有一个坑需要注意:
任何对象都继承了Object对象,或者其它对象,继承的类的属性是默认不可遍历的,for... in循环遍历的时候会跳过,但是这个属性是可以更改为可以遍历的,那么就会造成遍历到不属于自身的属性。
举例来说,对象都继承了toString属性,但是for...in循环不会遍历到这个属性。
var obj = {};// toString 属性是存在的obj.toString // toString() { [native code] } for (var p in obj) { console.log(p); } // 没有任何输出
如果继承的属性是可遍历的,那么就会被for...in循环遍历到。但如果只想遍历自身的属性,使用for...in的时候,应该结合使用hasOwnProperty方法,在循环内部判断一下,某个属性是否为对象自身的属性。否则就可以产生遍历失真的情况。
var person = { name: '老张' }; for (var key in person) { if (person.hasOwnProperty(key)) { console.log(key); } }// name
此外,for循环遍历json对象有点奇葩:
无规律json数组:
var json = [{dd:'SB',AA:'东东',re1:123}, {cccc:'dd',lk:'1qw'}]; for(var i=0,l=json.length;i<l;i++){ for(var key in json[i]){ alert(key+’:'+json[i][key]); } }
为什么要 l=json.length;i<l呢?小伙伴们自己思考下吧!哈哈哈哈……
有规律json数组:
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); }
5.map()循环:
map方法将数组的所有成员依次传入参数函数,然后把每一次的执行结果组成一个新数组返回。
注意:是返回一个新数组,而不会改变原数组。
var numbers = [1, 2, 3]; numbers.map(function (n) { return n + 1; }); // [2, 3, 4] numbers // [1, 2, 3]
map方法接受一个函数作为参数。该函数调用时,map方法向它传入三个参数:当前成员、当前位置和数组本身。
[1, 2, 3].map(function(elem, index, arr) { return elem * index; }); // [0, 2, 6]
此外,map()循环还可以接受第二个参数,用来绑定回调函数内部的this变量,将回调函数内部的this对象,指向第二个参数,间接操作这个参数(一般是数组)。
var arr = ['a', 'b', 'c']; [1, 2].map(function (e) { return this[e]; }, arr) // ['b', 'c']
上面代码通过map方法的第二个参数,将回调函数内部的this对象,指向arr数组。间接操作了数组arr; forEach同样具有这个功能。
6.forEach循环
forEach方法与map方法很相似,也是对数组的所有成员依次执行参数函数。但是,forEach方法不返回值,只用来操作数据。也就是说,如果数组遍历的目的是为了得到返回值,那么使用map方法,否则使用forEach方法。forEach的用法与map方法一致,参数是一个函数,该函数同样接受三个参数:当前值、当前位置、整个数组。
function log(element, index, array) { console.log('[' + index + '] = ' + element); } ; [2, 5, 9].forEach(log); // [0] = 2 // [1] = 5 // [2] = 9
此外,forEach循环和map循环一样也可以用绑定回调函数内部的this变量,间接操作其它变量(参考上面的map()循环例子)。
7.filter()过滤循环
filter方法用于过滤数组成员,满足条件的成员组成一个新数组返回。它的参数是一个函数,所有数组成员依次执行该函数,返回结果为true的成员组成一个新数组返回。该方法不会改变原数组。
[1, 2, 3, 4, 5].filter(function (elem) { return (elem > 3); }) // [4, 5] // 上面代码将大于3的数组成员,作为一个新数组返回。 var arr = [0, 1, 'a', false]; arr.filter(Boolean) // [1, "a"]
filter方法的参数函数也可以接受三个参数:当前成员,当前位置和整个数 组。
[1, 2, 3, 4, 5].filter(function (elem, index, arr) { return index % 2 === 0; }); // [1, 3, 5]
此外,filter方法也可以接受第二个参数,用来绑定参数函数内部的this变量。
var obj = { MAX: 3 }; var myFilter = function (item) { if (item > this.MAX) return true; }; var arr = [2, 8, 3, 4, 1, 3, 2, 9]; arr.filter(myFilter, obj) // [8, 4, 9]
上面代码中,过滤器myFilter内部有this变量,它可以被filter方法的第二个参数obj绑定,返回大于3的成员。
8.some(),every()循环遍历,统计数组是否满足某个条件
这两个方法类似“断言”(assert),返回一个布尔值,表示判断数组成员是否符合某种条件。
它们接受一个函数作为参数,所有数组成员依次执行该函数。该函数接受三个参数:当前成员、当前位置和整个数组,然后返回一个布尔值。
some方法是只要一个成员的返回值是true,则整个some方法的返回值就是true,否则返回false。
var arr = [1, 2, 3, 4, 5]; arr.some(function (elem, index, arr) { return elem >= 3; }); // true
而every方法则相反,所有成员的返回值都是true,整个every方法才返回true,否则返回false。两相比较,some()只要有一个是true,便返回true;而every()只要有一个是false,便返回false.
var arr = [1, 2, 3, 4, 5]; arr.every(function (elem, index, arr) { return elem >= 3; }); // false
这两个方法在实际开发中,大有可用之处。比如在判定用户是否勾选了不可操作的数据,或者是否勾选了一条可以操作的数据可以使用这两个方法遍历循环数组。
9.reduce(),reduceRight()方法可依次处理数组的每个成员
reduce方法和reduceRight方法依次处理数组的每个成员,最终累计为一个值。它们的差别是,reduce是从左到右处理(从第一个成员到最后一个成员),reduceRight则是从右到左(从最后一个成员到第一个成员),其他完全一样。
[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
reduce方法和reduceRight方法的第一个参数都是一个函数。该函数接受以下四个参数。
累积变量,默认为数组的第一个成员
当前变量,默认为数组的第二个成员
当前位置(从0开始)
原数组
这四个参数之中,只有前两个是必须的,后两个则是可选的。
如果要对累积变量指定初值,可以把它放在reduce方法和reduceRight方法的第二个参数。
[1, 2, 3, 4, 5].reduce(function (a, b) { return a + b; }, 10); // 25
上面的第二个参数相当于设定了默认值,处理空数组时尤其有用,可避免一些空指针异常。
由于这两个方法会遍历数组,所以实际上还可以用来做一些遍历相关的操作。比如,找出字符长度最长的数组成员。
function findLongest(entries) { return entries.reduce(function (longest, entry) { return entry.length > longest.length ? entry : longest; }, ''); }
findLongest(['aaa', 'bb', 'c'])
// "aaa"
上面代码中,reduce的参数函数会将字符长度较长的那个数组成员,作为累积值。这导致遍历所有成员之后,累积值就是字符长度最长的那个成员。
10.Object,keys遍历对象的属性
Object.keys方法的参数是一个对象,返回一个数组。该数组的成员都是该对象自身的(而不是继承的)所有属性名,且只返回可枚举的属性。
var obj = { p1: 123, p2: 456 }; Object.keys(obj) // ["p1", "p2"]
11.Object.getOwnPropertyNames()遍历对象的属性
Object.getOwnPropertyNames方法与Object.keys类似,也是接受一个对象作为参数,返回一个数组,包含了该对象自身的所有属性名。但它能返回不可枚举的属性。
var a = ['Hello', 'World']; Object.keys(a) // ["0", "1"] Object.getOwnPropertyNames(a) // ["0", "1", "length"]
上面代码中,数组的length属性是不可枚举的属性,所以只出现在Object.getOwnPropertyNames方法的返回结果中。
由于 JavaScript 没有提供计算对象属性个数的方法,所以可以用这两个方法代替。
var obj = { p1: 123, p2: 456 }; Object.keys(obj).length // 2 Object.getOwnPropertyNames(obj).length // 2
以上循环特征(相同与不同):
一:map(),foreach,filter循环的共同之处:
1.foreach,map,filter循环中途是无法停止的,总是会将所有成员遍历完。
2.他们都可以接受第二个参数,用来绑定回调函数内部的this变量,将回调函数内部的this对象,指向第二个参数,间接操作这个参数(一般是数组)。
二:map()循环和forEach循环的不同:
forEach循环没有返回值;map,filter循环有返回值。
三:map(环和filter()循环都会跳过空位,for和while不会
var f = function (n) { return 'a' }; [1, undefined, 2].map(f) // ["a", "a", "a"] [1, null, 2].map(f) // ["a", "a", "a"] [1, , 2].map(f) // ["a", , "a"]
上面代码中,map方法不会跳过undefined和null,但是会跳过空位。forEach方法也会跳过数组的空位,这里就不举例了。
四:some()和every():
some()只要有一个是true,便返回true;而every()只要有一个是false,便返回false.
五:reduce(),reduceRight():
reduce是从左到右处理(从第一个成员到最后一个成员),reduceRight则是从右到左(从最后一个成员到第一个成员)。
六:Object对象的两个遍历Object.keys与Object.getOwnPropertyNames:
他们都是遍历对象的属性,也是接受一个对象作为参数,返回一个数组,包含了该对象自身的所有属性名。但Object.keys不能返回不可枚举的属性;Object.getOwnPropertyNames能返回不可枚举的属性。
方式二: 使用JQuery 的遍历:
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的 }); for(var i=0;i<filterarray.length;i++){ alert(filterarray[i]); } for (key in filterarray){ alert(filterarray[key]); } }
2.$.each()筛选遍历数组或json对象
function(){ var anObject = {one:1,two:2,three:3};//对json数组each $.each(anObject,function(name,value) { alert(name); alert(value); }); var anArray = ['one','two','three']; $.each(anArray,function(n,value){ alert(n); alert(value); }); }
3.$.inArray()筛选遍历数组
inArray()循环能返回参数在数组中对应的坐标。
function(){ var anArray = ['one','two','three']; var index = $.inArray(‘two’,anArray); alert(index);//返回该值在数组中的键值,返回1 alert(anArray[index]);//value is two }
4.$.map()筛选遍历数组
$().ready( function(){ var strings = ['0','1','2','3','4','S','6']; var values = $.map(strings,function(value){ var result = new Number(value); return isNaN(result) ? null:result;//isNaN:is Not a Number的缩写 }); for (key in values) { alert(values[key]); } });
map循环常用语往数组中添加新元素,第二种写法:
this.detEntityList.map(item => { //往比遍历到的对象中添加属性 Object.assign(item, { sourceType: item.businessType, }) });
map() 把每个元素通过函数传递到当前匹配集合中,生成包含返回值的新的 jQuery 对象。此用法与原生js的map循环用法一致。
哈哈哈哈,亲爱的同学们,是不是感觉好多啊,其实不要特意去记忆啊,个人建议吧原生for循环,forEach循环,还有Juery的each熟悉就可以啦!如果你再开发者发现这几个循环不好用的话,那就来我这里找找看,这15种循环中,绝对有你有需要的。
同学们,如果你觉得我的文章写的好,可关注博主微信公众号是:“Java深度编程”,“诗人与黑客”。也可关注作者,后续将继续更新中
三、最后加一种for...of循环的常用场景
for...of
语句创建一个循环来迭代可迭代的对象。在 ES6 中引入的 for...of
循环,以替代 for...in
和 forEach()
,并支持新的迭代协议。for...of
允许你遍历 Arrays(数组), Strings(字符串), Maps(映射), Sets(集合)等可迭代的数据结构等。
1. 数组迭代
for...of
最常见的应用是对数组项进行迭代。该循环可以高效得完成迭代,而无需其他变量来保持索引。
const array = ['Strawberry', 'Apple', 'Banana']; for (const value of array) { console.log(value); } // Strawberry // Apple // Banana
2. 遍历一个对象数组
var fruits = [{name:'Strawberry'},{name: 'Apple'},{ name:'Banana'}];
for (var {name} of fruits) {
console.log(name);
}
//Strawberry
//Apple
//Banana
3.迭代String
let iterable = "boo"; for (let value of iterable) { console.log(value); } // "b" // "o" // "o"
4.迭代Map
let iterable = new Map([["a", 1], ["b", 2], ["c", 3]]); for (let entry of iterable) { console.log(entry); } // ["a", 1] // ["b", 2] // ["c", 3] for (let [key, value] of iterable) { console.log(value); } // 1 // 2 // 3
5.迭代Set
let iterable = new Set([1, 1, 2, 2, 3, 3]); for (let value of iterable) { console.log(value); } // 1 // 2 // 3
6.迭代arguments对象
(function() { for (let argument of arguments) { console.log(argument); } })(1, 2, 3); // 1 // 2 // 3
//arguments
是函数体内的特殊变量,包含函数的所有参数,这是一个经典的类数组对象。
7.迭代DOM集合
迭代 DOM 元素集合,比如一个NodeList对象:下面的例子演示给每一个 article 标签内的 p 标签添加一个 "read
" 类。
//注意:这只能在实现了NodeList.prototype[Symbol.iterator]的平台上运行 let articleParagraphs = document.querySelectorAll("article > p"); for (let paragraph of articleParagraphs) { paragraph.classList.add("read"); }
学无止境,更多方法,建议去看看 MDN 文档 以寻找更好的方法。