JS 規(guī)范-常用

from airbnb translation https://github.com/lin-123/javascript

References

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

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

    Why? 因?yàn)檫@個確保你不會改變你的初始值坷随,重復(fù)引用會導(dǎo)致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? 因?yàn)?code>let是塊級作用域温眉,而var是函數(shù)級作用域

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

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 當(dāng)創(chuàng)建一個帶有動態(tài)屬性名的對象時够话,用計(jì)算后屬性名

    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.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 只對那些無效的標(biāo)示使用引號 ''. eslint: quote-props

    Why? 通常我們認(rèn)為這種方式主觀上易讀。他優(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.8"></a>
<a name="objects--rest-spread"></a>

  • 3.8 對象淺拷貝時露懒,更推薦使用擴(kuò)展運(yùn)算符[就是...運(yùn)算符],而不是Object.assign砂心。獲取對象指定的幾個屬性時懈词,用對象的rest解構(gòu)運(yùn)算符[也是...運(yùn)算符]更好。
    • 這一段不太好翻譯出來辩诞, 大家看下面的例子就懂了坎弯。.
// 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擴(kuò)展運(yùn)算符 ...
const original = { a: 1, b: 2 };
// 淺拷貝
const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 }

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

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 用擴(kuò)展運(yùn)算符做數(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... 運(yùn)算符而不是Array.from來將一個可迭代的對象轉(zhuǎn)換成數(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ù)組對象轉(zhuǎn)成一個數(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 而不是 ... 運(yùn)算符去做map遍歷崎脉。 因?yàn)檫@樣可以避免創(chuàng)建一個臨時數(shù)組。

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

Destructuring

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

  • 5.1 用對象的解構(gòu)賦值來獲取和使用對象某個或多個屬性值伯顶。 eslint: prefer-destructuring

    Why? 解構(gòu)保存了這些屬性的臨時值/引用

    // 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ù)組解構(gòu).

    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 多個返回值用對象的解構(gòu)囚灼,而不是數(shù)組解構(gòu)。

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

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

Strings

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

  • 6.1 對string用單引號 '' 啦撮。 eslint: quotes

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

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

  • 6.2 超過100個字符的字符串不應(yīng)該用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 永遠(yuǎn)不要在字符串中用eval(),他就是潘多拉盒子衷戈。 eslint: no-eval

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

  • 6.5 不要使用不必要的轉(zhuǎn)義字符狭吼。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}'`;
    

Functions

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

  • 7.5 不要用arguments命名參數(shù)殖妇。他的優(yōu)先級高于每個函數(shù)作用域自帶的 arguments 對象刁笙, 這會導(dǎo)致函數(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 用默認(rèn)參數(shù)語法而不是在函數(shù)里對參數(shù)重新賦值前鹅。

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

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

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

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

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

  • 7.10 不要用函數(shù)構(gòu)造器創(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.12"></a>
<a name="functions--mutate-params"></a>

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

    Why? 操作參數(shù)對象對原始調(diào)用者會導(dǎo)致意想不到的副作用。 就是不要改參數(shù)的數(shù)據(jù)結(jié)構(gòu)口四,保留參數(shù)原始值和數(shù)據(jù)結(jié)構(gòu)孵运。

    // 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ù)重新賦值會導(dǎo)致意外行為窃祝,尤其是對 arguments掐松。這也會導(dǎo)致優(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.15"></a>
<a name="functions--signature-invocation-indentation"></a>

  • 7.15 調(diào)用或者書寫一個包含多個參數(shù)的函數(shù)應(yīng)該想這個指南里的其他多行代碼寫法一樣: 每行值包含一個參數(shù)粪小,每行逗號結(jié)尾。

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

Modules

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

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

    Why? 這確保你有單個默認(rèn)的導(dǎo)出

    // 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? 雖然一行是簡潔的探膊,有一個明確的方式進(jìn)口和一個明確的出口方式來保證一致性。

    // 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多行會使代碼難以維護(hù)

    // 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 不要導(dǎo)出可變的東西
    eslint: import/no-mutable-exports

    Why? 變化通常都是需要避免逞壁,特別是當(dāng)你要輸出可變的綁定。雖然在某些場景下可能需要這種技術(shù)锐锣,但總的來說應(yīng)該導(dǎo)出常量腌闯。

    // 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 在一個單一導(dǎo)出模塊里,用 export default 更好雕憔。
    eslint: import/prefer-default-export

    Why? 鼓勵使用更多文件姿骏,每個文件只做一件事情并導(dǎo)出,這樣可讀性和可維護(hù)性更好斤彼。

    // 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應(yīng)該縮進(jìn)琉苇,就像多行數(shù)組和對象字面量

    Why? 花括號與樣式指南中每個其他花括號塊遵循相同的縮進(jìn)規(guī)則嘲玫,逗號也是。

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

教學(xué)項(xiàng)目中不換行并扇,選前者

Variables

<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.5"></a>
<a name="variables--no-chain-assignment"></a>

  • 13.5 不要使用鏈?zhǔn)阶兞糠峙洹?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 不要使用一元自增自減運(yùn)算符(++--). eslint no-plusplus

    Why? 根據(jù)eslint文檔俩莽,一元增量和減量語句受到自動分號插入的影響旺坠,并且可能會導(dǎo)致應(yīng)用程序中的值遞增或遞減的無聲錯誤。 使用num + = 1而不是num ++num ++語句來表達(dá)你的值也是更有表現(xiàn)力的扮超。 禁止一元增量和減量語句還會阻止您無意地預(yù)增/預(yù)減值取刃,這也會導(dǎo)致程序出現(xiàn)意外行為蹋肮。

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

<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? 一個聲明了但未使用的變量更像是由于重構(gòu)未完成產(chǎn)生的錯誤漆魔。這種在代碼中出現(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' 即使沒有使用也可以可以被忽略改抡, 因?yàn)檫@個有一個 rest 取值的屬性。
    // 這是從對象中抽取一個忽略特殊字段的對象的一種形式
    var { type, ...coords } = data;
    // 'coords' 現(xiàn)在就是一個沒有 'type' 屬性的 'data' 對象
    

Comparison Operators & Equality

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

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

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

  • 15.6 三元表達(dá)式不應(yīng)該嵌套系瓢,通常是單行表達(dá)式阿纤。

    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 避免不需要的三元表達(dá)式

    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 用圓括號來混合這些操作符。 只有當(dāng)標(biāo)準(zhǔn)的算術(shù)運(yùn)算符(+, -, *, & /)夷陋, 并且它們的優(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;
    

Blocks

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

  • 16.2 if表達(dá)式的elseif的關(guān)閉大括號在一行藐窄。 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;
      }
    }
    

Control Statements

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

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

    Why? 把邏輯操作符放在行首是讓操作符的對齊方式和鏈?zhǔn)胶瘮?shù)保持一致嘶卧。這提高了可讀性,也讓復(fù)雜邏輯更容易看清楚凉袱。

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

