资讯专栏INFORMATION COLUMN

Airbnb JavaScript 编码风格指南(2018年最新版)

array_huang / 1674人阅读

摘要:对象声明时分类简写和非简写的属性名。函数使用命名函数表达式而不是函数声明。讨论函数名和变量引用名不同第一个函数没有属性,在过程中,它会是一个匿名函数。箭头函数当你必须要使用匿名函数如在传递内联回调时,请使用箭头函数。

Airbnb JavaScript 编码风格指南(2018年最新版)
访问此原文地址:http://galaxyteam.pub/didi-fe...
另外欢迎访问我们维护的https://www.threejs.online 中文站 (欢迎Star!)

本文译者:滴滴出行上海前端(FE)团队杨永乐同学

类型

基本类型:直接存取

string

number

boolean

null

undefined

symbol

const foo = 1;
let bar = foo;

bar = 9;

console.log(foo, bar); // => 1, 9

symbol 类型不能完全polyfilled,所以请谨慎使用

复杂类型: 通过引用的方式存取

object

array

function

const foo = [1, 2];
const bar = foo;

bar[0] = 9;

console.log(foo[0], bar[0]); // => 9, 9

引用

使用const申明引用类型,避免使用var。eslint 设置:prefer-const,no-const-assign

为什么?这能确保你无法对引用重新赋值,也不会导致出现 bug 或难以理解。
// bad
var a = 1;
var b = 2;

// good
const a = 1;
const b = 2;

如果必须对引用类型重新赋值,使用let而非var。eslint设置:no-var jscs: disallowVar

为什么?相比于var函数作用域,let块级作用域更容易理解
// bad
var count = 1;
if (true) {
  count += 1;
}

// good, use the let.
let count = 1;
if (true) {
  count += 1;
}

注意letconst都是块级作用域

// const and let only exist in the blocks they are defined in.
{
  let a = 1;
  const b = 1;
}
console.log(a); // ReferenceError
console.log(b); // ReferenceError

对象

使用字面值创建对象。eslint: no-new-object

// bad
const item = new Object();

// good
const item = {};

创建对象的动态属性时,使用计算属性

为什么?这样可以在一个地方定义对象所有的属性
function getKey(k) {
  return `a key named ${k}`;
}

// bad
const obj = {
  id: 5,
  name: "San Francisco",
};
obj[getKey("enabled")] = true;

