2023 前端一场面试及答案整理

news2025/2/25 14:12:08

金三马上就要开始了,俗话说得好,知己知彼百战百胜,多准备总是没有错的。以面试的形式和大家一起学习、一起回顾我们的职场生涯。今天简单总结一下我个人去面试,包括我在面试别人时的经验。加油加加油!!!

目录

开头热场问题

1. 说一下工作中解决过比较困难的问题 或 说一下自己项目中比较有亮点的地方

2. 你了解浏览器的事件循环吗?

    2.1 为什么 js 在浏览器中有事件循环的机制?

    2.2 你了解事件循环当中的两种任务吗?

    2.3 为什么要引入微任务的概念,只有宏任务可以吗?

    2.4 你了解 Node.js 的事件循环吗?Node中的事件循环和浏览器的事件循环有什么区别?

        2.5 这个时候理论问了这么多了,开始实践1

        2.6 实践2

     2.7 实践3 

3. 事件的捕获和冒泡机制你了解多少?

    3.1 基本概念

    3.2  window.addEventListener 监听的是什么阶段的事件?         

    3.3 平常有哪些场景用到了这些机制? 

4.  你工作中用过防抖和节流吗?

    4.1 基本概念

    4.2 分别适合用在什么场景?

    4.3  手写节流函数

5. 你了解 Promise 吗?平时用的多吗?

    5.1 Promise.all( ) 你知道有什么特性吗?

    5.2 如果其中一个 Promise 报错了怎么办?

    5.3 如果有一个 Promise 报错了,那么其他的 Promise 还会执行吗?

    5.4 手写一个 Promise.all(  )

    5.5 Promise 在初始化的时候已经执行了,那么利用这个特性我们可以做点什么(扩展性问题)?

 6. 字节经典算法题---- 接雨水


开头热场问题

1. 说一下工作中解决过比较困难的问题 或 说一下自己项目中比较有亮点的地方

   考察目的:面试官主要看一下我们解决问题的能力

   解答:这个问题 主要是靠大家的工作积累,平时工作过程中可以养成一个良好的习惯,无论做什么需求的时候,都花点时间去记录一下,这样积累无论是一年,还是两年,或者五年都会积累很多也无需求,然后自己梳理一下,在面试的时候反馈给面试官,让面试官虎躯一震,offer马上到手~~~

2. 你了解浏览器的事件循环吗?

     考察目的:以此问题作为一个突破口,深度挖掘你对整个概念的了解

    2.1 为什么 js 在浏览器中有事件循环的机制?

     解答

               ① JS 是单线程的

               ② event loop

    2.2 你了解事件循环当中的两种任务吗?

     解答

                ① 宏任务:整体代码块、setTimeOut、setInterval、I/O操作

                ② 微任务:new Promise().then()、mutationObserver(前端的回溯)

    2.3 为什么要引入微任务的概念,只有宏任务可以吗?

    解答

        宏任务:先进先出的原则

        在 JS 的执行过程中 或者说在页面的渲染过程中,宏任务是按照先进先出的原则执行,我们并不能准确的控制 这些任务被推进任务队列里,但是我们这个时候如果出来一个非常高优先级的任务,这个时候该怎么办?如果我们只有宏任务,再往任务队列里面推一个,秉承着先进先出的原则,那么它肯定是最后一个执行的,所以要引入微任务;

