Những tính năng mới trong ECMAScript 2020 (ES11) 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, và nó không ngừng được cải tiến để đáp ứng nhu cầu phát triển ứng dụng web hiện đại. Mỗi năm, ECMAScript – tiêu chuẩn của JavaScript – đều được cập nhật với các tính năng mới giúp lập trình viên viết code dễ đọc hơn, hiệu quả hơn và tối ưu hơn.

ECMAScript 2020 (ES11) là phiên bản mới được phát hành với nhiều cải tiến đáng chú ý, giúp đơn giản hóa cú pháp và nâng cao hiệu suất làm việc với dữ liệu. Một số tính năng nổi bật trong ES11 bao gồm Optional Chaining (?.) giúp truy cập thuộc tính an toàn hơn, Nullish Coalescing Operator (??) giúp kiểm tra giá trị null hoặc undefined dễ dàng hơn, BigInt hỗ trợ làm việc với số nguyên lớn, và Dynamic Import giúp tối ưu hiệu suất khi tải module.

Vậy ES11 có gì mới và tại sao nó lại quan trọng trong lập trình JavaScript hiện đại? Hãy cùng tìm hiểu chi tiết những tính năng nổi bật của ECMAScript 2020 trong bài viết này.

ECMAScript 2020 (ES11) là gì?

ECMAScript 2020 (hay ES11) là phiên bản cập nhật của tiêu chuẩn ECMAScript – nền tảng của JavaScript. Được phát hành vào năm 2020, ES11 tiếp tục bổ sung nhiều tính năng quan trọng giúp đơn giản hóa cú pháp, cải thiện hiệu suất và tối ưu hóa quy trình phát triển ứng dụng web.

Trước đây, các phiên bản ECMAScript trước như ES6, ES7, ES8... đã mang lại nhiều cải tiến đáng kể như let & const, async/await, Promise, Object.entries(), flatMap(), v.v. Với ES11, JavaScript tiếp tục phát triển theo hướng hiện đại hơn với những tính năng mới như Optional Chaining (?.), Nullish Coalescing Operator (??), BigInt, Dynamic Import, v.v.

Tại sao ES11 quan trọng đối với lập trình JavaScript hiện đại?

ES11 đóng vai trò quan trọng trong việc giúp lập trình viên viết code dễ đọc, ngắn gọn và tối ưu hơn. Dưới đây là một số lý do khiến ES11 trở thành một bước tiến quan trọng trong lập trình JavaScript hiện đại:

Tăng cường tính dễ đọc và bảo trì code

  • Tính năng Optional Chaining (?.) giúp truy cập thuộc tính của object một cách an toàn, tránh lỗi khi truy cập giá trị null hoặc undefined.
  • Nullish Coalescing Operator (??) giúp xử lý giá trị null và undefined trực quan hơn so với toán tử ||.

Hỗ trợ làm việc với số nguyên lớn

  • BigInt là một trong những cải tiến quan trọng giúp JavaScript có thể làm việc với số nguyên cực lớn mà trước đây Number không thể xử lý chính xác.

Tối ưu hóa hiệu suất và cải thiện cách quản lý module

  • Dynamic Import (import()) giúp tải module JavaScript một cách linh hoạt, chỉ tải khi cần thiết, giúp tối ưu hiệu suất ứng dụng web.

Cải thiện khả năng làm việc với dữ liệu

  • Promise.allSettled() giúp xử lý nhiều Promise đồng thời mà không bị lỗi khi có một Promise thất bại, giúp ứng dụng ổn định hơn.
  • String.prototype.matchAll() giúp làm việc với biểu thức chính quy (RegEx) dễ dàng hơn.

Được hỗ trợ trên các trình duyệt và môi trường Node.js hiện đại

  • Hầu hết các trình duyệt và phiên bản Node.js mới đều hỗ trợ ES11, giúp lập trình viên có thể sử dụng các tính năng mới mà không lo về khả năng tương thích.

Nhìn chung, ECMAScript 2020 không chỉ giúp lập trình viên viết code hiệu quả hơn mà còn tối ưu hóa cách làm việc với dữ liệu, nâng cao hiệu suất và giúp JavaScript tiếp tục phát triển mạnh mẽ trong kỷ nguyên web hiện đại.

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

Nullish Coalescing Operator (??) – Toán tử hợp nhất nullish

