Airbnb JavaScript 風格指南1

https://github.com/airbnb/javascript#translation

目錄

  1. Types
  2. References
  3. Objects
  4. Arrays
  5. Destructuring
  6. Strings
  7. Functions
  8. Arrow Functions
  9. Classes & Constructors
  10. Modules
  11. Iterators and Generators
  12. Properties
  13. Variables
  14. Hoisting
  15. Comparison Operators & Equality
  16. Blocks
  17. Control Statements
  18. Comments
  19. Whitespace
  20. Commas

Types

<a name="1.1"></a>
<a name="types--primitives"></a>

  • 1.1 基本類型: 你可以直接獲取到基本類型的值

    • string
    • number
    • boolean
    • null
    • undefined
    • symbol
    const foo = 1;
    let bar = foo;
    
    bar = 9;
    
    console.log(foo, bar); // => 1, 9
    
    • Symbols 不能被正確的polyfill诀姚。 所以在不能原生支持symbol類型的環(huán)境[瀏覽器]中,不應該使用 symbol 類型玷禽。

<a name="1.2"></a>
<a name="types--complex"></a>

  • 1.2 復雜類型: 復雜類型賦值是獲取到他的引用的值赫段。 相當于傳引用

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

? back to top

References

<a name="2.1"></a>
<a name="references--prefer-const"></a>

  • 2.1 所有的賦值都用const,避免使用var. eslint: prefer-const, no-const-assign

    Why? 因為這個確保你不會改變你的初始值矢赁,重復引用會導致bug和代碼難以理解

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

<a name="2.2"></a>
<a name="references--disallow-var"></a>

  • 2.2 如果你一定要對參數(shù)重新賦值糯笙,那就用let,而不是var. eslint: no-var

    Why? 因為let是塊級作用域撩银,而var是函數(shù)級作用域

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

<a name="2.3"></a>
<a name="references--block-scope"></a>

  • 2.3 注意: let给涕、const都是塊級作用域

    // const 和 let 都只存在于它定義的那個塊級作用域
    {
      let a = 1;
      const b = 1;
    }
    console.log(a); // ReferenceError
    console.log(b); // ReferenceError
    

? back to top

Objects

<a name="3.1"></a>
<a name="objects--no-new"></a>

  • 3.1 使用字面值創(chuàng)建對象. eslint: no-new-object

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

<a name="3.2"></a>
<a name="es6-computed-properties"></a>

  • 3.2 當創(chuàng)建一個帶有動態(tài)屬性名的對象時,用計算后屬性名

    Why? 這可以使你將定義的所有屬性放在對象的一個地方.

    
    function getKey(k) {
      return `a key named ${k}`;
    }
    
    // bad
    const obj = {
      id: 5,
      name: 'San Francisco',
    };
    obj[getKey('enabled')] = true;
    
    // good getKey('enabled')是動態(tài)屬性名
    const obj = {
      id: 5,
      name: 'San Francisco',
      [getKey('enabled')]: true,
    };
    

<a name="3.3"></a>
<a name="es6-object-shorthand"></a>

  • 3.3 用對象方法簡寫. eslint: object-shorthand

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

<a name="3.4"></a>
<a name="es6-object-concise"></a>

  • 3.4 用屬性值縮寫. eslint: object-shorthand

    Why? 這樣寫的更少且更可讀

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

<a name="3.5"></a>
<a name="objects--grouped-shorthand"></a>

  • 3.5 將你的所有縮寫放在對象聲明的開始.

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

<a name="3.6"></a>
<a name="objects--quoted-props"></a>

  • 3.6 只對那些無效的標示使用引號 ''. eslint: quote-props

    Why? 通常我們認為這種方式主觀上易讀额获。他優(yōu)化了代碼高亮够庙,并且頁更容易被許多JS引擎壓縮。

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

<a name="3.7"></a>
<a name="objects--prototype-builtins"></a>

  • 3.7 不要直接調用Object.prototype上的方法抄邀,如hasOwnProperty, propertyIsEnumerable, isPrototypeOf耘眨。

    Why? 在一些有問題的對象上, 這些方法可能會被屏蔽掉 - 如:{ hasOwnProperty: false } - 或這是一個空對象Object.create(null)

    // bad
    console.log(object.hasOwnProperty(key));
    
    // good
    console.log(Object.prototype.hasOwnProperty.call(object, key));
    
    // best
    const has = Object.prototype.hasOwnProperty; // 在模塊作用內做一次緩存
    /* or */
    import has from 'has'; // https://www.npmjs.com/package/has
    // ...
    console.log(has.call(object, key));
    

<a name="3.8"></a>
<a name="objects--rest-spread"></a>

  • 3.8 對象淺拷貝時境肾,更推薦使用擴展運算符[就是...運算符]剔难,而不是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 es6擴展運算符 ...
const original = { a: 1, b: 2 };
// 淺拷貝
const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 }

// rest 賦值運算符
const { a, ...noA } = copy; // noA => { b: 2, c: 3 }

? back to top

Arrays

<a name="4.1"></a>
<a name="arrays--literals"></a>

  • 4.1 用字面量賦值砂心。 eslint: no-array-constructor

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

<a name="4.2"></a>
<a name="arrays--push"></a>

  • 4.2Array#push 代替直接向數(shù)組中添加一個值。

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

<a name="4.3"></a>
<a name="es6-array-spreads"></a>

  • 4.3 用擴展運算符做數(shù)組淺拷貝楔绞,類似上面的對象淺拷貝

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

<a name="4.4"></a>
<a name="arrays--from-iterable"></a>

  • 4.4... 運算符而不是Array.from來將一個可迭代的對象轉換成數(shù)組结闸。

    const foo = document.querySelectorAll('.foo');
    
    // good
    const nodes = Array.from(foo);
    
    // best
    const nodes = [...foo];
    

<a name="4.5"></a>
<a name="arrays--from-array-like"></a>

  • 4.5Array.from 去將一個類數(shù)組對象轉成一個數(shù)組。

    const arrLike = { 0: 'foo', 1: 'bar', 2: 'baz', length: 3 };
    
    // bad
    const arr = Array.prototype.slice.call(arrLike);
    
    // good
    const arr = Array.from(arrLike);
    

