You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The first kind is *data properties*. We already know how to work with them. All properties that we've been using till now were data properties.
6
+
Đầu tiên là *thuộc tính dữ liệu* (data properties). Chúng ta đã biết và làm việc với chúng. Tất cả các thuộc tính chúng ta đã sử dụng cho đến giờ đều là các thuộc tính dữ liệu.
7
7
8
-
The second type of properties is something new. It's *accessor properties*. They are essentially functions that work on getting and setting a value, but look like regular properties to an external code.
8
+
Loại thứ hai sẽ được học trong bài này gọi là các *thuộc tính truy cập* (accessor properties). Về cơ bản chúng là các hàm có tác dụng lấy và cài đặt một giá trị - (tức là các phương thức), nhưng cách sử dụng giống một thuộc tính bình thường.
9
9
10
-
## Getters and setters
10
+
## Getter và Setter
11
11
12
-
Accessor properties are represented by "getter" and "setter" methods. In an object literal they are denoted by `get`and`set`:
12
+
Các thuộc tính truy cập được biểu diễn bằng hai phương thức gọi là "getter" và "setter". Trong literal đối tượng chúng được nhận biết bởi hai từ khóa `get`và`set`:
13
13
14
14
```js
15
15
let obj = {
16
16
*!*get propName()*/!* {
17
-
// getter, the code executed on getting obj.propName
17
+
// getter, phương thức này chạy khi truy cập "obj.propName"
18
18
},
19
19
20
20
*!*set propName(value)*/!* {
21
-
// setter, the code executed on setting obj.propName = value
21
+
// setter, phương thức này chạy khi gán "obj.propName = value"
22
22
}
23
23
};
24
24
```
25
25
26
-
The getter works when `obj.propName` is read, the setter -- when it is assigned.
26
+
Phương thức getter chạy khi truy cập `obj.propName`, setter chạy khi gán một giá trị cho nó.
27
27
28
-
For instance, we have a `user`object with `name`and`surname`:
28
+
Ví dụ, ta có đối tượng `user`với thuộc tính `name`và`surname`:
29
29
30
30
```js run
31
31
let user = {
32
-
name:"John",
33
-
surname:"Smith"
32
+
name:"Hùng",
33
+
surname:"Phùng"
34
34
};
35
35
```
36
36
37
-
Now we want to add a "fullName" property, that should be "John Smith". Of course, we don't want to copy-paste existing information, so we can implement it as an accessor:
37
+
Giờ ta muốn thêm thuộc tính `fullName` có giá trị là `"Phùng Hùng"`. Tất nhiên, chúng ta không sao chép thủ công các thông tin hiện có làm giá trị của `fullName`. Chúng ta có thể thực hiện việc này bằng một getter:
38
38
39
39
```js run
40
40
let user = {
41
-
name:"John",
42
-
surname:"Smith",
41
+
name:"Hùng",
42
+
surname:"Phùng",
43
43
44
44
*!*
45
45
getfullName() {
46
-
return`${this.name}${this.surname}`;
46
+
return`${this.surname}${this.name}`;
47
47
}
48
48
*/!*
49
49
};
50
50
51
51
*!*
52
-
alert(user.fullName); //John Smith
52
+
alert(user.fullName); //Phùng Hùng
53
53
*/!*
54
54
```
55
55
56
-
From outside, an accessor property looks like a regular one. That's the idea of accessor properties. We don't *call*`user.fullName`as a function, we *read* it normally: the getter runs behind the scenes.
56
+
Từ bên ngoài, các thuộc tính truy cập trông như thuộc tính dữ liệu. Nó cũng là ý tưởng cho sự xuất hiện của các thuộc tính truy cập. Chúng ta không gọi `user.fullName`như gọi phương thức, mà gọi giống như *đọc* một thuộc tính bình thường: getter sẽ tự động chạy "phía sau hậu trường".
57
57
58
-
As of now, `fullName`has only a getter. If we attempt to assign `user.fullName=`, there will be an error.
58
+
Đến giờ, `fullName`mới chỉ có getter. Nếu chúng ta muốn thay đổi giá trị của nó bằng cách gán `user.fullName=` thì sẽ có lỗi:
59
59
60
-
Let's fix it by adding a setter for`user.fullName`:
60
+
Để có thể gán giá trị cho một thuộc tính truy cập, cần tạo setter cho nó. Cùng thêm một setter cho`user.fullName`:
61
61
62
62
```js run
63
63
let user = {
64
-
name:"John",
65
-
surname:"Smith",
64
+
name:"Hùng",
65
+
surname:"Phùng",
66
66
67
67
getfullName() {
68
-
return`${this.name}${this.surname}`;
68
+
return`${this.surname}${this.name}`;
69
69
},
70
70
71
71
*!*
72
72
setfullName(value) {
73
-
[this.name, this.surname] =value.split("");
73
+
[this.surname, this.name] =value.split("");
74
74
}
75
75
*/!*
76
76
};
77
77
78
-
//set fullName is executed with the given value.
79
-
user.fullName="Alice Cooper";
78
+
//Khi gán setter được chạy, đối số value lấy từ vế phải của =
79
+
user.fullName="Phùng Ngọc";
80
80
81
-
alert(user.name); //Alice
82
-
alert(user.surname); //Cooper
81
+
alert(user.name); //Ngọc
82
+
alert(user.surname); //Phùng
83
83
```
84
84
85
-
As the result, we have a "virtual" property `fullName`. It is readable and writable, but in fact does not exist.
85
+
Kết quả là chúng ta có một thuộc tính "ảo" `fullName`. Ta có thể đọc và ghi nó, nhưng thực tế nó không tồn tại trong đối tượng.
86
86
87
-
```smart header="Accessor properties are only accessible with get/set"
88
-
Once a property is defined with `get prop()` or `set prop()`, it's an accessor property, not a data property any more.
87
+
```smart header="Các thuộc tính truy cập chỉ có thể truy cập nhờ getter và setter"
88
+
Khi một thuộc tính đã được định nghĩa với `get prop()` hoặc `set prop()`, nó trở thành một thuộc tính truy cập, không phải là thuộc tính dữ liệu nữa.
89
89
90
-
- If there's a getter -- we can read `object.prop`, otherwise we can't.
91
-
- If there's a setter -- we can set `object.prop=...`, otherwise we can't.
90
+
- Chúng ta chỉ có thể đọc thuộc tính truy cập `object.prop` nếu có getter cho nó.
91
+
- Chúng ta chỉ có thể ghi thuộc tính truy cập `object.prop=...` nếu có setter cho nó.
92
92
93
-
And in either case we can't `delete` an accessor property.
93
+
Và trong cả hai trường hợp, ta không thể xóa một thuộc tính truy cập.
94
94
```
95
95
96
96
97
-
## Accessor descriptors
97
+
## Descriptor của thuộc tính truy cập
98
98
99
-
Descriptors for accessor properties are different -- as compared with data properties.
99
+
Các descriptor của thuộc trính truy cập khác với descriptor của thuộc tính dữ liệu mà ta đã học.
100
100
101
-
For accessor properties, there is no `value`and`writable`, but instead there are `get`and`set` functions.
101
+
Nó không có `value`và`writable`, mà thay bằng hai hàm `get`và`set`.
102
102
103
-
So an accessor descriptor may have:
103
+
Cụ thể descriptor của thuộc tính truy cập có:
104
104
105
-
-**`get`** -- a function without arguments, that works when a property is read,
106
-
-**`set`** -- a function with one argument, that is called when the property is set,
107
-
-**`enumerable`** -- same as for data properties,
108
-
-**`configurable`** -- same as for data properties.
105
+
-**`get`** -- hàm không có tham số, chạy khi đọc thuộc tính,
106
+
-**`set`** -- hàm có một tham số, chạy khi ghi thuộc tính,
107
+
-**`enumerable`** -- giống thuộc tính dữ liệu,
108
+
-**`configurable`** -- giống thuộc tính dữ liệu.
109
109
110
-
For instance, to create an accessor `fullName`with`defineProperty`, we can pass a descriptor with `get`and`set`:
110
+
Ví dụ, để tạo thuộc tính truy cập `fullName`bằng`defineProperty`, chúng ta có thể truyền một descriptor có hai phương thức `get`và`set`:
111
111
112
112
```js run
113
113
let user = {
114
-
name:"John",
115
-
surname:"Smith"
114
+
name:"Hùng",
115
+
surname:"Phùng"
116
116
};
117
117
118
118
*!*
119
119
Object.defineProperty(user, 'fullName', {
120
120
get() {
121
-
return`${this.name}${this.surname}`;
121
+
return`${this.surname}${this.name}`;
122
122
},
123
123
124
124
set(value) {
125
-
[this.name, this.surname] =value.split("");
125
+
[this.surname, this.name] =value.split("");
126
126
}
127
127
*/!*
128
128
});
129
129
130
-
alert(user.fullName); //John Smith
130
+
alert(user.fullName); //Phùng Hùng
131
131
132
132
for(let key in user) alert(key); // name, surname
133
133
```
134
134
135
-
Please note once again that a property can be either an accessor or a data property, not both.
135
+
Vui lòng chú ý một lần nữa, một thuộc tính chỉ có thể là thuộc tính truy cập hoặc thuộc tính dữ liệu, không thể là cả hai cùng lúc.
136
136
137
-
If we try to supply both `get`and`value`in the same descriptor, there will be an error:
137
+
Nếu đưa cả `get`và`value`trong một descriptor, sẽ gây ra lỗi:
Getters/setters can be used as wrappers over "real" property values to gain more control over them.
154
+
Getters/setters có thể dùng như một thuộc tính "bao" lấy thuộc tính thực thực, để kiểm soát giá trị được đưa vào.
155
155
156
-
For instance, if we want to forbid too short names for `user`, we can store `name`in a special property `_name`. And filter assignments in the setter:
156
+
Ví dụ, nếu chúng ta muốn chặn một tên quá ngắn cho `user`, chúng ta có thể tạo một thuộc tính truy cập `name`lưu trong thuộc tính thực `_name` và thêm bước kiểm tra vào trong setter:
157
157
158
158
```js run
159
159
let user = {
@@ -163,63 +163,63 @@ let user = {
163
163
164
164
setname(value) {
165
165
if (value.length<4) {
166
-
alert("Name is too short, need at least 4 characters");
166
+
alert("Tên quá ngắn, cần nhiều hơn 4 ký tự");
167
167
return;
168
168
}
169
169
this._name= value;
170
170
}
171
171
};
172
172
173
-
user.name="Pete";
174
-
alert(user.name); //Pete
173
+
user.name="Hùng";
174
+
alert(user.name); //Hùng
175
175
176
-
user.name=""; //Name is too short...
176
+
user.name=""; //Tên quá ngắn, cần nhiều hơn 4 ký tự
177
177
```
178
178
179
-
Technically, the external code may still access the name directly by using `user._name`. But there is a widely known agreement that properties starting with an underscore `"_"`are internal and should not be touched from outside the object.
179
+
Vễ mặt kỹ thuật, mã bên ngoài vẫn có thể truy cập và thay đổi trực tiếp thuộc tính `user._name`. Nhưng có một thỏa thuận được chấp nhận rộng rãi rằng các thuộc tính có tên bắt đầu bằng `"_"`được coi là thuộc tính riêng của đối tượng và không nên truy cập hay thay đổi trực tiếp từ bên ngoài.
180
180
181
181
182
-
## Using for compatibility
182
+
## Cung cấp sự tương thích
183
183
184
-
One of the great ideas behind getters and setters -- they allow to take control over a "regular" data property at any moment by replacing it with getter and setter and tweak its behavior.
184
+
Các getter và setter cho phép ta thay thế một thuộc tính dữ liệu thông thường bằng phiên bản khác sử dụng thuộc tính truy cập với khả năng kiểm soát tốt hơn.
185
185
186
-
Let's say we started implementing user objects using data properties `name`and`age`:
186
+
Giả sử chúng ta tạo đối tượng người dùng có hai thuộc tính `name`và`age`:
187
187
188
188
```js
189
189
functionUser(name, age) {
190
190
this.name= name;
191
191
this.age= age;
192
192
}
193
193
194
-
letjohn=newUser("John", 25);
194
+
lethung=newUser("Hùng", 33);
195
195
196
-
alert( john.age ); //25
196
+
alert( hung.age ); //33
197
197
```
198
198
199
-
...But sooner or later, things may change. Instead of `age`we may decide to store`birthday`, because it's more precise and convenient:
199
+
...Nhưng ngay sau đó, thay vì `age`ta quyết định sử dụng`birthday`, bởi nó chính xác và thuận tiện hơn:
200
200
201
201
```js
202
202
functionUser(name, birthday) {
203
203
this.name= name;
204
204
this.birthday= birthday;
205
205
}
206
206
207
-
letjohn=newUser("John", newDate(1992, 6, 1));
207
+
lethung=newUser("Hùng", newDate(1986, 8, 3));
208
208
```
209
209
210
-
Now what to do with the old code that still uses `age` property?
210
+
Giờ ta phải làm gì với những mã cũ vẫn còn sử dụng thuộc tính `age`?
211
211
212
-
We can try to find all such places and fix them, but that takes time and can be hard to do if that code is written/used by many other people. And besides, `age`is a nice thing to have in `user`, right? In some places it's just what we want.
212
+
Chúng ta có thể tìm và sửa lại, nhưng nó tốn rất nhiều thời gian và rất khó nếu mã được viết bởi những người khác. Hơn nữa sự có mặt của thuộc tính `age`trong đối tượng người dùng vẫn hợp lý và ta chỉ muốn thay đổi ở một số chỗ mà thôi.
213
213
214
-
Adding a getter for `age`solves the problem:
214
+
Thêm thuộc tính truy cập cho `age`sẽ giải quyết được vấn đề này:
215
215
216
216
```js run no-beautify
217
217
functionUser(name, birthday) {
218
218
this.name= name;
219
219
this.birthday= birthday;
220
220
221
221
*!*
222
-
// age is calculated from the current date and birthday
222
+
// age có thể tính được từ birthday
223
223
Object.defineProperty(this, "age", {
224
224
get() {
225
225
let todayYear =newDate().getFullYear();
@@ -229,10 +229,10 @@ function User(name, birthday) {
229
229
*/!*
230
230
}
231
231
232
-
letjohn=newUser("John", newDate(1992, 6, 1));
232
+
lethung=newUser("Hùng", newDate(1986, 8, 3));
233
233
234
-
alert( john.birthday ); // birthday is available
235
-
alert( john.age ); // ...as well as the age
234
+
alert( john.birthday ); // birthday vẫn truy cập được
235
+
alert( john.age ); // ...và age cũng vậy
236
236
```
237
237
238
-
Now the old code works too and we've got a nice additional property.
238
+
Và giờ các đoạn mã cũ sử dụng `age` vẫn làm việc tốt.
0 commit comments