npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

ys7-style

v1.0.0

Published

A mostly reasonable approach to JavaScript.

Downloads

3

Readme

ys7 JavaScript Style Guide

build

目录

  1. 类型
  2. 引用
  3. 对象
  4. 数组
  5. 解构
  6. 字符串
  7. 函数
  8. 箭头函数
  9. 构造函数
  10. 模块
  11. Iterators & Generators
  12. 属性
  13. 变量
  14. 提升
  15. 比较运算符 & 等号
  16. 代码块
  17. 注释
  18. 空白
  19. 逗号
  20. 分号
  21. 类型转换
  22. 命名规则
  23. 存取器
  24. 事件
  25. jQuery
  26. ECMAScript 5 兼容性
  27. ECMAScript 6 编码规范
  28. 测试
  29. 性能
  30. 资源
  31. 使用人群
  32. 翻译
  33. JavaScript 编码规范说明
  34. 一起来讨论 JavaScript
  35. Contributors
  36. License

类型

  • 1.1 基本类型: 直接存取基本类型。

    • 字符串
    • 数值
    • 布尔类型
    • null
    • undefined
    const foo = 1;
    let bar = foo;
    
    bar = 9;
    
    console.log(foo, bar); // => 1, 9
  • 1.2 引用类型: 通过引用的方式存取复杂类型。

    • 对象
    • 数组
    • 函数
    const foo = [1, 2];
    const bar = foo;
    
    bar[0] = 9;
    
    console.log(foo[0], bar[0]); // => 9, 9

引用

  • 2.1 对所有的引用使用 const ;不要使用 var

    为什么?这能确保你无法对引用重新赋值,也不会导致出现 bug 或难以理解。

    // bad
    var a = 1;
    var b = 2;
    
    // good
    const a = 1;
    const b = 2;
  • 2.2 如果你一定需要可变动的引用,使用 let 代替 var

    为什么?因为 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 和 let 只存在于它们被定义的区块内。
    {
      let a = 1;
      const b = 1;
    }
    console.log(a); // ReferenceError
    console.log(b); // ReferenceError

对象

  • 3.1 使用字面值创建对象。

    // bad
    const item = new Object();
    
    // good
    const item = {};
  • 3.2 如果你的代码在浏览器环境下执行,别使用 保留字 作为键值。这样的话在 IE8 不会运行。 更多信息。 但在 ES6 模块和服务器端中使用没有问题。

    // bad
    const superman = {
      default: { clark: 'kent' },
      private: true,
    };
    
    // good
    const superman = {
      defaults: { clark: 'kent' },
      hidden: true,
    };
  • 3.3 使用同义词替换需要使用的保留字。

    // bad
    const superman = {
      class: 'alien',
    };
    
    // bad
    const superman = {
      klass: 'alien',
    };
    
    // good
    const superman = {
      type: 'alien',
    };
  • 3.4 创建有动态属性名的对象时,使用可被计算的属性名称。

    为什么?因为这样可以让你在一个地方定义所有的对象属性。

    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 使用对象方法的简写。

    // 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 使用对象属性值的简写。

    为什么?因为这样更短更有描述性。

  • 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,
      twoJedisWalkIntoACantina: 2,
      lukeSkywalker,
      episodeThree: 3,
      mayTheFourth: 4,
      anakinSkywalker,
    };
    
    // good
    const obj = {
      lukeSkywalker,
      anakinSkywalker,
      episodeOne: 1,
      twoJedisWalkIntoACantina: 2,
      episodeThree: 3,
      mayTheFourth: 4,
    };
  • 3.8 只对无效的标识符使用引号.

    为什么?通常我们认为这样做可以有利于代码阅读,他有助于代码高亮,而且很多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, propertyIsEnumerable, 和 isPrototypeOf.

    为什么?这些方法使用在对象属性上会有问题,考虑下如果这个对象是{ hasOwnProperty: false }或者是由null创建(Object.create(null)).那就不能使用hasOwnProperty这些方法了.