// good
const obj = {
  id: 5,

  [getKey("enabled")]: true,
};
```

使用对象方法的简写形式。 eslint: object-shorthand jscs: requireEnhancedObjectLiterals

为什么?方法定义简洁清晰
// bad
const atom = {
  value: 1,

  addValue: function (value) {
    return atom.value + value;
  },
};

// good
const atom = {
  value: 1,

  addValue(value) {
    return atom.value + value;
  },
};

使用属性值简写形式。eslint: object-shorthand jscs: [requireEnhancedObjectLiterals]

为什么?书写更加简洁,更有描述性。
const lukeSkywalker = "Luke Skywalker";

// bad
const obj = {
  lukeSkywalker: lukeSkywalker,
};

// good
const obj = {
  lukeSkywalker,
};

对象声明时分类简写和非简写的属性名。

为什么?更清晰的了解哪些属性是简写的。
const anakinSkywalker = "Anakin Skywalker";
const lukeSkywalker = "Luke Skywalker";

// bad
const obj = {
  episodeOne: 1,
  twoJediWalkIntoACantina: 2,
  lukeSkywalker,
  episodeThree: 3,
  mayTheFourth: 4,
  anakinSkywalker,
};

// good
const obj = {
  lukeSkywalker,
  anakinSkywalker,
  episodeOne: 1,
  twoJediWalkIntoACantina: 2,
  episodeThree: 3,
  mayTheFourth: 4,
};

只有对那些不合法的属性名标识符添加引号。eslint: quote-props jscs: disallowQuotedKeysInObjects

为什么?对象属性更直观,可读性强。能够代码高亮显示,同时对于大多数的js引擎更容易优化代码。
// bad
const bad = {
  "foo": 3,
  "bar": 4,
  "data-blah": 5,
};

// good
const good = {
  foo: 3,
  bar: 4,
  "data-blah": 5,
};

不要直接使用Object.prototype上的方法,例如hasOwnProperty, propertyIsEnumerable, 和 isPrototypeOf

为什么?这些方法可能受对象的其他属性影响。例如{ hasOwnProperty: false } 或者 对象可能是null(Object.create(null))
// bad
console.log(object.hasOwnProperty(key));

const object = Object.create(null);
obj.hasOwnProperty(key) // Uncaught TypeError: obj.hasOwnProperty is not a function

// good
console.log(Object.prototype.hasOwnProperty.call(object, key));

// best
const has = Object.prototype.hasOwnProperty; // cache the lookup once, in module scope.
/* or */
import has from "has"; // https://www.npmjs.com/package/has
// ...
console.log(has.call(object, key));

浅拷贝对象时推荐使用对象展开操作(object spread operator)而不是Object.assign。使用对象剩余操作符(object rest operator)获取对象中剩余的属性。

为什么?Object.assign使用不当会修改原对象
// very bad
const original = { a: 1, b: 2 };
const copy = Object.assign(original, { c: 3 }); // this mutates `original` ಠ_ಠ
delete copy.a; // so does this

// bad
const original = { a: 1, b: 2 };
const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 }

// good
const original = { a: 1, b: 2 };
const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 }

const { a, ...noA } = copy; // noA => { b: 2, c: 3 }

数组

使用字面量声明数组。eslint: no-array-constructor

// bad
const items = new Array();

// good
const items = [];

向数组添加元素时,使用Arrary#push替代直接赋值。

const someStack = [];

// bad
someStack[someStack.length] = "abracadabra";

// good
someStack.push("abracadabra");

使用数组展开操作符...拷贝数组

// bad
const len = items.length;
const itemsCopy = [];
let i;

for (i = 0; i < len; i += 1) {
  itemsCopy[i] = items[i];
}

// good
const itemsCopy = [...items];

将类数组对象(array-like)转换成数组时,使用...而不是Array.from

const foo = document.querySelectorAll(".foo");

// good
const nodes = Array.from(foo);

// best
const nodes = [...foo];

当需要对可遍历对象进行map操作时,使用Array.from而不是展开操作符...,避免新建一个临时数组。

// bad
const baz = [...foo].map(bar);

// good
const baz = Array.from(foo, bar);

数组方法回调需要有返回值。如果函数体比较简单,可以直接用表达式,省略return语句。 eslint: array-callback-return

// good
[1, 2, 3].map((x) => {
  const y = x + 1;
  return x * y;
});

// good
[1, 2, 3].map(x => x + 1);

// bad - no returned value means `memo` becomes undefined after the first iteration
[[0, 1], [2, 3], [4, 5]].reduce((memo, item, index) => {
  const flatten = memo.concat(item);
  memo[index] = flatten;
});

// good
[[0, 1], [2, 3], [4, 5]].reduce((memo, item, index) => {
  const flatten = memo.concat(item);
  memo[index] = flatten;
  return flatten;
});

// bad
inbox.filter((msg) => {
  const { subject, author } = msg;
  if (subject === "Mockingbird") {
    return author === "Harper Lee";
  } else {
    return false;
  }
});

// good
inbox.filter((msg) => {
  const { subject, author } = msg;
  if (subject === "Mockingbird") {
    return author === "Harper Lee";
  }

  return false;
});

如果数组有多行,请在打开和关闭数组括号之前使用换行符

为什么? 更具有可读性
// bad
const arr = [
  [0, 1], [2, 3], [4, 5],
];

const objectInArray = [{
  id: 1,
}, {
  id: 2,
}];

const numberInArray = [
  1, 2,
];

// good
const arr = [[0, 1], [2, 3], [4, 5]];

const objectInArray = [
  {
    id: 1,
  },
  {
    id: 2,
  },
];

const numberInArray = [
  1,
  2,
];

解构

访问和使用对象的多个属性时用对象解构操作。eslint: prefer-destructuring jscs: requireObjectDestructuring

为什么?解构可以避免为这些属性创建临时引用。
// bad
function getFullName(user) {
  const firstName = user.firstName;
  const lastName = user.lastName;

  return `${firstName} ${lastName}`;
}

// good
function getFullName(user) {
  const { firstName, lastName } = user;
  return `${firstName} ${lastName}`;
}

// best
function getFullName({ firstName, lastName }) {
  return `${firstName} ${lastName}`;
}

使用数组解构。eslint: prefer-destructuring jscs: requireArrayDestructuring

const arr = [1, 2, 3, 4];

// bad
const first = arr[0];
const second = arr[1];

// good
const [first, second] = arr;

使用对象解构来实现多个返回值,而不是数组解构。jscs: disallowArrayDestructuringReturn

为什么?你可以随时为返回值新增属性而不用关心属性的顺序。
// bad
function processInput(input) {
  // then a miracle occurs
  return [left, right, top, bottom];
}

// 调用者需要注意返回值中对象的顺序
const [left, __, top] = processInput(input);

// good
function processInput(input) {
  // then a miracle occurs
  return { left, right, top, bottom };
}

// 调用者只需要使用它需要的对象
const { left, top } = processInput(input);

字符串

字符串使用单引号。eslint: quotes jscs: validateQuoteMarks

// bad
const name = "Capt. Janeway";

// bad - 当需要插值或者换行时才使用模板文字
const name = `Capt. Janeway`;

// good
const name = "Capt. Janeway";

不超过100个字符的字符串不应该使用连接符或者换行书写。

为什么?换行的字符串不好阅读,并且不方便搜索代码。
// bad
const errorMessage = "This is a super long error that was thrown because 
of Batman. When you stop to think about how Batman had anything to do 
with this, you would get nowhere 
fast.";

// bad
const errorMessage = "This is a super long error that was thrown because " +
  "of Batman. When you stop to think about how Batman had anything to do " +
  "with this, you would get nowhere fast.";

// good
const errorMessage = "This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.";

以编程方式构建字符串时,使用模板字符串而不是连接符。eslint: prefer-template template-curly-spacing jscs: requireTemplateStrings

为什么?模板字符串更为简洁,更具可读性。
// bad
function sayHi(name) {
  return "How are you, " + name + "?";
}

// bad
function sayHi(name) {
  return ["How are you, ", name, "?"].join();
}

// bad
function sayHi(name) {
  return `How are you, ${ name }?`;
}

// good
function sayHi(name) {
  return `How are you, ${name}?`;
}

永远不要在字符串上使用eval()方法,它有太多的问题。eslint: no-eval

不要过多的转义字符串。eslint: no-useless-escape

为什么?反斜杠影响代码可读性,只有在必要的时候才使用。
// bad
const foo = ""this" is "quoted"";

// good
const foo = ""this" is "quoted"";
const foo = `my name is "${name}"`;

函数

使用命名函数表达式而不是函数声明。eslint: func-style jscs: disallowFunctionDeclarations

为什么?函数声明会被提前。这意味着很可能在函数定义前引用该函数,但是不会报错。这不利于代码的可读性和可维护性。如果你发现一个函数定义的很大很复杂,以至于妨碍了了解文件中的其他内容,那么是时候把这个函数提取到自己的模块中去了!不要忘记显示指定表达式的名称,尽管它能从变量名中被推断出来(现代浏览器或者编译器(如Babel)支持)。这能让错误的调用栈更清晰。(讨论)
// bad
function foo() {
  // ...
}

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

// good
// 函数名和变量引用名不同
const short = function longUniqueMoreDescriptiveLexicalFoo() {
  // ...
};
// Is it worse
const sum = function(a, b) {
  return a + b;
};

// than this?
const my_sum = function sum(a, b) {
  return a + b;
};
第一个函数没有.name属性,在debugging过程中,它会是一个匿名函数。第二个函数有名字为sum,你可以检索到它,调试过程中能够快速定位。

使用banel 和babel-preset-env配置,const foo = () => {}会转换成var foo = function foo () {},并且从Node v6开始,const foo = () => {}中的foo 也有.name。所以它不再是匿名函数。(函数名字推断)

用圆括号包裹立即执行函数表达式(IIFE)。eslint: wrap-iife jscs: requireParenthesesAroundIIFE

为什么? 立即执行函数表达式是单一执行单元-使用圆括号包裹调用,简洁明了的表示了这一点。请注意,在通用的模块中,你几乎用不到IIFE。
// immediately-invoked function expression (IIFE)
(function () {
  console.log("Welcome to the Internet. Please follow me.");
}());

永远不要在一个非函数代码块(if、while 等)中声明一个函数,把那个函数赋给一个变量。浏览器允许你这么做,但它们的解析表现不一致。eslint: no-loop-func

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

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

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

永远不要把参数命名为arguments。这将取代原来函数作用域内的 arguments对象。

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

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

不要使用arguments。可以选择 rest 语法 ... 替代。

为什么?使用 ... 能明确你要传入的参数。另外 rest 参数是一个真正的数组,而 arguments 是一个类数组。
// bad
function concatenateAll() {
  const args = Array.prototype.slice.call(arguments);
  return args.join("");
}

// good
function concatenateAll(...args) {
  return args.join("");
}

使用函数默认参数指定默认值,而不是用一个可变的函数参数

// really bad
function handleThings(opts) {
  // 不!我们不应该改变函数参数
  // 更糟糕的是: 如果 opts 是 falsy (为""或者是false), 它仍然会被赋值为对象,但是这可能会引发bug
  opts = opts || {};
  // ...
}

// still bad
function handleThings(opts) {
  if (opts === void 0) {
    opts = {};
  }
  // ...
}

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

8.使用函数参数默认值的时避免副作用。

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

```javascript
var 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 = {}) {
  // ...
}

