ES6新特性


传送门:阮一峰ES6入门教程

API网址

可用API https://api.apiopen.top/api/sentences

let,const

let

let声明变量的语法:

    //直接声明
    let a;
    //声明并赋值
    let b = 100;
    //批量声明并赋值
    let c = 'iloveyou',h = [];
  • let 不能重复声明
  • 块级作用域
  • 不存在变量提升(var执行前先收集,再声明前赋值为undefined)
  • 不影响作用域链
    {
      let school = "东北师大";
      function fn(){
        console.log(school);//函数作用域内没有,会向上一级寻找
      }
      fn();
    }

let作用域案例:大div套三个小div,依次点击使小div变成粉色

第一次使用var遍历,不成功,因为var是全局作用域,遍历之后i = 3,点击时没有items[3]

    var items = document.getElementsByClassName('item');
    // 遍历并绑定事件
    for(var i = 0;i < items.length;i ++){
      items[i].onclick = function(){
        // this.style.background = 'pink';
        items[i].style.background = 'pink';
      }
    }
    console.log(window.i);
    // 全局变量i循环体,每一次让i自增

for循环分解:(var)

{
      var i = 0;
    }
    {
      var i = 1;
    }
    {
      var i = 2;
    }
    //i全局存在,执行onclick时作用域找不到,向外层寻找,此时i = 3

for循环分解:(let)

    {
      let i = 0;
      items[i].onclick = function(){
        items[i].style.background = 'pink';
        //此函数块内没有i,顺着作用域链往上i = 2
      }
    }
    {
      let i = 1;
      items[i].onclick = function(){
        items[i].style.background = 'pink';
        //顺着作用域链往上 i = 1.
      }
    }
    {
      let i = 2;
      items[i].onclick = function(){
        items[i].style.background = 'pink';
      }
    }

const

const声明常量,常量是值不能修改的量

    const SCHOOL = '东北师大';
    console.log(SCHOOL);

注意:

  • 一定要赋初始值
  • 一般常量名使用大写
  • 常量值不能修改
  • 也是块级作用域
  • 对于数组和对象的属性做修改,不算作对常量进行修改,不报错(因为常量指向的地址没有改变)
    const TEAM = ['UZI','MXLG','MING','LETME']; TEAM.push('meiko');
    因此数组和对象使用const声明,避免误操作修改数据的值

箭头函数

    let add = function(a,b){
      return a + b;
    }

    //省略function,加 =>
    //小括号写参数
    let fn = (a,b) => {
      return a + b;
    }
    let result = fn(1,2);

箭头函数特性

  • this是静态的,this始终指向函数声明时所在作用域下的this的值
  • 不能作为构造函数实例化对象
  • 不能使用arguments变量(注:arguments变量用来保存实参)

第一点解释
直接调用

    function getName(){
      console.log(this.name);
    }
    let getName2 = () => {
      console.log(this.name);
    }
    window.name = '东北师大';
    const school = {
      name:"NorthEast"
    }
    //普通函数直接调用this值指向window
    getName();//东北师大
    //箭头函数在全局作用域下调用,this值也是指向window
    getName2();//东北师大

使用call方法调用(call方法会改变函数内部this的值)

    function getName(){
      console.log(this.name);
    }
    let getName2 = () => {
      console.log(this.name);
    }
    window.name = '东北师大';
    const school = {
      name:"NorthEast"
    }
    getName.call(school);//NorthEast
    //箭头函数this值是静态的,指向函数在声明时所在作用域下那个this值
    getName2.call(school);//东北师大

** 第二点解释**

    let Person = (name,age) => {
      this.name = name;
      this.age = age;
    }
    let me = new Person('xiao',30);
    console.log(me);//报错

第三点解释

    // let add = (n) => {
    //   return n + n;
    // }
    let add = n => {
      return n + n;
    }
    console.log(add(9));

箭头函数的简写

  1. 省略小括号(当形参有且只有一个时)
    // let pow = (n) => {
    //   return n * n;
    // }
    let pow = (n) => n * n;
    console.log(pow(9));
  1. 省略花括号(当代码体只有一条语句时)
    此时return也必须省略,语句执行结果就是函数返回值
  <script>
    // let pow = (n) => {
    //   return n * n;
    // }
    let pow = (n) => n * n;
    console.log(pow(9));

箭头函数案例
1.点击div,2s后变成粉色

    div{
      width: 80px;
      height: 60px;
      background-color: rgb(104, 174, 240);
    }
<div id="ad"></div>
    let ad = document.getElementById('ad');
    ad.addEventListener("click",function(){
      //把外层函数作用域下的this进行保存
      let _this = this;
      setTimeout(function(){
        //这里的this指向window,window没有style属性
        //当前作用域找不到_this,往外层找
        _this.style.background = 'pink';
      },2000)
    });
    let ad = document.getElementById('ad');
    ad.addEventListener("click",function(){
      setTimeout(() => {
        //箭头函数,this指向声明时所在函数的this,即addEventListener函数
        //该函数this指事件源ad
        this.style.background = 'pink';
      },2000)
    });

