Thứ ba, 15/09/2020 | 00:00 GMT+7

5 Mẹo để Viết Điều kiện Tốt hơn trong JavaScript


Khi làm việc với JavaScript, ta xử lý rất nhiều với các điều kiện, đây là 5 mẹo để bạn viết các điều kiện tốt hơn / sạch hơn.

1. Sử dụng Array.includes cho Nhiều tiêu chí

Hãy xem ví dụ dưới đây:

// condition
function test(fruit) {
  if (fruit == 'apple' || fruit == 'strawberry') {
    console.log('red');
  }
}

Thoạt nhìn, ví dụ trên có vẻ tốt. Tuy nhiên, điều gì sẽ xảy ra nếu ta nhận được nhiều trái cây màu đỏ hơn, chẳng hạn như cherrycranberries ? Ta sẽ mở rộng tuyên bố với nhiều hơn nữa || ?

Ta có thể viết lại điều kiện ở trên bằng cách sử dụng Array.includes (Array.includes)

function test(fruit) {
  // extract conditions to array
  const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];

  if (redFruits.includes(fruit)) {
    console.log('red');
  }
}

Ta extract các red fruits (điều kiện) vào một mảng. Bằng cách này, mã trông gọn gàng hơn.

2. Ít làm tổ, trở lại sớm

Hãy mở rộng ví dụ trước để bao gồm thêm hai điều kiện:

  • nếu không có trái cây được cung cấp, hãy ném lỗi
  • chấp nhận và in số lượng trái cây nếu vượt quá 10.
function test(fruit, quantity) {
  const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];

  // condition 1: fruit must has value
  if (fruit) {
    // condition 2: must be red
    if (redFruits.includes(fruit)) {
      console.log('red');

      // condition 3: must be big quantity
      if (quantity > 10) {
        console.log('big quantity');
      }
    }
  } else {
    throw new Error('No fruit!');
  }
}

// test results
test(null); // error: No fruits
test('apple'); // print: red
test('apple', 20); // print: red, big quantity

Nhìn vào đoạn mã trên, ta có:

  • 1 câu lệnh if / else lọc ra điều kiện không hợp lệ
  • 3 cấp độ của câu lệnh if lồng nhau (điều kiện 1, 2 & 3)

Một nguyên tắc chung mà cá nhân tôi tuân theo là quay lại sớm khi tìm thấy các điều kiện không hợp lệ .

/_ return early when invalid conditions found _/

function test(fruit, quantity) {
  const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];

  // condition 1: throw error early
  if (!fruit) throw new Error('No fruit!');

  // condition 2: must be red
  if (redFruits.includes(fruit)) {
    console.log('red');

    // condition 3: must be big quantity
    if (quantity > 10) {
      console.log('big quantity');
    }
  }
}

Bằng cách này, ta có một ít cấp hơn của câu lệnh lồng nhau. Phong cách mã hóa này đặc biệt tốt khi bạn có câu lệnh if dài (hãy tưởng tượng bạn cần phải cuộn xuống dưới cùng để biết có một câu lệnh khác, không hay ho).

Ta có thể giảm bớt việc làm tổ hơn nữa nếu, bằng cách đảo ngược các điều kiện và quay trở lại sớm. Hãy xem điều kiện 2 bên dưới để biết cách ta thực hiện:

/_ return early when invalid conditions found _/

function test(fruit, quantity) {
  const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];

  if (!fruit) throw new Error('No fruit!'); // condition 1: throw error early
  if (!redFruits.includes(fruit)) return; // condition 2: stop when fruit is not red

  console.log('red');

  // condition 3: must be big quantity
  if (quantity > 10) {
    console.log('big quantity');
  }
}

Bằng cách đảo ngược các điều kiện của điều kiện 2, mã của ta bây giờ không có câu lệnh lồng nhau. Kỹ thuật này rất hữu ích khi ta phải thực hiện logic dài và ta muốn dừng quá trình tiếp theo khi một điều kiện không được đáp ứng.

Tuy nhiên, đó không phải là luật cứng để làm điều này. Hãy tự hỏi mình, version này (không lồng nhau) có tốt hơn / dễ đọc hơn version trước (điều kiện 2 với lồng nhau) không?

Đối với tôi, tôi sẽ chỉ để nó như version trước (điều kiện 2 với lồng nhau). Đó là vì:

  • mã ngắn và thẳng về phía trước, nó rõ ràng hơn với if lồng nhau
  • tình trạng đảo ngược có thể làm tăng quá trình suy nghĩ (tăng tải nhận thức)

