Featured image of post Hướng dẫn phong cách Airbnb JavaScript

Hướng dẫn phong cách Airbnb JavaScript

Hướng dẫn phong cách Airbnb JavaScript

Photo by Pankaj Patel on Unsplash

https://github.com/jigsawye/javascript

Hướng dẫn phong cách Airbnb JavaScript()

Một cách tiếp cận hợp lý nhất đối với JavaScript.

Downloads Gitter

Các hướng dẫn phong cách khác

Dịch từ Airbnb JavaScript Style Guide.

Các kiểu (Types)

  • 1.1 Nguyên thủy (Primitives): Bạn truy cập trực tiếp vào các kiểu nguyên thủy.
  • string
  • number
  • boolean
  • null
  • undefined
const foo = 1;
let bar = foo;

bar = 9;

console.log(foo, bar); // => 1, 9
  • 1.2 Phức hợp (Complex): Bạn truy cập các kiểu phức hợp bằng tham chiếu.
  • object
  • array
  • function
const foo = [1, 2];
const bar = foo;

bar[0] = 9;

console.log(foo[0], bar[0]); // => 9, 9

Tham chiếu (References)

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 của mình, điều này có thể dẫn đến lỗi và mã khó hiểu.

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

// good
const a = 1;
const b = 2;
  • 2.2 Nếu bạn phải gán lại tham chiếu, hãy sử dụng let thay vì var. eslint: no-var jscs: disallowVar

Tại sao? let thuộc phạm vi khối (block-scoped), thay vì phạm vi hàm (function-scoped) giống như var.

// bad
var count = 1;
if (true) {
    count += 1;
}

// good, use the let.
let count = 1;
if (true) {
    count += 1;
}
  • 2.3 Lưu ý rằng cả letconst đều thuộc phạm vi khối.
// const và let chỉ tồn tại trong các khối mà chúng được định nghĩa.
{
    let a = 1;
    const b = 1;
}
console.log(a); // ReferenceError
console.log(b); // ReferenceError

Đối tượng (Objects)

  • 3.1 Sử dụng cú pháp literal để tạo đối tượng. eslint rules: no-new-object.
// bad
const item = new Object();

// good
const item = {};
// bad
const superman = {
    default: { clark: 'kent' },
    private: true,
};

// good
const superman = {
    defaults: { clark: 'kent' },
    hidden: true,
};
// bad
const superman = {
    class: 'alien',
};

// bad
const superman = {
    klass: 'alien',
};

// good
const superman = {
    type: 'alien',
};

  • 3.4 Sử dụng tên thuộc tính được tính toán (computed property names) khi tạo các đối tượng với tên thuộc tính động.

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 ở một nơi.


function getKey(k) {
    return `a key named ${k}`;
}

// bad
const obj = {
    id: 5,
    name: 'San Francisco',
};
obj[getKey('enabled')] = true;

// good
const obj = {
    id: 5,
    name: 'San Francisco',
    [getKey('enabled')]: true,
};

// bad
const atom = {
    value: 1,

    addValue: function (value) {
    return atom.value + value;
    },
};

// good
const atom = {
    value: 1,

    addValue(value) {
    return atom.value + value;
    },
};

Tại sao? Nó ngắn hơn và rõ ràng hơn.

const lukeSkywalker = 'Luke Skywalker';

// bad
const obj = {
    lukeSkywalker: lukeSkywalker,
};

// good
const obj = {
    lukeSkywalker,
};
  • 3.7 Nhóm các thuộc tính viết tắt của bạn ở đầu khai báo đối tượng.

Tại sao? Để dễ dàng biết thuộc tính nào đang sử dụng cách viết tắt.

const anakinSkywalker = 'Anakin Skywalker';
const lukeSkywalker = 'Luke Skywalker';

// bad
const obj = {
    episodeOne: 1,
    twoJediWalkIntoACantina: 2,
    lukeSkywalker,
    episodeThree: 3,
    mayTheFourth: 4,
    anakinSkywalker,
};

// good
const obj = {
    lukeSkywalker,
    anakinSkywalker,
    episodeOne: 1,
    twoJediWalkIntoACantina: 2,
    episodeThree: 3,
    mayTheFourth: 4,
};

Tại sao? Nói chung chúng tôi coi nó là chủ quan dễ đọc hơn. Nó cải thiện việc tô sáng cú pháp và cũng dễ dàng được tối ưu hóa bởi nhiều công cụ JS.

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

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

Mảng (Arrays)

// bad
const items = new Array();

// good
const items = [];
  • 4.2 Sử dụng Array#push thay vì gán trực tiếp để thêm một mục vào mảng.
const someStack = [];

// bad
someStack[someStack.length] = 'abracadabra';

// good
someStack.push('abracadabra');

  • 4.3 Sử dụng array spreads ... để sao chép mảng.
// bad
const len = items.length;
const itemsCopy = [];
let i;

for (i = 0; i < len; i++) {
    itemsCopy[i] = items[i];
}

// good
const itemsCopy = [...items];
  • 4.4 Để chuyển đổi một đối tượng giống mảng (array-like object) thành một mảng, hãy sử dụng Array#from.
const foo = document.querySelectorAll('.foo');
const nodes = Array.from(foo);
  • 4.5 Sử dụng các câu lệnh return trong các callback của phương thức mảng. Có thể bỏ qua return nếu thân hàm bao gồm một câu lệnh duy nhất theo sau 8.2. eslint: array-callback-return
// good
[1, 2, 3].map((x) => {
    const y = x + 1;
    return x * y;
});

// good
[1, 2, 3].map(x => x + 1);

// bad
const flat = {};
[[0, 1], [2, 3], [4, 5]].reduce((memo, item, index) => {
    const flatten = memo.concat(item);
    flat[index] = memo.concat(item);
});

// good
const flat = {};
[[0, 1], [2, 3], [4, 5]].reduce((memo, item, index) => {
    const flatten = memo.concat(item);
    flat[index] = flatten;
    return flatten;
});

// bad
inbox.filter((msg) => {
    const { subject, author } = msg;
    if (subject === 'Mockingbird') {
    return author === 'Harper Lee';
    } else {
    return false;
    }
});

// good
inbox.filter((msg) => {
    const { subject, author } = msg;
    if (subject === 'Mockingbird') {
    return author === 'Harper Lee';
    }

    return false;
});

