Dạo gần đây mình đi làm thêm, project hiện tại có sử dụng React với cả ES6 – chuẩn Javascript mới. Do mấy bài viết trước mình chê JavaScript sida nhiều thấy cũng tội, hôm nay viết một bài nói tốt cho nó một tí để đổi gió nhé.
Phiên bản JavaScript hiện tại chúng ta đang sử dụng dựa trên chuẩn ECMAScript 5 (ES5). Hiện tại, JavaScript được sử dụng ngày càng nhiều, từ front-end cho đến back-end, điều này đòi hỏi sự cải tiến trong JavaScript (Nghĩ cũng đúng, cái ngôn ngữ sida thế mà code mấy hệ thống to to, code phức tạp thì để lâu chả banh chành ra à !!). Đó là lý do chuẩn ECMAScript 6 (ES6) ra đời, cung cấp 1 số tính năng mới cho JavaScript, đồng thời giúp code trở nên tường minh và dễ viết hơn.
Trong phạm vi bài viết, mình sẽ giới thiệu một số tính năng mới của ES6 và mổ xẻ so sánh nó với ES5 (Mình chỉ giới thiệu 1 số tính năng hay thôi nhé, các bạn tham khảo nguồn dưới cuối bài để tìm hiểu thêm). Để chạy được ES6 phải ta setup hoặc add thư viện hơi rắc rối, biết các bạn lười mình đã chuẩn bị sẵn 1 link jsfiddle hỗ trợ ES6 cho các bạn, các bạn cứ vào mà nghịch code ES6 thoải mái thôi: https://jsfiddle.net/jwtg7a1g/.
Tính năng nào cảm thấy hay mình sẽ đặt lên đầu tiên nhé. Bắt đầu nào!!
1. Arrow (Lambda Expression)
Ở ES6, thay vì khai báo function như kiểu thông thường, ta đã có thể sử dụng =>. Cách khai báo này tương tự như Lambda Expression trong C#, giúp cho code tường minh và ngắn gọn hơn rất rất nhiều.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; | |
// Giả sử ta muốn tìm các số chẵn | |
// Cách viết cũ | |
var odd = numbers.filter(function(n) { return n % 2 == 1 }); | |
console.log(odd); | |
// Với arrow | |
odd = numbers.filter(n => n % 2 == 1); | |
console.log(odd); |
Ngoài ra, nhờ có arrow, ta không còn bị tình trạng this bị bind nhầm như trước kia nữa.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var person = { | |
firstName: 'Hoang', | |
friends : ['Minh', 'Sang', 'Khoa', 'Hoang'], | |
showFriend: function() { | |
this.friends.forEach(function(fr) { | |
// Với cách viết cũ, this ở đây sẽ là object window, không phải person | |
console.log(this.firstName + ' have a friend named ' + fr); | |
}); | |
// Ta sử dụng arrow, this vẫn là object person | |
this.friends.forEach(fr => console.log(this.firstName + ' have a friend named ' + fr)); | |
} | |
}; |
2. Default parameter, destructuring, spread operator
Default parameter đã có từ lâu trong C#, giờ JavaScript cũng đã có nhưng… Java vẫn chưa có. Nhờ default parameter, ta có thể xác định giá trị mặc định của tham số truyền vào
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Cách cũ, phải check tham số truyền vào rồi xác định giá trị | |
function multiply(a, b) { | |
var b = typeof b !== 'undefined' ? b : 1; | |
return a*b; | |
} | |
// Với ES6, chỉ cần sử dụng dấu = | |
function multiply(a, b = 1) { | |
return a*b; | |
} | |
multiply(5); // 5 |
Destructuring cũng là một tính năng khá hay, nó cho phép ta “phân rã” các phần tử trong 1 array hoặc 1 object
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Với array | |
var foo = ["one", "two", "three"]; | |
// Cách cũ | |
var one = foo[0]; | |
var two = foo[1]; | |
var three = foo[2]; | |
// Dùng destructuring | |
var [one, two, three] = foo; | |
// Với object | |
var obj = {firstName:'Hoang', lastName:'Pham'}; | |
// Cách cũ | |
var firstName = obj.firstName; | |
var lastName = obj.lastName; | |
// Dùng destructuring | |
var {firstName, lastName} = obj; | |
// Nếu muốn lấy tên biến khác tên field của object | |
var {firstName : fn, lastName : ln} = obj; //fn: Hoang, ln: Pham |
Một tính năng mới khác mà mình cảm thấy khá thú vị đó là spread operator, tính năng này cho phép chuyển đổi qua lại giữa 1 array và danh sách các params. Nghe hơi khó hiểu nhỉ, nhìn code là hiểu ngay.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function f(x, …y) { | |
// y ở đây là array, chứa ["hello", true, false] | |
return x * y.length; | |
} | |
f(3, "hello", true, falser) == 9; | |
// Cách gọi này tương tự với f(3, ["hello", true, false]) | |
function f(x, y, z) { | |
return x + y + z; | |
} | |
f(…[1,2,3]) == 6; | |
// Cách gọi này tương tự với f(1, 2, 3); |
3. Cải tiến syntax class và object
Lần trước, mình đã chửi thằng JavaScript sida vì nó chẳng có class gì sất, mà phải dùng prototype. Chắc nghe chửi nhiều quá nên các bác cũng sợ, giờ đã phải thêm class vào ES6. Trong ES6, class có hỗ trợ constructor, get/set, việc kế thừa cũng rất dễ thực hiện bằng từ khóa extends.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Animal { | |
constructor(name) { | |
this.name = name; | |
} | |
speak() { | |
console.log(this.name + ' makes a noise.'); | |
} | |
} | |
class Dog extends Animal { | |
speak() { | |
console.log(this.name + ' barks.'); | |
} | |
} |
Với cách khai báo object mới, ta có thể viết code một cách ngắn gọn và rõ ràng hơn nhiều. Mình là mình lười code lắm, viết code càng ít mình càng khoái.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var firstName = 'Hoang'; | |
var lastName = 'Pham'; | |
// Khai báo object kiểu cũ | |
var obj = { | |
firstName: firstName, | |
lastName: lastName, | |
showName: function() { console.log(this.firstName + ' ' + this.lastName) } | |
}; | |
// Khai báo kiểu mới, ngắn gọn hơn | |
// Không cần lặp lại tên biến hay function | |
var obj = { | |
firstName, | |
lastName, | |
showName() { console.log(this.firstName + ' ' + this.lastName) } | |
}; | |
4. Iterator
Ngày xưa, để duyệt qua từng phần tử trong một mảng, ta phải sử dụng hàm for, chạy index từ 0 tới cuối mảng. Về sau đỡ hơn, ta có thể sử dụng hàm forEach. Tuy nhiên nhiều người lại thấy cú pháp hàm forEach hơi lạ, không được tự nhiên cho lắm. Trong ES6, ta đã có thêm for… of để duyệt từng phần tử trong một mảng (Đừng nhầm với for…in, để duyệt các trường trong 1 object nhé).
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; | |
// Cách cũ, duyệt từ đầu | |
for(var i = 0; i< numbers.length; i ++) | |
{ | |
console.log(number[i]); | |
} | |
// Dùng forEach | |
numbers.forEach(function(number) { | |
console.log(number); | |
}) | |
// Dùng for…of, dễ viết dễ đọc | |
for(var number of numbers) console.log(number); |
5. Template String
Chức năng này khá giống chức năng string interpolation trong C# 6.0. Trước đây, JavaScript không có string.format, do đó ta phải cộng chuỗi bằng tay rất cực. Giờ đây, sử dụng template string, ta không cần phải mất công cộng chuỗi nữa, code rõ ràng hơn nhiều.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var name = "Bob", time = "today"; | |
// Cách cũ | |
console.log("Hello " + name + " how are you " + time + " ?"); | |
// Dùng string interpolation, để ý dấu ` | |
console.log(`Hello ${name}, how are you ${time}?`); |
6. Map và Set
Nhắc lại một chút kiến thức cơ bản: Map là cấu trúc dữ liệu cho phép ta lưu dữ liệu dưới dạng Key-Value, Set là một mảng mà trong đó không có phần tử nào trùng nhau (Bạn nào quên thì lật sách Cấu trúc dữ liệu và thuật toán ra xem lại nhé). Giờ ES6 đã bổ sung thêm 2 cấu trúc dữ liệu này, giúp việc code được dễ dàng hơn.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Sets | |
var s = new Set(); | |
s.add("hello").add("goodbye").add("hello"); | |
s.size === 2; | |
s.has("hello") === true; | |
// Maps | |
var m = new Map(); | |
m.set("hello", 42); | |
m.set(s, 34); | |
m.get(s) == 34; |
7. Promise
Promise là một khái niệm khá hay, giúp cho việc viết code asynchonous (bất đồng bộ) dễ dàng hơn. Promise được sử dụng trong rất nhiều thư viện như jQuery, AngularJS. Lần khác có thời gian mình sẽ viết bài nói rõ hơn về khái niệm này, còn hiện tại các bạn qua blog của bạn mình xem tạm nhé: Tìm hiểu về promise.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Code from: http://www.html5rocks.com/en/tutorials/es6/promises/ | |
var promise = new Promise(function(resolve, reject) { | |
// do a thing, possibly async, then… | |
if (true) { | |
resolve("Stuff worked!"); | |
} | |
else { | |
reject(Error("It broke")); | |
} | |
}); | |
promise.then(function(result) { | |
console.log(result); // "Stuff worked!" | |
}, function(err) { | |
console.log(err); // Error: "It broke" | |
}); |
Có thể thấy, ES6 đã làm JavaScript bớt sida hơn nhiều. Tuy nhiên, ES6 vẫn còn một khuyết điểm, đó là nó chưa được hỗ trợ hầu hết các trình duyệt. IE và Chrome không thể chạy trực tiếp ES6 được, Firefox thì chỉ chạy được 1 số tính năng: https://kangax.github.io/compat-table/es6/.
(Update 08/02/2017: Hiện tại phần lớn các tính năng của ES6 đã chạy được trên Microsoft Edge, Firefox, Chrome và Safari phiên bản mới nhất rồi nhé).
Dù vậy, hiện tại nhiều công ty đã áp dụng ES6 vào code. Lập trình viên viết code ES6 như thường, sau đó sử dụng babel/traceur để dịch code EcmaScript 6 sang EcmaScript 5 (Project hiện tại của mình cũng vậy, cứ viết code ES6 xong nó tự build ra JavaScript ES5, khá sướng). Trong tương lai vài năm nữa, khi các trình duyệt đã hỗ trợ đầy đủ, ta có thể viết ES6 và chạy thẳng trên trình duyệt luôn.
Trong phạm vi bài viết, mình không thể nêu hết toàn bộ các cải tiến của ES6 được. Bạn nào có hứng thú có thể tham khảo thêm ở một số nguồn dưới đây:
Chào anh,
anh cho em hỏi ES6 này chỉ sử dụng được trên node.js thôi hả. Em thấy bài viết hay thì tìm hiểu thì thấy set up toàn dùng lệnh npm không. Không thấy dùng để include vào html
LikeLiked by 1 person
Hiện tại ES6 dùng đc trên chrome rồi em 😉
LikeLike
Bài viết hay có đưa cách cũ và mới dễ so sánh và dễ hiểu ạ. cảm ơn anh nhiều
LikeLike