天天看點

數組 | Array_API(含手寫原理)

建立數組

(1)new Array() 【ES5】

建立數組可以通過

Array

構造函數的方式構造數組 (new 操作符可以省略)

let colors = new Array('red', 'green', 'yellow'); 
console.log(colors);  // ['red', 'green', 'yellow']
           

特殊:當傳入一個數值的時候,會建立一個指定數組的數組,用逗号建立的數組空位,值為

undefined

(關于數組空位,發現一些好玩的,請看這篇博文)

let arr = Array(10);  // 這裡省略了new操作符
console.log(arr);  // [empty × 10]
console.log(arr.length);  // 10
           

(2)Array.of() 【ES6】

Array.of()

建立一個具有可變數量參數的新數組執行個體,而不考慮參數的數量或類型

Array.of()

代替了之前用

Array.prototype.slice.call(arguments)

轉數組的笨拙寫法

Array.of()

Array

構造函數的差別在于處理單個數組的情況
Array(10);   // [empty × 10]
Array.of(10);   // [10]
           

(3)Array.from() 【ES6】

Array.from()

建立一個具有可變數量參數的新數組執行個體,而不考慮參數的數量或類型

文法(注意:容易被忽略)

參數

  • arrayLike

    :類數組或者可疊代對象(如Map,Set等)或者有一個

    length

    屬性和可索引元素的結構
  • mapFn

    (可選):用于增強數組元素的回調函數
  • thisArg

    (可選):執行回調時的

    this

    對象

舉例

// 第二個參數的妙用
let arrLike = {
    '0': 1,
    '1': 2,
    '2': 3,
    '3': 4,
    length: 4,
};

let arr = Array.from(arrLike, item => item * 3);
console.log(arr);   // [3,6,9,12]
           

Array.from()

對現有數組是淺拷貝

let arr1 = [5,6,7,8];
let arr2 = Array.from(arr1);
console.log(arr1 === arr2);   // false
           

數組索引

(1)中括号索引法

let colors = ['red', 'green', 'yellow'];
console.log(colors[1]);  // green
           

(2)Array.length()

Array.length()

傳回或設定一個數組中的元素個數
let colors = ['red', 'green', 'yellow'];
console.log(colors.length);  // 3
           

注意:數組的

length

并不隻是可讀的,而是可以通過修改

length

屬性,從數組的末尾删除或者添加元素

// 删除
let colors = ['red', 'green', 'yellow'];
colors.length = 2;
console.log(colors); // ['red', 'green']

// 添加
let colors = ['red', 'green', 'yellow'];
colors.length = 4;
console.log(colors[3]); // undefined

// 使用length屬性可以友善為數組末尾添加元素
let colors = ['red', 'green', 'yellow'];
colors[colors.length] = 'pink';
console.log(colors);     // ['red', 'green', 'yellow', 'pink']
           

檢測數組

(1)Array.isArray()

Array.isArray([1,2,3]);   // true
Array.isArray({name: 'Katrina'});   // false
           

思考:檢測一個對象是否是數組的方法有?

疊代器方法

(1)Array.prototype.values() 【ES6】

values()

方法傳回一個新的

Array Iterator

對象,該對象包含數組每個索引的值

(2)Array.prototype.keys() 【ES6】

keys()

方法傳回一個包含數組中每個索引鍵的

Array Iterator

對象

(3)Array.prototype.entries() 【ES6】

entries()

方法傳回一個新的Array Iterator對象,該對象包含數組中每個索引的鍵/值對
const a = ['foo', 'bar', 'baz', 'qux'];

const aValues = Array.from(a.values());
const aKeys = Array.from(a.keys());
const aEntries = Array.from(a.entries());

console.log(aValues);   // ['foo', 'bar', 'baz', 'qux']
console.log(aKeys);     // [0, 1, 2, 3]
console.log(aEntries);   // [[0, 'foo'], [1, 'bar'], [2, 'baz'], [3, 'qux']]


// 利用解構指派可以很容易拆分鍵值對
for (let [key, value] of aEntries) {
    console.log(key, value);
};

