二十二、类型转换 Type Casting & Coercion
-
22.1 在声明开头执行强制类型转换。Perform type coercion at the beginning of the statement.
-
22.2 转为String:使用
String(待转变量)
将其他类型转为字符串。Strings:useString
(eslint:no-new-wrappers
)// => this.reviewScore = 9; // bad const totalScore = new String(this.reviewScore); // typeof totalScore is "object" not "string" // bad const totalScore = this.reviewScore + ''; // invokes this.reviewScore.valueOf() // bad const totalScore = this.reviewScore.toString(); // isn’t guaranteed to return a string // good const totalScore = String(this.reviewScore);
-
22.3 转为Number:使用
Number
将其他类型转为Number,或使用parseInt
将String转为Number。Numbers: UseNumber
for type casting andparseInt
always with a radix for parsing strings. (eslint:radix
no-new-wrappers
)Why? The
parseInt
function produces an integer value dictated by interpretation of the contents of the string argument according to the specified radix. Leading whitespace in string is ignored. If radix isundefined
or0
, it is assumed to be10
except when the number begins with the character pairs0x
or0X
, in which case a radix of 16 is assumed. This differs from ECMAScript 3, which merely discouraged (but allowed) octal interpretation. Many implementations have not adopted this behavior as of 2013. And, because older browsers must be supported, always specify a radix.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);
-
22.4 请在注释中解释为什么要用移位运算,无论你在做什么,比如由于
parseInt
是你的性能瓶颈导致你一定要用移位运算。 请说明这个是因为性能原因。If for whatever reason you are doing something wild andparseInt
is your bottleneck and need to use Bitshift for performance reasons, leave a comment explaining why and what you’re doing.// good /** * parseInt was the reason my code was slow.导致代码运行慢 * Bitshifting the String to coerce it to a * Number made it a lot faster. */ const val = inputValue >> 0;
-
22.5 - 注意: 使用 bitshift 操作时要小心。数字表示为 64 位值,但 bitshift 操作始终返回 32 位整数。对于大于32位的整数值,Bitshift可能会导致意外行为。Note: Be careful when using bitshift operations. Numbers are represented as 64-bit values, but bitshift operations always return a 32-bit integer (source). Bitshift can lead to unexpected behavior for integer values larger than 32 bits. Discussion. Largest signed 32-bit Int is 2,147,483,647:
2147483647 >> 0; // => 2147483647 2147483648 >> 0; // => -2147483648 2147483649 >> 0; // => -2147483647
-
22.6 转为Boolean:使用
Boolean()
或!!
。Booleans: UseBoolean()
||!!
(eslint:no-new-wrappers
)const age = 0; // bad const hasAge = new Boolean(age); // good const hasAge = Boolean(age); // best const hasAge = !!age;
二十三、命名约定 Naming Conventions
-
23.1 避免用一个字母命名,让你的命名更加语义化。Avoid single letter names. Be descriptive with your naming. (eslint:
id-length
)// bad function q() { // ... } // good function query() { // ... }
-
23.2 用 驼峰 命名你的对象、函数、实例。Use camelCase when naming objects, functions, and instances. (eslint:
camelcase
)// bad const OBJEcttsssss = {}; const this_is_my_object = {}; function c() {} // good const thisIsMyObject = {}; function thisIsMyFunction() {}
-
23.3 用 PascalCase 命名类。Use PascalCase only when naming constructors or classes. (eslint:
new-cap
)// bad function user(options) { this.name = options.name; } const bad = new user({ name: 'nope', }); // good class User { constructor(options) { this.name = options.name; } } const good = new User({ name: 'yup', });
-
23.4 不要用前置或后置下划线。Do not use trailing or leading underscores. eslint:
no-underscore-dangle
Why? JavaScript does not have the concept of privacy in terms of properties or methods. Although a leading underscore is a common convention to mean “private”, in fact, these properties are fully public, and as such, are part of your public API contract. This convention might lead developers to wrongly think that a change won’t count as breaking, or that tests aren’t needed. tl;dr: if you want something to be “private”, it must not be observably present.
// bad this.__firstName__ = 'Panda'; this.firstName_ = 'Panda'; this._firstName = 'Panda'; // good this.firstName = 'Panda'; // good, in environments where WeakMaps are available // see https://kangax.github.io/compat-table/es6/#test-WeakMap const firstNames = new WeakMap(); firstNames.set(this, 'Panda');
-
23.5 不要保存
this
的引用,使用箭头函数或硬绑定。Don’t save references tothis
. Use arrow functions or 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); }; }
-
23.6 文件名应与默认导出(
export default
)的名称完全匹配。A base filename should exactly match the name of its default export.// file 1 contents class CheckBox { // ... } export default CheckBox; // file 2 contents export default function fortyTwo() { return 42; } // file 3 contents export default function insideDirectory() {} // in some other file // bad import CheckBox from './checkBox'; // PascalCase import/export, camelCase filename import FortyTwo from './FortyTwo'; // PascalCase import/filename, camelCase export import InsideDirectory from './InsideDirectory'; // PascalCase import/filename, camelCase export // bad import CheckBox from './check_box'; // PascalCase import/export, snake_case filename import forty_two from './forty_two'; // snake_case import/filename, camelCase export import inside_directory from './inside_directory'; // snake_case import, camelCase export import index from './inside_directory/index'; // requiring the index file explicitly import insideDirectory from './insideDirectory/index'; // requiring the index file explicitly // good import CheckBox from './CheckBox'; // PascalCase export/import/filename import fortyTwo from './fortyTwo'; // camelCase export/import/filename import insideDirectory from './insideDirectory'; // camelCase export/import/directory name/implicit "index" // ^ supports both insideDirectory.js and insideDirectory/index.js
-
23.7 默认导出(
export default
)一个函数时,函数名、文件名统一。Use camelCase when you export-default a function. Your filename should be identical to your function’s name.function makeStyleGuide() { // ... } export default makeStyleGuide;
-
23.8 当你 export 一个构造函数/类/单例/函数库对象时用 PascalCase。Use PascalCase when you export a constructor / class / singleton / function library / bare object.
const AirbnbStyleGuide = { es6: { }, }; export default AirbnbStyleGuide;
-
23.9 简称和首字母缩写应该全部大写或全部小写。Acronyms and initialisms should always be all uppercased, or all lowercased.
Why? Names are for readability, not to appease a computer algorithm.
// bad import SmsContainer from './containers/SmsContainer'; // bad const HttpRequests = [ // ... ]; // good import SMSContainer from './containers/SMSContainer'; // good const HTTPRequests = [ // ... ]; // also good const httpRequests = [ // ... ]; // best import TextMessageContainer from './containers/TextMessageContainer'; // best const requests = [ // ... ];
-
23.10 全大写字母定义用来导出的常量。You may optionally uppercase a constant only if it (1) is exported, (2) is a
const
(it can not be reassigned), and (3) the programmer can trust it (and its nested properties) to never change.Why? This is an additional tool to assist in situations where the programmer would be unsure if a variable might ever change. UPPERCASE_VARIABLES are letting the programmer know that they can trust the variable (and its properties) not to change.
- What about all
const
variables? - This is unnecessary, so uppercasing should not be used for constants within a file. It should be used for exported constants however. - What about exported objects? - Uppercase at the top level of export (e.g.
EXPORTED_OBJECT.key
) and maintain that all nested properties do not change.
// bad const PRIVATE_VARIABLE = 'should not be unnecessarily uppercased within a file'; // bad export const THING_TO_BE_CHANGED = 'should obviously not be uppercased'; // bad export let REASSIGNABLE_VARIABLE = 'do not use let with uppercase variables'; // --- // allowed but does not supply semantic value export const apiKey = 'SOMEKEY'; // better in most cases export const API_KEY = 'SOMEKEY'; // --- // bad - unnecessarily uppercases key while adding no semantic value export const MAPPING = { KEY: 'value' }; // good export const MAPPING = { key: 'value', };
- What about all
二十四、访问器 Accessors
- 24.1 不需要使用属性的访问器函数。Accessor functions for properties are not required.
-
24.2 不要使用 JavaScript 的 getters/setters,因为他们会产生副作用,并且难以测试、维护和理解。如果必要,你可以用 getVal()和 setVal() 去构建。Do not use JavaScript getters/setters as they cause unexpected side effects and are harder to test, maintain, and reason about. Instead, if you do make accessor functions, use
getVal()
andsetVal('hello')
.// bad class Dragon { get age() { // ... } set age(value) { // ... } } // good class Dragon { getAge() { // ... } setAge(value) { // ... } }
-
24.3 如果属性/方法是一个
boolean
, 请用isVal()
或hasVal()
。If the property/method is aboolean
, useisVal()
orhasVal()
.// bad if (!dragon.age()) { return false; } // good if (!dragon.hasAge()) { return false; }
-
24.4 可以用 get() 和 set() 函数,但是要保持一致。It’s okay to create
get()
andset()
functions, but be consistent.class Jedi { constructor(options = {}) { const lightsaber = options.lightsaber || 'blue'; this.set('lightsaber', lightsaber); } set(key, val) { this[key] = val; } get(key) { return this[key]; } }
二十九、标准库 Standard Library
标准库包含一些实用程序,这些实用程序在功能上已损坏,但由于遗留原因而保留。The Standard Library contains utilities that are functionally broken but remain for legacy reasons.
-
29.1 使用
Number.isNaN
代替全局isNaN
。UseNumber.isNaN
instead of globalisNaN
. (eslint:no-restricted-globals
)Why? The global
isNaN
coerces non-numbers to numbers, returning true for anything that coerces to NaN. If this behavior is desired, make it explicit.为什么?全局
isNaN
将非数字强制转换为数字,对任何强制 NaN 的东西返回 true。 如果需要此行为,请明确说明。// bad isNaN('1.2'); // false isNaN('1.2.3'); // true // good Number.isNaN('1.2.3'); // false Number.isNaN(Number('1.2.3')); // true
-
29.2 使用
Number.isFinite
代替全局isFinite
。UseNumber.isFinite
instead of globalisFinite
. *(eslint:no-restricted-globals
)
-
Why? The global
isFinite
coerces non-numbers to numbers, returning true for anything that coerces to a finite number. If this behavior is desired, make it explicit.为什么?全局将非数字强制转换为数字,对于强制为有限数字的任何内容返回 true。 如果需要此行为,请明确说明。
isFinite
// bad isFinite('2e3'); // true // good Number.isFinite('2e3'); // false Number.isFinite(parseInt('2e3', 10)); // true
三十、测试 Testing
-
30.1 Yup.
function foo() { return true; }
-
30.2 No, but seriously:
- Whichever testing framework you use, you should be writing tests!
- Strive to write many small pure functions, and minimize where mutations occur.
- Be cautious about stubs and mocks - they can make your tests more brittle.
- We primarily use
mocha
andjest
at Airbnb.tape
is also used occasionally for small, separate modules. - 100% test coverage is a good goal to strive for, even if it’s not always practical to reach it.
- Whenever you fix a bug, write a regression test. A bug fixed without a regression test is almost certainly going to break again in the future.