<a name="4.6"></a>
<a name="arrays--mapping"></a>

  • 4.6Array.from 而不是 ... 運算符去做map遍歷酒朵。 因為這樣可以避免創(chuàng)建一個臨時數(shù)組桦锄。

    // bad
    const baz = [...foo].map(bar);
    
    // good
    const baz = Array.from(foo, bar);
    

<a name="4.7"></a>
<a name="arrays--callback-return"></a>

  • 4.7 在數(shù)組方法的回調函數(shù)中使用 return 語句。 如果函數(shù)體由一條返回一個表達式的語句組成蔫耽, 并且這個表達式沒有副作用结耀, 這個時候可以忽略return,詳見 8.2. eslint: array-callback-return

    // good
    [1, 2, 3].map((x) => {
      const y = x + 1;
      return x * y;
    });
    
    // good 函數(shù)只有一個語句
    [1, 2, 3].map(x => x + 1);
    
    // bad - 沒有返回值匙铡, 因為在第一次迭代后acc 就變成undefined了
    [[0, 1], [2, 3], [4, 5]].reduce((acc, item, index) => {
      const flatten = acc.concat(item);
      acc[index] = flatten;
    });
    
    // good
    [[0, 1], [2, 3], [4, 5]].reduce((acc, item, index) => {
      const flatten = acc.concat(item);
      acc[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;
    });
    

<a name="4.8"></a>
<a name="arrays--bracket-newline"></a>

  • 4.8 如果一個數(shù)組有很多行图甜,在數(shù)組的 [ 后和 ] 前斷行。 請看下面示例

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

? back to top

Destructuring

<a name="5.1"></a>
<a name="destructuring--object"></a>

  • 5.1 用對象的解構賦值來獲取和使用對象某個或多個屬性值鳖眼。 eslint: prefer-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}`;
    }
    

<a name="5.2"></a>
<a name="destructuring--array"></a>

  • 5.2 用數(shù)組解構.

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

<a name="5.3"></a>
<a name="destructuring--object-over-array"></a>

  • 5.3 多個返回值用對象的解構黑毅,而不是數(shù)據(jù)解構。

    Why? 你可以在后期添加新的屬性或者變換變量的順序而不會打破原有的調用

    // bad
    function processInput(input) {
      // 然后就是見證奇跡的時刻
      return [left, right, top, bottom];
    }
    
    // 調用者需要想一想返回值的順序
    const [left, __, top] = processInput(input);
    
    // good
    function processInput(input) {
      // oops钦讳, 奇跡又發(fā)生了
      return { left, right, top, bottom };
    }
    
    // 調用者只需要選擇他想用的值就好了
    const { left, top } = processInput(input);
    

? back to top

Strings

<a name="6.1"></a>
<a name="strings--quotes"></a>

  • 6.1 對string用單引號 '' 矿瘦。 eslint: quotes

    // bad
    const name = "Capt. Janeway";
    
    // bad - 樣例應該包含插入文字或換行
    const name = `Capt. Janeway`;
    
    // good
    const name = 'Capt. Janeway';
    

<a name="6.2"></a>
<a name="strings--line-length"></a>

  • 6.2 超過100個字符的字符串不應該用string串聯(lián)成多行。

    Why? 被折斷的字符串工作起來是糟糕的而且使得代碼更不易被搜索愿卒。

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

<a name="6.3"></a>
<a name="es6-template-literals"></a>

  • 6.3 用字符串模板而不是字符串拼接來組織可編程字符串缚去。 eslint: prefer-template template-curly-spacing

    Why? 模板字符串更具可讀性、語法簡潔琼开、字符串插入?yún)?shù)易结。

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

<a name="6.4"></a>
<a name="strings--eval"></a>

  • 6.4 永遠不要在字符串中用eval(),他就是潘多拉盒子柜候。 eslint: no-eval

<a name="6.5"></a>
<a name="strings--escaping"></a>

  • 6.5 不要使用不必要的轉義字符搞动。eslint: no-useless-escape

    Why? 反斜線可讀性差,所以他們只在必須使用時才出現(xiàn)哦

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

? back to top

Functions

<a name="7.1"></a>
<a name="functions--declarations"></a>

  • 7.1 用命名函數(shù)表達式而不是函數(shù)聲明改橘。eslint: func-style

    函數(shù)表達式: const func = function () {}

    函數(shù)聲明: function func() {}

    Why? 函數(shù)聲明時作用域被提前了滋尉,這意味著在一個文件里函數(shù)很容易(太容易了)在其定義之前被引用。這樣傷害了代碼可讀性和可維護性飞主。如果你發(fā)現(xiàn)一個函數(shù)又大又復雜狮惜,這個函數(shù)妨礙這個文件其他部分的理解性,這可能就是時候把這個函數(shù)單獨抽成一個模塊了碌识。別忘了給表達式顯示的命名碾篡,不用管這個名字是不是由一個確定的變量推斷出來的,這消除了由匿名函數(shù)在錯誤調用棧產生的所有假設筏餐,這在現(xiàn)代瀏覽器和類似babel編譯器中很常見 (Discussion)

    Why? 這一段還不理解這種錯誤發(fā)生的場景开泽,所以只能直譯過來了, 另附原文
    Why? Function declarations are hoisted, which means that it’s easy - too easy - to reference the function before it is defined in the file. This harms readability and maintainability. If you find that a function’s definition is large or complex enough that it is interfering with understanding the rest of the file, then perhaps it’s time to extract it to its own module! Don’t forget to explicitly name the expression, regardless of whether or not the name is inferred from the containing variable (which is often the case in modern browsers or when using compilers such as Babel). This eliminates any assumptions made about the Error’s call stack. (Discussion)

    // bad
    function foo() {
      // ...
    }
    
    // bad
    const foo = function () {
      // ...
    };
    
    // good
    // lexical name distinguished from the variable-referenced invocation(s)
    // 函數(shù)表達式名和聲明的函數(shù)名是不一樣的
    const short = function longUniqueMoreDescriptiveLexicalFoo() {
      // ...
    };
    

<a name="7.2"></a>
<a name="functions--iife"></a>

  • 7.2 把立即執(zhí)行函數(shù)包裹在圓括號里魁瞪。 eslint: wrap-iife

    Why? immediately invoked function expression = IIFE
    Why? 一個立即調用的函數(shù)表達式是一個單元 - 把它和他的調用者(圓括號)包裹起來穆律,在括號中可以清晰的地表達這些惠呼。
    Why? 注意:在模塊化世界里,你幾乎用不著 IIFE

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

<a name="7.3"></a>
<a name="functions--in-blocks"></a>

  • 7.3 不要在非函數(shù)塊(if峦耘、while等等)內聲明函數(shù)剔蹋。把這個函數(shù)分配給一個變量。瀏覽器會允許你這樣做辅髓,但瀏覽器解析方式不同泣崩,這是一個壞消息÷蹇冢【詳見no-loop-func】 eslint: no-loop-func

<a name="7.4"></a>
<a name="functions--note-on-blocks"></a>

  • 7.4 Note: 在ECMA-262中 [塊 block] 的定義是: 一系列的語句矫付; 但是函數(shù)聲明不是一個語句。 函數(shù)表達式是一個語句第焰。

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

<a name="7.5"></a>
<a name="functions--arguments-shadow"></a>

  • 7.5 不要用arguments命名參數(shù)买优。他的優(yōu)先級高于每個函數(shù)作用域自帶的 arguments 對象, 這會導致函數(shù)自帶的 arguments 值被覆蓋

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

<a name="7.6"></a>
<a name="es6-rest"></a>

  • 7.6 不要使用arguments樟遣,用rest語法...代替而叼。 eslint: prefer-rest-params

    Why? ...明確你想用那個參數(shù)。而且rest參數(shù)是真數(shù)組豹悬,而不是類似數(shù)組的arguments

    // bad
    function concatenateAll() {
      const args = Array.prototype.slice.call(arguments);
      return args.join('');
    }
    
    // good
    function concatenateAll(...args) {
      return args.join('');
    }
    

<a name="7.7"></a>
<a name="es6-default-parameters"></a>

  • 7.7 用默認參數(shù)語法而不是在函數(shù)里對參數(shù)重新賦值葵陵。

    // really bad
    function handleThings(opts) {
      // 不, 我們不該改arguments
      // 第二: 如果 opts 的值為 false, 它會被賦值為 {}
      // 雖然你想這么寫瞻佛, 但是這個會帶來一些細微的bug
      opts = opts || {};
      // ...
    }
    
    // still bad
    function handleThings(opts) {
      if (opts === void 0) {
        opts = {};
      }
      // ...
    }
    
    // good
    function handleThings(opts = {}) {
      // ...
    }
    

<a name="7.8"></a>
<a name="functions--default-side-effects"></a>

  • 7.8 默認參數(shù)避免副作用

    Why? 他會令人迷惑不解脱篙, 比如下面這個, a到底等于幾伤柄, 這個需要想一下绊困。

    var b = 1;
    // bad
    function count(a = b++) {
      console.log(a);
    }
    count();  // 1
    count();  // 2
    count(3); // 3
    count();  // 3
    

<a name="7.9"></a>
<a name="functions--defaults-last"></a>

  • 7.9 把默認參數(shù)賦值放在最后

    // bad
    function handleThings(opts = {}, name) {
      // ...
    }
    
    // good
    function handleThings(name, opts = {}) {
      // ...
    }
    

<a name="7.10"></a>
<a name="functions--constructor"></a>

  • 7.10 不要用函數(shù)構造器創(chuàng)建函數(shù)。 eslint: no-new-func

    Why? 以這種方式創(chuàng)建函數(shù)將類似于字符串 eval()适刀,這會打開漏洞秤朗。

    // bad
    var add = new Function('a', 'b', 'return a + b');
    
    // still bad
    var subtract = Function('a', 'b', 'return a - b');
    

<a name="7.11"></a>
<a name="functions--signature-spacing"></a>

  • 7.11 函數(shù)簽名部分要有空格。eslint: space-before-function-paren space-before-blocks

    Why? 統(tǒng)一性好笔喉,而且在你添加/刪除一個名字的時候不需要添加/刪除空格

    // bad
    const f = function(){};
    const g = function (){};
    const h = function() {};
    
    // good
    const x = function () {};
    const y = function a() {};
    

<a name="7.12"></a>
<a name="functions--mutate-params"></a>

  • 7.12 不要改參數(shù). eslint: no-param-reassign

    Why? 操作參數(shù)對象對原始調用者會導致意想不到的副作用取视。 就是不要改參數(shù)的數(shù)據(jù)結構,保留參數(shù)原始值和數(shù)據(jù)結構常挚。

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

<a name="7.13"></a>
<a name="functions--reassign-params"></a>

  • 7.13 不要對參數(shù)重新賦值作谭。 eslint: no-param-reassign

    Why? 參數(shù)重新賦值會導致意外行為,尤其是對 arguments奄毡。這也會導致優(yōu)化問題折欠,特別是在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) {
      // ...
    }
    

<a name="7.14"></a>
<a name="functions--spread-vs-apply"></a>

  • 7.14spread操作符...去調用多變的函數(shù)更好。 eslint: prefer-spread

    Why? 這樣更清晰,你不必提供上下文锐秦,而且你不能輕易地用apply來組成new

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

<a name="7.15"></a>
<a name="functions--signature-invocation-indentation"></a>

  • 7.15 調用或者書寫一個包含多個參數(shù)的函數(shù)應該像這個指南里的其他多行代碼寫法一樣: 每行值包含一個參數(shù)咪奖,每行逗號結尾。

    // bad
    function foo(bar,
                 baz,
                 quux) {
      // ...
    }
    
    // good 縮進不要太過分
    function foo(
      bar,
      baz,
      quux,
    ) {
      // ...
    }
    
    // bad
    console.log(foo,
      bar,
      baz);
    
    // good
    console.log(
      foo,
      bar,
      baz,
    );
    

? back to top

Arrow Functions

<a name="8.1"></a>
<a name="arrows--use-them"></a>

  • 8.1 當你一定要用函數(shù)表達式(在回調函數(shù)里)的時候就用箭頭表達式吧农猬。 eslint: prefer-arrow-callback, arrow-spacing

    Why? 他創(chuàng)建了一個this的當前執(zhí)行上下文的函數(shù)的版本赡艰,這通常就是你想要的售淡;而且箭頭函數(shù)是更簡潔的語法

    Why? 什么時候不用箭頭函數(shù): 如果你有一個相當復雜的函數(shù)斤葱,你可能會把這個邏輯移出到他自己的函數(shù)聲明里。

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

<a name="8.2"></a>
<a name="arrows--implicit-return"></a>

  • 8.2 如果函數(shù)體由一個沒有副作用的表達式語句組成揖闸,刪除大括號和return揍堕。否則,繼續(xù)用大括號和 return 語句汤纸。 eslint: arrow-parens, arrow-body-style

    Why? 語法糖衩茸,當多個函數(shù)鏈在一起的時候好讀

    // 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
    }));
    
    // 表達式有副作用就不要用隱式return
    function foo(callback) {
      const val = callback();
      if (val === true) {
        // Do something if callback returns true
      }
    }
    
    let bool = false;
    
    // bad
    // 這種情況會return bool = true, 不好
    foo(() => bool = true);
    
    // good
    foo(() => {
      bool = true;
    });
    

<a name="8.3"></a>
<a name="arrows--paren-wrap"></a>

  • 8.3 萬一表達式涉及多行,把他包裹在圓括號里更可讀贮泞。

    Why? 這樣清晰的顯示函數(shù)的開始和結束

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

<a name="8.4"></a>
<a name="arrows--one-arg-parens"></a>

  • 8.4 如果你的函數(shù)只有一個參數(shù)并且函數(shù)體沒有大括號楞慈,就刪除圓括號。否則啃擦,參數(shù)總是放在圓括號里囊蓝。 注意: 一直用圓括號也是沒問題,只需要配置 “always” option for eslint. eslint: arrow-parens

    Why? 這樣少一些混亂令蛉, 其實沒啥語法上的講究聚霜,就保持一個風格。

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

<a name="8.5"></a>
<a name="arrows--confusing"></a>

  • 8.5 避免箭頭函數(shù)(=>)和比較操作符(<=, >=)混淆. eslint: no-confusing-arrow

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

<a name="8.6"></a>
<a name="whitespace--implicit-arrow-linebreak"></a>

  • 8.6 在隱式return中強制約束函數(shù)體的位置珠叔, 就寫在箭頭后面蝎宇。 eslint: implicit-arrow-linebreak

    // bad
    (foo) =>
      bar;
    
    (foo) =>
      (bar);
    
    // good
    (foo) => bar;
    (foo) => (bar);
    (foo) => (
       bar
    )
    

? back to top

Classes & Constructors

<a name="9.1"></a>
<a name="constructors--use-class"></a>

  • 9.1 常用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;
      }
    }
    

<a name="9.2"></a>
<a name="constructors--extends"></a>

  • 9.2extends實現(xiàn)繼承

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

<a name="9.3"></a>
<a name="constructors--chaining"></a>

  • 9.3 方法可以返回this來實現(xiàn)方法鏈

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

<a name="9.4"></a>
<a name="constructors--tostring"></a>

  • 9.4 寫一個定制的toString()方法是可以的祷安,只要保證它是可以正常工作且沒有副作用的

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

<a name="9.5"></a>
<a name="constructors--no-useless"></a>

  • 9.5 如果沒有具體說明姥芥,類有默認的構造方法。一個空的構造函數(shù)或只是代表父類的構造函數(shù)是不需要寫的汇鞭。 eslint: no-useless-constructor

    // bad
    class Jedi {
      constructor() {}
    
      getName() {
        return this.name;
      }
    }
    
    // bad
    class Rey extends Jedi {
      // 這種構造函數(shù)是不需要寫的
      constructor(...args) {
        super(...args);
      }
    }
    
    // good
    class Rey extends Jedi {
      constructor(...args) {
        super(...args);
        this.name = 'Rey';
      }
    }
    

<a name="9.6"></a>
<a name="classes--no-duplicate-members"></a>

  • 9.6 避免重復類成員凉唐。 eslint: no-dupe-class-members

    Why? 重復類成員會默默的執(zhí)行最后一個 —— 重復本身也是一個bug

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

<a name="classes--methods-use-this"></a>

  • 9.7 除非外部庫或框架需要使用特定的非靜態(tài)方法,否則類方法應該使用this或被做成靜態(tài)方法虱咧。
    作為一個實例方法應該表明它根據(jù)接收者的屬性有不同的行為熊榛。eslint: class-methods-use-this

    // bad
    class Foo {
      bar() {
        console.log('bar');
      }
    }
    
    // good - this 被使用了 
    class Foo {
      bar() {
        console.log(this.bar);
      }
    }
    
    // good - constructor 不一定要使用this
    class Foo {
      constructor() {
        // ...
      }
    }
    
    // good - 靜態(tài)方法不需要使用 this
    class Foo {
      static bar() {
        console.log('bar');
      }
    }
    

? back to top

Modules

<a name="10.1"></a>
<a name="modules--use-them"></a>

  • 10.1 用(import/export) 模塊而不是無標準的模塊系統(tǒng)。你可以隨時轉到你喜歡的模塊系統(tǒng)腕巡。

    Why? 模塊化是未來玄坦,讓我們現(xiàn)在就開啟未來吧。

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

<a name="10.2"></a>
<a name="modules--no-wildcard"></a>

  • 10.2 不要用import通配符, 就是 * 這種方式

    Why? 這確保你有單個默認的導出

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

<a name="10.3"></a>
<a name="modules--no-export-from-import"></a>

  • 10.3 不要直接從import中直接export

    Why? 雖然一行是簡潔的煎楣,有一個明確的方式進口和一個明確的出口方式來保證一致性豺总。

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

<a name="10.4"></a>
<a name="modules--no-duplicate-imports"></a>

  • 10.4 一個路徑只 import 一次。
    eslint: no-duplicate-imports

    Why? 從同一個路徑下import多行會使代碼難以維護

    // bad
    import foo from 'foo';
    // … some other imports … //
    import { named1, named2 } from 'foo';
    
    // good
    import foo, { named1, named2 } from 'foo';
    
    // good
    import foo, {
      named1,
      named2,
    } from 'foo';
    

<a name="10.5"></a>
<a name="modules--no-mutable-exports"></a>

  • 10.5 不要導出可變的東西
    eslint: import/no-mutable-exports

    Why? 變化通常都是需要避免择懂,特別是當你要輸出可變的綁定喻喳。雖然在某些場景下可能需要這種技術,但總的來說應該導出常量困曙。

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

<a name="10.6"></a>
<a name="modules--prefer-default-export"></a>

  • 10.6 在一個單一導出模塊里表伦,用 export default 更好。
    eslint: import/prefer-default-export

    Why? 鼓勵使用更多文件慷丽,每個文件只做一件事情并導出蹦哼,這樣可讀性和可維護性更好。

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

<a name="10.7"></a>
<a name="modules--imports-first"></a>

  • 10.7 import 放在其他所有語句之前要糊。
    eslint: import/first

    Why? 讓import放在最前面防止意外行為纲熏。

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

<a name="10.8"></a>
<a name="modules--multiline-imports-over-newlines"></a>

  • 10.8 多行import應該縮進,就像多行數(shù)組和對象字面量

    Why? 花括號與樣式指南中每個其他花括號塊遵循相同的縮進規(guī)則锄俄,逗號也是局劲。

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

<a name="10.9"></a>
<a name="modules--no-webpack-loader-syntax"></a>

  • 10.9 在import語句里不允許Webpack loader語法
    eslint: import/no-webpack-loader-syntax

    Why? 一旦用Webpack語法在import里會把代碼耦合到模塊綁定器。最好是在webpack.config.js里寫webpack loader語法

    // bad
    import fooSass from 'css!sass!foo.scss';
    import barCss from 'style!css!bar.css';
    
    // good
    import fooSass from 'foo.scss';
    import barCss from 'bar.css';
    

? back to top

Iterators and Generators

<a name="11.1"></a>
<a name="iterators--nope"></a>

  • 11.1 不要用遍歷器奶赠。用JavaScript高級函數(shù)代替for-in鱼填、 for-of。 eslint: no-iterator no-restricted-syntax

    Why? 這強調了我們不可變的規(guī)則车柠。 處理返回值的純函數(shù)比副作用更容易剔氏。

    Why? 用數(shù)組的這些迭代方法: map() / every() / filter() / find() / findIndex() / reduce() / some() / ... , 用對象的這些方法 Object.keys() / Object.values() / Object.entries() 去產生一個數(shù)組, 這樣你就能去遍歷對象了竹祷。

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

<a name="11.2"></a>
<a name="generators--nope"></a>

  • 11.2 現(xiàn)在不要用generator

    Why? 它在es5上支持的不好

<a name="11.3"></a>
<a name="generators--spacing"></a>

  • 11.3 如果你一定要用谈跛,或者你忽略我們的建議, 請確保它們的函數(shù)簽名空格是得當?shù)摹?eslint: generator-star-spacing

    Why? function* 是同一概念關鍵字 - *不是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* () {
      // ...
    }
    

? back to top

Properties

<a name="12.1"></a>
<a name="properties--dot"></a>

  • 12.1 訪問屬性時使用點符號. eslint: dot-notation

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

<a name="12.2"></a>
<a name="properties--bracket"></a>

  • 12.2 當獲取的屬性是變量時用方括號[]

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

<a name="12.3"></a>
<a name="es2016-properties--exponentiation-operator"></a>

  • 12.3 做冪運算時用冪操作符 ** 塑陵。 eslint: no-restricted-properties.

    // bad
    const binary = Math.pow(2, 10);
    
    // good
    const binary = 2 ** 10;
    

? back to top

Variables

<a name="13.1"></a>
<a name="variables--const"></a>

  • 13.1constlet聲明變量感憾。不這樣做會導致全局變量。 我們想要避免污染全局命名空間令花。首長這樣警告我們阻桅。 eslint: no-undef prefer-const

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

<a name="13.2"></a>
<a name="variables--one-const"></a>

  • 13.2 每個變量都用一個 constlet。 eslint: one-var

    Why? 這種方式很容易去聲明新的變量兼都,你不用去考慮把;調換成,嫂沉,或者引入一個只有標點的不同的變化。這種做法也可以是你在調試的時候單步每個聲明語句扮碧,而不是一下跳過所有聲明趟章。

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

<a name="13.3"></a>
<a name="variables--const-let-group"></a>

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

<a name="13.4"></a>
<a name="variables--define-where-used"></a>

  • 13.4 在你需要的地方聲明變量宏侍,但是要放在合理的位置

    Why? letconst 都是塊級作用域而不是函數(shù)級作用域

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

<a name="13.5"></a>
<a name="variables--no-chain-assignment"></a>

  • 13.5 不要使用鏈接變量分配。 eslint: no-multi-assign

    Why? 鏈接變量分配創(chuàng)建隱式全局變量蜀漆。

    // bad
    (function example() {
      // JavaScript 將這一段解釋為
      // let a = ( b = ( c = 1 ) );
      // let 只對變量 a 起作用; 變量 b 和 c 都變成了全局變量
      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
    
    // `const` 也是如此
    

<a name="13.6"></a>
<a name="variables--unary-increment-decrement"></a>

  • 13.6 不要使用一元自增自減運算符(++谅河, --). eslint no-plusplus

    Why? 根據(jù)eslint文檔,一元增量和減量語句受到自動分號插入的影響确丢,并且可能會導致應用程序中的值遞增或遞減的無聲錯誤绷耍。 使用num + = 1而不是num ++num ++語句來表達你的值也是更有表現(xiàn)力的。 禁止一元增量和減量語句還會阻止您無意地預增/預減值蠕嫁,這也會導致程序出現(xiàn)意外行為锨天。

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

<a name="13.7"></a>
<a name="variables--linebreak"></a>

  • 13.7 在賦值的時候避免在 = 前/后換行。 如果你的賦值語句超出 max-len剃毒, 那就用小括號把這個值包起來再換行。 eslint operator-linebreak.

    Why? 在 = 附近換行容易混淆這個賦值語句搂赋。

    // bad
    const foo =
      superLongLongLongLongLongLongLongLongFunctionName();
    
    // bad
    const foo
      = 'superLongLongLongLongLongLongLongLongString';
    
    // good
    const foo = (
      superLongLongLongLongLongLongLongLongFunctionName()
    );
    
    // good
    const foo = 'superLongLongLongLongLongLongLongLongString';
    

<a name="13.8"></a>
<a name="variables--no-unused-vars"></a>

  • 13.8 不允許有未使用的變量赘阀。 eslint: no-unused-vars

    Why? 一個聲明了但未使用的變量更像是由于重構未完成產生的錯誤。這種在代碼中出現(xiàn)的變量會使閱讀者迷惑脑奠。

    // bad
    
    var some_unused_var = 42;
    
    // 寫了沒用
    var y = 10;
    y = 5;
    
    // 變量改了自己的值基公,也沒有用這個變量
    var z = 0;
    z = z + 1;
    
    // 參數(shù)定義了但未使用
    function getX(x, y) {
        return x;
    }
    
    // good
    function getXPlusY(x, y) {
      return x + y;
    }
    
    var x = 1;
    var y = a + 2;
    
    alert(getXPlusY(x, y));
    
    // 'type' 即使沒有使用也可以可以被忽略, 因為這個有一個 rest 取值的屬性宋欺。
    // 這是從對象中抽取一個忽略特殊字段的對象的一種形式
    var { type, ...coords } = data;
    // 'coords' 現(xiàn)在就是一個沒有 'type' 屬性的 'data' 對象
    

? back to top

Hoisting

<a name="14.1"></a>
<a name="hoisting--about"></a>

  • 14.1 var聲明會被提前到他的作用域的最前面轰豆,它分配的值還沒有提前。constlet被賦予了新的調用概念時效區(qū) —— Temporal Dead Zones (TDZ)齿诞。 重要的是要知道為什么 typeof不再安全.

    // 我們知道這個不會工作酸休,假設沒有定義全局的notDefined
    function example() {
      console.log(notDefined); // => throws a ReferenceError
    }
    
    // 在你引用的地方之后聲明一個變量,他會正常輸出是因為變量作用域上升祷杈。
    // 注意: declaredButNotAssigned的值沒有上升
    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;
    }
    

<a name="14.2"></a>
<a name="hoisting--anon-expressions"></a>

  • 14.2 匿名函數(shù)表達式和 var 情況相同

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

<a name="14.3"></a>
<a name="hoisting--named-expresions"></a>

  • 14.3 已命名函數(shù)表達式提升他的變量名宿刮,不是函數(shù)名或函數(shù)體

    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');
      };
    }
    
    // 函數(shù)名和變量名一樣是也如此
    function example() {
      console.log(named); // => undefined
    
      named(); // => TypeError named is not a function
    
      var named = function named() {
        console.log('named');
      };
    }
    

<a name="14.4"></a>
<a name="hoisting--declarations"></a>

  • 14.4 函數(shù)聲明則提升了函數(shù)名和函數(shù)體

    function example() {
      superPower(); // => Flying
    
      function superPower() {
        console.log('Flying');
      }
    }
    
  • 詳情請見JavaScript Scoping & Hoisting by Ben Cherry.

? back to top

Comparison Operators & Equality

<a name="15.1"></a>
<a name="comparison--eqeqeq"></a>

  • 15.1===!== 而不是 ==!=. eslint: eqeqeq

<a name="15.2"></a>
<a name="comparison--if"></a>

  • 15.2 條件語句如'if'語句使用強制`ToBoolean'抽象方法來評估它們的表達式,并且始終遵循以下簡單規(guī)則:

    • Objects 計算成 true
    • Undefined 計算成 false
    • Null 計算成 false
    • Booleans 計算成 the value of the boolean
    • Numbers
      • +0, -0, or NaN 計算成 false
      • 其他 true
    • Strings
      • '' 計算成 false
      • 其他 true
    if ([0] && []) {
      // true
      // 數(shù)組(即使是空數(shù)組)是對象私蕾,對象會計算成true
    }
    