不做強(qiáng)制要求

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ù)調(diào)用和定義時钟鸵,參數(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 用空格來隔開運(yùn)算符涤躲。 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 文件結(jié)尾空一行. 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 當(dāng)出現(xiàn)長的方法鏈(>2個)時用縮進(jìn)棺耍。用點(diǎn)開頭強(qiáng)調(diào)該行是一個方法調(diào)用,而不是一個新的語句种樱。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="19.9"></a>
<a name="whitespace--in-parens"></a>

  • 19.9 圓括號里不要加空格。 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.10"></a>
<a name="whitespace--in-brackets"></a>

  • 19.10 方括號里不要加空格害幅∠校看示例。 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.11"></a>
<a name="whitespace--in-braces"></a>

  • 19.11 花括號里加空格狠怨。 eslint: object-curly-spacing

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

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

  • 19.12 避免一行代碼超過120個字符(包含空格)。

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

    Why? 這樣確奔呛校可讀性和可維護(hù)性

    // 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.13"></a>
<a name="whitespace--block-spacing"></a>

  • 19.13 作為語句的花括號內(nèi)也要加空格 —— { 后和 } 前都需要空格茵汰。 eslint: block-spacing

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

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

  • 19.14 , 前不要空格, , 后需要空格孽鸡。 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.15"></a>
<a name="whitespace--computed-property-spacing"></a>

  • 19.15 計(jì)算屬性內(nèi)要空格。參考上述花括號和中括號的規(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.16"></a>
<a name="whitespace--func-call-spacing"></a>

  • 19.16 調(diào)用函數(shù)時彬碱,函數(shù)名和小括號之間不要空格。 eslint: func-call-spacing

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

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

  • 19.17 在對象的字面量屬性中奥洼, key value 之間要有空格巷疼。 eslint: key-spacing

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

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

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

  • 19.19 避免出現(xiàn)多個空行灵奖。 在文件末尾只允許空一行嚼沿。 eslint: no-multiple-empty-lines

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

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 額外結(jié)尾逗號: eslint: comma-dangle

    Why? 這導(dǎo)致git diffs更清潔瓷患。 此外骡尽,像Babel這樣的轉(zhuǎn)換器會刪除轉(zhuǎn)換代碼中的額外的逗號,這意味著你不必?fù)?dān)心舊版瀏覽器中的結(jié)尾逗號問題擅编。

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

Semicolons

