ES6内容
iterator
遍历器iterator
makeIterator是个遍历器,生成遍历器对象it
var it = makeIterator(['a', 'b']);
it.next() // { value: "a", done: false }
it.next() // { value: "b", done: false }
it.next() // { value: undefined, done: true }
function makeIterator(array) {
var nextIndex = 0;
return {
next: function() {
return nextIndex < array.length ?
{value: array[nextIndex++], done: false} :
{value: undefined, done: true};
}
};
}
iterable接口
对象具有Symbol.iterator
方法就是部署了iterable接口,但如果Symbol.iterator
返回的不是遍历对象,会报错。下面对象部署了iterable接口
var obj = {
value : 1,
[Symbol.iterator](){
let me = this
return {
next(){
return {
value: me.value++,
done: me.value >= 10
}
}
}
}
}
iterable接口为数据结构提供统一的数据访问机制,具有线性访问特点。
原生部署的有:数组、类似数组对象、Set和Map,数组、Set、Map的entries、keys、values方法的返回。
类似数组对象如 arguments对象 DOM NodeList对象;
对象部署Iterator接口:
function* entries(obj){
for(let key of Object.keys(obj)){
yield [key, obj[key]]
}
}
部署了iterable接口的数据结构使用场景
解构赋值、扩展运算符、yield *、for…of、Array.from、Map()、Set() Promise.all Promise.trace
for…of
对比for…in
for…in
获取键名,无序的,循环对象所有可枚举的属性,作用数组时,返回的key是字符串
for…of
of后面跟遍历器对象,或者部署了遍历器接口的数据类型。返回有序元素,相对与forEach可以break、continue
如果跟makeIterator,会报错
for(let v of [1,2,3]){console.log(v)}
for(let v of [1,2,3][Symbol.iterator]()){console.log(v)}//两结果一样
其它
遍历器对象的return方法
一般用在for...of循环中提前退出break时或者throw,会执行定义在遍历器中return方法,return方法必须返回一个对象
'use strict';
/**
* node v6.9.0 chrome52下执行return
* @type {{cur: number}}
*/
var obj = {
cur: 1,
next() {
return {
value: this.cur++,
done: false
}
},
return() {
this.cur = 0
console.log('execute iterator\'s method of return')
return {
done: true
}
},
[Symbol.iterator]() { // 没有会报错
return this;
}
};
for (let v of obj[Symbol.iterator]()) {
//throw new Error(); 也会执行return
if (v > 10) {
break;
}
if (v == 8) {
continue;
}
console.log(v);
}
generator函数
- generator函数生成了多个返回值,每次执行返回一个状态。
- generator函数作为异步编码的解决方案,提供函数执行时暂停功能。
generator函数相关知识点
yield右边的表达式是延迟执行的
表达式中yield要用()包起来,但是函数参数,表达式右边的例外
generator函数执行后,返回遍历器对象g,该对象具有Symbol.iterator方法,执行后返回自身。
generator函数内部的return,执行到return,返回value等于return,done等于true
g.next(data) data参数会传到上一个yield停留地方,作为其返回值
g.return(data) 返回{value:data,done:true},nodeJs6.2.2支持。
/**
* return nodeJs暂不支持,调用会报错,nodeJs6.2.2支持
*/
function* gen(){
yield 1;
try{
yield 11;
yield 22;
yield 33;
}finally{
console.log('a')
yield 21;
yield 22;
}
yield 2;
}
let itr = gen()
console.log(itr.next()) // { value: 1, done: false }
console.log(itr.return(31)) // { value: 31, done: true }
console.log(itr.next()) // { value: undefined, done: true }
console.log(itr.next()) // { value: undefined, done: true }
console.log(itr.next()) // { value: undefined, done: true }
generator抛错
g.throw()
遍历器对象可以执行throw,generator函数内部有
try...catch
,再被catch,直到运行结束或者执行时遇到下一个next。如果没被捕获,比如连续throw两次,会抛到generator外面。/**
* 一开始没执行next,就执行throw,内部无法捕获。
*/
function* gen(){
try{
console.log('start')
yield 1;
}catch(e){
console.log('内部捕获',e)
}
yield 2;
}
var g = gen();
try{
//g.throw('a');
console.log(g.next())
console.log(g.throw('b'))
}catch(e){
console.log('外部捕获',e)
} /**
* 遍历器对象连续两次throw
*/ function* errCnt() {
try {
yield 5 // { value: 5, done: false }
} catch (e) {
console.log('内部捕获', e)
//throw new Error('cry')
}
yield 6
yield 7
}
var itr = errCnt()
console.log(itr.next())
console.log(itr.throw('a')) // { value: 6, done: false }
try {
console.log(itr.throw('a'))
} catch (e) {
console.log('外部捕获', e)
console.log(itr.next()) // { value: undefined, done: true }
}
如果错误有没被捕获,程序中断执行。
遍历器对象throw,generator内部捕获后,会顺带执行下一个next。
没有执行过next,就执行throw,内部无法捕获。
Generator函数体内报错,外部捕获后,下次还执行next,done为true,value undefined
'use strict'; function* foo() {
let x = yield 3;
let y = x.toUpperCase();
yield y;
yield 5;
} var it = foo(); console.log(it.next()); // { value:3, done:false } try {
console.log(it.next(42));
} catch (err) {
console.log(err);
console.log(it.next()); // {value: undefined, done: true}
}
Generator的遍历器对象抛错后,内部没捕获,外部捕获,下次执行next,同上
var a = yield * AA
AA必须是部署了遍历器接口的数据结构,A如果是Generator生成的,且Generator有return,会将值赋值到a。
function* gen1(){
yield 1;
yield 2;
return 3;
}
function* gen2(gen){
yield 11;
let rtn = yield* gen();
console.log('rtn: ' + rtn)
yield 22;
}
let itr1 = gen1()
console.log(itr1.next()) // { value: 1, done: false }
console.log(itr1.next()) // { value: 2, done: false }
console.log(itr1.next()) // { value: 3, done: true }
let itr2 = gen2(gen1)
console.log(itr2.next()) // { value: 11, done: false }
console.log(itr2.next()) // { value: 1, done: false }
console.log(itr2.next()) // { value: 2, done: false }
// rtn: 3
console.log(itr2.next()) // { value: 22, done: false }
console.log(itr2.next()) // { value: undefined, done: true }
for(let v of gen2(gen1)){
console.log(v)
}
AA如果直接是Generator,会报错;for...of如果直接是Generator,也会报错。
this
function* gen(){
yield 1;
yield 2;
yield this.name = ’sprying'
}
gen.prototype.sayHi = () =>console.log(‘hi')
const g = gen()
g.next()
g.next()
g.next()
g.sayHi()
g.name // null
如果上面const g = gen()换成
const g = gen.apply(gen.prototype)
这时候g.name就有值
注意new gen会报错
Generator函数的原型时Generator.prototype(假设是ownProto);
ownProto原型是sharedProto,sharedProto.hasOwnProperty("next")
sharedProto的原型是iterProto,iterProto.hasOwnProperty(Symbol.iterator)
generator函数两大用途
作为异步编程的解决方案
函数遇到异步操作时,yield暂停,异步回调触发时,再继续执行。具体实现流程如下:
- 当执行到yield时暂停,执行yield右边表达式,后将结果和done状态返回调用者。
- 调用者根据结果判断是否继续执行,或者异步时等到什么时候执行,执行的时候传回什么给generator内部。
- 什么时候执行,传回什么,是通过异步编程协议来规范,比如promise、thinkify。
promise
yield返回结果是promise对象,异步响应时,触发then,即
// 业务代码
function * gen(){
yield new Promise((resolve, reject) => {
setTimeout(()=>{
resolve({ok: true})
}, 500)
})
}
// 执行器背后的核心处理逻辑,执行next后,value是promise
promise.then(function(data){
g.next(data)
})
thunkify
yield返回参数是函数,传入回调,执行这个函数。异步响应时,执行回调,回调的参数是data,即。
// 业务代码
function * gen(){
yield function(callback){
setTimeout(()=>{
callback({ok: true})
}, 500)
}
} // 执行器背后的核心处理逻辑
hook((data) = >{
g.next(data)
})
假设下面场景
fs.readFile('/etc/passwd', (err, data) => {
if (err) throw err;
console.log(data);
}); yield function(callback){
fs.readFile('/etc/passwd', (err, data) => {
if (err) throw err;
callback(data)
});
}
每次都这样写,是不是很麻烦?我们可以封装个函数
function thunkify(callback){
return function(...args){
return function(hook){
callback(...[...args, hook])
}
}
} // 下面就简洁了很多
const readFile = thunkify(fs.readFile)
function * gen(){
yield readFile(filename)
}
生成具有iterable接口数据结构
function* gen(){
yield 1;
yield 2;
yield 3;
return 4;
}
for(let v of gen()){
console.log(v)
}//1,2,3
promise
promise知识点
实例化Promise时,传入的函数立即执行,then在当前同步执行完时执行
resolve可以传入下一个promise实例
/**
* 注意执行顺序
*/
setTimeout(()=>console.log(1),0)
new Promise(function (resolve, reject) {
console.log(2);
x/2;
resolve();
}).then(function () {
console.log(3)
//throw new Error('err')
},function(err){
console.log(err)
});
console.log(4)
promise错误
捕获错误,可以在then第二参数回调中,但建议使用catch。
运行中出现错误会触发报错
状态已经resolve再throw错误,是无效的,如果前面情况是setTimeout再throw,错误会抛到外面。
catch后再then,如果then中再发生错误是无法被前面catch捕获的。
catch中报错,后面也没catch,导致无法捕获,也不会传递到外层。
错误发生后,不管后面有几个catch,只会被第一个catch捕获执行,后面then还可以继续执行
错误没被捕获,触发下面
process.on('unhandledRejection', function (err, p) {}) /**
* reject未被catch,会被传递到unhandledRejection
* Promise内部throw没被catch,会被传递到unhandledRejection,其它不做任何处理
* throw后有catch,还有then,但是then应该是catch生成的默认resolve的promise
*/
new Promise((resolve, reject) => {
//reject(new Error('err'))
//setTimeout(() => {
throw new Error('err-1')
//}, 0)
//resolve('done')
})
.catch(err => console.log('err: ', err))
.then((data) => {
console.log('then: ' + data)
})
process.on('unhandledRejection', function (err, p) {
//console.error(err.stack)
}); var someAsyncThing = function () {
return new Promise(function (resolve, reject) {
// 下面一行会报错,因为x没有声明
resolve(x + 2);
});
}; // 注意执行时间
///*
someAsyncThing()
.catch(function (error) {
console.log('oh no', error);
})
.then(function () {
console.log('carry on');
});
//*/
Promise.all
参数是具有Iterator接口的对象,如果都是fulfilled,触发的then的参数回调的参数是数组。如果首先一个出来rejected,错误捕获的回调参数是首先出现错误那个。Promise.all对应的各个值如果不是Promise,调用Promise.resolve
Promise.race
谁先改变状态,结果和回调的参数就听谁
Promise.resolve
var jsPromise = Promise.resolve($.ajax('/whatever.json'));
参数是个thenable对象,立即执行thenable对象的then
参数是其它值,比如字符串
参数是空的
/**
* Created by yingchun.fyc@alibaba-inc.com on 16/7/13.
*/
let thenable = {
then(resolve, reject){
resolve('thenable')
}
}
Promise.resolve(thenable).then(res => console.log(res))
var p = Promise.resolve('hi')
p.then(res => console.log(res))
// 输出
// hi
// thenable
Promise.reject
参数同上
最新异步编程方式
Generator+(Promise/thunk)
generator函数允许执行暂停。当遇到yield时暂停,Js代码可以控制继续执行,比如控制yield后面的异步响应后,继续执行。暂停、和继续执行是我们写的Js代码控制,也就是,实现个执行器,让这些操作自动执行,就可以实现同步方式写异步代码。
执行器是个函数,返回promise。约定yield后面跟promise或者thunk函数。执行器执行到g.next(),返回obj,obj.value里的异步响应后,如果obj.done为false,继续执行,将响应的值传给g.next(data),如此循环。如果什么时候g.next,返回的done是true,那么等待value异步响应后,resolve响应的值,结束循环。
如果g.next时,报错,首先g.throw给generator处理,处理完继续next;处理失败,直接结束。如果异步响应出错,同样处理。thunk函数,异步响应时执行callback,规定第一参数传错误信息。
要并行处理异步时,yield后面跟数组、对象,执行器Promise.all下处理。
如果Generator函数,再套了一个Generator,放在yield后面。执行器里就再调一次执行器。
上面就是co的实现原理。
现在我们反思这样一个问题,同步方式写异步代码,遇到异步时,程序等待异步响应后,再继续执行,那么nodeJs异步处理优势就没了吗?一开始,我也是这么认为的,但是co执行Generator函数时,虽然内部yield暂停了,但是整个Generator并没有因此卡住,还是会继续执行co后续逻辑。所以nodeJs异步处理的优势还在。
async
async属于ES7,不过引入babel的transform-async-to-generator就可以转码使用。await在ES6是保留字,ES5中使用它是合法。
普通函数中使用await会报错。
Async函数有多种使用形式。
// 函数声明
async function foo() {}
// 函数表达式
const foo = async function () {};
// 对象的方法
let obj = { async foo() {} };
// 箭头函数
const foo = async () => {};
async、await组合跟执行器co很像,只是它不再需要执行器了,像一般函数调用,返回的仍然是Promise。await相比co的yield,后面可以是基本数据类型。
至于错误处理机制,实际上跟co结果一样。不想结束,也是需要try...catch。或者promise后加catch。
至于并发执行,先都生成Promise实例,然后await。或者Promise.all([asyncMethod1(), asyncMethod2()])
/**
* Created by yingchun.fyc@alibaba-inc.com on 16/9/12.
*/
async function f() {
try {
await Promise.reject('出错了');
} catch(e) {
}
return await Promise.resolve('hello world');
}
f()
.then(v => console.log(v))
async function dbFuc(fn) {
let docs = [1,2,3];
let promises = docs.map((doc) => fn(doc));
let results = await Promise.all(promises);
console.log(results);
}
// 或者使用下面的写法
// 两个运行实际差不多,因为都是先生成了promise,再调用await。await、yield,参数默认值都是延迟执行的。
async function dbFuc1(fn) {
let docs = [4,5,6];
let promises = docs.map((doc) => fn(doc));
let results = [];
for (let promise of promises) {
results.push(await promise);
}
console.log(results);
}
var startTime = (new Date()).getTime()
dbFuc1((data) => {
return new Promise((resolve, reject) => {
setTimeout(()=>{
resolve(data)
}, 1000)
})
}).then(() =>{
console.log((new Date().getTime() - startTime))
})
class
关键字class定义类,方法之间没有
,
,方法名可以是变量[defineVar],定义的class只能new,否则报错。方法名不可枚举。构造函数在constructor方法中定义可以使用Object.assign新增方法。
class 不存在变量提升
class表达式
let myClass = class Me {} //Me.name只能内部调用,Me也只能内部用
myClass.name // Me
实例的__proto__,指向原型对象
私有方法
使用Symbol定义方法名
const bar = Symbol(“bar")
继承extends
继承重写constructor,要在constructor中先调用super(),否则会报错。
super在对象方法中都可以使用,但是奇怪的是,下面第一个正常,第二个会报错。
var obj = {
toString() {
return "MyObject: " + super.toString();
}
};
var obj = {
toString: function() {
return "MyObject: " + super.toString();
}
};
可以继承原生的构造函数,但是继承Object时,无法向父类的构造函数传入参数。
相比es5的继承不能继承原生的构造函数,即使es5继承了,也不具备原生的能力。
Object.getPrototypeOf获取类的父类
Object.getPrototypeOf(B) === A
Object.setPrototypeOf
Object.setPrototypeOf = function (obj, proto) {
obj.__proto__ = proto;
return obj;
}
其它
方法名前可加set/get,并且是定义在descriptor上,Object.getOwnPropertyDescriptor
方法名前可加static
es7才支持属性名直接在类里定义
关于class具体使用例子,这里就不贴出来了。
解构赋值destructuring
数组的解构赋值
支持嵌套,等号右边是可遍历(iterator)的结构
等号两边可以不完全匹配,或左边小,或右边没相应值(这时undefined)
支持默认值,默认值如果是表达式,表达式是惰性求值的
let [x=y,y=1] = [1,2]
let [a=b,b=1] = []// Uncaught ReferenceError: b is not defined(…)
var [a, , [b], c] = [5, null, [6]];
var [a, , [b], c] = [5, undefined, [6]];
var [a, , [b], c] = [5, , [6]];// a = 5; b = 6; c = undefined
var [a, b, c] = "ab"; // a = 'a'; b = 'b'; c = undefined
var [c] = "
ES6内容的更多相关文章
- ES6整体内容
ES6内容: 附网站链接:http://www.jscwwd.com/article/5e6488e849a13d1a89caf574
- React Native填坑之旅--class(番外篇)
无论React还是RN都已经迈入了ES6的时代,甚至凭借Babel的支持都进入了ES7.ES6内容很多,本文主要讲解类相关的内容. 构造函数 定义侦探类作为例子. ES5的"类"是 ...
- 【JavaScript数据结构系列】01-数组Array
[JavaScript数据结构系列]01-数组Array 码路工人 CoderMonkey 转载请注明作者与出处 # [JavaScript数据结构系列] # 01-数组Array 数组: 是有序的元 ...
- ES6/ES2015核心内容
ECMAScript定义了: JS语言语法 – 语法解析规则.关键字.语句.声明.运算符等. 类型 – 布尔型.数字.字符串.对象等. 原型和继承 内建对象和函数的标准库 – JSON.Math.数组 ...
- ES6就是ES2015 的主要内容
转自 https://segmentfault.com/a/1190000004365693 ECMAScript 6(以下简称ES6)是JavaScript语言的下一代标准.因为当前版本的ES6是在 ...
- 30分钟掌握ES6/ES2015核心内容
30分钟掌握ES6/ES2015核心内容 ECMAScript 6(以下简称ES6)是JavaScript语言的下一代标准.因为当前版本的ES6是在2015年发布的,所以又称ECMAScript ...
- ES6核心内容精讲--快速实践ES6(二)
Iterator和for...of 是什么: Iterator(遍历器)是专门用来控制如何遍历的对象,具有特殊的接口. 怎么用: Iterator(遍历器)对象带有next方法,每一次调用next方法 ...
- es6的新内容
前端学习总结(十八)ES6--新一代的javascript 发表于2016/6/11 21:44:27 2733人阅读 分类: javascript 简介 ECMAScript 6(以下简称ES6) ...
- 30分钟掌握ES6/ES2015核心内容(上)
ECMAScript 6(以下简称ES6)是JavaScript语言的下一代标准.因为当前版本的ES6是在2015年发布的,所以又称ECMAScript 2015. 也就是说,ES6就是ES2015. ...
随机推荐
- Verilog MIPS32 CPU(五)-- CP0
Verilog MIPS32 CPU(一)-- PC寄存器 Verilog MIPS32 CPU(二)-- Regfiles Verilog MIPS32 CPU(三)-- ALU Verilog M ...
- Asp.Net Core下的两种路由配置方式
与Asp.Net Mvc创建区域的时候会自动为你创建区域路由方式不同的是,Asp.Net Core下需要自己手动做一些配置,但更灵活了. 我们先创建一个区域,如下图 然后我们启动访问/Manage/H ...
- 【原创】插件式ICE服务框架
Zero ICE在跨平台.跨语言的环境中是一种非常好的RPC方案,而且使用简单.早期在使用ICE时,每一个后端功能模块都以独立服务方式部署,在功能模块较少时不会有明显的问题,但是随着功能模块的增多,部 ...
- [USACO09FEB] 改造路Revamping Trails | [JLOI2011] 飞行路线
题目链接: 改造路 飞行路线 其实这两道题基本上是一样的,就是分层图的套路题. 为什么是分层图呢?首先,我们的选择次数比较少,可以把这几层的图建出来而不会爆空间.然后因为选择一个边权为0的路线之后我们 ...
- 【OCP|052】052考试题库又变了,最新052题库收集整理-第15题
15.Which two are true about space management in tablespaces? A) Locally managed tablespaces have eit ...
- “全栈2019”Java第六十二章:接口与常量详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- maven(私库)上传jar包
在实际开发过程中,我们经常会遇到需要引用的jar依赖,在我们公司的maven仓库不存在,这个时候我们就需要把jar上传上去,在项目中添加对应依赖就OK了. 步骤1:下载jar 在http://mvnr ...
- CentOS 下安装 SNMP 服务
CentOS 中搭建 SNMP 服务 0.前言 首先这个服务我不知道有什么用,学习CCNA的也许有了解.所以这里仅仅只是教做题,下面还有一些搜到的配置文件希望会大家有所帮助. 简单网络管理协议(SNM ...
- Unity---解决重新调整游戏分辨率后,再运行游戏还是和之前分辨率一样的问题
经历 上次在Unity做了个小游戏,发布的时候忘了取消默认全屏了. 于是在Unity重新发布了一下,可是出来后分辨率还是默认全屏. 当时百思不得其解 原因 主要是因为当用Unity发布一个新游戏的时候 ...
- NOIP模拟题汇总(加厚版)
\(NOIP\)模拟题汇总(加厚版) T1 string 描述 有一个仅由 '0' 和 '1' 组成的字符串 \(A\),可以对其执行下列两个操作: 删除 \(A\)中的第一个字符: 若 \(A\)中 ...