<a name="15.3"></a>
<a name="comparison--shortcuts"></a>

  • 15.3 布爾值用縮寫僵缺,而字符串和數(shù)字要明確比較對象

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

<a name="15.4"></a>
<a name="comparison--moreinfo"></a>

<a name="15.5"></a>
<a name="comparison--switch-blocks"></a>

  • 15.5casedefault分句里用大括號創(chuàng)建一塊包含語法聲明的區(qū)域(e.g. let, const, function, and class). eslint rules: no-case-declarations.

    Why? 語法聲明在整個switch的代碼塊里都可見踩叭,但是只有當其被分配后才會初始化磕潮,他的初始化時當這個case被執(zhí)行時才產生。 當多個case分句試圖定義同一個事情時就出問題了

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

<a name="15.6"></a>
<a name="comparison--nested-ternaries"></a>

  • 15.6 三元表達式不應該嵌套,通常是單行表達式揉抵。

    eslint rules: no-nested-ternary.

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

<a name="15.7"></a>
<a name="comparison--unneeded-ternary"></a>

  • 15.7 避免不需要的三元表達式

    eslint rules: no-unneeded-ternary.

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

<a name="15.8"></a>
<a name="comparison--no-mixed-operators"></a>

  • 15.8 用圓括號來混合這些操作符亡容。 只有當標準的算術運算符(+, -, *, & /), 并且它們的優(yōu)先級顯而易見時冤今,可以不用圓括號括起來闺兢。 eslint: no-mixed-operators

    Why? 這提高了可讀性,并且明確了開發(fā)者的意圖

    // bad
    const foo = a && b < 0 || c > 0 || d + 1 === 0;
    
    // bad
    const bar = a ** b - 5 % d;
    
    // bad
    // 別人會陷入(a || b) && c 的迷惑中
    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;
    

