ECMAScript 6不完全教程

1. 尝试ES6

这里有三种简朴地体式格局用于ES6编程:

  1. Web浏览器:运用Babel REPL,能够将ES6编译成ES5的平台,而且并不须要装置。

  2. 敕令行:运用babel-node,能够实行ES6的Node.js版本(会在内部编译es5)。须要经由过程npm装置。

  3. 种种js引擎:依据ES6语法兼容表,找出被支撑的ES6功用。

关于第一点和第二点,这有更多细节。

1.1 Babel REPL

Babel REPL主要有四个部份:

1、左上角包括es6源代码
2、左下角能够检察es6中的语法错误
3、右上角是es6被编译成es5的源代码
4、右下角是经由过程console.log()的输出结果

《ECMAScript 6不完全教程》

1.2 babel-node

babel-node能够经由过程npm装置:

$ npm install --global babel

跟node一样,能够敕令开启REPL交互:

$ babel-node

一旦开启REPL,就能够去实行ES6代码:

> let arr = [1, 2, 3];
> arr.map(x => x * x)
[ 1, 4, 9 ]

注重:babel-node现在不支撑多行输入
Babel官网上有管多关于Babel CLI的东西。

2. 从var到let/const

es6有两种新的体式格局来声明变量:
1、let用于声明块级作用于变量
2、const用于声明常量,其值不能被转变。

letconst能够用来替换var声明变量,然则不能自觉运用,由于差异的作用域会转变代码的行动。比方:

    var x = 3;
    function func(randomize) {
        if (randomize) {
            var x = Math.random(); // (A) scope: whole function
            return x;
        }
        return x; // accesses the x from line A
    }
    func(false); // undefined

func()会心外埠返回undefined。你能够重写这部份代码,就晓得为何返回undefined了:

    var x = 3;
    function func(randomize) {
        var x;
        if (randomize) {
            x = Math.random();
            return x;
        }
        return x;
    }
    func(false); // undefined

假如用let替代之前的var,就会获得差异的结果:

    let x = 3;
    function func(randomize) {
        if (randomize) {
            let x = Math.random();
            return x;
        }
        return x;
    }
    func(false); // 3

因此,自觉地用letconst替代var是有风险的,我的发起是:
1、只在新代码中运用letconst
2、丢弃旧代码或细致认证

更多信息:es6中的变量和作用域

3. 从IIFEs到代码块

在es5中,假如要保护当地变量,不能不运用IIFE:

(function () {  // open IIFE
        var tmp = ···;
        ···
    }());  // close IIFE
    
    console.log(tmp); // ReferenceError

而在es6中,则只须要代码块和let声明:

    {  // open block
        let tmp = ···;
        ···
    }  // close block
    
    console.log(tmp); // ReferenceError

更多信息:防止IIFEs

4. 从字符串拼接到模板常量

在es6中,关于字符串插值和多行字符串,Javscript能获得其字面值。

4.1 字符串插值

在es5中,是将结果放在字符串中举行拼接:

 function printCoord(x, y) {
        console.log('('+x+', '+y+')');
    }

es6中,经由过程字符串字面模板,能够在字符串中插进去变量值:

function printCoord(x, y) {
        console.log(`(${x}, ${y})`);
    }
4.2 多行字符串

模板字面量也能输出多行字符串。
比方,在es5中,输出多行字符串,得如许:

var HTML5_SKELETON =
        '<!doctype html>\n' +
        '<html>\n' +
        '<head>\n' +
        '    <meta charset="UTF-8">\n' +
        '    <title></title>\n' +
        '</head>\n' +
        '<body>\n' +
        '</body>\n' +
        '</html>\n';

假如经由过程反斜线转义新行,代码看起来会惬意点(但照样要显现的增加新行):

var HTML5_SKELETON = '\
        <!doctype html>\n\
        <html>\n\
        <head>\n\
            <meta charset="UTF-8">\n\
            <title></title>\n\
        </head>\n\
        <body>\n\
        </body>\n\
        </html>';

而es6得模板字面量能跨多行:

const HTML5_SKELETON = `
        <!doctype html>
        <html>
        <head>
            <meta charset="UTF-8">
            <title></title>
        </head>
        <body>
        </body>
        </html>`;

更多信息:字面量模板

5. 从函数表达式到箭头函数

在es5中,在函数表达式中必需警惕运用this。在示例中,我建立了辅佐变量_this_,以便于我能再line B处运用:

function UiComponent {
        var _this = this; // (A)
        var button = document.getElementById('myButton');
        button.addEventListener('click', function () {
            console.log('CLICK');
            _this.handleClick(); // (B)
        });
    }
    UiComponent.prototype.handleClick = function () {
        ···
    };

在es6中,能够运用箭头函数,它不会影响this

class UiComponent {
        constructor() {
            let button = document.getElementById('myButton');
            button.addEventListener('click', () => {
                console.log('CLICK');
                this.handleClick(); // (A)
            });
        }
        handleClick() {
            ···
        }
    }

关于只返回结果的短小回调函数,箭头函数是异常方便的。
在es5中,以下的回调是相对冗杂的:

