JS 中可以提升幸福度的小技巧

本文主要介绍一些JS中用到的小技巧,可以在日常Coding中提升幸福度,将不定期更新~

表达式和运算符

短路运算符 &&||

我们知道逻辑与 && 与逻辑或 || 是短路运算符,短路运算符就是从左到右的运算中前者满足要求,就不再执行后者了;可以理解为:

  • && 为取假运算,从左到右依次判断,如果遇到一个假值,就返回假值,以后不再执行,否则返回最后一个真值
  • || 为取真运算,从左到右依次判断,如果遇到一个真值,就返回真值,以后不再执行,否则返回最后一个假值
    1
    2
    3
    4
    5
    // 逻辑与返回第一个是 false 的操作数 或者 最后一个是 true的操作数
    console.log(1 && 2 && 0); //0
    console.log(1 && 0 && 1); //0
    console.log(1 && 2 && 3); //3
    // 如果某个操作数为 false,则该操作数之后的操作数都不会被计算
1
2
3
4
5
// 逻辑或返回第一个是 true 的操作数 或者 最后一个是 false的操作数 
console.log(1 || 2 || 0); //1
console.log(0 || 2 || 1); //2
console.log(0 || 0 || false); //false
// 如果某个操作数为 true,则该操作数之后的操作数都不会被计算

如果逻辑与和逻辑或作混合运算,则逻辑与的优先级高:

1
2
3
console.log(1 && 2 || 0); //2 
console.log(0 || 2 && 1); //1
console.log(0 && 2 || 1); //1

按位操作符 &|

  • & 两个数值的个位分别相与,同时为 1才得 1,只要一个为 0就为 0
  • | 两个数值的只要有一个为 1,那么结果都为 1。否则就为 0

判断奇偶数 &1

对一个数字 &1 可以判断奇偶数,负数也同样适用, num&1

1
2
1.3 | 0   // 1
-1.9 | 0 // 1

取整 |0

对一个数字 |0可以取整,负数也同样适用,num|0

1
2
1.3 | 0   // 1
-1.9 | 0 // 1

类型强制转换

双位运算符 ~~

可以使用双位操作符来替代 Math.floor()。双否定位操作符的优势在于它执行相同的操作运行速度更快。

1
2
3
Math.floor(6.66) === 6  // true
// 简写为>>:
~~6.66 === 6 // true

不过要注意,对整数来说 ~~ 运算结果与 Math.floor() 运算结果相同,而对于负数来说不相同:

1
2
Math.floor(-6.66)  // -7
~~-6.66 // -6
1
2
3
4
5
6
7
8
9
10
// 转换成布尔值Boolean 用 !!
!![] === true

// 转换成数值Number 用 +
+[] === 0

// 转换成字符串 用 ''+
''+[] === ''
// 取整数 用~~
~~6.66 === 6

代码复用

Object [key]

虽然将 foo.bar 写成 foo [‘bar’] 是一种常见的做法,但是这种做法构成了编写可重用代码的基础.许多框架使用了这种方法,比如element的表单验证

请考虑下面这个验证函数的简化示例:

1
2
3
4
5
6
7
8
function validate(values) {
if(!values.first)
return false;
if(!values.last)
return false;
return true;
}
console.log(validate({first:'Bruce',last:'Wayne'})); // true

上面的函数完美的完成验证工作.但是当有很多表单,则需要应用验证,此时会有不同的字段和规则.如果可以构建一个在运行时配置的通用验证函数,会是一个好选择.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// object validation rules
const schema = {
first: {
required:true
},
last: {
required:true
}
}

// universal validation function
const validate = (schema, values) => {
for(field in schema) {
if(schema[field].required) {
if(!values[field]) {
return false;
}
}
}
return true;
}
console.log(validate(schema, {first:'Bruce'})); // false
console.log(validate(schema, {first:'Bruce',last:'Wayne'})); // true

