2010-12-15 115 views
17

Venant de C#/PHP, je voudrais avoir des getters/setters complets sur les classes (fonctions) que je crée avec Javascript.Meilleur moyen de créer des getters/setters de classe en Javascript?

Cependant, dans une grande partie du code Javascript que j'ai rencontré, les getters et les setters ne sont pas utilisés, plutôt des variables publiques simples. J'ai eu le plaisir de trouver John Resig's article sur les getters et les setters, mais quelques commentaires qui disent que certains navigateurs "ne supportent pas les getters et les setters" ce qui m'embrouille car ils ne sont pas une "caractéristique" de Javascript mais plus d'un motif simple qui utilise la syntaxe Javascript de base. Cet article a également été écrit en 2007, donc il pourrait être obsolète maintenant.

Quel est l'état actuel des getters et des setters en Javascript? Sont-ils en effet "pris en charge" par tous les navigateurs aujourd'hui (quel que soit ce que cela signifie)? Sont-ils un modèle de programmation utile pour Javascript ou sont des classes Javascript (étant des fonctions) mieux avec des variables publiques? Existe-t-il une meilleure façon de les mettre en œuvre que les suivantes?

$(document).ready(function() { 
    var module = new Module('idcode'); 
    module.set_id_code('new idcode'); 
    module.set_title('new title'); 
    $('body').html(module.get_id_code()+': '+module.get_title()); 
}); 

function Module(id_code, title) { 
    var id_code = id_code; 
    var title = title; 

    //id_code 
    this.get_id_code = function() { 
     return id_code; 
    } 
    this.set_id_code = function(value) { 
     id_code = value; 
    } 

    //title 
    this.get_title = function() { 
     return title; 
    } 
    this.set_title = function(value) { 
     title = value; 
    } 
} 
+2

Pourquoi voulez-vous du code bloat? – gdj

+0

Exactement, je ne veux pas de bloat de code, mais je voudrais avoir la séparation de l'accès public et privé à mes classes comme je le fais dans d'autres langages tels que PHP et C#. PHP a __get et __set méthodes magiques et C# a sa "syntaxe de propriété" pour obtenir la séparation sans la syntaxe boursouflée. Des fonctionnalités comme celle-ci en Javascript? –

+0

Le code ci-dessus a-t-il fonctionné dans IE 7/8/9 ?? – Shaggy

Répondre

1

accesseurs ne sont pas caractéristiques, mais « design patterns » (code ballonnement dans ce cas) pour les langues qui ne prennent pas en charge la syntaxe de la propriété.

Puisque Javascript n'a pas besoin de getters et setters, vous ne voulez pas les écrire. Utilisez les fonctionnalités linguistiques qui sont à votre disposition et les idiomes qui fonctionnent bien dans une langue ne fonctionnent pas très bien dans une autre.

Une de mes citations préférées vient de la communauté Python:

Nous sommes tous adultes consentants ici

en discutant pourquoi des variables privées et la dissimulation des informations ne sont pas nécessaires.

La cote peut être trouvée here. Apprenez ce que la langue vous offre et adoptez sa culture et ses règles.

+1

-1 Les mutateurs de propriété sont essentiels pour une bonne encapsulation. Permettre des objets dans les internes d'un autre objet provoque des bugs horribles! Il n'aurait aucun moyen de garder son état interne cohérent. En outre, le langage supporte nativement les getters et les setters. –

5

Que diriez-vous:

function Module(id_code, title) { 
    var id_code = id_code; 
    var title = title; 

    var privateProps = {}; 

    this.setProperty = function(name, value) { 
     // here you could e.g. log something 
     privateProps[name] = value; 
    } 

    this.getProperty = function(name) { 
     return privateProps[name]; 
    } 
} 

Les méthodes getter et setter agissent ici sur un objet privé utilisé pour stocker les propriétés qui ne peuvent être accessibles à partir de toute autre méthode. Ainsi, vous pourriez, par exemple, implémenter un setter (ou getter) qui se connecte ou fait ajax ou autre, chaque fois qu'une propriété est modifiée (l'un des buts des méthodes getter/setter).

+2

Cela ne fournit aucune fonctionnalité utile. setProperty et getProperty sont des fonctions publiques, donc cela ajoute juste un niveau d'indirection. Il n'ajoute pas la possibilité d'appeler des fonctions getter et setter privées. –

+0

Il ajoute des propriétés qui ne sont pas accessibles à l'exception des méthodes getter et setter - exactement comme les méthodes getter et setter publiques sont utilisées pour modifier les membres privés dans d'autres langues. C'est une démonstration - ces méthodes pourraient aussi faire d'autres choses. – sje397

+0

assez juste - mais soit ajouter un crochet dans votre code pour le faire, ou ajouter un commentaire dans votre code où le comportement pourrait être modifié. Oui, c'est évident pour les programmeurs vétérans javascript, mais pas pour les débutants. –

9

Vous manquez le point, je pense. (Ou peut-être les autres answerers manquent point.) ECMAScript fournit un "derrière les coulisses" mécanisme getter/setter, de sorte que

x.foo = 3; 
y = x.foo; 

traduit vraiment en (sorte de)

x.PutValue("foo",3); 
y = x.GetValue("foo"); 

