提交 7e49c041930f27d09f9ae411293869eec80973db

作者 juvenile
0 个父辈

修改

正在显示 2 个修改的文件 包含 3618 行增加0 行删除
  1 +# 代码规范
  2 +
  3 +## HTML 规范-代码规范
  4 +
  5 +### DOCTYPE 设置
  6 +
  7 +文档类型统一使用 html5 的 doctype:
  8 +
  9 +```html
  10 +<!DOCTYPE html>
  11 +```
  12 +
  13 +### 页面编码
  14 +
  15 +编码默认使用 UTF-8,特定情况下有指定要求也可以是 GBK
  16 +
  17 +```html
  18 +<meta charset="GBK" />
  19 +```
  20 +
  21 +```html
  22 +<meta charset="UTF-8" />
  23 +```
  24 +
  25 +请尽量统一写成标准的 “UTF-8”,不要写成 “utf-8” 或 “utf8” 或 “UTF8”。根据 IETF 对 UTF-8 的定义,其编码标准的写法是 “UTF-8”;而 UTF8 或 utf8 的写法只是出现在某些编程系统中,如 .NET framework 的类 System.Text.Encoding 中的一个属性名就叫 UTF8。
  26 +
  27 +### TDK
  28 +
  29 +#### 页面标题(Title)
  30 +
  31 +页面名称-产品中文全称-官方网站-产品 slogan,28 个汉字以内
  32 +
  33 +```html
  34 +<title>前端-代码规范-小爱</title>
  35 +```
  36 +
  37 +#### 页面关键字(Keywords)
  38 +
  39 +Keywords 为产品名、专题名、专题相关名词,之间用英文半角逗号隔开
  40 +
  41 +```html
  42 +<meta name="keywords" content="前端代码规范文档" />
  43 +```
  44 +
  45 +#### 页面描述(Description)
  46 +
  47 +不超过 150 个字符,描述内容要和页面内容相关。
  48 +
  49 +```html
  50 +<meta name="description" content="前端代码规范文档" />
  51 +```
  52 +
  53 +### 页面 Meta
  54 +
  55 +PC 端 Meta:
  56 +
  57 +```html
  58 +<meta charset="gbk" />
  59 +<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
  60 +<meta name="robots" content="all" />
  61 +<meta name="author" content="Tencent-CP" />
  62 +<meta name="Copyright" content="Tencent" />
  63 +<meta name="Description" content="页面的描述内容" />
  64 +<meta name="Keywords" content="页面关键字" />
  65 +```
  66 +
  67 +移动端 Meta:
  68 +
  69 +```html
  70 +<meta charset="gbk" />
  71 +<meta
  72 + name="viewport"
  73 + content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"
  74 +/>
  75 +<!-- 为了防止页面数字被识别为电话号码,可根据实际需要添加: -->
  76 +<meta name="format-detection" content="telephone=no" />
  77 +<!-- 让添加到主屏幕的网页再次打开时全屏展示,可添加: -->
  78 +<meta content="yes" name="mobile-web-app-capable" />
  79 +<meta content="yes" name="apple-mobile-web-app-capable" />
  80 +<meta name="robots" content="all" />
  81 +<meta name="author" content="Tencent-CP" />
  82 +<meta name="Copyright" content="Tencent" />
  83 +<meta name="Description" content="页面的描述内容" />
  84 +<meta name="Keywords" content="页面关键字" />
  85 +```
  86 +
  87 +### 元素及标签闭合
  88 +
  89 +HTML 元素共有以下 5 种:
  90 +
  91 +- 空元素:area、base、br、col、command、embed、hr、img、input、keygen、link、meta、param、source、track、wbr
  92 +- 原始文本元素:script、style
  93 +- RCDATA 元素:textarea、title
  94 +- 外来元素:来自 MathML 命名空间和 SVG 命名空间的元素。
  95 +- 常规元素:其他 HTML 允许的元素都称为常规元素。
  96 +
  97 +元素标签的闭合应遵循以下原则:
  98 +
  99 +> Tags are used to delimit the start and end of elements in the markup. Raw text, escapable raw text, and normal elements have a start tag to indicate where they begin, and an end tag to indicate where they end. The start and end tags of certain normal elements can be omitted, as described below in the section on optional tags. Those that cannot be omitted must not be omitted. Void elements only have a start tag; end tags must not be specified for void elements. Foreign elements must either have a start tag and an end tag, or a start tag that is marked as self-closing, in which case they must not have an end tag.
  100 +
  101 +- 原始文本元素、RCDATA 元素以及常规元素都有一个开始标签来表示开始,一个结束标签来表示结束。
  102 +- 某些元素的开始和结束标签是可以省略的,如果规定标签不能被省略,那么就绝对不能省略它。
  103 +- 空元素只有一个开始标签,且不能为空元素设置结束标签。
  104 +- 外来元素可以有一个开始标签和配对的结束标签,或者只有一个自闭合的开始标签,且后者情况下该元素不能有结束标签。
  105 +
  106 +## HTML 规范-注释规范
  107 +
  108 +### 遵循标准
  109 +
  110 +HTML 注释规范写法应该遵循以下标准:
  111 +
  112 +> Comments must start with the four character sequence U+003C LESS-THAN SIGN, U+0021 EXCLAMATION MARK, U+002D HYPHEN-MINUS, U+002D HYPHEN-MINUS (<!–). Following this sequence, the comment may have text, with the additional restriction that the text must not start with a single “>” (U+003E) character, nor start with a U+002D HYPHEN-MINUS character (-) followed by a “>” (U+003E) character, nor contain two consecutive U+002D HYPHEN-MINUS characters (–), nor end with a U+002D HYPHEN-MINUS character (-). Finally, the comment must be ended by the three character sequence U+002D HYPHEN-MINUS, U+002D HYPHEN-MINUS, U+003E GREATER-THAN SIGN (–>).
  113 +
  114 +- 必须以 4 个有序字符开始:编码为 U+003C LESS-THAN SIGN 的小于号, 编码为 U+0021 EXCLAMATION MARK 的感叹号, 编码为 U+002D HYPHEN-MINUS 横线, 编码为 U+002D HYPHEN-MINUS 横线 ,即 “<!–”
  115 +- 在此之后是注释内容,注释的内容有以下限制:
  116 + 1. 不能以单个 “>” (U+003E) 字符开始
  117 + 2. 不能以由 “-“(U+002D HYPHEN-MINUS)和 ”>” (U+003E) 组合的字符开始,即 “->”
  118 + 3. 不能包含两个连续的 U+002D HYPHEN-MINUS 字符,即 “–”
  119 + 4. 不能以一个 U+002D HYPHEN-MINUS 字符结束,即 “-”
  120 +- 必须以 3 个有序字符结束:U+002D HYPHEN-MINUS, U+002D HYPHEN-MINUS, U+003E GREATER-THAN SIGN,即 “–>”
  121 +
  122 +标准写法:
  123 +
  124 +```md
  125 +<!--Comment Text-->
  126 +```
  127 +
  128 +错误写法:
  129 +
  130 +```md
  131 +<!-->The Wrong Comment Text-->
  132 +
  133 +<!--->The Wrong Comment Text-->
  134 +
  135 +<!--The--Wrong--Comment Text-->
  136 +
  137 +<!--The Wrong Comment Text--->
  138 +```
  139 +
  140 +[www.w3.org]: https://www.w3.org/
  141 +[#comments]: https://www.w3.org/TR/2014/REC-html5-20141028/syntax.html#comments
  142 +
  143 +参考 [www.w3.org] [#Comments]
  144 +
  145 +### 单行注释
  146 +
  147 +一般用于简单的描述,如某些状态描述、属性描述等
  148 +
  149 +注释内容前后各一个空格字符,注释位于要注释代码的上面,单独占一行
  150 +
  151 +推荐:
  152 +
  153 +```html
  154 +<!-- Comment Text -->
  155 +<div>...</div>
  156 +```
  157 +
  158 +不推荐:
  159 +
  160 +```html
  161 +<div>...</div>
  162 +<!-- Comment Text -->
  163 +
  164 +<div>
  165 + <!-- Comment Text -->
  166 + ...
  167 +</div>
  168 +```
  169 +
  170 +### 模块注释
  171 +
  172 +一般用于描述模块的名称以及模块开始与结束的位置
  173 +
  174 +注释内容前后各一个空格字符,<!-- S Comment Text --> 表示模块开始,<!-- E Comment Text --> 表示模块结束,模块与模块之间相隔一行
  175 +
  176 +推荐写法:
  177 +
  178 +```html
  179 +<!-- S Comment Text A -->
  180 +<div class="mod_a">...</div>
  181 +<!-- E Comment Text A -->
  182 +
  183 +<!-- S Comment Text B -->
  184 +<div class="mod_b">...</div>
  185 +<!-- E Comment Text B -->
  186 +```
  187 +
  188 +不推荐写法:
  189 +
  190 +```html
  191 +<!-- S Comment Text A -->
  192 +<div class="mod_a">...</div>
  193 +<!-- E Comment Text A -->
  194 +<!-- S Comment Text B -->
  195 +<div class="mod_b">...</div>
  196 +<!-- E Comment Text B -->
  197 +```
  198 +
  199 +## CSS 规范-代码规范
  200 +
  201 +### 编码规范
  202 +
  203 +CSS 样式表是一个序列通用字符集,传输和存储过程中,这些字符必须由支持 US-ASCII(例如 UTF-8, ISO 8859-x, SHIFT JIS 等)字符编码方式编译
  204 +
  205 +### 文档内嵌样式表编码
  206 +
  207 +> When a style sheet is embedded in another document, such as in the STYLE element or “style” attribute of HTML, the style sheet shares the character encoding of the whole document.
  208 +
  209 +当样式出现在其它文档,如 HTML 的 STYLE 标签或标签属性 “style”,样式的编码由文档的决定。
  210 +
  211 +### 文档外链样式表编码
  212 +
  213 +> When a style sheet resides in a separate file, user agents must observe the following priorities when determining a style sheet’s character encoding (from highest priority to lowest):
  214 +
  215 +> 1. An HTTP “charset” parameter in a “Content-Type” field (or similar parameters in other protocols)
  216 +> 2. BOM and/or @charset
  217 +> 3. or other metadata from the linking mechanism (if any)
  218 +> 4. charset of referring style sheet or document (if any)
  219 +> 5. Assume UTF-8
  220 +
  221 +文档外链样式表的编码可以由以下各项按照由高到低的优先级顺序决定:
  222 +
  223 +1. HTTP “Content-Type” 字段参数 “charset”(或其它协议相似的参数)
  224 +2. BOM(byte-order mark)和(或)@charset
  225 +3. Link 中的元数据设置(如果有的话)
  226 +4. 引用样式表字符集或文档编码(如果有的话)
  227 +5. 假定为 UTF-8 编码
  228 +
  229 +### 样式表编码
  230 +
  231 +> Authors using an @charset rule must place the rule at the very beginning of the style sheet, preceded by no characters. (If a byte order mark is appropriate for the encoding used, it may precede the @charset rule.)
  232 +
  233 +> @charset must be written literally, i.e., the 10 characters ‘@charset “‘ (lowercase, no backslash escapes), followed by the encoding name, followed by ‘“;’.
  234 +
  235 +- @charset 规则一定要在样式文件的第一行首个字符位置开始,否则的话就会有机会让 BOM 设置生效(如果有设置 BOM 的话)而优于 @charset 作为样式表的编码
  236 +- @charset ""; 一定要写上,并且用小写字母,不能出现转义符
  237 +
  238 +#### 代码格式化
  239 +
  240 +样式书写一般有两种:一种是紧凑格式 (Compact)
  241 +
  242 +```css
  243 +.jdc {display: block; width: 50px;}
  244 +```
  245 +
  246 +一种是展开格式(Expanded)
  247 +
  248 +```css
  249 +.jdc {
  250 + display: block;
  251 + width: 50px;
  252 +}
  253 +```
  254 +
  255 +统一使用展开格式书写样式
  256 +
  257 +#### 代码大小写
  258 +
  259 +样式选择器,属性名,属性值关键字全部使用小写字母书写,属性字符串允许使用大小写。
  260 +
  261 +```css
  262 +/* 推荐 */
  263 +.jdc {
  264 + display: block;
  265 +}
  266 +
  267 +/* 不推荐 */
  268 +.JDC {
  269 + display: BLOCK;
  270 +}
  271 +```
  272 +
  273 +#### 选择器
  274 +
  275 +- 尽量少用通用选择器 \*
  276 +- 不使用 ID 选择器
  277 +- 不使用无具体语义定义的标签选择器
  278 +
  279 +```css
  280 +/* 推荐 */
  281 +.jdc {}
  282 +.jdc li {}
  283 +.jdc li p {}
  284 +
  285 +/* 不推荐 */
  286 +* {}
  287 +#jdc {}
  288 +.jdc div {}
  289 +```
  290 +
  291 +#### 代码缩进
  292 +
  293 +强制使用 2 个空格做为一个缩进层级,不允许使用 4 个空格 或 tab 字符。属性名 与之后的 : 之间不允许包含空格, : 与 属性值 之间必须包含空格:增强代码易读性。
  294 +
  295 +```css
  296 +/* 不推荐 */
  297 +.box {
  298 + width: 100%;
  299 +}
  300 +
  301 +/* 推荐 */
  302 +.box {
  303 + width: 100%;
  304 +}
  305 +```
  306 +
  307 +#### 逗号分隔的取值,逗号之后一个空格
  308 +
  309 +```css
  310 +推荐: .jdc {
  311 + box-shadow: 1px 1px 1px #333, 2px 2px 2px #ccc;
  312 +}
  313 +不推荐: .jdc {
  314 + box-shadow: 1px 1px 1px #333,2px 2px 2px #ccc;
  315 +}
  316 +```
  317 +
  318 +#### 不要为 0 指明单位
  319 +
  320 +```css
  321 +推荐: .jdc {
  322 + margin: 0 10px;
  323 +}
  324 +不推荐: .jdc {
  325 + margin: 0px 10px;
  326 +}
  327 +```
  328 +
  329 +#### 行长度
  330 +
  331 +建议 每行不得超过 120 个字符,除非单行不可分割。
  332 +建议 对于超长的样式,在样式值的 空格 处或 , 后换行,建议按逻辑分组。
  333 +
  334 +```css
  335 +/* 示例 */
  336 +
  337 +/* 不同属性值按逻辑分组 */
  338 +background: transparent url(aVeryVeryVeryLongUrlIsPlacedHere) no-repeat 0 0;
  339 +
  340 +/* 可重复多次的属性,每次重复一行 */
  341 +background-image: url(aVeryVeryVeryLongUrlIsPlacedHere)
  342 + url(anotherVeryVeryVeryLongUrlIsPlacedHere);
  343 +
  344 +/* 类似函数的属性值可以根据函数调用的缩进进行 */
  345 +background-image: -webkit-gradient(
  346 + linear,
  347 + left bottom,
  348 + left top,
  349 + color-stop(0.04, rgb(88, 94, 124)),
  350 + color-stop(0.52, rgb(115, 123, 162))
  351 +);
  352 +```
  353 +
  354 +#### CSS3 浏览器私有前缀写法
  355 +
  356 +```css
  357 +.jdc {
  358 + -webkit-border-radius: 10px;
  359 + -moz-border-radius: 10px;
  360 + -o-border-radius: 10px;
  361 + -ms-border-radius: 10px;
  362 + border-radius: 10px;
  363 +}
  364 +```
  365 +
  366 +## CSS 代码规范-注释规范
  367 +
  368 +### 单行注释
  369 +
  370 +注释内容第一个字符和最后一个字符都是一个空格字符,单独占一行,行与行之间相隔一行
  371 +
  372 +```css
  373 +推荐:
  374 +
  375 +/* Comment Text */
  376 +.jdc {}
  377 +
  378 +/* Comment Text */
  379 +.jdc {}
  380 +
  381 +不推荐:
  382 +
  383 +/*Comment Text*/
  384 +.jdc {
  385 + display: block;
  386 +}
  387 +.jdc {
  388 + display: block; /*Comment Text*/
  389 +}
  390 +```
  391 +
  392 +### 模块注释
  393 +
  394 +注释内容第一个字符和最后一个字符都是一个空格字符,/_ 与 模块信息描述占一行,多个横线分隔符-与_/占一行,行与行之间相隔两行
  395 +
  396 +```css
  397 +推荐:
  398 +
  399 +/* Module A
  400 +---------------------------------------------------------------- */
  401 +.mod_a {}
  402 +
  403 +/* Module B
  404 +---------------------------------------------------------------- */
  405 +.mod_b {}
  406 +不推荐:
  407 +
  408 +/* Module A ---------------------------------------------------- */
  409 +.mod_a {}
  410 +/* Module B ---------------------------------------------------- */
  411 +.mod_b {}
  412 +```
  413 +
  414 +## CSS 代码规范-媒体查询
  415 +
  416 +### 常用查询语句
  417 +
  418 +判断设备横竖屏
  419 +
  420 +```css
  421 +/* 横屏 */
  422 +@media all and (orientation: landscape) {
  423 +
  424 +}
  425 +
  426 +/* 竖屏 */
  427 +@media all and (orientation: portrait) {
  428 +
  429 +}
  430 +```
  431 +
  432 +判断设备宽高
  433 +
  434 +```css
  435 +/* 设备宽度大于 320px 小于 640px */
  436 +@media all and (min-width: 320px) and (max-width: 640px) {
  437 +
  438 +}
  439 +```
  440 +
  441 +判断设备像素比
  442 +
  443 +```css
  444 +/* 设备像素比为 1 */
  445 +@media only screen and (-webkit-min-device-pixel-ratio: 1),
  446 + only screen and (min-device-pixel-ratio: 1) {
  447 +
  448 +}
  449 +
  450 +/* 设备像素比为 1.5 */
  451 +@media only screen and (-webkit-min-device-pixel-ratio: 1.5),
  452 + only screen and (min-device-pixel-ratio: 1.5) {
  453 +
  454 +}
  455 +
  456 +/* 设备像素比为 2 */
  457 +@media only screen and (-webkit-min-device-pixel-ratio: 2),
  458 + only screen and (min-device-pixel-ratio: 2) {
  459 +
  460 +}
  461 +```
  462 +
  463 +### 常用设备设置
  464 +
  465 +#### iPhones
  466 +
  467 +```css
  468 +/* ----------- iPhone 4 and 4S ----------- */
  469 +
  470 +/* Portrait and Landscape */
  471 +@media only screen and (min-device-width: 320px) and (max-device-width: 480px) and (-webkit-min-device-pixel-ratio: 2) {
  472 +
  473 +}
  474 +
  475 +/* Portrait */
  476 +@media only screen and (min-device-width: 320px) and (max-device-width: 480px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: portrait) {
  477 +
  478 +}
  479 +
  480 +/* Landscape */
  481 +@media only screen and (min-device-width: 320px) and (max-device-width: 480px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: landscape) {
  482 +
  483 +}
  484 +
  485 +/* ----------- iPhone 5 and 5S ----------- */
  486 +
  487 +/* Portrait and Landscape */
  488 +@media only screen and (min-device-width: 320px) and (max-device-width: 568px) and (-webkit-min-device-pixel-ratio: 2) {
  489 +
  490 +}
  491 +
  492 +/* Portrait */
  493 +@media only screen and (min-device-width: 320px) and (max-device-width: 568px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: portrait) {
  494 +
  495 +}
  496 +
  497 +/* Landscape */
  498 +@media only screen and (min-device-width: 320px) and (max-device-width: 568px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: landscape) {
  499 +
  500 +}
  501 +
  502 +/* ----------- iPhone 6 ----------- */
  503 +
  504 +/* Portrait and Landscape */
  505 +@media only screen and (min-device-width: 375px) and (max-device-width: 667px) and (-webkit-min-device-pixel-ratio: 2) {
  506 +
  507 +}
  508 +
  509 +/* Portrait */
  510 +@media only screen and (min-device-width: 375px) and (max-device-width: 667px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: portrait) {
  511 +
  512 +}
  513 +
  514 +/* Landscape */
  515 +@media only screen and (min-device-width: 375px) and (max-device-width: 667px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: landscape) {
  516 +
  517 +}
  518 +
  519 +/* ----------- iPhone 6+ ----------- */
  520 +
  521 +/* Portrait and Landscape */
  522 +@media only screen and (min-device-width: 414px) and (max-device-width: 736px) and (-webkit-min-device-pixel-ratio: 3) {
  523 +
  524 +}
  525 +
  526 +/* Portrait */
  527 +@media only screen and (min-device-width: 414px) and (max-device-width: 736px) and (-webkit-min-device-pixel-ratio: 3) and (orientation: portrait) {
  528 +
  529 +}
  530 +
  531 +/* Landscape */
  532 +@media only screen and (min-device-width: 414px) and (max-device-width: 736px) and (-webkit-min-device-pixel-ratio: 3) and (orientation: landscape) {
  533 +
  534 +}
  535 +```
  536 +
  537 +#### Galaxy Phones
  538 +
  539 +```css
  540 +/* ----------- Galaxy S3 ----------- */
  541 +
  542 +/* Portrait and Landscape */
  543 +@media screen and (device-width: 320px) and (device-height: 640px) and (-webkit-device-pixel-ratio: 2) {
  544 +
  545 +}
  546 +
  547 +/* Portrait */
  548 +@media screen and (device-width: 320px) and (device-height: 640px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait) {
  549 +
  550 +}
  551 +
  552 +/* Landscape */
  553 +@media screen and (device-width: 320px) and (device-height: 640px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape) {
  554 +
  555 +}
  556 +
  557 +/* ----------- Galaxy S4 ----------- */
  558 +
  559 +/* Portrait and Landscape */
  560 +@media screen and (device-width: 320px) and (device-height: 640px) and (-webkit-device-pixel-ratio: 3) {
  561 +
  562 +}
  563 +
  564 +/* Portrait */
  565 +@media screen and (device-width: 320px) and (device-height: 640px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait) {
  566 +
  567 +}
  568 +
  569 +/* Landscape */
  570 +@media screen and (device-width: 320px) and (device-height: 640px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape) {
  571 +
  572 +}
  573 +
  574 +/* ----------- Galaxy S5 ----------- */
  575 +
  576 +/* Portrait and Landscape */
  577 +@media screen and (device-width: 360px) and (device-height: 640px) and (-webkit-device-pixel-ratio: 3) {
  578 +
  579 +}
  580 +
  581 +/* Portrait */
  582 +@media screen and (device-width: 360px) and (device-height: 640px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait) {
  583 +
  584 +}
  585 +
  586 +/* Landscape */
  587 +@media screen and (device-width: 360px) and (device-height: 640px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape) {
  588 +
  589 +}
  590 +```
  591 +
  592 +#### HTC Phones
  593 +
  594 +```css
  595 +/* ----------- HTC One ----------- */
  596 +
  597 +/* Portrait and Landscape */
  598 +@media screen and (device-width: 360px) and (device-height: 640px) and (-webkit-device-pixel-ratio: 3) {
  599 +
  600 +}
  601 +
  602 +/* Portrait */
  603 +@media screen and (device-width: 360px) and (device-height: 640px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait) {
  604 +
  605 +}
  606 +
  607 +/* Landscape */
  608 +@media screen and (device-width: 360px) and (device-height: 640px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape) {
  609 +
  610 +}
  611 +```
  612 +
  613 +#### iPads
  614 +
  615 +```css
  616 +/* ----------- iPad mini ----------- */
  617 +
  618 +/* Portrait and Landscape */
  619 +@media only screen and (min-device-width: 768px) and (max-device-width: 1024px) and (-webkit-min-device-pixel-ratio: 1) {
  620 +
  621 +}
  622 +
  623 +/* Portrait */
  624 +@media only screen and (min-device-width: 768px) and (max-device-width: 1024px) and (orientation: portrait) and (-webkit-min-device-pixel-ratio: 1) {
  625 +
  626 +}
  627 +
  628 +/* Landscape */
  629 +@media only screen and (min-device-width: 768px) and (max-device-width: 1024px) and (orientation: landscape) and (-webkit-min-device-pixel-ratio: 1) {
  630 +
  631 +}
  632 +
  633 +/* ----------- iPad 1 and 2 ----------- */
  634 +
  635 +/* Portrait and Landscape */
  636 +@media only screen and (min-device-width: 768px) and (max-device-width: 1024px) and (-webkit-min-device-pixel-ratio: 1) {
  637 +
  638 +}
  639 +
  640 +/* Portrait */
  641 +@media only screen and (min-device-width: 768px) and (max-device-width: 1024px) and (orientation: portrait) and (-webkit-min-device-pixel-ratio: 1) {
  642 +
  643 +}
  644 +
  645 +/* Landscape */
  646 +@media only screen and (min-device-width: 768px) and (max-device-width: 1024px) and (orientation: landscape) and (-webkit-min-device-pixel-ratio: 1) {
  647 +
  648 +}
  649 +
  650 +/* ----------- iPad 3 and 4 ----------- */
  651 +
  652 +/* Portrait and Landscape */
  653 +@media only screen and (min-device-width: 768px) and (max-device-width: 1024px) and (-webkit-min-device-pixel-ratio: 2) {
  654 +
  655 +}
  656 +
  657 +/* Portrait */
  658 +@media only screen and (min-device-width: 768px) and (max-device-width: 1024px) and (orientation: portrait) and (-webkit-min-device-pixel-ratio: 2) {
  659 +
  660 +}
  661 +
  662 +/* Landscape */
  663 +@media only screen and (min-device-width: 768px) and (max-device-width: 1024px) and (orientation: landscape) and (-webkit-min-device-pixel-ratio: 2) {
  664 +
  665 +}
  666 +```
  667 +
  668 +## CSS 规范-命名规范
  669 +
  670 +### ClassName 命名
  671 +
  672 +ClassName 的命名应该尽量精短、明确,必须以字母开头命名,且全部字母为小写,单词之间统一使用下划线 “\_” 连接
  673 +
  674 +基于姓氏命名法(继承 + 外来),如下图:
  675 +祖先模块不能出现下划线,除了是全站公用模块,如 mod\_ 系列的命名:
  676 +
  677 +```html
  678 +推荐:
  679 +
  680 +<div class="modulename">
  681 + <div class="modulename_info">
  682 + <div class="modulename_son"></div>
  683 + <div class="modulename_son"></div>
  684 + ...
  685 + </div>
  686 +</div>
  687 +
  688 +<!-- 这个是全站公用模块,祖先模块允许直接出现下划线 -->
  689 +<div class="mod_info">
  690 + <div class="mod_info_son"></div>
  691 + <div class="mod_info_son"></div>
  692 + ...
  693 +</div>
  694 +不推荐:
  695 +
  696 +<div class="modulename_info">
  697 + <div class="modulename_info_son"></div>
  698 + <div class="modulename_info_son"></div>
  699 + ...
  700 +</div>
  701 +```
  702 +
  703 +在子孙模块数量可预测的情况下,严格继承祖先模块的命名前缀
  704 +
  705 +```html
  706 +<div class="modulename">
  707 + <div class="modulename_cover"></div>
  708 + <div class="modulename_info"></div>
  709 +</div>
  710 +```
  711 +
  712 +当子孙模块超过 4 级或以上的时候,可以考虑在祖先模块内具有识辨性的独立缩写作为新的子孙模块
  713 +
  714 +```html
  715 +推荐:
  716 +
  717 +<div class="modulename">
  718 + <div class="modulename_cover"></div>
  719 + <div class="modulename_info">
  720 + <div class="modulename_info_user">
  721 + <div class="modulename_info_user_img">
  722 + <img src="" alt="" />
  723 + <!-- 这个时候 miui 为 modulename_info_user_img 首字母缩写-->
  724 + <div class="miui_tit"></div>
  725 + <div class="miui_txt"></div>
  726 + ...
  727 + </div>
  728 + </div>
  729 + <div class="modulename_info_list"></div>
  730 + </div>
  731 +</div>
  732 +不推荐:
  733 +
  734 +<div class="modulename">
  735 + <div class="modulename_cover"></div>
  736 + <div class="modulename_info">
  737 + <div class="modulename_info_user">
  738 + <div class="modulename_info_user_img">
  739 + <img src="" alt="" />
  740 + <div class="modulename_info_user_img_tit"></div>
  741 + <div class="modulename_info_user_img_txt"></div>
  742 + ...
  743 + </div>
  744 + </div>
  745 + <div class="modulename_info_list"></div>
  746 + </div>
  747 +</div>
  748 +```
  749 +
  750 +### 模块命名
  751 +
  752 +全站公共模块:以 mod\_ 开头
  753 +
  754 +```html
  755 +<div class="mod_yours"></div>
  756 +```
  757 +
  758 +业务公共模块:以 业务名*mod* 开头
  759 +
  760 +```html
  761 +<div class="paipai_mod_yours"></div>
  762 +```
  763 +
  764 +### 常用命名推荐
  765 +
  766 +注意:ad、banner、gg、guanggao 等有机会和广告挂勾的字眠不建议直接用来做 ClassName,因为有些浏览器插件(Chrome 的广告拦截插件等)会直接过滤这些类名,因此
  767 +
  768 +```html
  769 +<div class="ad"></div>
  770 +```
  771 +
  772 +这种广告的英文或拼音类名不应该出现
  773 +
  774 +另外,敏感不和谐字眼也不应该出现,如:
  775 +
  776 +```html
  777 +<div class="fuck"></div>
  778 +<div class="jer"></div>
  779 +<div class="sm"></div>
  780 +<div class="gcd"></div>
  781 +<div class="ass"></div>
  782 +<div class="KMT"></div>
  783 +...
  784 +```
  785 +
  786 +| about | 关于 |
  787 +| ---------------------- | ---------------------------------------- |
  788 +| account | 账户 |
  789 +| arrow | 箭头图标 |
  790 +| article | 文章 |
  791 +| aside | 边栏 |
  792 +| audio | 音频 |
  793 +| avatar | 头像 |
  794 +| bg,background | 背景 |
  795 +| bar | 栏(工具类) |
  796 +| branding | 品牌化 |
  797 +| crumb,breadcrumbs | 面包屑 |
  798 +| btn,button | 按钮 |
  799 +| caption | 标题,说明 |
  800 +| category | 分类 |
  801 +| chart | 图表 |
  802 +| clearfix | 清除浮动 |
  803 +| close | 关闭 |
  804 +| col,column | 列 |
  805 +| comment | 评论 |
  806 +| community | 社区 |
  807 +| container | 容器 |
  808 +| content | 内容 |
  809 +| copyright | 版权 |
  810 +| current | 当前态,选中态 |
  811 +| default | 默认 |
  812 +| description | 描述 |
  813 +| details | 细节 |
  814 +| disabled | 不可用 |
  815 +| entry | 文章,博文 |
  816 +| error | 错误 |
  817 +| even | 偶数,常用于多行列表或表格中 |
  818 +| fail | 失败(提示) |
  819 +| feature | 专题 |
  820 +| fewer | 收起 |
  821 +| field | 用于表单的输入区域 |
  822 +| figure | 图 |
  823 +| filter | 筛选 |
  824 +| first | 第一个,常用于列表中 |
  825 +| footer | 页脚 |
  826 +| forum | 论坛 |
  827 +| gallery | 画廊 |
  828 +| group | 模块,清除浮动 |
  829 +| header | 页头 |
  830 +| help | 帮助 |
  831 +| hide | 隐藏 |
  832 +| hightlight | 高亮 |
  833 +| home | 主页 |
  834 +| icon | 图标 |
  835 +| info,information | 信息 |
  836 +| last | 最后一个,常用于列表中 |
  837 +| links | 链接 |
  838 +| login | 登录 |
  839 +| logout | 退出 |
  840 +| logo | 标志 |
  841 +| main | 主体 |
  842 +| menu | 菜单 |
  843 +| meta | 作者、更新时间等信息栏,一般位于标题之下 |
  844 +| module | 模块 |
  845 +| more | 更多(展开) |
  846 +| msg,message | 消息 |
  847 +| nav,navigation | 导航 |
  848 +| next | 下一页 |
  849 +| nub | 小块 |
  850 +| odd | 奇数,常用于多行列表或表格中 |
  851 +| off | 鼠标离开 |
  852 +| on | 鼠标移过 |
  853 +| output | 输出 |
  854 +| pagination | 分页 |
  855 +| pop,popup | 弹窗 |
  856 +| preview | 预览 |
  857 +| previous | 上一页 |
  858 +| primary | 主要 |
  859 +| progress | 进度条 |
  860 +| promotion | 促销 |
  861 +| rcommd,recommendations | 推荐 |
  862 +| reg,register | 注册 |
  863 +| save | 保存 |
  864 +| search | 搜索 |
  865 +| secondary | 次要 |
  866 +| section | 区块 |
  867 +| selected | 已选 |
  868 +| share | 分享 |
  869 +| show | 显示 |
  870 +| sidebar | 边栏,侧栏 |
  871 +| slide | 幻灯片,图片切换 |
  872 +| sort | 排序 |
  873 +| sub | 次级的,子级的 |
  874 +| submit | 提交 |
  875 +| subscribe | 订阅 |
  876 +| subtitle | 副标题 |
  877 +| success | 成功(提示) |
  878 +| summary | 摘要 |
  879 +| tab | 标签页 |
  880 +| table | 表格 |
  881 +| txt,text | 文本 |
  882 +| thumbnail | 缩略图 |
  883 +| time | 时间 |
  884 +| tips | 提示 |
  885 +| title | 标题 |
  886 +| video | 视频 |
  887 +| wrap | 容器,包,一般用于最外层 |
  888 +| wrapper | 容器,包,一般用于最外层 |
  889 +
  890 +## JavaScript-代码规范
  891 +
  892 +### 类型
  893 +
  894 +1. 原始值:当你访问一个原始类型的时候,你可以直接使用它的值.
  895 +
  896 + - string
  897 + - number
  898 + - boolean
  899 + - null
  900 + - undefined
  901 + - symbol
  902 +
  903 + ```js
  904 + const foo = 1;
  905 + let bar = foo;
  906 +
  907 + bar = 9;
  908 +
  909 + console.log(foo, bar); // => 1, 9
  910 + ```
  911 +
  912 + - 标识符不能完全被支持,因此在针对不支持的浏览器或者环境时不应该使用它们。
  913 +
  914 +2. 复杂类型: 当你访问一个复杂类型的时候,你需要一个值得引用。
  915 +
  916 + - object
  917 + - array
  918 + - function
  919 +
  920 + ```js
  921 + const foo = [1, 2];
  922 + const bar = foo;
  923 +
  924 + bar[0] = 9;
  925 +
  926 + console.log(foo[0], bar[0]); // => 9, 9
  927 + ```
  928 +
  929 +### 变量
  930 +
  931 +1. 使用 `const` 定义你的所有引用;避免使用 `var`。 eslint: [prefer-const](https://eslint.org/docs/rules/prefer-const.html), [no-const-assign](https://eslint.org/docs/rules/no-const-assign.html)
  932 + > 为什么? 这样能够确保你不能重新赋值你的引用,否则可能导致错误或者产生难以理解的代码。
  933 +
  934 +```js
  935 +// bad
  936 +var a = 1;
  937 +var b = 2;
  938 +
  939 +// good
  940 +const a = 1;
  941 +const b = 2;
  942 +```
  943 +
  944 +2. 如果你必须重新赋值你的引用, 使用 `let` 代替 `var`。 >为什么? `let` 是块级作用域,而不像 `var` 是函数作用域. eslint: [no-var](https://eslint.org/docs/rules/no-var.html)
  945 +
  946 +```js
  947 +// bad
  948 +var count = 1;
  949 +if (true) {
  950 + count += 1;
  951 +}
  952 +
  953 +// good, use the let.
  954 +let count = 1;
  955 +if (true) {
  956 + count += 1;
  957 +}
  958 +```
  959 +
  960 +3. 注意,let 和 const 都是块级范围的。
  961 +```js
  962 +// const 和 let 只存在于他们定义的块中。
  963 +{
  964 + let a = 1;
  965 + const b = 1;
  966 +}
  967 +console.log(a); // ReferenceError
  968 +console.log(b); // ReferenceError
  969 +```
  970 +
  971 +### 对象
  972 +
  973 +1. 使用字面语法来创建对象。 eslint: [no-new-object](https://eslint.org/docs/rules/no-new-object.html)
  974 +
  975 +```js
  976 +// bad
  977 +
  978 +const item = new Object();
  979 +
  980 +// good
  981 +const item = {};
  982 +```
  983 +
  984 +2. 在创建具有动态属性名称的对象时使用计算属性名。
  985 + > 为什么? 它允许你在一个地方定义对象的所有属性。
  986 +
  987 +```js
  988 +function getKey(k) {
  989 + return `a key named ${k}`;
  990 +}
  991 +
  992 +// bad
  993 +const obj = {
  994 + id: 5,
  995 + name: "San Francisco",
  996 +};
  997 +obj[getKey("enabled")] = true;
  998 +
  999 +// good
  1000 +const obj = {
  1001 + id: 5,
  1002 + name: "San Francisco",
  1003 + [getKey("enabled")]: true,
  1004 +};
  1005 +```
  1006 +
  1007 +3. 使用对象方法的缩写。eslint: [object-shorthand](https://eslint.org/docs/rules/object-shorthand.html)
  1008 +
  1009 +```js
  1010 +// bad
  1011 +const atom = {
  1012 + value: 1,
  1013 +
  1014 + addValue: function (value) {
  1015 + return atom.value + value;
  1016 + },
  1017 +};
  1018 +
  1019 +// good
  1020 +const atom = {
  1021 + value: 1,
  1022 +
  1023 + addValue(value) {
  1024 + return atom.value + value;
  1025 + },
  1026 +};
  1027 +```
  1028 +
  1029 +4. 使用属性值的缩写。 eslint: [object-shorthand](https://eslint.org/docs/rules/object-shorthand.html)
  1030 + > 为什么? 它的写法和描述较短。
  1031 +
  1032 +```js
  1033 +const lukeSkywalker = "Luke Skywalker";
  1034 +
  1035 +// bad
  1036 +const obj = {
  1037 + lukeSkywalker: lukeSkywalker,
  1038 +};
  1039 +
  1040 +// good
  1041 +const obj = {
  1042 + lukeSkywalker,
  1043 +};
  1044 +```
  1045 +
  1046 +5. 在对象声明的时候将简写的属性进行分组。
  1047 + > 为什么? 这样更容易的判断哪些属性使用的简写。
  1048 +
  1049 +```js
  1050 +const anakinSkywalker = "Anakin Skywalker";
  1051 +const lukeSkywalker = "Luke Skywalker";
  1052 +
  1053 +// bad
  1054 +const obj = {
  1055 + episodeOne: 1,
  1056 + twoJediWalkIntoACantina: 2,
  1057 + lukeSkywalker,
  1058 + episodeThree: 3,
  1059 + mayTheFourth: 4,
  1060 + anakinSkywalker,
  1061 +};
  1062 +
  1063 +// good
  1064 +const obj = {
  1065 + lukeSkywalker,
  1066 + anakinSkywalker,
  1067 + episodeOne: 1,
  1068 + twoJediWalkIntoACantina: 2,
  1069 + episodeThree: 3,
  1070 + mayTheFourth: 4,
  1071 +};
  1072 +```
  1073 +
  1074 +6. 只使用引号标注无效标识符的属性。eslint: [quote-props](https://eslint.org/docs/rules/quote-props.html)
  1075 + > 为什么? 总的来说,我们认为这样更容易阅读。 它提升了语法高亮显示,并且更容易通过许多 JS 引擎优化。
  1076 +
  1077 +```js
  1078 +// bad
  1079 +const bad = {
  1080 + 'foo': 3,
  1081 + 'bar': 4,
  1082 + 'data-blah': 5,
  1083 +};
  1084 +
  1085 +// good
  1086 +const good = {
  1087 + foo: 3,
  1088 + bar: 4,
  1089 + 'data-blah': 5,
  1090 +};
  1091 +```
  1092 +
  1093 +7. 不能直接调用 Object.prototype 的方法,如: hasOwnProperty 、 propertyIsEnumerable 和 isPrototypeOf。
  1094 + > 为什么? 这些方法可能被以下问题对象的属性追踪 - 相应的有 { hasOwnProperty: false } - 或者,对象是一个空对象 (Object.create(null))。
  1095 +
  1096 +```js
  1097 +// bad
  1098 +console.log(object.hasOwnProperty(key));
  1099 +
  1100 +// good
  1101 +console.log(Object.prototype.hasOwnProperty.call(object, key));
  1102 +
  1103 +// best
  1104 +const has = Object.prototype.hasOwnProperty; // 在模块范围内的缓存中查找一次
  1105 +/* or */
  1106 +import has from "has"; // https://www.npmjs.com/package/has
  1107 +// ...
  1108 +console.log(has.call(object, key));
  1109 +```
  1110 +
  1111 +8. 更喜欢对象扩展操作符,而不是用 Object.assign 浅拷贝一个对象。 使用对象的 rest 操作符来获得一个具有某些属性的新对象。
  1112 +
  1113 +```js
  1114 +// very bad
  1115 +const original = { a: 1, b: 2 };
  1116 +const copy = Object.assign(original, { c: 3 }); // 变异的 `original` ಠ_ಠ
  1117 +delete copy.a; // 这....
  1118 +
  1119 +// bad
  1120 +const original = { a: 1, b: 2 };
  1121 +const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 }
  1122 +
  1123 +// good
  1124 +const original = { a: 1, b: 2 };
  1125 +const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 }
  1126 +
  1127 +const { a, ...noA } = copy; // noA => { b: 2, c: 3 }
  1128 +```
  1129 +
  1130 +### 数组
  1131 +
  1132 +1. 使用字面语法创建数组。eslint: [no-array-constructor](https://eslint.org/docs/rules/no-array-constructor.html)
  1133 +
  1134 +```js
  1135 +// bad
  1136 +const items = new Array();
  1137 +
  1138 +// good
  1139 +const items = [];
  1140 +```
  1141 +
  1142 +2. 使用 [Array#push](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push) 取代直接赋值来给数组添加项。
  1143 +
  1144 +```js
  1145 +const someStack = [];
  1146 +
  1147 +// bad
  1148 +someStack[someStack.length] = "abracadabra";
  1149 +
  1150 +// good
  1151 +someStack.push("abracadabra");
  1152 +```
  1153 +
  1154 +3. 使用数组展开方法 `...` 来拷贝数组。
  1155 +
  1156 +```js
  1157 +// bad
  1158 +const len = items.length;
  1159 +const itemsCopy = [];
  1160 +let i;
  1161 +
  1162 +for (i = 0; i < len; i += 1) {
  1163 + itemsCopy[i] = items[i];
  1164 +}
  1165 +
  1166 +// good
  1167 +const itemsCopy = [...items];
  1168 +```
  1169 +
  1170 +4. 将一个类数组对象转换成一个数组, 使用展开方法 ... 代替 [Array.from](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from)
  1171 +
  1172 +```js
  1173 +const foo = document.querySelectorAll(".foo");
  1174 +
  1175 +// good
  1176 +const nodes = Array.from(foo);
  1177 +
  1178 +// best
  1179 +const nodes = [...foo];
  1180 +```
  1181 +
  1182 +5. 对于对迭代器的映射,使用 [Array.from](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from) 替代展开方法 ... , 因为它避免了创建中间数组。
  1183 +
  1184 +```js
  1185 +// bad
  1186 +const baz = [...foo].map(bar);
  1187 +
  1188 +// good
  1189 +const baz = Array.from(foo, bar);
  1190 +```
  1191 +
  1192 +6. 在数组回调方法中使用 return 语句。 如果函数体由一个返回无副作用的表达式的单个语句组成,那么可以省略返回值。 eslint: [array-callback-return](https://eslint.org/docs/rules/array-callback-return)
  1193 +
  1194 +```js
  1195 +// good
  1196 +[1, 2, 3].map((x) => {
  1197 + const y = x + 1;
  1198 + return x * y;
  1199 +});
  1200 +
  1201 +// good
  1202 +[1, 2, 3].map((x) => x + 1);
  1203 +
  1204 +// bad - 没有返回值,意味着在第一次迭代后 `acc` 没有被定义
  1205 +[
  1206 + [0, 1],
  1207 + [2, 3],
  1208 + [4, 5],
  1209 +].reduce((acc, item, index) => {
  1210 + const flatten = acc.concat(item);
  1211 + acc[index] = flatten;
  1212 +});
  1213 +
  1214 +// good
  1215 +[
  1216 + [0, 1],
  1217 + [2, 3],
  1218 + [4, 5],
  1219 +].reduce((acc, item, index) => {
  1220 + const flatten = acc.concat(item);
  1221 + acc[index] = flatten;
  1222 + return flatten;
  1223 +});
  1224 +
  1225 +// bad
  1226 +inbox.filter((msg) => {
  1227 + const { subject, author } = msg;
  1228 + if (subject === "Mockingbird") {
  1229 + return author === "Harper Lee";
  1230 + } else {
  1231 + return false;
  1232 + }
  1233 +});
  1234 +
  1235 +// good
  1236 +inbox.filter((msg) => {
  1237 + const { subject, author } = msg;
  1238 + if (subject === "Mockingbird") {
  1239 + return author === "Harper Lee";
  1240 + }
  1241 +
  1242 + return false;
  1243 +});
  1244 +```
  1245 +
  1246 +7. 如果数组有多行,则在开始的时候换行,然后在结束的时候换行。
  1247 +
  1248 +```js
  1249 +// bad
  1250 +const arr = [
  1251 + [0, 1], [2, 3], [4, 5],
  1252 +];
  1253 +
  1254 +const objectInArray = [{
  1255 + id: 1,
  1256 +}, {
  1257 + id: 2,
  1258 +}];
  1259 +
  1260 +const numberInArray = [
  1261 + 1, 2,
  1262 +];
  1263 +
  1264 +// good
  1265 +const arr = [
  1266 + [0, 1],
  1267 + [2, 3],
  1268 + [4, 5],
  1269 +];
  1270 +
  1271 +const objectInArray = [
  1272 + {
  1273 + id: 1,
  1274 + },
  1275 + {
  1276 + id: 2,
  1277 + },
  1278 +];
  1279 +
  1280 +const numberInArray = [1, 2];
  1281 +```
  1282 +
  1283 +### 解构
  1284 +
  1285 +1. 在访问和使用对象的多个属性的时候使用对象的解构。eslint: [prefer-destructuring](https://eslint.org/docs/rules/prefer-destructuring)
  1286 + > 为什么? 解构可以避免为这些属性创建临时引用。
  1287 +
  1288 +```js
  1289 +// bad
  1290 +function getFullName(user) {
  1291 + const firstName = user.firstName;
  1292 + const lastName = user.lastName;
  1293 +
  1294 + return `${firstName} ${lastName}`;
  1295 +}
  1296 +
  1297 +// good
  1298 +function getFullName(user) {
  1299 + const { firstName, lastName } = user;
  1300 + return `${firstName} ${lastName}`;
  1301 +}
  1302 +
  1303 +// best
  1304 +function getFullName({ firstName, lastName }) {
  1305 + return `${firstName} ${lastName}`;
  1306 +}
  1307 +```
  1308 +
  1309 +2. 使用数组解构。eslint: [prefer-destructuring](https://eslint.org/docs/rules/prefer-destructuring)
  1310 +
  1311 +```js
  1312 +const arr = [1, 2, 3, 4];
  1313 +
  1314 +// bad
  1315 +const first = arr[0];
  1316 +const second = arr[1];
  1317 +
  1318 +// good
  1319 +const [first, second] = arr;
  1320 +```
  1321 +
  1322 +3. 对于多个返回值使用对象解构,而不是数组解构。
  1323 + > 为什么? 你可以随时添加新的属性或者改变属性的顺序,而不用修改调用方。
  1324 +
  1325 +```js
  1326 +// bad
  1327 +function processInput(input) {
  1328 + // 处理代码...
  1329 + return [left, right, top, bottom];
  1330 +}
  1331 +
  1332 +// 调用者需要考虑返回数据的顺序。
  1333 +const [left, __, top] = processInput(input);
  1334 +
  1335 +// good
  1336 +function processInput(input) {
  1337 + // 处理代码...
  1338 + return { left, right, top, bottom };
  1339 +}
  1340 +
  1341 +// 调用者只选择他们需要的数据。
  1342 +const { left, top } = processInput(input);
  1343 +```
  1344 +
  1345 +### 字符
  1346 +
  1347 +1. 使用单引号 '' 定义字符串 eslint: [quotes](https://eslint.org/docs/rules/quotes.html)
  1348 +
  1349 +```js
  1350 +// bad
  1351 +const name = "Capt. Janeway";
  1352 +
  1353 +// bad - 模板文字应该包含插值或换行。
  1354 +const name = `Capt. Janeway`;
  1355 +
  1356 +// good
  1357 +const name = "Capt. Janeway";
  1358 +```
  1359 +
  1360 +2. 使行超过 100 个字符的字符串不应使用字符串连接跨多行写入。
  1361 + > 为什么? 断开的字符串更加难以工作,并且使代码搜索更加困难。
  1362 +
  1363 +```js
  1364 +// bad
  1365 +const errorMessage =
  1366 + "This is a super long error that was thrown because \
  1367 +of Batman. When you stop to think about how Batman had anything to do \
  1368 +with this, you would get nowhere \
  1369 +fast.";
  1370 +
  1371 +// bad
  1372 +const errorMessage =
  1373 + "This is a super long error that was thrown because " +
  1374 + "of Batman. When you stop to think about how Batman had anything to do " +
  1375 + "with this, you would get nowhere fast.";
  1376 +
  1377 +// good
  1378 +const errorMessage =
  1379 + "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.";
  1380 +```
  1381 +
  1382 +3. 当以编程模式构建字符串时,使用字符串模板代替字符串拼接。eslint: [prefer-template](https://eslint.org/docs/rules/prefer-template.html) [template-curly-spacing](https://eslint.org/docs/rules/template-curly-spacing)
  1383 + > 为什么? 字符串模板为您提供了一种可读的、简洁的语法,具有正确的换行和字符串插值特性。
  1384 +
  1385 +```js
  1386 +// bad
  1387 +function sayHi(name) {
  1388 + return "How are you, " + name + "?";
  1389 +}
  1390 +
  1391 +// bad
  1392 +function sayHi(name) {
  1393 + return ["How are you, ", name, "?"].join();
  1394 +}
  1395 +
  1396 +// bad
  1397 +function sayHi(name) {
  1398 + return `How are you, ${name}?`;
  1399 +}
  1400 +
  1401 +// good
  1402 +function sayHi(name) {
  1403 + return `How are you, ${name}?`;
  1404 +}
  1405 +```
  1406 +
  1407 +4. 不要在字符串上使用 eval() ,它打开了太多漏洞。eslint: [no-eval](https://eslint.org/docs/rules/no-eval)
  1408 +
  1409 +5. 不要转义字符串中不必要的字符。eslint: [no-useless-escape](https://eslint.org/docs/rules/no-useless-escape)
  1410 + > 为什么? 反斜杠损害了可读性,因此只有在必要的时候才会出现。
  1411 +
  1412 +```js
  1413 +// bad
  1414 +const foo = '\'this\' \i\s \"quoted\"';
  1415 +
  1416 +// good
  1417 +const foo = '\'this\' is "quoted"';
  1418 +const foo = `my name is '${name}'`;
  1419 +```
  1420 +
  1421 +### 方法
  1422 +
  1423 +1. 使用命名的函数表达式代替函数声明。eslint: [func-style](https://eslint.org/docs/rules/func-style)
  1424 + > 为什么? 函数声明是挂起的,这意味着在它在文件中定义之前,很容易引用函数。这会损害可读性和可维护性。如果您发现函数的定义是大的或复杂的,以至于它干扰了对文件的其余部分的理解,那么也许是时候将它提取到它自己的模块中了!不要忘记显式地命名这个表达式,不管它的名称是否从包含变量(在现代浏览器中经常是这样,或者在使用诸如 Babel 之类的编译器时)。这消除了对错误的调用堆栈的任何假设。([Discussion](https://github.com/airbnb/javascript/issues/794))
  1425 +
  1426 +```js
  1427 +// bad
  1428 +function foo() {
  1429 + // ...
  1430 +}
  1431 +
  1432 +// bad
  1433 +const foo = function () {
  1434 + // ...
  1435 +};
  1436 +
  1437 +// good
  1438 +// 从变量引用调用中区分的词汇名称
  1439 +const short = function longUniqueMoreDescriptiveLexicalFoo() {
  1440 + // ...
  1441 +};
  1442 +```
  1443 +
  1444 +2. Wrap 立即调用函数表达式。 eslint: [wrap-iife](https://eslint.org/docs/rules/wrap-iife.html)
  1445 + > 为什么? 立即调用的函数表达式是单个单元 - 包装, 并且拥有括号调用, 在括号内, 清晰的表达式。 请注意,在一个到处都是模块的世界中,您几乎不需要一个 IIFE 。
  1446 +
  1447 +```js
  1448 +// immediately-invoked function expression (IIFE) 立即调用的函数表达式
  1449 +(function () {
  1450 + console.log("Welcome to the Internet. Please follow me.");
  1451 +})();
  1452 +```
  1453 +
  1454 +3. 切记不要在非功能块中声明函数 (if, while, 等)。 将函数赋值给变量。 浏览器允许你这样做,但是他们都有不同的解释,这是个坏消息。eslint: [no-loop-func](https://eslint.org/docs/rules/no-loop-func.html)
  1455 +
  1456 +4. 注意: ECMA-262 将 block 定义为语句列表。 函数声明不是语句。
  1457 +
  1458 +```js
  1459 +// bad
  1460 +if (currentUser) {
  1461 + function test() {
  1462 + console.log("Nope.");
  1463 + }
  1464 +}
  1465 +
  1466 +// good
  1467 +let test;
  1468 +if (currentUser) {
  1469 + test = () => {
  1470 + console.log("Yup.");
  1471 + };
  1472 +}
  1473 +```
  1474 +
  1475 +5. 永远不要定义一个参数为 arguments。 这将会优先于每个函数给定范围的 arguments 对象。
  1476 +
  1477 +```js
  1478 +// bad
  1479 +function foo(name, options, arguments) {
  1480 + // ...
  1481 +}
  1482 +
  1483 +// good
  1484 +function foo(name, options, args) {
  1485 + // ...
  1486 +}
  1487 +```
  1488 +
  1489 +6. 不要使用 `arguments`, 选择使用 rest 语法 `...` 代替。 eslint: [prefer-rest-params](https://eslint.org/docs/rules/prefer-rest-params)
  1490 + > 为什么? `...` 明确了你想要拉取什么参数。 更甚, rest 参数是一个真正的数组,而不仅仅是类数组的 `arguments` 。
  1491 +
  1492 +```js
  1493 +// bad
  1494 +function concatenateAll() {
  1495 + const args = Array.prototype.slice.call(arguments);
  1496 + return args.join("");
  1497 +}
  1498 +
  1499 +// good
  1500 +function concatenateAll(...args) {
  1501 + return args.join("");
  1502 +}
  1503 +```
  1504 +
  1505 +7. 使用默认的参数语法,而不是改变函数参数。
  1506 +
  1507 +```js
  1508 +// really bad
  1509 +function handleThings(opts) {
  1510 + // No! We shouldn’t mutate function arguments.
  1511 + // Double bad: if opts is falsy it'll be set to an object which may
  1512 + // be what you want but it can introduce subtle bugs.
  1513 + opts = opts || {};
  1514 + // ...
  1515 +}
  1516 +
  1517 +// still bad
  1518 +function handleThings(opts) {
  1519 + if (opts === void 0) {
  1520 + opts = {};
  1521 + }
  1522 + // ...
  1523 +}
  1524 +
  1525 +// good
  1526 +function handleThings(opts = {}) {
  1527 + // ...
  1528 +}
  1529 +```
  1530 +
  1531 +8. 避免使用默认参数的副作用。
  1532 + > 为什么? 他们很容易混淆。
  1533 +
  1534 +```js
  1535 +var b = 1;
  1536 +// bad
  1537 +function count(a = b++) {
  1538 + console.log(a);
  1539 +}
  1540 +count(); // 1
  1541 +count(); // 2
  1542 +count(3); // 3
  1543 +count(); // 3
  1544 +```
  1545 +
  1546 +9. 总是把默认参数放在最后。
  1547 +
  1548 +```js
  1549 +// bad
  1550 +function handleThings(opts = {}, name) {
  1551 + // ...
  1552 +}
  1553 +
  1554 +// good
  1555 +function handleThings(name, opts = {}) {
  1556 + // ...
  1557 +}
  1558 +```
  1559 +
  1560 +10. 永远不要使用函数构造器来创建一个新函数。 eslint: [no-new-func](https://eslint.org/docs/rules/no-new-func)
  1561 + > 为什么? 以这种方式创建一个函数将对一个类似于 eval() 的字符串进行计算,这将打开漏洞。
  1562 +
  1563 +```js
  1564 +// bad
  1565 +var add = new Function("a", "b", "return a + b");
  1566 +
  1567 +// still bad
  1568 +var subtract = Function("a", "b", "return a - b");
  1569 +```
  1570 +
  1571 +11. 函数签名中的间距。 eslint: [space-before-function-paren](https://eslint.org/docs/rules/space-before-function-paren) [space-before-blocks](https://eslint.org/docs/rules/space-before-blocks)
  1572 + > 为什么? 一致性很好,在删除或添加名称时不需要添加或删除空格。
  1573 +
  1574 +```js
  1575 +// bad
  1576 +const f = function () {};
  1577 +const g = function () {};
  1578 +const h = function () {};
  1579 +
  1580 +// good
  1581 +const x = function () {};
  1582 +const y = function a() {};
  1583 +```
  1584 +
  1585 +12. 没用变异参数。eslint: [no-param-reassign](https://eslint.org/docs/rules/no-param-reassign.html)
  1586 + > 为什么? 将传入的对象作为参数进行操作可能会在原始调用程序中造成不必要的变量副作用。
  1587 +
  1588 +```js
  1589 +// bad
  1590 +function f1(obj) {
  1591 + obj.key = 1;
  1592 +}
  1593 +
  1594 +// good
  1595 +function f2(obj) {
  1596 + const key = Object.prototype.hasOwnProperty.call(obj, "key") ? obj.key : 1;
  1597 +}
  1598 +```
  1599 +
  1600 +13. 不要再赋值参数。 eslint: [no-param-reassign](https://eslint.org/docs/rules/no-param-reassign.html)
  1601 + > 为什么? 重新赋值参数会导致意外的行为,尤其是在访问 arguments 对象的时候。 它还可能导致性能优化问题,尤其是在 V8 中。
  1602 +
  1603 +```js
  1604 +// bad
  1605 +function f1(a) {
  1606 + a = 1;
  1607 + // ...
  1608 +}
  1609 +
  1610 +function f2(a) {
  1611 + if (!a) {
  1612 + a = 1;
  1613 + }
  1614 + // ...
  1615 +}
  1616 +
  1617 +// good
  1618 +function f3(a) {
  1619 + const b = a || 1;
  1620 + // ...
  1621 +}
  1622 +
  1623 +function f4(a = 1) {
  1624 + // ...
  1625 +}
  1626 +```
  1627 +
  1628 +14. 优先使用扩展运算符 `...` 来调用可变参数函数。 eslint: [prefer-spread](https://eslint.org/docs/rules/prefer-spread)
  1629 + > 为什么? 它更加干净,你不需要提供上下文,并且你不能轻易的使用 `apply` 来 `new` 。
  1630 +
  1631 +```js
  1632 +// bad
  1633 +const x = [1, 2, 3, 4, 5];
  1634 +console.log.apply(console, x);
  1635 +
  1636 +// good
  1637 +const x = [1, 2, 3, 4, 5];
  1638 +console.log(...x);
  1639 +
  1640 +// bad
  1641 +new (Function.prototype.bind.apply(Date, [null, 2016, 8, 5]))();
  1642 +
  1643 +// good
  1644 +new Date(...[2016, 8, 5]);
  1645 +```
  1646 +
  1647 +15. 具有多行签名或者调用的函数应该像本指南中的其他多行列表一样缩进:在一行上只有一个条目,并且每个条目最后加上逗号。eslint: [function-paren-newline](https://eslint.org/docs/rules/function-paren-newline)
  1648 +
  1649 +```js
  1650 +// bad
  1651 +function foo(bar,
  1652 + baz,
  1653 + quux) {
  1654 + // ...
  1655 +}
  1656 +
  1657 +// good
  1658 +function foo(
  1659 + bar,
  1660 + baz,
  1661 + quux,
  1662 +) {
  1663 + // ...
  1664 +}
  1665 +
  1666 +// bad
  1667 +console.log(foo,
  1668 + bar,
  1669 + baz);
  1670 +
  1671 +// good
  1672 +console.log(
  1673 + foo,
  1674 + bar,
  1675 + baz,
  1676 +);
  1677 +```
  1678 +
  1679 +### 箭头函数
  1680 +
  1681 +1. 当你必须使用匿名函数时 (当传递内联函数时), 使用箭头函数。eslint: [prefer-arrow-callback](https://eslint.org/docs/rules/prefer-arrow-callback.html), [arrow-spacing](https://eslint.org/docs/rules/arrow-spacing.html)
  1682 + > 为什么? 它创建了一个在 this 上下文中执行的函数版本,它通常是你想要的,并且是一个更简洁的语法。
  1683 +
  1684 +> 为什么不? 如果你有一个相当复杂的函数,你可以把这个逻辑转移到它自己的命名函数表达式中。
  1685 +
  1686 +```js
  1687 +// bad
  1688 +[1, 2, 3].map(function (x) {
  1689 + const y = x + 1;
  1690 + return x * y;
  1691 +});
  1692 +
  1693 +// good
  1694 +[1, 2, 3].map((x) => {
  1695 + const y = x + 1;
  1696 + return x * y;
  1697 +});
  1698 +```
  1699 +
  1700 +2. 如果函数体包含一个单独的语句,返回一个没有副作用的 [expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#expressions) , 省略括号并使用隐式返回。否则,保留括号并使用 `return` 语句。 eslint: [arrow-parens](https://eslint.org/docs/rules/arrow-parens.html), [arrow-body-style](https://eslint.org/docs/rules/arrow-body-style.html)
  1701 + > 为什么? 语法糖。 多个函数被链接在一起时,提高可读性。
  1702 +
  1703 +```js
  1704 +// bad
  1705 +[1, 2, 3].map((number) => {
  1706 + const nextNumber = number + 1;
  1707 + `A string containing the ${nextNumber}.`;
  1708 +});
  1709 +
  1710 +// good
  1711 +[1, 2, 3].map((number) => `A string containing the ${number}.`);
  1712 +
  1713 +// good
  1714 +[1, 2, 3].map((number) => {
  1715 + const nextNumber = number + 1;
  1716 + return `A string containing the ${nextNumber}.`;
  1717 +});
  1718 +
  1719 +// good
  1720 +[1, 2, 3].map((number, index) => ({
  1721 + [index]: number,
  1722 +}));
  1723 +
  1724 +// 没有副作用的隐式返回
  1725 +function foo(callback) {
  1726 + const val = callback();
  1727 + if (val === true) {
  1728 + // 如果回调返回 true 执行
  1729 + }
  1730 +}
  1731 +
  1732 +let bool = false;
  1733 +
  1734 +// bad
  1735 +foo(() => (bool = true));
  1736 +
  1737 +// good
  1738 +foo(() => {
  1739 + bool = true;
  1740 +});
  1741 +```
  1742 +
  1743 +3. 如果表达式跨越多个行,用括号将其括起来,以获得更好的可读性。
  1744 + > 为什么? 它清楚地显示了函数的起点和终点。
  1745 +
  1746 +```js
  1747 +// bad
  1748 +['get', 'post', 'put'].map(httpMethod => Object.prototype.hasOwnProperty.call(
  1749 + httpMagicObjectWithAVeryLongName,
  1750 + httpMethod,
  1751 + )
  1752 +);
  1753 +
  1754 +// good
  1755 +["get", "post", "put"].map((httpMethod) =>
  1756 + Object.prototype.hasOwnProperty.call(
  1757 + httpMagicObjectWithAVeryLongName,
  1758 + httpMethod
  1759 + )
  1760 +);
  1761 +```
  1762 +
  1763 +4. 如果你的函数接收一个参数,则可以不用括号,省略括号。 否则,为了保证清晰和一致性,需要在参数周围加上括号。 注意:总是使用括号是可以接受的,在这种情况下,我们使用 “always” option 来配置 eslint. eslint: [arrow-parens](https://eslint.org/docs/rules/arrow-parens.html)
  1764 + > 为什么? 减少视觉上的混乱。
  1765 +
  1766 +```js
  1767 +// bad
  1768 +[1, 2, 3].map((x) => x * x);
  1769 +
  1770 +// good
  1771 +[1, 2, 3].map((x) => x * x);
  1772 +
  1773 +// good
  1774 +[1, 2, 3].map(
  1775 + (number) =>
  1776 + `A long string with the ${number}. Its so long that we dont want it to take up space on the .map line!`
  1777 +);
  1778 +
  1779 +// bad
  1780 +[1, 2, 3].map(x => {
  1781 + const y = x + 1;
  1782 + return x * y;
  1783 +});
  1784 +
  1785 +// good
  1786 +[1, 2, 3].map((x) => {
  1787 + const y = x + 1;
  1788 + return x * y;
  1789 +});
  1790 +```
  1791 +
  1792 +5. 避免箭头函数符号 (=>) 和比较运算符 (<=, >=) 的混淆。eslint: [no-confusing-arrow](https://eslint.org/docs/rules/no-confusing-arrow)
  1793 +
  1794 +```js
  1795 +// bad
  1796 +const itemHeight = (item) =>
  1797 + item.height > 256 ? item.largeSize : item.smallSize;
  1798 +
  1799 +// bad
  1800 +const itemHeight = (item) =>
  1801 + item.height > 256 ? item.largeSize : item.smallSize;
  1802 +
  1803 +// good
  1804 +const itemHeight = (item) =>
  1805 + (item.height > 256 ? item.largeSize : item.smallSize);
  1806 +
  1807 +// good
  1808 +const itemHeight = (item) => {
  1809 + const { height, largeSize, smallSize } = item;
  1810 + return height > 256 ? largeSize : smallSize;
  1811 +};
  1812 +```
  1813 +
  1814 +6. 注意带有隐式返回的箭头函数函数体的位置。eslint: [implicit-arrow-linebreak](https://eslint.org/docs/rules/implicit-arrow-linebreak)
  1815 +
  1816 +```js
  1817 +// bad
  1818 +(foo) =>
  1819 + bar;
  1820 +
  1821 +(foo) =>
  1822 + (bar);
  1823 +
  1824 +// good
  1825 +(foo) => bar;
  1826 +(foo) => (bar);
  1827 +(foo) => (
  1828 + bar
  1829 +)
  1830 +```
  1831 +
  1832 +### 类和构造器
  1833 +
  1834 +1. 尽量使用 `class`. 避免直接操作 `prototype` .
  1835 + > 为什么? class 语法更简洁,更容易推理。
  1836 +
  1837 +```js
  1838 +// bad
  1839 +function Queue(contents = []) {
  1840 + this.queue = [...contents];
  1841 +}
  1842 +Queue.prototype.pop = function () {
  1843 + const value = this.queue[0];
  1844 + this.queue.splice(0, 1);
  1845 + return value;
  1846 +};
  1847 +
  1848 +// good
  1849 +class Queue {
  1850 + constructor(contents = []) {
  1851 + this.queue = [...contents];
  1852 + }
  1853 + pop() {
  1854 + const value = this.queue[0];
  1855 + this.queue.splice(0, 1);
  1856 + return value;
  1857 + }
  1858 +}
  1859 +```
  1860 +
  1861 +2. 使用 extends 来扩展继承。
  1862 + > 为什么? 它是一个内置的方法,可以在不破坏 instanceof 的情况下继承原型功能。
  1863 +
  1864 +```js
  1865 +// bad
  1866 +const inherits = require("inherits");
  1867 +function PeekableQueue(contents) {
  1868 + Queue.apply(this, contents);
  1869 +}
  1870 +inherits(PeekableQueue, Queue);
  1871 +PeekableQueue.prototype.peek = function () {
  1872 + return this.queue[0];
  1873 +};
  1874 +
  1875 +// good
  1876 +class PeekableQueue extends Queue {
  1877 + peek() {
  1878 + return this.queue[0];
  1879 + }
  1880 +}
  1881 +```
  1882 +
  1883 +3. 方法返回了 this 来供其内部方法调用。
  1884 +
  1885 +```js
  1886 +// bad
  1887 +Jedi.prototype.jump = function () {
  1888 + this.jumping = true;
  1889 + return true;
  1890 +};
  1891 +
  1892 +Jedi.prototype.setHeight = function (height) {
  1893 + this.height = height;
  1894 +};
  1895 +
  1896 +const luke = new Jedi();
  1897 +luke.jump(); // => true
  1898 +luke.setHeight(20); // => undefined
  1899 +
  1900 +// good
  1901 +class Jedi {
  1902 + jump() {
  1903 + this.jumping = true;
  1904 + return this;
  1905 + }
  1906 +
  1907 + setHeight(height) {
  1908 + this.height = height;
  1909 + return this;
  1910 + }
  1911 +}
  1912 +
  1913 +const luke = new Jedi();
  1914 +
  1915 +luke.jump().setHeight(20);
  1916 +```
  1917 +
  1918 +4. 只要在确保能正常工作并且不产生任何副作用的情况下,编写一个自定义的 `toString()` 方法也是可以的。
  1919 +
  1920 +```js
  1921 +class Jedi {
  1922 + constructor(options = {}) {
  1923 + this.name = options.name || "no name";
  1924 + }
  1925 +
  1926 + getName() {
  1927 + return this.name;
  1928 + }
  1929 +
  1930 + toString() {
  1931 + return `Jedi - ${this.getName()}`;
  1932 + }
  1933 +}
  1934 +```
  1935 +
  1936 +5. 如果没有指定类,则类具有默认的构造器。 一个空的构造器或是一个代表父类的函数是没有必要的。eslint: [no-useless-constructor](https://eslint.org/docs/rules/no-useless-constructor)
  1937 +
  1938 +```js
  1939 +// bad
  1940 +class Jedi {
  1941 + constructor() {}
  1942 +
  1943 + getName() {
  1944 + return this.name;
  1945 + }
  1946 +}
  1947 +
  1948 +// bad
  1949 +class Rey extends Jedi {
  1950 + constructor(...args) {
  1951 + super(...args);
  1952 + }
  1953 +}
  1954 +
  1955 +// good
  1956 +class Rey extends Jedi {
  1957 + constructor(...args) {
  1958 + super(...args);
  1959 + this.name = "Rey";
  1960 + }
  1961 +}
  1962 +```
  1963 +
  1964 +6. 避免定义重复的类成员。eslint: [no-dupe-class-members](https://eslint.org/docs/rules/no-dupe-class-members)
  1965 + > 为什么? 重复的类成员声明将会默认倾向于最后一个 - 具有重复的类成员可以说是一个错误。
  1966 +
  1967 +```js
  1968 +// bad
  1969 +class Foo {
  1970 + bar() {
  1971 + return 1;
  1972 + }
  1973 + bar() {
  1974 + return 2;
  1975 + }
  1976 +}
  1977 +
  1978 +// good
  1979 +class Foo {
  1980 + bar() {
  1981 + return 1;
  1982 + }
  1983 +}
  1984 +
  1985 +// good
  1986 +class Foo {
  1987 + bar() {
  1988 + return 2;
  1989 + }
  1990 +}
  1991 +```
  1992 +
  1993 +### 模块
  1994 +
  1995 +1. 你可能经常使用模块 (`import/export`) 在一些非标准模块的系统上。 你也可以在你喜欢的模块系统上相互转换。
  1996 + > 为什么? 模块是未来的趋势,让我们拥抱未来。
  1997 +
  1998 +```js
  1999 +// bad
  2000 +const AirbnbStyleGuide = require('./AirbnbStyleGuide');
  2001 +module.exports = AirbnbStyleGuide.es6;
  2002 +
  2003 +// ok
  2004 +import AirbnbStyleGuide from './AirbnbStyleGuide';
  2005 +export default AirbnbStyleGuide.es6;
  2006 +
  2007 +// best
  2008 +import { es6 } from './AirbnbStyleGuide';
  2009 +export default es6;
  2010 +```
  2011 +
  2012 +2. 不要直接从导入导出。
  2013 + > 为什么? 虽然写在一行很简洁,但是有一个明确的导入和一个明确的导出能够保证一致性。
  2014 +
  2015 +```js
  2016 +// bad
  2017 +// filename es6.js
  2018 +export { es6 as default } from './AirbnbStyleGuide';
  2019 +
  2020 +// good
  2021 +// filename es6.js
  2022 +import { es6 } from './AirbnbStyleGuide';
  2023 +export default es6;
  2024 +```
  2025 +
  2026 +3. 只从一个路径导入所有需要的东西。eslint: [no-duplicate-imports](https://eslint.org/docs/rules/no-duplicate-imports)
  2027 + > 为什么? 从同一个路径导入多个行,使代码更难以维护。
  2028 +
  2029 +```js
  2030 +// bad
  2031 +import foo from "foo";
  2032 +// … 其他导入 … //
  2033 +import { named1, named2 } from "foo";
  2034 +
  2035 +// good
  2036 +import foo, { named1, named2 } from "foo";
  2037 +
  2038 +// good
  2039 +import foo, { named1, named2 } from "foo";
  2040 +```
  2041 +
  2042 +4. 不要导出可变的引用。eslint: [import/no-mutable-exports](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-mutable-exports.md)
  2043 + > 为什么? 在一般情况下,应该避免发生突变,但是在导出可变引用时及其容易发生突变。虽然在某些特殊情况下,可能需要这样,但是一般情况下只需要导出常量引用。
  2044 +
  2045 +```js
  2046 +// bad
  2047 +let foo = 3;
  2048 +export { foo };
  2049 +
  2050 +// good
  2051 +const foo = 3;
  2052 +export { foo };
  2053 +```
  2054 +
  2055 +5. 在单个导出的模块中,选择默认模块而不是指定的导出。eslint: [import/prefer-default-export](https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/prefer-default-export.md)
  2056 + > 为什么? 在一般情况下,应该避免发生突变,但是在导出可变引用时及其容易发生突变。虽然在某些特殊情况下,可能需要这样,但是一般情况下只需要导出常量引用。
  2057 +
  2058 +```js
  2059 +// bad
  2060 +let foo = 3;
  2061 +export { foo };
  2062 +
  2063 +// good
  2064 +const foo = 3;
  2065 +export { foo };
  2066 +```
  2067 +
  2068 +6. 将所有的 `imports` 语句放在所有非导入语句的上边。eslint: [import/first](https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/first.md)
  2069 + > 为什么? 由于所有的 imports 都被提前,保持他们在顶部是为了防止意外发生
  2070 +
  2071 +```js
  2072 +// bad
  2073 +import foo from "foo";
  2074 +foo.init();
  2075 +
  2076 +import bar from "bar";
  2077 +
  2078 +// good
  2079 +import foo from "foo";
  2080 +import bar from "bar";
  2081 +
  2082 +foo.init();
  2083 +```
  2084 +
  2085 +8. 多行导入应该像多行数组和对象一样缩进。
  2086 + > 为什么? 花括号和其他规范一样,遵循相同的缩进规则,后边的都好一样。
  2087 +
  2088 +```js
  2089 +// bad
  2090 +import { longNameA, longNameB, longNameC, longNameD, longNameE } from "path";
  2091 +
  2092 +// good
  2093 +import { longNameA, longNameB, longNameC, longNameD, longNameE } from "path";
  2094 +```
  2095 +
  2096 +9. 在模块导入语句中禁止使用 Webpack 加载器语法。eslint: [import/no-webpack-loader-syntax](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-webpack-loader-syntax.md)
  2097 + > 为什么? 因为在导入语句中使用 webpack 语法,将代码和模块绑定在一起。应该在 webpack.config.js 中使用加载器语法。
  2098 +
  2099 +```js
  2100 +// bad
  2101 +import fooSass from "css!sass!foo.scss";
  2102 +import barCss from "style!css!bar.css";
  2103 +
  2104 +// good
  2105 +import fooSass from "foo.scss";
  2106 +import barCss from "bar.css";
  2107 +```
  2108 +
  2109 +### 属性
  2110 +
  2111 +1. 访问属性时使用点符号。eslint: [dot-notation](https://eslint.org/docs/rules/dot-notation.html)
  2112 +
  2113 +```js
  2114 +const luke = {
  2115 + jedi: true,
  2116 + age: 28,
  2117 +};
  2118 +
  2119 +// bad
  2120 +const isJedi = luke["jedi"];
  2121 +
  2122 +// good
  2123 +const isJedi = luke.jedi;
  2124 +```
  2125 +
  2126 +2. 使用变量访问属性时,使用 `[]`表示法。
  2127 +
  2128 +```js
  2129 +const luke = {
  2130 + jedi: true,
  2131 + age: 28,
  2132 +};
  2133 +
  2134 +function getProp(prop) {
  2135 + return luke[prop];
  2136 +}
  2137 +
  2138 +const isJedi = getProp("jedi");
  2139 +```
  2140 +
  2141 +3. 计算指数时,可以使用 `**` 运算符。eslint: [no-restricted-properties](https://eslint.org/docs/rules/no-restricted-properties)
  2142 +
  2143 +```js
  2144 +// bad
  2145 +const binary = Math.pow(2, 10);
  2146 +
  2147 +// good
  2148 +const binary = 2 ** 10;
  2149 +```
  2150 +
  2151 +### 变量
  2152 +
  2153 +1. 使用 `const` 或者 `let` 来定义变量。 不这样做将创建一个全局变量。 我们希望避免污染全局命名空间。 Captain Planet 警告过我们。 eslint: [no-undef](https://eslint.org/docs/rules/no-undef) [prefer-const](https://eslint.org/docs/rules/prefer-const)
  2154 +
  2155 +```js
  2156 +// bad
  2157 +superPower = new SuperPower();
  2158 +
  2159 +// good
  2160 +const superPower = new SuperPower();
  2161 +```
  2162 +
  2163 +2. 使用 const 或者 let 声明每一个变量。eslint: [one-var](https://eslint.org/docs/rules/one-var.html)
  2164 + > 为什么? 这样更容易添加新的变量声明,而且你不必担心是使用 ; 还是使用 , 或引入标点符号的差别。 你可以通过 debugger 逐步查看每个声明,而不是立即跳过所有声明。
  2165 +
  2166 +```js
  2167 +// bad
  2168 +const items = getItems(),
  2169 + goSportsTeam = true,
  2170 + dragonball = "z";
  2171 +
  2172 +// bad
  2173 +// (compare to above, and try to spot the mistake)
  2174 +const items = getItems(),
  2175 + goSportsTeam = true;
  2176 + dragonball = "z";
  2177 +
  2178 +// good
  2179 +const items = getItems();
  2180 +const goSportsTeam = true;
  2181 +const dragonball = "z";
  2182 +```
  2183 +
  2184 +3. 把 const 声明的放在一起,把 let 声明的放在一起。
  2185 + > 为什么? 这在后边如果需要根据前边的赋值变量指定一个变量时很有用。
  2186 +
  2187 +```js
  2188 +// bad
  2189 +let i,
  2190 + len,
  2191 + dragonball,
  2192 + items = getItems(),
  2193 + goSportsTeam = true;
  2194 +
  2195 +// bad
  2196 +let i;
  2197 +const items = getItems();
  2198 +let dragonball;
  2199 +const goSportsTeam = true;
  2200 +let len;
  2201 +
  2202 +// good
  2203 +const goSportsTeam = true;
  2204 +const items = getItems();
  2205 +let dragonball;
  2206 +let i;
  2207 +let length;
  2208 +```
  2209 +
  2210 +4. 在你需要的使用定义变量,但是要把它们放在一个合理的地方。
  2211 + > 为什么? `let` 和 `const` 是块级作用域而不是函数作用域。
  2212 +
  2213 +```js
  2214 +// bad - 不必要的函数调用
  2215 +function checkName(hasName) {
  2216 + const name = getName();
  2217 +
  2218 + if (hasName === "test") {
  2219 + return false;
  2220 + }
  2221 +
  2222 + if (name === "test") {
  2223 + this.setName("");
  2224 + return false;
  2225 + }
  2226 +
  2227 + return name;
  2228 +}
  2229 +
  2230 +// good
  2231 +function checkName(hasName) {
  2232 + if (hasName === "test") {
  2233 + return false;
  2234 + }
  2235 +
  2236 + const name = getName();
  2237 +
  2238 + if (name === "test") {
  2239 + this.setName("");
  2240 + return false;
  2241 + }
  2242 +
  2243 + return name;
  2244 +}
  2245 +```
  2246 +
  2247 +5. 不要链式变量赋值。eslint: [no-multi-assign](https://eslint.org/docs/rules/no-multi-assign)
  2248 + > 为什么? 链式变量赋值会创建隐式全局变量。
  2249 +
  2250 +```js
  2251 +// bad
  2252 +(function example() {
  2253 + // JavaScript 把它解释为
  2254 + // let a = ( b = ( c = 1 ) );
  2255 + // let 关键词只适用于变量 a ;变量 b 和变量 c 则变成了全局变量。
  2256 + let a = (b = c = 1);
  2257 +})();
  2258 +
  2259 +console.log(a); // throws ReferenceError
  2260 +console.log(b); // 1
  2261 +console.log(c); // 1
  2262 +
  2263 +// good
  2264 +(function example() {
  2265 + let a = 1;
  2266 + let b = a;
  2267 + let c = a;
  2268 +})();
  2269 +
  2270 +console.log(a); // throws ReferenceError
  2271 +console.log(b); // throws ReferenceError
  2272 +console.log(c); // throws ReferenceError
  2273 +
  2274 +// 对于 `const` 也一样
  2275 +```
  2276 +
  2277 +6. 避免使用不必要的递增和递减 (++, --)。 eslint [no-plusplus](https://eslint.org/docs/rules/no-plusplus)
  2278 + > 为什么? 在 eslint 文档中,一元递增和递减语句以自动分号插入为主题,并且在应用程序中可能会导致默认值的递增或递减。它还可以用像 num += 1 这样的语句来改变您的值,而不是使用 num++ 或 num ++ 。不允许不必要的增量和减量语句也会使您无法预先递增/预递减值,这也会导致程序中的意外行为。
  2279 +
  2280 +```js
  2281 +// bad
  2282 +
  2283 +const array = [1, 2, 3];
  2284 +let num = 1;
  2285 +num++;
  2286 +--num;
  2287 +
  2288 +let sum = 0;
  2289 +let truthyCount = 0;
  2290 +for (let i = 0; i < array.length; i++) {
  2291 + let value = array[i];
  2292 + sum += value;
  2293 + if (value) {
  2294 + truthyCount++;
  2295 + }
  2296 +}
  2297 +
  2298 +// good
  2299 +
  2300 +const array = [1, 2, 3];
  2301 +let num = 1;
  2302 +num += 1;
  2303 +num -= 1;
  2304 +
  2305 +const sum = array.reduce((a, b) => a + b, 0);
  2306 +const truthyCount = array.filter(Boolean).length;
  2307 +```
  2308 +
  2309 +7. 避免在赋值语句 `=` 前后换行。如果你的代码违反了 `max-len`, 使用括号包裹。eslint [operator-linebreak](https://eslint.org/docs/rules/operator-linebreak.html)
  2310 + > 为什么? 在 = 前后换行,可能混淆赋的值。
  2311 +
  2312 +```js
  2313 +// bad
  2314 +const foo = superLongLongLongLongLongLongLongLongFunctionName();
  2315 +
  2316 +// bad
  2317 +const foo = "superLongLongLongLongLongLongLongLongString";
  2318 +
  2319 +// good
  2320 +const foo = superLongLongLongLongLongLongLongLongFunctionName();
  2321 +
  2322 +// good
  2323 +const foo = "superLongLongLongLongLongLongLongLongString";
  2324 +```
  2325 +
  2326 +### 提升
  2327 +
  2328 +1. var 定义的变量会被提升到函数范围的最顶部,但是它的赋值不会。`const` 和 `let` 声明的变量受到一个称之为 [Temporal Dead Zones (TDZ)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#Temporal_Dead_Zone_and_errors_with_let) 的新概念保护。 知道为什么 [typeof](https://es.discourse.group/t/about-the-proposals-category/15) 不再安全 是很重要的。
  2329 +
  2330 +```js
  2331 +// 我们知道这个行不通 (假设没有未定义的全局变量)
  2332 +function example() {
  2333 + console.log(notDefined); // => throws a ReferenceError
  2334 +}
  2335 +
  2336 +// 在引用变量后创建变量声明将会因变量提升而起作用。
  2337 +// 注意: 真正的值 `true` 不会被提升。
  2338 +function example() {
  2339 + console.log(declaredButNotAssigned); // => undefined
  2340 + var declaredButNotAssigned = true;
  2341 +}
  2342 +
  2343 +// 解释器将变量提升到函数的顶部
  2344 +// 这意味着我们可以将上边的例子重写为:
  2345 +function example() {
  2346 + let declaredButNotAssigned;
  2347 + console.log(declaredButNotAssigned); // => undefined
  2348 + declaredButNotAssigned = true;
  2349 +}
  2350 +
  2351 +// 使用 const 和 let
  2352 +function example() {
  2353 + console.log(declaredButNotAssigned); // => throws a ReferenceError
  2354 + console.log(typeof declaredButNotAssigned); // => throws a ReferenceError
  2355 + const declaredButNotAssigned = true;
  2356 +}
  2357 +```
  2358 +
  2359 +2. 匿名函数表达式提升变量名,而不是函数赋值。
  2360 +
  2361 +```js
  2362 +function example() {
  2363 + console.log(anonymous); // => undefined
  2364 +
  2365 + anonymous(); // => TypeError anonymous is not a function
  2366 +
  2367 + var anonymous = function () {
  2368 + console.log("anonymous function expression");
  2369 + };
  2370 +}
  2371 +```
  2372 +
  2373 +3. 命名函数表达式提升的是变量名,而不是函数名或者函数体。
  2374 +
  2375 +```js
  2376 +function example() {
  2377 + console.log(named); // => undefined
  2378 +
  2379 + named(); // => TypeError named is not a function
  2380 +
  2381 + superPower(); // => ReferenceError superPower is not defined
  2382 +
  2383 + var named = function superPower() {
  2384 + console.log("Flying");
  2385 + };
  2386 +}
  2387 +
  2388 +// 当函数名和变量名相同时也是如此。
  2389 +function example() {
  2390 + console.log(named); // => undefined
  2391 +
  2392 + named(); // => TypeError named is not a function
  2393 +
  2394 + var named = function named() {
  2395 + console.log("named");
  2396 + };
  2397 +}
  2398 +```
  2399 +
  2400 +4. 函数声明提升其名称和函数体。
  2401 +
  2402 +```js
  2403 +function example() {
  2404 + superPower(); // => Flying
  2405 +
  2406 + function superPower() {
  2407 + console.log("Flying");
  2408 + }
  2409 +}
  2410 +```
  2411 +
  2412 +### 比较运算符和等号
  2413 +
  2414 +1. 使用 === 和 !== 而不是 == 和 !=。 eslint: [eqeqeq](https://eslint.org/docs/rules/eqeqeq.html)
  2415 +2. 条件语句,例如 if 语句使用 ToBoolean 的抽象方法来计算表达式的结果,并始终遵循以下简单的规则:
  2416 + - Objects 的取值为: true
  2417 + - Undefined 的取值为: false
  2418 + - Null 的取值为: false
  2419 + - Booleans 的取值为: 布尔值的取值
  2420 + - Numbers 的取值为:如果为 +0, -0, or NaN 值为 false 否则为 true
  2421 + - Strings 的取值为: 如果是一个空字符串 '' 值为 false 否则为 true
  2422 +
  2423 +```js
  2424 +if ([0] && []) {
  2425 + // true
  2426 + // 一个数组(即使是空的)是一个对象,对象的取值为 true
  2427 +}
  2428 +```
  2429 +
  2430 +3. 对于布尔值使用简写,但是对于字符串和数字进行显式比较。
  2431 +
  2432 +```js
  2433 +// bad
  2434 +if (isValid === true) {
  2435 + // ...
  2436 +}
  2437 +
  2438 +// good
  2439 +if (isValid) {
  2440 + // ...
  2441 +}
  2442 +
  2443 +// bad
  2444 +if (name) {
  2445 + // ...
  2446 +}
  2447 +
  2448 +// good
  2449 +if (name !== "") {
  2450 + // ...
  2451 +}
  2452 +
  2453 +// bad
  2454 +if (collection.length) {
  2455 + // ...
  2456 +}
  2457 +
  2458 +// good
  2459 +if (collection.length > 0) {
  2460 + // ...
  2461 +}
  2462 +```
  2463 +
  2464 +4. 在 case 和 default 的子句中,如果存在声明 (例如. let, const, function, 和 class),使用大括号来创建块eslint: [no-case-declarations](https://eslint.org/docs/rules/no-case-declarations.html)
  2465 + > 为什么? 语法声明在整个 switch 块中都是可见的,但是只有在赋值的时候才会被初始化,这种情况只有在 case 条件达到才会发生。 当多个 case 语句定义相同的东西是,这会导致问题问题。
  2466 +
  2467 +```js
  2468 +// bad
  2469 +switch (foo) {
  2470 + case 1:
  2471 + let x = 1;
  2472 + break;
  2473 + case 2:
  2474 + const y = 2;
  2475 + break;
  2476 + case 3:
  2477 + function f() {
  2478 + // ...
  2479 + }
  2480 + break;
  2481 + default:
  2482 + class C {}
  2483 +}
  2484 +
  2485 +// good
  2486 +switch (foo) {
  2487 + case 1: {
  2488 + let x = 1;
  2489 + break;
  2490 + }
  2491 + case 2: {
  2492 + const y = 2;
  2493 + break;
  2494 + }
  2495 + case 3: {
  2496 + function f() {
  2497 + // ...
  2498 + }
  2499 + break;
  2500 + }
  2501 + case 4:
  2502 + bar();
  2503 + break;
  2504 + default: {
  2505 + class C {}
  2506 + }
  2507 +}
  2508 +```
  2509 +
  2510 +5. 三目表达式不应该嵌套,通常是单行表达式。eslint: [no-nested-ternary](https://eslint.org/docs/rules/no-nested-ternary.html)
  2511 +
  2512 +```js
  2513 +// bad
  2514 +const foo = maybe1 > maybe2 ? "bar" : value1 > value2 ? "baz" : null;
  2515 +
  2516 +// 分离为两个三目表达式
  2517 +const maybeNull = value1 > value2 ? "baz" : null;
  2518 +
  2519 +// better
  2520 +const foo = maybe1 > maybe2 ? "bar" : maybeNull;
  2521 +
  2522 +// best
  2523 +const foo = maybe1 > maybe2 ? "bar" : maybeNull;
  2524 +```
  2525 +
  2526 +6. 避免不必要的三目表达式。eslint: [no-unneeded-ternary](https://eslint.org/docs/rules/no-unneeded-ternary.html)
  2527 +
  2528 +```js
  2529 +// bad
  2530 +const foo = a ? a : b;
  2531 +const bar = c ? true : false;
  2532 +const baz = c ? false : true;
  2533 +
  2534 +// good
  2535 +const foo = a || b;
  2536 +const bar = !!c;
  2537 +const baz = !c;
  2538 +```
  2539 +
  2540 +7. 使用该混合运算符时,使用括号括起来。 唯一例外的是标准算数运算符 ```(+, -, \*, & /)``` 因为他们的优先级被广泛理解。 eslint: [no-mixed-operators](https://eslint.org/docs/rules/no-mixed-operators.html)
  2541 + > 为什么? 这能提高可读性并且表明开发人员的意图。
  2542 +
  2543 +```js
  2544 +// bad
  2545 +const foo = (a && b < 0) || c > 0 || d + 1 === 0;
  2546 +
  2547 +// bad
  2548 +const bar = a ** b - (5 % d);
  2549 +
  2550 +// bad
  2551 +// 可能陷入一种 (a || b) && c 的思考
  2552 +if (a || (b && c)) {
  2553 + return d;
  2554 +}
  2555 +
  2556 +// good
  2557 +const foo = (a && b < 0) || c > 0 || d + 1 === 0;
  2558 +
  2559 +// good
  2560 +const bar = a ** b - (5 % d);
  2561 +
  2562 +// good
  2563 +if (a || (b && c)) {
  2564 + return d;
  2565 +}
  2566 +
  2567 +// good
  2568 +const bar = a + (b / c) * d;
  2569 +```
  2570 +
  2571 +### 块
  2572 +
  2573 +1. 当有多行代码块的时候,使用大括号包裹。eslint: [nonblock-statement-body-position](https://eslint.org/docs/rules/nonblock-statement-body-position)
  2574 +
  2575 +```js
  2576 +// bad
  2577 +if (test) return false;
  2578 +
  2579 +// good
  2580 +if (test) return false;
  2581 +
  2582 +// good
  2583 +if (test) {
  2584 + return false;
  2585 +}
  2586 +
  2587 +// bad
  2588 +function foo() {
  2589 + return false;
  2590 +}
  2591 +
  2592 +// good
  2593 +function bar() {
  2594 + return false;
  2595 +}
  2596 +```
  2597 +
  2598 +2. 如果你使用的是 if 和 else 的多行代码块,则将 else 语句放在 if 块闭括号同一行的位置。eslint: [brace-style](https://eslint.org/docs/rules/brace-style.html)
  2599 +
  2600 +```js
  2601 +// bad
  2602 +if (test) {
  2603 + thing1();
  2604 + thing2();
  2605 +} else {
  2606 + thing3();
  2607 +}
  2608 +
  2609 +// good
  2610 +if (test) {
  2611 + thing1();
  2612 + thing2();
  2613 +} else {
  2614 + thing3();
  2615 +}
  2616 +```
  2617 +
  2618 +3. 如果一个 if 块总是执行一个 return 语句,那么接下来的 else 块就没有必要了。 如果一个包含 return 语句的 else if 块,在一个包含了 return 语句的 if 块之后,那么可以拆成多个 if 块。 eslint: [no-else-return](https://eslint.org/docs/rules/no-else-return)
  2619 +
  2620 +```js
  2621 +// bad
  2622 +function foo() {
  2623 + if (x) {
  2624 + return x;
  2625 + } else {
  2626 + return y;
  2627 + }
  2628 +}
  2629 +
  2630 +// bad
  2631 +function cats() {
  2632 + if (x) {
  2633 + return x;
  2634 + } else if (y) {
  2635 + return y;
  2636 + }
  2637 +}
  2638 +
  2639 +// bad
  2640 +function dogs() {
  2641 + if (x) {
  2642 + return x;
  2643 + } else {
  2644 + if (y) {
  2645 + return y;
  2646 + }
  2647 + }
  2648 +}
  2649 +
  2650 +// good
  2651 +function foo() {
  2652 + if (x) {
  2653 + return x;
  2654 + }
  2655 +
  2656 + return y;
  2657 +}
  2658 +
  2659 +// good
  2660 +function cats() {
  2661 + if (x) {
  2662 + return x;
  2663 + }
  2664 +
  2665 + if (y) {
  2666 + return y;
  2667 + }
  2668 +}
  2669 +
  2670 +// good
  2671 +function dogs(x) {
  2672 + if (x) {
  2673 + if (z) {
  2674 + return y;
  2675 + }
  2676 + } else {
  2677 + return z;
  2678 + }
  2679 +}
  2680 +```
  2681 +
  2682 +### 控制语句
  2683 +
  2684 +1. 如果你的控制语句 (if, while 等) 太长或者超过了一行最大长度的限制,则可以将每个条件(或组)放入一个新的行。 逻辑运算符应该在行的开始。
  2685 + > 为什么? 要求操作符在行的开始保持对齐并遵循类似方法衔接的模式。 这提高了可读性,并且使更复杂的逻辑更容易直观的被理解。
  2686 +
  2687 +```js
  2688 +// bad
  2689 +if (
  2690 + (foo === 123 || bar === "abc") &&
  2691 + doesItLookGoodWhenItBecomesThatLong() &&
  2692 + isThisReallyHappening()
  2693 +) {
  2694 + thing1();
  2695 +}
  2696 +
  2697 +// bad
  2698 +if (foo === 123 && bar === "abc") {
  2699 + thing1();
  2700 +}
  2701 +
  2702 +// bad
  2703 +if (foo === 123 && bar === "abc") {
  2704 + thing1();
  2705 +}
  2706 +
  2707 +// bad
  2708 +if (foo === 123 && bar === "abc") {
  2709 + thing1();
  2710 +}
  2711 +
  2712 +// good
  2713 +if (foo === 123 && bar === "abc") {
  2714 + thing1();
  2715 +}
  2716 +
  2717 +// good
  2718 +if (
  2719 + (foo === 123 || bar === "abc") &&
  2720 + doesItLookGoodWhenItBecomesThatLong() &&
  2721 + isThisReallyHappening()
  2722 +) {
  2723 + thing1();
  2724 +}
  2725 +
  2726 +// good
  2727 +if (foo === 123 && bar === "abc") {
  2728 + thing1();
  2729 +}
  2730 +```
  2731 +
  2732 +### 注释
  2733 +
  2734 +1. 使用 `/** ... */` 来进行多行注释。
  2735 +
  2736 +```js
  2737 +// bad
  2738 +// make() returns a new element
  2739 +// based on the passed in tag name
  2740 +//
  2741 +// @param {String} tag
  2742 +// @return {Element} element
  2743 +function make(tag) {
  2744 + // ...
  2745 +
  2746 + return element;
  2747 +}
  2748 +
  2749 +// good
  2750 +/**
  2751 + * make() returns a new element
  2752 + * based on the passed-in tag name
  2753 + */
  2754 +function make(tag) {
  2755 + // ...
  2756 +
  2757 + return element;
  2758 +}
  2759 +```
  2760 +
  2761 +2. 使用 // 进行单行注释。 将单行注释放在需要注释的行的上方新行。 在注释之前放一个空行,除非它在块的第一行。
  2762 +
  2763 +```js
  2764 +// bad
  2765 +const active = true; // is current tab
  2766 +
  2767 +// good
  2768 +// is current tab
  2769 +const active = true;
  2770 +
  2771 +// bad
  2772 +function getType() {
  2773 + console.log("fetching type...");
  2774 + // set the default type to 'no type'
  2775 + const type = this.type || "no type";
  2776 +
  2777 + return type;
  2778 +}
  2779 +
  2780 +// good
  2781 +function getType() {
  2782 + console.log("fetching type...");
  2783 +
  2784 + // set the default type to 'no type'
  2785 + const type = this.type || "no type";
  2786 +
  2787 + return type;
  2788 +}
  2789 +
  2790 +// also good
  2791 +function getType() {
  2792 + // set the default type to 'no type'
  2793 + const type = this.type || "no type";
  2794 +
  2795 + return type;
  2796 +}
  2797 +```
  2798 +
  2799 +3. 用一个空格开始所有的注释,使它更容易阅读。
  2800 +
  2801 +```js
  2802 +// bad
  2803 +//is current tab
  2804 +const active = true;
  2805 +
  2806 +// good
  2807 +// is current tab
  2808 +const active = true;
  2809 +
  2810 +// bad
  2811 +/**
  2812 + *make() returns a new element
  2813 + *based on the passed-in tag name
  2814 + */
  2815 +function make(tag) {
  2816 + // ...
  2817 +
  2818 + return element;
  2819 +}
  2820 +
  2821 +// good
  2822 +/**
  2823 + * make() returns a new element
  2824 + * based on the passed-in tag name
  2825 + */
  2826 +function make(tag) {
  2827 + // ...
  2828 +
  2829 + return element;
  2830 +}
  2831 +```
  2832 +
  2833 +4. 使用 // FIXME: 注释一个问题。
  2834 +
  2835 +```js
  2836 +class Calculator extends Abacus {
  2837 + constructor() {
  2838 + super();
  2839 +
  2840 + // FIXME: 这里不应该使用全局变量
  2841 + total = 0;
  2842 + }
  2843 +}
  2844 +```
  2845 +
  2846 +5. 使用 // TODO: 注释解决问题的方法。
  2847 +
  2848 +```js
  2849 +class Calculator extends Abacus {
  2850 + constructor() {
  2851 + super();
  2852 +
  2853 + // TODO: total 应该由一个 param 的选项配置
  2854 + this.total = 0;
  2855 + }
  2856 +}
  2857 +```
  2858 +
  2859 +### 空白
  2860 +
  2861 +1. 使用 tabs (空格字符) 设置为 2 个空格。eslint: [indent](https://eslint.org/docs/rules/indent.html)
  2862 +
  2863 +```js
  2864 +// bad
  2865 +function foo() {
  2866 +∙∙∙∙let name;
  2867 +}
  2868 +
  2869 +// bad
  2870 +function bar() {
  2871 +let name;
  2872 +}
  2873 +
  2874 +// good
  2875 +function baz() {
  2876 +∙∙let name;
  2877 +}
  2878 +```
  2879 +
  2880 +2. 在主体前放置一个空格。 eslint: [space-before-blocks](https://eslint.org/docs/rules/space-before-blocks.html)
  2881 +
  2882 +```js
  2883 +// bad
  2884 +function test(){
  2885 + console.log("test");
  2886 +}
  2887 +
  2888 +// good
  2889 +function test() {
  2890 + console.log("test");
  2891 +}
  2892 +
  2893 +// bad
  2894 +dog.set("attr",{
  2895 + age: "1 year",
  2896 + breed: "Bernese Mountain Dog",
  2897 +});
  2898 +
  2899 +// good
  2900 +dog.set("attr", {
  2901 + age: "1 year",
  2902 + breed: "Bernese Mountain Dog",
  2903 +});
  2904 +```
  2905 +
  2906 +3. 在控制语句(if, while 等)开始括号之前放置一个空格。 在函数调用和是声明中,在参数列表和函数名之间没有空格eslint: [keyword-spacing](https://eslint.org/docs/rules/keyword-spacing.html)
  2907 +
  2908 +```js
  2909 +// bad
  2910 +if(isJedi) {
  2911 + fight();
  2912 +}
  2913 +
  2914 +// good
  2915 +if (isJedi) {
  2916 + fight();
  2917 +}
  2918 +
  2919 +// bad
  2920 +function fight () {
  2921 + console.log ("Swooosh!");
  2922 +}
  2923 +
  2924 +// good
  2925 +function fight() {
  2926 + console.log("Swooosh!");
  2927 +}
  2928 +```
  2929 +
  2930 +4. 用空格分离操作符。eslint: [space-infix-ops](https://eslint.org/docs/rules/space-infix-ops.html)
  2931 +
  2932 +```js
  2933 +// bad
  2934 +const x=y+5;
  2935 +
  2936 +// good
  2937 +const x = y + 5;
  2938 +```
  2939 +
  2940 +5. 使用单个换行符结束文件。eslint: [eol-last](https://github.com/eslint/eslint/blob/master/docs/rules/eol-last.md)
  2941 +
  2942 +```js
  2943 +// bad
  2944 +import { es6 } from './AirbnbStyleGuide';
  2945 + // ...
  2946 +export default es6;
  2947 +
  2948 +// bad
  2949 +import { es6 } from './AirbnbStyleGuide';
  2950 + // ...
  2951 +export default es6;
  2952 +
  2953 +// good
  2954 +import { es6 } from './AirbnbStyleGuide';
  2955 + // ...
  2956 +export default es6;
  2957 +```
  2958 +
  2959 +6. 在使用链式方法调用的时候使用缩进(超过两个方法链)。 使用一个引导点,强调该行是方法调用,而不是新的语句。eslint: [newline-per-chained-call](https://eslint.org/docs/rules/newline-per-chained-call) [no-whitespace-before-property](https://eslint.org/docs/rules/no-whitespace-before-property)
  2960 +
  2961 +```js
  2962 +// bad
  2963 +$("#items").find(".selected").highlight().end().find(".open").updateCount();
  2964 +
  2965 +// bad
  2966 +$("#items").
  2967 + find(".selected")
  2968 + .highlight()
  2969 + .end()
  2970 + .find(".open")
  2971 + .updateCount();
  2972 +
  2973 +// good
  2974 +$("#items")
  2975 + .find(".selected")
  2976 + .highlight()
  2977 + .end()
  2978 + .find(".open")
  2979 + .updateCount();
  2980 +
  2981 +// bad
  2982 +const leds = stage.selectAll(".led").data(data).enter().append("svg:svg").classed("led", true)
  2983 + .attr("width", (radius + margin) * 2)
  2984 + .append("svg:g")
  2985 + .attr("transform", `translate(${radius + margin},${radius + margin})`)
  2986 + .call(tron.led);
  2987 +
  2988 +// good
  2989 +const leds = stage.selectAll(".led")
  2990 + .data(data)
  2991 + .enter().append("svg:svg")
  2992 + .classed("led", true)
  2993 + .attr("width", (radius + margin) * 2)
  2994 + .append("svg:g")
  2995 + .attr("transform", `translate(${radius + margin},${radius + margin})`)
  2996 + .call(tron.led);
  2997 +
  2998 +// good
  2999 +const leds = stage.selectAll(".led").data(data);
  3000 +```
  3001 +
  3002 +7. 在块和下一个语句之前留下一空白行。
  3003 +
  3004 +```js
  3005 +// bad
  3006 +if (foo) {
  3007 + return bar;
  3008 +}
  3009 +return baz;
  3010 +
  3011 +// good
  3012 +if (foo) {
  3013 + return bar;
  3014 +}
  3015 +
  3016 +return baz;
  3017 +
  3018 +// bad
  3019 +const obj = {
  3020 + foo() {
  3021 + },
  3022 + bar() {
  3023 + },
  3024 +};
  3025 +return obj;
  3026 +
  3027 +// good
  3028 +const obj = {
  3029 + foo() {
  3030 +
  3031 + },
  3032 +
  3033 + bar() {
  3034 +
  3035 + },
  3036 +};
  3037 +
  3038 +return obj;
  3039 +
  3040 +// bad
  3041 +const arr = [
  3042 + function foo() {
  3043 + },
  3044 + function bar() {
  3045 + }
  3046 +];
  3047 +return arr;
  3048 +
  3049 +// good
  3050 +const arr = [
  3051 + function foo() {
  3052 + },
  3053 +
  3054 + function bar() {
  3055 + }
  3056 +];
  3057 +
  3058 +return arr;
  3059 +```
  3060 +
  3061 +8. 在花括号内添加空格。eslint: [object-curly-spacing](https://eslint.org/docs/rules/object-curly-spacing.html)
  3062 +
  3063 +```js
  3064 +// bad
  3065 +const foo = {clark: "kent" };
  3066 +
  3067 +// good
  3068 +const foo = { clark: "kent" };
  3069 +```
  3070 +
  3071 +9. 避免让你的代码行超过 100 个字符(包括空格)。 注意:根据上边的 约束,长字符串可免除此规定,不应分解。eslint: [max-len](https://eslint.org/docs/rules/max-len.html)
  3072 + > 为什么? 这样能够确保可读性和可维护性。
  3073 +
  3074 +```js
  3075 +// bad
  3076 +const foo =
  3077 + jsonData &&
  3078 + jsonData.foo &&
  3079 + jsonData.foo.bar &&
  3080 + jsonData.foo.bar.baz &&
  3081 + jsonData.foo.bar.baz.quux &&
  3082 + jsonData.foo.bar.baz.quux.xyzzy;
  3083 +
  3084 +// bad
  3085 +$.ajax({ method: "POST", url: "https://airbnb.com/", data: { name: "John" } })
  3086 + .done(() => console.log("Congratulations!"))
  3087 + .fail(() => console.log("You have failed this city."));
  3088 +
  3089 +// good
  3090 +const foo =jsonData
  3091 + &&jsonData.foo
  3092 + &&jsonData.foo.bar
  3093 + &&jsonData.foo.bar.baz
  3094 + &&jsonData.foo.bar.baz.quux
  3095 + &&jsonData.foo.bar.baz.quux.xyzzy;
  3096 +
  3097 +// good
  3098 +$.ajax({
  3099 + method: "POST",
  3100 + url: "https://airbnb.com/",
  3101 + data: { name: "John" },
  3102 +})
  3103 + .done(() => console.log("Congratulations!"))
  3104 + .fail(() => console.log("You have failed this city."));
  3105 +```
  3106 +
  3107 +10. 要求打开的块标志和同一行上的标志拥有一致的间距。此规则还会在同一行关闭的块标记和前边的标记强制实施一致的间距。 eslint: [block-spacing](https://eslint.org/docs/rules/block-spacing)
  3108 +
  3109 +```js
  3110 +// bad
  3111 +function foo() {return true;}
  3112 +if (foo) {bar = 0;}
  3113 +
  3114 +// good
  3115 +function foo() { return true; }
  3116 +if (foo) { bar = 0; }
  3117 +```
  3118 +
  3119 +11. 逗号之前避免使用空格,逗号之后需要使用空格。eslint: [comma-spacing](https://eslint.org/docs/rules/comma-spacing)
  3120 +
  3121 +```js
  3122 +// bad
  3123 +var foo = 1,bar = 2;
  3124 +var arr = [1, 2];
  3125 +
  3126 +// good
  3127 +var foo = 1, bar = 2;
  3128 +var arr = [1, 2];
  3129 +```
  3130 +
  3131 +12. 在函数和它的调用之间强化间距。eslint: [func-call-spacing](https://eslint.org/docs/rules/func-call-spacing)
  3132 +
  3133 +```js
  3134 +// bad
  3135 +func ();
  3136 +
  3137 +func
  3138 +();
  3139 +
  3140 +// good
  3141 +func();
  3142 +```
  3143 +
  3144 +13. 在对象的属性和值之间强化间距。 eslint: [key-spacing](https://eslint.org/docs/rules/key-spacing)
  3145 +
  3146 +```js
  3147 +// bad
  3148 +var obj = { "foo" : 42 };
  3149 +var obj2 = { "foo":42 };
  3150 +
  3151 +// good
  3152 +var obj = { "foo": 42 };
  3153 +```
  3154 +
  3155 +### 分号
  3156 +
  3157 +1. 分号 eslint: [semi](https://eslint.org/docs/rules/semi.html)
  3158 + > 为什么? 当 JavaScript 遇见一个没有分号的换行符时,它会使用一个叫做 Automatic Semicolon Insertion 的规则来确定是否应该以换行符视为语句的结束,并且如果认为如此,会在代码中断前插入一个分号到代码中。 但是,ASI 包含了一些奇怪的行为,如果 JavaScript 错误的解释了你的换行符,你的代码将会中断。 随着新特性成为 JavaScript 的一部分,这些规则将变得更加复杂。 明确地终止你的语句,并配置你的 linter 以捕获缺少的分号将有助于防止你遇到的问题。
  3159 +
  3160 +```js
  3161 +// bad - 可能异常
  3162 +const luke = {}
  3163 +const leia = {}
  3164 +[(luke, leia)].forEach((jedi) => (jedi.father = "vader"))
  3165 +
  3166 +// bad - 可能异常
  3167 +const reaction = "No! That's impossible!"
  3168 + (async function meanwhileOnTheFalcon() {
  3169 + // handle `leia`, `lando`, `chewie`, `r2`, `c3p0`
  3170 + // ...
  3171 + }())
  3172 +
  3173 +
  3174 +// bad - 返回 `undefined` 而不是下一行的值 - 当 `return` 单独一行的时候 ASI 总是会发生
  3175 +function foo() {
  3176 + return
  3177 + ("search your feelings, you know it to be foo")
  3178 +}
  3179 +
  3180 +// good
  3181 +const luke = {};
  3182 +const leia = {};
  3183 +[luke, leia].forEach((jedi) => {
  3184 + jedi.father = "vader";
  3185 +});
  3186 +
  3187 +// good
  3188 +const reaction = "No! That's impossible!";
  3189 +(async function meanwhileOnTheFalcon() {
  3190 + // handle `leia`, `lando`, `chewie`, `r2`, `c3p0`
  3191 + // ...
  3192 +}());
  3193 +
  3194 +// good
  3195 +function foo() {
  3196 + return "search your feelings, you know it to be foo";
  3197 +}
  3198 +```
  3199 +
  3200 +### 类型转换和强制类型转换
  3201 +
  3202 +1. 在语句开始前进行类型转换。
  3203 +
  3204 +2. 字符类型 eslint: [no-new-wrappers](https://eslint.org/docs/rules/no-new-wrappers)
  3205 +
  3206 +```js
  3207 +// => this.reviewScore = 9;
  3208 +
  3209 +// bad
  3210 +const totalScore = new String(this.reviewScore); // typeof totalScore is "object" not "string"
  3211 +
  3212 +// bad
  3213 +const totalScore = this.reviewScore + ""; // invokes this.reviewScore.valueOf()
  3214 +
  3215 +// bad
  3216 +const totalScore = this.reviewScore.toString(); // isn’t guaranteed to return a string
  3217 +
  3218 +// good
  3219 +const totalScore = String(this.reviewScore);
  3220 +```
  3221 +
  3222 +3. 数字类型:使用 Number 进行类型铸造和 parseInt 总是通过一个基数来解析一个字符串。eslint: [radix](https://eslint.org/docs/rules/radix) [no-new-wrappers](https://eslint.org/docs/rules/no-new-wrappers)
  3223 +
  3224 +```js
  3225 +const inputValue = "4";
  3226 +
  3227 +// bad
  3228 +const val = new Number(inputValue);
  3229 +
  3230 +// bad
  3231 +const val = +inputValue;
  3232 +
  3233 +// bad
  3234 +const val = inputValue >> 0;
  3235 +
  3236 +// bad
  3237 +const val = parseInt(inputValue);
  3238 +
  3239 +// good
  3240 +const val = Number(inputValue);
  3241 +
  3242 +// good
  3243 +const val = parseInt(inputValue, 10);
  3244 +```
  3245 +
  3246 +4. 如果出于某种原因,你正在做一些疯狂的事情,而 parseInt 是你的瓶颈,并且出于 性能问题 需要使用位运算, 请写下注释,说明为什么这样做和你做了什么。
  3247 +
  3248 +```js
  3249 +// good
  3250 +/**
  3251 + * parseInt 使我的代码变慢。
  3252 + * 位运算将一个字符串转换成数字更快。
  3253 + */
  3254 +const val = inputValue >> 0;
  3255 +```
  3256 +
  3257 +5. 注意: 当你使用位运算的时候要小心。 数字总是被以 [64-bit](https://es5.github.io/#x4.3.19) 值 的形式表示,但是位运算总是返回一个 32-bit 的整数 [(来源)](https://es5.github.io/#x11.7)。 对于大于 32 位的整数值,位运算可能会导致意外行为。[讨论](https://github.com/airbnb/javascript/issues/109)。 最大的 32 位整数是: 2,147,483,647。
  3258 +
  3259 +```js
  3260 +2147483647 >> 0; // => 2147483647
  3261 +2147483648 >> 0; // => -2147483648
  3262 +2147483649 >> 0; // => -2147483647
  3263 +```
  3264 +
  3265 +6. 布尔类型
  3266 +
  3267 +```js
  3268 +const age = 0;
  3269 +
  3270 +// bad
  3271 +const hasAge = new Boolean(age);
  3272 +
  3273 +// good
  3274 +const hasAge = Boolean(age);
  3275 +
  3276 +// best
  3277 +const hasAge = !!age;
  3278 +```
  3279 +
  3280 +### 命名规范
  3281 +
  3282 +1. 避免单字母的名字。用你的命名来描述功能。eslint: [id-length](https://eslint.org/docs/rules/id-length)
  3283 +
  3284 +```js
  3285 +// bad
  3286 +function q() {
  3287 + // ...
  3288 +}
  3289 +
  3290 +// good
  3291 +function query() {
  3292 + // ...
  3293 +}
  3294 +```
  3295 +
  3296 +2. 在命名对象、函数和实例时使用驼峰命名法(camelCase)。eslint: [camelcase](https://eslint.org/docs/rules/camelcase.html)
  3297 +
  3298 +```js
  3299 +// bad
  3300 +const OBJEcttsssss = {};
  3301 +const this_is_my_object = {};
  3302 +function c() {}
  3303 +
  3304 +// good
  3305 +const thisIsMyObject = {};
  3306 +function thisIsMyFunction() {}
  3307 +```
  3308 +
  3309 +3. 只有在命名构造器或者类的时候才用帕斯卡拼命名法(PascalCase)。 eslint: [new-cap](https://eslint.org/docs/rules/new-cap.html)
  3310 +
  3311 +```js
  3312 +// bad
  3313 +function user(options) {
  3314 + this.name = options.name;
  3315 +}
  3316 +
  3317 +const bad = new user({
  3318 + name: "nope",
  3319 +});
  3320 +
  3321 +// good
  3322 +class User {
  3323 + constructor(options) {
  3324 + this.name = options.name;
  3325 + }
  3326 +}
  3327 +
  3328 +const good = new User({
  3329 + name: "yup",
  3330 +});
  3331 +```
  3332 +
  3333 +4. 不要使用前置或者后置下划线。eslint: [no-underscore-dangle](https://eslint.org/docs/rules/no-underscore-dangle.html)
  3334 + > 为什么? JavaScript 在属性和方法方面没有隐私设置。 虽然前置的下划线是一种常见的惯例,意思是 “private” ,事实上,这些属性时公开的,因此,它们也是你公共 API 的一部分。 这种约定可能导致开发人员错误的认为更改不会被视为中断,或者不需要测试。建议:如果你想要什么东西是 “private” , 那就一定不能有明显的表现。
  3335 +
  3336 +```js
  3337 +// bad
  3338 +this.__firstName__ = "Panda";
  3339 +this.firstName_ = "Panda";
  3340 +this._firstName = "Panda";
  3341 +
  3342 +// good
  3343 +this.firstName = "Panda";
  3344 +
  3345 +// 好,在 WeakMapx 可用的环境中
  3346 +// see https://kangax.github.io/compat-table/es6/#test-WeakMap
  3347 +const firstNames = new WeakMap();
  3348 +firstNames.set(this, "Panda");
  3349 +```
  3350 +
  3351 +5. 不要保存 this 的引用。 使用箭头函数或者 [函数#bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind)
  3352 +
  3353 +```js
  3354 +// bad
  3355 +function foo() {
  3356 + const self = this;
  3357 + return function () {
  3358 + console.log(self);
  3359 + };
  3360 +}
  3361 +
  3362 +// bad
  3363 +function foo() {
  3364 + const that = this;
  3365 + return function () {
  3366 + console.log(that);
  3367 + };
  3368 +}
  3369 +
  3370 +// good
  3371 +function foo() {
  3372 + return () => {
  3373 + console.log(this);
  3374 + };
  3375 +}
  3376 +```
  3377 +
  3378 +6. 文件名应该和默认导出的名称完全匹配。
  3379 +
  3380 +```js
  3381 +// file 1 contents
  3382 +class CheckBox {
  3383 + // ...
  3384 +}
  3385 +export default CheckBox;
  3386 +
  3387 +// file 2 contents
  3388 +export default function fortyTwo() { return 42; }
  3389 +
  3390 +// file 3 contents
  3391 +export default function insideDirectory() {}
  3392 +
  3393 +// in some other file
  3394 +// bad
  3395 +import CheckBox from './checkBox'; // PascalCase import/export, camelCase filename
  3396 +import FortyTwo from './FortyTwo'; // PascalCase import/filename, camelCase export
  3397 +import InsideDirectory from './InsideDirectory'; // PascalCase import/filename, camelCase export
  3398 +
  3399 +// bad
  3400 +import CheckBox from './check_box'; // PascalCase import/export, snake_case filename
  3401 +import forty_two from './forty_two'; // snake_case import/filename, camelCase export
  3402 +import inside_directory from './inside_directory'; // snake_case import, camelCase export
  3403 +import index from './inside_directory/index'; // requiring the index file explicitly
  3404 +import insideDirectory from './insideDirectory/index'; // requiring the index file explicitly
  3405 +
  3406 +// good
  3407 +import CheckBox from './CheckBox'; // PascalCase export/import/filename
  3408 +import fortyTwo from './fortyTwo'; // camelCase export/import/filename
  3409 +import insideDirectory from './insideDirectory'; // camelCase export/import/directory name/implicit "index"
  3410 +// ^ supports both insideDirectory.js and insideDirectory/index.js
  3411 +```
  3412 +
  3413 +7. 当你导出默认函数时使用驼峰命名法。 你的文件名应该和方法名相同。
  3414 +
  3415 +```js
  3416 +function makeStyleGuide() {
  3417 + // ...
  3418 +}
  3419 +
  3420 +export default makeStyleGuide;
  3421 +```
  3422 +
  3423 +8. 当你导出一个构造器 / 类 / 单例 / 函数库 / 暴露的对象时应该使用帕斯卡命名法。
  3424 +
  3425 +```js
  3426 +const AirbnbStyleGuide = {
  3427 + es6: {},
  3428 +};
  3429 +
  3430 +export default AirbnbStyleGuide;
  3431 +```
  3432 +
  3433 +9. 缩略词和缩写都必须是全部大写或者全部小写。
  3434 + > 为什么? 名字是为了可读性,不是为了满足计算机算法。
  3435 +
  3436 +```js
  3437 +// bad
  3438 +import SmsContainer from "./containers/SmsContainer";
  3439 +
  3440 +// bad
  3441 +const HttpRequests = [
  3442 + // ...
  3443 +];
  3444 +
  3445 +// good
  3446 +import SMSContainer from "./containers/SMSContainer";
  3447 +
  3448 +// good
  3449 +const HTTPRequests = [
  3450 + // ...
  3451 +];
  3452 +
  3453 +// also good
  3454 +const httpRequests = [
  3455 + // ...
  3456 +];
  3457 +
  3458 +// best
  3459 +import TextMessageContainer from "./containers/TextMessageContainer";
  3460 +
  3461 +// best
  3462 +const requests = [
  3463 + // ...
  3464 +];
  3465 +```
  3466 +
  3467 +10. 你可以大写一个常量,如果它:(1)被导出,(2)使用 const 定义(不能被重新赋值),(3)程序员可以信任它(以及其嵌套的属性)是不变的。
  3468 + > 为什么? 这是一个可以帮助程序员确定变量是否会发生变化的辅助工具。UPPERCASE_VARIABLES 可以让程序员知道他们可以相信变量(及其属性)不会改变。
  3469 +
  3470 +- 是否是对所有的 const 定义的变量? - 这个是没有必要的,不应该在文件中使用大写。但是,它应该用于导出常量。
  3471 +- 导出对象呢? - 在顶级导出属性 (e.g. EXPORTED_OBJECT.key) 并且保持所有嵌套属性不变。
  3472 +
  3473 +```js
  3474 +// bad
  3475 +const PRIVATE_VARIABLE = "should not be unnecessarily uppercased within a file";
  3476 +
  3477 +// bad
  3478 +export const THING_TO_BE_CHANGED = "should obviously not be uppercased";
  3479 +
  3480 +// bad
  3481 +export let REASSIGNABLE_VARIABLE = "do not use let with uppercase variables";
  3482 +
  3483 +// ---
  3484 +
  3485 +// 允许,但是不提供语义值
  3486 +export const apiKey = "SOMEKEY";
  3487 +
  3488 +// 多数情况下,很好
  3489 +export const API_KEY = "SOMEKEY";
  3490 +
  3491 +// ---
  3492 +
  3493 +// bad - 不必要大写 key 没有增加语义值
  3494 +export const MAPPING = {
  3495 + KEY: "value",
  3496 +};
  3497 +
  3498 +// good
  3499 +export const MAPPING = {
  3500 + key: "value",
  3501 +};
  3502 +```
  1 +# 代码规范相关计划文面
  2 +
  3 +## 目的:养成统一的团队规范
  4 +
  5 +### 一、尽量实现代码风格统一
  6 +
  7 +1. 一定要熟悉规范文档的要求,然后再进行开发。
  8 +2. 尽量做到与文档的要求一致,在无法实现的情况下尽量询问如何用相应的方法实现相应的业务要求。
  9 +
  10 +### 二、让开发者水平跟理解保持在统一水平线。
  11 +
  12 +1. 尽量开发者都是用HTML5+CSS3+JS(ES最新规范)。
  13 +2. 开发者可以分享页面性能、设计模式、算法相关等文章让大家了解并应用下去。
  14 +
  15 +### 三、节省开发时间成本。
  16 +
  17 +1. 每次编写业务代码时可利用画图或者其他之类方法先做业务模式设计。减少相应的bug跟时间成本。
  18 +2. 凡事能够复制的都可以提取出去做公用。
  19 +
  20 +## 预期效果
  21 +
  22 +1. 通过一段时间让大家了解代码规范,使得团队代码风格尽量做到统一。
  23 +
  24 +2. 让大家尽量去拥抱新技术。去熟悉其原理。
  25 +
  26 +3. 轻松阅读同事之间的代码逻辑。
  27 +
  28 +## 方法:通过相应的文档、编辑器工具、CI 工具、个人约束来实现代码规范。
  29 +
  30 +### 一、HTML、CSS、JS 规范文档
  31 +
  32 +### 二、css 项目工具:[stylelint](http://stylelint.docschina.org/user-guide/rules/)
  33 +1. 安装使用
  34 +```shell
  35 +npm install stylelint --save-dev
  36 +// 需配合安装 stylelint-config-standard stylelint-config-prettier 插件
  37 +```
  38 +2. 添加命令
  39 +```shell
  40 +"lint:style": "stylelint \"src/**/*.less\" --syntax less",
  41 +```
  42 +3. 在lint-staged中添加
  43 +
  44 +### 三、js 项目工具:[Eslint](https://cn.eslint.org/)
  45 +1. 安装使用
  46 +```shell
  47 +// 全局安装
  48 +npm install eslint -g
  49 +// 项目安装
  50 +npm install eslint --save-dev
  51 +
  52 +2. 使用
  53 +```shell
  54 +// 初始化项目eslint 根据相应的项目要求配置所需配置
  55 +eslint init
  56 +```
  57 +### 四、利用 git hooks 检测代码提交
  58 +```shell
  59 +// 在 lint-staged中添加
  60 +"*.{js,jsx,ts,tsx}":["git add","eslint", "prettier --write"],
  61 + "**/*.less": "stylelint --syntax less"
  62 +```
  63 +
  64 +### 五、gitlab-CI 工具
  65 +在项目创建时做好```gitlab``` Web钩子的配置,做好事件推送机制。
  66 +在Jenkins中代码编译。
  67 +### 六、定期时间沟通试用方法
  68 +
  69 +## 过程
  70 +
  71 +### 一、制定 gitlab 新项目模版
  72 +1. 做好web端template模板。
  73 +2. 做好小程序template模板。
  74 +### 二、阅读代码规范文档
  75 +1. 阅读代码规范文档,主要是js中的规范,内容相对较多。能应用到项目中去。
  76 +2. 在新项目开发过程中严格使用。
  77 +### 三、记录开发时遇到的问题
  78 +在gitlab中开放问题记录文档。随时可提交,可给出相应的解决方案。然后定期讨论解决相应的问题。
  79 +### 四、代码 review
  80 +所有人都可查看前端项目的代码,每次提交在群中发出相应的提交地址。每个人都可查看评论,如果符合代码规范,没有任何问题即可MR。否则打回重新调整提交。
  81 +```shell
  82 +// 暂存所有文件
  83 +git add .
  84 +// 提交当前暂存的文件
  85 +git commit -m "内容" // 内容规定:时间-开发内容-开发/bug提交等
  86 +// 提交跟踪过的文件
  87 +git commit -am "跟踪文件"
  88 +// 可使用alias 定义快捷命令
  89 +git config --global alias.xx "commit -am"
  90 +// 新提交与上次提交保存在一个commit
  91 +git commit --amend -m "内容"
  92 +// 如果想撤回工作目录禁止使用reset可食用revert
  93 +git revert ’工作记录id‘
  94 +// 开启fetch。
  95 +// 熟悉使用meger、remote、branch、 stash /stash pop 、 rebase、log、 reflog、 cherry-pick等命令
  96 +```
  97 +## 验收效果
  98 +
  99 +1. 是否达到制定目的跟预期效果
  100 +2. 相应的工具是否使用熟练
  101 +3. 真正开发中是否遇到不可抗拒的问题
  102 +
  103 +## 团队思考
  104 +
  105 +### 一、如何去加强我们的代码规范约束
  106 +
  107 +### 二、怎么让我们的代码规范能持续稳定的继承下去
  108 +
  109 +### 三、谁去维护相应的文档跟技术的迭代更新
  110 +
  111 +
  112 +### 相应链接
  113 +1. [eslint官方版](https://cn.eslint.org/) [阿里社区版](https://cloud.tencent.com/developer/doc/1078)
  114 +2. [stylelint](http://stylelint.docschina.org/user-guide/rules/)
  115 +3. [代码整洁](https://github.com/ryanmcdermott/clean-code-javascript) [中文版](https://github.com/BingKui/javascript-zh)
  116 +4. [腾讯代码规范](https://tgideas.qq.com/doc/index.html),[京东代码规范](https://guide.aotu.io/index.html)
注册登录 后发表评论