Phá vỡ cấu trúc (Destructuring)

  • 5.1 Sử dụng phá vỡ cấu trúc đối tượng khi truy cập và sử dụng nhiều thuộc tính của một đối tượng. jscs: requireObjectDestructuring

Tại sao? Phá vỡ cấu trúc giúp bạn không phải tạo các tham chiếu tạm thời cho các thuộc tính đó.

// bad
function getFullName(user) {
    const firstName = user.firstName;
    const lastName = user.lastName;

    return `${firstName} ${lastName}`;
}

// good
function getFullName(user) {
    const { firstName, lastName } = user;
    return `${firstName} ${lastName}`;
}

// best
function getFullName({ firstName, lastName }) {
    return `${firstName} ${lastName}`;
}
const arr = [1, 2, 3, 4];

// bad
const first = arr[0];
const second = arr[1];

// good
const [first, second] = arr;
  • 5.3 Sử dụng phá vỡ cấu trúc đối tượng cho nhiều giá trị trả về, không phải phá vỡ cấu trúc mảng.

Tại sao? Bạn có thể thêm các thuộc tính mới hoặc thay đổi thứ tự của mọi thứ mà không làm hỏng các nơi gọi.

// bad
function processInput(input) {
    // sau đó một phép màu xảy ra
    return [left, right, top, bottom];
}

// người gọi cần phải suy nghĩ về thứ tự của dữ liệu trả về
const [left, __, top] = processInput(input);

// good
function processInput(input) {
    // sau đó một phép màu xảy ra
    return { left, right, top, bottom };
}

// người gọi chỉ chọn dữ liệu họ cần
const { left, right } = processInput(input);

Chuỗi (Strings)

// bad
const name = "Capt. Janeway";

// good
const name = 'Capt. Janeway';
  • 6.2 Các chuỗi làm cho dòng vượt quá 100 ký tự không nên được viết trên nhiều dòng bằng cách sử dụng nối chuỗi.
  • 6.3 Lưu ý: Nếu lạm dụng, nối chuỗi dài có thể ảnh hưởng đến hiệu suất. jsPerf & Thảo luận.
// bad
const errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.';

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

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

Tại sao? Template strings cung cấp cho bạn cú pháp ngắn gọn, dễ đọc với các dòng mới phù hợp và các tính năng nội suy chuỗi (string interpolation).

// bad
function sayHi(name) {
    return 'How are you, ' + name + '?';
}

// bad
function sayHi(name) {
    return ['How are you, ', name, '?'].join();
}

// bad
function sayHi(name) {
    return `How are you, ${ name }?`;
}

// good
function sayHi(name) {
    return `How are you, ${name}?`;
}
  • 6.5 Không bao giờ sử dụng eval() trên một chuỗi, nó mở ra quá nhiều lỗ hổng.

Hàm (Functions)

Tại sao? Khai báo hàm có tên, vì vậy chúng dễ nhận biết hơn trong stack traces. Ngoài ra, khai báo hàm được hoisted (đưa lên đầu), trong khi biểu thức hàm thì không. Quy tắc này giúp cho Arrow Functions có thể thay thế hoàn toàn biểu thức hàm.

// bad
const foo = function () {
};

// good
function foo() {
}

Tại sao? IIFE là một đơn vị duy nhất - bao gồm cả hàm và lệnh gọi của nó trong dấu ngoặc đơn làm cho điều này rõ ràng. Lưu ý rằng trong thế giới mô-đun, bạn thường không cần IIFEs nữa.

// immediately-invoked function expression (IIFE)
(function () {
    console.log('Welcome to the Internet. Please follow me.');
}());
  • 7.3 Không bao giờ khai báo một hàm 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 sẽ cho phép bạn làm điều đó, nhưng tất cả chúng đều diễn giải nó theo cách khác nhau. eslint: no-loop-func

  • 7.4 Lưu ý: ECMA-262 định nghĩa block là một danh sách các câu lệnh (statements). Một khai báo hàm không phải là một câu lệnh. Đọc ghi chú của ECMA-262 về vấn đề này.

// bad
if (currentUser) {
    function test() {
    console.log('Nope.');
    }
}

// good
let test;
if (currentUser) {
    test = () => {
    console.log('Yup.');
    };
}
  • 7.5 Không bao giờ đặt tên tham số là arguments. Điều 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.
// bad
function nope(name, options, arguments) {
    // ...stuff...
}

// good
function yup(name, options, args) {
    // ...stuff...
}

  • 7.6 Không bao giờ sử dụng arguments, chọn sử dụng cú pháp rest ... thay thế. prefer-rest-params

Tại sao? ... rõ ràng về những đối số bạn muốn lấy ra. Thêm vào đó, các đối số rest là một Array thực sự, và không chỉ đơn thuần là Array-like như arguments.

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

// good
function concatenateAll(...args) {
    return args.join('');
}

  • 7.7 Sử dụng cú pháp tham số mặc định thay vì thay đổi các đối số của hàm.
// really bad
function handleThings(opts) {
    // No! We shouldn't mutate function arguments.
    // Double bad: if opts is false it will be set to an object which may
    // be what you want but it can cause subtle bugs.
    opts = opts || {};
    // ...
}

// still bad
function handleThings(opts) {
    if (opts === void 0) {
    opts = {};
    }
    // ...
}

// good
function handleThings(opts = {}) {
    // ...
}
  • 7.8 Tránh các tác dụng phụ (side effects) với các tham số mặc định.

Tại sao? Chung gây nhầm lẫn khi suy luận.

var b = 1;
// bad
function count(a = b++) {
    console.log(a);
}
count();  // 1
count();  // 2
count(3); // 3
count();  // 3
  • 7.9 Luôn đặt các tham số mặc định ở cuối cùng.
// bad
function handleThings(opts = {}, name) {
    // ...
}

// good
function handleThings(name, opts = {}) {
    // ...
}
  • 7.10 Không bao giờ sử dụng Function constructor để tạo một hàm mới.

Tại sao? Tạo một hàm theo cách này đánh giá một chuỗi tương tự như eval(), điều này mở ra các lỗ hổng.

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

// still bad
var subtract = Function('a', 'b', 'return a - b');
  • 7.11 Khoảng cách trong chữ ký hàm (function signature).

