Những điều làm ES6 được yêu thích

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 !

Những điều làm ES6 được yêu thích

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

Lịch sử phát triển của JavaScript / ECMAScript
Nguồn: JS / ECMA History – W3School
Lịch sử phát triển của JavaScript / ECMAScript
Nguồn: JS / ECMA History – W3School

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é.

callback hell
Callback hell
// 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:

Để lại một bình luận nhé