/*
	0 'foo'
	1 'bar'
	2 'baz'
	3 'qux'
*/
           

手寫實作

// entries()
Array.prototype.myEntries = function(arr) {
    let res = [];
    
    for (let i = 0; i < this.length; i++) {
        res.push([i, this[i]])
    };
    return res;
};


// test
const a = ['foo', 'bar', 'baz', 'qux'];
console.log(a.myEntries()); 

/*
	[[0, 'foo'], [1, 'bar'], [2, 'baz'], [3, 'qux']]
*/
           

複制和填充

(1)批量複制:copyWithin() 【ES6】

copyWithin()

方法淺複制數組的一部分到同一數組中的另一個位置,并傳回它,不會改變原數組的長度

文法

參數

  • target

    :從這個位置開始填充
  • start

    (可選):填充的内容從這個位置開始截取
  • end

    (可選):填充的内容到這個位置截取完畢(不包含end)

注意

  • 負索引會被計算成負索引+length
  • copyWithin()

    靜默忽略超出數組邊界、零長度及方向相反的索引範圍

舉例

let arr = [0,1,2,3,4,5];
arr.copyWithin(0, 2, 4);   // [2,3,2,3,4,5]
           
/*
	需要注意:
		1. copyWithin()靜默忽略超出數組邊界、零長度及方向相反的索引範圍
		2. 不會改變原數組的長度
		
*/
Array.prototype.myCopyWithin = function(target, start, end) {
    target < 0 ? target +length : target;
    start < 0 ? start +length : start;
    end < 0 ? end +length : end;
    
    const arr = this;
    for (let i = start; i < end; i++) {
        arr[target] = arr[i]
    };
    return arr;
};

// test
let arr = [0,1,2,3,4,5];
arr.copyWithin(0, 2, 4);   // [2,3,2,3,4,5] 
           

(2)填充數組:fill() 【ES6】

fill()

方法用一個固定值填充一個數組中從起始索引到終止索引内的全部元素,不包括終止索引,會改變原數組

文法

參數

  • value

    :用于填充數組的元素
  • start

    :起始索引,預設為0
  • end

    :終止索引,預設為

    this.length

注意

  • 負索引會被計算成負索引+length
  • fill()

    靜默忽略超出數組邊界、零長度及方向相反的索引範圍

舉例

let arr = [1,2,3,4,5,6,7];

// 索引過低忽略
arr.fill(0, -3, 4);
console.log(arr);   // [1,2,3,4,5,6,7]

// 索引過高忽略
arr.fill(0, 20, 24);
console.log(arr);   // [1,2,3,4,5,6,7]

// 索引反向忽略
arr.fill(0, 6, 3);
console.log(arr);   // [1,2,3,4,5,6,7]

// 索引部分可用,填充可用部分
arr.fill(0, 3, 20);
console.log(arr);   // [1,2,3,0,0,0,0]
           

手寫實作

/*
	需要注意:
		1. fill()靜默忽略超出數組邊界、零長度及方向相反的索引範圍
		2. 會改變原數組
*/ 

Array.prototype.myFill = function(value, start, end) {
    start < 0 ? start + length : start;
    end < 0 ? end + length : end;
    end > this.length ? this.length : end;
    for (let i = start; i < end; i++) {
        this[i] = value;
    };
    
    return this;
};

// test
let arr = [1,2,3,4,5,6,7];
arr.fill(0, 3, 20);
console.log(arr);   // [1,2,3,0,0,0,0]
           

轉換方法

(1)toString() && toLocaleString() && valueOf()

valueOf()

傳回數組本身

toString()

傳回由數組中每個值的等效字元串拼接而成的一個逗号分隔的字元串

toLocaleString()

傳回一個字元串表示數組中的元素。數組中的元素将使用各自的

toLocaleString

方法轉成字元串,這些字元串将使用一個特定語言環境的字元串(例如一個逗号 “,”)隔開

舉例

let colors = ['red', 'green', 'yellow'];

colors.toString();  // 'red,green,yellow'
colors.valueOf();   // ['red', 'green', 'yellow']

