// good
list.map(item=> item *2);// goodconstfetchName=asyncid=>{const user =awaitrequest(`users/${id}`);return user.fullName;};// bad
list.map((item)=> item *2);// badconstfetchName=async(id)=>{const user =awaitrequest(`users/${id}`);return user.fullName;};
箭头函数的函数体只有一个单行表达式语句,且作为返回值时,省略 {} 和 return
// good
list.map(item=> item *2);constfoo=()=>(
condition
?returnValueA():returnValueB());// bad
list.map(item=>{return item *2;});
箭头函数的函数体只有一个 Object Literal,且作为返回值时,使用 () 包裹
// good
list.map(item=>({name: item[0],email: item[1]}));
在 if / else / for / do / while 语句中,即使只有一行,也不得省略块 {…}
// goodconst hangModules =[];const missModules =[];const visited ={};// bad 一次声明多个变量const hangModules =[],
missModules =[],
visited ={};// bad 使用保留字作为变量名constfunction='a';// bad 将`undefined`赋值给变量const a =undefined;// bad 连续赋值const a = b = c =5;
变量建议 即用即声明,不得在函数或其它形式的代码块起始位置统一声明所有变量
// goodfunctionkv2List(source){const list =[];for(let key in source){if(source.hasOwnProperty(key)){const item ={k: key,v: source[key],};
list.push(item);}}const str = list.join('/');return{ list, str };}// badfunctionkv2List(source){const list =[];let key;let item;let str;for(key in source){if(source.hasOwnProperty(key)){
item ={k: key,v: source[key],};
list.push(item);}}
str = list.join('/');return{ list, str };}
// goodconst{first: firstName,last: lastName }= person;const one =1;const two =2;// badconst[ one, two, three ]=[1,2,3];const{ one, two }={one:1,two:2};
使用剩余运算符时,剩余运算符之前的所有元素必需具名
// goodlet[one, two,...anyOther]= myArray;let other = myArray.slice(3);// badlet[,,,...other]= myArray;
// goodif(!expressionA){return;}process(a);if(!expressionB){return;}process(b);if(expressionC){// do sth}else{// do sth}// badif(expresssionA){process(a);if(expressionB){process(b);if(expressionC){// do sth}else{// do sth}}}
switch(typeof variable){case'object':// ......break;case'number':case'boolean':case'string':// ......break;}// badconst type =typeof variable;if(type ==='object'){// ......}elseif(type ==='number'|| type ==='boolean'|| type ==='string'){// ......}
switch 语句
每个 case 标签要么通过 break,return,throw 结束,要么通过注释直接跳过到下一标签。
即使 default 标签中不包含逻辑,也不要省略。
// goodswitch(input){case1:case2:prepareOneOrTwo();// fall throughcase3:handleOneTwoOrThree();break;default:handleLargeNumber(input);}
循环
不要在循环体中包含函数表达式,事先将函数提取到循环体外
// goodfunctionclicker(){// ......}for(let i =0, len = elements.length; i < len; i++){const element = elements[i];addListener(element,'click', clicker);}// badfor(let i =0, len = elements.length; i < len; i++){const element = elements[i];addListener(element,'click',function(){});}
对循环内多次使用的不变值,在循环外用变量缓存
// goodconst width = wrap.offsetWidth +'px';for(let i =0, len = elements.length; i < len; i++){const element = elements[i];
element.style.width = width;// ......}// badfor(let i =0, len = elements.length; i < len; i++){const element = elements[i];
element.style.width = wrap.offsetWidth +'px';// ......}
对有序集合进行遍历时,缓存 length
// 正序遍历for(let i =0, len = elements.length; i < len; i++){const element = elements[i];// ......}// 逆序遍历let len = elements.length;while(len--){const element = elements[len];// ......}
const str ='我是一个字符串';const html ='<div class="cls">拼接HTML可以省去双引号转义</div>';
使用字符串拼接的方式生成 HTML,需要根据语境进行合理的转义
// HTML 转义const str ='<p>'+htmlEncode(content)+'</p>';// HTML 转义const str ='<input type="text" value="'+htmlEncode(value)+'">';// URL 转义const str ='<a href="/?key='+htmlEncode(urlEncode(value))+'">link</a>';// JavaScript字符串 转义 + HTML 转义const str ='<button οnclick="check(\''+htmlEncode(strLiteral(name))+'\')">提交</button>';
单行字符串的拼接或者字符串本身包含单引号建议使用字符串模板
const str =`'name': ${name}`;
不要使用 \ 进行多行接续
// goodconst longString ='This is a very long string that far exceeds the 80 '+'column limit. It does not contain long stretches of spaces since '+'the concatenated strings are cleaner.';// badconst longString ='This is a very long string that far exceeds the 80 \
column limit. It unfortunately contains long stretches of spaces due \
to how the continued lines are indented.';
字符串内变量替换时,不要使用 2 层及以上的函数调用
// goodconst fullName =getFullName(getFirstName(),getLastName());const s =`Hello ${fullName}`;// badconst s =`Hello ${getFullName(getFirstName(),getLastName())}`;
// good
console.log(Object.prototype.hasOwnProperty.call(object, key));const has =Object.prototype.hasOwnProperty;
console.log(has.call(object, key));// bad
console.log(object.hasOwnProperty(key));
// good
foo =[...foo, newValue];
bar =[...bar,...newValues];// bad
foo = foo.concat(newValue);
bar = bar.concat(newValues);
多行数组最后一个元素后面加逗号
// goodconst foo =['first value','second value',];const bar =['first value','second value'];// badconst foo =['first value','second value'];const bar =['first value','second value',];
数组遍历时,使用数组的原生方法以替代 for in 、 for of 用法
const numbers =[1,2,3,4,5];// 数组求和// badlet sum =0;for(let num of numbers){
sum += num;}
sum ===15;// goodlet sum =0;
numbers.forEach(num=>{
sum += num;});
sum ===15;// best 使用最恰当的方法const sum = numbers.reduce((total, num)=> total + num,0);
sum ===15;// 数组所有元素 +1// badconst increasedByOne =[];for(let i =0; i < numbers.length; i++){
increasedByOne.push(numbers[i]+1);}// goodconst increasedByOne =[];
numbers.forEach((num)=>{
increasedByOne.push(num +1);});// best 使用最恰当的方法const increasedByOne = numbers.map(num=> num +1);
// good functioninfo(person){const thisInfo ={...person.info};
thisInfo.xx ='info';return thisInfo;}// bad functioninfo(person){const thisInfo = person.info;
thisInfo.xx ='info';return thisInfo;}
使用变量默认语法代替基于条件判断的默认值声明
// goodfunctionfoo(text ='hello'){}// badfunctionfoo(text){
text =(typeof text !=='undefined')? text :'hello';}functionfoo(text){
text = text ||'hello';}
// goodimport{ bar }from'./bar';functionfoo(){import('./foo').then(foo=> console.log(foo));
bar.work();}// badfunctionfoo(){
bar.work();}import{ bar }from'./bar';