nhat.dev
  • Tin tức
  • Dịch vụ
  • Lập trình
    • ReactJS
    • React Native
    • Angular
    • VueJS
  • Hackintosh
    • Hackintosh
    • Opencore
  • Liên hệ
No Result
View All Result
  • Đăng nhập
logo nhat.dev
  • Tin tức
  • Dịch vụ
  • Lập trình
    • ReactJS
    • React Native
    • Angular
    • VueJS
  • Hackintosh
    • Hackintosh
    • Opencore
  • Liên hệ
No Result
View All Result
nhat.dev
No Result
View All Result
Home Lập trình Javascript

ES2020 có gì hot?

Nhat Tran by Nhat Tran
13 Tháng Ba, 2020
ES2020 có gì hot?
477
SHARES
1.5k
VIEWS
Chia sẻ lên FacebookChia sẻ lên Twitter

Bài viết này chỉ mang tính chất chỉ mặt điểm danh những điểm đáng lưu ý của ES2020. Để xem danh sách chi tiết, bạn hãy nhảy ngay đến trang https://tc39.es. Nếu chưa quen thuộc với quy trình TC39, đừng ngại ngùng và hãy đọc ngay bài viết này của anh Dong Nguyen.

Nullish coalescing

Đầu tiên phải nhắc đến nullish coalescing hay toán tử ??. Theo định nghĩa của MDN, ?? là một toán tử logic sẽ trả về vế phải nếu vế trái là null hoặc undefined. Do đó bạn có thể dùng nó để short-circuit như thế này.

Có thể bạnquan tâm

JavaScript Memoization là gì? Tối ưu Javascript

Những thủ thuật jQuery bạn nên biết

Tôi tái cấu trúc code, refactor như thế nào cho hiệu quả?

function a() {
  return null
}
function b() {
  return 1
}
function c() {
  return 2
}

console.log(a() ?? c()) // 2
console.log(b() ?? c()) // 1

Có lẽ trường hợp sử dụng thường gặp nhất là khi cần khai báo biến là thuộc tính của một đối tượng. Để đề phòng thuộc tính đó không tồn tại (trả về undefined) hoặc có giá trị null, chúng ta hay sử dụng || để gán một giá trị mặc định.

const response = {
settings: {
nullValue: null,
height: 400,
animationDuration: 0,
headerText: '',
showSplashScreen: false,
},
}

// Kết quả: 'for undefined'
const undefinedValue = response.settings.undefinedValue || 'for undefined'

// Kết quả: 'for null'
const nullValue = response.settings.nullValue || 'for null'

Nhưng nếu xui trúng phải thuộc tính có giá trị falsy như 0, '' hay false, || sẽ không hoạt động như mong muốn.

// Boolean('') === false --> 'Hello, world!'
const headerText = response.settings.headerText || 'Hello, world!'

// Boolean(0) === false --> 300
const animationDuration = response.settings.animationDuration || 300

// Boolean(false) === false --> true
const showSplashScreen = response.settings.showSplashScreen || true

Toán tử ?? được đề xuất để giải quyết vấn đề này. Bạn cũng có thể đoán ?? hoạt động tương tự như ||, nhưng vẫn chạy đúng với các giá trị falsy.

// Kết quả: 'for undefined'
const undefinedValue = response.settings.undefinedValue ?? 'for undefined'

// Kết quả: 'for null'
const nullValue = response.settings.nullValue ?? 'for null'

// Kết quả: ''
const headerText = response.settings.headerText ?? 'Hello, world!'

// Kết quả: 0
const animationDuration = response.settings.animationDuration ?? 300

// Kết quả: false
const showSplashScreen = response.settings.showSplashScreen ?? true

Bất ngờ thay

Xem thử đoạn mã sau sử dụng phân rã biến (object destructuring).

const {
underfinedValue = 'for undefined',
nullValue = 'for null',
headerText = 'Hello, world',
} = response.settings

console.log(underfinedValue) // 'for undefined'
console.log(nullValue) // null
console.log(headerText) // ''

Có thể thấy là chỉ khi thuộc tính có giá trị undefined thì giá trị mặc định mới được sử dụng. Ngoài ra null và các giá trị falsy vẫn được gán chính xác.

Optional chaining

Chuyện gì sẽ xảy ra với đoạn mã sau?

const station = {
id: 123,
name: 'EVN Q7 Station',
type: { id: 1, vendor: 'EhkooEV', model: null },
}

console.log(station.type.model.id) // Error: can't access property "id", station.type.model is null
console.log(station.foo.bar) // Error: can't access property "bar", station.foo is undefined

