前端进阶-js查漏补缺

1、部分语法基础

1.1、let、const

特性:// 1、暂时行死区
// 比如有这一个例子
let aa = "111"
function test(){console.log(aa)let aa = "22"
}
// 会报错引用错误,就是因为在函数test作用域内存在暂时性死区,如果把aa注释掉,则console.log(aa) 会打印 22// 2、没有变量提升
// 3、不能刚重复定义
// 4、可以产生作用域

1.2、解构相关

数组解构

const [x,y,[c]] = [1, 2,[4,5,6]];
console.log(x,y,c); // 1 2 4

对象解构

const {name, age, address: {city, country}} = {name: 'John',age: 30,address: {city: 'New York',country: 'USA'}
}
console.log(name, age, city, country); // John 30  USA

字符串解构

// 字符串解构
const [a, b, c, d, e] = 'hello';
const {length : len} = 'hello';
console.log(a, b, c, d, e, len); // h e l l o  5

2、字符串扩展

2.1、判断字符串是否包含

// 字符串是否包含
const str = "hello"
console.log(str.includes('h'));  // true
// 字符串是否以指定字符串开头
console.log(str.startsWith('h')); // true
// 字符串是否以指定字符串结尾
console.log(str.endsWith('o'));  // true// 以上三个方法都包含第二个参数,具体用法如下, 前两个都是从那个下标开始找,后一面一个是前n个字符串是否以 xx 结尾
console.log(str.includes('e', 1));  // true
console.log(str.startsWith('e', 1)); // true
// 这个的第二个参数稍微不一样,这是相当与str.slice(0, 4).endsWidth()
console.log(str.endsWith('l', 4));  // true

2.2、matchAll 与 match对比

// matchAll 使用 与 match 对比
// matchAll 返回一个迭代器,而 match 返回匹配到的数组// 加入有這麽一個字符串 ul>li的,我们想要取出其中的值,做其他处理
const str = `<ul><li>Item 1</li><li>Item 2</li><li>Item 3</li></ul>
`
const regex = /<li>(?<content>.*)<\/li>/g;// 使用 match 方法
const matchResults = str.match(regex);
console.log(matchResults.map((v) => v.replace(/<\/?li>/g, ""))); // ["<li>Item 1</li>", "<li>Item 2</li>", "<li>Item 3</li>"]// 使用 matchAll 方法, 返回的是一个迭代器,可以通过forof 遍历, 也可以通过 [...matchAllResults].map 获取出值
const matchAllResults = str.matchAll(regex);
for (const match of matchAllResults) {console.log(match.groups.content);  // "Item 1", "Item 2", "Item 3"
}

3.3、重复

// 字符串重复
const str2 = "hello"
console.log(str2.repeat(3));  // hellohellohello
console.log(str2.repeat(0));  // ""
console.log(str2.repeat("2"));  // "hellohello"/*字符填充 padStart、padEnd,前后填充第一个参数:填充完之后字符串的长度第二个参数:用于填充的字符串*/
const str = "Hello";
console.log(str.padStart(10, "World")); // "WorldHello"
const num = 123;
console.log(num.toString().padStart(10, "0")); // "0000123"
console.log(str.padEnd(11, "World")); // "HelloWorldW"
console.log(num.toString().padEnd(10, "0")); // "1230000"

3、数值

3.1、数值进制

// 进制数表示
const num2 = 10
const num3 = 0b1010 // 二进制
const num4 = 0o12 // 八进制
const num5 = 0xA  // 十六进制

3.2、判断是否是 NaN 与 判断是否是有限值

// 判断是否为NaN, Number.isNaN 不会对数字进行类型转换、对非数值都返回false
console.log(Number.isNaN(10));  // false
console.log(Number.isNaN("55"));  // false
console.log(Number.isNaN(NaN));  // true
// 全局方法 isNaN 会对要判断的值进行类型转换,转换成数字,再判断
console.log(isNaN(10));  // false
console.log(isNaN("55"));  // false
console.log(isNaN(NaN));  // true
console.log(isNaN("abc"));  // true// 判断是否为有限数 对于非数值都返回false
console.log(Number.isFinite(10));  // true
console.log(Number.isFinite("55"));  // false
console.log(Number.isFinite(NaN));  // false
console.log(Number.isFinite(Infinity));  // false
console.log(Number.isFinite(100/0));  // false// 全局方法 isFinite 会对要判断的值进行类型转换,转换成数字,再判断, 对于转不成数值的字符串,会返回false
console.log(isFinite(10));  // true
console.log(isFinite("55"));  // true
console.log(isFinite(NaN));  // false
console.log(isFinite(Infinity));  // false
console.log(isFinite(100/0));  // false
console.log(isFinite("abc"));  // false

3.3、bigInt

 