2.从数组中返回偶数的元素

   const arr = [1,6,9,10,100,25];
   
    //filter返回一个新数组,新数组中是满足条件的元素
    //item是必选参数,表示当前元素的值
    
    // 第一种
    // const result = arr.filter(function(item){
    //   if(item % 2 === 0) return true;
    //   else return false;
    // })

    // 第二种
    // const result = arr.filter((item) => {
    //   if(item % 2 === 0) return true;
    //   else return false;
    // })

    // 第三种
    const result = arr.filter(item => item % 2 === 0);
    console.log(result);

箭头函数

  • 适合用于与this无关的回调:定时器,数组的方法回调
  • 不适合与this有关的回调:DOM元素的事件回调(此时this应该指向事件源),对象的方法
    {
      name:'东北师大',
      getName:function(){
        //this指向所在这个函数块
        this.name;
      }
    }
    {
      name:'东北师大',
      getName:() => {
        //this指向外层作用域的this值
        this.name;
      }
    }

变量的解构赋值

解构赋值:从数组和对象中提取值,赋值给变量

数组解构

    const F4 = ['小沈阳','刘能','赵四','宋小宝'];
    //相当于声明了四个变量,
    let [xiao,liu,zhao,song] = F4;
    console.log(xiao);
    console.log(liu);
    console.log(zhao);
    console.log(song);

对象解构

    const zhao = {
      name:"赵本山",
      age:"不详",
      xiaopin:function(){
        console.log("我可以演小品");
      }
    }
    //变量名要一样,zhao里没有解构器
    let {name,age,xiaopin} = zhao;
    console.log(name);
    console.log(age);
    console.log(xiaopin);
    xiaopin()
    const zhao = {
      name:"赵本山",
      age:"不详",
      xiaopin:function(){
        console.log("我可以演小品");
      }
    }
    //单独解构
    let {xiaopin} = zhao;
    xiaopin();
    //避免写zhao.xiapin();

模板字符串(反引号)

    let string = `我也是一个字符串哦!`;
    console.log(string,typeof string);

用单引号

    let string = '<ul>'
      +'<li>沈腾</li>'
      +'<li>玛丽</li>'
      +'<li>魏翔</li>'
      +'<li>艾伦</li>'
      +'</ul>'
    console.log(string);

用反引号

    let string = 
    `<ul>
        <li>沈腾</li>
        <li>玛丽</li>
        <li>魏翔</li>
        <li>艾伦</li>
    </ul>`
    console.log(string);

特性:

  • 内容中可以出现换行符,单引号双引号不可以
  • 变量拼接
    let lovest = '魏翔';
    let out = `${lovest}是我心目中最搞笑的演员`;
    console.log(out);

对象的简化写法

    let name = '东北师大';
    let gradu = function(){
      console.log("我们毕业啦");
    }
    const school = {
      //简化书写内容
      name,
      gradu,
      beauty(){
        console.log("真好看");
      }

      // beauty:function(){
      //   console.log("我们学校真好看");
      // }
      //省略:function

    }
    console.log(school);

函数参数的默认值设置

ES6允许给函数参数赋初始值,位置要靠后

    function add(a,b,c = 10){
      return a + b + c;
    }
    let result = add(1,2);
    console.log(result);

与解构赋值结合

    // function connect(options){
    //   let host = options.host;
    //   let username = options.username;
    // }

    // 与解构赋值结合
    function connect({host,username,password,port}){
      console.log(host);
      console.log(username);
      console.log(password);
      console.log(port);
    }

    //调用方法,传入一个对象
    connect({
      host:'localhost',
      username:'root',
      password:'root',
      port:3306
    })

给属性赋初始值

	function connect({host = "127.0.0.1",username,password,port}){
      console.log(host);
      console.log(username);
      console.log(password);
      console.log(port);
    }

    //调用方法,传入一个对象
    connect({
      //host:'localhost',
      username:'root',
      password:'root',
      port:3306
    })

rest参数

代替arguments,用于获取函数的实参

 //ES5获取实参的方式
    function data(){
      //arguments原型是对象
      console.log(arguments);
    }
    data('哈哈','嘻嘻','呵呵');

    // rest参数
    //声明方式:...标识符
    function data(...args){
      //数组,可以使用filter,some,every,map方法
      console.log(args);
    }
    data('阿娇','白芷','思慧');

    //rest参数必须放在最后
    function fn(a,b,...args){
      console.log(a);
      console.log(b);
      console.log(args);
    }
    fn(1,2,3,4,5);

