11563 sujets

JavaScript, DOM et API Web HTML5

Bonjour à tous.
J'ai un objet défini de la façon suivante :

var UPDATEBOX = {
	perform: function(event) {
		event.stopPropagation();
		this.close();
		if(this.textField.isChanged()) {
			this.noteInfo.update(this.textField.getValue());
		}
	},
	close: function(event = '') {
		if(event) event.stopPropagation();
		document.body.appendChild(this.updateBox);
	},
	init: function(noteInfo, noteAction) {
		this.updateBox = $('UPDATEBOX');
		if(!this.updateBox) {
			this.titleNode = newNode('h3', '.closeable');
			this.titleNode.addEventListener('click', event => this.close(event));
			this.textField = new InputField('', '', 'textarea');
			this.updateButton = new ButtonField('update', 'Enregistrer', this.perform.bind(this));
			this.updateSet = new Fieldset('', '#UPDATEBOX', this.titleNode, this.textField, this.updateButton);
			this.updateBox = this.updateSet.node();
			this.close();
		}
		this.noteInfo = noteInfo;
		this.noteAction = noteAction;
		this.titleNode.innerText = noteInfo.title;
		this.textField.reset(noteInfo.text);
		Deactivate();
		this.noteInfo.element.appendChild(this.updateBox);
	}
}

Au moment de l'exécution le programme déclare que this.perform est inconnu.

Après pas mal d'essais j'ai ajouté en tête une déclaration de propriété bidon

