前端复健笔记1

1.vite里source-map配置有什么作用

Vite 中,source-map(源码映射)配置的核心作用是‌将构建或编译后的代码映射回原始源代码‌,从而在浏览器开发者工具中直接查看和调试原始的 TypeScript、JSX、SCSS 等源码,而非压缩或转译后的产物代码,方便设置断点、查看变量,大幅提升问题排查效率。配置文件:vite.config.js,值:true(生成 .map 文件,并在 bundle 中添加 //# sourceMappingURL= 注释) | false | hidden(生成 .map 文件,但‌不添加‌注释) | inline(Source Map 内联到 JS 文件中(作为 data URI))。

import { defineConfig } from 'vite';

export default defineConfig({
  build: {
    sourcemap: process.env.NODE_ENV === 'production' ? 'hidden' : true
  }
});

Vite 在 vite dev 模式下默认使用 inline-source-map,无需额外配置即可调试 TS/SCSS 等源码。

‌开发环境‌:保持 sourcemap: true(默认),确保快速精准调试。

‌生产环境‌:若无错误监控系统 → sourcemap: false;若使用 Sentry 等工具 → sourcemap: 'hidden',并上传 .map 文件至监控平台。

大型项目‌:结合 rollupOptions.output.sourcemapExcludeSources 减少 .map 文件体积。

 

2.vue-router history模式上线时需要注意什么事项

①后端服务器配置重定向规则。History模式依赖 HTML5 History API,URL无#,刷新或直接访问路由时会向服务器发送请求。若服务器未配置,将因找不到对应静态资源返回 ‌404‌。需将所有前端路由请求回退至 index.html,由 Vue Router 接管。

②正确设置 base 路径(如部署在子目录)‌。若应用部署在非根域名下(如 https://example.com/my-app/),需在创建 Router 实例时指定 base:

const router = createRouter({
  history: createWebHistory('/my-app/'), // Vue 3
  // 或
  mode: 'history',
  base: '/my-app/',
  routes
});

  

③检查资源路径引用方式‌,确保 index.html 中引入的 CSS、JS、图片等资源使用‌绝对路径‌(以 / 开头),避免因路由层级导致 404。

④验证打包配置(如使用 Vue CLI 或 Vite)‌。‌Vue CLI‌:确保 publicPath 为 '/'(默认)或与部署路径一致;Vite‌:检查 base 配置。

// vue.config.js
module.exports = {
  publicPath: process.env.NODE_ENV === 'production' ? '/my-app/' : '/'
};

  

// vite.config.js
export default defineConfig({
  base: '/my-app/'
});

  

⑤上线前务必在浏览器中直接访问非首页路由(如 /about)并刷新,确认是否正常加载。

 

3.scss中除了变量还有哪些常用语法

①嵌套规则(Nesting)‌。允许将子选择器嵌套在父选择器内部,使代码结构更清晰、贴近 HTML 层级。

②混合宏(Mixins)。可定义可重用的样式块,支持参数和默认值,类似函数。

③继承(@extend)。一个选择器可以继承另一个选择器的所有样式,减少重复代码。

④函数(Functions)。支持内置函数(如 lighten()、darken()、rgba() 等),也支持自定义函数。

⑤控制指令(Control Directives)。包括条件语句(@if / @else)和循环(@for、@each、@while),用于动态生成样式。

⑥占位符选择器(Placeholder Selectors)。以 % 开头,定义不会直接输出的可继承样式,常用于抽象公共样式。

⑦导入(@import)。可将多个 SCSS 文件合并编译,支持模块化开发。

⑧插值(Interpolation)。使用 #{} 在选择器、属性名或值中插入变量。

‌⑨默认变量(!default)。设置变量的默认值,允许后续覆盖。

⑩注释(Comments)。支持单行(//,不输出到 CSS)和多行(/* */,会保留)注释。

⑩①属性嵌套(Nested Properties)。对于具有相同前缀的属性(如 border、font),可进行嵌套写法。

示例:

.nav {
  ul { margin: 0; padding: 0; }
  li { display: inline-block; }
  a { color: blue; }
}

@mixin border-radius($radius: 5px) {
  border-radius: $radius;
}
.box { @include border-radius(10px); }

%btn { padding: 10px; border: none; }
.btn-primary { @extend %btn; background-color: blue; }

@function px-to-rem($px, $base: 16px) {
  @return ($px / $base) * 1rem;
}
.text { font-size: px-to-rem(18px); }

@for $i from 1 through 3 {
  .col-#{$i} { width: 100% / $i; }
}

%center { display: flex; justify-content: center; }
.container { @extend %center; }

@import 'variables';
@import 'buttons';

$property: margin;
.box { #{$property}: 10px; }

$color: blue !default;
$color: red; // 覆盖默认值

.box {
  font: {
    family: Arial;
    size: 16px;
  }
}

  

4、【JS】对闭包的理解

闭包就是在一个内层函数中访问到其外层函数的作用域。在 JavaScript中,每当创建一个函数,闭包就会在函数创建的同时被创建出来,作为函数内部与外部连接起来的一座桥梁。

闭包的优缺点:优点:1:变量长期驻扎在内存中,可以重复使用变量;2:闭包可以实现局部变量,避免全局变量的污染;3:可用于声明私有函数和变量。缺点:1.滥用闭包会造成内存泄露;2.性能损失大。

闭包的工作原理:1.‌函数的作用域‌:在JavaScript中,每个函数都有自己的作用域。当一个函数在其内部创建另一个函数时,内部函数会捕获其外部函数的变量。2.变量的生命周期‌:通常,当一个函数执行完毕后,其局部变量会被销毁。但当内部函数被返回或以其他方式被外部访问时,这些变量不会被销毁(无法被垃圾回收机制回收),因为它们被内部函数“捕获”了。

闭包的作用:私有化变量、模块化、缓存、防抖节流、循环绑定事件。

防抖示例:

function debounce(fn, delay) {
  let timer = null;
  return function(...args) {
    clearTimeout(timer);
    timer = setTimeout(() => fn.apply(this, args), delay);
  };
}

  

5.事件循环(Event Loop)

事件循环是由一个或以上的任务队列组成的。由于 JavaScript 是单线程语言,所以在 JS 中所有的任务都需要排队执行,这些任务共同组成了任务队列,依次排队执行的过程,形成一个执行栈。在任务队列中,最先执行是同步任务。

同步任务就是当上一个任务执行完成后,接下来可以立即执行的任务。它们在主线程上依次排队执行,直到清空。

异步任务就是需要等待被通知才以执行的任务,它们不会直接进入主线程执行,而是进入到微任务队列或下一次事件循环中的任务队列进行等待。

任务队列中遇到的宏任务将进入到下一次事件循环的任务队列,而微任务则会被放入到本次事件循环的微任务队列中。

异步任务分为宏任务和微任务:

常见宏任务:script、setTimeout、setInterval、document.appendChild()

常见微任务:Promise.then/catch/finally、MutationObserver、queueMicrotask

执行顺序:同步 → 微任务 → 渲染 → 下一个宏任务

 

6.promise封装接口返回的时候,如何串联后续流程(如另一个接口)

常见方法:

①使用.then()链式调用:每个.then()接收上一个Promise的成功结果,并返回一个新的Promise,从而可以无限串联。例如,先通过fetch获取数据,然后解析JSON,最后处理业务数据。

②使用async/await语法:在支持async/await的环境中,使用await关键字等待每个Promise解决,实现串行执行,代码更简洁。

③封装接口调用:可以将重复的Promise代码封装成函数,减少冗余代码。例如,针对同一个接口的多次嵌套调用,可以封装成函数进行调用。

④使用Promise.all():当需要同时处理多个异步请求并控制返回结果的顺序时,可以使用Promise.all()。它接收一个Promise数组,并返回一个新的Promise,当所有输入的Promise都解决后,新的Promise也解决,并返回一个包含所有结果的数组。

⑤使用Promise.race():如果只需要返回最快执行完成的Promise的结果,可使用Promise.race()。它接收一个Promise数组,返回一个新的Promise,当第一个输入的Promise解决或拒绝时,新的Promise也解决或拒绝,并返回该结果。

 

7.深拷贝与浅拷贝相关

JavaScript中,对象和数组是引用类型,这意味着将它们赋值给一个变量或者作为函数参数传递时,实际上是在传递一个指向内存中对象的引用,而不是对象本身的副本。

①浅拷贝:只复制对象的第一层属性。也就是说,如果原始对象的属性是基本类型(如数字、字符串、布尔值),那么浅拷贝会复制这些值,且完全独立互不影响;但如果属性是引用类型(如数组、对象、函数),那么拷贝的只是引用,而不复制引用指向的内存地址中的数据,引用类型字段指向同一对象,修改会互相影响。

浅拷贝的方法:Object.assign();展开运算符(...);slice()方法【返回一个新数组,不改变原数组,但若数组包含对象,对象引用仍共享】……

②深拷贝:深拷贝会创建一个全新的对象,并且递归地复制所有属性,使得原始对象和拷贝对象完全独立,互不影响。深拷贝后的对象中所有的属性都是新的引用,即使属性是引用类型,也会被完全复制。

深拷贝的方法:JSON.parse(JSON.stringify(obj))【不能处理函数、undefined、循环引用、特殊对象(如Date、RegExp)等】;lodash的cloneDeep()……

 

8.computed和watch

相同点:

  • 本质上都是一个watcher实例,都通过响应式系统与数据,页面建立通信,只是行为不同
  • 计算属性和监听属性对于新值和旧值一样的赋值操作,都不会做任何变化,不过这一点的实现是在响应式系统完成的。
  • 都是以Vue的依赖追踪机制为基础的

不同点:

  • 机制不同:computed是‌计算属性‌,基于响应式依赖自动缓存派生值,依赖不变时直接返回缓存结果。watch是‌侦听器‌,用于监听特定数据变化并执行副作用操作(如异步请求、复杂逻辑),无缓存机制。
  • 使用场景不同:computed用于需要计算时;watch用于需要在数据变化时执行异步操作时(比如发送网络请求)、需要执行一些开销较大的操作,但又不需要实时更新UI时(比如监听浏览器的URL变化)。
  • computed支持缓存、不支持异步、必须同步返回值‌;watch:无缓存、支持异步、可深度监听对象/数组内部变化。

computed有什么场景是值发生了变化,但是结果没有被更新:

 

 

  • ‌直接通过索引修改数组元素‌
  • 修改数组长度‌(如:arr.length = newLength)
  • 在对象上动态添加新属性‌(若对象不是响应式的,或属性在初始化时不存在,直接赋值(如 obj.newProp = value
  • 使用非响应式对象替换响应式对象‌(如:state.data = { ... },若新对象不是通过 reactive() 或 ref() 创建,则会丢失响应式连接 ‌‌)
  • 在 computed 中读取了未被正确追踪的属性‌(如解构响应式对象:const { name } = this.user,此时 name 是普通变量,脱离了 Vue 的响应式系统 ‌‌
  • 依赖的值是 props 中未在 data/setup 中声明的字段‌
  • 使用了 Object.freeze() 冻结的对象‌(冻结后的对象属性变化不会触发响应式更新 ‌‌
  • computed 返回的是引用类型,但内部结构变化未通过响应式 API 触发‌(如仅修改了 reactive 对象中的普通属性,但该对象本身未被正确初始化为响应式 ‌‌

 

9.data为什么是一个函数,并且要返回一个对象

①为什么是一个函数

为了确保每个组件实例拥有‌独立的状态‌,避免数据共享带来的副作用。

Vue 组件通常会被多次复用(如多个按钮、卡片等),如果 data 是一个普通对象,所有组件实例会共享同一个引用,导致一个实例修改数据时,其他实例也会受到影响。当 data 是函数时,Vue 在创建每个组件实例时都会‌调用该函数‌,从而获得一个‌全新的数据对象‌,彼此隔离,互不干扰 ‌‌

②为什么必须返回一个对象

Vue 的响应式机制(基于 Object.defineProperty 或 Proxy)只能对‌对象的属性‌进行数据劫持。返回对象后,Vue 会将其所有属性转换为 getter/setter,实现视图自动更新 ‌‌。且对象可以包含多个属性,方便组织和访问组件状态 ‌‌

 

10.

 

posted @ 2026-05-10 21:37  芝麻小仙女  阅读(18)  评论(0)    收藏  举报