Javascript changeant dynamiquement les objets. Travailler avec des objets en javascript - Utiliser des fonctions - Théorie et pratique. Vérification de l'existence des propriétés

Une visite sur une ressource Web est un URI spécifique dans la barre d'adresse du navigateur. Le visiteur indique l'adresse de la page, et elle est analysée par le navigateur en éléments de l'arborescence DOM - Document Object Model. Tout lien sur cette page indique au navigateur d'analyser une autre page et de créer une autre arborescence d'objets.

Le navigateur permet au visiteur de revenir en arrière ou d'avancer dans une chaîne de pages qui ont déjà été consultées dans la session en cours.

En fait, les actions des utilisateurs se déplacent entre les systèmes d'objets formés au cours du processus de visite des pages. Chaque page est son propre arbre DOM et, en plus, les objets JavaScript sont des objets de la syntaxe du langage lui-même et des descriptions personnalisées.

DOM : chargement, mise à jour et modification

Il existe trois options principales qui forment les objets de la page de ressources Web, à la fois au niveau du DOM et du langage JavaScript lui-même, qui ont exécuté les constructions pour créer des variables, et sur la base des descriptions faites par le développeur :

  • chargement - le visiteur est venu sur la page du site ;
  • mise à jour - visiteur (bouton du navigateur ou Ctrl-F5) ;
  • changer un élément de page, par exemple (AJAX, script, événement, ...).

Les trois processus sont fondamentalement différents, mais il est particulièrement important de distinguer les caractéristiques des deux premiers. Il est difficile d'empêcher un visiteur d'actualiser la page - il s'agit d'une dépendance inextricable du visiteur qu'un développeur doit garder à l'esprit.

La navigation autour de la page et au-delà doit résider exclusivement dans la fonctionnalité de la page elle-même, et non dans l'historique des visites du navigateur et les fonctions de ses boutons. De nombreux sites déclarent cette exigence importante, mais les visiteurs la violent traditionnellement.

Changer la page sans recharger au niveau de son élément individuel (par exemple, AJAX) est une solution courante pour les pages dynamiques. En règle générale, cela est utilisé pour naviguer dans les éléments de la page, changer ses objets, contrôler le dialogue avec le visiteur.

Objets JavaScript fondamentaux

JavaScript est basé sur les objets. Presque toutes les variables de langage sont des objets. Le développeur peut formuler ses propres descriptions d'objets en utilisant une variété de syntaxes.

Tout ce qui n'est pas une "chaîne", un "nombre", vrai, faux, nul ou indéfini est un objet. Dans le cadre de la syntaxe du langage, cela peut être ignoré, ne comprenant par les objets que les éléments DOM et les propres descriptions de l'objet JavaScript.La structure fondamentale du langage dans la plupart des cas pour le développeur n'a pas de valeur pratique significative.

Par exemple, les fonctions mathématiques sont représentées par l'objet Math. C'est pratique dans le cadre du concept du langage, mais pour le développeur c'est juste une syntaxe pratique pour utiliser l'arsenal nécessaire d'opérations mathématiques.

Il est important de travailler correctement avec le DOM et de décrire correctement vos propres objets. La syntaxe des fonctions d'objet JavaScript et des expressions pour les appliquer est une forme d'écriture de la logique de l'algorithme requis.

Chaînes, tableaux et objets

Tous les objets JavaScript sont basés sur la règle "property" = "value" et le concept de tableau associatif. Dans sa forme la plus simple, l'objet JavaScript est une collection de paires propriété = valeur. Dans ce cas, la "valeur" ne peut pas toujours être un nombre, et la propriété n'est pas toujours écrite sans guillemets.

Le nommage des propriétés ne doit pas être galvaudé. Idéalement, lorsque les noms de propriété contiennent uniquement des caractères latins, satisfont aux exigences de nommage des variables et ne sont pas des mots clés (y compris réservés) de la langue.

Aucun ordre de propriété n'est attendu, mais lors de la création ou de l'initialisation d'un tableau associatif, il est parfaitement acceptable de savoir comment ses éléments sont organisés. Il n'est pas recommandé d'utiliser cette circonstance, mais il est possible de la garder à l'esprit.

Initialiser un tableau de propriétés signifie à la fois :

  • créer un tableau ;
  • création d'objets.

Dans un contexte d'application spécifique, vous pouvez considérer un objet JavaScript - en tant que tableau associatif, et ailleurs dans l'algorithme - en tant qu'objet, lui affecter les méthodes nécessaires, modifier les valeurs de ses éléments.

Étant donné que les noms et les valeurs des propriétés doivent être spécifiés au format chaîne lors de leur création ou de leur modification, il est recommandé d'utiliser la notation en minuscules et les guillemets.

Accéder aux propriétés de l'objet

Vous pouvez obtenir et modifier les valeurs des propriétés des objets avec la construction Object.keys : JavaScript forme un tableau de toutes les propriétés des objets. Lorsque les objets sont créés dynamiquement, cette construction est très pratique, car elle génère automatiquement une liste de toutes les propriétés disponibles dans l'objet.

Dans cet exemple, la description des deux tableaux se fait de manière différente. A l'usage, les deux tableaux sont équivalents, car ils contiennent des propriétés du même nom et leurs valeurs. La boucle parcourt toutes les propriétés du deuxième tableau et forme une chaîne de toutes les valeurs.

Un effet similaire peut être obtenu avec la notation par points ou la notation entre crochets :

  • x1_Obj .NameLast;
  • x1_Obj ["NomPremier"].

Les deux constructions sont valables et donnent le résultat souhaité. Dans l'exemple donné, lors de la spécification d'un tableau entre accolades "()", une erreur peut être commise sous la forme du symbole "," à la fin de l'énumération (marquée dans l'exemple par un cercle rouge). Les navigateurs ignorent généralement le caractère supplémentaire dans l'énumération, mais il est préférable de ne pas le faire.

Suppression des propriétés de l'objet

Puisqu'un objet est un tableau associatif, l'opération L'objet de suppression JavaScript est exécuté au niveau de l'objet courant (en cas d'héritage - c'est important) et visualisé sur la collection de propriétés de cet objet.

Dans le contexte de l'exemple donné, vous pouvez utiliser les constructions suivantes :

  • supprimer x1_Obj .NameLast ;
  • supprimer x2_Obj ["NameFirst"] ;

La première construction supprime le deuxième élément du premier objet, la deuxième construction supprime le premier élément du deuxième objet. L'opérateur delete ne fonctionne pas sur les propriétés du prototype et renvoie false si la propriété ne peut pas être supprimée.

Propriétés et méthodes des objets

La syntaxe des propriétés et fonctions (méthodes) des objets JavaScript est similaire aux canons généraux de la syntaxe et de la sémantique du langage. En fait, le contraire est vrai.

Les propriétés et les méthodes des objets sont une variante de la description des informations et des actions autorisées via le paradigme JavaScript orienté objet.

Cet exemple décrit l'objet x3_Obj, qui n'a que deux propriétés : item et pos. Ensuite, la méthode hello () a été ajoutée en tant que fonction. En conséquence, l'interprétation de cette description dans le contexte des valeurs de propriété, les valeurs d'objet JavaScript feront comme indiqué dans la fenêtre de résultat, c'est-à-dire qu'elle placera le corps de la fonction (1) en tant que valeur.

Lorsque la propriété Hello() est appelée directement, elle est interprétée comme une méthode (fonction) et le résultat (2) sera l'exécution du code de cette méthode.

Le mot clé this dans un objet

Pour s'orienter dans l'espace des propriétés d'un objet, un développeur peut utiliser mot-clé this et se référer aux propriétés qu'il décrit pour obtenir ou modifier leurs valeurs.

Ce n'est que le début de la description d'un objet avec seulement un corps de constructeur. Cet exemple décrit un objet cookie. L'objet est initialisé au moment du chargement de la page avec la construction :

  • var oCookie = nouveau scCookies (cOwnerCode);
  • oCookie .Init ();

Dans cet exemple, le cOwnerCode est - code unique visiteur. Sinon, un nouveau code sera généré dans le constructeur de l'objet oCookie. Peu importe ce que le développeur de l'objet entendait par l'autorisation du visiteur, il est important de savoir comment le mot-clé this est utilisé ici pour décrire les méthodes de l'objet et pour les appeler à partir d'autres méthodes de l'objet :

  • ce .GetCookie = fonction (cName) (...) ;
  • ce .SetCookie = fonction (cName, cValue) (...).

C'est ainsi que sont décrites les méthodes de l'objet pour lire un cookie par son nom et écrire la valeur d'un cookie avec un nom spécifique.

  • ce .GetCookie ("cOwner");
  • ce .SetCookie ("cOwner", cOwner);

Donc, ils sont utilisés, si à la suite de la première construction la valeur ne sera pas présentée, alors la deuxième construction la définit.

Exemple d'objet cookie

Il est possible de discuter de l'objet et du paradigme orienté objet d'un langage fonctionnant dans un environnement de navigateur. C'est intéressant, mais la réalité est pratique, pas théorique. Servir le DOM d'une page, fournir une boîte à outils pour manipuler des objets et parcourir des objets systèmes est point fort JavaScript.

Dans la pratique orientée objet, autre chose est important. Travailler avec des cookies sur presque toutes les ressources Web est dans l'ordre des choses. L'implémenter dans un format objet est une excellente idée. Dans ce contexte, l'initialisation de l'objet se produit au moment de l'ouverture de la page : la page est chargée = l'objet cookie existe et tout a été lu, et ce qui n'a pas été créé.

