ES6新增API:Array篇(二)

forceddd 發表於 2021-11-30
JavaScript ES6

新增的原型方法

  1. Array.prototype.copyWithin

    函式型別:

    /**
    * @author: forceddd
    * @desc:  將陣列中的,從start位置開始至end位置(不包含end處的元素)結束的元素,進行淺複製,並從target處開始覆蓋該陣列。最後將修改後的陣列返回
    * @param {number} target 複製到陣列的起始覆蓋位置,預設值為0
    * @param {number} start 開始複製元素的位置,預設值為0
    * @param {number|undefined} end 結束複製元素的位置,預設值為陣列長度
    * @return {any[]} 改變之後的陣列
    */
    <T>(target?: number, start?: number, end?: number | undefined)=> T[]

    copyWithin將陣列中的,從start位置開始至end位置(包含end處的元素)結束的元素,進行淺複製,並從target處開始覆蓋該陣列。最後將修改後的陣列返回。

    //不傳入引數時,都使用預設值,相當於 [1, 2, 3].copyWithin(0,0,3)
    //首先複製了陣列中的[ 0, 3 )的部分,即[1,2,3]
    //然後從陣列的下標0處開始覆蓋,覆蓋之後得到[1, 2, 3]
    console.log([1, 2, 3].copyWithin()); //[ 1, 2, 3 ]
    //從陣列的下標1處開始覆蓋,複製的部分為[1, 2, 3],從原陣列的下標1處開始覆蓋,原陣列只剩餘兩個位置,所以結果為[ 1, 1, 2 ]
    console.log([1, 2, 3].copyWithin(1)); //[ 1, 1, 2 ]

    有幾點需要注意的是:

    第一,copyWithin會修改原陣列,返回的是修改之後的原陣列,而不是建立的一個新陣列。

    const arr = [1, 2, 3];
    const res = arr.copyWithin(1, 0);
    
    console.log(arr === res, arr);//true [ 1, 1, 2 ]

    第二,當target>=arr.length時,不會發生複製行為,直接返回沒有進行任何修改的原陣列。

    const arr = [1, 2, 3];
    const res = arr.copyWithin(6, 2);
    //返回沒有進行任何修改的原陣列
    console.log(arr === res, arr); //true [ 1, 2, 3 ]

    第三,當targetstart或者end傳入負數時,代表此時的從陣列末尾開始計算,假如傳入的值是-1,就代表倒數第一個元素的位置。

    const arr = [1, 2, 3];
    const res = arr.copyWithin(-2, 2);
    //從下標2開始複製得到的複製部分為 [ 3 ]
    //從-2,即倒數第二個元素開始覆蓋,就得到了 [1, 3, 3 ]
    console.log(arr === res, arr); //true [ 1, 3, 3 ]
  2. Array.prototype.fill

    函式型別:

    /**
    * @author: forceddd
    * @desc: 將陣列從start位置開始至end結束(不包括end)的部分都賦值為value
    * @param {any} value 用來給陣列中元素賦值的值
    * @param {number} start 賦值的起始位置,預設為0
    * @param {number} end 賦值的結束位置,預設為陣列的長度
    * @return {*} 返回值為賦值之後的原陣列
    */
    (value?: any, start?: number, end?: number) => any[];

    fill 將陣列從start位置開始至end結束(不包括end)的部分都賦值為value,然後將陣列返回。

    console.log(Array(4).fill()); //[ undefined, undefined, undefined, undefined ]
    console.log(Array(4).fill(0)); //[ 0, 0, 0, 0 ]
    console.log(Array(4).fill(0, 1, 2)); //[ <1 empty item>, 0, <2 empty items> ]

    fillcopyWithin一樣,返回的也是原陣列,並且當start或者end負數時,也是和copyWithin相同的處理方式。

    除此之外,從程式碼中也可以看出,fill會產生空位元素,而且如果value值為物件,則賦值時使用的是物件的引用。換句話說:

    const v = [];
    const arr = Array(4).fill(v);
    console.log(arr[0] === arr[1]); //true
    arr[0].push(1);
    console.log(arr);//[ [ 1 ], [ 1 ], [ 1 ], [ 1 ] ]
  3. Array.prototype.find

    函式型別:

    /**
    * @author: forceddd
    * @desc:   找到陣列中使得findFn返回值為true的第一個元素並將其返回
    * @param {FindFn} findFn 陣列每一項上執行的函式
    * @param {any} thisArg 回撥函式findFn中的this物件
    * @return {*}
    */
    (findFn: FindFn, thisArg?: any) => any;
    /**
    * @author: forceddd
    * @param {any} item 陣列中的元素
    * @param {number} index 當前元素在陣列中的下標
    * @param {any} arr 陣列例項
    * @return {boolean} 
    */
    type FindFn = (item: any, index: number, arr: any[]) => boolean;

    find會返回陣列中使得回撥函式返回值為true第一個元素,如果沒有這樣的元素,會返回undefined

    console.log([1, 2, 3].find((v) => v >= 2));//2
    在ES6之前,使用indexOf方法需要進行嚴格匹配(===)才能判定元素是否存在,使用some方法雖然可以自定義比對的回撥函式,但是隻能返回boolean,而不能獲得元素本身。

    需要注意的是,find中回撥函式的執行次數是根據陣列的下標決定的,下標 [ 0 , arr.length - 1 ] 的範圍都會執行一次,它不關心當前元素的值,所以在當前元素是空位元素的時候,find中的回撥函式會把元素值作為undefined執行一次,這和mapforEach等函式是不同的。

    [1, , 3, 4].find((v) => console.log(v)); //1 undefined 3 4
    [1, , 3, 4].map((v) => console.log(v)); //1 3 4

    另外,當find中的回撥函式第一次執行時,它的執行次數 [ 0 , arr.length - 1 ] 就已經確定了,並且不會再改變。這也就意味著,假設我們要處理的陣列arr長度為5,在回撥函式執行的過程中,我們修改了arr,使其長度成為了10,或者我們刪除了一個元素,使其長度變為4,回撥函式都會執行5次。當元素被刪除的情況下,回撥函式在執行時訪問不到該元素,會以undefined代替該元素繼續執行。

    [1, 2, 3, 4].find((v, i, arr) => {
    //刪除一個元素
    i === 0 && arr.pop();
    console.log({ v, i });
    }); 
    //{ v: 1, i: 0 }
    //{ v: 2, i: 1 }
    //{ v: 3, i: 2 }
    //{ v: undefined, i: 3 }
  4. Array.prototype.findIndex

    findIndexfind方法基本相同,只有返回值有區別,findIndex返回的是符合條件的元素下標,在沒有這樣的元素時,會返回-1

  5. keys,values,entries

    函式型別:

    type Keys = () => Iterator<number>;
    type Values = () => Iterator<any>;
    type Entries = () => Iterator<[number, any]>;

    keysvaluesentries都不需要任何引數,返回的都是一個迭代器。不同點在於迭代器中的值分別是陣列的下標、陣列的元素以及陣列的下標和陣列元素組成的 [ i , v ] 形式的鍵值對。

    const it = ['a', 'b', 'c'].entries();
    console.log(it.next()); //{ value: [ 0, 'a' ], done: false }
    console.log(it.next()); //{ value: [ 1, 'b' ], done: false }
    console.log(it.next()); //{ value: [ 2, 'c' ], done: false }
    console.log(it.next()); // { value: undefined, done: true }