12/08/2018, 16:09

12 thủ thuật hữu ích trong JavaScript

Trong bài viết này tôi sẽ chia sẻ 12 thủ thuật vô cùng hữu ích cho JavaScript. Những thủ thuật này sẽ giúp bạn giảm lượng code cũng như làm code chạy tối ưu hơn. Đôi lúc chúng ta cần kiểm tra nếu một vài biến tồn tại hoặc nếu nó có một giá trị hợp lệ hay không. Để xác nhận như vậy, bạn có thể sử ...

Trong bài viết này tôi sẽ chia sẻ 12 thủ thuật vô cùng hữu ích cho JavaScript. Những thủ thuật này sẽ giúp bạn giảm lượng code cũng như làm code chạy tối ưu hơn.

Đôi lúc chúng ta cần kiểm tra nếu một vài biến tồn tại hoặc nếu nó có một giá trị hợp lệ hay không. Để xác nhận như vậy, bạn có thể sử dụng !! (toán tử phủ định đôi). Nó sẽ tự động chuyển đổi mọi kiểu dữ liệu về boolean và biến này sẽ trả về false chỉ khi nó có những giá trị như: 0, null, "", undefined hoặc NaN, ngược lại nó sẽ trả về true. Để hiểu hơn về cách nó hoạt động, hãy xem ví dụ đơn giản sau:

function Account(cash) {  
    this.cash = cash;
    this.hasMoney = !!cash;
}
var account = new Account(100.50);  
console.log(account.cash); // 100.50  
console.log(account.hasMoney); // true
var emptyAccount = new Account(0);  
console.log(emptyAccount.cash); // 0  
console.log(emptyAccount.hasMoney); // false

Trong ví dụ trên, nếu account.cash có giá trị lớn hơn 0 thì account.hasMoney sẽ có giá trị là true.

Thủ thuật này rất tuyệt vời và dễ dàng để thực hiện, nhưng nó chỉ hoạt động với chuỗi những con số, ngược lại nó sẽ trả về NaN (Not a Number). Hãy nhìn ví dụ sau:

function toNumber(strNumber) {  
    return +strNumber;
}
console.log(toNumber("1234")); // 1234  
console.log(toNumber("ACB")); // NaN

Thủ thuật này cũng hoạt động với cả Date và trong trường hợp này nó sẽ trả về timestamp:

console.log(+new Date()) // 1461288164385

Nếu bạn thấy một đoạn code giống như này:

if (connected) {  
    login();
}

Bạn có thể rút gọn nó bằng cách kết hợp một biến (sẽ được xác nhận) và một hàm sử dụng && (toán tử AND) ở giữa. Ví dụ, đoạn code trên có thể trở nên ngắn gọn trong một dòng:

connected && login();

Bạn có thể làm tương tự để kiểm tra nếu một vài thuộc tính hay hàm tồn tại trong object. Tương tự như đoạn code dưới đây:

user && user.login();

Ngày nay trong ES6 đã hỗ trợ tham số mặc định. Trong trường hợp bạn muốn giả lập tính năng này trong các trình duyệt cũ thì bạn có thể sử dụng || (toán tự OR) bằng cách chèn giá trị mặc định như là tham số thứ hai để sử dụng. Nếu tham số đầu tiên trả về false thì tham số thứ hai sẽ được sử dụng như là một giá trị mặc định. Xem ví dụ sau:

function User(name, age) {  
    this.name = name || "Oliver Queen";
    this.age = age || 27;
}
var user1 = new User();  
console.log(user1.name); // Oliver Queen  
console.log(user1.age); // 27
var user2 = new User("Barry Allen", 25);  
console.log(user2.name); // Barry Allen  
console.log(user2.age); // 25

Mẹo này rất đơn giản và gây tác động lớn tới hiệu suất khi xử lý các mảng lớn trong vòng lặp. Hầu hết thì mọi người sử dụng vòng lặp for như sau để duyệt qua mảng:

for (var i = 0; i < array.length; i++) {  
    console.log(array[i]);
}

Nếu bạn làm việc với các mảng nhỏ thì không sao, nhưng nếu bạn xử lý những mảng lớn thì đoạn code này sẽ tính toán lại kích cỡ của mảng sau mỗi lần lặp và sẽ gây ra một chút chậm chễ (delay). Để tránh điều này, bạn có thể cache array.length trong một biến để dùng nó thay vì gọi array.length trong mỗi lần lặp:

var length = array.length;  
for (var i = 0; i < length; i++) {  
    console.log(array[i]);
}

Để làm nó trông gọn hơn, chỉ việc viết lại như sau:

for (var i = 0, length = array.length; i < length; i++) {  
    console.log(array[i]);
}

