【ES6 - ES11】新特性

ES 介绍

ES全称 EcmaScript,是脚本语言的规范,而平时编写的 JavaScript 是 EcmaScript 的一种实现,所以 ES 新特性其实指的就是 JavaScript 的新特性

ES6

1. 变量 let

	// 语法
	let a
	let b,c,d
	let f = 521, g = '123', h = []
	
	// 1、变量不能重复声明
	let star = '1';
	let star = 2; // 报错
	
	// 2、块级作用域 全局、函数、eval(es5的严格模式才有)
	// if else while for {}
	{
		let name = 'baozi';
	}
	console.log(name); // 报错,name没有定义
	
	// 3、不存在变量提升
	console.log(varName); // var 定义的变量存在变量提升,不报错,但是输出 undefined
	var varName = '123';
	console.log(letName); // 报错,不允许在声明变量之前,使用变量
	let letName = '123';
	
	// 4、不影响作用域链
	{
		let catName = '花姐';
		function sayName() {
			console.log(catName); // 花姐
		}
		sayName();
	}

let 经典案例

 	<div class="item"></div>
    <div class="item"></div>
    <script>
        let items = document.getElementsByClassName('item')
        // 使用 var 定义
        for(var i = 0 ; i < items.length; i++) {
            items[i].onclick = function() {
                // 成功修改
                // this.style.background = 'pink';
                // 修改失败,因为使用 var 定义的i,没有块级作用域,等循环执行完,window.i 等于2,找不到对应元素
                items[i].style.background = 'pink';
            }
        }
        // 使用 let 定义
		for(let i = 0 ; i < items.length; i++) {
            items[i].onclick = function() {
                // 成功修改
                // this.style.background = 'pink';
                // 修改成功,因为使用 let 定义的i,有块级作用域。会缓存 i
                items[i].style.background = 'pink';
            }
        }
    </script>

2. 常量 const

	// 声明常量
	const CATNAME= '花姐';
	
	// 1、一定要赋初始值
	const A; // 报错
	
	// 2、一般常量使用大写(潜规则),写小写也可以,不报错
	
	// 3、常量值不能修改
	CATNAME = '橘宝'; // 报错
	
	// 4、块级作用域 全局、函数、eval(es5的严格模式才有)
	// if else while for {}
	{
		const NAME= 'baozi';
	}
	console.log(NAME); // 报错,NAME没有定义

	// 5、对于数组和对象的元素修改,不算做对常量的修改,不会报错
	const TEAM = ['花姐', '橘宝'];
	TEAM.push('花姐姐'); // 不会报错,常量指向的地址没有改变
	TEAM = ['花姐姐']; // 报错,地址指向发现改变

3. 变量解构赋值

	// 允许按照一定模式从数组和对象中提取值,对变量进行赋值,被称为解构赋值
	// 1、数组的解构
	const catArray = ['花姐', '橘宝'];
    let [HJ, JB] = catArray;
    
	// 2、对象的解构
	const catObject= {
        name: '花姐',
        sayName: function() {
            console.log(this.name);
        },
        insideObj: { value: { key:1 } }
    };
    // 传统解构赋值
    let { name, sayName } = catObject;
    sayName();
    
    // 给新的变量名赋值
	let {name: catName} = catObject;
	console.log(catName); // 花姐

	// 连续解构赋值 value = { key:1 },没有解构出来变量 insideObj,打印为 insideObj is not defined
	const {insideObj: {value}} = catObject; 
	
	// 连续解构并重名 newValue = { key:1 }, 没有解构出来变量 value ,打印为 insideObj is not defined
    const {insideObj: {value: newValue}} = catObject; 
   
	// 给默认值
	var {name = '花姐', minName = '橘宝'} = catObject;
	console.log(name); // 花姐
	console.log(minName); // 橘宝

4. 模板字符串 ``

	// 1、声明
    let str = `我叫花姐`;
    console.log(str, typeof str); // 我叫花姐,string
    
	// 2、内容中可以直接出现换行符
	str = `<ul>
                <li>我叫${name}</li>
            </ul>`
            
	// 3、变量拼接
	let name = '花姐';
	str = `我叫${name}`;

5. 对象简化写法

	// 允许在在大括号里面,直接写入变量和函数,作为对象的属性和方法
    let name = '花姐';
    let sayName = function() {
        console.log(this.name);
    }
    let catInfo = {
        name,
        sayName,
        improve(){
           console.log('省略声明函数时的 冒号 与 function 字段')
       	}
    }

6. 箭头函数

	// ES6 允许使用 箭头 ( => ) 定义函数
    // 声明一个函数
    let fn = (a) => { return a }
    fn(1)

    // 1、this 是静态的,始终指向函数声明时所在的作用域下的 this 的值
    function sayName() {
        console.log(this.name)
    }        
    let  sayName2 = () => {
        console.log(this.name)
    }        
    // 设置 window 对象的 name 属性
    window.name = '花姐'
    const catObject = {
        name: '橘宝'
    }
    // 直接调用
    sayName(); // 花姐
    sayName2(); // 花姐
    // call 方法调用 - 箭头函数的 this 指向也不会修改
    sayName.call(catObject); // 橘宝
    sayName2.call(catObject); // 花姐

    // 2、不能作为构造函数去实例化对象
    let CatInfo = (name, age) => {
        this.name = name
        this.age = age
    }
    let info = new CatInfo('花姐', 5)
    console.log(info) // 报错,CatInfo is not a constructor

    // 3、不能使用 arguments 变量
    let argInfo = () => {
        console.log(arguments)
    }
    argInfo(1,2,3) // 报错,arguments is not define

    // 4、箭头函数的简写
    // 1) 省略小括号、当形参有且只有一个的时候
    let add = n => {
        return n + n
    }
    // 2) 省略花括号、当代码体只有一条语句的时候, 此时 return 必须省略,语句的执行结果就是返回值
    let pow = n => n*n
            