Tại sao? Sự nhất quán là tốt, và bạn không nên phải thêm hoặc xóa khoảng trắng khi thêm hoặc xóa tên.

// bad
const f = function(){};
const g = function (){};
const h = function() {};

// good
const x = function () {};
const y = function a() {};

Tại sao? Thao tác các đối tượng được truyền vào dưới dạng tham số có thể gây ra tác dụng phụ biến không mong muốn trong trình gọi ban đầu.

// bad
function f1(obj) {
    obj.key = 1;
};

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

Tại sao? Việc gán lại các tham số có thể dẫn đến hành vi không mong muốn, đặc biệt khi truy cập đối tượng arguments. Nó cũng có thể gây ra các vấn đề tối ưu hóa, đặc biệt là trong V8.

```javascript
// bad
function f1(a) {
a = 1;
}

function f2(a) {
if (!a) { a = 1; }
}

// good
function f3(a) {
const b = a || 1;
}

function f4(a = 1) {
}
```

Arrow Functions

Tại sao? Nó tạo ra một phiên bản của hàm thực thi trong ngữ cảnh của this, thường là những gì bạn muốn, và là một cú pháp ngắn gọn hơn.

Tại sao không? Nếu bạn có một hàm khá phức tạp, di chuyển logic đó ra bên ngoài vào khai báo hàm của riêng nó.

// bad
[1, 2, 3].map(function (x) {
    const y = x + 1;
    return x * y;
});

// good
[1, 2, 3].map((x) => {
    const y = x + 1;
    return x * y;
});

Tại sao? Syntactic sugar (Cú pháp ngọt). Nó dễ đọc khi nhiều hàm được nối với nhau.

Tại sao không? Nếu bạn định trả về một đối tượng.

// bad
[1, 2, 3].map(number => {
    const nextNumber = number + 1;
    `A string containing the ${nextNumber}.`;
});

// good
[1, 2, 3].map(number => `A string containing the ${number}.`);

// good
[1, 2, 3].map((number) => {
    const nextNumber = number + 1;
    return `A string containing the ${nextNumber}.`;
});
  • 8.3 Trong trường hợp biểu thức kéo dài trên nhiều dòng, hãy bao bọc nó trong dấu ngoặc đơn để dễ đọc hơn.

Tại sao? Nó cho thấy rõ nơi hàm bắt đầu và kết thúc.

// bad
[1, 2, 3].map(number => 'As time went by, the string containing the ' +
    `${number} became much longer. So we needed to break it over multiple ` +
    'lines.'
);

// good
[1, 2, 3].map(number => (
    `As time went by, the string containing the ${number} became much ` +
    'longer. So we needed to break it over multiple lines.'
));
  • 8.4 Nếu hàm của bạn lấy một đối số duy nhất và không sử dụng dấu ngoặc nhọn, hãy bỏ qua dấu ngoặc đơn. Nếu không, hãy luôn bao gồm dấu ngoặc đơn xung quanh các đối số. eslint: arrow-parens jscs: disallowParenthesesAroundArrowParam

Tại sao? Ít lộn xộn về mặt thị giác.

// bad
[1, 2, 3].map((x) => x * x);

// good
[1, 2, 3].map(x => x * x);
// good
[1, 2, 3].map(number => (
    `A long string with the ${number}. It’s so long that we’ve broken it ` +
    'over multiple lines!'
));

// bad
[1, 2, 3].map(x => {
    const y = x + 1;
    return x * y;
});

// good
[1, 2, 3].map((x) => {
    const y = x + 1;
    return x * y;
});
  • 8.5 Tránh nhầm lẫn cú pháp arrow function (=>) với các toán tử so sánh (<=, >=). eslint: no-confusing-arrow
// bad
const itemHeight = item => item.height > 256 ? item.largeSize : item.smallSize;

// bad
const itemHeight = (item) => item.height > 256 ? item.largeSize : item.smallSize;

// good
const itemHeight = item => { return item.height > 256 ? item.largeSize : item.smallSize; }

Constructors

  • 9.1 Luôn sử dụng class. Tránh thao túng prototype trực tiếp.

Tại sao? Cú pháp class ngắn gọn hơn và dễ suy luận hơn.

// bad
function Queue(contents = []) {
    this._queue = [...contents];
}
Queue.prototype.pop = function () {
    const value = this._queue[0];
    this._queue.splice(0, 1);
    return value;
}


// good
class Queue {
    constructor(contents = []) {
    this._queue = [...contents];
    }
    pop() {
    const value = this._queue[0];
    this._queue.splice(0, 1);
    return value;
    }
}
  • 9.2 Sử dụng extends để kế thừa.

Tại sao? Đây là một cách tích hợp để kế thừa chức năng từ một nguyên mẫu (prototype) mà không phá vỡ instanceof.

// bad
const inherits = require('inherits');
function PeekableQueue(contents) {
    Queue.apply(this, contents);
}
inherits(PeekableQueue, Queue);
PeekableQueue.prototype.peek = function () {
    return this._queue[0];
}

// good
class PeekableQueue extends Queue {
    peek() {
    return this._queue[0];
    }
}
  • 9.3 Các phương thức có thể trả về this để giúp việc nối chuỗi phương thức (method chaining).
// bad
Jedi.prototype.jump = function () {
    this.jumping = true;
    return true;
};

Jedi.prototype.setHeight = function (height) {
    this.height = height;
};

const luke = new Jedi();
luke.jump(); // => true
luke.setHeight(20); // => undefined

// good
class Jedi {
    jump() {
    this.jumping = true;
    return this;
    }

    setHeight(height) {
    this.height = height;
    return this;
    }
}

const luke = new Jedi();

luke.jump()
    .setHeight(20);
  • 9.4 Không sao khi viết một phương thức toString() tùy chỉnh, chỉ cần đảm bảo rằng nó hoạt động thành công và không gây ra tác dụng phụ.
class Jedi {
    constructor(options = {}) {
    this.name = options.name || 'no name';
    }

    getName() {
    return this.name;
    }

    toString() {
    return `Jedi - ${this.getName()}`;
    }
}
  • 9.5 Các lớp có một constructor mặc định nếu không có constructor nào được chỉ định. Một constructor trống hoặc chỉ ủy quyền cho một lớp cha là không cần thiết. no-useless-constructor
