es6语法
*let和const
1.{}包住里面就是块作用域,let只在块作用域生效
2.let不能重复定义相同变量
3.const是常量,不能修改,定义后是只读不能修改。
4.const声明的时候必须赋值,也有块作用域。
5.const如果定义成对象,就可以修改的,对象是引用类型(返回值是存储内存的指针,指针是不变的,但是对象本身是可以变的)。
*解构赋值
左边一个结构,右边一个结构,然后左右一一对应进行赋值
数组解构赋值
{
let a,b,rest;
[a,b] = [1,2];
console.log(a,b) //1 2
}
{
let a,b,rest;
[a,b,...rest] = [1,2,3,4,5,6];
console.log(a,b,rest) //1 2 [3,4,5,6]
}
{
let a,b,c,rest;
[a,b,c=3] = [1,2];
console.log(a,b) //1 2 如果不定义c给默认值3,就等于定义没赋值undefined
}
对象解构赋值
{
let a,b;
({a,b}={a:1,b:2})
console.log(a,b) //1 2
}
字符串解构赋值
布尔值解构赋值
函数参数解构赋值
数值解构赋值
应用场景
适合变量交换
数组型
{
let a =1;
let b=2;
[a,b] = [b,a]
console.log(a,b) //2,1
}
{
function f(){
retrun [1,2]
}
let a,b
[a,b]=f()
console.log(a,b) //简单接收返回值
}
{
function f(){
renturn [1,2,3,4,5]
}
let a,b,c
[a,,,b] =f()
console.log(a,b) // 1 4 按顺序匹配用, 分割 。用来选择性接收某几个变量
}
{
function f(){
renturn [1,2,3,4,5]
}
let a,b,c
[a,...b] =f()
console.log(a,b) // 1 [2,3,4,5] 这种是不知道返回的数组长度是多少,我只关心第一个,其他就返回一个数组,想用就遍历,就等于取出第一个元素,其他放在一个数组里面
}
对象型
{
let o = {p:42,q:true}
let {p,q} = o
console.log(p,q) //42 true
}
{
let {a=10,b=5} = {a:3}
console.log(a,b) // 3 5
}
{
let metaData = {
title:'abc',
test:[{
title:'test',
desc:'description'
}]
}
let {title:esTitle,test:[{title:cnTitle}]} = metaData;
console.log(esTitle,cnTitle) // abc test
}
*正则扩展
正则新增特性
构造函数的变化
//es5
let regex new RegExp('xyz','i') //i忽略大小写 两个参数
let regx2 = new RegExp(/xyz/i) //一个参数
//es6
let regx3 = new RegExp(/xyz/ig,'i') //es6第二个参数会覆盖第一个参数所制定
的修饰符
console.log(regex3.flags)//获取当前的修饰符
正则方法的扩展
u修饰符
{
console.log('u-1',/^\uD83D/.test('\uD83D\uDC2A')) // true 当成两个字母
console.log('u-1',/^\uD83D/u.test('\uD83D\uDC2A'))//false u会把2个字符当作一个字符
}
y修饰符
{
let s = 'bbb_bb_b'
let a1 = /b+/g
let a2 = /b+/y
console.log('one',a1.exec(s),a2.exec(s))
console.log('two',a1.exec(s),a2.exec(s))
//g是从上一次匹配的位置再寻找,不强调必须是匹配下一个字符的开始匹配,中间任何位置匹配上都算
//y是一定要匹配到下一个字符也匹配到才算
}
s修饰符
*字符串拓展
新增特训
Unicode表示法
console.log('a',`\u0061`)
console.log('a',`\u20BB7`) //这个会打印乱码和7 因为组合超过0XFFFF字节
console.log('a',`\u{20BB7}`)
遍历接口
let str = '\u{20bb7}abc'
for(let code of str){
console.log('es6',code)
}
模版字符串
let name='list'
let info = 'hello world'
let m = `i am ${name},${info}`
新增方法10种
//判断字符串种是否包含某些字符
let str = 'string'
console.log('includes',str.includes('r')) //true
//判断字符串是不是以某个字符为起始或者终始
let str = 'string'
console.log('start',str.startsWith('str')) //true
console.log('end',str.endsWith('ng')) //true
//复制字符串
let str = 'abc'
console.log(str.repeat(2)) //abcabc
//补位(可用于日期选择)
//向前补
console.log('1'.padStart(2,'0')) //意思就是要2位,不够用0补,输出01
//向后补
console.log('1'.padEnd(2,'0')) //意思就是要2位,不够用0补,输出10
//raw \转义 就是又加一个\
console.log(String.raw`Hi\n${1+2}`)
console.log(`Hi\n${1+2}`)
//标签模版
参考https://www.cnblogs.com/sminocence/p/6832331.html
参考https://www.jianshu.com/p/c65b9930dd11
*数值扩展
数值处理新增特性
1.新增方法
console.log(Number.isFinite(15)) //判断这个数是不是无穷大
console.log(NUmber.isNaN(NaN)) //判断这个数是不是一个数
console.log(Number.isInteger(25))//判断这个数是不是一个整数
console.log(Math.trnc(4.1))//取整 小数会删掉
console.log(Math.sign(-5))//判断是否正负数或者0
2.方法调整
数组扩展
数组新增特性
Array.form
//把一个集合转换成真正的数组
<p>你好</p>
<p>你好1</p>
<p>你好2</p>
{
let p = document.querySelectorAll('p')
let pArr = Array.from(p)
pArr.forEach(function(item){
console.log(item.texrContent)
})
}
{
//第二个用法 可以遍历第一个参数的数组,类似map方法
console.log(Array.from([1,3,4],function(item){return item*2}))
}
Array.of
//把一组数据变量,转换成数据类型
let arr = Array.of(3,9,11,20,30)
console.log(arr)//[3,9,11,20,30]
copyWithin
{
console.log([1,2,3,4,5].copyWithin(0,3,4)) 1参数:从那个位置开始替换 2:从那个位置开始读取位置 3:从那个位置截止 //[4,2,3,4,5]
}
find\findIndex
{
//查找数组中有没有一个元素大于3的,找出第一个满足就停止查找
console.log([1,2,3,4,5,6].find(function(item){ return item>3})) //4
}
{
//查找数组中有没有一个元素大于3的,找出第一个满足返回下标就停止查找
console.log([1,2,3,4,5,6].findIndex(function(item){ return item>3})) //3
}
fill
console.log([1,'a',undefined].fill(7))//把数组里面的每个值变成7
//['a','b','c'].fill(7,1,3) 后面2个参数是起始和结束位置,从第一个开始换一直到第三个
entries\keys\values
//keys返回下标
{
for(let index of ['1','c','ks'].keys()){
console.log(index)
}
}
//values返回值 (有兼容问题这个)
{
for(let value of ['1','c','ks'].values()){
console.log(value)
}
}
//entries返回下标和值
{
for(let [index,value] of ['1','c','ks'].entries()){
console.log(value,index)
}
}
includes
//查找一个数组是否包含某个元素
{
console.log([1,2,NaN].includes(1)) //true
}
*函数扩展
函数新增特性
参数默认值
{
//默认值变量后面不能有再有没有默认值的变量!!!!!!
function test(x,y='world'){
console.log(x,y)
}
test('hello')
}
rest参数
//把一系列的参数转换成一个数组
//作用就是把你不确定有多少个参数,最终把你输入的参数转换成一个数组
//注意rest参数后面不能再有参数,不然会报错
{
function test3(...arg){
for(let v of arg){
console.log(v)
}
}
test3(1,2,3,4,5,'a')
}
扩展运算符
{
//把一个数组拆开
console.log(...[1,2,3])
}
箭头函数
{
//第一部分函数名,函数参数(如果没有参数就给一个()),函数返回值
let arrow = v => v*2
console.log(arrow(3)) //6
}
this绑定
尾调用
//提升性能
{
function tail(x){
console.log('tail',x)
}
funciton fx(x){
return tail(x)
}
fx(123)
}
*对象扩展
函数新增特性
简洁表示法
{
let o = 1
let l =2
let es5 = {
o:o,
k:k
}
let es6 = {
o,
k
}
}
{
let es5_method = {
hello:function(){
console.log('hello')
}
}
let es6_method = {
hello(){
console.log('hello')
}
}
}
属性表达式
{
let a = 'b'
let es5_obj={
a:'c',
b:'c'
}
//[]相当于传了个变量过去,比如像生成一个对象,k值可以变化的 就挺有用的
let es6_obj = {
[a]:'c'
}
console.log(es6_obj) // b:c
}
扩展运算符
{
let {a,b,...c} = {a:'test',b:'kill',c:'ddd',d:'ccc'}
//a对应a b对应b c对应后面的c,d
//如果后面还有都统统赋值给c
}
Object新增方法
//新增API
//和===一样
console.log('字符串',Object.is('abc','abc'),'abc'==='abc')
console.log('数组',Object.is([],[]),[]===[]) //数组是引用类型,地址指向不一样,所以打印是 false
console.log('拷贝',Object.assign({a:'a'},{b:'b'})) //就会合并在一起,浅拷贝
//遍历
let test = {k:123,o:456}
for(let [key,value] of Object.entries(test)){
console.log([key,value])
}
*Symbol
Symbol的概念
提供一个独一无二的值
{
//声明
let a1 = Symbol();
let a2 = Symbol();
console.log(a1===a2) //false
let a3 = Symbol.for('a3')
let a4 = Symbol.for('a3') //先去全局找 有就引用,没就创建一个独一无二的值
console.log(a3===a4) //true
}
Symbol的作用
{
//可以生成唯一的,不会重复,就算重写也覆盖不到。
//注意,如果用Symbol定义,用for of 是取不到的,需要用Object.getOwnPropertySymbols()
let a1 = Symbol.for('abc')
let obj = {
[a1]: '123',
'abc': 345,
'c': 456
}
console.log(obj) //abc:345,c:456,Symbol(abc):123
Object.getOwnPropertySymbols(obj).forEach*function(item){
console.log(obj[item]) //只能拿到k值是Symbol的
}
Reflect.ownKeys(obj) //能拿到Symbol和非Symbol的值 也是返回数组,可以直接使用forEach
}
*数据结构
Set的用法(数组去理解,但是不能重复)
{
let list = new Set();
list.add(5)
list.add(7)//在Set里面增加东西要用add
console.log(list.size) //在Set里面的长度,理解是数组的length
}
{
let arr = [1,2,3,4,5]
let list = new Set(arr) //标示list是转换一个Set的数据类型集合
}
{
let list = new Set()
lista.add(1)
lista.add(2)
lista.add(1)
console.log(list) //最后一个1不会存在,去重了
let arr = [1,2,3,1,2]
let list2 = new Set(arr)
console.log(list2) //1.2.3 不会对数据转换,如果[1,2,3,1,'2'] 字符串2不会过滤
}
{
let arr = ['add','delete','clear','has']
let list = new Set(arr)
console.log('has',list.has('add')) //true 判断集合是否含有add
console.log('delete',list.delete('add')) //{'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(key)
}
//输出都一样 都是名称
for(let value of list.values()){
console.log(value)
}
}
WeakSet的用法 (弱引用)
//支持的数据类型区别,WeakSet只能是对象,弱引用,不会检测有没有在其他地方用过,不会改变原指向地址
{
let weakList = new WeakSet()
let arg = {}
weakList.add(arg)
console.log(weakList) // {}
}
Map的用法(Object去理解,一个k,v值)
{
let map = new Map()
let arr = ['123']
map.set(arr,456) //添加元素 map的k可以是任何的数据类型
console.log(map.get(arr)) //456
console.log(map) // ['123'] => 456
}
{
//第二种定义方式
let map = new Map([['a',123],['b',456]])
console.log(map)
map.size //获取长度
map.delete('a') //删除
map.clear() //清空
}
WeakMap的用法 (弱引用)
//和WeakSet一样
JSON 和 Map的相同点就是 key,value的方式存储的, 而JSON精确的说键值只支持String(也可以存数值,但是数值存进去,取出来还是String),Map键值都可以存储对象.
键值对的存储结构你自己也可以写.
最后总结:
filter方法是对原数组进行过滤筛选,产生一个新的数组对象
map方法对元素中的元素进行加工处理,产生一个新的数组对象。
Map与Array的对比
//数据结构横向对比,增,查,改,删
{
let map = new Map()
let array = []
//增
map.set('t',1)
array.push({t:1})
console.info(map,array)
//查
let map_exist = map.has('t')
let array_exist = array.find(item=>item.t)
console.info(map_exist,array_exist)
//改
map.set('t',2)
array.forEach(item=>item.t?item.t=2:'')
console.info(map_exist,array_exist)
//删
map.delete('t')
let index = array.findIndex(item=>item.t)
array.splice(index,1)
}
Set与Array的对比
{
let set = new Set()
let array=[]
//增
set.add({t:1})
array.push({t:1})
//查
let set_exist = set.has({t:1})
let array_exist = array.find(item=>item.t)
//改
set.forEach(item=>item.t?item.t=2:'')
array_exist.forEach(item=>item.t?item.t=2:'')
//删
set.forEach(item=>item.t?set.delete(item):'')
let index = array.findIndex(item=>item.t)
array.splice(index,1)
}
Map与Object的对比
Set与Object的对比
{
//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
//查
map.has('t')
set.has(item)
't' in obj
//改
map.set('t',2)
item.t = 2
obj['t'] = 2
//删除
map.delete('t')
set.delete(item)
delete obj['t']
}
//优先使用map,如果对数据要求比较高唯一性考虑set
*Proxy和Reflect
Proxy和Reflect的概念
{
//有一个类似供应商的原始数据
let obj = {
time:'2017-03-11',
name:'net',
_r:123
}
//然后通过new Proxy先生成一个对象,这个对象是映射obj,然后中间做一些操作,最后用户访问的是monitor,不管用户是读取还是设置monitor对象,最终由这个Proxy传递给obj对象
let monitor = new Proxy(obj,{
//拦截对象属性的读取
get(target,key){
return target[key].replace('2017','2018') //不管你读取我什么属性,我要把属性所有的2017值替换成2018
},
//拦截对象设置属性
set(target,key,value){
if(key === 'name'){
return target[key] =value
}else{
return target[key]
}//只允许修改name属性
},
//拦截key in object操作
has(target,key){
if(key==='name'){
return target[key]
}else{
return false
}
},
//拦截删除
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')
}
})
//读取操作 monitor.time
console.log('get',monitor.time)
//设置操作
monitor.time = '2018'
console.log('set',monitor.time)
//拦截in
console.log('has','name' in monitor)
//删除
delete monitor.time
console.log('delete',monitor)
//循环
console.log('ownKeys',Object.keys(monitor))
}
{
let obj = {
time:'2017-03-11',
name:'net',
_r:123
}
Reflect.get(obj,'time')
Reflect.set('obj','name','mukewang')
Reflect.has(obj,'name')
}
Proxy和Reflect的适用场景
{
//对数据校验,比如手机号格式是否正确
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}` 不存在)
}
}
})
}
}
*类
类的概念
基本语法
{
//基本定义和生成实例
class Parent{
constructor(name='mukewang'){
this.name = name
}
}
let v_parent = new Parent('v')
console.log(v_parent)
}
类的继承
{
//继承
class Parent{
constructor(name='mukewang'){
this.name = name
}
}
class Child extends Parent{
}
console.log(new Child())
}
{
//继承传递参数
class Parent{
constructor(name='mukewang'){
this.name = name
}
}
class Child extends Parent{
constructor(name='child'){
super(name) //覆盖父类 完成子类向父类传递参数, 这个一定要放在构造函数的第一行
}
}
console.log(new Child())
}
静态方法
{
//静态方法 概念:是通过类去调用,而不是通过实例去调用
class Parent{
constructor(name='mukewang'){
this.name = name
}
static tell(){
console.log('tell')
}
}
Parent.tell()
}
静态属性
{
//静态属性
class Parent{
constructor(name='mukewang'){
this.name = name
}
}
Parent.type = 'test'
console.log(Parent.type) //不用实例调用,用类调用
}
geter
{
//getter,setter
class Parent{
constructor(name='mukewang'){
this.name = name
}
//定义一个实例里的属性
get longName(){
return 'mk' + this.name
}
set longName(value){
this.name = value
}
}
let v = new Parent()
console.log('getter',v.longName) //mkmukewang
v.longName = 'hello'
console.log('setter',v.longName) //mkhello
}
setter
*Promise
什么是异步
Promise的作用
Promise的基本用法
{
// 基本定义
let ajax=function(callback){
console.log('执行');
setTimeout(function () {
callback&&callback.call()
}, 1000);
};
ajax(function(){
console.log('timeout1');
})
}
{
//基本操作
let ajax=function(){
console.log('执行2');
return new Promise(function(resolve,reject){
setTimeout(function () {
resolve()
}, 1000);
})
};
ajax().then(function(){
console.log('promise','timeout2');
})
}
{
//多个.then用法
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);
});
}
高级用法
一、Pomise.all的使用
Promise.all可以将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值。
具体代码如下:
let p1 = new Promise((resolve, reject) => {
resolve('成功了')
})
let p2 = new Promise((resolve, reject) => {
resolve('success')
})
let p3 = Promse.reject('失败')
Promise.all([p1, p2]).then((result) => {
console.log(result) //['成功了', 'success']
}).catch((error) => {
console.log(error)
})
Promise.all([p1,p3,p2]).then((result) => {
console.log(result)
}).catch((error) => {
console.log(error) // 失败了,打出 '失败'
})
Promse.all在处理多个异步处理时非常有用,比如说一个页面上需要等两个或多个ajax的数据回来以后才正常显示,在此之前只显示loading图标。
代码模拟:
let wake = (time) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`${time / 1000}秒后醒来`)
}, time)
})
}
let p1 = wake(3000)
let p2 = wake(2000)
Promise.all([p1, p2]).then((result) => {
console.log(result) // [ '3秒后醒来', '2秒后醒来' ]
}).catch((error) => {
console.log(error)
})
需要特别注意的是,Promise.all获得的成功结果的数组里面的数据顺序和Promise.all接收到的数组顺序是一致的,即p1的结果在前,即便p1的结果获取的比p2要晚。这带来了一个绝大的好处:在前端开发请求数据的过程中,偶尔会遇到发送多个请求并根据请求顺序获取和使用数据的场景,使用Promise.all毫无疑问可以解决这个问题。
二、Promise.race的使用
顾名思义,Promse.race就是赛跑的意思,意思就是说,Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
},1000)
})
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('failed')
}, 500)
})
Promise.race([p1, p2]).then((result) => {
console.log(result)
}).catch((error) => {
console.log(error) // 打开的是 'failed'
})
原理是挺简单的,但是在实际运用中还没有想到什么的使用场景会使用到。
*lterator和for...of循环
什么是lterator接口
lterator的基本用法
{
let arr=['hello','world'];
let map=arr[Symbol.iterator]();
console.log(map.next());
console.log(map.next());
console.log(map.next());
}
{
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:arr[index++],
done:false
}
}else{
return {
value:arr[index++],
done:true
}
}
}
}
}
}
for(let key of obj){
console.log(key);
}
}
{
let arr=['hello','world'];
for(let value of arr){
console.log('value',value);
}
}
for...of
*Generator
基本概念
解决异步编程 async和await就是它的语法糖
next函数的用法
yield*的语法
{
// genertaor基本定义
let tell=function* (){
yield 'a';
yield 'b';
return 'c'
};
let k=tell();
console.log(k.next());
console.log(k.next());
console.log(k.next());
console.log(k.next());
}
{
let obj={};
obj[Symbol.iterator]=function* (){
yield 1;
yield 2;
yield 3;
}
for(let value of obj){
console.log('value',value);
}
}
{
let state=function* (){
while(1){
yield 'A';
yield 'B';
yield '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 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());
// }
*Decorator
基本概念
是一个函数用来修改类的行为
基本用法
{
let readonly=function(target,name,descriptor){
descriptor.writable=false;
return descriptor
};
class Test{
@readonly
time(){
return '2017-03-11'
}
}
let test=new Test();
// test.time=function(){
// console.log('reset time');
// };
console.log(test.time());
}
{
let typename=function(target,name,descriptor){
target.myname='hello';
}
@typename
class Test{
}
console.log('类修饰符',Test.myname);
// 第三方库修饰器的js库:core-decorators; npm install core-decorators
}
*模块化
基本概念
ES6的模块化语法
// export let A=123;
//
// export function test(){
// console.log('test');
// }
//
// export class Hello{
// test(){
// console.log('class');
// }
// }
let A=123;
let test=function(){
console.log('test');
}
class Hello{
test(){
console.log('class');
}
}
export default {
A,
test,
Hello
}
//导入
import Lesson17 form './class/lesson17'
console.log(Lesson17.A)