了解到宏任务与微任务过后,我们来学习宏任务与微任务的执行顺序。        

  • 代码开始执行,创建一个全局调用栈,script作为宏任务执行
  • 执行过程过同步任务立即执行,异步任务根据异步任务类型分别注册到微任务队列和宏任务队列
  • 同步任务执行完毕,查看任务队列
    • 若存在微任务,将微任务队列全部执行(包括执行微任务过程中产生的新微任务)
    • 若无微任务,查看宏任务队列,执行第一个宏任务,宏任务执行完毕,查看微任务队列,重复上述操作,直至宏任务队列为空

    2.4 你了解 Node.js 的事件循环吗?Node中的事件循环和浏览器的事件循环有什么区别?

    解答

            Node宏任务的执行顺序:

                ① timers定时器:执行已经安排过的,setTimeout 和 setInterval 的回调函数;

                ②pending callback 待定回调:执行延迟到下一个循环迭代的I/O回调;

                ③idle,prepare:仅系统内部使用;

                ④poll:检索新的I/O事件,执行与I/O相关的回调

                ⑤check:执行setImmediate() 回调函数

                ⑥close callback:socket.on('close', (  )=>{  })

          微任务和宏任务在node的执行顺序:

        首先大家要明白,Node中微任务和宏任务的执行顺序是和 node 的版本有关系的

        Node V10 之前:

                 ① 执行完上述一个阶段中的所有任务

                 ② 执行 nextTick 队列里面的内容

                 ③ 执行完微任务队列的内容

        Node V10 之后:

                和浏览器的行为统一了

        2.5 这个时候理论问了这么多了,开始实践1

async function async1() {
  console.log("async1 start");
  await async2();
  console.log("async1 end");
}
async function async2() {
  console.log("async2");
}
console.log("script start");
setTimeout(() => {
  console.log("setTimeout");
}, 0);
async1();
new Promise((resolve) => {
  console.log("promise1");
  resolve();
}).then(() => {
  console.log("promise2");
});
console.log("script end");

// 1. script start
// 2. async1 start
// 3. async2
// 4. promise1
// 5. script end
// 6. async1 end
// 7. promise2
// 8. setTimeout

        2.6 实践2

                这个就比较有难度了,如果真的不会,千万不要张嘴就来一句:“我不会”,这个时候我作为面试官的时候心里就在想:“我屮艸芔茻,这好尴尬”!娱乐一下开个玩笑,这个时候要尝试着说出自己的思路,即使是错的,你也要让面试官看到你的 进取、钻研精神!

console.log("start");
setTimeout(() => {
  console.log("children2");
  Promise.resolve().then(() => {
    console.log("children3");
  });
}, 0);

new Promise((resolve, reject) => {
  console.log("children4");
  setTimeout(() => {
    console.log("children5");
    resolve("children6"); // 此处大坑
  }, 0);
}).then((res) => {
  console.log("children7");
  setTimeout(() => {
    console.log(res);
  }, 0);
});

// 1. start
// 2. children4
/** 第一轮宏任务执行结束,尝试清空微任务队列,发现没有微任务,尝试执行下一轮宏任务   */
// 3. children2
/** 第二轮宏任务执行结束,尝试清空微任务队列,   */
// 4. children3
// 5. children5
/** 第三轮宏任务执行结束,尝试清空微任务队列,   */
// 6. children7
// 7. children6

     2.7 实践3 

        到这一步,大家心里是不是在想:“面试官怎么抓着 事件循环不放了”,最后一道题

const p = () => {
  return new Promise((resolve, reject) => {
    const p1 = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve(1); // 这里 不会再输出了,因为 resolve(2) 已经把结果输出
      }, 0);
      resolve(2);
    });
    p1.then((res) => {
      console.log(res);
    });
    console.log(3);
    resolve(4);
  });
};
p().then((res) => {
  console.log(res);
});
console.log("end");

// 1. 3
// 2. end
// 3. 2
// 4. 4

                 到此为止,事件循环结束!

3. 事件的捕获和冒泡机制你了解多少?

    3.1 基本概念

           以HTML为例:↓

           捕获:从window →  parent  →  child  →  son 到目标元素以后,转为冒泡

           冒泡:目标元素 son  →  child  →  parent  → window

    3.2  window.addEventListener 监听的是什么阶段的事件?         

// 冒泡阶段
window.addEventListener("click", () => {

}); // 第三个参数默认为 false,为false 时,监听的为冒泡阶段

