Archives par mot-clé : JavaScript

JavaScript : les nouvelles méthodes sur l’objet Array apportées par ES6/ES2015

ES5 a apporté de nouvelles méthodes à l’objet Array que j’avais abordés dans un article précédent. La nouvelle version ES2015 (anciennement ES6) apportent également quelques nouveautés que nous allons voir.

Array.prototype.find

La méthode find() permet de retourner le premier élément d’un tableau respectant une condition via une fonction passée en paramètre. Si aucun element ne satisfait le critère, undefined est retourné.

const numbers = [1, 2, 3, 4, 5, 6];
let estPair = function (n) {
    return n % 2 === 0;
};
let firstEven = numbers.find(estPair); //2

La documentation sur MDN

Array.prototype.findIndex

findIndex() est identique a find à la différence qu’elle retourne l’index du premier élément à la place de l’élément lui même. Si aucun element ne satisfait le critère, -1 est retourné.

const numbers = [1, 2, 3, 4, 5, 6];
let estPair = function (n) {
    return n % 2 === 0;
};
let firstEvenIndex = numbers.findIndex(estPair); //1

La documentation sur MDN

Array.prototype.entries

La méthode entries() retourne un nouvel itérateur (Array Iterator) qui contient les clés/valeurs pour chaque index du tableau.

const arr = ['a', 'b', 'c'];
for (let item of arr) {
    console.log(item); // => 'a' 'b' 'c'
}
for (let pair of arr.entries()) {
    console.log(pair); // => [0, 'a'] [1, 'b'] [2, 'c']
}

La documentation sur MDN

keys

La méthode keys() retourne un nouvel itérateur (Array Iterator) contenant les clés pour chaque index du tableau.

const arr = [1, 2, 3];
const arrIterator = arr.keys();
let nextVal
while (nextVal = arrIterator.next().value) {
 console.log(nextVal);
}
// => 1
// => 2
// => 3

La documentation sur MDN

Array.of

La méthode (statique) Array.of() créé une nouvelle instance d’un tableau contenant les valeurs passés en paramètres, quelque soit le type ou le nombre de paramètres.

Array.of(1); // => [1]
Array.of(1,2,3); // => [1,2,3]

La documentation sur MDN

Array.from

La méthode (statique) Array.from() créé une nouvelle instance d’un tableau à partir d’un objet assimilés à un tableau array-like (comme arguments ou des noeuds du DOM) ou d’un objet iterable.

On peut utiliser Array.from() depuis arguments, des éléments du DOM, Map, Set, String…

// Array-like object (arguments) to Array
function f() {
  return Array.from(arguments);
}

f(1, 2, 3); 
// [1, 2, 3]

// Any iterable object...
// Set
var s = new Set(["foo", window]);
Array.from(s);   
// ["foo", window]

// Map
var m = new Map([[1, 2], [2, 4], [4, 8]]);
Array.from(m);                          
// [[1, 2], [2, 4], [4, 8]]  

// String
Array.from("foo");           
// ["f", "o", "o"]

// Using an arrow function as the map function to
// manipulate the elements
Array.from([1, 2, 3], x => x + x);      
// [2, 4, 6]

// Generate a sequence of numbers
Array.from({length: 5}, (v, k) => k);    
// [0, 1, 2, 3, 4]

La documentation sur MDN

ES7 / ES2016

La version 7 ou 2016 devrait également apportés d’autres nouveautés (encore en cours de validation …).

Liens

La page MDN sur l’objet Array
Une présentation sur l’utilisation des tableaux et objets : Working with Arrays and Objects in modern JavaScript (les slides) et la vidéo :

Il existe des polyfills pour ces méthodes. Vous pouvez également utiliser underscore ou lodash qui propose ses méthodes depuis un moment et bien d’autres .. (la documentation concernant les Arrays de underscore).

ES6 : quelques nouveautés de la prochaine version de JavaScript – Part III

Cet article est la suite d’une série d’articles sur ES6 :

Avant de commencer, une petite information en terme de nommage, ES6 a été renommé en ES2015.

Promise

Définissons tout d’abord ce qu’est une promesse :
Une promesse représente l’éventuel résultat d’une opération asynchrone

