一、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 = `<ul>
<li>天使</li>
<li>魔鬼</li>
<li>上帝</li>
</ul>`;
//若换成‘或者“则报错,不允许换行。
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用来承接未声明但在实际调用中多出来的参数。)
//不能使用arguments
let 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;
//不给值,有默认值就是默认值,否则undifinded
let numSkey = skyFun(3,54,3);//70
let numSky = skyFun(1,2,3,9);//15
console.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...of
let arrayMe = [...mySet];
console.log(arrayMe);
//遍历
for(let i of mySet){
console.log(i);
}
//清空Set
mySet.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..语句。
//Map
let 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();
//现创建Class
class 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);//undefined
console.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、Number
Number.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,不是为false
console.log(Number.isFinite(100/0));//false
console.log(Number.isFinite(34));//true
console.log(Number.isFinite(Number.PI))//false
//3、判断数的正负,正为1,负为-1,0为0
console.log(Math.sign(3));
console.log(Math.sign(-3));
console.log(Math.sign(0));
//4.判断是否NaN
console.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是分别暴露。
- 引入
<script type="module">
//引入
import * as a from "./testAgain.js";
//引入后暴露属性都被加入a中,通过a来调用。
console.log(a.name);
console.log(a);
</script>
结果:
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!");
}
}
}
引用方式也要发生变化,因为默认方式相当于在中间又加了个对象。
<script type="module">
//引入后暴露属性都被加入a中,通过a来调用。
console.log(a.default.name);
console.log(a.default);
</script>
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文件中引入
<script src="./app.js" type="module">
</script>
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}){
//当传入对象的一些属性没被显示标出,就会被存入other
console.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}){
//当传入对象的一些属性没被显示标出,就会被存入other
console.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 = '<a href="https://baidu.com">尚</a>';
let ZZ = /<a href="(.*)">(.*)<\/a>/;
//接收正则表达式接收到的数据,小括号是子正则
let result = ZZ.exec(zongUrl);
console.log(result[0]);
console.log(result[1]);
console.log(result[2]);
console.log(result);
B、现方式:直接键值对,预防正则变动导致结构下标变动
let zongUrl = '<a href="https://baidu.com">尚</a>';
let ZZ2 = /<a href="(?<url>.*)">(?<content>.*)<\/a>/;
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 = /(?<=锋)\d+/;
let end2 = forContent.exec(love);
console.log(end2);
与上结果一致。
C、dotAll模式
let text = `<li>
<a>天下无双</a>
<p>2022/12/01</p>
</li>
<li>
<a>冲天</a>
<p>2003/11/23</p>
</li>`;
//原来方式:用\s+匹配换行和空格
let ZZ = /<li>\s+<a>(.*?)<\/a>\s+<p>(.*?)<\/p>/;
console.log(ZZ.exec(text));
//现在使用dotAll模式,用.除换行外的任何匹配任何字符
let ZZ2 = /<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/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 = `<li>
<a>天下无双</a>
<p>2022/12/01</p>
</li>
<li>
<a>冲天</a>
<p>2003/11/23</p>
</li>`;
let zzM = /<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/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;
//使用可选链操作符,有错返回undefined
let 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();});});