专栏首页Super 前端深入理解ES6--迭代器、生成器、代理、反射、Promise

深入理解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 条评论
登录 后参与评论

相关文章

  • 前端MVC&MVP&MVVM

    “少壮不努力,长大干IT!”。公司项目重构终于进入尾声了,两个月快累成“狗”了。重构前端框架使用了MVVM+Node,从“铁器时代”直接进入“全栈时代”。下面是...

    奋飛
  • JavaScript正则表达式

    正则表达式是一个拆分字符串并查询相关信息的过程。 正则表达式通常被称为一个模式(pattern),是一个用简单方式描述或者匹配一系列符合某个语法规则的字符串...

    奋飛
  • Memcache集群环境下缓存解决方案

    版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。

    奋飛
  • 记两道关于事件循环的题

    这里的关键其实是搞清楚 await async2() 做了什么事情。我以为在 async1 内部,async2 被调用之后,就会继续往后执行,因此是先打印 as...

    Chor
  • ES6中Array数组你应该知道的操作

    上一次我们讲解了JavaScript的Array,了解了很多关于Array的属性,方法等。相信大家收益颇多,今天为大家带来更深次的了解,希望您可以学习更多。如果...

    Javanx
  • Python-生成模拟原始脑电数据

    在实验中有时需要原始脑电数据来进行模拟实验,但又限于实验条件的不足,需要构造模拟的原始脑电数据。

    脑机接口社区
  • ES6 学习笔记之字符串拓展

    字符换相关的拓展在书中有非常详细的介绍,我这里仅记录一些可能会用到的函数或方法,以备后用。

    我与梦想有个约会
  • Docker 网络模型之 macvlan 详解,图解,实验完整

    上一篇文章我们详细介绍了 macvlan 这种技术,macvlan 详解,由于它高效易配置的特性,被用在了 Docker 的网络方案设计中,这篇文章就来说说这个...

    CloudDeveloper
  • 类装饰器

      在理解类装饰器之前,先回忆一下有关装饰器的知识。装饰器本质上就是一个函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外的功能,装饰器的返回值也是一...

    py3study
  • ES6精华:数值扩展

    JS采用IEEE 754标准的64位双精度格式存储数值。 数值的精度最多可达到53个二进制位(1个隐藏位和52个有效位)。 如果数值的精度超过此限度,第54位及...

    前端博客 : alili.tech

扫码关注云+社区

领取腾讯云代金券