写在前面的话

这是一篇提升编程技巧的文章,我敢肯定几乎是每一个优秀的程序员必须掌握的编程技巧。

这些年来一直在学习,这些技巧有些是从网上看到的,有些是阅读源码时看到的,还有一些是平时编程过程中的最佳实践,所以我写了这篇文章。

文章还提供了一些示例代码,还有一些说明,帮助初学者理解这些代码。

三元操作符

1
2
3
4
5
6
7
8
const age = 30
let result

if (age > 30) {
result = '年龄大于30'
} else {
retuslt = '年龄小于等于30'
}

用于三元操作符代替if else语言,写出更简洁的代码:

1
const result = age > 30 ? '年龄大于30' : '年龄小于等于30'

表达式也可以内嵌:

1
const result = age > 30 ? '年龄大于30' : age > 20 ? '年龄大于20' : age > 10 ? '年龄大于10' : '年龄小于等于10'

巧用 || 赋值

为了确保要赋的值是一个有效的变量,你可能会写出这样的代码:

1
2
3
4
let a
if (b !== null || b !== undefined || b !== '') {
a = b;
}

我们使用 || 赋值就可以这样写:

1
var a = b || 'new';

注意: 如果b的值是 0false, 那么a的值就是new

if 条件判断简写

1
2
3
if (testvar === true) {
// do something...
}

在进行 if 条件判断时,我们是可以省略比较运算符的:

1
2
3
if (testvar) {
// do something...
}

科学计数法

你可能见过这种写法: 这种结尾不带0的数字写法。例如,1e7实际上就是1后面跟7个0。它表示一个十进制数字(JavaScript将其解释为浮点类型),等于10,000,000。

1
for (let i = 0; i < 10000; i++) {}

科学计数法:

1
2
3
4
5
6
7
8
9
for (let i = 0; i < 1e4; i++) {}

// 下面的值是相等的
1e0 === 1;
1e1 === 10;
1e2 === 100;
1e3 === 1000;
1e4 === 10000;
1e5 === 100000;

箭头函数

普通函数一旦发生函数嵌套,会显得臃肿:

1
2
3
4
5
6
7
8
9
10
11
function sayHello(name) {
console.log('Hello', name);
}

setTimeout(function() {
console.log('Finished')
}, 2000);

list.forEach(function(item) {
console.log(item);
});

而使用箭头函数后,就可以这样写:

1
2
3
4
5
sayHello = name => console.log('Hello', name);

setTimeout(() => console.log('Finished'), 2000);

list.forEach(item => console.log(item));

注意:两种写法不是完全等价的,因为箭头函数内部的this是固定的。

隐式return

return 是javascript里函数返回值的关键字。如果箭头函数是一个表达式,会隐式返回结果

1
2
3
function calcCircumference(diameter) {
return Math.PI * diameter
}

加括号的函数体返回对象字面量:

1
const calcCircumference = diameter => (Math.PI * diameter)

默认参数

1
2
3
4
5
function speed(l, w, h) {
w = w || 3
h = h || 4
return l * w * h;
}

在ES6, 您可以在函数声明中定义参数默认值:

1
2
speed = (l, w = 3, h = 4 ) => (l * w * h);
speed(2) // 2 * 3 * 4 = 24

多行字符串拼接

如果你曾经发现自己需要编写多行字符串的代码,你会怎么写:

1
2
3
4
5
6
const lorem = '先来看全国的确诊数据和新增确诊数据:2月11日0—24时,\n\t'
+ '31个省(自治区、直辖市)和新疆生产建设兵团报告,\n\t'
+ '新增确诊病例2015例(湖北1638例),\n\t'
+ '新增重症病例871例(湖北897例),\n\t'
+ '新增死亡病例97例(湖北94例,河南、湖南、重庆各1例),\n\t'
+ '新增疑似病例3342例(湖北1685例),当日新增治愈出院病例744例(湖北417例)。\n\t'

有一个简单的写法:使用反引号

1
2
3
4
5
6
const lorem = `先来看全国的确诊数据和新增确诊数据:2月11日0—24时,
31个省(自治区、直辖市)和新疆生产建设兵团报告,
新增确诊病例2015例(湖北1638例),
新增重症病例871例(湖北897例),
新增死亡病例97例(湖北94例,河南、湖南、重庆各1例),
新增疑似病例3342例(湖北1685例),当日新增治愈出院病例744例(湖北417例)。`