/*bigInt由于number 的数值范围是-2^53 2^53,所以无法精确表示大于 2^53 的数值,所以就需要bigint这个数值类型*/// bigint 不能与 number 进行运算
// 因为 bigint 无法与 number 进行隐式转换let bigIntValue = 123n;
let numberValue = 123;
// console.log(bigIntValue + numberValue); // 报错
console.log(bigIntValue + BigInt(numberValue)); // 246n// 但是可以进行比较
console.log(bigIntValue == numberValue); // true
console.log(bigIntValue === numberValue); // false

4、数组扩展

4.1、扩展运算符与剩余参数

// 扩展运算符
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const arr3 = [...arr1, ...arr2]; // 浅层复制
console.log(arr3); // [1, 2, 3, 4, 5, 6]// 剩余参数
const [a, b, ...rest] = [1, 2, 3, 4, 5];
console.log(a); // 1
console.log(b); // 2
console.log(rest); // [3, 4, 5]

4.2、Array.from 与 Array.of


// Array.from 可以将类数组转成数组
function foo() {
return Array.from(arguments);
}
console.log(foo(1, 2, 3)); // [1, 2, 3]
// 还可以像 map 的回调函数那样使用
const arr = Array.from([1, 2, 3], x => x \* 2);
console.log(arr); // [2, 4, 6]// Array.of 用于创建一个具有可变数量参数的新数组实例,而不考虑参数化的数量
console.log(Array.of(1, 2, 3)); // [1, 2, 3]
console.log(Array.of(3)); // [3]
// 与 Array 构造函数不同,Array 当只有一个参数的情况下,返回的是一个长度为 n 的空数组
console.log(Array(3)); // [ , , ]

4.3、fill

// fill
const arr6 = [1, 2, 3, 4, 5];
arr6.fill(0, 1, 3); // 将索引 1 到索引 3 的元素替换为 0
console.log(arr6); // [1, 0, 0, 4, 5]
// fill 方法还可以用于数组的初始化
const arr7 = new Array(5).fill(0); // 创建一个长度为 5 的空数组
console.log(arr7); // [0, 0, 0, 0, 0]

4.4、find、findIndex、findLast、findLastIndex


// find 与 findIndex 查找满足指定条件的第一个元素,分别返回该元素和索引
const arr4 = [1, 2, 3, 4, 5];
const found = arr4.find(x => x > 3); // 返回值
console.log(found); // 4
const foundIndex = arr4.findIndex(x => x > 3); // 返索引
console.log(foundIndex); // 3// findLast 与 findLastIndex 查找满足指定条件的最后一个元素,分别返回该元素和索引,需要注意的是 node 版本需要比较新的版本,才支持这两个方法,比如 18.17.1
const arr5 = [1, 2, 3, 4, 5];
const foundLast = arr5.findLast(x => x > 3); // 返回值
console.log(foundLast); // 5
const foundLastIndex = arr5.findLastIndex(x => x > 3); // 返索引
console.log(foundLastIndex); // 4

4.5、flat、flatMap

// flat flatMap
const arr8 = [1, 2, [3, 4, [5, 6]]];
const flatArr = arr8.flat(); // 默认只会将数组拉平一层
console.log(flatArr); // [1, 2, 3, 4, [5, 6]]
const flatArr2 = arr8.flat(2); // 拉平多层
console.log(flatArr2); // [1, 2, 3, 4, 5, 6]
// key-map 的数组对象数组, 可以使用 flatMap 来扁平化
const arr9 = [{name: 'xx', list: [1,2,3]}, {name: 'yy', list: [4,5,6]}];
const flatMapArr = arr9.flatMap(x => x.list); // 会将每个 list 扁平化,相当于先调用map,再 flat
console.log(flatMapArr); // [1, 2, 3, 4, 5, 6]

5、对象扩展

5.1、扩展运算符

// 扩展运算符
const person1 = {
name: 'John',
age: 30
};
const person2 = {
...person1,
name: 'Jane'
};
console.log(person2); // 输出: { name: 'Jane', age: 30 }

5.2、Object.assign

// Object.assign()
const person3 = {
name: 'John'
};
const person4 = {
age: 30
};
const person5 = {
course: 99
};
Object.assign(person3, person4, person5);
console.log(person3); // 输出: { name: 'John', age: 30, course: 99}

5.3、Object.is

// Object.is
const person6 = {
name: 'John',
age: 30
};
const person7 = {
name: 'John',
age: 30
}
console.log(Object.is(person6, person7)); // 输出: false
console.log(Object.is(NaN, NaN)); // 输出: true
console.log(Object.is(+0, -0)); // 输出: false
// 与 === 运算符的区别
console.log(+0 === -0); // 输出: true
console.log(NaN === NaN); // 输出: false

5.4、Object.fromEntries

