web-dev-qa-db-fra.com

Getters \ setters pour les nuls

J'ai essayé de comprendre les accesseurs et les setters et que cela ne s'enfonce pas. J'ai lu JavaScript Getters and Setters et définition de Getters and Setters et ne comprends tout simplement pas. il.

Quelqu'un peut-il clairement indiquer:

  1. Qu'est-ce qu'un getter et un setter sont censés faire, et
  2. Donnez des exemples TRÈS simples?
128
oksf

Outre réponse de @ millimoose , les paramètres peuvent également être utilisés pour mettre à jour d'autres valeurs.

function Name(first, last) {
    this.first = first;
    this.last = last;
}

Name.prototype = {
    get fullName() {
        return this.first + " " + this.last;
    },

    set fullName(name) {
        var names = name.split(" ");
        this.first = names[0];
        this.last = names[1];
    }
};

Maintenant, vous pouvez définir fullName, et first et last seront mis à jour et inversement.

n = new Name('Claude', 'Monet')
n.first # "Claude"
n.last # "Monet"
n.fullName # "Claude Monet"
n.fullName = "Gustav Klimt"
n.first # "Gustav"
n.last # "Klimt"
96
Matthew Crumley

Vous les utiliseriez par exemple pour implémenter des propriétés calculées.

Par exemple:

function Circle(radius) {
    this.radius = radius;
}

Object.defineProperty(Circle.prototype, 'circumference', {
    get: function() { return 2*Math.PI*this.radius; }
});

Object.defineProperty(Circle.prototype, 'area', {
    get: function() { return Math.PI*this.radius*this.radius; }
});

c = new Circle(10);
console.log(c.area); // Should output 314.159
console.log(c.circumference); // Should output 62.832

(CodePen)

57
millimoose

Getters et Setters en JavaScript

Vue d'ensemble

Les getters et les setters en JavaScript sont utilisés pour définir les propriétés calculées , ou les accesseurs . Une propriété calculée est une propriété qui utilise une fonction pour obtenir ou définir une valeur d'objet. La théorie de base fait quelque chose comme ça:

var user = { /* ... object with getters and setters ... */ };
user.phone = '+1 (123) 456-7890'; // updates a database
console.log( user.areaCode ); // displays '123'
console.log( user.area ); // displays 'Anytown, USA'

Ceci est utile pour effectuer automatiquement des tâches en arrière-plan lors de l'accès à une propriété, telles que le maintien de nombres, le reformatage de chaînes, le déclenchement d'événements ayant une valeur modifiée, la mise à jour de données relationnelles, l'accès aux propriétés privées, etc.

Les exemples ci-dessous montrent la syntaxe de base, bien qu'ils obtiennent et définissent simplement la valeur de l'objet interne sans rien faire de spécial. Dans les cas réels, vous modifierez la valeur d'entrée et/ou de sortie en fonction de vos besoins, comme indiqué ci-dessus.

get/set Mots-clés

ECMAScript 5 prend en charge les mots-clés get et set pour la définition des propriétés calculées. Ils fonctionnent avec tous les navigateurs modernes sauf IE 8 et inférieur.

var foo = {
    bar : 123,
    get bar(){ return bar; },
    set bar( value ){ this.bar = value; }
};
foo.bar = 456;
var gaz = foo.bar;

Getters et Setters personnalisés

get et set ne sont pas des mots réservés. Ils peuvent donc être surchargés pour créer vos propres fonctions de propriété calculées, calculées entre navigateurs. Cela fonctionnera dans n'importe quel navigateur.

var foo = {
    _bar : 123,
    get : function( name ){ return this[ '_' + name ]; },
    set : function( name, value ){ this[ '_' + name ] = value; }
};
foo.set( 'bar', 456 );
var gaz = foo.get( 'bar' );

Ou pour une approche plus compacte, une seule fonction peut être utilisée.

var foo = {
    _bar : 123,
    value : function( name /*, value */ ){
        if( arguments.length < 2 ){ return this[ '_' + name ]; }
        this[ '_' + name ] = value;
    }
};
foo.value( 'bar', 456 );
var gaz = foo.value( 'bar' );

Évitez de faire quelque chose comme ça, ce qui peut conduire à un gonflement du code.

var foo = {
    _a : 123, _b : 456, _c : 789,
    getA : function(){ return this.bar; },
    getB : ..., getC : ..., setA : ..., setB : ..., setC : ...
};

