JavaScript陣列常用方法解析和深層次js陣列扁平化

程式設計師布歐 發表於 2022-05-18
JavaScript

前言

陣列作為在開發中常用的集合,除了for迴圈遍歷以外,還有很多內建物件的方法,包括map,以及陣列篩選元素filter等。

注:文章結尾處附深層次陣列扁平化方法操作。

作為引用資料型別的一種,在處理陣列Array的時候,我們需要考慮到深拷貝和淺拷貝的情況
可以參考以下文章

常用陣列操作方法

push末尾追加元素

/**
 * @param push 將一個或多個元素新增到陣列的末尾,返回該陣列的新長度
 *
 * 集合apply和call合併陣列
 *
 */
let user = ["zhangsan", "lisi"];
console.log(user.push("xiaoming")); //	3
console.log(user); // ["zhangsan", "lisi", "xiaoming"]
let user1 = ["xiaowang", "xiaoming"];
let user2 = ["zhangsan", "lisi"];
console.log(Array.prototype.push.apply(user1, user2)); // 	4
console.log(user1); // ["xiaowang", "xiaoming", "zhangsan", "lisi"]

pop刪除陣列末尾元素

/**
 *
 * @param pop 方法從陣列中刪除最後一個元素,返回值是該元素。
 *
 * 如果陣列是空陣列,那麼返回的是undefined
 *
 */
let user = ["zhangsan", "lisi"];
console.log(user.pop()); //	lisi
console.log(user); //	["zhangsan"]
let empArray = [];
console.log(empArray.pop()); //	undefined

sort排序

/**
 *
 * @param sort
 *
 * 使用原地演算法對陣列的元素進行排序,並返回陣列。
 * 預設排序順序是在將元素轉換為字串,然後比較它們的UTF-16程式碼單元值序列時構建的
 * 由於它取決於具體實現,因此無法保證排序的時間和空間複雜性。
 *
 * arr.sort([compareFunction])
 *
 * @param compareFunction
 *
 * 用來指定按某種順序進行排列的函式。
 * 如果省略,元素按照轉換為的字串的各個字元的Unicode位點進行排序。
 *
 * 如果沒有指明 compareFunction ,那麼元素會按照轉換為的字串的諸個字元的Unicode位點進行排序。
 * 例如 "Banana" 會被排列到 "cherry" 之前。
 * 當數字按由小到大排序時,9 出	* 現在 80 之前,但因為(沒有指明 compareFunction),比較的數字會先被轉換為字串,所以在Unicode順序上 "80" 要比 "9" 要靠前。
 * 如果指明瞭 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) 必須總是對相同的輸入返回相同的比較結果,否則排序的結果將是不確定的。
 *
 * firstEl
 * 第一個用於比較的元素。
 * secondEl
 * 第二個用於比較的元素
 *
 */
/**
 *
 * 基本用法
 *
 * */

const user = ["zhangsan", "lisi", "xiaoming", "xiaowang"];
user.sort();
console.log(user); // ["lisi", "xiaoming", "xiaowang", "zhangsan"]
const array1 = [1, 30, 4, 21, 100000];
array1.sort();
console.log(array1); // [1, 100000, 21, 30, 4]

/**
 *
 * 自定義排序方法
 *
 * */
var numbers = [4, 2, 5, 1, 3];
let sortFun = function (a, b) {
  return a - b;
};
numbers.sort(sortFun);
console.log(numbers); // [1, 2, 3, 4, 5]

shift陣列開頭新增元素 && unshift陣列開頭刪除元素

/**
 *
 * @param shift
 * 從陣列中刪除第一個元素,並返回該元素的值,如果刪除空陣列,返回值是undefined
 *
 * @param unshift
 * 方法將一個或多個元素新增到陣列的開頭,並返回該陣列的新長度
 *
 * */
let user = ["zhangsan", "lisi"];
console.log(user.shift()); //	zhangsan
console.log(user); //	["lisi"]
let empArray = [];
console.log(empArray.shift()); //	undefined
let user1 = ["xiaoming", "xiaowang"];
console.log(user1.unshift("xiaoming1", "xiaowang1")); //	4
console.log(user1); //	["xiaoming1", "xiaowang1", "xiaoming", "xiaowang"]