Toán tử ?? là một cách mới để xử lý giá trị null hoặc undefined mà không bị ảnh hưởng bởi các giá trị falsy khác như 0, false, hoặc "".

So sánh giữa ??||

  • Toán tử || (hoặc logic) trả về giá trị đầu tiên có thể chuyển đổi thành true (truthy).
  • Toán tử ?? chỉ kiểm tra nullundefined, không ảnh hưởng đến các giá trị falsy khác như 0, false, "".

Ví dụ ứng dụng thực tế:

let value1 = null ?? "Giá trị mặc định";
console.log(value1); // "Giá trị mặc định"

let value2 = 0 ?? 100; 
console.log(value2); // 0 (giữ nguyên giá trị)

let value3 = "" ?? "Chuỗi mặc định"; 
console.log(value3); // "" (giữ nguyên giá trị)

Ứng dụng của ?? giúp giảm lỗi khi làm việc với dữ liệu động từ API hoặc form nhập liệu.

Optional Chaining (?.) – Truy cập thuộc tính an toàn

Tính năng Optional Chaining (?.) giúp truy cập thuộc tính của object một cách an toàn mà không gây lỗi khi object đó là null hoặc undefined.

Ứng dụng khi làm việc với dữ liệu động từ API response:

Trước đây, khi muốn truy cập thuộc tính sâu trong một object mà không chắc chắn nó tồn tại, chúng ta phải kiểm tra từng bước:

if (user && user.profile && user.profile.address) {
  console.log(user.profile.address.street);
}

Với ES11, chúng ta có thể sử dụng ?. để đơn giản hóa:

console.log(user?.profile?.address?.street); // Không lỗi nếu address không tồn tại

Nếu user.profile.address không tồn tại, kết quả sẽ là undefined thay vì gây lỗi.

Ví dụ minh họa cách sử dụng:

let user = { name: "Alice", profile: { age: 25 } };
console.log(user?.profile?.age); // 25
console.log(user?.contact?.email); // undefined

BigInt – Hỗ trợ số nguyên lớn

Trước ES11, JavaScript chỉ có thể xử lý số nguyên đến 2^53 - 1 (Number.MAX_SAFE_INTEGER). Với BigInt, chúng ta có thể làm việc với số lớn hơn.

Cách sử dụng BigInt với hậu tố n:

let bigNumber = 12345678901234567890n; 
console.log(bigNumber); // 12345678901234567890n
console.log(typeof bigNumber); // "bigint"

Ứng dụng trong tài chính và mật mã:

  • Xử lý số lớn trong giao dịch tài chính.
  • Mã hóa dữ liệu với thuật toán số nguyên lớn.

Promise.allSettled() – Hỗ trợ quản lý nhiều Promise cùng lúc

Trước đây, Promise.all() sẽ thất bại ngay khi có một Promise bị reject. Promise.allSettled() trong ES11 giúp giải quyết vấn đề này bằng cách đợi tất cả Promise hoàn thành, bất kể chúng thành công hay thất bại.

So sánh Promise.all()Promise.allSettled():

let promises = [
  Promise.resolve("Thành công 1"),
  Promise.reject("Lỗi 1"),
  Promise.resolve("Thành công 2"),
];

Promise.all(promises).then(console.log).catch(console.error);
// Lỗi 1 - Dừng ngay lập tức

Promise.allSettled(promises).then(console.log);
// [{status: "fulfilled", value: "Thành công 1"}, {status: "rejected", reason: "Lỗi 1"}, {status: "fulfilled", value: "Thành công 2"}]

Khi gọi nhiều API và cần xử lý tất cả kết quả dù có lỗi.

Dynamic Import – Import module động

Trước ES11, các module phải được import tĩnh ngay từ đầu (import ... from "module"). Dynamic Import cho phép import module khi cần thiết, giúp tối ưu hiệu suất.

Ví dụ cách sử dụng import() để load module động:
async function loadModule() {
  let { default: myModule } = await import("./myModule.js");
  myModule.sayHello();
}
loadModule();
  • Lazy Loading: Chỉ tải code khi cần thiết.
  • Giảm kích thước file JavaScript ban đầu.

String.prototype.matchAll() – Cải tiến trong làm việc với RegEx

Trước đây, String.prototype.match() chỉ trả về mảng kết quả đầu tiên. Với matchAll(), ta có thể lấy tất cả kết quả khớp.

Ví dụ minh họa cách sử dụng:
let text = "ES11 ra mắt năm 2020, ES12 ra mắt năm 2021";
let regex = /ES(\d+)/g;
let matches = [...text.matchAll(regex)];

console.log(matches);
// [
//   ["ES11", "11"], 
//   ["ES12", "12"]
// ]

Khi cần lặp qua nhiều kết quả khớp với RegEx.

globalThis – Truy cập biến toàn cục thống nhất

Trước đây, cách truy cập biến toàn cục khác nhau giữa môi trường:

  • window trong trình duyệt.
  • global trong Node.js.
  • self trong Web Workers.

globalThis giúp truy cập biến toàn cục một cách nhất quán trên mọi môi trường.

Ví dụ minh họa:
globalThis.myVar = "Hello World";
console.log(globalThis.myVar); // "Hello World"

Viết code chạy trên cả trình duyệt và Node.js mà không cần kiểm tra môi trường.

import.meta – Lấy thông tin metadata của module

Tính năng import.meta cho phép lấy thông tin về module hiện tại, hữu ích khi làm việc với ES Modules.

Ví dụ minh họa cách sử dụng:
console.log(import.meta.url); 
// Trả về URL của module đang chạy

Tìm đường dẫn module trong Webpack.Tạo URL động trong ứng dụng web.

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

ECMAScript 2020 (ES11) mang đến nhiều cải tiến giúp lập trình viên viết code ngắn gọn, dễ hiểu, tối ưu hiệu suất, và nâng cao khả năng xử lý dữ liệu. Dưới đây là những ứng dụng quan trọng của ES11 trong thực tế.

Giúp code ngắn gọn, rõ ràng hơn với Nullish Coalescing (??) và Optional Chaining (?.)

Nullish Coalescing (??) – Xử lý giá trị null và undefined hiệu quả hơn

Trước đây, khi muốn kiểm tra giá trị null hoặc undefined, chúng ta thường sử dụng toán tử ||. Tuy nhiên, điều này có thể dẫn đến lỗi không mong muốn nếu giá trị hợp lệ lại là 0, false, hoặc "".

Ví dụ: Không dùng ?? (dễ gây lỗi)

let discount = 0 || 10; // 10 (mặc dù discount có giá trị hợp lệ là 0)
console.log(discount);

Ở đây, vì 0 là falsy, nên || đã trả về 10 không chính xác.

Dùng ?? để tránh lỗi

let discount = 0 ?? 10; // Giữ nguyên 0 vì nó không phải null/undefined
console.log(discount);

Khi xử lý cấu hình mặc định, giá trị đầu vào, hoặc dữ liệu API trả về có thể chứa null hoặc undefined.

Optional Chaining (?.) – Truy cập thuộc tính an toàn

Trước đây, nếu muốn truy cập sâu vào một object mà không chắc chắn tất cả các cấp đều tồn tại, ta phải kiểm tra từng cấp bằng &&:

Ví dụ: Không dùng ?. (cồng kềnh)

if (user && user.profile && user.profile.address) {
  console.log(user.profile.address.street);
}
Dùng ?. giúp code ngắn gọn hơn
console.log(user?.profile?.address?.street); // undefined nếu không tồn tại

Khi làm việc với dữ liệu động từ API, form nhập liệu, hoặc cấu trúc object phức tạp.

Cải thiện hiệu suất với Dynamic Import và Promise.allSettled()

Dynamic Import – Tối ưu hiệu suất tải module

Trước ES11, các module phải được import tĩnh ngay từ đầu, làm tăng thời gian tải trang.

Ví dụ: Import tĩnh (cồng kềnh, không linh hoạt)

import { heavyFunction } from "./heavyModule.js";
heavyFunction();

Ngay cả khi không sử dụng heavyFunction(), module vẫn được tải.

Import động giúp tải module khi cần

async function loadModule() {
  let { heavyFunction } = await import("./heavyModule.js");
  heavyFunction();
}
loadModule();

Lazy loading, tối ưu hiệu suất web, chỉ tải module khi cần.

Promise.allSettled() – Xử lý nhiều Promise hiệu quả hơn

Trước đây, nếu một Promise bị lỗi trong Promise.all(), toàn bộ sẽ bị hủy.

Ví dụ: Promise.all() dừng ngay khi gặp lỗi

Promise.all([
  Promise.resolve("Success 1"),
  Promise.reject("Error"), 
  Promise.resolve("Success 2")
])
.then(console.log)
.catch(console.error); // "Error" - Dừng ngay lập tức