展开操作符

展开操作符:将一个数组转为用逗号分隔的参数序列。

1
2
3
4
5
6
7
// joining arrays
const odd = [1, 3, 5];
const nums = [2 ,4 , 6].concat(odd);

// cloning arrays
const arr = [1, 2, 3, 4];
const arr2 = arr.slice()

在ES6中,可以使用展开运算符:

1
2
3
4
5
6
7
8
// joining arrays
const odd = [1, 3, 5 ];
const nums = [2 ,4 , 6, ...odd];
console.log(nums); // [ 2, 4, 6, 1, 3, 5 ]

// cloning arrays
const arr = [1, 2, 3, 4];
const arr2 = [...arr];

不使用 contact 方法,你可以使用展开运算符,将一个数组插入到另外一个数组的任何一个位置。

1
2
const odd = [1, 3, 5 ];
const nums = [2, ...odd, 4, 6];

展开运算符也可以和解构赋值结合使用:

1
2
3
4
const { a, b, ...z } = { a: 1, b: 2, c: 3, d: 4 };
console.log(a) // 1
console.log(b) // 2
console.log(z) // { c: 3, d: 4 }

强制校验参数

默认情况下,你在调用一个函数的时候,未传入任何参数,这个参数会被当做 undefined 处理。

你可以用if判断当参数为 undefined 时,抛出一个错误:

1
2
3
4
5
6
function foo(bar) {
if(bar === undefined) {
throw new Error('缺少参数!');
}
return bar;
}

你可以采用强制校验参数:

1
2
3
4
5
6
7
mandatory = () => {
throw new Error('缺少参数!');
}

foo = (bar = mandatory()) => {
return bar;
}

Object[key]

Foo.bar 等价于 Foo['bar'] ,这种写法可以让我们更好的复用代码。

来看下面这一段简化后的校验表单的例子:

1
2
3
4
5
6
7
8
9
function validate(values) {
if(!values.first)
return false;
if(!values.last)
return false;
return true;
}

console.log(validate({first: 'Kobe', last: 'Bryant'})); // true

但是,考虑这样一个场景: 如果项目中有很多表单需要校验,但是每个表单字段的校验规则又都不一样。

我们可以考虑创建一个可以在运行时配置的通用验证函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 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: 'Kobe'})); // false
console.log(validate(schema, {first: 'Kobe', last: 'Bryant'})); // true

现在我们将验证规则和校验函数分开,提高了代码的扩展性。

~ (按位非)

有一个非常实用的双按位不操作符的用例。可以使用它来替代Math.floor()

优点是,它的运算速度更快。你可以在这里阅读更多关于按位运算符的信息。

1
2
3
Math.floor(4.9) === 4  //true

~~4.9 === 4 //true

String 转 Number

1
2
const num1 = parseInt("100");
const num2 = parseFloat("100.01");
1
2
const num1 = +"100"; // converts to int data type
const num2 = +"100.01"; // converts to float data type

按位非(~)代替 indexOf()

使用数组执行查找时,indexOf() 函数用于检索要查找元素的位置。如果没有找到该元素,则返回值 -1。在JavaScript中,0被认为是false,而大于或小于0的数字被认为是true

因此,必须像这样写代码:

1
2
3
4
5
6
7
if(arr.indexOf(item) > -1) { // Confirm item IS found

}

if(arr.indexOf(item) === -1) { // Confirm item IS NOT found

}
1
2
3
4
5
6
7
if(~arr.indexOf(item)) { // Confirm item IS found

}

if(!~arr.indexOf(item)) { // Confirm item IS NOT found

}

按位(~)运算符将为除 -1 以外的任何值返回 true,取反直接前面加 ! 即可。

我们也可以使用 include() 函数:

1
2
3
if(arr.includes(item)) { // Returns true if the item exists, false if it doesn't

}

结束

我通过阅读大量的优秀的源码和文章找到这些代码最佳实践,当然还有很多,都需要我们共同去收集。如果你其他更好的实践,请通过评论告诉我,非常感谢!

如果这篇文章对你有用,麻烦点个赞👍!