La notion de promise (promesse en français) n’est pas nouvelle et existe dans différentes librairies sous différentes formes comme :

Les Promise seront inclus de manière native dans ES6.

Les promise permettent de gérer plus facilement les méthodes asynchrones et d’éviter un code difficile à lire et maintenable si on utilise des callback. En effet on arrive facilement à avoir du code comme cela :

step1(function (value1) {
    step2(function (value2) {
        step3(function (value3) {
            step4(function (value4) {
                step5(function (value5) {
                    step6(function (value6) {
                        // Do something with value6
                    });
                });
            });
        });
    });
});

C’est ce qu’on appelle pyramid of doom ou callback hell.

Un nouvel objet Promise est introduit dans ES6. Le constructeur prend en paramètre une fonction avec 2 fonctions en paramètre : resolved et reject. La fonction resolve est à appeler si il n’y a pas eu d’erreur avec les valeurs de retour. Elle permet d’indiquer que la promise est résolue permettant la suite des actions. La fonction reject est à appeler si une erreur est survenue.

Création d’une Promise

    var promise = new Promise(
        function (resolve, reject) { // (A)
            ...
            if (...) {
                resolve(value); // success
            } else {
                reject(reason); // failure
            }
        });

Une fois notre promise définie, nous allons pouvoir définir un handler sur cette promise afin de réaliser des actions sur la future valeur. L’enchaînement des actions se fait via la méthode then. Cette fonction prend en paramètre 2 fonctions: la 1ere pour le succès (resolve) et la deuxième lors d’une erreur (reject). Les erreurs peuvent être également gérés via la méthode catch.

Utilisation d’une promise

 httpGet('http://myServer.com/file.txt')
    .then(
        function (value) { //Success
            console.log('Contents: ' + value);
        },
        function (reason) { //Error
            console.error('An error occurred', reason);
        });

L’avantage des promises est qu’on peut facilement les chaîner, ou les composer.

Fetch, la nouvelle API pour faire des appels Ajax utilise les promises. (un article pour aller plus loin)

Il existe des polyfills afin de pouvoir les utiliser dès maintenant :

Quelques liens sur le sujet :

Destructuring

Le destructuring permet d’initialiser des variables en les extrayant à partir d’objet existant.

//Array : on extrait 3 variables m, d et y à partir d'un tableau
var [m, d, y] = [12, 21, 1981]; 

//object : on extrait les propriétés d'un objet
//Ici on définit une fonction qui extrait la liste des classe CSS d'un élément
var listOfCLass = function ({ classList } ) {
    Array.from(classList).forEach( (item) => console.log(item))
};
listOfCLass(document.body);

Une autre utilisation avec un module quand on ne veut importer qu’une partie d’un module. (cf chapitre module dans la partie II).

Quelques liens :

ES7

La future version d’EcmaScript est déjà en préparation et je vais parler de 2 des nouveautés qui sont à mes yeux les plus intéressantes.

Object.observe

Object.observe() est une nouvelle API qui permet de s’abonner aux changements effectués sur un objet. A chaque modification sur l’objet, un événement sera lancé contenant la liste des changements (ajout d’une propriété, modification d’une valeur, suppression d’une propriété) sur l’objet.

Voici un exemple tirée de la documentation de Object.observe sur MDN :

var obj = {
  foo: 0,
  bar: 1
};

Object.observe(obj, function(changes) {
  console.log(changes);
});

obj.baz = 2;
// [{name: 'baz', object: <obj>, type: 'add'}]

obj.foo = 'hello';
// [{name: 'foo', object: <obj>, type: 'update', oldValue: 0}]

delete obj.baz;
// [{name: 'baz', object: <obj>, type: 'delete', oldValue: 2}]

Cela permet notamment de facilement mettre en place du data-binding (Angular 2 l’utilise afin d’améliorer les performances et éviter le « dirty checking »).

Quelques liens sur le sujet :

Async/Await

ES6 simplifie, via l’introduction des promesses, grandement la gestion de code asynchrone. Async va encore plus loin afin de faciliter la lecture et la compréhension.
ES7 introduit 2 nouveaux mots clés : async et await.

