ES6学习记录
声明
- 声明变量:
let 变量名
1.变量不能重复声明 2.块级作用域(只在代码块中有效) 3.不存在变量提升(代码上要在调用之前声明才行) 4.不影响作用域链
- 声明常量:
const 常量名 = 常量值
1.一定要赋初始值 2.一般常量使用大写 3.常量的值不能修改 4.块级作用域(只在代码块中有效) 5.对于数组和对象的元素修改,不算做对常量的修改,不会报错(不改变指向的地址)
变量解构赋值
ES6允许按照一定模式从数组和对象中提取值,对变量进行赋值
-
数组的解构
const arr= ["A","B","C","D"] let [a,b,c,d]=arr console.log(a);//打印"A" console.log(b);//打印"B" console.log(c);//打印"C" console.log(d);//打印"D"
-
对象的解构
const Person = { name:"小A", age:15, test:function(){ console.log("这是测试用的函数") } } let {name,age,test} = Person console.log(name);//打印"小A" console.log(age);//打印15 test();//打印"这是测试用的函数"
解构后方法中的this会指向全局(我用的node调试的,所以解构后getName()方法中的this指向了global,网页中估计是window),然后我把this改成了Person,不确定实战中会不会有问题,代码如下:
const Person = { name:"小A", age:15, getName:function(){ console.log("名字是"+Person.name) }, } let {name,age,getName} = Person console.log(name);//打印"小A" console.log(age);//打印15 getName();//打印"名字是小A"
新的声明字符串的方式
//1.声明方式
let str = `这是一个字符串`;
//2.内容中可以直接换行
let strDiv =`<div>
<ul>
<li>这是一个list</li>
<li>这是一个list</li>
<li>这是一个list</li>
<li>这是一个list</li>
</ul>
</div>
`
//3.变量拼接
let strBefore = `哈哈哈`
let strAfter = `呵呵呵`
let strAll = `${strBefore}${strAfter}`
console.log(strAll)//打印"哈哈哈呵呵呵"
简化对象写法
ES6允许直接在大括号里写入变量和函数,作为对象的属性和方法
示例:
let str = `这是一个字符串`
let fun = function(){
console.log("这是一个函数")
}
const obj = {
str,
fun,
testObj(){
console.log("这是对象");
}
}
console.log(obj);
箭头函数
ES6允许使用(param)=>{}
定义函数
let fun = ()=>{
console.log("这是一个函数")
}
fun()
//箭头函数:
//1.this是静态的,this始终指向函数声明时所在作用域下的this的值,无论什么方式调用(包括call,apply等),都无法改变this
//2.不能作为构造函数实例化对象
//3.不能使用arguments变量
//4.箭头函数简写
// (1)省略小括号,当形参有且只有一个的时候
let aPlus = a =>{return a + a ;}
// (2)省略大括号,当代码体只有一条语句的时候,此时return必须省略,而且语句的执行结果就是函数的返回值
let aPlus = a => a + a ;
注意:
箭头函数适合与this无关的回调,定时器,数组的方法回调
箭头函数不适合与this有关的回调,事件回调,对象的方法
函数中参数的初值
ES6允许给函数参数赋值初始值
//1. 形参初始值 具有默认值的参数,一般位置要靠后
function add(a,b,c=1){
return a+b+c
}
let result = add(1,2)
console.log(result)
//2. 与解构赋值结合
function connect({host="127.0.0.1",username,password,port}){
console.log(host)
console.log(username)
console.log(password)
console.log(port)
}
connect({
host:"192.168.1.101",
username:'root',
password:'123',
port:3306
})
rest参数
ES6引入rest参数,用于获取函数的实参,用来代替arguments
rest参数:(需要用…开头)
function test(...args){
console.log(args)
}
test('小A','小B','小C')//打印 [ '小A', '小B', '小C' ]
注意:rest参数必须要放到参数最后
扩展运算符
- 扩展运算符能将数组转换为逗号分隔的参数序列
声明一个数组…const arr = ['小A','小B','小C'] function testArr(){ console.log(arguments); } testArr(...arr); //打印{ '0': '小A', '1': '小B', '2': '小C' }
- 扩展运算符能用于数组的合并
const arrA = ['小A','小B'] const arrB = ['小C','小D'] const arrC = [...arrA,...arrB] console.log(arrC)//打印[ '小A', '小B', '小C', '小D' ]
- 扩展运算符能用于数组的克隆
const arrA = ['小A','小B'] const arrB = [...arrA] console.log(arrA)
- 将伪数组转为真正的数组
经常见到的伪数组有函数的arguments对象、dom.querySelectorAll等获取的NodeList类(NodeList本身具有forEach方法)等。function test(){ const args = [...arguments] console.log(args) } test('小A','小B','小C')//打印 [ '小A', '小B', '小C' ]
Symbol
ES6引入了一个新的原始数据类型Symbol,表示独一无二的值,是JavaScript的第七种数据类型,每个从Symbol()返回的symbol值都是唯一的。一个symbol值能作为对象属性的标识符,这是该数据类型仅有的目的
- Symbol特点
(1)Symbol的值是唯一的,用来解决命名冲突的问题
(2)Symbol值不能与其他数据进行运算
(3)Symbol定义的对象属性不能使用for…in循环遍历,但是可以使用Reflect.ownKeys来获取对象的所有键名 - Symbol的使用
使用 Symbol.for() 方法和 Symbol.keyFor() 方法从全局的symbol注册表设置和取得symbolvar a = Symbol('a') var b = Symbol('a') console.log(a === b) //输出false,说明symbol()是独一无二的值 //而括号里的'a'仅仅只是用来注释 //即使两个注释都是'a',也是不同的Symbol //注释只是我们自己标上去用来告诉我们自己它是哪个Symbol
Symbol.for('test')//设置一个symbol并放入全局symbol注册表中,键为'test' Symbol.for('test')//读取全局symbol中的test console.log(Symbol.for('test')===Symbol.for("test"))//返回的是true,因为是全局的,等于号前后的都指向全局注册表中同一个symbol值,全局的symbol在其他地方也能获取 console.log(Symbol("test2") ===Symbol("test2"))//返回的是false,因为不是全局的,两次创建的是两个不同的,独一无二的
迭代器
迭代器(Iterator)是一种接口,为各种不同的数据结构提供统一的访问机制,任何数据结构只要部署Iterator接口(这里的接口指的是对象中的一个属性),就可以完成遍历操作
- ES6创造了一种新的遍历命令for…of循环,Iterator接口主要提供for…of消费
- 原生具备iterator接口的数据(可用for of 遍历)
- Array - Arguments - Set - Map - String - TypedArray - NodeList
- 工作原理
(1)创建一个指针对象,指向当前数据结构的起始位置 (2)第一次调用对象的next方法,指针自动指向数据结构的第一个成员 (3)接下来不断调用next方法,指针一直往后移动,直到指向最后一个成员 (4)每调用next方法返回一个包含value和done属性的对象 - value表示值,done表示是否完成
- for of的使用
const arr = ['小A','小B','小C','小D'] for(let itemValue of arr ){ console.log(itemValue) } let iterator = arr[Symbol.iterator](); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next());
- 自定义遍历
//Symbol.iterator 为每一个对象定义了默认的迭代器。该迭代器可以被 for...of 循环使用。 const objA = { name:"小A", friends:["小B","小C","小D","小E"], [Symbol.iterator](){ let index = 0; let _this = this; return { next:function () { if(index<_this.friends.length){ const result = {value:_this.friends[index],done:false} index++; return result }else{ return {value:undefined,done:true} } } } } } for(let itemValue of objA){ console.log(itemValue) }
生成器
生成器是一个特殊的函数,能对异步编程产生影响
异步编程,纯回调函数如: node fs/ ajax/ mongodb
- 生成器函数的声明
function * 函数名(){}
function * aaa(){ yield 111; //yield关键字使生成器函数执行暂停,yield关键字后面的表达式的值返回给生成器的调用者 yield 222; yield 333; } let iter = aaa(); console.log(iter.next());//打印111 console.log(iter.next());//打印222 console.log(iter.next());//打印333
- 生成器函数传参
//如下代码可知:后一次调用的参数会成为前一次调用的整体返回结果 function * test(arg){ console.log(arg);//这里打印undefined,说明'xx'没传进来 let a = yield 111; console.log(a);//这里打印'aa',说明上面一次的返回结果变成了'aa' console.log(yield 222)//这里打印了bb,说明了yield 222返回结果变成了bb yield 333; } let iter = test(); console.log(iter.next());//打印111 console.log(iter.next('aa'));//打印222 console.log(iter.next('zz'));//打印333 /* 整体输出结果如下,说明调用时yield语句会执行并返回结果,但是在执行后面的调用时,前面一句yield语句的返回值就会变成后面调用时传入的参数,通过这样的方式就能实现异步编程参数传递 { value: 111, done: false } aa { value: 222, done: false } zz { value: 333, done: false } */
异步编程
异步编程 文件操作 网络操作(ajax,request) 数据库操作
解决回调地狱的问题
- 案例1:
不使用生成器时代码:
使用生成器时代码:function myPrint(){ setTimeout(() => { console.log("111"); setTimeout(() => { console.log("222"); setTimeout(() => { console.log("333"); }, 1000); }, 1000); }, 1000); } myPrint()
function one(){ setTimeout(()=>{ console.log(111) iter.next() },1000) } function two(){ setTimeout(()=>{ console.log(222) iter.next() },1000) } function three(){ setTimeout(()=>{ console.log(333) },1000) } function * gen(){ yield one(); yield two(); yield three(); } let iter = gen(); iter.next();
- 案例2:
//获取用户数据 商品数据 订单数据 function getUsers() { setTimeout(() => { let data = "用户数据" iterator.next(data) }, 1000) } function getOrders(){ setTimeout(() => { let data = "订单数据" iterator.next(data) }, 1000) } function getGoods(){ setTimeout(() => { let data = "商品数据" iterator.next(data) }, 1000) } function * gen(){ let users = yield getUsers() console.log(users) let orders = yield getOrders() console.log(orders) let goods = yield getGoods() console.log(goods) } let iterator = gen() iterator.next()
Promise
Promise是ES6引入的异步编程的新解决方案,语法上promise是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果
(1)Promise 构造函数: Promise(excutor){}
(2)Promise.prototype.then方法
(3)Promise.prototype.catch方法
//实例化Promise对象
const p = new Promise(function(resolve,reject){
setTimeout(()=>{
// let data = '执行成功'
// resolve(data)
let err = '执行失败'
reject(data)
},1000)
})
p.then((value)=>{
console.log(value)
},(reason)=>{
console.log(reason)
})
-
Promis读取文件案例:
const fs = require('fs') const p = new Promise(function(resolve,reject){ fs.readFile('./test.txt',(err,data)=>{ if(err) reject(err) resolve(data) }) }) p.then(function(value){ console.log(value.toString()) },function(reason){ console.log("读取失败") })
-
Promise封装Ajax
原生js中的Ajax://1.创建对象 const xhr = new XMLHttpRequest(); //2.初始化 xhr.open("GET","https://127.0.0.1:8000") //3.发送 xhr.send() //4.绑定事件,处理响应结果 xhr.onreadystatechange = function(){ if(xhr.readyState === 4){ //判断响应状态码200-299 if(xhr.status>=200&&xhr.status<300>){ //成功 console.log(xhr.response) } else{ //失败 console.log(xhr.status) } } }
Promise封装的Ajax
var p =new Promise(function(resolve,reject){ //1.创建对象 const xhr = new XMLHttpRequest(); //2.初始化 xhr.open("GET","https://127.0.0.1:8000") //3.发送 xhr.send() //4.绑定事件,处理响应结果 xhr.onreadystatechange = function(){ if(xhr.readyState === 4){ //判断响应状态码200-299 if(xhr.status>=200&&xhr.status<300>){ //成功 resolve(xhr.response) } else{ //失败 reject(xhr.status) } } } }) p.then(value=>{ console.log(value) },reason=>{ console.log(reason) })
-
链式调用
从前往后,一个成功调用后return下一个Promise对象,可以解决回调地狱的问题p.then(value=>{ }).then(value=>{ })
链式调用读取文件示例
const fs = require('fs'); let p = new Promise((resolve,reject)=>{ fs.readFile('./one.txt',(err,data)=>{ resolve(data) }) }) p.then(value=>{ return new Promise((resolve,reject)=>{ fs.readFile('./two.txt',(err,data)=>{ resolve([value,data]) }) }) }).then(value=>{ return new Promise((resolve,reject)=>{ fs.readFile('./three.txt',(err,data)=>{ value.push(data) resolve(value) }) }) }).then(value=>{ console.log(value.join('\r\n')) })
-
Promise对象catch
catch专门用来获取异常,通常只用then也可以const p = new Promise((resolve,reject)=>{ setTimeout(()=>{ //设置p对象的状态为失败,并设置失败的值 reject("出错啦") },1000) }) p.catch(function(reason){ console.warn(reason) })
集合set
ES6提供了新的数据结构set(集合)。它类似于数组,但成员的值都是唯一的,集合实现了iterator接口,所以可以使用扩展运算符和for…of进行遍历
- 集合的属性和方法
size 返回集合的元素个数 add 增加一个新元素,返回当前集合 delete 删除元素,返回boolean值 has 检测集合中是否包含某个元素,返回boolean值
- 声明集合和使用
let s = new Set() let s2 = new Set(["小A","小B","小C","小A","小D"]) console.log(s2.size)//打印4 因为小A重复,在集合大小里面不计算重复的内容 s2.add('小E') s2.delete('小A') console.log(s2.has('小A')) console.log(s2)//Set(4) { '小B', '小C', '小D', '小E' } s2.clear()
- 集合案例
let arr = [1,2,3,4,5,4,3,2,1] //1.数组去重 let result = [...new Set(arr)] //2.数组求交集 let arr2 = [4,5,6,5,6] let result2 = [...new Set(arr)].filter(item=>{ let s2 = new Set(arr2) if(s2.has(item)){ return true } else { return false } }) //求交集的另一种写法 let result2 = [...new Set(arr)].filter(item=>new Set(arr2).has(item)) console.log(result2)//打印 [ 4, 5 ] //3.数组求并集 let union = [...new Set([...arr,...arr2])] console.log(union) //4.数组求差集 //arr1和arr2的差集,就是arr1中有,arr2没有 //arr2和arr1的差集,就是arr2中有,arr1没有 let diff = [...new Set(arr)].filter(item=>!(new Set(arr2).has(item))) console.log(diff)
Map
ES6中提供了Map数据结构,它类似于对象,也是键值对的集合。但是键的范围不限于字符串,各种类型的值(包括对象)都可以当作键。Map也实现了iterator接口,所以可以使用扩展运算符和for of进行遍历。
- Map的属性和方法
size 返回Map的元素个数 set 增加一个新元素,返回当前Map get 返回键名对象的键值 has 检测Map中是否包含某个元素,返回boolean值 clear 清空集合,返回undefined
- 声明Map和使用Map
//声明Map let m = new Map() m.set('name','小A') m.set('change',function(){ console.log("小A改变了") }) console.log(m) /* 结果: Map(2) { 'name' => '小A', 'change' => [Function (anonymous)] } */ //另一种方式添加键值 let mykey = { person:'小A' } m.set(mykey,['小B','小C']) console.log(m) /* 结果: Map(3) { 'name' => '小A', 'change' => [Function (anonymous)], { person: '小A' } => [ '小B', '小C' ] } */ //其他方法 console.log(m.size) m.delete('name') console.log(m.get('change')) for(let v of m){ console.log(v) } m.clear()
class 类
ES6 提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板,通过class关键字,可以定义类。基本上,ES6的class可以看作是一个语法糖,它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更清晰、更像面向对象编程的语法而已
知识点
class 声明类
constructor 定义构造函数初始化
extends 继承父类
super 调用父级构造方法
static 定义静态方法和属性
父类方法可以重写
-
类的写法
class 类名{ //构造方法,名字不能修改 constructor(参数1,参数2){ this.属性1 = 参数1 this.属性2 = 参数2 } //方法,必须使用该语法 即方法名(){} //不能使用es5的对象完整形式 方法名:function(){} 方法名(){} } //实例化 let 对象 = new 类名(参数1,参数2)
-
class静态成员
通过static关键字声明的属性,属于类,而不属于实例化对象,需要通过 类名.静态属性 来获取 -
构造函数继承
ES5构造函数的继承//父类 function Phone(brand,price){ this.brand = brand this.price = price } Phone.prototype.call = function(){ console.log("我可以打电话") } //子类 function SmartPhone(brand,price,color,size){ Phone.call(this,brand,price) this.color = color this.size = size } //设置子级构造函数的原型 SmartPhone.prototype = new Phone SmartPhone.prototype.constructor = SmartPhone //声明子类的方法 SmartPhone.prototype.photo = function(){ console.log("我可以拍照") } SmartPhone.prototype.playGame = function(){ console.log("我可以玩游戏") }
ES6类的继承
class Phone{ constructor(brand,price){ this.brand = brand; this.price = price; } call(){ console.log("我可以打电话") } } class SmartPhone extends Phone{ constructor(brand,price,color,size){ super(brand,price)//相当于Phone.call(this,brand,price) this.color = color this.size = size } photo(){ console.log("拍照") } playGame(){ console.log("玩游戏") } }
-
子类对父类方法的重写
不能通过子类的成员中调用super来调用父类的方法
只能在子类中完全重写父类的方法 -
class中的getter和setter设置
class Phone{ get price(){ console.log("价格属性被读取了") } set price(newVal){ console.log("价格属性被修改了") } } let s = new Phone() s.price = 'free'
ES6的数据拓展
// Number.EPSILON是JavaScript表示的最小精度
// EPSILON属性的值接近于2.2204460492503130808472633361816E-16
理论上可以用来比较大小
function equal(a,b){
if(Math.abs(a-b)<Number.EPSILON){
return true
}else{
return false
}
}
//1.二进制和八进制
let b = 0b1010 //二进制0b开头表示
let o = 0o777 //八进制0o开头表示
let d = 100 //十进制直接写
let x = 0xff //十六进制用0x表示
//2.Number.isFinite检测一个数值是否为有限数
//3.Number.isNaN 检测一个数值是否为NaN
//4.Number.parseInt Number.parseFloat字符串转整数
//5.Number.isInteger判断一个数是否为整数
//6.Math.trunc将数字的小数部分抹掉
//7.Math.sign 判断一个数到底为正数(返回1) 负数(返回-1) 还是0(返回0)
对象方法拓展
//1.Object.is判断两个对象是否完全相等
console.log(Object.is(120,120))//true
console.log(Object.is(NaN,NaN))//true
console.log(NaN===NaN)//false
//2.Object.assign 对象的合并
Object.assign(obj1,obj2)
//如果属性出现重名,合并后面参数会把前面参数覆盖
//如果属性原本其中一个没有,那么合并后会加上
//3.Object.setPrototypeOf 设置原型对象 Object.getPrototypeOf获取原型对象
ES6的模块化
模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来
-
模块化的好处
- 防止命名冲突 - 代码复用 - 高维护性
-
ES6之前的模块化规范产品
规范=>规范对应的产品 CommonJS =>NodeJS、Browserify AMD=>requireJS CMD=>seaJS
-
ES6模块化语法
模块功能主要由两个命令构成:export和import
export命令用于规定模块的对外接口
import命令用于输入其他模块提供的功能 -
简单试用
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script type="module"> import * as test from "./src/js/test.js" console.log(test) </script> </body> </html>
js代码:
export let name = "小A" export function getName(){ console.log("小A") }
-
暴露方式
分别暴露export let name = "小A" export function getName(){ console.log("小A") }
统一暴露
let name = "小A" function getName(){ console.log("小A") } export {name,getName}
默认暴露
export default{ name:"小A", getName(){ console.log("小A") } }
-
引用方式
通用方式导入import * as test from "./src/js/test.js"
解构赋值形式
import {name,getName} from "./src/js/test.js" import {name as personName ,getName} from"./src/js/test.js"//使用别名 import {default as test}from "./src/js/test.js"
简便形式(只能针对默认暴露使用)
import test form "./src/js/test.js"
-
使用ES6模块化的另一种方式
通过一个入口文件(通常是app.js)统一引入
然后html页面里面只写<script src = "./src/js/app.js" type = module></script>
-
ES6模块化代码在项目中的使用方式
通过babel进行转化,将ES6转化为ES51.安装工具 babel-cli babel-preset-env browserify(或者webpack) npm i babel-cli babel-preset-env browserify -D //-D代表开发依赖,即dev环境 2.转化(等号中间不要加空格) npx babel src/js -d dist/js --presets=babel-preset-env 3.打包 npx browserify dist/js/app.js -o dist/bundle.js
打包完了以后html里script的src要进行修改才能使用
ES7新特性
数组.includes(元素)
用于判断数组中是否含有某元素,返回boolean**
幂运算 2的10次方可以写成2**10
和Math.pow(2,10)
一样
ES8新特性
async和await
async和await两种语法结合可以让异步代码像同步代码一样
- async函数
async函数的返回值为promise对象
promise对象的结果由async函数执行的返回值决定
注意:async function fn(){ //返回一个字符串 //return '哈哈哈' //抛出错误,返回的结果是一个失败的promise对象 throw new Error("出错啦") } const result = fn() console.log(result)
1.如果代码中返回的结果不是一个promise类型的对象,运行时返回的结果也是一个成功的promise对象 2.如果代码中抛出错误,返回的结果是一个失败的Promise 3.如果代码中返回值设置的是Promise对象,返回结果就会跟我们自己返回的Promise一致
- await表达式
await必须要放在async函数中
await右侧的表达式一般为promise对象
await返回的是promise成功的值
await的promise失败了,就会抛出异常,需要通过try…catch捕获处理
示例:const p = new Promise((resolve,reject)=>{ //resolve("用户数据") reject("失败啦") }) //await要放在async函数中 async function main(){ try{ let result = await p//await返回的结果是promise对象成功的值 console.log(result) } catch(e){ console.log(e)//在catch里面可以得到失败的值 } }
- async await读取文件实践
const fs = require('fs') function readOneTxt(){ return new Promise((resolve,reject)=>{ fs.readFile('./one.txt',(err,data)=>{ if (err) reject(err) resolve(data) }) }) } function readTwoTxt(){ return new Promise((resolve,reject)=>{ fs.readFile('./two.txt',(err,data)=>{ if (err) reject(err) resolve(data) }) }) } function readThreeTxt(){ return new Promise((resolve,reject)=>{ fs.readFile('./three.txt',(err,data)=>{ if (err) reject(err) resolve(data) }) }) } async function main(){ let oneTxt = await readOneTxt() let twoTxt = await readTwoTxt() let threeTxt = await readThreeTxt() console.log(oneTxt.toString()) console.log(twoTxt.toString()) console.log(threeTxt.toString()) } main()
ES8对象方法拓展
获取对象所有的键Object.keys(对象)
获取对象所有的值Object.values(对象)
对象转二维数组(键值数组) Object.entries(对象)
,
键值数组: [[键1,值1],[键2,值2]...]
//方便创建map
const m = new Map(Object.entries(对象))
获取对象属性的描述对象Object.getOwnPropertyDescriptors(对象)
ES9 rest参数与spread扩展运算符
在ES6中已经引入了rest参数与spread扩展运算符,但是ES6只针对于数组,ES9中为对象提供了像数组一样的rest参数和扩展运算符
可以做对象的合并
ES9正则扩展
- 命名捕获分组
之前的写法:
现在的写法:let str = '<a href = "http://127.0.0.1/">本地服务器</a>' const reg = /<a href = "(.*)">(.*)<\/a>/ const result = reg.exe(str) console.log(result[1])//打印'http://127.0.0.1/' console.log(result[1])//打印'本地服务器'
let str = '<a href = "http://127.0.0.1/">本地服务器</a>' const reg = /<a href = "(?<url>.*)">(?<text>.*)<\/a>/ console.log(result.groups.url) console.log(result.groups.text) //好处是即使正则表达式结构变了也只要改表达式里的名字就行
- 反向断言
//声明字符串 let str = 'JS5211314你知道么555啦啦啦' //正向断言 //const reg = /\d+(?=啦)/ //const result = reg.exec(str) //反向断言 const reg = /(?<=么)/ const result = reg.exec(str) console.log(result)
- dotAll模式
//dot . 元字符 除换行字符以外的任意单个字符 //加匹配模式s以后.可以匹配任意字符 let str = ` <ul> <li> <a>肖申克的救赎</a> <p>上映日期: 1994-09-10</p> </li> <li> <a>阿甘正传</a> <p>上映日期: 1994-07-06</p> </li> </ul> ` const reg = /<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/gs let result let data = [] while(result = reg.exec(str)){ data.push({title:result[1],time:result[2]}) } console.log(data)
ES10
- 二维数组转对象
Object.fromEntries(二维数组)
- 字符串扩展方法
字符串.trimStart()
清除字符串左侧空白
字符串.trimEnd()
清除字符串右侧空白 - flat与flatMap
flat
将多维数组转低维数组const arr = [1,2,3,4,[5,6,[7,8,9]]]//这是一个三维数组 console.log(arr.flat())//转为二维数组 console.log(arr.flat(2))//转为一维数组 //参数是深度,是一个数字,默认是1
flatMap
是Map和flat操作的结合,可以直接将结果变为一维数组const arr = [1,2,3,4] const result = arr.flatMap(item = >{item*10}) console.log(result)
- Symbol的扩展
Symbol.prototype.description
获取字符串属性的描述
ES11
-
私有属性
属性前用#标记为私有class Person{ //公有属性 name //私有属性 #age #weight constructor(name,age,weight){ this.name = name this.#age = age this.#weight = weight } intro(){ console.log(this.name) console.log(this.#age) console.log(this.#weight) } } const girl = new Person('小红',18,'45kg') //console.log(girl.#age)无法获取 girl.intro();//可以获取
-
Promise.allSettled(promise对象数组)
方法
可以返回一个成功的Promise对象,对象的值是参数中每一个promise对象的判断结果和值
和Promise.all()
很像,但是Promise.all()
的参数数组只有全部成功才会返回成功的promise
他们两个通常都用来做批量异步任务 -
字符串扩展matchAll方法
用于批量提取数据(爬虫)let str = ` <ul> <li> <a>肖申克的救赎</a> <p>上映日期: 1994-09-10</p> </li> <li> <a>阿甘正传</a> <p>上映日期: 1994-07-06</p> </li> </ul> ` //声明正则 const reg = /<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/sg const result = str.matchAll(reg) //for(let v of result){ // console.log(v) //} const arr = [...result] console.log(arr)
-
可选链操作符
?.
以前的写法function main(config){ const dbHost = config&&config.db&&config.db.host//避免用户不传参数报错 console.log(dbHost) } main({ db:{ host:'192.168.1.101', username:'root' }, cache:{ host:'192.168.1.102', username:'admin' } })
现在的写法
function main(config){ const dbHost = config?.db?.host//免去层层判断 console.log(dbHost) } main()
-
动态import
实现了按需加载,使用的是import函数,这个函数参数是路径,返回结果是一个promise对象,这个对象成功的值是我们需要引入的模块暴露的对象。这样提高了加载的效率const btn = document.getElementById('btn') btn.onclick = function(){ import('./test.js').then(module=>{ module.myTest()//myTest是'./test.js'中暴露的函数 }) }
-
BigInt类型 大整型
主要用于大数值的运算注:不能跟普通整数运算
声明:let n = 521n
(在普通的整数后面加一个n)
普通整型转换为大整型:BigInt(整数)
//大数值运算 let max = Number.MAX_SAFE_INTEGER console.log(max) console.log(max+1) console.log(max+2) console.log(BigInt(max)) console.log(BigInt(max)+BigInt(1)) console.log(BigInt(max)+BigInt(2)) /* 输出: 9007199254740991 9007199254740992 9007199254740992 9007199254740991n 9007199254740992n 9007199254740993n */
-
绝对全局对象this
globalThis
这个对象始终指向全局对象
网页中指向window
nodeJS中指向global