Bootstrap

2025新鲜出炉--前端面试题(一)


在这里插入图片描述

1. vue3有用过吗, 和vue2之间有哪些区别

在这里插入图片描述

是的,我有使用过 Vue 3。Vue 3 与 Vue 2 之间的一些主要区别包括:

  • 组合式 API:Vue 3 引入了 Composition API,它允许我们将相关代码逻辑组织在一起,而不是分散在不同的生命周期钩子和属性中,这有助于代码的维护和重用。
  • 性能提升:Vue 3 使用了 Proxy 实现响应式系统,这使得它的性能比 Vue 2 的 Object.defineProperty 更好,尤其是在处理大型数据对象时。
  • Tree-shaking 支持:Vue 3 的设计允许通过 tree-shaking 来减少最终构建的体积,因为组件的 API 是按需导入的。
  • 更好的类型支持:Vue 3 从一开始就考虑了 TypeScript 的支持,使得类型推断更加准确。
  • 新的生命周期钩子:例如 setup() 钩子,它是在组件创建之前调用的。
  • Fragment、Teleport 和 Suspense:Vue 3 支持了多个根节点(Fragment),Teleport 提供了一种将子组件渲染到 DOM 树的其他位置的方法,而 Suspense 则提供了等待嵌套组件渲染的机制。

2. vue-router有几种路由, 分别怎么实现

Vue Router 主要有以下几种路由方式:
实现这些路由通常是在 Vue Router 的配置对象中定义路由规则,然后使用 <router-view><router-link> 组件在应用中展示和导航。
- 动态路由匹配:通过 :param 的方式定义动态路由参数,例如 /user/:id
- 嵌套路由:在路由配置中使用 children 属性来定义子路由。
- 编程式导航:通过调用 router.pushrouter.replace 等方法来实现编程式导航。
- 命名视图:可以在同一个路由下定义多个视图,通过命名视图可以实现多视图布局。
- 重定向和别名:通过 redirect 属性进行重定向,或者使用 alias 属性为路由定义别名。
在这里插入图片描述

3. webpack和rollup这两个什么区别, 你会怎么选择

Webpack 和 Rollup 有以下区别:
我会根据项目需求来选择。如果是在开发应用,我会选择 Webpack,因为它提供了更全面的工具链支持。如果是在开发库或框架,我会倾向于使用 Rollup,因为它可以生成更简洁的代码。

  • 设计理念:Webpack 是为了处理复杂的模块依赖关系而设计的,适用于应用程序开发。Rollup 则专注于 ES6 模块打包,更适合库和框架的开发。
  • 功能:Webpack 提供了丰富的插件系统,可以处理多种类型的资源,如图片、样式表等。Rollup 则更专注于 JavaScript 的打包,插件较少。
  • 代码分割:Webpack 内置了代码分割功能,可以按需加载模块。Rollup 则需要借助插件来实现。

4. 你能简单介绍一下webpack项目的构建流程吗

Webpack 的构建流程大致如下:

  • 入口:Webpack 从定义的入口文件开始,递归地解析每个模块的依赖关系。
  • 加载器(Loaders):Webpack 使用加载器来处理非 JavaScript 文件,将它们转换为模块。
  • 插件(Plugins):在构建过程中,插件可以执行各种任务,如打包优化、资源管理和环境变量注入等。
  • 模块解析:Webpack 解析每个模块的路径和依赖关系。
  • 打包:Webpack 将所有模块打包成一个或多个 bundle。
  • 输出:最后,Webpack 将打包后的文件输出到指定的目录。

5. webpack平时有手写过loader和plugin吗

是的,我有手写过简单的 Webpack loader 和 plugin。一个 loader 是一个用于转换模块源代码的函数,它接收源代码作为参数,并返回转换后的代码。例如,我写过将特定格式的文件转换为 JavaScript 模块的 loader。而 plugin 则是用于扩展 Webpack 功能的对象,它通过在 Webpack 生命周期的特定时点挂载自定义函数来实现。我写过一些简单的 plugin,比如用于清理构建目录或在构建完成后执行某些自定义任务的 plugin。这些经验帮助我更好地理解了 Webpack 的工作原理,并能够根据项目需求进行定制化处理。

6. webpack这块你平时做过哪些优化吗?

