手动学深度学习-预备知识

预备知识(perliminaries)

这一章主要是安装需要的软件以及jupyter记事本

conda

anaconda

英 [ˌænəˈkɒndə] 美 [ˌænəˈkɑːndə]

n. 水蚺(南美洲蟒蛇)

python原意巨蟒,这个anacoda也是一种蟒,联系还是很巧妙的

adaconda是一个包和依赖的管理工具,类似于node.js的npm

只用安装conda就可以完成各种安装了,不用再单独安装python

minicoda就是anaconda的缩减版

下载地址 —— minicoda

安装jupyter记事本

我们的课本是用jupyter记事本写的,所以我们需要conda安装一下依赖

1
conda env create -f environment.yml

如果觉得国外网站比较慢,可以用国内的源

1
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple

眼前遇到第一个问题,按照流程走,并不能打开jupyter记事本

提示错误为

1
Warning: you have pip-installed dependencies in your environment file, but you do not list pip itself as one of your conda dependencies.  Conda may not use the correct pip to install your packages, and they may end up in the wrong place.  Please add an explicit pip dependency.  I'm adding one for you, but still nagging you.

打开environment.yml看看配置,我理解应该跟package.json类似

1
2
3
4
5
6
7
8
9
name: gluon
dependencies:
- python=3.6
- pip:
- mxnet==1.5.0
- d2lzh==1.0.0
- jupyter==1.0.0
- matplotlib==2.2.2
- pandas==0.23.4

我理解是pip的内容没有安装成功

因为我手动安装是可以完成的

但是眼前知识面太窄了,并不知道比较优雅的做法,只好把pip都手动安装了一下

1
2
3
4
5
pip install mxnet
pip install d2lzh
pip install jupyter
pip install matplotlib
pip install pandas

但是安装mexnet时候numpy出错

1
pip install mxnet

用了各种方法,都过不去,安装numpy的时候出错

单独安装numpy没有问题,但是安装mxnet就报错,今天卡这里了。

后来降级了一下python,用3.7没有问题了,应该是兼容问题,真是麻烦啊。

python7下载

jupyter记事本

启动了jupyter记事本,最大的好处是可以随意的运行页面的代码。

原图——

修改图——

这样可以随意的修改一下字段看看最后输出,对于学习会有很大帮助呢

Dive into deep learning

新的历程

领到了中科院的录取通知书

现在中科院读研,研究“人工智能与应用”。

老师给出了要学习的书籍——

  1. 李沐,《动手学深度学习》,英文版名称:Dive into Deep Learning。Deep Learning for the Layman(为外行准备的深度学习)
  2. 周志华,《机器学习》
  3. 韩家炜,《数据挖掘》
  4. 李航,《统计学习方法》

Dive into deep learning 《手动学深度学习》

这个书籍应该是最简单的一本,并且有在线的,纸质书籍反而是后来出的

中文网址https://zh.d2l.ai/

英文网址http://www.d2l.ai/

前言 pretext

中文

英文

中英文差异

这本书强烈建议中英文一起看,因为有一些差异。

英文不过关的话,可以看了中文之后,再看一下英文版。

眼前来看,英文版比中文版多很多内容。

AI库

mxnet

pytorch

tensorflow

本书主要用的mxnet库,其实用啥库都一样,只要思想正确就行

深度学习简介(Introduction)

所有内容都是我自己理解的,如果有错误,我会回来修改。

第一章,我了解机器学习首先要明白一个问题——

机器学习最重要的是多个样本,然后给出正确样本,机器会分析出正确样本的特征,用来分析新的样本是否正确。

所以,人工智能最重要的是给机器足够多的样本,这样机器可以把正确的方式找出来。

记得之前看《机器学习》(西瓜书)的时候,就有这样的例子,西瓜的成熟,在花纹、瓜秧、声响多个样本中,找出符合好瓜的样本。在多个样本录入之后,就会正确找出好瓜。

所以我现在了解,人工智能首先需要大数据的支持,也就是——

足够多的样本(以及正确样本)

transition 过渡动画

过渡

css3时代,增加了一个transition属性,用处是让变化增加过程

1
2
3
.example {
transition: [transition-property] [transition-duration] [transition-timing-function] [transition-delay];
}

我们来个简单的例子

1
2
3
4
5
6
7
8
9
.box {
transition: background-color 0.5s ease;
background-color: red;
width:100px;
height:100px;
}
.box:hover {
background-color: green;
}

可以用鼠标经过一下下面红色方块,会渐渐变成绿色;移开又会渐渐变回红色。

1
<div class="box">&nbsp;</div>

参数

跟其他css语言类似,transition是四个属性的简写
如果不懂css的简写可以从基础看起,比如margin: [margin-top] [margin-right] [margin-bottom] [margin-left]

1
2
3
.example {
transition: background-color 0.5s ease 200ms;
}

上面的属性详细的写法是下面的

1
2
3
4
5
6
.example {
transition-property: background-color; /* 过渡属性为背景颜色 */
transition-duration: 0.5s; /* 过渡动画持续0.5秒 */
transition-timing-function: ease; /* 过渡时间方法为ease缓动 */
transition-delay: 200ms; /* 动画延迟200毫秒执行 */
}

过渡属性

transition-property

  1. 单一属性

    1
    2
    3
    .example {
    transition-property: background-color; /* 单独写一种css的属性 */
    }
  2. 属性列表,逗号分隔

    1
    2
    3
    .example {
    transition-property: background-color, width, padding; /* 逗号分隔的多种css的属性 */
    }
  3. 关键字,none

    1
    2
    3
    .example {
    transition-property: none; /* 设置为none的时候,没有缓动,可以在需要清除缓动时候做这种赋值处理 */
    }
  4. 关键字,all

    1
    2
    3
    .example {
    transition-property: all; /* 设置为all的时候,所有属性都有缓动,这是默认值 */
    }

持续时间

transition-duration

动画执行的时间,默认值为0s,单位可以用s(秒)和ms(毫秒)

1
2
3
4
5
6
.example {
transition-duration: 0.5s; /* 缓动动画间隔为0.5秒 */
}
.other {
transition-duration: 500ms; /* 缓动动画间隔为500毫秒(其实也就是0.5秒) */
}

延迟时间

transition-delay

动画延迟执行的时间,默认值为0s,单位可以用s(秒)和ms(毫秒)

1
2
3
4
5
6
.example {
transition-delay: 0.5s; /* 缓动动画延迟0.5秒执行 */
}
.other {
transition-delay: 500ms; /* 缓动动画延迟500毫秒(其实也就是0.5秒)执行 */
}

过渡方式

transition-timing-function

缓动系数

  • ease
  • linear
  • ease-in
  • ease-out
  • ease-in-out
缓动系数 图片 贝塞尔 简介
ease 0.25, 0.1, 0.25, 1.0 开始加速运动,结束减速运动直至停止
linear 0.0, 0.0, 1.0, 1.0 速度不变
ease-in 0.42, 0.0, 1.0, 1.0 加速运动
ease-out 0.0, 0.0, 0.58, 1.0 减速运动
ease-in-out 0.42, 0.0, 0.58, 1.0 开始加速运动,结束减速运动直至停止。相当于ease的升级版

可以实际写一下对比一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
.spread {
transition-property: width;
transition-duration: 2s;
background-color: red;
width: 100px;
height: 20px;
color: white;
margin-top: 2px;
}
.spread:hover {
width: 300px;
}
.ease {
transition-timing-function: ease;
}
.linear {
transition-timing-function: linear;
}
.ease-in{
transition-timing-function: ease-in;
}
.ease-out {
transition-timing-function: ease-out;
}
.ease-in-out {
transition-timing-function: ease-in-out;
}

1
2
3
4
5
<div class="spread ease">ease</div>
<div class="spread linear">linear</div>
<div class="spread ease-in">ease-in</div>
<div class="spread ease-out">ease-out</div>
<div class="spread ease-in-out">ease-in-out</div>

贝塞尔曲线

每一个缓动系数都可以用一个贝塞尔曲线来表示

1
2
3
4
.ease-in-out {
transition-timing-function: ease-in-out;
transition-timing-function: cubic-bezier(0.42, 0.0, 0.58, 1.0); /*这个写法等同于ease-in-out*/
}

在chrome等浏览器,在编辑css属性的地方,可以如果是transition-timing-function,点击可以直接进入编辑

你拖动控制杆,就可以在最下面得到你想要的贝塞尔曲线值

步骤

  • step-start
  • step-end

设定动画分几步完成,一般在雪碧图时候要用

参数 图片 简介
steps(2, start) 动画分2步完成,初始状态在开始
steps(4, end) 动画分4步完成,初始状态在结束

这一项其实是单独的,但是也在transition-timing-function里

1
2
3
.ease-in-out {
transition-timing-function: linear steps(2, start);
}

模块开发

目的

把一些常用的公共组件单独拿出来做成npm组件包,可以直接下载使用

好处

  1. 一套组件,多个项目用,减少重复开发
  2. 组件开发和项目开发可以同步进行
  3. 组件可以多个版本轻松升降级

结构

文件 描述
vue.config.js vue-cli配置
.npmignore 发包过滤文件
package.json npm包文件,发布公共组件来说,这里非常重要
packages 模块源文件
┣ popup 弹窗组件
┃ ┣ src 源文件
┃ ┃ ┗ popup.vue 实际文件
┃ ┗ index 引导文件
┣ module 其他的模块都按照popup的方式添加
┗ index.js 主文件,配置加载内容,以及需要依赖
lib 模块(编译后,用来publish)
┣ dayu.umd.js 糅合模式组件
┣ dayu.umd.min.js 糅合模式组件(最小化)
┗ dayu.common.js commonjs模式组件
examples 模块示例,可以理解成以前的src
┣ router 路由
┣ views 页面
┃ ┣ popup.vue 弹窗展示页面
┃ ┗ page 其他页面文件按照都按照popup的方式添加
┣ app.vue
┗ main.js 入口文件
public 公共模板,给examples用的

组件

以前做项目基本就是一个src为源文件,一个dist为生成文件
但是做组件,肯定要有packages为组件源文件,lib为组件的生成文件。可以理解为src和dist,生成组件就是build

1
vue-cli-service build --target lib --name dayu --dest lib packages/index.js

我们创造一个lib,名称为dayu,从packages/index.js文件创造
vue-cli-service的各种命令,可以去官网 https://cli.vuejs.org/zh/guide/cli-service.html#使用命令