陣列合並concat


/**
 *
 * @param concat
 *
 * 方法用於合併兩個或多個陣列。返回值是新陣列,原陣列不會發生更改
 *
 * 注:陣列合並是淺拷貝
 *
 */
let user = ["zhangsan", "lisi"];
let user1 = [["xiaowang"], { name: "xiaoming" }];
console.log(user.concat(user1)); // ["zhangsan","lisi",["xiaowang"],{name: "xiaoming"}]
console.log(user); // ["zhangsan", "lisi"]

indexOf查詢元素 && includes查詢元素是否存在

/**
 *
 * @param indexOf
 *
 * 返回在陣列中可以找到一個給定元素的第一個索引,如果不存在,則返回-1,
 * 常用於判斷陣列是否存在某個元素
 *
 * @param includes
 *
 * 判斷一個陣列是否包含一個指定的值,返回值是布林值 true 或者 false
 *
 */
let user = ["zhangsan", "lisi"];
console.log(user.indexOf("lisi")); // 1
console.log(user.indexOf("xiaoming")); // -1
let user1 = ["zhangsan", ["xiaowang"], { name: "xiaoming" }];
console.log(user1.includes("zhangsan")); // true
console.log(user1.includes(["xiaowang"])); // false
console.log(user1.includes({ name: "xiaoming" })); // false

reverse反轉陣列

/**
 *
 * @param reverse
 *
 * 反轉陣列元素,將原有陣列倒敘顯示,會改變元素的元素位置
 *
 */
let user = ["zhangsan", "lisi", "xiaoming"];
console.log(user.reverse()); // ["xiaoming", "lisi", "zhangsan"]
console.log(user); // ["xiaoming", "lisi", "zhangsan"]
let user1 = ["zhangsan", ["xiaowang", "lisi"], { name: "xiaoming" }];
console.log(user1.reverse()); // [{name: "xiaoming"},["xiaowang", "lisi"],"zhangsan"]

陣列切割成字串join

/**
 *
 * @param join
 *
 * 根據傳入的引數字串,對陣列進行切割,返回值是使用引數拼接元素的字串
 * 如果陣列只有一個元素,則不使用分割符號
 *
 */
let user = ["zhangsan", "lisi", "xiaoming"];
console.log(user.join(" ")); // zhangsan lisi xiaoming
console.log(user.join("")); // zhangsanlisixiaoming
console.log(user.join(",")); // zhangsan,lisi,xiaoming
console.log(user.join({ a: 1 })); // zhangsan[object Object]lisi[object Object]xiaoming
console.log(user); // ["zhangsan", "lisi", "xiaoming"]

slice運算元組,替換,刪除,新增

slice使用的範圍較廣,不同的引數可以實現對陣列的刪除,新增和替換等,使用的時候需要注意引數的具體使用方法

/**
 *
 * @param slice
 *
 * 返回一個新的陣列物件,
 * 這一物件是一個由 begin 和 end 決定的原陣列的淺拷貝(包括 begin,不包括end)。原始陣列不會被改變。
 *
 * @param begin
 * 提取起始處的索引(從 0 開始),從該索引開始提取原陣列元素。
 * 如果該引數為負數,則表示從原陣列中的倒數第幾個元素開始提取,slice(-2) 表示提取原陣列中的倒數第二個元素到最後一個元素(包含最後一個元素)。
 * 如果省略 begin,則 slice 從索引 0 開始。
 * 如果 begin 超出原陣列的索引範圍,則會返回空陣列
 *
 * @param end
 *
 * 提取終止處的索引(從 0 開始),在該索引處結束提取原陣列元素。
 * slice 會提取原陣列中索引從 begin 到 end 的所有元素(包含 begin,但不包含 end)。
 * slice(1,4) 會提取原陣列中從第二個元素開始一直到第四個元素的所有元素 (索引為 1, 2, 3的元素)。
 * 如果該引數為負數, 則它表示在原陣列中的倒數第幾個元素結束抽取。
 * slice(-2,-1) 表示抽取了原陣列中的倒數第二個元素到最後一個元素(不包含最後一個元素,也就是隻有倒數第二個元素)。
 * 如果 end 被省略,則 slice 會一直提取到原陣列末尾。如果 end 大於陣列的長度,slice 也會一直提取到原陣列末尾。
 *
 */
