[x, y] = [y, x];
function func() { return [1, 2, 3]; } var [a, b, c] = func();
// 参数是一组无次序的值 function f({x, y, z}) { ... } f({z: 1, y: 2, x: 3});
`var jsonData = { id: 12, name: "sss", data: [867, 5309] }; let { id, name, data: number } = jsonData;`
function move({x = 1, y = 2} = {}) { // 默认值 return [x, y]; } move({x: 3}); // y使用默认值,x:3, y:2
const 声明一个只读的常量。const声明的常量不能从新赋值。编程
常量使用Symbol值最大的好处,就是其余任何值都不可能有相同的值了
Symbol.for方法能够从新使用同一个Symbol值。
对象的属性名如今能够有两种类型,一种是原来就有的字符串,另外一种就是新增的Symbol类型json
JavaScript只有indexOf方法,能够用来肯定一个字符串是否包含在另外一个字符串中。ES6又提供了三种新方法。数组
`var s = 'Hello world!'; s.startsWith('Hello') // true s.endsWith('!') // true s.includes('w') // true`
Array.from方法用于将两类对象转为真正的数组promise
var arr= { '0': 'a', '1': 'b', '2': 'c', length: 3 }; // ES6的写法 var arr2 = Array.from(arr); // ['a', 'b', 'c']
Array.of方法用于将一组值,转换为数组。若是没有参数,就返回一个空数组。浏览器
Array.of(7, 8, 9) // [7,8,9] Array.of(13) // [13] Array.of() // [] Array.of(13).length // 1
箭头函数this对象指向
普通函数this 的指向服务器
箭头函数的this指向数据结构
箭头函数体内的this对象就是定义时所在的对象,而不是使用时所在的对象。app
简单而言,箭头函数使用时,不绑定this对象,箭头函数没有本身的this,它的this是继承而来的,默认指向在定义箭头函数时所处的对象。异步
function foo() { return () => { return () => { return () => { console.log('id:', this.id); }; }; }; } var f = foo.call({id: 1}); // 设置foo的id为1 var t1 = f.call({id: 2})()(); // id: 1 var t2 = f().call({id: 3})(); // id: 1 var t3 = f()().call({id: 4}); // id: 1
上面代码之中,只有一个this,就是函数foo的this。因此t一、t二、t3都输出一样的结果。async
由于全部的内层函数都是箭头函数,都没有本身的this,它们的this其实都是最外层foo函数的this。因此箭头函数的this指向是建立它所在的对象,不会改变。
箭头函数有几个使用注意点:
(1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
(2)不能够看成构造函数,也就是说,不可使用new命令,不然会抛出一个错误。
(3)不可使用arguments对象,该对象在函数体内不存在。若是要用,能够用Rest参数代替。
(4)不可使用yield命令,所以箭头函数不能用做Generator函数。
ES6引入rest参数(形式为“...变量名”),用于获取函数的多余参数,这样就不须要使用arguments对象了。rest参数搭配的变量是一个数组,该变量将多余的参数放入数组中。
function add(...values) { let sum = 0; for (var num of values) { sum += num; } return sum; } add(4, 5, 6,7) // 22
注意,rest参数以后不能再有其余参数(即只能是最后一个参数),不然会报错。函数的length属性,不包括rest参数。
ES6一共有5种方法能够遍历对象的属性:
for...in循环遍历对象自身的和继承的可枚举属性(不含Symbol属性)。
Object.keys返回一个数组,包括对象自身的(不含继承的)全部可枚举属性(不含Symbol属性)。
Object.getOwnPropertyNames返回一个数组,包含对象自身的全部属性(不含Symbol属性,可是包括不可枚举属性)。
Object.getOwnPropertySymbols返回一个数组,包含对象自身的全部Symbol属性。
Reflect.ownKeys返回一个数组,包含对象自身的全部属性,无论是属性名是Symbol或字符串,也无论是否可枚举。
以上的5种方法遍历对象的属性,都遵照一样的属性遍历的次序规则。
class关键字建立一个类代码以下:
class Person{ constructor(x, y) { this.x = x; this.y = y; } // 方法之间不加逗号隔开,不然报错 sum(){ // 方法前面不用加function var sum=this.x+this.y; return sum } }
上面代码定义了一个“类”,能够看到里面有一个constructor方法,这就是构造方法,经过new命令生成对象实例时,自动调用该方法。而this关键字则表明实例对象。
构造函数的prototype属性,在ES6的“类”上面继续存在。全部的方法仍是在prototype属性上。
类的方法内部若是含有 this,它默认指向类的实例。
ES6提供了新的数据结构Set。它相似于数组,可是成员的值都是惟一的,没有重复的值。
var set = new Set([1, 2, 3, 3, 4, 4]); set // Set { 1, 2, 3, 4 }
上面代码能够发现,定义的set对象会本身去除重复的值。Set表示数据的类型是Set。
由于Set数据值的惟一性,咱们能够用它来对数组进行去重。代码以下
var arr=[1, 2, 2, 3, 4, 4]; // 定义一个数组 var set = new Set(arr); //使用扩展运算符Set结构转为数组 var newArr=[...set]; // 或者使用Array.from方法将Set结构转为数组 var newArr=Array.from(set); newArr // [1, 2, 3, 4]
Set实例的方法分为两大类:操做方法(用于操做数据)和遍历方法(用于遍历成员)。
下面先介绍四个操做方法。
var s=new Set(); // 定义s 数据类型为 Set s.add(1).add(2).add(2); // 使用add方法添加值,重复值不会被添加 s.size // 2 注意2被加入了两次,可是去重了一个,因此s的成员数是2 s.has(1) // true 使用has方法判断是否有该值,有因此返回true s.has(2) // true s.has(3) // false 没有该值返回 false s.delete(2); // 使用delete删除该值 s.has(2) // false 由于2被上面删除了,因此没该值,返回false
Set结构的实例有四个遍历方法,能够用于遍历成员。Set的遍历顺序就是插入顺序。
Map数据结构解决了传统对象只能用字符串看成键的局限性。
Map结构的实例属性和操做方法以下:
(1)size属性
size属性返回Map结构的成员总数。
(2)set(key, value)
set方法设置key所对应的键值,而后返回整个Map结构。若是key已经有值,则键值会被更新,不然就新生成该键。
(3)get(key)
get方法读取key对应的键值,若是找不到key,返回undefined。
(4)has(key)
has方法返回一个布尔值,表示某个键是否在Map数据结构中。
(5)delete(key)
delete方法删除某个键,返回true。若是删除失败,返回false。
(6)clear()
clear方法清除全部成员,没有返回值。
使用方法以下:
var map=new Map(); map.set('foo', true); // 设置 map.size; // 1 map.get('foo'); // true map.has('foo') // true map.delete('foo'); // 删除map对象的foo键,删除后使用has返回false map.clear() // 删除map对象全部的键
Map其余方法
Map原生提供三个遍历器生成函数和一个遍历方法。
遍历方法和Set的差很少。
数据结构的互相转换
(1)Map转为数组
前面已经提过,Map转为数组最方便的方法,就是使用扩展运算符(...)。
[...myMap] // myMap表示Map数据
(2)数组转为Map
将数组转入Map构造函数,就能够转为Map。
new Map(数组)
(3)Map转为对象
若是全部Map的键都是字符串,它能够转为对象。
// Map转对象函数 function cMapToObj(strMap) { let obj = Object.create(null); for (let [k,v] of strMap) { obj[k] = v; } return obj; } cMapToObj(myMap)
(4)对象转为Map
function objToMap(obj) { let strMap = new Map(); for (let k of Object.keys(obj)) { strMap.set(k, obj[k]); } return strMap; } objToMap(对象)
(5)Map转为JSON
Map转为JSON要区分两种状况。一种状况是Map的键名都是字符串,这时能够选择转为对象JSON。
JSON.stringify(cMapToObj(myMap)) // cMapToObj是上面定义的函数
另外一种状况是Map的键名有非字符串,这时能够选择转为数组JSON。
JSON.stringify([...myMap])
(6)JSON转为Map
JSON转为Map,正常状况下,全部键名都是字符串。
objToMap(JSON.parse( json数据 )) // objToMap是上面定义的函数
Proxy 能够理解成,在目标对象以前架设一层“拦截”,外界对该对象的访问,都必须先经过这层拦截,所以提供了一种机制,能够对外界的访问进行过滤和改写。
下面是常见的 Proxy 支持的拦截操做方法。
(1)get(target, propKey, receiver)
拦截对象属性的读取,好比proxy.foo和proxy['foo']。
最后一个参数receiver是一个对象,可选,参见下面Reflect.get的部分。
(2)set(target, propKey, value, receiver)
拦截对象属性的设置,好比proxy.foo = v或proxy['foo'] = v,返回一个布尔值。
(3)has(target, propKey)
拦截propKey in proxy的操做,以及对象的hasOwnProperty方法,返回一个布尔值。
(4)deleteProperty(target, propKey)
拦截delete proxy[propKey]的操做,返回一个布尔值。
(5)apply(target, object, args)
拦截 Proxy 实例做为函数调用的操做,好比proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)。
(6)construct(target, args)
拦截 Proxy 实例做为构造函数调用的操做,好比new proxy(...args)。
get()
get方法用于拦截某个属性的读取操做。上文已经有一个例子,下面是另外一个拦截读取操做的例子。
var person = { name: "jack" }; var proxy = new Proxy(person, { get: function(target, property) { if (property in target) { return target[property]; } else { throw new ReferenceError("Property \"" + property + "\" does not exist."); } } }); proxy.name // "jack" proxy.age // 抛出一个错误
上面代码表示,若是访问目标对象不存在的属性,会抛出一个错误。若是没有这个拦截函数,访问不存在的属性,只会返回undefined。
set()
set方法用来拦截某个属性的赋值操做。
let obj = { set: function(obj, prop, value) { if (prop === 'age') { if (!Number.isInteger(value)) { throw new TypeError('错误信息:不是整数'); } if (value > 200) { throw new RangeError('错误信息:年龄大于200'); } } // 对于age之外的属性,直接保存 obj[prop] = value; } }; let person = new Proxy({}, obj); person.age = 13; person.age // 13 person.age = 'jack' // age不是整数报错 person.age = 300 // age大于200报错
上面代码中,因为设置了存值函数set,任何不符合要求的age属性赋值都会抛出一个错误。
ES6创造了一种新的遍历命令for...of循环。Iterator接口的目的,就是为全部数据结构提供了一种统一的访问机制,即for...of循环
Iterator的遍历过程以下:
return方法的使用场合是,若是for...of循环提早退出(一般是由于出错,或者有break语句或continue语句),就会调用return方法。若是一个对象在完成遍历前,须要清理或释放资源,就能够部署return方法,注意,return方法必须返回一个对象,这是Generator规格决定的。
数组遍历语法的比较
for循环
最原始的就是for循环
for(var i=0;i<10;i++){ console.log(i); }
forEach
数组提供内置的forEach方法,缺点是没法中途跳出forEach循环,break命令或return命令都不能奏效。
myArray.forEach(function (value) { console.log(value); });
for...in
遍历的是key。
缺点:数组的键名是数字,可是for...in循环是以字符串做为键名“0”、“1”、“2”等等。
for...in循环主要是为遍历对象而设计的,不适用于遍历数组。
for (let i of list) { console.log( i ); }
for...of
遍历的是value。
for ...of 循环相比上面几种作法,有一些显著的优势。
for (var n of list ) { if (n > 1000) break; console.log(n); } var list=[1,3,"a","b",6];
代码1
for( var i in list){ console.log(i) }
代码2
for(var i of list){ console.log(i) }
代码1依次输出结果的是:0 1 2 3 4
代码2依次输出的结果是:1 3 a b 6
Promise是为了解决多重嵌套回调函数而提出的它不是新的语法功能,而是一种新的写法,容许将回调函数的嵌套,改为链式调用。从语法上说,Promise是一个对象,从它能够获取异步操做的消息。
Promise提供统一的API,各类异步操做均可以用一样的方法进行处理
Promise有如下两个特色:
Promise也有一些缺点:
ES6规定,Promise对象是一个构造函数,用来生成Promise实例。
Promise构造函数接受一个函数做为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由JavaScript引擎提供,不用本身部署。
下面代码创造了一个Promise实例。
var promise = new Promise(function(resolve, reject) { if (true){ resolve(value); } else { reject(error); } });
resolve函数的做用是,将Promise对象的状态从“未完成”变为“成功”(即从Pending变为Resolved),在异步操做成功时调用并将异步操做的结果,做为参数传递出去。
**reject函数的做用是,将Promise对象的状态从“未完成”变为“失败”(即从Pending变为Rejected),在异步操做失败时调用并将异步操做报出的错误,做为参数传递出去。
**
then方法
Promise实例具备then方法。
then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。所以能够采用链式写法,即then方法后面再调用另外一个then方法。
catch方法
Promise.prototype.catch方法是.then(null, rejection)的别名,用于指定发生错误时的回调函数。
`
`getJSON("/posts.json") .then(function(posts) {}) .catch(function(error) {console.log('发生错误!', error); });`
`
上面代码中,getJSON方法返回一个Promise对象,若是该对象状态变为Resolved,则会调用then方法指定的回调函数;若是异步操做抛出错误,状态就会变为Rejected,就会调用catch方法指定的回调函数来处理这个错误。另外,then方法指定的回调函数,若是运行中抛出错误也会被catch方法捕获。
p.then((val) => console.log("fulfilled:", val)) .catch((err) => console.log("rejected:", err)); // 等同于 p.then((val) => console.log("fulfilled:", val)) .then(null, (err) => console.log("rejected:", err));
ES6诞生之前,异步编程的方法,常见的有下面四种。
ES6将JavaScript异步编程带入了一个全新的阶段,ES7的Async函数更是提出了异步编程的新解决方案
async函数
ES7提供了async函数,使得异步操做变得更加方便。
async函数是什么?
async函数就是Generator函数的语法糖。
语法 async function name(param) { statements }
返回值
async 函数返回一个 Promise 对象,可使用 then 方法添加回调函数。
async函数内部return语句返回的值,会成为then方法回调函数的参数。
async function foo(){ return "这是async函数的返回值"; } console.log(foo()) // Promise { '这是async函数的返回值' } foo().then((args)=>{ // 回调函数是箭头函数 console.log(args); // 这是async函数的返回值 })
await命令
await操做符用于等待一个 Promise 对象, 它只能在异步函数 async function 内部使用。
await 的返回值
function testAwait (x) { return new Promise(resolve => { setTimeout(() => { resolve(x); }, 2000); }); } async function foo() { var x = await testAwait ("hello world"); console.log(x); } foo (); // hello world
async function f() { return await 123; } f().then(v => console.log(v)) // 123
async函数返回的Promise对象,必须等到内部全部await命令的Promise对象执行完才会发生状态改变。也就是说,只有async函数内部的异步操做执行完才会执行then方法指定的回调函数。
async函数的错误处理
若是await后面的异步操做出错,那么等同于async函数返回的Promise对象被reject。
async function f() { await new Promise(function (resolve, reject) { throw new Error('出错了111'); }); } f() .then(v => console.log(v)) .catch(e => console.log(e)) // Error:出错了111
上面代码中,async函数f执行后,await后面的Promise对象会抛出一个错误对象,致使catch方法的回调函数被调用,它的参数就是抛出的错误对象。
防止出错的方法,把await命令放在try...catch代码块中。
async function f() { try { await new Promise(function (resolve, reject) { throw new Error('出错了'); }); } catch(e) { } return await('hello world'); }
十3、ES6模块化
ES6 以前,社区制定了一些模块加载方案,最主要的有 CommonJS 和 AMD 两种。前者用于服务器,后者用于浏览器
ES6 在语言标准的层面上,实现了模块功能,成为浏览器和服务器通用的模块解决方案。
模块功能主要由两个命令构成:export 和 import。export命令用于规定模块的对外接口,import命令用于输入其余模块提供的功能。
使用export命令定义了模块的对外接口之后,其余 JS 文件就能够经过import命令加载这个模块。
注意,import命令具备提高效果,会提高到整个模块的头部,首先执行。
一个模块就是一个独立的文件。该文件内部的全部变量,外部没法获取。
若是你但愿外部可以读取模块内部的某个变量,就必须使用export关键字输出该变量。