JavaScript Avancé Sujets sélectionnés

Portée de this

Dans une méthode this se réfère à l’objet courant

var myobj = {
  mymethod: function(a, b) {
    console.log(this, a, b);
  }
}
myobj.mymethod(1, 2)
Object { mymethod: myobj.mymethod() } 1 2

pour une fonction, il se réfère à l’objet global (Window dans un browser)

var myfunc = myobj.mymethod
myfunc(1, 2)
Window → http://defeo.lu/aws/lessons/advanced-js 1 2

this peut être lié (bound en anglais)

var myfunc2 = myfunc.bind(myobj);
myfunc2(1, 2);
myfunc.call(myobj, 1, 2);
myfunc.apply(myobj, [1, 2]);
Object { mymethod: myobj.mymethod() } 1 2
Object { mymethod: myobj.mymethod() } 1 2
Object { mymethod: myobj.mymethod() } 1 2

Voir http://bonsaiden.github.io/JavaScript-Garden/#function.this.

Fermeture autour de this

Chaque fonction définit un nouveau this. Ceci est problèmatique avec les fonctions anonymes.

function Personne() {
  this.age = 0;
  // Viellit toutes les secondes 
  setInterval(function() {
    this.age += 1;
  }, 1000)
}
p = new Personne();
setInterval(function () { console.log(p); }, 1000)
Object { age: 0 }
Object { age: 0 }
Object { age: 0 }

Solution : sauvegarder this dans une variable locale.

function Personne() {
  var self = this;
  self.age = 0;
  setInterval(function() {
    self.age++;
  }, 1000);
}
setInterval(function () { console.log(p); }, 1000)
Object { age: 1 }
Object { age: 2 }
Object { age: 3 }

this en ES6

Les fonctions flêche de ES6 changent de sémantique, pour s’adpter à cet usage.

function Personne() {
  this.age = 0;
  // Viellit toutes les secondes 
  setInterval(() => {
    this.age += 1;
  }, 1000)
}
p = new Personne();
setInterval(function () { console.log(p); }, 1000)
Object { age: 1 }
Object { age: 2 }
Object { age: 3 }

La fonction anonyme flêche est fermée autour du this de la portée englobante.

Voir aussi la page MDN sur le sujet.

Prototypes

Les prototypes remplacent l’héritage

function A() { this.one = 1; }

function B() { this.two = 2; }
B.prototype = new A();

var C = new B();
C.one;                         // donne 1
C.two;                         // donne 2

Les prototypes enrichissent les objets

var foo = "bar";
foo.methodeBete;                    // undefined

String.prototype.methodeBete = function() {
        return "bête";
}
foo.methodeBete();                  // donne "bête"

Classes en ES6

ES6 introduit les classes. Il s’agit de sucre syntaxique autour des objets et leurs prototypes.

class Voiture {
	constructor(vitesse) {
		this.vitesse = vitesse;
	}
	vroom() {
		console.log('VR' + Array(vitesse).join('O') + 'M!');
	}
}
class Ferrari extends Voiture {
	constructor() {
		super(20);
	}
}

v = Ferrari();
v.vroom();
VROOOOOOOOOOOOOOOOOOOM!

Ce n’est encore supporté dans aucun browser.

Fork me on GitHub