Blog Logo

ES6标准入门

写于2017-03-19 15:36 阅读耗时47分钟 阅读量


本文章是本人通过学习阮一峰的《ES6标准入门》这本书所做的笔记和介绍。

ES6


1.什么是ES6?

ES6是ECMAScript6的简称,是JavaScript语言的下一代标准,已于2015年6月正式发布。 ECMAScript和JavaScript的关系是,前者是后者的规格,后者是前者的一种实现。因为ECMAScript标准除了JavaScript语言用到外,还有 JScript和ActionScript。

ES6从开始制定到最后发布,整整用了15年。 关于各大浏览器最新版本对ES6的支持,可以参阅http://kangax.github.io/compat-table/es6/。随着时间的推移,支持度已经越来越高,ES6的大部分特性都实现了。

Node.js是JavaScript语言的服务器运行环境,对ES6的支持度比浏览器更高。

**Babel**是一个广为使用的ES6转码器,可以将ES6代码转为JavaScript代码,从而在浏览器或其他环境执行。


2.Airbnb的JavaScript风格规范

书中内容主要讲解ES6语法,也特别的细致,在这里就不一一说明了。我们直接用ES6语法去替代之前的语法。 Airbnb原文地址::https://github.com/airbnb/javascript

用更合理的方式写 JavaScript: 翻译自 Airbnb JavaScript Style Guide

目录

  1. 类型
  2. 参数
  3. 对象
  4. 数组
  5. 解构赋值
  6. 字符串
  7. 函数
  8. 箭头函数
  9. Class
  10. 模块
  11. 迭代器及生成器
  12. 属性
  13. 变量
  14. 提升
  15. 条件式与等号
  16. 区块
  17. 注解
  18. 空格
  19. 逗号
  20. 分号
  21. 类型转换
  22. 命名规则
  23. 存取器
  24. 事件
  25. jQuery

类型

  • 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

⬆ 回到顶端


参数

  • 2.1 对于所有的参数使用 const;避免使用 var

    // bad
    var a = 1;
    var b = 2;
    
    // good
    const a = 1;
    const b = 2;
  • 2.2 如果你需要可变动的参数,使用 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 如果对象的属性名是动态的,可以在创建对象时使用属性表达式定义。

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

    // bad
    const atom = {
      value: 1,
    
      addValue: function (value) {
        return atom.value + value;
      },
    };
    
    // good
    const atom = {
      value: 1,
    
      addValue(value) {
        return atom.value + value;
      },
    };

  • 3.4 使用属性值的简写。

    const lukeSkywalker = 'Luke Skywalker';
    
    // bad
    const obj = {
      lukeSkywalker: lukeSkywalker,
    };
    
    // good
    const obj = {
      lukeSkywalker,
    };
  • 3.5 在声明对象开始时将您的简写的属性进行分组。

    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,
    };
  • 3.6 只引用无效标识符的属性。

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

// good
const good = {
  foo: 3,
  bar: 4,
  'data-blah': 5,
};
  • 3.7 不要直接调用Object.prototype方法,例如hasOwnProperty,propertyIsEnumerable和isPrototypeOf。

    // 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 */
    import has from 'has';
    // ...
    console.log(has.call(object, key));
  • 3.8 对象尽量静态化,一旦定义,就不得随意添加新的属性。如果添加属性不可避免,要使用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 }

⬆ 回到顶端


数组

  • 4.1 使用简洁的语法建立数组。

    // 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语句。

    // 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] = memo.concat(item);
    });
    
    // 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(user) {
      const { firstName, lastName } = user;
      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) {
      // 这时神奇的事情出现了
      return [left, right, top, bottom];
    }
    
    // 获取时必须考虑回传的顺序。
    const [left, __, top] = processInput(input);
    
    // good
    function processInput(input) {
      // 这时神奇的事情出现了
      return { left, right, top, bottom };
    }
    
    // 获取时只需选择需要的属性
    const { left, right } = processInput(input);

⬆ 回到顶端


