# 其他相关
一些不知道分到那个类目下的就放这里了
# 字符串转数组或对象 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"]
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}
2
3
4
5
6
# 第二个参数传数组 Array
JSON.stringify 的第二个参数传数组时,那么它只会转换数组中的 key,比如下面例子中,只会转换 name 属性
const obj = {
name: 'lsx',
age: 20
}
console.log(JSON.stringify(obj, ['name']))
//{"name":"lsx"}
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
// }
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
// }
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"
2
3
4
5
6
7
8
9
# JSON.stringify 局限性
很多人使用 JSON.stringify 来做深拷贝,但是这是万万不行的,因为它是有局限性的
从下面例子可以看出:
undefined、function、symbol 在转换后直接被忽略了
正则表达式转换成对象,日期转换成字符串
NaN、Infinity 直接变成 null 所以千万不要用 JSON.stringify 来做深拷贝!!!得不到满意的结果的!!!
# 环引用报错
对包含循环引用的对象(对象之间相互引用,形成无限循环)执行此方法,会抛出错误
以前旧版的浏览器和 Nodejs 是会直接报错的,但是貌似现在新版的不会报错了
# 数据分组 Object.groupBy
需要在 谷歌浏览器 117 以上的版本 才能运行
同时也支持了 Map.groupBy 这个方法,暂时处于实验阶段
# setTimeout+Promise+Async 输出顺序
JavaScript 代码执行机制,我就归结为三句话
遇到同步代码直接执行
遇到异步代码先放一边,并且将他回调函数存起来,存的地方叫事件队列
等所有同步代码都执行完,再从事件队列中把存起来的所有异步回调函数拿出来按顺序执行
console.log(1) // 同步
setTimeout(() => {
console.log(2) // 异步
}, 2000);
console.log(3) // 同步
setTimeout(() => {
console.log(4) // 异步
}, 0);
console.log(5) // 同步
输出 : 1 3 5 4 2
2
3
4
5
6
7
8
9
10
11
# 函数的 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
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
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' ]
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...'))
})
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)
})
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' }
]
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)
})
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)
})
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))
})
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
})
2
3
4
5