const animals = ["ant", "bison", "camel", "duck", "elephant"];
console.log(animals.slice(2)); // Array ["camel", "duck", "elephant"]
console.log(animals.slice(2, 4)); // Array ["camel", "duck"]
console.log(animals.slice(1, 5)); // Array ["bison", "camel", "duck", "elephant"]
console.log(animals.slice(-2)); // Array ["duck", "elephant"]
console.log(animals.slice(2, -1)); // Array ["camel", "duck"]
console.log(animals.slice()); // Array ["ant", "bison", "camel", "duck", "elephant"]
/**
 *
 * @param splice(start[, deleteCount[, item1[, item2[, ...]]]])
 *
 * 通過刪除或替換現有元素或者原地新增新的元素來修改陣列,並以陣列形式返回被修改的內容。此方法會改變原陣列
 *
 * 由被刪除的元素組成的一個陣列。如果只刪除了一個元素,則返回只包含一個元素的陣列。如果沒有刪除元素,則返回空陣列。
 *
 * @param start
 *
 * 指定修改的開始位置,預設從下標0開始。
 * 如果超出了陣列的長度,則從陣列末尾開始新增元素;
 * 如果是負值,則表示從陣列末位開始的第幾位(從-1計數,這意味著-n是倒數第n個元素並且等價於array.length-n);
 * 如果負數的絕對值大於陣列的長度,則表示開始位置為第0位。
 *
 * @param deleteCount
 *
 * 整數,表示要移除的陣列元素的個數。
 * 如果 deleteCount 大於 start 之後的元素的總數,則從 start 後面的元素都將被刪除(含第 start 位)。
 * 如果 deleteCount 被省略了,
 * 或者它的值大於等於array.length - start(也就是說,如果它大於或者等於start之後的所有元素的數量),
 * 那麼start之後陣列的所有元素都會被刪除。
 *
 * 如果 deleteCount 是 0 或者負數,則不移除元素。這種情況下,至少應新增一個新元素。
 * @param item1, item2, ...
 *
 * 要新增進陣列的元素,從start 位置開始。如果不指定,則 splice() 將只刪除陣列元素
 *
 */
const months = ["Jan", "March", "April", "June"];
months.splice(1, 0, "Feb"); // 下表為1,插入一個元素
console.log(months); // ["Jan", "Feb", "March", "April", "June"]
months.splice(4, 1, "May"); // 替換下標為4的元素
console.log(months); // ["Jan", "Feb", "March", "April", "May"]
let del = months.splice(1, 1); // 刪除
console.log(del); // ["Feb"]
console.log(months); // ["Jan", "April", "May"]

every校驗陣列所有元素

/**
 *
 * @param every
 * 測試一個陣列內的所有元素是否都能通過某個指定函式的測試,返回值是布林值 true or false
 * 備註:若收到一個空陣列,此方法在任何情況下都會返回 true。
 *
 * arr.every(callback(element[, index[, array]])[, thisArg])
 * callback
 * 用來測試每個元素的函式,它可以接收三個引數:
 *
 * @param element 用於測試的當前值。
 * @param index可選 用於測試的當前值的索引。
 * @param array可選 呼叫 every 的當前陣列。
 *
 * every 方法為陣列中的每個元素執行一次 callback 函式,直到它找到一個會使 callback 返回 false 的元素。
 * 如果發現了一個這樣的元素,every 方法將會立即返回 false。
 * 否則,callback 為每一個元素返回 true,every 就會返回 true。
 *
 * callback 只會為那些已經被賦值的索引呼叫。不會為那些被刪除或從未被賦值的索引呼叫。
 * callback 在被呼叫時可傳入三個引數:元素值,元素的索引,原陣列。
 * 如果為 every 提供一個 thisArg 引數,則該引數為呼叫 callback 時的 this 值。
 * 如果省略該引數,則 callback 被呼叫時的 this 值,在非嚴格模式下為全域性物件,在嚴格模式下傳入 undefined。
 *
 *
 * every 不會改變原陣列。
 * every 遍歷的元素範圍在第一次呼叫 callback 之前就已確定了。
 * 在呼叫 every 之後新增到陣列中的元素不會被 callback 訪問到。
 * 如果陣列中存在的元素被更改,則他們傳入 callback 的值是 every 訪問到他們那一刻的值。
 * 那些被刪除的元素或從來未被賦值的元素將不會被訪問到。
 *
 * */
