一、ES是什么?
ES 全称 EcmaScript,是脚本语言的规范,JavaScript 是 EcmaScript的一种实现,所以 ES 新特性其实指的就是 JavaScript 的新特性
1.1 ECMA-262
Ecma 国际制定了许多标准,而 ECMA-262 只是其中的一个,ECMA-262(ECMAScript)历史版本查看网址:这里
版本 | 时间 | 概述 |
---|
第 1 版 | 1997年 | 制定了语言的基本语法 | 第 2 版 | 1998年 | 较小改动 | 第 3 版 | 1999年 | 引入正则、异常处理、格式化输出等。IE 开始支持 | 第 4 版 | 2007年 | 过于激进,未发布 | 第 5 版 | 2009年 | 引入严格模式、JSON,扩展对象、数组、原型、字符串、日期方法 | 第 6 版 | 2015年 | 模块化、面向对象语法、Promise、箭头函数、let、const、数组解构赋值 等等 | 第 7 版 | 2016年 | 幂运算符、数组扩展、Async/await 关键字 | 第 8 版 | 2017年 | Async/await、字符串扩展 | 第 9 版 | 2018年 | 对象解构赋值、正则扩展 | 第 10版 | 2019年 | 扩展对象、数组方法 | 第 11版 | 2020年 | 链式操作、动态导入等 | ES.next | 2020+ | 动态指向下一个版本 |
1.2 为什么要学习 ES6
- ES6 的版本变动内容最多,具有里程碑意义;
- ES6 加入许多新的语法特性,编程实现更简单、高效;
- ES6 是前端发展趋势,就业必备技能
?
二、ES6新特性
2.1 新特性总体概括
1、let 关键字
2、const关键字
3、变量和对象的解构赋值
4、模板字符串
5、简化对象和函数写法
6、箭头函数
7、ES6中函数参数的默认值
给函数的参数设置默认值;
8、rest参数
拿到实参;
9、扩展运算符
将一个数组转为用逗号分隔的参数序列;
10、Symbol
表示独一无二的值;
11、迭代器
用来遍历集合、数组等;
12、生成器
是一种异步编程解决方案;
13、Promise
非常强大的异步编程的新解决方案;
14、Set集合
类似数组,但元素不重复的集合;
15、Map集合
16、class类
17、数值扩展
18、对象扩展
19、模块化
20、Babel对ES6模块化代码转换
- 为了适配浏览器,将更新的ES规范转换成ES5规范;
21、ES6模块化引入NPM包
?
2.2 let关键字
特性:
-
不允许重复声明; -
块级作用域(局部变量); -
不存在变量提升; -
不影响作用域链;
声明代码示例:
let b,c,d;
let e = 100;
let f = 521, g = 'iloveyou', h = [];
1. 不允许重复声明
let dog = "狗";
let dog = "猫";
运行结果:
2. 块儿级作用域(局部变量)
{
let cat = " 猫 "; console.log(cat);
}
console.log(cat);
?
3. 不存在变量提升
什么是变量提升:
就是在变量创建之前使用(比如输出:输出的是默认值),let不存在,var存在;
console.log(people1);
console.log(people2);
var people1 = "大哥";
let people2 = "二哥";
?
4. 不影响作用域链
什么是作用域链:就是代码块内有代码块,跟常规编程语言一样,上级代码块中的局部变量下级可用
{
let p = "大哥";
function fn(){
console.log(p);
}
fn();
}
?
2.3 const关键字
const 关键字用来声明常量,const 声明有以下特点:
-
声明必须赋初始值; -
标识符一般为大写(习惯); -
不允许重复声明; -
值不允许修改; -
块级作用域(局部变量);
?
2.4 变量和对象的解构赋值
什么是解构赋值:
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构赋值;
const F4 = ["大哥","二哥","三哥","四哥"];
let [a,b,c,d] = F4;
console.log(a + b + c + d);
const F3 = {
name : "大哥", age : 22,
sex : "男",
xiaopin : function(){
console.log("我会演小品!");
}
}
let {name,age,sex,xiaopin} = F3;
console.log(name + age + sex + xiaopin);
xiaopin();
?
2.5 模板字符串
模板字符串(template string)是增强版的字符串,用反引号(`)标识,特点:
- 字符串中可以出现换行符;
- 可以使用 ${} 形式引用变量来实现变量拼接;
let s = "大哥";
let out = `${s}是我最大的榜样!`;
console.log(out);
?
2.6 简化对象和函数写法
如果属性名和变量名相同,ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁;
let name = "hhhh";
let change = function(){
console.log("活着就是为了改变世界!");
}
const school = {
name,
change,
say(){
console.log("言行一致!");
}
}
school.change();
school.say();
?
2.7 箭头函数
ES6允许使用箭头(=>)定义函数,箭头函数提供了一种更加简洁的函数书写方式,箭头函数多用于匿名函数的定义;
箭头函数的重要特性
-
箭头函数的this是静态的,始终指向函数声明时所在作用域下的 this 的值(外层作用域); -
不能作为构造函数实例化对象; -
不能使用 arguments 变量; -
如果形参只有一个,则小括号可以省略; -
函数体如果只有一条语句,则花括号可以省略,且return也必须省略,该条语句的执行结果就是函数的返回值; -
没有原型对象,没有prototype属性;
let speak = () => console.log("hello 哈哈!");
speak();
let hi = name => "hi " + name;
console.log(hi("訾博"));
let he = (a,b,c) => a + b + c;
console.log(he(1,2,3));
const school = {
name : "dada",
}
window.name = "小小";
function getName(){
console.log(this.name);
}
getName1 = () => {
console.log(this.name);
}
getName();
getName1();
getName.call(school);
getName1.call(school);
let Persion = (name,age) => {
this.name = name;
this.age = age;
}
let me = new Persion("訾博",24);
console.log(me);
let fn = () => console.log(arguments);
fn(1,2,3);
let add = n => {
return n + n;
}
let pow = (n) => n*n;
?
案例一:点击 div 2s后颜色变成粉色
传统写法有问题:
<body>
<div id="ad"></div>
<script>
let ad = document.getElementById('ad');
ad.addEventListener("click", function(){
setTimeout(function(){
console.log(this);
this.style.background = 'pink';
},2000);
});
</script>
</body>
总结:在 setInterval 和 setTimeout 中传入函数时,函数中的 this 会指向 window 对象
传统解决问题的写法:
<script>
let ad = document.getElementById('ad');
ad.addEventListener("click", function(){
let _this = this;
setTimeout(function(){
console.log(this);
_this.style.background = 'pink';
},2000);
});
</script>
箭头函数解决问题的写法:
<script>
let ad = document.getElementById('ad');
ad.addEventListener("click", function(){
setTimeout(() => {
this.style.background = 'pink'
},2000);
})
</script>
?
案例二:从数组中返回偶数的元素
const arr = [1, 6, 9, 10, 100, 25];
const result = arr.filter(function(item){
if(item % 2 === 0){
return true;
} else {
return false;
}
});
const result = arr.filter(item => item % 2 === 0);
总结:
- 箭头函数适合与 this 无关的回调。定时器,数组的方法回调
- 箭头函数不适合与 this 有关的回调。DOM元素事件回调,,对象的方法
?
2.8 ES6中函数参数的默认值
ES6允许给函数的参数赋初始值;
作用:
<script>
function add(a,b,c=10) {
return a + b + c;
}
let result = add(1,2);
console.log(result);
function connect({host="127.0.0.1", username,password, port}){
console.log(host)
console.log(username)
console.log(password)
console.log(port)
}
connect({
host: 'atguigu.com',
username: 'root',
password: 'root',
port: 3306
})
</script>
?
2.9 rest 参数
ES6 引入 rest 参数,用于获取函数的实参,用来代替 arguments;
参考文章:点击
function data(){
console.log(arguments);
}
data("大哥","二哥","三哥","四哥");
function data(...args){
console.log(args);
}
data("大哥","二哥","三哥","四哥");
?
2.10 扩展运算符
... 扩展运算符能将数组转换为逗号分隔的参数序列;
扩展运算符也是三个点(…)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列,对数组进行解包;
<script>
const tfboys = ['易烊千玺', '王源', '王俊凯'];
function chunwan() {
console.log(arguments);
}
chunwan(...tfboys);
</script>
应用
- 数组的合并
- 数组的克隆(是浅拷贝)
- 将伪数组转为真正的数组
const kuaizi = ['王太利','肖央'];
const fenghuang = ['曾毅','玲花'];
const zuixuanxiaopingguo = [...kuaizi, ...fenghuang];
const sanzhihua = ['E','G','M'];
const sanyecao = [...sanzhihua];
const divs = document.querySelectorAll('div');
const divArr = [...divs];
console.log(divArr);
?
2.11 Symbol
ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值。它是 JavaScript 语言的第七种数据类型,是一种类似于字符串的数据类型;
参考文章:https://blog.csdn.net/fesfsefgs/article/details/108354248
1. Symbol 特点:
-
Symbol 的值是唯一的,用来解决命名冲突的问题; -
Symbol 值不能与其他数据进行运算; -
Symbol 定义的对象属性不能使用 for…in 循环遍历 ,但是可以使用 Reflect.ownKeys 来获取对象的所有键名;
<script>
let s = Symbol();
let s2 = Symbol('尚硅谷');
let s3 = Symbol('尚硅谷');
console.log(s2==s3);
let s4 = Symbol.for('尚硅谷');
let s5 = Symbol.for('尚硅谷');
console.log(s4==s5);
</script>
作用:symbol表示一个独一无二的值,可以给对象添加属性和方式
2. Symbol内置值
ES6 还提供了 11 个内置的 Symbol 值,指向语言内部使用的方法。可以称这些方法为魔术方法,因为它们会在特定的场景下自动执行;
?
2.12 迭代器
迭代器是一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口(JS里面就是指对象里面的一个属性),就可以完成遍历操作;
特性:
-
ES6 创造了一种新的遍历命令 for…of 循环 -
Iterator 接口主要供 for…of 消费; 原生具备 iterator 接口的数据(可用 for of 遍历):
- Array;
- Arguments;
- Set;
- Map;
- String;
- TypedArray;
- NodeList;
工作原理
-
创建一个指针对象,指向当前数据结构的起始位置; -
第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员; -
接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员; -
每调用 next 方法返回一个包含 value 和 done(是否迭代完成的状态) 属性的对象;
注:需要自定义遍历数据的时候,要想到迭代器;
<script>
const xiyou = ['唐僧', '孙悟空', '猪八戒', '沙僧'];
for(let v of xiyou){
console.log(v);
}
let iterator = xiyou[Symbol.iterator]();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
let iterator1 = xiyou[Symbol.iterator]();
console.log(iterator1.next());
</script>
迭代器实现自定义遍历数据:
<script>
const banji = {
name: "终极一班",
stus: ['xiaoming', 'xiaoning', 'xiaotian', 'knight'],
[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>
?
2.13 生成器
生成器函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同,以前用的是春回调函数;
1. 基本用法
定义生成器函数:需要在函数名和 function 之间添加一个*
<script>
function* gen() {
console.log(111);
yield '一只没有耳朵';
console.log(222);
yield '一只没有尾部';
console.log(333);
yield ' 真 奇 怪 ';
console.log(444);
}
let iterator = gen();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log("遍历:");
for(let v of gen()){
console.log(v);
}
</script>
结果:
2. 向生成器传入实参
后一个 next 方法中若传入实参,该实参将作为上一个 yield 语句的整体返回结果
function * gen(arg){
console.log(arg);
let one = yield 111;
console.log(one);
let two = yield 222;
console.log(two);
let three = yield 333;
console.log(three);
}
let iterator = gen("AAA");
console.log(iterator.next());
console.log(iterator.next("BBB"));
console.log(iterator.next("CCC"));
console.log(iterator.next("DDD"));
结果:
3. 实例
实例1:
需求:1s后控制台输出111,再过2s后控制台输出222,再过3s后控制台输出333
function one(){
setTimeout(()=>{
console.log(111);
iterator.next();
},1000)
}
function two(){
setTimeout(()=>{
console.log(222);
iterator.next();
},1000)
}
function three(){
setTimeout(()=>{
console.log(333);
iterator.next();
},1000)
}
function * gen(){
yield one();
yield two();
yield three();
}
let iterator = gen();
iterator.next();
实例2:
需求:模拟获取: 用户数据,订单数据,商品数据,实际生活中有了用户才有订单,有了订单才有商品数据。
function getUsers(){
setTimeout(()=>{
let data = "用户数据";
iterator.next(data);
},1000);
}
function getOrders(){
setTimeout(()=>{
let data = "订单数据";
iterator.next(data);
},1000);
}
function getGoods(){
setTimeout(()=>{
let data = "商品数据";
iterator.next(data);
},1000);
}
function * gen(){
let users = yield getUsers();
console.log(users);
let orders = yield getOrders();
console.log(orders);
let goods = yield getGoods();
console.log(goods);
}
let iterator = gen();
iterator.next();
结果:
2.14 Promise
Promise 是 ES6 引入的异步编程(文件操作 网络操作(ajax,request) 数据库操作)的新解决方案。语法上 Promise 是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果;
- Promise 构造函数:
Promise (excutor) {} ; Promise.prototype.then 方法;Promise.prototype.catch 方法;
其做法就是:**将异步函数结果成功或失败的处理和操作提出来,以前是在回调函数中操作
每个promise对象都有两个属性:
- PromiseState:保存Promise当前的状态
- PromiseValue:保存Promise返回的值
const p = new Promise(function(resolve,reject){
setTimeout(function(){
let data = "数据";
resolve(data);
let err = "失败了!";
reject(err);
},1000);
});
p.then(function(value){
console.log(value);
}, function(reason){
console.log(reason);
});
实例1:封装读文件的操作
写法一:一般写法
const fs = require("fs");
fs.readFile("resources/text.txt",(err,data)=>{
if(err) throw err;
console.log(data.toString());
});
写法二:利用Promise
const p = new Promise(function(resolve,data){
fs.readFile("resources/text.txt",(err,data)=>{
if(err) reject(err);
resolve(data);
});
});
p.then(function(value){
console.log(value.toString());
},function(reason){
console.log(reason);
})
?
实例2:封装Ajax请求
写法一:原生请求
const xhr = new XMLHttpRequest();
xhr.open("GET","https://api.apiopen.top/getJoke");
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
if(xhr.status>=200 && xhr.status< 300){
console.log(xhr.response);
} else{
console.error(xhr.status);
}
}
}
写法二:利用Promise
const p = new Promise(function(resolve,reason){
const xhr = new XMLHttpRequest();
xhr.open("GET","https://api.apiopen.top/getJoke");
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
if(xhr.status>=200 && xhr.status < 300){
resolve(xhr.response);
}else{
reason(xhr.status);
}
}
}
});
p.then(function(value){
console.log(value.toString());
},function(reason){
console.log(reason);
})
?
2. Promise.prototype.then
要点:
- 调用 then 方法,then 方法的返回结果是 promise 对象,所以可以链式调用;
- Promise 对象的状态由回调函数的结果决定:
- 如果回调函数中返回的结果是非 promise 类型的数据,则状态为成功,返回值为对象的成功值;
- 如果返回的是 Promise 类型的数据,则该 Promise 对象的状态决定上面 Promise 对象 p 的状态;
- 如果是抛出错误,则Promsie对象的状态为 rejected,PromiseValue就为抛出来的那个错误的值。
const p = new Promise((resolve,reject) => {
setTimeout(() => {
resolve("用户数据");
},1000);
});
const result = p.then(value => {
console.log(value);
},reason => {
console.error(reason);
})
p.then(value=>{},reason=>{}).then(value=>{},reason=>{});
console.log(result);
在回调函数中什么也不返回的结果:
?
3. 语法糖
?
2.15 Set
ES6 提供了新的数据结构 Set(集合)。它类似于数组,但成员的值都是唯一的,集合实现了 iterator(迭代器)接口,所以可以使用 扩展运算符 和 **for…of… **进行遍历,
1. Set 的属性和方法
-
new Set(接收一个可迭代数组),自动去重 -
size:返回集合的元素个数;注意不是用 length!!! -
add:增加一个新元素,返回当前集合; -
delete:删除元素,返回 boolean 值; -
has:检测集合中是否包含某个元素,返回 boolean 值; -
clear:清空集合,返回 undefined;
let s = new Set(); console.log(s,typeof s);
let s1 = new Set(["大哥","二哥","三哥","四哥","三哥"]);
console.log(s1);
console.log(s1.size);
s1.add("大姐");
console.log(s1);
let result = s1.delete("三哥");
console.log(result);
console.log(s1);
let r1 = s1.has("二姐");
console.log(r1);
s1.clear();
console.log(s1);
结果:
?
2. Set实践
let arr = [1,2,3,4,5,4,3,2,1];
let res1 = [...new Set(arr)];
console.log(res1);
let arr2 = [3,4,5,6,5,4,3];
let res2 = [...new Set(arr)].filter(item => new Set(arr2).has(item));
console.log(res2);
let union = [...new Set([...arr,...arr2])];
console.log(union);
let result1 = [...new Set(arr)].filter(item =>!(new Set(arr2).has(item)));
console.log(result1);
2.16 Map
ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合。但是**“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键**。Map 也实现了iterator 接口,所以可以使用**『扩展运算符』和『for…of…』**进行遍历;
Map 的属性和方法:
-
size:返回 Map 的元素个数; -
set: 增加一个新元素,返回当前 Map; -
get:返回键名对象的键值; -
has:检测 Map 中是否包含某个元素,返回 boolean 值; -
clear:清空集合,返回 undefined;
?
2.17 Class 类
ES6 提供了更接近传统语言(Java,C++)的写法,引入了 Class(类)这个概念,作为对象的模板。通过 class 关键字,可以定义类。基本上,ES6 的 class 可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的 class 写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已;
要点:
-
class 声明类; -
constructor 定义构造函数初始化; -
extends 继承父类; -
super 调用父级构造方法; -
static 定义静态方法和属性; -
父类方法可以重写;
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 shouji{
constructor(brand,price) {
this.brand = brand;
this.price = price;
}
call(){
console.log("我可以打电话!");
}
}
let HuaWeiplus = new shouji("华为",5999);
HuaWeiplus.call();
console.log(HuaWeiplus);
?
1. Class 中的静态成员
要点:
- ES5 中实例对象和函数对象的属性是不相通的,实例对象跟构造函数的原型对象是相通的。函数对象的属性属于函数对象,不属于实例对象。
- ES6 中类中加了 static 的属性是静态属性,静态属性属于类而不属于实例对象。
function Phone(){}
Phone.name = "手机";
Phone.change = function(){
console.log("我可以改变世界!");
}
let nokia = new Phone();
console.log(nokia.name);
nokia.change();
Phone.prototype.color = "黑色";
console.log(nokia.color);
class Phone{
static name = "手机";
static change(){
console.log("我可以改变世界!");
}
}
let nokia = new Phone();
console.log(nokia.name);
?
2. 构造函数实现继承
function Phone(brand,price){
this.brand = brand;
this.price = price;
}
Phone.prototype.call = function(){
console.log("我可以打电话!");
}
function SmartPhone(brand,price,color,size){
Phone.call(this,brand,price);
this.color = color;
this.size = size;
}
SmartPhone.prototype = new Phone;
SmartPhone.prototype.constructor = SmartPhone;
SmartPhone.prototype.photo = function(){
console.log("我可以拍照!");
}
SmartPhone.prototype.game = function(){
console.log("我可以玩游戏!");
}
const chuizi = new SmartPhone("锤子",2499,"黑色","5.5inch");
console.log(chuizi);
chuizi.call();
chuizi.photo();
chuizi.game();
class Phone{
constructor(brand,price) {
this.brand = brand;
this.price = price;
}
call(){
console.log("我可以打电话!");
}
}
class SmartPhone extends Phone{
constructor(brand,price,color,size) {
super(brand,price);
this.size = size;
}
photo(){
console.log("我可以拍照!");
}
game(){
console.log("我可以玩游戏!");
}
}
const chuizi = new SmartPhone("小米",1999,"黑色","5.15inch");
console.log(chuizi);
chuizi.call();
chuizi.photo();
chuizi.game();
ES5中的结果:
ES6中的结果:
3. 子类对父类方法的重写
在子类声明一个跟父类同名的方法
class Phone{
constructor(brand,price) {
this.brand = brand;
this.price = price;
}
call(){
console.log("我可以打电话!");
}
}
class SmartPhone extends Phone{
constructor(brand,price,color,size) {
super(brand,price);
this.size = size;
}
photo(){
console.log("我可以拍照!");
}
game(){
console.log("我可以玩游戏!");
}
call(){
console.log("我可以进行视频通话!");
}
}
const chuizi = new SmartPhone("小米",1999,"黑色","5.15inch");
console.log(chuizi);
chuizi.call();
chuizi.photo();
chuizi.game();
结果:
4. class 中 getter 和 setter
class Phone{
get price(){
console.log("价格属性被读取了!");
return 123;
}
set price(newVal){
console.log("价格属性被修改了!");
}
}
let s = new Phone();
console.log(s.price);
s.price = 'free'
?
2.18 数值扩展
Number.EPSILON 是 JavaScript 表示的最小精度;
EPSILON 属性的值接近于 2.2204460492503130808472633361816E-16;
应用:主要用在浮点数的运算上
ES6 提供了二进制和八进制数值的新的写法,分别用前缀 0b 和 0o 表示;
- Number.isFinite() 与 Number.isNaN() :
Number.isFinite() 用来检查一个数值是否为有限的;
Number.isNaN() 用来检查一个值是否为 NaN;
- Number.parseInt() 与 Number.parseFloat():
ES6 将全局方法 parseInt 和 parseFloat,移植到 Number 对象上面,使用不变;
用于去除一个数的小数部分,返回整数部分;
Number.isInteger() 用来判断一个数值是否为整数;
function equal(a, b){
return Math.abs(a-b) < Number.EPSILON;
}
equal = (a, b) => Math.abs(a-b) < Number.EPSILON;
console.log(0.1 + 0.2 === 0.3);
console.log(equal(0.1 + 0.2, 0.3));
let b = 0b1010;
let o = 0o777;
let d = 100;
let x = 0xff;
console.log(x);
console.log("2、Number.isFinite 检测一个数值是否为有限数");
console.log(Number.isFinite(100));
console.log(Number.isFinite(100/0));
console.log(Number.isFinite(Infinity));
console.log("3. Number.isNaN 检测一个数值是否为 NaN"); console.log(Number.isNaN(123));
console.log(Number.parseInt('5211314love'));
console.log(Number.parseFloat('3.1415926神奇'));
console.log(Number.isInteger(5));
console.log(Number.isInteger(2.5));
console.log(Math.trunc(3.5));
console.log(Math.sign(100));
console.log(Math.sign(0));
console.log(Math.sign(-20000));
?
2.19 对象方法的扩展
ES6 新增了一些 Object 对象的方法:
-
Object.is 用来比较两个值是否严格相等,与『===』行为基本一致,除了(+0 与 NaN); -
Object.assign 用于对象的合并,将源对象的所有可枚举属性,复制到目标对象; -
proto、Object.setPrototypeOf、 Object.setPrototypeOf 可以直接设置原型对象;
console.log(Object.is(120,120));
console.log(Object.is(NaN,NaN));
console.log(NaN === NaN);
const config1 = {
host : "localhost",
port : 3306,
name : "root",
pass : "root",
test : "test"
}
const config2 = {
host : "http://zibo.com",
port : 300300600,
name : "root4444",
pass : "root4444",
test2 : "test2"
}
console.log(Object.assign(config1,config2));
const school = {
name : "尚硅谷"
}
const cities = {
xiaoqu : ['北京','上海','深圳']
}
Object.setPrototypeOf(school,cities);
console.log(Object.getPrototypeOf(school));
console.log(school);
结果:
?
2.20 模块化
模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来;
这里讲一下 ES6 import 和 export 的知识点
1. ES6模块数据暴露语法(export)汇总
m.js(逐个导出模块):
export let school = "尚硅谷";
export function teach(){
console.log("我们可以教你开发技术!");
}
n.js(统一导出模块):
let school = "尚硅谷";
function findJob(){
console.log("我们可以帮你找到好工作!");
}
export {school,findJob}
o.js(默认导出模块):
export default{
school : "尚硅谷",
change : function(){
console.log("我们可以帮你改变人生!");
}
}
index.html(引入和使用模块):
结果:
2. ES6导入模块语法(import)汇总
<script type="module">
import * as m from "./js/m.js";
console.log(m);
console.log(m.school);
m.teach();
import * as n from "./js/n.js";
console.log(n);
console.log(n.school);
n.findJob();
import * as o from "./js/o.js";
console.log(o);
console.log(o.default.school);
o.default.change();
import {school,teach} from "./js/m.js";
import {school as xuexiao,findJob} from "./js/n.js";
import {default as one} from "./js/o.js";
console.log(school);
teach();
console.log(xuexiao);
console.log(one);
console.log(one.school);
one.change();
import oh from "./js/o.js";
console.log(oh);
console.log(oh.school);
oh.change();
</script>
浏览器使用ES6模块化的方式是将代码整合到另一个文件中,然后用 script 标签引入,但需要指定 type = "module" :
其他具体要点见我的另两篇文章 前端工程化 和 Webpack 究竟是什么?如何理解Webpack 中关于对模块化的讲解。
?
2.21 Babel对ES6模块化代码转换
1. babel 是什么
Babel 是一个 JavaScript 编译器,能够将新的ES规范语法转换成ES5的语法;因为不是所有的浏览器都支持最新的ES规范,所以一般项目中都需要使用Babel进行转换;
具体的使用方法见 Webpack 究竟是什么?如何理解Webpack
?
2.22 ES6模块化引入NPM包
?
三、ES7 新特性
新特性总体概况
1、Array.prototype.includes
- 判断数组中是否包含某元素,语法:arr.includes(元素值);
2、指数操作符
- 在 ES7 中引入指数运算符「**」,用来实现幂运算,功能与 Math.pow 结果相同;例如:2的10次方:2**10;
?
四、ES8 新特性
4.1 新特性总体概况
1、async 和 await
2、对象方法扩展
?
4.2 async 和 await
async 和 await 两种语法结合可以让异步代码看起来像同步代码一样,简化异步函数的写法;
1. async 函数要点
-
async 函数的返回值为 promise 对象; -
promise 对象的结果由 async 函数执行的返回值决定:
- 只要返回的值不是 promise 类型的对象,哪怕是没有返回的值,都是一个成功的 Promise 对象
- 返回的结果是一个 Promise 对象,Promise 对象是成功的,那 async 函数返回的结果也是成功的。成功的值就是Promise对象返回的结果。
2. await 表达式要点
-
await 必须写在 async 函数中; -
await 右侧的表达式一般为 promise 对象; -
await 返回的是 promise 成功的值; -
await 的 promise 失败了, 就会抛出异常, 需要通过 try…catch 捕获处理;
const p = new Promise((resolve,reject)=>{
resolve("成功啦!");
})
async function fn(){
let result = await p;
console.log(result);
}
fn();
?
3. async 和 await 读取文件案例
const fs = require("fs");
function readText() {
return new Promise((resolve, reject) => {
fs.readFile("../resources/text.txt", (err, data) => {
if (err) reject(err);
resolve(data);
})
})
}
function readText1() {
return new Promise((resolve, reject) => {
fs.readFile("../resources/test1.txt", (err, data) => {
if (err) reject(err);
resolve(data);
})
})
}
function readText2() {
return new Promise((resolve, reject) => {
fs.readFile("../resources/test2.txt", (err, data) => {
if (err) reject(err);
resolve(data);
})
})
}
async function main(){
let t0 = await readText();
let t1 = await readText1();
let t2 = await readText2();
console.log(t0.toString());
console.log(t1.toString());
console.log(t2.toString());
}
?
4. async 和 await 结合发送ajax请求
function sendAjax(url){
return new Promise((resolve,reject)=>{
const x = new XMLHttpRequest();
x.open("GET",url);
x.send();
x.onreadystatechange = function(){
if(x.readyState == 4){
if(x.status>=200 && x.status<300){
resolve(x.response);
}else{
reject(x.status);
}
}
}
});
}
async function main(){
let result = await sendAjax("https://api.apiopen.top/getJoke"); console.log(result);
}
main();
?
4.3 对象方法扩展
ES8 中扩展的对象方法有:Object.values 、Object.values 、Object.entries 和 Object.getOwnPropertyDescriptors
-
Object.keys():获取对象所有的键; -
Object.values():获取对象所有的值,返回一个给定对象的所有可枚举属性值的数组; -
Object.entries():返回给定对象自身可遍历属性 [key,value] 的数组; -
Object.getOwnPropertyDescriptors():返回指定对象所有自身属性的描述对象;
let school = {
name : "訾博",
age : 24,
sex : "男"
}
console.log(Object.keys(school));
console.log(Object.values(school));
console.log(Object.entries(school));
const map = new Map(Object.entries(school));
console.log(map);
console.log(map.get("name"));
console.log(Object.getOwnPropertyDescriptors(school));
const obj = Object.create(null,{
name : {
value : "訾博",
writable : true,
configuration : true,
enumerable : true
}
});
?
五、ES9的新特性
5.1 新特性总体概况
1、Rest 参数与 spread 扩展运算符
2、正则扩展
?
5.2 扩展运算符和rest参数
Rest 参数和扩展运算符在 ES6 中已经引入,不过 ES6 中是只针对数组,在 ES9 中为对象提供了像数组一样的 扩展运算符和 rest参数。
function connect({ host,port,...user}) {
console.log(host);
console.log(port);
console.log(user);
}
connect({
host: '127.0.0.1',
port: 3306,
username: 'root',
password: 'root',
type: 'master'
});
const skillOne = { q: '天音波'}
const skillTwo = { w: '金钟罩'}
const skillThree = { e: '天雷破'}
const skillFour = { r: '猛龙摆尾', z: '胡说八道'}
const mangseng = {...skillOne,...skillTwo,...skillThree,...skillFour};
console.log(mangseng)
结果:
5.3 正则扩展
1. 命名捕获分组
ES9 允许命名捕获组使用符号『?』,这样获取捕获结果可读性更强;
let str = '<a href="http://www.baidu.com">訾博</a>';
const reg = /<a href="(.*)">(.*)<\/a>/;
const result = reg.exec(str);
console.log(result);
console.log(result[1]);
console.log(result[2]);
const reg1 = /<a href="(?<url>.*)">(?<text>.*)<\/a>/;
const result1 = reg1.exec(str);
console.log(result1);
console.log(result1.groups.url);
console.log(result1.groups.text);
2. 反向断言
ES9 支持反向断言,通过对匹配结果前面的内容进行判断,对匹配进行筛选;
let str = "JS5201314你知道么555啦啦啦";
const reg = /\d+(?=啦)/;
const result = reg.exec(str);
console.log(result);
const reg1 = /(?<=么)\d+/;
const result1 = reg.exec(str);
console.log(result1);
3. dotAll 模式
正则表达式中的点. 匹配除回车外的任何单字符,标记『s』改变这种行为,允许行终止符出现;
let str = `
<ul>
<li>
<a>肖生克的救赎</a>
<p>上映日期: 1994-09-10</p>
</li>
<li>
<a>阿甘正传</a>
<p>上映日期: 1994-07-06</p>
</li>
</ul>`;
const reg = /<li>\s+<a>(.*?)<\/a>\s+<p>(.*?)<\/p>/;
const reg = /<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/gs;
const result = reg.exec(str);
console.log(result);
let result;
let data = [];
while(result = reg.exec(str)){
console.log(result);
data.push({title:result[1],time:result[2]});
}
console.log(data);
结果:
?
六、ES10的新特性
6.1 新特性总体概况
对象扩展方法:
1、Object.fromEntries
2、trimStart 和 trimEnd
3、Array.prototype.flat与 flatMap
4、Symbol.prototype.description
?
6.2 Object.fromEntries
将二维数组或者 map 转换成对象;之前学的Object.entries是将对象转换成二维数组;
const result = Object.fromEntries([
["name","小小"],
["age",24],
]);
console.log(result);
const m = new Map();
m.set("name","小小");
m.set("age",24);
const result1 = Object.fromEntries(m);
console.log(result1);
结果:
6.3 Array.prototype.flat与 flatMap
将多维数组转换成低维数组;
const arr = [1,2,3,[4,5],6,7];
console.log(arr.flat());
const arr2 = [1,2,3,[4,5,[6,7]],8,9];
console.log(arr2.flat());
console.log(arr2.flat(2));
const arr3 = [1,2,3,4,5];
const result0 = arr3.map(item => item * 10);
console.log(result0);
const result = arr3.map(item => [item * 10]);
console.log(result);
const result1 = arr3.flatMap(item => [item * 10]);
console.log(result1);
?
6.4 Symbol.prototype.description
获取Symbol的描述字符串;
let s = Symbol("小小");
console.log(s.description)
?
七、ES11的新特性
7.1 新特性总体概况
1、类的私有属性
2、Promise.allSettled
3、String.prototype.matchAll
4、可选链操作符
5、动态 import 导入
6、BigInt
7、绝对全局对象globalThis
?
7.2 类的私有属性
class Person{
name;
#age;
#weight;
constructor(name, age, weight){
this.name = name;
this.#age = age;
this.#weight = weight;
}
intro(){
console.log(this.name);
console.log(this.#age);
console.log(this.#weight);
}
}
const girl = new Person("小兰",18,"90kg");
console.log(girl);
console.log(girl.name);
console.log(girl.age);
girl.intro();
?
7.3 Promise.allSettled
获取多个promise执行的结果集;返回的结果 PromiseStatus 永远是成功的状态。PromiseValue是每个对象值合起来的数组
const p1 = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve("商品数据-1");
},1000);
});
const p2 = new Promise((resolve,reject)=>{
setTimeout(()=>{
reject("失败啦");
},1000);
});
const result = Promise.allSettled([p1,p2]);
console.log(result);
const result1 = Promise.all([p1,p2]);
console.log(result1);
Promise.all 是要所有的 Promise 对象都成功才返回成功,不然就是失败的Promise对象。而Promise.allSettled的结果永远是成功的状态。
?
7.4 String.prototype.matchAll
let str = `
<ul>
<li>
<a>肖生克的救赎</a>
<p>上映日期: 1994-09-10</p>
</li>
<li>
<a>阿甘正传</a>
<p>上映日期: 1994-07-06</p>
</li>
</ul>`;
const reg = /<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/sg;
const result = str.matchAll(reg);
console.log(...result);
for(let v of result){
console.log(v);
}
?
7.5 可选链操作符
如果存在则往下走,省略对对象是否传入的层层判断;
function main(config){
const dbHost = config && config.db && config.db.host;
const dbHost = config?.db?.host;
console.log(dbHost);
}
main({
db:{
host:"192.168.1.100",
username:"root"
},
cache:{
host:"192.168.1.200",
username:"admin"
}
});
?
7.6 动态 import 导入(按需加载)
以前的 import 是一股脑把所有需要的模块全部导进来,就不能实现懒加载,效率也较低。
使用 import 动态导入后返回的是一个 Promise 对象。
// index.html
<body>
<button id="btn">点击</button>
<script src="app.js" type="module"></script>
</body>
export function hello(){
alert('Hello');
}
const btn = document.getElementById('btn');
btn.onclick = function(){
import('./hello.js').then(module => {
module.hello();
});
}
?
7.7 Bigint
注意:bigint类型不能直接跟普通的 int 类型做运算
let n = 100n;
console.log(n,typeof(n));
let m = 123;
console.log(BigInt(m));
let max = Number.MAX_SAFE_INTEGER;
console.log(max);
console.log(max+1);
console.log(max+2);
console.log(BigInt(max));
console.log(BigInt(max)+BigInt(1));
console.log(BigInt(max)+BigInt(2));
结果:
7.8 绝对全局对象globalThis
无论执行环境是什么,始终指向全局对象
|