美文网首页scriptDevs
ECMAScript 6 (ES6) 新特性介绍 二

ECMAScript 6 (ES6) 新特性介绍 二

作者: 乌龟怕铁锤 | 来源:发表于2017-12-14 11:24 被阅读11次

    原文地址 ECMAScript 6 — New Features: Overview & Comparison
    本文介绍 ECMAScript 6中的新特性并通过具体代码演示与ECMAScript 5的差别。译者额外增加了一些例子和说明 .

    ECMAScript 6 是2015年推出的第6版本的ECMAScript标准(即Javascript标准),同时也被成为ECMAScript 2015.

    ECMAScript 6 中定了了许多新的Javascript特性,包括新的类和模块,类似python的generators和generators表达式, 箭头函数, 二进制数据, 类型数组, 集合类型(maps, set & 弱maps), promises, reflection, proxy等。它也被称作 ES6 Harmony. (和谐ES6)

    本文是该系列文章的第二篇

    增强的对象属性

    变量速写

    缩短了对于对象属性的定义习惯

    ECMAScript 6的实现

    obj = { x, y }
    

    对比ECMAScript 5的实现

    obj = { x: x, y: y };
    

    支持表达式计算属性的定义

    支持表达式计算属性的定义

    ECMAScript 6的实现

    let obj = {
        foo: "bar",
        [ "baz" + quux() ]: 42
    }
    

    对比ECMAScript 5的实现

    var obj = {
        foo: "bar"
    };
    obj[ "baz" + quux() ] = 42;
    

    函数属性

    支持在对象中直接的函数符号定义, 普通函数和生产(generator)函数均可

    ECMAScript 6的实现

    obj = {
        foo (a, b) {
            …
        },
        bar (x, y) {
            …
        },
        *quux (x, y) {
            …
        }
    }
    

    对比ECMAScript 5的实现

    obj = {
        foo: function (a, b) {
            …
        },
        bar: function (x, y) {
            …
        },
        //  quux: ES5中没有这样的生产(generator)函数
        …
    };
    

    释放赋值

    数组的值匹配

    数组可以很直观的释放其中的值到不同的变量中去

    ECMAScript 6的实现

    var list = [ 1, 2, 3 ]
    var [ a, , b ] = list
    [ b, a ] = [ a, b ]
    

    对比ECMAScript 5的实现

    var list = [ 1, 2, 3 ];
    var a = list[0], b = list[2];
    var tmp = a; a = b; b = tmp;
    

    对象匹配的便捷符号

    可以很直观的把对象中的属性释放到对应的变量中

    ECMAScript 6的实现

    var { op, lhs, rhs } = getASTNode() // 返回obj中有op, lhs, rhs属性
    

    对比ECMAScript 5的实现

    var tmp = getASTNode();
    var op  = tmp.op;
    var lhs = tmp.lhs;
    var rhs = tmp.rhs;
    

    对象深层匹配

    对于多层的对象属性,也能够通过符号直观的匹配

    ECMAScript 6的实现

    var { op: a, lhs: { op: b }, rhs: c } = getASTNode() //其中的lhs是一个有op属性的对象
    

    对比ECMAScript 5的实现

    var tmp = getASTNode();
    var a = tmp.op;
    var b = tmp.lhs.op;
    var c = tmp.rhs;
    

    参数上下文匹配

    对函数传参的时候,也可以方便的把数组和对象释放成不同的参数

    ECMAScript 6的实现

    function f ([ name, val ]) { // 数组拆出值 相当于传入 (name, val)
        console.log(name, val)
    }
    function g ({ name: n, val: v }) { // 对象拆出值, 相当于传入 (n, v)
        console.log(n, v)
    }
    function h ({ name, val }) { // 对象拆出值, 相当于传入 (name, val)
        console.log(name, val)
    }
    f([ "bar", 42 ])
    g({ name: "foo", val:  7 })
    h({ name: "bar", val: 42 })
    

    对比ECMAScript 5的实现

    function f (arg) {
        var name = arg[0];
        var val  = arg[1];
        console.log(name, val);
    };
    function g (arg) {
        var n = arg.name;
        var v = arg.val;
        console.log(n, v);
    };
    function h (arg) {
        var name = arg.name;
        var val  = arg.val;
        console.log(name, val);
    };
    f([ "bar", 42 ]);
    g({ name: "foo", val:  7 });
    h({ name: "bar", val: 42 });
    

    释放的容错机制

    当释放的参数无法匹配上时,会自动容错到默认值

    ECMAScript 6的实现

    var list = [ 7, 42 ]
    var [ a = 1, b = 2, c = 3, d ] = list
    a === 7
    b === 42
    c === 3  // 匹配之前默认值3
    d === undefined // 无匹配 成为默认undefined
    

    对比ECMAScript 5的实现

    var list = [ 7, 42 ];
    var a = typeof list[0] !== "undefined" ? list[0] : 1;
    var b = typeof list[1] !== "undefined" ? list[1] : 2;
    var c = typeof list[2] !== "undefined" ? list[2] : 3;
    var d = typeof list[3] !== "undefined" ? list[3] : undefined;
    a === 7;
    b === 42;
    c === 3;
    d === undefined;
    

    模块

    模块值的导入和导出

    支持从模块中导入/导出值,但又不污染全局名字空间

    ECMAScript 6的实现

    //  lib/math.js
    export function sum (x, y) { return x + y } // 导出函数
    export var pi = 3.141593  // 导出变量 
    
    //  someApp.js
    import * as math from "lib/math"
    console.log("2π = " + math.sum(math.pi, math.pi))
    
    //  otherApp.js
    import { sum, pi } from "lib/math"
    console.log("2π = " + sum(pi, pi))
    
    

    对比ECMAScript 5的实现

    LibMath = {};
    LibMath.sum = function (x, y) { return x + y };
    LibMath.pi = 3.141593;
    
    //  someApp.js
    var math = LibMath;
    console.log("2π = " + math.sum(math.pi, math.pi));
    
    //  otherApp.js
    var sum = LibMath.sum, pi = LibMath.pi;
    console.log("2π = " + sum(pi, pi));
    

    默认和通配符

    可以通过通配符导出所有的符号, 通过标记default默认导出 (无需声明)
    ECMAScript 6的实现

    //  lib/mathplusplus.js
    export * from "lib/math"
    export var e = 2.71828182846
    export default (x) => Math.exp(x)  //默认导出exp函数
    
    //  someApp.js
    import exp, { pi, e } from "lib/mathplusplus"
    console.log("e^{π} = " + exp(pi))
    

    对比ECMAScript 5的实现

    //  lib/mathplusplus.js
    LibMathPP = {};
    for (symbol in LibMath)
        if (LibMath.hasOwnProperty(symbol))
            LibMathPP[symbol] = LibMath[symbol];
    LibMathPP.e = 2.71828182846;
    LibMathPP.exp = function (x) { return Math.exp(x) };
    
    //  someApp.js
    var exp = LibMathPP.exp, pi = LibMathPP.pi, e = LibMathPP.e;
    console.log("e^{π} = " + exp(pi));
    

    类定义

    更加直接,面向对象风格的类

    ECMAScript 6的实现

    class Shape {
        constructor (id, x, y) {   // 类的构造函数
            this.id = id
            this.move(x, y)
        }
        move (x, y) {   // 类函数
            this.x = x
            this.y = y
        }
    }
    

    对比ECMAScript 5的实现

    var Shape = function (id, x, y) {
        this.id = id;
        this.move(x, y);
    };
    Shape.prototype.move = function (x, y) {
        this.x = x;
        this.y = y;
    };
    

    类的继承

    面向对象风格的类继承方式
    ECMAScript 6的实现

    class Rectangle extends Shape {
        constructor (id, x, y, width, height) {
            super(id, x, y)
            this.width  = width
            this.height = height
        }
    }
    class Circle extends Shape {  // Circle继承于Shape同时扩展了构造函数参数 
        constructor (id, x, y, radius) {
            super(id, x, y)
            this.radius = radius
        }
    }
    

    对比ECMAScript 5的实现

    var Rectangle = function (id, x, y, width, height) {
        Shape.call(this, id, x, y);
        this.width  = width;
        this.height = height;
    };
    Rectangle.prototype = Object.create(Shape.prototype);
    Rectangle.prototype.constructor = Rectangle;
    var Circle = function (id, x, y, radius) {
        Shape.call(this, id, x, y);
        this.radius = radius;
    };
    Circle.prototype = Object.create(Shape.prototype);
    Circle.prototype.constructor = Circle;  // 需要通过prototype来替换构造函数
    

    类的多继承,聚合

    支持对多个类的继承(即对应的类函数的聚合) 需要注意的是以下代码例子中的 聚合(aggregation)函数是有现成的库可以使用的

    ECMAScript 6的实现

    var aggregation = (baseClass, ...mixins) => {
        let base = class _Combined extends baseClass {
            constructor (...args) {
                super(...args)
                mixins.forEach((mixin) => {
                    mixin.prototype.initializer.call(this)
                })
            }
        }
        let copyProps = (target, source) => {
            Object.getOwnPropertyNames(source)
                .concat(Object.getOwnPropertySymbols(source))
                .forEach((prop) => {
                if (prop.match(/^(?:constructor|prototype|arguments|caller|name|bind|call|apply|toString|length)$/))
                    return
                Object.defineProperty(target, prop, Object.getOwnPropertyDescriptor(source, prop))
            })
        }
        mixins.forEach((mixin) => {
            copyProps(base.prototype, mixin.prototype)
            copyProps(base, mixin)
        })
        return base
    }
    
    class Colored {
        initializer ()     { this._color = "white" }
        get color ()       { return this._color }
        set color (v)      { this._color = v }
    }
    
    class ZCoord {
        initializer ()     { this._z = 0 }
        get z ()           { return this._z }
        set z (v)          { this._z = v }
    }
    
    class Shape {
        constructor (x, y) { this._x = x; this._y = y }
        get x ()           { return this._x }
        set x (v)          { this._x = v }
        get y ()           { return this._y }
        set y (v)          { this._y = v }
    }
    
    class Rectangle extends aggregation(Shape, Colored, ZCoord) {}
    
    var rect = new Rectangle(7, 42)
    rect.z     = 1000
    rect.color = "red"
    console.log(rect.x, rect.y, rect.z, rect.color)
    
    

    对比ECMAScript 5的实现

    var aggregation = function (baseClass, mixins) {
        var base = function () {
            baseClass.apply(this, arguments);
            mixins.forEach(function (mixin) {
                mixin.prototype.initializer.call(this);
            }.bind(this));
        };
        base.prototype = Object.create(baseClass.prototype);
        base.prototype.constructor = base;
        var copyProps = function (target, source) {
            Object.getOwnPropertyNames(source).forEach(function (prop) {
                if (prop.match(/^(?:constructor|prototype|arguments|caller|name|bind|call|apply|toString|length)$/))
                    return
                Object.defineProperty(target, prop, Object.getOwnPropertyDescriptor(source, prop))
            })
        }
        mixins.forEach(function (mixin) {
            copyProps(base.prototype, mixin.prototype);
            copyProps(base, mixin);
        });
        return base;
    };
    
    var Colored = function () {};
    Colored.prototype = {
        initializer: function ()  { this._color = "white"; },
        getColor:    function ()  { return this._color; },
        setColor:    function (v) { this._color = v; }
    };
    
    var ZCoord = function () {};
    ZCoord.prototype = {
        initializer: function ()  { this._z = 0; },
        getZ:        function ()  { return this._z; },
        setZ:        function (v) { this._z = v; }
    };
    
    var Shape = function (x, y) {
        this._x = x; this._y = y;
    };
    Shape.prototype = {
        getX: function ()  { return this._x; },
        setX: function (v) { this._x = v; },
        getY: function ()  { return this._y; },
        setY: function (v) { this._y = v; }
    }
    
    var _Combined = aggregation(Shape, [ Colored, ZCoord ]);
    var Rectangle = function (x, y) {
        _Combined.call(this, x, y);
    };
    Rectangle.prototype = Object.create(_Combined.prototype);
    Rectangle.prototype.constructor = Rectangle;
    
    var rect = new Rectangle(7, 42);
    rect.setZ(1000);
    rect.setColor("red");
    console.log(rect.getX(), rect.getY(), rect.getZ(), rect.getColor());
    

    基类的访问

    对基类的构造函数和方法的直观访问。

    ECMAScript 6的实现

    class Shape {
        …
        toString () {
            return `Shape(${this.id})`
        }
    }
    class Rectangle extends Shape {
        constructor (id, x, y, width, height) {
            super(id, x, y)
            …
        }
        toString () {
            return "Rectangle > " + super.toString() // 通过super 访问父类
        }
    }
    class Circle extends Shape {
        constructor (id, x, y, radius) {
            super(id, x, y)
            …
        }
        toString () {
            return "Circle > " + super.toString()
        }
    }
    

    对比ECMAScript 5的实现

    var Shape = function (id, x, y) {
        …
    };
    Shape.prototype.toString = function (x, y) {
        return "Shape(" + this.id + ")"
    };
    var Rectangle = function (id, x, y, width, height) {
        Shape.call(this, id, x, y);
        …
    };
    Rectangle.prototype.toString = function () {
        return "Rectangle > " + Shape.prototype.toString.call(this);
    };
    var Circle = function (id, x, y, radius) {
        Shape.call(this, id, x, y);
        …
    };
    Circle.prototype.toString = function () {
        return "Circle > " + Shape.prototype.toString.call(this); //没有super只能通过对应的原型中函数调用 
    };
    

    静态成员

    简单的支持类静态成员

    ECMAScript 6的实现

    class Rectangle extends Shape {
        …
        static defaultRectangle () {
            return new Rectangle("default", 0, 0, 100, 100)
        }
    }
    class Circle extends Shape {
        …
        static defaultCircle () {
            return new Circle("default", 0, 0, 100)
        }
    }
    var defRectangle = Rectangle.defaultRectangle()
    var defCircle    = Circle.defaultCircle()
    

    对比ECMAScript 5的实现

    var Rectangle = function (id, x, y, width, height) {
        …
    };
    Rectangle.defaultRectangle = function () {
        return new Rectangle("default", 0, 0, 100, 100);
    };
    var Circle = function (id, x, y, width, height) {
        …
    };
    Circle.defaultCircle = function () {
        return new Circle("default", 0, 0, 100);
    };
    var defRectangle = Rectangle.defaultRectangle();
    var defCircle    = Circle.defaultCircle();
    

    Getter/Setter

    Getter/Setter 支持直接在类中定义了

    ECMAScript 6的实现

    class Rectangle {
        constructor (width, height) {
            this._width  = width
            this._height = height
        }
        set width  (width)  { this._width = width               }
        get width  ()       { return this._width                }
        set height (height) { this._height = height             }
        get height ()       { return this._height               }
        get area   ()       { return this._width * this._height }
    }
    var r = new Rectangle(50, 20)
    r.area === 1000
    

    对比ECMAScript 5的实现

    var Rectangle = function (width, height) {
        this._width  = width;
        this._height = height;
    };
    Rectangle.prototype = {
        set width  (width)  { this._width = width;               },
        get width  ()       { return this._width;                },
        set height (height) { this._height = height;             },
        get height ()       { return this._height;               },
        get area   ()       { return this._width * this._height; }
    };
    var r = new Rectangle(50, 20);
    r.area === 1000;
    

    相关文章

      网友评论

        本文标题:ECMAScript 6 (ES6) 新特性介绍 二

        本文链接:https://www.haomeiwen.com/subject/rdjkixtx.html