有时候一些其他领域的小伙伴,会私信问一些非博主领域相关触及知识盲区的问题,什么C++,C#,大前端…
其中有很多朋友问面试相关的,我之前的文章内有一篇关于Python领域面经汇总的置顶文章,那篇文章在我有空的时候,有价值的问题也会持续更新收录进去,感兴趣的可以去阅读:
极具参考价值的Python面试题!从创业公司到一线大厂的真实面经汇总(持续更新)
最近有几位朋友问前端的面试题目,说实话,我很难从专业的角度去给出总结,但是既然大家有需要,我还是在周末之余通过咨询相关领域的朋友跟目前比较主流的一些问题进行了一个汇总,于是有了这么一篇文章,希望它能够帮到你
前端天花板确实低,VP很少见?尽头小组长?撒一把米放键盘上?对于前端的梗很多,但是这都不重要!深耕自己的领域,你就是专家!
首先优化Loader的文件搜索范围:
module.exports = {
module: {
rules: [
{
// js 文件才使用 babel
test: /\.js$/,
loader: 'babel-loader',
// 只在 src 文件夹下查找
include: [resolve('src')],
// 不会去查找的路径
exclude: /node_modules/
}
]
}
}
对于 Babel 来说,希望只作用在 JS 代码上的,然后 node_modules 中使用的代码都是编译过的,所以完全没有必要再去处理一遍
当然这样做还不够,还可以将 Babel 编译过的文件缓存起来,下次只需要编译更改过的代码文件即可,这样可以大幅度加快打包时间
遍历旧数组,然后拿着旧数组元素去查询新数组,如果该元素在新数组里面没有出现过,我们就添加,否则不添加。先封装一个函数,unique:
function unique(arr){
var newArr =\[]
for(var i =0; i< arr.length; i++){
if (newArr.indexOf(arr\[i] === -1){
newArr.push(arr\[i])
}
}
return newArr
}
var demo = unique(\[])
console.log(demo)
异步方法,异步渲染最后一步,与JS事件循环联系紧密。主要使用了宏任务微任务(setTimeout、promise那些),定义了一个异步方法,多次调用nextTick会将方法存入队列,通过异步方法清空当前队列
Webpack 对图片进行压缩
减少 ES6 转为 ES5 的冗余代码
提取公共代码
模板预编译
提取组件的 CSS
优化 SourceMap
构建结果输出分析
Vue 项目的编译优化
v-if 和 v-show 区分使用场景
computed 和 watch 区分使用场景
v-for 遍历必须为 item 添加 key,且避免同时使用 v-if
长列表性能优化
事件的销毁
图片资源懒加载
路由懒加载
第三方插件的按需引入
优化无限列表性能
服务端渲染 SSR or 预渲染
开启gzip压缩、浏览器缓存、CDN使用、使用Chrome Performance查找性能瓶颈
四种命中查找,四个指针
1、旧前与新前(先比开头,后插入和删除节点的这种情况)
2、旧后与新后(比结尾,前插入或删除的情况)
3、旧前与新后(头与尾比,此种发生了,涉及移动节点,那么新前指向的节点,移动到旧后之后)
4、旧后与新前(尾与头比,此种发生了,涉及移动节点,那么新前指向的节点,移动到旧前之前)
事件循环是JavaScript中处理异步代码执行的机制。它负责管理调度和执行异步任务,并将它们添加到执行队列中。
在JavaScript中,事件循环的作用是确保异步任务按照正确的顺序执行,并且不会阻塞主线程。它通过不断地从执行队列中取出任务并执行,以实现非阻塞的异步操作
浏览器缓存是浏览器在本地存储Web页面和资源的副本,以便在后续访问时可以快速加载。它的作用是减少对服务器的请求次数和网络传输量,提高页面加载速度和用户体验。
浏览器缓存通过在首次请求时将资源保存到本地,并在后续请求时检查资源是否已经存在并且没有过期来工作。如果资源已经存在且未过期,浏览器会直接从缓存中加载资源,而不是从服务器重新下载
Web Workers是一种浏览器提供的JavaScript API,用于在后台线程中执行耗时的计算任务,以避免阻塞主线程。
Web Workers的作用是提高浏览器的响应性能,使得在执行复杂计算或处理大量数据时,不会影响用户界面的流畅性。
Web Workers通过将任务委托给后台线程来实现并行处理,从而充分利用多核处理器的能力。它们可以与主线程进行通信,但不能直接访问DOM或执行UI相关的操作
浏览器的垃圾回收机制是一种自动管理内存的机制,用于检测和回收不再使用的对象,以释放内存资源。
垃圾回收机制通过标记-清除算法实现。它的工作原理如下:
标记阶段:垃圾回收器会从根对象(如全局对象)开始,递归遍历所有对象,并标记仍然可访问的对象。
清除阶段:垃圾回收器会扫描堆内存,清除未被标记的对象,并回收它们所占用的内存空间。
垃圾回收机制的目标是识别和回收不再使用的对象,以避免内存泄漏和提高内存利用率
虚拟DOM本质上是JavaScript对象,是对真实DOM的抽象
状态变更时,记录新树和旧树的差异
最后把差异更新到真正的dom中
层叠顺序(z-index)用于控制元素在垂直方向上的堆叠顺序。具有较高层叠顺序值的元素将显示在较低层叠顺序值的元素之上。默认情况下,层叠顺序值为auto
伪类用于向选择器添加特殊的状态,如:hover、:active等。伪元素用于向选择器添加特殊的元素,如::before、::after
/* 伪类示例 */
a:hover {
color: red;
}
/* 伪元素示例 */
p::before {
content: "前缀";
}
在vue2中,v-for的优先级是高于v-if
vue3中则完全相反,v-if的优先级高于v-for
BFC(块级格式化上下文)是CSS中的一种渲染模式,它创建了一个独立的渲染环境,其中的元素按照一定的规则进行布局和定位。BFC的作用包括:清除浮动、防止外边距重叠
flexbox布局是一种用于创建灵活的、响应式的布局的CSS模块。它通过flex容器和flex项目的组合来实现强大的布局能力。其优势包括简单易用、自适应性强、对齐和分布控制灵活
CSS的盒模型是用于布局和定位元素的概念。它由内容区域、内边距、边框和外边距组成,这些部分依次包裹在元素周围
CSS选择器用于选择要应用样式的HTML元素。选择器的优先级规则是:内联样式 > ID选择器 > 类选择器、属性选择器、伪类选择器 > 元素选择器 > 通用选择器。同时,使用!important可以提升样式的优先级
在vue2中,v-for的优先级是高于v-if,把它们放在一起,输出的渲染函数中可以看出会先执行循环再判断条件,哪怕我们只渲染列表中一小部分元素,也得在每次重渲染的时候遍历整个列表,这会比较浪费;另外需要注意的是在vue3中则完全相反,v-if的优先级高于v-for,所以v-if执行时,它调用的变量还不存在,就会导致异常
工厂模式:虚拟 DOM 根据参数的不同返回基础标签的 Vnode 和组件 Vnode
单例模式:vuex 和 vue-router 的插件注册方法 install 判断如果系统存在实例就直接返回掉
发布-订阅模式 (vue 事件机制)
观察者模式 (响应式数据原理)
装饰模式: (@装饰器的用法)
策略模式:指对象有某个行为,但是在不同的场景中,该行为有不同的实现方案-比如选项的合并策略
Vue 的编译过程就是将 template 转化为 render 函数的过程 分为以下三步:
1、将模板字符串 转换成 element ASTs(解析器)
2、对AST进行静态节点标记,主要用来做虚拟DOM的渲染优化(优化器)
3、使用 element ASTs 生成 render 函数代码字符串(代码生成器)
export function compileToFunctions(template) {
// 我们需要把html字符串变成render函数
// 1.把html代码转成ast语法树 ast用来描述代码本身形成树结构 不仅可以描述html 也能描述css以及js语法
// 很多库都运用到了ast 比如 webpack babel eslint等等
let ast = parse(template);
// 2.优化静态节点
// 这个有兴趣的可以去看源码 不影响核心功能就不实现了
// if (options.optimize !== false) {
// optimize(ast, options);
// }
// 3.通过ast 重新生成代码
// 我们最后生成的代码需要和render函数一样
// 类似_c('div',{id:"app"},_c('div',undefined,_v("hello"+_s(name)),_c('span',undefined,_v("world"))))
// _c代表创建元素 _v代表创建文本 _s代表文Json.stringify--把对象解析成文本
let code = generate(ast);
// 使用with语法改变作用域为this 之后调用render函数可以使用call改变this 方便code里面的变量取值
let renderFn = new Function(`with(this){return ${code}}`);
return renderFn;
}
Vue3.x 改用 Proxy 替代 Object.defineProperty。因为 Proxy 可以直接监听对象和数组的变化,并且有多达 13 种拦截方法
import { mutableHandlers } from "./baseHandlers"; // 代理相关逻辑
import { isObject } from "./util"; // 工具方法
export function reactive(target) {
// 根据不同参数创建不同响应式对象
return createReactiveObject(target, mutableHandlers);
}
function createReactiveObject(target, baseHandler) {
if (!isObject(target)) {
return target;
}
const observed = new Proxy(target, baseHandler);
return observed;
}
const get = createGetter();
const set = createSetter();
function createGetter() {
return function get(target, key, receiver) {
// 对获取的值进行放射
const res = Reflect.get(target, key, receiver);
console.log("属性获取", key);
if (isObject(res)) {
// 如果获取的值是对象类型,则返回当前对象的代理对象
return reactive(res);
}
return res;
};
}
function createSetter() {
return function set(target, key, value, receiver) {
const oldValue = target[key];
const hadKey = hasOwn(target, key);
const result = Reflect.set(target, key, value, receiver);
if (!hadKey) {
console.log("属性新增", key, value);
} else if (hasChanged(value, oldValue)) {
console.log("属性值被修改", key, value);
}
return result;
};
}
export const mutableHandlers = {
get, // 当获取属性时调用此方法
set, // 当修改属性时调用此方法
};
Vue中的双向数据绑定是通过v-model指令实现的。v-model可以在表单元素(如、、)上创建双向数据绑定。当用户输入改变表单元素的值时,数据模型会自动更新;反之,当数据模型的值改变时,表单元素也会自动更新
Vue中的生命周期钩子包括beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeDestroy和destroyed。它们的执行顺序如下:
beforeCreate、created beforeMount、mounted、beforeUpdate、updated beforeDestroy、destroyed
Vue中的路由是通过Vue Router实现的。Vue Router是Vue.js官方提供的路由管理器,它允许开发者在Vue应用中实现单页面应用(SPA)。Vue Router通过配置路由映射关系,将URL路径与组件进行关联,并提供导航功能,使用户可以在不刷新页面的情况下切换视图
watch和computed都可以用于监听数据的变化,但它们的用法和实现方式略有不同。watch用于监听指定的数据变化,并在数据变化时执行相应的操作。computed用于根据依赖的数据动态计算得出一个新的值,并将该值缓存起来,只有在依赖的数据发生变化时才会重新计算
依赖注入是一种设计模式,用于将依赖关系从一个组件传递到另一个组件。在Vue中,依赖注入通过provide和inject选项实现。父组件通过provide提供数据,然后子组件通过inject注入这些数据。它在跨多个层级的组件通信中非常有用
mutation中的操作是一系列的同步函数,用于修改state中的变量的的状态。当使用vuex时需要通过commit来提交需要操作的内容。mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是实际进行状态更改的地方,并且它会接受 state 作为第一个参数:
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
increment (state) {
state.count++ // 变更状态
}
}
})
router是VueRouter的一个对象,通过Vue.use(VueRouter)和VueRouter构造函数得到一个router的实例对象,这个对象中是一个全局的对象,包含了所有的路由包含了许多关键的对象和属性。
route是一个跳转的路由对象,每一个路由都会有一个route对象,是一个局部的对象,可以获取对应的name,path,params,query
<!-- 父组件 -->
<template>
<div>
<slot name="header"></slot>
<slot :data="data"></slot>
</div>
</template>
<!-- 子组件 -->
<template>
<div>
<slot name="header">默认标题</slot>
<slot :data="computedData">{{ computedData }}</slot>
</div>
</template>
Vue.js的动画系统通过CSS过渡和动画类实现。通过在元素上添加过渡类或动画类,可以触发相应的过渡效果或动画效果。示例:
<transition name="fade">
<div v-if="show">显示内容</div>
</transition>
<!-- CSS样式 -->
<style>
.fade-enter-active, .fade-leave-active {
transition: opacity 0.5s;
}
.fade-enter, .fade-leave-to {
opacity: 0;
}
</style>
Vue.js提供了全局的错误处理机制和组件级别的错误处理机制。全局错误处理可以通过errorCaptured钩子函数捕获和处理错误。组件级别的错误处理可以通过errorCaptured钩子函数或errorHandler选项捕获和处理错误
Vue.js的响应式系统对于数组的变异方法(如push、pop、splice等)是无法追踪的。为了解决这个限制,Vue提供了一些特殊的方法,如Vue.set、vm.$set和Array.prototype.splice。这些方法可以用于更新数组并保持响应式
Composition API是Vue.js 3中引入的一种新的组织组件逻辑的方式。它允许开发者通过函数的方式组织和重用逻辑,而不是通过选项对象。相比之下,Options API是Vue.js 2中常用的组织组件逻辑的方式,通过选项对象中的属性来定义组件的数据、方法
Suspense是Vue.js 3中引入的一种机制,用于处理异步组件的加载状态。它可以在异步组件加载完成之前显示一个占位符,并在加载完成后渲染异步组件的内容。这样可以更好地处理异步组件的加载过程,提供更好的用户体验
provide和inject用于实现组件之间的依赖注入。通过在父组件中使用provide提供数据,然后在子组件中使用inject注入这些数据。示例:
// 父组件
const Parent = {
provide: {
message: 'Hello Spider!'
},
// ...
}
// 子组件
const Child = {
inject: ['message'],
created() {
console.log(this.message); // 输出:Hello Spider!
},
// ...
}
watchEffect用于监听响应式数据的变化,并在回调函数中执行相应的操作。它会自动追踪依赖,并在依赖变化时重新运行回调函数。watch用于监听指定的响应式数据,并在其变化时执行相应的操作。它可以精确地指定要监听的数据,并提供更多的配置选项。一般来说,如果只需要监听一个响应式数据的变化并执行相应操作,可以使用watchEffect;如果需要更细粒度的控制,可以使用watch
React是一个用于构建用户界面的JavaScript库。它的核心概念是组件化和声明式编程。React将用户界面拆分为独立的可重用组件,并使用声明式语法描述组件的状态和UI的关系,使得构建复杂的UI变得简单和可维护
React生命周期方法是在组件不同阶段执行的特定方法。以下是一些常用的React生命周期方法:
**
componentDidMount:组件挂载后立即调用
componentDidUpdate:组件更新后调用
componentWillUnmount:组件卸载前调用
shouldComponentUpdate:决定组件是否需要重新渲染
getDerivedStateFromProps:根据props的变化来更新状态**
React Context是一种用于在组件树中共享数据的机制。它可以避免通过props一层层传递数据,使得跨组件的数据共享变得更加简单和高效。React Context提供了一个Provider和Consumer组件,用于提供和消费共享的数据
React Router是React中用于处理路由的库。它提供了一种在单页面应用中实现导航和路由功能的方式。React Router可以帮助开发者实现页面之间的切换、URL参数的传递、嵌套路由等功能
React Hooks是React 16.8版本引入的一种特性,用于在函数组件中使用状态和其他React特性。Hooks提供了一种无需编写类组件的方式来管理状态和处理副作用,使得函数组件具有类组件的能力
好了,到这里又到了跟大家说再见的时候了。创作不易,帮忙点个赞再走吧。你的支持是我创作的动力,希望能带给大家更多优质的文章