基于Airbnb JavaScript Style Guide的javascript代码规范
本文是完整代码规范建议的子集,提及内容为eslint可检查部分。
补充规范:
IDE/构建工具/格式化工具配置请看配置文档
本文规则分为三类:
- 强制: 不符合规范 =>
eslint error - 建议 / warn: 不符合规范 =>
eslint warn警告提示 - 建议 / off: 建议你以这样的方式进行 =>
eslint off不进行检查
建议通读完整规范,获得更好的代码书写指导建议。
修改的部分会以[modified]标注,无此说明的即与原文规约相同。
- 对象
- 数组
- 解构
- 字符串
- 函数
- 箭头函数
- 构造函数
- 模块
- Iterators & Generators
- 属性
- 变量
- 提升
- 比较运算符 & 等号
- 代码块
- 注释
- 空白
- 逗号
- 分号
- 类型转换
- 命名规则
- 存取器
- 事件
- jQuery
- ECMAScript 5 兼容性
- ECMAScript 6 编码规范
2.1[强制] 对所有的引用使用
const;不要使用var。 eslint:prefer-const,no-const-assign为什么?这能确保你无法对引用重新赋值,也不会导致出现 bug 或难以理解。
// badvara=1;varb=2;// goodconsta=1;constb=2;
2.2[强制] 如果你一定需要可变动的引用,使用
let代替var。 eslint:no-varjscs:disallowVar为什么?因为
let是块级作用域,而var是函数作用域。// badvarcount=1;if(true){count+=1;}// good, use the let.letcount=1;if(true){count+=1;}
3.1[强制] 使用字面值创建对象。 eslint:
no-new-object// badconstitem=newObject();// goodconstitem={};
3.4[强制] 使用对象属性值的简写。 eslint:
object-shorthandjscs:requireEnhancedObjectLiterals为什么?因为这样更短更有描述性。
constlukeSkywalker='Luke Skywalker';// badconstobj={lukeSkywalker: lukeSkywalker,};// goodconstobj={ lukeSkywalker,};
3.6[强制] 仅在对象属性有特殊符号时使用引号包裹。 eslint:
quote-propsjscs:disallowQuotedKeysInObjects为什么? 这样看上去更加易读,另外还能有相关的代码高亮,也容易被许多JS引擎优化。
// badconstbad={'foo': 3,'bar': 4,'data-blah': 5,};// goodconstgood={foo: 3,bar: 4,'data-blah': 5,};
4.1[强制] 使用字面值创建数组。 eslint:
no-array-constructor// badconstitems=newArray();// goodconstitems=[];
4.5[强制] 数组的相关方法使用return语句。如果函数体仅由一个带表达式且无副作用的语句组成,可以忽略return。 参考8.2. eslint:
array-callback-return// good[1,2,3].map((x)=>{consty=x+1;returnx*y;});// good[1,2,3].map(x=>x+1);// badconstflat={};[[0,1],[2,3],[4,5]].reduce((memo,item,index)=>{constflatten=memo.concat(item);flat[index]=flatten;});// goodconstflat={};[[0,1],[2,3],[4,5]].reduce((memo,item,index)=>{constflatten=memo.concat(item);flat[index]=flatten;returnflatten;});// badinbox.filter((msg)=>{const{ subject, author }=msg;if(subject==='Mockingbird'){returnauthor==='Harper Lee';}else{returnfalse;}});// goodinbox.filter((msg)=>{const{ subject, author }=msg;if(subject==='Mockingbird'){returnauthor==='Harper Lee';}returnfalse;});
6.1[强制] 字符串使用单引号
''。 eslint:quotesjscs:validateQuoteMarks// badconstname="Capt. Janeway";// goodconstname='Capt. Janeway';
6.4
[modified][建议 / warn]程序化生成字符串时,使用模板字符串代替字符串连接。 eslint:prefer-templatetemplate-curly-spacingjscs:requireTemplateStrings为什么?模板字符串更为简洁,更具可读性。
// badfunctionsayHi(name){return'How are you, '+name+'?';}// badfunctionsayHi(name){return['How are you, ',name,'?'].join();}// goodfunctionsayHi(name){return`How are you, ${name}?`;}
6.5
[modified][建议 / off] 不要对字符串使用不必要的escape操作。 eslint:no-useless-escape为什么? 反斜杠会影响可读性,仅在必须的时候使用它。
// badconstfoo='\'this\' \i\s \"quoted\"';// goodconstfoo='\'this\' is "quoted"';constfoo=`my name is '${name}'`;
7.1
[modified][建议 / off] 使用具名函数代替函数声明。 eslint:func-stylejscs:disallowFunctionDeclarations为什么?因为函数声明会把函数提升(hoisted), 这样易使函数在定义前被引用。这会影响可读性和可维护性。如果一个函数的定义很长或很复杂,会干扰对文件剩余部分的理解,更好的方式是将它抽象在它自己的模块中。别忘了给函数表达式命名 - 匿名函数会使得在错误调用栈中定位问题变得困难。(讨论)
// badfunctionfoo(){// ...}// badconstfoo=function(){// ...};// goodconstfoo=functionbar(){// ...};
7.2[强制] 对于立即调用(IIFE)的函数表达式,用括号包裹函数体。 eslint:
wrap-iifejscs:requireParenthesesAroundIIFE为什么?立即调用函数是一个独立单元 - 用括号包裹函数体可以清晰地表达这一点。需要注意的是,在一个到处都是「模块」的世界,几乎从不需要IIFE。
// 立即调用的函数 (IIFE)(function(){console.log('Welcome to the Internet. Please follow me.');}());
7.3[强制] 永远不要在一个非函数代码块(
if、while等)中声明一个函数,把那个函数赋给一个变量。浏览器允许你这么做,但它们的解析表现不一致。 eslint:no-loop-func
7.6
[modified][建议 / off] 不要使用arguments。可以选择 rest 语法...替代。 eslint:prefer-rest-params为什么?使用
...能明确你要传入的参数。另外 rest 参数是一个真正的数组,而arguments是一个类数组。// badfunctionconcatenateAll(){constargs=Array.prototype.slice.call(arguments);returnargs.join('');}// goodfunctionconcatenateAll(...args){returnargs.join('');}
7.10[强制] 永远不要使用Function构造函数来创建一个新函数。 eslint:
no-new-func为什么?这种方式在分析字符串时与eval()类似,会带来各种问题。
// badvaradd=newFunction('a','b','return a + b');// still badvarsubtract=Function('a','b','return a - b');
7.11[强制] [强制] 在函数签名中使用空格。 eslint:
space-before-function-parenspace-before-blocks为什么?保持一致性是最佳实践, 另外如果在添加或删除名称时也不应增加/删除空格。
// badconstf=function(){};constg=function(){};consth=function(){};// goodconstx=function(){};consty=functiona(){};
7.12[强制] 永远不要改变(mutate)参数。 eslint:
no-param-reassign为什么?对传入的参数进行操作会在原始调用带来不想要的变量副作用。
// badfunctionf1(obj){obj.key=1;}// goodfunctionf2(obj){constkey=Object.prototype.hasOwnProperty.call(obj,'key') ? obj.key : 1;}
7.13[强制] 永远不要对参数重新赋值(reassign)。 eslint:
no-param-reassign为什么?对参数重新赋值会引起意料之外的行为,特别是对于
arguments的访问。同时它会引起优化问题,特别在V8引擎中。// badfunctionf1(a){a=1;// ...}functionf2(a){if(!a){a=1;}// ...}// goodfunctionf3(a){constb=a||1;// ...}functionf4(a=1){// ...}
7.14
[modified][建议 / warn] 推荐使用展开运算符...来调用可变参数的函数。 eslint:prefer-spread为什么?这样更加清晰,也不用提供上下文,而且把
new和apply组合的方式也比较蛋疼。// badconstx=[1,2,3,4,5];console.log.apply(console,x);// goodconstx=[1,2,3,4,5];console.log(...x);// badnew(Function.prototype.bind.apply(Date,[null,2016,8,5]));// goodnewDate(...[2016,8,5]);
8.1[强制] 当你必须使用函数表达式(或传递一个匿名函数)时,使用箭头函数符号。 eslint:
prefer-arrow-callback,arrow-spacingjscs:requireArrowFunctions为什么?因为箭头函数创造了新的一个
this执行环境(译注:参考 Arrow functions - JavaScript | MDN 和 ES6 arrow functions, syntax and lexical scoping),通常情况下都能满足你的需求,而且这样的写法更为简洁。为什么不?如果你有一个相当复杂的函数,你或许可以把逻辑部分转移到一个函数声明上。
// bad[1,2,3].map(function(x){consty=x+1;returnx*y;});// good[1,2,3].map((x)=>{consty=x+1;returnx*y;});
8.2[强制] 如果一个函数适合用一行写出并且只有一个参数,那就把花括号、圆括号和
return都省略掉。如果不是,那就不要省略。 eslint:arrow-parens,arrow-body-stylejscs:disallowParenthesesAroundArrowParam,requireShorthandArrowFunctions为什么?语法糖。在链式调用中可读性很高。
// bad[1,2,3].map(number=>{constnextNumber=number+1;`A string containing the ${nextNumber}.`;});// good[1,2,3].map(number=>`A string containing the ${number}.`);// good[1,2,3].map((number)=>{constnextNumber=number+1;return`A string containing the ${nextNumber}.`;});// good[1,2,3].map((number,index)=>({[index]: number,}));// 当有副作用时,不要隐式returnfunctionfoo(callback){constval=callback();if(val===true){// Do something if callback returns true}}letbool=false;// badfoo(()=>bool=true);// goodfoo(()=>{bool=true;});
8.4[强制] 如果函数是单参数且不需要花括号
{},则要省略掉括号。否则,始终用括号包裹参数,这样更加清晰,可读性也更好。 注:始终使用括号包裹参数也可以。 在eslint中使用 “always” option 或在jscs中不引入disallowParenthesesAroundArrowParam。 eslint:arrow-parensjscs:disallowParenthesesAroundArrowParam为什么? 可以避免视觉上的混乱。
// bad[1,2,3].map((x)=>x*x);// good[1,2,3].map(x=>x*x);// good[1,2,3].map(number=>(`A long string with the ${number}. It’s so long that we don’t want it to take up space on the .map line!`));// bad[1,2,3].map(x=>{consty=x+1;returnx*y;});// good[1,2,3].map((x)=>{consty=x+1;returnx*y;});
8.5
[modified][建议 / off] 在箭头函数后避免使用 (<=,>=)这样的比较操作符。 eslint:no-confusing-arrow// badconstitemHeight=item=>item.height>256 ? item.largeSize : item.smallSize;// badconstitemHeight=(item)=>item.height>256 ? item.largeSize : item.smallSize;// goodconstitemHeight=item=>(item.height>256 ? item.largeSize : item.smallSize);// goodconstitemHeight=(item)=>{const{ height, largeSize, smallSize }=item;returnheight>256 ? largeSize : smallSize;};
9.1[强制] 总是使用
class。避免直接操作prototype。为什么? 因为
class语法更为简洁易读。// badfunctionQueue(contents=[]){this._queue=[...contents];}Queue.prototype.pop=function(){constvalue=this._queue[0];this._queue.splice(0,1);returnvalue;}// goodclassQueue{constructor(contents=[]){this._queue=[...contents];}pop(){constvalue=this._queue[0];this._queue.splice(0,1);returnvalue;}}
9.5[强制]如果没有显式声明,类都有个默认的构造器(constructor)。一个空或者仅代理了父类的构造函数是不必要的。 eslint:
no-useless-constructor// badclassJedi{constructor(){}getName(){returnthis.name;}}// badclassReyextendsJedi{constructor(...args){super(...args);}}// goodclassReyextendsJedi{constructor(...args){super(...args);this.name='Rey';}}
9.6[强制] 避免重复类成员。 eslint:
no-dupe-class-members为什么? 重复声明类成员,默认最后一个优先级最高 - 几乎肯定是个bug。
// badclassFoo{bar(){return1;}bar(){return2;}}// goodclassFoo{bar(){return1;}}// goodclassFoo{bar(){return2;}}
10.4[强制] 避免从同一个位置重复import. eslint:
no-duplicate-imports为什么? 这样会降低可维护性。
// badimportfoofrom'foo';// … some other imports … //import{named1,named2}from'foo';// goodimportfoo,{named1,named2}from'foo';// goodimportfoo,{named1,named2,}from'foo';
10.5[强制] 不要将可变量export。 eslint:
import/no-mutable-exports为什么? 一般来说需要避免可变,特别是在export可变量时。虽然在某些特殊情况下需要这么做,但是一般来说只对常量的引用作export。
// badletfoo=3;export{foo};// goodconstfoo=3;export{foo};
10.6[强制] 只有单个export的模块,推荐使用default export而不是具名export。 eslint:
import/prefer-default-export// badexportfunctionfoo(){}// goodexportdefaultfunctionfoo(){}
10.7[强制] 把所有的
import放在非import句式前。 eslint:import/first为什么?
import存在提升(hoisted),把它们都置于文件顶部可以避免一些奇怪的行为。// badimportfoofrom'foo';foo.init();importbarfrom'bar';// goodimportfoofrom'foo';importbarfrom'bar';foo.init();
10.9[强制] 在import语句中不允许使用webpack loader语法。 eslint:
import/no-webpack-loader-syntax为什么? 使用这种语法的代码对打包工具有强依赖。推荐在
webpack.config.js中使用这类语法。// badimportfooSassfrom'css!sass!foo.scss';importbarCssfrom'style!css!bar.css';// goodimportfooSassfrom'foo.scss';importbarCssfrom'bar.css';
11.3[强制] 如果必须要使用generator, 那么要确保函数签名中使用正确的空格格式。 eslint:
generator-star-spacing为什么?
function和*都是概念上的关键字 -*不是function的修饰符,function*是一个统一结构体, 与function不同。// badfunction*foo(){// ...}// badconstbar=function*(){// ...};// badconstbaz=function*(){// ...};// badconstquux=function*(){// ...};// badfunction*foo(){// ...}// badfunction*foo(){// ...}// very badfunction*foo(){// ...}// very badconstwat=function*(){// ...};// goodfunction*foo(){// ...}// goodconstfoo=function*(){// ...};
12.1[建议 / warn] 使用
.来访问对象的属性。 eslint:dot-notationjscs:requireDotNotationconstluke={jedi: true,age: 28,};// badconstisJedi=luke['jedi'];// goodconstisJedi=luke.jedi;
13.1[强制] 一直使用
const或let来声明变量,如果不这样做就会产生全局变量。 我们需要避免全局命名空间的污染。地球队长已经警告过我们了。(译注:全局,global 亦有全球的意思。地球队长的责任是保卫地球环境,所以他警告我们不要造成「全球」污染。)eslint:no-undefprefer-const// badsuperPower=newSuperPower();// goodconstsuperPower=newSuperPower();
13.2[强制] 使用
const或let声明每一个变量。 eslint:one-varjscs:disallowMultipleVarDecl为什么?增加新变量将变的更加容易,而且你永远不用再担心调换错
;跟,。// badconstitems=getItems(),goSportsTeam=true,dragonball='z';// bad// (compare to above, and try to spot the mistake)constitems=getItems(),goSportsTeam=true;dragonball='z';// goodconstitems=getItems();constgoSportsTeam=true;constdragonball='z';
13.5[强制] 不要使用链式变量赋值.
为什么?链式变量赋值会创建隐式全局变量。
// bad(functionexample(){// JavaScript 解释器将这个语句解释为// let a = ( b = ( c = 1 ) );// let关键字仅对a生效,b和c变成了全局变量。leta=b=c=1;}());console.log(a);// throws ReferenceErrorconsole.log(b);// 1console.log(c);// 1// good(functionexample(){leta=1;letb=a;letc=a;}());console.log(a);// throws ReferenceErrorconsole.log(b);// throws ReferenceErrorconsole.log(c);// throws ReferenceError// 对于 `const`也是一样的。
13.6
[modified][建议 / off] 避免使用一元增减运算符(++, --)。 eslintno-plusplus为什么? 根据eslint文档, 一元增减运算符会自动加入分号,在应用中会引起静默错误。使用
num += 1代替num++或num ++来变更值会显得更加易读。 不使用一元增减运算符也可以避免在不注意的情况下值做了预增减(pre-incrementing/pre-decrementing),也会导致预期外的错误。// badconstarray=[1,2,3];letnum=1;num++;--num;letsum=0;lettruthyCount=0;for(leti=0;i<array.length;i++){letvalue=array[i];sum+=value;if(value){truthyCount++;}}// goodconstarray=[1,2,3];letnum=1;num+=1;num-=1;constsum=array.reduce((a,b)=>a+b,0);consttruthyCount=array.filter(Boolean).length;
- 想了解更多信息,参考 Ben Cherry 的 JavaScript Scoping & Hoisting。
16.2[强制] 如果通过
if和else使用多行代码块,把else另起一行。把eslint:else放在if代码块关闭括号的同一行。brace-stylejscs:disallowNewlineBeforeBlockStatements// badif(test){thing1();thing2();}else{thing3();}// goodif(test){thing1();thing2();}else{thing3();}
18.3[强制] 所有注释开头加一个空格,增加可读性。 eslint:
spaced-comment// bad//is current tabconstactive=true;// good// is current tabconstactive=true;// bad/** *make() returns a new element *based on the passed-in tag name */functionmake(tag){// ...returnelement;}// good/** * make() returns a new element * based on the passed-in tag name */functionmake(tag){// ...returnelement;}
19.1[强制] 使用 2 个空格作为缩进。 eslint:
indentjscs:validateIndentation// badfunction(){∙∙∙∙constname;}// badfunction(){∙constname;}// goodfunction(){∙∙constname;}
19.2[强制] 在花括号前放一个空格。 eslint:
space-before-blocksjscs:requireSpaceBeforeBlockStatements// badfunctiontest(){console.log('test');}// goodfunctiontest(){console.log('test');}// baddog.set('attr',{age: '1 year',breed: 'Bernese Mountain Dog',});// gooddog.set('attr',{age: '1 year',breed: 'Bernese Mountain Dog',});
19.3[强制] 在控制语句(
if、while等)的小括号前放一个空格。在函数调用及声明中,不在函数的参数列表前加空格。 eslint:keyword-spacingjscs:requireSpaceAfterKeywords// badif(isJedi){fight();}// goodif(isJedi){fight();}// badfunctionfight(){console.log('Swooosh!');}// goodfunctionfight(){console.log('Swooosh!');}
19.4[强制] 使用空格把运算符隔开。 eslint:
space-infix-opsjscs:requireSpaceBeforeBinaryOperators,requireSpaceAfterBinaryOperators// badconstx=y+5;// goodconstx=y+5;
19.5[强制] 在文件末尾插入一个空行。 eslint:
eol-last// bad(function(global){// ...stuff...})(this);
// bad(function(global){// ...stuff...})(this);↵↵
// good(function(global){// ...stuff...})(this);↵
19.6[强制] 在使用长方法链时进行缩进。使用前面的点
.强调这是方法调用而不是新语句。 eslint:newline-per-chained-callno-whitespace-before-property译注:当链式超过4个之后使用换行。
// bad$('#items').find('.selected').highlight().end().find('.open').updateCount();// bad$('#items').find('.selected').highlight().end().find('.open').updateCount();// good$('#items').find('.selected').highlight().end().find('.open').updateCount();// badconstleds=stage.selectAll('.led').data(data).enter().append('svg:svg').class('led',true).attr('width',(radius+margin)*2).append('svg:g').attr('transform','translate('+(radius+margin)+','+(radius+margin)+')').call(tron.led);// goodconstleds=stage.selectAll('.led').data(data).enter().append('svg:svg').classed('led',true).attr('width',(radius+margin)*2).append('svg:g').attr('transform','translate('+(radius+margin)+','+(radius+margin)+')').call(tron.led);
19.8[强制]不要用代码块起始/结束位置加入空行。 eslint:
padded-blocksjscs:disallowPaddingNewlinesInBlocks// badfunctionbar(){console.log(foo);}// also badif(baz){console.log(qux);}else{console.log(foo);}// goodfunctionbar(){console.log(foo);}// goodif(baz){console.log(qux);}else{console.log(foo);}
19.9[强制] 不要在括号前后加入空格。 eslint:
space-in-parensjscs:disallowSpacesInsideParentheses// badfunctionbar(foo){returnfoo;}// goodfunctionbar(foo){returnfoo;}// badif(foo){console.log(foo);}// goodif(foo){console.log(foo);}
19.10[强制] 不要在数组起始和尾部加入空格。 eslint:
array-bracket-spacingjscs:disallowSpacesInsideArrayBrackets// badconstfoo=[1,2,3];console.log(foo[0]);// goodconstfoo=[1,2,3];console.log(foo[0]);
19.11[强制] 在花括号首尾加入空格。 eslint:
object-curly-spacingjscs:requireSpacesInsideObjectBrackets// badconstfoo={clark: 'kent'};// goodconstfoo={clark: 'kent'};
19.12[强制] 避免一行超过100个字符。 备注:每个如上above的长字符串 可以不遵循这条规则。 eslint:
max-lenjscs:maximumLineLength为什么?这样做可以增加可读性和可维护性。
// badconstfoo=jsonData&&jsonData.foo&&jsonData.foo.bar&&jsonData.foo.bar.baz&&jsonData.foo.bar.baz.quux&&jsonData.foo.bar.baz.quux.xyzzy;// bad$.ajax({method: 'POST',url: 'https://airbnb.com/',data: {name: 'John'}}).done(()=>console.log('Congratulations!')).fail(()=>console.log('You have failed this city.'));// goodconstfoo=jsonData&&jsonData.foo&&jsonData.foo.bar&&jsonData.foo.bar.baz&&jsonData.foo.bar.baz.quux&&jsonData.foo.bar.baz.quux.xyzzy;// good$.ajax({method: 'POST',url: 'https://airbnb.com/',data: {name: 'John'},}).done(()=>console.log('Congratulations!')).fail(()=>console.log('You have failed this city.'));
20.1[强制] 行首逗号:不需要。 eslint:
comma-stylejscs:requireCommaBeforeLineBreak// badconststory=[once,upon,aTime];// goodconststory=[once,upon,aTime,];// badconsthero={firstName: 'Ada',lastName: 'Lovelace',birthYear: 1815,superPower: 'computers'};// goodconsthero={firstName: 'Ada',lastName: 'Lovelace',birthYear: 1815,superPower: 'computers',};
20.2[强制] 增加结尾的逗号: 需要。 eslint:
comma-danglejscs:requireTrailingComma为什么? 这会让 git diffs 更干净。另外,像 babel 这样的转译器会移除结尾多余的逗号,也就是说你不必担心老旧浏览器的尾逗号问题。
// bad - git diff without trailing commaconsthero={firstName: 'Florence',-lastName: 'Nightingale'+lastName: 'Nightingale',+inventorOf: ['coxcomb graph','modern nursing']}// good - git diff with trailing commaconsthero={firstName: 'Florence',lastName: 'Nightingale',+inventorOf: ['coxcomb chart','modern nursing'],}// badconsthero={firstName: 'Dana',lastName: 'Scully'};constheroes=['Batman','Superman'];// goodconsthero={firstName: 'Dana',lastName: 'Scully',};constheroes=['Batman','Superman',];
21.1[强制]在语句末使用分号 eslint:
semijscs:requireSemicolons// bad(function(){constname='Skywalker'returnname})()// good(()=>{constname='Skywalker';returnname;})();// good (防止函数在两个 IIFE 合并时被当成一个参数);(()=>{constname='Skywalker';returnname;})();
22.3[强制] 对数字使用
parseInt转换,并带上类型转换的基数。 eslint:radixconstinputValue='4';// badconstval=newNumber(inputValue);// badconstval=+inputValue;// badconstval=inputValue>>0;// badconstval=parseInt(inputValue);// goodconstval=Number(inputValue);// goodconstval=parseInt(inputValue,10);
23.1
[modified][建议 / off]避免单字母命名。命名应语义化。 eslint:id-length// badfunctionq(){// ...stuff...}// goodfunctionquery(){// ..stuff..}
23.2[强制] 使用驼峰式命名对象、函数和实例。 eslint:
camelcasejscs:requireCamelCaseOrUpperCaseIdentifiers// badconstOBJEcttsssss={};constthis_is_my_object={};functionc(){}// goodconstthisIsMyObject={};functionthisIsMyFunction(){}
23.3[强制] 使用帕斯卡式命名构造函数或类。 eslint:
new-capjscs:requireCapitalizedConstructors// badfunctionuser(options){this.name=options.name;}constbad=newuser({name: 'nope',});// goodclassUser{constructor(options){this.name=options.name;}}constgood=newUser({name: 'yup',});
23.4
[modified][建议 / warn] 不要使用下划线_结尾或开头来命名属性和方法。 eslint:no-underscore-danglejscs:disallowDanglingUnderscores为什么? Javascript对属性或方法而言并没有「私有」的定义。虽然用大多人用下划线开头表示“私有”, 但是实际上这些方法是完全公有的,是公共API的一部分。这种方式会让开发者误认为修改不会影响到它,或者不需要测试。如果你需要一些“私有”定义,那么它们不应该这样显眼。
// badthis.__firstName__='Panda';this.firstName_='Panda';this._firstName='Panda';// goodthis.firstName='Panda';
23.5[强制] 别保存
this的引用。使用箭头函数或 Function#bind. jscs:disallowNodeTypes// badfunctionfoo(){constself=this;returnfunction(){console.log(self);};}// badfunctionfoo(){constthat=this;returnfunction(){console.log(that);};}// goodfunctionfoo(){return()=>{console.log(this);};}
28.1 以下是链接到 ES6 的各个特性的列表。