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 ( ) 造成比較