人生不过一场绚烂循环

栏目: JavaScript · 发布时间: 7年前

内容简介:在某个秘密的季节,青春逝去,不复重来。或许它只是残留在清澈阳光下的某一个不经意的思绪碎片,但它依然能让我们的眼睛里泛出淡淡的光来。额,不好意思,走错片场了,今日不谈李易安,且论循环。本文讲的是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()循环有返回值。

四丶参考资料


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Algorithms + Data Structures = Programs

Algorithms + Data Structures = Programs

Niklaus Wirth / Prentice Hall / 1975-11-11 / GBP 84.95

It might seem completely dated with all its examples written in the now outmoded Pascal programming language (well, unless you are one of those Delphi zealot trying to resist to the Java/.NET dominanc......一起来看看 《Algorithms + Data Structures = Programs》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具