在使用 Webpack 进行项目构建时,我进行了一些优化措施来提升构建速度和减少最终包的大小:

  • 使用 webpack-merge 合并配置:我将基础配置和开发/生产环境配置分开,使用 webpack-merge 来合并配置,这样可以保持配置的可维护性。
  • 利用 SplitChunksPlugin 进行代码分割:通过配置 SplitChunksPlugin,我将公共的依赖模块提取到单独的 chunk 中,这样可以利用浏览器缓存,减少重复加载。
  • 使用 TerserPlugin 进行代码压缩:在生产环境中,我使用 TerserPlugin 来压缩 JavaScript 代码,减少文件体积。
  • 开启 tree-shaking:确保只打包用到的模块和代码,减少不必要的代码。
  • 配置 externals:对于一些大型的库,比如 lodashmoment,我会将它们配置为外部依赖,避免打包到最终的 bundle 中。
  • 使用 webpack-bundle-analyzer 分析打包结果:通过可视化工具来分析打包后的文件大小,进一步优化。
  • 利用缓存:通过配置 cache-loaderHardSourceWebpackPlugin 来缓存构建结果,提高二次构建的速度。

7. var, let, const都有什么区别?

  • var 是 ES5 中的变量声明方式,它具有函数作用域或全局作用域,存在变量提升的问题,且可以重复声明。
  • let 是 ES6 中引入的,它具有块级作用域,不存在变量提升,但可以在同一作用域内重复声明。
  • const 也是 ES6 中引入的,用于声明一个只读的常量引用,它同样具有块级作用域,且不允许重复声明。但是,const 声明的对象属性是可以修改的,因为 const 只保证变量名指向的地址不变,不保证地址内的值不变。

8. const a = { b: 1 }; a.b = 2有什么方法让他赋值无效?

要使 a.b = 2 赋值无效,可以使用 Object.freeze() 方法来冻结对象,这样就不能再修改对象的属性了。示例代码如下:

const a = Object.freeze({ b: 1 });
a.b = 2; // 这行代码不会生效,因为对象已经被冻结

9. arr = [6, 4, 5, 3, 1, 8]能不能用快速排序把数组升序?

function quickSort(arr) {
  if (arr.length <= 1) {
    return arr;
  }
  const pivot = arr[0];
  const left = [];
  const right = [];
  for (let i = 1; i < arr.length; i++) {
    if (arr[i] < pivot) {
      left.push(arr[i]);
    } else {
      right.push(arr[i]);
    }
  }
  return quickSort(left).concat(pivot, quickSort(right));
}

const sortedArr = quickSort([6, 4, 5, 3, 1, 8]);
console.log(sortedArr); // 输出升序数组
 

10. 能不能实现一个洗牌算法,打乱一个升序数组?

可以使用 Fisher-Yates(也称为 Knuth)洗牌算法来实现。以下是该算法的一个简单实现:

function shuffleArray(arr) {
  for (let i = arr.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [arr[i], arr[j]] = [arr[j], arr[i]]; // 交换元素
  }
  return arr;
}

const orderedArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const shuffledArray = shuffleArray(orderedArray);
console.log(shuffledArray); // 输出打乱后的数组

11. 如何计算一个算法的时间复杂度和空间复杂度?

时间复杂度是指算法执行的时间与输入数据量之间的关系。计算时间复杂度的步骤通常包括:

  • 确定算法的基本操作:基本操作通常是算法中出现次数最多的原子操作。
  • 分析算法中基本操作的执行次数:这通常涉及到循环的次数,递归的深度等。
  • 表达基本操作的执行次数与输入规模的关系:使用大O符号表示法来描述这种关系。

空间复杂度是指算法在执行过程中临时占用存储空间的大小。计算空间复杂度的步骤通常包括:

  • 确定算法中使用的变量和数据结构:包括局部变量、全局变量、递归栈等。
  • 分析这些变量和数据结构所占用的空间大小:通常考虑最坏情况下的空间占用。
  • 表达空间占用与输入规模的关系:同样使用大O符号表示法。

12. promise你平时有哪些使用场景?

Promise 是 JavaScript 中用于处理异步操作的一种机制。以下是一些常见的使用场景:

  • 异步网络请求:例如,使用 fetch API 进行网络请求时,返回的是一个 Promise 对象。
  • 异步文件操作:例如,在 Node.js 中读取文件时,可以使用 fs.promises API。
  • 数据库操作:在处理数据库查询时,很多数据库库都支持使用 Promise。
  • 执行顺序控制:需要按顺序执行一系列异步操作时,可以使用 Promise.then() 链式调用。
  • 并发控制:使用 Promise.all()Promise.race() 来处理多个并发异步操作。

13. 实现一个sleep(1000)方法

在 JavaScript 中,可以使用 Promise 来实现一个 sleep 函数:

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

// 使用示例
sleep(1000).then(() => {
  console.log('唤醒');
});