async permet de définir une fonction comme étant asynchrone alors que await permet d’indiquer que l’on souhaite bloquer l’exécution du code jusqu’au retour de la fonction.

Voici un exemple d’utilisation :

async function getUserName() {
    return 'royto';
}

async function displayLogoutMessage() {
    var user = await getUserName();
    alert(`GoodBye ${user} !`);
}

Pour ceux qui viennent du monde .NET cette syntaxe ne devrait pas les surprendre 🙂

Quelques liens :

Liens sur ES6 / ES2015

JavaScript : Utiliser ES6 maintenant avec Babel

Je vous ai parlé dans des articles précédent de la nouvelle version de JavaScript, ES6/ES2015, Harmony.
J’avais évoqué des outils afin de pouvoir utiliser ces nouveautés dés maintenant, malgré le support partiel dans les navigateurs ou dans de vieux navigateurs.

Babel est transpileur qui va transformer du code ES6 en code compatible ES5 (version compatible dans la plupart des navigateur (IE ….). Babel est la fusion de 2 projets : 6to5 et esnext.

Il supporte l’ensemble des nouveautés de ES6 et même certaines fonctionnalités de ES7. Il a l’avantage de produire un code compréhensible et ne nécessite pas l’inclusion d’un script additionnel dans votre page (comme traceur, un autre transpileur).

Babel est basé sur node et il existe des plugins pour la plupart des task runner JavaScript comme Grunt, Gulp, …

Voyons comment l’utiliser avec grunt.

Installation et utilisation

Tout d’abord, installons le package grunt pour babel. L’installation se fait via la commande :

npm install grunt-babel --save-dev

Nous définissons une tache nommée babel dans notre Gruntfile.js, qui va prendre nos fichiers écrit en ES6 et les transpiler en ES5.

J’ai configuré une tache avec 2 configurations, une pour le dev et une pour générer un package, dist.

 //transpilation to ES5
  babel: {
    options: {
      sourceMap: true,
      blacklist: ["strict"]
    },
    dev: {
      files: [{
        expand : true,
        cwd: '<%= yeoman.app %>/scripts/',
        src: ['**/*.js'],
        dest: '<%= yeoman.dist %>/scripts/',
        ext: '.js'
      }]
    },
    dist: {
      files: [{
        expand : true,
        cwd: '<%= yeoman.tmp %>/concat/scripts',
        src: '*.js',
        dest: '<%= yeoman.tmp %>/concat/scripts',
        ext: '.js'
      }]
    }
  }

Il est possible d’activer des options. Dans mon cas, j’ai activé les sourcesmaps et supprimé l’option strict qui rajoute les « use strict » en début de fichier (ils sont déjà présent dans mes fichiers).

Il nous faut maintenant l’inclure dans nos taches grunt. Je l’inclus dans ma tache serve qui permet d’avoir un serveur web.

  grunt.registerTask('serve', function (target) {
    if (target === 'dist') {
      return grunt.task.run(['build', 'connect:dist:keepalive']);
    }

    grunt.task.run([
      'clean:server',
      'bowerInstall',
      'concurrent:server',
      'autoprefixer',
      'copy:dist',
      'babel:dev',
      'connect:livereload',
      'watch'
    ]);
  });

Bien entendu, nous pouvons configurer grunt pour transpiler notre code à la volée et recharger la page via watch et livereload pour un process de développement plus fluide :

 watch: {
  js: {
    files: ['<%= yeoman.app %>/scripts/{,*/}*.js'],
    tasks: ['newer:eslint:all', 'newer:babel:dev'],
    options: {
      livereload: true
    }
  },
  //others file types ...
}

Exemple de Code généré

Voici du code ES6 que nous allons transpiler avec babel (let, expression lamda, string templates, classes)

//Exemple avec une expression lambda
var double = x => x * 2;

//string template
var deux = 2;
let quatre = double(deux);
console.log(`${quatre} est le double de 
            ${deux}`);

//Exemple avec une classe
class Person {
  constructor(firstname, lastname) {
    this.firstname = firstname;
    this.lastname = lastname;
  }
  fullname() {
    return this.firstname + ' ' + this.lastname; 
  }
}

let julien = new Person('Julien', 'Roy');
console.log(julien.fullname());

Et voici le code généré par Babel

//Exemple avec une expression lambda
'use strict';

var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }

