ES6汇总
声明方法
1、let 命令
(1) let 声明的变量只在所在代码块有效,在同个块级作用域不允许重复声明
(2) 不存在变量提升,子块级作用域重复声明变量后不影响上级变量的值
(3) let 存在在暂时性死区,即在声明变量后才能使用变量
2、const 命令
(1) 拥有let的属性
(2) 对于非对象或者非数组的变量进行声明后,变量为只读
(3) 对于数组或者对象可以通过Object.freeze(变量),实现子属性只读
3、类声明class
(1) 只是一种语法糖,不具备面向对象的语言那样的特性
(2) getters声明 、setters声明将方法当变量使用
//声明类
class Book{
//构造器,在new的时候执行
constructor(name){
this._author = author;
},
// getter
get writer(){
return this._author;
}
// setter
set writer(updatedAuthor){
this._author = updatedAuthor;
}
// 等价于 Book.prototype.show = function(){ }
show(){
return this._author
}
}
const book1 = new Book ('anonymous');
console.log(book1.writer); // anonymous
book1.writer = 'wut';
console.log(book1.writer); // wut
//继承
class FaceBook extends Book{
constructor(name){
//调用父类构造器
super()
}
}
数据类型
1、Symbol类型
提供唯一性的值
(1) 等值性
let a = Symbol();
console.log(typeof a);//symbol
let b = Symbol();
console.log(a==b,a===b);//false false
//有则取没有则创建
let a = Symbol.for('my');
let b = Symbol.for('my');
console.log(a==b,a===b);//true true
(2) 用作私有属性,在let of 中不会被遍历到
let a = Symbol.for('my');
let obj = {
[a]:'qiang',
age:18
}
for(let [key,value] of Object.entries(obj)){
console.log(key,value);
}
(3) 获取私有属性方法
//获取所有私有属性
Object.getOwnPropertySymbols(obj)
//获取对象所有属性
Reflect.ownKeys(obj)
2、Set集合
类似于没有重复值的数组
(1) 初始化
let setList = new Set(); //{}
let setList = new Set([1,2,1]); //{1, 2}
(2) 属性方法
setList.add(1); //插入
setList.size; //长度
setList.delete(1); //删除
setList.clear(); //清空
set.has(arg); //判断存在
3、Map映射
类似于对象, key可以为任何类型
(1) 初始化
let mapList = new Map();
mapList.set('name','zhangsan'); //{"name" => "zhangsan}
let mapList = new Map([
['name','zhangsan'],
['age',18]
]); //{"name" => "zhangsan", "age" => 18}
(2) 属性方法
mapList.set('count',90); //插入或者修改
mapList.get('count'); //获取
mapList.size; //长度
mapList.delete('count'); //删除
mapList.clear(); //清空
mapList.has(arg); //判断key存在
for(let key of mapList.keys()){
console.log(key);
} //name age
for(let value of mapList.values()){
console.log(value);
} //zhangsan 18
for(let [key,value ]of mapList.entries()){
console.log(key,value);
}
访问代理
1、Proxy
用来更改对象的默认处理方法
let target = {};
//创建访问代理
let newTarget= new Proxy(target, handler);
//其中代理事件handler可能有
{
// 在读取代理对象的原型时触发该操作
getPrototypeOf(),
// 在设置代理对象的原型时触发该操作
setPrototypeOf(),
// 在判断一个代理对象是否是可扩展时触发该操作
isExtensible(),
// 在让一个代理对象不可扩展时触发该操作
preventExtensions(),
// 在获取代理对象某个属性的属性描述时触发该操作,比如在执行
getOwnPropertyDescriptor(),
// 在定义代理对象某个属性时的属性描述时触发该操作
defineProperty(),
// 在判断代理对象是否拥有某个属性时触发该操作,比如在执行 "foo" in proxy 时。
has(target,key),
// 在读取代理对象的某个属性时触发该操作,比如在执行 proxy.foo 时。
get(target, key, proxy),
// 在给代理对象的某个属性赋值时触发该操作,比如在执行 proxy.foo = 1 时。
set(target, key, value, proxy),
// 在删除代理对象的某个属性时触发该操作,比如在执行 delete proxy.foo 时。
deleteProperty(target,key),
// 在获取代理对象的所有属性键时触发该操作,比如在执行 Object.getOwnPropertyNames(proxy) 时。
ownKeys(target),
// 在调用一个目标对象为函数的代理对象时触发该操作,比如在执行 proxy() 时。
apply(),
// 在给一个目标对象为构造函数的代理对象构造实例时触发该操作,比如在执行new proxy() 时。
construct()
}
2、Reflect
调用对象的默认处理方法,通常结合Proxy一起使用在拦截默认行为后再调用默认处理方法保证不会出错
//Reflect拥有Proxy代理的所有事件
let newTarget= new Proxy(target, {
get (target, key, proxy){
return Reflect.get(target,key,proxy)
},
set (target, key, value, proxy) {
if (key === 'age') {
target[key] = value > 0 && value < 100 ? value : 0
}
return Reflect.set(target, key, value, proxy);
}
});
解构赋值
1、将复合类型变量转化成多个变量
//获得对象 左边也需对象
const voxel = {x: 3.6, y: 7.4, z: 6.54 };
//直接获得对象的成员属性,名称要一致
const { x, y, z } = voxel;
//别名的方式
const { x : a, y : b, z : c } = voxel;
//允许默认值
const {x, g = 'b'} = voxel; // x=3.6, g='b'
//部分分组
const {name,...c} = obj = { name:'zhangsan', age:18, co:12}; //c = {age:18, co:12}
//嵌套方式
const a = {
start: { x: 5, y: 6},
end: { x: 6, y: -9 }
};
const { start : { x: startX, y: startY }} = a;
//在定义函数中使用参数为对象时,用来接收属性
const fun= ({ x, y, z}) => {
// 函数操作
}
fun(voxel);
//获得数组 左边也需数组
const [a, b] = [1, 2, 3, 4, 5, 6];
const [a, b,,, c] = [1, 2, 3, 4, 5, 6];
const [a, b, ...arr] = [1, 2, 3, 4, 5, 6];
字符串
1、字符串模板
(1) 用反引号标识一段文本
(2) 可以在${}内插入变量或者执行函数
(3) 可以自由换行
const greeting = `Hello, my name is ${person.name}!
I am ${person.age} years old.`;
2、字符串函数
(1) includes(*
)判断是否包含字符* 可用于数组
(2) startsWith(**
)判断是否以**
为起始
(3) endsWith(**
)判断是否以**
为结束
(4) repeat(num)复制字符串num次
计算相关
1、判断
(1) Number.isFinite(val) 是不是 不是无穷大
(2) Number.isNaN(val) 是不是 不是一个数
(3) Number.isInteger(val) 是不是 一个整数
(4) Number.isSafeInteger(val) 是不是 安全
(5) Math.sign(val) 正数1 负数-1 0是0
2、计算
(1)Math.cbrt(val) 求立方根
数组扩展
1、Spread展开运算符 ...
将数组打散,只能用在参数或者数组项中
console.log(1, ...[2, 3, 4], 5) //1 2 3 4 5
2、REST剩余运算符 ...
将参数剩余部分转化成数组, REST参数只能在声明的结尾处使用
function say(a, ...args) {
return args;
}
say(1,2,3,4); // [2,3,4]
3、Array.of
Array.of(arg1,arg2,,,) 生成数组
console.log(Array.of(1,2,'1','2'));//[1,2,'1','2']
//或者用来遍历
let arr = Array.from([1,2,3],function(item){
return item*2;
}) //[2, 4, 6]
4、arr.fill
arr.fill(arg1,start,end) 数组元素替换
[0,1,2, 3,4,5, 6].fill(7);//[7,7,7,7,7,7,7]
[0,1,2, 3,4,5, 6].fill(7,1,3);//[0,7,7,7,4,5,6]
5、let...of遍历
let arr = ['1','2','3'];
for(let index of arr.keys()){
console.log(index);
}//0 1 2
for(let value of arr){
console.log(value );
}//1 2 3
for(let value of arr.values()){
console.log(value );
}//1 2 3
for(let [index,value] of arr.entries()){
console.log(index+'+'+value);
}//0,1 1,2 2,3
6、arr.find
arr.find(function(item){return boolearn;}) 在arr中查找符合条件的元素,返回第一个符合条件的元素
arr.findIndex() 是返回下标
let arr = [1,2,3,4,5,6,NaN];
console.log(arr.find(function(item){
return item>3;
}));//4
对象扩展
1、属性简写
let a = 3,b = 5;
let obj = {a,b}; //{a: 3, b: 5}
2、属性方法的简写
let obj = {
add(a,b){
return a+b;
}
}
3、key用变量
let a = 'name';
let obj = {
[a]:'zhangsan'
}
4、let of遍历
let obj = {
name:'zhangsan',
age:18
}
for(let [key,value] of Object.entries(obj)){
console.log(key+":"+value);
}
5、Iterator 遍历器
(1) 统一的数据遍历接口可供for of 直接遍历,或者使用next()进行遍历
(2) 默认支持的类型有Array、Map、Set、String、TypedArray、函数的arguments对象、NodeList 对象
(3)实现自定义的Iterator 遍历器
let obj = {
name:'zhangsan',
age:18,
count:[{yuWen:80},{huaXue:90}],
//添加Symbol.iterator属性
[Symbol.iterator](){
let index = 0;
let map = new Map();
for(let key in obj){
map.set(key,obj[key]);
}
let arr = Array.from(map);
return {
//包含next方法
next(){
if(index<arr.length){
//返回一个{value:xxx,done:boolean}
return {
value:arr[index++][1],
done:false
}
}else{
return {
value:undefined,
done:true
}
}
}
}
}
}
for(let value of obj){
console.log(value);
} zhangsan 18 [{…}, {…}]
函数相关
1、函数默认值
function say(who, sth = 'hello') {
return `${who} say ${sth}`;
}
2、箭头函数
this取决于上一级作用域
const myFunc = (item ) => {
const myVar = item * 2;
return myVar;
}
//简写 不能返回{}会被识别为函数体
const myFunc = (item) => item * 2;
异步编程
1、Generator 生成器函数
遍历器生成函数
(1) 通过function* 来声明是生成器函数
(2) yield 断点和next执行
let tell = function* (){
//当程序执行到yield时候会暂停执行,需要执行next()才会到达下个yield
yield 1;
yield 2;
yield 3;
}
let k = tell();
//当执行next时会返回上个yield表达式的值,并跳到下个yield
//done状态只有找不到下个yield才返回true
console.log(k.next());//{value: 1, done: false}
console.log(k.next());//{value: 2, done: false}
console.log(k.next());//{value: 3, done: false}
console.log(k.next());//{value: undefined, done: true}
2、Promise 异步链式对象
可以将异步操作以同步操作的流程表达出来
(1) 基本状态 pending(进行中)、fulfilled(已成功)、rejected(已失败),且只有异步结果可以决定当前是哪一种状态
(2) 基本使用
//注意执行resolve或者reject时,同代码块的后续代码依然执行
new Promise((resolve, reject) => {
//todo 在执行new的时候 该代码块就会执行
if(1){
//执行resolve就会进入下个then的第一个函数 参数1会被携带
resolve(1);
//该代码会被执行
console.log(555);
} else{
//错误具有“冒泡”性质,会一直向后传递,直到被捕获为止,且只会被最近的捕获
//如果错误被正常捕获,则捕获后的then能正常执行
//例如定义了then的第二个函数捕获错误后 则后续then依然能正常进行
//一般不要使用第二个函数而是通过catch
//以下会中断执行会进入then的第二个函数或者进入catch
//执行reject
reject('error');
//抛异常
throw 'throw on onFulfilled_1';
//返回一个promise
return Promise.reject('error msg');
//返回一个空promise 则一直处于等待导致后面
}
}).then(
//第一个函数为执行成功的时候执行的方法
function (r) {
//then方法返回值若不是promise类型则默认会被转化为一个新的Promise实例(注意,不是原来那个Promise实例)
//原Promise对象的状态将跟新对象保持一致
return r+1; //2
},
//第二个函数为执行失败的时候执行的方法
//能捕获reject、throw
function (err){
console.log("rejected: ", err);
}
).then(()=>{
//内部能正常执行try catch
try{
JSON.parse([]);
} catch(e){
console.log('json error')
}
//返回空promise状态变成pending 使后续等待而无法执行
return new Promise(()=>{});
}).then(()=>{
console.log('stop test');
}).catch(err => {
//能捕获reject、throw
console.log('[catch]', err);
});
(3)简写用法
const p = Promise.reject('出错了').catch(e => {});
const p = Promise.resolve().then(e => {});
(4) Promise.all() 同时执行多个Promise并接收所有返回结果
Promise.all([
Promise.resolve().then(() => {
return 111;;
}),
Promise.resolve().then(() => {
return 222;
}),
//如果有异常且没被捕获则执行最近的catch不会进入then
Promise.reject(333),
//如果有异常且被捕获则then能获得所有返回值
Promise.reject(333).catch(a => {return a});
]
).then(result => {
//result为所有结果的数组集合
console.log('result:',result)}
).catch(
//按照最近原则,Promise项有自己的异常捕获则下面代码不执行
e => {console.log(e)}
);
(5) Promise.race() 同时执行多个Promise并只返回最早执行完毕的Promise
Promise.race([
new Promise((resolve, reject) =>{
setTimeout(()=>{
resolve(1111)
},300)
}).then(() => { return 111; }),
//这个会先执行
Promise.resolve().then(() => {
return 222;
}),
Promise.reject(333).catch(a => {})
]).then(result => {
console.log('result:',result)
}).catch(e => {console.log(e)});
(6)缺点:
无法中途取消。
如果不设置回调函数,Promise
内部抛出的错误,不会反应到外部。
Module 模块
1、export
使外部能够读取模块内部的某个变量或者方法,需要在最顶层作用域使用如文件尾部
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;
function f() {}
export {firstName};
export {lastName};
export {year};
export {f};
//等价于
export { firstName, lastName, year };
//重命名
export { firstName as first, lastName as last, year };
//匿名输出 f对外不可见 且export default 后面只能接对象、函数或者class
export default f;
//一个文件可以同时拥有一个export default 和多个export
//整体输出别的模块
export * from 'my_module';
2、import
通过这个命令加载export输出的模块
(1)使用
//解构获取
import { firstName, lastName, year } from './profile.js'
//重命名
import { lastName as surname } from './profile.js';
//直接执行模块里所有代码
import './profile.js';
//整体获取
import * as msg from './profile.js';
msg.firstName
//使用export default 可用
import msg from './profile.js';
//同时使用export default 和export
import year, { firstName, lastName} from './profile.js';
(2)import 是静态执行,所以不能使用表达式和变量
(3)import 命令具有提升效果,在当前文件下可以先执行再import
3、模块继承
//获取别的模块然后export
export * from 'circle';
export var e = 2.71828182846;
export default function(x) {
return Math.exp(x);
}
ES7
计算相关
1、计算
(1) 次方运算 **
3 ** 2 //9
数组扩展
1、includes
使用===判断是否存在,注意两个特殊情况
['a', 'b', 'c', 'd'].includes('b') // true
//第二个参数为起始查找位置
['a', 'b', 'c', 'd'].includes('b', 1) // true
//注意NaN == NaN、 +0 == -0
ES8
字符串
1、字符串函数
(1)padStart、padEnd 字符串补全,当length超过大于字符串长度才有效
//前面补全
'es8'.padStart(5); // ' es8'
'es8'.padStart(6, 'woof'); // 'wooes8'
'es8'.padStart(7, '0'); // '0000es8'
//后面补全
'es8'.padEnd(5); // 'es8 '
'es8'.padEnd(6, 'woof'); // 'es8woo'
'es8'.padEnd(7, '6'); // 'es86666'
对象扩展
1、Object.values 、Object.entries
获得对象值的数组
//注意键都是数字则按键名排序
const obj = { x: 'xxx', y: 1 };
//获取键
Object.keys(obj); // ['x', 'y']
//获取值
Object.values(obj); // ['xxx', 1]
//获取键值对
Object.entries(obj); // [['x', 'xxx'], ['y', 1]]
//结合let of进行对象遍历
for (let key of Object.keys(obj)) {
console.log(key);
}
2、Object.getOwnPropertyDescriptors
获取对象非继承的属性描述符,可能有 configurable、enumerable、writable、get、set 以及 value
const obj = { es8: 'hello es8' };
Object.getOwnPropertyDescriptor(obj, 'es8');
// { configurable: true, enumerable: true, value: "hello es8", writable: true }
异步编程
1、Async functions
是Generator函数的语法糖,async 声明的函数的返回值若不是Promise类型则自动转为Promise
(1) 声明方式
//函数声明
async function foo() {
//返回promise
return new Promise((resolve) => {
setTimeout(resolve, 100);
});
}
//函数表达式
const foo = async function() {}
//对象的方式
let obj = {
async foo() {}
}
//箭头函数
const foo = async () => {}
(2) 使用方法
//按顺序处理
async function asyncFunc() {
//await 为等待一个async声明的函数返回
const result1 = await otherAsyncFunc1();
//异常捕获
const result2 = await otherAsyncFunc2().catch(error => {});
//异常捕获
try {
const result2 = await otherAsyncFunc2();
} catch (err) {
console.error(err);
}
}
//并发处理
async function asyncFunc() {
const [result1, result2] = await Promise.all([
otherAsyncFunc1(),
otherAsyncFunc2()
]);
}
ES9
对象扩展
1、Spread展开运算符 ...
对比es6,支持对象
console.log({a:1, ...{b:2,c:3}, d:4}) //{a: 1, b: 2, c: 3, d: 4}
2、REST剩余运算符 ...
对比es6,可将对象参数剩余部分转化成对象
function say({ a, ...args}) {
return args;
}
say({a: 1, b: 2, c: 3}); //{b: 2, c: 3}
字符串
1、正则表达式
//增加s选项.可以匹配换行符
/hello.es9/s.test('hello\nes9');
//通过\p{...}和\P{...}标识和u选项 增加unicode的属性转义匹配
//匹配空格
/^\p{White_Space}+$/u.test(' ')
//匹配希腊字母
/^\p{Script=Greek}+$/u.test('μετά')
//匹配拉丁字母
/^\p{Script=Latin}+$/u.test('Grüße')
//匹配单独的替代字符
/^\p{Surrogate}+$/u.test('\u{D83D}')
//通过?<name>标记实现命名捕获特定内容
/const matched = (?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u.exec('2018-12-31');
//matched.groups.year、matched.groups.month、matched.groups.day
//匹配反向断言,表示前面不匹配某字符串 (?<!...)
/(?<!95|98|NT|2000)Windows/u.test('1000Windows');
异步编程
1、for await 异步迭代器
解决循环调用await不能等待异步函数执行
async function foo(array) {
for await (let i of array) {
doSomething(i);
}
}
2、Promise.finally
无论成功还是失败必定调用
return new Promise((reslove, reject) => {
}).then((res) => {
}).catch((err) => {
}).finally(() => {
});
ES10
声明方法
1、class的私有属性
通过#声明私有属性
class Message {
#message = "Howdy"
greet() { console.log(this.#message) }
}
const greeting = new Message()
greeting.greet() // Howdy
console.log(greeting.#message) // Private name #message is not defined
2、globalThis
标准化全局对象,可以无视当前js环境
// browser 环境
console.log(frames); // => Window {...}
// node 环境
console.log(global); // => Object [global] {...}
异步编程
1、Promise.allSettled
与es6的Promise.all相比,Promise项不管有没有捕获异常都能在then获得所有状态
const p1 = new Promise((res, rej) => setTimeout(res, 1000));
const p2 = new Promise((res, rej) => setTimeout(rej, 1000));
Promise.allSettled([p1, p2]).then(data => console.log(data)).catch(x =>{console.log('error', x)});
//[{status: "fulfilled", value: undefined},{status: "rejected,reason: undefined}]
字符串
1、trimStart、trimEnd
去除前面或者后面的空格
const string = ' Hello ES2019! ';
string.trimStart(); // 'Hello ES2019! '
string.trimEnd(); // ' Hello ES2019!'
2、matchAll
正则匹配所有,返回的是Iterator 需要用let of遍历
let iterator = "hello".matchAll(/[el]/);
for (const match of iterator)
console.log(match);
//[ 'e', index: 1, input: 'hello' ] // Iteration 1
//[ 'l', index: 2, input: 'hello' ] // Iteration 2
//[ 'l', index: 3, input: 'hello' ] // Iteration 3
对象扩展
1、Object.fromEntries
相对于es8 Object.entries的反操作,将二维数组转对象
const entries = [ ['foo', 'bar'] ];
const object = Object.fromEntries(entries); // { foo: 'bar' }
数组扩展
1、Object.fromEntries
相对于es8 Object.entries的反操作,将二维数组转对象
const entries = [ ['foo', 'bar'] ];
const object = Object.fromEntries(entries); // { foo: 'bar' }
2、flat数组展平、flatMap展平遍历
//参数表示展平深度默认1
[1, 2, [3, 4]].flat(); // [ 1, 2, 3, 4 ]
[1, 2, [3, 4, [5, 6]]].flat(2); // [ 1, 2, 3, 4, 5, 6 ]
//展平会忽略空位
[1, 2, , 4, 5].flat(); // [1, 2, 4, 5]
//展平遍历 只能展开1层 并对返回的数组进行flat(1)操作
[2, 3, 4].flatMap((x) => [x, x * 2]) // [2, 4, 3, 6, 4, 8]
数据类型
1、Symbol.description
相对于es6,可通过Symbol.description获得标识符
const symbol = Symbol('This is a Symbol');
Symbol.description; // 'This is a Symbol'
2、BigInt
扩大整数的范围
console.log(9007199254740995n); // 9007199254740995n
BigInt("9007199254740995"); // 9007199254740995n
//只允许bigint之间进行数学预算
//不允许用+号表示正数 如+10n
//除法只保留整数部分
25n / 10n; // 2n
//可以用关系表达式来判断跨类型的数
10n > 1、10n == 10、5n < 10
Module 模块
1、await import
相对于es6,可以实现动态import
(async function () {
const module2 = './modB.js'
const module = await import(module2)
module.sayHello()
})()