ES6新特性详解

-let关键字声明变量新特性

  • 变量不能重复声明
  • 具有块儿级作用域(只在对应的{}块儿内有效)
  • 不具备变量提升(即在let关键字声明的变量之前使用该变量会报错)
  • 不影响作用域链(即在let声明变量的块儿内书写函数访问该变量时,在函数体内没找到该变量依然会随着作用域链向上找)
  • 暂时性死区(用let在块儿级作用域中声明的变量与外界隔离,即使变量名相同也互不影响)
  // 例如下列代码
  var boxs = document.getElementsByClassName("box")
      for (var i = 0; i < boxs.length; i++) {
         boxs[i].onclick = function() {
           boxs[i].style.backgroundColor = "red"
         }
       }

在for循环内使用var关键字声明i时,此时i声明在全局,当代码执行时会先将for循环执行完,为boxs中的元素绑定事件,当事件实际触发时,全局的i已经变为了boxs.length+1,因此事件并不会触发
使用let关键字声明

 // 使用let关键字声明
 var boxs = document.getElementsByClassName("box")
   for (leti = 0; i < boxs.length; i++) {
      boxs[i].onclick = function() {
        boxs[i].style.backgroundColor = "red"
      }
    }

但是如果使用let关键字进行声明,for循环执行时每次i的值都只在当前的块儿级作用域有效,互不影响,因此在事件响应函数内能正确访问到当前点击事件对应的元素对象,其相当于:

  {
  let i = 0;
    boxs[i].onclick = function() {
       boxs[i].style.backgroundColor = "red"
     }
   }
  {
  let i = 1;
    boxs[i].onclick = function() {
       boxs[i].style.backgroundColor = "red"
     }
   }等等
     
