高效编写Javascript代码的技巧
- 什么是优雅的代码✨
- 1. 对不允许更改的常量声明——const
- 2. 对允许更改的变量——let
- 3. 声明对象——{}
- 4. 声明数组——[]
- 5. 连接字符串——``
- 6. 使用对象方法的简写——fn(){}
- 7. 对象中的值简写——{ value }
- 8. 将对象值分配给另一个对象的示例——{ ...obj }
- 9. 给数组添加元素——push
- 10. 连接数组——[ ...arr1, ...arr2 ]
- 11. 获取对象的多个属性——{ name, value }
- 12. 从对象获取值——{ a, b }
- 13. 创建函数——() => {}
- 14. 函数中设置默认值——(a = 1) => {}
- 15. 求和——reduce
- 16. 判断某个属性值是否存在于数组中——some
- 17. 布尔值的快捷方式——===
- 18. 值的快捷方式——三目运算符
- 19. 循环遍历数组元素——for..in
- 20. if多条件判断——includes()
- 21. if...else...——隐式转换
- 22. null/undefined/''检查——||
- 23. 空对象{}检查——Object.keys(data).length
- 24. 空数组[]检查——data.length
- 25. 函数条件调用——三目运算符
- 26. switch条件判断——&&
- 27. 多行字符串——``
- 28. 函数隐式返回——return
- 29. 重复多次字符串——repeat()
- 30. 指数运算——**
- 31. 把对象转换成一个由若干对象组成的数组——Object.entries()
- 32. 数字转换成整型——~~
- 33. 非布尔值类型转化成布尔值类型——!!
- 34. 判断当前对象是否存在,若存在则执行下一个,不存在则抛出——可选链操作符?.
- 35. 值为null或undefined时设置默认值——??
- 36. 遍历获取对象中所有属性名——Object.keys()
- 37. 遍历获取对象中所有属性值——Object.keys()
- 38. switch-case更短的替代方案——对象字典
- 39. If,for…in,for…of和的使用
- 40. 过滤数组中的所有假值——filter
- 41. 取整——num | 0
- 42. 判断对象中是否存在某个属性——in
- 43. 将数组平铺到指定深度——flat()
- 44. 对象数组按照某个属性查询最大值——Math.max.apply()
- 45. 删除对象某个属性——{ a, b, ...obj }
- 46. 使用数组成员对变量赋值时——const [a, b] = arr
什么是优雅的代码✨
优雅的代码包括以下方面:
首先就是代码的简洁,能够使用一行代码解决的,就不要写两行及以上,其次就是便于阅读,代码不仅仅是用来让机器(服务器,浏览器)来运行的,而是需要用人来编写,维护的,可能是自己,也可能是现在的同事,未来的同事,这个就是代码的可维护性
还有一个就是我们很关注的就是性能,就比如我们经常写的循环,在满足业务功能条件的时候,能少一次循环就少一次循环,还有就是不再使用的引用类型的数据,要及时手动的进行内存的释放,(虽然有垃圾回收机制),但是早一点释放内存是不是更好呢
1. 对不允许更改的常量声明——const
// bad
var a = 1;
// good
const a = 1;
2. 对允许更改的变量——let
// bad
var a = 1;
for (var i; i < 10; i++){
a = 1 + i;
}
// good
let a = 1;
for (let i; i < 10; i++){
a += i
}
3. 声明对象——{}
// bad
const obj = new Object();
// good
const obj = {};
4. 声明数组——[]
// bad
const arr = new Array();
// good
const arr = [];
5. 连接字符串——``
// bad
const str = 'world';
const newStr = 'hello' + str;
// good
const str = 'world';
const newStr = `hello ${str}`;
6. 使用对象方法的简写——fn(){}
// bad
const obj = {
val: 1,
fn: function() {
return obj.val + 1;
}
}
// good
const obj = {
val: 1,
fn(){
return obj.val++;
}
}
7. 对象中的值简写——{ value }
// bad
const value = 1;
const obj = { value: value };
//good
const value = 1;
const obj = { value };
8. 将对象值分配给另一个对象的示例——{ …obj }
// bad
const obj1 = { a: 1, b: 2 };
let obj2 = { c: 3, d: 4 };
obj2.a = obj1.a;
obj2.b = obj1.b;
// good
const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1, c: 3, d: 4 };
9. 给数组添加元素——push
// bad
const arr = [];
arr[arr.length] = "hello world";
// good
const arr = [];
arr.push("hello world");
10. 连接数组——[ …arr1, …arr2 ]
// bad
const arr1 = [1, 2, 3, 4, 5];
const arr2 = [6, 7, 8, 9, 10];
const arr = arr1.concat(arr2);
// good
const arr1 = [1, 2, 3, 4, 5];
const arr2 = [6, 7, 8, 9, 10];
const arr = [...arr1, ...arr2];
11. 获取对象的多个属性——{ name, value }
// bad
function fn(obj) {
return `${obj.name} ${obj.value}`
}
// good
function fn({ name, value }) {
return `${name} ${value}`
}
12. 从对象获取值——{ a, b }
// bad
const obj = { a: 1, b: 2 };
const a = obj.a;
const b = obj.b;
// good
const obj = { a: 1, b: 2 };
const { a, b } = obj;
13. 创建函数——() => {}
// bad
function fn() {};
// bad
const fn = function() {};
// good
const fn = () => {};
14. 函数中设置默认值——(a = 1) => {}
// bad
const fn = (a, b) => {
if(!a) a = 1;
if(!b) b = 1;
return { a, b };
}
// good
const fn = (a = 1, b = 2) => {
return { a, b };
}
15. 求和——reduce
// bad
const arr= [1, 2, 3, 4, 5];
let total = 0;
arr.forEach( (n) => { total += n})
// bad
const arr = [1, 2, 3, 4, 5];
let total = 0;
for (let i; i < arr.length; i++){
total += arr[i];
}
// good
const arr = [1, 2, 3, 4, 5];
const total = arr.reduce((total, num) => total + num);
16. 判断某个属性值是否存在于数组中——some
// bad
const arr = [{ a: 1 }, { a: 2 }, { a: 3 }];
let exist = false;
arr.forEach(item => {
if(item.a === 2) exist = true;
});
// good
const arr = [{ a: 1 }, { a: 2 }, { a: 3 }];
const exist = arr.some(item => item.a === 2)
17. 布尔值的快捷方式——===
// bad
const a = 1;
const b = 1;
let isTrue = false;
if(a === b) {
isTrue = true;
}
// good
const a = 1;
const b = 1;
const isTrue = a === b;
18. 值的快捷方式——三目运算符
// bad
const a = 5;
let b;
if(a === 5) {
b = 3;
} else {
b = 2;
}
// good
const a = 5;
const b = a === 5 ? 3 : 2;
19. 循环遍历数组元素——for…in
// bad
const arr= [1, 2, 3, 4, 5];
for(let i = 0; i < arr.length; i++) {
console.log(arr[i]);
}
// good
const arr= [1, 2, 3, 4, 5];
for(let val of heroes) {
console.log(val);
}
20. if多条件判断——includes()
// bad
if(x === 'abc' || x === 'def' || x === 'ghi' || x === 'jkl'){}
// good
if(['abc', 'def', 'ghi', 'jkl'].includes(x)){}
21. if…else…——隐式转换
// bad
let test;
if(x > 10){
test = true;
}else{
test = false;
}
// good
const test = x > 10;
22. null/undefined/’'检查——||
// bad
if(data !== null || data !== undefined || data !== ''){
let arr = data;
}
// good
let arr = data || '';
23. 空对象{}检查——Object.keys(data).length
// bad
const data = {};
if(JSON.stringify(data) == "{}"){}
// good
const data = {};
if(Object.keys(data).length){}
24. 空数组[]检查——data.length
// bad
const data = [];
if(JSON.stringify(data) == "[]"){}
// good
const data = [];
if(data.length){}
25. 函数条件调用——三目运算符
// bad
function test() {
console.log('test1');
};
function test2() {
console.log('test2');
}
var test3 = 1;
if(test3 === 1){
test1();
}else{
test2();
}
// good
(test3 === 1 ? test1 : test2)();
26. switch条件判断——&&
// bad
switch (data) {
case 1:
test1();
break;
case 2:
test2();
break;
case 3:
test3();
break;
}
// good
var data = {
1: test1,
2: test2,
3: test
};
data[1] && data[1]();
data[2] && data[2]();
data[3] && data[3]();
27. 多行字符串——``
// bad
const data = 'abc abc abc abc abc abc\n\t'
+ 'test test,test test test test\n\t'
// good
const data = `abc abc abc abc abc abc
test test,test test test test`
28. 函数隐式返回——return
// bad
function fn(a) {
return Math.PI * a;
}
// good
const fn = a => (
Math.PI * a
)
29. 重复多次字符串——repeat()
// bad
let str = '';
for(let i = 0; i < 5; i++) {
str += 'test';
}
// good
'test '.repeat(5);
30. 指数运算——**
// bad
Math.pow(2, 3);
// good
2**3
31. 把对象转换成一个由若干对象组成的数组——Object.entries()
// bad
const data = { a: 1, b: 2, c: 3 };
const arr = [];
for(const key in data){
arr.push([key, data[key]]);
};
console.log(arr);
// good
const data = { test1: 'abc', test2: 'cde', test3: 'efg' };
const arr = Object.entries(data);
console.log(arr);
// 输出
[ [ 'a', 1 ],
[ 'b', 2 ],
[ 'c', 3 ] ]
32. 数字转换成整型——~~
(两个按位非运算符只适用于 32 位整型)
// bad
Math.floor(1.9) === 1;
// good
~~1.9 === 1
33. 非布尔值类型转化成布尔值类型——!!
// bad
if(Boolean([].length)){}
// good
if(!![].length){}
34. 判断当前对象是否存在,若存在则执行下一个,不存在则抛出——可选链操作符?.
可选链操作符?.的作用就是判断这个对象(res)下的(res.data)下的(res.data.list)是否为null或者undefined,当其中一链为null或者undefined时就返回undefined,这样即使中间缺少一个属性也不会报错
// bad
let arr = res && res.data && res.data.list
// good
let arr = res?.data?.list
35. 值为null或undefined时设置默认值——??
// bad
let arr = res && res.data || []
// good
let arr = res?.data ?? []
【拓展】关于||与??的区别
||: 判断布尔值为false时,赋默认值
??:只判断null和undefined时,赋默认值
console.log(1 || "xx") //1
console.log(0 || "xx") //xx
console.log(null || "xx") //xx
console.log(undefined || "xx") //xx
console.log(-1 || "xx") //-1
console.log("" || "xx") //xx
console.log(1 ?? "xx") //1
console.log(0 ?? "xx") //0
console.log(null ?? "xx") //xx
console.log(undefined ?? "xx") //xx
console.log(-1 ?? "xx") //-1
console.log("" ?? "xx") //''
36. 遍历获取对象中所有属性名——Object.keys()
// bad
let arr = [];
for(const key in {key1: 1, key2: 2}){
arr.push(key)
}
console.log(arr); // ["key1", "key2"]
// good
console.log(Object.keys({key1: 1, key2: 2})); // ["key1", "key2"]
37. 遍历获取对象中所有属性值——Object.keys()
// bad
let arr = [];
const obj = {key1: 1, key2: 2};
for(const key in obj ){
arr.push(obj[key])
}
console.log(arr); // [1, 2]
// good
console.log(Object.values({key1: 1, key2: 2})); // [1, 2]
38. switch-case更短的替代方案——对象字典
const num = 3
// bad
switch (num) {
case 1:
console.log(123);
break;
case 2:
console.log(456);
break;
case 3:
console.log(789);
break;
}
// good
cases = {
1: () => {
console.log(123);
},
2: () => {
console.log(456);
},
3: () => {
console.log(789);
},
default: () => {
console.log('default');
}
};
cases[num]() || cases['default'](); // 789
39. If,for…in,for…of和的使用
- 能用三元运算符就用,减少if的嵌套
- 减少多余条件判断,查询结束立即返回**(早返回,多返回)**,如果是函数返回if里面和外面返回相同的数据类型
- If…else if…else多个条件时以else结尾,因为符合防御性编程规则
- NaN不应该用于比较,应该是判断是否是数字
- Switch…case使用在至少有三个判断值,case不可省,每次case必须用break跳出
- for…of遍历数组和字符串
- for…in遍历对象
For…in遍历对象包括所有继承的属性,所以如果只是想使用对象本身的属性需要做一个判断
40. 过滤数组中的所有假值——filter
const compact = arr => arr.filter(Boolean)
compact([0, 1, false, 2, '', 3, 'a', 'e' * 23, NaN, 's', 34]) // [ 1, 2, 3, 'a', 's', 34 ]
41. 取整——num | 0
1.3 | 0 // 1
-1.9 | 0 // -1
42. 判断对象中是否存在某个属性——in
'a' in { a: 1, b: 2, c: 3 } // true
'd' in { a: 1, b: 2, c: 3 } // false
43. 将数组平铺到指定深度——flat()
let a1 = [{a:1},{a:2},[{a:3},{a:4},[{a:5}]]]
a1.flat() // [{a:1},{a:2},{a:3},{a:4},[{a:5}]]
44. 对象数组按照某个属性查询最大值——Math.max.apply()
var array=[
{
"index_id": 119,
"area_id": "18335623",
"name": "满意度",
"value": "100"
},
{
"index_id": 119,
"area_id": "18335624",
"name": "满意度",
"value": "20"
},
{
"index_id": 119,
"area_id": "18335625",
"name": "满意度",
"value": "80"
}];
// 一行代码搞定
Math.max.apply(Math, array.map(function(o) {return o.value}))
45. 删除对象某个属性——{ a, b, …obj }
let {_internal, tooBig, ...cleanObject} = {el1: '1', _internal:"secret", tooBig:{}, el2: '2', el3: '3'};
console.log(cleanObject); // {el1: '1', el2: '2', el3: '3'}
46. 使用数组成员对变量赋值时——const [a, b] = arr
const Arr = [1, 2, 3, 4];
// bad
const first = Arr[0];
const second = Arr[1];
// good
const [first, second] = Arr;