javascript里面有关遍历的方法有多种,这里我就总结一下,使可以直观的了解每种方法是怎么使用的。不论是前端仍是后端都会涉及到对数据的处理。通常来讲,数据常常会以数组或者对象的形式存放在数据库中,这就意味着咱们常常要对数组或者对象进行操做,而对数组或者对象进行操做,遍历必然少不了。下面在介绍遍历的方法以前,我会先介绍一下数据类型以及内存模型等一些相关的知识。javascript
ECMAScript
的数据类型分为:前端
基本数据类型(Number
,String
,Boolean
,Undefined
,Null
,Symbol(ES6)
)java
引用数据类型(Object
,Array
,Function
,RegExp
,Date
,Error
)程序员
两种数据类型的区别:存储位置不一样es6
栈(stack):一种先进后出的数据结构,由操做系统(编译器)自动分配,释放的内存空间。算法
堆(heap):一种树形数据结构,通常由程序员分配(经过new
关键字),释放的动态内存空间, 若程序员不释放,程序结束后由系统虚拟机的垃圾回收算法来决定是否回收。数据库
内存模型与语言有关系json
栈区:存放es5中基本数据类型、引用数据类型的引用后端
堆区:存放数组,对象等引用数据类型自己数组
变量区:五种数据类型数据自己
代码区:函数体的二进制代码
注意:
栈区对应着堆区,变量区,代码区这三个区,他们数据的引用均存放在栈区中。
栈区存放的是空间小,大小固定的,频繁被使用的数据,读取速度快。
堆区存放的是空间大,大小不固定的数据,若是这些数据存放在栈区将影响程序的性能。
引用数据类型的指针存在栈区,该指针指向堆区该实体的起始地址,当解释器寻找引用值时,会首先检索其
在栈中的地址,取得地址后从堆中得到实体。
//es6的变量声明
let num = 111;
复制代码
执行这段代码会通过这些过程
1.建立惟一标识符 num
2.在内存变量区分配一个空间,并将该空间的地址0034HHH(假设)存在栈区
3.在变量区分配的空间里存一个值111
咱们认为标识符num
等于地址0034HHH,这个地址的空间里保存着一个值111
如今执行下面代码
let num = 111;
num = num+1;
console.log(num);//112
复制代码
在这个过程最后打印的num
的地址是否仍是0034HHH,而保存的值是112?并非的
执行let num=num+1
的时候,系统从新分配了一个空间,而且num
等于这个新空间的地址(0064HBC),新的空间保存的值为112
注意:在es6
里面,与let
不一样的是,const
声明的常量,其地址是不会变的,所以不容许从新赋值且必须赋初始值
Array
在Javascrip
t 中是一个对象,与其余语言的Array
是有区别的。在JavaScript
中 Array
的索引是属性名。Javascript
中的 Array
在内存上并不连续,其次, Array
的索引并非指偏移量。实际上, Array
的索引也不是 Number
类型,而是String
类型的。咱们能够正确使用如arr[0]
的写法的缘由是语言能够自动将Number
类型的 0 转换成 String
类型的 “0″ 。因此,在Javascript
中历来就没有 Array
的索引,而只有相似 “0″ 、 “1″ 等等的属性。每一个 Array
对象都有一个 length
的属性,这一点与其余语言的Array
很像,可是length
属于不可枚举属性,实际上, Array
对象还有许多其余不可枚举的属性。
关于JavaScript
中的对象,我以前的文章js对象与对象原型中有详细的介绍
1.typeof
用于检查数据类型,其返回值为字符串类型,返回值有number
,string
,undefined
,function
,object
须要特别注意的是:typeof(NAN)-->undefined
,typeof([],{},null)-->object
2.instanceof
用于判断一个实例对象是否是由这个构造函数实例化出来的,若是是,则返回true
,不然返回false
,如:p instanceof Person
3.原型中的构造器
若是p._proto_.constructor==Person.prototype.constructor
,说明实例对象p
是由构造函数Person
实例化出来的
4.toString.call(value)
鉴于typeof
用于判断数据类型的局限性,toString.call()
能够准确的判断数据类型
在实际的项目中,会有这样的需求,从接口获取到的数组或者对象格式的数据须要经过遍历,而且在遍历的过程作一些操做去改变原来的值,可是有的状况下就仅仅是简单的遍历而已。那么这里涉及到什么样的操做才会改变原数组或者对象的值呢?
下面,咱们先来看看两个对比的例子
//操做一
var arr=[1,2,3];
for(var i=0,len=arr.length;i<len;i++){
arr[i]*2;
}
console.log(arr);//(3) [1, 2, 3]
复制代码
以上操做,原来数组的值并无变化
//操做二
var arr=[1,2,3];
for(var i=0,len=arr.length;i<len;i++){
arr[i]=arr[i]*2;//经过引用从新赋值
}
console.log(arr);//(3) [2, 4, 6]
复制代码
以上操做发现,原来数组的值改变了,这是为何?上面我有介绍过基本数据类型的声明与赋值过程,能够发现值的改变很大程度实际上是地址的改变,上面经过引用从新赋值,因此原数组的值改变了。
json={
name:'xiaoming',
sex:'男',
age:22
}
json.age=json.age+1;
console.log(json);//{name: "xiaoming", sex: "男", age: 23}
复制代码
以上操做发现,对象 json 的 age 的值被改变了,不论是数组仍是对象,都是经过索引或者键值对中的键来找到相应的值的,而索引或者键就是引用也就是地址,因此不论是数组仍是对象,值的改变操做必定要涉及到地址的改变,原来的值才会被改变。
做用:for循环是最基础的遍历方法,通常用来遍历数组,单纯的遍历,不会改变原数组的值
var arr = [1, 2, 3];
for(var i = 0, len = arr.length; i < len; i++) {
console.log(typeof i)//number
console.log(arr[i]);//1 2 3
}
console.log(arr);//(3)[1,2,3]
复制代码
注意:
i 是索引,number 类型
为了不遍历过程重复获取数组长度,应使用临时变量,将长度缓存起来
没有返回值
若是在遍历的过程从新赋值,那必然是会改变数组原来的值的
var arr = [1, 2, 3];
for(var i = 0, len = arr.length; i < len; i++) {
arr[i]=arr[i]*2;
}
console.log(arr);//(3)[2,4,6]
复制代码
做用:for in 能够遍历数组,对象的属性,也能遍历原型链上的属性(最后遍历),i
为string
类型
在JavaScript中,数组中的索引,相似 “0″ 、 “1″ 等等的属性
var arr=['h','e','l','l','o'];
for(var i in arr){
console.log(typeof i)//string
console.log(arr[i]);//h e l l o
}
console.log(arr);//(5)['h','e','l','l','o']
复制代码
注意:
i 为索引(属性),string 类型
若是在遍历过程从新对数组进行赋值,也是会改变数组原来的值的
const arr = [1, 2, 3];
for(var i = 0, len = arr.length; i < len; i++) {
arr[i]=arr[i]*2;
}
console.log(arr);//(3)[2,4,6]
复制代码
若是原来的数组扩展了私有属性,那么会在最后把数组的私有属性遍历出来,基于这一点,通常不会使用 for in 来遍历数组
var arr=['h','e','l','l','o'];
arr.a='world';//扩展私有属性
for(var i in arr){
console.log(arr[i]);
}
console.log(arr);//(5) ["h", "e", "l", "l", "o", a: "world"]
复制代码
json={
name:'xiaoming',
sex:'男',
age:22
}
for(var i in json){
console.log(json[i]);//xiaoming 男 22
}
console.log(json);//{name: "xiaoming", sex: "男", age: 22}
复制代码
注意:
i 为属性,string类型
for in 会将对象的属性遍历出来
若是在遍历的过程从新赋值,会改变原来的值
json={
name:'xiaoming',
sex:'男',
age:22
}
for(var i in json){
json[i]=json[i]+'1111';
}
console.log(json);//{name: "xiaoming111", sex: "男111", age: 22111}
复制代码
若是在对象原型上添加属性,会在最后遍历出来
function Person(name,age) {
this.name=name;
this.age=age;
}
//经过原型添加属性
Person.prototype.sex='男'
var p=new Person("小明",20);
for(var i in p){
console.log(p[i]);//小明 20 男
}
console.log(p);//Person {name: "小明", age: 20}
复制代码
做用:for of 通常与 for in 造成对比,功能与 for in 相似,可是不能用来遍历对象
var arr=[1,2,3];
//for in 遍历数组
for(let i in a){
console.log(i);//0 1 2
console.log(a[i]);//1 2 3
}
//for of 遍历数组
var arr=[1,2,3];
for(let i of arr){
console.log(i);//1 2 3
}
复制代码
注意:
做用:forEach ( ) 方法用于调用数组的每一个元素,并将元素传递给回调函数,回调函数一个有三个参数。
语法:array.forEach(function(item, index, arr), thisValue)
参数:
参数 | 描述 |
---|---|
item | 必需,当前元素 |
index | 可选,当前元素的索引值 |
arr | 可选,当前元素所属的数组对象 |
thisValue | 可选,传递给函数的值通常用 "this" 值,若是这个参数为空, "undefined" 会传递给 "this" 值 |
var arr=['a','b','c','d'];
arr.forEach(function(item,index,arr){
console.log(item,index);
//a,0
//b,1
//c,2
//d,3
});
console.log(arr);//(4) ["a", "b", "c", "d"]
复制代码
注意:
forEach( ) 没有返回值,对 return 不起做用
回调函数内部不能有break,continue的,不然会报错的
遍历过程不必定会改变原数组的值,具体要看是否涉及到地址的操做
var arr=[1,2,3];
arr.forEach(item => {
item = item * 2;//未涉及地址操做
})
console.log(arr);//(3) [1,2,3]
复制代码
var arr=[1,2,3];
arr.forEach((item,index) => {
arr[index] = item * 2;//涉及地址操做
})
console.log(arr);//(3) [2, 4, 6]
复制代码
var arr = [
{name:'xiaoming',age:16},
{name:'zhangsan',age:17}
];
arr.forEach(item => {
item.age = item.age + 1;//涉及地址操做
});
console.log(arr);//(2) [{name:'xiaoming,age:17'}, {name:'zhangsan',age:'18'}]
复制代码
做用:map ( ) 方法按照原始数组元素顺序依次处理元素,返回一个新数组,新数组中的元素为原始数组元素调用函数处理后的值
语法:array.map(function(item,index,arr ), thisValue)
参数:
参数 | 描述 |
---|---|
item | 必须,当前元素的值 |
index | 可选,当前元素的索引值 |
arr | 可选,当前元素属于的数组对象 |
thisvalue | 可选,对象做为该执行回调时使用,传递给函数,用做 "this" 的值。若是省略了 thisValue,或者传入 null、undefined,那么回调函数的 this 为全局对象。 |
var arr = [1,2,3];
var temp=arr.map((item,index)=>{
console.log(item,index);
//1 0
//2 1
//3 2
})
console.log(temp);//(3) [undefined, undefined, undefined]
console.log(arr);//(3)[1,2,3]
复制代码
var arr = [1,2,3];
var temp=arr.map(item=>{
return item*2;
})
console.log(temp);//(3) [2, 4, 6]
console.log(arr);//(3) [1, 2, 3]
复制代码
注意:
map( ) 不会对空数组进行检测
map( ) 不会改变原始数组
每一个元素都会执行相应的回调函数,必需要有返回值,不然结果为 undefined
var arr = [10,2,5,22,65,44,32];
var temp=arr.map((item,index)=>{
console.log(item);//10,2,5,22,65,44,32
if(item>30){
return item;
}
})
console.log(temp);//(7) [undefined, undefined, undefined, undefined, 65, 44, 32]
console.log(arr);//(7) [10, 2, 5, 22, 65, 44, 32]
复制代码
做用:filter() 是个过滤器,该方法建立一个新的数组,新数组中的元素是经过检查原数组中符合条件的全部元素。
语法:array.filter(function(item,index,arr), thisValue)
参数:
参数 | 描述 |
---|---|
item | 必需,当前元素 |
index | 可选,当前元素的索引值 |
arr | 可选,当前元素所属的数组对象 |
thisValue | 可选,传递给函数的值通常用 "this" 值,若是这个参数为空, "undefined" 会传递给 "this" 值 |
var arr = [1,2,3];
var temp=arr.filter((item,index)=>{
console.log(item,index);
//1 0
//2 1
//3 2
})
console.log(temp);//(3) []
console.log(arr);//(3)[1,2,3]
复制代码
var arr = [1,2,30,11,3];
var temp=arr.filter((item)=>{
console.log(item);//1,2,30,11,3
return item>10
})
console.log(temp);//(2) [30, 11]
console.log(arr);//(5) [1, 2, 30, 11, 3]
复制代码
//数组去重
var arr=['apple','pear','apple','banana'];
var r=arr.filter(function(item,index,self){
return self.indexOf(item)===index;
})
复制代码
注意:
做用:find() 方法返回知足回调条件的指定数组的第一个元素的值,数组中的元素依次执行回调函数,当数组中的元素知足条件时, find() 返回符合条件的元素,以后的元素再也不执行函数,若是都没有符合条件的元素返回 undefined
语法:array.find(function(item, index, arr),thisValue)
参数:
参数 | 描述 |
---|---|
item | 必需,当前元素 |
index | 可选,当前元素的索引值 |
arr | 可选,当前元素所属的数组对象 |
thisValue | 可选,传递给函数的值通常用 "this" 值,若是这个参数为空, "undefined" 会传递给 "this" 值 |
var arr = [1,2,3];
var temp=arr.findIndex((item,index)=>{
console.log(item,index);
//1 0
//2 1
//3 2
})
console.log(temp);//undefined
console.log(arr);//(3)[1,2,3]
复制代码
var arr = [1,2,30,11,3];
var temp=arr.find((item)=>{
console.log(item);//1,2,30
return item>10
})
console.log(temp);//30
console.log(arr);//(5) [1, 2, 30, 11, 3]
复制代码
var arr = [1,2,30,11,3];
var temp=arr.find((item)=>{
console.log(item);//1,2,30,11,3
return item>100
})
console.log(temp);//undefined
console.log(arr);//(5) [1, 2, 30, 11, 3]
复制代码
注意:
做用:findIndex() 方法返回知足回调函数条件的指定数组的第一个元素的索引,没有符合条件则返回-1。
语法:array.findIndex(function(item, index, arr), thisValue)
参数:
参数 | 描述 |
---|---|
item | 必需,当前元素 |
index | 可选,当前元素的索引值 |
arr | 可选,当前元素所属的数组对象 |
thisValue | 可选,传递给函数的值通常用 "this" 值,若是这个参数为空, "undefined" 会传递给 "this" 值 |
var arr = [1,2,3];
var temp=arr.findIndex((item,index)=>{
console.log(item,index);
//1 0
//2 1
//3 2
})
console.log(temp);//-1
console.log(arr);//(3)[1,2,3]
复制代码
var arr = [1,2,30,11,3];
var temp=arr.findIndex((item)=>{
console.log(item);//1,2,30
return item>10
})
console.log(temp);//2
console.log(arr);//(5) [1, 2, 30, 11, 3]
复制代码
注意:
findIndex() 不会对空数组进行检测
findIndex() 不会改变原始数组
并非数组中全部的元素都执行回调函数,当数组中的元素一旦知足条件时, findIndex() 返回符合条件的元素的索引,以后的元素不会再执行回调函数
做用:some() 方法用于检测数组中的元素是否知足指定条件,会依次执行数组的每一个元素,若是有一个元素知足条件,则表达式返回 true , 剩余的元素不会再执行检测,若是没有知足条件的元素,则返回false
语法:array.some(function(item,index,arr),thisValue)
参数:
参数 | 描述 |
---|---|
item | 必需,当前元素 |
index | 可选,当前元素的索引值 |
arr | 可选,当前元素所属的数组对象 |
thisValue | 可选,传递给函数的值通常用 "this" 值,若是这个参数为空, "undefined" 会传递给 "this" 值 |
var arr = [1,2,3];
var temp=arr.some((item,index)=>{
console.log(item,index);
//1 0
//2 1
//3 2
})
console.log(temp);//false
console.log(arr);//(3)[1,2,3]
复制代码
var arr = [1,2,30,11,3];
var temp=arr.some((item)=>{
console.log(item);//1,2,30
return item>10
})
console.log(temp);//true
console.log(arr);//(5) [1, 2, 30, 11, 3]
复制代码
注意:
some ( ) 不会对空数组进行检测
some ( ) 不会改变原始数组
并非数组中全部的元素都执行回调函数,当数组中的元素一旦知足条件时,结果返回 true,以后的元素再也不执行了
做用:every() 方法用于检测数组全部元素是否都符合指定条件,会依次执行数组中的每一个元素,若是数组中检测到有一个元素不知足,则整个表达式返回 false ,且剩余的元素不会再进行检测,只有全部元素都知足条件,则返回 true
语法:array.every(function(item,index,arr), thisValue)
参数:
参数 | 描述 |
---|---|
item | 必需,当前元素 |
index | 可选,当前元素的索引值 |
arr | 可选,当前元素所属的数组对象 |
thisValue | 可选,传递给函数的值通常用 "this" 值,若是这个参数为空, "undefined" 会传递给 "this" 值 |
var arr = [1,2,3];
var temp=arr.every((item,index)=>{
console.log(item,index);//1 0
})
console.log(temp);//false
console.log(arr);//(3)[1,2,3]
复制代码
var arr = [1,2,30,11,3];
var temp=arr.every((item)=>{
console.log(item);//1,2,30,11,3
return item>0
})
console.log(temp);//true
console.log(arr);//(5) [1, 2, 30, 11, 3]
复制代码
注意:
every ( ) 不会对空数组进行检测
every ( ) 不会改变原始数组
every ( ) 与 some ( ) 造成比较