ins-vueVue.js学习vue

Vue项目开发与规范--es6语法规范篇

2018-08-01  本文已影响1人  youins

目录

简介

ECMAScript 6 简称 ES6,是 JavaScript 语言的下一代标准,已经在2015年6月正式发布了。它的目标是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。

ECMAScript 和 JavaScript 的关系:前者是后者的语法规格,后者是前者的一种实现.

↑ 回到目录

let-const

作用域的概念

如何使用let和const

直接看代码

// 块作用域
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定义常量,赋值以后不能改变
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表示法
遍历接口
新增方法
模板,便签字符串

{
    // 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
}

↑ 回到目录

函数的扩展

新增

// 函数参数的默认值

{
  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
}

↑ 回到目录

对象的扩展

新增

{
  // 简洁表示法
  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

// 声明方式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的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))
}
{
  // 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
// 先定义一个对象
{
  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"]

}


{
  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
}

↑ 回到目录

上一篇 下一篇

猜你喜欢

热点阅读