ECMAScript (hay ES) là một chuẩn đặc tả ngôn ngữ kịch bản và nó được tạo ra để tiêu chuẩn hoá cho JavaScript. ECMAScript bản đầu tiên (ES1) ra đời năm 1997 và hiện nay đã trải qua rất nhiều phiên bản. Trong đó, phiên bản ES6 ra đời như một làn gió mới khiến người dùng JavaScript thích thú nhiều hơn.
Bài viết hôm nay hãy cùng mình tìm hiểu những điều làm ES6 được yêu thích như thế nhé 😎
Let’s get started !

Lịch sử phát triển của JavaScript / ECMAScript


Như bạn có thể thấy, ES6 (ECMA2015) ra đời năm 2015 và được hỗ trợ tất cả trình duyệt năm 2018. Nên bạn có thể thoải mái viết ES6 rồi nhé 😗 Hiện tại thì đã có phiên bản ES12, mình sẽ có bài viết nói về các tính năng mới của version này sau nhé.
1. Constant
Trong ES5 bạn không thể dùng từ khoá const để định nghĩa 1 biến bất biến (constant). Mà bạn có thể dùng Object.defineProperty để làm điều đó.
// ES5 Object.defineProperty (window, "VAR_CONSTANT",{ value : 10, writable: false }); // ES6 const VAR_CONSTANT = 10;
2. Scoping without hoisting
Trong ES5, bạn dùng từ khoá var để khai báo 1 biến nào đó. Điều này dẫn đến tình trạng hoisting.
Hoisting là hiểu đơn giản là bạn có thể khai báo lại một biến khi nó đã được sử dụng (vì các biến sẽ được tự động chuyển lên đầu scope để khai báo). Điều này khiến việc quản lý biến của chúng ta trở nên rất phức tạp và dễ bị nhầm lẫn.
Với ES6, bạn có thể giải quyết nó bằng cách khai báo từ khoá với let, const.
// ES5 console.log(a); // undefined var a = 5; // a = 5 var a = 8; // a = 8 // Tương đương (trình duyệt tự hiểu) var a; console.log(a); a = 5;
// ES6 console.log(a); // Error: a is not defined let a = 5; // a = 5 let a = 6; // Error: Identifier 'a' has already been declared
3. Arrow functions
Trong ES6, bạn có một cách định nghĩa function kiểu khác bằng cách sử dụng ký tự =>. Với cách này code của bạn sẽ ngắn gọn và tường minh hơn nhiều.
// ES5 odds = evens.map(function (v) { return v + 1; }); pairs = evens.map(function (v) { return { even: v, odd: v + 1 }; }); nums = evens.map(function (v, i) { return v + i; }); const doSomething = function(){ // ... } // ES6 odds = evens.map(v => v + 1); pairs = evens.map(v => ({ even: v, odd: v + 1 })); nums = evens.map((v, i) => v + i); const doSomething = () => { // ... }
Ngoài ra, Arrow functions còn giải quyết vấn đề binding this. Bạn có thể tham khảo thêm ở đây nhé.
4. Default Parameter Values
Với ES6, bạn có thể gán các giá trị mặc định cho các tham số của hàm, trong trường hợp người dùng không truyền vào thì function sẽ tự lấy giá trị đó để làm mặc định.
// ES5 function f (x, y, z) { if (y === undefined) y = 7; if (z === undefined) z = 42; return x + y + z; }; f(1) === 50; // true // ES6 function f (x, y = 7, z = 42) { return x + y + z } f(1) === 50; // true
5. Rest Parameter
Trong ES6, bạn có thể tổng hợp các tham số còn lại mà người dùng truyền vào hàm thành một tham số duy nhất, một cách ngắn gọn hơn so với ES5 với rest parameter. Điều này rất hữu ích khi bạn không biết trước được chính xác số lượng tham số mà người dùng truyền vào.
// ES5 function f (x, y) { var a = Array.prototype.slice.call(arguments, 2); return (x + y) * a.length; }; f(1, 2, "hello", true, 7) === 9; // ES6 function f (x, y, ...a) { return (x + y) * a.length } f(1, 2, "hello", true, 7) === 9
6. Toán tử Spread
Toán tử … (spread) giúp bạn trải các phần tử của một tập hợp có thể lặp lại (như một mảng hoặc thậm chí một chuỗi) thành cả phần tử và các tham số hàm riêng lẻ. Mình hay dùng toán tử này để clone một mảng đơn giản.
// ES5 var params = [ "hello", true, 7 ]; var other = [ 1, 2 ].concat(params); // [ 1, 2, "hello", true, 7 ] // ES56 var params = [ "hello", true, 7 ]; var other = [ 1, 2, ...params ]; // [ 1, 2, "hello", true, 7 ]
7. Template Literals hay Template String
ES6 hỗ trợ template string, giúp việc nối các chuỗi của chúng ta trở nên dễ dàng và tường minh hơn rất nhiều so với ES5.
var age = 18; var firstName = "Dyno"; var lastName = "Nguyen"; // expect: Xin chào Dyno Nguyen 18 tuổi. // ES5 var message = "Xin chào " + firstName + " " + lastName + " " + age.toString() + " tuổi."; // ES6 var message = `Xin chào ${firstName} ${lastName} ${age} tuổi.`;
Không những thế, với template string bạn có thể viết các chuỗi nhiều dòng liện tục mà không cần dùng các ký tự đặc biệt, hay phải cộng các chuỗi lại (multi-line string hay raw string).
// ES5 var message = "Xin chào!\n" + "Tôi là Dyno Nguyễn.\n" + "Năm nay tôi vừa tròn 18 tuổi.\n"; // ES6 var message = `Xin chào! Tôi là Dyno Nguyễn. Năm nay tôi vừa tròn 18 tuổi.`;
8. Destructuring Assignment
Đây là điều mình thích nhất trong ES6. Với Destructuring Assignment, mọi khai báo trở nên ngắn gọn hơn rất nhiều. Cùng mình tìm hiểu qua một vài ví dụ bên dưới nhé.
// Rút ngắn khai báo với mảng // ES5 var list = [ 1, 2, 3 ]; var a = list[0], b = list[2]; // a = 1, b = 3; // ES6 var list = [ 1, 2, 3 ] var [ a, , b ] = list; // a = 1, b = 3;
// Swap a, b; // ES5 var temp = a; a = b; b = temp; // ES6 [a, b] = [b, a];
function getObj(){ return { a: 1, b: 2, c: 3 }; } // ES5 var obj = getObj(); var a = obj.a; var b = obj.b; var newName = obj.c; // ES6 var { a, b, c: newName } = getObj();
// Gán và đặt giá trị mặc định // ES5 var obj = { a: 1 }; var list = [ 1 ]; var a = obj.a; var b = obj.b === undefined ? 2 : obj.b; var x = list[0]; var y = list[1] === undefined ? 2 : list[1]; // ES6 var obj = { a: 1 } var list = [ 1 ] var { a, b = 2 } = obj var [ x, y = 2 ] = list
Còn nhiều thứ khác nữa, bạn có thể tham khảo thêm ở đây nhé: JavaScript tips and tricks
9. Enhanced Object Properties
Rút ngắn cú pháp khai báo object với ES6 như sau:
// ES5 var x = 0, y = 0; var obj = { x: x, y: y }; // ES 6 var x = 0, y = 0 var obj = { x, y }
10. Promise
ES6 cung cấp cho chúng ta từ khoá Promise để xử lý các trường hợp asynchronous một cách thuận tiện hơn. Tránh trường hợp callback hell ở ES5. Bạn có thể đọc thêm Callback, Promise và Async/Await trong Javascript để hiểu hơn nhé.

