{"id":21055214,"url":"https://github.com/dangkyokhoang/javascript-style-guide","last_synced_at":"2025-07-23T07:03:29.329Z","repository":{"id":263481444,"uuid":"165032930","full_name":"dangkyokhoang/javascript-style-guide","owner":"dangkyokhoang","description":"Bản dịch tiếng Việt cho Định hướng Lối viết JavaScript của Airbnb","archived":false,"fork":false,"pushed_at":"2021-05-18T05:50:02.000Z","size":46,"stargazers_count":105,"open_issues_count":0,"forks_count":45,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-05-15T23:42:02.195Z","etag":null,"topics":["arrow-functions","es2015","es2016","es2017","es2018","es6","eslint","javascript","linting","naming-conventions","style-guide","style-linter","styleguide","tc39","vietnamese"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dangkyokhoang.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2019-01-10T09:43:22.000Z","updated_at":"2025-04-03T06:43:39.000Z","dependencies_parsed_at":null,"dependency_job_id":"f7ff9a78-cf63-43a9-9502-9f411ab63167","html_url":"https://github.com/dangkyokhoang/javascript-style-guide","commit_stats":null,"previous_names":["dangkyokhoang/javascript-style-guide"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/dangkyokhoang/javascript-style-guide","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dangkyokhoang%2Fjavascript-style-guide","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dangkyokhoang%2Fjavascript-style-guide/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dangkyokhoang%2Fjavascript-style-guide/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dangkyokhoang%2Fjavascript-style-guide/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dangkyokhoang","download_url":"https://codeload.github.com/dangkyokhoang/javascript-style-guide/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dangkyokhoang%2Fjavascript-style-guide/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266633043,"owners_count":23959466,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-23T02:00:09.312Z","response_time":66,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["arrow-functions","es2015","es2016","es2017","es2018","es6","eslint","javascript","linting","naming-conventions","style-guide","style-linter","styleguide","tc39","vietnamese"],"created_at":"2024-11-19T16:37:33.051Z","updated_at":"2025-07-23T07:03:29.259Z","avatar_url":"https://github.com/dangkyokhoang.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# \u003ca name=\"airbnb-javascript-style-guide-\"\u003eĐịnh hướng Lối viết JavaScript của Airbnb() {\u003c/a\u003e\n\n*Một cách tiếp cận hợp lý đối với JavaScript*\n\n\u003e **Lưu ý của người dịch**: Bản dịch này, với nỗ lực truyền đạt nội dung bằng tiếng Việt nhiều nhất có thể, đã dịch sang tiếng Việt các thuật ngữ, và/hoặc các từ, cụm từ mà thông thường không được dịch, như: \"style guide\", \"object\", \"polyfill\", v.v. Nếu bạn cảm thấy không quen thuộc hoặc khó khăn trong việc hiểu một số từ trong bản dịch này, hoặc muốn biết các từ tương ứng trong Tiếng Anh, vui lòng tham khảo phần [Danh mục các Thuật ngữ](#terminology).\n\n\u003e **Lưu ý**: Định hướng này giả định bạn đang sử dụng [Babel](https://babeljs.io), và đòi hỏi bạn sử dụng [babel-preset-airbnb](https://npmjs.com/babel-preset-airbnb) hoặc một bộ tương đương. Nó cũng giả định rằng bạn đang cài bộ trợ năng cho ứng dụng của bạn, như [airbnb-browser-shims](https://npmjs.com/airbnb-browser-shims) hoặc một bộ tương đương.\n\n[![Lượt tải](https://img.shields.io/npm/dm/eslint-config-airbnb.svg)](https://www.npmjs.com/package/eslint-config-airbnb)\n[![Lượt tải](https://img.shields.io/npm/dm/eslint-config-airbnb-base.svg)](https://www.npmjs.com/package/eslint-config-airbnb-base)\n[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/airbnb/javascript?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge)\n\nĐịnh hướng này cũng được dịch sang các ngôn ngữ khác. Xem phần [Dịch](#translation).\n\nCác Định hướng Lối viết Khác\n\n  - [ES5 (Đã lỗi thời)](https://github.com/airbnb/javascript/tree/es5-deprecated/es5)\n  - [React](https://github.com/airbnb/javascript/blob/master/react)\n  - [CSS-trong-JavaScript](https://github.com/airbnb/javascript/blob/master/css-in-javascript)\n  - [CSS \u0026 Sass](https://github.com/airbnb/css)\n  - [Ruby](https://github.com/airbnb/ruby)\n\n## \u003ca name=\"table-of-contents\"\u003eMục lục\u003c/a\u003e\n\n  1. [Các Kiểu giá trị](#types)\n  1. [Các Tham chiếu](#references)\n  1. [Các Đối tượng](#objects)\n  1. [Các Mảng](#arrays)\n  1. [Trích xuất](#destructuring)\n  1. [Các Chuỗi](#strings)\n  1. [Các Hàm](#functions)\n  1. [Các Hàm mũi tên](#arrow-functions)\n  1. [Các Lớp \u0026 các Hàm tạo](#classes--constructors)\n  1. [Các Mô-đun](#modules)\n  1. [Các Đối tượng duyệt and các Hàm sinh trị](#iterators-and-generators)\n  1. [Các Thuộc tính](#properties)\n  1. [Các Biến](#variables)\n  1. [Sự kéo lên](#hoisting)\n  1. [Các Toán tử So sánh và Sự bằng nhau](#comparison-operators--equality)\n  1. [Các Khối](#blocks)\n  1. [Các Câu lệnh Điều khiển](#control-statements)\n  1. [Các Chú thích](#comments)\n  1. [Khoảng trắng](#whitespace)\n  1. [Các Dấu phẩy](#commas)\n  1. [Các Dấu chấm phẩy](#semicolons)\n  1. [Sự ép kiểu](#type-casting--coercion)\n  1. [Các Quy ước Đặt tên](#naming-conventions)\n  1. [Các Hàm truy cập](#accessors)\n  1. [Các Sự kiện](#events)\n  1. [jQuery](#jquery)\n  1. [Tính tương thích của ECMAScript 5](#ecmascript-5-compatibility)\n  1. [Lối viết ECMAScript 6+ (ES 2015+)](#ecmascript-6-es-2015-styles)\n  1. [Thư viện Tiêu chuẩn](#standard-library)\n  1. [Sự kiểm thử](#testing)\n  1. [Hiệu suất](#performance)\n  1. [Các Tài nguyên](#resources)\n  1. [Thực tế Áp dụng](#in-the-wild)\n  1. [Danh mục các Thuật ngữ](#terminology)\n  1. [Dịch](#translation)\n  1. [Về Hướng dẫn Lối viết JavaScript](#the-javascript-style-guide-guide)\n  1. [Nói chuyện với Chúng tôi về JavaScript](#chat-with-us-about-javascript)\n  1. [Những Người đóng góp](#contributors)\n  1. [Giấy phép](#license)\n  1. [Các Sửa đổi](#amendments)\n\n## \u003ca name=\"types\"\u003eCác Kiểu giá trị\u003c/a\u003e\n\n  \u003ca name=\"types--primitives\"\u003e\u003c/a\u003e\u003ca name=\"1.1\"\u003e\u003c/a\u003e\n  - [1.1](#types--primitives) **Kiểu nguyên thủy**: Khi bạn truy cập một giá trị kiểu nguyên thủy, bạn làm việc trực tiếp trên giá trị của nó.\n\n    - `string`\n    - `number`\n    - `boolean`\n    - `null`\n    - `undefined`\n    - `symbol`\n    - `bigint`\n\n    ``` javascript\n    const foo = 1;\n    let bar = foo;\n\n    bar = 9;\n\n    console.log(foo, bar); // =\u003e 1, 9\n    ```\n\n    - Sự thiếu hỗ trợ cho các `Symbol` và `BigInt` không thể được lấp đầy bởi các bộ trợ năng một cách toàn diện, do đó, chúng không nên được sử dụng khi hướng đến các trình duyệt/môi trường không có hỗ trợ sẵn.\n\n  \u003ca name=\"types--complex\"\u003e\u003c/a\u003e\u003ca name=\"1.2\"\u003e\u003c/a\u003e\n  - [1.2](#types--complex) **Kiểu phức tạp**: Khi bạn truy cập một giá trị kiểu phức tạp, bạn làm việc trên tham chiếu giá trị của nó.\n\n    - `object`\n    - `array`\n    - `function`\n\n    ``` javascript\n    const foo = [1, 2];\n    const bar = foo;\n\n    bar[0] = 9;\n\n    console.log(foo[0], bar[0]); // =\u003e 9, 9\n    ```\n\n**[⬆ về đầu trang](#table-of-contents)**\n\n## \u003ca name=\"references\"\u003eCác Tham chiếu\u003c/a\u003e\n\n  \u003ca name=\"references--prefer-const\"\u003e\u003c/a\u003e\u003ca name=\"2.1\"\u003e\u003c/a\u003e\n  - [2.1](#references--prefer-const) Sử dụng `const` đối với tất cả các tham chiếu; tránh sử dụng `var`. eslint: [`prefer-const`](https://eslint.org/docs/rules/prefer-const.html), [`no-const-assign`](https://eslint.org/docs/rules/no-const-assign.html)\n\n    \u003e Tại sao? Điều này đảm bảo rằng bạn không thể gán lại các tham chiếu, việc có thể gây ra các lỗi và gây khó khăn cho sự đọc hiểu mã nguồn.\n\n    ``` javascript\n    // không tốt\n    var a = 1;\n    var b = 2;\n\n    // tốt\n    const a = 1;\n    const b = 2;\n    ```\n\n  \u003ca name=\"references--disallow-var\"\u003e\u003c/a\u003e\u003ca name=\"2.2\"\u003e\u003c/a\u003e\n  - [2.2](#references--disallow-var) Nếu bạn bắt buộc phải gán lại các tham chiếu, sử dụng `let`, thay vì `var`. eslint: [`no-var`](https://eslint.org/docs/rules/no-var.html)\n\n    \u003e Tại sao? `let` thuộc phạm vi khối mà nó được khởi tạo, thay vì thuộc phạm vi hàm như `var`.\n\n    ``` javascript\n    // không tốt\n    var count = 1;\n    if (true) {\n      count += 1;\n    }\n\n    // tốt, sử dụng let.\n    let count = 1;\n    if (true) {\n      count += 1;\n    }\n    ```\n\n  \u003ca name=\"references--block-scope\"\u003e\u003c/a\u003e\u003ca name=\"2.3\"\u003e\u003c/a\u003e\n  - [2.3](#references--block-scope) Lưu ý rằng cả `let` và `const` đều thuộc phạm vi khối, còn `var` thuộc phạm vi hàm.\n\n    ``` javascript\n    // const và let chỉ tồn tại trong phạm vi khối tạo ra chúng.\n    {\n      let a = 1;\n      const b = 1;\n      var c = 1;\n    }\n    console.log(a); // ReferenceError\n    console.log(b); // ReferenceError\n    console.log(c); // In ra 1\n    ```\n\n    Trong đoạn mã trên, bạn có thể thấy rằng lỗi ReferenceError xảy ra khi truy cập `a` và `b`, trong khi `c` vẫn là số đã gán. Nguyên nhân là vì `a` và `b` thuộc phạm vi khối, còn `c` thuộc phạm vi hàm chứa đoạn mã trên.\n\n**[⬆ về đầu trang](#table-of-contents)**\n\n## \u003ca name=\"objects\"\u003eCác Đối tượng\u003c/a\u003e\n\n  \u003ca name=\"objects--no-new\"\u003e\u003c/a\u003e\u003ca name=\"3.1\"\u003e\u003c/a\u003e\n  - [3.1](#objects--no-new) Sử dụng cú pháp nguyên văn `{}` để khởi tạo đối tượng. eslint: [`no-new-object`](https://eslint.org/docs/rules/no-new-object.html)\n\n    ``` javascript\n    // không tốt\n    const item = new Object();\n\n    // tốt\n    const item = {};\n    ```\n\n  \u003ca name=\"es6-computed-properties\"\u003e\u003c/a\u003e\u003ca name=\"3.4\"\u003e\u003c/a\u003e\n  - [3.2](#es6-computed-properties) Sử dụng các tên được tính của thuộc tính `[key()]` khi tạo các đối tượng có các tên của thuộc tính là động.\n\n    \u003e Tại sao? Chúng cho phép bạn định nghĩa tất cả các thuộc tính của một đối tượng cùng một chỗ.\n\n    ``` javascript\n\n    function getKey(k) {\n      return `tên của thuộc tính là ${k}`;\n    }\n\n    // không tốt\n    const obj = {\n      id: 5,\n      name: 'San Francisco',\n    };\n    obj[getKey('enabled')] = true;\n\n    // tốt\n    const obj = {\n      id: 5,\n      name: 'San Francisco',\n      [getKey('enabled')]: true,\n    };\n    ```\n\n  \u003ca name=\"es6-object-shorthand\"\u003e\u003c/a\u003e\u003ca name=\"3.5\"\u003e\u003c/a\u003e\n  - [3.3](#es6-object-shorthand) Sử dụng cú pháp định nghĩa phương thức rút gọn để định nghĩa các phương thức của đối tượng. eslint: [`object-shorthand`](https://eslint.org/docs/rules/object-shorthand.html)\n\n    ``` javascript\n    // không tốt\n    const atom = {\n      value: 1,\n\n      addValue: function (value) {\n        return atom.value + value;\n      },\n    };\n\n    // tốt\n    const atom = {\n      value: 1,\n\n      addValue(value) {\n        return atom.value + value;\n      },\n    };\n    ```\n\n  \u003ca name=\"es6-object-concise\"\u003e\u003c/a\u003e\u003ca name=\"3.6\"\u003e\u003c/a\u003e\n  - [3.4](#es6-object-concise) Sử dụng cú pháp định nghĩa thuộc tính rút gọn để định nghĩa các thuộc tính của đối tượng. eslint: [`object-shorthand`](https://eslint.org/docs/rules/object-shorthand.html)\n\n    \u003e Tại sao? Nó ngắn gọn và súc tích.\n\n    ``` javascript\n    const lukeSkywalker = 'Luke Skywalker';\n\n    // không tốt\n    const obj = {\n      lukeSkywalker: lukeSkywalker,\n    };\n\n    // tốt\n    const obj = {\n      lukeSkywalker,\n    };\n    ```\n\n  \u003ca name=\"objects--grouped-shorthand\"\u003e\u003c/a\u003e\u003ca name=\"3.7\"\u003e\u003c/a\u003e\n  - [3.5](#objects--grouped-shorthand) Gom tất cả các thuộc tính rút gọn ở trên cùng khi khai báo đối tượng.\n\n    \u003e Tại sao? Điều này giúp bạn dễ dàng biết được thuộc tính nào sử dụng cú pháp rút gọn.\n\n    ``` javascript\n    const anakinSkywalker = 'Anakin Skywalker';\n    const lukeSkywalker = 'Luke Skywalker';\n\n    // không tốt\n    const obj = {\n      episodeOne: 1,\n      twoJediWalkIntoACantina: 2,\n      lukeSkywalker,\n      episodeThree: 3,\n      mayTheFourth: 4,\n      anakinSkywalker,\n    };\n\n    // tốt\n    const obj = {\n      lukeSkywalker,\n      anakinSkywalker,\n      episodeOne: 1,\n      twoJediWalkIntoACantina: 2,\n      episodeThree: 3,\n      mayTheFourth: 4,\n    };\n    ```\n\n  \u003ca name=\"objects--quoted-props\"\u003e\u003c/a\u003e\u003ca name=\"3.8\"\u003e\u003c/a\u003e\n  - [3.6](#objects--quoted-props) Chỉ sử dụng dấu lược `' '` cho các thuộc tính có định danh không hợp lệ. eslint: [`quote-props`](https://eslint.org/docs/rules/quote-props.html)\n\n    \u003e Tại sao? Nhìn chung, chúng ta sẽ thấy nó dễ đọc hơn nhiều. Nó cải thiện nhấn mạnh cú pháp, và nó cũng giúp việc tối ưu hóa bằng các trình thực thi JS hiệu quả hơn.\n\n    ``` javascript\n    // không tốt\n    const bad = {\n      'foo': 3,\n      'bar': 4,\n      'một-cái-tên': 5,\n    };\n\n    // tốt\n    const good = {\n      foo: 3,\n      bar: 4,\n      'một-cái-tên': 5,\n    };\n    ```\n\n  \u003ca name=\"objects--prototype-builtins\"\u003e\u003c/a\u003e\n  - [3.7](#objects--prototype-builtins) Không gọi các phương thức `Object.prototype` một cách trực tiếp, ví dụ như `hasOwnProperty`, `propertyIsEnumerable`, và `isPrototypeOf`. eslint: [`no-prototype-builtins`](https://eslint.org/docs/rules/no-prototype-builtins)\n\n    \u003e Tại sao? Những phương thức này có thể bị thay thế bởi các thuộc tính của một đối tượng - như `{ hasOwnProperty: false }` - hoặc, đối tượng có thể là một đối tượng rỗng (`Object.create(null)`).\n\n    ``` javascript\n    // không tốt\n    console.log(object.hasOwnProperty(key));\n\n    // tốt\n    console.log(Object.prototype.hasOwnProperty.call(object, key));\n\n    // tốt nhất\n    const has = Object.prototype.hasOwnProperty; // lưu tạm phương thức một lần, dùng cho cả mô-đun.\n    console.log(has.call(object, key));\n    /* hoặc */\n    import has from 'has'; // https://www.npmjs.com/package/has\n    console.log(has.call(object, key));\n    ```\n\n  \u003ca name=\"objects--rest-spread\"\u003e\u003c/a\u003e\n  - [3.8](#objects--rest-spread) Ưu tiên sử dụng cú pháp liệt kê `...` so với [`Object.assign`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) để tạo bản sao nhanh của một đối tượng. Sử dụng toán tử còn-lại `...` để tạo một đối tượng mới với một số thuộc tính đã bị loại bỏ. eslint: [`prefer-object-spread`](https://eslint.org/docs/rules/prefer-object-spread)\n\n    ``` javascript\n    // rất không tốt\n    const original = { a: 1, b: 2 };\n    const copy = Object.assign(original, { c: 3 }); // cái này làm biến đổi `original` ಠ_ಠ\n    delete copy.a; // cái này cũng vậy\n\n    // không tốt\n    const original = { a: 1, b: 2 };\n    const copy = Object.assign({}, original, { c: 3 }); // copy =\u003e { a: 1, b: 2, c: 3 }\n\n    // tốt\n    const original = { a: 1, b: 2 };\n    const copy = { ...original, c: 3 }; // copy =\u003e { a: 1, b: 2, c: 3 }\n\n    const { a, ...noA } = copy; // noA =\u003e { b: 2, c: 3 }\n    ```\n\n**[⬆ về đầu trang](#table-of-contents)**\n\n## \u003ca name=\"arrays\"\u003eCác Mảng\u003c/a\u003e\n\n  \u003ca name=\"arrays--literals\"\u003e\u003c/a\u003e\u003ca name=\"4.1\"\u003e\u003c/a\u003e\n  - [4.1](#arrays--literals) Sử dụng cú pháp nguyên văn `[]` để khởi tạo mảng. eslint: [`no-array-constructor`](https://eslint.org/docs/rules/no-array-constructor.html)\n\n    ``` javascript\n    // không tốt\n    const items = new Array();\n\n    // tốt\n    const items = [];\n    ```\n\n  \u003ca name=\"arrays--push\"\u003e\u003c/a\u003e\u003ca name=\"4.2\"\u003e\u003c/a\u003e\n  - [4.2](#arrays--push) Sử dụng [Array#push](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/push), thay vì phép gán, để thêm các mục cho một mảng.\n\n    ``` javascript\n    const someStack = [];\n\n    // không tốt\n    someStack[someStack.length] = 'abracadabra';\n\n    // tốt\n    someStack.push('abracadabra');\n    ```\n\n  \u003ca name=\"es6-array-spreads\"\u003e\u003c/a\u003e\u003ca name=\"4.3\"\u003e\u003c/a\u003e\n  - [4.3](#es6-array-spreads) Sử dụng toán tử liệt kê `...` để sao nhanh một mảng.\n\n    ``` javascript\n    // không tốt\n    const len = items.length;\n    const itemsCopy = [];\n    let i;\n\n    for (i = 0; i \u003c len; i += 1) {\n      itemsCopy[i] = items[i];\n    }\n\n    // tốt\n    const itemsCopy = [...items];\n    ```\n\n  \u003ca name=\"arrays--from\"\u003e\u003c/a\u003e\n  \u003ca name=\"arrays--from-iterable\"\u003e\u003c/a\u003e\u003ca name=\"4.4\"\u003e\u003c/a\u003e\n  - [4.4](#arrays--from-iterable) Để chuyển đổi một đối tượng khả duyệt thành một mảng, sử dụng toán tử liệt kê `...` thay vì [`Array.from`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/from).\n\n    ``` javascript\n    const foo = document.querySelectorAll('.foo');\n\n    // tốt\n    const nodes = Array.from(foo);\n\n    // tốt nhất\n    const nodes = [...foo];\n    ```\n\n  \u003ca name=\"arrays--from-array-like\"\u003e\u003c/a\u003e\n  - [4.5](#arrays--from-array-like) Sử dụng [`Array.from`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/from) để chuyển đổi một đối tượng giống-mảng thành một mảng.\n\n    ``` javascript\n    const arrLike = { 0: 'foo', 1: 'bar', 2: 'baz', length: 3 };\n\n    // không tốt\n    const arr = Array.prototype.slice.call(arrLike);\n\n    // tốt\n    const arr = Array.from(arrLike);\n    ```\n\n  \u003ca name=\"arrays--mapping\"\u003e\u003c/a\u003e\n  - [4.6](#arrays--mapping) Sử dụng [`Array.from`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/from), thay vì toán tử liệt kê `...`, để ánh xạ một đối tượng khả duyệt, vì nó không tạo ra một mảng trung gian.\n\n    ``` javascript\n    // không tốt\n    const baz = [...foo].map(bar);\n\n    // tốt\n    const baz = Array.from(foo, bar);\n    ```\n\n  \u003ca name=\"arrays--callback-return\"\u003e\u003c/a\u003e\u003ca name=\"4.5\"\u003e\u003c/a\u003e\n  - [4.7](#arrays--callback-return) Sử dụng các lệnh `return` cho các hàm gọi lại dùng cho các phương thức của mảng. Được phép bỏ qua `return` nếu phần thân hàm chỉ gồm một câu lệnh trả về một biểu thức không có hiệu ứng phụ, theo quy tắc [8.2](#arrows--implicit-return). eslint: [`array-callback-return`](https://eslint.org/docs/rules/array-callback-return)\n\n    ``` javascript\n    // tốt\n    [1, 2, 3].map((x) =\u003e {\n      const y = x + 1;\n      return x * y;\n    });\n\n    // tốt\n    [1, 2, 3].map((x) =\u003e x + 1);\n\n    // không tốt - không có giá trị trả về đồng nghĩa với `acc` sẽ trở thành undefined sau lượt duyệt đầu tiên\n    [[0, 1], [2, 3], [4, 5]].reduce((acc, item, index) =\u003e {\n      const flatten = acc.concat(item);\n    });\n\n    // tốt\n    [[0, 1], [2, 3], [4, 5]].reduce((acc, item, index) =\u003e {\n      const flatten = acc.concat(item);\n      return flatten;\n    });\n\n    // không tốt\n    inbox.filter((msg) =\u003e {\n      const { subject, author } = msg;\n      if (subject === 'Con chim nhại') {\n        return author === 'Harper Lee';\n      } else {\n        return false;\n      }\n    });\n\n    // tốt\n    inbox.filter((msg) =\u003e {\n      const { subject, author } = msg;\n      if (subject === 'Con chim nhại') {\n        return author === 'Harper Lee';\n      }\n\n      return false;\n    });\n    ```\n\n  \u003ca name=\"arrays--bracket-newline\"\u003e\u003c/a\u003e\n  - [4.8](#arrays--bracket-newline) Sử dụng dấu ngắt dòng trước và sau các dấu đóng và mở ngoặc vuông nếu một mảng nằm trên nhiều dòng.\n\n    ``` javascript\n    // không tốt\n    const arr = [\n      [0, 1], [2, 3], [4, 5],\n    ];\n\n    const objectInArray = [{\n      id: 1,\n    }, {\n      id: 2,\n    }];\n\n    const numberInArray = [\n      1, 2,\n    ];\n\n    // tốt\n    const arr = [[0, 1], [2, 3], [4, 5]];\n\n    const objectInArray = [\n      {\n        id: 1,\n      },\n      {\n        id: 2,\n      },\n    ];\n\n    const numberInArray = [\n      1,\n      2,\n    ];\n    ```\n\n**[⬆ về đầu trang](#table-of-contents)**\n\n## \u003ca name=\"destructuring\"\u003eTrích xuất\u003c/a\u003e\n\n  \u003ca name=\"destructuring--object\"\u003e\u003c/a\u003e\u003ca name=\"5.1\"\u003e\u003c/a\u003e\n  - [5.1](#destructuring--object) Sử dụng trích xuất đối tượng khi truy cập và sử dụng nhiều thuộc tính của một đối tượng. eslint: [`prefer-destructuring`](https://eslint.org/docs/rules/prefer-destructuring)\n\n    \u003e Tại sao? Trích xuất giúp việc tạo các tham chiếu đến các thuộc tính trở nên dễ dàng hơn và hạn chế việc truy cập một đối tượng lặp đi lặp lại. Việc truy cập đối tượng lặp đi lặp lại tạo ra nhiều đoạn mã trùng lặp hơn, cần phải đọc nhiều hơn, và tăng khả năng xảy ra nhầm lẫn. Trích xuất đối tượng cũng tạo nên một ý tưởng về cấu trúc của đối tượng được sử dụng trong khối, thay vì cần phải đọc toàn bộ khối để xác định những thuộc tính được sử dụng.\n\n    ``` javascript\n    // không tốt\n    function getFullName(user) {\n      const firstName = user.firstName;\n      const lastName = user.lastName;\n\n      return `${firstName} ${lastName}`;\n    }\n\n    // tốt\n    function getFullName(user) {\n      const { firstName, lastName } = user;\n      return `${firstName} ${lastName}`;\n    }\n\n    // best\n    function getFullName({ firstName, lastName }) {\n      return `${firstName} ${lastName}`;\n    }\n    ```\n\n  \u003ca name=\"destructuring--array\"\u003e\u003c/a\u003e\u003ca name=\"5.2\"\u003e\u003c/a\u003e\n  - [5.2](#destructuring--array) Hãy sử dụng trích xuất mảng. eslint: [`prefer-destructuring`](https://eslint.org/docs/rules/prefer-destructuring)\n\n    ``` javascript\n    const arr = [1, 2, 3, 4];\n\n    // không tốt\n    const first = arr[0];\n    const second = arr[1];\n\n    // tốt\n    const [first, second] = arr;\n    ```\n\n  \u003ca name=\"destructuring--object-over-array\"\u003e\u003c/a\u003e\u003ca name=\"5.3\"\u003e\u003c/a\u003e\n  - [5.3](#destructuring--object-over-array) Sử dụng trích xuất đối tượng khi có nhiều giá trị trả về, thay vì trích xuất mảng.\n\n    \u003e Tại sao? Bạn có thể thêm các thuộc tính mới qua thời gian hay thay đổi thứ tự các thứ mà không lo làm hỏng các phép gọi trước đó.\n\n    ``` javascript\n    // không tốt\n    function processInput(input) {\n      // khi một phép màu xảy ra\n      return [left, right, top, bottom];\n    }\n\n    // người gọi cần nghĩ về thứ tự của giá trị trả về\n    const [left, __, top] = processInput(input);\n\n    // tốt\n    function processInput(input) {\n      // khi một phép màu xảy ra\n      return { left, right, top, bottom };\n    }\n\n    // người gọi chỉ cần chọn giá trị mà họ muốn\n    const { left, top } = processInput(input);\n    ```\n\n**[⬆ về đầu trang](#table-of-contents)**\n\n## \u003ca name=\"strings\"\u003eCác Chuỗi\u003c/a\u003e\n\n  \u003ca name=\"strings--quotes\"\u003e\u003c/a\u003e\u003ca name=\"6.1\"\u003e\u003c/a\u003e\n  - [6.1](#strings--quotes) Sử dụng dấu lược cho các chuỗi. eslint: [`quotes`](https://eslint.org/docs/rules/quotes.html)\n\n    ``` javascript\n    // không tốt\n    const name = \"Capt. Janeway\";\n\n    // không tốt - các nguyên văn mẫu nên chứa sự biến đổi chuỗi hoặc ngắt dòng\n    const name = `Capt. Janeway`;\n\n    // tốt\n    const name = 'Capt. Janeway';\n    ```\n\n  \u003ca name=\"strings--line-length\"\u003e\u003c/a\u003e\u003ca name=\"6.2\"\u003e\u003c/a\u003e\n  - [6.2](#strings--line-length) Các chuỗi, dù khiến cho độ dài của dòng lớn hơn 100 ký tự, không nên được viết thành nhiều dòng sử dụng ghép chuỗi.\n\n    \u003e Tại sao? Các chuỗi bị chia nhỏ rất khó để làm việc cùng và khiến việc tìm kiếm trong mã nguồn trở nên khó hơn.\n\n    ``` javascript\n    // không tốt\n    const errorMessage = 'Đây là một lỗi rất dài mà được ném ra bởi \\\n    Người Dơi. Khi bạn ngừng nghĩ về việc tại sao Người Dơi chẳng có liên \\\n    quan gì với thứ này, bạn sẽ vẫn chẳng đi đến đâu với \\\n    đâu.';\n\n    // không tốt\n    const errorMessage = 'Đây là một lỗi rất dài mà được ném ra bởi' +\n        'Người Dơi. Khi bạn ngừng nghĩ về việc tại sao Người Dơi chẳng có liên' +\n        'quan gì với thứ này, bạn sẽ vẫn chẳng đi đến đâu với' +\n        'đâu.';\n\n    // tốt\n    const errorMessage = 'Đây là một lỗi rất dài mà được ném ra bởi Người Dơi. Khi bạn ngừng nghĩ về việc tại sao Người Dơi chẳng có liên quan gì với thứ này, bạn sẽ vẫn chẳng đi đến đâu với đâu.';\n    ```\n\n  \u003ca name=\"es6-template-literals\"\u003e\u003c/a\u003e\u003ca name=\"6.4\"\u003e\u003c/a\u003e\n  - [6.3](#es6-template-literals) Khi xây dựng các chuỗi theo một chu trình, sử dụng mẫu chuỗi thay vì ghép chuỗi. eslint: [`prefer-template`](https://eslint.org/docs/rules/prefer-template.html) [`template-curly-spacing`](https://eslint.org/docs/rules/template-curly-spacing)\n\n    \u003e Tại sao? Các mẫu chuỗi cho bạn một cú pháp súc tích, dễ đọc với các ngắt dòng và các tính năng ghép chuỗi phù hợp.\n\n    ``` javascript\n    // không tốt\n    function sayHi(name) {\n      return 'Bạn có khỏe không, ' + name + '?';\n    }\n\n    // không tốt\n    function sayHi(name) {\n      return ['Bạn có khỏe không, ', name, '?'].join();\n    }\n\n    // tốt\n    function sayHi(name) {\n      return `Bạn có khỏe không, ${name}?`;\n    }\n    ```\n\n  \u003ca name=\"strings--eval\"\u003e\u003c/a\u003e\u003ca name=\"6.5\"\u003e\u003c/a\u003e\n  - [6.4](#strings--eval) Không bao giờ sử dụng `eval()` cho một chuỗi, điều đó mở ra rất nhiều các lỗ hổng và rủi ro. eslint: [`no-eval`](https://eslint.org/docs/rules/no-eval)\n\n  \u003ca name=\"strings--escaping\"\u003e\u003c/a\u003e\n  - [6.5](#strings--escaping) Không sử dụng các ký tự thoát trong một chuỗi khi không cần thiết. eslint: [`no-useless-escape`](https://eslint.org/docs/rules/no-useless-escape)\n\n    \u003e Tại sao? Các dấu chéo ngược làm giảm tính khả đọc, vì thế chúng chỉ nên xuất hiện khi cần.\n\n    ``` javascript\n    // không tốt\n    const foo = '\\'cái này\\' \\đư\\ợc \\\"cho trong ngoặc\\\"';\n\n    // tốt\n    const foo = '\\'cái này\\' được \"cho trong ngoặc\"';\n    const foo = `tên của tôi là '${name}'`;\n    ```\n\n**[⬆ về đầu trang](#table-of-contents)**\n\n## \u003ca name=\"functions\"\u003eCác Hàm\u003c/a\u003e\n\n  \u003ca name=\"functions--declarations\"\u003e\u003c/a\u003e\u003ca name=\"7.1\"\u003e\u003c/a\u003e\n  - [7.1](#functions--declarations) Sử dụng biểu thức hàm hữu danh thay vì khai báo hàm. eslint: [`func-style`](https://eslint.org/docs/rules/func-style)\n\n    \u003e Tại sao? Các khai báo hàm đều được kéo lên, đồng nghĩa với việc một hàm rất dễ có khả năng được sử dụng trước cả khi nó được định nghĩa trong tệp. Điều này làm giảm tính khả đọc và khả năng bảo trì. Nếu bạn thấy một hàm đủ lớn hoặc phức tạp đến mức ảnh hưởng đến việc đọc hiểu phần còn lại của tệp thì, có lẽ, nó nên được tách ra thành một mô-đun riêng! Đừng quên đặt tên cho biểu thức một cách rõ ràng, cho dù tên hàm có thể được suy ra từ tên biến chứa hàm đó (thường gặp ở các trình duyệt mới nhất hoặc các trình biên dịch như Babel). Điều này loại bỏ các nhận định liên quan đến ngăn xếp của một lỗi. ([Cuộc thảo luận](https://github.com/airbnb/javascript/issues/794))\n\n    ``` javascript\n    // không tốt\n    function foo() {\n      // ...\n    }\n\n    // không tốt\n    const foo = function () {\n      // ...\n    };\n\n    // tốt\n    // tên riêng của hàm, phân biệt với tên tham chiếu được gọi khi cần sử dụng\n    const short = function longUniqueMoreDescriptiveLexicalFoo() {\n      // ...\n    };\n    ```\n\n  \u003ca name=\"functions--iife\"\u003e\u003c/a\u003e\u003ca name=\"7.2\"\u003e\u003c/a\u003e\n  - [7.2](#functions--iife) Đặt các biểu thức hàm gọi tức thời trong ngoặc. eslint: [`wrap-iife`](https://eslint.org/docs/rules/wrap-iife.html)\n\n    \u003e Tại sao? Một biểu thức hàm gọi tức thời mà một đơn vị riêng - đặt nó và dấu ngoặc dùng để gọi nó `()` trong ngoặc để biểu đạt nó một cách rõ ràng. Cũng cần biết là, trong cái thế giới mà mô-đun ngập tràn mọi nơi như bây giờ, bạn cũng chả mấy khi cần dùng đến biểu thức hàm gọi tức thời.\n\n    ``` javascript\n    // biểu thức hàm gọi tức thời\n    (function () {\n      console.log('Xin chào đến với thế giới. Hãy đi theo tôi.');\n    }());\n    ```\n\n  \u003ca name=\"functions--in-blocks\"\u003e\u003c/a\u003e\u003ca name=\"7.3\"\u003e\u003c/a\u003e\n  - [7.3](#functions--in-blocks) Không bao giờ khai báo một hàm bên trong một khối không phải hàm (`if`, `while`, v.v.). Thay vào đó, hãy gán hàm cho một biến. Các trình duyệt đều sẽ cho phép bạn làm điều đó, nhưng tiếc là, cách mà chúng diễn dịch là khác nhau. eslint: [`no-loop-func`](https://eslint.org/docs/rules/no-loop-func.html)\n\n  \u003ca name=\"functions--note-on-blocks\"\u003e\u003c/a\u003e\u003ca name=\"7.4\"\u003e\u003c/a\u003e\n  - [7.4](#functions--note-on-blocks) **Ghi chú:** ECMA-262 định nghĩa một `khối` là tập hợp một hoặc một vài câu lệnh. Một khai báo hàm không phải là một câu lệnh.\n\n    ``` javascript\n    // không tốt\n    if (currentUser) {\n      function test() {\n        console.log('Đừng!');\n      }\n    }\n\n    // tốt\n    let test;\n    if (currentUser) {\n      test = () =\u003e {\n        console.log('Tốt đó.');\n      };\n    }\n    ```\n\n  \u003ca name=\"functions--arguments-shadow\"\u003e\u003c/a\u003e\u003ca name=\"7.5\"\u003e\u003c/a\u003e\n  - [7.5](#functions--arguments-shadow) Không bao giờ đặt tên một tham số là `arguments`. Tham số này sẽ được ưu tiên hơn đối tượng `arguments` được cung cấp cho mỗi phạm vi hàm.\n\n    ``` javascript\n    // không tốt\n    function foo(name, options, arguments) {\n      // ...\n    }\n\n    // tốt\n    function foo(name, options, args) {\n      // ...\n    }\n    ```\n\n  \u003ca name=\"es6-rest\"\u003e\u003c/a\u003e\u003ca name=\"7.6\"\u003e\u003c/a\u003e\n  - [7.6](#es6-rest) Không bao giờ sử dụng `arguments`, thay vào đó, hãy sử dụng cú pháp còn-lại `...`. eslint: [`prefer-rest-params`](https://eslint.org/docs/rules/prefer-rest-params)\n\n    \u003e Tại sao? `...` định rõ các đối số mà bạn muốn lấy. Thêm nữa, kết quả của còn-lại là một mảng đúng nghĩa, thay vì chỉ là giống-mảng như `arguments`.\n\n    ``` javascript\n    // không tốt\n    function concatenateAll() {\n      const args = Array.prototype.slice.call(arguments);\n      return args.join('');\n    }\n\n    // tốt\n    function concatenateAll(...args) {\n      return args.join('');\n    }\n    ```\n\n  \u003ca name=\"es6-default-parameters\"\u003e\u003c/a\u003e\u003ca name=\"7.7\"\u003e\u003c/a\u003e\n  - [7.7](#es6-default-parameters) Sử dụng tham số mặc định thay vì làm biến đổi các đối số truyền vào hàm.\n\n    ``` javascript\n    // rất tệ\n    function handleThings(opts) {\n      // Không! Chúng ta không nên biến đổi các đối số.\n      // Cái tệ thứ hai: Nếu opts là kiểu sai, nó sẽ bị đổi thành một đối tượng.\n      // Đó có thể là điều bạn muốn, nhưng nó thi thoảng gây ra lỗi.\n      opts = opts || {};\n      // ...\n    }\n\n    // vẫn tệ\n    function handleThings(opts) {\n      if (opts === void 0) {\n        opts = {};\n      }\n      // ...\n    }\n\n    // tốt\n    function handleThings(opts = {}) {\n      // ...\n    }\n    ```\n\n  \u003ca name=\"functions--default-side-effects\"\u003e\u003c/a\u003e\u003ca name=\"7.8\"\u003e\u003c/a\u003e\n  - [7.8](#functions--default-side-effects) Tránh gây ra hiệu ứng phụ với tham số mặc định.\n\n    \u003e Tại sao? Chúng khá là rối để có thể hình dung.\n\n    ``` javascript\n    var b = 1;\n    // không tốt\n    function count(a = b++) {\n      console.log(a);\n    }\n    count();  // 1\n    count();  // 2\n    count(3); // 3\n    count();  // 3\n    ```\n\n  \u003ca name=\"functions--defaults-last\"\u003e\u003c/a\u003e\u003ca name=\"7.9\"\u003e\u003c/a\u003e\n  - [7.9](#functions--defaults-last) Luôn để các tham số mặc định ở sau cùng. eslint: [`default-param-last`](https://eslint.org/docs/rules/default-param-last)\n\n    ``` javascript\n    // không tốt\n    function handleThings(opts = {}, name) {\n      // ...\n    }\n\n    // tốt\n    function handleThings(name, opts = {}) {\n      // ...\n    }\n    ```\n\n  \u003ca name=\"functions--constructor\"\u003e\u003c/a\u003e\u003ca name=\"7.10\"\u003e\u003c/a\u003e\n  - [7.10](#functions--constructor) Không bao giờ sử dụng hàm tạo `Function` để tạo hàm. eslint: [`no-new-func`](https://eslint.org/docs/rules/no-new-func)\n\n    \u003e Tại sao? Tạo một hàm theo cách này cũng thực thi chuỗi giống như `eval()` vậy, thứ mà mở ra các lỗ hổng.\n\n    ``` javascript\n    // không tốt\n    var add = new Function('a', 'b', 'return a + b');\n\n    // vẫn là không tốt\n    var subtract = Function('a', 'b', 'return a - b');\n    ```\n\n  \u003ca name=\"functions--signature-spacing\"\u003e\u003c/a\u003e\u003ca name=\"7.11\"\u003e\u003c/a\u003e\n  - [7.11](#functions--signature-spacing) Sử dụng các dấu cách giữa các bộ phận hàm. eslint: [`space-before-function-paren`](https://eslint.org/docs/rules/space-before-function-paren) [`space-before-blocks`](https://eslint.org/docs/rules/space-before-blocks)\n\n    \u003e Tại sao? Sự đồng nhất vẫn cứ là tốt, và bạn không cần phải thêm hoặc bớt dấu cách khi không đặt tên hàm.\n\n    ``` javascript\n    // không tốt\n    const f = function(){};\n    const g = function (){};\n    const h = function() {};\n\n    // tốt\n    const x = function () {};\n    const y = function a() {};\n    ```\n\n  \u003ca name=\"functions--mutate-params\"\u003e\u003c/a\u003e\u003ca name=\"7.12\"\u003e\u003c/a\u003e\n  - [7.12](#functions--mutate-params) Không bao giờ làm biến đổi các tham số. eslint: [`no-param-reassign`](https://eslint.org/docs/rules/no-param-reassign.html)\n\n    \u003e Tại sao? Việc can thiệp vào các đối tượng được truyền vào dưới dạng tham số có thể gây hiệu ứng phụ không mong muốn đối với biến tại tiến trình gọi.\n\n    ``` javascript\n    // không tốt\n    function f1(obj) {\n      obj.key = 1;\n    }\n\n    // tốt\n    function f2(obj) {\n      const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1;\n    }\n    ```\n\n  \u003ca name=\"functions--reassign-params\"\u003e\u003c/a\u003e\u003ca name=\"7.13\"\u003e\u003c/a\u003e\n  - [7.13](#functions--reassign-params) Không bao giờ gán lại các tham số. eslint: [`no-param-reassign`](https://eslint.org/docs/rules/no-param-reassign.html)\n\n    \u003e Tại sao? Việc gán lại các tham số có thể dẫn tới hành vi không mong muốn, đặc biệt là khi truy cập đối tượng `arguments`. Nó cũng có thể gây ra một số vấn đề về tối ưu hóa, nhất là trong V8.\n\n    ``` javascript\n    // không tốt\n    function f1(a) {\n      a = 1;\n      // ...\n    }\n\n    function f2(a) {\n      if (!a) { a = 1; }\n      // ...\n    }\n\n    // tốt\n    function f3(a) {\n      const b = a || 1;\n      // ...\n    }\n\n    function f4(a = 1) {\n      // ...\n    }\n    ```\n\n  \u003ca name=\"functions--spread-vs-apply\"\u003e\u003c/a\u003e\u003ca name=\"7.14\"\u003e\u003c/a\u003e\n  - [7.14](#functions--spread-vs-apply) Ưu tiên sử dụng cú pháp liệt kê `...` để gọi các hàm bất định. eslint: [`prefer-spread`](https://eslint.org/docs/rules/prefer-spread)\n\n    \u003e Tại sao? Nó nhìn sáng sủa hơn, bạn không cần phải đặt ngữ cảnh, và bạn cũng đâu thể dễ dàng kết hợp `new` với `apply`.\n\n    ``` javascript\n    // không tốt\n    const x = [1, 2, 3, 4, 5];\n    console.log.apply(console, x);\n\n    // tốt\n    const x = [1, 2, 3, 4, 5];\n    console.log(...x);\n\n    // không tốt\n    new (Function.prototype.bind.apply(Date, [null, 2016, 8, 5]));\n\n    // tốt\n    new Date(...[2016, 8, 5]);\n    ```\n\n  \u003ca name=\"functions--signature-invocation-indentation\"\u003e\u003c/a\u003e\n  - [7.15](#functions--signature-invocation-indentation) Các hàm với các bộ phận hàm, hoặc các phép gọi, nằm trên nhiều dòng nên được căn đầu dòng như tất cả các danh sách nhiều dòng khác trong hướng dẫn này: với mỗi mục nằm trên một dòng riêng biệt, cùng với một dấu phẩy ngay sau mục cuối cùng. eslint: [`function-paren-newline`](https://eslint.org/docs/rules/function-paren-newline)\n\n    ``` javascript\n    // không tốt\n    function foo(bar,\n                 baz,\n                 quux) {\n      // ...\n    }\n\n    // tốt\n    function foo(\n      bar,\n      baz,\n      quux,\n    ) {\n      // ...\n    }\n\n    // không tốt\n    console.log(foo,\n      bar,\n      baz);\n\n    // tốt\n    console.log(\n      foo,\n      bar,\n      baz,\n    );\n    ```\n\n**[⬆ về đầu trang](#table-of-contents)**\n\n## \u003ca name=\"arrow-functions\"\u003eCác Hàm mũi tên\u003c/a\u003e\n\n  \u003ca name=\"arrows--use-them\"\u003e\u003c/a\u003e\u003ca name=\"8.1\"\u003e\u003c/a\u003e\n  - [8.1](#arrows--use-them) Khi bạn phải sử dụng một hàm vô danh (như khi cần truyền một hàm gọi lại trên cùng dòng), sử dụng ký pháp hàm mũi tên. eslint: [`prefer-arrow-callback`](https://eslint.org/docs/rules/prefer-arrow-callback.html), [`arrow-spacing`](https://eslint.org/docs/rules/arrow-spacing.html)\n\n    \u003e Tại sao? Nó tạo ra một hàm thực thi trên ngữ cảnh của `this`, thường là thứ bạn cần, và nó rất súc tích.\n\n    \u003e Khi nào thì không? Khi bạn có một hàm tương đối rắc rối, bạn cần phải chuyển lô-gíc của hàm đó sang biểu thức hàm hữu danh.\n\n    ``` javascript\n    // không tốt\n    [1, 2, 3].map(function (x) {\n      const y = x + 1;\n      return x * y;\n    });\n\n    // tốt\n    [1, 2, 3].map((x) =\u003e {\n      const y = x + 1;\n      return x * y;\n    });\n    ```\n\n  \u003ca name=\"arrows--implicit-return\"\u003e\u003c/a\u003e\u003ca name=\"8.2\"\u003e\u003c/a\u003e\n  - [8.2](#arrows--implicit-return) Nếu như phần thân hàm chỉ gồm một câu lệnh trả về một [biểu thức](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Expressions) mà không có hiệu ứng phụ, bỏ qua dấu ngoặc nhọn và sử dụng trả về ngầm định. Nếu không, giữ nguyên dấu ngoặc và sử dụng lệnh `return`. eslint: [`arrow-parens`](https://eslint.org/docs/rules/arrow-parens.html), [`arrow-body-style`](https://eslint.org/docs/rules/arrow-body-style.html)\n\n    \u003e Tại sao? Cú pháp tiện lợi. Nó dễ đọc khi nhiều hàm nối chuỗi nhau.\n\n    ``` javascript\n    // không tốt\n    [1, 2, 3].map((number) =\u003e {\n      const nextNumber = number + 1;\n      `Một chuỗi có chứa số ${nextNumber}.`;\n    });\n\n    // tốt\n    [1, 2, 3].map((number) =\u003e `Một chuỗi có chứa số ${number + 1}.`);\n\n    // tốt\n    [1, 2, 3].map((number) =\u003e {\n      const nextNumber = number + 1;\n      return `Một chuỗi có chứa số ${nextNumber}.`;\n    });\n\n    // tốt\n    [1, 2, 3].map((number, index) =\u003e ({\n      [index]: number,\n    }));\n\n    // Không dùng trả về ngầm định khi có hiệu ứng phụ\n    function foo(callback) {\n      const val = callback();\n      if (val === true) {\n        // Thực hiện gì đó nếu hàm gọi lại trả về true\n      }\n    }\n\n    let bool = false;\n\n    // không tốt\n    foo(() =\u003e bool = true);\n\n    // tốt\n    foo(() =\u003e {\n      bool = true;\n    });\n    ```\n\n  \u003ca name=\"arrows--paren-wrap\"\u003e\u003c/a\u003e\u003ca name=\"8.3\"\u003e\u003c/a\u003e\n  - [8.3](#arrows--paren-wrap) Trong trường hợp biểu thức nằm trên nhiều dòng, nhóm nó trong ngoặc để dễ đọc hơn.\n\n    \u003e Tại sao? Nó cho thấy một cách rõ ràng điểm bắt đầu và kết thúc hàm.\n\n    ``` javascript\n    // không tốt\n    ['get', 'post', 'put'].map((httpMethod) =\u003e Object.prototype.hasOwnProperty.call(\n        httpMagicObjectWithAVeryLongName,\n        httpMethod,\n      )\n    );\n\n    // tốt\n    ['get', 'post', 'put'].map((httpMethod) =\u003e (\n      Object.prototype.hasOwnProperty.call(\n        httpMagicObjectWithAVeryLongName,\n        httpMethod,\n      )\n    ));\n    ```\n\n  \u003ca name=\"arrows--one-arg-parens\"\u003e\u003c/a\u003e\u003ca name=\"8.4\"\u003e\u003c/a\u003e\n  - [8.4](#arrows--one-arg-parens) Luôn sử dụng ngoặc tròn xung quanh các đối số để rõ ràng và nhất quán. eslint: [`arrow-parens`](https://eslint.org/docs/rules/arrow-parens.html)\n\n    \u003e Tại sao? Giảm thiểu sự khác biệt khi thêm và xóa các đối số.\n\n    ``` javascript\n    // không tốt\n    [1, 2, 3].map(x =\u003e x * x);\n\n    // tốt\n    [1, 2, 3].map((x) =\u003e x * x);\n\n    // tốt\n    [1, 2, 3].map((number) =\u003e (\n      `Một chuỗi thật là dài với số ${number}. Nó quá dài để chúng ta có thể viết cùng dòng với dòng .map!`\n    ));\n\n    // không tốt\n    [1, 2, 3].map(x =\u003e {\n      const y = x + 1;\n      return x * y;\n    });\n\n    // tốt\n    [1, 2, 3].map((x) =\u003e {\n      const y = x + 1;\n      return x * y;\n    });\n    ```\n\n  \u003ca name=\"arrows--confusing\"\u003e\u003c/a\u003e\u003ca name=\"8.5\"\u003e\u003c/a\u003e\n  - [8.5](#arrows--confusing) Tránh gây dễ nhầm lẫn giữa cú pháp hàm mũi tên (`=\u003e`) với các toán tử so sánh (`\u003c=`, `\u003e=`). eslint: [`no-confusing-arrow`](https://eslint.org/docs/rules/no-confusing-arrow)\n\n    ``` javascript\n    // không tốt\n    const itemHeight = (item) =\u003e item.height \u003c= 256 ? item.largeSize : item.smallSize;\n\n    // không tốt\n    const itemHeight = (item) =\u003e item.height \u003e= 256 ? item.largeSize : item.smallSize;\n\n    // tốt\n    const itemHeight = (item) =\u003e (item.height \u003c= 256 ? item.largeSize : item.smallSize);\n\n    // tốt\n    const itemHeight = (item) =\u003e {\n      const { height, largeSize, smallSize } = item;\n      return height \u003c= 256 ? largeSize : smallSize;\n    };\n    ```\n\n  \u003ca name=\"whitespace--implicit-arrow-linebreak\"\u003e\u003c/a\u003e\n  - [8.6](#whitespace--implicit-arrow-linebreak) Cách đặt vị trí của phần thân hàm mũi tên với trả về ngầm định. eslint: [`implicit-arrow-linebreak`](https://eslint.org/docs/rules/implicit-arrow-linebreak)\n\n    ``` javascript\n    // không tốt\n    (foo) =\u003e\n      bar;\n\n    (foo) =\u003e\n      (bar);\n\n    // tốt\n    (foo) =\u003e bar;\n    (foo) =\u003e (bar);\n    (foo) =\u003e (\n       bar\n    )\n    ```\n\n**[⬆ về đầu trang](#table-of-contents)**\n\n## \u003ca name=\"classes--constructors\"\u003eCác Lớp và các Hàm tạo\u003c/a\u003e\n\n  \u003ca name=\"constructors--use-class\"\u003e\u003c/a\u003e\u003ca name=\"9.1\"\u003e\u003c/a\u003e\n  - [9.1](#constructors--use-class) Luôn sử dụng `class`. Tránh việc can thiệp trực tiếp vào `prototype`.\n\n    \u003e Tại sao? Cú pháp `class` súc tích, dễ hiểu và dễ hình dung.\n\n    ``` javascript\n    // không tốt\n    function Queue(contents = []) {\n      this.queue = [...contents];\n    }\n    Queue.prototype.pop = function () {\n      const value = this.queue[0];\n      this.queue.splice(0, 1);\n      return value;\n    };\n\n    // tốt\n    class Queue {\n      constructor(contents = []) {\n        this.queue = [...contents];\n      }\n      pop() {\n        const value = this.queue[0];\n        this.queue.splice(0, 1);\n        return value;\n      }\n    }\n    ```\n\n  \u003ca name=\"constructors--extends\"\u003e\u003c/a\u003e\u003ca name=\"9.2\"\u003e\u003c/a\u003e\n  - [9.2](#constructors--extends) Sử dụng `extends` cho thừa kế.\n\n    \u003e Tại sao? Nó là cách sẵn có để thừa kế nguyên mẫu mà không làm ảnh hưởng đến `instanceof`.\n\n    ``` javascript\n    // không tốt\n    const inherits = require('inherits');\n    function PeekableQueue(contents) {\n      Queue.apply(this, contents);\n    }\n    inherits(PeekableQueue, Queue);\n    PeekableQueue.prototype.peek = function () {\n      return this.queue[0];\n    };\n\n    // tốt\n    class PeekableQueue extends Queue {\n      peek() {\n        return this.queue[0];\n      }\n    }\n    ```\n\n  \u003ca name=\"constructors--chaining\"\u003e\u003c/a\u003e\u003ca name=\"9.3\"\u003e\u003c/a\u003e\n  - [9.3](#constructors--chaining) Các phương thức, mỗi khi có thể, hãy trả về `this` để tiện cho việc nối chuỗi phương thức.\n\n    ``` javascript\n    // không tốt\n    Jedi.prototype.jump = function () {\n      this.jumping = true;\n      return true;\n    };\n\n    Jedi.prototype.setHeight = function (height) {\n      this.height = height;\n    };\n\n    const luke = new Jedi();\n    luke.jump(); // =\u003e true\n    luke.setHeight(20); // =\u003e undefined\n\n    // tốt\n    class Jedi {\n      jump() {\n        this.jumping = true;\n        return this;\n      }\n\n      setHeight(height) {\n        this.height = height;\n        return this;\n      }\n    }\n\n    const luke = new Jedi();\n\n    luke.jump()\n      .setHeight(20);\n    ```\n\n  \u003ca name=\"constructors--tostring\"\u003e\u003c/a\u003e\u003ca name=\"9.4\"\u003e\u003c/a\u003e\n  - [9.4](#constructors--tostring) Có thể viết phương thức `toString()` tùy ý, chỉ cần đảm bản nó hoạt động hoàn hảo và không gây ra các hiệu ứng phụ.\n\n    ``` javascript\n    class Jedi {\n      constructor(options = {}) {\n        this.name = options.name || 'vô danh';\n      }\n\n      getName() {\n        return this.name;\n      }\n\n      toString() {\n        return `Jedi - ${this.getName()}`;\n      }\n    }\n    ```\n\n  \u003ca name=\"constructors--no-useless\"\u003e\u003c/a\u003e\u003ca name=\"9.5\"\u003e\u003c/a\u003e\n  - [9.5](#constructors--no-useless) Các lớp có một hàm tạo mặc định nếu không được chỉ định. Một hàm tạo rỗng, hoặc chỉ trỏ đến lớp cha, là không cần thiết. eslint: [`no-useless-constructor`](https://eslint.org/docs/rules/no-useless-constructor)\n\n    ``` javascript\n    // không tốt\n    class Jedi {\n      constructor() {}\n\n      getName() {\n        return this.name;\n      }\n    }\n\n    // không tốt\n    class Rey extends Jedi {\n      constructor(...args) {\n        super(...args);\n      }\n    }\n\n    // tốt\n    class Rey extends Jedi {\n      constructor(...args) {\n        super(...args);\n        this.name = 'Rey';\n      }\n    }\n    ```\n\n  \u003ca name=\"classes--no-duplicate-members\"\u003e\u003c/a\u003e\n  - [9.6](#classes--no-duplicate-members) Tránh trùng lặp các thành viên của một lớp. eslint: [`no-dupe-class-members`](https://eslint.org/docs/rules/no-dupe-class-members)\n\n    \u003e Tại sao? Với các khai báo thành viên bị lặp, khai báo cuối được tự động ưu tiên - việc có sự trùng lặp gần như chắc chắn là một lỗi.\n\n    ``` javascript\n    // không tốt\n    class Foo {\n      bar() { return 1; }\n      bar() { return 2; }\n    }\n\n    // tốt\n    class Foo {\n      bar() { return 1; }\n    }\n\n    // tốt\n    class Foo {\n      bar() { return 2; }\n    }\n    ```\n\n  \u003ca name=\"classes--methods-use-this\"\u003e\u003c/a\u003e\n  - [9.7](#classes--methods-use-this) Các phương thức của lớp nên sử dụng `this` hoặc được chuyển thành phương thức tĩnh, trừ trường hợp thư viện bên ngoài hoặc bộ khung phần mềm bắt buộc sử dụng phương thức không phải phương thức tĩnh. Một phương thức là phương thức của thực thể nên mang ý nghĩa rằng nó hoạt động khác nhau dựa trên những thuộc tính của đối tượng đích.  eslint: [`class-methods-use-this`](https://eslint.org/docs/rules/class-methods-use-this)\n\n    ```javascript\n    // không tốt\n    class Foo {\n      bar() {\n        console.log('bar');\n      }\n    }\n\n    // tốt - this được sử dụng\n    class Foo {\n      bar() {\n        console.log(this.bar);\n      }\n    }\n\n    // tốt - constructor là ngoại lệ\n    class Foo {\n      constructor() {\n        // ...\n      }\n    }\n\n    // tốt - phương thức tĩnh không nên sử dụng this\n    class Foo {\n      static bar() {\n        console.log('bar');\n      }\n    }\n    ```\n\n**[⬆ về đầu trang](#table-of-contents)**\n\n## \u003ca name=\"modules\"\u003eCác Mô-đun\u003c/a\u003e\n\n  \u003ca name=\"modules--use-them\"\u003e\u003c/a\u003e\u003ca name=\"10.1\"\u003e\u003c/a\u003e\n  - [10.1](#modules--use-them) Luôn sử dụng mô-đun (`import`/`export`) thay vì một hệ thống mô-đun phi chuẩn. Bạn luôn có thể dịch mã sang hệ thống mô-đun mà bạn thích.\n\n    \u003e Tại sao? Mô-đun là tương lai, hãy cùng sử dụng tương lai ngay lúc này.\n\n    ``` javascript\n    // không tốt\n    const AirbnbStyleGuide = require('./AirbnbStyleGuide');\n    module.exports = AirbnbStyleGuide.es6;\n\n    // ok\n    import AirbnbStyleGuide from './AirbnbStyleGuide';\n    export default AirbnbStyleGuide.es6;\n\n    // best\n    import { es6 } from './AirbnbStyleGuide';\n    export default es6;\n    ```\n\n  \u003ca name=\"modules--no-wildcard\"\u003e\u003c/a\u003e\u003ca name=\"10.2\"\u003e\u003c/a\u003e\n  - [10.2](#modules--no-wildcard) Không sử dụng ký tự đại diện để nhập.\n\n    \u003e Tại sao? Điều này đảm bảo bạn chỉ xuất mặc định một giá trị.\n\n    ``` javascript\n    // không tốt\n    import * as AirbnbStyleGuide from './AirbnbStyleGuide';\n\n    // tốt\n    import AirbnbStyleGuide from './AirbnbStyleGuide';\n    ```\n\n  \u003ca name=\"modules--no-export-from-import\"\u003e\u003c/a\u003e\u003ca name=\"10.3\"\u003e\u003c/a\u003e\n  - [10.3](#modules--no-export-from-import) Và không xuất trực tiếp từ một lệnh nhập.\n\n    \u003e Tại sao? Mặc dù cấu trúc một dòng là súc tích, việc nhập một cách rõ ràng và xuất một cách rõ ràng làm cho mọi thứ nhất quán.\n\n    ``` javascript\n    // không tốt\n    // tên tệp es6.js\n    export { es6 as default } from './AirbnbStyleGuide';\n\n    // tốt\n    // tên tệp es6.js\n    import { es6 } from './AirbnbStyleGuide';\n    export default es6;\n    ```\n\n  \u003ca name=\"modules--no-duplicate-imports\"\u003e\u003c/a\u003e\n  - [10.4](#modules--no-duplicate-imports) Chỉ nhập từ một đường dẫn ở chung một chỗ.\n eslint: [`no-duplicate-imports`](https://eslint.org/docs/rules/no-duplicate-imports)\n    \u003e Tại sao? Có nhiều dòng nhập từ cùng một đường dẫn khiến mã nguồn trở nên khó bảo trì hơn.\n\n    ``` javascript\n    // không tốt\n    import foo from 'foo';\n    // … và nhập một vài thứ nữa … //\n    import { named1, named2 } from 'foo';\n\n    // tốt\n    import foo, { named1, named2 } from 'foo';\n\n    // tốt\n    import foo, {\n      named1,\n      named2,\n    } from 'foo';\n    ```\n\n  \u003ca name=\"modules--no-mutable-exports\"\u003e\u003c/a\u003e\n  - [10.5](#modules--no-mutable-exports) Không xuất các ràng buộc có thể bị biến đổi.\n eslint: [`import/no-mutable-exports`](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-mutable-exports.md)\n    \u003e Tại sao? Sự biến đổi, nói chung, nên được tránh, nhưng đặc biệt là đối với trường hợp xuất các giá trị có thể bị biến đổi. Trong khi kỹ thuật này có thể là cần thiết trong một số trường hợp đặc biệt, nhìn chung, chỉ nên xuất các giá trị là hằng.\n\n    ``` javascript\n    // không tốt\n    let foo = 3;\n    export { foo };\n\n    // tốt\n    const foo = 3;\n    export { foo };\n    ```\n\n  \u003ca name=\"modules--prefer-default-export\"\u003e\u003c/a\u003e\n  - [10.6](#modules--prefer-default-export) Trong các mô-đun chỉ có một địa chỉ xuất, ưu tiên xuất mặc định thay vì xuất hữu danh.\n eslint: [`import/prefer-default-export`](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/prefer-default-export.md)\n    \u003e Tại sao? Nhằm khuyến khích các tệp chỉ xuất một giá trị, giúp mã nguồn dễ đọc và dễ bảo trì.\n\n    ``` javascript\n    // không tốt\n    export function foo() {}\n\n    // tốt\n    export default function foo() {}\n    ```\n\n  \u003ca name=\"modules--imports-first\"\u003e\u003c/a\u003e\n  - [10.7](#modules--imports-first) Đặt tất cả các lệnh `import` trên cùng.\n eslint: [`import/first`](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/first.md)\n    \u003e Tại sao? Vì các lệnh `import` được kéo lên, việc đặt tất cả chúng ở trên cùng nhằm ngăn chặn các hành vi không đáng có.\n\n    ``` javascript\n    // không tốt\n    import foo from 'foo';\n    foo.init();\n\n    import bar from 'bar';\n\n    // tốt\n    import foo from 'foo';\n    import bar from 'bar';\n\n    foo.init();\n    ```\n\n  \u003ca name=\"modules--multiline-imports-over-newlines\"\u003e\u003c/a\u003e\n  - [10.8](#modules--multiline-imports-over-newlines) Các lệnh nhập nhiều dòng nên được căn đầu dòng giống như các mảng hay đối tượng nguyên văn nhiều dòng. eslint: [`object-curly-newline`](https://eslint.org/docs/rules/object-curly-newline)\n\n    \u003e Tại sao? Các đấu ngoặc nhọn đều có cùng các quy tắc căn đầu dòng như tất cả mọi khối ngoặc nhọn trong bản định hướng này, cùng với như dấu phẩy ở cuối.\n\n    ``` javascript\n    // không tốt\n    import {longNameA, longNameB, longNameC, longNameD, longNameE} from 'path';\n\n    // tốt\n    import {\n      longNameA,\n      longNameB,\n      longNameC,\n      longNameD,\n      longNameE,\n    } from 'path';\n    ```\n\n  \u003ca name=\"modules--no-webpack-loader-syntax\"\u003e\u003c/a\u003e\n  - [10.9](#modules--no-webpack-loader-syntax) Không cho phép cú pháp bộ tải Webpack trong các lệnh nhập mô-đun.\n eslint: [`import/no-webpack-loader-syntax`](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-webpack-loader-syntax.md)\n    \u003e Tại sao? Vì sử dụng cú pháp Webpack trong các lệnh nhập gom mã thành một bộ tổng hợp mô-đun. Ưu tiên sử dụng cú pháp bộ tải trong `webpack.config.js`.\n\n    ``` javascript\n    // không tốt\n    import fooSass from 'css!sass!foo.scss';\n    import barCss from 'style!css!bar.css';\n\n    // tốt\n    import fooSass from 'foo.scss';\n    import barCss from 'bar.css';\n    ```\n\n  \u003ca name=\"modules--import-extensions\"\u003e\u003c/a\u003e\n  - [10.10](#modules--import-extensions) Không thêm phần mở rộng của tên tệp JavaScript. eslint: [`import/extensions`](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/extensions.md)\n    \u003e Tạo sao? Việc thêm phần mở rộng của tệp khiến cho việc cải tiến mã nguồn trở nên khó khăn hơn, và tạo nên những chi tiết không cần thiết trong lệnh nhập mô-đun mỗi khi bạn sử dụng.\n\n    ```javascript\n    // không tốt\n    import foo from './foo.js';\n    import bar from './bar.jsx';\n    import baz from './baz/index.jsx';\n    // tốt\n    import foo from './foo';\n    import bar from './bar';\n    import baz from './baz';\n    ```\n\n**[⬆ về đầu trang](#table-of-contents)**\n\n## \u003ca name=\"iterators-and-generators\"\u003eCác Đối tượng duyệt và các Hàm sinh trị\u003c/a\u003e\n\n  \u003ca name=\"iterators--nope\"\u003e\u003c/a\u003e\u003ca name=\"11.1\"\u003e\u003c/a\u003e\n  - [11.1](#iterators--nope) Không sử dụng các đối tượng duyệt. Ưu tiên sử dụng các hàm bậc cao hơn của JavaScript thay vì các vòng lặp như `for-in` hay `for-of`. eslint: [`no-iterator`](https://eslint.org/docs/rules/no-iterator.html) [`no-restricted-syntax`](https://eslint.org/docs/rules/no-restricted-syntax)\n\n    \u003e Tại sao? Điều này đảm bảo việc thực hiện quy tắc bất biến. Làm việc với các hàm thuần mà trả về các giá trị sẽ dễ tưởng tượng hơn so với các hiệu ứng phụ.\n\n    \u003e Sử dụng `map()` / `every()` / `filter()` / `find()` / `findIndex()` / `reduce()` / `some()` / ... để duyệt qua một mảng, và `Object.keys()` / `Object.values()` / `Object.entries()` để tạo một mảng để bạn có thể duyệt qua một đối tượng.\n\n    ``` javascript\n    const numbers = [1, 2, 3, 4, 5];\n\n    // không tốt\n    let sum = 0;\n    for (let num of numbers) {\n      sum += num;\n    }\n    sum === 15;\n\n    // tốt\n    let sum = 0;\n    numbers.forEach((num) =\u003e {\n      sum += num;\n    });\n    sum === 15;\n\n    // tốt nhất, sử dụng hàm\n    const sum = numbers.reduce((total, num) =\u003e total + num, 0);\n    sum === 15;\n\n    // không tốt\n    const increasedByOne = [];\n    for (let i = 0; i \u003c numbers.length; i++) {\n      increasedByOne.push(numbers[i] + 1);\n    }\n\n    // tốt\n    const increasedByOne = [];\n    numbers.forEach((num) =\u003e {\n      increasedByOne.push(num + 1);\n    });\n\n    // tốt nhất, vẫn là sử dụng hàm\n    const increasedByOne = numbers.map((num) =\u003e num + 1);\n    ```\n\n  \u003ca name=\"generators--nope\"\u003e\u003c/a\u003e\u003ca name=\"11.2\"\u003e\u003c/a\u003e\n  - [11.2](#generators--nope) Không sử dụng các hàm sinh trị `function*` vào thời điểm này.\n\n    \u003e Tại sao? Nó không thể được dịch mã sang ES5 một cách hoàn hảo.\n\n  \u003ca name=\"generators--spacing\"\u003e\u003c/a\u003e\n  - [11.3](#generators--spacing) Nếu bạn bắt buộc phải dùng các hàm sinh trị, hoặc bạn bỏ qua [khuyến nghị của chúng tôi](#generators--nope), hãy đảm bảo rằng bạn sử dụng dấu cách giữa các bộ phận hàm một cách hợp lý. eslint: [`generator-star-spacing`](https://eslint.org/docs/rules/generator-star-spacing)\n\n    \u003e Tại sao? `function` và `*` là tạo thành một từ khóa riêng - `*` không phải là từ khóa điều chỉnh cho `function`, `function*` là một cấu tạo riêng biệt, khác với `function`.\n\n    ``` javascript\n    // không tốt\n    function * foo() {\n      // ...\n    }\n\n    // không tốt\n    const bar = function * () {\n      // ...\n    };\n\n    // không tốt\n    const baz = function *() {\n      // ...\n    };\n\n    // không tốt\n    const quux = function*() {\n      // ...\n    };\n\n    // không tốt\n    function*foo() {\n      // ...\n    }\n\n    // không tốt\n    function *foo() {\n      // ...\n    }\n\n    // rất tệ\n    function\n    *\n    foo() {\n      // ...\n    }\n\n    // rất rất tệ\n    const wat = function\n    *\n    () {\n      // ...\n    };\n\n    // tốt\n    function* foo() {\n      // ...\n    }\n\n    // tốt\n    const foo = function* () {\n      // ...\n    };\n    ```\n\n**[⬆ về đầu trang](#table-of-contents)**\n\n## \u003ca name=\"properties\"\u003eCác Thuộc tính\u003c/a\u003e\n\n  \u003ca name=\"properties--dot\"\u003e\u003c/a\u003e\u003ca name=\"12.1\"\u003e\u003c/a\u003e\n  - [12.1](#properties--dot) Sử dụng ký pháp chấm `.` để truy cập các thuộc tính. eslint: [`dot-notation`](https://eslint.org/docs/rules/dot-notation.html)\n\n    ``` javascript\n    const luke = {\n      jedi: true,\n      age: 28,\n    };\n\n    // không tốt\n    const isJedi = luke['jedi'];\n\n    // tốt\n    const isJedi = luke.jedi;\n    ```\n\n  \u003ca name=\"properties--bracket\"\u003e\u003c/a\u003e\u003ca name=\"12.2\"\u003e\u003c/a\u003e\n  - [12.2](#properties--bracket) Sử dụng ký pháp ngoặc `[]` để truy cập thuộc tính với một biến.\n\n    ``` javascript\n    const luke = {\n      jedi: true,\n      age: 28,\n    };\n\n    function getProp(prop) {\n      return luke[prop];\n    }\n\n    const isJedi = getProp('jedi');\n    ```\n\n  \u003ca name=\"es2016-properties--exponentiation-operator\"\u003e\u003c/a\u003e\n  - [12.3](#es2016-properties--exponentiation-operator) Sử dụng toán tử lũy thừa `**` để tính các lũy thừa. eslint: [`no-restricted-properties`](https://eslint.org/docs/rules/no-restricted-properties).\n\n    ``` javascript\n    // không tốt\n    const binary = Math.pow(2, 10);\n\n    // tốt\n    const binary = 2 ** 10;\n    ```\n\n**[⬆ về đầu trang](#table-of-contents)**\n\n## \u003ca name=\"variables\"\u003eCác Biến\u003c/a\u003e\n\n  \u003ca name=\"variables--const\"\u003e\u003c/a\u003e\u003ca name=\"13.1\"\u003e\u003c/a\u003e\n  - [13.1](#variables--const) Luôn sử dụng `const` hoặc `let` để khai báo biến. Không làm như vậy sẽ dẫn đến các biến toàn cục. Chúng ta muốn tránh việc làm ô nhiễm không gian tên toàn cục. Đội trưởng Hành tinh đã cảnh báo chúng ta. eslint: [`no-undef`](https://eslint.org/docs/rules/no-undef) [`prefer-const`](https://eslint.org/docs/rules/prefer-const)\n\n    ``` javascript\n    // không tốt\n    superPower = new SuperPower();\n\n    // tốt\n    const superPower = new SuperPower();\n    ```\n\n  \u003ca name=\"variables--one-const\"\u003e\u003c/a\u003e\u003ca name=\"13.2\"\u003e\u003c/a\u003e\n  - [13.2](#variables--one-const) Sử dụng một `const` hoặc `let` khai báo cho mỗi biến hoặc phép gán. eslint: [`one-var`](https://eslint.org/docs/rules/one-var.html)\n\n    \u003e Tại sao? Khai báo theo cách này giúp dễ thêm các khai báo mới, và bạn chẳng phải nghĩ về việc phải dùng `;` hay `,`. Bạn còn có thể bước qua mỗi khai báo trong trình gỡ lỗi, thay vì nhảy qua toàn bộ chúng trong một bước.\n\n    ``` javascript\n    // không tốt\n    const items = getItems(),\n        goSportsTeam = true,\n        dragonball = 'z';\n\n    // không tốt\n    // (so sánh với trên kia và thử tìm ra lỗi ở đây)\n    const items = getItems(),\n        goSportsTeam = true;\n        dragonball = 'z';\n\n    // tốt\n    const items = getItems();\n    const goSportsTeam = true;\n    const dragonball = 'z';\n    ```\n\n  \u003ca name=\"variables--const-let-group\"\u003e\u003c/a\u003e\u003ca name=\"13.3\"\u003e\u003c/a\u003e\n  - [13.3](#variables--const-let-group) Nhóm tất cả các `const` và rồi nhóm tất cả các `let`.\n\n    \u003e Tại sao? Điều này hữu ích khi, sau đó, bạn sẽ cần gán lại một biến dựa trên các biến đã gán trước đó.\n\n    ``` javascript\n    // không tốt\n    let i, len, dragonball,\n        items = getItems(),\n        goSportsTeam = true;\n\n    // không tốt\n    let i;\n    const items = getItems();\n    let dragonball;\n    const goSportsTeam = true;\n    let len;\n\n    // tốt\n    const goSportsTeam = true;\n    const items = getItems();\n    let dragonball;\n    let i;\n    let length;\n    ```\n\n  \u003ca name=\"variables--define-where-used\"\u003e\u003c/a\u003e\u003ca name=\"13.4\"\u003e\u003c/a\u003e\n  - [13.4](#variables--define-where-used) Chỉ gán biến khi cần, nhưng nhớ đặt chúng ở một nơi hợp lý.\n\n    \u003e Tại sao? `let` và `const` thuộc phạm vi khối, không phải phạm vi hàm.\n\n    ``` javascript\n    // không tốt - phép gọi hàm không cần thiết\n    function checkName(hasName) {\n      const name = getName();\n\n      if (hasName === 'thí nghiệm') {\n        return false;\n      }\n\n      if (name === 'thí nghiệm') {\n        this.setName('');\n        return false;\n      }\n\n      return name;\n    }\n\n    // tốt\n    function checkName(hasName) {\n      if (hasName === 'thí nghiệm') {\n        return false;\n      }\n\n      const name = getName();\n\n      if (name === 'thí nghiệm') {\n        this.setName('');\n        return false;\n      }\n\n      return name;\n    }\n    ```\n\n  \u003ca name=\"variables--no-chain-assignment\"\u003e\u003c/a\u003e\u003ca name=\"13.5\"\u003e\u003c/a\u003e\n  - [13.5](#variables--no-chain-assignment) Đừng nối chuỗi các phép gán. eslint: [`no-multi-assign`](https://eslint.org/docs/rules/no-multi-assign)\n\n    \u003e Tại sao? Việc nối chuỗi các phép gán tạo ra các biến toàn cục ngầm định.\n\n    ``` javascript\n    // không tốt\n    (function example() {\n      // JavaScript diễn giải điều này như\n      // let a = ( b = ( c = 1 ) );\n      // Từ khóa let chỉ áp dụng đối với biến a; các biến b và c sẽ trở thành\n      // các biến toàn cục.\n      let a = b = c = 1;\n    }());\n\n    console.log(a); // ném ra ReferenceError\n    console.log(b); // 1\n    console.log(c); // 1\n\n    // tốt\n    (function example() {\n      let a = 1;\n      let b = a;\n      let c = a;\n    }());\n\n    console.log(a); // ném ra ReferenceError\n    console.log(b); // ném ra ReferenceError\n    console.log(c); // ném ra ReferenceError\n\n    // điều tương tự áp dụng với `const`\n    ```\n\n  \u003ca name=\"variables--unary-increment-decrement\"\u003e\u003c/a\u003e\u003ca name=\"13.6\"\u003e\u003c/a\u003e\n  - [13.6](#variables--unary-increment-decrement) Tránh việc sử dụng các phép tăng và giảm một ngôi (`++`, `--`). eslint [`no-plusplus`](https://eslint.org/docs/rules/no-plusplus)\n\n    \u003e Tại sao? Theo như tài liệu của eslint, các phép tăng hoặc giảm một ngôi phụ thuộc vào Quy tắc thêm dấu chấm phẩy tự động và có thể gây ra các lỗi câm trong việc tăng hoặc giảm các giá trị trong một ứng dụng. Sự diễn đạt cũng trở nên rõ ràng hơn khi bạn biến đổi các giá trị với các lệnh, như `num += 1`, thay vì `num++` hay `num ++`. Việc không cho phép các lệnh tăng hoặc giảm một ngôi cũng giúp bạn tránh được các sự tiền tăng/tiền giảm các giá trị một cách không chủ ý, điều có thể cũng gây ra những hành vi không mong muốn cho chương trình của bạn.\n\n    ``` javascript\n    // không tốt\n\n    const array = [1, 2, 3];\n    let num = 1;\n    num++;\n    --num;\n\n    let sum = 0;\n    let truthyCount = 0;\n    for (let i = 0; i \u003c array.length; i++) {\n      let value = array[i];\n      sum += value;\n      if (value) {\n        truthyCount++;\n      }\n    }\n\n    // tốt\n\n    const array = [1, 2, 3];\n    let num = 1;\n    num += 1;\n    num -= 1;\n\n    const sum = array.reduce((a, b) =\u003e a + b, 0);\n    const truthyCount = array.filter(Boolean).length;\n    ```\n\n\u003ca name=\"variables--linebreak\"\u003e\u003c/a\u003e\n  - [13.7](#variables--linebreak) Tránh các dấu ngắt dòng trước và sau `=` trong một phép gán. Nếu phép gán của bạn vi phạm [`max-len`](https://eslint.org/docs/rules/max-len.html), hãy đặt giá trị trong ngoặc tròn. eslint [`operator-linebreak`](https://eslint.org/docs/rules/operator-linebreak.html).\n\n    \u003e Tại sao? Các dấu ngắt dòng quanh `=` có thể làm mờ nhạt giá trị trong phép gán.\n\n    ``` javascript\n    // không tốt\n    const foo =\n      superLongLongLongLongLongLongLongLongFunctionName();\n\n    // không tốt\n    const foo\n      = 'một chuỗi rất rất rất rất rất rất rất rất rất rất là dài';\n\n    // tốt\n    const foo = (\n      superLongLongLongLongLongLongLongLongFunctionName()\n    );\n\n    // tốt\n    const foo = 'một chuỗi rất rất rất rất rất rất rất rất rất rất là dài';\n    ```\n\n\u003ca name=\"variables--no-unused-vars\"\u003e\u003c/a\u003e\n  - [13.8](#variables--no-unused-vars) Không cho phép các biến không được sử dụng. eslint: [`no-unused-vars`](https://eslint.org/docs/rules/no-unused-vars)\n\n    \u003e Tại sao? Các biến được khai báo nhưng không được sử dụng ở khắp mọi nơi trong mã gần như chắc chắn là một lỗi do sự cải tiến mã nguồn chưa hoàn thiện. Những biến như vậy chiếm chỗ trong mã và có thể gây ra sự khó hiểu cho người đọc.\n\n    ``` javascript\n    // không tốt\n\n    var some_unused_var = 42;\n\n    // Các biến chỉ-viết không được coi là đã được sử dụng.\n    var y = 10;\n    y = 5;\n\n    // Một phép đọc để sửa chính nó không được coi là đã sử dụng.\n    var z = 0;\n    z = z + 1;\n\n    // Đối số không được sử dụng.\n    function getX(x, y) {\n        return x;\n    }\n\n    // tốt\n\n    function getXPlusY(x, y) {\n      return x + y;\n    }\n\n    var x = 1;\n    var y = a + 2;\n\n    alert(getXPlusY(x, y));\n\n    // 'type' được bỏ qua kể cả khi nó không được sử dụng vì còn có\n    // các thuộc tính đồng đẳng còn-lại.\n    // Đây là một cách để trích xuất một đối tượng mà bỏ qua một vài thuộc tính.\n    var { type, ...coords } = data;\n    // 'coords' bây giờ là 'data' đã loại bỏ thuộc tính 'type'.\n    ```\n\n**[⬆ về đầu trang](#table-of-contents)**\n\n## \u003ca name=\"hoisting\"\u003eSự kéo lên\u003c/a\u003e\n\n  \u003ca name=\"hoisting--about\"\u003e\u003c/a\u003e\u003ca name=\"14.1\"\u003e\u003c/a\u003e\n  - [14.1](#hoisting--about) Các khai báo bằng `var` được kéo lên đầu của phạm vi hàm gần nhất, còn phép gán thì không. Các khai báo bằng `const` và `let` thì mang trên mình một đặc tính khác là [Giai đoạn chết](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#Temporal_dead_zone). Điều này là quan trọng để biết tại sao [`typeof` không còn an toàn](https://web.archive.org/web/20200121061528/http://es-discourse.com/t/why-typeof-is-no-longer-safe/15).\n\n    ``` javascript\n    // chúng ta biết thứ này sẽ không hoạt động (giả định rằng\n    // không có biến toàn cục nào tên là notDefined)\n    function example() {\n      console.log(notDefined); // =\u003e ném ra ReferenceError\n    }\n\n    // việc khai báo một biến sau khi bạn\n    // sử dụng biến đó vẫn sẽ chạy bởi vì\n    // sự nổi lên của biến. Lưu ý: phép gán\n    // giá trị `true` không được kéo lên.\n    function example() {\n      console.log(declaredButNotAssigned); // =\u003e undefined\n      var declaredButNotAssigned = true;\n    }\n\n    // trình biên dịch sẽ kéo khai báo biến\n    // lên trên đầu của phạm vi hàm,\n    // điều này có nghĩa là ví dụ trên có thể được viết là:\n    function example() {\n      let declaredButNotAssigned;\n      console.log(declaredButNotAssigned); // =\u003e undefined\n      declaredButNotAssigned = true;\n    }\n\n    // dùng const và let\n    function example() {\n      console.log(declaredButNotAssigned); // =\u003e ném ra ReferenceError\n      console.log(typeof declaredButNotAssigned); // =\u003e ném ra ReferenceError\n      const declaredButNotAssigned = true;\n    }\n    ```\n\n  \u003ca name=\"hoisting--anon-expressions\"\u003e\u003c/a\u003e\u003ca name=\"14.2\"\u003e\u003c/a\u003e\n  - [14.2](#hoisting--anon-expressions) Các biểu thức hàm vô danh sẽ được kéo tên biến lên, nhưng không được kéo phép gán hàm.\n\n    ``` javascript\n    function example() {\n      console.log(anonymous); // =\u003e undefined\n\n      anonymous(); // =\u003e TypeError anonymous is not a function\n\n      var anonymous = function () {\n        console.log('biểu thức hàm vô danh');\n      };\n    }\n    ```\n\n  \u003ca name=\"hoisting--named-expresions\"\u003e\u003c/a\u003e\u003ca name=\"hoisting--named-expressions\"\u003e\u003c/a\u003e\u003ca name=\"14.3\"\u003e\u003c/a\u003e\n  - [14.3](#hoisting--named-expressions) Biểu thức hàm hữu danh sẽ được kéo tên biến lên, nhưng không được kéo tên hàm và thân hàm.\n\n    ``` javascript\n    function example() {\n      console.log(named); // =\u003e undefined\n\n      named(); // =\u003e TypeError named is not a function\n\n      superPower(); // =\u003e ReferenceError superPower is not defined\n\n      var named = function superPower() {\n        console.log('Nhìn tui đang bay nè');\n      };\n    }\n\n    // điều tương tự cũng đúng nếu\n    // tên hàm là trùng với tên biến.\n    function example() {\n      console.log(named); // =\u003e undefined\n\n      named(); // =\u003e TypeError named is not a function\n\n      var named = function named() {\n        console.log('named');\n      };\n    }\n    ```\n\n  \u003ca name=\"hoisting--declarations\"\u003e\u003c/a\u003e\u003ca name=\"14.4\"\u003e\u003c/a\u003e\n  - [14.4](#hoisting--declarations) Khai báo hàm được kéo cả tên và thân hàm lên.\n\n    ``` javascript\n    function example() {\n      superPower(); // =\u003e Nhìn tui đang bay nè\n\n      function superPower() {\n        console.log('Nhìn tui đang bay nè');\n      }\n    }\n    ```\n\n  - Để tìm hiểu thêm, tham khảo bài viết [JavaScript Scoping \u0026 Hoisting](http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting/) bởi [Ben Cherry](http://www.adequatelygood.com/).\n\n**[⬆ về đầu trang](#table-of-contents)**\n\n## \u003ca name=\"comparison-operators--equality\"\u003eCác Toán tử So sánh và Sự bằng nhau\u003c/a\u003e\n\n  \u003ca name=\"comparison--eqeqeq\"\u003e\u003c/a\u003e\u003ca name=\"15.1\"\u003e\u003c/a\u003e\n  - [15.1](#comparison--eqeqeq) Sử dụng `===` và `!==` thay vì `==` và `!=`. eslint: [`eqeqeq`](https://eslint.org/docs/rules/eqeqeq.html)\n\n  \u003ca name=\"comparison--if\"\u003e\u003c/a\u003e\u003ca name=\"15.2\"\u003e\u003c/a\u003e\n  - [15.2](#comparison--if) Các câu lệnh điều kiện như lệnh `if` xét biểu thức của chúng bằng cách ép kiểu bằng một phương thức ảo`ToBoolean` và đều tuân theo những quy tắc đơn giản sau:\n\n    - **Các đối tượng** tương đương với **true**\n    - **Undefined** tương đương với **false**\n    - **Null** tương đương với **false**\n    - **Các boolean** tương đương với **giá trị của boolean**\n    - **Các số** tương đương với **false** nếu là **+0, -0, hoặc NaN**, còn không sẽ là **true**\n    - **Các chuỗi** tương đương vớiv**false** nếu là một chuỗi rỗng `''`, còn không sẽ là **true**\n\n    ``` javascript\n    if ([0] \u0026\u0026 []) {\n      // true\n      // một mảng (dù là mảng rỗng) là một đối tượng,\n      // mà đối tượng luôn tương đương với true\n    }\n    ```\n\n  \u003ca name=\"comparison--shortcuts\"\u003e\u003c/a\u003e\u003ca name=\"15.3\"\u003e\u003c/a\u003e\n  - [15.3](#comparison--shortcuts) Sử dụng dạng rút gọn cho các boolean, nhưng dùng dạng so sánh cụ thể đối với chuỗi và số.\n\n    ``` javascript\n    // không tốt\n    if (isValid === true) {\n      // ...\n    }\n\n    // tốt\n    if (isValid) {\n      // ...\n    }\n\n    // không tốt\n    if (name) {\n      // ...\n    }\n\n    // tốt\n    if (name !== '') {\n      // ...\n    }\n\n    // không tốt\n    if (collection.length) {\n      // ...\n    }\n\n    // tốt\n    if (collection.length \u003e 0) {\n      // ...\n    }\n    ```\n\n  \u003ca name=\"comparison--moreinfo\"\u003e\u003c/a\u003e\u003ca name=\"15.4\"\u003e\u003c/a\u003e\n  - [15.4](#comparison--moreinfo) Để biết thêm chi tiết, xem bài viết [Truth Equality and JavaScript](https://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/#more-2108) bởi Angus Croll.\n\n  \u003ca name=\"comparison--switch-blocks\"\u003e\u003c/a\u003e\u003ca name=\"15.5\"\u003e\u003c/a\u003e\n  - [15.5](#comparison--switch-blocks) Sử dụng các dấu ngoặc cho các khối của mệnh đề `case` và `default` nếu nó có chứa các khai báo (như `let`, `const`, `function`, và `class`). eslint: [`no-case-declarations`](https://eslint.org/docs/rules/no-case-declarations.html)\n\n    \u003e Tại sao? Các khai báo tồn tại trong cả khối `switch` nhưng chỉ được khởi tạo khi được gán, mà nó chỉ xảy ra khi `case` của nó xảy ra. Điều này gây ra các lỗi khi mà nhiều mệnh đề `case` muốn định nghĩa cùng một thứ.\n\n    ``` javascript\n    // không tốt\n    switch (foo) {\n      case 1:\n        let x = 1;\n        break;\n      case 2:\n        const y = 2;\n        break;\n      case 3:\n        function f() {\n          // ...\n        }\n        break;\n      default:\n        class C {}\n    }\n\n    // tốt\n    switch (foo) {\n      case 1: {\n        let x = 1;\n        break;\n      }\n      case 2: {\n        const y = 2;\n        break;\n      }\n      case 3: {\n        function f() {\n          // ...\n        }\n        break;\n      }\n      case 4:\n        bar();\n        break;\n      default: {\n        class C {}\n      }\n    }\n    ```\n\n  \u003ca name=\"comparison--nested-ternaries\"\u003e\u003c/a\u003e\u003ca name=\"15.6\"\u003e\u003c/a\u003e\n  - [15.6](#comparison--nested-ternaries) Các toán tử ba ngôi không nên được đặt trong ngoặc và thường được viết trên một dòng riêng. eslint: [`no-nested-ternary`](https://eslint.org/docs/rules/no-nested-ternary.html)\n\n    ``` javascript\n    // không tốt\n    const foo = maybe1 \u003e maybe2\n      ? \"hi hi\"\n      : value1 \u003e value2 ? \"hi hi\" : null;\n\n    // chia thành hai biểu thức ba ngôi riêng biệt\n    // là tốt nhất\n    const maybeNull = value1 \u003e value2 ? 'hi hi' : null;\n    const foo = maybe1 \u003e maybe2 ? 'hi hi' : maybeNull;\n    ```\n\n  \u003ca name=\"comparison--unneeded-ternary\"\u003e\u003c/a\u003e\u003ca name=\"15.7\"\u003e\u003c/a\u003e\n  - [15.7](#comparison--unneeded-ternary) Tránh các câu lệnh ba ngôi không đáng có. eslint: [`no-unneeded-ternary`](https://eslint.org/docs/rules/no-unneeded-ternary.html)\n\n    ``` javascript\n    // không tốt\n    const foo = a ? a : b;\n    const bar = c ? true : false;\n    const baz = c ? false : true;\n\n    // tốt\n    const foo = a || b;\n    const bar = !!c;\n    const baz = !c;\n    ```\n\n  \u003ca name=\"comparison--no-mixed-operators\"\u003e\u003c/a\u003e\n  - [15.8](#comparison--no-mixed-operators) Khi kết hợp các toán tử, nhớ đóng chúng trong ngoặc. Ngoại lệ duy nhất là các toán tử tiêu chuẩn: `+`, `-` và `**` vì chúng có thứ tự ưu tiên mà ai ai cũng hiểu. Chúng tôi khuyến khích việc sử dụng đóng ngoặc cho `/` và `*` vì thứ tự ưu tiên của chúng có thể bị nhầm lẫn khi chúng được sử dụng gần nhau. eslint: [`no-mixed-operators`](https://eslint.org/docs/rules/no-mixed-operators.html)\n\n    \u003e Tại sao? Điều này cả thiện tính khả đọc và làm rõ ý định của nhà phát triển.\n\n    ``` javascript\n    // không tốt\n    const foo = a \u0026\u0026 b \u003c 0 || c \u003e 0 || d + 1 === 0;\n\n    // không tốt\n    const bar = a ** b - 5 % d;\n\n    // không tốt\n    // ai đó có thể bị rối và nghĩ nó là (a || b) \u0026\u0026 c\n    if (a || b \u0026\u0026 c) {\n      return d;\n    }\n\n    // không tốt\n    const bar = a + b / c * d;\n\n    // tốt\n    const foo = (a \u0026\u0026 b \u003c 0) || c \u003e 0 || (d + 1 === 0);\n\n    // tốt\n    const bar = a ** b - (5 % d);\n\n    // tốt\n    if (a || (b \u0026\u0026 c)) {\n      return d;\n    }\n\n    // tốt\n    const bar = a + (b / c) * d;\n    ```\n\n**[⬆ về đầu trang](#table-of-contents)**\n\n## \u003ca name=\"blocks\"\u003eCác Khối\u003c/a\u003e\n\n  \u003ca name=\"blocks--braces\"\u003e\u003c/a\u003e\u003ca name=\"16.1\"\u003e\u003c/a\u003e\n  - [16.1](#blocks--braces) Sử dụng các dấu ngoặc cho các khối nhiều dòng. eslint: [`nonblock-statement-body-position`](https://eslint.org/docs/rules/nonblock-statement-body-position)\n\n    ``` javascript\n    // không tốt\n    if (test)\n      return false;\n\n    // tốt\n    if (test) return false;\n\n    // tốt\n    if (test) {\n      return false;\n    }\n\n    // không tốt\n    function foo() { return false; }\n\n    // tốt\n    function bar() {\n      return false;\n    }\n    ```\n\n  \u003ca name=\"blocks--cuddled-elses\"\u003e\u003c/a\u003e\u003ca name=\"16.2\"\u003e\u003c/a\u003e\n  - [16.2](#blocks--cuddled-elses) Nếu bạn đang sử dụng các khối nhiều dòng với `if` và `else`, đặt `else` trên cùng dòng với dấu đóng ngoặc của khối `if`. eslint: [`brace-style`](https://eslint.org/docs/rules/brace-style.html)\n\n    ``` javascript\n    // không tốt\n    if (test) {\n      thing1();\n      thing2();\n    }\n    else {\n      thing3();\n    }\n\n    // tốt\n    if (test) {\n      thing1();\n      thing2();\n    } else {\n      thing3();\n    }\n    ```\n\n  \u003ca name=\"blocks--no-else-return\"\u003e\u003c/a\u003e\u003ca name=\"16.3\"\u003e\u003c/a\u003e\n  - [16.3](#blocks--no-else-return) Nếu một khối `if` luôn thực hiện lệnh `return`, những khối `else` tiếp theo là không cần thiết. Một lệnh `return` trong một khối `else if` theo sau một khối `if` mà có chứa `return` có thể được tách thành nhiều khối `if`. eslint: [`no-else-return`](https://eslint.org/docs/rules/no-else-return)\n\n    ``` javascript\n    // không tốt\n    function foo() {\n      if (x) {\n        return x;\n      } else {\n        return y;\n      }\n    }\n\n    // không tốt\n    function cats() {\n      if (x) {\n        return x;\n      } else if (y) {\n        return y;\n      }\n    }\n\n    // không tốt\n    function dogs() {\n      if (x) {\n        return x;\n      } else {\n        if (y) {\n          return y;\n        }\n      }\n    }\n\n    // tốt\n    function foo() {\n      if (x) {\n        return x;\n      }\n\n      return y;\n    }\n\n    // tốt\n    function cats() {\n      if (x) {\n        return x;\n      }\n\n      if (y) {\n        return y;\n      }\n    }\n\n    // tốt\n    function dogs(x) {\n      if (x) {\n        if (z) {\n          return y;\n        }\n      } else {\n        return z;\n      }\n    }\n    ```\n\n**[⬆ về đầu trang](#table-of-contents)**\n\n## \u003ca name=\"control-statements\"\u003eCác Câu lệnh Điều khiển\u003c/a\u003e\n\n  \u003ca name=\"control-statements\"\u003e\u003c/a\u003e\n  - [17.1](#control-statements) Nếu trong trường hợp lệnh điều khiển (`if`, `while`, v.v.) của bạn trở lên quá dài và vượt quá giới hạn độ dài dòng, mỗi (nhóm) điều kiện có thể được đặt ở một dòng mới. Toán tử lô-gíc nên được đặt ở đầu dòng.\n\n    \u003e Tại sao? Việc đặt các toán tử ở đầu dòng giúp các toán tử được căn đều và tuân theo cùng một mô hình với việc nối chuỗi phương thức. Điều này cũng cải thiện tính khả đọc vì khiến cho việc theo dõi một lô-gíc phức tạp trở nên đơn giản hơn.\n\n    ``` javascript\n    // không tốt\n    if ((foo === 123 || bar === 'abc') \u0026\u0026 doesItLookGoodWhenItBecomesThatLong() \u0026\u0026 isThisReallyHappening()) {\n      thing1();\n    }\n\n    // không tốt\n    if (foo === 123 \u0026\u0026\n      bar === 'abc') {\n      thing1();\n    }\n\n    // không tốt\n    if (foo === 123\n      \u0026\u0026 bar === 'abc') {\n      thing1();\n    }\n\n    // không tốt\n    if (\n      foo === 123 \u0026\u0026\n      bar === 'abc'\n    ) {\n      thing1();\n    }\n\n    // tốt\n    if (\n      foo === 123\n      \u0026\u0026 bar === 'abc'\n    ) {\n      thing1();\n    }\n\n    // tốt\n    if (\n      (foo === 123 || bar === 'abc')\n      \u0026\u0026 doesItLookGoodWhenItBecomesThatLong()\n      \u0026\u0026 isThisReallyHappening()\n    ) {\n      thing1();\n    }\n\n    // tốt\n    if (foo === 123 \u0026\u0026 bar === 'abc') {\n      thing1();\n    }\n    ```\n\n  \u003ca name=\"control-statement--value-selection\"\u003e\u003c/a\u003e\u003ca name=\"control-statements--value-selection\"\u003e\u003c/a\u003e\n  - [17.2](#control-statements--value-selection) Không sử dụng toán tử lựa chọn thay cho các câu lệnh điều khiển.\n\n    ``` javascript\n    // không tốt\n    !isRunning \u0026\u0026 startRunning();\n\n    // tốt\n    if (!isRunning) {\n      startRunning();\n    }\n    ```\n\n**[⬆ về đầu trang](#table-of-contents)**\n\n## \u003ca name=\"comments\"\u003eCác Chú thích\u003c/a\u003e\n\n  \u003ca name=\"comments--multiline\"\u003e\u003c/a\u003e\u003ca name=\"17.1\"\u003e\u003c/a\u003e\n  - [18.1](#comments--multiline) Sử dụng `/** ... */` cho các chú thích nhiều dòng.\n\n    ``` javascript\n    // không tốt\n    // make() trả về một phần tử\n    // dựa trên tag được truyền vào\n    //\n    // @param {String} tag\n    // @return {Element} element\n    function make(tag) {\n\n      // ...\n\n      return element;\n    }\n\n    // tốt\n    /**\n     * make() trả về một phần tử\n     * dựa trên tag được truyền vào\n     */\n    function make(tag) {\n\n      // ...\n\n      return element;\n    }\n    ```\n\n  \u003ca name=\"comments--singleline\"\u003e\u003c/a\u003e\u003ca name=\"17.2\"\u003e\u003c/a\u003e\n  - [18.2](#comments--singleline) Sử dụng `//` cho các chú thích một dòng. Đặt các chú thích một dòng ở một dòng riêng, bên trên chủ đề của chú thích. Để một dòng trống trước chú thích trừ khi chú thích là dòng đầu tiên của một khối.\n\n    ``` javascript\n    // không tốt\n    const active = true;  // là thẻ hiện tại\n\n    // tốt\n    // là thẻ hiện tại\n    const active = true;\n\n    // không tốt\n    function getType() {\n      console.log('đang lấy loại...');\n      // đặt loại mặc định là 'không phân loại'\n      const type = this.type || 'không phân loại';\n\n      return type;\n    }\n\n    // tốt\n    function getType() {\n      console.log('đang lấy loại...');\n\n      // đặt loại mặc định là 'không phân loại'\n      const type = this.type || 'không phân loại';\n\n      return type;\n    }\n\n    // như này cũng tốt\n    function getType() {\n      // đặt loại mặc định là 'không phân loại'\n      const type = this.type || 'không phân loại';\n\n      return type;\n    }\n    ```\n\n  \u003ca name=\"comments--spaces\"\u003e\u003c/a\u003e\n  - [18.3](#comments--spaces) Bắt đầu tất cả các chú thích bằng một dấu cách để dễ đọc hơn. eslint: [`spaced-comment`](https://eslint.org/docs/rules/spaced-comment)\n\n    ``` javascript\n    // không tốt\n    //là thẻ hiện tại\n    const active = true;\n\n    // tốt\n    // là thẻ hiện tại\n    const active = true;\n\n    // không tốt\n    /**\n     *make() trả về một phần tử\n     *dựa trên tag được truyền vào\n     */\n    function make(tag) {\n\n      // ...\n\n      return element;\n    }\n\n    // tốt\n    /**\n     * make() trả về một phần tử\n     * dựa trên tag được truyền vào\n     */\n    function make(tag) {\n\n      // ...\n\n      return element;\n    }\n    ```\n\n  \u003ca name=\"comments--actionitems\"\u003e\u003c/a\u003e\u003ca name=\"17.3\"\u003e\u003c/a\u003e\n  - [18.4](#comments--actionitems) Thêm `FIXME` hoặc `TODO` vào đầu chú thích giúp các nhà phát triển dễ dàng biết được rằng bạn đang chỉ ra một vấn đề cần được xem lại, hoặc bạn đang đề xuất cách giải quyết cho vấn đề nên mà được áp dụng. Các hành động có thể như `FIXME: -- cần xem xét về thứ này` hoặc `TODO: -- cần áp dụng`.\n\n  \u003ca name=\"comments--fixme\"\u003e\u003c/a\u003e\u003ca name=\"17.4\"\u003e\u003c/a\u003e\n  - [18.5](#comments--fixme) Sử dụng `// FIXME:` để chú giải các vấn đề.\n\n    ``` javascript\n    class Calculator extends Abacus {\n      constructor() {\n        super();\n\n        // FIXME: không nên dùng biến toàn cục ở đây\n        total = 0;\n      }\n    }\n    ```\n\n  \u003ca name=\"comments--todo\"\u003e\u003c/a\u003e\u003ca name=\"17.5\"\u003e\u003c/a\u003e\n  - [18.6](#comments--todo) Sử dụng `// TODO:` để chú giải các cách giải quyết cho các vấn đề.\n\n    ``` javascript\n    class Calculator extends Abacus {\n      constructor() {\n        super();\n\n        // TODO: giá trị của total nên được chuyển thành tham số\n        this.total = 0;\n      }\n    }\n    ```\n\n**[⬆ về đầu trang](#table-of-contents)**\n\n## \u003ca name=\"whitespace\"\u003eKhoảng trắng\u003c/a\u003e\n\n  \u003ca name=\"whitespace--spaces\"\u003e\u003c/a\u003e\u003ca name=\"18.1\"\u003e\u003c/a\u003e\n  - [19.1](#whitespace--spaces) Sử dụng các tab ngắn (dấu cách) đặt về 2 dấu cách. eslint: [`indent`](https://eslint.org/docs/rules/indent.html)\n\n    ``` javascript\n    // không tốt\n    function foo() {\n    ∙∙∙∙let name;\n    }\n\n    // không tốt\n    function bar() {\n    ∙let name;\n    }\n\n    // tốt\n    function baz() {\n    ∙∙let name;\n    }\n    ```\n\n  \u003ca name=\"whitespace--before-blocks\"\u003e\u003c/a\u003e\u003ca name=\"18.2\"\u003e\u003c/a\u003e\n  - [19.2](#whitespace--before-blocks) Đặt 1 cách trước dấu mở ngoặc. eslint: [`space-before-blocks`](https://eslint.org/docs/rules/space-before-blocks.html)\n\n    ``` javascript\n    // không tốt\n    function test(){\n      console.log('ví dụ');\n    }\n\n    // tốt\n    function test() {\n      console.log('ví dụ');\n    }\n\n    // không tốt\n    dog.set('attr',{\n      age: '1 năm',\n      breed: 'Chó núi Bern',\n    });\n\n    // tốt\n    dog.set('attr', {\n      age: '1 năm',\n      breed: 'Chó núi Bern',\n    });\n    ```\n\n  \u003ca name=\"whitespace--around-keywords\"\u003e\u003c/a\u003e\u003ca name=\"18.3\"\u003e\u003c/a\u003e\n  - [19.3](#whitespace--around-keywords) Đặt 1 dấu cách trước dấu mở ngoặc tròn của các lệnh điều khiển (`if`, `while`, v.v.). Không đặt dấu cách giữa danh sách đối số và tên hàm trong các phép gọi và khai báo hàm. eslint: [`keyword-spacing`](https://eslint.org/docs/rules/keyword-spacing.html)\n\n    ``` javascript\n    // không tốt\n    if(isJedi) {\n      fight ();\n    }\n\n    // tốt\n    if (isJedi) {\n      fight();\n    }\n\n    // không tốt\n    function fight () {\n      console.log ('Uiiiiii!');\n    }\n\n    // tốt\n    function fight() {\n      console.log('Uiiiiii!');\n    }\n    ```\n\n  \u003ca name=\"whitespace--infix-ops\"\u003e\u003c/a\u003e\u003ca name=\"18.4\"\u003e\u003c/a\u003e\n  - [19.4](#whitespace--infix-ops) Đặt dấu cách trước và sau các toán tử. eslint: [`space-infix-ops`](https://eslint.org/docs/rules/space-infix-ops.html)\n\n    ``` javascript\n    // không tốt\n    const x=y+5;\n\n    // tốt\n    const x = y + 5;\n    ```\n\n  \u003ca name=\"whitespace--newline-at-end\"\u003e\u003c/a\u003e\u003ca name=\"18.5\"\u003e\u003c/a\u003e\n  - [19.5](#whitespace--newline-at-end) Kết thúc tệp với một dấu ngắt dòng. eslint: [`eol-last`](https://github.com/eslint/eslint/blob/master/docs/rules/eol-last.md)\n\n    ``` javascript\n    // không tốt\n    import { es6 } from './AirbnbStyleGuide';\n      // ...\n    export default es6;\n    ```\n\n    ``` javascript\n    // không tốt\n    import { es6 } from './AirbnbStyleGuide';\n      // ...\n    export default es6;↵\n    ↵\n    ```\n\n    ``` javascript\n    // tốt\n    import { es6 } from './AirbnbStyleGuide';\n      // ...\n    export default es6;↵\n    ```\n\n  \u003ca name=\"whitespace--chains\"\u003e\u003c/a\u003e\u003ca name=\"18.6\"\u003e\u003c/a\u003e\n  - [19.6](#whitespace--chains) Căn đầu dòng khi tạo các chuỗi phương thức (nhiều hơn 2 chuỗi phương thức). Đặt dấu chấm ở đầu, để nhấn mạnh dòng này là một phép gọi phương thức, không phải là một câu lệnh mới. eslint: [`newline-per-chained-call`](https://eslint.org/docs/rules/newline-per-chained-call) [`no-whitespace-before-property`](https://eslint.org/docs/rules/no-whitespace-before-property)\n\n    ``` javascript\n    // không tốt\n    $('#items').find('.selected').highlight().end().find('.open').updateCount();\n\n    // không tốt\n    $('#items').\n      find('.selected').\n        highlight().\n        end().\n      find('.open').\n        updateCount();\n\n    // tốt\n    $('#items')\n      .find('.selected')\n        .highlight()\n        .end()\n      .find('.open')\n        .updateCount();\n\n    // không tốt\n    const leds = stage.selectAll('.led').data(data).enter().append('svg:svg').classed('led', true)\n        .attr('width', (radius + margin) * 2).append('svg:g')\n        .attr('transform', `translate(${radius + margin},${radius + margin})`)\n        .call(tron.led);\n\n    // tốt\n    const leds = stage.selectAll('.led')\n        .data(data)\n      .enter().append('svg:svg')\n        .classed('led', true)\n        .attr('width', (radius + margin) * 2)\n      .append('svg:g')\n        .attr('transform', `translate(${radius + margin},${radius + margin})`)\n        .call(tron.led);\n\n    // tốt\n    const leds = stage.selectAll('.led').data(data);\n    const svg = leds.enter().append('svg:svg');\n    svg.classed('led', true).attr('width', (radius + margin) * 2);\n    const g = svg.append('svg:g');\n    g.attr('transform', `translate(${radius + margin},${radius + margin})`).call(tron.led);\n    ```\n\n  \u003ca name=\"whitespace--after-blocks\"\u003e\u003c/a\u003e\u003ca name=\"18.7\"\u003e\u003c/a\u003e\n  - [19.7](#whitespace--after-blocks) Để một dòng trống sau mỗi khối và trước câu lệnh tiếp theo.\n\n    ``` javascript\n    // không tốt\n    if (foo) {\n      return bar;\n    }\n    return baz;\n\n    // tốt\n    if (foo) {\n      return bar;\n    }\n\n    return baz;\n\n    // không tốt\n    const obj = {\n      foo() {\n      },\n      bar() {\n      },\n    };\n    return obj;\n\n    // tốt\n    const obj = {\n      foo() {\n      },\n\n      bar() {\n      },\n    };\n\n    return obj;\n\n    // không tốt\n    const arr = [\n      function foo() {\n      },\n      function bar() {\n      },\n    ];\n    return arr;\n\n    // tốt\n    const arr = [\n      function foo() {\n      },\n\n      function bar() {\n      },\n    ];\n\n    return arr;\n    ```\n\n  \u003ca name=\"whitespace--padded-blocks\"\u003e\u003c/a\u003e\u003ca name=\"18.8\"\u003e\u003c/a\u003e\n  - [19.8](#whitespace--padded-blocks) Không kê các khối với các dòng trống. eslint: [`padded-blocks`](https://eslint.org/docs/rules/padded-blocks.html)\n\n    ``` javascript\n    // không tốt\n    function bar() {\n\n      console.log(foo);\n\n    }\n\n    // không tốt\n    if (baz) {\n\n      console.log(qux);\n    } else {\n      console.log(foo);\n\n    }\n\n    // không tốt\n    class Foo {\n\n      constructor(bar) {\n        this.bar = bar;\n      }\n    }\n\n    // tốt\n    function bar() {\n      console.log(foo);\n    }\n\n    // tốt\n    if (baz) {\n      console.log(qux);\n    } else {\n      console.log(foo);\n    }\n    ```\n\n  \u003ca name=\"whitespace--no-multiple-blanks\"\u003e\u003c/a\u003e\n  - [19.9](#whitespace--no-multiple-blanks) Do not use multiple blank lines to pad your code. eslint: [`no-multiple-empty-lines`](https://eslint.org/docs/rules/no-multiple-empty-lines)\n\n    \u003c!-- markdownlint-disable MD012 --\u003e\n    ``` javascript\n    // không tốt\n    class Person {\n      constructor(fullName, email, birthday) {\n        this.fullName = fullName;\n\n\n        this.email = email;\n\n\n        this.setAge(birthday);\n      }\n\n\n      setAge(birthday) {\n        const today = new Date();\n\n\n        const age = this.getAge(today, birthday);\n\n\n        this.age = age;\n      }\n\n\n      getAge(today, birthday) {\n        // ..\n      }\n    }\n\n    // tốt\n    class Person {\n      constructor(fullName, email, birthday) {\n        this.fullName = fullName;\n        this.email = email;\n        this.setAge(birthday);\n      }\n\n      setAge(birthday) {\n        const today = new Date();\n        const age = getAge(today, birthday);\n        this.age = age;\n      }\n\n      getAge(today, birthday) {\n        // ..\n      }\n    }\n    ```\n\n  \u003ca name=\"whitespace--in-parens\"\u003e\u003c/a\u003e\u003ca name=\"18.9\"\u003e\u003c/a\u003e\n  - [19.10](#whitespace--in-parens) Không thêm các dấu cách trong dấu ngoặc tròn. eslint: [`space-in-parens`](https://eslint.org/docs/rules/space-in-parens.html)\n\n    ``` javascript\n    // không tốt\n    function bar( foo ) {\n      return foo;\n    }\n\n    // tốt\n    function bar(foo) {\n      return foo;\n    }\n\n    // không tốt\n    if ( foo ) {\n      console.log(foo);\n    }\n\n    // tốt\n    if (foo) {\n      console.log(foo);\n    }\n    ```\n\n  \u003ca name=\"whitespace--in-brackets\"\u003e\u003c/a\u003e\u003ca name=\"18.10\"\u003e\u003c/a\u003e\n  - [19.11](#whitespace--in-brackets) Không thêm các dấu cách trong các dấu ngoặc vuông. eslint: [`array-bracket-spacing`](https://eslint.org/docs/rules/array-bracket-spacing.html)\n\n    ``` javascript\n    // không tốt\n    const foo = [ 1, 2, 3 ];\n    console.log(foo[ 0 ]);\n\n    // tốt\n    const foo = [1, 2, 3];\n    console.log(foo[0]);\n    ```\n\n  \u003ca name=\"whitespace--in-braces\"\u003e\u003c/a\u003e\u003ca name=\"18.11\"\u003e\u003c/a\u003e\n  - [19.12](#whitespace--in-braces) Thêm các dấu cách giữa các dấu ngoặc nhọn. eslint: [`object-curly-spacing`](https://eslint.org/docs/rules/object-curly-spacing.html)\n\n    ``` javascript\n    // không tốt\n    const foo = {clark: 'kent'};\n\n    // tốt\n    const foo = { clark: 'kent' };\n    ```\n\n  \u003ca name=\"whitespace--max-len\"\u003e\u003c/a\u003e\u003ca name=\"18.12\"\u003e\u003c/a\u003e\n  - [19.13](#whitespace--max-len) Tránh các dòng mã có nhiều hơn 100 ký tự (kể cả khoảng trắng). Lưu ý: theo như [trên đây](#strings--line-length), các chuỗi được loại trừ bởi quy tắc này, và bạn không nên chia chúng ra. eslint: [`max-len`](https://eslint.org/docs/rules/max-len.html)\n\n    \u003e Tại sao? Điều này đảm bảo tính khả đọc và khả năng bảo trì.\n\n    ``` javascript\n    // không tốt\n    const foo = jsonData \u0026\u0026 jsonData.foo \u0026\u0026 jsonData.foo.bar \u0026\u0026 jsonData.foo.bar.baz \u0026\u0026 jsonData.foo.bar.baz.quux \u0026\u0026 jsonData.foo.bar.baz.quux.xyzzy;\n\n    // không tốt\n    $.ajax({ method: 'POST', url: 'https://airbnb.com/', data: { name: 'John' } }).done(() =\u003e console.log('Chúc mừng!')).fail(() =\u003e console.log('You have failed this city.'));\n\n    // tốt\n    const foo = jsonData\n      \u0026\u0026 jsonData.foo\n      \u0026\u0026 jsonData.foo.bar\n      \u0026\u0026 jsonData.foo.bar.baz\n      \u0026\u0026 jsonData.foo.bar.baz.quux\n      \u0026\u0026 jsonData.foo.bar.baz.quux.xyzzy;\n\n    // tốt\n    $.ajax({\n      method: 'POST',\n      url: 'https://airbnb.com/',\n      data: { name: 'John' },\n    })\n      .done(() =\u003e console.log('Chúc mừng!'))\n      .fail(() =\u003e console.log('You have failed this city.'));\n    ```\n\n  \u003ca name=\"whitespace--block-spacing\"\u003e\u003c/a\u003e\n  - [19.14](#whitespace--block-spacing) Đảm bảo sự nhất quán về dấu cách sau dấu mở ngoặc và trước ký tự đầu tiên sau nó trên cùng một dòng. Quy tắc này cũng yêu cầu sự nhất quán về dấu cách trước dấu đóng ngoặc và sau ký tự cuối cùng trước nó trên cùng một dòng. eslint: [`block-spacing`](https://eslint.org/docs/rules/block-spacing)\n\n    ``` javascript\n    // không tốt\n    function foo() {return true;}\n    if (foo) { bar = 0;}\n\n    // tốt\n    function foo() { return true; }\n    if (foo) { bar = 0; }\n    ```\n\n  \u003ca name=\"whitespace--comma-spacing\"\u003e\u003c/a\u003e\n  - [19.15](#whitespace--comma-spacing) Không sử dụng dấu cách trước dấu phẩy và phải sử dụng dấu cách sau dấu phẩy. eslint: [`comma-spacing`](https://eslint.org/docs/rules/comma-spacing)\n\n    ``` javascript\n    // không tốt\n    var foo = 1,bar = 2;\n    var arr = [1 , 2];\n\n    // tốt\n    var foo = 1, bar = 2;\n    var arr = [1, 2];\n    ```\n\n  \u003ca name=\"whitespace--computed-property-spacing\"\u003e\u003c/a\u003e\n  - [19.16](#whitespace--computed-property-spacing) Không đặt dấu cách bên trong dấu ngoặc của thuộc tính được tính. eslint: [`computed-property-spacing`](https://eslint.org/docs/rules/computed-property-spacing)\n\n    ``` javascript\n    // không tốt\n    obj[foo ]\n    obj[ 'foo']\n    var x = {[ b ]: a}\n    obj[foo[ bar ]]\n\n    // tốt\n    obj[foo]\n    obj['foo']\n    var x = { [b]: a }\n    obj[foo[bar]]\n    ```\n\n  \u003ca name=\"whitespace--func-call-spacing\"\u003e\u003c/a\u003e\n  - [19.17](#whitespace--func-call-spacing) Tránh sử dụng dấu cách giữa các hàm và phép gọi chúng. eslint: [`func-call-spacing`](https://eslint.org/docs/rules/func-call-spacing)\n\n    ``` javascript\n    // không tốt\n    func ();\n\n    func\n    ();\n\n    // tốt\n    func();\n    ```\n\n  \u003ca name=\"whitespace--key-spacing\"\u003e\u003c/a\u003e\n  - [19.18](#whitespace--key-spacing) Đặt dấu cách giữa các tên và giá trị của các thuộc tính nguyên văn. eslint: [`key-spacing`](https://eslint.org/docs/rules/key-spacing)\n\n    ``` javascript\n    // không tốt\n    var obj = { foo : 42 };\n    var obj2 = { foo:42 };\n\n    // tốt\n    var obj = { foo: 42 };\n    ```\n\n  \u003ca name=\"whitespace--no-trailing-spaces\"\u003e\u003c/a\u003e\n  - [19.19](#whitespace--no-trailing-spaces) Tránh các dấu cách ở cuối các dòng. eslint: [`no-trailing-spaces`](https://eslint.org/docs/rules/no-trailing-spaces)\n\n  \u003ca name=\"whitespace--no-multiple-empty-lines\"\u003e\u003c/a\u003e\n  - [19.20](#whitespace--no-multiple-empty-lines) Tránh để nhiều dòng trống liên tiếp, chỉ để một dòng trống ở cuối tệp, và không để dòng trống ở đầu tệp. eslint: [`no-multiple-empty-lines`](https://eslint.org/docs/rules/no-multiple-empty-lines)\n\n    \u003c!-- markdownlint-disable MD012 --\u003e\n    ``` javascript\n    // không tốt - nhiều dòng trống liên tiếp\n    var x = 1;\n\n\n    var y = 2;\n\n    // bad - 2+ dòng trống ở cuối tệp\n    var x = 1;\n    var y = 2;\n\n\n    // không tốt - 1+ dòng trống ở đầu tệp\n\n    var x = 1;\n    var y = 2;\n\n    // tốt\n    var x = 1;\n    var y = 2;\n\n    ```\n    \u003c!-- markdownlint-enable MD012 --\u003e\n\n**[⬆ về đầu trang](#table-of-contents)**\n\n## \u003ca name=\"commas\"\u003eCác Dấu phẩy\u003c/a\u003e\n\n  \u003ca name=\"commas--leading-trailing\"\u003e\u003c/a\u003e\u003ca name=\"19.1\"\u003e\u003c/a\u003e\n  - [20.1](#commas--leading-trailing) Các dấu phẩy ở đầu: **Đừng!** eslint: [`comma-style`](https://eslint.org/docs/rules/comma-style.html)\n\n    ``` javascript\n    // không tốt\n    const story = [\n        once\n      , upon\n      , aTime\n    ];\n\n    // tốt\n    const story = [\n      once,\n      upon,\n      aTime,\n    ];\n\n    // không tốt\n    const hero = {\n        firstName: 'Ada'\n      , lastName: 'Lovelace'\n      , birthYear: 1815\n      , superPower: 'máy tính'\n    };\n\n    // tốt\n    const hero = {\n      firstName: 'Ada',\n      lastName: 'Lovelace',\n      birthYear: 1815,\n      superPower: 'máy tính',\n    };\n    ```\n\n  \u003ca name=\"commas--dangling\"\u003e\u003c/a\u003e\u003ca name=\"19.2\"\u003e\u003c/a\u003e\n  - [20.2](#commas--dangling) Thêm một dấu phẩy ở cuối: **Đúng đó!** eslint: [`comma-dangle`](https://eslint.org/docs/rules/comma-dangle.html)\n\n    \u003e Tại sao? Điều này làm cho các so sánh git gọn gàng hơn. Ngoài ra, các trình dịch mã như Babel sẽ xóa các dấu phẩy ở cuối trong mã được dịch, có nghĩa là bạn không cần lo lắng về [vấn đề của dấu phẩy ở cuối](https://github.com/airbnb/javascript/blob/es5-deprecated/es5/README.md#commas) trên các trình duyệt cũ.\n\n    ```diff\n    // không tốt - so sánh git khi không có dấu phẩy ở cuối\n    const hero = {\n         firstName: 'Florence',\n    -    lastName: 'Nightingale'\n    +    lastName: 'Nightingale',\n    +    inventorOf: ['coxcomb chart', 'modern nursing']\n    };\n\n    // tốt - so sánh git khi có các dấu phẩy ở cuối\n    const hero = {\n         firstName: 'Florence',\n         lastName: 'Nightingale',\n    +    inventorOf: ['coxcomb chart', 'modern nursing'],\n    };\n    ```\n\n    ```  javascript\n    // không tốt\n    const hero = {\n      firstName: 'Dana',\n      lastName: 'Scully'\n    };\n\n    const heroes = [\n      'Batman',\n      'Superman'\n    ];\n\n    // tốt\n    const hero = {\n      firstName: 'Dana',\n      lastName: 'Scully',\n    };\n\n    const heroes = [\n      'Batman',\n      'Superman',\n    ];\n\n    // không tốt\n    function createHero(\n      firstName,\n      lastName,\n      inventorOf\n    ) {\n      // không làm gì cả\n    }\n\n    // tốt\n    function createHero(\n      firstName,\n      lastName,\n      inventorOf,\n    ) {\n      // không làm gì cả\n    }\n\n    // tốt (lưu ý là không được đặt dấu phẩy sau phần từ \"còn-lại\")\n    function createHero(\n      firstName,\n      lastName,\n      inventorOf,\n      ...heroArgs\n    ) {\n      // không làm gì cả\n    }\n\n    // không tốt\n    createHero(\n      firstName,\n      lastName,\n      inventorOf\n    );\n\n    // tốt\n    createHero(\n      firstName,\n      lastName,\n      inventorOf,\n    );\n\n    // tốt (lưu ý là không được đặt dấu phẩy sau phần từ \"còn-lại\")\n    createHero(\n      firstName,\n      lastName,\n      inventorOf,\n      ...heroArgs\n    );\n    ```\n\n**[⬆ về đầu trang](#table-of-contents)**\n\n## \u003ca name=\"semicolons\"\u003eCác Dấu chấm phẩy\u003c/a\u003e\n\n  \u003ca name=\"semicolons--required\"\u003e\u003c/a\u003e\u003ca name=\"20.1\"\u003e\u003c/a\u003e\n  - [21.1](#semicolons--required) **Dĩ nhiên.** eslint: [`semi`](https://eslint.org/docs/rul","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdangkyokhoang%2Fjavascript-style-guide","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdangkyokhoang%2Fjavascript-style-guide","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdangkyokhoang%2Fjavascript-style-guide/lists"}