數組html
數組是值的有序集合,每一個值叫作一個元素,而每一個元素在數組中有一個位置,以數字表示,稱爲索引。前端
JavaScript數組的索引是基於零的32位數值,第一個元素索引爲0,數組最大能容納4294967295(即2^32-1)個元素。web
JavaScript數組是動態的,根據須要它們會增加或縮減,而且在建立數組時無需聲明一個固定的大小或者在數組大小變化時無需從新分配空間。編程
JavaScript數組多是稀疏的,數組元素的索引不必定要連續的,它們之間能夠有空缺。設計模式
每一個JavaScript數組都有一個length屬性,針對非稀疏數組,該屬性就是數組元素的個數。針對稀疏數組,length比全部元素的索引都要大。數組
建立數組 一、最簡單的方法是使用數組直接量(字面量)建立數組。瀏覽器
var empty = []; //沒有元素的數組
var arr = [1.1, true, "a",]; //3個不一樣類型的元素和結尾的逗號
複製代碼
數組直接量中的值也不必定必須是常量,它們能夠是任意的表達式:緩存
var number = 1;
var list = [number, number+1, number+2];
複製代碼
若是省略數組直接量中的某個值,省略的元素用empty表示(就是沒有這個元素),訪問的話會返回undefined。bash
var count = [1,,3]; // 數組打印出來是(3) [1, empty, 3], count[1] === undefined是true。
var undefs = [,,]; // 數組直接量語法容許有可選的結尾的逗號,顧[,,]只有兩個元素而非三個,undefs.length 是 2
複製代碼
二、構造函數Array()建立數組 調用時沒有參數,等同於[],建立一個沒有任何元素的空數組數據結構
var arr = new Array();
複製代碼
調用時有一個數值參數,它指定長度
var arr = new Array(10) // (10) [empty × 10]
複製代碼
顯式指定兩個或者多個數組元素或者數組元素的一個非數值元素
var arr = new Array(1,2,3,"one");
複製代碼
三、ES6的一些方法 (1)Array.of() 返回由全部參數組成的數組,不考慮參數的數量或類型,若是沒有參數就返回一個空數組 (ES6新增)
參數:
elementN 任意個參數,將按順序成爲返回數組中的元素。
注意:
of() 能夠解決上述構造器因參數個數不一樣,致使的行爲有差別的問題(參數只有一個數值時,構造函數會把它當成數組的長度)。
Array.of(1,2,3); // [1,2,3]
Array.of(1,{a:1},null,undefined) // [1, {a:1}, null, undefined]
// 只有一個數值參數時
let B = new Array(3); // (3) [empty × 3]
let C = Array.of(3); // [3]
複製代碼
返回值: 新的 Array 實例。
(2)Array.from()從一個類數組或可迭代對象中建立一個新的數組 (ES6新增)
參數:
第一個參數:想要轉換成數組的類數組或可迭代對象 第二個參數(可選):回調函數,相似數組的map方法,對每一個元素進行處理,將處理後的值放入返回的數組。 第三個參數(可選):綁定回調函數的this對象
// 有length屬性的類數組
Array.from({length:5},(v,i) => i) //[0, 1, 2, 3, 4]
// 部署了Iterator接口的數據結構 好比:字符串、Set、NodeList對象
Array.from('hello') // ['h','e','l','l','o']
Array.from(new Set(['a','b'])) // ['a','b']
// 傳入一個數組生成的是一個新的數組,引用不一樣,修改新數組不會改變原數組
let arr1 = [1,2,3]
let arr2 = Array.from(arr);
arr2[1] = 4;
console.log(arr1,arr2)
//[1, 2, 3] [1, 4, 3]
複製代碼
返回值: 新的 Array 實例。
知識點
//數組合並去重
function combine(){
let arr = [].concat.apply([], arguments); //沒有去重複的新數組,以後用Set數據結構的特性來去重
return Array.from(new Set(arr));
}
var m = [1, 2, 2], n = [2,3,3];
console.log(combine(m,n));
複製代碼
數組方法
一、會改變原數組的方法
let arr = [1,2,3];
let length = arr.push('末尾1','末尾2'); // 返回數組長度
console.log(arr,length)
// [1, 2, 3, "末尾1", "末尾2"] 5
複製代碼
返回值: 數組的長度
//組合使用push()和pop()可以用JavaScript數組實現先進後出的棧
let stack = [];
stack.push(1,2) // 返回長度2,這時stack的值是[1,2]
stack.pop() // 返回刪除的值2,這時stack的值是[1]
複製代碼
返回值: 從數組中刪除的元素(當數組爲空時返回undefined)。
let arr = [3,4,5];
let length = arr.unshift(1,2); // 返回長度是5
console.log(arr, length)
//[1, 2, 3, 4, 5] 5
複製代碼
注意: 當調用unshift()添加多個參數時,參數時一次性插入的,而非一次一個地插入。就像是上例添加1和2,他們插入到數組中的順序跟參數列表中的順序一致,而不是[2,1,3,4,5]。
返回值: 返回數組新的長度。
let arr = [1,2,3];
let item = arr.shift(); // 返回刪除的值1
console.log(arr, item)
// [2, 3] 1
複製代碼
返回值: 從數組中刪除的元素; 若是數組爲空則返回undefined 。
參數:
start
指定修改的開始位置(從0計數)。若是超出了數組的長度,則從數組末尾開始添加內容;若是是負值,則表示從數組末位開始的第幾位(從-1計數);若只使用start參數而不使用deleteCount、item,如:array.splice(start) ,表示刪除[start,end]的元素。
deleteCount (可選)
整數,表示要移除的數組元素的個數。若是 deleteCount 是 0,則不移除元素。這種狀況下,至少應添加一個新元素。若是 deleteCount 大於start 以後的元素的總數,則從 start 後面的元素都將被刪除(含第 start 位)。 若是deleteCount被省略,則其至關於(arr.length - start)。
item1, item2, ... (可選)
要添加進數組的元素,從start 位置開始。若是不指定,則 splice() 將只刪除數組元素。
返回值: 由被刪除的元素組成的一個數組。若是隻刪除了一個元素,則返回只包含一個元素的數組。若是沒有刪除元素,則返回空數組。
// start不超過數組長度(如下操做是連續的)
let arr = [1,2,3,4,5];
arr.splice(2) // arr是[1,2],返回值是[3,4,5]
arr.splice(1,1) // arr是[1],返回值是[2]
arr.splice(0,3) // arr是[],返回值是[1],由於此時數組從第0位開始不夠3位,因此是刪除從0開始到最後的全部元素。
// start大於數組長度(如下操做是連續的)
let arr = [1,2,3,4,5];
arr.splice(5) // arr是[1,2,3,4,5],返回值是[]
arr.splice(5,3,6) // arr是[1,2,3,4,5,6],返回值是[]
arr.splice(5,3,7) // arr是[1,2,3,4,5,7] 返回值是[6]
// start是負數(如下操做是連續的)
let arr = [1,2,3,4,5];
arr.splice(-3,2); // arr是[1,2,5], 返回值是[3,4]
arr.splice(-4); // arr是[],返回值是[1,2,5]
// 插入數組時,是插入數組自己,而不是數組元素
let arr = [1,4,5];
arr.splice(1,0,[2,3]) // arr是[1,[2,3],4,5],返回值是[]
複製代碼
compareFunction (可選) 用來指定按某種順序進行排列的函數。若是省略,元素按照轉換爲的字符串的各個字符的Unicode位點進行排序。 若是指明瞭 compareFunction ,那麼數組會按照調用該函數的返回值排序。即 a 和 b 是兩個將要被比較的元素:
若是 compareFunction(a, b) 小於 0 ,那麼 a 會被排列到 b 以前; 若是 compareFunction(a, b) 等於 0 , a 和 b 的相對位置不變。備註: ECMAScript 標準並不保證這一行爲,並且也不是全部瀏覽器都會遵照(例如 Mozilla 在 2003 年以前的版本); 若是 compareFunction(a, b) 大於 0 , b 會被排列到 a 以前。 compareFunction(a, b) 必須老是對相同的輸入返回相同的比較結果,不然排序的結果將是不肯定的。
var stringArray = ["Blue", "Humpback", "Beluga"];
var numberArray = [40, 1, 5, 200];
function compareNumbers(a, b){
return a - b;
}
console.log('stringArray:' + stringArray.join());
console.log('Sorted:' + stringArray.sort());
console.log('numberArray:' + numberArray.join());
// 沒有使用比較函數時,數字並不會按照咱們設想的那樣排序
console.log('Sorted without a compare function:'+ numberArray.sort());
console.log('Sorted with compareNumbers:'+ numberArray.sort(compareNumbers));
//打印以下
// stringArray: Blue,Humpback,Beluga
// Sorted: Beluga,Blue,Humpback
// numberArray: 40,1,5,200
// Sorted without a compare function: 1,200,40,5
// Sorted with compareNumbers: 1,5,40,200
複製代碼
返回值: 返回排序後的數組。原數組已經被排序後的數組代替。
let arr = [1,2,3];
arr.reverse() // arr是[3,2,1],返回值是[3,2,1]
複製代碼
返回值: 返回順序顛倒後的數組。原數組已經被排序後的數組代替。
參數:
target
0 爲基底的索引,複製序列到該位置。若是是負數,target 將從末尾開始計算。
若是 target 大於等於 arr.length,將會不發生拷貝。若是 target 在 start 以後,複製的序列將被修改以符合 arr.length。
start
0 爲基底的索引,開始複製元素的起始位置。若是是負數,start 將從末尾開始計算。
若是 start 被忽略,copyWithin 將會從0開始複製。
end
0 爲基底的索引,開始複製元素的結束位置。copyWithin 將會拷貝到該位置,但不包括 end 這個位置的元素。若是是負數, end 將從末尾開始計算。
若是 end 被忽略,copyWithin 將會複製到 arr.length。
返回值: 改變了的數組。
[1, 2, 3, 4, 5].copyWithin(-2);
// [1, 2, 3, 1, 2]
[1, 2, 3, 4, 5].copyWithin(0, 3);
// [4, 5, 3, 4, 5]
[1, 2, 3, 4, 5].copyWithin(0, 3, 4);
// [4, 2, 3, 4, 5]
[1, 2, 3, 4, 5].copyWithin(-2, -3, -1);
// [1, 2, 3, 3, 4]
// copyWithin 函數是設計爲通用的,其不要求其 this 值必須是一個數組對象。
[].copyWithin.call({length: 5, 3: 1}, 0, 3);
// {0: 1, 3: 1, length: 5}
複製代碼
參數:
value 用來填充數組元素的值。
start (可選) 起始索引,默認值爲0。
end (可選) 終止索引,默認值爲 this.length。
若是 start 是個負數, 則開始索引會被自動計算成爲 length+start, 其中 length 是 this 對象的 length 屬性值. 若是 end 是個負數, 則結束索引會被自動計算成爲 length+end。
返回值: 修改後的數組
[1, 2, 3].fill(4); // [4, 4, 4]
[1, 2, 3].fill(4, 1); // [1, 4, 4]
[1, 2, 3].fill(4, 1, 2); // [1, 4, 3]
[1, 2, 3].fill(4, 1, 1); // [1, 2, 3]
[1, 2, 3].fill(4, 3, 3); // [1, 2, 3]
[1, 2, 3].fill(4, -3, -2); // [4, 2, 3]
[1, 2, 3].fill(4, NaN, NaN); // [1, 2, 3]
[1, 2, 3].fill(4, 3, 5); // [1, 2, 3]
Array(3).fill(4); // [4, 4, 4]
//fill 方法故意被設計成通用方法, 該方法不要求 this 是數組對象。
[].fill.call({ length: 3 }, 4); // {0: 4, 1: 4, 2: 4, length: 3}
複製代碼
二、不改變原數組的方法
begin (可選)
從該索引處開始提取原數組中的元素(從0開始)。
若是該參數爲負數,則表示從原數組中的倒數第幾個元素開始提取,slice(-2)表示提取原數組中的倒數第二個元素到最後一個元素(包含最後一個元素)。
若是省略 begin,則 slice 從索引 0 開始。
end (可選)
在該索引處結束提取原數組元素(從0開始)。
slice會提取原數組中索引從 begin 到 end 的全部元素(包含begin,但不包含end)。 slice(1,4) 提取原數組中的第二個元素開始直到第四個元素的全部元素 (索引爲 1, 2, 3的元素)。
若是該參數爲負數, 則它表示在原數組中的倒數第幾個元素結束抽取。 slice(-2,-1)表示抽取了原數組中的倒數第二個元素到最後一個元素(不包含最後一個元素,也就是隻有倒數第二個元素)。
若是 end 被省略,則slice 會一直提取到原數組末尾。
若是 end 大於數組長度,slice 也會一直提取到原數組末尾。
返回值: 一個含有提取元素的新數組
let arr = [1,2,3,4,5];
let arr1 = arr.slice(1,3); // arr是[1,2,3,4,5], arr1是[2,3]
let arr2 = arr.slice(-2,-1); // arr是[1,2,3,4,5], arr2是[4]
// 開始位置在結束位置後面,獲得的數組是空
let arr3 = arr.slice(-2, -3); // arr是[1,2,3,4,5], arr3是[]
let arr4 = arr.slice(2, 1); // arr是[1,2,3,4,5], arr4是[]
//若是元素是個對象引用 (不是實際的對象),slice 會拷貝這個對象引用到新的數組裏。兩個對象引用都引用了同一個對象。若是被引用的對象發生改變,則新的和原來的數組中的這個元素也會發生改變。
let arr = [{name: 'xiaoming'}];
let arr1 = arr.slice(); // arr是[{name: xiaoming}],arr1是[{name: 'xiaoming'}]
arr1[0].name = 'xiaogang'; // arr是[{name: 'xiaogang'}],arr1是[{name: 'xiaogang'}]
// 對於字符串、數字及布爾值來講(不是 String、Number 或者 Boolean 對象),slice 會拷貝這些值到新的數組裏。在別的數組裏修改這些字符串或數字或是布爾值,將不會影響另外一個數組。
let arr = [1,2,3];
let arr1 = arr.slice(); // arr是[1,2,3],arr1是[1,2,3]
arr1[1] = "two"; // arr是[1,2,3],arr1是[1,"two",3]
// 固然,若是向兩個數組任一中添加了新元素(簡單或者引用類型),則另外一個不會受到影響。
複製代碼
separator (可選) 指定一個字符串來分隔數組的每一個元素。 若是有(separator),將分隔符轉換爲字符串。 若是省略(),數組元素用逗號分隔。默認爲 ","。 若是separator是空字符串(""),則全部元素之間都沒有任何字符。
let num = [1,2,3];
let str1 = num.join(); // 1,2,3
let str2 = num.join(', ') // 1, 2, 3
let str3 = num.join('') // 123
//全部的數組元素被轉換成字符串,再用一個分隔符將這些字符串鏈接起來。若是元素是undefined 或者null, 則會轉化成空字符串。
let num = [1,null,3];
let str1 = num.join(); // 1,,3
//若是數組中的元素是數組,會將裏面的數組也調用join()
let num = [[1,2],3];
let str1 = num.join('-'); // 1,2-3
// 若是數組中的元素是對象,對象會被轉爲[object Object]字符串
let num = [{num: 1},2,3];
let str1 = num.join('-'); // [object Object]-2-3
複製代碼
返回值: 一個全部數組元素鏈接的字符串。若是 arr.length 爲0,則返回空字符串
知識點
// 扁平化簡單的二維數組
const arr = [11, [22, 33], [44, 55], 66];
const flatArr = arr.join().split(','); // ["11", "22", "33", "44", "55", "66"]
複製代碼
[1,2,3].toString(); // 1,2,3
[1,[2,'c']].toString(); //1,2,c
// 以上與不使用任何參數調用join()方法返回的字符串是同樣的。
// 如下的這個例子要跟下面的toLocaleString對照看
[{a:1},1,new Date()].toString() //"[object Object],1,Sat Jul 07 2018 18:43:45 GMT+0800 (中國標準時間)"
複製代碼
注意: 當數組和字符串操做的時候,js 會調用這個方法將數組自動轉換成字符串
[1,2,3]+'abc' //1,2,3abc
複製代碼
返回值: 返回一個字符串表示數組中的元素
知識點
// 扁平化簡單的二維數組
const arr = [11, [22, 33], [44, 55], 66];
const flatArr = arr.toString().split(','); // ["11", "22", "33", "44", "55", "66"]
複製代碼
locales (可選) 帶有BCP 47語言標記的字符串或字符串數組
options (可選) 一個可配置屬性的對象
//數組中的元素將會使用各自的 toLocaleString 方法:
// Object: Object.prototype.toLocaleString()
// Number: Number.prototype.toLocaleString()
// Date: Date.prototype.toLocaleString()
let prices = ['¥7', 500, 8123, 12];
// 不帶參數
prices.toLocaleString(); // "¥7,500,8,123,12"
//帶參數
prices.toLocaleString('ja-JP', { style: 'currency', currency: 'JPY' }); // "¥7,500,8,123,12"
//MDN上的舉例中說是 "¥7,¥500,¥8,123,¥12",在瀏覽器和Node中驗證了返回的都是 "¥7,500,8,123,12" 啊!
// 如下的這個例子要跟上面的toString對照看
[{a:1},1,new Date()].toLocaleString() //"[object Object],1,2018/7/7 下午6:45:00"
複製代碼
返回值: 表示數組元素的字符串。
參數:
valueN (可選) 將(多個)數組和/或值鏈接成新數組。
[1,2,3].concat([4,5,6],[7,8,9]) // [1, 2, 3, 4, 5, 6, 7, 8, 9]
['a','b','c'].concat(1,[2,3],[[4,5]]) // ["a", "b", "c", 1, 2, 3, [4,5]]
// concat方法不會改變this或任何做爲參數提供的數組,而是返回一個淺拷貝,因此原始數組和新數組都引用相同的對象。 若是引用的對象被修改,新數組和原始數組都會變。
let obj = {a: 1};
let arr1 = [2,obj];
let arr2 = [1].concat(arr1);
console.log(arr1,arr2) //[2,{a:1}],[1,2,{a:1}]
//記錄下上面的打印結果以後修改obj
obj.a = 2;
console.log(arr1,arr2) ////[2,{a:2}],[1,2,{a:2}]
// 說了是淺拷貝,並且原數組也不改變,那咱們就能夠用它來實現數組的淺拷貝功能
let num1 = [1,2,3];
//第一種
let num2 = num1.concat();
//第二種
let num2 = [].concat(num1);
num2[0] = 'a';
console.log(num1,num2); // [1, 2, 3] ["a", 2, 3]
複製代碼
返回值: 新的 Array 實例
知識點
// concat 和擴展運算符能夠快速扁平化數組
const arr = [11, [22, 33], [44, 55], 66];
const flatArr = [].concat(...arr); // [11, 22, 33, 44, 55, 66]
複製代碼
obj 須要檢測的值。
// 下面的函數調用都返回 true
Array.isArray([]);
Array.isArray([1]);
Array.isArray(new Array());
// 這裏注意:Array.prototype 也是一個數組,一個屬性值不是索引的數組。[constructor: ƒ, concat: ƒ, find: ƒ, findIndex: ƒ, pop: ƒ, …]
Array.isArray(Array.prototype);
// 下面的函數調用都返回 false
Array.isArray();
Array.isArray({});
Array.isArray(null);
Array.isArray(undefined);
Array.isArray(17);
Array.isArray('Array');
Array.isArray(true);
Array.isArray(false);
Array.isArray({ __proto__: Array.prototype });
複製代碼
返回值: 若是對象是 Array,則爲true; 不然爲false。
知識點
//判斷數組的歷程
// step one: 使用constructor
var a = [1];
console.log(a.constructor === Array) // true
// 可是原型的contructor屬性是能夠被改寫的,例如在原型繼承的時候,咱們都是要把繼承過來的prototype的constructor改寫成咱們當前的
var a = [1];
a.__proto__.constructor = '1';
console.log(a.constructor === Array) // false
// step two : 使用instanceof
var a = [1];
console.log(a instanceof Array) // true
//可是instanceof不能檢測iframes的數組
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
xArray = window.frames[window.frames.length-1].Array;
var arr = new xArray(1,2,3); // [1,2,3]
arr instanceof Array; // false
// step three :萬無一失的Object.prototype.toString.call
Array.isArray = function(arg) {
return Object.prototype.toString.call(arg) === '[object Array]';
};
// step four : Array.isArray()
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
xArray = window.frames[window.frames.length-1].Array;
var arr = new xArray(1,2,3); // [1,2,3]
Array.isArray(arr); // true,也能夠檢測iframes的數組
複製代碼
三、數組遍歷、映射、過濾、檢測、簡化等方法
介紹方法以前,先對這些數組方法作一個概述:
首先,大多數方法的第一個參數接收一個函數,而且對數組的每一個元素(或一些元素)調用一次該函數。若是是稀疏數組,對不存在的元素不調用該函數。大多數狀況下,調用提供的函數使用三個參數:數組元素、元素的索引和數組自己。一般,只須要第一個參數值,能夠忽略後兩個參數。
大多數方法,第二個參數是可選的。若是有第二個參數,則調用的第一個函數參數被看作是第二個參數的方法,即當執行第一個函數參數時用做this的值(參考對象)。
方法的返回值很重要,不一樣的方法處理返回值的方式也不同。
下面這些方法運行時的規則:
對於空數組是不會執行回調函數的
對於已在迭代過程當中刪除的元素,或者空元素會跳過回調函數
遍歷次數在第一次循環前就會肯定,再添加到數組中的元素不會被遍歷。
若是已經存在的值被改變,則傳遞給 callback 的值是遍歷到他們那一刻的值。
已刪除的項不會被遍歷到。若是已訪問的元素在迭代時被刪除了(例如使用 shift()) ,以後的元素將被跳過
callback 爲數組中每一個元素執行的函數,該函數接收三個參數:
currentValue(當前值) 數組中正在處理的當前元素。
index(索引) 數組中正在處理的當前元素的索引。
array forEach()方法正在操做的數組。
thisArg (可選) 當執行回調函數時用做this的值(參考對象)。默認值爲undefined
注意:
forEach沒法中途退出循環,只能用return退出本次回調,進行下一次回調,若是要提早終止,能夠把forEach方法放在try塊中,並能拋出一個異常,但這種方法是不推薦的。 它與以後會說到的幾個方法不一樣,老是返回 undefined值,即便你return了一個值。
// 一、 空元素不遍歷,undefined和null是會遍歷的。
let numberArr = [1,2,,3];
numberArr.forEach(function (value,index,array) {
console.log(value,index,array)
})
//打印信息以下,可見空元素是不會遍歷的
//1 0 [1, 2, empty, 3]
//2 1 [1, 2, empty, 3]
//3 3 [1, 2, empty, 3]
let nullArr = [1,2,null,3];
nullArr.forEach(function (value,index,array) {
console.log(value,index,array)
})
//打印信息以下,null是會遍歷的
//1 0 (4) [1, 2, null, 3]
//2 1 (4) [1, 2, null, 3]
//null 2 (4) [1, 2, null, 3]
//3 3 (4) [1, 2, null, 3]
//二、已刪除的項不會被遍歷到。若是已訪問的元素在迭代時被刪除了,以後的元素將被跳過
let numberArr = [1,2,3];
numberArr.forEach(function (value,index,array) {
if(index === 0) {
delete numberArr[2]; //刪除第三項
//或者numberArr.pop()
}
console.log(value,index,array)
})
//打印信息以下:
// 1 0 (3) [1, 2, empty]
// 2 1 (3) [1, 2, empty]
let numberArr1 = [1,2,3,4];
numberArr1.forEach(function (value,index,array) {
if(index === 1) {
numberArr1.shift() //遍歷到第二項的時候,刪除第一項
}
console.log(value,index,array)
})
// 打印信息以下,遍歷到第二項的時候,刪除第一項,會跳過第三項
// 1 0 (4) [1, 2, 3, 4]
// 2 1 (3) [2, 3, 4]
// 4 2 (3) [2, 3, 4]
// 三、forEach 遍歷的範圍在第一次調用 callback 前就會肯定。調用forEach 後添加到數組中的項不會被 callback 訪問到。若是已經存在的值被改變,則傳遞給 callback 的值是 forEach 遍歷到他們那一刻的值。
let arr = [1,2,3];
arr.forEach(function (value,index,array) {
if(index === 0) {
arr.push('新增的不會被遍歷到')
arr[2] = 4;
}
console.log(value,index,array)
})
// 1 0 (4) [1, 2, 4, "新增的不會被遍歷到"]
// 2 1 (4) [1, 2, 4, "新增的不會被遍歷到"]
// 4 2 (4) [1, 2, 4, "新增的不會被遍歷到"]
// 四、使用thisArg參數 和 箭頭函數使用thisArg
let arr = [1,2,3];
let obj = {arr: 'thisArg'}
arr.forEach(function () {
console.log(this.arr)
},obj)
// 打印三次 'thisArg'
let arr = [1,2,3];
let obj = {arr: 'thisArg'}
arr.forEach(() => {
console.log(this.arr)
},obj)
// 打印三次 undefined
// 五、forEach沒法中途退出循環,只能用return退出本次回調,進行下一次回調
let arr = [1,2,3];
let result = arr.forEach((value) => {
if(value == 2) {
return value;
}
console.log(value)
})
console.log(result) // undefined ,即便中間return vlaue,也仍是undefined
//打印value的值以下,說明return 並不能終止循環
// 1
// 3
複製代碼
返回值: undefined
callback 生成新數組元素的函數,使用三個參 這個函數跟forEach()的函數不一樣的是,傳遞給map()的函數應該有返回值。
currentValue callback 的第一個參數,數組中正在處理的當前元素。 index callback 的第二個參數,數組中正在處理的當前元素的索引。 array callback 的第三個參數,map 方法被調用的數組。 thisArg (可選) 執行 callback 函數時 使用的this 值。
注意: map() 返回的是新數組,它不修改調用的數組。若是是稀疏數組,返回的也是相同方式的稀疏數組:它具備相同的長度,相同索引的缺失元素(由於空值不會調用函數)
let number = [1,2,3];
let doubles = number.map(function (value) {
return value * 2;
})
console.log(number, doubles)
// [1,2,3] [2,4,6]
複製代碼
返回值: 一個新數組,每一個元素都是回調函數的結果
知識點 不要用 map 代替 forEach,map 會建立一個新的數組,佔用內存。若是你不用 map 的返回值,那你就應當使用 forEach
callback 用來測試數組的每一個元素的函數。調用時使用參數 (element, index, array)。返回true表示保留該元素(經過測試),false則不保留。它接受三個參數:
element 當前在數組中處理的元素 index(可選) 正在處理元素在數組中的索引 array(可選)調用了filter篩選器的數組 thisArg(可選)可選。執行 callback 時的用於 this 的值。
注意:
callback 只會在已經賦值的索引上被調用,對於那些已經被刪除或者從未被賦值的索引不會被調用。也就是說filter()會跳過稀疏數組中缺乏的元素,它的返回數組老是稠密的,能夠用這個方法壓縮稀疏數組的空缺。 filter 不會改變原數組,它返回過濾後的新數組。
let number = [1,2,3,4,5,6];
let small = number.filter((value) => {
return value < 4;
})
console.log(number,small)
// 打印 [1, 2, 3, 4, 5, 6] [1, 2, 3]
//壓縮稀疏數組的空缺
let arr = [1,2,3,,5];
let arr1 = arr.filter(() => true);
console.log(arr,arr1)
// 打印 [1, 2, 3, empty, 5] [1, 2, 3, 5]
複製代碼
返回值: 一個新的經過測試的元素的集合的數組,若是沒有經過測試則返回空數組。
callback 用來測試每一個元素的函數。
thisArg 執行 callback 時使用的 this 值。
注意:
every 方法爲數組中的每一個元素執行一次 callback 函數,callback 只會爲那些已經被賦值的索引調用。不會爲那些被刪除或歷來沒被賦值的索引調用。every 方法在callback第一次返回false後就返回false,而後終止遍歷。但若是callback一直返回true,它將會遍歷整個數組,最終返回true。
空數組上調用every方法,返回 true,由於空數組沒有元素,因此空數組中全部元素都符合給定的條件
every 不會改變原數組
let arr = [12,34,5,23,44];
let num = 0;
let result = arr.every(function (element, index, array) {
num++;
return element > 10;
})
console.log(result,num) // 打印 false 3
// 可見發現5這個小於10的元素後,遍歷當即終止,num爲3
let arr = [12,34,,23,44];
let num = 0;
let result = arr.every(function (element, index, array) {
num++;
return element > 10;
})
console.log(result,num) // 打印 true 4
// 不會遍歷沒有賦值的索引位置,因此num爲4
let result = [].every(function (element, index, array) {
return element > 10;
})
console.log(result) // 打印 true
複製代碼
返回值: 一個布爾值,當全部的元素都符合條件才返回true,不然返回false
callback 用來測試每一個元素的函數
thisArg 可選 執行 callback 時使用的 this 值。
注意:
some 爲數組中的每個元素執行一次 callback 函數,直到找到一個使得 callback 返回一個「真值」,這時,some 將會當即返回 true。不然,some 返回 false。callback 只會在那些」有值「的索引上被調用,不會在那些被刪除或歷來未被賦值的索引上調用。
some 被調用時不會改變數組。
空數組調用some,返回false
// 一個簡單的例子說明
function isBiggerThan10(element, index, array) {
return element > 10;
}
[2, 5, 8, 1, 4].some(isBiggerThan10); // false
[12, 5, 8, 1, 4].some(isBiggerThan10); // true
// 實現一個跟includes方法相似的功能
let arr = [1,2,3];
function include(value) {
return arr.some((element) => {
return element === value;
})
}
include(2) // true
include(4) // false
let result = [].some(function (element, index, array) {
return element > 10;
})
console.log(result) // 打印 false
複製代碼
返回值: 只要數組中的任意一個元素在回調函數中返回的是真值,就返回true,不然爲false
callback 執行數組中每一個值的函數,包含四個參數:
accumulator 累加器累加回調的返回值; 它是上一次調用回調時返回的累積值,或initialValue(以下所示)。
currentValue 數組中正在處理的元素。
currentIndex (可選) 數組中正在處理的當前元素的索引。 若是提供了initialValue,則索引號爲0,不然爲索引爲1。
array (可選) 調用reduce的數組
initialValue (可選) 用做第一個調用 callback的第一個參數的值。 若是沒有提供初始值,則將使用數組中的第一個元素。 在沒有初始值的空數組上調用 reduce 將報錯。
注意:
reduce爲數組中的每個元素依次執行callback函數,不包括數組中被刪除或從未被賦值的元素,回調函數第一次執行時,accumulator 和currentValue的取值有兩種狀況:調用reduce時提供initialValue,accumulator取值爲initialValue,currentValue取數組中的第一個值;沒有提供 initialValue,accumulator取數組中的第一個值,currentValue取數組中的第二個值。即:若是沒有提供initialValue,reduce 會從索引1的地方開始執行 callback 方法,跳過第一個索引。若是提供initialValue,從索引0開始。
若是數組爲空且沒有提供initialValue,會拋出TypeError 。若是數組僅有一個元素(不管位置如何)而且沒有提供initialValue, 或者有提供initialValue可是數組爲空,那麼此惟一值將被返回而且callback不會被執行。
let arr = [1,2,3,4,5];
let sum = arr.reduce((x,y) => x + y,0);
console.log(sum) // 15
// 看一下initialValue傳和不傳的區別
let arr = [1,2,3,4,5];
arr.reduce(function (accumulator,currentValue,currentIndex,arr) {
console.log(currentIndex)
return accumulator + currentValue;
})
// 1,2,3,4,5 沒傳入initialValue,索引是從1開始
arr.reduce(function (accumulator,currentValue,currentIndex,arr) {
console.log(currentIndex)
return accumulator + currentValue;
},10)
// 0,1,2,3,4,5 傳入initialValue,索引從0開始
// 應用到二維數組展開
let arr = [[0, 1], [2, 3], [4, 5]].reduce(
(a, b) => a.concat(b)
);
console.log(arr)
// [0, 1, 2, 3, 4, 5]
複製代碼
返回值: 函數累計處理的結果
searchElement 要查找的元素
fromIndex (可選)開始查找的位置。 若是該索引值大於或等於數組長度,意味着不會在數組裏查找,返回-1。
若是該索引值是負值,表明相對數組末尾的偏移量,即-1表示從最後一個元素開始查找,-2表示從倒數第二個元素開始查找,注意的是,這並不改變其查找順序,查找順序仍然是從前向後查詢數組。
若是該索引值是負值,其絕對值大於數組長度,則整個數組都將會被查詢。其默認值爲0。
注意: indexOf 使用嚴格相等(即 ===)比較 searchElement 和數組中的元素。並且indexOf()不能識別 NaN
let array = [2, 5, 9];
array.indexOf(2) // 0
array.indexOf(7) // -1
array.indexOf(9, 2) // 2
array.indexOf(9, 3) // -1
array.indexOf(2, -1) // -1
array.indexOf(2, -3) // 0
array.indexOf(2, -4) // 0
let array1 = [1,2,NaN];
array1.indexOf(NaN) // -1
複製代碼
返回值: 首個被找到的元素在數組中的索引位置; 若沒有找到則返回 -1
searchElement 要查找的元素
fromIndex (可選)開始查找的位置。默認爲數組的長度減 1,即整個數組都被查找。 若是該值大於或等於數組的長度,則整個數組會被查找。 若是爲負值,將其視爲從數組末尾向前的偏移。即便該值爲負,數組仍然會被從後向前查找。 若是該值爲負時,其絕對值大於數組長度,則方法返回 -1,即數組不會被查找。
注意: lastIndexOf 使用嚴格相等(即 ===)比較 searchElement 和數組中的元素。並且lastIndexOf()不能識別 NaN
let array = [2,5,9,2];
array.lastIndexOf(9) // 2
array.lastIndexOf('9') // -1 嚴格相等
array.lastIndexOf(7) // -1
array.lastIndexOf(2,4) // 3
array.lastIndexOf(2,3) // 3
array.lastIndexOf(2,2) // 0
array.lastIndexOf(2,-1) // 3
array.lastIndexOf(2,-2) // 0
array.lastIndexOf(2,-4) // 0
array.lastIndexOf(2,-5) // -1
複製代碼
返回值: 數組中最後一個符合元素的索引,如未找到返回-1
searchElement 須要查找的元素值。
fromIndex (可選) 從該索引處開始查找 searchElement。默認爲 0。若是爲負值,則按升序從 array.length + fromIndex 的索引開始搜索。負值絕對值超過長數組度,從0開始搜索。
若是fromIndex 大於等於數組長度 ,則返回 false 。該數組不會被搜索。
注意:
includes解決了兩個indexOf的問題:
indexOf方法不能識別NaN indexOf方法檢查是否包含某個值不夠語義化,須要判斷是否不等於-1,表達不夠直觀
[1, 2, 3].includes(2); // true
[1, 2, 3].includes(4); // false
[1, 2, 3].includes(3, 3); // false
[1, 2, 3].includes(3, -1); // true
[1, 2, 3].includes(3, -4); // true
[1, 2, NaN].includes(NaN); // true
複製代碼
返回值: 一個布爾值,根據狀況,若是包含則返回 true,不然返回false。
callback 在數組每一項上執行的函數,接收 3 個參數:
element 當前遍歷到的元素。 index 當前遍歷到的索引。 array 數組自己。 thisArg 可選,指定 callback 的 this 參數。
注意:
這兩個方法對數組中的每一項元素執行一次 callback 函數,直至有一個 callback 返回 true。在稀疏數組中,即便對於數組中不存在的條目的索引也會調用回調函數。 這意味着對於稀疏數組來講,該方法的效率要低於那些只遍歷有值的索引的方法。
當找到一個callback判斷爲true的元素,find方法會當即返回這個元素的值,不然返回 undefined。findIndex會當即返回該元素的索引。若是回調從不返回真值,或者數組的length爲0,則findIndex返回-1。
這兩個方法都不會修改所調用的數組
// find
let a = [1, 4, -5, 10].find((n) => n < 0); // 返回元素-5
let b = [1, 4, -5, 10,NaN].find((n) => Object.is(NaN, n)); // 返回元素NaN
// findIndex
let a = [1, 4, -5, 10].findIndex((n) => n < 0); // 返回索引2
let b = [1, 4, -5, 10,NaN].findIndex((n) => isNaN(n)); // 返回索引4
// 稀疏數組
let a =[1,,3,4];
let index = 0;
a.find((n) => {
console.log(index++) //0,1,2 第二次是empty也會調用一次,並且返回爲true,當即退出
return n === 3;
})
複製代碼
返回值:
find 方法,當某個元素經過 callback 的測試時,返回數組中的一個值,不然返回 undefined。 findIndex方法,返回數組中知足提供的測試函數的第一個元素的索引。不然返回-1。
知識點 不要用 find() 代替 some(),一般混用是這種場景,find 返回第一個符合條件的值,直接拿這個值作 if 判斷是否存在,可是這個符合條件的值也有可能剛好爲 0。 find 是找到數組中的值後對其進一步處理,通常用於對象數組的狀況;some 纔是檢查存在性;二者不可混用。
都是一個新的 Array 迭代器對象
for (let key of ['a', 'b'].keys()) {
console.log(key);
}
// 0
// 1
for (let value of ['a', 'b'].values()) {
console.log(value);
}
// 'a'
// 'b'
for (let value of ['a', 'b'][Symbol.iterator]()) {
console.log(value);
}
// 'a'
// 'b'
for (let [key, value] of ['a', 'b'].entries()) {
console.log(key, value);
}
// 0 "a"
// 1 "b"
複製代碼
**擴展幾個概念 ** 一、數組的索引和對象key有什麼關係? 數組是對象的特殊形式,使用方括號訪問數組元素和使用方括號訪問對象屬性同樣。JavaScript將指定的數字索引值轉換成字符串——索引1變成"1"——而後將其做爲屬性名來使用。數組的特別之處在於,當使用小於2^32的非負整數做爲屬性名時數組會自動維護其length屬性。
// 索引到屬性名的轉化
let arr = [1,2,3];
console.log(arr[1]) // 2
console.log(arr["1"]) // 2
複製代碼
全部的數組都是對象,能夠爲其建立任意名字的屬性,不過,只有在小於2^32的非負整數纔是索引,數組纔會根據須要更新length。事實上數組的索引僅僅是對象屬性名的一種特殊類型,這意味着JavaScript數組沒有「越界」錯誤的概念。當查詢任何對象中不存在的屬性時,不會報錯,只會獲得undefined
let arr = [];
arr["a"] = 1;
console.log(arr,arr.length) // arr是[a:1] length是0
複製代碼
對於使用負數或非整數的狀況,數值會轉換爲字符串,字符串做爲屬性名來用,當時只能當作常規的對象屬性,而非數組的索引。
let arr = [];
arr[-1.23] = 0;
console.log(arr,arr.length) // arr是[-1.23: 0] length是0
複製代碼
使用非負整數的字符串或者一個跟整數相等的浮點數時,它就當作數組的索引而非對象屬性。
let arr = [];
arr["100"] = 'a';
console.log(arr,arr.length) // arr 是[empty × 100, "a"],length 是101
let arr1 = [];
arr1[1.0000] = 'b';
console.log(arr1,arr1.length) // arr 是[empty, "b"],length 是2
複製代碼
2.稀疏數組
稀疏數組就是包含從0開始的不連續索引的數組。一般數組的length屬性值表明數組中元素的個數。若是數組是稀疏的,length屬性值大於元素的個數
足夠稀疏的數組一般在實現上比稠密的數組更慢,更耗內存,在這樣的數組中查找元素所用的時間就變得跟常規對象的查找時間同樣長了,失去了性能的優點。
let a1 = [,,]; // 數組直接量,該數組是[empty × 2]
0 in a1 // false: a1在索引0處沒有元素
let a2 = new Array(3); //[empty × 3],該數組根本沒有元素
0 in a2 // false: a2在索引0處沒有元素
let a3 = [undefined];
0 in a3 // true: a3在索引0處有一個值爲undefined的元素
let a4 = [,undefined];
0 in a4 // fasle: a4在索引0處沒有元素
1 in a4 // true: a4在索引1處有一個值爲undefined的元素
console.log(a4[0],a4[1]) // undefined undefined,可見數組訪問返回undefined,多是稀疏數組,也多是數組元素爲undefined
複製代碼
三、類數組對象
擁有一個數值length屬性和對應非負整數屬性的對象看作一種類型的數組
數組跟類數組相比有如下不一樣:
當有新元素添加到數組中時,自動更新length屬性
設置length爲一個較小值將截斷數組
從Array.prototype中繼承了一些方法
其類屬性爲'Array'
JavaScript 數組有不少方法特地定義通用,所以他們不只應用在真正的數組並且在類數組對象上都能正確工做,JavaScript權威指南一書說的是:ES5中全部的方法都是通用的,ES3中除了toString()和toLocaleString()意外全部方法也是通用的。
類數組對象顯然沒有繼承自Array.prototype,因此它們不能直接調用數組方法,不過能夠間接地使用Function.call方法調用。
// 類數組應用通用方法
let arrayLike = {0: 'name', 1: 'age', 2: 'address', length: 3 }
Array.prototype.join.call(arrayLike,'*') // "name*age*address"
// 還記得當初獲取的DOM元素怎麼轉化成數組麼?
functon toArray (DOM) {
return Array.prototype.slice.call(DOM);
}
//對的,這樣也能夠的
let htmlCollection = document.getElementsByTagName('h2');
let arr1 = Array.prototype.map.call(htmlCollection,function (ele,index){return ele});
console.log(Array.isArray(arr1)) // true
// 還有這樣
let arrayLike = {0: 'name', 1: 'age', 2: 'address', length: 3 }
let arr2 = Array.prototype.concat.apply([],arrayLike);
console.log(arr) //["name", "age", "address"]
// ES6如今這樣
let arrayLike = {0: 'name', 1: 'age', 2: 'address', length: 3 }
let arr3 = Array.from(arrayLike);
console.log(arr3) // ["name", "age", "address"]
複製代碼
四、 JavaScript數組的進化——類型化數組的引入 先說一下廣泛意義上的Array,數組是一串 連續 的內存位置,用來保存某些值。JavaScript 中的數組是哈希映射,可使用不一樣的數據結構來實現,如鏈表,上一個元素包含下一個元素的引用。這樣其餘語言中數組的取值是根據內存位置進行數學計算就能找到,而在JavaScript中就須要遍歷鏈表之類的結構,數組越長,遍歷鏈表跟數據計算相比就越慢。
現代 JavaScript 引擎是會給數組分配連續內存的 —— 若是數組是同質的(全部元素類型相同)。因此在寫代碼時保證數組同質,以便 JIT(即時編譯器)可以使用 c 編譯器式的計算方法讀取元素是一種優雅的方式。
不過,一旦你想要在某個同質數組中插入一個其餘類型的元素,JIT 將解構整個數組,並按照舊有的方式從新建立。
ES6 增長了 ArrayBuffer, 提供一塊連續內存供咱們隨意操做。然而,直接操做內存仍是太複雜、偏底層。因而便有了處理 ArrayBuffer 的視圖(View)。
ArrayBuffer 對象用來表示通用的、固定長度的原始二進制數據緩衝區。ArrayBuffer 不能直接操做,而是要經過類型數組對象或 DataView 對象來操做,它們會將緩衝區中的數據表示爲特定的格式,並經過這些格式來讀寫緩衝區的內容。
語法: new ArrayBuffer(length)
參數
length:要建立的 ArrayBuffer 的大小,單位爲字節。
返回值:一個指定大小的 ArrayBuffer 對象,其內容被初始化爲 0。
異常:若是 length 大於 Number.MAX_SAFE_INTEGER(>= 2 ** 53)或爲負數,則拋出一個 RangeError 異常。
複製代碼
類型數組對象 一個TypedArray 對象描述一個底層的二進制數據緩存區的一個相似數組(array-like)視圖。事實上,沒有名爲 TypedArray的全局對象,也沒有一個名爲的 TypedArray構造函數。相反,有許多不一樣的全局對象,下面會列出這些針對特定元素類型的類型化數組的構造函數。
new TypedArray(); // ES2017中新增
new TypedArray(length);
new TypedArray(typedArray);
new TypedArray(object);
new TypedArray(buffer [, byteOffset [, length]]);
TypedArray()指的是如下的其中之一:
Int8Array();//8位二進制帶符號整數 -2^7~(2^7) - 1,大小1個字節
Uint8Array();//8位無符號整數 0~(2^8) - 1,大小1個字節
Int16Array();//16位二進制帶符號整數 -2^15~(2^15)-1,大小2個字節
Uint16Array();//16位無符號整數 0~(2^16) - 1,大小2個字節
Int32Array();// 32位二進制帶符號整數 -2^31~(2^31)-1,大小4個字節
Uint32Array();//32位無符號整數 0~(2^32) - 1,大小4個字節
Float32Array();//32位IEEE浮點數,大小4個字節
Float64Array(); //64位IEEE浮點數,大小8個字節
複製代碼
應用:
var buffer = new ArrayBuffer(8);
var view = new Int32Array(buffer);
view[0] = 100;
console.log(view)// [100,0],一個八個字節,Int32Array一個元素大小是4個字節,因此只能放下兩個元素
複製代碼
這裏推薦一下個人前端學習交流羣:784783012,裏面都是學習前端的,若是你想製做酷炫的網頁,想學習編程。本身整理了一份2018最全面前端學習資料,從最基礎的HTML+CSS+JS【炫酷特效,遊戲,插件封裝,設計模式】到移動端HTML5的項目實戰的學習資料都有整理,送給每一位前端小夥伴,有想學習web前端的,或是轉行,或是大學生,還有工做中想提高本身能力的,正在學習的小夥伴歡迎加入學習。