前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >前端手写笔试题(干货版)

前端手写笔试题(干货版)

作者头像
我是leon
修改2022-05-11 10:08:11
3300
修改2022-05-11 10:08:11
举报
文章被收录于专栏:leon的专栏leon的专栏

以下是纯干货总结的手写版笔试题代码,拿走不谢!

Promise 变体

promise.first

第一个返回成功的 Promise

代码语言:javascript
复制
if (!Promise.first) {
  Promise.first = (promiseList) => {
    return new Promise((resolve, reject) => {
      let rejectNum = 0;
      const len = promiseList.length;

      promiseList.forEach((pr) => {
        Promise.resolve(pr)
          .then(resolve)
          .catch(() => {
            rejectNum++; // 记录reject的个数
            if (rejectNum == len) {
              reject("all promise is reject");
            }
          });
      });
    });
  };
}

promise.last

最后一个返回成功的 Promise

代码语言:javascript
复制
if (!Promise.last) {
  Promise.last = (promiseList) => {
    return new Promise((resolve, reject) => {
      let num = 0;
      const len = promiseList.length;
      let lastResult;

      const fn = () => {
        if (num !== len) {
          return;
        }
        lastResult ? resolve(lastResult) : reject("all promise is reject");
      };

      promiseList.forEach((pr) => {
        Promise.resolve(pr)
          .then((data) => {
            lastResult = data;
            num++;
            fn();
          })
          .catch(() => {
            num++;
            fn();
          });
      });
    });
  };
}

promise.none

与 Promise.all 相反,所有的 promise 都被拒绝,则 Promise.none 变成完成状态

代码语言:javascript
复制
if (!Promise.none) {
  Promise.none = (promiseList) => {
    return Promise.all(
      promiseList.map((pr) => {
        return new Promise((resolve, reject) => {
          return Promise.resolve(pr).then(reject, resolve);
        });
      })
    );
  };
}

Promise.any

表示只获取所有的 promise 中进入完成状态的结果,被拒绝的则忽略掉

代码语言:javascript
复制
if (!Promise.any) {
  Promise.any = (promiseList) => {
    return new Promise((resolve, reject) => {
      const result = [];
      let num = 0;
      const len = promiseList.length;

      const fn = () => {
        if (num == len) {
          result.length < 1 ? reject("all promise is reject") : resolve(result);
        }
      };

      promiseList.forEach((pr) => {
        Promise.resolve(pr)
          .then((data) => {
            result.push(data);
            num++;
            fn();
          })
          .catch(() => {
            num++;
            fn();
          });
      });
    });
  };
}

Promise.every

所有 promise 都进入完成状态,则返回 true,否则返回 false

代码语言:javascript
复制
if (!Promise.every) {
  Promise.every = (promiseList) => {
    return new Promise((resolve, reject) => {
      Promise.all(promiseList)
        .then(() => Promise.resolve(true))
        .catch(() => Promise.reject(false));
    });
  };
}

Promisify

题意

代码语言:javascript
复制
// 使用前

fs.readFile("./index.js", (err, data) => {
  if (!err) {
    console.log(data.toString());
  }

  console.log(err);
});

// 使用promisify后

const readFile = promisify(fs.readFile);

readFile("./index.js")
  .then((data) => {
    console.log(data.toString());
  })

  .catch((err) => {
    console.log("error:", err);
  });

解法

代码语言:javascript
复制
function promisify(fn) {
  return (...args) => {
    return new Promise((resolve, reject) => {
      fn.apply(this, [
        ...args,
        (err, data) => {
          if (!err) {
            return resolve(data);
          }

          return reject(err);
        },
      ]);
    });
  };
}

模拟实现 sleep

代码语言:javascript
复制
async function sleep(sleepTime) {
  return new Promise((resolve) => {
    setTimeout(resolve, sleepTime);
  });
}

JS 实现一个带有并发限制的异步调度器

题意

JS 实现一个带有并发限制的异步调度器 Scheduler,保证同时运行的任务最多有十个,完善代码中 Scheduler 类:

代码语言:javascript
复制
Class Scheduler{
	constructor(max){}
	run(callback){/*...*/}
}

let s = new Scheduler(10);
s.run(async () => {
  /* some async operations */
});

解法

代码语言:javascript
复制
Class Scheduler{
	COUNT = 0;
	LIST = [];
	constructor(max){
		this.LIMIT = 10;
	}
	async run(callback){
		if(this.COUNT >= this.LIMIT){
			// 通过await,只要不resolve,代码运行就会阻塞在这里
			await new Promise((resolve) => {
				this.list.push(resolve);
			});

		}
		this.COUNT++;

		const result = await callback();

		this.COUNT--;

		if(this.list.length > 0){
			this.list.shift()(); // 解锁代码阻塞
		}

		return result;
	}
}

let s = new Scheduler(10);
s.run(async () => {
  /* some async operations */
});
s.run(async () => {
  /* some async operations */
});
s.run(async () => {
  /* some async operations */
});

