Coder Social home page Coder Social logo

airbnb-javascript-style-guide-cn's Introduction

Airbnb JavaScript编码规范指南(ES6)中文版 {

个人翻译,一些个人见解会用"注:"的形式标出 个人翻译的CSS规范:Airbnb CSS/Sass规范

内容

  1. 类型
  2. 引用
  3. 对象
  4. 数组
  5. 解构
  6. 字符串
  7. 函数
  8. 箭头函数
  9. [类 & 构造函数](#类 & 构造函数)
  10. 模块
  11. 迭代器和生成器
  12. 属性
  13. 变量
  14. 变量提升
  15. [比较运算符 & 相等](#比较运算符 & 相等)
  16. (代码)块
  17. 注释
  18. 空格
  19. 逗号
  20. 分号
  21. 类型转换
  22. 命名规则
  23. 存取器
  24. 事件
  25. jQuery
  26. [ECMAScript 5 兼容性](#ECMAScript 5兼容性)
  27. [ECMAScript 6+ 风格](#ECMAScript 6+ 风格)
  28. 测试
  29. 性能
  30. 资源
  31. 谁在使用?
  32. 翻译
  33. JavaScript编码规范指南
  34. 和我们聊聊JavaScript
  35. 贡献者
  36. 许可

类型

  • 1.1 原始类型: 存取原始类型直接作用于值本身.

    • string
    • number
    • boolean
    • null
    • undefined
    const foo = 1;
    let bar = foo;
    
    bar = 9;
    
    console.log(foo, bar); // => 1, 9

  • 1.2 复杂类型: 存取复杂类型作用于值的引用.

    • object
    • array
    • function
    const foo = [1, 2];
    const bar = foo;
    
    bar[0] = 9;
    
    console.log(foo[0], bar[0]); // => 9, 9

⬆ back to top

引用

  • 2.1 对引用使用const;避免使用var.eslint: prefer-const, no-const-assign

    原因:会确保你不会改变引用的指向,这可能会产生bug并且代码难以理解

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

  • 2.2 如果要改变引用的指向,使用let而非var.eslint: no-var jscs: disallowVar

    原因:let是块级作用于而var是函数作用域.

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

  • 2.3 注意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

⬆ back to top

对象

  • 3.1 使用字面语法创建对象. eslint: no-new-object

    // bad
    const item = new Object();
    
    // good
    const item = {};

  • 3.4 创建动态属性名字的对象时使用计算后的属性名.

    Why? 原因:允许你在一个地方定义一个对象的全部属性.

    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,
      name: 'San Francisco',
      [getKey('enabled')]: true,
    };

  • 3.5 使用对象方法简写. 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;
      },
    };

  • 3.6 使用简写属性. eslint: object-shorthand jscs: requireEnhancedObjectLiterals

    原因:书写描述更简短.

    const lukeSkywalker = 'Luke Skywalker';
    
    // bad
    const obj = {
      lukeSkywalker: lukeSkywalker,
    };
    
    // good
    const obj = {
      lukeSkywalker,
    };

  • 3.7 将简写属性统一放到对象声明开头.

    原因:容易区分使用简写的属性.

    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,
    };

原因:通常我们主观上认为更易读.有利于语法高亮,更容易被许多JS引擎优化.

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

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

  • 3.9 不要直接使用Object.prototype,hasOwnProperty, propertyIsEnumerableisPrototypeOf等方法.

原因:这些方法可能会被对象自身的同名属性覆盖-考虑{ hasOwnProperty: false }或者对象是null.

// bad
console.log(object.hasOwnProperty(key));

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

// best
const has = Object.prototype.hasOwnProperty; // cache the lookup once, in module scope.
/* or */
const has = require('has');

console.log(has.call(object, key));

⬆ back to top

数组

  • 4.1 使用字面量语法创建数组. eslint: no-array-constructor

    // bad
    const items = new Array();
    
    // good
    const items = [];

  • 4.2 使用 Array#push 而不是直接给数组赋值.

    const someStack = [];
    
    // bad
    someStack[someStack.length] = 'abracadabra';
    
    // good
    someStack.push('abracadabra');

  • 4.3 使用数组扩展运算符...拷贝数组.

    // bad
    const len = items.length;
    const itemsCopy = [];
    let i;
    
    for (i = 0; i < len; i++) {
      itemsCopy[i] = items[i];
    }
    
    // good
    const itemsCopy = [...items];

  • 4.4 将类数组对象转换成数组使用Array.from.

    const foo = document.querySelectorAll('.foo');
    const nodes = Array.from(foo);

  • 4.5 在数组方法的回调函数中使用return.如果函数体只有一条声明则可以省略return8.2. 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
    const flat = {};
    [[0, 1], [2, 3], [4, 5]].reduce((memo, item, index) => {
      const flatten = memo.concat(item);
      flat[index] = flatten;
    });
    
    // good
    const flat = {};
    [[0, 1], [2, 3], [4, 5]].reduce((memo, item, index) => {
      const flatten = memo.concat(item);
      flat[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;
    });

⬆ back to top

解构

  • 5.1 使用对象的多个属性时使用对象解构. 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}`;
    }

  • 5.2 使用数组解构. jscs: requireArrayDestructuring

    const arr = [1, 2, 3, 4];
    
    // bad
    const first = arr[0];
    const second = arr[1];
    
    // good
    const [first, second] = arr;

  • 5.3 对于多个返回值使用对象解构而不是数组解构. jscs: disallowArrayDestructuringReturn

    原因:可以非破坏性地随时增加或者改变属性顺序.

    // bad
    function processInput(input) {
      // then a miracle occurs
      return [left, right, top, bottom];
    }
    
    // the caller needs to think about the order of return data
    const [left, __, top] = processInput(input);
    
    // good
    function processInput(input) {
      // then a miracle occurs
      return { left, right, top, bottom };
    }
    
    // the caller selects only the data they need
    const { left, top } = processInput(input);

⬆ back to top

字符串

  • 6.1 字符串使用单引号 '' . eslint: quotes jscs: validateQuoteMarks

    // bad
    const name = "Capt. Janeway";
    
    // bad - template literals should contain interpolation or newlines
    const name = `Capt. Janeway`;
    
    // good
    const name = 'Capt. Janeway';

  • 6.2 一行超过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.';

  • 6.4 动态构建字符串时使用模板字符串而不是拼接. 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}?`;
    }

  • 6.5 不要对字符串使用eval(),漏洞太多.

  • 6.6 不要在字符串中使用不必要的转义字符. eslint: no-useless-escape

    原因:反斜线不利于阅读,应该只在必要的时候出现.

    // bad
    const foo = '\'this\' \i\s \"quoted\"';
    
    // good
    const foo = '\'this\' is "quoted"';
    const foo = `'this' is "quoted"`;

