Quel est le prototype
Le type de fonction a un prototype de propriété, qui est traduit directement dans le prototype. Cette propriété est un pointeur, pointant vers un objet, qui contient certaines propriétés et méthodes, qui seront partagées par toutes les instances (objets) générées par la fonction actuelle.
Sur la base de ce qui a été dit auparavant, vous pouvez obtenir le code suivant:
fonction personne () {...} personne.prototype = {country: 'China', SayName: function () {...}}Tout d'abord, une personne d'instance de type de fonction est créée, puis le prototype de méthode de la personne est un objet, et la déclaration pointe vers un objet. Les propriétés et méthodes de cet objet seront partagées par l'instance générée par la fonction de personne actuelle. C'est-à-dire:
Person1 = new Person (); Person2 = new Person ();
Person1 et Person2 sont tous deux générés à nouveau via des instances de type de fonction de personne. Les deux ont le pays et la méthode communs communs, car ils ont tous un pointeur (__proto__), pointant directement l'objet pointé par Person.prototype. Cependant, veuillez noter que le pointeur __proto__ n'est pas standard. Il n'est défini que par des navigateurs tels que Chrome et Firefox. En fait, cette propriété ne sera pas utilisée, mais n'est utilisée que comme compréhension du prototype:
En ce qui concerne l'utilisation des prototypes et d'autres méthodes, nous en parlerons plus spécifiquement plus tard.
Créer un motif d'objet
Ensuite, examinons les méthodes et les modèles communs pour créer des objets, ainsi que leurs avantages et leurs inconvénients.
1. Modèle d'usine
Tout comme une usine, le processus de création d'objets en béton est abstrait et les fonctions sont utilisées pour encapsuler les détails de la création d'objets avec des interfaces spécifiques. En utilisant des fonctions au lieu de travaux de répétition partielle, le code est le suivant:
fonction createSerson (nom, âge, travail) {var o = nouveau objet (); o.name = name; O.age = âge; O.Job = Job; o.sayName = function () {alert (this.name); }; retour o;} var person1 = createSerson ("jiangshi", "22", "ingénieur");Cela crée une personne, et le modèle d'usine résout le problème de la création répétée de plusieurs objets similaires, mais ne résout pas le problème de reconnaissance des objets. C'est juste qu'un objet est simplement créé, et peu importe si cet objet est créé à partir d'un modèle humain ou d'un modèle animal, il est impossible de distinguer le type de cet objet.
2. Mode constructeur
Créez un constructeur personnalisé pour définir les propriétés et les méthodes de types d'objets personnalisés.
Personne de fonction (nom, âge, travail) {this.name = name; this.age = âge; this.job = jpb; this.sayName = function () {alert (this.name); };}; var person1 = new personne (...);3. La différence entre le mode constructeur et le mode d'usine:
La personne est un objet de type de fonction. Après nouveau, un objet continuera d'être généré. Cependant, puisque cet objet nouvellement généré est passé dans la fonction et attribué à ce pointeur, le contenu transmis devient la propriété ou la méthode de l'objet nouvellement généré.
L'habitude par défaut des constructeurs est capitalisée dans la première lettre. L'exécution de code ci-dessus passe par les étapes suivantes:
Dans les cas générés de cette manière, ils contiennent tous un attribut de constructeur par défaut pointant vers la fonction du constructeur, par exemple:
alerte (personne1.constructor == personne);
Par conséquent, en utilisant le modèle du constructeur, il existe une distinction de type et son instance peut être identifiée comme un type spécifique.
De plus, le constructeur est une fonction ordinaire. Parce que vous souhaitez faire des commentaires pour obtenir un nouvel objet, vous utilisez de nouveaux pour l'appeler. Sinon, l'exécuter directement est comme une fonction normale. Par exemple, si vous exécutez Person.SayName () ci-dessus, Window.name apparaîtra parce que la fonction est exécutée sous la fenêtre, donc ce point vers la fenêtre.
Le mode constructeur est également défectueux. Les méthodes en mode constructeur sont recréées sur chaque instance, donc les fonctions du même nom sur différentes instances ne sont pas égales. Par exemple:
Person1.sayName == Person2.SayName; //FAUX
C'est-à-dire que chaque instance d'objet, les attributs et les méthodes générées par le constructeur est unique et copiées. Les attributs sont uniques, car c'est exactement la différence entre les objets, mais de nombreuses méthodes ont les mêmes fonctions et code. Si vous les copiez plusieurs fois à plusieurs reprises, vous gaspillerez évidemment des ressources.
Nous pouvons donc mettre la fonction à l'extérieur, puis pointer la fonction avec un pointeur dans le constructeur. Dans l'instance générée, la méthode stocke un pointeur vers une certaine fonction, ce qui signifie une fonction partagée:
Fonction Person (nom, âge) {this.name = name; this.age = âge; this.sayName = SayName;} function sayName () {alert (this.name);}Cependant, de cette manière, cette fonction devient une fonction globale, et elle n'est pas fortement corrélée avec le constructeur de la personne et n'a pas d'encapsulation.
Ensuite, veuillez venir en mode prototype.
Mode prototype
Une partie des bases sur les prototypes a été introduite plus tôt. Autrement dit, chaque fonction a un attribut prototype, pointant vers un objet (objet prototype), et certaines propriétés ou méthodes peuvent être placées dans cet objet. Ensuite, l'instance générée par cette fonction aura un attribut irrégulier (__proto__) pointant vers le prototype.
De ce point de vue, vous devriez être en mesure de comprendre que les propriétés et les méthodes générées par le prototype sont partagées par toutes les instances.
Cela résout simplement le problème du partage des fonctions dans le mode constructeur ci-dessus et dans les exemples. Par exemple, le code suivant:
function Person () {....} personne.prototype.name = "jiangsUi"; personne.prototype.sayName = function () {alert (this.name);}; var person1 = new personne (); personne1.sayName (); // Jiangshiiou
Personne.prototype = {constructeur: personne, nom: "jiangsui", sayName: function () {alert (this.name); }};La deuxième méthode couvre l'ensemble de l'objet Prototype, vous devez donc spécifier manuellement la propriété du constructeur, pointant vers la fonction du constructeur, sinon il pointera vers l'objet.
Trouvons leur relation:
Utilisez isPrototypeOf () pour déterminer la relation entre les objets. Par exemple:
Personne.prototype.isprototypeof (Person1);
Lorsque le code lit une certaine propriété d'un objet, une recherche sera effectuée. Commencez par l'objet actuel, et sinon, recherchez l'objet prototype pointé par le pointeur, sans rechercher le constructeur. L'instance d'objet est accessible mais ne peut pas remplacer la valeur de l'objet Prototype. Si un attribut avec le même nom que l'objet Prototype est défini dans l'instance, le processus de recherche se termine par l'instance sans accéder à l'objet Prototype, de sorte que l'objectif d'écrasement est atteint. Par conséquent, même si cette propriété est définie sur NULL, cela signifie que la propriété existe déjà dans l'instance et que la propriété ne sera pas annulée, de sorte que la propriété correspondante du prototype est accessible.
Par conséquent, vous devez utiliser l'opérateur de suppression pour supprimer complètement les attributs d'instance afin que le prototype puisse être revisité.
Le prototype est dynamique et toutes les modifications apportées à l'objet prototype peuvent être immédiatement réfléchies à partir de l'instance. La raison en est la relation de liaison lâche entre l'instance et le prototype. Chaque fois que la méthode de propriété de l'instance est appelée, une requête sera réalisée. Si le prototype change, le résultat de la requête changera également.
Après avoir compris le prototype, nous pouvons également ajouter de nouvelles méthodes ou attributs à l'objet natif. Les types de référence natifs tels que l'objet, le tableau, la chaîne, etc. sont similaires aux constructeurs ci-dessus. Nous pouvons utiliser le prototype pour étendre leurs méthodes. Par exemple:
String.prototype.startswith = function (text) {return this.indexof (text) == 0;}; var msg = "Hello World"; msg.startswith ("Bonjour");Ce code ajoute une méthode startSwith à la chaîne de type de référence native, qui doit passer dans un paramètre pour voir si la chaîne à tester commence par un paramètre. En raison de la nature dynamique du prototype, toutes les variables du type de chaîne obtiennent cette méthode en l'exécutant.
Cependant, cette méthode n'est pas recommandée. Si vous utilisez trop et trop de code, cela entraînera des difficultés de maintenance, une confusion dans le code, etc. De manière générale, un type de référence natif sera hérité d'abord, puis créé sur un type nouvellement personnalisé. En ce qui concerne l'héritage, nous le résumerons plus tard.
Le motif prototype n'est pas non plus omnipotent. Tous les attributs et méthodes du prototype sont partagés par toutes les instances, il est donc très adapté aux fonctions et à d'autres fonctions, mais pour les attributs contenant des types de référence, certains conflits surviendront. Par exemple:
fonction personne () {} personne.prototype = {constructeur: personne, amis: ["greg", "jack"]}; var person1 = new Person (); var person2 = new Person (); person1.friends.push ("tom"); console.log (Person2.friends);Vous verrez dans Console qu'il y a un tom supplémentaire pour les amis de Person2, ce qui n'est pas ce que je veux, mais lors de la définition de son ami à Person1, cela affecte l'instance Person2.
Nous devons donc l'utiliser en combinaison avec le motif prototype et le modèle de constructeur.
Utilisez le mode constructeur et le mode prototype en combinaison
Il s'agit du modèle le plus couramment utilisé. Le constructeur est utilisé pour définir les propriétés d'instance et personnaliser en passant par des paramètres; Le prototype est utilisé pour définir des méthodes ou des attributs qui nécessitent un partage entre toutes les instances. De cette façon, la personnalisation est obtenue, le partage est assuré et les problèmes sont évités.
Personne de fonction (nom, âge, travail) {this.name = name; this.age = âge; this.job = job; this.friends = ["greg", "jack"];} personne.prototype = {constructeur: personne, SayName: function () {alert (this.name); }}; var jiangsUi = new personne ("jiangshi", "22", "ingénieur");Exemples d'application pratiques
OK, ici vous pouvez comprendre ce qu'est le prototype et comment créer des objets, mais quelles sont les utilisations? En effet, mon travail précédent était simplement d'écrire du code en utilisant jQuery, et je ne pouvais pas utiliser l'encapsulation et puis générer des objets pour implémenter des fonctions, etc. Alors, quelles sont les utilisations?
Cette méthode de développement est principalement utilisée pour le développement modulaire et d'assemblage. Par exemple, la fonction pop-up que vous utilisez souvent, bien sûr, vous pouvez coller et copier le code contextuel à chaque fois, puis le modifier et l'utiliser dans le projet. Un meilleur choix consiste à résumer abstraitement votre code de fonction pop-up dans un tel composant, de sorte que lorsque vous avez besoin d'utiliser des fenêtres contextuelles, vous n'avez qu'à transmettre des paramètres pour générer une instance pop-up et vous pouvez l'appeler.
Prototype d'objets et de chaînes prototypes
Dans JavaScript, tout est un objet, mais il existe également des différences dans les objets. Il peut être à peu près divisé en deux catégories, à savoir: objets ordinaires (objet) et objets de fonction (fonction).
D'une manière générale, les objets générés par la nouvelle fonction sont des objets de fonction, et d'autres objets sont des objets ordinaires.
Donnez un exemple:
Fonction f1 () {// TODO} var f2 = fonction () {// TODO}; var f3 = new function ('x', 'console.log (x)'); var o1 = {}; var o2 = nouvel objet (); var o3 = new f1 (); Console.log (typeof f1, // Fonction Typeof F2, // Fonction Typeof F3, // Type de fonction O1, // Type d'objet O2, // Type d'objet O3 // Objet); >> Fonction Fonction Fonction Objet Objet Objet Objet ObjetF1 appartient à la déclaration d'une fonction. La façon la plus courante de définir une fonction est que F2 est en fait une fonction anonyme. Attribuez cette fonction anonyme à F2, qui appartient à une expression de fonction. F3 n'est pas courant, mais c'est aussi un objet de fonction.
La fonction est un objet qui vient avec JS. Lorsque F1 et F2 sont créés, JS créera automatiquement ces objets via une nouvelle fonction (). Par conséquent, ces trois objets sont créés via une nouvelle fonction ().
Il existe deux façons de créer des objets dans JavaScript: les littéraux d'objets et les nouvelles expressions. La création d'O1 et d'O2 correspond simplement à ces deux manières. Concentrons-nous sur O3. Si vous utilisez les idées de Java et C # pour comprendre, O3 est un objet d'instance de F1, et O3 et F1 sont le même type. Au moins, je le pensais avant, mais ce n'est pas ...
Alors, comment le comprenez-vous? C'est très simple. Voir si O3 est généré via une nouvelle fonction. Évidemment pas. Puisqu'il n'est pas un objet de fonction, c'est un objet ordinaire.
Après une simple compréhension des objets de fonction et des objets ordinaires, apprenons les prototypes et les chaînes de prototypes en JavaScript:
Dans JS, chaque fois qu'un objet de fonction F1 est créé, certaines propriétés sont intégrées dans l'objet, y compris le prototype et __proto__, le prototype est l'objet Prototype, qui enregistre certaines propriétés et méthodes de F1.
Il convient de noter que le prototype est invisible pour F1, c'est-à-dire que F1 ne recherchera pas les propriétés et les méthodes dans le prototype.
fonction f () {} f.prototype.foo = "ABC"; console.log (f.foo); //indéfiniAlors, à quoi sert le prototype? En fait, la fonction principale du prototype est l'héritage. En termes de laïque, les propriétés et les méthodes définies dans le prototype sont toutes laissées à leurs "descendants", de sorte que les sous-classes peuvent accéder pleinement aux propriétés et méthodes du prototype.
Pour savoir comment F1 quitte les prototypes pour les "descendants", nous devons comprendre la chaîne de prototypes dans JS. À l'heure actuelle, le __proto__ en JS est entré sur le marché. Ce gars est très étrange et caché, de sorte que vous ne le voyez souvent pas, mais il existe à la fois dans les objets ordinaires et les objets de fonction. Sa fonction est d'enregistrer l'objet prototype de la classe parent. Lorsque JS crée un objet à travers une nouvelle expression, il attribue généralement le prototype de la classe parent à l'attribut __proto__ du nouvel objet, qui forme une génération de succession ...
fonction f () {} f.prototype.foo = "ABC"; var obj = new f (); console.log (obj.foo); //abcMaintenant, nous savons que __proto__ dans OBJ enregistre le prototype de F, alors qu'est-ce qui est enregistré dans __proto__ dans le prototype de F? Voir l'image suivante:
Comme le montre la figure, l'objet.prototype stocké dans le __proto__ de f.prototype, et il y a aussi __proto__ dans l'objet objet.prototype., Et d'après le résultat de sortie, object.prototype .__ Proto__ est nul, indiquant la fin du prototype d'objet OBJ. Comme indiqué dans la figure ci-dessous:
Une fois que l'objet OBJ a une telle chaîne de prototype, lorsque Obj.foo est exécuté, OBJ découvrira d'abord s'il a l'attribut, mais ne trouvera pas son propre prototype. Lorsque Foo ne peut être trouvé, OBJ recherchera à son tour la chaîne prototype ...
Dans l'exemple ci-dessus, nous définissons l'attribut FOO sur le prototype de F, puis OBJ trouvera cet attribut sur la chaîne prototype et l'exécutera.