Các lớp tích hợp như Array, Map và các lớp khác cũng có thể mở rộng.

Chẳng hạn, ở đây PowerArraykế thừa từ nguồn gốc Array:

/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact: cafedevn@gmail.com
Fanpage: https://www.facebook.com/cafedevn
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
*/

// add one more method to it (can do more)
class PowerArray extends Array {
  isEmpty() {
    return this.length === 0;
  }
}

let arr = new PowerArray(1, 2, 5, 10, 50);
alert(arr.isEmpty()); // false

let filteredArr = arr.filter(item => item >= 10);
alert(filteredArr); // 10, 50
alert(filteredArr.isEmpty()); // false

Xin lưu ý một điều rất thú vị. Phương thức như filter, mapvà những phương thức khác – trả về đối tượng mới chính là loại di truyền củaPowerArray(có kiểu PowerArray). Việc thực hiện nội bộ của họ sử dụng thuộc tínhconstructor của đối tượng cho điều đó.

Trong ví dụ trên,

arr.constructor === PowerArray

Khi hàmarr.filter()được gọi, bên trong nó tạo ra mảng kết quả mới bằng cách sử dụng chính xác arr.constructor. Điều đó thực sự rất tuyệt, bởi vì chúng ta có thể tiếp tục sử dụng các phương thức của PowerArray hơn nữa về kết quả.

Thậm chí nhiều hơn, chúng ta có thể tùy chỉnh hành vi đó.

Chúng ta có thể thêm một getter tĩnh đặc biệt Symbol.speciescho lớp. Nếu nó tồn tại, nó sẽ trả về hàm tạo mà JavaScript sẽ sử dụng bên trong để tạo các thực thể mới map, filterv.v.

Nếu chúng ta muốn xây dựng trong các phương thức như maphoặc filtertrở về mảng thông thường, chúng ta có thể trở lại Arraytrong Symbol.species, giống như ở đây:

class PowerArray extends Array {
  isEmpty() {
    return this.length === 0;
  }

  // built-in methods will use this as the constructor
  static get [Symbol.species]() {
    return Array;
  }
}

let arr = new PowerArray(1, 2, 5, 10, 50);
alert(arr.isEmpty()); // false

// filter creates new array using arr.constructor[Symbol.species] as constructor
let filteredArr = arr.filter(item => item >= 10);

// filteredArr is not PowerArray, but Array
alert(filteredArr.isEmpty()); // Error: filteredArr.isEmpty is not a function

Như bạn có thể thấy, bây giờ .filtertrả  lại Array. Vì vậy, hàm mở rộng không được thông qua nữa.

Các bộ sưu tập khác hoạt động tương tự

Các bộ sưu tập khác, như MapSet, hoạt động như nhau. Họ cũng sử dụng Symbol.species.

1. Không có kế thừa tĩnh trong đối tượng tích hợp

Các đối tượng tích hợp sẵn có các phương thức tĩnh riêng Object.keys, Array.isArrayv.v.

Như chúng ta đã biết, các lớp bản địa mở rộng lẫn nhau. Ví dụ, Arraymở rộng Object.

Thông thường, khi một lớp mở rộng lớp khác, cả hai phương thức tĩnh và không tĩnh đều được kế thừa. Điều đó đã được giải thích kỹ lưỡng trong bài viết Thuộc tính và phương pháp tĩnh.

Nhưng các lớp tích hợp là một ngoại lệ. Họ không kế thừa thống kê lẫn nhau.

Ví dụ, cả hai ArrayDatekế thừa từ Object, vì vậy các thể hiện của chúng có các phương thức từ Object.prototype. Nhưng Array.[[Prototype]]không tham chiếu Object, vì vậy, không có kế thừa được, ví dụ, phương thức tĩnhArray.keys()(hoặc Date.keys()) .

Đây là cấu trúc hình ảnh cho DateObject:

Như bạn có thể thấy, không có liên kết giữa DateObject. Họ là độc lập, chỉ Date.prototypethừa kế từ Object.prototype.

Đó là một sự khác biệt quan trọng của sự kế thừa giữa các đối tượng tích hợp so với những gì chúng ta có được extends.

Full series tự học Javascript từ cơ bản tới nâng cao tại đây nha.

Nếu bạn thấy hay và hữu ích, bạn có thể tham gia các kênh sau của cafedev để nhận được nhiều hơn nữa:

Chào thân ái và quyết thắng!

Đăng ký kênh youtube để ủng hộ Cafedev nha các bạn, Thanks you!