D - F 系列
1、防抖函数,限制高频触发
1const debounce = (fn, ms = 0) => { 2 let timeoutId; 3 return function(...args) { 4 clearTimeout(timeoutId); 5 timeoutId = setTimeout(() => fn.apply(this, args), ms); 6 }; 7};
- 可以运用在监听屏幕缩放,或者input 搜索时,做一些性能优化
2、转换首字母(或其他)大小写
1const decapitalize = ([first, ...rest], upperRest = false) => 2 first.toLowerCase() + 3 (upperRest ? rest.join('').toUpperCase() : rest.join('')); 4 5decapitalize('FooBar'); // 'fooBar' 6decapitalize('FooBar', true); // 'fOOBAR'
- [first, ...rest] 通过这种解构的方式将字符分割成数组,同时获取到首字母
3、深克隆
1const deepClone = obj => { 2 if (obj === null) return null; 3 let clone = Object.assign({}, obj); 4 Object.keys(clone).forEach( 5 key => 6 (clone[key] = 7 typeof obj[key] === 'object' ? deepClone(obj[key]) : obj[key]) 8 ); 9 // 如果是数组仍然会转成 key - value 形式 10 if (Array.isArray(obj)) { 11 // 添加 length 属性,便于 Array.from 进行转换(类数组或者可迭代对象) 12 clone.length = obj.length; 13 return Array.from(clone); 14 } 15 return clone; 16};
4、数组打平
1const deepFlatten = arr => 2 [].concat(...arr.map(v => (Array.isArray(v) ? deepFlatten(v) : v))) 3 4// 数组打平 至指定深度 5 6const flatten = (arr, depth = 1) => 7 arr.reduce( 8 (a, v) => 9 a.concat(depth > 1 && Array.isArray(v) ? flatten(v, depth - 1) : v), 10 [] 11 ); 12 13flatten([1, [2], 3, 4]); // [1, 2, 3, 4] 14flatten([1, [2, [3, [4, 5], 6], 7], 8], 2); // [1, 2, 3, [4, 5], 6, 7, 8]
- 利用 map 将多维数组中的值返回成新数组,最后再展开与 [] 连接
- 可以看到,在解决一些深层次嵌套问题时(深度冻结一个对象),大多会用到递归思想,以后类似问题可以往这方面思考
5、两个数组的交集(Set的使用)
1const difference = (a, b) => { 2 const s = new Set(b); 3 return a.filter(x => !s.has(x)); 4} 5difference([1, 2, 3, 3], [1, 2, 4]); // [3, 3]
- 补充几个关于 set 的小知识
- Set 对象允许你存储任何类型的唯一值(只会出现一次),无论是原始值或者是对象引用
- 同时 set 的原型上提供了几个方法,size()(值的个数),add()(尾部添加),clear()(清除set对象中的所有元素),has()(返回布尔值)...
与数组相关
- 除了使用 Array.from() 转换外,还可以使用 ... 展开操作符
- 去重相关
本例中主要使用 has() 方法来判断两数组中的交集
6、实现一个求阶乘的函数
1const factorial = n => 2 n < 0 3 ? (() => { 4 throw new TypeError('Negative numbers are not allowed!'); 5 })() 6 : n <= 1 7 ? 1 8 : n * factorial(n - 1); 9 10factorial(6); // 720
7、生成一个指定长度数组,包含斐波那契数列
1const fibonacci = n => 2 Array.from({ length: n }).reduce( 3 (acc, val, i) => acc.concat(i > 1 ? acc[i - 1] + acc[i - 2] : i), 4 [] 5 ); 6 7fibonacci(6); // [0, 1, 1, 2, 3, 5]
- 通过 Array.from() 产生一个指定长度数组
- reduce() ,给定初始值为 [],再使用 concat() 进行连接 acc,同时就做累加了
- reduce()的好处就是 参数 acc 是上一次调用回调时返回的累积值
8、实现一个从右侧开始的数组遍历
1const forEachRight = (arr, callback) => 2 arr 3 .slice() 4 .reverse() 5 .forEach(callback); 6forEachRight([1, 2, 3, 4], val => console.log(val)); // '4', '3', '2', '1'
- 有点意思,从右侧开始遍历,其实就是先拷贝一个副本,然后颠倒,再遍历
9、全屏模式下打开或关闭一个元素
1const fullscreen = (mode = true, el = 'body') => 2 mode 3 ? document.querySelector(el).requestFullscreen() 4 : document.exitFullscreen(); 5 6fullscreen(); // Opens `body` in fullscreen mode 7fullscreen(false); // Exits fullscreen mode
- requestFullscreen() 这个倒是是没见过
10、节流函数
1const throttle = (fn, wait) => { 2 let inThrottle, lastFn, lastTime; 3 return function() { 4 const context = this, 5 args = arguments; 6 if (!inThrottle) { 7 fn.apply(context, args); 8 lastTime = Date.now(); 9 inThrottle = true; 10 } else { 11 clearTimeout(lastFn); 12 lastFn = setTimeout(function() { 13 if (Date.now() - lastTime >= wait) { 14 fn.apply(context, args); 15 lastTime = Date.now(); 16 } 17 }, Math.max(wait - (Date.now() - lastTime), 0)); 18 } 19 }; 20}; 21 22window.addEventListener( 23 'resize', 24 throttle(function(evt) { 25 console.log(window.innerWidth); 26 console.log(window.innerHeight); 27 }, 250) 28); // Will log the window dimensions at most every 250ms
