Что значит «вар это = это»? значит в JavaScript?

351

В файле JavaScript я увидел:

function Somefunction(){
   var that = this; 
   ... 
}

Какова цель объявления thatи назначения thisэтого ему?

Крис
источник
3
возможный дубликат var self = this?
Берги
6
Хак «this» и «that» не требуется для функций со стрелками. С функциями стрелок «это» работает как положено. Смотрите здесь для более подробной информации ES6 в глубине: функции стрелки
Сатгуру Шривастава
1
здесь концепция этого объясняется scotch.io/@alZami/understanding-this-in-javascript
AL-zami
Отличное объяснение загадочного поведения на основе контекста здесь
RBT
Последнее и обновленное объяснение можно найти здесь
Сукрит Гупта

Ответы:

486

Я собираюсь начать этот ответ с иллюстрации:

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.

lonesomeday
источник
149
Я обычно хожу с var self = this;. Слово, thatкажется, подразумевает, что переменная является чем угодно, НО this.
Дэвид Мердок
13
@ Давид Да, я думал, что это несколько вводит в заблуждение. Но если, как говорит Крокфорд, это соглашение, разумно ли идти по этому пути. Я полностью согласен с вами, хотя, имеет гораздо больше смысла.
Эль Ронноко
4
@El Ronnoco, но «У него седые волосы и чокнутая борода, и его манера поведения напоминает сварливого старика, который кричит детям, чтобы он убирался с газона». - blogging.compendiumblog.com/blog/software-for-humans/0/0/… ;-p
Дэвид Мердок
7
@ElRonnoco: Это обращение к власти, хотя. Если мы только когда-либо делаем то, что «известные люди» говорят, что мы должны делать, мы идем к катастрофе.
Гонки легкости на орбите
3
forEachФункция принимает второй необязательный аргумент , который является связывание функции. colours.forEach(function(){/* 'this' is bound correctly --> */}, this);Поэтому следует добавить примечание, var that = thisкоторое на самом деле не нужно forEach.
Мэтт Кларксон
107

Из Крокфорда

По соглашению, мы делаем эту переменную приватной . Это используется, чтобы сделать объект доступным для приватных методов. Это временное решение для ошибки в спецификации ECMAScript языка , который вызывает это должен быть установлен неправильно для внутренних функций.

JS Fiddle

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 думает, что это называется неопределенным

Эль Ронноко
источник
2
Спасибо, суммирую это достаточно хорошо для меня.
Крис
3
Я прочитал это, не понял, потому что не было никаких деталей, искал в Google, нашел эту страницу. Где я снова указал на то же предложение. Отсюда и отрицательный голос.
Адитья депутат
3
Это справедливо, я бы сказал, что кому-то, незнакомому с JavaScript, будет трудно понять концепцию только из моего ответа. Я ответил очень кратко (и я сделал ссылку на страницу, для которой вы гуглили ...) Я бы сказал, что ответ одиночного дня самый ясный, хотя я бы все-таки предпочел его на простом JS, а не на примере jQuery.
Эль Ронноко
16
Я не обижаюсь. Приятно видеть кого-то, кто комментирует при понижении голосов!
Эль Ронноко
4
Проблема с ответом Крокфорда состоит в том, что thatпеременная вообще не используется в его примере. Это выглядит так, как будто создание переменной-держателя thisделает что-то с остальным кодом.
r3m0t
86

Это хак, чтобы заставить внутренние функции (функции, определенные внутри других функций) работать так, как они должны. В 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 намекает на Дугласа, Крокфорд считает, что это хорошая идея.

Waylon Flinn
источник
8
Я полагаю, что это более полезный ответ, чем принятый. Потому что это объясняет причину, по которой Крокфорд изобрел «это», а ответ о jQuery - нет.
Константин Смольянин
4
Это на самом деле лучший пример, чем принятый ответ. Это объясняет, как это выглядит как «ошибка в спецификации языка ECMAScript, которая приводит к неправильной установке этого параметра для внутренних функций», говорит Дуглас.
Какации
1
Вы можете сделать грамматику правильной, хотя. Я знаю, что это больше похоже на опечатку, но это может сбить с толку новичков в JavaScript, так как этот вопрос больше похож на новичка. Я имею в виду, что это должно быть: var car = {}; car.starter = {}; car.start = function () {...}
Какация
1
@kakacii Спасибо. Исправлено сейчас.
Уэйлон Флинн
9

Использование 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);
};
Адела
источник
3

Иногда 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;
};
Ахмад Аджми
источник
2

Вот пример

$(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.

stacksonstacksonstacks
источник