JavaScript的一些优雅写法

“阅前必阅”

  JavaScript博大精深,本人只是在工作中,发现了一些js的各种写法,下面介绍的是一些能简化代码量的写法,但是有一些我是不太推荐的,详细原因也有论述。抛的砖是砸到头了还是引出了玉,就看各位了。

切换变量0和1

1
2
3
4
5
6
7
8
9
10
11
// if判断可以这么写
let flag = 0;
if (flag === 0) {
flag = 1;
} else {
flag = 0;
}
// 也可以用三目运算符
flag = flag === 0 ? 1 : 0;
// 也可以使用位异或(^)
flag ^= 1;

  一般我要求自己的团队在js上是尽量少用位运算,为什么呢?因为位运算其实二进制数执行运算,包括与&、或|、异或^、非~、左移<<、右移>>都是整数的逐位运算。然而,不幸的是在js内部所有数字都是双精度浮点数,所以这些运算js会先转为整数再运算,而且代码阅读性也会降低。
其实说到位运算,还不得不提一个月更贴,为什么

1
console.log(0.1 + 0.2 === 0.3); // false

  总结一句就是十进制转二进制的精度丢失,如果想深入了解,推荐一篇文章0.1 + 0.2不等于0.3?为什么JavaScript有这种“骚”操作?

!!

  继续说位运算的非,我在项目中看到越来越多的人用!!来判空等操作,本身来讲也没问题,但是毫无节制的使用!!真的有必要吗?比如已知表达式就是一个Boolean值,还需要这样判断吗?
  还是先讲讲!!的逻辑吧,非运算字面比较简单——真就是假,假就是真,不过js的类型特点,还是详细看下:

1
2
3
4
5
6
7
8
9
console.log(!null); // true
let u = void 0; // undefined
console.log(!u); // true
console.log(!0); // true
console.log(!1); // false
console.log(!''); // true
console.log(!'a'); // false
console.log(!{}); // false
console.log(!{ a: 'a' }); // false

  这里基本涵盖了所有类型(boolean就没必要参与了),可以看到null、undefined、0、’’是true,其它为false,所以我们就明白为什么很多人用这个来判断空字符串了吧,问题却来了0不是空啊,比如常见场景我们Http请求时,要剔除空参数,但如果参数有个0,那就尴尬了吧~即使你真的要将0纳入false范畴,我也更推荐下面的做法:

1
2
3
4
5
6
7
8
9
console.log(Boolean('null'));
let u = void 0; // undefined
console.log(Boolean(u));
console.log(Boolean(0));
console.log(Boolean(1));
console.log(Boolean(''));
console.log(Boolean('a'));
console.log(Boolean({}));
console.log(Boolean({ a: 'a' }));

  如果你只是单纯的想判断空,可以使用下面的方法

1
2
3
4
5
6
function isEmpty(str) {
return null == str || '' == str;
}
console.log(isEmpty(0));
console.log(isEmpty(void 0));
console.log(isEmpty(null));

交换值

  如果用位运算,则

1
2
3
4
5
6
7
let a = 1;
let b = 2;
a ^= b;
b ^= a;
a ^= b;
console.log(a); // 2
console.log(b); // 1

但与借助中间值,似乎差距不大

1
2
3
4
5
6
7
let a = 1;
let b = 2;
let c = a;
a = b;
b = c;
console.log(a); // 2
console.log(b); // 1

而现在基本都支持ES6的情况下,其实可以用解构才操作

1
2
3
4
5
let a = 1;
let b = 2;
[a, b] = [b, a];
console.log(a); // 2
console.log(b); // 1
  • 解构一般用来如本例的交换值,或者从对象取值,如
1
2
3
4
5
6
7
8
9
// 从对象中取值
let obj = { a: 1, b: 2, c: 3 };
let { a, b, c } = obj;
console.log(a, b, c); // 1,2,3

// 从数组中取值
let arr = [1, 2, 3, 4, 5];
let [a, , , b, , c] = arr;
console.log(a, b, c); // 1 4 undefined

  但解构的作用可不仅仅是如此,还有很多妙处,比如:从数组中取一个值,如果该索引不存在则赋一个默认值

1
2
3
4
5
6
7
let arr = [1];
let value = 'a';
if (arr.length > 1) {
value = arr[1];
}
console.log(value); // a

  而用解构,则仅需

1
2
3
let arr = [1];
let [, value = 'a'] = arr;
console.log(value); // a

用户签到

  在开发中,我用位运算较多的一个场景——签到,比如下面的做法来实现判断用户一个月的签到情况:

  1. 每天对应一个数
1
dayNum = Math.pow(2, day); // day是日期(几号)
  1. 如果该天签到,则签到数值加上该数值
1
daySum += dayNum;
  1. 判断某天是否签到
1
(dayNum & daySum) === dayNum

比如

1
2
3
4
5
6
7
8
// 假设用户1 3 5号三天签到了
let daySum = Math.pow(2, 1) + Math.pow(2, 3) + Math.pow(2, 5);
// 判断2号是否签到
let day2 = Math.pow(2, 2);
console.log((day2 & daySum) === day2); // false
// 判断3号是否签到
let day3 = Math.pow(2, 3);
console.log((day3 & daySum) === day3); // false

  关于原理,用二进制来算,就一目了然了。

创建重复的字符串

1
2
3
4
5
6
7
8
9
let repeat1 = '';
for (let i = 0; i < 7; i++) {
repeat1 += 'a';
}
console.log('repeat1=', repeat1); // aaaaaaa
let repeat2 = Array(7).join('a');
console.log('repeat2=', repeat2); // aaaaaa
let repeat3 = 'a'.repeat(7); // ES6写法
console.log('repeat3=', repeat3); // aaaaaaa
  • 第三种写法是ES6的api,将字符串复制指定次数。
  • 第二种写法是借助join的插入函数实现需求功能,这里其实不是很推荐,因为你打印repeat2会发现,其实只有6个a,因为join是在元素中插入,所以这里要实现复制7次就得创建一个8个元素的数组,一个字符串还要先创建一个数组,个人觉得没必要。

清空数组的操作

1
2
3
4
5
let arr = [1,2,3];
// 第一种写法
arr = [];
// 第二种写法
arr.length = 0;

  两种写法有什么区别呢?
  第一种写法其实是赋值一个新数组给变量aar,第二种写法是直接操作原数组。看下面例子

1
2
3
4
5
6
7
8
9
let arr = [1, 2, 3];
let arr2 = arr;
arr = [];
console.log('arr=', arr); // []
console.log('arr2=', arr2); // [ 1, 2, 3 ]
arr = arr2;
arr2.length = 0;
console.log('arr=', arr); // []
console.log('arr2=', arr2); // []
  • 两种写法,很明显不能一棍子说优劣,但如果你的数组不需要使用了,自然应该使用Array.length=0的写法。

END

  最后附赠JS社区玩坏的梗~

1
2
console.log(([][[]] + [])[+!![]] + ([] + {})[!+[] + !![]]);
console.log((!(~+[]) + {})[--[~+""][+[]] * [~+[]] + ~~!+[]] + ({} + [])[[~!+[]] * ~+[]]);

以上所有知识点皆来源于网络,各位有兴趣可以再去深入了解,如果发现本文有什么错误,可以后台给我留言。最后,非常感谢陈皮皮【公众号:菜鸟小栈】提供的几款VSCode的插件,真的好用!!!