es2015 - enhance angular 1x applications

Post on 14-Apr-2017

393 Views

Category:

Software

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

ES2015ENHANCE ANGULAR 1.X APPLICATIONS

Ernest Nowacki

AGENDAWhat?Why?How?Raw meat!

WHAT?ES2015 is a significant and the first update to the

language since ES5 was standardized in 2009

FEATURESlet + const arrows classes

enhanced object literals modules promises

template strings destructuring default + rest + spread

iterators + for..of generators subclassable built-ins

map + set + weakmap + weakset proxies symbols

math + number + string + array + object APIs binary and octal literals tail calls

unicode

WHY?This Ecma Standard has been adopted by the General

Assembly of June 2015.

PROSBackward compatibilityLess boilerplateBetter maintainabilityBetter preparation for Angular 2.0Easier for newcomersStaying current

Slide from Jafar Husain's talk: ES7 evolution of JS

CONSBrowser compatibilityRequire transpilationNo established best practisesNew things to learn

http://kangax.github.io/compat-table/es6

HOW?

http://babeljs.io

SIMPLE INTEGRATIONvar gulp = require("gulp");var babel = require("gulp­babel");

gulp.task("default", function () return gulp.src("src/app.js") .pipe(babel()) .pipe(gulp.dest("dist")););

ONLINE PLAYGROUND

http://babeljs.io/repl

WEBPACK

http://webpack.github.io

JUMP START WEBPACK + BABEL +ANGULAR: GULP-ANGULAR

yo gulp­angular

DIVE DEEP

LET, CONST, BLOCK SCOPElet a = 2; let a = 3; console.log( a ); // 3console.log( a ); // 2

const a = 2; console.log( a ); // 2 a = 3; // TypeError!

BLOCK SCOPING ES5 VS ES2015if (true) function weather() console.log( "Sun" ); else function weather() console.log( "Rain" ); weather();

ES5var funcs = [];for (var i = 0; i < 5; i++) funcs.push( function() console.log( i ); );funcs[3](); // 5

ES2015var funcs = [];for (let i = 0; i < 5; i++) funcs.push( function() console.log( i ); );funcs[3](); // 3

TEMPORAL DEAD ZONE(TDZ)

TEMPORAL DEAD ZONE (TDZ)console.log( a ); // undefinedconsole.log( b ); // ReferenceError!var a;let b;

if( typeof a === 'undefined' ) console.log('a is ok');

if( typeof b === 'undefined' ) //ReferenceError! console.log('b is ok');

let b;

*it's not an issue when using babel

(NOT SO) CONSTconst arr = ['dog', 'cat', 'snake'];arr.push('fish');console.log(arr); // ['dog', 'cat', 'snake', 'fish'];

EVOLUTION OF CONTROLLERS

BEGINING'use strict';

angular.module('app').controller('TodoCtrl', function($scope) $scope.todos = [];

$scope.newTodo = '' ;

$scope.addTodo = function(todo) $scope.todos.push(todo);

$scope.removeTodo = function (todo) $scope.todos.splice($scope.todos.indexOf(todo), 1); ;);

<div ng­controller="TodoCtrl"> <input type="text" ng­model="newTodo"> <button type="button" ng­click="addTodo(newTodo)"></button> <ul> <li ng­repeat="todo in todos"> todo <button type="button" ng­click="removeTodo(todo)"></button> </li> </ul></div>

SMALL IMPROVEMENTS(function () 'use strict'; angular.module('app').controller('TodoCtrl', TodoCtrl);

function TodoCtrl($scope) $scope.todos = []; $scope.newTodo = '' ;

$scope.addTodo = function addTodo(todo) $scope.todos.push(todo);

$scope.removeTodo = function removeTodo(todo) $scope.todos.splice($scope.todos.indexOf(todo), 1); ; );

controllerAs<div ng­controller="TodoCtrl as ctrl"> <input type="text" ng­model="ctrl.newTodo"> <button type="button" ng­click="ctrl.addTodo(newTodo)"></button> <ul> <li ng­repeat="todo in ctrl.todos"> todo <button type="button" ng­click="ctrl.removeTodo(todo)"></button </li> </ul></div>

(function () 'use strict'; angular.module('app').controller('TodoCtrl', TodoCtrl);

function TodoCtrl() this.todos = []; this.newTodo = '' ;

this.addTodo = function addTodo(todo) this.todos.push(todo);

this.removeTodo = function removeTodo(todo) this.todos.splice(this.todos.indexOf(todo), 1); ; );

ALMOST THERE BUT ..

