7.1 用命名函数表达式而不是函数声明。eslint: func-style
函数表达式: const func = function () {}
函数声明: function func() {}
Why? 函数声明时作用域被提前了,这意味着在一个文件里函数很容易(太容易了)在其定义之前被引用。这样伤害了代码可读性和可维护性。如果你发现一个函数又大又复杂,这个函数妨碍这个文件其他部分的理解性,这可能就是时候把这个函数单独抽成一个模块了。别忘了给表达式显示的命名,不用管这个名字是不是由一个确定的变量推断出来的,这消除了由匿名函数在错误调用栈产生的所有假设,这在现代浏览器和类似babel编译器中很常见 (Discussion)
// bad
function foo() { // ... }
// bad
const foo = function () { // ... };
// good 函数表达式名和声明的函数名是不一样的
const short = function longUniqueMoreDescriptiveLexicalFoo() { // ... };
- 7.3 不要在非函数块(if、while等等)内声明函数。把这个函数分配给一个变量。浏览器会允许你这样做,但浏览器解析方式不同,这是一个坏消息。【详见
no-loop-func
】 eslint: no-loop-func
-
7.4 Note: 在ECMA-262中 [块
block
] 的定义是: 一系列的语句; 但是函数声明不是一个语句。 函数表达式是一个语句。// bad if (currentUser) { function test() { console.log('Nope.'); } } // good let test; if (currentUser) { test = () => { console.log('Yup.'); }; }
-
7.5 不要用
arguments
命名参数。他的优先级高于每个函数作用域自带的arguments
对象, 这会导致函数自带的arguments
值被覆盖// bad function foo(name, options, arguments) { // ... } // good function foo(name, options, args) { // ... }
-
7.6 不要使用
arguments
,用rest语法...
代替。 eslint: prefer-rest-paramsWhy?
...
明确你想用那个参数。而且rest参数是真数组,而不是类似数组的arguments
// bad function concatenateAll() { const args = Array.prototype.slice.call(arguments); return args.join(''); } // good function concatenateAll(...args) { return args.join(''); }
-
7.7 用默认参数语法而不是在函数里对参数重新赋值。
// really bad function handleThings(opts) { // 不, 我们不该改arguments // 第二: 如果 opts 的值为 false, 它会被赋值为 {} // 虽然你想这么写, 但是这个会带来一些细微的bug opts = opts || {}; // ... } // still bad function handleThings(opts) { if (opts === void 0) { opts = {}; } // ... } // good function handleThings(opts = {}) { // ... }
-
7.13 不要对参数重新赋值。 eslint: 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) { // ... }