let 声明变量
- 变量不能重复声明
- 块级作用域
for循环中用let定义i
const定义常量
-
必须要赋初始值
-
首字母一般大写
-
常量值不能修改
-
块级作用域
-
对于数组和对象的元素修改,不算做对常量的修改,不会报错
const Team = ['1','2','3'] Team.push('4') // 不报错 Team = 100 //报错
解构赋值
-
数组的解构
const arr = ['one','two','three'] let [1,2,3] = arr console.log(1) //one console.log(2) //two console.log(3) //three -
对象的解构
const john = { name: '1', age : '2', sayHello: function(){ console.log('hello') } } let { n, a, s} = john console.log(n) console.log(a) console.log(s) s() //hello //如果单用 必须同名 let {sayHello} = john sayHello()
模版字符串
-
声明
let str = `模版字符串` console.log(str,typeof str) //string -
内容中可以直接出现换行符
let str = `<ul> <li>1</li> <li>2</li> </ul>` -
变量拼接
let lovest = '魏翔' let out = `${lovest}是我心中最搞笑的演员` console.lg(out)
对象的简写
let name = 'ma'
let sayHello = function(){
console.log('hello')
}
const jony = {
name,
sayhello,
improve(){
console.log('hello hello')
}
}
//等效于
const jony = {
name: name,
sayhello: sayhello,
improve(){
console.log('hello hello')
}
}
箭头函数
-
声明
let fn = function(a,b){ return a+b } fn(1,2) //简化 let fn = (a,b) =>{ return a+b } fn(1,2) -
箭头函数中
this是静态的,this始终指向函数声明时所在作用域下的this的值function getName(){ console.log(this.name) } let getName2 =()=>{ console.log(this.name) } let name = '小翔' const matx = { name: 'xiaoxiang' } //直接调用 getName() //小翔 getName2() //小翔 //call方法调用 getName.call(matx)//this指向matx xiaoxiang getName2.call(matx)//this不会指向matx 小翔 -
不能作为构造实例化对象
let Person = (name,age)=>{ this.name = name this.age = age } let me = new Person('mtx',20) //错误使用 console.log(me)//报错 -
不能使用 agruments 变量
let fn =()=>{ console.log(arguments) } fn(1,2,3) //arguments is not defined -
箭头函数的简写
-
省略小括号 当形参有且只有一个的时候
let add = n =>{ return n + n } console.log(add(9)) -
省略花括号{ } 当代码体只有一条语句时 return关键字必须省略 语句执行结果就是函数返回值
let pow = (n) =>n*n console.log(pow(8))
-
-
运用
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>箭头函数实践</title> <style> div { width: 200px; height: 200px; background: #58a; } </style> </head> <body> <div id="ad"></div> <script> //需求-1 点击 div 2s 后颜色变成『粉色』 //获取元素 let ad = document.getElementById('ad'); //绑定事件 ad.addEventListener("click", function(){ //保存 this 的值 // let _this = this; //定时器 setTimeout(() => { //修改背景颜色 this // console.log(this); // _this.style.background = 'pink'; this.style.background = 'pink'; }, 2000); }); //需求-2 从数组中返回偶数的元素 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); console.log(result); </script> </body> </html>总结:
- 箭头函数适合与 this 无关的回调. 定时器, 数组的方法回调
- 箭头函数不适合与 this 有关的回调. 事件回调, 对象的方法
函数参数的默认值设置
- 形参初始值 具有默认值的参数,一般位置要靠后(潜规则)
function add(a,b,c=10){
return a + b + c
}
console.log(add(1,2))
-
与解构赋值结合
function connect(option){ let host = options.host let username = options.username let password = options.password } //这种方式繁琐 connect({ host: 'localhost', username: 'root', password: 'root', }) //利用解构赋值操作 还可以赋初始值 function connect({host,username,password,port='3006'})
rest操作符...
用于获取函数的实参,用来代替 arguments
//ES5获取实参
function date(){
console.log(arguments)
}
date('2022','02','04')//返回arguments数组 arguments[0]='2022'
//rest 参数
function date(...args){
console.log(args)//返回一个数组 可以使用一些方法 filter some every map
}
date('2022','02','04')
//rest 参数必须要放到参数最后
function fn(a,b,...args){
console.log(a)
console.log(b)
console.log(args)
}
fn(1,2,3,4,5,6) //a=1 b=2 args=[3,4,5,6]
扩展(spread)运算符...
能将[数组]转换为逗号分隔的[参数序列]
const arr=[1,2,3]
function nums(){
console.log(arguments)
}
nums(...arr)
区分rest操作符和扩展运算符
//当被用于迭代器中时,它是一个扩展操作符:
function foo(x,y,z) {
console.log(x,y,z);
}
let arr = [1,2,3];
foo(...arr); // 1 2 3
//当被用于函数传参时,是一个rest操作符
function foo(...args) {
console.log(args);
}
foo( 1, 2, 3, 4, 5); // [1, 2, 3, 4, 5]
运用:
//1. 数组的合并
const kuaizi = ['王太利','肖央'];
const fenghuang = ['曾毅','玲花'];
// const zuixuanxiaopingguo = kuaizi.concat(fenghuang);
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');
const divArr = [...divs];
console.log(divArr);// arguments
数据类型 Symbol 表示独一无二的值
-
特点
- Symbol的值是唯一的,用来解决命名冲突的问题
- Symbol的值不能与其他数据进行运算
- Symbol定义的对象属性不能使用
for...in循环遍历,但是可以使用Reflect.ownKeys来获取对象的所有键名
-
基础
//创建Symbol let s = Symbol(); // console.log(s, typeof s); //symbol let s2 = Symbol('尚硅谷'); let s3 = Symbol('尚硅谷'); console.log(s2 === s3) //false //Symbol.for 创建 Symbol()函数 Symbol.for对象 let s4 = Symbol.for('尚硅谷'); let s5 = Symbol.for('尚硅谷'); console.log(s4 === s5) //true //不能与其他数据进行运算 let result = s + 100; //错误 let result = s > 100; //错误 let result = s + s; //错误 // USONB 七种数据类型 u undefine //未定义 s string Symbol //字符串 Symbol o object //对象 n null number b boolean -
使用
let game = { name:'俄罗斯方块', up: function(){}, down: function(){} }; //现在需要向game对象中添加方法 up和down 但是不确定game对象是否已经有了up 和down属性名 //先声明对象 let methods = { up: Symbol(), down: Symbol() } //向game对象添加 up 和 down 方法 game[methods.up] = function(){ console.log('up') } game[methods.down] = function(){ console.log('down') } console.log(game) //有两个symbol类型的方法 //或者: let youxi = { name:"狼人杀", say: function(){ console.log('say') }, [Symbol('say')]: function(){ console.log("我可以发言") }, zibao: function(){ console.log('zibao') }, [Symbol('zibao')]: function(){ console.log('我可以自爆'); } } console.log(youxi) -
Symbol内置属性
//1 Symbol.hasInstance 当其他对象使用instanceof运算符,判断是否为该对象的实例时,会调用这个方法 class Person{ static [Symbol.hasInstance](param){ console.log(param); console.log("我被用来检测类型了"); return false; //设置为true则返回true 可以自己设置 } } let o = {name:'o'}; console.log(o instanceof Person); //{name: 'o'} 我被用来检测类型了 false //2 Symbol.isConcatSpreadable //对象的Symbol.isConcatSpreadable属性等于的是一个布尔值,表示该对象用于 Array.prototype.concat()时,是否可以展开。 const arr = [1,2,3]; const arr2 = [4,5,6]; console.log(arr.concat(arr2)); //[1,2,3,4,5,6] arr2[Symbol.isConcatSpreadable] = false; console.log(arr.concat(arr2)); //[1,2,3,[4,5,6]]
迭代器
Iterator是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署Iterator接口,就可以完成遍历操作
-
ES6创造了一种新的遍历命令 for...of循环, Iterator接口主要供 for...of消费
-
原生具备 iterator接口的数据 (可用 for of遍历 )
- Array
- Arguments
- Set
- Map
- String
- TypedArray
- NodeList
const arr = ['1','2','3'] //for...of 遍历 for(let k of arr){ console.log(k) } let iterator = xiyou[Symbol.iterator]() //调用对象的next方法 console.log(iterator.next())// 1 console.log(iterator.next())// 2 console.log(iterator.next())// 3 console.log(iterator.next())// undefined -
自定义遍历数据
//声明一个对象 const banji = { name: "终极一班", stus: [ 'xiaoming', 'xiaoning', 'xiaotian', 'knight' ], //定义 iterator接口 否则无法使用 for...of 遍历 [Symbol.iterator]() { //索引变量 let index = 0; //把当前this对象保存到_this 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}; } } }; } } //遍历这个对象的stus属性 for (let v of banji) { console.log(v); }
生成器函数 异步编程
之前学过的 node中的fs ajax 都是纯回调函数方式
//参考JS高级笔记 Generator生成器
function* foo(x) {
var y = 2 * (yield (x + 1));
var z = yield (y / 3);
return (x + y + z);
}
var a = foo(5);
a.next() // Object{value:6, done:false}
a.next() // Object{value:NaN, done:false}
a.next() // Object{value:NaN, done:true}
var b = foo(5);
b.next() // { value:6, done:false }
b.next(12) // { value:8, done:false }
b.next(13) // { value:42, done:true }
回调地狱:
解决办法:
// 1s 后控制台输出 111 2s后输出 222 3s后输出 333
function one(){
setTimeout(()=>{
console.log(111);
iterator.next();
},1000)
}
function two(){
setTimeout(()=>{
console.log(222);
iterator.next();
},2000)
}
function three(){
setTimeout(()=>{
console.log(333);
iterator.next();
},3000)
}
function * gen(){
yield one();
yield two();
yield three();
}
//调用生成器函数
let iterator = gen();
iterator.next();
实例:
//模拟获取 先获取用户数据 再获取用户对应订单数据 再获取对应商品数据
function getUsers(){
setTimeout(()=>{
let data = '用户数据';
//调用 next 方法, 并且将数据传入
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)//用户数据 next传入data='用户数据'
let orders = yield getOrders();
console.log(orders)//订单数据 next传入data=...
let goods = yield getGoods();
console.log(goods) //商品数据 next传入data=...
}
//调用生成器函数
let iterator = gen();
iterator.next();//只需要调用一次next()函数就可以把三个函数依次执行 因为三个函数内部又执行next()
Promise
Promise是 ES6引入的异步编程的新解决方案 。语法上 Promise是一个构造函数, 用来封装异步操作并可以获取其成功或失败的结果。
-
resolve() 中可以放置一个参数用于向下一个 then 传递一个值,then 中的函数也可以返回一个值传递给 then。但是,如果 then 中返回的是一个 Promise 对象,那么下一个 then 将相当于对这个返回的 Promise 进行操作,这一点从刚才的计时器的例子中可以看出来。
-
reject() 参数中一般会传递一个异常给之后的 catch 函数用于处理异常。
-
但是请注意以下两点:
-
resolve 和 reject 的作用域只有起始函数,不包括 then 以及其他序列;
-
resolve 和 reject 并不能够使起始函数停止运行,别忘了 return。
-
-
Promise 类有 .then() .catch() 和 .finally() 三个方法,这三个方法的参数都是一个函数,.then() 可以将参数中的函数添加到当前 Promise 的正常执行序列,.catch() 则是设定 Promise 的异常处理序列,.finally() 是在 Promise 执行的最后一定会执行的序列。 .then() 传入的函数会按顺序依次执行,有任何异常都会直接跳到 catch 序列
-
基础
//实例化 Promise 对象 const p = new Promise(function(resolve,reject){ setTimeout(function(){ let data = '数据库中的用户数据' //成功 执行reslove 返回data p状态为成功 resolve(data) //失败 执行reject 返回err p状态为失败 //let err = '数据读取失败' //reject(err) },1000) }) //调用 promise 对象的 then 方法 resolve()中可以放置一个参数用于向下一个then 传递一个值 p.then(function(value){ //成功调用 console.log(value) //数据库中的用户数据 },function(reason){ //失败调用 console.log(reason) //数据读取失败 }) -
封装读取文件
//1. 引入 fs 模块 const fs = require('fs'); //2. 调用方法读取文件 // fs.readFile('./resources/为学.md', (err, data)=>{ // //如果失败, 则抛出错误 // if(err) throw err; // //如果没有出错, 则输出内容 // console.log(data.toString()); // }); //3. 使用 Promise 封装 const p = new Promise(function(resolve, reject){ fs.readFile("./demo.txt", (err, data)=>{ //判断如果失败 if(err) reject(err); //如果成功 resolve(data); }); }); p.then(function(value){ console.log(value.toString()); }, function(reason){ console.log("读取失败!!"); }); -
封装AJax请求
<script> // 接口地址: https://api.apiopen.top/getJoke const p = new Promise((resolve, reject) => { //1. 创建对象 const xhr = new XMLHttpRequest(); //2. 初始化 xhr.open("GET", "https://api.apiopen.top/getJ"); //3. 发送 xhr.send(); //4. 绑定事件, 处理响应结果 xhr.onreadystatechange = function () { //判断 if (xhr.readyState === 4) { //判断响应状态码 200-299 if (xhr.status >= 200 && xhr.status < 300) { //表示成功 resolve(xhr.response); } else { //如果失败 reject(xhr.status); } } } }) //指定回调 p.then(function(value){ console.log(value); }, function(reason){ console.error(reason); }); </script> -
then方法
//创建 promise 对象 const p = new Promise((resolve, reject)=>{ setTimeout(()=>{ resolve('用户数据'); reject('出错啦'); }, 1000) }); //调用 then 方法 then方法的返回结果是Promise对象, 对象状态由回调函数的执行结果决定 //如果回调函数中返回的结果是非promise类型的属性, 状态为成功, 返回值为对象的成功的值 const result = p.then(value => { console.log(value); //1. 非 promise 类型的属性 失败 return 'iloveyou'; //2. 是 promise 对象 成功 return new Promise((resolve, reject)=>{ resolve('ok'); //也可以设置 reject('error'); 那么设置为失败状态 // }); //3. 抛出错误 失败 // throw new Error('出错啦!'); throw '出错啦!'; }, reason=>{ console.warn(reason); }); //链式调用 p.then(value=>{ //成功回调 },reason=>{ //失败回调 }).then(value=>{ //成功回调 },reason=>{ //失败回调 }) console.log(result) //只保留一个调用 p.then(value=>{ //成功调用 }).then(value=>{ //成功调用 }) -
实践 读取多个文件
//引入 fs 模块 const fs = require("fs"); // fs.readFile('./resources/为学.md', (err, data1)=>{ // fs.readFile('./resources/插秧诗.md', (err, data2)=>{ // fs.readFile('./resources/观书有感.md', (err, data3)=>{ // let result = data1 + '\r\n' +data2 +'\r\n'+ data3; // console.log(result); // }); // }); // }); //使用 promise 实现 const p = new Promise((resolve, reject) => { fs.readFile("./resources/为学.md", (err, data) => { resolve(data); }); }); p.then(value => { return new Promise((resolve, reject) => { fs.readFile("./resources/插秧诗.md", (err, data) => { resolve([value, data]); }); }); }).then(value => { return new Promise((resolve, reject) => { fs.readFile("./resources/观书有感.md", (err, data) => { //压入 value.push(data); resolve(value); }); }) }).then(value => { console.log(value.join('\r\n')); }); -
catch 用来指定promise失败的回调
catch和then的区别: 如果在then的第一个函数里抛出了异常,后面的catch能捕获到,而then的第二个函数捕获不到。
const p = new Promise((resolve, reject)=>{ setTimeout(()=>{ //设置 p 对象的状态为失败, 并设置失败的值 reject("出错啦!"); }, 1000) }); //第一种方式 // p.then(function(value){}, function(reason){ // console.error(reason); // }); //catch 方式 p.catch(function(reason){ console.warn(reason); });
Set
ES6 提供了新的数据结构 Set(集合 )。它类似于数组,但成员的值都是唯 一的 ,集合实现了 iterator接口,所以可以使用『扩展运算符』和『 for…of…』进 行遍历。
//声明
let s = new Set()
console.log(s,typeof s)//Set(0) object
let s2 = new Set(['大事儿','小事儿','好事儿','坏事儿','小事儿']);
//元素个数
// console.log(s2.size);
//添加新的元素
// s2.add('喜事儿');
//删除元素
// s2.delete('坏事儿');
//检测
// console.log(s2.has('糟心事'));
//清空
// s2.clear();
// console.log(s2);
for(let v of s2){
console.log(v);
}
实践:
let arr = [1,2,3,4,5,4,3,2,1];
//1. 数组去重
let result = [...new Set(arr)];
console.log(result);
//2. 交集
let arr2 = [4,5,6,5,6];
///[...new Set(arr)] 把集合转换为数组形式
let result = [...new Set(arr)].filter(item => {
let s2 = new Set(arr2);// 4 5 6
if(s2.has(item)){
return true;
}else{
return false;
}
});
let result = [...new Set(arr)].filter(item => new Set(arr2).has(item));
console.log(result);
//3. 并集
let union = [...new Set([...arr, ...arr2])];
console.log(union);
//4. 差集
let diff = [...new Set(arr)].filter(item => !(new Set(arr2).has(item)));
console.log(diff);
重点:[...new Set(arr)] 把集合转换为数组形式
Map
ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合。 但是“键” 的范围不限于字符串,各种类型的值(包括对象)都可以当作键。 Map也实现了 iterator接口,所以可以使用『扩展运算符』和『 for…of…』进行遍历
//声明 Map
let m = new Map();
//添加元素
m.set('name','尚硅谷');
m.set('change', function(){
console.log("我们可以改变你!!");
});
let key = {
school : 'ATGUIGU'
};
m.set(key, ['北京','上海','深圳']);
//size
console.log(m.size);
//删除
m.delete('name');
//获取
console.log(m.get('change'));
console.log(m.get(key));
//清空
m.clear();
//遍历
for(let v of m){
console.log(v);
}
// console.log(m);
class介绍与初体验
//手机
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
class Shouji{
//构造方法 名字不能修改
constructor(brand, price){
this.brand = brand;
this.price = price;
}
//方法必须使用该语法, 不能使用 ES5 的对象完整形式
//方法名(){}
call(){
console.log("我可以打电话!!");
}
}
let onePlus = new Shouji("1+", 1999);
console.log(onePlus);
静态成员
function Phone(){ }
Phone.name = '手机';
Phone.change = function(){
console.log("我可以改变世界");
}
Phone.prototype.size = '5.5inch';
let nokia = new Phone();
console.log(nokia.name);//undefined
// nokia.change() //change is not a function 不互通
console.log(nokia.size); //5.5inch
class Phone{
//静态属性
static name = '手机';
static change(){
console.log("我可以改变世界");
}
}
let nokia = new Phone();
console.log(nokia.name);//手机
console.log(Phone.name);//我可以改变世界
ES5构造函数继承
//手机
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.playGame = function(){
console.log("我可以玩游戏");
}
const chuizi = new SmartPhone('锤子',2499,'黑色','5.5inch');
console.log(chuizi);
类继承
class Phone{
//构造方法
constructor(brand, price){
this.brand = brand;
this.price = price;
}
//父类的成员属性
call(){
console.log("我可以打电话!!");
}
}
class SmartPhone extends Phone {
//构造方法
constructor(brand, price, color, size){
//父类的constructor方法
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();
getter和setter的设置
// get 和 set
class Phone{
get price(){
console.log("价格属性被读取了");
return '111';
}
//set 必须要有一个参数
set price(newVal){
console.log('价格属性被修改了');
}
}
//实例化对象
let s = new Phone();
console.log(s.price);//价格属性被读取了
s.price = 'free';//价格属性被修改了
数值拓展
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);
console.log(equal(0.1 + 0.2, 0.3))
1. 二进制和八进制
let b = 0b1010;//二进制 0b
let o = 0o777;//八进制 0o
let d = 100;//十进制 100
let x = 0xff;//十六进制 0x
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
3. Number.isNaN 检测一个数值是否为 NaN
console.log(Number.isNaN(123));
4. Number.parseInt Number.parseFloat字符串转整数
console.log(Number.parseInt('521314love'));//521314
console.log(Number.parseFloat('3.14神奇'));//3.14
5. Number.isInteger 判断一个数是否为整数
console.log(Number.isInteger(5));
console.log(Number.isInteger(2.5));
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
对象方法拓展
1. Object.is 判断两个值是否完全相等
console.log(Object.is(120, 120));// ===
console.log(Object.is(NaN, NaN));// ===
console.log(NaN === NaN);// ===
2. Object.assign 对象的合并
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',
test2: 'test2'
}
//Object.assign(被覆盖对象,覆盖对象)
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)//变为原型对象
模块化
-
优势:
- 防止命名冲突
- 代码复用
- 高维护性
-
ES6模块化语法
-
export命令用于规定模块的对外接口
-
分别暴露
export let m1 = 1 export let m2 = 2 -
统一暴露
export { m1: 1, m2: 2 nums: function(){ console.log('3') } } -
默认暴露
export default{ school: 'ATGUIGU' change: function(){ consloe.log('hello') } }
-
-
import命令用于输入其他模块提供的功能
-
通用方式导入
import * as m1 from './m1.js' //所有的数据都导入 -
解构赋值形式
(export name)import {school,teach}from './m2.js' //对于默认暴露 import {default as m3}from './m3.js' -
简介形式 只针对默认暴露
(export default)import m3 from './m3.js'
-
-
babel对ES6模块化代码转换
1. 安装工具 npm i babel-cli babel-preset-env browserify(webpack) -D
2. 编译 npx babel src/js -d dist/js --presets=babel-preset-env
3. 打包 npx browserify dist/js/app.js -o dist/bundle.js
ES7新特性
// includes 返回布尔值 indexOf 返回下标(索引)
const mingzhu = ['西游记','红楼梦','三国演义','水浒传'];
//判断
console.log(mingzhu.includes('西游记'));//true
console.log(mingzhu.includes('金瓶梅'));/
// **
console.log(2 ** 10);
console.log(Math.pow(2, 10));
ES8 async与await
async和await两种语法结合可以让异步代码像同步代码一样
-
async
- async 函数返回值为 promise 对象
- promise 对象的结果由 async 函数执行的返回值决定
- 如果在函数中 return 一个直接量,async 会把这个直接量通过 Promise.resolve() 封装成 Promise 对象。
//async 函数 async function fn(){ // 返回一个字符串 // return '尚硅谷'; // 1 返回的结果不是一个 Promise 类型的对象, 返回的结果就是成功 Promise 对象 // return; 也是成功的 Promise 对象 //2 抛出错误, 返回的结果是一个失败的 Promise // throw new Error('出错啦!'); //3 返回的结果如果是一个 Promise 对象 return new Promise((resolve, reject)=>{ resolve('成功的数据'); //reject("失败的错误");也可以设置为失败 }); } const result = fn(); //调用 then 方法 result.then(value => { console.log(value);//成功的数据 }, reason => { console.warn(reason);//失败的数据 }) -
await
- await 必须写在 async 函数中,但 async 函数可以没有 await
- await 右侧表达式一般为 promise 对象,若是一个值则返回该值
async函数必须等到内部所有的await命令的Promise对象执行完,才会发生状态改变。- await 表达式会暂停当前 async function 的执行,阻塞下边的代码,等待 Promise 处理完成。若 Promise 正常处理(fulfilled),其回调的resolve函数参数作为 await 表达式的值,继续执行 async function。
- 若 Promise 处理异常(rejected),await 表达式会把 Promise 的异常原因抛出,而不是返回,需要用try catch捕获。
- 即await 返回的是promise 成功的值,若是promise失败,await就会抛出该异常,需要通过
try catch捕获 - await相当于Promise的then并且同一作用域下await下面的内容全部作为then中回调的内容
//创建 promise 对象 const p = new Promise((resolve, reject) => { // resolve("用户数据"); reject("失败啦!"); }) // await 要放在 async 函数中. async function main() { try { let result = await p; console.log(result);//若p被设置成功 输出:用户数据 } catch (e) { console.log(e);//若p被设置失败 输出:失败啦 } } //调用函数 main(); -
多个await之间的执行顺序
- await运算符后面不是一个promise对象而是一个值,那await表达式的运算结果就是该值
- await会先执行await后面的表达式,等到的是一个promise对象,然后阻塞后面的代码,执行同步任务,等着promise对象resolve,然后得到resolve的值,作为await表达式的运算结果
function test1() { console.log(111); } function test2() { console.log(222); } async function test3() { await test1(); await test2(); } test3(); //输出结果111 222function test1() { setTimeout( ()=> { console.log(111); }, 1000); } function test2() { console.log(222); } async function test3() { await test1(); await test2(); } test3(); //输出结果222 111function test1() { return new Promise(resolve => { setTimeout(() => { console.log(111); resolve(); }, 2000) }) } function test2(res) { setTimeout(() => { console.log(222); }, 1000); } async function test3() { await test1(); await test2(); } test3(); //输出结果: 111 222执行test3(),执行test1(),遇到promise,阻塞代码,此时test2()不执行,运行test1(),等待2s,输出111,运行resolve(),执行test2(),等待1s,输出222。
-
测试
function testSometing() { console.log("testSomething"); return "return testSomething"; } async function testAsync() { console.log("testAsync"); return Promise.resolve("hello async"); } async function test() { console.log("test start..."); const testFn1 = await testSometing(); console.log('testFn1 '+testFn1); const testFn2 = await testAsync(); console.log('testFn2 '+testFn2); console.log('test end...'); } test(); var promiseFn = new Promise((resolve)=> { console.log("promise START..."); resolve("promise RESOLVE"); }); promiseFn.then((val)=> console.log('val '+val)); console.log("===END===")- test()打印出
”test start...“。 await testSomething(),根据”await后面对应的的函数会先执行一遍,然后就会跳出整个async函数来执行后面js栈的代码“,会先执行testSometing()这个函数,打印出“testSometing”的字符串。- 然后跳出async,执行
promiseFn打印出“promise START...”,返回的Promiseresolve("promise RESOLVE")放入Promise队列 。 - 继续执行主线程栈中的
console.log("===END==="),打印“===END===” - 根据”等本轮事件循环执行完了之后又会跳回到async函数中等待await后面表达式的返回值,如果返回值为非promise则继续执行async函数后面的代码,否则将返回的promise放入Promise队列“,跳回async函数,因为
testSometing()不是async函数,返回值为非promise,打印"return testSomething" - test()函数继续执行,执行到
testFn2(),执行testAsync(),打印"testAsync" - 然后跳出async,因为主线程没有任务,所以进入Promise队列,执行
promiseFn.then((val)=> console.log(val));打印出“promise RESOLVE” - 跳回到test()继续执行
console.log(testFn2)的返回值,打印出“hello async” - 最后打印
“test end...”
- test()打印出
-
async和await结合读取文件//1. 引入 fs 模块 const fs = require("fs"); //读取『为学』 function readWeiXue() { return new Promise((resolve, reject) => { 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); }) }) } //声明一个 async 函数 async function main(){ //获取为学内容 await 返回的是 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(); -
async和await封装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"); //再次测试 发送第二个AJAX请求 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();
ES8对象扩展方法
//声明对象
const school = {
name:"尚硅谷",
cities:['北京','上海','深圳'],
xueke: ['前端','Java','大数据','运维']
};
//获取对象所有的键名
console.log(Object.keys(school));
//获取对象所有的值
console.log(Object.values(school));
//entries 返回一个二维数组 每个成员是一个数组 该数组第一个元素是键 第二个元素是值
console.log(Object.entries(school));
//可以用来创建 Map
const m = new Map(Object.entries(school));
console.log(m.get('cities'));
//对象属性的描述对象
//原型对象
console.log(Object.getOwnPropertyDescriptors(school));
//描述对象
const obj = Object.create(null, {
name: {
//设置值
value: '尚硅谷',
//属性特性
writable: true,
configurable: true,
enumerable: true
}
});
ES9扩展运算符与rest参数
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: '天音波'
}
const skillTwo = {
w: '金钟罩'
}
const skillThree = {
e: '天雷破'
}
const skillFour = {
r: '猛龙摆尾'
}
const mangseng = {...skillOne, ...skillTwo, ...skillThree, ...skillFour};
console.log(mangseng)
ES9正则扩展
-
命名捕获分组
//声明一个字符串 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>/; //分组命名为url text const result = reg.exec(str); console.log(result.groups.url); console.log(result.groups.text); -
反向断言
//声明字符串 let str = 'JS5211314你知道么555啦啦啦'; //正向断言 根据后面内容判断前面的内容是否合法 const reg = /\d+(?=啦)/;//\d查找数字 n+ 匹配任何包含至少一个n的字符串 const result = reg.exec(str);//555 //反向断言 根据前面的内容判断后面的内容是否合法 const reg = /(?<=么)\d+/; const result = reg.exec(str); console.log(result); -
dotAll模式
dotAll属性表明是否在正则表达式中一起使用"s"修饰符(引入/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>/; \s查找空白字符 //利用dotAll模式 /s .就可以匹配任意字符 const reg = /<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/gs; /g全局匹配 //执行匹配 // 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);
ES10
- 对象扩展方法
Object.fromEntries将二维数组转换为对象
//二维数组
// const result = Object.fromEntries([
// ['name','尚硅谷'],
// ['xueke', 'Java,大数据,前端,云计算']
// ]);
//Map
// const m = new Map();
// m.set('name','ATGUIGU');
// const result = Object.fromEntries(m);
//ES8 Object.entries 也可以将对象转为二维数组
const arr = Object.entries({
name: "尚硅谷"
})
console.log(arr);
2.字符串方法扩展
// ES5 trim 清除字符串两侧空白字符
let str = ' iloveyou ';
console.log(str);
console.log(str.trimStart());//清除左侧空白字符
console.log(str.trimEnd());//清除右侧空白字符
3.数组方法拓展
//flat
//将多维数组转化为低维数组
const arr = [1,2,3,4,[5,6]];
console.log(arr.flat()) //二维转一维
const arr = [1,2,3,4,[5,6,[7,8,9]]];
//参数为维度 是一个数字
console.log(arr.flat(2));//三维转二维
//flatMap
const arr = [1,2,3,4];
const result = arr.map(item => item * 10);//[10 20 30 40]
const result = arr.map(item => [item * 10]);//返回二维数组[[10],[20],[30],[40]]
const result = arr.flatMap(item => [item * 10]);//降维 [10 20 30 40]
console.log(result);
4.Symbol.prototype.description
//创建 Symbol
let s = Symbol('尚硅谷');
console.log(s.description);
ES11
-
私有属性
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, '45kg'); console.log(girl.name); console.log(girl.#age);//无法直接访问 console.log(girl.#weight); girl.intro() //可以访问 -
Promise.allSettled
//声明两个promise对象 const p1 = new Promise((resolve, reject)=>{ setTimeout(()=>{ resolve('商品数据 - 1'); },1000) }); const p2 = new Promise((resolve, reject)=>{ setTimeout(()=>{ //resolve('商品数据 - 2'); reject('出错啦!'); },1000) }); //调用 allsettled 方法 const result = Promise.allSettled([p1, p2]);//返回的PromiseStatus都是成功的 即时p2设置为reject //与 allsettled 类似 const res = Promise.all([p1, p2]); //结果由p1 p2 决定 有一个失败res状态就是失败两个都成功才会成功 console.log(res);p1 p2 都成功 res:
-
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); // for(let v of result){ // console.log(v); // } const arr = [...result]; console.log(arr); -
可选链操作符
// ?. function main(config){ //原来方式 const dbHost = config && config.db && config.db.host;判断config是否存在再判断config.db是否存在再取出host值 const dbHost = config?.db?.host; console.log(dbHost);//即使不存在也不会报错 输出undefined } main({ db: { host:'192.168.1.100', username: 'root' }, cache: { host: '192.168.1.200', username:'admin' } }) -
动态import 实现按需加载
-
BigInt 类型
//大整形 let n = 521n; console.log(n, typeof(n));//521n BigInt //函数 let n = 123; console.log(BigInt(n));//123n console.log(BigInt(1.2));//报错 不是整数 //用于大数值运算 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)) -
绝对全局对象
globalThis-
始终指向全局对象
-
浏览器下指向
window -
node.js环境下指向
global
-