L'orienté objet en JavaScript et questions fréquentes

Publié par Jean-Nicolas Viens le vendredi 12 décembre 2014 à 06:10

Avez-vous déjà créé un objet en JavaScript?

Ça semble anodin pour un langage où "tout est un objet", mais en réalité cet exercice demande de bien comprendre plusieurs concepts fondamentaux du JavaScript. Ce n'est rien de bien compliqué, il suffit de s'y arrêter quelques instants pour bien tout comprendre.

Ce billet est le premier de trois dans lequel nous couvrirons tous les concepts JavaScript requis pour créer un objet : de la porté des variables à la création d'objet.

Nous nous baserons sur le code généré par coffeescript, qui est un langage qui génère du JavaScript, mais avec une syntaxe plus simple. Le but est de comprendre pourquoi coffeescript génère ce code.

Vous pouvez utiliser ce convertisseur pour convertir les exemples suivants entre le JavaScript et le coffeescript. Avec jsfiddle vous pouvez exécuter ces exemples facilement (autant ceux en JavaScript que ceux en coffeescript).

Voici la classe telle que déclarée en coffeescript :

class Cart
  constructor: ->
    @items = []
  
  addItem: (item) ->
    @items.push item

Et voici le code JavaScript généré :

var Cart;

Cart = (function() {
  function Cart() {
    this.items = []; 
  }

  Cart.prototype.addItem = function(item) {
    return this.items.push(item);
  };

  return Cart;

})();

Il y a plusieurs concepts à comprendre avant de bien voir l'utilité de ce code. Nous procéderons étape par étape séparées sur 3 billets de blogue.

Pour référence complète, voici les liens vers les différents concepts :

Portée d'une variable

Premièrement, il faut se souvenir qu'une variable est globale si elle est déclarée sans le mot-clé var. Autrement, sa portée est la fonction qui l'englobe.

function foo() {
  var a = 2;
  b = 4;
}

console.log(b); // Erreur: variable inexistante.

foo();
console.log(b); // Après l'appel de foo(), b = 4!
console.log(a); // Erreur: variable inexistante.

Un cas souvent pathologique est la boucle for :

function foo() {
  for(i = 0; i <=10; i++ {
  }
}

console.log(i); // 10!

Le plus grand danger présentement est "d'écraser" une valeur globale avec une autre, ce qui est évidement très difficile à trouver comme bogue. Pour l'instant le JavaScript est à toute fin pratique "single thread", donc on a pas de problème de ce côté là. Par contre, il n'est pas dit que ce sera toujours ainsi (j'anticipe déjà les projets de 1000 JP pour corriger tout ça!). Mais on s'égare, revenons au code et regardons ce qu'est une IIFE.

IIFE et portée

Une IIFE (Immediatly invoked function expression) est la déclaration d'une fonction qui est immédiatement invoquée. Remarquez bien les parenthèses qui entourent la fonction. Voici un exemple :

var total = (function() {
  var ajouterUn = function(nombre) {
    return nombre + 1;
  }
  return ajouterUn(2);
})();

On a le même résultat que si ajouterUn était déclaré à l'extérieur, mais ici la fonction ajouterUn devient une méthode privée. Impossible de l'invoquer après que total soit calculé puisque ajouterUn est déclaré avec le mot-clé var. Sa portée (scope) est donc la fonction qui l'englobe.

Les fonctions au premier plan

En JavaScript, une fonction est un type comme un autre.

On peut la stocker dans une variable :

var direAllo = function() { return "Allô!"; }

Ce qui est identique à :

function direAllo() {  return "Allô!"; }

Ou la retourner :

var direAllo = function() {
  return function() {
    return "Allô!";
  }
}

console.log(direAllo()()); // les doubles ()() ne sont pas une erreur! On invoque la fonction retournée.

Et on peut combiner les deux :

var direAllo = function() {
  var direAlloJohn = function() {
    return "Allô, John!";
  }

  return direAlloJohn;
}

Dans ce cas, direAllo() sera une fonction (la même que direAlloJohn). Il faut noter par contre que la fonction direAlloJohn n'aura jamais été exposée publiquement (en dehors de la fonction qui l'encapsule).

Prototype

Le prototype contient une série de méthodes à copier dans chaque nouvel objet. C'est un gabarit (template) qui dicte comment créer un objet. On pourrait donc ajouter à l'exemple précédent :

var Cart = function() {
  this.allo = "Allô!";
}

Cart.prototype.salut = function() {
  console.log("1: " + this.allo);
  return "Salut!";
}

var aCart = new Cart();
console.log("2: " + aCart.allo);
console.log("3: " + aCart.salut()); 

Le résultat sera, dans l'ordre :

  • 2: Allô!
  • 1: Allô!
  • 3: Salut!

Le constructeur et les méthodes dans le prototype partagent le même objet `this`, qui est unique et indépendant entre chaque objet (à chaque instanciation). On en apprendra d'avantage sur les constructeurs et le mot-clé `this` dans le prochain article!

Conclusion

Nous avons vu trois concepts de base du JavaScript qui ne sont pas exactement reliés à l'orienté objet, mais qui nous serviront très prochainement.

Pour la suite, nous verrons :

  • Comment utiliser le mot-clé `this`
  • Comment utiliser le mot-clé `new`
  • Faire des méthodes statiques

Entre temps, je vous conseille fortement d'expérimenter avec les concepts tirés des langages fonctionnels. Bien que JavaScript ne soit pas réellement un langage fonctionnel, la possibilité de traiter des fonctions comme des données a des répercussions importantes. Entre autre, vous pouvez essayer de mieux comprendre les promises de jQuery.

Cet article vous a plu? Sachez que nous préparons une formation dédiée aux technologies client (frontend). Nous aimerions votre opinon afin de mieux cibler les besoins des développeurs web et nous apprécierions grandement que vous répondiez à ce court sondage. N'hésitez pas à y écrire tout ce qui pourrait vous intéresser!

blog comments powered by Disqus

0 Comments:

Post a comment

Comments have been closed for this post.