前端进阶-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

// 遍历 Map

for (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 ] ]

// 清空 Map

myMap.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 ] length
    return 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: '广州市',
  })
); // false

Object.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) // 20

let b = 0
b &&=20
console.log(b) // 0

// ||=
let c = 10
c ||=20
console.log(c) // 10

let d = 0
d ||=20
console.log(d) // 20

// ??=
let e = 10
e ??=20
console.log(e) // 10

let 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 true

let num2 = 123.456;
console.log(num2); // 输出: 123.456

let 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)); // true
    console.log(ws.has(foo)); // true
    console.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)); // true
    console.log(ws2.has(foo2)); // true
    console.log(ws2);  // Set(2) {Object {name: 111}, Object {age: 18}}

    foo2 = null; // 标记没了,则会被清除,不会考虑ws 中的东西
    console.log(ws2.has(foo2)); // false
    console.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)); // value
    console.log(weakMap.has(obj)); // true
    console.log("有值", weakMap); //  WeakMap { key:{ name: 'zs' }, value: 'value' }

    obj = null
    console.log("无值", weakMap); // WeakMap {} 如果是 Map 则这里会有值,就有可能会造成内存泄漏的情况
  </script>
</body>
</html>

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【loguru】【notifiers】配置ERROR级别邮件发送通知

完整代码 from loguru import logger from notifiers import get_notifier# 获取电子邮件通知器 notifier get_notifier("email")# 配置电子邮件通知参数 email_params {"username": "xxxxx163.com", # 发送邮件的用户名&#xff0c;我这里用…

时机:产品成功的关键因子

在商业世界里&#xff0c;产品成功与否往往与许多因素有关&#xff1a;优秀的创意、强大的团队、充足的资金等。然而&#xff0c;在这些因素之外&#xff0c;一个常被忽视但至关重要的因素就是“时机”。正如古语所言&#xff1a;“人为可做&#xff0c;天时难造”&#xff0c;…

LabVIEW电子类实验虚拟仿真系统

开发了基于LabVIEW开发的电子类实验虚拟仿真实验系统。该系统通过图形化编程方式&#xff0c;实现了复杂电子实验操作的虚拟化&#xff0c;不仅提高了学生的操作熟练度和学习兴趣&#xff0c;而且通过智能评价模块提供即时反馈&#xff0c;促进教学和学习的互动。 项目背景 在…

目标检测——可见光和红外船舶图像配对数据集

引言 亲爱的读者们&#xff0c;您是否在寻找某个特定的数据集&#xff0c;用于研究或项目实践&#xff1f;欢迎您在评论区留言&#xff0c;或者通过公众号私信告诉我&#xff0c;您想要的数据集的类型主题。小编会竭尽全力为您寻找&#xff0c;并在找到后第一时间与您分享。 …

webpack逆向

声明&#xff1a;个人总结记录一下&#xff0c;避免忘记 1、webpack 类型 单文件 直接可以在文件顶部找到加载器 多文件 顶部找不到加载器 如图所示 多文件的这话&#xff0c;全局搜所 69725 找到类似n(69725) ,单点n进去&#xff0c;可以找到加载器 2、调用 通过赋值的方…

金属3D打印技术革新模具制造业

在当今竞争激烈的制造业领域&#xff0c;模具制造业正面临着诸多挑战。冷却时间长、模具温度控制困难、制造周期长以及成本高昂等问题&#xff0c;一直是制约模具制造业发展的瓶颈。然而&#xff0c;随着金属3D打印技术的快速发展&#xff0c;模具制造业迎来了前所未有的机遇。…

SpringAI快速上手

一、导入依赖 镜像&#xff08;导入maven依赖&#xff09; <repositories><repository><id>spring-snapshots</id><name>Spring Snapshots</name><url>https://repo.spring.io/snapshot</url><releases><enabled>…

宿舍用电管理模块一进三出的升级改造

宿舍用电管理模块一进三出石家庄光大远通电气有限公司产品在高校日常管理工作中,宿舍管理是一项重要工作。宿舍管理内容复杂,而且涉及学生的日常生活,意义重大。其中,学生宿舍内漏电,超负荷用电,违规用电等现象一直是困扰后勤管理的普遍问题。随着学生日常生活方式以及生活用品…

光功率计传感器