拓展运算符

... 将数组 转换为 逗号分隔的参数序列

   const cities = ['新疆','西藏','青海'];
   function chunwan(){
     console.log(arguments);
   }
   chunwan(cities);//一个成员
   chunwan(...cities);//三个成员
  //  等同于chunwan('新疆','西藏','青海');

拓展运算符的应用

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];
    console.log(sanyecao);

3.将伪数组转为真正的数组

    const divs = document.querySelectorAll('div');
    console.log(divs);//对象
    const divArr = [...divs];
    console.log(divArr);//数组

symbol

symbol是es6的新的原始数据类型,表示独一无二的值。是js的第七种数据类型
Symbol创建的两个方式

    //Symbol是一个函数
    let s = Symbol();
    let s2 = Symbol('尚硅谷');
    let s3 = Symbol('尚硅谷');
    console.log(s2 === s3);//false

    //Symbol.for创建,可以通过描述字符串得到唯一的symbol值
    //Symbol是一个对象
    let s4 = Symbol.for('尚硅谷');
    let s5 = Symbol.for('尚硅谷');
    console.log(s4 === s5);//true
  • Symbol的值是惟一的,用来解决命名冲突的问题
  • Symbol的值不能与其他数据进行运算
  • Symbol定义的对象属性不能用for…in循环遍历,但是可以使用Reflect.ownKeys来获取对象的所有键名
    js数据类型:USONB
    u:undefined
    s:string symbol
    o:object
    n:null number
    b:boolean

Symbol的使用场景

给对象添加Symbol类型的属性和方法,表示独一无二的值,防止与原有属性名产生冲突
1.

    //快速安全地把方法(和up,down相关)添加到对象game上
    let game = {
      name:'俄罗斯方块',
    };
    //声明一个对象,两个属性对应的都是Symbol类型的值
    let methods = {
      up:Symbol(),
      down:Symbol()
    };
    // 给game拓展方法
    game[methods.up] = function(){
      consolelog("我可以改变形状");
    }
    game[methods.down] = function(){
      console.log("我可以快速下降");
    }
    console.log(game);
    let youxi = {
      name:"狼人杀",
      //不可以直接写Symbol,因为Symbol是一个动态值,不是固定属性
      // Symbol():function(){}
      //Symbol是动态表达式,应该添上中括号
      [Symbol('say')]:function(){
        console.log("我可以发言")
      },
      [Symbol('zibao')]:function(){
        console.log("我可以自爆");
      }
    }
    console.log(youxi)

Symbol的内置值

除了定义自己使用的Symbol唯一值以外,ES6还提供了11个内置的Symbol属性,Symbol.xxx整体作为对象的属性而存在

    class Person{
      static [Symbol.hasInstance](param){
        console.log(param);
        console.log("我被用来检测类型了");
      }
    }
    let o = {};
    console.log(o instanceof Person)
    const arr = [1,2,3];
    const arr2 = [4,5,6];
    arr2[Symbol.isConcatSpreadable] = false;
    console.log(arr.concat(arr2));

迭代器

迭代器(iterator)是一种接口。ES6创造一种新的遍历命令for...of,iterator接口主要供该命令消费
原生具备iterator的数据(可用for…of遍历)

  • Array
  • Arguments
  • Set
  • Map
  • String
  • TypedArray
  • NodeList
    const xiyou = ['唐僧','孙悟空','猪八戒','沙僧'];
    //使用for...of遍历
    //for...in保存键名,for...of保存键值
    for(let v of xiyou){
      console.log(v);
    }
    console.log(xiyou);

遍历的工作原理:

  • Symbol.iterator()创建一个指针对象,指向当前数据结构的起始位置
  • 返回的指针对象有next(),第一次调用next(),指针自动指向数据结构第一个元素
  • 接下来不断调用,指针往后移,直到指向最后一个元素
  • 每调用next()返回一个包含value和done属性的对象
    const xiyou = ['唐僧','孙悟空','猪八戒','沙僧'];
    //使用for...of遍历
    //for...in保存键名,for...of保存键值
    for(let v of xiyou){
      console.log(v);
    }
    console.log(xiyou);
    let iterator = xiyou[Symbol.iterator]();
    //调用next()
    console.log(iterator.next());//指针指向第一个成员唐僧
    console.log(iterator.next());//孙悟空
    console.log(iterator.next());//猪八戒
    console.log(iterator.next());//沙僧
    console.log(iterator.next());//value:undefined,done:true

迭代器案例

