ES6-11

一、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的特点

  1. 不能和其他数据类型进行运算,包括字符串拼接。
  2. 在对象中声明的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、迭代器原理

  1. 首先创建一个指针对象指向当前数据结构的起始位置
  2. 执行指针对象中的next方法,指向数据结构的第一个成员;
  3. 不断执行next方法,不断指向下一个结构,返回数据。
  4. 返回数据结构类型为一个属性为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();});});

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值