这篇文章主要记录一下平时自己实践得到的, 博客中学习的以及在一些项目源码中看到的 javascript 技巧。有些东西可以说是奇淫技巧,有些可能是 ES6+ 中一些比较具有实用性的新语法。
&& 和 || 的妙用有时候我们需要在某个函数或变量为 true 时执行另外一个函数。例如:
1 2 3 4 5 6 7 | const task1 = () => { console.log('执行 task1'); return Math.random() >= 0.5;}const task2 = () => console.log('task1 执行成功后执行 task2');if (task1()) task2(); |
上面的 if 语句可以使用 && 直接简写为:
1 | task1() && task2(); |
如果还要在 task1 失败后执行 task3, 可以使用:
1 2 | const task3 = () => console.log('task1 执行失败后执行 task3');task1() && task2() || task3(); |
本质上还是利用了 && 和 || 的短路特性。
下面展示一个我最近使用 react hooks 开发的项目的的一个代码片段:
01 02 03 04 05 06 07 08 09 10 11 12 13 | const ProfileItem = (props) => { const { name, value, render } = props; return ( <div className="profile-item"> <span className="item-name">{name}</span> <form action=""> {/* 根据是否有 render 这个 props 来返回不同的内容 */} {render && render(props) || <SimpleProfileItemContent value={value}/>} </form> </div> )} |
函数默认值ES5 版本使用短路或操作符来设置函数默认值的方式其实很常见。但是有一些坑,下面展示的代码中当默认值参数为一个数字时,传参为 0 还是会使用默认值,必须对 y 为 0 的时候单独进行判断。
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 | const pow = (x, y) => { y = y || 2; let result = 1; for (let i = 0, max = y; i < max; i++) { result *= x; } return result;}console.log(pow(2)); // => 4console.log(pow(2, 3)); // => 8// 当 y 传值为 0 时, y 取值 2console.log(pow(2, 0)); // => 4 |
ES6 版本ES6 在语法层面提供的默认值语法就靠谱的多了
01 02 03 04 05 06 07 08 09 10 11 12 | const pow = (x, y=2) => { let result = 1; for (let i = 0, max = y; i < max; i++) { result *= x; } return result;}console.log(pow(2)); // => 4console.log(pow(2, 3)) // => 8console.log(pow(2, 0)); // => 1 |
类数组转数组类数组指的是像 arguments ,jquery 对象一样可以使用下标访问还有 length 属性的和数组很像但并不是数组的一类对象。
类数组没有 slice, map 等集合函数,这也是为什么我们有时候需要将类数组转换成数组的原因。
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 | function func() { for (let i = 0, max = arguments.length; i < max; i++) { console.log(arguments[i]); } console.log(Array.isArray(arguments)); // => false // 类数组没有 slice, forEach, map 等集合函数 console.log(arguments.slice === undefined); // => true}func('Google', 'facebook', 'Microsoft'); // => // Google// facebook// Microsoft |
ES5 中的转换方法将 Array 原型中的 slice 方法绑定到 arguments 对象上调用,并且不传参数目的为了让其返回所有的元素。
1 2 3 4 5 6 | function func() { const array = Array.prototype.slice.call(arguments); console.log(array.slice(0, 1));}func('Google', 'facebook', 'Microsoft'); // => [ 'Google' ] |
ES6 中的转换方法ES6 将类数组转换成数组的方法多一些。
使用扩展运算符
1 2 3 4 5 | function func() { console.log([...arguments])}func('Google', 'facebook', 'Microsoft'); // [ 'Google', 'facebook', 'Microsoft' ] |
使用 Array.from
1 2 3 4 5 | function func() { console.log(Array.from(arguments))}func('Google', 'facebook', 'Microsoft'); // [ 'Google', 'facebook', 'Microsoft' ] |
构造一个连续整数的数组这里就直接给出我觉得最好的方法了
1 2 3 | // 输出 2 开始连续的8个整数const array = Array.from({ length: 8}).map((ele, index) => index + 2);console.log(array); // => [ 2, 3, 4, 5, 6, 7, 8, 9 ] |
函数参数使用结构赋值函数参数比较多的时候我们往往会让参数直接接受一个配置对象。但是使用对象参数我们无法设置默认值,在函数体中使用对象参数时还需要使用通过对象参数来访问,当访问次数比较多或者嵌套比较深就会觉得不方便。在函数参数中使用结构赋值就解决了上面的问题。
01 02 03 04 05 06 07 08 09 10 11 12 | // 必须给对象参数设置默认值, 不然传参数时因为没有解构对象会报错const getUsers = ({ offset=0, limit=1, orderBy="salary"}={}) => { // 根据条件查询数据库返回用户数据 console.log({ offset, limit, orderBy });}getUsers({ offset: 10, limit: 20,orderBy: 'age' }); // => { offset: 10, limit: 20, orderBy: 'age' }getUsers();// => { offset: 0, limit: 1, orderBy: 'salary' } |
使用 !! 将其它类型转换成 bool 型
01 02 03 04 05 06 07 08 09 10 | console.log(!!{}); // trueconsole.log(!!0); // falseconsole.log(!![]); // trueconsole.log(!!undefined); // falseconst httpGet = (url, retry) => { if (!!retry) { // 超时重发 }} |
JSON.stringify深度克隆使用先序列化再反序列化这种方式来深度克隆对象在一般情况下很方便,缺点就是无法克隆函数以及继承的属性。
如果还幺克隆函数属性,推荐使用 lodash 的 cloneDeep。
01 02 03 04 05 06 07 08 09 10 11 | const me = { name: 'lyreal666', age: 23, speak() { console.log(`Hello, I'm ly!`); }}const clonedMe = JSON.parse(JSON.stringify(me));console.log(clonedMe); // => { name: 'lyreal666', age: 23 }console.log(clonedMe.speak === undefined); // => true |
文章转载至:https://juejin.cn/post/6844903812763746317