示例

examples是示例页面,就是专门做一个页面去调试一下packages的组件
以前dev和build都是编译src的内容,现在build是生成lib组件,dev是新打开一个示例页面去测试lib的组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// examples/main.js
import Vue from 'vue';
import router from './router';
import app from './app';
import dayu from '../packages'; // 载入组件源码

Vue.use(dayu); // 应用组件

Vue.config.productionTip = false;

new Vue({
router,
render: h => h(app)
}).$mount('#app');

因为把src改成了examples,需要修改webpack的配置,我们使用的vue-cli,有专门的vue配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// vue.config.js
const path = require('path');
module.exports = {
pages: { // 将 examples 目录添加为新的页面
index: {
entry: 'examples/main.js', // page 的入口
template: 'public/index.html', // 模板来源
filename: 'index.html' // 输出文件名
}
},
css: { extract: false }, // css文件不分离
configureWebpack: {
resolve: {
alias: {
'@': path.join(__dirname, 'examples') // @的根目录位置从之前的src改成了examples
}
}
}
};

vue.config的各种配置可以看 https://cli.vuejs.org/zh/config/#pages

eslint完整解析

ESLint配置详细解析

我们项目用的vue以及想相关的解析

如果出现下面这样的报错

1
error  Requires a space before '}'  block-spacing

按照最后一个关键词,就可以找到正确的写法

下面就是所有的配置

accessor-pairs

对象中强制配对set和get

1
'accessor-pairs': 2

就是对象中不能设置了set却没有get,但是有get没有set是可以的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 错误
var o = {
set a(value) {
this.val = value;
}
};

// 正确
var o = {
set a(value) {
this.val = value;
},
get a() {
return this.val;
}
};

// 正确
var o = {
get a() {
return this.val;
}
};

space

空格

arrow-spacing

箭头函数前后空格

1
2
3
4
'arrow-spacing': [2, {
'before': true,
'after': true
}]

我们要求箭头函数必须前后有空格

1
2
3
4
5
// { "before": true, "after": true }前后都要有空格
(a) => {}

// { "before": false, "after": false }前后都不能有空格
(a)=>{}

block-spacing

大括号之内的空格或者换行

1
'block-spacing': [2, 'always']

我们要求大括号之内前后必须有空格或者换行

1
2
3
4
5
6
7
8
9
10
11
12
13
// 正确
function foo() { return true; }
if (foo) { bar = 0; }
function baz() {
let i = 0;
return i;
}
// 错误
function foo() {return true;}//两边都没空格
if (foo) { bar = 0;}//右边没空格
function baz() {let i = 0;//左边没有换行或者空格
return i;
}

key-spacing

属性空格

1
2
3
4
'key-spacing': [2, {
'beforeColon': false,
'afterColon': true
}]

默认是属性之前没有空格之后有空格

1
var obj = { "foo": 42 };

keyword-spacing

关键字空格

1
2
3
4
'keyword-spacing': [2, {
'before': true,
'after': true
}]

关键字前后都加空格

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 正确
if (foo) {
//...
} else if (bar) {
//...
} else {
//...
}

//错误
if (foo) {
//...
}else if (bar) {// 关键字else前面没有空格
//...
} else{// 关键字else后面没有空格
//...
}

generator-star-spacing

生成器的星号空格

1
2
3
4
'generator-star-spacing': [2, {
'before': true,
'after': true
}]

我们要求星号前后都有空格

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 正确
function * generator() {
yield "44";
yield "55";
}

// 错误
function* generator() {
yield "44";
yield "55";
}

// 错误
function *generator() {
yield "44";
yield "55";
}

yield-star-spacing

生产的空格

1
'yield-star-spacing': [2, 'both']

生产跟生成器一样两边加空格

1
2
3
4
5
//正确
function * generator() {
yield * other();
}
//错误

no-multi-spaces

多空格

1
'no-multi-spaces': 2

禁止多空格

1
2
3
4
5
6
7
8
9
10
11
12
13
//正确
var a = 1;
if(foo === "bar") {}
a << b
var arr = [1, 2];
a ? b: c

//错误
var a = 1; // 等号右边多了空格
if(foo === "bar") {} // 全等左边多了空格
a << b // 逻辑左移右边两个空格
var arr = [1, 2]; // 数组元素中间多了空格
a ? b: c //?后面多了空格

space-before-blocks

括号前的空格

1
'space-before-blocks': [2, 'always']

括号之前要有空格

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//正确
if (a) {
b();
}
if (a) {
b();
} else{
c();
}
function a() {}
for (;;) {
b();
}
try {} catch(a) {}

//错误
if (a){
b();
}
function a(){}
for (;;){
b();
}
try {} catch(a){}
class Foo{
constructor(){}
}

space-before-function-paren

函数空格

1
'space-before-function-paren': [2, 'never']

定义函数函数的括号之前不写空格

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
//正确
function foo() {
// ...
}
var bar = function() {
// ...
};
var bar = function foo() {
// ...
};
class Foo {
constructor() {
// ...
}
}
var foo = {
bar() {
// ...
}
};
var foo = async() => 1;

//错误
function foo () {
// ...
}
var bar = function () {
// ...
};
var bar = function foo () {
// ...
};
class Foo {
constructor () {
// ...
}
}
var foo = {
bar () {
// ...
}
};
var foo = async () => 1;

no-spaced-func

函数空白

1
'no-spaced-func': 2

函数间不要有任何空白

1
2
3
4
5
6
7
8
//正确
fn()

//错误
fn ()

fn
()

padded-blocks

声明中的空白

1
'padded-blocks': [2, 'never']

声明中不要有空白

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//正确
if (a) {
b();
}

//错误
if (a) {

b();

}
if (a) {

b();
}
if (a) {
b();

}

no-trailing-spaces

句尾空格

1
'no-trailing-spaces': 2

禁止在句尾也就是分号之后加空格

1
2
3
//错误
var foo = 0;//•••••
var baz = 5;//••

eol-last

页面结尾

1
'eol-last': 2

页面的结尾必须有一个空行

1
2
3
4
// 正确
function doSmth() {
var foo = 2;
}\n

brace-style

括号样式

1
2
3
'brace-style': [2, '1tbs', {
'allowSingleLine': true
}]

我们设置1tbs的的样式,以及允许单行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// 正确
function foo() {
return true;
}

if (foo) {
bar();
}

if (foo) {
bar();
} else {
baz();
}

try {
somethingRisky();
} catch(e) {
handleError();
}

// 没有大括号,没有问题
if (foo) bar();
else if (baz) boom();

// 允许单行
function nop() { return; }

if (foo) { bar(); }

if (foo) { bar(); } else { baz(); }

try { somethingRisky(); } catch(e) { handleError(); }

//错误
function foo()
{// 大括号开始需要跟方法同一行
return true;
}

if (foo)
{// 大括号开始需要跟控制同一行
bar();
}

try
{ // 大括号开始需要跟控制同一行
somethingRisky();
} catch(e)
{ // 大括号开始需要跟捕获同一行
handleError();
}

if (foo) {
bar();
}// 大括号结束需要跟后续同一行
else {
baz();
}

camelcase

驼峰样式

1
2
3
'camelcase': [0, {
'properties': 'always'
}]

我们关闭了规则,虽然建议大家都要用驼峰命名变量,但是有时候我们引用的module不是驼峰的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import { no_camelcased as camelCased } from "external-module";

var myFavoriteColor = "#112C85";
var _myFavoriteColor = "#112C85";
var myFavoriteColor_ = "#112C85";
var MY_FAVORITE_COLOR = "#112C85";
var foo = bar.baz_boom;
var foo = { qux: bar.baz_boom };

obj.do_something();
do_something();
new do_something();

var { category_id: category } = query;

function foo({ isCamelCased }) {
// ...
};

function foo({ isCamelCased: isAlsoCamelCased }) {
// ...
}

function foo({ isCamelCased = 'default value' }) {
// ...
};

var { categoryId = 1 } = query;

var { foo: isCamelCased } = bar;

var { foo: isCamelCased = 1 } = quz;

comma

逗号

comma-dangle

尾部逗号,区别于默认

1
'comma-dangle': [1, 'never']

数组或者对象,尾部是不能有逗号的,但是为了方便调试,我们只是设置了警告,没有限定为错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 正确
var foo = {
bar: "baz",
qux: "quux"
};

var arr = [1,2];

foo({
bar: "baz",
qux: "quux"
});

// 错误
var foo = {
bar: "baz",
qux: "quux",
};

var arr = [1,2,];

foo({
bar: "baz",
qux: "quux",
});

comma-spacing

逗号空格

1
2
3
4
'comma-spacing': [2, {
'before': false,
'after': true
}]

我们设置的为逗号之前不能有空格,之后必须有空格

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 正确
var foo = 1, bar = 2;
var arr = [1, 2];
var obj = {"foo": "bar", "baz": "qur"};
foo(a, b);
new Foo(a, b);
function foo(a, b){}

// 错误
var foo = 1 ,bar = 2;
var arr = [1 , 2];
var obj = {"foo": "bar" ,"baz": "qur"};
foo(a ,b);
new Foo(a ,b);
function foo(a ,b){}

comma-style

逗号样式

1
'comma-style': [2, 'last']

每个单元以逗号结尾

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// 正确
var foo = 1, bar = 2;

var foo = 1,
bar = 2;

var foo = ["apples",
"oranges"];

function bar() {
return {
"a": 1,
"b:": 2
};
}

// 错误
var foo = 1
,
bar = 2;

var foo = 1
, bar = 2;

var foo = ["apples"
, "oranges"];

function bar() {
return {
"a": 1
,"b:": 2
};
}

regular

正则表达式

no-control-regex

正则字节控制

1
'no-control-regex': 0

正常来说使用的正则字节是ascii(0-31),但是现在后续多了很多,尤其是要用中文,所以我们关掉了这个

1
2
var pattern1 = /\x1f/; //16进制1f就是10进制的31
var pattern2 = new RegExp("\x1f");

no-empty-character-class

禁止空字节

1
'no-empty-character-class': 2

正则表达式中不要有空字节

1
2
3
4
5
6
7
8
9
10
// 正确
/^abc/.test("abcdefg"); // true
"abcdefg".match(/^abc/); // ["abc"]

/^abc[a-z]/.test("abcdefg"); // true
"abcdefg".match(/^abc[a-z]/); // ["abcd"]

