JavaScript : 3 fondamentaux

Après quelques années à écrire dans un langage, on finit facilement par oublier les premières difficultés que l’on avait rencontrées. Et à force de faire de la veille, de l’autoformation et de parler entre experts dans des conférences, j’ai un peu quitté la réalité de la majorité des équipes Web.

Maintenant que je suis consultant indépendant je retourne dans des équipes qui avaient autre chose à faire que de se demander si on a le droit de parler de classe en JavaScript, quelle est la bonne définition d’une closure, ou quelles sont les fonctionnalités de EcmaScript 5 qui auraient du rester dans Ecmascript.Next.

J’avais déjà parlé sur ce blog de JavaScript et la programmation orienté objet pour les développeurs PHP, nous allons explorer ici les 3 notions fondamentales de JavaScript qui sont probablement les plus grosses sources de bugs, d’incompréhension et de frustration pour le développeur Web moyen. Et qui accessoirement sont la base d’une programmation plus évoluée par la suite.

JavaScript est différent : apprenez le

Le monde du développement Web semble dominé par les langages dérivés de la syntaxe du C, PHP en tête, avec des paradigmes qui se ressemblent. Forcément en abordant JavaScript dont la syntaxe n’est pas vraiment révolutionnaire, on est tenté d’appliquer la même logique. Mais c’est oublier un peu vite que ce langage a été créé il y a déjà 15 ans, quand Java était seulement à mode et pas encore ultra dominant comme aujourd’hui, et qu’il est principalement l’héritier de langages comme Erlang et Lisp, aujourd’hui très peu connus. En fait le mot Java dans JavaScript a été rajouté pour des raisons commerciales, et seuls quelques concepts comme la syntaxe et je crois la gestion des dates ont contribué à former JavaScript. JavaScript n’est donc qu’un cousin éloigné des langages mainstream.

Le maître mot de ses concepteurs semble avoir été la versatilité. Nous allons voir qu’en explorant seulement 3 bases à priori simples, il est possible d’obtenir à peu près n’importe quoi, ce que les grands maître de JavaScript s’amusent tous les jours à faire. En attendant de passer dans la catégorie des maîtres, il faut déjà maîtriser ces bases pour faciliter son travail au quotidien.

Nous allons donc nous baser sur EcmaScript 3 (le javascript de IE6-7-8) dont les trois fondamentaux sont :

  • La portée des variables ( var + function)
  • Les fonctions
  • Le contexte (this)

Commençons par la portée.

La portée des variables

La théorie

La portée, c’est ce que voit l’interpréteur à un moment donné de l’exécution du code. Ouvrez un fichier JS, tapez le mot clé debugger; où bon vous semble, démarrez firebug ou votre outil préféré et cherchez l’onglet « Espions » ou « Watch ».

L’onglet Watch ou Espions de Firebug

La règle pour comprendre comment est créée une portée est très simple :

1 function = 1 portée

Concrètement vous avez la portée globale où tout se trouve (dans un navigateur, c’est window), puis à chaque fonction que vous créez, vous créez une nouvelle portée, et celles ci peuvent s’imbriquer à l’infini. Chaque fois que vous précédez une assignation par le mot clé var, la variable n’est visible qu’à partir de cette portée.

test1 = function() {
	var x = 1;
	test2 = function() {
		var x = 2;
		test3 = function() {
			var x = 3;
			console.log(x); // 3
		}();
	}();
	console.log(x); // 1
}();
console.log(x); // undefined

Si vous exécutez le code précédent dans votre console JavaScript, vous constaterez 3 choses :

  • le console.log le plus profond affiche bien sur la dernière valeur de x, à savoir 3. Dans ce troisième niveau, on a écrasé les valeurs précédentes de x.
  • malgré cet écrasement à un niveau inférieur, le second console.log (qui affiche 1) montre bien que les nouvelles valeurs de x ne sont pas visibles depuis la première fonction.
  • enfin le dernier console.log est fait au niveau global, en dehors des définitions de fonction. Ici x n’existe même pas.

La pratique

