master 3bcfae99ddf2 cached
79 files
299.7 KB
101.5k tokens
1 requests
Download .txt
Showing preview only (380K chars total). Download the full file or copy to clipboard to get everything.
Repository: xiaoliuxiansheng/work-summary
Branch: master
Commit: 3bcfae99ddf2
Files: 79
Total size: 299.7 KB

Directory structure:
gitextract_aeb36g8b/

├── .gitignore
├── .idea/
│   ├── $CACHE_FILE$
│   ├── .gitignore
│   ├── inspectionProfiles/
│   │   └── profiles_settings.xml
│   ├── misc.xml
│   ├── modules.xml
│   ├── vcs.xml
│   └── work-sunnary.iml
├── CSS/
│   ├── Input placeholder属性样式修改(颜色,大小,位置).md
│   ├── common.css
│   ├── less 中使用grid布局.md
│   ├── reset.css
│   └── 常用css.md
├── Git/
│   └── 使用规范.md
├── HTML/
│   ├── 双飞翼布局.html
│   ├── 圣杯布局.html
│   └── 防止移动端点击输入框页面变大.md
├── HTTP/
│   ├── 封装axios请求拦截器.md
│   └── 设置请求头.md
├── JAVASCRIPT/
│   ├── FormData使用方法.md
│   ├── JavaScript规范.md
│   ├── 上传oss.md
│   ├── 下载文件流.md
│   ├── 修改url的某个参数值.md
│   ├── 功能性js插件.md
│   ├── 基于vant上传组件oss/
│   │   └── 服务器.md
│   ├── 完美url跳转方式.md
│   ├── 常用js代码块.md
│   ├── 数组中的对象去重.md
│   ├── 文件流转为文件.md
│   ├── 时间与时间戳的转换.md
│   ├── 时间戳转日期.md
│   ├── 深度克隆.md
│   ├── 深度拷贝.md
│   ├── 滚动加载demo.md
│   ├── 用递归算法实现,数组长度为5且元素的随机数在2-32间不重复的值.html
│   ├── 获取当前周每天对应的时间戳.md
│   └── 获取当前月份 第一天 最后一天.md
├── Node/
│   ├── NodeJs文档归纳.md
│   ├── Sequelize.md
│   ├── express浅尝.md
│   ├── koa浅尝.md
│   └── 现有使用量较大的框架.md
├── README.md
├── React/
│   ├── React代码规范.md
│   └── 常见使用总结.md
├── React-Native/
│   ├── APP端消息推送.md
│   ├── APP端消息推送之极光推送.md
│   ├── ios通过浏览器下载app/
│   │   └── 方法.md
│   ├── 使用Promise封装fetch请求.md
│   └── 使用总结.md
├── Redis/
│   ├── index.md
│   └── 浅尝.md
├── package.json
├── vue/
│   ├── Vue导出页面为PDF、word、html格式.md
│   ├── element-audio.md
│   ├── element-ui/
│   │   └── element更改表格表头、行、列、指定单元格样式.md
│   ├── js中使用filter里面的方法.md
│   ├── vue 中使用rem.md
│   ├── vue 项目中如何在页面刷新的状态下保留数据.md
│   ├── vue中怎么重置data?.md
│   ├── 上传图片oss.md
│   ├── 上传文件oss.md
│   ├── 如何动态添加页面title 跟 favicon.ico.md
│   ├── 子组件向父组件传参父组件添加自定义数据.md
│   ├── 资料文档集合.md
│   ├── 阿里云oss 上传.md
│   └── 页面刷新的时候如何保存store.md
├── webpack/
│   └── 日常问题总结.md
├── 插件/
│   ├── Canvas 插件(签名板).md
│   ├── echart.js.md
│   ├── moment.js.md
│   ├── one.md
│   └── postCSS.md
├── 数据库/
│   ├── 数据库建表规则.md
│   └── 设计规范.md
├── 正则/
│   ├── input框只能输入正整数.md
│   └── 文本保存换行 跟空格.md
└── 温顾而知新/
    └── 知识点集合.md

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
# Created by .ignore support plugin (hsz.mobi)


================================================
FILE: .idea/$CACHE_FILE$
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="NodePackageJsonFileManager">
    <packageJsonPaths />
  </component>
</project>

================================================
FILE: .idea/.gitignore
================================================
# Default ignored files
/workspace.xml

================================================
FILE: .idea/inspectionProfiles/profiles_settings.xml
================================================
<component name="InspectionProjectProfileManager">
  <settings>
    <option name="PROJECT_PROFILE" />
  </settings>
</component>

================================================
FILE: .idea/misc.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="JavaScriptSettings">
    <option name="languageLevel" value="ES6" />
  </component>
</project>

================================================
FILE: .idea/modules.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="ProjectModuleManager">
    <modules>
      <module fileurl="file://$PROJECT_DIR$/.idea/work-sunnary.iml" filepath="$PROJECT_DIR$/.idea/work-sunnary.iml" />
    </modules>
  </component>
</project>

================================================
FILE: .idea/vcs.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="VcsDirectoryMappings">
    <mapping directory="$PROJECT_DIR$" vcs="Git" />
  </component>
</project>

================================================
FILE: .idea/work-sunnary.iml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
  <component name="NewModuleRootManager">
    <content url="file://$MODULE_DIR$">
      <excludeFolder url="file://$MODULE_DIR$/.tmp" />
      <excludeFolder url="file://$MODULE_DIR$/temp" />
      <excludeFolder url="file://$MODULE_DIR$/tmp" />
    </content>
    <orderEntry type="inheritedJdk" />
    <orderEntry type="sourceFolder" forTests="false" />
  </component>
</module>

================================================
FILE: CSS/Input placeholder属性样式修改(颜色,大小,位置).md
================================================
## Input placeholder属性样式修改(颜色,大小,位置)
```html
 1 <!DOCTYPE html>
 2 <html>
 3 <head>
 4     <meta charset="utf-8">
 5     <title></title>
 6     <style>
 7     
 8     input::-webkit-input-placeholder {
 9         /* placeholder颜色  */
10         color: #aab2bd;
11         /* placeholder字体大小  */
12         font-size: 12px;
13         /* placeholder位置  */
14         text-align: right;
15     }
16     input {
17         border: 1px solid red;
18     }
19     </style>
20 </head>
21 <body>
22     
23     <input type="text" placeholder="请输入手机号">
24     
25 </body>
26 </html>
```
*间距用padding*

================================================
FILE: CSS/common.css
================================================
@charset "utf-8";
/*
                   _ooOoo_
                  o8888888o
                  88" . "88
                  (| -_- |)
                  O\  =  /O
               ____/`---'\____
             .'  \\|     |//  `.
            /  \\|||  :  |||//  \
           /  _||||| -:- |||||-  \
           |   | \\\  -  /// |   |
           | \_|  ''\---/''  |   |
           \  .-\__  `-`  ___/-. /
         ___`. .'  /--.--\  `. . __
      ."" '<  `.___\_<|>_/___.'  >'"".
     | | :  `- \`.;`\ _ /`;.`/ - ` : | |
     \  \ `-.   \_ __\ /__ _/   .-` /  /
======`-.____`-.___\_____/___.-`____.-'======
                   `=---='
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
         佛祖保佑       永无BUG
*/

/*
	@名称: 通用css
	@功能: 重置样式,清除浏览器默认样式,并配置适合设计的基础样式(强调文本是否大多是粗体、主文字色,主链接色,主字体等)。
		   功能样式,从常用样式方法中抽离,按需使用,使用前请先阅读 CSS规范 中相关条列。
		   常见动画效果的集合,主要用于效果演示和参考,也可以直接调用。
*/

/* ----------   reset   ---------- */

/* 防止用户自定义背景颜色对网页的影响,添加让用户可以自定义字体 */
html{color:#666;background:#fff;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;}

/* 内外边距通常让各个浏览器样式的表现位置不同 */
/*body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td,hr,button,article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{margin:0;padding:0;}*/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
main, menu, nav, output, ruby, section, summary,
time, mark, audio, video {margin: 0;padding: 0;border: 0;font-size: 100%;font: inherit;vertical-align: baseline;}
/* 重设 HTML5 标签, IE 需要在 js 中 createElement(TAG) */
/*article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block;}*/
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section {display: block;}
/* HTML5 hidden-attribute fix for newer browsers */
*[hidden] {display: none;}

/* HTML5 媒体文件跟 img 保持一致 */
audio,canvas,video{display:inline-block;*display:inline;*zoom:1;}

/* 要注意表单元素并不继承父级 font 的问题 */
body,button,input,select,textarea{font:12px/1 "Microsoft YaHei","微软雅黑","宋体","PingFang SC",Arial,sans-serif;}
body {line-height: 1;}
input,select,textarea{font-size:100%;}
/* 去掉各Table  cell 的边距并让其边重合 */
table{border-collapse:collapse;border-spacing:0;}

/* IE bug fixed: th 不继承 text-align*/
th,pre,code,kbd,samp{text-align:inherit;}

/* 去除默认边框 */
fieldset,img{border:0;}

/* ie6 7 8(q) bug 显示为行内表现 */
iframe{display:block;}

/* 去掉 firefox 下此元素的边框 */
abbr,acronym{border:0;font-variant:normal;}

/* 一致的 del 样式 */
del{text-decoration:line-through;}

address,caption,cite,code,dfn,em,th,var {font-style:normal;}

/* 去掉列表前的标识, li 会继承 */
ol,ul{list-style:none;}

/* 对齐是排版最重要的因素, 别让什么都居中 */
caption,th{text-align:left;}

/* 让标题都自定义, 适应多个系统应用 */
h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:500;}
blockquote, q {quotes: none;}
blockquote:before, blockquote:after, q:before, q:after {content: '';content: none;}

/* 统一上标和下标 */
sub, sup{font-size:75%; line-height:0; position:relative; vertical-align:baseline;}
sup{ top:-0.5em; }
sub{ bottom:-0.25em; }

/* 超链接和按钮鼠标手型 */
a,button{cursor:pointer;}

/* 默认不显示下划线,保持页面简洁 */
ins,a{text-decoration:none;}

/* 代码字体 */
code,kbd,pre,samp{font-family:monospace, serif;font-size:1em;}

/* 让字体显示正常 */
i,cite,em,var,address,dfn{font-style:normal;}

/*去掉浏览器系统默认的触发边框*/
input,a{outline:0;}

/* 文本域正常显示 */
textarea{overflow:auto;resize:none;}

/* ----------   function   ---------- */

/* 清除浮动 */
.clearfix:after{display:block;clear:both;visibility:hidden;height:0;overflow:hidden;content:".";}
.clearfix{zoom:1;}    /* for IE6 IE7 */
/* 隐藏, 通常用来与 JS 配合 */
.fn-hide{display:none;}
/* 设置内联, 减少浮动带来的bug */
.fn-left,.fn-right{display:inline;}
.fn-left{float:left;}
.fn-right{float:right;}
/* 定位 */
.fn-pr{position:relative;}
.fn-pa{position:absolute;}
.fn-pf{position:absolute;}
.fn-prz{position:relative;zoom:1;}
/*溢出隐藏*/
.fn-oh{overflow:hidden;}
/* 单行文字溢出时出现省略号,需设定宽度 */
.fn-toe{overflow:hidden;word-wrap:normal;white-space:nowrap;text-overflow:ellipsis;}
.fn-lhn{line-height:normal;}
/* 多行省略适用于webkit内核和移动端 */
.fn-toe2 {display: -webkit-box;-webkit-box-orient: vertical;-webkit-line-clamp: 2;overflow: hidden;}
.fn-toe3 {display: -webkit-box;-webkit-box-orient: vertical;-webkit-line-clamp: 3;overflow: hidden;}
.fn-toe4 {display: -webkit-box;-webkit-box-orient: vertical;-webkit-line-clamp: 4;overflow: hidden;}
/*字体*/
.fn-ff0{font-family:\5b8b\4f53;} /*宋体*/
.fn-ff1{font-family:"Microsoft YaHei",\5fae\8f6f\96c5\9ed1,arial,\5b8b\4f53;}
/* 字体大小 */
.fn-fs12{font-size:12px;}
.fn-fs14{font-size:14px;}
.fn-fs16{font-size:16px;}
.fn-fs18{font-size:18px;}
/* 字体粗细 */
.fn-fwn{font-weight:normal;}
.fn-fwb{font-weight:bold;}
/* 对齐方式 */
.fn-tal{text-align:left;}
.fn-tac{text-align:center;}
.fn-tar{text-align:right;}
.fn-taj{text-align:justify;text-justify:inter-ideograph;} /*两端对齐*/
.fn-vam{vertical-align:middle;}
/* 换行 */
.fn-wsp{overflow:hidden;text-align:left;white-space:pre-wrap;word-wrap:break-word;word-break:break-all;}
/* 强制不换行 */
.fn-wsn{word-wrap:normal;white-space:nowrap;}
/* 强制换行 */
.fn-wwb{white-space:normal;word-wrap:break-word;word-break:break-all;}
/* 文字缩进 */
.fn-ti{overflow:hidden;text-indent:-30000px;}
.fn-ti2{text-indent:2em;}
/* 鼠标触发 */
.fn-tdu,.fn-tdu:hover{text-decoration:underline;}
.fn-tdn,.fn-tdn:hover{text-decoration:none;}
/* 鼠标样式 */
.fn-csp{cursor:pointer;}
.fn-csd{cursor:default;}
.fn-csh{cursor:help;}
.fn-csm{cursor:move;}
/* 人民币符号 */
.fn-rmb{font-family:arial;font-style:normal;padding-right:4px;}
/* chrome 下字体过小的问题 */
.fn-webkit-adjust{-webkit-text-size-adjust:none;}
/* 禁选文本 */
.fn-usn{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;}

