JavaScript: Các phương thức định nghĩa và truy xuất đối tượng

Tổng quan về đối tượng trong JavaScript

Có một câu nói phổ biến rằng trong JavaScript "mọi thứ đều là đối tượng". Mặc dù điều này không hoàn toàn chính xác về mặt kỹ thuật, nhưng nó phản ánh một thực tế rằng các kiểu dữ liệu nguyên thủy trong JavaScript đều có thể sử dụng các phương thức như đối tượng.

// Ví dụ với kiểu Number
const soThuc = 9.876;
console.log(soThuc.toString());
console.log(soThuc.valueOf());
console.log(soThuc.toFixed(2));
console.log(Number.prototype);

// Ví dụ với kiểu String
const tenMoi = 'LapTrinhWeb';
console.log(tenMoi.length);
console.log(tenMoi.substring(4));
console.log(tenMoi.padEnd(12, '*'));
console.log(String.prototype);

// Ví dụ với kiểu Boolean
const giaTri = false;
console.log(giaTri.toString());
console.log(Boolean.prototype);

Trong JavaScript, các hàm được định nghĩa trên đối tượng được gọi là phương thức (method), sử dụng cú pháp doiTuong.phuongThuc(). Ngoài phương thức, đối tượng còn có thuộc tính (property), sử dụng cú pháp doiTuong.thuocTinh. Điểm khác biệt cơ bản là: phương thức là hàm, còn thuộc tính là giá trị.

const nguoiDung = {
  hoTen: 'Nguyen Van A',
  tuoi: 25,
  chaoHoi() {
    console.log(`Toi la ${this.hoTen}, nam nay ${this.tuoi} tuoi`);
  }
}

Trong JavaScript, có nhiều cách để tạo đối tượng khác nhau, không giống như mảng chỉ có vài cách khai báo.

1. Định nghĩa đối tượng bằng object literal

Đối tượng trong JavaScript có thể chứa bất kỳ giá trị nào: hàm, mảng, đối tượng khác, undefined, null, NaN...

const khoaDong = 'maDong';
const fnKey = () => {};

const doiTuong1 = {
  ten: 'TrangWeb',
  soLuong: 5,
  'mau-sac-uu-thich': 'xanh',
  [Symbol('ma')]: 456,
  [khoaDong]: 'giaTriDong',
  [fnKey]: 'Su dung ham lam ten',
  chao() {
    console.log('Xin chao!');
  },
  noi: function() {
    console.log('Hi!');
  }
};

2. Sử dụng Constructor

Mặc dù ít được sử dụng hơn, constructor Object cũng có thể tạo đối tượng:

const khoaDong = 'maDong';
const fnKey = () => {};

const doiTuong2 = new Object();
doiTuong2.ten = 'TrangWeb';
doiTuong2.soLuong = 5;
doiTuong2['mau-sac-uu-thich'] = 'xanh';
doiTuong2[Symbol('ma')] = 456;
doiTuong2[khoaDong] = 'giaTriDong';
doiTuong2[fnKey] = 'Su dung ham lam ten';
doiTuong2.chao = function() {
  console.log('Xin chao!');
}
doiTuong2.noi = function() {
  console.log('Hi!');
}

3. Sử dụng Object.create()

Phương thức tĩnh Object.create() dùng để tạo đối tượng với prototype cho trước:

const doiTuong3 = Object.create({
  ten: 'TrangWeb',
})
doiTuong3.toString(); // Gọi phương thức từ prototype

Object.create thường được dùng để kế thừa và mở rộng đối tượng:

const doiTuong4 = {
  ten: 'TrangWeb',
}
const doiTuong5 = Object.create(doiTuong4);
doiTuong5.soLuong = 5;
doiTuong5['mau-sac-uu-thich'] = 'xanh';

4. Tự định nghĩa Constructor

Ngoài các constructor có sẵn, có thể tự tạo constructor để định nghĩa đối tượng:

function UngDung() {
  this.ten = 'TrangWeb';
  this.soLuong = 5;
  this['mau-sac-uu-thich'] = 'xanh';
}
const doiTuong6 = new UngDung();

Từ khóa function có thể dùng để tạo constructor - đây là cách phổ biến để tạo class trước khi ES6 ra đời.

5. Sử dụng Class (ES6)

