Javascript
Một cách tiếp cận hợp lý đối với JavaScript - @Airbnb
  • 1.1 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ó.
    • string
    • number
    • boolean
    • null
    • undefined
    • symbol
    1
    const foo = 1;
    2
    let bar = foo;
    3
    4
    bar = 9;
    5
    6
    console.log(foo, bar); // => 1, 9
    Copied!
    • Sự thiếu hỗ trợ cho các Symbol 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.
  • 1.2 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ó.
    • object
    • array
    • function
    1
    const foo = [1, 2];
    2
    const bar = foo;
    3
    4
    bar[0] = 9;
    5
    6
    console.log(foo[0], bar[0]); // => 9, 9
    Copied!
  • 2.1 Sử dụng const đối với tất cả các tham chiếu; tránh sử dụng var. eslint: prefer-const, no-const-assign
    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.
    1
    // không tốt
    2
    var a = 1;
    3
    var b = 2;
    4
    5
    // tốt
    6
    const a = 1;
    7
    const b = 2;
    Copied!
  • 2.2 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
    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.
    1
    // không tốt
    2
    var count = 1;
    3
    if (true) {
    4
    count += 1;
    5
    }
    6
    7
    // tốt, sử dụng let.
    8
    let count = 1;
    9
    if (true) {
    10
    count += 1;
    11
    }
    Copied!
  • 2.3 Lưu ý rằng cả letconst đều thuộc phạm vi khối.
    1
    // const và let chỉ tồn tại trong phạm vi khối tạo ra chúng.
    2
    {
    3
    let a = 1;
    4
    const b = 1;
    5
    }
    6
    console.log(a); // ReferenceError
    7
    console.log(b); // ReferenceError
    Copied!
  • 3.1 Sử dụng cú pháp nguyên văn {} để khởi tạo đối tượng. eslint: no-new-object
    1
    // không tốt
    2
    const item = new Object();
    3
    4
    // tốt
    5
    const item = {};
    Copied!
  • 3.2 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.
    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ỗ.
    1
    function getKey(k) {
    2
    return `tên của thuộc tính là ${k}`;
    3
    }
    4
    5
    // không tốt
    6
    const obj = {
    7
    id: 5,
    8
    name: 'San Francisco',
    9
    };
    10
    obj[getKey('enabled')] = true;
    11
    12
    // tốt
    13
    const obj = {
    14
    id: 5,
    15
    name: 'San Francisco',
    16
    [getKey('enabled')]: true,
    17
    };
    Copied!
  • 3.3 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
    1
    // không tốt
    2
    const atom = {
    3
    value: 1,
    4
    5
    addValue: function (value) {
    6
    return atom.value + value;
    7
    },
    8
    };
    9
    10
    // tốt
    11
    const atom = {
    12
    value: 1,
    13
    14
    addValue(value) {
    15
    return atom.value + value;
    16
    },
    17
    };
    Copied!
  • 3.4 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
    Tại sao? Nó ngắn gọn và súc tích.
    1
    const lukeSkywalker = 'Luke Skywalker';
    2
    3
    // không tốt
    4
    const obj = {
    5
    lukeSkywalker: lukeSkywalker,
    6
    };
    7
    8
    // tốt
    9
    const obj = {
    10
    lukeSkywalker,
    11
    };
    Copied!
  • 3.5 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.
    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.
    1
    const anakinSkywalker = 'Anakin Skywalker';
    2
    const lukeSkywalker = 'Luke Skywalker';
    3
    4
    // không tốt
    5
    const obj = {
    6
    episodeOne: 1,
    7
    twoJediWalkIntoACantina: 2,
    8
    lukeSkywalker,
    9
    episodeThree: 3,
    10
    mayTheFourth: 4,
    11
    anakinSkywalker,
    12
    };
    13
    14
    // tốt
    15
    const obj = {
    16
    lukeSkywalker,
    17
    anakinSkywalker,
    18
    episodeOne: 1,
    19
    twoJediWalkIntoACantina: 2,
    20
    episodeThree: 3,
    21
    mayTheFourth: 4,
    22
    };
    Copied!
  • 3.6 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
    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.
    1
    // không tốt
    2
    const bad = {
    3
    'foo': 3,
    4
    'bar': 4,
    5
    'một-cái-tên': 5,
    6
    };
    7
    8
    // tốt
    9
    const good = {
    10
    foo: 3,
    11
    bar: 4,
    12
    'một-cái-tên': 5,
    13
    };
    Copied!
  • 3.7 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
    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)).
    1
    // không tốt
    2
    console.log(object.hasOwnProperty(key));
    3
    4
    // tốt
    5
    console.log(Object.prototype.hasOwnProperty.call(object, key));
    6
    7
    // tốt nhất
    8
    const has = Object.prototype.hasOwnProperty; // lưu tạm phương thức một lần, dùng cho cả mô-đun.
    9
    /* hoặc */
    10
    import has from 'has'; // https://www.npmjs.com/package/has
    11
    // ...
    12
    console.log(has.call(object, key));
    Copied!
  • 3.8 Ưu tiên sử dụng toán tử liệt kê ... so với 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ỏ
    1
    // rất không tốt
    2
    const original = { a: 1, b: 2 };
    3
    const copy = Object.assign(original, { c: 3 }); // cái này làm biến đổi `original` ಠ_ಠ
    4
    delete copy.a; // cái này cũng vậy
    5
    6
    // không tốt
    7
    const original = { a: 1, b: 2 };
    8
    const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 }
    9
    10
    // tốt
    11
    const original = { a: 1, b: 2 };
    12
    const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 }
    13
    14
    const { a, ...noA } = copy; // noA => { b: 2, c: 3 }
    Copied!
  • 4.1 Sử dụng cú pháp nguyên văn [] để khởi tạo mảng. eslint: no-array-constructor
    1
    // không tốt
    2
    const items = new Array();
    3
    4
    // tốt
    5
    const items = [];
    Copied!
  • 4.2 Sử dụng Array#push, thay vì phép gán, để thêm các mục cho một mảng.
    1
    const someStack = [];
    2
    3
    // không tốt
    4
    someStack[someStack.length] = 'abracadabra';
    5
    6
    // tốt
    7
    someStack.push('abracadabra');
    Copied!
  • 4.3 Sử dụng toán tử liệt kê ... để sao nhanh một mảng.
    1
    // không tốt
    2
    const len = items.length;
    3
    const itemsCopy = [];
    4
    let i;
    5
    6
    for (i = 0; i < len; i += 1) {
    7
    itemsCopy[i] = items[i];
    8
    }
    9
    10
    // tốt
    11
    const itemsCopy = [...items];
    Copied!
  • 4.4 Để 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.
    1
    const foo = document.querySelectorAll('.foo');
    2
    3
    // tốt
    4
    const nodes = Array.from(foo);
    5
    6
    // tốt nhất
    7
    const nodes = [...foo];
    Copied!
  • 4.5 Sử dụng Array.from để chuyển đổi một đối tượng giống-mảng thành một mảng.
    1
    const arrLike = { 0: 'foo', 1: 'bar', 2: 'baz', length: 3 };
    2
    3
    // không tốt
    4
    const arr = Array.prototype.slice.call(arrLike);
    5
    6
    // tốt
    7
    const arr = Array.from(arrLike);
    Copied!
  • 4.6 Sử dụng 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.
    1
    // không tốt
    2
    const baz = [...foo].map(bar);
    3
    4
    // tốt
    5
    const baz = Array.from(foo, bar);
    Copied!
  • 4.7 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. eslint: array-callback-return
    1
    // tốt
    2
    [1, 2, 3].map((x) => {
    3
    const y = x + 1;
    4
    return x * y;
    5
    });
    6
    7
    // tốt
    8
    [1, 2, 3].map(x => x + 1);
    9
    10
    // 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
    11
    [[0, 1], [2, 3], [4, 5]].reduce((acc, item, index) => {
    12
    const flatten = acc.concat(item);
    13
    });
    14
    15
    // tốt
    16
    [[0, 1], [2, 3], [4, 5]].reduce((acc, item, index) => {
    17
    const flatten = acc.concat(item);
    18
    return flatten;
    19
    });
    20
    21
    // không tốt
    22
    inbox.filter((msg) => {
    23
    const { subject, author } = msg;
    24
    if (subject === 'Con chim nhại') {
    25
    return author === 'Harper Lee';
    26
    } else {
    27
    return false;
    28
    }
    29
    });
    30
    31
    // tốt
    32
    inbox.filter((msg) => {
    33
    const { subject, author } = msg;
    34
    if (subject === 'Con chim nhại') {
    35
    return author === 'Harper Lee';
    36
    }
    37
    38
    return false;
    39
    });
    Copied!
  • 4.8 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.
    1
    // không tốt
    2
    const arr = [
    3
    [0, 1], [2, 3], [4, 5],
    4
    ];
    5
    6
    const objectInArray = [{
    7
    id: 1,
    8
    }, {
    9
    id: 2,
    10
    }];
    11
    12
    const numberInArray = [
    13
    1, 2,
    14
    ];
    15
    16
    // tốt
    17
    const arr = [[0, 1], [2, 3], [4, 5]];
    18
    19
    const objectInArray = [
    20
    {
    21
    id: 1,
    22
    },
    23
    {
    24
    id: 2,
    25
    },
    26
    ];
    27
    28
    const numberInArray = [
    29
    1,
    30
    2,
    31
    ];
    Copied!
  • 5.1 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
    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.
    1
    // không tốt
    2
    function getFullName(user) {
    3
    const firstName = user.firstName;
    4
    const lastName = user.lastName;
    5
    6
    return `${firstName} ${lastName}`;
    7
    }
    8
    9
    // tốt
    10
    function getFullName(user) {
    11
    const { firstName, lastName } = user;
    12
    return `${firstName} ${lastName}`;
    13
    }
    14
    15
    // best
    16
    function getFullName({ firstName, lastName }) {
    17
    return `${firstName} ${lastName}`;
    18
    }
    Copied!
  • 5.2 Hãy sử dụng trích xuất mảng. eslint: prefer-destructuring
    1
    const arr = [1, 2, 3, 4];
    2
    3
    // không tốt
    4
    const first = arr[0];
    5
    const second = arr[1];
    6
    7
    // tốt
    8
    const [first, second] = arr;
    Copied!
  • 5.3 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.
    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 đó.
    1
    // không tốt
    2
    function processInput(input) {
    3
    // khi một phép màu xảy ra
    4
    return [left, right, top, bottom];
    5
    }
    6
    7
    // người gọi cần nghĩ về thứ tự của giá trị trả về
    8
    const [left, __, top] = processInput(input);
    9
    10
    // tốt
    11
    function processInput(input) {
    12
    // khi một phép màu xảy ra
    13
    return { left, right, top, bottom };
    14
    }
    15
    16
    // người gọi chỉ cần chọn giá trị mà họ muốn
    17
    const { left, top } = processInput(input);
    Copied!
  • 6.1 Sử dụng dấu lược cho các chuỗi. eslint: quotes
    1
    // không tốt
    2
    const name = "Capt. Janeway";
    3
    4
    // 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
    5
    const name = `Capt. Janeway`;
    6
    7
    // tốt
    8
    const name = 'Capt. Janeway';
    Copied!
  • 6.2 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.
    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.
    1
    // không tốt
    2
    const errorMessage = 'Đây là một lỗi rất dài mà được ném ra bởi \
    3
    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 \
    4
    quan gì với thứ này, bạn sẽ vẫn chẳng đi đến đâu với \
    5
    đâu.';
    6
    7
    // không tốt
    8
    const errorMessage = 'Đây là một lỗi rất dài mà được ném ra bởi' +
    9
    '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' +
    10
    'quan gì với thứ này, bạn sẽ vẫn chẳng đi đến đâu với' +
    11
    'đâu.';
    12
    13
    // tốt
    14
    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.';
    Copied!
  • 6.3 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 template-curly-spacing
    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.
    1
    // không tốt
    2
    function sayHi(name) {
    3
    return 'Bạn có khỏe không, ' + name + '?';
    4
    }
    5
    6
    // không tốt
    7
    function sayHi(name) {
    8
    return ['Bạn có khỏe không, ', name, '?'].join();
    9
    }
    10
    11
    // tốt
    12
    function sayHi(name) {
    13
    return `Bạn có khỏe không, ${name}?`;
    14
    }
    Copied!
  • 6.4 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
  • 6.5 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
    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.
    1
    // không tốt
    2
    const foo = '\'cái này\' \đư\ợc \"cho trong ngoặc\"';
    3
    4
    // tốt
    5
    const foo = '\'cái này\' được "cho trong ngoặc"';
    6
    const foo = `tên của tôi là '${name}'`;
    Copied!