数组

  • 4.1 使用字面值创建数组。

    // bad
    const items = new Array();
    
    // good
    const items = [];
  • 4.2 向数组添加元素时使用 Arrary#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 += 1) {
      itemsCopy[i] = items[i];
    }
    
    // good
    const itemsCopy = [...items];
  • 4.4 使用 Array#from 把一个类数组对象转换成数组。

    const foo = document.querySelectorAll('.foo');
    const nodes = Array.from(foo);
  • 4.5 在Array的方法回调中使用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;
    });

解构

  • 5.1 使用解构存取和使用多属性对象。

    为什么?因为解构能减少临时引用属性。

    // bad
    function getFullName(user) {
      const firstName = user.firstName;
      const lastName = user.lastName;
    
      return `${firstName} ${lastName}`;
    }
    
    // good
    function getFullName(obj) {
      const { firstName, lastName } = obj;
      return `${firstName} ${lastName}`;
    }
    
    // best
    function getFullName({ firstName, lastName }) {
      return `${firstName} ${lastName}`;
    }
  • 5.2 对数组使用解构赋值。

    const arr = [1, 2, 3, 4];
    
    // bad
    const first = arr[0];
    const second = arr[1];
    
    // good
    const [first, second] = arr;
  • 5.3 需要回传多个值时,使用对象解构,而不是数组解构。

    为什么?增加属性或者改变排序不会改变调用时的位置。

    // 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, right } = processInput(input);

字符串

  • 6.1 字符串使用单引号 ''

    // bad
    const name = "Capt. Janeway";
    
    // good
    const name = 'Capt. Janeway';
  • 6.2 字符串超过 80 个字节应该使用字符串连接号换行。

  • 6.3 注:过度使用字串连接符号可能会对性能造成影响。jsPerf讨论.

    // 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 程序化生成字符串时,使用模板字符串代替字符串连接。

    为什么?模板字符串更为简洁,更具可读性。

    // bad
    function sayHi(name) {
      return 'How are you, ' + name + '?';
    }
    
    // bad
    function sayHi(name) {
      return ['How are you, ', name, '?'].join();
    }
    
    // good
    function sayHi(name) {
      return `How are you, ${name}?`;
    }
  • 6.5 永远不要在string上使用evel(),它会引起许多问题。

  • 6.6 不要在string上使用不必要的转译词。

    为什么?反斜杠影响可读性,非必要不要使用。

    ```
    // bad
    const foo = '\'this\' \i\s \"quoted\"';
        
    // good
    const foo = '\'this\' is "quoted"';
    const foo = `my name is '${name}'`;
    ```