Vì vậy, hãy luôn đặt mục tiêu Ít làm tổ và Về sớm nhưng đừng lạm dụng nó . Có một bài báo và cuộc thảo luận StackOverflow nói thêm về chủ đề này nếu bạn quan tâm:

3. Sử dụng các tham số chức năng mặc định và cấu trúc

Tôi đoán mã bên dưới có thể trông quen thuộc với bạn, ta luôn cần kiểm tra null / undefined và gán giá trị mặc định khi làm việc với JavaScript:

function test(fruit, quantity) {
  if (!fruit) return;
  const q = quantity || 1; // if quantity not provided, default to one

  console.log(`We have ${q} ${fruit}!`);
}

//test results
test('banana'); // We have 1 banana!
test('apple', 2); // We have 2 apple!

Trong thực tế, ta có thể loại bỏ biến q bằng cách gán các tham số hàm mặc định.

function test(fruit, quantity = 1) { // if quantity not provided, default to one
  if (!fruit) return;
  console.log(`We have ${quantity} ${fruit}!`);
}

//test results
test('banana'); // We have 1 banana!
test('apple', 2); // We have 2 apple!

Dễ dàng và trực quan hơn nhiều phải không? Xin lưu ý mỗi tham số có thể có tham số chức năng mặc định riêng. Ví dụ, ta cũng có thể gán giá trị mặc định cho fruit : function test(fruit = 'unknown', quantity = 1) .

Nếu fruit của ta là một vật thể thì sao? Ta có thể gán tham số mặc định không?

function test(fruit) { 
  // printing fruit name if value provided
  if (fruit && fruit.name)  {
    console.log (fruit.name);
  } else {
    console.log('unknown');
  }
}

//test results
test(undefined); // unknown
test({ }); // unknown
test({ name: 'apple', color: 'red' }); // apple

Nhìn vào ví dụ trên, ta muốn in tên trái cây nếu nó có sẵn hoặc ta sẽ in không xác định. Ta có thể tránh việc kiểm tra fruit && fruit.name điều kiện với tham số hàm mặc định & hủy.

// destructing - get name property only
// assign default empty object {}
function test({name} = {}) {
  console.log (name || 'unknown');
}

//test results
test(undefined); // unknown
test({ }); // unknown
test({ name: 'apple', color: 'red' }); // apple

Vì ta chỉ cần name thuộc tính từ fruit, ta có thể hủy tham số bằng cách sử dụng {name} , sau đó ta có thể sử dụng name làm biến trong mã của ta thay vì fruit.name .

Ta cũng gán đối tượng trống {} làm giá trị mặc định. Nếu ta không làm như vậy, bạn sẽ gặp lỗi khi thực hiện test(undefined) dòng test(undefined) - Cannot destructure property name of 'undefined' or 'null'. bởi vì không có thuộc tính name trong không xác định.

Nếu bạn không phiền khi sử dụng thư viện của bên thứ 3, có một số cách để giảm bớt việc kiểm tra null:

  • sử dụng hàm Lodash get
  • sử dụng thư viện idx open-souce của Facebook (với Babeljs)

Đây là một ví dụ về việc sử dụng Lodash:

// Include lodash library, you will get _
function test(fruit) {
  console.log(__.get(fruit, 'name', 'unknown'); // get property name, if not available, assign default value 'unknown'
}

//test results
test(undefined); // unknown
test({ }); // unknown
test({ name: 'apple', color: 'red' }); // apple

Bạn có thể chạy mã demo ở đây . Ngoài ra, nếu bạn là người yêu thích Lập trình chức năng (FP), bạn có thể chọn sử dụng Lodash fp , version chức năng của Lodash (phương thức được thay đổi thành get hoặc getOr ).

4. Bản đồ ủng hộ / Đối tượng theo nghĩa đen hơn Tuyên bố chuyển đổi

Hãy xem ví dụ dưới đây, ta muốn in hoa quả dựa trên màu sắc:

function test(color) {
  // use switch case to find fruits in color
  switch (color) {
    case 'red':
      return ['apple', 'strawberry'];
    case 'yellow':
      return ['banana', 'pineapple'];
    case 'purple':
      return ['grape', 'plum'];
    default:
      return [];
  }
}

//test results
test(null); // []
test('yellow'); // ['banana', 'pineapple']

Đoạn mã trên có vẻ không có gì sai, nhưng tôi thấy nó khá dài dòng. Kết quả tương tự cũng có thể đạt được với object đen với cú pháp rõ ràng hơn:

// use object literal to find fruits in color
  const fruitColor = {
    red: ['apple', 'strawberry'],
    yellow: ['banana', 'pineapple'],
    purple: ['grape', 'plum']
  };

function test(color) {
  return fruitColor[color] || [];
}

Ngoài ra, bạn có thể sử dụng Bản đồ để đạt được kết quả tương tự:

// use Map to find fruits in color
  const fruitColor = new Map()
    .set('red', ['apple', 'strawberry'])
    .set('yellow', ['banana', 'pineapple'])
    .set('purple', ['grape', 'plum']);

function test(color) {
  return fruitColor.get(color) || [];
}

Bản đồ là kiểu đối tượng có sẵn kể từ ES2015, cho phép bạn lưu trữ cặp giá trị khóa.

Ta có nên cấm sử dụng câu lệnh switch không? Đừng giới hạn bản thân với điều đó. Cá nhân tôi sử dụng đối tượng theo nghĩa đen khi nào có thể, nhưng tôi sẽ không đặt ra luật cứng để chặn điều đó, hãy sử dụng bất kỳ điều nào phù hợp với kịch bản của bạn.

Todd Motto có một bài viết đào sâu hơn về câu lệnh switch so với đối tượng theo nghĩa đen, bạn có thể đọc ở đây .

TL; DR; Cấu trúc lại cú pháp

Đối với ví dụ trên, ta có thể cấu trúc lại mã của bạn để đạt được kết quả tương tự với Array.filter .


 const fruits = [
    { name: 'apple', color: 'red' }, 
    { name: 'strawberry', color: 'red' }, 
    { name: 'banana', color: 'yellow' }, 
    { name: 'pineapple', color: 'yellow' }, 
    { name: 'grape', color: 'purple' }, 
    { name: 'plum', color: 'purple' }
];

function test(color) {
  // use Array filter to find fruits in color

  return fruits.filter(f => f.color == color);
}

Luôn có nhiều hơn 1 cách để đạt được cùng một kết quả. Ta đã chỉ ra 4 với cùng một ví dụ. Viết mã rất thú vị!

5. Sử dụng Array.every & Array.some cho tất cả / một phần tiêu chí

Mẹo cuối cùng này thiên về việc sử dụng hàm Mảng Javascript mới (nhưng không quá mới) để giảm các dòng mã. Nhìn vào đoạn mã dưới đây, ta muốn kiểm tra xem tất cả các loại trái cây có màu đỏ hay không:

const fruits = [
    { name: 'apple', color: 'red' },
    { name: 'banana', color: 'yellow' },
    { name: 'grape', color: 'purple' }
  ];

function test() {
  let isAllRed = true;

  // condition: all fruits must be red
  for (let f of fruits) {
    if (!isAllRed) break;
    isAllRed = (f.color == 'red');
  }

  console.log(isAllRed); // false
}

Mã dài quá! Ta có thể giảm số dòng với Array.every :

const fruits = [
    { name: 'apple', color: 'red' },
    { name: 'banana', color: 'yellow' },
    { name: 'grape', color: 'purple' }
  ];

function test() {
  // condition: short way, all fruits must be red
  const isAllRed = fruits.every(f => f.color == 'red');

  console.log(isAllRed); // false
}

Bây giờ sạch hơn nhiều phải không? Theo cách tương tự, nếu ta muốn kiểm tra xem quả nào có màu đỏ hay không, ta có thể sử dụng Array.some để đạt được nó trong một dòng.

const fruits = [
    { name: 'apple', color: 'red' },
    { name: 'banana', color: 'yellow' },
    { name: 'grape', color: 'purple' }
];

function test() {
  // condition: if any fruit is red
  const isAnyRed = fruits.some(f => f.color == 'red');

  console.log(isAnyRed); // true
}

Tóm lược

Hãy cùng nhau tạo ra mã dễ đọc hơn. Tôi hy vọng bạn học được điều gì đó mới trong bài viết này.

Đó là tất cả. Chúc bạn viết mã vui vẻ!


Tags:

Các tin liên quan

Lời hứa của JavaScript dành cho người giả
2020-09-15
Sao chép các đối tượng trong JavaScript
2020-09-15
Cách sử dụng API tìm nạp JavaScript để lấy dữ liệu
2020-09-15
Cách mã hóa và giải mã chuỗi với Base64 trong JavaScript
2020-09-15
Toán tử đơn nguyên JavaScript: Đơn giản và hữu ích
2020-09-15
Hiểu Hoisting trong JavaScript
2020-09-15
Hiểu Vòng lặp sự kiện, Gọi lại, Hứa hẹn và Không đồng bộ / Chờ đợi trong JavaScript
2020-09-10
Bốn phương pháp để tìm kiếm thông qua các mảng trong JavaScript
2020-09-09
Sử dụng phương thức Array.find trong JavaScript
2020-09-09
split () Phương thức chuỗi trong JavaScript
2020-09-09