從頭開始複習js之讓你不折不扣搞清楚數組

關於數組這一塊,從開始寫項目開始就一直在用,可是基本都沒有整理過,怎麼說呢?既然在複習這個東西,那我今天正好在複習這個數組,就集中整理一下在實際開發中用到頻率最高的數據吧。前端

1、 es5中的數組方法

es5中定義了22個數組的方法,這22個方法的使用頻率基本貫穿整個前端開發,若是你想進入前端,這22個應該成爲你的本能反應。下面就針對這22個,我來簡單作一下代碼的實例吧:es6

1.一、 數組定義

關於數組定義通常有兩種方式:數組

  • new字符
  • 數組字面量
  • 數組的清空

具體的定義以下:bash

var testArray = new Array();
var testArray1 = [1,2,3,4,5];
複製代碼

額,這裏重點提一下數組的清空,我建議使用:函數

var testArray = [];
複製代碼

1.二、 數組檢測

在es5裏面檢測數據類型是否是數組的方式主要有兩個,length主要用來獲取數組的長度:ui

  • instanceof:判斷構造函數
  • isArray
  • length:返回數據內元素的個數

具體的代碼以下:this

var array = [1,2,3,4,5];
var object = { key:1,value:"hello"};

console.log(array instanceof Array); // true
console.log(object instanceof Array); // false

console.log(Array.isArray(array)); // true
console.log(Array.isArray(object)); // false

console.log(array.length) // 5
複製代碼

1.三、 數組轉化成字符串

數據轉化成字符串通常有三種方式:編碼

  • toLocaleString
  • toString
  • join

來看下面一段代碼:es5

console.log(array.toString()); // 1,2,3,4,5
console.log(array.toLocaleString()); // 1,2,3,4,5
console.log(array.join("")); // 12345
console.log(array.join("&&")); // 1&&2&&3&&4&&5
console.log(array.join()); // 1,2,3,4,5
複製代碼

首先toStringtoLocaleString是將數組直接轉化成String,中間用逗號分隔。(到如今爲止我都不知道二者在Array中有什麼區別,我本身作實驗只在Date中發現了一點異常。)spa

其次是join:數組元素先被轉換爲字符串,再將這些字符串用 separator 分割鏈接在一塊兒。若是沒提供分隔符,將一個逗號用做分隔符。

1.四、 數組的添加和刪除

數組的增刪操做的屬性一共下面幾種:

  • push:在數組的最末尾添加元素
  • pop:在數據的最末尾刪除元素
  • unshift: 在數組的最前面添加一個元素
  • shift: 刪除數組的最前面一項

來看下面一段代碼:

var array = [1,2,3,4,5];
array.push(999); // [ 1, 2, 3, 4, 5, 999 ]
array.pop(); // [ 1, 2, 3, 4, 5 ]
array.unshift(999); // [ 999, 1, 2, 3, 4, 5 ]
array.shift(); // [ 1, 2, 3, 4, 5 ]
複製代碼

1.五、 數組的排序

關於數組的排序,主要有兩個方法:

  • reverse 翻轉數組
var array = [1,2,3,4,5];
array.reverse(); // [ 5, 4, 3, 2, 1 ]
複製代碼
  • sort //數組中按元素來排序,默認是按照首個字符的Unicode編碼排序,因此默認是從小到大排序。

sort方法接收兩個參數,第一個是數組,第二個參數若是存在,就會按照第二個函數的返回值來排序,若是不存在 缺省值是從小到大。來看下面一段代碼:

array.sort() // [ 1, 2, 3, 4, 5 ]

array.sort((a,b)=>{
	return b-a;
});
console.log(array); // [ 5, 4, 3, 2, 1 ]
複製代碼

關於數組的排序這一塊的源碼呢,以前我有看過一部分,我發現,在源碼中數組長度小於23的時候採用的是插入排序,反之則用的是快速排序。(甚至命名都是InsertionSort,QuickSort),關於排序的實現方式,能夠去看一下 我以前寫的排序的文章來複習一下,我以爲我本身寫的還比較好理解的。

1.六、 數組元素的裁剪/縫補

  • concat: 合併數組
var array1 = [1,2,3];
var array2 = ["1","2","3"];
console.log(array1.concat(array2)); // [1,2,3,"1","2","3"];
複製代碼
  • slice: 數組截取
var arr = [1, 2, 3, "a", "b", "c"];
console.log(arr.slice(3));      //["a", "b", "c"]
console.log(arr.slice(0,3));      // [1, 2, 3]
console.log(arr.slice(0,10));      // [1, 2, 3, "a", "b", "c"]
console.log(arr.slice(7,10));      //[]
console.log(arr.slice(-2));      // ["b", "c"]
console.log(arr.slice(3,0));      // []
console.log(arr); // 
複製代碼