// 错误
/^abc[]/.test("abcdefg"); // false
"abcdefg".match(/^abc[]/); // null

no-invalid-regexp

无效的正则

1
'no-invalid-regexp': 2

错误的正则只有在执行时候才会报错,定义时候不会,所以我们加入验证

1
2
3
4
5
6
7
8
9
// 正确
RegExp('.');
new RegExp;
this.RegExp('[');

// 错误
RegExp('[');
RegExp('.', 'z');
new RegExp('\\');

no-regex-spaces

正则空格

1
'no-regex-spaces': 2

禁止直接输入数量的空格,如果有请用{}定义数字

1
2
3
4
5
6
7
//正确
var re = /foo {3}bar/;
var re = new RegExp("foo {3}bar");

//错误
var re = /foo bar/;
var re = new RegExp("foo bar");

class

constructor-super

构造时候使用超类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 正确
class A {
constructor() { }
}

class A extends B {
constructor() {
super();
}
}

// 错误
class A {
constructor() {
super(); // 语法错误,因为没有继承
}
}

class A extends B {
constructor() { } // 需要超类
}

new-cap

类首字母大写

1
2
3
4
'new-cap': [2, {
'newIsCap': true,
'capIsNew': false
}]

默认为首字母大写

1
2
3
4
5
// 正确
var friend = new Person();
var friend = Person(); //并没有要求必须new
// 错误
var friend = new person();// 类需要首字母大写

new-parens

插入语

1
'new-parens': 2

js里,new一个类,如果没有参数,可以不写后面的括号的,但是别的语言都不行,所以统一一下

1
2
3
4
5
6
7
8
// 正确
var person = new Person();
var person = new (Person)();
var person = new Person("Name");

// 错误
var person = new Person;
var person = new (Person);

no-class-assign

类重定义

1
'no-class-assign': 2

class的方式定义的类,不要再重新定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 错误
class A { }
A = 0;

A = 0;
class A { }

class A {
b() {
A = 0;
}
}

let A = class A {
b() {
A = 0;
}
}

no-dupe-class-members

重复方法

1
'no-dupe-class-members': 2

不要再类里定义重复的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 错误
class Foo {
bar() { }
bar() { }
}

class Foo {
bar() { }
get bar() { }
}

class Foo {
static bar() { }
static bar() { }
}

no-dupe-keys

重复键

1
'no-dupe-keys': 2

不要定义重复的键

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 正确

// 错误
var foo = {
bar: "baz",
bar: "qux"
};

var foo = {
"bar": "baz",
bar: "qux"
};

var foo = {
0x1: "baz",
1: "qux"
};

curly

圆括号

1
'curly': [2, 'multi-line']

函数或者控制可以单行没有大括号,多行需要大括号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// 正确
if (foo) foo++; else doSomething();

if (foo) foo++;
else if (bar) baz()
else doSomething();

do something();
while (foo);

while (foo
&& bar) baz();

if (foo) {
foo++;
}

if (foo) { foo++; }

while (true) {
doSomething();
doSomethingElse();
}

// 错误
if (foo)
doSomething();
else
doSomethingElse();

if (foo) foo(
bar,
baz);

dot-location

圆点

1
'dot-location': [2, 'property']

属性为主体,圆点跟属性作为一个整体

1
2
3
4
5
6
7
8
// 正确
var foo = object
.property;
var bar = object.property;

//错误
var foo = object.
property;

eqeqeq

等式,专门应对不正确的等式类型

1
'eqeqeq': [2, 'allow-null']

我们要求必须同时应对类型,并且允许为空

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 正确
a === b
foo === true
bananas !== 1
value === undefined
typeof foo === 'undefined'
'hello' !== 'world'
0 === 0
true === true
foo === null

// 错误
a == b
foo == true
bananas != 1
value == undefined
typeof foo == 'undefined'
'hello' != 'world'
0 == 0
true == true
foo == null

可能你会觉得很多地方就是要数字和字符串都适用,那么做个处理就行了

1
2
3
code == 200 // 常用的判断request的code,但是有时候给的是数字有时候给的字符串
code === 200 || code === "200" // 我们加上一个字符串的判断就可以了
parseInt( code ) === 200 // 或者专门吧code转化成数字,但是注意一下,字符串不能做16进制的转换,碰上非数字,后面的内容就会丢失

handle-callback-err

错误回调

1
'handle-callback-err': [2, '^(err|error)$']

有错误的话要有抛出操作,就是参数一旦有“err”或者“error”一定要针对这个错误做特殊处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 正确
function loadData (err, data) {
if (err) {
console.log(err.stack);
}
doSomething();
}

function generateError (err) {
if (err) {}
}

// 错误
function loadData (err, data) {
doSomething(); // 没做错误处理
}

indent

缩进

indent

缩进

1
2
3
'indent': [2, 2, {
'SwitchCase': 1
}]

建议使用两个空格,理由是

  • 用两个空格的人很多,并且在逐渐增加
  • 层级多了,也只是一层2个,不会让横向过长
    1
    2
    3
    4
    5
    6
    7
    8
    9
    if(true){
    console.log("exec");
    }
    switch(a){
    case "a":
    break;
    case "b":
    break;
    }

no-mixed-spaces-and-tabs

空格和tabs混排

1
'no-mixed-spaces-and-tabs': 2

禁止空格和tabs混排

1
2
3
4
5
6
7
8
9
//正确
function add(x, y) {
return x + y;
}

//错误
function add(x, y) {
/*tab*/return x + y;
}

jsx-quotes

标签引号

1
'jsx-quotes': [2, 'prefer-single']

标签引号请用单引号

1
2
3
4
5
6
<!-- 正确 -->
<a b='c' />
<a b="'" />

<!-- 错误 -->
<a b="c" />

array

数组

no-array-constructor

数组构造

1
'no-array-constructor': 2

数组构造时候可以使用长度作为参数,也可以使用数组中的元素作为参数

但是这样会有冲突,如果数组中只放了一个数字,那么是长度还是元素呢?
所以我们禁止使用元素作为参数构造

1
2
3
4
5
6
7
// 正确
Array(500);
new Array(someOtherArray.length);

// 错误
Array(0, 1, 2);
new Array(0, 1, 2);

no-sparse-arrays

数组空元素

1
'no-sparse-arrays': 2

禁止设置数组的空元素

1
2
3
4
5
6
//正确
var colors = [ "red", "blue", ]; // 结尾有个逗号不是语法错误

//错误
var items = [,];
var colors = [ "red",, "blue" ];

no-caller

隐含参数

1
'no-caller': 2

未来版本会去除这个,并且在es5的严格模式中不能用,所以我们禁止

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 正确
function foo(n) {
if (n <= 0) {
return;
}
foo(n - 1);
}
[1,2,3,4,5].map(function factorial(n) {
return !(n > 1) ? 1 : factorial(n - 1) * n;
});

// 错误
function foo(n) {
if (n <= 0) {
return;
}
arguments.callee(n - 1);
}
[1,2,3,4,5].map(function(n) {
return !(n > 1) ? 1 : arguments.callee(n - 1) * n;
});

no-console

输出

1
'no-console': 'off'

虽然是关闭状态,但是最好做完一个阶段之后去掉输出

no-cond-assign

条件定义变量

1
'no-cond-assign': 2

不要再条件里面定义变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 正确
var x;
if (x === 0) {
var b = 1;
}
function setHeight(someNode) {
"use strict";
do {
someNode.height = "100px";
} while ((someNode = someNode.parentNode) !== null);
}


// 错误
var x;
if (x = 0) {
var b = 1;
}

function setHeight(someNode) {
"use strict";
do {
someNode.height = "100px";
} while (someNode = someNode.parentNode);
}

no-const-assign

常量定义

1
'no-const-assign': 2

不要给常量再赋值

1
2
3
// 错误
const a = 0;
a = 1;

no-delete-var

删除变量

1
'no-delete-var': 2

delete是用来删除属性的,如果删除变量会有非预期的错误

1
2
3
4
5
6
7
// 正确
let obj = { a:1 };
delete obj.a; //这时候obj是{},没有了a属性

// 错误
var x;
delete x;

no-dupe-args

重复参数

1
'no-dupe-args': 2

不要再函数中定义重复的参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 正确
function foo(a, b, c) {
console.log(a, b, c);
}
var bar = function (a, b, c) {
console.log(a, b, c);
};

// 错误
function foo(a, b, a) {
console.log("value of the second a:", a);
}
var bar = function (a, b, a) {
console.log("value of the second a:", a);
};

no-duplicate-case

相同的case

1
'no-duplicate-case': 2

不要设置相同的case

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// 正确
switch (a) {
case one:
break;
case 2:
break;
case 3:
break;
default:
break;
}

// 错误
var a = 1,
one = 1;

switch (a) {
case 1: // 重复
break;
case 2:
break;
case 1: // 重复
break;
default:
break;
}

switch (a) {
case one: // 重复
break;
case 2:
break;
case one: // 重复
break;
default:
break;
}

switch (a) {
case "1": // 重复
break;
case "2":
break;
case "1": // 重复
break;
default:
break;
}

no-empty-pattern

空匹配

1
'no-empty-pattern': 2

禁止空匹配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 正确
var {a = {}} = foo; // 创建变量a
var {a = []} = foo;
function foo({a = {}}) {}
function foo({a = []}) {}

// 错误
var {} = foo;
var [] = foo;
var {a: {}} = foo; // 不会创建任何变量
var {a: []} = foo;
function foo({}) {}
function foo([]) {}
function foo({a: {}}) {}
function foo({a: []}) {}

no-eval

转化执行

1
'no-eval': 2

禁止使用eval

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 正确
var obj = { x: "foo" },
key = "x",
value = obj[key];

// 错误
var obj = { x: "foo" },
key = "x",
value = eval("obj." + key);

(0, eval)("var a = 0");

var foo = eval;
foo("var a = 0");

this.eval("var a = 0");

no-ex-assign

抛出异常定义

1
'no-ex-assign': 2

禁止冲定义抛出的异常

1
2
3
4
5
6
7
8
9
10
11
12
13
// 正确
try {
// code
} catch (e) {
var foo = 10;
}

// 错误
try {
// code
} catch (e) {
e = 10;
}

no-extend-native

原生扩展

1
'no-extend-native': 2

禁止原生扩展

