为什么叫ES6?

ECMAScript是TC39(浏览器厂商:谷歌,苹果,火狐等)推出的js的版本。

es5 => 2009年

es6 => 2015年

es7 => 2016年

...

es10 => 2019年

esnext => 最新版

ES6 新特性

1.let声明变量及特性

  • 变量不能重复声明
  • 块级作用域
  • 不存在变量提升
  • 不影响作用域链

2.const声明常量

  • 必须有初始值
  • 常量不能修改
  • 块级作用域
  • 一般常量使用大写(潜规则-不是必须的)

3.解构赋值

按照一定模式从数组和对象中取值

// 解构数组
const F3 = ['a','b','c']
let [a,b,c] = F3

// 解构对象
const obj = {
	name:"张三",
	age:20,
	say(){}
}
let {name,age,say} = obj

4.模板字符串

模板字符串用 `` 表示,模板字符串中使用 ${变量} 语法替换动态变量。

let aa = '张三'
let str = `${aa}是最帅的!`

5.对象简化写法

ES6对对象进行了简化处理,写起来更简单。

let name = '张三';
let change = function(){}
// 简化写法 - 推荐
const obj = {
	name,
	change,
	fn(){}
}
// 传统写法
let obj = {
	name:name,
	change:change,
	fn:function(){}
}

6.箭头函数

简写:单个参数可以省略小括号(),单条执行语句可以省略花括号{}和return

let aa = (a,b)=>a+b;
  • 箭头函数的this始终指向函数声明时所在作用域的this

  • 不能作为构造函数

  • 不能使用argument变量

7.函数参数设置默认值

  • 形参初始值

    function (a=2){}
    

8.rest参数

rest参数 通过 ...args 获取参数的参数集合(数组格式)

function date(...args){}
date('12','333','43') // ['12','333','43']
  • rest 参数必须放到最后(多个参数)
function aaa(a,b,...args){}
aaa(1,2,3,4,5) // a:1,b:2,c:[3,4,5]

9.扩展运算符

[...]将数组转换为逗号分割的参数序列

let aa = [1,2,3]
function ccc(){
	console.log(arguments)
}
ccc(...aa) // a,b,c

扩展运算符的应用:

  • 数组合并

    let a = [1],b = [2,3]
    let c = [...a,...b]
    
  • 数组克隆

    let d = [...c]
    
  • 将伪数组转成数组

  •   const div = document.querySelectorAll('div')
      let arrr = [...div]
    

10.数据类型symbol

es6 引入了新的原始数据类型symbol。

特点:

  • Symbol值唯一
  • Symbol值不能进行运算、比较
  • Symbol定义的对象不能用for循环,但是可以用Reflect.ownKeys获取对象的所有key名。
// 创建Symbol
let s = Symbol()
let s1 = Symbol('稀罕三')
let s2 = Symbol('稀罕三')
// s1 !== s2

// 通过Symbol.for 创建
let s3 = Symbol.for('稀罕三')
let s4 = Symbol.for('稀罕三')
// s3 === s4

11.迭代器 iterator

迭代器iterator是一种接口(对象的一个属性 Symbol.iterator),数据结构只要有这个结果就可以进行遍历操作。以下:Array,Arguments,Set,Map,String,TypedArray,NodeList 都可以进行for of遍历。

工作原理:

  • 创建一个指针对象,指向当前数据结构的起始位置。
  • 第一次调用next方法,指针知道指向第一个成员。每次返回一个包含value和done属性的对象
  • 接下来每次调用next方法,指针都会一直往后移动,直到最后一个(最后一个done返回true,表示结束)。
let arrr = [1,2,3,4]
let iterator = arrr[Symbol.iterator]()
// 调用对象的next方法
console.log(iterator.next())

应用场景:自定义遍历数据

const obj = {
	name:"一班",
	students:[
		'xiaoming','xiaohong','xiaoli'
	],
    // 通过自定义迭代器实现对象数组属性可迭代
    [Symbol.iterator](){
        let index = 0;
        let that = this;
        return{
            next:function(){
                if(index < that.students.length){
                    index++;
                    return {
                        value: that.students[index],
                        done: false
                    }
                }else{
                     return {
                        value: undefined,
                        done: true
                    }
                }
            }
        }
    }
}
// 返回结果是 obj的students每次的成员
for(let v of obj){
	console.log(v)
}