var double = function double(x) {
  return x * 2;
};

//string template
var deux = 2;
var quatre = double(deux);
console.log('' + quatre + ' est le double de \n            ' + deux);

//Exemple avec une classe

var Person = (function () {
  function Person(firstname, lastname) {
    _classCallCheck(this, Person);

    this.firstname = firstname;
    this.lastname = lastname;
  }

  _createClass(Person, [{
    key: 'fullname',
    value: function fullname() {
      return this.firstname + ' ' + this.lastname;
    }
  }]);

  return Person;
})();

var julien = new Person('Julien', 'Roy');
console.log(julien.fullname());

Liens

  • REPL: une page qui permet de tester la conversion de votre code

ES6 : quelques nouveautés de la prochaine version de JavaScript – Part II

Cet article est la suite de ES6 : quelques nouveautés de la prochaine version de JavaScript.

Modules

La gestion de modules/dépendances est un vrai manque dans JavaScript. Des solutions comme AMD ou CommonJs ont permis de combler ce manque. La nouvelle version de JavaScript apporte une gestion native des modules.

Un module est défini dans un fichier. Les fonctions de ce fichier ne sont pas visibles des autres fichier à moins de les exporter explicitement. Cela se fait via l’introduction de 2 nouveaux mots clés : import et export. Export permet de définir ce que vous voulez exposer. A l’opposé,  import permet de d’importer tout ou partie d’un module.

Déclarons un fichier utils.js qui contient une fonction permettant de générer un Uuid

function generateUUID () {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
        var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r &amp;amp; 0x3 | 0x8);
        return v.toString(16);
    });
};

export { generateUUID }

Importons la méthode generateUUID dans un autre module

import { generateUUID } from 'utils';

var uuid = generateUUID();

On peut même importer le module complet

import 'utils' as utils;
 
console.log(utils.generateUUID());

Quelques liens pour aller plus loin :

Angular 2.0 utilisera les modules ES6.

Classes

ES6 apporte la gestion des classes via le mot clé class (avec d’autres comme constructor et extends). JavaScript est déjà objet via les prototypes mais peu de gens savent les utiliser.
Les nouveaux mots clés sont juste du « sucre syntaxique » au dessus des prototypes afin de faciliter l’écriture sous forme de classes, plus familier des personnes venant de Java, C#, ….

Pour ceux qui s’intéressent au développement objet via les prototypes, je conseille la présentation de Christophe Porteneuve, portant notamment sur les prototypes, à Paris Web : slides et vidéo.

Voici un exemple de la définition d’une classe Employee héritant de Person.

class Person {
    constructor(firstName, lastName, age) { //constructors!
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
    }

    fullName(){
        console.log(this.firstName + &amp;quot; &amp;quot; + this.lastName);
    }
}

class Employee extends Person { //inheritance
    constructor(firstName, lastName, age, salary) {
        super(firstName, lastName, age); //call the parent constructor with super
        this.salary = salary;
    }

    printSalary(){
        console.log('Salary : ' + this.salary);
    }
}

let julien = new Employee('Julien', 'Roy', '33', 150000);

julien.fullName();
julien.printSalary();

Quelques liens pour aller plus loin avec les classes ES6.

Améliorations sur les objets

ES6 apporte également des raccourcis concernant la création d’objet concernant :

la création de méthode

//ES5
var obj = {
        myMethod: function () {
            ···
        }
    };
//ES6
var obj = {
        myMethod() {
            ···
        }
    };

les propriétés

Il n’est plus necessaire de spécifier la valeur si on créer une propriété à partir d’une variable.

let x = 4;
let y = 1;
let obj = { x, y }; //ES6
let es5Obj = { x : x; y : y};

Computed property keys

Il est maintenant possible de créer des propriétés ayant une clé composé lors de la création d’un objet.

let obj = {
        [propKey]: true,
        ['b'+'ar']: 123
    };

