一、ES6
js的异步和同步,js是单线程语言:
同步:加入主线程,按顺序执行,即上一个同步任务结束后,本任务跟着执行。
异步:加入任务队列,等待主线程上任务都执行完毕,请求主线程后才能执行。
(一)let变量
A、let作用域为块(或者for循环和if while)
{let you = "forever";}console.log(you);//报错,找不到you,因为you变量在块中。
B、命名一致冲突报错
//let命名一致冲突报错,但是var不会let he = "老大";let he = "我会等";//会报错。
C、不存在自动提升(变量声明提升)
//不存在变量自动提升,根据实际出现位置命名变量 console.log(her);//报错无法找到变量,但是若是var则是undefinded,能够找到变量。 let her = "Drling";
var的话,会把所有变量放在代码前面声明,到对应行后再赋值,所以如果是var不会报错。
D、点击变换实例
//获取元素let items = document.getElementsByClassName("item");//循环遍历for(let i = 0; i < items.length;i++){items[i].onclick = function(){items[i].style.backgroundColor = 'pink';}}console.log("完成!");
这样可以,如果把循环中let换为var,则会出错,因为var是全局作用域,会在函数向外寻找时加至items[3],所以找不到元素颜色无法变换。
(二)const变量
A、const作用域也是块,用来定义常量,常量一般大写
//常量声明const ONE = 'go';
B、声明时必须赋值,而后不可更改
//不能修改(否则报错)const TWO = 'thyShy';//const TWO = 'xiaohu';修改已定义常量,报错。因为常量指向变化
C、数组常量可以改,因为指向不变
const THREE = ["kuisang","永恩"];THREE.push("凯隐");//不会报错,指向没变console.log(THREE);
(三)解构赋值
解构赋值允许按照一定规则,从数组或者对象中提取数值,赋给变量。
A、数组解构赋值
//数组结构赋值(根据顺序)const me = ['大头儿子','小头爸爸','一休'];let[you,he,her] = me;console.log(you + he + her);
B、对象解构赋值
//声明对象const him = { name : '赵子龙', sex : '男', kill : function(){console.log('七进七出,骁勇善战'); }}//根据变量名提取,不能随便改名。let{name,sex,kill} = him;console.log(name + sex + kill);kill();//调用
(三)字符串新声明方式`
A、声明
//声明let four = `这首歌是写给黄淮。`;
B、允许换行
//可以使用换行let five = `- 天使
- 魔鬼
- 上帝
`;//若换成‘或者“则报错,不允许换行。
C、字符串拼接
//字符串拼接let six = `黄淮`;let seven = `写给${six}`;console.log(seven);
不同于之前使用+号拼接,这里使用${}。
(四)对象属性声明简化书写
如果对象的属性名要赋已经声明的变量,且变量名和属性名一致,则省写冒号和赋值;
对象中声明函数也可以简化为:函数名(){};
let myName = '托尼斯达克';let myGo = function(){console.log("fly");}const myObject = { myName,//之前,myName:myName myGo, myLove(){console.log('she love me too!'); }//之前 myLove:function(){}}//验证console.log(myObject.myName);myObject.myGo();myObject.myLove();
(五)函数声明的简化(箭头函数)
A、简化书写
const functionTest = (a,b,c) => { return a + b - c;}let num = functionTest(4,5,1);console.log(num);
B、this指向始终不变
简化函数声明中的this始终指向函数声明时所在的作用域所在的this下的值,例如在函数A中声明的函数B中的this就始终指向函数A,在对象中或者直接声明的函数始终指向window对象。
//1、this始终指向自声明后,始终如一。 window.name="我是windows";const myCloud = {name:"我是myCloud对象的云", testOne : function(){console.log(this.name);},//原来方式声明 testTwo:()=>{console.log(this.name);}//简化方式声明}myCloud.testOne();myCloud.testTwo();//用call改变this指向,后原始方式变化,简化方式不变。myCloud.testOne.call(window);myCloud.testTwo.call(window);
输出结果:
即使用call函数改变testTwo使其指向myCloud也没有用,一直是window。
myCloud.testTwo.call(myCloud);//我是windows
C、不能作为构造函数构造实例化对象
/不能构造实例化对象let youTestFun = (a,b)=>{this.a = a,this.b = b}const meTestFun = new youTestFun("我","你");//报错
我认为,还是跟this指向固定不变有关,所以在构造过程中无法动态变化赋值。
D、不能使用arguments参数
不能使用函数默认参数arguments。(注:非简化声明的函数存在arguments用来承接未声明但在实际调用中多出来的参数。)
//不能使用argumentslet youTestFunOne = ()=>{console.log(arguments);}youTestFunOne("me");//报错找不到arguments
不使用简化方式:
let youTestFunOne = function(){console.log(arguments);}youTestFunOne("me");//结果为arguments["me"]
E、箭头函数简化
当声明的函数只有一个参数或者函数中语句只用一句时,可以对箭头函数进行再简化,可以省略括号或花括号且那一条语句不需要return,默认为将结果作为返回值。
简化前:
let meTestFunh= (n) => {return n + 1;}let heMe = meTestFunh(9);console.log(heMe);
简化后:
let meTestFunh= n => n + 1;let heMe = meTestFunh(9);console.log(heMe);
F、实际应用
实践一:
//需求,点击块后,2s后变色。let chCon = document.getElementsByClassName("changeColorContain");let chCoCon = chCon[0];chCOCon.addEventListener("click",function(){ setTimeout(function(){this.style.backgroundColor= "blue";//这里this指向调用者windows,而window无style,会报错。 }, 2000);});
修改一:this传导到元素
//需求,点击块后,2s后变色。let chCon = document.getElementsByClassName("changeColorContain");let chCoCon = chCon[0];chCoCon.addEventListener("click",function(){let _this = this; setTimeout(function(){_this.style.backgroundColor= "blue"; //——this往上找找到this,而上面this指向元素chCoCon。 }, 2000);});
修改二: 通过箭头函数,指向所在所用域下this的值,即(元素chCoCon)
//需求,点击块后,2s后变色。let chCon = document.getElementsByClassName("changeColorContain");let chCoCon = chCon[0];chCoCon.addEventListener("click",function(){ setTimeout(()=>{this.style.backgroundColor= "blue"; }, 2000);});
实践二:
//从数组中筛选出2的偶数const numSub = [2,3,53,88,100,23]; const result = numSub.filter(function(item){if(item % 2 == 0){return true;}else{return false;} }) console.log(result);
改进:
//从数组中筛选出2的偶数const numSub = [2,3,53,88,100,23]; const result = numSub.filter(item=> item % 2 == 0) console.log(result);
(六)参数赋默认值
A、简单参数赋默认值
const skyFun = (a,b,c,d=10)=> a + b + c + d;//不给值,有默认值就是默认值,否则undifindedlet numSkey = skyFun(3,54,3);//70let numSky = skyFun(1,2,3,9);//15console.log(numSkey + " " + numSky);
B、对象型参数中属性赋默认值
如果函数中传入参数是对象,则要先将对象写成参数解构形式,然后赋默认值。
//和解构赋值结合使用let outBody = ({name,sex,age=18})=>{console.log("刚满" + age + "岁~");}const myLove = {name: '老爹',sex: '男',age: 20} outBody(myLove);//传入对象,age有值为20; outBody({name:"爱人",sex:"女"});//传入对象,无age,使用默认值18。
(七)rest参数
A、ES5和ES6对比
//ES5可变参数接收 let myChangeFun = function(){ console.log(arguments);}; myChangeFun("萧炎","荒天帝","美杜莎","七彩吞天蟒");//arguments以对象形式保存 //ES6可变参数接收 let myChangeFunTwo = (...args)=> {console.log(args);};myChangeFunTwo("萧炎","荒天帝","美杜莎","七彩吞天蟒");//该风格,以数组形式保存。
结果展示:
(八)扩展运算符
A、功能
可以将数组中的元素变为以逗号隔开的参数序列:
//扩展运算符let myArray = ["萧炎","荒天帝","美杜莎","七彩吞天蟒"];let showMy = function(){console.log(arguments)};//是一个参数,类型是数组。//正常传参数,数组,1个参数showMy(myArray);//用扩展运算符,变量,4个参数showMy(...myArray);
B、数组合并
//利用扩展运算符合并let myArrayThree = [...myArrayOne,...myArrayTwo];console.log(myArrayThree);
C、将伪数组变为真数组
变为数组后可以使用数组的一些方法
//伪数组let divs = document.querySelectorAll("div");//真数组let myDivs = [...divs];console.log(divs);console.log(myDivs);
D、数组的克隆
let one = ["邓紫棋"]; let two = ["hh"];two = [...one]; console.log(two);
这种克隆是浅拷贝,基本类型复制值,引用类型复制引用地址,指向同一个值,新对象(引用类型)会影响原对象。即是说,当复制的数组中还有数组,就是复制最里层数组地址。
(九)Symbol
Symbo是ES6中新出现的基本数据类型,是继前五大数据类型(字符串,null,undefinded,Object,num(数字),布尔)后出现的第六大数据类型。
因为对象中的键值在ES5中只能使用字符串,会存在key值冲突的风险,尤其是当合作过程中拿到一个陌生的对象,很容易在添加方法过程中导致key重复。故而Symbol诞生,它的特点就是唯一,即使在利用Symbol中函数生成同样字符串,也是不同键值,相等运算为false。
A、为对象添加方法的两种方式
//symbol()的使用let rabbit = {name: '小白兔',age: 18,skip(){console.log("唱跳rap");},eat(){console.log("吃的很多!");}} //作用一:防重复key命名 //方式一: let model = { skip: Symbol(), eat: Symbol() } rabbit[model.skip] = function(){console.log("新增skip方法"); } rabbit[model.eat] = function(){ console.log("新增的吃方法"); } console.log(rabbit); //方式二 let tigger = { name:"微少", age: 20, [Symbol("fly")](){console.log("轰轰轰!"); }, [Symbol("fly")](){ console.log("哈哈哈"); } } console.log(tigger);
B、Symbol的特点
- 不能和其他数据类型进行运算,包括字符串拼接。
- 在对象中声明的Symbol类型的key,在循环遍历对象过程中是透明的。
C、Symbol的内置属性
作为一种基础数据类型,在作为唯一键值称为对象中的属性,也可以在声明对象属性时调用内置属性生成对象的key值,这些key下的属性或者方法会在特定时机被调用。
- Symbol.hasInstance
当属性对应的类被作为instanceof的对象时,其对应方法会被自动调用
//Symbol内置属性 class people{static[Symbol.hasInstance](){ console.log("我是Symbol.hasInstance作为键值的方法,我被自动调用了");} } let Bob = {}; //当people被用于 instanceof 时,该方法会被自动调用 Bob instanceof people;
运行结果:
还有很多内置属性,可以搜索查看,基本都是在特定情况下,自动调用某种函数。
(十)Iterator(迭代器)
ES6引入迭代器接口,只要实现了迭代器接口的数据类型,就可以使用for…..of….循环语法。
A、默认实现迭代器的数据结构类型
Array、Arguments、Set、Map、String、TypedArray、NodeList
Array使用迭代器演示:
//iterator迭代器,默认实现迭代器的结构let red = ["红","蓝","白","紫","天下"];for(let zi of red){console.log(zi);//of 展示内容}for(let wo in red){ console.log(wo);//in 展示下标}
B、迭代器原理
- 首先创建一个指针对象指向当前数据结构的起始位置
- 执行指针对象中的next方法,指向数据结构的第一个成员;
- 不断执行next方法,不断指向下一个结构,返回数据。
- 返回数据结构类型为一个属性为value和done的对象,done为false时会一直执行next函数,知道done为true。
let red = ["红","蓝","白","紫","天下"];let myIterator = red[Symbol.iterator]();for(let i = 0; i <= red.length;i++){ console.log(myIterator.next());}
C、自定义迭代器
let contain = {name: 'shao杰',lover:["米老鼠","柯洁","tiancai","小八嘎" ],[Symbol.iterator](){let index = -1;let _this = this;return{ next(){ if(index == -1){ index++;return {value: _this.name,done: false} }else if(index<_this.lover.length - 1 && index != -1){index++;return {value:_this.lover[index],done:false} }else{return {value:_this.lover[index],done:true}; } } }}} for(let one of contain){console.log(one); }
(十二)生成器
A、一种特殊的函数(生成器)
生成器函数返回的是一个迭代器对象,通过调用next方法执行其中语句,yield语句相当于暂停标志,每次next,执行一段代码,后返回yield语句后内容
//生成器函数 function * lover(){console.log("one,我是天选也是唯一"); yield "one",console.log("冲天香阵透长安"); yield "two", console.log("i am iron man"); yield "three"}//调用生成器函数room = lover();room.next();//每次调用都会执行一个yield之前的句子,并返回yield后数据。room.next();
B、传参
- 生成器传参
//生成器函数 function * lover(param,me){console.log(param + "我爱你!" + me);yield "one",console.log("冲天香阵透长安"); yield "two", console.log("i am iron man"); yield "three"}//调用生成器函数room = lover("美女","我");room.next();//每次调用都会执行一个yield之前的句子,并返回yield后数据。
- next传参
next中传入的参数会作为上一个yield语句的返回值。
//生成器函数 function * lover(){console.log("我爱你!");let oneReturn = yield "one";// 这里返回的是上一个yield的返回值console.log("上一个yield的返回值是" + oneReturn); yield "two"; console.log("i am iron man"); yield "three"}//调用生成器函数room = lover();let reture = room.next();//每次调用都会执行一个yield之前的句子,并返回yield后数据。console.log(reture);room.next("你好老弟");room.next();
C、简化异步函数调用
原方式:(每步应该添加定时器,这里省略了)
function getOrder(){let data = "订单数据";console.log("获得了订单!");return data;}function getCust(){let dataUp = getOrder();let data = "顾客信息";console.log("获得了订单数据:" + dataUp + "顾客信息。");return data + dataUp;}function getAll(){ let dataUp = getCust();let data = "全部信息";console.log("获取了全部" + data + dataUp);return dataUp + data;}getAll();
使用生成函数:(这里每一步必须使用定时器,否则报错!)
function getOrder(){setTimeout(()=>{let data = "订单数据";zongzi.next(data);//调用下一步,并为OrderData赋值;},2000)}function getCust(){setTimeout(()=>{let data = "顾客信息";zongzi.next(data);},2000)}function getAll(){setTimeout(()=>{let data = "全部信息";zongzi.next(data);},2000)}function * myTest(){let OrderData = yield getOrder();console.log("拿到了订单数据" + OrderData);let CustData = yield getCust();let CuOrData = CustData + OrderData;console.log("拿到了订单和客户数据" + CuOrData);let allData = yield getAll();let zongInfo = allData + CuOrData;console.log("拿到所有数据" + zongInfo);}let zongzi = myTest();zongzi.next();
(十三)Promise
A、使用
//两个参数,名称随意,都是函数,第一个成功时调用,改变testOne状态为成功。//第二个失败时调用,改变testOne状态为失败。let testOne = new Promise(function(get,reject){setTimeout(()=>{//一、错误情况// console.log("一堆逻辑");// console.log("有错误出现");// error = "计算有误";// reject(error);//传入错误的原因,参数。//二、成功情况value = "太酷了";get(value);})})// then两个参数,第一个函数状态为成功执行,第二个状态为失败执行。testOne.then((value)=>{console.log("执行成功,获取到的数据为" + value);},(error)=>{console.log("错误的原因是" + error);console.log("一堆对出现错误后的处理逻辑");})
B、实例(读取文件内容到控制台)(要用到node.js)
- 不使用Promise
//读取文件到控制台const fs = require('fs');fs.readFile("./test.txt",(error,data)=>{if(error)throw error;//出错的逻辑console.log(data.toString());})
- 使用Promise
//读取文件到控制台const fs = require('fs');// fs.readFile("./test.txt",(error,data)=>{// if(error)throw error;//出错的逻辑// console.log(data.toString());// })let myPromise = new Promise(function(get,back){fs.readFile("./test.txtm",(error,data)=>{if(error){back(error);//传入原因}else{get(data);}})});myPromise.then((data)=>{console.log(data.toString());},(error)=>{console.log(error);});
(十四)Set集合
A、特点:可使用扩展运算符,不允许重复(自动去重)
//Set集合,不可重复let mySet = new Set([1,1,2,2,3,4,3,2]);//添加元素mySet.add(0);//删除元素mySet.delete(1);//返回元素个数let all = mySet.size;console.log(mySet + "总数是" + all);//判断是否存在某元素console.log(mySet.has(0));//转化数组,因继承Interator接口,所以可以使用扩展运算符和for...oflet arrayMe = [...mySet];console.log(arrayMe);//遍历for(let i of mySet){ console.log(i);}//清空SetmySet.clear();console.log(mySet);
结果:
B、集合操作
//集合操作let oneArr = [1,1,2,2,3,3,0,0,4];let twoArr = [4,4,5,5,3,6,6];//交集let oneSet = new Set([...oneArr]);//去重let twoSet = new Set([...twoArr]);let resultSet = [...oneSet].filter((item)=> twoSet.has(item));console.log(resultSet);//并集let resultSetTwo = new Set([...oneArr,...twoArr]);console.log(resultSetTwo);//差集let resultSetThree = [...oneSet].filter((item) => !twoSet.has(item));console.log(resultSetThree);
结果:
(十五)Map
Map很像对象,里面是键值对的数据结构,和对象不同,任何类型(包括对象)都可以成为Map的键值,继承了Interator接口,可以使用扩展运算符和for…of..语句。
//Maplet myMap = new Map();myMap.set("姓名","道发");myMap.set([1,2,3],"哈哈");let object = {name: "唧唧",age: 18}myMap.set(object,"我爱你!");for(let o of myMap){console.log(o);}
(十六)Class
Class是对象的一种规范和模版,简化了之前声明构造函数的过程,采用更易理解的方式声明对象的模版。
//声明构造函数function people(name,lover){this.name = name;this.lover= lover;}//添加方法people.prototype.sayLove = function(){console.log(this.lover + "我爱你!");}//创建对象,调用方法let onePeople = new people("杜若衡","天流芳");onePeople.sayLove();//现创建Classclass PP{ //构造方法,new对象时会自动调用constructor(name,lover){this.name=name;this.lover=lover; } //函数声明固定格式,不可为name:function()方式 sayLove(){console.log(this.lover + "我爱你!"); }}//创建对象,调用方法let PPOne = new PP("琉璃月","陌上桑");PPOne.sayLove();
A、静态成员
只属于类或者构造函数的属性或者函数。
//静态成员//构造函数的静态成员function wo(){}//下面的属性属于构造函数,不属于对象。wo.name = "郦道元";wo.age = 18;wo.prototype.trueName="你";let woOne = new wo();//class的静态成员class hi{ static name = "郦道元"; static age = 18; trueName = "你";constructor(){}}let hiOne = new hi();console.log(wo.age);console.log(hi.age);//对象和构造函数的原型中属性相通,和在其内部直接声明的属性。console.log(woOne.trueName);console.log(hiOne.trueName);console.log(woOne.age);//undefinedconsole.log(hiOne.age);//undefined
B、get和set
get和set后面跟属性名,当要获取该属性就会调用get函数,当要修改就会调用set函数,注意不要返回自身,不然会陷入循环调用地狱。
class People{myPrice;constructor(first,end){this.first = first;this.end = end;}get price(){this.myPrice = this.first + this.end;return this.myPrice; }set price(value){this.myPrice = value; return myPrice;}}let hei = new People(1000,800);let wo = hei.price;console.log(hei.price);会调用get
(十七)继承
A、构造函数继承
//继承function Phone(band,type){this.band = band;this.type = type;}Phone.prototype.say = function(){console.log("我是" + this.band + "牌子的" + this.type);}function SmartPhone(band,type,price,color){ Phone.call(this,band,type); this.price = price; this.color = color;}//将子构造函数原型指向父类的原型,继承父类的方法SmartPhone.prototype= Phone.prototype;//创造对象检查let SmartTrue = new SmartPhone("锤子","智能手机",1000,"红色");SmartTrue.say();console.log(SmartTrue);
B、类的继承
class Phone{constructor(band,type){this.band = band;this.type = type;}say(){console.log("我是" + this.band + "的" + this.type);} }class SmartPhone extends Phone{constructor(band,type,price,color){super(band,type);this.price = price;this.color = color;} //新增方法 speak(){console.log("我是" + this.band + "手机,我为自己代言!"); }} //声明对象并尝试let myPhone = new SmartPhone("苹果","智能手机",4900,"红色");myPhone.say();myPhone.speak();
C、重写
截取上面例子的子类展示重写
class SmartPhone extends Phone{constructor(band,type,price,color){super(band,type);this.price = price;this.color = color;} //新增方法 speak(){console.log("我是" + this.band + "手机,我为自己代言!"); } //重写方法 say(){console.log("我是重写后的方法"); }} //声明对象并尝试let myPhone = new SmartPhone("苹果","智能手机",4900,"红色");myPhone.say();myPhone.speak();
(十九)Number和Math的属性方法
//1、NumberNumber.EPSILON;//该属性是Number计算的最小误差,通过该属性改变比较结果。function equal(a,b){if(a - b < Number.EPSILON){return true;}else{return false;}}let a = 0.2;let b = 0.5;console.log(equal((a+b),0.7));//2、判断有限数,是为true,不是为falseconsole.log(Number.isFinite(100/0));//falseconsole.log(Number.isFinite(34));//trueconsole.log(Number.isFinite(Number.PI))//false//3、判断数的正负,正为1,负为-1,0为0console.log(Math.sign(3));console.log(Math.sign(-3));console.log(Math.sign(0));//4.判断是否NaNconsole.log(Number.isNaN(100/0));console.log(Number.isNaN("天"));//5.将字符串转化为数值console.log(Number.parseInt("1243544"));console.log(Number.parseFloat("1.23344"));//6.判断一个数是否为整数console.log(Number.isInteger(45));console.log(Number.isInteger(2.133));//7.将浮点数的小数部分抹去console.log(Math.trunc(2.99));//默认下舍入
(二十)对象方法扩展
A、Object.is(A,B)
判断A和B两个数是否完全相等,和===功能相似,但是对NaN之间比较的判断结果不一,is为true,===为false。
let one = Object.is(2,2);//相当于===,判断两个数是否完全相等。//例外,NaN对于===是faluse,对于is来讲是true;console.log(one);console.log(Object.is(NaN,NaN));
B、Object.assign(A,B)
令对象B中内容,根据同key覆盖进行覆盖,覆盖对象A中的属性。对于属性A中没有属性B中存在的属性,在A中增加,对于A中存在,但B中不存在的属性,保持不变。
let ObOne = {name: "小天才",age: 18,fly(){console.log("小天才飞上天了!");},mySelf: "我独苗"}let ObTwo = {name: "大猪蹄子",age: 20,fly(){console.log("大猪蹄子飞上天了");},he:"别浪"}//让后者覆盖前者 Object.assign(ObOne,ObTwo);console.log(ObOne);
C、插入原型链(一般不用)
let me = {name: "我",age: 19}let you = {name: "你",age: 20,say(){console.log("你看着我眼睛~");}}//将后者作为前者的原型对象(插入原型链)Object.setPrototypeOf(me,you);
(二十一)模块化
A、什么是模块化
ES5时我们引入js文件,每个js文件中的变量不能出现命名冲突,这样就导致很多麻烦,所以引入模块化,也适用于大型项目的合作开发。
模块化的好处有:防止命名冲突、方便代码复用、维护升级方便。
B、暴露与引用
模块之间要相互调用,就要用到暴露和引用语法,我们用一个js文件来代表一个模块。
因为要用不同文件,所以要解决跨域问题,这个问题可以用Live Server插件来解决,下载之后,在vs code右下角打开,然后在文件中右击,选择用live Server运行,那么该插件会自动扮演一个代理服务器,这样就能够解决跨域问题了。
- 暴露
export const name = "jack";export const rose ={name: "rose",age: 20,say(){console.log("i love you jack!");}}//export是分别暴露。
- 引入
//引入import *as a from "./testAgain.js";//引入后暴露属性都被加入a中,通过a来调用。console.log(a.name);console.log(a);
结果:
C、其他暴露方式
- 统一暴露
const name = "jack"; const rose ={name: "rose",age: 20,say(){console.log("i love you jack!");}}//统一暴露export{name,rose}
- 默认暴露
export default{ name : "jack",rose:{name: "rose",age: 20,say(){console.log("i love you jack!");}} }
引用方式也要发生变化,因为默认方式相当于在中间又加了个对象。
//引入后暴露属性都被加入a中,通过a来调用。console.log(a.default.name);console.log(a.default);
D、其他引入方式
- 针对默认暴露
//a 直接为default的别名import a from "./testAgain.js";//解构赋值,设置别名import {default as a} from "./testAgain.js";
- 针对统一暴露
//引入后直接,变为属性值使用,可用as设置别名import {name,rose} from "./testmoren.js";
E、主模块
当模块过多时,我们可以使用主模块使解构更加清晰,如上有testAgain.js和testmoren.js,这时再增加主模块(app.js),在主模块中使用引用语句。
- app.js
import {name,rose} from "./testmoren.js";import {default as me} from "./testAgain.js";console.log(me);console.log(name);console.log(rose);
- html文件中引入
F、新版本引入模块和包的方式
import $ from 'jquery';//原方式:let jquery = require('jquery');
二、ES7
(一)includes丰富indexOf
includes检测数组是否含有某元素返回的是布尔值。indexof返回的是1或者-1。
let array = ["红楼梦","大闹天宫","西厢记"];console.log(array.includes("金瓶梅"));console.log(array.indexOf("高老头"));
(二)** 代替Math.pow
console.log(Math.pow(2,20));console.log(2 ** 20);
三、ES8
(一)async函数
async函数是返回值是Promise对象,Promise对象中的状态根据函数返回情况不同而不同。
A、返回非Promise值,则Promise对象的状态(status)为fulfilled(成功)
函数返回值填充Promise对象的result部分。
async function me(one,two){ return "我会等";}let hi = me(); console.log(hi);
B、return是Promise对象,则返回Promise状态视情况而定
Promise的失败调用函数传参或成功调用函数传参,作为返回Promise的result。
Promise的执行结果作为返回Promise的status
async function me(one,two){let PromiseMe = new Promise((fulfilled,reject)=>{if(one == 1 && two == 2){fulfilled("执行成功"); }else {reject("执行失败!"); }}); return PromiseMe;} console.log(me(1,2)); console.log(me(1,1));
(二)await指令
await指令只能出现在async函数体中,await指令后跟返回值为Promise对象的函数,如果Promise对象status为成功,则await返回result,Promise对象status为失败,则直接抛出错误。
A、使用
function mid(one,two){let PromiseMe = new Promise((fulfilled,reject)=>{if(one == 1 && two == 2){fulfilled("执行成功"); }else {reject("执行失败!"); }} ); return PromiseMe;}async function me(one,two){try{let winRe = await mid(one,two);//成功后返回结果console.log(winRe)}catch(error){console.log(error);}} me(1,2); me(1,1);
B、实例读取文件
const fs = require('fs');function getFile(path){return new Promise((fulfilled,reject)=>{ fs.readFile(path,(err,data)=>{ if(err) reject("出错了!"); fulfilled(data.toString()); })})}async function mid(path){try{let result = await getFile(path);console.log(result);}catch(err){console.log(err);}}mid("./test.txt");
C、实例(用ajax发送请求)
function sendAJAX(){return new Promise((fulfilled,reject)=>{let ajax = new XMLHttpRequest();ajax.open("get","https://api.xygeng.cn/one");ajax.send();ajax.onreadystatechange = function(){if(ajax.readyState == 4){if(ajax.status >= 200 && ajax.status <=399){fulfilled(ajax.response);}else{reject(ajax.status);}}}})}async function sendA(){let content = await sendAJAX();console.log(content);}sendA();
(三)对象方法扩展
A、遍历对象的方法
const obj = {name: "令斛楚",age: 20,lover:["清漪","美杜莎","傻妞"],do(){console.log("fly");}}//返回对象键值构成的数组const objKeyArr = Object.keys(obj);//返回对象属性值构成的数组const objValueArr = Object.values(obj);//返回对象属性和键构成的键值对const objKVArr = Object.entries(obj); //变为Map集合const objToMap = new Map(objKVArr);console.log(objKeyArr);console.log(objValueArr);console.log(objKVArr);
B、获取对象的描述对象
描述对象中规定了更清晰的属性描述,包括value,可写(writed)、可配置(configurable)、可枚举(enumerable)。
通过Object.create()方法创建的对象,必须制定描述细节属性。
const obj = {name: "令斛楚",age: 20,lover:["清漪","美杜莎","傻妞"],do(){console.log("fly");}}let objDes = Object.getOwnPropertyDescriptors(obj);console.log(objDes);//第一个参数是要继承的对象,第二个是新创建的对象结构let obj2 = Object.create(null,{name:{value: "卞之琳",writable: true,configurable: true,Enumerable: true }})console.log(obj2);
四、ES9
(一)对象使用Rest语法和扩展运算符
A、Rest语法
function getObjProperty({name,age,...other}){//当传入对象的一些属性没被显示标出,就会被存入otherconsole.log(name);console.log(age);console.log(other);}const obj = {name: "令斛楚",age: 20,lover:["清漪","美杜莎","傻妞"],do(){console.log("fly");}}getObjProperty(obj);
B、扩展运算符
function getObjProperty({name,age,...other}){//当传入对象的一些属性没被显示标出,就会被存入otherconsole.log(name);console.log(age);console.log(other);}const obj = {name: "令斛楚",age: 20,lover:["清漪","美杜莎","傻妞"],do(){console.log("fly");}}const obj2 = {name2: "风清扬",age: 23}//将对象拆解到新的对象。 let objArr = {...obj}; console.log(objArr); //合并对象到新的对象,如果有属性名冲突,则后面覆盖前面 let objArr2 = {...obj,...obj2}; console.log(objArr2);
(二)正则表达式的命名捕获分组
A、原方式:保存在数组中
let zongUrl = '尚'; let ZZ = /(.*)/; //接收正则表达式接收到的数据,小括号是子正则 let result = ZZ.exec(zongUrl); console.log(result[0]); console.log(result[1]); console.log(result[2]); console.log(result);
B、现方式:直接键值对,预防正则变动导致结构下标变动
let zongUrl = '尚';let ZZ2 = /(?.*)/; let result2 = ZZ2.exec(zongUrl);console.log(result2.groups.url);console.log(result2.groups.content);
(三)正向断言与反向断言、dotall模式
A、正向断言
判断筛选内容后面是否满足条件:
let love = "1314521冲锋888杀呀"; //如果数字会随机变化,并且筛选后面为杀的数字。 let outSha = /\d+(?=杀)/; let end = outSha.exec(love); console.log(end);
B、反向断言
判断筛选内容前面是否满足条件:
let love = "1314521冲锋888杀呀";let forContent = /(" />let text = ` 天下无双 2022/12/01
冲天 2003/11/23
`;//原来方式:用\s+匹配换行和空格let ZZ = /\s+(.*?)\s+(.*?)/;console.log(ZZ.exec(text));//现在使用dotAll模式,用.除换行外的任何匹配任何字符let ZZ2 = /
.*?(.*?).*?(.*?)/s;console.log(ZZ2.exec(text));
五、ES10
(一)Object.fromEntries
//Object.fromEntries 用键值类型数组元素或者map构造对象let you = Object.fromEntries([["name","陈旺财"],["age",19],["lover","托尼"],["you","你"]]);console.log(you);//与上一个过程相逆let me = Object.entries(you);console.log(me);
(二)字符串清除空格
//trimstart清除字符串开头空格 trimend 清除字符串后面空格let me = "i love you ";console.log(me.trimEnd());console.log(me.trimStart());
(三)数组方法扩展
//数组方法扩展let arr = ["我是谁","我是天王老子","哈哈",['天下有约',"哈哈"]]//将二维数组展开为一维数组let chong = arr.flat();console.log(chong);//flatMap当要遍历的数组中有元素有多维数组,用此函数遍历可以将元素自动降维。每次遍历都会//执行一个回调函数//map函数也是每次执行一个回调函数,但是不会自动降维。let resultMe=arr.flatMap(item => [item]); let resultYou =arr.map(item => [item]); console.log(resultMe); console.log(resultYou);
(四)Symbol获取描述字符串
let mySymbol =Symbol("哇哈哈"); let bin = mySymbol.description;console.log(bin);
六、ES11
(一)类(class)的私用属性
//为类添加私有属性 class myName{//公有属性name = "天下";//私有属性,仅函数内部能够调用#age = 19;constructor(name,age){this.#age = age;this.name= name;}say(){console.log(this.name + "" + this.#age);} } let trueName = new myName("冲天",19); trueName.say(); console.log(trueName.age);//undefined,私有属性无法外部使用
(二)Promise.allSettled()
批量执行Promise:
//批量执行Promise let myPromiseOne = new Promise((win,reject)=>{ setTimeout(()=> {win("成功获取数据1!");},1000); }) let youPromiseTwo = new Promise((win,reject)=>{ setTimeout(()=>{reject("获取数据失败!");},1000); }) let resultPromise = Promise.allSettled([myPromiseOne,youPromiseTwo]); console.log(resultPromise); //Promise.all()一荣俱荣,一损俱损;let resultPromiseTwo = Promise.all([myPromiseOne,youPromiseTwo]);//报错
(三)String.protoType.matchAll()
//String的matchAll方法,与正常的exec加上sg不同,该方法返回的是迭代器对象。 let text2 = ` 天下无双 2022/12/01
冲天 2003/11/23
`; let zzM = /.*?(.*?).*?(.*?)/sg; let allResult = text2.matchAll(zzM); for(let m of allResult){console.log(m); } //下面执行next不能和上面循环共同出现,不然next在下面执行时指向空。 console.log(allResult.next()); console.log(allResult.next());
(四)可选链操作符
用来对传入对象类型的参数进行属性是否存在判断:
//可选链操作符,用于对深层次对象类型参数进行属性判断 function main(forEach){//原来判断,如果无错,会返回,如果有错直接报//let all = forEach && forEach.name && forEach.name.detailName && forEach.name.detailName.hiName;//使用可选链操作符,有错返回undefinedlet all = forEach?.name?.detailName?.hiName;console.log(all); } main({name:{detailName:{hiName: "大志"}},age: 18 });
(五)大整型
//大整数类型 //1、声明 let intMe = 193443n; console.log(intMe,typeof(intMe)); //2、函数将变量转化为大整型 let intHe = 18389384; let intRes = BigInt(intHe); console.log(intRes,typeof(intHe),typeof(intRes)); //3、大整型计算 //获取最大int数,正常情况下,这个数再加2就不会再往上加了; let bigInt = Number.MAX_SAFE_INTEGER; let nomalIntAll = bigInt + 2; let BigIntAll = BigInt(bigInt) + BigInt(2);//注意大整型不能和整型计算 console.log(bigInt); console.log(nomalIntAll); console.log(BigIntAll);
(六)globalThis
globalThis始终执行windows对象,无论在任何位置,都可以使用它对windows对象进行操作。
(七)模块动态引入(import函数)
外部js模块:
export function me(){alert("你好!");}
动态引入:
//原方式,这种方式是在文件加载的时候直接引入//import * as hello from "./app.js";//import函数会在事件发生时再引入模块 let button = document.getElementById("myButton");button.addEventListener("click",()=>{import("./app.js").then(module =>{module.me();});});