Updated on
Création et Manipulation d’Objets en JavaScript
Points clés :
- Les objets en JavaScript sont des conteneurs mutables pour des propriétés. Une propriété est une paire clé-valeur, où la clé est une chaîne de caractères (ou un symbole), et la valeur peut être n’importe quelle valeur JavaScript valide.
-
Les objets littéraux sont la manière la plus simple de créer un objet. Par exemple :
const w = { '°C': 27, humidity: '80%', place: 'Le Havre' };
-
Vous pouvez accéder aux propriétés d’un objet en utilisant soit la notation pointée, soit la notation entre crochets :
w['°C']; // 27 w.humidity; // '80%'
Lorsqu’une propriété n’existe pas, elle retourne
undefined
:w.pressure; // undefined
-
Vous pouvez modifier les propriétés ainsi :
w.pressure = 1030; w.place = 'Nice';
-
Les objets sont passés par référence, donc les modifications effectuées sur un objet se refléteront dans toutes les variables qui y font référence :
const w2 = w; w['°C'] = 34; console.log(w2['°C']); // 34
La chaîne de prototypes :
- Chaque objet en JavaScript a un prototype implicite. Par défaut, tous les objets héritent de
Object.prototype
. - Les prototypes permettent aux objets d’hériter de propriétés et de méthodes d’autres objets.
- La recherche de propriétés et de méthodes se fait en remontant la chaîne de prototypes jusqu’à
Object.prototype
.
object
├── properties
│ └── ...
└── *prototype*
├── properties
│ └── ...
└── *prototype*
└── ...
Exemple :
const o = {
'a': 0,
'b': false
};
Object.prototype.ok = function() {
return 'C\'est OK !';
};
Object.prototype.not_ok = 'Pas OK.';
console.log(o.ok()); // 'C'est OK !'
console.log(o.not_ok); // 'Pas OK.'
-
Dans cet exemple, l’objet
o
n’a pas la méthodeok
ni la propriéténot_ok
, mais il peut y accéder car elles sont héritées deObject.prototype
:object : `o` ├── properties │ ├── 'a': 0 │ └── 'b': false └── *prototype* ├── properties │ ├── ok: [Function] │ └── not_ok: 'Pas OK.' └── *prototype* └── undefined
Cela montre comment les prototypes permettent aux objets d’accéder à des propriétés et méthodes qui ne sont pas directement définies sur eux.
Approches pour créer un objet en JavaScript
Objet littéral ({}
)
📌 L’approche la plus simple et intuitive, mais pas idéale pour des objets partageant des méthodes.
const book = {
title: "1984",
author: "George Orwell",
read() {
console.log(`Vous lisez "${this.title}" de ${this.author}.`);
}
};
book.read(); // Vous lisez "1984" de George Orwell.
✅ Simple et lisible.
❌ Pas de partage efficace des méthodes : chaque instance duplique les fonctions.
Object.create()
, prototypes et champs cachés
La fonctionnalité la plus importante de Object.create
est de permettre de définir des objets sécurisés. Les valeurs peuvent être en lecture seule ou protégées par des accesseurs… Les attributs ne peuvent pas vraiment être privés, mais ils peuvent être cachés.
Exemple :
var obj = Object.create(null); // Objet sans lien de prototype
var obj2 = Object.create(Object.prototype); // équivalent à "var obj2 = {};"
var positivePoint = Object.create(Object.prototype, {
x: {
get: function() { return this._x || 0; },
set: function(value) {
if (value < 0) {
console.log("Erreur ! Ce point doit avoir des valeurs positives", this.y);
} else {
this._x = value;
}
},
},
y: {
get: function() { return this._y || 0; },
set: function(value) {
if (value < 0) {
console.log("Erreur ! Ce point doit avoir des valeurs positives");
} else {
this._y = value;
}
},
},
toString: {
value: function() {
return '(' + this.x + ', ' + this.y + ')';
},
}
});
Utilisation :
positivePoint.x = 10; // Définit x à 10
positivePoint.y = -5; // Affiche l'erreur, car y ne peut pas être négatif
positivePoint.y = 5; // Définit y à 5
console.log(positivePoint.toString()); // (10, 5)
Cela montre comment Object.create
permet de créer des objets sécurisés en contrôlant l’accès à leurs propriétés et en cachant des données internes.
✅ Créer des objets sécurisés en contrôlant l’accès à leurs propriétés et en cachant des données internes.
✅ Bonne maîtrise de l’héritage sans utiliser class
.
❌ Moins intuitif que class
et peu utilisé en pratique.
Fonction Constructeur (new
+ Prototype)
📌 Une méthode classique pour créer plusieurs objets partageant des méthodes.
🔹 Exemple : Une gestion d’inventaire
function Product(name, price) {
this.name = name;
this.price = price;
}
// Ajout d'une méthode partagée via le prototype
Product.prototype.displayInfo = function () {
console.log(`${this.name} coûte ${this.price}€`);
};
const laptop = new Product("MacBook", 2500);
const phone = new Product("iPhone", 1200);
laptop.displayInfo(); // MacBook coûte 2500€
phone.displayInfo(); // iPhone coûte 1200€
console.log(laptop.__proto__ === Product.prototype); // true
✅ Plus performant que l’objet littéral grâce au partage de méthodes via prototype
.
❌ Syntaxe plus lourde et remplacée par class
en ES6.
Class class
en ES6 (Design Pattern Class
+ Champs Privés)
📌 Le class
en ES6 simplifie l’approche objet avec une syntaxe plus intuitive.
Exemple : Gestion d’utilisateurs avec champs privés (#
)
class User {
#password; // Champ privé
constructor(username, password) {
this.username = username;
this.#password = password;
}
checkPassword(input) {
return this.#password === input;
}
get usernameInfo() {
return `Utilisateur: ${this.username}`;
}
}
const user = new User("Alice", "supersecret");
console.log(user.username); // Alice
console.log(user.checkPassword("supersecret")); // true
console.log(user.#password); // Erreur ! (Champ privé)
✅ Plus lisible et proche d’autres langages orientés objet.
✅ Possibilité d’avoir des champs privés (#password
).
❌ Attention, sous le capot, cela utilise toujours le mécanisme de prototype !
Héritage grâce à la Chaîne de Prototypes
📌 Comment JavaScript cherche une méthode ou propriété dans la chaîne de prototypes ?
Exemple :
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} fait un bruit.`);
}
}
class Dog extends Animal {
speak() {
console.log(`${this.name} aboie.`);
}
}
const myDog = new Dog("Rex");
myDog.speak(); // Rex aboie.
console.log(myDog.hasOwnProperty("speak")); // false (il est sur le prototype)
console.log(Object.getPrototypeOf(myDog) === Dog.prototype); // true
console.log(Object.getPrototypeOf(Dog.prototype) === Animal.prototype); // true
console.log(Object.getPrototypeOf(Animal.prototype) === Object.prototype); // true
console.log(Object.getPrototypeOf(Object.prototype)); // null
myDog
├── propriétés
│ ├── name: String
└── *prototype* (Dog.prototype)
├── propriétés
│ └── speak(): [Fonction]
└── *prototype* (Animal.prototype)
├── propriétés
│ └── speak(): [Fonction]
└── *prototype* (Object.prototype)
├── propriétés
│ └── hasOwnProperty(): [Fonction]
└── *prototype* (null)
✅ Si une méthode n’est pas trouvée, JavaScript remonte la chaîne jusqu’à Object.prototype
.
✅ Si elle n’existe pas, il retourne undefined
.
❌ Attention : Si une méthode speak()
existe dans Dog.prototype
, celle de Animal.prototype
est ignorée.
Héritage Prototypal avec Object.create()
const mammal = {
breathe() {
console.log("Respire...");
}
};
const cat = Object.create(mammal, {
breathe: {
value: function() {
console.log("Le chat respire doucement...");
}
},
meow: {
value: function() {
console.log("Miaou !");
}
}
});
cat.breathe(); // Le chat respire doucement...
cat.meow(); // Miaou !
✅ Permet de créer un objet sans class
avec une chaîne d’héritage explicite.
Héritage avec extends
class Employee {
constructor(name, salary) {
this.name = name;
this.salary = salary;
}
showInfo() {
console.log(`${this.name} gagne ${this.salary}€.`);
}
}
class Manager extends Employee {
constructor(name, salary, department) {
super(name, salary);
this.department = department;
}
showInfo() {
console.log(`${this.name}, manager du département ${this.department}, gagne ${this.salary}€.`);
}
}
const boss = new Manager("Sophie", 80000, "IT");
boss.showInfo(); // Sophie, manager du département IT, gagne 80000€.
✅ super()
permet d’appeler le constructeur parent.
✅ Plus lisible que Object.create()
, recommandé pour du code moderne.
Conclusion
🔹 Comprendre le fonctionnement des objets et prototypes est essentiel pour bien gérer les modèles objets.
🔹 Les classes en ES6 facilitent la programmation objet, mais sous le capot, tout repose sur les prototypes.
🔹 Les prototypes permettent un héritage puissant, mais ce mécanisme est différents des schémas d’héritage classiques en génie logiciel (java)