第4章 前端面试技能拼图2 :前端基础知识 , 必知必会
4-3 4-4 Ajax-Fetch-Axios三者有什么区别
答案:
- ajax 是一种技术称呼,不是具体的 API 和库
- fetch 是新的异步请求 API ,可代替 XMLHttpRequest
- axios 是第三方库
AJAX
—— Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)
即使用 JS 进行异步请求
,基于当时 JS 规范,异步请求主要使用 XMLHttpRequest 这个底层 API
所以,有一道常考的面试题:请用 XMLHttpRequest 实现 ajax
function ajax(url, successFn) {
const xhr = new XMLHttpRequest()
xhr.open("GET", url, false)
xhr.onreadystatechange = function () {
// 这里的函数异步执行,可参考之前 JS 基础中的异步模块
if (xhr.readyState == 4) {
if (xhr.status == 200) {
successFn(xhr.responseText)
}
}
}
xhr.send(null)
}
fetch 是一个原生 API
,它和 XMLHttpRequest 一个级别。
fetch 和 XMLHttpRequest 的区别
- 写法更加简洁
- 原生支持 promise
面试题:用 fetch 实现一个 ajax
function ajax(url) {
return fetch(url).then(res => res.json())
}
axios 是一个第三方库
随着 Vue 一起崛起。它和 jquery 一样(jquery 也有 ajax 功能)
axios 内部可以用 XMLHttpRequest 或者 fetch 实现
4-5 4-6 -防抖和节流有什么区别,分别用于什么场景
防抖:一个搜索输入框,等输入停止之后,自动执行搜索
<body>
<p>debounce</p>
搜索 <input id="input1">
<script>
function debounce(fn, delay = 200) {
let timer = 0
return function () {
if (timer) clearTimeout(timer) //注意这里
timer = setTimeout(() => {
fn.apply(this, arguments) // 透传 this 和参数
timer = 0
}, delay)
}
}
const input1 = document.getElementById('input1')
input1.addEventListener('keyup', debounce(() => {
console.log('发起搜索', input1.value)
}), 300)
</script>
</body>
节流:drag 的回调,上传进度的回调,都可以设置一个固定的频率,没必要那么频繁
<body>
<p>throttle</p>
<div id="div1" draggable="true" style="width: 100px; height: 50px; background-color: #ccc; padding: 10px;">
可拖拽
</div>
<script>
function throttle(fn, delay = 100) {
let timer = 0
return function () {
if (timer) return // 注意这里
timer = setTimeout(() => {
fn.apply(this, arguments)
timer = 0
}, delay)
}
}
const div1 = document.getElementById('div1')
div1.addEventListener('drag', throttle((e) => {
console.log('鼠标的位置', e.offsetX, e.offsetY)
}))
</script>
</body>
答案:
防抖和节流都用于处理频繁触发的操作,优化操作体验。
触发频率
- 防抖,不固定。限制执行次数,多次密集的触发只执行一次
- 节流,固定。限制执行频率,有节奏地执行
场景
- 防抖,结果式,即一次调用即可
- 节流,过程式,即需要持续一个过程,一次不够
4-7 -px-%-em-rem-vw-vh有什么区别
- px:像素,基本单位
- %:相对于父元素的尺寸。
- em:相对于当前元素的
font-size
。首行缩进可以使用text-indent: 2em
- rem:rem = root em;相对于根元素的
font-size
。可以根据媒体查询,设置根元素的font-size
,实现移动端适配
- vw/vh:
- vw 屏幕宽度的 1%
- vh 屏幕高度的 1%
- vmin 两者最小值
- vmax 两者最大值
4-8 -什么时候不能使用箭头函数【重要】
答案:
箭头函数的缺点
- arguments 参数
- 无法改变 this
不适用的场景
- 对象方法
- 对象原型
【记得】
- 构造函数
- 动态上下文【这里面使用
this
是不行的】
- Vue 生命周期和方法
【重要】
Vue 组件是一个对象,而 React 组件是一个 class (如果不考虑 Composition API 和 Hooks)
4-9 请描述 TCP 三次握手和四次挥手【捉住重点即可】
建立连接
客户端和服务端通过 HTTP 协议发送请求,并获取内容
在发送请求之前,需要先建立连接,确定目标机器处于可接受请求的状态。
HTTP 协议是一个应用层的协议,它只规定了 req 和 res 的数据格式,如状态码、header、body 等。
而建立网络连接需要更加底层的 TCP 协议
三次握手
三次握手,即建立一次 TCP 连接时,客户端和服务端总共需要发送 3 个包
过程
- 客户端发包,服务端收到。服务端确认:客户端的发送能力是正常的。
- 服务端发包,客户端收到。客户端确认:服务端的接收能力是正常的。
- 客户端发包,服务端收到。服务端确认:客户端即将给我发送数据,我要准备接收。
建立连接完成,然后就开始发送数据,通讯。
四次挥手
挥手,就是关闭连接
你在 chrome 中看到的是一次 http 请求,其实背后可能需要好几次网络传输,只不过浏览器给合并起来了。
【注意】这里你需要等着确认对方关门,才算是完全关闭连接,不能你说一声就不管了。跟日常生活不一样。
- 你:我准备睡觉了
- 张三:好的 (此时可能还要继续给你发送,你也得继续接收。直到张三发送完)
- 张三:我也准备去睡了
- 你:好,去睡吧 (然后你可以走了,张三可以关门了,连接结束)
过程
- 客户端发包,服务端接收。服务端确认:客户端已经请求结束
- 服务端发包,客户端接收。客户端确认:服务端已经收到,我等待它关闭
- 服务端发包:客户端接受。客户端确认:服务端已经发送完成,可以关闭
- 客户端发包,服务端接收。服务端确认:可以关闭了
图示
4-10 JS中for-in和for-of有什么区别
答案
- for…in 遍历一个对象的可枚举属性,如对象、数组、字符串。针对属性,所以获得 key
- for…of 遍历一个可迭代对象,如数组、字符串、Map/Set 。针对一个迭代对象,所以获得 value
key 和 value
for…in 遍历 key , for…of 遍历 value
遍历对象
for…in 可以遍历对象,for…of 不可以
遍历 Map/Set
for…of 可以遍历 Map/Set ,for…in 不可以
遍历 generator
for…of 可遍历 generator ,for…in 不可以
对象的可枚举属性
for…in 遍历一个对象的可枚举属性。
使用 Object.getOwnPropertyDescriptors(obj)
可以获取对象的所有属性描述,看 enumerable: true
来判断该属性是否可枚举。
对象,数组,字符串
可迭代对象
for…of 遍历一个可迭代对象。
其实就是迭代器模式,通过一个 next
方法返回下一个元素。
该对象要实现一个 [Symbol.iterator]
方法,其中返回一个 next
函数,用于返回下一个 value(不是 key)。
可以执行 arr[Symbol.iterator]()
看一下。
JS 中内置迭代器的类型有 String
Array
arguments
NodeList
Map
Set
generator
等。
4-11 -【连环问】for-await-of 有什么作用
用于遍历异步请求的可迭代对象。
4-12 -offsetHeight-scrollHeight-clientHeight有什么区别
- offsetHeight -
border
+ padding + content - clientHeight - padding + content
- scrollHeight - padding +
实际内容的高度
scrollTop scrollLeft: DOM 内部元素滚动的距离
4-13 - HTMLCollection和NodeList
有什么区别
答案
- HTMLCollection 是 Element 集合,NodeList 是 Node 集合
- Node 是所有 DOM 节点的基类,Element 是 html 元素的基类
Node 和 Element
DOM 结构是一棵树,树的所有节点都是 Node
,包括:document,元素,文本,注释,fragment 等
Element
继承于 Node 。它是所有 html 元素的基类,如 HTMLParagraphElement
HTMLDivElement
HTMLCollection 和 NodeList
HTMLCollection 是 Element 集合,它由获取 Element 的 API 返回
elem.children
document.getElementsByTagName('p')
NodeList 是 Node 集合,它由获取 Node 的 API 返回
document.querySelectorAll('p')
elem.childNodes
拓展 HTMLCollection 和 NodeList 都不是数组,而是“类数组”,转换为数组:
const arr1 = Array.from(list)
const arr2 = Array.prototype.slice.call(list)
const arr3 = [...list]
4-14 -Vue中computed和watch有什么区别
答案:
- computed 就已有数据产出新数据,有缓存
- watch 监听已有数据
4-15 4-16 4-17 4-18 Vue组件通讯有几种方式,尽量全面-props-emits和自定义事件
答案:
- 父子组件通讯
props
emits
this.$emit
$attrs
(也可以通过v-bind="$attrs"
向下级传递)$parent
$refs
- 多级组件上下级
provide
inject
- 跨级、全局
- 自定义事件
- Vuex
props / $emit
适用于父子组件。
- 父组件向子组件传递 props 和事件
- 子组件接收 props ,使用
this.$emit
调用事件
自定义事件
适用于兄弟组件,或者“距离”较远的组件。
常用 API
- 绑定事件
event.on(key, fn)
或event.once(key, fn)
- 触发事件
event.emit(key, data)
- 解绑事件
event.off(key, fn)
Vue 版本的区别
- Vue 2.x 可以使用 Vue 实例作为自定义事件
- Vue 3.x 需要使用第三方的自定义事件,例如 https://www.npmjs.com/package/event-emitter
【注意】组件销毁时记得 off
事件,否则可能会造成内存泄漏
$attrs
$attrs
存储是父组件中传递过来的,且未在 props
和 emits
中定义的属性和事件。
相当于 props
和 emits
的一个补充。
继续向下级传递,可以使用 v-bind="$attrs"
。这会在下级组件中渲染 DOM 属性,可以用 inheritAttrs: false
避免。
【注意】Vue3 中移除了 $listeners
,合并到了 $attrs
中。
$parent
通过 this.$parent
可以获取父组件,并可以继续获取属性、调用方法等。
【注意】Vue3 中移除了 $children
,建议使用 $refs
$refs
通过 this.$refs.xxx
可以获取某个子组件,前提是模板中要设置 ref="xxx"
。
【注意】要在 mounted
中获取 this.$refs
,不能在 created
中获取。
provide / inject
父子组件通讯方式非常多。如果是多层级的上下级组件通讯,可以使用 provide 和 inject 。
在上级组件定一个 provide ,下级组件即可通过 inject 接收。
- 传递静态数据直接使用
provide: { x: 10 }
形式 - 传递组件数据需要使用
provide() { return { x: this.xx } }
形式,但做不到响应式 - 响应式需要借助
computed
来支持
Vuex全局数据管理
4-19 -Vuex中action和mutation有什么区别
- mutation
- 建议原子操作,每次只修改一个数据,不要贪多
- 必须是同步代码,方便查看 devTools 中的状态变化
- action
- 可包含多个 mutation
- 可以是异步操作
4-20 -JS严格模式有什么特点
- 全局变量必须声明
- 禁止使用 with
- 创建 eval 作用域
- 禁止 this 指向全局作用域
- 函数参数不能重名
4-21 HTTP跨域时为何要发送options请求
使用 CORS 跨域请求时,经常会看到一个“多余”的 options请求,之后才发送了实际的请求。该请求就是为了检查服务端的 headers 信息,是否符合客户端的预期。所以它没有 body 的返回。
规范要求,对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求。—— MDN
答案:options 请求就是对 CORS跨域请求之间的一次预检查,检查成功再发起正式请求,是浏览器自行处理的。了解即可,实际开发中不用过于关注
4-22 4-23 扩展补充:Restful API 常用 method
暂无