不要使用Function构造器创建函数。 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");

函数名两边留白。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() {};

不要修改参数。 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

为什么?重新分配参数可能会导致意外的行为,特别是在访问参数对象时。 它也可能导致优化问题,特别是在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

为什么?它更简洁,你不需要提供上下文,并且组合使用newapply不容易。
// 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]);

带有多行函数签名或调用的函数应该像本指南中的其他多行列表一样缩进:每行中包含一项,最后一个项目带有逗号。

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

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

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

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

箭头函数

当你必须要使用匿名函数(如在传递内联回调时),请使用箭头函数。eslint: prefer-arrow-callback, arrow-spacing jscs: requireArrowFunctions

为什么?因为箭头函数创造了新的一个 this 执行环境,通常情况下都能满足你的需求,而且这样的写法更为简洁。(参考 Arrow functions - JavaScript | MDN )

为什么不?如果你有一个相当复杂的函数,你或许可以把逻辑部分转移到一个函数声明上。

// bad
[1, 2, 3].map(function (x) {
  const y = x + 1;
  return x * y;
});

// good
[1, 2, 3].map((x) => {
  const y = x + 1;
  return x * y;
});

如果一个函数适合用一行写出并且只有一个参数,那就把花括号、圆括号和 return 都省略掉。如果不是,那就不要省略。eslint: arrow-parens, arrow-body-style jscs: disallowParenthesesAroundArrowParam, requireShorthandArrowFunctions