箭头函数的实践与应用场景
箭头函数适合与 this 无关的回调:定时器、数组的方法回调
箭头函数不适合 与 this 有关的回调: 事件回调,对象的方法 (会把this指向外层作用域的 this 值,而不是回调函数或对象本身) – 不适合不是不能

    <div class="ad"></div>
    <div class="ad1"></div>
    <script>
     	// 案例1 定时器 this 指向问题
    	let ad = document.getElementById('ad')
        ad.addEventListener('click', function(){
            // 保存当前的作用域的 this
            let _this = this
            setTimeout(function(){
                this.style.background ='pink'; // 无效, this 是指向 window 的            
                _this.style.background ='pink'; // 成功
            }, 2000)
        })

        let ad1 = document.getElementById('ad1')
        ad1.addEventListener('click', function(){
            setTimeout(() => {
                this.style.background ='pink'; // 成功 箭头函数是静态的,指向声明时所在的作用域下的this
            }, 2000)
        })
        
        // 案例2 - 数组返回偶数
        const arr = [1,6,9,10,100]
        const result = arr.filter(function(item){
            return item % 2 === 0 ? true : false
        })
        const result1 = arr.filter(item => item % 2 === 0)
        
    </script>

7. 函数参数的默认值设置

	// ES6 允许给函数参数赋值初始值
    // 1、形参初始值, 具有默认值的参数,一般位置靠后(潜规则)
    function add(a, b = 1) { return a + b }
    let result = add(2)

    // 2、与解构赋值结合
    function info({name = '花姐', age = 5}) {
        console.log(name, age)
    }
    info({
        name: '橘宝',
        age: 2
    })

8. rest 参数

es6 中 rest 与 spread 扩展运算符,只针对数组
es9 中为对象提供了像数组一样的 rest 参数 与 扩展运算符

	// ES5获取实参的方式
    function ES5Date() {
        console.log(arguments) // argument 是一个对象
    }
    ES5Date('花姐', '橘宝')

    // ES6 引入 rest 参数,用于获取函数的实参, 用来代替 argument
    function ES6Date(...args) {
        console.log(args) // args 是一个数组
    }
    ES6Date('花姐', '橘宝')

    // rest 参数必须放到参数最后
    function fn(a, b, ...args) {
        console(a, b, args) // 1,2, [3, 4]
    }
    fn(1,2,3,4)

9. spread 扩展运算符 …

es6 中 rest 与 spread 扩展运算符,只针对数组
es9 中为对象提供了像数组一样的 rest 参数 与 扩展运算符

	// [扩展运算符] 能将 [数组] 转换为逗号分隔的 [参数序列]
    const catArray = ['花姐', '橘宝'];
    function catInfo(){
        console.log(arguments);
    }
    cartInfo(catArray); // arguments只有一个对象属性,值为['花姐', '橘宝']
    cartInfo(...catArray) // arguments有两个对象属性,分别为'花姐', '橘宝'
   	// 1、数据的合并
    const HJ = ['花姐']
     const JB = ['橘宝']
     // es5 写法
     const catInfo = HJ.concat(JB); // ['花姐', '橘宝']
     const catInfo1 = [...HJ, ...JB]; // ['花姐', '橘宝']

     // 2、数据的克隆
     const catInfo3 = [...HJ];  // 若数据有引用类型的索引值是浅拷贝,若是基础数据类型,则是深拷贝
     
     // 3、将伪数组转为真正的数组
     const divs =document.querySelectorAll('div'); // divs 是一个 object 对象
     const divArr = [...divs]; // divArr 为 数组

10. Symbol

Symbol 是一种新的原始数据类型,,表示独一无二的值,一种类型与字符串的数据类型。
特点:
Symbol 值是唯一的,用来解决命名冲突的问题
Symbol 值不能与其他数据进行运算
Symbol 定义的对象属性不能使用 for…in 循环遍历,但是可以使用 Reflect.ownKeys 来获取对象的所有键名

	// 使用 Symbol() 创建
    let s = Symbol();
    console.log(s, typeof s); // Symbol(), "symbol"

    let s2 = Symbol('花姐');
    let s3 = Symbol('花姐');
    console.log(s2 == s3) // false

    // 使用 Symbol.for() 创建:传入的值表示唯一,会相等
    let s4 = Symbol.for('花姐');
    let s5 = Symbol.for('花姐');
    console.log(s4, typeof s4); // Symbol(花姐), "symbol"
    console.log(s4 === s5) // true

    // 不能与其他数据进行运算
    let result = s + 100; // 报错	
    
    // 数据类型总结:undefined、string、object、null、number、boolean

