基于Airbnb JavaScript Style Guide的最合理的TypeScript方法
- Types
- References
- Objects
- Arrays
- Destructuring
- Strings
- Functions
- Arrow Functions
- Constructors
- Modules
- Iterators and Generators
- Properties
- Variables
- Hoisting
- Comparison Operators & Equality
- Blocks
- Comments
- Whitespace
- Commas
- Semicolons
- Type Casting & Coercion
- Naming Conventions
- Accessors
- Events
- jQuery
- Type Annotations
- Interfaces
- Organization
- ECMAScript 5 Compatibility
- ECMAScript 6 Styles
- Typescript 1.5 Styles
- License
-
1.1 基本类型: 访问基本类型时,直接使用其值.
string
number
boolean
null
undefined
const foo = 1; let bar = foo; bar = 9; console.log(foo, bar); // => 1, 9
-
1.2 复杂类型: 访问复杂类型时,需要引用其值.
object
array
function
const foo = [1, 2]; const bar = foo; bar[0] = 9; console.log(foo[0], bar[0]); // => 9, 9
-
2.1 所有的赋值都用
const
,避免使用var
.why? 这样可以确保你不能重新分配引用(变异),这可能导致bug和难以理解的代码.
// bad var a = 1; var b = 2; // good const a = 1; const b = 2;
-
2.2 如果你一定要对参数重新赋值,那就用
let
,而不是var
.Why? 因为
let
是块级作用域,而var
是函数级作用域.// bad var count = 1; if (true) { count += 1; } // good, use the let. let count = 1; if (true) { count += 1; }
-
2.3 注意:
let
、const
都是块级作用域.// const and let only exist in the blocks they are defined in. { let a = 1; const b = 1; } console.log(a); // ReferenceError console.log(b); // ReferenceError
-
3.1 使用字面量创建对象.
// bad const item = new Object(); // good const item = {};
-
3.2 不要使用保留字作为键. 在IE8中将无法使用.更多信息.
// bad const superman = { default: { clark: 'kent' }, private: true, }; // good const superman = { defaults: { clark: 'kent' }, hidden: true, };
-
3.3 使用可读的同义词代替保留字.
// bad const superman = { class: 'alien', }; // bad const superman = { klass: 'alien', }; // good const superman = { type: 'alien', };
-
3.4 使用动态属性名称创建对象时,用计算后属性名称.
Why? 这可以使你将定义的所有属性放在对象的一个地方.
const getKey = function(k) { return `a key named ${k}`; } // bad const obj = { id: 5, name: 'San Francisco', }; obj[getKey('enabled')] = true; // good const obj = { id: 5, name: 'San Francisco', [getKey('enabled')]: true, };
-
3.5 使用箭头函数代替对象属性或匿名函数的对象方法.
// bad const atom = { value: 1, addValue: function (value) { return atom.value + value; }, }; // bad const atom = { value: 1, addValue(value) { return atom.value + value; }, }; // good const atom = { value: 1, addValue: (value) => atom.value + value };
-
3.6 用属性值缩写.
Why? It is shorter to write and descriptive.
const lukeSkywalker = 'Luke Skywalker'; // bad const obj = { lukeSkywalker: lukeSkywalker, }; // good const obj = { lukeSkywalker, };
-
3.7 将你的所有缩写放在对象声明的开始.
Why? 这样也是为了更方便的知道有哪些属性用了缩写.
const anakinSkywalker = 'Anakin Skywalker'; const lukeSkywalker = 'Luke Skywalker'; // bad const obj = { episodeOne: 1, twoJedisWalkIntoACantina: 2, lukeSkywalker, episodeThree: 3, mayTheFourth: 4, anakinSkywalker, }; // good const obj = { lukeSkywalker, anakinSkywalker, episodeOne: 1, twoJedisWalkIntoACantina: 2, episodeThree: 3, mayTheFourth: 4, };
-
4.1 使用字面量创建数组.
// bad const items = new Array(); // good const items = [];
-
4.2 用Array#push代替直接向数组中添加一个值.
const someStack = []; // bad someStack[someStack.length] = 'abracadabra'; // good someStack.push('abracadabra');
-
4.3 用扩展运算符
...
做数组浅拷贝.// bad const len = items.length; const itemsCopy = []; let i; for (i = 0; i < len; i++) { itemsCopy[i] = items[i]; } // good const itemsCopy = [...items];
-
4.4 用
Array.from
将一个类数组对象转成一个数组.const foo = document.querySelectorAll('.foo'); const nodes = Array.from(foo);
-
5.1 用对象的解构赋值来获取和使用对象某个或多个属性值.
Why? 解构保存了这些属性的临时值/引用.
// bad const getFullName = function(user) { const firstName = user.firstName; const lastName = user.lastName; return `${firstName} ${lastName}`; } // good const getFullName = function(obj) { const { firstName, lastName } = obj; return `${firstName} ${lastName}`; } // best const getFullName = function({ firstName, lastName }) { return `${firstName} ${lastName}`; }
-
5.2 用数组解构.
const arr = [1, 2, 3, 4]; // bad const first = arr[0]; const second = arr[1]; // good const [first, second] = arr;
-
5.3 多个返回值用对象的解构,而不是数据解构.
Why? 你可以在后期添加新的属性或者变换变量的顺序而不会打破原有的调用.
// bad const processInput = function(input) { // 然后奇迹发生了 return [left, right, top, bottom]; } // 调用者需要想一想返回值的顺序 const [left, __, top] = processInput(input); // good const processInput = function(input) { // 然后奇迹发生了 return { left, right, top, bottom }; } // 调用者只需要选择他想用的值就好了 const { left, right } = processInput(input);
-
6.1 对string用单引号
''
.// bad const name = "Capt. Janeway"; // good const name = 'Capt. Janeway';
-
6.2 长度超过80个字符的字符串应使用字符串串联写在多行中.
-
6.3 注意:如果过度使用,带有连接的长字符串可能会影响性能. jsPerf & Discussion.
// bad const errorMessage = '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.'; // bad const errorMessage = '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.'; // good const errorMessage = '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.';
-
6.4 用字符串模板而不是字符串拼接来组织可编程字符串.
Why? 模板字符串更具可读性、语法简洁、字符串插入参数.
// bad const sayHi = function(name) { return 'How are you, ' + name + '?'; } // bad const sayHi = function(name) { return ['How are you, ', name, '?'].join(); } // good const sayHi = function(name) { return `How are you, ${name}?`; }
-
7.1 用命名函数表达式而不是函数声明.
Why? 错误放置的函数声明会引起误解,在少数情况下(如果有)您不能使用分配给变量的函数表达式. See function-declarations-vs-function-expressions.
// bad function foo() { } // good const foo = function() { }; // good const foo = () => { };
-
7.2 函数表达式:
// immediately-invoked function expression (IIFE) (() => { console.log('Welcome to the Internet. Please follow me.'); })();
-
7.3 不要在非函数块(if、while等等)内声明函数.把这个函数分配给一个变量.浏览器会允许你这样做,但浏览器解析方式不同,这是一个坏消息.
-
7.4 Note: ECMA-262将
block
定义为语句列表. 函数声明不是语句. Read ECMA-262's note on this issue.// bad if (currentUser) { const test = function() { console.log('Nope.'); } } // good let test; if (currentUser) { test = () => { console.log('Yup.'); }; }
-
7.5 不要用
arguments
命名参数.它的优先级高于每个函数作用域自带的arguments
对象, 这会导致函数自带的arguments
值被覆盖.// bad const nope = function(name, options, arguments) { // ...stuff... } // good const yup = function(name, options, args) { // ...stuff... }
-
7.6 不要使用
arguments
,用rest语法...
代替.Why?
...
明确你想用哪个参数.而且rest参数是真数组,而不是类似数组的arguments
.// bad const concatenateAll = function() { const args = Array.prototype.slice.call(arguments); return args.join(''); } // good const concatenateAll = function(...args) { return args.join(''); }
-
7.7 用默认参数语法而不是在函数里对参数重新赋值.
// really bad const handleThings = function(opts) { // 不, 我们不该改arguments // 第二: 如果 opts 的值为 false, 它会被赋值为 {} // 虽然你想这么写, 但是这个会带来一些细微的bug opts = opts || {}; // ... } // still bad const handleThings = function(opts) { if (opts === void 0) { opts = {}; } // ... } // good const handleThings = function(opts = {}) { //opts为undefined时,会被赋值为{} // ... }
-
7.8 默认参数避免副作用.
Why? 它会令人迷惑不解.
var b = 1; // bad const count = function(a = b++) { console.log(a); } count(); // 1 count(); // 2 count(3); // 3 count(); // 3
-
8.1 当你必须使用函数表达式时(如传递匿名函数时),请使用箭头函数符号.
Why? 它创建了一个
this
的当前执行上下文的函数的版本,这通常就是你想要的;而且箭头函数是更简洁的语法.Why not? 如果函数相当复杂,则可以将该逻辑移到其自己的函数声明中.
// bad [1, 2, 3].map(function (x) { return x * x; }); // good [1, 2, 3].map((x) => { return x * x; }); // good [1, 2, 3].map((x) => x * x;);
-
8.2 如果函数主体适合一行且只有一个参数,则可以忽略大括号和括号,并使用隐式返回. 否则,添加括号,大括号并使用
return
语句.Why? 语法糖,当多个函数链在一起的时候易读.
Why not? 当你计算返回一个对象.
// good [1, 2, 3].map(x => x * x); // good [1, 2, 3].reduce((total, n) => { return total + n; }, 0);
-
9.1 常用
class
,避免直接操作prototype
.Why?
class
语法更简洁更易理解.// bad function Queue(contents = []) { this._queue = [...contents]; } Queue.prototype.pop = function() { const value = this._queue[0]; this._queue.splice(0, 1); return value; } // good class Queue { constructor(contents = []) { this._queue = [...contents]; } pop() { const value = this._queue[0]; this._queue.splice(0, 1); return value; } }
-
9.2 用
extends
实现继承.Why? 它是一种内置的方法来继承原型功能而不打破
instanceof
.// bad const inherits = require('inherits'); function PeekableQueue(contents) { Queue.apply(this, contents); } inherits(PeekableQueue, Queue); PeekableQueue.prototype.peek = function() { return this._queue[0]; } // good class PeekableQueue extends Queue { peek() { return this._queue[0]; } }
-
9.3 方法可以返回
this
来实现方法链.// bad Jedi.prototype.jump = function() { this.jumping = true; return true; }; Jedi.prototype.setHeight = function(height) { this.height = height; }; const luke = new Jedi(); luke.jump(); // => true luke.setHeight(20); // => undefined // good class Jedi { jump() { this.jumping = true; return this; } setHeight(height) { this.height = height; return this; } } const luke = new Jedi(); luke.jump() .setHeight(20);
-
9.4 写一个定制的toString()方法是可以的,只要保证它是可以正常工作且没有副作用的.
class Jedi { contructor(options = {}) { this.name = options.name || 'no name'; } getName() { return this.name; } toString() { return `Jedi - ${this.getName()}`; } }
- 9.5 Typescript classes placeholder.
-
10.1 用(
import
/export
) 模块而不是无标准的模块系统.你可以随时转到你喜欢的模块系统.Why? 模块化是未来,让我们现在就开启未来吧.
// bad const AirbnbStyleGuide = require('./AirbnbStyleGuide'); module.exports = AirbnbStyleGuide.es6; // ok import AirbnbStyleGuide from './AirbnbStyleGuide'; export default AirbnbStyleGuide.es6; // best import { es6 } from './AirbnbStyleGuide'; export default es6;
-
10.2 不要直接从
import
中导出.Why? 虽然一行是简洁的,有一个明确的方式进口和一个明确的出口方式来保证一致性.
// bad // filename es6.js export { es6 as default } from './airbnbStyleGuide'; // good // filename es6.js import { es6 } from './AirbnbStyleGuide'; export default es6;
-
10.3 将TypeScript模块导入用于具有类型定义的非ES6库. 检查DefinitelyTyped 中可用的类型定义文件.
Why? 这将在可用时提供来自外部模块的类型信息
// bad /// <reference path="lodash/lodash.d.ts" /> var lodash = require('lodash') // good /// <reference path="lodash/lodash.d.ts" /> import lodash = require('lodash')
-
10.4 按类型导入组模块,然后按变量名称按字母顺序. 请遵循以下规则来排序模块导入: + 具有类型定义的外部库 + 具有通配符导入功能的内部typescript模块 + 不带通配符导入的内部typescript模块 + 没有类型定义的外部库
Why? 这样可以使导入部分在所有模块中保持一致.
// bad /// <reference path="../typings/tsd.d.ts" /> import * as Api from './api'; import _ = require('lodash'); var Distillery = require('distillery-js'); import Partner from './partner'; import * as Util from './util'; import Q = require('Q'); var request = require('request'); import Customer from './customer'; // good /// <reference path="../typings/tsd.d.ts" /> import _ = require('lodash'); import Q = require('Q'); import * as Api from './api'; import * as Util from './util'; import Customer from './customer'; import Partner from './partner'; var Distillery = require('distillery-js'); var request = require('request');
-
11.1 不要使用迭代器.用JavaScript高级函数(例如
map()
andreduce()
) 代替for-of
这样的循环.Why? 这强调了我们不可变的规则. 处理返回值的纯函数比副作用更容易.
const numbers = [1, 2, 3, 4, 5]; // bad let sum = 0; for (let num of numbers) { sum += num; } sum === 15; // good let sum = 0; numbers.forEach((num) => sum += num); sum === 15; // best (use the functional force) const sum = numbers.reduce((total, num) => total + num, 0); sum === 15;
-
11.2 现在不要用generator.
Why? 它在ES5上支持的不好.
-
12.1 访问属性时使用点符号.
const luke = { jedi: true, age: 28, }; // bad const isJedi = luke['jedi']; // good const isJedi = luke.jedi;
-
12.2 当获取的属性是变量时用方括号
[]
取.const luke = { jedi: true, age: 28, }; const getProp = function(prop) { return luke[prop]; } const isJedi = getProp('jedi');
-
13.1 始终使用const声明变量. 不这样做将导致全局变量. 我们要避免污染全局名称空间.
// bad superPower = new SuperPower(); // good const superPower = new SuperPower();
-
13.2 每个变量使用一个
const
声明.Why? 这种方式很容易去声明新的变量,你不用去考虑把
;
调换成,
,或者引入一个只有标点的不同的变化.这种做法也可以是你在调试的时候单步每个声明语句,而不是一下跳过所有声明.// bad const items = getItems(), goSportsTeam = true, dragonball = 'z'; // bad // (compare to above, and try to spot the mistake) const items = getItems(), goSportsTeam = true; dragonball = 'z'; // good const items = getItems(); const goSportsTeam = true; const dragonball = 'z';
-
13.3
const
放一起,let
放一起.Why? 在你需要分配一个新的变量, 而这个变量依赖之前分配过的变量的时候,这种做法是有帮助的.
// bad let i, len, dragonball, items = getItems(), goSportsTeam = true; // bad let i; const items = getItems(); let dragonball; const goSportsTeam = true; let len; // good const goSportsTeam = true; const items = getItems(); let dragonball; let i; let length;
-
13.4 在你需要的地方声明变量,但是要放在合理的位置.
Why?
let
和const
都是块级作用域而不是函数级作用域.// good function() { test(); console.log('doing stuff..'); //..other stuff.. const name = getName(); if (name === 'test') { return false; } return name; } // bad - unnessary function call function(hasName) { const name = getName(); if (!hasName) { return false; } this.setFirstName(name); return true; } // good function(hasName) { if (!hasName) { return false; } const name = getName(); this.setFirstName(name); return true; }
-
14.1
var
声明会被提前到他的作用域的最前面,它分配的值还没有提前.const
和let
被赋予了新的调用概念 时效区 —— Temporal Dead Zones (TDZ). 重要的是要知道为什么 typeof is no longer safe.// 我们知道这个不会工作,假设没有定义全局的notDefined function example() { console.log(notDefined); // => throws a ReferenceError } // 在你引用的地方之后声明一个变量,他会正常输出是因为变量作用域上升. // 注意: declaredButNotAssigned的值没有上升 function example() { console.log(declaredButNotAssigned); // => undefined var declaredButNotAssigned = true; } // 解释器把变量声明提升到作用域最前面, // 可以重写成如下例子, 二者意义相同 function example() { let declaredButNotAssigned; console.log(declaredButNotAssigned); // => undefined declaredButNotAssigned = true; } // 用 const, let就不一样了 function example() { console.log(declaredButNotAssigned); // => throws a ReferenceError console.log(typeof declaredButNotAssigned); // => throws a ReferenceError const declaredButNotAssigned = true; }
-
14.2 匿名函数表达式将使用其变量名,而不是函数分配.
function example() { console.log(anonymous); // => undefined anonymous(); // => TypeError anonymous is not a function var anonymous = function() { console.log('anonymous function expression'); }; }
-
14.3 已命名函数表达式提升他的变量名,不是函数名或函数体.
function example() { console.log(named); // => undefined named(); // => TypeError named is not a function superPower(); // => ReferenceError superPower is not defined var named = function superPower() { console.log('Flying'); }; } // 函数名和变量名一样是也如此 function example() { console.log(named); // => undefined named(); // => TypeError named is not a function var named = function named() { console.log('named'); } }
-
14.4 函数声明则提升了函数名和函数体.
function example() { superPower(); // => Flying function superPower() { console.log('Flying'); } }
-
详情请见 JavaScript Scoping & Hoisting by Ben Cherry.
-
15.1 用
===
和!==
而不是==
和!=
. -
15.2 条件语句如'if'语句使用强制`ToBoolean'抽象方法来评估它们的表达式,并且始终遵循以下简单规则:
- Objects 计算成 true
- Undefined 计算成 false
- Null 计算成 false
- Booleans 计算成 the value of the boolean
- Numbers
- +0, -0, or NaN 计算成 false
- 其他 true
- Strings
''
计算成 false- 其他 true
if ([0]) { // true // An array is an object, objects evaluate to true }
-
15.3 布尔值用缩写.
// bad if (name !== '') { // ...stuff... } // good if (name) { // ...stuff... } // bad if (collection.length > 0) { // ...stuff... } // good if (collection.length) { // ...stuff... }
-
15.4 更多信息请见 Truth Equality and JavaScript by Angus Croll.
-
16.1 将大括号与多行块一起使用,或者将大括号省略给两个行块.
// bad if (test) return false; // ok if (test) return false; // good if (test) { return false; } // bad function() { return false; } // good function() { return false; }
-
16.2
if
表达式的else
和if
的关闭大括号在一行.// bad if (test) { thing1(); thing2(); } else { thing3(); } // good if (test) { thing1(); thing2(); } else { thing3(); }
-
16.3 如果您使用带有
if
和else
的多行块,请不要省略花括号.Why? 在多行块中省略花括号很容易导致意外行为.
// bad if (test) thing1(); thing2(); else thing3(); // good if (test) { thing1(); thing2(); } else { thing3(); }
-
-
17.1 对多行注释使用
/ ** ... * /
. 包括说明,为所有参数指定类型和值并返回值.// bad // make() returns a new element // based on the passed in tag name // // @param {String} tag // @return {Element} element const make = function(tag) { // ...stuff... return element; } // good /** * make() returns a new element * based on the passed in tag name * * @param {String} tag * @return {Element} element */ const make = function(tag) { // ...stuff... return element; }
-
17.2 单行注释用
//
. 将单行注释放在被注释区域上面.如果注释不是在第一行,那么注释前面就空一行.// bad const active = true; // is current tab // good // is current tab const active = true; // bad const getType = function() { console.log('fetching type...'); // set the default type to 'no type' const type = this._type || 'no type'; return type; } // good const getType = function() { console.log('fetching type...'); // set the default type to 'no type' const type = this._type || 'no type'; return type; }
-
17.3 给您的注释加上FIXME或TODO前缀可以帮助其他开发人员快速了解您是否指出需要重新审视的问题,或者是否建议解决需要实施的问题. 这些与常规评论不同,因为它们是可行的. 这些动作是" FIXME-需要弄清楚"或" TODO-需要实现".
-
17.4 使用
// FIXME:
注释问题.class Calculator { constructor() { // FIXME: shouldn't use a global here total = 0; } }
-
17.5 使用
// TODO:
注释问题的解决方案.class Calculator { constructor() { // TODO: total should be configurable by an options param this.total = 0; } }
-
18.1 两个空格用tab.
// bad function() { ∙∙∙∙const name; } // bad function() { ∙const name; } // good function() { ∙∙const name; }
-
18.2 在大括号前空一格.
// bad const test = function(){ console.log('test'); } // good const test = function() { 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', });
-
18.3 在控制语句(
if
,while
等)的圆括号前空一格.在函数调用和定义时,参数列表和函数名之间不空格.// bad if(isJedi) { fight (); } // good if (isJedi) { fight(); } // bad const fight = function () { console.log ('Swooosh!'); } // good const fight = function() { console.log('Swooosh!'); }
-
18.4 用空格来隔开运算符.
// bad const x=y+5; // good const x = y + 5;
-
18.5 用单个换行符结束文件.
// bad (function(global) { // ...stuff... })(this);
// bad (function(global) { // ...stuff... })(this);↵ ↵
// good (function(global) { // ...stuff... })(this);↵
-
18.5 当出现长的方法链(>2个)时用缩进.用点开头强调该行是一个方法调用,而不是一个新的语句.
// 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(); // bad const 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 const leds = 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);
-
18.6 在块打开之后和块关闭之前留空行
// bad
if (foo) {
return bar;
}
// good
if (foo) {
return bar;
}
// bad
const baz = function(foo) {
return bar;
}
// good
const baz = function(foo) {
return bar;
}
-
18.7 在一个代码块后下一条语句前空一行.
// bad if (foo) { return bar; } return baz; // good if (foo) { return bar; } return baz; // bad const obj = { foo() { }, bar() { }, }; return obj; // good const obj = { foo() { }, bar() { }, }; return obj;
-
19.1 不要前置逗号.
// bad const story = [ once , upon , aTime ]; // good const story = [ once, upon, aTime, ]; // bad const hero = { firstName: 'Ada' , lastName: 'Lovelace' , birthYear: 1815 , superPower: 'computers' }; // good const hero = { firstName: 'Ada', lastName: 'Lovelace', birthYear: 1815, superPower: 'computers', };
-
19.2 额外结尾逗号: Yup.
Why? 这导致git diffs更清洁. 此外,像Babel这样的转换器会删除转换代码中的额外的逗号,这意味着你不必担心旧版浏览器中的[ trailing comma problem in legacy browsers.
// bad - git diff without trailing comma const hero = { firstName: 'Florence', - lastName: 'Nightingale' + lastName: 'Nightingale', + inventorOf: ['coxcomb graph', 'mordern nursing'] } // good - git diff with trailing comma const hero = { firstName: 'Florence', lastName: 'Nightingale', + inventorOf: ['coxcomb chart', 'mordern nursing'], } // bad const hero = { firstName: 'Dana', lastName: 'Scully' }; const heroes = [ 'Batman', 'Superman' ]; // good const hero = { firstName: 'Dana', lastName: 'Scully', }; const heroes = [ 'Batman', 'Superman', ];
-
20.1 Yup.
// bad (function() { const name = 'Skywalker' return name })() // good (() => { const name = 'Skywalker'; return name; })(); // good (行首加分号,避免文件被连接到一起时立即执行函数被当做变量来执行.) ;(() => { const name = 'Skywalker'; return name; })();
-
21.1 在语句开始执行强制类型转换.
-
21.2 Strings:
// => this.reviewScore = 9; // bad const totalScore = this.reviewScore + ''; // good const totalScore = String(this.reviewScore);
-
21.3 使用
parseInt
表示数字,并始终使用基数进行类型转换.const inputValue = '4'; // bad const val = new Number(inputValue); // bad const val = +inputValue; // bad const val = inputValue >> 0; // bad const val = parseInt(inputValue); // good const val = Number(inputValue); // good const val = parseInt(inputValue, 10);
-
21.4 如果出于某种原因您正在做一些疯狂的事情,而" parseInt"是您的瓶颈,并且出于[性能原因](http://jsperf.com/coercion-vs-casting/3)而需要使用移位运算,请在注释中说明原因以及 你在做什么.
// good /** * parseInt是代码运行慢的原因 * 用Bitshifting将字符串转成数字使代码运行效率大幅增长 */ const val = inputValue >> 0;
-
21.5 注意: 用移位运算要小心. 数字使用64-位表示的,但移位运算常常返回的是32为整形source).移位运算对大于32位的整数会导致意外行为.Discussion. 最大的32位整数是 2,147,483,647:
2147483647 >> 0 //=> 2147483647 2147483648 >> 0 //=> -2147483648 2147483649 >> 0 //=> -2147483647
-
21.6 布尔:
const age = 0; // bad const hasAge = new Boolean(age); // good const hasAge = Boolean(age); // good const hasAge = !!age;
-
22.1 避免用一个字母命名,让你的命名可描述.
// bad function q() { // ...stuff... } // good function query() { // ..stuff.. }
-
22.2 命名对象、函数和实例时,使用小驼峰式.
// bad const OBJEcttsssss = {}; const this_is_my_object = {}; const c = function() {} // good const thisIsMyObject = {}; const thisIsMyFunction = function() {}
-
22.3 命名构造函数、类、模块或接口时,使用大驼峰式.
// bad function user(options) { this.name = options.name; } const bad = new user({ name: 'nope', }); // good module AperatureScience { class User { constructor(options) { this.name = options.name; } } } const good = new AperatureScience.User({ name: 'yup', });
-
22.4 命名对象属性时,使用snake_case.
// bad const panda = { firstName: 'Mr.', LastName: 'Panda' } // good const panda = { first_name: 'Mr.', Last_name: 'Panda' }
-
22.5 命名私有属性时,请使用下划线" _".
// bad this.__firstName__ = 'Panda'; this.firstName_ = 'Panda'; // good this._firstName = 'Panda';
-
22.6 不要保存对"this"的引用. 使用箭头函数或Function#bind.
// bad function foo() { const self = this; return function() { console.log(self); }; } // bad function foo() { const that = this; return function() { console.log(that); }; } // good function foo() { return () => { console.log(this); }; }
-
22.7 如果文件导出单个类,则文件名应与该类的名称完全相同.
// file contents class CheckBox { // ... } export default CheckBox; // in some other file // bad import CheckBox from './checkBox'; // bad import CheckBox from './check_box'; // good import CheckBox from './CheckBox';
-
22.8 当你export-default一个函数时,函数名用小驼峰,文件名需要和函数名一致.
function makeStyleGuide() { } export default makeStyleGuide;
-
22.9 当你export一个结构体/类/单例/函数库/对象 时用大驼峰.
const AirbnbStyleGuide = { es6: { } }; export default AirbnbStyleGuide;
-
23.1 不需要使用属性的访问器函数.
-
23.2 不要使用JavaScript的getters/setters,因为他们会产生副作用,并且难以测试、维护和理解.相反的,你可以用 getVal()和setVal('hello')去创造你自己的accessor函数.
// bad dragon.age(); // good dragon.getAge(); // bad dragon.age(25); // good dragon.setAge(25);
-
23.3 如果属性/方法是
boolean
, 用isVal()
或hasVal()
.// bad if (!dragon.age()) { return false; } // good if (!dragon.hasAge()) { return false; }
-
23.4 用get()和set()函数是可以的,但是要一起用.
class Jedi { constructor(options = {}) { const lightsaber = options.lightsaber || 'blue'; this.set('lightsaber', lightsaber); } set(key, val) { this[key] = val; } get(key) { return this[key]; } }
-
24.1 通过哈希而不是原始值向事件装载数据时(不论是DOM事件还是像Backbone事件的很多属性). 这使得后续的贡献者(程序员)向这个事件装载更多的数据时不用去找或者更新每个处理器.例如:
// bad $(this).trigger('listingUpdated', listing.id); ... $(this).on('listingUpdated', function(e, listingId) { // do something with listingId });
prefer:
// good $(this).trigger('listingUpdated', { listingId : listing.id }); ... $(this).on('listingUpdated', function(e, data) { // do something with data.listingId });
-
25.1 jQuery对象用
$
变量表示.// bad const sidebar = $('.sidebar'); // good const $sidebar = $('.sidebar');
-
25.2 暂存jQuery查找.
// bad function setSidebar() { $('.sidebar').hide(); // ...stuff... $('.sidebar').css({ 'background-color': 'pink' }); } // good function setSidebar() { const $sidebar = $('.sidebar'); $sidebar.hide(); // ...stuff... $sidebar.css({ 'background-color': 'pink' }); }
-
25.3 DOM查找用层叠式
$('.sidebar ul')
或 父节点 > 子节点$('.sidebar > ul')
. jsPerf -
25.4 用jQuery对象查询作用域的
find
方法查询.// bad $('ul', '.sidebar').hide(); // bad $('.sidebar').find('ul').hide(); // good $('.sidebar ul').hide(); // good $('.sidebar > ul').hide(); // good $sidebar.find('ul').hide();
- 26.1 Type annotations placeholder.
- 26.2 如果只需要一个,则使用" T"作为类型变量.
function identify<T>(arg: T): T {
return arg;
}
- 26.3 如果需要多个类型变量,请以字母"T"开头,并按字母顺序命名变量.
function find<T, U extends Findable>(needle: T, haystack: U): U {
return haystack.find(needle)
}
- 26.4 如果可能,允许编译器推断变量的类型.
// bad
const output = identify<string>("myString");
// good
const output = identity("myString");
- 26.5 使用泛型创建函数时,请确保在类型中包含构造函数.
function create<t>(thing: {new(): T;}): T {
return new thing();
}
- 27.1 Interface placeholder.
- 28.1 每个逻辑组件1个文件,每个文件应通过模块划分为逻辑分区.
module Automobile {
module Honda {
}
}
- 28.2 每个文件导出一个主模块,以便其他文件可以使用.
module Automobile {
// 隐藏的模块,将无法通过“ require”访问
Honda {
}
// 公共模块,可以通过“ require”访问
export Ford {
export function vroom() {
console.log('vroom!');
}
}
}
export default Automobile;
- 28.3 在每个模块中按以下顺序对代码进行排序(字母顺序):
- var
- export var
- let
- export let
- const
- export const
- interface
- export interface
- function
- export function
- class
- export class
- module
- export module
- 29.1 Refer to Kangax's ES5 compatibility table.
- 30.1 这是收集到的各种ES6特性的链接.
- Arrow Functions
- Classes
- Object Shorthand
- Object Concise
- Object Computed Properties
- Template Strings
- Destructuring
- Default Parameters
- Rest
- Array Spreads
- Let and Const
- Iterators and Generators
- Modules
- 31.1 这是收集到的各种ES6特性的链接.
(The MIT License)
Copyright (c) 2014 Airbnb
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.