Javascript est un langage objet, même s’il ne possède pas un modèle de programmation par classes mais une modèle orienté prototype.
Un objet n’est donc pas une instance de classe mais un clone de prototype, et peut être modifié «à chaud».
Ce concept est extrêmement puissant [1], puisque l’héritage est dynamique, c’est à dire qu’un objet peut changer de parent en cours de route (cf. section Héritage)
Le fait d’ajouter une fonction dans le prototype, rend cette fonction disponible immédiatement dans l’ensemble des clones.
var a1 = ["4", "2"]
Array.prototype.size = function() { return this.length; }
var a2 = ["s", "y", "n", "b", "i", "o", "z"]
a1.size()
=> 2
a2.size()
=> 7
Javascript est un langage interprété et typé dynamiquement. Il existe deux moyens de connaitre le type d’un objet:
var a = true
typeof a
=> "boolean"
a.constructor.name
=> "Boolean"
typeof Boolean
=> "function"
Boolean.constructor.name
=> "Function"
typeof Function
=> "function"
Function représente donc la base de l’héritage.
Il est possible au sein d’une fonction de définir des variables ou méthodes qui ne seront pas accessibles de l’extérieur.
function A() {
// private
var _foo = "foo";
function foo() {
return _foo;
};
// public
this._bar = "bar";
this.bar = function() {
return this._bar;
}
// public method returning private attribute
this.baz = function() {
return _foo;
}
}
var a = new A;
a.foo()
=> TypeError: a.foo is not a function
a._foo
=> "undefined"
a.bar()
=> "bar"
a._bar
=> "bar"
a.baz()
=> "foo"
// static method
A.parse = function() { … }
var a = new A
a.parse()
// TypeError: a.parse is not a function
La notion de namespace n’existe pas à proprement parler en Javascript mais elle est très simple à simuler:
var com = {};
com.synbioz = {};
com.synbioz.app = function(name, url) {
this._name = name;
this._url = url;
}
new com.synbioz.app("foo", "foo.com")
Il faut imaginer la méthode prototype comme un pointeur vers le constructeur dans un héritage par classe.
function Human() { this.speak = function() { return "bonjour" } }
function Monster() { this.speak = function() { return "grrrr" } }
function Hulk() {}
// hulk inherits from Human
Hulk.prototype = new Human()
hulk1 = new Hulk()
hulk1.speak()
=> "bonjour"
// hulk inherits from Monster
Hulk.prototype = new Monster()
hulk2 = new Hulk()
hulk2.speak()
=> "grrrr"
// warning:
hulk1.speak()
=> "bonjour"
Le changement de constructeur n’impacte pas les objets déjà créés car la propriété prototype de hulk1 n’a pas été modifiée, c’est le prototype du parent (Hulk) qui a été modifié.
// still does'nt work
hulk1.prototype = new Monster();
hulk1.speak()
=> "bonjour"
Ce code n’a logiquement aucun effet, on ne peut pas modifier directement le prototype de l’objet, cela reviendrait à vouloir modifier le constructeur d’une instance dans un héritage par classe.
Toutefois, dans certaines implémentations (ex: mozilla), l’objet garde une référence vers le prototype parent.
Attention, la propriété n’est pas standard et ne fonctionne pas sur tous les navigateurs.
hulk1.__proto__ = new Monster
hulk1.speak()
=> "grrrr"
[1]: Attention, Un grand pouvoir implique de grandes responsabilités.
L’équipe Synbioz.
Libres d’être ensemble.
Nos conseils et ressources pour vos développements produit.