Những tính năng mới ECMAScript 2019 (ES10) trong JavaScript

JavaScript Versions | by Học Javascript

JavaScript là một trong những ngôn ngữ lập trình phổ biến nhất hiện nay, được sử dụng rộng rãi trong phát triển web và ứng dụng hiện đại. Để đáp ứng nhu cầu ngày càng cao của lập trình viên, ECMAScript – tiêu chuẩn của JavaScript – liên tục được cập nhật với các tính năng mới, giúp cải thiện cú pháp, tối ưu hiệu suất và tăng cường khả năng xử lý dữ liệu.

ECMAScript 2019 (ES10) là phiên bản tiếp theo của tiêu chuẩn này, mang đến nhiều cải tiến quan trọng giúp lập trình viên viết code dễ dàng hơn. Những tính năng như Array.prototype.flat(), Object.fromEntries(), Optional Catch Binding, String.trimStart()/trimEnd(), và nhiều cải tiến khác giúp JavaScript trở nên mạnh mẽ và linh hoạt hơn.

Trong bài viết này, mình sẽ tìm hiểu chi tiết những tính năng mới của ES10, so sánh với các phiên bản trước và tìm hiểu cách áp dụng chúng vào thực tế.

ECMAScript 2019 (ES10) là gì?

ECMAScript 2019 (hay ES10) là phiên bản tiêu chuẩn ECMAScript được phát hành vào năm 2019, tiếp tục cải tiến và bổ sung các tính năng giúp JavaScript trở nên mạnh mẽ hơn. So với các phiên bản trước, ES10 không thay đổi quá nhiều về mặt cú pháp nhưng vẫn mang lại nhiều tiện ích quan trọng, giúp lập trình viên viết code dễ dàng hơn, tối ưu hiệu suất và xử lý dữ liệu hiệu quả hơn.

Sau sự ra đời của ES6 (2015) với những thay đổi lớn như let, const, arrow function, class, modules, các phiên bản tiếp theo tập trung vào việc tối ưu hóa, nâng cao hiệu suất và cải thiện cú pháp để giúp JavaScript thân thiện hơn với lập trình viên. ES10 là một bước tiến tiếp theo, bổ sung những công cụ hữu ích cho lập trình viên mà không làm thay đổi quá nhiều cách thức hoạt động của ngôn ngữ.

Những cải tiến quan trọng của ES10 giúp JavaScript linh hoạt và hiệu quả hơn

Array.prototype.flat() và Array.prototype.flatMap()

  • flat() giúp làm phẳng mảng nhiều cấp độ, giúp xử lý dữ liệu dễ dàng hơn.
  • flatMap() kết hợp map()flat(), giúp tối ưu hóa xử lý mảng.

Ví dụ:

const arr = [1, 2, [3, 4, [5, 6]]];
console.log(arr.flat(2)); 
// Output: [1, 2, 3, 4, 5, 6]

Object.fromEntries() – Chuyển mảng key-value thành object

  • Chuyển một mảng chứa các cặp [key, value] thành một object.
  • Dễ dàng tạo object từ các dữ liệu có cấu trúc danh sách.

Ví dụ:

const entries = [['name', 'Alice'], ['age', 25]];
const obj = Object.fromEntries(entries);
console.log(obj); 
// Output: { name: 'Alice', age: 25 }

String.prototype.trimStart() và trimEnd()

  • trimStart() loại bỏ khoảng trắng ở đầu chuỗi.
  • trimEnd() loại bỏ khoảng trắng ở cuối chuỗi.

Ví dụ:

const str = "   Hello World!   ";
console.log(str.trimStart()); // "Hello World!   "
console.log(str.trimEnd());   // "   Hello World!"

Optional Catch Binding – Viết gọn try...catch

  • Trong ES10, không bắt buộc phải khai báo biến lỗi trong catch().

Ví dụ:

try {
  throw new Error("Lỗi!");
} catch { // Không cần đặt (error)
  console.log("Có lỗi xảy ra!");
}

Symbol.prototype.description – Lấy mô tả của Symbol

  • Truy xuất mô tả của Symbol dễ dàng hơn với .description.

Ví dụ:

const sym = Symbol("Mô tả");
console.log(sym.description); // "Mô tả"

JSON.stringify() cải tiến – Hiển thị chính xác số nguyên lớn

  • Tránh lỗi khi xử lý số nguyên lớn trong JavaScript.

Ví dụ:

console.log(JSON.stringify({ value: 1n })); 
// Output: '{"value":"1"}'

Cải tiến Regular Expression (RegEx)

  • dotAll flag (s): . có thể khớp với ký tự xuống dòng (\n).
  • Unicode Property Escapes (\p{}): Dễ dàng làm việc với ký tự Unicode.

