Những tính năng mới của ECMAScript 2018 (ES9) trong JavaScript

JavaScript Versions | by Học Javascript

ECMAScript (ES) là tiêu chuẩn của JavaScript, đóng vai trò quan trọng trong việc định hình và phát triển ngôn ngữ này theo thời gian. Mỗi phiên bản mới của ECMAScript đều mang lại những cải tiến đáng kể, giúp JavaScript trở nên mạnh mẽ, dễ sử dụng và tối ưu hơn.

ECMAScript 2018 (ES9) là một bản nâng cấp quan trọng, tiếp tục mở rộng các tính năng từ ES8 và bổ sung những cải tiến mới như Rest/Spread Properties cho object, vòng lặp bất đồng bộ (for-await-of), Promise.prototype.finally(), và cải tiến Regular Expressions (RegEx). Những cập nhật này giúp lập trình viên viết code ngắn gọn hơn, dễ bảo trì hơn và xử lý dữ liệu bất đồng bộ hiệu quả hơn.

Trong bài viết này, chúng ta sẽ tìm hiểu chi tiết về các tính năng mới của ES9, ứng dụng của chúng trong lập trình JavaScript và so sánh với các phiên bản trước đó.

ECMAScript 2018 (ES9) là gì?

ECMAScript 2018 (hay còn gọi là ES9) là phiên bản thứ 9 của tiêu chuẩn ECMAScript, được chính thức phát hành vào năm 2018. ES9 tiếp tục mở rộng và cải thiện các tính năng của JavaScript, giúp lập trình viên viết code hiệu quả, dễ hiểu và tối ưu hơn.

Mặc dù ES9 không có quá nhiều thay đổi lớn như ES6, nhưng nó giới thiệu một số cải tiến quan trọng, đặc biệt là về bất đồng bộ (asynchronous programming), object manipulation (xử lý đối tượng)Regular Expressions (Biểu thức chính quy - RegEx).

Tại sao ES9 quan trọng trong lập trình JavaScript?

Cải thiện xử lý bất đồng bộ với Asynchronous Iteration

Trong ES9, JavaScript bổ sung khả năng lặp bất đồng bộ với for-await-of, giúp duyệt qua các iterable object (như mảng hoặc API stream) một cách dễ dàng mà không cần callback hoặc Promise chaining.

  • Dễ đọc hơn so với việc sử dụng .then() hoặc .catch() của Promise.
  • Tối ưu hiệu suất khi xử lý dữ liệu bất đồng bộ như API request hoặc WebSockets.

Ví dụ:

async function fetchData(urls) {
  for await (let url of urls) {
    let response = await fetch(url);
    let data = await response.json();
    console.log(data);
  }
}

Hỗ trợ tốt hơn cho Promises với .finally()

Trước ES9, khi làm việc với Promises, chúng ta chỉ có .then().catch(). Nhưng ES9 đã thêm .finally(), giúp chạy một đoạn mã sau khi Promise hoàn thành (bất kể thành công hay thất bại).

  • Giúp dọn dẹp tài nguyên (ví dụ: đóng kết nối, xóa loading spinner, v.v.).
  • Tránh lặp lại mã xử lý chung cho cả .then() và .catch().

Ví dụ:

fetch("https://api.example.com/data")
  .then(response => response.json())
  .catch(error => console.log("Lỗi:", error))
  .finally(() => console.log("Xử lý xong!"));

Cải thiện cách thao tác Object với Rest/Spread Properties

Trước đây, Rest và Spread chỉ có thể dùng với mảng (Array). ES9 mở rộng khả năng này cho Object, giúp sao chép, gộp hoặc lấy dữ liệu dễ dàng hơn.

  • Viết code gọn hơn, không cần dùng Object.assign().
  • Giúp quản lý dliệu tốt hơn, đặc biệt là khi làm việc với API.
const user = { name: "Alice", age: 25, country: "VN" };
const { name, ...otherInfo } = user; // Tách name, lấy phần còn lại
console.log(otherInfo); // { age: 25, country: "VN" }

