Treviso JS Meetup:
Cattive abitudini e
Linee guida
Anti-patterns
(ovvero situazioni da evitare)
Dichiarare variabili senza il "var"
Dichiarando variabili senza il var, automaticamente
andiamo a definirle come Globali.
Da evitare!
name="Paperino";
function stampaPaperino() {
name ="Paperino";
console.log(name);
}
Utilizzando il "var", lo scope (ambiente dove vive la
variabile) diventa quello della funzione in cui è definita.
Corretto!
var name="Paperino";
function stampaPaperino() {
var name ="Paperino";
console.log(name);
}
var a = b = 0;
In questo caso l'interprete riscrive il codice in questo modo:
quindi "b" è globale.
Da evitare!
b = 0;
var a = b;
Questo pattern prevede di dichiarare tutte le variabili
utilizzando un solo "var".
Corretto!
var a = 0,
b = 0;
Sparpagliare variabili all'interno di
una funzione
"pluto" e "paperino" sono dichiarate in due momenti
separati all'interno della funzione.
Da evitare!
function plutoAiutaPaperino() {
var pluto = new Pluto();
pluto.corre();
pluto.mangia();
...
var paperino = new Paperino();
pluto.aiuta(paperino);
}
Più leggibile e evitiamo problemi legati all' "hoisting".
Corretto!
function plutoAiutaPaperino() {
var pluto = new Pluto(),
paperino = new Paperino();
pluto.corre();
pluto.mangia();
pluto.aiuta(paperino);
}
For loops scritti male
"i" in questo caso è globale. Se "list" è un array
particolarmente grande il dover recuperare ad ogni
iterazione il valore di "list.length" rallenta il codice.
Da evitare!
for(i = 0; i < list.length; i++) {
// do something
};
"list.length" in questo caso viene "cachato" nella variabile
"len". ( )
Corretto!
for(var i = 0, len = list.length; i < len; i++) {
// do something
};
http://jsperf.com/loops
Eval is evil
"eval" esegue il codice javascript inserito in una stringa.
Da evitare!
eval('var i = "Welcome Hackers!"; alert(i);');
Usare i costruttori predefiniti al
posto della sintassi "literal".
Qualsiasi cosa in Javascript è un Object, il linguaggio mette
a disposizione dei costruttori che ereditano da Object
implementando nuove funzionalità. "new Array()" ad
esempio crea un oggetto di tipo Array con delle funzionalità
come "pop","push","shift", etc.
Da evitare!
var disney = new Array("Pippo","Topolino","Paperino");
Corretto!
var disney = ["Pippo","Topolino","Paperino"];
Questa sintassi è molto più pulita e condivisa da gran parte
dei linguaggi di programmazione.
Inquinamento Globale
E' buona norma evitare di definire variabili o funzioni nello
"scope globale" perchè sono accessibili e modificabili in
qualsiasi punto dell'applicazione.
C'è il rischio che vengano accidentalmente sovrascritte da
altri programmatori o plugin esterni e rendono il codice
difficile da mantenere.
Da evitare!
<script>
var pluto = new Pluto(),
plutoHouse = new DogHouse({color:red,material:'wood', size: [100,100
function loadPlutoHouse() {
return pluto.load(house);
}
</script>
Tutte le variabili definite nel frammento di codice sopra-
riportato sono globali perchè non sono definite all'interno di
una funzione.
Usare una funzione che viene definita e subito invocata crea
uno "scope isolato". Variabili e funzioni esistono solo
all'interno dell' IIFE.
Corretto!
<script>
// IIFE = Immediately-Invoked Function Expression
(function(document, window, undefined){
var pluto = new Pluto(),
plutoHouse = new DogHouse({color:red,material:'wood', size: [100
function loadPlutoHouse() {
return pluto.load(house);
}
})(document,window);
</script>
Esempio in jQuery
<script>
// IIFE = Immediately-Invoked Function Expression
(function($,document, window){
//code immediately executed goes here
$(function(){
//code executed on document ready goes here
});
})(jQuery, document,window, undefined);
</script>
jQuery
Anti-patterns
Evviva i costruttori!
Ogni volta che usiamo $('...') viene creato un nuovo oggetto
jQuery parsando il DOM e cercando l'elemento
corrispondente. Assolutamente poco performante.
Da evitare!
$('button.confirm').on('click', function() {
// Do it once
$('.modal').modal();
// And once more
$('.modal').addClass('active');
// And again for good measure
$('modal').css(...);
});
jQuery ci permette di "concatenare" più funzioni al
medesimo oggetto $ perchè ogni funzione ritorna l'instanza
dell'elemento DOM jquerizzato.
Soluzione 1: Chaining
$('button.confirm').on('click', function() {
$('.modal')
.modal()
.addClass('active')
.css(...);
});
Salvare il riferimento all'oggetto jQuery per poi riusarlo nel
codice è la soluzione ottimale. In particolare all'interno dei
listener evitiamo di dover "attraversare" il DOM ogni volta
che si scatena l'evento a cui l'ascoltatore è associato.
Soluzione 2: Caching
var $buttonConfirm = $('button.confirm'),
$modal = $('.modal');
$background = $('.bg-overlay');
$buttonConfirm.on('click', function() {
$modal
.modal()
.addClass('active')
.css(...);
$background.removeClass('hidden');
});
L'inferno delle CallBack
Annidare callback porta a codice difficile da capire e
mantenere.
Da evitare!
$buttonConfirm.on('click', function() {
$overlay.fadeIn(400, function(){
$.ajax('/some/modal/content',{},function(data){
$overlay.html(data).slideUp(300, function() {
....
})
})
})
});
Portare le funzioni all'esterno aiuta la leggibilità.
Un pò meglio
$buttonConfirm.on('click', showOverlay);
function showOverlay() {
$overlay.fadeIn(400, getOverlayDataFromServer);
}
function getOverlayDataFromServer() {
$.ajax('/some/modal/content',{}, updateOverlayContent);
}
function updateOverlayContent(data) {
$overlay.html(data).slideUp(300, function() {
....
})
}
Alcuni medoti jQuery ritornano direttamente un Deferred
object, è possibile creare anche "azioni" custom che
utilizzano $.Deferred.
Deferred Objects
$buttonConfirm.on('click', function(e){
$.when(showOverlay())
.then(getOverlayDataFromServer())
.done(updateOverlayContent(data))
.fail(function(){ alert("Something went wrong!") });
});
function showOverlay() {
// $.fn.fadeIn has a promise() method defined so it works like a deferred
return $overlay.fadeIn(400);
}
function getOverlayDataFromServer() {
return $.ajax('/some/modal/content');
}
function updateOverlayContent(data) {
Linee guida
(Tools per scrivere Javascript pulito)
'use strict';
Con questa dicitura abilitiamo la modalità "Strict Mode":
per alcuni sbagli (o cattive abitudini) normalmente accettati
dall'interprete JS vengono sollevati errori.
'use strict';
function myFunction() {
'use strict';
//...
}
Usare un linter JS: JsHint
Può essere usato sia come plugin nell'editor di testo sia
all'interno del vostro task manager (Grunt/Gulp).
Esempio
Scegliere una StyleGuide e usare
JSCS
Ogni programmatore ha le sue abitudini, giuste o sbagliate
che siano.
Scegliere una styleguide e condividerla con il team di
progetto è fontamentale per avere un codice omogeneo e
"stilisticamente" pulito.
AirBnB
Google
jQuery
Idiomatic.js
JSCS

Cattive abitudini e-lineeguida

  • 1.
  • 2.
  • 3.
  • 4.
    Dichiarando variabili senzail var, automaticamente andiamo a definirle come Globali. Da evitare! name="Paperino"; function stampaPaperino() { name ="Paperino"; console.log(name); }
  • 5.
    Utilizzando il "var",lo scope (ambiente dove vive la variabile) diventa quello della funzione in cui è definita. Corretto! var name="Paperino"; function stampaPaperino() { var name ="Paperino"; console.log(name); }
  • 6.
    var a =b = 0;
  • 7.
    In questo casol'interprete riscrive il codice in questo modo: quindi "b" è globale. Da evitare! b = 0; var a = b;
  • 8.
    Questo pattern prevededi dichiarare tutte le variabili utilizzando un solo "var". Corretto! var a = 0, b = 0;
  • 9.
  • 10.
    "pluto" e "paperino"sono dichiarate in due momenti separati all'interno della funzione. Da evitare! function plutoAiutaPaperino() { var pluto = new Pluto(); pluto.corre(); pluto.mangia(); ... var paperino = new Paperino(); pluto.aiuta(paperino); }
  • 11.
    Più leggibile eevitiamo problemi legati all' "hoisting". Corretto! function plutoAiutaPaperino() { var pluto = new Pluto(), paperino = new Paperino(); pluto.corre(); pluto.mangia(); pluto.aiuta(paperino); }
  • 12.
  • 13.
    "i" in questocaso è globale. Se "list" è un array particolarmente grande il dover recuperare ad ogni iterazione il valore di "list.length" rallenta il codice. Da evitare! for(i = 0; i < list.length; i++) { // do something };
  • 14.
    "list.length" in questocaso viene "cachato" nella variabile "len". ( ) Corretto! for(var i = 0, len = list.length; i < len; i++) { // do something }; http://jsperf.com/loops
  • 15.
  • 16.
    "eval" esegue ilcodice javascript inserito in una stringa. Da evitare! eval('var i = "Welcome Hackers!"; alert(i);');
  • 17.
    Usare i costruttoripredefiniti al posto della sintassi "literal".
  • 18.
    Qualsiasi cosa inJavascript è un Object, il linguaggio mette a disposizione dei costruttori che ereditano da Object implementando nuove funzionalità. "new Array()" ad esempio crea un oggetto di tipo Array con delle funzionalità come "pop","push","shift", etc. Da evitare! var disney = new Array("Pippo","Topolino","Paperino");
  • 19.
    Corretto! var disney =["Pippo","Topolino","Paperino"]; Questa sintassi è molto più pulita e condivisa da gran parte dei linguaggi di programmazione.
  • 20.
  • 21.
    E' buona normaevitare di definire variabili o funzioni nello "scope globale" perchè sono accessibili e modificabili in qualsiasi punto dell'applicazione. C'è il rischio che vengano accidentalmente sovrascritte da altri programmatori o plugin esterni e rendono il codice difficile da mantenere.
  • 22.
    Da evitare! <script> var pluto= new Pluto(), plutoHouse = new DogHouse({color:red,material:'wood', size: [100,100 function loadPlutoHouse() { return pluto.load(house); } </script> Tutte le variabili definite nel frammento di codice sopra- riportato sono globali perchè non sono definite all'interno di una funzione.
  • 23.
    Usare una funzioneche viene definita e subito invocata crea uno "scope isolato". Variabili e funzioni esistono solo all'interno dell' IIFE. Corretto! <script> // IIFE = Immediately-Invoked Function Expression (function(document, window, undefined){ var pluto = new Pluto(), plutoHouse = new DogHouse({color:red,material:'wood', size: [100 function loadPlutoHouse() { return pluto.load(house); } })(document,window); </script>
  • 24.
    Esempio in jQuery <script> //IIFE = Immediately-Invoked Function Expression (function($,document, window){ //code immediately executed goes here $(function(){ //code executed on document ready goes here }); })(jQuery, document,window, undefined); </script>
  • 25.
  • 26.
  • 27.
    Ogni volta cheusiamo $('...') viene creato un nuovo oggetto jQuery parsando il DOM e cercando l'elemento corrispondente. Assolutamente poco performante. Da evitare! $('button.confirm').on('click', function() { // Do it once $('.modal').modal(); // And once more $('.modal').addClass('active'); // And again for good measure $('modal').css(...); });
  • 28.
    jQuery ci permettedi "concatenare" più funzioni al medesimo oggetto $ perchè ogni funzione ritorna l'instanza dell'elemento DOM jquerizzato. Soluzione 1: Chaining $('button.confirm').on('click', function() { $('.modal') .modal() .addClass('active') .css(...); });
  • 29.
    Salvare il riferimentoall'oggetto jQuery per poi riusarlo nel codice è la soluzione ottimale. In particolare all'interno dei listener evitiamo di dover "attraversare" il DOM ogni volta che si scatena l'evento a cui l'ascoltatore è associato. Soluzione 2: Caching var $buttonConfirm = $('button.confirm'), $modal = $('.modal'); $background = $('.bg-overlay'); $buttonConfirm.on('click', function() { $modal .modal() .addClass('active') .css(...); $background.removeClass('hidden'); });
  • 30.
  • 31.
    Annidare callback portaa codice difficile da capire e mantenere. Da evitare! $buttonConfirm.on('click', function() { $overlay.fadeIn(400, function(){ $.ajax('/some/modal/content',{},function(data){ $overlay.html(data).slideUp(300, function() { .... }) }) }) });
  • 32.
    Portare le funzioniall'esterno aiuta la leggibilità. Un pò meglio $buttonConfirm.on('click', showOverlay); function showOverlay() { $overlay.fadeIn(400, getOverlayDataFromServer); } function getOverlayDataFromServer() { $.ajax('/some/modal/content',{}, updateOverlayContent); } function updateOverlayContent(data) { $overlay.html(data).slideUp(300, function() { .... }) }
  • 33.
    Alcuni medoti jQueryritornano direttamente un Deferred object, è possibile creare anche "azioni" custom che utilizzano $.Deferred. Deferred Objects $buttonConfirm.on('click', function(e){ $.when(showOverlay()) .then(getOverlayDataFromServer()) .done(updateOverlayContent(data)) .fail(function(){ alert("Something went wrong!") }); }); function showOverlay() { // $.fn.fadeIn has a promise() method defined so it works like a deferred return $overlay.fadeIn(400); } function getOverlayDataFromServer() { return $.ajax('/some/modal/content'); } function updateOverlayContent(data) {
  • 34.
  • 35.
  • 36.
    Con questa dicituraabilitiamo la modalità "Strict Mode": per alcuni sbagli (o cattive abitudini) normalmente accettati dall'interprete JS vengono sollevati errori. 'use strict'; function myFunction() { 'use strict'; //... }
  • 37.
    Usare un linterJS: JsHint
  • 38.
    Può essere usatosia come plugin nell'editor di testo sia all'interno del vostro task manager (Grunt/Gulp).
  • 39.
  • 40.
  • 41.
    Ogni programmatore hale sue abitudini, giuste o sbagliate che siano. Scegliere una styleguide e condividerla con il team di progetto è fontamentale per avere un codice omogeneo e "stilisticamente" pulito. AirBnB Google jQuery Idiomatic.js
  • 42.