Ví dụ:

const regex = /hello.world/s; 
console.log(regex.test("hello\nworld")); // true

Các tính năng mới trong ES10 trong Javascript

Array.prototype.flat() và Array.prototype.flatMap() – Xử lý mảng lồng nhau dễ dàng hơn

flat(depth): Làm phẳng mảng lồng nhau với độ sâu tùy chỉnh

Trước đây, khi làm việc với mảng lồng nhau, lập trình viên phải dùng vòng lặp hoặc reduce() để xử lý. Với ES10, phương thức flat() giúp làm phẳng mảng dễ dàng hơn bằng cách chỉ định độ sâu (depth).

Ví dụ:

const arr = [1, 2, [3, 4, [5, 6]]];

console.log(arr.flat());  // Mặc định depth = 1
// Output: [1, 2, 3, 4, [5, 6]]

console.log(arr.flat(2)); // Làm phẳng tới độ sâu 2
// Output: [1, 2, 3, 4, 5, 6]

flatMap(callback): Kết hợp map()flat() để xử lý mảng hiệu quả hơn

  • flatMap() giúp xử lý dữ liệu tốt hơn khi vừa cần biến đổi (map) vừa làm phẳng (flat).
  • Thay vì dùng map().flat(), ES10 cung cấp flatMap() để tối ưu hiệu suất.

Ví dụ:

const arr = [1, 2, 3];

const result = arr.flatMap(num => [num, num * 2]);

console.log(result);
// Output: [1, 2, 2, 4, 3, 6]

Object.fromEntries() – Chuyển đổi danh sách cặp key-value thành object

  • Trước đây, khi muốn chuyển một danh sách cặp [key, value] thành object, lập trình viên phải dùng vòng lặp hoặc reduce().
  • ES10 giới thiệu Object.fromEntries(), giúp tạo object từ mảng cặp key-value một cách đơn giản.

Ứng dụng trong xử lý dữ liệu JSON và API

Khi làm việc với API trả về dữ liệu dạng mảng key-value, ta có thể chuyển đổi nó thành object một cách dễ dàng.

Ví dụ:

const entries = [['name', 'Alice'], ['age', 25]];

const obj = Object.fromEntries(entries);

console.log(obj);
// Output: { name: 'Alice', age: 25 }

So sánh với Object.entries()

  • Object.entries(obj): Biến object thành mảng key-value.
  • Object.fromEntries(arr): Biến mảng key-value thành object.

Ví dụ:

const user = { id: 1, username: "Alice" };

const entries = Object.entries(user);
console.log(entries); 
// Output: [['id', 1], ['username', 'Alice']]

const newUser = Object.fromEntries(entries);
console.log(newUser);
// Output: { id: 1, username: 'Alice' }

String.prototype.trimStart() và String.prototype.trimEnd() – Loại bỏ khoảng trắng đầu/cuối chuỗi

Trước ES10, JavaScript chỉ có trim(), nhưng ES10 bổ sung hai phương thức mới:

  • trimStart() (tương đương trimLeft() nhưng chuẩn hơn).
  • trimEnd() (tương đương trimRight()).

Ví dụ:

const str = "   Hello World!   ";

console.log(str.trimStart()); // "Hello World!   "
console.log(str.trimEnd());   // "   Hello World!"

Ứng dụng: Hữu ích khi làm việc với dữ liệu đầu vào của người dùng hoặc khi xử lý văn bản từ API.

Optional Catch Binding – Đơn giản hóa khối try...catch

  • Trước đây, khi sử dụng catch(), ta phải định nghĩa một biến cho lỗi, ngay cả khi không dùng đến.
  • ES10 cho phép bỏ qua biến lỗi nếu không cần xử lý lỗi cụ thể.

Ví dụ:

try {
  throw new Error("Lỗi!");
} catch {  // Không cần đặt (error)
  console.log("Có lỗi xảy ra!");
}

Lợi ích: Viết code ngắn gọn hơn khi không cần truy xuất lỗi.

Symbol.prototype.description – Lấy mô tả của Symbol

  • Trước đây, để lấy mô tả của Symbol, ta phải gọi String(symbol).
  • ES10 cho phép truy xuất trực tiếp với .description.

Ví dụ:

const sym = Symbol("Mô tả");

console.log(sym.description); 
// Output: "Mô tả"

Hữu ích khi debug hoặc log thông tin.

JSON ⬌ Buffer – Cải thiện xử lý dữ liệu trong Node.js

  • Trước ES10: Không có cách trực tiếp chuyển đổi giữa JSONBuffer.
  • ES10: Cải thiện khả năng serialize/deserialize dữ liệu nhị phân trong Node.js.

