前端面试题(Vue篇)

发布时间 2024-01-11 08:56:09作者: 谁说程序猿很猥琐

每个面试都需要做充分的准备,面试建议从以下几个方面准备:

1、技术,这个是硬性要求。如果技术栈 主要是react,可以重点准备react,如果是vue,重点准备vue,当然 js、css等前端的基础 是最基本的东西。除此之外,要做一定的深度拓展,比如了解其实现原理。

2、沟通,要准备 自己所做过项目的的 项目背景、自己负责的模块、遇到的难题、自己解决了哪些问题。在沟通时 最好 1,2,3,4,。。这样逻辑清晰的表述【这点非常重要】

3、 自己的学习能力,技术的迭代很快,作为一名技术同学,对技术的追求必不可少。面试中最好体现自己有一定的学习能力。

--------------------------------------------------------------------------------------------------------------------------------------------------

1、项目介绍:项目陈述,挑一个重点项目,了解项目团队组成,人数,个人在这个项目中承担的责任,收获以及解决了哪些难题

2、平时如何学习前端技术的,重点考察学习能力

3、对react 和 vue 的理解

4、JavaScript、HTML5、CSS3、NodeJs

技术篇:

基础:

css:

什么是盒模型?它有哪些部分组成?

答:盒模型是指在网页布局过程中,每个元素都被描绘成一个矩形框,这个矩形框由内容区、内边距、边框和外边距组成。

请解释CSS的层叠顺序(Specificity)是什么,如何计算它?

答:层叠顺序是指在样式冲突时,浏览器根据选择器的特异度(Specificity)来确定应用哪个样式。特异度由选择器中的ID、类、标签等因素决定,一般以四个值的形式表示,越具体的选择器特异度越高。可以使用公式计算:[inline styles] > [IDs] > [classes, pseudo-classes, attributes] > [elements, pseudo-elements]。
介绍一下Flexbox和Grid布局,它们有什么区别?

答:Flexbox是一种一维布局系统,主要用于排列元素,适用于需要灵活调整元素位置和尺寸的情况;而Grid布局是一种二维布局系统,适用于将页面划分为行和列进行布局。
什么是响应式设计?如何通过CSS实现响应式布局?

答:响应式设计是指根据用户设备的不同尺寸和屏幕分辨率,使网站能够自动调整布局以适应不同的显示环境。通过使用媒体查询(@media)和相对单位(如百分比、em等),可以实现响应式布局。
如何垂直居中一个元素?

答:可以使用flex布局或者绝对定位的方式来实现垂直居中,也可以使用表格布局或者CSS3的transform属性。
请解释一下CSS中的伪类和伪元素的区别?

答:伪类是用于向某些选择器添加特殊的效果,比如:hover、:active等,而伪元素则是创建一些不在文档树中的元素,比如::before、::after等。
什么是BFC(块级格式化上下文)?它有什么作用?

答:BFC是块级格式化上下文的缩写,它是页面上的一个独立容器,容器内部的元素不会影响到外部元素,可以避免外边距重叠等问题。
请描述一下CSS中的选择器优先级是如何计算的?

答:选择器优先级是通过计算选择器中ID选择器、类选择器、元素选择器和内联样式的数量来确定的,一般以四个值的形式表示。
介绍一下CSS中的动画和过渡的区别,以及它们的应用场景。

答:过渡是元素从一种状态变换到另一种状态时的平滑过渡效果,而动画则是元素具有连续的动作效果。通常过渡用于简单的交互效果,而动画适用于更复杂的动态效果。
什么是响应式图片?你会如何优化网站中的图片加载速度?

答:响应式图片是能够根据不同设备和屏幕尺寸自动调整大小的图片。优化图片加载速度的方法包括压缩图片、使用合适的图片格式、懒加载以及使用CDN等。
请解释一下CSS中的“box-sizing”属性的作用?

答:box-sizing属性用于指定元素的盒模型是标准盒模型还是IE盒模型,默认值为content-box,可以设置为border-box以方便计算元素的尺寸。
如何实现一个简单的CSS网格系统?

