居然之家二,详细面试题解析
- 深浅拷贝有哪些方法
- 深浅拷贝有哪些方法
- JSON.parse(JSON.stringify(object)) 有什么缺点
- 前端浏览器的存储方式有哪些
- 防抖节流,应用场景,手写一个防抖节流
- Promise是干什么的?Promise.all()接受三个promise,如果第二个失败了还会执行第三个吗?
- async/await 怎么捕获异常
- React,哪一个版本有hooks,怎么进行数据通信
- React生命周期
- webpack,它的插件loader,plugin,拆包
- 事件循环
- 代码执行顺序, 那些是宏任务和微任务,区别?
- new()方法会执行什么?
- 单点登录?怎么判断是否登录?
- 微前端,低代码有了解吗?
- 平时怎么学习前端的
- 最近在看那些技术?
- attribute 和 property 的区别
- webpack构建流程
深浅拷贝有哪些方法
- 浅拷贝:Object.assign()、...扩展运算符、数组的slice()和concat()
- 深拷贝:JSON.parse(JSON.stringify())、手动编写递归函数复制对象、使用第三方库如Lodash的_.cloneDeep()方法。
JSON.parse(JSON.stringify(object)) 有什么缺点
使用 JSON.parse(JSON.stringify()) 深拷贝时需要注意不能拷贝循环引用属性和函数属性。
- 该方式无法拷贝对象的函数属性和基于原型继承的属性;
- 该方式无法处理循环引用的情况,即当一个对象内部出现循环引用时,该方式会报错或拷贝出一个不完整的对象;
- 该方式也无法处理特殊的对象类型,如 Date、RegExp 等。
手写一个深浅拷贝
浅拷贝:只是将数据中所有的数据引用下来,依旧指向同一个存放地址,拷贝之后的数据修改之后,也会影响到原数据的中的对象数据
function shallowCopy(obj){
var data = {};
for (var i in obj){
if(obj.hasOwnProperty(i)){ // for in 循环,也会循环原型链上的属性,所以这里需要判断一下
//hasOwnProperty的相关知识点,查看下面的:相关知识点补充
data[i] = obj[i]
}
}
return data
}
深拷贝:将数据中所有的数据拷贝下来,对拷贝之后的数据进行修改不会影响到原数据
function deepCopy(obj) {
if (typeof obj !== 'object' || obj === null) {
return obj; // 非对象类型直接返回
}
let copy = Array.isArray(obj) ? [] : {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
copy[key] = deepCopy(obj[key]); // 递归拷贝对象的每个属性值
}
}
return copy;
}
前端浏览器的存储方式有哪些
- Cookies:一种小型文本文件,用于从网站发送到用户设备上。浏览器会自动在后续请求中包含这些数据。Cookies一般被用来记录用户的登录状态、购物车信息等。
- localStorage:可以将数据永久性保存在客户端,即便关闭浏览器或重新启动电脑,数据也不会被清除。localStorage 数据存储容量较大,一般为 5MB 或以上,可以保存大量数据
- sessionStorage:sessionStorage 只能保存在当前会话中,当用户关闭当前窗口或标签页时,数据将会被清除。同时,不同的窗口和标签页之间也无法共享 sessionStorage。
- IndexedDB:IndexedDB 是一款本地数据库,类似于前端版的 SQL 数据库。它支持更复杂的数据类型和更强的查询功能,适合存储大数据量的结构化数据。
防抖节流,应用场景,手写一个防抖节流
防抖:n 秒后再执行回调,若在 n 秒内被重复触发,则重新计时;防抖的基本思想是在函数被连续调用时,只执行最后一次调用,并在指定的时间间隔内没有新的调用才执行函数。如果在时间间隔内有新的调用,则重新计时。
- 输入框搜索:当用户在输入框中连续输入字符时,使用防抖可以避免每次输入都触发搜索请求,而是在用户停止输入一段时间后才触发搜索请求,减少不必要的请求。
- 窗口调整:当窗口大小调整时,使用防抖可以确保调整完成后才执行相应的操作,避免频繁触发操作。
- 按钮点击:当用户频繁点击按钮时,使用防抖可以确保只有最后一次点击有效,避免误操作或重复操作。
function debounce(func, delay) {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => {
func.apply(this, args);
}, delay);
};
}
节流: n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效;节流的基本思想是限制函数在一定时间间隔内的执行次数,例如每隔一段时间执行一次,并在该时间间隔内忽略其他的函数调用。
- 页面滚动:当用户滚动页面时,使用节流可以控制触发事件的频率,减少滚动事件的处理次数,提高页面的流畅度。
- 鼠标移动:当用户在页面上移动鼠标时,使用节流可以限制触发事件的频率,避免触发过多的事件处理逻辑。
function throttle(func, delay) {
let timer;
return function (...args) {
if (!timer) {
timer = setTimeout(() => {
func.apply(this, args);
timer = null;
}, delay);
}
};
}
Promise是干什么的?Promise.all()接受三个promise,如果第二个失败了还会执行第三个吗?
Promise是异步编程的一种解决方案,可以解决传统的回调地狱问题,使得异步代码更加扁平化、可读性更高,避免了多层嵌套的回调函数。
如果第二个Promise执行失败,Promise.all()返回的Promise会立即失败,并把第二个Promise的拒绝原因作为参数传递给失败的回调函数,同时第三个Promise不会被执行。
async/await 怎么捕获异常
在 async 函数内部,可以使用 try 关键字来包裹可能抛出异常的代码块。在 await 表达式之后,如果异步操作抛出异常,它将被捕获并传递给 catch 块,然后执行相应的错误处理逻辑。在 catch 块中,可以访问到抛出的异常对象,并进行相应的处理,例如打印错误信息或执行其他错误处理操作。
注意,使用 try/catch 只能捕获到 await 表达式所在的异步函数内部抛出的异常。如果在异步函数之外发生异常,或者在异步函数内部的同步代码中发生异常,try/catch 是无法捕获到的。在这种情况下,可以使用 .catch() 方法来捕获异常,或者在调用异步函数的地方使用 try/catch 来处理异常。
React,哪一个版本有hooks,怎么进行数据通信
React Hooks 是从 React 16.8 版本引入的。在此版本之前,React 的组件主要是基于类的,使用类组件来管理状态和生命周期方法
使用 Hooks 进行数据通信有多种方式,以下是一些常见的方法:
-
Props:父组件通过 Props 将数据传递给子组件。子组件可以通过 props 对象获取传递过来的数据,并在组件内部使用。
-
Context:Context 提供了一种在组件之间共享数据的方法,避免了通过 Props 层层传递数据。通过创建一个 Context 对象,在父组件中将需要共享的数据包裹在 Provider 组件中,子组件可以通过 useContext Hook 或 Consumer 组件来获取共享数据。
-
useState Hook:useState Hook 可以在函数组件中声明和管理状态。通过调用 useState 返回的状态和更新函数,组件可以在函数组件中维护自己的状态数据。
-
useReducer Hook:useReducer Hook 是另一种用于状态管理的 Hook。它接受一个 reducer 函数和初始状态作为参数,并返回当前状态和 dispatch 函数。通过 dispatch 函数可以触发 reducer 来更新状态。
-
Redux 或其他状态管理库:如果需要更复杂的状态管理和数据通信方案,可以使用像 Redux 这样的状态管理库。Redux 提供了统一的状态管理和数据流控制机制,使得组件之间的数据通信更加可预测和可维护。
React生命周期
组件从 被创建 到 被销毁 的过程称为组件的生命周期。
组件的生命周期可分成三个状态:
- Mounting(挂载时)
- Updating(更新时)
- Unmounting(卸载时)
组件的生命周期可分为三个阶段:
- Render: 用于计算当前的状态/更新信息,会根据产生的任务的优先级,安排任务的调度(schedule)
- Pre-commit: commit 之前,可以获取当前 DOM 的快照(snap)
- Commit: 把所有更新都 commit 到 DOM 树上
webpack,它的插件loader,plugin,拆包
Webpack是一个现代化的静态模块打包工具,它主要用于构建和打包前端项目
- Loader是Webpack的核心概念之一,它用于处理非JavaScript文件。Webpack通过Loader可以将不同类型的文件(例如CSS、图片、字体等)转换为模块,并将其添加到依赖图中。常见的Loader有:
1. babel-loader:将ES6+的JavaScript代码转换为可以在旧版本浏览器中运行的JavaScript代码。
2. css-loader:处理CSS文件,使其能够被Webpack打包。
3. file-loader:处理文件,例如图片和字体文件,将其复制到输出目录,并返回文件路径。
4. style-loader:将CSS代码注入到页面的<style>标签中。
Loader可以通过在Webpack配置文件中的module.rules中进行配置。每个规则对象都包含了一个test属性,用于匹配需要处理的文件类型,以及一个use属性,用于指定使用的Loader。
- Plugin是Webpack的另一个重要概念,它可以用于执行更广泛的任务,例如打包优化、资源管理、环境变量注入等。Plugin通过在Webpack构建过程的不同阶段注入钩子函数来实现其功能。常见的Plugin有:
1. HtmlWebpackPlugin:生成HTML文件,并将Webpack打包后的文件自动引入到HTML中。
2. MiniCssExtractPlugin:将CSS提取为单独的文件,而不是注入到页面的<style>标签中。
3. OptimizeCSSAssetsPlugin:优化CSS输出,例如压缩和去重。
4. CleanWebpackPlugin:在每次构建之前清理输出目录。
- 拆包是一种优化技术,用于将大型的代码包拆分为更小的块。这样可以实现按需加载,减少初始加载的文件大小,提高网页的加载速度。Webpack提供了多种拆包的方式,例如:
1. 入口点拆包:将应用程序的不同部分拆分成多个入口点,每个入口点对应一个输出文件。
2. 动态导入:使用ES6的import()语法实现按需加载。
3. SplitChunks Plugin:通过配置optimization.splitChunks选项,
将公共模块拆分到单独的文件中。
事件循环
事件循环(Event Loop)是 JavaScript 运行时环境(如浏览器或 Node.js)用来处理异步操作的机制。它负责管理 JavaScript 代码的执行顺序,使得异步操作能够以非阻塞的方式进行。
事件循环的主要思想是将任务分为不同的队列,然后按照特定的规则来执行这些队列中的任务。在浏览器环境中,事件循环由浏览器的主线程控制,而在 Node.js 环境中,则由 Node.js 的事件驱动模型管理。
下面是事件循环的基本步骤:
-
执行同步任务:从调用栈(执行上下文栈)中取出位于栈顶的同步任务执行。
-
执行微任务(Microtask)队列:在执行同步任务过程中,如果遇到微任务(如 Promise 的回调函数、queueMicrotask 方法等),则将其添加到微任务队列中。
-
执行宏任务(Macrotask)队列:当同步任务和微任务队列都为空时,事件循环会从宏任务队列中取出一个任务执行。常见的宏任务包括 setTimeout、setInterval、requestAnimationFrame、I/O 操作等。
-
更新渲染:在浏览器环境中,如果当前任务完成后需要更新页面的渲染,会执行渲染操作。
-
重复上述步骤:事件循环会不断重复执行上述步骤,直到所有任务都被处理完毕。
代码执行顺序, 那些是宏任务和微任务,区别?
- 执行完当前宏任务中的同步代码。
- 执行当前宏任务产生的微任务队列中的所有微任务。微任务队列为空才会进入下一步。
- 执行下一个宏任务。 微任务的执行优先级高于宏任务。也就是说,在一个宏任务执行完毕后,会先执行微任务队列中的所有微任务,然后再执行下一个宏任务。
- 宏任务(Macrotask):setTimeout、setInterval、setImmediate(仅在 Node.js 中)、I/O 操作、渲染事件(在浏览器中)、UI 交互事件(在浏览器中)等
- 微任务(Microtask):Promise 的回调、async/await、queueMicrotask 方法等。
new()方法会执行什么?
- 创建一个空对象
- 将空对象的原型指向构造函数的原型
- 将构造函数的 this 指向新创建的对象
- 返回新创建的对象:如果构造函数没有显式返回一个对象,则默认返回新创建的对象。如果构造函数返回的是一个非对象值(如基本类型),则返回新创建的对象实例。
单点登录?怎么判断是否登录?
单点登录(Single Sign-On,简称 SSO)是一种身份验证和授权机制,允许用户使用一组凭据(如用户名和密码)来访问多个相关系统或应用,而不需要在每个系统中重新进行身份验证。
在单点登录流程中,用户只需要登录一次,然后就可以访问与该身份验证机制集成的多个应用或系统,而无需在每个应用中单独进行登录。这提供了更方便的用户体验,并减少了用户需要记住多个账号和密码的负担。
要判断用户是否登录,可以使用以下方法:
- 会话管理:在用户登录成功后,服务器可以创建一个会话,并为该会话分配一个唯一的会话标识(如 Session ID)。服务器将会话标识存储在用户的浏览器 Cookie 或其他存储机制中,并在用户发送请求时进行验证。如果会话有效,则可以判断用户已登录。
- 令牌验证:在某些情况下,单点登录系统会生成一个令牌(Token),并将其发送给用户。用户在每个请求中都需要携带该令牌。服务器接收到请求后会验证令牌的有效性,如果有效,则判断用户已登录。
- 单点登录协议:单点登录通常使用一些标准化的协议,如 OAuth、OpenID Connect 等。这些协议定义了身份验证和授权的流程,并提供了一种机制来验证用户的登录状态。
微前端,低代码有了解吗?
微前端(Micro Frontends)是一种架构风格,旨在将前端应用程序拆分为更小、更可管理的部分,每个部分都是独立的子应用。这些子应用可以独立开发、部署和扩展,并可以通过统一的容器应用程序来组合在一起。微前端的目标是提高前端开发的灵活性、可维护性和可扩展性,同时支持团队间的独立开发和快速交付。
微前端的主要概念包括:
- 拆分:将前端应用拆分为更小的功能单元,每个单元被开发和维护为独立的子应用。
- 集成:通过容器应用程序将多个子应用集成在一起,容器应用程序提供导航、路由和通信等功能。
- 独立开发和部署:每个子应用都可以独立开发、测试和部署,不受其他子应用的影响。
- 通信和状态管理:子应用之间可以通过事件总线、共享状态或其他通信机制进行交互和共享数据。
低代码(Low-Code)是一种应用开发方法,旨在通过使用可视化界面、拖放组件和少量的手写代码来加速应用程序的开发过程。低代码平台提供了一系列可配置的组件和预定义的业务逻辑,开发人员可以通过配置和定制来创建应用程序,而不是从头开始编写所有代码。
低代码的主要特点包括:
- 可视化开发:通过可视化界面进行开发,无需编写大量的代码。
- 组件驱动:低代码平台提供了一系列可复用的组件,开发人员可以通过拖放组件来快速搭建界面和业务逻辑。
- 快速迭代:低代码平台提供了快速迭代和快速发布的能力,使得应用程序的开发和更新变得更加敏捷和高效。
- 可扩展性:低代码平台通常提供了扩展机制,开发人员可以自定义组件或添加自定义代码来满足特定需求。
平时怎么学习前端的
- 自主学习:强调你的主动性和自学能力,说明你经常主动寻找学习资源,如在线教程、文档、博客文章、视频教程等,并且能够理解和应用所学知识。
- 实践项目:强调你通过实践项目来巩固所学的知识。你可以提到你参与过的个人项目、练习项目、开源项目等,说明你能够将所学的理论知识应用到实际项目中,并通过项目中遇到的问题来学习和成长。
- 社区参与:强调你参与技术社区的活动,如参与讨论、提问、回答问题、分享经验等。你可以提到你在技术论坛、开发者社区、GitHub等平台上积极参与,与其他开发者交流和学习,从他们的经验中获得启发和指导。
- 持续学习:强调你的学习态度和持续学习的能力。你可以提到你关注前端领域的最新动态和发展趋势,如阅读相关技术博客、订阅新闻通讯、关注前端社交媒体账号等,以保持对新技术和工具的了解
webpack 构建流程
webpack 的运行流程是一个串行的过程,它的工作流程就是将各个插件串联起来
从启动到结束会依次执行以下三大步骤:
- 初始化流程:从配置文件和 Shell 语句中读取与合并参数,并初始化需要使用的插件和配置插件等执行环境所需要的参数
- 编译构建流程:从 Entry 发出,针对每个 Module 串行调用对应的 Loader 去翻译文件内容,再找到该 Module 依赖的 Module,递归地进行编译处理
- 输出流程:对编译后的 Module 组合成 Chunk,把 Chunk 转换成文件,输出到文件系统
根据真实面试经历盘点面试题目,总结面试经验,分类总结面试题目答案