<a name="21.1"></a>

  • 21.1 Yup. eslint: semi

    Why? 當(dāng) JavaScript 遇到?jīng)]有分號結(jié)尾的一行攀细,它會執(zhí)行自動插入分號 Automatic Semicolon Insertion這一規(guī)則來決定行末是否加分號。如果JavaScript在你的斷行里錯誤的插入了分號爱态,就會出現(xiàn)一些古怪的行為谭贪。當(dāng)新的功能加到JavaScript里后, 這些規(guī)則會變得更復(fù)雜難懂锦担。顯示的結(jié)束語句俭识,并通過配置代碼檢查去捕獲沒有帶分號的地方可以幫助你防止這種錯誤。

    // bad
    (function () {
      const name = 'Skywalker'
      return name
    })()
    
    // good
    (function () {
      const name = 'Skywalker';
      return name;
    }());
    
    // good, 行首加分號洞渔,避免文件被連接到一起時立即執(zhí)行函數(shù)被當(dāng)做變量來執(zhí)行套媚。
    ;(() => {
      const name = 'Skywalker';
      return name;
    }());
    

    Read more.

Type Casting & Coercion

<a name="22.1"></a>
<a name="coercion--explicit"></a>

  • 22.1 在語句開始執(zhí)行強(qiáng)制類型轉(zhuǎn)換缚态。

<a name="22.2"></a>
<a name="coercion--strings"></a>

  • 22.2 Strings: eslint: no-new-wrappers

    // => this.reviewScore = 9;
    
    // bad
    const totalScore = new String(this.reviewScore); // typeof totalScore is "object" not "string"
    
    // bad
    const totalScore = this.reviewScore + ''; // invokes this.reviewScore.valueOf()
    
    // bad
    const totalScore = this.reviewScore.toString(); // 不保證返回string
    
    // good
    const totalScore = String(this.reviewScore);
    

<a name="22.3"></a>
<a name="coercion--numbers"></a>

  • 22.3 Numbers: 用 Number 做類型轉(zhuǎn)換,parseInt轉(zhuǎn)換string常需要帶上基數(shù)凑阶。 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);
    

<a name="22.6"></a>
<a name="coercion--booleans"></a>

  • 22.6 布爾:

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

<a name="23.4"></a>
<a name="naming--leading-underscore"></a>

  • 23.4 不要用前置或后置下劃線猿规。 eslint: no-underscore-dangle

    Why? JavaScript 沒有私有屬性或私有方法的概念。盡管前置下劃線通常的概念上意味著“private”宙橱,事實(shí)上姨俩,這些屬性是完全公有的,因此這部分也是你的API的內(nèi)容师郑。這一概念可能會導(dǎo)致開發(fā)者誤以為更改這個不會導(dǎo)致崩潰或者不需要測試环葵。 如果你想要什么東西變成“private”,那就不要讓它在這里出現(xiàn)宝冕。

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

<a name="23.5"></a>
<a name="naming--self-this"></a>

  • 23.5 不要保存引用this张遭, 用箭頭函數(shù)或函數(shù)綁定——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);
      };
    }
    

<a name="23.6"></a>
<a name="naming--filename-matches-export"></a>

  • 23.6 export default導(dǎo)出模塊A,則這個文件名也叫A.*地梨, import 時候的參數(shù)也叫A菊卷。 大小寫完全一致。

    // 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
    
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末宝剖,一起剝皮案震驚了整個濱河市洁闰,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌万细,老刑警劉巖扑眉,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異赖钞,居然都是意外死亡腰素,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進(jìn)店門雪营,熙熙樓的掌柜王于貴愁眉苦臉地迎上來弓千,“玉大人,你說我怎么就攤上這事卓缰〖瞥剩” “怎么了?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵征唬,是天一觀的道長捌显。 經(jīng)常有香客問我,道長总寒,這世上最難降的妖魔是什么扶歪? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上善镰,老公的妹妹穿的比我還像新娘妹萨。我一直安慰自己瞬沦,他們只是感情好浮声,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布禁荒。 她就那樣靜靜地躺著坷备,像睡著了一般。 火紅的嫁衣襯著肌膚如雪裁赠。 梳的紋絲不亂的頭發(fā)上蹈集,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天闺兢,我揣著相機(jī)與錄音桥状,去河邊找鬼帽揪。 笑死,一個胖子當(dāng)著我的面吹牛辅斟,可吹牛的內(nèi)容都是我干的转晰。 我是一名探鬼主播,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼士飒,長吁一口氣:“原來是場噩夢啊……” “哼查邢!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起酵幕,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤侠坎,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后裙盾,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡他嫡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年番官,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片钢属。...
    茶點(diǎn)故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡徘熔,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出淆党,到底是詐尸還是另有隱情酷师,我是刑警寧澤,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布染乌,位于F島的核電站山孔,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏荷憋。R本人自食惡果不足惜台颠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望勒庄。 院中可真熱鬧串前,春花似錦瘫里、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至坛吁,卻和暖如春劳殖,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背阶冈。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工闷尿, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人女坑。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓填具,卻偏偏與公主長得像,于是被迫代替她去往敵國和親匆骗。 傳聞我的和親對象是個殘疾皇子劳景,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,060評論 2 355

推薦閱讀更多精彩內(nèi)容