This trong Javascript là gì

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.
Chính vì thế, nếu bạn gặp this, đừng có dịch nó là cái nàymà hãy dịch nó thành bối cảnh hay nơi gọi tao[context]

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]; // true

class trong ES6

Xét ví dụ một đoạn tutorial trong document của react:

class Toggle extends React.Component { constructor[props] { super[props]; console.log["1: ", this] this.state = {isToggleOn: true}; } handleClick[] { console.log["2: ", this] this.setState[prevState => [{ isToggleOn: !prevState.isToggleOn }]]; } render[] { console.log["3: ", this] return [
{this.state.isToggleOn ? 'ON' : 'OFF'}
]; } } ReactDOM.render[ , document.getElementById['root'] ];

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:
constructor[props] { super[props]; console.log["1: ", this] this.state = {isToggleOn: true}; this.handleClick = this.handleClick.bind[this]; // thêm dòng này vào }
  • 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ó.
handleClick = [] => { console.log["2: ", this] this.setState[prevState => [{ isToggleOn: !prevState.isToggleOn }]]; }
  • 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.
render[] { return [ this.handleClick[e]}> Click me ]; }

Một số ví dụ kiểm tra

VD1:

var obj = { someData: "a string" }; function myFun[] { console.log[this]; } obj.staticFunction = myFun; obj.staticFunction[]; //=======result==========// // this is obj // //=======================//

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:

function Person[]{ this.age = 10; setTimeout[function[]{ this.age++; console.log[this.age]; }, 1000]; } var p = new Person[]; //=========result==========// // NaN // //=========================//

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

Video liên quan

Chủ Đề