const isBelowThreshold = (currentValue) => currentValue < 40;
const array1 = [1, 30, 39, 29, 10, 13];
console.log(array1.every(isBelowThreshold)); // true

some 測試陣列中是不是至少有1個元素通過了被提供的函式測試。返回值是布林值

/**
 *
 * @param some 測試陣列中是不是至少有1個元素通過了被提供的函式測試。返回值是布林值
 *
 * */
const array = [1, 2, 3, 4, 5];
const even = (element) => element % 2 === 0; //確認偶數
console.log(array.some(even)); // true;

深層次遞迴陣列flat


/**
 * @param flat	按照一個可指定的深度遞迴遍歷陣列,並將所有元素與遍歷到的子陣列中的元素合併為一個新陣列返回。
 *
 * var newArray = arr.flat([depth])
 * @depth  指定要提取巢狀陣列的結構深度,預設值為 1。
 * */
let arr1 = [1, 2, [3, 4]];
console.log(arr1.flat()); // [1, 2, 3, 4]
let arr2 = [1, 2, [3, 4, [5, 6]]];
console.log(arr2.flat()); // [1, 2, 3, 4, [5, 6]]
let arr3 = [1, 2, [3, 4, [5, 6]]];
console.log(arr3.flat(2)); // [1, 2, 3, 4, 5, 6]
//使用 Infinity,可展開任意深度的巢狀陣列
let arr4 = [1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]];
console.log(arr4.flat(Infinity)); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let objArray = [{ name: "zhangsan", children: ["張三"] }];
console.log(objArray.flat(Infinity)); // [{ name: "zhangsan", children: ["張三"] }]

map遍歷陣列

/**
 * @param map
 *
 * 建立一個新陣列,這個新陣列由原陣列中的每個元素都呼叫一次提供的函式後的返回值組成
 *
 * */
const array1 = [1, 4, 9, 16];
const map1 = array1.map((x) => x * 2);
console.log(map1); // [2, 8, 18, 32]

reduce和filter

reduce和filter的基本操作方法在之前的文章有提到過,這裡不做複述

文章地址JavaScript 陣列方法filter和reduce

陣列操作示例:

陣列物件根據屬性整理陣列

/**
 * 按照陣列物件某個屬性整理資料
 *
 * */
let user1 = [
  { name: "zhangsan", age: 21 },
  { name: "lisi", age: 20 },
  { name: "xiaoming", age: 20 },
];
function groupBy(objectArray, property) {
  return objectArray.reduce(function (acc, obj) {
    let key = obj[property];
    if (!acc[key]) {
      acc[key] = [];
    }
    acc[key].push(obj);
    return acc;
  }, {});
}
let ageList = groupBy(user1, "age");
console.log(ageList); // {[{name: "lisi", age: 20},{name: "xiaoming", age: 20}],[{name: "zhangsan", age: 21}]}


陣列扁平化-深層次

function flatten(array) {
  var flattend = [];
  (function flat(array) {
    array.forEach(function (el) {
      for (let i in el) {
        if (Object.prototype.toString.call(el[i]) === "[object Array]")
          flat(el[i]);
      }
      flattend.push(el);
    });
  })(array);
  return flattend;
}
let user2 = [
  {
    name: "zhangsan",
    age: 20,
    child: [{ name: "xiaoming" }],
    child1: [{ name: "xiaowang" }],
  },
];
let flattenArray = flatten(user2);
console.log(flattenArray);

結尾

以上就是JavaScript中陣列較為常用的方法,其他沒有提及的方法,需要的同學可以查閱相關文章,或者留言,後續的文章整理然後作為補充。

原始碼地址

文章部落格地址:JavaScript陣列常用方法解析和深層次js陣列扁平化

歡迎關注公眾號:程式設計師布歐,不定期更新一些文章

創作不易,轉載請註明出處和作者。