Sauter les bases, je connais PHP
La base
Le JavaScript côté navigateur
Les librairies incontournables
Pour aller plus loin
Cas Pratiques (ES2015)

Dans ce chapitre nous allons faire le point sur le fonctionnement interne des objets en JavaScript et on va parler de la notion de prototype.

Prototype ?

Si vous inspectez une variable avec votre navigateur vous remarquerez qu'il y a une propriété particulière __proto__. Cette propriété est un objet qui contient aussi des propriété et des méthodes.

var a = 1
a.__proto__
/*
{
    constructor: function Number()
    toExponential: function toExponential()
    toFixed: function toFixed()
    toLocaleString: function toLocaleString()
    toPrecision: function toPrecision()
    toString: function toString()
    valueOf: function valueOf()
    __proto__: Object
}
*/

Lorsque l'on fait appel à une propriété sur un objet, le JavaScript va chercher si la propriété est présente sur l'objet puis sur son prototype, puis sur le prototype de son prototype (et ainsi de suite...). C'est ce système qui est utilisé en interne pour faire fonctionner les variables de bases.

Par exemple un objet vide (qui n'a aucune propriétés) dispose quand même de certaines méthodes. Ces méthodes sont en fait placées dans le prototype de l'objet.

var a = {} // L'objet est vide
a.toString() // Pourtant il a une méthode toString()
console.log(a) // Si on regarde le prototype __proto__ on trouve bien la méthode toString()

On peut utiliser ce système pour créer des nouveau types de variables par exemple :

// On crée l'objet qui contient les méthodes que l'on souhaite rendre disponible sur tous nos objet de type "Eleve"
var Eleve = {
    moyenne: function () {
        var somme = 0
        for (var i = 0; i < this.notes.length; i++) {
            somme += this.notes[i]
        }
        return somme / this.notes.length
    }
}

var jean = {notes: [10, 12]} // On crée un eleve en utilisant un objet
jean.__proto__ = Eleve // On change le prototype
jean.moyenne() // 11, La méthode moyenne est disponible sur le prototype et peut donc être appellée

Object.create()

La méthode montrée plus haut n'a rien d'officiel et ne sera jamais utilisé. Lorsque l'on souhaite créer un objet on pourra utiliser la méthode create() sur l'objet Object. Ainsi le code écrit au dessus peut être simplifié :

// On écriera jamais ça
var jean = {notes: [10, 12]} // On crée un eleve en utilisant un objet
jean.__proto__ = Eleve // On change le prototype
jean.moyenne() // 11, La méthode moyenne est disponible sur le prototype et peut donc être appellée

// On peut utiliser Object.create()
var jean = Object.create(Eleve) // Crée un objet qui aura comme prototype Eleve
jean.notes = [10, 12]
jean.moyenne() // 11

De la même façon, pour accéder au prototype d'un obet on utilisera la méthode getPrototypeOf().

Object.getPrototypeOf(1) // Number {}

Le constructeur

Object.create() est une méthode relativement récente pour créer des objets. Par défaut on utilise un constructeur.

// La fonction sera utilisé pour "construire" un objet
var Eleve = function (nom) {
    this.nom = nom // On ajoutera une propriété "nom" 
}

var jean = new Eleve('Jean') // On crée une nouvelle "instance" de l'objet Eleve
jean // {nom: 'Jean'}

Ce constructeur a la particularité de donner un prototype particulier aux instances qui sont crées. En effet si on fait

Object.getPrototypeOf(jean) === Eleve.prototype /// true

En résumé, les objets créés à partie d'un constructeur ont comme prototype la propriété prototype de la fonction. Si on souhaite créer une méthode moyenne disponible pour tous les élèves on pourra faire :

// La fonction sera utilisé pour "construire" un objet
var Eleve = function (nom) {
    this.nom = nom // On ajoutera une propriété "nom" 
}

Eleve.prototype.moyenne = function () {
    var somme = 0
    for (var i = 0; i < this.notes.length; i++) {
        somme += this.notes[i]
    }
    return somme / this.notes.length
}

var jean = new Eleve('Jean') 
jean.notes = [10, 12]
jean.moyenne() // 11