Nous avons vu comment le couple var + function permet de définir une portée et empêche le code en dehors de la portée de voir certaines variables. Pourquoi ne pas tout mettre au niveau global ? Pour des raison d’organisation du code et de maintenabilité ! Imaginez le code suivant :

function genericFunctionName() {
	for(i = 0; i < myArray.length; i++) {
		console.log(i);
	}
}
for(i = 0; i < 10; i++) {
	genericFunctionName();
}

Nous avons simplement une fonction qui parcourt un tableau fictif, puis nous appelons cette fonction 10 fois. N’exécutez surtout pas cela dans votre navigateur, car c’est une boucle infinie !

En fait les deux boucles for utilisent le même nom de variable (i) pour compter les tours. C’est un nom extrêmement commun et ça ne poserait pas de problème si les deux boucles ne pointaient pas sur la même variable ! Fixons cela.

function genericFunctionName() {
	for( var i = 0; i < myArray.length; i++) {
		console.log(i);
	}
}
for(i = 0; i < 10; i++) {
	genericFunctionName();
}

Dans la fonction, nous avons rajouté le mot clé var pour spécifier que la variable n’appartenait qu’à cette fonction. Les deux bouclent ne pointent plus sur la même variable même si leurs noms sont les mêmes. C’est très important pour le développeur de savoir qu’il est le seul maître sur les variables qu’il crée pour créer un code particulier. Ceci nous donne la première application concrète des portées.

Créer son espace de travail sécurisé

En tant que développeur, vous allez créer ou modifier du code sur des pages dont vous ne maîtrisez pas l’environnement. Entre l’historique du code, vos collègues et les publicités ou les widgets, beaucoup de variables sont créées ou écrasées au niveau global sans que vous ne puissiez le prévoir. Au milieu de cette tourmente, je vous propose de vous créer un petit havre de paix :

(function() { 
}()) 

Je vous conseille de démarrer tout fichier javascript ou tout code entre balise <script> par la première ligne et de toujours terminer par la dernière. Ce bout de code vous permet de poser les bases de votre portée et de créer des variables qui n’appartiennent qu’à vous, sans pour autant s’isoler du reste du monde.

(function() {
	var privateVariable = true;
	window.init = function() {
		console.log( privateVariable );
	}
}())
init(); // true
console.log(privateVariable); // undefined 

Exécutez ce code, et vous verrez que privateVariable n’est pas accessible de l’extérieur, mais que le code défini à l’intérieur permet d’y accéder. Très pratique en environnement hostile. Vous remarquerez aussi que l’on rattache la fonction init directement à la portée globale, afin qu’elle soit elle aussi visible de l’extérieur.

Les fonctions

C’était si simple …

Il est facile de créer une fonction et de l’exécuter. Les syntaxes que vous utilisez au quotidien sont celles ci :

// création v1
function action() {}
// création v2
action = function() {};
// exécution
action();

Simple non ?

La fausse bonne idée

Au fait quelle est la différence entre les deux manières de déclarer une fonction ? Pour la première ( function nom() ) le compilateur JavaScript extrait toutes les définitions et les met à disposition au niveau global AVANT de commencer l’exécution. Concrètement vous pouvez même exécuter la fonction avant qu’elle ne soit créée dans la source.

// exécution avant la définition !
action();
// création
function action() {}

Cool ? Pas vraiment : c’est systématiquement la dernière déclaration dans la source qui est prise en compte par les interpréteurs JS. Vous ne pouvez pas conditionner la définition des fonctions. Par exemple le code suivant ne va pas s’exécuter comme vous pourriez le penser :


if( 1 == 1 ) {
	// l'exécution du code passe ici ...
	function action() {
		console.log('a == 1');
	}
} else {
	// ... pourtant le compilateur se souvient de cette fonction
	function action() {
		console.log('a != 1');
	}
}
action(); // a != 1 

Lors de l’exécution, l’interpréteur passe bien dans le premier if et pourtant c’est la seconde définition qui est retenue, uniquement parce qu’elle arrive en dernier dans la source.
Et malgré cela, contrairement à d’autres langages, la déclaration d’une fonction n’est valable que pour la portée en cours et ses descendantes. Dans le code suivant, la fonction action n’est pas visible au niveau global :