Dans le processus de travail avec la page, le visiteur effectue certaines actions et le navigateur doit modifier ou créer des cookies. Il existe deux méthodes objet (décrites ci-dessus) qui font cela.

En fait, l'objet cookie apparaît immédiatement après que le navigateur a construit le DOM et ajoute une nouvelle fonctionnalité au système d'objets JavaScript : lire et créer (modifier) ​​le cookie.

Sur ce exemple simple est considérée comme une procédure de création d'objets réels qui ont exclusivement leurs propres propriétés et fonctionnalités (méthodes). Chaque objet fait son travail et ne participe pas à l'algorithme général, ne modifie pas les données des autres objets ou l'espace de noms général.

Avec cette approche, le développeur assure la création d'un système d'objets uniques suffisant pour décrire et maintenir le problème en cours de résolution.

Événements de page et d'objet

Un élément important du fonctionnement du DOM et de JavaScript : l'objet événement "s - permet d'obtenir des informations sur un événement dans son gestionnaire. Presque chaque élément de la page peut se voir attribuer son propre gestionnaire pour un ou plusieurs événements.

En fait, un développeur JavaScript ne crée pas un seul gros « morceau » de code, mais de nombreuses descriptions de fonctions, d'objets, de structures de données et attribue des gestionnaires d'événements à des éléments de page spécifiques.

L'événement d'objet est une information sur l'événement qui a provoqué le gestionnaire et la capacité de ce gestionnaire à effectuer une réponse adéquate à cet événement. Chaque événement diffère non seulement par le nom et le lieu d'occurrence, mais également par de nombreux autres paramètres.

En particulier, les événements de clavier sont un ensemble de paramètres, les événements de souris sont une plage de données complètement différente et la réponse du serveur via AJAX est entièrement planifiée par le développeur lui-même.

Dans chaque cas spécifique, l'image des événements susceptibles de se produire sur la page est transformée en une gamme de gestionnaires inclus ; en dehors des options fournies pour traiter un ensemble spécifique d'événements, la page n'entreprend aucune action.

Création et exploitation d'objets

Le navigateur "transforme" l'URI, l'adresse de la ressource Web spécifiée par le visiteur, en une arborescence DOM - le système d'objets de page de cette ressource Web. Lorsqu'un visiteur parcourt les liens d'une page, le navigateur accède aux arborescences correspondantes des autres pages.

Cette circonstance permet au développeur de construire son propre système d'objets comme base d'une ressource Web qui répond de manière adéquate au comportement du visiteur. Si nous distinguons la fonctionnalité générale, par exemple :

  • travailler avec des cookies ;
  • recevoir/transmettre des données (AJAX) ;
  • conseils contextuels ;
  • messages internes (chat du site) ;
  • autres tâches;

une fois créés, les systèmes objets peuvent être utilisés pour développer d'autres sites. C'est un avantage significatif de l'approche objet par rapport à l'utilisation habituelle de JavaScript comme langage de navigateur qui assure le fonctionnement de la page et la réaction aux événements.

Les objets sont des composants complets qui peuvent être stylisés comme fichiers individuels et l'utiliser à l'avenir. Une caractéristique de cette approche est la possibilité de retour d'informations, lorsqu'un objet mis à jour et amélioré peut être utilisé dans un développement précédent, mettant automatiquement à jour ses fonctionnalités sans modifier le site.

La tâche :

1. Il y a trois objets (trois voitures): première voiture, seconde_Voiture et troisième_Voiture.

2. Chacun des objets (voitures) a un ensemble de propriétés et leurs valeurs correspondantes (caractéristiques du véhicule).

3. Considérez l'un des objets :

var first_Car = (
faire : "VAZ",
/* fabricant */
modèle : 2106,
/ * maquette * /
année : 1980,
/* année d'émission */
couleur beige",
/* Couleur */
passagers : 5,
/ * nombre de passagers * /
cabriolet : faux,
/ * capote cabriolet * /
kilométrage: 80000
/* kilométrage */
}

Propriétés Fabriquer et Couleur avoir des valeurs de chaîne ;

Propriétés maquette, année, passagers et kilométrage- valeurs numériques ;

Biens convertible prend une valeur booléenne.

Vous devez faire ce qui suit:

Écrire une fonction qui vérifie la voiture par deux paramètres (année de fabrication et kilométrage) et renvoie une valeur booléenne vrai ou alors faux.

Détails:

1. La fonction a un paramètre auto, en qualité de laquelle il reçoit l'un des 3 objets. Par exemple, la voiture discutée ci-dessus première voiture.

2. La fonction doit fonctionner avec n'importe quel objet similaire.

Fonction de vérification d'un objet - vrai ou faux

