2010-12-10 72 views
0

Impossible de comprendre comment accéder aux propriétés "étendues" d'un objet enfant à partir d'un rappel dans le parent. Mes deux tentatives sont ci-dessous. Je voudrais pour la fonction "say_something" alerter "say hi", où "salut" vient de l'enfant. Au lieu de cela, il est dit "dis indéfini".JavaScript: lorsque B hérite de A, les rappels dans A ne peuvent pas voir B

Tentative 1: Je crée un objet "a", puis crée un nouvel objet "b" qui en dérive. Mais un rappel dans "a" (ici à partir d'un setTimeout) n'aura pas accès à la bonne "ceci".

var a = {}; 
a.say_something = function() { setTimeout(function() { alert("say " + this.text); }, 0); }; 

var b = Object.create(a); 
b.text = "hi"; 

b.say_something(); // alerts "say undefined" 

Tentative 2: La sagesse commune dit réarranger pour permettre une variable « que » accessible dans le rappel. Mais, contrairement à « ce », « qui » ne peut pas accéder aux propriétés de « b »:

var a = (function() { 
    var that = {}; 
    that.say_something = function() { setTimeout(function() { alert("say " + that.text); }, 0); }; 
    return that; 
}()); 

var b = (function() { 
    var that = Object.create(a); 
    that.text = "hi"; 
    return that; 
}()); 

b.say_something(); // alerts "say undefined" 

PS, j'utiliser la fonction Object.create de Douglas Crockford au lieu de la (source de confusion pour moi) nouvelle(). Il est copié ici:

if (typeof Object.create !== "function") { 
    Object.create = function (o) { 
     function F() {} 
     F.prototype = o; 
     return new F(); 
    }; 
} 

Répondre

2

Si vous ajoutez

a.say_something(); 

vous premier exemple, il retournera say undefined. Le problème est que setTimeout n'exécute pas le code qu'il appelle dans la portée dans laquelle il est appelé.

Nous pouvons résoudre ce soit par:

  1. coder en dur une référence à l'objet existant alert('say ' + a.text);
  2. En utilisant call() et apply() de préciser le contexte dans lequel la fonction doit exécuter. (Et bind() aussi - pour les dernières plates-formes.)

L'approche n ° 2 est ce que vous cherchez.

var a = {}; 
a.text = "hello!"; 
function say_something() { 
    var that = this; // Save the reference to *this* this. 
    setTimeout(function() { console.log.call(that, "say " + that.text); }, 0); 
} 
a.say_something = say_something; 
a.say_something(); // say hello! 

var b = (function() { 
    var that = Object.create(a); 
    that.text = "hi there!"; 
    return that; 
}()); 

b.say_something(); // say hi there! 
+0

"Enregistrer la référence à * ceci * ceci" est ce qu'il a fait. Merci! Pour que mon code "Attempt 2" fonctionne, j'ai ajouté un * second * "var that = this;" directement avant l'appel à setTimeout, comme vous le suggérez. (Il ombrage/"écrase" le premier "var that = {};", que je continue à utiliser ailleurs) –

2

Dans une fonction setTimeout, "this" fait toujours référence à l'objet Window.

Ce que je fais habituellement est quelque chose comme (testé et fonctionne)

a.say_something = function() { 
    var thisObj = this; 
    setTimeout(function() { 
     alert("say " + thisObj.text); 
    }, 0); 
}; 
+0

Est-ce que cette adresse le problème parent-enfant du tout? –