(function() {
	function action() {
		console.log('action');
	}
}())
action(); // undefined

La manière traditionnelle de déclarer les fonctions est donc assez trompeuse et de ce fait tombe doucement en désuétude. Pour des débutants on utilisera plutôt la seconde méthode qui a le mérite de pouvoir explicitement choisir la portée de ses fonctions, au même titre qu’une variable

var action = function() {};

En ce qui concerne le compilateur cette syntaxe est une variable avec pointeur sur une fonction anonyme. Le désavantage est que lorsque vous utilisez un débogueur pas à pas, la pile d’appels (call stack) ne vous affiche pas le nom des fonctions (l’anonymat sur Internet existe donc). Vous pouvez retrouver le nom de la variable assignée simplement en cliquant sur la fonction et en regardant dans la source.

Particularités Javascript

JavaScript a rajouté plusieurs particularités aux fonctions qui les rendent terriblement puissantes et flexibles. En fait toutes les constructions de code un peu élaborées telles que l’orientation objet ou l’application de design pattern se basent sur ces spécificités. Nous entrons donc dans le coeur de JavaScript.

Auto-exécution

En rajoutant simplement une paire de parenthèses après une déclaration, la fonction va immédiatement être exécutée.

var autoInit = function() {
	console.log('hello world');
}();
// hello world

Comme nous l’avons vu tout à l’heure, cela vous permettra principalement de créer des portées, pour protéger l’ensemble de votre script, et nous allons voir dans une minute que vous pouvez aussi l’utiliser dans certains cas particuliers.

Classe ou fonction ?

En JavaScript, tout est objet. Un objet n’est jamais qu’une collection de clés et de valeurs, et les valeurs peuvent être tout et n’importe quoi y compris d’autres objets. Lorsqu’une fonction est créée, automatiquement JavaScript y rajoute la propriété prototype. Tapez le code suivant dans votre console JavaScript :

var myFunction = function() {};
console.log( myFunction.prototype ); // Object

Nous avons donc un objet myFunction.prototype et nous pouvons directement y accéder pour y rajouter des valeurs, comme d’autres fonctions par exemple. Ensuite pour accéder à ces fonctions, nous allons utiliser le mot clé new.

// cette innocente fonction devient un constructeur
var myClass = function () {
	this.publicVariable = 0;
};
// accès au prototype
myClass.prototype = {
	decrement:function() {
		console.log( --this.publicVariable );
	},
	increment:function() {
		console.log( ++this.publicVariable );
	}
};

myObject = new myClass();
myObject.decrement(); // -1
myObject.decrement(); // -2

myObject2 = new myClass();
myObject2.increment(); // 1
myObject2.increment(); // 2

Entre nous, nous venons de créer quelque chose qui ressemble furieusement à une classe, avec une instanciation (new myClass), des variables propres à chaque instance ( this.publicVariable ) et un constructeur (le corps de la fonction).

Orienté objet ?

Si vous trouvez bizarre qu’une fonction se transforme soudainement en classe puis en objet, attendez de voir la suite. Toujours grâce à la notion du tout objet de JavaScript, nous pouvons également faire de l’héritage ! Là encore, en utilisant .prototype, nous allons créer une nouvelle fonction (ou classe) qui va hériter des méthodes de la première. Outre la déclaration de la nouvelle fonction, cela ne va prendre que deux lignes.

mySubClass = function() {
	// maintenant on part de 10 au lieu de 0
	this.publicVariable = 10;
};
mySubClass.prototype = myClass.prototype;
mySubClass.prototype.constructor = mySubClass;

myObject2 = new mySubClass();
myObject2.increment(); // 11
myObject2.increment(); // 12

La première ligne après la déclaration de fonction fait pointer l’objet .prototype de notre nouvelle fonction vers l’objet .prototype de la classe mère, empruntant ainsi toutes ses propriétés. La seconde ligne est là pour rectifier un défaut de l’écrasement de .prototype : on refait pointer .prototype.constructor (encore une propriété automatiquement créée pour toutes les fonctions) vers le bon constructeur.

Slip ou caleçon ?