1
2
3
// 错误
Object.prototype.a = "a";
Object.defineProperty(Array.prototype, "times", { value: 999 });

因为如果做了原生扩展,所有的用到这个原生的内容都会有问题,比如

1
2
3
4
5
6
7
8
9
10
11
Object.prototype.extra = 55;

var users = {
"123": "Stan",
"456": "David"
};

// 您并没有做别的
for (var id in users) {
console.log(id); // console的为:"123", "456", "extra",因为你在原生Object里增加了一个extra
}

no-extra-bind

绑定

1
'no-extra-bind': 2

禁止多余的绑定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// 正确
var x = function () {
this.foo();
}.bind(bar);

var x = function (a) {
return a + 1;
}.bind(foo, bar);

// 错误
var x = function () {
foo();
}.bind(bar);

var x = (() => {
foo();
}).bind(bar);

var x = (() => {
this.foo();
}).bind(bar);

var x = function () {
(function () {
this.foo();
}());
}.bind(bar);

var x = function () {
function foo() {
this.bar();
}
}.bind(baz);

no-extra-boolean-cast

额外的按位计算

1
'no-extra-boolean-cast': 2

禁止额外的布尔操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// 正确
var foo = !!bar;
var foo = Boolean(bar);

function foo() {
return !!bar;
}

var foo = bar ? !!baz : !!bat;

// 错误
var foo = !!!bar;

var foo = !!bar ? baz : bat;

var foo = Boolean(!!bar);

var foo = new Boolean(!!bar);

if (!!foo) {
// ...
}

if (Boolean(foo)) {
// ...
}

while (!!foo) {
// ...
}

do {
// ...
} while (Boolean(foo));

for (; !!foo; ) {
// ...
}

no-extra-parens

1
'no-extra-parens': [2, 'functions']

禁止额外的插入

1
2
3
4
5
6
7
8
9
10
11
12
13
// 正确
(0).toString();
(Object.prototype.toString.call());
({}.toString.call());
(function(){} ? a() : b());
(/^a$/).test(x);
a = (b * c);
(a * b) + c;
typeof (a);

// 错误
((function foo() {}))();
var y = (function () {return 1;});

no-fallthrough

抛出

1
'no-fallthrough': 2

禁止switch无抛出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// 正确
switch(foo) {
case 1:
doSomething();
break;
case 2:
doSomething();
}

function bar(foo) {
switch(foo) {
case 1:
doSomething();
return;
case 2:
doSomething();
}
}

switch(foo) {
case 1:
doSomething();
throw new Error("Boo!");
case 2:
doSomething();
}

switch(foo) {
case 1:
case 2:
doSomething();
}

switch(foo) {
case 1:
doSomething();
// 其他抛出

case 2:
doSomething();
}

// 错误
switch(foo) {
case 1:
doSomething();
case 2:
doSomething();
}

no-floating-decimal

浮点小数

1
'no-floating-decimal': 2

虽然有简写的方式,但是请用完整的方式写小数

1
2
3
4
5
6
7
8
9
// 正确
var num = 0.5;
var num = 2.0;
var num = -0.7;

// 错误
var num = .5;
var num = 2.;
var num = -.7;

no-func-assign

函数重定义

1
'no-func-assign': 2

不要给函数重定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 正确
var foo = function () {}
foo = bar;

function foo(foo) { // `foo` is shadowed.
foo = bar;
}

function foo() {
var foo = bar; // `foo` is shadowed.
}

// 错误
function foo() {}
foo = bar;

function foo() {
foo = bar;
}
foo = bar;
function foo() {}

no-implied-eval

隐eval

1
'no-implied-eval': 2

需要避免所有使用eval的地方

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 正确
setTimeout(function() {
alert("Hi!");
}, 100);

setInterval(function() {
alert("Hi!");
}, 100);

// 错误
setTimeout("alert('Hi!');", 100);
setInterval("alert('Hi!');", 100);
execScript("alert('Hi!')");
window.setTimeout("count = 5", 10);
window.setInterval("foo = bar", 10);

no-inner-declarations

内部定义

1
'no-inner-declarations': [2, 'functions']

不要使用内部定义,会有异步的隐患

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 正确
function doSomething() { }

function doSomethingElse() {
function doAnotherThing() { }
}

if (test) {
asyncCall(id, function (err, data) { });
}

var fn;
if (test) {
fn = function fnExpression() { };
}

// 错误
if (test) {
function doSomething() { }
}

function doSomethingElse() {
if (test) {
function doAnotherThing() { }
}
}

no-irregular-whitespace

不合法的空白

1
'no-irregular-whitespace': 2

不要用不合法的空白

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
\u000B - Line Tabulation (\v) - <VT>
\u000C - Form Feed (\f) - <FF>
\u00A0 - No-Break Space - <NBSP>
\u0085 - Next Line
\u1680 - Ogham Space Mark
\u180E - Mongolian Vowel Separator - <MVS>
\ufeff - Zero Width No-Break Space - <BOM>
\u2000 - En Quad
\u2001 - Em Quad
\u2002 - En Space - <ENSP>
\u2003 - Em Space - <EMSP>
\u2004 - Tree-Per-Em
\u2005 - Four-Per-Em
\u2006 - Six-Per-Em
\u2007 - Figure Space
\u2008 - Punctuation Space - <PUNCSP>
\u2009 - Thin Space
\u200A - Hair Space
\u200B - Zero Width Space - <ZWSP>
\u2028 - Line Separator
\u2029 - Paragraph Separator
\u202F - Narrow No-Break Space
\u205f - Medium Mathematical Space
\u3000 - Ideographic Space

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// 正确
function thing() {
return ' <NBSP>thing';
}
function thing() {
return '​<ZWSP>thing';
}
function thing() {
return 'th <NBSP>ing';
}

// 错误
function thing() /*<NBSP>*/{
return 'test';
}

function thing( /*<NBSP>*/){
return 'test';
}

function thing /*<NBSP>*/(){
return 'test';
}

function thing᠎/*<MVS>*/(){
return 'test';
}

function thing() {
return 'test'; /*<ENSP>*/
}

function thing() {
return 'test'; /*<NBSP>*/
}

function thing() {
// Description <NBSP>: some descriptive text
}

/*
Description <NBSP>: some descriptive text
*/

function thing() {
return / <NBSP>regexp/;
}

/*eslint-env es6*/
function thing() {
return `template <NBSP>string`;
}

no-iterator

迭代器

1
'no-iterator': 2

不要自定义迭代器的属性,未来会有迭代器

1
2
3
4
5
6
7
8
9
// 正确
var __iterator__ = foo; // Not using the `__iterator__` property.

// 错误
Foo.prototype.__iterator__ = function() {
return new FooIterator(this);
};
foo.__iterator__ = function () {};
foo["__iterator__"] = function () {};

no-label-var

函数标签

1
'no-label-var': 2

不要把函数标签跟变量冲突

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 正确
function foo() {
var q = t;
}
function bar() {
q:
for(;;) {
break q;
}
}

// 错误
var x = foo;
function bar() {
x:
for (;;) {
break x;
}
}

no-labels

标签

1
2
3
4
'no-labels': [2, {
'allowLoop': false,
'allowSwitch': false
}]

循环和switch不要设置标签

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// 正确
var f = {
label: "foo"
};
while (true) {
break;
}
while (true) {
continue;
}

// 错误
label:
while(true) {
// ...
}

label:
while(true) {
break label;
}

label:
while(true) {
continue label;
}

label:
switch (a) {
case 0:
break label;
}

label:
{
break label;
}

label:
if (a) {
break label;
}

no-lone-blocks

空闭包

1
'no-lone-blocks': 2

不要使用空闭包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
//正确
while (foo) {
bar();
}
if (foo) {
if (bar) {
baz();
}
}
function bar() {
baz();
}
{
let x = 1;
}
{
const y = 1;
}
{
class Foo {}
}
aLabel: {
}

//错误
{}
if (foo) {
bar();
{
baz();
}
}
function bar() {
{
baz();
}
}
{
function foo() {}
}
{
aLabel: {
}
}

no-multi-str

换行字符串

1
'no-multi-str': 2

换行请用\n,不要用格式的字符串,很可能除了换行多了很多别的东西

1
2
3
4
5
6
7
//正确
var x = "Line 1\n" +
"Line 2";

//错误
var x = "Line 1 \
Line 2";

no-multiple-empty-lines

空行

1
2
3
'no-multiple-empty-lines': [2, {
'max': 1
}]

禁止空行超过1

1
2
3
4
5
6
7
8
9
10
//正确
var foo = 5;
// 一行
var bar = 3;

//错误
var foo = 5;
// 超过了一行

var bar = 3;

no-native-reassign

原生定义

1
'no-native-reassign': 2

不要重定义环境

1
2
3
4
5
6
//错误
Object = null;
undefined = 1;
window = {};
length = 1;
top = 1;

no-negated-in-lhs

负运算

1
'no-negated-in-lhs': 2

非应该优先级最高,但是低于in表达式

1
2
3
4
5
6
7
8
9
10
11
12
//正确
if(!(key in object)) {
// key不在object对象中
}
if(('' + !key) in object) {
// 括号的优先级永远最高,但是key需要是字符串,所以需要转化成字符串
}

//错误
if(!key in object) {
// 这个实际是(key in object),但是大部分人看来认为是非key在object
}

no-new-object

new定义object

1
'no-new-object': 2

使用{}定义object比new Object()写的更方便

1
2
3
4
5
6
7
//正确
var myObject = new CustomObject();
var myObject = {};

//错误
var myObject = new Object();
var myObject = new Object;

no-new-require

new定义require

1
'no-new-require': 2

禁止require的module直接new

1
2
3
4
5
6
//正确
var AppHeader = require('app-header');
var appHeader = new AppHeader();

//错误
var appHeader = new require('app-header');

no-new-symbol

symbol类

1
'no-new-symbol': 2

symbol是一个function并且不带构造

1
2
3
4
5
//正确
var foo = Symbol('foo');

//错误
var foo = new Symbol('foo');

no-new-wrappers

包装对象

1
'no-new-wrappers': 2

不需要构造的类型,都直接用函数方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//正确
var text = String(someValue);
var num = Number(someValue);

var object = new MyString();

//错误
var stringObject = new String("Hello world");
var numberObject = new Number(33);
var booleanObject = new Boolean(false);

var stringObject = new String;
var numberObject = new Number;
var booleanObject = new Boolean;

