前言
面试其实也是工作经验的总结,在工作之余,将工作中的问题记录总结,也是为下一份工作面试打好基础。
常规面试问题
1、项目中的跨域如何处理的。
跨域是一个比较大的话题,问题本身在开发过程中比较常见的问题,
对跨域的理解和解决方法可以点击这里
2、防抖与节流,什么场景用。
防抖:防止抖动、阻止用户行为多次触发请求。即是高频触发的事件,一定时间内、只有最后一次被触发生效。
使用场景:
- 监听页面数据变化重置页面布局,如:调整浏览器大小。
- 登录、发送短信、支付等避免用户点击太快导致多次触发请求。
- 表单、文档实现自动保存,监听在没任何操作后多长时间进行自动保存。
代码实现封装防抖:
function dobunce (fn, waitTime){
let timer = null;
return (...arg) => {
if(timer) clearTimeout(timer)
timer = setTimerout(()=>{
fn(...arg)
},waitTime)
}
}
节流:节约流量、控制事件的发生频率,即是高频触发的事件、一定时间内只触发一次。
使用场景:
- 输入框实时输入搜索展示下拉框。
- 监听滚动条到指定位置触发加载更多。
- 每隔多长时间记录鼠标位置,
代码实现:
function throttle(fn,waitTime){
let timer = null;
return (...args)=>{
if(timer) return
timer = setTimeout(()=>{
fn(...args)
timer=null
}, waitTime)
}
}
3、HTTP协议 的理解。
4、懒加载如何判断元素出现在视口内?
判断元素是否在视口内:需要了解浏览器判断一个元素位置的方法。首先我们需要了解怎么判断浏览器的宽、高。
//兼容所有浏览,获取浏览器的宽高的方法;
const w=window.innerWidth
|| document.documentElement.clientWidth
|| document.body.clientWidth;
const h=window.innerHeight
|| document.documentElement.clientHeight
|| document.body.clientHeight;
//window 常用的方法
window.close() //关闭浏览器窗口
window.open() // 开启浏览器窗口
window.resizeTo() // 调整浏览器窗口
window.moveTo() //移动浏览器
同时我们还需要了解元素属性;
getBoundingClientRect();
Element.getBoundingClientRect() 方法返回一个 DOMRect 对象,其提供了元素的大小及其相对于视口的位置。拥有left, top, right, bottom, x, y, width, height属性。
使用 getBoundingClientRect 方法 判断元素是否在视口内部、公式为:
el.getBoundingClientRect().top < viewHight(视口高度)
代码实现:
const elIsInViewPort = (el) => {
const viewHight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
const elToViewHeight = el.getBoundingClientRect()?.top;
return elToViewHeight <= viewHight + 100 //+100 目的是为了提前加载数据
}
IntersectionObserver 接口;
IntersectionObserver 接口(从属于 Intersection Observer API)提供了一种异步观察目标元素与其祖先元素
顶级文档视口(viewport)交叉状态的方法。其祖先元素或视口被称为根(root)
了解更多 IntersectionObserver API 移步到这里
使用 IntersectionObserver 判断元素是否在视口内 代码实现方法
//
const intersectionObserver = new IntersectionObserver((entries)=>{
// 如果 intersectionRatio 为 0,则目标在视野外,
if(entries.length < 1) return
entries.forEatch((target)=>{
if(target.isIntersecting){
//停止对元素的观察
intersectionObserver.unobserve(target)
}
})
})
const elArr = [...document.querySelectorArr('.selectEle')]
elArr.forEatch((item)=>{
intersectionObserver.observe(item) //对元素进行监听;
})
5、ES6中let、const与ES5 var的区别。
let ,const, var 都是js 中使用来申明变量的方法。
var 声明的变量 为全局变量,及是 window 下的变量,存在变量提升问题。
let、 const 为es6 新提出的申明变量的方法,申明的变量为块级作用域、
const 声明 的变量为常量、必须初始化值、不能修改变量值、否则会报错。
let 申明的块级作用域变量,可以修改变量值。
let const 声明的变量都不能重复声明,重复声明会报错。var 声明重复变量不报错会覆盖前面变量的值。
6、Promise的理解。
promise js 使用来异步执行代码的方法,由于js 执行代码为同步的,一次只执行一次任务,阻塞其他任务。
7、JavaScript有哪些数据类型?如何判断这些类型。
js中数据类型:
类型 | typeOf 返回值 |
---|---|
Null | “Object” |
Undefined | “Object” |
Boolean | “boolean” |
Number | “number” |
BigInt | “bigint” |
String | “string” |
Symbol | “symbol” |
判断数据类型方法
方法一:typeOf
能够精确的返回数据的基本数据类型,但是不能明确判断出, Null、 Underfined 对象值,
方法二: instanceOf
可以拿根据 instanceOf 判断对象是继承哪一个原始类型,判断方法为根据js原型链特性,逐级向上找到根节点
代码实现instanceOf
const myInstanceOf = (obj,type) =>{
if(typeOf obj !== 'object' || obj == null) return false
let proto = Object.getProtoTypeOf(obj)
while(true){
if(proto === null) return false
else if(proto === type.protoType){
return true
}else {
proto = Object.getProtoTypeOf(proto)
}
}
}
//使用方法
const s = 'abc'
myInstanceOf(s, 'string') // true
方法三: Object.protoType.toString.call(obj)
toString 方法为对象原型上的方法,直接调用toString 方法 返回 “[object: ‘Xxxxx’]” , ‘Xxxxx’ 就为对象的类型,object 调用toString 方法 直接返回 “[object: ‘object’]” 字符串, 其他类型的值调用需要使用call() 调用才能返回正确的值。
Object.protoType.toString({
}) // "[object Object]"
Object.protoType.toString.call('str') //"[object String]"
Object.protoType.toString.call(124) // "[object Number]"
其他也可以使用 数据类型的转换
如: Boolean() 类型转换 Number() 类型转换
8、Axios与Ajax的区别。
Axios和Ajax是两种不同的技术,用于实现前后端数据交互。
-
Axios是一个基于Promise的HTTP客户端,可以用于浏览器和Node.js环境。它支持跨域请求、拦截请求和响应、取消请求等功能。Axios可以通过简单的API发送HTTP请求,并且可以处理响应结果。它是一个相对较新的技术,逐渐取代了旧的Ajax技术。
-
Ajax(Asynchronous JavaScript and XML)是一种用于创建异步请求的技术。它可以使网页在不重新加载的情况下更新部分内容,提升用户体验。Ajax可以使用XMLHttpRequest对象来发送HTTP请求,并通过回调函数处理响应结果。
所以,主要区别如下:
- Axios是一个基于Promise的HTTP客户端,而Ajax是一种用于创建异步请求的技术。
- Axios可以用于浏览器和Node.js环境,而Ajax只能用于浏览器环境。
- Axios支持更多的功能,如跨域请求、拦截请求和响应、取消请求等。
- 使用Axios时,可以通过简单的API发送HTTP请求,而使用Ajax需要手动创建XMLHttpRequest对象。
- Axios相对来说是较新的技术,逐渐取代了Ajax的使用。
9、HTML中的DOM操作是指使用JavaScript来操作HTML文档中的各个元素和属性。DOM(文档对象模型)提供了一种访问和操作HTML文档的标准方式。
通过DOM操作,可以实现以下功能:
-
获取元素:使用document对象的方法,如getElementById、getElementsByTagName、getElementsByClassName等来获取HTML文档中的元素。
-
修改元素的内容:使用innerHTML属性来修改元素的内容,或使用textContent属性来修改文本内容。
-
修改元素的样式:使用style属性来修改元素的样式,如颜色、背景、字体等。
-
修改元素的属性:使用setAttribute方法来修改元素的属性,如class、id、src等。
-
创建和删除元素:使用createElement方法创建新的元素,并使用appendChild或insertBefore方法将其插入到指定位置,使用removeChild方法将元素从文档中删除。
-
监听事件:使用addEventListener方法来监听元素上的事件,如点击、鼠标移动等。
-
修改表单数据:可以使用JavaScript来获取和修改表单元素的值,如input、select、textarea等。
通过以上DOM操作,可以实现动态地更新HTML文档的内容、样式和行为,使网页具有更好的交互性和用户体验。HTML中的DOM操作。
10、普通函数和自定义hook的区别。
-
使用方式:
- 普通函数可以在任何地方被调用,可以接受任意参数并返回一个值。
- 自定义hook只能在函数组件中使用,并且必须按照规定的方式调用和使用返回的值。
-
设计思路:
- 普通函数通常用于解决具体的问题,实现一些特定的功能逻辑。
- 自定义hook是一种将复用逻辑进行抽象和封装的方式,它可以将组件之间的共享逻辑提取出来,并使其更容易被理解、测试和维护。
-
命名规范:
- 普通函数没有特定的命名规范,可以根据需求起一个合适的名称。
- 自定义hook的命名必须以"use"开头,这是React的约定,以便开发者能够识别出它们是hooks。
总结起来,普通函数主要用于解决具体问题,而自定义hook主要用于复用和共享逻辑。自定义hook的设计目标是将组件之间的逻辑提取出来,使得逻辑更加清晰、可重用,并且符合React的设计理念。普通函数与自定义hook的区别。
11、SSR服务端渲染的理解。
SSR(Server-Side Rendering)是一种Web开发技术,它在服务器端生成完整的HTML内容,然后将其发送到客户端浏览器进行展示。与传统的客户端渲染(CSR)不同,客户端渲染是指在浏览器中使用JavaScript来动态生成HTML内容。
SSR的主要优势是改善了网页的加载性能和搜索引擎优化(SEO)。由于页面在服务器端生成,用户在请求页面时会直接获得完整的HTML内容,因此首次加载速度比CSR更快,且可以提供更好的搜索引擎抓取和索引。
SSR的实现需要使用一些特定的框架或库,如React的Next.js、Vue的Nuxt.js等。这些工具提供了服务端渲染的功能,可以将组件在服务器端渲染为HTML,并将其与浏览器端的JavaScript进行关联,以实现客户端的交互功能。
SSR的基本流程包括以下几个步骤:
- 服务器接收到请求,并根据请求的URL确定需要渲染的组件。
- 服务器使用组件渲染引擎(如React的服务器端渲染引擎)将组件渲染为HTML字符串。
- 服务器将生成的HTML字符串作为响应发送给客户端浏览器。
- 客户端浏览器接收到HTML响应后,会执行其中的JavaScript代码并构建页面的DOM结构。
- 客户端渲染工具会接管页面的控制,并处理用户的交互行为,如点击、输入等。
- 当用户进行交互时,客户端会通过Ajax或WebSocket等技术与服务器进行通信,获取数据并更新页面。
需要注意的是,由于SSR需要在服务器端进行组件渲染,因此对服务器的负载有一定的影响。此外,SSR也增加了开发的复杂性,因为需要同时处理服务器端和客户端的渲染逻辑。
12、浏览器如何做静态资源缓存?
浏览器可以通过以下几种方式进行静态资源缓存:
-
设置HTTP缓存头:浏览器通过设置响应头中的缓存相关字段,指示浏览器对静态资源进行缓存。常用的响应头字段有:
- Expires: 指定静态资源的过期时间,浏览器在过期时间之前不会重新请求该资源。
- Cache-Control: 控制缓存的行为,如设置为
max-age=3600
表示资源在一个小时内有效。 - Last-Modified/If-Modified-Since: 服务器返回资源的最后修改时间,浏览器在下一次请求时通过
If-Modified-Since
字段将上次的最后修改时间发送给服务器,如果资源在服务器上的最后修改时间仍然一致,服务器会返回一个304 Not Modified
的响应,表示资源未变化,浏览器可以使用缓存的版本。
-
ETag/If-None-Match: 服务器对于每个资源生成一个唯一的标识符,称为ETag,浏览器在下一次请求时通过
If-None-Match
字段将上次请求中服务器返回的ETag发送给服务器,如果这个资源的ETag仍然一致,服务器会返回一个304 Not Modified
的响应。 -
Service Worker缓存:通过Service Worker技术,浏览器可以在离线状态或网络不稳定的情况下,拦截对静态资源的请求并返回缓存的版本。
-
localStorage/IndexedDB: 将静态资源缓存到本地存储(localStorage或IndexedDB)中,下次使用时直接从本地读取。
需要注意的是,浏览器缓存是由浏览器自行处理的,开发人员只需在服务器端设置合适的响应头字段和缓存策略即可。另外,浏览器缓存只适用于静态资源,动态资源每次访问都会向服务器发起请求。
13、样式覆盖如何处理?
在前端开发中,样式覆盖是处理样式冲突的重要问题。以下是一些常见的处理样式覆盖的方法:
-
使用更具体的选择器:如果多个样式规则应用于同一个元素,可以使用更具体的选择器来指定优先级。例如,使用id选择器比class选择器具有更高的优先级。
-
使用!important:使用!important声明可以将样式规则的优先级提升到最高级别,但应谨慎使用此方法,因为它可能会导致样式无法继承和覆盖。
-
修改HTML结构:通过修改HTML结构可以改变元素的嵌套关系,从而达到覆盖样式的目的。例如,将要覆盖样式的元素移到不受其他样式影响的位置。
-
使用内联样式:通过将样式规则直接写在元素的style属性中,可以覆盖外部样式表中的样式。但这种方法比较繁琐,而且不易维护。
-
使用CSS权重:CSS权重是指样式规则的优先级,根据选择器的权重大小来决定样式的应用顺序。可以利用选择器的权重来控制样式覆盖的顺序。
-
使用CSS预处理器:使用CSS预处理器(如Sass或Less)可以更方便地管理样式覆盖问题。预处理器提供了变量、混