ES6 In 

Modern Development

By

       汤桂川  @广发证券

About me

汤桂川

资深汕头人

写代码、爱旅游

@ 腾讯 - AlloyTeam 前端工程师

  • WebQQ and Smart QQ
  • PC QQ and QQ群
  • 手机QQ:吃喝玩乐,兴趣部落

@ 广发证券 - 资深前端工程师

  • 广发微店 - 易淘金
  • 广发大数据日志平台
  • 金钥匙 - 金融界的Uber

Agenda - 大纲

① ES6介绍

  • JavaScript简史
  • 重点新特性
  • Coding Style
  • Best Practice

② ES6实战开发

  • Angular - ES6 

  • Angular 2.0

  • Babel

  • jspm, Webpack, Gulp

  • Linting,  Debug , Test

  • React, Node, Meteor - ES6

③ 发展趋势

  • ES7
  • Babel support
  • Trending

Part 1 - ES6介绍

👐

 

  • 1995 LiveScript发布      随后改名为 JavaScript
  • 1997 ECMAScript 1 
  • 1999 ES3 (大变化)
  • ES4 流产 (harmony)
  • 2009  ES5(ES3.1)
  • 2015. 06. 17   ES6  ECMAScript 2015 

JavaScript简史

Brendan Eich  @Netscape

->1993年的小鲜肉

ECMAScript 5 在浏览器的实现情况

数据来源:http://kangax.github.io/compat-table/es5/

ECMAScript 6 在浏览器的实现情况

数据来源:http://kangax.github.io/compat-table/es6/

ES6 重点新特性

爱看规范的男生运气不会太差。

-- 乔布斯??

Arrows

Syntax

const name = 'object name';
let obj = {
  name,
  init() {
    // Lexical this
    $.on('click', () => this.name);
  }
};
  • C# 3.0 lambda 
  • Lexical this
  • 单行隐性return value
  • No arguments object
// 以上代码等同于 ES5
var name = 'object name';
var obj = {
  name: name,
  init: function init() {
    var _this = this;
    
    $.on('click', function () {
      return _this.name;
    });
  }
};

严格模式下,模块里顶层的this是undefined

 

//改造一下上面例子,this变成什么?
let obj = {
    init: ()=> this
};

注意点(keng) :

// 上面代码等同于:
var obj = {
    init: function test() {
        return undefined;
    }
};

Template String

Syntax

// 多行字符串,引号
var multiStr = `In 'JavaScript' this is
                not legal.`;

// 字符串插值
var name = "QCon", time = "today";
console.log(`Hello ${name},
how are you ${time}?`);

注意点(keng) ?

Classes

Syntax

class Animal {
  constructor(name) {
    this.name = name;
  }
  say(msg){
    alert(`${this.name} says ${msg}`);
  }
  static staticMethod() {
    return '不能被实例继承,子类可继承父类';
  }
}
class Panda extends Animal {
  say(msg = 'hi') {
    super(msg); // 调用父类say方法
  }
}
let panda = new Panda('Tuan');
panda.say(); // 'Tuan says hi'
panda.say('Ooooh'); // 'Tuan says Ooooh'
  • constructor
  • this
  • default
  • extends
  • super
  • 静态方法
// 上面代码转换为ES5 
'use strict';

function _inherits(subClass, superClass) { 
if (typeof superClass !== 'function' && superClass !== null) { 
throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); 
} subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); 
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ superClass; 
}
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
var Animal = (function () {
  function Animal(name) {
    _classCallCheck(this, Animal);
    this.name = name;
  }
  Animal.prototype.say = function say(msg) {
    alert(this.name + ' says ' + msg);
  };
  Animal.staticMethod = function staticMethod() {
    return '不能被实例继承,子类可继承父类';
  };
  return Animal;
})();
var Panda = (function (_Animal) {
  _inherits(Panda, _Animal);
  function Panda() {
    _classCallCheck(this, Panda);
    _Animal.apply(this, arguments);
  }
  Panda.prototype.say = function say() {
    var msg = arguments.length <= 0 || arguments[0] === undefined ? 'hi' : arguments[0];
    _Animal.prototype.say.call(this, msg); // 调用父类say方法
  };
  return Panda;
})(Animal);
var panda = new Panda('Tuan');
panda.say(); // 'Tuan says hi'
panda.say('Ooooh'); // 'Tuan says Ooooh'
// 好
class SomeClass {
  constructor() {
    // constructor
  }

