ES6-ES11新特性知识点
一、ES6
1、查看ES6兼容性
http://kangax.github.io/compat-table/es6/ 可查看兼容性
2、let定义变量
快速入门:
//特点:
//1.let变量不能重复声明,只在当前块生效
//2.不存在变量提升
//3.不影响作用域链效果
//4.存在 暂时性死区:代码块内,使用let命令声明变量之前,该变量都是不可用的
let star = '小猪';
深入理解:
3、const定义常量
快速入门:
//特点:
//1.const声明常量时必须赋初值,值一旦确认便不可修改,一般常量名大写(代码规范)
//2.const常量同块内不能重复声明,只在当前块生效
//3.不影响作用域链效果
//4.不存在变量提升
//5.存在暂时性死区:代码块内,使用const命令声明常量之前,该常量都是不可用的
const star = '小猪';
深入理解:
4、作用域
快速入门:
ES6之后作用域为:
全局作用域、函数作用域、{}块级作用域(新增)、
eval(ES严格模式下存在)
深入理解:
5、变量的解构赋值
快速入门:
//ES6 允许按照一定模式从数组和对象中提取值,对变量进行赋值,
//这被称为解构赋值。
//1. 数组的结构
const F4 = ['小沈阳','刘能','赵四','宋小宝'];
let [xiao, liu, zhao, song] = F4;
console.log(xiao); //小沈阳
console.log(liu); //刘能
console.log(zhao);//赵四
console.log(song);//宋小宝
//2. 对象的解构
const zhao = {
name: '赵本山',
age: '不详',
xiaopin: function(){
console.log("我可以演小品");
}
};
let {name, age, xiaopin} = zhao;
console.log(name);//赵本山
console.log(age);//不详
console.log(xiaopin);
/**
* ƒ (){
console.log("我可以演小品");
}
*/
xiaopin();//我可以演小品
//结构对象,需要与对象zhao 内部函数属性同名
let {xiaopin} = zhao;
xiaopin();//我可以演小品
深入理解:
6、模板字符串
快速入门:
// ES6 引入新的声明字符串的方式 『``』 反引号
//语法
let str1=`我也是一字符串哦`
//2. 内容中可以直接出现换行符
let str2 = `<ul>
<li>沈腾</li>
<li>玛丽</li>
<li>魏翔</li>
<li>艾伦</li>
</ul>`;
//3. 变量拼接 ${}
let lovest = '魏翔';
let out = `${lovest}是我心目中最搞笑的演员!!`;
console.log(out);
深入理解:
7、简化对象写法
快速入门:
<script>
//ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。
//这样的书写更加简洁
let name = '尚硅谷';
let change = function(){
console.log('我们可以改变你!!');
}
//ES6允许在大括号里面,直接写入变量和函数名,作为对象的属性和方法
// ES6还允许在对象中声明函数时,去掉:和function
let SCHOOL = {
name,//等价于name:name
change,//等价于change(){}
//简化函数声明等价于improve:function(){}
improve(){
console.log("我们可以提高你的技能");
}
}
console.log(school);
</script>
8、箭头函数
快速入门:
// ES6 允许使用「箭头」(=>)定义函数。
//声明一个函数
// let fn = function(a,b){return a + b;}
let fn = (a,b) => {
return a + b;
}
//调用函数
let result = fn(1, 2);
console.log(result);//3
//1.箭头函数 this 是静态的. this 始终指向函数声明时所在作用域下的this 的值,不可改变
function getName(){
console.log(this.name);
}
let getName2 = () => {
console.log(this.name);
}
//设置 window 对象的 name 属性
window.name = '尚硅谷';
const school = {
name: "ATGUIGU"
}
//直接调用
// getName(); //尚硅谷
// getName2(); //尚硅谷
//call 方法调用
// getName.call(school);//ATGUIGU 普通函数this指向调用它的对象
// getName2.call(school);//尚硅谷 箭头函数this依旧指向window
//2. 不能作为构造函数实例化对象 报错Unacught TypeError:XXX is not a constructor
// let Person = (name, age) => {
// this.name = name;
// this.age = age;
// }
// let me = new Person('xiao',30);
// console.log(me);
//3.不能使用 arguments 变量 报错Uncaught ReferenceError:arguments is not defined
// let fn = () => {
// console.log(arguments);
// }
// fn(1,2,3);
//4.箭头函数简写
//(1) 省略小括号, 当形参有且只有一个的时候
// let add = n => {
// return n + n;
// }
// console.log(add(9));//18
//(2) 省略花括号, 当代码体只有一条语句的时候, 此时 return 必须省略
// 而且语句的执行结果就是函数的返回值
//let pow = n => n * n;
// console.log(pow(8));//64
9、参数默认值
//ES6 允许给函数参数赋值初始值
//1. 形参初始值 具有默认值的参数, 一般位置要靠后(代码规范)
// function add(a,c=10,b) {
// return a + b + c;
// }
// let result = add(1,2);
// console.log(result);
//2.可以 与解构赋值结合
function connect({
host = "127.0.0.1", //默认值 会被传入覆盖
username,
password,
port
}) {
console.log(host)
console.log(username)
console.log(password)
console.log(port)
}
let option = { //this指向 option
host: this.host,
username: this.username,
password: this.password,
port: this.port
}
option.host = "localhost"
option.username = "user"
//解构赋值 类似 {host,username,password,port}=option
connect(option)
10、rest参数
// 新特性:ES6 引入 rest 参数,用于获取函数的实参,用来代替 arguments
// ES5 获取实参的方式
// function date(){
// console.log(arguments);
// }
// date('白芷','阿娇','思慧');
// rest 参数 获取实参的方式
// function date(...args){ //res参数 ...args 可变参数列表 是一个数组
// console.log(args);// 因为是数组 所以可以传入 filter some every map
// }
// date('阿娇','柏芝','思慧');
// !!!语法限制 rest 参数必须要放到参数最后
// function fn(a,b,...args){
// console.log(a);
// console.log(b);
// console.log(args);
// }
// fn(1,2,3,4,5,6);
11、拓展运算符
// 『...』 扩展运算符能将『数组』转换为逗号分隔的『参数序列』
//声明一个数组 ...
const tfboys = ['易烊千玺', '王源', '王俊凯'];
// 声明一个函数
function chunwan() {
console.log(arguments); // '易烊千玺','王源','王俊凯'
}
chunwan(...tfboys); //...后等同于 chunwan('易烊千玺','王源','王俊凯')
与rest参数不同的是 拓展运算符书写在 函数调用的实参位置
应用场景:
<body>
<div></div>
<div></div>
<div></div>
<script>
//1. 数组的合并 情圣 误杀 唐探
// const kuaizi = ['王太利','肖央'];
// const fenghuang = ['曾毅','玲花'];
// //ES5做法 const zuixuanxiaopingguo = kuaizi.concat(fenghuang);
// ES6做法: 拓展运算符
// const zuixuanxiaopingguo = [...kuaizi, ...fenghuang];
// console.log(zuixuanxiaopingguo);
//2. 数组的克隆
// const sanzhihua = ['E','G','M'];
// const sanyecao = [...sanzhihua];// ['E','G','M'] 数组内部若存在引用类型则为浅拷贝
// console.log(sanyecao);
//3. 将伪数组转为真正的数组
const divs = document.querySelectorAll('div');
console.log(divs); //对象
const divArr = [...divs]; //数组
console.log(divArr); // arguments
</script>
</body>
12、Symbol
**含义:**ES6引入的一种新的数据类型 Symbol,表示独一无二的值,
主要作用是给对象添加属性和方法
是js第七种数据类型
特点:
1、Symbol的值唯一,用来解决命名冲突问题
2、Symbol值不能与其他数据类型进行运算
3、 Symbol定义的对象属性不能使用 for…in循环遍历,
但可以使用Reflect.ownKeys来获取对象的所有键名
一、创建方式
//创建Symbol
//Symbol是一个函数对象
let s = Symbol();
//console.log(s, typeof s);
//Symbol('xuexi') 这种方式创建的Symbol值是变化的
let s2 = Symbol('xuexi'); // xuexi是类似注释的功能
let s3 = Symbol('xuexi');
console.log(s2 === s3); //false
//Symbol.for 创建 for() 根据参数字符串创建Symbol,得到唯一的Symbol值
// Symbol.for('xuexi') 这种方式创建的Symbol值是不变的
let s4 = Symbol.for('xuexi');
let s5 = Symbol.for('xuexi');
console.log(s4 === s5); //true
//注意点
//不能与其他数据进行运算
//ncaught TypeError: Cannot convert a Symbol value to a number at
//let result = s + 100;
// let result = s > 100;
// let result = s + s;
// USONB you are so niubility Js七种数据类型
// u undefined
// s string symbol
// o object
// n null number
// b boolean
二、应用场景
//向对象中添加方法 up down
//ES5方式
//若在已存在的对象上进行添加属性时,
//直接声明方式可能存在与原对象属性命名冲突问题
let game = {
name: '俄罗斯方块',
up: function () {},
down: function () {}
};
//ES6 利用Symbol解决
//添加方式一:
// let methods = {
// up: Symbol(),
// down: Symbol()
// };
// game[methods.up] = function(){
// console.log("我可以改变形状");
// }
// game[methods.down] = function(){
// console.log("我可以快速下降!!");
// }
// console.log(game);
//添加方式二
let youxi = {
name: "狼人杀",
[Symbol('say')]: function () {
console.log("我可以发言")
},
[Symbol('zibao')]: function () {
console.log('我可以自爆');
}
}
console.log(youxi)
//youxi[Symbol('say')]();报错 无法调用 因为 Symbol('say') 方式创建Symbol的值是动态变化的
//console.log(Symbol('say')===Symbol('say')); false
youxi[Reflect.ownKeys(youxi)[1]](); //调用方法
三、内置属性
//Symbol内置属性 控制对象在特定情景下的表现 定义后在特定场景自动触发 拓展了对象的功能
//1. 例子 Symbol.hasInstance
//其他对象 与当前对象进行instanceof时 [Symbol.hasInstance] 会被触发调用 控制类型检测
// class Person{
// static [Symbol.hasInstance](param){ //param实参为 instanceof表达式左侧内容
// console.log(param);
// console.log("我被用来检测类型了");
// return false;//instanceof结果为false
// }
// }
// let o = {};
// console.log(o instanceof Person);
//2.例子 [Symbol.isConcatSpreadable]
// 设置数组是否在合并时展开(数组传化为逗号隔开的数字序列)
// const arr = [1,2,3];
// const arr2 = [4,5,6];
// arr2[Symbol.isConcatSpreadable] = false;//不可展开
// console.log(arr.concat(arr2));//1,2,3,arr2数组
13、迭代器
含义:遍历器(Iterator)就是一种机制。它是一种接口,为各种不同的数据结构提 供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作。
Iterator 在js中指对象的一个属性,也就是Symbol(Symbol.Iterator)
ES6 创造了一种新的遍历命令 for…of 循环,Iterator 接口主要供 for…of 消费
原生具备Iterator接口的数据:
a) Array
b) Arguments
c) Set
d) Map
e) String
f) TypedArray
g) NodeList
原理:
a) Symbol.Iterator返回创建一个指针对象,指向当前数据结构的起始位置
b) 指针对象 第一次调用对象的 next ()方法,指针自动指向数据结构的第一个成员
c) 接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员
d) 每调用 next 方法返回一个包含 value 和 done 属性的对象
//声明一个数组
const xiyou = ['唐僧', '孙悟空', '猪八戒', '沙僧'];
console.log(xiyou);
//使用 for...of 遍历数组
// for(let v of xiyou){
// console.log(v);
// }
//原理
//iterator对象的next方法执行返回 遍历数组 内容
let iterator = xiyou[Symbol.iterator]();
//调用iterator对象的next方法
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
自定义迭代器遍历对象
//声明一个对象 自定义对象无法使用 for of 遍历
const banji = {
name: "六年级一班",
stus: [
'xiaoming',
'xiaoning',
'xiaotian',
'knight'
],
/*
对象进行 for...of 循环时,会调用 Symbol.iterator 方法,
返回该对象的默认遍历器
*/
[Symbol.iterator]() {
//this 当前对象=banji
let keys = Object.keys(this)
let len = keys.length
let values = Object.values(this)
//索引变量
let index = 0;
let _this = this;
return { //a.返回一个对象 为指针对象
next: function () { //b.c.指针对象里设置next方法
if (index < len) {
//console.log(_this);
const result = {
value: {
k: keys[index],
v: values[index]
},
done: false //表遍历未结束
};
//下标自增
index++;
//返回结果
return result;
} else {
//d.返回一个包含value合done属性的对象
return {
value: undefined,
done: true //遍历结束
};
}
}
};
}
}
//遍历这个对象
for (let v of banji) {
console.log(v);
}
14、生成器函数
概念: 生成器函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同
特点:
1、生成器函数执行时是可暂停的,之后又能从暂停处继续执行。(暂停标识:yield
)
2、其中yield语句类似于return:可以返回一个内部状态值,yield 后跟要返回的内容
但不同的是,return结束函数执行,让生成器对象的done状态变为true
yield* 表示将任务交给别的生成器执行
3、调用生成器函数返回一个迭代器
5、生成器执行方法:next()的参数表示上一条yield语句的返回值,所有第一次使用next方法时,传递的参数是无效的。
入门语法示例:
//生成器其实就是一个特殊的函数,主要进行异步编程
//异步编程 纯回调函数 node fs ajax mongodb
//yield 算是函数代码的分隔符,将函数代码分块,next方法分块执行
//声明方式 *
function * gen(){
console.log(111);
yield '一只没有耳朵';//第一次next()返回 {value: '一只没有耳朵', done: false}
console.log(222);
yield '一只没有尾部';//第二次next()返回 {value: '一只没有尾部', done: false}
console.log(333);
yield '真奇怪';
console.log(444);
}
let iterator = gen();
//执行方式:生成器返回迭代器next()调用执行 done:false执行未结束
console.log(iterator.next());//执行显示 111 返回对象{value: '一只没有耳朵', done: false}
console.log(iterator.next());//执行显示 222 返回对象{value: '一只没有尾部', done: false}
console.log(iterator.next());
console.log(iterator.next());
//遍历
// for(let v of gen()){
// console.log(v);
// }
一、生成器函数的参数传递
//next传入的参数将作为上一个yeild语句的返回结果
function * gen(arg){
console.log(arg);
let one = yield 111;//111为返回结果
console.log(one);
let two = yield 222;
console.log(two);
let three = yield 333;
console.log(three);
}
//执行获取迭代器对象
let iterator = gen('AAA');
//第一次调用next()
console.log(iterator.next());
//第二次调用next() 传入的参数将会是上一个next的返回值
console.log(iterator.next('BBB'));
//第三次调用next()
console.log(iterator.next('CCC'));
//console.log(iterator.next('DDD'));
三、实际应用
案例1:
1s 后控制台输出 111 2s后输出 222 3s后输出 333
// 异步编程 应用 :文件操作 网络操作(ajax, request) 数据库操作
// 任务: 1s 后控制台输出 111 2s后输出 222 3s后输出 333
// ES5 写法
// :产生的回调地狱 代码可读性极差
// setTimeout(() => {
// console.log(111);
// setTimeout(() => {
// console.log(222);
// setTimeout(() => {
// console.log(333);
// }, 3000);
// }, 2000);
// }, 1000);
//ES6 实现
//声明第一个异步任务
function one(){
setTimeout(()=>{
console.log(111);
iterator.next();//调用two()方法
},1000)
}
//声明第二个异步任务
function two(){
setTimeout(()=>{
console.log(222);
iterator.next();//调用three()方法
},2000)
}
//声明第三个异步任务
function three(){
setTimeout(()=>{
console.log(333);
iterator.next(); //继续向下调用
},3000)
}
function * gen(){
//统一管理调用
yield one();
yield two();
yield three();
}
//调用生成器函数
let iterator = gen();
iterator.next();
案例2:
模拟获取 1、用户数据 2、订单数据 3、商品数据
//模拟获取 1、用户数据 2、订单数据 3、商品数据
//定时器模拟 请求过程
//1、获取用户数据
function getUsers(UserID){
setTimeout(()=>{
console.log("getUsers()获取到的用户数据")
console.log(UserID)
let data = '用户数据'+UserID;
iterator.next(data);//传递给下一个next()的参数将作为本次函数调用的返回值
}, 1000);
}
//2、获取订单数据
function getOrders(userData){
setTimeout(()=>{
console.log("getOrder获取到的用户数据")
console.log(userData)
let data = '订单数据'+123456;
iterator.next(data);
}, 1000)
}
//3、获取商品数据
function getGoods(orderData){
setTimeout(()=>{
console.log("getGoodsr获取到的订单数据")
console.log(orderData)
let data = '商品数据';
iterator.next(data);
}, 1000)
}
function * gen(UserId){
let users = yield getUsers(UserId);
let orders = yield getOrders(users);
let goods = yield getGoods(orders);
}
//调用生成器函数
let iterator = gen("992285544");
iterator.next();//执行getUser()
[译] 什么是 JavaScript 生成器?如何使用生成器? - 知乎 (zhihu.com)
15、class
含义:ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对
象的模板。
通过 class 关键字,可以定义类。基本上,ES6 的 class 可以看作只是
一个语法糖,它的绝大部分功能,ES5 都可以做到,新的 class 写法只是让对象
原型的写法更加清晰、更像面向对象编程的语法而已。
class定义静态成员属性
//static 修饰成员属性 由类名调用
class Phone{
//静态属性
static name = '手机';
static change(){
console.log("我可以改变世界");
}
}
let nokia = new Phone();
console.log(nokia.name);//undeifind
console.log(Phone.name);//手机
实现继承
1、es5 方式
//手机 父类
function Phone(brand, price){
this.brand = brand;
this.price = price;
}
Phone.prototype.call = function(){
console.log("我可以打电话");
}
//智能手机 子类
function SmartPhone(brand, price, color, size){
//this.Phone(brand,price)等价于
//SmartPhone.Phone(brand,price)子类调父类获得父类所有属性和函数
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.playGame = function(){
console.log("我可以玩游戏");
}
const chuizi = new SmartPhone('锤子',2499,'黑色','5.5inch');
console.log(chuizi);
2、ES6方式
方法重写
很像java的
//父类
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);// Phone.call(this, brand, price)
this.color = color;
this.size = size;
}
photo(){
console.log("拍照");
}
playGame(){
console.log("玩游戏");
}
//子类重写父类的方法 重写后无法调到父类的重名方法
call(){
console.log('我可以进行视频通话');
}
}
const xiaomi = new SmartPhone('小米',799,'黑色','4.7inch');
// console.log(xiaomi);
xiaomi.call();
xiaomi.photo();
xiaomi.playGame();
get和set方法
// get 和 set
class Phone{
//默认无参构造
get price(){
console.log("价格属性被读取了");
return 'iloveyou';
}
set price(newVal){//必须有参数
console.log('价格属性被修改了');
}
}
//实例化对象
let s = new Phone();
console.log(s.price);// iloveyou 执行class类中的price()方法
s.price = 'free';
(49条消息) JavaScript系列—class(静态方法和属性、实例属性、私有方法和属性)_jiaojsun的博客-CSDN博客
16、ES6数值拓展
//0. Number.EPSILON 是 JavaScript 表示的最小精度,主要解决精度问题
//EPSILON 属性的值接近于 2.2204460492503130808472633361816E-16
// function equal(a, b){
// //(两数差值 小于最小精度数) 表示 两数字想等解决精度问题
// if(Math.abs(a-b) < Number.EPSILON){
// return true;
// }else{
// return false;
// }
// }
// console.log(0.1 + 0.2 === 0.3);//fasle 不符合常理
// console.log(equal(0.1 + 0.2, 0.3))
//1. 变量值表示:二进制和八进制
// let b = 0b1010;
// let o = 0o777;
// let d = 100;
// let x = 0xff;
// console.log(x);
//2. Number.isFinite 检测一个数值是否为有限数
// console.log(Number.isFinite(100));//true
// console.log(Number.isFinite(100/0));//false
// console.log(Number.isFinite(Infinity));//false
//Infinity 表无线
//3. Number.isNaN 检测一个数值是否为 NaN(与数字相关)
// console.log(Number.isNaN(123));
//4. Number.parseInt Number.parseFloat 字符串转整数/小数 自动截取
// console.log(Number.parseInt('5211314love'));//5211314
// console.log(Number.parseFloat('3.1415926神奇'));3.1415926
//5. Number.isInteger 判断一个数是否为整数
// console.log(Number.isInteger(5));//true
// console.log(Number.isInteger(2.5));//false
//6. Math.trunc 将数字的小数部分抹掉
// console.log(Math.trunc(3.5)); //3
//7. Math.sign 判断一个数到底为正数 负数 还是零
console.log(Math.sign(100)); //1
console.log(Math.sign(0)); //0
console.log(Math.sign(-20000)); //-1
17、对象方法拓展
//1. Object.is 判断两个值是否完全相等
// console.log(Object.is(120, 120));// === true
// console.log(Object.is(NaN, NaN));// === true
//直接=== 永远false
// console.log(NaN === NaN);// === false
//2. Object.assign(obj1,obj2) 对象的合并
// 属性内容冲突时 obj2对象覆盖前面obj1对象
// const config1 = {
// host: 'localhost',
// port: 3306,
// name: 'root',
// pass: 'root',
// test: 'test'
// };
// const config2 = {
// host: 'http://atguigu.com',
// port: 33060,
// name: 'atguigu.com',
// pass: 'iloveyou',
// tes2: 'test2'
// }
// console.log(Object.assign(config1, config2));
//3. Object.setPrototypeOf(目标对象,原型对象) 设置原型对象 Object.getPrototypeof
//不推荐
const school = {
name: '尚硅谷'
}
const cities = {
xiaoqu: ['北京', '上海', '深圳']
}
Object.setPrototypeOf(school, cities);
console.log(Object.getPrototypeOf(school));
console.log(school);
18、ES6模块化
模块化是指将大的程序文件,拆分成有联系的小文件即模块
一、模块化优势
1、防止命名冲突
2、代码复用
3、高维护性
二、模块化规范产品
ES6之前js没有自己的模块规范化
ES6 之前的模块化规范有:
- CommonJS 规范=> NodeJS、Browserify
- AMD规范 => requireJS
- CMD规范 => seaJS
三、ES6模块化语法
模块功能主要由两个命令构成:export 和 import。
⚫ export 命令用于规定模块的对外接口
⚫ import 命令用于输入其他模块提供的功能
四、实例
//./js/module1.js文件
//export 对外暴露 school 和 teach()
//分别暴露方式
export let school='xuexiao'
export function teach(){
console.log("我可以教学生");
}
//./js/module2.js文件
let job="js开发"
function findJob(){
console.log("找工作!!!");
}
//统一对外暴露
export {job,findJob}
//./js/module3.js
//默认暴露
export default{
school:'xuexiao',
change:function(){
console.log("改变你");
}
}
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script type="module">
//1、通用导入方式
//./index.html 文件
//引入module1.js 取到所有export暴露数据(分别暴露) 存入module1
import * as m1 from './js/module1.js'
console.log(m1);
//引入module2.js 内容(统一暴露)
import * as m2 from './js/module2.js'
console.log(m2);
//引入module3.js 默认暴露
import * as m3 from './js/module3.js'
console.log(m3);
m3.default.change();
//2、结构赋值形式
import {school,teach} from './js/module1.js'
//重名时 可以使用别名,导入名称应和包内名称一致
import {school as qinghua,findJob} from './js/module2.js'
//默认暴露不可直接default
import {default as module3} from './js/module3.js'
console.log(school);
console.log(teach);
console.log(qinghua);
console.log(findJob);
console.log(module3);
//3、简便形式 (只针对默认暴露)
import mm3 from './js/module3.js'
console.log(mm3);
</script>
<!-- 导入入口文件 -->
<script src="./js/app.js" type="module"></script>
</body>
</html>
入口文件 ./js/app.js
//4、书写入口文件引入模块
import * as m1 from './module1.js'
import * as m2 from './module2.js'
import * as m3 from './module3.js'
console.log(m1);
console.log(m2);
console.log(m3);
五、模块化代码在项目中的使用方式
Bable转化
主要作用:将最新的ES6语法转化为浏览器可以识别的ES5语法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!--
1、安装
babel-cli babel命令行工具
babel-preset-env 预设包包含最新es语法
browserify 轻量打包工具,类似webpack
输入命令安装:
npm初始化:>npm init --yes
安装工具:?>npm i babel-cli / babel-preset-env / browserify -d
2、执行babel转换
局部安装:>npx babel 源代码目录 -d 编译结果目录 --presets=babel-preset-env
全局安装:>babel
3、打包
针对模块化入口文件,否则无法正常引入
>npx browserify 编译结果目录入口文件 -o 打包输出目录
例子:>npx browserify dist/js/app.js -o dist/index.js
-->
</body>
</html>
ES6模块化引入NPM包
二、ES7
/**
* 1、Array.prototype.includes() 检测数组是否包含某个元素
* 返回值 Boolean
* /
*
// const mingzhu = ['西游记','红楼梦','三国演义','水浒传'];
//判断
// console.log(mingzhu.includes('西游记')); //true
// console.log(mingzhu.includes('金瓶梅')); //false
/**
* 2、 ** 幂运算
*
*/
console.log(2 ** 10); // ES7
console.log(Math.pow(2, 10)); //ES5
三、ES8
1、async函数
作用:
async和await两种语法结合可以让异步代码像同步代码一样书写
特点:
1、async函数返回值为promise对象。
2、promise对象的结果由async函数执行的返回值决定
语法:
//async 函数(呃think)
//特殊函数 总是返回promise对象
//声明方式:
async function fn() {
//返回值特点:
// 返回的结果不是一个 Promise 类型的对象, 则就是成功 Promise 对象
// 1、返回一个字符串 返回结果仍是成功状态的Promise对象
//return '尚硅谷';
// 2、return 返回一个成功的promise对象
// return;
// 3、抛出错误, 返回的结果是一个失败的 Promise
// throw new Error('出错啦!');
// 4、返回的结果如果是一个 Promise 对象
return new Promise((resolve, reject) => {
resolve('成功的数据'); //成功的promise对象
//reject("失败的错误");
});
}
const result = fn();
console.log(result);
//调用 then 方法
result.then(value => { //成功时
console.log(value);
}, reason => { //失败时
console.warn(reason);
})
2、await表达式
特点:
1、await 必须写在 async 函数中
2、 await 右侧的表达式一般为 promise 对象
3、 await 返回的是 promise 成功的值
4、 await 的 promise 失败了, 就会抛出异常, 需要通过 try…catch 捕获处理
语法:
//创建 promise 对象
const p = new Promise((resolve, reject) => {
// resolve("用户数据");
reject("失败啦!");
})
// await 要放在 async 函数中.
async function main() {
try {
let result = await p;
//await表达式只返回成功的Promise对象 失败会抛出异常
console.log(result);
} catch (e) {
console.log(e);
}
}
//调用函数
main(); //失败啦!
async和await结合案例
1、结合读取文件
//1. 引入nodejs fs 模块
const fs = require("fs");
//读取『为学』
function readWeiXue() {
return new Promise((resolve, reject) => {
//读取 为学.md
fs.readFile("./resources/为学.md", (err, data) => {
//如果失败
if (err) reject(err);
//如果成功
resolve(data);
})
})
}
//读取『插秧诗』
function readChaYangShi() {
return new Promise((resolve, reject) => {
fs.readFile("./resources/插秧诗.md", (err, data) => {
//如果失败
if (err) reject(err);
//如果成功
resolve(data);
})
})
}
//读取『 观书有感』
function readGuanShu() {
return new Promise((resolve, reject) => {
fs.readFile("./resources/观书有感.md", (err, data) => {
//如果失败
if (err) reject(err);
//如果成功
resolve(data);
})
})
}
//2、声明一个 async 函数
async function main(){
//获取为学内容 promise对象
let weixue = await readWeiXue();
//获取插秧诗内容
let chayang = await readChaYangShi();
//获取观书有感
let guanshu = await readGuanShu();
console.log(weixue.toString());
console.log(chayang.toString());
console.log(guanshu.toString());
}
main();
//运行指令 》 node 文件名.js
2、结合发送Ajax请求
// 发送 AJAX 请求, 返回的结果是 Promise 对象
function sendAJAX(url) {
return new Promise((resolve, reject) => {
//1. 创建对象
const x = new XMLHttpRequest();
//2. 初始化
x.open('GET', url);
//3. 发送
x.send();
//4. 事件绑定
x.onreadystatechange = function () {
if (x.readyState === 4) {
if (x.status >= 200 && x.status < 300) {
//成功啦
resolve(x.response);
}else{
//如果失败
reject(x.status);
}
}
}
})
}
//promise then 方法测试
// sendAJAX("https://api.apiopen.top/getJoke").then(value=>{
// console.log(value);
// }, reason=>{})
// async 与 await 测试 axios
async function main(){
//发送 AJAX 请求
let result = await sendAJAX("https://api.apiopen.top/getJoke");
//再次测试
let tianqi = await sendAJAX('https://www.tianqiapi.com/api/?version=v1&city=%E5%8C%97%E4%BA%AC&appid=23941491&appsecret=TXoD5e8P')
console.log(tianqi);
}
main();
3、对象方法的拓展
- Object.values()方法返回一个给定对象的所有可枚举属性值的数组
- Object.entries()方法返回一个给定对象自身可遍历属性 [key,value] 的数组
- Object.getOwnPropertyDescriptors()该方法返回指定对象所有自身属性的描述对象
//声明对象
const school = {
name: "尚硅谷",
cities: ['北京', '上海', '深圳'],
xueke: ['前端', 'Java', '大数据', '运维']
};
//1、获取对象所有的键
// console.log(Object.keys(school));
//获取对象所有的值
// console.log(Object.values(school));
//2、获取元素键值 entries
// console.log(Object.entries(school));
//创建 Map
// const m = new Map(Object.entries(school));
// console.log(m.get('cities'));
//3、对象属性的描述对象
// console.log(Object.getOwnPropertyDescriptors(school));
// const obj = Object.create(null, {
// name: {
// //设置值
// value: '尚硅谷',
// //属性特性
// writable: true,//是否可写
// configurable: true, //是否可配置
// enumerable: true//是否可以枚举
// }
// });
js对象属性描述对象参考:
属性描述对象 – JavaScript 标准参考教程(alpha) (ruanyifeng.com)
四、ES9
1、对象的拓展运算符
/**
Rest 参数与 spread 扩展运算符在 ES6 中已经引入,不过 ES6 中只针对于数组,
在 ES9 中为对象提供了
像数组一样的 rest 参数和扩展运算符
*/
//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: '天音波',
f: '闪现'
}
const skillTwo = {
w: '金钟罩'
}
const skillThree = {
e: '天雷破'
}
const skillFour = {
r: '猛龙摆尾'
}
const mangseng = {
...skillOne,
...skillTwo,
...skillThree,
...skillFour
};
console.log(mangseng)
2、正则拓展:命名捕获分组
//声明一个字符串
// let str = '<a href="http://www.atguigu.com">尚硅谷</a>';
// //提取 url 与 『标签文本』
// const reg = /<a href="(.*)">(.*)<\/a>/;
// //执行
// const result = reg.exec(str);
// console.log(result);
// // console.log(result[1]);
// // console.log(result[2]);
let str = '<a href="http://www.atguigu.com">尚硅谷</a>';
//分组命名 语法: ?<命名>
const reg = /<a href="(?<url>.*)">(?<text>.*)<\/a>/;
const result = reg.exec(str);
console.log(result.groups.url);
console.log(result.groups.text);
3、正则拓展2:反向断言
//声明字符串
let str = 'JS5211314你知道么555啦啦啦';
//正向断言
const reg = /\d+(?=啦)/;
const result = reg.exec(str);
//反向断言
const reg = /(?<=么)\d+/;
const result = reg.exec(str);
console.log(result);
3、正则拓展:dotAll模式
//dot . 元字符 除换行符以外的任意单个字符
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);
let result;
let data = [];
while(result = reg.exec(str)){
data.push({title: result[1], time: result[2]});
}
//输出结果
console.log(data);