为什么?这是一个很好用的语法糖。在链式调用中可读性很高。
// bad
[1, 2, 3].map(number => {
  const nextNumber = number + 1;
  `A string containing the ${nextNumber}.`;
});

// good
[1, 2, 3].map(number => `A string containing the ${number}.`);

// good
[1, 2, 3].map((number) => {
  const nextNumber = number + 1;
  return `A string containing the ${nextNumber}.`;
});

// good

  [index]: number,
}));

// No implicit return with side effects
function foo(callback) {
  const val = callback();
  if (val === true) {
    // Do something if callback returns true
  }
}

let bool = false;

// bad
foo(() => bool = true);

// good
foo(() => {
  bool = true;
});
```

如果表达式过长需要多行表示,请将其包含在括号中,增加可读性。

为什么?它能清除的标识函数的开始和结束位置。
// bad
["get", "post", "put"].map(httpMethod => Object.prototype.hasOwnProperty.call(
    httpMagicObjectWithAVeryLongName,
    httpMethod,
  )
);

// good
["get", "post", "put"].map(httpMethod => (
  Object.prototype.hasOwnProperty.call(
    httpMagicObjectWithAVeryLongName,
    httpMethod,
  )
));

如果函数只有一个参数并且函数体没有使用花括号,那就省略括号。否则,为了保持清晰一致性,总在参数周围加上括号。总是使用括号也是可以接受的,在这种情况下使用eslint的 “always” option 或者不要在jscs中引入 disallowParenthesesAroundArrowParam。eslint: arrow-parens jscs: disallowParenthesesAroundArrowParam

为什么? 不那么混乱,可读性强。
// bad
[1, 2, 3].map((x) => x * x);

// good
[1, 2, 3].map(x => x * x);

// good
[1, 2, 3].map(number => (
  `A long string with the ${number}. It’s so long that we don’t want it to take up space on the .map line!`
));

// bad
[1, 2, 3].map(x => {
  const y = x + 1;
  return x * y;
});

// good
[1, 2, 3].map((x) => {
  const y = x + 1;
  return x * y;
});

避免箭头函数语法(=>)和比较运算符(<=,=>)一起使用时带来的困惑。

// bad
const itemHeight = item => item.height > 256 ? item.largeSize : item.smallSize;

// bad
const itemHeight = (item) => item.height > 256 ? item.largeSize : item.smallSize;

// good
const itemHeight = item => (item.height > 256 ? item.largeSize : item.smallSize);

// good
const itemHeight = (item) => {
  const { height, largeSize, smallSize } = item;
  return height > 256 ? largeSize : smallSize;
};

类 & 构造函数

总是使用class。避免直接操作prototype

为什么?class语法更简洁更易于理解。
// bad
function Queue(contents = []) {
  this.queue = [...contents];
}
Queue.prototype.pop = function () {
  const value = this.queue[0];
  this.queue.splice(0, 1);
  return value;
};

// good
class Queue {
  constructor(contents = []) {
    this.queue = [...contents];
  }
  pop() {
    const value = this.queue[0];
    this.queue.splice(0, 1);
    return value;
  }
}

使用extends继承。

为什么? 因为 extends 是一个内建的原型继承方法并且不会破坏 instanceof。
// bad
const inherits = require("inherits");
function PeekableQueue(contents) {
  Queue.apply(this, contents);
}
inherits(PeekableQueue, Queue);
PeekableQueue.prototype.peek = function () {
  return this.queue[0];
};

// good
class PeekableQueue extends Queue {
  peek() {
    return this.queue[0];
  }
}

方法可以返回 this 来帮助链式调用。

// bad
Jedi.prototype.jump = function () {
  this.jumping = true;
  return true;
};

Jedi.prototype.setHeight = function (height) {
  this.height = height;
};

const luke = new Jedi();
luke.jump(); // => true
luke.setHeight(20); // => undefined

// good
class Jedi {
  jump() {
    this.jumping = true;
    return this;
  }

  setHeight(height) {
    this.height = height;
    return this;
  }
}

const luke = new Jedi();

luke.jump()
  .setHeight(20);

可以写一个自定义的 toString() 方法,但要确保它能正常运行并且不会引起副作用。

class Jedi {
  constructor(options = {}) {
    this.name = options.name || "no name";
  }

  getName() {
    return this.name;
  }

  toString() {
    return `Jedi - ${this.getName()}`;
  }
}

类有默认构造器。一个空的构造函数或者只是重载父类构造函数是不必要的。eslint: no-useless-constructor

// bad
class Jedi {
  constructor() {}

  getName() {
    return this.name;
  }
}

// bad
class Rey extends Jedi {
  constructor(...args) {
    super(...args);
  }
}

// good
class Rey extends Jedi {
  constructor(...args) {
    super(...args);
    this.name = "Rey";
  }
}

避免重复的类成员。eslint: no-dupe-class-members

为什么?重复的类成员声明中只有最后一个生效-重复的声明肯定是一个错误。
// bad
class Foo {
  bar() { return 1; }
  bar() { return 2; }
}

// good
class Foo {
  bar() { return 1; }
}

// good
class Foo {
  bar() { return 2; }
}

模块

总是使用模组 (import/export) 而不是其他非标准模块系统。你可以编译为你喜欢的模块系统。

为什么?模块是未来,让我们开始迈向未来吧。
// bad
const AirbnbStyleGuide = require("./AirbnbStyleGuide");
module.exports = AirbnbStyleGuide.es6;

// ok
import AirbnbStyleGuide from "./AirbnbStyleGuide";
export default AirbnbStyleGuide.es6;

// best
import { es6 } from "./AirbnbStyleGuide";
export default es6;

不要使用通配符 import

为什么?这样确保只有一个默认的export
// bad
import * as AirbnbStyleGuide from "./AirbnbStyleGuide";

// good
import AirbnbStyleGuide from "./AirbnbStyleGuide";

不要直接从importexport

为什么?虽然一行代码简洁明了,但让 importexport 各司其职让事情能保持一致。
// bad
// filename es6.js
export { es6 as default } from "./AirbnbStyleGuide";

// good
// filename es6.js
import { es6 } from "./AirbnbStyleGuide";
export default es6;

同一个路径只使用一次import。eslint: no-duplicate-imports

为什么?相同路径有多个import会导致代码难以维护。
// bad
import foo from "foo";
// … some other imports … //
import { named1, named2 } from "foo";

// good
import foo, { named1, named2 } from "foo";

// good
import foo, {
  named1,
  named2,
} from "foo";

不要export可变的绑定。 eslint: import/no-mutable-exports

为什么?避免不确定的可变量,特别是export可变的绑定。如果某些特殊情况需要使用这种场景,通常应该export常量引用。
// bad
let foo = 3;
export { foo };

// good
const foo = 3;
export { foo };

模块中只有单个export,最好使用default export 。 eslint: import/prefer-default-export

为什么?一个文件最好只做一件事,这样更具备可读性和可维护性。
// bad
export function foo() {}

// good
export default function foo() {}

将所有的import语句放在文件的顶部。eslint: import/first

为什么?由于imports会被提升,最好保持它们在顶部以防出现不可预期的行为。
// bad
import foo from "foo";
foo.init();

import bar from "bar";

// good
import foo from "foo";
import bar from "bar";

foo.init();

多行import应该和多行数组和对象一样有缩进。

为什么?花括号需要遵循与指南中的每个其他花括号相同的缩进规则,末尾的逗号也一样。
// bad
import {longNameA, longNameB, longNameC, longNameD, longNameE} from "path";

// good
import {
  longNameA,
  longNameB,
  longNameC,
  longNameD,
  longNameE,
} from "path";

禁止在模块导入语句中使用Webpack加载器语法。eslint: import/no-webpack-loader-syntax

为什么?在import中使用webpack 语法会将代码耦合进bundler中。推荐在webpack.config.js中配置loader 规则。
// bad
import fooSass from "css!sass!foo.scss";
import barCss from "style!css!bar.css";

// good
import fooSass from "foo.scss";
import barCss from "bar.css";

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/57165.html

相关文章

  • Airbnb JavaScript 编码风格指南2018新版

    摘要:对象声明时分类简写和非简写的属性名。函数使用命名函数表达式而不是函数声明。讨论函数名和变量引用名不同第一个函数没有属性,在过程中,它会是一个匿名函数。箭头函数当你必须要使用匿名函数如在传递内联回调时,请使用箭头函数。 Airbnb JavaScript 编码风格指南(2018年最新版) 访问此原文地址:http://galaxyteam.pub/didi-fe...另外欢迎访问我们维护...

    VincentFF 评论0 收藏0
  • 在 React-CRA 应用中配合 VSCode 使用 ESLint 实践前端代码规范

    摘要:编码规范是独角兽公司内部的编码规范,该项目是上很受欢迎的一个开源项目,在前端开发中使用广泛,本文的配置规则就是以编码规范和编码规范作为基础的。 更新时间:2019-01-22React.js create-react-app 项目 + VSCode 编辑器 + ESLint 代码检查工具 + Airbnb 编码规范 前言 为什么要使用 ESLint 在项目开发过程中,编写符合团队编码规...

    Hujiawei 评论0 收藏0
  • 【译】前端练级攻略

    摘要:由于系统变得越来越复杂,人们提出了称为预处理器和后处理器的工具来管理复杂性。后处理器在由预处理器手写或编译后对应用更改。我之前建议的文章,,也涵盖了预处理器相关的知识。 译者:前端小智 原文:medium.freecodecamp.org/from-zero-t… medium.freecodecamp.org/from-zero-t… 我记得我刚开始学习前端开发的时候。我看到了很多文章及...

    wuyumin 评论0 收藏0
  • 前端练级攻略(第一部分)

    摘要:第一部分介绍了如何使用和开发接口。由于系统变得越来越复杂,人们提出了称为预处理器和后处理器的工具来管理复杂性。当您第一次得知有预处理器和后处理器时,你很有可能在任何地方已经使用它们。我之前建议的文章,,也涵盖了预处理器相关的知识。 我记得我刚开始学习前端开发的时候。我看到了很多文章及资料,被学习的资料压得喘不过气来,甚至不知道从哪里开始。 本指南列出前端学习路线,并提供了平时收藏的一些...

    qpal 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<