12.生成器 generator

生成器是一个特殊的函数(可迭代)。在function和函数名之间使用 *,函数里面通过关键字 yield 分割迭代层次,然后通过next()方法调用。

function * gen(){
	yield '第1次';
	yield '第2次';
	yield '第3次';
}

let iteror = gen()
iteror.next(); // 第1次
iteror.next(); // 第2次
iteror.next(); // 第3次

迭代器可以传参,在调用next时执行参数。next(arg)方法可以传入实参,作为上一次的返回结果(next参数影响上次的结果)。

function * gen(arg){
	console.log(arg);
	let one = yield '第1次';
	yield '第2次';
	yield '第3次';
}
let iteror = gen('AAA')
iteror.next(); // 第1次
iteror.next('BBB'); // 第2次 one会被改成BBB ,同时返回‘第2次’

生成器实例- 解决回调地狱问题

函数调用生成器next方法,执行下一次调用,避免函数嵌套函数的情况出现

function getuser(){
	console.log(111);
    iteror.next('user'); // 函数调用生成器next方法,执行下一次调用,避免函数嵌套函数的情况出现
}
function getorder(){
	console.log(222);
    iteror.next('order'); 
}
function getGoods(){
	console.log(333);
    iteror.next('goods'); 
}

function * gen(){
    let users = yield getuser();
    let order = yield getorder();
    let goods = yield getGoods();
}
let iteror = gen()
iteror.next(); 

13.Promise

Promise是ES6引入的解决异步编程的新方法。用于解决回调地狱的问题。

Promise 函数的状态有:pending(初始化状态),fulfilled(已成功)和rejected(已失败)

let p = new Promise((resolve,reject)=>{
	// 默认状态是 pending
	try{
		resolve('成功') // resolve将状态修改为fulfilled
	}catch(e){
		reject('失败') // reject将状态修改为rejected
	}
})

// 调用promise对象的then方法
p.then(function(res){
    console.log(res);
},function(e){
    console.log(e);
})

then()方法接收2个函数,第一个函数是成功回调(resolve时触发),第二个参数是失败回调(reject时触发)。

then返回结果:返回结果是Promise对象,对象的状态由函数执行的结果决定。

  • then如果返回结果是非Promise,如:“123”,那么返回值是对象成功的值
  • 返回结果是一个Promise,then的返回值是Promise的返回值
  • 如果then抛出了错误,then的返回值就是抛出的错误值
//node 获取文件内容异步
import fs form 'fs';
let p =new Promise((resolve,reject)=>{
	fs.readFile('./1.txt',(err,data)=>{
		if(err) reject(err)
		resolve(data)
	})
})
p.then(val=>{
    console.log(val.tostring())
},err=>{
    console.error(err)
})

14.集合 Set

ES6新增的数据结构 Set集合,集合中元素不能有重复(会自动去重)。

属性方法

  • size 集合元素长度
  • add 新增元素
  • delete 删除元素
  • has 检测是否含有元素
  • clear 清空集合
let s = new Set([1,2,3,4,2]) // Set[1,2,3,4]
s.size // 4
s.add(31)
s.delete(31)
s.clear()

集合用法

  • 数组去重
    let arr = [...new Set([1,2,3,2])]
    

15.Map

ES6新增的数据结构 Map,保存数据是键值对集合。但是“键值”可以是任何类型的值(包括对象)。

Map原型也有interator接口,所以也可以使用扩展运算符和for of循环。

  • size 返回Map的元素长度
  • set 增加新元素并返回当前Map
  • get 返回键名对应的值
  • has 检测是否函数某个元素
  • delete 删除指定键值对
  • clear 清空集合
let m = new Map();
m.set('name','七娃');
m.set({name:'七娃'},function(){}) // key和value都可以是任意类型
m.get('name')
m.delete('name')
m.clear()

16.Class 类

