This trong JS
Ta có thể hiểu this trong JS cũng giống như trong ngôn ngữ tự nhiên của tiếng Anh. Nó giống như một danh từ để thay thế cho danh từ khác tránh việc lặp đi lặp lại. Ví dụ Michael is handsome because he is rich danh từ he ở trên là để tránh việc lặp lại Michael Xét tiếp ví dụ tiếp về sử dụng ...
Ta có thể hiểu this trong JS cũng giống như trong ngôn ngữ tự nhiên của tiếng Anh. Nó giống như một danh từ để thay thế cho danh từ khác tránh việc lặp đi lặp lại. Ví dụ
Michael is handsome because he is rich
danh từ he ở trên là để tránh việc lặp lại Michael
Xét tiếp ví dụ tiếp về sử dụng this trong JS
var person = { firstName: "Michael", lastName: "Scofield", fullName: function () { console.log(this.firstName + " " + this.lastName); // ta cũng có thể viết theo cách này console.log(person.firstName + " " + person.lastName); } }
person.fullName() Michael Scofield Michael Scofield
- Như ví dụ trên có thể thấy việc dùng this hay chính object đó để gọi là tương đương đều in ra 2 dòng fullName như nhau Nhưng khi dùng object person để gọi thì có vấn đề khác đó là có thể có một global variable nào đó bên ngoài cũng có tên person và khi gọi person có thể nó sẽ không lấy giá trị từ bên trong object mà bạn muốn.
- Điều đó dễ gây ra bug cũng như Việc debug sẽ trở nên khó khăn hơn.
Javascipt this
Tất cả các function trong JS đều có các properties, nó cũng giống như các object. Khi thực thi function nó sẽ lấy this property của object
this luôn luôn refer và giữ giá trị của object. Nó thường được sử dụng trong function hoặc method.
this được sử dụng bên trong function (giả sử là function A), nó chứa giá trị của object mà gọi đến function A
Chúng ta cần this để accesss vào các method và thuộc tính của object mà nó gọi đến function A, đặc biệt alf khi chúng ta không biết tên của object được gọi và đôi khi là một một object không có tên. this là shortcut để refer tới invoking object.
$ (".button").click (function (event) { console.log ($ (this).prop ("name")); });
$(this) Là jQuery syntax nó tương tự như this trong JavaScript, được sử dụng trong anonymous function. Anonymous function này sẽ thực thi phương thức click và lý do mà $this được bind tới button object là vì jQuery library bind $(this) tới object mà nó gọi phương thức click do đó $(this) sẽ có giá trị của $(".button") object.
this không được gán giá trị cho tới khi một object gọi function mà this được định nghĩa trong function này
Sử dụng this ở global scope
- Ở global scope khi code được thực thi ở browser, tất cả các global variable và các function được định nghĩa bên trong window object. Do đó, khi chúng ta sử this ở global function nó sẽ refer, và lấy giá trị của global window object.
var firstName = "Peter", lastName = "Ally"; function showFullName () { // "this" sẽ chứa giá trị của window object bởi vì fullName được định nghĩa ở global scope, giống như firstName, lastName console.log (this.firstName + " " + this.lastName); } var person = { firstName :"Penelope", lastName :"Barrymore", showFullName:function () { // `this` trong trường hợp này tham chiếu tới person object, bởi vì hàm showFullName này sẽ được gọi bởi person object console.log (this.firstName + " " + this.lastName); } } showFullName (); // Peter Ally // window là một object mà nó có thể gọi được tất cả các biến hay các function được định nghĩa ở global window.showFullName (); // Peter Ally // this ở bên trong showFullName method được định nghĩa bên trong person object do đó khi gọi nói sẽ lấy object là person person.showFullName (); // Penelope Barrymore
Khi this được sử dụng bên trong method, được truyền qua callback function
var user = { data:[ {name:"T. Woods", age:37}, {name:"P. Mickelson", age:43} ], clickHandler:function (event) { var randomNum = ((Math.random () * 2 | 0) + 1) - 1; // lấy random 0 hoặc 1 console.log (this.data[randomNum].name + " " + this.data[randomNum].age); } } // Outut là undefined bởi vì không button jQuery không có data property nào cả $ ("button").click (user.clickHandler); // Cannot read property '0' of undefined
Đoạn code ở trên chúng ta đang truyền user.clickHandler tới click function của jQuery object như một callback Và khi đó this bên trong user.clickHandler sẽ không còn tham chiếu tới user object nữa, lúc này nó sẽ tham chiếu tới object, object mà đang gọi user.clickHandler method, Mà object mà ta gọi user.clickHandler chính là jQuery object $("button") thực thi click function
Để tránh bị như vậy nó cần được làm rõ khi mà context thay đổi, khi chúng ta thực thi một phương thức ở một phức thức khác, this keyword sẽ không còn được tham chiếu tới object định nghĩa ra nó nữa, nó sẽ tham chiếu tới object gọi method có định nghĩa this bên trong
Solution để fix:
Như ở ví dụ trên chúng ta cần this tham chiếu tới user object thay vì jQuery object $("button"), chúng ta có thể sử dụng bind(), apply(), call() method để set giá trị cho this
thay vì gọi như cách cũ
$ ("button").click (user.clickHandler);
ta sẽ sử dụng bind() method để gán lại giá trị cho this
$("button").click (user.clickHandler.bind (user)); // P. Mickelson 43
this trong closure
Một ví dụ khác về việc dùng this ở trong một inner method (hay còn gọi là closure). Một chú ý quan trọng đó là closure không thể access this của outer function bằng cách dùng keyword this bởi vì this chỉ có thể access bên trong function của chính nó không phải một inner function
var user = { tournament: "The Masters", data: [ {name:"T. Woods", age:37}, {name:"P. Mickelson", age:43} ], clickHandler:function () { // khi gọi `this.data` ở đây vẫn được bởi vì ở dưới ta gọi `user.clickHandler` nên this ở đây refer tới object gọi phương thức định nghĩa nó (chính là user) this.data.forEach (function (person) { // Nhưng ở đây thì không đây là một `anonymous function` và this bên trong function này không còn tham chiếu tới user object nữa console.log ("What is This referring to? " + this); //[object Window] console.log (person.name + " is playing at " + this.tournament); // T. Woods is playing at undefined // P. Mickelson is playing at undefined }) } } user.clickHandler(); // What is "this" referring to? [object Window]
this bên trong anonymous function không thể access this ở outer function, và nó thuộc về global window object
Solution để fix:
Để giải quyết vấn đề khi gọi this bên trong anonymous function truyền qua forEach method, đó là gán this object cho một biến trước khi chúng ta gọi forEach
var user = { tournament: "The Masters", data:[ {name:"T. Woods", age:37}, {name:"P. Mickelson", age:43} ], clickHandler:function (event) { var theUserObj = this; this.data.forEach (function (person) { console.log (person.name + " is playing at " + theUserObj.tournament); }) } } user.clickHandler(); // T. Woods is playing at The Masters // P. Mickelson is playing at The Masters
Khi this được sử dụng trong method mà method này được gán bởi một biến khác
//data này ở global scope var data = [ {name:"Samantha", age:12}, {name:"Alexis", age:14} ]; var user = { // biến data này thuộc về user object data :[ {name:"T. Woods", age:37}, {name:"P. Mickelson", age:43} ], showData:function (event) { var randomNum = ((Math.random () * 2 | 0) + 1) - 1; // random number between 0 and 1 console.log (this.data[randomNum].name + " " + this.data[randomNum].age); } } // gán method user.showData cho một biến var showUserData = user.showData; //khi gọi showUserData function ở global scope, giá trị in ra sẽ là dữ liệu biến data của global scope chứ không phải `data` của user object showUserData (); // Samantha 12 (from the global data array)
Solution để fix:
sử dụng bind method để set value cho this
var showUserData = user.showData.bind(user); showUserData ();
Khi this được định nghĩa ở một biến nhưng lại được sử dụng bởi một biến khác
// Chúng ta có 2 object một có method `avg()` và object còn lại thì không // Ta sẽ mượn `avg()` method var gameController = { scores:[20, 34, 55, 46, 77], avgScore:null, players :[ {name: "Tommy", playerID: 987, age: 23}, {name: "Pau", playerID: 87, age: 33} ] } var appController = { scores:[900, 845, 809, 950], avgScore: null, avg: function () { var sumOfScores = this.scores.reduce (function (prev, cur, index, array) { return prev + cur; }); this.avgScore = sumOfScores / this.scores.length; } } //avgScore của gameController object sẽ lấy giá trị avg của appController từ score của appController chứ không phải từ score của gameController object gameController.avgScore = appController.avg();
this vẫn này không tham chiếu tới gameController object nó vẫn thuộc về appController bởi vì nó được gọi ở appController vậy để làm sao this có thể tham chiếu tới gamController object
*Solution để fix: *
sử dụng method apply()
appController.avg.apply (gameController, gameController.scores); console.log (gameController.avgScore); // 46.4 console.log (appController.avgScore); // null
gameController mượn avg method của appController để gán giá trị cho avgScore của gameController object this bên trong appController.avg() sẽ được gán cho gameController object bởi vì chúng ta đã truyền gameController vào apply method ở tham số đầu tiên
http://javascriptissexy.com/understand-javascripts-this-with-clarity-and-master-it/ You dont know JS