Animée par Charles Jacquin
Les objets de type array possède les méthodes suivantes :
var languages = ['C++','Java','JavaScript'];
languages.push('Python');
languages.unshift('C');
console.log(languages);
// ['c','c++','Java','JavaScript','Python']
Pour ajouter un element en fin de tableau, il faut utiliser la méthode push.
Pour ajouter un element en début de tableau, il faut utiliser la méthode unshift.
var languages = ['C++','Java','JavaScript', 'C#', 'Python'];
languages.pop();
languages.shift();
console.log(languages);
// ['Java','Javascript', 'C#']
languages.splice(1,1);
// le premier param est la position de l'élement à supprimer,
// le deuxième param est le nombre d'élément à supprimer.
console.log(languages);
// ['Java', 'C#']
Pour retirer un element en fin de tableau, il faut utiliser la méthode pop.
Pour retirer un element en début de tableau, il faut utiliser la méthode shift.
Pour toutes les autres positions, il faut utiliser la méthode splice.
var myStringArray = [13,5,3,24,7,6,75,45];
myStringArray.sort(function(a,b){
return a-b;
});
// Ascendant
console.log(myStringArray);
myStringArray.sort(function(a,b){
return b-a;
});
//descendant
console.log(myStringArray);
//inverse l'ordre d'un tableau (les derniers seront les premiers)
myString.reverse();
console.log(myStringArray);
La methode sort va nous permettre de réordonner un tableau de string ou un tableau de number.
la méthode reverse inverse l'ordre des éléments.
var myArray = ['foo','bar'];
console.log(myArray.join('/')); //affiche foo/bar
console.log(myArray.join()); //affiche foo,bar
La méthode join permet de réunir tous les éléments d'un tableau dans une chaine de caractère.
Le deuxième paramètre (optionnel), indique la chaine de caractère qui delimitera les élements
La méthode toString appelé sur un array appelera en réalité join
var myArray = ['foo','bar', 'toto', 'tata'];
var slicedArray = myArray.slice(1,2);
console.log(slicedArray.join());
//affiche bar, toto
La méthode slice retourne un nouveau tableau qui contient une portion du tableau de base.
Si le tableau est un tableau d'objet, les deux tableaux contiennent des références vers les mêmes objets.
var myArray = ['foo','bar', 'toto', 'tata', 'bar'];
console.log(myArray.indexOf('bar'));
//affiche 1
console.log(myArray.indexOfLast('bar'));
Les méthodes indexOf et indexOfLast retourne la position dans le tableau de l'élément fournit en paramètre.
Si l'élément ne se trouve pas dans le tableau retourne -1
var myArray = ['foo','bar', 'toto', 'tata'];
myArray.forEach(function(value, index){
console.log(value, index);
//ici on peut manipuler chaque valeur une par une
})
Pour boucler dans un tableaux nous n'auront pas forcément besoin d'utiliser le for.
La fonction fournit en paramètre sera appelée à chaque itération de la boucle.
Il n'est pas possible d'utiliser breack avec la methode Array.prototype.forEach
!
var nombrePair = [2,4,6,8,10];
nombreImpair = nombrePair.map(function(value, index){
console.log(value, index);
return value -1;
})
console.log(nombrePair.join());
// affiche 2,4,6,8,10
console.log(nombreImpair.join());
// affiche 1,3,5,7,9
La fonction map retourne un nouveau tableau, chaque élément du tableau originel sera transformé par le callback.
Array.prototype.map = function(projection){
//la function retourne un array créons le
var response = [];
//on lance la boucle
this.forEach(function(value, index){
//on stocke dans le tableau de réponse, la valeur modifiée
//par la fonction passée en paramétre
response.push(projection(value));
})
//on retourne le tableau
return response;
}
Réecrivons la fonction map :
var nombres = [1,2,3,4,5,6,7,8,9,10];
var nombrePair = nombres.filter(function(value){
return value % 2 === 0;
});
var nombreImpair = nombres.filter(function(value){
return value % 2 === 1;
});
console.log('nombre pair : ', nombrePair.join());
// affiche 2,4,6,8,10
console.log('nombre impair : ',nombreImpair.join());
// affiche 1,3,5,7,9
La methode filter retourne un nouveau tableau contenant tous les éléments du premier tableau pour lesquel le callback retourne true.
var nombres = [1,2,3,4];
var reducedArray = nombres.reduce(function(valeurPrecedente, valeurCourante, index){
return valeurPrecedente + valeurCourante;
}, 0);
console.log(reducedArray);
// affiche 10
La methode reduce est un accumulateur, elle traite chaque valeur de la liste de la gauche vers la droite afin de réduire le tableau à une seule valeur.
var users = [
{
name: 'foo'
},
{
name: 'bar'
}
];
var fooUser = users.find(function(user) {
return user.name === 'foo';
})
console.log(fooUser);
// affiche { name: 'foo' }
La méthode find permet de retrouver le premier élément du tableau correspondant à l'expression booléene retournée.
ES6 ~ ES2015
Classes, Inheritance
Modules
Iterators, Generators
Scoping
Promises, Proxies
Arrow functions
Collections
...
Dernière version finallisé ECMAScript6 (ES6, ES2015, Harmony)
Changement de convention de nommage (ES7 = ES2016)
Implémentation en cours dans les browsers
Utilisation de transpileurs et de polyfills pour assurer la compatibilité
Un standard pour les languages de script
Le language le plus populaire est JavaScript
ActionScript, Lua pour les plus connus
May '95
Dec '95
Sep '95
1997
Aug '96
1999
1998
2009
2003
2015
2011
2016
Mocha (Brendan Eich, Netscape)
LiveScript
JavaScript
Edition 1
JScript (Microsoft)
Edition 2
Edition 3
Edition 4
Edition 5
Edition 5.1
Edition 6
Edition 7
ECMA-262 specification
Un Transpiler est un type de compilateur qui transforme du code d'un language vers un autre
ES5 est largement supporté par les browsers
Le code ES6 doit être compilé
Deux transpiler ES6 -> ES5
Traceur (Google)
Babel (Community)
Babel est le standard:
Le code compilé est plus lisible (sic)
Support de JSX (pour React)
Une autre alternative consiste à utiliser un preprocesseur JS
CoffeeScript
Dart
Typescript
Flow
Traceur ES6 -> ES5 transpilation
/*jshint esnext: true */
import Todo from './todo';
import {values} from './generators';
class TodoList {
constructor() {
this.todos = {};
this.length = 0;
}
add(text, done = false) {
let todo = new Todo(text, done);
this.todos[String(todo.timestamp)] = todo;
this.length++;
}
archiveCompleted() {
for (let todo of values(this.todos)) {
if (todo.done) this.delete(todo);
}
}
delete(todo) {
delete this.todos[String(todo.timestamp)];
this.length--;
}
getUncompletedCount() {
let count = 0;
for (let todo of values(this.todos)) {
if (!todo.done) count++;
}
return count;
}
}
export default TodoList;
$traceurRuntime.registerModule("todoservice.js", [], function() {
"use strict";
var __moduleName = "todoservice.js";
var Todo = $traceurRuntime.getModule($traceurRuntime.normalizeModuleName("./todo", "todoservice.js")).default;
var values = $traceurRuntime.getModule($traceurRuntime.normalizeModuleName("./generators", "todoservice.js")).values;
var TodoList = function() {
function TodoList() {
this.todos = {};
this.length = 0;
}
return ($traceurRuntime.createClass)(TodoList, {
add: function(text) {
var done = arguments[1] !== (void 0) ? arguments[1] : false;
var todo = new Todo(text, done);
this.todos[String(todo.timestamp)] = todo;
this.length++;
},
archiveCompleted: function() {
var $__7 = true;
var $__8 = false;
var $__9 = undefined;
try {
for (var $__5 = void 0,
$__4 = (values(this.todos))[Symbol.iterator](); !($__7 = ($__5 = $__4.next()).done); $__7 = true) {
var todo = $__5.value;
{
if (todo.done)
this.delete(todo);
}
}
} catch ($__10) {
$__8 = true;
$__9 = $__10;
} finally {
try {
if (!$__7 && $__4.return != null) {
$__4.return();
}
} finally {
if ($__8) {
throw $__9;
}
}
}
},
delete: function(todo) {
delete this.todos[String(todo.timestamp)];
this.length--;
},
getUncompletedCount: function() {
var count = 0;
var $__7 = true;
var $__8 = false;
var $__9 = undefined;
try {
for (var $__5 = void 0,
$__4 = (values(this.todos))[Symbol.iterator](); !($__7 = ($__5 = $__4.next()).done); $__7 = true) {
var todo = $__5.value;
{
if (!todo.done)
count++;
}
}
} catch ($__10) {
$__8 = true;
$__9 = $__10;
} finally {
try {
if (!$__7 && $__4.return != null) {
$__4.return();
}
} finally {
if ($__8) {
throw $__9;
}
}
}
return count;
}
}, {});
}();
var $__default = TodoList;
return {get default() {
return $__default;
}};
});
$traceurRuntime.getModule("todoservice.js" + '');
ES5
ES6
Babel ES6 -> ES5 transpilation
/*jshint esnext: true */
import Todo from './todo';
import {values} from './generators';
class TodoList {
constructor() {
this.todos = {};
this.length = 0;
}
add(text, done = false) {
let todo = new Todo(text, done);
this.todos[String(todo.timestamp)] = todo;
this.length++;
}
archiveCompleted() {
for (let todo of values(this.todos)) {
if (todo.done) this.delete(todo);
}
}
delete(todo) {
delete this.todos[String(todo.timestamp)];
this.length--;
}
getUncompletedCount() {
let count = 0;
for (let todo of values(this.todos)) {
if (!todo.done) count++;
}
return count;
}
}
export default TodoList;
/*jshint esnext: true */
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
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 _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
var _todo = require('./todo');
var _todo2 = _interopRequireDefault(_todo);
var _generators = require('./generators');
var TodoList = (function () {
function TodoList() {
_classCallCheck(this, TodoList);
this.todos = {};
this.length = 0;
}
_createClass(TodoList, [{
key: 'add',
value: function add(text) {
var done = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1];
var todo = new _todo2['default'](text, done);
this.todos[String(todo.timestamp)] = todo;
this.length++;
}
}, {
key: 'archiveCompleted',
value: function archiveCompleted() {
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = (0, _generators.values)(this.todos)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var todo = _step.value;
if (todo.done) this['delete'](todo);
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator['return']) {
_iterator['return']();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
}
}, {
key: 'delete',
value: function _delete(todo) {
delete this.todos[String(todo.timestamp)];
this.length--;
}
}, {
key: 'getUncompletedCount',
value: function getUncompletedCount() {
var count = 0;
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = (0, _generators.values)(this.todos)[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var todo = _step2.value;
if (!todo.done) count++;
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2['return']) {
_iterator2['return']();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
return count;
}
}]);
return TodoList;
})();
exports['default'] = TodoList;
module.exports = exports['default'];
ES5
ES6
ES6 amène la standardisation
Actuellement: AMD, CommonJS
Avant: Rien (global)
Avec ECMAScript 6, les modules sont des fichiers
un module par fichier
un fichier par module
Une donnée exportée dans un module est accessible partout où le module est importé
// ClientService.js
class ClientService {
constructor() { this.clients = []; }
addClient(client) { this.clients.add(client); }
}
export default ClientService();
import ClientService from './ClientService';
class ClientComponent {
clientService = new ClientService();
submitClient(client) {
this.clientService.addClient(client);
}
}
ES6
ES6
module.exports = ClientService;
CommonJS
export default ClientService;
ES6
var Service = require('./ClientService');
import Service from ('./ClientService');
Default exports
Un seul par module
Lors de l'import, le nom du module est libre
// ClientService.js
class ClientService {
constructor() { this.clients = []; }
addClient(client) { this.clients.add(client); }
}
export default new ClientService();
ES6
import ClientService from './ClientService';
ES6
import MyService from './ClientService';
class ClientComponent {
submitClient(client) {
MyService.addClient(client);
} }
Default exports
//------ MyClass.js ------
class MyClass { ... };
export default MyClass;
//------MyFunction.js ----
function myFunction() { ... };
export default myFunction;
//------ lib.js ------
export const sqrt = Math.sqrt;
export function square(x) {
return x * x;
}
export function diag(x, y) {
return sqrt(square(x) + square(y));
}
Named exports
// ----- main.js ---
import * as lib from './lib';
console.log(lib.square(11)); // 121
console.log(lib.diag(4, 3)); // 5
// ----- main.js ---
import MyClass from './MyClass'
import thatFunction from './myFunction'
var my = new MyClass();
var res = thatFunction();
// Constants.js
var $BANKRUPTCY_MIN_DEBT = 1001; var $SEQUESTRATION_MIN_DEBT = 3000;
export $BANKRUPTCY_MIN_DEBT; export $SEQUESTRATION_MIN_DEBT;
ES6
// Constants.js
var $BANKRUPTCY_MIN_DEBT = 1001; var $SEQUESTRATION_MIN_DEBT = 3000;
export { $BANKRUPTCY_MIN_DEBT, $SEQUESTRATION_MIN_DEBT }
ES6
Plusieurs export par module
Peut être mixer avec default
import { $BANKRUPTCY_MIN_DEBT,
$SEQUESTRATION_MIN_DEBT } from './Constants';
//do something
CommonJS
AMD
// someModule.js
function doSomething () {
console.log("foo");
}
exports.doSomething = doSomething;
//otherModule.js
var someModule = require('someModule');
someModule.doSomething();
// someModule.js
define(["lib"], function (lib) {
function doSomething() {
console.log("foo");
}
return {
doSomething: doSomething
}
});
//otherModule.js
require(["someModule"], function(someModule){
someModule.doSomething();
});
Syntaxe compacte
chargement synchrone
node.js, browserify, webpack
Chargement asynchrone
RequireJS
Renommage à l'import:
ES6
ES6
import {$BANKRUPTCY_MIN_DEBT as minBank,
$SEQUESTRATION_MIN_DEBT as minSeq
} from './Constants';
function isEligibleForBankruptcySequestration(
isScottish, debtTotal) {
var minDebt;
if(isScottish) { minDebt = minSeq }
else { minDebt = minBank };
return debtTotal >= minDebt;
}
// Constants.js
var $BANKRUPTCY_MIN_DEBT = 1001;
var $SEQUESTRATION_MIN_DEBT = 3000;
export $BANKRUPTCY_MIN_DEBT;
export $SEQUESTRATION_MIN_DEBT;
let foo = 4;
foo = 5;
const bar = {};
bar.foo = 'bar';
lorsqu'il est utilisé dans une boucle le scope de let est limité à la boucle.
(ce n'était pas le cas avec "var")
function doSomething() {
let i = 4;
for (let i = 0; i < 50; i++) {
console.log(i)
}
console.log(i):
}
const name = 'white'; const myOldSchoolString = 'yo Mr ' + name;
const myEs2015String = `yo Mr ${name}`;
Une arrow function est une fonction qui ne crée pas de nouveaux contexte this.
const myLambda = () => {
}
//parfait pour les callbacks myAsyncCall(myParam, (data) => {
})
myPromise()
.then(data => {
})
.catch(err => {
})
Plus de
var self = this;
Si il n y a qu'un seul paramètre, les parenthèses sont optionnelles
const obj = { test: 123, test2: 456, test3: 789 }
const { test2, test3 } = obj
console.log(test2) // 456
console.log(test3) // 789
Spread accepte une collection (Array ou Object)
const add = (a, b) => a + b;
let args = [3, 5];
add(...args);
let cde = ['c', 'd', 'e'];
let scale = ['a', 'b', ...cde, 'f', 'g'];
// ['a', 'b', 'c', 'd', 'e', 'f', 'g']
let mapABC = { a: 5, b: 6, c: 3};
let mapABCD = { ...mapABC, d: 7};
// { a: 5, b: 6, c: 3, d: 7 }
S'utilise lors de l'appel de la fonction
Rest partage la syntaxe de Spread, mais permet à une fonction d’accéder à un nombre variable de paramètres.
function add(...numbers) {
return numbers[0] + numbers[1];
}
add(3, 2); // 5
function print(a, b, c, ...more) {
console.log(more[0]);
console.log(arguments[0]);
}
print(1, 2, 3, 4, 5); // 4 1
S'utilise lors de la déclaration de la fonction
//modern style
const addEs6 = (...numbers) => numbers.reduce((p, c) => p + c, 0);
addEs6(1, 2, 3); // 6
Abstraction qui permet d'écrire du code asynchrone lisible et maintenable.
function myPromisedTimer (timer) {
return new Promise((resolve, reject) => {
if(typeof timer !== 'number')
return reject(new Error('timer must be a number'))
setTimeout(() => {
resolve(`${timer} second later`);
},timer * 1000)
})
}
myPromisedTimer(6)
.then(message => console.log(message))
.catch(err => console.error(err))
Pour les vieux navigateurs, il faudra utiliser un polyfill.
Enchainement
function myPromisedTimer (timer) {
return new Promise((resolve, reject) => {
if(typeof timer !== 'number')
return reject(new Error('timer must be a number'))
setTimeout(() => {
resolve(timer * 2);
},timer * 1000)
})
}
myPromisedTimer(6)
.then(newTimer => {
return myPromisedTimer(9);
})
.then(newTimer => {
return myPromisedTimer(2)
})
.catch(err => console.error(err))
Traitements parallèles
Promise.all([
myPromisedTimer(4),
myPromisedTimer(8),
anotherPromise()
])
.then(response => {
//response is an array of 3
})
.catch(err => console.error(err))
export class User {
constructor(name) {
this.name = name
}
doSomething() {
console.log(this.name);
}
static aStaticMethod() {
}
}
const myUser = new User('toto')
export function User(name) {
this.name = name
}
User.prototype.doSomething() {
console.log(this.name);
}
User.aStaticMethod() {
}
var myUser = new User('toto')
import {Person} from './Person'
export class User extends Person {
constructor(name, email) {
super(email)
this.name = name
}
doSomething() {
console.log(this.name);
}
}
const myUser = new User('toto', 't@gm')
myUser.sendEmail()
export class Person {
constructor(email) {
this.email = email
}
sendEmail() {
}
}
Héritage
const fetchPosts = async () => {
let result
try {
const response = await fetch('http://webapi/post')
result = response.json()
} catch (err) {
console.error(err)
}
return result
}
function readOnly (target, key, descriptor) {
descriptor.writable = false
return descriptor
}
class Cat {
@readOnly
miaule() {
return `${this.name} says miaou`
}
}
décorer une propriété
function isSuperHero (target) {
target.isSuperHero = true
return target
}
@isSuperHero
class Cat {
@readOnly
miaule() {
return `${this.name} says miaou`
}
}
console.log(Cat.isSuperHero) //true
décorer une classe
Single Page Application (SPA)
Dans les années 90, les RIA c’est… des applets Java !
Dans les années 2000, on voit apparaître…
2
ou
ou
ou
Node.js est utilisé comme plateforme de développement.
npm est le gestionnaire de paquets pour Node.js, et permet d'installer les outils de l'environnement de développement ainsi que les dépendances de notre projet.
$ npm search
nom-du-module $ npm install nom-du-module $ sudo npm install nom-du-module -g $ npm install $ npm update
"dependencies": {
"@angular/http": "2.0.0-rc.2",
"@angular/common": "2.0.0-rc.2",
"@angular/compiler": "2.0.0-rc.2",
"@angular/core": "2.0.0-rc.2",
"@angular/forms": "^0.1.0",
"@angular/platform-browser": "2.0.0-rc.2",
"@angular/platform-browser-dynamic": "2.0.0-rc.2",
"@angular/platform-server": "2.0.0-rc.2",
"@angular/router": "3.0.0-alpha.7",
"@angular/router-deprecated": "2.0.0-rc.2",
"ie-shim": "^0.1.0",
"core-js": "^2.4.0",
"rxjs": "5.0.0-beta.9",
"zone.js": "~0.6.12"
}
module bundler.
The
production
unbiased
flexible
extensible
open source
Webpack va prendre en charge le build et le développement de A à Z.
$ npm i webpack webpack-dev-server -D
Une fois l'installation terminée, nous avons accés à ces deux éxécutables dans les "scripts" du package.json
{
"scripts": {
"build:prod": "webpack --progress -p",
"server:dev":
"webpack-dev-server --inline --progress"
}
}
module.exports = { debug: true, cache: true,
devtool: 'cheap-module-eval-source-map', entry: { vendor: './src/vendor.js', main: './src/app.js', }, output: {
path: 'dist', filename: '[name].bundle.js', sourceMapFilename: '[name].map', chunkFilename: '[id].chunk.js' },
plugins: [ new DefinePlugin({ 'ENV': JSON.stringify(process.env.ENV), }), ], module: { loaders: [ { test: /\.js$/,
loader: 'babel-loader' }, { test: /\.css$/, loader: 'style!css' }, { test: /\.html$/, loader: 'raw-loader' }, ] }
});
Remplace le live-reload
Applique des changements dans votre application sans rechargement de la page.
Fonctionne grace à un webSocket.
Nécessite l'utilisation de plugins.
Outils de qualimétrie pour le js et le jsx
Fonctionne avec l'ensemble des outils de dev traditionnels: IDE, build ....
Fichier de configuration à placer dans le repertoire concerné.
Possibilité d'avoir plusieurs fichiers par projet.
{
"parser": "babel-eslint",
"extends": "airbnb",
"env": {
"browser": true,
"node": true
},
"rules": {
"semi": [
"error",
"never"
],
"arrow-body-style": 0,
"arrow-parens": 0,
"no-confusing-arrow": 0,
"no-console": 0
}
}