# 其他相关

一些不知道分到那个类目下的就放这里了

# 字符串转数组或对象 JSON.parse

const objStr = '{"name": "Alice", "age": 25}'
const obj = JSON.parse(objStr)

console.log(obj) // {name: "Alice", age: 25}

let str = '[1, 2, 3, 4, 5]'
let arr = JSON.parse(str)
console.log(arr) // [1, 2, 3, 4, 5]

//普通字符串转换方法一
let str = 'Hello World'
let arr = str.split('') // 以空字符串作为分隔符
console.log(arr) // ["H", "e", "l", "l", "o", " ", "W", "o", "r", "l", "d"]
//普通字符串转换方法二
let str = 'Hello World'
let arr = Array.from(str)
console.log(arr) // ["H", "e", "l", "l", "o", " ", "W", "o", "r", "l", "d"]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 将一个对象或者数组转成字符串 JSON.stringify

const obj = {
  name: 'lsx',
  age: 20
}
console.log(JSON.stringify(obj))
//{"name":"lsx","age":20}
1
2
3
4
5
6

# 第二个参数传数组 Array

JSON.stringify 的第二个参数传数组时,那么它只会转换数组中的 key,比如下面例子中,只会转换 name 属性

const obj = {
  name: 'lsx',
  age: 20
}
console.log(JSON.stringify(obj, ['name']))
//{"name":"lsx"}
1
2
3
4
5
6

# 第三个参数传数字 Number

JSON.stringify 的第三个参数传数字时,这个数字会被当成 JSON 的缩进级别

比如下面例子,分别是 2 空格、4 空格、6 空格缩进

const obj = {
  name: 'lsx',
  age: 20
}
console.log(JSON.stringify(obj, null, 2))
console.log(JSON.stringify(obj, null, 4))
console.log(JSON.stringify(obj, null, 5))
// {
//     "name":"lsx",
//     "age":20
// }
// {
//         "name":"lsx",
//         "age":20
// }
// {
//             "name":"lsx",
//             "age":20
// }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 第三个参数传字符串 String

JSON.stringify 的第三个参数传字符串时,这个字符串会被当成 JSON 的缩进占位符

const obj = {
  name: 'lsx',
  age: 20
}
console.log(JSON.stringify(obj, null, '-'))
console.log(JSON.stringify(obj, null, '--'))
console.log(JSON.stringify(obj, null, '---'))
// {
// -"name":"lsx",
// -"age":20
// }
// {
// --"name":"lsx",
// --"age":20
// }
// {
// ---"name":"lsx",
// ---"age":20
// }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# toJSON

如果被转换的对象中有 toJSON 这个方法的话,那么当 JSON.stringify 进行转换后,会获取这个 toJSON 方法的 执行返回值

const obj = {
  name: 'lsx',
  age: 20,
  toJSON: function () {
    return 'toJSON rerult'
  }
}
console.log(JSON.stringify(obj))
//"toJSON rerult"
1
2
3
4
5
6
7
8
9

# JSON.stringify 局限性

很多人使用 JSON.stringify 来做深拷贝,但是这是万万不行的,因为它是有局限性的 alt text

从下面例子可以看出:

  • undefined、function、symbol 在转换后直接被忽略了

  • 正则表达式转换成对象,日期转换成字符串

  • NaN、Infinity 直接变成 null 所以千万不要用 JSON.stringify 来做深拷贝!!!得不到满意的结果的!!!

alt text

# 环引用报错

对包含循环引用的对象(对象之间相互引用,形成无限循环)执行此方法,会抛出错误

以前旧版的浏览器和 Nodejs 是会直接报错的,但是貌似现在新版的不会报错了

alt text

# 数据分组 Object.groupBy

需要在 谷歌浏览器 117 以上的版本 才能运行

alt text

同时也支持了 Map.groupBy 这个方法,暂时处于实验阶段

# setTimeout+Promise+Async 输出顺序

JavaScript 代码执行机制,我就归结为三句话

  • 遇到同步代码直接执行

  • 遇到异步代码先放一边,并且将他回调函数存起来,存的地方叫事件队列

  • 等所有同步代码都执行完,再从事件队列中把存起来的所有异步回调函数拿出来按顺序执行

alt text

console.log(1) // 同步
setTimeout(() => {
  console.log(2) // 异步
}, 2000);
console.log(3) // 同步
setTimeout(() => {
  console.log(4) // 异步
}, 0);
console.log(5) // 同步

输出 : 1 3 5 4 2
1
2
3
4
5
6
7
8
9
10
11

alt text

# 函数的 length 是多少

如果有默认参数的话,函数的 length 会是多少呢?

function fn1(name) {}

function fn2(name = '林三心') {}

function fn3(name, age = 22) {}

function fn4(name, age = 22, gender) {}