? back to top

Blocks

<a name="16.1"></a>
<a name="blocks--braces"></a>

  • 16.1 用大括號包裹多行代碼塊戏罢。 eslint: nonblock-statement-body-position

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

<a name="16.2"></a>
<a name="blocks--cuddled-elses"></a>

  • 16.2 if表達式的elseif的關閉大括號在一行屋谭。 eslint: brace-style

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

<a name="16.3"></a>
<a name="blocks--no-else-return"></a>

  • 16.3 如果 if 語句中總是需要用 return 返回, 那后續(xù)的 else 就不需要寫了龟糕。 if 塊中包含 return桐磁, 它后面的 else if 塊中也包含了 return, 這個時候就可以把 return 分到多個 if 語句塊中讲岁。 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;
        }
      } else {
        return z;
      }
    }
    

? back to top

Control Statements

<a name="17.1"></a>
<a name="control-statements"></a>

  • 17.1 當你的控制語句(if, while 等)太長或者超過最大長度限制的時候我擂, 把每一個(組)判斷條件放在單獨一行里。 邏輯操作符放在行首缓艳。

    Why? 把邏輯操作符放在行首是讓操作符的對齊方式和鏈式函數(shù)保持一致校摩。這提高了可讀性,也讓復雜邏輯更容易看清楚阶淘。

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