答:可以使用flexbox布局或者CSS Grid布局来实现简单的网格系统,也可以借助float和clear属性来实现。
什么是CSS预处理器?请举例说明它的优点和常用的预处理器有哪些?

答:CSS预处理器是一种将类似于编程语言的结构引入CSS中的工具,比如Sass、Less等,可以让开发者编写更加简洁、易于维护的CSS代码。
什么是CSS Sprites?它们有什么优点和缺点?

答:CSS Sprites是一种将网页中多个图片合并成一张图片,并通过background-position来显示不同部分的技术,可以减少HTTP请求,但维护成本较高。
如何实现一个元素的圆角边框?

答:可以使用border-radius属性来设置元素的圆角边框,也可以利用图片或者伪元素来实现。
请解释一下CSS中的“display: none”与“visibility: hidden”的区别?

答:display: none会使元素完全从页面中移除,占用的空间也会消失,而visibility: hidden则只是将元素隐藏,但保留其占用的空间。
什么是响应式字体?如何实现在不同设备上的字体大小适配?

答:响应式字体是指能够根据设备不同的尺寸和分辨率自动调整大小的字体。可以使用相对单位(如em、rem)或者媒体查询来实现字体大小的适配。
介绍一下CSS中的字体排版相关的属性,比如“line-height”、“letter-spacing”等。

答:line-height用于设置行高,letter-spacing用于设置字符之间的间距,还有text-align、text-transform等属性用于控制文本的对齐和大小写转换。
请描述一下“CSS reset”和“normalize.css”的作用和区别?

答:CSS reset用于重置浏览器默认样式,而normalize.css则是在保留有用的默认样式的基础上,校正浏览器样式的不一致性。
如何实现一个简单的CSS动态效果,比如鼠标悬停时的元素变化?

答:可以使用:hover伪类来实现鼠标悬停时的元素变化,也可以使用transition或者动画来实现更复杂的动态效果。

 

JavaScript:

1. JavaScript 中有哪些不同的数据类型? 

JavaScript 中的数据类型包括字符串、数字、布尔值、对象、未定义和空值。

JavaScript有六种数据类型:Number、String、Boolean、Symbol、Object+和+Undefined

2、null和undefined有什么区别? 

null 表示有意不存在任何对象值,而 undefined 表示不存在值或未初始化的变量。

3. JavaScript 中的 bind() 方法的用途是什么?

 bind() 方法创建一个新函数,在调用时具有指定的 this 值和传递给它的参数

4 在 JavaScript 中循环遍历数组有哪些不同的方法?

 你可以使用 for 循环、forEach()、map()、filter()、reduce() 和其他数组方法遍历数组

5. JavaScript 中 JSON.parse() 方法的用途是什么? 

JSON.parse() 方法用于解析 JSON 字符串并将其转换为 JavaScript 对象。

6.你如何处理 JavaScript 中的异步编程?

JavaScript 中的异步编程可以使用回调、承诺或异步/等待语法来处理,允许非阻塞地执行代码和处理异步任务。

1. JavaScript 中的Hoisting是什么?

Hoisting是 JavaScript 中的一种行为,其中变量和函数声明被移动到其作用域的顶部。这意味着可以在代码中声明变量和函数之前使用它们。但是,只会声明,不会赋值。

console.log(x); //undefined

var x = 5;

在这个例子中,变量 x 被提升到范围的顶部,但它的赋值 5 没有,所以当我们尝试记录 x 的值时,它返回 undefined。

2. JavaScript 中的闭包是什么?

闭包是一个函数,即使在外部函数返回之后,它也可以访问其外部范围内的变量。

function outerFunction(x) {

return function innerFunction() {

return x;

}

}

const myClosure = outerFunction(10);

console.log(myClosure()); //10

在此示例中,内部函数 innerFunction 可以从其外部范围访问变量 x,因此,即使在 outerFunction 返回后它也可以返回其值。

3. 讲解JavaScript中的事件冒泡和捕获

事件冒泡和捕获是在 DOM 中传播事件的两种方式。

事件冒泡是指事件首先被最内层元素捕获和处理,然后传播到外层元素。

事件捕获则相反,事件首先由最外层元素处理,然后传播到内部元素。

<div onclick="alert('div')">

