Apprendre le JavaScript depuis le PHP

Voir la vidéo
Description Sommaire

Le problème lorsque l'on cherche à apprendre un nouveau langage est que l'on se retape systématiquement les bases : Les variables, les fonctions, les conditions... Ce qui peut s'avérer pénible lorsque l'on connait déjà un autre langage de programmation. Aussi, je vous propose d'utiliser les connaissances que vous avez déjà en PHP afin d'accélerer votre apprentissage du JavaScript.

Les variables

Les variables en JavaScript doivent être déclarées avant d'être utilisées mais il n'est pas nécessaire de les préfixer par un $

var a = 1
a // 1

Il n'est d'ailleurs pas nécessaire de terminer nos instructions par des ;.

Les variables ont des types similaires à ceux que l'on connait en PHP. En revanche il n'existe pas de tableaux associatifs. Ils sont "remplacés" par des objets.

var a = 1 // nombres
var b = "chaine" // Pas de différence entre " et ' 
var c = ['tab', 2, 3.14] // Les tableaux fonctionnent comme en PHP
// Les objets "remplacent" les tableaux associatifs
var d = {
    nom: 'Marc',
    note: 18
    notes: [2, 10, 16]    
}
d.nom // Marc 
d['nom'] // Marc
var e = null // valeur nulle
var f = false // booléen
var g = undefined // Pas d'équivalent en PHP
var h // Prendra automatiquement la valeur undefined

Pour la concaténation le JavaScript n'utilisent pas l'opérateur . mais une simple addition

"Salut" + " les gens" // "Salut les gens"
// Attention par contre à la conversion implicite
"1" + 1 // 11
"43" > 7 // false (la comparaison est fait par ordre alphabétique car 7 est considéré comme une chaine)
43 > 7 // true 
"1" * 3 // 3 (pas possible de multiplier une chaine, "1" est implicitement convertit en nombre)

Les conditions

Les conditions fonctionnent comme en PHP à un détail prèt

if (<condition>) {

} else if (<condition>) { // Le else if s'écrit en 2 mots

} else {

}

Les boucles

Les boucles s'écrivent de la même façon qu'en PHP avec le while ou le for

while (<condition>) {

}

for (var i = 0; i < 10; i++) {

}

En JavaScript il n'existe pas de boucles foreach (on verra comment contourner le problème) plus tard

Les fonctions

Les fonctions peuvent s'écrire comme en PHP et sont un type de variable particulier. On pourra ainsi les stocker dans une variable.

function demo (a) {
    return a * 3   
}

var demo2 = function (a) {
    return a * 3   
}

demo(3) // 9

La différence entre ces 2 manières de déclarer une fonction est expliquée dans le chapitre consacré à l'hoisting

En revanche il y a quelques différences avec PHP

  1. Une fonction a accès au contexte extérieur (variables externes à la fonction, en PHP on doit utiliser le use () pour obtenir un résultat similaire).
  2. Une fonction peut être appellée avec un nombre incorrect de paramètre, les paramètres manquant prendront la valeur undefined.
  3. Il n'est pas possible d'assigner une valeur par défaut aux paramètres
  4. Les fonctions sont très souvent utilisées en callback (encore peu exploité en PHP)
// 1. La fonction peut utiliser des variables hors de la portée locale
var b = "1"
function demo (a) {
    return b    
}
demo() // "1"
b = 3
demo() // 3

// 2. On peut appeller une fonction sans paramètre
function demo (a) {
    return a    
}
demo() // undefined

// 3. Si on veut donner une valeur par défaut au paramètre
function demo (a) {
    if (a === undefined) {
        a = 0
    }
}

En JavaScript tout est objet

En JavaScript les types de bases sont des "instances" de certains objet. Ils ont ainsi des méthodes et des propriétés spécifiques.

"Salut" // C'est une instance de l'objet String
"Salut".toUpperCase() // "SALUT"
1.123124.toFixed(2) // "1.12"
// L'objet de base à lui aussi des méthodes
String.fromCharCode(65) // "A"
"aze".length // 3
["Salut", "les", "gens"].length // 3
"1,2,3".split(',') // ['1', '2', '3']
// Un remplaçant pour notre fameux foreach ^^
["Salut", "les", "gens"].forEach(function (eleve) {
    "Salut " + eleve 
})

L'ensemble des méthodes et types primaires sont disponible sur la documentation MDN

POO en JavaScript

Le JavaScript est un langage entièrement objet qui ne partage pas la même logique que PHP. Je vais ici essayer de faire des analogies mais il faut savoir que le langage n'utilise pas de classes mais plutôt un système d'héritage basé sur les prototypes.

Notre première "classe"

class Eleve {

    private $nom;