⬆ back to top

函数

  • 7.1 使用函数声明而非函数表达式. eslint: func-style 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 用圆括号包裹自执行匿名函数. eslint: wrap-iife jscs: requireParenthesesAroundIIFE

    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.

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

  • 7.3 不要在非函数块(if,while等)中声明函数.要将函数赋给变量.浏览器允许你这么做,但是处理方式不同,这不是好消息. eslint: no-loop-func

  • 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.

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

  • 7.5 不要将参数命名为 arguments. 会导致该参数的优先级高于每个函数作用域内原先存在的arguments对象.

    // bad
    function nope(name, options, arguments) {
      // ...stuff...
    }
    
    // good
    function yup(name, options, args) {
      // ...stuff...
    }

  • 7.6 不要使用 arguments, 使用扩展语法 ... . eslint: prefer-rest-params

    原因:...是你想获得的参数列表,因此,扩展语法的参数是真正的数组,而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 不要使用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');

  • 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

    原因:显然你无需使用上下文,很难结合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, 08, 05]));
    
    // good
    new Date(...[2016, 08, 05]);

⬆ back to top

箭头函数

  • 8.1 当你必须使用函数表达式(传递匿名函数)时,使用箭头函数标记. eslint: prefer-arrow-callback, arrow-spacing jscs: requireArrowFunctions

    原因:这会创建一个能在其中使用this上下文的函数,这是你想要的,语法也更明确.

    不适用的地方:如果有一个相当复杂的函数,应该把逻辑放到自己的函数声明里.

    // 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;
    });

  • 8.2 如果函数体只包含一条表达语句,可以省略花括号并使用隐式的return. 否则保留花括号并使用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
    [1, 2, 3].map((number, index) => ({
      index: number
    }));

  • 8.3 一旦语句跨多行,使用圆括号包裹以便更好阅读.

    原因:清晰展示了函数的开始和结束.

    // bad
    [1, 2, 3].map(number => 'As time went by, the string containing the ' +
      `${number} became much longer. So we needed to break it over multiple ` +
      'lines.'
    );
    
    // good
    [1, 2, 3].map(number => (
      `As time went by, the string containing the ${number} became much ` +
      'longer. So we needed to break it over multiple lines.'
    ));

  • 8.4 函数如果只有一个参数并且没用花括号,则省略圆括号. 否则总是使用圆括号包裹参数. 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’ve broken it ` +
      'over multiple lines!'
    ));
    
    // 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;
    });

  • 8.5 避免把箭头函数语法 (=>) 和比较运算符 (<=, >=)弄混. eslint: no-confusing-arrow

    // 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;
    };

⬆ back to top

类 & 构造函数

  • 9.1 总是使用 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;
      }
    }

  • 9.2 使用 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];
      }
    }

  • 9.3 方法可以返回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);

  • 9.4 在确保表现正常没有副作用的情况下可以重写传统的toString()方法.

    class Jedi {
      constructor(options = {}) {
        this.name = options.name || 'no name';
      }
    
      getName() {
        return this.name;
      }
    
      toString() {
        return `Jedi - ${this.getName()}`;
      }
    }

  • 9.5 如果未声明构造函数,则类会有一个默认的构造函数. 没必要用空的构造函数或者将其委托给父类. 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';
      }
    }

  • 9.6 避免类成员重复. eslint: no-dupe-class-members

    原因:重复的类成员声明会默认使用最后声明的-有重复值基本就是bug.

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

⬆ back to top

模块

  • 10.1 在非标准模块系统的基础上使用模块 (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;

  • 10.2 不要使用通配符导入.

    原因:这会确保你只有一个默认的export.

    // bad
    import * as AirbnbStyleGuide from './AirbnbStyleGuide';
    
    // good
    import AirbnbStyleGuide from './AirbnbStyleGuide';

  • 10.3 不要从import中export.

    原因:很显然有一个明确的方法来import和export会保持一致性.

    // bad
    // filename es6.js
    export { es6 as default } from './airbnbStyleGuide';
    
    // good
    // filename es6.js
    import { es6 } from './AirbnbStyleGuide';
    export default es6;

  • 10.4 只允许在一个地方从一个路径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';

  • 10.5 不要export可变的绑定值. eslint: import/no-mutable-exports

    原因:通常来说可变应该被避免,尤其是在export绑定值的时候.通常来说,这个技术只在常量引用被导出的时候使用.

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

  • 10.6 在单一expoort的模块中,建议export default而不是具名export. eslint: import/prefer-default-export

    // bad
    export function foo() {}
    
    // good
    export default function foo() {}

  • 10.7 将所有的import放在非import语句前. eslint: import/imports-first

    原因:由于import会被提前,将其全部置于顶部会避免意外行为.

    // bad
    import foo from 'foo';
    foo.init();
    
    import bar from 'bar';
    
    // good
    import foo from 'foo';
    import bar from 'bar';
    
    foo.init();

⬆ back to top

迭代器和生成器

  • 11.1 不要使用迭代器.建议使用JS更高优先级的函数代替for-infor-of循环. eslint: no-iterator no-restricted-syntax

    原因:这会强化不可变的规则.处理返回值的纯函数要比消除副作用容易.

    使用 map() / every() / filter() / find() / findIndex() / reduce() / some() / ... 来遍历数组, 用 Object.keys() / Object.values() / Object.entries() 来制造数组以便能对对象进行迭代.

    const numbers = [1, 2, 3, 4, 5];
    
    // bad
    let sum = 0;
    for (let num of numbers) {
      sum += num;
    }
    
    sum === 15;
    
    // good
    let sum = 0;
    numbers.forEach(num => sum += num);
    sum === 15;
    
    // best (use the functional force)
    const sum = numbers.reduce((total, num) => total + num, 0);
    sum === 15;

  • 11.2 现在不要使用生成器.

    原因:不能很好地转译为ES5.

  • 11.3 如果你非得使用生成器或者无视 建议, 请确保函数签名中的空格正确. eslint: generator-star-spacing

    原因:function*是同一个概念 - *不是function的修饰符,function*是不同于function的独特的构造函数.

    // bad
    function * foo() {
    }
    
    const bar = function * () {
    }
    
    const baz = function *() {
    }
    
    const quux = function*() {
    }
    
    function*foo() {
    }
    
    function *foo() {
    }
    
    // very bad
    function
    *
    foo() {
    }
    
    const wat = function
    *
    () {
    }
    
    // good
    function* foo() {
    }
    
    const foo = function* () {
    }

⬆ back to top

Properties

  • 12.1 访问属性时使用.. eslint: dot-notation jscs: requireDotNotation

    const luke = {
      jedi: true,
      age: 28,
    };
    
    // bad
    const isJedi = luke['jedi'];
    
    // good
    const isJedi = luke.jedi;

  • 12.2 当访问的属性是变量时使用 [] .

    const luke = {
      jedi: true,
      age: 28,
    };
    
    function getProp(prop) {
      return luke[prop];
    }
    
    const isJedi = getProp('jedi');

⬆ back to top

Variables

  • 13.1 总是使用 const 声明变量. 不这么做会导致全局变量问题. 要避免污染全局命名空间. eslint: no-undef prefer-const

    // bad
    superPower = new SuperPower();
    
    // good
    const superPower = new SuperPower();

  • 13.2 每个变量声明前都要使用const. eslint: one-var jscs: disallowMultipleVarDecl

    原因:这种方式更易添加变量声明,不用考虑将;变成,.用debugger逐个调试也很方便,而不是一次跳过所有变量.

    // bad
    const items = getItems(),
        goSportsTeam = true,
        dragonball = 'z';
    
    // bad
    // (compare to above, and try to spot the mistake)
    const items = getItems(),
        goSportsTeam = true;
        dragonball = 'z';
    
    // good
    const items = getItems();
    const goSportsTeam = true;
    const dragonball = 'z';

  • 13.3constlet 分别放到一起.

    原因:当需要给依赖前一个已经赋值的变量的变量赋值时很有用.

    // bad
    let i, len, dragonball,
        items = getItems(),
        goSportsTeam = true;
    
    // bad
    let i;
    const items = getItems();
    let dragonball;
    const goSportsTeam = true;
    let len;
    
    // good
    const goSportsTeam = true;
    const items = getItems();
    let dragonball;
    let i;
    let length;

  • 13.4 在需要的地方给变量赋值,但位置要合理.

    原因:letconst 是块级作用域而不是函数级作用域.

    // bad - unnecessary function call
    function checkName(hasName) {
      const name = getName();
    
      if (hasName === 'test') {
        return false;
      }
    
      if (name === 'test') {
        this.setName('');
        return false;
      }
    
      return name;
    }
    
    // good
    function checkName(hasName) {
      if (hasName === 'test') {
        return false;
      }
    
      const name = getName();
    
      if (name === 'test') {
        this.setName('');
        return false;
      }
    
      return name;
    }

  • 13.5 变量不要进行链式赋值.

    原因:变量链式赋值会创建隐藏的全局变量.

    // bad
    (function example() {
      // JavaScript interprets this as
      // let a = ( b = ( c = 1 ) );
      // The let keyword only applies to variable a; variables b and c become
      // global variables.
      let a = b = c = 1;
    }());
    
    console.log(a); // undefined
    console.log(b); // 1
    console.log(c); // 1
    
    // good
    (function example() {
      let a = 1;
      let b = a;
      let c = a;
    }());
    
    console.log(a); // undefined
    console.log(b); // undefined
    console.log(c); // undefined
    
    // the same applies for `const`

⬆ back to top

变量提升

  • 14.1 var声明会被提升到作用域的顶部, 但是赋值不会. constlet 声明有一个新的概念叫 临时死区 (TDZ). 了解 typeof不再安全很重要.

    // we know this wouldn't work (assuming there
    // is no notDefined global variable)
    function example() {
      console.log(notDefined); // => throws a ReferenceError
    }
    
    // creating a variable declaration after you
    // reference the variable will work due to
    // variable hoisting. Note: the assignment
    // value of `true` is not hoisted.
    function example() {
      console.log(declaredButNotAssigned); // => undefined
      var declaredButNotAssigned = true;
    }
    
    // the interpreter is hoisting the variable
    // declaration to the top of the scope,
    // which means our example could be rewritten as:
    function example() {
      let declaredButNotAssigned;
      console.log(declaredButNotAssigned); // => undefined
      declaredButNotAssigned = true;
    }
    
    // using const and let
    function example() {
      console.log(declaredButNotAssigned); // => throws a ReferenceError
      console.log(typeof declaredButNotAssigned); // => throws a ReferenceError
      const declaredButNotAssigned = true;
    }

  • 14.2 匿名函数表达式会提升变量名字而不是函数赋值.

    function example() {
      console.log(anonymous); // => undefined
    
      anonymous(); // => TypeError anonymous is not a function
    
      var anonymous = function () {
        console.log('anonymous function expression');
      };
    }

  • 14.3 具名函数表达式提升变量名字而不是函数名字或函数体.

    function example() {
      console.log(named); // => undefined
    
      named(); // => TypeError named is not a function
    
      superPower(); // => ReferenceError superPower is not defined
    
      var named = function superPower() {
        console.log('Flying');
      };
    }
    
    // the same is true when the function name
    // is the same as the variable name.
    function example() {
      console.log(named); // => undefined
    
      named(); // => TypeError named is not a function
    
      var named = function named() {
        console.log('named');
      }
    }

  • 14.4 函数声明会提升函数名和函数体.

    function example() {
      superPower(); // => Flying
    
      function superPower() {
        console.log('Flying');
      }
    }
  • 更多信息请参考 JavaScript Scoping & Hoisting by Ben Cherry.

⬆ back to top

比较运算符 & 相等

  • 15.1 使用 ===!==而非 ==!=. eslint: eqeqeq

  • 15.2 条件声明例如 if 会用 ToBoolean 这个抽象方法将表达式转成布尔值并遵循如下规则:

    • Objects evaluate to true
    • Undefined evaluates to false
    • Null evaluates to false
    • Booleans evaluate to the value of the boolean
    • Numbers evaluate to false if +0, -0, or NaN, otherwise true
    • Strings evaluate to false if an empty string '', otherwise true
    if ([0] && []) {
      // true
      // an array (even an empty one) is an object, objects will evaluate to true
    }

  • 15.3 使用简写.

    // bad
    if (name !== '') {
      // ...stuff...
    }
    
    // good
    if (name) {
      // ...stuff...
    }
    
    // bad
    if (collection.length > 0) {
      // ...stuff...
    }
    
    // good
    if (collection.length) {
      // ...stuff...
    }

  • 15.5 在用 casedefault 语句创建的包含有如下词语(如 let, const, functionclass)的代码块中使用花括号 .

原因:这些词语在整个switch中可见但是仅仅在当执行到case时被赋值的时候初始化.当多条case语句试图定义同一个变量时会导致问题.

eslint rules: no-case-declarations.

```javascript
// bad
switch (foo) {
  case 1:
    let x = 1;
    break;
  case 2:
    const y = 2;
    break;
  case 3:
    function f() {}
    break;
  default:
    class C {}
}