De nouvelles méthodes sont également disponible :

Object.is()

Object.is permet une comparaison supprimant des cas bizarres en js lors des comparaison avec ===

(NaN !== NaN) //false 
-0 === +0 //false
var isSame = Object.is(value1, value2);

Object.assign()

La méthode assign permet la copie les propriétés d’un objet source dans un autre objet (idéal pour les options par défaut ou le clone d’objet).
Cette méthode existait dans plusieurs librairies comme $.extend en jQuery ou _.defaults pour Underscore/lodash.

Exemple de copie d’un objet avec Object.assign()

var obj = { a: 1 };
var copy = Object.assign({}, obj);

Quelques liens pour aller plus loin :

Symbols

ES6 apporte un nouveau type primitif : les Symbols. Ils sont uniques (2 symbols ne sont jamais égaux) et immutables (non modifiables). Ils peuvent être utilisés pour définir une propriétés d’un objet par exemple (on utilisera la méthode Object.getOwnPropertySymbols() pour obtenir les propriétés de type symbole d’un objet).

//Création d'un symbol
let symbol1 = Symbol();

//Utilisation d'un symbol comme propriété d'un objet
const MY_KEY = Symbol();
let obj = {
    [MY_KEY]: 123
};

Quelques liens sur le sujet :

Références

Quelques liens en complément de ceux de l’article précédent :

la suite au prochain épisode …

Outils CSS3 – HTML5 – JavaScript : Episode 9

Au menu, des liens, des outils, des présentations … sur HTML, CSS et JavaScript.

Talks

Voici quelques présentations que j’ai beaucoup appréciées :

HTML

CSS

  • Pure : Un framework CSS (gère le responsive)
  • Responsive Web Design
  • PlentyofFrameworks : trouver le framework CSS qui vous convient
  • Enjoycss : éditeur de composant CSS
  • CSSShake : Une feuille de style pour secouez vos éléments
  • Style Guide guide : site regroupant des générateurs de style guide (guide d’utilisation de vos style (un exemple))
  • CSS Values : permet de rechercher une propriété CSS pour facilement connaître son utilisation et les valeurs possibles
  • Bounce.js : un générateur d’animation CSS 3
  • CSS Stats : Statistique concernant CSS (nb de sélecteurs, couleurs, …) d’un site
  • Critical Path CSS Generator : Générateur de Critical Path. Critical Path est une technique qui consiste à injecter, directement dans votre code HTML(inline, dans le header) le code CSS minimal afin d’accélérer la vitesse de rendu de votre page. Le reste du code CSS est à charger via des fichiers CSS classique en fin de page. Cet outils permet d’extraire le code CSS à injecter en fonction d’une page.
  • Flexplorer : un générateur et outils de test de flexbox
  • une cheatsheet sur la propriété flexbox en css3

JavaScript

Divers

Underscore/Lo-Dash : Utilisation de _.chain

J’ai présenté dans un article précédent la bibliothèque utilitaire underscore (et son fork lo-Dash). Je vais ici présenter la méthode chain qui permet de facilement chaîner vos appels pour simplifier l’écriture de votre code.

Imaginons que nous avons une liste de documents et que nous souhaitons récupérer le nom des 10 documents les plus récents (en utilisant la propriété lastUpdate).

On pourrait écrire :

//on tri par la propriété lastUpdate
var orderedDocuments = _.sortBy(documents, 'lastupdate');
//on inverse 
var descOrderedDocuments = _.reverse(orderedDocuments);
//on prend les 10 premiers
var last10Documents = _.first(descOrderedDocuments, 10);
//on récupère leur nom 
var last10DocumentNames = _.pluck(last10Documents, 'name');

On peut voir ici que l’on doit créer des variables temporaires afin de passer le résultat d’une méthode à la méthode suivante, ce qui a pour conséquence de polluer le namespace avec des variables qui ne sont utilisées qu’une fois et d’utiliser de la mémoire inutilement. De plus, si vous devez modifier l’ordre d’appels, vous devrez vous assurer de passer la bonne variable temporaire au bon moment.