Commentaires sur la solution :

  • On a donc trois objets (trois voitures), chacun pouvant être analysé à l'aide de la fonction bonne_Voiture.
  • Une fonction bon_voiture a un paramètre auto, qui peut être n'importe lequel des objets (voitures): première voiture, seconde_Voiture ou alors troisième_Voiture: fonction good_Car (voiture) .
  • Dans les fonctions du corps bonne_Voiture une condition a été établie selon laquelle :

    Si la valeur de la propriété année objet auto moins de 2000 (autrement dit : si l'année de fabrication de la voiture est inférieure à 2000), alors la fonction renvoie faux;

    Sinon, si la valeur de la propriété kilométrage objet auto plus de 50 000 (si le kilométrage de la voiture est supérieur à 50 000), alors la fonction renvoie faux;

    Sinon, la fonction renvoie vrai.

  • Ensuite, nous appelons la fonction et spécifions l'objet en tant que paramètre troisième_Voiture(troisième voiture) qui réussit le test. Le résultat de la fonction est stocké dans une variable résultat:
    var result = good_Car (third_Car); .
  • Variable résultat affiché à l'écran;
  • Deux autres objets (auto) ne satisfera pas aux exigences de la condition.

Optimiser votre code

Nous allons continuer travailler avec des objets en javascript.

Ainsi, la fonction ci-dessus lors de la vérification des objets (voitures) donne comme résultat vrai ou alors faux (vrai ou faux).

Il est possible d'améliorer légèrement la qualité de perception de la solution du problème considéré, c'est-à-dire au lieu de vrai ou alors faux afficher n'importe quel texte. Pour ce faire, nous allons créer une condition d'analyse du résultat.

Résultat Solution conditionnelle - Résultat ...

La condition d'analyse du résultat est composée comme suit.

  • Expression si (résultat) est une forme abrégée d'expression
    si (résultat == vrai) .
  • Si le résultat de la fonction bonne_Voiture est vrai vrai, puis nous affichons la phrase : « Vous avez une bonne voiture : 2012 année de fabrication, avec kilométrage 15000 km. ", où

    2012 et 15000 sont des valeurs de propriété année et kilométrage objet troisième_Voiture.

  • Si la condition de vérification du résultat retournera une valeur fausse faux, alors nous verrons : "Nous ne parlerons pas de votre voiture....". c'est-à-dire l'objet en question (voiture) vérification échouée.

Optimisation du code - Aller plus loin - Ajouter une fonction

Mais ce n'est pas tout. Examinez de près l'extrait de code pour appeler la fonction et analyser le résultat :

/ * Appel de la fonction et Analyse du résultat * /
var result = good_Car ( troisième_Voiture );

si (résultat) (
document.write ("Vous avez une belle voiture :" + third_Car .year + "année de fabrication, avec kilométrage" + third_Car .mileage + "km.");
}
autre (
document.write ("Ne parlons pas de votre voiture ....");
}

Ici l'objet troisième_Voiture (troisième voiture) est indiqué trois fois :

  • Premier appel d'une fonction bonne_Voiture il est spécifié en paramètre : good_Car (third_Car) .
  • Et puis il apparaît deux fois de plus quand on s'y réfère pour indiquer ses propriétés : troisième_Voiture.année et Third_Car.mileage .

Je n'ai pas aimé cela, car lors de l'analyse d'un autre objet (auto) nous aurons aussi son nom indiquer trois fois!!!

Pour obtenir une indication unique de l'objet analysé, vous avez également besoin du résultat de la fonction bonne_Voiture et analyse de ce résultat (c'est-à-dire l'ensemble) ajouter à une autre fonction.

Solution utilisant une fonction supplémentaire - Résultat ...

Vous avez une bonne voiture : 2012, avec 15 000 km de kilométrage.

Dernière mise à jour : 08.04.2018

La programmation orientée objet est l'un des paradigmes dominants dans le développement d'applications aujourd'hui, et en JavaScript, nous pouvons également tirer pleinement parti de la POO. Dans le même temps, la programmation orientée objet présente certaines particularités par rapport à JavaScript.

Objets

Dans les rubriques précédentes, nous avons travaillé avec des données primitives - nombres, chaînes, mais les données ne représentent pas toujours des types primitifs. Par exemple, si dans notre programme nous devons décrire l'essence d'une personne qui a un nom, un âge, un sexe, etc., alors naturellement nous ne pourrons pas représenter l'essence d'une personne sous la forme d'un nombre ou un string. Nous avons besoin de quelques lignes ou chiffres pour décrire correctement la personne. À cet égard, une personne agira comme une structure complexe complexe, qui aura des propriétés distinctes - âge, taille, nom, prénom, etc.

JavaScript utilise des objets pour travailler avec de telles structures. Chaque objet peut stocker des propriétés qui décrivent son état et des méthodes qui décrivent son comportement.

Création d'un nouvel objet

Il existe plusieurs façons de créer un nouvel objet.

La première consiste à utiliser le constructeur Object :

Var utilisateur = nouvel objet ();

Dans ce cas, l'objet est appelé utilisateur. Elle est définie comme n'importe quelle variable régulière à l'aide du mot-clé var.

L'expression new Object () représente un appel à un constructeur, une fonction qui crée un nouvel objet. L'opérateur new est utilisé pour appeler le constructeur. Appeler un constructeur revient en fait à appeler une fonction normale.

La deuxième façon de créer un objet consiste à utiliser des accolades :

Var utilisateur = ();

Aujourd'hui, la deuxième méthode est plus courante.

Propriétés de l'objet

Après avoir créé un objet, nous pouvons y définir des propriétés. Pour définir une propriété, vous devez spécifier le nom de la propriété après le nom de l'objet séparé par un point et lui affecter une valeur :

Var utilisateur = (); user.name = "Tom"; user.age = 26 ;

Dans ce cas, deux propriétés, name et age, sont déclarées et reçoivent les valeurs correspondantes. Après cela, nous pouvons utiliser ces propriétés, par exemple, afficher leurs valeurs dans la console :

Console.log (nom.utilisateur) ; console.log (user.age);

Vous pouvez également définir des propriétés lors de la définition d'un objet :

Var user = (nom : "Tom", âge : 26) ;

Dans ce cas, un deux-points est utilisé pour attribuer une valeur à une propriété et une virgule (plutôt qu'un point-virgule) est utilisée après la définition de la propriété.

De plus, une manière abrégée de définir les propriétés est disponible :

Nom de la variable = "Tom" ; âge variable = 34 ; var utilisateur = (nom, âge); console.log (nom.utilisateur); // Tom console.log (user.age); // 34

Dans ce cas, les noms des variables sont aussi les noms des propriétés de l'objet. Et de cette façon, vous pouvez créer des structures plus complexes :

Nom de la variable = "Tom" ; âge variable = 34 ; var utilisateur = (nom, âge); var professeur = (utilisateur, cours : "JavaScript"); console.log (enseignant.utilisateur); // (nom : "Tom", âge : 34) console.log (enseignant.cours); //JavaScript

Méthodes objet

Les méthodes d'un objet définissent son comportement ou les actions qu'il effectue. Les méthodes sont des fonctions. Par exemple, définissons une méthode qui afficherait le nom et l'âge d'une personne :

Var utilisateur = (); user.name = "Tom"; user.age = 26 ; user.display = function () (console.log (user.name); console.log (user.age);); // appelle la méthode user.display() ;

Comme pour les fonctions, les méthodes sont d'abord définies puis appelées.

De plus, les méthodes peuvent être définies directement lors de la définition d'un objet :

Var user = (nom : "Tom", âge : 26, affichage : fonction () (console.log (this.name); console.log (this.age);));

Comme pour les propriétés, une méthode se voit attribuer une référence de fonction à l'aide d'un caractère deux-points.

Pour faire référence aux propriétés ou aux méthodes d'un objet dans cet objet, utilisez le mot clé this. Cela signifie une référence à l'objet courant.

Vous pouvez également utiliser un raccourci pour définir des méthodes, lorsque les deux points et le mot fonction sont omis :

Var user = (nom : "Tom", age : 26, display () (console.log (this.name, this.age);), move (place) (console.log (this.name, "goes to" , endroit);)); user.display (); // Tom 26 user.move ("la boutique"); // Tom va au magasin

Syntaxe du tableau

Il existe également un autre moyen de définir des propriétés et des méthodes à l'aide de la syntaxe de tableau :

Var utilisateur = (); utilisateur ["nom"] = "Tom"; utilisateur ["âge"] = 26 ; user ["display"] = function () (console.log (user.name); console.log (user.age);); // appelle la méthode user ["display"] ();

Chaque nom de propriété ou de méthode est placé entre guillemets et entre crochets, puis une valeur est également affectée. Par exemple, l'utilisateur ["age"] = 26.

Lorsque vous faites référence à ces propriétés et méthodes, vous pouvez utiliser soit la notation par points (user.name), soit vous pouvez vous référer à ceci : user ["name"]

Les chaînes en tant que propriétés et méthodes

Il convient également de noter que les noms de propriétés et de méthodes d'un objet sont toujours des chaînes. C'est-à-dire que nous pourrions réécrire la définition précédente d'un objet comme suit :

Var user = ("name": "Tom", "age": 26, "display": function () (console.log (user.name); console.log (user.age);)); // appelle la méthode user.display() ;

D'une part, il n'y a pas de différence entre les deux définitions. D'un autre côté, il existe des cas où l'emballage de chaîne peut aider. Par exemple, si un nom de propriété se compose de deux mots séparés par un espace :

Var user = (nom : "Tom", age : 26, "full name": "Tom Johns", "display info": function () (console.log (user.name); console.log (user.age) ;)); console.log (utilisateur ["nom complet"]); utilisateur ["afficher les informations"] ();

Seulement dans ce cas, pour faire référence à de telles propriétés et méthodes, nous devons utiliser la syntaxe des tableaux.

Supprimer des propriétés

Ci-dessus, nous avons vu comment ajouter dynamiquement de nouvelles propriétés à un objet. Cependant, nous pouvons également supprimer des propriétés et des méthodes à l'aide de l'opérateur delete. Et tout comme pour l'ajout, nous pouvons supprimer des propriétés de deux manières. La première consiste à utiliser la notation par points :

Supprimer object.property

Ou utilisez la syntaxe du tableau :

Supprimer l'objet ["propriété"]

Par exemple, supprimons la propriété :

Var utilisateur = (); user.name = "Tom"; user.age = 26 ; user.display = function () (console.log (user.name); console.log (user.age);); console.log (nom.utilisateur); // Tom delete user.name; // supprimer la propriété // option alternative // ​​supprimer l'utilisateur ["nom"]; console.log (nom.utilisateur); // indéfini

Après la suppression, la propriété sera indéfinie, donc lorsque vous essayez d'y accéder, le programme retournera indéfini.

Dans cet article, je veux parler de manière aussi complète et cohérente que possible de ce qu'est un objet en JavaScript, de ses capacités, des relations qui peuvent être construites entre les objets et des méthodes d'héritage "natif" qui en découlent, comment tout cela affecte performances et qu'est-ce que tout cela :)

L'article ne dira PAS un mot sur : l'émulation du paradigme classe-objet traditionnel, le sucre syntaxique, les wrappers et les frameworks.

La complexité du matériel augmentera du début à la fin de l'article, donc pour les pros les premières parties peuvent sembler ennuyeuses et triviales, mais plus loin ce sera beaucoup plus intéressant :)

Objets en JavaScript

De nombreux articles contiennent la phrase "En JavaScript, tout est un objet". Techniquement, ce n'est pas tout à fait vrai, mais cela fait bonne impression sur les débutants :)

En effet, une grande partie d'un langage est un objet, et même ce qui n'est pas un objet peut avoir certaines de ses capacités.

Il est important de comprendre que le mot "objet" n'est pas utilisé ici dans le sens d'"un objet d'une certaine classe". Un objet en JavaScript n'est avant tout qu'une collection de propriétés (si c'est plus facile pour quelqu'un, vous pouvez l'appeler un tableau associatif ou une liste), constituée de paires clé-valeur. De plus, la clé ne peut être qu'une chaîne (même pour les éléments de tableau), mais la valeur peut être n'importe quel type de données répertorié ci-dessous.

Il y en a donc 6 en JavaScript types de base les données sont non définies (sans valeur), Null, Boolean (booléen), String (string), Number (nombre) et Object (objet).
De plus, les 5 premiers sont primitif types de données, mais pas Object. De plus, on peut supposer conditionnellement que le type Object a des "sous-types": un tableau (Array), une fonction (Function), une expression régulière (RegExp), et d'autres.
Il s'agit d'une description quelque peu simplifiée, mais en pratique, elle est généralement suffisante.

De plus, les types primitifs String, Number et Boolean sont associés d'une certaine manière aux "sous-types" non primitifs d'Object : String, Number et Boolean, respectivement.
Cela signifie que la chaîne "Hello, world", par exemple, peut être créée à la fois comme valeur primitive et comme objet String.
En bref, cela est fait pour que le programmeur puisse utiliser des méthodes et des propriétés lorsqu'il travaille avec des valeurs primitives comme s'il s'agissait d'objets. Vous pouvez en savoir plus à ce sujet dans la section correspondante de cet article.

Travail par référence

Un lien est un moyen d'accéder à un objet sous différents noms. Le travail avec tous les objets est effectué exclusivement par référence.
Démontrons cela avec un exemple :
essai = fonction () (alerte ("Bonjour !")) // Créer une fonction (alerte ("Bonjour!")) (Et la fonction, on s'en souvient, est un objet à part entière) et faire de la variable de test une référence à celle-ci
test_link = test; // test_link fait désormais également référence à notre fonction
test (); // Bonjour!
test_link (); // Bonjour!


Comme on peut le voir, le premier lien et le second donnent le même résultat.
Il est nécessaire de réaliser que nous n'avons aucune fonction nommée test, et que la variable de test n'est pas une sorte de lien "principal" ou "principal", et que "test_link" est mineur.

Notre fonction, comme tout autre objet, n'est qu'une zone en mémoire, et toutes les références à cette zone sont absolument équivalentes. De plus, un objet peut n'avoir aucune référence - dans ce cas, il est dit anonyme, et ne peut être utilisé qu'immédiatement après sa création (par exemple, passé à une fonction), sinon il sera impossible d'y accéder et bientôt il sera détruit par le ramasse-miettes (garbage collection), qui supprime les objets sans références.

Voyons pourquoi il est si important de comprendre ceci :

test = (accessoire : "Du texte") // Crée un objet avec une propriété prop
test_link = test; // Créer un autre lien vers cet objet

Alerte (test.prop) ; // Du texte

// Changer la propriété de l'objet
test_link.prop = "nouveau texte";

Alerte (test.prop) ; // nouveau texte
alerte (test_link.prop); // nouveau texte
/ * On pourrait dire que la propriété a changé ici et là - mais ce n'est pas le cas.
L'objet est un. La propriété a donc changé une fois dedans, et les liens continuent de pointer là où ils pointent. * /

// Ajoute une nouvelle propriété et supprime l'ancienne
test.new_prop = "bonjour";
supprimer test.prop;

Alerte (test_link.prop); // non défini - cette propriété n'existe plus
alerte (test_link.new_prop);

// Supprimer le lien
supprimer le test ;
alerte (test.new_prop);
/ * A ce stade, le script lèvera une erreur, car test n'existe plus, et test.new_prop n'existe d'autant plus * /
alerte (test_link.new_prop); // Bonjour
/ * mais ici tout est en ordre, car nous n'avons pas supprimé l'objet lui-même, mais seulement un lien vers celui-ci. Maintenant, notre objet est pointé par un seul lien test_link * /

// Créer un nouvel objet
test = test_link; // Tout d'abord, créez à nouveau le lien de test
test_link = (prop: "un texte") // Et voici le nouvel objet

Alerte (test_link.prop); // Du texte
alerte (test.prop) ; // indéfini
/ * La création d'un nouvel objet rompt le lien, et maintenant test et test_link pointent vers différents objets.
En fait, cela revient à supprimer le test_link et à le recréer, mais pointant déjà vers un autre objet */
alerte (test.new_prop); // bonjour - maintenant test contient un lien vers notre tout premier objet


* Ce code source a été mis en évidence avec Source Code Highlighter.

Ce comportement des objets soulève souvent beaucoup de questions pour les développeurs novices, j'espère donc que ce texte apportera un peu de clarté. Si nous voulons créer une copie vraiment nouvelle et indépendante de l'objet, et non un lien, alors la seule façon de le faire est de créer un nouvel objet et d'y copier les propriétés requises.

Il convient également de noter que travailler avec des objets par référence, en plus des effets amusants mentionnés ci-dessus, permet également d'importantes économies de mémoire, ce qui est important lorsqu'un objet est largement utilisé à divers endroits du programme.

Valeurs primitives

Comme je l'ai mentionné ci-dessus, les types de données String et Number peuvent être à la fois des objets et des valeurs primitives.
obj = nouvelle chaîne ("bonjour"); // Créer une chaîne en tant qu'objet
simple = "bonjour" ; // Crée une valeur primitive

Alerte (obj) ; // Bonjour
alerte (simple); // bonjour - jusqu'ici tout est prévisible

Alerte (obj.length); // 6 - un objet de type String a une propriété length qui stocke la longueur de la chaîne
alerte (simple.longueur); // 6
/ * Bien que simple ne soit pas un objet, nous pouvons accéder au même ensemble de propriétés qu'un objet String. C'est assez pratique * /

Obj.prop = "texte";
simple.prop = "texte";

Alerte (obj.prop) ; // text - puisque obj est un objet ordinaire, alors nous pouvons facilement lui donner une propriété supplémentaire
alerte (simple.prop); // non défini - mais simple n'est pas un objet, et ce nombre ne fonctionnera pas pour nous

* Ce code source a été mis en évidence avec Source Code Highlighter.


La même chose est vraie pour le nombre et le booléen (enfin, outre le fait qu'ils n'ont pas de propriété de longueur, mais il existe un certain nombre d'autres propriétés merveilleuses).
L'utilisation de chaînes et de nombres comme objets n'a aucune utilité pratique. les valeurs primitives sont plus pratiques à utiliser, mais conservent en même temps toutes les fonctionnalités nécessaires. Cependant, dans un souci d'exhaustivité, il est nécessaire de comprendre ce mécanisme.

Ne confondez pas l'utilisation de valeurs primitives avec l'utilisation de littéraux - par exemple, que nous créions un tableau en tant que "test = new Array ()" ou en tant que "test =", le résultat sera toujours le même objet . Nous n'obtiendrons aucune valeur primitive.

Créer et utiliser des objets

Ainsi, contrairement aux langages où le paradigme classe-objet est implémenté, nous n'avons pas besoin de créer d'abord une classe, afin de créer un objet de la classe plus tard. Nous pouvons immédiatement créer un objet, ce que nous ferons dans l'exemple suivant :
essai = (
simple_property : "Bonjour",
propriété_objet : (
user_1 : "Petya",
user_2 : "Vasya"
},
function_property : fonction (utilisateur) (
alert (ce .simple_property + "," + ce .object_property);
}
}

Test.function_property ("user_1"); // Bonjour, Petya.

* Ce code source a été mis en évidence avec Source Code Highlighter.


Devant nous se trouve l'objet de test, qui possède 3 propriétés, dont les noms, j'espère, parlent d'eux-mêmes. Ce qui nous intéresse le plus, c'est la propriété function_property, qui contient la fonction. Une telle fonction peut être appelée une méthode d'un objet.

Notre fonction utilise deux fois le mot-clé this, qui est un pointeur (c'est-à-dire une référence) vers l'objet à partir duquel la fonction est appelée. Ainsi, this.simple_property = test.simple_property = "Bonjour", et this.object_property = test.object_property = "Petya".

Il faut bien comprendre qu'il s'agit toujours de l'objet à partir duquel la fonction est appelée, et non de l'objet auquel elle appartient. Bien que dans cet exemple il s'agisse du même objet, ce n'est pas toujours le cas.

test.function_property ("user_1"); // Bonjour, Petya.

Test2 = nouvel objet (); // Une autre forme de création d'un nouvel objet, similaire à test2 = ()

Test.function_property.call (test2, "user_1"); //erreur
/ * La méthode call permet d'appeler une fonction pour le compte d'un autre objet. Dans ce cas, nous appelons la méthode function_property de l'objet de test, et cela ne pointe plus vers l'objet de test, mais vers l'objet test2. Et depuis il n'y a pas de propriété object_property, alors lorsque vous essayez d'obtenir this.object_property, le script donnera une erreur * /

// essaie de corriger la situation
test2.simple_property = "Bonne journée";
test2.object_property = test.object_property; // Dans ce cas, on utilisera l'indication de l'objet par référence afin de ne pas dupliquer le code

Test.function_property.call (test2, "user_1"); // Bonne journée, Petya.


* Ce code source a été mis en évidence avec Source Code Highlighter.

Il devrait également être clair à partir de l'exemple qu'il n'y a pas d'étapes claires pour créer et utiliser un objet. L'objet peut être modifié de quelque manière que ce soit à tout moment - avant, après et même pendant l'utilisation. C'est également une différence importante par rapport à la POO "traditionnelle".

Constructeur

Dans l'exemple ci-dessus, nous avons créé 2 objets qui présentent des similitudes. Les propriétés simple_property et object_property étaient présentes. De toute évidence, lors de l'écriture de code réel, la tâche de créer des objets identiques ou simplement similaires se pose souvent. Et bien sûr, nous n'avons pas à créer manuellement tous ces objets.

Un constructeur viendra à notre secours. Un constructeur en JavaScript ne fait pas partie d'une classe (car il n'y a pas de classes), mais juste une fonction à part entière. La fonction la plus courante.

fais_moi = fonction (_name) (
alerte ("J'ai été lancé");
ce .name = _name;

}


/ * Voyons ce qui se passe ici. L'interprète voit le nouvel opérateur et vérifie ce qui se trouve à sa droite. Parce que make_me est une fonction, et il peut être utilisé comme constructeur, puis un nouvel objet est créé en mémoire et la fonction make_me est exécutée, et son this pointe vers ce nouvel objet. Ensuite, nous ajoutons la propriété name à cet objet, qui reçoit la valeur de l'argument _name, et la méthode show_name. Aussi (je ne sais pas à quel moment, mais ça n'a pas d'importance) la variable enfant commence à pointer vers notre nouvel objet qui vient de naître * /

Alerte (nom.enfant) ; //Vasya
child.show_name (); //Vasya


child2.show_name (); //Pierre

Child2.show_name = function () (alerte ( "Je ne dirai pas mon nom");} // N'oubliez pas que nous pouvons changer nos objets à tout moment
child2.show_name (); // je ne dirai pas mon nom

Child.show_name (); // Vasya - les enfants ne s'influencent en aucune façon


* Ce code source a été mis en évidence avec Source Code Highlighter.

Vous pouvez également comparer le constructeur à un père - il donne naissance à un enfant, le dotant de certaines qualités, mais immédiatement après la création, l'enfant devient complètement indépendant du parent et peut devenir très différent de ses frères.
Si nous rappelons la description des types de données au début de l'article, alors il devient clair que Object et ses sous-types (Function, Array et autres) sont en fait des constructeurs qui donnent à l'objet créé les capacités d'une fonction, d'un tableau, etc.

Donc c'est beaucoup mieux. Nous avons maintenant la possibilité de créer des objets selon un certain modèle. Cependant, tout ne va pas bien. Premièrement, chaque objet que nous créons et toutes ses propriétés et méthodes occupent une place distincte dans la mémoire, bien qu'à bien des égards, ils soient répétés. Deuxièmement, que se passe-t-il si nous voulons maintenir la connexion entre le parent et l'enfant et pouvoir modifier tous les objets enfants à la fois. Un prototype viendra à notre secours.

Prototype

Tout comme chaque enfant a un père et une mère (au moins biologiquement), il en va de même pour chaque objet en JavaScript. Et si le père, comme nous l'avons décidé, travaille comme designer, alors la mère n'est qu'un prototype. Voyons comment cela se passe :
fais_moi = fonction (_name) (
alerte ("J'ai été lancé");
ce .name = _name;
this .show_name = function () (alerte (ce .name);)
}
/*
En voyant le mot-clé de fonction, l'interpréteur vérifie le code à sa droite, et puisque all ok - crée un nouvel objet en mémoire, qui est également notre fonction. Ensuite, automatiquement (sans la participation du programmeur) une propriété prototype est créée pour cette fonction, qui fait référence à un objet vide. Si nous le faisions manuellement, cela ressemblerait à make_me.prototype = new Object ();

Ensuite, l'objet donné (pointé par la propriété prototype) est également automatiquement ajouté avec une propriété constructeur pointant vers la fonction. Il s'avère qu'un tel lien cyclique.

Or cet objet, qui peut être décrit comme (constructeur : ... voici une référence à la fonction ...) - est le prototype de la fonction.
*/

// L'objet est bien un objet
alerte (type de make_me.prototype.constructor); // La fonction est notre fonction
alerte (make_me.prototype.constructor === make_me); // vrai

// Ajout d'une nouvelle méthode au prototype de la fonction make_me

Enfant = nouveau make_me ("Vasya"); // ils m'ont lancé
/ * Maintenant, en plus de tout ce qui est décrit dans l'exemple précédent, une propriété cachée supplémentaire [] est créée dans l'objet enfant, qui pointe vers le même objet que make_me.prototype. Parce que la propriété est cachée, nous ne pouvons ni voir sa valeur ni la modifier - cependant, elle joue un rôle important dans les travaux ultérieurs * /

Alerte (nom.enfant) ; //Vasya
child.show_name (); //Vasya

Child.set_name ("Kolya");
/ * Tout d'abord, l'interpréteur recherche la méthode set_name sur l'objet enfant. Puisqu'il n'est pas là, il continue à rechercher l'enfant.[] Property, le trouve là et l'exécute. * /
child.show_name (); // Kolya - maintenant le nom de Vasya est Kolya :)

Make_me.prototype.show_name2 = function () (alerte ("Bonjour," + ce .nom ;) //T.k. le prototype est un objet ordinaire, on peut aussi le changer à la volée

Child2 = nouveau make_me ("Petya");
child2.show_name2 (); // Bonjour, Petya
child.show_name2 (); // Salut Kolya - les changements dans le prototype affectent non seulement les objets nouvellement créés, mais aussi tous les anciens

Child2.show_name2 = function () (alerte ( "Je ne dirai pas mon nom");} // Nous pouvons toujours modifier l'objet lui-même, tandis que la nouvelle méthode show_name2 dans cet objet (et uniquement dans celui-ci) "écrasera" pour ainsi dire l'ancienne méthode du prototype
child2.show_name2 (); // Je ne dirai pas mon nom - parce que nous avons maintenant notre propre méthode show_name2, puis elle est appelée et aucune recherche dans le prototype n'a lieu

Child.show_name2 (); // Bonjour, Kolya - tout est toujours là

Make_me.prototype = (prop: "bonjour") // Essayons de recréer le prototype à nouveau

Alerte (child.prop) ; // indéfini
child.show_name2 (); //Bonjour Kolia
/ * Si vous vous souvenez de ce qu'est le travail par référence, alors tout est clair. Recréer le prototype rompt la connexion, et maintenant la propriété [] des objets enfant et enfant2 pointe vers un objet (qui était le prototype de la fonction make_me), et la propriété make_me.prototype vers un autre objet, qui est le nouveau prototype de la fonction make_me * /

Child3 = nouveau make_me ("Oleg");
alerte (child3.prop); // bonjour - comme prévu


* Ce code source a été mis en évidence avec Source Code Highlighter.

Comme le montre l'exemple, tant que le père reste fidèle à la mère (c'est-à-dire tant que le prototype de la fonction reste le même), tous les enfants dépendent de la mère et sont sensibles à tous ses changements. Cependant, dès que les parents divorcent (le concepteur change le prototype en un autre), les enfants se dispersent immédiatement qui où et il n'y a plus de lien avec eux.

Un peu de terminologie
Jusqu'à ce que la connexion primaire entre le constructeur et le prototype soit rompue, nous pouvons observer l'image suivante :

fais_moi = fonction (_name) (
alerte ("J'ai été lancé");
ce .name = _name;
this .show_name = function () (alerte (ce .name);)
}

Make_me.prototype.set_name = fonction (_name) (ce .name = _name ;)
enfant = nouveau make_me ("Vasya");

Alerte (type de make_me.prototype); // objet - la fonction a une propriété prototype
alerte (typed'enfant.prototype); // non défini - l'objet créé n'a AUCUNE propriété de prototype
alerte (child.constructor.prototype === make_me.prototype); // true - mais l'objet a une propriété constructeur, qui pointe vers la fonction constructeur make_me, qui, à son tour, a une propriété prototype


* Ce code source a été mis en évidence avec Source Code Highlighter.

Comme je l'ai remarqué après avoir lu de nombreux forums sur ce sujet, les principaux problèmes rencontrés par les gens lorsqu'ils confondent la propriété prototype d'une fonction et la propriété cachée [] d'un objet créé avec cette fonction.
Ces deux propriétés sont une référence au même objet (tant que la connexion primaire du prototype avec le constructeur n'est pas rompue), mais ce sont néanmoins des propriétés différentes, avec des noms différents, l'une d'elles est disponible pour le programmeur, et l'autre ne l'est pas.

Il est toujours nécessaire de bien comprendre que si nous parlons du prototype d'un constructeur, alors il s'agit toujours de la propriété prototype, et s'il s'agit du prototype de l'objet créé, alors il s'agit d'une propriété cachée [].

Héritage

Nous savons maintenant que chaque objet a une référence de prototype cachée et que chaque prototype est un objet normal.
Les lecteurs les plus perspicaces ont déjà senti l'odeur de la récursivité :)
En effet, depuis un prototype est un objet ordinaire, alors il a à son tour un lien avec son prototype, et ainsi de suite. C'est ainsi que la hiérarchie des prototypes est implémentée.
oiseau = une fonction () () // Ceci est le constructeur de l'oiseau
bird.prototype.cry = function () (alerte ("Crie!");) // L'oiseau peut crier
bird.prototype.fly = function () (alerte ("Je vole!");) // et vole

Canard = fonction () ()
canard.prototype = nouvel oiseau ();
canard.prototype.cry = fonction () (alerte ("Quack couac!");) // Le canard crie différemment
canard.prototype.constructor = canard; // Force la propriété prototype.constructor à être définie sur duck, car sinon il fera référence à l'oiseau

Billy = nouveau canard (); // Billy est notre canard
billy.fly (); //Je vole! - Billy peut voler parce que c'est un oiseau
billy.cry (); //Coin coin! - Billy crie charlatan parce que c'est un canard


* Ce code source a été mis en évidence avec Source Code Highlighter.

C'est ainsi que vous pouvez implémenter une hiérarchie de n'importe quel niveau d'imbrication.

Problème d'astérisque

Maintenant, puisque nous en savons tellement sur tout cela, essayons de comprendre ce qui se passe dans ces trois lignes.
fais_moi = une fonction () ()
enfant = nouveau make_me ();
alerte (child.toString ()); // les sorties

* Ce code source a été mis en évidence avec Source Code Highlighter.

Sur la première ligne, nous créons une nouvelle fonction et une variable make_me qui pointe vers cette fonction. Cela crée un prototype pour la fonction, make_me.prototype, qui contient une propriété de constructeur pointant vers make_me.
Mais ce n'est pas tout :)
Parce que la fonction make_me est aussi un objet, alors elle a à son tour un papa et une maman, c'est-à-dire constructeur et prototype. Son constructeur est une fonction native du langage Function() et son prototype est un objet contenant des méthodes call, apply, etc. - c'est grâce à ce prototype que l'on peut utiliser ces méthodes dans n'importe quelle fonction. Cela donne à la fonction make_me une propriété [] qui pointe vers Function.prototype.

À son tour, le prototype du constructeur Function est également un objet, dont le constructeur est (surprise !) Object (c'est-à-dire Function.prototype. []. Constructor === Object), et le prototype est un objet contenant les propriétés standard et les méthodes de l'objet, telles que toString, hasOwnProperty et autres (en d'autres termes - Function.prototype. [] ["hasOwnProperty"] - c'est exactement la même méthode que nous pouvons utiliser dans tous les objets dérivés - et c'est exactement le propre méthode de cet objet, et non hérité ). De cette manière intéressante, nous constatons que toutes sortes d'objets sont dérivés d'Objet.

Pouvons-nous continuer plus loin ? Il s'avère que non. Object.prototype contient les propriétés de base d'un objet précisément parce qu'il n'a pas son propre prototype. Objet.prototype.[] = Null ; À ce stade, le voyage à travers la chaîne de prototypes pour trouver une propriété ou une méthode s'arrête.

Un autre fait intéressant- le constructeur de Object est Function. Ceux. Objet. []. Constructeur === Fonction.
Il existe une autre référence circulaire - le constructeur Object est Function et le constructeur Function.prototype est Object.

Revenons à notre exemple. Nous avons déjà compris comment la fonction est créée, passons maintenant à la deuxième ligne. Là, nous créons un objet enfant dont le constructeur est la fonction make_me et le prototype est make_me.prototype.

Eh bien, dans la troisième ligne, nous voyons comment l'interpréteur remonte la chaîne, d'enfant à enfant. [] (Aka make_me.prototype), puis à child. []. [] (Aka Object.prototype), et déjà il trouve la méthode toString, qui est lancée pour exécution.

Impuretés

Il peut sembler que l'héritage via des prototypes est la seule façon dont JavaScript est possible. C'est faux.
Nous avons affaire à un langage très flexible qui offre moins de règles que de possibilités.

Par exemple, si nous le voulons, nous ne pouvons pas du tout utiliser de prototypes, mais programmer en utilisant le concept de mixins. Pour cela, nos bons vieux amis constructeurs vous seront utiles.

// Ceci est un constructeur humain
homme = fonction () (
this .live = function () (alerte ("Je vis");) // Une personne sait vivre
this .walk = function () (alerte ("Je marche");) // Une personne peut marcher
}

// C'est le constructeur du poète
poète = fonction () (
this .kill = function () (alerte ( "Le poète a tué un homme");} // Un poète peut tuer une personne
this .live = function () (alerte ("Je suis mort");) // Cela entraînera la mort de la personne
}

Vladimir = homme nouveau (); // Vladimir est un homme
vladimir.live (); // Je vis - il est vivant
vladimir.walk (); // je marche - il marche

Poète.appel (vladimir); // Exécute le constructeur poète pour l'objet vladimir
vladimir.kill (); // Le poète a tué l'homme
vladimir.live (); //Je suis mort

// Et maintenant le focus
appel.homme (vladimir);
vladimir.live (); //Je vis


* Ce code source a été mis en évidence avec Source Code Highlighter.

Que voit-on dans cet exemple ? Premièrement, c'est la possibilité d'hériter de plusieurs objets qui ne sont pas dans la même hiérarchie. Dans l'exemple, il y en a 2, mais il peut y en avoir autant que vous le souhaitez.
Deuxièmement, c'est l'absence de toute hiérarchie. Le remplacement des propriétés et des méthodes est déterminé uniquement par l'ordre dans lequel les constructeurs sont appelés.
Troisièmement, il s'agit de la possibilité de modifier un objet de manière encore plus dynamique, et il s'agit d'un objet distinct, et non de tous les descendants, comme lors du changement de prototype.

Mise à jour : Fermetures et propriétés privées

Afin de ne pas gonfler cet article déjà assez volumineux, je donne un lien vers l'article Fermetures en JavaScript, où il est écrit en détail à ce sujet.

Que faire de tout ça maintenant

Comme je l'ai dit plus haut, les modifications arbitraires des objets individuels, l'utilisation de constructeurs, de mixins et la flexibilité des prototypes ne sont que des outils, des opportunités qui permettent à un programmeur de créer un code à la fois terrible et beau à tous égards. Il est seulement important de comprendre quelles tâches nous résolvons, par quels moyens, quels objectifs nous atteignons et quel prix nous payons pour cela.

De plus, la question du prix est plutôt non triviale, surtout si l'on parle de développement pour le navigateur. Internet Explorer 6 et 7 versions.
1. Mémoire - tout est simple ici. Dans tous les navigateurs, l'héritage sur les prototypes prend plusieurs fois moins de mémoire que lors de la création de méthodes via des constructeurs. De plus, plus nous avons de méthodes et de propriétés, plus la différence est grande. Cependant, il convient de rappeler que si nous n'avons pas un millier d'objets identiques, mais un seul, la consommation de mémoire sera de toute façon faible, car il y a d'autres facteurs à considérer ici.
2. Temps de processeur - ici, les principales subtilités sont liées aux navigateurs de Microsoft.
D'une part, les objets où les méthodes et les propriétés sont créées via un constructeur peuvent être créés plusieurs fois (dans certains cas des dizaines ou des centaines de fois) plus lentement que via un prototype. Plus il y a de méthodes, plus c'est lent. Donc, si votre IE se bloque pendant quelques secondes lors de l'initialisation du script - il y a une raison de creuser dans cette direction.

D'un autre côté, les propres méthodes d'un objet (créées via un constructeur) peuvent s'exécuter légèrement plus rapidement que celles prototypées. Si vous avez désespérément besoin d'accélérer l'exécution d'une méthode dans ce navigateur, vous devez en tenir compte. Gardez à l'esprit que c'est l'appel de méthode (c'est-à-dire sa recherche dans l'objet) qui est accéléré, et non son exécution. Donc, si la méthode elle-même s'exécute pendant une seconde, vous ne remarquerez pas d'augmentation particulière des performances.

Dans d'autres navigateurs, des problèmes similaires sont observés, où le temps de création d'objets et d'appel de leurs méthodes est approximativement le même pour les deux approches.

P.S. Habituellement, dans les articles de ce genre, l'auteur propose une sorte de wrapper, essayant soit d'implémenter l'héritage classe-objet basé sur un prototype, soit simplement du sucre syntaxique pour l'héritage prototypique. Je ne le fais pas exprès, car Je pense qu'une personne qui comprend le sens de cet article est capable d'écrire n'importe quelle enveloppe pour elle-même, et bien d'autres choses intéressantes :)

Balises : ajouter des balises

Les objets sont la pierre angulaire de JavaScript. De nombreux types de données intégrés sont représentés sous forme d'objets. Pour être un développeur JavaScript performant, vous devez avoir une compréhension claire de leur fonctionnement. Les blocs de construction d'un objet sont appelés ses champs ou propriétés. objet JavaScript... Ils sont utilisés pour décrire n'importe quel aspect d'un objet. La propriété peut décrire la longueur de la liste, la couleur du ciel ou la date de naissance d'une personne. La création d'objets est un processus simple. Le langage fournit une syntaxe connue sous le nom de littéraux d'objet, qui sont indiqués par des accolades.

Accéder aux propriétés

La langue fournit deux entrées pour accéder aux propriétés. La première et la plus courante est la notation par points. Avec la notation par points, une ressource est accessible en spécifiant le nom de l'objet hôte, suivi du point et du nom de la propriété. Par exemple, lorsque object.foo a initialement reçu la valeur un, sa valeur deviendra 2 après l'exécution de l'instruction JavaScript des objets.

Une syntaxe alternative pour l'accès est connue sous le nom de notation entre parenthèses. En notation, le nom de l'objet est suivi d'un ensemble de crochets. Ils spécifient le nom de la propriété sous forme de chaîne :

objet ["toto"] = objet ["toto"] + 1.

Elle est plus expressive que la notation par points car elle permet à une variable de spécifier tout ou partie d'un nom de propriété. Cela est possible car l'interpréteur d'objets JavaScript convertit automatiquement cette expression en chaîne, puis récupère la propriété correspondante. Les noms de propriétés sont créés à la volée en concaténant le contenu de la variable f avec la chaîne "oo":

objet = "barre".

La notation entre crochets permet aux noms de propriété de contenir des caractères qui ne sont pas autorisés dans la notation par points. Par exemple, la déclaration suivante est tout à fait légale entre parenthèses. Cependant, si l'utilisateur essaie de créer le même nom de propriété en notation pointée, il rencontrera une erreur de syntaxe :

objet [" [email protégé]# $% & * (). "] = vrai.

Les propriétés des objets JavaScript imbriqués sont accessibles en liant des points et/ou des parenthèses. Par exemple, l'objet suivant contient un objet imbriqué nommé baz contenant un autre objet nommé foo qui a une propriété nommée bar contenant la valeur cinq :

var objet = (baz : (foo : (bar : 5))).

Les expressions suivantes accèdent à la barre de propriétés imbriquée. La première expression utilise la notation par points, tandis que la seconde expression utilise la notation carrée. La troisième expression combine les deux entrées pour obtenir le même résultat :

  • objet.baz.foo.bar ;
  • objet ["baz"] ["foo"] ["bar"] ;
  • objet ["baz"]. foo ["bar"].

Des expressions comme celle illustrée dans l'exemple précédent peuvent dégrader les performances si elles sont mal utilisées et rendre l'objet JavaScript inutilisable. L'évaluation de chaque expression de point ou de parenthèse prend du temps. Si la même propriété est utilisée plusieurs fois, il est alors logique d'accéder à la propriété une fois, puis de stocker la valeur dans une variable locale pour toutes les utilisations futures.

Fonctionner comme méthode

Lorsqu'une fonction est utilisée comme propriété d'un objet, elle est appelée méthode. Comme les propriétés, elles sont spécifiées en utilisant la notation littérale d'objet. Par exemple:

var objet = (somme : fonction (foo, bar) (return foo + bar;)).

Les méthodes d'objet JavaScript peuvent être appelées à l'aide d'étiquettes et de parenthèses. L'exemple suivant appelle la méthode sum() de l'exemple précédent en utilisant les deux entrées :

  • objet.somme (1, 2);
  • objet ["somme"] (1, 2).

La notation littérale d'objet est utile pour créer de nouveaux objets, mais elle ne peut pas ajouter de propriétés ou de méthodes aux objets existants. Heureusement, l'ajout de nouvelles données est aussi simple que la création d'une instruction d'affectation. Un objet vide est créé. Ensuite, à l'aide des instructions d'affectation, deux propriétés sont ajoutées, foo et bar, ainsi que la méthode baz :

  • objet var = ();
  • objet.foo = 1;
  • objet.bar = null;
  • object.baz = function () (retourne "bonjour de baz ()";).

Encapsuler des programmes

L'idée de base derrière la programmation orientée objet est de diviser les programmes en plus petits morceaux et de rendre chacun responsable de la gestion de son propre état. Ainsi, une certaine connaissance du fonctionnement d'une partie d'un programme peut être locale à cette partie. Quelqu'un qui travaille sur le reste du programme n'a pas besoin de s'en souvenir ou même de le savoir. Chaque fois que ces données locales changent, seul le code qui les entoure immédiatement doit être mis à jour.

Les différentes parties d'un tel programme interagissent les unes avec les autres via des interfaces, des ensembles limités de fonctions ou de liaisons qui fournissent des fonctionnalités utiles à un niveau plus abstrait, cachant leur implémentation exacte. Ces parties du programme sont modélisées à l'aide d'objets. Leur interface se compose d'un ensemble spécifique de méthodes et de propriétés. Les propriétés qui font partie d'une interface sont appelées propriétés publiques. Le reste, qui ne doit pas toucher au code externe, est dit privé.

De nombreux langages offrent la possibilité de faire la distinction entre les propriétés publiques et privées et ne permettent pas au code externe d'accéder aux propriétés privées. JavaScript, adoptant à nouveau une approche minimaliste, n'a pas encore été atteint. Des travaux sont actuellement en cours pour ajouter cette langue. Par conséquent, les programmeurs JavaScript utiliseront cette idée avec succès. En règle générale, l'interface disponible est décrite dans la documentation ou les commentaires. Il est également courant de placer un trait de soulignement (_) au début des noms de propriété pour indiquer que les propriétés sont privées. Séparer l'interface de l'implémentation est une excellente idée. Il est communément appelé encapsulation.

Propriétés

Un objet avec des crochets (...) est appelé un objet littéral. Vous pouvez immédiatement mettre certaines propriétés entre parenthèses (...). Par exemple, les paires "clé : valeur et ainsi de suite" :

let user = (// un nom d'objet : "John", // par clé "name" store value "(! LANG: John" age: 30 // by key "age" store value 30 }.!}

La propriété a une clé (également appelée "nom" ou "identifiant") avant les deux points ":" et une valeur à sa droite. L'objet utilisateur a deux propriétés. L'objet JavaScript utilisateur résultant avec deux fichiers signés intitulés « nom » et « âge ». Vous pouvez ajouter, supprimer et lire des fichiers à tout moment. Les valeurs de propriété sont disponibles en utilisant la notation par points. Il peut être de tout type. Un booléen peut être ajouté. Pour supprimer une propriété, utilisez delete dans le cas d'erreur d'un objet JavaScript.

Tous les objets d'erreur JavaScript sont des descendants de l'objet Error ou d'un objet hérité :

  1. L'objet Erreur de syntaxe hérite de l'objet Erreur.
  2. Erreur d'analyse JSON d'un type spécifique d'objet Erreur de syntaxe.

Pour approfondir encore plus la façon dont les applications gèrent les erreurs JavaScript, examinez de plus près Airbrake JavaScript, un outil de suivi des bogues pour les alertes en temps réel et une compréhension instantanée de ce qui n'allait pas avec le code JavaScript.

Messages d'erreur qu'un utilisateur peut recevoir avant de supprimer un objet JavaScript :

  1. Caractère de contrôle incorrect dans le littéral de chaîne.
  2. Caractère incorrect dans un littéral de chaîne.
  3. Mauvaise sortie Unicode.
  4. Mauvais caractère d'échappement.
  5. Chaîne non terminée.
  6. Code non numérique inattendu.
  7. Il n'y a pas de chiffres après la virgule.
  8. Nombre fractionnaire non terminé.
  9. Il n'y a pas de chiffres après l'indicateur de degré.
  10. Il n'y a pas de chiffres après le signe exposant.
  11. La partie exponentielle n'a pas de nombre.
  12. Fin inattendue des données.
  13. Un mot-clé inattendu.
  14. Un symbole inattendu.
  15. Fin des données lors de la lecture du contenu de l'objet.
  16. Le nom de propriété attendu ou ")".

Propriétés de calcul

Vous pouvez utiliser des crochets dans un littéral d'objet. C'est ce qu'on appelle les propriétés calculées. Un exemple est montré ci-dessous.

La valeur de propriété calculée est simple : cela signifie que le nom de la propriété doit être tiré du fruit. Ainsi, si un visiteur entre « pomme », sac devient (pomme : 5). Vous pouvez utiliser des expressions plus complexes entre crochets :

laisser fruit = "pomme";

: 5 // sac.appleOrdinateurs = 5

Les crochets sont beaucoup plus puissants que la notation par points. Ils acceptent les noms de propriétés et les variables. Mais ils sont aussi plus lourds à écrire. Par conséquent, la plupart du temps, lorsque les noms de propriétés sont connus et simples, un point est utilisé. Et si vous avez besoin de quelque chose de plus complexe, passez aux crochets.

Réservation de mots

Une variable ne peut pas avoir un nom égal à l'un des mots réservés tels que for, let, return, etc. Mais il n'y a pas de telle limitation lors du tri d'objets JavaScript.


En principe, n'importe quel nom est autorisé, mais il y en a un spécial : il « __proto__ » bénéficie d'un traitement spécial pour des raisons historiques. Par exemple, vous ne pouvez pas lui attribuer une valeur autre que object :

obj .__ proto__ = 5;

alerte (obj .__ proto__); //, n'a pas fonctionné comme prévu

Comme vous pouvez le voir dans le code, l'affectation de la primitive 5 est ignorée. Cela peut devenir une source de bogues et même de vulnérabilités si l'opérateur a l'intention de stocker des paires clé-valeur arbitraires dans l'objet et de permettre au visiteur de spécifier les clés. Dans ce cas, le visiteur peut sélectionner "proto" comme clé et l'ajouter à l'objet JavaScript. Il existe un moyen de faire des objets traités avec __proto__ comme une propriété normale. Il existe également une autre carte des structures de données qui prennent en charge les clés arbitraires.

Propriétés d'entier

Le terme "propriété entière" désigne ici une chaîne qui peut être convertie à partir d'un entier sans modification. Ainsi, par exemple, "49" est un nom de propriété entier, car lorsqu'il est converti en entier et inversement, c'est toujours le même. Mais "+49" et "1.2" ne le sont pas. En revanche, si les clés ne sont pas entières, alors elles sont listées dans l'ordre de création. Voir exemple ci-dessous.


Pour résoudre le problème des codes de numérotation, vous pouvez « tricher » en rendant les codes non entiers. L'ajout d'un "+" (signe plus) devant chaque code est suffisant. Maintenant, cela fonctionnera comme prévu.

La différence entre les objets et les primitives est qu'ils sont stockés et copiés "par référence". Les valeurs primitives sont attribuées et copiées "en tant que valeur entière". Une variable stocke une "adresse en mémoire", pas l'objet lui-même ou une "référence" à celui-ci. Vous pouvez utiliser n'importe quelle variable pour accéder et modifier son contenu.


L'exemple ci-dessus montre qu'il n'y a qu'un seul objet et admin pour s'y connecter. Ensuite, s'il utilise ultérieurement une clé différente (utilisateur), l'utilisateur détectera le changement.

Les opérateurs d'égalité == et d'égalité stricte === fonctionnent de la même manière pour les objets. Deux objets ne sont égaux que s'ils sont le même objet. Pour les comparaisons comme obj1> obj2, ou pour les comparaisons avec la primitive obj == 5, les objets sont convertis en primitives. Pour être honnête, de telles comparaisons sont très rarement nécessaires et sont généralement le résultat d'une erreur de codage.

Validation d'objet JavaScript

Les objets ont accès à n'importe quelle propriété. Cependant, s'il n'existe pas du tout, ce ne sera pas une erreur. Seul l'accès à une propriété inexistante renvoie undefined. Il fournit un moyen très courant de vérifier une propriété et de la comparer à une propriété non définie. Ci-dessous un exemple.


Utilisation de "in" pour les propriétés qui stockent undefined. Habituellement, la vérification de comparaison stricte "=== undefined" fonctionne correctement. Il existe un cas particulier où il échoue et « in » fonctionne correctement. C'est lorsqu'une propriété d'un objet existe mais reste indéfinie.


Dans le code ci-dessus, la propriété obj.test existe techniquement. Par conséquent, l'opérateur in fonctionne correctement. De telles situations sont très rares car undefined n'est généralement pas attribué. La plupart du temps, des valeurs "inconnues" ou "vides" nulles sont utilisées. Ainsi, l'opérateur in est, en fait, un invité dans le code.

Boucle "for..in"

Afin de parcourir toutes les clés d'un objet à l'autre, il existe une forme spéciale de boucle : for..in. C'est une chose complètement différente de la construction for (;;).

Ci-dessous un exemple.


Veuillez noter que tous les constructeurs "for" vous permettent de déclarer la variable de bouclage à l'intérieur de la boucle en tant que clé let. Vous pouvez également utiliser une clé de nom de variable différente à la place.

Par exemple, for (let prop in obj) est également largement utilisé.

Il existe un "crochet carré" alternatif qui fonctionne sur n'importe quelle chaîne.


Cela étant dit, le point exige que les clés de l'objet JavaScript soient un identifiant de variable valide, c'est-à-dire qu'il n'y ait pas d'espaces ou d'autres restrictions. Vous devez faire attention à ce que la ligne à l'intérieur des crochets soit correctement citée. Les crochets permettent également d'obtenir un nom de propriété à partir de n'importe quelle expression, par opposition à une chaîne littérale à partir d'une variable :

let key = "aime les oiseaux" ;

// identique à l'utilisateur ["aime les oiseaux"] = true;

utilisateur = vrai.

Ici, la variable clé peut être calculée au moment de l'exécution et dépend de l'entrée de l'utilisateur, puis utilisée pour accéder à la propriété. Cela donne aux programmeurs une grande flexibilité. La notation par points ne peut pas être utilisée de la même manière, car elle itérera sur l'objet JavaScript. Ci-dessous un exemple.


Objet const

L'objet const déclaré peut être modifié. Un exemple est montré ci-dessous.


Il peut sembler qu'un objet JavaScript en ligne (*) génère une erreur, mais ce n'est pas le cas. C'est parce que const capture la valeur de l'utilisateur lui-même. Et ici, l'utilisateur conserve une référence au même objet tout le temps. La ligne (*) va à l'intérieur de l'objet, elle n'est pas réaffectée par l'utilisateur. Const donnera une erreur si vous essayez de définir l'utilisateur et autre chose. Clonage et fusion, Object.assign crée une autre référence au même objet s'il doit être dupliqué. C'est aussi faisable, mais un peu plus compliqué car il n'y a pas de méthode intégrée dans JavaScript. En fait, cela est rarement nécessaire. La copie par référence est utilisée dans la plupart des cas. Mais si vous en avez vraiment besoin, vous devez créer un objet JavaScript et répliquer la structure de l'objet existant, en copiant ses propriétés à un niveau primitif. Ci-dessous un exemple.


Et vous pouvez également utiliser la méthode Object.assign pour cela. Les arguments dest et src1, ..., srcN sont des objets. Il copie les propriétés de tous les objets src1, ..., srcNINTO dest. En d'autres termes, les propriétés de tous les arguments à partir du deuxième sont copiées vers le premier. Il retourne ensuite au dest. Par exemple, vous pouvez l'utiliser pour combiner plusieurs objets en un seul.


Et il est également possible d'utiliser Object.assign pour remplacer la boucle de clonage simple. Il copie toutes les propriétés utilisateur dans un objet vide et le renvoie, tout comme une boucle mais plus courte. Jusqu'à présent, toutes les propriétés utilisateur ont été supposées primitives. Mais les propriétés peuvent être des références à d'autres objets.

Pour résoudre ce problème, vous devez utiliser une boucle de clonage qui vérifie chaque valeur utilisateur et, s'il s'agit d'un objet, réplique sa structure. C'est ce qu'on appelle le "clonage profond".

Il existe un algorithme de clonage profond standard qui gère le cas ci-dessus et des cas plus complexes appelés algorithme de clonage structuré. Pour éviter de réinventer la roue, vous pouvez utiliser une implémentation fonctionnelle de la bibliothèque JavaScript lodash appelée _.cloneDeep (obj).

Techniques avancées

Si un programmeur parcourt un objet et cherche à récupérer toutes les propriétés dans le même ordre dans lequel elles ont été ajoutées, il peut s'appuyer sur un "ordre spécial" où les propriétés entières sont triées et d'autres sont formées dans l'ordre dans lequel l'objet JavaScript a été créé .

Les méthodes objet avancées traitent de concepts rarement utilisés en JavaScript. En effet, ces fonctionnalités puissantes ne sont pas nécessaires dans les scénarios normaux. Certaines de ces méthodes peuvent ne pas fonctionner dans les navigateurs plus anciens tels que les premières versions de Netscape 4.

L'utilisation du prototype pourrait être utilisée pour créer des objets JavaScript et toutes les méthodes mycircle, pas seulement de nouvelles. Cela donne une charge de performance mixte. Ils n'ont pas besoin de conserver des copies séparées des méthodes pour chaque instance de l'objet, ils peuvent donc nécessiter moins de mémoire pour fonctionner, mais le navigateur doit rechercher les portées actuelle et parente pour les trouver. Cela peut conduire à une latence extrême. En règle générale, l'utilisateur doit utiliser ce qui est approprié pour le code plutôt que de fonder sa décision sur les performances, à moins qu'il ne s'agisse d'un environnement contrôlé très spécifique.


Retourne vrai

Dans certains cas, il peut être nécessaire qu'une propriété d'un objet soit liée à l'objet lui-même ou quelque part dans la chaîne de prototypes. En JavaScript, tous les objets utilisent la méthode hasOwnProperty, qui renvoie true si cette propriété est liée à une seule instance d'objet. Dans ce cas, il devient possible de vérifier si le constructeur de l'objet a la même propriété avec la même valeur que l'instance de l'objet elle-même. Cela peut donner un résultat erroné s'il existe des propriétés d'objet JavaScript distinctes avec la même valeur pour l'instance d'objet et le prototype de chaîne. La méthode hasOwnProperty prend un seul paramètre, le nom de la propriété sous forme de chaîne.


Les méthodes privées peuvent être créées de la même manière. C'est juste une fonction qui est créée à l'intérieur d'une fonction constructeur. Cela peut sembler déroutant pour certains, mais c'est ainsi que cela fonctionne. Une fonction privée ne peut être appelée que par le constructeur lui-même ou par des méthodes définies dans la chaîne. Elles peuvent être utilisées comme méthodes publiques si elles sont affectées à un constructeur public et accessibles à l'aide de méthodes ouvertes Objets Javascript.

fonction myob () (fonction cantBeSeen () (alerte (secretValue);

) var valeursecrète = "";

this.method1 = function () (secretValue = "(! LANG: pas de surprises";!}

this.method2 = cantBeSeen;

) var oneOb = nouveau myob ();

unOb.method1 ();

// alerte "pas de surprises" oneOb.method2 ();

// alerte "pas de surprises".

Modèle de commande

Les objets de commande permettent des systèmes faiblement couplés, séparant ceux qui émettent la demande des objets et, en fait, traitent la demande. Ces demandes sont appelées événements et le code qui gère les demandes est appelé gestionnaires d'événements.

Supposons que vous créez des applications qui prennent en charge les actions du Presse-papiers Couper, Copier et Coller. Ces actions peuvent être déclenchées de différentes manières dans toute l'application : par le système de menus, par le menu contextuel, par exemple en cliquant sur bouton de droite souris sur le champ de texte ou un raccourci clavier. Les objets de commande permettent de centraliser le traitement de ces actions, une pour chaque opération lorsque vous n'avez besoin que d'une seule commande pour traiter toutes les requêtes Couper, une pour toutes les requêtes de copie et une pour toutes les requêtes Coller.

Les commandes centralisant tous les traitements, elles interviennent aussi souvent dans le traitement des fonctions d'annulation pour l'ensemble de l'application. Des améliorations significatives peuvent être obtenues en appliquant des techniques JavaScript modernes, ce qui se traduit par des applications plus efficaces, fiables et maintenables.

Les modèles JavaScript + jQuery peuvent être utilisés pour voir comment procéder. Ce package unique comprend un JavaScript optimisé pour tous les modèles GoF utilisant des fonctionnalités plus avancées telles que des espaces de noms, des prototypes, des modules, des objets de fonction, des fermetures, des fonctions anonymes, etc. Si les utilisateurs veulent les derniers outils et techniques pour les modèles JavaScript, les modèles jQuery et les architectures de modèles, alors c'est la meilleure option utilisation. Ce package contient des informations précieuses et pertinentes pour les développeurs JavaScript. Voici ce qui est inclus :

  1. Modèles GoF optimisés pour JavaScript.
  2. Modèles de conception JavaScript modernes.
  3. Modèles de conception Modèle-Vue.
  4. Modèles de conception JQuery.
  5. Modèles architecturaux Expressions JavaScript.
  6. Exemples d'applications (MVC, SPA, etc.)

Les bases suggérées de la syntaxe des objets JavaScript sont très importantes pour les programmeurs novices. Vous devez d'abord comprendre les objets, puis il y aura une connaissance de la programmation orientée objet. Il est impératif d'avoir une compréhension approfondie de ce matériel car il sert de base au reste du langage JavaScript.

Vous avez aimé l'article ? A partager entre amis :