Symbol 使用场景

	// 使用 Symbol定义一个函数, 使用场景,防止影响到原本对象的属性或方法
	let say = Symbol('say')
    let youxi = {
        name: '狼人杀',
        say: function() {
            console.log('狼人杀')
        },
        [say]: function(){
            console.log('Symbol狼人杀')
        }
    }
    console.log(youxi.say()); // 狼人杀
    console.log(youxi[say]()); // Symbol狼人杀

Symbol 的内置属性用来对数据的操作进行扩展,例如 isConcatSpreadable 可以用于指定数组是否可以展开

11. 迭代器 iterator

任何数据结构只要部署 iterator 接口,就可以完成遍历操作,iterator 接口就是对象里面的一个 Symbol.iterator 属性
迭代器工作原理:

  1. 创建一个指针对象,指向当前数据结构的起始位置
  2. 第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员
  3. 接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员
  4. 每调用 next 方法返回一个包含 value 和 done 属性的对象
		const catInfo = ['花姐', '橘宝'];
        let interator = catInfo[Symbol.iterator]();
        // 调用对象的 next 方法
        console.log(interator.next()); // {done: false, value: "花姐"}
        console.log(interator.next()); // {done: false, value: "橘宝"}
        console.log(interator.next()); // {done: true, value: ""}

需要自定义遍历数据的时候,要想到迭代器

		// 未设置迭代器
		const catOldInfo = {
            name: '琼姐的喵喵们',
            catName: ['花姐', '橘宝'],
        }
        // 直接使用 for...of 无法遍历对象,(for...in就可以)
        for( let v of catOldInfo ) {
            console.log(v); // 报错,catInfo is not iterable
        }

		// 自定义迭代器
		const catInfo = {
            name: '琼姐的喵喵们',
            catName: ['花姐', '橘宝'],
            [Symbol.iterator](){
                let index = 0
                return {
                    next: () => {
                        if(index < this.catName.length) {
                            const result = {value: this.catName[index], done: false};
                            index++;
                            return result
                        } else {
                            return {value: undefined, done: true};
                        }
                    }
                }
            }
        }
        // catInfo 对象设置了 Symbol.iterator,对象就可以遍历
        for( let v of catInfo) {
            console.log(v); // '花姐', '橘宝'
        }

12. 生成器 Generator

生成器基础语法

		// es6 提供的一种异步编程解决方案,生成器是一个特殊的函数
		// yield 函数代码的分隔符,由 next() 方法执行
		// next 方法返回的是一个对象
		// next 方法可以传入实参,next 传入的实参将作为上一个 yield 语句返回的结果
		function * gen(arg) { 
		    console.log("*gen ~ arg", arg); // A
		    let one = yield '花姐';
		    console.log("*gen ~ one", one); // B
		    let two = yield '橘宝'; 
		    console.log("*gen ~ two", two); // C
		}
		let iterator = gen('A');
		console.log(iterator.next()); // {value: '花姐', done: false}
		console.log(iterator.next('B')); // {value: '橘宝', done: false}
		console.log(iterator.next('C')); // {value: undefined, done: true}
		
		// 可以使用 for...of 对gen迭代器进行遍历
		for(let v of gen()) {
		    console.log(v); // '花姐', '橘宝'
		}

生成器函数实例 - 异步获取数据

		function getCatName(){
		   setTimeout(() => {
		       let data = '花姐';
		       iterator.next(data);
		   }, 1000)
		}
		function getCatAge() {
		   setTimeout(() => {
		       let data = '5'
		       iterator.next(data);
		   }, 1000)
		}
		function * gen(){
		   let catName = yield getCatName();
		   console.log("gen ~ catName", catName)
		   let catAge = yield getCatAge();
		   console.log("gen ~ catAge", catAge)
		}
		// 调用生成器函数
		let iterator = gen();
		iterator.next();

13. Promise

promise共有三种状态,pending,fulfilled,rejected
状态只能从 pending 变为 fulfilled 状态(成功状态)或者从 pending 变为rejected状态(失败状态)
当 new 一个 promise 时,就已经开始自动执行函数。promise 是同步的,但 then 是异步的

		// es6 引入的异步编程的新解决方案
		// 语法上 Promise 是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果
        // Promise 构造函数: Promise(excutor) {}
        // 实例化对象
        const P = new Promise((resolve, reject) => {
            setTimeout(() => {
                // 表示成功=
                resolve('花姐')
                // 表示失败
                // reject('读取数据失败')
            }, 1000)
        })  
        
        /**
         * Promise.prototype.then()
         * then 方法的返回结果是 Promise 对象,对象状态由回调函数的执行结果决定
         *    1、如果回调函数中返回的结果是 非 Promise 类型的属性,状态为成功,返回值为对象的成功的值
         *         若写了 return ,则返回值是 return 的值
         *         若没有写 return, 则返回值是 undefined
         *    2、如果回调函数中返回的结果是 Promise 对象,则回调函数的状态由返回的 Promise 对象决定
         *    3、抛出错误,状态为失败  --- throw new Error('出错啦!')
        */
        let result = P.then(res => {
            console.log("res", res)
            // return 123;  // result 状态为成功
            // return new Promise((resolve, reject) => {}); // result 状态由这个 Promise 对象状态决定
            // throw new Error('出错啦!'); // result 状态为失败
        }, err => {
            console.log("err", err)
        })
        
        /**
         * Promise.prototype.catch() 用来指定 Promise 失败回调
        */
        P.catch(err => {
            console.log("err", err)
        })