Promise.allSettled() – Đợi tất cả hoàn thành

Promise.allSettled([
  Promise.resolve("Success 1"),
  Promise.reject("Error"),
  Promise.resolve("Success 2")
])
.then(console.log);
// [{status: "fulfilled", value: "Success 1"}, {status: "rejected", reason: "Error"}, {status: "fulfilled", value: "Success 2"}]

Gọi nhiều API song song, không bị gián đoạn khi một API thất bại.

Hỗ trợ tốt hơn trong tính toán số lớn với BigInt

Trước đây, JavaScript không thể xử lý số lớn hơn 2^53 - 1 (Number.MAX_SAFE_INTEGER). Với BigInt, ta có thể làm việc với số nguyên rất lớn, quan trọng trong tài chính, mật mã, và khoa học dữ liệu.

Ví dụ: Dùng BigInt để tính toán số lớn

let bigNumber = 123456789012345678901234567890n;
console.log(bigNumber * 2n); 
// 246913578024691357802469135780n
Xử lý tiền tệ, mã hóa RSA, tính toán khoa học.

Giúp làm việc với dữ liệu và chuỗi hiệu quả hơn với matchAll() và globalThis

matchAll() – Duyệt qua tất cả kết quả của RegEx

Trước ES11, match() chỉ trả về một danh sách tĩnh, không cung cấp vị trí của từng kết quả.

Ví dụ: match() chỉ trả về một mảng đơn giản

let text = "ES11 ra mắt năm 2020, ES12 ra mắt năm 2021";
console.log(text.match(/ES(\d+)/g)); // ["ES11", "ES12"]

matchAll() trả về Iterator chứa thông tin chi tiết

let matches = [...text.matchAll(/ES(\d+)/g)];
console.log(matches);
/*
[
  ["ES11", "11", index: 0, input: "ES11 ra mắt năm 2020, ES12 ra mắt năm 2021"],
  ["ES12", "12", index: 20, input: "ES11 ra mắt năm 2020, ES12 ra mắt năm 2021"]
]
*/

Ứng dụng: Phân tích dữ liệu văn bản, trích xuất thông tin từ chuỗi.

globalThis – Truy cập biến toàn cục nhất quán trên mọi môi trường

Trước đây, truy cập biến toàn cục khác nhau giữa trình duyệt và Node.js.

Ví dụ: Không có globalThis, phải kiểm tra từng môi trường

let globalVar = "Hello";
console.log(typeof window !== "undefined" ? window.globalVar : globalVar); // Không thống nhất

globalThis giúp code chạy đồng nhất

globalThis.globalVar = "Hello";
console.log(globalThis.globalVar); // "Hello"

Viết code chạy trên cả trình duyệt và Node.js mà không cần kiểm tra môi trường.

So sánh ES11 với ES10 trong Javascript

Cả ECMAScript 2019 (ES10) và ECMAScript 2020 (ES11) đều mang đến những cải tiến quan trọng giúp JavaScript ngày càng mạnh mẽ và dễ sử dụng hơn. Tuy nhiên, ES11 tập trung vào việc cải tiến cú pháp để code an toàn hơn, hỗ trợ tốt hơn cho số nguyên lớn, quản lý bất đồng bộ hiệu quả hơn và tối ưu hóa hiệu suất. Dưới đây là những điểm khác biệt chính giữa hai phiên bản.

ES11 cải tiến cú pháp giúp code an toàn hơn so với ES10 (?. và ??)

Optional Chaining (?.) – Viết code ngắn gọn và tránh lỗi undefined

Trong ES10, khi truy cập thuộc tính của một object có thể là undefined hoặc null, chúng ta phải kiểm tra từng cấp một để tránh lỗi.

Ví dụ: Không có ?. trong ES10, phải kiểm tra thủ công

let user = {};
console.log(user && user.profile && user.profile.name); // undefined (cồng kềnh)

ES11 đơn giản hóa với Optional Chaining

console.log(user?.profile?.name); // undefined (không báo lỗi)

Giúp code ngắn gọn hơn, dễ đọc hơn, và giảm rủi ro lỗi khi truy cập object lồng nhau.

Nullish Coalescing (??) – Kiểm tra giá trị null/undefined chính xác hơn

Trong ES10, toán tử || thường được sử dụng để gán giá trị mặc định, nhưng nó có nhược điểm: nếu giá trị hợp lệ là 0, false hoặc "", nó vẫn bị thay thế.

