Trong một tệp JavaScript tôi thấy:
function Somefunction(){
var that = this;
...
}
Mục đích của việc khai báo that
và gán this
nó cho nó là gì?
Trong một tệp JavaScript tôi thấy:
function Somefunction(){
var that = this;
...
}
Mục đích của việc khai báo that
và gán this
nó cho nó là gì?
Câu trả lời:
Tôi sẽ bắt đầu câu trả lời này bằng một minh họa:
var colours = ['red', 'green', 'blue'];
document.getElementById('element').addEventListener('click', function() {
// this is a reference to the element clicked on
var that = this;
colours.forEach(function() {
// this is undefined
// that is a reference to the element clicked on
});
});
Câu trả lời của tôi ban đầu đã chứng minh điều này với jQuery, chỉ khác một chút:
$('#element').click(function(){
// this is a reference to the element clicked on
var that = this;
$('.elements').each(function(){
// this is a reference to the current element in the loop
// that is still a reference to the element clicked on
});
});
Vì this
thường xuyên thay đổi khi bạn thay đổi phạm vi bằng cách gọi một hàm mới, bạn không thể truy cập giá trị ban đầu bằng cách sử dụng nó. Bí danh that
cho phép bạn vẫn truy cập giá trị ban đầu của this
.
Cá nhân, tôi không thích sử dụng that
như bí danh. Nó hiếm khi rõ ràng những gì nó được đề cập đến, đặc biệt là nếu các chức năng dài hơn một vài dòng. Tôi luôn luôn sử dụng một bí danh mô tả nhiều hơn. Trong các ví dụ của tôi ở trên, tôi có thể sử dụng clickedEl
.
var self = this;
. Từ này that
dường như ngụ ý biến là bất cứ điều gì NHƯNG this
.
forEach
chức năng phải mất một giây là đối số tùy chọn được các ràng buộc của hàm. colours.forEach(function(){/* 'this' is bound correctly --> */}, this);
Vì vậy, một lưu ý nên được thêm vào mà var that = this
không thực sự cần thiết với forEach
.
Từ Crockford
Theo quy ước, chúng ta thực hiện một tin rằng biến. Điều này được sử dụng để làm cho đối tượng có sẵn cho các phương thức riêng tư. Đây là một cách giải quyết cho một lỗi trong Đặc tả ngôn ngữ ECMAScript khiến điều này được đặt không chính xác cho các chức năng bên trong.
function usesThis(name) {
this.myName = name;
function returnMe() {
return this; //scope is lost because of the inner function
}
return {
returnMe : returnMe
}
}
function usesThat(name) {
var that = this;
this.myName = name;
function returnMe() {
return that; //scope is baked in with 'that' to the "class"
}
return {
returnMe : returnMe
}
}
var usesthat = new usesThat('Dave');
var usesthis = new usesThis('John');
alert("UsesThat thinks it's called " + usesthat.returnMe().myName + '\r\n' +
"UsesThis thinks it's called " + usesthis.returnMe().myName);
Thông báo này ...
Sử dụng Điều đó nghĩ rằng nó được gọi là Dave
Sử dụng Điều này nghĩ rằng nó được gọi là không xác định
that
biến không được sử dụng trong ví dụ của anh ấy. Nó làm cho nó trông giống như chỉ cần tạo một biến giữ giữ this
một cái gì đó cho phần còn lại của mã.
Đây là một hack để làm cho các chức năng bên trong (các chức năng được xác định bên trong các chức năng khác) hoạt động giống như chúng cần. Trong javascript khi bạn xác định một chức năng bên trong một chức năng khác this
sẽ tự động được đặt thành phạm vi toàn cầu. Điều này có thể gây nhầm lẫn bởi vì bạn mong đợi this
có cùng giá trị như trong hàm ngoài.
var car = {};
car.starter = {};
car.start = function(){
var that = this;
// you can access car.starter inside this method with 'this'
this.starter.active = false;
var activateStarter = function(){
// 'this' now points to the global scope
// 'this.starter' is undefined, so we use 'that' instead.
that.starter.active = true;
// you could also use car.starter, but using 'that' gives
// us more consistency and flexibility
};
activateStarter();
};
Đây là một vấn đề cụ thể khi bạn tạo một hàm như một phương thức của một đối tượng (như car.start
trong ví dụ) sau đó tạo một hàm bên trong phương thức đó (như activateStarter
). Trong phương thức cấp cao nhất this
trỏ đến đối tượng, nó là một phương thức (trong trường hợp này car
) , nhưng trong hàm bên trong this
bây giờ chỉ đến phạm vi toàn cục. Đây là một nỗi đau.
Tạo một biến để sử dụng theo quy ước trong cả hai phạm vi là một giải pháp cho vấn đề rất chung này với javascript (mặc dù nó cũng hữu ích trong các hàm jquery). Đây là lý do tại sao tên âm thanh rất chung that
được sử dụng. Đó là một quy ước dễ nhận biết để khắc phục một thiếu sót trong ngôn ngữ.
Giống như gợi ý của El Ronnoco tại Douglas Crockford nghĩ rằng đây là một ý tưởng tốt.
Việc sử dụng that
không thực sự cần thiết nếu bạn thực hiện một cách giải quyết với việc sử dụng call()
hoặc apply()
:
var car = {};
car.starter = {};
car.start = function(){
this.starter.active = false;
var activateStarter = function(){
// 'this' now points to our main object
this.starter.active = true;
};
activateStarter.apply(this);
};
Đôi khi this
có thể tham chiếu đến một phạm vi khác và tham chiếu đến một cái gì đó khác, ví dụ giả sử bạn muốn gọi một phương thức xây dựng bên trong một sự kiện DOM, trong trường hợp this
này sẽ đề cập đến phần tử DOM không phải là đối tượng được tạo.
HTML
<button id="button">Alert Name</button>
Mã não
var Person = function(name) {
this.name = name;
var that = this;
this.sayHi = function() {
alert(that.name);
};
};
var ahmad = new Person('Ahmad');
var element = document.getElementById('button');
element.addEventListener('click', ahmad.sayHi); // => Ahmad
Giải pháp ở trên sẽ khẳng this
định that
sau đó chúng ta có thể và truy cập thuộc tính name bên trong sayHi
phương thức từ đó that
, vì vậy điều này có thể được gọi mà không gặp vấn đề gì trong lệnh gọi DOM.
Một giải pháp khác là gán một that
đối tượng trống và thêm các thuộc tính và phương thức cho nó và sau đó trả về nó. Nhưng với giải pháp này, bạn đã mất các prototype
nhà xây dựng.
var Person = function(name) {
var that = {};
that.name = name;
that.sayHi = function() {
alert(that.name);
};
return that;
};
Đây là một ví dụ `
$(document).ready(function() {
var lastItem = null;
$(".our-work-group > p > a").click(function(e) {
e.preventDefault();
var item = $(this).html(); //Here value of "this" is ".our-work-group > p > a"
if (item == lastItem) {
lastItem = null;
$('.our-work-single-page').show();
} else {
lastItem = item;
$('.our-work-single-page').each(function() {
var imgAlt = $(this).find('img').attr('alt'); //Here value of "this" is '.our-work-single-page'.
if (imgAlt != item) {
$(this).hide();
} else {
$(this).show();
}
});
}
});
});`
Vì vậy, bạn có thể thấy giá trị này là hai giá trị khác nhau tùy thuộc vào phần tử DOM mà bạn nhắm mục tiêu nhưng khi bạn thêm "cái đó" vào mã ở trên, bạn sẽ thay đổi giá trị của "cái này" mà bạn đang nhắm mục tiêu.
`$(document).ready(function() {
var lastItem = null;
$(".our-work-group > p > a").click(function(e) {
e.preventDefault();
var item = $(this).html(); //Here value of "this" is ".our-work-group > p > a"
if (item == lastItem) {
lastItem = null;
var that = this;
$('.our-work-single-page').show();
} else {
lastItem = item;
$('.our-work-single-page').each(function() {
***$(that).css("background-color", "#ffe700");*** //Here value of "that" is ".our-work-group > p > a"....
var imgAlt = $(this).find('img').attr('alt');
if (imgAlt != item) {
$(this).hide();
} else {
$(this).show();
}
});
}
});
});`
..... $ (đó) .css ("màu nền", "# ffe700"); // Ở đây giá trị của "that" là ".our-work-group> p> a" vì giá trị của var that = this; vì vậy mặc dù chúng tôi đang ở "this" = '.our-work-single-page', chúng tôi vẫn có thể sử dụng "that" để thao tác với phần tử DOM trước đó.