Promise 中的 allrace 方法

		function P1() {
		     return new Promise((resolve, reject) => {
		         setTimeout(() => {
		             resolve('第一个异步执行成功')
		         }, 2000)
		     })
		}
		function P2() {
		   return new Promise((resolve, reject) => {
		       setTimeout(() => {
		           resolve('第二个异步执行成功')
		       }, 1000)
		   })
		}		
		// all 实现并行执行时, 返回的是每个异步函数执行回调后的结果组成的数组
		// 返回结果的状态要根据每个 promise 的状态来决定,要全部成功才会是成功
		Promise.all([P1(), P2()]).then(res => {
		   console.log('all', res); // ['第一个异步执行成功', '第二个异步执行成功']
		}).catch(reason => {
		   console.log('all',reason)
		})
		
		// race 实现并行执行时, 谁先执行结束,谁先进入回调
		Promise.race([P1(), P2()]).then(res => {
		   console.log('race', res); // '第二个异步执行成功'
		}).catch(reason => {
		   console.log('race', reason)
		})

14. 集合 Set()

es6 新增的数据结构 Set (集合),类似数组,但成员的值都是唯一的。
Set 也实现了 iterator 接口,可使用 扩展运算符 和 for…of 进行遍历

		// Set 是 object 类型
		let s = new Set();
		console.log(s, typeof s); // Set(0) {size: 0} 'object'
		
		// 自动去重
		let s2 = new Set(['花姐', '橘宝', '花姐']);
		console.log(s2); // Set(2) {'花姐', '橘宝'}
		
		// set 可遍历
		for(let v of s2) {
		    console.log(v); // 花姐, 橘宝
		}
		
		// size 返回元素个数
		console.log(s2.size); // 2
		
		// add 添加新的元素
		s2.add('喵猪');
		console.log(s2); // Set(3) {'花姐', '橘宝', '喵猪'}
		
		// delete 删除元素
		s2.delete('喵猪')
		console.log(s2); // Set(2) {'花姐', '橘宝'}
		
		// has 检测是否包含某个元素
		console.log(s2.has('喵猪')); // false
		
		// clear 清空 
		s2.clear()
		console.log(s2) // Set(0) {size: 0}

Set 实践

		let arr = [1,2,2,2,3,4,5]
		// 1、数组去重
		let result1 = [...new Set(arr)];
		console.log(result1); //  [1, 2, 3, 4, 5]
		
		// 2、交集
		let arr2 = [1, 4, 6, 7]
		let result2 = [...new Set(arr)].filter(item => new Set(arr2).has(item));
		console.log(result2); // [1, 4]
		
		// 3、并集
		let result3 = [...new Set([...arr, ...arr2])];
		console.log(result3); // [1, 2, 3, 4, 5, 6, 7]
		
		// 4、差集
		let result4 = [...new Set(arr)].filter(item => !(new Set(arr2).has(item)));
		console.log(result4); // [2, 3, 5]

15. Map()

es6 提供了 Map 数据结构,类似对象,也是键值对的集合,但是键的范围不限于字符串,各种类型的值(包括对象)都可以当键
Map 也实现了 iterator 接口,可使用 扩展运算符 和 for…of 进行遍历

		// Map 是 object 类型
		let m = new Map();
		
		// set 添加元素
		m.set('name', '花姐');
		console.log(m, typeof m); // Map(1) {'name' => '花姐'}  'object'
		
		// get 获取元素
		m.get('name')
		
		// set 可遍历
		for(let v of m) {
		   console.log(v); // ['name', '花姐']
		}
		
		// size 返回元素个数
		console.log(m.size); // 1
		
		// delete 删除元素
		m.delete('name')
		
		// clear 清空 
		m.clear()

16. class 类

es5 通过构造函数实例一个对象的语法

        // 声明一个构造函数
        function Phone(brand) {
            this.brand = brand;
        }
        // 添加实例方法 -- 函数不可直接调用 Phone.call() -- undefined
        Phone.prototype.call = function() {
            console.log('打电话')
        }
        
        // 静态成员 添加函数属性 -- 实例不可用
        Phone.catName = '花姐';
        Phone.sayName = function() {
            console.log('我是花姐')
        }
        console.log(Phone.sayName()); // 我是花姐        
        // 实例化对象
        let minPhone = new Phone('迷你手机')
        console.log(minPhone); // Phone {brand: '迷你手机'}
        console.log(minPhone.call()); // 打电话
        // 静态属性,实例获取不到
        console.log(minPhone.sayName()); // 报错,minPhone.sayName is not a function

		// 继承 使用 call + SmartPhone.prototype = new Phone +  SmartPhone.prototype.constructor = SmartPhone
		function SmartPhone(brand, price){
            Phone.call(this, brand)
            this.price = price
        }
        // 设置子级构造函数的原型
        SmartPhone.prototype = new Phone;
        SmartPhone.prototype.constructor = SmartPhone;
        // 声明子类的方法
        SmartPhone.prototype.photo = function() {
            console.log('拍照')
        }
        // 实例化对象
        let sPhone = new SmartPhone('小手机', 99)
        console.log(sPhone); // SmartPhone {brand: '小手机', price: 99}
        

