- Notifications
You must be signed in to change notification settings - Fork208
adamlu/javascript-style-guide
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
原文: https://github.com/airbnb/javascript
注:本人根据自己的开发习惯删除和修改了部分规范
原始值: 相当于传值
string
number
boolean
null
undefined
varfoo=1,bar=foo;bar=9;console.log(foo,bar);// => 1, 9
复杂类型: 相当于传引用
object
array
function
varfoo=[1,2],bar=foo;bar[0]=9;console.log(foo[0],bar[0]);// => 9, 9
使用字面值创建对象
// badvaritem=newObject();// goodvaritem={};
不要使用保留字reserved words 作为键
// badvarsuperman={class:'superhero',default:{clark:'kent'},private:true};// goodvarsuperman={klass:'superhero',defaults:{clark:'kent'},hidden:true};
使用字面值创建数组
// badvaritems=newArray();// goodvaritems=[];
如果你不知道数组的长度,使用push
varsomeStack=[];// badsomeStack[someStack.length]='abracadabra';// goodsomeStack.push('abracadabra');
当你需要拷贝数组时使用slice.jsPerf
varlen=items.length,itemsCopy=[],i;// badfor(i=0;i<len;i++){itemsCopy[i]=items[i];}// gooditemsCopy=items.slice();
使用slice将类数组的对象转成数组.
functiontrigger(){varargs=Array.prototype.slice.call(arguments); ...}
对字符串使用单引号
''
// badvarname="Bob Parr";// goodvarname='Bob Parr';// badvarfullName="Bob "+this.lastName;// goodvarfullName='Bob '+this.lastName;
超过80个字符的字符串应该使用字符串连接换行
注: 如果过度使用,长字符串连接可能会对性能有影响.jsPerf &Discussion
// badvarerrorMessage='This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.';// badvarerrorMessage='This is a super long error that \was thrown because of Batman. \When you stop to think about \how Batman had anything to do \with this, you would get nowhere \fast.';// goodvarerrorMessage='This is a super long error that '+'was thrown because of Batman.'+'When you stop to think about '+'how Batman had anything to do '+'with this, you would get nowhere '+'fast.';
编程时使用join而不是字符串连接来构建字符串,特别是IE:jsPerf.
varitems,messages,length,i;messages=[{state:'success',message:'This one worked.'},{state:'success',message:'This one worked as well.'},{state:'error',message:'This one did not work.'}];length=messages.length;// badfunctioninbox(messages){items='<ul>';for(i=0;i<length;i++){items+='<li>'+messages[i].message+'</li>';}returnitems+'</ul>';}// goodfunctioninbox(messages){items=[];for(i=0;i<length;i++){items[i]=messages[i].message;}return'<ul><li>'+items.join('</li><li>')+'</li></ul>';}
函数表达式:
// 匿名函数表达式varanonymous=function(){returntrue;};// 有名函数表达式varnamed=functionnamed(){returntrue;};// 立即调用函数表达式(function(){console.log('Welcome to the Internet. Please follow me.');})();
绝对不要在一个非函数块里声明一个函数,把那个函数赋给一个变量。浏览器允许你这么做,但是它们解析不同。
注: ECMA-262定义把
块
定义为一组语句,函数声明不是一个语句。阅读ECMA-262对这个问题的说明.// badif(currentUser){functiontest(){console.log('Nope.');}}// goodif(currentUser){vartest=functiontest(){console.log('Yup.');};}
绝对不要把参数命名为
arguments
, 这将会逾越函数作用域内传过来的arguments
对象.// badfunctionnope(name,options,arguments){// ...stuff...}// goodfunctionyup(name,options,args){// ...stuff...}
当使用变量访问属性时使用中括号.
varluke={jedi:true,age:28};functiongetProp(prop){returnluke[prop];}varisJedi=getProp('jedi');
总是使用
var
来声明变量,如果不这么做将导致产生全局变量,我们要避免污染全局命名空间。// badsuperPower=newSuperPower();// goodvarsuperPower=newSuperPower();
使用一个
var
以及新行声明多个变量,缩进4个空格。// badvaritems=getItems();vargoSportsTeam=true;vardragonball='z';// goodvaritems=getItems(),goSportsTeam=true,dragonball='z';
最后再声明未赋值的变量,当你想引用之前已赋值变量的时候很有用。
// badvari,len,dragonball,items=getItems(),goSportsTeam=true;// badvari,items=getItems(),dragonball,goSportsTeam=true,len;// goodvaritems=getItems(),goSportsTeam=true,dragonball,length,i;
在作用域顶部声明变量,避免变量声明和赋值引起的相关问题。
// badfunction(){test();console.log('doing stuff..');//..other stuff..varname=getName();if(name==='test'){returnfalse;}returnname;}// goodfunction(){varname=getName();test();console.log('doing stuff..');//..other stuff..if(name==='test'){returnfalse;}returnname;}// badfunction(){varname=getName();if(!arguments.length){returnfalse;}returntrue;}// goodfunction(){if(!arguments.length){returnfalse;}varname=getName();returntrue;}
适当使用
===
和!==
以及==
和!=
.条件表达式的强制类型转换遵循以下规则:
- 对象 被计算为true
- Undefined 被计算为false
- Null 被计算为false
- 布尔值 被计算为布尔的值
- 数字 如果是+0, -0, or NaN 被计算为false , 否则为true
- 字符串 如果是空字符串
''
则被计算为false, 否则为true
if([0]){// true// An array is an object, objects evaluate to true}
使用快捷方式.
// badif(name!==''){// ...stuff...}// goodif(name){// ...stuff...}// badif(collection.length>0){// ...stuff...}// goodif(collection.length){// ...stuff...}
给所有多行的块使用大括号
// badif(test)returnfalse;// goodif(test)returnfalse;// goodif(test){returnfalse;}// badfunction(){returnfalse;}// goodfunction(){returnfalse;}
使用
/** ... */
进行多行注释,包括描述,指定类型以及参数值和返回值// bad// make() returns a new element// based on the passed in tag name////@param <String> tag//@return <Element> elementfunctionmake(tag){// ...stuff...returnelement;}// good/** * make() returns a new element * based on the passed in tag name * *@param <String> tag *@return <Element> element */functionmake(tag){// ...stuff...returnelement;}
使用
//
进行单行注释,在评论对象的上面进行单行注释,注释前放一个空行.// badvaractive=true;// is current tab// good// is current tabvaractive=true;// badfunctiongetType(){console.log('fetching type...');// set the default type to 'no type'vartype=this._type||'no type';returntype;}// goodfunctiongetType(){console.log('fetching type...');// set the default type to 'no type'vartype=this._type||'no type';returntype;}
如果你有一个问题需要重新来看一下或如果你建议一个需要被实现的解决方法的话需要在你的注释前面加上
FIXME
或TODO
帮助其他人迅速理解functionCalculator(){// FIXME: shouldn't use a global heretotal=0;returnthis;}
functionCalculator(){// TODO: total should be configurable by an options paramthis.total=0;returnthis;}
**[[⬆]](#TOC)**## <a name='whitespace'>空白</a>- 将tab设为4个空格 ```javascript // bad function() { ∙∙var name; } // bad function() { ∙var name; } // good function() { ∙∙∙∙var name; } ```- 大括号前放一个空格 ```javascript // bad function test(){ console.log('test'); } // good function test() { console.log('test'); } // bad dog.set('attr',{ age: '1 year', breed: 'Bernese Mountain Dog' }); // good dog.set('attr', { age: '1 year', breed: 'Bernese Mountain Dog' }); ```- 在做长方法链时使用缩进. ```javascript // bad $('#items').find('.selected').highlight().end().find('.open').updateCount(); // good $('#items') .find('.selected') .highlight() .end() .find('.open') .updateCount(); // bad var leds = 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); // good var leds = 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); ``` **[[⬆]](#TOC)**## <a name='commas'>逗号</a>- 不要将逗号放前面 ```javascript // bad var once , upon , aTime; // good var once, upon, aTime; // bad var hero = { firstName: 'Bob' , lastName: 'Parr' , heroName: 'Mr. Incredible' , superPower: 'strength' }; // good var hero = { firstName: 'Bob', lastName: 'Parr', heroName: 'Mr. Incredible', superPower: 'strength' }; ```- 不要加多余的逗号,这可能会在IE下引起错误,同时如果多一个逗号某些ES3的实现会计算多数组的长度。 ```javascript // bad var hero = { firstName: 'Kevin', lastName: 'Flynn', }; var heroes = [ 'Batman', 'Superman', ]; // good var hero = { firstName: 'Kevin', lastName: 'Flynn' }; var heroes = [ 'Batman', 'Superman' ]; ``` **[[⬆]](#TOC)**## <a name='semicolons'>分号</a>- 语句结束一定要加分号 ```javascript // bad (function() { var name = 'Skywalker' return name })() // good (function() { var name = 'Skywalker'; return name; })(); // good ;(function() { var name = 'Skywalker'; return name; })(); ``` **[[⬆]](#TOC)**## <a name='type-coercion'>类型转换</a>- 在语句的开始执行类型转换.- 字符串: ```javascript // => this.reviewScore = 9; // bad var totalScore = this.reviewScore + ''; // good var totalScore = '' + this.reviewScore; // bad var totalScore = '' + this.reviewScore + ' total score'; // good var totalScore = this.reviewScore + ' total score'; ```- 对数字使用 `parseInt` 并且总是带上类型转换的基数. ```javascript var inputValue = '4'; // bad var val = new Number(inputValue); // bad var val = +inputValue; // bad var val = inputValue >> 0; // bad var val = parseInt(inputValue); // good var val = Number(inputValue); // good var val = parseInt(inputValue, 10); // good /** * parseInt was the reason my code was slow. * Bitshifting the String to coerce it to a * Number made it a lot faster. */ var val = inputValue >> 0; ```- 布尔值: ```javascript var age = 0; // bad var hasAge = new Boolean(age); // good var hasAge = Boolean(age); // good var hasAge = !!age; ``` **[[⬆]](#TOC)**## <a name='naming-conventions'>命名约定</a>- 避免单个字符名,让你的变量名有描述意义。 ```javascript // bad function q() { // ...stuff... } // good function query() { // ..stuff.. } ```- 当命名对象、函数和实例时使用驼峰命名规则 ```javascript // bad var OBJEcttsssss = {}; var this_is_my_object = {}; var this-is-my-object = {}; function c() {}; var u = new user({ name: 'Bob Parr' }); // good var thisIsMyObject = {}; function thisIsMyFunction() {}; var user = new User({ name: 'Bob Parr' }); ```- 当命名构造函数或类时使用驼峰式大写 ```javascript // bad function user(options) { this.name = options.name; } var bad = new user({ name: 'nope' }); // good function User(options) { this.name = options.name; } var good = new User({ name: 'yup' }); ```- 命名私有属性时前面加个下划线 `_` ```javascript // bad this.__firstName__ = 'Panda'; this.firstName_ = 'Panda'; // good this._firstName = 'Panda'; ```- 当保存对 `this` 的引用时使用 `_this`. ```javascript // bad function() { var self = this; return function() { console.log(self); }; } // bad function() { var that = this; return function() { console.log(that); }; } // good function() { var _this = this; return function() { console.log(_this); }; } ``` **[[⬆]](#TOC)**## <a name='accessors'>存取器</a>- 属性的存取器函数不是必需的- 如果你确实有存取器函数的话使用getVal() 和 setVal('hello') ```javascript // bad dragon.age(); // good dragon.getAge(); // bad dragon.age(25); // good dragon.setAge(25); ```- 如果属性是布尔值,使用isVal() 或 hasVal() ```javascript // bad if (!dragon.age()) { return false; } // good if (!dragon.hasAge()) { return false; } ```- 可以创建get()和set()函数,但是要保持一致 ```javascript function Jedi(options) { options || (options = {}); var lightsaber = options.lightsaber || 'blue'; this.set('lightsaber', lightsaber); } Jedi.prototype.set = function(key, val) { this[key] = val; }; Jedi.prototype.get = function(key) { return this[key]; }; ``` **[[⬆]](#TOC)**## <a name='constructors'>构造器</a>- 给对象原型分配方法,而不是用一个新的对象覆盖原型,覆盖原型会使继承出现问题。 ```javascript function Jedi() { console.log('new jedi'); } // bad Jedi.prototype = { fight: function fight() { console.log('fighting'); }, block: function block() { console.log('blocking'); } }; // good Jedi.prototype.fight = function fight() { console.log('fighting'); }; Jedi.prototype.block = function block() { console.log('blocking'); }; ```- 方法可以返回 `this` 帮助方法可链。 ```javascript // bad Jedi.prototype.jump = function() { this.jumping = true; return true; }; Jedi.prototype.setHeight = function(height) { this.height = height; }; var luke = new Jedi(); luke.jump(); // => true luke.setHeight(20) // => undefined // good Jedi.prototype.jump = function() { this.jumping = true; return this; }; Jedi.prototype.setHeight = function(height) { this.height = height; return this; }; var luke = new Jedi(); luke.jump() .setHeight(20); ```- 可以写一个自定义的toString()方法,但是确保它工作正常并且不会有副作用。 ```javascript function Jedi(options) { options || (options = {}); this.name = options.name || 'no name'; } Jedi.prototype.getName = function getName() { return this.name; }; Jedi.prototype.toString = function toString() { return 'Jedi - ' + this.getName(); }; ``` **[[⬆]](#TOC)**## <a name='events'>事件</a>- 当给事件附加数据时,传入一个哈希而不是原始值,这可以让后面的贡献者加入更多数据到事件数据里而不用找出并更新那个事件的事件处理器 ```js // bad $(this).trigger('listingUpdated', listing.id); ... $(this).on('listingUpdated', function(e, listingId) { // do something with listingId }); ``` 更好: ```js // good $(this).trigger('listingUpdated', { listingId : listing.id }); ... $(this).on('listingUpdated', function(e, data) { // do something with data.listingId }); ```**[[⬆]](#TOC)**## <a name='modules'>模块</a>- 模块应该以 `!` 开始,这保证了如果一个有问题的模块忘记包含最后的分号在合并后不会出现错误- 这个文件应该以驼峰命名,并在同名文件夹下,同时导出的时候名字一致- 加入一个名为noConflict()的方法来设置导出的模块为之前的版本并返回它- 总是在模块顶部声明 `'use strict';` ```javascript // fancyInput/fancyInput.js !function(global) { 'use strict'; var previousFancyInput = global.FancyInput; function FancyInput(options) { this.options = options || {}; } FancyInput.noConflict = function noConflict() { global.FancyInput = previousFancyInput; return FancyInput; }; global.FancyInput = FancyInput; }(this); ``` **[[⬆]](#TOC)**## <a name='jquery'>jQuery</a>- 缓存jQuery查询 ```javascript // bad function setSidebar() { $('.sidebar').hide(); // ...stuff... $('.sidebar').css({ 'background-color': 'pink' }); } // good function setSidebar() { var $sidebar = $('.sidebar'); $sidebar.hide(); // ...stuff... $sidebar.css({ 'background-color': 'pink' }); } ```- 对DOM查询使用级联的 `$('.sidebar ul')` 或 `$('.sidebar ul')`,[jsPerf](http://jsperf.com/jquery-find-vs-context-sel/16)- 对有作用域的jQuery对象查询使用 `find` ```javascript // bad $('.sidebar', 'ul').hide(); // bad $('.sidebar').find('ul').hide(); // good $('.sidebar ul').hide(); // good $('.sidebar > ul').hide(); // good (slower) $sidebar.find('ul'); // good (faster) $($sidebar[0]).find('ul'); ``` **[[⬆]](#TOC)**## <a name='es5'>ECMAScript 5兼容性</a>- 参考[Kangax](https://twitter.com/kangax/)的 ES5 [compatibility table](http://kangax.github.com/es5-compat-table/)**[[⬆]](#TOC)**## <a name='performance'>性能</a>- [On Layout & Web Performance](http://kellegous.com/j/2013/01/26/layout-performance/)- [String vs Array Concat](http://jsperf.com/string-vs-array-concat/2)- [Try/Catch Cost In a Loop](http://jsperf.com/try-catch-in-loop-cost)- [Bang Function](http://jsperf.com/bang-function)- [jQuery Find vs Context, Selector](http://jsperf.com/jquery-find-vs-context-sel/13)- [innerHTML vs textContent for script text](http://jsperf.com/innerhtml-vs-textcontent-for-script-text)- [Long String Concatenation](http://jsperf.com/ya-string-concat)- Loading...**[[⬆]](#TOC)**## <a name='resources'>资源</a>**Read This**- [Annotated ECMAScript 5.1](http://es5.github.com/)**其它规范**- [Google JavaScript Style Guide](http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml)- [jQuery Core Style Guidelines](http://docs.jquery.com/JQuery_Core_Style_Guidelines)- [Principles of Writing Consistent, Idiomatic JavaScript](https://github.com/rwldrn/idiomatic.js/)**其它风格**- [Naming this in nested functions](https://gist.github.com/4135065) - Christian Johansen- [Conditional Callbacks](https://github.com/airbnb/javascript/issues/52)**阅读更多**- [Understanding JavaScript Closures](http://javascriptweblog.wordpress.com/2010/10/25/understanding-javascript-closures/) - Angus Croll**书籍**- [#"hidden" data-csrf="true" value="Fg2eqcQancuSl8MwfIk7UDw8J/zVBi7nT2j8n0URxd8nW+MoZSBQKOPS2T0AY6hAlhI6KGGOjJjUBz6slFqUQg==" />
About
JavaScript规范
Resources
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Releases
Packages0
[8]ページ先頭