光探测仪表: 激光功率计探头按照不同的原理和材料分为热电堆型、光电二极管型以及包含两种传感器的综合探头, 激光能量计则有热释电传感器和热电堆传感器探头 热释电效应传感器: 热释电传感器的工作原理主要是基于热释电效应。当物体处于不同温度时,会发射出不同强度的红…

【RabbitMQ】异步消息及Rabbitmq安装

https://blog.csdn.net/weixin_73077810/article/details/133836287 https://www.bilibili.com/video/BV1mN4y1Z7t9/ 同步调用和异步调用 如果我们的业务需要实时得到服务提供方的响应&#xff0c;则应该选择同步通讯&#xff08;同步调用&#xff09;。 如果我们追求更高的效…

怎样快速清理电脑里的所有软件 怎么删除干净电脑软件

苹果电脑内的软件来源主要有两个&#xff0c;一是系统预装&#xff0c;二是用户自行下载。但并不是所有应用程序都是高频使用状态&#xff0c;甚至好多是从未打开过的“屏幕装饰”。小编今日独家攻略&#xff0c;内存告急如何快速清理电脑里的所有软件&#xff0c;怎么删除干净…

upload-labs第八关教程

upload-labs第八关教程 一、源代码分析代码审计 二、绕过分析点绕过上传eval.php使用burp suite进行抓包修改放包&#xff0c;查看是否上传成功使用中国蚁剑进行连接 一、源代码分析 代码审计 $is_upload false; $msg null; if (isset($_POST[submit])) {if (file_exists(U…

第一篇:容器化的未来:从Docker的革命到云原生架构

容器化的未来&#xff1a;从Docker的革命到云原生架构 1. 引言 在当今快速演进的技术领域&#xff0c;容器化技术已经成为云计算和微服务架构的重要组成部分。该技术以其高效的资源利用率、快速的部署能力和卓越的隔离性能&#xff0c;彻底改变了软件开发和部署的方式。容器化…

机器学习:GANs网络在图像和视频技术中的应用前景

Hi~&#xff01;这里是奋斗的小羊&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f4a5;&#x1f4a5;个人主页&#xff1a;奋斗的小羊 &#x1f4a5;&#x1f4a5;所属专栏&#xff1a;C语言 &#x1f680;本系列文章为个人学习…

【漏洞复现】六零导航页 _include_file.php 任意文件上传漏洞

免责声明&#xff1a; 本文内容旨在提供有关特定漏洞或安全漏洞的信息&#xff0c;以帮助用户更好地了解可能存在的风险。公布此类信息的目的在于促进网络安全意识和技术进步&#xff0c;并非出于任何恶意目的。阅读者应该明白&#xff0c;在利用本文提到的漏洞信息或进行相关测…

西门子学习笔记15 - 位逻辑操作的学习

1、点动操作&#xff08;按下按钮就启动松开就停止&#xff09; 2、自锁电路&#xff08;可以自己保持的状态除非常闭停止按下&#xff09; 3、取反操作&#xff08;顾名思义就是反过来1就变成0&#xff0c;0就变成1&#xff09; 4、置为复位&#xff08;置位之后如果不复位的话…

Elixir学习笔记——进程(Processes)

在 Elixir 中&#xff0c;所有代码都在进程内运行。进程彼此隔离&#xff0c;彼此并发运行并通过消息传递进行通信。进程不仅是 Elixir 中并发的基础&#xff0c;而且还提供了构建分布式和容错程序的方法。 Elixir 的进程不应与操作系统进程混淆。Elixir 中的进程在内存和 CPU…

餐厅点餐系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;管理员管理&#xff0c;商品管理&#xff0c;用户管理&#xff0c;店家管理&#xff0c;广告管理 店家账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;商品管理&#xff0c;广告管…

新能源汽车高压上电、高压下电逻辑分析

高压上电逻辑 新能源汽车的上电分为高压上电和低压上电&#xff0c;高压上电流程一般理解为高压件通电的过程&#xff0c;具体流程如下&#xff1a; 1、点火开关处于ON档时&#xff0c;仪表盘点亮&#xff0c;低压电接通。 2、VCU、BMS、MCU等控制模块依次被唤醒并开始进行自检…

驾校在线考试系统源码 手机+PC+平板自适应

Thinkphp在线考题源码 驾校在线考试系统 手机PC平板 自适应&#xff0c;机动车驾驶培训学校驾校类网站源码带手机端 运行环境&#xff1a;phpmysql 内附安装说明 驾校在线考试系统源码 手机PC平板自适应