alert(colors.toString())  // 'red,green,yellow'
alert(colors.valueOf())  // 'red,green,yellow'
alert(colors)   // 'red,green,yellow'

/*
	這裡被顯式調用toString()方法和valueOf()方法,分别傳回數組的字元串表示
	最後alert(colors),因為alert期待字元串,是以調用了toString()方法
*/


let person1 = {
    toLocaleString() {
    	return "Nikolaos";
	},
    toString() {
    	return "Nicholas";
    }
};
let person2 = {
    toLocaleString() {
    	return "Grigorios";
    },
    toString() {
    	return "Greg";
    }
};
let people = [person1, person2];
alert(people); // Nicholas,Greg   調用toString()
alert(people.toString()); // Nicholas,Greg   調用toString()
alert(people.toLocaleString()); // Nikolaos,Grigorios  調用toLocaleString()
           

(2)join()

join()

傳回以指定分隔符分隔數組元素的字元串
let colors = ['red', 'green', 'yellow'];
console.log(colors.join('-'));   // 'red-green-yellow'
           

注意:如果數組中某一項是

null

或者

undefined

,則傳回值會以空字元串表示

手寫實作

/*
	需要注意:
		1. separator預設為逗号分隔
		2. 如果數組中某一項是``null``或者``undefined``,則傳回值會以空字元串表示
*/ 
Array.prototype.myJoin = function(separator = ',') {
    let res = '';
    
    for (let i = 0; i < this.length; i++) {
        this[i] = this[i] === undefined || this[i] === null ? '' : this[i];
        if (i < this.length - 1) {
            res += (this[i] + separator);
        } else if (i === this.length - 1) {
            res += this[i];
        };
    };
    
    return res;
};


// test
const a = [1,,3,4,undefined,6];
console.log(a.myJoin());   // 1,,3,4,,6
console.log(a.myJoin('-'));  // 1--3-4--6
           

棧和隊列方法

(1)push() 【ES5】

向數組末尾添加元素,傳回修改後數組的長度

手寫實作

/*
	需要注意:傳回的是修改後數組的長度
*/
Array.prototype.myPush = function() {
    return [...this, ...arguments].length;
};

// test
let a = [1,2,4,5,6];
console.log(a.myPush(8,9));   //7
           

(2)pop() 【ES5】

删除數組的最後一項,同時減少數組的

length

值,傳回被删除的元素

手寫實作

/*
	需要注意:
		1. 要減少數組的length值
		2. 傳回被删除的元素
		3. 數組長度為0時傳回undefined
*/
Array.prototype.myPop = function() {
    if (this.length === 0) return undefined;
    const res = this[this.length - 1];
    this.length = this.length - 1;
    
    return res;
};

let a = [1,2,4,5,6];
console.log(a.myPop());   // 6
console.log(a.length);    // 4
           

(3)shift() 【ES5】

删除數組的第一項,同時減少數組的

length

值,傳回被删除的元素

手寫實作

/*
	需要注意:
		1. 要減少數組的length值
		2. 傳回被删除的元素
		3. 數組長度為0時傳回undefined
*/
Array.prototype.myShift = function() {
    if (this.length === 0) return 0;
    const res = this[0];
    for (let i = 1; i < this.length; i++) {
        this[i-1] = this[i];
    };
    this.length = this.length - 1;
    return res;
};

let a = [1,2,4,5,6];
console.log(a.myShift());   // 1
console.log(a);    // [2,4,5,6]
           

(4)unshift() 【ES5】

在數組開頭添加元素,傳回修改後數組的長度

手寫實作

/*
	需要注意:傳回的是修改後數組的長度
*/
Array.prototype.myUnshift = function() {
    return [...arguments, ...this].length;
};

// test
let a = [1,2,4,5,6];
console.log(a.myUnshift(8,9));   //7
           

排序方法

補課啦:常見的排序算法及JS實作

(1)數組排序:sort() 【ES5】

sort()

方法用原地算法(即不建立額外的空間)對數組的元素進行排序,并傳回數組。預設排序順序是在将元素轉換為字元串,然後比較它們的 UTF-16 代碼單元值序列時建構的

文法