這裏值得咱們注意的點是: 一、 slice默認接收兩個參數,slice(start,end),表示從開始截取的位置和截取結束的位置。 二、 若是隻填寫一個參數,是從該位置開始向後截取,直到末尾。 三、 若是隻填寫一個負數參數的話,是從末尾開始向前截取。 四、 若是第一個參數比後面大,返回值爲空數組。 五、 若是截取的開始位置大於數組長度返回空數組。 六、 若是截取的結束位置大於數組的長度,返回開始截取到數據的末尾的數列。

  • splice:數組的刪除,刪除,增長的數據

首先來看一個基礎的例子

var arr = [1, 2, 3, "a", "b", "c"];
arr.splice(2);// [ 1, 2 ]
arr.splice(0,1); // [2]
複製代碼

而後咱們再來看一個帶插入的例子:

var arr1 = [1, 2, 3, "a", "b", "c"];
arr1.splice(3,2,"hello","world");// [ 1, 2, 3, 'hello', 'world', 'c' ]
複製代碼

值得咱們注意的點是: 一、 splice的參數含義是:splice(開始操做的索引值,刪除幾項,後面的n項表明從開始操做的索引值開始插入的項) 二、 若是隻傳入一個參數,默認返回0到指定參數的值

1.七、 數組的查找

  • indexof/lastIndexOf,從數組的前/後查數據的索引 來看下面一個例子
var arr = [1, 2, 3, "a", "b", "c"];
console.log(arr.indexOf("b")); // 4
console.log(arr.lastIndexOf("b")); // 4
console.log(arr.indexOf("es")); // -1
複製代碼

這裏值得注意的是:indexOf是去查詢元素第一次出現的索引,而lastIndexOf是去查詢元素最後一次出現的索引。

  • every 若是數組內的每個元素都知足一個要求,就返回true
var arr = [ 1, 2, 3, 4, 5 ];

arr.every((item,index,array)=>{
	if(item>0) return true;
	return false;
}); //true

arr.every((item,index,array)=>{
	if(item>3) return true;
	return false;
}); // false
複製代碼

從上面的代碼,咱們能夠看出: 一、 every接收一個函數,函數的返回參數有三個,遍歷的項,當前遍歷的index和數組自己 二、 當函數的所有項都返回true的時候every才成立;有一項不返回true,every將不會成立。

  • some:若是數組內存在一個元素知足回調函數內的要求,就返回true 關於some能夠跟every作對比記憶。
var arr = [ 1, 2, 3, 4, 5 ];

arr.some((item,index,array)=>{
	if(item>4) return true;
	return false;
}); //true

arr.some((item,index,array)=>{
	if(item>7) return true;
	return false;
}); // false
複製代碼

從上面的代碼,咱們能夠看出 一、 some接收一個函數,函數的返回參數有三個,遍歷的項,當前遍歷的index和數組自己 二、 當函數的所有項都返回false的時候some就會返回false;有一項返回true,some都將成立。

  • filter:返回數組內知足回調函數的元素 一樣這個函數也能對比和上面兩個記憶。來看下面一段代碼。
var arr = [ 1, 2, 3, 4, 5 ];

arr.filter((item,index,array)=>{
	return item>3;
}); //[ 4, 5 ]
複製代碼

從上面能夠看出來,filter將會篩選出知足條件的數列出來。

  • forEach: 數組遍歷 這個就不作演示了,主要是遍歷,跟for同樣

1.八、 數組的重裝和合並

  • map:對於數組的每一項都用函數進行重組,若是不return,返回undefined 關於map方法,其實在開發中用到的真的特別多,來看下面一個例子:
var arr = [ 1, 2, 3, 4, 5 ];

arr.map((item,index,array)=>{
	if(item>3){
		return {key:"小於三的數",value:item}
	}
	return {key:"大於二的數",value:item}
}); 
//[ { key: '大於二的數', value: 1 },
// { key: '大於二的數', value: 2 },
// { key: '大於二的數', value: 3 },
// { key: '小於三的數', value: 4 },
// { key: '小於三的數', value: 5 } ]
複製代碼

從上面咱們能夠得出,map方法是將每一項的返回值從新組裝成一個新的數組,若是沒有return會返回。

  • reduce/reduceRight:從左/右開始對元素的累加。
var arr = [ 1, 2, 3, 4, 5 ];

var result1 = arr.reduce((sum,item)=>{
	return sum*10 + item;
});

var  result2 = arr.reduceRight((sum,item)=>{
	return sum*10 + item;
});

console.log(result1)
console.log(result2)
複製代碼

2、 es5後新增的數組方法