手写 Promise

Promise 要点

  • Promise 是一个类,传入的参数是一个执行器,会立即执行
  • Promise 有三种状态
    • pending 等待
    • fulfilled 完成
    • rejected 失败
  • 状态只能改变一次,不能逆向。
    • pending -> fulfilled
    • pending -> rejected
  • Promise 使用 resolve 和 reject 两个函数来改变状态
  • then 方法内部做状态判断,执行对应的方法
  • 有静态方法 Promise.resolve 和 Promise.reject

手写版

代码语言:javascript
复制
// 状态常量
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";

class Promise {
  state = PENDING;
  value = undefined;
  reason = undefined;
  onResolveCallback = [];
  onRejectCallback = [];

  constructor(executor) {
    try {
      executor(this.resolve, this.reject);
    } catch (err) {
      this.reject(err);
    }
  }
  resolve(data) {
    if (this.state !== PENDING) {
      return;
    }
    this.state = FULFILLED;
    this.value = data;

    while (this.onResolveCallback.length > 0) {
      const currentResolve = this.onResolveCallback.shift();
      currentResolve(this.value);
    }
  }
  reject(err) {
    if (this.state !== PENDING) {
      return;
    }
    this.state = REJECTED;
    this.reason = err;

    while (this.onRejectCallback.length > 0) {
      const currentReject = this.onRejectCallback.shift();
      currentReject(this.reason);
    }
  }
  static resolve(param) {
    // param是Promise对象,直接返回
    if (param instanceof Promise) {
      return param;
    }

    // 转成普通的Promise
    return new Promise((resolve) => {
      resolve(param);
    });
  }
  static reject(reason) {
    return new Promise((resolve, reject) => {
      reject(reason);
    });
  }
  catch(fn) {
    if (this.state == REJECTED) {
      typeof fn == "function" && fn(this.reason);
    }
  }
  then(resolve, reject) {
    const realResolve =
      typeof resolve == "function" ? resolve : (value) => value;
    const realReject =
      typeof reject == "function"
        ? reject
        : (reason) => {
            throw reason;
          };

    // 链式调用,需要返回新的Promise实例

    const newPromise = new Promise((resolve, reject) => {
      // 创建一个微任务,等待Promise初始化完成

      const microResolve = () => {
        queueMicrotask(() => {
          try {
            const x = realResolve(this.value);
            resolvePromise(newPromise, x, resolve, reject);
          } catch (err) {
            reject(err);
          }
        });
      };

      const microReject = () => {
        queueMicrotask(() => {
          try {
            const x = realReject(this.reason);
            resolvePromise(newPromise, x, reasolve, reject);
          } catch (err) {
            reject(err);
          }
        });
      };

      if (this.state == FULFILLED) {
        return microResolve(this.value);
      }
      if (this.state == REJECTED) {
        return microReject(this.reason);
      }
      if (this.state == PENDING) {
        this.onResolveCallback.push(microResolve);
        this.onRejectCallback.push(microReject);
      }
    });

    return newPromise;
  }
}

function resolvePromise(newPromise, x, resolve, reject) {
  if (newPromise == x) {
    return reject(new Error("循环引用"));
  }

  if (x instanceof Promise) {
    x.then(resolve, reject);
  } else {
    resolve(x);
  }
}

模拟 bind 的实现

ES5 版本

代码语言:javascript
复制
Function.prototype.bind =
  Function.prototype.bind ||
  function (context) {
    if (typeof this !== "function") {
      throw new Error("can't bind");
    }

    let self = this;
    let args = Array.prototype.slice(arguments, 1); // 缓存参数

    const fnOP = function () {};

    const bound = function () {
      let innerArgs = Array.prototype.slice(arguments);

      return self.apply(
        this instanceof fnOP ? this : context,
        args.concat(innerArgs)
      );
    };

    fnOP.prototype = this.prototype;
    bound.prototype = new fnOP();

    return bound;
  };

ES6 版本

代码语言:javascript
复制
Function.prototype.bind =
  Function.prototype.bind ||
  function () {
    if (typeof this !== "function") {
      throw new Error("can't bind");
    }

    const args = Array.from(arguments);
    const context = args.shift();
    const self = this;

    const fnOP = Object.create(this.prototype);

    const fn = function () {
      const innerArgs = Array.from(arguments);
      return self.apply(
        this instanceof fnOP ? this : context,
        args.concat(innerArgs)
      );
    };

    fn.prototype = fnOP;

    return fn;
  };

模拟 new 的实现

代码语言:javascript
复制
function Otaku(name, age) {
  this.name = name;
  this.age = age;

  this.habit = "Games";
}

Otaku.prototype.strength = 60;

Otaku.prototype.sayYourName = function () {
  console.log("I am " + this.name);
};

// 调用
myNew(Otaku, "Kevin", "18");

console.log(person.name); // Kevin
console.log(person.habit); // Games
console.log(person.strength); // 60