function fn5(name = '林三心', age, gender) {}

console.log(fn1.length) // 1
console.log(fn2.length) // 0
console.log(fn3.length) // 1
console.log(fn4.length) // 1
console.log(fn5.length) // 0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

说明了,function 的 length,就是第一个具有默认值之前的参数个数

在函数的形参中,还有剩余参数这个东西,那如果具有剩余参数,会是怎么算呢?

function fn1(name, ...args) {}

console.log(fn1.length) // 1
123['toString'].length + 123 = ?的答案是124
1
2
3
4

可以看出,剩余参数是不算进 length 的计算之中的

总结就是:length 是函数对象的一个属性值,指该函数有多少个必须要传入的参数,即形参的个数。形参的数量 不包括剩余参数个数,仅包括第一个具有默认值之前的参数个数

# 当所有异步操作都成功完成时才继续执行 Promise.all()

当你需要并行执行多个异步操作,并且只有当所有异步操作都成功完成时才继续执行后续代码。

const promise1 = Promise.resolve('Promise')
const promise2 = new Promise((resolve, reject) => {
  setTimeout(resolve, 2000, 'is')
})
const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 1000, 'useful')
})

Promise.all([promise1, promise2, promise3]).then(values => {
  console.log(values)
})
//[ 'Promise', 'is', 'useful' ]
1
2
3
4
5
6
7
8
9
10
11
12

但如果某个 promise 对象在执行过程中抛出异常,比如,promise2 对象在执行时抛出异常

const promise2 = new Promise((resolve, reject) => {
  setTimeout(reject, 2000, new Error('Crash...'))
})
1
2
3

那么,你就无法正常获取 promise1 和 promise3 对象返回的结果。针对这个问题,你可以使用 Promise.allSettled() 方法。

# 待多个异步操作完成,并且你需要知道每个异步操作的结果 Promise.allSettled()

当你想要等待多个异步操作完成,并且你需要知道每个异步操作的结果。

const promise1 = Promise.resolve('Promise')
const promise2 = new Promise((resolve, reject) => {
  setTimeout(reject, 2000, new Error('Crash...'))
})
const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 1000, 'useful')
})

Promise.allSettled([promise1, promise2, promise3]).then(values => {
  console.log(values)
})
1
2
3
4
5
6
7
8
9
10
11

运行以上代码之后,控制台会输出以下结果。数组中每个对象上的 status 属性是用于标识对应 promise 对象的 执行状态

[
  { status: 'fulfilled', value: 'Promise' },
  {
    status: 'rejected',
    reason: Error: Crash...
  },
  { status: 'fulfilled', value: 'useful' }
]
1
2
3
4
5
6
7
8

# 多个异步操作,只关心最先完成 Promise.race()

当你有多个异步操作,并且你只关心哪个操作最先完成,不管它是成功还是失败。

const promise1 = new Promise((resolve, reject) => {
  setTimeout(reject, 1000, 'Promise 1 resolved')
})

const promise2 = new Promise((resolve, reject) => {
  setTimeout(resolve, 2000, 'Promise 2 resolved')
})

Promise.race([promise1, promise2]).then(value => {
  console.log(value)
})
1
2
3
4
5
6
7
8
9
10
11

以上代码成功运行后,控制台会输出 "Promise 1 resolved"。

# 多个异步操作,得到第一个成功的异步操作的结果 Promise.any()

当你有多个异步操作,并且你想要得到第一个成功的异步操作的结果,而忽略其他已失败的异步操作。

const promise1 = Promise.reject('any')
const promise2 = new Promise(resolve => setTimeout(resolve, 100, 'Promise 2 resolved'))
const promise3 = new Promise(resolve => setTimeout(resolve, 500, 'Promise 3 resolved'))

Promise.any([promise1, promise2, promise3]).then(value => {
  console.log(value)
})
1
2
3
4
5
6
7

以上代码成功运行后,控制台会输出 "Promise 2 resolved"。

# 外部控制 Promise 对象的状态 Promise.withResolvers()

在某些场景下,我们希望在外部控制 Promise 对象的状态。比如,在请求网络数据的场景,当成功接收所有数据 后,才调用 resolve 方法设置当前 Promise 的返回数据。

let resolve, reject
const promise = new Promise((res, rej) => {
  resolve = res
  reject = rej
})

asyncRequest(config, response => {
  const buffer = []
  response.on('callback-request', id => {
    promise.then(data => callback(id, data))
  })
  response.on('data', data => buffer.push(data))
  response.on('end', () => resolve(buffer))
  response.on('error', reason => reject(reason))
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

上述的场景在日常工作中很常见,为了避免重复写以下代码。

let resolve, reject
const promise = new Promise((res, rej) => {
  resolve = res
  reject = rej
})
1
2
3
4
5
知识汇总   |