Web nâng cao (6) - JavaScript cho React (5)

Bài trước: Web nâng cao (5) - JavaScript cho React (4)

-----

1.1       JavaScript cho React (5)

1.1.1       Đối tượng và mảng

Từ phiên bản ES2016 (hay ES7), JavaScript cung cấp các kĩ thuật khá thuận lợi để làm việc với kiểu dữ liệu object và array. Các kĩ thuật này đang được sử dụng rộng rãi trong các ứng dụng viết bằng React. Trong phần này chúng ta cùng tìm hiểu một số kĩ thuật sau:

– Destructuring

– Object literal enhancement

– Spread operator

Destructuring trên object

Trong tiếng Anh, từ structure có nghĩa là cấu trúc; tiền tố “de” có nghĩa là opposite, remove hoặc reduce. Vậy destructure hay destructuring có nghĩa là phá vỡ cấu trúc.

Trong JavaScript, mảng (array) và đối tượng (object) là kiểu dữ liệu có cấu trúc, vậy destructuring một mảng hay đối tượng nghĩa là phá vỡ cấu trúc của mảng hoặc đối tượng ban đầu.

Bạn có thể sử dụng phép gán để chỉ lấy một số thuộc tính trong một đối tượng, tên của thuộc tính được sử dụng để làm tên biến. Ví dụ, đối tượng sinhVien gồm 4 thuộc tính, tuy nhiên chúng ta tạm thời chỉ muốn sử dụng giá trị của 2 thuộc tính là ten, mssv:

const sinhVien = {

      ten: "Van Teo",

      mssv: "00112233",

      lop: "CNTT",

      dangKyMonHoc: ["A", "B", "C"]

     };

     const { ten, mssv } = sinhVien;

     console.log(ten, mssv);// Van Teo 00112233

Việc phá vỡ cấu trúc được thực hiện bằng phép gán nên có thuật ngữ tiếng Anh là destructuring assigment.

Destructuring assigment là cú pháp viết dưới dạng một phép gán, cho phép gán giá trị của một mảng hoặc thuộc tính của một đối tượng vào trong các biến.

Bạn có thể thay đổi giá trị của các biến vừa mới được tạo ra, mà không làm thay đổi giá trị của thuộc tính trong đối tượng gốc. Ví dụ:

 const sinhVien = {

      ten: "Van Teo",

      mssv: "00112233",

      lop: "CNTT",

      dangKyMonHoc: ["A", "B", "C"]

     };

     let { ten, mssv } = sinhVien;

     ten = "Le Ti";

     mssv = "44332211";

     console.log(ten, mssv); // Le Ti 44332211

     console.log(sinhVien.ten, sinhVien.mssv);//Van Teo 00112233

Destructuring một đối tượng truyền vào cho hàm

Thông thường, bạn có thể truy cập thuộc tính của một đối tượng khi truyền cho hàm theo cách sau:

const sinhVien = {

      ten: "Van Teo",

      mssv: "00112233"

     };

     const xuatTen = sv => {

      console.log(`Ten sinh vien la: ${sv.ten}`);

     };

     xuatTen(sinhVien);

Với destructuring, thay vì phải sử dụng dấu chấm (.) để truy cập vào thuộc tính của đối tượng, bạn có thể truyền và truy cập trực tiếp thuộc tính của một đối tượng theo cách sau:

const sinhVien = {

      ten: "Van Teo",

      mssv: "00112233"

     };

     const xuatTen = ({ ten }) => {

      console.log(`Ten sinh vien la: ${ ten }`);

     };

     xuatTen(sinhVien);

Nếu cấu trúc của sinhVien có lồng thêm một đối tượng nữa, thì bạn vẫn có thể truy cập vào thuộc tính của đối tượng con bằng dấu hai chấm (:), ví dụ:

 const sinhVien = {

      ten: "Van Teo",

      mssv: "00112233",

      giaoVien: {

        ten: "Le Ngo",

        tuoi: 30

      }

     };

     const xuatTen = ({ giaoVien: { ten }}) => {

      console.log(`Ten sinh vien la: ${ ten }`);

     };

     xuatTen(sinhVien);

Destructuring trên array

Ví dụ, bạn muốn lấy giá trị đầu tiên của mảng gán vào một biến.

const [firstAnimal] = ['Cat', 'Fish', 'Dog'];

console.log(firstAnimal); // Cat