// Object.fromEntries() 方法把键值对列表转换为一个对象。
// 例如,将一个 Map 结构转换为对象:
const entries = new Map([['foo', 'bar'],
])
console.log(Object.fromEntries(entries)); // { foo: 'bar' }// 用法2
const obj = {name: 'John',age: 30,city: 'New York'
}const keyValues = Object.entries(obj);
console.log(keyValues); // [ [ 'name', 'John' ], [ 'age', 30 ], [ 'city', 'New York' ] ]
console.log(Object.fromEntries(keyValues)); // { name: 'John', age: 30, city: 'New York' }// 用法3
// 将一个 URLSearchParams 结构转换为对象:
const paramsString = 'q=URLUtils.searchParams&topic=api';
const searchParams = new URLSearchParams(paramsString);
// 当然也可以像这样获取 searchParams.get
console.log(searchParams.get('q')); // URLUtils.searchParams
console.log(searchParams.get('topic')); // api
console.log(Object.fromEntries(searchParams)); // { q: 'URLUtils.searchParams', topic: 'api' }

6、函数扩展

6.1、参数默认值与剩余参数

// 函数参数默认值,注意假如有多个参数,默认值只能从最后开始放
function greet(name = 'World') {console.log(`Hello, ${name}!`);
}
greet(); // 输出:Hello, World!
greet('Alice'); // 输出:Hello, Alice!// 剩余参数,主要是平替 arguments
function sum(...nums) {return nums.reduce((a, b) => a + b, 0);
}
console.log(sum(1, 2, 3, 4, 5)); // 输出:15
function printNums(x, y, ...nums) {console.log(x, y, nums);
}
printNums(1, 2, 3, 4, 5); // 输出:1 2 [3, 4, 5]

6.2、箭头函数

/*箭头函数, 当只有一个参数时,可以省略小括号,当函数体只有一个表达式时,可以省略大括号和 return 关键字如果返回值是对象,需要用小括号包起来没有this(与上下文同一个),无法访问arguments, 无法作为构造函数*/
const add = (a, b) => a + b;
console.log(add(1, 2)); // 输出:3

7、Symbol

7.1、Symbol基础使用

// 创建Symbol
const sym1 = Symbol();
const sym2 = Symbol('key'); // 带有描述的字符串
// console.log(sym1 > "666");  //  Cannot convert a Symbol value to a number
// 显示调用 toString
console.log(sym2.toString() + "666"); // Symbol(key)666
// 隐式转换boolean
if (sym2) {console.log("symbol is true");  // symbol is true
}// symbol 作为对象属性名,就不会出现属性覆盖的情况了
const sym3 = Symbol();
const obj = {};
obj[sym3] = "symbol property";
console.log(obj[sym3]);  // symbol property
const obj1 = {...obj}
console.log(obj1[sym3]);  // symbol property
// 一些防止意外更改的属性,,可以传一个字符串作为symbol描述,方便查看对象的时候区别那个属性
const keys = {name: Symbol("name"),age: Symbol("age"),gender: Symbol("gender"),hobby: Symbol("hobby")
}const obj2 = {[keys.name]: "张三",[keys.age]: 18,[keys.gender]: "男",[keys.hobby]: "篮球",other: "其他"
}
console.log(obj2[keys.name]);  // 张三// 不能forin遍历,这块的结果是啥也不打印
for (const key in obj2) {console.log(key);
}// 能用Object.getOwnPropertySymbols获取
console.log(Object.getOwnPropertySymbols(obj2));  // [Symbol(name), Symbol(age), Symbol(gender), Symbol(hobby)]
// 也可以用Reflect.ownKeys
console.log(Reflect.ownKeys(obj2));  // [ 'other', Symbol(name), Symbol(age), Symbol(gender), Symbol(hobby) ]

7.2、Symbol 作为常量使用

/*symbol 作为常量, 为啥要这么是用,就是为了避免本来定义的常量的情况下例如 const COLOR_RED = "red"; 然後在用的时候非 getComplement("red")这么用,而不是getComplement(COLOR_RED)这么用使用symbol 作为常量,可以防止上面的问题
*/
const COLOR_RED = Symbol();
const COLOR_GREEN = Symbol();function getComplement(color) {switch (color) {case COLOR_RED:return "RED";case COLOR_GREEN:return "GREEN";default:}
}// 测试
console.log(getComplement(COLOR_RED));  // COLOR_GREEN
console.log(getComplement(COLOR_GREEN));  // COLOR_RED// Symbol 获取描述符的方法
const sym = Symbol('name');
console.log(sym.description); // 输出 "name"

8、iterator

Symbol.iterator的作用
 *  1、是为各种数据结构,提供一个统一的、简便的访问接口
 *  2、是使得数据结构的成员能够按某种次序排列
 *  3、ES6创造了一种新的遍历命令for...of循环,Iterator接口主要供for...of消费
 *  4、一个数据结构只要部署了Iterator接口,我们就称这种数据结构是“可遍历的”
 *  5、原生具有迭代器的数据结构 Array Map Set String NodeList arguments 后面两个是伪数组