// 捕获阶段
window.addEventListener("click", () => {
  
}, true);

    3.3 平常有哪些场景用到了这些机制? 

        3.3.1. 事件委托 

    <ul id="ul">
      <li>1</li>
      <li>2</li>
      <li>3</li>
      <li>4</li>
      <li>5</li>
      <li>6</li>
      <li>7</li>
      <li>8</li>
    </ul>


    const ul = document.querySelector("ul");
    ul.addEventListener("click", (e) => {
      const target = e.target;
      if (target.tagName.toLowerCase() === "li") {
        const liList = document.querySelectorAll("li");
        //  这里之所以会这么写,是因为 liList 并非是一个真正的 Array
        // 此时返回的是一个 nodeList,如果想使用 数组的 方法,需要改变this
        const index = Array.prototype.indexOf.call(liList, target);
        console.log(`内容:${target.innerHTML},索引:${index}`);
      }
    });

        3.3.2  场景设计题

        一个历史页面,上面有若干按钮的点击逻辑,每个按钮都有自己的 click 事件

        新需求来了:给每一个访问的用户添加了一个属性,如果 banned = true,此用户点击页面上的任何按钮或元素,都不可响应原来的函数。而是直接 alert 提示,你被封禁了。

        实现:采用 事件捕获 机制完成(当然实现的思路有三种,甚至更多,这里只说事件捕获)      

/**
    * 场景设计题
    一个历史页面,上面有若干按钮的点击逻辑,每个按钮都有自己的 click 事件
     新需求来了:给每一个访问的用户添加了一个属性,如果 banned = true,此用户点击页面上的任何按钮或元素,
    都不可响应原来的函数。而是直接 alert 提示,你被封禁了。
*/


window.addEventListener(
  "click",
  (e) => {
    if (banned) {
      e.stopPropagation();
    }
  },
  true
);

4.  你工作中用过防抖和节流吗?

    4.1 基本概念

        防抖:持续触发事件的时候,一定时间段内,没有再触发事件,时间处理函数才会执行一次

        节流:持续触发事件的时候,保证一段时间内只调用一次事件处理函数(固定时间)

    4.2 分别适合用在什么场景?

        防抖:input输入(巨量引擎)

        节流:resize(屏幕大小改变)、 scroll(滚动时)   ---> 一定要执行的,给一个固定间隔 

    4.3  手写节流函数

        时间戳写法,第一次立即执行

// 时间戳写法,第一次立即执行
const throttle = (fn, interval) => {
  let last = 0;
  return () => {
    let now = Date.now();
    if (now - last >= interval) {
      fn.apply(this, arguments);
    }
  };
};
const handle = () => {
  console.log(Math.random());
};
const throttleHandle = throttle(handle, 3000);
throttleHandle();
throttleHandle();

        定时器写法,第一次也需要延时 具体 时间以后再执行

// 定时器写法,第一次也会延时 具体的时间执行
const throttle = (fn, interval) => {
  let timer = null;
  return function () {
    let context = this;
    let args = arguments;
    if (!timer) {
      timer = setTimeout(() => {
        fn.apply(context, args);
        timer = null;
      }, interval);
    }
  };
};
const handle = () => {
  console.log(Math.random());
};
const throttleHandle = throttle(handle, 1000);
throttleHandle();
throttleHandle();

        精确的实现一个节流函数,无论是第一次之后还是最后一次(避免最后一次执行还会再等具体时间之后再执行)

// 精确的实现一个节流函数,无论是第一次之后还是最后一次(避免最后一次执行还会再等具体时间之后再执行)
const throttle = (fn, delay) => {
  let timer = null;
  let startTime = Date.now();
  return function () {
    let curTime = null;
    let remainning = delay - (curTime - startTime);
    let context = this;
    let args = arguments;
    clearTimeout(timer);
    if (remainning <= 0) {
      fn.apply(context, args);
      startTime = Date.now();
    } else {
      timer = setTimeout(fn, remainning);
    }
  };
};

        