Có lẽ đây là một trong những lỗi thường gặp nhất khi làm việc với JavaScript 🙁 Nhưng không sao, đã có cú pháp ?. để giải quyết vấn đề. ?. cho phép bạn truy xuất sâu vào thuộc tính của các đối tượng lồng nhau, và lỡ như trên đường đời tấp nập, ta vô tình vấp phải một giá trị null hay undefined thì cũng không có lỗi xảy ra.

console.log(station?.foo?.bar) // undefined
console.log(station.type.model?.id) // undefined

?. còn có thể dùng để kiểm tra một phương thức có tồn tại hay không trước khi gọi.

const station = {
id: 123,
name: 'EVN Q7 Station',
}

console.log(station.getName?.()) // undefined

// Hoặc thử đi sâu hơn
console.log(station?.model?.getModelName?.()) // undefined

// Nhưng bạn phải cẩn thận nhe, nếu gọi trúng thuộc tính có tồn tại nhưng không phải là function
console.log(station?.name?.()) // Error: station.name is not a function

?. cũng hoạt động tốt khi truy xuất phần tử của mảng.

const arr = [1, 2, 3, 4, 5]
console.log(arr[999]?.[888]) // undefined

// Thử gọi hàm
console.log(arr[999]?.[888]?.()) // undefined

Promise.allSettled

Chắc bạn đã biết về hàm Promise.all(promises) nhận vào một mảng các promises và trả về kết quả của các promises đó, sau khi chúng được resolved/ fulfilled (chạy thành công). Trong quá trình thực thi Promise.all(), nếu một trong số các promises bị rejected thì Promise.all() cũng sẽ bị rejected. Tương tự như vậy, Promise.allSettled(promises) cũng nhận vào một mảng các promises, nhưng nó sẽ chờ bất đồng bộ cho tất cả các promises được thực thi hết, không quan tâm resolved/ rejected. Sau đó, Promise.allSettled() sẽ trả về một mảng kết quả. Mỗi phần tử của mảng sẽ có thuộc tính sau:

  • Nếu promise được resolved: { status: 'fulfilled', value: <kết quả trả về của promise> }
  • Nếu promise bị rejected: { status: 'rejected', reason: <vì sao promise bị rejected> }

Ví dụ:

const p1 = Promise.resolve(122)
const p2 = Promise.reject(new Error('Me do not like this'))
const p3 = Promise.resolve('foo')

Promise.allSettled([p1, p2, p3]).then(results => console.log(results))
/*
Kết quả là:
[
{
"status": "fulfilled",
"value": 122
},
{
"status": "rejected",
"reason": Error("Me do not like this")
},
{
"status": "fulfilled",
"value": "foo"
}
]
*/

Dynamic import

Bạn đã biết đến dùng import trong ES6 để…à um…import một module.

import fs from 'fs'
import React from 'react'

Cách dùng import như thế này được gọi là static import, và nó cho phép các công cụ đóng gói (build tools) như webpack hay rollup phân tích và tối ưu kết quả sau cùng, chẳng hạn như thực hiện rung cây (tree-shaking). Điểm hạn chế của static import là bạn bắt buộc phải khai báo import ở đầu module, và không thể import module dựa theo một điều kiện nào đó.

Dynamic import, như cái tên gợi ý, cho phép bạn sử dụng module một cách linh động hơn. Cú pháp:

// my/module.js
export function sayOhYeah() {
console.log('Oh yeah!')
}

export default function() {
return 1
}

// index.js
import('/my/module').then(module => {
module.sayOhYeah() // 'Oh yeah!'
module.default() // 1
})

Bạn có thể thấy import() trả về một promise. Do đó bạn có thể dùng async/await để nhìn gọn gàng đẹp đẽ hơn.

// index.js
const module = await import('/my/module')
module.sayOhYeah() // 'Oh yeah!'
module.default() // 1

Lưu ý là mặc dù import() nhìn như một lời gọi hàm, nhưng bản thân import không phải là một hàm đâu nha. Do đó nó không thừa kế từ Function.prototype, nên bạn cũng không thể .call() hay .apply(). Bạn cũng không thể const myImport = import được mô.

Một trong những lợi ích dễ thấy nhất của dynamic import là nó cho phép bạn lazy-loading: chỉ tải các module khi cần thiết. Điều này đặc biệt hữu ích cho các tính năng như bản địa hóa (i18n), khi bạn chỉ cần load tập tin ngôn ngữ trong trường hợp người dùng thay đổi lựa chọn. Hoặc trong các SPA, bạn có thể lazy-load các components dựa vào route.

Top-level await

Giả sử bạn có một module như thế này.

// module.js
import fetchUser from 'states/fetchUser'

// Bạn không thể
const user = await fetchUser() // SyntaxError: await is only valid in async function
console.log(user)

// Mà thay vào đó:
async function run() {
const user = await fetchUser()
console.log(user)
}
run()