```

-const关键字声明常量新特性

  • const用来声明一个常量,且在声明时必须赋值,不然会报错
  • 同样具有块儿级作用域
  • 同样具有暂时性死区
  • 声明的变量不可更改(注意:声明的变量如果是普通的值的话其值是不可更改的,但是如果声明的是一个对象或数组,可以修改其内部的内容,这是因为const指向的地址没有发生变化,但是仍然不可以更改地址的指向)
  • 潜规测–>声明的常量名大写

-解构赋值

  • 针对数组[ ]、对象进行了模式匹配,简化了语法
数组-按顺序一一对应
// 左侧变量数和数组内元素个数相等
 let [ a, b, c] = [1, 2, 3]
 console.log(a, b, c) // 1, 2, 3
// 左侧变量数和数组内元素个数不等
let [a, b] = [1, 2, 3]
console.log(a, b) // 1,2

let [a ,b ,c] = [1, 2]
console.log(a, b, c)   // 1,2,undefined

// 剩余运算符(展开运算符) ...
let [a , ...b] = [1, 2, 3]
console.log(a, b) //  a, [2,3]
  • 针对对象{ }时,接收数据的变量必须和对象的属性相同
     let obj = {name: '猪八戒', age: 39, sex: '男'};
     let {name ,age, sex} = obj;
     console.log(name, age, sex);// 猪八戒, 39, 男

-模板字符串

  • 也可以用来声明一个字符串
  • 模板字符串声明的字符串支持换行,不需要再用+号拼接
  • 在模板字符串里可以通过${ }进行变量拼接
// 字符串拼接,十分方便,单引号和双引号需要用+号连接
      let str = `<ul>
     <li></li>
     <li></li>
     <li></li>
     </ul>`
    
// 变量拼接 ${ }
let name = 猪;
let str = `${name}八戒` 
console.log(str) // 猪八戒

-对象的简化写法

  • 在ES6中支持在大括号{ } 里直接写入变量、函数来作为对象的属性、方法
    let name = "猪八戒";
    let changeName = function(name) {
         this.name = name;
     };
     const person = {
         name,
         changeName
     }
    console.log(person.name) // 猪八戒
    person.changeName("孙悟空");
    console.log(person.name) // 孙悟空
     }

-箭头函数 ( ) => { }

  • 在ES6中支持用箭头函数来声明一个函数,简化了代码
  • ( )内书写形参, { } 内书写代码体
  • 箭头函数的this是静态的(即不可通过call 和 apply改变this指向),它始终指向声明时所在作用域下的this
	 // 函数声明方法
     function getName() {
         console.log(this.name);
      }
     // 箭头函数方法
     let getName2 = () => {
        console.log(this.name);
     }
     // 在Window对象下添加一个属性
     window.name = "猪八戒";
     // 添加一个对象
    const Person = {
        name: "孙悟空"
     };
     // 当直接调用时
     getName(); // 猪八戒
     getName2(); // 猪八戒

     // 指定对象调用
     getName.call(Person); // 孙悟空
     getName2.call(Person);// 猪八戒(即this的指向没有改变)
  • 箭头函数的简写
    当( )内参数只有一个时,括号可以不写,{ }大括号里只有一条语句且该语句的执行结果是返回值时,大括号可以不写,同时return得去掉
let add = (i) => {
	return i+i;
}
等价于
let add =  i => i+i;
console.log(add(1)); // 2

使用箭头函数注意事项
1.不能作为构造函数实例化对象
2. 箭头函数内部不能使用 arguments伪数组获取传递进来的实参
箭头函数适用范围
1.适合与this无关的回调,例如定时器、数组的方法回调
2.不适合与this有关的回调,例如事件的回调、对象的方法

-函数形参的初始值

  • 在ES6中允许在函数声明时,为形参赋初始值
  • 初始值一般位置要靠后,不然传参时容易将其覆盖
  • 初始值可以被覆盖
// 示例代码
function add(a , b, c = 520){
	return a + b + c;
}
 console.log(add(0, 0)); // 520
 console.log(add(0, 0, 996)); // 996
  • 形参初始值与解构赋值联合使用
    function connect({ name, age,sex })
     {
      console.log(name, age, sex); // 孙悟空 18 男
    }
    connect({
      name: "孙悟空",
      age: 18,
      sex: "男"
    })

- rest参数获取函数实参

  • 在ES6之前可以通过arguments获取函数传递的实参,其返回结果是一个Object
  • 在ES6引入的rest参数获取函数传递的实参,其返回结果是一个数组,因此我们可以对返回结果调用一些数组的API操作
// 语法如下
function person(...args){
		console.log(args);	
 		// ["孙悟空", "猪八戒"]   是一个Array
}
person('孙悟空','猪八戒')
  • 一个函数如果有多个形参,那么rest参数必须放到最后,例如
// 例如
function person(a, ...args){
		console.log(args);	// ["猪八戒", "白骨精"]
}
person('孙悟空','猪八戒', '白骨精')

-扩展运算符 …

  • 在ES6中引入了扩展运算符,它可以将一个数组转换成一个用逗号分割的参数序列
  • 例如将[“猪八戒”, “白骨精” , “孙悟空”] ==> “猪八戒”, “白骨精” , “孙悟空”
  • 常通过扩展运算符进行函数传参数组合并数组克隆将伪数组(object)转换成真数组(Array)
// 数组合并
     let person1 = ["孙悟空", "猪八戒"];
     let person2 = ["唐僧", "沙僧"];
     const person3 = [...person1, ...person2];
     console.log(person3);// ["孙悟空", "猪八戒", "唐僧", "沙僧"]
// 数组克隆
	 let oldArr = [1, 2, 3];
     let newArr = [...oldArr];
     console.log(newArr);// [1, 2, 3]
// 函数传参
	 let person1 = ["孙悟空", "猪八戒"];
     function person() {
       console.log(arguments);
       //结果(Object): Arguments(2) ["孙悟空", "猪八戒", callee: ƒ, >Symbol(Symbol.iterator): ƒ]
     }
     person(...person1);
// 将伪数组转换成真数组
// 注意,因为ES6有了rest参数,所以不用对arguments进行转换
// 此处只是举例
 	 let person1 = ["孙悟空", "猪八戒"];
     function person() {
       console.log(arguments);  // 接收到的是一个伪数组
       let arr = [...arguments];
       console.log(arr); // 结果(Array): ["孙悟空", "猪八戒"]
     }
     person(...person1);

-Symbol的基本使用

  • Symbol是ES6新引进的一种原始数据类型, 用来解决命名冲突,表示独一无二的值,是JavaScript的第种数据类型(前六种: String Number Boolean Null Undefined Object),Symbol类似于字符串
  • Symbol的特点:
    1.值唯一
    2.不能与其它数据进行运算(+ - * /)
    3. 通过Symbol定义的对象属性不能通过for…in来遍历,只能通过Reflect.ownKeys来获取该对象的所有键名
  • Symbol的创建方式(Symbol括号内相当于标识符)
	1.通过Symbol( )创建 
 // 该方式创建的对象是唯一的  
   console.log(Symbol('str') === Symbol('str'));// false
	2.通过Symbol.for( )
// 这种创建的对象是同一个
   console.log(Symbol.for('str') === Symbol.for('str')); // true
  • Symbol的应用场景
    为对象添加属性时,使用Symbol(‘属性名’)可以避免该对象中存在同名属性而造成覆盖
      let person = {
       name: "孙悟空",
       age: 18
     }
     // 声明一个对象
     let property = {
      name: Symbol(),
       age: Symbol()
     }
     // 声明方式一
     // 向person对象中添加属性  
     person[property.name] = "猪八戒";
     person[property.age] = "20";
     console.log(person);
     结果: {name: "孙悟空", age: 18, Symbol(): "猪八戒", Symbol(): "20"}
     
     // 声明方式二
       let xiyouji = {
       name: "西游记",
       [Symbol('say')]: function() {
         console.log("我是西游记");
       }
     }
     console.log(xiyouji);
     结果:{name: "西游记", Symbol(say): ƒ}
			name: "西游记"
			Symbol(say): ƒ ()
			__proto__: Object

-Symbol的内置属性

  • Symbol.hasInstanceof 用于判断某个对象是否为某构造器的实例对象,并可通过一个形参来接收被判断的实例对象
class Person {
 static [Symbol.hasInstance](param) {
 	console.log(param);
   	console.log("我被用于检测类型")
 }
} 
console.log([] instanceof Person );
  • Symbol.isConcatSpreadable 用于控制某对象使用concat( )方法时是否可展开, 它的值是一个布尔值
     let arr1 = [1, 2, 3];
     let arr2 = [4, 5, 6];
     let newArr = arr1.concat(arr2);
     console.log(newArr);//[1, 2, 3, 4, 5, 6]
     arr2[Symbol.isConcatSpreadable] = false; // 设置arr2不可展开
     newArr = arr1.concat(arr2);
     console.log(newArr);// [1, 2, 3, Array(3)]

更多参见下表更多可参加下表在这里插入图片描述

-迭代器(Iterator)

  • 迭代器是一种接口,为各种不同的数据结构提供统一的访问机制。
  • ES6创建了一种新的遍历方式 for…of循环,iterator接口主要就是供for…of循环使用
  • 原生具备iterator接口的数据:
    1.Array
    2.Arguments
    3.Set
    4.Map
    5.String
    6.TyppedArray
    7.NodeList
	// for...of遍历数组   遍历得到的是每一项的值
      let arr = ["孙悟空", "猪八戒", "白骨精"];
    for (var v of arr) {
      console.log(v); // 孙悟空  猪八戒  白骨精
    }
    
    // for...in遍历  遍历得到的是数值下标
    for (var v of arr) {
      console.log(v); // 0 1 2
    }
  • 迭代器原理:
  1. 创建一个指针对象,指向当前数据结构的起始位置
  2. 第一次调用next方法的时候,指针会自动指向数据结构的第一个成员
// next方法在数据结构里Symbol.iterator()的返回中
    //arr[Symbol.iterator]返回的是一个函数属性,需要调用
    let iterator = arr[Symbol.iterator]( ) ;
    console.log(iterator);// Array Iterator { }
  • 接下来每调用一次next方法指针都会指向数据结构的下一个成员,直到指向最后一个成员
 	 let iterator = arr[Symbol.iterator]();
	 console.log(iterator.next()); // {value: "孙悟空", done: false}
  • 每次调用都会返回一个对象,里面包含了value和done两个属性,value是当前指向的数据结构成员,done是表示当前遍历是否完成的一个状态,为true时结束遍历。
    注意: 因此当需要自定义遍历数据结构的时候得想到使用迭代器

-自定义数据迭代

    // 创建一个对象
    let banji = {
      name: "我们不一班",
      students: ["孙悟空", "猪八戒", "二郎神", "唐僧", "沙和尚"],
      
      // 定义Symbol.iterator方法
      [Symbol.iterator]() {
        // 创建一个索引
        let index = 0;
        // 保存this指向
        let _this = this;
        return {
          // 在Symbol.iterator内存在一个next方法,将其返回
          next: function() {
            if (index < _this.students.length) {
              // 每次迭代返回的结果都是一个包含value和done两个属性的对象,因此注意格式
              const result = {value: _this.students[index], done: false  };
              // 同时索引自增
              index++;
              // 返回结果
              return result;
            } else {
              // 进入这里说明已经遍历完了
             return {  value: undefined,  done: true };
            }
          }
        };
      }
    }

-生成器(generator )

生成器是一个特殊的函数,它的返回是一个迭代器,声明方法是在 function 关键字和函数名之间放一个星号( * )来表示,并能使用新的 yield 关键字,相当于函数代码的分隔符

   // 定义一个生成器
   function* generator() {
     	yield "孙悟空";
        yield "猪八戒";
        yield "沙和尚";
        yield "唐僧";
   }
   // 执行生成器,并接收返回的迭代器
   let iterator = generator()
   // 调用迭代器的next()方法执行生成器内语句,返回的是一个包含value和done的对象
   console.log(iterator.next().value); // 孙悟空
   console.log(iterator.next().value); // 猪八戒
   console.log(iterator.next().value); // 沙和尚
   console.log(iterator.next().value); // 唐僧
   console.log(iterator.next().value); // undefined
  • 由于生成器(generator)返回的是一个迭代器,因此可以使用for…of循环遍历迭代器
   // 执行生成器,并接收返回的迭代器
   let iterator = generator()
   // 使用for...of遍历
   for (let v of iterator) {
     console.log(v);// 孙悟空 猪八戒 沙和尚 唐僧
   }

-生成器函数的参数传递

  • next方法可以传入实参,该参数是作为上一个yield语句的返回结果
      // 定义一个生成器
   function* generator(args) {
     console.log(args);
     let one = yield "孙悟空";
     console.log(one);
     let two = yield "猪八戒";
     console.log(two);
     let three = yield "沙和尚";
     console.log(three);
     let four = yield "唐僧";
     console.log(four);
   }
   // 执行生成器获取迭代器对象
   // 生成器函数可以传入参数
   let iterator = generator("111");  // 可以整体传参  111
   // next方法可以传入实参,该参数是作为上一个yield语句的返回结果   
   console.log(iterator.next().value); //  孙悟空 222
   console.log(iterator.next("222").value); //  猪八戒 333
   console.log(iterator.next("333").value); //  沙和尚 444
   console.log(iterator.next("444").value); //  唐僧

-Promise

  • Promise是ES6新引进的解决异步编程的一种方案,Promise是一个构造函数,专门用来封装异步操作,并接收其运行成功或者失败的结果
  • Promise可以避免异步操作多层嵌套的问题,即回调地狱通过对对象调then方法拿到成功或失败的数据,然后在Promise对象外部进行接下来的操作,从而避免了多层嵌套
  • Promise有三种状态, 这三种状态的切换只能是pending转换为其它两种,具有不可逆性:
    1.pending: 待处理的
    2.resolved: 执行完成,允许继续向下执行
    3.rejected: 执行失败,其结果并不是我们想要的,拒绝向下执行
  • Promise的执行结果可以通过then( )方法来接收,需要传入两个回调,第一个作为Promise的状态为resolved(即成功)的回调,第二个函数作为Promise状态为rejected的回调,第二个回调一般不用,捕获异常通常使用catch( )方法来捕获
 // 创建一个Promise实例对象,传入一个回调,该回调中可以接收两个参数resolved
      和rejected
       let p = new Promise(function(resolved, rejected) {
 // 执行一个异步操作
       setTimeout(function() {
         // let SucceedInfo = "得到需要的结果";
         // resolved(SucceedInfo);
         let errorInfo = "该结果不想要";
         rejected(errorInfo);
       }, 1000)
     })
 // 调用Promise对象的then方法获得返回信息
 // then方法传入两个回调,第一个接收Promise对象中执行得到满意结果(即>resolved)的信息,第二个接收rejected的信息
     p.then(function(value) {
       console.log(value); // 得到需要的结果
     }, function(rejected) {
       console.log(rejected); // 该结果不想要
     })
 // 通过catch( )捕获异常
      p.then(function(value) {
       console.log(value); // 得到需要的结果
     }).catch()				// Uncaught (in promise) 该结果不想要

-Promise静态方法

  • Promise.reject(reason)
    通俗理解:创建一个立即拒绝的promise
    官方解释:返回一个状态为已拒绝的 Promise 对象,并将给定的失败信息传递给对应的处理函数。
  • Promise.resolve(value)
    通俗理解:创建一个立即完成的promise
  • Promise.all(iterable)
    通俗理解:同时返回多个promise执行的结果,有一个错误就返回错误
    官方解释:当所有的 promise 对象都成功或有任意一个 promise 失败,这个方法就会返回一个新的 promise 对象。
    如果所有的 promise 都成功了,它会把一个包含 iterable 里所有 promise 返回值的数组作为成功回调的返回值。顺序跟 iterable 的顺序保持一致。
    一旦有任意一个 iterable 里面的 promise 对象失败则立即以该 promise 对象失败的理由来拒绝这个新的 promise。
  • Promise.allSettled(iterable)
    通俗理解:无论执行成功或失败,都会返回一个对象数组,其中对象对应每个promise的执行结果
    官方解释:等到所有 promise 都已敲定(每个 promise 都已兑现或已拒绝)。返回一个 promise,该 promise 在所有 promise 都敲定后完成,并兑现一个对象数组,其中的对象对应每个 promise 的结果。
  • Promise.any(iterable)
    通俗理解:返回执行最快的且执行成功的那个promise对象的值
    官方解释:接收一个 promise 对象的集合,当其中的任意一个 promise 成功,就返回那个成功的 promise 的值,只有全部的promise对象都执行错误才会抛出错误。
  • Promise.race(iterable)
    通俗理解:返回执行最快的那个promise对象,无论对错
    官方解释:等到任意一个 promise 的状态变为已敲定。
    当 iterable 参数里的任意一个子 promise 成功或失败后,父 promise 马上也会用子 promise 的成功返回值或失败详情作为参数调用父 promise 绑定的相应处理函数,并返回该 promise 对象。

-Promise实例

  • Promise读取文件
// 引入fs模块
const fs = require('fs');

// 普通方法读取文件
// fs.readFile(('./为学.md'), (err, data) => {
//   // 如果读取错误则抛出错误
//   if (err) throw err;
//   // 成功则输出文件
//   console.log(data.toString());
// });

// 使用Promise封装
const p = new Promise(function(resolved, rejected) {
 // 读取文件,返回结果是一个Buffer(缓存数据)
 fs.readFile(("./为学.md"), (err, data) => {
   // 如果读取失败
   if (err) rejected(err);
   // 如果读取成功
   resolved(data);
 })
});
// 通过then方法获取Promise对象运行结果
p.then(function(value) {
 console.log(value.toString());
}).catch()
  • Promise封装AJAX
      // 接口地址: https://api.apiopen.top/api/sentences

      const p = new Promise(function(resolved, rejected) {
        // 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) {
            // 判断响应状态码  200-299
            if (xhr.status >= 200 && xhr.status < 300) {
             // 成功 打印结果
              resolved(xhr.response);
            } else {
              // 失败
              rejected(xhr.status);
            }
          }
        }
      })

      // 指定回调
      p.then(function(value) {
        console.log(value);
      }).catch()

-Promise的then方法的返回值

  • 调用then方法返回的也是一个Promise对象,里面有两个参数PromiseState(执行状态),PromiseResult(返回值)
  • then方法的返回值取决与其内部回调函数的返回值
    1.如果内部回调函数执行结果返回的是一个非Promise对象
    则then方法返回的Promise对象中PromiseState对应的值是fulfilled,PromiseResult的值就是rejected中的值
    2.如果内部回调执行结果返回的是Promise对象,则then方法的返回值取决于内部回调返回的Promise对象(假设命名为A)的执行结果
    2.1 若A内部执行成功(即调用resolved),PromiseState就是fulfilled,而PromiseResult的值就是resolved内的值
    2.2 若A内部调用了rejected方法,则PromiseState就是rejected,而PromiseResult的值就是rejected内的值

-then方法的链式调用

  • 可以通过then方法内部回调返回一个Promise对象的特性来完成then方法的链式调用
// 引入fs模块
const fs = require('fs');

// Promise读取多个文件(此处读取3个)
const p = new Promise((resolved, rejected) => {
 // 读取文件
 fs.readFile('./为学.md', (err, data) => {
   resolved(data);
 })
})

// 调用then方法获取数据
// 为了实现不断通过then方法对多个文件进行链式调用获取里层的值,应该在then方法>的回调里返回一个Promise对象
p.then(value => {
 // 返回一个Promise
 return new Promise((resolved, rejected) => {
   // 读取为学2文件
   fs.readFile('./为学2.md', (err, data) => {
     // 将为学2的数据和为学的封装成数组返回
     resolved([value, data])
   })
 })
}).then(value => { //此时then方法返回的value的值就是为学和为学2的一个数组
 return new Promise((resolved, rejected) => {
   fs.readFile('./为学3.md', (err, data) => {
     // 将为学3的数据push到数组返回
     value.push(data);
     resolved(value);// 此时返回的value就是我们想要的结果
   })
 })
}).then(value => {// 通过then方法接收内部返回的最终结果
 console.log(value.toString());
})

-Set(集合)

  • Set是ES6新增的一种数据结构,可通过new关键字来实例化一个Set对象,在Set中,成员的key都是唯一的,因此Set内部没有重复的元素
  • Set内部具有iterator接口,因此对Set类型的对象可以使用扩展运算符(…)和for…of遍历
  • Set的属性
    1.Set.prototype.constructor : 指向Set构造函数本身
    2.Set.size: 返回Set实例对象中的成员个数
  • Set的操作方法
    1.add( ):向Set对象中添加
    2.delete( ):删除Set对象中某个值,返回一个布尔值
    3.has( ):用于判断Set中是否包含某个成员,返回一个布尔值
    4.clear( ):清除所有成员
  • Set的遍历方法
    1.keys():返回建名的遍历器;
    2.values():返回建值的遍历器;
    3.entries():返回建值对的遍历器;
    4.forEach():使用回调函数遍历每个成员;
  • Set基本用法实例
      // Set数组去重
     let arr1 = [1, 2, 3, 4, 5, 4, 3, 2, 1];
     let arr2 = [...new Set(arr1)];
     console.log(arr2); // [1, 2, 3, 4, 5]

     // 求交集(arr1和arr3)-- 利用数组的过滤器方法
     let arr3 = [1, 2, 3, 7, 8, 9];
     let result = [...new Set(arr1)].filter(item => new Set(arr3).has(item));
     console.log(result); // [1, 2, 3]

     // 求并集(arr1和arr3)
     let unionSet = [...new Set([...new Set(arr1), ...new Set(arr3)])];
     console.log(unionSet); // [1, 2, 3, 4, 5, 7, 8, 9]

     // 求差集(求arr1和arr3的差集)-- 要看谁和谁求差集,谁是主体会影响最终结果
     let chaSet = [...new Set(arr1)].filter(item => !new Set(arr3).has(item));
     console.log(chaSet);[4, 5]

-Map数据结构

  • 在ES6中新增了Map数据结构,它类似于一个对象,也是一个键值对的集合。但是Map的键没有限值,可以是任何值,包括是一个对象
  • Map数据结构中也提供了iterator接口,因此它可以使用扩展运算符和for…of遍历
  • Map的属性和方法
    1.size : 返回map中的元素个数
    2.set : 新增一个元素并返回当前map对象
    3.delete: 删除指定键名的元素
    4.get: 返回键名对应的值
    5.has: 检测map中是否包含某个元素(包含布尔值)并返回一个布尔值
    6.clear: 清空map中所有元素,返回undefined
  • 代码示例
      // 声明一个Map实例
      let m = new Map();
      // 添加
      m.set('键', '值');
      m.set('函数', function() {});
      console.log(m); //  {"键" => "值", "函数" => ƒ}
      // 删除
      m.delete('键');
      console.log(m); // {"函数" => ƒ}
      // 获取
      m.get('函数');
      console.log(m); // {"函数" => ƒ}
      // 检测
      console.log(m.has('函数')); // true
      // 个数
      console.log(m.size); // 1
      // 清空
      console.log(m.clear()); // undefined

-Class类

  • ES6提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。基本上,ES6的class可以看作只是一个语法糖,它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。
  • 构造函数使用constructor关键字来声明,构造函数可以省略,默认的构造函数会自动生成
  • 静态属性和静态方法: 只在类本身,不会被实例对象继承,只有父类本身和继承该父类的子类对象才可以使用父类静态方法
  • 子类可以重写父类方法,可以在子类中通过书写与父类同名的方法实现重写
  • 类的继承,我们通过extends关键字来声明一个类继承自另一个类
  • 可以通过super( ) 方法在子类中调用父类的构造函数,注意如果子类有任何自己的初始化内容需要完成,它也必须先使用 super() 来调用父类的构造函数,并传递父类构造函数期望的任何参数。
  • 在类中我们可以通过**#属性名**的方式定义一个私有属性或者私有方法
      // 父类
     class Person {
       // 静态属性和静态方法,只在类本身,不会被实例对象继承,只有父类>本身和继承该父类的子类对象才可以使用父类静态方法
       static name = "猪";
       static print() {
         console.log("Static");
       }
       // 构造函数,固定写法
       constructor(name, age) {
         this.name = name;
         this.age = age
       }
       // 方法
       call() {
         console.log("hello");
       }
     }
     // 创建一个实例对象
     let p = new Person("fc", 21);
     Person.print() // 类对象本身可以使用静态方法方法
     p.call()
     console.log(p);

     // 创建一个子类
     class Students extends Person {
       constructor(name, age, id, sex) {
         // 调用父类的构造函数
         super(name, age); // 相当于 Person.call(this,name,age)
         this.id = id;
         this.sex = sex;
       }
     }

     // 创建一个子类实例
     let s = new Students("ly", 21, 928, "女");
     Students.print()
     console.log(s);

-Class类gettr和setter运用

-getter

有时需要允许访问返回动态计算值的属性,或者你可能需要反映内部变量的状态,而不需要使用显式方法调用,此时就可以使用getter

  • 可以通过get语法将对象属性绑定到查询该属性时将被调用的函数
  • 在类中通过get关键字添加的属性是被定义在实例的原型上的
  • 在该属性被查询时,会自动执行该属性绑定的函数,同时会输出该函数的返回值
  • 使用get语法注意事项:
    1.可以使用数值或字符串作为标识
    2.必须不带参数
    3.它不能与另一个 get 或具有相同属性的数据条目同时出现在一个对象字面量中(不允许使用 { get x() { }, get x() { } } 和 { x: …, get x() { } })
    4.可通过delete操作符删除getter
    5.可通过对象名.defineProperty( )的方式在现有对象上定义getter,但此时定义的属性将在实例自身

-setter

  • 当尝试设置属性时,set 语法将对象属性绑定到要调用的函数。可以在类中应用。
  • 语法:set prop(val) { /* … */ }
    参数说明: prop 要绑定到给定函数的属性名; val 用于保存尝试分配给prop的值的变量的一个别名
  • 使用set语法注意事项
    1.它的标识符可以是数字或字符串
    2.它必须一个明确的参数
    3.在对象字面量中,不能为一个已有真实值的变量使用 set,也不能为一个属性设置多个 set。 ( { set x(v) { }, set x(v) { } } 和 { x: …, set x(v) { } } 是不允许的 )
    4.set定义的属性名是伪属性(未定义的),单纯访问它时会返回undefined
    5.可以使用delete关键字移除一个setter
    6.可通过对象名.defineProperty( )的方式在现有对象上定义setter

-数值扩展

  // Number.EPSILON是 JavaScript的最小精度,属性的值接近于 >2.22044...E-16
  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))  //false
  console.log(equal(0.1+0.2,0.3))  //true

  //二进制和八进制
  let b = 0b1010; //2进制
  let o = 0o777;  //8进制
  let d = 100;    //10进制
  let x = 0xff;   //16进制
  console.log(x)   //255

  //检测一个数是否为有限数
  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

  //字符串转整数
  console.log(Number.parseInt('5213123love')); //5213123
  console.log(Number.parseFloat('5.123123神器')); //5.123123

  //判断是否为整数
  console.log(Number.isInteger(5));  //true
  console.log(Number.isInteger(2.5)); //false
  
  //将小数部分抹除
  console.log(Math.trunc(3.45345345345)) //3

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

-对象方法扩展

  • Object.create() 方法用于创建一个新对象,使用现有的对象来作为新创建对象的原型(prototype)
  • Object.is 判断两个值是否完全相等
    可以判断NaN和NaN相等,会返回true,这点全等===做不到
  • Object.assign 对象的合并
  • Object.setPrototypeOf 设置原型对象 (不建议,Object.create()更高效)
  • Object.getPrototypeof读取原型对象
   //1.Object.is 判断两个值是否完全相等
   console.log(Object.is(120,120))  //true
	console.log(Object.is(NaN,NaN))  //false

   //2.Object.assign 对象的合并
   const a = {
       name:'ran',
       age:12
   }
   const b = {
       pass:'i love you'
   }
   console.log(Object.assign(a,b))   //{name:'ran',age:'12',pass:'i love you'}

   //3.Object.setPrototypeOf 设置原型对象 Object.getPrototypeof
   const school = {
       name:'尚硅谷'
   }
   const cities = {
       xiaoqu:['北京','上海']
   }
   Object.setPrototypeOf(school,cities)
   console.log(Object.getPrototypeOf(school))  //{xiaoqu: Array(2)}
   console.log(school)  //{name: "尚硅谷"}

-模块化

  • 模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来
  • 模块化的好处:防止命名冲突、代码复用、高维护性
  • 模块功能主要有两个命令构成:export和inport
    1.export命令用于规定模块的对外接口
    2.inport命令用于输入其他模块提供的功能
  • 暴露语法
//统一暴露
function method(){
   console.log('我是统一暴露');
}
export {school,findjob}

//默认暴露
export default {
   change:function(){
       console.log('我是默认暴露')
   }
}
  • 引入方法
// 通用导入
import * as m1 from "./src/js/m1.js"
import * as m2 from "./src/js/m2.js"
import * as m3 from "./src/js/m3.js"

// 解构赋值方式导入
import {school,teach} from "./src/js/m1.js"
import {school as guigu,findJob} from "./src/js/m2.js"
import {default as m3 } from "./src/js/m3.js"

// 针对默认暴露的简便引入写法
import m3 from "./src/js/m3.js"
  • 模块引入方式二
    为了避免不断在script标签中引入过多模块导致代码变得冗余时,我们可以专门创建一个js文件来引入所以模块,然后只在script标签中引入这一个js文件即可实现引入大量模块,且不会造成script中出现大量引入模块的语句
    语法: src=“引入了所有模块的js文件路径” type = “module”

- ES7新特性

  • 在ES7中引入了Array.prototype.includes,用来检测检测数值中是否包含某个元素,返回的值是一个boolean
  • 在ES5中可以使用indexof来检测,但是其返回值是如果存在则返回其对应坐标,如果不存在则返回-1
  • 同时在ES7中引入了操作符**,用来实现幂运算,其功能和Math.pow( )相同

-ES8新特性

- Promise的async和await

1.async 函数是使用async关键字声明的函数。async 函数是 AsyncFunction 构造函数的实例,并且其中允许使用 await 关键字。async 和 await 关键字让我们可以用一种更简洁的方式写出基于 Promise 的异步行为,而无需刻意地链式调用 promise。
2.async函数的返回值是一个promise对象(即使在函数内部返回的不是一个promise,也会被包装成promise),这个 promise 要么会通过一个由 async 函数返回的值被解决,要么会通过一个从 async 函数中抛出的(或其中没有被捕获到的)异常被拒绝。
3.await关键字只在 async 函数内有效。如果你在 async 函数体之外使用它,就会抛出语法错误 SyntaxError 。
4.async/await的目的为了简化使用基于 promise 的 API 时所需的语法。async/await 的行为就好像搭配使用了生成器和 promise。
5.使用async和await后函数体内需要通过try{ }.catch(e){ }的方式捕获异常
6.在async的函数内当我们使用await调用函数后,当前函数后边的所有代码会在当前函数执行完毕后,被放入到微任务队列中

  • 使用async函数实例
异步读取文件
// 引入fs模块
let fs = require('fs');

// 读取为学1
function read1() {
 return new Promise((resolve, reject) => {
   fs.readFile('./为学.md', (err, data) => {
     // 如果读取错误则抛出
     if (err) throw err;
     // 成功
     resolve(data);
   })
 })
}
// 读取为学2
function read2() {
 return new Promise((resolve, reject) => {
   fs.readFile('./为学2.md', (err, data) => {
     if (err) throw err;
     resolve(data)
   })
 })
}
// 读取为学3
function read3() {
 return new Promise((resolve, reject) => {
   fs.readFile('./为学3.md', (err, data) => {
     if (err) throw err;
     resolve(data)
   })
 })
}


async function main() {
 let data1 = await read1();
 let data2 = await read2();
 let data3 = await read3();


 let arr = [data1, data2, data3];
 console.log(arr.join("\r\n").toString());
}

main()

// 封装AJAX请求函数
    function sendAJAX(url) {
       return new Promise((resolve, reject) => {
         // 创建请求实例
         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)
             }
           }
         }
       })
     }

     /*      // 通过then方法测试
           sendAJAX("https://api.apiopen.top/api/sentences").then((value) => >{
             console.log(value);
          }).catch() */

     // async异步操作测试
     async function main() {
       let value = await sendAJAX("https://api.apiopen.top/api/sentences")
       console.log(value);
     }
     main()

-ES8对象方法扩展

  • 引入了kews、values、emtries、getOwnPropertyDescriptor等方法
   const school = {
       name:'尚硅谷',
       cities:['北京','上海','深圳'],
       xueke:['前端','Java','大数据','运维']
   };

   //获取对象所有的键
   console.log(Object.keys(school));

   //获取对象所有的值
   console.log(Object.values(school));

   //entries,用来创建map
   console.log(Object.entries(school));
   console.log(new Map(Object.entries(school)))

   //对象属性的描述对象
   console.log(Object.getOwnPropertyDescriptor(school))
   
   const obj = Object.create(null,{
       name:{
           value:'尚硅谷',
           //属性特性
           writable:true,
           configurable:true,
           enumerable:true,
       }
})

-ES9 rest参数和展开运算符

  • 在ES9中rest参数和展开运算符已经可以在对象中使用
   function connect({host,port,...user}){
       console.log(host);
       console.log(port);
       console.log(user)
   }
   connect({
       host:'127.0.0.1',
       port:3306,
       username:'root',
       password:'root',
       type:'master'
   })  //127.0.0.1  3306  {username: "root", password: "root", type: "master"}
   const AA={
       username:'ran'
   }
   const BB={
       password:'lyyrhf'
   }
   const CC={
       job:'Java'
   }
   const D={...AA,...BB,...CC};
   console.log(D) //{username: "ran", password: "lyyrhf", job: "Java"}

-ES10

  • 对象扩展方法
  //二维数组
     const arr = [
       ['name', 'FC'],
       ['age', '21', '22']
     ]
     let res = Object.fromEntries(arr);
     console.log(res); //	{name: "FC", age: "21"}

  //Map
     const m = new Map();
     m.set('name', 'FC');
     const result = Object.fromEntries(m);
     console.log(result); // {name: "FC"}
  • 字符串扩展方法
  let str= '       asdsadsaads       '
  console.log(str) //       asdsadsaads       
  console.log(str.trimStart()) //asdsadsaads       清空左侧空格
  console.log(str.trimEnd()) //       asd  清空右侧空格
  • 数组方法扩展
    const arr = [1,2,3,[4,5,6,[7,8,9]]]
   //参数为深度,是一个数字
    console.log(arr.flat(2)) //[1,2,3,4,5,6,7,8,9]

	const arr2=[1,2,3,4]
    const result = arr2.flatmap(item => [item * 10]); 
    //如果map的结果是一个多>维数组可以进行flat 是两个操作的结合
  • Symbol.prototype.description
let s1 = Symbol('尚硅谷');
console.log(s1.description) //尚硅谷

-ES11

  • 对象私有属性扩展
    可以通过在属性前加一个#的方式为对象设置私有属性
  • Promise.allSettled方法
   //声明两个promise对象
   const p1 = new Promise((resolve, reject) => {
       setTimeout(()=>{
           resolve('商品数据-1')
       },1000)
   })

   const p2 = new Promise((resolve, reject) => {
       setTimeout(()=>{
           reject('出错了!')
       },1000)
   })

   //调用allsettled方法:返回的结果始终是一个成功的,并且异步任务的结果>和状态都存在
   const res = Promise.allSettled([p1,p2]);
   console.log(res)

   // Promise {<pending>}
   //     __proto__: Promise
   //     [[PromiseState]]: "fulfilled"
   //     [[PromiseResult]]: Array(2)

   //调用all方法:返回的结果是按照p1、p2的状态来的,如果都成功,则成>功,如果一个失败,则失败,失败的结果是失败的Promise的结果
   const result = Promise.all([p1,p2])
   console.log(result)
  • 可选链操作符(?.)
//相当于一个判断符,如果前面的有,就进入下一层级
function main(config){
   const dbHost = config?.db?.host
   console.log(dbHost) //192.168.1.100
}

main({
   db:{
       host:'192.168.1.100',
       username:'root'
   },
   cache:{
   	host:'192.168.1.200',
   	username:'admin'
	}
})
  • import的动态引入
btn.onclick = function(){
   //使用之前并未引入,动态引入,返回的其实是一个Promise对象
   import('./hello.js').then(module=>{
       module.hello();
   })
}
  • BinInt类型
//大整型
let n = 521n;
console.log(n,typeof(n))  // 521n  n 

//函数
let n = 123;
console.log(BigInt(n)) // 123n  //不要使用浮点型,只能用int

//大数值运算
let max = Number.MAX_SAFE_INTEGER; // 9007199254740991
console.log(max +1) // 9007199254740992
console.log(max +2) // 9007199254740992 出问题了
console.log(BigInt(max)+BigInt(1)) 9007199254740992n
console.log(BigInt(max)+BigInt(2)) 9007199254740993n
  • 绝对全局对象globalThis
 //适用于复杂环境下直接操作window
console.log(globalThis) //window
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值