不要使用Function构造函数创建函数, eslint: no-new-func
原因:此方式创建函数和对字符串使用
eval()
一样会产生漏洞// bad const add = new Function('a', 'b', 'return a + b') // still bad const subtract = Function('a', 'b', 'return a - b')
在函数签名中使用空格,eslint: space-before-function-paren space-before-blocks
`
js
// bad
const f = function(){}
const g = function (){}
const h = function() {}// good
const x = function b () {}
const y = function a () {}
使用具名函数表达式而非函数声明,eslint: func-style
原因:这样做会导致函数声明被提升,这意味着很容易在文件中定义此函数之前引用它,不利于可读性和可维护性。如果你发现函数定义既庞大又复杂以至于不能理解文件的其他部分,或许你应该将它拆分成模块!别忘记要显式命名表达式,而不用管名字是否是从包含的变量(通常出现在现代浏览器中或者使用 Babel 编译器的时候)中推断的。这样会消除错误调用堆栈中的任何假设。 (讨论)
// bad function foo () { // ... } // bad const foo = function () { // ... } // good // lexical name distinguished from the variable-referenced invocation(s) const short = function longUniqueMoreDescriptiveLexicalFoo () { // ... }
用圆括号包裹自执行匿名函数,eslint:wrap-iife
原因:一个立即执行匿名函数表达式是一个单一的单元,将其及其调用括号包装在括号中,能够清楚地表达这一点。注意,在到处都是模块的世界中几乎不需要 IIFE。
// immediately-invoked function expression (IIFE) (function () { console.log('Welcome to the Internet. Please follow me.') }())
不要在非函数代码块(
if
,while
等)中声明函数,eslint:no-loop-func// bad if (isUse) { function test () { // do something } } // good let test if (isUse) { test = () => { // do something } }
不要将参数命名为
arguments
,会导致该参数的优先级高于每个函数作用域内原先存在的arguments
对象// bad function foo (name, options, arguments) { // ... } // good function foo (name, options, args) { // ... }
不要使用
arguments
,使用 剩余运算符...
arguments
只是一个类数组,而...
是一个真正的数组// bad function test () { const args = Array.prototype.slice.call(arguments) return args.join('') } // good function test (...args) { return args.join('') }
使用参数默认值语法而不是修改函数参数
// 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 = { }) { // ... }
避免参数默认值的副作用
let b = 1 // bad function count (a = b++) { console.log(a) } count() // 1 count() // 2 count(3) // 3 count() // 3
将参数默认值放在最后
// bad function handleThings (opts = {}, name) { // ... } // good function handleThings (name, opts = {}) { // ... }
不要更改参数,eslint: no-param-reassign
原因:操作作为参数传入的对象可能在原始调用中造成意想不到的变量副作用
// bad function f1 (obj) { obj.key = 1 } // good function f2 (obj) { const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1 }
不要给参数重新赋值,eslint: no-param-reassign
原因:参数重新赋值可能会导致无法预期的行为,尤其是当操作
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) { }
调用可变参数函数时建议使用展开运算符
....
, eslint: prefer-spread原因:显然你无需使用上下文,很难结合
new
和apply
// 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])