ES6/ES7内容解析
一、变量/赋值
1、变量
ES6在之前用于定义变量关键字var的基础上新增了let和const关键字。其比较如下:
var:定义变量,可多次赋值,有变量提升功能,可重复定义,无块级作用域
let:定义变量,可多次赋值,无变量提升,有暂时性死区,不可重复定义,块级作用域
const:定义常量,定义的时候就需要赋值,赋值之后不可修改,,无变量提升,有暂时性死区,不可重复定义,块级作用域
块级作用域就是作用域在{}里边。
2、解构赋值
- 左右两边必须一样
- 定义和赋值必须同步完成
let [a,b,c] = [12,5,8]; // a=12,b=5,c=8
let arr = [2,3,4];
let [e,f,g] = arr; // e=2,f=3,g=4
let {a, b, c} = {a:5,b:12,c:88}; // a=5,b=12,c=88
// let {a, b, c} = {5,12,88}; //会报错,因为等号右边不是一个对象,即不是一个合规的东西
//let {a, b, c};
//{a, b, c} = {a:5,b:12,c:88}; // 报错,因为声明和赋值没有同时完成
let [a, b, c] = [12, {a:{n1:5, n2:8}, b:12, c:8},99]; //a=12,b ={a:{n1:5, n2:8}, b:12,c:8},c=99
二、函数
1、箭头函数
//普通函数写法
function 函数名(参数1,参数2){
函数体
}
// 或者
let 函数名 = function(参数1,参数2){
函数体
}
// 箭头函数写法
(参数1,参数2) => {
函数体
}
// 或者
let 函数名 = (参数1,参数2) =>{
函数体
}
- 如果有且仅有一个参数,可以省略()
- 如果函数体仅有一条语句,而且该语句是return,可以省略{}和return
let arr = [2,5,3,7,1,9,44,88,33];
arr.sort((n1, n2) => {return n1-n2;});
// 可以简写为:
arr.sort((n1, n2) => n1-n2); // 1,2,3,5,7,9,33,44,88
// 另一个例子
let show = function(a){
return a * 3;
}
alert(show(13)); // 39
// 等价于
let show = a => a * 3; // 即给我一个a,给你一个a*3
alert(show(13)); // 39
2、默认参数
- 常见的默认参数写法
function show(a,b,c){
// 给b的默认参数为5,写法有以下3种
b = b || 5;
//if(!b){
// b = 5;
//}
//b||=5;
c||=9;
console.log(a,b,c);
}
alert(show(12)); //12,5,9
alert(show(12,7,6)); //12,7,6
- 新的默认参数方法
function show(a,b=5,c=9){
console.log(a,b,c);
}
alert(show(12)); //12,5,9
alert(show(12,7,6)); //12,7,6
3、参数展开(剩余参数,数组展开)
- "三个点"的第一个作用:用来接收剩余参数
剩余参数必须在参数列表的最后位置
function show(a,b,...args){
console.log(a,b,args);
}
show(12,37,33,55,88,11); // 12,37,[33,55,88,11]
- "三个点"的第二个作用:展开一个数组
let arr = [12,5,8];
//...arr 完全等价于 12,5,8
let arr2 = [...arr,5,...arr, 7,8]; // 12,5,8,5,12,5,8,7,8
let arr3 = [5,6,7];
arr3.push(...arr); // 5,6,7,12,5,8
function show1(...args){
show2(args);
}
function show2(a,b){
console.log(a,b);
}
show1(12,5); //12,5
三、数组/JSON
1、 数组
数组共新增了5种方法:均是生成一个新数组,原数组不变。
- map:映射,即一一对应,一个对一个
let arr = [12,55,88,77];
let arr2 = arr.map(item => item >= 60); // arr2为arr中分数是否及格
console.log(arr2); // false,false,true,true
- filter:过滤,即进去一堆,出来一堆符合条件的
let arr = [12,55,88,77];
let arr2 = arr.filter(item => item % 2 === 0); // arr2为arr中为偶数的数
console.log(arr2); // 12,88
- forEach:遍历,对数组的每一项走一遍,类似于普通的for循环,没有返回值
let arr = [12,55,88,77];
let sum =0;
arr.forEach(item => {
sum = sum + item;
});
console.log(sum); // 232
- reduce:汇总,即进去一堆,出来一个
用途:
- reduce()方法可以搞定的东西特别多,就是循环遍历能做的,reduce都可以做,比如数组求和、数组求积、统计数组中元素出现的次数、数组去重等等。
用法:
- reduce() 方法对数组中的每个元素执行一个由您提供的reduce函数(依次执行),将其结果汇总为单个返回值。 reduce 为数组中的每一个元素依次执行回调函数,接受四个参数:初始值 initialValue(或者上一次回调函数的返回值),当前元素值cur,当前索引index,调用 reduce 的数组arr。
参数:
- 参数一: callback 函数(执行数组中每个值的函数,包含四个参数):
prev 必需 (上一次调用回调返回的值,或者是提供的初始值(initialValue))
cur 必需(数组中当前被处理的元素)
index 可选 (当前元素在数组中的索引)
arr 可选 (调用 reduce 的数组)- 参数二:initialValue 可选 (表示初始值,作为第一次调用 callback 的第一个参数。)
提供初始值,cur 从数组第一项开始,若不提供初始值,则 cur 从第二项开始执行,对应的第一次 prev 是数组第一项的值
// 求和(带一个参数)
let arr = [12,55,88,77];
let sum = arr.reduce((initialValue,cur,index) => {
console.log("initialValue=",initialValue," cur=",cur," index=",index);
// initialValue= 12 cur= 55 index= 1
// initialValue= 67 cur= 88 index= 2
// initialValue= 155 cur= 77 index= 3
return initialValue + cur;
});
console.log(sum); // 232
// 求平均值
let arr = [12,55,88,77];
let avg = arr.reduce((initialValue,cur,index) => {
console.log("initialValue=",initialValue," cur=",cur," index=",index);
// initialValue= 12 cur= 55 index= 1
// initialValue= 67 cur= 88 index= 2
// initialValue= 155 cur= 77 index= 3
if(index < arr.length - 1){
return initialValue + cur;
}else{
return (initialValue + cur) / arr.length;
}
});
console.log(avg); // 58
// 求和(带两个参数)
let arr = [12,55,88,77];
let sum = arr.reduce((initialValue,cur,index) => {
console.log("initialValue=",initialValue," cur=",cur," index=",index);
// initialValue= 10 cur= 12 index= 0
// initialValue= 22 cur= 55 index= 1
// initialValue= 77 cur= 88 index= 2
// initialValue= 165 cur= 77 index= 3
return initialValue + cur;
}, 10);
console.log(sum); // 242
reduce是一个对数组累积操作的方法,使用时要加上 return 返回累积操作的数据。这样 prev 才能获取上一次执行的结果,否则是 undefined
let arr = [12,55,88,77];
let sum = arr.reduce((initialValue,cur,index) => {
console.log("initialValue=",initialValue," cur=",cur," index=",index);
// initialValue= 12 cur= 55 index= 1
// initialValue= undefined cur= 88 index= 2
// initialValue= undefined cur= 77 index= 3
});
console.log("sum=",sum); // undefined
空数组执行 reduce 操作且不提供初始值时reduce会报错
let arr = [];
let sum = arr.reduce((initialValue,cur,index) => {
// Uncaught TypeError: Reduce of empty array with no initial value
// at Array.reduce (<anonymous>)
// at <anonymous>:2:15
console.log("initialValue=",initialValue," cur=",cur," index=",index);
});
空数组执行 reduce 操作但是设置了初始值就不会报错
let arr = [];
let sum = arr.reduce((initialValue,cur,index) => {
console.log("initialValue=",initialValue," cur=",cur," index=",index);
return initialValue + cur;
}, 0);
console.log("sum=",sum," arr=",arr); // 0 []
- from:即Array.from,可以把一个拥有length属性的对象或可迭代的对象(即类数组)变成一个真正的数组。
语法
- Array.from(object, mapFunction, thisValue);
参数:
- object:必需,要转换为数组的对象。
- mapFunction:可选,数组中每个元素要调用的函数。
- thisValue:可选,映射函数(mapFunction)中的 this 对象。
// 数组去重
var setObj = new Set([1, 2, 3,4,1,2]); // 集合中没有重复的元素,实现去重,不过数组变成了set集合
var objArr = Array.from(setObj); // 将set集合转化为数组类型
console.log("objArr=",objArr); // objArr=[1,2,3,4]
// 用箭头语法和映射函数更改元素的值。
let arr = [1,2,3];
var arr1 = Array.from(arr, x => x * 10);
console.log("arr=",arr," arr1=",arr1); // arr=[1,2,3] arr1=[10,20,30]
2、JSON
两个变化:
- 简写:名字和值一样的情况下,可以只写名字;
- 方法中的function可以不写
let a = 12;
let b = 5;
let json = {a:a, b:b}
console.log("json=",json); // json= {a: 12, b: 5}
// 简写
let json = {a, b}
console.log("json=",json); // json= {a: 12, b: 5}
let JSON = {
a:12,
b: 5,
show: function(){
console.log("a+b=", a+b)
}
}
JSON.show(); // a+b= 17
// 方法中的function可以不写
let JSON = {
a:12,
b: 5,
show(){
console.log("a+b=", a+b)
}
}
JSON.show(); // a+b= 17
四、字符串
1、字符串模版
2个特点:
- 植入变量
- 任意折行
// 植入变量
let json = {
name: "张三",
age: 18,
};
console.log("我叫"+json.name+",我今年"+json.age+"岁"); // 我叫张三,我今年18岁
//等价于
console.log(`我叫${json.name},我今年${json.age}岁`); // 我叫张三,我今年18岁
// 任意折行:原样打印
console.log(`abc
cd
efg`);
//abc
// cd
// efg
2、字符串方法
两个方法:
- startsWith(): 判断字符串是否以某些特定字符开头;
- endsWith(): 判断字符串是否以某些特定的字符结尾;
let str = "13567899090";
if(str.startsWith("135")){
console.log("移动");
}else{
console.log("联通");
}
// 移动
let str1 = "file.txt";
if(str1.endsWith(".txt")){
console.log("文本");
}else{
console.log("其他");
}
// 文本
五、面向对象
1、类
传统的面向对象的JS是一个方法,而且是通过prototype属性为对象添加方法。
// 传统的创建对象的方法
function Person(name,age){
this.name = name;
this.age = age;
}
Person.prototype.showName = function(){
console.log(`我叫${this.name}`);
}
Person.prototype.showAge = function(){
console.log(`我${this.age}岁`);
}
let p1 = new Person("zhangsan",17);
console.log("p1.name=", p1.name); // p1.name= zhangsan
// 传统的继承
function Worker(name,age,job){
Person.call(this,name,age);
this.job = job;
}
Worker.prototype = new Person();
Worker.prototype.constructor = Worker; // 设置构造函数
Worker.prototype.showJob = function(){
console.log(`我从事${this.job}工作`);
}
let p2 = new Worker("blue",18,"打杂");
console.log("p2.job=", p2.job); //p2.job= 打杂
- class:
ES6新增了一个关键字class,用于创建类对象。- constructor:
constructor是构造函数。- extend:
ES6新增了关键字extends,用于继承父类。- super:
super超类,即父类(父类的构造函数)。
class Person{
constructor(name,age){
this.name = name;
this.age = age;
}
showName(){
console.log(`我叫${this.name}`);
}
showAge(){
console.log(`我${this.age}岁`);
}
}
let p3 = new Person("pink", 13);
console.log("p3.name=", p3.name," p3.age=",p3.age); // p3.name= pink p3.age= 13
class Worker extends Person{
constructor(name,age,job){
super(name,age); // 超类,代表父类的构造函数
this.job = job;
}
showJob(){
console.log(`我是从事${this.job}工作的。`);
}
}
let p4 = new Worker("black",20,"web");
p4.showJob(); // 我是从事web工作的。
2、bind()
bind():给函数绑定一个固定的this
3、箭头函数的this
- 普通函数的this:根据调用我的人走,即谁调用我this就是谁,this老变
// 普通函数必须有人调用它才知道this是谁
function (){
console.log(this); // this不知道是谁,因为没有人调用它
}
setTimeout(function (){
console.log(this); // Window,因为setTimeout其实是window.setTimeout
}, 50);
document.onclick = function (){
console.log(this); // document,因为document在调用它
}
let arr = [12,5,8,99];
arr.a = function (){
console.log(this);
}
arr.a(); // [12, 5, 8, 99, a: ƒ] this取决于谁调用它
- 箭头函数的this:根据我所在的环境,我的环境是谁this就是谁,this恒定
() => {
console.log(this); // Window 该箭头函数处在全局window的环境下,因此this就是window
}
document.onclick = () => {
console.log(this); // Window,根据所在的环境是window
}
let arr = [12,5,8,99];
arr.a = () => {
console.log(this);
}
arr.a(); // Window
document.onclick = function (){
let arr = [1,2,3];
arr.a = () => {
console.log(this); // document,因为箭头函数在document里边,也就是当前环境是document
}
arr.a();
}
// 箭头函数的优先级比bind高(类似于bind失效了)
document.onclick = function (){
let a = () => {
console.log(this); //此处的this是document
}
setTimeout(a.bind(12), 50); // document,bind改变this失效,因为箭头函数的优先级比bind优先级高
}
六、promise
promise:可以将一个异步操作同步化,即同步的写法,异步的执行顺序。
- 同步:串行------一个事情没有做完不能开始另一件事情------简单、方便
- 异步:并发------一个事情阻塞了,可以开始另一件事情------性能高、体验好
//普通的异步
$.ajax({
url: '/banner_data',
success(banners){
$.ajax({
url: '/user_data',
success(user){
$.ajax({
url: '/items_data',
success(items){
$.ajax({
url: '/news_data',
success(news){
console.log("数据获取成功");
},
error(){
console.log("数据获取失败");
}
})
},
error(){
console.log("数据获取失败");
}
})
},
error(){
console.log("数据获取失败");
}
})
},
error(){
console.log("数据获取失败");
}
})
// 同步
let banners = $.ajax({url: '/banner_data'});
let user = $.ajax({url: '/user_data'});
let items = $.ajax({url: '/items_data'});
let news = $.ajax({url: '/news_data'});
// promise: 用同步的方法写异步
// 1、创建new一个promise对象
// 2、promise有一个回调函数,回调函数有两个参数,一个是resolve成功,一个是reject失败
let p = new promise((resolve, reject) => {
$.ajax({
url: '/banner_data',
dataType: 'json', // 设置解析json
success(json){ // 请求成功的时候调用
resolve(json);
},
error(err){ // 请求失败的时候调用
reject(err);
}
});
});
// then表示promise对象内部的操作完成了之后,就会调用then里边的回调函数,成功调用第一个函数(resolve),失败调用第二个函数(reject)
p.then(json => {
// json是resolve传出来的
console.log("成功");
},
err => {
console.log("失败");
});
//Promise.all([])是promise对象上的一个方法,接收一个数组作为参数,数组是一堆promise对象,all是当所有的promise对象执行结束之后执行then方法。
let p1 = new promise((resolve, reject) => {
$.ajax({
url: '1.txt',
dataType: 'json', // 设置解析json
success(json){ // 请求成功的时候调用
resolve(json);
},
error(err){ // 请求失败的时候调用
reject(err);
}
});
});
let p2 = new promise((resolve, reject) => {
$.ajax({
url: '2.txt',
dataType: 'json', // 设置解析json
success(json){ // 请求成功的时候调用
resolve(json);
},
error(err){ // 请求失败的时候调用
reject(err);
}
});
});
let p3 = new promise((resolve, reject) => {
$.ajax({
url: '3.txt',
dataType: 'json', // 设置解析json
success(json){ // 请求成功的时候调用
resolve(json);
},
error(err){ // 请求失败的时候调用
reject(err);
}
});
});
Promise.all([p1,p2,p3]).then(arr => {
// 其中arr分别是p1、p2、p3接口的返回数据
console.log("成功");
}, err => {
console.log("失败");
});
// jQuery的$.ajax其实返回的是一个promise对象,或者说兼容了promise的对象,包含then方法
$.ajax({url: '3.txt',dataType: 'json'}).then(json => {
console.log("成功");
}, err => {
console.log("失败");
})
// 简化的Promise请求
Promise.all([
$.ajax({url:"1.txt", dataType: "json"}),
$.ajax({url:"2.txt", dataType: "json"}),
$.ajax({url:"3.txt", dataType: "json"})
]).then(arr => {
let [a1,a2,a3] = arr; // a1,a2,a3分别是三个接口返回的数据
console.log("成功", a1, a2, a3);
}, err => {
console.log("失败");
1、服务器怎么用
- 东西(代码和文件)放在www里边;
- 路径转换: c:\wamp\www\ 变为 http://localhost/
2、promise
- let p = new promise((resolve, reject) => {
resolve();
reject();
});- p.then(() => {}, () => {})
3、回调函数
- 回调,类似于提醒,或者轮询。
- 不是定义的人来调用,将回调函数交给谁谁来执行。
- 不知道什么时候调用,反正到执行条件的时候我叫你。
回调函数就是函数的一种,是一种行为。
btn.onclick = function(){
console.log(“回调函数已执行”);
}
Promise的作用:解除异步操作,将异步过程同步化
Promise的局限性:带有逻辑的异步操作比较麻烦
promise.all(): 与的关系,所有的请求都成功
promise.race(): 或的关系,只要有一个完成就ok(用于网络测速之类的场景)
七、generator
generator:生成器函数,是对promise的改进版本。
- 能暂停------yield
- yield可以往里传参,也可以往出带返回值
// 普通函数
function show(){
console.log("普通函数");
}
// genneretor函数
function *show(){
console.log("普通函数");
}
// generator函数不会直接执行函数体,会返回一个generator对象,有一个next对象,从函数开始执行到第一个yield之前。
function *show(){
console.log("aaa");
yield;// 暂停标志
console.log("bbb");
}
let gen = show();
gen.next(); // aaa
gen.next(); // bbb
// 也可以用一个定时器执行下一步
setTimeout(function(){
gen.next()
}, 5000);
// yield传值(传参数)
function *show(){
console.log("aaa");
let a = yield;// 暂停标志
console.log("bbb"+ a);
}
let gen = show();
gen.next(); // aaa
gen.next(12); // bbb12
// 上边generator方法的执行顺序:
function *show(){
console.log("aaa");
yield;
-----------------------第一个next()方法-------------------------------
let a = yield;// 暂停标志
console.log("bbb"+ a);
-----------------------第二个next()方法:因此yield传值的话应该是在第二个next()种传参数a-------------------------------
}
// yield返回值1
function *show(){
console.log("aaa");
yield 55;// 暂停标志
console.log("bbb");
}
let gen = show();
let res1 = gen.next(); // aaa
console.log(res1); // {value: 55, done: false} done:是表示该方法是否已经执行完成,即是否执行到return语句
let res2 = gen.next(); // bbb
console.log(res2); // {value: undefined, done: true}
// yield返回值2
function *show(){
console.log("aaa");
yield 55;// 暂停标志
console.log("bbb");
return 88;
}
let gen = show(); // gen是iterator对象
let res1 = gen.next(); // aaa res1是一个简单的json对象了
console.log(res1); // {value: 55, done: false} done:是表示该方法是否已经执行完成,即是否执行到return语句
let res2 = gen.next(); // bbb
console.log(res2); // {value: 88, done: true} value:表示返回值,也即return的值
箭头函数不支持写成生成器函数。
// generator和promise的配合: $.ajax其实就是promise对象
function *show(){
let data1 = yield $.ajax({url: "1.txt", dataType: "json"});
if(data1.a + data1.b > 10){
let data2 = yield $.ajax({url: "2.txt", dataType: "json"});
console.log(data2[0]);
}else{
let data3 = yield $.ajax({url: "3.txt", dataType: "json"});
console.log(data3.name);
}
}
runner(show); // 执行show方法
generator与promise配合的缺点:
- 不能单独执行,需要外来的runner方法辅助执行----外来的runner不统一、不标准、性能低
- generator函数不能写成箭头函数
八、async/await
//generetor的写法
function *xxx(){
...
let res1 = yield xx; // 用res接收yield传递的结果(参数),yield可以用于暂停
...
let res2 = yield xx;
...
}
// async/await的写法
async function xxx(){ // 去掉*,function前边添加async
...
let res1 = await xx; // 将yield换成await即可,await后边可以跟一个promise对象,可以跟一个generator,也可以跟一个值,后边非异步的话就不会等待
...
let res2 = await xx;
...
}
// async/await的使用
function sleep(sec){
return new Promise((resolve, reject) => {
setTimeout(function(){
resolve();
}, sec*1000);
});
}
async function show(){
console.log("a");
await sleep(1);
console.log("b");
await sleep(3);
console.log("c");
}
show(); // 调用 先打印a,停一秒钟,打印b,再停三秒钟,打印c
async function show(){
let res1 = await $.ajax({url: "1.txt", dataType: "json"});
let res2 = await $.ajax({url: "2.txt", dataType: "json"});
let res3 = await $.ajax({url: "3.txt", dataType: "json"});
console.log("res1=", res1, " res2=", res2, " res3=", res3);
}
show(); // 调用 先打印a,停一秒钟,打印b,再停三秒钟,打印c
//箭头函数写法 等价于
(async () => {
let res1 = await $.ajax({url: "1.txt", dataType: "json"});
let res2 = await $.ajax({url: "2.txt", dataType: "json"});
let res3 = await $.ajax({url: "3.txt", dataType: "json"});
console.log("res1=", res1, " res2=", res2, " res3=", res3);
})();
// 匿名函数写法 等价于
(async function (){
let res1 = await $.ajax({url: "1.txt", dataType: "json"});
let res2 = await $.ajax({url: "2.txt", dataType: "json"});
let res3 = await $.ajax({url: "3.txt", dataType: "json"});
console.log("res1=", res1, " res2=", res2, " res3=", res3);
})();
// async/await 将异步同步化
(async function (){
let res1 = await $.ajax({url: "1.txt", dataType: "json"});
if(res1.a + res1.b > 10){
let res2 = await $.ajax({url: "2.txt", dataType: "json"});
console.log(" res2=", res2);
}else{
let res3 = await $.ajax({url: "3.txt", dataType: "json"});
console.log(" res3=", res3);
}
})();
// 总结
async function xxx(){
...
let 需要接收的结果 = await 需要执行的异步操作; // 此处的异步操作可以是promise、generator、async等
}
// async 和 await是配合把异步操作同步化的
// async 和 await 的错误处理
async function show(){
let res1 = await $.ajax({url: "1.txt", dataType: "json"});
let res2 = await $.ajax({url: "223312.txt", dataType: "json"}); // 假设不存在名称为223312的txt文件,即异步请求会出错
let res3 = await $.ajax({url: "3.txt", dataType: "json"});
console.log("res1=", res1, " res2=", res2, " res3=", res3);
}
show(); // 报错 404
// try/catch异常捕获
try{
show(); // 并不能正确的捕获show方法中的异常,因为这种写法是需要show方法执行完成之后捕获异常的
}catch(err){
console.log("有问题 err=", err);
}
// 正确的异常捕获方法
async function show(){
try{
let res1 = await $.ajax({url: "1.txt", dataType: "json"});
let res2 = await $.ajax({url: "223312.txt", dataType: "json"}); // 假设不存在名称为223312的txt文件,即异步请求会出错
let res3 = await $.ajax({url: "3.txt", dataType: "json"});
console.log("res1=", res1, " res2=", res2, " res3=", res3);
} catch(err){
console.log("有问题 err=", err);
}
}
show(); // 打印有问题,并报404错误
九、模块化
js原本不支持模块化,ES6自带模块化,比如import等。