Pardon je voulais dire : pour les classes, vous êtes plutôt prototype ou closure ? On vient de voir que grâce à .prototype on pouvait émuler une classe en JavaScript. Les fonctions peuvent également renvoyer des objets simples contenant des propriétés et des méthodes, et la manière de les utiliser se rapprochera toujours terriblement d’une classe.

myClass = function () { 
	// variable privée !
	var privateVariable = 0; 
	// méthodes publiques
	return { 
		decrement:function() { 
			console.log( --privateVariable ); 
		}, 
		increment:function() { 
			console.log( ++privateVariable ); 
		} 
	} 
};
myObject = myClass(); 
myObject.decrement(); // -1 
myObject.decrement(); // -2 
myObject2 = myClass(); 
myObject2.increment(); // 1 
myObject2.increment(); // 2

Plusieurs différences par rapport à la version prototype :

  • Notez le return {...} dans la définition de la fonction : vous pouvez y mettre exactement ce que vous auriez mis dans le prototype.
  • Vous pouvez utiliser la portée de la fonction constructeur pour avoir des variables privées (ici var privateVariable), alors qu’il n’est pas possible d’avoir des variables privées avec prototype
  • Lorsque vous instanciez votre classe, vous n’avez plus besoin d’utiliser new myClass(), un simple appel sans new suffit.
  • Le mot clé this désigne l’objet renvoyé, alors qu’avec prototype il désignait le corps de la fonction constructeur. Généralement avec closure on n’utilise plus du tout this
  • la création des fonction est évalué à chaque fois que vous invoquez la fonction constructeur, tandis que ce n’est fait qu’une seule fois avec prototype. N’utilisez jamais closure avec des objets qui peuvent être instanciés des centaines de fois.

Voilà pour l’essentiel sur les fonctions : avec cela vous maîtrisez déjà leur portée et vous pouvez commencer à développer orienté objet, ce qui va vous permettre d’éviter beaucoup de bug et d’avoir un code plus maintenable.

Le contexte ou this

this est le petit mot clé qui perd beaucoup de développeurs, notamment lorsque l’on est habitué aux dérivés du C comme PHP. En JavaScript comme ailleurs, il fait référence au contexte d’exécution, donc le code suivant s’exécutera probablement comme vous vous y attendez :

myClass = function() { 
	this.id = 'myClass'; 
} 
myClass.prototype = { 
	action:function() { 
		console.log( this.id ); 
	} 
}; 
myObject = new myClass(); 
myObject.action(); // 'myclass'

Ici on a défini dans le constructeur this.id avec une certaine valeur, puis on instancie la classe (new myClass()) et la méthode action() accède tout naturellement à this pour retrouver la valeur de id.
Pourtant lorsque vous voulez exécuter myObject.action au clic sur un élément du DOM, plus rien ne marche comme prévu.

document.body.onclick = myObject.action; 
// document.body.id
 


Vous pouvez exécuter les deux bouts de code précédent dans votre console JavaScript et cliquer sur la page, vous verrez que this.id n’est plus ‘myClass’ mais fait référence à l’id du body, qui n’existe peut être même pas. Ceci n’est pas particulier au DOM d’ailleurs, imaginez que vous créiez un autre objet qui aurait un événement onfire que vous auriez besoin d’écouter :

myEvent = { 
	id:'myEvent' 
};
myEvent.onfire = myObject.action; 
myEvent.onfire(); // 'myEvent' au lieu de 'myClass'


Lorsque onfire() s’exécute, il exécute bien le corps de la fonction action, mais comme pour les objets du DOM, this fait référence à l’objet d’où est exécutée la fonction, pas forcément à l’objet d’origine de la fonction.
Ceci est du à la versatilité de JavaScript qui permet de très simplement copier le corps d’une fonction d’un objet à l’autre, alors que dans les langages traditionnels orienté objet il vous faut explicitement faire de l’héritage. Comment fixer cela ? Il y a au moins deux méthodes.

Changement de contexte (natif)

La première méthode est native à JavaScript et utilise la fonction .call(). Ici seule la dernière ligne a changé :