ES6 giới thiệu cú pháp class để định nghĩa đối tượng rõ ràng hơn:

class UngDung {
  constructor() {
    this.ten = 'TrangWeb';
    this.soLuong = 5;
    this['mau-sac-uu-thich'] = 'xanh';
  }
  noi() {
    console.log('Hi!');
  }
}
const doiTuong7 = new UngDung();

Các cách truy xuất giá trị đối tượng

1. Truy xuất bằng dấu chấm (Dot notation)

const doiTuong1 = {
  ten: 'TrangWeb',
  soLuong: 5,
  'mau-sac-uu-thich': 'xanh',
  noi() {
    console.log('Hi!');
  }
}
console.log(doiTuong1.ten);
console.log(doiTuong1.noi());

2. Truy xuất bằng dấu ngoặc vuông (Bracket notation)

Cú pháp dấu chấm có hạn chế với các thuộc tính có ký tự đặc biệt. Ví dụ, doiTuong1.mau-sac-uu-thich sẽ báo lỗi vì dấu "-" bị hiểu là toán tử trừ. Khi đó cần dùng cú pháp mảng:

const doiTuong1 = {
  ten: 'TrangWeb',
  soLuong: 5,
  'mau-sac-uu-thich': 'xanh',
  noi() {
    console.log('Hi!');
  }
}
console.log(doiTuong1['mau-sac-uu-thich']);
console.log(doiTuong1['noi']());

Với dấu ngoặc vuông, có thể dùng biến để truy xuất thuộc tính động:

const khoaDong = 'maDong';

const doiTuong1 = {
  [khoaDong]: 'TrangWeb',
}
console.log(doiTuong1[khoaDong]);

3. Destructuring Assignment

Đây là tính năng mới trong ES6, rất quan trọng trong JavaScript hiện đại:

const doiTuong1 = {
  ten: 'TrangWeb',
  soLuong: 5,
}

const { ten, soLuong, giaTriMacDinh = 'Mac dinh' } = doiTuong1;
console.log(ten, soLuong);
console.log(giaTriMacDinh);

4. Các phương thức tĩnh của Object

Object cung cấp các phương thức tĩnh để lấy keys, values và entries:

const doiTuong1 = {
  ten: 'TrangWeb',
  soLuong: 5,
}
const keys = Object.keys(doiTuong1);
const values = Object.values(doiTuong1);
const entries = Object.entries(doiTuong1);
console.log(keys);
console.log(values);
console.log(entries);

5. Getter và Setter

Sử dụng getset để tạo thuộc tính tính toán, cho phép kiểm soát việc đọc/ghi thuộc tính:

const doiTuong1 = {
  tienTo: 'Website:',
  tenChinh: 'LapTrinh',
  get ten() {
    return `${this.tienTo} ${this.tenChinh}`;
  },
  set ten(giaTri) {
    [this.tienTo, this.tenChinh] = giaTri.split(': ');
  }
}
console.log(doiTuong1.ten);
doiTuong1.ten = 'LapTrinh: Website';
console.log(doiTuong1.ten);

6. Truy xuất prototype chain

Nếu thuộc tính không tồn tại trong đối tượng, JavaScript sẽ tìm kiếm trong prototype chain:

const doiTuong1 = {
  ten: 'TrangWeb',
  soLuong: 5,
}
console.log(doiTuong1.toString());

7. Optional Chaining (ES2020)

Toán tử optional chaining giải quyết vấn đề lỗi khi truy xuất thuộc tính không tồn tại:

const doiTuong1 = {
  ten: 'TrangWeb',
  soLuong: 5,
}
// Truy xuất trực tiếp sẽ gây lỗi TypeError
console.log(doiTuong1.diaChi.thanhPho);
// Sử dụng optional chaining, trả về undefined nếu không tồn tại
console.log(doiTuong1?.diaChi?.thanhPho);

Trên đây là hầu hết các cách định nghĩa và truy xuất đối tượng trong JavaScript được sử dụng phổ biến. Một số phương thức ít dùng hơn như Reflect.get() không được đề cập, nhưng với kiến thức này, bạn đã có thể làm việc với đối tượng một cách thành thạo.

Thẻ: JavaScript objects ECMAScript prototype class

Đăng vào ngày 30 tháng 6 lúc 16:51