ES6 ---> ES2015 ---> 2015年6月份推出,并在推出之后ECMA表示以后每年的6月份都会推出一个版本(然后现在出现什么ES7、ES8、ES9....),其实只是一个年份表示,小版本更新,只有ES2015才是大版本更新。
目录>
1、let 、const 变量定义(声明)
2、解构赋值
3、字符串模板
4、... 三个点,扩展运算符,rest 运算符
5、箭头函数 (参数) => {代码块}
6、数组
7、Promise
8、模板化(import...from..、export、default)
9、类class 和 继承 extends
10、Symbol 基本数据类型
11、generator * yield 同步执行
12、async await
1、let 、const 变量定义(声明)
// 之前 var
for(var i = 0; i < 10; i ++){
//TODO
}
console.log(i,window.i) //10 因为用var定义的变量为全局的,是window对象的属性
// 变量提升
function fn() {
console.log(a) // undefined 因为a变量提升,相当于在这句之前定义了一个var a;然后访问a时只是定义了,没有赋值,所以是undefined。
var a = 5;
};
fn();
//-------------------------
// let 可以作为局部作用域,不会存在变量提升问题,let 不能在同一作用域下重复定义变量
console.log(num); //num is not defined,没有变量提升
let num = 10;
let num = 20; //'num' has already been declared,let 不能在同一作用域下重复定义变量
for (let y = 0; y < 3; y ++){
let y = "aaa";
console.log(y) //输出三次"aaa",因为let y是局部作用域,而(let y = 0; y < 3; y ++)这是一个作用域,{let y = "aaa";}这也是一个作用域,所以不会影响到循环中的y。
}
let a = 10;
if(1){
console.log(a); //a is not defined ,这里不会先去找全局的a,而是等待区域 ----> TDZ区域开始
let a = 5; // TDZ区域结束
}
// const 常量,一但用const定义后,值就不能进行修改。
const a = 10;
a = 20; //Assignment to constant variable.
// 注意:const定义的常量必须是有赋值的。
const b;
console.log(b); // Missing initializer in const declaration
2、解构赋值
// 把变量的值进行解构赋值,类似于key:val
let arrs = [1,2,3];
console.log(arrs[0],arrs[1],arrs[2]); //1 2 3
let [a,b,c] = [1,2,3];
console.log(a,b,c); // 1 2 3
// 解构赋值中设置默认值
let {oa,ob,oc="暂无数据!"} = {
oa : 111,
ob : 222
}
console.log(oa,ob,oc); // 111 222 暂无数据!
//解构赋值中可以对undefined进行设置默认值,但不是对null设置默认值
let [a,b,c="暂无数据!"] = [1,2,undefined];
console.log(a,b,c); // 1 2 暂无数据!
// 注意
let [aa,bb,cc="暂无数据!"] = [11,22,null];
console.log(aa,bb,cc); // 11 22 null 不能对null设置默认值
// 交换数据
let a = 10,b = 5;
console.log(a,b); // 10 5
[a,b] = [b,a];
console.log(a,b); // 5 10
// 函数解构
function getIn(){
return {
a:10,
b:20
}
}
let {a,b,c="123"} = getIn();
console.log(a,b,c) //10 20 "123"
//参数解构
function show({a,b="默认值"}){
console.log(a,b); //10 默认值
}
show({
a:10
})
3、字符串模板
// es6之前 '字符串'+变量+'字符串'
var num = 10;
var str = 'aaa' + num + 'bbb';
// es6 `字符串${变量}字符串`
var str1 = `aaa${num}bbb`;
// ES6字符串查找 includes
// ES6之前
let strs = "name is hjm";
// indexOf是检查字符串是否有此字符串,并返回需要检查字符串的第一个字符位置,所以判断是否包含字符串都是判断!=-1;
if(strs.indexOf("is") != -1){
console.log("有");
}else{
console.log("无");
}
console.log(strs.indexOf("is")); //返回的是i的索引,没有就返回-1
// ES6字符串查找。includes
console.log(strs.includes("is")); //返回的true/false
// 查找字符串是否以规定的字符串的开头 startsWith
let str1 = "https://www.xxx.com";
let str2 = "file://www.xxx.com";
console.log(str2.startsWith("https")) //返回的true/false
// 查找字符串是否以规定的字符串的结尾 endsWith
let str11 = "https://www.xxx.com";
let str22 = "file://www.xxx.cn";
console.log(str22.endsWith("cn")) //返回的true/false
//字符串填充 padStart向字符串前面填充,padEnd向字符串后面填充
//说明:let 新字符串 = padStart(字符串总长度, 需要拼接的字符串);
let str_1 = "a";
let str_2 = "xxx";
console.log(str_1.padStart(str_1.length+str_2.length,str_2)) //xxxa
console.log(str_1.padEnd(str_1.length+str_2.length,str_2)) //axxx
4、 ... 三个点,扩展运算符,rest 运算符
let arrs = ["aaa", "bbb", "ccc"];
console.log(arrs); // ["aaa", "bbb", "ccc"]
console.log(...arrs) // aaa bbb ccc 展开
text(...arrs);
function text(a,b,c){
console.log(a,b,c) // aaa bbb ccc
}
// 拷贝数组
let arr11 = [1,2,3,4];
let arr22 = [...arr11];
arr11[0] = 111;
console.log(arr22[0]) // 1
// 合并数组
function sum(...arr){
console.log(arr); // [1, 2, 3]
}
sum(1,2,3)
// 展开数组
function sum1(a,b,c="默认值"){
console.log(a,b,c); // 1 2 "默认值"
}
sum1(...[1,2])
// 解构+剩于传参
function sum2([a,b,...c]) {
console.log(a,b,c); // 1 2 [3, 4]
}
sum2([1,2,3,4])
5 、 箭头函数 (参数) => {代码块}
// 没有arguments
function show1(){
console.log(arguments)
}
let show2 = () => {
console.log(arguments)
}
show1();
// show2(); //箭头函数没有arguments
// 构造函数 :注-> 箭头函数不能当构造函数使用,因为this指向问题。
function person(name,age="默认值") {
this.name = name;
this.age = age;
this.run = function(){
console.log(this.name, this.age);
}
}
let p1 = new person();
p1.name = "hjm";
p1.run();
//ES2017中函数传参可以是逗号结尾
function p2(a,b,c,){
console.log(a,b,c);
}
p2(1,2,3)
6、数组 forEach map filter some every from find assign Object.is ** 幂运算符
//forEach 和普通for循环一样
let arr = ['a','b','c','d'];
// forEach就是代替普通的for循环,forEach参数中的function是每循环一次的回调函数,回调函数中的几个参数:val,index,arr
//forEach没有返回值,map有返回值
arr.forEach(function(val,index,arr){
console.log(val,index,arr)
})
//map 有返回值
let arr = ['a','b','c','d'];
//map如果没有写return,默认就会有返回值,返回的是undefined
//如果map函数没有写返回值就和forEach及普通for循环一样。
let newArr = arr.map((val, index, arr) => {
console.log(val,index,arr)
})
console.log(newArr) //[undefined, undefined, undefined, undefined] 如果不写return,那默认返回undefined
// ******平常用map一定是要有返回值,如果不需要返回值,那直接用forEach及普通for循环就行********
let newArr1 = arr.map((val, index, arr) => {
console.log(val,index,arr)
return 1;
})
console.log(newArr1) //[1, 1, 1, 1]
//map一般用于重新整理数据中使用
let arr1 = [{
title: 'hjm',
text : 'xxx'
}]
let newArr2 = arr1.map((val, index, arr1) => {
let json = {};
json.a = `@@@@${val.title}`;
json.b = `123${val.text}`;
return json;
})
console.log(newArr2) // Object
console.log(...newArr2) // {a: "@@@@hjm", b: "123xxx"}
//filter 数据过滤,类似map,有返回值
let arr = [
{
num : 1,
status : true
},{
num : 2,
status : false
},{
num : 3,
status : true
}
]
let arrs = arr.filter((item, index, arr) => {
return item.status == true;
})
console.log(arrs); //返回为true的json对象
console.log(...arrs);
//some 查找数组中是否有满足条件元素,有就返回true
let arr = ["a","b","c"];
let a = arr.some((val, index ,arr) => {
return val == 'b';
})
console.log(a) //true
//every 查找数组中每一个元素是否都满足条件。
let arr = [1, 3, 5, 6];
let a = arr.every((val, index ,arr) => {
return val%2 == 1; //判断数组中每一个元素是否为奇数
})
console.log(a) //false
//from 把类数组转换成数组,有length的对象都可以用from进行数组转换
let str = "abc";
let arr = Array.from(str); //有length的对象都可以用from进行数组转换
console.log(arr) //Array
let json = {
0:'a',
1:'b',
2:'c',
length:2
}
let arr1 = Array.from(json); //json对象有自定义length属性,所以可以转换成数组,但length的值决定数组的内容和长度
console.log(arr1); //["a", "b"],因为from会根据length的长度返回对应元素
//find 返回符合条件的第一个元素。
let arr = [2,43,76,87,10];
let arrs = arr.find((val, index, arr) => {
return val > 50;
})
console.log(arrs) //76
// findIndex 返回符合条件的第一个元素的下标。
let arrs1 = arr.findIndex((val, index, arr) => {
return val > 50;
})
console.log(arrs1) //2 第三个元素
//assign 1、合并对象,2、复制一个对象
// let 新的对象 = Object.assign(目标对象,需要操作的对象);
let a = {a:1},b = {b:2,a:4},c = {c:3};
let newJson = Object.assign({}, a,b,c);
console.log(newJson) //{a: 4, b: 2, c: 3} 对象属性有重复的会后面替换前面的
let arr = [1,2,3,4];
let arr1 = Object.assign([], arr);
arr1.push(5)
console.log(arr1) //[1, 2, 3, 4, 5]
console.log(arr) //[1, 2, 3, 4]
//Object.is 判断两个元素是否相等
console.log(NaN == NaN); //false
console.log(Object.is(NaN, NaN)); //true
console.log(+0 == -0); // true
console.log(Object.is(+0, -0)) //false
// ** 幂运算符 计算次方
//ES2017新增运算符 幂:计算次方
console.log(Math.pow(2,3)) //以前
console.log(2 ** 4) // ES2017新增
7、Promise (resolve、reject、then、catch、Promise.all)
// Promise 解决异步问题
//let Promise对象 = new Promise(function(resolve成功状态,reject失败状态){})
//每一个Promise对象都有一个成功状态的回调then(res=>{}),和一个失败状态回调catch(err=>{})
let promise = new Promise(function(resolve,reject){
if(0){
resolve("ok");
}else{
reject("no");
}
})
promise.then(res=>{
console.log(res)
},err=>{
console.log("err:"+err) //err:no
})
promise.catch(errs=>{
console.log("catch:"+errs) //catch:no
})
// 缩写
new Promise(function(resolve,reject){
if(1){
resolve("ok");
}else{
reject("no");
}
}).then(res=>{
console.log(res)
}).catch(errs=>{
console.log(errs)
})
//all 所有的Promise对象必须是成功的,才会有返回
let p1 = Promise.resolve("11");
let p2 = Promise.reject("22");
let p3 = Promise.reject("33");
Promise.all([p1,p2,p3]).then(red=>{
console.log(red) //有reject,所以这里没有返回
}).catch(err=>{
console.log(err) //只返回错误的第一个
})
let test = (onTime, status) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if(status){
resolve(`${onTime / 1000}秒`);
}else{
reject(`${onTime / 1000}秒`);
}
},onTime)
})
}
let on1 = test(3000, true);
let on2 = test(2000, true);
Promise.all([on1, on2]).then(res => {
console.log(`${res} : 成功回调`); //3秒,2秒 : 成功回调 如果多个Promise中有一个reject状态的,那么就不会进行then成功回调中
}).catch(err => {
console.log(`${err} : 错误回调`); //如果多个Promise中有多个reject状态的,那么只会返因第一个reject回调
})
8、模板化(import...from..、export、default)
//注意:模块多次引入也只会导入一次
// as 给变量取别名
/*
module1.js中
定义 let a=10,b=5,c=1;
export {
a as aa,
b,
c
}
*/
import {aa,b as bb,c} from "./module/module1.js"
let d = c + 100
console.log(aa,bb,c,d); //10 50 100 200 as 给变量取别名
// * 代表导入全部export中注册的变量
import * as allModule from "./module/module1.js"
console.log(allModule, "* 代表导入全部export中注册的变量"); //Module对象,Module中有export属性为aa、b、c
//export default命令用于指定模块的默认输出,一个模块只能有一个默认输出,因此export default命令只能使用一次
/*
module2.js中
export default 100;
let name='hjm',age=18;
export {
name,
age
}
*/
// 没有{}的导入模块必须在模块中是export default定义的,如果要导入其它变量,那要a后面加,{}继续导入就行
import a,{name,age} from "./module/module2.js"
console.log(a,name,age); // 100 "hjm" 18
// import有提升效果,在import导入之前可以访问到模块中的属性。
console.log(a,name,age); // 100 "hjm" 18 import有提升效果
// 多个模块导入
import Person,{num1,num2,sum} from "./module/module2.js"
// 导入模块中的变量发生改变,外面也会改变。而不是像js\css一样要重新加载
/*
//module6.js
export let nums1 = 10;
setTimeout(() => { //两秒后修改nums1的值,让外部使用此模块也动态修改,不用加载第二次。
nums1 = 111;
}, 2000)
*/
import {nums1} from "./module/module6.js"
console.log(nums1); // 10
setTimeout(() => {
console.log(nums1,"导入模块中的变量发生改变,外面也会改变。"); //111
}, 2100)
// import() 动态导入,根据条件导入需要的模块,返回的是一个Promist对象.
let importFile = "";
if(true){
importFile = "./module/module6.js";
}
import(importFile).then(res=>{
console.log("导入成功", nums1)
})
9、类和继承
// es6之前 函数模拟类,function函数也是全局函数,有提升;
let p1 = new Person("hjm",18);
function Person(name, age) {
this.name = name;
this.age = age;
this.show = function(){
console.log(this.name);
}
}
Person.prototype.showName = function(){ //给类增加showNamw方法
console.log("showNamw", this.name);
}
Object.assign(Person.prototype, { // assign 合并,增加showAge、showNames方法
showAge(){
console.log("showAge",this.age);
},
showNames(){
console.log("showNames",this.name);
}
})
p1.show(); // hjm
p1.showName(); // showNamw hjm
p1.showNames(); //showNames hjm
p1.showAge(); // showAge 18
// es6 类实现
//class没有提升,在定义之前new Persons是不行的。
class Persons{
// constructor:类中的构造函数,只要调用new就自动执行
constructor(name, age) {
console.log(name,age); // 222 333,还没挂载this,只是传参。
// 挂载当前类属性
this.name = name;
this.age = age;
console.log(this.name,this.age); //222 333 this已经挂载完成
}
show(){
console.log(this.name)
}
}
new Persons("222","333").show();
// 类里面的静态方法 ->static 修饰的类方法
class Prosons1 {
constructor(arg) {
}
show(){
console.log("类对象方法,和Object-C语法很像,用对象调用的方法叫对象方法")
}
static show1(){
console.log("用static修饰的方法,类静态方法->类方法,和Object-C语法很像,用类本身调用的方法叫类方法")
}
}
let p2 = new Prosons1();
p2.show(); // p2类对象调用show方法,对象方法.
Prosons1.show1(); //Prosons1 类本身调用方法,类方法
// ---------------- 继承 extends------------------------
/*
es6之前继承
1、原型链继承
原型链继承核心: 将父类的实例作为子类的原型。
子类.prototype = new 父类();
var 子类 = new 子类();
2、构造函数模式 call(this)
*/
// es6 extends继承
class Person {
constructor(name) {
this.name = name;
}
run() {
console.log(this.name,"es6");
}
go() {
console.log("父类方法,go");
}
}
class Stu extends Person{
constructor(name,haha) {
super(name,); //子类想访问父类属性就必须继承父类属性,super(name,),如果子类有自己的属性,那也可以在constructor函数中写
this.haha = haha;
}
run() {
// super是一个对象
super.run();
console.log("子类中的方法,和父类中方法重名,如果想执行父类方法也是调用super.父类方法");
}
eat() {
console.log("学生在吃")
}
}
let person = new Person("-------11--------");
let stu = new Stu("父类继承属性","子类属性");
stu.go();
stu.run(); //子类中有父类同名方法,那就执行子类方法,如果想执行父类方法也是调用super
console.log(stu.name,stu.haha)
stu.eat();
10、Symbol 基本数据类型
/*
值类型(基本类型):字符串(String)、数字(Number)、布尔(Boolean)、对空(Null)、未定义(Undefined)、Symbol(es6新增类型)。
引用数据类型:对象(Object)、数组(Array)、函数(Function)。
*/
/*
Symbol注意点
1. Symbol不需要像其它数据类型new出来,Symbol不能new
new Array()
new String()
Symbol()
一般用于定义一些key。
*/
// 注意:如果symbol做为json中的key使用,那么用for in就循环不出来
let json = {
a : 11,
b : 22,
[symbol] : 33
}
for (let key in json) {
console.log(key, json[key]) // a 11 b 22
}
11、generator *
function * show(){
yield "执行第一步";
yield "执行第二步";
return "执行第三步";
}
//generator返回的是一个对象,通过next调用函数执行
let s1 = show();
// 手动调用,比较麻烦,在es2017中出现了async、await来解决异步问题
// value为执行后的返回值,done表示是否执行完成
console.log(s1.next()); //{value: "执行第一步", done: false}
console.log(s1.next()); //{value: "执行第二步", done: false}
console.log(s1.next()); //{value: "执行第三步", done: true}
12、async await
/*
1、await 只能配合 async 使用
2、相比generator语义化更强,generator是用*表示,语义化不强.
3、await后面可以是函数、表达式、Promise、布尔值、数字、字符串
4、async函数返回的是一个Promise对象
5、只要await语句后面的Promise状态是reject,那么整个async函数都会中断,最好用try catch捕获一下错误。
*/
async function fn(){ //async返回的是一个Promise对象
return "async返回的是一个Promise对象";
}
fn().then(res => {
console.log(res) //"async返回的是一个Promise对象"
})
async function fn1(){
try{
throw new Error("出错了!"); //只要await语句后面的Promise状态是reject,那么整个async函数都会中断
}catch(e){
//TODO handle the exception
console.log("有await的地方,都用try catch,因为其中有一个await出现错误,那么就不会往下执行。")
}
// 也可以用Promise的catch来捕获错误,并让后继代码继续执行
await Promise.reject("出错了!").catch(err => {
console.log("不让程序中断,catch捕获错误,并继续向下执行");
})
return "111";
}
fn1().then(res => {
console.log(res)
}).catch(err => {
console.log(err);
})
网友评论