es6 class 语法

		class Phone {
			// static 声明静态属性
		    static catName = '花姐'
		    // 构造器
		    constructor(brand) {
		        this.brand = brand;
		    }
		    // 方法不能使用 es5 的 function 去声明,必须使用" 函数名() {} "的语法
		    call(){
		        console.log('打电话');
		    }
			// static 声明静态方法
		    static sayName() {
		       console.log('我是花姐')
		    }
		}
		console.log(Phone.call()); // 报错, Class constructor Phone cannot be invoked without 'new'
		console.log(Phone.sayName()); // 我是花姐
		
		let minPhone = new Phone('迷你手机');
		console.log(minPhone); // Phone {brand: '迷你手机'}
		console.log(minPhone.call()); // 打电话
		// 静态属性,实例获取不到
		console.log(minPhone.sayName()); // 报错,minPhone.sayName is not a function

		// 继承 使用 extends 
		class SmartPhone extends Phone {
            constructor(brand, price){
                super(brand)
                this.price = price
            }
            photo(){
                console.log('拍照')
            }
            //  重写父类方法
            call(){
		        console.log('extends 打电话');
		    }
		    
		    // get 与 set
		    get name() {
                return this._name || '花姐';
            }
            set name(neWVal) {
                this._name = neWVal;
            }
        }

        let sPhone = new SmartPhone('小手机', 99)
        console.log(sPhone); // SmartPhone {brand: '小手机', price: 99}
        console.log(sPhone.call()); // extends 打电话
        console.log(sPhone.name); // '花姐'

17. ES6 数值扩展

		// 1、Number.EPSILON 是JavaScript 表示的最小精度
		console.log(0.1 + 0.2 === 0.3 ); // false
		function equal(a, b){
		    return Math.abs(a - b) < Number.EPSILON ? true : false;
		}
		console.log(equal(0.1 + 0.2, 0.3)); // true
		
		// 2、Number.isFinite 检测一个数值是否是有限数
		console.log(Number.isFinite(100)); // true
		console.log(Number.isFinite(100 / 0)); // false
		console.log(Number.isFinite(Infinity)); // false
		
		// 3、Number.isNaN 检测一个数值是否为 NaN
		console.log(Number.isNaN(123)); // false
		
		// 4、Number.parseInt 和 Number.parseFloat 字符串转整数
		console.log(Number.parseInt('12454.154sd')); // 12454
		console.log(Number.parseFloat('4545.45lobc')); // 4545.45
		
		// 5、Number.isInteger 判断一个数是否为整数
		console.log(Number.isInteger(5)); // true
		console.log(Number.isInteger(2.5)); // false
		
		// 6、Math.trunc 将数字的小数部分抹掉, 与 floor 向下取整很像
		console.log(Math.trunc(2.8)); // 2
		console.log(Math.floor(2.6)); // 2
		
		// 7、Math.sign 判断一个数是正数 负数 还是 0
		console.log(Math.sign(100)); // 1
		console.log(Math.sign(0)); // 0
		console.log(Math.sign(-110)); // -1

17. ES6 对象方法扩展

		// 1、Object.is 判断两个数值(只能用来检测基本数据类型)是否完全相等;
		// 跟 === 很像,但是 NaN === NaN 为false ,Object.is(NaN, NaN)为true
		console.log(Object.is(120, 120)); // true
		console.log(Object.is(NaN, NaN)); // true
		console.log(Object.is({name: '123'}, {name: '123'})); // false
		
		// 2、Object.assign 对象的合并, 若有相同属性名,后面会覆盖前面的属性值,若有属性不存在,则会保留
		const catHJ = {
			name: '花姐',
			age: 5
		}
		const catJB = {
			name: '橘宝'
		}
		console.log(Object.assign(catHJ, catJB)); // {name: '橘宝', age: 5}
		
		// 3、Object.setPrototypeOf 设置原型对象 和 Object.getPrototypeOf 获取原型对象
		const catInfo = { 
			name: '花姐'
		}
		const catAge = {
			age: 5
		}
		
		Object.setPrototypeOf(catInfo, catAge);
		console.log(catInfo); // 会把 age 写到 catInfo 的原型对象(_proto_)上
		console.log(Object.getPrototypeOf(catInfo)); // {age: 5}

18. ES6 模块化

模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合进来
优势:防止命名冲突、代码复用、高维护性
es6 之前的模块化规范:

  • CommonJS => NodeJS、Browserify
  • AMD => requireJS
  • CMD => seaJS

es6 模块化语法;主要由 export 和 import 两个命令组成:

  • export 命令用于规定模块的对外接口
  • import 命令用于输入其他模块提供的功能

模块暴露方式

  • 默认暴露 catInfo.js
		export default {
		    catAge: 5,
		    sayAge: function(){
		        console.log(this.catAge)
		    }
		}
  • 分别暴露 catInfo.js
		export let catName = '花姐';
		export function getCatName() {
		    console.log(catName)
		}
  • 统一暴露 catInfo.js
		let catName = '花姐';		
		function getCatName() {
		    console.log(catName);
		}
		export {dogName, getDogName}