Pour les exemples ci-dessus, les noms de propriété internes sont abstraits avec un trait de soulignement afin de décourager les utilisateurs de simplement faire foo.bar Vs. foo.get( 'bar' ) et d'obtenir une valeur "non cuite". Vous pouvez utiliser du code conditionnel pour effectuer différentes tâches en fonction du nom de la propriété à laquelle vous accédez (via le paramètre name.).

Object.defineProperty ()

Utiliser Object.defineProperty() est un autre moyen d’ajouter des accesseurs et des setters, et peut être utilisé sur des objets définis. Il peut également être utilisé pour définir des comportements configurables et énumérables. Cette syntaxe fonctionne également avec IE 8, mais malheureusement uniquement sur les objets DOM.

var foo = { bar : 123 };
Object.defineProperty( foo, 'bar', {
    get : function(){ return bar; },
    set : function( value ){ this.bar = value; }
} );
foo.bar = 456;
var gaz = foo.bar;

__defineGetter __ ()

Enfin, __defineGetter__() est une autre option. Il est obsolète, mais reste largement utilisé sur le Web et ne risque donc pas de disparaître de si tôt. Cela fonctionne sur tous les navigateurs sauf IE 10 et inférieur. Bien que les autres options fonctionnent également bien sur les non-IE, celle-ci n'est donc pas utile.

var foo = { bar : 123; }
foo.__defineGetter__( 'bar', function(){ return this.bar; } );
foo.__defineSetter__( 'bar', function( value ){ this.bar = value; } );

Voir également

MDN get , set , Object.defineProperty () , __ defineGetter __ () , __ defineSetter __ ()
MSDN Support IE8 Getter

54
Beejor

Désolé de ressusciter une vieille question, mais je pensais pouvoir donner quelques exemples très simples et des explications pour les nuls. Aucune des autres réponses postées n’illustre la syntaxe comme celle du premier exemple de guide MDN , qui est à peu près aussi basique que possible.

Getter:

var settings = {
    firstname: 'John',
    lastname: 'Smith',
    get fullname() { return this.firstname + ' ' + this.lastname; }
};

console.log(settings.fullname);

... se connecter John Smith, bien sûr. A getter se comporte comme une propriété d'objet variable, mais offre la flexibilité d'une fonction pour calculer sa valeur renvoyée à la volée. C'est en gros une manière élégante de créer une fonction qui ne nécessite pas () lors de l'appel.

Setter:

var address = {
    set raw(what) {
        var loc = what.split(/\s*;\s*/),
        area = loc[1].split(/,?\s+(\w{2})\s+(?=\d{5})/);

        this.street = loc[0];
        this.city = area[0];
        this.state = area[1];
        this.Zip = area[2];
    }
};

address.raw = '123 Lexington Ave; New York NY  10001';
console.log(address.city);

... se connecter New York à la console. Comme les getters, setters sont appelés avec la même syntaxe que la définition de la valeur d'une propriété d'objet, mais constituent un autre moyen sophistiqué d'appeler une fonction sans ().

Voir this jsfiddle pour un exemple plus complet, peut-être plus pratique. Le fait de passer des valeurs dans l'objet setter déclenche la création ou le peuplement d'autres objets. En particulier, dans l'exemple jffiddle, le passage d'un tableau de nombres invite le fixateur à calculer la moyenne, la médiane, le mode et la plage; définit ensuite les propriétés de l'objet pour chaque résultat.

14
rojo

Les accesseurs et les setters n'ont de sens que si vous avez des propriétés privées de classes. Comme Javascript ne possède pas vraiment de propriétés de classe privées, contrairement aux langages orientés objet, il peut être difficile à comprendre. Voici un exemple d'objet compteur privé. La bonne chose à propos de cet objet est que la variable interne "nombre" ne peut pas être accessible de l'extérieur de l'objet.

var counter = function() {
    var count = 0;

    this.inc = function() {
        count++;
    };

    this.getCount = function() {
        return count;
    };
};

var i = new Counter();
i.inc();
i.inc();
// writes "2" to the document
document.write( i.getCount());

Si vous êtes toujours confus, jetez un coup d'œil à l'article de Crockford sur Membres privés en Javascript .

11
John

Je pense que le premier article auquel vous faites référence énonce clairement:

L'avantage évident d'écrire du code JavaScript de cette manière est que vous pouvez l'utiliser pour masquer des valeurs auxquelles vous ne souhaitez pas que l'utilisateur ait directement accès.

