Объектная переменная javascript становится undefined внутри анонимной функции

Поэтому я не могу понять, почему переменная this.tasks становится undefined внутри прослушивателя событий добавления, который у меня внутри объекта цели. У меня такое чувство, что это может иметь какое-то отношение к асинхронному программированию (которое я до сих пор не совсем понимаю). Извините, я немного JS noob, но если вы, ребята, можете объяснить мне, что я делаю неправильно, и что может быть лучшим решением, которое было бы потрясающе! Спасибо.

function Goal(name) {
        this.gDiv =  document.createElement('div');
        this.name = name || "goal";
        this.tasks = document.createElement('ul');
        //Sets the styling and content and adds it to the parent element
        this.initialize = function() {
            this.gDiv.className = "default";
            this.gDiv.setAttribute("id", this.name);
            this.gDiv.innerHTML = this.name;
            elem.appendChild(this.gDiv);

            this.gDiv.parentNode.insertBefore(this.tasks, this.gDiv.nextSibling);
            this.tasks.style.display = "none";


        };  
        //Creates a list underneath the a dive associated with the Goal object
        this.addTask = function(task) {
            var newLi = document.createElement('li');
                newLi.innerHTML = task;
                this.tasks.appendChild(newLi);
        };

        this.gDiv.addEventListener('click', function(){
            alert(this.tasks);              
        });

    }

Спасибо, ребята! Вы все ответили на мой вопрос! Некоторое время я почесывал голову. Престижность для всех вас!

Ответ 1

Область действия изменяется, когда вы вводите это анонимное закрытие, и изменяется "это". Вы можете взломать его, выполнив

var self = this;

А затем вместо этого используется self (например):

function Goal(name) {
    var self = this;

    /* ... */

    this.gDiv.addEventListener('click', function(){
        alert(self.tasks);              
    });

Если вы используете jQuery, вы можете сделать что-то более приятное:

this.gDiv.addEventListener('click', $.proxy(function() {
    alert(this.tasks);
 }, this));

В любом случае, все работает отлично.

ОБНОВЛЕНИЕ: В ES6 можно использовать функции стрелок, поскольку они не связывают свое собственное "это", так что это становится еще проще:

this.gDiv.addEventListener('click', () => {
    alert(this.tasks);
 });

Ответ 2

Вот сравнение некоторых методов (включая вашу проблему), чтобы дать вам дегустатор и немного попытаться объяснить.

// This is the problem that you have,
// where `this` inside the anonymous function
// is a different scope to it parent
function Test1(something) {
  // `this` here refers to Test1 scope
  this.something = something;
  setTimeout(function() {
    // `this` here refers to the anonymous function scope
    // `this.something` is `undefined` here
    console.log(this.something);
  }, 1000);
};

new Test1('Hello');

Ответ 3

В ES6 были введены функции стрелок, которые не связывают их с этим.

MDN для справки.

Таким образом, создание анонимной функции с использованием синтаксиса стрелок, вероятно, является самым простым способом преодоления этой проблемы в наши дни. В настоящее время поддерживается всеми основными браузерами, кроме IE.