Airbnb Javascript GUIDE

原文链接

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) {
    }