// good
switch (foo) {
  case 1: {
    let x = 1;
    break;
  }
  case 2: {
    const y = 2;
    break;
  }
  case 3: {
    function f() {}
    break;
  }
  case 4:
    bar();
    break;
  default: {
    class C {}
  }
}
```

  • 15.6 通常三元运算不应该被嵌套应该只是单行表达式.

    eslint rules: no-nested-ternary.

    // bad
    const foo = maybe1 > maybe2
      ? "bar"
      : value1 > value2 ? "baz" : null;
    
    // better
    const maybeNull = value1 > value2 ? 'baz' : null;
    
    const foo = maybe1 > maybe2
      ? 'bar'
      : maybeNull;
    
    // best
    const maybeNull = value1 > value2 ? 'baz' : null;
    
    const foo = maybe1 > maybe2 ? 'bar' : maybeNull;

  • 15.7 避免不必要的三元表达式.

    eslint rules: no-unneeded-ternary.

    // bad
    const foo = a ? a : b;
    const bar = c ? true : false;
    const baz = c ? false : true;
    
    // good
    const foo = a || b;
    const bar = !!c;
    const baz = !c;

⬆ back to top

##(代码)块

  • 16.1 多行代码块使用花括号.

    // bad
    if (test)
      return false;
    
    // good
    if (test) return false;
    
    // good
    if (test) {
      return false;
    }
    
    // bad
    function foo() { return false; }
    
    // good
    function bar() {
      return false;
    }

  • 16.2 如果使用ifelse多行代码块,把else放到和if块的闭合括号同一行. eslint: brace-style jscs: disallowNewlineBeforeBlockStatements

    // bad
    if (test) {
      thing1();
      thing2();
    }
    else {
      thing3();
    }
    
    // good
    if (test) {
      thing1();
      thing2();
    } else {
      thing3();
    }

⬆ back to top

注释

  • 17.1 多行注释使用 /** ... */ . 包含描述,指定所有参数的类型和值和返回值.

    // bad
    // make() returns a new element
    // based on the passed in tag name
    //
    // @param {String} tag
    // @return {Element} element
    function make(tag) {
    
      // ...stuff...
    
      return element;
    }
    
    // good
    /**
     * make() returns a new element
     * based on the passed in tag name
     *
     * @param {String} tag
     * @return {Element} element
     */
    function make(tag) {
    
      // ...stuff...
    
      return element;
    }

  • 17.2 单行注释使用 //. 在要注释部分的上边一行放置注释. 如果不是块的第一行则在注释前留一个空行.

    // bad
    const active = true;  // is current tab
    
    // good
    // is current tab
    const active = true;
    
    // bad
    function getType() {
      console.log('fetching type...');
      // set the default type to 'no type'
      const type = this._type || 'no type';
    
      return type;
    }
    
    // good
    function getType() {
      console.log('fetching type...');
    
      // set the default type to 'no type'
      const type = this._type || 'no type';
    
      return type;
    }
    
    // also good
    function getType() {
      // set the default type to 'no type'
      const type = this._type || 'no type';
    
      return type;
    }

  • 17.3 如果想表明这个问题以后会再次被查看或者给出了这个问题的解决方案,在注释前加上前缀FIXME或者TODO会有利于很快理解问题. 这些不同于一般的注释因为它们是可操作的. 操作是 FIXME: -- need to figure this outTODO: -- need to implement.

  • 17.4 使用 // FIXME: 来标注问题.

    class Calculator extends Abacus {
      constructor() {
        super();
    
        // FIXME: shouldn't use a global here
        total = 0;
      }
    }

  • 17.5 使用 // TODO: 来标明问题的解决方案.

    class Calculator extends Abacus {
      constructor() {
        super();
    
        // TODO: total should be configurable by an options param
        this.total = 0;
      }
    }

⬆ back to top

空格

  • 18.1 将软tab设置为两个空格. eslint: indent jscs: validateIndentation

    // bad
    function foo() {
    ∙∙∙∙const name;
    }
    
    // bad
    function bar() {
    ∙const name;
    }
    
    // good
    function baz() {
    ∙∙const name;
    }

  • 18.2 在起始花括号前加一个空格. eslint: space-before-blocks jscs: requireSpaceBeforeBlockStatements

    // bad
    function test(){
      console.log('test');
    }
    
    // good
    function test() {
      console.log('test');
    }
    
    // bad
    dog.set('attr',{
      age: '1 year',
      breed: 'Bernese Mountain Dog',
    });
    
    // good
    dog.set('attr', {
      age: '1 year',
      breed: 'Bernese Mountain Dog',
    });

  • 18.3 在控制语句的圆括号前加一个空格 (if, while 等). 在函数调用和声明中在参数列表和函数名间不要放置空格. eslint: keyword-spacing jscs: requireSpaceAfterKeywords

    // bad
    if(isJedi) {
      fight ();
    }
    
    // good
    if (isJedi) {
      fight();
    }
    
    // bad
    function fight () {
      console.log ('Swooosh!');
    }
    
    // good
    function fight() {
      console.log('Swooosh!');
    }

  • 18.5 用空行结束文件. eslint: eol-last

    // bad
    (function (global) {
      // ...stuff...
    })(this);
    // bad
    (function (global) {
      // ...stuff...
    })(this);
    
    // good
    (function (global) {
      // ...stuff...
    })(this);

  • 18.6 进行长的函数链式调用时使用缩进(超过两个方法的链式调用).为了强调该行是方法调用而不是新的语句声明要用.开头. eslint: newline-per-chained-call no-whitespace-before-property

    // bad
    $('#items').find('.selected').highlight().end().find('.open').updateCount();
    
    // bad
    $('#items').
      find('.selected').
        highlight().
        end().
      find('.open').
        updateCount();
    
    // good
    $('#items')
      .find('.selected')
        .highlight()
        .end()
      .find('.open')
        .updateCount();
    
    // bad
    const leds = stage.selectAll('.led').data(data).enter().append('svg:svg').classed('led', true)
        .attr('width', (radius + margin) * 2).append('svg:g')
        .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
        .call(tron.led);
    
    // good
    const leds = stage.selectAll('.led')
        .data(data)
      .enter().append('svg:svg')
        .classed('led', true)
        .attr('width', (radius + margin) * 2)
      .append('svg:g')
        .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
        .call(tron.led);
    
    // good
    const leds = stage.selectAll('.led').data(data);

  • 18.7 在代码块结束和下一个声明前留一个空行. jscs: requirePaddingNewLinesAfterBlocks

    // bad
    if (foo) {
      return bar;
    }
    return baz;
    
    // good
    if (foo) {
      return bar;
    }
    
    return baz;
    
    // bad
    const obj = {
      foo() {
      },
      bar() {
      },
    };
    return obj;
    
    // good
    const obj = {
      foo() {
      },
    
      bar() {
      },
    };
    
    return obj;
    
    // bad
    const arr = [
      function foo() {
      },
      function bar() {
      },
    ];
    return arr;
    
    // good
    const arr = [
      function foo() {
      },
    
      function bar() {
      },
    ];
    
    return arr;

  • 18.8 不用再代码块中使用空行填充. eslint: padded-blocks jscs: disallowPaddingNewlinesInBlocks

    // bad
    function bar() {
    
      console.log(foo);
    
    }
    
    // also bad
    if (baz) {
    
      console.log(qux);
    } else {
      console.log(foo);
    
    }
    
    // good
    function bar() {
      console.log(foo);
    }
    
    // good
    if (baz) {
      console.log(qux);
    } else {
      console.log(foo);
    }

  • 18.9 圆括号中不要添加括号. eslint: space-in-parens jscs: disallowSpacesInsideParentheses

    // bad
    function bar( foo ) {
      return foo;
    }
    
    // good
    function bar(foo) {
      return foo;
    }
    
    // bad
    if ( foo ) {
      console.log(foo);
    }
    
    // good
    if (foo) {
      console.log(foo);
    }

  • 18.12 避免一行代码超过100个字符(包括空格). 注意: above,不包括整体不应爱被分割的长字符串. eslint: max-len jscs: maximumLineLength

    原因:确保可读性和可维护性.

    // bad
    const foo = jsonData && jsonData.foo && jsonData.foo.bar && jsonData.foo.bar.baz && jsonData.foo.bar.baz.quux && jsonData.foo.bar.baz.quux.xyzzy;
    
    // bad
    $.ajax({ method: 'POST', url: 'https://airbnb.com/', data: { name: 'John' } }).done(() => console.log('Congratulations!')).fail(() => console.log('You have failed this city.'));
    
    // good
    const foo = jsonData
      && jsonData.foo
      && jsonData.foo.bar
      && jsonData.foo.bar.baz
      && jsonData.foo.bar.baz.quux
      && jsonData.foo.bar.baz.quux.xyzzy;
    
    // good
    $.ajax({
      method: 'POST',
      url: 'https://airbnb.com/',
      data: { name: 'John' },
    })
      .done(() => console.log('Congratulations!'))
      .fail(() => console.log('You have failed this city.'));

⬆ back to top

逗号

  • 19.1 不要用,作为行的开始 eslint: comma-style jscs: requireCommaBeforeLineBreak

    // bad
    const story = [
        once
      , upon
      , aTime
    ];
    
    // good
    const story = [
      once,
      upon,
      aTime,
    ];
    
    // bad
    const hero = {
        firstName: 'Ada'
      , lastName: 'Lovelace'
      , birthYear: 1815
      , superPower: 'computers'
    };
    
    // good
    const hero = {
      firstName: 'Ada',
      lastName: 'Lovelace',
      birthYear: 1815,
      superPower: 'computers',
    };

  • 19.2 结尾使用额外的逗号 eslint: comma-dangle jscs: requireTrailingComma

    原因:会让git diff更干净. 你不必担心老式浏览器的问题 结尾逗号问题因为Babel转译器会在转译后的代码中移除额外的逗号.

    // bad - git diff without trailing comma
    const hero = {
         firstName: 'Florence',
    -    lastName: 'Nightingale'
    +    lastName: 'Nightingale',
    +    inventorOf: ['coxcomb chart', 'modern nursing']
    };
    
    // good - git diff with trailing comma
    const hero = {
         firstName: 'Florence',
         lastName: 'Nightingale',
    +    inventorOf: ['coxcomb chart', 'modern nursing'],
    };
    
    // bad
    const hero = {
      firstName: 'Dana',
      lastName: 'Scully'
    };
    
    const heroes = [
      'Batman',
      'Superman'
    ];
    
    // good
    const hero = {
      firstName: 'Dana',
      lastName: 'Scully',
    };
    
    const heroes = [
      'Batman',
      'Superman',
    ];

⬆ back to top

分号

  • 20.1 需要使用分号 eslint: semi jscs: requireSemicolons

    // bad
    (function () {
      const name = 'Skywalker'
      return name
    })()
    
    // good
    (function () {
      const name = 'Skywalker';
      return name;
    }());
    
    // good, but legacy (guards against the function becoming an argument when two files with IIFEs are concatenated)
    ;(() => {
      const name = 'Skywalker';
      return name;
    }());

    更多.

⬆ back to top

类型转换

  • 21.1 在声明的开始部分进行类型强转.

  • 21.2 Strings:

    // => this.reviewScore = 9;
    
    // bad
    const totalScore = this.reviewScore + ''; // invokes this.reviewScore.valueOf()
    
    // bad
    const totalScore = this.reviewScore.toString(); // isn't guaranteed to return a string
    
    // good
    const totalScore = String(this.reviewScore);

  • 21.3 数字: 使用 Number 进行转换,使用带基数的 parseInt 对字符串进行转换. eslint: radix

    const inputValue = '4';
    
    // bad
    const val = new Number(inputValue);
    
    // bad
    const val = +inputValue;
    
    // bad
    const val = inputValue >> 0;
    
    // bad
    const val = parseInt(inputValue);
    
    // good
    const val = Number(inputValue);
    
    // good
    const val = parseInt(inputValue, 10);

  • 21.4 不管什么原因你使用了 parseInt,到达了性能瓶颈,你需要使用位运算性能原因, 请注释说明这么做的原因.

    // good
    /**
     * parseInt was the reason my code was slow.
     * Bitshifting the String to coerce it to a
     * Number made it a lot faster.
     */
    const val = inputValue >> 0;

  • 21.5 注意: 使用位运算请小心. 数字使用 64位值表示, 但是位运算只返回32位整数 (代码). 小于32位整数的位运算会导致不可预期的行为. 讨论. 最大的有符号整数是 2,147,483,647:

    2147483647 >> 0 //=> 2147483647
    2147483648 >> 0 //=> -2147483648
    2147483649 >> 0 //=> -2147483647

  • 21.6 布尔值:

    const age = 0;
    
    // bad
    const hasAge = new Boolean(age);
    
    // good
    const hasAge = Boolean(age);
    
    // best
    const hasAge = !!age;

⬆ back to top

命名规则

  • 22.1 避免单字母名字. 命名需有可描述性. eslint: id-length

    // bad
    function q() {
      // ...stuff...
    }
    
    // good
    function query() {
      // ..stuff..
    }

  • 22.2 命名对象,函数和实例时使用驼峰风格. eslint: camelcase jscs: requireCamelCaseOrUpperCaseIdentifiers

    // bad
    const OBJEcttsssss = {};
    const this_is_my_object = {};
    function c() {}
    
    // good
    const thisIsMyObject = {};
    function thisIsMyFunction() {}

  • 22.3 当命名构造函数或类的时候使用帕斯卡风格. eslint: new-cap jscs: requireCapitalizedConstructors

    // bad
    function user(options) {
      this.name = options.name;
    }
    
    const bad = new user({
      name: 'nope',
    });
    
    // good
    class User {
      constructor(options) {
        this.name = options.name;
      }
    }
    
    const good = new User({
      name: 'yup',
    });

  • 22.4 不要使用下划线开头或结尾. eslint: no-underscore-dangle jscs: disallowDanglingUnderscores

    原因:Javascript对于属性和方法并没有隐私的概念.尽管下划线开头通常意味着'private', 事实上这些属性是完全公开的,是公开API的一部分. 这种风格可能导致开发者错误地认为这不重要或者测试也不必要. 也就是说: 如果你想让其 “private”, 必须使其不可见.

    // bad
    this.__firstName__ = 'Panda';
    this.firstName_ = 'Panda';
    this._firstName = 'Panda';
    
    // good
    this.firstName = 'Panda';

  • 22.5 不要保存指向 this的引用. 使用箭头函数或 函数的#bind. jscs: disallowNodeTypes

    // bad
    function foo() {
      const self = this;
      return function () {
        console.log(self);
      };
    }
    
    // bad
    function foo() {
      const that = this;
      return function () {
        console.log(that);
      };
    }
    
    // good
    function foo() {
      return () => {
        console.log(this);
      };
    }

  • 22.6 基本的文件名应该和默认导出的名字刚好匹配.

    // file 1 contents
    class CheckBox {
      // ...
    }
    export default CheckBox;
    
    // file 2 contents
    export default function fortyTwo() { return 42; }
    
    // file 3 contents
    export default function insideDirectory() {}
    
    // in some other file
    // bad
    import CheckBox from './checkBox'; // PascalCase import/export, camelCase filename
    import FortyTwo from './FortyTwo'; // PascalCase import/filename, camelCase export
    import InsideDirectory from './InsideDirectory'; // PascalCase import/filename, camelCase export
    
    // bad
    import CheckBox from './check_box'; // PascalCase import/export, snake_case filename
    import forty_two from './forty_two'; // snake_case import/filename, camelCase export
    import inside_directory from './inside_directory'; // snake_case import, camelCase export
    import index from './inside_directory/index'; // requiring the index file explicitly
    import insideDirectory from './insideDirectory/index'; // requiring the index file explicitly
    
    // good
    import CheckBox from './CheckBox'; // PascalCase export/import/filename
    import fortyTwo from './fortyTwo'; // camelCase export/import/filename
    import insideDirectory from './insideDirectory'; // camelCase export/import/directory name/implicit "index"
    // ^ supports both insideDirectory.js and insideDirectory/index.js

  • 22.7 Use camelCase when you export-default a function当默认导出一个函数时使用驼峰风格. 文件名要和函数名相同.

    function makeStyleGuide() {
    }
    
    export default makeStyleGuide;

  • 22.8 当导出 构造函数 / 类 / 单例 / 函数库 / 对象时使用帕斯卡风格.

    const AirbnbStyleGuide = {
      es6: {
      }
    };
    
    export default AirbnbStyleGuide;

⬆ back to top

存取器

  • 23.1 属性的存取器不是必需的.

  • 23.2 不要使用JavaScript getters/setters 因为可能引起不可预期的副作用很难测试维护和理解. 相反,如果要使用存取器函数,使用 getVal() 和 setVal('hello').

    // bad
    class Dragon {
      get age() {
        // ...
      }
    
      set age(value) {
        // ...
      }
    }
    
    // good
    class Dragon {
      getAge() {
        // ...
      }
    
      setAge(value) {
        // ...
      }
    }

  • 23.3如果属性/方法是 boolean, 使用 isVal()hasVal()方法.

    // bad
    if (!dragon.age()) {
      return false;
    }
    
    // good
    if (!dragon.hasAge()) {
      return false;
    }

  • 23.4 也可以创建 get() 和 set() 函数, 但要保持一直.

    class Jedi {
      constructor(options = {}) {
        const lightsaber = options.lightsaber || 'blue';
        this.set('lightsaber', lightsaber);
      }
    
      set(key, val) {
        this[key] = val;
      }
    
      get(key) {
        return this[key];
      }
    }

⬆ back to top

事件

  • 24.1 当将数据和事件绑定时 (不论是 DOM 事件还是其他像Backbone一类的事件), 传摘要值而不是原始值. 这会允许接下来的修改者不用查找和更新事件的每一个处理器就可以给事件添加更多的数据,不要使用下边的:

    // bad
    $(this).trigger('listingUpdated', listing.id);
    
    ...
    
    $(this).on('listingUpdated', (e, listingId) => {
      // do something with listingId
    });

    建议:

    // good
    $(this).trigger('listingUpdated', { listingId: listing.id });
    
    ...
    
    $(this).on('listingUpdated', (e, data) => {
      // do something with data.listingId
    });

⬆ back to top

jQuery

  • 25.1$为前缀命名jQuery对象变量. jscs: requireDollarBeforejQueryAssignment

    // bad
    const sidebar = $('.sidebar');
    
    // good
    const $sidebar = $('.sidebar');
    
    // good
    const $sidebarBtn = $('.sidebar-btn');

  • 25.2 缓存jQuery选择器的查询结果.

    // bad
    function setSidebar() {
      $('.sidebar').hide();
    
      // ...stuff...
    
      $('.sidebar').css({
        'background-color': 'pink'
      });
    }
    
    // good
    function setSidebar() {
      const $sidebar = $('.sidebar');
      $sidebar.hide();
    
      // ...stuff...
    
      $sidebar.css({
        'background-color': 'pink'
      });
    }

  • 25.3 DOM 查询使用后代选择器 $('.sidebar ul') 或者 父类 > 子类 $('.sidebar > ul')选择器. jsPerf

  • 25.4 范围内 jQuery 对象查询使用 find .

    // bad
    $('ul', '.sidebar').hide();
    
    // bad
    $('.sidebar').find('ul').hide();
    
    // good
    $('.sidebar ul').hide();
    
    // good
    $('.sidebar > ul').hide();
    
    // good
    $sidebar.find('ul').hide();

⬆ back to top

ECMAScript 5 兼容性

⬆ back to top

ECMAScript 6 特性

  • 27.1 这是不同ES6特性的链接集合.
  1. 箭头函数
  2. 对象简写
  3. Object Concise
  4. 对象计算属性
  5. 模板字符串
  6. 解构
  7. 默认参数
  8. 扩展运算符
  9. 数组展开
  10. Let 和 Const
  11. 迭代器和生成器
  12. 模块

⬆ back to top

测试

  • 28.1 建议

    function foo() {
      return true;
    }

  • 28.2 不要这么做,很严重:
  • 不论你用哪一个测试框架,都应该写测试用例!
  • 尽力写一些简洁的函数, 使改动数据的部分最小化.
  • 小心使用 stubs 和 mocks - 它们会使测试变得脆弱.
  • 我们在Airbnb中主要使用 mocha. tape 有时也用于小的独立模块.
  • 100%的测试覆盖率是需要努力达成的目标,即使这是不切实际的.
  • 无论何时修复bug, 写回归测试. 没有回归测试的bug修复几乎会在将在再次出现.

⬆ back to top

性能

⬆ back to top

资源

学习 ES6

阅读

工具

其他编码规范指南

其他风格

更深的阅读

书籍

博客

播客

⬆ back to top

谁在使用

这是一份使用这份编码规范的组织列表.给我们提PR我们会把你加到这份列表里.

⬆ back to top

翻译

其他语言的版本:

JavaScript编码规范指南

和我们聊聊JavaScript

贡献者

许可

(The MIT License)

Copyright (c) 2014-2016 Airbnb

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

⬆ back to top

修改

我们鼓励你fork这份指南并改变规则来适应你团队的风格.你还可以列出一些修改补充.这可以让你不用处理合并冲突就可以定期升级编码规范指南

};

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.