2011-03-15 4 views
4

Actuellement, je crée des objets en javascript en déclarant une construction (fonction régulière), puis ajouter des méthodes au prototype comme siéviter d'avoir à déclarer « var moi = ce » pour les fonctions javascript prototype

function Test(){ 
} 
Test.prototype.test1 = function(){ 
    var me = this; 
} 

Cependant, je voudrais éviter d'avoir à déclarer var me = this au sommet de chaque fonction. Ce qui suit semble fonctionner, mais il semble que ce serait très inefficace:

$(document).ready(function(){ 
var n = 0; 
(function(){ 

    function createTest(){ 
     var me; 
     function Test(){ 
      this.n = n; 
      this.testArr = [1, 2, 3, 4]; 
      n++; 
     } 

     Test.prototype.test1 = function(){ 
      me.test2(); 
     }; 
     Test.prototype.test2 = function(){ 
      alert(me.n); 
      $.getJSON('test.php', {}, function(reply) 
       //want to be able to use 'me' here 
       me.newField = reply; 
      }); 
     }; 

     var t = new Test(); 
     me = t; 
     return t; 
    } 
    window['createTest'] = createTest; 
})(); 

var t = createTest(); 
t.test1(); 
var t2 = createTest(); 
t2.test1(); 
t.test1(); 
}); 

Ce code donne les résultats prévu, mais est-il réellement aussi inefficace qu'il semble (l'objet de test étant nouveau déclaré chaque fois que vous appelez createTest())?

Anyhoo, cela semblerait un peu hacky ... y a-t-il une manière complètement différente de faire ceci qui est meilleure?

EDIT: La vraie raison pour laquelle je voudrais faire ceci est que les rappels comme celui dans test2 auront des références à la bonne this.

+2

Vous devriez lire ceci (excusez le jeu de mots): http://bonsaiden.github.com/JavaScript-Garden/#function.this –

+0

très instructif. Merci beaucoup! Oh, et votre calembour est excusé :) – Hersheezy

Répondre

2

Ce que vous pouvez faire est de lier la valeur actuelle this à un function et de stocker une copie quelque part. (Par souci d'efficacité.)

if (!Function.prototype.bind) { 
    // Most modern browsers will have this built-in but just in case. 
    Function.prototype.bind = function (obj) { 
     var slice = [].slice, 
      args = slice.call(arguments, 1), 
      self = this, 
      nop = function() { }, 
      bound = function() { 
       return self.apply(this instanceof nop ? this : (obj || {}), 
            args.concat(slice.call(arguments))); 
      }; 
     nop.prototype = self.prototype; 
     bound.prototype = new nop(); 
     return bound; 
    }; 
} 

function Test(n) { 
    this.n = n; 
    this.callback = (function() { 
     alert(this.n); 
    }).bind(this) 
} 

Test.prototype.test1 = function() { 
    this.test2(); 
} 

Test.prototype.test2 = function() { 
    doSomething(this.callback); 
} 

function doSomething(callback) { 
    callback(); 
} 

var t = new Test(2); 
t.test1(); 
+0

ouais mais si vous aviez un rappel à l'intérieur de l'un des prototypes, 'this' ne fera pas référence à l'objet. désolé de ne pas être assez clair. s'il vous plaît voir la modification. – Hersheezy

+0

@Hersheezy - Voir mise à jour. – ChaosPandion

+0

Hmmm, cela signifie-t-il que pour chaque fonction de l'objet Test, je devrais ajouter 'this.func = (function() {...}). Bind (this)' dans le constructeur? Si c'est le cas, je pense que le fait de déclarer 'var me = this' en haut de chaque fonction' Test.prototype' serait plus propre ... – Hersheezy

2

Je me rends compte de votre question n'a pas été marqué avec jQuery, mais que vous utilisez dans votre exemple, donc ma solution utilise également jQuery.

J'utilise parfois la fonction $.proxy pour éviter le contexte de rappel. Look at this simple jsfiddle example. Source ci-dessous.

function Test(){ 
    this.bind(); 
} 

Test.prototype.bind = function(){ 
    $('input').bind('change', $.proxy(this.change, this)); 
    // you could use $.proxy on anonymous functions also (as in your $.getJSON example) 
} 
Test.prototype.change = function(event){ 
    // currentField must be set from e.target 
    // because this is `Test` instance 
    console.log(this instanceof Test);   // true 
    console.log(event.target == $('input')[0]); // true 
    this.currentField = event.target;   // set new field 
}; 

function createTest(){ 
    return new Test(); 
} 

$(function(){ // ready callback calls test factory 
    var t1 = createTest(); 
}); 
+0

Très cool! Bon point, je devrais avoir tagué avec jQuery ...Je pense que je vais jouer avec cela et voir combien cela va répondre à mes besoins dans la pratique. – Hersheezy

0

La plupart du temps, je viens de déclarer une variable locale qui fait référence à cela, chaque fois que je besoin d'une référence à cela dans un rappel:

function Foo() { 
} 

Foo.prototype.bar = function() { 
    var that=this; 
    setTimeout(function() { 
    that.something="This goes to the right object"; 
    }, 5000); 
} 

Vous pouvez également utiliser bind() comme celui-ci :

Function Foo() { 
    this.bar = this.bar.bind(this); 
    // ... repeated for each function ... 
} 

Foo.prototype.bar = function() { 
} 

Qu'est-ce que cela vous est que chaque fois que vous donne créer une nouvelle instance Foo, les méthodes sont liées à l'instance en cours, de sorte que vous pouvez les utiliser comme des fonctions de rappel pour setTimeout() et al.

Questions connexes