自定义(按自己意愿)遍历数据时,想到迭代器

    const banji = {
      name:'终极一班',
      stus:[
        'xiaoming',
        'xiaoning',
        'xiaotian',
        'knight'
      ],
      [Symbol.iterator](){
        //索引变量
        let index = 0;
        // let _this = this;
        //返回一个对象
        return {
          next:() => {
            if(index < this.stus.length){
              const result =  {value:this.stus[index],done:false};
              index ++;
              return result;
            }
            else{
              return {value:undefined,done:true}
            }
          }
        };
      }
    }
    // 使用for...of遍历对象,返回数组的成员.对对象进行遍历
    for(let v of banji){
      console.log(v);
    }
    //banji.stus.forEach()不符合面向对象的思想

生成器

生成器是异步编程的一种解决方案
三个特殊性:

    //声明要加*
    function * gen(){
      console.log("hallo generator");
    }
    //调用函数并执行next方法才能执行
    let iterator = gen();
    iterator.next();
    function * gen(){
      //生成器函数可以出现yield语句,yield可算作函数代码的分隔符
      // 代码块一
      console.log(111);
      yield '一直没有耳朵';
      // 代码块二
      console.log(222);
      yield '一直没有尾巴';
      //三
      console.log(333);
      yield '真奇怪';
      // 四
      console.log(444);
    }
    //调用函数并执行next方法才能执行
    let iterator = gen();
    iterator.next();
    iterator.next();
    iterator.next();
    iterator.next();
    function * gen(){
      //生成器函数可以出现yield语句,yield可算作函数代码的分隔符。next函数遇到yield会停止
      yield '一直没有耳朵';
      yield '一直没有尾巴';
      yield '真奇怪';
    }
    let iterator = gen();
    console.log(iterator.next());
    console.log(iterator.next());
    console.log(iterator.next());
    console.log(iterator.next());
    //遍历
    for(let v of gen()){
      console.log(v);
    }
    //整体的函数传参
    function * gen(arg){
      console.log(arg);
      let one = yield 111;//第一个yield
      yield 222;
      yield 333;
    }
    // 执行获取迭代器对象
    let iterator = gen('AAA');
    console.log(iterator.next());
    //next语句也可以传参,作为上一个yield的返回结果
    console.log(iterator.next('BBB'));//第二个next语句

生成器案例

案例一

1s后控制台输出111,2s后输出222,3s后输出333
方案一:回调地狱

    setTimeout(() => {
      console.log(111);
      setTimeout(() => {
        console.log(222);
        setTimeout(() => {
          console.log(333);
        },3000)
      },2000)
    },1000)

方法二:生成器

    //声明三个函数分别完成三个异步任务
    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 = '用户数据';
        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);
      let orders = yield getOrders();
      console.log(orders);
      let goods = yield getGoods();
      console.log(goods);
    }
    //调用生成器函数
    let iterator = gen();
    iterator.next();//执行第一段代码

    //无法保持数据关联度
    // getUser();
    // getOrderss();
    // getGoods();

promise

promise是ES6引入的异步编程的新解决方案。语法上promise是一个构造函数,可以实例化对象,用来封装异步操作。可以获取其成功或者失败的结果

    // 实例化promise对象,
    // 接收函数类型的参数,该函数有resolve,reject两个形参
    const p = new Promise(function(resolve,reject){
      //封装异步操作
      setTimeout(function(){
        let data = '数据库中的用户数据';
        //调用resolve和reject函数改变promise对象的状态
        //对象的状态变成成功
        // resolve(data);

        let err = '数据读取失败';
        reject(err);
      },1000)
    });

    //成功则调用promise对象的then方法
    // then方法接收两个函数型参数,每个函数一个形参
    p.then(function(value){
      //成功则调用第一个回调函数的方法
      console.log(value);
    },function(reason){
      //失败执行第二个回调函数
      console.error(reason);
    })

promise封装读取文件内容

读取文件是异步操作。避免代码持续向内部缩进

const fs = require('fs');

/* 调用readFile方法读取文件
fs.readFile('./resources/为学.md',(err,data) => {
  if(err) throw err;
  console.log(data.toString());
}) */

// 使用promise封装
const p = new Promise(function(resolve,reject){
  fs.readFile("./resources/为学.md",(err,data) => {
    if(err) reject(err);
    resolve(data);
  })
});

p.then(function(value){
  console.log(value.toString());
},function(reason){
  console.log("读取失败");
});

Promise封装Ajax请求

   const p = new Promise((resolve,reject) => {
      // 1.创建对象
      const xhr = new XMLHttpRequest();
      // 2.初始化
      xhr.open("GET","https://api.apiopen.top/api/sentences");
      // 3.发送
      xhr.send();
      // 4.绑定事件
      xhr.onreadystatechange = function(){
        if(xhr.readyState === 4){
          //判断响应状态码
          if(xhr.status >= 200 && xhr.status < 300){
            //console.log(xhr.response);
            resolve(xhr.response);
          }else{
            //console.log(xhr.status);
            reject(xhr.status);
          }
        }
      }
    })

    //指定成功和失败的回调
    //在.then方法回调,结构更清晰
    p.then(function(value){
      console.log(value);
    },function(reason){
      console.error(reason);
    })

