Le livre "Comment JavaScript fonctionne"

image La plupart des langages de programmation sont nés d'un ancien paradigme né à l'époque de Fortran. Le gourou du JavaScript, Douglas Crockford, déracine ces racines sèches, nous permettant de penser à l'avenir de la programmation, passant à un nouveau niveau de compréhension des exigences de la prochaine langue.

L'auteur commence par les bases: noms, nombres, valeurs logiques, caractères et autres informations de base. Vous apprendrez non seulement les problèmes et les difficultés de travailler avec des types en JavaScript, mais aussi comment les contourner. Ensuite, vous commencerez à vous familiariser avec les structures de données et les fonctions pour comprendre les mécanismes qui les sous-tendent et apprendre à utiliser des fonctions d'ordre supérieur et un style de programmation orienté objet sans classes.

Extrait
Comment le code fonctionne sans classes


Et vous pensez que vous êtes intelligent en dehors de toutes les classes et gratuit.
John Lennon

L'une des idées clés dans le développement de la programmation orientée objet était un modèle pour l'échange de données entre les parties du programme. Le nom de la méthode et ses arguments doivent être représentés sous forme de messages. Un appel de méthode envoie un message à l'objet. Chaque objet est caractérisé par son propre comportement, qui se manifeste lors de la réception de messages spécifiques. L'expéditeur pense que le destinataire sait quoi faire du message.

Un autre avantage est le polymorphisme. Chaque objet qui reconnaît un message particulier a le droit de le recevoir. Ce qui se passe ensuite dépend de la spécialisation de l'objet. Et c'est une pensée très productive.

Malheureusement, nous avons commencé à être distraits par l'héritage - un schéma très efficace pour réutiliser le code. Son importance est associée à la capacité de réduire les coûts de main-d'œuvre lors de l'élaboration d'un programme. L'héritage est construit sur un plan similaire, à l'exception de certaines nuances. Nous pouvons dire qu'un objet ou une classe d'objets est similaire à un autre objet ou une classe d'objets, mais il présente des différences importantes. Dans une situation simple, tout fonctionne très bien. Il convient de rappeler que la POO moderne a commencé avec Smalltalk, un langage de programmation pour enfants. À mesure que la situation se complique, l'héritage devient problématique. Il donne lieu à une forte cohésion des classes. La modification d'une classe peut entraîner l'échec des classes qui en dépendent. Les modules des classes sont tout simplement inutiles.

De plus, nous observons une attention accrue aux propriétés et non aux objets. Une attention particulière est accordée aux méthodes d'obtention (méthodes get) et d'attribution (méthodes set) à chaque propriété individuelle, et dans les projets encore moins réussis, les propriétés sont ouvertes et peuvent être modifiées à l'insu de l'objet. Il est possible d'introduire un projet plus réussi, où les propriétés sont masquées, et les méthodes traitent les transactions, pas seulement les changements de propriétés. Mais cette approche n'est pas souvent appliquée.

De plus, il y a trop de dépendance de type. Les types sont devenus une caractéristique de Fortran et des langages ultérieurs, car ils étaient pratiques pour les créateurs de compilateurs. Depuis lors, la mythologie autour des types s'est développée, ayant acquis des affirmations extravagantes selon lesquelles les types protègent le programme contre les erreurs. Malgré le dévouement aux types, les erreurs n'ont pas quitté la pratique quotidienne.

Les types sont respectés et loués pour la détection précoce des erreurs de calcul au stade de la compilation. Plus tôt un oubli est découvert, plus le coût sera faible pour l'éliminer. Mais avec des tests appropriés du programme, toutes ces erreurs de calcul sont détectées très rapidement. Par conséquent, les erreurs d'identification de type sont classées comme à faible coût.

Les types ne sont pas à blâmer pour l'apparition d'erreurs difficiles à détecter et coûteuses. Leur faute n'est pas dans l'occurrence de problèmes causés par de telles erreurs et nécessitant quelques astuces. Les types peuvent nous pousser à utiliser des méthodes de programmation obscures, déroutantes et douteuses.