const newUser = { ...user, job: "Developer" }; // Gộp object
console.log(newUser); // { name: "Alice", age: 25, country: "VN", job: "Developer" }

Cải tiến Regular Expressions (RegEx) giúp xử lý chuỗi dễ dàng hơn

ES9 mang lại nhiều cải tiến quan trọng cho RegEx, giúp xử lý chuỗi dễ dàng hơn:

  • dotAll mode (s flag): . có thể khớp với ký tự xuống dòng (\n).
  • Named Capture Groups: Đặt tên cho nhóm trong RegEx để truy xuất dễ dàng hơn.
  • Lookbehind Assertions: Kiểm tra ký tự đứng trước trong chuỗi.
  • Unicode Property Escapes: Hỗ trợ kiểm tra ký tự Unicode dễ dàng hơn.

Ví dụ:

const text = "Hello\nWorld";
console.log(/Hello.World/.test(text)); // false (trước ES9)
console.log(/Hello.World/s.test(text)); // true (ES9 hỗ trợ)

const date = "Ngày: 2024-03-18";
const regex = /Ngày: (?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const match = date.match(regex);
console.log(match.groups.year); // "2024"
console.log(match.groups.month); // "03"
console.log(match.groups.day); // "18"

Các tính năng mới trong ES9 (ECMAScript 2018)

ECMAScript 2018 (ES9) mang đến một số cải tiến quan trọng giúp lập trình JavaScript dễ đọc hơn, tối ưu hóa hiệu suất và cải thiện khả năng xử lý dữ liệu bất đồng bộ. Dưới đây là những tính năng chính của ES9 cùng với giải thích và ví dụ minh họa.

Rest/Spread Properties cho Object

Trước ES9, Rest và Spread chỉ có thể được sử dụng với mảng. Trong ES9, JavaScript mở rộng khả năng này cho Object, giúp việc sao chép, trích xuất và gộp dữ liệu trở nên dễ dàng hơn.

Rest Properties (...rest)

Rest giúp lấy phần còn lại của một Object và lưu vào một biến mới.

  • Tách dữ liệu từ object mà không cần xóa thủ công.
  • Hữu ích khi xử lý dữ liệu từ API, lọc thông tin, hoặc chuyển đổi dữ liệu.

Ví dụ:

const user = { name: "Alice", age: 25, country: "VN", job: "Developer" };

const { name, ...otherInfo } = user;  // Lấy name, còn lại lưu vào otherInfo
console.log(name);        // Alice
console.log(otherInfo);   // { age: 25, country: "VN", job: "Developer" }

Spread Properties (...spread)

Spread giúp sao chép một Object hoặc gộp nhiều Object lại với nhau mà không làm thay đổi dữ liệu gốc.

  • Tạo bản sao của Object để tránh thay đổi dữ liệu gốc.
  • Gộp nhiều Object lại với nhau một cách dễ dàng.

Ví dụ:

const user = { name: "Alice", age: 25 };
const job = { title: "Developer", company: "TechCorp" };

const fullProfile = { ...user, ...job }; // Gộp hai object
console.log(fullProfile); 
// { name: "Alice", age: 25, title: "Developer", company: "TechCorp" }

Asynchronous Iteration (Vòng lặp bất đồng bộ)

ES9 giới thiệu for-await-of, giúp duyệt qua các iterable object bất đồng bộ như API, WebSocket, hoặc Stream.

  • Giúp xử lý nhiều request API mà không cần Promise chaining.
  • Tránh callback hell, giúp code dễ đọc hơn khi làm việc với async/await.

Ví dụ:

async function fetchData(urls) {
  for await (let url of urls) {
    let response = await fetch(url);
    let data = await response.json();
    console.log(data);
  }
}

const urls = [
  "https://jsonplaceholder.typicode.com/todos/1",
  "https://jsonplaceholder.typicode.com/todos/2"
];

fetchData(urls);

Giải thích:

  • for-await-of giúp duyệt qua từng URL, gửi request và đợi kết quả.
  • Code dễ đọc hơn so với sử dụng .then() lồng nhau.

Promise.prototype.finally() – Cải thiện xử lý Promise

Trước ES9, khi làm việc với Promise, chúng ta chỉ có .then().catch(). Trong ES9, .finally() được thêm vào giúp chạy một đoạn mã sau khi Promise hoàn thành (bất kể thành công hay thất bại).

  • Dọn dẹp tài nguyên (đóng kết nối, tắt loading spinner, v.v.).
  • Tránh lặp lại mã trong cả .then() và .catch().

Ví dụ:

fetch("https://jsonplaceholder.typicode.com/todos/1")
  .then(response => response.json())
  .catch(error => console.log("Lỗi:", error))
  .finally(() => console.log("Xử lý xong!"));

Giải thích:

  • .finally() luôn chạy dù Promise thành công hay thất bại.
  • Giúp dọn dẹp tài nguyên, ẩn loading spinner, hoặc thực hiện các tác vụ chung.

Regular Expression Enhancements (Cải tiến Biểu thức Chính quy - RegEx)

ES9 cải tiến RegEx với 4 tính năng mới, giúp xử lý chuỗi mạnh mẽ hơn:

dotAll mode (s flag)

Mặc định, dấu . trong RegEx không khớp với ký tự xuống dòng (\n). Trong ES9, s flag giúp dấu . có thể khớp với mọi ký tự, kể cả \n.

Ví dụ:

const text = "Hello\nWorld";
console.log(/Hello.World/.test(text)); // false (trước ES9)
console.log(/Hello.World/s.test(text)); // true (ES9 hỗ trợ)

Named Capture Groups (Nhóm có tên)

Trước ES9, khi dùng dấu ngoặc ( ) trong RegEx, kết quả trả về là một mảng. ES9 cho phép đặt tên cho nhóm, giúp truy xuất dễ dàng hơn.

Ví dụ:

const date = "Ngày: 2024-03-18";
const regex = /Ngày: (?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;

const match = date.match(regex);
console.log(match.groups.year); // "2024"
console.log(match.groups.month); // "03"
console.log(match.groups.day); // "18"

Lookbehind Assertions (?<=?<!)

Trước ES9, JavaScript chỉ hỗ trợ Lookahead Assertions (?=) nhưng không hỗ trợ Lookbehind Assertions (?<=?<!). ES9 bổ sung tính năng này giúp kiểm tra ký tự đứng trước trong chuỗi.

Ví dụ:

const price = "200$";
console.log(/(?<=\$)\d+/.test(price)); // true (số sau $)
console.log(/(?<!\$)\d+/.test(price)); // false (số không đứng sau $)

Giải thích:

  • (?<=\$)\d+ chỉ tìm số nếu nó đứng sau $.
  • (?<!\$)\d+ chỉ tìm số nếu nó KHÔNG đứng sau $.

Unicode Property Escapes (\p{}\P{})

ES9 hỗ trợ tìm kiếm ký tự Unicode bằng cách sử dụng \p{}.

Ví dụ:

console.log(/\p{Emoji}/u.test("")); // true (Emoji)
console.log(/\p{Script=Han}/u.test("漢字")); // true (chữ Hán)

Ứng dụng của ES9 trong lập trình JavaScript

ECMAScript 2018 (ES9) không chỉ giúp đơn giản hóa cú pháp mà còn cải thiện hiệu suất và khả năng xử lý bất đồng bộ trong JavaScript. Dưới đây là những ứng dụng quan trọng của ES9 trong thực tế.

Viết code ngắn gọn và dễ hiểu hơn với Rest/Spread Properties

Trước ES9, khi làm việc với Object, chúng ta phải sử dụng các phương pháp thủ công để trích xuất dữ liệu hoặc sao chép object. Với Rest/Spread Properties, việc này trở nên đơn giản và dễ đọc hơn.

  • Tách dữ liệu từ API response mà không cần lặp lại nhiều dòng code.
  • Sao chép object mà không làm thay đổi dữ liệu gốc.

Ví dụ: Xóa một thuộc tính khỏi Object
Trước ES9, để xóa một thuộc tính trong object, chúng ta phải dùng delete:

const user = { name: "Alice", age: 25, country: "VN" };
delete user.age;
console.log(user); // { name: "Alice", country: "VN" }

Với ES9, chúng ta có thể sử dụng Rest Properties để làm điều này dễ dàng hơn:

const user = { name: "Alice", age: 25, country: "VN" };
const { age, ...userWithoutAge } = user; // Lấy phần còn lại
console.log(userWithoutAge); // { name: "Alice", country: "VN" }

Ví dụ: Gộp nhiều object với Spread Properties

const user = { name: "Alice", age: 25 };
const job = { title: "Developer", company: "TechCorp" };

const profile = { ...user, ...job };
console.log(profile); 
// { name: "Alice", age: 25, title: "Developer", company: "TechCorp" }

Kết quả: Viết code ngắn gọn hơn, dễ đọc và bảo trì hơn.

Tối ưu hóa xử lý bất đồng bộ với for-await-of và .finally()

JavaScript ngày càng phụ thuộc vào bất đồng bộ khi làm việc với API, Database, hoặc Streaming Data. ES9 giúp tối ưu hóa code xử lý bất đồng bộ bằng hai cách:

for-await-of – Lặp qua dữ liệu bất đồng bộ một cách dễ dàng

for-await-of giúp duyệt qua danh sách dữ liệu bất đồng bộ như API requests mà không cần .then() lồng nhau.

Ví dụ: Lặp qua danh sách API mà không cần .then() nhiều lần

async function fetchData(urls) {
  for await (let url of urls) {
    let response = await fetch(url);
    let data = await response.json();
    console.log(data);
  }
}

const urls = [
  "https://jsonplaceholder.typicode.com/todos/1",
  "https://jsonplaceholder.typicode.com/todos/2"
];

fetchData(urls);

Kết quả:

  • Giúp mã nguồn gọn gàng hơn, không cần .then() lồng nhau.
  • Dễ đọc hơn so với cách xử lý Promise truyền thống.

.finally() – Giúp dọn dẹp tài nguyên một cách tự động

Trong ES9, .finally() giúp đảm bảo một đoạn mã luôn được thực thi sau khi một Promise kết thúc (bất kể thành công hay thất bại).

Ví dụ: Hiển thị và ẩn loading spinner khi fetch dữ liệu

console.log("Đang tải dữ liệu...");
fetch("https://jsonplaceholder.typicode.com/todos/1")
  .then(response => response.json())
  .then(data => console.log("Dữ liệu nhận được:", data))
  .catch(error => console.log("Lỗi:", error))
  .finally(() => console.log("Tải dữ liệu xong!"));

Kết quả:

  • Dọn dẹp tài nguyên như đóng kết nối, ẩn spinner khi hoàn tất request.
  • Không cần viết mã lặp lại trong .then().catch().

Cải thiện hiệu suất làm việc với chuỗi bằng các cải tiến RegEx

ES9 cung cấp các cải tiến cho Regular Expressions (RegEx) giúp xử lý chuỗi mạnh mẽ hơn, đặc biệt trong việc tìm kiếm và trích xuất dữ liệu.

  • Tìm kiếm dữ liệu đa dòng trong văn bản với dotAll mode.
  • Trích xuất dữ liệu dễ dàng hơn với Named Capture Groups.
  • Hỗ trợ Lookbehind Assertions để kiểm tra dữ liệu phía trước.

Ví dụ: dotAll mode (s flag) giúp tìm kiếm cả ký tự xuống dòng (\n)

const text = "Hello\nWorld";
console.log(/Hello.World/.test(text)); // false (trước ES9)
console.log(/Hello.World/s.test(text)); // true (ES9 hỗ trợ)

Ví dụ: Named Capture Groups giúp đặt tên cho kết quả tìm kiếm

const date = "Ngày: 2024-03-18";
const regex = /Ngày: (?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;

const match = date.match(regex);
console.log(match.groups.year); // "2024"
console.log(match.groups.month); // "03"
console.log(match.groups.day); // "18"

Kết quả:

  • Code dễ đọc hơn khi xử lý chuỗi với RegEx.
  • Nâng cao hiệu suất làm việc với dữ liệu văn bản.

Được hỗ trợ rộng rãi trên trình duyệt và Node.js hiện đại

ES9 đã được các trình duyệt hiện đại và Node.js hỗ trợ rộng rãi, giúp lập trình viên có thể sử dụng ngay mà không cần thư viện bổ sung.

  • Viết code JavaScript hiện đại, chạy tốt trên Chrome, Firefox, Edge, Safari.
  • Tương thích với Node.js v10+ giúp tối ưu hóa server-side JavaScript.
  • Tích hợp với các framework như React, Vue, Angular để viết ứng dụng web hiệu quả hơn.

Ví dụ: Kiểm tra trình duyệt có hỗ trợ ES9 hay không

if (typeof Object.getOwnPropertyDescriptors === "function") {
  console.log("Trình duyệt hỗ trợ ES9");
} else {
  console.log("Trình duyệt không hỗ trợ ES9");
}

Kết quả:

  • Nếu trình duyệt hỗ trợ ES9, code sẽ chạy mà không cần polyfill.
  • Nếu trình duyệt không hỗ trợ ES9, có thể sử dụng Babel để chuyển đổi.

So sánh ES9 với ES8 trong Javascript

ECMAScript 2018 (ES9) mở rộng và cải tiến nhiều tính năng từ ECMAScript 2017 (ES8), đặc biệt trong xử lý bất đồng bộ, quản lý object, và làm việc với Regular Expressions. Dưới đây là những điểm khác biệt quan trọng giữa ES9 và ES8.

Xử lý bất đồng bộ: ES9 tối ưu hóa với .finally()

Cả ES8 và ES9 đều tập trung vào cải thiện việc xử lý bất đồng bộ, nhưng ES9 giới thiệu .finally() giúp quản lý Promise tốt hơn.

Điểm hạn chế của ES8

Trước ES9, để thực hiện một tác vụ sau khi Promise hoàn thành, chúng ta chỉ có thể dùng .then().catch(). Điều này dẫn đến việc phải lặp lại mã nhiều lần.

Ví dụ trong ES8 (Chưa có .finally())

fetch("https://jsonplaceholder.typicode.com/todos/1")
  .then(response => response.json())
  .then(data => console.log("Dữ liệu nhận được:", data))
  .catch(error => console.log("Lỗi:", error))
  .then(() => console.log("Hoàn thành xử lý!")); // Lặp lại trong .then()

Cải tiến của ES9 với .finally()

Với ES9, chúng ta có thể dùng .finally() để đảm bảo một đoạn mã luôn được thực thi, dù Promise thành công hay thất bại.

Ví dụ trong ES9 (Sử dụng .finally())

fetch("https://jsonplaceholder.typicode.com/todos/1")
  .then(response => response.json())
  .then(data => console.log("Dữ liệu nhận được:", data))
  .catch(error => console.log("Lỗi:", error))
  .finally(() => console.log("Hoàn thành xử lý!")); // Được gọi dù thành công hay thất bại

Kết quả:

  • ES9 giúp code gọn gàng hơn bằng cách loại bỏ logic lặp lại trong .then().
  • .finally() đảm bảo tài nguyên được dọn dẹp đúng cách.

Xử lý Object: ES9 giới thiệu Rest/Spread Properties

Trong ES8, các phương thức Object.values()Object.entries() giúp thao tác với object dễ dàng hơn, nhưng ES9 tiếp tục mở rộng khả năng này với Rest/Spread Properties.

Điểm hạn chế của ES8

ES8 cung cấp Object.values()Object.entries() để làm việc với object dễ dàng hơn, nhưng không hỗ trợ tách hoặc gộp object một cách linh hoạt.

Ví dụ trong ES8 (Sử dụng Object.values()Object.entries())

const user = { name: "Alice", age: 25, country: "VN" };
console.log(Object.values(user)); // ["Alice", 25, "VN"]
console.log(Object.entries(user)); // [["name", "Alice"], ["age", 25], ["country", "VN"]]

Cải tiến của ES9 với Rest/Spread Properties

ES9 bổ sung Rest Properties (...rest) và Spread Properties (...spread), giúp tách dữ liệu và sao chép object một cách linh hoạt hơn.

Ví dụ trong ES9 (Sử dụng ...rest để loại bỏ một thuộc tính khỏi object)

const user = { name: "Alice", age: 25, country: "VN" };
const { age, ...userWithoutAge } = user;
console.log(userWithoutAge); // { name: "Alice", country: "VN" }

Ví dụ trong ES9 (Sử dụng ...spread để gộp object)

const user = { name: "Alice", age: 25 };
const job = { title: "Developer", company: "TechCorp" };

const profile = { ...user, ...job };
console.log(profile); 
// { name: "Alice", age: 25, title: "Developer", company: "TechCorp" }

Kết quả:

  • ES9 giúp thao tác với object giống như mảng trong ES6, làm cho code dễ đọc hơn.
  • Gộp hoặc loại bỏ thuộc tính dễ dàng hơn so với Object.assign().

Cải tiến về Regular Expressions: ES9 linh hoạt hơn

ES8 đã giúp làm việc với object dễ dàng hơn, nhưng chưa cải thiện Regular Expressions (RegEx). ES9 đã khắc phục điều này với các tính năng dotAll mode (s flag), Named Capture Groups, và Lookbehind Assertions.

Điểm hạn chế của ES8

Trước ES9, dấu chấm (.) trong RegEx không khớp với ký tự xuống dòng (\n), gây khó khăn trong xử lý văn bản đa dòng.

Ví dụ trong ES8 (Không thể tìm kiếm xuống dòng)

const text = "Hello\nWorld";
console.log(/Hello.World/.test(text)); // false

Cải tiến của ES9 với dotAll mode (s flag)

ES9 cho phép sử dụng s flag để . khớp với cả xuống dòng (\n).

Ví dụ trong ES9 (Tìm kiếm qua nhiều dòng với s flag)

const text = "Hello\nWorld";
console.log(/Hello.World/s.test(text)); // true

ES9 hỗ trợ Named Capture Groups giúp truy xuất kết quả dễ dàng hơn

Ví dụ trong ES9 (Sử dụng Named Capture Groups)

const date = "Ngày: 2024-03-18";
const regex = /Ngày: (?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;

const match = date.match(regex);
console.log(match.groups.year); // "2024"
console.log(match.groups.month); // "03"
console.log(match.groups.day); // "18"

Kết quả:

  • ES9 giúp RegEx dễ đọc hơn với tên nhóm thay vì chỉ số [1], [2].

ES9 hỗ trợ Lookbehind Assertions giúp kiểm tra ký tự đứng trước

Ví dụ trong ES9 (Tìm kiếm số đứng sau ký tự $)

const price = "Giá: $100";
console.log(/(?<=\$)\d+/.test(price)); // true
console.log(price.match(/(?<=\$)\d+/)[0]); // "100"

Kết quả:

  • ES9 giúp RegEx mạnh mẽ hơn, hỗ trợ tìm kiếm dựa vào ký tự đứng trước.

Kết bài

ECMAScript 2018 (ES9) tiếp tục cải tiến JavaScript bằng cách mở rộng khả năng xử lý bất đồng bộ, tối ưu thao tác với object, và cải thiện Regular Expressions. Những tính năng như .finally(), Rest/Spread Properties, và các nâng cấp về RegEx giúp lập trình viên viết code ngắn gọn hơn, dễ bảo trì hơn và tối ưu hiệu suất tốt hơn.

So với ES8, ES9 mang lại những nâng cấp thực tế hơn, giúp lập trình viên làm việc hiệu quả hơn với Promise, object, và chuỗi. Việc áp dụng những tính năng này sẽ giúp code dễ đọc hơn, linh hoạt hơn và giảm lỗi trong quá trình phát triển.

Với sự hỗ trợ trên hầu hết các trình duyệt hiện đại và môi trường Node.js, ES9 là một bước tiến quan trọng trong sự phát triển của JavaScript, giúp nó trở thành một ngôn ngữ mạnh mẽ hơn, phù hợp với các ứng dụng web hiện đại.

Bài viết liên quan