.then方法

    const p = new Promise((resolve,reject) => {
      setTimeout(function(){
        resolve("用户数据");
        // reject("出错了");
      },1000)
    })
    //.then方法返回状态也是一个promise,返回结果由回调函数的执行结果确定
    
    //1.不写返回值返回undefined
    const result = p.then(value => {
      console.log(value);
      //2.如果返回值是非Promise属性,状态为成功,返回值是对象的成功的值
      // return 'iloveyou'

      //3.如果返回promise对象,内部promise状态决定.then方法promise的状态
      // return new Promise((resolve,reject) => {
      //   // resolve('ok');
      //   reject('error');
      // });

      // 4.抛出错误
      // throw '出错啦!';//抛出字符串
      throw new Error("出错啦!");
    },reason => {
      console.warn(reason);
    })
    console.log(result);

链式调用(杜绝回调地狱)

    p.then(value => {},reson => {})
    .then(value => {},reson => {})

实践练习:多个文件内容读取

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]);//resolve后,then方法返回的promise也成功
    });
  });
}).then(value => {//此时value是第1、2文件的数组
  return new Promise((resolve,reject) => {
    fs.readFile('./resources/李白.md',(err,data) => {
      // 数组压入
      value.push(data);
      resolve(value);//value是三个文件的数组
    })
  })
}).then(value => {
  // console.log(value);
  console.log(value.join('\r\n'));
})

.catch方法

语法糖,then方法不指定第一个参数和catch是一样的

    const p = new Promise((resolve,reject) => {
      setTimeout(() => {
        // 修改p状态为失败,并设置失败的值
        reject("出错啦");
      },1000)
    });

    // p.then(function(value){},function(reason){
    //   console.error(reason);
    // })

    p.catch(function(reason){
      console.warn(reason);
    })

集合

ES6提供了新的数据结构Set(集合),类似于数组,但成员的值都是惟一的
实现了iterator接口,可以使用let of遍历

    let s = new Set();
    //去重的方法之一
    let s2 = new Set(['大事','小事','好事','坏事','小事']);
    //元素个数
    console.log(s2.size);
    s2.add('喜事');
    s2.delete('坏事');
    s2.has('好事');
    // s2.clear();
    for(let v of s2){
      console.log(v);
    }

求集合的去重、交并差案例

    let arr = [1,2,3,4,5,4,3,2,1];
    // 1.数组去重
    let result1 = new Set(arr);//集合,不是数组
    result1 = [...new Set(arr)];//扩展运算符
    
    //2.交集
    let arr2 = [4,5,6,5,6];
    let result2 = [...new Set(arr)].filter(item => {
      //result2是数组,filter返回一个新数组。item是必选参数
      let s2 = new Set(arr2);
      // s2是集合,有has方法判断
      if(s2.has(item)) return true;
      else return false;
    })
    // 简易写法
    // let result2 = [...new Set(arr)].filter(item => new Set(arr2).has(item));

    // 3.并集
    // ...将数组、集合分成逗号分开的参数序列
    //整体加上中括号后又是一个数组
    let union = [...new Set([...arr,...arr2])];

    //4.差集
    let diff = [...new Set(arr)].filter(item => !(new Set(arr2).has(item)));
    console.log(diff);

map

ES6提供了Map数据结构。类似于对象,升级版的对象,是键值对的集合,但是“键”不限于字符串,可以是各种类型的值。
Map也实现了iterator接口,可以用扩展运算符...for...of...遍历
Map的属性和方法:

  • size 返回Map元素个数
  • set 添加新元素,返回当前Map m.set(‘键名’,'键值')
  • get 返回键名对象的键值
  • has
  • clear 返回undefined
    let m = new Map();
    m.set('name','尚硅谷');
    m.set('change',function(){
      console.log("我们可以改变你");
    })
    let key = {
      school:'ATGUIGU'
    };
    m.set(key,['北京','上海','深圳']);
    console.log(m.size);//长度
    console.log(m.get('change'));//获取
    console.log(m.get(key));//获取
    m.delete('name');//删除
    // m.clear();//清空
    //遍历
    for(let v of m){
      console.log(VBArray);
    }

class

ES6提供了更接近传统语言(java,c++)的写法,引入类的概念,可以当做语法糖,其功能ES5基本都能完成,新的写法可以让对象原型写得更清晰,更面向对象。