Voyons comment utiliser _.chain afin de simplifier et de rendre plus lisible ce code. Il faut d’abord appeler chain. Chain va retourner un wrapper (au lieu du résultat) ce qui va nous permettre d’appeler d’autres méthodes qui vont modifier le résultat. Le résultat de la méthode précédente est passé automatiquement à la fonction suivante. Une fois toutes les opérations terminées, il suffit d’appeler value() pour obtenir le résultat.

var lastDocuments = _.chain(documents)
    .sortBy('lastupdate')
    .reverse()
    .first(10)
    .pluck('name')
    .value();

Le code s’en trouve plus lisible et plus maintenable.

Pour ceux qui font du .NET, cela se rapproche de ce qu’on peut faire avec Linq.

ES6 : quelques nouveautés de la prochaine version de JavaScript

JavaScript est basé sur la norme EcmaScript. La version 6, appelée Harmony, va apporter beaucoup de nouveautés qui vont améliorer et combler certains manques du langage.
Voici quelques améliorations que je trouve très intéressantes :

let

Let est le nouveau var. Il permet de déclarer une nouvelle variable mais avec un scope (portée) local contrairement à var.

Ainsi avec var, la portée est soit globale soit liée à la fonction dans laquelle celle-ci est définie. Let permet d’avoir une granularité plus fine (for, if, …) comme il l’est dans d’autres langages.

var t = 1;
if (true) {
  let t = 3;
  for (; t <= 5; t++) {
  	console.log(t);
  }
}
console.log(t);

// 3
// 4
// 5
// 1

Le lien vers la documentation de let sur MDN et un article complet sur le sujet : Variables and scoping in ECMAScript 6

Arrow functions

Les Arrow function est une nouvelle façon de définir des fonctions, un peu comme les expressions lambda en C#. Cela peut s’avèrer pratique dans le cas de définition de callback par exemple.

Une arrow function se définit via =>. La déclaration des paramètres se fait avant la flèche. Si il y a plusieurs paramètres, on entourera les paramètres par des parenthèses. Si l’expression est sur une ligne, celle-ci sera retournée. Si elle est sur plusieurs lignes, celle-ci doit être entourée d’accolades.

Voici un exemple d’un map avec une fonction qui met les valeurs au carré.

var myValues = [1,2,3,4,5];

var squared = myValues.map(x => x*x);
console.log(squared);  //-> [1, 4, 9, 16, 25]

//définition d'un function qui permet de déterminer si n nombre est pair
var even = (x) => x % 2 == 0;
var evenValues = myValues.filter(even);
console.log(evenValues);  //-> [2, 4]

var complex = (a, b) => {
    if (a > b) {
        return a;
    } else {
        return b;
    }
}

Le lien vers la documentation des arrow functions sur MDN.

Rest Parameters

Les rest parameters permettent de définir une fonction qui prend un  nombre infini de paramètres sous la forme d’un tableau.

On définit notre dernier paramètre comme étant un rest parameter en ajoutant … devant le nom du paramètre. Nous ne sommes plus obligé de passer par arguments. L’avantage étant ici que notre paramèter est nommé et qu’il s’agit d’un véritable array et qu’on peut donc lui appliquer ses méthodes spécifiques (reduce, sort, map, …).

On peut appeler notre méthode de 2 façons :

  • en passant la liste sous forme de paramètres à la suite les uns des autres
  • en passant la liste sous forme d’un tableau. Dans ce cas, il faut le préfixer par …

Voici un exemple (issue de la page MDN concernant les Rest Parameters et compléter avec l’appel sous forme de tableau)

function multiply(multiplier, ...theArgs) {
  return theArgs.map(function (element) {
    return multiplier * element;
  });
}

var arr = multiply(2, 1, 2, 3); 
console.log(arr); // [2, 4, 6]

var arr = multiply(2, ...[1, 2, 3]); 
console.log(arr); // [2, 4, 6]

Cela ressemble aux params en C#.

Default Parameters

ES6 va permettre de donner des valeurs par défaut aux paramètres de vos fonctions. Cela se fait comme dans d’autres langagues de la façon suivante :