Le but ici est d'encapsuler et d'abréger les champs en leur permettant uniquement l'accès via une méthode get () ou set (). De cette façon, vous pouvez stocker le champ/les données en interne de la manière que vous souhaitez, mais les composants extérieurs ne sont éloignés que de l'interface publiée. Cela vous permet d’apporter des modifications internes sans modifier les interfaces externes, de procéder à des validations ou à des vérifications d’erreur au sein de la méthode set (), etc.

7
matt b

Bien que nous ayons souvent l'habitude de voir des objets avec des propriétés publiques sans aucun contrôle d'accès, JavaScript nous permet de décrire avec précision les propriétés. En fait, nous pouvons utiliser des descripteurs afin de contrôler comment une propriété peut être consultée et quelle logique nous pouvons lui appliquer. Prenons l'exemple suivant:

var employee = {
    first: "Boris",
    last: "Sergeev",
    get fullName() {
        return this.first + " " + this.last;
    },
    set fullName(value) {
        var parts = value.toString().split(" ");
        this.first = parts[0] || "";
        this.last = parts[1] || "";
    },
    email: "[email protected]"
};

Le résultat final:

console.log(employee.fullName); //Boris Sergeev
employee.fullName = "Alex Makarenko";

console.log(employee.first);//Alex
console.log(employee.last);//Makarenko
console.log(employee.fullName);//Alex Makarenko
6
Michael Horojanski

Ce qui est tellement déroutant à ce sujet ... les getters sont des fonctions qui sont appelées lorsque vous obtenez une propriété, des setters, lorsque vous la définissez. par exemple, si vous le faites

obj.prop = "abc";

Vous définissez la propriété prop. Si vous utilisez des getters/setters, la fonction setter sera appelée, avec "abc" comme argument. La définition de la fonction de définition à l'intérieur de l'objet devrait idéalement ressembler à ceci:

set prop(var) {
   // do stuff with var...
}

Je ne sais pas si cela est bien mis en œuvre sur les navigateurs. Il semble que Firefox ait également une syntaxe alternative, avec des méthodes spéciales ("magiques") à double soulignement. Comme d'habitude, Internet Explorer ne supporte rien de tout cela.

2
Rolf

Le explication que j'ai lue m'a aussi quelque peu dérouté, car j'essayais d'ajouter une propriété à un prototype existant que je n'avais pas écrit. Le remplacement du prototype semblait donc être une mauvaise approche. Donc, pour la postérité, voici comment j'ai ajouté une propriété last à Array:

Object.defineProperty(Array.prototype, "last", {
    get: function() { return this[this.length - 1] }
});

Un peu plus agréable que d’ajouter une fonction IMHO.

2
shawkinaw

Vous pouvez définir une méthode d'instance pour la classe js, via le prototype du constructeur.

Voici l'exemple de code:

// BaseClass

var BaseClass = function(name) {
    // instance property
    this.name = name;
};

// instance method
BaseClass.prototype.getName = function() {
    return this.name;
};
BaseClass.prototype.setName = function(name) {
    return this.name = name;
};


// test - start
function test() {
    var b1 = new BaseClass("b1");
    var b2 = new BaseClass("b2");
    console.log(b1.getName());
    console.log(b2.getName());

    b1.setName("b1_new");
    console.log(b1.getName());
    console.log(b2.getName());
}

test();
// test - end

Et, cela devrait fonctionner pour n'importe quel navigateur, vous pouvez aussi simplement utiliser nodejs pour exécuter ce code.

2
Eric Wang

Si vous faites référence au concept d'accesseurs, l'objectif simple est de cacher le stockage sous-jacent à toute manipulation arbitraire. Le mécanisme le plus extrême pour cela est

function Foo(someValue) {
    this.getValue = function() { return someValue; }
    return this;
}

var myFoo = new Foo(5);
/* We can read someValue through getValue(), but there is no mechanism
 * to modify it -- hurrah, we have achieved encapsulation!
 */
myFoo.getValue();

Si vous faites référence à la fonctionnalité JS getter/setter actuelle, par exemple. defineGetter/defineSetter, ou { get Foo() { /* code */ } }, il est intéressant de noter que, dans la plupart des moteurs modernes, l'utilisation ultérieure de ces propriétés sera beaucoup plus lente qu'elle ne le serait autrement. par exemple. comparer les performances de

var a = { getValue: function(){ return 5; }; }
for (var i = 0; i < 100000; i++)
    a.getValue();

vs.

var a = { get value(){ return 5; }; }
for (var i = 0; i < 100000; i++)
    a.value;
1
olliej