Hỏi - đáp Nơi cung cấp thông tin nghề nghiệp và giải đáp những thắc mắc thường gặp của bạn

18+ kĩ thuật rút gọn code Javascript của bạn

1. Toán tử 3 ngôi (Ternary Operator)

Sử dụng khi cần rút ngắn đoạn if..else thành 1 dòng. Thay vì

const x = 100;
let result;
if (x < 1000) {
  result = "nhỏ hơn 1000";
} else {
  result = "lớn hơn hoặc bằng 1000";
}

thì

const x = 100;
const result = (x < 1000) ? "nhỏ hơn 1000" :  "lớn hơn hoặc bằng 1000";

2. Shorthand Evaluate

Khi gán giá trị của biến cho biến khác, chúng ta thường muốn đảm bảo rằng giá trị biến đó không null, không undefinded hoặc rỗng, vì vậy mà cần phải viết một loạt điều kiện để kiểm tra:

let variable2;
if (variable1 !== null || variable1 !== undefined || variable1 !== '') {
     variable2 = variable1;
} else {
    variable2 = "";
}

Có thể rút ngắn gọn thành:

const variable2 = variable1  || "";

3. Khai báo biến

Khai báo biến tốt nhất là khai báo khi bắt đầu 1 function. Cách viết sau sẽ giúp bạn tiết kiệm được thời gian cũng như số dòng khi khai báo: Thay vì

let x;
let y;
let z = 3;

Thay bằng:

let x, y, z = 3;

4. Bỏ qua toán tử so sánh bằng trong If

Khi điều kiện là so sánh bằng, trong trường hợp biến đã được định nghĩa trước và quy ước kiểu là Boolean, ta có thể bỏ qua toán tử so sánh == hoặc ===

if (isTurnOn === true)

Thay bằng

if (isTurnOn)

Hoặc nếu trong trường hợp giá trị cần là false

if (!isTurnOn)

5. Vòng lặp For

Tip sau sẽ thực sự hữu ích trong trường hợp bạn muốn sử dụng Js thuần mà không phụ thuộc vào thư viện bên thứ 3 như Lodash hay jQuery. Thay vì:

for (let i = 0; i < sampleArr.length; i++)

Thành

for (let item in sampleArr)

6. Decimal base exponents

Để biểu diễn số hàng triệu, hàng tỉ, thay vì viết một đống con số 0, ta có thể viết thành kiểu là số thực phẩy động (float type). Thay vì

for (let i = 0; i < 100000; i++) {}

thành

for (let i = 0; i < 1e5; i++) {}
# giá trị các biểu thức sau đều là true
1e0 === 1;
1e1 === 10;
1e2 === 100;
1e3 === 1000;
1e4 === 10000;
1e5 === 100000;

7. Object property

ES6 cung cấp cho ta khả năng gán property cho object dễ dàng hơn. Nếu tên key trùng luôn với tên biến, thì, thay vì:

const x = 1, y = 2;
const obj = { x: x, y: y };

có thể viết lại thành

const x = 1, y = 2;
const obj = { x, y };

8. Rút gọn khai báo function

Kiểu khai báo function cũ thì dễ đọc dễ viết, nhưng nó sẽ trở nên rối khi nằm chung với những lời gọi hàm khác. Ví dụ thay vì

function sayHello(name) {
  console.log('Hello', name);
}

setTimeout(function() {
  console.log('Loaded')
}, 2000);

list.forEach(function(item) {
  console.log(item);
});

có thể dùng cú pháp arrow để khai báo function (arrow function):

sayHello = name => console.log('Hello', name);

setTimeout(() => console.log('Loaded'), 2000);

list.forEach(item => console.log(item));

9. Implicit Return

Thường ta sử dụng return để trả về kết quả cuối của function. Tuy nhiên trong arrow function thì việc return kết quả là implicit: Thay vì:

function getValue(ratio) {
  return ratio * 6.9;
}

có thể ngắn gọn hơn:

getValue = ratio => ratio * 6.9

10. Giá trị default cho params của function