no-obj-calls

非函数类

1
'no-obj-calls': 2

全局类不要用函数方式调用

1
2
3
4
5
6
7
8
9
10
11
//正确
function area(r) {
return Math.PI * r * r;
}
var object = JSON.parse("{}");
var value = Reflect.get({ x: 1, y: 2 }, "x");

//错误
var math = Math();
var json = JSON();
var reflect = Reflect();

no-octal

十进制数的导零

1
'no-octal': 2

禁止十进制数用导零

1
2
3
4
5
6
//正确
var num = "071";

//错误
var num = 071;
var result = 5 + 07;

no-octal-escape

十进制转义

1
'no-octal-escape': 2

禁止十进制转义

1
2
3
4
5
6
//正确
var foo = "Copyright \u00A9"; // unicode码
var foo = "Copyright \xA9"; // 十六进制

//错误
var foo = "Copyright \251"; // 十进制

no-path-concat

地址链接

1
'no-path-concat': 2

禁止直接把地址做链接

1
2
3
4
5
6
7
8
//正确
var fullPath = dirname + "/foo.js";
var fullPath = path.join(__dirname, "foo.js");
var fullPath = path.resolve(__dirname, "foo.js");

//错误
var fullPath = __dirname + "/foo.js";
var fullPath = __filename + "/foo.js";

no-proto

原型

1
'no-proto': 2

禁止直接操作或者定义原型

1
2
3
4
5
6
7
8
9
10
//正确
var a = Object.getPrototypeOf(obj);
Object.setPrototypeOf(obj, b);
var c = { __proto__: a };

//错误
var a = obj.__proto__;
var a = obj["__proto__"];
obj.__proto__ = b;
obj["__proto__"] = b;

no-redeclare

变量重生命

1
'no-redeclare': 2

禁止变量重复声明

1
2
3
//错误
var a = 3;
var a = 10;

no-return-assign

返回定义

1
'no-return-assign': [2, 'except-parens']

禁止在返回时候做定义

1
2
3
4
5
6
7
//错误
function doSomething() {
return foo = bar + 2;
}
function doSomething() {
return foo += 2;
}

no-self-assign

自定义

1
'no-self-assign': 2

禁止自己给自己定义

1
2
3
4
5
//错误
foo = foo;
[a, b] = [a, b];
[a, ...b] = [x, ...b];
({a, b} = {a, x});

no-self-compare

自比较

1
'no-self-compare': 2

禁止自己跟自己比较

1
2
3
4
5
//错误
var x = 10;
if (x === x) {
x = 20;
}

no-sequences

序列

1
'no-sequences': 2

禁止逗号操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//正确
foo = (doSomething(), val);
(0, eval)("doSomething();");
do {} while ((doSomething(), !!test));
for (i = 0, j = 10; i < j; i++, j--);
if ((doSomething(), !!test));
switch ((val = foo(), val)) {}
while ((val = foo(), val < 42));

//错误
foo = doSomething(), val;
0, eval("doSomething();");
do {} while (doSomething(), !!test);
for (; doSomething(), !!test; );
if (doSomething(), !!test);
switch (val = foo(), val) {}
while (val = foo(), val < 42);
with (doSomething(), val) {}

no-shadow-restricted-names

严格命名

1
'no-shadow-restricted-names': 2

禁止使用预留字段命名

1
2
3
4
5
//错误
function NaN(){}
!function(Infinity){};
var undefined = 5;
try {} catch(eval){}

no-this-before-super

this在超类之前

1
'no-this-before-super': 2

禁止在超类之前使用this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
//正确
class A {
constructor() {
this.a = 0; // OK, 没有继承也就没有super
}
}
class A extends B {
constructor() {
super();
this.a = 0; // OK, 成员变量赋值在super之后.
}
}
class A extends B {
foo() {
this.a = 0; // OK. 使用this的作用域不是构造.
}
}

//错误
class A extends B {
constructor() {
this.a = 0; // super之前赋值成员变量
super();
}
}
class A extends B {
constructor() {
this.foo(); // super之前调用方法
super();
}
}
class A extends B {
constructor() {
super.foo(); // super之前调用静态方法
super();
}
}
class A extends B {
constructor() {
super(this.foo()); // 参数传递之前并未super
}
}

no-throw-literal

抛出异常

1
'no-throw-literal': 2

抛出错误需要是Error

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//正确
throw new Error();

throw new Error("error");

var e = new Error("error");
throw e;

try {
throw new Error("error");
} catch (e) {
throw e; // catch的参数就是Error类
}

//错误
throw "error";
throw 0;
throw undefined;
throw null;
var err = new Error();
throw "an " + err;
// err is recast to a string literal
var err = new Error();
throw `${err}`

no-undef

未定义变量

1
'no-undef': 2

禁止使用未定义变量

1
2
//错误
b = 10; // 变量b没有定义,严格模式下语法错误

no-undef-init

未定义赋值

1
'no-undef-init': 2

禁止赋值为undefined

1
2
3
4
5
6
7
8
//正确
var foo;
let bar;
const baz = undefined;

//错误
var foo = undefined;
let bar = undefined;

no-unexpected-multiline

多行

1
'no-unexpected-multiline': 2

禁止不必要的多行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//正确
var foo = bar;
(1 || 2).baz();

var foo = bar
;(1 || 2).baz()

var hello = 'world';
[1, 2, 3].forEach(addNumber);

var hello = 'world'
void [1, 2, 3].forEach(addNumber);

let x = function() {};
`hello`

let tag = function() {}
tag `hello`

//错误
var foo = bar
(1 || 2).baz();

var hello = 'world'
[1, 2, 3].forEach(addNumber);

let x = function() {}
`hello`

let x = function() {}
x
`hello`

let x = foo
/regex/g.test(bar)

no-unmodified-loop-condition

循环中未修改的条件

1
'no-unmodified-loop-condition': 2

禁止循环中出现未修改的条件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//正确
while (node) {
doSomething(node);
node = node.parent;
}
for (var j = 0; j < items.length; ++j) {
doSomething(items[j]);
}
while (node !== root) {
doSomething(node);
node = node.parent; // node在循环中改变
}
while (node ? A : B) {
doSomething(node);
node = node.parent; // 三元表达式在循环中改变
}
while (obj.foo) {
doSomething(obj); // doSomething函数可能修改obj的foo属性
}
while (check(obj)) { // check函数可能返回多样的值
doSomething(obj);
}

//错误
while (node) {
doSomething(node);
}
node = other; // 条件在循环外改变

for (var j = 0; j < items.length; ++i) { // 条件j和items没有在循环中改变
doSomething(items[j]);
}
while (node !== root) { // 条件node和root没有在循环中改变
doSomething(node);
}

no-unneeded-ternary

不必要的三元表达式

1
2
3
'no-unneeded-ternary': [2, {
'defaultAssignment': false
}]

禁止不必要的三元表达式

1
2
3
4
5
6
7
8
9
10
11
//正确
var a = x === 2 ? "Yes" : "No";
var a = x !== false;
var a = x ? "Yes" : "No";
var a = x ? y : x;
var a = x ? x : 1;

//错误
var a = x === 2 ? true : false; // 直接写 var a = x === 2 就行了
var a = x ? true : false; // 直接写 var a = x 就行了
var a = f(x ? x : 1); // 直接写 f(x || 1) 就行了

no-unreachable

未到达

1
'no-unreachable': 2

禁止未到达部分还有表达式,比如return、throw、break、continue之后的表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//错误
function foo() {
return true;
console.log("done");
}

function bar() {
throw new Error("Oops!");
console.log("done");
}

while(value) {
break;
console.log("done");
}

throw new Error("Oops!");
console.log("done");

function baz() {
if (Math.random() < 0.5) {
return;
} else {
throw new Error();
}
console.log("done");
}

no-unsafe-finally

不安全的finally

1
'no-unsafe-finally': 2

禁止在finally中使用 return、throw、break 和 continue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//正确

//错误
let foo = function() {
try {
return 1;
} catch(err) {
return 2;
} finally {
return 3;
}
};
let foo = function() {
try {
return 1;
} catch(err) {
return 2;
} finally {
throw new Error;
}
};

no-unused-vars

未使用的变量

1
2
3
4
'no-unused-vars': [1, {
'vars': 'local',
'args': 'none'
}]

未使用的变量,我们为了方便调试,因为很多时候我们预先留好参数,修改了级别为警告

1
2
3
4
//错误
(function(a, b, c) { // c没有使用
return a + b;
})(1, 2);

no-useless-call

不必要的调用

1
'no-useless-call': 2

禁止不必要的call和apply

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//正确
foo.call(obj, 1, 2, 3);
foo.apply(obj, [1, 2, 3]);
obj.foo.call(null, 1, 2, 3);
obj.foo.apply(null, [1, 2, 3]);
obj.foo.call(otherObj, 1, 2, 3);
obj.foo.apply(otherObj, [1, 2, 3]);

// argument list 是有效的
foo.apply(undefined, args);
foo.apply(null, args);
obj.foo.apply(obj, args);

//错误
// 这跟foo(1, 2, 3)一样
foo.call(undefined, 1, 2, 3);
foo.apply(undefined, [1, 2, 3]);
foo.call(null, 1, 2, 3);
foo.apply(null, [1, 2, 3]);
// 这跟foo(1, 2, 3)一样
obj.foo.call(obj, 1, 2, 3);
obj.foo.apply(obj, [1, 2, 3]);

no-useless-computed-key

1
'no-useless-computed-key': 2
1
2
3
4
5
//正确
var foo = {"a": "b"};

//错误
var foo = {["a"]: "b"};

no-useless-constructor

无用的构造

1
'no-useless-constructor': 2

禁止无用的构造

1
2
3
4
5
6
7
8
9
10
11
//错误
class A {
constructor () { // 构造没任何用
}
}

class A extends B {
constructor (...args) {
super(...args); // 不写这个也会有这个构造
}
}

no-useless-escape

不必要的转义

1
'no-useless-escape': 0

禁止不必要的转义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//正确
"\"";
'\'';
"\x12";
"\u00a9";
"\371";
"xs\u2111";
`\``;
`\${${foo}}`;
`$\{${foo}}`;
/\\/g;
/\t/g;
/\w\$\*\^\./;

//错误
"\'";
'\"';
"\#";
"\e";
`\"`;
`\"${foo}\"`;
`\#{foo}`;
/\!/;
/\@/;

