本规范用于指导前端开发代码规范参考
# 1 常量# 1.1 使用 const 您的所有引用的 避免使用 var。为什么?这样可以确保您不能重新分配引用,这可能导致错误和难以理解的代码。
var a = 1 var b = 2 const a = 1 const b = 2
# 1.2 如果必须重新分配引用,请使用 let 代替 var。为什么?let 是像块一样,而不是像函数一样 var。
var count = 1 if ( true ) { count += 1 } let count = 1 if ( true ) { count += 1 }
# 1.3 请注意,let 和 const 都是块范围的。{ let a = 1 const b = 1 } console. log ( a) console. log ( b)
# 2 对象 Objects# 2.1 使用文字语法进行对象创建。const item = new Object ( ) const item = { }
# 2.2 创建具有动态属性名称的对象时,请使用计算的属性名称。为什么?它们使您可以在一处定义对象的所有属性。
function getKey ( k ) { return ` a key named ${ k} ` } const obj = { id: 5 , name: 'San Francisco' , } obj[ getKey ( 'enabled' ) ] = true const obj = { id: 5 , name: 'San Francisco' , [ getKey ( 'enabled' ) ] : true , }
# 2.3 使用对象方法的简写。const atom = { value: 1 , addValue : function ( value ) { return atom. value + value } , } const atom = { value: 1 , addValue ( value ) { return atom. value + value } , }
# 2.4 使用属性值速记为什么?它简短而具有描述性。
const lukeSkywalker = 'Luke Skywalker' const obj = { lukeSkywalker: lukeSkywalker, } const obj = { lukeSkywalker, }
# 2.5 在对象声明的开头对速记属性进行分组为什么?比较容易分辨出哪些属性正在使用速记。
const anakinSkywalker = 'Anakin Skywalker' const lukeSkywalker = 'Luke Skywalker' const obj = { episodeOne: 1 , twoJediWalkIntoACantina: 2 , lukeSkywalker, episodeThree: 3 , mayTheFourth: 4 , anakinSkywalker, } const obj = { lukeSkywalker, anakinSkywalker, episodeOne: 1 , twoJediWalkIntoACantina: 2 , episodeThree: 3 , mayTheFourth: 4 , }
2.6 仅引用无效标识符的属性
为什么?总的来说,我们认为它在主观上更容易阅读。它改善了语法突出显示的功能,并且也容易被许多 JS 引擎优化。
const bad = { 'foo' : 3 , 'bar' : 4 , 'data-blah' : 5 , } const good = { foo: 3 , bar: 4 , 'data-blah' : 5 , }
# 2.7 不叫 Object.prototype 直接的方法,如 hasOwnProperty,propertyIsEnumerable 和 isPrototypeOf。为什么?这些方法可能会受到所讨论对象的属性的影响 - 考虑 {hasOwnProperty: false}- 或者该对象可能是空对象(Object.create (null))。
console. log ( object. hasOwnProperty ( key) ) console. log ( Object . prototype. hasOwnProperty . call ( object, key) ) const has = Object . prototype. hasOwnProperty console. log ( has . call ( object, key) ) import has from 'has' console. log ( has ( object, key) )
# 2.8 首选对象散布运算符,而不是 Object.assign 浅表复制对象。使用对象剩余运算符可获取省略了某些属性的新对象。const original = { a: 1 , b: 2 } const copy = Object. assign ( original, { c: 3 } ) delete copy. a const original = { a: 1 , b: 2 } const copy = Object. assign ( { } , original, { c: 3 } ) const original = { a: 1 , b: 2 } const copy = { ... original, c: 3 } const { a, ... noA } = copy
# 3 数组 Array# 3.1 使用文字语法创建数组。const items = new Array ( ) const items = [ ]
# 3.2 使用 Array#push 而不是直接分配将项目添加到数组。const someStack = [ ] someStack[ someStack. length] = 'abracadabra' someStack. push ( 'abracadabra' )
# 3.3 使用数组跨度... 复制数组。const len = items. lengthconst itemsCopy = [ ] let ifor ( i = 0 i < len i += 1 ) { itemsCopy[ i] = items[ i] } const itemsCopy = [ ... items]
# 3.4 要将可迭代对象转换为数组,请使用扩展... 而不是 Array.from。const foo = document. querySelectorAll ( '.foo' ) const nodes = Array. from ( foo) const nodes = [ ... foo]
# 3.5 使用 Array.from 用于类似阵列的对象转换为一个数组。const arrLike = { 0 : 'foo' , 1 : 'bar' , 2 : 'baz' , length: 3 } const arr = Array . prototype. slice . call ( arrLike) const arr = Array. from ( arrLike)
# 3.6 使用 Array.from 而不是扩展... 来映射可迭代对象,因为它避免了创建中间数组。const baz = [ ... foo] . map ( bar) const baz = Array. from ( foo, bar)
# 3.7 在数组方法回调中使用 return 语句。如果函数主体由返回 8.2 之后的无副作用的表达式的单个语句组成,则可以省略 return 。[ 1 , 2 , 3 ] . map ( ( x ) => { const y = x + 1 return x * y } ) [ 1 , 2 , 3 ] . map ( ( x ) => x + 1 ) [ [ 0 , 1 ] , [ 2 , 3 ] , [ 4 , 5 ] ] . reduce ( ( acc, item, index ) => { const flatten = acc. concat ( item) } ) [ [ 0 , 1 ] , [ 2 , 3 ] , [ 4 , 5 ] ] . reduce ( ( acc, item, index ) => { const flatten = acc. concat ( item) return flatten } ) inbox. filter ( ( msg ) => { const { subject, author } = msg if ( subject === 'Mockingbird' ) { return author === 'Harper Lee' } else { return false } } ) inbox. filter ( ( msg ) => { const { subject, author } = msg if ( subject === 'Mockingbird' ) { return author === 'Harper Lee' } return false } )
# 3.8 如果数组有多行,则在打开和关闭数组括号之后使用换行符。const arr = [ [ 0 , 1 ] , [ 2 , 3 ] , [ 4 , 5 ] , ] const objectInArray = [ { id: 1 , } , { id: 2 , } ] const numberInArray = [ 1 , 2 , ] const arr = [ [ 0 , 1 ] , [ 2 , 3 ] , [ 4 , 5 ] ] const objectInArray = [ { id: 1 , } , { id: 2 , } , ] const numberInArray = [ 1 , 2 , ]
# 解构 Destructuring# 4.1 在访问和使用对象的多个属性时,请使用对象分解。为什么?解构使您不必为这些属性创建临时引用。
function getFullName ( user ) { const firstName = user. firstName const lastName = user. lastName return ` ${ firstName} ${ lastName} ` } function getFullName ( user ) { const { firstName, lastName } = user return ` ${ firstName} ${ lastName} ` } function getFullName ( { firstName, lastName } ) { return ` ${ firstName} ${ lastName} ` }
# 4.2 使用数组解构。const arr = [ 1 , 2 , 3 , 4 ] const first = arr[ 0 ] const second = arr[ 1 ] const [ first, second] = arr
# 4.3 将对象分解用于多个返回值,而不是数组分解。为什么?您可以随时间添加新属性或更改事物顺序,而不会中断呼叫站点。
function processInput ( input ) { return [ left, right, top, bottom] } const [ left, __, top] = processInput ( input) function processInput ( input ) { return { left, right, top, bottom } } const { left, top } = processInput ( input)
# 5 字符串 Strings# 5.1 '' 对字符串使用单引号。const name = "Capt. Janeway" const name = ` Capt. Janeway ` const name = 'Capt. Janeway'
# 5.2 导致该行超过 100 个字符的字符串不应使用字符串连接跨多行写入。为什么?破碎的字符串很痛苦,使代码难以搜索。
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.' 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.' 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.'
# 5.3 以编程方式构建字符串时,请使用模板字符串而不是串联。为什么?模板字符串为您提供了清晰易懂的语法,并带有适当的换行符和字符串插值功能。
function sayHi ( name ) { return 'How are you, ' + name + '?' } function sayHi ( name ) { return [ 'How are you, ' , name, '?' ] . join ( ) } function sayHi ( name ) { return ` How are you, ${ name } ? ` } function sayHi ( name ) { return ` How are you, ${ name} ? ` }
# 5.4 切勿 eval () 在字符串上使用,它会打开太多漏洞。# 5.5 不要不必要地转义字符串中的字符。为什么?反斜杠会损害可读性,因此仅在必要时才应使用反斜杠。
const foo = '\'this\' \i\s \"quoted\"' const foo = '\'this\' is "quoted"' const foo = ` my name is ' ${ name} ' `
# 6 方法 Functions# 6.1 用命名函数表达式而不是函数声明。为什么?悬挂了函数声明,这意味着在文件中定义函数之前很容易 - 太容易 - 对其进行引用。这会损害可读性和可维护性。如果发现函数的定义足够大或过于复杂,以至于妨碍了对文件其余部分的理解,那么也许是时候将其提取到自己的模块中了!无论是否从包含变量中推断出名称,都不要忘记为表达式明确命名(这在现代浏览器中或使用 Babel 等编译器时通常是这种情况)。这消除了有关错误的调用堆栈的任何假设。
function foo ( ) { } const foo = function ( ) { } const short = function longUniqueMoreDescriptiveLexicalFoo ( ) { }
# 6.2 将立即调用的函数表达式包装在括号中为什么?立即调用的函数表达式是一个单元 - 将其及其包装的调用 paren 封装在 parens 中,以整洁的方式表示出来。请注意,在一个无处不在的模块的世界中,几乎不需要 IIFE。
( function ( ) { console. log ( 'Welcome to the Internet. Please follow me.' ) } ( ) )
# 6.3 从不在非功能块(声明一个函数 if,while 等等)。而是将函数分配给变量。浏览器将允许您执行此操作,但是它们都以不同的方式解释它,这是个坏消息。# 6.4 注意: ECMA-262 将 a 定义 block 为语句列表。函数声明不是语句。if ( currentUser) { function test ( ) { console. log ( 'Nope.' ) } } let testif ( currentUser) { test = ( ) => { console. log ( 'Yup.' ) } }
# 6.5 永远不要命名参数 arguments。这将优先于 arguments 分配给每个功能范围的对象。function foo ( name, options, arguments ) { } function foo ( name, options, args ) { }
# 6.6 从不使用 arguments,... 而是改用 rest 语法。为什么?... 明确说明您要提取的参数。另外,其余参数是一个实际的 Array,而不仅仅是 like 这样的 Array arguments。
function concatenateAll ( ) { const args = Array . prototype. slice . call ( arguments) return args. join ( '' ) } function concatenateAll ( ... args) { return args. join ( '' ) }
# 6.7 使用默认参数语法而不是对函数参数进行突变。function handleThings ( opts ) { opts = opts || { } } function handleThings ( opts ) { if ( opts === void 0 ) { opts = { } } } function handleThings ( opts = { } ) { }
# 6.8 避免使用默认参数的副作用。为什么?他们对此感到困惑。
var b = 1 function count ( a = b++ ) { console. log ( a) } count ( ) count ( ) count ( 3 ) count ( )
# 6.9 始终将默认参数放在最后。function handleThings ( opts = { } , name ) { } function handleThings ( name, opts = { } ) { }
# 6.10 切勿使用 Function 构造函数创建新函数。为什么?以这种方式创建函数的评估字符串类似于 eval (),这将打开漏洞。
var add = new Function ( 'a' , 'b' , 'return a + b' ) var subtract = Function ( 'a' , 'b' , 'return a - b' )
# 6.11 功能签名中的间距。为什么?一致性很好,添加或删除名称时不必添加或删除空格。
const f = function ( ) { } const g = function ( ) { } const h = function ( ) { } const x = function ( ) { } const y = function a ( ) { }
# 6.12 请勿更改参数。为什么?操纵作为参数传入的对象可能会在原始调用方中导致不必要的变量副作用。
function f1 ( obj ) { obj. key = 1 } function f2 ( obj ) { const key = Object . prototype. hasOwnProperty . call ( obj, 'key' ) ? obj. key : 1 }
# 6.13 切勿重新分配参数。为什么?重新分配参数可能会导致意外行为,尤其是在访问 arguments 对象时。它还可能导致优化问题,尤其是在 V8 中。
function f1 ( a ) { a = 1 } function f2 ( a ) { if ( ! a) { a = 1 } } function f3 ( a ) { const b = a || 1 } function f4 ( a = 1 ) { }
# 6.14 优先使用散布运算符... 来调用可变参数函数。为什么?它更干净,您无需提供上下文,也无法轻松地 new 与组合 apply。
const x = [ 1 , 2 , 3 , 4 , 5 ] console. log . apply ( console, x) const x = [ 1 , 2 , 3 , 4 , 5 ] console. log ( ... x) new ( Function . prototype. bind . apply ( Date, [ null , 2016 , 8 , 5 ] ) ) new Date ( ... [ 2016 , 8 , 5 ] )
# 6.15 具有多行签名或调用的函数应像本指南中的其他所有多行列表一样缩进:每个项目单独一行,最后一个项目后跟逗号。function foo ( bar, baz, quux) { } function foo ( bar, baz, quux, ) { } console. log ( foo, bar, baz) console. log ( foo, bar, baz, )
# 7 方法 Functions# 7.1 当您必须使用匿名函数时(如传递内联回调时),请使用箭头函数符号。为什么?它创建函数的版本,该版本在的上下文中执行,this 通常是您想要的,并且语法更简洁。
为什么不?如果您有一个相当复杂的函数,则可以将该逻辑移到它自己的命名函数表达式中。
[ 1 , 2 , 3 ] . map ( function ( x ) { const y = x + 1 return x * y } ) [ 1 , 2 , 3 ] . map ( ( x ) => { const y = x + 1 return x * y } )
# 7.2 如果函数主体由返回无副作用的表达式的单个语句组成,则省略花括号并使用隐式返回。否则,请保留括号并使用 return 语句。为什么?语法糖。将多个功能链接在一起时,它读起来很好。
[ 1 , 2 , 3 ] . map ( ( number ) => { const nextNumber = number + 1 ` A string containing the ${ nextNumber} . ` } ) [ 1 , 2 , 3 ] . map ( ( number ) => ` A string containing the ${ number + 1 } . ` ) [ 1 , 2 , 3 ] . map ( ( number ) => { const nextNumber = number + 1 return ` A string containing the ${ nextNumber} . ` } ) [ 1 , 2 , 3 ] . map ( ( number, index ) => ( { [ index] : number, } ) ) function foo ( callback ) { const val = callback ( ) if ( val === true ) { } } let bool = false foo ( ( ) => bool = true ) foo ( ( ) => { bool = true } )
# 7.3 如果表达式跨越多行,请将其括在括号中以提高可读性。为什么?它清楚地显示了函数的开始和结束位置。
[ 'get' , 'post' , 'put' ] . map ( ( httpMethod ) => Object . prototype. hasOwnProperty . call ( httpMagicObjectWithAVeryLongName, httpMethod, ) ) [ 'get' , 'post' , 'put' ] . map ( ( httpMethod ) => ( Object . prototype. hasOwnProperty . call ( httpMagicObjectWithAVeryLongName, httpMethod, ) ) )
# 7.4 为了清楚和一致起见,请始终在参数周围加上括号。为什么?添加或删除参数时,最大程度减少差异流失。
[ 1 , 2 , 3 ] . map ( x => x * x) [ 1 , 2 , 3 ] . map ( ( x ) => x * x) [ 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! ` ) ) [ 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! ` ) ) [ 1 , 2 , 3 ] . map ( x => { const y = x + 1 return x * y } ) [ 1 , 2 , 3 ] . map ( ( x ) => { const y = x + 1 return x * y } )
# 7.5 避免将箭头函数语法(=>)与比较运算符(<=,>=)混淆。const itemHeight = ( item ) => item. height <= 256 ? item. largeSize : item. smallSizeconst itemHeight = ( item ) => item. height >= 256 ? item. largeSize : item. smallSizeconst itemHeight = ( item ) => ( item. height <= 256 ? item. largeSize : item. smallSize) const itemHeight = ( item ) => { const { height, largeSize, smallSize } = item return height <= 256 ? largeSize : smallSize }
# 7.6 使用隐式返回值强制箭头函数体的位置。( foo ) => bar ( foo ) => ( bar) ( foo ) => bar ( foo ) => ( bar) ( foo ) => ( bar )
# 8 类和构造函数 Classes & Constructors# 8.1 始终使用 class。避免 prototype 直接操作。为什么?class 语法更简洁,更容易推理。
function Queue ( contents = [ ] ) { this . queue = [ ... contents] } Queue . prototype. pop = function ( ) { const value = this . queue[ 0 ] this . queue. splice ( 0 , 1 ) return value } class Queue { constructor ( contents = [ ] ) { this . queue = [ ... contents] } pop ( ) { const value = this . queue[ 0 ] this . queue. splice ( 0 , 1 ) return value } }
# 8.2 使用 extends 继承。为什么?这是一种继承原型功能而不中断的内置方法 instanceof。
const inherits = require ( 'inherits' ) function PeekableQueue ( contents ) { Queue . apply ( this , contents) } inherits ( PeekableQueue, Queue) PeekableQueue . prototype. peek = function ( ) { return this . queue[ 0 ] } class PeekableQueue extends Queue { peek ( ) { return this . queue[ 0 ] } }
# 8.3 方法可以返回 this 以帮助方法链接。Jedi . prototype. jump = function ( ) { this . jumping = true return true } Jedi . prototype. setHeight = function ( height ) { this . height = height } const luke = new Jedi ( ) luke. jump ( ) luke. setHeight ( 20 ) class Jedi { jump ( ) { this . jumping = true return this } setHeight ( height ) { this . height = height return this } } const luke = new Jedi ( ) luke. jump ( ) . setHeight ( 20 )
# 8.4 编写自定义 toString () 方法是可以的,只需确保它可以成功运行并且没有副作用。class Jedi { constructor ( options = { } ) { this . name = options. name || 'no name' } getName ( ) { return this . name } toString ( ) { return ` Jedi - ${ this . getName ( ) } ` } }
# 8.5 如果未指定类,则类具有默认构造函数。不需要空的构造函数或仅委托给父类的构造函数。class Jedi { constructor ( ) { } getName ( ) { return this . name } } class Rey extends Jedi { constructor ( ... args) { super ( ... args) } } class Rey extends Jedi { constructor ( ... args) { super ( ... args) this . name = 'Rey' } }
# 8.6 避免重复的班级成员。为什么?重复的类成员声明将默默地选择最后一个 - 几乎可以肯定,重复是一个错误。
class Foo { bar ( ) { return 1 } bar ( ) { return 2 } } class Foo { bar ( ) { return 1 } } class Foo { bar ( ) { return 2 } }
# 8.7 this 除非外部库或框架要求使用特定的非静态方法,否则应使用类方法或将其制成静态方法。作为实例方法,应表明其行为根据接收者的属性而有所不同。class Foo { bar ( ) { console. log ( 'bar' ) } } class Foo { bar ( ) { console. log ( this . bar) } } class Foo { constructor ( ) { } } class Foo { static bar ( ) { console. log ( 'bar' ) } }
# 9 Modules# 9.1 始终在非标准模块系统上使用模块(import/export)。您始终可以转换到首选的模块系统。为什么?模块是未来,让我们现在就开始使用未来。
const AirbnbStyleGuide = require ( './AirbnbStyleGuide' ) module. exports = AirbnbStyleGuide. es6 import AirbnbStyleGuide from './AirbnbStyleGuide' export default AirbnbStyleGuide. es6import { es6 } from './AirbnbStyleGuide' export default es6
# 9.2 不要使用通配符导入。为什么?这可确保您具有单个默认导出。
import * as AirbnbStyleGuide from './AirbnbStyleGuide' import AirbnbStyleGuide from './AirbnbStyleGuide'
# 9.3 请勿直接从进口货物中出口。为什么?尽管单线简明扼要,但采用一种清晰的导入方式和一种清晰的导出方式可以使事情保持一致。
export { es6 as default } from './AirbnbStyleGuide' import { es6 } from './AirbnbStyleGuide' export default es6
# 9.4 仅从一个位置的路径导入。为什么?具有从同一路径导入的多行可能会使代码难以维护。
import foo from 'foo' import { named1, named2 } from 'foo' import foo, { named1, named2 } from 'foo' import foo, { named1, named2, } from 'foo'
# 9.5 不要导出可变绑定。W 为什么?通常应避免突变,尤其是在导出可变绑定时。尽管在某些特殊情况下可能需要使用此技术,但通常只应导出常量引用。
let foo = 3 export { foo } const foo = 3 export { foo }
# 9.6 在具有单个导出功能的模块中,优先使用默认导出而不是命名导出。为什么?鼓励更多只导出一件事情的文件,这对于可读性和可维护性来说更好。
export function foo ( ) { } export default function foo ( ) { }
# 9.7 将所有 imports 放在非导入语句之上。为什么?由于 imports 被吊起,因此将它们全部保持在顶部可防止出现意外行为。
import foo from 'foo' foo. init ( ) import bar from 'bar' import foo from 'foo' import bar from 'bar' foo. init ( )
# 9.8 多行导入应像多行数组和对象文字一样缩进。为什么?花括号与样式指南中的每个其他花括号块遵循相同的缩进规则,尾随逗号也是如此。
import { longNameA, longNameB, longNameC, longNameD, longNameE} from 'path' import { longNameA, longNameB, longNameC, longNameD, longNameE, } from 'path'
# 9.9 在模块 import 语句中禁止 Webpack loader 语法。为什么?由于在导入中使用 Webpack 语法,因此会将代码耦合到模块捆绑器。最好在中使用 loader 语法 webpack.config.js。
import fooSass from 'css!sass!foo.scss' import barCss from 'style!css!bar.css' import fooSass from 'foo.scss' import barCss from 'bar.css'
# 9.10 不要包括 eslint JavaScript 文件扩展名:import/extensions为什么?包括扩展将阻止重构,并在每个使用者中不适当地对要导入的模块的实现细节进行硬编码。
import foo from './foo.js' import bar from './bar.jsx' import baz from './baz/index.jsx' import foo from './foo' import bar from './bar' import baz from './baz'
# 10 迭代器和生成器 Iterators and Generators# 10.1 不要使用迭代器。更喜欢 JavaScript 的高阶函数,而不是像 for-in 或那样的循环 for-of。为什么?这执行了我们不变的规则。处理返回值的纯函数比副作用更容易推论。
使用 map ()/every ()/filter ()/find ()/findIndex ()/reduce ()/some ()/... ... 遍历数组,和 Object.keys ()/ Object.values ()/ Object.entries () 产生数组,以便可以遍历对象。
const numbers = [ 1 , 2 , 3 , 4 , 5 ] let sum = 0 for ( let num of numbers) { sum += num } sum === 15 let sum = 0 numbers. forEach ( ( num ) => { sum += num } ) sum === 15 const sum = numbers. reduce ( ( total, num ) => total + num, 0 ) sum === 15 const increasedByOne = [ ] for ( let i = 0 i < numbers. length i++ ) { increasedByOne. push ( numbers[ i] + 1 ) } const increasedByOne = [ ] numbers. forEach ( ( num ) => { increasedByOne. push ( num + 1 ) } ) const increasedByOne = numbers. map ( ( num ) => num + 1 )
# 10.2 现在不要使用生成器。为什么?它们不能很好地移植到 ES5。
# 10.3 如果必须使用生成器,或者不考虑我们的建议,请确保生成器的功能签名间距适当。为什么?function 并且 * 属于相同概念关键字的一部分 - 不是的修饰语 function,function 是唯一的构造,不同于 function。
function * foo ( ) { } const bar = function * ( ) { } const baz = function * ( ) { } const quux = function * ( ) { } function * foo ( ) { } function * foo ( ) { } function * foo ( ) { } const wat = function * ( ) { } function * foo ( ) { } const foo = function * ( ) { }
# 11 属性 Properties# 11.1 访问属性时,请使用点符号。const luke = { jedi: true , age: 28 , } const isJedi = luke[ 'jedi' ] const isJedi = luke. jedi
# 11.2 使用 [] 变量访问属性时,请使用方括号表示法。const luke = { jedi: true , age: 28 , } function getProp ( prop ) { return luke[ prop] } const isJedi = getProp ( 'jedi' )
# 11.3 ** 计算指数时,请使用指数运算符。const binary = Math. pow ( 2 , 10 ) const binary = 2 ** 10
# 12 变量 Variables# 12.1 始终使用 const 或 let 声明变量。不这样做将导致全局变量。我们要避免污染全局名称空间。星球船长警告过我们。superPower = new SuperPower ( ) const superPower = new SuperPower ( )
# 12.2 每个变量或赋值使用一个 const 或 let 声明。为什么?通过这种方式添加新的变量声明更加容易,而且您不必担心将 a 换成;a , 或引入仅标点符号的 diff。您也可以使用调试器逐步执行每个声明,而不是一次跳过所有声明。
const items = getItems ( ) , goSportsTeam = true , dragonball = 'z' const items = getItems ( ) , goSportsTeam = true dragonball = 'z' const items = getItems ( ) const goSportsTeam = true const dragonball = 'z'
# 12.3 将所有 consts 分组,然后将所有 lets 分组。为什么?以后您可能需要根据先前分配的变量之一分配变量时,这很有用。
let i, len, dragonball, items = getItems ( ) , goSportsTeam = true let iconst items = getItems ( ) let dragonballconst goSportsTeam = true let lenconst goSportsTeam = true const items = getItems ( ) let dragonballlet ilet length
# 12.4 在需要的地方分配变量,但将其放置在合理的位置。为什么?let 并且 const 是块作用域而不是函数作用域。
function checkName ( hasName ) { const name = getName ( ) if ( hasName === 'test' ) { return false } if ( name === 'test' ) { this . setName ( '' ) return false } return name } function checkName ( hasName ) { if ( hasName === 'test' ) { return false } const name = getName ( ) if ( name === 'test' ) { this . setName ( '' ) return false } return name }
# 12.5 不要链接变量分配。为什么?链接变量分配会创建隐式全局变量。
( function example ( ) { let a = b = c = 1 } ( ) ) console. log ( a) console. log ( b) console. log ( c) ( function example ( ) { let a = 1 let b = a let c = a } ( ) ) console. log ( a) console. log ( b) console. log ( c)
# 12.6 避免使用一元增减(++,--)。为什么?根据 eslint 文档,一元增量和减量语句会自动插入分号,并且会因应用程序中的值增减而导致静默错误。使用诸如 num += 1 而不是 num++ 或的语句来改变您的值也更具表现力 num ++。禁止一元增量和减量语句还可以防止无意中对值进行预增 / 预减,这也可能导致程序出现意外行为。
const array = [ 1 , 2 , 3 ] let num = 1 num++ -- numlet sum = 0 let truthyCount = 0 for ( let i = 0 i < array. length i++ ) { let value = array[ i] sum += value if ( value) { truthyCount++ } } const array = [ 1 , 2 , 3 ] let num = 1 num += 1 num -= 1 const sum = array. reduce ( ( a, b ) => a + b, 0 ) const truthyCount = array. filter ( Boolean) . length
# 12.7 = 在作业之前或之后避免换行。如果您的分配违反 max-len,则将值括在括号中。为什么?周围的换行符 = 可能会使分配的值变得模糊。
const foo = superLongLongLongLongLongLongLongLongFunctionName ( ) const foo = 'superLongLongLongLongLongLongLongLongString' const foo = ( superLongLongLongLongLongLongLongLongFunctionName ( ) ) const foo = 'superLongLongLongLongLongLongLongLongString'
# 12.8 禁止使用未使用的变量。为什么?由于重构不完全,在代码中任何地方声明并没有使用的变量很可能是错误。这样的变量会占用代码中的空间,并可能引起读者的困惑。
var some_unused_var = 42 var y = 10 y = 5 var z = 0 z = z + 1 function getX ( x, y ) { return x } function getXPlusY ( x, y ) { return x + y } var x = 1 var y = a + 2 alert ( getXPlusY ( x, y) ) var { type, ... coords } = data
# 13 Hoisting# 13.1 var 声明被提升到最接近的封闭函数范围的顶部,而不是赋值。const 和 let 声明被赋予一个所谓的新概念颞盲区(TDZ) 。重要的是要知道为什么 typeof 不再安全。function example ( ) { console. log ( notDefined) } function example ( ) { console. log ( declaredButNotAssigned) var declaredButNotAssigned = true } function example ( ) { let declaredButNotAssigned console. log ( declaredButNotAssigned) declaredButNotAssigned = true } function example ( ) { console. log ( declaredButNotAssigned) console. log ( typeof declaredButNotAssigned) const declaredButNotAssigned = true }
# 13.2 匿名函数表达式将提升其变量名,而不是函数赋值。function example ( ) { console. log ( anonymous) anonymous ( ) var anonymous = function ( ) { console. log ( 'anonymous function expression' ) } }
# 13.3 命名函数表达式将提升变量名,而不是函数名或函数体。function example ( ) { console. log ( named) named ( ) superPower ( ) var named = function superPower ( ) { console. log ( 'Flying' ) } } function example ( ) { console. log ( named) named ( ) var named = function named ( ) { console. log ( 'named' ) } }
# 13.4 函数声明将提升其名称和函数主体。function example ( ) { superPower ( ) function superPower ( ) { console. log ( 'Flying' ) } }
# 14 Comparison Operators & Equality# 14.1 使用 === 和! 过度 和!=。# 14.2 条件语句(例如,if 语句)使用 ToBoolean 抽象方法强制使用强制表达式来评估其表达式,并始终遵循以下简单规则:对象评估为 true 未定义的结果为 false 空评估为假 布尔值的取值为布尔值 如果 + 0,-0 或 NaN,则数字的计算结果为 false,否则为 true 如果为空字符串,则字符串评估为 false'',否则为 true # 14.3 将快捷方式用于布尔值,但对字符串和数字进行显式比较。if ( isValid === true ) { } if ( isValid) { } if ( name) { } if ( name !== '' ) { } if ( collection. length) { } if ( collection. length > 0 ) { }
# 14.4 使用大括号来创建块 case 和 default 包含词汇声明条款(例如 let,const,function,和 class)。为什么?词法声明在整个 switch 块中都是可见的,但是只有在分配时才进行初始化,只有在 case 到达时才进行初始化。当多个 case 子句尝试定义同一事物时,这会导致问题。
switch ( foo) { case 1 : let x = 1 break case 2 : const y = 2 break case 3 : function f ( ) { } break default : class C { } } switch ( foo) { case 1 : { let x = 1 break } case 2 : { const y = 2 break } case 3 : { function f ( ) { } break } case 4 : bar ( ) break default : { class C { } } }
# 14.5 三元数不应嵌套,并且通常是单行表达式。const foo = maybe1 > maybe2 ? "bar" : value1 > value2 ? "baz" : null const maybeNull = value1 > value2 ? 'baz' : null const foo = maybe1 > maybe2 ? 'bar' : maybeNull const foo = maybe1 > maybe2 ? 'bar' : maybeNull
# 14.6 避免不必要的三元语句。const foo = a ? a : bconst bar = c ? true : false const baz = c ? false : true const foo = a || bconst bar = ! ! cconst baz = ! c
# 14.7 混合运算符时,请将其括在括号中。唯一的例外是标准的算术运算符:+,-,和 ** 因为它们的优先级被广义地理解。我们建议将括起来 / 并 * 放在括号中,因为当它们混合使用时,它们的优先级可能会模棱两可。为什么?这提高了可读性并阐明了开发人员的意图。
const foo = a && b < 0 || c > 0 || d + 1 === 0 const bar = a ** b - 5 % dif ( a || b && c) { return d } const bar = a + b / c * dconst foo = ( a && b < 0 ) || c > 0 || ( d + 1 === 0 ) const bar = a ** b - ( 5 % d) if ( a || ( b && c) ) { return d } const bar = a + ( b / c) * d
# 15 Blocks# 15.1 将括号与所有多行块一起使用。if ( test) return false if ( test) return false if ( test) { return false } function foo ( ) { return false } function bar ( ) { return false }
# 15.2 如果您使用带有 if 和的多行块,请与该块的右括号 else 放在 else 同一行 if。if ( test) { thing1 ( ) thing2 ( ) } else { thing3 ( ) } if ( test) { thing1 ( ) thing2 ( ) } else { thing3 ( ) }
# 15.3 如果某个 if 块始终执行一条 return 语句,else 则不需要随后的块。甲 return 在 else if 块中的以下 if 一个包含块 return 可以被分成多个 if 块。function foo ( ) { if ( x) { return x } else { return y } } function cats ( ) { if ( x) { return x } else if ( y) { return y } } function dogs ( ) { if ( x) { return x } else { if ( y) { return y } } } function foo ( ) { if ( x) { return x } return y } function cats ( ) { if ( x) { return x } if ( y) { return y } } function dogs ( x ) { if ( x) { if ( z) { return y } } else { return z } }
# 16 Control Statements# 16.1 如果您的控制语句(if,while 等)过长或超过最大行长,则可以将每个(分组的)条件放到新行中。逻辑运算符应从此行开始。为什么?在行的开头要求运算符使运算符保持对齐并遵循类似于方法链接的模式。通过更轻松地从视觉上遵循复杂的逻辑,这也提高了可读性。
if ( ( foo === 123 || bar === 'abc' ) && doesItLookGoodWhenItBecomesThatLong ( ) && isThisReallyHappening ( ) ) { thing1 ( ) } if ( foo === 123 && bar === 'abc' ) { thing1 ( ) } if ( foo === 123 && bar === 'abc' ) { thing1 ( ) } if ( foo === 123 && bar === 'abc' ) { thing1 ( ) } if ( foo === 123 && bar === 'abc' ) { thing1 ( ) } if ( ( foo === 123 || bar === 'abc' ) && doesItLookGoodWhenItBecomesThatLong ( ) && isThisReallyHappening ( ) ) { thing1 ( ) } if ( foo === 123 && bar === 'abc' ) { thing1 ( ) }
# 16.2 不要使用选择运算符代替控制语句。! isRunning && startRunning ( ) if ( ! isRunning) { startRunning ( ) }
# 17.1 使用 /** ... */ 的多行注释。function make ( tag ) { return element } * make() returns a new element * based on the passed-in tag name */ function make ( tag ) { return element }
# 17.2 使用 // 的单行注释。将单行注释放在注释主题上方的换行符上。除非注释位于块的第一行,否则在注释之前放置一个空行。const active = true const active = true function getType ( ) { console. log ( 'fetching type...' ) const type = this . type || 'no type' return type } function getType ( ) { console. log ( 'fetching type...' ) const type = this . type || 'no type' return type } function getType ( ) { const type = this . type || 'no type' return type }
# 17.3 在所有注释的开头加一个空格,以使其易于阅读。const active = true const active = true *make() returns a new element *based on the passed-in tag name */ function make ( tag ) { return element } * make() returns a new element * based on the passed-in tag name */ function make ( tag ) { return element }
# 17.5 使用 // FIXME: 注释的问题。class Calculator extends Abacus { constructor ( ) { super ( ) total = 0 } }
# 17.6 使用 // TODO: 注释解决问题的办法。class Calculator extends Abacus { constructor ( ) { super ( ) this . total = 0 } }
# 18 空格 Whitespace# 18.1 使用设置为 2 个空格的软标签(空格字符)。function foo ( ) { ∙∙∙∙let name } function bar ( ) { ∙let name } function baz ( ) { ∙∙let name }
# 18.2 在前支架之前放置 1 个空格。function test ( ) { console. log ( 'test' ) } function test ( ) { console. log ( 'test' ) } dog. set ( 'attr' , { age: '1 year' , breed: 'Bernese Mountain Dog' , } ) dog. set ( 'attr' , { age: '1 year' , breed: 'Bernese Mountain Dog' , } )
# 18.3 在控制语句(if,while 等)中,在圆括号前放置 1 个空格。在函数调用和声明中,参数列表和函数名称之间不能留空格。if ( isJedi) { fight ( ) } if ( isJedi) { fight ( ) } function fight ( ) { console. log ( 'Swooosh!' ) } function fight ( ) { console. log ( 'Swooosh!' ) }
# 18.4 用空格隔开运算符。const x= y+ 5 const x = y + 5
# 18.5 使用单个换行符结束文件。import { es6 } from './AirbnbStyleGuide' export default es6import { es6 } from './AirbnbStyleGuide' export default es6↵↵ import { es6 } from './AirbnbStyleGuide' export default es6↵
# 18.6 制作较长的方法链(两个以上的方法链)时,请使用缩进。使用前导点,强调该行是方法调用,而不是新语句。$ ( '#items' ) . find ( '.selected' ) . highlight ( ) . end ( ) . find ( '.open' ) . updateCount ( ) $ ( '#items' ) . find ( '.selected' ) . highlight ( ) . end ( ) . find ( '.open' ) . updateCount ( ) $ ( '#items' ) . find ( '.selected' ) . highlight ( ) . end ( ) . find ( '.open' ) . updateCount ( ) 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) 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) const leds = stage. selectAll ( '.led' ) . data ( data)
# 18.7 在块之后和下一条语句之前保留空白行。if ( foo) { return bar } return bazif ( foo) { return bar } return bazconst obj = { foo ( ) { } , bar ( ) { } , } return objconst obj = { foo ( ) { } , bar ( ) { } , } return objconst arr = [ function foo ( ) { } , function bar ( ) { } , ] return arrconst arr = [ function foo ( ) { } , function bar ( ) { } , ] return arr
# 18.8 不要用空行填充块。function bar ( ) { console. log ( foo) } if ( baz) { console. log ( qux) } else { console. log ( foo) } class Foo { constructor ( bar ) { this . bar = bar } } function bar ( ) { console. log ( foo) } if ( baz) { console. log ( qux) } else { console. log ( foo) }
# 18.9 请勿使用多个空行来填充代码。class Person { constructor ( fullName, email, birthday ) { this . fullName = fullName this . email = email this . setAge ( birthday) } setAge ( birthday ) { const today = new Date ( ) const age = this . getAge ( today, birthday) this . age = age } getAge ( today, birthday ) { } } class Person { constructor ( fullName, email, birthday ) { this . fullName = fullName this . email = email this . setAge ( birthday) } setAge ( birthday ) { const today = new Date ( ) const age = getAge ( today, birthday) this . age = age } getAge ( today, birthday ) { } }
# 18.10 请勿在括号内添加空格。function bar ( foo ) { return foo } function bar ( foo ) { return foo } if ( foo ) { console. log ( foo) } if ( foo) { console. log ( foo) }
# 18.11 请勿在方括号内添加空格。const foo = [ 1 , 2 , 3 ] console. log ( foo[ 0 ] ) const foo = [ 1 , 2 , 3 ] console. log ( foo[ 0 ] )
# 18.12 在花括号内添加空格。const foo = { clark: 'kent' } const foo = { clark: 'kent' }
# 18.13 避免使用超过 100 个字符(包括空格)的代码行。注意:根据上述规定,长字符串不受此规则约束,并且不应分解。为什么?这确保了可读性和可维护性。
const foo = jsonData && jsonData. foo && jsonData. foo. bar && jsonData. foo. bar. baz && jsonData. foo. bar. baz. quux && jsonData. foo. bar. baz. quux. xyzzy$. ajax ( { method: 'POST' , url: 'https://airbnb.com/' , data: { name: 'John' } } ) . done ( ( ) => console. log ( 'Congratulations!' ) ) . fail ( ( ) => console. log ( 'You have failed this city.' ) ) const foo = jsonData && jsonData. foo && jsonData. foo. bar && jsonData. foo. bar. baz && jsonData. foo. bar. baz. quux && jsonData. foo. bar. baz. quux. xyzzy $. ajax ( { method: 'POST' , url: 'https://airbnb.com/' , data: { name: 'John' } , } ) . done ( ( ) => console. log ( 'Congratulations!' ) ) . fail ( ( ) => console. log ( 'You have failed this city.' ) )
# 18.14 在同一行中的一个打开的块令牌和下一个令牌之间,要求保持一致的间距。该规则还强制在同一行上的封闭块令牌和先前令牌内保持一致的间距。function foo ( ) { return true } if ( foo) { bar = 0 } function foo ( ) { return true } if ( foo) { bar = 0 }
# 18.15 避免在逗号前加空格,并在逗号后加空格。```javascript` // bad var foo = 1,bar = 2 var arr = [1 , 2]
// good var foo = 1, bar = 2 var arr = [1, 2]
## 18.16 在计算的属性括号内强制使用间距。
```javascript
// bad
obj[foo ]
obj[ 'foo']
var x = {[ b ]: a}
obj[foo[ bar ]]
// good
obj[foo]
obj['foo']
var x = { [b]: a }
obj[foo[bar]]
# 18.17 避免在函数及其调用之间留空格。# 18.18 强制在对象文字属性中的键和值之间保持间距。var obj = { foo : 42 } var obj2 = { foo: 42 } var obj = { foo: 42 }
# 18.19 避免在行尾使用空格。# 18.20 避免出现多个空行,仅在文件末尾允许一个换行符,并在文件开始时避免换行符。var x = 1 var y = 2 var x = 1 var y = 2 var x = 1 var y = 2 var x = 1 var y = 2
# 19 逗号 Commas# 19.1 主要逗号:Nope。const story = [ once , upon , aTime ] const story = [ once, upon, aTime, ] const hero = { firstName: 'Ada' , lastName: 'Lovelace' , birthYear: 1815 , superPower: 'computers' } const hero = { firstName: 'Ada' , lastName: 'Lovelace' , birthYear: 1815 , superPower: 'computers' , }
# 19.2 其他尾随逗号: Yup。为什么?这将导致更干净的 git diff。同样,像 Babel 这样的编译器也将删除已编译代码中的其他尾部逗号,这意味着您不必担心传统浏览器中的尾部逗号问题 。
const hero = { firstName: 'Florence' , - lastName: 'Nightingale' + lastName: 'Nightingale' , + inventorOf: [ 'coxcomb chart' , 'modern nursing' ] } const hero = { firstName: 'Florence' , lastName: 'Nightingale' , + inventorOf: [ 'coxcomb chart' , 'modern nursing' ] , } const hero = { firstName: 'Dana' , lastName: 'Scully' } const heroes = [ 'Batman' , 'Superman' ] const hero = { firstName: 'Dana' , lastName: 'Scully' , } const heroes = [ 'Batman' , 'Superman' , ] function createHero ( firstName, lastName, inventorOf ) { } function createHero ( firstName, lastName, inventorOf, ) { } function createHero ( firstName, lastName, inventorOf, ... heroArgs ) { } createHero ( firstName, lastName, inventorOf ) createHero ( firstName, lastName, inventorOf, ) createHero ( firstName, lastName, inventorOf, ... heroArgs )
# 20 分号 Semicolons# 20.1 Yup。为什么?当 JavaScript 遇到没有分号的换行符时,它将使用称为自动分号插入的一组规则来确定是否应将该换行符视为语句的结尾,并(如其名称所示)将分号放入您的如果这样的话,在换行符之前输入代码。但是,ASI 包含一些异常行为,如果 JavaScript 错误地解释了换行符,则代码将中断。随着新功能成为 JavaScript 的一部分,这些规则将变得更加复杂。明确终止您的语句并配置短毛猫以捕获缺少的分号将有助于防止您遇到问题。
const luke = { } const leia = { } [ luke, leia] . forEach ( ( jedi ) => jedi. father = 'vader' ) const reaction = "No! That’s impossible!" ( async function meanwhileOnTheFalcon ( ) { } ( ) ) function foo ( ) { return 'search your feelings, you know it to be foo' } const luke = { } const leia = { } [ luke, leia] . forEach ( ( jedi ) => { jedi. father = 'vader' } ) const reaction = "No! That’s impossible!" ( async function meanwhileOnTheFalcon ( ) { } ( ) ) function foo ( ) { return 'search your feelings, you know it to be foo' } Read more.
# 21 Type Casting & Coercion# 21.1 在语句的开头执行类型强制。# 21.2 字符串 Stringsconst totalScore = new String ( this . reviewScore) const totalScore = this . reviewScore + '' const totalScore = this . reviewScore. toString ( ) const totalScore = String ( this . reviewScore)
# 21.3 数字:Number 用于类型转换,并且 parseInt 始终使用基数来解析字符串。const inputValue = '4' const val = new Number ( inputValue) const val = + inputValueconst val = inputValue >> 0 const val = parseInt ( inputValue) const val = Number ( inputValue) const val = parseInt ( inputValue, 10 )
# 21.4 如果出于某种原因您正在做一些疯狂的事情,并且 parseInt 是瓶颈,并且出于性能原因而需要使用 Bitshift ,请在注释中说明原因和原因。 * 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
# 21.5 注意:使用位移操作时要小心。数字表示为 64 位值,但是位移位操作始终返回 32 位整数(source)。对于大于 32 位的整数,位移位会导致意外的行为。讨论。最大的有符号 32 位 Int 是 2,147,483,647:2147483647 >> 0 2147483648 >> 0 2147483649 >> 0
# 21.6 布尔值const age = 0 const hasAge = new Boolean ( age) const hasAge = Boolean ( age) const hasAge = ! ! age
# 22 命名约定 Naming Conventions# 22.1 避免使用单个字母名称。用您的命名来描述。function q ( ) { } function query ( ) { }
# 22.2 在命名对象,函数和实例时,请使用 camelCase。const OBJEcttsssss = { } const this_is_my_object = { } function c ( ) { } const thisIsMyObject = { } function thisIsMyFunction ( ) { }
# 22.3 仅在命名构造函数或类时使用 PascalCase。function user ( options ) { this . name = options. name } const bad = new user ( { name: 'nope' , } ) class User { constructor ( options ) { this . name = options. name } } const good = new User ( { name: 'yup' , } )
# 22.4 请勿使用下划线或前划线。为什么?JavaScript 在属性或方法方面没有隐私的概念。尽管下划线是表示 “私有” 的通用约定,但实际上,这些属性是完全公开的,因此是您的公共 API 合同的一部分。该约定可能导致开发人员错误地认为更改不会被视为破坏或不需要测试。tl; dr:如果您希望某些东西是 “私有的”,那么它一定不能明显地存在。
this . __firstName__ = 'Panda' this . firstName_ = 'Panda' this . _firstName = 'Panda' this . firstName = 'Panda' const firstNames = new WeakMap ( ) firstNames. set ( this , 'Panda' )
# 22.5 不要保存对的引用 this。使用箭头函数或 Function#bind。function foo ( ) { const self = this return function ( ) { console. log ( self) } } function foo ( ) { const that = this return function ( ) { console. log ( that) } } function foo ( ) { return ( ) => { console. log ( this ) } }
# 22.6 基本文件名应与默认导出文件名完全匹配。class CheckBox { } export default CheckBoxexport default function fortyTwo ( ) { return 42 } export default function insideDirectory ( ) { } import CheckBox from './checkBox' import FortyTwo from './FortyTwo' import InsideDirectory from './InsideDirectory' import CheckBox from './check_box' import forty_two from './forty_two' import inside_directory from './inside_directory' import index from './inside_directory/index' import insideDirectory from './insideDirectory/index' import CheckBox from './CheckBox' import fortyTwo from './fortyTwo' import insideDirectory from './insideDirectory'
# 22.7 导出默认功能时,请使用 camelCase。文件名应与函数名称相同。function makeStyleGuide ( ) { } export default makeStyleGuide
# 22.8 在导出构造函数 / 类 / 单例 / 函数库 / 裸对象时使用 PascalCase。const AirbnbStyleGuide = { es6: { } , } export default AirbnbStyleGuide
# 22.9 首字母缩写词和首字母缩写应始终全部大写或全部小写。为什么?名称是为了提高可读性,而不是为了安抚计算机算法。
import SmsContainer from './containers/SmsContainer' const HttpRequests = [ ] import SMSContainer from './containers/SMSContainer' const HTTPRequests = [ ] const httpRequests = [ ] import TextMessageContainer from './containers/TextMessageContainer' const requests = [ ]
# 22.10 您可以选择仅在以下情况下将常量大写:(1)已导出,(2)是一个 const(不能重新分配),并且(3)程序员可以相信它(及其嵌套属性)永不更改。为什么?这是一个辅助工具,可在程序员不确定变量是否会发生变化的情况下提供帮助。UPPERCASE_VARIABLES 让程序员知道他们可以信任变量(及其属性)不变。
那所有 const 变量呢?- 这是不必要的,因此大写不应用于文件中的常量。但是,应将其用于导出的常量。 导出的对象呢?- 在导出的顶层使用大写字母(例如 EXPORTED_OBJECT.key),并保持所有嵌套属性不变。 const PRIVATE_VARIABLE = 'should not be unnecessarily uppercased within a file' export const THING_TO_BE_CHANGED = 'should obviously not be uppercased' export let REASSIGNABLE_VARIABLE = 'do not use let with uppercase variables' export const apiKey = 'SOMEKEY' export const API_KEY = 'SOMEKEY' export const MAPPING = { KEY : 'value' } export const MAPPING = { key: 'value' }
# 23 存取器 Accessors# 23.1 不需要属性的访问器功能。# 23.2 请勿使用 JavaScript getter /setter,因为它们会导致意外的副作用,并且更难以测试,维护和推论。相反,如果您确实使访问器函数,请使用 getVal () 和 setVal ('hello')。class Dragon { get age ( ) { } set age ( value ) { } } class Dragon { getAge ( ) { } setAge ( value ) { } }
# 23.3 如果属性 / 方法是 a boolean,请使用 isVal () 或 hasVal ()。if ( ! dragon. age ( ) ) { return false } 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 Events# 24.1 在将数据有效负载附加到事件(无论是 DOM 事件还是诸如 Backbone 事件之类的更专有的东西)时,请传递对象文字(也称为 “哈希”)而不是原始值。这允许后续的参与者将更多数据添加到事件有效负载,而无需查找和更新事件的每个处理程序。例如,instead of$ ( this ) . trigger ( 'listingUpdated' , listing. id) $ ( this ) . on ( 'listingUpdated' , ( e, listingID ) => { } ) prefer: $ ( this ) . trigger ( 'listingUpdated' , { listingID: listing. id } ) $ ( this ) . on ( 'listingUpdated' , ( e, data ) => { } )
# 25 jQuery# 25.1 用前缀 jQuery 对象变量 $。const sidebar = $ ( '.sidebar' ) const $sidebar = $ ( '.sidebar' ) const $sidebarBtn = $ ( '.sidebar-btn' )
# 25.2 缓存 jQuery 查询。function setSidebar ( ) { $ ( '.sidebar' ) . hide ( ) $ ( '.sidebar' ) . css ( { 'background-color' : 'pink' , } ) } function setSidebar ( ) { const $sidebar = $ ( '.sidebar' ) $sidebar. hide ( ) $sidebar. css ( { 'background-color' : 'pink' , } ) }
# 25.4 使用 find 与范围的 jQuery 对象的查询。$ ( 'ul' , '.sidebar' ) . hide ( ) $ ( '.sidebar' ) . find ( 'ul' ) . hide ( ) $ ( '.sidebar ul' ) . hide ( ) $ ( '.sidebar > ul' ) . hide ( ) $sidebar. find ( 'ul' ) . hide ( )
# 26 ECMAScript 5 兼容性 ECMAScript 5 Compatibility# 26.1 请参阅 Kangax 的 ES5 兼容性表 。# 27 Standard Library该标准库 包含了实用程序在功能上打破,但仍遗留原因。
# 27.1 使用 Number.isNaN 代替 global isNaN。为什么?全局将 isNaN 非数字强制转换为数字,对于任何强制为 NaN 的值,返回 true。如果需要此行为,请使其明确。
isNaN ( '1.2' ) isNaN ( '1.2.3' ) Number. isNaN ( '1.2.3' ) Number. isNaN ( Number ( '1.2.3' ) )
# 27.2 使用 Number.isFinite 而不是 global isFinite。为什么?全局将 isFinite 非数字强制为数字,对于任何强制为有限数字的值,都返回 true。如果需要此行为,请使其明确。
isFinite ( '2e3' ) Number. isFinite ( '2e3' ) Number. isFinite ( parseInt ( '2e3' , 10 ) )