JavaScript30秒, 從入門到放棄

supermao發表於2017-12-25

有意思

最近很火的github上的庫30-seconds-of-code,特別有意思,程式碼也很優雅。

  1. 能學es6
  2. 自己翻譯,能學英語
  3. 程式碼很美,很優雅,美即正義
  4. 函式式表達,享受

arrayGcd

Calculates the greatest common denominator (gcd) of an array of numbers.

Use Array.reduce() and the gcd formula (uses recursion) to calculate the greatest common denominator of an array of numbers.

const arrayGcd = arr =>{
  const gcd = (x, y) => !y ? x : gcd(y, x % y);
  return arr.reduce((a,b) => gcd(a,b));
}
// arrayGcd([1,2,3,4,5]) -> 1
// arrayGcd([4,8,12]) -> 4
複製程式碼

計算陣列的最大公約數。

使用Array.reduce()gcd公式(使用遞迴)來計算一個陣列的最大公約數。

➜  code cat arrayGcd.js
const arrayGcd = arr => {
    const gcd = (x, y) => !y ? x : gcd(y, x % y);
    return arr.reduce((a, b) => gcd(a, b));
}

console.log(arrayGcd([1, 2, 3, 4, 5]));
console.log(arrayGcd([4, 8, 12]));
➜  code node arrayGcd.js
1
4
複製程式碼

gcd即歐幾里德演算法,具體不表,自查。這裡用到了陣列的reduce方法,相當簡潔,reduce不太瞭解的話,看下mdn就明白。

arrayLcm

Calculates the lowest common multiple (lcm) of an array of numbers.

Use Array.reduce() and the lcm formula (uses recursion) to calculate the lowest common multiple of an array of numbers.

const arrayLcm = arr =>{
 const gcd = (x, y) => !y ? x : gcd(y, x % y);
 const lcm = (x, y) => (x*y)/gcd(x, y) 
 return arr.reduce((a,b) => lcm(a,b));
}
// arrayLcm([1,2,3,4,5]) -> 60
// arrayLcm([4,8,12]) -> 24
複製程式碼

計算一個陣列的最小公倍數。

使用Array.reduce()lcm公式(使用遞迴)來計算一個陣列的最大公約數。

➜  code cat arrayLcm.js
const arrayLcm = arr => {
  const gcd = (x, y) => (!y ? x : gcd(y, x % y));
  const lcm = (x, y) => x * y / gcd(x, y);
  return arr.reduce((a, b) => lcm(a, b));
};

console.log(arrayLcm([1, 2, 3, 4, 5]));
console.log(arrayLcm([4, 8, 12]));
➜  code node arrayLcm.js
60
24
複製程式碼

lcm演算法用到了前面的gcd演算法,關鍵點是兩個數的最大公約數和最小公倍數的乘積正好就是這兩個數的乘積。

arrayMax

Returns the maximum value in an array.

Use Math.max() combined with the spread operator (...) to get the maximum value in the array.

const arrayMax = arr => Math.max(...arr);
// arrayMax([10, 1, 5]) -> 10
複製程式碼

返回陣列中最大的值。

使用Math.max()ES6的擴充套件運算子返回陣列中最大的值。

➜  code cat arrayMax.js
const arrayMax = arr => Math.max(...arr);

console.log(arrayMax([10, 1, 5]));
➜  code node arrayMax.js
10
複製程式碼

實際上就是Math.max()乾的事,沒啥可說的了。

arrayMin

Returns the minimum value in an array.

Use Math.min() combined with the spread operator (...) to get the minimum value in the array.

const arrayMin = arr => Math.min(...arr);
// arrayMin([10, 1, 5]) -> 1
複製程式碼

返回陣列中最小的值。

使用Math.min()ES6的擴充套件運算子返回陣列中最小的值。

➜  code cat arrayMin.js
const arrayMin = arr => Math.min(...arr);

console.log(arrayMin([10, 1, 5]));
➜  code node arrayMin.js
1
複製程式碼

實際上就是Math.min()乾的事,沒啥可說的了。

chunk

Chunks an array into smaller arrays of a specified size.

Use Array.from() to create a new array, that fits the number of chunks that will be produced. Use Array.slice() to map each element of the new array to a chunk the length of size. If the original array can't be split evenly, the final chunk will contain the remaining elements.

const chunk = (arr, size) =>
 Array.from({length: Math.ceil(arr.length / size)}, (v, i) => arr.slice(i * size, i * size + size));
// chunk([1,2,3,4,5], 2) -> [[1,2],[3,4],[5]]
複製程式碼

按照給定的size將一個陣列切分成含有size個數的更小陣列塊的陣列。

使用Array.from()生產新的符合定義的陣列。使用Array.slice()來擷取指定size個元素組成新的陣列塊。如果原陣列長度不能被size整除,最後的剩餘的那些元素將歸屬於最後一個塊。

➜  code cat chunk.js
const chunk = (arr, size) =>
  Array.from({ length: Math.ceil(arr.length / size) }, (v, i) =>
    arr.slice(i * size, i * size + size)
  );

console.log(chunk([1, 2, 3, 4, 5], 2));
➜  code node chunk.js
[ [ 1, 2 ], [ 3, 4 ], [ 5 ] ]
複製程式碼