Thủ thuật này vô cùng hữu ích khi bạn cần kiểm tra nếu một vài thuộc tính tồn tại hay không và nó giúp tránh chạy các hàm hay thuộc tính chưa định nghĩa (undefined). Nếu bạn định viết code chạy trên đa trình duyệt thì bạn cũng có thể sử dụng kỹ thuật này. Ví dụ, hãy tưởng tượng rằng bạn cần viết code mà tương thích với IE6 và bạn muốn sử dụng document.querySelector() để lấy một vài phần tử bằng ID của chúng. Tuy nhiên, trong trình duyệt này thì hàm đó không tồn tại, vậy nên để kiểm tra xem hàm này có tồn tại không bạn có thể sử dụng toán tử in, xem ví dụ:

if ('querySelector' in document) {  
    document.querySelector("#id");
} else {
    document.getElementById("id");
}

Trong trường hợp này, nếu không có hàm querySelector trong document, chúng ta có thể sử dụng document.getElementById() thay thế.

Array.prototype.slice(begin, end) có thể cắt mảng khi bạn đặt tham số begin và end. Nhưng nếu bạn không nhập tham số end, hàm này sẽ tự động đặt giá trị lớn nhất cho mảng. Tôi nghĩ rằng ít người biết được hàm này có thể chấp nhận giá trị âm, và nếu bạn đặt tham số begin là một số âm thì bạn sẽ lấy ra các phần tử cuối cùng từ mảng:

var array = [1, 2, 3, 4, 5, 6];  
console.log(array.slice(-1)); // [6]  
console.log(array.slice(-2)); // [5,6]  
console.log(array.slice(-3)); // [4,5,6]

Kỹ thuật này có thể khóa kích cỡ mảng, điều này rất hữu ích để xóa một vài phần tử của mảng dựa trên số phần tử mà bạn muốn. Ví dụ, nếu bạn có một mảng với 10 phần tử nhưng bạn chỉ muốn lấy 5 phần tử đầu tiên thì bạn có thể cắt ngắn mảng, làm nó nhỏ hơn bằng cách đặt array.length = 5. Xem ví dụ sau:

var array = [1, 2, 3, 4, 5, 6];  
console.log(array.length); // 6  
array.length = 3;  
console.log(array.length); // 3  
console.log(array); // [1,2,3]

Hàm String.replace() cho phép sử dụng String và Regex để thay thế chuỗi, nhưng hàm này chỉ thay thế các chuỗi con xuất hiện đầu tiên. Nhưng bạn có thể giả lập một hàm replaceAll() bằng cách sử dụng /g ở cuối Regex:

var string = "john john";  
console.log(string.replace(/hn/, "ana")); // "joana john"  
console.log(string.replace(/hn/g, "ana")); // "joana joana"

Nếu bạn cần gộp hai mảng thì có thể sử dụng hàm Array.concat():

var array1 = [1, 2, 3];  
var array2 = [4, 5, 6];  
console.log(array1.concat(array2)); // [1,2,3,4,5,6];

Tuy nhiên, hàm này không phải là cách thích hợp nhất để gộp các mảng lớn vì nó sẽ tốn rất nhiều bộ nhớ do tạo ra một mảng mới. Trong trường hợp này, bạn có thể sử dụng Array.push.apply(arr1, arr2). Thay vì tạo ra một mảng mới thì nó sẽ gộp mảng thứ hai vào mảng thứ nhất từ đó giảm việc sử dụng bộ nhớ:

var array1 = [1, 2, 3];  
var array2 = [4, 5, 6];  
console.log(array1.push.apply(array1, array2)); // [1,2,3,4,5,6];

Nếu bạn chạy hàm document.querySelectorAll("p"), nó sẽ trả về một mảng chứa các phần tử DOM - NodeList object. Nhưng object này không có toàn bộ các hàm của mảng như: sort(), reduce(), map(), filter(). Trong trường hợp bạn muốn sử dụng các hàm này và nhiều hàm sẵn có khác của mảng, bạn cần chuyển NodeList thành mảng. Để thực hiện kĩ thuật này bạn chỉ cần dùng hàm: [].slice.call(elements)

var elements = document.querySelectorAll("p"); // NodeList  
var arrayElements = [].slice.call(elements); // Now the NodeList is an array  
var arrayElements = Array.from(elements); // This is another way of converting NodeList to Array

Để xáo trộn các phần tử của mảng mà không cần sử dụng các thư viện riêng như Lodash, bạn chỉ cần sử dụng thủ thuật sau:

var list = [1, 2, 3];  
console.log(list.sort(function() {  
    return Math.random() - 0.5
})); // [2,1,3]
0