var arr = [1, 2, 3];
    var squares = arr.map(function (x) { return x * x });

在es6中,箭头函数会更简约:

let arr = [1, 2, 3];
    let squares = arr.map(x => x * x);

在定义参数时,假如只要一个参数,括号是能够省略的。因此,(x) => x x and x => x x 都是许可的。
更多信息:箭头函数

6. 处置惩罚多个返回值

一些函数或要领能经由过程数组或对象返回多个值。在es5中,老是须要建立中心变量来接见返回值。es6中,能够运用解构。

6.1 经由过程数组返回多个值

exec()返回类数组对象的捕捉组。es5中,当要接见捕捉组的值时,须要一个中心变量:

var matchObj =
        /^(\d\d\d\d)-(\d\d)-(\d\d)$/
        .exec('2999-12-31');
    var year = matchObj[1];
    var month = matchObj[2];
    var day = matchObj[3];

es6中,解构使代码更简朴:

let [, year, month, day] =
        /^(\d\d\d\d)-(\d\d)-(\d\d)$/
        .exec('2999-12-31');

空得逗号示意跳过数组的第一个元素。

6.2 经由过程对象返回多个值

Object.getOwnPropertyDescriptor()会返回一个属性描述符对象。

es5中,仍须要一个中心变量来接见你感兴趣的对象属性值:

var obj = { foo: 123 };
    
    var propDesc = Object.getOwnPropertyDescriptor(obj, 'foo');
    var writable = propDesc.writable;
    var configurable = propDesc.configurable;
    
    console.log(writable, configurable); // true true

es6,能够运用解构:

let obj = { foo: 123 };
    
    let {writable, configurable} =
        Object.getOwnPropertyDescriptor(obj, 'foo');
    
    console.log(writable, configurable); // true true

{writable, configurable}的值以下:

 { writable: writable, configurable: configurable }

更多信息:解构

7. 从for到forEach再到for-of

先说es6,平常会如许迭代数组:

var arr = ['a', 'b', 'c'];
    for (var i=0; i<arr.length; i++) {
        var elem = arr[i];
        console.log(elem);
    }

也能够运用ArrayforEach

arr.forEach(function (elem) {
        console.log(elem);
    });

for轮回的长处是能够中缀,forEach的长处是简约。
而es6的for-of轮回则连系了二者的长处:

let arr = ['a', 'b', 'c'];
    for (let elem of arr) {
        console.log(elem);
    }

for-of轮回也能经由过程数组的entries要领和解构返回数组的索引和对应的值:

for (let [index, elem] of arr.entries()) {
        console.log(index+'. '+elem);
    }

更多信息:for-of轮回

8. 参数默许值

es5中,指定参数默许值得如许:

function foo(x, y) {
        x = x || 0;
        y = y || 0;
        ···
    }

es6有个更简约的语法:

function foo(x=0, y=0) {
        ···
    }

es6语法还一个长处:参数默许值只能被undefined触发,而在es5中,则会被任何z为false的值触发。

更多信息:参数默许值

9. 定名参数

在Javascript中,定名参数的广泛体式格局是对象字面量:

selectEntries({ start: 0, end: -1 });

其等价完成:

function selectEntries(options) {
        var start = options.start || 0;
        var end = options.end || -1;
        var step = options.step || 1;
        ···
    }

es6中,解构是语法更简朴:

function selectEntries({ start=0, end=-1, step=1 }) {
        ···
    }
9.1 使参数可选

es5中使参数可选的做法是如许的:

function selectEntries(options) {
        options = options || {}; // (A)
        var start = options.start || 0;
        var end = options.end || -1;
        var step = options.step || 1;
        ···
    }

es6中,能够指定{}为参数的默许值:

function selectEntries({ start=0, end=-1, step=1 } = {}) {
        ···
    }

更多信息:模仿定名参数

10. 从arguments到参数扩大

es5中,若想让要领或函数接收恣意个数的参数,就必需运用指定的arguments变量:

function logAllArguments() {
        for (var i=0; i < arguments.length; i++) {
            console.log(arguments[i]);
        }
    }

es6中,能够运用...操纵到达同样地结果:

function logAllArguments(...args) {
        for (let arg of args) {
            console.log(arg);
        }
    }

另有更nice的语法:

function format(pattern, ...args) {
        ···
    }

而es5中的处置惩罚则相对愚笨:

function format() {
        var pattern = arguments[0];
        var args = arguments.slice(1);
        ···
    }

更多信息:Rest parameters

11. 从apply到漫衍操纵符(…)

es5中,apply()会将数组转会成参数,es6中运用漫衍操纵符到达同样地目标。

11.1 Math.max()

es5–>apply():

> Math.max.apply(null, [-1, 5, 11, 3])
    11

es6–>spread operator:

> Math.max(...[-1, 5, 11, 3])
    11
11.2 Array.prototype.push()

es5–>apply():

    var arr1 = ['a', 'b'];
    var arr2 = ['c', 'd'];
    
    arr1.push.apply(arr1, arr2);
        // arr1 is now ['a', 'b', 'c', 'd']