no-whitespace-before-property

属性前的空格

1
'no-whitespace-before-property': 2

属性前不要有空格

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//正确
foo.bar
foo[bar]
foo[ bar ]
foo.bar.baz
foo
.bar().baz()
foo
.bar()
.baz()
foo.
bar().
baz()

//错误
foo [bar]
foo. bar
foo .bar
foo. bar. baz
foo. bar()
.baz()
foo
.bar(). baz()

no-with

不使用with

1
'no-with': 2

with有潜在的风险,现在已经有很多方式可以代替with了

1
2
3
4
5
6
7
//正确
const r = ({x, y}) => Math.sqrt(x * x + y * y);

//错误
with (point) {
r = Math.sqrt(x * x + y * y); // r是否point的属性呢?
}

one-var

单变量

1
2
3
'one-var': [2, {
'initialized': 'never'
}]

为了浏览方便,可以一次定义多个变量,但是不要一次给多个变量赋值

1
2
3
4
5
6
7
8
9
10
11
12
//正确
function foo() {
var foo = true;
var bar = false;
var a, b, c; // Uninitialized variables are ignored
}

//错误
function foo() {
var foo = true,
bar = false;
}

operator-linebreak

操作符

1
2
3
4
5
6
'operator-linebreak': [2, 'after', {
'overrides': {
'?': 'before',
':': 'before'
}
}]

操作符紧跟之后,三元表达式在之前

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//正确
foo = 1 + 2;
foo = 1 +
2;
foo =
5;
if (someCondition ||
otherCondition) {
}
answer = everything ?
42 :
foo;

//错误
foo = 1
+
2;
foo = 1
+ 2;
foo
= 5;
if (someCondition
|| otherCondition) {
}
answer = everything
? 42
: foo;

quotes

引号

1
2
3
4
'quotes': [2, 'single', {
'avoidEscape': true,
'allowTemplateLiterals': true
}]

为了统一,请字符串用单引号,但是为了防止转义是可以用双引号的

1
2
3
4
5
6
7
//正确
var single = 'single';
var backtick = `back${x}tick`; // 允许模板
var unescaped = "a string containing 'single' quotes"; // 为了避免转义单引号,可以用双引号

//错误
var double = "double";

semi

分号

1
'semi': [2, 'always']

必须加分号

1
2
3
4
5
//正确
var website = "eslint.org";

//错误
var name = "ESLint"

semi-spacing

分号空白

1
2
3
4
'semi-spacing': [2, {
'before': false,
'after': true
}]

左边不能有空白,右边必须有空白

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//正确
var foo;
var foo; var bar;
throw new Error("error");
while (a) { break; }
for (i = 0; i < 10; i++) {}
for (;;) {}
if (true) {;}
;foo();

//错误
var foo ;
var foo;var bar;
throw new Error("error") ;
while (a) { break ; }
for (i = 0 ; i < 10 ; i++) {}
for (i = 0;i < 10;i++) {}

space-in-parens

参数空白

1
'space-in-parens': [2, 'never']

函数的参数括号两边不留空白

1
2
3
4
5
6
7
8
9
10
11
12
//正确
foo();
foo('bar');
var foo = (1 + 2) * 3;
(function () { return 'bar'; }());

//错误
foo( 'bar');
foo('bar' );
foo( 'bar' );
var foo = ( 1 + 2 ) * 3;
( function () { return 'bar'; }() );

space-infix-ops

操作符空白

1
'space-infix-ops': 2

操作符两边留空白

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//正确
a + b
a + b
a ? b : c
const a = {b:1};
var {a = 0} = bar;
function foo(a = 0) { }

//错误
a+b
a+ b
a +b
a?b:c
const a={b:1};
var {a=0}=bar;
function foo(a=0) { }

space-unary-ops

单元操作符空格

1
2
3
4
'space-unary-ops': [2, {
'words': true,
'nonwords': false
}]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//正确
delete foo.bar; // 文字操作符需要有空格
new Foo; // 文字操作符需要有空格
void 0; // 文字操作符需要有空格
++foo; // 非文字操作符不能有空格
foo--; // 非文字操作符不能有空格
-foo; // 非文字操作符不能有空格
+"3"; // 非文字操作符不能有空格

//错误
typeof!foo;
void{foo:0};
new[foo][0];
delete(foo.bar);
++ foo;
foo --;
- foo;
+ "3";

spaced-comment

注释的空格

1
2
3
'spaced-comment': [2, 'always', {
'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
}]

注释需要加个空格

1
2
3
4
5
6
7
8
9
10
11
12
13
//正确
// This is a comment with a whitespace at the beginning
/* This is a comment with a whitespace at the beginning */
/*
* This is a comment with a whitespace at the beginning
*/
/*
This comment has a newline
*/

//错误
//This is a comment with no whitespace at the beginning
/*This is a comment with no whitespace at the beginning */

template-curly-spacing

模板中的变量

1
'template-curly-spacing': [2, 'never']

模板中的变量不要加空格

1
2
3
4
5
6
7
8
9
10
//正确
`hello, ${people.name}!`;
`hello, ${
people.name
}!`;

//错误
`hello, ${ people.name}!`;
`hello, ${people.name }!`;
`hello, ${ people.name }!`;

use-isnan

非数字

1
'use-isnan': 2

判断非数字,请使用isNaN函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//正确
if (isNaN(foo)) {
// ...
}
if (!isNaN(foo)) {
// ...
}

//错误
if (foo == NaN) {
// ...
}
if (foo != NaN) {
// ...
}

valid-typeof

正确的类型

1
'valid-typeof': 2

请使用正确的类型

1
2
3
4
5
6
7
8
9
10
11
//正确
typeof foo === "string"
typeof bar == "undefined"
typeof foo === baz
typeof bar === typeof qux

//错误
typeof foo === "strnig"
typeof foo == "undefimed"
typeof bar != "nunber"
typeof bar !== "fucntion"

wrap-iife

闭包调用

1
'wrap-iife': [2, 'any']

直接调用函数需要括号括起来

1
2
3
4
5
6
//正确
var x = (function () { return { y: 1 };}());
var x = (function () { return { y: 1 };})();

//错误
var x = function () { return { y: 1 };}();

yoda

1
'yoda': [2, 'never']

条件里,变量在左,对比的值在右

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//正确
if (5 & value) {
// ...
}
if (value === "red") {
// ...
}

//错误
if ("red" === color) {
// ...
}
if (true == flag) {
// ...
}
if (5 > count) {
// ...
}
if (-1 < str.indexOf(substr)) {
// ...
}
if (0 <= x && x < 1) {
// ...
}

prefer-const

常量

1
'prefer-const': 1

没有被重定义的变量请用const,但是开发过程中经常有暂时没有重定义的变量,所以修改了警告级别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//错误
let a = 3;
console.log(a);

let a;
a = 0;
console.log(a);

for (let i in [1, 2, 3]) { // 遍历时候i不会被重定义
console.log(i);
}

for (let a of [1, 2, 3]) { // 遍历时候i不会被重定义
console.log(a);
}

no-debugger

调试

1
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0

在正式环境中不能有调试,开发环境关闭

1
2
3
4
function isTruthy(x) {
debugger;
return Boolean(x);
}

object-curly-spacing

对象空格

1
2
3
'object-curly-spacing': [2, 'always', {
objectsInObjects: false
}]

定义对象的大括号内两边加空格

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//正确
var obj = {};
var obj = { 'foo': 'bar' };
var obj = { 'foo': { 'bar': 'baz' }, 'qux': 'quxx' };
var obj = {
'foo': 'bar'
};
var { x } = y;
import { foo } from 'bar';

//错误
var obj = {'foo': 'bar'};
var obj = {'foo': 'bar' };
var obj = { baz: {'foo': 'qux'}, bar};
var obj = {baz: { 'foo': 'qux' }, bar};
var obj = {'foo': 'bar'
};
var obj = {
'foo':'bar'};
var {x} = y;
import {foo } from 'bar';

array-bracket-spacing

数组空格

1
'array-bracket-spacing': [2, 'never']

定义数字的中括号内,无空格

1
2
3
4
5
6
7
8
9
10
11
12
13
//正确
var arr = [];
var arr = ['foo', 'bar'];
var arr = [
'foo',
'bar'
];

//错误
var arr = [ 'foo', 'bar' ];
var arr = ['foo', 'bar' ];
var arr = [ ['foo'], 'bar'];
var arr = [[ 'foo' ], 'bar'];

脚手架

脚手架开发

准备

先找个目录初始化一下npm

1
2
3
mkdir cli
cd cli
npm init

program

使用program组件可以实现命令行的操作

安装

首先我们安装commander

1
npm i -S commander

版本

最简单的program显示版本

我们创建一个index.js文件,写入下面的代码

1
2
3
const program = require('commander'); // 为什么命名叫program而不是commander,因为commander是保留字段
program.version("0.0.1"); // 设置版本号
program.parse(process.argv); // 解析进程

如果不知道process关键字,可以去看 http://nodejs.cn/api/process.html

我们用node执行一下

1
node index.js --version

会得到我们设置的版本号

1
0.0.1

我们一般用package作为版本号

1
const VER = require('../package.json').version

最终代码

1
2
3
const program = require('commander');
program.version(require('../package.json').version); // 直接获取当前的package的version作为版本号
program.parse(process.argv);

帮助

上世纪电脑都靠命令行执行时候,就会有“-h”和“–help”作为帮助,显示命令如何用

1
2
3
4
const program = require('commander');
program.version(require('../package.json').version);
program.parse(process.argv);
program.help(); // 写上这么一行,自动的就会有所有设置的参数提示

命令

比如我们用的vue create

1
2
3
program
.command('create') // 命令
.action(cmd => console.log(cmd)); // 命令动作

我们执行一下

1
node index.js create

会执行action里面的function,输出cmd
还可以加一些参数,我们看下完整代码

1
2
3
4
5
6
7
8
9
10
const program = require('commander');
program.version(require('../package.json').version);
program
.command('create') // 创建项目
.alias('c') // 别名,用来简写
.description('create project(构造项目)') // 描述
.option('-d, --default', 'skip prompt and use default preset.') // 选项
.action(cmd => console.log(cmd));
program.parse(process.argv); // 解析进程
program.help();

并且你加了command之后,help会自动增加

1
node index.js --help