2.一、 數組的建立和初始化

關於from和of,其實可能遇到call和bind,能夠看看以前個人文章。

  • Array.from 咱們來看一組代碼:
var obj = {
	"0":"a",
	"1":"b",
	"2":"c",
	length: 3
}
var obj1 = {
	"0":"a",
	"1":"b",
	"2":"c",
}
var obj2 = {
	"a":"a",
	"b":"b",
	"c":"c",
	length: 3
}

console.log(Array.from(obj)); // [ 'a', 'b', 'c' ]
console.log(Array.from(obj1)); // []
console.log(Array.from(obj2)); // [ undefined, undefined, undefined ]
複製代碼

從上面的代碼,咱們能夠清楚的發現: 一、 Array.from是須要length屬性的,若是沒有length屬性,將返回空數組 二、 Array.from操做對象的屬性名必定是數字,否則會返回undefined。

  • Array.of

Array.of主要用於將一組值轉化成數組

Array.of(3, 11, 8) // [3,11,8]
Array.of(3) // [3]
Array.of(3).length // 1
複製代碼

Array.of的建立主要是爲了彌補Array方法的一些小漏洞,例如:

Array() // []
Array(3) // [, , ,]
Array(3, 11, 8) // [3, 11, 8]
複製代碼
  • fill

fill方法的做用是,將給的定值填充到數組中,來看下面一組代碼:

['a', 'b', 'c'].fill(7);  // [7, 7, 7]
new Array(3).fill(7)  // [7, 7, 7]
['a', 'b', 'c'].fill(7, 1, 2) // ['a', 7, 'c']
let arr = new Array(3).fill({name: "jkb"});
arr[0].name = "klivitam";
console.log(arr); // [{name: "klivitam"}, {name: "klivitam"}, {name: "klivitam"}]
複製代碼

從上面的代碼咱們能夠發現: 一、 fill接收三個參數,fill(填充的值,填充的開始值,填充的結束值) 二、當只存在一個參數時,默認將所有數組都填充給列表項 三、 當填充的值是對象的時候,咱們是填充的對象的指針,因此這是一個坑 在用的時候請謹慎哦。

2.二、 數組的查找

  • find/findIndex
let data = [1,2,3,4,5];
let obj = {
   name:"klivitam",
   number:1
}
let result1 =  data.find((it,index,arr)=>{
   return it>3;
})
let result2 = data.findIndex((it,index,arr)=>{
   return it>3;
})
let result3 =  data.find((it,index,arr)=>{
   return it>10;
})
let result4 = data.find(function(v){
   return v>this.number;
},obj)
console.log(result1) // 4
console.log(result2) // 3
console.log(result3) // undefined
console.log(result4) // 2
複製代碼

從面的代碼咱們能夠發現: 一、 find和findIndex分別都接收兩個參數,第一個是函數,第二個是對象,前一個函數的this指針指向後一個對象 二、 find和findIndex只能發現數組內出現的第一個值,若是沒有發現返回undefined

  • includes
let data = [1,2,3,4,5,NaN];

console.log(data.includes(1)); // true
console.log(data.includes(1,2)) // false
console.log(data.includes(NaN)) // true
console.log(data.indexOf(NaN)) // -1
複製代碼

從面的代碼咱們就能夠清楚的發現: 一、 includes方法接收兩個參數,第一個是搜索的值,第二個是從數據的第幾項開始搜索 二、 indexOf沒法查找到NaN的位置,可是includes能夠。

  • entries/keys/values
let data = [1,2,3];
for (let index of data.keys()) {
  console.log(index);
}
// 0
// 1
// 2

for (let elem of data.values()) {
  console.log(elem);
}
// 1
// 2
// 3

//這裏使用瞭解構賦值
for (let [index, elem] of data.entries()) {
  console.log(index, elem);
}
// 0 1
// 1 2
// 2 3
複製代碼

2.二、 數組的操做

  • 擴展運算符 擴展運算符(spread)是三個點(...)。它將一個數組轉爲用逗號分隔的參數序列。具體的事例代碼以下:
console.log(...[1, 2, 3]); // 1,2,3
console.log((...[1, 2,3])); // Uncaught SyntaxError: Unexpected number
Math.max(...[14, 3, 77]) // 77
const [...[1,2,3]] = a1;  // 1,2,3
[...['a', 'b'], ...['c'], ...['d', 'e']]; // [a,b,c,d,e]
[...'hello'];// [h,e,l,l,0]
複製代碼

關於擴展運算符這一塊,我不想過多的來說解,其實不少東西 仍是要靠本身在寫代碼的時候來總結,關於有些技術,我也不知道哪裏好,可是遇到問題了 我就想用。

  • copyWithin