Có thể sử dụng if để gán giá trị default cho params của function trong trường hợp cần thiết. Tuy nhiên từ ES6, bạn có thể gán giá trị default cho params ngay khi khai báo hàm. Thay vì:

function getValue(a, b, c) {
  if (a === undefined)
    a = 3;
  if (b === undefined)
    b = 4;
  return a * b + c;
}

thành:

getValue = (a, b = 3, c = 4 ) => (a * b + c);

11. Template Literals

Mệt mỏi vì dùng toán tử + để cộng biến nối chuỗi ? Từ ES6 trở đi, ta được cung cấp một giải pháp ngắn gọn và trực quan hơn bằng cách sử dụng ${} trong cặp nháy backtick ```:

const welcome = 'You have logged in as ' + first + ' ' + last + '.'

thay bằng:

const welcome = `You have logged in as ${first} ${last} .`;

12. Destructuring Assignment

Nếu đã làm việc với các framework js, hẳn ta không lạ gì việc truyền các data dưới dạng object giữa các component với nhau. Khi data object được truyền tới nơi thì ta cần unpack nó.

const action = require('lib/action')
const service = require('lib/service')

const form = this.props.form;
const errors = this.props.errors;
const entity = this.props.entity;
const controller = this.props.controller;
const component = this.props.component;

Đoạn trên có thể rút gọn:

import { action, service } from 'lib';

const { form, errors, entity, controller, component } = this.props;

13. Multi-line string

Để gán giá trị cho một biến là một chuối nhiều dòng, thay vì:

const lorem = 'Lorem ipsum dolor sit amet, consectetur\n\t'
    + 'adipisicing elit, sed do eiusmod tempor incididunt\n\t'
    + 'ut labore et dolore magna aliqua. Ut enim ad minim\n\t'
    + 'veniam, quis nostrud exercitation ullamco laboris\n\t'
    + 'nisi ut aliquip ex ea commodo consequat. Duis aute\n\t'
    + 'irure dolor in reprehenderit in voluptate velit esse.\n\t'

đơn giản ta wrap tất cả text trong cặp backtick ```

const lorem = `Lorem ipsum dolor sit amet, consectetur
    adipisicing elit, sed do eiusmod tempor incididunt
    ut labore et dolore magna aliqua. Ut enim ad minim
    veniam, quis nostrud exercitation ullamco laboris
    nisi ut aliquip ex ea commodo consequat. Duis aute
    irure dolor in reprehenderit in voluptate velit esse.`

14. Spread Operator

Trong ES6 spec có giới thiệu một chức năng mới khá là lợi hại mà không phải ai cũng hay dùng, đó là Spread Operator. Chức năng này không có gì là xa lạ với các ngôn ngữ khác, trong thế giới Ruby thì nó tương đương splat operator. Spread Operator cho phép chuyển đổi một chuỗi thành nhiều argument (trong trường hợp gọi với hàm) hoặc thành nhiều phần tử (cho array). Thêm vào nữa nó cũng cho phép làm nhiệm vụ destructure. Operator này có syntax là 3 dấu chấm ...

// joining arrays
const odd = [1, 3, 5];
const nums = [2 ,4 , 6].concat(odd);

// cloning arrays
const arr = [1, 2, 3, 4];
const arr2 = arr.slice()

Ngắn gọn hơn:

// joining arrays
const odd = [1, 3, 5 ];
const nums = [2 ,4 , 6, ...odd];

// cloning arrays
const arr = [1, 2, 3, 4];
const arr2 = [...arr];

Không như hàm concat(), dùng spread operator, ta có thể chèn 1 array vào vị trí bất kì nào trong array cần chèn tới:

const odd = [1, 3, 5 ];
const nums = [2, ...odd, 4 , 6];
  • Spread operator trong gọi hàm: Nếu có 1 hàm như sau:
function sayHello(firstName, lastName, nickName) {}

vả array chứa thông tin sẽ dùng làm tham số truyền vào:

var names = ['Duy', 'Tăng', 'buffet']