Bạn cũng có thể sử dụng “mẫu khớp” (list matching) để bỏ qua các giá trị không cần thiết. Trong “mẫu khớp”, giá trị không lấy (bỏ qua) được đại diện bằng dấu phẩy (,). Ví dụ, bạn muốn bỏ qua hai giá trị đầu tiên và chỉ muốn lấy giá trị thứ 3 của mảng:

 const [, , lastAnimal] = ['Cat', 'Fish', 'Dog'];

console.log(lastAnimal); // Dog

1.1.2       Object literal nâng cao – toán tử spread

Object literal nâng cao

Object literal là đối tượng được tạo bằng cặp dấu ngoặc nhọn {}.

Object literal nâng cao (object literal enhancement) là cú pháp viết dưới dạng một object literal, được sử dụng để nhóm các biến toàn cục thành một đối tượng. Có thể thấy object literal nâng cao có chức năng ngược lại so với destructuring.

Ví dụ,

const tenSP = 'sach';

const maSP = '1234';

 

const sp = { tenSP, maSP };

console.log(sp); // {tenSP: "sach", maSP: "1234"}

Object literal nâng cao có thể gom cả phương thức và biến, để tạo ra đối tượng, ví dụ:

const tenSP = 'sach';

const maSP = '1234';

const print = function() {

     console.log(`Ten san pham la ${ this.tenSP }, co ma san pham la ${ this.maSP }`);

}

const sp = { tenSP, maSP, print };

sp.print(); // Ten san pham la sach, co ma so la 1234

Nhờ có object literal nâng cao, bạn có thể khai báo phương thức của một đối tượng mà không cần tới từ khóa function. Ví dụ,

Theo cách cũ, cần có từ khóa function,

var sanPham = {

     tenSP: 'sach',

     maSP: '1234',

     print: function() {

     console.log(`Ten san pham la ${ this.tenSP }, co ma san pham la ${ this.maSP }`);

     }

};

 

sanPham.print();

Theo cách mới, phương thức của đối tượng không cần từ khóa function, đối với thuộc tính thì chỉ cần lấy tên của biến toàn cục vào làm thuộc tính của đối tượng, giá trị của thuộc tính sẽ được tham chiếu ngầm tới giá trị của biến toàn cục. Ví dụ,

     const tenSP = "sach";

     const maSP = "1234";

var sanPham = {

     tenSP,

     maSP,

     print() {

     console.log(`Ten san pham la ${ this.tenSP }, co ma san pham la ${ this.maSP }`);

     }

};

 

sanPham.print();

Toán tử spread

Toán tử spread tạm dịch là toán tử mở rộng (spread có nghĩa là mở rộng), kí hiệu bằng ba dấu chấm (…).

Toán tử spread được dùng để thực hiện một số tác vụ khác nhau, cụ thể:

Nối mảng

Từ hai mảng cho trước, cho thể sử dụng toán tử spread để nối hai mảng lại thành một mảng mới. Ví dụ:

const sinhVien1 = ['Teo', 'Ti', 'Mui'];

const sinhVien2 = ['Quyet', 'Tam', 'Hoc'];

const sinhVien = [...sinhVien1, ...sinhVien2];

console.log(sinhVien);

Lấy phần tử cuối của mảng

Để lấy phần tử cuối của mảng, có thể dựa vào thuộc tính length để lấy phần tử cuối, hoặc sử dụng hàm đảo ngược chuỗi (reverse) kết hợp với destructuring như sau:

const sinhVien1 = ['Teo', 'Ti', 'Mui'];

const [last] = sinhVien1.reverse();

console.log(last); // Mui

// tuy nhien, mang sinhVien1 da bi thay doi, day la ket qua khong mong muon

console.log(sinhVien1); // Mui Ti Teo

Tuy nhiên, cách làm ở đoạn mã trên đã làm thay đổi thứ tự các phần tử trên mảng gốc, đây là kết quả không mong muốn, vì nó sẽ ảnh hưởng đến các xử lý khác.

Để khắc phục chuyện này, có thể sử dụng toán tử spread, nó sẽ nhân bản mảng gốc thành một mảng tạm và thực hiện đảo ngược mảng tạm, như vậy sẽ không làm ảnh hưởng đến mảng gốc, xem ví dụ,

const sinhVien1 = ['Teo', 'Ti', 'Mui'];

const [last] = [...sinhVien1].reverse();

