ES6的简单介绍
一 ECMAScript的简介
1.1 什么是 ECMAScript
ECMAScript,发音 [ek - ma - script] 。在中文中, ECMAScript 可以读作 "伊克玛Script"。
官方定义: ECMAScript 是定义脚本语言的规范, 而 JavaScript 是遵循 ECMAScript 规范实现的一种编程语言。ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。
1.2 ES6 和 JavaScript 的区别
ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的一种实现(另外的 ECMAScript 方言还有 JScript 和 ActionScript)。日常场合,这两个词是可以互换。
ES6(ECMAScript 2015)是ECMAScript规范的第六个版本,JavaScript基于第六版的规范,新增很多功能。
1.3 ES6的新规范
-
ES6引入了"块级作用域",使用let和const关键字来声明变量和常量,使变量的作用域清晰可控
-
ES6引入了"箭头函数",箭头函数比传统的函数语法更简洁, 具有更少的冗余代码
-
ES6引入了"类(Class)"的概念,这是一种基于原型的面向对象编程的语法糖, 使用类可以更方便地创建和管理对象
-
ES6引入了"模板字符串", 使用反引号(`)创建字符串可以方便地嵌入变量和表达式
-
ES6引入了"解构赋值", 这是一种新的赋值语法,可以将数组或对象的属性直接赋值给变量
-
ES6引入了"函数参数默认值"
-
ES6引入了"Promise对象", 简化了异步编程, 使其更可读和可维护
-
ES6引入了 Set、Map 等
-
ES6引入了"模块化"(ES Module)
……
ES7 ~ ES13 新特性
ES7(ECMAScript 2016)
数组 includes() 方法
指数运算符
Array.prototype.includes()
ES8(ECMAScript 2017)
async/await 异步编程解决方案的改进
共享内存和原子操作的支持
Object.values() 和 Object.entries()
String.prototype.padStart() 和 String.prototype.padEnd()
ES9(ECMAScript 2018)
异步迭代器
Promise finally() 方法
Rest/Spread 属性
正则表达式具有命名捕获组
ES10(ECMAScript 2019)
Array.prototype.flat() 和 Array.prototype.flatMap()
Object.fromEntries()
String.prototype.trimStart() 和 String.prototype.trimEnd()
catch 块可以省略参数
ES11(ECMAScript 2020)
可选链 ?. 和 Nullish 合并运算符 ??
Promise.allSettled() 方法
动态 import()
全局对象globalThis
ES12(ECMAScript 2021)
String.prototype.replaceAll()
数字分隔符
WeakRefs 弱引用
Promise.any() 方法
ES13(ECMAScript 2022)
Class fields 类字段
SIMD(Single Instruction, Multiple Data)指令集
更好的BigInt支持
二 变量与常量
2.1 var定义变量(ES6之前)
-
var可以在全局范围或者函数范围内声明变量
-
var 变量可以重新声明和修改
-
var 的变量提升:在执行代码前,变量或函数的声明会移至到作用域的顶端。比如:
我们这样写 | 会被解析成这样 |
---|---|
|
|
变量提升后,会使用undefined进行初始化,因此并不会报 变量没有被定义错误
-
总结如下:
var定义的变量,与java语言中的变量的用法相比较,并没有那么严谨。因此ES6之后引入了两个let和const,以及块级作用域的概念。
测试代码:
// 1. var可以定义全局变量、和在函数内定义局部变量。
var myfriend = "zhangSan"
function f1(){
var hisfriend="lisi"
}
//输出变量
console.log("全局变量:"+myfriend);
// console.log("局部变量: "+hisfriend);//报错,会终止下面代码进行
console.log("全局变量会自动绑定到window对象上:"+window.myfriend);
//2. var定义的变量,可以重新定义和修改
var myfriend = "小七";
console.log("全局变量:"+myfriend);
myfriend="小八";
console.log("全局变量:"+myfriend);
//3.var 定义的变量,可以提升:在执行代码时,将变量或者函数提升到了执行的代码之前(作用域顶端)
//3.1 变量的提升: 相当于在使用变量前 增加了变量的定义以及初始化: var 变量=undefined
//3.2 函数的提升: 函数的定义提升到了使用前,因此不会报错。
f2()
function f2(){
console.log("--执行了f2--")
}
console.log(yourfriend);
var yourfriend = "小九";
2.2 let和const(ES6之后)
从ES6开始,引入了块级作用域,以及let和const两个关键字来规范变量的用法。目的是要像java变量一样更具严谨性。块级作用域,其实就是{}包含的范围。直接书写{},或者函数体的{}就是块级作用域。
2.2.1 let定义的变量
必须先声明和初始化,才能使用变量
变量的作用域,就是其所在的
{}
,在作用域范围外使用,会报错在作用域内,变量可以被修改,但是不能重复声明
2.2.2 const定义的变量
const定义的变量,是常量,因此不能被再次赋值
const定义的常量,也是有其作用域的,只能在作用域内被访问。
测试代码如下:
// 因为var定义的变量不够严谨,因此ES6规范,引入了块级作用域与两个关键字let const
// 1. 块级作用域: 可以直接书写的{}, 以及函数体的{}
// 2. let用于定义变量,严谨性与java语音的变量一直。
// 3. const用于定义变量,是常量,与java语言的常量相似
{
let x = 10
let y = 20 , z = 30;
console.log(x,y,z);
//可以被覆盖
x = 100,y=200,z=300;
console.log(x,y,z);
}
// let定义的变量不能超出作用域范围
// console.log(x,y,z);//Uncaught ReferenceError: x is not defined
let x =1000;
console.log("x:"+x);
// let x =2000; //同一个作用域内,变量只能定义一次。
console.log("全局变量"+window.x); //undefined let定义的全局变量 不会自动绑定到window上
// let定义的变量 可以提升 但是提升后没有初始化,因此在使用时会报Cannot access 'num1' before initialization。
// 自己理解, 就是let定义不能提前使用
// console.log(num1);
let num1 = 100;
const pi=3.1415926535;
// pi = 3.15; const定义的变量,不能被再次赋值,因为是常量
console.log("pi的值:"+pi);
{
console.log("在块里打印pi的值:"+pi);
const pe = 0.618;
console.log("黄金比例值:"+pe);
}
// 定义的变量也不能在作用域外面使用
// console.log("在作用域外面打印黄金比例值:"+pe)
// 定义一个变量,来存储匿名函数对象
let f3= function(){
console.log("hello es6");
}
f3()
三 模版字符串与解构
3.1 模版字符串
//1. 模版字符串 ES6规范中,引入了返单引号 `` 与linux的shell脚本中的``是一个意思
// 之前的字符串拼接方式,使用 + 号拼接
let name = "zhansgan";
let age= 21;
let information = '我的名字是'+name+',今年'+age+"岁。";
console.log(information);
// es6中,在返单引号里,可以直接写变量,只不过变量需要使用${}包起来, 返单引号里也可以直接换行
let name1="lisi";
let age1 = 21;
let information2 = `我的名字是${name1},我今年${age1}岁`;
console.log(information2);
let information3 = `鹅鹅鹅,
曲项向天歌。
白毛浮绿水,
红掌拨清波。
`
console.log(information3);
3.2 解构
// 2. 解构: 可以理解为解开解构。 即将数组元素、集合元素、对象属性等赋值给变量
// 语法结构: [变量1,变量2,变量3.....] = 数组|集合|对象
let names=['张三','lisi','rose'];
let n1 = names[0];
let n2 = names[1];
let n3 = names[2];
console.log(n1,n2,n3);
// 使用中括号定义一个变量数组,分别从左到右接收后面的数组对象里的元素
let[x,y,z] = ['join','tom','michael']
console.log(x,y,z);
var [,m1,,m2] = [10,20,30,40]
console.log(m1,m2);
let[,,,last]=[100,200,300,400]
console.log(last);
//3. 使用解构的方式来完成两个变量里的值的交换
let a1 = 10;
let a2 = 20;
[a1,a2]=[a1,a2];
console.log(a1,a2);
// 4. 解构对象
let person ={
'pname':"zhangsan",
gender:'f',
age:21
}
console.log(person);
// 4.1 在解构对象时,使用{}存储变量名,不是[],而且变量名要和属性名相同
let{pname}= person;
console.log(pname);
// 4.2 如果想用一个不与属性名相同的变量,也就是自定义变量,那么需要再属性名变量后添加冒号和自定义变量名
let{gender,age:myage, pname:pname1} = person;
console.log(gender,myage,pname1);
//4.3 可以给没有的属性,设置默认值
let{gender: mygender,idcard = 1004}=person;
console.log(mygender,idcard);
let[h1,h2,h3=3] = [1,2];
console.log(h1,h2,h3);
四 JS中的数据类型
之前我们学习过,JS中的数据类型主要分为两类,
一类是数值(基本)类型
String,Number,Boolean, null, undefined, Symbol
一类是引用数据(对象)类型
Object,Array,Function,RegExp,Date
在ES6中,又引入了Set、Map、Class等引用类型…
4.1 Set、扩展运算符
Set 是一种特殊的数据结构,是用于存储无序且唯一的值的集合对象。
// ES6规范中,引入了一个新的类型set
// 回顾: 基本数值类型(Number,Boolean,String,null,undefined,Symbol)
// 引用(对象)类型(Array,Object,Function,Date,RegExp)
// set: 是一种数据结构,无序且唯一(不能重复)
// set的创建
let s1 = new Set() //空Set
console.log(s1);
let s2 = new Set([1,2,3]);// 创建一个有元素的set集合, 注意 元素使用中括号[]包起来
console.log("集合对象:",s2);
console.log("集合的元素个数:"+s2.size);
// set是无序的,因此不能使用下标访问s2
// console.log(s2[2]);
// 添加元素
s2.add(4);
console.log(s2);
s2.add(4);// 再次添加相同元素,添加不进去
console.log(s2);
//删除元素
s2.delete(3);
console.log(s2);
// 查看set中是否有某一个元素
let f1 = s2.has(2);
console.log("是否有2这个元素:",f1);
//遍历1: for...of
// for(let element of s2){
for(element of s2){
console.log(element);
}
// 遍历2: forEach
// 回调函数: 函数A作为参数,传入到另外一个函数B中,函数A会在函数B中执行,函数A就是回调函数
let print1=function (a,b,c){
console.log(a,b,c);
}
s2.forEach(print1);
// 清空set
s2.clear();
console.log("集合对象:",s2);
console.log("集合的元素个数:"+s2.size);
// 扩展运算符: ... 作用:用于展开数组、set、map
let s3 = new Set([1,2,3]);
//将s3装成数组对象,使用了扩展运算符
let arr1 = [...s3]
console.log(arr1);
let s4 = [1,2,3];
let s5 = [5,6,7];
let s6 = [s4,4,s5];
console.log(s6);
let s7 = [...s4,4,...s5];
// let s8 = [...s6];
console.log(s7);
// console.log(s8);
// 使用扩展运算符,展开对象操作
let obj1 = {name:"zhangsan"};
let obj2 = {gender:'f'};
let obj3 = {
...obj1,
age:21,
...obj2
}
console.log(obj3);
//set 转成数组的另外一种方式: Array.from方法
let s8 = new Set(['lucy','lily','tom']);
let arr2 = Array.from(s8);
console.log(arr2);
//遍历数组
arr2.forEach((value,index)=>console.log(index,value))
4.2 Map
Map 是一种特殊的数据结构,是用于存储键值对的有序集合对象。
// map:ES6规范引入的一种新的数据结构,用于存储键值对。有序(添加顺序)。
// 创建Map对象
let m1 = new Map();
console.log(m1);
let m2 = new Map([
['1003','tom'],
['1004','lily']
]);
console.log(m2);
console.log("map的长度:",m2.size);
//添加元素
m2.set("1005","john");
console.log(m2);
// 添加key重复的元素,会覆盖原有的value
m2.set("1004","wangwu")
console.log(m2)
m2.delete("1003");
console.log(m2);
//查看上下文是否有某一个key的元素
console.log("是否存在key为1002的元素:",m2.has("1002"));
// 遍历1
m2.forEach((value,key)=>console.log(value,key));
// 遍历2
for([key,value] of m2){
console.log(key,value);
}
//遍历3
let es = m2.entries();
console.log(es);
es.forEach((entry,index)=>{
// entry 是每一个键值对,又因为键值对是两个元素的数组,因此可以使用下标访问entry的key和value
console.log(entry[0],entry[1]);
})
// 遍历4:
let ks = m2.keys();
ks.forEach(key=>{console.log(key,m2.get(key));
})
//遍历5:
let vs = m2.values();
vs.forEach(v=> console.log(v))
//map转数组
let arr1 = Array.from(m2);
console.log(arr1);
console.log(arr1[0][1]);
//清空map
m2.clear();
console.log(m2);
4.3 class
ES6引入了class关键字,用来定义类。 类是多个具有相同特征的对象的模版,用一个类可以创建许多不同的对象。
4.3.1 基本用法
-
语法格式:
class 类名{…}
-
类名首字母需要大写,用于区别变量名。
-
类体中可以定义属性、构造方法、实例方法等
4.3.2 案例演示
//ES6中,也引入了关键字class,用于描述类的概念,类是一堆具有相同特征的模版,对象是类的具体实例。
// 我们可以用类,来创建多个不同的对象。
class Person{
//提供属性
name
age
gender
//提供构造函数 一般用于初始化属性。
constructor(name,age,gender){
this.name=name;
this.age=age;
this.gender = gender;
}
// 提供实例方法
sayHi(othername){
console.log(`${othername},你好,我是${this.name},今年${this.age}岁`);
}
}
// 使用类创建一个对象
let p1 = new Person("张三",21,'女') //new关键字后书写类名(有参传参),底层默认就会调用构造函数
console.log(p1);
p1.sayHi("李四")
class Teacher{
//如果没有显式的书写属性,在构造函数中,直接使用的变量就会自动提升为属性,注意,必须使用this.调用
constructor(name,age,gender,a){
this.name=name;
this.age=age;
this.gender = gender;
// idcard = a;
this.idCard=a;
}
}
let t1 = new Teacher("liu",21,'nan',123123);
console.log(t1);
//调用属性:
console.log(t1.name,t1.age,t1.gender,t1.idCard);
class Student{
#idCard //设置私有属性,前面添加#
constructor(name,gender,age,idCard){
this.name = name;
this.gender = gender;
this.age = age;
this.#idCard = idCard;
}
//为私有属性提供getter方法(也叫存取器)
get idCard(){
return this.#idCard;
}
set idCard(value){
this.#idCard=value;
}
}
let s1 = new Student("wangwu","男",21,123123123);
console.log(s1);
//访问非私有属性
console.log(s1.name,s1.age,s1.gender);
//访问私有属性
console.log(s1.idCard); //当获取私有属性时,其实调用的是getter存取器
// 给非私有属性赋值
s1.name ="wanglaowu";
console.log(s1);
//给私有属性赋值
s1.idCard=123321333111222; //底层调用的是setter存取器
console.log(s1.idCard);
4.4 类的继承
ES6类支持单继承,使用extends关键字,就可以继承class了。
// 类的继承:关键字extends
class Human {
constructor(name,gender,age){
this.name=name;
this.gender=gender;
this.age=age;
}
// 提供实例方法
sayHi(othername){
console.log(`${othername},你好,我是${this.name},今年${this.age}岁`);
}
}
//子类型 :
// 1.子类的构造器可以不写,默认调用父类的构造器进行赋值操作
// 2.子类提供构造函数时,必须使用super(有参传参)调用父类的构造器。必须放在首行。
// 3.父类的属性,方法,都会被继承到子类型中
class Emp extends Human{
constructor(name,gender,age,idcard){
super(name,gender,age)
this.idcard = idcard;
}
}
let emp = new Emp("员工1","男",21,19292929);
console.log(emp);
console.log(emp.age);
emp.sayHi("wanglaoqi")
console.log(emp.idcard);
注意:
子类型 :
1.子类的构造器可以不写,默认调用父类的构造器进行赋值操作
2.子类提供构造函数时,必须使用super(有参传参)调用父类的构造器。必须放在首行。
3.父类的属性,方法,都会被继承到子类型中
4.5 箭头函数
ES6规范中引入的新写法, 目的是为了简化函数的写法,对标的是java的lambda表达式。
// 匿名函数的定义
let getSum1 = function(a,b){
console.log(a+b);
}
getSum1(10,20)
//使用箭头函数来简化写法 (形参列表)=>{函数体}
let getSum2 = (a,b)=>{console.log(a+b);};
let getSum3 = (a,b)=>console.log(a+b);
// 调用的时候
getSum2(10,20);
getSum3(10,20);
// 箭头函数的继续简化: 形参列表中只有一个形参时,可以省略小括号
let getSum4 = num =>{return Math.pow(num,3);};
console.log(getSum4(3));
// 箭头函数的继续简化:函数体中只有一行代码时,可以省略花括号,但是不能有return。如果有return,必须省略
let getSum5= (n1,n2)=>n1+n2;
console.log(getSum5(1,2));