web-dev-qa-db-fra.com

Pourquoi déclarer des propriétés sur le prototype pour les variables d'instance en JavaScript

J'essaie de comprendre cet art noir appelé JavaScript - et, je dois l'avouer, plutôt enthousiasmé. Je regarde des exemples de code, principalement de "easeljs", car c’est ce que je vais principalement utiliser. Et je suis un peu confus ..

Je pense (je crois comprendre) la différence entre l’utilisation de prototype pour les fonctions ou propriétés qui sont des variables class et l’utilisation de this.someProp pour les variables 'instance' (Oui, je comprends qu’il n’existe pas de classes en JavaScript.) 

Le code que j'ai examiné et que j'utilise comme modèles pour mon propre code, des variables declareprototype, auxquelles il se réfère ensuite, c'est-à-dire i.e.

Dans le constructeur: 

this.name = name;

Puis une déclaration: 

Object.prototype.name;

Et ensuite, 

this.name = "Freddy";

Ceci est dans les fonctions appelées avec 'new', alors dans ce cas, si je comprends bien, this fait référence à l'objet actuel. Ce qui me laisse perplexe, c’est ce que fait la déclaration de prototype et pourquoi l’utilisons-nous pour des variables d’exemple?


Clarification : Dans le code suivant, je ne vois pas ce que le prototype déclaration de radius permet d'obtenir:

(function(){
    // constructor
    function MyCircle(radius){
        this.radius = radius;
    }
    MyCircle.prototype.radius;
    this.area = function(){
        return 3.14*this.radius*this.radius;
    };
    window.MyCircle = MyCircle;
}());
23
DaveM

La valeur sur un prototype a un comportement de clé différent de celui défini sur une propriété directement sur l'instance. Essaye ça:

// Create a constructor
function A() {}

// Add a prototype property
A.prototype.name = "Freddy";

// Create two object instances from
// the constructor
var a = new A();
var b = new A();

// Both instances have the property
// that we created on the prototype
console.log(a.name); // Freddy
console.log(b.name); // Freddy

// Now change the property on the
// prototype
A.prototype.name = "George";

// Both instances inherit the change.
// Really they are just reading the
// same property from the prototype
// rather than their own property
console.log(a.name); // George
console.log(b.name); // George

Cela ne serait pas possible sans héritage prototypique. 

Vous pouvez tester si la propriété est la propriété instances ou la propriété prototype à l'aide de la méthode hasOwnProperty.

console.log(a.hasOwnProperty("name")); // false

Une instance peut remplacer la valeur prototype.

b.name = "Chris";
console.log(b.hasOwnProperty("name")); // true
console.log(a.name); // George
console.log(b.name); // Chris

Et revenez à la valeur prototype.

delete b.name;
console.log(b.hasOwnProperty("name")); // false
console.log(b.name); // George

Ceci est une partie puissante de l'héritage prototype. 

Dans l'autre motif:

function A() {
  this.name = "George";
}

La variable this.name est à nouveau déclarée à chaque nouvelle instance.

Il est logique que les méthodes soient déclarées comme fonctions sur le prototype. Plutôt que de redéclarer la définition de la fonction à chaque instance, toutes les instances peuvent partager une seule fonction. 

En termes de variables, plutôt que de fonctions, le prototype peut éventuellement être utilisé pour les valeurs par défaut dans le cas où une instance ne définit pas sa propre valeur.

Le code dans un violon

55
Stuart Wakefield

Une valeur stockée sur le prototype fournit une valeur default pour cette propriété.

Si vous écrivez ensuite une valeur dans cette propriété, l'instance instance acquerra cette nouvelle valeur en masquant la valeur du prototype, qui restera intacte.

Dans le contexte du code que vous avez maintenant ajouté à la question:

MyCircle.prototype.radius;

ne fait absolument rien. C'est un non-op - il tente de lire cette propriété, puis rejette le résultat.

11
Alnitak

D'autres réponses ont déjà expliqué la différence entre les propriétés prototype et d'instance.

Mais juste pour ajouter à la réponse, décomposons votre extrait de code:

(function(){                         // <------- 1
   // constructor
   function MyCircle(radius){        // <------- 2
       this.radius = radius;         // <------- 2.1
   }
   MyCircle.prototype.radius;        // <------- 3
   this.area = function(){           // <------- 4
       return 3.14*this.radius*this.radius;
   };
   window.MyCircle = MyCircle;       // <------- 5
}());
  1. Création d'une IIFE qui agit comme un conteneur de portée pour le code interne
  2. Déclarer une fonction appelée MyCircle à l'aide d'un modèle constructeur (mais notez qu'elle n'est jamais "construite" et devrait donc probablement supprimer la lettre majuscule car elle induit en erreur)
    • lorsque invoqué crée une propriété d'instance radius sur l'objet appelé
  3. Tenter d'accéder à une propriété radius sur la variable MyCircle de la fonction prototype qui n'existe pas, a pour résultat undefined
  4. Créer une propriété d'instance area sur l'objet de fenêtre global et lui attribuer une expression de fonction
  5. Création d'une propriété d'instance MyCircle sur un objet window et affectation de la fonction MyCircle

Résumé: On dirait qu'il crée une propriété area et MyCircle sur l'objet global window et que, lorsque MyCircle est appelé, il crée une propriété supplémentaire radius.

Utilisation: MyCircle doit être invoqué avant area puisque celui-ci repose sur l'initialisation du rayon par MyCircle:

window.MyCircle(10);
window.area(); // evaluates to 314
0
linasmnew

Oui, je conviens que le prototype peut être utilisé pour les valeurs par défaut des propriétés (variables). La fonction constructeur n'a pas besoin de déclarer une propriété; cela peut être fait conditionnellement.

function Person( name, age ) {
    this.name = name;

    if ( age ) {
        this.age = age;
    }
}

Person.prototype.sayHello = function() {
    console.log( 'My name is ' + this.name + '.' );
};

Person.prototype.sayAge = function() {
    if ( this.age ) {
        console.log( 'I am ' + this.age + ' yrs old!' ); 
    } else {
        console.log( 'I do not know my age!' );
    }
};

Person.prototype.age = 0.7;

//-----------

var person = new Person( 'Lucy' );
console.log( 'person.name', person.name ); // Lucy
console.log( 'person.age', person.age );   // 0.7
person.sayAge();                           // I am 0.7 yrs old!

Voyez comment la variable age de Lucy est déclarée et initialisée sous condition.

0
Michael R