<a name="17.2"></a>
<a name="control-statements--value-selection"></a>

  • 17.2 不要用選擇操作符代替控制語句衙吩。

    // bad
    !isRunning && startRunning();
    
    // good
    if (!isRunning) {
      startRunning();
    }
    

? back to top

Comments

<a name="18.1"></a>
<a name="comments--multiline"></a>

  • 18.1 多行注釋用 /** ... */

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

<a name="18.2"></a>
<a name="comments--singleline"></a>

  • 18.2 單行注釋用//,將單行注釋放在被注釋區(qū)域上面溪窒。如果注釋不是在第一行坤塞,那么注釋前面就空一行

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

<a name="18.3"></a>
<a name="comments--spaces"></a>

  • 18.3 所有注釋開頭空一個,方便閱讀澈蚌。 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;
    }
    

<a name="18.4"></a>
<a name="comments--actionitems"></a>

  • 18.4 在你的注釋前使用FIXME'或TODO'前綴摹芙, 這有助于其他開發(fā)人員快速理解你指出的需要重新訪問的問題, 或者您建議需要實現(xiàn)的問題的解決方案瘫辩。 這些不同于常規(guī)注釋坛悉,因為它們是可操作的。 動作是FIXME: - 需要計算出來TODO: - 需要實現(xiàn)裸影。

