记录 30 seconds of code 项目个人觉得中有价值的片段或者小技巧 (一)

A - C 系列

1、+ 号的隐式类型转换使用

1+[3] //3 2+[1,2,3].slice(-1) //将 [3] 转换为了3

2、日期的转换

1const addDaysToDate = (date, n) => { 2 const d = new Date(date); 3 d.setDate(d.getDate() + n); 4 return d.toISOString().split('T')[0]; 5}; 6addDaysToDate('2020-10-15', 10); // '2020-10-25'
  • 平时做日期的计算可能更多的使用时间戳,秒数去加减,其实有对应的 setDate,getDate等方法去做(月份也一样)
  • toISOString 可以将日期对象转换为 YYYY-MM-DDTHH:mm:ss.sssZ 格式,分割掉 T 字符,即可以得到日期形式

3、对象的合并

1Object.assign 2// 在像某对象添加多个属性时,可以直接采取合并方式 3const addStyles = (el, styles) => Object.assign(el.style, styles) 4addStyles(document.getElementById('my-element'), { 5 background: 'red', 6 color: '#ffff00', 7 fontSize: '3rem' 8})

4、Array.from

1/** 2对于这个api知道更多的只是将类数组转化为真正的数组 3(arrayLike,mapFn) 准确的说应该是类数组或者 可迭代对象({length: 5}) 4mapFn 接收一个回调,返回的数组每个元素会执行该回调 5**/ 6let a = Array.from({length: 10},(_,i) => i) 7a // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

5、关于工具函数封装tips

  • 在封装工具类函数时,可以往闭包的角度靠(内部再返回一个函数)
  • 有时候可以具有更好的拓展性
1// 栗子:获取某些数中的最大值 2const ary = (fn,n) => (...arg) => fn(...arg.slice(0,n)) 3const firstTwoMax = ary(Math.max, 2) 4firstTwoMax(1,2,3,4) 5 6// ary的函数将传入的函数,作为返回函数的返回值调用,类似于将传入的函数缓存下来,再一次调用时,传入比较值 7// 这样有个好处是,其实我们可以更改比较条件,比如 取最小值等等 8// 这样工具函数更具有灵活性

6、 按条件分割数组

1const bifurcateBy = (arr, fn) => 2 arr.reduce((acc, val, i) => (acc[fn(val, i) ? 0 : 1].push(val), acc), [ 3 [], 4 [], 5]) 6bifurcateBy(['beep', 'boop', 'foo', 'bar'], x => x[0] === 'b'); 7// [ ['beep', 'boop', 'bar'], ['foo'] ] 8 9/** 10利用 reduce 将结果汇总,同时把分割条件作为一个 返回布尔值的函数传入 11内部通过布尔值的判断,添加到对应的数组中 12**/

7、二分搜索算法,来查找已排序数组中某元素的位置

  • 尽管现在有api可以直接实现位置查找,不过这个算法思想还是可以的