Ví dụ:

const buffer = Buffer.from('Hello');
const json = JSON.stringify(buffer);
console.log(json);
// Output: {"type":"Buffer","data":[72,101,108,108,111]}

Well-formed JSON.stringify() – Xử lý tốt hơn các ký tự đặc biệt trong JSON

  • ES10: JSON.stringify() giờ đây xử lý tốt hơn các ký tự UTF-8 không hợp lệ.
  • Trước đây, nếu chuỗi chứa ký tự không hợp lệ, nó có thể gây lỗi khi parse JSON.

Ví dụ:

console.log(JSON.stringify("\uD800"));
// Trước ES10: '"�"' (ký tự lỗi)
// ES10: '"\\ud800"' (mã Unicode hợp lệ)

Function.prototype.toString() – Hiển thị định nghĩa chính xác của function

  • Trước ES10, toString() của function có thể thay đổi hoặc bị chuẩn hóa lại.
  • ES10: toString() trả về nội dung chính xác như khi khai báo.

Ví dụ:

function test() {
  console.log("Hello World!");
}

console.log(test.toString());
/*
Output:
function test() {
  console.log("Hello World!");
}
*/

Hữu ích trong debug, kiểm tra function runtime.

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

ECMAScript 2019 (ES10) mang lại nhiều tính năng giúp lập trình viên viết code ngắn gọn hơn, dễ đọc hơn và tối ưu hóa hiệu suất. Dưới đây là một số ứng dụng cụ thể của ES10 trong thực tế.

Giúp code ngắn gọn và dễ đọc hơn

Các phương thức mới như flatMap(), trimStart(), trimEnd(), và Optional Catch Binding giúp loại bỏ những đoạn code dài dòng không cần thiết, cải thiện khả năng đọc code.

Ứng dụng của flatMap() trong xử lý mảng phức tạp

  • Khi làm việc với dữ liệu dạng mảng lồng nhau hoặc cần vừa map vừa làm phẳng dữ liệu, flatMap() giúp giảm số dòng code cần viết.
  • Trước đây, lập trình viên phải dùng map() kết hợp với flat(), nhưng ES10 giúp xử lý gọn hơn.

Ví dụ:

const orders = [
  { id: 1, items: ["Laptop", "Mouse"] },
  { id: 2, items: ["Keyboard"] },
];

const items = orders.flatMap(order => order.items);
console.log(items);
// Output: ["Laptop", "Mouse", "Keyboard"]

Ứng dụng của trimStart()trimEnd() trong xử lý chuỗi đầu vào

  • Khi nhận dữ liệu từ người dùng hoặc API, khoảng trắng thừa ở đầu/cuối chuỗi có thể gây lỗi khi xử lý.
  • ES10 giúp chuẩn hóa chuỗi nhập vào mà không cần dùng trim() toàn bộ.

Ví dụ:

const userInput = "   Hello, World!   ";
console.log(userInput.trimStart()); // "Hello, World!   "
console.log(userInput.trimEnd());   // "   Hello, World!"

Optional Catch Binding giúp viết code ngắn gọn hơn

  • Trong các tình huống xử lý ngoại lệ mà không cần chi tiết lỗi, ES10 giúp loại bỏ biến lỗi không cần thiết.

Ví dụ:

try {
  JSON.parse("{ invalid JSON }");
} catch {
  console.log("Lỗi JSON không hợp lệ!");
}

Cải thiện hiệu suất xử lý dữ liệu JSON, Buffer, và Symbol

Một số cải tiến trong ES10 giúp xử lý dữ liệu hiệu quả hơn trong ứng dụng web và server-side.

Ứng dụng của Object.fromEntries() trong việc xử lý dữ liệu API

  • Khi làm việc với API trả về mảng key-value, ES10 giúp chuyển đổi nó thành object nhanh chóng.

Ví dụ:

const entries = new Map([
  ["name", "Alice"],
  ["age", 25],
]);

const user = Object.fromEntries(entries);
console.log(user);
// Output: { name: "Alice", age: 25 }

Ứng dụng của Symbol.prototype.description trong debug và logging

  • Trước ES10, việc truy xuất mô tả của Symbol khá bất tiện, nhưng giờ đây có thể dễ dàng lấy thông tin cho mục đích debug.

Ví dụ:

const sym = Symbol("ID của user");
console.log(sym.description); // Output: "ID của user"