參數

  • compareFunction

    (可選):用來指定按某種順序進行排列的函數。如果省略,元素按照轉換為的字元串的各個字元的 Unicode 位點進行排序
function compareFunction(value1, value2) {
    if (value1 < value2) {
        return -1;    // 負值,value1排在value2前面
    } else if (value1 > value2) {
        return 1;    // 正值,value1排在value2後面
    } else {
        return 0;
    }
};
           

(2)翻轉數組:reverse() 【ES5】

reverse()

方法将數組中元素的位置颠倒,并傳回該數組,該方法會改變原數組

手寫實作

/*
	改變原數組
*/
Array.prototype.myReverse = function() {
    if (this.length <= 1) return this;
    let left = 0, right = this.length -1;
    while (left <= right) {
        [this[left], this[right]] = [this[right], this[left]];
        left++;
        right--;
    };
    return this;
};

// test
const arr = ['h', 'e', 'l', 'l', 'o'];
console.log(arr.myReverse());   // ['o', 'l', 'l', 'e', 'h']
           

操作方法

(1)合并數組:concat() 【ES5】

concat()

方法用于合并兩個或多個數組,此方法會首先建立一個目前數組的副本,然後再把參數添加到副本末尾,是以不會更改現有數組,而是傳回一個新數組

文法

參數

  • valueN

    :可以是數組或者值

注意

可以使用

Symbol.isConcatSpreadable

來控制傳入的類數組對象是否強制打平,

true

為強制打平

舉例

let a1 = [1,2,3];
let a2 = {
    [Symbol.isConcatSpreadable]:true,
    length: 2,
    0: 4,
    1: 5,
};
let a3 = {
    [Symbol.isConcatSpreadable]:false,
    length: 2,
    0: 4,
    1: 5,
};

// 強制打平
let a1_2 = a1.concat(a2);
console.log(a1_2);     // [1,2,3,4,5]

// 不強制打平
let a1_3 = a1.concat(a3);
console.log(a1_3);     // [1,2,3, {[Symbol.isConcatSpreadable]:false,length: 2,0: 4,1: 5}]
           

手寫實作

/*
	注意:此方法會建立一個目前數組的副本,并不會修改原數組
*/
Array.prototype.myConcat = function() {
    let args = [...arguments];
    let res = this;
    
    for (let i = 0; i < args.length; i++) {
        if (typeof args[i] === 'object') {
            res = [...res, ...args[i]];
        } else {
            res[res.length] = args[i];
        }
    }; 
    return res;
};


// test
const a1 = [1,2,3];
const a2 = [5,6];
console.log(a1.myConcat(4, a2)); // [1,2,3,4,5,6]
           

(2)截取數組:slice() 【ES5】

slice()

方法傳回一個新的數組對象,這一對象是一個由

begin

end

決定的原數組的淺拷貝(包括

begin

,不包括

end

),原始數組不會被改變

文法

參數

  • start

    (可選):起始索引,預設為0
  • end

    (可選):終止索引(不含),預設為

    this.length

注意

  • 遇到負索引需要進行索引+length處理
  • start

    超過原數組的索引範圍傳回空數組
  • end

    大于原數組的長度,則截取到原數組的末尾

手寫實作

Array.prototype.mySlice = function(start, end) {
    start > 0 ? start : start +length;
    end > 0 ? end : end +length;
    end > this.length ? this.length : end;
    
    let res = [];
    for (let i = start; i < end; i++) {
        res.push(this[i]);
    };
    
    return res;
};

// test
const arr = ['h', 'e', 'l', 'l', 'o'];
console.log(arr.mySlice(2,4));  // ['l', 'l'];
console.log(arr);   // ['h', 'e', 'l', 'l', 'o']
           

(3)插入元素:splice() 【ES5】

splice()

方法通過删除或替換現有元素或者原地添加新的元素來修改數組,并以數組形式傳回被修改的内容,此方法會改變原數組

文法

參數

  • start

    :起始位置
  • deletecount

    (可選):要移除數組元素的個數,0或者負數表示不移除
  • item1 item2

    (可選):要添加的元素

傳回值