1const binarySearch = (arr,item) => { 2 // 获取首位下标 3 let l = 0, 4 r = arr.length - 1; 5 while(l <= r) { 6 // 找到中间下标 7 const middle = Math.floor( (l + r) / 2) 8 const guess = arr[middle] 9 // 中间值与目标值比较 10 if(guess == item) return middle 11 // 中间值 > 目标值 ? 说明目标值在左侧,则取左边中间值再比较,反之亦然 12 guess > item ? r = middle - 1 : l = middle + 1 13 } 14 return -1 15} 16binarySearch([1,2,3,4],4) // 3
  • 二分搜索算法,采取折中的方式,将中间值与目标做比较,然后不断修改中间值,进而找到目标值

8、冒泡排序

1const bubbleSort = arr => { 2 let swapped = false; 3 const a = [...arr]; 4 for (let i = 1; i < a.length; i++) { 5 swapped = false; 6 for (let j = 0; j < a.length - i; j++) { 7 if (a[j + 1] < a[j]) { 8 // es6 变量交换 9 [a[j], a[j + 1]] = [a[j + 1], a[j]]; 10 swapped = true; 11 } 12 } 13 if (!swapped) return a; 14 } 15 return a; 16};
  • 核心思想是将当前值a 与 下一位置值b比较,如果 a > b,就把 a和b交互位置
  • 同时,一轮排序其实就可以实现最大值排最后了,所以循环次数越往后会越少,这也是 i < a.length ,j < a.length - i 的原因
  • es6 的变量交换位置,更加方便了,其实也可以用于多个变量的赋值改变类似: [count, i] = [count + 1, r + 1]...

9、将字符串首字母转换为大写

1// 有意思的是 这里只是通过解构的方式,就把字符串的首字符与剩余字符分开了 2// 在此之前你说否还想着截取首字母再来转换? 3const capitalize = ([first, ...rest], lowerRest = false) => 4 first.toUpperCase() + 5 (lowerRest ? rest.join('').toLowerCase() : rest.join('')); 6 7capitalize('fooBar', true); // 'Foobar'

10、链式控制异步流程

1const chainAsync = fns => { 2 let curr = 0; 3 const last = fns[fns.length - 1]; 4 // 内部实现一个函数,用于逐次从数组中提取执行函数 5 const next = () => { 6 const fn = fns[curr++]; 7 // 提取函数与最后一个做对比,是否为最后一个函数 8 // 同时将这个内部函数,作为回调,传入下一个 异步函数中 9 fn === last ? fn() : fn(next); 10 }; 11 next(); 12}; 13 14chainAsync([ 15 next => { 16 console.log('0 seconds'); 17 // 函数执行后,再执行传入的回调next 18 setTimeout(next, 1000); 19 }, 20 next => { 21 console.log('1 second'); 22 setTimeout(next, 1000); 23 }, 24 () => { 25 console.log('2 second'); 26 } 27]);
  • 异步的实现,其实还是回调的使用,只不过封装后,看似同步
  • 好比 Promise的resolve,获取结果后,通过resolve回调出去
  • Promise + async ,运用迭代器,使得可以控制函数的暂停和恢复,更加具有同步风范

11、js 实现一个剪切板

1const copyToClipboard = str => { 2 const el = document.createElement('textarea'); 3 el.value = str; 4 el.setAttribute('readonly', ''); 5 el.style.position = 'absolute'; 6 el.style.left = '-9999px'; 7 document.body.appendChild(el); 8 const selected = 9 document.getSelection().rangeCount > 0 10 ? document.getSelection().getRangeAt(0) 11 : false; 12 el.select(); 13 document.execCommand('copy'); 14 document.body.removeChild(el); 15 if (selected) { 16 document.getSelection().removeAllRanges(); 17 document.getSelection().addRange(selected); 18 } 19} 20 21copyToClipboard('Lorem ipsum')

12、根据给定函数或者属性,统计符合条件的数组元素的个数

1const countBy = (arr, fn) => 2 arr.map(typeof fn === 'function' ? fn : val => val[fn]).reduce((acc, val) => { 3 acc[val] = (acc[val] || 0) + 1; 4 return acc; 5}, {}); 6 7countBy([6.1, 4.2, 6.3], Math.floor); // {4: 1, 6: 2} 8countBy(['one', 'two', 'three'], 'length'); // {3: 2, 5: 1} 9countBy([{ count: 5 }, { count: 10 }, { count: 5 }], x => x.count)

13、实现一个发布订阅模式

1const createEventHub = () => ({ 2 hub: Object.create(null), 3 emit(event, data) { 4 (this.hub[event] || []).forEach(handler => handler(data)); 5 }, 6 on(event, handler) { 7 if (!this.hub[event]) this.hub[event] = []; 8 this.hub[event].push(handler); 9 }, 10 off(event, handler) { 11 const i = (this.hub[event] || []).findIndex(h => h === handler); 12 if (i > -1) this.hub[event].splice(i, 1); 13 if (this.hub[event].length === 0) delete this.hub[event]; 14 } 15}); 16 17const handler = data => console.log(data); 18const hub = createEventHub(); 19let increment = 0; 20 21// Subscribe: 22hub.on('message', handler); 23hub.on('message', () => console.log('Message event fired')); 24hub.on('increment', () => increment++); 25 26// Publish 27hub.emit('message', 'hello world'); 28hub.emit('message', { hello: 'world' }); 29hub.emit('increment'); 30 31// Unsubscribe 32hub.off('message', handler);

14、补充一点关于函数length属性

1/*** 2 * js 函数的length是表示参数的个数,需要注意的是 3 * 该个数指的是 函数必须接收参数的个数,且是有效参数(应当是默认值前的参数个数) 4 * */ 5function a( a,b = 10,c) {} //a.lenght = 1 6 a(10,'',30) // a = 10 b = '' c = 30 7 a(10,null,30) // a = 10 b = null c = 30 8 a(10,undefiend,30) // a =10 b = 10 c = 30 9// 对于包含默认值的参数,只有传递 undefiend 时(或者不传)才是取默认值,其他情况均为传啥就是啥
点赞
收藏

评论区

加载中...

相关推荐

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

记录 30 seconds of code 项目个人觉得中有价值的片段或者小技巧(二)

DF系列1、防抖函数,限制高频触发jsconstdebounce(fn,ms0)lettimeoutId;returnfunction(...args)clearTimeout(timeoutId);timeoutIdsetTimeout(()fn.apply(this,args),ms);

记录 30 seconds of code 项目个人觉得中有价值的片段或者小技巧(三)

GI系列获取元素距离顶部的距离jsconstgetVerticalOffsetelletoffsetel.offsetTop,elel;while(el.offsetParent)elel.offsetParent;offsetel.offsetTop;returnoffse

java8 时间类与Date类的相互转化

java8时间类与Date类的相互转化在转换中,我们需要注意,因为java8之前Date是包含日期和时间的,而LocalDate只包含日期,LocalTime只包含时间,所以与Date在互转中,势必会丢失日期或者时间,或者会使用起始时间。如果转LocalDateTime,那么就不存在信息误差。//Date与Instant的相互转化

记录 30 seconds of code 项目个人觉得中有价值的片段或者小技巧(四)

JZ系列获取数组元素下标(findIndex的实现)jsconstlinearSearch(arr,item)for(constiinarr)if(arriitem)returni;return1;;linearSearch(2,9,9,9);//1linearSearch(

mysql相似于oracle的to_char() to_date()方法

mysql日期和字符相互转换方法date\_format(date,'%Y%m%d')  oracle中的to\_char();str\_to\_date(date,'%Y%m%d')  oracle中的to\_date();%Y:代表4位的年份%y:代表2为的年份