Puisque vous avez demandé un similar question, prenons-le pas à pas. C'est un peu plus long, mais cela peut vous faire gagner beaucoup plus de temps que ce que j'ai écrit:
La propriété est une fonctionnalité de POO conçue pour la séparation nette du code client. Par exemple, dans certains e-shop vous pourriez avoir des objets comme celui-ci:
function Product(name,price) {
this.name = name;
this.price = price;
this.discount = 0;
}
var sneakers = new Product("Sneakers",20); // {name:"Sneakers",price:20,discount:0}
var tshirt = new Product("T-shirt",10); // {name:"T-shirt",price:10,discount:0}
Puis dans votre code client (e-shop), vous pouvez ajouter des remises à vos produits:
function badProduct(obj) { obj.discount+= 20; ... }
function generalDiscount(obj) { obj.discount+= 10; ... }
function distributorDiscount(obj) { obj.discount+= 15; ... }
plus tard , le propriétaire du magasin en ligne pourrait réaliser que la réduction ne peut pas être supérieure à 80%. Maintenant, vous devez trouver toutes les occurrences de la modification d'actualisation dans le code client et ajouter une ligne
if(obj.discount>80) obj.discount = 80;
Puis le propriétaire e-shop peut encore changer sa stratégie, comme « si le client est revendeur, la remise maximale peut être 90% ". Et vous devez faire le changement sur plusieurs endroits et vous devez vous rappeler de modifier ces lignes à chaque fois que la stratégie est modifiée. C'est un mauvais design. C'est pourquoi l'encapsulation est le principe de base de la POO.Si le constructeur était comme ça:
function Product(name,price) {
var _name=name, _price=price, _discount=0;
this.getName = function() { return _name; }
this.setName = function(value) { _name = value; }
this.getPrice = function() { return _price; }
this.setPrice = function(value) { _price = value; }
this.getDiscount = function() { return _discount; }
this.setDiscount = function(value) { _discount = value; }
}
Ensuite, vous pouvez simplement l'alter getDiscount
(accesseur) et setDiscount
méthodes (mutator). Le problème est que la plupart des membres se comportent comme des variables communes, juste la réduction nécessite des soins spéciaux ici. Mais une bonne conception nécessite l'encapsulation de chaque membre de données pour maintenir le code extensible. Vous devez donc ajouter beaucoup de code qui ne fait rien. C'est aussi une mauvaise conception, un passe-partout antipattern. Parfois, vous ne pouvez pas simplement refactoriser les champs à des méthodes plus tard (le code de l'eshop peut devenir grand ou un code tiers peut dépendre de l'ancienne version), de sorte que le standard est moins mauvais ici. Mais encore, c'est le mal. C'est pourquoi les propriétés ont été introduites dans plusieurs langues. Vous pouvez conserver le code original, transformer simplement l'élément d'escompte dans une propriété avec get
et set
blocs:
function Product(name,price) {
this.name = name;
this.price = price;
//this.discount = 0; // <- remove this line and refactor with the code below
var _discount; // private member
Object.defineProperty(this,"discount",{
get: function() { return _discount; },
set: function(value) { _discount = value; if(_discount>80) _discount = 80; }
});
}
// the client code
var sneakers = new Product("Sneakers",20);
sneakers.discount = 50; // 50, setter is called
sneakers.discount+= 20; // 70, setter is called
sneakers.discount+= 20; // 80, not 90!
alert(sneakers.discount); // getter is called
Notez la dernière ligne: la responsabilité de la valeur d'actualisation correcte a été transférée du code client (e définition de magasin) à la définition du produit. Le produit est responsable de la cohérence de ses membres de données. Un bon design est (à peu près dit) si le code fonctionne de la même manière que nos pensées.
Tellement de propriétés. Mais javascript est différent de pures langages orientés objet tels que C# et les codes les caractéristiques différemment:
En C#, transformant les champs en propriétés est un breaking change, si les champs publics doivent être codés comme Auto-Implemented Properties si votre code peut être utilisé dans client compilé séparément.
En Javascript, les propriétés standard (membre de données avec getter et setter décrit ci-dessus) sont définis par descripteur accesseur (dans le lien que vous avez dans votre question). En exclusivité, vous pouvez utiliser descripteur de données (vous ne pouvez donc pas utiliser i.e.valeur et mis sur la même propriété):
- descripteur accesseur = get + set (voir l'exemple ci-dessus)
- obtenir doit être une fonction; sa valeur de retour est utilisée pour lire la propriété; si non spécifié, la valeur par défaut est indéfini, qui se comporte comme une fonction qui renvoie undefined
- mis doit être une fonction; son paramètre est rempli avec RHS en assignant une valeur à la propriété; si non spécifié, la valeur par défaut est undefined, qui se comporte comme une fonction vide
- descripteur de données = valeur + inscriptible (voir l'exemple ci-dessous)
- valeur défaut undefined; si inscriptible, configurable et dénombrable (voir ci-dessous) sont vraies, la propriété se comporte comme un champ de données ordinaires
- inscriptible - par défaut faux; sinon true, la propriété est en lecture seule; tentative d'écriture est ignorée sans erreur *!
Les deux descripteurs peuvent avoir ces membres:
- configurables - par défaut faux; si ce n'est pas vrai, la propriété ne peut pas être supprimée; tentative de suppression est ignorée sans erreur *!
- dénombrable - par défaut faux; si vrai, il sera itéré dans
for(var i in theObject)
; si elle est fausse, il ne sera pas réitérée, mais il est encore accessible du public
*, sauf dans strict mode - dans ce cas, JS arrête l'exécution avec TypeError moins qu'il ne soit pris dans try-catch block
Pour lire ces paramètres, utilisez Object.getOwnPropertyDescriptor()
.
savoir par exemple:
var o = {};
Object.defineProperty(o,"test",{
value: "a",
configurable: true
});
console.log(Object.getOwnPropertyDescriptor(o,"test")); // check the settings
for(var i in o) console.log(o[i]); // nothing, o.test is not enumerable
console.log(o.test); // "a"
o.test = "b"; // o.test is still "a", (is not writable, no error)
delete(o.test); // bye bye, o.test (was configurable)
o.test = "b"; // o.test is "b"
for(var i in o) console.log(o[i]); // "b", default fields are enumerable
Si vous ne souhaitez pas autoriser le code client de ces tricheurs, vous pouvez restreindre l'objet de trois niveaux de confinement:
- Object.preventExtensions(yourObject) Prévient nouvelles propriétés à ajouter à yourObject. Utilisez
Object.isExtensible(<yourObject>)
pour vérifier si la méthode a été utilisée sur l'objet. La prévention est peu profonde (lire ci-dessous).
- Object.seal(yourObject) comme ci-dessus et les propriétés ne peuvent pas être supprimées (définit effectivement
configurable: false
à toutes les propriétés). Utilisez Object.isSealed(<yourObject>)
pour détecter cette fonctionnalité sur l'objet. Le sceau est peu profond (lire ci-dessous).
- Object.freeze(yourObject) comme ci-dessus et les propriétés ne peuvent pas être modifiées (en fait
writable: false
à toutes les propriétés avec un descripteur de données). La propriété d'écriture de Setter n'est pas affectée (puisqu'elle n'en a pas). Le gel est peu profond: cela signifie que si la propriété est Objet, ses propriétés ne sont pas gelées (si vous le souhaitez, vous devriez effectuer quelque chose comme "deep freeze", similaire à deep copy - cloning). Utilisez Object.isFrozen(<yourObject>)
pour le détecter.
Vous n'avez pas besoin de déranger avec ceci si vous écrivez juste quelques lignes amusantes. Mais si vous voulez coder un jeu (comme vous l'avez mentionné dans la question liée), vous devriez vraiment vous préoccuper du bon design. Essayez de google quelque chose à propos de antipatterns et odeur de code. Cela vous aidera à éviter des situations comme "Oh, j'ai besoin de réécrire complètement mon code!", il peut vous faire économiser des mois de désespoir si vous voulez beaucoup coder. Bonne chance.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty c'est un excellent tutoriel ici. – Martian2049