notes·de·pit - Mot-clé - javascriptParfois j'apprends à pêcher à des gens qui n'aiment pas le poisson2023-06-13T11:41:09+02:00PiTurn:md5:45526db4e4cfb511098640352c276065DotclearJavascript c'est (pas) comme Javaurn:md5:0c11bc485cb1f2843f45d716e29f96662015-10-10T12:27:00+02:002015-10-11T16:28:46+02:00PiTMes doigts dans le clavieresigeekjavajavascript<p><img src="https://blog.namok.be/public/images/divers/2015/blue_duck_by_sudlice-d7x15ds.jpg" alt="blue_duck_by_sudlice-d7x15ds.jpg" style="margin: 0 auto; display: block;" title="blue_duck_by_sudlice-d7x15ds.jpg, oct. 2015" /></p>
<p><em>ou « J'ai lu pour vous "<a href="http://shop.oreilly.com/product/0636920027065.do">Head first. Javascript Programming</a>" »</em></p>
<p><br/></p>
<hr />
<p><a href="https://blog.namok.be/?post/2015/10/10/javascript-versus-java#vocabulaire">Vocabulaire et concepts</a><br />
<a href="https://blog.namok.be/?post/2015/10/10/javascript-versus-java#type">Type</a><br />
<a href="https://blog.namok.be/?post/2015/10/10/javascript-versus-java#compilation-interpretation">Compilation, interprètation</a><br />
<a href="https://blog.namok.be/?post/2015/10/10/javascript-versus-java#closure">Closure et <em>first class value</em></a><br />
<a href="https://blog.namok.be/?post/2015/10/10/javascript-versus-java#inheritence">Héritage par prototype <em>versus</em> héritage classique (par classe)</a><br />
<a href="https://blog.namok.be/?post/2015/10/10/javascript-versus-java#falsey">falsex - trusthy</a></p>
<hr />
<p><br/></p>
<p>Javascript, c'est comme Java car il contient le mot <em>Java</em>.<br />
Javascript, c'est comme Java car une grande partie de la syntaxe est pareille:</p>
<ul>
<li>les accolades <code>{}</code> sont les délimiteurs de blocs;</li>
<li>les mots clés de base sont les mêmes (<code>do while for if else break continue
return switch throw try catch instance(o/O)f</code>…);</li>
<li>les littéraux numériques et logiques sont pareils;</li>
<li>les opérateurs arithmétiques, logiques et de comparaison — même
l'opérateur ternaire — existent dans les deux langages;</li>
<li>les commentaires se mettent aussi entre <code>/* */</code>;</li>
<li>les noms de variables contiennent des caractères, des chiffres et <code>$</code> et
<code>_</code>;</li>
<li>il est possible de définir des objets et tous héritent — attention, la
notion d'héritage est différente — de <code>Object</code>;</li>
<li>il existe des objets prédéfinis qui s'appellent; <code>Object</code>, <code>Date</code>, <code>String</code>,
<code>Math</code>…;</li>
</ul>
<p><br/></p>
<p><strong><em>It's all folks !</em></strong><br />
<strong>C'est tout les gars !</strong></p>
<p><br/></p>
<p>La similitude s'arrête là.<br />
Javascript ce n'est pas comme Java.</p>
<h2 id="vocabulaire">Vocabulaire, concepts et usage</h2>
<p>Java traite avec des classes, des interfaces, des objets, des attributs, des
méthodes (éventuellement) statiques tandis que Javascript manipule des objets,
des propriétés et des fonctions.</p>
<p>Certains concepts — s'ils ne sont pas semblables — sont (très) proches.
D'autres pas du tout. C'est à cette question que tente de répondre l'article
^^</p>
<p>L'usage que l'on veut faire du langage est très différent. Là où Java est un
langage orienté <em>desktop</em> et applications d'entreprise, Javascript est
interprèté par le navigateur et, de ce fait, il est très orienté applications
web. Il est très fort pour ça. Il s'intègre parfaitement avec HTML et CSS. Avec
<a href="https://nodejs.org/en/">Node.js</a> il se retrouve maintenant du côté serveur et des librairies
telles que <a href="http://nwjs.io">nw.js</a> le place également dans les applications desktop.</p>
<h2 id="type">Type</h2>
<p>Java est un langage fortement typé. Java demande que l'on déclare une variable
avant de l'utiliser. Le contenu de cette variable devra être (à conversion
près) du type annoncé. En Javascript, pas besoin de définir le type lors de
la « déclaration » d'une variable et, même si les expressions ont un type, une
variable peut recevoir n'importe quel type de valeur… et en changer au fur et
à mesure de l'exécution du programme.</p>
<p>Le mot clé <code>var</code> précisera le <em>scope</em> de la variable. Une variable pourra être
globale ou locale.</p>
<p>Une variable Javascript peut même recevoir une fonction comme valeur.</p>
<pre class="brush: js; gutter: false;">
var foo = function() {
// insert code
};
</pre>
<p>En Javascript, on a ce que l'on appelle, le <em>duck typing</em></p>
<blockquote>
<p>Si ça vole comme un canard, cancane comme un canard et nage comme un canard
alors, c'est un canard.<br />
<em>Javascript guy</em></p>
</blockquote>
<pre class="brush: js; gutter: false;">
var foo = "I'm a String"
// foo is a string
foo = new Duck()
// now, it's a duck
</pre>
<p>En Java, une variable a un certain type et le type de l'instance doit être le
même ou être un enfant.</p>
<blockquote>
<p>Si c'est un canard alors… c'est un canard.<br />
<em>Java guy</em></p>
</blockquote>
<pre class="brush: java; gutter: false;">
Duck duck = new Duck();
// duck is a duck
Bird bird = new Duck();
// bird is Bird type and Duck type instance
// Duck must inherit from Bird
</pre>
<h2 id="compilation-interpretation">Compilation, interprètation</h2>
<p>Java est un langage <strong>compilé et interprèté</strong>. Le compilateur — qui
génère le <em>bytecode</em> exécuté par la machine virtuelle Java — vérifiera la
concordance des types lors de son analyse sémantique. Au <em>runtime</em> une
seconde vérification aura lieu afin de voir si le type de l'instance est bien
du type attendu.</p>
<p>Javascript est un langage interprèté par le navigateur. L'interprètation se
fait en deux passes. Lors de la première passe, le navigateur interprète les
déclarations de fonctions et les « mémorise ». Dans un second temps, il
interprète tout le reste.</p>
<p>Il est possible en Javascript de déclarer des fonctions de deux manières
différentes.</p>
<p>La méthode classique — au sens, semblable aux autres langages:</p>
<pre class="brush: js; gutter: false;">
function foo() {
// insert code
}
</pre>
<p>La méthode « déclaration de variable » puisqu'une variable peut être une
fonction:</p>
<pre class="brush: js; gutter: false;">
var foo = function() {
// insert code
};
</pre>
<p>La seule différence entre ces deux notations est le moment où elles sont
évaluées. Dans le premier cas, l'évaluation est faite lors de la première
passe et dans le second cas, lors de la deuxième passe. Cela peut, bien
sûr, avoir une influence sur le code.</p>
<p><strong>Remarque</strong> Pour tester facilement du code Javascript, installez <a href="http://getfirebug.com/">firebug</a></p>
<h2 id="closure">Closure et <em>first class value</em></h2>
<p>Les fonctions Javascript — à l'inverse des méthodes (statiques) Java — sont
des <em>first class values</em> (valeurs de première classe, traduction libre). Une
<em>first class value</em>:</p>
<ul>
<li>peut être assignée à une variable (ou un tableau, une <em>map</em>);</li>
<li>peut être passée en paramètre d'une fonction;</li>
<li>peut être retournée par une fonction</li>
</ul>
<p>Javascript permet donc d'écrire:</p>
<pre class="brush: js; gutter: false;">
function addN(n){
var adder = function(x){
return x+n;
}
return adder;
}
var add2 = addN(2);
var result = add2(3), // result equals 5
</pre>
<p>Allons un pas plus loin comme le propose <a href="http://shop.oreilly.com/product/0636920027065.do">Head First Javascript</a> et
écrivons: </p>
<pre class="brush: js; gutter: false;">
var foo = "Global";
function bar(){
var foo = "Local";
function inner(){
return foo,
}
return inner; // return the function
}
var baz = bar();
var result = baz();
// result equals Local or Global ?
</pre>
<p>Puisque l'on retourne une fonction, l'appel à <code>baz</code> est un appel de la
fonction <code>inner</code>… puisque <code>bar</code> retourne cette fonction <code>inner</code>.</p>
<p>La question de savoir que retourne la fonction <code>baz</code> est la même que de se
demander si Javascript retourne la variable locale ou la variable globale. Mon
raisonnement — si je suis habitué à des langages comme Java et C++ et que je
suis l'appel des méthodes, la création / destruction des variables locales
— me dit que c'est <code>"Global"</code> qui est retourné. En effet, je pense — à tort
comme nous allons voir — que comme la fonction <code>bar</code> n'est appelée qu'une
seule fois lors de l'assignation de <code>bar</code> à <code>baz</code>, la variable locale <code>foo</code>
n'existe plus lors de l'appel à <code>baz</code>.</p>
<p>— C'est sans compter sur les closures, mon bon.<br />
— Qu'est-ce donc, mon brave ?</p>
<p>Une <strong>closure</strong> est une fonction <strong>et</strong> l'environnement dans lequel elle est
définie. Dans l'exemple, lorsque <code>bar</code> retourne <code>inner</code>, elle retourne aussi
l'environnement de <code>bar</code>… à savoir la variable locale <code>foo = "Local"</code>. Dès
lors, quand <code>baz</code> est appelé, <code>inner</code> est exécutée dans l'environnement dans
lequel elle a été définie. Elle retourne donc la valeur <code>"Local"</code>.</p>
<blockquote>
<p><strong>closure</strong> n.f. Une fonction et son environnement c'est-à-dire le contexte
dans lequel elle a été définie.</p>
</blockquote>
<p>Les fonctions Javascript sont donc toujours évaluées dans l'environnement dans
lequel elles ont été définies. Leur <em>lexical scope</em>, portée lexicale. Grâce
à ce concept, on pourra éviter l'utilisation de variables globales. <em>Les
variables globales, c'est le mal</em>.</p>
<p>Là où je pourrais avoir envie d'écrire (mais c'est mal, rappelle-toi):</p>
<pre class="brush: js; gutter: false;">
var count = 0;
function counter() {
count++;
return count;
}
// counter(); counter()…
</pre>
<p>avec les <em>closures</em>, je peux me passer de la variable globale en ajoutant « un
niveau de fonction » comme suit:</p>
<pre class="brush: js; gutter: false;">
function makeCounter() {
var count = 0;
function counter() {
count++;
return count;
}
return counter;
}
var do = makeCounter();
// do(); do(); do()
</pre>
<p>La variable <code>count</code> est une <strong>variable libre (<em>free variable</em>)</strong> dans la
fonction <code>counter</code>, elle n'est pas globale, ni locale ni un paramètre. La
closure est faite par la fonction <code>makeCounter</code> qui retourne la fonction
<code>counter</code> et son environnement. Environnement qui contient la variable
<code>count</code>. Même après l'appel (unique) à la méthode <code>makeCounter</code>, la variable
(locale à <code>makeCounter</code>) continue d'exister dans l'environnement de la
fonction <code>counter</code>.</p>
<p>Nous verrons plus encore l'utilité de ceci lorsque l'on voudra programmer en
orienté objet — et donc mettre en œuvre l'héritage et le polymorphisme — et
que l'on constatera que Javascript n'implémente pas la notion classique par
classes de l'orienté objet mais un héritage par prototype.</p>
<h2 id="inheritence">Héritage par prototype <em>versus</em> héritage classique (par classes)</h2>
<p>Javascript permet de créer des <em>objects literals</em> (des littéraux objets) qui
représentent une instance d'un objet. Un objet a des propriétés et des
fonctions.</p>
<pre class="brush: js; gutter: false;">
var duck = {
name: "Ducky",
// …
foo: function() {
// code function
}
}
</pre>
<p><strong>Comment faire pour déclarer une classe et instancier moult objets de la même
classe ?</strong></p>
<p>Java permet de déclarer une classe. Cette classe contient des membres
— attributs, méthodes et constructeurs — statiques ou non. Les membres
statiques sont partagés par toutes les instances. Les autres sont propres
à une instance.</p>
<pre class="brush: java; gutter: false;">
public class Duck{
protected String name;
public Duck(String n){
this.name = n;
}
public void foo() {
// code method
}
}
Duck duck = new Duck("Ducky");
</pre>
<p>Javascript permet de créer un constructeur et d'instancier des objets à partir
de ce constructeur et du mot clé <code>this</code>. Un constructeur est une fonction
contenant des propriétés — précédées de <code>this</code> qui référence l'objet — et des
fonctions. Par convention ce constructeur s'écrit en <em>CamelCase</em> — le nom
commence par une majuscule — comme en Java.</p>
<pre class="brush: js; gutter: false;">
function Duck (name){
this.name = name;
// …
this.foo = function() {
// code function
};
}
var duck = new Duck("Ducky");
</pre>
<p>Javascript va créer toutes les propriétés définies dans le constructeur
<strong>y compris les fonctions</strong> pour toutes les instances. Une fonction sera donc
présente — avec son environnement — autant de fois que l'objet est instancié.
C'est un problème.</p>
<p>La solution est le <strong>prototype</strong>. Ce prototype est une propriété du
constructeur. Dans ce prototype (unique) peuvent se trouver des propriétés et
des fonctions. Ces propriétés et fonctions sont communes à toutes les
instances créées à partir du constructeur.</p>
<p>Si l'on ajoute des propriétés ou des fonctions au prototype alors que des
objets ont déjà été créés, pas de soucis. Toutes les instances présentes et
à venir en bénéficieront. Si l'on décide de réécrire une fonction dans une
instance particulière seule cette instance bénéficiera de la réécriture.
Javascript cherche une propriété ou une fonction dans l'objet. S'il ne trouve
pas, il cherche dans le prototype. On écrira donc quelque chose à l'allure
suivante:</p>
<pre class="brush: js; gutter: false;">
function Duck(name){
this.name = name;
// …
}
Duck.prototype.foo = function() {
// code function
}
</pre>
<p>Si une propriété définie dans le prototype — et donc disponible et partagée
par toutes les instances — est changée par une instance alors une copie de
cette propriété est attribuée à l'instance. La valeur initiale, celle dans le
prototype est conservée.</p>
<pre class="brush: js; gutter: false;">Duck.prototype.bar = false;
Duck.prototype.baz = function() {
this.bar;
// bar = false, it's prototype value
this.bar = true;
// new bar property for this
}
var duck = new Duck("Ducky");
duck.baz()
// duck have now new property bar. value is true
</pre>
<p>Il est possible d'avoir une chaine de prototypes. C'est « l'héritage par
prototype ». Là où Java — via le mot clé <em>extends</em> — permet de créer une
nouvelle classe, Javascript — et son héritage par prototype — demande de
préciser que le prototype est celui du parent. Pour écrire correctement un
objet enfant en Javascript, on peut écrire:</p>
<pre class="brush: js; gutter: false;">
function Child() {
Parent.call(this, …);
// some code
}
Child.prototype = new Parent();
Child.prototype.constructeur = Child;
Child.prototype.foo = …
</pre>
<p>Le constructeur de l'enfant appelle le constructeur du parent. Le prototype de
l'enfant est celui du parent. C'est ce qui marque l'héritage. Le constructeur
de l'enfant s'appelle <em>Child</em>. Sans ça, il s'appellerait <em>Parent</em>. Le
prototype de l'enfant est complété. Il est possible de réécrire des fonctions
définies dans le parent.</p>
<p>Comme en Java toutes les classes héritent de la classe <code>Object</code>, en Javascript
tous les constructeurs héritent du prototype de <code>Object</code>. Cet objet propose
quelques fonctions semblables aux méthodes de la classe <code>Object</code> de Java:
<code>toString</code>, <code>hasOwnProperty</code>, <code>valueOf</code>…</p>
<p>En Java, si je veux « enrichir » un objet, j'en hérite ou je réédite la classe
et recompile. Pour les classes du langage, je ne peux pas les compléter. En
Javascript, je peux directement compléter le prototype de n'importe quel
objet. À utiliser avec parcimonie.</p>
<pre class="brush: js; gutter: false;">
String.prototype.foo = function() {…}
</pre>
<h2 id="falsey"><em>falsey - trusthy</em></h2>
<p>Java n'accepte que deux valeurs booléennes; <code>true</code> et <code>false</code>. Lors de
l'évaluation d'une expression booléenne, celle-ci doit donc être vraie ou
fausse. Parfois, on aimerait dire que c'est faux alors que la valeur n'est pas
(vraiment) fausse. On voudrait dire que si c'est <code>null</code> c'est faux ou bien que
si c'est <code>undefined</code>, c'est faux…</p>
<p>Javascript propose la <em>falsey value</em> qui peut apparaitre dans un test.</p>
<blockquote>
<p><em>falsey value</em>: <code>undefined</code>, <code>0</code>, <code>NaN</code>, <code>null</code>, <code>""</code></p>
</blockquote>
<p>Toute valeur qui n'est pas <em>falsey</em> est <em>trusthy</em>.</p>
<p><br/></p>
<p>Javascript et Java sont deux langages différents, plus personne n'en doute
maintenant. Cet article ne pointe que l'une ou l'autre différences <strong>propres au noyau du langage</strong>. Je ne m'intéresse pas ici aux différences dans la gestion des évènements, des entrées / sorties, des formats de communications entre applications…</p>
<p>Il reste énormément à dire sur Java et sur Javascript. Le but n'était pas de présenter les deux langages. Pour aller plus loin, je vous encourage à lire <a href="http://shop.oreilly.com/product/0636920027065.do">Head First Javascript Programming</a>. Pour avoir une introduction d'un autre genre, <a href="http://connect.ed-diamond.com/Linux-Pratique/LPHS-024/">Linux Pratique Hors Série 24</a> nous parle de Javascript, <a href="https://jquery.com">JQuery</a> et <a href="https://angularjs.org/">AngularJS</a>. <a href="http://phantomjs.org/">PhantomJS</a> nous permet d'<a href="http://namok.be/blog/?post/2015/07/29/recuperer-derniere-image-instagram">exécuter du code JS sans navigateur</a>.</p>
<p>Vous pouvez reprendre une activité normale…</p>
<p><br/></p>
<p><br/></p>
<p><em>Crédit photo chez <a href="http://deviantart.com">DeviantArt</a> par <a href="http://sudlice.deviantart.com/art/Blue-Duck-478744192">Sudlice</a>. Si ça vole
comme un canard, cancane comme un canard et nage comme un canard. Alors, c'est
un canard… bleu.</em></p>