var UPDATEBOX = {
	name: 'UPDATEBOX',
	perform: function(event) {
		event.stopPropagation();
		this.close();
		if(this.textField.isChanged()) {
			this.noteInfo.update(this.textField.getValue());
		}
	},
       ............

et l'erreur ne se produit plus.
C'est comme si un objet devait avoir au moins une propriété et pas seulement des méthodes.
Cela vous semble-t-il normal ?
Modifié par PapyJP (24 Oct 2025 - 10:46)
Modérateur
Bonjour,
PapyJP a écrit :
Cela vous semble-t-il normal ?

Tu as un bug quelque part dans tes fonctions (ça dépend de ce qu'il y a ailleurs dans la page).

Le code ci-dessous marche :
let UPDATEBOX = {
	perform: function() {alert(1);}
}
UPDATEBOX.perform();

Attention à l'utilisation de this. Il n'est pas toujours ce qu'on croit.

Amicalement,
parsimonhi a écrit :
Tu as un bug quelque part dans tes fonctions (ça dépend de ce qu'il y a ailleurs dans la page).

Depuis 60 ans que je fais des programmes, je sais qu'il y a toujours des bugs quelque part...
Reste à comprendre ce qui peut provoquer ce comportement.
Pour l'instant les personnes qui l'ont utilisée, outre moi-même, n'ont pas rencontré d'erreur dans cette page, mais je sais que c'est une question de temps
Smiley cligne
Modérateur
Bonjour,
PapyJP a écrit :
Reste à comprendre ce qui peut provoquer ce comportement.

Je pense qu'au moment où tu utilises this.perform, this n'est pas l'objet UPDATEBOX, ce qui expliquerait pourquoi le navigateur te dit que this.perform est inconnu.

Fais un console.log(this) juste avant d'utiliser this.perform et tu verras ce qu'il en est vraiment.

Amicalement,
Modérateur
Salut,

je passe en coup de vent. Dans un objet scalaire, on peut écrire comme ceci maintenant :

var UPDATEBOX = {
    perform(event) {
        //....
    },
    close(event = '') {
        //....
    },
    init(noteInfo, noteAction) {
        //....
    }
}


Le problème de cette syntaxe est que tu vas te retrouver avec une belle ambiquité (d'où la syntaxe ES6/ESNext).

Je t'encourage à rédiger d'une manière plus moderne afin d'éviter le bug d'ambiquité (JS objet prototype).

ps :
- UPDATEBOX en majuscule ? Smiley hum
- Je n'ai pas lu ton code en entier. Cependant, tu as peut-être l'occasion d'utiliser un web componenent Smiley cligne
Merci. J’utilise cette syntaxe pour les classes mais comme je n’étais pas sûr que ça marchait aussi pour les objets et que j’avais le problème signalé plus haut j’ai préféré revenir à l’ancienne syntaxe. Je remets ça au goût du jour durant le week-end.
Pour les noms en majuscules, c’est une convention que j’utilise dans tous les langages pour désigner les variables globales. De même var et non pas let ou const pour leur déclaration.
Modifié par PapyJP (25 Oct 2025 - 00:32)
Bonjour,

Je viens de faire le test sous Node, et j'observe le même comportement: le this n'est pas automatiquement bindé pour un objet littéral, quelque soit la syntaxe utilisée (ES5 ou ES6).

Ma théorie est la suivante, mais elle est à vérifier !

Quand on définit un objet littéral, quelque soit la syntaxe, on n'assigne ni plus ni moins que des propriétés normales à l'objet. Ce n'est pas interdit d'attribuer des fonctions comme propriétés, et des fonctions qui n'ont à priori rien à voir avec l'objet.
En d'autres termes le this n'est pas bindé parce que c'est une propriété normale de l'objet, la fonction n'est pas inscrite dans son prototype.

Regardez ce code:


let o1 = {
test: function () { console.log(this); }
};

let o2 = {
test () { console.log(this); }
};

let temp = function () { 
console.log(this);
};

let o3 = {
test: temp
};

let o4 = { };
o4.test = temp;



Dans les 4 cas on peut appeler o1.test(), o2.test(), o3.test() et o4.test(). Avec o3 et o4 on met bien en évidence que la fonction n'a rien à voir avec l'objet, et donc dans tous les cas on affiche undefined.
Présenté de cette façon, c'est assez logique non ?

En revanche quand on écrit:


class C {
test () { console.log(this); }
}

let o = new C();
o.test(); // N'affiche pas undefined


On crée un prototype nommé C qu'on assigne à o. Grosso modo ça revient plus ou moins à écrire:


C = {
test: function () { console.log(this); }
};

let o = { };
o.__proto__ = C; // code hypothétique attribuant le prototype à o
o.test();  / test n'est pas une propriété primaire de o, mais se trouve dans le prototype, donc le this est bien bindé


IL ne faut pas oublier qu'en réalité, la majeure partie des ajouts de Es6 ne sont que des sucres syntaxiques. Le fonctionnement interne de JavaScript, la machine virtuelle (p.ex. V8 pour Chrome et Node) n'a pas tant évolué que ça.
En particulier, l'apparition des classes ES6 n'a pas fait disparaitre le fonctionnement interne par prototype au coeur de JavaScript.


Est-ce qu'il y a un expert JavaScript dans la salle pour confirmer ou infirmer définitivement mes suppositions ?
Merci d'avoir essayé d'analyser le problème.
Mais je ne comprends pas pourquoi ça marche quand j'ajoute une propriété bidon avant la définition de la méthode Smiley eek
Par contre si j'utilise la nouvelle syntaxe

var UPDATEBOX = {
	perform(event) {
		event.stopPropagation();
		this.close();
		if(this.textField.isChanged()) {
			this.noteInfo.update(this.textField.getValue());
		}
	},
	close(event = '') {
		if(event) event.stopPropagation();
		document.body.appendChild(this.updateBox);
	},
	init(noteInfo, noteAction) {
		this.updateBox = $('UPDATEBOX');
		if(!this.updateBox) {
			this.titleNode = newNode('h3', '.closeable');
			this.titleNode.addEventListener('click', event => this.close(event));
			this.textField = new InputField('', '', 'textarea');
			this.updateButton = new ButtonField('update', 'Enregistrer', this.perform.bind(this));
			this.updateSet = new Fieldset('', '#UPDATEBOX', this.titleNode, this.textField, this.updateButton);
			this.updateBox = this.updateSet.node();
			this.close();
		}
		this.noteInfo = noteInfo;
		this.noteAction = noteAction;
		this.titleNode.innerText = noteInfo.title;
		this.textField.reset(noteInfo.text);
		Deactivate();
		this.noteInfo.element.appendChild(this.updateBox);
	}
}

ça fonctionne correctement.
Smiley rolleyes Smiley eek Smiley confus Smiley decu
Modérateur
Bonjour,

QuentinC a écrit :
Est-ce qu'il y a un expert JavaScript dans la salle pour confirmer ou infirmer définitivement mes suppositions ?


PapyJP a écrit :
Merci d'avoir essayé d'analyser le problème.
Mais je ne comprends pas pourquoi ça marche quand j'ajoute une propriété bidon avant la définition de la méthode

La valeur de this dans une méthode d'un objet (et plus généralement une fonction) dépend de la manière dont on utilise l'objet et sa méthode.

En gros, la raison en est que la valeur de this est décidée au tout dernier moment lors de l'exécution. C'est assez complexe et difficile à expliquer en quelques lignes tellement il y a de cas possibles. Eventuellement, on peut lire https://stackoverflow.com/questions/13441307/how-does-the-this-keyword-in-javascript-act-within-an-object-literal pour plus de détails.

Et on n'a pas ici le code de PapyJP qui utilise l'objet et sa méthode. On ne peut donc pas vraiment savoir où est l'effet de bord.

EDIT: j'avais mis un exemple, mais finalement, il ne démontre rien, je le retire donc.

Amicalement,
Modifié par parsimonhi (25 Oct 2025 - 13:12)
Difficile vous donner accès au code qui se trouve dans la partie administration du site.
L’utilisation de l’objet UPDATEBOX est la suivante:
1) définition par le code ci-dessus dans le fichier js
2) appel de la fonction UPDATEBOX.init(noteInfo) par une méthode d’un objet noteInfo de la classe NoteInfo
3) la méthode init crée si besoin un formulaire de saisie, l’affiche dans une balise <div> gérée par l’objet noteInfo ce qui le rend visible
4) la méthode perform analyse le résultat de la saisie et le transmet à la méthode update de l’objet noteInfo qui a appelé init
5) la méthode close permet de masquer le formulaire de saisie en le renvoyant à la fin de la page
Rien de bien compliqué en théorie et le code ne fait aucune autre utilisation de UPDATEBOX que ce que je viens de décrire.
Dans la mesure où le problème ne se manifeste plus je considère qu’il est résolu.