В файле JavaScript я увидел:
function Somefunction(){
var that = this;
...
}
Какова цель объявления thatи назначения thisэтого ему?
В файле JavaScript я увидел:
function Somefunction(){
var that = this;
...
}
Какова цель объявления thatи назначения thisэтого ему?
Ответы:
Я собираюсь начать этот ответ с иллюстрации:
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
});
});
Мой ответ первоначально продемонстрировал это с помощью jQuery, который немного отличается:
$('#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
});
});
Поскольку thisчасто изменяется при изменении области действия путем вызова новой функции, вы не можете получить доступ к исходному значению с помощью его. Псевдоним это thatпозволяет вам по-прежнему получить доступ к первоначальному значению this.
Лично мне не нравится использование в thatкачестве псевдонима. Редко очевидно, к чему это относится, особенно если функции длиннее пары строк. Я всегда использую более описательный псевдоним. В моих примерах выше я бы, наверное, использовал clickedEl.
var self = this;. Слово, thatкажется, подразумевает, что переменная является чем угодно, НО this.
forEachФункция принимает второй необязательный аргумент , который является связывание функции. colours.forEach(function(){/* 'this' is bound correctly --> */}, this);Поэтому следует добавить примечание, var that = thisкоторое на самом деле не нужно forEach.
Из Крокфорда
По соглашению, мы делаем эту переменную приватной . Это используется, чтобы сделать объект доступным для приватных методов. Это временное решение для ошибки в спецификации ECMAScript языка , который вызывает это должен быть установлен неправильно для внутренних функций.
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);
Это оповещения ...
Использует, что думает, что это называется Дейв
UsesThis думает, что это называется неопределенным
thatпеременная вообще не используется в его примере. Это выглядит так, как будто создание переменной-держателя thisделает что-то с остальным кодом.
Это хак, чтобы заставить внутренние функции (функции, определенные внутри других функций) работать так, как они должны. В JavaScript, когда вы определяете одну функцию внутри другой, thisавтоматически устанавливается глобальная область видимости. Это может сбить с толку, потому что вы ожидаете thisиметь то же значение, что и во внешней функции.
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();
};
Это определенно проблема, когда вы создаете функцию как метод объекта (как car.startв примере), а затем создаете функцию внутри этого метода (как activateStarter). В методе верхнего уровня thisуказывает на объект, это метод (в данном случае car), но во внутренней функции thisтеперь указывает на глобальную область. Это боль.
Создание переменной для использования по соглашению в обеих областях является решением этой очень общей проблемы с javascript (хотя это также полезно в функциях jquery). Вот почему используется очень общее звучащее имя that. Это легко узнаваемое соглашение для преодоления недостатка в языке.
Как El Ronnoco намекает на Дугласа, Крокфорд считает, что это хорошая идея.
Использование thatне является действительно необходимым, если вы делаете обходной путь с использованием call()или 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);
};
Иногда thisможет ссылаться на другую область и ссылаться на что-то другое, например, предположим, что вы хотите вызвать метод конструктора внутри события DOM, в этом случае thisбудет ссылаться на элемент DOM, а не на созданный объект.
HTML
<button id="button">Alert Name</button>
JS
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
Решение выше воли Ассинга thisдля thatэтого мы можем и доступ свойства имени внутри sayHiметода из that, так что это может быть вызвано без проблем внутри вызова DOM.
Другое решение - назначить пустой thatобъект и добавить к нему свойства и методы, а затем вернуть его. Но с этим решением вы потеряли prototypeконструктор.
var Person = function(name) {
var that = {};
that.name = name;
that.sayHi = function() {
alert(that.name);
};
return that;
};
Вот пример
$(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();
}
});
}
});
});`
Таким образом, вы можете видеть, что это значение - два разных значения в зависимости от целевого элемента DOM, но когда вы добавляете «this» в код выше, вы меняете значение «this», на которое вы нацелены.
`$(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();
}
});
}
});
});`
..... $ (that) .css ("background-color", "# ffe700"); // Здесь значение "that" равно ".our-work-group> p> a", потому что значение var that = this; так что, хотя мы находимся в «this» = «.our-work-single-page», мы можем использовать «this» для манипулирования предыдущим элементом DOM.