Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extending built-in classes #209

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 25 additions & 25 deletions 1-js/09-classes/05-extend-natives/article.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@

# Extending built-in classes
# Mở rộng các class dựng sẵn

Built-in classes like Array, Map and others are extendable also.
Các class dựng sẵn như Array, Map và các class khác cũng có thể mở rộng được.

For instance, here `PowerArray` inherits from the native `Array`:
Chẳng hạn, ở đây `PowerArray` kế thừa từ `Array` gốc:

```js run
// add one more method to it (can do more)
// thêm một phương thức nữa vào nó (có thể làm nhiều hơn)
class PowerArray extends Array {
isEmpty() {
return this.length === 0;
Expand All @@ -21,20 +21,20 @@ alert(filteredArr); // 10, 50
alert(filteredArr.isEmpty()); // false
```

Please note a very interesting thing. Built-in methods like `filter`, `map` and others -- return new objects of exactly the inherited type `PowerArray`. Their internal implementation uses the object's `constructor` property for that.
Hãy lưu ý một điều rất thú vị. Các phương thức tích hợp sẵn như `filter`, `map` và các phương thức khác -- trả về các đối tượng mới thuộc loại chính xác `PowerArray` được kế thừa. Việc triển khai nội bộ của chúng sử dụng thuộc tính `constructor` của đối tượng cho điều đó.

In the example above,
Trong ví dụ trên,
```js
arr.constructor === PowerArray
```

When `arr.filter()` is called, it internally creates the new array of results using exactly `arr.constructor`, not basic `Array`. That's actually very cool, because we can keep using `PowerArray` methods further on the result.
Khi `arr.filter()` được gọi, nó sẽ tạo array kết quả mới bên trong bằng cách sử dụng chính xác `arr.constructor`, chứ không phải `Array` cơ bản. Đ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 `PowerArray` cho kết quả.

Even more, we can customize that behavior.
Hơn nữa, chúng ta có thể tùy chỉnh hành vi đó.

We can add a special static getter `Symbol.species` to the class. If it exists, it should return the constructor that JavaScript will use internally to create new entities in `map`, `filter` and so on.
Chúng ta có thể thêm một getter tĩnh đặc biệt `Symbol.species` vào class. Nếu nó tồn tại, nó sẽ trả về hàm tạo mà JavaScript sẽ sử dụng nội bộ để tạo các thực thể mới trong `map`, `filter`, v.v.

If we'd like built-in methods like `map` or `filter` to return regular arrays, we can return `Array` in `Symbol.species`, like here:
Nếu muốn các phương thức tích hợp sẵn như `map` hoặc `filter` trả về các array thông thường, chúng ta có thể trả về `Array` trong `Symbol.species`, như sau:

```js run
class PowerArray extends Array {
Expand All @@ -43,7 +43,7 @@ class PowerArray extends Array {
}

*!*
// built-in methods will use this as the constructor
// các phương thức tích hợp sẽ sử dụng phương thức này làm hàm tạo
static get [Symbol.species]() {
return Array;
}
Expand All @@ -53,37 +53,37 @@ class PowerArray extends 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
// bộ lọc tạo array mới bằng cách sử dụng arr.constructor[Symbol.species] làm hàm tạo
let filteredArr = arr.filter(item => item >= 10);

*!*
// filteredArr is not PowerArray, but Array
// filterArr không phải là PowerArray, mà là Array
*/!*
alert(filteredArr.isEmpty()); // Error: filteredArr.isEmpty is not a function
```

As you can see, now `.filter` returns `Array`. So the extended functionality is not passed any further.
Như bạn có thể thấy, bây giờ `.filter` trả về `Array`. Vì vậy, hàm mở rộng không được thông qua nữa.

```smart header="Other collections work similarly"
Other collections, such as `Map` and `Set`, work alike. They also use `Symbol.species`.
```smart header="Các bộ sưu tập khác hoạt động tương tự"
Các bộ sưu tập khác, chẳng hạn như `Map` `Set`, hoạt động như nhau. Chúng cũng sử dụng `Symbol.species`.
```

## No static inheritance in built-ins
## Không có kế thừa tĩnh trong tích hợp

Built-in objects have their own static methods, for instance `Object.keys`, `Array.isArray` etc.
Các đối tượng tích hợp sẵn có các phương thức tĩnh của riêng chúng, chẳng hạn như `Object.keys`, `Array.isArray`, v.v.

As we already know, native classes extend each other. For instance, `Array` extends `Object`.
Như chúng ta đã biết, các class bản địa mở rộng lẫn nhau. Chẳng hạn, `Array` mở rộng `Object`.

Normally, when one class extends another, both static and non-static methods are inherited. That was thoroughly explained in the article [](info:static-properties-methods#statics-and-inheritance).
Thông thường, khi một class mở rộng một class khác, cả phương thức tĩnh và không tĩnh đều được kế thừa. Điều đó đã được giải thích cặn kẽ trong bài viết [](info:static-properties-methods#statics-and-inheritance).

But built-in classes are an exception. They don't inherit statics from each other.
Nhưng các class dựng sẵn là một ngoại lệ. Chúng không kế thừa số liệu thống kê từ nhau.

For example, both `Array` and `Date` inherit from `Object`, so their instances have methods from `Object.prototype`. But `Array.[[Prototype]]` does not reference `Object`, so there's no, for instance, `Array.keys()` (or `Date.keys()`) static method.
Ví dụ: cả `Array` `Date` đều kế thừa từ `Object`, vì vậy các phiên bả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`, do đó, chẳng hạn, không có phương thức tĩnh `Array.keys()` (hoặc `Date.keys()`).

Here's the picture structure for `Date` and `Object`:
Đây là cấu trúc hình ảnh cho `Date` `Object`:

![](object-date-inheritance.svg)

As you can see, there's no link between `Date` and `Object`. They are independent, only `Date.prototype` inherits from `Object.prototype`.
Như bạn có thể thấy, không có liên kết nào giữa `Date` `Object`. Chúng độc lập, chỉ có `Date.prototype` kế thừa từ `Object.prototype`

That's an important difference of inheritance between built-in objects compared to what we get with `extends`.
Đó là sự khác biệt quan trọng của tính kế thừa giữa các đối tượng dựng sẵn so với những gì chúng ta nhận được với `extends`.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.