Ví dụ: Dùng || trong ES10 có thể gây lỗi logic

let discount = 0 || 10; // 10 (mặc dù 0 là giá trị hợp lệ)
console.log(discount);

ES11 giải quyết vấn đề với ??

let discount = 0 ?? 10; // 0 (vẫn giữ nguyên vì không phải null/undefined)
console.log(discount);

iúp kiểm tra giá trị chính xác hơn, đặc biệt trong xử lý dữ liệu đầu vào, cấu hình mặc định và dữ liệu API trả về.

ES11 hỗ trợ số nguyên lớn hơn với BigInt, điều mà ES10 chưa có

Trước ES11, JavaScript chỉ có thể xử lý số nguyên trong phạm vi từ -(2^53 - 1) đến 2^53 - 1 (Number.MAX_SAFE_INTEGER). Nếu vượt quá, sẽ có lỗi mất chính xác.

Ví dụ: Giới hạn của số nguyên trong ES10

console.log(9007199254740991 + 1); // 9007199254740992 (sai)
console.log(9007199254740991 + 2); // 9007199254740992 (sai)

ES11 hỗ trợ BigInt giúp tính toán chính xác hơn

let bigNumber = 9007199254740991n + 2n;
console.log(bigNumber); // 9007199254740993n (chính xác)

BigInt giúp xử lý số nguyên lớn trong tài chính, mật mã, và tính toán khoa học, điều mà ES10 không làm được.

Promise.allSettled() trong ES11 giúp quản lý Promise tốt hơn so với Promise.all() trong ES10

Trong ES10, Promise.all() chỉ trả về kết quả khi tất cả Promise thành công. Nếu một Promise bị lỗi, toàn bộ sẽ bị hủy.

Ví dụ: Promise.all() trong ES10 có thể gây lỗi toàn bộ

Promise.all([
  Promise.resolve("Success 1"),
  Promise.reject("Error"),
  Promise.resolve("Success 2")
])
.then(console.log)
.catch(console.error); // "Error" - Dừng ngay lập tức

ES11 giải quyết vấn đề với Promise.allSettled()

Promise.allSettled([
  Promise.resolve("Success 1"),
  Promise.reject("Error"),
  Promise.resolve("Success 2")
])
.then(console.log);
/*
[
  { status: "fulfilled", value: "Success 1" },
  { status: "rejected", reason: "Error" },
  { status: "fulfilled", value: "Success 2" }
]
*/

Giúp xử lý nhiều API song song mà không bị gián đoạn nếu có lỗi.

Dynamic Import trong ES11 giúp tối ưu hiệu suất so với ES10

Trong ES10 và các phiên bản trước đó, các module phải được import ngay từ đầu, làm chậm tốc độ tải trang.

Ví dụ: Import tĩnh trong ES10 (tải tất cả module ngay từ đầu)

import { heavyFunction } from "./heavyModule.js";
heavyFunction(); 

Ngay cả khi heavyFunction() không được gọi, module vẫn tải, làm giảm hiệu suất.

ES11 hỗ trợ Dynamic Import, tải module khi cần thiết

async function loadModule() {
  let { heavyFunction } = await import("./heavyModule.js");
  heavyFunction();
}
loadModule();

Ưu điểm của ES11: Tối ưu hiệu suất, giảm dung lượng tải ban đầu, và cải thiện tốc độ trang web.

Kết bài

ECMAScript 2020 (ES11) đánh dấu một bước tiến quan trọng trong JavaScript với nhiều tính năng mạnh mẽ giúp viết code dễ dàng hơn, ngắn gọn hơn và tối ưu hiệu suất tốt hơn. Những cải tiến như Optional Chaining (?.), Nullish Coalescing (??), BigInt, Promise.allSettled(), Dynamic Import không chỉ giúp lập trình viên làm việc hiệu quả hơn mà còn giúp JavaScript trở nên linh hoạt và mạnh mẽ hơn.

Với việc đơn giản hóa cú pháp, cải thiện khả năng xử lý dữ liệu, và tối ưu hiệu suất, ES11 là một bản nâng cấp quan trọng mà mọi lập trình viên JavaScript nên nắm vững. Nếu bạn đang phát triển ứng dụng hiện đại, hãy tận dụng các tính năng mới này để viết code sạch hơn, nhanh hơn và đáng tin cậy hơn.

Bài viết liên quan