新增的原型方法
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 ]
第三,當
target
、start
或者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 ]
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> ]
fill
和copyWithin
一樣,返回的也是原陣列,並且當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 ] ]
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
執行一次,這和map
、forEach
等函式是不同的。[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 }
Array.prototype.findIndex
findIndex
與find
方法基本相同,只有返回值有區別,findIndex
返回的是符合條件的元素下標,在沒有這樣的元素時,會返回-1
。keys,values,entries
函式型別:
type Keys = () => Iterator<number>; type Values = () => Iterator<any>; type Entries = () => Iterator<[number, any]>;
keys
,values
,entries
都不需要任何引數,返回的都是一個迭代器。不同點在於迭代器中的值分別是陣列的下標、陣列的元素以及陣列的下標和陣列元素組成的[ 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 }