let和const命令
let命令
- 循环体的let变量只对花括号做用域可见,花括号外不可见
- 循环体的语句部分是一个父做用域,而循环体内部是一个单独的子做用域
- let声明的变量不存在变量提高,未声明的使用会报错
- 只要块级做用域内存在let声明,它所声明的变量就绑定了这个区域,再也不受外部的影响
- let不容许在相同的做用域重复声明同一个变量,子父级做用域能够同名变量声明
const命令
- const常量的值一旦声明就不得改变
- const一旦声明变量,就必须当即初始化,不能留到之后赋值
- const的做用域与let命令相同,只在声明所在的块级做用域内有效
- const命令一样存在暂时性死区,只能在声明的位置后面使用
- const声明的常量,也与let同样不可重复声明
- 对于复合类型的变量,变量名不指向数据,而是指向数据所在的地址,因此const命令只是保证变量名指向的地址不变,并不保证该地址的数据不变
——let和const命令的声明再也不自动归入global对象(window)node
块级做用域与函数声明
- ES6的浏览器下,块级做用域内声明的函数会被提高至全局做用域或函数做用域顶部,做为
var fn = undefined
- 其余的游览器下,仍是将块级做用域的函数声明看成let处理
- 应该避免在块级做用域内声明函数,若是确实须要也应该使用函数表达式而不是函数声明
- ES6的块级做用域容许声明函数,但只在使用大括号的状况下成立,若是没有使用大括号就会报错
变量的解构赋值
数组的解构赋值
- 只要某种数据结构具备Iterator接口,均可以采用数组形式的解构赋值
- 解构赋值容许指定默认值,可是若是一个数组成员不严格等于undefined,默认值不会生效
- 若是默认值是一个表达式,那么这个表达式是惰性求值的,即只有在用到的时候才会求值
- 默认值能够引用解构赋值的其余变量,但该变量必须已经声明
- 可使用嵌套进行解构赋值
let [foo, [[bar], baz]] = [1, [[2], 3]];
对象的解构赋值
- 变量必须与属性同名,才能取到正确的值
let { foo, bar } = { foo: "aaa", bar: "bbb" };
- 若是变量名与属性名不一致,必须写成
let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
- 声明后再进行的赋值必须加圆括号
let foo;——({foo} = {foo: 1});
- 对象的解构也能够指定默认值,同数组同样成员对应必须严格等于undefined,默认值才会生效
字符串的解构赋值
- 字符串进行解构赋值时,会被转换成一个相似数组的对象
const ### a, b, c, d, e = 'hello'
- 相似数组的对象都有一个length属性,所以还能够对这个属性解构赋值
let { length : len } = 'hello'
数值和布尔值的解构赋值
- 解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象
let {toString: s} = 123;
s === Number.prototype.toString // true
- 因为undefined和null没法转为对象,因此对它们进行解构赋值,都会报错
let { prop: x } = undefined; // TypeError
函数参数的解构赋值
- 函数参数的解构赋值遵循基本解构类型的特色
圆括号问题
- 不能使用圆括号的状况:
- a.变量声明语句中,不能带有圆括号
- b.函数参数中,模式不能带有圆括号
- c.赋值语句中,不能将整个模式,或嵌套模式中的一层,放在圆括号之中
- 能使用圆括号的状况:
解构赋值的用途
- 交换变量的值
- 从函数返回多个值
- 函数参数的定义
- 提取JSON数据
- 函数参数的默认值
- 遍历Map结构
- 输入模块的指定方法
字符串的扩展
- codePointAt()——处理4个字节储存的字符,返回一个字符的码点(默认十进制,十六进制可使用toString方法转换)
- String.fromCodePoint()——能够识别大于0xFFFF的字符,弥补了String.fromCharCode方法的不足
- ES6为字符串添加了遍历器接口for...of,除了遍历字符串,这个遍历器最大的优势是能够识别大于0xFFFF的码点
- at()提案——识别Unicode编号大于0xFFFF的字符,返回正确的字符
- normalize()——将字符的不一样表示方法统一为一样的形式,这称为Unicode正规化
- 索引字符是否存在——接受二个参数,第一个表示索引字符,第二个表示起始位置
- includes()——返回布尔值,表示是否找到了参数字符串
- startsWith()——返回布尔值,表示参数字符串是否在源字符串的头部
- endsWith()——返回布尔值,表示参数字符串是否在源字符串的尾部
- repeat()——将原字符串重复n次,返回一个新字符串
- a.参数若是是小数,会被取整
- b.参数是负数或Infinity,会报错
- c.参数是0到-1之间的小数,则等同于0(这是由于会先进行取整运算)
- d.参数是字符串,则会先转换成数字
- 字符串补全长度——接受两个参数(第一个表示字符串补全的最小长度,第二个表示要参与补全的字符串)
- padStart()——用于头部补全
- padEnd()——用于尾部补全
- a.若是原字符串的长度,等于或大于指定的最小长度,则返回原字符串
- b.若是用来补全的字符串与原字符串,二者的长度之和超过了指定的最小长度,则会截去超出位数的补全字符串
- c.若是省略第二个参数,默认使用空格补全长度
- 用途:
- a.为数值补全指定位数
'1'.padStart(10, '0')
- b.日期字符串格式化
'12'.padStart(10, 'YYYY-MM-DD')
- 模板字符串
- a.模板字符串是加强版的字符串,用反引号()标识
- b.能够看成普通字符串使用,也能够用来定义多行字符串,或者在字符串中嵌入变量
- c.空格,缩进和换行的状态都会被保持,除非使用.trim()去除
- d.模板字符串中嵌入变量,须要将变量名写在${}之中,{}至关于js执行域,能够放置变量,表达式和函数(可调用)等
- e.若是大括号中的值不是字符串,将按照通常的规则转为字符串;若是内部是一个字符串,将原样输出
- 标签模版
- a.模版字符串前跟函数名,该函数将会被调用来处理该模版字符串,这被称为"标签模版"功能
- b.函数处理模版字符串的时候,会将没有变量${}的部分拼合成数组参数,变量${}部分的结果做为后续参数
- c.函数处理模版字符串时,参数形式被转换为(数组,参数1,参数2..),其中的数组项有一个raw属性,与参数数组的项几乎相同,惟一的区别是字符串里面的斜杠都被转义了
- String.raw模版字符串
- a.用于处理模版字符串,返回一个斜杠都被转义的字符串(若是原字符串斜杠已经转义,String.raw不会作任何处理)
- b.也能够做为正常的函数使用,第一个参数应该是一个具备raw属性的对象,且raw属性的值应该是一个数组
- 模版字符串的限制
- a.默认会将字符串转义,所以致使了没法嵌入其余语言
- b.解决提案——遇到不合法的字符串转义,就返回undefined,而不是报错,而且从raw属性上面能够获得原始字符串
正则的扩展
数值的扩展
二进制和八进制表示法
- 二进制——0b(或0B)
- 八进制——0o(或0O)
新增api
- Number.isInteger()——是否为整数
- Number.EPSILON——极小常量,能够接受的偏差范围
- Number.MAX_SAFE_INTEGER
- Number.MIN_SAFE_INTEGER——安全整数
- Number.isSafeInteger()——整数是否落在安全范围(超出精度的结果会被自动设为界点值,因此验证运算结果是否落在安全整数的范围内,不要只验证运算结果,而要同时验证参与运算的每一个值)
function trusty (left, right, result) {
if (Number.isSafeInteger(left) &&
Number.isSafeInteger(right) &&
Number.isSafeInteger(result)) {
return result;
}
throw new RangeError('Operation cannot be trusted!');
}
Math对象的拓展
- Math.trunc()——去除一个数的小数部分
- Math.sign()——判断一个数是正数,负数,仍是零
- Math.cbrt()——计算一个数的立方根
- Math.clz32()——一个数的32位无符号整数形式有多少个前导0
- Math.imul()——返回两个数以32位带符号整数形式相乘的结果(解决相乘数超过js精度的问题)
- Math.fround()——返回一个数的单精度浮点数形式(主要用于那些没法用64个二进制位精确表示的小数)
- Math.hypot()——返回全部参数的平方和的平方根
指数运算符
函数的扩展
函数参数的默认值
- 参数变量是默认声明的,不能用let或const再次声明(可用var,二者独立)
- 使用参数默认值时,不能有同名参数
- 参数默认值是惰性求值的——若是参数默认值是变量,那么参数实际值只有运行时才能肯定
- 参数默认值可为解构赋值形式
function({a}={}){}
函数的length属性
- 函数的length属性,不包括rest参数和参数默认值
函数默认值做用域
- 一旦设置了参数默认值,函数进行声明初始化时,参数会造成一个单独的做用域
- 参数默认值造成的做用域与函数体内部的做用域不属于同一个做用域,后者优先级大于前者
rest参数
- 获取函数的多余参数,在参数中展示为数组
- rest只能做为最后一个,它以后不能再有其余参数
扩展运算符
- 将一个数组转为用逗号分隔的参数序列——可用于伪数组(arguments,nodelist)
- 若是将扩展运算符用于数组的解构赋值,只能放在参数的最后一位,不然会报错
- 任何实现了Iterator接口的对象,均可以用扩展运算符转为真正的数组——### ...伪数组
- 扩展运算符在处理字符串(Iterator接口)时,除能将其转换为数组还能识别32位的Unicode字符
严格模式
- 函数参数使用了默认值、解构赋值、或者扩展运算符,那么函数内部就不能显式设定为严格模式,不然会报错
- 解决办法——在函数体外设置严格模式
name属性
- 函数表达式下,es5的name取值为空字符串,es6为变量名
- Function构造函数返回的函数实例,name属性的值为anonymous
- bind返回的函数,name属性值会加上bound前缀+函数名
- 用一个Symbol值的变量去定义方法,name属性返回Symbol值的描述
箭头函数
- 函数体内的this对象,就是定义生效时所在的对象,而不是使用时所在的对象
- 不能够看成构造函数的new命令,由于箭头函数内部没有this,只能获取到外层this
- 不可使用arguments对象,该对象在函数体内不存在,可用rest参数代替
- 不可使用yield命令,所以箭头函数不能用做Generator函数
- super、new.target在箭头函数中一样不存在,由于不存在内部this,因此用call()、apply()、bind()去改变函数this指向的操做无效
绑定this
- call、apply、bind的替代品——对象::函数,返回原对象
- 该运算符会自动将左边的对象,做为上下文环境(即this对象),绑定到右边的函数上面
尾调用优化
- 当尾调用函数内部不依赖于外层变量做用域的时候,函数执行时调用帧就只有一项,这将大大节省内存
- ES6的尾调用优化只在严格模式下开启,正常模式是无效的
尾递归优化
- 对于尾递归来讲,因为只存在一个调用帧,因此永远不会发生“栈溢出”错误
- 尾递归的单次调用帧下降了算法复杂度,减轻了运算压力
- 尾递归应该是单项的,对于多项尾递归同时进行一样会增长调用帧,形成“栈溢出”
- 解决尾递归调用栈太多的办法是采用"循环"换掉"递归",在循环中每一步返回另外一个函数并执行
函数参数的尾逗号
- 函数参数定义和调用时的参数书写均可以在参数尾部添加多于的逗号
数组的扩展
静态方法
- Array.from——用于将相似数组的对象和可遍历的对象(带iterable句柄)转换为真正的数组
- a.接受3个参数——Array.from(对象,过滤函数,上下文)
- b.任何有length属性的对象,均可以经过Array.from方法转为数组,扩展运算符没法转作到
- c.能正确处理各类Unicode字符,能够避免JavaScript将大于\uFFFF的Unicode字符,算做两个字符的bug
- Array.of——用于将一组值,转换为数组
- a.弥补用数组构造函数生成数组的差别性
- b.Array(3) ### '','',''与Array(3, 11, 8) ### 3, 11, 8
实例方法
- copyWithin()
在当前数组内部,将指定位置的成员复制到其余位置(覆盖该位置),返回当前数组(开始替换的位置,开始复制的位置,结束复制的位置)
- fill()
填充和替换(值,起始位置,结束为止)
- includes(值,位置)
是否包含给定值(不像indexOf方法同样采用全等于进行比较)
- find(条件函数)
查找符合条件的值并返回
- findIndex(条件函数)
查找符合条件的值并返回位置
- entries()
键值对遍历器(iterator)
- keys()
键名遍历器(iterator)
- values()
键值遍历器(iterator)
数组的空位
- Array(2)——['','']
- es6的数组遍历方法都会跳过空位,map也会跳过,可是会保留空位
- join()和toString()会将空位视为undefined,而undefined和null会被处理成空字符串
- es6新增方法会默认将空位转换为undefined,for...of循环则会遍历空位
对象的拓展
属性的简洁表示法
- 容许在对象中直接写入变量,变量名做为键,变量值做为值
- 容许对象定义中的方法简写(省却:和function)
属性名表达式
- 容许在对象字面量定义中,[表达式]做为键的写法
- 若是属性名表达式的键是一个对象变量,那它会自动转换为"[object Object]"名
新增api
- Object.is(值1,值2)
是否严格相等
- Object.assign(target,source1,source2..)
对象浅拷贝
- a.若是target传递undefind和null会报错
- b.除引用类型外,source只接受字符串,其他忽略
- c.属性名为Symbol值的属性也会被Object.assign拷贝
- d.对于嵌套形式的对象形式,source会覆盖整个键名对应的对象
- f.处理数组时会把数组视为对象,经过对应数组下标进行属性拷贝和覆盖
- e.没法正确拷贝get属性和set属性(undefined)
- Object.setPrototypeOf(obj,prototype)
为对象设置原型
- Object.getPrototypeOf(obj)
返回对象的原型
- Object.getOwnPropertySymbols()
返回Symbol属性键数组
- Object.keys()
返回键数组(可枚举)
- Object.values()
返回值数组(可枚举)
- Object.entries()
返回键值对数组
- Object.getOwnPropertyDescriptors()
返回指定对象全部自身属性的描述对象
对象的扩展运算符
- 在解构赋值下,"...obj"等于剩余对象集
- 在解构赋值下,"...obj"必须处于最后一位
- 在对象使用中,"...obj"将对象拆散成单个键值对放入{}(可用于浅拷贝和对象合并)
- 在对象使用中,若是出现同名键值对,后面会覆盖前面的(适用于对象的扩展运算符)
- 在对象使用中,若是扩展运算符表明的对象键值对中有get取值函数,这个函数会执行
Null传导运算符·提案
- 经过符号"?."简化逻辑与,简化对象判断
const firstName = (message&&message.body&&message.body.user&&message.body.user.firstName) || 'default'
const firstName = message?.body?.user?.firstName || 'default'
Symbol
使用注意
- 一种新的原始数据类型,表示独一无二的值
- 能够接受一个字符串参数,用于Symbol值的描述区分
Symbol("xjh")
- 不能用new操做符,也不能参与运算,相似于字符串
- 对象操做必须用中括号表示,用点运算符赋值无效——用Symbol值直接定义或赋值会转换为字符串键
- 若是Symbol()的参数是一个对象,就会调用该对象的toString方法将其转为字符串,而后才生成一个Symbol值
- Symbol值能够强制类型转换为字符串,布尔值,数组和对象,可是不能转换为数
相关api
- Symbol.for("name")
- a.若是存在登记为name的symbol值就取到,不然就建立
- b.若是存在登记为name的symbol值,重复的调用只会获得同一个symbol值
- c.Symbol.for建立的symbol值是全局的,iframe生成的能够在主页获取到
- Symbol.keyFor("name")
- a.返回已登记的Symbol类型值的key
- b.Symbol("name")建立的不属于登记返回,没法返回key
内置Symbol
- Symbol.hasInstance
- a.等同于instancsof,判断是否为该对象的实例时,会调用这个方法
- b.foo instanceof Foo在语言内部,实际调用的是Foo[Symbol.hasInstance(foo)]
- Symbol.isConcatSpreadable
- a.等于一个布尔值,表示该对象使用Array.prototype.concat()时,是否能够展开
- b.数组的默认行为是能够展开的,Symbol.isConcatSpreadable属性等于true或undefined,都有这个效果
- c.相似数组的对象也能够展开,但它的Symbol.isConcatSpreadable属性默认为false,必须手动打开
- Symbol.species
- a.指向当前对象的构造函数,创造实例时,默认会调用这个方法
- b.定义Symbol.species属性要采用get读取器,默认读取this
- Symbol.match
- a.返回一个执行正则的match函数
- b.当执行str.match(obj)时,若是obj中存在该属性,则在会调用它
- Symbol.replace
- a.返回一个执行替换的replace函数
- b.当执行str.replace(obj,"World")时,若是obj中存在该属性,则在会调用它
- Symbol.search
- a.返回一个执行查找的search函数
- b.当执行str.search(obj)时,若是obj中存在该属性,则在会调用它
- Symbol.split
- a.返回一个执行查找的search函数
- b.当执行str.split(obj)时,若是obj中存在该属性,则在会调用它
- Symbol.iterator
- a.指向当前对象默认的遍历器方法
- b.对象进行for...of循环时,会调用Symbol.iterator方法
- Symbol.toPrimitive
- a.返回将对象转为原始类型值的方法
- b.Symbol.toPrimitive被调用时,会接受一个字符串参数,表示当前运算的模式
- Number:该场合须要转成数值
- tring:该场合须要转成字符串
- Default:该场合能够转成数值,也能够转成字符串
- Symbol.toStringTag
- a.返回一个类型字符串表示的函数
- b.当执行Object.prototype.toString时,若是obj中存在该属性,则在会调用它
- Symbol.unscopables
- a.指向一个对象,指定了使用with关键字时,哪些属性会被with环境排除
- b.被它指定的属性和方法将在with做用域中被忽略
Set和Map数据结构
Set
- 一种相似于数组的新数据结构,成员的值都是惟一的,不存在重复
- Set的构造函数接受数组(或具备iterable接口的其余数据结构)做为参数
- Set的值是跟内存地址绑定的,只要内存地址不同,就视为两个值
- Set的实例默承认遍历,它的默认遍历器生成函数就是values方法
- Set的遍历顺序就是插入顺序,keys方法和values方法的行为彻底一致
- 实例属性和方法
- size 返回成员个数
- add() 添加某个值(返回Set实例)
- delete() 删除某个值(返回布尔值)
- has() 返回布尔值
- clear() 清除全部成员(没有返回值)
- keys() 返回键名遍历器
- values() 返回键值遍历器
- entries() 返回键值对遍历器
- forEach() 带回调函数的遍历方法
WeakSet
- WeakSet结构与Set相似,也是不重复的值的集合,没有size和length属性
- 构造函数的参数也只能接受数组或相似数组,但其成员必须为对象
- WeakSet中的对象都是弱引用,其指向的对象不计入垃圾回收机制
- WeakSet用于存储DOM节点时,若是节点从文档移除,会自动进行垃圾回收
- 实例属性和方法
- add() 添加对象(返回实例)
- delete() 删除某个值(返回布尔值)
- has() 返回布尔值
Map
- 一种相似于对象的新数据结构,可是键的范围不限于字符串,各类类型的值均可以看成键
- 构造函数接受数组(或具备iterable接口的其余数据结构)做为参数,数组项为表明键值项的数组(### "a",1)
- Map的键上是跟内存地址绑定的,只要内存地址不同,就视为两个键
- 实例属性和方法
- size 返回成员个数
- set 添加键值对(返回Set实例)
- get 返回值(无则undefined)
- has() 返回布尔值
- delete() 删除某个值(返回布尔值)
- clear() 清除全部成员(没有返回值)
- keys() 返回键名的遍历器
- values() 返回键值的遍历器
- entries() 返回全部成员的遍历器
- forEach() 遍历Map的全部成员
WeakMap
- WeakMap结构与Map结构相似,也是用于生成键值对的集合,没有size和length属性
- WeakMap只接受对象做为键名(null除外),不接受其余类型的值做为键名
- WeakMap的键名都是弱引用,键名所指向的对象不计入垃圾回收机制
- WeakMap用于储存dom节点的临时数据时,若是节点从文档移除,会自动进行垃圾回收
- 实例属性和方法
- get() 获得对象
- set() 添加对象(返回实例)
- delete() 删除某个值(返回布尔值)
- has() 返回布尔值
Proxy
概述
- Proxy用于修改某些操做的默认行为,等同于在语言层面作出修改,属于一种“元编程”
- new Proxy(target, handler)接收2个参数,target表明目标对象,handler表明参数对象,用于定制行为
- 若是handler没有设置任何拦截,那就等同于直接指向原对象
- 若是一个属性不可配置和不可写,则该属性不能被代理,经过Proxy对象操做该属性会报错
实例方法
- get()
- set()
- apply()
- has()——对象是否具备某个属性
- construct()——针对new命令
- deleteProperty()——delete操做
- a.方法返回false,属性就没法被delete删除
- defineProperty()
- getOwnPropertyDescriptor()
- getPrototypeOf()
- a.getPrototypeOf方法的返回值必须是对象或者null,不然会报错
- isExtensible()——是否锁定[不可拓展属性]
- a.该方法只能返回布尔值,不然返回值会被自动转为布尔值
- b.proxy(拦截函数返回值)与target的Object.isExtensible()结果必须一致,不然报错
- ownKeys()——对象自身属性的读取操做
- a.主要拦截Object.keys(),Object.getOwnPropertyNames()和Object.getOwnPropertySymbols()函数
- b.ownKeys方法返回的数组成员,只能是字符串,不然会报错
- c.拦截Object.keys时,有三类属性会被ownKeys方法自动过滤——不存在的属性,不可遍历的属性和Symbol值属性
- d.若是目标对象是不可扩展的,ownKeys返回的数组之中必须包含原对象的全部属性,且不能包含多余的属性,不然报错
- preventExtensions()——锁定操做
- a.该方法只能返回布尔值,不然返回值会被自动转为布尔值
- b.只有目标对象不可扩展时,返回值才能为true,不然会报错
- setPrototypeOf()——设置原型属性
- a.该方法只能返回布尔值,不然返回值会被自动转为布尔值
- b.若是目标对象不可扩展,则setPrototypeOf方法不得改变目标对象的原型
静态方法
- Proxy.revocable()
- a.返回一个可取消的实例
- b.执行实例的revoke方法后,proxy实例不可再访问,不然会报错
this问题
- 在Proxy代理的状况下,目标对象内部的this关键字会指向proxy实例
- 有些原生对象的内部属性,只有经过正确的this才能拿到,因此Proxy也没法代理这些原生对象的属性
Reflect
概述
- 将Object对象的一些明显属于语言内部的方法放到Reflect对象上
- 现阶段,某些方法同时在Object和Reflect对象上部署,将来的新方法将只部署在Reflect对象上
- 修改某些Object方法的返回结果,让其变得更合理
- Object.defineProperty在没法定义属性时,会抛出一个错误,而Reflect.defineProperty则会返回false
- 让以前是命令式的Object操做行为变成函数行为
"a" in obj,delet obj['a']
变成Reflect.has(obj, name),Reflect.deleteProperty(obj, name)
- Reflect对象的方法与Proxy对象的方法一一对应,只要是Proxy对象的方法,就能在Reflect对象上找到对应的方法
静态方法
- get()
- set()
- a.若是Proxy对象和Reflect对象联合使用,经过proxy对Reflect传入context会触发proxy的defineProperty拦截
- has()
- deleteProperty()
- a.若是删除成功或者被删除的属性不存在,返回true;删除失败,返回false
- construct()
- a.等同于new target(...args),提供了一种不使用new,来调用构造函数的方法
- getPrototypeOf()
- a.若是参数不是对象,Object.getPrototypeOf会将这个参数转为对象,而后再运行,而Reflect.getPrototypeOf会报错
- setPrototypeOf()
- a.用于设置对象的__proto__属性,返回第一个参数对象
- b.若是第一个参数不是对象,Object.setPrototypeOf会返回这个参数,而Reflect.setPrototypeOf会报错
- **apply()
- defineProperty()
- getOwnPropertyDescriptor()
- a.若是第一个参数不是对象,Object.getOwnPropertyDescriptor会返回undefined,而Reflect.getOwnPropertyDescriptor会抛出错误
- isExtensible()
- a.对象是否能够拓展
- b.若是参数不是对象,Object.isExtensible会返回false,由于非对象原本就是不可扩展的,而Reflect.isExtensible会报错
- preventExtensions()
- a.设置对象为不可拓展
- b.若是参数不是对象,Object.preventExtensions在es5环境报错,在es6环境返回传入的参数,而Reflect.preventExtensions会报错
- ownKeys()
- a.返回对象的全部属性(可枚举和不可枚举,可读和不可读)
Promise对象
Promise含义
- Promise是一个能够获取异步操做消息的对象,它提供了统一的API,使得各类异步操做均可以用一样的方法进行处理
- Promise有三种状态Pending,Resolved和Rejected,只有异步操做的结果,能够决定当前是哪种状态
- Promise对象的状态不受外界影响,一旦状态改变,就不会再变,任什么时候候获得的都是这个结果
- Promise实例之间进行传递的时候,被传递实例会等待传递实例的状态改变后才进行回调状态操做
- 优势:
- a.能够将异步操做以同步操做的流程表达出来,避免了层层嵌套的回调函数
- b.统一的接口使得控制异步操做更加容易
- 缺点:
- a.没法取消Promise,一旦新建它就会当即执行,没法中途取消
- b.若是不设置回调函数,Promise内部抛出的错误不会反应到外部
- c.当处于Pending状态时,没法得知目前进展到哪个阶段(刚刚开始仍是即将完成)
基本用法
var promise = new Promise(function(resolve, reject) {
if (true){
resolve(value);
} else {
reject(error);
}
});
promise.then(function(value) {
// success
}, function(error) {
// failure
});
Promise.prototype.then
- then方法会默认返回一个新Promise实例,所以能够进行链式操做
- then方法主动return的值会做为下一个then方法的参数
- then方法主动return的new Promise实例会被加入异步堆栈,只有其状态改变才会执行其链式的then回调
Promise.prototype.catch
- Promise.prototype.catch方法是.then(null,Rejected)的别名,用于指定发生错误时的回调函数
- 若是异步操做抛出错误,状态就会变为Rejected,就会调用catch方法指定的回调函数
- then方法指定的回调函数,若是运行中抛出错误,也会被catch方法捕获
- 在Promise构造函数回调中直接调用Rejected方法会触发catch方法
- catch方法返回的仍是一个Promise对象,所以后面还能够接着调用then方法
- catch方法之中,还能再抛出错误,当还存在下一个catch的时候就会捕获并执行
Promise.all
- 用于将多个Promise实例,包装成一个新的Promise实例
- Promise.all方法接受一个数组做为参数
- a.若是数组由Promise实例组成,则会等待其中的Promise都完成时才会触发Promise.all实例的状态变化
- b.若是数组不禁Promise实例组成,就会直接调用Promise.resolve方法,将参数转为Promise实例,再进一步处理
- 只有p一、p二、p3的状态都完成,组合p的状态才会完成
- 只要p一、p二、p3之中有一个被rejected,组合p的状态就变成rejected(此时第一个被reject的实例返回值会传递给p的回调函数)
Promise.race
- 同上
- 只要有一个Promise参数实例完成,就会调用Promise.race实例的状态变化,将率先完成的子Promise参数传递给Promise.race回调
Promise.resolve
- 将现有对象转为Promise对象
- a.当参数为Promise对象时,会原封不动返回该对象
- b.当参数为带"then"键名方法的对象时,会将这个对象转为Promise对象,而后就当即执行该对象的then方法
- c.当参数为非带"then"键名方法的对象时,Promise.resolve方法返回一个新的Promise对象,状态为Resolved
- d.不带参数时,Promise.resolve方法直接返回一个新的Promise对象,状态为Resolved
Promise.reject
- 返回一个新的Promise实例,状态为rejected,参数为错误信息
- Promise.reject()方法的参数,会原封不动地做为reject或catch的回调参数
Promise.try提案
- 对于那种多是同步多是异步的返回操做提供统一的处理方式,动态执行对应的同步/异步状态
- database.users.get({id: userId})有可能报同步错误,有可能报异步错误
Promise.try(database.users.get({id: userId})).then(...).catch(...)
Iterator和for...of循环
Iterator的做用
- 为各类数据结构,提供一个统一的、简便的访问接口(for...of)
- 使得数据结构的成员可以按某种次序排列
- 当使用for...of循环遍历某种数据结构时,该循环会自动去寻找Iterator接口
默认Iterator接口
- 部署了Symbol.iterator属性的数据结构,就称为部署了遍历器接口
- 原生具有Iterator接口的数据结构有:Array,Map,Set,String,TypedArray和函数的arguments对象
调用场合
- 解构赋值,扩展运算符,yield*,for..of
遍历器对象的return和throw方法
- return方法
- 调用场景——若是for...of循环提早退出(一般是由于出错,或者有break语句或continue语句)
- 部署场景——若是一个对象在完成遍历前,须要清理或释放资源,就能够部署return方法
- throw方法
- 主要是配合Generator函数使用,通常的遍历器对象用不到这个方法
for...of循环
- 一个数据结构只要部署了Symbol.iterator属性,就被视为具备iterator接口,就能够用for...of循环遍历它的成员
- for...of循环内部调用的就是数据结构的Symbol.iterator方法
- 拥有iterator接口的数据结构——字符串,数组,类数组(arguments和DOM NodeList),Generator对象
- for...of更经常使用于数组循环,for...in更经常使用于对象循环
Generator函数的语法
基本概念
- 语法上,function关键字与函数名之间有一个星号*,函数体内部使用yield表达式
- Generator属于普通函数,调用不会当即执行,而是返回一个遍历器对象,须要调用next()才能执行yield状态
- Generator函数就是遍历器生成函数,所以能够把Generator赋值给对象的Symbol.iterator属性,从而使得该对象具备Iterator接口,能够被for...of循环和扩展运算符转换
yield表达式
- yield表达式若是用在一个表达式中,必须放在圆括号里面;若是用做函数参数或放在赋值表达式右边,能够不加括号
- yield表达式自己没有返回值,老是返回undefined;
- next方法能够带一个参数,该参数就会被看成上一个yield表达式的返回值
- 因为next方法的参数表示上一个yield表达式的返回值,因此在第一次使用next方法时,传递参数是无效的
Generator.prototype.throw()
- Generator函数返回的遍历器对象,都有一个throw方法,能够在函数体外抛出错误,而后在Generator函数体内捕获
- throw方法能够接受一个参数,该参数会被catch语句接收,建议抛出Error对象的实例
- 一旦Generator执行过程当中抛出错误,且没有被内部捕获,就不会再执行下去了,Generator函数默认结束
Generator.prototype.return()
- 调用return方法后会终结Generator函数,返回值的value属性就是return方法的参数,没有即为undefined
- 若是Generator函数内部有try...finally代码块,那么return方法会推迟到finally代码块执行完再执行
yield* 表达式
- yield* obj,若是obj是遍历器对象,将会遍历该对象的yield,增长步长
- 任何数据结构只要有Iterator接口,就能够被yield*遍历
Generator函数的异步应用
- Generator函数将异步操做表示得很简洁,可是流程管理却不方便
- 解决方案
- Thunk函数
- a.js版本的Thunk函数方案是将多参数函数转换为单参数函数版本
- b.可引入node模块,也能够本身书写,用于管理Generator函数流程
- co模块
- a.js版本的co函数方案是对promise的包装
async函数
- Generator函数的语法糖
- 改进特色
- a.内置执行器 ——自动执行完,无需写thunk和co自执行方案
- b.更好的语义
- c.更广的适用性 ——异步等待执行,同步直接执行
- d.返回promise ——可用then方法指定下一步操做
- 基本语法
- a.async函数返回一个Promise对象,可使用then方法添加回调函数
- b.async函数的return值会成为返回的Promise对象的值,then方法的参数
- c.遇到await就会等待异步/同步操做完成,而后接着执行函数体
- d.await命令后是一个Promise对象,若是不是则会被转成一个当即resolve的Promise对象
- 错误处理
- a.async函数内抛出错误,会致使返回的promise对象变为reject状态
- b.只要一个await语句后面的Promise变为reject,那么整个async函数都会中断执行,错误信息会传入catch方法
- c.若是异步操做失败,却不但愿中断后续异步操做,方法有:
- 1).使用try...catch语句,将await放入try,catch捕捉后会继续执行后续代码
- 2).对await后的promise对象增添catch方法进行错误捕捉,而后程序会继续执行后续代码
- 异步遍历器(提案)
- a.异步遍历器的最大的语法特色就是,用遍历器的next方法,能返回一个Promise对象
- b.对象的异步遍历器接口,部署在Symbol.asyncIterator属性上面
- c.next方法能够连续调用,没必要等到上一步Promise对象resolve之后再调用;next方法会累积起来,自动按照每一步的顺序运行下去
- for await...of(提案)
- a.for await...of循环的一个用途,是部署了asyncIterable操做的异步接口,能够直接放入这个循环
- b.for...of自动调用遍历器的next方法,获得一个Promise对象;await用来处理这个Promise对象,一旦resolve,就把获得的值传入循环体
- c.for await...of循环也能够用于同步遍历器
- 异步Generator函数(提案)
- a.async函数与Generator函数的结合,await后面的操做会返回Promise对象
- b.普通的async函数返回的是一个Promise对象,而异步Generator函数返回的是一个异步Iterator对象,经过调用next方法来返回可操做的Promise对象
- c.yield *后面一样能够继续跟异步Generator函数
Class
Class基本语法
- 类的数据类型就是函数,类自己指向构造函数
- 类内部全部定义的方法都是不可枚举的
- 类自己和内部的属性方法能够采用变量来声明和表示
- 不使用new的类调用会报错
- 当constructor未被显示添加,空的constructor会被默认添加
- class声明不存在变量提高
- 采用class表达式,能够写出当即执行的class
- 类和模块的内部,默认就是严格模式
- class的get和set函数也定义在原型上
Class的静态方法
- 父类的静态方法,能够被子类继承——子类调用父类静态方法
- 子类也能够经过super,在静态方法中调用父类的静态方法
Class的静态属性和实例属性
[es6用法]
// 实例属性
class MyClass {
constructor() {
this.myProp=42;
}
}
// 静态属性
MyClass.属性=值;
[es7提案]
// 实例属性——实例能够取到
class MyClass {
myProp=42;
constructor() {
console.log(this.myProp); // 42
}
}
// 静态属性
class MyClass {
static myProp=42;
constructor() {
console.log(MyClass.myProp); // 42
}
}
class的私有属性
new.target属性
- 返回new命令做用的那个构造函数,若是是class内部调用则返回当前class
- new.target只适用于构造函数或class内部的constructor方法
- 若是构造函数不是经过new命令调用的,则new.target会返回undefined
- 能够用来肯定构造函数是怎么调用的,也能够用其作不可实例化的抽象类
Class的继承
Class继承
- 基本用法
- 1.存在继承关系后,constructor内必须执行super()操做,不然会报无this的错误
- 2.子类实例的构建是基于对父类实例加工,super()至关于对子类进行父类.call(this)
- 3.super返回父类实例后,植入子类原型属性和constructor,而后再接入到子类原型上
- super关键字
- 1.super用做函数时,必须用在constructor以内,不然会报错
- 2.super用做对象时,在普通方法中指向父类原型对象,在静态方法中指向父类
- 3.经过super调用父类的方法时,至关于父级原型调用该方法,可是super会绑定子类的this
- 4.经过super对某个属性赋值时,由于super绑定了子类的this,于是会赋值到子类属性上,可是调用时依然会在父级原型查找
- 5.super并非动态绑定的,而是在声明时“静态”绑定的
- 原生构造函数的继承
- 1.es5以前原生构造函数没法用this去绑定,致使拿不到其内部实例属性,没法实现真正继承
- 2.es6经过extends继承能够自定义原生数据结构,实现子类的真正继承和拓展能力
3.super传参对Object原生类型无效,es6规定Object构造函数会忽略参数
Decorator
基本语法
- 书写上,置于要修改的类和方法之上
- 只能用于类和类的方法,不能用于函数,由于存在函数提高
- 无论是修饰类仍是修饰方法,都支持多个修饰器
- 修饰器对行为的改变,发生在编译器,而不是运行时,其本质是编译时执行函数
类的修饰
- 当用于修饰类的时候,它的第一个参数表明所要修饰的目标类
方法的修饰
- 修饰器不只能够修饰类,还能够修饰类的方法
- 修饰方法的时候,接受三个参数(target, name, descriptor)
- 当多个修饰器一块儿用时,遵循先从外到内进入,而后由内向外执行
Module的语法
export命令
- export命令规定的是对外的接口,所以必须与模块内部的变量创建一一对应关系
export { 变量名 }
- export语句输出的接口,与其对应的值是动态绑定关系,即经过该接口,能够取到模块内部实时的值一必定时器动态改变值的状况
- export命令能够出如今模块的任何位置,只要处于模块顶层就能够,若是处于块级做用域内就会报错一一import命令一样如此
import命令
- import命令具备提高效果,会提高到整个模块的头部首先执行,由于import命令是属于编译阶段执行
- 因为import是静态执行,因此不能使用表达式和变量这些只有在运行时才能获得结果的语法结构
- import语句会执行所加载的模块,所以能够有以下的写法
import 'a';
import '1';
- 屡次重复执行同一句import语句,那么只会执行一次,而不会执行屡次
import { foo } from 'my_module';
import { bar } from 'my_module';
模块的总体加载
import * as 模块名 from './文件名';
export default命令
- 为模块指定默认输出时,import命令能够为模块指定任意名字,且不须要用{}括号包起来
- 模块内部的声明函数在外部是无效的,加载的时候视同为匿名函数进行加载
- 一个模块只能有一个默认输出
- export default本质上就是一个叫作default的变量或方法,所以能够用as语句进行更名
var a = 1; export default a;
——将变量a的值赋给变量default,所以export default 1
也是能够的
- 同时输入默认方法和其余变量
import abc,{ each } from 'lodash'
export与import的复合写法
若是在一个模块之中,先输入后输出同一个模块,import语句能够与export语句写在一块儿es6
export { foo, bar } from 'my_module';
//等同于
import { foo, bar } from 'my_module';
export { foo, bar };
export * from 'my_module'; ——会忽略my_module模块的default
export { default } from 'foo';
export { foo as myFoo } from 'my_module';
export { es6 as default } from './someModule';
export { default as es6 } from './someModule';
import()提案
- 属于运行时执行的动态加载,区别于import的静态加载
- import()函数能够用在任何地方,不只仅是模块,非模块的脚本也可使用
- import()函数与所加载的模块没有静态链接关系,这点也是与import语句不相同
- import()相似于Node的require方法,区别主要是前者是异步加载,后者是同步加载
- import()返回一个Promise对象,并容许模块路径动态生成——import(f()).then(...)
Module的加载实现
游览器加载
- script标签中defer和async的区别——defer是渲染完再执行,async是下载完就执行——即不能保证执行顺序
- 浏览器加载ES6模块也使用
<script>
标签,但要加入type="module"属性,效果等同于defer
- a.代码运行在模块做用域,顶层变量对外不可见
- b.默认采用严格模式,无论有无"use strict"
- c.模块之中,import和export指令对应模块时,.js后缀不能省略
- d.模块顶层this为undefined
es6模块与commonjs模块的差别
- commonjs模块输出的是一个值的拷贝,es6模块输出的是值的引用
- commonjs模块是运行时加载,es6模块是编译时输出接口
- commonjs顶层this指向当前模块,es6顶层this指向undefined
- es6模块是动态引用,不会缓存值,模块里面的变量绑定其所在的模块,意味着能够获取模块的动态变化
- es6输入的模块变量,只是一个“符号链接”,属于只读的,对它进行从新赋值会报错
- export经过接口输出的是同一个值,所以不一样的脚本加载这个接口,获得的都是一样的实例
node加载
- node中采用两套方案进行加载,es6模块和commonjs采用各自的加载方案
- 若是不输出任何接口,但但愿被node认为是es6模块,能够在脚本中写"export {}"
import加载commonjs模块
- import加载commonjs模块,node会自动将module.exports属性看成模块的默认输出,即等同于export default
- import加载commonjs模块时,commonjs模块的输出缓存机制依然有效,被引入模块内部的变化不会更新到引入模块
- import {readfile} from 'fs'报错
缘由——fs是commonjs格式,只有在运行时才能肯定readfile接口,而import命令要求编译时就肯定这个接口
解决办法——改成总体输入
require加载es6模块
- 采用require命令加载es6模块时,es6模块的全部输出接口会成为输入对象的属性
- require加载es6模块依然存在缓存机制,被引入模块内部的变化不会更新到引入模块
循环加载·commonjs
- commonjs的重要特性就是加载时执行,即脚本代码在require的时候就会执行,而后在内存生成一个对象
- commonjs模块不管加载多少次,都只会在第一次加载时运行一次,之后再执行加载,都只会到缓存中取值,返回第一次运行结果
循环加载·es6
- es6模块是动态引用,若是使用import从一个模块加载变量(即import foo from 'foo'),那些变量不会被缓存,而是成为一个 指向被加载模块的引用,意味着能够取到值得变化