一、变量的解构赋值 就是按照一定的模式对数组或者对象里面的变量进行提取然后进行赋值 这就是解构
1.数组的解构赋值
1.ES6中允许按照一定的模式,从数组和对象中提取值,对变量进行赋值,这被称为解构
let [a, b, c] = [1, 2, 3];
2.本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值
3.如果等号两边模式不匹配那么就解构失败,变量都会被赋予undefined
let [foo] = [];
let [bar, foo] = [1];
4.等号左边的模式,只匹配一部分的等号右边的数组。这种情况下,解构依然可以成功
let [x, y] = [1, 2, 3];
5.如果等号右边不是数组,那就会报错
let [foo] = 1;
6.解构赋值允许指定默认值 如果右边数组的值是null 默认值将失效
let [foo = true] = [];
let [x = 1] = [undefined];
let [x = 1] = [null]; 默认值x=1将失效,x会等于null
6.1.如果有默认值,但右边又指定了值,那么默认值会被覆盖
6.2.默认值允许引用已经定义的变量 如果未声明就使用那么会报错
let [x = 1, y = x] = [1, 2]; // x=1; y=2
7.如果默认值是一个表达式,那么这个表达式是惰性求值的,即只有在用到的时候,才会求值
function f() {console.log('aaa');}
let [x = f()] = [1];
2.对象的解构赋值
1.let { foo, bar } = { foo: "aaa", bar: "bbb" };
2.数组的解构赋值,次序必须一一对应才能得到正确的值,而对象的解构赋值没有次序,只要变量名一样
3.let { foo: baz } = { foo: 'aaa', bar: 'bbb' };baz会得到aaa
4.let { foo: baz } = { foo: "aaa", bar: "bbb" };foo只是匹配模式,而baz才是变量
3.es5是全局作用域和函数作用域 es6引出大括号{}块级作用域
4.let
1.没有变量声明提升
2.必须先定义后使用
3.一个变量不能重复定义,但是可以重复多次赋值
4.for循环for(类似父级作用域){子级作用域}
5.TDZ暂时性死区 块级作用域开始和结束之间,只有let和const才有暂时性死区
6.const
1.定义完成后必须马上赋值,后面就不能修改了,修改就会报错
2.const本质不能修改的是保存的那个变量的指针地址不能修改,类似数组这类数据类型可以通过方法向数组里面添加数据,数组本身的地址指针没有发生改变,这样是允许的
3.Object.freeze(obj);此方法有冻结对象的功能,冻结之后就不能修改里面的内容了
7.没有块级作用域之前是使用立即执行函数模拟一个块级作用域
8.解构赋值 就是拆开来赋值,自定义方便自己开发 适用于数组和对象
1.左右两边解构要一致 不然对应会错乱 解构数组要求次序一一对应
<script>
var arr=[1,2,3];
var [a,b,c='9999'] = [1,2];
console.log(arr[0],arr[1],arr[2]);
console.log(a,b,c);
</script>
2.解构对象 还可以取别名 还可以给默认值 如果后台未传值或者传过来undefined那么就会适应默认值,但是如果传过来null那就不会使用默认值而是null
<script>
let json = {
name : "张三",
age : 18,
job : "hehhee"
}
let {name,age,job:a} = {
name : "张三",
age : 18,
job : "hehhee"
}
console.log(json);
console.log(json.name,json.age,json.job);
console.log(name,age,job);
</script>
3.import {a,b,c} from './' 也是解构的应用
9.字符串模板 ``
1.以往如果要在字符串里面拼接变量,那需要"+变量+" 这样是非常麻烦的,也比较容易出错
2.字符串模板的诞生就很好的解决了这个问题只需要${变量}
3.优点``支持随意换行 不需要使用字符串连接了
4.字符串新增方法
1.字符串查找str.includes('要找的东西')返回值是布尔值
2.以往要查找字符串使用的是str.indexOf('要查找的东西')返回值是索引位置,没有就是返回-1
3.匹配只能找到是否包含这个东西但他前后有什么就不会去判断
4.字符串还提供了判断是否以规定字符串开头str.startsWith("监测东西")
5.结尾方法str.endsWith("监测东西")
6.重复字符串str.repeat(100)
以上都是es2016里面新增的方法
7.es2017新加了一个字符串填充方法
1.str.padStart(填充完毕后字符串长度,要填充的字符串)
10.es6中函数的变化
1.参数可以给默认值了
2.函数参数默认是已经定义了,不能再重复定义了
3.扩展运算符、rest运算符
1.有扩展数组的功能 也就是展开数组
function test3(x,y,z){
console.log(x,y,z);
}
test3(...[1,9,8]);
2.还有变回数组的功能 接收一系列一个一个的数据变成数组
function test2(...a){
console.log(a.sort());
}
test2(1,9,8,7,5,2,3);
3.还能有剩余功能 剩余参数必须放到最后
function test4(a,b,...c){
console.log(a,b);
console.log(c);
}
test4(1,9,8,7,5,2,3);
4.Array.from(参数)方法可以把东西转成数组,目前已知参数可以是字符串,数组
5.箭头函数的引入
1.箭头函数左边是参数 右边是返回值 let show = () => 1 直接写如果没有{}就是直接代表返回值,这个是最简单的格式,实用性不高
2.正常完整格式()=>{}
3.注意事项
1.在全局使用var定义一个变量属于window,使用let 和const定义不属于window
2.setTimeout()里面普通函数this指向window
3.箭头函数里面的this不再指向window,不再指向谁调用就指向谁,而指向其定义时所在的对象,归定义时所在的父级对象所有,如果定义时所在window那么就指向window
4.箭头函数里面没有arguments 代替品就是扩展运算符...argu
5.箭头函数不能做构造函数
6.es2017里面规定函数参数最后允许有一个逗号了,以前实惠报错的
11.数组
1.es5的时候数组循环使用for arr.forEach(function(val,index,arr){},第二个参数可选,this指向谁,默认指向window)
2.arr.map(function(val,index,arr){}) 功能类似forEach() map专业术语叫映射 它主要用处就是配合return返回一个新数组,没有return返回值就是undefined
1.map()作用就是对数据结构进行整理 因为有时候从后台拿过来的数据需要进行修改或者运算就可以使用map
3.arr.filter(function(val,index,arr){}) 过滤 如果回调函数返回值是true就留下该条数据
4.arr.some(function(val,index,arr){}) 循环查找,查找是否符合条件,其中之一符合条件就OK 返回值是个布尔值
5.arr.every(function(val,index,arr){})循环查找,查找是否符合条件,全部项都符合条件就OK 返回值是个布尔值
6.arr.reduce(function(prev,cur,index,arr){}); 从左往右
6.1. arr.reduceRight(function(prev,cur,index,arr){}); 从右往左
7.Math.pow(a,b) a的b次方 es2017新增的一个运算符a**b求的也是a的b次方
8.es6里面新增了一个for .. of .. 循环 类似于for-in循环遍历对象,但for of循环功能更多
9.数组上有一个方法arr.keys()返回的都是数组的key下标
9.1数组还增加了一个arr.entries() 数组的某一项
12.数组新增方法
1.将一个类数组转成数组,因为类数组是不能使用数组的方法如push等let arr = [...类数组]
2.Array.from()作用就是把类数组对象转成数组
3.类数组个人观点就是具备length这个属性,就可以使用Array.from()
<script>
let json = {
0 : 'apple',
1 : 'banana',
2 : 'pear',
length : 3
}
let arr = Array.from(json);
console.log(arr);
</script>
4.Array.of('apple','banana','pear')功能是把一组值转换成数组,类似扩展运算符...
5.arr.find(function(val,index,arr){})找出返回符合条件的第一个值
6.arr.findIndex(function(val,index,arr){})找出返回符合条件的第一个值的索引
7.arr.fill(要填充的内容,从第几项开始,第几项结束)填充
es2016新增arr.includes() 返回值是个布尔值 arr.indexOf()
13.对象的变化
1.对象简介语法 直接写name,等于name : name, 切记箭头函数里面的this问题
<script>
let name = 'hehe';
let age = 48;
let json = {
name : name,
age : age,
showA : function(){
return this.name;
}
}
console.log(json);
let json2 = {
name,
age,
showA(){
return this.age;
}
}
console.log(json2);
console.log('********************');
console.log(json.showA());
console.log(json2.showA());
</script>
2.新增Object.is(第一个数,第二个数)比较两个数是否相等 两个东西一样他就相等
1.Object.is(NaN,NaN);返回值是true
2.Object.is(+0,-0);返回值是false
3.Object.assign(target,suorce..) 用来合并对象 后面的覆盖前面的 当然还适用于数组
let o1 = {a : 1};
let o2 = {b : 2};
let o3 = {c : 3};
let o4 = Object.assign({},o1,o2,o3);
console.log(o4);
let arrr = ['apple','banana','tomato'];
let newArr = Object.assign([],arrr);
newArr.push('pear');
用途:
1.复制一个对象
2.合并参数
4.es2017引入的Object.keys() Object.entries() Object.values()都可以对应简写keys,entries,values他们的参数都是对象
5.对象也可以使用扩展运算... 计划2018引入
<script>
let {x,y,...z} = {x : 1,y : 2,a : 3,b : 4}
console.log(x,y,z);
let json = {m : 1,n : 2}
let json1 = {...json}
console.log(json1);
json1.l = 3;
console.log(json1);
console.log(json);
</script>
14.Promise 承诺,许诺 作用就是解决异步回调,也就是回调函数里面再套回调函数 传统解决这个问题使用的是回调函数和事件
1.new Promise(function(resolve,reject){}); resolve成功调用,reject失败调用
<script>
let a = 100;
let promise = new Promise(function(resolve,reject){
if(a==10){
resolve('成功!');
}else{
reject('失败!');
}
});
promise.then(function(res){
console.log(res);
},function(rej){
console.log(rej);
});
</script>
2.promise.then(success,error)
3.promise.catch(function(err){})专门捕捉错误的
4.以上方法返回值都是promise这个对象,允许多次连续调用new Promise().then(res=>{}).catch(err=>{})
5.Promise.resolve('aa') 将现有的东西转成promise对象并且是resolve状态
let promise1 = new Promise(resolve => {
resolve('aa');
})
6.Promise.reject('bb') 将现有的东西转成promise对象并且处于reject状态
7.Promise.all([p1,p2,p3])将多个promise对象打包成一个数组 必须确保都是resolve状态
let p1 = Promise.resolve('aaaaaa');
let p2 = Promise.resolve('bbbbbb');
let p3 = Promise.resolve('cccccc');
Promise.all([p1,p2,p3]).then(res=>{
let [result1,result2,result3] = res;
console.log(result1,result2,result3);
})
15.模块化 es6之前是没有模块化的,但是社区制定了一套规范,如基于commonjs的nodejs,还有AMD、CMD等规范
1.之前的模块太过混乱,所以es6就出来规范,统一了服务端和服务端的模块
2.如何定义模块
3.如何使用模块 要使用模块必须运行在服务器端 需要说明type
<script type="module">
import './module/test.js'
</script>
4.import引入模块允许相对路径和绝对路径 多次引入算一次
1.import './module/test.js'
2.https://code.jquery.com/jquery-3.3.1.min.js相当于引入js文件没有其他作用
5.引入和导出允许设置别名
console.log('模块1');
export const a = 12;
alert(a);
let x = 1;
let y = 2;
let z = 3;
export {x,y,z}
export {x as xx,y as yy,z as zz}
<script type="module">
import {a} from './module/test.js';
console.log(a);
import {x,y,z} from './module/test.js';
console.log(x,y,z);
import {xx,yy,zz} from './module/test.js';
console.log(xx,yy,zz);
import {xx as xxx,yy as yyy,zz as zzz} from './module/test.js';
console.log(xxx,yyy,zzz);
</script>
6.还支持全部一起引入import * as module from './module/test.js';全部参数会存入module对象里面
7.import有自动提升到顶部的功能,最先执行
8.模块里面的参数值改变,引用的地方也会改变,相当于实时监测,跟common规范不一样,common规范会缓存
9.以上的模块加载类似于静态加载,不能按照自己需求条件想加载就加载,只能是要么加载要么不加载
10.动态加载模块 使用了Promise规范 按需加载 可以使用if条件判断是否加载模块 路径可以是动态的
import('./module/test.js').then(res=>{});
Promise.all([
import('./module/1.js'),
import('./module/2.js'),
]).then((mod1,mod2)=>{
console.log(mod1);
console.log(mod2);
})
11.在最新的ES7(ES2017)中提出的前端异步特性:async、await。
1.async顾名思义是“异步”的意思,async用于声明一个函数是异步的。而await从字面意思上是“等待”的意思,就是用于等待异步完成。并且await只能在async函数中使用
2.通常async、await都是跟随Promise一起使用的,因为async返回的都是一个Promise对象
3.await得到Promise对象之后就等待Promise接下来的resolve或者reject
12.模块化默认都是严格模式
16.es6中的类
1.es5以前没有类这个概念 面向对象-类 属性和方法 没有类之前用的是构造函数
let aaa = 'temp';
class Person2{
//constructor是构造函数,只要调用new了这个函数就会自动执行
constructor(name,age){
console.log(`构造函数执行了,名字是${name}年龄是${age}`);
//属性直接跟之前一样直接写
this.name = name;
this.age = age;
}
//方法也是直接写
showName(){
console.log(`名字是${this.name}`);
}
showAge(){
console.log(`年龄是${this.age}`);
}
[aaa](){
console.log('我可以使用变量和表达式了,但调用我的时候需要使用temp');
}
}
let p2 = new Person2('hehe',999);
p2.showAge();
p2.showName();
p2.temp();
2.注意定义方法不需要function 也不需要逗号隔开
3.其他定义类的方法const Person = class{}
4.es6里面属性名可以使用变量和表达式了,对象里面的属性名也可以使用变量和表达式
5.类没有提升功能,必须定义完了才能使用,函数和变量是有提升的
6.es5里面有个bind方法也可以改变this指向
7.类里面取值设置值函数getter和setter 可以监听到数据的变化和取值
<script>
class Person{
constructor(){
}
get aaa(){
return 'aaa属性'
}
set aaa(val){
console.log(`你设置了aaa这个属性,值是${val}`);
}
}
let p=new Person();
p.aaa=123;
console.log(p.aaa);
</script>
8.类里面还有个静态方法给类Person调用的,上面几个例子里面的方法都是给对象实例p调用的
1.定义静态方法只需要加一个static
17.类的继承class Student2 extends Person2{}
1.子类继承父类注意事项
1.子类的constructor里面必须执行一遍super(args);作用是把父类的参数拿过来,如果不拿就会被覆盖还会报错
2.因为子类需要有自己的单独东西,所以上面的一步super(args)必不可少
3.子类如果有方法跟父类一样就会覆盖子类的方法,但是可以在子类里面调用super.showName();
4.super这个对象代替的是父类
18.es6新增的一个数据类型symbol 使用情况一般 node底层用的多
1. let syml = Symbol('aaaa');
console.log(syml);
2.Symbol('aaaa');不能加new
3.Symbol()返回值是一个唯一的值,可以作为对象的key,如果symbol作为对象的key那么使用for in循环无法遍历出symbol
19.generator函数 生成器 用于解决异步问题,深度嵌套问题 function * show(){}
1.generator定义 gen函数执行后返回是个对象
<script>
function * gen(){
yield 'welcome';
yield 'to';
return '买买买'
}
//使用方法
let g = gen();
console.log(g.next());//{value: "welcome", done: false}
console.log(g.next());//{value: "to", done: false}
console.log(g.next());//{value: "买买买", done: true}
</script>
2.上面是手动调用,比较麻烦,使用for..of..可以遍历generator但是return不会遍历出来
3.generator是迭代器
4.还可以通过解构来访问到generator里面的内容let [a,b,c] = gen();解构也解构不到return的值,还可以直接...gen()
5.还可以直接转成数组Array.from(gen());
6.异步:不连续,上一个操作没有执行完,下一个操作照样开始执行
7.同步:连续,上一个操作没有执行完,下一个不能开始
8.关于异步
1.回调函数
2.事件监听
3.发布订阅
4.promise对象
4.1generator
5.async es2017提供
20.async 异步 配合await使用
1.解决异步的几个方法promise generator async
let fs = require('fs');
function readFile(fileName){
return new Promise((resolve,reject)=>{
fs.readFile(fileName,(err,data)=>{
if(err){
reject(err);
}else{
resolve(data);
}
});
});
}
readFile('data/1.txt').then(res=>{
console.log(res.toString());
return readFile('data/2.txt');
}).then(res=>{
console.log(res.toString());
});
function * gen(){
yield readFile('data/1.txt');
yield readFile('data/2.txt');
}
let g1 = gen();
g1.next().value.then(res=>{
console.log(`这个是generator函数读取的数据${res.toString()}`);
return g1.next().value;
}).then(res=>{
console.log(`这个是generator函数读取的数据${res.toString()}`);
});
async function fn(){
let f1 = await readFile('data/1.txt');
console.log(`这个是async读取的数据${f1.toString()}`);
let f2 = await readFile('data/2.txt');
console.log(`这个是async读取的数据${f2.toString()}`);
}
fn();
2.async特点
1.await只能放到async里面
let f1 = await readFile('data/1.txt');
2.相比于generator语义化更强
3.await后面可以是promise对象,也可以是数字、字符串
4.async函数返回值是一个promise对象
5.只要await语句后面的promise状态变成reject
6.解决async抛出错误可以使用try{}catch{} 也可以是promise本身的catch
7.有await语句建议都建议使用try{}catch{}
21.es6新增的数据结构,数组和对象都是一种数据结构
1.新增的set数据结构,类似数组但是里面不能有重复值,会自动去重
2.set用法let setArr = new Set(['a','b','c']);
3.set数据结构是有keys的默认keys和values相等
4.他也有forEach()方法
5.允许连续调用
6.可以用来数组去重
7.官方建议new Set([]) 如果存储对象就会出错,但是可以使用add方法添加
8.官方建议new WeakSet({}) 可以存对象,但是也是只能使用add添加,不能直接{} 开发不建议使用这个,它没有size属性,也没有clear
9.set数据结构类似数组
<script>
let setArr = new Set(['a','b','c']);
console.log(setArr);
setArr.add('d');
console.log(setArr);
setArr.delete('b');
console.log(setArr);
console.log(setArr.has('b'));
console.log(setArr.size);
console.log(setArr);
console.log('--------');
setArr.clear();
console.log(setArr);
console.log('----数组去重----');
let arr = [1,2,3,4,5,1,2,1,2,3,4];
let newArr = [...new Set(arr)];
console.log(newArr);
console.log('----set数据结构变成数组然后数组可以使用map----');
let setArr1 = new Set(['a','b','c']);
let newset1 = new Set([...setArr1].map(val=>val+'6'));
console.log(setArr1);
console.log(newset1);
console.log('----set数据结构中存入对象----');
let json = {
a : 1,
b : 2
}
let json1 = {
a : 'apple',
b : 'banana'
}
let sset = new Set();
sset.add(json).add(json1);
console.log(sset);
sset.forEach(item=>{
console.log(item);
})
</script>
22.es新增数据结构map类似对象
1.传统的对象的key只能是字符串,map的key可以是任意类型
<script>
let map = new Map();
let json = {
a : 1,
b : 2
}
map.set('key','value');
console.log(map);
map.set(json,'aaa');
map.set('aaa',json);
console.log(map);
console.log(map.get('key'));//按key获取value
map.delete('key');
console.log(map.has('key'));
console.log(map);
//map.clear();//清空
console.log(map);
for(let [key,value] of map){
console.log(key,value);
}
for(let key of map.keys()){}
for(let value of map.values()){}
for(let [key,value] of map.entries()){}
map.forEach((val,index)=>{});
</script>
2.新增set和get方法用于设置值和获取值
3.map也有WeakMap WeakMap的key只能是对象
4.总结
1.Set对应的是数组,不能重复,没有key 没有get方法
2.Map对象的是对象,是对对象功能的增强,key可以是任意类型
<script>
let map = new Map();
let json = {
a : 1,
b : 2
}
map.set('key','value');
console.log(map);
map.set(json,'aaa');
map.set('aaa',json);
console.log(map);
console.log(map.get('key'));//按key获取value
map.delete('key');
console.log(map.has('key'));
console.log(map);
//map.clear();//清空
console.log(map);
for(let [key,value] of map){
console.log(key,value);
}
for(let key of map.keys()){}
for(let value of map.values()){}
for(let [key,value] of map.entries()){}
map.forEach((val,index)=>{});
</script>
23.es6数字的变化
1.以往很多方法都挂到了Number身上
<script>
let a = 0b10;//二进制
let b = 0o11;//八进制
console.log(a);
console.log(b);
console.log(Number.isNaN(a));
console.log(Number.isFinite(b));//判断a是不是数字,不会进行类型转换
console.log(Number.isInteger(a));//判断a是不是整数
Number.parseInt();
Number.parseFloat();
Number.isSafeInteger();
Number.MAX_SAFE_INTEGER();
Number.MIN_SAFE_INTEGER();
</script>
2.安全整数-(2**53-1)---(2**53-1)判断安全整数的方法Number.isSafeInteger();
3.Math变化
<script>
let a = 2.55;
let b = -2.55;
let c = 9;
Math.abs(a);//取绝对值
console.log(Math.sqrt(c));//开方
Math.trunc(a);//截断,只保留整数部分,不进行四舍五入
Math.sign(a);//判断一个数是正数还是负数,不是数字返回NaN
Math.cbrt(27);//开立方根
</script>
24.es2018新增的东西(es9)
1.命名捕获 正则表达式里面的新增的东西 语法(?<名字>)
2.反向引用命名捕获 语法\k<名字>
3.想要配合正则表达式里面的replace之前是$1,$2现在如果使用命名捕获那么就是$<名字>
4.之前的.代表的是匹配所有,但是回车换行无法匹配
5.es2018出来一个dotAll模式改正了.可以匹配所有字符,包括换行回车,需要配合let reg = /\w.\w/s;let str = 'aa\naa';
6.标签函数function fn(){} 但使用上有区别,fn`aaa`
<script>
function fn(args){
console.log(args);
console.log(args[0].toUpperCase())
}
fn`welcome`;
</script>
25.Proxy 代理 封装框架用的多
1.设计模式的一种 代理模式
2.作用:比如vue中的拦截 其他的如预警、上报、扩展功能、统计,增强对象功能
3.使用
1.new Proxy(target,handle);target是被代理的对象,handel是对代理对象做什么操作
4.代理拦截函数时需要配合Reflect反射
5.Reflect.apply(要调用的函数,this指向,[]);变着法调用函数
<script>
function show(...args){
console.log(this);
console.log(args);
}
show(1,2,3,4);
show.call('aaa',1,2,3,4);
show.apply('aaaaa',[1,2,3,4]);
Reflect.apply(show,'bbbb',[1,2,3,4,55]);
</script>
26.1判断属性是否存在 属性 in {}