jQuery / JavaScript путаница с указателем

Поведение this при вызове функции bar сбивает меня с толку. См. Код ниже. Есть ли способ сделать так, чтобы "this" был простым старым экземпляром объекта js, когда bar вызывается из обработчика кликов, вместо того, чтобы быть элементом html?

// a class with a method

function foo() {

    this.bar();  // when called here, "this" is the foo instance

    var barf = this.bar;
    barf();   // when called here, "this" is the global object

    // when called from a click, "this" is the html element
    $("#thing").after($("<div>click me</div>").click(barf));
}

foo.prototype.bar = function() {
    alert(this);
}

person I. J. Kennedy    schedule 02.04.2009    source источник
comment
Пожалуйста, объясните "this" is the foo instance. Следующий jsfiddle (jsfiddle.net/yY6fp/1) демонстрирует, что this в this.bar() оценивается как window (глобальный) объект.   -  person Kevin Meredith    schedule 02.01.2014


Ответы (7)


Добро пожаловать в мир JavaScript! : D

Вы забрели в область видимости и закрытия javascript.

Краткий ответ:

this.bar()

выполняется в рамках foo (поскольку this относится к foo)

var barf = this.bar;
barf();

выполняется в глобальном масштабе.

this.bar в основном означает:

выполнить функцию, указанную this.bar, в рамках this (foo). Когда вы скопировали this.bar в barf и запустите barf. Javascript понимается как запуск функции, на которую указывает barf, а поскольку this нет, он просто запускается в глобальной области.

Чтобы исправить это, вы можете изменить

barf();

примерно так:

barf.apply(this);

Это указывает Javascript привязать область действия this к barf перед его выполнением.

Для событий jquery вам нужно будет использовать анонимную функцию или расширить функцию привязки в прототипе для поддержки области видимости.

Для получения дополнительной информации:

person Aaron Qian    schedule 02.04.2009
comment
Я сам не уверен на 100% в терминологии, но я думаю, что этот ответ (и связанные с ним ресурсы) путают «область действия» с «контекстом выполнения». Объект, на который указывает this, является контекстом выполнения и полностью не зависит от области действия (к которой имеют отношение замыкания). Область действия определяется во время создания функции и определяет, какие переменные может видеть функция; контекст выполнения определяется всякий раз, когда вызывается функция, и определяет, на что указывает this. Замени везде здесь «область видимости» на «контекст выполнения», и только тогда это будет правильно - я думаю! - person Mark Amery; 13.06.2013

Хорошее объяснение ключевого слова this в JavaScript доступно в QuirksMode.

person Pawel Krakowiak    schedule 02.04.2009

Вы можете найти это:

Управление значением this в событии jQuery

или это:

http://www.learningjquery.com/2007/08/what-is-this

Полезный.

person Will Dean    schedule 02.04.2009

Получите книгу: JavaScript: хорошие части.

Также прочитайте как можно больше Дугласа Крокфорда http://www.crockford.com/javascript/

person Chris Brandsma    schedule 02.04.2009

Вы можете использовать Function.apply в функции, чтобы указать, что this должно относиться к:

$("#thing").after($("<div>click me</div>").click(function() {
    barf.apply(document); // now this refers to the document
});
person moff    schedule 02.04.2009
comment
Помимо того, что в вашем коде отсутствует закрытая скобка, функция apply мгновенно выполняет функцию barf вместо того, чтобы возвращать указатель на функцию. - person Martin; 02.04.2009

Это потому, что this всегда является экземпляром, к которому прикреплена функция. В случае EventHandler это класс, вызвавший событие.

Вы можете помочь себе с помощью такой анонимной функции:

function foo() {
  var obj = this;
  $("#thing").after($("<div>click me</div>").click(function(){obj.bar();}));
}

foo.prototype.bar = function() {
  alert(this);
}
person Martin    schedule 02.04.2009

this.bar();  // when called here, "this" is the foo instance

этот комментарий неверен, когда foo используется как обычная функция, а не как конструктор. здесь:

foo();//this stands for window
person Boki    schedule 01.02.2014