统计数组中元素出现次数 reduce() 方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。
reducer 函数接收4个参数:
1.Accumulator (acc) (累计器)
2.Current Value (cur) (当前值)
3.Current Index (idx) (当前索引)
4.Source Array (src) (源数组)
您的 reducer 函数的返回值分配给累计器,该返回值在数组的每个迭代中被记住,并最后成为最终的单个结果值。
1 2 3 4 5 const count = arr => arr.reduce((acc, val) => { acc[val] = (acc[val] || 0) + 1; return acc; },{}) count([1,1,2,3,1,1,2]); // {1:4,2:2,3:1}
数组扁平化(完全) concat() 方法用于连接两个或多个数组。该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。
1 2 3 4 5 6 const aryFlatten = arr => [].concat(...arr.map(v => Array.isArray(v) ? aryFlatten(v) :v)) reduce版 const aryFlatten = arr => arr.reduce((a, v) => a.concat(Array.isArray(v) ? aryFlatten(v) : v),[]) aryFlatten([1, [2], [[3], 4], 5]); // [1,2,3,4,5]
根据提供的层数扁平化 1 2 3 const flattenBy = (arr, depth=1) => arr.reduce((a, v) => a.concat(depth>1 && Array.isArray(v) ? flattenBy(v, depth-1) : v),[]) flattenBy([1, [2, [3, [4, 5], 6], 7], 8], 2); // [1, 2, 3, [4, 5], 6, 7, 8]
去除数组中的所有假植 1 2 3 const filterFalsy = arr => arr.filter(Boolean) filterFalsy(['', true, {}, false, 'sample', 1, 0]); // [true, {}, 'sample', 1]
获取指定值在数组中出现的所有下标 1 2 3 const indexOfAll = (arr, val) => arr.reduce((a, v, i) => v===val? [...a,i]: a,[]) indexOfAll([1, 2, 3, 1, 2, 3], 1); // [0,3]
通过给定的结束值,开始值,步长生成数组 Array.from() 方法从一个类似数组或可迭代对象中创建一个新的数组实例。
Math.ceil 向上取整
1 2 3 4 5 6 7 const initializeArrayWithRange = (end, start=0, step=1) => Array.from({length: Math.ceil(end-start+1)/step}, (v, i)=> i*step+start) initializeArrayWithRange(5); // [0,1,2,3,4,5] initializeArrayWithRange(7, 3); // [3,4,5,6,7] initializeArrayWithRange(9, 0, 2); // [0,2,4,6,8]
获取两个数组的交集 1 2 3 4 5 6 7 8 9 const intersection = (a, b) => { const s = new Set(b) return a.filter(x => s.has(x)) } 或 const intersection = (a, b) => a.filter(x => b.includes(a)) intersection([1, 2, 3], [4, 3, 2]); // [2, 3]
打乱数组顺序 1 2 3 4 5 6 7 8 9 10 const shuffle = arr =>{ let m = arr.length; while(m){ let i = Math.floor(Math.random() * m--) [arr[i],arr[m]] = [arr[m],arr[i]] } return arr; } shuffle([1, 2, 3]); // [2, 3, 1]
根据提供的方法留下符合条件的 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const uniqueElementsBy = (arr, fn) => arr.reduce((acc, val) => { !acc.some(x => fn(x,val))?acc.push(val):'' return acc; } ,[]) uniqueElementsBy( [ { id: 0, value: 'a' }, { id: 1, value: 'b' }, { id: 2, value: 'c' }, { id: 1, value: 'd' }, { id: 0, value: 'e' } ], (a, b) => a.id == b.id ); 返回 [ { id: 0, value: 'a' }, { id: 1, value: 'b' }, { id: 2, value: 'c' } ]
防抖 1 2 3 4 5 6 7 8 const debounce = (fn, ms=0)=>{ let timer; return fn(...args){ clearTimeout(timer); timer = setTimeout(() => fn.bind(this,args),ms) } }
先立即执行一次再防抖 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 const debounce = (fn, ms=0, immediate=true)=>{ let timer; return function(...args){ if(timer) clearTimeout(timer) if(immediate){ fn() immediate=false }else{ timer = setTimeout(()=>{ fn.apply(this,args) immediate=true },ms) } } }
斐波那契 1 2 3 4 5 6 7 8 9 10 11 const fb = (n) => Array.from({length:n+1}).reduce((acc,val,i) => (acc.concat(i>1?acc[i-2]+acc[i-1]:i)),[]) fb(5) // [1,1,2,3,5] 只要最后一项 function fb(n){ return n < 2 ? n : fb(n - 1) + fb(n - 2); } fb(5) // 5
先立即执行一次再节流 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const throttle = (fn, wait) => { let inThrottle, lastFn, lastTime; return function() { const context = this, args = arguments; if (!inThrottle) { fn.apply(context, args); lastTime = Date.now(); inThrottle = true; } else { clearTimeout(lastFn); lastFn = setTimeout(function() { if (Date.now() - lastTime >= wait) { fn.apply(context, args); lastTime = Date.now(); } }, Math.max(wait - (Date.now() - lastTime), 0)); } }; };
只执行一次的方法 1 2 3 4 5 6 7 8 9 const once = fn => { let called = false; return fn(...args){ if(called) return; called = true; return fn.apply(this,...args) } }
生成指定范围内的n个随机数 1 2 3 const randomIntArrayInRange = (max, min, n) => Array.from({length:n},()=> Math.floor(Math.random() * (max-min+1) + min)))
深拷贝 1 2 3 4 5 6 7 8 9 10 11 12 const deepClone = obj => { let clone = Object.assign({}, obj); Object.keys(clone).forEach( key => (clone[key] = typeof obj[key] === 'object' ? deepClone(obj[key]) : obj[key]) ); return Array.isArray(obj) && obj.length ? (clone.length = obj.length) && Array.from(clone) : Array.isArray(obj) ? Array.from(obj) : clone; };
计算大整数之和 1 2 3 4 5 6 7 8 9 10 11 function sumStrings(a, b) { var res = '', c = 0; a = a.split(''); b = b.split(''); while (a.length || b.length || c) { c += ~~a.pop() + ~~b.pop(); res = c % 10 + res; c = c > 9; } return res.replace(/^0+/, ''); }
new的模拟实现 1 2 3 4 5 6 7 8 9 10 11 12 13 function objectFactory() { var obj = new Object(), Constructor = [].shift.call(arguments); obj.__proto__ = Constructor.prototype; var ret = Constructor.apply(obj, arguments); return typeof ret === 'object' ? ret : obj; };
继承 构造继承 1 2 3 4 5 6 7 8 9 10 11 12 13 14 function Parent(){ this.arr = [1,2,3] this.name = 'parent' } function Child(){ Parent.apply(this); } Parent.prototype.id = '1' var child1 = new Child(); console.log(child1.name,child1.id) // parent undefined 总结:构造继承不会继承父级原型上的属性
原型继承 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 function Parent(){ this.arr = [1,2,3] this.name = 'parent' } function Child(){ this.age = 3 } Child.prototype = new Parent(); Parent.prototype.id = '1' let child1 = new Child(); console.log(child1.name,child1.id) // parent 1 child1.arr[0] = 3 child1.name = 'child' let child2 = new Child(); console.log(child2.arr,child2.name) // [3,2,3],parent 总结:原型继承继承了原型上的属性,但是改变原型上的应用类型,所有实例对象的该属性都会被改变
组合继承 1 2 3 4 5 6 7 8 9 10 11 function Parent(){ this.arr = [1,2,3] this.name = 'parent' } function Child(){ this.age = 3 } let obj = Object.create(Parent.prototype) Child.prototype.constructor = Child