all([4, 2, 3], x => x > 1); // true
all([1, 2, 3]); // true
複製代碼2. allEqual:檢查數組各項相等
const allEqual = arr => arr.every(val => val === arr[0]);算法
allEqual([1, 2, 3, 4, 5, 6]); // false
allEqual([1, 1, 1, 1]); // true
複製代碼3. approximatelyEqual:約等於
const approximatelyEqual = (v1, v2, epsilon = 0.001) => Math.abs(v1 - v2) < epsilon;數組
approximatelyEqual(Math.PI / 2.0, 1.5708); // true
複製代碼4. arrayToCSV:數組轉CSV格式(帶空格的字符串)緩存
const arrayToCSV = (arr, delimiter = ',') =>
arr.map(v => v.map(x => "${x}"
).join(delimiter)).join('\n');markdown
arrayToCSV([['a', 'b'], ['c', 'd']]); // '"a","b"\n"c","d"'
arrayToCSV([['a', 'b'], ['c', 'd']], ';'); // '"a";"b"\n"c";"d"'
複製代碼5. arrayToHtmlList:數組轉li列表
此代碼段將數組的元素轉換爲<li>標籤,並將其附加到給定ID的列表中。
const arrayToHtmlList = (arr, listID) =>
(el => (
(el = document.querySelector('#' + listID)),
(el.innerHTML += arr.map(item => <li>${item}</li>
).join(''))
))();app
arrayToHtmlList(['item 1', 'item 2'], 'myListID');
複製代碼6. average:平均數
const average = (...nums) => nums.reduce((acc, val) => acc + val, 0) / nums.length;
average(...[1, 2, 3]); // 2
average(1, 2, 3); // 2
複製代碼7. averageBy:數組對象屬性平均數
此代碼段將獲取數組對象屬性的平均值
const averageBy = (arr, fn) =>
arr.map(typeof fn === 'function' ? fn : val => val[fn]).reduce((acc, val) => acc + val, 0) /
arr.length;dom
averageBy([{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }], o => o.n); // 5
averageBy([{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }], 'n'); // 5
複製代碼8. bifurcate:拆分斷言後的數組
能夠根據每一個元素返回的值,使用reduce()和push() 將元素添加到第二次參數fn中 。
const bifurcate = (arr, filter) =>
arr.reduce((acc, val, i) => (acc[filter[i] ? 0 : 1].push(val), acc), [[], []]);
bifurcate(['beep', 'boop', 'foo', 'bar'], [true, true, false, true]);
// [ ['beep', 'boop', 'bar'], ['foo'] ]
複製代碼9. castArray:其它類型轉數組
const castArray = val => (Array.isArray(val) ? val : [val]);ide
castArray('foo'); // ['foo']
castArray([1]); // [1]
castArray(1); // [1]
複製代碼10. compact:去除數組中的無效/無用值
const compact = arr => arr.filter(Boolean);函數
compact([0, 1, false, 2, '', 3, 'a', 'e' * 23, NaN, 's', 34]);
// [ 1, 2, 3, 'a', 's', 34 ]
複製代碼11. countOccurrences:檢測數值出現次數
const countOccurrences = (arr, val) => arr.reduce((a, v) => (v === val ? a + 1 : a), 0);
countOccurrences([1, 1, 2, 1, 2, 3], 1); // 3
複製代碼12. deepFlatten:遞歸扁平化數組
const deepFlatten = arr => [].concat(...arr.map(v => (Array.isArray(v) ? deepFlatten(v) : v)));oop
deepFlatten([1, [2], [[3], 4], 5]); // [1,2,3,4,5]
複製代碼13. difference:尋找差別
此代碼段查找兩個數組之間的差別。this
const difference = (a, b) => {
const s = new Set(b);
return a.filter(x => !s.has(x));
};
difference([1, 2, 3], [1, 2, 4]); // [3]
複製代碼14. differenceBy:先執行再尋找差別
在將給定函數應用於兩個列表的每一個元素以後,此方法返回兩個數組之間的差別。
const differenceBy = (a, b, fn) => {
const s = new Set(b.map(fn));
return a.filter(x => !s.has(fn(x)));
};
differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor); // [1.2]
differenceBy([{ x: 2 }, { x: 1 }], [{ x: 1 }], v => v.x); // [ { x: 2 } ]
複製代碼15. dropWhile:刪除不符合條件的值
此代碼段從數組頂部開始刪除元素,直到傳遞的函數返回爲true。
const dropWhile = (arr, func) => {
while (arr.length > 0 && !func(arr[0])) arr = arr.slice(1);
return arr;
};
dropWhile([1, 2, 3, 4], n => n >= 3); // [3,4]
複製代碼16. flatten:指定深度扁平化數組
此代碼段第二參數可指定深度。
const flatten = (arr, depth = 1) =>
arr.reduce((a, v) => a.concat(depth > 1 && Array.isArray(v) ? flatten(v, depth - 1) : v), []);
flatten([1, [2], 3, 4]); // [1, 2, 3, 4]
flatten([1, [2, [3, [4, 5], 6], 7], 8], 2); // [1, 2, 3, [4, 5], 6, 7, 8]
複製代碼17. indexOfAll:返回數組中某值的全部索引
此代碼段可用於獲取數組中某個值的全部索引,若是此值中未包含該值,則返回一個空數組。
const indexOfAll = (arr, val) => arr.reduce((acc, el, i) => (el === val ? [...acc, i] : acc), []);
indexOfAll([1, 2, 3, 1, 2, 3], 1); // [0,3]
indexOfAll([1, 2, 3], 4); // []
複製代碼18. intersection:兩數組的交集
const intersection = (a, b) => {
const s = new Set(b);
return a.filter(x => s.has(x));
};
intersection([1, 2, 3], [4, 3, 2]); // [2, 3]
複製代碼19. intersectionWith:兩數組都符合條件的交集
此片斷可用於在對兩個數組的每一個元素執行了函數以後,返回兩個數組中存在的元素列表。
const intersectionBy = (a, b, fn) => {
const s = new Set(b.map(fn));
return a.filter(x => s.has(fn(x)));
};
intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor); // [2.1]
複製代碼20. intersectionWith:先比較後返回交集
const intersectionWith = (a, b, comp) => a.filter(x => b.findIndex(y => comp(x, y)) !== -1);
intersectionWith([1, 1.2, 1.5, 3, 0], [1.9, 3, 0, 3.9], (a, b) => Math.round(a) === Math.round(b)); // [1.5, 3, 0]
複製代碼21. minN:返回指定長度的升序數組
const minN = (arr, n = 1) => [...arr].sort((a, b) => a - b).slice(0, n);
minN([1, 2, 3]); // [1]
minN([1, 2, 3], 2); // [1,2]
複製代碼22. negate:根據條件反向篩選
const negate = func => (...args) => !func(...args);
[1, 2, 3, 4, 5, 6].filter(negate(n => n % 2 === 0)); // [ 1, 3, 5 ]
複製代碼23. randomIntArrayInRange:生成兩數之間指定長度的隨機數組
const randomIntArrayInRange = (min, max, n = 1) =>
Array.from({ length: n }, () => Math.floor(Math.random() * (max - min + 1)) + min);
randomIntArrayInRange(12, 35, 10); // [ 34, 14, 27, 17, 30, 27, 20, 26, 21, 14 ]
複製代碼24. sample:在指定數組中獲取隨機數
const sample = arr => arr[Math.floor(Math.random() * arr.length)];
sample([3, 7, 9, 11]); // 9
複製代碼25. sampleSize:在指定數組中獲取指定長度的隨機數
此代碼段可用於從數組中獲取指定長度的隨機數,直至窮盡數組。
使用Fisher-Yates算法對數組中的元素進行隨機選擇。
const sampleSize = ([...arr], n = 1) => {
let m = arr.length;
while (m) {
const i = Math.floor(Math.random() * m--);
[arr[m], arr[i]] = [arr[i], arr[m]];
}
return arr.slice(0, n);
};
sampleSize([1, 2, 3], 2); // [3,1]
sampleSize([1, 2, 3], 4); // [2,3,1]
複製代碼26. shuffle:「洗牌」 數組
此代碼段使用Fisher-Yates算法隨機排序數組的元素。
const shuffle = ([...arr]) => {
let m = arr.length;
while (m) {
const i = Math.floor(Math.random() * m--);
[arr[m], arr[i]] = [arr[i], arr[m]];
}
return arr;
};
const foo = [1, 2, 3];
shuffle(foo); // [2, 3, 1], foo = [1, 2, 3]
複製代碼27. nest:根據parent_id生成樹結構(阿里一面真題)
根據每項的parent_id,生成具體樹形結構的對象。
const nest = (items, id = null, link = 'parent_id') =>
items
.filter(item => item[link] === id)
.map(item => ({ ...item, children: nest(items, item.id) }));
複製代碼用法:
const comments = [
{ id: 1, parent_id: null },
{ id: 2, parent_id: 1 },
{ id: 3, parent_id: 1 },
{ id: 4, parent_id: 2 },
{ id: 5, parent_id: 4 }
];
const nestedComments = nest(comments); // [{ id: 1, parent_id: null, children: [...] }]
複製代碼
強烈建議去理解這個的實現,由於這是我親身遇到的阿里一面真題:
defer(console.log, 'a'), console.log('b'); // logs 'b' then 'a'
複製代碼3. runPromisesInSeries:運行多個Promises
const runPromisesInSeries = ps => ps.reduce((p, next) => p.then(next), Promise.resolve());
const delay = d => new Promise(r => setTimeout(r, d));
runPromisesInSeries([() => delay(1000), () => delay(2000)]);
//依次執行每一個Promises ,總共須要3秒鐘才能完成
複製代碼4. timeTaken:計算函數執行時間
const timeTaken = callback => {
console.time('timeTaken');
const r = callback();
console.timeEnd('timeTaken');
return r;
};
timeTaken(() => Math.pow(2, 10)); // 1024, (logged): timeTaken: 0.02099609375ms
複製代碼5. createEventHub:簡單的發佈/訂閱模式
建立一個發佈/訂閱(發佈-訂閱)事件集線,有emit,on和off方法。
使用Object.create(null)建立一個空的hub對象。
emit,根據event參數解析處理程序數組,而後.forEach()經過傳入數據做爲參數來運行每一個處理程序。
on,爲事件建立一個數組(若不存在則爲空數組),而後.push()將處理程序添加到該數組。
off,用.findIndex()在事件數組中查找處理程序的索引,並使用.splice()刪除。
const createEventHub = () => ({
hub: Object.create(null),
emit(event, data) {
(this.hub[event] || []).forEach(handler => handler(data));
},
on(event, handler) {
if (!this.hub[event]) this.hub[event] = [];
this.hub[event].push(handler);
},
off(event, handler) {
const i = (this.hub[event] || []).findIndex(h => h === handler);
if (i > -1) this.hub[event].splice(i, 1);
if (this.hub[event].length === 0) delete this.hub[event];
}
});
複製代碼用法:
const handler = data => console.log(data);
const hub = createEventHub();
let increment = 0;
// 訂閱,監聽不一樣事件
hub.on('message', handler);
hub.on('message', () => console.log('Message event fired'));
hub.on('increment', () => increment++);
// 發佈:發出事件以調用全部訂閱給它們的處理程序,並將數據做爲參數傳遞給它們
hub.emit('message', 'hello world'); // 打印 'hello world' 和 'Message event fired'
hub.emit('message', { hello: 'world' }); // 打印 對象 和 'Message event fired'
hub.emit('increment'); // increment = 1
// 中止訂閱
hub.off('message', handler);
複製代碼6. memoize:緩存函數
經過實例化一個Map對象來建立一個空的緩存。
經過檢查輸入值的函數輸出是否已緩存,返回存儲一個參數的函數,該參數將被提供給已記憶的函數;若是沒有,則存儲並返回它。
const memoize = fn => {
const cache = new Map();
const cached = function(val) {
return cache.has(val) ? cache.get(val) : cache.set(val, fn.call(this, val)) && cache.get(val);
};
cached.cache = cache;
return cached;
};
複製代碼Ps: 這個版本可能不是很清晰,還有Vue源碼版的:
/**
利用Object.keys(obj)聯合Array.prototype.reduce(),以每片葉子節點轉換爲扁平的路徑節點。
若是鍵的值是一個對象,則函數使用調用適當的自身prefix以建立路徑Object.assign()。
不然,它將適當的前綴鍵值對添加到累加器對象。
prefix除非您但願每一個鍵都有一個前綴,不然應始終省略第二個參數。
const flattenObject = (obj, prefix = '') =>
Object.keys(obj).reduce((acc, k) => {
const pre = prefix.length ? prefix + '.' : '';
if (typeof obj[k] === 'object') Object.assign(acc, flattenObject(obj[k], pre + k));
else acc[pre + k] = obj[k];
return acc;
}, {});
flattenObject({ a: { b: { c: 1 } }, d: 1 }); // { 'a.b.c': 1, d: 1 }
複製代碼9. unflattenObject:以鍵的路徑展開對象
與上面的相反,展開對象。
const unflattenObject = obj =>
Object.keys(obj).reduce((acc, k) => {
if (k.indexOf('.') !== -1) {
const keys = k.split('.');
Object.assign(
acc,
JSON.parse(
'{' +
keys.map((v, i) => (i !== keys.length - 1 ? "${v}":{
: "${v}":
)).join('') +
obj[k] +
'}'.repeat(keys.length)
)
);
} else acc[k] = obj[k];
return acc;
}, {});
unflattenObject({ 'a.b.c': 1, d: 1 }); // { a: { b: { c: 1 } }, d: 1 }
複製代碼這個的用途,在作Tree組件或複雜表單時取值很是舒服。
byteSize('