1. Mở đầu
Trước khi học hiểu về thisbạn nên học trước vềscope và closure
Trong js, từ khóa thislà thứ rất hay nhưng cũng là thứ gây ra bao rắc rối cho nhiều người, nhất là đối với những người đi từ ngôn ngữ lập trình khác sang js.
Lý do lớn nhất khiến thisgây hiểu nhầm cho bao nhiêu người chính là vì ý nghĩa từ điểncủa chính từ this
Khi bạn bắt gặp từ thistrong lập trình, gần như chắc chắn bạn sẽ nghĩ tới nó chính là tham chiếu tới instancehiện tại hoặc nội hàmhiện tại, và đó cũng là lý do khiến nhiều người hiểu nhầm từ thistrong js.
Có 2 chú ý khi bạn bắt gặp thismà cần phải nhớ đó là:
- thischính là bối cảnh[context] của nơi mà hàm chứa từ thisđược gọi. Bạn hãy nhớ từ thistham chiếu tới cái vùng không gian mà hàm chứa từ thisđược gọi.
- Chỉ có 2 loại contextđối với thislà objectchứa method được gọi hoặc global, ngoài ra không có loại khác.
- Khi gặp từ this, chỉ quan tâm tới cái nơi gọi hàm chứa nó chứ không được dịch thislà nội hàm hiện tại.
2. thiskhông phải là tham chiếu tới chính function.
function foo[num] { console.log["foo: " + num]; //keep track of how many times `foo` is called this.count++; } foo.count = 0; var i; for [i=0; i {return this}]; console.log[foo[] === globalObject]; // true // 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]; // trueclass trong ES6
Xét ví dụ một đoạn tutorial trong document của react:
Các bước thực thi như sau:
- Đầu tiên là tìm tới nơi bắt đầu gọi hàm ở đâu? Nó là đoạn ReactDOM.render[...
- Khi gọi trong đó, nó sẽ khởi tạo một object Toggle
- Khi object Toggle được khởi tạo, hàm constructorđược thực thi, thistrong hàm này chính là object củaToggle[xem với từ khóa newở phía trên]
- Sau khi constructor được gọi xong, hàm renderđược gọi thực thi, thisở đây vẫn là object của class Toggle
Bạn để ý trong hàm rendercó đoạn , khác với inline event handlergiải thích ở phía trên thì syntax này có vẻ giống nhưng lại không thêm dâu []vào sau handleClick. Khi nào trigger onClick được gọi thì this.handleClickmới được thực thi. Nhưng lúc biên dịch thì thisở đây vẫn là object của Togglenên không có lỗi gì xảy ra.
Khi render xong và bạn click vào button thì chuyện gì xảy ra?
Khi click, câu lệnh this.handleClicksẽ thực thi, nhảy vào hàm handleClick[]như giải thích ở phần DOM event handlerthis ở đây sẽ là global[window]chứ không phải object của Togglenên nó sẽ báo lỗi không biết hàm setStatecủa window.
Để sửa lỗi này, có một số cách như sau:
- Cách 1: Luôn set thisthành trigger element trong constructor của class bằng cách thêm dòng như sau:
- Cách 2: Biến hàm handleClickthành arrow functionđể cho chính hàm đó không có thismà sẽ sử dụng thiscủa contextgọi nó.
- Cách 3: Biến hàm callback thành arrow function nhưng cách này khuyến cáo là không nên sử dụng so với 2 cách trên do vấn đề hiệu năng.
Một số ví dụ kiểm tra
VD1:
VD2:
var obj = { myMethod : function [] { console.log[this]; } }; var myFun = obj.myMethod; myFun[]; //=========result==========// // this is global[window] // //=========================//VD3:
function myFun[] { console.log[this]; } var obj = { myMethod : function [] { eval["myFun[]"]; } }; obj.myMethod[]; //=========result==========// // this is global[window] // //=========================//VD4:
function myFun[] { console.log[this]; } var obj = { someData: "a string" }; myFun.call[obj]; //=========result==========// // this is obj // //=========================//VD5:
function Person[]{ var age = 10; setTimeout[function[]{ this.age++; console.log[this.age]; }, 1000]; } var p = Person[]; //=========result==========// // NaN // //=========================// var q = new Person[]; //=========result==========// // NaN // //=========================//VD6:
function Person[]{ this.age = 10; setTimeout[function[]{ this.age++; console.log[this.age]; }, 1000]; } var p = Person[]; //=========result==========// // 11 // //=========================//nhưng:
Link tham khảo:
//github.com/getify/You-Dont-Know-JS/blob/master/this%20%26%20object%20prototypes/ch2.md
//github.com/getify/You-Dont-Know-JS/blob/master/this%20%26%20object%20prototypes/ch2.md
//stackoverflow.com/questions/3127429/how-does-the-this-keyword-work/3127440#3127440
//developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
//reactjs.org/docs/handling-events.html