FINAL FORM(function () 'use strict'; angular.module('app').controller('TodoCtrl', TodoCtrl);

function TodoCtrl() var vm = this; vm.todos = []; vm.newTodo = '' ;

vm.addTodo = addTodo; vm.removeTodo = removeTodo;

function addTodo(todo) vm.todos.push(todo);

function removeTodo(todo) vm.todos.splice(vm.todos.indexOf(todo), 1);

ES6 CLASSES'use strict';

class TodoCtrl constructor() this.todos = []; this.newTodo = '';

addTodo(todo) this.todos.push(todo);

removeTodo(todo) this.todos.splice(this.todos.indexOf(todo), 1); ;angular.module('app').controller('TodoCtrl', TodoCtrl);

ORLY?

ES5 PROTOTYPESfunction TodoCtrl() this.todos = []; this.newTodo = '';TodoCtrl.prototype.addTodo = function(todo) this.todos.push(todo);TodoCtrl.prototype.removeTodo = function(todo) this.todos.splice(this.todos.indexOf(todo), 1);;angular.module('app').controller('TodoCtrl', TodoCtrl);

SETTERS AND GETTERSclass MyClass constructor() this._prop = 0; get prop() console.log('getter'); return this._prop; set prop(value) console.log('setter: ' + value); this._prop = value;

let inst = new MyClass();inst = 123; // setter + 123inst.prop; // getter //123

EASY EXTENDINGclass Foo constructor(a,b) this.x = a; this.y = b;

gimmeXY() return this.x * this.y;

class Bar extends Foo constructor(a,b,c) super( a, b ); this.z = c;

gimmeXYZ()

CLASS SUMMARYMust be used with new operator, unlike ES5Foo.call(obj);It's not hoisted!Can not declare properties outside of constructor(except ES7 private proposal)Can not access super properties in constructorConstructor is optional

HANDLING DIclass Ctrl constructor(Service, AnotherService) this.Service = Service; this.AnotherService = AnotherService;

doSomething() this.Service.doSomething();

MY PREFERRED WAYlet internal;

class Ctrl constructor(Service, AnotherService) internal = Service, AnotherService;

doSomething() internal.Service.doSomething();

BE CAREFUL WITH GETTERS<span ng­repeat="n in ctrl.items100 track by $index"> e2Ctrl.test</span>

class Ctrl constructor() this.items100 = new Array(100); this._test = 'some test value';

get test() console.log('test'); return this._test;

//100x test + in digest cycles

COMMON LOGIC IN SERVICESclass StateAware constructor() this.state = current: 'init' ;

load() this.state.current = 'loading'; return this.loadData() .then((resp) => this.data = resp; ) .finally(() = > this.state.current = 'ready'; );

HOW ABOUT DIRECTIVES?

class Sample constructor() this.restrict = 'E'; this.scope = ; this.controller = 'SampleCtrl'; this.controllerAs = 'ctrl'; this.templateUrl = 'sample.html'; this.bindToController = info: '=' ; angular.module('app').directive('sample', () => new Sample());

MODULES

KEEPING IT SIMPLEconsole.log('This will fire on import');var globalVariable = "This looks bad";

class Ctrl something() return 'something'; angular.module('app').controller('Ctrl', Ctrl);

angular.module('app', []);import 'Ctrl';console.log(globalVariable);

//This will fire on import//undefined

BEING MORE SPECIFICclass Service something() return 'something'; export default Service;

import Service from './services/Service';

angular.module('app', []).service('Service', Service);

BEING PICKYclass Component constructor() //.. standard DDO this.controller = 'Ctrl'; this.controllerAs = 'ctrl'; this.bindToController = true; this.template = '<div>ctrl.something</div>'; class Ctrl constructor() this.something = 'Some text'; export Component, Ctrl ;

import Component, Ctrl from 'componentDirective';angular.module('app', []) .controller('Ctrl', Ctrl) .directive('component', () => new Component());

IMPORTING WITH ALIASexport function helperFunction() // ..export function getSomething() // ..export var randomVariable = 'o_O';

import * as lib from 'helpers';

lib.helperFunction();console.log(lib.randomVariable);

WHY MODULES?Standarized syntaxBetter code organizationAvoid pollution of global namespace

let data = [ id: 1, name: 'John Snow', deleted: true, id: 2, name: 'Ned Stark', deleted: true, //.. far far down .. id: 60, name: 'Aria Stark', deleted: false];

Standard functiondata.filter(function(person) return !person.deleted;);

Arrow functiondata.filter(person => !person.deleted);

USAGE IN CALLBACKSfunction Clickable() this.clicks = 0;

$('.elem').on('click', () => this.clicks++; console.log(this.clicks); );

MULTIPLE ARGUMENT CALLSdata.forEach((person, index) => console.log(`$index. $person.name`););

SYNTAX GOTCHAlet returnItem = id => (id: id, name: 'Some name');

SUMMARY1. Lexical this2. Can't change this3. Can't be used with new4. Don't have arguments array-like object

TEMPLATE STRINGSlet name = "Ice Cube";let greeting = `Hello $name!`;console.log(greeting); //Hello Ice Cube

var text =`This ismore then oneline!`;

console.log( text );//This is//more then one//line!

TAGGINGlet message = Currency`You should pay $value @currency@ discount.`;

function Currency(templateData, ...args) return templateData.map((part, index) => let str = part; if( args[index] ) str = part + String(args[index]); return str.replace('@currency@', 'PLN'); ).join('');

setOptions(0, 500); //500, 500, blur

DEFAULT, SPREAD, RESTES5

function setOptions(debounce, interval, event) debounce = debounce || 500; interval = interval || 100; event = event || 'blur';

console.info(debounce, interval, event);

setOptions(); //500, 100, blursetOptions(200); //200, 100, blursetOptions(undefined, null, 'change'); //500, 100, change

setOptions(undefined, null, 'change'); //500, 0, change

ES2015function setOptions(debounce = 500, interval = 100, event = 'blur') console.info(debounce, interval, event);

setOptions(); //500, 100, blursetOptions(200); //200, 100, blursetOptions(0, 500); //0, 500, blur

SPREADES5

function foo(x,y,z) console.log( x, y, z );foo.apply( null, [1,2,3] ); // 1 2 3

ES2015function foo(x,y,z) console.log( x, y, z );foo( ...[1,2,3] ); // 1 2 3

ANOTHER USAGE OF SPREADlet a = [2,3,4];let b = [ 1, ...a, 5 ];console.log( b ); // [1,2,3,4,5]

RESTfunction foo(x, y, ...z) console.log( x, y, z );foo( 1, 2, 3, 4, 5 ); // 1 2 [3,4,5]

ES5function test() var args = Array.prototype.slice.call( arguments ); //do sth

ES2015function test(...args) //do sth

DESTRUCTURING, PROPERTY ASSIGNSHORTCUTS

ES5function data() return [1, 2, 3];let tmp = data();let a = tmp[0], //a = 1 b = tmp[1], //b = 2 c = tmp[2]; //c = 3

ES2015function data() return [1, 2, 3];let [a,b,c] = data(); // a = 1, b = 2, c = 3

DESTRUCTURING OBJECTSfunction data() return firstName: 'John', lastName: 'Snow', occupation: 'Lord Commander of the Night's Watch' ;var firstName, lastName: a, occupation: b = data();

//firstName = 'John',//a: 'Snow',//b: 'Lord Commander of the Night's Watch'

UNIVERSITY CLASSIC - VARIABLE SWAPvar x = 10, y = 20;[ y, x ] = [ x, y ];console.log( x, y ); // 20 10

DESTRUCTURE NULL OR UNDEFINED =ERROR!

let x, y = null;let a, b = undefined;

HOWEVER UNEXISTING VARIABLESARE OK

let options = a: 1, b: 2;let a, c = options;console.log(a); // 1console.log(b); //undefinedconsole.log(c); //undefined

SYNTAX GOTCHAlet person = id: 1, address: street: 'Przy parku', city: 'Warszawa' ;let id;let address;

id, address = person; //Error(id, address = person); //Ok!

OBJECTS AND ARRAYS AREDESTRUCTURED AS REFERENCES!

let color = name: 'white', rgb: [255, 255, 255];

let name: colorName, rgb = color;console.log(colorName); //'white'console.log(rgb); //[255, 255, 255]console.log(rgb === color.rgb); // true

DESTRUCTURE FUNCTION PARAMS

ES5function setCookie(name, value, options) options = options || ; let secure = options.secure; let path = options.path; let domain = options.domain; //....

setCookie('presentation', 'es2015', secure: false;);

DESTRUCTURE FUNCTION PARAMS

ES2015function setCookie(name, value, secure, path, domain = ) //...

setCookie('presentation', 'es2015', secure: false;);

PROMISES

ES2015 PROMISE SYNTAXvar promise = new Promise((resolve, reject) => setTimeout(resolve, 1000););

REMOVING CALLBACK LEGACY CODEimport LegacyLib from 'LegacyLib';

let internal;class LegacyLibDecorator constructor($q) internal = $q; loadData() let deferred = $q.defer(); LegacyLib.loadData( result => deferred.resolve(result), error => deferred.reject(error) ); return deferred;

REFACTOR USING PROMISE SYNTAXimport LegacyLib from 'LegacyLib';

let internal;class LegacyLibDecorator constructor($q) internal = $q; loadData() return $q((resolve, reject) => LegacyLib.loadData( result => resolve(result), error => reject(error) ); );

Mozilla Hacks: ES6 in depth

ExploringJS Feature overview

Babel learn-es6 Great talk to go to next

http://hacks.mozilla.org/category/es6-in-depthhttp://exploringjs.com/es6/

http://github.com/lukehoban/es6featureshttp://babeljs.io/docs/learn-es2015/

https://www.youtube.com/watch?v=DqMFX91ToLw

top related