<p onclick="alert('p')">

Click me!

</p>

</div>

在这个例子中,如果 p 元素被点击,事件将首先被 p 元素捕获并调用 alert('p') 函数。

然后,事件将传播到 div 元素并调用 alert('div') 函数。这是事件冒泡的一个例子。

如果我们在 addEventListener 中使用 useCapture 参数并将其设置为 true,则事件将首先被 div 元素捕获,然后传播到 p 元素。这是一个事件捕获的例子。

4. 用 JavaScript 解释“this”

在 JavaScript 中,this 指的是函数是其方法的对象。

const person = {

name: "John",

sayName: function() {

console.log(this.name);

}

}

person.sayName(); // "John"

在此示例中,this 指的是 person 对象,因此调用 this.name 会返回“John”。this 的值可以根据函数的调用方式而改变。

6. 解释 setTimeout 在 JavaScript 中的工作原理

setTimeout 是一个允许您在经过一定时间后执行函数的函数。

console.log("Started!");

setTimeout(() => {

console.log("Hello!");

}, 2000);

console.log("Ended!");

在此示例中,console.log("Started!") 被立即调用,然后 setTimeout 被调用,回调函数记录“Hello!” 和 2000 毫秒的时间。之后立即调用 console.log("Ended!") 。传递给 setTimeout 的回调函数将在 2 秒后调用。

7. 解释 setInterval 在 JavaScript 中的工作原理

setInterval 与setTimeout 类似,但它会以指定的时间间隔重复执行提供的函数。

let count = 0;

const intervalId = setInterval(() => {

console.log(`Interval count: ${count}`);

count++;

if (count === 5) {

clearInterval(intervalId);

}

}, 1000);

在此示例中,提供的函数将每 1000 毫秒(1 秒)执行一次,每次计数都会增加 1。clearInterval 函数用于在 5 次迭代后停止间隔。

8. 解释什么是 JavaScript 中的 promise

Promise 是一个对象,表示异步操作的最终完成(或失败)及其结果值。

const promise = new Promise((resolve, reject) => {

setTimeout(() => {

resolve("Success!");

}, 2000);

});

promise

.then(result => console.log(result))

.catch(error => console.log(error));

在此示例中,使用 setTimeout 函数创建了一个 promise,该函数在 2 秒后调用 resolve 函数。promise 有两个方法,then 和 catch,可用于处理已解析的值或发生的任何错误。

9.解释JavaScript中==和===的区别

==(松散相等)在执行任何必要的类型转换后比较两个值是否相等。===(严格相等)在不执行任何类型转换的情况下比较两个值是否相等。

console.log(0 == false); // true

console.log(0 === false); // false

在此示例中,0 和 false 大致相等,因为它们都是假值,但它们并不严格相等,因为 0 是数字而 false 是布尔值。

通常建议在 JavaScript 中使用 === 进行比较,因为它可以帮助防止意外的类型强制转换。

10.解释JavaScript中let、var、const的区别

let 和 var 用于在 JavaScript 中声明变量,但它们的行为略有不同。let 变量是块作用域的,这意味着它们只能在声明它们的块内访问。

var 变量是函数作用域的,这意味着它们可以在它们声明的整个函数内访问。

if (true) {

let x = 5;

}

console.log(x); // ReferenceError: x is not definedCopy code

if (true) {

var x = 5;

}

console.log(x); // 5

const 用于声明一个常量变量,这意味着它的值在声明后不能重新赋值。

const x = 5;

x = 10; // TypeError: Assignment to constant variable

一般来说,最佳实践是默认使用 const,并且仅在需要重新分配变量时才使用 let。

技术站:VUE

1、谈谈你对Vue的理解

简单来说,vue就是一个用于创建用户界面的渐进式的Javascript框架。

它有3个优点:

第一个是采用组件化模式,把html、css、js等组合封装成一个vue组件,这个vue组件是可以重复使用的,这样的话就大大提高了代码的利用率,以及代码维护起来会更加方便。

第二个是声明式编码,程序员可以直接在页面上用vue指令循环遍历数据源,不用手动操作DOM节点,提高软件开发效率。

