前端八股整理|JavaScript|高频小题 01

文章目录

1.computed和watch的区别是什么?computed是怎么实现缓存的,底层实现原理是什么?

computed 是计算属性,用于从已有响应式数据中派生出一个新值.watch 是侦听器,用于监听数据变化并执行副作用逻辑.computed 有缓存,只有依赖变化时才会重新计算,watch 没有缓存,数据变化就会执行回调.computed 适合模板中直接使用. watch 适合异步请求、日志记录、手动操作 DOM、联动处理等副作用场景.总结就是,computed 更关注"得到一个值",watch 更关注"数据变了以后做一件事"

深挖 1:computed是怎么实现缓存的,底层实现原理是什么?

结论:computed 的缓存本质是依赖不变时直接返回上一次计算结果;只有依赖发生变化时,才会把缓存标记为失效并重新计算。

computed 之所以能缓存,本质上是因为它内部会维护一个"是否需要重新计算"的标记。第一次读取 computed 值时,会执行传入的 getter,并把结果保存下来;之后如果依赖项没有发生变化,再次读取时就直接返回上一次的结果,不会重复执行 getter。

当 computed 依赖的响应式数据发生变化时,Vue 不会立刻重新计算,而是先把这个 computed 标记成"脏值",也就是缓存失效。等到下次真正有人读取这个 computed 值时,才会重新执行 getter,得到新结果并再次缓存。

2.了解过哪些布局,flex布局说一下,宽高不定的div如何定位在屏幕中间,宽高为0能用flex实现吗?

第一问:了解过哪些布局?

我了解过的布局方式主要有普通文档流、浮动布局、定位布局、Flex 布局和 Grid 布局。早期页面中会比较多用浮动和定位来做布局,现在实际开发里更常用的是 Flex 和 Grid。其中 Flex 更适合一维布局,主要解决一行或者一列上的对齐和分布问题;Grid 更适合二维布局,可以同时从行和列两个维度去划分区域。

拓展了解:

普通文档流就是按照 html 的顺序,比如几个 div,就是从上到下 div 都占一行,浮动布局就是 float ,定位布局就是 postion:绝对定位相对定位

第二问:Flex 布局说一下

Flex 是一种一维弹性布局模型,主要用于控制子元素在主轴和交叉轴上的排列方式。

使用时父元素设置 display: flex,之后可以通过:

• flex-direction 控制主轴方向

• justify-content 控制主轴对齐

• align-items 控制交叉轴对齐

• flex-wrap 控制是否换行

• 子元素通过 flex、flex-grow、flex-shrink、flex-basis 控制伸缩

它比较适合做水平排列、垂直居中、两端对齐、等分布局这类场景。

拓展了解::

为什么不叫横轴纵轴?

因为不是固定横轴纵轴,flex-direction 决定主轴的方向,它是 row,那主轴就是横向,反之就是纵向的,交叉轴就是主轴垂直的那个方向.

第三问:宽高不定的 div 如何定位在屏幕中间

方式一:绝对定位 + transform

css 复制代码
.parent {
  position: relative;
  width: 100vw;
  height: 100vh;
}

.child {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}

方式二:Flex 居中

css 复制代码
.parent {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100vw;
  height: 100vh;
}

如果父容器就是整个视口,其实更常用 flex 直接居中,实现会更简单。

第四问:宽高为 0 能用 flex 实现吗

可以。

因为 flex 控制的是flex item 在容器中的排列和对齐方式,并不要求子元素必须有宽高。

即使子元素宽高为 0,只要它是一个 flex item,仍然可以被放到父容器中心。

只是如果元素本身宽高为 0 且没有内容,视觉上看不到,所以看起来像"没有效果"。

css 复制代码
.parent {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100vw;
  height: 100vh;
}

.child {
  width: 0;
  height: 0;
}

3.cookie/localstorage/sessionstorage有什么区别?

它们都是浏览器提供的、在客户端(浏览器端)存储数据的技术,但它们在容量、生命周期、以及与服务器的通信这三个核心方面有着本质的区别。

cookie:
生命周期 :Cookie 的生命周期是可以手动设置的。我们可以给它设置一个过期时间,到时间后它就会自动失效。如果不设置,它默认在浏览器关闭时失效(这种也叫会话 Cookie)。如果设置了expires 或是 Max-age,就不是浏览器关闭就失效了,而是保存到指定时间.

容量:cookie 的容量比较小,一个域名下只能存储大约4KB 的数据

与服务器通信:每次发送 HTTP 请求到同个域名下时,浏览器都会自动把该域名下的所有 Cookie 都打包好,放在请求头里一起发送给服务器

缺点:

  • 每次请求都会携带,如果 Cookie 里存了太多不必要的数据,会增加网络流量,影响性能。
  • API 不够友好,需要手动封装

LocalStorage,属于Web Storage API:

生命周期:永久性存储,只要用户不手动清除浏览器缓存(或者代码里主动 localStorage.clear()),数据就永远不会过期,即使关闭浏览器、关机重启,数据依然存在。

容量: 非常大,通常在 5MB 到 10MB 之间

与服务器通信:纯粹的本地存储,它永远不会被自动发送到服务器

SessionStorage:

生命周期:"会话"级别的存储,单个浏览器标签页的生命周期,一旦这个标签页被关闭,它里面存储的所有 SessionStorage 数据都会被立即清除.

关键点: 即使是同一个网站,在两个不同的标签页里打开,它们的 SessionStorage 也是不互通、不共享的。

容量和与服务器通信和LocalStorage一样

