Vue项目开发与规范--es6语法规范篇
2018-08-01 本文已影响1人
youins
目录
- 简介
- let const
- 解构赋值
- 正则的扩展
- 字符串的扩展
- 数值的扩展
- 数组的扩展
- 函数的扩展
- 对象的扩展
- Symbol
- set和map以及和数组对象的对比
- Proxy和Reflect
- Class
- Promise
- Iterator
- genertaor函数
- Decorator
简介
ECMAScript 6 简称 ES6,是 JavaScript 语言的下一代标准,已经在2015年6月正式发布了。它的目标是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。
ECMAScript 和 JavaScript 的关系:前者是后者的语法规格,后者是前者的一种实现.
let-const
作用域的概念
- 在es5中只有全局作用域和函数作用域
- 在es6中新增块作用域
如何使用let和const
直接看代码
- let
// 块作用域
for(let i=1; i<3; i++){
console.log(i) //1 2
}
console.log(i) // ReferenceError 这里为啥会报这个错误呢
1.let声明的是块作用域
2.这里找不到i应该报undefined的啊,因为在es6中强制使用严格模式,变量未定义直接引用就会报引用异常。也就是说自动使用了
'use strict'
// 不能重复定义
let a = 1
let a = 2 // 会报Duplicate declaration这个错误,因为let声明的变量不能重复定义
- const
- 也是块作用域和let一样
- 和let有一个区别,let可以声明的时候不赋值,但是const必须声明时赋值
// const定义常量,赋值以后不能改变
const PI = 3.14
PI = 1 //会报PI is read-only这个错误,因为const定义的不能修改
// 声明必须赋值
const a
a = 1 // 会报Unexpected token这个错,因为 const 定义的时候必须赋值
// 特殊的
const k = {a: 1}
k.b=2 //k={a:1,b:2} k是引用类型 返回值是指针,k的指针并没有变,所以不会报错
不存在变量提升,变量未声明使用会报错ReferenceError
解构赋值
分类
数组 对象 字符串 布尔值 函数参数 数值 的解构赋值,这主要说数值和对象的,其他的都差不多
- 数组的解构赋值
//最基本的写法
{
let a,b
[a,b] = [1,2]
console.log(a,b) // 1,2
}
// 加默认值
{
let a,b
[a,b,c=3] = [1,2]
console.log(a,b,c) // 1,2,3
}
// 使用场景
// 1. 变量的值交换
{
let a = 1
let b = 2
[a,b] = [b,a]
console.log(a,b) //2, 1
}
// 2. 从函数的返回值取值
{
function f(){
return [1,2]
}
let a,b
[a,b] = f()
console.log(a,b) // 1, 2
}
// 3. 从函数的返回值中取值,并且弄成我们想要的格式
{
function f(){
return [1,2,3,4,5]
}
let a,b,c
[a,,,b]=f()
console.log(a,b) //1,4
}
// 4. 同样,取我们想要的
{
function f(){
return [1,2,3,4,5]
}
let a,b,c
[a,...b]=f()
console.log(a,b) //1, [2,3,4,5]
}
// 5. 取我们想要的,意思就是乐意要啥就拿啥
{
let a,b,rest
[a,b,..rest] = [1,2,3,4,5]
console.log(a,b,rest) // 1, 2, [3,4,5]
}
- 对象的解构赋值
// 基本写法
{
let a,b
{{a,b} = {a:1,b:2}}
console.log(a,b) // 1, 2
}
{
let o = {a:1,q:true}
let {a,p} = o
console.log(a,q) //1,true
}
// 加默认值
{
let {a=10,b=1} = {a=1}
console.log(a,b) //1,1 ,默认值会被后面的值替换
}
// 使用场景
// 模拟后端接口,取我们想要的值
{
let data = {
title: 'a',
test:[{
title: 'b'
desc: 'desc'
}]
}
let {title:esTitle,test:[{title:cTitle}]} = data
console.log(esTitle,cTitle) // a ,b
}
最后 为啥都加了一个大括号呢,这样的目的是利用块作用域把变量隔离开,要不就报重复定义的错了
正则的扩展
新特性
构造函数的变化
方法的扩展
u y 修饰符
//构造函数的变化
{
// es5 RegExp的两种情况
//第一种情况,参数是字符串,这时第二个参数表示正则表达式的修饰符
let regex=new RegExp('xyz','i')
// 第二种情况,参数是一个正则表示式
let regex2= new RegExp(/xyz/i)
console.log(regex.test('xyz123')) // true
console.log(regex2.test('xyz123')) //true
// es6 构造函数第一个参数是一个正则对象,可以使用第二个参数指定修饰符
let regex3 = new RegExp(/xyz/ig,'i')
// ig会被覆盖
console.log(regex3.flags) // i
}
// y修饰符
// y修饰符于g类似都是全局搜索,g修饰符只要剩余位置中存在匹配就可,而y修饰符确保匹配必须从剩余的第一个位置开始
{
let s='aaa_a_a'
let a1=/b+/g
let a2=/b+/y
console.log('one',a1.exec(s)) //[aaa,inex:0,input:'aaa_a_a']
console.log('one',a2.exec(s)) //[aaa,inex:0,input:'aaa_a_a']
console.log('two',a1.exec(s)) //[a,inex:4,input:'aaa_a_a']
console.log('two',a2.exec(s)) // null
// sticky
console.log(a1.sticky) //false
console.log(a2.sticky) //true
}
// u修饰符
{
// 新增了使用大括号表示 Unicode,这种表示法在正则表达式中必须加上u修饰符,才能识别当中的大括号,否则会被解读为量词。
// u 修饰符 用于处理utf-16编码
console.log(/^\uD83D/.test('\uD83D\uDC2A')) // true
console.log(/^\uD83D/u.test('\uD83D\uDC2A')) // false
// \uD83D\uDC2A是一个四个字节的 UTF-16 编码,代表一个字符。但是,ES5 不支持四个字节的 UTF-16 编码,
// 会将其识别为两个字符,导致第一行行代码结果为true。加了u修饰符以后,ES6 就会识别其为一个字符,所以第二行代码结果为false
console.log(/\u{61}/.test('a')) // false
console.log(/\u{61}/u.test('a')) // true
// Unicode 字符表示法,可以正确识别超过两个字符的unicode代码
console.log(`\u{20BB7}`) // 吉
let s= '吉'
console.log(/^.$/.test(s)) // false
console.log(/^.$/u.test(s)) // true
console.log('test',/吉{2}/.test('吉吉')) // false
console.log('test-2',/吉{2}/u.test('吉吉')) // true
}
字符串的扩展
新增
Unicode表示法
遍历接口
新增方法
模板,便签字符串
- Unicode表示法
{
// es5的写法
console.log(`\u0061`) // a
consoel.log(`\u20BB7`) // 不正常显示 因为这个大于了 0xFFFF,超出这个必须用双字节形式表示
console.log(`\uD842\uDFB7`) // 𠮷
// es6的写法 用\u{}
console.log(`\u{20BB7}`) // 𠮷
}
//js内部,字符以UTF-16的格式储存,每个字符固定为2个字节。对于那些需要4个字节储存的字符(Unicode码大于0xFFFF的字符),js会认为它们是两个字符
{
let s = '𠮷'
// es5
console.log(s.length) // 2
console.log(s.charAt(0)) // 乱码
console.log(s.charAt(1)) //乱码
console.log(s.charCodeAt(0)) // 55362
console.log(s.charCodeAt(1)) // 57271
// es6
let s1 = '𠮷a'
console.log(s1.length) // 3
console.log(s1.codePointAt(0)) // 134071
console.log(s1.codePointAt(0).toString(16)) // 20bb7
console.log(s1.codePointAt(1)) // 57271
console.log(s1.codePointAt(2)) // 97
}
// ES5提供String.fromCharCode方法,用于从码点返回对应字符,但是这个方法不能识别32位的UTF-16字符(Unicode编号大于0xFFFF)
// ES6提供了String.fromCodePoint方法,可以识别大于0xFFFF的字符,在作用上,与codePointAt方法相反
{
//es5
console.log(String.fromCharCode('0x20bb7')) // 乱码
//es6
console.log(String.formCodePoint('0x20bb7')) // 𠮷
}
- 遍历接口
{
// es5
let str='\u{20bb7}abc'
for(let i =0;i<str.length;i++){
console.log(str[i]) // 乱码 乱码 a b c
}
// es6
for(let code of str){
console.log(code) // 𠮷 a b c for of 可以正确识别
}
}
- 新的常用方法
// includes startsWith endsWith
{
let str = 'string'
console.log(str.includes('r')) // true
console.log(str.startsWith('s')) // true
console.log(str.endsWith('g')) // true
}
// repeat
{
let str = 'abc'
console.log(str.repeat(2)) // abcabc
}
//忽略换行
{
console.log(String.raw`Hi\n${1+2}`) Hi\n3
console.log(S`Hi\n${1+2}`) // 换行
}
// padStart padEnd 这两个还处于草案阶段,要使用babel-polyfill进行编译
{
console.log('1',padStart(2.'0')) //01 第一个参数是长度,长度不够补0
console.log('1',padEnd(2.'0')) //10
}
- 便签,模板字符串,很好用
{
let name="dou";
let info="hello";
let m=`i am ${name},${info}`;
console.log(m); //i am dou, hello
}
{
let user={
name:'name',
info:'hello'
};
console.log(abc`i am ${user.name},${user.info}`);
function abc(s,v1,v2){
console.log(s,v1,v2);
return s+v1+v2
}
// i am ,,,dou hello
}
数值的扩展
新特性
二进制和八进制表示法
新增方法
- 二进制和八进制表示法
{
//二进制
console.log(0b111110111) //503
//八进制
console.log(0o767) //503
}
- 新增方法,常用的
{
// 检查是不是有限的 (-2^53,2^53)
console.log(Number.isFinite(1)) // true
console.log(Number.isFinite(NaN)) // false
console.log(Number.isFinite(1/0)) // false
// 检查是不是NaN
console.log(Number.isNaN(NaN)) // true
console.log(Number.isNaN(0)) // false
}
{
// 检查是不是整数
console.log(Number.isInteger(1)) //true
// 这要注意
console.log(Number.isInteger(1.0)) //true
console.log(Number.isInteger(1.1)) //false
console.log(Number.isInteger('1')) //false
}
{
// 最大和最小安全数值
console.log(Number.MAX_SAFE_INTEGER)
console.log(Number.MIN_SAFE_INTEGER)
console.log(Number.isSafeIntger(1)) //true
}
{
// 取整
console.log(Math.trunc(1.1)) //1
console.log(Math.trunc(1.9)) //1
//判断一个数到底是正数、负数、还是零
console.log(Math.sign(-2)) //-1
console.log(Math.sign(0)) // 0
console.log(Math.sign(2)) // 1
console.log(Math.sign('2')) // 1
console.log(Math.sign('aa')) // NaN
}
数组的扩展
新特性
Array.from
Array.of
copyeWithin
find/findIndex
fill
entries\keys\values
includes
直接看代码
{
// Array.of 将一组值,转换为数组
let arr = Array.of(1,2,3,4)
console.log(arr) [1,2,3,4]
let emptyArr = Array.of()
console.log(emptyArr) // []
//Array.from 把类数组转为数组
console.log(Array.from([1,2,3],function(item){
return item*2 // 2,4,6
}))
//fill填充 第二个和第三个参数,用于指定填充的起始位置和结束位置
console.log([1,'a',undefined].fill(1)) //[1,1,1]
console.log([a,b,c],fill(7,1,3)) // [a,7,7]
}
// key values entries
{
for(let i of [1,2,3].key()){
console.log(i) //0,1,2
}
//兼容
for(let v of [1,2,3].values()){
console.log(v) //1,2,3
}
for(let [i,v] of [1,2,3].entries()){
console.log(i,v) // 0 1 1 2 2 3
}
}
//copyWithin将指定位置的成员复制到其他位置,并返回新数组
{
console.log([1,2,3,4,5].copyWithin(0,3,4)) //[4,2,3,4,5]
}
//find findIndex 找出第一个符合条件的数组成员
{
console.log([1,2,3,4,5,6].find(function(item){
return item>3
})) // 4 只找一次
console.log([1,2,3,4,5,6].findIndex(function(item){
return item>3
})) // 3 只找一次
}
// includes 找数组里的值,可以找NaN
{
console.log([1,2,NaN].includes(1)) //true
console.log([1,2,NaN].includes(NaN)) //true
}
函数的扩展
新增
- 函数参数的默认值
- rest参数
- 箭头函数
- 尾调用
// 函数参数的默认值
{
function test(x, y = 'world'){
console.log('默认值',x,y);
}
test('hello'); // hello world
// 如果传的参数默认值会被替换
test('hello','dou'); //hello dou
// 注意这会带来一个作用域的问题
var x = 1;
function f(x, y = x) {
console.log(y);
}
f(2) // 2
// 设置默认值,会形成一个单独的作用域等到初始化结束,这个作用域就会消失
let x = 1;
function f(y = x) {
let x = 2;
console.log(y);
}
f() // 1
}
// rest参数
{
function test3(...arg){
for(let v of arg){
console.log('rest',v);
}
}
test3(1,2,3,4,'a') //1,2,3,4,a
// rest参数会将传入的字符串转化为数组
}
//扩展运算符 相当于rest的逆运算=>把数组展开
{
console.log(...[1,2,4]); // 1,2,4
console.log('a',...[1,2,4]); // a,1,2,4
}
// 箭头函数 不在说了
{
let arrow = v => v*2;
console.log(arrow(1)) // 2
}
// 尾调用,优化用,不再展开,基本形式如下
{
function tail(x){
console.log('tail',x);
}
function fx(x){
return tail(x)
}
fx(123) // tail 123
}
对象的扩展
新增
- 简洁表示法
- 属性表达式
- 新增API
- 扩展运算符
{
// 简洁表示法
let o=1;
let k=2;
let es5={
o:o,
k:k
};
let es6={
o,
k
};
console.log(es5,es6); // 是一样的结果
let es5_method={
hello:function(){
console.log('hello');
}
};
let es6_method={
hello(){
console.log('hello');
}
};
console.log(es5_method.hello(),es6_method.hello()); // 也是一样的,在vue中我们就是用的简洁表示
}
{
// 属性表达式
let a='b';
let es5_obj={
a:'c',
b:'c'
};
let es6_obj={
[a]:'c'
}
console.log(es5_obj,es6_obj) // es5的就不说了 es6输出 {b:c}
}
{
// is
console.log(Object.is('abc','abc'),'abc'==='abc') // true true
console.log(Object.is([],[]),[]===[]); // false false
// 注意
+0 === -0 //true
NaN === NaN // false
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
//assign
console.log('拷贝',Object.assign({a:'a'},{b:'b'})) // {a:a,b:b} 注意这是浅拷贝
// entries
let test={k:123,o:456};
for(let [key,value] of Object.entries(test)){
console.log([key,value])
// [k,123] [o,456]
}
}
{
// 扩展运算符
let {a,b,...c}={a:'test',b:'kill',c:'ddd',d:'ccc'};
// babel对这个支持还不是很友好
c={
c:'ddd',
d:'ccc'
}
}
symbol
ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值
这个玩意我觉得没啥用处阿,简单看一下
// 声明方式
{
// 第一种声明方式
let a1=Symbol();
let a2=Symbol();
console.log(a1===a2);
// false Symbol声明的是独一无二的
// 第二种声明方式
let a3=Symbol.for('a3');
let a4=Symbol.for('a3');
console.log(a3===a4);
// true 都引用的a3
}
// 作为对象的key和symbol的遍历
{
let a1=Symbol.for('abc');
let obj={
[a1]:'123',
'abc':345,
'c':456
};
console.log(obj); // 三个值,放控制台打印一下.这里就不写了
// 注意 for of 遍历找不到symbol的值
for(let [key,value] of Object.entries(obj)){
console.log('let of',key,value);
// abc:345 c:456
}
// Object.getOwnPropertySymbols只可以找到symbol
Object.getOwnPropertySymbols(obj).forEach(function(item){
console.log(obj[item]);
})
// Reflect这个玩意 啥都可以找到
Reflect.ownKeys(obj).forEach(function(item){
console.log('ownkeys',item,obj[item]);
})
}
set和map以及和数组对象的对比
新增数据结构Set 和 Map
-
Set
Set和数组类似,但是成员唯一
// 声明方式1
{
let list = new Set()
list.add(5)
list.add(7)
console.log(list.size) // 2
}
// 声明方式2
{
let arr = [1,2,3,4,5]
let list = new Set(arr)
console.log(list.size) // 5
}
// 不可以有重复的成员
{
let list = new Set()
list.add(1)
list.add(2)
list.add(1)
console.log(list); // 只有 1,2
// 用途 数组去重
let arr=[1,2,3,1,2]
let list2=new Set(arr)
console.log(list2) // 1,2,3
}
// api crud 不再多说 看栗子
{
let arr=['add','delete','clear','has']
let list=new Set(arr)
console.log('has',list.has('add')) // true
console.log('delete',list.delete('add'),list) // 'delete','clear','has'
list.clear() // 没了都删了
console.log('list',list)
}
// 遍历 都是我们常用的
{
let arr=['add','delete','clear','has']
let list=new Set(arr)
for(let key of list.keys()){
console.log('keys',key)
}
for(let value of list.values()){
console.log('value',value)
}
for(let [key,value] of list.entries()){
console.log('entries',key,value)
}
list.forEach(function(item){console.log(item)})
}
// weakSet 这玩意成员只能是对象,Set有的方法他都有
{
let weakList=new WeakSet()
let arg={}
weakList.add(arg)
console.log(weakList);
}
- Map
// 声明方式
// map的key可以是任意数据类型
{
let map = new Map()
let arr=['123']
map.set(arr,456)
console.log('map',map,map.get(arr)) // 456
}
// 常用api,和set很类似,放控制台打印就明白
{
let map = new Map([['a',123],['b',456]])
console.log('map',map)
console.log('size',map.size)
console.log('delete',map.delete('a'),map)
console.log('clear',map.clear(),map)
}
// weakmap 和weakSet一样 成员必须是对象
{
let weakmap=new WeakMap()
let o={}
weakmap.set(o,123)
console.log(weakmap.get(o))
}
- Set,Map和数组,对象的横向对比
{
// map和array的对比
// 数据结构横向对比,增,查,改,删
let map=new Map()
let array=[]
// 增
map.set('t',1)
array.push({t:1})
console.info('map-array',map,array)
// 查
let map_exist=map.has('t');
let array_exist=array.find(item=>item.t)
console.info('map-array',map_exist,array_exist)
// 改
map.set('t',2)
array.forEach(item=>item.t?item.t=2:'')
console.info('map-array-modify',map,array)
// 删
map.delete('t')
let index=array.findIndex(item=>item.t)
array.splice(index,1)
console.info('map-array-empty',map,array)
}
{
// set和array的对比
let set=new Set()
let array=[]
// 增
set.add({t:1})
array.push({t:1})
console.info('set-array',set,array)
// 查
let set_exist=set.has({t:1})
let array_exist=array.find(item=>item.t)
console.info('set-array',set_exist,array_exist)
// 改
set.forEach(item=>item.t?item.t=2:'')
array.forEach(item=>item.t?item.t=2:'')
console.info('set-array-modify',set,array)
// 删
set.forEach(item=>item.t?set.delete(item):'')
let index=array.findIndex(item=>item.t)
array.splice(index,1)
console.info('set-array-empty',set,array)
}
{
// map,set,object对比
let item={t:1}
let map=new Map()
let set=new Set()
let obj={}
// 增
map.set('t',1)
set.add(item)
obj['t']=1
console.info('map-set-obj',obj,map,set)
// 查
console.info({
map_exist:map.has('t'),
set_exist:set.has(item),
obj_exist:'t' in obj
})
// 改
map.set('t',2)
item.t=2
obj['t']=2
console.info('map-set-obj-modify',obj,map,set)
// 删除
map.delete('t')
set.delete(item)
delete obj['t']
console.info('map-set-obj-empty',obj,map,set)
}
简单总结
对比看来,map占有优势,所以我们应该优先使用map,使用建议 map=>set=>array
proxyhe-reflect
Proxy和Reflect 这两或的方法都是一样的,放一起说了
- Proxy可以理解成一个拦截器,直接看栗子
// Proxy
// 先定义一个对象
{
let obj={
time:'2017-09-11',
name:'dou',
_r:123
};
// 声明一个Proxy
let monitor=new Proxy(obj,{
// 拦截对象属性的读取
get(target,key){
return target[key].replace('2017','2018')
},
// 拦截对象设置属性
set(target,key,value){
if(key==='name'){
return target[key]=value
}else{
return target[key]
}
},
// 拦截key in object操作
has(target,key){
if(key==='name'){
return target[key]
}else{
return false
}
},
// 拦截delete
deleteProperty(target,key){
if(key.indexOf('_')>-1){
delete target[key]
return true
}else{
return target[key]
}
},
// 拦截Object.keys,Object.getOwnPropertySymbols,Object.getOwnPropertyNames
ownKeys(target){
return Object.keys(target).filter(item=>item!='time')
}
});
// api
console.log('get',monitor.time) // 2018-09-11
monitor.time='2018';
monitor.name='zhi';
console.log('set',monitor.time,monitor);
// 2018-09-11 time: "2017-09-11", name: "zhi", _r: 123
console.log('has','name' in monitor,'time' in monitor); // true false
// time 是删不掉的,因为我们上面设置了只可以删除_开始的
delete monitor.time
console.log('delete',monitor)
// time: "2017-09-11", name: "zhi", _r: 123
delete monitor._r
console.log('delete',monitor)
// time: "2017-09-11", name: "zhi"
console.log('ownKeys',Object.keys(monitor)) // ["name"]
}
- Reflect
{
let obj={
time:'2017-03-11',
name:'net',
_r:123
};
console.log('Reflect get',Reflect.get(obj,'time')) // 2017-03-11
Reflect.set(obj,'name','zhi')
console.log(obj); // time: "2017-03-11", name: "zhi", _r: 123
console.log('has',Reflect.has(obj,'name')) //true
}
// 撸一个例子
{
function validator(target,validator){
return new Proxy(target,{
_validator:validator,
set(target,key,value,proxy){
if(target.hasOwnProperty(key)){
let va=this._validator[key];
if(!!va(value)){
return Reflect.set(target,key,value,proxy)
}else{
throw Error(`不能设置${key}到${value}`)
}
}else{
throw Error(`${key} 不存在`)
}
}
})
}
const personValidators={
name(val){
return typeof val==='string'
},
age(val){
return typeof val === 'number' && val>18
},
mobile(val){
}
}
class Person{
constructor(name,age){
this.name=name
this.age=age
this.mobile='1111'
return validator(this,personValidators)
}
}
const person=new Person('lilei',30)
console.info(person) // name: "lilei", age: 30, mobile: "1111"
person.name='Han mei mei'
console.info(person) // name: "Han mei mei", age: 30, mobile: "1111"
}
class
{
// 基本定义和生成实例
class Parent{
constructor(name='dou'){
this.name=name
}
}
let v_parent=new Parent('v')
console.log('构造函数和实例',v_parent); // {name:v}
}
{
// 继承
class Parent{
constructor(name='zhi'){
this.name=name
}
}
class Child extends Parent{
}
console.log('继承',new Child()) // zhi
}
{
// 继承传递参数
class Parent{
constructor(name='wei'){
this.name=name
}
}
class Child extends Parent{
constructor(name='child'){
// 这里要注意了 这个super必须要写在第一行,如果子类有自己的属性,不写在第一行就报错
super(name)
this.type='child'
}
}
console.log('继承传递参数',new Child('hello')) // { name: 'hello', type: 'child' }
}
{
// getter,setter
class Parent{
constructor(name='wei'){
this.name=name
}
get longName(){
return 'mk'+this.name
}
set longName(value){
this.name=value
}
}
let v=new Parent();
console.log('getter',v.longName) // mkwei
v.longName='hello'
console.log('setter',v.longName) // mkhello
}
{
// 静态方法
class Parent{
constructor(name='dou'){
this.name=name
}
static tell(){
console.log('tell')
}
}
Parent.tell() // tell
}
{
// 静态属性
class Parent{
constructor(name='zhi'){
this.name=name;
}
static tell(){
console.log('tell')
}
}
Parent.type='test'
console.log('静态属性',Parent.type) // test
}
promise
{
// es5和es6异步操作对比
//es5 通过回掉方式
let ajax=function(callback){
console.log('执行')
setTimeout(function () {
callback&&callback.call()
}, 1000)
};
ajax(function(){
console.log('timeout1')
})
// 执行 timeout1
}
{
// es6通过promise
let ajax=function(){
console.log('执行2')
return new Promise(function(resolve,reject){
setTimeout(function () {
resolve()
}, 1000)
})
};
ajax().then(function(){
console.log('promise','timeout2')
})
// 执行 timeout2
}
{
// 链式调用
let ajax=function(){
console.log('执行3');
return new Promise(function(resolve,reject){
setTimeout(function () {
resolve()
}, 1000)
})
};
ajax()
.then(function(){
return new Promise(function(resolve,reject){
setTimeout(function () {
resolve()
}, 2000)
});
})
.then(function(){
console.log('timeout3')
})
}
{
// 错误处理
let ajax=function(num){
console.log('执行4')
return new Promise(function(resolve,reject){
if(num>5){
resolve()
}else{
throw new Error('出错了')
}
})
}
ajax(6).then(function(){
console.log('log',6)
}).catch(function(err){
console.log('catch',err)
});
ajax(3).then(function(){
console.log('log',3)
}).catch(function(err){
console.log('catch',err)
});
// 执行4 执行4 log 6 报错
}
// all 和 race
{
// 所有图片加载完再添加到页面
function loadImg(src){
return new Promise((resolve,reject)=>{
let img=document.createElement('img')
img.src=src
img.onload=function(){
resolve(img)
}
img.onerror=function(err){
reject(err)
}
})
}
function showImgs(imgs){
imgs.forEach(function(img){
document.body.appendChild(img)
})
}
Promise.all([
loadImg('df1ef0720bea6832.png'),
loadImg('http://i4.buimg.com/5677501/2b07ee25b08930ba.png'),
loadImg('http://baidu.com/567751/5eb8190d6b2a1c9c.png')
]).then(showImgs)
}
{
// 有一个图片加载完就添加到页面
function loadImg(src){
return new Promise((resolve,reject)=>{
let img=document.createElement('img')
img.src=src
img.onload=function(){
resolve(img)
}
img.onerror=function(err){
reject(err);
}
})
}
function showImgs(img){
let p=document.createElement('p')
p.appendChild(img);
document.body.appendChild(p)
}
Promise.race([
loadImg('http://i4.buimg.com/567571/df1ef0720bea6832.png'),
loadImg('http://i4.buimg.com/567751/2b07ee25b08930ba.png'),
loadImg('http://i2.muimg.com/567751/5eb8190d6b2a1c9c.png')
]).then(showImgs)
}
iterator
{
let arr=['hello','world']
// 数组的Iterator,自带的
let map=arr[Symbol.iterator]()
console.log(map.next())
console.log(map.next())
console.log(map.next())
// 输出
{ value: 'hello', done: false }
{ value: 'world', done: false }
{ value: undefined, done: true }
}
// 自定义Iterator接口
// 之所以对象没有部署Iterator接口,是因为不知道我们在对象你存什么,这时候我们自己定义就可以
{
let obj={
start:[1,3,2],
end:[7,9,8],
// 这里好好看一下
[Symbol.iterator](){
let self=this
let index=0
let arr=self.start.concat(self.end)
let len=arr.length
return {
next(){
if(index<len){
return {
// 返回是 value 和 done
value:arr[index++],
done:false
}
}else{
return {
value:arr[index++],
done:true
}
}
}
}
}
}
for(let key of obj){
console.log(key) // 123798
}
}
genertaor函数
{
// genertaor基本定义
let tell=function* (){
yield 'a'
yield 'b'
return 'c'
};
let k=tell()
console.log(k.next()) // {value: "a", done: false}
console.log(k.next()) // {value: "b", done: false}
console.log(k.next()) // {value: "c", done: true}
console.log(k.next()) // {value: undefined, done: true}
}
// 用genertaor来部署iterator接口,在说iterator接口的时候,也自定义过,比较一下
{
let obj={};
obj[Symbol.iterator]=function* (){
yield 1
yield 2
yield 3
}
for(let value of obj){
console.log(value)// 1 2 3
}
}
// 实现无限轮询
{
let state=function* (){
while(1){
yield 'A'
yield 'B'
yield 'C'
}
}
let status=state()
console.log(status.next()) // A
console.log(status.next()) // B
console.log(status.next()) // C
console.log(status.next()) // A
console.log(status.next()) // B
// 如果一直调用next方法 会无限轮询
}
// sync和genertaor 使用方法一样
// {
// let state=async function (){
// while(1){
// await 'A';
// await 'B';
// await 'C';
// }
// }
// let status=state();
// console.log(status.next());
// console.log(status.next());
// console.log(status.next());
// console.log(status.next());
// console.log(status.next());
// }
//
// 整两个栗子
// 抽奖
{
let draw=function(count){
//具体抽奖逻辑
console.info(`剩余${count}次`)
}
let residue=function* (count){
while (count>0) {
count--;
yield draw(count);
}
}
let star=residue(5)
let btn=document.createElement('button')
btn.id='start'
btn.textContent='抽奖'
document.body.appendChild(btn)
document.getElementById('start').addEventListener('click',function(){
star.next();
},false)
}
// 长轮询
{
let ajax=function* (){
yield new Promise(function(resolve,reject){
setTimeout(function () {
resolve({code:0})
}, 200);
})
}
let pull=function(){
let genertaor=ajax()
let step=genertaor.next()
step.value.then(function(d){
if(d.code!=0){
setTimeout(function () {
console.info('wait')
pull()
}, 1000)
}else{
console.info(d)
}
})
}
pull();
}
decorator
// 方法的修饰
{
let readonly=function(target,name,descriptor){
descriptor.writable=false
return descriptor
};
class Test{
@readonly
time(){
return '2017-03-11'
}
}
let test=new Test()
console.log(test.time());
}
// class 的修饰
{
// 加一个静态属性
let typename=function(target,name,descriptor){
target.myname='hello'
}
@typename
class Test{
}
console.log('类修饰符',Test.myname);
// 第三方库修饰器的js库已经为我们写好了跟多的修饰器
// core-decorators; npm install core-decorators
}
// 来个栗子 实现业务和逻辑的分离
{
let log=(type)=>{
return function(target,name,descriptor){
let src_method=descriptor.value
descriptor.value=(...arg)=>{
src_method.apply(target,arg)
console.info(`log ${type}`)
}
}
}
class AD{
@log('show')
show(){
console.info('ad is show')
}
@log('click')
click(){
console.info('ad is click')
}
}
let ad=new AD()
ad.show()
ad.click()
ad is show
log show
ad is click
log click
}