类型
基本类型
- string - number - boolean - null - undefined - symbol(表示独一无二的值,使用时需要注意浏览器是否支持) //example const symbol1 = Symbol(); const symbol2 = Symbol(42); const symbol3 = Symbol('foo'); console.log(typeof symbol1); // expected output: "symbol" console.log(symbol3.toString()); // expected output: "Symbol(foo)" console.log(Symbol('foo') === Symbol('foo')); // expected output: false
复杂类型
- array- object- function
声明变量
//块级作用域内有效- let//块级作用域内有效 不可重复赋值- const
对象
直接声明
//badlet obj = new Object();//goodlet obj = {};
动态属性名
//badfunction getKey(key){ return `${key}`}let obj = { id:1 name:"jack"} obj[getKey("age")] = 18;console.log(obj.age) //18//goodlet obj = { name:"jack", age:18, [getKey("age")]:18}
对象方法简写
//badlet obj = { name:"jack", age:18, show:function(arg){ console.log(arg) }} //goodlet obj = { name:"jack", age:18, show(arg){ console.log(arg) }}
属性值简写
//badlet age = 18;let obj = { name:"jack", age:age}//goodlet obj = { age,//简写最好放前面 name:"jack", "data-id":5//键名尽量不加引号,除非没有引号不合法}
不要直接使用Object.prototype的方法
//不要直接使用Object.prototype的方法,如hasOwnProperty, propertyIsEnumerable和isPrototypeOf//badlet obj = { id:1, name:"jack"}obj.hasOwnProperty("name");//goodObject.prototype.hasOwnProperty.call(obj,"name");//bestvar has = Object.prototype.hasOwnProperty;has.call(obj,"name")
用变量的解构赋值代替Object.assign()做浅拷贝
//用变量的解构赋值代替Object.assign()做浅拷贝//badlet ori = {a:1,b:2};let copy = Object.assign({},ori,{c:3});//goodlet ori = {a:1,b:2};let copy = {...ori,c:3};//{a:1,b:2,c:3}let {a,...notA} = copy; // notA={b:2,c:3}
数组
简洁声明
//badlet arr = new Array();//goodlet arr = [];
使用push代替直接分配元素给数组
//badlet arr = [];arr[arr.length] = "abc";//goodarr.push("abc");
扩展运算符...代替数组拷贝
//badlet arr = [1,2,3];let copy = [];for(let i=0;i
转换类数组的对象为数组
let div = document.querySelectAll("div");//goodlet arr = Array.from(div);//bestlet arr = [...div]
数组方法中的return
//当function大括号只有一个表达式时,{}和rerun都可以省//bad[1,2,3].map(x=>{ let y = x+1; return x*y}) //good[1,2,3].map(x=>x+1)
解构赋值
//object//goodfunction getFullName(user){ let {firstName,lastName} = user; return `${firstName}${lastName}`}//bestfunction getFullName({firstName,lastName}){ return `${firstName}${lastName}`}//arraylet arr = [1,2,3,4];//badlet first = arr[0];let sec = arr[1];//good[first,sec] = arr
函数的多个返回值用对象解构赋值
//badfunction processInput(input){ return [let,top,right,bottom]}//goodfunction processInput(input){ return {let,top,right,bottom}}//uselet {left,bottom} = processInput(input);
字符串
使用单引号
//badlet str = "hello world";//goodlet str = 'hello world'
尽量别转行
//有转行时,当然字符数不超过100的情况尽量别转行//badlet str = 'hello world,'+ 'balabalabala';//good
let str = 'hello world,balabalabala'
字符串变量拼接
//badlet str = 'hello '+name+' !';//goodlet str =`hello ${name} !`;
函数
复杂名称的函数赋值给一个简洁变量名
//bad let foo= function(){} function foo(){} //good let foo = function getPageFooComponent(){} //use foo();
别在if while等语句中声明函数
//badif(){ function test(){}}//goodlet test;if(){ test = ()=>{console.log("hello")}}
别用arguments作为参数名
//badfunction foo(name,arguments){}//goodfunction foo(name,arg){}
扩展运算符...代替arguments
//badfunction test(){ let args = Array.portotype.slice.call(arguments); return args.join('');}//goodfunction test(...args){ return args.join('');}
默认参数
//badfuntion test(opt){ let opt = opt || {}}//goodfunction test(opt={}){}
别在参数体里面计算
//badlet a=1;function test(b = a++){ }
将赋值的参数放在最后
//badfunction test(opt = {},name){}//goodfunction test(name,opt = {}){}
别对参数重新赋值
//badfunction test(a){ let a=1;}function test(a){ if(!a){ let a=1; }}//goodfunction test(a){ let b = a || 1;}function test(a = 1){ }
类&构造方法
用class代替传统的prototype手动方法
//badfunction Queue(contents = []){ this.queue = [contents];}Queue.prototype.pop = function(){ let value = this.queue[0]; this.queue.spice(0,1); return value;}//goodclass Queue { constructor(contents = []){ this.queue = [contents] } pop(){ let value = this.queue[0]; this.queue.spice(0,1); return value; }}
用extend做继承
//goodclass Dog extends Animal{ yell(){ return 'wangwang' }}
this的指向
//bad Jedi.prototype.jump = function(){ this.jumping = true; return true; } Jedi.prototype.setHeight= function(height){ this.height = height; } let luck = new Jedi(); luck.jump(); luck.setHeight(20);//goodclass Jedi{ jump(){ this.jumping = true; return true; } setHeight(height){ this.height = height; }}let luck = new Jedi();luck.jump();luck.setHeight(20);
子类的构造函数必须执行一次super函数
//badclass test { constructor() {}//空constructor不需要 getName() { return this.name; }}//badclass test { constructor(...args) { super(...args)//只是为了继承constructor不需要 }}//goodclass test { constructor(...args) { super(...args) this.name = 'key' }}
模块
import/export
//badlet AirbnbJavascriptGuide = require('./AirbnbJavascriptGuide ');module.exports = AirbnbJavascriptGuide.es6;//okimport AirbnbJavascriptGuide from './AirbnbJavascriptGuide ';export default AirbnbJavascriptGuide.es6;//bestimport {es6} from './AirbnbJavascriptGuide ';export default es6;
忌用通配符import
//badimport * as AirbnbJavascriptGuide from './AirbnbJavascriptGuide ';//goodimport AirbnbJavascriptGuide from './AirbnbJavascriptGuide ';
别在import时同时export
//badexport { es6 as default } from './AirbnbJavascriptGuide ';//goodimport { es6 } from './AirbnbJavascriptGuide ';export default es6;
同一个地址放在一个import
//bad import foo form 'foo';...import { name,age } from 'foo';//goodimport foo,{ name,age } form 'foo';//bestimport foo,{ name, age } form 'foo';
只有一个export时 用export default
//badexport function foo() {}//goodexport default foo() {}
不要在import时用Webpack loader
//badimport foo from 'css!sass!foo.scss';//goodimport foo from 'foo.css';
迭代遍历
用map、every、filter,find,findIndex,some,reduce等代替for-in,for-of
let numbers = [1,2,3,4]//badlet sum = 0;for(let num of numbers){ sum += num;} //goodlet sum = 0;numbers.forEach(num => sum += num);//badlet increaseByOne = [];for(let i = 0;i< numbers.length;i++){ increaseByOne .push(numbers[i]+1);}//goodlet increaseByOne = numbers.map(num => num + 1);
正确的constructor的书写
//goodlet test = function* (){ //...}
属性
通过.访问属性
let luke = { jedi:true, age:28}//badlet isJedi = luke['jedi'];//goodlet isJedi = luke.jedi;
通过变量访问属性时使用中括号 []
let luke = { jedi:true, age:28}function getProp(prop) { return luke[prop];}let isJedi = getProp('jedi')
##变量##
用let和const声明变量
//goodlet superPower = new SuperPower();
提升
var 声明会被提升至该作用域的顶部,但它们赋值不会提升
//bad// 由于变量提升的原因,// 在引用变量后再声明变量是可以运行的。// 注:变量的赋值 `true` 不会被提升。function example() { console.log(declaredButNotAssigned); // => undefined var declaredButNotAssigned = true;}
匿名函数表达式的变量名会被提升,但函数内容并不会
function example() { console.log(anonymous); // => undefined anonymous(); // => TypeError anonymous is not a function var anonymous = function() { console.log('anonymous function expression'); };}
函数声明的名称和函数体都会被提升
function example() { superPower(); // => Flying function superPower() { console.log('Flying'); }}
比较和等号
优先使用 === 和 !== 而不是 == 和 !=
//goodif(a===1){}
使用简写
// badif (name !== '') { // ...stuff...}// goodif (name) { // ...stuff...}// badif (collection.length > 0) { // ...stuff...}// goodif (collection.length) { // ...stuff...}
三元运算符通写在一行
// bad
const foo = maybe1 > maybe2 ? "bar" : value1 > value2 ? "baz" : null;// split into 2 separated ternary expressionsconst maybeNull = value1 > value2 ? 'baz' : null;// betterconst foo = maybe1 > maybe2 ? 'bar' : maybeNull;// bestconst foo = maybe1 > maybe2 ? 'bar' : maybeNull;
避免不必要的三元运算符
// badconst foo = a ? a : b;const bar = c ? true : false;const baz = c ? false : true;// goodconst foo = a || b;const bar = !!c;const baz = !c;
混合运算时,尽量用括号,易懂
//badif(a || b && c){ //...}//goodif(a || (b && c)){ //...}
代码块
用大括号包裹所有的多行代码块
// badif (test) return false;// goodif (test){ return false; }
条件语句
条件语句,换行将运算符放在最前面
// bad
if ((foo === 123 || bar === 'abc') && doesItLookGoodWhenItBecomesThatLong() && isThisReallyHappening()) { thing1();}//goodif ( (foo === 123 || bar === 'abc') && doesItLookGoodWhenItBecomesThatLong() && isThisReallyHappening() ) { thing1();}
注释
- 使用 /** ... */ 作为多行注释- 使用 // 作为单行注释 ,上方空一行- 使用 // FIXME: 标注问题- 使用 // TODO: 标注问题的解决方式
逗号
- 行首逗号:不需要- 结尾的逗号: 需要
分号
- 别省略分号
类型转换
字符串
// badconst totalScore = new String(this.reviewScore); // typeof totalScore is "object" not "string"// badconst totalScore = this.reviewScore + ''; // invokes this.reviewScore.valueOf()// badconst totalScore = this.reviewScore.toString(); // isn’t guaranteed to return a string// goodconst totalScore = String(this.reviewScore);
数字
let inputValue= 4;// badconst val = new Number(inputValue);// badconst val = +inputValue;// badconst val = inputValue >> 0;// badconst val = parseInt(inputValue);// goodconst val = Number(inputValue);// goodconst val = parseInt(inputValue, 10);
布尔
const age = 0;// badconst hasAge = new Boolean(age);// goodconst hasAge = Boolean(age);// goodconst hasAge = !!age;
命名规则
- 避免单字母命名。命名应具备描述性- 使用驼峰式命名对象、函数和实例- 使用ES6命名构造函数或类class User { constructor(options) { this.name = options.name; }}let good = new User({ name:"yup"});- 使用下划线 _ 开头命名私有属性- 使用箭头函数避免this引用错误//bad function test(){ let self = this; return function(){ console.log(self); }}//goodfunction test(){ return ()=>{ console.log(this); }}- 文件只输出一个类,文件名必须和类名完全保持一致// file contentsclass CheckBox { // ...}export default CheckBox;// in some other file// badimport CheckBox from './checkBox';// badimport CheckBox from './check_box';// goodimport CheckBox from './CheckBox';
存取器
- 使用好get、set- is、has- 保持一致// baddragon.age();// gooddragon.getAge();// badif (!dragon.age()) { return false;}// goodif (!dragon.hasAge()) { return false;}
事件
// bad$(this).trigger('listingUpdated', listing.id);...$(this).on('listingUpdated', function(e, listingId) { // do something with listingId}); // good$(this).trigger('listingUpdated', { listingId : listing.id });...$(this).on('listingUpdated', function(e, data) { // do something with data.listingId});
jQuery
使用 $ 作为存储 jQuery 对象的变量名前缀
// badconst sidebar = $('.sidebar');// goodconst $sidebar = $('.sidebar');
缓存 jQuery 查询
const $sidebar = $('.sidebar');
对 DOM 查询使用层叠
$('.sidebar ul')$('.sidebar > ul')
对有作用域的 jQuery 对象查询使用 find
// bad$('ul', '.sidebar').hide();// good$sidebar.find('ul').hide();参考:https://github.com/airbnb/javascript