第三个是采用虚拟DOM和利用Diff算法,把后台的数据传到虚拟DOM中,利用Diff算法比较前后数据更新的变化,这样就可以尽量地复用DOM节点,优化性能。

2、你能讲一讲MVVM吗?

MVVM是Model-View-ViewModel缩写,也就是把MVC中的Controller演变成ViewModel。Model层代表数据模型,View代表UI组件,ViewModel是View和Model层的桥梁,数据会绑定到viewModel层并自动将数据渲染到页面中,视图变化的时候会通知viewModel层更新数据。

3.说一下Vue的生命周期

beforeCreate是new Vue()之后触发的第一个钩子,在当前阶段data、methods、computed以及watch上的数据和方法都不能被访问。
created在实例创建完成后发生,当前阶段已经完成了数据观测,也就是可以使用数据,更改数据,在这里更改数据不会触发updated函数。可以做一些初始数据的获取,在当前阶段无法与Dom进行交互,如果非要想,可以通过vm.$nextTick来访问Dom。
beforeMount发生在挂载之前,在这之前template模板已导入渲染函数编译。而当前阶段虚拟Dom已经创建完成,即将开始渲染。在此时也可以对数据进行更改,不会触发updated。
mounted在挂载完成后发生,在当前阶段,真实的Dom挂载完毕,数据完成双向绑定,可以访问到Dom节点,使用$refs属性对Dom进行操作。
beforeUpdate发生在更新之前,也就是响应式数据发生更新,虚拟dom重新渲染之前被触发,你可以在当前阶段进行更改数据,不会造成重渲染。
updated发生在更新完成之后,当前阶段组件Dom已完成更新。要注意的是避免在此期间更改数据,因为这可能会导致无限循环的更新。
beforeDestroy发生在实例销毁之前,在当前阶段实例完全可以被使用,我们可以在这时进行善后收尾工作,比如清除计时器。
destroyed发生在实例销毁之后,这个时候只剩下了dom空壳。组件已被拆解,数据绑定被卸除,监听被移出,子实例也统统被销毁。

4.你的接口请求一般放在哪个生命周期中?

接口请求一般放在mounted中,但需要注意的是服务端渲染时不支持mounted,需要放到created中

5.再说一下Computed和Watch

Computed本质是一个具备缓存的watcher,依赖的属性发生变化就会更新视图。
适用于计算比较消耗性能的计算场景。当表达式过于复杂时,在模板中放入过多逻辑会让模板难以维护,可以将复杂的逻辑放入计算属性中处理。
Watch没有缓存性,更多的是观察的作用,可以监听某些数据执行回调。当我们需要深度监听对象中的属性时,可以打开deep:true选项,这样便会对对象中的每一项进行监听。这样会带来性能问题,优化的话可以使用字符串形式监听,如果没有写到组件中,不要忘记使用unWatch手动注销哦。

6、说一下computed和methods的区别

computed和methods的区别主要有两个:

第一个是属性、方法调用。computed是属性调用,在定义函数时以属性的形式调用,methods是方法调用,在定义函数时以方法的形式调用,要加()

第二个是缓存功能,computed是计算属性,是有缓存的,当它的依赖属性改变的时候,才会进行重新计算,如果数据没有改变,它是不会运行的。而methods是方法,没有缓存功能,只要你调用一次,不管数据是否改变,它都是执行。

所以,性能方面的比较的话,computed是比methods的性能会好一点,去掉那些无谓的操作。

7.说一下v-if和v-show的区别

当条件不成立时,v-if不会渲染DOM元素,v-show操作的是样式(display),切换当前DOM的显示和隐藏。

8.Vue模版编译原理知道吗,能简单说一下吗?

简单说,Vue的编译过程就是将template转化为render函数的过程。会经历以下阶段:
生成AST树
优化
codegen
首先解析模版,生成AST语法树(一种用JavaScript对象的形式来描述整个模板)。
使用大量的正则表达式对模板进行解析,遇到标签、文本的时候都会执行对应的钩子进行相关处理。
Vue的数据是响应式的,但其实模板中并不是所有的数据都是响应式的。有一些数据首次渲染后就不会再变化,对应的DOM也不会变化。那么优化过程就是深度遍历AST树,按照相关条件对树节点进行标记。这些被标记的节点(静态节点)我们就可以跳过对它们的比对,对运行时的模板起到很大的优化作用。
编译的最后一步是将优化后的AST树转换为可执行的代码。