ES5和ES6中class的语法区别

    // ES5写法
    //手机
    function Phone(brand,price){
      //this是所在函数所属对象的引用。
      //哪个对象调用了this所在的函数,this就代表哪个对象
      this.brand = brand;
      this.price = price;
    }
    //添加方法
    //在一个对象的上下文中应用另一个对象的方法
    Phone.prototype.call = function(){
      console.log("我可以打电话!");
    }
    //实例化对象
    let Huawei = new Phone('华为','5999');
    Huawei.call();
    console.log(Huawei);

    //ES6
    
    class Person{
      // 构造方法是特殊方法,名字不可修改,自动执行
      //使用new+类名时会自动执行constructor方法
      constructor(name,school){
        this.name = name;
        this.school = school;
      }
      //加方法,必须使用该语法
      call(){
        console.log("我可以干活!");
      }
    }
    //类就绪,实例化
    let Huang = new Person("YUYING","NORTH");
    console.log(Huang);
    Huang.call();

static静态成员

    // ES5
    // 构造函数本身也是对象
    function Phone(){
      //
    }
    // 这两个属性属于函数对象,不属于实例对象
    //这样的属性是静态成员
    Phone.name = '手机';
    Phone.chage = function(){
      console.log("我可以改变世界");
    }
    //实例对象没有构造函数对象的属性
    // 实例对象属性和构造函数原型对象相同
    Phone.prototype.size = '5.5inch';
    let nokia = new Phone;
    console.log(nokia.size);

    // 实例对象和函数对象属性不同

    //ES6
    class Person{
      // static标注的属性和方法,属于类,不属于实例对象
      static name = '人';
      static change(){
        console.log("读书改变命运");
      }
    }
    let Huang = new Person;
    console.log(nokia.name);
    console.log(Person.name);

继承

