7 Functions 函数
7.1 Use function declarations instead of function expressions. jscs: requireFunctionDeclarations
使用函数定义代替函数表达式。Why? Function declarations are named, so they’re easier to identify in call stacks. Also, the whole body of a function declaration is hoisted, whereas only the reference of a function expression is hoisted. This rule makes it possible to always use Arrow Functions in place of function expressions.
为什么?函数定义是有名字的,所以他们可以更容易的在调用栈中识别出来。同样,方法定义的整个方法体被提前到最前面,而函数表达式只有对方法的引用会被提到最前。这条规则让总是用箭头函数替换函数表达式可行。
// bad const foo = function () { }; // good function foo() { }
7.2 Immediately invoked function expressions: eslint: wrap-iife jscs: requireParenthesesAroundIIFE
IIFE:必须用小括号包围。Why? An immediately invoked function expression is a single unit - wrapping both it, and its invocation parens, in parens, cleanly expresses this. Note that in a world with modules everywhere, you almost never need an IIFE.
为什么?一个IIFE是一个完整的单位——包括它的定义和它的调用括号。把IIFE写在括号里,可以清楚的表达这个意思。注意,在一个到处都是在modules的世界里,你几乎用不到IIFE。
// immediately-invoked function expression (IIFE) (function () { console.log('Welcome to the Internet. Please follow me.'); }());
7.3 Never declare a function in a non-function block (if, while, etc). Assign the function to a variable instead. Browsers will allow you to do it, but they all interpret it differently, which is bad news bears. eslint: no-loop-func
绝对不要在一个非函数语句块里定义一个函数(例如,if/while)。用把函数赋给一个变量代替。浏览器允许你做这个,但是它们解释起来不一样,这是一个很糟糕的记忆。
7.4 Note: ECMA-262 defines a block as a list of statements. A function declaration is not a statement. Read ECMA-262’s note on this issue.
注意,ECMA-262定义了“一个语句块是一组语句”。函数定义不是语句。读ECMA-262的Note关注这个问题。
// bad if (currentUser) { function test() { console.log('Nope.'); } } // good let test; if (currentUser) { test = () => { console.log('Yup.'); }; }
7.5 Never name a parameter arguments. This will take precedence over the arguments object that is given to every function scope.
不要把一个参数命名成arguments。这会覆盖每个函数都有的arguments。
// bad function nope(name, options, arguments) { // ...stuff... } // good function yup(name, options, args) { // ...stuff... }
*函数会有一个叫arguments的参数,来代表所有的参数。
x = findMax(1, 123, 500, 115, 44, 88); function findMax() { var i; var max = -Infinity; for (i = 0; i < arguments.length; i++) { if (arguments[i] > max) { max = arguments[i]; } } return max; }
7.6 Never use arguments, opt to use rest syntax … instead. prefer-rest-params
永远不要用arguments,用rest语法
...
代替。Why? … is explicit about which arguments you want pulled. Plus, rest arguments are a real Array, and not merely Array-like like arguments.
为什么?...
能明确的标示哪一个参数你想展开。另外,rest参数是一个真实的数组,而不是像arguments那样,只是一个类似数组的变量。// bad function concatenateAll() { const args = Array.prototype.slice.call(arguments); return args.join(''); } // good function concatenateAll(...args) { return args.join(''); }
7.7 Use default parameter syntax rather than mutating function arguments.
用默认参数的语法,而不是修改函数的参数。
// 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 = {}) { // ... }
7.8 Avoid side effects with default parameters.
避免在默认参数中的副作用。不要在默认参数中修改外部的变量 参考
Why? They are confusing to reason about.
为什么?因为会让你迷惑为什么会这样。var b = 1; // bad function count(a = b++) { console.log(a); } count(); // 1 count(); // 2 count(3); // 3 count(); // 3
7.9 Always put default parameters last.
总是把默认参数放到最后。
// bad function handleThings(opts = {}, name) { // ... } // good function handleThings(name, opts = {}) { // ... }
7.10 Never use the Function constructor to create a new function.
永远不要用函数构建器去创建一个新的函数。
Why? Creating a function in this way evaluates a string similarly to eval(), which opens vulnerabilities.
为什么?用这种方法去创建一个函数就像用eval()
,非常容易被攻击。7.11 Spacing in a function signature.
在函数签名中保留空格。
Why? Consistency is good, and you shouldn’t have to add or remove a space when adding or removing a name.
为什么,因为这样统一性很好。并且你在添加或删除名字的时候去添加、删除空格。// bad const f = function(){}; const g = function (){}; const h = function() {}; // good const x = function () {}; const y = function a() {};
7.12 Never mutate parameters. eslint: no-param-reassign
永远不要修改参数。
Why? Manipulating objects passed in as parameters can cause unwanted variable side effects in the original caller.
为什么?操作参数里传进来的对象能导致调用者中不想要的副作用变化。// bad function f1(obj) { obj.key = 1; }; // good function f2(obj) { const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1; };
7.13 Never reassign parameters. eslint: no-param-reassign
永远不要重新给参数赋值。
Why? Reassigning parameters can lead to unexpected behavior, especially when accessing the arguments object. It can also cause optimization issues, especially in V8.
为什么?重新给参数赋值能导致不可预期的行为,特别是访问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) { }