function sayMsg(msg='This is a default message.') {
	console.log(msg);
}
sayMsg();
sayMsg('This is a different message!');

Le lien vers la documentation des default parameters sur MDN.

Array comprehension

Array comprehension est une nouvelle syntaxe pour créer des tableaux à parir de tableaux existant.

Pour cela on va utiliser la syntaxe suivante :

var square = [for (i of [ 1, 2, 3 ]) i*i ]; 
// [ 1, 4, 9 ]

var abc = [ 'A', 'B', 'C' ];
var lowChar = [for (letters of abc) letters.toLowerCase()];
// [ 'a', 'b', 'c' ]

//On peut rajouter des conditions
[for (i of [1, 2, 3, 4]) if (i > 3) i];
// [ 1, 2 ] 

//utiliser plusieurs tableaux
var cross = [for (i of [1, 2, 3]) for (j of [a, b, c]) i+j];
// [ '1a', '1b', '1c', '2a', '2b', '2c', '3a', '3b', '3c']

Le lien vers la documentation des Array comprehension sur MDN.

Generators

Les generators sont des itérateurs spéciaux qui permettent de récuperer la valeur suivante que lors de l’appel à next.

Il introduit le mot clé yield qui permet de définir la valeur retournée. Lors du permier appel à la fonction Generator, on récupère l’itérateur. La récupération d’une nouvelle valeur se fait via next(). Une exception StopIteration est lancée si il n’y pas de nouvelle valeur. Lors d’un appel à next, la fonction continuera son exécution à partir du dernier yield atteint.

Un Exemple tiré d’un article sur les Iterators et Generators sur MDN.

function simpleGenerator(){
  yield "first";
  yield "second";
  yield "third";
  for (var i = 0; i > 3; i++)
    yield i;
}

var g = simpleGenerator();
print(g.next()); // prints "first"
print(g.next()); // prints "second"
print(g.next()); // prints "third"
print(g.next()); // prints 0
print(g.next()); // prints 1
print(g.next()); // prints 2
print(g.next()); // StopIteration is thrown

Template Strings

Permet de définir des templates sous la forme de chaîne de caractères sans passer par une librairie externe (mustache, jsrender, …)