ES5构造函数继承

    // ES5构造函数继承
    //父级构造函数
    function Phone(brand,price){
      this.brand = brand;
      this.price = price;
    }
    Phone.prototype.call = function(){
      console.log("我可以打电话!");
    }
    //子级构造函数
    function smartPhone(brand,price,color,size){
      //先调用父级构造函数初始化代码
      // 通过call方法修改this值,this指向smartPhone的实例对象
      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.game = function(){
      console.log("可以打游戏");
    }

    // 实例化
    const Apple = new smartPhone('苹果',5000,'red','5.5inch');
    console.log(Apple);

class类继承

    class Phone{
      constructor(brand,price){
        this.brand = brand;
        this.price = price;
      }
      call(){
        console.log('我可以打电话');
      }
    }

    class smartPhone extends Phone {
      //构造方法
      constructor(brand,price,color,size){
        //调用父类的构造方法进行初始化,super就是父类的constructor方法
        super(brand,price);//Phone.call(this,brand,price);
        this.color = color;
        this.size = size;
      }
      //添加子类独有的方法
      photo(){
        console.log("拍照");
      }
      game(){
        console.log("游戏");
      }
    }
    //实例化
    const OPPO = new smartPhone('欧珀',799,'red','5.5inch');
    console.log(OPPO);
    OPPO.call();
    OPPO.game();
    OPPO.photo();

子类对父类的方法重写

子类不可以直接调用父类的同名方法

getter和setter

对对象的属性进行方法绑定
get:封装对象动态属性
set:添加判断

   class Phone{
      //没有构造方法也是合理的
      get price(){
        console.log("价格属性被读取了");
        return 'iloveyou'
      }
      set price(newVal){
        console.log('价格属性被修改了');
      }
    }
    //实例化对象
    let s = new Phone();
    //读取price属性,就执行里边代码
    //返回值就是属性的值
    console.log(s.price);
    s.price = 'free';

模块化

模块化:将大文件拆分成小文件,再将小文件组合起来
好处:

  1. 防止面临冲突
  2. 代码复用
  3. 高维护性

export

  1. 分别暴露
export let school = "NENU"
export function study(){
  console.log("I LOVE STUDY")
}
  1. 统一暴露
let school = "NENU"
function study(){
  console.log("I LOVE STUDY")
}

export{
  school,study
}
  1. 默认暴露
//暴露数据可以是任意类型,可以数数字,字符串等,对象居多
export default{
  school:"NENU",
  study:function(){
    console.log("I LOVE STUDY")
  }
}
//该方法调用时要多加一层default结构
//message.default.study();

import

  1. 通用导入方式
<script type = "module">
  import * as message from "./index.js"
  console.log(message);
</script>
  1. 解构赋值形式
<script type = "module">
  import {school,study} from "./index.js";
  //使用别名避免冲突
  import {school as NE,qualify} from './index2.js';
  // m3是对象,有一个default属性,里边存的是变量
  //必须给default取别名
  import {default as m3} from "./index.js";
  
  console.log(m3)
  console.log(school);
  console.log(study);
  console.log(NE);
  console.log(qualify);
</script>

3.简便形式(针对默认暴露)

<script type = "module">
  import message from "./index.js"
  console.log(message)
</script>

其它引入方式:在script标签中加入src和type属性,另建一个js文件

模块化代码在项目中的引用(babel对ES6模块化代码转换)

环境配置

npm init --yes
npm i babel-cli babel-preset-env browserity -D

async和await(ES8)

async

异步编程的新解决方案
async函数返回promise对象
promise对象的结果由async函数执行的返回值决定

    async function fn(){
      //只要return的不是promise对象,结果都是promise对象,状态是fulfilled
      // return 'hhh';

      //若抛出错误,返回rejected的promise
      // throw new Error("出错啦");

      //返回promise对象,由promise状态决定
      return new Promise((resolve,reject) => {
        // resolve('成功的数据');
        reject('失败的数据');
      })
    }
    const result = fn();
    console.log(result);

    result.then(value => {
      console.log(value)
    },reason => {
      console.warn(reason)
    })

await

await必须卸载async函数里,右侧为promise对象,返回promise成功的值,如果promise失败,抛出异常,通过try…catch处理

    const p = new Promise((resolve,reject) => {
      // resolve("成功数据");
      reject("失败数据");
    })
    async function main(){
      try{
        let result = await p;//await返回结果就是promise对象成功的数据
        console.log(result);
      } 
      catch(e){//catch语句可以得到失败的结果
        console.log(e);
      }
    }
    main();

async和await结合读取文件内容

//引入文件模块
const fs = require('fs')
// 使用promise函数调用
function readLibai(){
  return new Promise((resolve,reject) => {
    fs.readFile('./resources/李白.md',(err,data) => {
      if(err) reject(err);
      resolve(data);
    })
  })
}
function readWeixue(){
  return new Promise((resolve,reject) => {
    fs.readFile('./resources/为学.md',(err,data) => {
      if(err) reject(err);
      resolve(data);
    })
  })
}
// async,await函数接收
async function main(){
  let libai = await readLibai();
  let weixue = await readWeixue();
  console.log(libai.toString())
  console.log(weixue.toString())
}
// 调用
main()

async和await结合发送ajax请求

   function sendAjax(url){
      return new Promise((reject,resolve) => {
        // 创建对象
        const xhr = new XMLHttpRequest();
        // 初始化
        xhr.open('GET', url);
        // 发送
        xhr.send();
        // 事件绑定
        xhr.onreadystatechange = function(){
          if(xhr.readyState === 4){
            if(xhr.status >= 200 && xhr.status <= 300){
              resolve(xhr.response);
            }
            else{
              reject(xhr.status);
            }
          }
        }
      })
    }
    // promise then 测试
    const result = sendAjax("https://api.apiopen.top/api/sentences").then((value => {
      console.log(value);
    },reason => {}))

数值扩展

	//js最小精度
    console.log(0.1+0.2);//0.30000000000000004
    console.log(0.1 + 0.2 === 0.3); //false
    function equal(a,b){
      if(Math.abs(a - b) < Number.EPSILON){
        return true;
      }
      else{
        return false;
      }
    }
    console.log(equal(0.1 + 0.2,0.3))//true

	//进制
    let b = 0b1010;//二进制
    let o = 0o777;//八进制
    let x = 0xff;//十进制

	//判断一个数值是否是有限数
    console.log(Number.isFinite(100));//true
    console.log(Number.isFinite(100/0));//false
    console.log(Number.isFinite(Infinity));//false

	//检测一个数字是否是NaN
    console.log(Number.isNaN(123));//false
    //ES6把isNaN作为Number的一个方法

    // 把字符串转化为整数/浮点数
    console.log(Number.parseInt('5213'));//5213
    console.log(Number.parseFloat('3.1415神奇'))//3.1415

    //判断一个数字是否是证书
    console.log(Number.isInteger(5));//true
    console.log(Number.isInteger(2.5));//false

    //将数字的小数部分抹掉
    console.log(Math.trunc(3.5));//3

    //检测一个数是正数、负数还是零
    console.log(Math.sign(100));//1
    console.log(Math.sign(0));//0
    console.log(Math.sign(-100));//-1

对象方法拓展

    // Object.is判断两个值是否完全相等
    console.log(Object.is(120,121));//false
    console.log(Object.is(NaN,NaN));//true
    console.log(NaN === NaN);//false

    //Object.assign 对象合并,适合配置合并
    //重名的覆盖掉,不同名的都显示
    const config1 = {
      host:'localhost',
      port:3306,
      name:'root',
      address:'xxxx'
    }
    const config2 = {
      host:'http://atguigu.com',
      port:33060,
      name:'atguigu.com',
      tel:1804622222
    }
    console.log(Object.assign(config1,config2));

    //Object.setPrototypeOf 设置原型对象
    //Object.getPrototypeof
    const school = {
      name:'xiaoming'
    }
    const cities = {
      province:['guangxi','jilin','beijing']
    }
    Object.setPrototypeOf(school,cities);
    console.log(school);
    console.log(Object.getPrototypeOf(school));
    //但是不建议这么添加属性,定义时直接写上较佳

对象展开(rest参数和扩展运算符)

rest参数和spread扩展运算符在ES6中已经引入,只针对数组
ES9中为对象也提供了rest参数和扩展运算符

  <script>
    //定义方法
    function connect({host,port,...user}){
      console.log(host);
      console.log(port);
      console.log(user);
    }
    // 调用方法
    connect({
      host:'127.0.0.1',
      port:3306,
      //后面两个参数会存到user变量中
      username:'root',
      password:'port'
    });
  </script>

扩展运算符:将对象展开,形成参数序列

  <script>
    const skillOne = {
      q:'天音波'
    }
    const skillTwo = {
      w:'金钟罩'
    }
    const skillThree = {
      e:'天音波'
    }
    const skillFour = {
      r:'猛龙摆尾'
    }
    // 把四个对象的属性放到一个对象里
    const mangseng = {
      ...skillOne,
      ...skillTwo,
      ...skillThree,
      ...skillFour
    }
    console.log(mangseng);//{ "q": "天音波","w": "金钟罩", "e": "天音波","r": "猛龙摆尾"}
  </script>

正则拓展

命名捕获分组

对分组匹配结果命名,方便对结果的处理

  1. 原始做法(groups:undefined)
    let str = '<a href="http://www.baidu.com">百度</a>'
    // 提取url和标签文本
    const reg = /<a href="(.*)">(.*)<\/a>/
    const result = reg.exec(str)
    //数组,result[0]是整个整个正则匹配,result[1]是第二个括号,result[2]是第二个括号
    console.log(result[1])
    console.log(result[2])
  1. 正则捕获分组做法(groups:键值对)
    避免更改需要获取的属性时引起的数组下标变化,因此更易于代码维护
    let str = '<a href="http://www.baidu.com">百度</a>'
    const reg = /<a href="(?<url>.*)">(?<text>.*)<\/a>/
    const result = reg.exec(str);
    console.log(result)
    console.log(result.groups.url)
    console.log(result.groups.text)

反向断言

断言:判断匹配结果是否正确。
根据目标值的前或后,做唯一性识别

// 正向断言
    let str = 'NENU20230329图书馆1042啦啦啦'
    const reg = /\d+(?=啦)/
    const result = reg.exec(str)
    console.log(result)
    console.log(result[0])

    //反向断言
    const reg2 = /(?<=馆)\d+/
    const result2 = reg2.exec(str)
    console.log(result2)

dotAll模式

加了s之后.可以匹配任意字符

  <script>
    let str = `
      <ul>
        <li>
          <a>肖申克的救赎</a>
          <p>上映日期:1994-09-10</p>
        </li>
        <li>
          <a>阿甘正传</a>
          <p>上映日期:1994-07-06</p>
        </li>
      </ul>`;
    // \s表示单个空白字符,加?表示禁止贪婪
    const reg = /<li>\s+<a>(.*?)<\/a>\s+<p>(.*?)<\/p>/
    const result = reg.exec(str);
    console.log(result);

    //使用dotAll模式
    // g表示全局匹配
    const reg2 = /<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/gs
    let data = [];
    let result2;
    while(result2 = reg2.exec(str)){
      data.push({title:result2[1],time:result2[2]});
    }
    console.log(data);
  </script>

对象方法拓展

Object.fromEntries 将二维数组或者map转化为对象
Object.Entries 将对象转化为二维数组

  // 二维数组
  const result = Object.fromEntries([
    ['name','NENU'],
    ['subject','math,art']
  ])
  // Map
  const m = new Map();
  m.set('name','TONG');
  const result2 = Object.fromEntries(m);
  console.log(result)
/*   {"name": "NENU","subject": "math,art"} */
  console.log(result2)
/*   {"name": "TONG"} */

  // Object.entries将对象转化为二维数组
  const arr = Object.entries({
    name:"HYY"
  })
  console.log(arr)

字符串方法拓展

trim清除字符串两端的空白字符

let str = '   iloveyou   '
console.log(str)
console.log(str.trimStart())
console.log(str.trimEnd())

数组方法拓展

flat将多维数组转化为低维数组,参数为深度

const arr = [1,2,3,4,[5,6]];
console.log(arr.flat());//[1,2,3,4,5,6]
const arr2 = [1,2,3,[4,5,6,[7,8,9]]];
console.log(arr2.flat())//[1,2,3,4,5,6,[7,8,9]]
console.log(arr2.flat(2))//[1,2,3,4,5,6,7,8,9]

const arr3 = [1,2,3]
// 乘10,且假设返回的是数组,就可以使用flatmap
const result = arr3.flatMap(item => [item * 10])
console.log(result)//[10,20,30]
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值