再战-美图前端面试
- css定位方式有哪些?
- 相对定位和绝对定位的区别?绝对定位的父元素没有定位会怎么办?
- 进程与线程的关系
- 一个进程有几个堆几个栈?一个线程呢?
- Vue实现响应式的原理
- Vue的依赖追踪
- Vue中for循环一百次改data里的某个值,最终真实生效的修改有几次?
- Vue的$nextTick是干什么用的?以及原理?
- 虚拟dom是用来干什么的?
- 了解diff算法吗?有什么特点?
- 闭包是什么?有哪些方式能产生闭包?闭包都会用在真实业务中的哪些场景
- Node有哪些内置模块?你用过哪些?
- Node有哪些框架?Express写一个中间件的基本语法有哪些API?
- 宏任务和微任务有哪些?
- 处理过哪些前端安全的工作?
- 在工作中用过什么算法?用过什么设计模式?
css定位方式有哪些?
- 静态定位(Static Positioning):默认的定位方式,元素按照正常的文档流排列,不受定位属性的影响。
- 相对定位(Relative Positioning):通过设置 position: relative; 来实现。元素相对于自身原来的位置进行偏移,但仍然占据原来的空间,周围的元素不会调整位置。
- 绝对定位(Absolute Positioning):通过设置 position: absolute; 来实现。元素相对于父元素或最近的已定位祖先元素进行定位,不占据文档流中的空间,会导致周围的元素重新布局。 4.固定定位(Fixed Positioning):通过设置 position: fixed; 来实现。元素相对于浏览器窗口进行定位,不随滚动而移动,始终保持在固定位置。
- 粘性定位(Sticky Positioning):通过设置 position: sticky; 来实现。元素根据正常文档流进行定位,直到滚动到指定阈值时,变为固定定位。
相对定位和绝对定位的区别?绝对定位的父元素没有定位会怎么办?
- 相对定位(Relative Positioning):元素相对于自身原来的位置进行偏移,但仍然占据原来的空间,周围的元素不会调整位置。相对定位使用 position: relative; 来设置。
- 绝对定位(Absolute Positioning):元素相对于父元素或最近的已定位祖先元素进行定位,不占据文档流中的空间,会导致周围的元素重新布局。绝对定位使用 position: absolute; 来设置。
如果绝对定位的父元素没有定位的话,绝对定位的元素会相对于最近的具有定位属性的祖先元素进行定位。如果没有祖先元素有定位属性,则相对于浏览器窗口进行定位。
进程与线程的关系
- 进程是资源分配的基本单位
- 线程是执行的基本单位:线程是进程中的一个执行单元,一个进程可以包含多个线程。线程共享进程的资源,包括内存空间、文件描述符等,它们可以同时并行执行不同的任务。
知道内存里的堆和栈吗?
堆是用于存储动态分配的内存的一块区域。
栈是用于存储函数调用和局部变量的一块区域。
一个进程有几个堆几个栈?一个线程呢?
- 一个进程通常有一个堆和一个栈。进程的堆用于存储动态分配的内存,进程的栈用于存储函数调用和局部变量。
- 一个线程通常也有一个堆和一个栈。每个线程拥有自己的栈,用于存储函数调用和局部变量,但所有线程共享同一个进程堆。这意味着多个线程可以共享相同的全局数据和动态分配的内存,但它们各自拥有自己的函数调用栈。
Vue实现响应式的原理
当 Vue 实例化时,会对数据对象进行递归遍历,使用 Object.defineProperty
将属性转化为 getter/setter
,并且在内部收集依赖,建立每个属性和 Watcher(观察者)
之间的联系。这样当属性被访问或修改时,就会触发相应的 getter 或 setter 方法,在这些方法中完成一些响应式的操作。
在数据变化时,setter 方法
会通知之前收集到的 Watcher 进行更新操作。这些 Watcher 在属性与视图之间起着桥梁的作用。当模板中使用了数据对象中的属性时,这些属性与 Watcher 建立了绑定关系,Watcher 将模板的渲染函数添加到对应属性的订阅列表中,从而实现当属性值变化时,自动更新模板信息的效果。
Vue 实现响应式的原理是将数据和视图相连,通过数据劫持、观察者模式和发布-订阅模式,建立数据与 Watcher 之间的联系,在数据发生变化时,自动更新对应的视图。这种实现方式使得 Vue 具有高效、灵活、可维护的特点
Vue的依赖追踪
Vue 使用依赖追踪来探测数据的变化,并自动更新相关的 DOM。当数据发生变化时,Vue 能够精确地知道哪些组件或者模板中的表达式需要重新求值,并进行相应的更新。
Vue 的依赖追踪通过使用 JavaScript 的 Object.defineProperty 方法来实现。当访问一个响应式对象的属性时,Vue 会收集当前组件的依赖,并将其保存在一个被称为“依赖收集器”的地方。当该属性发生变化时,Vue 可以根据之前收集的依赖,找到所有依赖该属性的组件或者模板,并触发它们的更新。
Vue中for循环一百次改data里的某个值,最终真实生效的修改有几次?
在 Vue 中,数据的更新是异步的,并且在同一个事件循环中,对于同一个数据的多次更新只会产生一次实际的DOM更新。这是为了性能优化的目的。
因此,如果使用 for 循环一百次来修改某个值,最终只会产生一次实际的DOM更新。
果你希望每次更新都立即反映到 DOM 上,可以使用 $nextTick
方法,将更新代码包裹在 $nextTick
回调函数中。
Vue的$nextTick是干什么用的?以及原理?
在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM
原理上,当我们修改 Vue 实例的数据时,Vue 会将这些数据的变化记录下来,然后在下一个事件循环中进行统一的 DOM 更新。而 $nextTick 就是利用了这个机制,将回调函数延迟到下一个 DOM 更新周期执行。
具体来说,当你调用了 $nextTick(callback) 方法时,Vue 会将这个回调函数放入一个队列中,并且等待当前的同步代码执行完成。当主线程空闲时(即下一个事件循环开始),Vue 会遍历这个队列,并依次执行队列中的回调函数。在执行回调函数之前,Vue 会先进行一次 DOM 更新,确保界面上的数据已经同步更新。
虚拟dom是用来干什么的?
它是用 JavaScript 对象来描述真实的 DOM 元素树,通过对比新旧虚拟 DOM 的差异,最终只对需要更新的部分进行真实 DOM 的更新操作,从而提高渲染效率。
了解diff算法吗?有什么特点?
diff 算法是一种通过同层的树节点进行比较的高效算法
特点是:深度优先,同层比较
-
只在同层级进行比较, 不会跨层级比较
-
在diff比较的过程中,循环从两边向中间比较
-
当数据发生改变时,订阅者watcher就会调用patch给真实的DOM打补丁
-
通过isSameVnode进行判断,相同则调用patchVnode方法
-
patchVnode做了以下操作:
- 找到对应的真实dom,称为el 如果都有都有文本节点且不相等,将el文本节点设置为Vnode的文本节点
- 如果oldVnode有子节点而VNode没有,则删除el子节点
- 如果oldVnode没有子节点而VNode有,则将VNode的子节点真实化后添加到el
- 如果两者都有子节点,则执行updateChildren函数比较子节点
-
updateChildren主要做了以下操作:
- 设置新旧VNode的头尾指针
- 新旧头尾指针进行比较,循环向中间靠拢,根据情况调用patchVnode进行patch重复流程、调用createElem创建一个新节点,从哈希表寻找 key一致的VNode 节点再分情况操作
闭包是什么?有哪些方式能产生闭包?闭包都会用在真实业务中的哪些场景
闭包是有权限访问其他函数作用域的局部变量的一个函数
创建闭包的几种方式:
- 在一个函数内部定义另一个函数,并将内部函数作为返回值返回。
- 将函数作为参数传递给其他函数,并在其他函数内部调用。
- 将函数赋值给对象的属性,并且该函数引用了对象的其他属性或方法。
- 通过立即执行函数表达式 (IIFE) 创建闭包。
闭包在真实业务中可以应用于以下场景:
- 防抖节流函数
- 封装私有变量和方法:闭包可以使得一些变量和方法仅在特定的函数作用域内访问,而不会被外部所修改或访问,从而实现了封装的效果。
- 模块化开发:通过使用闭包,可以创建独立的模块,并隐藏模块内部的实现细节,只暴露需要对外提供的接口,从而实现模块化开发和避免命名冲突。
- 保存状态:由于闭包可以访问其外部函数的变量和参数,因此可以通过闭包保存一些状态,使得这些状态在函数执行完毕后仍然存在。
- 实现高阶函数:在函数式编程中,闭包经常用于实现高阶函数,例如函数柯里化、函数组合等。
如果滥用闭包,可能会导致内存泄漏问题,因为闭包会一直保持对其引用环境的引用。因此,在使用闭包时需要注意及时释放不再使用的闭包。
Node有哪些内置模块?你用过哪些?
- fs 模块(文件系统模块):用于对文件系统的操作,包括读取文件、写入文件、修改文件权限等。
- http 模块:用于创建 HTTP 服务器和客户端,可以实现基于 HTTP 协议的网络通信。
- path 模块:提供处理文件路径的工具,包括获取文件名、扩展名,拼接路径等。
- util 模块:提供一些常用的工具函数,包括继承、事件监听等。
- stream 模块:用于处理流数据,可以将数据流分成多个块进行处理,提高性能和内存效率。
- url 模块:提供 URL 的处理和解析功能,包括解析 URL、拼接 URL 等。
- querystring 模块:用于解析和格式化 URL 中的查询字符串。
- events 模块:用于实现事件的发布与订阅机制,可以创建和触发事件。
Node有哪些框架?Express写一个中间件的基本语法有哪些API?
Express.js、Koa.js、Egg.js、Next.js
以下是一些常用的 API:
- app.use(path, middleware):向 Express 应用程序添加中间件函数,其中 path 参数是可选的,用于指定中间件函数的路径。
- app.get(path, callback):处理 HTTP GET 请求的路由,其中 path 参数是匹配的 URL,callback 参数是在匹配到 URL 时进行的回调函数。
- app.post(path, callback):处理 HTTP POST 请求的路由,与 app.get() 方法类似。
- app.listen(port, [hostname], callback):启动 Express 应用程序并监听指定的端口和主机名,其中 callback 是可选的,用于在应用程序启动时执行一些操作。
- req.params:包含路由参数的对象,例如 /users/:id 的 id 参数可以通过 req.params.id 来获取。
- req.query:包含查询字符串参数的对象,例如 URL 中的 ?name=John&age=30 可以通过 req.query.name 和 req.query.age 来获取。
- res.send(body):将响应内容发送给客户端,其中 body 参数可以是字符串、Buffer、数组或者对象。。
- next([err]):将控制权交给下一个中间件或路由处理函数,如果传递了 err 参数,则代表出现了错误,Express 将跳过后续中间件并返回错误。
宏任务和微任务有哪些?
常见的宏任务有:
- setTimeout、setInterval 等计时器任务;
- DOM 事件(例如 click、load 等事件);
- I/O 任务(例如读取文件和写入文件);
- 请求动画帧(requestAnimationFrame)。
常见的微任务有:
- Promise 中的 then()、catch()、finally();
- MutationObserver 监听器;
- process.nextTick (Node.js 环境中)。
处理过哪些前端安全的工作?
- 输入验证:对用户输入进行验证和过滤,避免 XSS 和 SQL 注入等安全漏洞。
- 密码加密:使用密码加密技术,避免明文存储或传输用户密码。
- HTTPS 通信:使用 HTTPS 协议保证数据传输的安全性。
- 防范 CSRF 攻击:在请求中添加 token 等随机参数,避免被攻击者利用 CSRF 攻击进行恶意操作。
在工作中用过什么算法?用过什么设计模式?
算法:
- 排序算法:例如冒泡排序、快速排序、归并排序等。用于对数据进行排序。
- 搜索算法:例如二分查找算法,用于在有序数组中快速查找目标值。
- 哈希算法:例如 MD5、SHA 等,用于对数据进行哈希加密。
- 图算法:例如深度优先搜索(DFS)、广度优先搜索(BFS)等,用于处理图相关的问题,如寻找最短路径等。
设计模式:
- 观察者模式:用于实现发布-订阅模式,在组件之间建立松耦合的通信机制。
- 单例模式:用于确保一个类只有一个实例,并提供全局访问点。
- 工厂模式:用于创建对象的接口,将对象的实例化延迟到子类。
- 装饰者模式:用于动态地给对象添加额外的职责,不改变其原有结构。
- 策略模式:用于定义一系列算法,使得它们可以互相替换,使得算法的变化独立于使用算法的客户。
根据真实面试经历盘点面试题目,总结面试经验,分类总结面试题目答案