字符串

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

    // bad
    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.3 当以函数式编程构建字符串时,请使用模板字符串而不是字符串链接。

    // 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.4 千万不要在字符串中使用 eval(),会造成许多的漏洞。

⬆ 回到顶端


函数

  • 7.1 使用函数声明而不是函数表达式。

    // bad 函数表达式
    const foo = function () {
    };
    
    // good 函数声明
    function foo() {
    }
  • 7.2 立即函数。

    为什么?一个立即函数是个独立的单元-将函数及匿名函数的括号包起來明确表示这一点。注意在模块世界的任何地方,你都不需要使用立即函数。

    // 立即函数(IIFE)
    (function () {
      console.log('Welcome to the Internet. Please follow me.');
    }());
  • 7.3 不要在非功能块(if,while等)中声明函数。将函数分配给变量。 浏览器将允许你这样做,但他们都解释不同,这是坏消息熊。

  • 7.4 注意: 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 語法 ... 替代。

    // 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 = 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构造函数创建一个新函数。

    // 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 优选使用spread运算符...来调用可变函数。

    // bad
    const x = [1, 2, 3, 4, 5];
    console.log.apply(console, x);
    
    // good
    const x = [1, 2, 3, 4, 5];
    console.log(...x);
    
    // bad
    new (Function.prototype.bind.apply(Date, [null, 2016, 8, 5]));
    
    // good
    new Date(...[2016, 8, 5]);
  • 7.15 带有多行签名或调用的函数应该缩进,就像本指南中的每一个其他多行列表一样:每一行上的每个项目本身,最后一个项目上有一个尾随逗号。

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

⬆ 回到顶端


箭头函数

  • 8.1 当必须使用函数表达式(如传递匿名函数时),使用箭头函数表示。

    // 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语句。

    // 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}.`;
    });
  • 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 如果你的函数只使用一个参数,那么可以很随意的省略括号。否则请在参数两侧加上括号。

    // 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 避免混淆箭头函数语法(=>)及比较运算符(<=>=)。

    // 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 => { return item.height > 256 ? item.largeSize : item.smallSize; }

⬆ 回到顶端

Class

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

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

    // 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 如果未指定类,则类具有默认构造函数。 一个空的构造函数或者只是委托给父类的函数是不必要的。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';
      }
    }

⬆ 回到顶端


模块

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

    // bad
    import * as AirbnbStyleGuide from './AirbnbStyleGuide';
    
    // good
    import AirbnbStyleGuide from './AirbnbStyleGuide';
  • 10.3 然后也不要直接从导入导出。

    // bad
    // filename es6.js
    export { es6 as default } from './airbnbStyleGuide';
    
    // good
    // filename es6.js
    import { es6 } from './AirbnbStyleGuide';
    export default es6;
  • 10.4 只能从一个位置的路径导入。

    // 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 在具有单个导出的模块中,首选默认导出超过命名导出。

    // bad
    export function foo() {}
    
    // good
    export default function foo() {}    
  • 10.7 将所有导入都放在非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 多行导入应该缩进,就像多行数组和对象字面量。

    // bad
    import {longNameA, longNameB, longNameC, longNameD, longNameE} from 'path';
    
    // good
    import {
      longNameA,
      longNameB,
      longNameC,
      longNameD,
      longNameE,
    } from 'path';    
  • 10.9 在模块import语句中禁止使用Webpack加载器语法

    // 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 不要使用迭代器。 最好是用JavaScript的高阶函数,来替代for-in或for-of循环。

    使用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;
    
    // bad
    const increasedByOne = [];
    for (let i = 0; i < numbers.length; i++) {
      increasedByOne.push(numbers[i] + 1);
    }
    
    // good
    const increasedByOne = [];
    numbers.forEach(num => increasedByOne.push(num + 1));
    
    // best (keeping it functional)
    const increasedByOne = numbers.map(num => num + 1);
    • 11.2 现在不要使用生成器。

    • 11.3 如果你必须使用生成器,或者如果你忽略我们的建议,确保他们的函数*后面有间隔。

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

⬆ 回到顶端