5. 你了解 Promise 吗?平时用的多吗?

    5.1 Promise.all( ) 你知道有什么特性吗?

         解答Promise.all( ) 会接受一个 Promise 数组,数组里面可以是 Promise 也可以是一个常量或者其他;执行情况为:Promise 里面的所有 Promise 执行完成以后才会返回结果;

    5.2 如果其中一个 Promise 报错了怎么办?

        解答:如果有一个报错了,那么整个 Promise.all(  ),就会返回一个 catch

    5.3 如果有一个 Promise 报错了,那么其他的 Promise 还会执行吗?

        解答:会的,因为 Promise 是在创建之初(实例化) 的时候已经执行了

    5.4 手写一个 Promise.all(  )

        面试官:“给你 三个 如下的 Promise ,调用你的Promise.all( )以后,看是否会在三秒以内返回对应的结果”        

// 测试
const pro1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("1");
  }, 1000);
});
const pro2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("3");
  }, 2000);
});
const pro3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("3");
  }, 3000);
});

// 测试题
const PromiseAll = (promiseArray) => {};

     如何实现?

        考点1:Promise.all(  ) 里面的参数有可能不是一个 Promise,如何处理?

        考点2:Promise.all(  ) 返回值的顺序,是你传入的 Promise 顺序,如何处理?

// 测试题
const PromiseAll = (promiseArray) => {
  return new Promise((resolve, reject) => {
    if (!Array.isArray(promiseArray)) {
      return reject(new Error("Type can only be array"));
    }
    const result = []; // promise 执行的结果集
    const promiseNums = promiseArray.length; // 当前循环次数
    let counter = 0; // 记录当前 promise 执行顺序,需要按照 传入的 promise 顺序返回
    for (let i = 0; i < promiseNums; i++) {
      Promise.resolve(promiseArray[i])
        .then((value) => {
          counter++;
          result.push(value);
          if (counter === promiseNums) {
            resolve(result);
          }
        })
        .catch((e) => reject(e));
    }
  });
};

console.log(
  PromiseAll([pro1, pro2, pro3])
    .then((res) => {
      console.log(res);
    })
    .catch((e) => {
      console.log(e);
    })
);

    5.5 Promise 在初始化的时候已经执行了,那么利用这个特性我们可以做点什么(扩展性问题)?

         解答:可以利用 promise 的这个特性做缓存;

        利用 装饰器 + Map结构,实现一个 Promise 的缓存

const cacheMap = new Map();
const enableCache = (target, name, descriptor) => {
  const val = descriptor.value;
  descriptor.value = async (...args) => {
    const cacheKey = name + JSON.stringify(args);
    if (!cacheMap.get(cacheKey)) {
      const cacheValue = Promise.resolve(val.apply(this, args)).catch((_) => {
        cacheMap.set(cacheKey, null);
      });
      cacheMap.set(cacheKey, cacheValue);
    }
    return cacheMap.get(cacheKey);
  };
  return descriptor;
};
class PromiseClass {
  @enableCache
  static async getInfo() {}
}

PromiseClass.getInfo(); // 第一次发送请求
PromiseClass.getInfo(); // 第二次以后就是缓存
PromiseClass.getInfo();
PromiseClass.getInfo();

 6. 字节经典算法题---- 接雨水

