<sub id="gqw76"><listing id="gqw76"></listing></sub>
      <sub id="gqw76"><listing id="gqw76"></listing></sub>

    1. <form id="gqw76"><legend id="gqw76"></legend></form>
    2. Airbnb JavaScript代碼規范(完整)

      類型Types

      基本數據類型

      • string
      • number
      • boolean
      • null
      • undefined
      • symbol
      const foo = 1;
      let bar = foo;
      
      bar = 9;
      
      console.log(foo, bar); // => 1, 9
      
      • Symbols不能真正的被polyfilled,因此當目標瀏覽器或者環境本地不支持時,不應當使用Symbols.

      復雜數據類型

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

      引用References

      // bad
      var a = 1;
      var b = 2;
      
      // good
      const a = 1;
      const b = 2;
      
      • 如果你必須對變量重新賦值,使用let. eslint: no-var

      why? let屬于塊作用域,var是函數作用域

      // bad
      var count = 1;
      if (true) {
        count += 1;
      }
      
      // good, use the let.
      let count = 1;
      if (true) {
        count += 1;
      }
      
      • 記住let和const都屬于塊作用域
      // 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
      

      對象Objects

      // bad
      const item = new Object();
      
      // good
      const item = {};
      
      • 在創建對象時,定義對象的所有屬性

      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,
      };
      
      // bad
      const atom = {
        value: 1,
      
        addValue: function (value) {
          return atom.value + value;
        },
      };
      
      // good
      const atom = {
        value: 1,
      
        addValue(value) {
          return atom.value + value;
        },
      };
      

      why?書寫更簡潔

      const lukeSkywalker = 'Luke Skywalker';
      
      // bad
      const obj = {
        lukeSkywalker: lukeSkywalker,
      };
      
      // good
      const obj = {
        lukeSkywalker,
      };
      
      • 把簡寫的屬性放在對象定義的開頭

      why?這樣更容易判斷哪些屬性使用了簡寫

      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,
      };
      
      • 只對不合法的標志符使用引號

      why?通常這樣代碼更可讀,同時語法高亮,且js引擎更容易優化。

      // bad
      const bad = {
        'foo': 3,
        'bar': 4,
        'data-blah': 5,
      };
      
      // good
      const good = {
        foo: 3,
        bar: 4,
        'data-blah': 5,
      };
      
      • 不要直接調用Object.prototype,同理: hasOwnProperty, propertyIsEnumerable, isPrototypeOf

      why?這些方法可能被吞沒,比如用Object.create(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 */
      import has from 'has';
      // ...
      console.log(has.call(object, key));
      
      • 使用對象的spread操作符而不是Object.assign方法來淺拷貝對象。使用rest操作符獲得一個去除某些屬性新的對象。
      // 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 }
      

      數組Arrays

      // bad
      const items = new Array();
      
      // good
      const items = [];
      
      • 使用Array#push方法添加元素
      const someStack = [];
      
      // bad
      someStack[someStack.length] = 'abracadabra';
      
      // good
      someStack.push('abracadabra');
      
      • 使用...操作拷貝數組
      // bad
      const len = items.length;
      const itemsCopy = [];
      let i;
      
      for (i = 0; i < len; i += 1) {
        itemsCopy[i] = items[i];
      }
      
      // good
      const itemsCopy = [...items];
      
      • 轉換array-like對象為array時,使用...而不是Array.from
      const foo = document.querySelectorAll('.foo');
      
      // good
      const nodes = Array.from(foo);
      
      // best
      const nodes = [...foo];
      
      • 對數組進行map時,使用Array.from替代...。因為前者的方式能避免創建中間數組
      // bad
      const baz = [...foo].map(bar);
      
      // good
      const baz = Array.from(foo, bar);
      
      • 在數組遍歷處理的回調函數中,使用返回語句。當回調函數中函數體只有單條語句且不會產生副作用時,可以省略return。eslint: array-callback-return
      // good
      [1, 2, 3].map((x) => {
        const y = x + 1;
        return x * y;
      });
      
      // good
      [1, 2, 3].map(x => x + 1);
      
      // bad - no returned value means `memo` becomes undefined after the first iteration
      const flat = {};
      [[0, 1], [2, 3], [4, 5]].reduce((memo, item, index) => {
        const flatten = memo.concat(item);
        memo[index] = flatten;
      });
      
      // good
      const flat = {};
      [[0, 1], [2, 3], [4, 5]].reduce((memo, item, index) => {
        const flatten = memo.concat(item);
        memo[index] = flatten;
        return flatten;
      });
      
      // bad
      inbox.filter((msg) => {
        const { subject, author } = msg;
        if (subject === 'Mockingbird') {
          return author === 'Harper Lee';
        } else {
          return false;
        }
      });
      
      // good
      inbox.filter((msg) => {
        const { subject, author } = msg;
        if (subject === 'Mockingbird') {
          return author === 'Harper Lee';
        }
      
        return false;
      });
      
      • 當數組有多行時,在開始和結束符號均換行
      // bad
      const arr = [
        [0, 1], [2, 3], [4, 5],
      ];
      
      const objectInArray = [{
        id: 1,
      }, {
        id: 2,
      }];
      
      const numberInArray = [
        1, 2,
      ];
      
      // good
      const arr = [[0, 1], [2, 3], [4, 5]];
      
      const objectInArray = [
        {
          id: 1,
        },
        {
          id: 2,
        },
      ];
      
      const numberInArray = [
        1,
        2,
      ];
      

      解構Destructuring

      why?解構可以減少臨時變量的定義

      // 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}`;
      }
      
      const arr = [1, 2, 3, 4];
      
      // bad
      const first = arr[0];
      const second = arr[1];
      
      // good
      const [first, second] = arr;
      
      • 當返回多個值時,使用對象解構方式,而不是數組解構

      why?當添加字段或者順序發生變化時,不依賴于位置

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

      字符串Strings

      • 字符串使用單引號' ' eslint: quotes
      // bad
      const name = "Capt. Janeway";
      
      // bad - template literals should contain interpolation or newlines
      const name = `Capt. Janeway`;
      
      // good
      const name = 'Capt. Janeway';
      
      • 字符串超過100個字符時,不應該跨行

      斷開的字符串不易搜索,且不方便

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

      why?模板字符串可讀性更強,語法更簡潔

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

      why?影響可讀性

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

      函數Functions

      • ?使用命名函數表達式,而不是函數聲明 eslint: func-style

      函數聲明的方式存在提升,即:無論在哪里聲明,效果等同于在函數頂部聲明,只要在同一個作用域范圍,就視為已經聲明,哪怕在聲明前就使用,也不會報錯。
      如果使用函數聲明方式定義函數,會影響可讀性和可維護性。當函數足夠大或者復雜時,對閱讀其余代碼造成困擾。

      // bad
      function foo() {
        // ...
      }
      
      // bad
      const foo = function () {
        // ...
      };
      
      // good
      // lexical name distinguished from the variable-referenced invocation(s)
      const short = function longUniqueMoreDescriptiveLexicalFoo() {
        // ...
      };
      
      • 要求 IIFE 使用括號括起來 eslint: wrap-iife
      // immediately-invoked function expression (IIFE)
      (function () {
        console.log('Welcome to the Internet. Please follow me.');
      }());
      
      • ?Never declare a function in a non-function block (if, while, etc). Assign the function to a variable instead. Browsers will allow you to do it, but they all interpret it differently, which is bad news bears. eslint: no-loop-func
      • ? 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.');
        };
      }
      
      • 不要命名參數為arguments。
      // bad
      function foo(name, options, arguments) {
        // ...
      }
      
      // good
      function foo(name, options, args) {
        // ...
      }
      
      • 選擇缺省參數的方式,避免修改參數
      // 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 = {}) {
        // ...
      }
      
      • 避免缺省參數帶來的副作用
      var b = 1;
      // bad
      function count(a = b++) {
        console.log(a);
      }
      count();  // 1
      count();  // 2
      count(3); // 3
      count();  // 3
      
      • 將缺省參數放置最后
      // bad
      function handleThings(opts = {}, name) {
        // ...
      }
      
      // good
      function handleThings(name, opts = {}) {
        // ...
      }
      
      • 不要使用Function構造函數創建函數 eslint: no-new-func
      // bad
      var add = new Function('a', 'b', 'return a + b');
      
      // still bad
      var subtract = Function('a', 'b', 'return a - b');
      
      // bad
      const f = function(){};
      const g = function (){};
      const h = function() {};
      
      // good
      const x = function () {};
      const y = function a() {};
      

      why?修改作為參數傳入的對象,容易引發不預料的副作用

      // bad
      function f1(obj) {
        obj.key = 1;
      }
      
      // good
      function f2(obj) {
        const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1;
      }
      

      why?對參數重新賦值會引發不可預料的行為,特別是訪問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) {
        // ...
      }
      

      why?更簡潔

      // bad
      const x = [1, 2, 3, 4, 5];
      console.log.apply(console, x);
      
      // good
      const x = [1, 2, 3, 4, 5];
      console.log(...x);
      
      // bad
      new (Function.prototype.bind.apply(Date, [null, 2016, 8, 5]));
      
      // good
      new Date(...[2016, 8, 5]);
      
      • 函數簽名或者函數調用占多行時,每一個參數占一行,并且最后一個參數帶逗號結束
      // bad
      function foo(bar,
                   baz,
                   quux) {
        // ...
      }
      
      // good
      function foo(
        bar,
        baz,
        quux,
      ) {
        // ...
      }
      
      // bad
      console.log(foo,
        bar,
        baz);
      
      // good
      console.log(
        foo,
        bar,
        baz,
      );
      

      箭頭函數Arrow Functions

      why?語法更簡潔,并且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;
      });
      
      • 如果函數體只有一條語句,且該語句不會產生副作用。使用簡寫方式,隱式返回;或者使用完整寫法,顯式return。
        eslint: arrow-parens, arrow-body-style
      // 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,
      }));
      
      // No implicit return with side effects
      function foo(callback) {
        const val = callback();
        if (val === true) {
          // Do something if callback returns true
        }
      }
      
      let bool = false;
      
      // bad
      foo(() => bool = true);
      
      // good
      foo(() => {
        bool = true;
      });
      
      • 當表達式占多行時,使用括號括起來增強可讀性

      why?函數開頭和結束更明確

      // bad
      ['get', 'post', 'put'].map(httpMethod => Object.prototype.hasOwnProperty.call(
          httpMagicObjectWithAVeryLongName,
          httpMethod,
        )
      );
      
      // good
      ['get', 'post', 'put'].map(httpMethod => (
        Object.prototype.hasOwnProperty.call(
          httpMagicObjectWithAVeryLongName,
          httpMethod,
        )
      ));
      
      • 如果函數只有一個參數,省略括號,省略花括號。否則,一直使用完整寫法,保持一致性。eslint: arrow-parens
      // bad
      [1, 2, 3].map((x) => x * x);
      
      // good
      [1, 2, 3].map(x => x * x);
      
      // good
      [1, 2, 3].map(number => (
        `A long string with the ${number}. It’s so long that we don’t want it to take up space on the .map line!`
      ));
      
      // bad
      [1, 2, 3].map(x => {
        const y = x + 1;
        return x * y;
      });
      
      // good
      [1, 2, 3].map((x) => {
        const y = x + 1;
        return x * y;
      });
      
      // bad
      const itemHeight = item => item.height > 256 ? item.largeSize : item.smallSize;
      
      // bad
      const itemHeight = (item) => item.height > 256 ? item.largeSize : item.smallSize;
      
      // good
      const itemHeight = item => (item.height > 256 ? item.largeSize : item.smallSize);
      
      // good
      const itemHeight = (item) => {
        const { height, largeSize, smallSize } = item;
        return height > 256 ? largeSize : smallSize;
      

      類和構造函數 Classes & Constructors

      • 使用class,避免直接操作prototype

      why?class 語法更簡潔,更易懂

      // bad
      function Queue(contents = []) {
        this.queue = [...contents];
      }
      Queue.prototype.pop = function () {
        const value = this.queue[0];
        this.queue.splice(0, 1);
        return value;
      };
      
      // good
      class Queue {
        constructor(contents = []) {
          this.queue = [...contents];
        }
        pop() {
          const value = this.queue[0];
          this.queue.splice(0, 1);
          return value;
        }
      }
      
      • 使用extends 繼承

      why?這是內置支持的繼承原型方法,同時不影響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];
        }
      }
      
      • 通過return this幫助鏈式方法調用
      // bad
      Jedi.prototype.jump = function () {
        this.jumping = true;
        return true;
      };
      
      Jedi.prototype.setHeight = function (height) {
        this.height = height;
      };
      
      const luke = new Jedi();
      luke.jump(); // => true
      luke.setHeight(20); // => undefined
      
      // good
      class Jedi {
        jump() {
          this.jumping = true;
          return this;
        }
      
        setHeight(height) {
          this.height = height;
          return this;
        }
      }
      
      const luke = new Jedi();
      
      luke.jump()
        .setHeight(20);
      
      • 自定義toString方法
      class Jedi {
        constructor(options = {}) {
          this.name = options.name || 'no name';
        }
      
        getName() {
          return this.name;
        }
      
        toString() {
          return `Jedi - ${this.getName()}`;
        }
      }
      
      // 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';
        }
      }
      

      why?后者會靜默覆蓋前者

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

      模塊Modules

      • 使用modules(import/export)

      why?modules是未來的趨勢

      // bad
      const AirbnbStyleGuide = require('./AirbnbStyleGuide');
      module.exports = AirbnbStyleGuide.es6;
      
      // ok
      import AirbnbStyleGuide from './AirbnbStyleGuide';
      export default AirbnbStyleGuide.es6;
      
      // best
      import { es6 } from './AirbnbStyleGuide';
      export default es6;
      
      • 不要使用*import
      // bad
      import * as AirbnbStyleGuide from './AirbnbStyleGuide';
      
      // good
      import AirbnbStyleGuide from './AirbnbStyleGuide';
      
      • 不要從import直接export

      why?盡管單行的方式更簡潔,但是一行import一行export代碼一致性更好

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

      why?維護性更好

      // 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';
      
      // bad
      let foo = 3;
      export { foo };
      
      // good
      const foo = 3;
      export { foo };
      

      why?可讀性和可維護性更強

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

      why?因為import行為會提升,因此保持它們放在最上面,防止產生令人奇怪的行為

      // bad
      import foo from 'foo';
      foo.init();
      
      import bar from 'bar';
      
      // good
      import foo from 'foo';
      import bar from 'bar';
      
      foo.init();
      
      • 多行import,像多行數組和多行對象字面量一樣寫

      why?縮進一致,尾行逗號結束

      // bad
      import {longNameA, longNameB, longNameC, longNameD, longNameE} from 'path';
      
      // good
      import {
        longNameA,
        longNameB,
        longNameC,
        longNameD,
        longNameE,
      } from 'path';
      
      // 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';
      

      迭代器與生成器 Iterators and Generators

      why?有利于函數式編程
      使用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);
      
      • 暫時不要使用生成器

      why?es5編譯得不太好

      • 如果你必須使用生成器,確保函數簽名空格方式正確。eslint: generator-star-spacing

      why? function和都是相同概念級別的關鍵字的一部分。function是唯一的標識符,區別于function。

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

      屬性Properties

      const luke = {
        jedi: true,
        age: 28,
      };
      
      // bad
      const isJedi = luke['jedi'];
      
      // good
      const isJedi = luke.jedi;
      
      • 通過變量訪問對象屬性時,使用[]
      const luke = {
        jedi: true,
        age: 28,
      };
      
      function getProp(prop) {
        return luke[prop];
      }
      
      const isJedi = getProp('jedi');
      
      // bad
      const binary = Math.pow(2, 10);
      
      // good
      const binary = 2 ** 10;
      

      變量

      • 總是使用const或者let定義變量。避免污染全局命名空間。eslint: no-undef
        prefer-const
      // bad
      superPower = new SuperPower();
      
      // good
      const superPower = new SuperPower();
      
      • 一個const或者let定義一個變量 eslint: one-var

      why? 更方便添加變量定義,方便debug

      // 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';
      
      • const放在一起,let放在一起

      why?更容易區分

      // 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;
      
      • 需要時再定義變量,并且放在合理的地方

      why?let和const屬于塊作用域

      // 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;
      }
      
      • 不要嵌套變量賦值

      why?嵌套變量賦值隱式創建全局變量

      // 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); // throws ReferenceError
      console.log(b); // 1
      console.log(c); // 1
      
      // good
      (function example() {
        let a = 1;
        let b = a;
        let c = a;
      }());
      
      console.log(a); // throws ReferenceError
      console.log(b); // throws ReferenceError
      console.log(c); // throws ReferenceError
      
      // the same applies for `const`
      

      why?因為一元操作符 ++ 和 -- 會自動添加分號,不同的空白可能會改變源代碼的語義。

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

      提升Hoisting

      • var聲明變量會提升到作用域頂部,賦值操作不會提升。const和let沒有類似的提升行為,因此要明白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;
      }
      
      • 匿名函數表達式會提升變量,但是不會提升函數賦值
      function example() {
        console.log(anonymous); // => undefined
      
        anonymous(); // => TypeError anonymous is not a function
      
        var anonymous = function () {
          console.log('anonymous function expression');
        };
      }
      
      • 命名函數表達式會提升變量,但是不是函數名或者函數體
      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');
        };
      }
      
      • 函數定義提升函數名稱和函數體
      function example() {
        superPower(); // => Flying
      
        function superPower() {
          console.log('Flying');
        }
      }
      

      比較操作符和等于操作Comparison Operators & Equality

      • 使用=、! eslint: eqeqeq
      • 條件語句比如if,判斷表達式值時,會強制執行ToBoolean,遵循以下規則:
      1. Object:true
      2. Undefined:false
      3. Null:false
      4. Booleans 取決于本身的值
      5. Number:+0,-0,NaN為false,其余為true
      6. String:‘’空字符串為false,其余為true
      if ([0] && []) {
        // true
        // an array (even an empty one) is an object, objects will evaluate to true
      }
      
      • 使用簡寫方式判斷,但是對strings和numbers比較使用顯式判斷
      // bad
      if (isValid === true) {
        // ...
      }
      
      // good
      if (isValid) {
        // ...
      }
      
      // bad
      if (name) {
        // ...
      }
      
      // good
      if (name !== '') {
        // ...
      }
      
      // bad
      if (collection.length) {
        // ...
      }
      
      // good
      if (collection.length > 0) {
        // ...
      }
      
      // 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 {}
        }
      }
      
      // bad
      const foo = maybe1 > maybe2
        ? "bar"
        : value1 > value2 ? "baz" : null;
      
      // split into 2 separated ternary expressions
      const maybeNull = value1 > value2 ? 'baz' : null;
      
      // better
      const foo = maybe1 > maybe2
        ? 'bar'
        : maybeNull;
      
      // best
      const foo = maybe1 > maybe2 ? 'bar' : maybeNull;
      
      // 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;
      
      // bad
      const foo = a && b < 0 || c > 0 || d + 1 === 0;
      
      // bad
      const bar = a ** b - 5 % d;
      
      // bad
      if (a || b && c) {
        return d;
      }
      
      // good
      const foo = (a && b < 0) || c > 0 || (d + 1 === 0);
      
      // good
      const bar = (a ** b) - (5 % d);
      
      // good
      if ((a || b) && c) {
        return d;
      }
      
      // good
      const bar = a + b / c * d;
      

      塊Blocks

      • ?使用{}
      // 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;
      }
      
      • 把else與if的結束放在一行 eslint: brace-style
      // bad
      if (test) {
        thing1();
        thing2();
      }
      else {
        thing3();
      }
      
      // good
      if (test) {
        thing1();
        thing2();
      } else {
        thing3();
      }
      
      • 禁止 if 語句中 return 語句之后有 else 塊 eslint: no-else-return
      // bad
      function foo() {
        if (x) {
          return x;
        } else {
          return y;
        }
      }
      
      // bad
      function cats() {
        if (x) {
          return x;
        } else if (y) {
          return y;
        }
      }
      
      // bad
      function dogs() {
        if (x) {
          return x;
        } else {
          if (y) {
            return y;
          }
        }
      }
      
      // good
      function foo() {
        if (x) {
          return x;
        }
      
        return y;
      }
      
      // good
      function cats() {
        if (x) {
          return x;
        }
      
        if (y) {
          return y;
        }
      }
      
      //good
      function dogs(x) {
        if (x) {
          if (z) {
            return y;
          }
        } 
        return z;
      }
      

      控制語句 Control Statements

      • 對于控制語句中的條件表達式太長的情況,應當換行處理,把操作符放在每行的開頭。
      // bad
      if ((foo === 123 || bar === 'abc') && doesItLookGoodWhenItBecomesThatLong() && isThisReallyHappening()) {
        thing1();
      }
      
      // bad
      if (foo === 123 &&
        bar === 'abc') {
        thing1();
      }
      
      // bad
      if (foo === 123
        && bar === 'abc') {
        thing1();
      }
      
      // bad
      if (
        foo === 123 &&
        bar === 'abc'
      ) {
        thing1();
      }
      
      // good
      if (
        foo === 123
        && bar === 'abc'
      ) {
        thing1();
      }
      
      // good
      if (
        (foo === 123 || bar === "abc")
        && doesItLookGoodWhenItBecomesThatLong()
        && isThisReallyHappening()
      ) {
        thing1();
      }
      
      // good
      if (foo === 123 && bar === 'abc') {
        thing1();
      }
      

      注釋

      • 使用/** ... */多行注釋
      // bad
      // make() returns a new element
      // based on the passed in tag name
      //
      // @param {String} tag
      // @return {Element} element
      function make(tag) {
      
        // ...
      
        return element;
      }
      
      // good
      /**
       * make() returns a new element
       * based on the passed-in tag name
       */
      function make(tag) {
      
        // ...
      
        return element;
      }
      
      • 單行注釋使用//。//放在代碼的上面一行,同時,如果不是區塊的開頭,注釋上方空行處理。
      // 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;
      }
      
      • 所有注釋空格開頭,增強易讀性 eslint: spaced-comment
      // 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;
      }
      
      • 使用FIXME或者TODO幫助開發者明白問題。
      • 使用 // FIXME 注釋問題
      class Calculator extends Abacus {
        constructor() {
          super();
      
          // FIXME: shouldn’t use a global here
          total = 0;
        }
      }
      
      • 使用 // TODO 注釋問題的解決方案
      class Calculator extends Abacus {
        constructor() {
          super();
      
          // TODO: total should be configurable by an options param
          this.total = 0;
        }
      }
      

      空白Whitespace eslint: indent

      • 使用2個空格
      // bad
      function foo() {
      ????let name;
      }
      
      // bad
      function bar() {
      ?let name;
      }
      
      // good
      function baz() {
      ??let name;
      }
      
      // 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',
      });
      
      // bad
      if(isJedi) {
        fight ();
      }
      
      // good
      if (isJedi) {
        fight();
      }
      
      // bad
      function fight () {
        console.log ('Swooosh!');
      }
      
      // good
      function fight() {
        console.log('Swooosh!');
      }
      
      // bad
      const x=y+5;
      
      // good
      const x = y + 5;
      
      • 文件結束時換一行 . eslint: eol-last
      // bad
      import { es6 } from './AirbnbStyleGuide';
        // ...
      export default es6;
      // bad
      import { es6 } from './AirbnbStyleGuide';
        // ...
      export default es6;?
      ?
      // good
      import { es6 } from './AirbnbStyleGuide';
        // ...
      export default es6;?
      
      // 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);
      
      • 在每個代碼塊的結束位置和下一語句的開頭空行
      // 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;
      
      // bad
      function bar() {
      
        console.log(foo);
      
      }
      
      // bad
      if (baz) {
      
        console.log(qux);
      } else {
        console.log(foo);
      
      }
      
      // bad
      class Foo {
      
        constructor(bar) {
          this.bar = bar;
        }
      }
      
      // good
      function bar() {
        console.log(foo);
      }
      
      // good
      if (baz) {
        console.log(qux);
      } else {
        console.log(foo);
      }
      
      // bad
      function bar( foo ) {
        return foo;
      }
      
      // good
      function bar(foo) {
        return foo;
      }
      
      // bad
      if ( foo ) {
        console.log(foo);
      }
      
      // good
      if (foo) {
        console.log(foo);
      }
      
      // bad
      const foo = [ 1, 2, 3 ];
      console.log(foo[ 0 ]);
      
      // good
      const foo = [1, 2, 3];
      console.log(foo[0]);
      
      // bad
      const foo = {clark: 'kent'};
      
      // good
      const foo = { clark: 'kent' };
      
      • 強制一行的最大長度100 eslint: max-len
      // 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.'));
      
      // 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',
      };
      

      why?減少無意義的git diffs

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

      分號 Semicolons

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

      類型轉換和強制類型轉換

      • ?Perform type coercion at the beginning of the statement.
      • 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);
      
      • Numbers:使用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);
      
      • 不管因為什么原因你必須使用位移操作,增加注釋說明
      // 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;
      
      • 小心位移操作。數值能表示64位數,但是位移操作只能返回32位整數。
      2147483647 >> 0; // => 2147483647
      2147483648 >> 0; // => -2147483648
      2147483649 >> 0; // => -2147483647
      
      • Boolean
      const age = 0;
      
      // bad
      const hasAge = new Boolean(age);
      
      // good
      const hasAge = Boolean(age);
      
      // best
      const hasAge = !!age;
      

      命名約定Naming Conventions

      • 不要使用一個字母命名 eslint: id-length
      // bad
      function q() {
        // ...
      }
      
      // good
      function query() {
        // ...
      }
      
      • 使用駝峰命名對象、函數和實例 eslint: camelcase
      // bad
      const OBJEcttsssss = {};
      const this_is_my_object = {};
      function c() {}
      
      // good
      const thisIsMyObject = {};
      function thisIsMyFunction() {}
      
      • 使用PascalCase命名構造函數或者Class eslint: new-cap
      // 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',
      });
      

      why?JavaScript沒有私有屬性或者私有方法的概念。使用下劃線容易造成誤解。

      // bad
      this.__firstName__ = 'Panda';
      this.firstName_ = 'Panda';
      this._firstName = 'Panda';
      
      // good
      this.firstName = 'Panda';
      
      • 不要保存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);
        };
      }
      
      • 文件名稱與export default 相符
      // 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
      
      • 當export default一個函數時,使用駝峰命名。文件名也必須一致
      function makeStyleGuide() {
        // ...
      }
      
      export default makeStyleGuide;
      
      • 當export constructor / class / singleton / function library / bare object,使用PascalCase命名方式
      const AirbnbStyleGuide = {
        es6: {
        },
      };
      
      export default AirbnbStyleGuide;
      
      • 縮略詞必須首字母大寫,或者全部小寫
      // bad
      import SmsContainer from './containers/SmsContainer';
      
      // bad
      const HttpRequests = [
        // ...
      ];
      
      // good
      import SMSContainer from './containers/SMSContainer';
      
      // good
      const HTTPRequests = [
        // ...
      ];
      
      // also good
      const httpRequests = [
        // ...
      ];
      
      // best
      import TextMessageContainer from './containers/TextMessageContainer';
      
      // best
      const requests = [
        // ...
      ];
      

      訪問器Accessors

      • 不需要屬性的訪問器函數
      • 不要使用getters/setters,會產生不可預期的副作用,而且難以維護和測試。
      // bad
      class Dragon {
        get age() {
          // ...
        }
      
        set age(value) {
          // ...
        }
      }
      
      // good
      class Dragon {
        getAge() {
          // ...
        }
      
        setAge(value) {
          // ...
        }
      }
      
      • 如果屬性或者方法是boolean,使用 isVal() 或者 hasVal()
      // bad
      if (!dragon.age()) {
        return false;
      }
      
      // good
      if (!dragon.hasAge()) {
        return false;
      }
      
      • 創建 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];
        }
      }
      

      事件Events

      • 對于event的handler傳遞數據時,使用 { key:value... } 方式。這樣,當需要傳遞更多信息時,不需要更改每個handler簽名
      // 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

      • jQuery對象變量使用 $ 區分
      // bad
      const sidebar = $('.sidebar');
      
      // good
      const $sidebar = $('.sidebar');
      
      // good
      const $sidebarBtn = $('.sidebar-btn');
      
      • 緩存jQuery lookups
      // bad
      function setSidebar() {
        $('.sidebar').hide();
      
        // ...
      
        $('.sidebar').css({
          'background-color': 'pink',
        });
      }
      
      // good
      function setSidebar() {
        const $sidebar = $('.sidebar');
        $sidebar.hide();
      
        // ...
      
        $sidebar.css({
          'background-color': 'pink',
        });
      }
      
      • Dom查找,使用級聯 $('.sidebar ul') 或者父子 $('.sidebar > ul')
      • 指定范圍進行find
      // bad
      $('ul', '.sidebar').hide();
      
      // bad
      $('.sidebar').find('ul').hide();
      
      // good
      $('.sidebar ul').hide();
      
      // good
      $('.sidebar > ul').hide();
      
      // good
      $sidebar.find('ul').hide();
      
      posted @ 2021-03-09 19:46  AaronHuang  閱讀(207)  評論(0編輯  收藏  舉報
      最新chease0ldman老人|无码亚洲人妻下载|大香蕉在线看好吊妞视频这里有精品www|亚洲色情综合网

        <sub id="gqw76"><listing id="gqw76"></listing></sub>
        <sub id="gqw76"><listing id="gqw76"></listing></sub>

      1. <form id="gqw76"><legend id="gqw76"></legend></form>