跳到主内容

Javascript手写代码题(二)

本文整理了 Javascript 手写代码题,包括使用 ES6 的 Proxy 实现数组负索引,实现一个 Promise.finallyPromise.allPromise.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() 方法接收一个 promiseiterable 类型(注:Array,Map,Set 都属于 ES6 的 iterable 类型)的输入,并且只返回一个 Promise 实例, 那个输入的所有 promiseresolve 回调的结果是一个数组。这个 Promiseresolve 回调执行是在所有输入的 promiseresolve 回调都结束,或者输入的 iterable 里没有 promise 了的时候。它的 reject 回调执行是,只要任何一个输入的 promisereject 回调执行或者输入不合法的 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);
}
}
);
}
});
};