题干:

        给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

        示例1:

        输入 height = [0,1,0,2,1,0,1,3,2,1,2,1]

        输出:6

        解释:上面是由数组  [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 单位的雨水(如上图,蓝色部分表示雨水)

        示例2:

        输入 height = [4,2,0,3,2,5]

        输出:9

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/405545.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2022最新Nodejs下载安装配置步骤(保姆级教程)

1. 进入官网选择下载版本 http://nodejs.cn/download/2.安装过程 步骤1&#xff1a;选择next选项 步骤2&#xff1a;勾选接受协议选项&#xff0c;点击 next&#xff08;下一步&#xff09;按钮 : 步骤3&#xff1a;其默认安装目录是C:\Program Files\nodejs\&#xff0c;当…

【Python】ttkbootstrap的介绍与使用

一、什么是ttkbootstrap&#xff1f; 官方文档 [较慢]&#xff1a;https://ttkbootstrap.readthedocs.io/en/latest/ ttkbootstrap 是一个基于 tkinter 的界面美化库&#xff0c;使用这个工具可以开发出类似前端 bootstrap 风格的 tkinter 桌面程序 二、安装步骤 安装命令…

Vue项目安装less和less-loader

第一步&#xff1a;查看webpack和webpack-cli是否安装 打开cmd&#xff0c;通过命令查看 webpack -vwebpack-cli -v如果没有安装&#xff0c;要先进行安装 可以通过 npm view webpack version / npm view webpack-cli version 查看当前webpack的最新版本 可以通过 npm vie…

什么是axios(写给小白的理解笔记)

0.为什么会诞生axios 最初浏览器页面向服务器请求数据时&#xff0c;返回的是整个页面&#xff0c;整个页面都会刷新&#xff0c;当我们只需要请求部分数据时&#xff0c;返回整个页面会造成网络资源的占用&#xff0c;为了提高数据请求效率&#xff0c;异步网络请求Ajax出现了…

羊了个羊网页版

最近羊了个羊火的不得了&#xff0c;利用周末时间实现一个网页版。步骤如下&#xff1a; 1&#xff0c;用reactjs 实现。 2&#xff0c;实现Gameroom类。 3&#xff0c;实现Card类。 4&#xff0c;通过父组件控制子组件通信方式&#xff0c;控制点击事件。 5&#xff0c;通过t…

nvm切换node版本

在实际的前端开发过程中&#xff0c;可能会经常遇见 node.js 的版本问题&#xff0c;不同的项目需要使用不同的 node.js 版本。比如Vue2和Vue3需要的Node版本不一样。 地址&#xff1a;https://github.com/coreybutler/nvm-windows/releases 注意&#xff1a;安装之前必须完…

ChatGPT初体验——震撼,好用,贾维斯已来

2022.12.26 大概一个月的使用体验&#xff0c;我觉得chagpt的使用还算远远超出我的想象&#xff0c;可以说只有你想不到的&#xff0c;最近需要写一个基于shell的学生选课系统&#xff0c;但是时间实在是紧张的很&#xff0c;一开始chatgpt是无法接受这么大的要求的&#xff0c…

js实现数组去重的方式(7种)

目录JS数组去重的方式1.利用Set()Array.from()2.利用两层循环数组的splice方法3.利用数组的indexOf方法4.利用数组的includes方法5.利用数组的filter()indexOf()6.利用Map()7.利用对象JS数组去重的方式 例&#xff1a;将下面数组去除重复元素&#xff08;以多种数据类型为例&a…

vue开发中,数据更新,但视图不刷新

我们在开发过程中会碰到数据更新&#xff0c;但是视图并未改变的情况&#xff0c;情况如下&#xff1a; 第一种:动态给对象新增属性或者删除属性是不会触发视图刷新的,Vue识别不到&#xff1b; 第二种:通过数组下标修改数组中的元素或者手动修改数组的长度,Vue识别不到&#…

【Javaweb学习笔记】在Eclipse中创建Web项目

【Javaweb学习笔记】在Eclipse中创建Web项目 哈喽大家好&#xff0c;这里是Java框架学习笔记专栏第二期 本期内容——在Eclipse中创建Web项目 前期回顾&#xff1a; 第一期——schema约束 笔者还是菜菜&#xff0c;还请大家多多指教呀&#xff01; 文章目录【Javaweb学习笔记】…

解决onebot提示当前QQ版本过低,请升级到最新版在登录!

文章目录前言方法一方法二1️⃣下载文件2️⃣本地运行3️⃣重新启动go-cqHttp4️⃣服务器下载go-cqhttp5️⃣配置gocqhttp6️⃣启动go-cqhttp结语前言 &#x1f947;个人主页&#xff1a;MIKE笔记 &#x1f948;文章专栏&#xff1a;技术教程 &#x1f4e3;TG交流群&#xff1a…

vue:聊天对话框的实现

实现效果&#xff1a;不知道怎么录屏 就用图片展示了&#xff0c;实现了聊天框的基础功能&#xff0c;也有一些细节考虑不完全。未输入消息时可发送图片或视频&#xff0c;输入消息后显示发送按钮&#xff0c;保持滚动条在位于底部的最新消息。 实现方式&#xff1a; 1.布局&a…

React中的setState使用细节和原理解析

文章目录setState使用详解使用setState的原因setState的基本用法setState的异步更新setState获取异步结果setState一定是异步?setState使用详解 前面我们有使用过setState的基本使用, 接下来我们对setState使用进行详细的介绍 使用setState的原因 开发中我们并不能直接通过修…

vue项目打断点的三种方式

方式一&#xff1a;使用debugger介绍&#xff1a;js自带的方法优点&#xff1a;简单好用&#xff0c;不需要额外的配置注意&#xff1a;生产环境下需要去掉方式二&#xff1a;使用vsCode插件断点介绍&#xff1a;vscode集成的断点调试&#xff0c;大佬必备优点&#xff1a;减少…

Nodejs安装及npm配置(超详细)

文章目录一、Node.js 下载二、Node.js 安装node.js简单安装三、Node.js 配置配置npm源关于npm源的更新四、可能遇到的问题1. 直接输入npm 或 npm 命令出错一、Node.js 下载 Node.js官网下载地址 Node.js中文下载地址 本文以 node.js 16.14.2 版本做演示&#xff0c;此版本要…

vue如何请求后端数据

在vue中&#xff0c;我们如何通过请求接口来访问后端的数据呢&#xff1f;在这里简单总结了一个小示例&#xff1a; 主要问题&#xff1a;如果不封装的话&#xff0c;在每次请求的时候都要书写一遍下面的代码&#xff0c;造成代码冗余。 1、在src目录下创建一个utils文件夹&am…

uniapp h5跳转微信小程序(wx-open-launch-weapp)

目录 一、注意事项 二、使用步骤 三、调整样式 一、注意事项 微信版本要求为&#xff1a;7.0.12及以上系统版本要求为&#xff1a;iOS 10.3及以上、Android 5.0及以上已认证的服务号&#xff0c;服务号绑定“JS接口安全域名”下的网页可使用此标签跳转任意合法合规的小程序。…

vue项目网页自适应,等比例放大缩小

同样是&#xff0c;虽然标题写的vue项目适用&#xff0c;但其它前端框架应该也可以。其它框架我没什么经验&#xff0c;可以参考着看看&#xff0c;应该适用。 本文章不涉及第三方插件&#xff0c;纯js。 自适应这个问题&#xff0c;老早以前就有一个解决方式&#xff0c;css中…

前端实现vue3使用axios调用后端接口

前言&#xff1a;在探索vue3.0的道路上调接口这件事很重要&#xff0c;所以我就把我探索出来的这条道展示出来&#xff0c;为大家提供便利&#xff0c;望喜欢&#xff0c;废话不多说展示&#xff01;&#xff01;&#xff01; 第一步&#xff1a;在src下创建一个http文件夹&am…

vue-devtools的安装与使用

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录前言一、vue-devtools是什么&#xff1f;二、vue-devtools安装1.下载vue-devtools工具2.安装vue-devtools工具三、vue-devtools的使用总结前言 主要介绍vue-devtool…