/* ----------   文本选中颜色   ---------- */
::selection {background: #00CCFF;color:#fff;}
::-moz-selection {background:#00CCFF;color:#fff;}
::-webkit-selection {background:#00CCFF;color:#fff;}

/* ----------   animation   ---------- */

/* 淡入 */
.a-fadein{-webkit-animation-name:fadein;-moz-animation-name:fadein;-ms-animation-name:fadein;animation-name:fadein;}
/* define */
/* 淡入 */
@-webkit-keyframes fadein{
    0%{opacity:0;}
    100%{opacity:1;}
}
@-moz-keyframes fadein{
    0%{opacity:0;}
    100%{opacity:1;}
}
@-ms-keyframes fadein{
    0%{opacity:0;}
    100%{opacity:1;}
}
@keyframes fadein{
    0%{opacity:0;}
    100%{opacity:1;}
}

/*padding*/
.fn-p5{padding:5px;}
.fn-p10{padding:10px;}
.fn-p15{padding:15px;}
.fn-p20{padding:20px;}
.fn-p25{padding:25px;}
.fn-p30{padding:30px;}
.fn-p40{padding:40px;}

.fn-pt5{padding-top:5px;}
.fn-pt10{padding-top:10px;}
.fn-pt15{padding-top:15px;}
.fn-pt20{padding-top:20px;}
.fn-pt25{padding-top:25px;}
.fn-pt30{padding-top:30px;}
.fn-pt40{padding-top:40px;}

.fn-pb5{padding-bottom:5px;}
.fn-pb10{padding-bottom:10px;}
.fn-pb15{padding-bottom:15px;}
.fn-pb20{padding-bottom:20px;}
.fn-pb25{padding-bottom:25px;}
.fn-pb30{padding-bottom:30px;}
.fn-pb40{padding-bottom:40px;}

.fn-pl5{padding-left:5px;}
.fn-pl10{padding-left:10px;}
.fn-pl15{padding-left:15px;}
.fn-pl20{padding-left:20px;}
.fn-pl25{padding-left:25px;}
.fn-pl30{padding-left:30px;}
.fn-pl40{padding-left:40px;}

.fn-pr5{padding-right:5px;}
.fn-pr10{padding-right:10px;}
.fn-pr15{padding-right:15px;}
.fn-pr20{padding-right:20px;}
.fn-pr25{padding-right:25px;}
.fn-pr30{padding-right:30px;}
.fn-pr40{padding-right:40px;}

/*margin*/

.fn-m5{margin:5px;}
.fn-m10{margin:10px;}
.fn-m15{margin:15px;}
.fn-m20{margin:20px;}
.fn-m25{margin:25px;}
.fn-m30{margin:30px;}
.fn-m40{margin:40px;}

.fn-mt5{margin-top:5px;}
.fn-mt10{margin-top:10px;}
.fn-mt15{margin-top:15px;}
.fn-mt20{margin-top:20px;}
.fn-mt25{margin-top:25px;}
.fn-mt30{margin-top:30px;}
.fn-mt40{margin-top:40px;}

.fn-mb5{margin-bottom:5px;}
.fn-mb10{margin-bottom:10px;}
.fn-mb15{margin-bottom:15px;}
.fn-mb20{margin-bottom:20px;}
.fn-mb25{margin-bottom:25px;}
.fn-mb30{margin-bottom:30px;}
.fn-mb40{margin-bottom:40px;}

.fn-ml5{margin-left:5px;}
.fn-ml10{margin-left:10px;}
.fn-ml15{margin-left:15px;}
.fn-ml20{margin-left:20px;}
.fn-ml25{margin-left:25px;}
.fn-ml30{margin-left:30px;}
.fn-ml40{margin-left:40px;}

.fn-mr5{margin-right:5px;}
.fn-mr10{margin-right:10px;}
.fn-mr15{margin-right:15px;}
.fn-mr20{margin-right:20px;}
.fn-mr25{margin-right:25px;}
.fn-mr30{margin-right:30px;}
.fn-mr40{margin-right:40px;}
.fn-ma{ margin:auto;}

/*border-radius*/

.fn-br {border-radius: 50%}
.fn-br5 {border-radius: 5px}
.fn-br10 {border-radius: 10px}


================================================
FILE: CSS/less 中使用grid布局.md
================================================
# less中使用grid布局 CSS网格列被转换为不同的值
#### 使用grid布局通常会使用 ‘/’ 符号 但是 直接使用会导致 最终转义的css属性值 为数于数相除的结果
### 解决方案 使用less中的转义(Escaping)
```css
grid-area: ~"2/2/3/3"; // 属性前后分别用该写法代替即可
```
#### Escaping:
转义(Escaping)允许你使用任意字符串作为属性或变量值。任何 ~"anything" 或 ~'anything' 形式的内容都将按原样输出,除非 interpolation


================================================
FILE: CSS/reset.css
================================================
/* http://meyerweb.com/eric/tools/css/reset/
   v4.0 | 20180602
   License: none (public domain)
*/

html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
main, menu, nav, output, ruby, section, summary,
time, mark, audio, video {
    margin: 0;
    padding: 0;
    border: 0;
    font-size: 100%;
    font: inherit;
    vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, main, menu, nav, section {
    display: block;
}
/* HTML5 hidden-attribute fix for newer browsers */
*[hidden] {
    display: none;
}
body {
    line-height: 1;
}
ol, ul {
    list-style: none;
}
blockquote, q {
    quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
    content: '';
    content: none;
}
table {
    border-collapse: collapse;
    border-spacing: 0;
}


================================================
FILE: CSS/常用css.md
================================================
### 以下是常用的代码收集,没有任何技术含量。

#### 1. css 2.x
- 文字换行
```css
/*强制不换行*/
white-space:nowrap;
/*自动换行*/
word-wrap: break-word;
word-break: normal;
/*强制英文单词断行*/
word-break:break-all;
```

- 两端对齐
```css
text-align:justify;text-justify:inter-ideogra
```

- [去掉Webkit(chrome)浏览器中input(文本框)或textarea的黄色焦点框](http://www.cnblogs.com/niao/archive/2012/09/07/2674511.html)
```css
input,button,select,textarea{ outline:none;}
textarea{ resize:none;}
```

- [去掉chrome记住密码后自动填充表单的黄色背景](http://www.tuicool.com/articles/EZ777n )

- ie6: position:fixed
```css
.fixed-top /* position fixed Top */{position:fixed;bottom:auto;top:0; }
* html .fixed-top /* IE6 position fixed Top */{position:absolute;bottom:auto;top:expression(eval(document.documentElement.scrollTop));}
*html{background-image:url(about:blank);background-attachment:fixed;}
```

- clearfix
```css

.clearfix:before,.clearfix:after{display:table;content:"";}
.clearfix:after{clear:both;}

.clearfix:after{visibility:hidden;display:block;font-size:0;content:" ";clear:both;height:0;}
.clearfix{display:inline-block;}
html[xmlns] .clearfix{display:block;}
* html .clearfix{height:1%;}

.clearfix{*zoom: 1;}
.clearfix:after{clear:both;display:table;content:"";}

.clearfix{overflow:hidden;_zoom:1;}
```
[http://www.daqianduan.com/3606.html](http://www.daqianduan.com/3606.html)

- seperate-table
```css
.tab{border-collapse:separate;border:1px solid #e0e0e0;}
.tab th,.tab td{padding:3px;font-size:12px;background:#f5f9fb;border:1px solid;border-color:#fff #deedf6 #deedf6 #fff;}
.tab th{background:#edf4f0;}
.tab tr.even td{background:#fff;}
```
```html
<table class="tab" width="100%" cellpadding="0" cellspacing="0" border="0">
    <tr>
        <th>111</th>
        <td>222</td>
    </tr>
    <tr>
        <th>111</th>
        <td>222</td>
    </tr>
</table>
```

- min-height: 最小高度兼容代码
```css
.minheight500{min-height:500px;height:auto !important;height:500px;overflow:visible;}
```
- 鼠标不允许点击
```css
cursor:not-allowed;
```
- mac font: osx平台字体优化
```css
font-family:"Hiragino Sans GB","Hiragino Sans GB W3",'微软雅黑';
```

- 文字过多后显示省略号
```css
.ellipsis,.ell{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
```

#### 2. css 3

- title 换行
```html
&#13;
```

- 关闭 x 符号
```html
&#215;
```

- 投影
```css
.b{box-shadow:inset 1px -1px 0 #f1f1f1;text-shadow:1px 1px 0px #630;}
filter:progid:DXImageTransform.Microsoft.gradient(enabled='true',startColorstr='#99000000',endColorstr='#99000000');background:rgba(0,0,0,.6);

background:rgba(0,0,0,0.5);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#50000000',endColorstr='#50000000')\9;
```
- [search占位](http://www.qianduan.net/search-box-style-custom-webkit.html)
```css
::-webkit-input-placeholder {}
::-moz-input-placeholder {}
input:focus::-webkit-input-placeholder { color: transparent; }
-webkit-appearance:none;  google边框去除
input[type="search"]{-webkit-appearance:textfield;} // 去除chrome默认样式
http://i.wanz.im/2011/02/04/remove_border_from_input_type_search/
http://blog.csdn.net/do_it__/article/details/6789699
line-height: normal; /* for non-ie */
line-height: 22px\9; /* for ie */
```

- [全部浏览器的兼容代码生成](http://www.colorzilla.com/gradient-editor/ )
[CSS 实现 textArea 的 placeholder 换行](http://segmentfault.com/a/1190000000362621)

- 阻止默认事件
```css
pointer-events:none;
```

- [去掉输入框聚焦时候的白色背景](http://ntesmailfetc.blog.163.com/blog/static/20628706120139184457401/)
```css
-webkit-user-modify: read-write-plaintext-only;
```

- [input:focus时input不随软键盘升起而抬高的情况](http://www.cnblogs.com/hongru/archive/2013/02/06/2902938.html)
```css
 :focus{-webkit-tap-highlight-color:rgba(255, 255, 255, 0);
 -webkit-user-modify:read-write-plaintext-only;}
```

- 变灰 gray
```css
html{
    filter: grayscale(100%);
    -webkit-filter: grayscale(100%);
    -moz-filter: grayscale(100%);
    -ms-filter: grayscale(100%);
    -o-filter: grayscale(100%);
    filter: url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><filter id=\'grayscale\'><feColorMatrix type=\'matrix\' values=\'0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0\'/></filter></svg>#grayscale");
    filter:progid:DXImageTransform.Microsoft.BasicImage(grayscale=1);
    -webkit-filter: grayscale(1);
}
```
- firefox 阻止选中
```css
-moz-user-focus:ignore;-moz-user-input:disabled;-moz-user-select:none;
```
- 箭头
```css
display:block;border:solid transparent;line-height: 0;width:0; height:0;border-top:solid #0288ce;border-width:8px 6px 0 6px;

border-style:solid; border-width:7px; border-color:transparent transparent transparent #ff7020;
position:absolute;top: 0;left: 0;border-width:20px;border-style:solid;border-color:#d1ddde transparent transparent #d1ddde;
```
ie6 bug测试,把border-style设为dashed.

- 取消textarea右下角可拖动手柄
```css
resize:none
```
- 取消chrome form表单的聚焦边框
```css
input,button,select,textarea{outline:none}
textarea{resize:none}
```
- 取消a链接的黄色边框
```css
a{-webkit-tap-highlight-color:rgba(0,0,0,0);}
```
- 取消input,button焦点或点击时蓝色边框
```css
input{outline:none;}
```
- webkit 水平居中
```css
display:-webkit-box;-webkit-box-pack:center; -webkit-box-align: center;
position:absolute; top:50%;left:50%;transform:translate(-50%,-50%);
```
- 取消chrome 搜索x提示
```css
input[type=search]::-webkit-search-decoration,
input[type=search]::-webkit-search-cancel-button,
input[type=search]::-webkit-search-results-button,
input[type=search]::-webkit-search-results-decoration {
    display: none;
}
```
- [chrome取消默认黄色背景](http://stackoverflow.com/questions/2338102/override-browser-form-filling-and-input-highlighting-with-html-css)
```css
input:-webkit-autofill {-webkit-box-shadow: 0 0 0px 1000px white inset;}
input:-webkit-autofill,
textarea:-webkit-autofill,
select:-webkit-autofill {
    -webkit-box-shadow: 0 0 0 1000px white inset;
}
autocomplete="off"
```
- 手机版本网页a标记虚线框问题
```css
a:focus {outline:none;-moz-outline:none;}
```
- 焦点去除背景
```css
-webkit-tap-highlight-color:rgba(255, 255, 255, 0);
-webkit-tap-highlight-color:transparent;  // i.e. Nexus5/Chrome and Kindle Fire HD 7''
```
- placeholder占位符颜色自定义
```css
input:-moz-placeholder {color: #369;}
::-webkit-input-placeholder {color:#369;}
```

- [IOS 禁用高亮](http://hi.barretlee.com/2014/03/31/tap-highlight-in-webview/)
```css
-webkit-tap-highlight-color:rgba(255,0,0,0.5);-webkit-tap-highlight-color:transparent; /* For some Androids */
```

- IOS iframe 滚动 [滚动回弹特效](http://www.cnblogs.com/flash3d/archive/2013/09/28/3343877.html)
```css
-webkit-overflow-scrolling:touch;overflow-y:scroll;
```

- [禁止选中文本](http://www.qianduan.net/introduce-user-select/)
```css
-moz-user-select:none;
-webkit-user-select:none;
-ms-user-select:none;
user-select:none;
```
- [模糊(毛玻璃)效果1](http://www.zhangxinxu.com/wordpress/2013/11/%E5%B0%8Ftip-%E4%BD%BF%E7%94%A8css%E5%B0%86%E5%9B%BE%E7%89%87%E8%BD%AC%E6%8D%A2%E6%88%90%E6%A8%A1%E7%B3%8A%E6%AF%9B%E7%8E%BB%E7%92%83%E6%95%88%E6%9E%9C/)
- [模糊(毛玻璃)效果2](http://mao.li/css3-blur-filter-pratice/)
- [模糊(毛玻璃)逼真效果](http://codepen.io/ariona/pen/geFIK)
```css
.blur {    
    -webkit-filter: blur(10px); /* Chrome, Opera */
       -moz-filter: blur(10px);
        -ms-filter: blur(10px);    
            filter: blur(10px);    
}
```
```html
<img src="mm1.jpg" />
<img src="mm1.jpg" class="blur" />
```

- 显示旋转加载图片,[下拉加载数据](https://github.com/chalecao/chale/blob/master/iscroll.js)
```css
#pullDown .pullDownIcon{display:inline-block;vertical-align:middle;width:40px;height:40px;background:url(https://github.com/chalecao/chale/blob/master/pull-icon%402x.png) 0 0 no-repeat;-webkit-background-size:40px 80px;background-size:40px 80px;-webkit-transition-property:-webkit-transform;-webkit-transition-duration:250ms}
#pullDown .pullDownIcon{-webkit-transform:rotate(0deg) translateZ(0)}
#pullDown .pullDownLabel{display:inline-block;vertical-align:middle;margin-left:5px;}
#pullDown.flip .pullDownIcon{-webkit-transform:rotate(-180deg) translateZ(0)}
#pullDown.loading .pullDownIcon{background-position:0 100%;-webkit-transform:rotate(0deg) translateZ(0);-webkit-transition-duration:0ms;-webkit-animation-name:loading;-webkit-animation-duration:2s;-webkit-animation-iteration-count:infinite;-webkit-animation-timing-function:linear}
@-webkit-keyframes loading{
    from{-webkit-transform:rotate(0deg) translateZ(0)}
    to{-webkit-transform:rotate(360deg) translateZ(0)}
}

```

```html
<div id="pullDown" class="none loading">
    <span class="pullDownIcon"></span><span class="pullDownLabel">正在载入中...</span>
</div>
```

- 手机多终端适配 media query[web app iphone4 iphone5 iphone6 响应式布局 适配代码](http://club.zoomla.cn/PItem?id=12594)
```css
@media (device-height:480px) and (-webkit-min-device-pixel-ratio:2){/* 兼容iphone4/4s */
    .class{}
}
@media (device-height:568px) and (-webkit-min-device-pixel-ratio:2){/* 兼容iphone5 */
    .class{}
}
@media (device-height:667px) and (-webkit-min-device-pixel-ratio:2){/* 兼容iphone6 */
    .class{}
}
@media (device-height:736px) and (-webkit-min-device-pixel-ratio:2){/* 兼容iphone6 Plus */
    .class{}
}
```

- 屏蔽苹果浏览器对数字的识别[Meta标签中的format-detection属性及含义](http://blog.sina.com.cn/s/blog_51048da70101cgea.html)
```html
<meta content="telephone=no" name="format-detection">
```

- 移除HTML5 input在type="number"时的上下小箭头
  - 在chrome下:
  ```css
    input::-webkit-outer-spin-button,input::-webkit-inner-spin-button{
        -webkit-appearance: none !important;
        margin: 0; 
    }
  ```
  - Firefox下:
  ```css
    input[type="number"]{-moz-appearance:textfield;}
  ```
    
  - 第二种方案:
    - 将type="number"改为type="tel",同样是数字键盘,但是没有箭头。
    
- [HTML5手机浏览直接给一个号码打电话,发短信](http://java-er.com/blog/html5-mobile-call-sms/)
  
```html
<a href="tel:15222222222">移动WEB页面JS一键拨打号码咨询功能</a>
<a href="sms:15222222222">移动WEB页面JS一键发送短信咨询功能</a>
<!--移动web页面自动探测电话号码-->
<meta name="format-detection" content="telephone=no">
<meta http-equiv="x-rim-auto-match" content="none">
```

- [CSS判断横屏竖屏](http://www.w3cways.com/1772.html)
```css
@media screen and (orientation: portrait) {
  /*竖屏 css*/
} 
@media screen and (orientation: landscape) {
  /*横屏 css*/
}
```

```javascript
//判断手机横竖屏状态:
window.addEventListener("onorientationchange" in window ? "orientationchange" : "resize", function() {
        if (window.orientation === 180 || window.orientation === 0) { 
            alert('竖屏状态!');
        } 
        if (window.orientation === 90 || window.orientation === -90 ){ 
            alert('横屏状态!');
        }  
    }, false); 
//移动端的浏览器一般都支持window.orientation这个参数,通过这个参数可以判断出手机是处在横屏还是竖屏状态。
```

- rem 适配,内容太多,只贴网址

    - [rem自适应方案](https://github.com/imweb/mobile/issues/3)
    - [html5移动端页面分辨率设置及相应字体大小设置的靠谱使用方式](http://www.cnblogs.com/willian/p/3573353.html)
    - [移动端高清、多屏适配方案](http://www.html-js.com/article/Mobile-terminal-H5-mobile-terminal-HD-multi-screen-adaptation-scheme%203041)
    - [通过rem布局+media-query:aspect-ratio实现移动端全机型适配覆盖](http://xiaoyuze88.github.io/blog/2015/05/12/%E9%80%9A%E8%BF%87rem%E5%B8%83%E5%B1%80+media-query%E7%9A%84aspect-ratio%E5%AE%9E%E7%8E%B0%E7%A7%BB%E5%8A%A8%E7%AB%AF%E5%85%A8%E6%9C%BA%E5%9E%8B%E9%80%82%E9%85%8D%E8%A6%86%E7%9B%96/)
    - [web app变革之rem](http://isux.tencent.com/web-app-rem.html)
    - [手机淘宝的flexible设计与实现](http://www.html-js.com/article/2402)
    - [移动端自适应方案](https://github.com/amfe/lib-flexible)
    - [【原创】移动端高清、多屏适配方案](http://www.html-js.com/article/3041)
    - [6个html5页面适配iphone6的技巧](http://qietuwang.baijia.baidu.com/article/73861)
    - [关于移动端 rem 布局的一些总结](http://segmentfault.com/a/1190000003690140)
    - [从网易与淘宝的font-size思考前端设计稿与工作流](http://www.cnblogs.com/lyzg/p/4877277.html)
    - [移动端自适应方案](http://f2e.souche.com/blog/yi-dong-duan-zi-gua-ying-fang-an/)
    - [MobileWeb 适配总结](http://www.w3ctech.com/topic/979)
    - [移动端web app自适应布局探索与总结](http://www.html-js.com/article/JavaScript-learning-notes%203234)
    - 公式
        
        ```javascript
        var PAGE_MAX_WIDTH = 1280,
            BASE_FONT_SIZE = 50;
        (function() {
            function n() {
                e.fontSize = Math.min(window.innerWidth / PAGE_MAX_WIDTH * BASE_FONT_SIZE, BASE_FONT_SIZE) + "px"
            }
            var e = document.documentElement.style;
            window.addEventListener("load", n),
            window.addEventListener("resize", n),
            n();
        }());
        ```
    
- 页面的切换使用了page-enter
```html
<meta http-equiv="PAGE-ENTER" content="RevealTrans(Duration=0,Transition=1)" />
```
- css相关总结网址

    - [css常用效果总结](http://www.haorooms.com/post/css_common)
    - [css的不常用效果总结](http://www.haorooms.com/post/css_notuse_common)
	- [css开发技巧](http://www.haorooms.com/post/css_skill)
	- [重温css的选择器](http://www.haorooms.com/post/css_selectelement)
	- [css的变量和继承](http://www.haorooms.com/post/css_inherit_bl)
	- [css3的混合模式](http://www.haorooms.com/post/css3_mixblendmode)
	- [css中伪元素before或after中content的特殊用法attr](http://www.haorooms.com/post/content_attr)

- 如何实现label长度固定,文字分散分布的效果
```css
/*css*/
.label {
      width: 200px;
      height: 30px; /*高度需要添加,不然文字下面会多出一些空隙*/
      text-align: justify; 
}
 .label:after{
        content: '';
        display: inline-block;
        width: 100%;
      }
/*html*/
<div class="label">产 品</div>
```


================================================
FILE: Git/使用规范.md
================================================
## 目的
* 统一团队Git Commit标准,便于后续代码review、版本发布、自动化生成change log;
* 可以提供更多更有效的历史信息,方便快速预览以及配合cherry-pick快速合并代码;
* 团队其他成员进行类git blame时可以快速明白代码用意;
## Git版本规范
### 分支
master分支为主分支(保护分支),不能直接在master上进行修改代码和提交;
* develop分支为测试分支,所以开发完成需要提交测试的功能合并到该分支;
* feature分支为开发分支,大家根据不同需求创建独立的功能分支,开发完成后合并到develop分支;
* fix分支为bug修复分支,需要根据实际情况对已发布的版本进行漏洞修复;
### Tag
采用三段式,v版本.里程碑.序号,如v1.2.1

* 架构升级或架构重大调整,修改第2位
* 新功能上线或者模块大的调整,修改第2位
* bug修复上线,修改第3位
### Git提交信息
message信息格式采用目前主流的Angular规范,这是目前使用最广的写法,比较合理和系统化,并且有配套的工具。
### commit message格式说明
Commit message一般包括三部分:Header、Body和Footer。
### Header
type(scope):subject

### type:用于说明commit的类别,规定为如下几种
* feat:新增功能;
* fix:修复bug;
* docs:修改文档;
* refactor:代码重构,未新增任何功能和修复任何bug;
* build:改变构建流程,新增依赖库、工具等(例如webpack修改);
* style:仅仅修改了空格、缩进等,不改变代码逻辑;
* perf:改善性能和体现的修改;
* chore:非src和test的修改;
* test:测试用例的修改;
* ci:自动化流程配置修改;
* revert:回滚到上一个版本;
* scope:【可选】用于说明commit的影响范围
* subject:commit的简要说明,尽量简短
### Body
对本次commit的详细描述,可分多行

### Footer
* 不兼容变动:需要描述相关信息
* 关闭指定Issue:输入Issue信息


================================================
FILE: HTML/双飞翼布局.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <div id="hd">header</div>
    <div id="middle">
        <div id="inside">middle</div>
    </div>
    <div id="left">left</div>
    <div id="right">right</div>
    <div id="footer">footer</div>
</head>
<body>

</body>
<script>
    Notification.requestPermission(function (perm) {
        if (perm == "granted") {
            var notification = new Notification("这是一个通知撒:", {
                dir: "auto",
                lang: "hi",
                tag: "testTag",
                icon: "https://static.cnblogs.com/images/adminlogo.gif",
                body: "通知content"
            });
        }
    })
</script>
<style>
    #hd{
        height:50px;
        background: #666;
        text-align: center;
    }
    #middle{
        float:left;
        width:100%;/*左栏上去到第一行*/
        height:100px;
        background:blue;
    }
    #left{
        float:left;
        width:180px;
        height:100px;
        margin-left:-100%;
        background:#0c9;
    }
    #right{
        float:left;
        width:200px;
        height:100px;
        margin-left:-200px;
        background:#0c9;
    }

    /*给内部div添加margin,把内容放到中间栏,其实整个背景还是100%*/
    #inside{
        margin:0 200px 0 180px;
        height:100px;
    }
    #footer{
        clear:both; /*记得清楚浮动*/
        height:50px;
        background: #666;
        text-align: center;
    }
</style>
</html>


================================================
FILE: HTML/圣杯布局.html
================================================
<!DOCTYPE html>
<html lang="en">
<div id="hd">header</div>
<div id="bd">
    <div id="middle">middle</div>
    <div id="left">left</div>
    <div id="right">right</div>
</div>
<div id="footer">footer</div>
<body>

</body>
<style>
    #hd{
        height:50px;
        background: #666;
        text-align: center;
    }
    #bd{
        /*左右栏通过添加负的margin放到正确的位置了,此段代码是为了摆正中间栏的位置*/
        padding:0 200px 0 180px;
        height:100px;
    }
    #middle{
        float:left;
        width:100%;/*左栏上去到第一行*/
        height:100px;
        background:blue;
    }
    #left{
        float:left;
        width:180px;
        height:100px;
        margin-left:-100%;
        background:#0c9;
        /*中间栏的位置摆正之后,左栏的位置也相应右移,通过相对定位的left恢复到正确位置*/
        position:relative;
        left:-180px;
    }
    #right{
        float:left;
        width:200px;
        height:100px;
        margin-left:-200px;
        background:#0c9;
        /*中间栏的位置摆正之后,右栏的位置也相应左移,通过相对定位的right恢复到正确位置*/
        position:relative;
        right:-200px;
    }
    #footer{
        height:50px;
        background: #666;
        text-align: center;
    }
</style>
</html>


================================================
FILE: HTML/防止移动端点击输入框页面变大.md
================================================
### 移动端页面不放大
```html
<meta content="yes" name="apple-mobile-web-app-capable"> 

<meta name="viewport" content="width=device-width,height=device-height,inital-scale=1.0,maximum-scale=1.0,user-scalable=no;">
```
需要显示工具栏和菜单栏时,不需要添加,默认值为no,即正常显示。如果content设置为yes,Web应用会以全屏模式运行,可以通过只读属性window.navigator.standalone来确定网页是否以全屏模式显示。


* width - viewport的宽度
* height - viewport的高度
* initial-scale - 初始的缩放比例
* minimum-scale - 允许用户缩放到的最小比例
* maximum-scale - 允许用户缩放到的最大比例
* user-scalable - 用户是否可以手动缩放

================================================
FILE: HTTP/封装axios请求拦截器.md
================================================
### 封装axios请求拦截器
````javascript 1.8
import axios from 'axios';
import { message } from 'antd';
import config from './config.js' // 基于开发环境的配置文件
import {
  remove,
  findLast
} from 'lodash';
import storage from '../utils/storage.ts' // 验证信息配置文件

const baseWaitTime = 500; // 默认的等待时间500毫秒
const requestURLRate = []; // 如:{ api: '/api/standardRoles', timestamp: 1596597701181 }

/**
 * 请求出入口
 * @param {*} api 地址
 * @param {*} method 方法,默认为GET
 * @param {*} params 参数,默认为空对象
 * @param {*} maxRequestCycleCount 最大请求频次(与baseWaitTime结合),默认为1
 * @param {*} serverHost 接口主机地址
 * @param {*} headers 传入头部信息,默认为空对象
 */
export default function axiosRequest(api, method = 'GET', params = {}, headers = {}, maxRequestCycleCount = 1, serverHost = config.HOST) {

  // 针对非GET请求进行限流拦截
  if (method != 'GET') {

    let nowTimestamp = new Date().getTime(); // 当前时间戳

    // 去除当前接口指定周期外的数据
    remove(requestURLRate, (o) => {
      return o.api === api && o.timestamp < nowTimestamp - (maxRequestCycleCount * baseWaitTime);
    });

    // 获取上一次请求信息(一般同周期只有一个,防止处理意外)
    let hasRequestURLRate = findLast(requestURLRate, o => (o.api === api));

    if (hasRequestURLRate && maxRequestCycleCount !== 0) {

      message.warning('当前访问的频次过高,请适当放慢手速!', 1);

      // 为了保持数据完整性,返回数据与接口定义一致
      return {
        errcode: -100,
        msg: null
      };

    } else {
      requestURLRate.push({
        api,
        timestamp: new Date().getTime()
      });
    }
  }
  
  return new Promise((resolve, reject) => {
    const token = storage().get('TOKEN');
    axios({
      method,
      headers: {
        authorization: 'Bearer ' + token,
        ...headers,
      },
      url: (serverHost || global.G_SERVER_HOST) + api,
      data: params
    })
    .then((res) => {
      if (res.status === 200) {
        if( res.data.error === 1){
          // console.log()
          message.error(res.data.detail ||res.data.msg || '请求错误!');
           // todo:错误收集
          reject(res.data);
        }else if(res.data.error === 0 || !res.data.error){
          resolve(res.data);
        }
      }
    })
    .catch((error) => {
      console.log(error)
      if (error) {
        // todo:错误收集
        message.error('服务端发生逻辑错误!');
      }
      reject(error);

    })
  })
}
````


================================================
FILE: HTTP/设置请求头.md
================================================
## 设置请求头
```javascript 1.8
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.setRequestHeader('Content-Length', JSON.stringify(data).length);
```


================================================
FILE: JAVASCRIPT/FormData使用方法.md
================================================
## formData的主要用途有两个
1. 将form表单元素的name与value进行组合,实现表单数据的序列化,从而减少表单元素的拼接,提高工作效率。
2. 异步上传文件
### 具体使用方法
#### 一、创建formData对象
1. 创建一个空对象
```javascript 1.8
let formdata = new FormData();//利用FormData构造函数 创建一个空对象
formdata.append('name','value') //通过append() 方法追加数据 两个参数分别对应 name value
formdata.set('name','zhangsan')// 通过set()方法 设置 name 为‘name’ 的value值
formdata.get('name') //通过get()方法获取name 为‘zhangsan’ 的value值
```
2. 通过表单创建初始化FormData
```html
<form id="advForm">
    <p>广告名称:<input type="text" name="advName"  value="xixi"></p>
    <p>广告类别:<select name="advType">
        <option value="1">轮播图</option>
        <option value="2">轮播图底部广告</option>
        <option value="3">热门回收广告</option>
        <option value="4">优品精选广告</option>
    </select></p>
    <p><input type="button" id="btn" value="添加"></p>
</form>
```
通过表单元素作为参数,实现对formData的初始化:
```html
//获得表单按钮元素
var btn=document.querySelector("#btn");
//为按钮添加点击事件
btn.onclick=function(){
    //根据ID获得页面当中的form表单元素
    var form=document.querySelector("#advForm");
    //将获得的表单元素作为参数,对formData进行初始化
    var formdata=new FormData(form);
    //通过get方法获得name为advName元素的value值
    console.log(formdata.get("advName"));//xixi
    //通过get方法获得name为advType元素的value值
    console.log(formdata.get("advType"));//1 
}
```
3. 通过has(key)来判断是否存在对应的key值
```javascript 1.8
console.log(formdata.has('zhangsan'))// true
```
4. 通过delete(key)删除数据
```javascript 1.8
formdata.delete('zhangsan')
```
#### 二、通过XMLHttpRequest()发送数据
```javascript 1.8
 // var formdata=new FormData(document.getElementById("advForm"));
 let formdata = new FormData();
formdata.append('name','value')
formdata.get('name') 
    var xhr=new XMLHttpRequest();
    xhr.open("post","http://127.0.0.1/xxx");
    xhr.send(formdata);
    xhr.onload=function(){
        if(xhr.status==200){
            //...
        }
    }
```    


================================================
FILE: JAVASCRIPT/JavaScript规范.md
================================================
/**
* @name: JavaScript规范
* @author: LIULIU
* @date: 2020-11-20 11:05
* @description:JavaScript规范
* @update: 2020-11-20 11:05
*/
# Airbnb JavaScript 代码规范() {

*一种写JavaScript更合理的代码风格。*

> **Note**: 本指南假设你使用了 [Babel](https://babeljs.io), 并且要求你使用 [babel-preset-airbnb](https://npmjs.com/babel-preset-airbnb) 或者其他同等资源。 并且假设你在你的应用中安装了 shims/polyfills ,使用[airbnb-browser-shims](https://npmjs.com/airbnb-browser-shims) 或者相同功能。

[![Downloads](https://img.shields.io/npm/dm/eslint-config-airbnb.svg)](https://www.npmjs.com/package/eslint-config-airbnb)
[![Downloads](https://img.shields.io/npm/dm/eslint-config-airbnb-base.svg)](https://www.npmjs.com/package/eslint-config-airbnb-base)
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/airbnb/javascript?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)

<!-- 本指南也提供了其他语言的版本。 查看 [翻译](#translation) -->

其他代码风格指南

  - [ES5 (Deprecated)](https://github.com/airbnb/javascript/tree/es5-deprecated/es5)
  - [React](react/)
  - [CSS-in-JavaScript](css-in-javascript/)
  - [CSS & Sass](https://github.com/airbnb/css)
  - [Ruby](https://github.com/airbnb/ruby)

## <a id="table-of-contents">目录</a>

  1. [类型](#types)
  1. [引用](#references)
  1. [对象](#objects)
  1. [数组](#arrays)
  1. [解构](#destructuring)
  1. [字符](#strings)
  1. [方法](#functions)
  1. [箭头函数](#arrow-functions)
  1. [类和构造器](#classes--constructors)
  1. [模块](#modules)
  1. [迭代器和发生器](#iterators-and-generators)
  1. [属性](#properties)
  1. [变量](#variables)
  1. [提升](#hoisting)
  1. [比较运算符和等号](#comparison-operators--equality)
  1. [块](#blocks)
  1. [控制语句](#control-statements)
  1. [注释](#comments)
  1. [空白](#whitespace)
  1. [逗号](#commas)
  1. [分号](#semicolons)
  1. [类型转换和强制类型转换](#type-casting--coercion)
  1. [命名规范](#naming-conventions)
  1. [存取器](#accessors)
  1. [事件](#events)
  1. [jQuery](#jquery)
  1. [ECMAScript 5 兼容性](#ecmascript-5-compatibility)
  1. [ECMAScript 6+ (ES 2015+) 风格](#ecmascript-6-es-2015-styles)
  1. [标准库](#standard-library)
  1. [测试](#testing)
  1. [性能](#performance)
  1. [资源](#resources)
  1. [JavaScript风格指南的指南](#the-javascript-style-guide-guide)
  1. [许可证](#license)
  1. [修正案](#amendments)

## <a id="types">类型</a>

  <a name="types--primitives"></a><a name="1.1"></a>
  - [1.1](#types--primitives) **原始值**: 当你访问一个原始类型的时候,你可以直接使用它的值。

    - `string`
    - `number`
    - `boolean`
    - `null`
    - `undefined`
    - `symbol`

    ```javascript
    const foo = 1;
    let bar = foo;

    bar = 9;

    console.log(foo, bar); // => 1, 9
    ```

    - 标识符不能完全被支持,因此在针对不支持的浏览器或者环境时不应该使用它们。

  <a name="types--complex"></a><a name="1.2"></a>
  - [1.2](#types--complex)  **复杂类型**: 当你访问一个复杂类型的时候,你需要一个值得引用。

    - `object`
    - `array`
    - `function`

    ```javascript
    const foo = [1, 2];
    const bar = foo;

    bar[0] = 9;

    console.log(foo[0], bar[0]); // => 9, 9
    ```

**[⬆ 返回目录](#table-of-contents)**

## <a id="references">引用</a>

  <a name="references--prefer-const"></a><a name="2.1"></a>
  - [2.1](#references--prefer-const) 使用 `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)

    > 为什么? 这样能够确保你不能重新赋值你的引用,否则可能导致错误或者产生难以理解的代码。.

    ```javascript
    // bad
    var a = 1;
    var b = 2;

    // good
    const a = 1;
    const b = 2;
    ```

  <a name="references--disallow-var"></a><a name="2.2"></a>
  - [2.2](#references--disallow-var) 如果你必须重新赋值你的引用, 使用 `let` 代替 `var`。 eslint: [`no-var`](https://eslint.org/docs/rules/no-var.html)

    > 为什么? `let` 是块级作用域,而不像 `var` 是函数作用域.

    ```javascript
    // bad
    var count = 1;
    if (true) {
      count += 1;
    }

    // good, use the let.
    let count = 1;
    if (true) {
      count += 1;
    }
    ```

  <a name="references--block-scope"></a><a name="2.3"></a>
  - [2.3](#references--block-scope) 注意,let 和 const 都是块级范围的。

    ```javascript
    // const 和 let 只存在于他们定义的块中。
    {
      let a = 1;
      const b = 1;
    }
    console.log(a); // ReferenceError
    console.log(b); // ReferenceError
    ```

**[⬆ 返回目录](#table-of-contents)**

## <a id="object">对象</a>

  <a name="objects--no-new"></a><a name="3.1"></a>
  - [3.1](#objects--no-new) 使用字面语法来创建对象。 eslint: [`no-new-object`](https://eslint.org/docs/rules/no-new-object.html)

    ```javascript
    // bad
    const item = new Object();

    // good
    const item = {};
    ```

  <a name="es6-computed-properties"></a><a name="3.4"></a>
  - [3.2](#es6-computed-properties) 在创建具有动态属性名称的对象时使用计算属性名。

    > 为什么? 它允许你在一个地方定义对象的所有属性。

    ```javascript

    function getKey(k) {
      return `a key named ${k}`;
    }

    // bad
    const obj = {
      id: 5,
      name: 'San Francisco',
    };
    obj[getKey('enabled')] = true;

    // good
    const obj = {
      id: 5,
      name: 'San Francisco',
      [getKey('enabled')]: true,
    };
    ```

  <a name="es6-object-shorthand"></a><a name="3.5"></a>
  - [3.3](#es6-object-shorthand) 使用对象方法的缩写。 eslint: [`object-shorthand`](https://eslint.org/docs/rules/object-shorthand.html)

    ```javascript
    // bad
    const atom = {
      value: 1,

      addValue: function (value) {
        return atom.value + value;
      },
    };

    // good
    const atom = {
      value: 1,

      addValue(value) {
        return atom.value + value;
      },
    };
    ```

  <a name="es6-object-concise"></a><a name="3.6"></a>
  - [3.4](#es6-object-concise) 使用属性值的缩写。 eslint: [`object-shorthand`](https://eslint.org/docs/rules/object-shorthand.html)

    > 为什么? 它的写法和描述较短。

    ```javascript
    const lukeSkywalker = 'Luke Skywalker';

    // bad
    const obj = {
      lukeSkywalker: lukeSkywalker,
    };

    // good
    const obj = {
      lukeSkywalker,
    };
    ```

  <a name="objects--grouped-shorthand"></a><a name="3.7"></a>
  - [3.5](#objects--grouped-shorthand) 在对象声明的时候将简写的属性进行分组。

    > 为什么? 这样更容易的判断哪些属性使用的简写。

    ```javascript
    const anakinSkywalker = 'Anakin Skywalker';
    const lukeSkywalker = 'Luke Skywalker';

    // bad
    const obj = {
      episodeOne: 1,
      twoJediWalkIntoACantina: 2,
      lukeSkywalker,
      episodeThree: 3,
      mayTheFourth: 4,
      anakinSkywalker,
    };

    // good
    const obj = {
      lukeSkywalker,
      anakinSkywalker,
      episodeOne: 1,
      twoJediWalkIntoACantina: 2,
      episodeThree: 3,
      mayTheFourth: 4,
    };
    ```

  <a name="objects--quoted-props"></a><a name="3.8"></a>
  - [3.6](#objects--quoted-props) 只使用引号标注无效标识符的属性。 eslint: [`quote-props`](https://eslint.org/docs/rules/quote-props.html)

    > 为什么? 总的来说,我们认为这样更容易阅读。 它提升了语法高亮显示,并且更容易通过许多 JS 引擎优化。
    ```javascript
    // bad
    const bad = {
      'foo': 3,
      'bar': 4,
      'data-blah': 5,
    };

    // good
    const good = {
      foo: 3,
      bar: 4,
      'data-blah': 5,
    };
    ```

  <a name="objects--prototype-builtins"></a>
  - [3.7](#objects--prototype-builtins) 不能直接调用 `Object.prototype` 的方法,如: `hasOwnProperty` 、 `propertyIsEnumerable` 和 `isPrototypeOf`。

    > 为什么? 这些方法可能被以下问题对象的属性追踪 - 相应的有 `{ hasOwnProperty: false }` - 或者,对象是一个空对象 (`Object.create(null)`)。

    ```javascript
    // bad
    console.log(object.hasOwnProperty(key));

    // good
    console.log(Object.prototype.hasOwnProperty.call(object, key));

    // best
    const has = Object.prototype.hasOwnProperty; // 在模块范围内的缓存中查找一次
    /* or */
    import has from 'has'; // https://www.npmjs.com/package/has
    // ...
    console.log(has.call(object, key));
    ```

  <a name="objects--rest-spread"></a>
  - [3.8](#objects--rest-spread) 更喜欢对象扩展操作符,而不是用 [`Object.assign`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) 浅拷贝一个对象。 使用对象的 rest 操作符来获得一个具有某些属性的新对象。

    ```javascript
    // very bad
    const original = { a: 1, b: 2 };
    const copy = Object.assign(original, { c: 3 }); // 变异的 `original` ಠ_ಠ
    delete copy.a; // 这....

    // bad
    const original = { a: 1, b: 2 };
    const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 }

    // good
    const original = { a: 1, b: 2 };
    const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 }

    const { a, ...noA } = copy; // noA => { b: 2, c: 3 }
    ```

**[⬆ 返回目录](#table-of-contents)**

## <a id="arrays">数组</a>

  <a name="arrays--literals"></a><a name="4.1"></a>
  - [4.1](#arrays--literals) 使用字面语法创建数组。 eslint: [`no-array-constructor`](https://eslint.org/docs/rules/no-array-constructor.html)

    ```javascript
    // bad
    const items = new Array();

    // good
    const items = [];
    ```

  <a name="arrays--push"></a><a name="4.2"></a>
  - [4.2](#arrays--push) 使用 [Array#push](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/push) 取代直接赋值来给数组添加项。

    ```javascript
    const someStack = [];

    // bad
    someStack[someStack.length] = 'abracadabra';

    // good
    someStack.push('abracadabra');
    ```

  <a name="es6-array-spreads"></a><a name="4.3"></a>
  - [4.3](#es6-array-spreads) 使用数组展开方法 `...` 来拷贝数组。

    ```javascript
    // bad
    const len = items.length;
    const itemsCopy = [];
    let i;

    for (i = 0; i < len; i += 1) {
      itemsCopy[i] = items[i];
    }

    // good
    const itemsCopy = [...items];
    ```

  <a name="arrays--from"></a><a name="4.4"></a>
  - [4.4](#arrays--from) 将一个类数组对象转换成一个数组, 使用展开方法 `...` 代替 [`Array.from`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/from)。

    ```javascript
    const foo = document.querySelectorAll('.foo');

    // good
    const nodes = Array.from(foo);

    // best
    const nodes = [...foo];
    ```

  <a name="arrays--mapping"></a>
  - [4.5](#arrays--mapping) 对于对迭代器的映射,使用 [Array.from](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/from) 替代展开方法 `...` , 因为它避免了创建中间数组。

    ```javascript
    // bad
    const baz = [...foo].map(bar);

    // good
    const baz = Array.from(foo, bar);
    ```

  <a name="arrays--callback-return"></a><a name="4.5"></a>
  - [4.6](#arrays--callback-return) 在数组回调方法中使用 return 语句。 如果函数体由一个返回无副作用的表达式的单个语句组成,那么可以省略返回值, 具体查看 [8.2](#arrows--implicit-return)。 eslint: [`array-callback-return`](https://eslint.org/docs/rules/array-callback-return)

    ```javascript
    // good
    [1, 2, 3].map((x) => {
      const y = x + 1;
      return x * y;
    });

    // good
    [1, 2, 3].map(x => x + 1);

    // bad - 没有返回值,意味着在第一次迭代后 `acc` 没有被定义
    [[0, 1], [2, 3], [4, 5]].reduce((acc, item, index) => {
      const flatten = acc.concat(item);
      acc[index] = flatten;
    });

    // good
    [[0, 1], [2, 3], [4, 5]].reduce((acc, item, index) => {
      const flatten = acc.concat(item);
      acc[index] = flatten;
      return flatten;
    });

    // bad
    inbox.filter((msg) => {
      const { subject, author } = msg;
      if (subject === 'Mockingbird') {
        return author === 'Harper Lee';
      } else {
        return false;
      }
    });

    // good
    inbox.filter((msg) => {
      const { subject, author } = msg;
      if (subject === 'Mockingbird') {
        return author === 'Harper Lee';
      }

      return false;
    });
    ```

  <a name="arrays--bracket-newline"></a>
  - [4.7](#arrays--bracket-newline) 如果数组有多行,则在开始的时候换行,然后在结束的时候换行。

    ```javascript
    // bad
    const arr = [
      [0, 1], [2, 3], [4, 5],
    ];

    const objectInArray = [{
      id: 1,
    }, {
      id: 2,
    }];

    const numberInArray = [
      1, 2,
    ];

    // good
    const arr = [[0, 1], [2, 3], [4, 5]];

    const objectInArray = [
      {
        id: 1,
      },
      {
        id: 2,
      },
    ];

    const numberInArray = [
      1,
      2,
    ];
    ```

**[⬆ 返回目录](#table-of-contents)**

## <a id="destructuring">解构</a>

  <a name="destructuring--object"></a><a name="5.1"></a>
  - [5.1](#destructuring--object) 在访问和使用对象的多个属性的时候使用对象的解构。 eslint: [`prefer-destructuring`](https://eslint.org/docs/rules/prefer-destructuring)

    > 为什么? 解构可以避免为这些属性创建临时引用。

    ```javascript
    // bad
    function getFullName(user) {
      const firstName = user.firstName;
      const lastName = user.lastName;

      return `${firstName} ${lastName}`;
    }

    // good
    function getFullName(user) {
      const { firstName, lastName } = user;
      return `${firstName} ${lastName}`;
    }

    // best
    function getFullName({ firstName, lastName }) {
      return `${firstName} ${lastName}`;
    }
    ```

  <a name="destructuring--array"></a><a name="5.2"></a>
  - [5.2](#destructuring--array) 使用数组解构。 eslint: [`prefer-destructuring`](https://eslint.org/docs/rules/prefer-destructuring)

    ```javascript
    const arr = [1, 2, 3, 4];

    // bad
    const first = arr[0];
    const second = arr[1];

    // good
    const [first, second] = arr;
    ```

  <a name="destructuring--object-over-array"></a><a name="5.3"></a>
  - [5.3](#destructuring--object-over-array) 对于多个返回值使用对象解构,而不是数组解构。

    > 为什么? 你可以随时添加新的属性或者改变属性的顺序,而不用修改调用方。

    ```javascript
    // bad
    function processInput(input) {
      // 处理代码...
      return [left, right, top, bottom];
    }

    // 调用者需要考虑返回数据的顺序。
    const [left, __, top] = processInput(input);

    // good
    function processInput(input) {
      // 处理代码...
      return { left, right, top, bottom };
    }

    // 调用者只选择他们需要的数据。
    const { left, top } = processInput(input);
    ```

**[⬆ 返回目录](#table-of-contents)**

## <a id="strings">字符</a>

  <a name="strings--quotes"></a><a name="6.1"></a>
  - [6.1](#strings--quotes) 使用单引号 `''` 定义字符串。 eslint: [`quotes`](https://eslint.org/docs/rules/quotes.html)

    ```javascript
    // bad
    const name = "Capt. Janeway";

    // bad - 模板文字应该包含插值或换行。
    const name = `Capt. Janeway`;

    // good
    const name = 'Capt. Janeway';
    ```

  <a name="strings--line-length"></a><a name="6.2"></a>
  - [6.2](#strings--line-length) 使行超过100个字符的字符串不应使用字符串连接跨多行写入。

    > 为什么? 断开的字符串更加难以工作,并且使代码搜索更加困难。

    ```javascript
    // bad
    const errorMessage = 'This is a super long error that was thrown because \
    of Batman. When you stop to think about how Batman had anything to do \
    with this, you would get nowhere \
    fast.';

    // bad
    const errorMessage = 'This is a super long error that was thrown because ' +
      'of Batman. When you stop to think about how Batman had anything to do ' +
      'with this, you would get nowhere fast.';

    // good
    const errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.';
    ```

  <a name="es6-template-literals"></a><a name="6.4"></a>
  - [6.3](#es6-template-literals) 当以编程模式构建字符串时,使用字符串模板代替字符串拼接。 eslint: [`prefer-template`](https://eslint.org/docs/rules/prefer-template.html) [`template-curly-spacing`](https://eslint.org/docs/rules/template-curly-spacing)

    > 为什么? 字符串模板为您提供了一种可读的、简洁的语法,具有正确的换行和字符串插值特性。

    ```javascript
    // bad
    function sayHi(name) {
      return 'How are you, ' + name + '?';
    }

    // bad
    function sayHi(name) {
      return ['How are you, ', name, '?'].join();
    }

    // bad
    function sayHi(name) {
      return `How are you, ${ name }?`;
    }

    // good
    function sayHi(name) {
      return `How are you, ${name}?`;
    }
    ```

  <a name="strings--eval"></a><a name="6.5"></a>
  - [6.4](#strings--eval) 不要在字符串上使用 `eval()` ,它打开了太多漏洞。 eslint: [`no-eval`](https://eslint.org/docs/rules/no-eval)

  <a name="strings--escaping"></a>
  - [6.5](#strings--escaping) 不要转义字符串中不必要的字符。 eslint: [`no-useless-escape`](https://eslint.org/docs/rules/no-useless-escape)

    > 为什么? 反斜杠损害了可读性,因此只有在必要的时候才会出现。

    ```javascript
    // bad
    const foo = '\'this\' \i\s \"quoted\"';

    // good
    const foo = '\'this\' is "quoted"';
    const foo = `my name is '${name}'`;
    ```

**[⬆ 返回目录](#table-of-contents)**

## <a id="functions">方法</a>

  <a name="functions--declarations"></a><a name="7.1"></a>
  - [7.1](#functions--declarations) 使用命名的函数表达式代替函数声明。 eslint: [`func-style`](https://eslint.org/docs/rules/func-style)

    > 为什么? 函数声明是挂起的,这意味着在它在文件中定义之前,很容易引用函数。这会损害可读性和可维护性。如果您发现函数的定义是大的或复杂的,以至于它干扰了对文件的其余部分的理解,那么也许是时候将它提取到它自己的模块中了!不要忘记显式地命名这个表达式,不管它的名称是否从包含变量(在现代浏览器中经常是这样,或者在使用诸如Babel之类的编译器时)。这消除了对错误的调用堆栈的任何假设。 ([Discussion](https://github.com/airbnb/javascript/issues/794))

    ```javascript
    // bad
    function foo() {
      // ...
    }

    // bad
    const foo = function () {
      // ...
    };

    // good
    // 从变量引用调用中区分的词汇名称
    const short = function longUniqueMoreDescriptiveLexicalFoo() {
      // ...
    };
    ```

  <a name="functions--iife"></a><a name="7.2"></a>
  - [7.2](#functions--iife) Wrap立即调用函数表达式。 eslint: [`wrap-iife`](https://eslint.org/docs/rules/wrap-iife.html)

    > 为什么? 立即调用的函数表达式是单个单元 - 包装, 并且拥有括号调用, 在括号内, 清晰的表达式。 请注意,在一个到处都是模块的世界中,您几乎不需要一个 IIFE 。

    ```javascript
    // immediately-invoked function expression (IIFE) 立即调用的函数表达式
    (function () {
      console.log('Welcome to the Internet. Please follow me.');
    }());
    ```

  <a name="functions--in-blocks"></a><a name="7.3"></a>
  - [7.3](#functions--in-blocks) 切记不要在非功能块中声明函数 (`if`, `while`, 等)。 将函数赋值给变量。 浏览器允许你这样做,但是他们都有不同的解释,这是个坏消息。 eslint: [`no-loop-func`](https://eslint.org/docs/rules/no-loop-func.html)

  <a name="functions--note-on-blocks"></a><a name="7.4"></a>
  - [7.4](#functions--note-on-blocks) **注意:** ECMA-262 将 `block` 定义为语句列表。 函数声明不是语句。

    ```javascript
    // bad
    if (currentUser) {
      function test() {
        console.log('Nope.');
      }
    }

    // good
    let test;
    if (currentUser) {
      test = () => {
        console.log('Yup.');
      };
    }
    ```

  <a name="functions--arguments-shadow"></a><a name="7.5"></a>
  - [7.5](#functions--arguments-shadow) 永远不要定义一个参数为 `arguments`。 这将会优先于每个函数给定范围的 `arguments` 对象。

    ```javascript
    // bad
    function foo(name, options, arguments) {
      // ...
    }

    // good
    function foo(name, options, args) {
      // ...
    }
    ```

  <a name="es6-rest"></a><a name="7.6"></a>
  - [7.6](#es6-rest) 不要使用 `arguments`, 选择使用 rest 语法 `...` 代替。 eslint: [`prefer-rest-params`](https://eslint.org/docs/rules/prefer-rest-params)

    > 为什么? `...` 明确了你想要拉取什么参数。 更甚, rest 参数是一个真正的数组,而不仅仅是类数组的 `arguments` 。

    ```javascript
    // bad
    function concatenateAll() {
      const args = Array.prototype.slice.call(arguments);
      return args.join('');
    }

    // good
    function concatenateAll(...args) {
      return args.join('');
    }
    ```

  <a name="es6-default-parameters"></a><a name="7.7"></a>
  - [7.7](#es6-default-parameters) 使用默认的参数语法,而不是改变函数参数。

    ```javascript
    // really bad
    function handleThings(opts) {
      // No! We shouldn’t mutate function arguments.
      // Double bad: if opts is falsy it'll be set to an object which may
      // be what you want but it can introduce subtle bugs.
      opts = opts || {};
      // ...
    }

    // still bad
    function handleThings(opts) {
      if (opts === void 0) {
        opts = {};
      }
      // ...
    }

    // good
    function handleThings(opts = {}) {
      // ...
    }
    ```

  <a name="functions--default-side-effects"></a><a name="7.8"></a>
  - [7.8](#functions--default-side-effects) 避免使用默认参数的副作用。

    > 为什么? 他们很容易混淆。

    ```javascript
    var b = 1;
    // bad
    function count(a = b++) {
      console.log(a);
    }
    count();  // 1
    count();  // 2
    count(3); // 3
    count();  // 3
    ```

  <a name="functions--defaults-last"></a><a name="7.9"></a>
  - [7.9](#functions--defaults-last) 总是把默认参数放在最后。

    ```javascript
    // bad
    function handleThings(opts = {}, name) {
      // ...
    }

    // good
    function handleThings(name, opts = {}) {
      // ...
    }
    ```

  <a name="functions--constructor"></a><a name="7.10"></a>
  - [7.10](#functions--constructor) 永远不要使用函数构造器来创建一个新函数。 eslint: [`no-new-func`](https://eslint.org/docs/rules/no-new-func)

    > 为什么? 以这种方式创建一个函数将对一个类似于 `eval()` 的字符串进行计算,这将打开漏洞。

    ```javascript
    // bad
    var add = new Function('a', 'b', 'return a + b');

    // still bad
    var subtract = Function('a', 'b', 'return a - b');
    ```

  <a name="functions--signature-spacing"></a><a name="7.11"></a>
  - [7.11](#functions--signature-spacing) 函数签名中的间距。 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)

    > 为什么? 一致性很好,在删除或添加名称时不需要添加或删除空格。

    ```javascript
    // bad
    const f = function(){};
    const g = function (){};
    const h = function() {};

    // good
    const x = function () {};
    const y = function a() {};
    ```

  <a name="functions--mutate-params"></a><a name="7.12"></a>
  - [7.12](#functions--mutate-params) 没用变异参数。 eslint: [`no-param-reassign`](https://eslint.org/docs/rules/no-param-reassign.html)

    > 为什么? 将传入的对象作为参数进行操作可能会在原始调用程序中造成不必要的变量副作用。

    ```javascript
    // bad
    function f1(obj) {
      obj.key = 1;
    }

    // good
    function f2(obj) {
      const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1;
    }
    ```

  <a name="functions--reassign-params"></a><a name="7.13"></a>
  - [7.13](#functions--reassign-params) 不要再赋值参数。 eslint: [`no-param-reassign`](https://eslint.org/docs/rules/no-param-reassign.html)

    > 为什么? 重新赋值参数会导致意外的行为,尤其是在访问 `arguments` 对象的时候。 它还可能导致性能优化问题,尤其是在 V8 中。

    ```javascript
    // bad
    function f1(a) {
      a = 1;
      // ...
    }

    function f2(a) {
      if (!a) { a = 1; }
      // ...
    }

    // good
    function f3(a) {
      const b = a || 1;
      // ...
    }

    function f4(a = 1) {
      // ...
    }
    ```

  <a name="functions--spread-vs-apply"></a><a name="7.14"></a>
  - [7.14](#functions--spread-vs-apply) 优先使用扩展运算符 `...` 来调用可变参数函数。 eslint: [`prefer-spread`](https://eslint.org/docs/rules/prefer-spread)

    > 为什么? 它更加干净,你不需要提供上下文,并且你不能轻易的使用 `apply` 来 `new` 。

    ```javascript
    // bad
    const x = [1, 2, 3, 4, 5];
    console.log.apply(console, x);

    // good
    const x = [1, 2, 3, 4, 5];
    console.log(...x);

    // bad
    new (Function.prototype.bind.apply(Date, [null, 2016, 8, 5]));

    // good
    new Date(...[2016, 8, 5]);
    ```

  <a name="functions--signature-invocation-indentation"></a>
  - [7.15](#functions--signature-invocation-indentation) 具有多行签名或者调用的函数应该像本指南中的其他多行列表一样缩进:在一行上只有一个条目,并且每个条目最后加上逗号。 eslint: [`function-paren-newline`](https://eslint.org/docs/rules/function-paren-newline)

    ```javascript
    // bad
    function foo(bar,
                 baz,
                 quux) {
      // ...
    }

    // good
    function foo(
      bar,
      baz,
      quux,
    ) {
      // ...
    }

    // bad
    console.log(foo,
      bar,
      baz);

    // good
    console.log(
      foo,
      bar,
      baz,
    );
    ```

**[⬆ 返回目录](#table-of-contents)**

## <a id="arrow-functions">箭头函数</a>

  <a name="arrows--use-them"></a><a name="8.1"></a>
  - [8.1](#arrows--use-them) 当你必须使用匿名函数时 (当传递内联函数时), 使用箭头函数。 eslint: [`prefer-arrow-callback`](https://eslint.org/docs/rules/prefer-arrow-callback.html), [`arrow-spacing`](https://eslint.org/docs/rules/arrow-spacing.html)

    > 为什么? 它创建了一个在 `this` 上下文中执行的函数版本,它通常是你想要的,并且是一个更简洁的语法。

    > 为什么不? 如果你有一个相当复杂的函数,你可以把这个逻辑转移到它自己的命名函数表达式中。

    ```javascript
    // bad
    [1, 2, 3].map(function (x) {
      const y = x + 1;
      return x * y;
    });

    // good
    [1, 2, 3].map((x) => {
      const y = x + 1;
      return x * y;
    });
    ```

  <a name="arrows--implicit-return"></a><a name="8.2"></a>
  - [8.2](#arrows--implicit-return) 如果函数体包含一个单独的语句,返回一个没有副作用的 [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)

    > 为什么? 语法糖。 多个函数被链接在一起时,提高可读性。

    ```javascript
    // bad
    [1, 2, 3].map(number => {
      const nextNumber = number + 1;
      `A string containing the ${nextNumber}.`;
    });

    // good
    [1, 2, 3].map(number => `A string containing the ${number}.`);

    // good
    [1, 2, 3].map((number) => {
      const nextNumber = number + 1;
      return `A string containing the ${nextNumber}.`;
    });

    // good
    [1, 2, 3].map((number, index) => ({
      [index]: number,
    }));

    // 没有副作用的隐式返回
    function foo(callback) {
      const val = callback();
      if (val === true) {
        // 如果回调返回 true 执行
      }
    }

    let bool = false;

    // bad
    foo(() => bool = true);

    // good
    foo(() => {
      bool = true;
    });
    ```

  <a name="arrows--paren-wrap"></a><a name="8.3"></a>
  - [8.3](#arrows--paren-wrap) 如果表达式跨越多个行,用括号将其括起来,以获得更好的可读性。

    > 为什么? 它清楚地显示了函数的起点和终点。

    ```javascript
    // bad
    ['get', 'post', 'put'].map(httpMethod => Object.prototype.hasOwnProperty.call(
        httpMagicObjectWithAVeryLongName,
        httpMethod,
      )
    );

    // good
    ['get', 'post', 'put'].map(httpMethod => (
      Object.prototype.hasOwnProperty.call(
        httpMagicObjectWithAVeryLongName,
        httpMethod,
      )
    ));
    ```

  <a name="arrows--one-arg-parens"></a><a name="8.4"></a>
  - [8.4](#arrows--one-arg-parens) 如果你的函数接收一个参数,则可以不用括号,省略括号。 否则,为了保证清晰和一致性,需要在参数周围加上括号。 注意:总是使用括号是可以接受的,在这种情况下,我们使用 [“always” option](https://eslint.org/docs/rules/arrow-parens#always) 来配置 eslint. eslint: [`arrow-parens`](https://eslint.org/docs/rules/arrow-parens.html)

    > 为什么? 减少视觉上的混乱。

    ```javascript
    // bad
    [1, 2, 3].map((x) => x * x);

    // good
    [1, 2, 3].map(x => x * x);

    // good
    [1, 2, 3].map(number => (
      `A long string with the ${number}. It’s so long that we don’t want it to take up space on the .map line!`
    ));

    // bad
    [1, 2, 3].map(x => {
      const y = x + 1;
      return x * y;
    });

    // good
    [1, 2, 3].map((x) => {
      const y = x + 1;
      return x * y;
    });
    ```

  <a name="arrows--confusing"></a><a name="8.5"></a>
  - [8.5](#arrows--confusing) 避免箭头函数符号 (`=>`) 和比较运算符 (`<=`, `>=`) 的混淆。 eslint: [`no-confusing-arrow`](https://eslint.org/docs/rules/no-confusing-arrow)

    ```javascript
    // bad
    const itemHeight = item => item.height > 256 ? item.largeSize : item.smallSize;

    // bad
    const itemHeight = (item) => item.height > 256 ? item.largeSize : item.smallSize;

    // good
    const itemHeight = item => (item.height > 256 ? item.largeSize : item.smallSize);

    // good
    const itemHeight = (item) => {
      const { height, largeSize, smallSize } = item;
      return height > 256 ? largeSize : smallSize;
    };
    ```

  <a name="whitespace--implicit-arrow-linebreak"></a>
  - [8.6](#whitespace--implicit-arrow-linebreak) 注意带有隐式返回的箭头函数函数体的位置。 eslint: [`implicit-arrow-linebreak`](https://eslint.org/docs/rules/implicit-arrow-linebreak)

    ```javascript
    // bad
    (foo) =>
      bar;

    (foo) =>
      (bar);

    // good
    (foo) => bar;
    (foo) => (bar);
    (foo) => (
       bar
    )
    ```

**[⬆ 返回目录](#table-of-contents)**

## <a id="classes--constructors">类和构造器</a>

  <a name="constructors--use-class"></a><a name="9.1"></a>
  - [9.1](#constructors--use-class) 尽量使用 `class`. 避免直接操作 `prototype` .

    > 为什么? `class` 语法更简洁,更容易推理。

    ```javascript
    // bad
    function Queue(contents = []) {
      this.queue = [...contents];
    }
    Queue.prototype.pop = function () {
      const value = this.queue[0];
      this.queue.splice(0, 1);
      return value;
    };

    // good
    class Queue {
      constructor(contents = []) {
        this.queue = [...contents];
      }
      pop() {
        const value = this.queue[0];
        this.queue.splice(0, 1);
        return value;
      }
    }
    ```

  <a name="constructors--extends"></a><a name="9.2"></a>
  - [9.2](#constructors--extends) 使用 `extends` 来扩展继承。

    > 为什么? 它是一个内置的方法,可以在不破坏 `instanceof` 的情况下继承原型功能。

    ```javascript
    // bad
    const inherits = require('inherits');
    function PeekableQueue(contents) {
      Queue.apply(this, contents);
    }
    inherits(PeekableQueue, Queue);
    PeekableQueue.prototype.peek = function () {
      return this.queue[0];
    };

    // good
    class PeekableQueue extends Queue {
      peek() {
        return this.queue[0];
      }
    }
    ```

  <a name="constructors--chaining"></a><a name="9.3"></a>
  - [9.3](#constructors--chaining) 方法返回了 `this` 来供其内部方法调用。

    ```javascript
    // bad
    Jedi.prototype.jump = function () {
      this.jumping = true;
      return true;
    };

    Jedi.prototype.setHeight = function (height) {
      this.height = height;
    };

    const luke = new Jedi();
    luke.jump(); // => true
    luke.setHeight(20); // => undefined

    // good
    class Jedi {
      jump() {
        this.jumping = true;
        return this;
      }

      setHeight(height) {
        this.height = height;
        return this;
      }
    }

    const luke = new Jedi();

    luke.jump()
      .setHeight(20);
    ```

  <a name="constructors--tostring"></a><a name="9.4"></a>
  - [9.4](#constructors--tostring) 只要在确保能正常工作并且不产生任何副作用的情况下,编写一个自定义的 `toString()` 方法也是可以的。

    ```javascript
    class Jedi {
      constructor(options = {}) {
        this.name = options.name || 'no name';
      }

      getName() {
        return this.name;
      }

      toString() {
        return `Jedi - ${this.getName()}`;
      }
    }
    ```

  <a name="constructors--no-useless"></a><a name="9.5"></a>
  - [9.5](#constructors--no-useless) 如果没有指定类,则类具有默认的构造器。 一个空的构造器或是一个代表父类的函数是没有必要的。 eslint: [`no-useless-constructor`](https://eslint.org/docs/rules/no-useless-constructor)

    ```javascript
    // bad
    class Jedi {
      constructor() {}

      getName() {
        return this.name;
      }
    }

    // bad
    class Rey extends Jedi {
      constructor(...args) {
        super(...args);
      }
    }

    // good
    class Rey extends Jedi {
      constructor(...args) {
        super(...args);
        this.name = 'Rey';
      }
    }
    ```

  <a name="classes--no-duplicate-members"></a>
  - [9.6](#classes--no-duplicate-members) 避免定义重复的类成员。 eslint: [`no-dupe-class-members`](https://eslint.org/docs/rules/no-dupe-class-members)

    > 为什么? 重复的类成员声明将会默认倾向于最后一个 - 具有重复的类成员可以说是一个错误。

    ```javascript
    // bad
    class Foo {
      bar() { return 1; }
      bar() { return 2; }
    }

    // good
    class Foo {
      bar() { return 1; }
    }

    // good
    class Foo {
      bar() { return 2; }
    }
    ```

**[⬆ 返回目录](#table-of-contents)**

## <a id="modules">模块</a>

  <a name="modules--use-them"></a><a name="10.1"></a>
  - [10.1](#modules--use-them) 你可能经常使用模块 (`import`/`export`) 在一些非标准模块的系统上。 你也可以在你喜欢的模块系统上相互转换。

    > 为什么? 模块是未来的趋势,让我们拥抱未来。

    ```javascript
    // bad
    const AirbnbStyleGuide = require('./AirbnbStyleGuide');
    module.exports = AirbnbStyleGuide.es6;

    // ok
    import AirbnbStyleGuide from './AirbnbStyleGuide';
    export default AirbnbStyleGuide.es6;

    // best
    import { es6 } from './AirbnbStyleGuide';
    export default es6;
    ```

  <a name="modules--no-wildcard"></a><a name="10.2"></a>
  - [10.2](#modules--no-wildcard) 不要使用通配符导入。

    > 为什么? 这确定你有一个单独的默认导出。

    ```javascript
    // bad
    import * as AirbnbStyleGuide from './AirbnbStyleGuide';

    // good
    import AirbnbStyleGuide from './AirbnbStyleGuide';
    ```

  <a name="modules--no-export-from-import"></a><a name="10.3"></a>
  - [10.3](#modules--no-export-from-import) 不要直接从导入导出。

    > 为什么? 虽然写在一行很简洁,但是有一个明确的导入和一个明确的导出能够保证一致性。

    ```javascript
    // bad
    // filename es6.js
    export { es6 as default } from './AirbnbStyleGuide';

    // good
    // filename es6.js
    import { es6 } from './AirbnbStyleGuide';
    export default es6;
    ```

  <a name="modules--no-duplicate-imports"></a>
  - [10.4](#modules--no-duplicate-imports) 只从一个路径导入所有需要的东西。
 eslint: [`no-duplicate-imports`](https://eslint.org/docs/rules/no-duplicate-imports)
    > 为什么? 从同一个路径导入多个行,使代码更难以维护。

    ```javascript
    // bad
    import foo from 'foo';
    // … 其他导入 … //
    import { named1, named2 } from 'foo';

    // good
    import foo, { named1, named2 } from 'foo';

    // good
    import foo, {
      named1,
      named2,
    } from 'foo';
    ```

  <a name="modules--no-mutable-exports"></a>
  - [10.5](#modules--no-mutable-exports) 不要导出可变的引用。
 eslint: [`import/no-mutable-exports`](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-mutable-exports.md)
    > 为什么? 在一般情况下,应该避免发生突变,但是在导出可变引用时及其容易发生突变。虽然在某些特殊情况下,可能需要这样,但是一般情况下只需要导出常量引用。

    ```javascript
    // bad
    let foo = 3;
    export { foo };

    // good
    const foo = 3;
    export { foo };
    ```

  <a name="modules--prefer-default-export"></a>
  - [10.6](#modules--prefer-default-export) 在单个导出的模块中,选择默认模块而不是指定的导出。
 eslint: [`import/prefer-default-export`](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/prefer-default-export.md)
    > 为什么? 为了鼓励更多的文件只导出一件东西,这样可读性和可维护性更好。

    ```javascript
    // bad
    export function foo() {}

    // good
    export default function foo() {}
    ```

  <a name="modules--imports-first"></a>
  - [10.7](#modules--imports-first) 将所有的 `import`s 语句放在所有非导入语句的上边。
 eslint: [`import/first`](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/first.md)
    > 为什么? 由于所有的 `import`s 都被提前,保持他们在顶部是为了防止意外发生。

    ```javascript
    // bad
    import foo from 'foo';
    foo.init();

    import bar from 'bar';

    // good
    import foo from 'foo';
    import bar from 'bar';

    foo.init();
    ```

  <a name="modules--multiline-imports-over-newlines"></a>
  - [10.8](#modules--multiline-imports-over-newlines) 多行导入应该像多行数组和对象一样缩进。

    > 为什么? 花括号和其他规范一样,遵循相同的缩进规则,后边的都好一样。

    ```javascript
    // bad
    import {longNameA, longNameB, longNameC, longNameD, longNameE} from 'path';

    // good
    import {
      longNameA,
      longNameB,
      longNameC,
      longNameD,
      longNameE,
    } from 'path';
    ```

  <a name="modules--no-webpack-loader-syntax"></a>
  - [10.9](#modules--no-webpack-loader-syntax) 在模块导入语句中禁止使用 Webpack 加载器语法。
 eslint: [`import/no-webpack-loader-syntax`](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-webpack-loader-syntax.md)
    > 为什么? 因为在导入语句中使用 webpack 语法,将代码和模块绑定在一起。应该在 `webpack.config.js` 中使用加载器语法。

    ```javascript
    // bad
    import fooSass from 'css!sass!foo.scss';
    import barCss from 'style!css!bar.css';

    // good
    import fooSass from 'foo.scss';
    import barCss from 'bar.css';
    ```

**[⬆ 返回目录](#table-of-contents)**

## <a id="iterators-and-generators">迭代器和发生器</a>

  <a name="iterators--nope"></a><a name="11.1"></a>
  - [11.1](#iterators--nope) 不要使用迭代器。 你应该使用 JavaScript 的高阶函数代替 `for-in` 或者 `for-of`。 eslint: [`no-iterator`](https://eslint.org/docs/rules/no-iterator.html) [`no-restricted-syntax`](https://eslint.org/docs/rules/no-restricted-syntax)

    > 为什么? 这是我们强制的规则。 拥有返回值得纯函数比这个更容易解释。

    > 使用 `map()` / `every()` / `filter()` / `find()` / `findIndex()` / `reduce()` / `some()` / ... 遍历数组, 和使用 `Object.keys()` / `Object.values()` / `Object.entries()` 迭代你的对象生成数组。

    ```javascript
    const numbers = [1, 2, 3, 4, 5];

    // bad
    let sum = 0;
    for (let num of numbers) {
      sum += num;
    }
    sum === 15;

    // good
    let sum = 0;
    numbers.forEach((num) => {
      sum += num;
    });
    sum === 15;

    // best (use the functional force)
    const sum = numbers.reduce((total, num) => total + num, 0);
    sum === 15;

    // bad
    const increasedByOne = [];
    for (let i = 0; i < numbers.length; i++) {
      increasedByOne.push(numbers[i] + 1);
    }

    // good
    const increasedByOne = [];
    numbers.forEach((num) => {
      increasedByOne.push(num + 1);
    });

    // best (keeping it functional)
    const increasedByOne = numbers.map(num => num + 1);
    ```

  <a name="generators--nope"></a><a name="11.2"></a>
  - [11.2](#generators--nope) 不要使用发生器。

    > 为什么? 它们不能很好的适应 ES5。

  <a name="generators--spacing"></a>
  - [11.3](#generators--spacing) 如果你必须使用发生器或者无视 [我们的建议](#generators--nope),请确保他们的函数签名是正常的间隔。 eslint: [`generator-star-spacing`](https://eslint.org/docs/rules/generator-star-spacing)

    > 为什么? `function` 和 `*` 是同一个概念关键字的一部分 - `*` 不是 `function` 的修饰符, `function*` 是一个不同于 `function` 的构造器。

    ```javascript
    // bad
    function * foo() {
      // ...
    }

    // bad
    const bar = function * () {
      // ...
    };

    // bad
    const baz = function *() {
      // ...
    };

    // bad
    const quux = function*() {
      // ...
    };

    // bad
    function*foo() {
      // ...
    }

    // bad
    function *foo() {
      // ...
    }

    // very bad
    function
    *
    foo() {
      // ...
    }

    // very bad
    const wat = function
    *
    () {
      // ...
    };

    // good
    function* foo() {
      // ...
    }

    // good
    const foo = function* () {
      // ...
    };
    ```

**[⬆ 返回目录](#table-of-contents)**

## <a id="properties">属性</a>

  <a name="properties--dot"></a><a name="12.1"></a>
  - [12.1](#properties--dot) 访问属性时使用点符号。 eslint: [`dot-notation`](https://eslint.org/docs/rules/dot-notation.html)

    ```javascript
    const luke = {
      jedi: true,
      age: 28,
    };

    // bad
    const isJedi = luke['jedi'];

    // good
    const isJedi = luke.jedi;
    ```

  <a name="properties--bracket"></a><a name="12.2"></a>
  - [12.2](#properties--bracket) 使用变量访问属性时,使用 `[]`表示法。

    ```javascript
    const luke = {
      jedi: true,
      age: 28,
    };

    function getProp(prop) {
      return luke[prop];
    }

    const isJedi = getProp('jedi');
    ```
  <a name="es2016-properties--exponentiation-operator"></a>
  - [12.3](#es2016-properties--exponentiation-operator) 计算指数时,可以使用 `**` 运算符。 eslint: [`no-restricted-properties`](https://eslint.org/docs/rules/no-restricted-properties).

    ```javascript
    // bad
    const binary = Math.pow(2, 10);

    // good
    const binary = 2 ** 10;
    ```

**[⬆ 返回目录](#table-of-contents)**

## <a id="variables">变量</a>

  <a name="variables--const"></a><a name="13.1"></a>
  - [13.1](#variables--const) 使用 `const` 或者 `let` 来定义变量。 不这样做将创建一个全局变量。 我们希望避免污染全局命名空间。 Captain Planet 警告过我们。 eslint: [`no-undef`](https://eslint.org/docs/rules/no-undef) [`prefer-const`](https://eslint.org/docs/rules/prefer-const)

    ```javascript
    // bad
    superPower = new SuperPower();

    // good
    const superPower = new SuperPower();
    ```

  <a name="variables--one-const"></a><a name="13.2"></a>
  - [13.2](#variables--one-const) 使用 `const` 或者 `let` 声明每一个变量。 eslint: [`one-var`](https://eslint.org/docs/rules/one-var.html)

    > 为什么? 这样更容易添加新的变量声明,而且你不必担心是使用 `;` 还是使用 `,` 或引入标点符号的差别。 你可以通过 debugger 逐步查看每个声明,而不是立即跳过所有声明。

    ```javascript
    // bad
    const items = getItems(),
        goSportsTeam = true,
        dragonball = 'z';

    // bad
    // (compare to above, and try to spot the mistake)
    const items = getItems(),
        goSportsTeam = true;
        dragonball = 'z';

    // good
    const items = getItems();
    const goSportsTeam = true;
    const dragonball = 'z';
    ```

  <a name="variables--const-let-group"></a><a name="13.3"></a>
  - [13.3](#variables--const-let-group) 把 `const` 声明的放在一起,把 `let` 声明的放在一起。.

    > 为什么? 这在后边如果需要根据前边的赋值变量指定一个变量时很有用。

    ```javascript
    // bad
    let i, len, dragonball,
        items = getItems(),
        goSportsTeam = true;

    // bad
    let i;
    const items = getItems();
    let dragonball;
    const goSportsTeam = true;
    let len;

    // good
    const goSportsTeam = true;
    const items = getItems();
    let dragonball;
    let i;
    let length;
    ```

  <a name="variables--define-where-used"></a><a name="13.4"></a>
  - [13.4](#variables--define-where-used) 在你需要的使用定义变量,但是要把它们放在一个合理的地方。

    > 为什么? `let` 和 `const` 是块级作用域而不是函数作用域。

    ```javascript
    // bad - 不必要的函数调用
    function checkName(hasName) {
      const name = getName();

      if (hasName === 'test') {
        return false;
      }

      if (name === 'test') {
        this.setName('');
        return false;
      }

      return name;
    }

    // good
    function checkName(hasName) {
      if (hasName === 'test') {
        return false;
      }

      const name = getName();

      if (name === 'test') {
        this.setName('');
        return false;
      }

      return name;
    }
    ```
  <a name="variables--no-chain-assignment"></a><a name="13.5"></a>
  - [13.5](#variables--no-chain-assignment) 不要链式变量赋值。 eslint: [`no-multi-assign`](https://eslint.org/docs/rules/no-multi-assign)

    > 为什么? 链式变量赋值会创建隐式全局变量。

    ```javascript
    // bad
    (function example() {
      // JavaScript 把它解释为
      // let a = ( b = ( c = 1 ) );
      // let 关键词只适用于变量 a ;变量 b 和变量 c 则变成了全局变量。
      let a = b = c = 1;
    }());

    console.log(a); // throws ReferenceError
    console.log(b); // 1
    console.log(c); // 1

    // good
    (function example() {
      let a = 1;
      let b = a;
      let c = a;
    }());

    console.log(a); // throws ReferenceError
    console.log(b); // throws ReferenceError
    console.log(c); // throws ReferenceError

    // 对于 `const` 也一样
    ```

  <a name="variables--unary-increment-decrement"></a><a name="13.6"></a>
  - [13.6](#variables--unary-increment-decrement) 避免使用不必要的递增和递减 (`++`, `--`)。 eslint [`no-plusplus`](https://eslint.org/docs/rules/no-plusplus)

    > 为什么? 在eslint文档中,一元递增和递减语句以自动分号插入为主题,并且在应用程序中可能会导致默认值的递增或递减。它还可以用像 `num += 1` 这样的语句来改变您的值,而不是使用 `num++` 或 `num ++` 。不允许不必要的增量和减量语句也会使您无法预先递增/预递减值,这也会导致程序中的意外行为。

    ```javascript
    // bad

    const array = [1, 2, 3];
    let num = 1;
    num++;
    --num;

    let sum = 0;
    let truthyCount = 0;
    for (let i = 0; i < array.length; i++) {
      let value = array[i];
      sum += value;
      if (value) {
        truthyCount++;
      }
    }

    // good

    const array = [1, 2, 3];
    let num = 1;
    num += 1;
    num -= 1;

    const sum = array.reduce((a, b) => a + b, 0);
    const truthyCount = array.filter(Boolean).length;
    ```

<a name="variables--linebreak"></a>
  - [13.7](#variables--linebreak) 避免在赋值语句 `=` 前后换行。如果你的代码违反了 [`max-len`](https://eslint.org/docs/rules/max-len.html), 使用括号包裹。 eslint [`operator-linebreak`](https://eslint.org/docs/rules/operator-linebreak.html).

    > 为什么? 在 `=` 前后换行,可能混淆赋的值。

    ```javascript
    // bad
    const foo =
      superLongLongLongLongLongLongLongLongFunctionName();

    // bad
    const foo
      = 'superLongLongLongLongLongLongLongLongString';

    // good
    const foo = (
      superLongLongLongLongLongLongLongLongFunctionName()
    );

    // good
    const foo = 'superLongLongLongLongLongLongLongLongString';
    ```

**[⬆ 返回目录](#table-of-contents)**

## <a id="hoisting">提升</a>

  <a name="hoisting--about"></a><a name="14.1"></a>
  - [14.1](#hoisting--about) `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 不再安全](http://es-discourse.com/t/why-typeof-is-no-longer-safe/15) 是很重要的。

    ```javascript
    // 我们知道这个行不通 (假设没有未定义的全局变量)
    function example() {
      console.log(notDefined); // => throws a ReferenceError
    }

    // 在引用变量后创建变量声明将会因变量提升而起作用。
    // 注意: 真正的值 `true` 不会被提升。
    function example() {
      console.log(declaredButNotAssigned); // => undefined
      var declaredButNotAssigned = true;
    }

    // 解释器将变量提升到函数的顶部
    // 这意味着我们可以将上边的例子重写为:
    function example() {
      let declaredButNotAssigned;
      console.log(declaredButNotAssigned); // => undefined
      declaredButNotAssigned = true;
    }

    // 使用 const 和 let
    function example() {
      console.log(declaredButNotAssigned); // => throws a ReferenceError
      console.log(typeof declaredButNotAssigned); // => throws a ReferenceError
      const declaredButNotAssigned = true;
    }
    ```

  <a name="hoisting--anon-expressions"></a><a name="14.2"></a>
  - [14.2](#hoisting--anon-expressions) 匿名函数表达式提升变量名,而不是函数赋值。

    ```javascript
    function example() {
      console.log(anonymous); // => undefined

      anonymous(); // => TypeError anonymous is not a function

      var anonymous = function () {
        console.log('anonymous function expression');
      };
    }
    ```

  <a name="hoisting--named-expresions"></a><a name="hoisting--named-expressions"></a><a name="14.3"></a>
  - [14.3](#hoisting--named-expressions) 命名函数表达式提升的是变量名,而不是函数名或者函数体。

    ```javascript
    function example() {
      console.log(named); // => undefined

      named(); // => TypeError named is not a function

      superPower(); // => ReferenceError superPower is not defined

      var named = function superPower() {
        console.log('Flying');
      };
    }

    // 当函数名和变量名相同时也是如此。
    function example() {
      console.log(named); // => undefined

      named(); // => TypeError named is not a function

      var named = function named() {
        console.log('named');
      };
    }
    ```

  <a name="hoisting--declarations"></a><a name="14.4"></a>
  - [14.4](#hoisting--declarations) 函数声明提升其名称和函数体。

    ```javascript
    function example() {
      superPower(); // => Flying

      function superPower() {
        console.log('Flying');
      }
    }
    ```

  - 更多信息请参考 [Ben Cherry](http://www.adequatelygood.com/) 的 [JavaScript Scoping & Hoisting](http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting/)。

**[⬆ 返回目录](#table-of-contents)**

## <a id="comparison-operators--equality">比较运算符和等号</a>

  <a name="comparison--eqeqeq"></a><a name="15.1"></a>
  - [15.1](#comparison--eqeqeq) 使用 `===` 和 `!==` 而不是 `==` 和 `!=`。 eslint: [`eqeqeq`](https://eslint.org/docs/rules/eqeqeq.html)

  <a name="comparison--if"></a><a name="15.2"></a>
  - [15.2](#comparison--if) 条件语句,例如 `if` 语句使用 `ToBoolean` 的抽象方法来计算表达式的结果,并始终遵循以下简单的规则:

    - **Objects** 的取值为: **true**
    - **Undefined** 的取值为: **false**
    - **Null** 的取值为: **false**
    - **Booleans** 的取值为: **布尔值的取值**
    - **Numbers** 的取值为:如果为 **+0, -0, or NaN** 值为 **false** 否则为 **true**
    - **Strings** 的取值为: 如果是一个空字符串 `''` 值为 **false** 否则为 **true**

    ```javascript
    if ([0] && []) {
      // true
      // 一个数组(即使是空的)是一个对象,对象的取值为 true
    }
    ```

  <a name="comparison--shortcuts"></a><a name="15.3"></a>
  - [15.3](#comparison--shortcuts) 对于布尔值使用简写,但是对于字符串和数字进行显式比较。

    ```javascript
    // bad
    if (isValid === true) {
      // ...
    }

    // good
    if (isValid) {
      // ...
    }

    // bad
    if (name) {
      // ...
    }

    // good
    if (name !== '') {
      // ...
    }

    // bad
    if (collection.length) {
      // ...
    }

    // good
    if (collection.length > 0) {
      // ...
    }
    ```

  <a name="comparison--moreinfo"></a><a name="15.4"></a>
  - [15.4](#comparison--moreinfo) 获取更多信息请查看 Angus Croll 的 [Truth Equality and JavaScript](https://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/#more-2108) 。

  <a name="comparison--switch-blocks"></a><a name="15.5"></a>
  - [15.5](#comparison--switch-blocks) 在 `case` 和 `default` 的子句中,如果存在声明 (例如. `let`, `const`, `function`, 和 `class`),使用大括号来创建块 。 eslint: [`no-case-declarations`](https://eslint.org/docs/rules/no-case-declarations.html)

    > 为什么? 语法声明在整个 `switch` 块中都是可见的,但是只有在赋值的时候才会被初始化,这种情况只有在 `case` 条件达到才会发生。 当多个 `case` 语句定义相同的东西是,这会导致问题问题。

    ```javascript
    // bad
    switch (foo) {
      case 1:
        let x = 1;
        break;
      case 2:
        const y = 2;
        break;
      case 3:
        function f() {
          // ...
        }
        break;
      default:
        class C {}
    }

    // good
    switch (foo) {
      case 1: {
        let x = 1;
        break;
      }
      case 2: {
        const y = 2;
        break;
      }
      case 3: {
        function f() {
          // ...
        }
        break;
      }
      case 4:
        bar();
        break;
      default: {
        class C {}
      }
    }
    ```

  <a name="comparison--nested-ternaries"></a><a name="15.6"></a>
  - [15.6](#comparison--nested-ternaries) 三目表达式不应该嵌套,通常是单行表达式。 eslint: [`no-nested-ternary`](https://eslint.org/docs/rules/no-nested-ternary.html)

    ```javascript
    // bad
    const foo = maybe1 > maybe2
      ? "bar"
      : value1 > value2 ? "baz" : null;

    // 分离为两个三目表达式
    const maybeNull = value1 > value2 ? 'baz' : null;

    // better
    const foo = maybe1 > maybe2
      ? 'bar'
      : maybeNull;

    // best
    const foo = maybe1 > maybe2 ? 'bar' : maybeNull;
    ```

  <a name="comparison--unneeded-ternary"></a><a name="15.7"></a>
  - [15.7](#comparison--unneeded-ternary) 避免不必要的三目表达式。 eslint: [`no-unneeded-ternary`](https://eslint.org/docs/rules/no-unneeded-ternary.html)

    ```javascript
    // bad
    const foo = a ? a : b;
    const bar = c ? true : false;
    const baz = c ? false : true;

    // good
    const foo = a || b;
    const bar = !!c;
    const baz = !c;
    ```

  <a name="comparison--no-mixed-operators"></a>
  - [15.8](#comparison--no-mixed-operators) 使用该混合运算符时,使用括号括起来。 唯一例外的是标准算数运算符 (`+`, `-`, `*`, & `/`) 因为他们的优先级被广泛理解。 eslint: [`no-mixed-operators`](https://eslint.org/docs/rules/no-mixed-operators.html)

    > 为什么? 这能提高可读性并且表明开发人员的意图。

    ```javascript
    // bad
    const foo = a && b < 0 || c > 0 || d + 1 === 0;

    // bad
    const bar = a ** b - 5 % d;

    // bad
    // 可能陷入一种 (a || b) && c 的思考
    if (a || b && c) {
      return d;
    }

    // good
    const foo = (a && b < 0) || c > 0 || (d + 1 === 0);

    // good
    const bar = (a ** b) - (5 % d);

    // good
    if (a || (b && c)) {
      return d;
    }

    // good
    const bar = a + b / c * d;
    ```

**[⬆ 返回目录](#table-of-contents)**

## <a id="blocks">块</a>

  <a name="blocks--braces"></a><a name="16.1"></a>
  - [16.1](#blocks--braces) 当有多行代码块的时候,使用大括号包裹。 eslint: [`nonblock-statement-body-position`](https://eslint.org/docs/rules/nonblock-statement-body-position)

    ```javascript
    // bad
    if (test)
      return false;

    // good
    if (test) return false;

    // good
    if (test) {
      return false;
    }

    // bad
    function foo() { return false; }

    // good
    function bar() {
      return false;
    }
    ```

  <a name="blocks--cuddled-elses"></a><a name="16.2"></a>
  - [16.2](#blocks--cuddled-elses) 如果你使用的是 `if` 和 `else` 的多行代码块,则将 `else` 语句放在 `if` 块闭括号同一行的位置。 eslint: [`brace-style`](https://eslint.org/docs/rules/brace-style.html)

    ```javascript
    // bad
    if (test) {
      thing1();
      thing2();
    }
    else {
      thing3();
    }

    // good
    if (test) {
      thing1();
      thing2();
    } else {
      thing3();
    }
    ```

  <a name="blocks--no-else-return"></a><a name="16.3"></a>
  - [16.3](#blocks--no-else-return) 如果一个 `if` 块总是执行一个 `return` 语句,那么接下来的 `else` 块就没有必要了。 如果一个包含 `return` 语句的 `else if` 块,在一个包含了 `return` 语句的 `if` 块之后,那么可以拆成多个 `if` 块。 eslint: [`no-else-return`](https://eslint.org/docs/rules/no-else-return)

    ```javascript
    // bad
    function foo() {
      if (x) {
        return x;
      } else {
        return y;
      }
    }

    // bad
    function cats() {
      if (x) {
        return x;
      } else if (y) {
        return y;
      }
    }

    // bad
    function dogs() {
      if (x) {
        return x;
      } else {
        if (y) {
          return y;
        }
      }
    }

    // good
    function foo() {
      if (x) {
        return x;
      }

      return y;
    }

    // good
    function cats() {
      if (x) {
        return x;
      }

      if (y) {
        return y;
      }
    }

    // good
    function dogs(x) {
      if (x) {
        if (z) {
          return y;
        }
      } else {
        return z;
      }
    }
    ```

**[⬆ 返回目录](#table-of-contents)**

## <a id="control-statements">控制语句</a>

  <a name="control-statements"></a>
  - [17.1](#control-statements) 如果你的控制语句 (`if`, `while` 等) 太长或者超过了一行最大长度的限制,则可以将每个条件(或组)放入一个新的行。 逻辑运算符应该在行的开始。

    > 为什么? 要求操作符在行的开始保持对齐并遵循类似方法衔接的模式。 这提高了可读性,并且使更复杂的逻辑更容易直观的被理解。

    ```javascript
    // bad
    if ((foo === 123 || bar === 'abc') && doesItLookGoodWhenItBecomesThatLong() && isThisReallyHappening()) {
      thing1();
    }

    // bad
    if (foo === 123 &&
      bar === 'abc') {
      thing1();
    }

    // bad
    if (foo === 123
      && bar === 'abc') {
      thing1();
    }

    // bad
    if (
      foo === 123 &&
      bar === 'abc'
    ) {
      thing1();
    }

    // good
    if (
      foo === 123
      && bar === 'abc'
    ) {
      thing1();
    }

    // good
    if (
      (foo === 123 || bar === 'abc')
      && doesItLookGoodWhenItBecomesThatLong()
      && isThisReallyHappening()
    ) {
      thing1();
    }

    // good
    if (foo === 123 && bar === 'abc') {
      thing1();
    }
    ```

  <a name="control-statement--value-selection"></a>
  - [17.2](#control-statements--value-selection) 不要使用选择操作符代替控制语句。

    ```javascript
    // bad
    !isRunning && startRunning();

    // good
    if (!isRunning) {
      startRunning();
    }
    ```

**[⬆ 返回目录](#table-of-contents)**

## <a id="comments">注释</a>

  <a name="comments--multiline"></a><a name="17.1"></a>
  - [18.1](#comments--multiline) 使用 `/** ... */` 来进行多行注释。

    ```javascript
    // bad
    // make() returns a new element
    // based on the passed in tag name
    //
    // @param {String} tag
    // @return {Element} element
    function make(tag) {

      // ...

      return element;
    }

    // good
    /**
     * make() returns a new element
     * based on the passed-in tag name
     */
    function make(tag) {

      // ...

      return element;
    }
    ```

  <a name="comments--singleline"></a><a name="17.2"></a>
  - [18.2](#comments--singleline) 使用 `//` 进行单行注释。 将单行注释放在需要注释的行的上方新行。 在注释之前放一个空行,除非它在块的第一行。

    ```javascript
    // bad
    const active = true;  // is current tab

    // good
    // is current tab
    const active = true;

    // bad
    function getType() {
      console.log('fetching type...');
      // set the default type to 'no type'
      const type = this.type || 'no type';

      return type;
    }

    // good
    function getType() {
      console.log('fetching type...');

      // set the default type to 'no type'
      const type = this.type || 'no type';

      return type;
    }

    // also good
    function getType() {
      // set the default type to 'no type'
      const type = this.type || 'no type';

      return type;
    }
    ```

  <a name="comments--spaces"></a>
  - [18.3](#comments--spaces) 用一个空格开始所有的注释,使它更容易阅读。 eslint: [`spaced-comment`](https://eslint.org/docs/rules/spaced-comment)

    ```javascript
    // bad
    //is current tab
    const active = true;

    // good
    // is current tab
    const active = true;

    // bad
    /**
     *make() returns a new element
     *based on the passed-in tag name
     */
    function make(tag) {

      // ...

      return element;
    }

    // good
    /**
     * make() returns a new element
     * based on the passed-in tag name
     */
    function make(tag) {

      // ...

      return element;
    }
    ```

  <a name="comments--actionitems"></a><a name="17.3"></a>
  - [18.4](#comments--actionitems) 使用 `FIXME` 或者 `TODO` 开始你的注释可以帮助其他开发人员快速了解,如果你提出了一个需要重新审视的问题,或者你对需要实现的问题提出的解决方案。 这些不同于其他评论,因为他们是可操作的。 这些行为是 `FIXME: -- 需要解决这个问题` 或者 `TODO: -- 需要被实现`。

  <a name="comments--fixme"></a><a name="17.4"></a>
  - [18.5](#comments--fixme) 使用 `// FIXME:` 注释一个问题。

    ```javascript
    class Calculator extends Abacus {
      constructor() {
        super();

        // FIXME: 这里不应该使用全局变量
        total = 0;
      }
    }
    ```

  <a name="comments--todo"></a><a name="17.5"></a>
  - [18.6](#comments--todo) 使用 `// TODO:` 注释解决问题的方法。

    ```javascript
    class Calculator extends Abacus {
      constructor() {
        super();

        // TODO: total 应该由一个 param 的选项配置
        this.total = 0;
      }
    }
    ```

**[⬆ 返回目录](#table-of-contents)**

## <a id="whitespace">空白</a>

  <a name="whitespace--spaces"></a><a name="18.1"></a>
  - [19.1](#whitespace--spaces) 使用 tabs (空格字符) 设置为 2 个空格。 eslint: [`indent`](https://eslint.org/docs/rules/indent.html)

    ```javascript
    // bad
    function foo() {
    ∙∙∙∙let name;
    }

    // bad
    function bar() {
    ∙let name;
    }

    // good
    function baz() {
    ∙∙let name;
    }
    ```

  <a name="whitespace--before-blocks"></a><a name="18.2"></a>
  - [19.2](#whitespace--before-blocks) 在主体前放置一个空格。 eslint: [`space-before-blocks`](https://eslint.org/docs/rules/space-before-blocks.html)

    ```javascript
    // bad
    function test(){
      console.log('test');
    }

    // good
    function test() {
      console.log('test');
    }

    // bad
    dog.set('attr',{
      age: '1 year',
      breed: 'Bernese Mountain Dog',
    });

    // good
    dog.set('attr', {
      age: '1 year',
      breed: 'Bernese Mountain Dog',
    });
    ```

  <a name="whitespace--around-keywords"></a><a name="18.3"></a>
  - [19.3](#whitespace--around-keywords) 在控制语句(`if`, `while` 等)开始括号之前放置一个空格。 在函数调用和是声明中,在参数列表和函数名之间没有空格。 eslint: [`keyword-spacing`](https://eslint.org/docs/rules/keyword-spacing.html)

    ```javascript
    // bad
    if(isJedi) {
      fight ();
    }

    // good
    if (isJedi) {
      fight();
    }

    // bad
    function fight () {
      console.log ('Swooosh!');
    }

    // good
    function fight() {
      console.log('Swooosh!');
    }
    ```

  <a name="whitespace--infix-ops"></a><a name="18.4"></a>
  - [19.4](#whitespace--infix-ops) 用空格分离操作符。 eslint: [`space-infix-ops`](https://eslint.org/docs/rules/space-infix-ops.html)

    ```javascript
    // bad
    const x=y+5;

    // good
    const x = y + 5;
    ```

  <a name="whitespace--newline-at-end"></a><a name="18.5"></a>
  - [19.5](#whitespace--newline-at-end) 使用单个换行符结束文件。 eslint: [`eol-last`](https://github.com/eslint/eslint/blob/master/docs/rules/eol-last.md)

    ```javascript
    // bad
    import { es6 } from './AirbnbStyleGuide';
      // ...
    export default es6;
    ```

    ```javascript
    // bad
    import { es6 } from './AirbnbStyleGuide';
      // ...
    export default es6;↵
    ↵
    ```

    ```javascript
    // good
    import { es6 } from './AirbnbStyleGuide';
      // ...
    export default es6;↵
    ```

  <a name="whitespace--chains"></a><a name="18.6"></a>
  - [19.6](#whitespace--chains) 在使用链式方法调用的时候使用缩进(超过两个方法链)。 使用一个引导点,强调该行是方法调用,而不是新的语句。 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)

    ```javascript
    // bad
    $('#items').find('.selected').highlight().end().find('.open').updateCount();

    // bad
    $('#items').
      find('.selected').
        highlight().
        end().
      find('.open').
        updateCount();

    // good
    $('#items')
      .find('.selected')
        .highlight()
        .end()
      .find('.open')
        .updateCount();

    // bad
    const leds = stage.selectAll('.led').data(data).enter().append('svg:svg').classed('led', true)
        .attr('width', (radius + margin) * 2).append('svg:g')
        .attr('transform', `translate(${radius + margin},${radius + margin})`)
        .call(tron.led);

    // good
    const leds = stage.selectAll('.led')
        .data(data)
      .enter().append('svg:svg')
        .classed('led', true)
        .attr('width', (radius + margin) * 2)
      .append('svg:g')
        .attr('transform', `translate(${radius + margin},${radius + margin})`)
        .call(tron.led);

    // good
    const leds = stage.selectAll('.led').data(data);
    ```

  <a name="whitespace--after-blocks"></a><a name="18.7"></a>
  - [19.7](#whitespace--after-blocks) 在块和下一个语句之前留下一空白行。

    ```javascript
    // bad
    if (foo) {
      return bar;
    }
    return baz;

    // good
    if (foo) {
      return bar;
    }

    return baz;

    // bad
    const obj = {
      foo() {
      },
      bar() {
      },
    };
    return obj;

    // good
    const obj = {
      foo() {
      },

      bar() {
      },
    };

    return obj;

    // bad
    const arr = [
      function foo() {
      },
      function bar() {
      },
    ];
    return arr;

    // good
    const arr = [
      function foo() {
      },

      function bar() {
      },
    ];

    return arr;
    ```

  <a name="whitespace--padded-blocks"></a><a name="18.8"></a>
  - [19.8](#whitespace--padded-blocks) 不要在块的开头使用空白行。 eslint: [`padded-blocks`](https://eslint.org/docs/rules/padded-blocks.html)

    ```javascript
    // bad
    function bar() {

      console.log(foo);

    }

    // bad
    if (baz) {

      console.log(qux);
    } else {
      console.log(foo);

    }

    // bad
    class Foo {

      constructor(bar) {
        this.bar = bar;
      }
    }

    // good
    function bar() {
      console.log(foo);
    }

    // good
    if (baz) {
      console.log(qux);
    } else {
      console.log(foo);
    }
    ```

  <a name="whitespace--in-parens"></a><a name="18.9"></a>
  - [19.9](#whitespace--in-parens) 不要在括号内添加空格。 eslint: [`space-in-parens`](https://eslint.org/docs/rules/space-in-parens.html)

    ```javascript
    // bad
    function bar( foo ) {
      return foo;
    }

    // good
    function bar(foo) {
      return foo;
    }

    // bad
    if ( foo ) {
      console.log(foo);
    }

    // good
    if (foo) {
      console.log(foo);
    }
    ```

  <a name="whitespace--in-brackets"></a><a name="18.10"></a>
  - [19.10](#whitespace--in-brackets) 不要在中括号中添加空格。 eslint: [`array-bracket-spacing`](https://eslint.org/docs/rules/array-bracket-spacing.html)

    ```javascript
    // bad
    const foo = [ 1, 2, 3 ];
    console.log(foo[ 0 ]);

    // good
    const foo = [1, 2, 3];
    console.log(foo[0]);
    ```

  <a name="whitespace--in-braces"></a><a name="18.11"></a>
  - [19.11](#whitespace--in-braces) 在花括号内添加空格。 eslint: [`object-curly-spacing`](https://eslint.org/docs/rules/object-curly-spacing.html)

    ```javascript
    // bad
    const foo = {clark: 'kent'};

    // good
    const foo = { clark: 'kent' };
    ```

  <a name="whitespace--max-len"></a><a name="18.12"></a>
  - [19.12](#whitespace--max-len) 避免让你的代码行超过100个字符(包括空格)。 注意:根据上边的 [约束](#strings--line-length),长字符串可免除此规定,不应分解。 eslint: [`max-len`](https://eslint.org/docs/rules/max-len.html)

    > 为什么? 这样能够确保可读性和可维护性。

    ```javascript
    // bad
    const foo = jsonData && jsonData.foo && jsonData.foo.bar && jsonData.foo.bar.baz && jsonData.foo.bar.baz.quux && jsonData.foo.bar.baz.quux.xyzzy;

    // bad
    $.ajax({ method: 'POST', url: 'https://airbnb.com/', data: { name: 'John' } }).done(() => console.log('Congratulations!')).fail(() => console.log('You have failed this city.'));

    // good
    const foo = jsonData
      && jsonData.foo
      && jsonData.foo.bar
      && jsonData.foo.bar.baz
      && jsonData.foo.bar.baz.quux
      && jsonData.foo.bar.baz.quux.xyzzy;

    // good
    $.ajax({
      method: 'POST',
      url: 'https://airbnb.com/',
      data: { name: 'John' },
    })
      .done(() => console.log('Congratulations!'))
      .fail(() => console.log('You have failed this city.'));
    ```

  <a name="whitespace--block-spacing"></a>
  - [19.13](#whitespace--block-spacing) 要求打开的块标志和同一行上的标志拥有一致的间距。此规则还会在同一行关闭的块标记和前边的标记强制实施一致的间距。 eslint: [`block-spacing`](https://eslint.org/docs/rules/block-spacing)

    ```javascript
    // bad
    function foo() {return true;}
    if (foo) { bar = 0;}

    // good
    function foo() { return true; }
    if (foo) { bar = 0; }
    ```

  <a name="whitespace--comma-spacing"></a>
  - [19.14](#whitespace--comma-spacing) 逗号之前避免使用空格,逗号之后需要使用空格。eslint: [`comma-spacing`](https://eslint.org/docs/rules/comma-spacing)

    ```javascript
    // bad
    var foo = 1,bar = 2;
    var arr = [1 , 2];

    // good
    var foo = 1, bar = 2;
    var arr = [1, 2];
    ```

  <a name="whitespace--computed-property-spacing"></a>
  - [19.15](#whitespace--computed-property-spacing) 在计算属性之间强化间距。eslint: [`computed-property-spacing`](https://eslint.org/docs/rules/computed-property-spacing)

    ```javascript
    // bad
    obj[foo ]
    obj[ 'foo']
    var x = {[ b ]: a}
    obj[foo[ bar ]]

    // good
    obj[foo]
    obj['foo']
    var x = { [b]: a }
    obj[foo[bar]]
    ```

  <a name="whitespace--func-call-spacing"></a>
  - [19.16](#whitespace--func-call-spacing) 在函数和它的调用之间强化间距。 eslint: [`func-call-spacing`](https://eslint.org/docs/rules/func-call-spacing)

    ```javascript
    // bad
    func ();

    func
    ();

    // good
    func();
    ```

  <a name="whitespace--key-spacing"></a>
  - [19.17](#whitespace--key-spacing) 在对象的属性和值之间强化间距。 eslint: [`key-spacing`](https://eslint.org/docs/rules/key-spacing)

    ```javascript
    // bad
    var obj = { "foo" : 42 };
    var obj2 = { "foo":42 };

    // good
    var obj = { "foo": 42 };
    ```

  <a name="whitespace--no-trailing-spaces"></a>
  - [19.18](#whitespace--no-trailing-spaces) 在行的末尾避免使用空格。 eslint: [`no-trailing-spaces`](https://eslint.org/docs/rules/no-trailing-spaces)

  <a name="whitespace--no-multiple-empty-lines"></a>
  - [19.19](#whitespace--no-multiple-empty-lines) 避免多个空行,并且只允许在文件末尾添加一个换行符。 eslint: [`no-multiple-empty-lines`](https://eslint.org/docs/rules/no-multiple-empty-lines)

    <!-- markdownlint-disable MD012 -->
    ```javascript
    // bad
    var x = 1;



    var y = 2;

    // good
    var x = 1;

    var y = 2;
    ```
    <!-- markdownlint-enable MD012 -->

**[⬆ 返回目录](#table-of-contents)**

## <a id="commas">逗号</a>

  <a name="commas--leading-trailing"></a><a name="19.1"></a>
  - [20.1](#commas--leading-trailing) 逗号前置: **不行** eslint: [`comma-style`](https://eslint.org/docs/rules/comma-style.html)

    ```javascript
    // bad
    const story = [
        once
      , upon
      , aTime
    ];

    // good
    const story = [
      once,
      upon,
      aTime,
    ];

    // bad
    const hero = {
        firstName: 'Ada'
      , lastName: 'Lovelace'
      , birthYear: 1815
      , superPower: 'computers'
    };

    // good
    const hero = {
      firstName: 'Ada',
      lastName: 'Lovelace',
      birthYear: 1815,
      superPower: 'computers',
    };
    ```

  <a name="commas--dangling"></a><a name="19.2"></a>
  - [20.2](#commas--dangling) 添加尾随逗号: **可以** eslint: [`comma-dangle`](https://eslint.org/docs/rules/comma-dangle.html)

    > 为什么? 这个将造成更清洁的 git 扩展差异。 另外,像 Babel 这样的编译器,会在转换后的代码中删除额外的尾随逗号,这意味着你不必担心在浏览器中后面的 [尾随逗号问题](https://github.com/airbnb/javascript/blob/es5-deprecated/es5/README.md#commas) 。

    ```diff
    // bad - 没有尾随逗号的 git 差异
    const hero = {
         firstName: 'Florence',
    -    lastName: 'Nightingale'
    +    lastName: 'Nightingale',
    +    inventorOf: ['coxcomb chart', 'modern nursing']
    };

    // good - 有尾随逗号的 git 差异
    const hero = {
         firstName: 'Florence',
         lastName: 'Nightingale',
    +    inventorOf: ['coxcomb chart', 'modern nursing'],
    };
    ```

    ```javascript
    // bad
    const hero = {
      firstName: 'Dana',
      lastName: 'Scully'
    };

    const heroes = [
      'Batman',
      'Superman'
    ];

    // good
    const hero = {
      firstName: 'Dana',
      lastName: 'Scully',
    };

    const heroes = [
      'Batman',
      'Superman',
    ];

    // bad
    function createHero(
      firstName,
      lastName,
      inventorOf
    ) {
      // does nothing
    }

    // good
    function createHero(
      firstName,
      lastName,
      inventorOf,
    ) {
      // does nothing
    }

    // good (注意逗号不能出现在 "rest" 元素后边)
    function createHero(
      firstName,
      lastName,
      inventorOf,
      ...heroArgs
    ) {
      // does nothing
    }

    // bad
    createHero(
      firstName,
      lastName,
      inventorOf
    );

    // good
    createHero(
      firstName,
      lastName,
      inventorOf,
    );

    // good (注意逗号不能出现在 "rest" 元素后边)
    createHero(
      firstName,
      lastName,
      inventorOf,
      ...heroArgs
    );
    ```

**[⬆ 返回目录](#table-of-contents)**

## <a id="semicolons">分号</a>

  <a name="semicolons--required"></a><a name="20.1"></a>
  - [21.1](#semicolons--required) **对** eslint: [`semi`](https://eslint.org/docs/rules/semi.html)

    > 为什么? 当 JavaScript 遇见一个没有分号的换行符时,它会使用一个叫做 [Automatic Semicolon Insertion](https://tc39.github.io/ecma262/#sec-automatic-semicolon-insertion) 的规则来确定是否应该以换行符视为语句的结束,并且如果认为如此,会在代码中断前插入一个分号到代码中。 但是,ASI 包含了一些奇怪的行为,如果 JavaScript 错误的解释了你的换行符,你的代码将会中断。 随着新特性成为 JavaScript 的一部分,这些规则将变得更加复杂。 明确地终止你的语句,并配置你的 linter 以捕获缺少的分号将有助于防止你遇到的问题。

    ```javascript
    // bad - 可能异常
    const luke = {}
    const leia = {}
    [luke, leia].forEach(jedi => jedi.father = 'vader')

    // bad - 可能异常
    const reaction = "No! That's impossible!"
    (async function meanwhileOnTheFalcon() {
      // handle `leia`, `lando`, `chewie`, `r2`, `c3p0`
      // ...
    }())

    // bad - 返回 `undefined` 而不是下一行的值 - 当 `return` 单独一行的时候 ASI 总是会发生
    function foo() {
      return
        'search your feelings, you know it to be foo'
    }

    // good
    const luke = {};
    const leia = {};
    [luke, leia].forEach((jedi) => {
      jedi.father = 'vader';
    });

    // good
    const reaction = "No! That's impossible!";
    (async function meanwhileOnTheFalcon() {
      // handle `leia`, `lando`, `chewie`, `r2`, `c3p0`
      // ...
    }());

    // good
    function foo() {
      return 'search your feelings, you know it to be foo';
    }
    ```

    [更多信息](https://stackoverflow.com/questions/7365172/semicolon-before-self-invoking-function/7365214#7365214).

**[⬆ 返回目录](#table-of-contents)**

## <a id="type-casting--coercion">类型转换和强制类型转换</a>

  <a name="coercion--explicit"></a><a name="21.1"></a>
  - [22.1](#coercion--explicit) 在语句开始前进行类型转换。

  <a name="coercion--strings"></a><a name="21.2"></a>
  - [22.2](#coercion--strings)  字符类型: eslint: [`no-new-wrappers`](https://eslint.org/docs/rules/no-new-wrappers)

    ```javascript
    // => this.reviewScore = 9;

    // bad
    const totalScore = new String(this.reviewScore); // typeof totalScore is "object" not "string"

    // bad
    const totalScore = this.reviewScore + ''; // invokes this.reviewScore.valueOf()

    // bad
    const totalScore = this.reviewScore.toString(); // isn’t guaranteed to return a string

    // good
    const totalScore = String(this.reviewScore);
    ```

  <a name="coercion--numbers"></a><a name="21.3"></a>
  - [22.3](#coercion--numbers) 数字类型:使用 `Number` 进行类型铸造和 `parseInt` 总是通过一个基数来解析一个字符串。 eslint: [`radix`](https://eslint.org/docs/rules/radix) [`no-new-wrappers`](https://eslint.org/docs/rules/no-new-wrappers)

    ```javascript
    const inputValue = '4';

    // bad
    const val = new Number(inputValue);

    // bad
    const val = +inputValue;

    // bad
    const val = inputValue >> 0;

    // bad
    const val = parseInt(inputValue);

    // good
    const val = Number(inputValue);

    // good
    const val = parseInt(inputValue, 10);
    ```

  <a name="coercion--comment-deviations"></a><a name="21.4"></a>
  - [22.4](#coercion--comment-deviations) 如果出于某种原因,你正在做一些疯狂的事情,而 `parseInt` 是你的瓶颈,并且出于 [性能问题](https://jsperf.com/coercion-vs-casting/3) 需要使用位运算, 请写下注释,说明为什么这样做和你做了什么。

    ```javascript
    // good
    /**
     * parseInt 使我的代码变慢。
     * 位运算将一个字符串转换成数字更快。
     */
    const val = inputValue >> 0;
    ```

  <a name="coercion--bitwise"></a><a name="21.5"></a>
  - [22.5](#coercion--bitwise) **注意:** 当你使用位运算的时候要小心。 数字总是被以 [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。

    ```javascript
    2147483647 >> 0; // => 2147483647
    2147483648 >> 0; // => -2147483648
    2147483649 >> 0; // => -2147483647
    ```

  <a name="coercion--booleans"></a><a name="21.6"></a>
  - [22.6](#coercion--booleans) 布尔类型: eslint: [`no-new-wrappers`](https://eslint.org/docs/rules/no-new-wrappers)

    ```javascript
    const age = 0;

    // bad
    const hasAge = new Boolean(age);

    // good
    const hasAge = Boolean(age);

    // best
    const hasAge = !!age;
    ```

**[⬆ 返回目录](#table-of-contents)**

## <a id="naming-conventions">命名规范</a>

  <a name="naming--descriptive"></a><a name="22.1"></a>
  - [23.1](#naming--descriptive) 避免单字母的名字。用你的命名来描述功能。 eslint: [`id-length`](https://eslint.org/docs/rules/id-length)

    ```javascript
    // bad
    function q() {
      // ...
    }

    // good
    function query() {
      // ...
    }
    ```

  <a name="naming--camelCase"></a><a name="22.2"></a>
  - [23.2](#naming--camelCase) 在命名对象、函数和实例时使用驼峰命名法(camelCase)。 eslint: [`camelcase`](https://eslint.org/docs/rules/camelcase.html)

    ```javascript
    // bad
    const OBJEcttsssss = {};
    const this_is_my_object = {};
    function c() {}

    // good
    const thisIsMyObject = {};
    function thisIsMyFunction() {}
    ```

  <a name="naming--PascalCase"></a><a name="22.3"></a>
  - [23.3](#naming--PascalCase) 只有在命名构造器或者类的时候才用帕斯卡拼命名法(PascalCase)。 eslint: [`new-cap`](https://eslint.org/docs/rules/new-cap.html)

    ```javascript
    // bad
    function user(options) {
      this.name = options.name;
    }

    const bad = new user({
      name: 'nope',
    });

    // good
    class User {
      constructor(options) {
        this.name = options.name;
      }
    }

    const good = new User({
      name: 'yup',
    });
    ```

  <a name="naming--leading-underscore"></a><a name="22.4"></a>
  - [23.4](#naming--leading-underscore) 不要使用前置或者后置下划线。 eslint: [`no-underscore-dangle`](https://eslint.org/docs/rules/no-underscore-dangle.html)

    > 为什么? JavaScript 在属性和方法方面没有隐私设置。 虽然前置的下划线是一种常见的惯例,意思是 “private” ,事实上,这些属性时公开的,因此,它们也是你公共 API 的一部分。 这种约定可能导致开发人员错误的认为更改不会被视为中断,或者不需要测试。建议:如果你想要什么东西是 “private” , 那就一定不能有明显的表现。

    ```javascript
    // bad
    this.__firstName__ = 'Panda';
    this.firstName_ = 'Panda';
    this._firstName = 'Panda';

    // good
    this.firstName = 'Panda';

    // 好,在 WeakMapx 可用的环境中
    // see https://kangax.github.io/compat-table/es6/#test-WeakMap
    const firstNames = new WeakMap();
    firstNames.set(this, 'Panda');
    ```

  <a name="naming--self-this"></a><a name="22.5"></a>
  - [23.5](#naming--self-this) 不要保存 `this` 的引用。 使用箭头函数或者 [函数#bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind)。

    ```javascript
    // bad
    function foo() {
      const self = this;
      return function () {
        console.log(self);
      };
    }

    // bad
    function foo() {
      const that = this;
      return function () {
        console.log(that);
      };
    }

    // good
    function foo() {
      return () => {
        console.log(this);
      };
    }
    ```

  <a name="naming--filename-matches-export"></a><a name="22.6"></a>
  - [23.6](#naming--filename-matches-export) 文件名应该和默认导出的名称完全匹配。

    ```javascript
    // file 1 contents
    class CheckBox {
      // ...
    }
    export default CheckBox;

    // file 2 contents
    export default function fortyTwo() { return 42; }

    // file 3 contents
    export default function insideDirectory() {}

    // in some other file
    // bad
    import CheckBox from './checkBox'; // PascalCase import/export, camelCase filename
    import FortyTwo from './FortyTwo'; // PascalCase import/filename, camelCase export
    import InsideDirectory from './InsideDirectory'; // PascalCase import/filename, camelCase export

    // bad
    import CheckBox from './check_box'; // PascalCase import/export, snake_case filename
    import forty_two from './forty_two'; // snake_case import/filename, camelCase export
    import inside_directory from './inside_directory'; // snake_case import, camelCase export
    import index from './inside_directory/index'; // requiring the index file explicitly
    import insideDirectory from './insideDirectory/index'; // requiring the index file explicitly

    // good
    import CheckBox from './CheckBox'; // PascalCase export/import/filename
    import fortyTwo from './fortyTwo'; // camelCase export/import/filename
    import insideDirectory from './insideDirectory'; // camelCase export/import/directory name/implicit "index"
    // ^ supports both insideDirectory.js and insideDirectory/index.js
    ```

  <a name="naming--camelCase-default-export"></a><a name="22.7"></a>
  - [23.7](#naming--camelCase-default-export) 当你导出默认函数时使用驼峰命名法。 你的文件名应该和方法名相同。

    ```javascript
    function makeStyleGuide() {
      // ...
    }

    export default makeStyleGuide;
    ```

  <a name="naming--PascalCase-singleton"></a><a name="22.8"></a>
  - [23.8](#naming--PascalCase-singleton) 当你导出一个构造器 / 类 / 单例 / 函数库 / 暴露的对象时应该使用帕斯卡命名法。

    ```javascript
    const AirbnbStyleGuide = {
      es6: {
      },
    };

    export default AirbnbStyleGuide;
    ```

  <a name="naming--Acronyms-and-Initialisms"></a>
  - [23.9](#naming--Acronyms-and-Initialisms) 缩略词和缩写都必须是全部大写或者全部小写。

    > 为什么? 名字是为了可读性,不是为了满足计算机算法。

    ```javascript
    // bad
    import SmsContainer from './containers/SmsContainer';

    // bad
    const HttpRequests = [
      // ...
    ];

    // good
    import SMSContainer from './containers/SMSContainer';

    // good
    const HTTPRequests = [
      // ...
    ];

    // also good
    const httpRequests = [
      // ...
    ];

    // best
    import TextMessageContainer from './containers/TextMessageContainer';

    // best
    const requests = [
      // ...
    ];
    ```

  <a name="naming--uppercase"></a>
  - [23.10](#naming--uppercase) 你可以大写一个常量,如果它:(1)被导出,(2)使用 `const` 定义(不能被重新赋值),(3)程序员可以信任它(以及其嵌套的属性)是不变的。

    > 为什么? 这是一个可以帮助程序员确定变量是否会发生变化的辅助工具。UPPERCASE_VARIABLES 可以让程序员知道他们可以相信变量(及其属性)不会改变。
    - 是否是对所有的 `const` 定义的变量? - 这个是没有必要的,不应该在文件中使用大写。但是,它应该用于导出常量。
    - 导出对象呢? - 在顶级导出属性 (e.g. `EXPORTED_OBJECT.key`) 并且保持所有嵌套属性不变。

    ```javascript
    // bad
    const PRIVATE_VARIABLE = 'should not be unnecessarily uppercased within a file';

    // bad
    export const THING_TO_BE_CHANGED = 'should obviously not be uppercased';

    // bad
    export let REASSIGNABLE_VARIABLE = 'do not use let with uppercase variables';

    // ---

    // 允许,但是不提供语义值
    export const apiKey = 'SOMEKEY';

    // 多数情况下,很好
    export const API_KEY = 'SOMEKEY';

    // ---

    // bad - 不必要大写 key 没有增加语义值
    export const MAPPING = {
      KEY: 'value'
    };

    // good
    export const MAPPING = {
      key: 'value'
    };
    ```

**[⬆ 返回目录](#table-of-contents)**

## <a id="accessors">存取器</a>

  <a name="accessors--not-required"></a><a name="23.1"></a>
  - [24.1](#accessors--not-required) 对于属性的的存取函数不是必须的。

  <a name="accessors--no-getters-setters"></a><a name="23.2"></a>
  - [24.2](#accessors--no-getters-setters) 不要使用 JavaScript 的 getters/setters 方法,因为它们会导致意外的副作用,并且更加难以测试、维护和推敲。 相应的,如果你需要存取函数的时候使用 `getVal()` 和 `setVal('hello')`。

    ```javascript
    // bad
    class Dragon {
      get age() {
        // ...
      }

      set age(value) {
        // ...
      }
    }

    // good
    class Dragon {
      getAge() {
        // ...
      }

      setAge(value) {
        // ...
      }
    }
    ```

  <a name="accessors--boolean-prefix"></a><a name="23.3"></a>
  - [24.3](#accessors--boolean-prefix) 如果属性/方法是一个 `boolean` 值,使用 `isVal()` 或者 `hasVal()`。

    ```javascript
    // bad
    if (!dragon.age()) {
      return false;
    }

    // good
    if (!dragon.hasAge()) {
      return false;
    }
    ```

  <a name="accessors--consistent"></a><a name="23.4"></a>
  - [24.4](#accessors--consistent) 可以创建 `get()` 和 `set()` 方法,但是要保证一致性。

    ```javascript
    class Jedi {
      constructor(options = {}) {
        const lightsaber = options.lightsaber || 'blue';
        this.set('lightsaber', lightsaber);
      }

      set(key, val) {
        this[key] = val;
      }

      get(key) {
        return this[key];
      }
    }
    ```

**[⬆ 返回目录](#table-of-contents)**

## <a id="events">事件</a>

  <a name="events--hash"></a><a name="24.1"></a>
  - [25.1](#events--hash) 当给事件(无论是 DOM 事件还是更加私有的事件)附加数据时,传入一个对象(通畅也叫做 “hash” ) 而不是原始值。 这样可以让后边的贡献者向事件数据添加更多的数据,而不用找出更新事件的每个处理器。 例如,不好的写法:

    ```javascript
    // bad
    $(this).trigger('listingUpdated', listing.id);

    // ...

    $(this).on('listingUpdated', (e, listingID) => {
      // do something with listingID
    });
    ```

    更好的写法:

    ```javascript
    // good
    $(this).trigger('listingUpdated', { listingID: listing.id });

    // ...

    $(this).on('listingUpdated', (e, data) => {
      // do something with data.listingID
    });
    ```

  **[⬆ 返回目录](#table-of-contents)**

## jQuery

  <a name="jquery--dollar-prefix"></a><a name="25.1"></a>
  - [26.1](#jquery--dollar-prefix) 对于 jQuery 对象的变量使用 `$` 作为前缀。

    ```javascript
    // bad
    const sidebar = $('.sidebar');

    // good
    const $sidebar = $('.sidebar');

    // good
    const $sidebarBtn = $('.sidebar-btn');
    ```

  <a name="jquery--cache"></a><a name="25.2"></a>
  - [26.2](#jquery--cache) 缓存 jQuery 查询。

    ```javascript
    // bad
    function setSidebar() {
      $('.sidebar').hide();

      // ...

      $('.sidebar').css({
        'background-color': 'pink',
      });
    }

    // good
    function setSidebar() {
      const $sidebar = $('.sidebar');
      $sidebar.hide();

      // ...

      $sidebar.css({
        'background-color': 'pink',
      });
    }
    ```

  <a name="jquery--queries"></a><a name="25.3"></a>
  - [26.3](#jquery--queries) 对于 DOM 查询使用层叠 `$('.sidebar ul')` 或 父元素 > 子元素 `$('.sidebar > ul')` 的格式。 [jsPerf](http://jsperf.com/jquery-find-vs-context-sel/16)

  <a name="jquery--find"></a><a name="25.4"></a>
  - [26.4](#jquery--find) 对于有作用域的 jQuery 对象查询使用 `find` 。

    ```javascript
    // bad
    $('ul', '.sidebar').hide();

    // bad
    $('.sidebar').find('ul').hide();

    // good
    $('.sidebar ul').hide();

    // good
    $('.sidebar > ul').hide();

    // good
    $sidebar.find('ul').hide();
    ```

**[⬆ 返回目录](#table-of-contents)**

## <a id="ecmascript-5-compatibility">ECMAScript 5 兼容性</a>

  <a name="es5-compat--kangax"></a><a name="26.1"></a>
  - [27.1](#es5-compat--kangax) 参考 [Kangax](https://twitter.com/kangax/)的 ES5 [兼容性表格](https://kangax.github.io/es5-compat-table/)。

**[⬆ 返回目录](#table-of-contents)**

<a name="ecmascript-6-styles"></a>
## ECMAScript 6+ (ES 2015+) Styles

  <a name="es6-styles"></a><a name="27.1"></a>
  - [28.1](#es6-styles) 这是一个链接到各种 ES6+ 特性的集合。

1. [箭头函数](#arrow-functions)
1. [类](#classes--constructors)
1. [对象简写](#es6-object-shorthand)
1. [对象简洁](#es6-object-concise)
1. [对象计算属性](#es6-computed-properties)
1. [字符串模板](#es6-template-literals)
1. [解构](#destructuring)
1. [默认参数](#es6-default-parameters)
1. [Rest](#es6-rest)
1. [数组展开](#es6-array-spreads)
1. [Let 和 Const](#references)
1. [求幂运算符](#es2016-properties--exponentiation-operator)
1. [迭代器和发生器](#iterators-and-generators)
1. [模块](#modules)

  <a name="tc39-proposals"></a>
  - [28.2](#tc39-proposals) 不要使用尚未达到第3阶段的 [TC39 建议](https://github.com/tc39/proposals)。

    > 为什么? [它们没有最终确定](https://tc39.github.io/process-document/), 并且它们可能会被改变或完全撤回。我们希望使用JavaScript,而建议还不是JavaScript。

**[⬆ 返回目录](#table-of-contents)**

## <a id="standard-library">标准库</a>

  [标准库](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects)
  包含功能已损坏的实用工具,但因为遗留原因而保留。

  <a name="standard-library--isnan"></a>
  - [29.1](#standard-library--isnan) 使用 `Number.isNaN` 代替全局的 `isNaN`.
    eslint: [`no-restricted-globals`](https://eslint.org/docs/rules/no-restricted-globals)

    > 为什么? 全局的 `isNaN` 强制非数字转化为数字,对任何强制转化为 NaN 的东西都返回 true。

    > 如果需要这种行为,请明确说明。

    ```javascript
    // bad
    isNaN('1.2'); // false
    isNaN('1.2.3'); // true

    // good
    Number.isNaN('1.2.3'); // false
    Number.isNaN(Number('1.2.3')); // true
    ```

  <a name="standard-library--isfinite"></a>
  - [29.2](#standard-library--isfinite) 使用 `Number.isFinite` 代替全局的 `isFinite`.
    eslint: [`no-restricted-globals`](https://eslint.org/docs/rules/no-restricted-globals)

    > 为什么? 全局的 `isFinite` 强制非数字转化为数字,对任何强制转化为有限数字的东西都返回 true。

    > 如果需要这种行为,请明确说明。

    ```javascript
    // bad
    isFinite('2e3'); // true

    // good
    Number.isFinite('2e3'); // false
    Number.isFinite(parseInt('2e3', 10)); // true
    ```

**[⬆ 返回目录](#table-of-contents)**

## Testing

  <a name="testing--yup"></a><a name="28.1"></a>
  - [30.1](#testing--yup) **是的.**

    ```javascript
    function foo() {
      return true;
    }
    ```

  <a name="testing--for-real"></a><a name="28.2"></a>
  - [30.2](#testing--for-real) **没有,但是认真**:
    - 无论你使用那种测试框架,都应该编写测试!
    - 努力写出许多小的纯函数,并尽量减少发生错误的地方。
    - 对于静态方法和 mock 要小心----它们会使你的测试更加脆弱。
    - 我们主要在 Airbnb 上使用 [`mocha`](https://www.npmjs.com/package/mocha) 和 [`jest`](https://www.npmjs.com/package/jest) 。 [`tape`](https://www.npmjs.com/package/tape) 也会用在一些小的独立模块上。
    - 100%的测试覆盖率是一个很好的目标,即使它并不总是可行的。
    - 无论何时修复bug,都要编写一个回归测试。在没有回归测试的情况下修复的bug在将来几乎肯定会再次崩溃。

**[⬆ 返回目录](#table-of-contents)**

## <a id="performance">性能</a>

  - [On Layout & Web Performance](https://www.kellegous.com/j/2013/01/26/layout-performance/)
  - [String vs Array Concat](https://jsperf.com/string-vs-array-concat/2)
  - [Try/Catch Cost In a Loop](https://jsperf.com/try-catch-in-loop-cost)
  - [Bang Function](https://jsperf.com/bang-function)
  - [jQuery Find vs Context, Selector](https://jsperf.com/jquery-find-vs-context-sel/13)
  - [innerHTML vs textContent for script text](https://jsperf.com/innerhtml-vs-textcontent-for-script-text)
  - [Long String Concatenation](https://jsperf.com/ya-string-concat)
  - [Are Javascript functions like `map()`, `reduce()`, and `filter()` optimized for traversing arrays?](https://www.quora.com/JavaScript-programming-language-Are-Javascript-functions-like-map-reduce-and-filter-already-optimized-for-traversing-array/answer/Quildreen-Motta)
  - Loading...

**[⬆ 返回目录](#table-of-contents)**

## <a id="resources">资源</a>

**学习 ES6+**

  - [Latest ECMA spec](https://tc39.github.io/ecma262/)
  - [ExploringJS](http://exploringjs.com/)
  - [ES6 Compatibility Table](https://kangax.github.io/compat-table/es6/)
  - [Comprehensive Overview of ES6 Features](http://es6-features.org/)

**读这个**

  - [Standard ECMA-262](http://www.ecma-international.org/ecma-262/6.0/index.html)

**工具**

  - Code Style Linters
    - [ESlint](https://eslint.org/) - [Airbnb Style .eslintrc](https://github.com/airbnb/javascript/blob/master/linters/.eslintrc)
    - [JSHint](http://jshint.com/) - [Airbnb Style .jshintrc](https://github.com/airbnb/javascript/blob/master/linters/.jshintrc)
  - Neutrino preset - [neutrino-preset-airbnb-base](https://neutrino.js.org/presets/neutrino-preset-airbnb-base/)

**其他编码规范**

  - [Google JavaScript Style Guide](https://google.github.io/styleguide/javascriptguide.xml)
  - [jQuery Core Style Guidelines](https://contribute.jquery.org/style-guide/js/)
  - [Principles of Writing Consistent, Idiomatic JavaScript](https://github.com/rwaldron/idiomatic.js)
  - [StandardJS](https://standardjs.com)

**其他风格**

  - [Naming this in nested functions](https://gist.github.com/cjohansen/4135065) - Christian Johansen
  - [Conditional Callbacks](https://github.com/airbnb/javascript/issues/52) - Ross Allen
  - [Popular JavaScript Coding Conventions on GitHub](http://sideeffect.kr/popularconvention/#javascript) - JeongHoon Byun
  - [Multiple var statements in JavaScript, not superfluous](http://benalman.com/news/2012/05/multiple-var-statements-javascript/) - Ben Alman

**进一步阅读**

  - [Understanding JavaScript Closures](https://javascriptweblog.wordpress.com/2010/10/25/understanding-javascript-closures/) - Angus Croll
  - [Basic JavaScript for the impatient programmer](http://www.2ality.com/2013/06/basic-javascript.html) - Dr. Axel Rauschmayer
  - [You Might Not Need jQuery](http://youmightnotneedjquery.com/) - Zack Bloom & Adam Schwartz
  - [ES6 Features](https://github.com/lukehoban/es6features) - Luke Hoban
  - [Frontend Guidelines](https://github.com/bendc/frontend-guidelines) - Benjamin De Cock

**书籍**

  - [JavaScript: The Good Parts](https://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742) - Douglas Crockford
  - [JavaScript Patterns](https://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752) - Stoyan Stefanov
  - [Pro JavaScript Design Patterns](https://www.amazon.com/JavaScript-Design-Patterns-Recipes-Problem-Solution/dp/159059908X)  - Ross Harmes and Dustin Diaz
  - [High Performance Web Sites: Essential Knowledge for Front-End Engineers](https://www.amazon.com/High-Performance-Web-Sites-Essential/dp/0596529309) - Steve Souders
  - [Maintainable JavaScript](https://www.amazon.com/Maintainable-JavaScript-Nicholas-C-Zakas/dp/1449327680) - Nicholas C. Zakas
  - [JavaScript Web Applications](https://www.amazon.com/JavaScript-Web-Applications-Alex-MacCaw/dp/144930351X) - Alex MacCaw
  - [Pro JavaScript Techniques](https://www.amazon.com/Pro-JavaScript-Techniques-John-Resig/dp/1590597273) - John Resig
  - [Smashing Node.js: JavaScript Everywhere](https://www.amazon.com/Smashing-Node-js-JavaScript-Everywhere-Magazine/dp/1119962595) - Guillermo Rauch
  - [Secrets of the JavaScript Ninja](https://www.amazon.com/Secrets-JavaScript-Ninja-John-Resig/dp/193398869X) - John Resig and Bear Bibeault
  - [Human JavaScript](http://humanjavascript.com/) - Henrik Joreteg
  - [Superhero.js](http://superherojs.com/) - Kim Joar Bekkelund, Mads Mobæk, & Olav Bjorkoy
  - [JSBooks](http://jsbooks.revolunet.com/) - Julien Bouquillon
  - [Third Party JavaScript](https://www.manning.com/books/third-party-javascript) - Ben Vinegar and Anton Kovalyov
  - [Effective JavaScript: 68 Specific Ways to Harness the Power of JavaScript](http://amzn.com/0321812182) - David Herman
  - [Eloquent JavaScript](http://eloquentjavascript.net/) - Marijn Haverbeke
  - [You Don’t Know JS: ES6 & Beyond](http://shop.oreilly.com/product/0636920033769.do) - Kyle Simpson

**博客**

  - [JavaScript Weekly](http://javascriptweekly.com/)
  - [JavaScript, JavaScript...](https://javascriptweblog.wordpress.com/)
  - [Bocoup Weblog](https://bocoup.com/weblog)
  - [Adequately Good](http://www.adequatelygood.com/)
  - [NCZOnline](https://www.nczonline.net/)
  - [Perfection Kills](http://perfectionkills.com/)
  - [Ben Alman](http://benalman.com/)
  - [Dmitry Baranovskiy](http://dmitry.baranovskiy.com/)
  - [nettuts](http://code.tutsplus.com/?s=javascript)

**播客**

  - [JavaScript Air](https://javascriptair.com/)
  - [JavaScript Jabber](https://devchat.tv/js-jabber/)

**[⬆ 返回目录](#table-of-contents)**

## <a id="the-javascript-style-guide-guide">JavaScript风格指南的指南</a>

  - [Reference](https://github.com/airbnb/javascript/wiki/The-JavaScript-Style-Guide-Guide)

## <a id="license">许可证</a>

(The MIT License)

Copyright (c) 2012 康兵奎

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

**[⬆ 返回目录](#table-of-contents)**

## <a id="amendments">修正案</a>

我们鼓励您使用此指南并更改规则以适应您的团队的风格指南。下面,你可以列出一些对风格指南的修正。这允许您定期更新您的样式指南,而不必处理合并冲突。

# };


================================================
FILE: JAVASCRIPT/上传oss.md
================================================
### 阿里云oss上传步骤
1. 获取oss token 示例如下
*  
```javascript 1.8
GetOssToken (file) {
                let _this = this
                return this.$axios.post(process.env.VUE_APP_BASE_URL + "/oss/get-token", { context: this.context }).then(res =>{
                        _this.uploadFile(res.content, file)
                    },()=>{
                        _this.$vux.toast.show({
                            text: '网络异常,请稍后再试'
                        })
                    })
            }
```     
2. 根据token信息上传文件至oss       
```javascript 1.8
 uploadFile (tokenObj, file) {
                this.$emit('upload-begin', file)
                let uploadUrl = tokenObj['host'] || ''
                let formData = new FormData()
                const data = new Date().getTime() //根据时间自定义文件名称
                console.log(formData.url);
                formData.append('name', `${data}.png`)
                formData.append('key', this.context + '/' + `${data}.png`)
                formData.append('policy', tokenObj['policy'] || '')
                formData.append('OSSAccessKeyId', tokenObj['accessid'] || '')
                formData.append('success_action_status', '200')
                formData.append('callback', tokenObj['callback'] || '')
                formData.append('signature', tokenObj['signature'] || '')
                formData.append('file', this.dataURLtoFile( file, `${data}.png`))
                let xhr = new XMLHttpRequest()
                xhr.open('POST', uploadUrl)
                xhr.send(formData)
                xhr.onload = () => {
                    if (xhr.status === 200) {
                        this.$emit('resulturl',uploadUrl + '/'+ JSON.parse(xhr.response).object)
                    }
                }
            }
```            


================================================
FILE: JAVASCRIPT/下载文件流.md
================================================
/*导出表格*/
```javascript 1.8
      downHandler () {
          this.downloadBtn = true;
          let xhr = new XMLHttpRequest();
          xhr.open('POST', process.env.VUE_APP_API_URL + '/plan/export-plans', true);
          xhr.setRequestHeader('Content-type', 'application/json');
          xhr.setRequestHeader('Authorization', VueCookie.get(process.env.VUE_APP_LOGIN_TOKEN_NAME));
          xhr.responseType = 'blob';
          xhr.onload = function () {
              let blob = new Blob([xhr.response], {type: 'application/vnd.ms-excel'});
              if (window.navigator.msSaveOrOpenBlob) {
                  navigator.msSaveBlob(blob, '日程总表.xlsx')
              } else {
                  let link = document.createElement('a');
                  let evt = document.createEvent('HTMLEvents');
                  evt.initEvent('click', false, false);
                  link.href = URL.createObjectURL(blob);
                  link.download = '日程总表.xlsx';
                  link.style.display = 'none';
                  document.body.appendChild(link);
                  link.click();
                  window.URL.revokeObjectURL(link.href);
                  document.body.removeChild(link);
              }
          };
          xhr.send(JSON.stringify({
              examId:this.$route.params.id,
          }));
          xhr.onreadystatechange = () => {
              if (xhr.readyState === 4 && xhr.status === 200) {
                  this.downloadBtn = false
              }
          }
      }
 ```
##  JavaScript 之 Blob 对象类型
  Blob(Binary Large Object)术语最初来自数据库(oracle 中也有类似的栏位类型。),早期数据库因为要存储声音、图片、以及可执行程序等二进制数据对象所以给该类对象取名为Blob。 
       在Web领域,Blob被定义为包含只读数据的类文件对象。Blob中的数据不一定是js原生数据形式。常见的File接口就继承自Blob,并扩展它用于支持用户系统的本地文件。
### 构建一个Blob对象通常有三种方式:
1. blob对象的构造函数来构建。
```javascript 1.8
var blob = new Blob(array[optional], options[optional]);
```
2. 从已有的Blob对象调用slice接口切出一个新的Blob对象。
3. canvas API toBlob方法,把当前绘制信息转为一个Blob对象。
#### 构造函数,接受两个参数</strong><br>
* 第一个参数:为一个数据序列,可以是任意格式的值,例如,任意数量的字符串,Blobs 以及 ArrayBuffers。
* 第二个参数:用于指定将要放入Blob中的数据的类型(MIME)(后端可以通过枚举MimeType,获取对应类型:
```javascript 1.8
 <script>
    var blob = new Blob(["Hello World!"],{type:"text/plain"});
  </script>
 ``` 
#### Blob对象的基本属性:
* size :Blob对象包含的字节数。(只读)
* type : Blob对象包含的数据类型MIME,如果类型未知则返回空字符串。
#### Blob对象的基本方法: 
* 大文件分割 (slice() 方法),slice方法与数组的slice类似。
```javascript 1.8
Blob.slice([start, [end, [content-type]]])
```
slice() 方法接受三个参数,起始偏移量,结束偏移量,还有可选的 mime 类型。如果 mime 类型,没有设置,那么新的 Blob 对象的 mime 类型和父级一样。

当要上传大文件的时候,此方法非常有用,可以将大文件分割分段,然后各自上传,因为分割之后的 Blob 对象和原始的是独立存在的。

不过目前浏览器实现此方法还没有统一,火狐使用的是 mozSlice() ,Chrome 使用的是 webkitSlice() ,其他浏览器则正常的方式 slice() 
```javascript 1.8
// 兼容写法
function sliceBlob(blob, start, end, type) {
      type = type || blob.type;
      if (blob.mozSlice) {
          return blob.mozSlice(start, end, type);
      } else if (blob.webkitSlice) {
          return blob.webkitSlice(start, end type);
      } else {
          throw new Error("This doesn't work!");
      }
    }
```

================================================
FILE: JAVASCRIPT/修改url的某个参数值.md
================================================
## 修改url的某个参数值
```javascript 1.8
function replaceParamVal(paramName,replaceWith) {
    var oUrl = this.location.href.toString();
    var re=eval('/('+ paramName+'=)([^&]*)/gi');
    var nUrl = oUrl.replace(re,paramName+'='+replaceWith);
    this.location = nUrl;
  window.location.href=nUrl
}
```
* 使用
replaceParamVal("userId","333")

================================================
FILE: JAVASCRIPT/功能性js插件.md
================================================
## 功能性js
```javascript 1.8
import moment from 'moment'

function pluralize (time, label) {
    if (time === 1) {
        return time + label
    }
    return time + label + 's'
}

export function timeAgo (time) {
    const between = Date.now() / 1000 - Number(time)
    if (between < 3600) {
        return pluralize(~~(between / 60), ' minute')
    } else if (between < 86400) {
        return pluralize(~~(between / 3600), ' hour')
    } else {
        return pluralize(~~(between / 86400), ' day')
    }
}

export function parseTime (time, cFormat) {
    if (arguments.length === 0) {
        return null
    }

    if ((time + '').length === 10) {
        time = +time * 1000
    }

    const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
    let date
    if (typeof time === 'object') {
        date = time
    } else {
        date = new Date(parseInt(time))
    }
    const formatObj = {
        y: date.getFullYear(),
        m: date.getMonth() + 1,
        d: date.getDate(),
        h: date.getHours(),
        i: date.getMinutes(),
        s: date.getSeconds(),
        a: date.getDay()
    }
    const timeStr = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
        let value = formatObj[key]
        if (key === 'a') {
            return ['一', '二', '三', '四', '五', '六', '日'][value - 1]
        }
        if (result.length > 0 && value < 10) {
            value = '0' + value
        }
        return value || 0
    })
    return timeStr
}

export function formatTime (time, option) {
    time = +time * 1000
    const d = new Date(time)
    const now = Date.now()

    const diff = (now - d) / 1000

    if (diff < 30) {
        return '刚刚'
    } else if (diff < 3600) {
        // less 1 hour
        return Math.ceil(diff / 60) + '分钟前'
    } else if (diff < 3600 * 24) {
        return Math.ceil(diff / 3600) + '小时前'
    } else if (diff < 3600 * 24 * 2) {
        return '1天前'
    }
    if (option) {
        return parseTime(time, option)
    } else {
        return (
            d.getMonth() +
            1 +
            '月' +
            d.getDate() +
            '日' +
            d.getHours() +
            '时' +
            d.getMinutes() +
            '分'
        )
    }
}

/*  数字 格式化 */
export function nFormatter (num, digits) {
    const si = [
        {value: 1e18, symbol: 'E'},
        {value: 1e15, symbol: 'P'},
        {value: 1e12, symbol: 'T'},
        {value: 1e9, symbol: 'G'},
        {value: 1e6, symbol: 'M'},
        {value: 1e3, symbol: 'k'}
    ]
    for (let i = 0; i < si.length; i++) {
        if (num >= si[i].value) {
            return (
                (num / si[i].value + 0.1)
                    .toFixed(digits)
                    .replace(/\.0+$|(\.[0-9]*[1-9])0+$/, '$1') + si[i].symbol
            )
        }
    }
    return num.toString()
}

export function html2Text (val) {
    const div = document.createElement('div')
    div.innerHTML = val
    return div.textContent || div.innerText
}

export function toThousandslsFilter (num) {
    return (+num || 0)
        .toString()
        .replace(/^-?\d+/g, m => m.replace(/(?=(?!\b)(\d{3})+$)/g, ','))
}

/**
 * 格式化文件大小
 * @param value
 * @returns {*}
 */
export function renderSize (value) {
    if (value === null || value === '') {
        return '0B'
    }
    let unitArr = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
    let srcsize = parseFloat(value)
    let index = Math.floor(Math.log(srcsize) / Math.log(1024))
    let size = srcsize / Math.pow(1024, index)
    size = size.toFixed(0) // 保留的小数位数
    return size + unitArr[index]
}

/**
 * 时间戳转时分
 * @param {number} Timestamps 时间戳
 * @returns {string} 23:59(分)
 */
export function timestampToHm (Timestamps) {
    return moment(Timestamps * 1000).format('HH:mm')
}

/**
 * 时分转时间戳
 */
export function timeToseconds (time) {
        var s = ''
        var hour = time.split(':')[0]
        var min = time.split(':')[1]
        s = Number(hour * 3600) + Number(min * 60)
        return s
}

/**
 * 时间戳转时分秒
 * @param {number} Timestamps 时间戳
 * @returns {string} 23:59:59(秒)
 */
export function timestampToHms (Timestamps) {
    return moment(Timestamps * 1000).format('HH:mm:ss')
}

/**
 * 时间戳转日期
 * @param Timestamps 时间戳
 * @returns {string} 2018-08-28 (日)
 */
export function timestampToYMD (Timestamps) {
    if (Timestamps) {
        return moment(Timestamps * 1000).format('YYYY-MM-DD')
    } else {
        return '--'
    }
}

/**
 * 时间戳转短时间
 * @param Timestamps 时间戳
 * @returns {string} 2018-08-28 23:59(分)
 */
export function timestampToYMDHm (Timestamps) {
    if (Timestamps) {
        return moment(Timestamps * 1000).format('YYYY-MM-DD HH:mm')
    } else {
        return '--'
    }
}

/**
 * 时间戳转长时间
 * @param Timestamps 时间戳
 * @returns {string} 2018-08-28 23:59:59(秒)
 */
export function timestampToYMDHms (Timestamps) {
    if (Timestamps) {
        return moment(Timestamps * 1000).format('YYYY-MM-DD HH:mm:ss')
    } else {
        return '--'
    }
}

/**
 * 时间转时间戳
 * @param {number} time 时间
 * @returns {string}  1534567891(秒)
 */
export function timeToTimestamp (time) {
    return moment(time, 'YYYY-MM-DD HH:mm:ss').valueOf() / 1000
}

/**
 * 时间转时分
 * @param {number} time 时间
 * @returns {string}  23:59(分)
 */
export function timeToHm (time) {
    let Timestamps = moment(time, 'YYYY-MM-DD HH:mm').valueOf()
    return moment(Timestamps).format('HH:mm')
}

/**
 * 时间转时分秒
 * @param {number} time 时间
 * @returns {string}  23:59:59(秒)
 */
export function timeToHms (time) {
    let Timestamps = moment(time, 'YYYY-MM-DD HH:mm').valueOf()
    return moment(Timestamps).format('HH:mm:ss')
}

/**
 * 时间对象转时分秒
 * @param {number} time 时间
 * @return {string} 2018-08-08 23:59:59(秒)
 */
export function timeToYMDms (time) {
    let Timestamps = moment(time, 'YYYY-MM-DD HH:mm:ss').valueOf()
    return moment(Timestamps).format('YYYY-MM-DD HH:mm:ss')
}

/**
 * 时间对象转时分
 * @param {number} time 时间
 * @return {string} 2018-08-08 23:59(分)
 */
export function timeToYMDm (time) {
    let Timestamps = moment(time, 'YYYY-MM-DD HH:mm:ss').valueOf()
    return moment(Timestamps).format('YYYY-MM-DD HH:mm')
}

/**
 * 格式化性别
 * @param {number} sex 0女 1男
 * @return {string}
 */
export function sex (sex) {
    switch (parseInt(sex)) {
        case 0:
            return '女'
        case 1:
            return '男'
    }
}

/**
 * 格式化审批同意拒绝
 * @param {number} status 0同意 1拒绝
 * @return {string}
 */
export function approvalStatus (status) {
    switch (parseInt(status)) {
        case 0:
            return '同意申请'
        case 1:
            return '拒绝申请'
    }
}

/**
 * 处理耗时
 * @param {Number} 送审时间ms
 * @returns {String} X天X小时X分
 */
export function consumingTime (s) {
    s = s < 0 ? 1 : s
    let day = Math.floor(s / 86400)
    let hours = Math.floor((s - day * 86400) / 3600)
    let minutes = Math.floor((s - day * 86400 - hours * 3600) / 60)
    return (day ? day + '天' : '') + (hours ? hours + '小时' : '') + (minutes ? minutes + '分钟' : '<1分钟')
}

/**
 * 日期转s
 * @param {String} eg: "2018-09-18T16:00:00.000Z"
 * @returns {String} X秒
 */
export function getDateFn (s) {
    return s ? new Date(s).getTime() / 1000 + '' : ''
}

/**
 * 深度克隆
 * @param   {Object} Obj 原数据
 * @returns {Object} {*} 克隆数据
 */
export function clone (Obj) {
    let buf
    if (Obj instanceof Array) {
        buf = [] // 创建一个空的数组
        let i = Obj.length
        while (i--) {
            buf[i] = clone(Obj[i])
        }
        return buf
    } else if (Obj instanceof Object) {
        buf = {} // 创建一个空对象
        for (let k in Obj) {
            // 为这个对象添加新的属性
            buf[k] = clone(Obj[k])
        }
        return buf
    } else {
        return Obj
    }
}

/**
 * 生成随机字符串
 * @param len 需要生生字符串的长度 默认生成6位字符串
 * @param charSet 自定义字符 默认[a-zA-Z0-9],或者自定义字符串'adasdaq2r413123'
 * @returns {string}
 */
export function randomString (len, charSet) {
    charSet = charSet || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
    len = len || 6
    let randomString = ''
    for (let i = 0; i < len; i++) {
        let randomPoz = Math.floor(Math.random() * charSet.length)
        randomString += charSet.substring(randomPoz, randomPoz + 1)
    }
    return randomString
}
/**
 * 格式化数字转汉字
 */
export function numberToChinese (section) {
    let chnNumChar = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九']
    let chnUnitChar = ['', '十', '百', '千', '万']
    let strIns = ''
    let chnStr = ''
    let unitPos = 0
    let zero = true
    while (section > 0) {
        let v = section % 10
        if (v === 0) {
            if (!zero) {
                zero = true
                chnStr = chnNumChar[v] + chnStr
            }
        } else {
            zero = false
            strIns = chnNumChar[v]
            strIns += chnUnitChar[unitPos]
            chnStr = strIns + chnStr
        }
        unitPos++
        section = Math.floor(section / 10)
    }
    return chnStr
}

/**
 * 数组遍历拼接  删除最后一个拼接符
 */
export function arrayToString (arr) {
    var str = ''
    for (var i = 0; i < arr.length; i++) {
        str += arr[i].name + '、'
    }
    // 去掉最后一个逗号(如果不需要去掉,就不用写)
    if (str.length > 0) {
        str = str.substr(0, str.length - 1)
    }
    return str
}

/**
 * 数字格式化星期几
 * @param {number} status 0同意 1拒绝
 * @return {string}
 */
export function weekDay (num) {
    switch (parseInt(num)) {
        case 1:
            return '星期一'
        case 2:
            return '星期二'
        case 3:
            return '星期三'
        case 4:
            return '星期四'
        case 5:
            return '星期五'
        case 6:
            return '星期六'
        case 7:
            return '星期日'
    }
}

/**
 * 时间戳格式化星期几
 * @param {string} time 时间
 * @return {string}
 */
export function timeToweekDay (time) {
    let weekDay = moment(time).format('dddd')
    switch (weekDay) {
        case 'Monday':
            return '星期一'
        case 'Tuesday':
            return '星期二'
        case 'Wednesday':
            return '星期三'
        case 'Thursday':
            return '星期四'
        case 'Friday':
            return '星期五'
        case 'Saturday':
            return '星期六'
        case 'Sunday':
            return '星期日'
    }
}
```

================================================
FILE: JAVASCRIPT/基于vant上传组件oss/服务器.md
================================================
```javascript 1.8
<template>
    <div class="uploader-photo">
      <van-uploader v-model="uploadlist" multiple :disabled="disabled"  :after-read="fileSelected" :max-count="maxCount" :before-delete="delImgs" accept="image/*"/>
    </div>
</template>

<script>
    /**
     * Uploadphoto
     * @author liuliu 2020/4/7 11:10
     * 上传图片
     */
    import { Uploader } from 'vant';
    import { Toast } from 'vant';
    import dz from "@/assets/js/common";
    export default {
        name: 'Uploadphoto',
        props: {},
        components: {
            'van-uploader':Uploader
        },
        props: {
            // 限制上传数量
            maxCount:{
              type:Number,
              default:() => {
                  return 10
              }
            },
            // 是否禁用
            disabled:{
                type:Boolean,
                default: () => {
                    return false;
                }
            },
            context: {
                default: "onlone_class_h5",
            },
            //初始文件列表
            files: {
                default: () => {
                    return [];
                }
            },
            //上传个数限制
            maxCount: {
                default: 10
            },
            //单个文件大小限制 单位 M
            maxSize: {
                type:Number,
                default: 10
            },
            //限制图片大小 格式必须为{h:70,w:70}如果只限制宽或者高就只填宽或者高
            imgWH: {
                default: () => {
                    return {};
                }
            }
        },
        data() {
            return {
                fileList:[],
                uploadlist:[],
                isuploadoss:true,// 判断是否上传至oss
                imgUrlEndText:''
            }
        },
        created() {
        },
        mounted() {
            /*判断是否有限制图片*/
            dz.foreach(this.imgWH, (key, val) => {
                if (val != "") {
                    this.imgUrlEndText =
                        "?x-oss-process=image/resize,m_fixed,h_" +
                        this.imgWH.h +
                        ",w_" +
                        this.imgWH.w;
                }
            });
        },
        computed: {},
        filters: {},
        watch: {
            fileList(val) {
                let latestFiles = [];
                val.forEach(file => {
                    latestFiles.push({
                        name: file.name,
                        url: file.url,
                        type:file.type
                    });
                });
                this.$emit("getfiles", latestFiles);
            }
        },
        methods: {
            fileSelected(file) {
                let fileSize = file.file.size;
                if (fileSize > this.maxSize * 1024 * 1024) {
                    this.$toast("上传图片超过限制大小:10M");
                    Toast.fail(`上传图片超过限制大小:${this.maxSize}M`);
                    return false;
                }
                if (!this.isuploadoss) {
                    this.$emit('getfiles',this.uploadlist)
                } else {
                    file.status = 'uploading';
                    file.message = '上传中...';
                    let data = file.file
                    data.id = `${dz.getRandomString()}_${file.file.name}_${Date.now()}`;
                    this.getFileNameType(data)
                    this.uploadFile(data)
                }
            },
            // 删除照片事件
            delImgs(file, name){
                this.uploadlist.splice(name.index,1)
                if (this.isuploadoss) {
                    this.fileList.splice(name.index,1)
                } else {
                    this.$emit('getfiles',this.uploadlist)
                }
            },
            //上传文件
            uploadFile(file) {
                let _this = this;
                //首先从服务器获取token
                return this.$SHNet.postJson(
                    process.env.VUE_APP_BASE_URL + '/oss/get-token',
                    {context: this.context},
                    res => {
                        _this.afterGetToken(res.content, file)
                    }
                )
            },
            //得到上传token后, 直接上传到OSS
            afterGetToken(tokenObj, file) {
                this.upToast =Toast.loading({
                    message: '上传中,请稍等',
                    forbidClick: true,
                    duration:0,
                });
                let _this = this;
                let uploadUrl = tokenObj["host"] || "";
                let formData = new FormData();
                file.url =
                    uploadUrl +
                    "/" +
                    this.context +
                    "/" +
                    file.id +
                    "." +
                    file.fileExtension +
                    this.imgUrlEndText;
                formData.append("name", file.name);
                formData.append(
                    "key",
                    this.context + "/" + file.id + "." + file.fileExtension
                );
                formData.append("policy", tokenObj["policy"] || "");
                formData.append("OSSAccessKeyId", tokenObj["accessid"] || "");
                formData.append("success_action_status", "200");
                formData.append("callback", tokenObj["callback"] || "");
                formData.append("signature", tokenObj["signature"] || "");
                formData.append("file", file);
                let xhr = new XMLHttpRequest();
                xhr.onreadystatechange = function () {
                    if (xhr.readyState==4 && xhr.status==200){
                        // 赋值
                        _this.uploadlist[_this.uploadlist.length-1].status = ''
                        _this.uploadlist[_this.uploadlist.length-1].message = ''
                        _this.fileList.push(file)
                        _this.upToast.clear();
                    }else if (xhr.readyState==4 && xhr.status!=200){
                        _this.upToast.clear();
                        this.uploadlist.splice(this.uploadlist.length-1,1)
                        Toast.fail("上传失败,请重新上传");
                    }

                }
                xhr.open("POST", uploadUrl);
                let result = xhr.send(formData);
            },
            // 初始化时获得文件类型,展示不同的默认图标
            getFileNameType(file) {
                let extName;
                let idx = file.name.lastIndexOf(".");
                let status;
                if (idx != -1) {
                    extName = file.name.substr(idx + 1).toUpperCase();
                    extName = extName.toLowerCase();
                    if (
                        extName != "jpg" &&
                        extName != "png" &&
                        extName != "jpeg" &&
                        extName != "gif" &&
                        extName != "mp4" &&
                        extName != "avi" &&
                        extName != "rmvb" &&
                        extName != "mkv" &&
                        extName != "mov"
                    ) {
                        return "not";
                    }
                    if (
                        extName == "jpg" ||
                        extName == "png" ||
                        extName == "jpeg" ||
                        extName == "gif"
                    ) {
                        status = 1;
                    }
                    if (
                        extName == "mp4" ||
                        extName == "avi" ||
                        extName == "rmvb" ||
                        extName == "mkv" ||
                        extName == "mov"
                    ) {
                        status = 2;
                    }
                    file.show = status;
                    file.fileExtension = extName;
                }
            }
        }
    }
</script>

<style lang="less">
    .Uploadphoto {
    }
</style>

```
dz文件 (功能性插件)
```javascript 1.8
// import Vue from 'vue'
import moment from 'moment'
let dz = {
  /**
  * 生成随机字符串
  * @param len
  * @returns {string}
  */
  getRandomString: function (len) {
    let leng = len || 32
    var chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'
    var maxPos = chars.length
    var pwd = ''
    for (var i = 0; i < leng; i++) {
      pwd += chars.charAt(Math.floor(Math.random() * maxPos))
    }
    return pwd
  },
  /**
  * 时间戳转 xxxx-xx-xx
  * @param value 时间戳
  * @returns {string}
  */
  timestampToshortText (value) {
    return moment(value * 1000).format('YYYY-MM-DD')
  },
  /**
  * 时间戳转 xxxx-xx-xx xx:xx(分)
  * @param value 时间戳
  * @returns {string}
  */
  timestampToMText (value) {
    return moment(value * 1000).format('YYYY-MM-DD HH:mm')
  },
  /**
  * 时间戳转 xxxx-xx-xx xx:xx:xx(秒)
  * @param value 时间戳
  * @returns {string}
  */
  timestampToLongText (value) {
    return moment(value * 1000).format('YYYY-MM-DD HH:mm:ss')
  },
  /**
   * 时间转时间戳 (秒)
   * 格式化时间戳
   * @param {number} time 时间
   */
  timeToTimestamp (time) {
    return moment(time, 'YYYY-MM-DD HH:mm:ss').valueOf() / 1000
  },
  /**
   * 获取当前时间戳 (秒)
   * 格式化时间戳
   * @param {number} time 时间
   */
  timeToTimestamps () {
    return moment(Date.now()).format('X')
  },
  /**
   * 获取当前年月日 (秒)
   * 格式化时间戳
   * @param {number} time 时间
   */
  timeToDatetimes () {
    return moment(Date.now()).format('YYYY-MM-DD')
  },
  /**
   * 时间转日期 xxxx:xx:xx
   * 格式化时间 2018-08-28
   * @param {string} time 时间
   */
  timeToDateTime (time) {
    let Timestamps = moment(time, 'YYYY-MM-DD HH:mm:ss').valueOf()
    return moment(Timestamps).format('YYYY-MM-DD')
  },
  /**
   * 时间转日期 xxxx:xx:xx
   * 格式化时间 2018-08-28 12:12
   * @param {string} time 时间
   */
  timeToDateTimes (time) {
    let Timestamps = moment(time, 'YYYY-MM-DD HH:mm:ss').valueOf()
    return moment(Timestamps).format('YYYY-MM-DD HH:mm')
  },
  // 循环
  foreach (arr, func) {
    for (var i in arr) {
      if (func(arr[i], i) === false) {
        return false
      }
    }
    return true
  },
  /**
   * 获取秒时间戳
   * @param  {Date}   day 标准时间格式
   * @return {Number}     转换成秒的时间戳
   */
  getSencondStamp (day) {
    return parseInt(moment(day)['_d'].getTime() / 1000)
  },
  /**
   * 时间戳/常见时间格式 格式化为 XXXX年XX月XX日
   * @param  {Date} day 标准时间格式/时间戳
   * @return {String}     2018年06月01日
   */
  timestampToYearText (day) {
    return moment(day).format('YYYY' + '年' + 'MM' + '月' + 'DD' + '日')
  },
  /**
   * 浅克隆
   * @param  {Object} obj   克隆对象
   * @return {Object} copy  克隆结果
   */
  clone (obj) {
    let copy = null
    // Handle the 3 simple types, and null or undefined
    if (obj == null || typeof obj !== 'object') return obj

    // Handle Date
    if (obj instanceof Date) {
      copy = new Date()
      copy.setTime(obj.getTime())
      return copy
    }

    // Handle Array
    if (obj instanceof Array) {
      copy = []
      for (var i = 0; i < obj.length; ++i) {
        copy[i] = this.clone(obj[i])
      }
      return copy
    }

    // Handle Object
    if (obj instanceof Object) {
      copy = {}
      if (window.JSON) {
        copy = JSON.parse(JSON.stringify(obj))
      } else {
        for (let j in obj) {
          copy = typeof obj[j] === 'object' ? this.clone(obj[j]) : obj[j]
        }
      }

      return copy
    }

    throw new Error("Unable to copy obj! Its type isn't supported.")
  },
  /**
   * 是否为微信浏览器
   * navigator.wxuserAgent 匹配win phone
   * @return {Boolean} true是 false
   */
  isWexinAgent () {
    let agent = navigator.userAgent.toLowerCase()

    return (/micromessenger/.test(agent)) || typeof navigator.wxuserAgent !== 'undefined'
  },
  /**
   * IOS字体大小设置为65%
   */
  adaptIOS () {
    let isIOS = null
    let u = navigator.userAgent
    if (/AppleWebKit.*Mobile/i.test(navigator.userAgent) || (/MIDP|SymbianOS|NOKIA|SAMSUNG|LG|NEC|TCL|Alcatel|BIRD|DBTEL|Dopod|PHILIPS|HAIER|LENOVO|MOT-|Nokia|SonyEricsson|SIE-|Amoi|ZTE/.test(navigator.userAgent))) {
      if (window.location.href.indexOf('?mobile') < 0) {
        try {
          if (/iPhone|mac|iPod|iPad/i.test(navigator.userAgent)) {
            isIOS = true
          } else {
            isIOS = false
          }
        } catch (e) {
          console.log(e)
        }
      }
    } else if (u.indexOf('iPad') > -1) {
      isIOS = true
    } else {
      isIOS = false
    }
    if (isIOS) {
      document.getElementsByTagName('html')[0].style.fontSize = '65%'
    }
  }
}

export default dz

```


================================================
FILE: JAVASCRIPT/完美url跳转方式.md
================================================
## 完美url跳转方式
`window.open().location = “http://-----”`

================================================
FILE: JAVASCRIPT/常用js代码块.md
================================================
/**
* @name: 常用js代码块
* @author: LIULIU
* @date: 2020-08-10 14:43
* @description:常用js代码块
* @update: 2020-08-10 14:43
*/

#### 1. PC - js
- 返回指定范围的随机数(m-n之间)的公式
```javascript
Math.random()*(n-m)+m
```

- [return false](http://stackoverflow.com/questions/1357118/event-preventdefault-vs-return-false)
- [return false](http://www.75team.com/archives/201)
```javascript
// event.preventDefault()会阻挡预设要发生的事件.
// event.stopPropagation()会阻挡发生冒泡事件.
// 而return false则是前面两者的事情他都会做:
// 他会做event.preventDefault();
// 他会做event.stopPropagation();
// 停止callback function的执行并且立即return回来
```

- 复制文本到剪切板
```javascript
function copyToClipboard(data) {
    const _tempInput = document.createElement('input')
    _tempInput.value = data.value
    document.body.appendChild(_tempInput)
    _tempInput.select()
    document.execCommand('Copy')
    document.body.removeChild(_tempInput)
}
```

- 前端生成文件并下载
```javascript
function createAndDownloadFile(fileName, content) {
    const aTag = document.createElement('a');
    const blob = new Blob([content]);
    aTag.download = `${fileName}.json`;
    aTag.href = URL.createObjectURL(blob);
    aTag.click();
    URL.revokeObjectURL(blob);
}
```

- 高亮文本
```javascript
function highlight(text, words, tag='span') {
    let i, len = words.length, re;
    for (i = 0; i < len; i++) {
	re = new RegExp(words[i], 'g');
	if (re.test(text)) {
	    text = text.replace(re, '<'+ tag +' class="highlight">$&</'+ tag +'>');
	}
    }
    return text;
}

```

- 限制文本字数
```javascript
function excerpt(str, nwords) {
    let words = str.split(' ');
    words.splice(nwords, words.length-1);
    return words.join(' ') +
	(words.length !== str.split(' ').length ? '…' : '');
}
```

- 简单创建动态菜单下拉列表
```javascript
function createMenu(items, tags=['ul', 'li']) {
    const parent = tags[0];
    const child = tags[1];
    let item, value = '';
    for (let i = 0, l = items.length; i < l; i++) {
	item = items[i];
	if (/:/.test(item)) {
	    item = items[i].split(':')[0];
	    value = items[i].split(':')[1];
	}
	items[i] = '<'+ child +' '+
	    (value && 'value="'+value+'"') +'>'+ 
	    item +'</'+ child +'>';
    }
    return '<'+ parent +'>'+ items.join('') +'</'+ parent +'>';
}
```

- 防止被Iframe嵌套
```javascript
if(top != self){
    location.href = ”about:blank”;
}
```

- 两种图片lazy加载的方式
第一个By JS中级交流群 成都-猎巫 第二个By 上海-zenki 
```javascript
// @description 准备为图片预加载使用的插件
// 使用的图片容器css类名为lazy-load-wrap
// 图片真实地址为data-lazy-src
// 当lazy-load-wrap容器进入视口,则开始替换容器内所有需要延迟加载的图片路径,并更改容器的加载状态
//第一种方法
$.fn.compassLazyLoad=function(){
	var _HEIGHT=window.innerHeight,
	_lazyLoadWrap=$('.lazy-load-wrap');

	var methods={
		setOffsetTop:function(){
			$.each(_lazyLoadWrap,function(i,n){
				$(n).attr({
					'top':n.offsetTop-_HEIGHT,
					'status':'wait'
				});
			})
		},
		isShow:function(){
			var _scrollTop=$(window).scrollTop;
			//利用image容器判断是否进入视口,而非image本身
			$.each(_lazyLoadWrap,function(){
				var _that=$(this);
				if (_that.attr('status')==='done') {
					return;
				};
				if (_that.attr('top')<=_scrollTop) {
					_that.find('img[data-lazy-src]').each(function(i,n){
						n.src=$(n).data('lazy-src');
					});
					_that.attr('status','done');
				};
			})
		},
		scroll:function(){
			$(window).on('scroll',function(){
				methods.isShow();
			});
		},
		init:function(){
			methods.setOffsetTop();
			methods.isShow();
			methods.scroll();
		}
	};
	methods.init();

}


//第二种方法

var exist=(function($){
	var timer=null,
	temp=[].slice.call($('.container'));
	ret={};

	for(var i=0,len=temp.length-1;i<=len;i++){
		ret[i]=temp[i];
	}
	var isExist=function(winTop,winEnd){
		for(var i in ret){
			console.log(ret);
			var item=ret[i],
			eleTop=item.offsetTop,
			eleEnd=eleTop+item.offsetHeight;

			if((eleTop>winTop&&eleTop<=winEnd)||(eleEnd>winTop&&eleEnd<=winEnd)){
				$(item).css('background','none');
				new Tab($(item).attr('id'),data).init;
				delete ret[i];
			}
		}
	}
	return {
		timer:timer;
		isExist:isExist;
	};
})($);



//第三种方法
Zepto(function ($) {
    var swiper = new Swiper('.swiper-container', {
        pagination: '.swiper-pagination',
        paginationClickable: true,
        autoplay: 3000,
        loop: true,
        autoplayDisableOnInteraction: false
    });
    (function lazyLoad() {
        var imgs = $(".lazyLoad");
        var src = '';
        $.each(imgs, function (index, item) {
            src = $(item).attr('data-src');
            $(item).attr('src', src);
        });
    })();
});
$(function () {
    var lazyLoadTimerId = null;
    /// 智能加载事件
    $(window).bind("scroll", function () {
        clearTimeout(lazyLoadTimerId);
        lazyLoadTimerId = setTimeout(function () {
            // 延迟加载所有图片
            var isHttp = (location.protocol === "http:");
            $("#ym_images img").each(function () {
                var self = $(this);
                if (self.filter(":above-the-fold").length > 0) {
                    var originUrl = self.attr("data-original");
                    self.attr("src", originUrl);
                }
            });
        }, 500);
    });
});

```

- 某年某月的1号为星期几
```javascript
var weekday = ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"];
weekday[new Date(2015, 9, 1).getDay()];	//2015年10月1号
```

#### 2. Mobile - js

- [js 判断IOS, 安卓](http://caibaojian.com/browser-ios-or-android.html)
```javascript
var u = navigator.userAgent, app = navigator.appVersion;
var isAndroid = u.indexOf('Android') > -1 || u.indexOf('Linux') > -1; //android终端或者uc浏览器
var isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端
alert('是否是Android:'+isAndroid);
alert('是否是iOS:'+isiOS);
```

#### 3. [微信 weixin](http://loo2k.com/blog/detecting-wechat-client/)

- UserAgent 判断微信客户端
```javascript
// Mozilla/5.0 (iPhone; CPU iPhone OS 8_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Mobile/12F70 MicroMessenger/6.1.5 NetType/WIFI
function isWechat() {  
    var ua = navigator.userAgent.toLowerCase();
    return /micromessenger/i.test(ua) || /windows phone/i.test(ua);
}
```
- 获取单个dom元素
```js
function $(selector, el) {
  if (!el) {
    el = document;
  }
  return el.querySelector(selector);
}
```
- 获取多个dom元素
```js
function $$(selector, el) {
  if (!el) {
    el = document;
  }
  return el.querySelectorAll(selector);
  // Note: the returned object is a NodeList.
  // If you'd like to convert it to a Array for convenience, use this instead:
  // return Array.prototype.slice.call(el.querySelectorAll(selector));
}
```
- 将nodeList集合转换为数组
```js
function convertToArray(nodeList) {
  var array = null
  try {
    // IE8-NodeList是COM对象
    array = Array.prototype.slice.call(nodeList, 0)
  } catch (err) {
    array = []
    for (var i = 0, len = nodeList.length; i < len; i++) {
      array.push(nodeList[i])
    }
  }
  return array
}
```
- ajax函数
```js
function ajax(setting) {
  //设置参数的初始值
  var opts = {
    method: (setting.method || "GET").toUpperCase(), //请求方式
    url: setting.url || "", // 请求地址
    async: setting.async || true, // 是否异步
    dataType: setting.dataType || "json", // 解析方式
    data: setting.data || "", // 参数
    success: setting.success || function () { }, // 请求成功回调
    error: setting.error || function () { } // 请求失败回调
  };

  // 参数格式化
  function params_format(obj) {
    var str = "";
    for (var i in obj) {
      str += i + "=" + obj[i] + "&";
    }
    return str
      .split("")
      .slice(0, -1)
      .join("");
  }

  // 创建ajax对象
  var xhr = new XMLHttpRequest();

  // 连接服务器open(方法GET/POST,请求地址, 异步传输)
  if (opts.method == "GET") {
    xhr.open(
      opts.method,
      opts.url + "?" + params_format(opts.data),
      opts.async
    );
    xhr.send();
  } else {
    xhr.open(opts.method, opts.url, opts.async);
    xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    xhr.send(opts.data);
  }

  /*
  ** 每当readyState改变时,就会触发onreadystatechange事件
  ** readyState属性存储有XMLHttpRequest的状态信息
  ** 0 :请求未初始化
  ** 1 :服务器连接已建立
  ** 2 :请求已接受
  ** 3 : 请求处理中
  ** 4 :请求已完成,且相应就绪
  */
  xhr.onreadystatechange = function () {
    if (xhr.readyState === 4 && (xhr.status === 200 || xhr.status === 304)) {
      switch (opts.dataType) {
        case "json":
          var json = JSON.parse(xhr.responseText);
          opts.success(json);
          break;
        case "xml":
          opts.success(xhr.responseXML);
          break;
        default:
          opts.success(xhr.responseText);
          break;
      }
    }
  };

  xhr.onerror = function (err) {
    opts.error(err);
  };
}
```

- JS接口安全域名不填写,分享onMenuShareAppMessage直接会取默认值。
```javascript
// 分享onMenuShareAppMessage直接会取默认值
```

- 关闭当前页面
```javascript
WeixinJSBridge.call('closeWindow');
```

- [支付接口方法调用必须在addevent里边调用](http://www.cnblogs.com/true_to_me/p/3565039.html)
```javascript
document.addEventListener('WeixinJSBridgeReady', function onBridgeReady(){
    that.initOrder();
}, false);
```

- 支付接口方法调用必须在
```javascript
WeixinJSBridge.invoke('getBrandWCPayRequest', d, function(res){
    if(res.err_msg == "get_brand_wcpay_request:ok"){
        // alert("支付成功");
        // union.release(d.orderId);
        resetUrl();
        paySuccess('home', d.orderId);
    } else {
        cancelOrder(d.orderId);
        // alert(res.err_msg);
    }
    loading.hide();
});
```

- 瀑布流无限加载实例 
```javascript
// be dependent on jquery & jquery.infinitescroll.min.js
// insert this '<div id="more"><a href="api?page="></a></div>' to your page.html
(function($){
  $(function(){
      var $container = $('.list-wrap-gd');
      function layOutCallBack() {
          $container.imagesLoaded(function(){
              $container.masonry({
                  itemSelector: '.item-bar',
                  gutter: 10
              });
          });
          $container.imagesLoaded().progress( function() {
              $container.masonry('layout');
          });
      }

      layOutCallBack();

      $container.infinitescroll({
          navSelector : "#more",
          nextSelector : "#more a",
          itemSelector : ".item-bar",
          pixelsFromNavToBottom: 300,
          loading:{
              img: "/images/masonry_loading.gif",
              msgText: ' ',
              finishedMsg: "<em>已经到最后一页</em>",
              finished: function(){
                  $("#more").remove();
                  $("#infscr-loading").hide();
              }
          },
          errorCallback:function(){
              $(window).unbind('.infscr');
          },
          pathParse: function (path, nextPage) {
              var query = "";
              var keyword=$("#search_keyword").val();
              var cat_id=$("#cat_id").val();
              var brand_id=$("#brand_id").val();
              var country_id = $("#country_id").val();
              query = query + "&namekeyword="+keyword;
              query = query +"&cat_id="+cat_id
              query = query + "&brand_id=" + brand_id; 
              query = query + "&country_id=" + country_id;
              path = [path,query];
              return path;
          }
      },

      function(newElements) {
          var $newElems = $( newElements ).css({ opacity: 0 });
          $newElems.imagesLoaded(function(){
              $newElems.animate({ opacity: 1 });
              $container.masonry( 'appended', $newElems, true );
              layOutCallBack();
          });
      });
  });
})(jQuery);
```
  
- [iOS,Safari浏览器,input等表单focus后fixed元素错位问题](https://www.snip2code.com/Snippet/176582/--iOS-Safari----input---focus-fixed-----)
```javascript
if( /iPhone|iPod|iPad/i.test(navigator.userAgent) ) {
  $(document).on('focus', 'input, textarea', function()
  {
     $('header').css("position", 'absolute');
     $('footer').css("position", 'absolute');
     
  });
  
  $(document).on('blur', 'input, textarea', function()
  {
       $('header').css("position", 'fixed');
       $('footer').css("position", 'fixed');
      
  });
} 

```
  
- 得到地理位置
```javascript
function getLocation(callback){
  if(navigator.geolocation){
      navigator.geolocation.getCurrentPosition(
              function(p){
                  callback(p.coords.latitude, p.coords.longitude);
              },
              function(e){
                  var msg = e.code + "\n" + e.message;
              }
      );
  }
}
```

- [rem计算适配](http://isux.tencent.com/web-app-rem.html)
```javascript
(function(doc, win){
  var docEl = doc.documentElement,
      resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
      recalc = function(){
          var clientWidth = docEl.clientWidth;
          if(!clientWidth) return;
          docEl.style.fontSize = 20 * (clientWidth / 320) + 'px';
      };

  if(!doc.addEventListener) return;
  win.addEventListener(resizeEvt, recalc, false);
  doc.addEventListener('DOMContentLoaded', recalc, false);
})(document, window);
```

- [另外一种rem方案](http://www.html-js.com/article/3041)
```javascript
var dpr, rem, scale;
var docEl = document.documentElement;
var fontEl = document.createElement('style');
var metaEl = document.querySelector('meta[name="viewport"]');

dpr = window.devicePixelRatio || 1;
rem = docEl.clientWidth * 2 / 10;
scale = 1 / dpr;


// 设置viewport,进行缩放,达到高清效果
metaEl.setAttribute('content', 'width=' + dpr * docEl.clientWidth + ',initial-scale=' + scale + ',maximum-scale=' + scale + ', minimum-scale=' + scale + ',user-scalable=no');

// 设置data-dpr属性,留作的css hack之用
docEl.setAttribute('data-dpr', dpr);

// 动态写入样式
docEl.firstElementChild.appendChild(fontEl);
fontEl.innerHTML = 'html{font-size:' + rem + 'px!important;}';

// 给js调用的,某一dpr下rem和px之间的转换函数
window.rem2px = function(v) {
    v = parseFloat(v);
    return v * rem;
};
window.px2rem = function(v) {
    v = parseFloat(v);
    return v / rem;
};

window.dpr = dpr;
window.rem = rem;
```

- 获取js所在路径
```js
function getJsDir (src) {
    var script = null;

    if (src) {
        script = [].filter.call(document.scripts, function (v) {
            return v.src.indexOf(src) !== -1;
        })[0];
    } else {
        script = document.scripts[document.scripts.length - 1];
    }

    return script ? script.src.substr(0, script.src.lastIndexOf('/')) : script;
}
```
- 页面加载自执行函数
```js
function addload(func) {
  var old = window.onload;
  if (typeof window.onload != "function") {
    window.onload = func;
  } else {
    window.onload = function () {
      old();
      func();
    }
  }
}
```

- 从全局捕获错误
```js
window.onerror = function (errMsg, scriptURI, lineNumber, columnNumber, errorObj) {
    setTimeout(function () {
        var rst = {
            "错误信息:": errMsg,
            "出错文件:": scriptURI,
            "出错行号:": lineNumber,
            "出错列号:": columnNumber,
            "错误详情:": errorObj
        };

        alert(JSON.stringify(rst, null, 10));
    });
};
```

- [如何通过 js 修改微信浏览器的title?](https://www.zhihu.com/question/26228251/answer/32405529)
```javascript
var $body = $('body');
document.title = 'title'; // hack在微信等webview中无法修改document.title的情况    
var $iframe = $('<iframe src="/favicon.ico"></iframe>').on('load', function(){ 
    setTimeout(function(){ 
        $iframe.off('load').remove() 
    }, 0) 
}).appendTo($body)
```

#### 1. 常用方法 - js
- 字符串长度截取
```js
function cutstr(str, len) {
    var temp,
        icount = 0,
        patrn = /[^\x00-\xff]/,
        strre = "";
    for (var i = 0; i < str.length; i++) {
        if (icount < len - 1) {
            temp = str.substr(i, 1);
                if (patrn.exec(temp) == null) {
                   icount = icount + 1
            } else {
                icount = icount + 2
            }
            strre += temp
            } else {
            break;
        }
    }
    return strre + "..."
}
```

- 替换全部
```js
String.prototype.replaceAll = function(s1, s2) {
    return this.replace(new RegExp(s1, "gm"), s2)
}
````

- 清除空格
```js
String.prototype.trim = function() {
    var reExtraSpace = /^\s*(.*?)\s+$/;
    return this.replace(reExtraSpace, "$1")
}
```

- 清除左空格/右空格
```js
function ltrim(s){ return s.replace( /^(\s*| *)/, ""); } 
function rtrim(s){ return s.replace( /(\s*| *)$/, ""); }
```
- 判断是否以某个字符串开头
```js
String.prototype.startWith = function (s) {
    return this.indexOf(s) == 0
}
```
- 判断是否以某个字符串结束	
```js
String.prototype.endWith = function (s) {
    var d = this.length - s.length;
    return (d >= 0 && this.lastIndexOf(s) == d)
}
```
- 转义html标签
```js
function HtmlEncode(text) {
    return text.replace(/&/g, '&').replace(/\"/g, '"').replace(/</g, '<').replace(/>/g, '>')
}
```
- 时间日期格式转换
```js
Date.prototype.Format = function(formatStr) {
    var str = formatStr;
    var Week = ['日', '一', '二', '三', '四', '五', '六'];
    str = str.replace(/yyyy|YYYY/, this.getFullYear());
    str = str.replace(/yy|YY/, this.getFullYear().toString().substr(2));
    str = str.replace(/MM/, (this.getMonth() + 1) > 9 ? (this.getMonth() + 1).toString() : '0' + (this.getMonth() + 1));
    str = str.replace(/M/g, (this.getMonth() + 1));
    str = str.replace(/w|W/g, Week[this.getDay()]);
    str = str.replace(/dd|DD/, this.getDate() > 9 ? this.getDate().toString() : '0' + this.getDate());
    str = str.replace(/d|D/g, this.getDate());
    str = str.replace(/hh|HH/, this.getHours() > 9 ? this.getHours().toString() : '0' + this.getHours());
    str = str.replace(/h|H/g, this.getHours());
    str = str.replace(/mm/, this.getMinutes() > 9 ? this.getMinutes().toString() : '0' + this.getMinutes());
    str = str.replace(/m/g, this.getMinutes());
    str = str.replace(/ss|SS/, this.getSeconds() > 9 ? this.getSeconds().toString() : '0' + this.getSeconds());
    str = str.replace(/s|S/g, this.getSeconds());
    return str
}
```

- 判断日期是否有效
```javascript
function isValidDate(value, userFormat='mm/dd/yyyy') {
    const delimiter = /[^mdy]/.exec(userFormat)[0];
    const theFormat = userFormat.split(delimiter);
    const theDate = value.split(delimiter);
    function isDate(date, format) {
	let m, d, y, i = 0, len = format.length, f;
	for (i; i < len; i++) {
	    f = format[i];
	    if (/m/.test(f)) m = date[i];
	    if (/d/.test(f)) d = date[i];
	    if (/y/.test(f)) y = date[i];
	}
	return (
	    m > 0 && m < 13 &&
	    y && y.length === 4 &&
	    d > 0 &&
	    d <= (new Date(y, m, 0)).getDate()
	);
    }

    return isDate(theDate, theFormat);
}
```

- 判断是否为数字类型	
```js
function isDigit(value) {
    var patrn = /^[0-9]*$/;
    if (patrn.exec(value) == null || value == "") {
        return false
    } else {
        return true
    }
}
```
- 判断具体类型	
```js
function getType(a) {
    var typeArray = Object.prototype.toString.call(a).split(" ");
    return typeArray[1].slice(0, -1);
}
```
- 设置cookie值
```js
function setCookie(name, value, Hours) {
    var d = new Date();
    var offset = 8;
    var utc = d.getTime() + (d.getTimezoneOffset() * 60000);
    var nd = utc + (3600000 * offset);
    var exp = new Date(nd);
    exp.setTime(exp.getTime() + Hours * 60 * 60 * 1000);
    document.cookie = name + "=" + escape(value) + ";path=/;expires=" + exp.toGMTString()
}
```
- 获取cookie值
```js
function getCookie(name) {
    var arr = document.cookie.match(new RegExp("(^| )" + name + "=([^;]*)(;|$)"));
    if (arr != null) return unescape(arr[2]);
    return null
}
```
- 加载样式文件表	
```js
function LoadStyle(url) {
    try {
        document.createStyleSheet(url)
    } catch(e) {
        var cssLink = document.createElement('link');
        cssLink.rel = 'stylesheet';
        cssLink.type = 'text/css';
        cssLink.href = url;
        var head = document.getElementsByTagName('head')[0];
        head.appendChild(cssLink)
    }
}
```
- 返回脚本内容
```js
function evalscript(s) {
    if(s.indexOf('<script') == -1) return s;
    var p = /<script[^\>]*?>([^\x00]*?)<\/script>/ig;
    var arr = [];
    while(arr = p.exec(s)) {
        var p1 = /<script[^\>]*?src=\"([^\>]*?)\"[^\>]*?(reload=\"1\")?(?:charset=\"([\w\-]+?)\")?><\/script>/i;
        var arr1 = [];
        arr1 = p1.exec(arr[0]);
        if(arr1) {
            appendscript(arr1[1], '', arr1[2], arr1[3]);
        } else {
            p1 = /<script(.*?)>([^\x00]+?)<\/script>/i;
            arr1 = p1.exec(arr[0]);
            appendscript('', arr1[2], arr1[1].indexOf('reload=') != -1);
        }
    }
    return s;
}
```
- 清除脚本内容
```js
function stripscript(s) {
    return s.replace(/<script.*?>.*?<\/script>/ig, '');
}
```
- 动态加载脚本文件
```js
function appendscript(src, text, reload, charset) {
    var id = hash(src + text);
    if(!reload && in_array(id, evalscripts)) return;
    if(reload && $(id)) {
        $(id).parentNode.removeChild($(id));
    }
 
    evalscripts.push(id);
    var scriptNode = document.createElement("script");
    scriptNode.type = "text/javascript";
    scriptNode.id = id;
    scriptNode.charset = charset ? charset : (BROWSER.firefox ? document.characterSet : document.charset);
    try {
        if(src) {
            scriptNode.src = src;
            scriptNode.onloadDone = false;
            scriptNode.onload = function () {
                scriptNode.onloadDone = true;
                JSLOADED[src] = 1;
             };
             scriptNode.onreadystatechange = function () {
                 if((scriptNode.readyState == 'loaded' || scriptNode.readyState == 'complete') && !scriptNode.onloadDone) {
                    scriptNode.onloadDone = true;
                    JSLOADED[src] = 1;
                }
             };
        } else if(text){
            scriptNode.text = text;
        }
        document.getElementsByTagName('head')[0].appendChild(scriptNode);
    } catch(e) {}
}
```
- 动态加载js或css文件
```js
function delay_js(url) {
  var type = url.split(".")
    , file = type[type.length - 1];
  if (file == "css") {
    var obj = document.createElement("link")
      , lnk = "href"
      , tp = "text/css";
    obj.setAttribute("rel", "stylesheet");
  } else
    var obj = document.createElement("script")
      , lnk = "src"
      , tp = "text/javascript";
  obj.setAttribute(lnk, url);
  obj.setAttribute("type", tp);
  file == "css" ? document.getElementsByTagName("head")[0].appendChild(obj) : document.body.appendChild(obj);
  return obj;
}
```
- 返回按ID检索的元素对象
```js
function $(id) {
    return !id ? null : document.getElementById(id);
}
```
- 检验URL链接是否有效	
```js
function getUrlState(URL){ 
    var xmlhttp = new ActiveXObject("microsoft.xmlhttp"); 
    xmlhttp.Open("GET",URL, false);  
    try{  
            xmlhttp.Send(); 
    }catch(e){
    }finally{ 
        var result = xmlhttp.responseText; 
        if(result){
            if(xmlhttp.Status==200){ 
                return(true); 
             }else{ 
                   return(false); 
             } 
         }else{ 
             return(false); 
         } 
    }
}
```
- 获取当前路径
```js
var currentPageUrl = "";
if (typeof this.href === "undefined") {
    currentPageUrl = document.location.toString().toLowerCase();
}else {
    currentPageUrl = this.href.toString().toLowerCase();
}
```
- 获取页面高度
```js
function getPageHeight(){
    var g = document, a = g.body, f = g.documentElement, d = g.compatMode == "BackCompat"
                    ? a
                    : g.documentElement;
    return Math.max(f.scrollHeight, a.scrollHeight, d.clientHeight);
}
```
- 获取页面可视宽度
```js
function getPageViewWidth(){
    var d = document, a = d.compatMode == "BackCompat" ? 
       				   d.body: d.documentElement;
    return a.clientWidth;
}
```
- 获取页面宽度
```js
function getPageWidth(){
    var g = document, a = g.body, f = g.documentElement, d = g.compatMode == "BackCompat"?
    					  a: g.documentElement;
    return Math.max(f.scrollWidth, a.scrollWidth, d.clientWidth);
}
```
- 随机数时间戳
```js
function uniqueId(){
    var a=Math.random,b=parseInt;
    return Number(new Date()).toString()+b(10*a())+b(10*a())+b(10*a());
}
```
- 日期格式化函数
```js
Date.prototype.format = function(format){
    var o = {
        "M+" : this.getMonth()+1, //month
        "d+" : this.getDate(),    //day
        "h+" : this.getHours(),   //hour
        "m+" : this.getMinutes(), //minute
        "s+" : this.getSeconds(), //second
        "q+" : Math.floor((this.getMonth()+3)/3),  //quarter
        "S" : this.getMilliseconds() //millisecond
    };
    if(/(y+)/.test(format)) format=format.replace(RegExp.$1,
(this.getFullYear()+"").substr(4 - RegExp.$1.length));
    for(var k in o){
        if(new RegExp("("+ k +")").test(format))
            format = format.replace(RegExp.$1,RegExp.$1.length==1 ? o[k] :("00"+ o[k]).substr((""+ o[k]).length));
    }
    return format;
}
//调用
//new Date().format("yyyy-MM-dd hh:mm:ss");
```
- 返回顶部的通用方法
```js
function backTop(btnId) {
    var btn = document.getElementById(btnId);
    var d = document.documentElement;
    var b = document.body;
    window.onscroll = set;
    btn.style.display = "none";
    btn.onclick = function() {
        btn.style.display = "none";
        window.onscroll = null;
        this.timer = setInterval(function() {
            d.scrollTop -= Math.ceil((d.scrollTop + b.scrollTop) * 0.1);
            b.scrollTop -= Math.ceil((d.scrollTop + b.scrollTop) * 0.1);
            if ((d.scrollTop + b.scrollTop) == 0) clearInterval(btn.timer, window.onscroll = set);
            }, 10);
    };
    function set() {
        btn.style.display = (d.scrollTop + b.scrollTop > 100) ? 'block': "none"
    }
};
backTop('goTop');
```
- 获得URL中GET参数值
```js
// 用法:如果地址是 test.htm?t1=1&t2=2&t3=3, 那么能取得:GET["t1"], GET["t2"], GET["t3"]
function get_get(){ 
    querystr = window.location.href.split("?")
    if(querystr[1]){
        GETs = querystr[1].split("&");
        GET = [];
        for(i=0;i<GETs.length;i++){
              tmp_arr = GETs.split("=")
              key=tmp_arr[0]
              GET[key] = tmp_arr[1]
        }
    }
    return querystr[1];
}
```
- 数组去重
```js
String.prototype.unique=function(){
    var x=this.split(/[\r\n]+/);
    var y='';
    for(var i=0;i<x.length;i++){
        if(!new RegExp("^"+x.replace(/([^\w])/ig,"\\$1")+"$","igm").test(y)){
            y+=x+"\r\n"
        }
    }
    return y
};
```
- 删除数组中某个元素
```js
Array.prototype.remove = function (val) {
  var index = this.indexOf(val);
  if (index > -1) {
    this.splice(index, 1);
  }
};
```

- 判断数组里是否有某个元素
```js
 Array.prototype.isContains = function (e) {
  for (i = 0; i < this.length && this[i] != e; i++);
  return !(i == this.length);
}
```
- 按字典顺序,对每行进行数组排序
```js
function SetSort(){
    var text=K1.value.split(/[\r\n]/).sort().join("\r\n");//顺序
    var test=K1.value.split(/[\r\n]/).sort().reverse().join("\r\n");//反序
    K1.value=K1.value!=text?text:test;
}
```
- 字符串反序输出
```js
function IsReverse(text){
    return text.split('').reverse().join('');
}
```
- 金额大写转换函数
```js
//格式转换
function transform(tranvalue) {
    try {
        var i = 1;
        var dw2 = new Array("", "万", "亿"); //大单位
        var dw1 = new Array("拾", "佰", "仟"); //小单位
        var dw = new Array("零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"); //整数部分用
        //以下是小写转换成大写显示在合计大写的文本框中     
        //分离整数与小数
        var source = tranvalue.split(".");
        var num = source[0];
        var dig = source[1];
        //转换整数部分
        var k1 = 0; //计小单位
        var k2 = 0; //计大单位
        var sum = 0;
        var str = "";
        var len = source[0].length; //整数的长度
        for (i = 1; i <= len; i++) {
              var n = source[0].charAt(len - i); //取得某个位数上的数字
              var bn = 0;
              if (len - i - 1 >= 0) {
                bn = source[0].charAt(len - i - 1); //取得某个位数前一位上的数字
              }
              sum = sum + Number(n);
              if (sum != 0) {
                str = dw[Number(n)].concat(str); //取得该数字对应的大写数字,并插入到str字符串的前面
                if (n == '0') sum = 0;
              }
              if (len - i - 1 >= 0) { //在数字范围内
                if (k1 != 3) { //加小单位
                      if (bn != 0) {
                        str = dw1[k1].concat(str);
                      }
                      k1++;
                } else { //不加小单位,加大单位
                      k1 = 0;
                      var temp = str.charAt(0);
                      if (temp == "万" || temp == "亿") //若大单位前没有数字则舍去大单位
                      str = str.substr(1, str.length - 1);
                      str = dw2[k2].concat(str);
                      sum = 0;
                }
              }
              if (k1 == 3){ //小单位到千则大单位进一
                k2++;
              }
        }
        //转换小数部分
        var strdig = "";
        if (dig != "") {
              var n = dig.charAt(0);
              if (n != 0) {
                strdig += dw[Number(n)] + "角"; //加数字
              }
              var n = dig.charAt(1);
              if (n != 0) {
                strdig += dw[Number(n)] + "分"; //加数字
              }
        }
        str += "元" + strdig;
    } catch(e) {
        return "0元";
    }
    return str;
}
```
- 格式化数字
```js
function fmoney(s, n) {
  //s:传入的float数字 ,n:希望返回小数点几位
  n = n > 0 && n <= 20 ? n : 2;
  s = parseFloat((s + "").replace(/[^\d\.-]/g, "")).toFixed(n) + "";
  var l = s
    .split(".")[0]
    .split("")
    .reverse(),
    r = s.split(".")[1];
  t = "";
  for (i = 0; i < l.length; i++) {
    t += l[i] + ((i + 1) % 3 == 0 && i + 1 != l.length ? "," : "");
  }
  return;
  t
    .split("")
    .reverse()
    .join("") +
    "." +
    r;
}
```


================================================
FILE: JAVASCRIPT/数组中的对象去重.md
================================================
## js中数组对象去重的方法

### 这里有两种方法
1. 采用对象访问属性的方法,判断属性值是否存在,如果不存在就添加
2. 采用数组中的reduce方法,遍历数组,也是通过对象访问属性的方法
``` javascript 1.8
var arr = [{
      key: '01',
      value: '乐乐'
   }, {
      key: '02',
      value: '博博'
   }, {
      key: '03',
      value: '淘淘'
   },{
      key: '04',
      value: '哈哈'
   },{
      key: '01',
      value: '乐乐'
   }];


   //  方法1:利用对象访问属性的方法,判断对象中是否存在key
   var result = [];
   var obj = {};
   for(var i =0; i<arr.length; i++){
      if(!obj[arr[i].key]){
         result.push(arr[i]);
         obj[arr[i].key] = true;
      }
   }
   console.log(result); // [{key: "01", value: "乐乐"},{key: "02", value: "博博"},{key: "03", value: "淘淘"},{key: "04", value: "哈哈"}]



   //  方法2:利用reduce方法遍历数组,reduce第一个参数是遍历需要执行的函数,第二个参数是item的初始值
      var obj = {};
    arr = arr.reduce(function(item, next) {
      obj[next.key] ? '' : obj[next.key] = true && item.push(next);
      return item;
   }, []);
   console.log(arr); // [{key: "01", value: "乐乐"},{key: "02", value: "博博"},{key: "03", value: "淘淘"},{key: "04", value: "哈哈"}]
   ```

================================================
FILE: JAVASCRIPT/文件流转为文件.md
================================================
## 文件流转为文件
```javascript 1.8
dataURLtoFile (dataurl, filename) {
                let arr = dataurl.split(',');
                let mime = arr[0].match(/:(.*?);/)[1];
                let bstr = atob(arr[1]);
                let n = bstr.length;
                let u8arr = new Uint8Array(n);
                while (n--) {
                    u8arr[n] = bstr.charCodeAt(n);
                }
                return new File([u8arr], filename, {type: mime});
            }
``` 
#### 参数解释     
*   dataurl: 文件流
*   filename:自定义文件名称   


================================================
FILE: JAVASCRIPT/时间与时间戳的转换.md
================================================
### 时分转当天的时间戳
```javascript 1.8
gettime(time){
    const start = time.split(':')
    const startime = new Date().setHours(start[0], start[1], 0, 0)
    return time
}
````
### 时间戳转时分 利用moment.js
```javascript 1.8
function timestampTos (Timestamps) {
    return moment(Timestamps * 1000).format('HH:mm')
}
```
```javascript 1.8
/**
 *
 *
 * 时间戳转时分秒
 * @param {number} Timestamps 时间戳
 * @returns {string} 23:59(分)
 */
export function timestampTos (Timestamps) {
    return moment(Timestamps * 1000).format('HH:mm')
}

/**
 * 时间戳转时分秒
 * @param {number} Timestamps 时间戳
 * @returns {string} 23:59:59(秒)
 */
export function timestampToms (Timestamps) {
    return moment(Timestamps * 1000).format('HH:mm:ss')
}

/**
 * 时间戳转日期
 * @param Timestamps 时间戳
 * @returns {string} 2018-08-28 (日)
 */
export function timestampToYMD (Timestamps) {
    if (Timestamps) {
        if (parseInt(Timestamps) === 1542011036 || parseInt(Timestamps) === 0) {
            return '--'
        } else {
            return moment(Timestamps * 1000).format('YYYY-MM-DD')
        }
    } else {
        return '--'
    }
}

/**
 * 时间戳转短时间
 * @param Timestamps 时间戳
 * @returns {string} 2018-08-28 23:59(分)
 */
export function timestampToYMDHm (Timestamps) {
    if (Timestamps && Timestamps !== '0') {
        return moment(Timestamps * 1000).format('YYYY-MM-DD HH:mm')
    } else {
        return '--'
    }
}

/**
 * 时间戳转长时间
 * @param Timestamps 时间戳
 * @returns {string} 2018-08-28 23:59:59(秒)
 */
export function timestampToYMDHms (Timestamps) {
    if (Timestamps) {
        return moment(Timestamps * 1000).format('YYYY-MM-DD HH:mm:ss')
    } else {
        return '--'
    }
}

***
 * 时间戳转为周几 10位时间戳
 */
export function timestampToWeek(time) {
  function timedat(res){   //res 为传入的时间戳   例:1509091800000

    var time = new Date(res);

    var y = time.getFullYear();

    var m = time.getMonth()+1;

    var d = time.getDate();

    return y+'-'+m+'-'+d;    //返回格式  "2017-10-27" 字符串
  };
  let date = new Date(timedat(time*1000))
  console.log(time,date)
  var week;
  if(date.getDay() == 0) week = "星期日"
  if(date.getDay() == 1) week = "星期一"
  if(date.getDay() == 2) week = "星期二"
  if(date.getDay() == 3) week = "星期三"
  if(date.getDay() == 4) week = "星期四"
  if(date.getDay() == 5) week = "星期五"
  if(date.getDay() == 6) week = "星期六"
  return week;
}
/**
 * 时间转时间戳
 * @param {number} time 时间
 * @returns {string}  1534567891(秒)
 */
export function timeToTimestamp (time) {
    return moment(time, 'YYYY-MM-DD HH:mm:ss').valueOf() / 1000
}

/**
 * 时间转时分
 * @param {number} time 时间
 * @returns {string}  23:59(分)
 */
export function timeToHm (time) {
    let Timestamps = moment(time, 'YYYY-MM-DD HH:mm').valueOf()
    return moment(Timestamps).format('HH:mm')
}

/**
 * 时间转时分秒
 * @param {number} time 时间
 * @returns {string}  23:59:59(秒)
 */
export function timeToHms (time) {
    let Timestamps = moment(time, 'YYYY-MM-DD HH:mm').valueOf()
    return moment(Timestamps).format('HH:mm:ss')
}

/**
 * 时间对象转时分秒
 * @param {number} time 时间
 * @return {string} 2018-08-08 23:59:59(秒)
 */
export function timeToYMDms (time) {
    let Timestamps = moment(time, 'YYYY-MM-DD HH:mm:ss').valueOf()
    return moment(Timestamps).format('YYYY-MM-DD HH:mm:ss')
}

/**
 * 时间对象转时分
 * @param {number} time 时间
 * @return {string} 2018-08-08 23:59(分)
 */
export function timeToYMDm (time) {
    let Timestamps = moment(time, 'YYYY-MM-DD HH:mm:ss').valueOf()
    return moment(Timestamps).format('YYYY-MM-DD HH:mm')
}
```


================================================
FILE: JAVASCRIPT/时间戳转日期.md
================================================
## 时间戳转日期
```javascript 1.8
formatDate: function (value) {
    // value 为毫秒格式
    let date = new Date(Number(value))
    let y = date.getFullYear()
    let MM = date.getMonth() + 1
    MM = MM < 10 ? ('0' + MM) : MM
    let d = date.getDate()
    d = d < 10 ? ('0' + d) : d
    let h = date.getHours()
    h = h < 10 ? ('0' + h) : h
    let m = date.getMinutes()
    m = m < 10 ? ('0' + m) : m
    return y + '-' + MM + '-' + d
}
```

================================================
FILE: JAVASCRIPT/深度克隆.md
================================================
```javascript 1.8
clone (obj) {
    // 处理3种简单类型,null或undefined
    // Handle the 3 simple types, and null or undefined
    if (obj === null || typeof obj !== 'object') return obj

    // 处理时间 Date
    if (obj instanceof Date) {
        let copy = new Date()
        copy.setTime(obj.getTime())
        return copy
    }
    // 处理数组 Array
    if (obj instanceof Array) {
        let copy = []
        for (let i = 0; i < obj.length; ++i) {
            copy[i] = clone(obj[i])
        }
        return copy
    }
    // 处理对象 Object
    if (obj instanceof Object) {
        let copy = {}
        for (let attr in obj) {
            if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr])
        }
        return copy
    }
    throw new Error('Unable to copy obj! Its type isn\'t supported.')
}
```



================================================
FILE: JAVASCRIPT/深度拷贝.md
================================================
## 深度拷贝
```javascript
clone (obj) {
    // 处理3种简单类型,null或undefined
    // Handle the 3 simple types, and null or undefined
    if (obj === null || typeof obj !== 'object') return obj
    // 处理时间 Date
    if (obj instanceof Date) {
        let copy = new Date()
        copy.setTime(obj.getTime())
        return copy
    }
    // 处理数组 Array
    if (obj instanceof Array) {
        let copy = []
        for (let i = 0; i < obj.length; ++i) {
            copy[i] = clone(obj[i])
        }
        return copy
    }
    // 处理对象 Object
    if (obj instanceof Object) {
        let copy = {}
        for (let attr in obj) {
            if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr])
        }
        return copy
    }
    throw new Error('Unable to copy obj! Its type isn\'t supported.')
}
```


================================================
FILE: JAVASCRIPT/滚动加载demo.md
================================================
## 滚动加载demo
```vuejs
ScrollLoading.vue(子组件)
<template>
    <div class="dz-loading-list">
        <slot :data="data"></slot>

        <div class="no-list-infos" v-if="data.length === 0 && !isImg">
            <!-- <img src="/static/image/noinfo.png" alt=""> -->
            暂无数据
        </div>
        <div class="no-evaluation-info"  v-if="data.length === 0 && isImg">
            <!-- <img src="/static/image/evaluation_default@2x.png" class="avatar"> -->
            <p class="text">对不起,未搜索到相关信息 </p>
        </div>

        <load-more v-show="showLoading" :show-loading="showLoading" tip="正在加载更多" background-color="#fbf9fe"></load-more>
        <div style="width:1px;height:1px;" id="scrollDiv"></div>
    </div>
</template>

<script>
    import {XButton, LoadMore} from 'vux'

    export default {
        components: {
            XButton, LoadMore
        },
        name: 'ScrollLoading',
        data() {
            return {
                isGettingData: false,
                currentPage: 1,
                isRead: 0,
                hasMoreData: true,
                showLoading: false,
                data: [],
                urlParam: {},
                getUrl: '',
                pager: {
                    totalCount: '',
                    pageSize: '',
                    currentPage: ''
                }
            }
        },
        watch: {
            otherObj: {
                handler() {
                    this.data = []
                    this.urlParam = {}
                    this.currentPage = 1;
                    for (let value in this.otherObj) {
                        this.urlParam[value] = this.otherObj[value]
                    }
                    this.hasMoreData = true
                    this.updateData(this.urlParam, 'change')
                },
                deep: true
            },
            loadUrl () {
                this.data = []
                this.urlParam = {}
                this.currentPage = 1;
                this.hasMoreData = true
                this.updateData(this.urlParam, 'change')
            }
        },
        props: {
            loadUrl: {
                required: true
            },
            dataListName: {
                required: true
            },
            otherObj: {
                required: false,
                type: Object
            },
            isGet: {
                type: Boolean,
                default: false
            },
            //是否清楚数组
            isClean: {
                type: Boolean
            },
            // 是否替换背景图
            isImg: {
                type: Boolean,
                default: false
            }
        },
        methods: {
            updateData(param, arg) {
                this.getUrl = this.loadUrl;
                let data = {};
                this.isGettingData = true;
                if (this.isGet) {
                    data = {};
                    if (this.getUrl.indexOf('page') == -1) {
                        this.getUrl = this.loadUrl + '?page=' + this.currentPage
                    }
                } else {
                    data = {page: this.currentPage};
                }

                for(let key in param){
                    data[key] = param[key]
                }
                // 页面验证
                if (this.pager.totalCount) {
                    if (this.currentPage > Math.ceil(parseInt(this.pager.totalCount)/parseInt(this.pager.pageSize)) ) {
                        this.showLoading = false
                        return
                    }
                }

                this.api.post(this.getUrl, {
                    ...data,
                    page: this.currentPage
                }, {},result => {
                    if (arg == 'change') {
                        this.data = []
                    }
                    this.pager = result.pager

                    this.$emit('getPaginationData', result.content)
                    this.isGettingData = false
                    if (this.dataListName.length != 0) {
                        if (result[this.dataListName].length == 0) {
                            this.showLoading = false;
                            this.hasMoreData = false;
                            return;
                        }

                        result[this.dataListName].forEach((item) => {
                            this.data.push(item);
                        });
                    } else {
                        if (result.length == 0) {
                            this.showLoading = false;
                            this.hasMoreData = false;
                            return;
                        }
                        result.forEach((item) => {
                            this.data.push(item);
                        });
                    }

                    this.$emit('updateData', this.data)
                    this.currentPage++
                })
            },
            scrollAction() {
                if (document.getElementById('scrollDiv')) {
                    var loadingMoreTop = document.getElementById('scrollDiv').offsetTop;
                    var windowScrollBotton = window.pageYOffset + window.screen.height;
                    if (windowScrollBotton >= (loadingMoreTop - 30) && this.isGettingData == false && this.hasMoreData) {
                        this.showLoading = true;
                        this.getData();
                    }
                }
            },
            getData() {
                if (this.otherObj) {
                    this.urlParam = {}
                    if (this.otherObj) {
                        for (let value in this.otherObj) {
                            this.urlParam[value] = this.otherObj[value];
                        }
                    }
               
Download .txt
gitextract_aeb36g8b/

├── .gitignore
├── .idea/
│   ├── $CACHE_FILE$
│   ├── .gitignore
│   ├── inspectionProfiles/
│   │   └── profiles_settings.xml
│   ├── misc.xml
│   ├── modules.xml
│   ├── vcs.xml
│   └── work-sunnary.iml
├── CSS/
│   ├── Input placeholder属性样式修改(颜色,大小,位置).md
│   ├── common.css
│   ├── less 中使用grid布局.md
│   ├── reset.css
│   └── 常用css.md
├── Git/
│   └── 使用规范.md
├── HTML/
│   ├── 双飞翼布局.html
│   ├── 圣杯布局.html
│   └── 防止移动端点击输入框页面变大.md
├── HTTP/
│   ├── 封装axios请求拦截器.md
│   └── 设置请求头.md
├── JAVASCRIPT/
│   ├── FormData使用方法.md
│   ├── JavaScript规范.md
│   ├── 上传oss.md
│   ├── 下载文件流.md
│   ├── 修改url的某个参数值.md
│   ├── 功能性js插件.md
│   ├── 基于vant上传组件oss/
│   │   └── 服务器.md
│   ├── 完美url跳转方式.md
│   ├── 常用js代码块.md
│   ├── 数组中的对象去重.md
│   ├── 文件流转为文件.md
│   ├── 时间与时间戳的转换.md
│   ├── 时间戳转日期.md
│   ├── 深度克隆.md
│   ├── 深度拷贝.md
│   ├── 滚动加载demo.md
│   ├── 用递归算法实现,数组长度为5且元素的随机数在2-32间不重复的值.html
│   ├── 获取当前周每天对应的时间戳.md
│   └── 获取当前月份 第一天 最后一天.md
├── Node/
│   ├── NodeJs文档归纳.md
│   ├── Sequelize.md
│   ├── express浅尝.md
│   ├── koa浅尝.md
│   └── 现有使用量较大的框架.md
├── README.md
├── React/
│   ├── React代码规范.md
│   └── 常见使用总结.md
├── React-Native/
│   ├── APP端消息推送.md
│   ├── APP端消息推送之极光推送.md
│   ├── ios通过浏览器下载app/
│   │   └── 方法.md
│   ├── 使用Promise封装fetch请求.md
│   └── 使用总结.md
├── Redis/
│   ├── index.md
│   └── 浅尝.md
├── package.json
├── vue/
│   ├── Vue导出页面为PDF、word、html格式.md
│   ├── element-audio.md
│   ├── element-ui/
│   │   └── element更改表格表头、行、列、指定单元格样式.md
│   ├── js中使用filter里面的方法.md
│   ├── vue 中使用rem.md
│   ├── vue 项目中如何在页面刷新的状态下保留数据.md
│   ├── vue中怎么重置data?.md
│   ├── 上传图片oss.md
│   ├── 上传文件oss.md
│   ├── 如何动态添加页面title 跟 favicon.ico.md
│   ├── 子组件向父组件传参父组件添加自定义数据.md
│   ├── 资料文档集合.md
│   ├── 阿里云oss 上传.md
│   └── 页面刷新的时候如何保存store.md
├── webpack/
│   └── 日常问题总结.md
├── 插件/
│   ├── Canvas 插件(签名板).md
│   ├── echart.js.md
│   ├── moment.js.md
│   ├── one.md
│   └── postCSS.md
├── 数据库/
│   ├── 数据库建表规则.md
│   └── 设计规范.md
├── 正则/
│   ├── input框只能输入正整数.md
│   └── 文本保存换行 跟空格.md
└── 温顾而知新/
    └── 知识点集合.md
Condensed preview — 79 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (384K chars).
[
  {
    "path": ".gitignore",
    "chars": 47,
    "preview": "# Created by .ignore support plugin (hsz.mobi)\n"
  },
  {
    "path": ".idea/$CACHE_FILE$",
    "chars": 159,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"NodePackageJsonFileManager\">\n    <packag"
  },
  {
    "path": ".idea/.gitignore",
    "chars": 39,
    "preview": "# Default ignored files\r\n/workspace.xml"
  },
  {
    "path": ".idea/inspectionProfiles/profiles_settings.xml",
    "chars": 128,
    "preview": "<component name=\"InspectionProjectProfileManager\">\n  <settings>\n    <option name=\"PROJECT_PROFILE\" />\n  </settings>\n</co"
  },
  {
    "path": ".idea/misc.xml",
    "chars": 179,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<project version=\"4\">\r\n  <component name=\"JavaScriptSettings\">\r\n    <option name"
  },
  {
    "path": ".idea/modules.xml",
    "chars": 283,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<project version=\"4\">\r\n  <component name=\"ProjectModuleManager\">\r\n    <modules>\r"
  },
  {
    "path": ".idea/vcs.xml",
    "chars": 185,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<project version=\"4\">\r\n  <component name=\"VcsDirectoryMappings\">\r\n    <mapping d"
  },
  {
    "path": ".idea/work-sunnary.iml",
    "chars": 469,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<module type=\"WEB_MODULE\" version=\"4\">\r\n  <component name=\"NewModuleRootManager\""
  },
  {
    "path": "CSS/Input placeholder属性样式修改(颜色,大小,位置).md",
    "chars": 591,
    "preview": "## Input placeholder属性样式修改(颜色,大小,位置)\n```html\n 1 <!DOCTYPE html>\n 2 <html>\n 3 <head>\n 4     <meta charset=\"utf-8\">\n 5    "
  },
  {
    "path": "CSS/common.css",
    "chars": 8768,
    "preview": "@charset \"utf-8\";\n/*\n                   _ooOoo_\n                  o8888888o\n                  88\" . \"88\n                "
  },
  {
    "path": "CSS/less 中使用grid布局.md",
    "chars": 277,
    "preview": "# less中使用grid布局 CSS网格列被转换为不同的值\n#### 使用grid布局通常会使用 ‘/’ 符号 但是 直接使用会导致 最终转义的css属性值 为数于数相除的结果\n### 解决方案 使用less中的转义(Escaping)\n"
  },
  {
    "path": "CSS/reset.css",
    "chars": 1228,
    "preview": "/* http://meyerweb.com/eric/tools/css/reset/\n   v4.0 | 20180602\n   License: none (public domain)\n*/\n\nhtml, body, div, sp"
  },
  {
    "path": "CSS/常用css.md",
    "chars": 13022,
    "preview": "### 以下是常用的代码收集,没有任何技术含量。\n\n#### 1. css 2.x\n- 文字换行\n```css\n/*强制不换行*/\nwhite-space:nowrap;\n/*自动换行*/\nword-wrap: break-word;\nwo"
  },
  {
    "path": "Git/使用规范.md",
    "chars": 990,
    "preview": "## 目的\n* 统一团队Git Commit标准,便于后续代码review、版本发布、自动化生成change log;\n* 可以提供更多更有效的历史信息,方便快速预览以及配合cherry-pick快速合并代码;\n* 团队其他成员进行类git"
  },
  {
    "path": "HTML/双飞翼布局.html",
    "chars": 1400,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <div id=\"hd\">header</div>\n    <div id=\"middle\">\n        <div id=\"inside\">mid"
  },
  {
    "path": "HTML/圣杯布局.html",
    "chars": 1141,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<div id=\"hd\">header</div>\n<div id=\"bd\">\n    <div id=\"middle\">middle</div>\n    <div id=\""
  },
  {
    "path": "HTML/防止移动端点击输入框页面变大.md",
    "chars": 486,
    "preview": "### 移动端页面不放大\n```html\n<meta content=\"yes\" name=\"apple-mobile-web-app-capable\"> \n\n<meta name=\"viewport\" content=\"width=dev"
  },
  {
    "path": "HTTP/封装axios请求拦截器.md",
    "chars": 2253,
    "preview": "### 封装axios请求拦截器\n````javascript 1.8\nimport axios from 'axios';\nimport { message } from 'antd';\nimport config from './con"
  },
  {
    "path": "HTTP/设置请求头.md",
    "chars": 158,
    "preview": "## 设置请求头\n```javascript 1.8\nxhr.setRequestHeader('Content-Type', 'application/json');\nxhr.setRequestHeader('Content-Lengt"
  },
  {
    "path": "JAVASCRIPT/FormData使用方法.md",
    "chars": 1817,
    "preview": "## formData的主要用途有两个\n1. 将form表单元素的name与value进行组合,实现表单数据的序列化,从而减少表单元素的拼接,提高工作效率。\n2. 异步上传文件\n### 具体使用方法\n#### 一、创建formData对象\n"
  },
  {
    "path": "JAVASCRIPT/JavaScript规范.md",
    "chars": 92161,
    "preview": "/**\n* @name: JavaScript规范\n* @author: LIULIU\n* @date: 2020-11-20 11:05\n* @description:JavaScript规范\n* @update: 2020-11-20 "
  },
  {
    "path": "JAVASCRIPT/上传oss.md",
    "chars": 1774,
    "preview": "### 阿里云oss上传步骤\n1. 获取oss token 示例如下\n*  \n```javascript 1.8\nGetOssToken (file) {\n                let _this = this\n         "
  },
  {
    "path": "JAVASCRIPT/下载文件流.md",
    "chars": 2997,
    "preview": "/*导出表格*/\n```javascript 1.8\n      downHandler () {\n          this.downloadBtn = true;\n          let xhr = new XMLHttpRequ"
  },
  {
    "path": "JAVASCRIPT/修改url的某个参数值.md",
    "chars": 333,
    "preview": "## 修改url的某个参数值\n```javascript 1.8\nfunction replaceParamVal(paramName,replaceWith) {\n    var oUrl = this.location.href.toS"
  },
  {
    "path": "JAVASCRIPT/功能性js插件.md",
    "chars": 10135,
    "preview": "## 功能性js\n```javascript 1.8\nimport moment from 'moment'\n\nfunction pluralize (time, label) {\n    if (time === 1) {\n       "
  },
  {
    "path": "JAVASCRIPT/基于vant上传组件oss/服务器.md",
    "chars": 12454,
    "preview": "```javascript 1.8\n<template>\n    <div class=\"uploader-photo\">\n      <van-uploader v-model=\"uploadlist\" multiple :disable"
  },
  {
    "path": "JAVASCRIPT/完美url跳转方式.md",
    "chars": 54,
    "preview": "## 完美url跳转方式\n`window.open().location = “http://-----”`"
  },
  {
    "path": "JAVASCRIPT/常用js代码块.md",
    "chars": 29075,
    "preview": "/**\n* @name: 常用js代码块\n* @author: LIULIU\n* @date: 2020-08-10 14:43\n* @description:常用js代码块\n* @update: 2020-08-10 14:43\n*/\n\n"
  },
  {
    "path": "JAVASCRIPT/数组中的对象去重.md",
    "chars": 1049,
    "preview": "## js中数组对象去重的方法\n\n### 这里有两种方法\n1. 采用对象访问属性的方法,判断属性值是否存在,如果不存在就添加\n2. 采用数组中的reduce方法,遍历数组,也是通过对象访问属性的方法\n``` javascript 1.8\nv"
  },
  {
    "path": "JAVASCRIPT/文件流转为文件.md",
    "chars": 531,
    "preview": "## 文件流转为文件\n```javascript 1.8\ndataURLtoFile (dataurl, filename) {\n                let arr = dataurl.split(',');\n         "
  },
  {
    "path": "JAVASCRIPT/时间与时间戳的转换.md",
    "chars": 3473,
    "preview": "### 时分转当天的时间戳\n```javascript 1.8\ngettime(time){\n    const start = time.split(':')\n    const startime = new Date().setHour"
  },
  {
    "path": "JAVASCRIPT/时间戳转日期.md",
    "chars": 433,
    "preview": "## 时间戳转日期\n```javascript 1.8\nformatDate: function (value) {\n    // value 为毫秒格式\n    let date = new Date(Number(value))\n   "
  },
  {
    "path": "JAVASCRIPT/深度克隆.md",
    "chars": 802,
    "preview": "```javascript 1.8\nclone (obj) {\n    // 处理3种简单类型,null或undefined\n    // Handle the 3 simple types, and null or undefined\n "
  },
  {
    "path": "JAVASCRIPT/深度拷贝.md",
    "chars": 804,
    "preview": "## 深度拷贝\n```javascript\nclone (obj) {\n    // 处理3种简单类型,null或undefined\n    // Handle the 3 simple types, and null or undefin"
  },
  {
    "path": "JAVASCRIPT/滚动加载demo.md",
    "chars": 12927,
    "preview": "## 滚动加载demo\n```vuejs\nScrollLoading.vue(子组件)\n<template>\n    <div class=\"dz-loading-list\">\n        <slot :data=\"data\"></sl"
  },
  {
    "path": "JAVASCRIPT/用递归算法实现,数组长度为5且元素的随机数在2-32间不重复的值.html",
    "chars": 642,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Title</title>\n</head>\n<body>\ndasdas\n</body"
  },
  {
    "path": "JAVASCRIPT/获取当前周每天对应的时间戳.md",
    "chars": 1935,
    "preview": "## 获取当前周 每天对应的时间戳\n```javascript 1.8\n//方法:\n_initSearchTime() {\n    let other = {\n        startTime: '',\n        endTime: "
  },
  {
    "path": "JAVASCRIPT/获取当前月份 第一天 最后一天.md",
    "chars": 367,
    "preview": "### 获取当前月份第一天和最后一天\n```javascript\nvar now = new Date(); //当前日期 \nvar nowMonth = now.getMonth(); //当前月 \nvar nowYear = now.g"
  },
  {
    "path": "Node/NodeJs文档归纳.md",
    "chars": 146,
    "preview": "## NodeJs 文档归纳\n* [你需要了解的有关 Node.js 的所有信息](https://www.imooc.com/article/300129)\n* [Node.js 入门你需要知道的 10 个问题](https://www."
  },
  {
    "path": "Node/Sequelize.md",
    "chars": 547,
    "preview": "## 一. api 文档定义:多对多关系 (Many-to-many association )\n\n\n\n ### 简单使用 - 例子(三表联合查询):\n\n * 第一步: 创建表及关联表\n\n 1、学生表student : id、name、se"
  },
  {
    "path": "Node/express浅尝.md",
    "chars": 1897,
    "preview": "### 官网地址(https://www.expressjs.com.cn/)\n### github(https://github.com/expressjs/expressjs.com)\n```javascript 1.8\n$ npm i"
  },
  {
    "path": "Node/koa浅尝.md",
    "chars": 867,
    "preview": "### 官网地址 (https://koa.bootcss.com/)\n### github (https://github.com/koajs)\n\n#### 创建koa2工程 \n> demo:(https://www.liaoxuefen"
  },
  {
    "path": "Node/现有使用量较大的框架.md",
    "chars": 568,
    "preview": "### 一、框架选择(https://segmentfault.com/a/1190000018973856)\n#### 1、Express\n> github Weekly Downloads: 10,651,670\nExpress是一个最"
  },
  {
    "path": "README.md",
    "chars": 6195,
    "preview": "\n# 工作 学习 总结\n\n收集 总结 一些在开发工作中的所遇到的点滴 ,所涉及的技术栈 包括 css、js、vuejs、react.js、react Native、node.js、redis等前端知识\n\n## 教程文档\n* [易百教程](h"
  },
  {
    "path": "React/React代码规范.md",
    "chars": 5956,
    "preview": "/**\n* @name: React代码规范\n* @author: LIULIU\n* @date: 2020-11-27 11:24\n* @description:React代码规范\n* @update: 2020-11-27 11:24\n"
  },
  {
    "path": "React/常见使用总结.md",
    "chars": 1955,
    "preview": "/**\n* @name: 常见使用总结\n* @author: LIULIU\n* @date: 2020-11-23 10:01\n* @description:常见使用总结\n* @update: 2020-11-23 10:01\n*/\n###"
  },
  {
    "path": "React-Native/APP端消息推送.md",
    "chars": 386,
    "preview": "### 可选择方案\n(极光、TPNS(腾讯云,原名:信鸽)、阿里云、友盟、个推、华为(短信,貌似无APP消息流)、百度云...)\n\n### 方案枚举\n服务器主动push消息到设备端,主要依赖于长连接。不同终端需要各自维护连接的高可用、自我实"
  },
  {
    "path": "React-Native/APP端消息推送之极光推送.md",
    "chars": 3205,
    "preview": "## 选择其原因\n相对接入成本低、成熟度高、文档完善、推送渠道支持多、有自建社区、新版本更新及时、有一定的免费额度。\n\n### [github 地址](https://github.com/jpush/jpush-react-native)"
  },
  {
    "path": "React-Native/ios通过浏览器下载app/方法.md",
    "chars": 1746,
    "preview": "## 通过 itms-services://?action=download-manifest&url=https://xxxxx.plist 链接方式下载\n\n### plist文件(必须为https协议地址)\n```javascript\n"
  },
  {
    "path": "React-Native/使用Promise封装fetch请求.md",
    "chars": 1787,
    "preview": "### 使用Promise封装fetch请求\n```javascript\nlet common_url = 'http://192.168.1.1:8080/';  //服务器地址\nlet token = '';   \n/**\n * @pa"
  },
  {
    "path": "React-Native/使用总结.md",
    "chars": 8854,
    "preview": "### 1、router: react-native-router-flux\n>基于react-navigation/native 二次封装\n### 2、字体图标:react-native-vector-icons(推荐)\n      遇到"
  },
  {
    "path": "Redis/index.md",
    "chars": 889,
    "preview": "* @name: index\n* @author: LIULIU\n* @date: 2020-08-07 09:47\n* @description:index\n* @update: 2020-08-07 09:47\n\n## 什么是redis"
  },
  {
    "path": "Redis/浅尝.md",
    "chars": 6747,
    "preview": "* @name: 浅尝\n* @author: LIULIU\n* @date: 2020-08-07 14:26\n* @description:浅尝\n* @update: 2020-08-07 14:26\n\n## 简单demo\n> 安装下载依"
  },
  {
    "path": "package.json",
    "chars": 516,
    "preview": "{\n  \"name\": \"work-sunnary\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"docs:de"
  },
  {
    "path": "vue/Vue导出页面为PDF、word、html格式.md",
    "chars": 89,
    "preview": "## Vue导出页面为PDF、word、html格式\n转载于链接:<https://blog.csdn.net/pratise/article/details/79249943>"
  },
  {
    "path": "vue/element-audio.md",
    "chars": 69,
    "preview": "## vue 音频播放 audio\n\n转载于(https://github.com/wangduanduan/element-audio)"
  },
  {
    "path": "vue/element-ui/element更改表格表头、行、列、指定单元格样式.md",
    "chars": 93,
    "preview": "## element更改表格表头、行、列、指定单元格样式\n<https://blog.csdn.net/ahrl__/article/details/80805792#comments>"
  },
  {
    "path": "vue/js中使用filter里面的方法.md",
    "chars": 56,
    "preview": "```javascript 1.8\nthis.$options.filters['方法名'](参数)\n````\n"
  },
  {
    "path": "vue/vue 中使用rem.md",
    "chars": 233,
    "preview": "## vue 中使用rem\n```javascript\ndocument.documentElement.style.fontSize = 100 * window.innerWidth/750 + 'px';\nwindow.addEven"
  },
  {
    "path": "vue/vue 项目中如何在页面刷新的状态下保留数据.md",
    "chars": 906,
    "preview": "## vue 项目中如何在页面刷新的状态下保留数据\n### 解决方法: \n\n  * 使用vuex作状态管理: 将vuex里面的数据同步更新到localStorage里面,改变vuex里的数据,便触发localStorage.setItem "
  },
  {
    "path": "vue/vue中怎么重置data?.md",
    "chars": 261,
    "preview": "# vue中怎么重置data?\n初始状态下设置data数据的默认值,重置时直接object.assign(this.$data, this.$options.data())\n\n说明:\nthis.$data获取当前状态下的data\nthis."
  },
  {
    "path": "vue/上传图片oss.md",
    "chars": 7207,
    "preview": "### 上传图片至oss 基于element-ui \n```javascript 1.8\n<template>\n    <div class=\"dz-upload-photo\">\n    <el-upload\n            :mu"
  },
  {
    "path": "vue/上传文件oss.md",
    "chars": 12942,
    "preview": "### 上传文件至oss 基于element-ui \n```javascript 1.8\n<template>\n        <el-upload\n            :multiple=\"false\"\n            cla"
  },
  {
    "path": "vue/如何动态添加页面title 跟 favicon.ico.md",
    "chars": 559,
    "preview": "## 如何动态添加页面title 跟 favicon.ico\n```javascript\n schoolName(newName) {\n                document.title = newName\n           "
  },
  {
    "path": "vue/子组件向父组件传参父组件添加自定义数据.md",
    "chars": 153,
    "preview": "## 子组件向父组件传参父组件添加自定义数据\n```javascript 1.8\n <select-devtype @GetData=\"GetDevtypeData($event,2)\" ></select-devtype>\n```\n$ev"
  },
  {
    "path": "vue/资料文档集合.md",
    "chars": 8215,
    "preview": "/**\n* @name: 资料文档集合\n* @author: LIULIU\n* @date: 2020-11-30 14:26\n* @description:资料文档集合\n* @update: 2020-11-30 14:26\n*/\n\n##"
  },
  {
    "path": "vue/阿里云oss 上传.md",
    "chars": 5900,
    "preview": "## oss 上传\n```JAVASCRIPT 1.8\n<template lang=\"html\">\n  <div class=\"pc-upload\">\n    <el-upload ref=\"upload\" :data=\"formData"
  },
  {
    "path": "vue/页面刷新的时候如何保存store.md",
    "chars": 425,
    "preview": "export default {\n  name: 'App',\n  created () {\n    //在页面加载时读取sessionStorage里的状态信息\n    if (sessionStorage.getItem(\"store\""
  },
  {
    "path": "webpack/日常问题总结.md",
    "chars": 120,
    "preview": "## 项目打包后 路径出现问题\n### 解决方案如下\n* 在 vue.config.js中配置 baseUrl:'./' ===> process.env.BASE_API:'./'\n* 配置 VUE_APP_PUBLIC_PATH=./\n"
  },
  {
    "path": "插件/Canvas 插件(签名板).md",
    "chars": 8555,
    "preview": "\n### canvas 签名板在h5的应用 插件:signature_pad  以下为基于vue vux的使用\n* 组件\n```javascript 1.8\n<template>\n  <div id=\"signature\">\n    <x-"
  },
  {
    "path": "插件/echart.js.md",
    "chars": 90,
    "preview": "## echart.js 封装按需引入\n转载于:<https://github.com/apache/incubator-echarts/blob/master/index.js>"
  },
  {
    "path": "插件/moment.js.md",
    "chars": 64,
    "preview": "## moment.js \nMoment.js 是一个 JavaScript 日期处理类库,用于解析、检验、操作、以及显示日期。"
  },
  {
    "path": "插件/one.md",
    "chars": 118,
    "preview": "## 聚合网址(https://www.juhe.cn/)\n免费向开发者提供全国车辆违章查询API,天气API,基站数据,移动联通基站,电信基站,覆盖国内外1000多个主要城市公共交通信息数据,衣食住行,金融,LBS数据以及其他各种有效"
  },
  {
    "path": "插件/postCSS.md",
    "chars": 165,
    "preview": "### PostCSS\n是一个用 JavaScript 工具和插件转换 CSS 代码的工具\n\n> 利用从 Can I Use 网站获取的数据为 CSS 规则添加特定厂商的前缀。Autoprefixer 自动获取浏览器的流行度和能够支持的属性"
  },
  {
    "path": "数据库/数据库建表规则.md",
    "chars": 885,
    "preview": "/**\n* @name: 数据库建表规则\n* @author: LIULIU\n* @date: 2020-09-25 15:44\n* @description:数据库建表规则\n* @update: 2020-09-25 15:44\n*/\n\n"
  },
  {
    "path": "数据库/设计规范.md",
    "chars": 5551,
    "preview": "/**\n* @name: 设计规范\n* @author: LIULIU\n* @date: 2020-09-25 17:05\n* @description:设计规范\n* @update: 2020-09-25 17:05\n*/\n# 一、命名规"
  },
  {
    "path": "正则/input框只能输入正整数.md",
    "chars": 109,
    "preview": "### input框只能输入正整数\n```javascript 1.8\nonKeypress=\"return(/[\\d]/.test(String.fromCharCode(event.keyCode)))\"\n```\n"
  },
  {
    "path": "正则/文本保存换行 跟空格.md",
    "chars": 96,
    "preview": "this.value.replace(/\\r\\n/g, '<br/>').replace(/\\n/g, '<br/>').replace(/\\s/g, '&nbsp;'),//保存空格 换行\n"
  },
  {
    "path": "温顾而知新/知识点集合.md",
    "chars": 6230,
    "preview": "### 一、页面导入样式时,使用link和@import有什么区别?\n#### 区别:\n1. link是XHTML标签,除了加载CSS外,还可以定义RSS等其他事务;@import属于CSS范畴,只能加载CSS。\n2. link引入的样式页"
  }
]

About this extraction

This page contains the full source code of the xiaoliuxiansheng/work-summary GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 79 files (299.7 KB), approximately 101.5k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!