  get aval() {
    // public getter
  }

  set aval(val) {
    // public setter
  }

  doSth() {
    // 公用方法
  }

  get _aval() {
    // private getter
  }

  set _aval() {
    // private setter
  }

  _doSth() {
    // 私有方法
  }
}

Modules

Syntax

// 模块导入
import angular from 'angular';
import { lightRed } from './colors';
import * as UserModule from './user.module';

let userCtrl = UserModule.ctrl;

// 模块导出
export default lightRed;
export { userCtrl };

AMD, CommonJS, UMD

More Detail in: 下一代模块化的js

ES6Features

查看详情:  ES6features(中文版)

More Info About ES6:

Part 2 - ES6实战开发

Workflow:

  • Angular - ES6
  • Babel
  •  Webpack & Gulp & JSPM
  • ESlint
  • Debug & Unit Test
  • React , Node, Meteor - ES6

Angular - ES6

⬇️

Babel

⬇️

 Webpack & Gulp & JSPM

⬇️

ESlint

⬇️

Debug & Unit Test

⬇️

React , Node, Meteor - ES6

Angular.js

  • Angular ES5
  • Angular ES6
  • Angular 2.0

Angular ES6 VS ES5

angular.module('myapp', ['localInfos'])
.service('locationService', ['localInfo', '$q',
 function(localInfo, $q) {
    $scope.localInfo = localInfo;

    // 打印当前状态
    $scope.printInfo = function(msg) {
       msg = msg || 'unknown';
       console.log('State:' + msg);  
    };

    // 寻找当前位置
    $scope.findLocation = function() {
      var deferred = $q.defer();
      var self = this;
      
      navigator.geolocation.getCurrentPosition(function(pos) {
        pos = pos || {};
        self.printInfo('Location');
        self.localInfo.save(pos);
        deferred.resolve('You are at ' + pos.coords.latitude);
      }, deferred.reject);

      return deferred.promise;
    };
  }
]);
            

ES5 Angular 1.x Service

angular.module('myapp', ['localInfos'])
.service('locationService', LocationService);

class LocationService {
    constructor(localInfo, $q) {
        'ngInject';
        this.localInfo = localInfo;
        this.$q = $q;
    }

    // 打印当前状态
    printInfo(msg = 'unknown') {
       console.log(`State: ${msg}`);  
    }

    // 寻找位置
    findLocation() {
        return this.$q((resolve, reject) => {

            navigator.geolocation.getCurrentPosition((pos = {}) => {
                this.printInfo('Location');
                this.localInfo.save(pos);
                resolve(`You are at ${pos.coords.latitude}`);
            }, reject);
        });
    }
}

            

ES6 Angular 1.x Service

// 'app/index.js'
import angular from 'angular';
import UserService from './user.service';
import UserController from './user.controller';

angular.module('myApp',[])
.factory('userService', UserService)
.controller('userController', UserController);

使用gulp-inject进行自动import与组装angular模块

Note: 文件遵循自动化命名规范(如: shop.controller.auto.js)

Angular with es6 In Depth

// 变成自动注入与Angular模块组装
import ShopController from './shop.controller.auto';

angular.module('shop',[])
.controller('shopController', ShopController);
// "shop/shop.module.js"
import { ShopController } from './shop/shop.controller';
import { ShopService } from './shop/shop.service';
 
let ctrl = ShopController;
let svc = ShopService.init; 
 
export { svc };
export { ctrl };

另一种按页面进行分模块导入导出,

并可DIY暴露特定方法的模式

// 调用方 'index.js'
import * as ShopModules from './shop/shop.module';
 