Les types sont comme un régime amaigrissant. Le régime n'est pas accusé de revenir et de prendre du poids. Elle n'est pas non plus considérée comme la cause de la souffrance ou des problèmes de santé qu'elle a causés. Les régimes donnent l'espoir que le poids reviendra à une norme saine et nous continuerons à manger de la malbouffe.

L'héritage classique nous permet de penser que nous créons des programmes de haute qualité, alors que nous faisons plus d'erreurs et appliquons des héritages de plus en plus inefficaces. Si vous ignorez les manifestations négatives, les types semblent être une victoire majeure. Les avantages sont évidents. Mais si vous regardez de plus près les types, vous remarquerez que les coûts dépassent les avantages.

Constructeur


Dans le chapitre 13, nous avons travaillé avec des usines - des fonctions qui renvoient des fonctions. Maintenant, nous pouvons faire quelque chose de similaire avec les constructeurs - des fonctions qui renvoient des objets qui contiennent des fonctions.

Commençons par créer counter_constructor, similaire au contre-générateur. Il a deux méthodes, de haut en bas:

function counter_constructor() { let counter = 0; function up() { counter += 1; return counter; } function down() { counter -= 1; return counter; } return Object.freeze({ up, down }); } 

L'objet retourné est figé. Il ne peut pas être endommagé ou endommagé. L'objet a un état. Le compteur variable est une propriété privée de l'objet. Vous ne pouvez y accéder que par des méthodes. Et nous n'avons pas besoin de l'utiliser.

C'est une circonstance très importante. L'interface objet est exclusivement des méthodes. Il a une coquille très solide. Nous obtenons la meilleure encapsulation. Il n'y a pas d'accès direct aux données. Il s'agit d'une conception modulaire de très haute qualité.

Un constructeur est une fonction qui renvoie un objet. Les paramètres et les variables constructeurs deviennent des propriétés privées de l'objet. Il n'a aucune propriété publique constituée de données. Les fonctions internes deviennent des méthodes objet. Ils transforment les propriétés en propriétés fermées. Les méthodes qui tombent dans un objet figé sont ouvertes.

Les méthodes doivent implémenter les transactions. Supposons, par exemple, que nous ayons un objet personne. Vous devrez peut-être modifier l'adresse de la personne dont les données y sont stockées. Pour ce faire, vous n'avez pas besoin d'un ensemble de fonctions distinct pour modifier chaque élément d'adresse individuel. Nous avons besoin d'une méthode qui reçoit un objet littéral, capable de décrire toutes les parties de l'adresse qui doivent être modifiées.

L'une des idées brillantes de JavaScript est le littéral objet. Il s'agit d'une syntaxe agréable et expressive pour regrouper les informations. En créant des méthodes qui consomment et créent des objets de données, vous pouvez réduire le nombre de méthodes, augmentant ainsi l'intégrité de l'objet.

Il s'avère que nous avons deux types d'objets.

  • Les objets durs contiennent uniquement des méthodes. Ces objets protègent l'intégrité des données contenues dans la fermeture. Ils nous fournissent le polymorphisme et l'encapsulation.
  • Les objets de données logicielles ne contiennent que des données. Ils n'ont aucun comportement. Ceci est juste une collection pratique avec laquelle les fonctions peuvent fonctionner.

On pense que la POO a commencé par ajouter des procédures aux enregistrements en langue kobol, garantissant ainsi une sorte de comportement. Je crois que la combinaison des méthodes et des propriétés des données a été un pas en avant important, mais ne devrait pas être la dernière étape.

Si l'objet matériel doit être converti en chaîne, la méthode toJSON doit être activée. Sinon, JSON.stringify le verra comme un objet vide, ignorant les méthodes et les données cachées (voir chapitre 22).

Options du constructeur


Une fois, j'ai créé un constructeur qui prend dix arguments. C'était très difficile à utiliser, car personne ne se souvenait de l'ordre des arguments. Plus tard, il a été remarqué que personne n'utilisait le deuxième argument, je voulais le supprimer de la liste des paramètres, mais cela casserait tout le code déjà développé.

Si j'étais prudent, j'aurais un constructeur qui prend un objet comme paramètre. Il est généralement extrait d'un littéral objet, mais peut provenir d'autres sources, par exemple du contenu JSON.

