1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
|
---
title: this
slug: Web/JavaScript/Reference/Operators/this
translation_of: Web/JavaScript/Reference/Operators/this
---
<div>{{jsSidebar("Operators")}}</div>
<p>Từ khoá<strong> <code>this</code> </strong>của hàm trong JavaScript hơi khác so với các ngôn ngữ khác. Nó cũng có một vài điểm khác nhau giữa 2 chế độ <a href="/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/Strict_mode">strict mode</a> và non-strict mode.</p>
<p>Trong hầu hết các trường hợp, giá trị của <code>this</code> được xác định bởi cách gọi hàm (runtime binding). Nó không thể được thiết lập bằng cách gán trong khi thực thi, và nó có thể khác nhau mỗi lần hàm được gọi. ES5 giới thiệu phương thức {{jsxref("Function.prototype.bind()", "bind()")}} để <a href="#">thiết lập giá trị của <code>this</code> bất kể hàm được gọi thế nào</a>, và ES2015 giới thiệu <a href="../Functions/Arrow_functions">arrow functions</a> mà không cung cấp ràng buộc với <code>this</code> của chúng (Nó sẽ giữ giá trị <code>this</code> của lexical context kèm theo).</p>
<div>{{EmbedInteractiveExample("pages/js/expressions-this.html")}}</div>
<h2 id="Cú_pháp">Cú pháp</h2>
<pre class="syntaxbox">this</pre>
<h3 id="Giá_trị">Giá trị</h3>
<p>Một thuộc tính của bối cảnh thực thi (global, function or eval), trong non–strict mode, luôn luôn tham chiếu tới một đối tượng và trong strict mode có thể là bất kỳ giá trị nào.</p>
<h2 id="Global_context">Global context</h2>
<p>Trong global context (bên ngoài các hàm), <code>this</code> tham chiếu tới global object cho dù trong strict mode hoặc không.</p>
<pre class="brush:js">// Trong trình duyệt, đối tượng window ?là global object:
console.log(this === window); // true
a = 37;
console.log(window.a); // 37
this.b = "MDN";
console.log(window.b) // "MDN"
console.log(b) // "MDN"
</pre>
<div class="blockIndicator note">
<p><strong>Note:</strong> Bạn có thể dễ dàng lấy được global object bằng cách sử dụng thuộc tính toàn cầu {{jsxref("globalThis")}}, bất kể bối cảnh hiện tại mà mã của bạn đang chạy.</p>
</div>
<h2 id="Function_context">Function context</h2>
<p>Bên trong một hàm, giá trị của <code>this</code> phụ thuộc vào cách gọi hàm.</p>
<h3 id="Simple_call">Simple call</h3>
<p>Vì đoạn mã sau không ở chế độ <a href="/en-US/docs/Web/JavaScript/Reference/Strict_mode">strict mode</a>, và vì giá trị của <code>this</code> không được thiết lập khi gọi, <code>this</code> mặc định là global objecct, đó là <a href="/en-US/docs/Web/API/Window" title="The Window interface represents a window containing a DOM document; the document property points to the DOM document loaded in that window."><code>window</code></a> trong trình duyệt. </p>
<pre class="brush:js">function f1() {
return this;
}
// In a browser:
f1() === window; // true
// In Node:
f1() === global; // true</pre>
<p>Tuy nhiên, trong chế độ strict mode, nếu giá trị của <code>this</code> không được thiết lập khi vào bối cảnh thực thi, nó sẽ giữ giá trị <code>undefined</code>, như ví dụ sau<strong>:</strong></p>
<pre class="brush:js">function f2() {
'use strict'; // see strict mode
return this;
}
f2() === undefined; // true
</pre>
<div class="note"> Trong ví dụ thứ 2, <code>this</code> nên là {{jsxref("undefined")}}, bởi vì <code>f2</code> được gọi 1 cách trực tiếp và không phải là một phương thức hoặc thuộc tính của một đối tượng(ví dụ <code>window.f2()</code>). ?Tính năng này sẽ không được triển khai trong một số trình duyệt khi chúng lần đầu hỗ trợ chế độ <a href="/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/Strict_mode" title="Strict mode">strict mode</a>. Như kết quả trên, chúng không trả về đối tượng <code>window</code>.</div>
<p>Để thiết lập giá trị cụ thể của <code>this</code> khi gọi hàm, sử dụng {{jsxref("Function.prototype.call()", "call()")}}, hoặc {{jsxref("Function.prototype.apply()", "apply()")}} như các ví dụ dưới đây<strong>.</strong></p>
<p><strong>Example 1</strong></p>
<pre class="brush:js" dir="rtl">// Một đối tượng có thể truyền vào như là tham số đầu tiên của call hoặc apply và this sẽ được ràng buộc với nó..
var obj = {a: 'Custom'};
// Thuộc tính này được thiết lập trên global object
var a = 'Global';
function whatsThis() {
return this.a; // Giá trị của this phụ thuộc vào cách hàm được gọi.
}
whatsThis(); // 'Global'
whatsThis.call(obj); // 'Custom'
whatsThis.apply(obj); // 'Custom'
</pre>
<p><strong>Example 2</strong></p>
<pre class="brush:js">function add(c, d) {
return this.a + this.b + c + d;
}
var o = {a: 1, b: 3};
// Tham số đầu tiên là đối tượng sử dụng như là
// 'this', tham số tiếp theo được truyền vào là
// đối số trong hàm gọi
add.call(o, 5, 7); // 16
// Tham số đầu tiên là đối tượng sử dụng như là
// 'this', tham số thứ 2 là 1 mảng
// các phần tử được sử dụng làm đối số trong lệnh gọi hàm
add.apply(o, [10, 20]); // 34
</pre>
<p> Chú ý trong chế độ non–strict mode, với <code>call</code> và <code>apply</code>, nếu giá trị được truyền vào <code>this</code> không phải là đối tượng, một nỗ lực sẽ được thực hiện để chuyển đổi nó thành đối tượng bằng cách sử dụng <code>ToObject</code>. Vì thế nếu bạn truyền vào giá trị primitive như <code>7</code> hoặc <code>'foo'</code>, nó sẽ được chuyển đổi thành Object bằng cách sử dụng các constructor liên quan, do đó <code>7</code> sẽ được chuyển đổi thành đối tượng như tạo bằng <code>new Number(7)</code> và string <code>'foo'</code> cũng được chuyển đổi thành đối tượng như tạo bằng <code>new String('foo')</code>, ví dụ:</p>
<pre class="brush:js">function bar() {
console.log(Object.prototype.toString.call(this));
}
bar.call(7); // [object Number]
bar.call('foo'); // [object String]
</pre>
<h3 id="The_bind_method">The <code>bind</code> method</h3>
<p>ECMAScript 5 giới thiệu {{jsxref("Function.prototype.bind()")}}. Gọi <code>f.bind(someObject)</code> tạo ra một hàm mới với cùng thân hàm và phạm vi như hàm <code>f</code>, nhưng <code>this</code> chỉ xảy ra trong hàm ban đầu, trong những hàm mới nó bị ràng buộc vĩnh viễn với đối số đầu tiên của <code>bind</code>, bất kể các hàm được sử dụng thế nào..</p>
<pre class="brush:js">function f() {
return this.a;
}
var g = f.bind({a: 'azerty'});
console.log(g()); // azerty
var h = g.bind({a: 'yoo'}); // bind only works once!
console.log(h()); // azerty
var o = {a: 37, f: f, g: g, h: h};
console.log(o.a, o.f(), o.g(), o.h()); // 37,37, azerty, azerty
</pre>
<h3 id="Arrow_functions">Arrow functions</h3>
<p>Trong <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions">arrow functions</a>, <code>this</code> giữ giá trị ?<code>this</code> của lexical context kèm theo. Trong đoạn mã toàn cục, nó sẽ được thiết lập là global object.</p>
<pre class="brush: js">var globalObject = this;
var foo = (() => this);
console.log(foo() === globalObject); // true</pre>
<div class="note">
<p> Lưu ý: nếu đối số this được truyền vào call, bind, hoặc apply ?trong việc gọi một arrow function nó sẽ bị bỏ qua. Bạn vẫn có thể thêm các đối số cho việc gọi hàm nhưng đối số đầu tiên (thisArg) nên được đặt thành null.</p>
</div>
<pre class="brush: js">// Call as a method of an object
var obj = {func: foo};
console.log(obj.func() === globalObject); // true
// Attempt to set this using call
console.log(foo.call(obj) === globalObject); // true
// Attempt to set this using bind
foo = foo.bind(obj);
console.log(foo() === globalObject); // true</pre>
<p>Không có vấn đề gì ở đây, <code>this</code> của <code>foo</code> vẫn giữ nguyên giá trị khi nó được tạo (trong ví dụ trên, nó là global object). Điều tương tự cũng được áp dụng cho những arrow function được tạo bên trong hàm khác: <code>this</code> của chúng giữ giá trị <code>this</code> của lexical context kèm theo.</p>
<pre class="brush: js">// Tạo 1 đối tượng với phương thức bar trả về 1 hàm, hàm này sẽ
// trả về this của nó. Hàm trả về là arrow function,
// vì thế this của nó được ràng buộc vĩnh viễn với this của hàm kèm theo.
// Giá trị của bar có thể được thiết lập trong khi gọi hàm,
// lần lượt đặt giá của hàm trả về.
var obj = {
bar: function() {
var x = (() => this);
return x;
}
};
// Gọi phương thức bar của obj, thiết lập this là obj.
// Gán một tham chiếu tới hàm trả về là fn
var fn = obj.bar();
// Gọi hàm fn mà không thiết lập 'this',
// thông thường sẽ mặc định cho global object hoặc undefined trong strict mode
console.log(fn() === obj); // true
// Nhưng hãy cẩn thận nếu bạn tham chiếu phương thức của đối tượng mà không gọi nó
var fn2 = obj.bar;
// Gọi hàm arrow function bên trong phương thức bar()
// nó sẽ trả về window, bởi vì nó theo 'this' từ fn2.
console.log(fn2()() == window); // true
</pre>
<p>Trong ví dụ trên, hàm (gọi nó là hàm ẩn danh A) gán cho <code>obj.bar</code> trả về một hàm khác (gọi là hàm ẩn danh B) mà nó là một arrow function. Kết quả là, <code>this</code> của hàm B được thiết lập vĩnh viễn là <code>this</code> của <code>obj.bar</code> (hàm A) khi được gọi. Khi hàm trả về (hàm B) được gọi, <code>this</code> của nó sẽ luôn là những gì được thiết lập ban đầu. Trong đoạn mã trên, <code>this</code> của hàm B được thiết lập theo <code>this</code> của hàm A đó là <code>obj</code>, vì thế nó vẫn được thiết lập là <code>obj</code> ngay cả khi được gọi theo cách thông thường thiết lập <code>this</code> thành <code>undefined</code> hoặc global object (hoặc bất kỳ phương thức nào khác như trong ví dụ trên được thực thi trong bối cảnh toàn cầu).</p>
<h3 id="As_an_object_method">As an object method</h3>
<p>Khi một hàm được gọi như là một phương thức của đối tượng,<code>this</code> được đặt thành đối tượng mà có phương thức được gọi trên.</p>
<p>Trong ví dụ dưới đây, khi <code>o.f()</code> được gọi, <code>this</code> bên trong hàm sẽ liên kết với đối tượng <code>o</code>.</p>
<pre class="brush:js">var o = {
prop: 37,
f: function() {
return this.prop;
}
};
console.log(o.f()); // 37
</pre>
<p>Lưu ý hành vi này hoàn toàn không bị ảnh hưởng bởi cách thức hoặc nơi chức năng được khai báo. Trong ví dụ ở trên, chúng ta khai báo hàm <code>f</code> bên trong đối tượng <code>o</code>. Tuy nhiên, chúng ta có thể dễ dàng khai báo hàm trước và đính kèm nó vào <code>o.f</code>. Làm như vậy sẽ có kết quả tương tự:</p>
<pre class="brush:js">var o = {prop: 37};
function independent() {
return this.prop;
}
o.f = independent;
console.log(o.f()); // 37
</pre>
<p>Điều này chứng tỏ rằng vấn đề chỉ là việc gọi hàm <code>f</code> của <code>o</code>.</p>
<p>Tương tự, ràng buộc với <code>this</code> chỉ bị ảnh hưởng bởi tham chiếu trực tiếp nhất. Trong ví dụ dưới, khi chúng ta gọi hàm, chúng ta gọi nó như là một phương thức <code>g</code> của đối tượng <code>o.b</code>. Khi thực thi, <code>this</code> bên trong hàm sẽ tham chiếu tới <code>o.b</code>. Thực tế đối tượng này là một thành viên của <code>o</code> không ảnh hưởng; tham chiếu trực tiếp nhất mới là quan trọng nhất.</p>
<pre class="brush:js">var o = {prop: 37};
function independent() { return this.prop; }
o.f = independent;
console.log(o.f()); // 37 bởi vì tham chiếu trực tiếp nhất là o
o.b = {g: independent, prop: 42};
console.log(o.b.g()); // 42 bởi vì tham chiếu trực tiếp nhất là o.b
</pre>
<h4 id="this_on_the_objects_prototype_chain"><code>this</code> on the object's prototype chain</h4>
<p>The same notion holds true for methods defined somewhere on the object's prototype chain. If the method is on an object's prototype chain, <code>this</code> refers to the object the method was called on, as if the method were on the object.</p>
<pre class="brush:js">var o = {f: function() { return this.a + this.b; }};
var p = Object.create(o);
p.a = 1;
p.b = 4;
console.log(p.f()); // 5
</pre>
<p>In this example, the object assigned to the variable <code>p</code> doesn't have its own <code>f</code> property, it inherits it from its prototype. But it doesn't matter that the lookup for <code>f</code> eventually finds a member with that name on <code>o</code>; the lookup began as a reference to <code>p.f</code>, so <code>this</code> inside the function takes the value of the object referred to as <code>p</code>. That is, since <code>f</code> is called as a method of <code>p</code>, its <code>this</code> refers to <code>p</code>. This is an interesting feature of JavaScript's prototype inheritance.</p>
<h4 id="this_with_a_getter_or_setter"><code>this</code> with a getter or setter</h4>
<p>Again, the same notion holds true when a function is invoked from a getter or a setter. A function used as getter or setter has its <code>this</code> bound to the object from which the property is being set or gotten.</p>
<pre class="brush:js">function sum() {
return this.a + this.b + this.c;
}
var o = {
a: 1,
b: 2,
c: 3,
get average() {
return (this.a + this.b + this.c) / 3;
}
};
Object.defineProperty(o, 'sum', {
get: sum, enumerable: true, configurable: true});
console.log(o.average, o.sum); // 2, 6
</pre>
<h3 id="As_a_constructor">As a constructor</h3>
<p>When a function is used as a constructor (with the {{jsxref("Operators/new", "new")}} keyword), its <code>this</code> is bound to the new object being constructed.</p>
<div class="note">
<p>While the default for a constructor is to return the object referenced by <code>this</code>, it can instead return some other object (if the return value isn't an object, then the <code>this</code> object is returned).</p>
</div>
<pre class="brush:js">/*
* Constructors work like this:
*
* function MyConstructor(){
* // Actual function body code goes here.
* // Create properties on |this| as
* // desired by assigning to them. E.g.,
* this.fum = "nom";
* // et cetera...
*
* // If the function has a return statement that
* // returns an object, that object will be the
* // result of the |new| expression. Otherwise,
* // the result of the expression is the object
* // currently bound to |this|
* // (i.e., the common case most usually seen).
* }
*/
function C() {
this.a = 37;
}
var o = new C();
console.log(o.a); // 37
function C2() {
this.a = 37;
return {a: 38};
}
o = new C2();
console.log(o.a); // 38
</pre>
<p>In the last example (<code>C2</code>), because an object was returned during construction, the new object that <code>this</code> was bound to simply gets discarded. (This essentially makes the statement "<code>this.a = 37;</code>" dead code. It's not exactly dead because it gets executed, but it can be eliminated with no outside effects.)</p>
<h3 id="As_a_DOM_event_handler">As a DOM event handler</h3>
<p>When a function is used as an event handler, its <code>this</code> is set to the element on which the listener is placed (some browsers do not follow this convention for listeners added dynamically with methods other than <a href="/en-US/docs/Web/API/EventTarget/addEventListener" title="The EventTarget method addEventListener() sets up a function that will be called whenever the specified event is delivered to the target."><code>addEventListener()</code></a>).</p>
<pre class="brush:js">// When called as a listener, turns the related element blue
function bluify(e) {
// Always true
console.log(this === e.currentTarget);
// true when currentTarget and target are the same object
console.log(this === e.target);
this.style.backgroundColor = '#A5D9F3';
}
// Get a list of every element in the document
var elements = document.getElementsByTagName('*');
// Add bluify as a click listener so when the
// element is clicked on, it turns blue
for (var i = 0; i < elements.length; i++) {
elements[i].addEventListener('click', bluify, false);
}</pre>
<h3 id="In_an_inline_event_handler">In an inline event handler</h3>
<p>When the code is called from an inline <a href="/en-US/docs/Web/Guide/Events/Event_handlers">on-event handler</a>, its <code>this</code> is set to the DOM element on which the listener is placed:</p>
<pre class="brush:js"><button onclick="alert(this.tagName.toLowerCase());">
Show this
</button>
</pre>
<p>The above alert shows <code>button</code>. Note however that only the outer code has its <code>this</code> set this way:</p>
<pre class="brush:js"><button onclick="alert((function() { return this; })());">
Show inner this
</button>
</pre>
<p>In this case, the inner function's <code>this</code> isn't set so it returns the global/window object (i.e. the default object in non–strict mode where <code>this</code> isn't set by the call).</p>
<h2 id="Specifications">Specifications</h2>
<table class="standard-table">
<tbody>
<tr>
<th scope="col">Specification</th>
</tr>
<tr>
<td>{{SpecName('ESDraft', '#sec-this-keyword', 'The this keyword')}}</td>
</tr>
</tbody>
</table>
<h2 id="Browser_compatibility">Browser compatibility</h2>
<p>{{Compat("javascript.operators.this")}}</p>
<h2 id="See_also">See also</h2>
<ul>
<li><a href="/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/Strict_mode">Strict mode</a></li>
<li><a href="https://dmitripavlutin.com/gentle-explanation-of-this-in-javascript/">Gentle explanation of 'this' keyword in JavaScript</a></li>
<li>Getting the global context: {{jsxref("globalThis")}}</li>
</ul>
|