ECMAScript 6
ECMAScript 6.0 是 2015 年 6 月年发布的新的 JavaScript 语言标准,它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。下面介绍 ECMAScript 6 一些主要新增的特性。
变量声明
const 用于声明常量,let 用于声明变量,他们都是块级作用域。
const a = 1;let b = 1;
模板字符串
用于拼接字符串。
let a = 'hello';let b = 'hello';console.log('print:' + a + b);let c = `print:${a}${b}`
默认参数
function test(a = 'world') { console.log(`print:hello,${a}`);}test();// print:hello,world
箭头函数
函数的简化写法。
function test(a = 'world') { console.log(`print:hello,${a}`);}const test = (a = 'world') => { console.log(`print:hello,${a}`);};
模块的导入和导出
import { Button } from 'antd';// 导出一个方法,这样就能在其他文件使用 `import` 导入使用了const test = (a = 'world') => { console.log(`print:hello,${a}`);};export default test;
析构赋值
const obj = { key: 'umi', author: 'sorrycc' };console.log(obj.key);const { key } = obj;// 等价于 `const key = obj.key;`const obj2 = { key };// 等价于 `const obj2 = { key: key };`;// 数组也有类似的用法const arr = [1, 2];const [foo, bar] = arr;console.log(foo);// 1
展开运算符
用于数组组装:
const arr = ['umi'];const texts = [...arr, 'dva'];// texts => ['umi', 'dva']用于取出数组部分属性:const arr = ['umi', 'dva', 'antd'];const [umi, ...other] = arr;// 前面已经提过析构赋值,所以第一项会赋值给 `umi`,剩下的会被组合成一个 `other` 数组console.log(umi);// umiconsole.log(other);// (2)['dva', 'antd']用于组合新的对象,key 相同时,靠后展开的值会覆盖靠前的值:const obj = { a: 1, b: 2 };const obj2 = { b: 3, c: 4 };const obj3 = { ...obj, ...obj2 };// obj3 => { a: 1, b: 3, c: 4 }
Promise
回调函数 callback
A callback is a function that is passed as an argument to another function and is executed after its parent function has completed.
在 JavaScript 中,回调函数具体的定义为:函数 A 作为参数(函数引用)传递到另一个函数 B 中,并且函数 B 运行完成后再执行函数 A。我们就把函数 A 叫做回调函数。例如:
// 当参数 a 大于 10 且参数 func2 是一个方法时 执行 func2function func1(a, func2) { if (a > 10 && typeof func2 == 'function') { func2() }}func1(11, function() { console.log('this is a callback')})
function doSomething(msg, callback) { alert(msg); if (typeof callback == "function") callback();}
doSomething("存 5000 块", function () { alert("稍等,马上办理"); alert('2 分钟后,您的业务已办理完毕');});
回调与同步、异步并没有直接的联系,回调只是一种实现方式,既可以有同步回调,也可以有异步回调。
回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用,用于对该事件或条件进行响应。
回调本质上是一种设计模式。设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了重用代码、让代码更容易被他人理解、保证代码可靠性。
在 1994 年,由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 四人合著出版了一本名为 Design Patterns - Elements of Reusable Object-Oriented Software(中文译名:设计模式 - 可复用的面向对象软件元素) 的书,该书首次提到了软件开发中设计模式的概念。
四位作者合称 GOF(四人帮,全拼 Gang of Four)。他们所提出的设计模式主要是基于以下的面向对象设计原则。
- 对接口编程而不是对实现编程。
- 优先使用对象组合而不是继承。
同步与异步
同步 (Synchronous) 和异步 (Asynchronous) 用来形容一次函数调用时的时间序列。
- 同步函数调用一旦开始,调用者必须等到函数调用返回后,才能继续后续的行为。
- 异步函数调用更像一个消息传递,一旦开始,函数调用就会立即返回,调用者就可以继续后续的操作。而异步函数通常会在另外一个线程中,“真实”地执行着。整个过程,不会阻碍调用者的工作。
为什么使用 promise
一般来说我们会碰到的回调嵌套都不会很多,一般就一到两级,但是某些情况下,回调嵌套很多时,代码就会非常繁琐,会给我们的编程带来很多的麻烦,难以维护和调试,一旦出现 bug,牵一发而动全身,这种情况俗称回调地狱。例如:
loadImg('a.jpg', function() { loadImg('b.jpg', function() { loadImg('c.jpg', function() { //... }); });});
当异步的任务很多的时候,维护大量的 callback 将是一场灾难。而 Promise 则可以让我们通过链式调用的方法去解决回调嵌套的问题,使我们的代码更容易理解和维护,而且 Promise 还增加了许多有用的特性,让我们处理异步编程得心应手。
Promise 对象
Promise 对象是一个代理对象(代理一个值),被代理的值在 Promise 对象创建时可能是未知的。它允许你为异步操作的成功和失败分别绑定相应的处理方法(handlers)。 这让异步方法可以像同步方法那样返回值,但并不是立即返回最终执行结果,而是一个能代表未来出现的结果的 promise 对象。
一个 Promise 有以下几种状态:
- pending: 初始状态,既不是成功,也不是失败状态。
- fulfilled: 意味着操作成功完成。
- rejected: 意味着操作失败。
let p = new Promise((resolve, reject) => { setTimeout(() => { Math.random() > 0.5 ? resolve('success') : reject('fail'); }, 1000)});
console.log(p);
p.then((result) => { console.log(result);}, (err) => { console.log(err);});
- 因为
Promise
是一个构造函数,所以我们使用了new
操作符来创建promise
。 - 构造函数
Promise
的参数是一个函数(暂时叫它 func),这个函数(func)有两个参数resolve
和reject
,它们分别是两个函数,这两个函数的作用就是将promise
的状态从pending
(等待)转换为resolved
(已解决)或者从pending
(等待)转换为rejected
(已失败)。 - 创建后的
promise
有一些方法,then
和catch
。当然我们也可以人为的在Promise
函数上添加一些满足我们自己需求的方法,方便每一个promise
对象使用。 then()
方法返回一个Promise
。它最多需要有两个参数:Promise 成功和失败情况的回调函数。Promise
函数体的内部包裹着一个异步的请求或者操作或者函数;然后我们可以在这个异步的操作完成的时候使用resolve
函数将我们获得的结果传递出去,或者使用reject
函数将错误的消息传递出去。- 每个操作都返回一样的
promise
对象,保证链式操作。 - 每个链式都通过
then
方法。 - 每个操作内部允许犯错,出了错误,统一由
catch
error
处理。 - 操作内部,也可以是一个操作链,通过
reject
或resolve
再造流程。