由被删除的元素組成的一個數組

如果隻删除了一個元素,則傳回隻包含一個元素的數組

如果沒有删除元素,則傳回空數組

方法

  • 删除:傳2個參數
  • 插入:傳3個參數
  • 替換:傳3個參數

手寫實作

/*
	改變原數組
*/
Array.prototype.mySlice = function() {
    let args = [...arguments];
    let start = Array.prototype.shift.call(args);
    let deletecunt = Array.prototype.shift.call(args);
    
    let left = this.slice(0, start);  // 左邊數組
    let right = this.slice(start+deletecount, this.length);  // 右邊數組
    
    let res = [...left, ...atgs, ... right];
    
    // 改變原數組
    for (let i = 0; i < res.length; i++) {
        this[i] = res[i];
    };
    
    return this.slice(start, start + deletcount);   // 傳回删除的資料
};

// test
var myFish = ['angel', 'clown', 'drum', 'mandarin', 'sturgeon'];
var removed = myFish.splice(3, 1);
console.log(removed);   // ['mandarin']


var myFish = ['angel', 'clown', 'drum', 'sturgeon'];
var removed = myFish.splice(2, 1, "trumpet");
console.log(removed);   // ['drum]
           

搜尋和位置方法

(1)按嚴格相等搜尋:indexOf() 【ES5】 && lastIndexOf() 【ES5】 && inclues() 【ES6】

indexOf()

方法傳回在數組中可以找到一個給定元素的第一個索引,如果不存在,則傳回-1

lastIndexOf()

方法傳回指定元素(也即有效的 JavaScript 值或變量)在數組中的最後一個的索引,如果不存在則傳回 -1,從數組的後面向前查找,從

fromIndex

處開始

includes()

方法用來判斷一個數組是否包含一個指定的值,根據情況,如果包含則傳回

true

,否則傳回

false

注意

  • 三者都可以指定

    fromIndex

    ,即從哪一項開始尋找
  • 三者都采用嚴格相等搜尋,即

    ===

    比較
  • 找到目标之後不會繼續往下找

手寫實作

/*
	嚴格相等
*/
// indexOf()
Array.prototype.myIndexOf = function(num, fromIndex = 0) {
    for (let i = fromIndex; i < this.length; i++) {
        if (this[i] === num) {
            return i;
        };
    };
    return -1;
};

// test 
const arr = [1,2,3,4,5,6];
console.log(arr.myIndexOf(2)) // 1
console.log(arr.myIndexOf(2, 4))   // -1


// includes()
Array.prototype.myIncludes = function(num, fromIndex = 0) {
    for (let i = fromIndex; i < this.length; i++) {
        if (this[i] === num) {
            return true;
        };
    };
    return false;
};

// test 
const arr = [1,2,3,4,5,6];
console.log(arr.myIncludes(2)) // true
console.log(arr.myIncludes(2, 4))   // false
           

(2)按斷言函數搜尋:find() && findIndex() 【ES6】 ALL

find()

方法傳回數組中滿足提供的測試函數的第一個元素的值,否則傳回undefined

findIndex()

方法傳回數組中滿足提供的測試函數的第一個元素的索引,若沒有找到對應元素則傳回-1

注意

  • 兩者都采用斷言函數搜尋,斷言函數接收3個參數:元素 索引 數組本身
  • 是以兩個的參數都是一個回調函數
  • 找到符合條件的元素後就不會再繼續

手寫實作

Array.prototype.myFind = function(callback) {
    if (typeof callback !== 'function') {
        throw new Error('callback must be a function');
    }
    
    const arr = this;
    for (let i = 0; i < arr.length; i++) {
        if (callback(arr[i], i, arr)) {
            return arr[i];
        };
    };
    
    return undefined;
}; 

// test
const arr = [1,2,3,4,5,6];
const res = arr.myFind((item, index, arr) => item > 4);   
console.log(res, arr);  // 5   [1,2,3,4,5,6]