Cải thiện hiệu suất JSON với Well-formed JSON.stringify()

  • Trước ES10, khi JSON.stringify() gặp ký tự không hợp lệ, nó có thể tạo lỗi không mong muốn.
  • ES10 giúp xử lý tốt hơn với các ký tự UTF-8 không hợp lệ.

Ví dụ:

console.log(JSON.stringify("\uD800")); // Output: '"\\ud800"' (thay vì lỗi)

Xử lý dữ liệu nhị phân với JSON ⬌ Buffer trong Node.js

  • Khi làm việc với dữ liệu nhị phân trong Node.js, ES10 giúp chuyển đổi giữa BufferJSON dễ dàng hơn.

Ví dụ:

const buffer = Buffer.from("Hello");
const json = JSON.stringify(buffer);
console.log(json);
// Output: {"type":"Buffer","data":[72,101,108,108,111]}

Hỗ trợ trên trình duyệt hiện đại và Node.js

Tương thích tốt với trình duyệt và Node.js

  • Các tính năng mới trong ES10 được hỗ trợ trên hầu hết các trình duyệt hiện đại như Chrome, Firefox, Edge, Safari.
  • Các tính năng như flatMap(), Object.fromEntries(), và cải tiến JSON giúp tối ưu hiệu suất cho các ứng dụng webserver-side.

Ứng dụng trong dự án thực tế

  • Frontend:
    • Xử lý chuỗi: trimStart(), trimEnd() giúp chuẩn hóa dữ liệu nhập từ form.
    • Xử lý mảng: flatMap() giúp tối ưu hóa dữ liệu trả về từ API.
  • Backend (Node.js):
    • Xử lý JSON & Buffer: Cải tiến giúp xử lý dữ liệu nhị phân nhanh hơn.

So sánh ES10 với ES9 trong Javascript

ECMAScript 2019 (ES10) và ECMAScript 2018 (ES9) đều mang đến những cải tiến quan trọng cho JavaScript, nhưng chúng có những khác biệt rõ ràng về mục tiêu phát triển:

  • ES9 (2018) tập trung vào cải tiến bất đồng bộ, xử lý Promise, và tối ưu hóa thao tác với object.
  • ES10 (2019) hướng đến tối ưu hiệu suất, đơn giản hóa cú pháp, và nâng cao khả năng xử lý mảng, chuỗi, JSON.

Dưới đây là những so sánh chi tiết giữa ES9 và ES10.

Xử lý mảng: ES10 tối ưu hơn với flat() và flatMap()

ES9: Tập trung vào Rest/Spread Properties để thao tác object

  • Rest Properties (...rest): Giúp lấy phần còn lại của object khi destructuring.
  • Spread Properties (...spread): Giúp gộp nhiều object lại với nhau dễ dàng.

Ví dụ trong ES9:

const user = { id: 1, name: "Alice", age: 25 };
const { id, ...info } = user;

console.log(info); // Output: { name: "Alice", age: 25 }

ES10: Thêm flat()flatMap() để xử lý mảng dễ dàng hơn

  • flat(depth): Làm phẳng mảng lồng nhau.
  • flatMap(callback): Kết hợp map()flat() để xử lý dữ liệu nhanh hơn.

Ví dụ trong ES10:

const nestedArray = [1, [2, [3, 4]], 5];
console.log(nestedArray.flat(2)); // Output: [1, 2, 3, 4, 5]

const numbers = [1, 2, 3];
console.log(numbers.flatMap(n => [n, n * 2])); 
// Output: [1, 2, 2, 4, 3, 6]
  • ES9 tập trung vào object (...rest, ...spread).
  • ES10 giúp xử lý mảng tốt hơn với flat()flatMap().

Bất đồng bộ: ES9 mạnh hơn với for-await-of, ES10 tối ưu hóa try...catch

ES9: Hỗ trợ for-await-of để xử lý bất đồng bộ tốt hơn

  • Dùng với async/await để lặp qua các iterable object bất đồng bộ như API hoặc stream.

Ví dụ trong ES9:

async function fetchData(urls) {
  for await (const url of urls) {
    console.log(await fetch(url).then(res => res.json()));
  }
}

ES10: Đơn giản hóa try...catch với Optional Catch Binding

  • Không cần khai báo biến lỗi khi dùng catch.
  • Giúp code ngắn gọn hơn khi không cần xử lý lỗi chi tiết.

Ví dụ trong ES10:

try {
  JSON.parse("{ invalid JSON }");
} catch {
  console.log("Lỗi JSON không hợp lệ!");
}
  • ES9 tối ưu bất đồng bộ với for-await-of.
  • ES10 giúp try...catch gọn hơn với Optional Catch Binding.

Xử lý Promise: ES9 tập trung vào bất đồng bộ, ES10 thêm .finally()