La définition d’un string template se fait via un ` (back tick). Les variables sont définies via ${ x } (x étant la variable).
Les templates string peuvent être définis sur plusieurs lignes (sans devoir faire de concaténation comme avec les strings).

let person = {name: 'Julien Roy'};
let tpl = `My name is ${person.name}.`;

console.log(tpl); //My name is Julien Roy

Autres nouveautés

Harmony apporte également d’autres nouveautés:

  • les classes
  • les modules
  • Mutation observers

Je parlerai dans un autre article de ces nouveautés très attendues.

Edit : le deuxième article sur les nouveautés de ES6.

Utilisation

Bien entendu, toutes ses nouveautés ne sont pas encore toutes intégrées dans les navigateurs, sachant que les spécifications ne sont pas encore figées et peuvent être amenées à évoluer. Il existe tout de même des outils qui permettent d’utiliser ces fonctionnalités comme des polyfills ou des transpileurs (compilation de code ES6 en ES5) comme Traceur ou 6to5. (les liens ci dessous ..)

Conclusion

ES6 apporte pas mal de nouveautés attendues par les développeurs qui vont permettre à JavaScript de combler certains manques et améliorer grandement son écriture pour en faire un langage « first class ». Pour information, la version 2.0 d’Angular est écrite en EcmaScript 6.

Références

Présentation de Yeoman

Aprés Grunt et Bower, je vais aujourd’hui vous présenter yeoman.

Yeoman est un « générateur » de projet.

Il est basé sur node.js et npm et utilise git pour la récupération des dépendances. Ces outils doivent donc être installés sur votre poste.

Installation

L’installation se fait via la commande suivante (avec l’option -g pour avoir la commande en global)

npm install -g yo

Bower et Grunt sont automatiquement installés.

Il faut également installer les générateurs que vous voulez utiliser. Vous pouvez trouver la liste des générateurs disponible ici. Pour notre exemple, nous allons installer le générateur pour angular via la commande suivante :

npm install -g generator-angular

Utilisation

Il suffit d’appeler ensuite la commande yo avec le générateur de votre choix :

yo angular

Quelques questions vous seront posées (voulez-vous utiliser sass, twitter bootstrap, ….,). Ces questions détermineront ce qui sera installé.Une fois les questions répondues, yeoman va se charger de télécharger toutes les dépendances du projet.

Création d'un projet angular via Yeoman

Comme je vous le disais, yeoman intègre grunt et bower. Des fichiers Gruntfile.js et bower.js seront donc déjà présent et configurés suivant le générateur utilisé. Pratique !!

Les générateurs peuvent également être utilisé pour créer des nouveaux fichiers comme dans le cas du générateur angular qui permet de créer des services, factory, controller, directives,  ….

Astuces

Pour connaître les générateurs installés, il faut lancer l’aide via la commande suivante :

yo -h

Liste des générateurs yoeman installésVous pouvez voir la liste des générateurs disponibles pour le seul angular. Notez également la présence de karma. En effet, le template de projet d’angular inclut Karma (anciennement Testacular), un lanceur de test multi-navigateur créé par l »équipe d’angular,  et permet donc d’initier un projet Karma .

Liens

Conclusion

Yeoman est très pratique pour démarrer rapidement un projet avec une bonne architecture et les bonnes pratiques d’un framework (tests unitaires, arborescence projet, …). Vous avez bien entendu la possibilité de générer votre propre générateur pour vos projets et les partager.

Outils CSS3 – HTML5 – JavaScript : Episode 8

Html

  • Une liste d’articles sur l’utilisation d’Emmet(part 1, 2, 3 et 4) (mon article de présentation d’Emmet qui s’appelait à l’époque Zen coding) Toujours sur le même sujet, une cheat sheet de emmet assez complète.
  • Un article qui présente l’api de vibration
  • Responsinator : Permet de visualiser le rendu d’un site en mode responsive sur différents terminaux (iPhone 3/4, iPhone 5, iPad, Android, …) en portrait et paysage. Un exemple avec mon site.

CSS

  • Spinkit : Animations d’attente en CSS3
  • Myth : Myth is a preprocessor that lets you write pure CSS without having to worry about slow browser support, or even slow spec approval. It’s like a CSS polyfill.
  • CSS Zen Garden : La nouvelle version HTML5 Zen Garden.
  • lesshat.com : collection de mixins less
  • extractCSS : permet d’extraire les styles inlines d’un code HTML
  • Stitches : un générateur de Sprites
  • CSS Animate : Outil de génération d’animations CSS

JavaScript

Divers

Présentation de Grunt

Le développement nécessite d’avoir de bons outils afin de gagner en productivité. L’automatisation des taches est un bon moyen de gagner du temps.

Grunt est un lanceur de taches. Il est basé sur NodeJS. Grunt permet de facilement automatiser vos taches liés au développement web. L’écosystème autour de nodeJs étant très dynamique, il existe une pléthore de taches grunt existantes

Je n’aborderai pas dans cet article l’installation et la configuration de grunt, vous trouverez dans la partie liens de très bons articles traitant ce sujet.

Voici une liste de quelques plugins utiles :

  • Less : Permet de compiler du des fichier LESS en CSS (il existe bien évidemment des plugins pour les autres préprocesseurs comme SASS ou Stylus
  • Cssmin : Permet de minifier vos CSS
  • Jshint : Permet de valider via JsHint votre code JavaScript
  • Concat : Permet la concaténation de fichier afin d’améliorer les performance de chargement de votre site
  • Uglify : Permet de minifier vos fichier js (permet également la concaténation avec possibilité d’utiliser Source map afin de debugger facilement vos scripts)
  • imageoptim / responsive-images : Permet d’optimiser et de générer des images adaptées à différentes résolution (responsive web design)
  • Watch : Permet de surveiller vos fichier et de lancer d’autres taches à chaque modification
  • HTMLHint : Validation de votre code HTML
  • jsdoc : Permet de générer la documentation de votre code js

Liens

Alternatives

Utilisez-vous Grunt ? Si oui, quelles taches utilisez-vous ?