Es6-Es13使用方法及特性(万字超详细)
目录
ES6
let
// 块级作用域
// 不允许重复声明
// 没有变量提升
// 暂存性死区
let name = "纳西妲";
function fn() {
console.log(name);
let name =
"局部作用域里调用之后再用let声明变量,就会出现暂存性死区,会报错";
}
fn();
// 不与顶层对象挂钩
var names = "挂载在window上";
console.log(window.names); // 挂载在window上
let notMsg = "不关联";
console.log(window.notMsg); // undefined
const
// 常量
// 不能重复定义
// 有块级特性
// 也有暂存性死区特点
// 也不与顶层对象挂钩
const name = 1;
// 当一个常量为复杂数据类型,是可以改变其属性的
const obj = Object.freeze({
name: "张三",
age: 18,
child: {
name: "冻不住",
},
});
// 可以使用冻结方法,让常量不可更改(只能冻住一层)
解构赋值
// 数组解构
let arr = [1, 2, 3];
let [a, b, c] = arr; // 1,2,3
let [d, [e, f], g] = [1, [2, 3], 5]; // 1,2,3,5
let [x = 999] = []; // 999
let [y = 999] = [666]; // 666
console.log(y);
// 对象解构
const obj = {
name: "张三",
age: 18,
child: { list: [6, 7, 8] },
};
let {
name,
age,
child: { list },
} = obj;
console.log(name, age, list);
// 字符串解构
let { length } = "nan";
console.log(length); // 3
模板字符串
// ${} 大括号里面可以放表达式或变量作为字符串
字符串与数值的扩展
let myName = "jack";
myName.includes("a", 1); // true 判断字符串是否包含某个字符
myName.startsWith("j", 0); // true 以...开始
myName.endsWith("j", 1); // true 以...结尾
myName.repeat(3); // jackjackjack 重复三次
Number.isFinite("100"); // false 判断数字是否合法,没有隐式转换
Number.isNaN(NaN); // true 判断数字是否是NaN
Number.isInteger(100.0); // true 判断数字是否是整数
// Number.EPSILON 极小常量,可以定义一个函数,判断两个值是否相等
function isEqual(x, y) {
return Math.abs(x - y) < Number.EPSILON;
}
console.log(isEqual(0.1 + 0.2, 0.3)); // true
// 直接舍弃小数
Math.trunc(1.8); // 1
Math.trunc(-1.8); // -1
// 判断一个数是正数、负数还是零,存在隐式转换
Math.sign(-100); // -1
Math.sign(+100); // 1
Math.sign(-0); // -0
Math.sign(+0); // 0
Math.sign("haha"); // NaN
数组的扩展
// 扩展运算符 ...
let arr1 = [1, 2, 3];
let arr2 = [1, 2, 3];
let newArr = [...arr1, ...arr2]; // [1, 2, 3, 1, 2, 3]
// 将类数组结构转换成数组 Array.from()
function fn() {
Array.from(new Set(arguments)); // [1, 2, 3, 4, 5]
}
fn(1, 2, 3, 4, 4, 5, 5);
// 创建数组 Array.of()
let arr3 = Array(3); // [空属性 × 3] 原始方法创建数组的弊端
let arr4 = Array.of(4); // [4]
// 从前向后查找数组元素 find findIndex()
// 从后向前查找数组元素 findLast findLastIndex() =>Es13
let arr = [111, 222, 333];
let res = arr.find((item) => {
return item > 111;
});
console.log(res); // 222
// 填充元素 fill()
let emptyArr = [1, 2, 3];
emptyArr.fill("替换元素", 0, 1); // ['替换元素', 2, 3]
对象的扩展
// 对象简写
let name = "moudleA";
let obj = {
name,
[name + "fn1"]: "方法1",
[name + "fn2"]: "方法2",
};
// {name: 'moudleA', moudleAfn1: '方法1', moudleAfn2: '方法2'}
let obj1 = {
name: "haha",
};
let obj2 = {
age: "lala",
};
// 对象的合并 es6
Object.assign(obj1, obj2); // {name: 'haha', age: 'lala'} 第一个参数的原对象会被影响
// 对象的合并 es9
console.log({ ...obj1, ...obj2 }); // {name: 'haha', age: 'lala'} 原对象不会被影响
// Object.is() 与 === 不同点
// 1.可以判断NaN和自身的相等
NaN === NaN; // false
Object.is(parseInt("name"), NaN); // true
// 2.可以判断+0和-0的不相等
+0 === -0; // true
Object.is(+0, -0); // false
函数的扩展
// 参数默认值
function name(a = 1, b) {}
// rest参数 剩余参数
function fn(a, ...params) {
console.log(a); // 1
console.log(...params); // 2,3,4,5
}
fn(1, 2, 3, 4, 5);
// 箭头函数
// 1. 只有一行代码可以简写
let arr = ["a", "b", "c"];
let newArr = arr.map((item) => `<li>${item}<li/>`); // ['<li>a<li/>', '<li>b<li/>',
'<li>c<li/>']
// 2.如果返回的是一个对象(大括号外面套一层小括号)
let objFun = () => ({ name: "haha", age: 10 }); // {name: 'haha', age: 10}
// 无法访问arguments,无法new
// 箭头函数本身没有this,它的this指向箭头函数的外部作用域
Symbol 类型
// 定义一个Symbol类型的变量
let s1 = Symbol();
// 不能进行运算
// 有隐式转换
if (s1) {
console.log(111); // 111
}
// 定义Symbol类型的变量时,最好放在一起使用,代码简洁易懂
let keys = {
name: Symbol("name"),
age: Symbol("age"),
};
let obj = {
[keys.name]: "不使用钥匙是拿不到值的",
[keys.age]: 18,
};
// {Symbol(name): '不使用钥匙是拿不到值的', Symbol(age): 18}
// for in 无法遍历Symbol类型
// Reflect.ownKeys() 可以拿到对象所有的属性(包括Symbol类型的属性)
Reflect.ownKeys(obj).forEach((item) => {
console.log(item, obj[item]);
}); // Symbol(name) '不使用钥匙是拿不到值的' Symbol(age) 18
// 作为常量
const eat = Symbol();
const sleep = Symbol();
function play(type) {
switch (type) {
case eat:
console.log("吃饭");
break;
case sleep:
console.log("睡觉");
break;
default:
break;
}
}
play(sleep); //睡觉
iterator 迭代器
// 迭代器 Iterator 一个数据结构只要具有Symbol.iterator属性,就认为是可遍历的
let arr = [1, 2, 3];
let iter = arr[Symbol.iterator]();
console.log(iter.next()); // {value: 1, done: false}
console.log(iter.next()); // {value: 2, done: false}
console.log(iter.next()); // {value: 3, done: false}
console.log(iter.next()); // {value: undefined, done: true}
// 原生默认具备iterator接口的数据结构
// Array Set Map String arguments对象 NodeList对象
// 利用迭代器封装遍历对象中可遍历的属性
let obj = {
name: "遍历对象",
age: 18,
list: [111, 222, 333],
// 迭代器
[Symbol.iterator]() {
let index = 0;
return {
next: () => {
return {
value: this.list[index++],
done: index === this.list.length + 1 ? true : false,
};
},
};
},
};
for (const item of obj) {
console.log(item); // 111 222 333
}
// 手写迭代器(ts)
const fn = (args: any) => {
let it: Iterator<any> = args[Symbol.iterator]();
let next: any = { done: false };
while (!next.done) {
next = it.next();
if (!next.done) {
// console.log(next);
if (next.value.length >= 2) {
console.log(`${next.value[1]}是${next.value[0]}`);
}
}
}
};
Set数据结构
// Set 结构类似于数组,但成员的值都是唯一的,没有重复的值
// 利用Set结构数组去重
let arr = [1, 2, 2, 3, 4, 5, 5, 6];
let [...res] = new Set(arr); // [1, 2, 3, 4, 5, 6]
// 添加
set.add(1);
// 长度
console.log(set.size);
// 删除
set.delete(1);
// 检查
console.log(set.has(1)); // true
// 封装一个可以去重复杂数组的函数
function fn(arr) {
let res = new Set();
return arr.filter((item) => {
let id = JSON.stringify(item);
if (res.has(id)) {
return false;
} else {
res.add(id);
return true;
}
});
}
Map数据结构
// Map 用来存储键值对结构的数据(key-value)
// Map 和 Object 主要区别:
// 1. Object中的属性只能是字符串或符号
// 2. Map任何类型的值都可以成为数据的key
const obj = {
name: "1",
age: 18,
};
console.log(obj);
// 创建map对象
const map = new Map();
map.set(obj, "纳西妲");
map.set(undefined, "妮露");
// // 存值
// map.set(obj, '啦啦')
// console.log(map)
// // 取值
// console.log(map.get(obj))
// // 删除
// map.delete(obj)
// // 查找
// console.log(map.has(NaN)) // false
// // 清空
// console.log(map.clear())
// // 长度
// console.log(map.size)
// 将数据类型为Map的对象转换为数组
const [...arr] = map;
console.log(arr);
// 遍历Map
for (const [key, value] of map) {
console.log(key, value);
}
// 获取所有的key
for (const key of map.keys()) {
console.log(key);
}
// 获取所有的value
for (const value of map.values()) {
console.log(value);
}
map.forEach((item, index) => {
console.log(item, index);
});
Proxy代理
// 在Proxy代理出现之前是用 Object.defineProperty 来拦截更改/获取dom行为
// 缺点 每次只能拦截一个属性,只能拦截对象
// let obj = {};
// Object.defineProperty(obj, "data", {
// get() {
// console.log("get");
// },
// set(value) {
// console.log("set", value);
// },
// });
// Proxy 可以拦截所有数据类型
let obj = {};
let proxy = new Proxy(obj, {
get(target, key) {
// 对于Set或Map这样的数据结构,需要判断如果是方法就修改this指向
let value = target[key];
if (value instanceof Function) {
return value.bind(target);
}
return value;
},
set(target, key, value) {
if (key === "data") {
box.innerHTML = value;
}
// 将值赋值给目标
// target[key] = value;
},
});
Reflect反射
// 代替Object 某些方法
let obj = {};
Reflect.defineProperty(obj, "name", {
value: "haha",
writable: false,
enumerable: false,
});
// 修改某些Object 方法返回结果
if (Reflect.defineProperty(target, property, attributes)) {
// success
} else {
// fail
}
// 命令式变为函数行为
Reflect.has(obj, "name"); //true
Reflect.deleteProperty(obj, "name");
// 设置和获取
Reflect.set(obj, "age", 10);
Reflect.get(obj, "age");
// 最重要的作用是配合Proxy设置/获取属性或方法
let proxy = new Proxy(obj, {
get(target, key) {
// 获取相应的方法
let value = Reflect.get(target, key);
// 如果是函数,修改this指向
if (value instanceof Function) {
return value.bind(target);
}
return value;
},
set(target, key, value) {
// 执行默认行为
Reflect.set([...arguments]);
},
});
Promise对象
// 基础写法
let promise = new Promise((res, rej) => {
setTimeout(() => {
res(1000);
}, 200);
});
promise
.then((res) => {
console.log("success", res);
})
.catch((err) => {
console.log("fail", err);
});
// 有三种状态,pendding状态 fulfilled状态 rejected状态
// 从pendding状态只能转换为fulfilled状态和rejected状态之间的一种状态,且改变后会凝固,不会再进行改变。
// 解决回调地狱的问题 => 利用链式调用
promise
.then((res) => {
console.log("success", res); // success 1000
// 如果return 非Promise类型,直接变为 fulfilled状态
// 如果return Promise类型,则根据这个Promise的状态去返回。
return res;
})
.then((res) => {
console.log("success", res); // success 1000
})
.catch((err) => {
console.log("fail", err);
});
// Promise.all([]) 等全部promise执行完了之后再执行
Promise.all([promise1, promise2])
.then((result) => {
console.log(result);
})
.catch((err) => {
console.log(err);
});
// Promise.race() 等最快的promise执行完了就执行
Promise.race([promise1, promise2])
.then((result) => {
console.log(result);
})
.catch((err) => {
console.log(err);
});
Generator生成器函数
// 基础使用
function* gen() {
console.log(1);
yield; // 产出
console.log(2);
yield;
console.log(3);
}
let g = gen();
g.next(); // 1
g.next(); // 2
g.next(); // 3
class语法
// 类是对象模板
class Person {
// 属性
name = "我是实例属性"; // 大部分情况下用实例属性
static props = "我是静态属性";
// 方法
sayHello() {
console.log("我是实例方法", this.name); // this指向当前实例
}
static sayHi() {
console.log("我是类方法", this); // this指向类
}
}
class Dog {}
// 调用构造函数创建对象(实例)
// 实例 类
const person1 = new Person();
const dog1 = new Dog();
// 利用 instanceof 可以判断一个对象是否由某个类创建
console.log(dog1 instanceof Person); // false
console.log(dog1 instanceof Dog); // true
console.log(person1.name); // 实例属性只能通过实例访问
console.log(Person.props); // 静态属性(类属性)只能通过类访问
// 调用实例方法
person1.sayHello();
// 调用类方法
Person.sayHi();
class继承
// 可以通过extends关键字来完成继承,最大的作用就是,在不修改类的情况下,对其进行扩展
// OCP 开闭原则,对修改关闭,对扩展开放
class Animal {
constructor(name) {
this.name = name;
}
sayHello() {
console.log(`动物在叫!`);
}
}
class Snake extends Animal {
// 重写构造函数
constructor(name, age) {
// 重写构造函数时,第一行代码必须是super()
super(name); // 调用父类的构造函数
this.age = age;
}
// 重写父类的方法
sayHello() {
// 在方法中可以使用super来调用父类的方法
super.sayHello();
console.log(`嘶嘶嘶!`);
}
}
const snake1 = new Snake("蛇", 10);
snake1.sayHello();
console.log(snake1); // Snake {name: '蛇', age: 10}
EMS规范和CJS规范
ES7
求幂运算符
Math.pow(3,2)===3**2 // 9
数组的includes方法
[1,2,NaN].includes(NaN) // true
[1,2,NaN].indexOf(NaN) // -1 数组的indexOf方法判断不出数组中是否有NaN
ES8
async和await
// 解决回调地狱的最优方案
function ajax1() {
return new Promise((res, rej) => {
setTimeout(() => {
res("第一个请求返回的值");
// rej("第一个请求失败");
}, 1000);
});
}
function ajax2() {
return new Promise((res, rej) => {
setTimeout(() => {
res("成功接收第一个请求的返回值");
// rej("第二个请求失败");
}, 2000);
});
}
// 第一种写法
async function test1() {
let res1 = await ajax1();
let res2 = await ajax2(res1);
return res2;
}
test1()
.then((result) => {
// 渲染页面
console.log(result);
})
.catch((err) => {
// 处理错误
console.log(err);
});
// 第二种写法
async function test2() {
try {
let res1 = await ajax1();
console.log(res1);
let res2 = await ajax2(res1);
console.log(res2);
console.log("渲染页面");
// 如何使用Promise.all方法
// let res = await Promise.all([ajax1(), ajax2(res1)]);
// console.log(res); // ['第一个请求返回的值', '成功接收第一个请求的返回值']
} catch (error) {
console.log(error, "处理错误");
}
}
test2();
对象方法扩展
// 对象的获取操作
let obj = {
name: "八重神子",
age: 500,
get changeName() {
return 666;
},
set changeName(value) {
this.name = value;
},
};
console.log(Object.keys(obj)); // es6 只取key ['name', 'age']
console.log(Object.values(obj)); // 只取值 ['八重神子', 500]
console.log(Object.entries(obj)); // key和值都获取 0: (2) ['name', '八重神子'] 1: (2) ['age', 500]
// 对象的复制操作,可以把对象里的方法一起复制
let obj1 = {};
Object.defineProperties(obj1, Object.getOwnPropertyDescriptors(obj));
字符串填充
// 字符串填充到指定长度
let str = "天道酬勤";
str.padEnd(10, "1"); // 天道酬勤111111
str.padStart(5, "6"); // 6天道酬勤
ES9
rest与扩展运算符
// 剩余参数
function name(a, ...b) {}
//扩展运算符
let obj = { a: 1, b: 2 };
// 这种方法复制只能深复制一层
// 如果对象属性有复杂数据类型则无法实现深复制
let obj1 = { ...obj };
正则命名捕获分组
let str = "今天是2022-10-10";
let reg = /(?<year>[0-9]{4})-(?<month>[0-9]{2})-(?<day>[0-9]{2})/;
let res = reg.exec(str);
let { year, month, day } = res.groups; // 2022 10 10
Promise.finally
// Promise.finally 最后执行,不管promise状态是成功还是失败
function ajax() {
return new Promise((res, rej) => {
rej("失败");
});
}
ajax()
.then((result) => {})
.catch((err) => {})
.finally(() => {
// 不管成功还是失败都隐藏loading
});
异步迭代
// 有一个任务数组,执行任务按顺序执行,任务1,任务2,任务3,以此类推(前提在for循环中执行)
// 1. 写一个ajax请求
function timer(t) {
return new Promise((res, rej) => {
setTimeout(() => {
res("data-" + t);
}, t);
});
}
// 写一个异步生成器生成异步任务
async function* gen() {
yield timer(1000);
yield timer(2000);
yield timer(3000);
}
// 利用 for await 遍历异步任务
async function test() {
let g = gen();
let arr = [g.next(), g.next(), g.next()];
for await (const item of arr) {
console.log(item);
}
}
test();
ES10
Object.fromEntries
// 用法1 将Map结构转化成对象
let arr = new Map();
arr.set("name", "haha");
arr.set("age", 18);
Object.fromEntries(arr); // {name: 'haha', age: 18}
// 用法2 将url参数转化成对象
let url = "name=lala&age=20";
let searchParams = new URLSearchParams(url);
Object.fromEntries(searchParams); // {name: 'lala', age: '20'}
// 用法三 转换对象形式
let obj = {
A: ["A1", "A2", "A3"],
B: ["B1", "B2"],
C: ["c1"],
};
let newArr = [];
for (const key in obj) {
newArr.push([key, obj[key].length]);
}
Object.fromEntries(newArr) // {A: 3, B: 2, C: 1}
trimStart和trimEnd
删除字符串前面的空格 str.trimStart()
删除字符串后面的空格 str.trimEnd()
flat()和flatMap()
// 扁平化 flat() flatMap()
[1, 2, 3, [4, 5, 6]].flat(); // [1, 2, 3, 4, 5, 6]
let addr = [
{
name: "A",
location: [1, 2, 3, 4],
},
{
name: "B",
location: [5, 6, 7, 8],
},
];
let resArr = addr.flatMap((item) => {
return item.location;
});
console.log(resArr); // [1, 2, 3, 4, 5, 6, 7, 8]
symbol.description
// 根据描述符查找Symbol属性
let s = Symbol("name");
s.description // name
ES11
Promise.allSettled
function ajax(flag, t) {
return new Promise((res, rej) => {
setTimeout(() => {
if (flag) {
res("成功");
} else {
rej("失败");
}
}, t);
});
}
// 把全部成功的请求返回,不用捕获失败的请求
Promise.allSettled([
ajax(true, 1000),
ajax(true, 2000),
ajax(false, 3000),
]).then((result) => {
let res = result.filter((item) => item.status === "fulfilled");
let newRes = res.flatMap((item) => item.value); // ['成功', '成功']
});
Module新增
<!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>es11</title>
</head>
<button id="login">登录</button>
<body>
<script>
function fn() {
return "管理员";
}
let login = document.querySelector("#login");
login.onclick = function () {
let role = fn();
render(role);
};
// 动态导入
async function render(role) {
if (role === "管理员") {
let res1 = await import("./1.js"); // 返回promise对象
console.log(res1);
} else {
let res2 = await import("./2.js");
console.log(res2);
}
}
</script>
</body>
</html>
// 1.js文件
console.log("管理员js加载了", import.meta);
// 管理员js加载了 {url: 'http://127.0.0.1:5500/Es6-Es13/1.js', resolve: ƒ}
export default {
name: "管理员",
};
// 无侵入式从别的模块继承过来然后导出
export * as js_2 from "./2.js";
字符串的matchAll方法
let str = `<ul>
<li>111</li>
<li>222</li>
<li>333</li>
</ul>`;
let reg = /<li>(.*)<\/li/g;
let obj = str.matchAll(reg);
for (const item of obj) {
console.log(item[1]); // 111 222 333
}
bigint (大整数)类型
// BigInt数据类型支持范围更大的整数值,可以用任意精度表示整数
BigInt(10); // 10n
BigInt(10) == 10; // true
BigInt(10) === 10; // false
// 如果后端给你返回的数据太大,他又不给你转换成字符串,就使用json-bigint插件进行转换
import JsonBigint from "json-bigint";
// 转换成字符串类型
// let JsonBigintStr = JsonBigint({ storeAsString: true });
// 转换成bigInt类型
let JsonBigintNative = JsonBigint({ useNativeBigInt: true });
let jsonStr = `{
"id":9007199254740993,
"list":[]
}`;
// JsonBigintStr.parse(jsonStr); // { id: '9007199254740993', list: [] }
JsonBigintNative.parse(jsonStr); // { id: 9007199254740993n, list: [] }
globalThis 顶层对象
// 在不同平台,都可以拿到当前环境的顶层对象,在跨平台开发时就无须再配置。
// 在浏览器环境 globalThis === window
空值合并运算符 ??
// 只要 ?? 前面不是null或undefined 就返回前面的值
// let str = null ?? "签名"; // 签名
// let str = undefined ?? "签名"; // 签名
// let str = 0 ?? "签名"; // 0
可选链操作符 ?.
// 当问号前面的值没有或为undefined时,直接返回undefined,不至于使代码报错
let obj = {
name: "张三",
// location: {
// now: "beijing",
// },
};
console.log(obj?.location?.now); // undefined
ES12
新增逻辑操作符
let a = true;
let b = false;
a &&= b; // false
a ||= b; // false
let obj = {
// name: 1,
};
obj.name ??= "默认名字"; // 默认名字
字符串的replaceAll 方法
// 可以全部替换
let str = `1,1,1,1`;
str.replaceAll("1", "*"); // *,*,*,*
Promise.any
let ajax1 = function () {
return new Promise((res, rej) => {
rej("纳西妲");
});
};
let ajax2 = function () {
return new Promise((res, rej) => {
res("八重神子");
});
};
let ajax3 = function () {
return new Promise((res, rej) => {
res("神里绫华");
});
};
// 只要任意请求成功,就直接返回该成功结果,全部失败才到catch
Promise.any([ajax1(), ajax2(), ajax3()])
.then((result) => {
console.log(result);
})
.catch((err) => {
console.log("err", err);
});
WeakRef
<!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>es12</title>
</head>
<div id="div">1111</div>
<body>
<script>
// 强引用
let obj = {
name: "大理石",
};
// Map(Set)结构存在的问题
// let m1 = new Map();
// m1.set(obj, "哈哈");
// obj = null;
// 因为引用计数机制,obj依然存在在m1里,没有被垃圾回收(内存泄漏)
// 弱引用 WeakMap WeakSet 只能存储复杂数据类型,size,for不能用
let m2 = new WeakMap();
m2.set(obj, "啦啦");
obj = null;
// 因为是弱引用,不存在引用计数机制,所以m2中的obj被回收了
let dom = new WeakRef(document.querySelector("#div"));
dom.deref(); // <div id="div">1111</div>
</script>
</body>
</html>
ES13
类新增特性
class Person {
// 初始值可以直接定义
state = {
name: "haha",
age: 18,
};
sex = "男";
// 实例私有属性
#play = "打游戏";
playGame() {
return this.#play;
}
// 静态私有属性配合静态公开方法
static #watch = "看电视";
static watchTv() {
return this.#watch;
}
// 静态代码块(可以写多个)
static obj = new Map();
static {
this.obj.set("name", "无量天尊");
this.obj.set("age", 8000);
}
static {
console.log(this.obj); // Map(2) {'name' => '无量天尊', 'age' => 8000}
}
// 判断某个属性是不是该类的私有属性
hasObj() {
return #play in this;
}
}
let person = new Person();
person.playGame(); // 打游戏
Person.watchTv(); // 看电视
person.hasObj(); // true
顶层 await
// js文件
function ajax() {
return new Promise((res, rej) => {
setTimeout(() => {
res("成功");
}, 2000);
});
}
// 当有数据是异步导出时,可以使用顶层 await 接收数据
let data = await ajax();
export default {
name: "haha",
data,
};
// html文件
<!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>es13</title>
</head>
<body>
<script type="module">
// 异步导出配合动态导入使用最佳
console.log("不能被阻塞的初始化数据"); // 不能被阻塞的初始化数据
let moduleA = await import("./ajax.js");
console.log(moduleA); // Module {Symbol(Symbol.toStringTag): 'Module'}
</script>
</body>
</html>
at函数
let arr = [1,2,3,4]
arr.at(0) // 第一个元素
arr.at(-1) // 倒数第一个元素
// 字符串也适用
findLast 和 findLastIndex
let arr = [10, 20, 30, 40];
let res = arr.findLast((value) => value < 40);
let resIndex = arr.findLastIndex((value) => value < 40);
console.log(res); // 30 从后面查找并返回第一个符合条件的元素
console.log(resIndex); // 2 从后面查找并返回第一个符合条件的元素的索引
catch捕获错误添加原因
function getData() {
try {
console.log(aaa);
} catch {
throw new Error("不符合规则", {
cause: {
a: "十连双黄",
b: "单抽出金",
},
});
}
}
try {
getData();
} catch (error) {
console.log(error, error.cause);
/* Error: 不符合规则
at getData (es13.html:27:17)
at es13.html:36:9 {a: '十连双黄', b: '单抽出金'}*/
}