使用:index.html (VS code 可以安装 Live Server,然后右键运行 html 文件)

		<script type="module">
	        // VS code 可以安装 Live Server,然后右键运行 html 文件
	        // 1、通用的导入方式
	        import * as catInfo from './catInfo.js'
	        
	        // 2、解构赋值形式
	        import {catName, getCatName} from './catInfo.js'
	        
			// 3、结构赋值 + 别名
	        import {catName as name, getCatName} from './catInfo.js'
			
			// 4、简便形式,只能针对默认暴露
			import catInfo from './catInfo.js'
	    </script>

模块化代码转换
通过 babel 转换

  • 先初始化项目:npm init --yes
  • 安装工具: npm i babel-cli babel-preset-env browserify -D
    babel-cli:babel 命令行工具
    babel-preset-env:babel 预设包,能将 es6 新特性转换为 es5语法
    browserify:简单的打包工具,日常开发中用 webpack
  • babel命令:
    全局安装:babel 源文件目录地址 -d 转换的结果储存的目录地址 --presets=babel-preset-env
    局部安装:npx babel 源文件目录地址 -d 转换的结果储存的目录地址 --presets=babel-preset-env
    例子: npx babel src/js -d dist/js --presets=babel-preset-env
  • 打包:
    命令:npx browserify 入口文件 -o 打包后输出的目录地址/bundle.js
    例子:npx browserify dist/js/main.js -o dist/bundle.js

ES7

1. Array.prototype.includes

includes 方法用来检测数组中是否包含某个元素,返回布尔类型值

		// indexOf 返回结果是索引值,includes返回的是 Boolean 值
		const catInfo = ['花姐', '橘宝']
		console.log(catInfo.includes('橘宝')); // true
		console.log(catInfo.indexOf('橘宝')); // 1

2. 幂运算**

		// a ** b 结果等同于 Math.pow(a, b)
		console.log(2 ** 10); // 1024
		console.log(Math.pow(2, 10)); // 1024

ES8

1. async 和 await

