美文网首页Devs
ECMAScript 6 (ES6) 新特性介绍 三

ECMAScript 6 (ES6) 新特性介绍 三

作者: 乌龟怕铁锤 | 来源:发表于2017-12-15 10:57 被阅读4次

    原文地址 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)

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

    Symbol 类型

    Symbol类型

    作为对象的一个唯一而且不可修改的属性. Symbol是个可选的描述,只是用在调试中。

    ECMAScript 6的实现

    Symbol("foo") !== Symbol("foo") 
    const foo = Symbol()
    const bar = Symbol()
    typeof foo === "symbol"
    typeof bar === "symbol"
    let obj = {}
    obj[foo] = "foo"
    obj[bar] = "bar"
    JSON.stringify(obj) // {}
    Object.keys(obj) // []
    Object.getOwnPropertyNames(obj) // []
    Object.getOwnPropertySymbols(obj) // [ foo, bar ]
    

    对比ECMAScript 5的实现

    // ES5中无该实现
    

    全局Symbol

    全局的Symbol是通过唯一的键来标志的

    ECMAScript 6的实现

    Symbol.for("app.foo") === Symbol.for("app.foo")
    const foo = Symbol.for("app.foo")
    const bar = Symbol.for("app.bar")
    Symbol.keyFor(foo) === "app.foo"
    Symbol.keyFor(bar) === "app.bar"
    typeof foo === "symbol"
    typeof bar === "symbol"
    let obj = {}
    obj[foo] = "foo"
    obj[bar] = "bar"
    JSON.stringify(obj) // {}
    Object.keys(obj) // []
    Object.getOwnPropertyNames(obj) // []
    Object.getOwnPropertySymbols(obj) // [ foo, bar ]
    

    对比ECMAScript 5的实现

    // ES5中无该实现
    

    迭代器 (Iterators)

    迭代器和For-Of 操作符

    通过“迭代”协议支持对象自定义它们的迭代行为。
    同时支持通过“迭代”协议来生成一些列的结果值 (无论有限还是无限的)
    最后,提供了方便的操作符(For-of)遍历一个迭代对象的所有值.

    ECMAScript 6的实现

    let fibonacci = {
        [Symbol.iterator]() { // 声明迭代器
            let pre = 0, cur = 1
            return {
               next () { // 迭代器每次迭代的函数
                   [ pre, cur ] = [ cur, pre + cur ]
                   return { done: false, value: cur } // 每次迭代值返回
               }
            }
        }
    }
    
    for (let n of fibonacci) { // 这里n的值是在 二 中介绍的释放赋值
        if (n > 1000)
            break
        console.log(n)
    }
    

    对比ECMAScript 5的实现

    var fibonacci = {  // 译者注: 还是觉得ES5这种写法更直观,迭代器是ES6中才引入的,之后怎么变化还未知
        next: (function () {
            var pre = 0, cur = 1;
            return function () {
                tmp = pre;
                pre = cur;
                cur += tmp;
                return cur;
            };
        })()
    };
    
    var n;
    for (;;) {
        n = fibonacci.next();
        if (n > 1000)
            break;
        console.log(n);
    }
    

    生产者

    生产者模式,迭代协议

    支持迭代形式的生产函数,通过控制流程的暂停和恢复来产生一些列的值 (无论有限还是无限)

    ECMAScript 6的实现

    let fibonacci = {
        *[Symbol.iterator]() {  // * 来标示生产者
            let pre = 0, cur = 1
            for (;;) {
                [ pre, cur ] = [ cur, pre + cur ]
                yield cur
            }
        }
    }
    
    for (let n of fibonacci) {
        if (n > 1000)
            break
        console.log(n)
    }
    

    对比ECMAScript 5的实现

    var fibonacci = {
        next: (function () {
            var pre = 0, cur = 1;
            return function () {
                tmp = pre;
                pre = cur;
                cur += tmp;
                return cur;
            };
        })()
    };
    
    var n;
    for (;;) {
        n = fibonacci.next();
        if (n > 1000)
            break;
        console.log(n);
    }
    

    直接使用生产者函数

    支持生产者函数,一种特别的函数, 通过控制流程的暂停和恢复来产生一些列的值 (无论有限还是无限)

    ECMAScript 6的实现

    function* range (start, end, step) {  // * 标示这是一个生产者函数
        while (start < end) {
            yield start   // 通过yieldl来输出中间结果并暂停
            start += step  // 恢复生产者的执行
        }
    }
    
    for (let i of range(0, 10, 2)) { // 对生产者函数的使用 
        console.log(i) // 0, 2, 4, 6, 8
    }
    

    对比ECMAScript 5的实现

     // ES5中无相对应的实现
    

    生产者匹配

    支持生产者函数产生的值分配到各种可能的情况中去

    ECMAScript 6的实现

    let fibonacci = function* (numbers) { // 定义生产者函数
        let pre = 0, cur = 1
        while (numbers-- > 0) {
            [ pre, cur ] = [ cur, pre + cur ]
            yield cur
        }
    }
    
    for (let n of fibonacci(1000)) // 使用在数组遍历中
        console.log(n)
    
    let numbers = [ ...fibonacci(1000) ] // 使用在数组赋值中
    
    let [ n1, n2, n3, ...others ] = fibonacci(1000) // 使用在数组释放赋值中
    

    对比ECMAScript 5的实现

    // 无对应的ES5实现
    

    生产者流程控制

    支持生产者, 一种可以控制流程暂停/恢复的特殊迭代器, 以协作支持和Promises这样的异步编程. [请注意,以下的async函数通常使用已经存在的库,例如co 或者Bluebird ]

    ECMAScript 6的实现

    // 生成异步的流程控制驱动函数
    function async (proc, ...params) {
        var iterator = proc(...params) // proc 是一个生产者函数 (带*)
        return new Promise((resolve, reject) => {
            let loop = (value) => {
                let result
                try {
                    result = iterator.next(value)
                }
                catch (err) {
                    reject(err)
                }
                if (result.done)
                    resolve(result.value)
                else if (   typeof result.value      === "object"
                         && typeof result.value.then === "function")
                    result.value.then((value) => {
                        loop(value)
                    }, (err) => {
                        reject(err)
                    })
                else
                    loop(result.value)
            }
            loop()
        })
    }
    
    //  application-specific asynchronous builder
    function makeAsync (text, after) {
        return new Promise((resolve, reject) => {
            setTimeout(() => resolve(text), after)
        })
    }
    
    //  application-specific asynchronous procedure
    async(function* (greeting) {
        let foo = yield makeAsync("foo", 300)
        let bar = yield makeAsync("bar", 200)
        let baz = yield makeAsync("baz", 100)
        return `${greeting} ${foo} ${bar} ${baz}`
    }, "Hello").then((msg) => {
        console.log("RESULT:", msg) // "Hello foo bar baz"
    })
    
    

    对比ECMAScript 5的实现

     // ES5中无相对应的实现
    
    

    生产者方法

    类或者对象中也支持生产者的方法

    ECMAScript 6的实现

    class Clz {
        * bar () { // 类中的生产者方法
            …
        }
    }
    let Obj = {
        * foo () {  // 对象中的生产者方法
            …
        }
    }
    

    对比ECMAScript 5的实现

     // ES5中无相对应的实现
    

    Map/Set 和WeakMap WeakSet

    Set 数据格式

    新增Set数据格式, 更清晰/方便的操作集合

    ECMAScript 6的实现

    let s = new Set()  
    s.add("hello").add("goodbye").add("hello") // 添加成员
    s.size === 2  // 成员数量
    s.has("hello") === true  // 成员存在
    for (let key of s.values()) // 遍历成员 -  通过添加的顺序(FIFO)
        console.log(key)
    

    对比ECMAScript 5的实现

    // set的出现的确让之前这类的操作便利性增加不少!
    var s = {}; 
    s["hello"] = true; s["goodbye"] = true; s["hello"] = true;
    Object.keys(s).length === 2;
    s["hello"] === true;
    for (var key in s) // arbitrary order
        if (s.hasOwnProperty(key))
            console.log(s[key]);
    

    Map数据格式

    新增Map数据格式, 更清晰/方便的操作数据映射

    ECMAScript 6的实现

    // 增加了几个方案的map操作,但总体上和之前的对象属性并无太大差别
    
    let m = new Map()
    let s = Symbol()
    m.set("hello", 42) 
    m.set(s, 34)
    m.get(s) === 34
    m.size === 2
    for (let [ key, val ] of m.entries()) 
        console.log(key + " = " + val)
    
    

    对比ECMAScript 5的实现

    var m = {};
    // ES5中无
    m["hello"] = 42;
    // ES5中无
    // ES5中无
    Object.keys(m).length === 2;
    for (key in m) {
        if (m.hasOwnProperty(key)) {
            var val = m[key];
            console.log(key + " = " + val);
        }
    }
    

    弱指向的数据格式

    对 Set和Map而言可以在前面增加关键字Weak, 这样能保证其中的对象只是引用关系,对象在WeakSet和WeakMap外发送的变化都会体现在其中。 能够保证无内存泄漏问题。

    ECMAScript 6的实现

    let isMarked     = new WeakSet()
    let attachedData = new WeakMap()
    
    export class Node {
        constructor (id)   { this.id = id                  }
        mark        ()     { isMarked.add(this)            }
        unmark      ()     { isMarked.delete(this)         }
        marked      ()     { return isMarked.has(this)     }
        set data    (data) { attachedData.set(this, data)  }
        get data    ()     { return attachedData.get(this) }
    }
    
    let foo = new Node("foo")
    
    JSON.stringify(foo) === '{"id":"foo"}'
    foo.mark()
    foo.data = "bar"
    foo.data === "bar"
    JSON.stringify(foo) === '{"id":"foo"}'
    
    isMarked.has(foo)     === true
    attachedData.has(foo) === true
    foo = null  /* 释放foo 同时也释放了WeakSet和WeakMap中的foo */
    attachedData.has(foo) === false
    isMarked.has(foo)     === false
    

    对比ECMAScript 5的实现

    // ES5中无
    

    类型数组

    类型数组

    类型数组是一种从二进制的数组空间里构建的数组,这可以方便的用来实现各种网络协议,加密算法和文件格式的操作。

    ECMAScript 6的实现

    //  ES6 下面例子中的Example类 同等于 这个c 的结构:
    //  struct Example { unsigned long id; char username[16]; float amountDue }
    class Example {
        constructor (buffer = new ArrayBuffer(24)) {
            this.buffer = buffer
        }
        set buffer (buffer) {
            this._buffer    = buffer
            this._id        = new Uint32Array (this._buffer,  0,  1) // 取该buffer从第0字节开始,1个uint32长作为id
            this._username  = new Uint8Array  (this._buffer,  4, 16) // 取该buffer的第4字节开始,开始共16个uint8长作为 username (字符数组)的空间
            this._amountDue = new Float32Array(this._buffer, 20,  1) // 取该buffer中的第20字节开始,共1个float32长作为amountDue的空间。
        }
        get buffer ()     { return this._buffer       }
        set id (v)        { this._id[0] = v           } // 为什么不是._id = v? 因为_id指向的是数组,但数组真正存储的起点是在第一个元素处, 即 ._id[0]  下面其他的元素同理
        get id ()         { return this._id[0]        }
        set username (v)  { this._username[0] = v     }  
        get username ()   { return this._username[0]  }
        set amountDue (v) { this._amountDue[0] = v    }
        get amountDue ()  { return this._amountDue[0] }
    }
    
    let example = new Example()
    example.id = 7  // 
    example.username = "John Doe"
    example.amountDue = 42.0
    
    // 这是buffer内存的状况:
    // 以16进制标示 每两位标示一个byte 
    // 0000 0007 (id)  
    // 4a6f 686e 2044 6f65 0000 0000 0000 0000 (John Doe)
    //  4228 0000 (42.0)
    

    对比ECMAScript 5的实现

    // ES5中无
    

    相关文章

      网友评论

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

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