9.Vue2.x和Vue3.x渲染器的diff算法分别说一下

同级比较,再比较子节点
先判断一方有子节点一方没有子节点的情况(如果新的children没有子节点,将旧的子节点移除)
比较都有子节点的情况(核心diff)
递归比较子节点
正常Diff两个树的时间复杂度是O(n^3),但实际情况下我们很少会进行跨层级的移动DOM,所以Vue将Diff进行了优化,从O(n^3) -> O(n),只有当新旧children都为多个子节点时才需要用核心的Diff算法进行同层级比较。
Vue2的核心Diff算法采用了双端比较的算法,同时从新旧children的两端开始进行比较,借助key值找到可复用的节点,再进行相关操作。相比React的Diff算法,同样情况下可以减少移动节点次数,减少不必要的性能损耗,更加的优雅。
Vue3.x借鉴了
ivi算法和 inferno算法
在创建VNode时就确定其类型,以及在 mount/patch 的过程中采用位运算来判断一个VNode的类型,在这个基础之上再配合核心的Diff算法,使得性能上较Vue2.x有了提升。(实际的实现可以结合Vue3.x源码看。)
该算法中还运用了动态规划的思想求解最长递归子序列。

10.再说一下虚拟Dom以及key属性的作用

由于在浏览器中操作DOM是很昂贵的。频繁的操作DOM,会产生一定的性能问题。这就是虚拟Dom的产生原因。
Vue2的Virtual DOM借鉴了开源库snabbdom的实现。
Virtual DOM本质就是用一个原生的JS对象去描述一个DOM节点。是对真实DOM的一层抽象。(也就是源码中的VNode类,它定义在src/core/vdom/vnode.js中。)
VirtualDOM映射到真实DOM要经历VNode的create、diff、patch等阶段。
key的作用是尽可能的复用 DOM 元素。
新旧 children 中的节点只有顺序是不同的时候,最佳的操作应该是通过移动元素的位置来达到更新的目的。
需要在新旧 children 的节点中保存映射关系,以便能够在旧 children 的节点中找到可复用的节点。key也就是children中节点的唯一标识。

10.Vue2.x组件通信有哪些方式?

父子组件通信

父->子props,子->父 $on、$emit
获取父子组件实例 $parent、$children
Ref 获取实例的方式调用组件的属性或者方法
Provide、inject 官方不推荐使用,但是写组件库时很常用
兄弟组件通信
Event Bus 实现跨组件通信 Vue.prototype.$bus = new Vue
Vuex
跨级组件通信
Vuex
$attrs、$listeners
Provide、inject

11.v-model是如何实现双向绑定的?

v-model是用来在表单控件或者组件上创建双向绑定的

他的本质是v-bind和v-on的语法糖

在一个组件上使用v-model,默认会为组件绑定名为value的prop和名为input的事件

12.怎样理解 Vue 的单向数据流?

所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。

额外的,每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。子组件想修改时,只能通过 $emit 派发一个自定义事件,父组件接收到后,由父组件修改。

有两种常见的试图改变一个 prop 的情形 :

这个 prop 用来传递一个初始值;这个子组件接下来希望将其作为一个本地的 prop 数据来使用。 在这种情况下,最好定义一个本地的 data 属性并将这个 prop 用作其初始值:

 props: ['initialCounter'],data: function () {   return {     counter: this.initialCounter    }  }
 

这个 prop 以一种原始的值传入且需要进行转换。 在这种情况下,最好使用这个 prop 的值来定义一个计算属性

 props: ['size'],computed: {   normalizedSize: function () {     return this.size.trim().toLowerCase()    }  }
 

13.hash路由和history路由实现原理说一下

location.hash的值实际就是URL中#后面的东西。

history实际采用了HTML5中提供的API来实现,主要有history.pushState()和history.replaceState()。

14、VUE2.0与 3.0区别

15-  keep-alive 的作用