摘要:本文主要学习了ECMAScript的基本知识。
1 简介 1.1 定义 ECMAScript是一种由ECMA组织(前身为欧洲计算机制造商协会)制定和发布的脚本语言规范。
JavaScript是ECMAScript的实现,一般情况下,ECMAScript和JavaScript表达的是同一个意思。
严格来说,JavaScript包含三个部分:
ECMAScript:核心,通用标准,简写为ES
DOM:文档对象模型,操作网页
BOM:浏览器对象模型,操作浏览器
1.2 历史版本 ES5:2009年发布 ES6:2015年发布,也称为ECMA2015 ES7:2016年发布,也称为ECMA2016 ES8:2017年发布,也称为ECMA2017 ES9:2018年发布,也称为ECMA2018 ES10:2019年发布,也称为ECMA2019
2 ES5 2.1 严格模式 在ES5中新增了严格模式,其作用是:
使得JS在更严格的条件下运行
消除JS语法的一些不合理、不严谨之处,减少一些怪异行为
消除JS代码运行的一些不安全之处,保证代码运行的安全
使用方式是在JS的第一行:
js
需要记住的几个变化:
声明定义变量必须用var
关键字:js
禁止自定义的函数中的this
关键字指向全局对象:js 1 2 3 4 5 'use strict' ;function Person (age ) { this .age = age } Person (18 );
创建eval
作用域:js 1 2 3 4 'use strict' ;var age = 16 ;eval ('var age = 18;' );console .log (age);
2.2 JSON支持 JSON是一种轻量级的数据交换模式,用于传输数据。
ES5提供了对JSON的支持:
js 1 2 3 4 5 6 7 8 9 10 11 var obj = { age : 18 } console .log (obj);console .log (typeof obj);var jsonStr = JSON .stringify (obj);console .log (jsonStr);console .log (typeof jsonStr);var jsonObj = JSON .parse (jsonStr);console .log (jsonObj);console .log (typeof jsonObj);
2.3 Object扩展 增加了一种创建对象的方式,支持通过将指定对象作为原型的方式创建对象:
js 1 2 3 4 5 6 7 var obj = { age : 18 } var newObj = {}console .log (newObj.__proto__ );newObj = Object .create (obj); console .log (newObj.__proto__ );
增加操作属性的方法:
js 1 2 3 4 5 var obj = { age : 18 } Object .defineProperty (obj, "age" , {value : 16 })console .log (obj.age );
2.4 Array扩展 查询元素在数组中的下标:
js 1 2 3 var arr = [1 , 2 , 3 , 2 , 1 ];console .log (arr.indexOf (2 ));console .log (arr.lastIndexOf (2 ));
遍历数组:
js 1 2 3 4 var arr = [1 , 2 , 3 , 2 , 1 ];arr.forEach (function (item, index ) { console .log ("[" + index + "]" , item); });
对数组进行处理:
js 1 2 3 4 5 var arr = [1 , 2 , 3 , 2 , 1 ];var newArr = arr.map (function (item, index ) { return item + 10 }); console .log (newArr);
对数组进行过滤:
js 1 2 3 4 5 var arr = [1 , 2 , 3 , 2 , 1 ];var newArr = arr.filter (function (item, index ) { return item > 1 }); console .log (newArr);
2.5 Function扩展 将函数的this对象修改为指定的对象:
js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 var age = 18 ;function fun (age ) { this .age = age; console .log (this + ' age = ' + this .age ); } fun (20 );console .log (age);var obj = {};var newFun = fun.bind (obj, 12 );console .log (obj.age );console .log (obj);newFun ();console .log (obj.age );console .log (obj);
也可以直接执行新方法,需要在方法后面增加()
,相当于call()
方法:
js 1 2 3 4 5 6 7 8 9 10 11 var age = 18 ;function fun (age ) { this .age = age; console .log (this + ' age = ' + this .age ); } fun (20 );console .log (age);var obj = {};fun.bind (obj, 16 )(); console .log (obj);
3 ES6 3.1 声明变量 使用let
关键字声明变量:
方式
作用域
重复声明
声明提升
使用var
关键字声明变量
属于全局变量
可以重复声明
存在变量提升
使用let
关键字声明变量
属于局部变量,会创建一个块级作用域
不能重复声明
不会预处理,不存在提升
使用const
关键字声明的变量被称为常量,和let
关键字类似,唯一的区别是不支持修改变量的值。
为了更好的区分常量,其标识符一般使用大写。
3.2 解构赋值 按照一定模式,从数组或者对象中提取值,对变量进行赋值,这被称为解构赋值。
对象解构可以同时获取对象多个属性,但是要求属性名一致,使用{}
包裹,按属性赋值:
js 1 2 3 4 5 6 7 8 let obj = { age :18 , sex :'男' }; let {age, sex} = obj;console .log (age, sex);let {age : objAge, sex : objSex} = obj;console .log (objAge, objSex);
数组解构可以同时获取多个元素,对变量名没有要求,使用[]
包裹,按下标顺序赋值:
js 1 2 3 let arr = [1 , 2 , 3 , 2 , 1 ];let [a, b, , , c, d] = arr;console .log (a, b, c, d);
3.3 模板字符串 使用模板字符串可以简化字符串的拼接,支持在字符串中使用变量、对象、表达式、方法的返回值。
对于模板字符串需要使用``
包裹,在字符串中的模板需要使用${}
包裹:
js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 let obj = { age :18 , sex :'男' }; console .log (`个人信息: 年龄:${obj.age} 性别:${obj.sex} 以上数据真实有效` );function fun ( ) { return "test" ; } console .log (`获取返回值:${fun()} ` )let arr = [1 , 2 , 3 , 2 , 1 ];console .log (`数组内容:${arr} ` );
3.4 简化对象 在定义对象时,可以直接写入变量和函数作为对象的属性方法,这样的书写更加简洁:
js 1 2 3 4 5 6 7 8 9 let age = 18 ;let sex = "男" ;let test = function ( ) {console .log ("test" )}let obj = { age, sex, test }; console .log (obj)
3.5 箭头函数 使用() => {}
箭头函数简化了函数的定义和调用,特点:
js 1 2 3 4 5 6 7 8 9 10 let fun1 = ( ) => console .log ("test" );fun1 ();let fun2 = str => "str = " + str;console .log (fun2 ("test" ));fun2 ('hello' );let fun3 = (age,sex ) => {let obj = {age, sex}; return obj};console .log (fun3 (18 ,"男" ));
3.6 扩展运算符 扩展运算符就是使用...变量名
作为变量,在特定场景下具有收集和扩展的功能。
使用扩展运算符的收集功能可以实现可变参数,必须将可变参数放在参数列表最后的位置:
js 1 2 3 4 function fun (a,b,...c ) { console .log (a,b,c); } fun (1 ,2 ,3 ,4 ,5 );
使用扩展运算符的扩展功能可以更加方便的操作数组:
js 1 2 3 4 let arr1 = [1 ,2 ,3 ];let arr2 = [4 ,5 ];let arr3 = [...arr1,...arr2];console .log (arr3);
还可以将伪数组转为真数组:
js 1 2 3 4 let home = document .getElementsByTagName ('div' );let arr = [...home];console .log (home);console .log (arr);
3.7 参数默认值 在定义函数时,支持设置参数的默认值,当没有传入参数时,会使用定义的默认值:
js 1 2 3 4 function fun (str = "test" ) { console .log ("hello" , str) } fun ();
3.8 Symbol 新增Symbol原始数据类型,用于解决命名冲突的问题,主要用于需要保证属性名唯一的场景。
Symbol属于第七种数据类型,其他六种是:Object,String,Number,Boolean,Null,Undefined。
创建Symbol类型的数据,因为不是对象,所以不能使用new关键字:
js 1 2 3 let s = Symbol ();console .log (s);console .log (typeof s);
支持在创建时传入参数作为标识符,支持其他类型数据,包括对象:
js 1 2 3 4 let s1 = Symbol ("test" );console .log (s1);let s2 = Symbol ({age :18 ,sex :"男" });console .log (s2);
在ES10中,增加了description
属性,用于获取传入的参数:
js 1 2 let s = Symbol ("test" );console .log (s.description );
即使创建了相同的Symbol数据,两个数据也是不同的,这就是Symbol的唯一性:
js 1 2 console .log (Symbol () == Symbol ());console .log (Symbol ("test" ) == Symbol ("test" ));
如果想要创建相同的数据,需要使用Symbol.for()
创建:
js 1 2 3 4 console .log (Symbol === Symbol .for ());console .log (Symbol .for () === Symbol .for ());console .log (Symbol === Symbol .for ("test" ));console .log (Symbol .for ("test" ) === Symbol .for ("test" ));
通过Symbol.for()
创建数据时会先从全局按照参数获取,如果获取到了就返回数据,如果没有获取到就会创建数据并注册到全局。
使用Symbol.keyFor()
获取全局中的参数:
js 1 2 let s = Symbol .for ("test" );console .log (Symbol .keyFor (s));
将Symbol作为对象的属性:
js 1 2 3 4 5 6 7 8 9 let name = Symbol ("name" );let obj = { [name]: "test" }; let sex = Symbol ("sex" );obj[sex] = '男' ; let age = Symbol ("age" );Object .defineProperty (obj, age, {value : 18 });console .log (obj);
虽然Symbol属性是共有属性,但是在遍历对象时,不会出现在for
循环中,也不会被Object的keys()
方法和getOwnPropertyNames()
方法获取,同样也不会被JSON.stringify()
返回。
可以通过Object的getOwnPropertySymbols()
方法获取,只能获取Symbol属性:
js 1 2 3 4 5 6 let obj = { [Symbol ("name" )]: "test" , [Symbol ("sex" )]: "男" , age : 18 }; console .log (Object .getOwnPropertySymbols (obj));
也可以使用Reflect.ownKeys()
方法获取所有类型的属性名:
js 1 2 3 4 5 6 let obj = { [Symbol ("name" )]: "test" , [Symbol ("sex" )]: "男" , age : 18 }; console .log (Reflect .ownKeys (obj));
3.9 Promise 引入Promise用于解决异步编程的问题,使用构造函数封装异步操作并可以获取其成功或失败的结果。
在执行完成后,Promise的状态会变成fulfilled(成功)或者rejected(失败),这种改变称为resolved(定型),并且一旦发生定型,结果就不会再次发生改变。
创建对象:
js 1 2 3 4 5 6 7 8 9 10 11 12 let promise = new Promise (function (resolve, reject ) { let value; let error; let result = true ; if (result){ resolve (value); } else { reject (error); } });
执行异步操作:
js 1 2 3 4 5 p.then (function (value ){ console .log (value); }, function (error ){ console .log (error); });
捕获异步操作中的异常:
js 1 2 3 p.catch (function (reason ){ console .log (reason); });
3.10 Iterator 迭代器Iterator是一种接口,为各种不同的数据结构提供统一的访问机制,任何数据结构只要部署了Iterator接口就可以完成遍历操作。
可以使用新的遍历命令for...of
循环,部署了Iterator接口的数据接口可以通过for...of
循环进行遍历。
和for...in
循环相比,通过for...of
循环的是value键值,而for...in
循环的是index键名。
原生具备Iterator接口的数据,即不需要改动就可以使用for...of
循环的有:Array、Arguments、Set、Map、String、TypedArray、NodeList。
非原生的数据可以通过自定义Iterator接口使用for...of
循环。
原生Iterator接口:
js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 let names = ['张三' , '李四' , '王五' ];for (let index in names) { console .log (index + " " + names[index]); } for (let value of names) { console .log (value); } let iterator = names[Symbol .iterator ]();for (var item = iterator.next (); item.done != true ; item = iterator.next ()) { console .log (item); } console .log (item);
自定义Iterator接口:
js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 let person = { name : "张三" , home : ['北京市' , '北京市' , '东城区' ], [Symbol .iterator ](){ let index = 0 ; let _this = this ; return { next : function ( ){ if (index < Object .keys (_this).length ){ let result = { value : _this[Object .keys (_this)[index]], done : false } index ++; return result; }else { return { value : undefined , done : true } } } } } } let iterator = person[Symbol .iterator ]();for (var item = iterator.next (); item.done != true ; item = iterator.next ()) { console .log (item); } console .log (item);
3.11 Generator 生成器Generator是一种异步编程解决方案,语法行为与传统函数完全不同。
在创建时需要使用*
符号创建,用于和普通函数区分:
js 1 2 3 function * gen ( ){ console .log ("hello" ); }
在调用时返回的是迭代器Iterator对象,所以需要使用next()
方法调用:
js 1 2 let iterator = gen ();iterator.next ();
在创建时,可以使用yield
对函数中的内容进行分割,在调用next()
方法执行时,会按照yield
分割执行,并返回yield
后面的值:
js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 function * gen ( ){ console .log ("hello1" ); yield 1 console .log ("hello2" ); yield 2 console .log ("hello3" ); } let iterator = gen ();console .log (iterator.next ());console .log (iterator.next ());console .log (iterator.next ());
在调用时,支持传入参数,需要在方法中接收yield
的值:
js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 function * gen (arg ){ console .log (arg); let arg1 = yield 1 console .log (arg1); let arg2 = yield 2 console .log (arg2); } let iterator = gen ("arg1" );console .log (iterator.next ());console .log (iterator.next ("arg2" ));console .log (iterator.next ("arg3" ));
3.12 Set 新增Set对象用于存储不重复的数据列表,默认实现了Iterator接口,支持存储不同类型的数据。
使用:
js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 let s = new Set ();s.add (1 ); s.add ('2' ); let arr = [3 , 4 , 5 ]s.add (arr); console .log (s);console .log (s.has (arr));console .log (s.size );s.forEach (v => console .log (v)); s.delete (arr); console .log (s);s.clear (); console .log (s);
3.13 Map 新增Map对象用于存储键值对,默认实现了Iterator接口,支持存储不同类型的键和值。
Map和Object一样,都可以存储对象的属性名和属性值,区别是Object的属性名只能是String类型或Symbol类型,而Map的键可以使任意类型。
使用:
js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 let m = new Map ();m.set (1 , 1 ); m.set ('2' , '2' ); let arr = [3 , 4 , 5 ]m.set (arr, arr); console .log (m);console .log (m.get (arr));console .log (m.has (arr));console .log (m.size );m.forEach ((k, v ) => console .log (k + ' = ' + v)); m.delete (arr); console .log (m);m.clear (); console .log (m);
3.14 Class 引入了类的概念,作为对象的模板,需要使用class
关键字声明。
使用:
js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 class Human { constructor (name ) { this .name = name; } hello ( ) { console .log ("我是" , this .name ); } test ( ) { console .log ("父类" ); } home ( ) { console .log ("地球" ); } static eat = "食物" ; set age (age ) { console .log ("设置年龄" , age); } get age () { console .log ("读取年龄" ); return 100 ; } } class Worker extends Human { work ( ) { console .log ("工作" ); } test ( ) { console .log ("子类" ); super .home (); } } let h = new Human ("人类" );h.hello (); console .log (h.name );console .log (h.eat );console .log (Human .eat );let w = new Worker ("工人" );w.hello (); w.work (); w.test (); h.age = 100 ; h.age ;
3.15 数值扩展 引入了二进制和八进制的新写法:
js 1 2 console .log (0b100 );console .log (0o100 );
定义最小精度,其值接近于2.22×10^(-16),即2.22乘以10的-16次方。
当无法准确的描述数值时,就会产生精度问题,比如无法通过二进制准确的表示0.1,再比如无法通过十进制表示1/3,等等。
当两个数的差值小于Number.EPSILON时,就认为两个数值是相等的:
js 1 2 3 4 5 console .log (0.1 + 0.2 === 0.3 );function equal (left, right ) { return Math .abs (left - right) < Number .EPSILON ; } console .log (equal (0.1 + 0.2 , 0.3 ));
检测数值是否是有限数:
js 1 2 console .log (Number .isFinite (1 ));console .log (Number .isFinite (1 /0 ));
检测数值是否为NaN:
js 1 2 3 console .log (Number .isFinite (1 ));console .log (Number .isFinite (NaN ));console .log (Number .isFinite (null ));
检测数值是否为整数:
js 1 2 console .log (Number .isInteger (1 ));console .log (Number .isInteger (1.1 ));
将字符串转为整数和浮点数:
js 1 2 console .log (Number .parseInt ("123test456" ));console .log (Number .parseFloat ("0.123test456" ));
检测数值是整数、负数还是零:
js 1 2 3 console .log (Math .sign (10 ));console .log (Math .sign (0 ));console .log (Math .sign (-10 ));
将数值的小数部分抹掉:
js 1 console .log (Math .trunc (1.1 ));
3.16 对象方法扩展 判断两个值是否完全相等:
js 1 2 3 console .log (Object .is (10 , 10 ));console .log (Object .is (NaN , NaN ));console .log (NaN === NaN );
对象的合并,当旧对象中有新对象中没有的时候,会进行合并,否则会直接覆盖:
js 1 2 3 4 5 6 7 8 9 let oldObj = { name : '张三' , sex : '男' } let newObj = { name : '李四' , age : 18 } console .log (Object .assign (oldObj, newObj));
操作原型对象:
js 1 2 3 4 5 6 7 8 9 10 let human = { eat : '食物' } let worker = { work : '打工' } console .log (worker.__proto__ );Object .setPrototypeOf (worker, human);console .log (worker.__proto__ );console .log (worker.__proto__ == Object .getPrototypeOf (worker));
3.17 模块化 3.17.1 说明 模块化是指将一个大的程序文件拆成许多小的文件,然后进行组合。
优势:
防止命名冲突:不同的模块之间可以使用相同名称的变量,彼此互不干扰。
代码复用:模块可以对外提供接口,相同的功能可以使用同一接口。
高维护性:模块之间独立运行,单个模块出现问题不会影响所有模块,模块支持单独升级。
模块化规范比较:
专用于服务器端,默认不支持在浏览器执行。
在服务器端使用,基于Node.js使用。 在浏览器端使用,使用Browserify编译打包JS文件,这个工具也是JS常用的打包工具。
专用于浏览器端,模块的加载时异步的。
在浏览器端使用,基于Require.js使用。
专用于浏览器端,模块的加载时异步的,并且在模块使用时才会加载和执行。
在浏览器端使用,基于Sea.js使用。
专用于浏览器端。
在浏览器端使用,使用Babel将ES6编译为兼容ES5的代码,使用Browserify编译打包JS文件。
3.17.2 导出方式 使用export
关键字将变量或方法导出。
分别导出,在JS文件中分别指定导出的变量或方法:
test.js 1 2 3 4 export let hello = "hello" ;export function test ( ) { console .log ("test" ); }
统一导出,使用export
关键字要导出的变量和方法集中导出:
test.js 1 2 3 4 5 let hello = "hello" ;function test ( ) { console .log ("test" ); } export {hello, test}
统一导出提供的并不是对象,所以导出的不是对象的简写形式,而是导出的标记,可以认为是名称。
默认导出,将要导出的变量和方法封装为对象:
test.js 1 2 3 4 5 6 7 8 let hello = "hello" ;function test ( ) { console .log ("test" ); } export default { hello, test }
默认导出提供的是对象,导出的内容是对象的简写形式,这一点和统一导出不同。
3.17.3 导入方式 使用import
关键字将其他模块导出的变量或方法导入进来,同时设置script
元素的type
属性的值为module
表示引入的是模块JS文件,并不是普通的JS文件。
全部导入,使用*
将导出的全部变量和方法导入到页面:
test.html 1 2 3 4 5 <script type ="module" > import * as test from "./test.js" ;console .log (test.hello );test.test (); </script >
命名导入,指定导入的变量和方法:
test.html 1 2 3 4 5 <script type ="module" > import {hello, test} from "./test.js" ;console .log (hello);test ();</script >
使用命名导入可以使用分别导出和统一导出的变量和方法,不能直接使用默认导出的变量和方法。
默认导入,可以使用默认导出的变量和方法:
test.html 1 2 3 4 5 6 7 8 <script type ="module" > import test from "./test.js" ;console .log (test.hello );test.test (); </script >
如果默认导出的只有一个变量或方法,在默认导入时导入的就是该变量或方法,不需要通过对象获取。
如果有大量模块需要引入,可以新建JS文件用于引入模块,然后将此文件引入到HTML文件:
app.js 1 import * as test from "./test.js" ;
在HTML文件中引入JS文件:
test.html 1 <script src ="./app.js" type ="module" > </script >
4 ES7 4.1 数组增强 判断数组是否包含某个数据:
js 1 2 3 let nums = [1 , 2 , 3 ];console .log (nums.includes (1 ));console .log (nums.includes (4 ));
4.2 指数操作符 引入**
指数运算符,用来实现幂运算,功能与Math.pow
结果相同:
js 1 2 console .log (2 ** 4 );console .log (Math .pow (2 , 4 ));
5 ES8 5.1 async和await 5.1.1 async函数 async函数会将返回值封装为Promise对象:
js 1 2 3 4 5 async function fun ( ) { console .log ("fun" ); } let result = fun ();console .log (result);
当函数执行成功时返回的是fulfilled状态的Promise对象,当函数执行失败时返回的是rejected状态的Promise对象。
当函数返回的是Promise对象时,不会再次封装,会将返回对象直接返回。
5.1.2 await表达式 await表达式必须写在async函数中,并且await右侧的表达式一般为Promise对象。
await返回的是Promise成功的值,需要使用手动捕获Promise失败的值。
使用:
js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 let promise = new Promise (function (resolve, reject ) { console .log ("promise" ); if (true ){ resolve ("success" ); } else { reject ("error" ); } }); async function fun ( ) { console .log ("fun" ); try { let result = await promise; console .log (result); } catch (e) { console .log (e); } } let result = fun ();console .log (result);
5.2 对象方法扩展 获取对象的属性名和属性值:
js 1 2 3 4 5 6 7 8 9 10 11 let person = { name : "test" , sex : "男" }; console .log (Object .keys (person));console .log (Object .values (person));console .log (Object .entries (person));let map = Object .entries (person);map.forEach (obj => console .log (obj));
获取对象属性信息:
js 1 2 3 4 5 6 7 8 let person = { name : "test" , sex : "男" }; console .log (Object .getOwnPropertyDescriptors (person));
6 ES9 6.1 Rest和Spread rest参数与spread扩展运算符在ES6中已经引入,不过ES6中只针对于数组。
使用rest参数:
js 1 2 3 4 5 6 7 8 9 10 11 function test ({...args} ) { console .log (args); } test ({ name : "张三" , sex : "男" , });
使用spread扩展运算符:
js 1 2 3 4 5 6 7 8 9 10 11 let attr1 = { name : "张三" } let attr2 = { sex : "男" } let attr3 = { age : "18" } let person = {...attr1, ...attr2, ...attr3}console .log (person);
6.2 正则扩展 6.2.1 捕获分组 ES9允许使用符号?<name>
获取捕获结果,可读性更强。
在ES9之前捕获结果,通过下标查看捕获分组,下标为0的元素是完整的匹配内容:
js 1 2 3 4 5 6 7 var reg = /(123)(a.a)/g ;var result;while (result = reg.exec ('123a4a123a5a' )) { console .log (result[1 ], result[2 ]); }
在ES9之后捕获结果:
js 1 2 3 4 5 6 7 var reg = /(?<first>123)(?<last>a.a)/g ;var result;while (result = reg.exec ('123a4a123a5a' )) { console .log (result.groups .first , result.groups .last ); }
6.2.2 反向断言 通过正则表达式的?=
符号进行正向断言,根据后面的判断是否返回前面的数据:
js 1 2 3 4 let test = '测试123正向456断言' ;let reg = /\d+(?=正向)/ ;let result = reg.exec (test);console .log (result[0 ]);
通过正则表达式的?<=
符号进行反向断言,根据前面的判断是否返回后面的数据:
js 1 2 3 4 let test = '测试123反向456断言' ;let reg = /(?<=反向)\d+/ ;let result = reg.exec (test);console .log (result[0 ]);
6.2.3 dotAll模式 使用.
匹配除回车外的任何单字符,如果使用了s
就可以匹配包括回车在内的任何单字符:
js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 let test = ` <ul> <li> <a>这是第1个a标签</a> <p>这是第1个p标签</p> </li> <li> <a>这是第2个a标签</a> <p>这是第2个p标签</p> </li> </ul> ` ;var reg = /<a>(.*?)<\/a>\s+<p>(.*?)<\/p>/g ;var result;while (result = reg.exec (test)) { console .log (result[1 ] + ' >>> ' + result[2 ]); } var reg = /<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/g s;while (result = reg.exec (test)) { console .log (result[1 ] + ' >>> ' + result[2 ]); }
7 ES10 7.1 创建对象 通过二维数组创建对象:
js 1 2 3 4 5 let person = Object .fromEntries ([ ['name' , '张三' ], ['sex' , '男' ] ]); console .log (person);
通过Map创建对象:
js 1 2 3 4 5 let map = new Map ();map.set ('name' , '张三' ); map.set ('sex' , '男' ); let person = Object .fromEntries (map);console .log (person);
Object类的fromEntries()
方法是entries()
方法的反向操作。
7.2 字符串扩展 新增支持清除字符串空格的方法:
js 1 2 3 let str = ' hello ' ;console .log (str.trimStart ());console .log (str.trimEnd ());
7.3 数组扩展 将高维数组转为低维数组,支持设置向下转变的维度数目,默认向下转变1个维度:
js 1 2 3 4 5 var arr = [1 ,2 ,[3 ,4 ]];console .log (arr.flat ());var arr = [1 ,2 ,[3 ,4 ,[5 ,6 ]]];console .log (arr.flat ());console .log (arr.flat (2 ));
在map()
方法的基础上,增加了flatMap()
方法,用于将结果向下维度转换处理:
js 1 2 3 var arr = [1 ,2 ];var result = arr.flatMap (item => [item * 10 ]);console .log (result);
7.4 Symbol扩展 支持在创建Symbol对象的时候传入描述内容:
js 1 2 var s = Symbol ('测试' );console .log (s.description );
8 ES11 8.1 私有属性 在属性前面添加#
符号表示该属性是私有属性:
js 1 2 3 4 5 6 7 8 9 10 11 class Person { name; #age; constructor (name, age ) { this .name = name; this .#age = age; } } let p = new Person ('张三' , 18 );console .log (p);console .log (p.#age);
8.2 Promise扩展 新增Promise的allSettled()
静态方法,接收Promise数组作为入参,将结果封装为Promise返回,状态为成功,值为数组的每个Promise执行的状态和结果:
js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 let p1result = false ;let p1 = new Promise ((resolve, reject ) => { setTimeout (() => { if (p1result) { resolve ("p1成功" ); } else { reject ("p1失败" ); } }, 100 ); }); let p2result = true ;let p2 = new Promise ((resolve, reject ) => { setTimeout (() => { if (p2result) { resolve ("p2成功" ); } else { reject ("p2失败" ); } }, 100 ); }); Promise .allSettled ([p1, p2]).then (function (value ){ console .log ("allSettled执行成功" ); value.forEach ((result ) => console .log (result)); }, function (error ){ console .log ("allSettled执行失败 " + error); }); Promise .all ([p1, p2]).then (function (value ){ console .log ("all执行成功" ); value.forEach ((result ) => console .log (result)); }, function (error ){ console .log ("all执行失败 " + error); });
和Promise的all()
静态方法不同,allSettled()
方法不论数组里的结果是否成功,始终返回成功,all()
会在数组里的结果存在失败时,返回失败。
8.3 字符串扩展 新增字符串matchAll()
方法,用于正则表达式,其结果和正则表达式的exec()
方法相同:
js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 var reg = /(123)(a.a)/g ;var matchResult = '123a4a123a5a' .match (reg);console .log (matchResult);var matchAllResult = '123a4a123a5a' .matchAll (reg);for (let r of matchAllResult) { console .log (r); } var execResult;while (execResult = reg.exec ('123a4a123a5a' )) { console .log (execResult); }
8.4 可选链操作符 使用?.
可选链操作符可以代替繁琐的层级判断是否为空的操作:
js 1 2 3 4 5 6 7 8 9 10 11 12 13 function test (config ) { console .log (config.db .url ); console .log (config && config.cache && config.cache .url ) console .log (config?.cache ?.url ) } test ({ db : { url : '192.168.1.10' } });
8.5 模块化扩展 在导入模块时支持动态导入,可以实现按需加载模块,即在用到某个模块时再导入,而不是在加载时全部导入,可以提高加载效率。
使用import()
方法传入文件路径即可导入指定文件,返回Promise对象,该对象的值是文件对应的导出的对象:
test.html 1 2 3 4 5 6 7 8 9 10 11 12 <script type ="module" > let btn = document .getElementById ('btn' );btn.onclick = function ( ) { import ("./test.js" ).then (test => { console .log (test.hello ); test.test (); }); } </script >
8.6 BigInt 新增数据类型BigInt用于表示大整型数字:
js 1 2 3 4 5 6 7 8 9 10 11 12 let n = 1024n ;console .log (n);console .log (typeof n);console .log (BigInt (0 ));let max = Number .MAX_SAFE_INTEGER ;console .log (max + 1 );console .log (max + 2 );console .log (BigInt (max) + BigInt (1 ));console .log (BigInt (max) + BigInt (2 ));
8.7 绝对全局对象 新增全局变量globalThis
指向全局变量:
js 1 console .log (globalThis);
条