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 属性
迭代器工作原理:
- 创建一个指针对象,指向当前数据结构的起始位置
- 第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员
- 接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员
- 每调用 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 中的 all 和 race 方法
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 对象