属性

  • 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 总是使用constlet声明变量。 不这样做会导致全局变量受污染。 我们希望避免污染全局命名空间。

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

    // bad
    const items = getItems(),
        goSportsTeam = true,
        dragonball = 'z';
    
    // bad
    // (比较上述例子找出错误)
    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 在需要的地方分配变量,但将它们放在合理的位置。

    // 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`    
  • 13.6 避免使用一元增量和减量(++, -- )。

    // bad
    
    const 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
    
    const 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 声明可以被提升至该作用域的最顶层,但赋予的值并不会。constlet 的声明被赋予了新的概念,成为暂时性死区(Temporal Dead Zones, TDZ)。这对于了解为什么 typeof 不再那么安全是相当重要的。

    // 我们知道这样是行不通的
    // (假设没有名为 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');
      };
    }
    
    // 当函数名称和变量名称相同时也是如此。
    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');
      }
    }

⬆ 回到顶端


条件表达式与等号

比较运算符和等号

  • 15.1 请使用 ===!== ,别使用 ==!=

  • 15.2 像是 if 的条件语法内会使用 ToBoolean 的抽象方法強转类型,并遵循以下规范:

    • Objects 转换为 true
    • Undefined 转换为 false
    • Null 转换为 false
    • Booleans 转换为 該布林值
    • Numbers 如果是 +0, -0, 或 NaN 則转换为 false,其他的皆为 true
    • **Strings ** 如果是空字串 '' 則转换为 false,其他的皆为 true
    if ([0] && []) {
      // true
      // 数组(即使为空)为一个对象,所以转换为 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 casedefault 包含了声明语法(例如:letconstfunctionclass)时使用大括号来建立区块。

    // 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 foo() { return false; }
    
    // good
    function bar() {
      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() 根据传入的 tag 名称回传一个新的元件
    //
    // @param {String} tag
    // @return {Element} element
    function make(tag) {
    
      // ...stuff...
    
      return element;
    }
    
    // good
    /**
     * make() 根据传入的 tag 名称回传一个新的元件
     *
     * @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 开始注释时使用空格,使其更容易阅读。

    // bad
    //is current tab
    const active = true;
    
    // good
    // is current tab
    const active = true;
    
    // bad
    /**
     *make() returns a new element
     *based on the passed-in tag name
     */
    function make(tag) {
    
      // ...
    
      return element;
    }
    
    // good
    /**
     * make() returns a new element
     * based on the passed-in tag name
     */
    function make(tag) {
    
      // ...
    
      return element;
    }
  • 17.4 在注解前方加上 FIXMETODO 可以帮助其他开发人员快速了解这是一个需要重新讨论的问题,或是一个等待实现的问题。和一般的注解不同,它们是可操作的。对应的动作为 FIXME -- 需要讨论并解決TODO -- 需要实现

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

⬆ 回到顶端


空格

  • 18.1 将 Tab 设定为两个空格。

    // bad
    function foo() {
    ∙∙∙∙const name;
    }
    
    // bad
    function bar() {
    const name;
    }
    
    // good
    function baz() {
    ∙∙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 在控制流程的语句(if, while 等等。)的左括号前加上一个空格。声明的函数和传入的参数间则没有空格。

    // 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
    import { es6 } from './AirbnbStyleGuide';
      // ...
    export default es6;
    // bad
    import { es6 } from './AirbnbStyleGuide';
      // ...
    export default es6;
    
    // good
    import { es6 } from './AirbnbStyleGuide';
      // ...
    export default es6;
  • 18.6 当多个方法链接(大于两个方法链接)时请换行缩进。利用前面的 . 强调该行是方法调用,而不是一个新的声明。

    // 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 在块之后和下一个语句之前留下空白行。

    // 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 不要用空白行填充块。

    // 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 不要在括号中添加空格。

    // 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.10 不要在中括号内添加空格。

    // bad
    const foo = [ 1, 2, 3 ];
    console.log(foo[ 0 ]);
    
    // good
    const foo = [1, 2, 3];
    console.log(foo[0]);
  • 18.11 在花括号中添加空格。

    // bad
    const foo = {clark: 'kent'};
    
    // good
    const foo = { clark: 'kent' };
  • 18.12 避免代码行长度超过100个字符(包括空格)。 注意:根据上述规定,长字符串不受此规则限制,不应分解。

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

⬆ 回到顶端


逗号

  • 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 增加结尾的逗号。 当行定义的对象,最后一个成员不以逗号结尾。多行定义的对象,最后一个以逗号结尾。

    // bad
    const a = {k1 : v1, k2 : v2, };
    const b = {
        k1: v1,
        k2: v2
    };
    
    // good
    const a = {k1 : v1, k2 : v2 };
    const b = {
        k1: v1,
        k2: v2,
    };
    // bad
    const hero = {
      firstName: 'Dana',
      lastName: 'Scully'
    };
    
    const heroes = [
      'Batman',
      'Superman'
    ];
    
    // good
    const hero = {
      firstName: 'Dana',
      lastName: 'Scully',
    };
    
    const heroes = [
      'Batman',
      'Superman',
    ];
    
    // bad
    function createHero(
      firstName,
      lastName,
      inventorOf
    ) {
      // does nothing
    }
    
    // good
    function createHero(
      firstName,
      lastName,
      inventorOf,
    ) {
      // does nothing
    }
    
    // good (note that a comma must not appear after a "rest" element)
    function createHero(
      firstName,
      lastName,
      inventorOf,
      ...heroArgs
    ) {
      // does nothing
    }
    
    // bad
    createHero(
      firstName,
      lastName,
      inventorOf
    );
    
    // good
    createHero(
      firstName,
      lastName,
      inventorOf,
    );
    
    // good (note that a comma must not appear after a "rest" element)
    createHero(
      firstName,
      lastName,
      inventorOf,
      ...heroArgs
    );

⬆ 回到顶端


分号

⬆ 回到顶端


类型转换

  • 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 Numbers:使用 Number 做类型转换,而 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 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 位元的数值产生异常 讨论串,32 位元的整数最大值为 2,147,483,647:

    2147483647 >> 0 //=> 2147483647
    2147483648 >> 0 //=> -2147483648
    2147483649 >> 0 //=> -2147483647
  • 21.6 Booleans::

    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 不要使用尾线或下划线。

    // bad
    this.__firstName__ = 'Panda';
    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 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 当你导出为预设的函数时请使用驼峰式大小写。您的文件名应与函数名相同。

    function makeStyleGuide() {
    }
    
    export default makeStyleGuide;
  • 22.8 当你导出为构造函数 / 类 / 单例 / 函数库 /空对象时请使用帕斯卡命名法。

    const AirbnbStyleGuide = {
      es6: {
      }
    };
    
    export default AirbnbStyleGuide;
  • 22.9 首字母缩写和初始化应该总是全部大写,或全部小写。

    // bad
    import SmsContainer from './containers/SmsContainer';
    
    // bad
    const HttpRequests = [
      // ...
    ];
    
    // good
    import SMSContainer from './containers/SMSContainer';
    
    // good
    const HTTPRequests = [
      // ...
    ];
    
    // best
    import TextMessageContainer from './containers/TextMessageContainer';
    
    // best
    const Requests = [
      // ...
    ];

⬆ 回到顶端


存取器

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

⬆ 回到顶端


事件

  • 24.1 当需要对事件传入资料时(不论是DOM事件或是其他私有事件),请传入物料替代单一的资料。这样可以使之后的开发人员直接加入其他资料到事件里,而不需更新 该事件的处理器。例如,比较不好的做法:

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

⬆ 回到顶端


jQuery

  • 25.1 jQuery 的对象请使用 $ 当前缀。

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

  • 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();

终于翻译完了,花了整整一天时间,里面的内容也大致过了一次,感觉自己还有很多没遵循的地方。代码如写作,应该有它的味道!谢谢!

Headshot of Maxi Ferreira

怀着敬畏之心,做好每一件事。