现在有了这个验证函数,我们就可以在所有窗体中重用,而无需为每个窗体编写自定义验证函数

数据模拟 MOCK

生成指定两个整数范围内的随机整数

1
const random = (m, n) => m + Math.floor(Math.random() * (n - m));random(0, 10);

一个固定值填充整个数组

1
Array(6).fill(1);      // [1, 1, 1, 1, 1, 1]

有序数组

1
2
3
Array.from({length: 10}, (v, i) => i)  // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Array(10).fill().map((v, i) => i++)
[...Array(10).keys()]

函数

函数默认值

1
2
const func = (a,b=3,c=4) => a+b+c;
func(1) // 8

注意,传入参数为 undefined 或者不传入的时候会使用默认参数,但是传入 null 还是会覆盖默认参数。

强制参数

ES6提供了默认参数值机制,允许你为参数设置默认值,防止在函数被调用时没有传入这些参数。

在下面的例子中,我们写了一个required()函数作为参数a和b的默认值。这意味着如果a或b其中有一个参数没有在调用时传值,会默认required()函数,然后抛出错误。

1
2
3
4
5
6
7
8
const required = (key='') => {
// throw new Error('Missing parameter!')
console.error(`缺少参数${key}`)
}
// 这里如果不传入参数,就会执行 required 函数报出错误
const add = (a = required(), b = required()) => a + b;
add(1, 2) // 3
add(1) // Error: Missing parameter.

惰性载入函数

在某个场景下我们的函数中有判断语句,这个判断依据在整个项目运行期间一般不会变化,所以判断分支在整个项目运行期间只会运行某个特定分支,那么就可以考虑惰性载入函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function foo(){
if(a !== b){
console.log('aaa')
}else{
console.log('bbb')
}
}
// 优化后
function foo(){
if(a !== b){
foo = function(){
console.log('aaa')
}
}else{
foo = function(){
console.log('bbb')
}
}
return foo()
}

那么第一次运行之后就会覆写这个方法,下一次再运行的时候就不会执行判断了。当然现在只有一个判断,如果判断很多,分支比较复杂,那么节约的资源还是可观的。

一次性函数

跟上面的惰性载入函数同理,可以在函数体里覆写当前函数,那么可以创建一个一次性的函数,重新赋值之前的代码相当于只运行了一次,适用于运行一些只需要执行一次的初始化代码

1
2
3
4
5
6
7
8
9
const sca = function() {
console.log('msg')
sca = function() {
console.log('foo')
}
}
sca() // msg
sca() // foo
sca() // foo

对象

使用解构删除不必要属性

有时候你不希望保留某些对象属性,也许是因为它们包含敏感信息或仅仅是太大了(just too big)。你可能会枚举整个对象然后删除它们,但实际上只需要简单的将这些无用属性赋值给变量,然后把想要保留的有用部分作为剩余参数就可以了。

下面的代码里,我们希望删除_internal和tooBig参数。我们可以把它们赋值给internal和tooBig变量,然后在cleanObject中存储剩下的属性以备后用。

1
2
3
let { _internal, tooBig, ...cleanObject } = { el1: '1', _internal: "secret", tooBig: {}, el2: '2', el3: '3' }

console.log(cleanObject); // {el1: '1', el2: '2', el3: '3'}

数组

统计数组中相同项的个数

很多时候,你希望统计数组中重复出现项的个数然后用一个对象表示。那么你可以使用reduce方法处理这个数组。

下面的代码将统计每一种车的数目然后把总数用一个对象表示。

1
2
3
4
5
6
let cars = ['BMW','Benz', 'Benz', 'Tesla', 'BMW', 'Toyota']
let carsObj = cars.reduce( (obj, name) => {
obj[name] = obj[name] ? ++obj[name] : 1;
return obj
}, {})
carsObj; // => { BMW: 2, Benz: 2, Tesla: 1, Toyota: 1 }