ES6的类class就是一个语法糖,能实现ES5的类各种功能,只是看起来更像一个面向对象编程的类。这种写法更接近于传统语言(java,c)。

class 类名{
	constructor(参数){
		this.参数 = 参数
	}
	方法(){}
}

构造函数

每个类都有自己的构造函数 constructor,但是也可以省略不写。

class Phone{
	get name(){
		return 'zhangsan'
	}
	set name(){
	
	}
}

静态成员

静态成员,通过 static 关键词定义静态成员。静态成员及方法只能通过类获取,不能通过类实例化对象获取。

class Phone{
    // 静态属性
	static price = '5000'
	constructor(name){
		this.name = name
	}
    // 静态方法
    static change(){ } 
}
// 获取静态属性和方法
Phone.price
Phone.change()

类继承

通过关键字 extends 继承父类属性和方法。

class Phone{
	constructor(name){
		this.name = name
	}
	call(){
	 	console.log('打电话')
	}
}
// 子类继承
class xiaomi extends Phone{
	constructor(name,size){
		super(name)
		this.size = size
	}
	photo(){}
}

子类内方法名和父类方法名一致,就是方法重写。重写后子类方法生效,父类无效!

类的getter和seter方法

类的getter,setter方法用于监听类属性读取和改变时

class Phone{
	get name(){
		return 'zhangsan'
	}
	set name(){
	}
}

17.ES6数值扩展

Number.EPSILON-数值最小精度

Number.EPSILON属性值接近于 2.22044604...E-16 ,我们可以用它解决js精度丢失的问题。

// 0.1+0.2 !== 0.3
function equal(a,b){
	if(Math.abs(a-b) < Number.EPSILON){
		return true
	}else{
		return false
	}
}
equal(0.1+0.2,0.3) // ture

####Number.isFinite-判断是否是有限数

console.log(Number.isFinite(100)) // ture
console.log(Number.isFinite(10/3)) // false

Number.isNaN-判断数值是否是NaN

Number.isNaN(3) // false

Number.parseInt 和Number.parseFloat

Number.parseInt 和es5的parseInt 是一样(都是将字符串转成整数),就是放到了Number对象下面。

console.log(Number.parseInt('213123looosss')) // 213123 会截取到后面的字母,保留数值
console.log(Number.parseFloat('10.2looooos')) // 10.2

Number.isInteger - 判断是否是整数

Number.isInteger(3) // true

Math.truc - 抹掉小数部分

Math.trunc(3.5) //3

Math.sign - 判断数值是正数(1),负数(-1),还是0

Math.sign(100) // 1
Math.sign(-100) // -1
Math.sign(0) // 0

18.ES6对象扩展

Object.is - 判断2个值是否完全相等

  • 判断对象返回false

  • 判断的值1负1正就返回false

// NaN === NaN  false
Object.is(NaN,NaN) // true

Object.assign - 对象合并

对象合并时,如果属性重复,后面对象的属性会覆盖前面的属性。

let obj = {
	name:'zhangsn'
}
let obj1 = {
	name:'zhangsn2',
	sex:'男'
}
let obj2 = Object.assign(obj,obj1)

####Object.setPrototypeOf - 设置对象的原型对象

setPrototypeOf 方法可以更改对象的原型对象,也可以理解为,在对象原型链之间插入一个原型。

let school = {name:"hi"}
let city = {
	list:[’北京‘]
}
Object.setPrototypeOf(school,city) // school 的原型 指向了city
Object.getPrototypeOf(school) // 获取对象的原型 city

19.ES6模块化

模块化是将一个大工程文件拆分成许多小文件,然后由小文件组合起来。

模块化优点:

  • 防止命名冲突
  • 代码复用
  • 高维护

ES6之前模块化规范:

  • CommonJS => nodejs
  • AMD => requireJS
  • CMD => seaJS

ES6模块化语法

模块功能主要有export和import构成。

// m1.js 文件
export let school = "张三";
export function say(){}

使用的时候使用 import 导入。导入的时候可以用 as 取别名。

浏览器使用模块化需要在 script 上加 type="module"。

<script type="module">
	import * as m1 from "./src/m1.js";
</script>

export暴露数据的方式:

// 分别暴露
export let school = "张三";
export function say(){}
// 统一暴露
let school = "张三";
function say(){}
export { school,say}
// 默认暴露 - 使用时需要使用 .default.school 才能访问到
export default{ 
	school = "张三",
	say(){}
}

import导入数据的方式:

// 通用导入
import * as m1 from "./src/m1.js";
// 解构赋值
import { school, say} from "./src/m1.js";
import { school as school2, change} from "./src/m2.js"; // as 别名避免同名
import { default as m3} from "./src/m3.js"; // 默认暴露,可以把default直接给别名
// 针对default默认暴露,可以直接简写
import m3 from "./src/m3.js"; // 默认暴露,export default {}

使用babel对ES6模块化代码转换步骤:

    1. 安装node插件 babel-cli babel-preset-env browserify(打包工具)
    1. npx babel src/js -d dist/js
    1. 打包 npx browserify dist/js/app.js -o dist/bundle.js

这样浏览器都可以支持bundle.js这个文件了。

ES7 新特性

1.Array.includes - 是否包含某个元素

const ss = [1,"2"]
ss.includes('2') // true
ss.includes(1) // false

2.幂运算**

ES7新增** 标识幂运算

let c = 2 ** 10 // 1024
// 等效于
let d = Math.pow(2,10) // 1024

ES8 新特性

1.async 和 await

异步编程解决方案:生成器,promise,async await

async 函数的返回值是一个promise对象,promise对象的解构由async函数执行返回值决定:

  • 返回一个非promise对象,如字符串,那么async的返回promise对象的状态是成功,值是该字符串;如果抛出了异常,那么返回promise对象的状态是失败,值是异常报错。
  • 返回promise对象,结果就是promise的结果。

注意事项:

  • await 必须写在 async里面
  • await 右侧表达式 一般是promise对象
  • await 返回值是promise的成功值
  • await的返回值失败就会抛异常,需要通过 try catch 捕获异常。
// 发送ajax
function ajax(url){
	return new Promise((resolve,reject)=>{
		// 1.创建对象
		let x = new XMLHttpRequest();
		// 2.初始化
		x.open('GET',url);
		// 3.发送
		x.send();
		// 4.事件绑定
		x.onreadystatechange = function(){
			if(x.readyState === 4){
				if(x.status>= 200 && x.status <200){
					resolve(x.response)
				}else{
					reject(x.status)
				}
			}
		}
	})
}

// then 获取返回结果
ajax("http://api.tianqi.com/api").then(val=>{
    console.log(val)
},err=>{
    console.log(err)
})

// 使用await
async function main(){
   let res =  await ajax("http://api.tianqi.com/api"); // 只返回成功结果
} 
main()

2.ES8 对象方法扩展

Object.keys 和Object.values

Object.keys 获取对象key的键值集合(数组)

Object.values 获取对象value值集合(数组)

let obj = {
	name:"sss",
	age:19,
	sex:1
}
Object.keys(obj)  // ['name','age','sex']
Object.values(obj)  // ['sss',19,1]

Object.entries - 对象转成键值对的集合

Object.entries 用于创建Map,返回的是一个数组

let obj = {
	name:"sss",
	age:19,
	sex:1
}
const m = new Map(Object.entries(obj))

Object.getOwnPropertyDescriptors - 获取对象所有属性的描述

Object.getOwnPropertyDescriptors(obj) 获取对象所有属性的描述

Object.getOwnPropertyDescriptor(obj,'name') 获取对象的某个对象的属性描述

let obj = {
	name:"sss",
	age:19,
	sex:1
}
Object.getOwnPropertyDescriptors(obj)
// age:{value: 19, writable: true, enumerable: true, configurable: true}
// name:{value: 'sss', writable: true, enumerable: true, configurable: true}
// sex:{value: 1, writable: true, enumerable: true, configurable: true}

声明对象描述:

var obj = new Object();
Object.defineProperty(obj, 'name', {
    configurable: false,
    writable: true, // 是否可以被赋值
    enumerable: true, // 是否可枚举
    value: '李明'
})

ES9 新特性

1.扩展运算符和rest参数