8.1、基础使用

// 获取迭代器
const arr = ["a", "b", "c"];
const iter = arr[Symbol.iterator]();
// 使用next方法遍历
console.log(iter.next()); // { value: 'a', done: false }
console.log(iter.next()); // { value: 'b', done: false }
console.log(iter.next()); // { value: 'c', done: false }
console.log(iter.next()); // { value: undefined, done: true }// 线性对象 增加迭代器, 则对象就可以使用for...of循环遍历了
const obj = {0: "a",1: "b",2: "c",length: 3,[Symbol.iterator]: Array.prototype[Symbol.iterator]
}
for (const c of obj) {console.log(c);
}

8.2、自定义迭代器

// 自定义迭代器
const obj2 = {data: ["a", "b", "c"],[Symbol.iterator]() {let index = 0;return {next: () => ({value: this.data[index++],done: index > this.data.length})}}
}
const iter2 = obj2[Symbol.iterator]();
console.log(iter2.next()); // { value: 'a', done: false }
console.log(iter2.next()); // { value: 'b', done: false }
console.log(iter2.next()); // { value: 'c', done: false }
console.log(iter2.next()); // { value: undefined, done: true }// 配合扩展运算符,或者Array.from,容有迭代器的数据结构,都会自动转成数组
const arr2 = [...obj2];
console.log(arr2); // ['a', 'b', 'c']
console.log(Array.from(obj2)); // ['a', 'b', 'c']

9、set

9.1、基础使用

// set 介绍及其使用
// 创建一个Set对象
const mySet = new Set();// 添加元素
mySet.add(1);
mySet.add(2);
mySet.add(3);// 检查元素是否存在
console.log(mySet.has(2)); // 输出 true
console.log(mySet.has(4)); // 输出 false// 删除元素
mySet.delete(2);// 获取Set的大小
console.log(mySet.size); // 输出 2// 遍历Set
for (let value of mySet) {console.log(value); // 输出 1, 3
}

9.2、进阶使用

// 将Set转换为数组
console.log(Array.from(mySet)); // 输出 [1, 3]
console.log([...mySet]); // 输出 [1, 3]// 清空Set
mySet.clear();// 检查Set是否为空
console.log(mySet.size === 0); // 输出 true// 合并Set
const set1 = new Set([1, 2, 3]);
const set2 = new Set([2, 3, 4]);
const unionSet = new Set([...set1, ...set2]);
console.log(unionSet); // 输出 Set { 1, 2, 3, 4 }// keys values entries set的键、值都是相同的
const mySet1 = new Set(['a', 'b', 'c']);for (let key of mySet1.keys()) {console.log(key); // 输出 'a', 'b', 'c'
}for (let value of mySet1.values()) {console.log(value); // 输出 'a', 'b', 'c'
}for (let entry of mySet1.entries()) {console.log(entry); // 输出 ['a', 'a'], ['b', 'b'], ['c', 'c']
}// 结合set实现一个去重复杂数组
function uniqueArray(arr) {const uniSet = new Set();return arr.filter((item)=>{const str = JSON.stringify(item);if (uniSet.has(str)) {return false;}else{uniSet.add(str);return true;}})
}const arr = [1, 1, 3, 4, {name:12}, {name:12}, [1,2], [1,2]];
console.log( uniqueArray(arr)); // [ 1, 3, 4, { name: 12 }, [ 1, 2 ] ]

10、map

10.1、基础使用

// 创建一个 Map 对象constkeyObj= {name:11}constmyMap=newMap([["aa", 11],["bb", 22],[keyObj, 33],[55, 33],]);// 添加键值对myMap.set("cc", 44);console.log(myMap); // Map(5) { 'aa' => 11, 'bb' => 22, { name: 11 } => 33, 55 => 33, 'cc' => 44 }// 是否包含某个键console.log(myMap.has("aa")); // true// 删除键值对myMap.delete(keyObj);console.log(myMap); // Map(4) { 'aa' => 11, 'bb' => 22, 55 => 33, 'cc' => 44 }// 获取键值对数量console.log(myMap.size); // 4// 遍历 Mapfor (constitemofmyMap) {console.log(item); // 输出键值对 [ 'aa', 11 ] [ 'bb', 22 ] [ 55, 33 ] [ 'cc', 44 ]}// 转成数组console.log([...myMap]); // [ [ 'aa', 11 ], [ 'bb', 22 ], [ 55, 33 ], [ 'cc', 44 ] ]console.log(Array.from(myMap)); // [ [ 'aa', 11 ], [ 'bb', 22 ], [ 55, 33 ], [ 'cc', 44 ] ]// 清空 MapmyMap.clear();console.log(myMap); // Map(0) {}

11、Proxy

11.1、基础使用