函数

  • 7.1 使用函数声明代替函数表达式。

    为什么?因为函数声明是可命名的,所以他们在调用栈中更容易被识别。此外,函数声明会把整个函数提升(hoisted),而函数表达式只会把函数的引用变量名提升。这条规则使得箭头函数可以取代函数表达式。

    // bad
    const foo = function () {
    };
    
    // good
    function foo() {
    }
  • 7.2 在立即调用的函数表达式外包装一层:

    // 立即调用的函数表达式 (IIFE)
    (() => {
      console.log('Welcome to the Internet. Please follow me.');
    })();
  • 7.3 永远不要在一个非函数代码块(ifwhile 等)中声明一个函数,把那个函数赋给一个变量。浏览器允许你这么做,但它们的解析表现不一致。

  • 7.4 注意: ECMA-262 把 block 定义为一组语句。函数声明不是语句。阅读 ECMA-262 关于这个问题的说明

    // 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。可以选择 rest 语法 ... 替代。

    为什么?使用 ... 能明确你要传入的参数。另外 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) {
      // 不!我们不应该改变函数参数。
      // 更加糟糕: 如果参数 opts 是 false 的话,它就会被设定为一个对象。
      // 但这样的写法会造成一些 Bugs。
      //(译注:例如当 opts 被赋值为空字符串,opts 仍然会被下一行代码设定为一个空对象。)
      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来构建一个新函数。

    为什么?以这种方式构建函数类似将使用evel来构建,会引起漏洞。

    // bad
    var add = new Function('a', 'b', 'return a + b');
       
    // still bad
    var subtract = Function('a', 'b', 'return a - b');
  • 7.11 在函数名字前添加一个空格。

    // bad
    const f = function(){};
    const g = function (){};
    const h = function() {};
         
    // good
    const x = function () {};
    const y = function a() {};
  • 7.12 永远不要更改参数。

    为什么?操作以传入的对象会在引用函数中引起无法预想的副作用,

    // bad
    function f1(obj) {
      obj.key = 1;
    };
         
    // good
    function f2(obj) {
      const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1;
    };
  • 7.13 永远不要对参数进行赋值。

    // 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 使用扩展操作符...代替call函数。

    为什么?这种方式更加的简洁,你不需要提供一个上下文,也不需要费劲的使用apply来构建。

    // 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]);
  • 7.15 拥有多个复杂参数的时候,应该将每个参数作为一行,并在最后加上逗号。

    // bad
    function foo(bar,
                 baz,
                 quux) {
      // body
    }
         
    // good
    function foo(
      bar,
      baz,
      quux,
    ) {
      // body
    }
         
    // bad
    console.log(foo,
      bar,
      baz);
         
    // good
    console.log(
      foo,
      bar,
      baz,
    );

箭头函数

  • 8.1 当你必须使用函数表达式(或传递一个匿名函数)时,使用箭头函数符号。

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

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

    // 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 都省略掉。如果不是,那就不要省略。

    为什么?语法糖。在链式调用中可读性很高。

    // good
    [1, 2, 3].map(x => x * x);
    
    // good
    [1, 2, 3].reduce((total, n) => {
      return total + n;
    }, 0);
  • 8.3 如果表达式有多行,就将其放在一对括号里面增加其可读性

    为什么?这样可以清晰的现实函数开始与结束的地方。

    // bad
    ['get', 'post', 'put'].map(httpMethod => Object.prototype.hasOwnProperty.call(
        httpMagicObjectWithAVeryLongName,
        httpMethod
      )
    );
        
    // good
    ['get', 'post', 'put'].map(httpMethod => (
      Object.prototype.hasOwnProperty.call(
        httpMagicObjectWithAVeryLongName,
        httpMethod
      )
    ));
  • 8.4 如果你的函数只有一个简单的参数,而且也没有使用大括号,那就省略参数的圆括号,否则的话就在参数上使用括号。

    为什么?更加的清晰。

    // 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;
    });
    • 8.5 避免混用箭头函数=>和大小比较>=<=
    // 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;
    };

类与构造器

  • 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 继承。

    为什么?因为 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 类如果没有特别定义都会有一个默认的构造函数,设置一个空的构造函数或者只是代表一个父类,是没有必要的。

    // 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 避免类成员的重复。

    为什么?重复的声明类成员会默认使用最后一个。拥有重复成员本来就是错的。

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

模块

  • 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 不要使用通配符 import。

    为什么?这样能确保你只有一个默认 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 一个地址只在一个地方导入inmport

    为什么?在多个地方导入相同地址的会使得代码难以维护。

    // 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 不要导出易变的绑定。

    为什么?通常情况下要避免导出易变的绑定,但在特殊情况下可以使用这种技术。一般来说,只有不变的引用可以导出。

    // bad
    let foo = 3;
    export { foo }
    
    // good
    const foo = 3;
    export { foo }
  • 10.6 只有单一导出的模块最好使用default而不是以名称导出。

    // bad
    export function foo() {}
    
    // good
    export default function foo() {}
  • 10.7 将所有的import语句放在非import语句之前。

    为什么?由于导入提升的缘故。把他们放在顶部有助于防止意外的行为。

    // bad
    import foo from 'foo';
    foo.init();
         
    import bar from 'bar';
         
    // good
    import foo from 'foo';
    import bar from 'bar';
         
    foo.init();
