【本文参与征文活动】
“阅前必阅”
JavaScript博大精深,本人只是在工作中,发现了一些js的各种写法,下面介绍的是一些能简化代码量的写法,但是有一些我是不太推荐的,详细原因也有论述。抛的砖是砸到头了还是引出了玉,就看各位了。
切换变量0和1
// if判断可以这么写
let flag = 0;
if (flag === 0) {
flag = 1;
} else {
flag = 0;
}
// 也可以用三目运算符
flag = flag === 0 ? 1 : 0;
// 也可以使用位异或(^)
flag ^= 1;
一般我要求自己的团队在js上是尽量少用位运算,为什么呢?因为位运算其实二进制数执行运算,包括与&、或|、异或^、非~、左移<<、右移>>都是整数的逐位运算。然而,不幸的是在js内部所有数字都是双精度浮点数,所以这些运算js会先转为整数再运算,而且代码阅读性也会降低。
其实说到位运算,还不得不提一个月更贴,为什么
console.log(0.1 + 0.2 === 0.3); // false
总结一句就是十进制转二进制的精度丢失,如果想深入了解,推荐一篇文章0.1 + 0.2不等于0.3?为什么JavaScript有这种“骚”操作?
!!
继续说位运算中的非,我在项目中看到越来越多的人用!!来判空等操作,针对一般场景也没什么问题,但是毫无节制的使用!!真的有必要吗?比如已知表达式就是一个Boolean值,还需要这样判断吗?
非运算字面比较简单——真就是假,假就是真,不过js的类型特点,还是详细看下:
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范畴,我也更推荐下面的做法:
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' }));
如果你只是单纯的想判断空,可以使用下面的方法
function isEmpty(str) {
return null == str || '' == str;
}
console.log(isEmpty(0));
console.log(isEmpty(void 0));
console.log(isEmpty(null));
交换值
如果用位运算,则
let a = 1;
let b = 2;
a ^= b;
b ^= a;
a ^= b;
console.log(a); // 2
console.log(b); // 1
但与借助中间值,似乎差距不大
let a = 1;
let b = 2;
let c = a;
a = b;
b = c;
console.log(a); // 2
console.log(b); // 1
而现在基本都支持ES6的情况下,其实可以用解构来操作
let a = 1;
let b = 2;
[a, b] = [b, a];
console.log(a); // 2
console.log(b); // 1
- 解构一般用来如本例的交换值,或者从对象取值,如
// 从对象中取值
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
但解构的作用可不仅仅是如此,还有很多妙处,比如:从数组中取一个值,如果该索引不存在则赋一个默认值
let arr = [1];
let value = 'a';
if (arr.length > 1) {
value = arr[1];
}
console.log(value); // a
而用解构,则仅需
let arr = [1];
let [, value = 'a'] = arr;
console.log(value); // a
用户签到
在开发中,我用位运算较多的一个场景——签到,比如下面的做法来实现判断用户一个月的签到情况:
- 每天对应一个数
dayNum = Math.pow(2, day); // day是日期(几号)
- 如果该天签到,则签到数值加上该数值
daySum += dayNum;
- 判断某天是否签到
(dayNum & daySum) === dayNum
比如
// 假设用户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); // true
关于原理,转成二进制去运算,就一目了然了。
创建重复的字符串
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个元素的数组,一个字符串还要先创建一个数组,个人觉得没必要。
清空数组的操作
let arr = [1,2,3];
// 第一种写法
arr = [];
// 第二种写法
arr.length = 0;
两种写法有什么区别呢?
第一种写法其实是赋值一个新数组给变量aar,第二种写法是直接操作原数组。看下面例子
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社区玩坏的梗~
console.log(([][[]] + [])[+!![]] + ([] + {})[!+[] + !![]]);
console.log((!(~+[]) + {})[--[~+""][+[]] * [~+[]] + ~~!+[]] + ({} + [])[[~!+[]] * ~+[]]);
以上所有知识点皆来源于网络,各位有兴趣可以再去深入了解,如果发现本文有什么错误,可以给我留言。
顺便推荐各位关注我的公众号: