ES6
ES6的特性比较多,在这里列举几个常用的:
类class
熟悉java等面向对象语言的开发者肯定都十分了解class,对于ES6来说,class就是个语法糖,只是让对象原型的写法变得更加简单和易于理解,我这里就不展开了。
模块化Module
模块的功能主要由export和import组成,每个模块都有自己单独的作用域,模块之间的相互调用关系是通过export来规定模块对外暴露的接口,通过import来引用其他模块提供的接口,同时还为模块创造了命名空间,防止函数的命名冲突。
导出变量:export var name='xxx'
导出常量:export const age='xx'
导出多个变量:export {name,age}
导出函数:export function
导入:import {xxx} from 'xxx'
块级作用域
使用var定义的变量为函数级作用域
使用let和const定义的变量为块级作用域
模板字符串
模板字符串使得字符串的拼接更加的简洁、直观
用反引号包裹字符串,变量放在${}中
//不使用模板字符串 var name='your name is'+first+'.' //使用模板字符串 var name=`your name is ${first}.`
Promise
promise是异步编程的一种解决方案,比传统的回调函数和事件更加合理和强大。简单来说,promise是一个容器,里面保存了一个在未来才会结束的事件,这种“承诺将来会实现的对象”在JavaScript中被称为promise对象。
promise对象有三个状态:pending
(进行中)、fulfilled
(resolved已成功)和rejected
(已失败)
基本用法:
创建一个promise实例
const promise = new Promise(function(resolve, reject) { //Promise
构造函数接受一个函数作为参数,该函数的两个参数分别是resolve
和reject
。它们是两个函数,由 JavaScript 引擎提供,不用自己部署。 if (/* 异步操作成功 */){ resolve(value); } else { reject(error); } });
Promise
实例生成以后,可以用then
方法分别指定resolved
状态和rejected
状态的回调函数。
promise.then(function(value) { // success }, function(error) { // failure });
then
方法可以接受两个回调函数作为参数。第一个回调函数是Promise
对象的状态变为resolved
时调用,第二个回调函数是Promise
对象的状态变为rejected
时调用。其中,第二个函数是可选的,不一定要提供。这两个函数都接受Promise
对象传出的值作为参数。
再看下面这个例子,这个test()函数有两个参数,这两个参数都是函数,如果执行成功,我们将调用resolve('200 OK')
,如果执行失败,我们将调用reject('timeout in ' + timeOut + ' seconds.')
。可以看出,test()函数只关心自身的逻辑,并不关心具体的resolve
和reject
将如何处理结果。
function test(resolve, reject) { var timeOut = Math.random() * 2; log('set timeout to: ' + timeOut + ' seconds.'); setTimeout(function () { if (timeOut < 1) { log('call resolve()...'); resolve('200 OK'); } else { log('call reject()...'); reject('timeout in ' + timeOut + ' seconds.'); } }, timeOut * 1000); }
new Promise(test).then(function (result) {
console.log('成功:' + result);
}).catch(function (reason) {
console.log('失败:' + reason);
});
可见Promise最大的好处是在异步执行的流程中,把执行代码和处理结果的代码清晰地分离了
Async/await
ES2018引入异步迭代器,await可以和for ...of循环一起使用,以串行的方式运行异步操作
async函数返回一个 Promise 对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。即async函数必须等到内部所有的 await 命令的Promise对象执行完,才会发生状态改变。
await 放置在Promise调用之前,await 强制后面点代码等待,直到Promise对象resolve,得到resolve的值作为await表达式的运算结果
await只能在async函数内部使用,用在普通函数里就会报错
下面是一个例子:
async function getStockPriceByName(name) { const symbol = await getStockSymbol(name); const stockPrice = await getStockPrice(symbol); return stockPrice; } getStockPriceByName('goog').then(function (result) { console.log(result); });
上面代码是一个获取股票报价的函数,函数前面的async
关键字,表明该函数内部有异步操作。调用该函数时,会立即返回一个Promise
对象。
proxy
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。
ES6 原生提供 Proxy 构造函数,用来生成 Proxy 实例。new Proxy()
表示生成一个Proxy
实例,target
参数表示所要拦截的目标对象,handler
参数也是一个对象,用来定制拦截行为。
var proxy = new Proxy(target, handler);
Proxy 支持的拦截操作一共 13 种,戳这里~
只要是proxy对象的方法,就能在reflect对象上找到对应的方法。
reflect:
- 可以拿到语言内部的方法(如Object.defineProperty)
- 修改某些Object方法的返回结果,让其变得更合理
- 让Obect操作都变成函数行为,而非命令式
Iterator和for...of
任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)
作用有三个:一是为各种数据结构,提供一个统一的、简便的访问接口;二是使得数据结构的成员能够按某种次序排列;三是 ES6 创造了一种新的遍历命令for...of
循环,Iterator 接口主要供for...of
消费。
原生具备 Iterator 接口的数据结构如下。
- Array
- Map
- Set
- String
- TypedArray
- 函数的 arguments 对象
- NodeList 对象
Generator
Generator函数两个特征:
- 关键字function和函数名之间有一个星号
- 函数体内部使用yield表达式,定义不同的内部状态
由于 Generator 函数返回的遍历器对象,只有调用next
方法才会遍历下一个内部状态,所以其实提供了一种可以暂停执行的函数。yield
表达式就是暂停标志。
遍历器对象的next
方法的运行逻辑如下。
(1)遇到yield
表达式,就暂停执行后面的操作,并将紧跟在yield
后面的那个表达式的值,作为返回的对象的value
属性值。
(2)下一次调用next
方法时,再继续往下执行,直到遇到下一个yield
表达式。
(3)如果没有再遇到新的yield
表达式,就一直运行到函数结束,直到return
语句为止,并将return
语句后面的表达式的值,作为返回的对象的value
属性值。
(4)如果该函数没有return
语句,则返回的对象的value
属性值为undefined
。
async
函数就是将 Generator 函数的星号(*
)替换成async
,将yield
替换成await,是Generator函数的语法糖
箭头函数
=>不只是关键字function的简写,它还带来了其他好处,箭头函数与包围它的代码共享同一个this,有经验的JavaScript开发者都熟悉诸如var self=this或var that=this这种引用外围this的模式,但借助=>就不需要这种模式了
//无参数,返回1 ()=>1 //有参数x,返回x+1 x=>x+1 //有两个参数,返回a+b (a,b)=>a+b //箭头后面是用花括号括起的函数体,需要自行通过return来返回值 ()=>{ alert("foo"); }
扩展操作符...
扩展运算符可以在函数调用/数组构造时,将数组表达式或者string在语法层面展开,还可以在构造对象时,将对象表达式按key-value的方式展开等等,接下来我来介绍一些常见的用法:
对象的扩展运算符:用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中
let bar = { a: 1, b: 2 }; let baz = { ...bar }; // { a: 1, b: 2 }
//等价于Object.assign({}, bar)
数组的扩展运算符:
可以将数组转化为参数数列
function add(x, y) { return x + y; } const numbers = [4, 38]; add(...numbers) // 42
可以复制数组:
const arr1 = [1, 2];
const arr2 = [...arr1];
可以与解构赋值结合起来,用于生成数组:
const [first, ...rest] = [1, 2, 3, 4, 5]; first // 1 rest // [2, 3, 4, 5]
//如果将扩展运算符用于数组赋值,只能放在参数的最后一位,否则会报错。
可以将字符串转为数组:
[...'hello'] // [ "h", "e", "l", "l", "o" ]
我们都知道阮一峰老师写了本es6入门的书,详细学习去那里啦~