// findIndex()
Array.prototype.myFindIndex = function(callback) {
    if (typeof callback !== 'function') {
        throw new Error('callback must be a function');
    }
    
    const arr = this;
    for (let i = 0; i < arr.length; i++) {
        if (callback(arr[i], i, arr)) {
            return i;
        };
    };
    
    return -1;
}; 
           

疊代方法

(1)every() 【ES5】

every()

方法測試一個數組内的所有元素是否都能通過某個指定函數的測試,它傳回一個布爾值

舉例

let arr = [3,4,5,6,7];
arr.every(item => item > 2);  // true
arr.every(item => item > 4);  // false

/*
	特點:必須每一項元素都滿足條件
*/
           

手寫實作

Array.prototype.myEvery = function(callback) {
    if (typeof callback !== 'function') {
        throw new Error('callback must be a function');
    };
    
    for (let i = 0; i < this.length; i++) {
        if (!callback(this[i], i, this)) {
            return false;
        }
    };
    return true;
};

// test
let arr = [3,4,5,6,7];
arr.myEvery(item => item > 2);  // true
arr.myEvery(item => item > 4);  // false
           

(2)some() 【ES5】

some()

方法測試數組中是不是至少有 1 個元素通過了被提供的函數測試,它傳回一個布爾值

舉例

let arr = [3,4,5,6,7];
arr.some(item => item > 2);  // true
arr.some(item => item > 4);  // true

/*
	特點:隻要有一項元素滿足即可
*/
           

手寫實作

Array.prototype.mySome = function(callback) {
    if (typeof callback !== 'function') {
        throw new Error('callback must be a function');
    };
    
    for (let i = 0; i < this.length; i++) {
        if (callback(this[i], i, this)) {
            return true;
        }
    };
    return false;
};

// test
let arr = [3,4,5,6,7];
arr.mySome(item => item > 4);  // true
arr.mySome(item => item > 8);  // false
           

(3)filter() 【ES5】

filter()

方法建立一個新數組,其包含通過所提供函數實作的測試的所有元素

舉例

let arr = [3,4,5,6,7];
arr.filter(item => item > 5);  // [ 6, 7]
           

手寫實作

// 疊代法
Array.prototype.myFilter = function(callback) {
    if (typeof callback !== 'function') {
        throw new Error('callback must be a function');
    };
    
    let res = [];
    for (let i = 0; i < this.length; i++) {
        if (callback(this[i], i, this)) {
            res.push(this[i]);
        };
    };
    return res;
};

let arr = [3,4,5,6,7];
arr.myFilter(item => item > 5);  // [ 6, 7]

// 借助reduce
Array.prototype.myFilter = function(callback) {
    if (typeof callback === 'function') {
        return this.reduce((prev, item, index, arr) => {
            if (callback(item, index, arr)) {
                prev.push(item);
            };
            return prev;
        }, [])
    } else {
        throw new Error('callback is not a fucntion');
    }
};

// test
let arr = [3,4,5,6,7];
arr.myFilter(item => item > 5);  // [ 6, 7]
           

(4)forEach() 【ES5】

forEach()

方法對數組的每個元素執行一次給定的函數,沒有傳回值,改變原數組

舉例

let arr = [3,4,5,6,7];
arr.forEach(item => item*2);
console.log(arr);  // [6,8,10,12,14]
           

手寫實作

/*
	注意: 改變原數組
	
*/
Array.prototype.myForEach = function(callback, thisArg) {
    const arr = this;
    
    for (let i = 0; i < arr.length; i++) {
        callback.call(thisArg, arr[i]);
    };
};

const obj = {
  num: 10
};
const arr = [1, 2, 3, 4, 5, 6];

arr.myForEach(function (value, index, arr) {
  console.log(value + this.num); // 依次列印:11 12 13 14 15 16
}, obj);
console.log(arr); // [1, 2, 3, 4, 5, 6]
           

(5)map() 【ES5】

map()

方法建立一個新數組,這個新數組由原數組中的每個元素都調用一次提供的函數後的傳回值組成

舉例

let arr = [3,4,5,6,7];
let newArr = arr.map(item => item*2);
console.log(newArr);  // [6,8,10,12,14]
           

注意

  • map

    僅對每一項已配置設定值得索引調用