// bad
class Jedi {
    constructor() {}

    getName() {
    return this.name;
    }
}

// bad
class Rey extends Jedi {
    constructor(...args) {
    super(...args);
    }
}

// good
class Rey extends Jedi {
    constructor(...args) {
    super(...args);
    this.name = 'Rey';
    }
}

Mô-đun (Modules)

  • 10.1 Luôn sử dụng các mô-đun (import/export) thay vì hệ thống mô-đun không chuẩn. Bạn luôn có thể chuyển đổi (transpile) sang hệ thống mô-đun ưa thích của bạn.

Tại sao? Các mô-đun là tương lai, hãy bắt đầu sử dụng tương lai ngay bây giờ.

// bad
const AirbnbStyleGuide = require('./AirbnbStyleGuide');
module.exports = AirbnbStyleGuide.es6;

// ok
import AirbnbStyleGuide from './AirbnbStyleGuide';
export default AirbnbStyleGuide.es6;

// best
import { es6 } from './AirbnbStyleGuide';
export default es6;
  • 10.2 Không sử dụng wildcard imports (import ký tự đại diện).

Tại sao? Điều này đảm bảo bạn có một default export duy nhất.

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

// good
import AirbnbStyleGuide from './AirbnbStyleGuide';
  • 10.3 Và không export trực tiếp từ một import.

Tại sao? Mặc dù viết một dòng ngắn gọn, nhưng có một cách rõ ràng để import và export mọi thứ làm cho mọi thứ nhất quán.

// bad
// filename es6.js
export { es6 as default } from './airbnbStyleGuide';

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

Iterators và Generators

  • 11.1 Đừng sử dụng iterators. Ưu tiên các hàm bậc cao của JavaScript như map()reduce() thay vì các vòng lặp như for-of. eslint: no-iterator

Tại sao? Điều này thực thi quy tắc bất biến (immutable) của chúng tôi. Làm việc với các hàm thuần túy trả về giá trị dễ suy luận hơn các tác dụng phụ.

eslint rules: no-iterator.

const numbers = [1, 2, 3, 4, 5];

// bad
let sum = 0;
for (let num of numbers) {
    sum += num;
}

sum === 15;

// good
let sum = 0;
numbers.forEach(num => sum += num);
sum === 15;

// best (use the functional force)
const sum = numbers.reduce((total, num) => total + num, 0);
sum === 15;
  • 11.2 Đừng sử dụng generators vào lúc này.

Tại sao? Chúng chưa chuyển đổi tốt sang ES5.

Thuộc tính (Properties)

const luke = {
    jedi: true,
    age: 28,
};

// bad
const isJedi = luke['jedi'];

// good
const isJedi = luke.jedi;
  • 12.2 Sử dụng bracket notation (ký hiệu ngoặc vuông) [] khi truy cập các thuộc tính bằng một biến.
const luke = {
    jedi: true,
    age: 28,
};

function getProp(prop) {
    return luke[prop];
}

const isJedi = getProp('jedi');

Biến (Variables)

  • 13.1 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 (global variables). Chúng tôi muốn tránh làm ô nhiễm không gian tên toàn cục (global namespace). Captain Planet đã cảnh báo chúng tôi về điều đó.
// bad
superPower = new SuperPower();

// good
const superPower = new SuperPower();

Tại sao? Dễ dàng hơn để thêm các khai báo biến mới theo cách này, và bạn không bao giờ phải lo lắng về việc hoán đổi một ; cho một , hoặc giới thiệu các sự khác biệt chỉ do dấu câu.

// bad
const items = getItems(),
    goSportsTeam = true,
    dragonball = 'z';

// bad
// (compare to above, notice the error)
const items = getItems(),
    goSportsTeam = true;
    dragonball = 'z';

// good
const items = getItems();
const goSportsTeam = true;
const dragonball = 'z';
  • 13.3 Nhóm tất cả các const của bạn và sau đó nhóm tất cả các let của bạn.

Tại sao? Điều này hữu ích khi sau này bạn có thể cần gán một biến phụ thuộc vào một trong các biến được gán trước đó.

// bad
let i, len, dragonball,
    items = getItems(),
    goSportsTeam = true;

// bad
let i;
const items = getItems();
let dragonball;
const goSportsTeam = true;
let len;

// good
const goSportsTeam = true;
const items = getItems();
let dragonball;
let i;
let length;
  • 13.4 Gán các biến ở nơi bạn cần chúng, nhưng đặt chúng ở một nơi hợp lý.

Tại sao? letconst là block scoped (phạm vi khối) và không phải function scoped (phạm vi hàm).

// bad - unnecessary function call
function checkName(hasName) {
    const name = getName();

    if (hasName === 'test') {
    return false;
    }

    if (name === 'test') {
    this.setName('');
    return false;
    }

    return name;
}

// good
function checkName(hasName) {
    if (hasName === 'test') {
    return false;
    }

    const name = getName();

    if (name === 'test') {
    this.setName('');
    return false;
    }

    return name;
}

Hoisting

  • 14.1 Các khai báo var được hoisted lên đầu phạm vi của chúng, nhưng việc gán của chúng thì không. Các khai báo constlet được ban phước với một khái niệm mới gọi là Temporal Dead Zones (TDZ). Điều quan trọng là phải biết tại sao typeof không còn an toàn nữa.
// we know this wouldn't work (assuming there
// is no notDefined global variable)
function example() {
    console.log(notDefined); // => throws a ReferenceError
}

// creating a variable declaration after you
// reference the variable will work due to
// variable hoisting. Note: the assignment
// value of `true` is not hoisted.
function example() {
    console.log(declaredButNotAssigned); // => undefined
    var declaredButNotAssigned = true;
}

// The interpreter is hoisting the variable
// declaration to the top of the scope,
// which means our example could be rewritten as:
function example() {
    let declaredButNotAssigned;
    console.log(declaredButNotAssigned); // => undefined
    declaredButNotAssigned = true;
}

// using const and let
function example() {
    console.log(declaredButNotAssigned); // => throws a ReferenceError
    console.log(typeof declaredButNotAssigned); // => throws a ReferenceError
    const declaredButNotAssigned = true;
}
  • 14.2 Anonymous function expressions hoist tên biến của chúng, nhưng không hoist phép gán hàm.
