Javascript classes

Javascript classes được giới thiệu trong ECMAScript 2015 (ES6). Các lớp JavaScript cung cấp một cú pháp đơn giản hơn và rõ ràng hơn để tạo các đối tượng và làm việc với sự thừa kế.

Định nghĩa class

Các class thực chất là "các hàm đặc biệt", và cũng giống như bạn có thể định nghĩa hàm và khai báo hàm, cú pháp class cũng có định nghĩa biểu thức lớp (class expressions) và khai báo lớp (class declarations).

Class declarations

Sử dụng từ khóa class để định nghĩa một class mới

class HinhChuNhat {
    constructor(chieuDai, chieuRong) {
        this.chieuDai = chieuDai;
        this.chieuRong = chieuRong;
  }
}

Class expressions

Một cách khác để định nghĩa class là sử dụng biểu thức. Biểu thức lớp có thể được đăt tên hoặc không.

// không đặt tên
let HinhChuNhat = class {
  constructor(chieuDai, chieuRong) {
    this.chieuDai = chieuDai;
    this.chieuRong = chieuRong;
  }
};

// đặt tên
let HinhChuNhat = class HinhChuNhat {
  constructor(chieuDai, chieuRong) {
    this.chieuDai = chieuDai;
    this.chieuRong = chieuRong;
  }
};

Định nghĩa thân Class và các method

Thân class được đặt trong cặp dấu ngoặc nhọn {}

Constructor

Method constructor là phương thức đặc biệt để tạo và khởi tạo một đối tượng được tạo ra bởi một lớp. Chỉ có thể có một phương thức constructor trong một lớp, nhiều hơn sẽ gây ra lỗi. Trong method constructor có thể sử dụng từ khóa super để gọi constructor của lớp cha.

Prototype methods

Định nghĩa các phuong thức bên trong class

class HinhChuNhat {
  constructor(chieuDai, chieuRong) {
    this.chieuDai = chieuDai;
    this.chieuRong = chieuRong;
  }
  // Getter
  get dienTich() {
    return this.tinhDienTich();
  }
  // Method
  tinhDienTich() {
    return this.chieuDai * this.chieuRong;
  }
}

const hinhVuong = new HinhChuNhat(10, 10);

console.log(hinhVuong.dienTich); // 100

Static methods

Các phương thức static chỉ có thể được gọi "tĩnh", không thể gọi thông qua một instance của class.

class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

  static distance(a, b) {
    const dx = a.x - b.x;
    const dy = a.y - b.y;

    return Math.hypot(dx, dy);
  }
}

const p1 = new Point(5, 5);
const p2 = new Point(10, 10);

console.log(Point.distance(p1, p2)); // 7.0710678118654755
console.log(p1.distance()); // TypeError: p1.distance is not a function

Boxing with prototype and static methods

Khi prototype methods hoặc static methods được gọi trong bối cảnh không có giá trị this thì từ khóa this sẽ trả về undefined bên trong function được gọi. Trừu tượng quá nhỉ, xem ví dụ thôi nào:

class Animal { 
  speak() {
    return this;
  }
  static eat() {
    return this;
  }
}

let obj = new Animal();
obj.speak(); // Animal {}
let speak = obj.speak;
speak(); // undefined

Animal.eat() // class Animal
let eat = Animal.eat;
eat(); // undefined

Viết lại theo cách khác xem kết quả thế nào nhé, ví dụ dưới đây có xảy ra autoboxing

function Animal() { }

Animal.prototype.speak = function() {
  return this;
}

Animal.eat = function() {
  return this;
}

let obj = new Animal();
let speak = obj.speak;
speak(); // global object

let eat = Animal.eat;
eat(); // global object

Kế thừa với từ khóa extends

CŨng giống như nhiều ngôn ngữ lập trình khác, chúng ta có thể tạo ra một class mới kế thừa từ class cha bằng từ khóa extends

class Animal { 
  constructor(name) {
    this.name = name;
  }
  
  speak() {
    console.log(this.name + ' gây ra tiếng ồn.');
  }
}

class Dog extends Animal {
  speak() {
    console.log(this.name + ' sủa gâu gâu.');
  }
}

var d = new Dog('Mitzie');
d.speak(); // Mitzie sủa gâu gâu.

Nếu có method constructor trong lớp con thì nó phải gọi super trước khi sử dụng được từ khóa this Chú ý rằng một class không thể kế thừa từ một object bình thường. Nếu muốn làm điều này, thì bạn có thể dùng Object.setPrototypeOf():

var Animal = {
  speak() {
    console.log(this.name + ' gây ra tiếng ồn.');
  }
};

class Dog {
  constructor(name) {
    this.name = name;
  }
}

Object.setPrototypeOf(Dog.prototype, Animal);// If you do not do this you will get a TypeError when you invoke speak

var d = new Dog('Mitzie');
d.speak(); // Mitzie gây ra tiếng ồn.

Gọi method trong class cha với từ khóa super

class Cat { 
  constructor(name) {
    this.name = name;
  }
  
  speak() {
    console.log(this.name + ' gây ra tiếng ồn.');
  }
}

class Lion extends Cat {
  speak() {
    super.speak();
    console.log(this.name + gầm...');
  }
}

var l = new Lion('Fuzzy');
l.speak(); 
// Fuzzy gây ra tiếng ồn.
// Fuzzy gầm...