myClass = function() { 
	this.id = 'myClass';
} 
myClass.prototype = { 
	action:function() { 
		console.log(this.id); 
	} 
}; 
myObject = new myClass(); 
myEvent = { 
	id:'myEvent' 
};
myEvent.onfire = myObject.action; 
myEvent.onfire.call( myObject ); // myClass


Le premier argument de la fonction .call() est l’objet qui sera utilisé pour this. Ici on redonne à onfire l’objet d’origine de la fonction action.
Le problème avec cette solution, c’est qu’il faudrait que vous soyez certain que TOUS les endroits où votre fonction peut être appelée vont rectifier le contexte d’exécution. Hors ne serait ce que pour les événement natifs du DOM cela n’est pas possible, sauf si vous utilisez une bibliothèque de manière systématique. Donc faire confiance à this n’est raisonnable que si vous maîtrisez parfaitement tout le code qui sera écrit.

Conservation du contexte (à la main)

Pour éviter ces problèmes de maintenance, la solution en vogue est de tout simplement ne jamais utiliser this directement et de préférer utiliser la syntaxe closure et une variable privée pour définir ses classes.

myClass = function() { 
	this.id = 'myClass';
	// capture du contexte
	var me = this;
	return {
		action:function() {
			console.log( me.id );
		}
	}
};
myObject = myClass(); 
document.body.onclick = myObject.action; 
// 'myClass'


On voit donc ici :

  • dans le constructeur, on capture le contexte avec une variable privée : var me = this
  • dans la fonction action on n’utilise plus this mais me

Peu importe l’endroit d’où est lancé la fonction (ici au clic sur la page), et peu importe la valeur réelle de this, on est maintenant certain que l’on aura toujours un accès à l’objet originel grâce à une variable privée. Bien sur this reste utilisable normalement, notamment si vous avez besoin de retrouver l’objet DOM cliqué par exemple.

Pour encore plus de souplesse avec les fonctions de JavaScript, allez voir la deuxième partie de cet article.

L’essentiel

Si vous ne deviez retenir que quelques points, les voici :

  • JavaScript a des concepts différents des langages majeurs et devient extrêmement important sur votre CV. Prenez le temps de l’apprendre
  • Les bibliothèques telles que jQuery ne sont pas faites pour couvrir les cas que nous venons de voir. jQuery permet d’utiliser le DOM sereinement, pas d’organiser votre code proprement.
  • Lorsque vous créez une classe, choisissez la syntaxe prototype pour la performance ou closure pour les variables privées et la maîtrise du contexte d’exécution
  • N’utilisez plus la syntaxe function maFonction() {}
  • Utilisez systématiquement la fonction anonyme auto-exécutée ( (function() { var .. }())) en début et fin de fichier ou de <script>
  • Utilisez systématiquement var pour vos variables, y compris celles qui font référence à des fonctions

Dernière chose : j’ai essayé d’être pratique, mais lire un post de blog ne suffit jamais pour comprendre des concepts de programmation : codez !