Cela offrirait de nombreux avantages.

  • Les lignes clés donnent au code un aspect documenté. Le code est plus facile à lire car il vous indique quel est chaque argument de l'appelant.
  • Les arguments peuvent être organisés dans n'importe quel ordre.
  • À l'avenir, vous pouvez ajouter de nouveaux arguments sans endommager le code existant.
  • Les paramètres non pertinents peuvent être ignorés.

Le plus souvent, un paramètre est utilisé pour initialiser une propriété privée. Cela se fait comme suit:

 function my_little_constructor(spec) { let { name, mana_cost, colors, type, supertypes, types, subtypes, text, flavor, power, toughness, loyalty, timeshifted, hand, life } = spec; 

Ce code crée et initialise 15 variables privées à l'aide de propriétés portant les mêmes noms que spec. Si spec n'a pas de propriété correspondante, une nouvelle variable est initialisée, à laquelle la valeur non définie est affectée. Cela vous permet de remplir toutes les valeurs manquantes avec des valeurs par défaut.

La composition


L'expressivité et l'efficacité vives de JavaScript vous permettent de créer des programmes dans le paradigme classique, bien que ce langage ne s'applique pas aux classiques. JavaScript permet également des améliorations. Nous pouvons travailler avec une composition fonctionnelle. Ainsi, au lieu d'ajouter quelque chose à titre d'exception, vous pouvez obtenir un peu de ceci et cela. Le constructeur a l'apparence générale suivante:

 function my_little_constructor(spec) { let {} = spec; const _ = other_constructor(spec); const  = function () { //   spec, , _,  }; return Object.freeze({ , _. }); } 

Votre constructeur peut appeler autant d'autres constructeurs que nécessaire pour accéder à la gestion des états et au comportement qu'ils fournissent. Vous pouvez même lui transmettre exactement le même objet de spécification. En documentant les paramètres de spécification, nous répertorions les propriétés nécessaires à my_little_constructor et les propriétés requises par d'autres constructeurs.

Parfois, vous pouvez simplement ajouter les méthodes résultantes à un objet figé. Dans d'autres cas, nous avons de nouvelles méthodes qui invoquent les méthodes reçues. Cela garantit que le code est réutilisé, semblable à l'héritage, mais sans forte cohésion. Un appel de fonction est le schéma de réutilisation de code d'origine, et rien de mieux n'a été inventé.

La taille


Avec cette approche de construction d'un objet, plus de mémoire est impliquée que lors de l'utilisation de prototypes, car chaque objet dur contient toutes les méthodes de l'objet et l'objet prototype contient un lien vers le prototype contenant les méthodes. La différence de consommation de mémoire est-elle significative? En comparant la différence avec les dernières réalisations en matière d'augmentation de la quantité de mémoire, nous pouvons dire: non. Nous sommes habitués à lire la mémoire en kilo-octets. Et maintenant, nous le considérons en gigaoctets. Dans ce contexte, la différence ne se ressent pas du tout.

La différence peut être réduite en améliorant la modularité. L'accent mis sur les transactions, et non sur les propriétés, vous permet de réduire le nombre de méthodes tout en améliorant la connectivité.

Le modèle classique se caractérise par l'uniformité. Chaque objet doit être une instance d'une classe. JavaScript supprime ces restrictions. Tous les objets n'ont pas besoin de se conformer à des règles aussi strictes.

Par exemple, je crois que cela n'a aucun sens que les points soient nécessairement des objets rigides avec des méthodes. Un point peut être un simple conteneur pour deux ou trois nombres. Les points sont passés à des fonctions capables de projection, d'interpolation, ou autre chose qui peut être fait avec des points. Cela peut être beaucoup plus productif que les points de sous-classement pour leur donner un comportement spécial. Laissez les fonctions fonctionner.

»Plus d'informations sur le livre sont disponibles sur le site Web de l'éditeur
» Contenu
» Extrait

25% de réduction sur les colporteurs - JavaScript

Lors du paiement de la version papier du livre, un livre électronique est envoyé par e-mail.

Source: https://habr.com/ru/post/fr455698/


All Articles