/*Proxy 它的作用实在对象与对象的属性之间架设一个代理,用于对对象的操作进行拦截和改写,它提供了一种机制,可以拦截并修改对象的任意属性,或者对属性进行操作。*/const target = {name: 'John',age: 30
};const proxy = new Proxy(target, {get: function(target, property, receiver) {console.log(`Getting ${property}`);return target[property];},set: function(target, property, value, receiver) {console.log(`Setting ${property} to ${value}`);target[property] = value;}
})
console.log(proxy.name);  // 输出 "Getting name" 和 "John"
proxy.age = 40;  // 输出 "Setting age to 40"
console.log(target.age); // 输出 40,target会与proxy同时改变

12、Reflect

 Reflect 可以用于获取目标对象的行为,他与Object类似,但是更加易读,为了操作
 对象提供了一种更加优雅的方式,它的方法与Proxy时对应的,代替Object 的部分方法

 12.1、基础使用

const obj = {name: 'why',age: 18
}/*** 获取与设置对象属性*/
// 获取对象上的属性
const name = Reflect.get(obj, 'name')
console.log(name) // why
// 设置对象的属性
Reflect.set(obj, 'address', '北京市')/*** 函数代替命令式的写法* delete obj.name --> Reflect.deleteProperty(obj, 'name')* name in obj --> Reflect.has(obj, 'name')*/
// 判断对象上是否有指定属性
const hasName = Reflect.has(obj, 'name')
console.log(hasName) // true// 删除对象的属性
Reflect.deleteProperty(obj, 'age')
console.log(obj); // { name: 'why', address: '北京市' }

12.2、与proxy使用

/*** 一般是与 proxy一起使用的*/
// 代理对象
const arr = [1,2,3]
// 代理配置
const proxy = new Proxy(arr, {get(target, key) {// 下面是执行被代理对象的自己的行为,在这之前可以拦截一些操作console.log("get", target, key); //get [ 1, 2, 3 ] push get [ 1, 2, 3 ] lengthreturn Reflect.get(target, key)},set(target, key, value) {console.log(target, key, value); // [ 1, 2, 3 ] push 4 [ 1, 2, 3, 4 ] length 4// 下面是执行被代理对象的自己的行为,在这之前可以拦截一些操作return Reflect.set(target, key, value)}
})
proxy.push(4);// 设置对象的属性的操作
const obj2 = {name: 'kobe',age: 30
}// 设置属性
Reflect.defineProperty(obj2, 'address', {value: '上海市',writable: false, // 是否可以修改
})/*修改了Object部分方法分返回结果Object.defineProperty() 如果执行失败,会抛出错误  -> Reflect.defineProperty()执行失败则会返回false下面搞两个例子作对比
*/
console.log(Reflect.defineProperty(obj2, 'address', {value: '广州市',})
); // falseObject.defineProperty(obj2, 'xxx', {value: 'xx',writable: false, // 是否可以修改
})
Object.defineProperty(obj2, 'xxx', {value: '66',
}) // 报错 Cannot redefine property: xxx

13、class

13.1、私有及静态属性

/*** class 语法糖使用* 可以写 get 、 set 方法, 但是实际中不建议使用,这里就不写相关 demo 了* 也可以写静态方法 static 开头*/
class Person {static money = 100; // 静态属性static getMoney() { // 静态方法return Person.money;}constructor(name, age) {this.name = name;this.age = age;}greet() {console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);}
}const person = new Person('John', 25);
person.greet(); // 输出:Hello, my name is John and I am 25 years old.
console.log(Person.getMoney(), Person.money); // 输出 100 100// 继承, 父类的静态方法、属性也会被继承
class Student extends Person {constructor(name, age, grade) {// 调用父类的构造函数super(name, age);this.grade = grade;}// 可以重写父类的方法greet() {// 可以通过 super 访问父类的方法super.greet();console.log(`Hello, my name is ${this.name} and I am ${this.age} years old. I am in grade ${this.grade}.`);}// 也可以添加自己的方法study() {console.log(`${this.name} is studying.`);}
}const student = new Student('Alice', 18, 'A');
student.greet(); // 输出:Hello, my name is Alice and I am 18 years old. Hello, my name is Alice and I am 18 years old. I am in grade A.
student.study(); // 输出:Alice is studying.
console.log(Student.money, Student.getMoney()); // 输出 100 100

14、正则扩展

14.1、命名捕获组(?<命名组名称>)

const str = '<a href="https://www.baidu.com">百度</a>';
// 捕获了两个命名组,分别是 url 和 text
const reg = /<a href="(?<url>.*)">(?<text>.*)<\/a>/;const result = reg.exec(str);
console.log(result.groups.url); // https://www.baidu.com
console.log(result.groups.text); // 百度

14.2、开始结束索引

var str = "今天是2024-06-11";
var regex = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/d;/*** 输出 includes就是 各个匹配组的开始及结束下标* ['2024-06-11','2024','06','11',index: 3,input: '今天是2024-06-11',groups: [Object: null prototype] { year: '2024', month: '06', day: '11' },indices: [[ 3, 13 ],    // "2024-06-11" 的开始即结束下标[ 3, 7 ],[ 8, 10 ],[ 11, 13 ],groups: [Object: null prototype] {year: [Array],month: [Array],day: [Array]}]
]*/
console.log(regex.exec(str));

15、异步迭代器

15.1、使用

主要是与for await结合使用

