es6 队列_ES6还可以这样学【下】

第一节 Promise

1.1 promise是什么?

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大

有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数

1.2 promsie产生的原因

在JavaScript的世界中,所有代码都是单线程执行的。

由于这个“缺陷”,导致JavaScript的所有网络操作,浏览器事件,都必须是异步执行。异步执行可以用回调函数实现:

function callback() {

console.log('Done');

}

console.log('before setTimeout()');

setTimeout(callback, 1000); // 1秒钟后调用callback函数

console.log('after setTimeout()');

观察上述代码执行,在Chrome的控制台输出可以看到:

before setTimeout()

after setTimeout()

(等待1秒后)

Done

可见,异步操作会在将来的某个时间点触发一个函数调用。

异步回调的问题:之前处理异步是通过纯粹的回调函数的形式进行处理

很容易进入到回调地狱中,剥夺了函数return的能力

问题可以解决,但是难以读懂,维护困难

稍有不慎就会踏入回调地狱 - 嵌套层次深,不好维护

回调地狱

一般情况我们一次性调用API就可以完成请求。

有些情况需要多次调用服务器API,就会形成一个链式调用,比如为了完成一个功能,我们需要调用API1、API2、API3,依次按照顺序进行调用,这个时候就会出现回调地狱的问题

1.3 promise详解

1.3.1 语法

new Promise(

function (resolve, reject) {

// 一段耗时的异步操作

resolve('成功') // 数据处理完成

// reject('失败') // 数据处理出错

}).then(

(res) => {console.log(res)}, // 成功

(err) => {console.log(err)} // 失败)

resolve作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;

reject作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

【代码演示】

请求网络接口:

图片懒加载

1.3.2 promise有三个状态:

1、pending[待定]初始状态

2、fulfilled[实现]操作成功

3、rejected[被否决]操作失败

当promise状态发生改变,就会触发then()里的响应函数处理后续步骤;

promise状态一经改变,不会再变。

Promise对象的状态改变,只有两种可能:

从pending变为fulfilled

从pending变为rejected。

这两种情况只要发生,状态就凝固了,不会再变了。

1.4 promise案例

回调包装成Promise,他有两个显而易见的好处:

1、可读性好

2、返回 的结果可以加入任何Promise队列

实战示例,回调地狱和promise对比:

1.4.1 传统写法

1.4.2 Promise

本章作业

Promise是什么 如何使用

第二节Generator

Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同

2.1 Generator语法

形式上,Generator 函数是一个普通函数,但是有两个特征。一是,function关键字与函数名之间有一个星号;二是,函数体内部使用yield表达式,定义不同的内部状态(yield在英语里的意思就是“产出”)。

yield 表达式

由于 Generator 函数返回的遍历器对象,只有调用next方法才会遍历下一个内部状态,所以其实提供了一种可以暂停执行的函数。yield表达式就是暂停标志。

遍历器对象的next方法的运行逻辑如下。

(1)遇到yield表达式,就暂停执行后面的操作,并将紧跟在yield后面的那个表达式的值,作为返回的对象的value属性值。

(2)下一次调用next方法时,再继续往下执行,直到遇到下一个yield表达式。

(3)如果没有再遇到新的yield表达式,就一直运行到函数结束,直到return语句为止,并将return语句后面的表达式的值,作为返回的对象的value属性值。

2.2 async

ES2017 标准引入了 async 函数,使得异步操作变得更加方便。

async 函数是什么?一句话,它就是 Generator 函数的语法糖

本章作业

Generator 函数

第三节 模块的导入导出

在es5中,用module.exports和exports导出模块,用require引入模块。

es6新增export和export default导出模块,import导入模块。

3.1名字导出(name export)

名字导出可以在模块中导出多个声明。

export

export后必须跟语句, 何为语句, 如声明, for, if 等都是语句, export 不能导出匿名函数, 也不能导出某个已经声明的变量, 如:

export const bar = function() {}; // 合法

export bar; // 非法

export 1; // 非法

export function foo () {}; // 合法, 后跟的是声明语句

export { foo }; // 合法, 后面跟的{}理解为语句, 就像if后面的{}一样

export { foo as bar }; // 合法export { foo: foo }; // 非法, 后面的{}被解析成对象

3.2 默认导出(default export)

一个模块只能有一个默认导出,对于默认导出,导入的名称可以和导出的名称不一致,这对于导出匿名函数或类非常有用。

3.2.1 export default

export default在整个模块中只能出现一次, 后只能具体的值, 何为具体的值, 如1, 2, 3, 再比如一个函数声明(非表达式), 或者是一个类声明(与函数声明一个意思), 或者匿名函数, 只要是能用变量接受的都可以, 例子:

export default 1; // 合法

export default function foo() {}; // 合法, 因为function foo() {} 能被变量接受, 如 var bar = function foo() {}

export default const bar = 1; // 非法, 因为var a = const bar = 1 是不合法的

export default { foo }; // 合法, {} 被理解为一个对象

export default { foo: foo }; // 合法, 同上

3.2.2 import

import语法为:

import { x, y } from './test.js';import * as some from './test.js'; // 命名空间导入import './test.js';import { default as test } from './test.js';

导入再导出

export { some } from './test.js';export * from './test.js';

导入后跟需要导入的绑定和模块说明符, 导入绑定的列表并非对象的解构, 二者并无关联, 导入的标识符很像const声明的变量, 不可更改, 也同时存在暂时性死区, 如有理解错误的地方还请不吝指教

第四节Class类

传统的javascript中只有对象,没有类的概念。它是基于原型的面向对象语言。原型对象特点就是将自身的属性共享给新对象。这样的写法相对于其它传统面向对象语言来讲,很有一种独树一帜的感脚!非常容易让人困惑!

如果要生成一个对象实例,需要先定义一个构造函数,然后通过new操作符来完成。构造函数示例:

当使用了构造函数,并且new 构造函数(),后台会隐式执行new Object()创建对象;

将构造函数的作用域给新对象,(即new Object()创建出的对象),而函数体内的this就代表new Object()出来的对象

执行构造函数的代码。

返回新对象(后台直接返回);

4.1 类的定义

ES6引入了Class(类)这个概念,通过class关键字可以定义类。该关键字的出现使得其在对象写法上更加清晰,更像是一种面向对象的语言。如果将之前的代码改为ES6的写法就会是这个样子:

注意项

1.在类中声明方法的时候,千万不要给该方法加上function关键字

2.方法之间不要用逗号分隔,否则会报错

由下面代码可以看出类实质上就是一个函数。类自身指向的就是构造函数。所以可以认为ES6中的类其实就是构造函数的另外一种写法!

console.log(typeof Person);//function

console.log(Person===Person.prototype.constructor);//true

以下代码说明构造函数的prototype属性,在ES6的类中依然存在着。

console.log(Person.prototype);//输出的结果是一个对象

实际上类的所有方法都定义在类的prototype属性上。代码证明下:

当然也可以通过prototype属性对类添加方法。如下:

还可以通过Object.assign方法来为对象动态增加方法

constructor方法是类的构造函数的默认方法,通过new命令生成对象实例时,自动调用该方法。

constructor方法如果没有显式定义,会隐式生成一个constructor方法。所以即使你没有添加构造函数,构造函数也是存在的。constructor方法默认返回实例对象this,但是也可以指定constructor方法返回一个全新的对象,让返回的实例对象不是该类的实例。

constructor中定义的属性可以称为实例属性(即定义在this对象上),constructor外声明的属性都是定义在原型上的,可以称为原型属性(即定义在class上)。hasOwnProperty()函数用于判断属性是否是实例属性。其结果是一个布尔值, true说明是实例属性,false说明不是实例属性。in操作符会在通过对象能够访问给定属性时返回true,无论该属性存在于实例中还是原型中。

类的所有实例共享一个原型对象,它们的原型都是Person.prototype,所以proto属性是相等的

由此,也可以通过proto来为类增加方法。使用实例的proto属性改写原型,会改变Class的原始定义,影响到所有实例,所以不推荐使用!

class不存在变量提升,所以需要先定义再使用。因为ES6不会把类的声明提升到代码头部,但是ES5就不一样,ES5存在变量提升,可以先使用,然后再定义。

4.2 Class 的继承

Class 可以通过extends关键字实现继承,这比 ES5 的通过修改原型链实现继承,要清晰和方便很多。

4.3 proxy

proxy在目标对象的外层搭建了一层拦截,外界对目标对象的某些操作,必须通过这层拦截

var proxy = new Proxy(target, handler);

new Proxy()表示生成一个Proxy实例,target参数表示所要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为

· targetWithLog 读取属性的值时,实际上执行的是 logHandler.get :在控制台输出信息,并且读取被代理对象 target 的属性。

· 在 targetWithLog 设置属性值时,实际上执行的是 logHandler.set :在控制台输出信息,并且设置被代理对象 target 的属性的值

4.4 Proxy的作用

对于代理模式 Proxy 的作用主要体现在三个方面拦截和监视外部对对象的访问

降低函数或类的复杂度

在复杂操作前对操作进行校验或对所需资源进行管理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值