function example() {
    console.log(anonymous); // => undefined

    anonymous(); // => TypeError anonymous is not a function

    var anonymous = function () {
    console.log('anonymous function expression');
    };
}
  • 14.3 Named function expressions hoist tên biến, không phải tên hàm hoặc thân hàm.
function example() {
    console.log(named); // => undefined

    named(); // => TypeError named is not a function

    superPower(); // => ReferenceError superPower is not defined

    var named = function superPower() {
    console.log('Flying');
    };
}

// the same is true when the function name
// is the same as the variable name.
function example() {
    console.log(named); // => undefined

    named(); // => TypeError named is not a function

    var named = function named() {
    console.log('named');
    }
}
  • 14.4 Function declarations hoist tên và thân hàm của chúng.
function example() {
    superPower(); // => Flying

    function superPower() {
    console.log('Flying');
    }
}

Toán tử so sánh & Đẳng thức (Comparison Operators & Equality)

  • 15.1 Sử dụng ===!== thay vì ==!=. eslint: eqeqeq

  • 15.2 Các câu lệnh điều kiện như câu lệnh if đánh giá biểu thức của chúng bằng cách ép buộc (coercion) với phương thức trừu tượng ToBoolean và luôn tuân theo các quy tắc đơn giản sau:

  • Objects đánh giá là true
  • Undefined đánh giá là false
  • Null đánh giá là false
  • Booleans đánh giá là giá trị của boolean
  • Numbers đánh giá là false nếu là +0, -0, hoặc NaN, ngược lại là true
  • Strings đánh giá là false nếu là một chuỗi rỗng '', ngược lại là true
if ([0] && []) {
    // true
    // an array (even an empty one) is an object, objects will evaluate to true
}
  • 15.3 Sử dụng phím tắt.
// bad
if (name !== '') {
    // ...stuff...
}

// good
if (name) {
    // ...stuff...
}

// bad
if (collection.length > 0) {
    // ...stuff...
}

// good
if (collection.length) {
    // ...stuff...
}
  • 15.4 Để biết thêm thông tin, xem Truth Equality and JavaScript bởi Angus Croll.
  • 15.5 Sử dụng dấu ngoặc nhọn để tạo các khối trong mệnh đề casedefault có chứa các khai báo lexical (ví dụ: let, const, function, và class).

Tại sao? Các khai báo lexical hiển thị trong toàn bộ khối switch nhưng chỉ được khởi tạo khi được gán, điều này chỉ xảy ra khi đạt đến case của nó. Điều này gây ra vấn đề khi nhiều mệnh đề case cố gắng định nghĩa cùng một thứ.

eslint rules: no-case-declarations.

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

// good
switch (foo) {
    case 1: {
    let x = 1;
    break;
    }
    case 2: {
    const y = 2;
    break;
    }
    case 3: {
    function f() {}
    break;
    }
    case 4:
    bar();
    break;
    default: {
    class C {}
    }
}
  • 15.7 Ternaries không nên lồng nhau và thường là các biểu thức một dòng.

eslint rules: no-nested-ternary.

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

// better
const maybeNull = value1 > value2 ? 'baz' : null;

const foo = maybe1 > maybe2
    ? 'bar'
    : maybeNull;

// best
const maybeNull = value1 > value2 ? 'baz' : null;

const foo = maybe1 > maybe2 ? 'bar' : maybeNull;
  • 15.8 Tránh các câu lệnh ternary không cần thiết.

eslint rules: no-unneeded-ternary.

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

// good
const foo = a || b;
const bar = !!c;
const baz = !c;

Khối (Blocks)

  • 16.1 Sử dụng dấu ngoặc nhọn với tất cả các khối nhiều dòng.
// bad
if (test)
    return false;

// good
if (test) return false;

// good
if (test) {
    return false;
}

// bad
function foo() { return false; }

// good
function bar() {
    return false;
}
// bad
if (test) {
    thing1();
    thing2();
}
else {
    thing3();
}

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

Các câu lệnh điều khiển (Control Statements)

  • 17.1 Trong trường hợp câu lệnh điều khiển của bạn (if, while, v.v.) quá dài hoặc vượt quá độ dài dòng tối đa, mỗi điều kiện (được nhóm) có thể được đặt vào một dòng mới. Toán tử logic nên bắt đầu dòng.

Tại sao? Yêu cầu các toán tử ở đầu dòng giữ cho các toán tử được căn chỉnh và tuân theo một mẫu tương tự như nối chuỗi phương thức. Điều này cũng cải thiện khả năng đọc bằng cách làm cho logic phức tạp dễ theo dõi hơn bằng mắt thường.

// bad
if ((foo === 123 || bar === 'abc') && doesItLookGoodWhenItBecomesThatLong() && isThisReallyHappening()) {
    thing1();
}

// bad
if (foo === 123 &&
    bar === 'abc') {
    thing1();
}

// bad
if (foo === 123
    && bar === 'abc') {
    thing1();
}

// bad
if (
    foo === 123 &&
    bar === 'abc'
) {
    thing1();
}

// good
if (
    foo === 123
    && bar === 'abc'
) {
    thing1();
}

// good
if (
    (foo === 123 || bar === 'abc')
    && doesItLookGoodWhenItBecomesThatLong()
    && isThisReallyHappening()
) {
    thing1();
}

// good
if (foo === 123 && bar === 'abc') {
    thing1();
}
  • 17.2 Đừng sử dụng toán tử lựa chọn thay cho câu lệnh điều khiển.
// bad
!isRunning && startRunning();

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

Bình luận (Comments)

  • 18.1 Sử dụng /** ... */ cho các bình luận nhiều dòng. Bao gồm mô tả, chỉ định kiểu và giá trị cho tất cả các tham số và giá trị trả về.
// bad
// make() returns a new element
// based on the passed in tag name
//
// @param {String} tag
// @return {Element} element
function make(tag) {

    // ...stuff...

    return element;
}

// good
/**
 * make() returns a new element
 * based on the passed in tag name
 *
 * @param {String} tag
 * @return {Element} element
 */
function make(tag) {

    // ...stuff...

    return element;
}
  • 18.2 Sử dụng // cho các bình luận một dòng. Đặt các bình luận một dòng trên một dòng mới phía trên chủ đề của bình luận. Đặt một dòng trống trước bình luận trừ khi nó ở dòng đầu tiên của khối.
