博主经历过多轮面试,因此想将自己的面试经验以及答题技巧,分享给即将面试找前端工作的同学。
2022高频经典前端面试题分为上中下三篇,分别会有html,css,js,es6,vue,ts,nodejs,以及hr面和反问面试官几个维度去进行,完整的还原面试场景。有想取经的同学欢迎关注其他的两篇。
HTML篇
1. 讲讲 HTML 中的语义化标签
2.HTML 5 有哪些新标签?(重点)
3.Canvas 和 SVG 的区别是什么?
CSS篇
1. BFC 是什么(必问)
BFC会与float元素相互覆盖吗?
BFC的区域不会与float的元素区域重叠 计算BFC的高度时,浮动子元素也参与计算 BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面元素,反之亦然。
2. 如何实现垂直居中?(重点)
1.绝对定位,上左为50%,再让上左外边距为: -(实际宽高/2)
2.绝对定位,上下左右为0,margin为auto(记得后面这一句话很重要!)
在知道不知道宽高的情况下都行:
3.绝对定位平移法: position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
4.弹性盒子的属性:(在父元素设置)display: flex; justify-content: center; align-items: center;
5.css3新增属性: 给父元素设置display:table,子元素设置display:table-cell,再加上一个vertical-align:middle。
3.CSS 选择器优先级如何确定?
选择器越具体,优先级越高;相同优先级,后面的覆盖前面的;
属性!Important优先级最高,但是要少用。
优先级:
!important(权重:无限大) > 行内样式(权重:1000) > ID选择器(权重:100) > class选择器=伪类选择器(权重:10) > 标签名称选择器=伪元素(权重:1) > 通配符选择器(权重:0) > 继承(没有权值) > 浏览器默认属性
4.选择器有哪些?
5. 如何清除浮动?(必问)
方法一:给父级元素宽度和高度
方法二:给父元素加上 overflow:hidden。
方法三:给兄弟元素加一个clear:both
方法四:利用伪元素选择器::after去除浮动
.clearfix::after{
content: '';
display: block; /*或者 table*/
clear: both;
}
6.两种盒模型(box-sizing)的区别?
content-box;(默认值)为就是W3C的标准盒模型的计算方式 width=content
border-box; 为就是IE盒模型的计算方式。width=content+padding+border
相同点都是用来指定宽度的,不同点是border-box更加好用。
7.W3C标准是什么?
W3C标准不是一个标准,而是一系列标准的集合,包含三部分的标准:结构标准、表现标准和动作标准。与结构标准对应的代表语言是HTML,与表现标准对应的代表语言是CSS,与动作标准对应的代表语言是JavaScript。
8.CSS3的新属性有哪些?(重点)
border-radius、border-image、 box-shadow、
background-size:规定背景图片的尺寸
background-origin:规定背景图片的定位区域
background-clip:规定背景的绘制区域
文本效果(常用)
text-shadow:设置文字阴影
word-wrap:强制换行
word-break
css3提出@font-face规则,规则中定义了font-family、font-weight、font-style、
font-stretch、src、unicode-range
2/3D转换
transform:向元素应用2/3D转换
transition:过渡
动画
@keyframes规则: (有个面试官问过我这个的属性)
animation、animation-name、animation-duration(规定动画所要完成的时间)、animation-direction(是否轮流反向播放动画)、animation-delay(规定在动画开始之前的延迟)、animation-timing-function(规定动画的速度曲线)、animation-iteration-count(次数)等
用户界面(常用)
box-sizing、resize
css3新增伪类
ele:nth-child() 选取父元素的第 N 个子元素,不论元素的类型。
:nth-last-child()
:only-child
:last-child
ele:nth-of-type(n) 选取父元素的第 N 个类型为 ele 的子元素。
简单总结来说,nth-child(n) 可以理解为先无条件选择子元素,后选择对应序号的元素并判断类型是否符合
nth-of-type(n) 则是先根据类型选择子元素,然后直接选择对应序号的元素即可。
:only-of-type()
:empty
:target 这个伪类允许我们选择基于URL的元素,如果这个元素有一个识别器(比如跟着一个#),那么:target会对使用这个ID识别器的元素增加样式。
:enabled
:disabled
:checked
:not
9.flex布局你会用到里面哪些属性?
Flex-wrap 单行还是多行
Justify-content 决定了items在主轴上的对齐方式:flex-start,flex-end,center,space-between,space-around
Align-items决定了items在交叉轴上的对齐方式:
flex-start,flex-end,center,baseline,normal,stretch
Align-content决定了多行flex items在交叉轴上的对齐方式:用法和Justify-content类似
9. 怎样理解flex:1,以及它的三个属性分别代表什么意思?
flex 属性是 flex-grow、flex-shrink 和 flex-basis 属性的简写属性。
flex: flex-grow flex-shrink flex-basis|auto|initial|inherit;
默认值: 0 1 auto
10.怎样实现单行多行超出自动省略号呢?多行呢?
11.你对响应式设计的理解是什么,怎么实现?
理解:响应式网站设计(Responsive Web design)是一种网络页面设计布局,页面的设计与开发应当根据用户行为以及设备环境(系统平台、屏幕尺寸、屏幕定向等)进行相应的响应和调整。
实现方式:
响应式设计的基本原理是通过媒体查询检测不同的设备屏幕尺寸做处理,
实现响应式布局的方式有如下:
媒体查询
百分比
vw/vh
rem
12.隐藏元素的方式有哪些?
通过css实现隐藏元素方法有如下:
1.display:none(脱离普通流)
2.visibility:hidden(特点:元素不可见,占据页面空间,无法响应点击事件)
3.opacity:0(只是视觉上看不见)
4.设置height、width模型属性为0
5.position:absolute(将元素移出可视区域,元素不可见,不影响页面布局)
6.clip-path: polygon(0px 0px,0px 0px,0px 0px,0px 0px);(特点:元素不可见,占据页面空间,无法响应点击事件)
13. position有哪些属性?(必考)
Static:静态定位,默认值,元素出现在正常的流中;
Relative:相对定位,相对于其正常位置进行定位;
Absolute:绝对定位,相对于static定位以外的第一个父元素进行定位;
Fixed:固定定位,相对于浏览器窗口进行定位,脱离原来的文档流。
14.块级元素和行内元素分别有哪些?
行内元素和块级元素的区别:
行内元素:与其他行内元素并排,不能设置宽高,默认的宽度就是文字的宽度。
块级元素:霸占一行,不能与其他任何元素并列。
能接受宽高,如果不设置宽度,那么宽度将默认变为父级的100%。
行内元素:除了p之外,所有的文本级标签,都是行内元素。p是个文本级标签,但是是个块级元素。span , a , b , i , u , em
块级元素:所有的容器级标签,都是块级元素,以及p标签。div , h系列 , li , dt ,dd
-
标签定义了定义列表;
标签定义了定义列表中的项目(即术语部分);
- 标签描述列表中的项目,用于生成定义列表各列表项的说明文字段。
注意了: 是一个可替换元素。它的 display 属性的默认值是 inline,但是它的默认分辨率是由被嵌入的图片的原始宽高来确定的,使得它就像 inline-block 一样。你可以为 设置 border/border-radius、padding/margin、width、height 等等的 CSS 属性。
15. 回流与重绘(重点)
回流:
当渲染树中部分或全部元素的尺寸、结构、位置、属性发生变化时,浏览器会重新渲染部分或者全部文档的过程就称为回流。(重排)
下面这些操作会导致回流:
• 页面的首次渲染
• 浏览器的窗口大小发生变化
• 元素的内容发生变化
• 元素的尺寸或者位置发生变化
• 元素的字体大小发生变化
• 激活CSS伪类
• 查询某些属性或者调用某些方法
• 添加或者删除可见的DOM元素
重绘:
当页面元素样式改变不影响元素在文档流中的位置时(background-color,border-color,visibility),浏览器只会将新样式赋予元素并进行重新绘制操作。
下面这些操作会导致重绘:
• color、background 相关属性:background-color、background-image 等
• outline 相关属性:outline-color、outline-width 、text-decoration
• border-radius、visibility、box-shadow
注意: 当触发回流时,一定会触发重绘,但是重绘不一定会引发回流。
减少回流与重绘的措施:
CSS中避免回流、重绘
. 尽可能在DOM树的最末端改变class
. 避免设置多层内联样式
. 动画效果应用到position属性为absolute或fixed的元素上
. 避免使用table布局
. 使用css3硬件加速,可以让transform、opacity、filters等动画效果不会引起回流重绘
JS操作避免回流、重绘
. 避免使用JS一个样式修改完接着改下一个样式,最好一次性更改CSS样式,或者将样式列表定义为class的名称
. 避免频繁操作DOM,使用文档片段创建一个子树,然后再拷贝到文档中
. 先隐藏元素,进行修改后再显示该元素,因为display:none上的DOM操作不会引发回流和重绘
. 避免循环读取offsetLeft等属性,在循环之前把它们存起来
. 对于复杂动画效果,使用绝对定位让其脱离文档流,否则会引起父元素及后续元素大量的回流
Js篇
1. js数据类型有哪些?(必考)
string number boolean undefined null object symbol bigint
2.堆和栈的区别
基本数据类型指的是简单的数据段,引用数据类型指的是有多个值构成的对象。基本数据类型存在于栈,引用数据类型存在于堆里面。
• 栈:静态分配和动态分配,栈空间的内存由系统自动分配,一般存放局部变量等,不需要手动管理内存。不会产生碎片,空间连续。
• 堆:堆空间的内存是动态分配的,一般存放对象,并且需要手动释放内存。采用的是链表的存储方式,会产生碎片。
• 栈 Stack:包括所有的携带指针引用堆上对象的值类型(原始类型,例如整型和布尔),以及定义程序控制流的指针。
堆 Heap:用于保存引用类型(包括对象、字符串和闭包)的内存段
3.原型链是什么?(重点)
原型指的是原型属性,原型也是一个对象。
当访问一个对象的属性时,如果这个对象内部不存在这个属性,那么它就会去它的原型对象里找这个属性,这个原型对象又会有自己的原型,于是就这样一直找下去,也就是原型链的概念。
原型链的终点是 null ,因为 Object.prototype.__proto__指向 null
那为什么是null呢?
首先要明确一点,原型链上的所有节点都是对象,
另外,规范要求原型链必须是有限长度的
(从任一节点出发,经过有限步骤后必须到达一个终点。显然也不能有环。)
那么,应该用什么对象作为终点呢?很显然应该用一个特殊的对象。
我们假设以Object.prototype为终点的话,取它的原型Object.prototype.proto;
取一个对象的属性时,可能发生三种情况:
如果属性存在,那么返回属性的值。
如果属性不存在,那么返回undefined。
不管属性存在还是不存在,有可能抛异常。
我们已经假设Object.prototype是终点了,所以看起来不能是情况1。另外,抛出异常也不是好的设计,所以也不是情况3。那么情况2呢,它不存在原型属性,返回undefined怎么样?也不好,因为返回undefined一种解释是原型不存在,但是也相当于原型就是undefined。这样,在原型链上就会存在一个非对象的值。
所以,最佳选择就是null。一方面,你没法访问null的属性,所以起到了终止原型链的作用;另一方面,null在某种意义上也是一种对象,即空对象,因为null一开始就是为表示一个“空”的对象存在的。这样一来,就不会违反“原型链上只能有对象”的约定。
所以,“原型链的终点是null”虽然不是必须不可的,但是却是最合理的。
4.this的指向?(必问)
1,在全局范围内,this指向全局对象;
全局函数调用时,指向调用全局函数的对象。
2,当对象函数调用的时候,this指向当前对象;
3,构造函数的this,是指向New出来的实例化对象;
(总结:全局对象,全局函数;对象函数调用(当前对象),构造函数(实例化对象))
4,箭头函数没有单独的this值,this在箭头函数创建时确定,它与声明所在的上下文相同。
5,监听器中的this,指向事件源;
6,Apply,call,bind改变this的指向。
7,普通函数,this指向window
8.绑定事件函数,this指向的是函数的调用者,btn这个按钮对象
// btn.onclick = function(){};
9.定时器函数,this指向window
10.立即执行函数–是自动调用,this指向window
5.New做了什么?
- 创建临时对象;2.绑定原型;3.执行构造函数;4.返回临时对象;
(创建、绑定、执行、返回)
6.构造函数与普通函数有什么区别?
1.构造函数也是一个普通函数,创建方式和普通函数一样,但构造函数习惯上首字母大写。
构造函数和普通函数的区别在于:调用方式不一样。作用也不一样(构造函数用来新建实例对象)
a. 普通函数的调用方式:直接调用 person();
b.构造函数的调用方式:需要使用new关键字来调用 new Person();
构造函数的函数名与类名相同:Person( ) 这个构造函数,Person 既是函数名,也是这个对象的类名
内部用this 来构造属性和方法
//比如下面这个例子:
function Person(name,job,age)
{
this.name=name;
this.job=job;
this.age=age;
this.sayHi=function()
{
alert("Hi")
}
}
普通函数例子:因为没有返回值,所以为undefined
构造函数例子:构造函数会马上创建一个新对象,并将该新对象作为返回值返回
7. 普通函数和箭头函数的区别?
this的指向是不一样的,普通函数的this是指向window,箭头函数有点的就是指向点,没有的就是指向window。
8.Js数组的常用方法(重点)
Js数组的常用方法:https://blog.csdn.net/weixin_45822171/article/details/123773198?
原数组改变的有:push pop shift unshift reverse sort splice
不改变原数组的有:concat map filter join every some indexOf forEach slice
字符串转数组的方法是:split() Array.from()
数组转字符串的方法是:toString() join()
9.什么是立即执行函数?
10.闭包(重点)
闭包是js的一种语法特性。
闭包就是能够读取其他函数内部变量的函数
创建闭包的最常见的方式就是在一个函数内创建另一个函数,创建的函数可以访问到当前函数的局部变量。
主要答题满分点,把代码背下来讲给面试官听:
function outerFn(){
var data = 10
var innerFn = function(){
data += 1
console.log(data)
}
return innerFn
}
var result = outerFn()
result()
result()
// 11// 12
口述:声明一个变量,它等于立即执行函数,立即执行函数里面再声明一个变量,声明一个立即函数对该变量进行操作。
那么如何能访问或修改到一个函数内部的变量呢?
函数的return就是这个传送门,可以将一个内部函数送出外部函数。 即使无法直接访问到外部函数内部的变量,也可以通过return出的内部函数去访问或修改外部函数的变量。
闭包解决了什么问题:
(在什么场景下用到它呢,就是问它解决的什么问题)
1.不必为函数命名,避免污染全局变量;
2. 提供对局部变量的间接访问,按需求进行共享和长期保存;
3.维持变量,使其不被垃圾回收。
4.内部形成单独的块级作用域,通过闭包实现变量/方法的私有化
优点:简单好用;
缺点:闭包使用不当可能造成内存泄露;
闭包产生的内存泄露怎么办?
1,在退出函数之前,将不使用的局部变量赋值为null;
2,避免变量的循环赋值和引用。
3,利用Jquery释放自身指定的所有事件处理程序。
由于jQuery考虑到了内存泄漏的潜在危害,所以它会手动释放自己指定的所有事件处理程序。 只要坚持使用jQuery的事件绑定方法,就可以一定程度上避免这种特定的常见原因导致的内存泄漏。
11.何实现类?(重点:手打代码)
1.使用原型:把对象本身的属性写在构造函数里面,把它的共有属性写在原型上面;
2.使用class:把对象本身的属性写在constroctor里面,把公共属性写在constroctor外面。
12.如何实现继承?(重点:手打代码)
13.手写节流防抖(重点)
节流:
是指规定一个单位时间,在这个单位时间内,只能有一次触发事件的回调函数执行,如果在同一个单位时间内某事件被触发多次,只有一次能生效。
节流可以使用在 scroll 函数的事件监听上,通过事件节流来降低事件调用的频率。
节流函数的适⽤场景:
拖拽场景:固定时间内只执⾏⼀次,防⽌超⾼频次触发位置变动
缩放场景:监控浏览器resize
动画场景:避免短时间内多次触发动画引起性能问题
// 节流(一段时间执行一次之后,就不执行第二次)
function throttle(fn, delay){
let flag = true
return function(){
if(flag){
fn.apply(this, arguments)
flag = false
setTimeout(()=>flag = true, delay)
}
}
}
const throttled = throttle(()=>console.log('hi'))
throttled()
防抖:
是指在事件被触发 n 秒后再执行回调,如果在这 n 秒内事件又被触发,则重新计时。
防抖函数的应用场景:
按钮提交场景:防⽌多次提交按钮,只执⾏最后提交的⼀次。
服务端验证场景:表单验证需要服务端配合,只执⾏⼀段连续的输⼊事件的最后⼀次,还有搜索联想词功能类似⽣存环境请⽤lodash.debounce
// 防抖(一段时间会等,然后带着一起做了)
function debounce(fn, delay){
let timerId = null
return function(){
if(timerId){window.clearTimeout(timerId)}
timerId = setTimeout(()=>{
fn.apply(this, arguments)
timerId = null
},delay)
}
}
const debounced = debounce(()=>console.log('hi'))
debounced()
14.手写Ajax(常考)
Ajax的实现过程?(常考)
1.创建XMLHttpRequest对象,也就是创建一个异步调用对象;
2.创建一个新的http请求,并且指定http请求的方法,url及验证信息;
3.设置响应http请求状态变化的函数;
4.发送http请求;
(以上代码就讲了这四步)
5.获取异步调用返回的数据;
6.使用JavaScript和DOM实现局部刷新;
15.深拷贝和浅拷贝(重点)
浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。
但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。
深拷贝和浅拷贝是只针对Object和Array这样的引用数据类型的。
16.数组去重(笔试常考)
//计数排序的方法:(只支持字符串)
var a1=[1,2,2,3,3,3]
var uniq = function(a){
var map ={}
for(let i=0;i<a.length;i++){
let number = a[i];
console.log("number",number)
if(number === undefined){
continue
}
if(number in map){
continue
}
map[number] = true
}
return Object.keys(map)
}
uniq(a1)
17.为什么0.1+0.2 ! == 0.3,如何让其相等
计算机是通过二进制的方式存储数据的,所以计算机计算0.1+0.2的时候,实际上是计算的两个数的二进制的和。0.1的二进制是0.0001100110011001100…(1100循环),0.2的二进制是:0.00110011001100…(1100循环),这两个数的二进制都是无限循环的数。
toFixed(num) 方法可把 Number 四舍五入为指定小数位数的数字。那为什么会出现这样的结果呢?
(n1 + n2).toFixed(2) // 注意,toFixed为四舍五入
18.对作用域、作用域链的理解
(1)全局作用域
• 最外层函数和最外层函数外面定义的变量拥有全局作用域
• 所有未定义直接赋值的变量自动声明为全局作用域
• 所有window对象的属性拥有全局作用域
• 全局作用域有很大的弊端,过多的全局作用域变量会污染全局命名空间,容易引起命名冲突。
(2)函数作用域
• 函数作用域声明在函数内部的变量,一般只有固定的代码片段可以访问到
• 作用域是分层的,内层作用域可以访问外层作用域,反之不行
(3)块级作用域
• 使用ES6中新增的let和const指令可以声明块级作用域,块级作用域可以在函数中创建也可以在一个代码块中的创建(由{ }包裹的代码片段)
• let和const声明的变量不会有变量提升,也不可以重复声明
• 在循环中比较适合绑定块级作用域,这样就可以把声明的计数器变量限制在循环内部。
(4)作用域链: 在当前作用域中查找所需变量,但是该作用域没有这个变量,那这个变量就是自由变量。如果在自己作用域找不到该变量就去父级作用域查找,依次向上级作用域查找,直到访问到window对象就被终止,这一层层的关系就是作用域链。
作用域链的作用是保证对执行环境有权访问的所有变量和函数的有序访问,通过作用域链,可以访问到外层环境的变量和函数。
19.数据类型检测的方式有哪些(常考)
(1)typeof
其中数组、对象、null都会被判断为object,其他判断都正确。
(2)Instanceof
instanceof可以正确判断对象的类型,其内部运行机制是判断在其原型链中能否找到该类型的原型。
但是instanceof只能正确判断引用数据类型,而不能判断基本数据类型。instanceof 运算符可以用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。
(3)Constructor
constructor有两个作用,一是判断数据的类型,二是对象实例通过 constrcutor 对象访问它的构造函数。
需要注意,如果创建一个对象来改变它的原型,constructor就不能用来判断数据类型了。
(4)Object.prototype.toString.call()
Object.prototype.toString.call() 使用 Object 对象的原型方法 toString 来判断数据类型。
20. 判断数组的方式有哪些
• 通过Object.prototype.toString.call()做判断
Object.prototype.toString.call(obj).slice(8,-1) === ‘Array’;
slice() 方法以新的数组对象,返回数组中被选中的元素。
slice() 方法选择从给定的 start 参数开始的元素,并在给定的 end 参数处结束,但不包括。
注释:slice() 方法不会改变原始数组
• 通过原型链做判断
obj.proto === Array.prototype;
• 通过ES6的Array.isArray()做判断
Array.isArrray(obj);
• 通过instanceof做判断
obj instanceof Array
• 通过Array.prototype.isPrototypeOf
Array.prototype.isPrototypeOf(obj)
21.事件冒泡
即事件开始时由最具体的元素接收,然后逐级向上传播到较为不具体的节点。
好比气泡从水底下一直向上冒泡,像dom树一样,一直到根元素。
如何阻止事件冒泡:
普通浏览器使用:event.stopPropagation() event.preventDefault()
IE浏览器使用:event.cancelBubble = true; eventreturnValue = false;
22.事件捕获
即从不具体的元素到具体的元素。
便是在某个地方把它抓住,不让他执行下去了,事件捕获是从外向内开始捕获。
23.事件委托、事件代理
事件委托也称之为事件代理(Event Delegation)。
即是把原本需要绑定在子元素的响应事件委托给父元素,让父元素担当事件监听的职务。
就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。
场景:
li标签的数量很大时,循环为每个子元素添加事件,绝非好方法。有一种优雅的方法,就是事件委托。
使用事件委托只为ul元素添加一个onclick事件处理程序。因为有事件冒泡机制,单击每个li标签时,都会被这个函数处理。
24.call() 和 apply() 的区别?
相同点:作用相同
不同的:传入参数的形式的不同。
• apply 接受两个参数,第一个参数指定了函数体内 this 对象的指向,第二个参数为一个带下标的集合,这个集合可以为数组,也可以为类数组,apply 方法把这个集合中的元素作为参数传递给被调用的函数。
• call 传入的参数数量不固定,跟 apply 相同的是,第一个参数也是代表函数体内的 this 指向,从第二个参数开始往后,每个参数被依次传入函数。
• bind() 它的参数和call()相同。它和前两者不同在于: bind() 方法会返回执行上下文被改变的函数而不会立即执行,而前两者是直接执行该函数。
25.JS中页面传递参数的方法
在JS中有多种页面传递参数的方法:
一、URL 传参
把参数值附在url后面传递到其他页面
二、H5 web storage
localStroage 和 sessionStorage
三、Cookie
使用浏览器Cookie传递参数
四、Form 表单
Form表单通过URL传递参数
26.mvvm和mvc的区别?(会考)
1.MVC:Model(模型)+View(视图)+controller(控制器),
View通过Controller来和Model联系,Controller是View和Model的协调者,View和Model不直接联系,基本联系都是单向的。
用户User通过控制器Controller来操作模板Model从而达到视图View的变化。
2. MVVM:Model+View+ViewModel。
在MVVM架构下,View 和 Model 之间并没有直接的联系,ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来;View的变化会自动更新到ViewModel,ViewModel的变化也会自动同步到View上显示。
因此开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。