<a name="18.5"></a>
<a name="comments--fixme"></a>

  • 18.5// FIXME:給問題做注釋

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

<a name="18.6"></a>
<a name="comments--todo"></a>

  • 18.6// TODO:去注釋問題的解決方案

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

? back to top

Whitespace

<a name="19.1"></a>
<a name="whitespace--spaces"></a>

  • 19.1 tab用兩個空格. eslint: indent

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

<a name="19.2"></a>
<a name="whitespace--before-blocks"></a>

  • 19.2 在大括號前空一格轩猩。 eslint: space-before-blocks

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

<a name="19.3"></a>
<a name="whitespace--around-keywords"></a>

  • 19.3 在控制語句(if, while 等)的圓括號前空一格卷扮。在函數(shù)調用和定義時,參數(shù)列表和函數(shù)名之間不空格摩幔。 eslint: keyword-spacing

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

<a name="19.4"></a>
<a name="whitespace--infix-ops"></a>

  • 19.4 用空格來隔開運算符鞭铆。 eslint: space-infix-ops

    // bad
    const x=y+5;
    
    // good
    const x = y + 5;
    

<a name="19.5"></a>
<a name="whitespace--newline-at-end"></a>

  • 19.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;?
    

<a name="19.6"></a>
<a name="whitespace--chains"></a>

  • 19.6 當出現(xiàn)長的方法鏈(>2個)時用縮進车遂。用點開頭強調該行是一個方法調用舶担,而不是一個新的語句。eslint: newline-per-chained-call no-whitespace-before-property

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

