[Tips Javascript] - Thói quen xấu khi viết code trong javascript nên tránh

Bạn đã rơi vào trường hợp này như thế này khi đọc một đoạn code (javascript) mà bạn có cảm thấy những điều này: 

1 - Hầu như không hiểu code đó để làm gì? 

2 - Code sử dụng quá nhiều thủ thuật trong đó? 

3 - Tuỳ tiện đặt tên function và variable ? 

Bài viết này cũng là một trong những bài viết về tips and tricks javascript các bạn nên đọc để hiểu nhiều hơn nữa nhé.

Đó chính là điều mà tôi muốn nói trong bài viết hôm nay. Khi viết code, không ai tránh khỏi những thói quen xấu trong function của mình. Do đó người khác đọc vào code của bạn cảm thấy khó hiểu đó là điều đương nhiên. 

Trong bài viết này, chúng ta sẽ bàn luận qua những ví dụ hình thành những thói quen xấu đó, và quan trọng là tôi sẽ trình bày để loại bỏ những thói quen xấu khi viết code. 

1 - Kiểm tra ngầm định trong javascript (implicit type)

Trước tiên các bạn nhìn vào đoạn mã sau:

console.log("2" + "1");  // => "21"
console.log("2" - "1");  // => 1

console.log('' == 0);    // => true

console.log(true == []); // -> false
console.log(true == ![]); // -> false

Bạn cảm thấy thế nào? Bối rối đúng không, tôi thì chả thấy có cái gì để hiểu ở đây hết. Dựa quá nhiều vào chuyển đổi implicit là một thói quen xấu. Trước hết, nó làm cho code của bạn kém ổn định hơn trong các trường hợp khác. Thứ hai, việc bạn mở rộng hay nâng cấp thì rất khó. 

Ta lấy một ví dụ để thấy bóng dáng của bạn ở trong đó không nha. 

Ví dụ: Hãy viết một function thực hiện chức năng là check một propertie của một object xem có tồn tai hay không? Nếu không hãy trả về một giá trị default.

function getProp(object, propertyName, defaultValue) {
  if (!object[propertyName]) {
    return defaultValue;
  }
  return object[propertyName];
}

const hero = {
  name: 'Batman',
  isVillian: false
};

console.log(getProp(hero, 'name', 'Unknown'));     // => 'Batman'

Quá tuyệt vời đúng không? getProp() sẽ trả về giá trị là 'Batman' vì check có tồn tại properties đó. Chúng ta hãy thử qua việc check properties isVillian trong object hero.

console.log(getProp(hero, 'isVillian', true)); // => true

Chuyện gì xảy ra vậy? Tại sao lại return là true? Nó là false mà. Đó chính là một thói quen xấu khi check một properties. Bởi vì if (!object[propertyName]) {...} nó sẽ trả về true. Do object[propertyName] trong trường hợp này là false. Do đó !false === true là đúng. 

Những lỗi này rất khó phát hiện trong những dự án lớn và nhiều người tham gia phát triển do đó bạn nên cẩn thận với chính code của mình. Để tránh những code xấu như vậy chúng ta thường viết rõ ràng hơn, cụ thể như thế này.

function getPropFixed(object, propertyName, defaultValue) {
   if (object[propertyName] === undefined) {
     return defaultValue;
   }
   return object[propertyName];
}

const hero = {
  name: 'Batman',
  isVillian: false
};

console.log(getPropFixed(hero, 'isVillian', true)); // => false

Việc check rõ ràng giúp chúng ta có thể tránh được những sai phạm nhỏ, và giúp các đồng nghiệp khác không tốn thời gian tìm bugs nữa nhé. Tôi mong trong số các bạn đọc ở đây nếu có cách nào hay hơn nữa thì xin comment trong topic này. Cảm ơn! 

2 - Việc khai báo biến tràn lan, tuỳ tiện.

À cái này hay nè. Tôi gặp khá nhiều, rất nhiều người dính đến trường hợp này. Đó là khai báo biến cho đẹp code, mà không biết chính những thói quen thế này làm rò rỉ các biến đã khai báo. 

Ta đi ví dụ sau:

function someFunc(array) {
  var index, item, length = array.length;
  /*
   * Lots of code
   */
  for (index = 0; index < length; index++) {
    item = array[index];
    // Use `item`
  }
  return someResult;
}

Đẹp vãi luôn. Các biến như index, item chính là function scoped. Nó chỉ cần thiết khai báo bên trong for() mà thôi, vì khi khai báo như vậy vô tình bạn gây rò rỉ hay gây ô nhiễm trong function. 

Việc block scope các biến khi sử dụng let và const sẽ giới hạn vòng đời của một biến và tôi khuyên các bạn nên sử dụng như thế này.

function someFunc(array) {
  /*
   * Lots of code
   */
  const length = array.length;
  for (let index = 0; index < length; index++) {
    const item = array[index];
    // Use `item`
  }
  return someResult;
}

Với cách viết này, các biến chỉ hoạt động trong vòng for() và khi length kết thúc thì vòng đời của nó cũng bị clear. Việc này giúp cho chúng ta không bị rò rỉ các biến trong function mỗi cá nhân. 

Lời khuyên: 

if block scope

// Bad
let message;
// ...
if (notFound) {
  message = 'Item not found';
  // Use `message`
}
// Good
if (notFound) {
  const message = 'Item not found';
  // Use `message`
}

for block scope

// Bad
let item;
for (item of array) {
  // Use `item`
}
// Good
for (const item of array) {
  // Use `item`
}

3 - Hãy luôn cập nhật những function mới nhất.

Từ khi có includes để check một item có trong array hay không thì tôi không bao giờ sử dụng lại array.indexOf(item) !== -1 đó nữa. 

Thay vì

 
array.indexOf(item) !== -1 

thì hãy sử dụng includes có từ ES2015

array.includes (item).

Tạm thời tới đây. Để đi có việc đã. Những thói quen xấu luôn ở trong mỗi chúng ta. Việc thay đổi mỗi ngày có thể giúp chúng ta thoát khỏi những cám dỗ đó trong viết code cho nên hãy luôn câph nhật nhé các bạn.