├── terminology.js ├── LICENSE.txt ├── terminology.md └── README.md /terminology.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | 5 | const readme = fs.readFileSync('README.md', 'utf8'); 6 | const terminology = fs.readFileSync('terminology.md', 'utf8'); 7 | const back = '**[⬆ về đầu trang](#table-of-contents)**'; 8 | 9 | // Terminology section is to be inserted before the translation section 10 | const search = /\s+(##.+"terminology"[\s\S]+|)(?=##.+"translation")/; 11 | const replacement = `\n\n${terminology.trim()}\n\n${back}\n\n`; 12 | 13 | fs.writeFileSync('README.md', readme.replace(search, replacement)); 14 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2012 Airbnb 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /terminology.md: -------------------------------------------------------------------------------- 1 | ## Danh mục các Thuật ngữ 2 | 3 | Dưới đây là danh mục các từ tiếng Anh tương ứng của 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. Các từ, cụm từ được dịch có thể chỉ đúng trong ngữ cảnh là bản dịch này. 4 | 5 | > Nếu bạn cảm thấy một thuật ngữ có vẻ được dịch chưa hợp lý, hoặc bạn cần sự giải thích về một thuật ngữ, bạn có thể mở một [Vấn đề](https://github.com/dangkyokhoang/javascript-style-guide/issues) để thảo luận. 6 | > 7 | > Nếu bạn biết một từ/cụm từ tiếng Việt thích hợp hơn cho một thuật ngữ, và nếu bạn sẵn lòng, bạn có thể mở một [Đề nghị kéo](https://github.com/dangkyokhoang/javascript-style-guide/pulls) cho một sửa đổi. 8 | 9 | | Tiếng Việt | English | 10 | | --- | --- | 11 | | Ánh xạ | Map/mapping | 12 | | Ba ngôi | Ternary | 13 | | Bản sao/sao | Copy | 14 | | Bản sao nhanh/sao nhanh | Shallow-copy | 15 | | Bắt | Catch | 16 | | Bất biến | Immutable | 17 | | Bẻ nhánh | Fork | 18 | | Biến | Variable/var | 19 | | Biến đổi/sự biến đổi | Mutate/mutation | 20 | | Biểu thức | Expression | 21 | | Biểu thức hàm | Function expression | 22 | | Biểu thức hàm gọi tức thời | Immediately invoked function expression/IIFE | 23 | | Bộ khung phần mềm | Framework | 24 | | Bộ phận hàm | Function signature | 25 | | Bộ tải | Loader | 26 | | Bộ tổng hợp | Bundler | 27 | | Bộ trợ năng | Shim/polyfill | 28 | | Bước | Step | 29 | | Cải tiến mã nguồn | Refactor code/code refactoring | 30 | | Căn đầu dòng | Indent | 31 | | Câu lệnh/lệnh | Statement | 32 | | Cấu trúc một dòng | One-liner | 33 | | Chỉ-viết | Write-only | 34 | | Chuỗi | String | 35 | | Chú thích | Comment | 36 | | Còn-lại | Rest | 37 | | Cơ số | Radix | 38 | | Cú pháp | Syntax | 39 | | Cú pháp tiện lợi | Syntactic sugar | 40 | | Cũ | Legacy | 41 | | Dấu gạch dưới | Underscore | 42 | | Dấu lược/dấu nháy đơn | Single quote | 43 | | Dấu ngắt dòng/dấu xuống dòng | Line break | 44 | | Dấu ngoặc | Brace | 45 | | Dấu ngoặc nhọn | Curly brace | 46 | | Dấu ngoặc tròn | Parenthesis/parentheses | 47 | | Dấu ngoặc vuông | Array bracket | 48 | | Dịch mã | Transpile | 49 | | Duyệt | Iterate | 50 | | Đề xuất | Proposal | 51 | | Đề nghị kéo | Pull request | 52 | | Định danh | Identifier | 53 | | Định hướng lối viết | Style guide | 54 | | Định nghĩa | Define | 55 | | Đối số | Argument | 56 | | Đối tượng | Object | 57 | | Đối tượng duyệt | Iterator/iterator object | 58 | | Đối tượng đích | Receiver | 59 | | Đối tượng độc nhất | Singleton | 60 | | Đối tượng khả duyệt | Iterable object | 61 | | Đối tượng rỗng | Null object | 62 | | Đối tượng trần | Bare object | 63 | | Độ bao phủ | Coverage | 64 | | Đường dẫn | Path | 65 | | Ép kiểu/sự ép kiểu | Coerce/coercion/cast/casting | 66 | | Gán/phép gán | Assign/assignment | 67 | | Gán lại | Reassign | 68 | | Ghép | Concatenate/concatenation/concat | 69 | | Giai đoạn chết | Temporal dead zone/TDZ | 70 | | Giá trị băm | Hash/hash value | 71 | | Giá trị gốc | Raw value | 72 | | Giả lập đối tượng | Mock | 73 | | Giả lập mô-đun | Stub | 74 | | Giống-mảng | Array-like | 75 | | Gọi/phép gọi | Call/invoke/invocation | 76 | | Hàm | Function | 77 | | Hàm bất định | Variadic function | 78 | | Hàm bậc cao hơn | Higher-order function | 79 | | Hàm đọc | Getter/getter function | 80 | | Hàm ghi | Setter/setter function | 81 | | Hàm gọi ngược | Callback/callback function | 82 | | Hàm gọi tức thời | Immediately invoked function | 83 | | Hàm hữu danh | Named function | 84 | | Hàm mũi tên | Arrow function | 85 | | Hàm sinh trị | Generator/generator function | 86 | | Hàm tạo | Constructor | 87 | | Hàm thuần | Pure function | 88 | | Hàm tiện ích | Utility/utility function | 89 | | Hàm truy cập | Accessor/accessor function | 90 | | Hàm vô danh | Anonymous function | 91 | | Hàm xử lý | Handler | 92 | | Hằng | Constant/const | 93 | | Hiệu suất | Performance/perf | 94 | | Hiệu ứng phụ | Side effect | 95 | | Kéo lên/sự kéo lên/nổi lên/sự nổi lên | Hoist/hoisting | 96 | | Kê | Pad | 97 | | Khai báo | Declare/declaration | 98 | | Khoảng trắng | Whitespace | 99 | | Không gian tên | Namespace | 100 | | Khối | Block | 101 | | Kiểm thử/sự kiểm thử | Test/testing | 102 | | Kiểu giá trị | Type | 103 | | Kiểu nguyên thủy | Primitive | 104 | | Kiểu sai | Falsy/falsey | 105 | | Ký pháp | Notation | 106 | | Ký pháp chấm | Dot notation | 107 | | Ký tự đại diện | Wildcard/wildcard character | 108 | | Ký tự thoát | Escape character | 109 | | Liên kết | Link | 110 | | Liệt kê | Spread | 111 | | Lô-gíc | Logic | 112 | | Lỗ hổng | Vulnerability | 113 | | Lỗi câm | Silent error | 114 | | Lớp | Class | 115 | | Lớp cha | Parent class/parent | 116 | | Lũy thừa | Exponentiation | 117 | | Lưu tạm | Cache | 118 | | Lựa chọn | Select/selection | 119 | | Mã/mã nguồn | Code/source code | 120 | | Mảng | Array | 121 | | Mô-đun | Module | 122 | | Một ngôi | Unary | 123 | | Ném ra | Throw | 124 | | Ngăn xếp | Call stack/stack | 125 | | Ngầm định | Implicit | 126 | | Nghẽn cổ chai | Bottleneck | 127 | | Ngoại lệ | Exception | 128 | | Nguyên mẫu | Prototype | 129 | | Nguyên văn | Literal | 130 | | Ngữ cảnh | Context | 131 | | Nhà phát triển | Developer/dev | 132 | | Nhập/lệnh nhập | Import | 133 | | Nối chuỗi | Chain/chaining | 134 | | Phần tử | Element | 135 | | Phép dịch chuyển bit | Bit-shift/bit-shift operation | 136 | | Phép tăng | Increment | 137 | | Phép giảm | Decrement | 138 | | Phép tiền tăng/sự tiền tăng | Pre-increment | 139 | | Phép tiền giảm/sự tiền giảm | Pre-decrement | 140 | | Phi chuẩn | Non-standard | 141 | | Phương thức | Method | 142 | | Quy tắc chèn dấu chấm phẩy tự động | Automatic semicolon insertion/ASI | 143 | | Quy ước đặt tên | Naming convention | 144 | | Ràng buộc | Binding | 145 | | Riêng tư | Private | 146 | | Rút gọn/dạng rút gọn | Shorthand/shortcut | 147 | | So sánh/sự so sánh | Compare/comparision | 148 | | Sự bằng nhau | Equality | 149 | | Sự kiện | Event/ev | 150 | | Tên của thuộc tính | Property name/key | 151 | | Tên được tính của thuộc tính | Computed property name | 152 | | Tham chiếu | Reference | 153 | | Tham số | Parameter | 154 | | Thành viên | Member | 155 | | Thân hàm | Function body | 156 | | Thẻ | Tab | 157 | | Thuộc phạm vi hàm | Function-scoped | 158 | | Thuộc phạm vi khối | Block-scoped | 159 | | Thuộc tính | Property | 160 | | Thư viện | Library/lib | 161 | | Thừa kế | Inherit/inheritance | 162 | | Thực thể | Instance | 163 | | Tiến trình gọi | Caller | 164 | | Tính khả đọc | Readability | 165 | | Tính tương thích | Compatibility | 166 | | Toàn cục | Global | 167 | | Toán tử | Operator | 168 | | Trình gỡ lỗi | Debugger | 169 | | Trình phân tích mã | Linter | 170 | | Trình thực thi | Engine | 171 | | Trích xuất/sự trích xuất | Destructure/destructuring/extract | 172 | | Trọng tải | Payload | 173 | | Truy cập | Access | 174 | | Truy vấn | Query | 175 | | Từ khóa | Keyword | 176 | | Từ khóa điều chỉnh | Modifier | 177 | | Ứng dụng | Application/app | 178 | | Vấn đề | Issue | 179 | | Xếp tầng | Cascade/cascading | 180 | | Xuất/lệnh xuất | Export | 181 | | Xuất hữu danh | Named export | 182 | | Xuất mặc định | Default export | 183 | | Xung đột khi gộp | Merge conflict | 184 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Định hướng Lối viết JavaScript của Airbnb() { 2 | 3 | *Một cách tiếp cận hợp lý đối với JavaScript* 4 | 5 | > **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). 6 | 7 | > **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. 8 | 9 | [![Lượt tải](https://img.shields.io/npm/dm/eslint-config-airbnb.svg)](https://www.npmjs.com/package/eslint-config-airbnb) 10 | [![Lượt tải](https://img.shields.io/npm/dm/eslint-config-airbnb-base.svg)](https://www.npmjs.com/package/eslint-config-airbnb-base) 11 | [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/airbnb/javascript?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) 12 | 13 | Định hướng này cũng được dịch sang các ngôn ngữ khác. Xem phần [Dịch](#translation). 14 | 15 | Các Định hướng Lối viết Khác 16 | 17 | - [ES5 (Đã lỗi thời)](https://github.com/airbnb/javascript/tree/es5-deprecated/es5) 18 | - [React](https://github.com/airbnb/javascript/blob/master/react) 19 | - [CSS-trong-JavaScript](https://github.com/airbnb/javascript/blob/master/css-in-javascript) 20 | - [CSS & Sass](https://github.com/airbnb/css) 21 | - [Ruby](https://github.com/airbnb/ruby) 22 | 23 | ## Mục lục 24 | 25 | 1. [Các Kiểu giá trị](#types) 26 | 1. [Các Tham chiếu](#references) 27 | 1. [Các Đối tượng](#objects) 28 | 1. [Các Mảng](#arrays) 29 | 1. [Trích xuất](#destructuring) 30 | 1. [Các Chuỗi](#strings) 31 | 1. [Các Hàm](#functions) 32 | 1. [Các Hàm mũi tên](#arrow-functions) 33 | 1. [Các Lớp & các Hàm tạo](#classes--constructors) 34 | 1. [Các Mô-đun](#modules) 35 | 1. [Các Đối tượng duyệt and các Hàm sinh trị](#iterators-and-generators) 36 | 1. [Các Thuộc tính](#properties) 37 | 1. [Các Biến](#variables) 38 | 1. [Sự kéo lên](#hoisting) 39 | 1. [Các Toán tử So sánh và Sự bằng nhau](#comparison-operators--equality) 40 | 1. [Các Khối](#blocks) 41 | 1. [Các Câu lệnh Điều khiển](#control-statements) 42 | 1. [Các Chú thích](#comments) 43 | 1. [Khoảng trắng](#whitespace) 44 | 1. [Các Dấu phẩy](#commas) 45 | 1. [Các Dấu chấm phẩy](#semicolons) 46 | 1. [Sự ép kiểu](#type-casting--coercion) 47 | 1. [Các Quy ước Đặt tên](#naming-conventions) 48 | 1. [Các Hàm truy cập](#accessors) 49 | 1. [Các Sự kiện](#events) 50 | 1. [jQuery](#jquery) 51 | 1. [Tính tương thích của ECMAScript 5](#ecmascript-5-compatibility) 52 | 1. [Lối viết ECMAScript 6+ (ES 2015+)](#ecmascript-6-es-2015-styles) 53 | 1. [Thư viện Tiêu chuẩn](#standard-library) 54 | 1. [Sự kiểm thử](#testing) 55 | 1. [Hiệu suất](#performance) 56 | 1. [Các Tài nguyên](#resources) 57 | 1. [Thực tế Áp dụng](#in-the-wild) 58 | 1. [Danh mục các Thuật ngữ](#terminology) 59 | 1. [Dịch](#translation) 60 | 1. [Về Hướng dẫn Lối viết JavaScript](#the-javascript-style-guide-guide) 61 | 1. [Nói chuyện với Chúng tôi về JavaScript](#chat-with-us-about-javascript) 62 | 1. [Những Người đóng góp](#contributors) 63 | 1. [Giấy phép](#license) 64 | 1. [Các Sửa đổi](#amendments) 65 | 66 | ## Các Kiểu giá trị 67 | 68 | 69 | - [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ó. 70 | 71 | - `string` 72 | - `number` 73 | - `boolean` 74 | - `null` 75 | - `undefined` 76 | - `symbol` 77 | - `bigint` 78 | 79 | ``` javascript 80 | const foo = 1; 81 | let bar = foo; 82 | 83 | bar = 9; 84 | 85 | console.log(foo, bar); // => 1, 9 86 | ``` 87 | 88 | - 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. 89 | 90 | 91 | - [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ó. 92 | 93 | - `object` 94 | - `array` 95 | - `function` 96 | 97 | ``` javascript 98 | const foo = [1, 2]; 99 | const bar = foo; 100 | 101 | bar[0] = 9; 102 | 103 | console.log(foo[0], bar[0]); // => 9, 9 104 | ``` 105 | 106 | **[⬆ về đầu trang](#table-of-contents)** 107 | 108 | ## Các Tham chiếu 109 | 110 | 111 | - [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) 112 | 113 | > 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. 114 | 115 | ``` javascript 116 | // không tốt 117 | var a = 1; 118 | var b = 2; 119 | 120 | // tốt 121 | const a = 1; 122 | const b = 2; 123 | ``` 124 | 125 | 126 | - [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) 127 | 128 | > 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`. 129 | 130 | ``` javascript 131 | // không tốt 132 | var count = 1; 133 | if (true) { 134 | count += 1; 135 | } 136 | 137 | // tốt, sử dụng let. 138 | let count = 1; 139 | if (true) { 140 | count += 1; 141 | } 142 | ``` 143 | 144 | 145 | - [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. 146 | 147 | ``` javascript 148 | // const và let chỉ tồn tại trong phạm vi khối tạo ra chúng. 149 | { 150 | let a = 1; 151 | const b = 1; 152 | var c = 1; 153 | } 154 | console.log(a); // ReferenceError 155 | console.log(b); // ReferenceError 156 | console.log(c); // In ra 1 157 | ``` 158 | 159 | 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. 160 | 161 | **[⬆ về đầu trang](#table-of-contents)** 162 | 163 | ## Các Đối tượng 164 | 165 | 166 | - [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) 167 | 168 | ``` javascript 169 | // không tốt 170 | const item = new Object(); 171 | 172 | // tốt 173 | const item = {}; 174 | ``` 175 | 176 | 177 | - [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. 178 | 179 | > 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ỗ. 180 | 181 | ``` javascript 182 | 183 | function getKey(k) { 184 | return `tên của thuộc tính là ${k}`; 185 | } 186 | 187 | // không tốt 188 | const obj = { 189 | id: 5, 190 | name: 'San Francisco', 191 | }; 192 | obj[getKey('enabled')] = true; 193 | 194 | // tốt 195 | const obj = { 196 | id: 5, 197 | name: 'San Francisco', 198 | [getKey('enabled')]: true, 199 | }; 200 | ``` 201 | 202 | 203 | - [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) 204 | 205 | ``` javascript 206 | // không tốt 207 | const atom = { 208 | value: 1, 209 | 210 | addValue: function (value) { 211 | return atom.value + value; 212 | }, 213 | }; 214 | 215 | // tốt 216 | const atom = { 217 | value: 1, 218 | 219 | addValue(value) { 220 | return atom.value + value; 221 | }, 222 | }; 223 | ``` 224 | 225 | 226 | - [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) 227 | 228 | > Tại sao? Nó ngắn gọn và súc tích. 229 | 230 | ``` javascript 231 | const lukeSkywalker = 'Luke Skywalker'; 232 | 233 | // không tốt 234 | const obj = { 235 | lukeSkywalker: lukeSkywalker, 236 | }; 237 | 238 | // tốt 239 | const obj = { 240 | lukeSkywalker, 241 | }; 242 | ``` 243 | 244 | 245 | - [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. 246 | 247 | > 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. 248 | 249 | ``` javascript 250 | const anakinSkywalker = 'Anakin Skywalker'; 251 | const lukeSkywalker = 'Luke Skywalker'; 252 | 253 | // không tốt 254 | const obj = { 255 | episodeOne: 1, 256 | twoJediWalkIntoACantina: 2, 257 | lukeSkywalker, 258 | episodeThree: 3, 259 | mayTheFourth: 4, 260 | anakinSkywalker, 261 | }; 262 | 263 | // tốt 264 | const obj = { 265 | lukeSkywalker, 266 | anakinSkywalker, 267 | episodeOne: 1, 268 | twoJediWalkIntoACantina: 2, 269 | episodeThree: 3, 270 | mayTheFourth: 4, 271 | }; 272 | ``` 273 | 274 | 275 | - [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) 276 | 277 | > 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. 278 | 279 | ``` javascript 280 | // không tốt 281 | const bad = { 282 | 'foo': 3, 283 | 'bar': 4, 284 | 'một-cái-tên': 5, 285 | }; 286 | 287 | // tốt 288 | const good = { 289 | foo: 3, 290 | bar: 4, 291 | 'một-cái-tên': 5, 292 | }; 293 | ``` 294 | 295 | 296 | - [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) 297 | 298 | > 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)`). 299 | 300 | ``` javascript 301 | // không tốt 302 | console.log(object.hasOwnProperty(key)); 303 | 304 | // tốt 305 | console.log(Object.prototype.hasOwnProperty.call(object, key)); 306 | 307 | // tốt nhất 308 | const has = Object.prototype.hasOwnProperty; // lưu tạm phương thức một lần, dùng cho cả mô-đun. 309 | console.log(has.call(object, key)); 310 | /* hoặc */ 311 | import has from 'has'; // https://www.npmjs.com/package/has 312 | console.log(has.call(object, key)); 313 | ``` 314 | 315 | 316 | - [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) 317 | 318 | ``` javascript 319 | // rất không tốt 320 | const original = { a: 1, b: 2 }; 321 | const copy = Object.assign(original, { c: 3 }); // cái này làm biến đổi `original` ಠ_ಠ 322 | delete copy.a; // cái này cũng vậy 323 | 324 | // không tốt 325 | const original = { a: 1, b: 2 }; 326 | const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 } 327 | 328 | // tốt 329 | const original = { a: 1, b: 2 }; 330 | const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 } 331 | 332 | const { a, ...noA } = copy; // noA => { b: 2, c: 3 } 333 | ``` 334 | 335 | **[⬆ về đầu trang](#table-of-contents)** 336 | 337 | ## Các Mảng 338 | 339 | 340 | - [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) 341 | 342 | ``` javascript 343 | // không tốt 344 | const items = new Array(); 345 | 346 | // tốt 347 | const items = []; 348 | ``` 349 | 350 | 351 | - [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. 352 | 353 | ``` javascript 354 | const someStack = []; 355 | 356 | // không tốt 357 | someStack[someStack.length] = 'abracadabra'; 358 | 359 | // tốt 360 | someStack.push('abracadabra'); 361 | ``` 362 | 363 | 364 | - [4.3](#es6-array-spreads) Sử dụng toán tử liệt kê `...` để sao nhanh một mảng. 365 | 366 | ``` javascript 367 | // không tốt 368 | const len = items.length; 369 | const itemsCopy = []; 370 | let i; 371 | 372 | for (i = 0; i < len; i += 1) { 373 | itemsCopy[i] = items[i]; 374 | } 375 | 376 | // tốt 377 | const itemsCopy = [...items]; 378 | ``` 379 | 380 | 381 | 382 | - [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). 383 | 384 | ``` javascript 385 | const foo = document.querySelectorAll('.foo'); 386 | 387 | // tốt 388 | const nodes = Array.from(foo); 389 | 390 | // tốt nhất 391 | const nodes = [...foo]; 392 | ``` 393 | 394 | 395 | - [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. 396 | 397 | ``` javascript 398 | const arrLike = { 0: 'foo', 1: 'bar', 2: 'baz', length: 3 }; 399 | 400 | // không tốt 401 | const arr = Array.prototype.slice.call(arrLike); 402 | 403 | // tốt 404 | const arr = Array.from(arrLike); 405 | ``` 406 | 407 | 408 | - [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. 409 | 410 | ``` javascript 411 | // không tốt 412 | const baz = [...foo].map(bar); 413 | 414 | // tốt 415 | const baz = Array.from(foo, bar); 416 | ``` 417 | 418 | 419 | - [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) 420 | 421 | ``` javascript 422 | // tốt 423 | [1, 2, 3].map((x) => { 424 | const y = x + 1; 425 | return x * y; 426 | }); 427 | 428 | // tốt 429 | [1, 2, 3].map((x) => x + 1); 430 | 431 | // 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 432 | [[0, 1], [2, 3], [4, 5]].reduce((acc, item, index) => { 433 | const flatten = acc.concat(item); 434 | }); 435 | 436 | // tốt 437 | [[0, 1], [2, 3], [4, 5]].reduce((acc, item, index) => { 438 | const flatten = acc.concat(item); 439 | return flatten; 440 | }); 441 | 442 | // không tốt 443 | inbox.filter((msg) => { 444 | const { subject, author } = msg; 445 | if (subject === 'Con chim nhại') { 446 | return author === 'Harper Lee'; 447 | } else { 448 | return false; 449 | } 450 | }); 451 | 452 | // tốt 453 | inbox.filter((msg) => { 454 | const { subject, author } = msg; 455 | if (subject === 'Con chim nhại') { 456 | return author === 'Harper Lee'; 457 | } 458 | 459 | return false; 460 | }); 461 | ``` 462 | 463 | 464 | - [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. 465 | 466 | ``` javascript 467 | // không tốt 468 | const arr = [ 469 | [0, 1], [2, 3], [4, 5], 470 | ]; 471 | 472 | const objectInArray = [{ 473 | id: 1, 474 | }, { 475 | id: 2, 476 | }]; 477 | 478 | const numberInArray = [ 479 | 1, 2, 480 | ]; 481 | 482 | // tốt 483 | const arr = [[0, 1], [2, 3], [4, 5]]; 484 | 485 | const objectInArray = [ 486 | { 487 | id: 1, 488 | }, 489 | { 490 | id: 2, 491 | }, 492 | ]; 493 | 494 | const numberInArray = [ 495 | 1, 496 | 2, 497 | ]; 498 | ``` 499 | 500 | **[⬆ về đầu trang](#table-of-contents)** 501 | 502 | ## Trích xuất 503 | 504 | 505 | - [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) 506 | 507 | > 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. 508 | 509 | ``` javascript 510 | // không tốt 511 | function getFullName(user) { 512 | const firstName = user.firstName; 513 | const lastName = user.lastName; 514 | 515 | return `${firstName} ${lastName}`; 516 | } 517 | 518 | // tốt 519 | function getFullName(user) { 520 | const { firstName, lastName } = user; 521 | return `${firstName} ${lastName}`; 522 | } 523 | 524 | // best 525 | function getFullName({ firstName, lastName }) { 526 | return `${firstName} ${lastName}`; 527 | } 528 | ``` 529 | 530 | 531 | - [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) 532 | 533 | ``` javascript 534 | const arr = [1, 2, 3, 4]; 535 | 536 | // không tốt 537 | const first = arr[0]; 538 | const second = arr[1]; 539 | 540 | // tốt 541 | const [first, second] = arr; 542 | ``` 543 | 544 | 545 | - [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. 546 | 547 | > 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 đó. 548 | 549 | ``` javascript 550 | // không tốt 551 | function processInput(input) { 552 | // khi một phép màu xảy ra 553 | return [left, right, top, bottom]; 554 | } 555 | 556 | // người gọi cần nghĩ về thứ tự của giá trị trả về 557 | const [left, __, top] = processInput(input); 558 | 559 | // tốt 560 | function processInput(input) { 561 | // khi một phép màu xảy ra 562 | return { left, right, top, bottom }; 563 | } 564 | 565 | // người gọi chỉ cần chọn giá trị mà họ muốn 566 | const { left, top } = processInput(input); 567 | ``` 568 | 569 | **[⬆ về đầu trang](#table-of-contents)** 570 | 571 | ## Các Chuỗi 572 | 573 | 574 | - [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) 575 | 576 | ``` javascript 577 | // không tốt 578 | const name = "Capt. Janeway"; 579 | 580 | // 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 581 | const name = `Capt. Janeway`; 582 | 583 | // tốt 584 | const name = 'Capt. Janeway'; 585 | ``` 586 | 587 | 588 | - [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. 589 | 590 | > 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. 591 | 592 | ``` javascript 593 | // không tốt 594 | const errorMessage = 'Đây là một lỗi rất dài mà được ném ra bởi \ 595 | 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 \ 596 | quan gì với thứ này, bạn sẽ vẫn chẳng đi đến đâu với \ 597 | đâu.'; 598 | 599 | // không tốt 600 | const errorMessage = 'Đây là một lỗi rất dài mà được ném ra bởi' + 601 | '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' + 602 | 'quan gì với thứ này, bạn sẽ vẫn chẳng đi đến đâu với' + 603 | 'đâu.'; 604 | 605 | // tốt 606 | 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.'; 607 | ``` 608 | 609 | 610 | - [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) 611 | 612 | > 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. 613 | 614 | ``` javascript 615 | // không tốt 616 | function sayHi(name) { 617 | return 'Bạn có khỏe không, ' + name + '?'; 618 | } 619 | 620 | // không tốt 621 | function sayHi(name) { 622 | return ['Bạn có khỏe không, ', name, '?'].join(); 623 | } 624 | 625 | // tốt 626 | function sayHi(name) { 627 | return `Bạn có khỏe không, ${name}?`; 628 | } 629 | ``` 630 | 631 | 632 | - [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) 633 | 634 | 635 | - [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) 636 | 637 | > 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. 638 | 639 | ``` javascript 640 | // không tốt 641 | const foo = '\'cái này\' \đư\ợc \"cho trong ngoặc\"'; 642 | 643 | // tốt 644 | const foo = '\'cái này\' được "cho trong ngoặc"'; 645 | const foo = `tên của tôi là '${name}'`; 646 | ``` 647 | 648 | **[⬆ về đầu trang](#table-of-contents)** 649 | 650 | ## Các Hàm 651 | 652 | 653 | - [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) 654 | 655 | > 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)) 656 | 657 | ``` javascript 658 | // không tốt 659 | function foo() { 660 | // ... 661 | } 662 | 663 | // không tốt 664 | const foo = function () { 665 | // ... 666 | }; 667 | 668 | // tốt 669 | // 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 670 | const short = function longUniqueMoreDescriptiveLexicalFoo() { 671 | // ... 672 | }; 673 | ``` 674 | 675 | 676 | - [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) 677 | 678 | > 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. 679 | 680 | ``` javascript 681 | // biểu thức hàm gọi tức thời 682 | (function () { 683 | console.log('Xin chào đến với thế giới. Hãy đi theo tôi.'); 684 | }()); 685 | ``` 686 | 687 | 688 | - [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) 689 | 690 | 691 | - [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. 692 | 693 | ``` javascript 694 | // không tốt 695 | if (currentUser) { 696 | function test() { 697 | console.log('Đừng!'); 698 | } 699 | } 700 | 701 | // tốt 702 | let test; 703 | if (currentUser) { 704 | test = () => { 705 | console.log('Tốt đó.'); 706 | }; 707 | } 708 | ``` 709 | 710 | 711 | - [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. 712 | 713 | ``` javascript 714 | // không tốt 715 | function foo(name, options, arguments) { 716 | // ... 717 | } 718 | 719 | // tốt 720 | function foo(name, options, args) { 721 | // ... 722 | } 723 | ``` 724 | 725 | 726 | - [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) 727 | 728 | > 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`. 729 | 730 | ``` javascript 731 | // không tốt 732 | function concatenateAll() { 733 | const args = Array.prototype.slice.call(arguments); 734 | return args.join(''); 735 | } 736 | 737 | // tốt 738 | function concatenateAll(...args) { 739 | return args.join(''); 740 | } 741 | ``` 742 | 743 | 744 | - [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. 745 | 746 | ``` javascript 747 | // rất tệ 748 | function handleThings(opts) { 749 | // Không! Chúng ta không nên biến đổi các đối số. 750 | // Cái tệ thứ hai: Nếu opts là kiểu sai, nó sẽ bị đổi thành một đối tượng. 751 | // Đó có thể là điều bạn muốn, nhưng nó thi thoảng gây ra lỗi. 752 | opts = opts || {}; 753 | // ... 754 | } 755 | 756 | // vẫn tệ 757 | function handleThings(opts) { 758 | if (opts === void 0) { 759 | opts = {}; 760 | } 761 | // ... 762 | } 763 | 764 | // tốt 765 | function handleThings(opts = {}) { 766 | // ... 767 | } 768 | ``` 769 | 770 | 771 | - [7.8](#functions--default-side-effects) Tránh gây ra hiệu ứng phụ với tham số mặc định. 772 | 773 | > Tại sao? Chúng khá là rối để có thể hình dung. 774 | 775 | ``` javascript 776 | var b = 1; 777 | // không tốt 778 | function count(a = b++) { 779 | console.log(a); 780 | } 781 | count(); // 1 782 | count(); // 2 783 | count(3); // 3 784 | count(); // 3 785 | ``` 786 | 787 | 788 | - [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) 789 | 790 | ``` javascript 791 | // không tốt 792 | function handleThings(opts = {}, name) { 793 | // ... 794 | } 795 | 796 | // tốt 797 | function handleThings(name, opts = {}) { 798 | // ... 799 | } 800 | ``` 801 | 802 | 803 | - [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) 804 | 805 | > 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. 806 | 807 | ``` javascript 808 | // không tốt 809 | var add = new Function('a', 'b', 'return a + b'); 810 | 811 | // vẫn là không tốt 812 | var subtract = Function('a', 'b', 'return a - b'); 813 | ``` 814 | 815 | 816 | - [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) 817 | 818 | > 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. 819 | 820 | ``` javascript 821 | // không tốt 822 | const f = function(){}; 823 | const g = function (){}; 824 | const h = function() {}; 825 | 826 | // tốt 827 | const x = function () {}; 828 | const y = function a() {}; 829 | ``` 830 | 831 | 832 | - [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) 833 | 834 | > 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. 835 | 836 | ``` javascript 837 | // không tốt 838 | function f1(obj) { 839 | obj.key = 1; 840 | } 841 | 842 | // tốt 843 | function f2(obj) { 844 | const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1; 845 | } 846 | ``` 847 | 848 | 849 | - [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) 850 | 851 | > 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. 852 | 853 | ``` javascript 854 | // không tốt 855 | function f1(a) { 856 | a = 1; 857 | // ... 858 | } 859 | 860 | function f2(a) { 861 | if (!a) { a = 1; } 862 | // ... 863 | } 864 | 865 | // tốt 866 | function f3(a) { 867 | const b = a || 1; 868 | // ... 869 | } 870 | 871 | function f4(a = 1) { 872 | // ... 873 | } 874 | ``` 875 | 876 | 877 | - [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) 878 | 879 | > 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`. 880 | 881 | ``` javascript 882 | // không tốt 883 | const x = [1, 2, 3, 4, 5]; 884 | console.log.apply(console, x); 885 | 886 | // tốt 887 | const x = [1, 2, 3, 4, 5]; 888 | console.log(...x); 889 | 890 | // không tốt 891 | new (Function.prototype.bind.apply(Date, [null, 2016, 8, 5])); 892 | 893 | // tốt 894 | new Date(...[2016, 8, 5]); 895 | ``` 896 | 897 | 898 | - [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) 899 | 900 | ``` javascript 901 | // không tốt 902 | function foo(bar, 903 | baz, 904 | quux) { 905 | // ... 906 | } 907 | 908 | // tốt 909 | function foo( 910 | bar, 911 | baz, 912 | quux, 913 | ) { 914 | // ... 915 | } 916 | 917 | // không tốt 918 | console.log(foo, 919 | bar, 920 | baz); 921 | 922 | // tốt 923 | console.log( 924 | foo, 925 | bar, 926 | baz, 927 | ); 928 | ``` 929 | 930 | **[⬆ về đầu trang](#table-of-contents)** 931 | 932 | ## Các Hàm mũi tên 933 | 934 | 935 | - [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) 936 | 937 | > 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. 938 | 939 | > 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. 940 | 941 | ``` javascript 942 | // không tốt 943 | [1, 2, 3].map(function (x) { 944 | const y = x + 1; 945 | return x * y; 946 | }); 947 | 948 | // tốt 949 | [1, 2, 3].map((x) => { 950 | const y = x + 1; 951 | return x * y; 952 | }); 953 | ``` 954 | 955 | 956 | - [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) 957 | 958 | > Tại sao? Cú pháp tiện lợi. Nó dễ đọc khi nhiều hàm nối chuỗi nhau. 959 | 960 | ``` javascript 961 | // không tốt 962 | [1, 2, 3].map((number) => { 963 | const nextNumber = number + 1; 964 | `Một chuỗi có chứa số ${nextNumber}.`; 965 | }); 966 | 967 | // tốt 968 | [1, 2, 3].map((number) => `Một chuỗi có chứa số ${number + 1}.`); 969 | 970 | // tốt 971 | [1, 2, 3].map((number) => { 972 | const nextNumber = number + 1; 973 | return `Một chuỗi có chứa số ${nextNumber}.`; 974 | }); 975 | 976 | // tốt 977 | [1, 2, 3].map((number, index) => ({ 978 | [index]: number, 979 | })); 980 | 981 | // Không dùng trả về ngầm định khi có hiệu ứng phụ 982 | function foo(callback) { 983 | const val = callback(); 984 | if (val === true) { 985 | // Thực hiện gì đó nếu hàm gọi lại trả về true 986 | } 987 | } 988 | 989 | let bool = false; 990 | 991 | // không tốt 992 | foo(() => bool = true); 993 | 994 | // tốt 995 | foo(() => { 996 | bool = true; 997 | }); 998 | ``` 999 | 1000 | 1001 | - [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. 1002 | 1003 | > 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. 1004 | 1005 | ``` javascript 1006 | // không tốt 1007 | ['get', 'post', 'put'].map((httpMethod) => Object.prototype.hasOwnProperty.call( 1008 | httpMagicObjectWithAVeryLongName, 1009 | httpMethod, 1010 | ) 1011 | ); 1012 | 1013 | // tốt 1014 | ['get', 'post', 'put'].map((httpMethod) => ( 1015 | Object.prototype.hasOwnProperty.call( 1016 | httpMagicObjectWithAVeryLongName, 1017 | httpMethod, 1018 | ) 1019 | )); 1020 | ``` 1021 | 1022 | 1023 | - [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) 1024 | 1025 | > Tại sao? Giảm thiểu sự khác biệt khi thêm và xóa các đối số. 1026 | 1027 | ``` javascript 1028 | // không tốt 1029 | [1, 2, 3].map(x => x * x); 1030 | 1031 | // tốt 1032 | [1, 2, 3].map((x) => x * x); 1033 | 1034 | // tốt 1035 | [1, 2, 3].map((number) => ( 1036 | `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!` 1037 | )); 1038 | 1039 | // không tốt 1040 | [1, 2, 3].map(x => { 1041 | const y = x + 1; 1042 | return x * y; 1043 | }); 1044 | 1045 | // tốt 1046 | [1, 2, 3].map((x) => { 1047 | const y = x + 1; 1048 | return x * y; 1049 | }); 1050 | ``` 1051 | 1052 | 1053 | - [8.5](#arrows--confusing) Tránh gây dễ nhầm lẫn giữa cú pháp hàm mũi tên (`=>`) với các toán tử so sánh (`<=`, `>=`). eslint: [`no-confusing-arrow`](https://eslint.org/docs/rules/no-confusing-arrow) 1054 | 1055 | ``` javascript 1056 | // không tốt 1057 | const itemHeight = (item) => item.height <= 256 ? item.largeSize : item.smallSize; 1058 | 1059 | // không tốt 1060 | const itemHeight = (item) => item.height >= 256 ? item.largeSize : item.smallSize; 1061 | 1062 | // tốt 1063 | const itemHeight = (item) => (item.height <= 256 ? item.largeSize : item.smallSize); 1064 | 1065 | // tốt 1066 | const itemHeight = (item) => { 1067 | const { height, largeSize, smallSize } = item; 1068 | return height <= 256 ? largeSize : smallSize; 1069 | }; 1070 | ``` 1071 | 1072 | 1073 | - [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) 1074 | 1075 | ``` javascript 1076 | // không tốt 1077 | (foo) => 1078 | bar; 1079 | 1080 | (foo) => 1081 | (bar); 1082 | 1083 | // tốt 1084 | (foo) => bar; 1085 | (foo) => (bar); 1086 | (foo) => ( 1087 | bar 1088 | ) 1089 | ``` 1090 | 1091 | **[⬆ về đầu trang](#table-of-contents)** 1092 | 1093 | ## Các Lớp và các Hàm tạo 1094 | 1095 | 1096 | - [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`. 1097 | 1098 | > Tại sao? Cú pháp `class` súc tích, dễ hiểu và dễ hình dung. 1099 | 1100 | ``` javascript 1101 | // không tốt 1102 | function Queue(contents = []) { 1103 | this.queue = [...contents]; 1104 | } 1105 | Queue.prototype.pop = function () { 1106 | const value = this.queue[0]; 1107 | this.queue.splice(0, 1); 1108 | return value; 1109 | }; 1110 | 1111 | // tốt 1112 | class Queue { 1113 | constructor(contents = []) { 1114 | this.queue = [...contents]; 1115 | } 1116 | pop() { 1117 | const value = this.queue[0]; 1118 | this.queue.splice(0, 1); 1119 | return value; 1120 | } 1121 | } 1122 | ``` 1123 | 1124 | 1125 | - [9.2](#constructors--extends) Sử dụng `extends` cho thừa kế. 1126 | 1127 | > 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`. 1128 | 1129 | ``` javascript 1130 | // không tốt 1131 | const inherits = require('inherits'); 1132 | function PeekableQueue(contents) { 1133 | Queue.apply(this, contents); 1134 | } 1135 | inherits(PeekableQueue, Queue); 1136 | PeekableQueue.prototype.peek = function () { 1137 | return this.queue[0]; 1138 | }; 1139 | 1140 | // tốt 1141 | class PeekableQueue extends Queue { 1142 | peek() { 1143 | return this.queue[0]; 1144 | } 1145 | } 1146 | ``` 1147 | 1148 | 1149 | - [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. 1150 | 1151 | ``` javascript 1152 | // không tốt 1153 | Jedi.prototype.jump = function () { 1154 | this.jumping = true; 1155 | return true; 1156 | }; 1157 | 1158 | Jedi.prototype.setHeight = function (height) { 1159 | this.height = height; 1160 | }; 1161 | 1162 | const luke = new Jedi(); 1163 | luke.jump(); // => true 1164 | luke.setHeight(20); // => undefined 1165 | 1166 | // tốt 1167 | class Jedi { 1168 | jump() { 1169 | this.jumping = true; 1170 | return this; 1171 | } 1172 | 1173 | setHeight(height) { 1174 | this.height = height; 1175 | return this; 1176 | } 1177 | } 1178 | 1179 | const luke = new Jedi(); 1180 | 1181 | luke.jump() 1182 | .setHeight(20); 1183 | ``` 1184 | 1185 | 1186 | - [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ụ. 1187 | 1188 | ``` javascript 1189 | class Jedi { 1190 | constructor(options = {}) { 1191 | this.name = options.name || 'vô danh'; 1192 | } 1193 | 1194 | getName() { 1195 | return this.name; 1196 | } 1197 | 1198 | toString() { 1199 | return `Jedi - ${this.getName()}`; 1200 | } 1201 | } 1202 | ``` 1203 | 1204 | 1205 | - [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) 1206 | 1207 | ``` javascript 1208 | // không tốt 1209 | class Jedi { 1210 | constructor() {} 1211 | 1212 | getName() { 1213 | return this.name; 1214 | } 1215 | } 1216 | 1217 | // không tốt 1218 | class Rey extends Jedi { 1219 | constructor(...args) { 1220 | super(...args); 1221 | } 1222 | } 1223 | 1224 | // tốt 1225 | class Rey extends Jedi { 1226 | constructor(...args) { 1227 | super(...args); 1228 | this.name = 'Rey'; 1229 | } 1230 | } 1231 | ``` 1232 | 1233 | 1234 | - [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) 1235 | 1236 | > 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. 1237 | 1238 | ``` javascript 1239 | // không tốt 1240 | class Foo { 1241 | bar() { return 1; } 1242 | bar() { return 2; } 1243 | } 1244 | 1245 | // tốt 1246 | class Foo { 1247 | bar() { return 1; } 1248 | } 1249 | 1250 | // tốt 1251 | class Foo { 1252 | bar() { return 2; } 1253 | } 1254 | ``` 1255 | 1256 | 1257 | - [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) 1258 | 1259 | ```javascript 1260 | // không tốt 1261 | class Foo { 1262 | bar() { 1263 | console.log('bar'); 1264 | } 1265 | } 1266 | 1267 | // tốt - this được sử dụng 1268 | class Foo { 1269 | bar() { 1270 | console.log(this.bar); 1271 | } 1272 | } 1273 | 1274 | // tốt - constructor là ngoại lệ 1275 | class Foo { 1276 | constructor() { 1277 | // ... 1278 | } 1279 | } 1280 | 1281 | // tốt - phương thức tĩnh không nên sử dụng this 1282 | class Foo { 1283 | static bar() { 1284 | console.log('bar'); 1285 | } 1286 | } 1287 | ``` 1288 | 1289 | **[⬆ về đầu trang](#table-of-contents)** 1290 | 1291 | ## Các Mô-đun 1292 | 1293 | 1294 | - [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. 1295 | 1296 | > Tại sao? Mô-đun là tương lai, hãy cùng sử dụng tương lai ngay lúc này. 1297 | 1298 | ``` javascript 1299 | // không tốt 1300 | const AirbnbStyleGuide = require('./AirbnbStyleGuide'); 1301 | module.exports = AirbnbStyleGuide.es6; 1302 | 1303 | // ok 1304 | import AirbnbStyleGuide from './AirbnbStyleGuide'; 1305 | export default AirbnbStyleGuide.es6; 1306 | 1307 | // best 1308 | import { es6 } from './AirbnbStyleGuide'; 1309 | export default es6; 1310 | ``` 1311 | 1312 | 1313 | - [10.2](#modules--no-wildcard) Không sử dụng ký tự đại diện để nhập. 1314 | 1315 | > Tại sao? Điều này đảm bảo bạn chỉ xuất mặc định một giá trị. 1316 | 1317 | ``` javascript 1318 | // không tốt 1319 | import * as AirbnbStyleGuide from './AirbnbStyleGuide'; 1320 | 1321 | // tốt 1322 | import AirbnbStyleGuide from './AirbnbStyleGuide'; 1323 | ``` 1324 | 1325 | 1326 | - [10.3](#modules--no-export-from-import) Và không xuất trực tiếp từ một lệnh nhập. 1327 | 1328 | > 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. 1329 | 1330 | ``` javascript 1331 | // không tốt 1332 | // tên tệp es6.js 1333 | export { es6 as default } from './AirbnbStyleGuide'; 1334 | 1335 | // tốt 1336 | // tên tệp es6.js 1337 | import { es6 } from './AirbnbStyleGuide'; 1338 | export default es6; 1339 | ``` 1340 | 1341 | 1342 | - [10.4](#modules--no-duplicate-imports) Chỉ nhập từ một đường dẫn ở chung một chỗ. 1343 | eslint: [`no-duplicate-imports`](https://eslint.org/docs/rules/no-duplicate-imports) 1344 | > 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. 1345 | 1346 | ``` javascript 1347 | // không tốt 1348 | import foo from 'foo'; 1349 | // … và nhập một vài thứ nữa … // 1350 | import { named1, named2 } from 'foo'; 1351 | 1352 | // tốt 1353 | import foo, { named1, named2 } from 'foo'; 1354 | 1355 | // tốt 1356 | import foo, { 1357 | named1, 1358 | named2, 1359 | } from 'foo'; 1360 | ``` 1361 | 1362 | 1363 | - [10.5](#modules--no-mutable-exports) Không xuất các ràng buộc có thể bị biến đổi. 1364 | eslint: [`import/no-mutable-exports`](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-mutable-exports.md) 1365 | > 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. 1366 | 1367 | ``` javascript 1368 | // không tốt 1369 | let foo = 3; 1370 | export { foo }; 1371 | 1372 | // tốt 1373 | const foo = 3; 1374 | export { foo }; 1375 | ``` 1376 | 1377 | 1378 | - [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. 1379 | eslint: [`import/prefer-default-export`](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/prefer-default-export.md) 1380 | > 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ì. 1381 | 1382 | ``` javascript 1383 | // không tốt 1384 | export function foo() {} 1385 | 1386 | // tốt 1387 | export default function foo() {} 1388 | ``` 1389 | 1390 | 1391 | - [10.7](#modules--imports-first) Đặt tất cả các lệnh `import` trên cùng. 1392 | eslint: [`import/first`](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/first.md) 1393 | > 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ó. 1394 | 1395 | ``` javascript 1396 | // không tốt 1397 | import foo from 'foo'; 1398 | foo.init(); 1399 | 1400 | import bar from 'bar'; 1401 | 1402 | // tốt 1403 | import foo from 'foo'; 1404 | import bar from 'bar'; 1405 | 1406 | foo.init(); 1407 | ``` 1408 | 1409 | 1410 | - [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) 1411 | 1412 | > 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. 1413 | 1414 | ``` javascript 1415 | // không tốt 1416 | import {longNameA, longNameB, longNameC, longNameD, longNameE} from 'path'; 1417 | 1418 | // tốt 1419 | import { 1420 | longNameA, 1421 | longNameB, 1422 | longNameC, 1423 | longNameD, 1424 | longNameE, 1425 | } from 'path'; 1426 | ``` 1427 | 1428 | 1429 | - [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. 1430 | eslint: [`import/no-webpack-loader-syntax`](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-webpack-loader-syntax.md) 1431 | > 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`. 1432 | 1433 | ``` javascript 1434 | // không tốt 1435 | import fooSass from 'css!sass!foo.scss'; 1436 | import barCss from 'style!css!bar.css'; 1437 | 1438 | // tốt 1439 | import fooSass from 'foo.scss'; 1440 | import barCss from 'bar.css'; 1441 | ``` 1442 | 1443 | 1444 | - [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) 1445 | > 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. 1446 | 1447 | ```javascript 1448 | // không tốt 1449 | import foo from './foo.js'; 1450 | import bar from './bar.jsx'; 1451 | import baz from './baz/index.jsx'; 1452 | // tốt 1453 | import foo from './foo'; 1454 | import bar from './bar'; 1455 | import baz from './baz'; 1456 | ``` 1457 | 1458 | **[⬆ về đầu trang](#table-of-contents)** 1459 | 1460 | ## Các Đối tượng duyệt và các Hàm sinh trị 1461 | 1462 | 1463 | - [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) 1464 | 1465 | > 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ụ. 1466 | 1467 | > 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. 1468 | 1469 | ``` javascript 1470 | const numbers = [1, 2, 3, 4, 5]; 1471 | 1472 | // không tốt 1473 | let sum = 0; 1474 | for (let num of numbers) { 1475 | sum += num; 1476 | } 1477 | sum === 15; 1478 | 1479 | // tốt 1480 | let sum = 0; 1481 | numbers.forEach((num) => { 1482 | sum += num; 1483 | }); 1484 | sum === 15; 1485 | 1486 | // tốt nhất, sử dụng hàm 1487 | const sum = numbers.reduce((total, num) => total + num, 0); 1488 | sum === 15; 1489 | 1490 | // không tốt 1491 | const increasedByOne = []; 1492 | for (let i = 0; i < numbers.length; i++) { 1493 | increasedByOne.push(numbers[i] + 1); 1494 | } 1495 | 1496 | // tốt 1497 | const increasedByOne = []; 1498 | numbers.forEach((num) => { 1499 | increasedByOne.push(num + 1); 1500 | }); 1501 | 1502 | // tốt nhất, vẫn là sử dụng hàm 1503 | const increasedByOne = numbers.map((num) => num + 1); 1504 | ``` 1505 | 1506 | 1507 | - [11.2](#generators--nope) Không sử dụng các hàm sinh trị `function*` vào thời điểm này. 1508 | 1509 | > Tại sao? Nó không thể được dịch mã sang ES5 một cách hoàn hảo. 1510 | 1511 | 1512 | - [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) 1513 | 1514 | > 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`. 1515 | 1516 | ``` javascript 1517 | // không tốt 1518 | function * foo() { 1519 | // ... 1520 | } 1521 | 1522 | // không tốt 1523 | const bar = function * () { 1524 | // ... 1525 | }; 1526 | 1527 | // không tốt 1528 | const baz = function *() { 1529 | // ... 1530 | }; 1531 | 1532 | // không tốt 1533 | const quux = function*() { 1534 | // ... 1535 | }; 1536 | 1537 | // không tốt 1538 | function*foo() { 1539 | // ... 1540 | } 1541 | 1542 | // không tốt 1543 | function *foo() { 1544 | // ... 1545 | } 1546 | 1547 | // rất tệ 1548 | function 1549 | * 1550 | foo() { 1551 | // ... 1552 | } 1553 | 1554 | // rất rất tệ 1555 | const wat = function 1556 | * 1557 | () { 1558 | // ... 1559 | }; 1560 | 1561 | // tốt 1562 | function* foo() { 1563 | // ... 1564 | } 1565 | 1566 | // tốt 1567 | const foo = function* () { 1568 | // ... 1569 | }; 1570 | ``` 1571 | 1572 | **[⬆ về đầu trang](#table-of-contents)** 1573 | 1574 | ## Các Thuộc tính 1575 | 1576 | 1577 | - [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) 1578 | 1579 | ``` javascript 1580 | const luke = { 1581 | jedi: true, 1582 | age: 28, 1583 | }; 1584 | 1585 | // không tốt 1586 | const isJedi = luke['jedi']; 1587 | 1588 | // tốt 1589 | const isJedi = luke.jedi; 1590 | ``` 1591 | 1592 | 1593 | - [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. 1594 | 1595 | ``` javascript 1596 | const luke = { 1597 | jedi: true, 1598 | age: 28, 1599 | }; 1600 | 1601 | function getProp(prop) { 1602 | return luke[prop]; 1603 | } 1604 | 1605 | const isJedi = getProp('jedi'); 1606 | ``` 1607 | 1608 | 1609 | - [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). 1610 | 1611 | ``` javascript 1612 | // không tốt 1613 | const binary = Math.pow(2, 10); 1614 | 1615 | // tốt 1616 | const binary = 2 ** 10; 1617 | ``` 1618 | 1619 | **[⬆ về đầu trang](#table-of-contents)** 1620 | 1621 | ## Các Biến 1622 | 1623 | 1624 | - [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) 1625 | 1626 | ``` javascript 1627 | // không tốt 1628 | superPower = new SuperPower(); 1629 | 1630 | // tốt 1631 | const superPower = new SuperPower(); 1632 | ``` 1633 | 1634 | 1635 | - [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) 1636 | 1637 | > 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. 1638 | 1639 | ``` javascript 1640 | // không tốt 1641 | const items = getItems(), 1642 | goSportsTeam = true, 1643 | dragonball = 'z'; 1644 | 1645 | // không tốt 1646 | // (so sánh với trên kia và thử tìm ra lỗi ở đây) 1647 | const items = getItems(), 1648 | goSportsTeam = true; 1649 | dragonball = 'z'; 1650 | 1651 | // tốt 1652 | const items = getItems(); 1653 | const goSportsTeam = true; 1654 | const dragonball = 'z'; 1655 | ``` 1656 | 1657 | 1658 | - [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`. 1659 | 1660 | > 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 đó. 1661 | 1662 | ``` javascript 1663 | // không tốt 1664 | let i, len, dragonball, 1665 | items = getItems(), 1666 | goSportsTeam = true; 1667 | 1668 | // không tốt 1669 | let i; 1670 | const items = getItems(); 1671 | let dragonball; 1672 | const goSportsTeam = true; 1673 | let len; 1674 | 1675 | // tốt 1676 | const goSportsTeam = true; 1677 | const items = getItems(); 1678 | let dragonball; 1679 | let i; 1680 | let length; 1681 | ``` 1682 | 1683 | 1684 | - [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ý. 1685 | 1686 | > Tại sao? `let` và `const` thuộc phạm vi khối, không phải phạm vi hàm. 1687 | 1688 | ``` javascript 1689 | // không tốt - phép gọi hàm không cần thiết 1690 | function checkName(hasName) { 1691 | const name = getName(); 1692 | 1693 | if (hasName === 'thí nghiệm') { 1694 | return false; 1695 | } 1696 | 1697 | if (name === 'thí nghiệm') { 1698 | this.setName(''); 1699 | return false; 1700 | } 1701 | 1702 | return name; 1703 | } 1704 | 1705 | // tốt 1706 | function checkName(hasName) { 1707 | if (hasName === 'thí nghiệm') { 1708 | return false; 1709 | } 1710 | 1711 | const name = getName(); 1712 | 1713 | if (name === 'thí nghiệm') { 1714 | this.setName(''); 1715 | return false; 1716 | } 1717 | 1718 | return name; 1719 | } 1720 | ``` 1721 | 1722 | 1723 | - [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) 1724 | 1725 | > 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. 1726 | 1727 | ``` javascript 1728 | // không tốt 1729 | (function example() { 1730 | // JavaScript diễn giải điều này như 1731 | // let a = ( b = ( c = 1 ) ); 1732 | // 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 1733 | // các biến toàn cục. 1734 | let a = b = c = 1; 1735 | }()); 1736 | 1737 | console.log(a); // ném ra ReferenceError 1738 | console.log(b); // 1 1739 | console.log(c); // 1 1740 | 1741 | // tốt 1742 | (function example() { 1743 | let a = 1; 1744 | let b = a; 1745 | let c = a; 1746 | }()); 1747 | 1748 | console.log(a); // ném ra ReferenceError 1749 | console.log(b); // ném ra ReferenceError 1750 | console.log(c); // ném ra ReferenceError 1751 | 1752 | // điều tương tự áp dụng với `const` 1753 | ``` 1754 | 1755 | 1756 | - [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) 1757 | 1758 | > 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. 1759 | 1760 | ``` javascript 1761 | // không tốt 1762 | 1763 | const array = [1, 2, 3]; 1764 | let num = 1; 1765 | num++; 1766 | --num; 1767 | 1768 | let sum = 0; 1769 | let truthyCount = 0; 1770 | for (let i = 0; i < array.length; i++) { 1771 | let value = array[i]; 1772 | sum += value; 1773 | if (value) { 1774 | truthyCount++; 1775 | } 1776 | } 1777 | 1778 | // tốt 1779 | 1780 | const array = [1, 2, 3]; 1781 | let num = 1; 1782 | num += 1; 1783 | num -= 1; 1784 | 1785 | const sum = array.reduce((a, b) => a + b, 0); 1786 | const truthyCount = array.filter(Boolean).length; 1787 | ``` 1788 | 1789 | 1790 | - [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). 1791 | 1792 | > 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. 1793 | 1794 | ``` javascript 1795 | // không tốt 1796 | const foo = 1797 | superLongLongLongLongLongLongLongLongFunctionName(); 1798 | 1799 | // không tốt 1800 | const foo 1801 | = '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'; 1802 | 1803 | // tốt 1804 | const foo = ( 1805 | superLongLongLongLongLongLongLongLongFunctionName() 1806 | ); 1807 | 1808 | // tốt 1809 | 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'; 1810 | ``` 1811 | 1812 | 1813 | - [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) 1814 | 1815 | > 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. 1816 | 1817 | ``` javascript 1818 | // không tốt 1819 | 1820 | var some_unused_var = 42; 1821 | 1822 | // Các biến chỉ-viết không được coi là đã được sử dụng. 1823 | var y = 10; 1824 | y = 5; 1825 | 1826 | // Một phép đọc để sửa chính nó không được coi là đã sử dụng. 1827 | var z = 0; 1828 | z = z + 1; 1829 | 1830 | // Đối số không được sử dụng. 1831 | function getX(x, y) { 1832 | return x; 1833 | } 1834 | 1835 | // tốt 1836 | 1837 | function getXPlusY(x, y) { 1838 | return x + y; 1839 | } 1840 | 1841 | var x = 1; 1842 | var y = a + 2; 1843 | 1844 | alert(getXPlusY(x, y)); 1845 | 1846 | // 'type' được bỏ qua kể cả khi nó không được sử dụng vì còn có 1847 | // các thuộc tính đồng đẳng còn-lại. 1848 | // Đâ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. 1849 | var { type, ...coords } = data; 1850 | // 'coords' bây giờ là 'data' đã loại bỏ thuộc tính 'type'. 1851 | ``` 1852 | 1853 | **[⬆ về đầu trang](#table-of-contents)** 1854 | 1855 | ## Sự kéo lên 1856 | 1857 | 1858 | - [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). 1859 | 1860 | ``` javascript 1861 | // chúng ta biết thứ này sẽ không hoạt động (giả định rằng 1862 | // không có biến toàn cục nào tên là notDefined) 1863 | function example() { 1864 | console.log(notDefined); // => ném ra ReferenceError 1865 | } 1866 | 1867 | // việc khai báo một biến sau khi bạn 1868 | // sử dụng biến đó vẫn sẽ chạy bởi vì 1869 | // sự nổi lên của biến. Lưu ý: phép gán 1870 | // giá trị `true` không được kéo lên. 1871 | function example() { 1872 | console.log(declaredButNotAssigned); // => undefined 1873 | var declaredButNotAssigned = true; 1874 | } 1875 | 1876 | // trình biên dịch sẽ kéo khai báo biến 1877 | // lên trên đầu của phạm vi hàm, 1878 | // điều này có nghĩa là ví dụ trên có thể được viết là: 1879 | function example() { 1880 | let declaredButNotAssigned; 1881 | console.log(declaredButNotAssigned); // => undefined 1882 | declaredButNotAssigned = true; 1883 | } 1884 | 1885 | // dùng const và let 1886 | function example() { 1887 | console.log(declaredButNotAssigned); // => ném ra ReferenceError 1888 | console.log(typeof declaredButNotAssigned); // => ném ra ReferenceError 1889 | const declaredButNotAssigned = true; 1890 | } 1891 | ``` 1892 | 1893 | 1894 | - [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. 1895 | 1896 | ``` javascript 1897 | function example() { 1898 | console.log(anonymous); // => undefined 1899 | 1900 | anonymous(); // => TypeError anonymous is not a function 1901 | 1902 | var anonymous = function () { 1903 | console.log('biểu thức hàm vô danh'); 1904 | }; 1905 | } 1906 | ``` 1907 | 1908 | 1909 | - [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. 1910 | 1911 | ``` javascript 1912 | function example() { 1913 | console.log(named); // => undefined 1914 | 1915 | named(); // => TypeError named is not a function 1916 | 1917 | superPower(); // => ReferenceError superPower is not defined 1918 | 1919 | var named = function superPower() { 1920 | console.log('Nhìn tui đang bay nè'); 1921 | }; 1922 | } 1923 | 1924 | // điều tương tự cũng đúng nếu 1925 | // tên hàm là trùng với tên biến. 1926 | function example() { 1927 | console.log(named); // => undefined 1928 | 1929 | named(); // => TypeError named is not a function 1930 | 1931 | var named = function named() { 1932 | console.log('named'); 1933 | }; 1934 | } 1935 | ``` 1936 | 1937 | 1938 | - [14.4](#hoisting--declarations) Khai báo hàm được kéo cả tên và thân hàm lên. 1939 | 1940 | ``` javascript 1941 | function example() { 1942 | superPower(); // => Nhìn tui đang bay nè 1943 | 1944 | function superPower() { 1945 | console.log('Nhìn tui đang bay nè'); 1946 | } 1947 | } 1948 | ``` 1949 | 1950 | - Để tìm hiểu thêm, tham khảo bài viết [JavaScript Scoping & Hoisting](http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting/) bởi [Ben Cherry](http://www.adequatelygood.com/). 1951 | 1952 | **[⬆ về đầu trang](#table-of-contents)** 1953 | 1954 | ## Các Toán tử So sánh và Sự bằng nhau 1955 | 1956 | 1957 | - [15.1](#comparison--eqeqeq) Sử dụng `===` và `!==` thay vì `==` và `!=`. eslint: [`eqeqeq`](https://eslint.org/docs/rules/eqeqeq.html) 1958 | 1959 | 1960 | - [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: 1961 | 1962 | - **Các đối tượng** tương đương với **true** 1963 | - **Undefined** tương đương với **false** 1964 | - **Null** tương đương với **false** 1965 | - **Các boolean** tương đương với **giá trị của boolean** 1966 | - **Các số** tương đương với **false** nếu là **+0, -0, hoặc NaN**, còn không sẽ là **true** 1967 | - **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** 1968 | 1969 | ``` javascript 1970 | if ([0] && []) { 1971 | // true 1972 | // một mảng (dù là mảng rỗng) là một đối tượng, 1973 | // mà đối tượng luôn tương đương với true 1974 | } 1975 | ``` 1976 | 1977 | 1978 | - [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ố. 1979 | 1980 | ``` javascript 1981 | // không tốt 1982 | if (isValid === true) { 1983 | // ... 1984 | } 1985 | 1986 | // tốt 1987 | if (isValid) { 1988 | // ... 1989 | } 1990 | 1991 | // không tốt 1992 | if (name) { 1993 | // ... 1994 | } 1995 | 1996 | // tốt 1997 | if (name !== '') { 1998 | // ... 1999 | } 2000 | 2001 | // không tốt 2002 | if (collection.length) { 2003 | // ... 2004 | } 2005 | 2006 | // tốt 2007 | if (collection.length > 0) { 2008 | // ... 2009 | } 2010 | ``` 2011 | 2012 | 2013 | - [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. 2014 | 2015 | 2016 | - [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) 2017 | 2018 | > 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ứ. 2019 | 2020 | ``` javascript 2021 | // không tốt 2022 | switch (foo) { 2023 | case 1: 2024 | let x = 1; 2025 | break; 2026 | case 2: 2027 | const y = 2; 2028 | break; 2029 | case 3: 2030 | function f() { 2031 | // ... 2032 | } 2033 | break; 2034 | default: 2035 | class C {} 2036 | } 2037 | 2038 | // tốt 2039 | switch (foo) { 2040 | case 1: { 2041 | let x = 1; 2042 | break; 2043 | } 2044 | case 2: { 2045 | const y = 2; 2046 | break; 2047 | } 2048 | case 3: { 2049 | function f() { 2050 | // ... 2051 | } 2052 | break; 2053 | } 2054 | case 4: 2055 | bar(); 2056 | break; 2057 | default: { 2058 | class C {} 2059 | } 2060 | } 2061 | ``` 2062 | 2063 | 2064 | - [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) 2065 | 2066 | ``` javascript 2067 | // không tốt 2068 | const foo = maybe1 > maybe2 2069 | ? "hi hi" 2070 | : value1 > value2 ? "hi hi" : null; 2071 | 2072 | // chia thành hai biểu thức ba ngôi riêng biệt 2073 | // là tốt nhất 2074 | const maybeNull = value1 > value2 ? 'hi hi' : null; 2075 | const foo = maybe1 > maybe2 ? 'hi hi' : maybeNull; 2076 | ``` 2077 | 2078 | 2079 | - [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) 2080 | 2081 | ``` javascript 2082 | // không tốt 2083 | const foo = a ? a : b; 2084 | const bar = c ? true : false; 2085 | const baz = c ? false : true; 2086 | 2087 | // tốt 2088 | const foo = a || b; 2089 | const bar = !!c; 2090 | const baz = !c; 2091 | ``` 2092 | 2093 | 2094 | - [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) 2095 | 2096 | > 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. 2097 | 2098 | ``` javascript 2099 | // không tốt 2100 | const foo = a && b < 0 || c > 0 || d + 1 === 0; 2101 | 2102 | // không tốt 2103 | const bar = a ** b - 5 % d; 2104 | 2105 | // không tốt 2106 | // ai đó có thể bị rối và nghĩ nó là (a || b) && c 2107 | if (a || b && c) { 2108 | return d; 2109 | } 2110 | 2111 | // không tốt 2112 | const bar = a + b / c * d; 2113 | 2114 | // tốt 2115 | const foo = (a && b < 0) || c > 0 || (d + 1 === 0); 2116 | 2117 | // tốt 2118 | const bar = a ** b - (5 % d); 2119 | 2120 | // tốt 2121 | if (a || (b && c)) { 2122 | return d; 2123 | } 2124 | 2125 | // tốt 2126 | const bar = a + (b / c) * d; 2127 | ``` 2128 | 2129 | **[⬆ về đầu trang](#table-of-contents)** 2130 | 2131 | ## Các Khối 2132 | 2133 | 2134 | - [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) 2135 | 2136 | ``` javascript 2137 | // không tốt 2138 | if (test) 2139 | return false; 2140 | 2141 | // tốt 2142 | if (test) return false; 2143 | 2144 | // tốt 2145 | if (test) { 2146 | return false; 2147 | } 2148 | 2149 | // không tốt 2150 | function foo() { return false; } 2151 | 2152 | // tốt 2153 | function bar() { 2154 | return false; 2155 | } 2156 | ``` 2157 | 2158 | 2159 | - [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) 2160 | 2161 | ``` javascript 2162 | // không tốt 2163 | if (test) { 2164 | thing1(); 2165 | thing2(); 2166 | } 2167 | else { 2168 | thing3(); 2169 | } 2170 | 2171 | // tốt 2172 | if (test) { 2173 | thing1(); 2174 | thing2(); 2175 | } else { 2176 | thing3(); 2177 | } 2178 | ``` 2179 | 2180 | 2181 | - [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) 2182 | 2183 | ``` javascript 2184 | // không tốt 2185 | function foo() { 2186 | if (x) { 2187 | return x; 2188 | } else { 2189 | return y; 2190 | } 2191 | } 2192 | 2193 | // không tốt 2194 | function cats() { 2195 | if (x) { 2196 | return x; 2197 | } else if (y) { 2198 | return y; 2199 | } 2200 | } 2201 | 2202 | // không tốt 2203 | function dogs() { 2204 | if (x) { 2205 | return x; 2206 | } else { 2207 | if (y) { 2208 | return y; 2209 | } 2210 | } 2211 | } 2212 | 2213 | // tốt 2214 | function foo() { 2215 | if (x) { 2216 | return x; 2217 | } 2218 | 2219 | return y; 2220 | } 2221 | 2222 | // tốt 2223 | function cats() { 2224 | if (x) { 2225 | return x; 2226 | } 2227 | 2228 | if (y) { 2229 | return y; 2230 | } 2231 | } 2232 | 2233 | // tốt 2234 | function dogs(x) { 2235 | if (x) { 2236 | if (z) { 2237 | return y; 2238 | } 2239 | } else { 2240 | return z; 2241 | } 2242 | } 2243 | ``` 2244 | 2245 | **[⬆ về đầu trang](#table-of-contents)** 2246 | 2247 | ## Các Câu lệnh Điều khiển 2248 | 2249 | 2250 | - [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. 2251 | 2252 | > 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. 2253 | 2254 | ``` javascript 2255 | // không tốt 2256 | if ((foo === 123 || bar === 'abc') && doesItLookGoodWhenItBecomesThatLong() && isThisReallyHappening()) { 2257 | thing1(); 2258 | } 2259 | 2260 | // không tốt 2261 | if (foo === 123 && 2262 | bar === 'abc') { 2263 | thing1(); 2264 | } 2265 | 2266 | // không tốt 2267 | if (foo === 123 2268 | && bar === 'abc') { 2269 | thing1(); 2270 | } 2271 | 2272 | // không tốt 2273 | if ( 2274 | foo === 123 && 2275 | bar === 'abc' 2276 | ) { 2277 | thing1(); 2278 | } 2279 | 2280 | // tốt 2281 | if ( 2282 | foo === 123 2283 | && bar === 'abc' 2284 | ) { 2285 | thing1(); 2286 | } 2287 | 2288 | // tốt 2289 | if ( 2290 | (foo === 123 || bar === 'abc') 2291 | && doesItLookGoodWhenItBecomesThatLong() 2292 | && isThisReallyHappening() 2293 | ) { 2294 | thing1(); 2295 | } 2296 | 2297 | // tốt 2298 | if (foo === 123 && bar === 'abc') { 2299 | thing1(); 2300 | } 2301 | ``` 2302 | 2303 | 2304 | - [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. 2305 | 2306 | ``` javascript 2307 | // không tốt 2308 | !isRunning && startRunning(); 2309 | 2310 | // tốt 2311 | if (!isRunning) { 2312 | startRunning(); 2313 | } 2314 | ``` 2315 | 2316 | **[⬆ về đầu trang](#table-of-contents)** 2317 | 2318 | ## Các Chú thích 2319 | 2320 | 2321 | - [18.1](#comments--multiline) Sử dụng `/** ... */` cho các chú thích nhiều dòng. 2322 | 2323 | ``` javascript 2324 | // không tốt 2325 | // make() trả về một phần tử 2326 | // dựa trên tag được truyền vào 2327 | // 2328 | // @param {String} tag 2329 | // @return {Element} element 2330 | function make(tag) { 2331 | 2332 | // ... 2333 | 2334 | return element; 2335 | } 2336 | 2337 | // tốt 2338 | /** 2339 | * make() trả về một phần tử 2340 | * dựa trên tag được truyền vào 2341 | */ 2342 | function make(tag) { 2343 | 2344 | // ... 2345 | 2346 | return element; 2347 | } 2348 | ``` 2349 | 2350 | 2351 | - [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. 2352 | 2353 | ``` javascript 2354 | // không tốt 2355 | const active = true; // là thẻ hiện tại 2356 | 2357 | // tốt 2358 | // là thẻ hiện tại 2359 | const active = true; 2360 | 2361 | // không tốt 2362 | function getType() { 2363 | console.log('đang lấy loại...'); 2364 | // đặt loại mặc định là 'không phân loại' 2365 | const type = this.type || 'không phân loại'; 2366 | 2367 | return type; 2368 | } 2369 | 2370 | // tốt 2371 | function getType() { 2372 | console.log('đang lấy loại...'); 2373 | 2374 | // đặt loại mặc định là 'không phân loại' 2375 | const type = this.type || 'không phân loại'; 2376 | 2377 | return type; 2378 | } 2379 | 2380 | // như này cũng tốt 2381 | function getType() { 2382 | // đặt loại mặc định là 'không phân loại' 2383 | const type = this.type || 'không phân loại'; 2384 | 2385 | return type; 2386 | } 2387 | ``` 2388 | 2389 | 2390 | - [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) 2391 | 2392 | ``` javascript 2393 | // không tốt 2394 | //là thẻ hiện tại 2395 | const active = true; 2396 | 2397 | // tốt 2398 | // là thẻ hiện tại 2399 | const active = true; 2400 | 2401 | // không tốt 2402 | /** 2403 | *make() trả về một phần tử 2404 | *dựa trên tag được truyền vào 2405 | */ 2406 | function make(tag) { 2407 | 2408 | // ... 2409 | 2410 | return element; 2411 | } 2412 | 2413 | // tốt 2414 | /** 2415 | * make() trả về một phần tử 2416 | * dựa trên tag được truyền vào 2417 | */ 2418 | function make(tag) { 2419 | 2420 | // ... 2421 | 2422 | return element; 2423 | } 2424 | ``` 2425 | 2426 | 2427 | - [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`. 2428 | 2429 | 2430 | - [18.5](#comments--fixme) Sử dụng `// FIXME:` để chú giải các vấn đề. 2431 | 2432 | ``` javascript 2433 | class Calculator extends Abacus { 2434 | constructor() { 2435 | super(); 2436 | 2437 | // FIXME: không nên dùng biến toàn cục ở đây 2438 | total = 0; 2439 | } 2440 | } 2441 | ``` 2442 | 2443 | 2444 | - [18.6](#comments--todo) Sử dụng `// TODO:` để chú giải các cách giải quyết cho các vấn đề. 2445 | 2446 | ``` javascript 2447 | class Calculator extends Abacus { 2448 | constructor() { 2449 | super(); 2450 | 2451 | // TODO: giá trị của total nên được chuyển thành tham số 2452 | this.total = 0; 2453 | } 2454 | } 2455 | ``` 2456 | 2457 | **[⬆ về đầu trang](#table-of-contents)** 2458 | 2459 | ## Khoảng trắng 2460 | 2461 | 2462 | - [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) 2463 | 2464 | ``` javascript 2465 | // không tốt 2466 | function foo() { 2467 | ∙∙∙∙let name; 2468 | } 2469 | 2470 | // không tốt 2471 | function bar() { 2472 | ∙let name; 2473 | } 2474 | 2475 | // tốt 2476 | function baz() { 2477 | ∙∙let name; 2478 | } 2479 | ``` 2480 | 2481 | 2482 | - [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) 2483 | 2484 | ``` javascript 2485 | // không tốt 2486 | function test(){ 2487 | console.log('ví dụ'); 2488 | } 2489 | 2490 | // tốt 2491 | function test() { 2492 | console.log('ví dụ'); 2493 | } 2494 | 2495 | // không tốt 2496 | dog.set('attr',{ 2497 | age: '1 năm', 2498 | breed: 'Chó núi Bern', 2499 | }); 2500 | 2501 | // tốt 2502 | dog.set('attr', { 2503 | age: '1 năm', 2504 | breed: 'Chó núi Bern', 2505 | }); 2506 | ``` 2507 | 2508 | 2509 | - [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) 2510 | 2511 | ``` javascript 2512 | // không tốt 2513 | if(isJedi) { 2514 | fight (); 2515 | } 2516 | 2517 | // tốt 2518 | if (isJedi) { 2519 | fight(); 2520 | } 2521 | 2522 | // không tốt 2523 | function fight () { 2524 | console.log ('Uiiiiii!'); 2525 | } 2526 | 2527 | // tốt 2528 | function fight() { 2529 | console.log('Uiiiiii!'); 2530 | } 2531 | ``` 2532 | 2533 | 2534 | - [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) 2535 | 2536 | ``` javascript 2537 | // không tốt 2538 | const x=y+5; 2539 | 2540 | // tốt 2541 | const x = y + 5; 2542 | ``` 2543 | 2544 | 2545 | - [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) 2546 | 2547 | ``` javascript 2548 | // không tốt 2549 | import { es6 } from './AirbnbStyleGuide'; 2550 | // ... 2551 | export default es6; 2552 | ``` 2553 | 2554 | ``` javascript 2555 | // không tốt 2556 | import { es6 } from './AirbnbStyleGuide'; 2557 | // ... 2558 | export default es6;↵ 2559 | ↵ 2560 | ``` 2561 | 2562 | ``` javascript 2563 | // tốt 2564 | import { es6 } from './AirbnbStyleGuide'; 2565 | // ... 2566 | export default es6;↵ 2567 | ``` 2568 | 2569 | 2570 | - [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) 2571 | 2572 | ``` javascript 2573 | // không tốt 2574 | $('#items').find('.selected').highlight().end().find('.open').updateCount(); 2575 | 2576 | // không tốt 2577 | $('#items'). 2578 | find('.selected'). 2579 | highlight(). 2580 | end(). 2581 | find('.open'). 2582 | updateCount(); 2583 | 2584 | // tốt 2585 | $('#items') 2586 | .find('.selected') 2587 | .highlight() 2588 | .end() 2589 | .find('.open') 2590 | .updateCount(); 2591 | 2592 | // không tốt 2593 | const leds = stage.selectAll('.led').data(data).enter().append('svg:svg').classed('led', true) 2594 | .attr('width', (radius + margin) * 2).append('svg:g') 2595 | .attr('transform', `translate(${radius + margin},${radius + margin})`) 2596 | .call(tron.led); 2597 | 2598 | // tốt 2599 | const leds = stage.selectAll('.led') 2600 | .data(data) 2601 | .enter().append('svg:svg') 2602 | .classed('led', true) 2603 | .attr('width', (radius + margin) * 2) 2604 | .append('svg:g') 2605 | .attr('transform', `translate(${radius + margin},${radius + margin})`) 2606 | .call(tron.led); 2607 | 2608 | // tốt 2609 | const leds = stage.selectAll('.led').data(data); 2610 | const svg = leds.enter().append('svg:svg'); 2611 | svg.classed('led', true).attr('width', (radius + margin) * 2); 2612 | const g = svg.append('svg:g'); 2613 | g.attr('transform', `translate(${radius + margin},${radius + margin})`).call(tron.led); 2614 | ``` 2615 | 2616 | 2617 | - [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. 2618 | 2619 | ``` javascript 2620 | // không tốt 2621 | if (foo) { 2622 | return bar; 2623 | } 2624 | return baz; 2625 | 2626 | // tốt 2627 | if (foo) { 2628 | return bar; 2629 | } 2630 | 2631 | return baz; 2632 | 2633 | // không tốt 2634 | const obj = { 2635 | foo() { 2636 | }, 2637 | bar() { 2638 | }, 2639 | }; 2640 | return obj; 2641 | 2642 | // tốt 2643 | const obj = { 2644 | foo() { 2645 | }, 2646 | 2647 | bar() { 2648 | }, 2649 | }; 2650 | 2651 | return obj; 2652 | 2653 | // không tốt 2654 | const arr = [ 2655 | function foo() { 2656 | }, 2657 | function bar() { 2658 | }, 2659 | ]; 2660 | return arr; 2661 | 2662 | // tốt 2663 | const arr = [ 2664 | function foo() { 2665 | }, 2666 | 2667 | function bar() { 2668 | }, 2669 | ]; 2670 | 2671 | return arr; 2672 | ``` 2673 | 2674 | 2675 | - [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) 2676 | 2677 | ``` javascript 2678 | // không tốt 2679 | function bar() { 2680 | 2681 | console.log(foo); 2682 | 2683 | } 2684 | 2685 | // không tốt 2686 | if (baz) { 2687 | 2688 | console.log(qux); 2689 | } else { 2690 | console.log(foo); 2691 | 2692 | } 2693 | 2694 | // không tốt 2695 | class Foo { 2696 | 2697 | constructor(bar) { 2698 | this.bar = bar; 2699 | } 2700 | } 2701 | 2702 | // tốt 2703 | function bar() { 2704 | console.log(foo); 2705 | } 2706 | 2707 | // tốt 2708 | if (baz) { 2709 | console.log(qux); 2710 | } else { 2711 | console.log(foo); 2712 | } 2713 | ``` 2714 | 2715 | 2716 | - [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) 2717 | 2718 | 2719 | ``` javascript 2720 | // không tốt 2721 | class Person { 2722 | constructor(fullName, email, birthday) { 2723 | this.fullName = fullName; 2724 | 2725 | 2726 | this.email = email; 2727 | 2728 | 2729 | this.setAge(birthday); 2730 | } 2731 | 2732 | 2733 | setAge(birthday) { 2734 | const today = new Date(); 2735 | 2736 | 2737 | const age = this.getAge(today, birthday); 2738 | 2739 | 2740 | this.age = age; 2741 | } 2742 | 2743 | 2744 | getAge(today, birthday) { 2745 | // .. 2746 | } 2747 | } 2748 | 2749 | // tốt 2750 | class Person { 2751 | constructor(fullName, email, birthday) { 2752 | this.fullName = fullName; 2753 | this.email = email; 2754 | this.setAge(birthday); 2755 | } 2756 | 2757 | setAge(birthday) { 2758 | const today = new Date(); 2759 | const age = getAge(today, birthday); 2760 | this.age = age; 2761 | } 2762 | 2763 | getAge(today, birthday) { 2764 | // .. 2765 | } 2766 | } 2767 | ``` 2768 | 2769 | 2770 | - [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) 2771 | 2772 | ``` javascript 2773 | // không tốt 2774 | function bar( foo ) { 2775 | return foo; 2776 | } 2777 | 2778 | // tốt 2779 | function bar(foo) { 2780 | return foo; 2781 | } 2782 | 2783 | // không tốt 2784 | if ( foo ) { 2785 | console.log(foo); 2786 | } 2787 | 2788 | // tốt 2789 | if (foo) { 2790 | console.log(foo); 2791 | } 2792 | ``` 2793 | 2794 | 2795 | - [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) 2796 | 2797 | ``` javascript 2798 | // không tốt 2799 | const foo = [ 1, 2, 3 ]; 2800 | console.log(foo[ 0 ]); 2801 | 2802 | // tốt 2803 | const foo = [1, 2, 3]; 2804 | console.log(foo[0]); 2805 | ``` 2806 | 2807 | 2808 | - [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) 2809 | 2810 | ``` javascript 2811 | // không tốt 2812 | const foo = {clark: 'kent'}; 2813 | 2814 | // tốt 2815 | const foo = { clark: 'kent' }; 2816 | ``` 2817 | 2818 | 2819 | - [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) 2820 | 2821 | > Tại sao? Điều này đảm bảo tính khả đọc và khả năng bảo trì. 2822 | 2823 | ``` javascript 2824 | // không tốt 2825 | const foo = jsonData && jsonData.foo && jsonData.foo.bar && jsonData.foo.bar.baz && jsonData.foo.bar.baz.quux && jsonData.foo.bar.baz.quux.xyzzy; 2826 | 2827 | // không tốt 2828 | $.ajax({ method: 'POST', url: 'https://airbnb.com/', data: { name: 'John' } }).done(() => console.log('Chúc mừng!')).fail(() => console.log('You have failed this city.')); 2829 | 2830 | // tốt 2831 | const foo = jsonData 2832 | && jsonData.foo 2833 | && jsonData.foo.bar 2834 | && jsonData.foo.bar.baz 2835 | && jsonData.foo.bar.baz.quux 2836 | && jsonData.foo.bar.baz.quux.xyzzy; 2837 | 2838 | // tốt 2839 | $.ajax({ 2840 | method: 'POST', 2841 | url: 'https://airbnb.com/', 2842 | data: { name: 'John' }, 2843 | }) 2844 | .done(() => console.log('Chúc mừng!')) 2845 | .fail(() => console.log('You have failed this city.')); 2846 | ``` 2847 | 2848 | 2849 | - [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) 2850 | 2851 | ``` javascript 2852 | // không tốt 2853 | function foo() {return true;} 2854 | if (foo) { bar = 0;} 2855 | 2856 | // tốt 2857 | function foo() { return true; } 2858 | if (foo) { bar = 0; } 2859 | ``` 2860 | 2861 | 2862 | - [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) 2863 | 2864 | ``` javascript 2865 | // không tốt 2866 | var foo = 1,bar = 2; 2867 | var arr = [1 , 2]; 2868 | 2869 | // tốt 2870 | var foo = 1, bar = 2; 2871 | var arr = [1, 2]; 2872 | ``` 2873 | 2874 | 2875 | - [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) 2876 | 2877 | ``` javascript 2878 | // không tốt 2879 | obj[foo ] 2880 | obj[ 'foo'] 2881 | var x = {[ b ]: a} 2882 | obj[foo[ bar ]] 2883 | 2884 | // tốt 2885 | obj[foo] 2886 | obj['foo'] 2887 | var x = { [b]: a } 2888 | obj[foo[bar]] 2889 | ``` 2890 | 2891 | 2892 | - [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) 2893 | 2894 | ``` javascript 2895 | // không tốt 2896 | func (); 2897 | 2898 | func 2899 | (); 2900 | 2901 | // tốt 2902 | func(); 2903 | ``` 2904 | 2905 | 2906 | - [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) 2907 | 2908 | ``` javascript 2909 | // không tốt 2910 | var obj = { foo : 42 }; 2911 | var obj2 = { foo:42 }; 2912 | 2913 | // tốt 2914 | var obj = { foo: 42 }; 2915 | ``` 2916 | 2917 | 2918 | - [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) 2919 | 2920 | 2921 | - [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) 2922 | 2923 | 2924 | ``` javascript 2925 | // không tốt - nhiều dòng trống liên tiếp 2926 | var x = 1; 2927 | 2928 | 2929 | var y = 2; 2930 | 2931 | // bad - 2+ dòng trống ở cuối tệp 2932 | var x = 1; 2933 | var y = 2; 2934 | 2935 | 2936 | // không tốt - 1+ dòng trống ở đầu tệp 2937 | 2938 | var x = 1; 2939 | var y = 2; 2940 | 2941 | // tốt 2942 | var x = 1; 2943 | var y = 2; 2944 | 2945 | ``` 2946 | 2947 | 2948 | **[⬆ về đầu trang](#table-of-contents)** 2949 | 2950 | ## Các Dấu phẩy 2951 | 2952 | 2953 | - [20.1](#commas--leading-trailing) Các dấu phẩy ở đầu: **Đừng!** eslint: [`comma-style`](https://eslint.org/docs/rules/comma-style.html) 2954 | 2955 | ``` javascript 2956 | // không tốt 2957 | const story = [ 2958 | once 2959 | , upon 2960 | , aTime 2961 | ]; 2962 | 2963 | // tốt 2964 | const story = [ 2965 | once, 2966 | upon, 2967 | aTime, 2968 | ]; 2969 | 2970 | // không tốt 2971 | const hero = { 2972 | firstName: 'Ada' 2973 | , lastName: 'Lovelace' 2974 | , birthYear: 1815 2975 | , superPower: 'máy tính' 2976 | }; 2977 | 2978 | // tốt 2979 | const hero = { 2980 | firstName: 'Ada', 2981 | lastName: 'Lovelace', 2982 | birthYear: 1815, 2983 | superPower: 'máy tính', 2984 | }; 2985 | ``` 2986 | 2987 | 2988 | - [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) 2989 | 2990 | > 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ũ. 2991 | 2992 | ```diff 2993 | // không tốt - so sánh git khi không có dấu phẩy ở cuối 2994 | const hero = { 2995 | firstName: 'Florence', 2996 | - lastName: 'Nightingale' 2997 | + lastName: 'Nightingale', 2998 | + inventorOf: ['coxcomb chart', 'modern nursing'] 2999 | }; 3000 | 3001 | // tốt - so sánh git khi có các dấu phẩy ở cuối 3002 | const hero = { 3003 | firstName: 'Florence', 3004 | lastName: 'Nightingale', 3005 | + inventorOf: ['coxcomb chart', 'modern nursing'], 3006 | }; 3007 | ``` 3008 | 3009 | ``` javascript 3010 | // không tốt 3011 | const hero = { 3012 | firstName: 'Dana', 3013 | lastName: 'Scully' 3014 | }; 3015 | 3016 | const heroes = [ 3017 | 'Batman', 3018 | 'Superman' 3019 | ]; 3020 | 3021 | // tốt 3022 | const hero = { 3023 | firstName: 'Dana', 3024 | lastName: 'Scully', 3025 | }; 3026 | 3027 | const heroes = [ 3028 | 'Batman', 3029 | 'Superman', 3030 | ]; 3031 | 3032 | // không tốt 3033 | function createHero( 3034 | firstName, 3035 | lastName, 3036 | inventorOf 3037 | ) { 3038 | // không làm gì cả 3039 | } 3040 | 3041 | // tốt 3042 | function createHero( 3043 | firstName, 3044 | lastName, 3045 | inventorOf, 3046 | ) { 3047 | // không làm gì cả 3048 | } 3049 | 3050 | // tốt (lưu ý là không được đặt dấu phẩy sau phần từ "còn-lại") 3051 | function createHero( 3052 | firstName, 3053 | lastName, 3054 | inventorOf, 3055 | ...heroArgs 3056 | ) { 3057 | // không làm gì cả 3058 | } 3059 | 3060 | // không tốt 3061 | createHero( 3062 | firstName, 3063 | lastName, 3064 | inventorOf 3065 | ); 3066 | 3067 | // tốt 3068 | createHero( 3069 | firstName, 3070 | lastName, 3071 | inventorOf, 3072 | ); 3073 | 3074 | // tốt (lưu ý là không được đặt dấu phẩy sau phần từ "còn-lại") 3075 | createHero( 3076 | firstName, 3077 | lastName, 3078 | inventorOf, 3079 | ...heroArgs 3080 | ); 3081 | ``` 3082 | 3083 | **[⬆ về đầu trang](#table-of-contents)** 3084 | 3085 | ## Các Dấu chấm phẩy 3086 | 3087 | 3088 | - [21.1](#semicolons--required) **Dĩ nhiên.** eslint: [`semi`](https://eslint.org/docs/rules/semi.html) 3089 | 3090 | > Tại sao? Khi JavaScript gặp một dấu ngắt dòng mà không có dấu chấm phẩy, nó sử dụng một bộ quy tắc gọi là [Quy tắc thêm dấu chấm phẩy tự động](https://tc39.github.io/ecma262/#sec-automatic-semicolon-insertion) để xác định xem dấu ngắt dòng có phải là kết thúc của một câu lệnh hay không, và (như cái tên gợi ý) đặt một dấu chấn phẩy vào mã của bạn, trước dấu ngắt dòng, nếu nó cho rằng nên làm vậy. Quy tắc thêm dấu chấm phẩy tự động có một vài hành vi lập dị, và mã của bạn sẽ hỏng nếu JavaScript hiểu sai dấu ngắt dòng của bạn. Những quy tắc này ngày càng trở nên phức tạp khi các tính năng mới được bổ sung vào JavaScript. Việc kết thúc các câu lệnh một cách rõ ràng và thiết lập trình phân tích mã của bạn bắt các lỗi thiếu dấu phẩy sẽ giúp bạn tránh được các vấn đề. 3091 | 3092 | ``` javascript 3093 | // không tốt - ném ra một ngoại lệ 3094 | const luke = {} 3095 | const leia = {} 3096 | [luke, leia].forEach((jedi) => jedi.father = 'vader') 3097 | 3098 | // không tốt - ngém ra một ngoại lệ 3099 | const reaction = "Không! Không thể nào!" 3100 | (async function meanwhileOnTheFalcon() { 3101 | // xử lý `leia`, `lando`, `chewie`, `r2`, `c3p0` 3102 | // ... 3103 | }()) 3104 | 3105 | // không tốt - trả về `undefined` thay vì giá trị ở dòng tiếp theo - điều luôn xảy ra khi `return` nằm một mình một dòng, do Quy tắc thêm dấu chấm phẩy tự động! 3106 | function foo() { 3107 | return 3108 | 'search your feelings, you know it to be foo' 3109 | } 3110 | 3111 | // tốt 3112 | const luke = {}; 3113 | const leia = {}; 3114 | [luke, leia].forEach((jedi) => { 3115 | jedi.father = 'vader'; 3116 | }); 3117 | 3118 | // tốt 3119 | const reaction = "Không! Không thể nào!"; 3120 | (async function meanwhileOnTheFalcon() { 3121 | // xử lý `leia`, `lando`, `chewie`, `r2`, `c3p0` 3122 | // ... 3123 | }()); 3124 | 3125 | // tốt 3126 | function foo() { 3127 | return 'search your feelings, you know it to be foo'; 3128 | } 3129 | ``` 3130 | 3131 | [Đọc thêm](https://stackoverflow.com/questions/7365172/semicolon-before-self-invoking-function/7365214#7365214). 3132 | 3133 | **[⬆ về đầu trang](#table-of-contents)** 3134 | 3135 | ## Sự ép kiểu 3136 | 3137 | 3138 | - [22.1](#coercion--explicit) Thực hiện ép kiểu ở đầu mỗi câu lệnh. 3139 | 3140 | 3141 | - [22.2](#coercion--strings) Đối với các chuỗi: eslint: [`no-new-wrappers`](https://eslint.org/docs/rules/no-new-wrappers) 3142 | 3143 | ``` javascript 3144 | // => this.reviewScore = 9; 3145 | 3146 | // không tốt 3147 | const totalScore = new String(this.reviewScore); // typeof totalScore là "object", không phải "string" 3148 | 3149 | // không tốt 3150 | const totalScore = this.reviewScore + ''; // cái này gọi this.reviewScore.valueOf() 3151 | 3152 | // không tốt 3153 | const totalScore = this.reviewScore.toString(); // không chắc chắn sẽ thu được một chuỗi 3154 | 3155 | // tốt 3156 | const totalScore = String(this.reviewScore); 3157 | ``` 3158 | 3159 | 3160 | - [22.3](#coercion--numbers) Đối với các số: Sử dụng `Number` để ép kiểu và `parseInt` luôn phải được dùng với một cơ số. eslint: [`radix`](https://eslint.org/docs/rules/radix) [`no-new-wrappers`](https://eslint.org/docs/rules/no-new-wrappers) 3161 | 3162 | > Tại sao? Hàm `parseInt` sinh ra một số nguyên bằng cách diễn giải nội dung của một chuỗi dựa trên một cơ số đã định. Ký tự trống ở đầu chuỗi được bỏ qua. Nếu cơ số là `undefined` hoặc `0`, cơ số đó được ngầm định là `10`, trừ trường hợp số trong chuỗi bắt đầu bằng cặp ký tự `0x` hoặc `0X`, khi đó cơ số `16` được sử dụng. Điều này khác với ECMAScript 3, khi nó chỉ không khuyến khích (nhưng cho phép) sử dụng diễn giải số theo hệ bát phân. Nhiều trình duyệt chưa áp dụng theo điều trên kể từ 2013. Và, vì những trình duyệt cũ cũng cần được hỗ trợ, hãy luôn sử dụng một cơ số. 3163 | 3164 | ``` javascript 3165 | const inputValue = '4'; 3166 | 3167 | // không tốt 3168 | const val = new Number(inputValue); 3169 | 3170 | // không tốt 3171 | const val = +inputValue; 3172 | 3173 | // không tốt 3174 | const val = inputValue >> 0; 3175 | 3176 | // không tốt 3177 | const val = parseInt(inputValue); 3178 | 3179 | // tốt 3180 | const val = Number(inputValue); 3181 | 3182 | // tốt 3183 | const val = parseInt(inputValue, 10); 3184 | ``` 3185 | 3186 | 3187 | - [22.4](#coercion--comment-deviations) Nếu, vì bất cứ lý do gì, bạn đang làm một điều gì đó thật điên và bạn gặp nghẽn cổ chai do `parseInt`, và bạn cần sử dụng phép dịch chuyển bit vì [các lý do hiệu suất](https://jsperf.com/coercion-vs-casting/3), nhớ để lại một chú thích để giải thích về thứ bạn đang làm và tại sao bạn làm vậy. 3188 | 3189 | ``` javascript 3190 | // tốt 3191 | /** 3192 | * parseInt là lý do khiến mã của tôi chạy chậm. 3193 | * Việc áp dụng phép dịch chuyển bit cho một chuỗi 3194 | * để ép nó sang kiểu số nhanh hơn nhiều. 3195 | */ 3196 | const val = inputValue >> 0; 3197 | ``` 3198 | 3199 | 3200 | - [22.5](#coercion--bitwise) **Lưu ý:** Cẩn thận khi sử dụng các phép dịch chuyển bit. Các số được biểu diễn dưới dạng các [giá trị 64-bit](https://es5.github.io/#x4.3.19), nhưng các phép dịch chuyển bit luôn trả về một số nguyên 32-bit ([nguồn](https://es5.github.io/#x11.7)). Phép dịch chuyển bit cũng có thể dẫn đến các hành vi không mong đợi đối với các giá trị lớn hơn 32 bit. [Cuộc thảo luận](https://github.com/airbnb/javascript/issues/109). Số nguyên có dấu 32-bit lớn nhất là 2,147,483,647: 3201 | 3202 | ``` javascript 3203 | 2147483647 >> 0; // => 2147483647 3204 | 2147483648 >> 0; // => -2147483648 3205 | 2147483649 >> 0; // => -2147483647 3206 | ``` 3207 | 3208 | 3209 | - [22.6](#coercion--booleans) Đối với các boolean: eslint: [`no-new-wrappers`](https://eslint.org/docs/rules/no-new-wrappers) 3210 | 3211 | ``` javascript 3212 | const age = 0; 3213 | 3214 | // không tốt 3215 | const hasAge = new Boolean(age); 3216 | 3217 | // tốt 3218 | const hasAge = Boolean(age); 3219 | 3220 | // tốt nhất 3221 | const hasAge = !!age; 3222 | ``` 3223 | 3224 | **[⬆ về đầu trang](#table-of-contents)** 3225 | 3226 | ## Các Quy ước Đặt tên 3227 | 3228 | 3229 | - [23.1](#naming--descriptive) Tránh sử dụng các tên chỉ có một chữ cái. Hãy đặt những cái tên thật ý nghĩa. eslint: [`id-length`](https://eslint.org/docs/rules/id-length) 3230 | 3231 | ``` javascript 3232 | // không tốt 3233 | function q() { 3234 | // ... 3235 | } 3236 | 3237 | // tốt 3238 | function query() { 3239 | // ... 3240 | } 3241 | ``` 3242 | 3243 | 3244 | - [23.2](#naming--camelCase) Sử dụng camelCase khi đặt tên các đối tượng, các hàm và các thực thể. eslint: [`camelcase`](https://eslint.org/docs/rules/camelcase.html) 3245 | 3246 | ``` javascript 3247 | // không tốt 3248 | const OBJEcttsssss = {}; 3249 | const this_is_my_object = {}; 3250 | function c() {} 3251 | 3252 | // tốt 3253 | const thisIsMyObject = {}; 3254 | function thisIsMyFunction() {} 3255 | ``` 3256 | 3257 | 3258 | - [23.3](#naming--PascalCase) Sử dụng PascalCase chỉ khi đặt tên các hàm tạo hay các lớp. eslint: [`new-cap`](https://eslint.org/docs/rules/new-cap.html) 3259 | 3260 | ``` javascript 3261 | // không tốt 3262 | function user(options) { 3263 | this.name = options.name; 3264 | } 3265 | 3266 | const bad = new user({ 3267 | name: 'đừnggg', 3268 | }); 3269 | 3270 | // tốt 3271 | class User { 3272 | constructor(options) { 3273 | this.name = options.name; 3274 | } 3275 | } 3276 | 3277 | const good = new User({ 3278 | name: 'đúng nè', 3279 | }); 3280 | ``` 3281 | 3282 | 3283 | - [23.4](#naming--leading-underscore) Không sử dụng các dấu gạch dưới ở đằng trước hoặc đằng sau. eslint: [`no-underscore-dangle`](https://eslint.org/docs/rules/no-underscore-dangle.html) 3284 | 3285 | > Tại sao? JavaScript không có khái niệm về tính riêng tư khi nói đến các thuộc tính hay các phương thức. Tuy rằng một dấu gạch dưới đặt ở đằng trước là một quy ước chung mang nghĩa “riêng tư”, thực tế, các thuộc tính trên đều hoàn toàn công khai, và vì vậy, là các thành phần trong API của bạn. Quy ước này có thể khiến các nhà phát triển nghĩ, một cách sai lầm, rằng một sự thay đổi chẳng làm hỏng điều gì, hoặc không cần thiết phải kiểm thử. tl;dr: nếu bạn muốn thứ gì đó thật “riêng tư”, sự tồn tại của nó phải được giấu đi. 3286 | 3287 | ``` javascript 3288 | // không tốt 3289 | this.__firstName__ = 'Panda'; 3290 | this.firstName_ = 'Panda'; 3291 | this._firstName = 'Panda'; 3292 | 3293 | // tốt 3294 | this.firstName = 'Panda'; 3295 | 3296 | // tốt, đối với các môi trường hỗ trợ WeakMap 3297 | // xem https://kangax.github.io/compat-table/es6/#test-WeakMap 3298 | const firstNames = new WeakMap(); 3299 | firstNames.set(this, 'Panda'); 3300 | ``` 3301 | 3302 | 3303 | - [23.5](#naming--self-this) Đừng lưu các tham chiếu đến `this`. Hãy sử dụng hàm mũi tên hoặc [Function#bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind). 3304 | 3305 | ``` javascript 3306 | // không tốt 3307 | function foo() { 3308 | const self = this; 3309 | return function () { 3310 | console.log(self); 3311 | }; 3312 | } 3313 | 3314 | // không tốt 3315 | function foo() { 3316 | const that = this; 3317 | return function () { 3318 | console.log(that); 3319 | }; 3320 | } 3321 | 3322 | // tốt 3323 | function foo() { 3324 | return () => { 3325 | console.log(this); 3326 | }; 3327 | } 3328 | ``` 3329 | 3330 | 3331 | - [23.6](#naming--filename-matches-export) Phần tên của một tên tệp nên giống với địa chỉ xuất mặc định của tệp đó. 3332 | 3333 | ``` javascript 3334 | // file 1 contents 3335 | class CheckBox { 3336 | // ... 3337 | } 3338 | export default CheckBox; 3339 | 3340 | // file 2 contents 3341 | export default function fortyTwo() { return 42; } 3342 | 3343 | // file 3 contents 3344 | export default function insideDirectory() {} 3345 | 3346 | // in some other file 3347 | // không tốt 3348 | import CheckBox from './checkBox'; // nhập PascalCase, tên camelCase 3349 | import FortyTwo from './FortyTwo'; // nhập/tên PascalCase, xuất camelCase 3350 | import InsideDirectory from './InsideDirectory'; // nhập/tên PascalCase, xuất camelCase 3351 | 3352 | // không tốt 3353 | import CheckBox from './check_box'; // nhập/xuất PascalCase, tên snake_case 3354 | import forty_two from './forty_two'; // nhập/tên snake_case, xuất camelCase 3355 | import inside_directory from './inside_directory'; // nhập snake_case, xuất camelCase 3356 | import index from './inside_directory/index'; // ghi tên tệp index 3357 | import insideDirectory from './insideDirectory/index'; // ghi tên tệp index 3358 | 3359 | // tốt 3360 | import CheckBox from './CheckBox'; // xuất/nhập/tên PascalCase 3361 | import fortyTwo from './fortyTwo'; // xuất/nhập/tên camelCase 3362 | import insideDirectory from './insideDirectory'; // xuất/nhập/tên camelCase; ngầm định "index" 3363 | // ^ hỗ trợ cả insideDirectory.js và insideDirectory/index.js 3364 | ``` 3365 | 3366 | 3367 | - [23.7](#naming--camelCase-default-export) Sử dụng camelCase khi xuất mặc định một hàm. Tên tệp nên trùng với tên hàm. 3368 | 3369 | ``` javascript 3370 | function makeStyleGuide() { 3371 | // ... 3372 | } 3373 | 3374 | export default makeStyleGuide; 3375 | ``` 3376 | 3377 | 3378 | - [23.8](#naming--PascalCase-singleton) Sử dụng PascalCase khi xuất mặc định một hàm tạo / lớp / đối tượng độc nhật / một thư viện các hàm / đối tượng trần. 3379 | 3380 | ``` javascript 3381 | const AirbnbStyleGuide = { 3382 | es6: { 3383 | }, 3384 | }; 3385 | 3386 | export default AirbnbStyleGuide; 3387 | ``` 3388 | 3389 | 3390 | - [23.9](#naming--Acronyms-and-Initialisms) Các từ viết tắt nên được viết hoa hoặc viết thường toàn bộ. 3391 | 3392 | > Tại sao? Các tên dùng để đọc, không phải để giải thích thuật toán. 3393 | 3394 | ``` javascript 3395 | // không tốt 3396 | import SmsContainer from './containers/SmsContainer'; 3397 | 3398 | // không tốt 3399 | const HttpRequests = [ 3400 | // ... 3401 | ]; 3402 | 3403 | // tốt 3404 | import SMSContainer from './containers/SMSContainer'; 3405 | 3406 | // tốt 3407 | const HTTPRequests = [ 3408 | // ... 3409 | ]; 3410 | 3411 | // như này cũng tốt 3412 | const httpRequests = [ 3413 | // ... 3414 | ]; 3415 | 3416 | // tốt nhất 3417 | import TextMessageContainer from './containers/TextMessageContainer'; 3418 | 3419 | // tốt nhất 3420 | const requests = [ 3421 | // ... 3422 | ]; 3423 | ``` 3424 | 3425 | 3426 | - [23.10](#naming--uppercase) Bạn có chọn viết hoa một hằng chỉ khi hằng đó (1) được xuất, và (2) một lập trình viên có thể tin tưởng rằng nó (và các thuộc tính của nó) là bất biến. 3427 | 3428 | > Tại sao? Đây là một công cụ khác để hỗ trợ chúng ta trong các hoàn cảnh mà một lập trình viên có thể không chắc chắn là một biến có bị thay đổi hay chưa. UPPERCASE_VARIABLES đang cho lập trình viên đó biết là biến này (và thuộc tính của nó) không có thay đổi gì hết. 3429 | - Thế còn các `const`? - Điều này là không cần thiết, vì việc viết hoa không nên được sử dụng cho các hằng ở trong cùng một tệp. Nó chỉ nên dùng cho các hằng được xuất. 3430 | - Thế còn một đối tượng được xuất thì sao? - Chỉ viết hoa ở hàng cao nhất của đối tượng xuất (kiểu như: `EXPORTED_OBJECT.key`) và đảm bảo rằng những thuộc tính của nó không thay đổi. 3431 | 3432 | ``` javascript 3433 | // không tốt 3434 | const PRIVATE_VARIABLE = 'không nên viết hoa bừa bãi các biến trong một tệp'; 3435 | 3436 | // không tốt 3437 | export const THING_TO_BE_CHANGED = 'rõ ràng không nên viết hoa'; 3438 | 3439 | // không tốt 3440 | export let REASSIGNABLE_VARIABLE = 'đừng có sử dụng let với tên viết hóa'; 3441 | 3442 | // --- 3443 | 3444 | // được cho phép, nhưng không không rõ về mặt ngữ nghĩa 3445 | export const apiKey = 'SOMEKEY'; 3446 | 3447 | // tốt hơn hầu hết các trường hợp khác 3448 | export const API_KEY = 'SOMEKEY'; 3449 | 3450 | // --- 3451 | 3452 | // không tốt - viết hoa không cần thiết chẳng cung cấp gì trị gì về mặt ngữ nghĩa 3453 | export const MAPPING = { 3454 | KEY: 'giá trị' 3455 | }; 3456 | 3457 | // tốt 3458 | export const MAPPING = { 3459 | key: 'giá trị' 3460 | }; 3461 | ``` 3462 | 3463 | **[⬆ về đầu trang](#table-of-contents)** 3464 | 3465 | ## Các Hàm truy cập 3466 | 3467 | 3468 | - [24.1](#accessors--not-required) Các hàm truy cập cho các thuộc tình là không bắt buộc. 3469 | 3470 | 3471 | - [24.2](#accessors--no-getters-setters) Không sử dụng hàm đọc/hàm ghi của JavaScript vì chúng gây ra các hiệu ứng phụ không mong muốn và khó để kiểm thử, bảo trì, và hình dung. Thay vào đó, nếu bạn muốn tạo hàm truy cập, sử dụng `getVal()` và `setVal('hello')`. 3472 | 3473 | ``` javascript 3474 | // không tốt 3475 | class Dragon { 3476 | get age() { 3477 | // ... 3478 | } 3479 | 3480 | set age(value) { 3481 | // ... 3482 | } 3483 | } 3484 | 3485 | // tốt 3486 | class Dragon { 3487 | getAge() { 3488 | // ... 3489 | } 3490 | 3491 | setAge(value) { 3492 | // ... 3493 | } 3494 | } 3495 | ``` 3496 | 3497 | 3498 | - [24.3](#accessors--boolean-prefix) Nếu thuộc tính/phương thức là một `boolean`, dùng `isVal()` hoặc `hasVal()`. 3499 | 3500 | ``` javascript 3501 | // không tốt 3502 | if (!dragon.age()) { 3503 | return false; 3504 | } 3505 | 3506 | // tốt 3507 | if (!dragon.hasAge()) { 3508 | return false; 3509 | } 3510 | ``` 3511 | 3512 | 3513 | - [24.4](#accessors--consistent) Có thể dùng các hàm `get()` và `set()`, nhưng nhớ là phải nhất quán. 3514 | 3515 | ``` javascript 3516 | class Jedi { 3517 | constructor(options = {}) { 3518 | const lightsaber = options.lightsaber || 'xanh dương'; 3519 | this.set('lightsaber', lightsaber); 3520 | } 3521 | 3522 | set(key, val) { 3523 | this[key] = val; 3524 | } 3525 | 3526 | get(key) { 3527 | return this[key]; 3528 | } 3529 | } 3530 | ``` 3531 | 3532 | **[⬆ về đầu trang](#table-of-contents)** 3533 | 3534 | ## Các Sự kiện 3535 | 3536 | 3537 | - [25.1](#events--hash) Khi gắn các trọng tải dữ liệu cho các sự kiện (dù là các sự kiện DOM hay thứ gì đó tư hữu hơn như các sự kiện trong Backbone), hãy truyền vào một đối tượng nguyên văn (hay còn gọi là "giá trị băm") thay vì giá trị gốc. Điều này cho phép những người đóng góp sau này có thể thêm dữ liệu vào trọng tải mà không cần phải tìm và cập nhật mỗi hàm xử lý cho sự kiện. Ví dụ, thay vì: 3538 | 3539 | ``` javascript 3540 | // không tốt 3541 | $(this).trigger('listingUpdated', listing.id); 3542 | 3543 | // ... 3544 | 3545 | $(this).on('listingUpdated', (e, listingID) => { 3546 | // làm gì đó với listingID 3547 | }); 3548 | ``` 3549 | 3550 | hãy dùng: 3551 | 3552 | ``` javascript 3553 | // tốt 3554 | $(this).trigger('listingUpdated', { listingID: listing.id }); 3555 | 3556 | // ... 3557 | 3558 | $(this).on('listingUpdated', (e, data) => { 3559 | // làm gì đó với listingID 3560 | }); 3561 | ``` 3562 | 3563 | **[⬆ về đầu trang](#table-of-contents)** 3564 | 3565 | ## jQuery 3566 | 3567 | 3568 | - [26.1](#jquery--dollar-prefix) Bắt đầu các biến lưu các đối tượng jQuery với `$`. 3569 | 3570 | ``` javascript 3571 | // không tốt 3572 | const sidebar = $('.sidebar'); 3573 | 3574 | // tốt 3575 | const $sidebar = $('.sidebar'); 3576 | 3577 | // tốt 3578 | const $sidebarBtn = $('.sidebar-btn'); 3579 | ``` 3580 | 3581 | 3582 | - [26.2](#jquery--cache) Lưu tạm các truy vấn jQuery. 3583 | 3584 | ``` javascript 3585 | // không tốt 3586 | function setSidebar() { 3587 | $('.sidebar').hide(); 3588 | 3589 | // ... 3590 | 3591 | $('.sidebar').css({ 3592 | 'background-color': 'pink', 3593 | }); 3594 | } 3595 | 3596 | // tốt 3597 | function setSidebar() { 3598 | const $sidebar = $('.sidebar'); 3599 | $sidebar.hide(); 3600 | 3601 | // ... 3602 | 3603 | $sidebar.css({ 3604 | 'background-color': 'pink', 3605 | }); 3606 | } 3607 | ``` 3608 | 3609 | 3610 | - [26.3](#jquery--queries) Với các truy vấn, hãy sử dụng truy vấn xếp tầng `$('.sidebar ul')` hoặc cha > con `$('.sidebar > ul')`. [jsPerf](http://jsperf.com/jquery-find-vs-context-sel/16) 3611 | 3612 | 3613 | - [26.4](#jquery--find) Sử dụng `find` với một phạm vi đối tượng jQuery cho các truy vấn. 3614 | 3615 | ``` javascript 3616 | // không tốt 3617 | $('ul', '.sidebar').hide(); 3618 | 3619 | // không tốt 3620 | $('.sidebar').find('ul').hide(); 3621 | 3622 | // tốt 3623 | $('.sidebar ul').hide(); 3624 | 3625 | // tốt 3626 | $('.sidebar > ul').hide(); 3627 | 3628 | // tốt 3629 | $sidebar.find('ul').hide(); 3630 | ``` 3631 | 3632 | **[⬆ về đầu trang](#table-of-contents)** 3633 | 3634 | ## Tính tương thích của ECMAScript 5 3635 | 3636 | 3637 | - [27.1](#es5-compat--kangax) Tham khảo [bảng tính tương thích](https://kangax.github.io/es5-compat-table/) ES5 của [Kangax](https://twitter.com/kangax/). 3638 | 3639 | **[⬆ về đầu trang](#table-of-contents)** 3640 | 3641 | 3642 | ## Lối viết ECMAScript 6+ (ES 2015+) 3643 | 3644 | 3645 | - [28.1](#es6-styles) Đây là một bộ sưu tập các liên kết tới các tính năng khác nhau của ES6+. 3646 | 3647 | 1. [Các Hàm mũi tên](#arrow-functions) 3648 | 1. [Các Lớp](#classes--constructors) 3649 | 1. [Cú pháp Định nghĩa Phương thức Rút gọn](#es6-object-shorthand) 3650 | 1. [Cú pháp Định nghĩa Thuộc tính Rút gọn](#es6-object-concise) 3651 | 1. [Các Tên Được tính của Thuộc tính](#es6-computed-properties) 3652 | 1. [Các Mẫu chuỗi](#es6-template-literals) 3653 | 1. [Trích xuất](#destructuring) 3654 | 1. [Các Tham số Mặc định](#es6-default-parameters) 3655 | 1. [Còn-lại](#es6-rest) 3656 | 1. [Liệt kê Mảng](#es6-array-spreads) 3657 | 1. [Let và Const](#references) 3658 | 1. [Toán tử Lũy thừa](#es2016-properties--exponentiation-operator) 3659 | 1. [Các Đối tượng duyệt và các Hàm sinh trị](#iterators-and-generators) 3660 | 1. [Các Mô-đun](#modules) 3661 | 3662 | 3663 | - [28.2](#tc39-proposals) Không sử dụng [các đề xuất TC39](https://github.com/tc39/proposals) mà chưa đến giai đoạn 3. 3664 | 3665 | > Tại sao? [Chúng chưa được hoàn thiện](https://tc39.github.io/process-document/), và chúng có thể thay đổi bất cứ lúc nào hoặc bị rút lại hoàn toàn. Chúng ta muốn sử dụng JavaScript, mà các đề xuất thì chưa phải là JavaScript. 3666 | 3667 | **[⬆ về đầu trang](#table-of-contents)** 3668 | 3669 | ## Thư viện Tiêu Chuẩn 3670 | 3671 | [Thư viện tiêu chuẩn](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects) 3672 | chứa các hàm tiện ích không hoạt động đúng lắm nhưng vẫn tồn tại vì các lý do cũ. 3673 | 3674 | 3675 | - [29.1](#standard-library--isnan) Sử dụng `Number.isNaN` thay vì hàm toàn cục `isNaN`. 3676 | eslint: [`no-restricted-globals`](https://eslint.org/docs/rules/no-restricted-globals) 3677 | 3678 | > Tại sao? Hàm toàn cục `isNaN` ép các giá trị không phải số thành số và trả về true cho tất cả những gì mà bị ép thành NaN. 3679 | > Nếu đây là hành vi mong muốn, hãy khiến nó được biểu đạt rõ ràng. 3680 | 3681 | ``` javascript 3682 | // không tốt 3683 | isNaN('1.2'); // false 3684 | isNaN('1.2.3'); // true 3685 | 3686 | // tốt 3687 | Number.isNaN('1.2.3'); // false 3688 | Number.isNaN(Number('1.2.3')); // true 3689 | ``` 3690 | 3691 | 3692 | - [29.2](#standard-library--isfinite) Sử dụng `Number.isFinite` thay vì hàm toàn cục `isFinite`. 3693 | eslint: [`no-restricted-globals`](https://eslint.org/docs/rules/no-restricted-globals) 3694 | 3695 | > Tại sao? Hàm toàn cục `isFinite` ép các giá trị không phải số thành số và trả về true cho tất cả những gì bị ép thành một số mà không phải là vô hạn. 3696 | > Nếu đây là hành vi mong muốn, hãy khiến nó được biểu đạt rõ ràng. 3697 | 3698 | ``` javascript 3699 | // không tốt 3700 | isFinite('2e3'); // true 3701 | 3702 | // tốt 3703 | Number.isFinite('2e3'); // false 3704 | Number.isFinite(parseInt('2e3', 10)); // true 3705 | ``` 3706 | 3707 | **[⬆ về đầu trang](#table-of-contents)** 3708 | 3709 | ## Sự kiểm thử 3710 | 3711 | 3712 | - [30.1](#testing--yup) **Có chứ.** 3713 | 3714 | ``` javascript 3715 | function foo() { 3716 | return true; 3717 | } 3718 | ``` 3719 | 3720 | 3721 | - [30.2](#testing--for-real) **Không, nhưng nghiêm túc này**: 3722 | - Dù bạn dùng nền tảng kiểm thử nào thì bạn cũng nên viết các kiểm thử! 3723 | - Cố gắng viết thật nhiều các hàm thuần, nhỏ và giảm thiểu số các sự biến đổi. 3724 | - Cẩn thận với các giả lập mô-đun và đối tượng - chúng có thể khiến các chương trình kiểm thử của bạn dễ vỡ. 3725 | - Chúng tôi chủ yếu sử dụng [`mocha`](https://www.npmjs.com/package/mocha) và [`jest`](https://www.npmjs.com/package/jest) tại Airbnb. [`tape`](https://www.npmjs.com/package/tape) cũng đôi khi được sử dụng cho các mô-đun nhỏ và tách biệt. 3726 | - 100% độ bao phủ kiểm thử là một mục tiêu tốt để phấn đấu, dù không phải lúc nào cũng khả thi. 3727 | - Mỗi khi bạn sửa một lỗi, _viết một kiểm thử hồi quy_. Một lỗi được sửa nhưng không được viết kiểm thử lại gần như chắc chắn sẽ lại hỏng trong tương lai. 3728 | 3729 | **[⬆ về đầu trang](#table-of-contents)** 3730 | 3731 | ## Hiệu suất 3732 | 3733 | - [On Layout & Web Performance](https://www.kellegous.com/j/2013/01/26/layout-performance/) 3734 | - [String vs Array Concat](https://jsperf.com/string-vs-array-concat/2) 3735 | - [Try/Catch Cost In a Loop](https://jsperf.com/try-catch-in-loop-cost/12) 3736 | - [Bang Function](https://jsperf.com/bang-function) 3737 | - [jQuery Find vs Context, Selector](https://jsperf.com/jquery-find-vs-context-sel/164) 3738 | - [innerHTML vs textContent for script text](https://jsperf.com/innerhtml-vs-textcontent-for-script-text) 3739 | - [Long String Concatenation](https://jsperf.com/ya-string-concat/38) 3740 | - [Are Javascript functions like `map()`, `reduce()`, and `filter()` optimized for traversing arrays?](https://www.quora.com/JavaScript-programming-language-Are-Javascript-functions-like-map-reduce-and-filter-already-optimized-for-traversing-array/answer/Quildreen-Motta) 3741 | - Đang tải... 3742 | 3743 | **[⬆ về đầu trang](#table-of-contents)** 3744 | 3745 | ## Các Tài nguyên 3746 | 3747 | **Học ES6+** 3748 | 3749 | - [Latest ECMA spec](https://tc39.github.io/ecma262/) 3750 | - [ExploringJS](http://exploringjs.com/) 3751 | - [ES6 Compatibility Table](https://kangax.github.io/compat-table/es6/) 3752 | - [Comprehensive Overview of ES6 Features](http://es6-features.org/) 3753 | 3754 | **Đọc cái này đi** 3755 | 3756 | - [Standard ECMA-262](http://www.ecma-international.org/ecma-262/6.0/index.html) 3757 | 3758 | **Các công cụ** 3759 | 3760 | - Trình phân tích lối viết mã 3761 | - [ESlint](https://eslint.org/) - [Lối viết của Airbnb .eslintrc](https://github.com/airbnb/javascript/blob/master/linters/.eslintrc) 3762 | - [JSHint](http://jshint.com/) - [Lối viết của Airbnb .jshintrc](https://github.com/airbnb/javascript/blob/master/linters/.jshintrc) 3763 | - Gói Neutrino - [@neutrinojs/airbnb](https://neutrinojs.org/packages/airbnb/) 3764 | 3765 | **Các Định hướng Lối viết Khác** 3766 | 3767 | - [Google JavaScript Style Guide](https://google.github.io/styleguide/jsguide.html) 3768 | - [Google JavaScript Style Guide (Old)](https://google.github.io/styleguide/javascriptguide.xml) 3769 | - [jQuery Core Style Guidelines](https://contribute.jquery.org/style-guide/js/) 3770 | - [Principles of Writing Consistent, Idiomatic JavaScript](https://github.com/rwaldron/idiomatic.js) 3771 | - [StandardJS](https://standardjs.com) 3772 | 3773 | **Các Lối viết Khác** 3774 | 3775 | - [Naming this in nested functions](https://gist.github.com/cjohansen/4135065) - Christian Johansen 3776 | - [Conditional Callbacks](https://github.com/airbnb/javascript/issues/52) - Ross Allen 3777 | - [Popular JavaScript Coding Conventions on GitHub](http://sideeffect.kr/popularconvention/#javascript) - JeongHoon Byun 3778 | - [Multiple var statements in JavaScript, not superfluous](http://benalman.com/news/2012/05/multiple-var-statements-javascript/) - Ben Alman 3779 | 3780 | **Đọc thêm** 3781 | 3782 | - [Understanding JavaScript Closures](https://javascriptweblog.wordpress.com/2010/10/25/understanding-javascript-closures/) - Angus Croll 3783 | - [Basic JavaScript for the impatient programmer](http://www.2ality.com/2013/06/basic-javascript.html) - Dr. Axel Rauschmayer 3784 | - [You Might Not Need jQuery](http://youmightnotneedjquery.com/) - Zack Bloom & Adam Schwartz 3785 | - [ES6 Features](https://github.com/lukehoban/es6features) - Luke Hoban 3786 | - [Frontend Guidelines](https://github.com/bendc/frontend-guidelines) - Benjamin De Cock 3787 | 3788 | **Các Tựa sách** 3789 | 3790 | - [JavaScript: The Good Parts](https://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742) - Douglas Crockford 3791 | - [JavaScript Patterns](https://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752) - Stoyan Stefanov 3792 | - [Pro JavaScript Design Patterns](https://www.amazon.com/JavaScript-Design-Patterns-Recipes-Problem-Solution/dp/159059908X) - Ross Harmes and Dustin Diaz 3793 | - [High Performance Web Sites: Essential Knowledge for Front-End Engineers](https://www.amazon.com/High-Performance-Web-Sites-Essential/dp/0596529309) - Steve Souders 3794 | - [Maintainable JavaScript](https://www.amazon.com/Maintainable-JavaScript-Nicholas-C-Zakas/dp/1449327680) - Nicholas C. Zakas 3795 | - [JavaScript Web Applications](https://www.amazon.com/JavaScript-Web-Applications-Alex-MacCaw/dp/144930351X) - Alex MacCaw 3796 | - [Pro JavaScript Techniques](https://www.amazon.com/Pro-JavaScript-Techniques-John-Resig/dp/1590597273) - John Resig 3797 | - [Smashing Node.js: JavaScript Everywhere](https://www.amazon.com/Smashing-Node-js-JavaScript-Everywhere-Magazine/dp/1119962595) - Guillermo Rauch 3798 | - [Secrets of the JavaScript Ninja](https://www.amazon.com/Secrets-JavaScript-Ninja-John-Resig/dp/193398869X) - John Resig and Bear Bibeault 3799 | - [Human JavaScript](http://humanjavascript.com/) - Henrik Joreteg 3800 | - [Superhero.js](http://superherojs.com/) - Kim Joar Bekkelund, Mads Mobæk, & Olav Bjorkoy 3801 | - [JSBooks](http://jsbooks.revolunet.com/) - Julien Bouquillon 3802 | - [Third Party JavaScript](https://www.manning.com/books/third-party-javascript) - Ben Vinegar and Anton Kovalyov 3803 | - [Effective JavaScript: 68 Specific Ways to Harness the Power of JavaScript](http://amzn.com/0321812182) - David Herman 3804 | - [Eloquent JavaScript](http://eloquentjavascript.net/) - Marijn Haverbeke 3805 | - [You Don’t Know JS: ES6 & Beyond](http://shop.oreilly.com/product/0636920033769.do) - Kyle Simpson 3806 | 3807 | **Các Bài viết** 3808 | 3809 | - [JavaScript Weekly](http://javascriptweekly.com/) 3810 | - [JavaScript, JavaScript...](https://javascriptweblog.wordpress.com/) 3811 | - [Bocoup Weblog](https://bocoup.com/weblog) 3812 | - [Adequately Good](http://www.adequatelygood.com/) 3813 | - [NCZOnline](https://www.nczonline.net/) 3814 | - [Perfection Kills](http://perfectionkills.com/) 3815 | - [Ben Alman](http://benalman.com/) 3816 | - [Dmitry Baranovskiy](http://dmitry.baranovskiy.com/) 3817 | - [nettuts](http://code.tutsplus.com/?s=javascript) 3818 | 3819 | **Các Bản phát thanh** 3820 | 3821 | - [JavaScript Air](https://javascriptair.com/) 3822 | - [JavaScript Jabber](https://devchat.tv/js-jabber/) 3823 | 3824 | **[⬆ về đầu trang](#table-of-contents)** 3825 | 3826 | ## Thực tế Áp dụng 3827 | 3828 | Đây là danh sách những tổ chức sử dụng định hướng lối viết này. Gửi cho chúng tôi một yêu cầu kéo và chúng tôi sẽ thêm bạn vào danh sách. 3829 | 3830 | - **123erfasst**: [123erfasst/javascript](https://github.com/123erfasst/javascript) 3831 | - **4Catalyzer**: [4Catalyzer/javascript](https://github.com/4Catalyzer/javascript) 3832 | - **Aan Zee**: [AanZee/javascript](https://github.com/AanZee/javascript) 3833 | - **Airbnb**: [airbnb/javascript](https://github.com/airbnb/javascript) 3834 | - **AloPeyk**: [AloPeyk](https://github.com/AloPeyk) 3835 | - **AltSchool**: [AltSchool/javascript](https://github.com/AltSchool/javascript) 3836 | - **Apartmint**: [apartmint/javascript](https://github.com/apartmint/javascript) 3837 | - **Ascribe**: [ascribe/javascript](https://github.com/ascribe/javascript) 3838 | - **Avant**: [avantcredit/javascript](https://github.com/avantcredit/javascript) 3839 | - **Axept**: [axept/javascript](https://github.com/axept/javascript) 3840 | - **Billabong**: [billabong/javascript](https://github.com/billabong/javascript) 3841 | - **Bisk**: [bisk](https://github.com/Bisk/) 3842 | - **Bonhomme**: [bonhommeparis/javascript](https://github.com/bonhommeparis/javascript) 3843 | - **Brainshark**: [brainshark/javascript](https://github.com/brainshark/javascript) 3844 | - **CaseNine**: [CaseNine/javascript](https://github.com/CaseNine/javascript) 3845 | - **Cerner**: [Cerner](https://github.com/cerner/) 3846 | - **Chartboost**: [ChartBoost/javascript-style-guide](https://github.com/ChartBoost/javascript-style-guide) 3847 | - **Coeur d'Alene Tribe**: [www.cdatribe-nsn.gov](https://www.cdatribe-nsn.gov) 3848 | - **ComparaOnline**: [comparaonline/javascript](https://github.com/comparaonline/javascript-style-guide) 3849 | - **Compass Learning**: [compasslearning/javascript-style-guide](https://github.com/compasslearning/javascript-style-guide) 3850 | - **DailyMotion**: [dailymotion/javascript](https://github.com/dailymotion/javascript) 3851 | - **DoSomething**: [DoSomething/eslint-config](https://github.com/DoSomething/eslint-config) 3852 | - **Digitpaint** [digitpaint/javascript](https://github.com/digitpaint/javascript) 3853 | - **Drupal**: [www.drupal.org](https://git.drupalcode.org/project/drupal/blob/8.6.x/core/.eslintrc.json) 3854 | - **Ecosia**: [ecosia/javascript](https://github.com/ecosia/javascript) 3855 | - **Evernote**: [evernote/javascript-style-guide](https://github.com/evernote/javascript-style-guide) 3856 | - **Evolution Gaming**: [evolution-gaming/javascript](https://github.com/evolution-gaming/javascript) 3857 | - **EvozonJs**: [evozonjs/javascript](https://github.com/evozonjs/javascript) 3858 | - **ExactTarget**: [ExactTarget/javascript](https://github.com/ExactTarget/javascript) 3859 | - **Flexberry**: [Flexberry/javascript-style-guide](https://github.com/Flexberry/javascript-style-guide) 3860 | - **Gawker Media**: [gawkermedia](https://github.com/gawkermedia/) 3861 | - **General Electric**: [GeneralElectric/javascript](https://github.com/GeneralElectric/javascript) 3862 | - **Generation Tux**: [GenerationTux/javascript](https://github.com/generationtux/styleguide) 3863 | - **GoodData**: [gooddata/gdc-js-style](https://github.com/gooddata/gdc-js-style) 3864 | - **GreenChef**: [greenchef/javascript](https://github.com/greenchef/javascript) 3865 | - **Grooveshark**: [grooveshark/javascript](https://github.com/grooveshark/javascript) 3866 | - **Grupo-Abraxas**: [Grupo-Abraxas/javascript](https://github.com/Grupo-Abraxas/javascript) 3867 | - **Happeo**: [happeo/javascript](https://github.com/happeo/javascript) 3868 | - **Honey**: [honeyscience/javascript](https://github.com/honeyscience/javascript) 3869 | - **How About We**: [howaboutwe/javascript](https://github.com/howaboutwe/javascript-style-guide) 3870 | - **HubSpot**: [HubSpot/javascript](https://github.com/HubSpot/javascript) 3871 | - **Hyper**: [hyperoslo/javascript-playbook](https://github.com/hyperoslo/javascript-playbook/blob/master/style.md) 3872 | - **InterCity Group**: [intercitygroup/javascript-style-guide](https://github.com/intercitygroup/javascript-style-guide) 3873 | - **Jam3**: [Jam3/Javascript-Code-Conventions](https://github.com/Jam3/Javascript-Code-Conventions) 3874 | - **JSSolutions**: [JSSolutions/javascript](https://github.com/JSSolutions/javascript) 3875 | - **Kaplan Komputing**: [kaplankomputing/javascript](https://github.com/kaplankomputing/javascript) 3876 | - **KickorStick**: [kickorstick](https://github.com/kickorstick/) 3877 | - **Kinetica Solutions**: [kinetica/javascript](https://github.com/kinetica/Javascript-style-guide) 3878 | - **LEINWAND**: [LEINWAND/javascript](https://github.com/LEINWAND/javascript) 3879 | - **Lonely Planet**: [lonelyplanet/javascript](https://github.com/lonelyplanet/javascript) 3880 | - **M2GEN**: [M2GEN/javascript](https://github.com/M2GEN/javascript) 3881 | - **Mighty Spring**: [mightyspring/javascript](https://github.com/mightyspring/javascript) 3882 | - **MinnPost**: [MinnPost/javascript](https://github.com/MinnPost/javascript) 3883 | - **MitocGroup**: [MitocGroup/javascript](https://github.com/MitocGroup/javascript) 3884 | - **Muber**: [muber](https://github.com/muber/) 3885 | - **National Geographic**: [natgeo](https://github.com/natgeo/) 3886 | - **NullDev**: [NullDevCo/JavaScript-Styleguide](https://github.com/NullDevCo/JavaScript-Styleguide) 3887 | - **Nulogy**: [nulogy/javascript](https://github.com/nulogy/javascript) 3888 | - **Orange Hill Development**: [orangehill/javascript](https://github.com/orangehill/javascript) 3889 | - **Orion Health**: [orionhealth/javascript](https://github.com/orionhealth/javascript) 3890 | - **OutBoxSoft**: [OutBoxSoft/javascript](https://github.com/OutBoxSoft/javascript) 3891 | - **Peerby**: [Peerby/javascript](https://github.com/Peerby/javascript) 3892 | - **Pier 1**: [Pier1/javascript](https://github.com/pier1/javascript) 3893 | - **Qotto**: [Qotto/javascript-style-guide](https://github.com/Qotto/javascript-style-guide) 3894 | - **React**: [facebook.github.io/react/contributing/how-to-contribute.html#style-guide](https://facebook.github.io/react/contributing/how-to-contribute.html#style-guide) 3895 | - **REI**: [reidev/js-style-guide](https://github.com/rei/code-style-guides/) 3896 | - **Ripple**: [ripple/javascript-style-guide](https://github.com/ripple/javascript-style-guide) 3897 | - **Sainsbury’s Supermarkets**: [jsainsburyplc](https://github.com/jsainsburyplc) 3898 | - **Shutterfly**: [shutterfly/javascript](https://github.com/shutterfly/javascript) 3899 | - **Sourcetoad**: [sourcetoad/javascript](https://github.com/sourcetoad/javascript) 3900 | - **Springload**: [springload](https://github.com/springload/) 3901 | - **StratoDem Analytics**: [stratodem/javascript](https://github.com/stratodem/javascript) 3902 | - **SteelKiwi Development**: [steelkiwi/javascript](https://github.com/steelkiwi/javascript) 3903 | - **StudentSphere**: [studentsphere/javascript](https://github.com/studentsphere/guide-javascript) 3904 | - **SwoopApp**: [swoopapp/javascript](https://github.com/swoopapp/javascript) 3905 | - **SysGarage**: [sysgarage/javascript-style-guide](https://github.com/sysgarage/javascript-style-guide) 3906 | - **Syzygy Warsaw**: [syzygypl/javascript](https://github.com/syzygypl/javascript) 3907 | - **Target**: [target/javascript](https://github.com/target/javascript) 3908 | - **Terra**: [terra](https://github.com/cerner?utf8=%E2%9C%93&q=terra&type=&language=) 3909 | - **TheLadders**: [TheLadders/javascript](https://github.com/TheLadders/javascript) 3910 | - **The Nerdery**: [thenerdery/javascript-standards](https://github.com/thenerdery/javascript-standards) 3911 | - **Tomify**: [tomprats](https://github.com/tomprats) 3912 | - **Traitify**: [traitify/eslint-config-traitify](https://github.com/traitify/eslint-config-traitify) 3913 | - **T4R Technology**: [T4R-Technology/javascript](https://github.com/T4R-Technology/javascript) 3914 | - **UrbanSim**: [urbansim](https://github.com/urbansim/) 3915 | - **VoxFeed**: [VoxFeed/javascript-style-guide](https://github.com/VoxFeed/javascript-style-guide) 3916 | - **WeBox Studio**: [weboxstudio/javascript](https://github.com/weboxstudio/javascript) 3917 | - **Weggo**: [Weggo/javascript](https://github.com/Weggo/javascript) 3918 | - **Zillow**: [zillow/javascript](https://github.com/zillow/javascript) 3919 | - **ZocDoc**: [ZocDoc/javascript](https://github.com/ZocDoc/javascript) 3920 | 3921 | **[⬆ về đầu trang](#table-of-contents)** 3922 | 3923 | ## Danh mục các Thuật ngữ 3924 | 3925 | Dưới đây là danh mục các từ tiếng Anh tương ứng của 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. Các từ, cụm từ được dịch có thể chỉ đúng trong ngữ cảnh là bản dịch này. 3926 | 3927 | > Nếu bạn cảm thấy một thuật ngữ có vẻ được dịch chưa hợp lý, hoặc bạn cần sự giải thích về một thuật ngữ, bạn có thể mở một [Vấn đề](https://github.com/dangkyokhoang/javascript-style-guide/issues) để thảo luận. 3928 | > 3929 | > Nếu bạn biết một từ/cụm từ tiếng Việt thích hợp hơn cho một thuật ngữ, và nếu bạn sẵn lòng, bạn có thể mở một [Đề nghị kéo](https://github.com/dangkyokhoang/javascript-style-guide/pulls) cho một sửa đổi. 3930 | 3931 | | Tiếng Việt | English | 3932 | | --- | --- | 3933 | | Ánh xạ | Map/mapping | 3934 | | Ba ngôi | Ternary | 3935 | | Bản sao/sao | Copy | 3936 | | Bản sao nhanh/sao nhanh | Shallow-copy | 3937 | | Bắt | Catch | 3938 | | Bất biến | Immutable | 3939 | | Bẻ nhánh | Fork | 3940 | | Biến | Variable/var | 3941 | | Biến đổi/sự biến đổi | Mutate/mutation | 3942 | | Biểu thức | Expression | 3943 | | Biểu thức hàm | Function expression | 3944 | | Biểu thức hàm gọi tức thời | Immediately invoked function expression/IIFE | 3945 | | Bộ khung phần mềm | Framework | 3946 | | Bộ phận hàm | Function signature | 3947 | | Bộ tải | Loader | 3948 | | Bộ tổng hợp | Bundler | 3949 | | Bộ trợ năng | Shim/polyfill | 3950 | | Bước | Step | 3951 | | Cải tiến mã nguồn | Refactor code/code refactoring | 3952 | | Căn đầu dòng | Indent | 3953 | | Câu lệnh/lệnh | Statement | 3954 | | Cấu trúc một dòng | One-liner | 3955 | | Chỉ-viết | Write-only | 3956 | | Chuỗi | String | 3957 | | Chú thích | Comment | 3958 | | Còn-lại | Rest | 3959 | | Cơ số | Radix | 3960 | | Cú pháp | Syntax | 3961 | | Cú pháp tiện lợi | Syntactic sugar | 3962 | | Cũ | Legacy | 3963 | | Dấu gạch dưới | Underscore | 3964 | | Dấu lược/dấu nháy đơn | Single quote | 3965 | | Dấu ngắt dòng/dấu xuống dòng | Line break | 3966 | | Dấu ngoặc | Brace | 3967 | | Dấu ngoặc nhọn | Curly brace | 3968 | | Dấu ngoặc tròn | Parenthesis/parentheses | 3969 | | Dấu ngoặc vuông | Array bracket | 3970 | | Dịch mã | Transpile | 3971 | | Duyệt | Iterate | 3972 | | Đề xuất | Proposal | 3973 | | Đề nghị kéo | Pull request | 3974 | | Định danh | Identifier | 3975 | | Định hướng lối viết | Style guide | 3976 | | Định nghĩa | Define | 3977 | | Đối số | Argument | 3978 | | Đối tượng | Object | 3979 | | Đối tượng duyệt | Iterator/iterator object | 3980 | | Đối tượng đích | Receiver | 3981 | | Đối tượng độc nhất | Singleton | 3982 | | Đối tượng khả duyệt | Iterable object | 3983 | | Đối tượng rỗng | Null object | 3984 | | Đối tượng trần | Bare object | 3985 | | Độ bao phủ | Coverage | 3986 | | Đường dẫn | Path | 3987 | | Ép kiểu/sự ép kiểu | Coerce/coercion/cast/casting | 3988 | | Gán/phép gán | Assign/assignment | 3989 | | Gán lại | Reassign | 3990 | | Ghép | Concatenate/concatenation/concat | 3991 | | Giai đoạn chết | Temporal dead zone/TDZ | 3992 | | Giá trị băm | Hash/hash value | 3993 | | Giá trị gốc | Raw value | 3994 | | Giả lập đối tượng | Mock | 3995 | | Giả lập mô-đun | Stub | 3996 | | Giống-mảng | Array-like | 3997 | | Gọi/phép gọi | Call/invoke/invocation | 3998 | | Hàm | Function | 3999 | | Hàm bất định | Variadic function | 4000 | | Hàm bậc cao hơn | Higher-order function | 4001 | | Hàm đọc | Getter/getter function | 4002 | | Hàm ghi | Setter/setter function | 4003 | | Hàm gọi ngược | Callback/callback function | 4004 | | Hàm gọi tức thời | Immediately invoked function | 4005 | | Hàm hữu danh | Named function | 4006 | | Hàm mũi tên | Arrow function | 4007 | | Hàm sinh trị | Generator/generator function | 4008 | | Hàm tạo | Constructor | 4009 | | Hàm thuần | Pure function | 4010 | | Hàm tiện ích | Utility/utility function | 4011 | | Hàm truy cập | Accessor/accessor function | 4012 | | Hàm vô danh | Anonymous function | 4013 | | Hàm xử lý | Handler | 4014 | | Hằng | Constant/const | 4015 | | Hiệu suất | Performance/perf | 4016 | | Hiệu ứng phụ | Side effect | 4017 | | Kéo lên/sự kéo lên/nổi lên/sự nổi lên | Hoist/hoisting | 4018 | | Kê | Pad | 4019 | | Khai báo | Declare/declaration | 4020 | | Khoảng trắng | Whitespace | 4021 | | Không gian tên | Namespace | 4022 | | Khối | Block | 4023 | | Kiểm thử/sự kiểm thử | Test/testing | 4024 | | Kiểu giá trị | Type | 4025 | | Kiểu nguyên thủy | Primitive | 4026 | | Kiểu sai | Falsy/falsey | 4027 | | Ký pháp | Notation | 4028 | | Ký pháp chấm | Dot notation | 4029 | | Ký tự đại diện | Wildcard/wildcard character | 4030 | | Ký tự thoát | Escape character | 4031 | | Liên kết | Link | 4032 | | Liệt kê | Spread | 4033 | | Lô-gíc | Logic | 4034 | | Lỗ hổng | Vulnerability | 4035 | | Lỗi câm | Silent error | 4036 | | Lớp | Class | 4037 | | Lớp cha | Parent class/parent | 4038 | | Lũy thừa | Exponentiation | 4039 | | Lưu tạm | Cache | 4040 | | Lựa chọn | Select/selection | 4041 | | Mã/mã nguồn | Code/source code | 4042 | | Mảng | Array | 4043 | | Mô-đun | Module | 4044 | | Một ngôi | Unary | 4045 | | Ném ra | Throw | 4046 | | Ngăn xếp | Call stack/stack | 4047 | | Ngầm định | Implicit | 4048 | | Nghẽn cổ chai | Bottleneck | 4049 | | Ngoại lệ | Exception | 4050 | | Nguyên mẫu | Prototype | 4051 | | Nguyên văn | Literal | 4052 | | Ngữ cảnh | Context | 4053 | | Nhà phát triển | Developer/dev | 4054 | | Nhập/lệnh nhập | Import | 4055 | | Nối chuỗi | Chain/chaining | 4056 | | Phần tử | Element | 4057 | | Phép dịch chuyển bit | Bit-shift/bit-shift operation | 4058 | | Phép tăng | Increment | 4059 | | Phép giảm | Decrement | 4060 | | Phép tiền tăng/sự tiền tăng | Pre-increment | 4061 | | Phép tiền giảm/sự tiền giảm | Pre-decrement | 4062 | | Phi chuẩn | Non-standard | 4063 | | Phương thức | Method | 4064 | | Quy tắc chèn dấu chấm phẩy tự động | Automatic semicolon insertion/ASI | 4065 | | Quy ước đặt tên | Naming convention | 4066 | | Ràng buộc | Binding | 4067 | | Riêng tư | Private | 4068 | | Rút gọn/dạng rút gọn | Shorthand/shortcut | 4069 | | So sánh/sự so sánh | Compare/comparision | 4070 | | Sự bằng nhau | Equality | 4071 | | Sự kiện | Event/ev | 4072 | | Tên của thuộc tính | Property name/key | 4073 | | Tên được tính của thuộc tính | Computed property name | 4074 | | Tham chiếu | Reference | 4075 | | Tham số | Parameter | 4076 | | Thành viên | Member | 4077 | | Thân hàm | Function body | 4078 | | Thẻ | Tab | 4079 | | Thuộc phạm vi hàm | Function-scoped | 4080 | | Thuộc phạm vi khối | Block-scoped | 4081 | | Thuộc tính | Property | 4082 | | Thư viện | Library/lib | 4083 | | Thừa kế | Inherit/inheritance | 4084 | | Thực thể | Instance | 4085 | | Tiến trình gọi | Caller | 4086 | | Tính khả đọc | Readability | 4087 | | Tính tương thích | Compatibility | 4088 | | Toàn cục | Global | 4089 | | Toán tử | Operator | 4090 | | Trình gỡ lỗi | Debugger | 4091 | | Trình phân tích mã | Linter | 4092 | | Trình thực thi | Engine | 4093 | | Trích xuất/sự trích xuất | Destructure/destructuring/extract | 4094 | | Trọng tải | Payload | 4095 | | Truy cập | Access | 4096 | | Truy vấn | Query | 4097 | | Từ khóa | Keyword | 4098 | | Từ khóa điều chỉnh | Modifier | 4099 | | Ứng dụng | Application/app | 4100 | | Vấn đề | Issue | 4101 | | Xếp tầng | Cascade/cascading | 4102 | | Xuất/lệnh xuất | Export | 4103 | | Xuất hữu danh | Named export | 4104 | | Xuất mặc định | Default export | 4105 | | Xung đột khi gộp | Merge conflict | 4106 | 4107 | **[⬆ về đầu trang](#table-of-contents)** 4108 | 4109 | ## Dịch 4110 | 4111 | Định hướng này cũng được dịch sang các ngôn ngữ khác: 4112 | 4113 | - ![en](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/United-States.png) **English (United States)**: [airbnb/javascript](https://github.com/airbnb/javascript) 4114 | - ![br](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Brazil.png) **Brazilian Portuguese**: [armoucar/javascript-style-guide](https://github.com/armoucar/javascript-style-guide) 4115 | - ![bg](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Bulgaria.png) **Bulgarian**: [borislavvv/javascript](https://github.com/borislavvv/javascript) 4116 | - ![ca](https://raw.githubusercontent.com/fpmweb/javascript-style-guide/master/img/catala.png) **Catalan**: [fpmweb/javascript-style-guide](https://github.com/fpmweb/javascript-style-guide) 4117 | - ![cn](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/China.png) **Chinese (Simplified)**: [lin-123/javascript](https://github.com/lin-123/javascript) 4118 | - ![tw](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Taiwan.png) **Chinese (Traditional)**: [jigsawye/javascript](https://github.com/jigsawye/javascript) 4119 | - ![fr](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/France.png) **French**: [nmussy/javascript-style-guide](https://github.com/nmussy/javascript-style-guide) 4120 | - ![de](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Germany.png) **German**: [timofurrer/javascript-style-guide](https://github.com/timofurrer/javascript-style-guide) 4121 | - ![it](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Italy.png) **Italian**: [sinkswim/javascript-style-guide](https://github.com/sinkswim/javascript-style-guide) 4122 | - ![jp](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Japan.png) **Japanese**: [mitsuruog/javascript-style-guide](https://github.com/mitsuruog/javascript-style-guide) 4123 | - ![kr](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/South-Korea.png) **Korean**: [ParkSB/javascript-style-guide](https://github.com/ParkSB/javascript-style-guide) 4124 | - ![ru](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Russia.png) **Russian**: [leonidlebedev/javascript-airbnb](https://github.com/leonidlebedev/javascript-airbnb) 4125 | - ![es](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Spain.png) **Spanish**: [paolocarrasco/javascript-style-guide](https://github.com/paolocarrasco/javascript-style-guide) 4126 | - ![th](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Thailand.png) **Thai**: [lvarayut/javascript-style-guide](https://github.com/lvarayut/javascript-style-guide) 4127 | - ![tr](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Turkey.png) **Turkish**: [eraycetinay/javascript](https://github.com/eraycetinay/javascript) 4128 | - ![ua](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Ukraine.png) **Ukrainian**: [ivanzusko/javascript](https://github.com/ivanzusko/javascript) 4129 | 4130 | ## Định hướng Lối viết JavaScript 4131 | 4132 | - [Lời dẫn](https://github.com/airbnb/javascript/wiki/The-JavaScript-Style-Guide-Guide) 4133 | 4134 | ## Nói chuyện với Chúng tôi về JavaScript 4135 | 4136 | - Tìm chúng tôi trên [gitter](https://gitter.im/airbnb/javascript). 4137 | 4138 | ## Những Người đóng góp 4139 | 4140 | - [Xem những Người đóng góp](https://github.com/airbnb/javascript/graphs/contributors) 4141 | 4142 | ## Giấy phép 4143 | 4144 | (The MIT License) 4145 | 4146 | Copyright (c) 2012 Airbnb 4147 | 4148 | Permission is hereby granted, free of charge, to any person obtaining 4149 | a copy of this software and associated documentation files (the 4150 | 'Software'), to deal in the Software without restriction, including 4151 | without limitation the rights to use, copy, modify, merge, publish, 4152 | distribute, sublicense, and/or sell copies of the Software, and to 4153 | permit persons to whom the Software is furnished to do so, subject to 4154 | the following conditions: 4155 | 4156 | The above copyright notice and this permission notice shall be 4157 | included in all copies or substantial portions of the Software. 4158 | 4159 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 4160 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 4161 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 4162 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 4163 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 4164 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 4165 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 4166 | 4167 | **[⬆ về đầu trang](#table-of-contents)** 4168 | 4169 | ## Các Sửa đổi 4170 | 4171 | Chúng tôi khuyến khích bạn bẻ nhánh bản định hướng này và thay đổi các quy tắc để phù hợp với định hướng lối viết của nhóm của bạn. Dưới đây, bạn có thể liệt kê các sửa đổi đối với bản định hướng này. Điều này cho phép bạn thỉnh thoảng cập nhật lối viết mà không cần giải quyết các xung đột khi gộp. 4172 | 4173 | # }; 4174 | --------------------------------------------------------------------------------