14.现在有10个请求, 但是同一时间只能发送三个, 并要保证顺序

可以使用 Promise 和队列来实现这个需求:

function sendRequest(requests, max) {
  let i = 0;
  const results = [];
  const executing = [];

  const enqueue = () => {
    if (i === requests.length) {
      return Promise.resolve();
    }
    const request = requests[i++].then(res => {
      results.push(res);
      return res;
    });
    executing.push(request);
    request.finally(() => executing.splice(executing.indexOf(request), 1));
    let r = Promise.resolve();
    if (executing.length >= max) {
      r = Promise.race(executing);
    }
    return r.then(() => enqueue());
  };

  return enqueue().then(() => results);
}

// 假设 `requests` 是一个包含10个请求的 Promise 数组
sendRequest(requests, 3).then(results => {
  console.log(results);
});

15.能否用C3动画实现一个旋转效果

可以使用 CSS3 的 @keyframes 规则和 transform 属性来实现旋转动画:

@keyframes rotate {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

.rotate-element {
  animation: rotate 2s linear infinite;
}

然后在 HTML 中应用这个类:

<div class="rotate-element">旋转我</div>

这样, rotate-element 类的元素就会持续旋转。

16. flex用过吗, 都有哪些属性, flex-grow属性是做什么的

是的,我经常使用 Flexbox 布局,因为它提供了一种更加灵活的方式来对齐和分配容器内元素的空间,即使它们的大小是未知或者是动态的。

Flexbox 的主要属性可以分为两类:容器属性和项目属性。

容器属性 包括:

  • display: 定义一个元素是否是一个 Flex 容器。
  • flex-direction: 定义主轴的方向。
  • flex-wrap: 定义容器是单行还是多行,以及如何处理子元素的换行。
  • flex-flow: 是 flex-directionflex-wrap 的简写形式。
  • justify-content: 定义了项目在主轴上的对齐方式。
  • align-items: 定义项目在交叉轴上如何对齐。
  • align-content: 定义了多根轴线的对齐方式。

项目属性 包括:

  • order: 定义项目的排列顺序。
  • flex-grow: 定义项目的放大比例,即如果存在剩余空间,项目应该放大的比例。
  • flex-shrink: 定义项目的缩小比例。
  • flex-basis: 定义了在分配多余空间之前,项目占据的主轴空间。
  • flex: 是 flex-grow, flex-shrinkflex-basis 的简写。
  • align-self: 允许单个项目有与其他项目不一样的对齐方式。

flex-grow 属性的作用是定义当父容器的空间有剩余时,子元素应该如何放大。它接受一个无单位的比例值,默认值为 0,表示即使有剩余空间,也不会放大。如果所有子元素的 flex-grow 值总和超过 1,它们会按照比例分配剩余空间。

17. 如何实现一个元素水平垂直同时居中

有多种方法可以实现元素的水平垂直居中:

使用 Flexbox:

.parent {
  display: flex;
  justify-content: center;
  align-items: center;
}

.child {
  /* 子元素样式 */
}

使用 Grid:

.parent {
  display: grid;
  place-items: center;
}

.child {
  /* 子元素样式 */
}

使用定位和 transform:

.parent {
  position: relative;
}

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

18.在平时项目中你都做过哪些性能优化

在项目中,我通常会进行以下性能优化:

  1. 代码分割:使用 Webpack 等模块打包工具进行代码分割,减少单次加载的资源大小。
  2. 懒加载:对于非首屏内容,使用懒加载技术,按需加载资源。
  3. 图片优化:使用适当格式的图片,如 WebP,以及压缩图片大小。
  4. 缓存利用:利用 HTTP 缓存,减少重复资源的加载。
  5. CSS/JS 文件压缩:通过压缩工具减小文件体积。
  6. 使用 CDN:通过 CDN 加速静态资源的加载。
  7. 减少重绘和回流:优化 DOM 操作,避免不必要的重绘和回流。
  8. 使用服务端渲染 (SSR):对于首屏内容,使用 SSR 加速内容的呈现。

19. 能否手写实现一个防抖函数

function debounce(func, wait) {
  let timeout;
  return function() {
    const context = this;
    const args = arguments;
    clearTimeout(timeout);
    timeout = setTimeout(() => {
      func.apply(context, args);
    }, wait);
  };
}

// 使用示例
window.addEventListener('resize', debounce(function() {
  console.log('窗口大小改变了!');
}, 250));

这个防抖函数会在事件触发后等待指定的等待时间( wait ),如果在这段时间内事件再次触发,则会重新计时。只有在等待时间结束后没有再次触发事件,才会执行传入的函数。

;