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
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 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
-----