<a name="19.7"></a>
<a name="whitespace--after-blocks"></a>

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

<a name="19.8"></a>
<a name="whitespace--padded-blocks"></a>

  • 19.8 不要用空白行填充塊蒲障。 eslint: padded-blocks

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

<a name="whitespace--no-multiple-blanks"></a>

  • 19.9不要在代碼之間使用多個空白行填充箱季。 eslint: no-multiple-empty-lines

    // bad
    class Person {
      constructor(fullName, email, birthday) {
        this.fullName = fullName;
    
    
        this.email = email;
    
    
        this.setAge(birthday);
      }
    
    
      setAge(birthday) {
        const today = new Date();
    
    
        const age = this.getAge(today, birthday);
    
    
        this.age = age;
      }
    
    
      getAge(today, birthday) {
        // ..
      }
    }
    
    // good
    class Person {
      constructor(fullName, email, birthday) {
        this.fullName = fullName;
        this.email = email;
        this.setAge(birthday);
      }
    
      setAge(birthday) {
        const today = new Date();
        const age = getAge(today, birthday);
        this.age = age;
      }
    
      getAge(today, birthday) {
        // ..
      }
    }
    

<a name="19.10"></a>
<a name="whitespace--in-parens"></a>

  • 19.10 圓括號里不要加空格锈津。 eslint: space-in-parens

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

<a name="19.11"></a>
<a name="whitespace--in-brackets"></a>

  • 19.11 方括號里不要加空格隆箩“齐看示例。 eslint: array-bracket-spacing

    // bad
    const foo = [ 1, 2, 3 ];
    console.log(foo[ 0 ]);
    
    // good逞力, 逗號分隔符還是要空格的
    const foo = [1, 2, 3];
    console.log(foo[0]);
    

<a name="19.12"></a>
<a name="whitespace--in-braces"></a>

  • 19.12 花括號里加空格糠爬。 eslint: object-curly-spacing

    // bad
    const foo = {clark: 'kent'};
    
    // good
    const foo = { clark: 'kent' };
    