es6的...只能用在数组上,es9把这个用法扩展到了对象上。

let obj = {
	name:'张三'
}
let obj2 = {
	sex:1
}
let obj3 = {
	age:19
}
// 使用扩展运算符合并对象
let ooo = {...obj,...obj2,...obj3}  // {name:'张三',sex:1,age:19}

main(ooo)
// rest 获取剩余参数,这里面的剩余参数会自动合并成一个对象
function main({a,...b}){
    
}

2.正则捕获分组

3.正则反向断言

根据内容的前后进行识别,从而获取需要的数据。

正向断言:通过需要的字符后面的字符获取前面的数据。语法:(?=所需字符后面的字符)

let str = ’js2131231你是555啦啦啦'
// 目标获取555
const reg = /\d+(?=啦)/;

反向断言:通过需要的字符前面的字符获取后面所需的数据。语法:(?<=所需字符前面的字符)

let str = ’js2131231你是555啦啦啦'
// 目标获取555
const reg = /(?<=是)\d+/;

ES10 新特性

1.Object.fromEntries - 将二维数组或Map类型转成对象

const res = Object.fromEntries([
	['name','zss'],
	['sex','19']
])
// {name: 'zss', sex: '19'}

Object.entries 是将对象转成二维数组(ES8)

const res = Object.entries ({
	name:'shangsan'
})
// [['name','shangsan']]

2.trimStart与trimEnd

trimStart 去除左侧空白符

trimEnd 去除右侧空白符

3.flat - 将多维数组转低维数组

let arr = [1,2,3,[4,5]]
arr.flat() // [1,2,3,4,5]

// 将多维转1维,需要给flat传参维度n-1
// 例如:将3维转1维
let arr = [1,2,3,[4,5,[6,7]]]
arr.flat(2) // [1,2,3,4,5,6,7]

flatMap是flat和map方法的结合,又降维又遍历。

4.Symbol.description - 获取Symbolde描述

Symbolde描述其实就是symbol的值。

let s = Symbol('张三')
s.description() // '张三'

ES11 新特性

1.类的私有属性

私有属性只能在类里面定义和调用,外部不能调用。

class Person{
	name;
	#age; // 私有属性
	#weight; // 私有属性
	constructor(name,age,weight){
		this.name = name;
		this.#age = age;
		this.#weight = weight;
	}
	init(){
		console.log(this.#age)
	}
}
let gir = new Person('lili',20,'120kg')

2.Promise.allSettled

Promise.allSettled([p1,p2]) 用于处理多个promise的返回结果,它永远是成功的,即便其中一个是失败的,但不影响其他的promise返回结果。

Promise.all 是所有的promise的返回结构都成功,才有返回成功,不然就失败。

3.可选链操作符

用 ?. 表示可选链操作符,应用场景:去深层级的属性

function main(config){
	// 目标获取host属性
    // 传统写法 且短路写法
    let host = config && config.db && config.db.host;
    // 使用可选链操作符 
    let host2 = config?.db?.host;
}
main({
    db:{
        host:"20.32.18.95"
    }
})

4.动态导入import

ES6在文件头部import导入文件的方式被称作静态导入;ES11引入了动态导入的概念,在用的时候导入,并返回一个promise对象,导入成功,文件对象就是返回值。

btn.onclick = function(){
	// 动态导入js模块
	import('./hello.js').then(module =>{
        // 导入成功的返回值module就是 动态文件抛出的对象
		module.hello()
	})
}

5.BigInt数据类型

ES11引入了新的数据类型BigInt,用于表示大整型的数字(不能是小数)

定义BigInt类型:

  • 方式1:在数字后面+n ,类型变成 BigInt
let n = 123n
  • 方式2:使用BigInt定义
let n = BigInt(123)

应用场景:大数值运算。

js支持最大的数值是 Number.MAX_SAFE_INTEGER - 9007199254740991 ,也就是说超过这个值进行运算就会失效,这时就需要使用BigInt。

let max = Number.MAX_SAFE_INTEGER;
let cc = BigInt(max) + BigInt(2)

6.globalThis - 特殊变量

globalThis 永远指向 全局环境。浏览器永远指向 window对象。