ES6 & ESNext 规范及编译工具简介
- 1、历史简介
- 2、变量定义新形式(let、const)
- 
- [2.1 let](#2.1 let)
- [2.2 const](#2.2 const)
- [2.3 实际开发中的使用](#2.3 实际开发中的使用)
 
- 3、解构语法
- 
- [3.1 数组解构](#3.1 数组解构)
- [3.2 对象解构](#3.2 对象解构)
- [3.3 嵌套解构](#3.3 嵌套解构)
- [3.4 默认值](#3.4 默认值)
 
- 4、模板字符串
- [5、 箭头函数](#5、 箭头函数)
- 6、ES6新增的数组方法
- 7、Set和Map
- 
- [7.1 Set](#7.1 Set)
- [7.2 Map](#7.2 Map)
 
- [8、面向对象编程------class 语法](#8、面向对象编程——class 语法)
- 
- [8.1 类、构造函数](#8.1 类、构造函数)
- [8.2 继承](#8.2 继承)
- [8.3 静态方法和属性](#8.3 静态方法和属性)
- [8.4 getter 和 setter](#8.4 getter 和 setter)
 
- [9、生成器 generator](#9、生成器 generator)
- [10、异步处理------callback、Promise、async & await](#10、异步处理——callback、Promise、async & await)
1、历史简介
ECMAScript:一种标准(ECMA-262)
JavaScript:一种语言
ES5:2011发布,第五个版本
ES6:2015发布的,第六个版本,大型变动 break change
ESNext:符合现在主流ES的预案,有几个阶段(大于1的就是属于ESNext)
阶段:
Stage 0:开工
Stage 1:收录意见
Stage 2:草案
3:候选者(基本要准备发布)
4:定案
2、变量定义新形式(let、const)
Q: var 定义变量有什么问题?
- 变量提升
- 无法形成词法作用域
- 可以随意篡改变量值,重复声明
2.1 let
let 关键字用于声明一个块级作用域的局部变量,可以将 let 声明的变量重新赋值。let 声明的变量只在代码块内部有效。
            
            
              javascript
              
              
            
          
          if (true) {
    let i = 1;
    console.log(i); // 输出 1
}
console.log(i); // 报错,i 未定义
console.log(a); // undefind(变量提升)
var a=2;
console.log(b); //报错,暂时性死区,let在下面定义了
let b=2死区
            
            
              javascript
              
              
            
          
          function bar(x=y,y=2){
    return [x,y]
}
bar()
//报错,y死区(运行时报错)
function bar(x=2,y=x){
    return [x,y]
}
bar()
//正常执行不允许重复声明
            
            
              javascript
              
              
            
          
          var a=2;
let a=1;
//报错2.2 const
const 关键字用于声明一个块级作用域的只读常量,一旦 const 声明了某个变量,就不能使用赋值语句改变它的值。常量必须在声明时进行初始化。
            
            
              javascript
              
              
            
          
          const PI = 3.1415926535;
PI = 3; // 报错,无法修改常量
const obj={}//具体引用的地址不能变
obj.a=1//不报错
obj=1//报错ES5里没有块级作用域
            
            
              javascript
              
              
            
          
          //ES6写法
if(true){
   function fn(){
   }
}
//ES5写法
if(true){
 var fn = function(){
   }
}2.3 实际开发中的使用
- 示例一:循环中使用 let 声明变量避免问题
            
            
              javascript
              
              
            
          
          for (let i = 0; i < 5; i++) {
    setTimeout(function() {
        console.log(i); // 0, 1, 2, 3, 4
    }, 1000);
}使用 let 声明的变量 i 有块级作用域,在每一次循环中都会重新定义并赋值,避免了使用 var 声明变量可能导致的变量共享问题。
- 示例二:使用 const 声明常量
            
            
              javascript
              
              
            
          
          const PI = 3.1415926;
const URL = "https://www.example.com";使用 const 声明常量可以防止被修改,保证代码的可靠性和稳定性。
- 示例三:使用 const 声明对象属性避免误修改
            
            
              javascript
              
              
            
          
          const user = {
    name: "张三",
    age: 18,
    gender: "男"
};
user.name = "李四";
console.log(user); // { name: "李四", age: 18, gender: "男" }
Object.freeze(user);
user.age = 20;
console.log(user); // { name: "李四", age: 18, gender: "男" }使用 const 声明对象属性可以避免误修改,同时使用 Object.freeze() 方法可以将对象冻结,防止意外修改对象属性。
总的来说,使用 let 或者 const 声明变量可以解决一些以往使用 var
变量定义存在的问题,例如变量作用域混乱,变量共享、变量易被修改等情况。使用 let 和 const
可以使代码更加健壮、可维护,提升开发效率和代码质量。
3、解构语法
定义:将数组或对象中的元素提取出来并赋值给变量
3.1 数组解构
            
            
              javascript
              
              
            
          
          const [a, b, c] = [1, 2, 3];
console.log(a, b, c); // 1 2 3在这个例子中,JavaScript 引擎背后发生的事情如下:
            
            
              javascript
              
              
            
          
          const tempArray = [1, 2, 3];
const a = tempArray[0];
const b = tempArray[1];
const c = tempArray[2];
console.log(a, b, c); // 1 2 3
            
            
              javascript
              
              
            
          
          let [a, ...rest] = [1, 2, 3];
console.log(a, rest); // 1 [2,3]
[x,y,,z]=[1,2,3,4]
console.log(x,y,z); // 1,2,43.2 对象解构
            
            
              javascript
              
              
            
          
          const {firstname: first, lastname: last, ...rest} = { firstname: 'John', lastname: 'Doe' };
console.log(first, last); // John Doe
let obj={
  p:['Hello',
  {y:'World'}
  ]
}
let {
 p:[x,{y}]
}=obj
//x,y   Hello,World3.3 嵌套解构
            
            
              javascript
              
              
            
          
          const [a, [b, [c]]] = [1, [2, [3]]];
console.log(a, b, c); // 1 2 33.4 默认值
            
            
              javascript
              
              
            
          
          const [a = 1, b = 2] = [];
console.log(a, b); // 1 2
let obj={a:1,b:2,c:3}
const {a=2}=obj
//a=obj.a?obj.a:2,obj的a存在,取obj.a,不存在,取默认值2
const {a:d=2}=obj
//另外取名字  d=obj.a?obj.a:24、模板字符串
            
            
              javascript
              
              
            
          
          const name = "Tom";
const age = 20;
const str = `My name is ${name}, I'm ${age} years old.
I'm from China.`;
console.log(str);5、 箭头函数
箭头函数与普通函数有哪些不同?
- this 指向,箭头函数不能定义构造器
- 不能 new
- 内部无 arguments 对象
- this 绑定方法失效,比如:call apply bind
            
            
              javascript
              
              
            
          
          // 传统函数定义
function multiply(x, y) {
  return x * y;
}
// 箭头函数
const multiply = (x, y) => x * y;
function foo(){
   setTimeout(() => {
      console.log(`num`,this.num);//没有自己的this,这里的this是foo的this
    }, 1000);
}
var num =123
foo()//输出 num 123
//改变函数指向
foo.call({
num:456
})
foo()//输出 num 456
//看一个例子
function Timer(){
  this.s1=0;
  this.s2=0;
  //箭头函数
  setInterval(()=>this.s1++,1000);//外层函数的this,指向Timer,改变了Timer实例的s1
  //普通函数
  setInterval(function(){
    this.s2++;//function的this,没有改变Timer实例的s2
  },1000);
}
var timer =new Timer()
    setTimeout(() => {
      console.log('s1:',timer.s1)
    }, 3100);
    setTimeout(() => {
      console.log('s2:',timer.s2)
    }, 3100);
    //输出:
    //s1:3
    //s2:06、ES6新增的数组方法
ES6新增了一些数组方法,具体可以看 ES6 入门教程
Js的全部数组方法,可以看 数组方法总结+详解
如:
- Array.flat()
 Array.flat()方法创建一个新数组,其中所有子数组元素递归地连接到指定的深度。(打平数组深度)
            
            
              javascript
              
              
            
          
           const arr = [1, [2, [3, [4]]]];
console.log(arr.flat(1)); // [1, 2, [3, [4]]]
console.log(arr.flat(2)); // [1, 2, 3, [4]]
console.log(arr.flat(3)); // [1, 2, 3, 4]
console.log(arr.flat(4)); // [1, 2, 3, 4]- Array.includes()
 Array.includes()方法判断一个数组是否包含某个指定的元素,根据情况,如果包含则返回true,否则返回false。
            
            
              javascript
              
              
            
          
          const arr = [1, 2, 3, 4, 5];
console.log(arr.includes(3)); // true
console.log(arr.includes(6)); // falseArray.from()
Array.of()
Array.find()
Array.findIndex()
Array.includes()
Array.flat()
Array.flatMap()
Array.every()
Array.some()
Array.reduce()
Array.reduceRight()
Array.sort()
Array.reverse()
Array.fill()
Array.slice()
Array.splice()
Array.copyWithin()
Array.forEach()
Array.map()
Array.filter()
7、Set和Map
Set 和 Map 主要的应用场景在于 数据重组 和 数据储存。
Set 是一种叫做 集合 的数据结构,Map 是一种叫做 字典 的数据结构。
7.1 Set
- ES6 新增的一种新的数据结构,类似于数组,成员唯一(内部元素没有重复的值)。且使用键对数据排序即顺序存储。
- Set 本身是一种构造函数,用来生成 Set 数据结构。
- Set 对象允许你储存任何类型的唯一值,无论是原始值或者是对象引用
            
            
              javascript
              
              
            
          
          var s1=new Set();
var s2=new Set([1,2,3]);
//  重复元素在Set中会自动过滤(即重复元素不会被保留)
var s=new Set([1,2,3,3]);
s.add(4);  // set{1,2,3,4}
s.add(3); //set{1,2,3,4}
s.size();   //4
s.has(3);  //trueweakSet 和Set一样的用法,不过里面的值只能是Symbol或对象,垃圾回收不会考虑weakSet 和weakMap里的值,内部变量没有可达性
7.2 Map
Map是一组键值对的结构,用于解决以往不能用对象做为键的问题,具有极快的查找速度。(注:函数、对象、基本类型都可以作为键或值。)
            
            
              javascript
              
              
            
          
          const m=new map(['Kris',21],['Bob',19],['Lily',25],['Jack',27]);
m.get('Kris');   //  21
m.get('Lily');   //  25
var mm=new Map( );	//初始化一个空的 map
mm.set('Pluto',23);	//添加新的key-value 值
mm.has('Pluto');   //true	是否存在key 'Pluto'
mm.get('Pluto');   	//23
mm.delete('Pluto');	//删除key   'Pluto '
一个key只能对应一个value,所以多次对一个key放入value,后面的值会把前面的值冲掉
const m=new Map([['Lily',100],['Bob',97]]);
m.get('Bob');  //97
m.set('Bob',88);  //对key放入新的value
m.get('Bob');  //888、面向对象编程------class 语法
JavaScript 的类最终也是一种函数,JavaScript 的 class 语法只是语法糖,使用 class 关键字创建的类会被编译成一个函数,因此其底层原理与函数有一些相似之处。
JavaScript原型继承实现继承的有哪些方式(详情可以看这篇博客)
- 原型链继承
- 借用构造函数
- 组合继承
- 原型式继承
- 寄生式继承
- 寄生组合继承
Class 语法继承,最接近我们自己实现的那种继承方式?
- 寄生组合继承
8.1 类、构造函数
ES6里的类
            
            
              javascript
              
              
            
          
          class Point{
  constructor(x,y){
     this.x=x;
     this.y=y;
  }
  toString(){
     return '('+this.x+','+this.y+')'
  }
}
new Point()等价于ES5
            
            
              javascript
              
              
            
          
          var Point = /*#__PURE__*/ (function () {
  function Point(x, y) {
    this.x = x;
    this.y = y;
  }
  var _proto=Point.prototype;
  _proto.toString=function toString(){
     return '('+this.x+','+this.y+')'
  }
  return Point;
})();
new Point();8.2 继承
在 JavaScript 中,继承是通过类的 prototype 属性实现的。在定义类时,可以使用 extends 关键字来继承其他的类:
            
            
              javascript
              
              
            
          
          class Student extends Person {
    constructor(name, age, grade) {
        super(name, age);
        this.grade = grade;
    }
}8.3 静态方法和属性
类中的静态方法和属性可以使用 static 关键字来定义,它们不是类实例的属性,而是类本身的属性和方法。
            
            
              javascript
              
              
            
          
          class Person {
    static species = "human";
    static saySpecies() {
        console.log(`We are ${this.species}.`);
    }
}8.4 getter 和 setter
在类中定义 getter 和 setter 方法可以让我们封装实例的内部数据属性,使得这些属性的读写行为更加的安全和合理。
            
            
              javascript
              
              
            
          
          class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    get name() {
        return this.name.toUpperCase();
    }
    set age(age) {
        if (age > 0 && age < 120) {
            this.age = age;
        } else {
            console.log("Invalid age value.");
        }
    }
    get age() {
        return this.age;
    }
}在类的实现中,getter 和 setter 其实是被定义在构造函数的 prototype 属性上,从而可以被该类的所有实例对象访问。
9、生成器 generator
生成器为了解决什么问题?
解决了函数的不可中断性
生成器是可中断函数,yield 关键字暂时中断函数执行,在合适的实际从中断位置继续执行。
            
            
              javascript
              
              
            
          
          function* generateSequence() {
  yield 1;
  yield 2;
  yield 3;
}
const sequence = generateSequence(); // 获取生成器实例
console.log(sequence.next().value); // 输出 1
console.log(sequence.next().value); // 输出 2
console.log(sequence.next().value); // 输出 310、异步处理------callback、Promise、async & await
这个部分可以看博客:3.1、前端异步编程(超详细手写实现Promise;实现all、race、allSettled、any;async/await的使用)