Đặt vấn đề
Mình thấy có rất nhiều bạn cảm thấy từ khoá this trong javascript
rất khó nắm bắt, khó làm quen và tiếp cận cho dù các bạn cũng đã tìm các bài viết, video trên mạng giải thích về từ khoá này, nhưng trong nhiều trường hợp, các bạn vẫn không hiểu và giải thích được vì sao this lại trả về giá trị này thay vì giá trị kia,… @[email protected] Vậy nên, hôm nay mình quyết định sẽ viết một bài ghi chú đầy đủ những gì các bạn cần biết về this trong js
.
Một số thuật ngữ được sử dụng trong bài viết
Constructure function:
Tương tự với class
trong các ngôn ngữ OOP
, hướng đối tượng
, được sử dụng để khởi tạo các object
có chung một đặc điểm. Có điều là, bất cứ function nào trong js (trừ arrow function
– cái mình sẽ nói sau ở phần lưu ý
) cũng có thể trở thành một constructure function.
Method:
Các bạn có thể hiểu một method
là một function
của một object
.
1. Okay, vậy this là gì ?
Rất ngắn gọn !
this chỉ đơn giản là một biến và biến này trả về object gần nhất chứa nó.
1 2 3 4 5 6 7 8 | <span class="token comment">// *** constructor function</span> <span class="token keyword">function</span> <span class="token function">ConstFunc</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">ConstFunc</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// *** => trả về window</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">ConstFunc</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// *** => trả về obj</span> |
Chúng ta hãy cùng phân tích ví dụ trên nhé. Ở ví dụ trên, mình có tạo một constructor function
tên là ConstFunc
, function này khi chạy sẽ trả về biến this khi nó được chạy.
- Ở lần chạy thứ 1, this trả về
window
doobject
gần nhất chứa từ khoá this khi này làwindow
. - Ở lần chạy thứ 2, do mình đã
khởi tạo
mộtobject
từConstFunc
, nênobject
gần nhất chứa this lúc này làConstFunc
chứ không còn làwindow
nữa.
Khá là rắc rối phải không , bây giờ mọi người hãy cùng xem tiếp các mục dưới đây để hiểu hơn về những gì mình viết nhé.
1. This trả về window (global object)
Nếu các bạn chưa biết thì tất cả code của ta viết đều được bao bởi window ( global object ), nên khi ta gọi this mà nó không được bao bởi một object khác thì this sẽ trả về window.
1 2 3 4 5 6 7 8 | console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// *** trả về window</span> <span class="token keyword">function</span> <span class="token function">func</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">func</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// *** trả về window</span> |
2. This trả về một object khác window
Như mình đã nói thì this sẽ trả về gần nhất chứa nó, điều này cũng đúng khi this được đặt bên trong một method
của một object
.
1 2 3 4 5 6 7 8 9 | <span class="token comment">// *** this nằm bên trong một method của một object</span> <span class="token keyword">const</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span> method<span class="token punctuation">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>obj<span class="token punctuation">.</span><span class="token function">method</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// *** this sẽ trả về obj</span> |
1 2 3 4 5 6 7 | <span class="token comment">// *** this nằm bên trong một object được khởi tạo từ một constructor function</span> <span class="token keyword">function</span> <span class="token function">ConstFunc</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">ConstFunc</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// *** => trả về obj</span> |
4. This trong các Event
This
trong các event sẽ trả về element
được đính kèm với event đó.
1 2 3 4 | document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">"btn"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function-variable function">onclick</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// *** => <div id="test">test</div> (html element)</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> |
5. Lưu ý
Strict mode
Nếu ta dùng strict mode
thì this trong các function sẽ trả về undefined
(trừ method
).
1 2 3 4 5 6 7 8 | <span class="token string">"use strict"</span> <span class="token keyword">function</span> <span class="token function">func</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">func</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// *** this sẽ trả về undefined</span> |
1 2 3 4 5 6 7 8 9 10 | <span class="token string">"use strict"</span> <span class="token keyword">const</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span> method<span class="token punctuation">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>obj<span class="token punctuation">.</span><span class="token function">method</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// *** this của method vẫn sẽ trả về obj</span> |
Arrow function
Giá trị mà this nằm trong một arrow function
trả về sẽ được kế thừa từ this của function
/method
, nơi mà arrow function
đó được khai báo chứ không còn trả trả về object
gần nhất chứa nó nữa. Trong trường hợp một arrow function
không được khai báo bên trong bất kỳ một function nào, thì this của arrow function
đó sẽ trả về window
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <span class="token keyword">const</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span> methoddd<span class="token punctuation">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// *** trả về obj</span> <span class="token keyword">const</span> <span class="token function-variable function">arrowFunc</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">arrowFunc</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// *** arrowFunc đc khai báo bên trong method methoddd</span> <span class="token comment">// nên giá trị this của arrowFunc sẽ được kế thừa từ this của methoddd</span> <span class="token comment">// và trả về obj</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>obj<span class="token punctuation">.</span><span class="token function">methoddd</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <span class="token keyword">const</span> <span class="token function-variable function">arrowFunc</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// *** giá trị của this của arrowFunc lần này sẽ là window</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span> methoddd<span class="token punctuation">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// *** trả về obj</span> <span class="token function">arrowFunc</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// *** this lần này sẽ trả về window do arrowFunc không còn được </span> <span class="token comment">// khai báo bên trong methoddd nữa</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>obj<span class="token punctuation">.</span><span class="token function">methoddd</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
Có một lưu ý nữa về arrow function
mà mình muốn chia sẻ với các bạn đó là vì this của arrow function
sẽ trả về undefined
nếu như nó không được khai báo bên trong bất kỳ một function
nào, nên arrow
function không bao giờ được sử dụng để làm constructure function
hay method
của một object
được khởi tạo bằng object initializer
(các bạn cứ hiểu cái này nghĩa là các object
được khai báo như thế này nhé: var obj = { ... }
).
1 2 3 4 5 6 7 8 | <span class="token comment">// *** dùng arrow function làm constructure function</span> <span class="token keyword">const</span> <span class="token function-variable function">Human</span> <span class="token operator">=</span> <span class="token punctuation">(</span>name<span class="token punctuation">,</span> age<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">=</span> name<span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>age <span class="token operator">=</span> age<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> man <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Human</span><span class="token punctuation">(</span><span class="token string">'Hunq'</span><span class="token punctuation">,</span> <span class="token number">20</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// *** => Uncaught TypeError: Human is not a constructor </span> |
1 2 3 4 5 6 7 8 | <span class="token comment">// *** dùng arrow function làm method của một object được khởi tạo bằng object inintializer</span> <span class="token keyword">const</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span> method<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">this</span> <span class="token punctuation">}</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>obj<span class="token punctuation">.</span><span class="token function">method</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// *** => this của method sẽ trả về window vì trên thực tế,</span> <span class="token comment">// method đang được khai báo độc lập (không nằm trong bất cứ function nào)</span> |
Lời kết.
Trong bài viết này, mình không liệt kê ra các trường hợp cụ thể mà các bạn phải nhớ khi sử dụng this như trong các bài viết khác để đem đến cho mọi người có một các nhìn khác về từ khóa này. Qua bài viết này, mình mong mọi người có thể thực sự hiểu và làm chủ được this mà không phải học thuộc hay nhớ bất cứ trường hợp nào của this nhé. Chúc các bạn một ngày tốt lành. Cheers !