để truyền tham số vào hàm thì cần làm như sau:

sayHello(names[0], names[1], names[2])

hoặc có cách khác hay hơn nếu chúng ta ko biết rõ biến names dài bao nhiêu với Function.prototype.apply

sayHello.apply(null, names)

Với ES6, ta có thể áp dụng spread operator như sau:

sayHello(...names)

15. Ràng buộc params

Default thì Javascript sẽ set parameters là undefined nếu không có value được truyền vào function. Ở một số ngôn ngữ khác, nó ném ra exception hoặc warning nếu không truyền đủ params. Để làm điều tương tự với Javascript, ta có thể xét ràng buộc:

function sample(param1) {
  if (param1 === undefined) {
     throw new Error('Thiếu tham số!');
  } 
  return param1;
}

Hoặc viết ngắn gọn hơn bằng cách sử dụng Mandatory parameter

mandatory = () => { throw new Error('Thiếu tham số!'); }

sample = (param1 = mandatory()) => param1

16. Array.find

Nếu từng phải viết hàm tìm kiếm bằng Javascript thuần, hẳn ta sẽ nghĩ ngay đến việc dùng vòng lặp for lặp qua từng phần tử và kiểm tra điều kiện tìm kiếm. Tuy nhiên trong ES6, function find của array được giới thiệu, giúp cho việc tìm phần tử trong array ngắn gọn hơn. Thay vì

const employees = [
  { name: 'Emp A', age: 25 },
  { name: 'Emp B', age: 28 },
  { name: 'Emp C', age: 35 }
]

function findEmp(name) {
  for(let i = 0; i<employees.length; ++i) {
    if(employees[i].name === name) {
      return employees[i];
    }
  }
}

const name = 'Emp A'
emp = findEmp(name)

thành

const name = 'Emp A'
emp = employees.find(item => item.name === name)

17. Object [key]

Để get property của object trong JS ngoài cách Obj.prop, còn có thể viết Obj['prop']. Nhìn qua thì dùng cả 2 cách đều cho kết quả như nhau. Tuy nhiên để viết được những đoạn code có thể tái sử dụng, thì cần sử dụng cách thứ 2: Xem xét ví dụ 1 hàm validation:

function validate(fullName) {
  if(!fullName.firstName)
    return false;
  if(!fullName.lastName)
    return false;
  return true;
}

console.log(validate({firstName:'Duy',lastName:'Buffet'})); // true

Đoạn code trên hoạt động rất tốt, tuy nhiên nó lại chỉ áp dụng được với duy nhất trường hợp object có đúng 2 property firstName, lastName. Để có thể áp dụng được với những object có property khác, validation rule khác thì ta cần viết tổng quát hơn:

const rule = {
  firstName: {
    required:true
  },
  lastName: {
    required:true
  }
}

const validate = (rule, values) => {
  for(prop in rule) {
    if(rule[prop].required) {
      if(!values[prop]) {
        return false;
      }
    }
  }
  return true;
}

console.log(validate(rule, {firstName:'Duy'})); // false
console.log(validate(rule, {firstName:'Duy',lastName:'Buffet'})); // true

Giờ thì hàm validate đã tổng quát hơn và có khả năng tái sử dụng nhờ cách gọi property Obj['prop']

18. Toán tử bitwise NOT Double

Double bitwise NOT (2 lần phủ định) có thể dùng thay thế cho hàm làm tròn xuống Math.floor(). Ưu điểm của các phép toán bitwise đó là nó thực hiện tác vụ tương tự cho hiệu suất cao hơn do làm việc trực tiếp với binary. Cách viết dài:

Math.floor(6.9) === 6 // true

Ngắn gọn:

~~6.9 === 6 // true

KẾT LUẬN

Trên đây bài viết đã tổng hợp một số kĩ thuật khiến code Javascript trở nên ngắn gọn, rõ ràng hơn. Hi vọng bài viết sẽ giúp được phần nào các bạn trong quá trình làm việc với Javascript.

Nguồn tham khảo

  1. ES6
  2. Sitepoint

Via Viblo