// bad
const active = true;  // is current tab

// good
// is current tab
const active = true;

// bad
function getType() {
    console.log('fetching type...');
    // set the default type to 'no type'
    const type = this._type || 'no type';

    return type;
}

// good
function getType() {
    console.log('fetching type...');

    // set the default type to 'no type'
    const type = this._type || 'no type';

    return type;
}

// also good
function getType() {
    // set the default type to 'no type'
    const type = this._type || 'no type';

    return type;
}
  • 18.3 Tiền tố các bình luận của bạn với FIXME hoặc TODO giúp các nhà phát triển khác nhanh chóng hiểu nếu bạn đang chỉ ra một vấn đề cần được xem xét lại hoặc nếu bạn đang đề xuất một giải pháp cần được thực hiện. Những điều này khác với các bình luận thông thường vì chúng có thể hành động được. Các hành động là FIXME: -- need to figure this out hoặc TODO: -- need to implement.

  • 18.4 Sử dụng // FIXME: để chú thích các vấn đề.

class Calculator extends Abacus {
    constructor() {
    super();

    // FIXME: shouldn't use a global here
    total = 0;
    }
}
  • 18.5 Sử dụng // TODO: để chú thích các giải pháp cho các vấn đề.
class Calculator extends Abacus {
    constructor() {
    super();

    // TODO: total should be configurable by an options param
    this.total = 0;
    }
}

Khoảng trắng (Whitespace)

  • 19.1 Sử dụng dấu tab mềm (ký tự khoảng trắng) được đặt thành 2 khoảng trắng. eslint: indent jscs: validateIndentation
// bad
function foo() {
∙∙∙∙const name;
}

// bad
function bar() {
const name;
}

// good
function baz() {
∙∙const name;
}
// bad
function test(){
    console.log('test');
}

// good
function test() {
    console.log('test');
}

// bad
dog.set('attr',{
    age: '1 year',
    breed: 'Bernese Mountain Dog',
});

// good
dog.set('attr', {
    age: '1 year',
    breed: 'Bernese Mountain Dog',
});
// bad
if(isJedi) {
    fight ();
}

// good
if (isJedi) {
    fight();
}

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

// good
function fight() {
    console.log('Swooosh!');
}
// bad
const x=y+5;

// good
const x = y + 5;
  • 19.5 Kết thúc tệp bằng một ký tự dòng mới (newline character).
// bad
(function (global) {
    // ...stuff...
})(this);
// bad
(function (global) {
    // ...stuff...
})(this);

// good
(function (global) {
    // ...stuff...
})(this);
  • 19.6 Sử dụng thụt đầu dòng khi thực hiện chuỗi phương thức dài (hơn 2 chuỗi phương thức). Sử dụng dấu chấm ở đầu, nhấn mạnh rằng dòng đó là một cuộc gọi phương thức, không phải là một câu lệnh mới. eslint: newline-per-chained-call no-whitespace-before-property
// bad
$('#items').find('.selected').highlight().end().find('.open').updateCount();

// bad
$('#items').
    find('.selected').
    highlight().
    end().
    find('.open').
    updateCount();

// good
$('#items')
    .find('.selected')
    .highlight()
    .end()
    .find('.open')
    .updateCount();

// bad
const leds = stage.selectAll('.led').data(data).enter().append('svg:svg').classed('led', true)
    .attr('width', (radius + margin) * 2).append('svg:g')
    .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
    .call(tron.led);

// good
const leds = stage.selectAll('.led')
    .data(data)
    .enter().append('svg:svg')
    .classed('led', true)
    .attr('width', (radius + margin) * 2)
    .append('svg:g')
    .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
    .call(tron.led);

// good
const leds = stage.selectAll('.led').data(data);
// bad
if (foo) {
    return bar;
}
return baz;

// good
if (foo) {
    return bar;
}

return baz;

// bad
const obj = {
    foo() {
    },
    bar() {
    },
};
return obj;

// good
const obj = {
    foo() {
    },

    bar() {
    },
};

return obj;

// bad
const arr = [
    function foo() {
    },
    function bar() {
    },
];
return arr;

// good
const arr = [
    function foo() {
    },

    function bar() {
    },
];

return arr;
// bad
function bar() {

    console.log(foo);

}

// also bad
if (baz) {

    console.log(qux);
} else {
    console.log(foo);

}

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

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

// good
function bar(foo) {
    return foo;
}

// bad
if ( foo ) {
    console.log(foo);
}

// good
if (foo) {
    console.log(foo);
}
// bad
const foo = [ 1, 2, 3 ];
console.log(foo[ 0 ]);

// good
const foo = [1, 2, 3];
console.log(foo[0]);
// bad
const foo = {clark: 'kent'};

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

Tại sao? Điều này đảm bảo khả năng đọc và khả năng bảo trì.

// bad
const foo = 'Whatever national crop flips the window. The cartoon reverts within the screw. Whatever wizard constrains a helpful ally. The counterpart ascends!';

// bad
$.ajax({ method: 'POST', url: 'https://airbnb.com/', data: { name: 'John' } }).done(() => console.log('Congratulations!')).fail(() => console.log('You have failed this city.'));

// good
const foo = 'Whatever national crop flips the window. The cartoon reverts within the screw. ' +
    'Whatever wizard constrains a helpful ally. The counterpart ascends!';

// good
$.ajax({
    method: 'POST',
    url: 'https://airbnb.com/',
    data: { name: 'John' },
})
    .done(() => console.log('Congratulations!'))
    .fail(() => console.log('You have failed this city.'));

Dấu phẩy (Commas)

// bad
const story = [
    once
    , upon
    , aTime
];

// good
const story = [
    once,
    upon,
    aTime,
];

// bad
const hero = {
    firstName: 'Ada'
    , lastName: 'Lovelace'
    , birthYear: 1815
    , superPower: 'computers'
};

// good
const hero = {
    firstName: 'Ada',
    lastName: 'Lovelace',
    birthYear: 1815,
    superPower: 'computers',
};

Tại sao? Điều này dẫn đến chênh lệch git rõ ràng hơn. Ngoài ra, các bộ chuyển đổi mã nguồn (transpilers) như Babel sẽ loại bỏ dấu phẩy cuối cùng bổ sung trong mã đã chuyển đổi, có nghĩa là bạn không phải lo lắng về vấn đề dấu phẩy cuối cùng trong các trình duyệt cũ.