- [10.8](#10.8) 多行导入应该像数组和对象导入一样使用缩进的方式导入。

 > 为什么?遵循花括号的使用的风格,。

    ```javascript
    // bad
    import foo from 'foo';
    foo.init();
    
    import bar from 'bar';
    
    // good
    import foo from 'foo';
    import bar from 'bar';
    
    foo.init();
    ```
- [10.9](#10.9) 在导入函数中禁止使用Webpack加载器的代码。

 > 为什么?webpack加载器可以在`webpack.config.js`中设置。

    ```javascript
    // 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';
    ```
    

迭代器和生成器

  • 11.1 不要使用迭代器。使用高阶函数例如 map()reduce() 替代 for-of

    为什么?这加强了我们不变的规则。处理纯函数的回调值更易读,这比它带来的副作用更重要。

    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 现在还不要使用 generators。

    为什么?因为它们现在还没法很好地编译到 ES5。 (译者注:目前(2016/03) Chrome 和 Node.js 的稳定版本都已支持 generators)

属性

  • 12.1 使用 . 来访问对象的属性。

    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');

变量

  • 13.1 一直使用 const 来声明变量,如果不这样做就会产生全局变量。我们需要避免全局命名空间的污染。地球队长已经警告过我们了。(译注:全局,global 亦有全球的意思。地球队长的责任是保卫地球环境,所以他警告我们不要造成「全球」污染。)

    // bad
    superPower = new SuperPower();
    
    // good
    const superPower = new SuperPower();
  • 13.2 使用 const 声明每一个变量。

    为什么?增加新变量将变的更加容易,而且你永远不用再担心调换错 ;,

    // 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.3 将所有的 constlet 分组

    为什么?当你需要把已赋值变量赋值给未赋值变量时非常有用。

    // 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 是块级作用域而不是函数作用域。

    // good
    function() {
      test();
      console.log('doing stuff..');
    
      //..other stuff..
    
      const name = getName();
    
      if (name === 'test') {
        return false;
      }
    
      return name;
    }
    
    // bad - unnecessary function call
    function(hasName) {
      const name = getName();
    
      if (!hasName) {
        return false;
      }
    
      this.setFirstName(name);
    
      return true;
    }
    
    // good
    function(hasName) {
      if (!hasName) {
        return false;
      }
    
      const name = getName();
      this.setFirstName(name);
    
      return true;
    }
  • 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`
  • 13.6 避免使用一元的增加++和减少--

    为什么?更具eslint的文档,一元的增加与减少会遭受自动的添加分号,而在在程序中会引起静默的错误,使用num += 1来代替一元的增减。

    // bad
        
    let array = [1, 2, 3];
    let num = 1;
    num++;
    --num;
        
    let sum = 0;
    let truthyCount = 0;
    for(let i = 0; i < array.length; i++){
    let value = array[i];
    sum += value;
    if (value) {
      truthyCount++;
    }
    }
        
    // good
        
    let array = [1, 2, 3];
    let num = 1;
    num += 1;
    num -= 1;
        
    const sum = array.reduce((a, b) => a + b, 0);
    const truthyCount = array.filter(Boolean).length;

变量提升

  • 14.1 var 声明会被提升至该作用域的顶部,但它们赋值不会提升。letconst 被赋予了一种称为「暂时性死区(Temporal Dead Zones, TDZ)」的概念。这对于了解为什么 type of 不再安全相当重要。

    // 我们知道这样运行不了 
    // (假设 notDefined 不是全局变量)
    function example() {
      console.log(notDefined); // => throws a ReferenceError
    }
    
    // 由于变量提升的原因,
    // 在引用变量后再声明变量是可以运行的。
    // 注:变量的赋值 `true` 不会被提升。
    function example() {
      console.log(declaredButNotAssigned); // => undefined
      var declaredButNotAssigned = true;
    }
    
    // 编译器会把函数声明提升到作用域的顶层,
    // 这意味着我们的例子可以改写成这样:
    function example() {
      let declaredButNotAssigned;
      console.log(declaredButNotAssigned); // => undefined
      declaredButNotAssigned = true;
    }
    
    // 使用 const 和 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');
      }
    }
  • 想了解更多信息,参考 Ben CherryJavaScript Scoping & Hoisting

比较运算符 & 等号

  • 15.1 优先使用 ===!== 而不是 ==!=.

  • 15.2 条件表达式例如 if 语句通过抽象方法 ToBoolean 强制计算它们的表达式并且总是遵守下面的规则:

    • 对象 被计算为 true
    • Undefined 被计算为 false
    • Null 被计算为 false
    • 布尔值 被计算为 布尔的值
    • 数字 如果是 +0、-0、或 NaN 被计算为 false, 否则为 true
    • 字符串 如果是空字符串 '' 被计算为 false,否则为 true
    if ([0]) {
      // true
      // An array is an object, objects 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.4 想了解更多信息,参考 Angus Croll 的 Truth Equality and JavaScript

  • 15.5 在使用switch-case语句的时候,加上default,并在case后的语句使用花括号。

    // 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 三元表达式不应该被嵌套,而且应该放在一行。

    // 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 避免不必要的三元表达式。

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

代码块

  • 16.1 使用大括号包裹所有的多行代码块。

    // bad
    if (test)
      return false;
    
    // good
    if (test) return false;
    
    // good
    if (test) {
      return false;
    }
    
    // bad
    function() { return false; }
    
    // good
    function() {
      return false;
    }
  • 16.2 如果通过 ifelse 使用多行代码块,把 else 放在 if 代码块关闭括号的同一行。

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

注释

  • 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;
    }
  • 17.3 给注释增加 FIXMETODO 的前缀可以帮助其他开发者快速了解这是一个需要复查的问题,或是给需要实现的功能提供一个解决方式。这将有别于常见的注释,因为它们是可操作的。使用 FIXME -- need to figure this out 或者 TODO -- need to implement

  • 17.4 使用 // FIXME: 标注问题。

    class Calculator {
      constructor() {
        // FIXME: shouldn't use a global here
        total = 0;
      }
    }
  • 17.5 使用 // TODO: 标注问题的解决方式。

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

空白

  • 18.1 使用 4 个空格作为缩进。

    // bad
    function() {
    ∙∙const name;
    }
    
    // bad
    function() {
    ∙const name;
    }
    
    // good
    function() {
    ∙∙∙∙const name;
    }
  • 18.2 在花括号前放一个空格。

    // 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 在控制语句(ifwhile 等)的小括号前放一个空格。在函数调用及声明中,不在函数的参数列表前加空格。

    // bad
    if(isJedi) {
      fight ();
    }
    
    // good
    if (isJedi) {
      fight();
    }
    
    // bad
    function fight () {
      console.log ('Swooosh!');
    }
    
    // good
    function fight() {
      console.log('Swooosh!');
    }
  • 18.4 使用空格把运算符隔开。

    // bad
    const x=y+5;
    
    // good
    const x = y + 5;
  • 18.5 在文件末尾插入一个空行。

    // bad
    (function(global) {
      // ...stuff...
    })(this);
    // bad
    (function(global) {
      // ...stuff...
    })(this);↵
    ↵
    // good
    (function(global) {
      // ...stuff...
    })(this);↵
  • 18.5 在使用长方法链时进行缩进。使用前面的点 . 强调这是方法调用而不是新语句。

    // 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').class('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);
  • 18.6 在块末和新语句前插入空行。

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

逗号

  • 19.1 行首逗号:不需要

    // 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 增加结尾的逗号: 需要

    为什么? 这会让 git diffs 更干净。另外,像 babel 这样的转译器会移除结尾多余的逗号,也就是说你不必担心老旧浏览器的尾逗号问题

    // bad - git diff without trailing comma
    const hero = {
         firstName: 'Florence',
    -    lastName: 'Nightingale'
    +    lastName: 'Nightingale',
    +    inventorOf: ['coxcomb graph', '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',
    ];

分号

  • 20.1 使用分号

    // bad
    (function() {
      const name = 'Skywalker'
      return name
    })()
    
    // good
    (() => {
      const name = 'Skywalker';
      return name;
    })();
    
    // good (防止函数在两个 IIFE 合并时被当成一个参数)
    ;(() => {
      const name = 'Skywalker';
      return name;
    })();

    Read more.

类型转换

  • 21.1 在语句开始时执行类型转换。

  • 21.2 字符串:

    //  => this.reviewScore = 9;
    
    // bad
    const totalScore = this.reviewScore + '';
    
    // good
    const totalScore = String(this.reviewScore);
  • 21.3 对数字使用 parseInt 转换,并带上类型转换的基数。

    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 导致我的程序变慢,
     * 改成使用位操作转换数字快多了。
     */
    const val = inputValue >> 0;
  • 21.5 注: 小心使用位操作运算符。数字会被当成 64 位值,但是位操作运算符总是返回 32 位的整数(参考)。位操作处理大于 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);
    
    // good
    const hasAge = !!age;

命名规则

  • 22.1 避免单字母命名。命名应具备描述性。

    // bad
    function q() {
      // ...stuff...
    }
    
    // good
    function query() {
      // ..stuff..
    }
  • 22.2 使用驼峰式命名对象、函数和实例。

    // bad
    const OBJEcttsssss = {};
    const this_is_my_object = {};
    function c() {}
    
    // good
    const thisIsMyObject = {};
    function thisIsMyFunction() {}
  • 22.3 使用帕斯卡命名构造函数或类。

    // 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 使用下划线 _ 开头命名私有属性。

    为什么?JavaScript 并没有私有属性或私有方法的概念。虽然使用下划线是表示「私有」的一种共识,但实际上这些属性是完全公开的,它本身就是你公共接口的一部分。这种习惯或许会导致开发者错误的认为改动它不会造成破坏或者不需要去测试。长话短说:如果你想要某处为「私有」,它必须不能是显式提出的。

    // bad
    this.__firstName__ = 'Panda';
    this._firstName_ = 'Panda';
    
    // good
    this.firstName = 'Panda';
  • 22.5 别保存 this 的引用。使用箭头函数或 Function#bind。

    // 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 contents
    class CheckBox {
      // ...
    }
    export default CheckBox;
    
    // in some other file
    // bad
    import CheckBox from './checkBox';
    
    // bad
    import CheckBox from './check_box';
    
    // good
    import CheckBox from './CheckBox';
  • 22.7 当你导出默认的函数时使用驼峰式命名。你的文件名必须和函数名完全保持一致。

    function makeStyleGuide() {
    }
    
    export default makeStyleGuide;
  • 22.8 当你导出单例、函数库、空对象时使用帕斯卡式命名。

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

存取器

  • 23.1 属性的存取函数不是必须的。

  • 23.2 如果你需要存取函数时使用 getVal()setVal('hello')

    // bad
    dragon.age();
    
    // good
    dragon.getAge();
    
    // bad
    dragon.age(25);
    
    // good
    dragon.setAge(25);
  • 23.3 如果属性是布尔值,使用 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];
      }
    }

事件

  • 24.1 当给事件附加数据时(无论是 DOM 事件还是私有事件),传入一个哈希而不是原始值。这样可以让后面的贡献者增加更多数据到事件数据而无需找出并更新事件的每一个处理器。例如,不好的写法:

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

    更好的写法:

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

jQuery

  • 25.1 使用 $ 作为存储 jQuery 对象的变量名前缀。

    // bad
    const sidebar = $('.sidebar');
    
    // good
    const $sidebar = $('.sidebar');
  • 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();

ECMAScript 5 兼容性

ECMAScript 6 规范

  • 27.1 以下是链接到 ES6 的各个特性的列表。
  1. Arrow Functions
  2. Classes
  3. Object Shorthand
  4. Object Concise
  5. Object Computed Properties
  6. Template Strings
  7. Destructuring
  8. Default Parameters
  9. Rest
  10. Array Spreads
  11. Let and Const
  12. Iterators and Generators
  13. Modules

测试

  • 28.1 需要.

    function() {
      return true;
    }

性能

⬆ 返回目录

资源

Learning ES6

Read This

Tools

Other Styleguides

Other Styles

Further Reading

Books

Blogs

};