В файле 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.