4.数组有哪些常用的方法?说说他们的用途?

数组常用方法我一般按几类来记。

增删类:有 push、pop、shift、unshift,分别用于在数组头尾添加和删除元素;

遍历处理类:有 map、filter、reduce,其中 map 返回映射后的新数组,filter 用于筛选符合条件的元素,reduce 可以把数组累积计算成一个值;

截取类有: slice,用于截取数组的一部分且不改变原数组,splice 则可以在指定位置增删改元素,会修改原数组;

查找类:find、findIndex 用于查找元素,includes 判断数组中是否包含某个值,

其他的,join 可以把数组拼接成字符串,sort 用于排序,fill 用于用固定值填充数组。

拓展了解:

find 是找到第一个满足条件的元素本身,返回的是元素值,不是下标。参数是回调函数

findIndex 找到第一个满足条件的元素下标,返回的是索引。

javascript 复制代码
const arr = [10, 20, 30]
const res = arr.find(item => item > 15)
console.log(res) // 20
const res = arr.findIndex(item => item > 15)
console.log(res) // 1

5.列表渲染时为什么要设置 key?他起什么作用?

列表渲染时设置 key,主要是为了让 Vue 在更新虚拟 DOM 时准确识别每个节点。因为 Vue 在 patch 过程中会尽量复用已有节点,如果不写 key,它通常会按位置进行就地复用;当列表发生新增、删除或顺序变化时,这种复用可能会出错,导致渲染异常,比如输入框内容错位或组件状态混乱。给每个节点设置稳定且唯一的 key 后,Vue 就能更准确地判断哪些节点应该复用、哪些需要新增、删除或移动,这样既能保证更新结果正确,也能提升 diff 的效率。

举例来看:

假如页面如下:

javascript 复制代码
[
  { id: 1, name: '张三' },
  { id: 2, name: '李四' }
]
javascript 复制代码
<div v-for="item in list">
  <input />
  <span>{{ item.name }}</span>
</div>

现在用户在第一个输入框里手动输入了:hello

然后再列表头部插入一个新数据:

javascript 复制代码
[
  { id: 3, name: '王五' },
  { id: 1, name: '张三' },
  { id: 2, name: '李四' }
]

Vue 更新时,如果没有 key,会按照位置比较:

旧列表:

• 旧第 1 个:张三

• 旧第 2 个:李四

新列表:

• 新第 1 个:王五

• 新第 2 个:张三

• 新第 3 个:李四

因为没有 key,Vue 不知道"张三"是不是原来那个张三,vue的复用过程就变成了

第一步,把原来第一个 DOM 节点拿过来,改一改内容,让它现在显示成"王五".

第二步,把原来第二个 DOM 节点拿过来,改一改内容,让它现在显示成"张三"

第三步,再新建一个节点显示"李四"

问题来了,原来第一个节点里的 input,被用户输入过 hello,正常他的旁边应该显示的名字应该是张三,但是现在由于这种就地按位置复用,旁边展示的名字变成了王五这是不正确的,这就是节点按位置复用,导致 DOM 状态和数据身份错位。

加入 key 后恢复正常,为什么有key 时为什么不会乱?

javascript 复制代码
<div v-for="item in list" :key="item.id">
  <input />
  <span>{{ item.name }}</span>
</div>

那 Vue 就知道:

• id=1 这一项还是原来的张三

• id=2 这一项还是原来的李四

• id=3 是新来的王五

这时候它不会再按"第几个位置"认人,而是按 id 认人。更像是新建一个王五节点,然后把张三和李四整体向后移

深挖 1:为什么不建议用index索引作为key?

其实上面的例子就能说明不能使用 index 作为索引,index 是列表中数据的位置,其实是不稳定的.当列表发生新增、删除或排序变化时,同一个元素的 index 会变化,导致 key 不稳定。这样 Vue 在 diff 的时候就可能错误复用节点,出现输入框内容错位、组件状态混乱等问题。

上述问题的最小复现:动态加入王五

javascript 复制代码
<script setup lang="ts">
import { ref } from 'vue'

const list = ref([
  { id: 1, name: '张三' },
  { id: 2, name: '李四' }
])

const addItem = () => {
  list.value.unshift({ id: 3, name: '王五' })
}
</script>

<template>
  <div>
    <button @click="addItem">头部插入</button>

    <div v-for="item in list">
      <input />
      <span>{{ item.name }}</span>
    </div>
  </div>
</template>
相关推荐
Flutter笔记2 小时前
如何在本地跑 Core ML 模型识别呼噜声,并用 iCloud 优雅同步?
前端·人工智能·程序员
_MyFavorite_2 小时前
JAVA重点基础、进阶知识及易错点总结(15)缓冲流 + 转换流
java·开发语言·spring boot
Greg_Zhong2 小时前
前端测试的学习阶段,由基础到进阶的过程认识.....
前端·前端、专业测试结合
Mr Xu_2 小时前
Vue3 + Leaflet实战:深入解析MarkerCluster点位聚合插件的使用与优化
前端·javascript·vue.js
D_C_tyu3 小时前
Vue + Leaflet 实现地图任意点位点击查看时间功能
前端·javascript·vue.js
白叔King3 小时前
aardio时间日期转换中文时间
前端·javascript·aardio
攀登的牵牛花3 小时前
本周 GitHub 趋势观察:为什么前端热榜越来越像“AI 工具市场”?
前端·github
qq_333120973 小时前
头歌答案--爬虫实战
java·前端·爬虫
Jinuss3 小时前
源码分析之React中的组件缓存React.memo
前端·react.js