深入理解ES6--迭代器、生成器、代理、反射、Promise

迭代器(Iterator)和生成器(Generator)

for-of循环展开运算符…都是针对迭代器的!!!

  • 不能使用箭头函数来创建生成器;ES6函数的简写方式可以(只需在函数名前加星号)
  • 可迭代对象具有Symbol.iterator属性,ES6中,所有的集合对象(数组、Set集合和Map集合)和字符串都是可迭代对象,这些对象都具有默认迭代器;
let collection = {
    items: [],
    *[Symbol.iterator]() {
        for (let item of this.items) {
            yield item
        }
    }  
}
collection.items.push(1)
collection.items.push(2)
for (let x of collection) console.log(x) // 1 2

内建迭代器

  • entries() 返回一个迭代器,其值为多个键值对;
let ary = ['a', 'b']
let mySet = new Set(['a', 'b'])
let myMap = new Map().set('name', 'ligang').set('age', 28)
for (let entry of ary.entries()) console.log(entry)   // [0, "a"][1, "b"]
for (let entry of mySet.entries()) console.log(entry) // ["a", "a"]["b", "b"]
for (let entry of myMap.entries()) console.log(entry) // ["name", "ligang"]["age", 28]
  • values() 返回一个迭代器,其值为集合的值;
  • keys() 返回一个迭代器,其值为集合中的所有键名

注意:数组和Set集合的默认迭代器是values();Map集合的默认迭代器是entries()

// Map集合可以使用解构
let myMap = new Map().set('name', 'ligang')
for (let [key, value] of myMap) console.log(key, value) // name ligang

展开运算符

展开运算符可以作用于可迭代对象,通过迭代器从对象中读取相应的值并插入到一个数组中。

let ary = ['a', 'b']
let mySet = new Set(['a', 'b'])
let myMap = new Map().set('name', 'ligang').set('age', 28)
console.log([...ary, 'c'])  // ["a", "b", "c"]
console.log([...mySet])     // ["a", "b"]
console.log([...myMap])     // [["name", "ligang"], ["age", 28]]

特别说明: ES6中展开运算符只针对iterable才起作用,默认有数组、set、map和字符串。**并不包含对象!**ES6规范中也并未将展开运算符支持对象,但是目前的主流浏览器Chrome和firefox均已实现该特性。这意味着如果想在低版本浏览器中使用需要特别的Babel插件进行转换!object-rest-spread

生成器返回值

展开运算符与for-of循环语句会直接忽略通过return语句指定的任何返回值,只要done变为true就立即停止读取其他的值!

function *createIterator() {
    yield 1;
    yield 2;
    return 3;
}
let myIterator = createIterator();
console.log(myIterator.next()); // {value: 1, done: false}
console.log(myIterator.next()); // {value: 2, done: false}
console.log(myIterator.next()); // {value: 3, done: true}

let myIterator2 = createIterator();
for(let x of myIterator1) console.log(x) // 1 2

let myIterator3 = createIterator();
console.log([..myIterator3]) // [1, 2]

代理(Proxy)和反射(Reflections)

可以通过代理陷阱复制所有内建javascript对象的行为,当操作发生时,这些陷阱会被自动调用;反射API使开发者能够实现每个代理的默认行为。 区分参数trapTarget和receiver

let target = {
    name: 'lg'
}
let proxy = new Proxy(target, {
    get(trapTarget, key, receiver) {
        console.log(Object.is(target, trapTarget)) // true
        console.log(Object.is(target, receiver))   // false
        if(!(key in receiver)) {
            throw new TypeError(`属性${key}不存在`)
        }
        return Reflect.get(trapTarget, key, receiver)
    }
})
console.log(proxy.name) // 'lg'
  • trapTarget:用于接收属性(代理的目标)的对象;
  • receiver:操作发生的对象(通常是代理)

注意:key in receiver要使用receiver,不要使用trapTarget,因为key in trapTarget会出发has陷阱!

基础proxy和reflect用法请查看:https://blog.csdn.net/ligang2585116/article/details/70553094#t9

Promise与异步编程

博客中已好多地方提及Promise相关的知识

Promise的使用场景

并行执行两个异步操作,当两个操作都结束时通知你;或者同时进行两个异步操作,只取优先完成的操作结果。在这些情况下,Promise是更好的选择!

Promise执行

Promise的执行器会立即执行,然后才执行后续流程中的代码。then中相关的代码并不会立即执行,因为完成或拒绝处理程序总是在执行器完成后被添加到任务队列的末尾。

let promise = new Promise((resolve, reject) => {
    console.log(1)
    resolve(2)
    console.log(3)
})
promise.then(val => console.log(val))
console.log(4)
// 输出:1 => 3 => 4 => 2

Promise链的返回值

let p1 = new Promise((resolve, reject) => {
    resolve(42)
})
p1.then((val) => {
    console.log(val)
    return val + 1
}).then(val => {
    console.log(val)
})
// 输出42、43

Promise链中返回Promise

触发完成处理程序

let p1 = new Promise((resolve, reject) => {
    resolve(42)
})
p1.then((val) => {
    console.log(val)
    let p2 = new Promise((resolve, reject) => {
        resolve(43)
    })
    return p2
}).then(val => console.log(val)) 
// 输出42、43

触发拒绝处理程序

let p1 = new Promise((resolve, reject) => {
    resolve(42)
})
p1.then((val) => {
    console.log(val)
    let p2 = new Promise((resolve, reject) => {
        reject('error')
    })
    return p2
}).then(val => console.log(val)) 
.catch(err => console.error(err))
// 输出42、error

捕获错误

在Promise的末尾留有一个拒绝处理程序可以确保能够正确处理素有可能发生的错误。

Promise.reject('Error')
    .then(() => console.log(1))
    .then(() => console.log(2))
    .catch(err => console.log(err))
// 输出:Error,1、2并不会输出
Promise.resolve('1')
    .then(val => console.log(val))
    .then(() => {throw new Error('error')})
    .then(() => console.log(2))
    .catch(err => console.log(err))
// 输出:1、Error,2并不会输出

全局的拒绝处理

Node环境

  • unhandledRejection:当promise失败(rejected),但又没有处理时触发;
  • rejectionHandled:当promise失败(rejected),被处理时触发。
process.on('unhandledRejection', function(reason, promise){})
process.on('rejectionHandled', function(reason, promise){})

浏览器环境

  • unhandledrejection:当promise失败(rejected),但又没有处理时触发;
  • rejectionhandled:当promise失败(rejected),被处理时触发。
window.onunhandledrejection = function(event) {console.log(event, '...')}
window.onrejectionhandled = function(event) {console.log(event, '...')}

示例

window.addEventListener('unhandledrejection', event => {
    // Prevent error output on the console:
    event.preventDefault();
    console.log('Reason: ' + event.reason);
});
window.addEventListener('rejectionhandled', event => {
    console.log('REJECTIONHANDLED');
});

function foo() {
    return Promise.reject('abc');
}
var r = foo();
setTimeout(() => {
    r.catch(e => {});
}, 0);
// Reason: abc
// REJECTIONHANDLED

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券