ES6
一、let和const命令
二、变量的解构赋值
三、字符串的扩展
四、数值的扩展
五、正则的扩展
六、数组的扩展
七、函数的扩展
八、对象的扩展
九、symbol
十、proxy和reflect
十一、二进制数组
十二、set和map数据结构
十三、iterator和for...of循环
十四、generator函数
十五、promise对象
十六、异步操作和async函数
十七、Class
十八、修饰器 (ES7 但babel支持)
十九、module
二十、编程风格[可参阅jscs.info]
一、let和const命令
1.1、let
{
let a = 10;
}
仅在代码块中使用有效;
不存在变量提升:需要在声明后使用;
暂时性死区:只要块级作用域内存在let,其变量便绑定了该区域,不受外部影响;
不允许重复声明:不允许相同作用域声明同一个变量;
1.2、块级作用域
由于不存在变量提升,块级作用域之间的元素互不影响。
1.3、const命令
声明常量,一旦声明,其值不能改变;
只有声明所在的块级作用域有效;
不存在变量提升,有暂时性死区;
对于对象、数组等指针型变量,不能改变的是指针,而非内部内容,如果需要防止内容的改变,使用object.freeze方法。
1.4、跨模块的常量
// constants.js 模块
export const A = 1;
export const B = 2;
export const C = 3;
// test1.js 模块
import * as constants from ‘./constants’;
console.log(constants.A);
// test2.js 模块
import {A, B} from ‘./constatns’;
console.log(A);
1.5 全局对象属性
window下,全局对象为window;nodejs环境下指的global对象。
ES6下,var、function命令声明的仍为全局变量;let、const、class命令不属于全局对象属性。
二、变量的解构赋值
2.1 数组的解构赋值
[a, b, c, d] = [1, 2, 3, 4],这种属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。
[head, …tail] = [1, 2, 3, 4] // head == 1; tail == [2, 3, 4]
如果解构不成功,则会赋值undefined
默认值:[x = 1, y] = [2, 3] or [x = f(), y] = [2, 3];如果默认值为表达式,仅在使用时,才会执行表达式。
2.2 对象的解构赋值
对象按照属性名取值,数组按照次序取值。
var {foo: baz, bar: tr} = {foo:’aaa’, bar: ‘bbb’};真正被复制的是baz,而非foo;
{x} = {x:1} //容易出错,一般会解析成代码块,最佳方式:({x}={x:1})
2.3 字符串的解构赋值
const [a, b, c, d, e] = ‘hello’;// a=‘h’,b=‘e’…
let {length: len} = ‘hello’;// len = 5;
2.4 数值与布尔值的解构赋值
如果右边是数值或布尔值,会先转换成对象。
2.5 函数参数的解构赋值
undefined会触发函数参数的默认值。
[1, undefined, 3].map((x = ‘yes’) => x) // [1, ‘yes’, 3]
2.6 圆括号问题
解析结构是表达式还是模式不容易,所以不要在模式中放置圆括号。
2.7 用途
a、交换变量
b、函数返回多个值
c、函数参数的定义
d、提取json数据
e、函数参数的默认值
f、遍历map结构
三、字符串的扩展
ES6加强了对Unicode的支持,并且扩展了字符串对象。
javascript允许采用\uxxxx形式表示一个字符,其中xxxx表示字符的码点。
3.1 字符的Unicode表示法
3.2 codePointAt() 可以判断字符是否为4个字节,返回字符对应的码点
3.3 string.fromCodePoint() 参数为码点,可返回字符值
3.4 字符串的遍历器接口
for (let codePoint of ‘foo’) {
// ‘f’, ‘o’, ‘o’ 其可自动识别四个字节的字符
}
3.5 at() 可返回四个字节的字符(汉字) 等价两字节的charAt()。
3.6 normalize() 将字符的不同表示方法统一为同样的形式。
3.7 includes(), startsWith(), endsWidth() 表示是否找到参数字符串,返回布尔值
3.8 string.repeat(n) 表示将原字符串重复n次
3.9 padStart, padEnd,用来补全字符串
‘x’.padStart(5, ‘ab’) //ababx 接受两个参数,第一个为总长,第二个为重复的字符。
3.10 模板字符串
使用反引号标识,嵌入变量${}
$(‘#result’).append(’there are <b>${count}</b>items.’);
3.11 模板编译
3.12 标签模板
可使用其嵌入其他语言,如jsx。
函数调用的一种特殊形式,标签指函数,紧跟其后的模版字符串是参数。
tag`hello ${a + b} world ${a * b}` => function tag([‘hello’, ‘ world’, ‘’], 15, 50)
3.13 string.raw() 充当模板字符串的处理函数,返回一个反斜线都被转移的字符串。
四、正则的扩展
4.1 RegExp构造函数 new RegExp(/abc/ig, ‘i’).flag // ‘i’
4.2 将四个正则方法:match、replace、search、split四个方法都定义在了RegExp的对象上
4.3 u修饰符 为正则添加了u修饰符,含义为’unicode模式’
a、点字符 .表示任意字符,对于四字节字符,无法匹配,配合修饰符u,可正确判断。
b、unicode字符表示法 新增了大括号表示Unicode字符 /u{61}/u.test(‘a’)
c、量词 /接{2}/u.test('接’) //true
e、预定义模式/^\S$/u.test(‘接’) // true
f、i修饰符
4.4 y修饰符 ‘粘连’修饰符 与g功能相同,不同之处y默认带^,下一位置就必须能够匹配上。
4.5 sticky属性 表示是否设置了y修饰符 var r = /hello/y; r.sticky // true
4.6 flags属性 返回正则的修饰符
4.7 RegExp.escape() 还未通过审核
五、数值的扩展
5.1 二进制和八进制数值表示法
0b || 0B 为二进制; 0o || 0O表示八进制
5.2 Number.isFinite(), Number.isNaN() 分别用来检查 Infinite 和 NaN这两个特殊值。
传统的这两个方法,会先调用Number()转为数字,在判断;而新方法不转换,直接判断。
5.3 Number.parseInt(), Number.parseFloat() 其行为不变,只是移植到了Number对象上。
5.4 Number.isInteger()用来判断是否为整数,3和3.0视为同一值。
5.5 Number.EPSILON 一个极小的常量,为了减小浮点数相减的误差而设,如果误差小于这个常量,则正确。
5.5545656563e-17 < Number.EPSILON
5.6 安全整数和Number.isSafeInteger()
ES6提供了两个常量,Number.MAX_SAFE_INTEGER和Number.MIN_SAFE_INTEGER
5.7 Math对象的扩展
增加了17个与数学相关的方法。
a、Math.trunc() 去除数字的小数部分,返回整数部分。
b、Math.sign() 判断一个数是正数、负数还是零,+1正数;-1负数;+0; -0; NaN
c、Math.cbrt() 计算一个数的立方根
d、Math.clz32() 返回一个32位无符号整数形式(使用二进制表示的)有多少个前导0
e、Math.imul() 返回两个数以32位带符号整数相乘的结果
f、Math.fround() 返回一个数的单精度浮点数形式
g、Math.hypot() 返回所有参数的平方和的平方根
对数方法:
h、Math.epm1(x) 返回e^x-1
i、Math.log1p(x) 返回 1/ln(1+x)
j、Math.log10(x) 返回10为底的x的对数 Math.log10(10000) //4
k、Math.log2(x) 返回以2为底x的对数
三角函数方法:
l、Math.sinh(x) 返回x的双曲正弦
m、Math.cosh(x) 返回x的双曲余弦
n、Math.tanh(x) 返回x的双曲正切
o、Math.asinh(x) 返回x的反双曲正弦
p、Math.acosh(x) 返回x的反双曲余弦
q、Math.atanh(x) 返回x的反双曲正切
5.8 指数运算符 **
2 ** 3 = 8
六、数组的扩展
6.1、Array.from() 将两类对象转换成真正的数组:类数组的对象及可遍历的对象(即必须有length属性)
如dom操作的nodeloost集合、函数内部arguments对象及ES6的Set和Map方法
document.querySelectorAll(‘p’)
tips: 运算符...也可将某些结构转换成数组;from能正确的识别unicode字符
Array.from(spans, s => s.textContent);其转换数组的同时,具备map的功能。
6.2、Array.of()
用于将一组值转换为数组。Array.of(3, 11, 8) // [3, 11, 8]
6.3、copyWithin(target, start = 0, end = this.length)
将数组内部指定位置的成员复制到其他位置上
6.4、find()和findIndex()
find找出第一个符合条件的数组成员,返回成员或者undefined
[1, 4, -5, 10].find((n) => n<0) //-5
findIndex()与上同,返回成员位置,否则返回-1
6.5、fill(x, start, end)
填充数组[‘a’, ‘b’].fill(7, 1, 2) // [‘a', 7]
6.6、 entries()、keys()、values()
用于遍历数组,返回一个遍历器对象,可用for..of遍历
entries为遍历键值对;keys为遍历键值;values为遍历值
for (let [index, elem] of [‘a’, ‘b’].entries()) // 0 ‘a’
6.7、includes(x, start, end)
返回一个布尔值,表示某个数组是否包含给定的值
6.8、数组的空位
[, , ,]空位不代表undefined
ES5对空位的处理不一致,而ES6进行统一,将空位都转换为undefined,空位不会被忽略掉。尽量避免空位出现。
6.9、数组推导
var a1 = [1, 2, 3,4];
var a2 = [for (i of a1) i* 2]; //[2, 4, 6, 8]
var a3 = [for (i of a1) if (i > 2) i]; //[3, 4]
其可替代map()及filter()方法
七、函数的扩展
7.1、函数参数的默认值
function log(x, y = ‘hello’){}
a、参数的解构赋值:重点区分参数的默认值与解构赋值的默认值。
b、默认参数:非显示的输入undefined,触发该参数等于默认值,null没有这个效果。
c、length属性:指定默认值的参数,不计入length,导致length失真。
d、作用域:当前函数作用域与全局作用域
try catch err throw
7.2、rest参数 “…变量名”
rest参数搭配的变量是一个数组,将多余的参数放入其中;rest参数之后不能再有参数。
7.3、扩展运算符
‘…’,将一个数组转为用逗号分隔的参数序列。
a、替代apply()
b、合并数组:[1, 2, …more]
c、与解构赋值结合:[1, 2, …rest] = list;
tips:扩展运算符用于数组赋值时,只能放在末尾。
d、字符串:[…’hello’] //[‘h’, ‘e’, ‘l’, ‘l’, ‘o’]
可正确返回字符的长度(可识别unicode字符);[...string].length
e、类数组对象:可转变成数组.
7.4、name属性
function foo(){} foo.name // “foo"
7.5、箭头函数
使用箭头定义函数;
a、var f = v => v; 等同于 var f = function(v) {return v};
b、函数不需要参数或者需要多个参数,就用()代替:
var f = () => v; 等同于 var f = function(a, b) {…… return v};
c、由于大括号被解析成代码块,如果需要返回对象,需要加上括号:
var fun = id => ({id: id, name: ‘hity’});
d、如果代码块多余一条语句,就需要用大括号包起来。
e、嵌套箭头函数
tips:
a、函数体内的this,是定义时的对象,而非运行时;
b、不可当构造函数;
c、arguments对象不存在,可用rest参数代替;
d、不可使用yield命令,无法用作generator函数;
e、箭头函数无自己的this作用域,this指向父级this;所以无法使用apply、call、bind改变this指向
f、无arguments、super、new.target;
7.6、函数绑定
‘::’可以将左边对象作为上下文绑定到右边的函数上。可以采用链式的写法,返回的还是原对象。
7.7、尾调用优化
概念:指某个函数的最后一步是调用另外一个函数:function f(x){ return g(x);}
尾调用优化,去掉外层的调用帧。
tips:仅当内部函数不需要使用外部函数的变量时,优化才会进行。
尾递归:递归非常消耗内存,将其转变为尾递归将只有o(1)的复杂度。
tips:尾递归仅严格模式下可用:“use strict”,这种情况下函数的信息都将移除~
八、对象的扩展
8.1、属性的简洁表示法
{x, y} == {x: x, y: y};
var obj = {
birth,
method() {
return ‘hello';
}
}
8.2、属性名表达式
let obj = {
[prop]: true,
[‘a’ + ‘b’]: 123
}
8.3、方法的name属性
(new Function()).name //anonymous
bind创造的方法,name属性返回“bound”加原函数名。
8.4、Object.is()
比较两个值是否严格相等。与 === 基本一致。(+0, -0)//false (NaN, NaN)// true
8.5、Object.assign(targetObj, srcObj)
作用:将srcObj的所有可枚举对象复制到targetObj上;其只复制自身属性,不可枚举的和继承的不会被复制。
8.6、属性的可枚举性
object.getOwnPropertyDescriptor(obj, ‘foo’);
// {value: 123, writable: true, enumerable: true, configurable: true}
有三个操作会忽略enumerable为false的属性:
a、for…in:遍历自身和继承的可枚举属性;
b、Object.keys():返回对象自身的可枚举属性键名;
c、JSON.stringify():串行化对象自身的可枚举属性;
d、Object.assign():复制自身可枚举的属性;
e、Reflect.enumerate():返回所有for...in循环会遍历的属性
tips:所有Class的原型的方法都不可枚举。
8.7、属性的遍历
ES6共6种方法遍历对象的属性:
for…in:(无symbol)
Object.keys():(无symbol)
Object.getOwnPropertyNames(obj):返回数组,包含对象自身所有属性(无symbol)
Object.getOwnPropertySymbols(obj):返回数组,包含对象自身的所有symbol属性
Reflect.ownKeys(obj):返回数组,包含对象自身所有的属性
Reflect.enumerate(obj):返回一个Iterator对象,遍历对象自身和继承所有可枚举属性(无symbol)
8.8、__proto__属性、Object.setPrototypeOf()、Object.getPrototypeOf()
__proto__属性用来设置、读取当前对象的prototype对象;但最好不用,而是使用object.setPrototypeOf(object,
prototype)、object.getPrototypeOf()、object.create()代替。
8.9、对象的扩展运算符
rest亦可用于对象,使用方法相同。
tips:
a、其为浅复制,如果一个键的值为复合类型,则复制这个值的引用。
b、不能复制继承自原型对象的属性。
c、rest对象中存在取值函数get,这个函数会立即执行。
九、symbol
9.1、概述
引入的原因:解决扩展他人对象属性时的命名冲突。
javascript的第7种数据类型为:symbol,属性名属于symbol就是独一无二的。
tips:symbol值不能与其他值运算,它不能添加属性,类似字符串。
symbol值可转为字符串、布尔值;
9.2、作为属性名的symbol
a {[mySymbol]: ‘hello’}
9.3、消除魔术字符串
指在代码之中多次出现、与代码形成强耦合的某一个具体的字符串或者数字。
9.4、属性名的遍历
可以设置一些非私有又希望仅内部使用的方法。
9.5、symbol.for(), symbol.keyFor()
symbol.for(name):查找对应的symbol,查到则返回,并登记在全局中,否则创建一个新的symbol。
symbol.keyFor(s1):返回已登记的symbol key(即name)。
9.6、内置的symbol值
十、Proxy和Reflect
proxy代理,可以理解成目标对象前架设一“拦截”层,外界访问必须先通过该拦截。
new Proxy(target, handle);
10.1、实例方法
a、get():用于拦截某个属性的读取操作;
b、set():用于拦截某个属性的赋值操作;
c、apply(): 用于拦截函数的调用、call和apply操作;
d、has(): 用于隐藏某些操作,不被in操作符发现;
e、construct(): 用于拦截new命令;
f、deleteProperty: 用于拦截delete操作,使得属性不被delete;
g、defineProperty:用于拦截object.defineProperty(添加新属性)操作;
h、enumerate():用于拦截for...in循环;
i、getOwnPropertyDescriptor():用于拦截object.getOwnPropertyDescriptor;
j、getPrototypeof():用于拦截其运算,以及其他一些操作;
k、isExtensible():用于拦截其操作;[如果对象是可扩展的(这表示可向对象添加新属性),则为 true;否则为 false。]
l、ownKeys():用于拦截object.keys操作;
m、preventExtensions():用于拦截其操作,必须返回布尔值;
n、setPrototypeOf():用于拦截其方法。
10.2、proxy.revocable()
返回一个可取消的proxy实例。
10.3、reflect概述
其设计目的:
a、将object上明显属于语法层面的方法放到reflect上;
b、修改某些object的返回结果,让其变得更合理;
c、让object操作都变成函数行为;
d、reflect对象的方法与proxy对象的方法一一对应,这样可以直接让proxy对象调用reflect对象完成默认行为。
十一、二进制数组(大略的过,需要理解内存之类的计算机原理等)
设计目的:为了让开发者能够通过javascript与操作系统的原生接口进行二进制通信。
二进制数组分三类:
a、arrayBuffer对象:代表原始的二进制数据;
b、typedArray视图:用于读写简单类型的二进制数据;
c、dataView视图:用于读写复杂类型的二进制数据。
typedArray有九种类型数据:int8、uint8、uint8C、int16、uint16、int32、uint32、float32、float64
dataView有除uint8C外的八种数据类型。
API用到了二进制数组操作二进制数据的有一下浏览器:
File API、XMLHttpRequest、Fetch API、Canvas、WebSocket
11.1、arrayBuffer对象
var buf = new ArrayBuffer(32);
arrayBuffer.prototype.byteLenth:由于分配内存的操作不一定成功,所以需要通过该字段来判断是否成功;
arrayBuffer.prototype.slice():允许将内存区域的一部分复制生成一个新的arrayBuffer对象;
arrayBuffer.isView():返回布尔值,表示参数是否为arrayBuffer的一个试图实例。
11.2、typedArray视图
其有九个构造函数,对应不同的数据类型;
形成的数组成员都是一种类型;
成员都是连续的,不会有空位;
默认值为0。
11.3、dataView视图
11.4、二进制数组的应用
a、ajax 返回的类型可以为二进制,设置为arraybuffer or blob;
b、canvas 类型值为uint8clampedarray
c、websocket 通过arraybuffer发送或者接收二进制数据;
d、fetch API 取回的数据为arrayBuffer对象;
e、file API 如果知道文件为二进制数据类型,也可以将其读取为arrayBuffer对象。
十二、set和map数据结构
12.1、set
set是一种新的数据结构,其与数组的区别是,没有重复值,成员值都唯一。set本身为构造函数。
set接受一个数组作为参数,var set =new Set([1, 2, 3, 4, 4]); // [1, 2, 3, 4]。
set加入的值,不会进行类型转换,判断相等使用的是 ===。
set实例的属性和方法:
set.prototype.size: 返回set成员的总数;
add(value): 添加某个值,返回set结构本身;
delete(value):删除某个值,返回一个布尔值;
has(value): 返回一个布尔值;
clear():清除所有成员,没有返回值。
遍历方法:keys()、values()、entries()、forEach()
12.2、weakSet
为不重复的值的集合,与set的区别:
a、其成员只能是对象;
b、其对象为弱对象,垃圾回收机制不考虑它的引用,因此,它是不可遍历的。
方法:add()、delete()、has();
其用处为:储存DOM节点,而不用担心这个节点从文档中移除时会发生内存泄漏。
12.3、map
map类似对象,区别在于键不同,对象的键限制只允许字符串,map的键不受限:
对象为“字符串-值”的对应,map为“值-值”的对应。
需要堤防一种情况,键为引用地址的情况:如
map.set([‘a’], 123);
map.get([‘a’]); // undefined
由于数组作为键时,标记的是数组所在的引用地址。
var k1 = [‘a’];
map.set(k1, 1234);
map.get(k1) // 1234
map的键是跟内存绑在一起的,只要内存地址不一样,就视为两个键。如此解决了同名属性碰撞的问题。
map的属性和方法:
size属性:返回成员总数;
set(key, value):设置键值,并返回整个map的结构;
get(key):读取key对应的值,找不到则返回undefined;
has(key):返回布尔值,确认键是否存在;
delete(key):删除某个键,返回布尔值;
clear():清除所有成员,没有返回值。
遍历方法:keys()、values()、entries()、forEach()。
可使用运算符(...)转换成数组。
转换:
a、map转数组(…)
b、数组转map;
c、map转对象;
d、对象转为map;
e、map转为son(键名为字符串);
f、json转为map(键名为字符串)。
12.4、weakmap
weakmap与map类似,但其只接受对象作为键名,键名指向的对象不计入垃圾回收机制。其有助于内存泄漏。
十三、iterator和for...of循环
iterator接口为各种不同的数据提供统一的访问机制。只要部署iterator接口,就可完成遍历操作。
作用:
a、为各种数据结构提供统一的、简便的访问接口;
b、使得数据结构的成员能够按照某种次序排列;
c、es6创造了一种新的遍历命令for...of循环,iterator接口主要供其消费。
遍历过程:
step1、创建指针对象,指向当前数据结构的起始位置;
step2、第一次调用指针对象的next方法,指向第一个成员;
step3、第二次调用next方法,指向第二个成员;
step4、不断调用,直到结束。
step2时,会返回数据结构当前的成员信息;具体是返回一个包含value和done的对象,value为成员值,done为布尔值,表示遍历是否结束。
iterator接口需要通过symbol.iterator来部署。
13.3、调用iterator接口的场合
解构赋值、扩展运算符、其他场合:for...of、array.from()、map()、set()、weakmap()、weakest()、promise.all()、promise.race()。
13.4、字符串的iterator接口
var string = “lala”;
var iterator = string[Symbol.iterator]();
修改遍历器对象。
13.5、iterator接口与generator函数
Symbol.iterator方法最简单的实现还是generator函数。
13.6、遍历器对象的return()、throw()
next方法是必须部署的方法,return方法用于for...of循环提前退出时(break、continue或者出错),调用。return方法必须返回一个对象。throw方法配合generator使用。
13.7、for...of循环
一个数据结构只要部署了Symbol.iterator属性,就可以用for...of循环遍历其成员。
for… in、for…of
数组、set、类数组对象[string]:for (let v of arr)
map:for (var [name, value] of es6)
十四、generator函数
14.1、简介
基本概念:Generator函数为ES6提供的一种异步编程解决方案,语法行为与传统函数完全不同。
Generator是状态机,也是遍历器对象生成器,返回一个遍历器对象。它的两个特征:a、function命令与函数名之间有一个星号;b、内部使用yield定义内部状态。最大特点,暂缓执行函数;通过next做暂缓和停顿。
其调用后,不执行,而是返回一个iterator对象,需用next方法调用,才执行。
yield语句无法用在普通函数中,否则出错;且用于表达式中时,需要放在圆括号内。
14.2、next方法的参数
next方法的参数为yield的执行结果,可向函数体内注入值。
yield返回值通常为undefined;如果next带有参数,则返回该参数。next传递的参数往往为上一次yield的返回值。
14.3、for…of循环
14.4、Generator.prototype.throw(),可在函数体外抛出错误,函数体内执行。
14.5、Generator.prototype.return()
可返回给定的值,并终结Generator函数的遍历。
g.return(“foo”) //{value: “foo”, done:true}
如果函数内部有try...finally代码块,那么return方法会推迟到finally代码执行完再执行。
14.6、yield语句
如果Generator函数内部调用另一个Generator函数,默认情况下无效;使用yield*,则生效。yield*表示在函数内部部署了一个for...of循环。
14.7、作为对象属性的Generator函数
let obj = {
* myGeneratorMethod() {}
}
14.8、Generator函数的this
构造函数返回的是一个内部的指针,可通过bind一个对象,赋予作用域,将this绑定在对象上。
14.9、Generator函数推导
let squard = (for (n of generator()) n * n);
14.10、含义
Generator与状态机,其本身包含状态机,不需要额外的外部变量保存状态。
14.11、应用
a、异步操作的同步表达
function* main() {
var result = yield request(url);
var resp = JSON.parse(result);
}
function request(url) {
makeAjaxCall(url, function(response) {
it.next(response);
});
}
var it = main();
it.next();
b、控制流管理
c、部署iterator接口
利用Generator函数可以在任意对象上部署Iterator接口。
d、作为数据结构
其可以返回一系列的值。
十五、promise对象
15.1、promise的含义
所谓promise就是一个对象,用来传递异步操作的消息。其有两个特点:
a、其状态不受外界影响;其有三种状态:pending(进行中)、resolved (已完成,又称”fulfilled”)、rejected(已失败);
b、一旦状态改变就不会再变,任何时候都可以得到这个结果;
有了promise对象就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调。
缺点:
无法取消promise;如果不设置回调,promise内部抛出的错误不会反应到外部;一般说来,如果事件不断发生,使用stream模式比部署promise更好。
15.2、基本用法
两个异步之间的调用:
var p1 = new Promise(function (resolve, reject){})
var p2 = new Promise(function (resolve, reject){
resolve(p1);
})
p2的状态为(p1 与 p2)的并集。只要一个为rejected,则为rejected;全部为resolved则为resolved。
15.3、Promise.prototype.then()
then方法返回一个promise实例(并非前一个实例),此时可以链式的调用then。
15.4、Promise.prototype.catch()
其是.then(null, rejection)的别名,用于指定发生错误的回调函数;promise在resolve后再抛出错误,并不会被捕获。
promise的错误具有“冒泡”性质,会一直向后传递,直到捕获为止。最好不在then的第二个参数定义rejected状态的回调,而应使用catch方法。
catch方法也是返回一个promise实例。
15.5、promise.all()
promise.all方法用于将多个promise实例包装成一个新的promise实例。
var p = Promise.all([p1, p2, p3]);其参数必须具有iterator接口,且返回的每个成员都是Promise实例。
p的状态为:
a、三者都为resolved,则它为resolved;
b、只要一个为rejected,则它为rejected;此时第一个被rejected的实例的返回值会传递给回调函数。
15.6、promise.race()
亦是将多个promise实例包装成一个新的promise实例。只要其中有一个实例改变状态,p的状态也跟着改变。
15.7、promise.resolve()
其可将现有对象转为promise对象;
promise.resolve(‘foo’) 等价于 new Promise(resolve => resolve('foo’));
15.8、promise.reject()
返回一个promise的实例,状态为rejected。
15.9、两个附加方法
done():为了最终捕获任何可能出现的错误;
finally():指定不管promise对象最后状态如何都会执行的操作。
15.10、应用
a、加载图片
b、Generator与Promise(管理 流程+异步 混合操作)
15.11、async函数(亦是用于取代回调函数解决异步操作)
十六、异步操作和async函数
在ES6诞生前,异步编程的方法大概有4种:
a、回调函数;
b、事件监听;
c、发布、订阅;
d、promise对象。
16.1、Generator函数
协程,类似线程,执行到一半转移执行权。yield命令将执行权交给其他协程。
其数据交换及错误处理:next(x);try{}catch{}.
fetch返回promise对象。
16.2、thunk函数(结合generator函数进行自动流程管理)
编译器的“传名调用”,将参数放到一个临时函数中,再将临时函数传入函数体内。这个临时函数就叫thunk函数。
16.3、co模块
co模块用于Generator函数的自动执行。
var co = require(‘co’);
co(gen);
co(gen).then(function() {
console.log(‘generator函数执行完毕');
});
如何交回generator的执行权:
a、回调函数。将异步包装成thunk函数,在回调函数中交回执行权。
b、promise对象。将异步操作包装成promise对象,用then 方法交回执行权。
co模块是将两种自动执行器包装成了一个模块,使用co的前提条件是,yield命令后面只能是thunk函数活着promise对象。
16.4、async函数(属于es7)
async函数:
a、内置执行器;
b、更好的语义;
c、更广的适应性,async函数的await命令后面可以使promise对象和原始类型值;
d、返回值为promise对象。
十七、Class
17.1、基本语法
定义类:
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return ‘(‘ + this.x + ‘, ‘ + this.y + ‘)’;
}
}
类的数据类型就是函数,类本身就指向构造函数。
类的内部定义的所有方法都是不可枚举的。
不存在变量提升。
17.2、class的继承
class之间通过extends关键字实现继承;通过super方法,指向父类的this对象。
class ColorPoint extends Point {
constructor(x, y, color) {
super(x, y); //调用父类的constructor(x, y)
this.color = color;
}
}
es5的继承实质上是先创造子类的实例对象this,然后再将父类的方法添加到this上(parent.apply(this));
es6的继承实质上是先创建父类的实例对象this(调用super方法),然后再用子类的构造函数修改this。
类的prototype属性和__proto__属性:
a、子类的__proto__属性表示构造函数的继承,指向父类;
b、子类的prototype的__proto__属性表示方法的继承,指向父类的prototype属性。
extends的继承目标:
只要具有prototype属性,就能被继承。
object.getPrototypeOf()方法从子类上获取父类。
super关键字代表父类的实例。
17.3、原生构造函数的继承
es5无法继承,es6可以。
17.4、class的取值函数(getter)和存值函数(setter)
与es5一样,在class内部可以使用get和set关键字对某个属性设置存值函数和取值函数,拦截该属性的存取行为。
17.5、class的generator方法
class Foo {
constructor(…args) {
this.args = args;
}
*[Symbol.iterator]() {
for (let arg of this.args) {
yield arg;
}
}
}
for (let x of new Foo(‘hello’, ‘world’)) {
console.log(‘x');
}
// hello //world
17.6、class的静态方法
定义:在一个方法上加static关键字,就表示该方法不会被实例继承,而是直接通过类调用,成为“静态方法”。
通过使用extends,可以让实例继承。
17.7、class的静态属性
定义:指class本身的属性,而不是定义在实例对象(this)上的属性。
17.8、new.target属性
new是从构造函数生成实例的命令。该属性可以确定构造函数是怎么调用的。
function Person(name) {
if (new.target === Person) {
this.name = name;
} else {
throw new Error('必须使用new生成实例’);
}
}
var person = new Person(‘hit') //正确
var notAPerson = Person.call(person, ‘张三’); // 报错
17.9、mixin模式的实现
定义:将多个类的接口“混入”另一个类:
十八、修饰器 (ES7 但babel支持)
18.1、类的修饰器
@testable
class MyTestableClass {}
其中的@testable为修饰器,修改了类的行为,增加了一个静态属性。
18.2、方法的修饰
class Person {
@readonly
name() {
return `${this.first} ${this.last}`
}
}
修饰器函数共接受3个参数,修饰的目标对象;修饰的属性名;属性的描述对象。
function readonly(target, name, descriptor) {
descriptor.writable = false;
return descriptor;
}
Object.definePrototype(Person.prototype, ’name’, descriptor);
18.3、为何修饰器不能用于函数
修饰器职能用于类及类的方法,因为其存在函数提升。
18.4、core-decorators.js
其是一个第三方模块,提供了几个常见的修饰器。
a、@autobind 使得方法中的this对象绑定原始对象。
b、@readonly使得属性或者方法不可写;
c、@override检查子类方法是否正确覆盖父类的同名方法;
d、@deprecate在控制台显示一条警告,表示该方法将废除;
e、@suppressWarnings 修饰器抑制decorated修饰器导致的console.warn调用。
18.5、使用修饰器实现自动发布事件
“发布/订阅”库postal.js
18.6、mixin
在修饰器的基础上可以实现mixin模式,就是对象继承的一种替代方案,在对象中混入另一个对象的方法。
18.7、trait
效果与mixin类似,但提供更多的功能,比如防止同名方法的冲突、排除混入某些方法、为混入的方法起别名等。第三方模块:traits-decorator。
十九、module
ES6的class只是面向对象编程的语法汤,升级了ES5构造函数的原型链继承的写法,并没有解决模块化问题。
commonjs模块是对象,输入时必须查找对象属性,其实质是整体加载模块,然后使用方法,这种为“运行时加载”。
es6模块不是对象,而是通过export命令显示的制定输出的代码,输入时采用静态命令的形式。
import{ start, exists, readFile} from ‘fs’;
以上实质是从fs模块加载3个方法,其他方法不加载。这种加载称为“编译时加载”
效率比commonjs高。
ES6模块化的其他优点:
a、不再需要UMD模块格式;
b、将来浏览器的新API可以用模块格式提供,不再需要做成全局变量或者navigator对象的属性;
c、不再需要对象作为命名空间,未来这些功能可通过模块实现。
19.1、严格模式 [lottery插件完成后做详细了解]
模块化自动采用严格模式,限制如下:
a、变量必须声明后使用;
b、函数的参数不能有同名属性,否则报错;
c、不能使用with语句;
d、不能对只读属性赋值,负责报错;
e、不能使用前缀0表示八进制,否则报错;
f、不能删除不可删除的属性,否则报错;
g、不能删除变量(delete prop),会报错,职能删除属性(delete global[prop]);
h、eval不会再外层作用域引入变量;
i、eval和arguments不能被重新赋值;
j、arguments不会自动反映函数参数的变化;
k、不能使用arguments.callee;
l、不能使用arguments.caller;
m、禁止this指向全局变量;
n、不能使用fn.caller和fn.arguments获取函数调用的堆栈;
o、增加保留字段(protected、static和interface)。
19.2、export命令
模块功能主要由两个命令构成:export和import;export用于规定模块的对外接口;import命令用于输入其他模块提供的功能。
// profile.js
export { f1 as firstName, lastName, year};
19.3、import命令
import {firstName as f1, lastName, year} from ‘./profile’;
19.4、模块的整体加载
除了指定加载某个输出值,还可以使用整体加载,即用(*)指定一个对象,所有输出值都加载在这个对象上。
import * as circle from ‘./circle’。
19.5、module命令
module可取代import命令,达到整体输入模块的作用。
module circle from ‘./circle’。
19.6、export default命令
export default function() {};
import cc32 from ‘crc32’;
vs
export function cc32() {};
import {crc32} from ‘crc32’;
留意大括号的区别(“{}”)。
19.7、模块的继承
export * from ‘circle’
表示输出circle模块的所有属性和方法。
19.8、ES6模块加载的实质
ES6模块加载机制与commonjs模块完全不同。commons模块输出的是一个值的拷贝,而ES6模块输出的是值的引用。
19.9、循环加载
commonjs模块的加载原理:加载时执行,即代码在require 时就会全部执行;一旦出现“循环加载”,就只输出已经执行的部分,还未执行的部分不输出。
ES6模块是动态引用,遇到模块加载命令import时不会去执行模块,只是生成饮用,开发者自己保证取值时能够真正取到值。
19.10、ES6模块的转码
除babel可以转外,一下两种方法也可以:
a、ES6 module transpiler
b、systemJS
二十、编程风格[可参阅jscs.info]
20.1、块级作用域
let 取代 var;
全局常量和线程安全:建议使用const而非let;
20.2、字符串
一律使用单引号或者反引号;const b = `foo${a}bar`;
20.3、解构赋值
数组成员对变量赋值,优先解构赋值。
20.4、对象
a、单行定义的对象,最后一个成员不以逗号结尾。多行定义的对象需要。
b、对象尽量静态化,一旦定义,就不得随意添加新的属性。
const a = {x: null};
a.x = 3;
c、如果对象属性名是动态的,在创建时,使用属性表达式定义。
const obj = {
id: 5,
[getKey(‘enabled’)]: true
}
d、对象的属性和方法尽量采用简洁表达法,易于描述和书写:
const atom = {
ref, //ref: ref
addValue(value) {
return atom.value + value;
}
}
20.5、数组
使用扩展运算符(...)复制数组。
const itemsCopy = […list];
20.6、函数
a、立即执行函数使用箭头函数
(() => {
console.log(‘Welecome to the Internet.');
})();
b、使用函数表达式的场合,使用箭头函数
[1, 2, 3].map([x] => {
return x*x;
})
c、箭头函数代替Function.prototype.bind,不应再用self/_this/that绑定this.
const boundMethod = (…params) => method.apply(this, params);
d、简单的、单行的、不会复用的函数,建议采用箭头函数。
e、所有配置项都应该集中在一个对象,放在最后一个参数,布尔值不可以直接作为参数:
function divide(a, b, {option = false} = {})
f、不再函数体内使用arguments变量,使用(…)代替:
function all(…args) {
return args.join('');
}
g、默认值语法设置函数参数的默认值:
function handle(opts = {}){}
20.7、map结构
注意区分object和map,如果只是需要key:value的数据结构,则使用map。
20.8、class
a、用class取代需要prototype的操作。
b、使用extends实现继承
20.9、模块
a、module语法是javascript模块的标准写法,使用import取代require;
b、使用export取代module.exports;
c、export default不要与普通export同时使用;
d、不要再模块输入中使用通配符*;
20.10、eslint的使用
其是一个语法规则和代码风格检查工具,可以确保语法正确、风格统一。
摘自:http://www.cnblogs.com/hity-tt/p/6511019.html