閱讀lodash原始碼之旅陣列方法篇-compact和concat

程式設計我的一切發表於2021-01-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函式所依賴的工具函式就多幾個。

  1. arrayPush陣列新增方法
  2. copyArray拷貝陣列元素
  3. 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;

總結

  1. ++index和index++不同之處,++i就是先加後用,i++就是先用後加。前置++下標不會越界,後置++下標越界。
  2. lodash庫運算元組一般都不會影響原有陣列。

相關文章