// bad - git diff without trailing comma
const hero = {
        firstName: 'Florence',
    lastName: 'Nightingale'
+    lastName: 'Nightingale',
+    inventorOf: ['coxcomb graph', 'modern nursing']
};

// good - git diff with trailing comma
const hero = {
        firstName: 'Florence',
        lastName: 'Nightingale',
+    inventorOf: ['coxcomb chart', 'modern nursing'],
};

// bad
const hero = {
    firstName: 'Dana',
    lastName: 'Scully'
};

const heroes = [
    'Batman',
    'Superman'
];

// good
const hero = {
    firstName: 'Dana',
    lastName: 'Scully',
};

const heroes = [
    'Batman',
    'Superman',
];

Dấu chấm phẩy (Semicolons)

// bad
(function () {
    const name = 'Skywalker'
    return name
})()

// good
(() => {
    const name = 'Skywalker';
    return name;
}());

// good (guards against the function becoming an argument when two files with IIFEs are concatenated)
;(() => {
    const name = 'Skywalker';
    return name;
}());

Đọc thêm.

Ép kiểu & Coercion (Type Casting & Coercion)

  • 22.1 Thực hiện ép kiểu ở đầu câu lệnh.
  • 22.2 Chuỗi (Strings):
// => this.reviewScore = 9;

// bad
const totalScore = this.reviewScore + '';

// good
const totalScore = String(this.reviewScore);
  • 22.3 Số (Numbers): Sử dụng Number để ép kiểu và parseInt luôn đi kèm với cơ số (radix) để phân tích chuỗi. eslint: radix
const inputValue = '4';

// bad
const val = new Number(inputValue);

// bad
const val = +inputValue;

// bad
const val = inputValue >> 0;

// bad
const val = parseInt(inputValue);

// good
const val = Number(inputValue);

// good
const val = parseInt(inputValue, 10);
  • 22.4 Nếu vì lý do nào đó bạn đang làm điều gì đó hoang dã và parseInt là nút cổ chai của bạn và cần sử dụng Bitshift vì lý do hiệu suất, hãy để lại bình luận giải thích lý do tại sao và bạn đang làm gì.
// good
/**
 * parseInt was the reason my code was slow.
 * Bitshifting the String to coerce it to a
 * Number made it a lot faster.
 */
const val = inputValue >> 0;
  • 22.5 Lưu ý: Hãy cẩn thận khi sử dụng các phép toán bitshift. Các số được biểu diễn dưới dạng giá trị 64-bit, nhưng các phép toán bitshift luôn trả về số nguyên 32-bit (nguồn). Bitshift có thể dẫn đến hành vi không mong muốn đối với các giá trị số nguyên lớn hơn 32 bit. Thảo luận. Số nguyên có dấu 32-bit lớn nhất là 2,147,483,647:
2147483647 >> 0 //=> 2147483647
2147483648 >> 0 //=> -2147483648
2147483649 >> 0 //=> -2147483647
const age = 0;

// bad
const hasAge = new Boolean(age);

// good
const hasAge = Boolean(age);

// good
const hasAge = !!age;

Quy ước đặt tên (Naming Conventions)

  • 23.1 Tránh tên biến một chữ cái. Hãy mô tả với việc đặt tên của bạn.
// bad
function q() {
    // ...stuff...
}

// good
function query() {
    // ..stuff..
}
// bad
const OBJEcttsssss = {};
const this_is_my_object = {};
function c() {}

// good
const thisIsMyObject = {};
function thisIsMyFunction() {}
// bad
function user(options) {
    this.name = options.name;
}

const bad = new user({
    name: 'nope',
});

// good
class User {
    constructor(options) {
    this.name = options.name;
    }
}

const good = new User({
    name: 'yup',
});
// bad
this.__firstName__ = 'Panda';
this.firstName_ = 'Panda';

// good
this._firstName = 'Panda';
  • 23.5 Đừng lưu tham chiếu đến this. Sử dụng arrow functions hoặc Function#bind. jscs: disallowNodeTypes
// bad
function foo() {
    const self = this;
    return function () {
    console.log(self);
    };
}

// bad
function foo() {
    const that = this;
    return function () {
    console.log(that);
    };
}

// good
function foo() {
    return () => {
    console.log(this);
    };
}
  • 23.6 Nếu tệp của bạn export một lớp duy nhất, tên tệp của bạn phải khớp chính xác với tên lớp đó.
// file contents
class CheckBox {
    // ...
}
export default CheckBox;

// in some other file
// bad
import CheckBox from './checkBox';

// bad
import CheckBox from './check_box';

// good
import CheckBox from './CheckBox';
  • 23.7 Sử dụng camelCase khi bạn export-default một hàm. Tên tệp của bạn phải giống hệt với tên hàm của bạn.
function makeStyleGuide() {
}

export default makeStyleGuide;
  • 23.8 Sử dụng PascalCase khi bạn export một singleton / thư viện hàm / đối tượng trần (bare object).
const AirbnbStyleGuide = {
    es6: {
    }
};

export default AirbnbStyleGuide;

Accessors

  • 24.1 Các hàm truy cập (Accessor functions) cho các thuộc tính là không bắt buộc.
  • 24.2 Đừng sử dụng JavaScript getters/setters vì chúng gây ra các tác dụng phụ không mong muốn và khó kiểm thử, bảo trì và lý luận. Thay vào đó, nếu bạn tạo các hàm truy cập, hãy sử dụng getVal() và setVal(‘hello’).
// bad
dragon.age();

// good
dragon.getAge();

// bad
dragon.age(25);

// good
dragon.setAge(25);
  • 24.3 Nếu thuộc tính là boolean, hãy sử dụng isVal() hoặc hasVal().
// bad
if (!dragon.age()) {
    return false;
}

// good
if (!dragon.hasAge()) {
    return false;
}
  • 24.4 Không sao khi tạo các hàm get() và set(), nhưng hãy nhất quán.
class Jedi {
    constructor(options = {}) {
    const lightsaber = options.lightsaber || 'blue';
    this.set('lightsaber', lightsaber);
    }

    set(key, val) {
    this[key] = val;
    }