你可以看到比之前多了一个commads提示命令名,并且按照description给了提示

1
2
3
4
5
6
7
8
Usage: www [options] [command]

Options:
-V, --version output the version number
-h, --help output usage information

Commands:
create|c [options] create project(构造项目)

其他详细内容可以看官网 https://github.com/tj/commander.js

inquirer

问询组件

安装

1
npm i -S inquirer

问询

我们创建一个create.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const inquirer = require('inquirer');
module.exports = cmd => {
inquirer
.prompt([
{
// 项目名称
name: 'name',
type: 'input',
default: 'my-project',
message: '请输入项目名称'
}
])
.then(p => console.log(p))
.catch(e => console.log('项目创建错误'));
};

然后把之前command的action增加

1
2
3
4
const create = require('create'); // 加载create
program
.command('create')
.action(create); // action的function设置为create函数

这时候会运行会出现一个bug

1
node index.js create

问询出现之后,就直接显示了帮助

1
2
3
4
5
6
7
8
? 请输入项目名称 (my-project) Usage: www [options] [command]

Options:
-V, --version output the version number
-h, --help output usage information

Commands:
create|c [options] create project(构造项目)

所以我们一般吧帮助做一个处理,因为命令很多时候是也要加内容,所以默认认为了命令不全,我们加一个入参为空才出帮助就可以了

1
2
3
if (!program.args.length) { // 参数为空时候显示帮助
program.help();
}

现在你可以看见了想要的问询

1
2
bash> dayu create
? 请输入项目名称 (my-project)

输入之后,也能在inquirer的then中以object的方式返回

1
2
? 请输入项目名称 my-project
{ name: 'my-project' }

问询的种类很多,除了输入,是不是那种可以选择的会更好呢

1
2
3
4
5
6
7
8
9
10
11
.prompt([
{
// 项目模板
name: 'template',
type: 'list',
choices: ['A', 'B', 'C'],// 供选择的内容
message: '请选择模板'
}
])
.then(p => console.log(p))
.catch(e => console.log('项目创建错误'));

这时候可以用上下选择你想要的

1
2
3
4
? 请选择模板
A
> B
C

其他详细内容可以看官网 https://github.com/SBoudrias/Inquirer.js

download-git-repo

下载git源

安装

1
npm i -S download-git-repo

下载git源

下载

我们创建一个project-build的文件