console.log(last); // Mui

// mang sinhVien1 khong bi thay doi

console.log(sinhVien1); // Teo Ti Mui

Lấy các phần tử còn lại của mảng

Từ một mảng cho trước, có thể sử dụng toán tử spread để lấy các phần tử còn lại của một mảng, xem ví dụ,

const sinhVien1 = ['Teo', 'Ti', 'Mui', 'Dan', 'Ngo'];

const [first, second, ...others] = sinhVien1;

console.log(others); // Mui Dan Ngo

Ở đoạn mã trên, biến first sẽ chứa giá trị đầu tiên của mảng, biến second chứa giá trị thứ hai, tất cả các giá trị còn lại của mảng sẽ chứa trong biến others.

Tạo mảng để chứa các tham số của hàm

Có thể sử dụng toán tử spread để định nghĩa một hàm với số tham số không xác định trước. Xem ví dụ sau, hàm directions (chỉ đường) sẽ nhận n đối số thông qua tham số args và thực hiện một số thao tác trên các tham số truyền vào,

function directions(...args) { // chi duong

     let [start,...remaining] = args;

     let [finish, ...stops] = remaining.reverse();

 

     console.log(`Hanh trinh gom ${ args.length } tinh`);

     console.log(`Bat dau xuat phat tai ${ start }`);

     console.log(`Dich den la tinh ${ finish }`);

     console.log(`Dung lai nghi tai ${ stops.length } tinh`);

}

 

directions('Lam dong', 'Khanh hoa', 'Phu yen', 'Binh dinh', 'Quang ngai', 'Quang nam', 'Da nang');

Với cách viết ở đoạn mã trên, có thể truyền vào số tham số tùy ý, đoạn mã vẫn chạy đúng.

Toán tử spread và đối tượng

Các thao tác của toán tử spread áp dụng được trên mảng thì cũng áp dụng được trên đối tượng. Ví dụ sau sẽ kết hợp hai đối tượng có sẵn thành một đối tượng mới,

const thongTinSV = {

     ten: 'Van Teo',

     MSSV: '1234'

};

const lienHeSV = {

     diaChi: '123, BTX, Dalat',

     dienThoai: '0123456789'

};

const sinhVien = {

     ...thongTinSV,

     ...lienHeSV

};

console.log(sinhVien);

// {

//    MSSV: "1234"

//    diaChi: "123, BTX, Dalat"

//    dienThoai: "0123456789"

//    ten: "Van Teo"

// }

1.1.3       Xem và đọc thêm

– Dùng các từ khóa sau để tìm kiếm trên mạng và đọc thêm: destructuring, object literal enhancement, spread operator

– [1] Alex Banks, Eve Porcello, Learning React – Mordern Patterns for Developing React Apps, O’Reilly Media, 2020, p18 – p23

1.1.4       Bài tập và thực hành

Bài tập 1. Viết lại các đoạn mã trong phần lý thuyết để chạy và kiểm tra lại kết quả.

1.1.5       Câu hỏi ôn tập

Câu 1. Trong JavaScript, bạn có thể sử dụng kĩ thuật destructuring để làm gì?

A. Gán giá trị của mảng hoặc thuộc tính của đối tượng vào các biến

B. Tạo ra kiểu dữ liệu cấu trúc

C. Tạo ra một đối tượng

D. Gộp hai đối tượng thành một đối tượng mới

Câu 2. Trong JavaScript, bạn có thể sử dụng Object literal enhancement để làm gì?

A. Tạo ra kiểu dữ liệu cấu trúc

B. Nhóm các biến toàn cục thành một đối tượng

C. Tạo ra mẫu xuất chuỗi

D. Định nghĩa ra một hàm

Câu 3. Trong JavaScript, bạn có thể sử dụng Spread operator để làm gì?

A. Nối mảng và thực hiện các thao tác khác trên mảng

B. Ghép 2 đối tượng thành một đối tượng mới

C. Chuyển đổi từ mảng sang chuỗi

D. Đáp án A và B

Câu 4. Đoạn mã JavaScript này : const [, , test] = ['Cat', 'Fish', 'Dog']; console.log(test); xuất ra kết quả gì ?

A. undefined

B. Cat

C. Fish

D. Dog

Đáp án: 1 (A), 2 (B), 3 (D), 4 (D)

-----

Cập nhật: 22/3/2022

-----