ES全称EcmaScript,是脚本语言的规范,而平时经常编写的EcmaScript的一种实现,所以ES新特性其实就是指JavaScript的新特性。
1.ES6版本变动内容最多,具有里程碑意义。
2.ES6加入了许多新的语法特性,编程实现更简单,高效
3.ES6是前段开发的趋势,就业必备
ES6允许按照一定模式从数组和对象中提取值,对变量进行赋值
es6允许直接在大括号里面直接写入变量和函数,作为对象的属性和方法,简化程序员书写代码的步骤。
es6允许使用 [箭头] (=>) 定义函数
一、this是静态的,this始终是指向函数声明时所在作用域下的this的值,箭头函数的this值是静态的,无论使用使用任何方式去调用它,它的this始终是指向函数在声明时所在作用域下的那个this值。
直接调用:
call方法调用:可以改变函数内部this的值,下面的结果可以看出call不能改变箭头函数中this的指向。
二、箭头函数不能作为构造函数来实例化对象
三、不能使用arguments变量【函数内部特殊的变量arguments,用来保存实参】
四、箭头函数的简写,两种情况
第一种:是省略小括号,当形参有且只有一个的时候可以省略。
第二种:是省略花括号,当代码体只有一条语句的时候,此时return必须省略,而且语序的执行结果就是函数的返回值。
箭头函数使用注意事项:
一、 箭头函数适用于this无关的回调,定时器,数组方法的回调
二、 箭头函数不适合与thi有关的回调,事件回调,对象的方法
es6中允许给函数参数赋值初始值
es6引用rest参数,用于获取函数的实参,用来代替arguments【获取函数在调用时所有的实参】
【…】扩展运算符能将【数组】转换成逗号分割的【参数序列】。
一、 symbol的值是唯一的,用来解决命名冲突问题。
二、symbol的值不能与其他数据进行运算。
三、symbol定义的对象属性不能使用for…in循环遍历,但是可以使用Reflect.ownKeys来获取对象的所有键名
第二种创建方式:其中括号内只是symbol的标志
第三种方式:【Symbol.for()】,symbol.for是一个全局的symbol表,如果有了就访问对应对象,如果没有就创建。
使用symbol添加对象和属性,我们可以很快速的很安全的把对象加入game里面,不会破坏原有的属性和方法。
除了定义自己使用的Symbol值以外,ES6还提供了很多内置的Symbol值,指向语言内部使用的方法。
迭代器是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据解构只要部署iterator接口,就可以完成遍历操作。
a. 创建一个指针,指向当前数据结构的起始位置。 b. 第一次调用对象的next方法,指针自动指向数据结构的第一个成员, c. 接下来不断调用next方法,指针一直往后移动,知道只想最后一个成员。 d. 每调用next方法返回一个包含value和done属性的对象 **注意:需要自定义遍历数据的时候要想到迭代器**
根据迭代器的工作原理自定义迭代器遍历数据
<script>
//声明一个对象
const banji = {
name:"终极一班",
stus:['小明','小天','小吴','小王',],
[Symbol.iterator](){
//索引变量
let index = 0;
//指向
let _this = this;
return {
next:function(){
if(index<_this.stus.length){
const result = {value:_this.stus[index],done:false}
//下标自增
index++;
//返回结果
return result;
}else{
return {value:undefined,done:true}
}
}
}
}
}
//遍历这个对象
for(let v of banji){
console.log(v);
}
</script>
生成器函数是ES6提供的一种异步编程解决方案,语法行为与传统函数完全不同,其实就是一个特殊的函数,用来异步编程,之前用的是纯回调函数
node \fs \ ajax\mongodb
生成器调用的next是可以传递实参的,而这个实参数就是这个yield语句整个返回结果。
异步编程:文件操作,网络操作(ajax,request)数据库操作
实例:1s输出111 ,2s输出222,3s输出333
层层回调,会变成回调地狱
上面代码会进入回调地狱,下面就不行
实例二、模拟获取,用户数据,订单数据,商品数据
调用:
promise是ES6引入的异步编程的新解决方案,语法上市promise是一个构造函数,用来封装异步操作并可以获取奇成功或失败的结果【解决回调地狱问题】
- Promise构造函数 :
Promise {excutor}{ }
Promise.prototype.then
方法Promise.prototype.catch
方法
1. 实例化Promise对象
Promise对象有三个状态,初始化,成功,失败
实例化promise对象:
//实例化Promise对象【三个状态:初始化,成功,失败】
const p = new Promise(function(resolve,reject){
setTimeout(() => {
let data = "数据库中的用户数据"
//resolve调用
resolve(data);
}, 1000);
});
调用成功和失败都会执行promise.then的方法,then的方法有两个参数,两个参数都是函数类型的值,每个函数都有一个形参,成功的执行then的第一个函数,失败的执行第二个执行参数,两个函数的形参分别是value和reason,成功的叫做value,失败的叫做reson。
调用then代码:
/*
调用成功,就会调用promise对象的then方法,
then方法接受两个参数,
两个参数都是函数类型的值,每个函数都有一个形参,成功的叫做value,失败的叫做reason
调到resolve代表成功,读取状态成功,then就会执行第一个回调函数代码
如果读取状态失败,调用带有
*/
p.then(
function(value){
console.log(value);
},
function(reason){
}
)
成功调用输出:
读取失败的例子:
const p = new Promise(function(resolve,reject){
setTimeout(() => {
//
let data = "数据库中的用户数据"
let err = "读取数据库失败"
//resolve调用
reject(err)
}, 1000);
});
p.then(function(value){
console.log(value);
},function(reason){
console.log(reason);
})
原生js输出文件内容【请求文件内容属于异步】
//引入fs模块
const fs = require('fs');
//调用方法读取文件
fs.readFile('./resources/1.md',(err,data)=>{
//如果失败则抛出错误
if(err) throw err;
//如果没有出错,则输出内容
console.log(data.toString());
})
//3.使用promise封装
const p = new Promise(function(resolve,reject){
fs.readFile("./resources/1.md",(err,data)=>{
//判断读取失败
if(err) reject(err);
//如果成功
resolve(data)
})
})
p.then(
function(value){
console.log(value.toString());
},
function(reason){
console.log(reason);
})
<script>
//接口地址:https://api.apiopen.top/getJoke
//创建对象
const xhr = new XMLHttpRequest();
//初始化
xhr.open("GET","https://api.apiopen.top/getJoke");
//发送
xhr.send();
//4.绑定时间,处理响应结果
xhr.onreadystatechange = function(){
//判断
if(xhr.readyState === 4){
//判断响应状态吗 200-299
if(xhr.status >= 200 && xhr.status < 300){
//表示成功
console.log(xhr.response);
}else{
//如果失败
console.log(xhr.status);
}
}
}
</script>
请求成功效果:
请求失败结果:
2. Promise进行封装Ajax代码
<script>
//接口地址:https://api.apiopen.top/getJoke
const p = new Promise((resolve,reject)=>{
//创建对象
const xhr = new XMLHttpRequest();
//初始化
xhr.open("GET","https://api.apiopen.top/getJoke");
//发送
xhr.send();
//4.绑定时间,处理响应结果
xhr.onreadystatechange = function(){
//判断
if(xhr.readyState === 4){
//判断响应状态吗 200-299
if(xhr.status >= 200 && xhr.status < 300){
//表示成功
resolve(xhr.response)
}else{
//如果失败
reject(xhr.status);
}
}
}
});
//指定回调
p.then(
function(value){
console.log(value);
},
function(reason){
console.log(reason);
})
</script>
成功效果:
失败效果:
处理方式不一样,原来是在回调函数里面处理成功和失败的结果,promise实在异步任务的后面通过then来指定回调,结构清晰,也不会产生回调地狱的问题。
then返回结果:返回结果是由执行函数的回调结果来决定的,如果回调函数中返回的结果是 ||promise类型的属性,状态为成功,返回值为对象的成功值。
then返回非Promise对象
//创建promise对象
const p = new Promise((resolve,reject)=>{
setTimeout(()=>{
//resolve("请求成功")
reject("请求失败")
},1000)
});
//调用 then方法
const result = p.then(value =>{
console.log(value);
return value;
},reason =>{
console.log(reason);
return reason;
})
console.log(result);
不写return
返回undefined
结果:
3. then返回Promise对象
then返回Promise对象,then中promise的状态就决定了then方法返回的一个对象的状态,then中Promise的失败就决定了then方法返回的一个失败的状态。
//创建promise对象
const p = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve("请求成功")
//reject("请求失败")
},1000)
});
//调用 then方法
const result = p.then(value =>{
return new Promise((resolve,reject)=>{
resolve('ok')
})
},reason =>{
console.log(reason);
})
console.log(result);
4. then抛出错误
【如果抛出错误的话,这个状态也是一个失败的Promise状态,错误的值就是抛出的值】
//创建promise对象
const p = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve("请求成功")
//reject("请求失败")
},1000)
});
//调用 then方法
const result = p.then(value =>{
//抛出错误
throw new Error("出错啦")
},reason =>{
console.log(reason);
})
console.log(result);
效果:
既然then的方法可以返回promise对象,所以说then方法可以链式调用,链式调用[then方法指定回调的时候是可以只指定一个的,可以通过链式调用来改变回调地狱的问题]
格式:
p.then(value=>{
//异步任务
},reason=>{
//异步任务
}).then(value=>{
//异步任务
},reason=>{
//异步任务
})
//回调地狱容易重名,很不容易被发现
//引入fs模块
const fs = require("fs")
fs.readFile('./resources/1.md',(err,data)=>{
fs.readFile('./resources/2.md',(err,data1)=>{
fs.readFile('./resources/3.md',(err,data2)=>{
let result = data+"\r\n"+data1+"\r\n"+data2
console.log(result);
});
});
});
上面代码可以发现 ,回调地狱容易重名,很不容易被发现。
Promise实现:
//使用promise来实现
const p = new Promise((resolve,reject)=>{
fs.readFile("./resources/1.md",(err,data)=>{
resolve(data);
})
})
p.then(value=>{
return new Promise((resolve,reject)=>{
fs.readFile("./resources/2.md",(err,data)=>{
resolve([value,data]);
});
});
}).then(value=>{
return new Promise((resolve,reject)=>{
fs.readFile("./resources/3.md",(err,data)=>{
//压入
value.push(data);
resolve(value)
});
});
}).then(value=>{
console.log(value.join('\r\n'));
})
catch用来指定promise失败的一个回调
第一种方式代码:
<script>
const p = new Promise((resolve,reject)=>{
setTimeout(()=>{
//设置p对象的状态为失败,并且设置失败的值
reject("出错啦")
})
})
p.then(function(value){
},function(reason){
console.error(reason);
})
</script>
第二种方式代码:
<script>
const p = new Promise((resolve,reject)=>{
setTimeout(()=>{
//设置p对象的状态为失败,并且设置失败的值
reject("出错啦")
})
})
p.catch(function(reason){
console.warn(reason);
})
</script>
set介绍
ES6提供了新的数据结构Set(集合)。它类似于数组,但成员的值都是唯一的集合实现了iterator接口,所以可以使用[扩展运算符]和[for…of…]进行遍历
集合的属性和方法:
1)size: 返回集合的元素个数
2)add: 郑加一个新元素,返回当前集合
3)delete: 删除元素,返回boolean值
4)has:检测集合中是否包含某个元素,返回boolean值
简单通过代码了解Set:
//声明一个set
let s = new Set();
//可以写入可迭代数据,可以去重
let s2 = new Set(['大事儿','小事儿','坏事儿','小事儿','很多事儿','大事儿'])
console.log(s,typeof s);
console.log(s2);
//元素个数
let s2 = new Set(['大事儿','小事儿','坏事儿','小事儿','很多事儿','大事儿'])
console.log(s2.size);
//向集合里添加新的元素
s2.add("喜事儿")
console.log("集合添加后有:"+s2.size+"个",s2);
//删除元素
s2.delete("坏事儿")
console.log("集合删除后有:"+s2.size+"个",s2);
//检测【检测集合中有没有该元素】
console.log(s2.has('喜事儿'));
//可以使用for...of...遍历
for(let v of s2){
console.log(v);
}
//清空集合
s2.clear();
console.log(s2);
已经知道两个数组:
let arr = [1,2,3,4,5,4,3,2,1,5,4,5,8,9,54,4,1]
let arr2 = [54,1,3,4,6,9,8]
//1.数组去重
let result = [...new Set(arr)]
console.log(result);
//2.交集
let arr2 = [54,1,3,4,6,9,8]
let result2 = [...new Set(arr)].filter(item=>{
let s2 = new Set(arr2)
if(s2.has(item)){
return true
}else{
return false
}
})
console.log(result2);
//简化版求交集
let result3 =[...new Set(arr)].filter(item=>new Set(arr2).has(item))
console.log(result3);
//3.并集
let result4 =[...new Set([...arr,...arr2])]
console.log(result4);
//4.差集
let result5 = [...new Set(arr)].filter(item=>{
let s2 = new Set(arr2)
if(!s2.has(item)){
return true
}else{
return false
}
})
let result6 =[...new Set(arr)].filter(item=>!new Set(arr2).has(item))
console.log(result5);
console.log(result6);
es6提供了map数据结构,它类似于对象,也是键值对的集合,但是"键"的范围不限于字符串,各种类型的值(包括对象)都可以当做键,map也实现了iterator接口,所以可以使用【扩展运算符】和【for…of…】进行遍历,map的属性和方法:
//声明 Map
let m = new Map();
//添加元素
m.set('name','吴又可');
m.set('change',function(){
console.log("无用的方法");
});
console.log(m);
//声明 Map
let m = new Map();
//添加元素
m.set('name','吴又可');
m.set('change',function(){
console.log("无用的方法");
});
let key = {
school : "sgg"
};
m.set(key,['北京','上海','广州']);
console.log(m);
//添加
m.set(key,['北京','上海','广州']);
//删除
m.delete('name')
console.log(m);
//获取
console.log(m.get('change'));
console.log(m.get(key));
//遍历
for(let v of m){
console.log(v);
}
//清空
m.clear();
es6提供了更接近传统语言的写法,引入了Class类这个概念,作为对象的模板,通过class关键字,可以定义类,基本上,es6的class可以看做只是一个语法糖,它的绝大部分功能,es5都可以做到,新的class写法只是让对象的圆形的写法更加清晰,更像面向对象编程的语法而已。
知识点:
(1) class声明类
(2) constructor定义构造函数初始化
(3) extends继承父类
(4) static定义静态方法和属性
(5) super调用父级构造方法
(6) 父类方法可以重写
回顾Es6类的使用
// 手机
function Phone(brand,price){
this.brand = brand;
this.price = price;
}
//添加方法
Phone.prototype.call = function(){
console.log("我可以打电话");
}
//实例化对象
let Huawei = new Phone('华为',5999);
Huawei.call();
console.log(Huawei);
// class
class Phone{
//构造方法,名字不能修改,当实例化的时候会自动执行
constructor(brand,price){
this.brand = brand;
this.price = price;
}
//方法必须使用该语法,不能使用es5的对象完整形式
call(){
console.log("我可以打电话");
}
}
let onePlus = new Phone("huawei",4999);
console.log(onePlus);
es5中的静态成员
es5中实例对象和函数对象的属性是不相通的,实例对象的属性和构造函数的原型对象相通,实例对象的隐式原型指向构造函数的原型对象
function Phone(){
}
Phone.name = "手机";
Phone.change = function(){
console.log("我可以改变世界");
}
Phone.prototype.size = "5.5inch"
let nokia = new Phone();
console.log(nokia.name);
console.log(nokia.size);
npkia.change();