2014-02-14 4 views
9

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

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);    
     }); 

    } 

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

ответ

8

Смена области применения при вводе этого анонимного закрытия и «это» изменяется. Вы можете взломать вокруг него, делая

var self = this; 

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

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)); 

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

EDIT: Спасибо за предложение по редактированию.

+0

Ваш ответ был хороший. Вы изменили его, и теперь я хотел бы знать, что заставляет вас думать, что лучше использовать метод jQuery? – Xotic750

+0

В большой базе кода я вижу «var self = this;» идиома все время, и она становится неуклюжей, особенно после того, как у вас есть дальнейшее гнездование закрытий. Это гарантирует, что ваше «это» всегда то, что вы намереваетесь. –

+0

Или можно использовать метод вызова – Misters

6

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

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

 
new Test1('Hello');

// This solution captures the parent `this` as `test2This`, 
 
// which can then be used inside the anonymous function 
 
function Test2(something) { 
 
    var test2This = this; 
 

 
    this.something = something; 
 
    setTimeout(function() { 
 
    console.log(test2This.something); 
 
    }, 1000); 
 
} 
 

 
new Test2('World');

// This solution captures `this` as `test3This` in an `IIFE closure` 
 
// which can then be used in the anonymous function 
 
// but is not available outside of the `IIFE closure` scope 
 
function Test3(something) { 
 
    this.something = something; 
 
    (function(test3This) { 
 
    setTimeout(function() { 
 
     console.log(test3This.something); 
 
    }, 1000); 
 
    }(this)); 
 
} 
 

 
new Test3('Goodbye');

// This method requires that you load an external library: jQuery 
 
// and then use it's `$.proxy` method to achieve the basics of 
 
// Test3 but instead of being referred to as `test3This` the 
 
// outer scope `this` becomes the inner scope `this` 
 
// Ahh, that's much clearer? 
 
function Test4(something) { 
 
    this.something = something; 
 
    setTimeout($.proxy(function() { 
 
    console.log(this.something); 
 
    }, this), 1000); 
 
} 
 

 
new Test4('Mum');
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

// This is approximately what jQuery's `$.proxy` does 
 
// but without having to load the whole library 
 
function Test5(something) { 
 
    this.something = something; 
 
    setTimeout((function(func, context) { 
 
    return function() { 
 
     func.call(context); 
 
    }; 
 
    }(function() { 
 
    console.log(this.something); 
 
    }, this)), 1000); 
 
} 
 

 
new Test5('Dad');

// Lets create the proxy method as a reuseable 
 
function proxy(func, context) { 
 
    var args = Array.prototype.slice.call(arguments, 2); 
 

 
    return function() { 
 
    return func.apply(
 
     context, 
 
     args.concat(Array.prototype.slice.call(arguments)) 
 
    ); 
 
    }; 
 
} 
 

 
// and now using it 
 
function Test6(something) { 
 
    this.something = something; 
 
    setTimeout(proxy(function() { 
 
    console.log(this.something); 
 
    }, this), 1000); 
 
} 
 

 
new Test6('Me want cookies');

Тогда мы имеем Function#bind

function Test7(something) { 
 
    this.something = something; 
 
    setTimeout(function() { 
 
    // `this` was bound to the parent's `this` using bind 
 
    console.log(this.something); 
 
    }.bind(this), 1000); 
 
}; 
 

 
new Test7('Num num');
<script src="https://cdnjs.cloudflare.com/ajax/libs/es5-shim/4.5.9/es5-shim.min.js"></script>

И совсем недавно ES2015 Arrow functions

function Test8(something) { 
 
    this.something = something; 
 
    setTimeout(() => console.log(this.something), 1000); 
 
}; 
 

 
new Test8('Whoop');

+0

Спасибо, что нашли время, чтобы собрать все это вместе! Вы чемпион! – kelibra

+0

Да, это отличная запись. Большое спасибо @ Xotic750 - я буду стремиться быть настолько основательным, как вы были в будущем. Я должен признать, что я относительно новичок в JavaScript, и это одно из лучших объяснений, которые я когда-либо видел в прокси-функциях в JS. –

0

ключевое слово 'это' изменения в это означает для обработчика событий с помощью конструктора

пожалуйста, обратитесь к MDN

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this#As_a_DOM_event_handler

+0

Спасибо за ссылку Тим! – kelibra

+0

Я бы рекомендовал использовать документы, а не следовать идиоматическим быстрым исправлениям без более глубокого понимания. –

0

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

MDN for reference.

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

Смежные вопросы