    public function __construct($nom) {
        $this->nom = $nom;
    }

    public function getNom () {
        return $this->nom;
    }
}

$jean = new Eleve('Jean');

Pour traduire ça en Javascript il faut créer un constructeur. On utilise pour cela une simple fonction

var Eleve = function (nom) {
    this.nom = nom 
}
var jean = new Eleve('Jean')

Lorsqu'une fonction est appellé avec l'opérateur new, elle est utilisé comme constructeur et génère un objet en utilisant le code de la fonction. On dit ainsi que jean est une instance de l'objet Eleve.

Si on souhaite maintenant créer une méthode accessible par toutes les instances de l'objet Eleve il faut l'assigner comme propriété de la propriété prototype de l'objet.

var Eleve = function (nom) {
    this.nom = nom 
}
Eleve.prototype.getNom = function () {
    return this.nom 
}
var jean = new Eleve('Jean')

Cette manière de faire les choses apporte certaines particularités :

  • Il n'existe pas de notion de visibilité privée / public / protégé
  • Il est possible de redéfinir des méthodes sur l'instance
var jean = new Eleve('Jean')
// On peut changer la méthode getNom seulement pour cette instance 
jean.getNom = function () {
    return 'John doe'   
}
  • Il est possible de modifier le prototype après coup, et ainsi donner à toutes les instances de nouvelles méthodes
String.prototype.lol = function () {
    return this + ' lol !'    
}
// Toutes les chaines ont maintenant une nouvelle méthode lol()
"1".lol()
  • Si on souhaite créer une méthode "statique" il suffit de créer la méthode directement sur l'objet
Eleve.demo = function () {
    return "demo"   
}

Une méthode peut donc être définie sur l'objet directement ou sur le prototype (pour ainsi affecter les instances)

Le mot clef this

Attention au mot clef this car il n'a pas la même valeur qu'en PHP. Par défaut this prend comme valeur la variable globale (window sur le navigateur, global sur nodejs) mais sa valeur peut changer dans une fonction suivant comment elle est appellée.

this // window ou global
var maFonction (a) {
    return this   
}
var eleve = {
    maFonction: function () {
        return this   
    }   
}
maFonction() // window ou global
eleve.maFonction() // eleve {}
maFonction.call('Salut', 'argument1') // 'Salut'
  • this prend comme valeur l'objet global par défaut
  • Si une méthode est appellée depuis un objet, this prendra comme valeur l'objet
  • On peut appeller une méthode en changeant la valeur de this gràce à la méthode call()

L'héritage

Maintenant que l'on a vu l'équivalent d'une classe, comment se passe l'héritage ?

class Eleve {

    private $nom;

    public function __construct($nom) {
        $this->nom = $nom;
    }

    public function getNom () {
        return $this->nom;
    }
}

class Delegue extends Eleve{
    public function getRole () {
        return 'delegue';
    }
}

$jean = new Delegue('Jean');

Pour reproduire ce système d'héritage en JavaScript il faut utiliser le système de prototype. En créant un prototype qui aura comme prototype le prototype de l'objet parent (c'est plus clair en lisant le code ^^)

// Le constructeur Eleve
var Eleve = function (nom) {
    this.nom = nom 
}
Eleve.prototype.getNom = function () {
    return this.nom 
}

// Le constructeur Delegue
function Delegue(nom) {
  // On appelle le constructeur parent
  Eleve.call(this, nom)
  // On pourrait ici rajouter une logique supplémentaire
}

// On va stocker dans le prototype de Delegue un objet 
// qui aura comme prototype, le prototype d'Eleve 
Delegue.prototype = Object.create(Eleve.prototype)

// La ligne du dessus écrase le constructeur donc on le redéfinit
Delegue.prototype.constructor = Delegue;

// On peut maintenant créer de nouvelle méthode d'instance
Delegue.prototype.getRole = function () {
    return 'delegue';
}
var jean = new Delegue('Jean');

Comme vous le voyez ici, l'héritage est beaucoup plus complexe à mettre en place qu'en PHP. Heureusement pour nous, le langage est en pleine transformation et il sera bientôt possible d'utiliser une syntaxe plus proche que ce que l'on connait en PHP avec le mot clef class (mais ce n'est pas encore disponible sur les navigateurs :().

Namespaces

Il n'existe pas de notion de namespace à proprement parler mais il est possible d'obtenir un principe similaire en mettant nos constructeur dans un plus gros objet.

var GRAFIKART = {
    Eleve: function () {

    }    
}
GRAFIKART.Eleve.prototype.maFonction = function () {

}
// On simule ainsi un namespace GRAFIKART en créant un objet englobant le reste de nos objets.
Publié
Technologies utilisées
Auteur :
Grafikart
Partager