[1, 2, 3, 4, 5].copyWithin(0, 3); // [4, 5, 3, 4, 5]
// 將3號位複製到0號位
[1, 2, 3, 4, 5].copyWithin(0, 3, 4) // [4, 2, 3, 4, 5]

[1, 2, 3, 4, 5].copyWithin(0, -2, -1); // [4, 2, 3, 4, 5]

[].copyWithin.call({length: 5, 3: 1}, 0, 3)// {0: 1, 3: 1, length: 5}
複製代碼

從上面的代碼咱們能夠發現: 一、 數組實例的copyWithin方法,在當前數組內部,將指定位置的成員複製到其餘位置(會覆蓋原有成員),而後返回當前數組。也就是說,使用這個方法,會修改當前數組。 二、 該方法接受三個參數,分別是從該位置開始替換數據,從該位置開始讀取數據,到該位置前中止讀取數據。

  • flat/flatMap
[1, 2, [3, 4]].flat(); // [1, 2, 3, 4]

[1, 2, [3, [4, 5]]].flat(); // [1, 2, 3, [4, 5]]

[1, 2, [3, [4, 5]]].flat(2); // [1, 2, 3, 4, 5]

[1, [2, [3]]].flat(Infinity)// [1, 2, 3]

[1, 2, , 4, 5].flat() // [1, 2, 4, 5]

[2, 3, 4].flatMap((x) => [x, x * 2])// [2, 4, 3, 6, 4, 8]
複製代碼

從上面的代碼咱們能夠發現:

  • flat的做用是:用於將嵌套的數組「拉平」,變成一維的數組。flapmap的做用是首先將元素進行一次map方法,而後再進行一次flat方法。
  • flat方法接受一個參數,表明拉伸的層數,也能夠用Infinity,拉平全部的嵌套數組
  • flat再拉平數組的時候,而後遇到空位會跳過該空位

3、數組的空位

前面在講解flat的時候,咱們提到了一個空位的概念,結合開發以及阮大神在博客中的總結,我也更深的瞭解到空位的差別。 首先咱們來看一段代碼:

[,'a'].forEach((x,i) => console.log(i)); // 1
['a',,'b'].filter(x => true) // ['a','b']
[,'a'].every(x => x==='a') // true
[1,,2].reduce((x,y) => x+y) // 3
[,'a'].some(x => x !== 'a') // false
[,'a'].map(x => 1) // [,1]
[,'a',undefined,null].join('#') // "#a##"
[,'a',undefined,null].toString() // ",a,,"
複製代碼

這裏咱們就能夠明顯的看到在es5中對空格的處理方法就已經出現了分歧。

  • forEach(), filter(), reduce(), every() 和some()都會跳過空位。
  • map()會跳過空位,但會保留這個值
  • join()和toString()會將空位視爲undefined,而undefined和null會被處理成空字符串。

那咱們來看es6呢?來看下面一段代碼:

Array.from(['a',,'b'])// [ "a", undefined, "b" ]
[...['a',,'b']] // [ "a", undefined, "b" ]
[,'a','b',,].copyWithin(2,0) // [,"a",,"a"]
new Array(3).fill('a') // ["a","a","a"]
let arr = [, ,];
for (let i of arr) {
  console.log(1);
}
// 1
// 1
[...[,'a'].entries()] // [[0,undefined], [1,"a"]]
[...[,'a'].keys()] // [0,1]
[...[,'a'].values()] // [undefined,"a"]
[,'a'].find(x => true) // undefined
[,'a'].findIndex(x => true) // 0
複製代碼

從上面代碼咱們能夠發現:

  • Array.from、擴展運算符、entries()、keys()、values()、find()和findIndex()方法會將數組的空位,轉爲undefined
  • fill()會將空位視爲正常的數組位置。
  • copyWithin()會連空位一塊兒拷貝。
  • 上面代碼中,數組arr有兩個空位,for...of並無忽略它們。若是改爲map方法遍歷,空位是會跳過的。

其實用代碼演示了這麼多,無非就是想說明一件道理:空位不一樣的方法對其的處理方式不一樣 若是你可以記得全部方法的處理方式,那你大能夠任意使用 若是不行 仍是儘可能避免出現空位吧

說在最後

這篇文章寫的我非常煩躁呀,主要總結下來東西實在是太多了,可是怎麼說呢?仍是有很大的好處的,好比數組的空位這個以前我就只知道基礎的幾種,剩下的 我基本都沒有去驗證,如今抽時間把這些東西所有驗證了一遍感受印象也加深了很多。好了 差很少一點鐘了,去睡覺了 (說好的從這周起開始睡美容覺的)

相關文章
相關標籤/搜索