    get(key) {
    return this[key];
    }
}

Sự kiện (Events)

  • 25.1 Khi đính kèm dữ liệu (payloads) vào các sự kiện (cho dù là sự kiện DOM hoặc thứ gì đó độc quyền hơn như sự kiện Backbone), hãy truyền một mã băm (hash) thay vì một giá trị thô. Điều này cho phép một người đóng góp tiếp theo thêm nhiều dữ liệu hơn vào payload sự kiện mà không cần tìm và cập nhật mọi trình xử lý cho sự kiện. Ví dụ, thay vì:
// bad
$(this).trigger('listingUpdated', listing.id);

...

$(this).on('listingUpdated', (e, listingId) => {
    // do something with listingId
});

thích:

// good
$(this).trigger('listingUpdated', { listingId: listing.id });

...

$(this).on('listingUpdated', (e, data) => {
    // do something with data.listingId
});

jQuery

// bad
const sidebar = $('.sidebar');

// good
const $sidebar = $('.sidebar');

// good
const $sidebarBtn = $('.sidebar-btn');
  • 26.2 Cache các truy vấn jQuery (jQuery lookups).
// bad
function setSidebar() {
    $('.sidebar').hide();

    // ...stuff...

    $('.sidebar').css({
    'background-color': 'pink'
    });
}

// good
function setSidebar() {
    const $sidebar = $('.sidebar');
    $sidebar.hide();

    // ...stuff...

    $sidebar.css({
    'background-color': 'pink'
    });
}
  • 26.3 Đối với các truy vấn DOM, sử dụng Cascading $('.sidebar ul') hoặc parent > child $('.sidebar > ul'). jsPerf
  • 26.4 Sử dụng find với phạm vi truy vấn đối tượng jQuery.
// bad
$('ul', '.sidebar').hide();

// bad
$('.sidebar').find('ul').hide();

// good
$('.sidebar ul').hide();

// good
$('.sidebar > ul').hide();

// good
$sidebar.find('ul').hide();

Tương thích ECMAScript 5 (ECMAScript 5 Compatibility)

Phong cách ECMAScript 6 (ECMAScript 6 Styles)

  • 28.1 Đây là một tập hợp các liên kết đến các tính năng ES6 khác nhau.
  1. Arrow Functions
  2. Classes
  3. Object Shorthand
  4. Object Concise
  5. Computed Object Properties
  6. Template Strings
  7. Destructuring
  8. Default Parameters
  9. Rest
  10. Array Spreads
  11. Let and Const
  12. Iterators and Generators
  13. Modules

Thư viện chuẩn (Standard Library)

Thư viện chuẩn chứa một số tiện ích bị hỏng nhưng để lại vì lý do kế thừa.

  • 29.1 Sử dụng Number.isNaN thay vì isNaN.

Tại sao? isNaN ép buộc các giá trị không phải số thành số, trả về true cho bất cứ thứ gì ép buộc thành NaN. Nếu hành vi này là mong muốn, hãy làm cho nó rõ ràng.

// bad
isNaN('1.2'); // false
isNaN('1.2.3'); // true

// good
Number.isNaN('1.2.3'); // false
Number.isNaN(Number('1.2.3')); // true
  • 29.2 Sử dụng Number.isFinite thay vì isFinite.

Tại sao? isFinite ép buộc các giá trị không phải số thành đố, trả về true cho bất cứ thứ gì ép buộc thành một số hữu hạn. Nếu hành vi này là mong muốn, hãy làm cho nó rõ ràng.

// bad
isFinite('2e3'); // true

// good
Number.isFinite('2e3'); // false
Number.isFinite(parseInt('2e3', 10)); // true

Kiểm thử (Testing)

function foo() {
    return true;
}
  • 30.2 Không, nghiêm túc đấy:
  • Cho dù bạn sử dụng khung kiểm thử nào, bạn cũng nên viết các bài kiểm tra!
  • Cố gắng viết nhiều hàm thuần túy nhỏ (pure functions), và tối thiểu hóa sự thay đổi (mutation).
  • Hãy cẩn thận với stubs và mocks - chúng có thể làm cho các bài kiểm tra của bạn dễ vỡ hơn.
  • Chúng tôi chủ yếu sử dụng mocha tại Airbnb. tape cũng được sử dụng thỉnh thoảng cho các mô-đun nhỏ, riêng biệt.
  • 100% độ bao phủ kiểm thử là một mục tiêu tốt để phấn đấu, ngay cả khi nó không phải lúc nào cũng thực tế để đạt được.
  • Bất cứ khi nào bạn sửa lỗi, hãy viết bài kiểm tra hồi quy (regression test). Một lỗi được sửa mà không có bài kiểm tra hồi quy gần như chắc chắn sẽ bị hỏng lại trong tương lai.

Hiệu suất (Performance)

Tài nguyên (Resources)

Học ES6

Nên đọc

Công cụ

  • Code Style Linters

Các hướng dẫn phong cách khác

Phong cách khác

Đọc thêm

Sách

Blogs

Podcasts

Trong thế giới thực (In the Wild)

Đây là danh sách các tổ chức sử dụng hướng dẫn phong cách này. Gửi cho chúng tôi một pull request hoặc một issue và chúng tôi sẽ thêm bạn vào danh sách.

Bản dịch (Translation)

Hướng dẫn phong cách này cũng có sẵn trong các ngôn ngữ khác:

Hướng dẫn về Hướng dẫn kiểu JavaScript (The JavaScript Style Guide Guide)

Trò chuyện với chúng tôi về JavaScript

  • Tìm chúng tôi trên gitter.

Những người đóng góp (Contributors)

Giấy phép (License)

(The MIT License)

Copyright (c) 2014-2016 Airbnb

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ‘Software’), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Amendments

Chúng tôi khuyến khích bạn fork hướng dẫn này và thay đổi các quy tắc để phù hợp với hướng dẫn phong cách của nhóm bạn. Dưới đây, bạn có thể liệt kê một số sửa đổi cho hướng dẫn phong cách. Điều này cho phép bạn định kỳ cập nhật hướng dẫn phong cách của mình mà không cần phải giải quyết xung đột hợp nhất (merge conflicts).

Reference

All rights reserved,未經允許不得隨意轉載
Built with Hugo
Theme Stack thiết kế bởi Jimmy