文章目录
- 1. vue3有用过吗, 和vue2之间有哪些区别
- 2. vue-router有几种路由, 分别怎么实现
- 3. webpack和rollup这两个什么区别, 你会怎么选择
- 4. 你能简单介绍一下webpack项目的构建流程吗
- 5. webpack平时有手写过loader和plugin吗
- 6. webpack这块你平时做过哪些优化吗?
- 7. var, let, const都有什么区别?
- 8. const a = { b: 1 }; a.b = 2有什么方法让他赋值无效?
- 9. arr = [6, 4, 5, 3, 1, 8]能不能用快速排序把数组升序?
- 10. 能不能实现一个洗牌算法,打乱一个升序数组?
- 11. 如何计算一个算法的时间复杂度和空间复杂度?
- 12. promise你平时有哪些使用场景?
- 13. 实现一个sleep(1000)方法
- 14.现在有10个请求, 但是同一时间只能发送三个, 并要保证顺序
- 15.能否用C3动画实现一个旋转效果
- 16. flex用过吗, 都有哪些属性, flex-grow属性是做什么的
- 17. 如何实现一个元素水平垂直同时居中
- 18.在平时项目中你都做过哪些性能优化
- 19. 能否手写实现一个防抖函数
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.push
、router.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
:对于一些大型的库,比如lodash
或moment
,我会将它们配置为外部依赖,避免打包到最终的 bundle 中。 - 使用
webpack-bundle-analyzer
分析打包结果:通过可视化工具来分析打包后的文件大小,进一步优化。 - 利用缓存:通过配置
cache-loader
或HardSourceWebpackPlugin
来缓存构建结果,提高二次构建的速度。
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-direction
和flex-wrap
的简写形式。justify-content
: 定义了项目在主轴上的对齐方式。align-items
: 定义项目在交叉轴上如何对齐。align-content
: 定义了多根轴线的对齐方式。
项目属性 包括:
order
: 定义项目的排列顺序。flex-grow
: 定义项目的放大比例,即如果存在剩余空间,项目应该放大的比例。flex-shrink
: 定义项目的缩小比例。flex-basis
: 定义了在分配多余空间之前,项目占据的主轴空间。flex
: 是flex-grow
,flex-shrink
和flex-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.在平时项目中你都做过哪些性能优化
在项目中,我通常会进行以下性能优化:
- 代码分割:使用 Webpack 等模块打包工具进行代码分割,减少单次加载的资源大小。
- 懒加载:对于非首屏内容,使用懒加载技术,按需加载资源。
- 图片优化:使用适当格式的图片,如 WebP,以及压缩图片大小。
- 缓存利用:利用 HTTP 缓存,减少重复资源的加载。
- CSS/JS 文件压缩:通过压缩工具减小文件体积。
- 使用 CDN:通过 CDN 加速静态资源的加载。
- 减少重绘和回流:优化 DOM 操作,避免不必要的重绘和回流。
- 使用服务端渲染 (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
),如果在这段时间内事件再次触发,则会重新计时。只有在等待时间结束后没有再次触发事件,才会执行传入的函数。