person.sayYourName(); // I am Kevin
代码语言:javascript
复制
// 实现
function myNew(fn, ...args) {
  const obj = Object.create(fn.prototype);

  const ret = fn.apply(obj, args); // ret有可能为null

  return typeof ret === "object" ? ret || obj : obj;
}

深拷贝

深拷贝注意点

  • 注意类型,7 种基本类型: booleanstringnumberundefinednullSymbolBigInt
  • Object类型的可能情况(Object.prototype.toString.call):
    • object Object
    • object Function - typeof function == function
    • object Null
    • object Array
    • object RegExp

解法

代码语言:javascript
复制
function deepCopy(data, hash = new WeakMap()) {
  if (typeof data !== "object" || data == null) {
    return data;
  }
  // 判断传入的待拷贝对象是否已经存在hash中,避免循环引用造成死循环
  if (hash.has(data)) {
    return hash.get(data);
  }

  const newData = Array.isArray(data) ? [] : {};
  const dataKeys = Object.keys(data);
  dataKeys.forEach((key) => {
    const current = data[key];
    const typeString = Object.prototype.toString.call(current).toLowerCase();

    if (typeof current !== "object" || current == null) {
      // 基本类型
      newData[key] = current;
      return;
    }

    switch (typeString) {
      case "[object array]":
        newData[key] = [...deepCopy(current, hash)];
        break;
      case "[object set]":
        newData[key] = new Set([...current.values()]);
        break;
      case "[object map]":
        newData[key] = new Map([...current]);
        break;
      default:
        // 普通对象进行递归操作
        hash.set(data, data);
        newData[key] = deepCopy(current, hash);
    }
  });

  return newData;
}

数组去重

ES6 Set

代码语言:javascript
复制
const uniqueArr = [...new Set(arr)];
const uniqueArr = Array.from(new Set(arr));

reduce

代码语言:javascript
复制
function unique(arr) {
  // 先排序,如果重复,则上一个下标的内容一样
  return arr.sort().reduce((acc, current) => {
    if (acc.length == 0 || acc[acc.length - 1] !== current) {
      acc.push(current);
    }
    return acc;
  }, []);
}

filter

代码语言:javascript
复制
function unique(arr) {
  return arr.filter((element, index, array) => {
    return array.indexOf(element) == index;
  });
}

扁平化数组

使用 reduce 方法进行扁平化

代码语言:javascript
复制
function flattenDeep(arr) {
  return Array.isArray(arr)
    ? arr.reduce((acc, current) => {
        return [...acc, ...flattenDeep(current)];
      }, [])
    : [arr];
}

模拟栈

代码语言:javascript
复制
function flattenDeep(arr) {
  const stack = [...arr]; // 先平展复制到stack
  const result = [];

  while (stack.length) {
    // 取出末尾的值
    const current = stack.pop();
    if (Array.isArray(current)) {
      // 如果值是数组,平展后,重新推入stack
      stack.push(...current);
    } else {
      // 末尾是普通值,则存入result
      result.unshift(current);
    }
  }
  return result;
}

柯里化

代码语言:javascript
复制
function curry(fn) {
  return function curried(...args) {
    if (args.length >= fn.length) {
      // 传入参数已覆盖所有形参
      fn.apply(this, args);
    } else {
      return function (...args2) {
        return curried.apply(this, args.concat(args2));
      };
    }
  };
}

防抖

代码语言:javascript
复制
function debounce(fn, wait) {
  let timer = null;
  return () => {
    clearTimeout(timer);
    timer = setTimeout(() => {
      fn.apply(this, Array.from(arguments));
    }, wait);
  };
}

节流

代码语言:javascript
复制
function throttle(fn, wait) {
  let timer = null;

  return () => {
    if (timer !== null) {
      return;
    }

    timer = setTimeout(() => {
      fn.apply(this.Array.from(arguments));
      timer = null;
    }, wait);
  };
}

最近笔者在整理第一本电子书书稿《前端面试手册》,有兴趣的同学可以关注下~

喜欢我文章的朋友,可以通过以下方式关注我:

关注
关注
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-03-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Promise 变体
    • promise.first
      • promise.last
        • promise.none
          • Promise.any
            • Promise.every
            • Promisify
              • 题意
                • 解法
                • 模拟实现 sleep
                • JS 实现一个带有并发限制的异步调度器
                  • 题意
                    • 解法
                    • 手写 Promise
                      • Promise 要点
                        • 手写版
                        • 模拟 bind 的实现
                          • ES5 版本
                            • ES6 版本
                            • 模拟 new 的实现
                            • 深拷贝
                              • 深拷贝注意点
                                • 解法
                                • 数组去重
                                  • ES6 Set
                                    • reduce
                                      • filter
                                      • 扁平化数组
                                        • 使用 reduce 方法进行扁平化
                                          • 模拟栈
                                          • 柯里化
                                          • 防抖
                                          • 节流
                                          领券
                                          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档