Các Hàm

  • 7.1 Sử dụng biểu thức hàm hữu danh thay vì khai báo hàm. eslint: func-style
    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)
    1
    // không tốt
    2
    function foo() {
    3
    // ...
    4
    }
    5
    6
    // không tốt
    7
    const foo = function () {
    8
    // ...
    9
    };
    10
    11
    // tốt
    12
    // 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
    13
    const short = function longUniqueMoreDescriptiveLexicalFoo() {
    14
    // ...
    15
    };
    Copied!
  • 7.2 Đặt các biểu thức hàm gọi tức thời trong ngoặc. eslint: wrap-iife
    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.
    1
    // biểu thức hàm gọi tức thời
    2
    (function () {
    3
    console.log('Xin chào đến với thế giới. Hãy đi theo tôi.');
    4
    }());
    Copied!
  • 7.3 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
  • 7.4 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.
    1
    // không tốt
    2
    if (currentUser) {
    3
    function test() {
    4
    console.log('Đừng!');
    5
    }
    6
    }
    7
    8
    // tốt
    9
    let test;
    10
    if (currentUser) {
    11
    test = () => {
    12
    console.log('Tốt đó.');
    13
    };
    14
    }
    Copied!
  • 7.5 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.
    1
    // không tốt
    2
    function foo(name, options, arguments) {
    3
    // ...
    4
    }
    5
    6
    // tốt
    7
    function foo(name, options, args) {
    8
    // ...
    9
    }
    Copied!
  • 7.6 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
    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.
    1
    // không tốt
    2
    function concatenateAll() {
    3
    const args = Array.prototype.slice.call(arguments);
    4
    return args.join('');
    5
    }
    6
    7
    // tốt
    8
    function concatenateAll(...args) {
    9
    return args.join('');
    10
    }
    Copied!
  • 7.7 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.
    1
    // rất tệ
    2
    function handleThings(opts) {
    3
    // Không! Chúng ta không nên biến đổi các đối số.
    4
    // Cái tệ thứ hai: Nếu opts là kiểu sai, nó sẽ bị đổi thành một đối tượng.
    5
    // Đó có thể là điều bạn muốn, nhưng nó thi thoảng gây ra lỗi.
    6
    opts = opts || {};
    7
    // ...
    8
    }
    9
    10
    // vẫn tệ
    11
    function handleThings(opts) {
    12
    if (opts === void 0) {
    13
    opts = {};
    14
    }
    15
    // ...
    16
    }
    17
    18
    // tốt
    19
    function handleThings(opts = {}) {
    20
    // ...
    21
    }
    Copied!
  • 7.8 Tránh gây ra hiệu ứng phụ với tham số mặc định.
    Tại sao? Chúng khá là rối để có thể hình dung.
    1
    var b = 1;
    2
    // không tốt
    3
    function count(a = b++) {
    4
    console.log(a);
    5
    }
    6
    count(); // 1
    7
    count(); // 2
    8
    count(3); // 3
    9
    count(); // 3
    Copied!
  • 7.9 Luôn để các tham số mặc định ở sau cùng.
    1
    // không tốt
    2
    function handleThings(opts = {}, name) {
    3
    // ...
    4
    }
    5
    6
    // tốt
    7
    function handleThings(name, opts = {}) {
    8
    // ...
    9
    }
    Copied!
  • 7.10 Không bao giờ sử dụng hàm tạo Function để tạo hàm. eslint: no-new-func
    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.
    1
    // không tốt
    2
    var add = new Function('a', 'b', 'return a + b');
    3
    4
    // vẫn là không tốt
    5
    var subtract = Function('a', 'b', 'return a - b');
    Copied!
  • 7.11 Sử dụng các dấu cách giữa các bộ phận hàm. eslint: space-before-function-paren space-before-blocks
    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.
    1
    // không tốt
    2
    const f = function(){};
    3
    const g = function (){};
    4
    const h = function() {};
    5
    6
    // tốt
    7
    const x = function () {};
    8
    const y = function a() {};
    Copied!
  • 7.12 Không bao giờ làm biến đổi các tham số. eslint: no-param-reassign
    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.
    1
    // không tốt
    2
    function f1(obj) {
    3
    obj.key = 1;
    4
    }
    5
    6
    // tốt
    7
    function f2(obj) {
    8
    const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1;
    9
    }
    Copied!
  • 7.13 Không bao giờ gán lại các tham số. eslint: no-param-reassign
    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.
    1
    // không tốt
    2
    function f1(a) {
    3
    a = 1;
    4
    // ...
    5
    }
    6
    7
    function f2(a) {
    8
    if (!a) { a = 1; }
    9
    // ...
    10
    }
    11
    12
    // tốt
    13
    function f3(a) {
    14
    const b = a || 1;
    15
    // ...
    16
    }
    17
    18
    function f4(a = 1) {
    19
    // ...
    20
    }
    Copied!
  • 7.14 Ưu tiên sử dụng toán tử liệt kê ... để gọi các hàm bất định. eslint: prefer-spread
    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.
    1
    // không tốt
    2
    const x = [1, 2, 3, 4, 5];
    3
    console.log.apply(console, x);
    4
    5
    // tốt
    6
    const x = [1, 2, 3, 4, 5];
    7
    console.log(...x);
    8
    9
    // không tốt
    10
    new (Function.prototype.bind.apply(Date, [null, 2016, 8, 5]));
    11
    12
    // tốt
    13
    new Date(...[2016, 8, 5]);
    Copied!
  • 7.15 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
    1
    // không tốt
    2
    function foo(bar,
    3
    baz,
    4
    quux) {
    5
    // ...
    6
    }
    7
    8
    // tốt
    9
    function foo(
    10
    bar,
    11
    baz,
    12
    quux,
    13
    ) {
    14
    // ...
    15
    }
    16
    17
    // không tốt
    18
    console.log(foo,
    19
    bar,
    20
    baz);
    21
    22
    // tốt
    23
    console.log(
    24
    foo,
    25
    bar,
    26
    baz,
    27
    );
    Copied!
  • 8.1 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, arrow-spacing
    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.
    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.
    1
    // không tốt
    2
    [1, 2, 3].map(function (x) {
    3
    const y = x + 1;
    4
    return x * y;
    5
    });
    6
    7
    // tốt
    8
    [1, 2, 3].map((x) => {
    9
    const y = x + 1;
    10
    return x * y;
    11
    });
    Copied!
  • 8.2 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 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, arrow-body-style
    Tại sao? Cú pháp tiện lợi. Nó dễ đọc khi nhiều hàm nối chuỗi nhau.
    1
    // không tốt
    2
    [1, 2, 3].map(number => {
    3
    const nextNumber = number + 1;
    4
    `Một chuỗi có chứa số ${nextNumber}.`;
    5
    });
    6
    7
    // tốt
    8
    [1, 2, 3].map(number => `Một chuỗi có chứa số ${number + 1}.`);
    9
    10
    // tốt
    11
    [1, 2, 3].map((number) => {
    12
    const nextNumber = number + 1;
    13
    return `Một chuỗi có chứa số ${nextNumber}.`;
    14
    });
    15
    16
    // tốt
    17
    [1, 2, 3].map((number, index) => ({
    18
    [index]: number,
    19
    }));
    20
    21
    // Không dùng trả về ngầm định khi có hiệu ứng phụ
    22
    function foo(callback) {
    23
    const val = callback();
    24
    if (val === true) {
    25
    // Thực hiện gì đó nếu hàm gọi lại trả về true
    26
    }
    27
    }
    28
    29
    let bool = false;
    30
    31
    // không tốt
    32
    foo(() => bool = true);
    33
    34
    // tốt
    35
    foo(() => {
    36
    bool = true;
    37
    });
    Copied!
  • 8.3 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.
    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.
    1
    // không tốt
    2
    ['get', 'post', 'put'].map(httpMethod => Object.prototype.hasOwnProperty.call(
    3
    httpMagicObjectWithAVeryLongName,
    4
    httpMethod,
    5
    )
    6
    );
    7
    8
    // tốt
    9
    ['get', 'post', 'put'].map(httpMethod => (
    10
    Object.prototype.hasOwnProperty.call(
    11
    httpMagicObjectWithAVeryLongName,
    12
    httpMethod,
    13
    )
    14
    ));
    Copied!
  • 8.4 Nếu hàm của bạn nhận một đối số và không sử dụng ngoặc nhọn, loại bỏ dấu ngoặc tròn. Nếu không, luôn luôn thêm ngoặc tròn trước và sau các đối số cho rõ ràng và nhất quán. Ghi chú: việc luôn sử dụng dấu ngoặc tròn được chấp nhận, khi đó, sử dụng tùy chọn “always” cho eslint. eslint: arrow-parens
    Tại sao? Nhìn bớt rối mắt.
    1
    // không tốt
    2
    [1, 2, 3].map((x) => x * x);
    3
    4
    // tốt
    5
    [1, 2, 3].map(x => x * x);
    6
    7
    // tốt
    8
    [1, 2, 3].map(number => (
    9
    `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!`
    10
    ));
    11
    12
    // không tốt
    13
    [1, 2, 3].map(x => {
    14
    const y = x + 1;
    15
    return x * y;
    16
    });
    17
    18
    // tốt
    19
    [1, 2, 3].map((x) => {
    20
    const y = x + 1;
    21
    return x * y;
    22
    });
    Copied!
  • 8.5 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
    1
    // không tốt
    2
    const itemHeight = item => item.height <= 256 ? item.largeSize : item.smallSize;
    3
    4
    // không tốt
    5
    const itemHeight = (item) => item.height >= 256 ? item.largeSize : item.smallSize;
    6
    7
    // tốt
    8
    const itemHeight = item => (item.height <= 256 ? item.largeSize : item.smallSize);
    9
    10
    // tốt
    11
    const itemHeight = (item) => {
    12
    const { height, largeSize, smallSize } = item;
    13
    return height <= 256 ? largeSize : smallSize;
    14
    };
    Copied!
  • 8.6 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
    1
    // không tốt
    2
    foo =>
    3
    bar;
    4
    5
    foo =>
    6
    (bar);
    7
    8
    // tốt
    9
    foo => bar;
    10
    foo => (bar);
    11
    foo => (
    12
    bar
    13
    )