async 和 await 两种语法结合可以让异步代码像同步代码一样

  • async 函数
    async 函数的返回值为 Promise 对象,可用 then 方法
    promise 对象的结果由 async 函数执行的返回值决定
		async function fn(){
		     // 1、返回的结果不是一个 Promise 类型的对象,返回的结果是成功的 Promise
		     // return '花姐';
		     // return;
		     // 2、抛出错误,返回的结果是一个失败的 Promise
		     // throw new Error('出错啦!');
		     // 3、返回的结果如果是一个 Promise 对象,该 Promise 对象的状态,就是返回的结果的状态
		     return new Promise((resolve, reject) => {
		         resolve('成功')
		     })
		 }
		 const result = fn();
		 console.log(result);
       	 result.then(res=>{}, err=> {)
  • await 表达式
    await 必须写在 async 函数中
    await 右侧的表达式一般为 promise 对象
    await 返回的 promise 成功的值
    await 的 promise 失败了,会抛出异常,需要通过 try…catch 捕获处理
		// 创建一个 Promise 对象
		const p = new Promise((resolve, reject) => {
		    resolve('花姐')
		})
		// await 要放在 async 中
		async function fn(){
		    try {
                let result = await p;
                console.log("result", result); // result 花姐
            } catch (e) {
                console.log(e)
            }
		}
		fn()
  • async 和 await 结合封装 XMLHttpRequest
		// 发送 AJAX 请求,返回的结果是 Promise 对象
		function sendAJAX(params){
		    return new Promise((resolve, reject) => {
		        // 创建对象
		        let xhr = new XMLHttpRequest();
		        // 初始化
		        xhr.open(params.method, params.url);
		        // 发送
		        xhr.send();
		        // 事件绑定
		        xhr.onreadystatechange = function(){
		            if(xhr.readyState == 4) {
		                if(xhr.status >= 200 && xhr.status < 300){
		                    resolve(xhr.response)
		                } else {
		                    resolve(xhr.status)
		                }
		            }
		        }
		
		    })
		}
		
		// Promise then 方法测试
		sendAJAX({ method: 'GET', url: '请求地址' }).then(res => {
		    console.log("res", res)
		}, err => {})
		
		// async  与 await 方法测试
		async function getData(){
		    let result1 = await sendAJAX({ method: 'GET', url: '请求地址' })
		    let result2 = await sendAJAX({ method: 'GET', url: '请求地址', data: result1 })
		}

2. 对象方法扩展

  • Object.keys (不是es8新特性)
    Object.keys 方法返回一个给定对象的所有键名的数组
		const catInfo = {
			name: '花姐',
			age: 5
		}
		// 获取对象所有的键名, Object.keys 可以用于判断对象是否为空对象
		console.log(Object.keys(catInfo)); // ['name', 'age']
  • Object.values
    Object.values 方法返回一个给定对象的所有可枚举属性值的数组
		const catInfo = {
			name: '花姐',
			age: 5
		}
		// 获取对象所有的值
		console.log(Object.values(catInfo)); // ['花姐', 5]
  • Object.entries
    Object.entries 方法返回一个给定对象自身可遍历属性 [key, value ] 的数组
		const catInfo = {
		   name: '花姐',
		   age: 5
		}
		console.log(Object.entries(catInfo)); // [['name', '花姐'], ['age', 5]]
		// 可用于创建一个 Map
		const m  = new Map(Object.entries(catInfo))
        console.log(m); // Map(2) {'name' => '花姐', 'age' => 5}
        console.log(m.get('name')); // 花姐
  • Object.getOwnPropertyDescriptors
    Object.getOwnPropertyDescriptors 方法返回指定对象所有自身属性的描述对象
    属性特性:
    configurable:是否可以删除
    enumerable:是否可以枚举
    writable:是否可写
		const catInfo = {
			name: '花姐',
			age: 5
		}
		console.log(Object.getOwnPropertyDescriptors(catInfo)); 
		/**
         * {
         *      age: {value: 5, writable: true, enumerable: true, configurable: true}, 
         *      name: {value: '花姐', writable: true, enumerable: true, configurable: true}
         * }
        */

ES9

1. rest 参数 与 spread 扩展运算符

在 es6 中 rest 参数与 spread 扩展运算符 已经引入,但是只针对数组
在 es9 中为对象提供了像数组一样的 rest 参数 和 spread 扩展运算符

  • rest 参数
		function catInfo({name, ...info}){
		    console.log(name); // 花姐
		    console.log(info); // {age: 5, color: '灰色'}
		}
		
		catInfo({
		    name: '花姐',
		    age: 5,
		    color: '灰色'
		});
  • spread 扩展运算符 …
		let catName = { name: '花姐' };

        let catAge = { age: 5 };
        
        let catColor = { color: '灰色' };
        // 合并对象
        const catInfo = {...catName, ...catAge, ...catColor}
        console.log(catInfo); // {name: '花姐', age: 5, color: '灰色'}

2. 正则扩展 - 命名捕获分组

		let str = '<a href="http:hj.com">花姐</a>';
        // 提取 url 与 标签文本
        // 没有捕获分组之前
        const reg1 = /<a href="(.*)">(.*)<\/a>/;
        const result1 = reg1.exec(str);
        console.log(result1[1], result1[2]);  
        // result 是一个数组
        // ['<a href="http:hj.com">花姐</a>', 'http:hj.com', '花姐', index: 0, input: '<a href="http:hj.com">花姐</a>', groups: undefined]
       
        // 有捕获分组
        const reg2 = /<a href="(?<url>.*)">(?<name>.*)<\/a>/;
        const result2 = reg2.exec(str);
        console.log(result2.groups);   
        // result 是一个数组, 分组内容放在 groups 中
        // ['<a href="http:hj.com">花姐</a>', 'http:hj.com', '花姐', index: 0, input: '<a href="http:hj.com">花姐</a>', groups: {name: "花姐", url: "http:hj.com" }]

2. 正则扩展 - 反向断言

		let str = `4545454你知道么555啦啦啦`
        // 正向断言
        const reg1 = /\d+(?=啦)/
        const result1 = reg1.exec(str);
        console.log(result1); 
        // ['555', index: 11, input: '4545454你知道么555啦啦啦', groups: undefined]

        // 反向断言
        const reg2 = /(?<=么)\d+/;
        const result2 = reg2.exec(str);
        console.log(result2);
        // ['555', index: 11, input: '4545454你知道么555啦啦啦', groups: undefined]

3. 正则扩展 - dotAll 模式

		// dot . 元字符  除换行符意外的任意单个字符
		let str = `
		   <ul>
		       <li>
		           <a>花姐</a>
		           <p>5岁</p>    
		       </li> 
		       <li>
		           <a>橘宝</a>
		           <p>2岁</p>    
		       </li>   
		   </ul>
		`
		
		// 旧写法 \s 用于匹配换行部分内容
		// 只匹配一个
		const reg1 = /<li>\s+<a>(.*?)<\/a>\s+<p>(.*?)<\/p>/;
		// 只匹配两个
		const reg2 = /<li>\s+<a>(.*?)<\/a>\s+<p>(.*?)<\/p>\s+<\/li>\s+<li>\s+<a>(.*?)<\/a>\s+<p>(.*?)<\/p>/; 
		const result1 = reg1.exec(str);
		const result2 = reg2.exec(str);
		console.log(result1, result2);
		
		// 新写法 //s 模式修正符s; /./s 能匹配任意字符
		// /g 模式修正符g,表示匹配全部
		const regDot = /<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/gs; 
		// 只匹配单个
		// const resultDot1 = regDot.exec(str); 
		// 匹配多个
		let resultDotAll = [];
		while(resultDot2 = regDot.exec(str)){
		   console.log("resultDot2", resultDot2)
		   resultDotAll.push({
		       name: resultDot2[1],
		       age: resultDot2[2]
		   })
		}

ES10

1. 对象扩展方法 Object.fromEntries

es8 的 Object.entries 与 es10 的Object.fromEntries 互运算
Object.entries 将对象转换为二维数组
Object.fromEntries 将二维数组装换为对象

		// es8 的 Object.entries
		const arr = Object.entries({
			name:'花姐',
			age: 5
		})
		console.log(arr); // [['name', '花姐'], ['age', 5]]
		
		// es10 的Object.fromEntries
		// 传入二维数据
		const result = Object.fromEntries([
			['name', '花姐'],
			['age', 5]
		])
		console.log(result);  // {name: '花姐', age: 5}
		
		// Map
		const m = new Map();
		m.set('name', '橘宝');
		m.set('age', 2);
		const resultMap = Object.fromEntries(m);
		console.log(resultMap); // {name: '橘宝', age: 2}

2. 字符串扩展方法 trimStart 和 trimEnd

		let str = '   内容   ';
		console.log(str);
		console.log(str.trim());
		console.log(str.trimStart());
		console.log(str.trimEnd());

3. 数组扩展方法 flat 和 flatMap

		// flat 将多维数组转为低维数组
		const flatArr = [1, [4, 5], [6, [46, 89]]];
		console.log(flatArr.flat()); //  [1, 4, 5, 6, [46, 89]]
		// flat(n), 参数 n 表示深度,是一个数字, 默认值是 1
		console.log(flatArr.flat(2)); // [1, 4, 5, 6, 46, 89]
		
		// flatMap 循环的同时,将数组变为一维数组
		const flatMapArr = [1,2,3]
		// map 与 flatMap 
		const resultMap = flatMapArr.map(item => [item * 10]); 
		console.log(resultMap); // [[10], [20], [30]]
		
		const resultFlatMap = flatMapArr.flatMap(item => [item * 10]); 
		console.log(resultFlatMap); // [10, 20, 30]

4. Symbol.prototype.description

		// description 用来获取 Symbol 的字符串描述
		let s = Symbol('花姐');
		console.log(s.description); // 花姐

ES11

1. 私有属性

		class cat{
		    // 公有属性
		    name;
		    // 静态属性 -- 供类使用,cat.color 可以获取
		    static color = '灰色';
		    // 私有属性 -- 只能是在类内部使用,cat.#age 也无法获取
		    #age;
		    #weight;
		    // 构造方法
		    constructor(name, age, weight){
		        this.name = name;
		        this.#age = age;
		        this.#weight = weight;
		    }
		    intor(){
		        console.log(this.#age, this.#weight)
		    }       
		}
		
		// 实例化
		let catInfo = new cat('花姐', 5, 10);
		console.log(catInfo.intor())

2. Promise.allSettled 方法

Promise.allSettled 接收一个 Promise 数组,返回结果也是 Promise 对象,并且永远是成功的状态

		const P1 = new Promise((resolve, reject) => {
		    setTimeout(() => {
		        resolve('商品数据 - 1')
		    }, 1000)
		})
		
		const P2 = new Promise((resolve, reject) => {
		    setTimeout(() => {
		        resolve('商品数据 - 2')
		    }, 1000)
		})
		
		// 调用 allSettled 方法,
		// allSettled 方法返回值是一个数组,并且永远是成功的状态
		// 数组每个元素是一个对象,对象包含的是当前每个 promise 的状态 和 结果值
		const result = Promise.allSettled([P1, P2]);
		console.log(result)
		
		// all 方法
		// all 方法返回值是一个数组,返回结果的状态要根据每个 promise 的状态来决定,要全部成功才会是成功
		const resultAll = Promise.all([P1, P2]);
		console.log(resultAll)

若每个异步都要成功才能执行下一步时,选择 Promise.all
若每个异步都想要得到结果但是不强制全部成功,则选择 Promise.allSettled

3. String.prototype.matchAll

		let str = `<ul>
            <li>
                <a>花姐</a>
                <p>5岁</p>    
            </li> 
            <li>
                <a>橘宝</a>
                <p>2岁</p>    
            </li>   
        </ul>`
        const reg = /<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/gs; 
        // 调用 matchAll 方法
        const result = str.matchAll(reg)
        for(let v of result){
            console.log(v)
        }

4. 可选链操作符 ?.

	function catInfo(config){
	    // 传统写法
	    const name1 = config && config.info && config.info.name
	    // 可选链写法
	    const name2 = config?.info?.name
	    console.log(name1, name2)
	}
	
	catInfo({
	    info:{ name: '花姐', age: 5 }
	})
	catInfo(); // 不传参数也不会报错

5. 动态 import

用于提高加载效率

  • catInfo.js
		export let catName = '花姐'
		
		export function getCatName() {
		    console.log(catName)
		}
  • index.html
<body>
    <button id="btn"></button>
    <script type="module">
    	// 静态 import
		import * as catInfo from './catInfo.js'
		console.log(catInfo.getCatName())
		
        const btn = document.getElementById('btn');
		btn.onclick = function(){
		    // 动态import
		    import('./src/js/catInfo.js').then(module => {
		        console.log(module.getCatName())
		    })
		}
</body>

6. BigInt 类型

		// 大整形 - 用于更大的数值运算; 语法: 普通整型(整数)后面 + n
        let n = 521n;
        console.log(n, typeof n); //521n 'bigint'

        // 函数 BigInt(n), n 参数只能是整数,不能是浮点型
        let n1 = 123; 
        console.log(BigInt(n1)); // 123n

        // 大数值运算 MAX_SAFE_INTEGER 表示最大安全整数
        let max = Number.MAX_SAFE_INTEGER;
        console.log(max); // 9007199254740991        
        console.log(max + 1); // 9007199254740992
        console.log(max + 2); // 9007199254740992 结果有问题

        // BigInt 类型不能直接跟普通整型做运算
        console.log(BigInt(max) + BigInt(1)); // 9007199254740992n
        console.log(BigInt(max) + BigInt(2)); // 9007199254740993n

7. 绝对全局对象 globalThis

	console.log(globalThis); // window 对象
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值