22 commentaires vers "JavaScript : 3 fondamentaux"

  1. switcherdav's Gravatar switcherdav
    11/17/2011 - 10:29 | Lien permanent

    Super article, merci pour le partage de connaissances

  2. 11/17/2011 - 12:02 | Lien permanent

    Merci d’avoir écrit cet article, il y a un manque de ressources en français sur JavaScript.

  3. 11/20/2011 - 18:34 | Lien permanent

    Merci pour cet article, toujours bien de reprendre les bases, je vois le même constat dans d’autres domaines notamment dans les webperfs, certaines équipes n’y sont pas du tout sensibilisées.

  4. 11/21/2011 - 12:22 | Lien permanent

    Hello jpv,
    super article ! Merci pour le partage.
    Je comprends mieux le fonctionnement des fonctions :)
    Au plaisir de te lire.

  5. Gouigouix's Gravatar Gouigouix
    11/22/2011 - 16:10 | Lien permanent

    Bonjour à tous,

    Attention dans ton exemple la fonction init() ne peut pas retourner true puisqu’elle est imbriquée dans une autre fonction ! Elle reste indéfini à l’extérieure de celle-ci comme la variable privateVariable.

    >> (function() {
    var privateVariable = true;
    function init() {
    console.log( privateVariable );
    }
    }())
    init();
    « « init » est indéfini »

  6. betadev's Gravatar betadev
    12/22/2011 - 14:38 | Lien permanent

    Excellent article , vraiment excellent !!!

  7. PEM's Gravatar PEM
    01/05/2012 - 12:32 | Lien permanent

    Salut Jean-Pierre,
    Travaillant quotidiennement avec JavaScript, je tenais à dire que j’ai trouvé cet article très bien !
    En revanche, si JQuery n’es pas vraiment taillé pour la POO, d’autres framework / toolkits le font pas mal du tout, comme Dojo Toolkit, par exemple, qui est compatible, dans sa version 1.7, avec les loader AMD :)
    Je pense que trop de développeur aborde JavaScript avec des paradigmes issus de langages tels que Java.
    Nous n’insistons pas assez sur le besoin d’oublier nos vielles habitudes de POO et d’essayer d’aborder JS avec une base vide, sans vielles refs :)

  8. 01/05/2012 - 13:31 | Lien permanent

    @PEM concernant la POO, moi le premier j’ai voulu réutiliser mes connaissances de PHP pour faire du JS. ça marche bien, j’ai même construit un très gros projet avec cette logique mais c’est vrai que plus tu rentres dans Javascript et plus tu te dis que la POO façon Java / PHP et les autres n’est pas la seule manière de programmer

  9. JackBenoit's Gravatar JackBenoit
    01/11/2012 - 15:47 | Lien permanent

    Merci bcp pour cet article. Ca fait 5 ans que je fais du javascript « en mode JAVA »
    sans vraiment connaitre et comprendre ces subtilités -de base- de syntaxe !
    je me sens moins bête là ;)

  10. 02/22/2012 - 11:35 | Lien permanent

    Salut,

    Je redécouvre ton article dans ma pile de ressources pour ma prochaine conférence sur le modèle objet en JS. Si ça ne te dérange pas, je vais peut-être même citer certains de tes propos. Certaines de tes formulations sont parfois plus parlantes que les miennes. Bien entendu, en citant l’auteur.
    Et d’avance je te remercie car j’avais oublié de parler de certaines choses que ce billet m’a remémoré. Pratique, j’étais un peu court d’un point de vue durée.

    Cordialement,
    Mathieu

  11. 02/22/2012 - 18:29 | Lien permanent

    Pas de problème mathieu, et merci de le citer ça fait plaisir :)
    Bonne chance pour ta présentation !
    Tu la fais à quelle occasion.

  12. Brocoli's Gravatar Brocoli
    02/22/2012 - 23:25 | Lien permanent

    Hello,

    Je ne comprends pas le fondement de la syntaxe :

    (function() {
    }())

    A quoi servent les parenthèses devant et à la fin ?

    Je comprends le principe de cloisonner son espace de travail dans une portée de locale, mais ne pourrait-on peut pas écrire simplement la chose suivante ? :

    function () {
    // code
    }

    Merci (sinon super article :) ).

  13. 02/23/2012 - 09:02 | Lien permanent

    En théorie function() {} suffit effectivement.
    Mais si tu tapes cela dans une console JS cela fait une parse error. Pour passer l’interpreteur JS il faut rajouter la première paire de () autour :
    (function(){})
    Là ton scope est bien créé. Cependant ta fonction est anonyme donc non-exécutable et le code à l’intérieur n’est pas exécuté. D’où la dernière paire de parenthèses après la définition de la fonction qui permet d’exécuter immédiatement la fonction à peine créée.
    (function(){})()
    la paire de parenthèses qui permet l’auto-exécution peut se placer aussi comme ceci :
    (function(){}())

  14. Brocoli's Gravatar Brocoli
    02/25/2012 - 00:07 | Lien permanent

    Ok merci !

    Encore une petite remarque.

    D’après un bouquin que j’ai sur Javascript il est possible de donner un nom à des fonctions littérales.

    Du coup au lieu d’écrire par exemple :

    var action = function() {};

    Je pourrais écrire :

    var action = function action() {};

    Ça fonctionne et j’ai la fonction action qui s’affiche dans la pile d’appels (et non plus une fonction anonyme). Par contre je trouve ça un peu crado vu qu’on nomme à priori 2 fois une fonction… Qu’en penses-tu ?

  15. 03/28/2012 - 11:50 | Lien permanent

    Salut, désolé, je n’avais pas vu ta réponse à mon commentaire sur le moment. J’ai tenu cette conférence à l’occasion de la ConFoo 2012.

    Si ça t’intéresse, j’ai mis les slides à dispo ici : http://www.slideshare.net/mathrobin/poo-et-java-script-notion-trop-incomprise . Elles sont en cours de refonte, des trucs sont en trop, des trucs manquent, enfin elles ne sont pas définitives de toute façon

  16. 08/18/2012 - 21:30 | Lien permanent

    Bonjour,
    ce bout de code affiche :
    if( 1 == 1 ) {
    // l’exécution du code passe ici …
    function action() {
    console.log(‘a == 1′);
    }
    } else {
    // … pourtant le compilateur se souvient de cette fonction
    function action() {
    console.log(‘a != 1′);
    }
    }
    action(); // a != 1

    a==1 et non a!=1
    Normal, puisqu’il rentre dans la condition de 1 ==1
    C’est ce qui sort dans mon console.log
    Une explication ?

  17. 09/19/2012 - 11:18 | Lien permanent

    Merci
    Un très bon article absolument nécessaire à un moment où on attaque directement avec jQuery sans étudier quelques bases

  18. Jo's Gravatar Jo
    06/14/2013 - 08:58 | Lien permanent

    Bonjour ! En premier lieu merci pour cet article qui a le grand mérite de mettre un peu de lumière sur certains points autrement difficiles à cerner avec le reste de la documentation sur internet.
    J’aurais cependant juste une question, par rapport à ce code :
     » myClass = function () {
    // variable privée !
    var privateVariable = 0;
    // méthodes publiques
    return {
    decrement:function() {
    console.log( –privateVariable );
    },
    increment:function() {
    console.log( ++privateVariable );
    }
    }
    };
    myObject = myClass();
    myObject.decrement(); // -1
    myObject.decrement(); // -2
    myObject2 = myClass();
    myObject2.increment(); // 1
    myObject2.increment(); // 2″
    J’ai d’abord cru que lors de son instanciation, myClass() ne renvoyait qu’un objet littéral composé des méthodes increment() et decrement(), bref ce qui se trouve après le return. Je pensais ainsi que le rôle de ces deux méthodes au sein de chaque instance était d’aller modifier la privateVariable qui elle, était unique et propre à myClass… Ainsi je croyais bêtement qu’après « myObject.decrement(); // -2″, en instanciant un 2eme objet, myClass() avant pour effet interne à myClass de « réinitialiser » privateVar à 0… Mais en fait pas du tout :) En rajoutant une petite méthode show() et l’appliquant à la première instance myObject mais à la fin du script pour voir l’état de la dite variable, je me suis aperçu que celle-ci affichait toujours -2 au lieu de 2 comme je m’y attendais. Voici donc ma question :
    Est-ce que cette privateVariable a été copiée dans chaque instance uniquement parce que dans le constructeur myClass, une référence y était faite dans increment() et decrement() ou bien est-ce que chaque fois qu’on instancie un Constructeur de cette façon (sans new) l’ensemble de ses variables privées sont copiées dans les instances, qu’une référence y est été faite dans une méthode ou non ?

    Bien cordialement.
    Jo

  19. Jo's Gravatar Jo
    06/14/2013 - 14:38 | Lien permanent

    Je retire ma question, je n’avais pas eu le temps de tout explorer et grâce à votre lien (http://fgribreau.com/articles/voyage-au-coeur-de-javascript.html), j’ai trouvé la réponse. Merci encore !

Laisser un commentaire

7 Trackbacks vers "JavaScript : 3 fondamentaux"

  1. sur 11/17/2011 at 12:02
  2. sur 01/12/2012 at 22:11
  3. sur 02/08/2012 at 11:27
  4. sur 03/22/2012 at 17:46
  5. sur 03/28/2012 at 14:14
  6. sur 03/28/2012 at 14:18
  7. sur 05/08/2012 at 12:31