1
2
3
4
5
6
7
8
9
import download from 'download-git-repo';
module.exports = (url, name) => {// url为git地址,name为本地创建的项目名也就是目录名称
download(url, name, {}, err => { // 下载模板
if (err) {
//失败
} else {
//成功
});
};

其他详细内容可以看官网 https://github.com/flipxfx/download-git-repo

handlebars

替换模板参数

安装

1
npm i -S handlebars

修改package

创建的项目需要替换package.json

1
2
3
4
5
6
{
"name": "{{name}}",
"version": "{{version}}",
"description": "{{description}}",
"author": "{{author}}",
}

替换我们就用这个方式

1
2
3
4
5
6
7
8
9
10
const meta = { // 设置模板参数
name: '项目名称',
version: '版本号',
description: '项目描述',
author: '作者'
};
const fileName = `${meta.name}/package.json`;
const content = fs.readFileSync(fileName).toString(); //读取package文件内容
const result = handlebars.compile(content)(meta); // 解析内容,并且用meta替换模板的变量
fs.writeFileSync(fileName, result); // 覆盖源文件

babel

安装

1
npm i -D babel-cli

配置加载环境

node是不能使用import的,但是我们经常看到babelrc

1
2
3
4
5
6
7
8
9
10
11
12
{
"presets": [
[
"env",
{
"target":{
"node":"current"
}
}
]
]
}

我们一般是吧src的源文件输出到dist里

1
babel src -d dist

最终应用的都是dist内的文件

语法规范

语法规范

syntax
英 [ˈsɪntæks] 美 [ˈsɪntæks]
n.句法; 句法规则[分析]; 语构; 语法;

计算机里,经常出现这个错误,就是语法错误,一般来说就是自己写的不符合这种编程的语法

1
2
3
4
5
const if = 123;// SyntaxError: Unexpected token if
{}.a;//SyntaxError: Unexpected token .
a()a;//SyntaxError: Unexpected identifier
if()a;//SyntaxError: Unexpected token )
……


ESLint

有些规范建议直接在eslint设置规范
错误等级有的地方用的是数字,可以参考一下

“off” 或者 0:关闭规则。
“warn” 或者 1:打开规则,并且作为一个警告(不影响exit code)。
“error” 或者 2:打开规则,并且作为一个错误(exit code将会是1)。

1
2
3
4
5
6
7
8
{
rules: {
'indent': [2, 2, {
'SwitchCase': 1
}],
'semi': [2, 'always'],
}
}

如果想在vscode自动语法提示中标注错误和警告,需要在setting里面添加

1
2
3
4
5
6
7
8
{
"eslint.validate": [
"javascript",{
"language": "vue"
},"html",
"vue"
]
}

indent 缩进

indent
英 [ɪnˈdent] 美 [ɪnˈdent]
vt. 切割…使呈锯齿状; 缩进排版;
常用方式有

  1. 一个tab(制表)
    1
    2
    3
    if(true){
    /*tab*/console.log("exec");
    }
  1. 四个space(空格)

    1
    2
    3
    if(true){
    console.log("exec");
    }
  2. 两个space

    1
    2
    3
    if(true){
    console.log("exec");
    }

建议使用两个空格,理由是

  • 用两个空格的人很多,并且在逐渐增加
  • 层级多了,也只是一层2个,不会让横向过长

eslint参数为

1
2
3
{
"indent": ["error", 2]
}

分号

semicolon
英 [ˌsemiˈkəʊlən] 美 [ˈsemikoʊlən]
n. 分号;
建议加分号,因为在很多情况下会有问题,尤其ASI

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
a = b + c
(d + e).print()
// 会解析成下面的
a = b + c(d + e).print();
//-------------
a = b
/hi/g.exec(c).map(d)
// 会解析成下面的
a = b / hi / g.exec(c).map(d);
//-------------
someFunction()
['ul', 'ol'].map(x => x + x)
// 会解析成下面的
const propKey = ('ul','ol'); // comma operator
assert.equal(propKey, 'ol');
someFunction()[propKey].map(x => x + x);

eslint参数为

1
2
3
{
'semi': ['error', 'always']
}

命名

变量以及属性的命名规则

必须是统一码(Unicode)

  • 字母:a-z,A-Z等
  • “$”(美元符号)和“_”(下划线)
    • “-”(横杠)不能用
  • 数字:0-9等
    • 不能以数字不能开头
      1
      2
      3
      4
      5
      6
      7
      const строка = '';
      const ε = 0.0001;
      let 变量 = 0.0001;
      let _tmp = 0;
      const $foo2 = true;
      let 0a = 1;// SyntaxError: Invalid or unexpected token
      let a-b = 1;// SyntaxError: Unexpected token -

小贴士
不能用预留关键字做变量,比如if,ture,const
但是可以做属性

1
2
3
const if = 123;// SyntaxError: Unexpected token if
const obj = { if: 123 };
obj.if// 123

所有js预留关键字

1
await break case catch class const continue debugger default delete do else export extends finally for function if import in instanceof let new return static super switch this throw try typeof var void while with yield

没有在js中使用,但是也预留的关键字

1
enum implements package protected interface private public

不是预留但是也要避免,他们本来就已经定义了关键字

1
Infinity NaN undefined async

虽然可以用,但是要避免用全局变量作为局部变量

1
String, Math, etc.

变量样式

  • 驼峰: threeConcatenatedWords
    • Camel case
  • 下划线(蛇形): three_concatenated_words
    • Underscore case (also called snake case)
  • 横线(肉串): three-concatenated-words
    • Dash case (also called kebab case)

我们变量一般选用驼峰,因为看起来简洁,也比下划线少打一些字
文件名,我们选择用横线,因为windows不区分大小写,比如git上提交的两个文件是myFile和myfile,在unix类的系统没事,但是在windows下会报错

1
my-module.js

大小写

首字母小写

1
2
3
4
let myVar;// 变量
function myFunction(){}// 函数
let obj = {};
obj.myMethod// 方法

首字母大写

1
class MyClass {}// 类

大写加下划线

1
const EVENT_START = "事件开始"// 常量

css请用肉串样式

1
special-class:{}

1
<div class="special-class"></div>

html标签以及属性也请用肉串样式

1
2
3
<common-tree :section-name="remote.tree.sectionName">
<div>...</div>
<common-tree>

下划线

成员变量

1
2
3
4
5
class MyClass{
construct(
this._memberVar = 1;
);
}

实体元素写两个下划线,就是在场景中实际存在的内容

1
2
3
4
5
class MyClass{
construct(
this.__element = document.getElementById("elementID");
);
}

命名规范

以下所有命名注意语义化,禁止使用a,b,name1,name2,拼音等命名方法

  1. 前缀应当为动词
  2. 可使用常见动词约定
前缀 示例 作用 返回
can canRead 判断是否可执行某个动作(权限) 函数返回一个布尔值。true:可执行;false:不可执行
has hasTag 判断是否含有某个值 函数返回一个布尔值。true:含有此值;false:不含有此值
is isExpire 判断是否为某个值 函数返回一个布尔值。true:为某个值;false:不为某个值
get getUserByName 获取某个值 函数返回一个非布尔值
set setUserName 设置某个值 无返回值、返回是否设置成功或者返回链式对象
load loadImage 加载某些数据 无返回值或者返回是否加载完成的结果

注释

Dom注释

方便在比较长的标签中,知道标签的开始位置以及结束位置

1
2
3
4
5
<!-- 文章列表列表模块 开始 -->
<div class="article-list">
...
</div>
<!-- 文章列表列表模块 结束 -->

函数注释:1.描述,2.入参,出参&类型

写清楚函数介绍以及参数和返回

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 函数描述
*
* @param {string} p1 参数1的说明
* @param {string} p2 参数2的说明,比较长那就换行了
* @param {number=} p3 参数3的说明(可选)
* @return {Object} 返回值描述
*/
function foo(p1, p2, p3) {
var p3 = p3 || 10;
return {
p1: p1,
p2: p2,
p3: p3
};
}

变量以及逻辑注释

放在变量后面,比放在前后多更好的可以形容变量
`js
let choices = [];// 模板选择
for(const k in tpl){// 把json的键插入数组,用于inquirer的list选择
choices.push(k);
}

markdown

markdown的使用
▸ 标题
▸ 段落
▸ 区块引用
▸ 代码区块
▸ 强调
▸ 列表
▸ 分割线
▸ 链接
▸ 图片
▸ 反斜杠
▸ 符号
▸ 表格
▸ 流程图

1. 标题

1.1. 使用= 和 -,标记一级和二级 标题。

代码

1
2
3
4
一级标题
=
二级标题
-

效果

一级标题
=
二级标题
-

1.2. 使用 #,可以表示 1-6级 标题。

代码

1
2
3
4
5
6
# 第一级标题 `<h1>` 
## 第二级标题 `<h2>`
### 第三级标题 `<h3>`
#### 第二四级标题 `<h4>`
##### 第五级标题 `<h5>`
###### 第六级标题 `<h6>`

效果

第一级标题 <h1>

第二级标题 <h2>

第三级标题 <h3>

第二四级标题 <h4>

第五级标题 <h5>
第六级标题 <h6>

2. 段落

段落的前后要有空行,所谓的空行是指没有文字内容。
若想在段内强制换行的方式是使用两个以上空格加上回车(引用中换行省略回车)

代码

1
第一段文字¶¶↵第二段文字

效果

第一段文字
第二段文字

3. 区块引用

在段落的每行或者只在第一行使用符号 > ,还可使用多个嵌套引用

代码

1
2
3
4
> 区块引用
>> 嵌套引用
>>> 三嵌套引用
>>>> 四嵌套引用

效果

区块引用

嵌套引用

三嵌套引用

四嵌套引用

4. 代码区块

代码区块的建立是在每行加上4个空格或者一个制表符(如同写代码一样)

使用‘`’符号,可以添加语言种类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
fun main(args: Array<String>) {   
println("Hello World!")

println("sum = ${sum(34, 67)}")
println("sum = ${sum(34, 67)}")
println("sum = ${sum(34, 6, 57, 34)}")

printSum(237, 57)
printSum(234, 567, 8)
vars(1, 4, 6, 78, 0, 6, 9, 8)


val sumLambda: (Int, Int) -> Int = { x, y -> x + y }
println("sumLambda = ${sumLambda(3, 6)}")

testFor()


val a: Int = 1000
println(a === a)//true 值相等,对象地址相等

//经过了装箱,创建了两个不同的对象
val boxedA: Int? = a
val anotherBoxedA: Int? = a

//虽然经过了装箱,但是值是相等的,都是10000
println(boxedA === anotherBoxedA) // false,值相等,对象地址不一样
println(boxedA == anotherBoxedA) // true,值相等
}

注意⚠️:需要和普通段落之间存在空行!

支持的语言

名称 关键字
AppleScript applescript
ActionScript 3.0 actionscript3, as3
Shell bash, shell
ColdFusion coldfusion, cf
C cpp, c
C# c#, c-sharp, csharp
CSS css
Delphi delphi, pascal, pas
diff&patch diff patch
Erlang erl, erlang
Groovy groovy
Java java
JavaFX jfx, javafx
JavaScript js, jscript, javascript
Perl perl, pl, Perl
PHP php
text text, plain
Python py, python
Ruby ruby, rails, ror, rb
SASS&SCSS sass, scss
Scala scala
SQL sql
Visual Basic vb, vbnet
XML xml, xhtml, xslt, html
Objective C objc, obj-c
F# f#, f-sharp, fsharp
R r, s, splus
matlab matlab
swift swift
GO go, golang

5. 强调

在强调内容两侧分别加上 *或者 -

代码

1
2
*斜体* ,_斜体_
**加粗**,__粗体__

效果

斜体 ,_斜体_
加粗粗体

6. 列表

无序

使用 . 、+、或- 标记无序列表

代码

1
2
3
4
5
6
-   第一项
+ 第二项
- 第三项
+ 第四项
- 第五项
+ 第六项

效果

  • 第一项
  • 第二项
  • 第三项
  • 第四项
  • 第五项
  • 第六项

**注意:标记后面最少有一个_空格_或制表符。若不在引用区块
中,必须和前方段落之间存在空行

有序

代码

1
2
3
4
5
6
1. 第一项
2. 第二项
3. 第三项
4. 第四项
5. 第五项
6. 第六项

效果

  1. 第一项
  2. 第二项
  3. 第三项
  4. 第四项
  5. 第五项
  6. 第六项

7. 分割线

分割线最常使用就是三个或以上的 * , ======还可以使用 - 和 _

代码

1
2
3
4
***
---
_____
======

效果




=======

8. 链接

行内式

代码

1
2
[GitHub](http://github.com)
自动生成连接 <http://www.github.com/>

效果

GitHub
自动生成连接 http://www.github.com/

参考式

代码

1
2
3
[GitHub][1]
[1]:http://github.com
自动生成连接 <http://www.github.com/>

效果

[GitHub][1]
[1]:http://github.com
自动生成连接 http://www.github.com/

注意:上述的 [1]:http://github.com 不出现在区块中

9. 图片

添加图片形式和链接相似,只需要在链接的基础上前方加一个 !号

代码

1
2
![GitHub set up](http://zh.mweb.im/asset/img/set-up-git.gif)
//格式: ![Alt Text](url)

效果

GitHub set up

10. 反斜杠 ‘\‘

相当于反转义作用。使符号成为普通符号

11. 符号

起到标记作用,如标签:
Ctrl+A 、Ctrl+C、Ctrl+V

12. 表格

1
2
3
4
5
6
第一格表头 | 第二格表头
---------| -------------
内容单元格 第一列第一格 | 内容单元格第二列第一格
内容单元格 第一列第二格 多加文字 | 内容单元格第二列第二格
内容单元格 第一列第三格 多加文字 | 内容单元格第二列第三格
内容单元格 第一列第四格 多加文字 | 内容单元格第二列第四格

效果

第一格表头 第二格表头
内容单元格 第一列第一格 内容单元格第二列第一格
内容单元格 第一列第二格 多加文字 内容单元格第二列第二格
内容单元格 第一列第三格 多加文字 内容单元格第二列第三格
内容单元格 第一列第四格 多加文字 内容单元格第二列第四格

13. 流程图

1
2
3
4
5
6
7
8
9
10
st=>start: Start:>https://www.jpjbp.com/
io=>inputoutput: verification
op=>operation: Your Operation
cond=>condition: Yes or No?
sub=>subroutine: Your Subroutine
e=>end

st->io->op->cond
cond(yes)->e
cond(no)->sub->io

效果

st=>start: Start:>https://www.jpjbp.com/
io=>inputoutput: verification
op=>operation: Your Operation
cond=>condition: Yes or No?
sub=>subroutine: Your Subroutine
e=>end

st->io->op->cond
cond(yes)->e
cond(no)->sub->io

更多语法参考: 流程图语法参考

nrm的使用

nrm是专门用来管理和快速切换私人配置的registry

全局安装nrm

1
npm i nrm -g

如果是unix系统,比如mac或者其他linux,需要添加sudo,然后还要输入密码

1
sudo npm i nrm -g

nrm有一些默认配置,用nrm ls命令查看默认配置

1
nrm ls

带*号即为当前使用的配置

1
2
3
4
5
6
7
  npm ---- https://registry.npmjs.org/
* cnpm --- http://r.cnpmjs.org/
taobao - https://registry.npm.taobao.org/
nj ----- https://registry.nodejitsu.com/
rednpm - http://registry.mirror.cqupt.edu.cn/
npmMirror https://skimdb.npmjs.com/registry/
edunpm - http://registry.enpmjs.org/

也可以直接用current命令查看当前使用的是哪个源

1
nrm current

使用nrm切换源

切到源http://registry.mirror.cqupt.edu.cn 命令:nrm use 源的别名,即

1
nrm use rednpm

查看*变化了位置

1
2
3
4
5
6
7
  npm ---- https://registry.npmjs.org/
cnpm --- http://r.cnpmjs.org/
taobao - https://registry.npm.taobao.org/
nj ----- https://registry.nodejitsu.com/
* rednpm - http://registry.mirror.cqupt.edu.cn/
npmMirror https://skimdb.npmjs.com/registry/
edunpm - http://registry.enpmjs.org/

用nrm add 命令添加公司私有npm源

http://test.jd.com (肯定不能暴露公司的私有源,这里代替的),起个别名叫jd

1
nrm add jd http://test.jd.com

执行成功提示

1
add registry jd success

接着查看nrm配置,发现最底部jd添加成功

1
2
3
4
5
6
7
8
  npm ---- https://registry.npmjs.org/
cnpm --- http://r.cnpmjs.org/
taobao - https://registry.npm.taobao.org/
nj ----- https://registry.nodejitsu.com/
* rednpm - http://registry.mirror.cqupt.edu.cn/
npmMirror https://skimdb.npmjs.com/registry/
edunpm - http://registry.enpmjs.org/
jd ----- https://test.jd.com/

需要用use去指向

1
nrm use jd

看看ls

1
2
3
4
5
6
7
8
  npm ---- https://registry.npmjs.org/
cnpm --- http://r.cnpmjs.org/
taobao - https://registry.npm.taobao.org/
nj ----- https://registry.nodejitsu.com/
rednpm - http://registry.mirror.cqupt.edu.cn/
npmMirror https://skimdb.npmjs.com/registry/
edunpm - http://registry.enpmjs.org/
* jd - http://registry.m.jd.com/

可以用test测试速度,我们来测试cnpm的速度

1
2
nrm test cnpm
nrm test npm

输出:

1
2
cnpm --- 1095ms
npm ---- 1241ms

做做对比,npm还是慢

删除源用del

1
nrm del jd

由于你选中的是这个源,删除之后会自动替换

1
2
3
4
5
6
⸨░░░░░░░░░░░░░░░░░░⸩ ⠙ :
delete registry jd success



Registry has been set to: https://registry.npmjs.org/

再看看ls

1
2
3
4
5
6
7
* npm ---- https://registry.npmjs.org/
cnpm --- http://r.cnpmjs.org/
taobao - https://registry.npm.taobao.org/
nj ----- https://registry.nodejitsu.com/
rednpm - http://registry.mirror.cqupt.edu.cn/
npmMirror https://skimdb.npmjs.com/registry/
edunpm - http://registry.enpmjs.org/

已经到最上面的源取了