閱讀lodash源碼之旅數組方法篇-compact和concat
- 2021 年 1 月 24 日
- 筆記
魯迅說過:只有閱讀過優秀庫源碼的人,才能配的上是真正的勇士。
compact
創建一個新數組,包含原數組中所有的非假值元素。例如false, null,0, 「」, undefined, 和 NaN 都是被認為是「假值」。
注意以上的描述並不包括[],{}因為在js中,這個兩個會進行隱式轉換會把這兩個值轉換成為true。換句話來說該函數並不會去過濾這兩個值。
官方代碼:
export function compact(array){
let resIndex = 0;
const result = []
if(array == null){ // 會把undefined給排除掉 因為 undefined == null 為true
return result
}
for(const value of array){
if(value){
result[resIndex++] = value
}
}
return result
}
個人理解代碼:
export function compact(array){
let resIndex = 0;
const result = []
if(array == null){ // 會把undefined給排除掉 因為 undefined == null 為true
return result
}
result = array.filter(v=>Boolean(v))
return result
}
直接利用filter進行遍歷,利用boolean,來對元素進行真假轉換。
concat
創建一個新數組,將array與任何數組 或 值連接在一起。
var array = [1];
var other = _.concat(array, 2, [3], [[4]]);
console.log(other);
// => [1, 2, 3, [4]]
console.log(array);
// => [1]
相對來說,concat函數所依賴的工具函數就多幾個。
- arrayPush數組添加方法
- copyArray拷貝數組元素
- baseFlatten扁平層級數組
export function concat(){
let length = arguments.length; // 獲取參數的個數
if (!length) {
return [];
}
let args = Array(length - 1); // 取除了第一個參數以外的參數的長度
let array = arguments[0]; // 取出數組的第一項
let index = length;
while (index--) {
args[index - 1] = arguments[index];
}
console.log(args); // 把第一個參數也就是目標數組,當作-1項添加為array
// 判斷一個參數是否是數組,不是就把它轉換成為數組,如果是數組則拷貝一份數組,再使用arrayPush方法,把每項的參數推進數組裏面去。
return arrayPush(Array.isArray(array) ? copyArray(array) : [array], baseFlatten(args, 1));
}
copyArray
拷貝數組,此操作不會影響到原有的數組。
參數 | 說明 |
---|---|
soure | 原數組參數 |
array | 結果數組 |
export function copyArray(source,array){
let index = -1;
let length = source.length;
array || (array = Array(length));
while(++index < length){
array[index] = source[index]
}
return array
}
baseFlatten
該方法主要用於扁平數組的操作
export function baseFlatten(array, depth, predicate, isStrict, result) {
let index = -1;
let length = array.length;
predicate || (predicate = isFlattenable); // isFlattenable 判斷是否是數組
result || (result = []);
while (++index < length) {
let value = array[index];
console.log(value);
if (depth > 0 && predicate(value)) { // 如果層級大於0並且該項是數組的話
if (depth > 1) { // 如果需要遞歸的層級大於1的情況則繼續遞歸下去解套
baseFlatten(value, depth - 1, predicate, isStrict, result);
} else { // 如果需要遞歸的層級為1的情況,則把所有的項添加目標數組
arrayPush(result, value);
}
} else if (!isStrict) {
result[result.length] = value;
}
}
return result;
}
isFlattenable(value){
return Array.isArray(value)
}
發散思考,該函數只要是通過depth變量,來控制篩選的層級,那麼我希望實現扁平所有的數組,那應該怎麼操作呢?
function flattern(arr) {
return arr.reduce((cur, next) => cur.concat(Array.isArray(next) ? flattern(next) : next), []);
}
arrayPush
添加元素進入原數組,會改變原數組結構,類似push方法
let index = -1;
let length = values.length;
let offset = array.length;
while (++index < length) {
array[index + offset] = values[index];
}
return array;
總結
- ++index和index++不同之處,++i就是先加後用,i++就是先用後加。前置++下標不會越界,後置++下標越界。
- lodash庫操作數組一般都不會影響原有數組。