函数

7.1 使用命名函数表达式代替函数声明

eslint: func-style jscs: disallowFunctionDeclarations

为什么?函数声明会存在变量提升,这样会非常溶蚀使一个文件在声明函数之前就引用了这个函数。这样会破坏可读性和可维护性。如果你发现函数的定义确实很大而且很复杂,放在文件里会影响别的代码的理解,那么或许你该考虑把它单独写成一个模块!不要忘了明确唯一的命名表达式,不管能否从变量里推测出这个名字的意思。这样可以消除任何调用栈错误的可能性。

// bad
function foo() {
  // ...
}

// bad
const foo = function () {
  // ...
};

// good
// 区别于变量引用调用的词汇名称
const short = function longUniqueMoreDescriptiveLexicalFoo() {
  // ...
};

7.2 用括号包裹立即调用函数表达式

eslint: wrap-iife jscs:requireParenthesesAroundIIFE

为什么?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.

// immediately-invoked function expression (IIFE)
(function () {
  console.log('Welcome to the Internet. Please follow me.');
}());

7.3 不要在一个非函数代码块中声明一个函数,可以把函数赋值给一个变量来代替。浏览器可能会允许你这样做,但它们的解析方式会不一致。

eslint: no-loop-func

7.4 注意: ECMA-262把block定义为语句。函数声明不是语句。

// bad
if (currentUser) {
  function test() {
    console.log('Nope.');
  }
}

// good
let test;
if (currentUser) {
  test = () => {
    console.log('Yup.');
  };
}

7.5 不要把参数命名为arguments。这样将会覆盖掉原本函数作用域内的arguments参数。

// bad
function foo(name, options, arguments) {
  // ...
}

// good
function foo(name, options, args) {
  // ...
}

7.6 不要使用arguments,选择使用rest语法...代替

eslint: prefer-rest-params

为什么?...能够明确你要使用的参数。而且,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) {
  // 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 避免默认参数的副作用

为什么?这样的写法让人困惑

var b = 1;
// bad
function count(a = b++) {
  console.log(a);
}
count();  // 1
count();  // 2
count(3); // 3
count();  // 3

7.9 通常把默认参数放到最后面

// bad
function handleThings(opts = {}, name) {
  // ...
}

// good
function handleThings(name, opts = {}) {
  // ...
}

7.10 不要使用函数的构造函数来创建一个函数

eslint: no-new-func

为什么?用这种方法创建一个函数相当于一个类似于eval()的字符串,这样很容易打开漏洞

// bad
var add = new Function('a', 'b', 'return a + b');

// still bad
var subtract = Function('a', 'b', 'return a - b');

7.11 在函数签名中使用空格

eslint: space-before-function-paren space-before-blocks

为什么?保持一致会很好,而且你不用在添加或者删除名字的时候添加或者删除空格

// bad
const f = function(){};
const g = function (){};
const h = function() {};

// good
const x = function () {};
const y = function a() {};

7.12 永远不要修改参数

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
}

7.13 永远不要重新声明参数

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

7.14 最好使用扩展运算符...来调用可变参数函数

eslint: prefer-spread

为什么?这样更简洁,你不需要提供上下文环境,而且用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])

7.15 有多行签名或调用的函数应该像本指南中的其他多行列表一样缩进:将每个项目单独放在一行上,并在最后一项上放置一个尾随逗号

// bad
function foo(bar,
             baz,
             quux) {
  // ...
}

// good
function foo(
  bar,
  baz,
  quux,
) {
  // ...
}

// bad
console.log(foo,
  bar,
  baz);

// good
console.log(
  foo,
  bar,
  baz,
);

results matching ""

    No results matching ""