Javascript手写代码题(二)
本文整理了 Javascript 手写代码题,包括使用 ES6 的 Proxy
实现数组负索引,实现一个 Promise.finally
,Promise.all
,Promise.race
函数。
使用 ES6 的 Proxy 实现数组负索引
负索引:可以使用负数访问下标,例如 arr[-1]
替代 arr[arr.length - 1]
访问最后一个元素,[-2] 访问倒数第二个元素,以此类推
const arrProxy = new Proxy(arr, {
get(target, key, receive) {
let index = key;
if (key < 0) {
index = target.length + Number(key); // 注意key是字符串,需要转为整数
}
return Reflect.get(target, index, receive);
},
});
实现一个 Promise.finally 函数
Promise.prototype.finally = function (callback) {
let P = this.constructor;
return this.then(
(value) => P.resolve(callback()).then(() => value),
(reason) =>
P.resolve(callback()).then(() => {
throw reason;
})
);
};
实现一个扁平数组的功能
例如现在有一个数组,[1, [2, 3], [4, [5, 6]]]
扁平化结果为 [1,2,3,4,5,6]
function flatten(arr) {
return arr.reduce((prev, curr) => {
if (Array.isArray(curr)) {
return prev.concat(flatten(curr));
}
return prev.concat(curr);
}, []); // 初始值为空数组
}
// 或者,直接原生方法
arr.flat(Infinity);
实现 Promise.all
Promise.all()
方法接收一个 promise
的 iterable
类型(注:Array,Map,Set 都属于 ES6 的 iterable
类型)的输入,并且只返回一个 Promise
实例, 那个输入的所有 promise
的 resolve
回调的结果是一个数组。这个 Promise
的 resolve
回调执行是在所有输入的 promise
的 resolve
回调都结束,或者输入的 iterable
里没有 promise
了的时候。它的 reject
回调执行是,只要任何一个输入的 promise
的 reject
回调执行或者输入不合法的 promise
就会立即抛出错误,并且 reject
的是第一个抛出的错误信息。
代码实现如下
Promise.mAll = function (iterables) {
return new Promise((resolve, reject) => {
let result = [];
let count = 0;
for (let i = 0; i < iterables.length; i++) {
Promise.resolve(iterables[i]).then((value) => {
result[i] = value;
count++;
if (count === iterables.length) {
// 所有都成功了,返回结果
resolve(result);
}
}, reject);
}
});
};
实现 Promise.race
Promise.race(iterable)
方法返回一个 promise,一旦迭代器中的某个 promise 解决或拒绝,返回的 promise 就会解决或拒绝。
实现代码如下
Promise.mRace = function(iterables) {
return new Promise((resolve, reject) => {
for (let i = 0; i < iterables.length; i++) {
Promise.resolve(iterables[i]).then(resolve, reject);
}
});
};
}
实现 Promise.allSettled
该 Promise.allSettled()
方法返回一个在所有给定的 promise 都已经 fulfilled 或 rejected 后的 promise,并带有一个对象数组,每个对象表示对应的 promise 结果。
当您有多个彼此不依赖的异步任务成功完成时,或者您总是想知道每个 promise 的结果时,通常使用它。
相比之下,Promise.all()
更适合彼此相互依赖或者在其中任何一个 reject 时立即结束。
实现代码如下
Promise.mAllSettled = function (iterables) {
return new Promise((resolve, reject) => {
let result = [];
let count = 0;
for (let i = 0; i < iterables.length; i++) {
Promise.resolve(iterables[i]).then(
(value) => {
result[i] = { status: "fulfilled", value };
count++;
if (count === iterables.length) {
resolve(result);
}
},
(reason) => {
result[i] = { status: "rejected", reason };
count++;
if (count === iterables.length) {
resolve(result);
}
}
);
}
});
};