let a = [1,2,,4];
let newA = a.map(item => item*2); // [2,4,,8]
           

手寫實作

// 疊代法
Array.prototype.myMap = function(callback) {
    if (typeof callback !== 'function') {
        throw new Error('callback must be a function');
    };
    let arr = this;
    let res = [];
    
    for (let i = 0; i < arr.length; i++) {
        let value = callback(arr[i], i, arr);
        res.push(value);
    };
    return res;
};

// test
let a = [1,2,4];
let newA = a.myMap(item => item*2); // [2,4,8]


// reduce改進 
Array.prototype.myMap = function(callback) {
    if (typeof callback !== 'function') {
        throw new Error('callback must be a function');
    };
    
    let arr = this;
    return arr.reduce((prev, curr, index, arr) => {
        prev.push(callback(curr, index, arr));
        return prev;
    }, [])
};

// test
let a = [1,2,4];
let newA = a.myMap(item => item*2); // [2,4,8]
           

歸并方法

(1)reduce() 【ES5】

reduce()

接收兩個參數:歸并函數和歸并起點的初始值

其中歸并函數接收四個參數:上一個歸并值、目前項、目前項的索引、數組本身。歸并函數傳回的任何值都會成為下一次調用同一個函數的第一個參數,即歸并值,如果沒有歸并起點的初始值,則把第一個元素作為初始值,疊代從第二個元素開始

reduce的應用詳見:強大的reduce

手寫實作

Array.prototype.myReduce = function(callbackFn, initalValue) {
    // Step1:檢驗
    if (this === null) {
        throw new Error('Array.prototype.reduce called on null or undefined');
    };
    if (typeof callbackFn !== 'function') {
        throw new Error('Callback must be a function');
    };
    
    let obj  = Object(this);
    const lenValue = obj.length;
    const len = lenValue >>> 0;
    
    if (!len && !initalValue) {
        throw new TypeError('The array contains no elements and initalValue is not provided')
    };
    
    // Step2: 确定accumulator初始值
    let k = 0;
    let accumulator;
    
    if (initalValue) {
        accumulator = initalValue;
    } else {
        let kPressent = false;
        while (!kPressent && k < len) {
            const pK = String(k);
            kPressent = obj.hasOwnProperty(pK);   // 是否有效
            if (kPressent) {
                accumulator = obj[pK];
            };
            k++;
        };
        if (!kPressent) {
           throw new TypeError('The array contains error elements'); 	
        };
    };
    
    // Step3:确定傳回值
    while (k < len) {
        if (k in obj) {
            accumulator = callbackFn(accumulator, obj[k], k, obj);
        };
        k++;
    };
    return accumulator;
};

// test
const arr = [1,2,3,4,5];
const sum = arr.myReduce((prev, curr) => prev+curr, 0);
console.log(sum);   // 15
           

(2)reduceRight() 【ES5】

reduceRight()

reduce()

唯一不同的就是周遊方向是從最後一項到第一項,其餘全部相同

其他

(1)數組扁平化:flat() 【ES6】

flat()

方法會按照一個可指定的深度遞歸周遊數組,并将所有元素與周遊到的子數組中的元素合并為一個新數組傳回

文法

參數

  • depth

    (可選):指定要提取嵌套數組的深度,預設為1
function myFlat(arr, depth = 1) {
    if (depth < 1) return arr;
    return arr.reduce((prev, curr, index, arr) => {
       return Array.isArray(curr) ? prev.concat(myFlat(curr, depth - 1)) : prev.concat(curr);
    }, [])
};

// test
const arr = [1, 2, [[3,4]]]
myFlat(arr, 1)    // [1, 2, [3,4]]
myFlat(arr, 2)    // [1, 2, 3, 4]
           

總結

(1)改變原數組方法

push

unshift

pop

shift

reverse

splice

sort

(2)ES6新增方法

Array.from

Array.of

copyWithin()

fill()

find()

findIndex()

entries()

keys()

values()

includes()

flat()

知識補充

數組空位

map和forEach的差別

強大的reduce

深淺拷貝

參考

MDN Array

繼續閱讀