angular.module('microshop',[])
.factory('shopSvc', ShopModules.svc)
.controller('shopCtrl', ShopModules.ctrl);
// 'user.service.js'
class UserService {
    constructor($http) {
        'ngInject';

        this.$http = $http;
        this.userUrl = '/serve/user/';
    }
    getUser(name = 'Hanmeimei') {
        return this.$http.get(this.userUrl + name)
            .then((response) => response.data);
    }
}

export default UserService;

'ngInject': 使用ng-annotate进行DI依赖自动注入

<div ng-app="myApp" ng-strict-di>

'ng-strict-di': missing DI annotations; ng 1.3 or later

Tips:  Directives - controller vs controllerAs

Angular ES6 VS 2.0

Angular 2.0

  • Why

  • What

 

 

  • When

AtScript vs TypeScript

No $scope, controller, 2-way data binding

No $watch, $apply: Zone.js

(events) , [properties]

 

 迁徙计划:

       Angular 1.4 Router

// Angular 2.0
import { UnicornHorn } from "../animals/unicorn";
class UnicornHype {
    constructor(unicornHorn:UnicornHorn) {
        this.horn = unicornHorn;
    }
    findUnicorn() {
        return new Promise((resolve, reject) => {
            navigator.geolocation.getCurrentPosition((pos) => {
                this.horn.thrust();
                resolve(`The unicorn is at ${pos.coords.latitude}`);
            }, reject);
        });
    }
}
          
            
// Angular ES6
angular.module('test', ['unicorn']).service('unicornHype', UnicornHype);
class UnicornHype {
    constructor(unicornHorn, $q) {
        'ngInject';    
        this.horn = unicornHorn;
        this.$q = $q;
    }
    findUnicorn() {
        return this.$q((resolve, reject) => {
            navigator.geolocation.getCurrentPosition((pos) => {
                this.horn.thrust();
                resolve(`The unicorn is at ${pos.coords.latitude}`);
            }, reject);
        });
    }
}
  

差异在哪儿?

完美

Who's using Angular ES6?

  • 广发证券金钥匙

 

  • 广发证券易淘金

 

  • 广发证券理财网店

Angular - ES6

⬇️

Babel

⬇️

Webpack & Gulp & JSPM

⬇️

ESlint

⬇️

Debug & Unit Test

⬇️

React , Node, Meteor - ES6

1.Compatibility(支持度高):

2.生态圈与社区成熟:

  • WHY

Eg:引擎优化

// ES6 
(...args) => args


// 转换为ES5
(function () {
  for (
        var _len = arguments.length, 
        args = Array(_len),
         _key = 0; 
        _key < _len;
         _key++
      ) {
    
    args[_key] = arguments[_key];
  }

  return args;
});

Babel中有哪些优雅的实现?

More Information:

Angular - ES6

⬇️

Babel

⬇️

Webpack & Gulp & JSPM 

⬇️

ESlint

⬇️

Debug & Unit Test

⬇️

React , Node, Meteor - ES6

// gulp与babel结合

var gulp = require("gulp");
var babel = require("gulp-babel");

gulp.task("default", function () {

  return gulp.src("src/app.js")

    .pipe(babel())

    .pipe(gulp.dest("dist"));
});

More Information:

Angular - ES6

⬇️

Babel

⬇️

Webpack & Gulp & JSPM

⬇️

ESlint

⬇️

Debug & Unit Test

⬇️

React , Node, Meteor - ES6

        -- ES6,AMD,CommonJS...

        -- babel-runtime

How

What

<!-- index.html -->

<script src="jspm_packages/system.js">
</script>
<script src="config.js"></script>
<script>
  System.import('./app/index');
</script>
// config.js
System.config({
  "baseURL": "/",
  "transpiler": "babel",
  "paths": {
    "*": "*.js",
    "github:*": "jspm_packages/github/*.js"
  }
});
  • Package Manager

        -- local git repos, Github, NPM, Bower

Angular - ES6

⬇️

Babel

⬇️

Webpack & Gulp & JSPM

⬇️

ESlint

⬇️

Debug & Unit Test

⬇️

React , Node, Meteor - ES6

ESLint

