Javascript ES6 mang đến nhiều cú pháp cũng như những tính năng vô cùng tuyệt vời, giúp code của bạn trông có vẻ hiện đại, dễ đọc hơn bao giờ hết. Có thể ví von ES6 giúp viết ít làm được nhiều (write less do more). ES6 giới thiệu nhiều tính năng mới như hàm arrow (arrow function), template string, khai báo class, mô-đun và… nhiều hơn nữa. Hôm nay chúng ta sẽ cùng tìm hiểu sơ qua nhé.
const
và let
Đầu tiên là const
, đó là một từ khóa mới trong ES6 giúp khai báo biến. Tuy nhiên const
có nhiều điểm “ghê gớm” hơn var
rất nhiều. Đó là khi bạn đã khai báo giá trị cho biến rồi thì không thể khai báo lại một nữa. Nói một cách khác nó là hằng số bất biến, tuy nhiên điều này ngoại trừ object nhé. Cùng check một ví dụ để hiểu hơn về nó nhé.
1 | const myVariable = 5; |
Vậy còn ngoại trừ object là như thế nào:
1 | const myObject = { |
Trong trường hợp trên nếu bạn viết:
1 | const myObject = 5; // error |
Thì sẽ xuất hiện lỗi, bởi vì giá trị ban đầu là object và bạn vừa assign cho nó một số nguyên, nó đã bị gán lại.
Từ đây các bạn có thể suy ra, Javascript sử dụng kiểu tham chiếu địa chỉ khi khai báo một biến. Ví dụ khi tạo biến myObject
Javascript sẽ tạo ra một vùng nhớ chứa giá trị của myObject
, địa chỉ vùng nhớ này được gán cho biến myObject
và khi sử dụng từ khóa const
thì bạn không được phép thay đổi giá trị mới hay nói cách khác là không trở myObject
tới vùng nhớ khác được nữa. Trong trường hợp object, việc bạn thay đổi giá trị thuộc tính của object thực ra bạn đang thay đổi giá trị tại vùng nhớ kia mà thôi.Tóm lại const
chỉ quan tâm bạn không được thay đổi địa chỉ mới là được.
Vậy nên dung const
trong trường hợp nào. Theo mình nó đặc biệt hữu ích khi dùng để gán giá trị là một target element của html. Ví dụ là khi bạn có một label, label này dùng khi bạn muốn chèn đoạn văn bản nào đấy.
1 | // thời xưa :v |
Tại sao nó lại nên dùng khi gán giá trị là một phần tử của html mà không dùng var? Thứ nhất nay hiện đại rồi, không ai xài var nữa :v thứ hai var có đặc tính là hoisting, scope của nó là function scope, còn với const là blocked scope. Nếu bạn có hiểu qua hoisting rồi thì sẽ hiểu ra chỗ này.
Vậy tại sao không dùng let? Đơn giản hãy để ý, bạn có muốn assign giá trị mới label của bạn không, id
trên HTML thì độc nhất rồi, vậy assign lại làm gì nữa. Vậy cách tốt nhất trong trường hợp này là sử dụng const 😊)
Về let
, let cho phép bạn gán giá trị khác cho một biến đã khai báo, khác với const không cho phép điều đó. Một điểm let
giống const
đó là scope của nó là blocked scope.
Scope thì bạn có thể tìm hiểu them trên mạng nhé. Đại khái là như vầy nè (chạy đoạn code này trên trình duyệt thì sẽ hiểu).
1 | function globalFunc() { // đây là function scope |
Hàm arrow (Arrow functions)
Với tính năng này mình chỉ biết khen thôi, nó thật sự tuyệt zời, trong các feature thì mình thích nó nhất đấy. Code sử dụng arrow function thì sẽ dễ đọc, dễ tổ chức và nhìn có vẻ hiện đại rất nhiều. Thay vì dùng kiểu truyền thống thì chuyển sang dùng arrow sẽ vui hơn đấy.
Sơ qua vậy thì bạn có thể thấy có tuyệt zời không :D, viết ít làm ngang ngửa có khi nhiều hơn cái thèn cũ ấy chứ.
Thêm một ví dụ nữa để bạn thấy arrow function hữu ích là sử dụng nó trong các hàm như map
, filter
và reduce
của array.
1 | const names = ['A', 'B', 'C', 'D']; |
Hai function kia cũng tương tự vậy. Code như vậy mình nghĩ trông sẽ đẹp hơn, dễ đọc và ngắn gọn rất nhiều
- Lưu ý:
1 | const me = { |
Nhưng nếu bạn viết lại như vầy:
1 | const me = { |
this
trong function thường sẽ là this
của object gọi nó, còn this
trong arrow function sẽ là this
bên ngoài nó, nói cách khác, nó không có this
, nó lấy this
bên ngoài mà xài.
Tuy nhiên sửa lại
Rút ra là khi sử dụng kiểu hiện đại thì theo luôn hiện đại và quan trọng hiểu rõ bản chất nhé.
Template Literals
Cái tên này mình quen gọi vậy, nó thuộc kiểu từ ngữ chuyên ngành không nên dịch ra, dịch ra nghe chuối lắm, hiểu là được rồi :v.
Bạn có để ý thấy ở các ví dụ dưới có chi rắc rối loằng ngoằn không.
1 | var name = 'Thang' |
Hic đó là cộng chuỗi trong console @@. Cái ni hồi xưa mình làm và hay bị lỗi thiếu dấu cộng đôi lúc thiếu luôn dấu '
hoặc "
:v. May thay ES6 giới thiệu một giải pháp thay thế, một giải pháp cho người hay loạn mắt (như mình).
1 | // ES6 |
Ôi cha cha, thật dễ nhìn.
Giá trị tham số mặc định
Thực ra ở một ví dụ bên trên mình đã sử dụng cái này rồi
1 | // age có giá trị mặc định là 22 |
Khác với ngôn ngữ khác, khi không truyền giá trị của tham số vào Javascipt tự động “ném” vào một giá trị mặc định t
và nó không sinh ra lỗi gì cả, xem ví dụ là hiểu nè.
1 | // age có giá trị mặc định là 22 |
Class
Như đã show trong ví dụ của arrow functions, class
là một tính năng mới của ES6, trong lập trình hướng đối tượng OOP, class chính là cái core. Nó giúp code của bạn nhìn có tổ chức và đảm bảo tính an toàn cũng như tính đóng gói của các biến.
Cấu trúc một class cơ bản như sau:
1 | class MyClass { |
Ví dụ:
Thừa kế từ class khác ta dùng extends
Bạn có thể đọc thêm về class tại đây https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes.
Array và Object destructing
Với tính năng này việc “bóc tách” thuộc tính hay value từ array hoặc object ra nhanh hơn bao giờ hết.
Ví dụ destructing với object
Vậy nếu mình destructing cái thuộc tính không có thì sao, ví dụ:
1 | const contact = { |
Kết quả nếu destructing một thuộc tính không có trong object, thì mặc định undefined
sẽ được trả về. Vì vậy chúng ta phải luôn đảm bảo tên biến và tên thuộc tính giống nhau. Vậy lỡ tao không muốn dùng tên thuộc tính đó thì làm thế nào, không lẽ tao phải quay về cách hồi xưa ông bà dùng :(. À sorry tao quên mất, còn một cách khác là mày dùng dấu :
(hai chấm) để thay đổi tên, ví dụ như sau:
1 | const contact = { |
Đối với array thì cũng tương tự, ta thay dấu ngoặc nhọn bằng dấu ngoặc vuông là được. Cơ mà không cần tên biến phải giống key của array, destructing của array sẽ xác định dựa vào thứ tự trong mảng đó.
1 | const players = ['Ronaldo', 'Messi', 'Neymar', 'Mbappe']; |
Khác với object bên này nếu destructing ra mà quá array, ví dụ bạn thêm vào player5
thì lỗi sẽ được bắn ra.
Rest parameter và toán tử Spread
Rest parameter
Rest parameter dịch ra là tham số còn lại, dịch ra nghe chuối quá thôi để yên cho nó hay. Nhiệm vụ của nó là lấy đối số truyền vào mà không xác định trước được số lượng và trả về một array, ví dụ:
Bạn muốn hàm sum
tính tổng 100 số do người dùng nhập vào. Vấn đề ở đây là không lẽ tạo ra 100 tham số cho hàm đó với lại nhỡ người dùng thích tính tổng 20 số thôi thì sao? Trong phạm vi bài viết này tui sẽ show bạn cách dùng rest parameter để giải quyết vấn đề này.
Cách giải quyết mang họ chuối (thực ra không ai viết thế này đâu, họ dùng arguments
cơ mà ví dụ này tui làm vậy cho nó thực tế :v):
1 | // setup 100 tham số vào đây |
Cách giải quyết mang tính thời đại
1 | function sum(a, b, ...n ) { |
Cú pháp:
1 | function f(a, b, ...theArgs) { |
Có thể áp dụng rest parameter để destructing đối số truyền vào.
1 | function sum(...[a, b, c]) { |
Vậy nếu không truyền đối số vào cho rest parameter thì như thế nào :)), lúc này thì rest parameter sẽ vẫn là một array nhưng là array có length bằng 0
.
1 | function f(a, b, ...theArgs) { |
Toán tử spread
Còn ở bên kia căn phòng, toán tử có cú pháp giống hệt “rest parameter”. Nhiệm vụ của spread là lấy các đối số vào cho nó sau đó “rải” hay “banh tách” các đối số này ra.
1 | const numbers = [1, 2, 3]; |
Nối mảng như siêu nhân.
1 | const parts = ['shoulders', 'knees']; |
Còn nhiều cái hay ho với cái này nữa, bạn có thể tham khảo tại link sau https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax.
Tóm lược
Nhìn sơ qua hai cái này dễ gây nhầm lẫn, nhất là chỗ destructing, có người A bảo rest paramater dùng để destructing được like that:
1 | const arr = [1, 2, 3, 4, 5, 6, 7]; |
Rồi nhiều người B, C khác nhìn vào bảo đây là spread ra nè, giống spread quá chừng mà.
Người A bảo vậy không sai :)) nhưng họ đi quá nhanh thành ra dễ gây rối và nhầm lẫn cho người mới bắt đầu, bởi vì ri rest parameter lấy đối đối số truyền vào, truyền vào đâu, truyền vào hàm hoặc … cái chi mà cần đối số truyền vào :v. Như ví dụ trên destructing mảng này cần đối số truyền vào để nhận giá trị sau khi destruct ra. Giả sử mảng arr
có length là 100 không lẽ bạn viết 100 đối số nhận giá trị like that:
1 | let [value1, value2, ..., value100] = arr; |
lúc này cái bạn cần là một đối số có khả năng gom các giá trị đã được destruct ra, chỉ có rest parameter thỏa chỗ này. Việc destructing ra thì nó giống spread nó sẽ tách ra sau đó nhờ rest parameter gom lại giúp nó. Túm lại chỗ này rest paramater dùng để destructing là chính xác nhé.
Rest parameter ngược lại với spread, rest thì “gom”, “tích góp” lại còn spread thì “tách”, “rải”, “phá”, “banh” ra.
Import và export
Hai từ khóa này là cải tiến đáng kể giúp cho javascript mạnh hơn bao giờ hết. Chúng cho phép bạn chia nhỏ code ra thành các thành phần và tái sử dụng.
Cách hoặc động của chúng khá đơn giản export
dùng để xuất module (mô đun có thể là biến, mảng object, class …) ra sau đó import
sẽ nhận module đó để sử dụng.
Ví dụ tui có 2 file. Một file tên là detailComponent.js
và file còn lại tên là homeComponent.js
.
Trong file detailComponent.js
tui code một function và muốn export function đó ra, tui viết như sau.
1 | export default function detail(name, age) { |
Trong file homeComponent.js
dùng import
để sử dụng.
1 | import detail from './detailComponent' |
Nếu muốn export nhiều và import nhiều module thì có thể viết lại như sau:
File detailComponent.js
.
1 | exports.detail = function (name, age) { |
File homeComponent.js
.
1 | import { detail, showName, showAge } from './detailComponent' |
Promise
Promises are a new feature of ES6. It’s a method to write asynchronous code. It can be used when, for example, we want to fetch data from an API, or when we have a function that takes time to be executed. Promises make it easier to solve the problem, so let’s create our first Promise!
Promise là một tính năng mới trong ES6 nó giúp bạn viết code bất đồng bộ tốt hơn. Vậy cần dùng promise trong trường hợp nào và dùng nó như thế nào? Ví dụ khi bạn muốn lấy data từ API, việc request tới server API tốn một khoảng thời gian, lúc này bạn cần dùng promise để khi mà API trả về xong, thì promise “báo” cho bạn biết là request đã oke hay không. Cùng viết thử promise xem sao nè.
1 | const myPromise = () => { |
Nếu nhìn vào console log bạn sẽ thấy nó return về một Promise, cơ mà tui muốn in ra dòng Promise ni đã chạy thành công
thôi mà, in ra rứa thì làm ăn được chi đây. Promise nhận 2 tham số truyền vào callback là resolve
và reject
. Resolve handle kết quả nếu thành công, reject thì sẽ xử lý lỗi khi chạy có lỗi.
Ví dụ:
Bây giờ nhìn vào console log thì kết quả là json của API kia được show ra.
ES6 thật sự mà nói có nhiều tính năng thật tuyệt vời, bạn có thể xem thêm tại đây.
Tổng kết
Mặc dù nay đã ra ES7, … đồ rồi, cơ mà ES6 vẫn được xem là một bước tiến lớn của Javascript, nên mình hi vọng các bạn thấy bài viết này hữu ích. Hi vọng nhận được sự ủng hộ, để thời gian mình cố gắng hơn. Cảm ơn bạn đã đọc bài viết. :))
Bài viết có tham khảo từ: https://medium.freecodecamp.org/write-less-do-more-with-javascript-es6-5fd4a8e50ee2