<a name="19.13"></a>
<a name="whitespace--max-len"></a>

  • 19.13 避免一行代碼超過100個字符(包含空格)执隧。

  • 注意: 對于上面——strings--line-length,長字符串不受此規(guī)則限制峦嗤,不應分解。 eslint: max-len

    Why? 這樣確碧胬妫可讀性和可維護性

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

<a name="19.14"></a>
<a name="whitespace--block-spacing"></a>

  • 19.14 作為語句的花括號內也要加空格 —— { 后和 } 前都需要空格耙替。 eslint: block-spacing

    // bad
    function foo() {return true;}
    if (foo) { bar = 0;}
    
    // good
    function foo() { return true; }
    if (foo) { bar = 0; }
    

<a name="19.15"></a>
<a name="whitespace--comma-spacing"></a>

  • 19.15 , 前不要空格俗扇, , 后需要空格铜幽。 eslint: comma-spacing

    // bad
    var foo = 1,bar = 2;
    var arr = [1 , 2];
    
    // good
    var foo = 1, bar = 2;
    var arr = [1, 2];
    

<a name="19.16"></a>
<a name="whitespace--computed-property-spacing"></a>

  • 19.16 計算屬性內要空格除抛。參考上述花括號和中括號的規(guī)則母截。 eslint: computed-property-spacing

    // bad
    obj[foo ]
    obj[ 'foo']
    var x = {[ b ]: a}
    obj[foo[ bar ]]
    
    // good
    obj[foo]
    obj['foo']
    var x = { [b]: a }
    obj[foo[bar]]
    

<a name="19.17"></a>
<a name="whitespace--func-call-spacing"></a>

  • 19.17 調用函數(shù)時清寇,函數(shù)名和小括號之間不要空格华烟。 eslint: func-call-spacing

    // bad
    func ();
    
    func
    ();
    
    // good
    func();
    

<a name="19.18"></a>
<a name="whitespace--key-spacing"></a>

  • 19.18 在對象的字面量屬性中, key value 之間要有空格负饲。 eslint: key-spacing

    // bad
    var obj = { "foo" : 42 };
    var obj2 = { "foo":42 };
    
    // good
    var obj = { "foo": 42 };
    

<a name="19.19"></a>
<a name="whitespace--no-trailing-spaces"></a>

<a name="19.20"></a>
<a name="whitespace--no-multiple-empty-lines"></a>

  • 19.20 避免出現(xiàn)多個空行吧慢。 在文件末尾只允許空一行赏表。 eslint: no-multiple-empty-lines

    // bad
    var x = 1;
    
    
    
    var y = 2;
    
    // good
    var x = 1;
    
    var y = 2;
    

? back to top

Commas

<a name="20.1"></a>
<a name="commas--leading-trailing"></a>

  • 20.1 不要前置逗號。 eslint: comma-style

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

<a name="20.2"></a>
<a name="commas--dangling"></a>

  • 20.2 額外結尾逗號: eslint: comma-dangle

    Why? 這導致git diffs更清潔悠轩。 此外火架,像Babel這樣的轉換器會刪除轉換代碼中的額外的逗號忙菠,這意味著你不必擔心舊版瀏覽器中的結尾逗號問題牛欢。

    // bad - 沒有結尾逗號的 git diff
    const hero = {
         firstName: 'Florence',
    -    lastName: 'Nightingale'
    +    lastName: 'Nightingale',
    +    inventorOf: ['coxcomb chart', 'modern nursing']
    };
    
    // good - 有結尾逗號的 git diff
    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
    )
    

? back to top

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末骡男,一起剝皮案震驚了整個濱河市傍睹,隨后出現(xiàn)的幾起案子拾稳,更是在濱河造成了極大的恐慌访得,老刑警劉巖悍抑,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異泥技,居然都是意外死亡珊豹,警方通過查閱死者的電腦和手機店茶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進店門轿腺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人憔辫,你說我怎么就攤上這事贰您〗跻啵” “怎么了杠园?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵返劲,是天一觀的道長篮绿。 經常有香客問我亲配,道長吼虎,這世上最難降的妖魔是什么思灰? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮油湖,結果婚禮上乏德,老公的妹妹穿的比我還像新娘喊括。我一直安慰自己,他們只是感情好贷痪,可當我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著舱沧,像睡著了一般熟吏。 火紅的嫁衣襯著肌膚如雪牵寺。 梳的紋絲不亂的頭發(fā)上帽氓,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天黎休,我揣著相機與錄音势腮,去河邊找鬼捎拯。 笑死玄渗,一個胖子當著我的面吹牛,可吹牛的內容都是我干的拓萌。 我是一名探鬼主播微王,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼炕倘,長吁一口氣:“原來是場噩夢啊……” “哼罩旋!你這毒婦竟也來了涨醋?” 一聲冷哼從身側響起浴骂,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤趣苏,失蹤者是張志新(化名)和其女友劉穎梯轻,沒想到半個月后芬为,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體媚朦,經...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡询张,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年份氧,在試婚紗的時候發(fā)現(xiàn)自己被綠了蜗帜。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片厅缺。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡诀豁,死狀恐怖舷胜,靈堂內的尸體忽然破棺而出烹骨,到底是詐尸還是另有隱情展氓,我是刑警寧澤遇汞,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布空入,位于F島的核電站歪赢,受9級特大地震影響埋凯,放射性物質發(fā)生泄漏白对。R本人自食惡果不足惜甩恼,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望钉蒲。 院中可真熱鬧子巾,春花似錦线梗、人聲如沸仪搔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽昌阿。三九已至懦冰,卻和暖如春刷钢,著一層夾襖步出監(jiān)牢的瞬間内地,已是汗流浹背阱缓。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留祭犯,地道東北人沃粗。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓最盅,卻偏偏與公主長得像涡贱,于是被迫代替她去往敵國和親问词。 傳聞我的和親對象是個殘疾皇子激挪,可洞房花燭夜當晚...
    茶點故事閱讀 42,834評論 2 345