Với top-level await, bạn có thể xem module như một async function thật bự và sử dụng từ khóa await thoải mái.

// module.js
import fetchUser from 'states/fetchUser'

// Với top-level await, đoạn mã sau sẽ không sinh ra lỗi
const user = await fetchUser()
console.log(user)

Kết hợp với dynamic import ở trên, code của bạn có thể gọn gàng hơn như thế này.

import getUserPreferences from 'states/getUserPreferences'
const pref = await getUserPreferences()
const lang = await import(`lang/${pref.language}`)
console.log(lang)

Lưu ý là bạn không thể dùng await trong các function không phải async đâu nhe.

function foo() {
const a = await bar() // 💥
}

Đọc thêm: Top level await trên blog của V8.

Thuộc tính riêng tư

Cuối cùng thì JS class cũng có thuộc tính riêng tư (private properties). Bằng cách thêm # vào trước tên thuộc tính hay phương thức, chúng sẽ chỉ có thể được truy cập từ bên trong class đó mà thôi.

class Message {
#message = "Howdy"

greet() {
console.log(this.#message)
}
}

const greeting = new Message()

greeting.greet()
console.log(greeting.#message)

Dấu phân cách số

Tính năng này cho phép bạn đặt dấu phân cách phần ngàn khi khai báo số lớn, giống như thế này.

const motTyHai = 1_200_000_000
const motTyHaiLeNam = 1_200_000_000.05

globalThis

Trước khi có globalThis thì để xác định biến global ở các môi trường khác nhau (node/ service worker/ trình duyệt), bạn phải kiểm tra như thế này:

var getGlobal = function() {
if (typeof self !== 'undefined') {
return self
}
if (typeof window !== 'undefined') {
return window
}
if (typeof global !== 'undefined') {
return global
}
throw new Error('unable to locate global object')
}

Sử dụng globalThis sẽ giải quyết vấn đề trên. Đọc thêm: MDN

Tags: ecmascriptES2020
Bài viết trước

Các dấu hiệu chứng tỏ bạn đang làm việc quá sức

Bài viết sau

Hướng dẫn cài đặt plugin hỗ trợ WordPress trong PhpStorm

Nhat Tran

Nhat Tran

Chia sẻ vài thứ hay ho bản thân tìm hiểu và tìm kiếm được đến mọi người

Bài viết sau
Hướng dẫn cài đặt plugin hỗ trợ WordPress trong PhpStorm

Hướng dẫn cài đặt plugin hỗ trợ WordPress trong PhpStorm

Subscribe
Notify of
guest
guest
0 Comments
Inline Feedbacks
View all comments

Recommended.

Google Analytic là gì? Sử dụng như thế nào?

Google Analytic là gì? Sử dụng như thế nào?

17 Tháng Ba, 2020
Top 10 thư viện hay và hữu ích cho Vue.js

Top 10 thư viện hay và hữu ích cho Vue.js

25 Tháng Tám, 2019

Trending.

Hướng dẫn cài macOS trên Laptop, PC 2019

Hướng dẫn cài macOS trên Laptop, PC 2019

6 Tháng Chín, 2020
Chuẩn bị kiến thức cơ bản trước khi “vọc” hackintosh

Hướng dẫn tạo bộ cài vanilla hackintosh dễ dàng nhất

6 Tháng Ba, 2020
Cách “lách” bản quyền âm thanh và hình ảnh video Youtube 2020

Cách “lách” bản quyền âm thanh và hình ảnh video Youtube 2020

2 Tháng Mười Một, 2020
Chuẩn bị kiến thức cơ bản trước khi “vọc” hackintosh

Phần cứng phù hợp với Hackintosh macOS

30 Tháng Mười Một, 2019
Chuẩn bị kiến thức cơ bản trước khi “vọc” hackintosh

Cài đặt Clover vào ổ cứng sau khi cài macOS

30 Tháng Mười Một, 2019
nhat.dev

© 2019 nhat.dev

Chia sẻ chút kiến thức, kinh nghiệm, thủ thuật mà bản thân đã tìm hiểu và đọc được với mọi người

  • About me
  • Privacy & Policy
  • Advertise
  • Contact

Theo dõi tôi

No Result
View All Result
  • Tin tức
  • Dịch vụ
  • Lập trình
    • ReactJS
    • React Native
    • Angular
    • VueJS
  • Hackintosh
    • Hackintosh
    • Opencore
  • Liên hệ

© 2019 nhat.dev

Xin chào

Sign In with Facebook
OR

Đăng nhập bằng SSO Nhatdev

Quên mật khẩu?

Create New Account!

Fill the forms below to register

All fields are required. Đăng nhập

Lấy lại mật khẩu

Vui lòng nhập tên người dùng hoặc địa chỉ email của bạn để đặt lại mật khẩu của bạn.

Đăng nhập