PutValue et GetValue sont des fonctions sans nom, non directement accessibles pour les setters et les getters pour les propriétés. (Voir le ECMAScript standard, 3rd ed., section 8.7.1 et 8.7.2) La 3ème édition ne semble pas explicitement définir comment les utilisateurs peuvent configurer des getters et des fonctions de setters personnalisés. L'implémentation de Javascript de Mozilla a fait et continue, par exemple.(Ce qui est JSDB qui utilise le langage Javascript 1.8):

js>x = {counter: 0}; 
[object Object] 
js>x.__defineGetter__("foo", function() {return this.counter++; }); 
js>x.foo 
0 
js>x.foo 
1 
js>x.foo 
2 
js>x.foo 
3 
js>x.foo 
4 

La syntaxe est (ou du moins a été jusqu'à présent) spécifique au navigateur. Internet Explorer en particulier fait défaut, au moins selon this SO question.

La 5ème édition du standard ECMAScript semble standardiser ce mécanisme. Voir this SO question on getters and setters.


modifier: Un exemple plus pratique, peut-être, à vos besoins:

function makePrivateObject() 
{ 
    var state = 0; 
    var out = {}; 
    out.__defineSetter__("foo", function(x) {}); 
    // prevent foo from being assigned directly 
    out.__defineGetter__("foo", function() { return state; }); 
    out.count = function() { return state++; } 
    return out; 
} 

js>x = makePrivateObject() 
[object Object] 
js>x.foo 
0 
js>x.foo = 33 
33 
js>x.foo 
0 
js>x.count() 
0 
js>x.count() 
1 
js>x.count() 
2 
js>x.foo 
3 
+2

Cela peut être la façon dont ils sont gérés en interne, mais techniquement, ils sont toujours des «variables publiques» si je ne peux pas contrôler l'accès à eux. L'avantage des getters et setters pour moi est que je peux déterminer par ex. que la propriété "Salaire" ne peut être modifiée que de manière interne, ou par ex. Quand elle est changée, (a) la modification est consignée, (b) et l'événement est déclenché, etc. À moins d'avoir des méthodes accesseur getter/setter, je n'ai pas la possibilité de définir cette couche de fonctionnalité pour mes classes. –

+2

Ah - mais il y a une subtilité ici; Si vous avez la possibilité d'utiliser des méthodes personnalisées getter/setter, vous le faites. Je vais modifier ma réponse. –

14

Firefox, Safari, Chrome et Opera (mais pas IE) ont tous le même non standard getter et setter mécanisme intégré. ECMAScript 5 inclut une syntaxe différente qui est currently making its way into browsers et deviendra la norme à l'avenir. IE 8 a déjà cette fonctionnalité, mais seulement sur les nœuds DOM, pas les objets JavaScript natifs réguliers. C'est ce que la syntaxe ressemble:

var obj = {}; 

Object.defineProperty(obj, "value", { 
    get: function() { 
     return this.val; 
    }, 
    set: function(val) { 
     this.val = val; 
    } 
}); 
5

Vous pouvez réellement définir setters et getters en javascript et pas seulement les mimick. Je pense que cela fonctionne sur tous les navigateurs sauf IE8 et ci-dessous.

$(document).ready(function() { 
    var module = new Module('idcode'); 
    module.id = 'new idcode'; 
    module.title = 'new title'; 
    $('body').html(module.id + ': ' + module.title); 
}); 

function Module(id, title) { 
    return { 
    id_code: id_code, 
    _title: title, 

    get id() { 
     return id_code; 
    }, 
    set id(value) { 
     id_code = value; 
    }, 

    get title() { 
     return _title; 
    }, 
    set title(value) { 
     title = value; 
    } 
    } 
}; 
2

J'aime:

// Module 
var Module = function() { 

    // prive getter/setter value 
    var __value; 

    // private getter/setter method 
    var _value = function() { 
     if(!arguments.length) return __value; 
     else __value = arguments[0]; 
    }; 

    // output/public  
    return { 
     value: _value 
    }; 
} 
0

Une façon fiable, sémantique que j'ai favorisé est d'utiliser setters et getters. Par exemple, j'ai créé l'objet suivant:

var myComplexObject = { 
    changelog: {}, 
    log: function(name, val) { 
    console.log("set " + name + " to " + val); 
    if (!this.changelog[name]) 
     this.changelog[name] = []; 
    this.changelog[name].push(val); 
    }, 
    set o (val) { 
    this.log("o", val); 
    }, 
    get o() { 
    console.log("You will never know the true value!"); 
    return 42; 
    } 
} 

Ici, chaque fois que vous lisez ou modifiez la valeur de o, le comportement est personnalisé. Prenons, par exemple, la ligne de code suivante et sa sortie de la console:

myComplexObject.o = "oxygen"; 
set o to oxygen 

Ensuite, dans cet exemple, en essayant de lire la valeur des résultats dans ce:

var read = myComplexObject.o; 
console.log(read); 
You will never know the true value! 
42 

Et, dans cet exemple, chaque nouvelle valeur que vous définissez est enregistrée:

myComplexObject.o = "Oh no!"; 
console.log(myComplexObject.changelog.o); 
set o to Oh no! 
["oxygen", "Oh no!"]