string
number
boolean
null
undefined
symbol
object
array
function
⬆ back to top
const
,避免使用var
. eslint: prefer-const
, no-const-assign
Why? 因为这个确保你不会改变你的初始值,重复引用会导致bug和代码难以理解
// bad var a = 1; var b = 2; // good const a = 1; const b = 2;
let
,而不是var
. eslint: no-var
Why? 因为let
是块级作用域,而var
是函数级作用域
// bad var count = 1; if (true) { count += 1; } // good, use the let. let count = 1; if (true) { count += 1; }
let
、const
都是块级作用域
// const 和 let 都只存在于它定义的那个块级作用域 { let a = 1; const b = 1; } console.log(a); // ReferenceError console.log(b); // ReferenceError⬆ back to top
no-new-object
// bad const item = new Object(); // good const item = {};
object-shorthand
// bad const atom = { value: 1, addValue: function (value) { return atom.value + value; }, }; // good const atom = { value: 1, // 对象的方法 addValue(value) { return atom.value + value; }, };
object-shorthand
Why? 这样写的更少且更可读
const lukeSkywalker = 'Luke Skywalker'; // bad const obj = { lukeSkywalker: lukeSkywalker, }; // good const obj = { lukeSkywalker, };
''
. eslint: quote-props
Why? 通常我们认为这种方式主观上易读。他优化了代码高亮,并且页更容易被许多JS引擎压缩。
// bad const bad = { 'foo': 3, 'bar': 4, 'data-blah': 5, }; // good const good = { foo: 3, bar: 4, 'data-blah': 5, };
Object.prototype
上的方法,如hasOwnProperty
, propertyIsEnumerable
, isPrototypeOf
。
Why? 在一些有问题的对象上, 这些方法可能会被屏蔽掉 - 如:{ hasOwnProperty: false }
- 或这是一个空对象Object.create(null)
// 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));
...
运算符],而不是Object.assign
。获取对象指定的几个属性时,用对象的rest解构运算符[也是...
运算符]更好。
// very bad const original = { a: 1, b: 2 }; const copy = Object.assign(original, { c: 3 }); // this mutates original ಠ_ಠ delete copy.a; // so does this // bad const original = { a: 1, b: 2 }; const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 } // good es6扩展运算符 ... const original = { a: 1, b: 2 }; // 浅拷贝 const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 } // rest 赋值运算符 const { a, ...noA } = copy; // noA => { b: 2, c: 3 }⬆ back to top
no-array-constructor
// bad const items = new Array(); // good const items = [];
...
运算符而不是Array.from
来将一个可迭代的对象转换成数组。
const foo = document.querySelectorAll('.foo'); // good const nodes = Array.from(foo); // best const nodes = [...foo];
Array.from
去将一个类数组对象转成一个数组。
const arrLike = { 0: 'foo', 1: 'bar', 2: 'baz', length: 3 }; // bad const arr = Array.prototype.slice.call(arrLike); // good const arr = Array.from(arrLike);
Array.from
而不是 ...
运算符去做map遍历。 因为这样可以避免创建一个临时数组。
// bad const baz = [...foo].map(bar); // good const baz = Array.from(foo, bar);
array-callback-return
// good [1, 2, 3].map((x) => { const y = x + 1; return x * y; }); // good 函数只有一个语句 [1, 2, 3].map(x => x + 1); // bad - 没有返回值, 因为在第一次迭代后acc 就变成undefined了 [[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; });
[
后和 ]
前断行。 请看下面示例
// 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, ];⬆ back to top
prefer-destructuring
Why? 解构保存了这些属性的临时值/引用
// 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}; }
⬆ back to top
''
。 eslint: quotes
// bad const name = "Capt. Janeway"; // bad - 样例应该包含插入文字或换行 const name = Capt. Janeway; // good const name = 'Capt. Janeway';
prefer-template
template-curly-spacing
Why? 模板字符串更具可读性、语法简洁、字符串插入参数。
// 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}?; }
eval()
,他就是潘多拉盒子。 eslint: no-eval
no-useless-escape
Why? 反斜线可读性差,所以他们只在必须使用时才出现哦
// bad const foo = '\'this\' \i\s \"quoted\"'; // good const foo = '\'this\' is "quoted"'; //best const foo = my name is '${name}';⬆ back to top
func-style
函数表达式: const func = function () {}
函数声明: function func() {}
Why? 函数声明时作用域被提前了,这意味着在一个文件里函数很容易(太容易了)在其定义之前被引用。这样伤害了代码可读性和可维护性。如果你发现一个函数有大又复杂,这个函数妨碍这个文件其他部分的理解性,这可能就是时候把这个函数单独抽成一个模块了。别忘了给表达式显示的命名,不用管这个名字是不是由一个确定的变量推断出来的,这消除了由匿名函数在错误调用栈产生的所有假设,这在现代浏览器和类似babel编译器中很常见 (Discussion)
Why? 这一段还不理解这种错误发生的场景,所以只能直译过来了, 另附原文
Why? Function declarations are hoisted, which means that it’s easy - too easy - to reference the function before it is defined in the file. This harms readability and maintainability. If you find that a function’s definition is large or complex enough that it is interfering with understanding the rest of the file, then perhaps it’s time to extract it to its own module! Don’t forget to explicitly name the expression, regardless of whether or not the name is inferred from the containing variable (which is often the case in modern browsers or when using compilers such as Babel). This eliminates any assumptions made about the Error’s call stack. (Discussion)
// bad function foo() { // ... } // bad const foo = function () { // ... }; // good // lexical name distinguished from the variable-referenced invocation(s) // 函数表达式名和声明的函数名是不一样的 const short = function longUniqueMoreDescriptiveLexicalFoo() { // ... };
wrap-iife
Why? immediately invoked function expression = IIFE
Why? 一个立即调用的函数表达式是一个单元 - 把它和他的调用者(圆括号)包裹起来,在括号中可以清晰的地表达这些。
Why? 注意:在模块化世界里,你几乎用不着 IIFE
// immediately-invoked function expression (IIFE) (function () { console.log('Welcome to the Internet. Please follow me.'); }());
no-loop-func
】 eslint: no-loop-func
block
] 的定义是: 一系列的语句; 但是函数声明不是一个语句。 函数表达式是一个语句。
// bad if (currentUser) { function test() { console.log('Nope.'); } } // good let test; if (currentUser) { test = () => { console.log('Yup.'); }; }
arguments
命名参数。他的优先级高于每个函数作用域自带的 arguments
对象, 这会导致函数自带的 arguments
值被覆盖
// bad function foo(name, options, arguments) { // ... } // good function foo(name, options, args) { // ... }
arguments
,用rest语法...
代替。 eslint: prefer-rest-params
Why? ...
明确你想用那个参数。而且rest参数是真数组,而不是类似数组的arguments
// bad function concatenateAll() { const args = Array.prototype.slice.call(arguments); return args.join(''); } // good function concatenateAll(...args) { return args.join(''); }
no-new-func
Why? 以这种方式创建函数将类似于字符串 eval(),这会打开漏洞。
// bad var add = new Function('a', 'b', 'return a + b'); // still bad var subtract = Function('a', 'b', 'return a - b');
space-before-function-paren
space-before-blocks
Why? 统一性好,而且在你添加/删除一个名字的时候不需要添加/删除空格
// bad const f = function(){}; const g = function (){}; const h = function() {}; // good const x = function () {}; const y = function a() {};
no-param-reassign
Why? 操作参数对象对原始调用者会导致意想不到的副作用。 就是不要改参数的数据结构,保留参数原始值和数据结构。
// bad function f1(obj) { obj.key = 1; }; // good function f2(obj) { const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1; };
no-param-reassign
Why? 参数重新赋值会导致意外行为,尤其是对 arguments
。这也会导致优化问题,特别是在V8里
// 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) { // ... }
spread
操作符...
去调用多变的函数更好。 eslint: prefer-spread
Why? 这样更清晰,你不必提供上下文,而且你不能轻易地用apply
来组成new
// 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]);
⬆ back to top