es6–>spread operator:

    let arr1 = ['a', 'b'];
    let arr2 = ['c', 'd'];
    
    arr1.push(...arr2);
        // arr1 is now ['a', 'b', 'c', 'd']

更多信息:spread operator

12. 从concat()到(…)

ES5 – concat():

    var arr1 = ['a', 'b'];
    var arr2 = ['c'];
    var arr3 = ['d', 'e'];
    
    console.log(arr1.concat(arr2, arr3));
        // [ 'a', 'b', 'c', 'd', 'e' ]

ES6 – spread operator:

    let arr1 = ['a', 'b'];
    let arr2 = ['c'];
    let arr3 = ['d', 'e'];
    
    console.log([...arr1, ...arr2, ...arr3]);
        // [ 'a', 'b', 'c', 'd', 'e' ]

更多信息:spread operator

13. 从组织器到类

关于组织器语法,es6的类则更轻便。

13.1 基本类

es5中完成一个基本类以下:

function Person(name) {
        this.name = name;
    }
    Person.prototype.describe = function () {
        return 'Person called '+this.name;
    };

es6中,类供应了更简约的语法:

class Person {
        constructor(name) {
            this.name = name;
        }
        describe() {
            return 'Person called '+this.name;
        }
    }

13.2 派生类

es5完成了类的派生,下面是完成派生类的一种范例要领:

function Employee(name, title) {
        Person.call(this, name); // super(name)
        this.title = title;
    }
    Employee.prototype = Object.create(Person.prototype);
    Employee.prototype.constructor = Employee;
    Employee.prototype.describe = function () {
        return Person.prototype.describe.call(this) // super.describe()
               + ' (' + this.title + ')';
    };

es6内置了类派生语法,要借助extends关键字:

class Employee extends Person {
        constructor(name, title) {
            super(name);
            this.title = title;
        }
        describe() {
            return super.describe() + ' (' + this.title + ')';
        }
    }

更多信息:

14. 从自定义error到Error派生

跟上面有点相似。es5中自定义error:

function MyError() {
        // Use Error as a function
        var superInstance = Error.apply(null, arguments);
        copyOwnPropertiesFrom(this, superInstance);
    }
    MyError.prototype = Object.create(Error.prototype);
    MyError.prototype.constructor = MyError;

es6经由过程派生完成:

class MyError extends Error {
    }

更多自信心:Subclassing built-in constructors

15. 从对象字面量的函数表达式和要领定义

语法上的差异。es5完成:

var obj = {
        foo: function () {
            ···
        },
        bar: function () {
            this.foo();
        }, // trailing comma is legal in ES5
    }

es6:

 let obj = {
        foo() {
            ···
        },
        bar() {
            this.foo();
        },
    }

更多信息:要领定义

16. 从对象到图

es5中应用对象来完成图的数据结构,须要将对象的prototype指向null,并保证__proto__上没有对应的键。

var dict = Object.create(null);
    function countWords(word) {
        var escapedWord = escapeKey(word);
        if (escapedWord in dict) {
            dict[escapedWord]++;
        } else {
            dict[escapedWord] = 1;
        }
    }
    function escapeKey(key) {
        if (key.indexOf('__proto__') === 0) {
            return key+'%';
        } else {
            return key;
        }
    }

es6则内置了Map数据结构;

let map = new Map();
    function countWords(word) {
        let count = map.get(word) || 0;
        map.set(word, count + 1);
    }

更多信息:Maps and Sets

17. 从CommonJS模块到es6 模块

es5中,模块体系是基于AMD或CommocJS语法。es6内置了模块语法,但并没有获得Javascript引擎优越支撑。

17.1 多个导出

在CommonJS中,能够如许完成:

 //------ lib.js ------
    var sqrt = Math.sqrt;
    function square(x) {
        return x * x;
    }
    function diag(x, y) {
        return sqrt(square(x) + square(y));
    }
    module.exports = {
        sqrt: sqrt,
        square: square,
        diag: diag,
    };
    
    //------ main1.js ------
    var square = require('lib').square;
    var diag = require('lib').diag;
    
    console.log(square(11)); // 121
    console.log(diag(4, 3)); // 5

es6的语法是酱紫的:

//------ 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));
    }
    
    //------ main1.js ------
    import { square, diag } from 'lib';
    console.log(square(11)); // 121
    console.log(diag(4, 3)); // 5

或许作为一个对象导入:

//------ main2.js ------
    import * as lib from 'lib'; // (A)
    console.log(lib.square(11)); // 121
    console.log(lib.diag(4, 3)); // 5
17.2 单个导出

Node.js继续了CommonJS的语法,能从模块导出单个值:

 //------ myFunc.js ------
    module.exports = function () { ··· };
    
    //------ main1.js ------
    var myFunc = require('myFunc');
    myFunc();

es6经由过程export default完成:

//------ myFunc.js ------
    export default function () { ··· } // no semicolon!
    
    //------ main1.js ------
    import myFunc from 'myFunc';
    myFunc();

更多信息:Modules

相干文章:ECMAScript 6新特征引见
译文出处:Getting started with ECMAScript 6

    原文作者:不写代码的码农
    原文地址: https://segmentfault.com/a/1190000003771043
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