Array.from(arrayLike, mapFn, thisArg)這個方法呢,第一個引數是一個類陣列或者可迭代的物件,第二個引數是一個應用在每一個陣列元素上的方法,第三個引數就是改變this的指向了。通俗說就是指定誰是你的爸爸。

這裡用了一個{ length: Math.ceil(arr.length / size) }迭代物件,length指定了迭代次數,它正好按照size分塊後的陣列長度正好就是原陣列長度除以size向上取整的值。向上取整就是為了滿足不能完全整除的情況。比如5個元素按照2個進行分塊,分了兩塊兩個元素的,剩最後一個元素成了獨立塊,總共3個元素。

(v, i),由於迭代的時候陣列在每一個位置上都是以undefined初始化的,所以v一直都是undefined

arr.slice(i * size, i * size + size)迭代過程中每次擷取size個數的元素組成新陣列。這裡的i就是隨著迭代變化,比如length是3,i就是0,1,2。

這裡的迭代類似python裡的range

➜  code python
Python 3.6.4 (default, Dec 23 2017, 10:37:40)
[GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.39.2)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import math
>>> arr = [1,2,3,4,5]
>>> size = 2
>>> for i in range(math.ceil(len(arr) / size)):
...     print('index: ', i)
...
index:  0
index:  1
index:  2
複製程式碼

compact

Removes falsey values from an array.

Use Array.filter() to filter out falsey values (false, null, 0, "", undefined, and NaN).

const compact = arr => arr.filter(Boolean);
// compact([0, 1, false, 2, '', 3, 'a', 'e'*23, NaN, 's', 34]) -> [ 1, 2, 3, 'a', 's', 34 ]
複製程式碼

移除掉陣列裡falsey的元素。(這個falsey不太好翻譯,我記得好像不是錯誤的,應該是該值布林運算值為false的,我個人常用!!進行運算)。

使用Array.filter()falsenull0""undefinedNaN這些falsey過濾掉。

➜  code cat compact.js
const compact = arr => arr.filter(Boolean);

console.log(compact([0, 1, false, 2, "", 3, "a", "e" * 23, NaN, "s", 34]));
➜  code node compact.js
[ 1, 2, 3, 'a', 's', 34 ]
複製程式碼

Array.prototype.filter()乾的,沒啥好說。

countOccurrences

Counts the occurrences of a value in an array.

Use Array.reduce() to increment a counter each time you encounter the specific value inside the array.

const countOccurrences = (arr, value) => arr.reduce((a, v) => v === value ? a + 1 : a + 0, 0);
// countOccurrences([1,1,2,1,2,3], 1) -> 3
複製程式碼

統計一個元素在一個陣列中出現的次數。

使用Array.reduce()在遍歷過程中如果指定元素在陣列中出現,則增加它的次數值,預設次數為0。

➜  code cat countOccurrences.js
const countOccurrences = (arr, value) =>
  arr.reduce((a, v) => (v === value ? a + 1 : a + 0), 0);

console.log(countOccurrences([1, 1, 2, 1, 2, 3], 1));
console.log(countOccurrences([1, 1, 2, 1, 2, 3], 5));
➜  code node countOccurrences.js
3
0
複製程式碼

三元運算子(v === value ? a + 1 : a + 0)遍歷過程中判斷遍歷陣列值v是否嚴格等於指定值value,是,次數a+1;否,a+0

最後的一個逗號後面的0,是這個初始值,即a=0,這個懂reduce方法都知道,特別指出是,因為這個函式一定會有返回值,如果指定元素沒有在陣列中出現一次,返回值是0,所以必須得初始化為0

deepFlatten

Deep flattens an array.

Use recursion. Use Array.concat() with an empty array ([]) and the spread operator (...) to flatten an array. Recursively flatten each element that is an array.

const deepFlatten = arr => [].concat(...arr.map(v => Array.isArray(v) ? deepFlatten(v) : v));
// deepFlatten([1,[2],[[3],4],5]) -> [1,2,3,4,5]
複製程式碼

深度攤平一個陣列。

使用遞迴方法。結合Array.concat()、空陣列[]ES6的擴充套件運算子來攤平一個陣列,如果攤平的元素還是一個陣列,就再遞迴運用該方法。

➜  code cat deepFlatten.js
const deepFlatten = arr =>
  [].concat(...arr.map(v => (Array.isArray(v) ? deepFlatten(v) : v)));

console.log(deepFlatten([1, [2], [[3], 4], 5]));
➜  code node deepFlatten.js
[ 1, 2, 3, 4, 5 ]
複製程式碼

三元運算子(Array.isArray(v) ? deepFlatten(v) : v)判斷v是否是一個陣列,是,返回遞迴運用deepFlatten(v)後的值;否,直接返回v

[].concat(...arr.map(fn))用空陣列把map運算產生的陣列進行擴充套件運算值拼接成結果陣列返回。

該方法是深度攤平方法,在很多時候還有特定的攤平一層的需求,underscore就有。實現的方法就是再加一個標誌引數進行處理即可。具體不講了。

應該會寫一個系列,今天先寫到這,明天繼續。

個人翻譯水平有限,歡迎大家在issues上批評指正。JavaScript30秒, 從入門到放棄

相關文章