 // 同步迭代器、简单使用
function *gen(){yield 1;yield 2;yield 3;
}for(let value of gen()){console.log(value); // 输出:1 2 3
}// promise 中有定時器
function timer(time){return new Promise(resolve => {setTimeout(()=>{resolve(`data-${time}`)}, time);});
}// 同步迭代器返回 promise
function *gen2(){yield timer(1000);yield timer(2000);yield timer(3000);
}const g = gen2();for(let value of g){console.log(value); // 输出:Promise { <pending> } Promise { <pending> } Promise { <pending> }
}// 异步生成器
async function *gen3(){yield timer(1000);yield timer(2000);yield timer(3000);
}async function test(){const g3 = gen3();// 三个异步生成器生成的 任务,这里不是同步执行的,是分别执行完,再从头开始执行的// 与普通的promise 普通的是并行执行的,分别会在第1、2、3秒输出结果const arr = [g3.next(), g3.next(), g3.next()];for await(const req of arr){console.log(req.value); // 第一秒的时候: data-1000 第三秒的时候:data-2000 第六秒的时候:data-3000}
}
test()

16、ES11

16.1、动态导入

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>异步迭代</title>
</head>
<body><script type="module">// module 新增 动态导入 import()async function dynamicImport() {const modulePath = './module.js';// then写法// import(modulePath)//   .then((module) => {//     // 在这里可以使用动态导入的模块//     module.default();//   })//   .catch((error) => {//     console.error('模块加载失败:', error);//   });// await 写法const module = await import(modulePath);console.log(module);  // 输出: { default: [Function] }}dynamicImport()</script>
</body>
</html>

16.2、模块化开发相关

module.js

export default {name: 666
}export function test(){}

统一管理模块

export * as obj from "xxx"	// 从其他模块导入东西在当前模块,并且与当前模块的东西一并导出去,在其他的地方使用的时候就引入当前模块即可

16.3、globalThis

提供一种标准方式,让我们在不同环境可以获取到对应的顶层对象、比如像浏览器环境的window、node环境的global等

17、ES12 及之后的

17.1、逻辑运算符

// &&=
let a = 10
a &&=20
console.log(a) // 20let b = 0
b &&=20
console.log(b) // 0// ||=
let c = 10
c ||=20
console.log(c) // 10let d = 0
d ||=20
console.log(d) // 20// ??=
let e = 10
e ??=20
console.log(e) // 10let f = 0
f ??=20
console.log(f) // 0// 示例
let user = null
user ??=666
console.log(user) // 666

17.2、数值分隔符

// 数值分隔符
let num = 123_456_789;
console.log(num, num === 123456789); // 输出: 123456789 truelet num2 = 123.456;
console.log(num2); // 输出: 123.456let num3 = 123_456.789;
console.log(num3); // 输出: 123456.789// 其他进制也可以这样表示
let binaryNum = 0b1010_1010;
console.log(binaryNum); // 输出: 170

17.3、WeakSet

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>weakSet</title>
</head>
<body><script>/*** weakSet* 类似于set,但是成员都是弱引用(且不嗯呢该是基本类型,只能是复杂类型),即垃圾回收机制不考虑WeakSet对该对象的引用,也就是说,* 如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于WeakSet之中。* 只有add delete has三个方法*/const ws = new WeakSet();let obj = {name: 111};let foo = {age: 18};ws.add(foo);ws.add(obj);console.log(ws.has(obj)); // trueconsole.log(ws.has(foo)); // trueconsole.log(ws);  // WeakSet {Object {name: 111}, Object {age: 18}}// foo = null; // 标记没了,则会被清除,不会考虑ws 中的东西// console.log(ws.has(foo)); // false// console.log(ws); // WeakSet {Object {name: 111}}// 与set 对比的话/*1. set 中的元素可以是基本类型,也可以是复杂类型,而WeakSet 中的元素只能是复杂类型2. WeakSet 中的元素都是弱引用,而set 中的元素都是强引用3. WeakSet 中的元素都是不可枚举的,而set 中的元素都是可枚举的4. WeakSet 中的元素都是不可遍历的,而set 中的元素都是可遍历的*/// 1. 基本类型let ws2 = new Set();let obj2 = {name: 111};let foo2 = {age: 18};ws2.add(foo2);ws2.add(obj2);console.log(ws2.has(obj2)); // trueconsole.log(ws2.has(foo2)); // trueconsole.log(ws2);  // Set(2) {Object {name: 111}, Object {age: 18}}foo2 = null; // 标记没了,则会被清除,不会考虑ws 中的东西console.log(ws2.has(foo2)); // falseconsole.log(ws2); // Set(1) {Object {name: 111}, Object {age: 18}} 引用还是在,就会出现问题</script>
</body>
</html>

17.4、weakMap

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>异步迭代</title>
</head>
<body><script>/*** weakMap* 类似于map,但是key只能是对象,不能是其他类型* 只有get set delete has四个方法* 不能遍历、垃圾回收机制会自动回收* 应用场景:* 1、存储一些需要频繁访问的数据*/const weakMap = new WeakMap();let obj = { name: 'zs' };weakMap.set(obj, 'value');console.log(weakMap.get(obj)); // valueconsole.log(weakMap.has(obj)); // trueconsole.log("有值", weakMap); //  WeakMap { key:{ name: 'zs' }, value: 'value' }obj = nullconsole.log("无值", weakMap); // WeakMap {} 如果是 Map 则这里会有值,就有可能会造成内存泄漏的情况</script>
</body>
</html>

以上便是本次ES6 查漏补缺的记录,欢迎留言交流,共勉

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/28072.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python pandas处理股票量化数据:笔记2

有一个同学用我的推荐链接注册了tushare社区帐号https://tushare.pro/register?reg671815&#xff0c;现在有了170分积分。目前使用数据的频率受限制。不过可以在调试期间通过python控制台获取数据&#xff0c;将数据保存在本地以后使用不用高频率访问tushare数据接口&#xf…

Scala的字符串插值

Scala的字符串插值 期待您的关注 ☀Scala学习笔记 目录 Scala的字符串插值 1. s插值器&#xff1a; 2. f插值器&#xff1a; 3. raw插值器&#xff1a; 在Scala中&#xff0c;字符串插值是一种方便的方式&#xff0c;可以在字符串中插入变量或表达式的值。Scala支持三种类型…

Mybatis用Map接收返回值可能出现的问题

先看一个示例 明明定义了Map<String,String> 实际内部存放的是Integer resultType是Map 也就是说Mybatis是通过反射将类型放进去的 躲过了编辑器检查 但是这样取值时候就会报类型转换错误 解决方式 resultMap 另外一种方式 用Number Integer和Double的父类 Ma…

大学生计算机基础题(二)

嗨&#xff0c;大家好&#xff0c;我是异星球的小怪同志 一个想法有点乱七八糟的小怪 如果觉得对你有帮助&#xff0c;请支持一波。 希望未来可以一起学习交流。 一、单选题&#xff08;20小题&#xff0c;共30分&#xff09; 1、已知a2,b3,print((ab)%b)的输出结果为&…

Excel/WPS《超级处理器》功能介绍与安装下载

超级处理器是基于Excel或WPS开发的一款插件&#xff0c;拥有近300个功能&#xff0c;非常简单高效的处理表格数据&#xff0c;安装即可使用。 点击此处&#xff1a;超i处理器安装下载 Excel菜单&#xff0c;显示如下图所示&#xff1a; WPS菜单显示&#xff0c;如下图所示&am…

15.混合专家模型(MoEs)技术揭秘

混合专家模型&#xff08;MoEs&#xff09;技术揭秘 混合专家模型&#xff08;Mixture-of-Experts, MoEs&#xff09;技术发展简史 Mixtral 8x7B &#xff1a;质效并举的稀疏混合专家模型 Mixtral 8x7B &#xff1a;质效并举的稀疏混合专家模型 MoEs 技术发展简史 MoEs 开山…

matplotlib twinx多y轴但单个图例

matplotlib 用 twinx 画多 y 轴参考 [1]。现想在画图例时&#xff0c;多个 y 轴的图例画在一起&#xff0c;写法参考 [2]。本文展示一个简例&#xff0c;效果&#xff1a; Code 要手动指定颜色&#xff0c;否则原 y 轴的用色和新 y 轴会重合。 import matplotlib.pyplot as…

永磁同步直线电机(PMLSM)控制与仿真2-永磁同步直线电机数学模型搭建

文章目录 1、公式总结2、电压方程模型3、运动方程4、推力方程5、转化关系 写在前面&#xff1a;原本为一篇文章写完了永磁同步直线电机数学模型介绍&#xff0c;永磁同步直线电机数学模型搭建&#xff0c;以及永磁同步直线电机三环参数整定及三环仿真模型搭建&#xff0c;但因为…

Dockerfile小技巧(通过变量指定程序配置文件内容)

思路&#xff1a;Dockerfile中定义变量&#xff0c;程序配置文件中使用占位符暂时代替变量内容&#xff0c;最后使用变量值替换占位符实现&#xff0c;这样就可以实现通过定义变量来定义程序启动时的一些参数了。 1、我以构建Nginx镜像为例&#xff0c;作为演示&#xff0c;Do…

TCP及UDP协议

tcp是点到点的&#xff0c;只有一条路径&#xff0c;到达顺序和发送顺序是相同的 回复的确认号是序发送端的序列号加上data的长度 1910 发送端的序列号也是那么算的 ack和下一个seq一样 那就没问题 三次握手四次挥手&#xff1a; 为啥是三次呢&#xff1f; 假如一次&#xf…

关于Linux ping 不通外网

网关为第三段为137那么子网ip第三段必须为137且IPaddr必须为137 将主机虚拟适配器连接到此网络必须勾上&#xff0c;不然vmnet适配器在windows将找不到 ping www.baidu.com不行的话试着勾上桥接模式应该是不行在勾上取消勾上桥接模式最后勾上nat模式

Spring框架的原理及应用详解(四)

本系列文章简介&#xff1a; 在当今的软件开发世界中&#xff0c;随着应用复杂性的不断增加和技术的快速发展&#xff0c;传统的编程方式已经难以满足快速迭代、高可扩展性和易于维护的需求。为此&#xff0c;开发者们一直在寻求更加高效、灵活且易于管理的开发框架&#xff0c…

【2024亲测无坑】在Centos.7虚拟机上安装Oracle 19C

目录 一、安装环境准备 1、linux虚拟机安装 2、虚拟机快照 3、空间检查&软件上传 二、Oracle软件安装 1.preinstall安装及其他配置准备 2.oracle安装 三、数据库实例的安装 1.netca——网络配置助手 2.dbca——数据库配置助手 四、ORACLE 19C 在linux centos 7上…

Linux rm命令由于要删的文件太多报-bash: /usr/bin/rm:参数列表过长,无法删除的解决办法

银河麒麟系统&#xff0c;在使用rm命令删除文件时报了如下错误&#xff0c;删不掉&#xff1a; 查了一下&#xff0c;原因就是要删除的文件太多了&#xff0c;例如我当前要删的文件共有这么多&#xff1a; 查到了解决办法&#xff0c;记录在此。需要使用xargs命令来解决参数列表…

Vue3 和 Vue2 对比分析及示例代码解析(初级)

Vue3 和 Vue2 的主要区别在于 Vue3 引入了 Composition API&#xff0c;这是一种新的组织和复用代码的方式。而 Vue2 主要依赖于 Options API。 先来看一个 Vue2 的示例&#xff1a; // Vue 2 export default {data() {return {count: 0}},methods: {increment() {this.count…

誉天教育近期开班计划(6月15日更新)

云计算HCIP 周末班 2024/6/15 田老师 售前IP-L3 周末班 2024/6/15 陈老师 RHCA442 晚班 2024/6/17邹老师 数通HCIE 晚班 2024/6/24阮老师 云计算HCIE直通车晚班 2024/6/25 曾老师 售前IT-L3 周末班 2024/6/29 伍老师 数通HCIP 晚班 2024/7/1杨老师 存储直通车 晚班 2024/7/1 高…

C# OpenCvSharp 逻辑运算-bitwise_and、bitwise_or、bitwise_not、bitwise_xor

bitwise_and 函数 🤝 作用或原理: 将两幅图像进行与运算,通过逻辑与运算可以单独提取图像中的某些感兴趣区域。如果有掩码参数,则只计算掩码覆盖的图像区域。 示例: 在实际应用中,可以用 bitwise_and 来提取图像中的某些部分。例如,我们可以从图像中提取出一个特定的颜…

【NoSQL数据库】Redis Cluster集群(含redis集群扩容脚本)

Redis Cluster集群 Redis ClusterRedis 分布式扩展之 Redis Cluster 方案功能数据如何进行存储 redis 集群架构集群伸缩向集群中添加一个新的master节点&#xff0c;并向其中存储 num10 .脚本对redis集群扩容缩容&#xff0c;脚本参数为redis集群&#xff0c;固定从6001移动200…

了解统计学中不同类型的分布

目录 一、说明 二、均匀分布&#xff1a; 三、机器学习和数据科学中的均匀分布示例&#xff1a; 3.1 对数正态分布&#xff1a; 3.2 机器学习和数据科学中的对数正态分布示例&#xff1a; 四、 帕累托分布 4.1 什么是幂律&#xff1f; 4.2 机器学习和数据科学中的帕累托分布示例…

如何清除anaconda3缓存?

如果长期使用anaconda不清理缓存&#xff0c;会导致anaconda占用磁盘空间越来越多&#xff0c;甚至系统磁盘撑爆。 清除包缓存&#xff1a; 打开 Anaconda Prompt 或者命令行窗口。运行以下命令清除包缓存&#xff1a;conda clean --all这会清除所有的包缓存&#xff0c;释放磁…