The pluggable linting utility for JavaScript and JSX

  • Why


  • How
  1. Support Babel    Transformed: ES7...
  2. Error Location Info

Angular - ES6

⬇️

Babel

⬇️

Webpack & Gulp & JSPM

⬇️

ESlint

⬇️

Debug & Unit Test

⬇️

React , Node, Meteor - ES6

HOW

  • - > ES5
  • Source Maps
  • Runtime Transpiler

Angular - ES6

⬇️

Babel

⬇️

Webpack & Gulp & JSPM

⬇️

ESlint

⬇️

Debug & Unit Test

⬇️

React , Node, Meteor - ES6

Tools

  • jasmine.js
  • karma.js

Setting up the test environment:

  • package.json
  • karma.config.js
  • test-context.js
// karma.config.js
module.exports = function(config) {
    config.set({
        browsers: ['PhantomJS'],
        frameworks: ['jasmine'],
        webpack: {
            module: {
                loaders: [{
                    test: /\.js/, 
                    loader: 'babel-loader', 
                    exclude: /node_modules/ 
                }]
            },
            watch: true
        }
    });
};
// test.js
export class Calculator{

    add(op1,op2){
        return op1 + op2;
    }

    subtract(op1,op2){
        return op1 - op2;
    }
}

Target File For Test:


// calculator-spec.js
import {Calculator} from './calculator';

describe('Calculator', () => {
   it('should add two numbers', () => {
       let calculator = new Calculator();
       let sum = calculator.add(1,4);
       expect(sum).toBe(5);
   });
    it('should subtract two numbers', () => {
        let calculator = new Calculator();
        let sum = calculator.subtract(4,1);
        expect(sum).toBe(3);
    });
});

Unit Test File:

Angular - ES6

⬇️

Babel

⬇️

Webpack & Gulp & JSPM

⬇️

ESlint

⬇️

Debug & Unit Test

⬇️

React , Node, Meteor - ES6

export class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = {count: props.initialCount};
  }
  tick() {
    this.setState({count: this.state.count + 1});
  }
  render() {
    return (
      <div onClick={this.tick.bind(this)}>
        Clicks: {this.state.count}
      </div>
    );
  }
}
Counter.propTypes = { 
    initialCount: React.PropTypes.number 
};
Counter.defaultProps = { initialCount: 0 };

Tools for react, jsx

Angular - ES6

⬇️

Babel

⬇️

Webpack & Gulp & JSPM

⬇️

ESlint

⬇️

Debug & Unit Test

⬇️

React Node, Meteor - ES6

           No more --harmony (Node v0.12)

 

 

  • shipping
  • staged
  • in progress

Angular - ES6

⬇️

Babel

⬇️

Webpack & Gulp & JSPM

⬇️

ESlint

⬇️

Debug & Unit Test

⬇️

React , Node, Meteor - ES6

 ES6 is now the official JavaScript

  of the Meteor platform.

 

 Every new Meteor project now uses ES6

  by default, in every JS file. 

  • 广发证券官网
  • 广发证券资管网
  • 广发证券操盘手
  • 广发证券理财APP

哪些产品使用了以上技术们?

Projects and Info

Part 3 - 发展趋势

ECMAScript 2016 (ES7)

方案生命周期 - stages:

   Stage 0  : Strawman  建议方案

   Stage  1  : Proposal     提案       

   Stage  2 :  Draft           草案          

   Stage  3 :  Candidate  候选方案   

   Stage  4 :  Finished     定案

Stage 0

Stage 1

Stage 2

Babel 支持

// 命令行
$ babel --stage 0

// 从代码里开启
babel.transform("code", { stage: 0 });

使用Babel玩转ES7

  • 开启支持stage里的特性
// 命令行 
$ babel --optional es7.decorators

// 从代码里开启
babel.transform("code", { optional: ["es7.decorators"] });
  • 单独开启某某ES7特性

注意:Stage 2 及以上是默认开启支持的

More Information:

Thank you!

By 汤桂川 with love

In Sydney  Fall 2015

广发证券前端团队愿景:

做地球上最有钱的前端团队

 

简历请砸:

⬇️

tangguichuan@gmail.com