JS期前端笔试题

156 阅读4分钟

画出浏览器渲染示意图

image.png

  • 追问1:引起无效回流的原因有哪些/怎样避免无效回流;
  • 追问2:你平时是如何优化前端性能的;
  • 追问3:页面白屏的成因与防治;
  • 追问4:渲染算不算异步?优先级如何?

请画出Animal-Person-Student三级继承关系到原型链示意图

原型链示意图3.jpg

  • 追问:class的extends起什么作用?背后到底干了写什么?
  • 追问:父类的方法实现子类不满意时怎么办?
  • 追问:既想使用父类实现,又想扩展出一些新内容,怎么办?
  • 追问:super(name)和super.sayHello()有何区别?
  • 追问:new 关键词做了些什么?
  • 追问:OOP的所有问题

请画出HTTP协议的缓存流程示意图

HTTP协议缓存机制.png

  • 追问:Etag和Last-Modified冲突时,该返数据还是304?
  • 追问:造成Etag未变但Last-Modified变了,为什么会形成这种现象?
  • 追问:用户的刷新动作对缓存有什么影响?

事件循环示意图

JS事件循环.jpg

  • 追问:同一时间:定时器到钟了,用户点击了,网络数据回来了,回调先后顺序
  • 追问:多个异步任务如何调度?
  • 追问:如何实现多个异步任务的串行有关联/无关联,并行有关联/无关联;
  • 追问:几乎所有异步问题...

手写防抖函数debounce

function debounce(fn, delay) {
  let timer = null;

  return function (...args) {
    if (timer) {
      clearTimeout(timer);
      timer = null
    }

    timer = setTimeout(() => {
      fn.apply(null, args);
      timer = null;
    }, delay);
  };
}

手写节流函数throttle

function throttle(fn, delay) {
  let lock = false;

  return function (...args) {
    if (!lock) {
      fn.apply(null, args);
      lock = true;

      /* 接下来的1秒内禁止点击回调触发 */
      setTimeout(() => {
        lock = false;
      }, delay);
    }
  };
}

手写深拷贝deepCopy

function deepCopy(data){
    switch (true) {
        /* 基本数据类型 */
        case typeof(data)!=="object" && typeof(data)!=="function":
            return data;

        /* 函数类型 */
        case typeof(data)==="function":
            return data;

        /* 数组类型 */
        case Array.isArray(data):
            const arr = []
            // 递归深拷贝所有元素 丢入arr
            for(let i=0;i<data.length;i++){
                arr[i] = deepCopy(data[i])
            }
            
            return arr;

        /* 对象类型 */
        case typeof(data)==="object":
            const obj = {}
            // 递归深拷贝对象中的所有key-value 丢入obj
            for(let key in data){
                obj[key] = deepCopy(data[key])
            }
            return obj;
    
        default:
            return data;
    }
}

手写Promise链求5的阶乘

function multiply(a, b, callback) {
    setTimeout(() => callback(a * b), 500);
}

function mulPromise(a, b) {
    return new Promise((resolve, reject) =>
     multiply.apply(null, [a, b, (ret) => resolve(ret)])
    );
}
    
mulPromise(2, 3)
.them(res => mulPromise(res, 4)
.them(res => mulPromise(res, 5)
.them(res => console.log('最终结果', res)

手写async-await求5的阶乘

 /* 云端乘法函数,请不要修改其代码 */
function multiply(a, b, callback) {
    setTimeout(() => {
    // 注意这里有机会出错!!!!!
     Math.random() > 0.5 ? callback(a * b) : callback(-1);
    }, 500);
}

// 基于multiply函数,使用async-await求得5的阶乘,如果云端出错妥善处理之
function mulPromise(a, b) {
    return new Promise((resolve, reject) => {
        multiply.apply(null, [ a,b, (ret) => {
            ret === -1 ? reject("云端计算失败") : resolve(ret);
            },
        ]);
    });
}

async function test() {
    try {
        let res = await mulPromise(2, 3)
        res = await mulPromise(res, 4)
        res = await mulPromise(res, 5)
        console.log(res)
    } catch(err) {
          console.log('err=', err)
       }
   }
test()

手写数组的批处理API(即入参为一个函数的API)demo各一个

const arr = [1, 2, 3, 4, 5]
遍历:
forEach((item, index) => { console.log(item) )

映射:
map((item) => {Math.pow(item, 2)})

过滤:
filter((item) => {item % 3 == 0})

所有:
every((item) => {item % 3 == 0})

有一个:
some((item) => {item % 3 == 0})

第一个:
find((item) => {item % 3 == 0})

累加:reduce((pv, cv) => {pv + cv})

在100基础上累加:reduce((pv, cv) => {pv + cv}, 100)

手写Promise三大静态调度API demo各一个

    /* 
        共荣期约:全都成功才算成功
        全部resolve时得到values,任何一个reject时 得到err
        场景:全部成功时 任务整体才成功
        */
      function promiseAll() {
        Promise.all([
          Promise.resolve(3),
          Promise.reject(42),
          new Promise(
            (resolve, reject) => setTimeout(() => resolve("foo"), 5000)
            //    (resolve,reject)=>setTimeout(()=>reject("我妈不让我和坏孩子玩"),5000)
          ),
        ])
          .then((values) => console.log("values=", values))
          .catch((err) => console.log("err=", err));
      }
 /* 
        完全期约:保证所有promise完成其任务 并获得一个具体的结果列表
        场景:一组无关联的并发任务 需要清楚知道每个Promise的最终状态
        */
      function promiseAllSettled() {
        Promise.allSettled([
          Promise.resolve(3),
          Promise.resolve(42),
          new Promise(
            // (resolve, reject) => setTimeout(() => resolve("foo"), 5000)
            (resolve, reject) =>
              setTimeout(() => reject("我妈不让我和坏孩子玩"), 5000)
          ),
        ])
          .then((values) => console.log("values=", values))
      }
 /* 
        竞速契约:以率先resolve/reject的promise的结果作为最终结果
        一组并发任务,以率先resolve或reject出来的结果为最终结果
        */
      function promiseRace() {
        Promise.race([
          new Promise((resolve, reject) => {
            setTimeout(resolve, 3000, "one");
          }),

          new Promise((resolve, reject) => {
            //   1000毫秒后 回调reject 入参two
            setTimeout(reject, 10000, "two");
          }),

          new Promise(
            // (resolve, reject) => setTimeout(() => resolve("foo"), 5000)
            (resolve, reject) =>
              setTimeout(() => reject("我妈不让我和坏孩子玩"), 5000)
          ),
        ])
          .then((value) => console.log("value=", value))
          .catch((err) => console.log("err=", err));
      }

扩展数组实现arr.countItems,以对象形式返回每个元素分别出现多少次

  const arr = [2, 5, 6, 6, 4, 3, 3, 4, 5, 2]
  Array.prototype.countItems = function () {
    let obj = {}
    this.forEach(item => {
      if (!obj[item]) {
        obj[item] = 1
      } else {
        obj[item]++
      }
    });
    return obj
  }
  console.log(arr.countItems());

手写Animal-Person-Student三级继承关系(含静态与覆写)原型链实现

手写Animal-Person-Student三级继承关系(含静态与覆写)class实现

手写多参柯里化高阶函数curry

手写同步函数的Promise化高阶函数promisify

手写管道高阶函数pipe

手写组合高阶函数compose

手写MyMap

手写MySet

前端核心笔试题(持续更新)具体看这里