ES9: Không có .finally(), chỉ có then()catch()

  • Nếu muốn thực hiện hành động sau khi Promise hoàn thành, cần gọi then() hoặc catch().

Ví dụ trong ES9:

fetch("https://api.example.com/data")
  .then(response => console.log("Success", response))
  .catch(error => console.log("Error", error));

ES10: Thêm Promise.prototype.finally() để xử lý tác vụ sau khi Promise kết thúc

  • .finally() giúp dọn dẹp tài nguyên hoặc thực hiện hành động chung sau khi Promise hoàn tất (thành công hoặc thất bại).

Ví dụ trong ES10:

fetch("https://api.example.com/data")
  .then(response => console.log("Success", response))
  .catch(error => console.log("Error", error))
  .finally(() => console.log("Request done!"));
  • ES9 chỉ có then()catch().
  • ES10 thêm .finally() để dọn dẹp tài nguyên dễ dàng hơn.

Cải tiến Biểu thức Chính quy (RegEx): ES9 mạnh hơn

ES9: Nâng cấp mạnh mẽ RegEx với dotAll, Named Capture Groups, Lookbehind

  • dotAll mode (s flag): Dấu . có thể khớp với ký tự xuống dòng (\n).
  • Named Capture Groups ((?<name>...)): Đặt tên nhóm trong RegEx.
  • Lookbehind Assertions (?<=?<!): Kiểm tra ký tự đứng trước.

Ví dụ trong ES9:

const regex = /(?<=\$)\d+/;
console.log("$100".match(regex)); // Output: ["100"]

ES10: Không có nhiều thay đổi về RegEx

  • ES10 tập trung vào cải thiện JSON, Buffer và Symbol hơn là RegEx.
  • ES9 mạnh về RegEx, giúp thao tác chuỗi tốt hơn.
  • ES10 không thay đổi nhiều về RegEx, tập trung vào JSON và Symbol.

JSON và Buffer: ES10 tối ưu hơn

ES9: Chưa tối ưu tốt JSON.stringify()

  • Khi gặp ký tự UTF-8 không hợp lệ, JSON.stringify() có thể gây lỗi.

ES10: Well-formed JSON.stringify() giúp xử lý tốt hơn

  • Ngăn chặn lỗi khi stringify chuỗi chứa ký tự không thể mã hóa.

Ví dụ trong ES10:

console.log(JSON.stringify("\uD800")); // Output: '"\\ud800"' (thay vì lỗi)
  • ES9 chưa xử lý tốt JSON.
  • ES10 giúp JSON.stringify() ổn định hơn khi gặp ký tự đặc biệt.

ES9 và ES10 bổ sung lẫn nhau

Tính năng ES9 (2018) ES10 (2019)
Xử lý mảng Không có flat()flatMap() Thêm flat(), flatMap() giúp xử lý mảng dễ dàng
Bất đồng bộ for-await-of giúp duyệt bất đồng bộ Optional Catch Binding giúp try...catch gọn hơn
Promise Chỉ có then(), catch() Thêm .finally() để xử lý sau khi Promise kết thúc
RegEx Thêm dotAll (s flag), Named Capture Groups, Lookbehind Không thay đổi nhiều về RegEx
JSON JSON.stringify() có thể lỗi với UTF-8 Well-formed JSON.stringify() giúp ổn định hơn

Kết bài

ECMAScript 2019 (ES10) tiếp tục cải tiến JavaScript bằng cách tối ưu hiệu suất, đơn giản hóa cú pháp và nâng cao khả năng xử lý dữ liệu. Các tính năng như flat()flatMap() giúp làm việc với mảng dễ dàng hơn, Object.fromEntries() hỗ trợ chuyển đổi dữ liệu linh hoạt, còn Optional Catch Binding giúp code gọn gàng hơn khi xử lý lỗi. Bên cạnh đó, Promise.prototype.finally() giúp quản lý bất đồng bộ tốt hơn, và cải tiến JSON.stringify() giúp xử lý dữ liệu ổn định hơn.

So với ES9, ES10 không chỉ tập trung vào việc tối ưu hóa bất đồng bộ mà còn mang đến các cải tiến thực tế giúp lập trình viên viết code hiệu quả hơn. Với sự hỗ trợ rộng rãi trên các trình duyệt hiện đại và Node.js, ES10 tiếp tục khẳng định tầm quan trọng của JavaScript trong phát triển web. Việc cập nhật và sử dụng các tính năng mới sẽ giúp lập trình viên tận dụng tối đa sức mạnh của JavaScript, nâng cao hiệu suất và cải thiện trải nghiệm người dùng.

Bài viết liên quan