// ES 5 function msgAfterTimeout (msg, who, timeout, onDone) { setTimeout(function () { onDone(msg + " Hello " + who + "!"); }, timeout); } msgAfterTimeout("", "Foo", 100, function (msg) { msgAfterTimeout(msg, "Bar", 200, function (msg) { console.log("done after 300ms:" + msg); }); }); // ES6 function msgAfterTimeout (msg, who, timeout) { return new Promise((resolve, reject) => { setTimeout(() => resolve(`${msg} Hello ${who}!`), timeout) }) } msgAfterTimeout("", "Foo", 100).then((msg) => msgAfterTimeout(msg, "Bar", 200) ).then((msg) => { console.log(`done after 300ms:${msg}`) })
11. Map và Set
ES6 đã bổ sung thêm 2 cấu trúc dữ liệu là set và map, 2 dạng cấu trúc dữ liệu này tuy ít sử dụng nhưng vẫn rất hữu ích trong nhiều trường hợp. Mình sẽ có bài viết chi tiết nói về 2 cấu trúc này sau nhé 😙
- Map là cấu trúc dữ liệu mà ta có thể lưu trữ dưới dạng key-value.
- Set là một mảng chứa các dữ liệu không trùng lắp.
const map = new Map(); map.set('firstName', 'Dyno'); map.set('lastName', 'Nguyen'); map.get('firstName'); // Dyno const set = new Set(); set.add(1); set.add(2); set.add(1); console.log(set); // Set(2){1, 2}
12. Exporting & Importing Modules
Ở ES6, nó cung cấp cho chúng ta từ khoá export và import để việc viết và nhập một module dễ dàng và trực quan hơn so với module.exports và require bên ES5. Ngoài ra, nhờ từ khoá import mà ta có rất nhiều cách để nhập một module vào linh hoạt hơn như import * as, import { … }, …
// ES5 var myModule = { x: 1, y: function(){ console.log('This is ES5') }} module.exports = myModule; var myModule = require('./myModule'); // ES6 const myModule = { x: 1, y: () => { console.log('This is ES5') }} export default myModule; import myModule from './myModule';
13. For … of và For … in
Trước đây, để duyệt qua các phần tử của mảng chúng ta hay dùng một biến index để duyệt từ 0 tới cuối mảng hoặc dùng forEach để tối ưu hơn trong vài trường hợp. Thì trong ES6 còn hỗ trợ chúng ta for … of để duyệt mảng khi chỉ cần lấy giá trị thay vì index.
Và for … in để duyệt qua các key của một object.
var nums = [1, 2, 3, 4, 5]; // ES5 var i, len = nums.length; for(i = 0; i < len; ++i){ console.log(len[i]); } // ES6 for(let num of nums){ console.log(num); }
14. Class và OOP trong JavaScript
Từ ES6, Javascript đã hỗ trợ cho chúng ta class để viết OOP như các ngôn ngữ khác. Thay vì chỉ sử dụng object với prototype như ES5. Ngoài ra, nó còn hỗ trợ constructor, getter, setter, extends đầy đủ cho anh em nghịch ngợm 😂
// ES5 var Shape = function (id, x, y) { this.id = id; this.move(x, y); }; Shape.prototype.move = function (x, y) { this.x = x; this.y = y; }; // ES6 class Shape { constructor (id, x, y) { this.id = id this.move(x, y) } move (x, y) { this.x = x this.y = y } }
Những điều làm ES6 được yêu thích
Tạm kết
Tất cả bên trên là những điều làm ES6 được yêu thích theo ý kiến của mình. Ngoài ra thì vẫn còn một vài thứ hay ho khác, nhưng do bài viết này đã quá dài nên mình xin dừng tại đây. Các bạn có thể tham khảo thêm tại:
Cảm ơn mọi người đã đọc bài viết này 😘
Bạn có thể tham khảo thêm: