2022 秋招前端面试题(十)(附答案)
扩展运算符的作用及使用场景
(1)对象扩展运算符
对象的扩展运算符(...)用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中。
上述方法实际上等价于:
Object.assign
方法用于对象的合并,将源对象(source)
的所有可枚举属性,复制到目标对象(target)
。Object.assign
方法的第一个参数是目标对象,后面的参数都是源对象。(如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性)。
同样,如果用户自定义的属性,放在扩展运算符后面,则扩展运算符内部的同名属性会被覆盖掉。
利用上述特性就可以很方便的修改对象的部分属性。在redux
中的reducer
函数规定必须是一个纯函数,reducer
中的state
对象要求不能直接修改,可以通过扩展运算符把修改路径的对象都复制一遍,然后产生一个新的对象返回。
需要注意:扩展运算符对对象实例的拷贝属于浅拷贝。
(2)数组扩展运算符
数组的扩展运算符可以将一个数组转为用逗号分隔的参数序列,且每次只能展开一层数组。
下面是数组的扩展运算符的应用:
将数组转换为参数序列
复制数组
要记住:扩展运算符(…)用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中,这里参数对象是个数组,数组里面的所有对象都是基础数据类型,将所有基础数据类型重新拷贝到新的数组中。
合并数组
如果想在数组内合并数组,可以这样:
扩展运算符与解构赋值结合起来,用于生成数组
需要注意:如果将扩展运算符用于数组赋值,只能放在参数的最后一位,否则会报错。
将字符串转为真正的数组
任何 Iterator 接口的对象,都可以用扩展运算符转为真正的数组
比较常见的应用是可以将某些数据结构转为数组:
用于替换es5
中的Array.prototype.slice.call(arguments)
写法。
使用
Math
函数获取数组中特定的值
陈述输入 URL 回车后的过程
vue-router
说一下常见的 git 操作
JS 闭包,你了解多少?
应该有面试官问过你:
什么是闭包?
闭包有哪些实际运用场景?
闭包是如何产生的?
闭包产生的变量如何被回收?
这些问题其实都可以被看作是同一个问题,那就是面试官在问你:你对JS闭包了解多少?
来总结一下我听到过的答案,尽量完全复原候选人面试的时候说的原话。
答案1:
就是一个function
里面return
了一个子函数,子函数访问了外面那个函数的变量。
答案2:
for 循环里面可以用闭包来解决问题。
答案3:
当前作用域产产生了对父作用域的引用。
答案4:
不知道。是跟浏览器的垃圾回收机制有关吗?
开杠了。请问,小伙伴的答案和以上的内容有多少相似程度?
其实,拿着这些问题好好想想,你就会发现这些问题都只是为了最终那一个问题。
闭包的底层实现原理
1. JS执行上下文
我们都知道,我们手写的 js 代码是要经过浏览器 V8 进行预编译后才能真正的被执行。例如变量提升、函数提升。举个栗子。
那么问题来了。 请问是谁来执行预编译操作的?那这个谁又是在哪里进行预编译的?
是的,你的疑惑没有错。js 代码运行需要一个运行环境,那这个环境就是执行上下文。 是的,js 运行前的预编译也是在这个环境中进行。
js 执行上下文分三种:
全局执行上下文
: 代码开始执行时首先进入的环境。函数执行上下文
:函数调用时,会开始执行函数中的代码。eval执行上下文
:不建议使用,可忽略。
那么,执行上下文的周期,分为两个阶段:
创建阶段
创建词法环境
生成变量对象(
VO
),建立作用域链、作用域链、作用域链(重要的事说三遍)确认
this
指向,并绑定this
执行阶段
。这个阶段进行变量赋值,函数引用及执行代码。
你现在猜猜看,预编译是发生在什么时候?
噢,我忘记说了,其实与编译还有另一个称呼:执行期上下文
。
预编译发生在函数执行之前。预编译四部曲为:
创建
AO
对象找形参和变量声明,将变量和形参作为 AO 属性名,值为
undefined
将实参和形参相统一
在函数体里找到函数声明,值赋予函数体。最后程序输出变量值的时候,就是从
AO
对象中拿。
所以,预编译真正的结果是:
我们重新来。
1. 什么叫变量对象?
变量对象是 js
代码在进入执行上下文时,js
引擎在内存中建立的一个对象,用来存放当前执行环境中的变量。
2. 变量对象(VO)的创建过程
变量对象的创建,是在执行上下文创建阶段,依次经过以下三个过程:
创建
arguments
对象。对于函数执行环境,首先查询是否有传入的实参,如果有,则会将参数名是实参值组成的键值对放入
arguments
对象中。否则,将参数名和undefined
组成的键值对放入arguments
对象中。
当遇到同名的函数时,后面的会覆盖前面的。
检查当前环境中的变量声明并赋值为
undefined
。当遇到同名的函数声明,为了避免函数被赋值为undefined
,会忽略此声明
根据以上三个步骤,对于变量提升也就知道是怎么回事了。
3. 变量对象变为活动对象
执行上下文的第二个阶段,称为执行阶段,在此时,会进行变量赋值,函数引用并执行其他代码,此时,变量对象变为活动对象。
我们还是举上面的例子:
在上面的代码中,代码真正开始执行是从第一行 console.log() 开始的,自这之前,执行上下文是这样的:
词法作用域(Lexical scope
)
这里想说明,我们在函数执行上下文中有变量,在全局执行上下文中有变量。JavaScript
的一个复杂之处在于它如何查找变量,如果在函数执行上下文中找不到变量,它将在调用上下文中寻找它,如果在它的调用上下文中没有找到,就一直往上一级,直到它在全局执行上下文中查找为止。(如果最后找不到,它就是 undefined
)。
再来举个栗子:
分析过程如下:
在全局上下文中声明变量
top
并赋值为 0.2 - 8 行。在全局执行上下文中声明了一个名为
createWarp
的变量,并为其分配了一个函数定义。其中第 3-7 行描述了其函数定义,并将函数定义存储到那个变量(createWarp
)中。第 9 行。我们在全局执行上下文中声明了一个名为
sum
的新变量,暂时,值为undefined
。第 9 行。遇到
()
,表明需要执行或调用一个函数。那么查找全局执行上下文的内存并查找名为createWarp
的变量。 明显,已经在步骤 2 中创建完毕。接着,调用它。调用函数时,回到第 2 行。创建一个新的
createWarp
执行上下文。我们可以在createWarp
的执行上下文中创建自有变量。js
引擎createWarp
的上下文添加到调用堆栈(call stack
)。因为这个函数没有参数,直接跳到它的主体部分.3 - 6 行。我们有一个新的函数声明,在
createWarp
执行上下文中创建一个变量add
。add
只存在于createWarp
执行上下文中, 其函数定义存储在名为add
的自有变量中。第 7 行,我们返回变量
add
的内容。js 引擎查找一个名为add
的变量并找到它. 第 4 行和第 5 行括号之间的内容构成该函数定义。createWarp
调用完毕,createWarp
执行上下文将被销毁。add 变量也跟着被销毁。 但add
函数定义仍然存在,因为它返回并赋值给了sum
变量。 (ps:这才是闭包产生的变量存于内存当中的真相
)接下来就是简单的执行过程,不再赘述。。
……
代码执行完毕,全局执行上下文被销毁。sum 和 result 也跟着被销毁。
小结一下
现在,如果再让你回答什么是闭包,你能答出多少?
其实,大家说的都对。不管是函数返回一个函数,还是产生了外部作用域的引用,都是有道理的。
所以,什么是闭包?
解释一下作用域链是如何产生的。
解释一下 js 执行上下文的创建、执行过程。
解释一下闭包所产生的变量放在哪了。
最后请把以上 3 点结合起来说给面试官听。
说一下怎么把类数组转换为数组?
ES6 新特性
HTML5 有哪些更新
1. 语义化标签
header:定义文档的页眉(头部);
nav:定义导航链接的部分;
footer:定义文档或节的页脚(底部);
article:定义文章内容;
section:定义文档中的节(section、区段);
aside:定义其所处内容之外的内容(侧边);
2. 媒体标签
(1) audio:音频
属性:
controls 控制面板
autoplay 自动播放
loop=‘true’ 循环播放
(2)video 视频
属性:
poster:指定视频还没有完全下载完毕,或者用户还没有点击播放前显示的封面。默认显示当前视频文件的第一针画面,当然通过 poster 也可以自己指定。
controls 控制面板
width
height
(3)source 标签因为浏览器对视频格式支持程度不一样,为了能够兼容不同的浏览器,可以通过 source 来指定视频源。
3. 表单
表单类型:
email :能够验证当前输入的邮箱地址是否合法
url : 验证 URL
number : 只能输入数字,其他输入不了,而且自带上下增大减小箭头,max 属性可以设置为最大值,min 可以设置为最小值,value 为默认值。
search : 输入框后面会给提供一个小叉,可以删除输入的内容,更加人性化。
range : 可以提供给一个范围,其中可以设置 max 和 min 以及 value,其中 value 属性可以设置为默认值
color : 提供了一个颜色拾取器
time : 时分秒
data : 日期选择年月日
datatime : 时间和日期(目前只有 Safari 支持)
datatime-local :日期时间控件
week :周控件
month:月控件
表单属性:
placeholder :提示信息
autofocus :自动获取焦点
autocomplete=“on” 或者 autocomplete=“off” 使用这个属性需要有两个前提:
表单必须提交过
必须有 name 属性。
required:要求输入框不能为空,必须有值才能够提交。
pattern=" " 里面写入想要的正则模式,例如手机号 patte="^(+86)?\d{10}$"
multiple:可以选择多个文件或者多个邮箱
form=" form 表单的 ID"
表单事件:
oninput 每当 input 里的输入框内容发生变化都会触发此事件。
oninvalid 当验证不通过时触发此事件。
4. 进度条、度量器
progress 标签:用来表示任务的进度(IE、Safari 不支持),max 用来表示任务的进度,value 表示已完成多少
meter 属性:用来显示剩余容量或剩余库存(IE、Safari 不支持)
high/low:规定被视作高/低的范围
max/min:规定最大/小值
value:规定当前度量值
设置规则:min < low < high < max
5.DOM 查询操作
document.querySelector()
document.querySelectorAll()
它们选择的对象可以是标签,可以是类(需要加点),可以是 ID(需要加 #)
6. Web 存储
HTML5 提供了两种在客户端存储数据的新方法:
localStorage - 没有时间限制的数据存储
sessionStorage - 针对一个 session 的数据存储
7. 其他
拖放:拖放是一种常见的特性,即抓取对象以后拖到另一个位置。设置元素可拖放:
画布(canvas ): canvas 元素使用 JavaScript 在网页上绘制图像。画布是一个矩形区域,可以控制其每一像素。canvas 拥有多种绘制路径、矩形、圆形、字符以及添加图像的方法。
SVG:SVG 指可伸缩矢量图形,用于定义用于网络的基于矢量的图形,使用 XML 格式定义图形,图像在放大或改变尺寸的情况下其图形质量不会有损失,它是万维网联盟的标准
地理定位:Geolocation(地理定位)用于定位用户的位置。‘
总结: (1)新增语义化标签:nav、header、footer、aside、section、article(2)音频、视频标签:audio、video(3)数据存储:localStorage、sessionStorage(4)canvas(画布)、Geolocation(地理定位)、websocket(通信协议)(5)input 标签新增属性:placeholder、autocomplete、autofocus、required(6)history API:go、forward、back、pushstate
移除的元素有:
纯表现的元素:basefont,big,center,font, s,strike,tt,u;
对可用性产生负面影响的元素:frame,frameset,noframes;
position 的属性有哪些,区别是什么
position 有以下属性值:
前面三者的定位方式如下:
relative: 元素的定位永远是相对于元素自身位置的,和其他元素没关系,也不会影响其他元素。
fixed: 元素的定位是相对于 window (或者 iframe)边界的,和其他元素没有关系。但是它具有破坏性,会导致其他元素位置的变化。
absolute: 元素的定位相对于前两者要复杂许多。如果为 absolute 设置了 top、left,浏览器会根据什么去确定它的纵向和横向的偏移量呢?答案是浏览器会递归查找该元素的所有父元素,如果找到一个设置了
position:relative/absolute/fixed
的元素,就以该元素为基准定位,如果没找到,就以浏览器边界定位。如下两个图所示:
HTML5 的离线储存怎么使用,它的工作原理是什么
离线存储指的是:在用户没有与因特网连接时,可以正常访问站点或应用,在用户与因特网连接时,更新用户机器上的缓存文件。
**原理:**HTML5 的离线存储是基于一个新建的 .appcache
文件的缓存机制(不是存储技术),通过这个文件上的解析清单离线存储资源,这些资源就会像 cookie 一样被存储了下来。之后当网络在处于离线状态下时,浏览器会通过被离线存储的数据进行页面展示
使用方法: (1)创建一个和 html 同名的 manifest 文件,然后在页面头部加入 manifest 属性:
(2)在 cache.manifest
文件中编写需要离线存储的资源:
CACHE: 表示需要离线存储的资源列表,由于包含 manifest 文件的页面将被自动离线存储,所以不需要把页面自身也列出来。
NETWORK: 表示在它下面列出来的资源只有在在线的情况下才能访问,他们不会被离线存储,所以在离线情况下无法使用这些资源。不过,如果在 CACHE 和 NETWORK 中有一个相同的资源,那么这个资源还是会被离线存储,也就是说 CACHE 的优先级更高。
FALLBACK: 表示如果访问第一个资源失败,那么就使用第二个资源来替换他,比如上面这个文件表示的就是如果访问根目录下任何一个资源失败了,那么就去访问 offline.html 。
(3)在离线状态时,操作 window.applicationCache
进行离线缓存的操作。
如何更新缓存:
(1)更新 manifest 文件
(2)通过 javascript 操作
(3)清除浏览器缓存
注意事项:
(1)浏览器对缓存数据的容量限制可能不太一样(某些浏览器设置的限制是每个站点 5MB)。
(2)如果 manifest 文件,或者内部列举的某一个文件不能正常下载,整个更新过程都将失败,浏览器继续全部使用老的缓存。
(3)引用 manifest 的 html 必须与 manifest 文件同源,在同一个域下。
(4)FALLBACK 中的资源必须和 manifest 文件同源。
(5)当一个资源被缓存后,该浏览器直接请求这个绝对路径也会访问缓存中的资源。
(6)站点中的其他页面即使没有设置 manifest 属性,请求的资源如果在缓存中也从缓存中访问。
(7)当 manifest 文件发生改变时,资源请求本身也会触发更新。
v-model 语法糖是怎么实现的
浏览器是如何对 HTML5 的离线储存资源进行管理和加载?
在线的情况下,浏览器发现 html 头部有 manifest 属性,它会请求 manifest 文件,如果是第一次访问页面 ,那么浏览器就会根据 manifest 文件的内容下载相应的资源并且进行离线存储。如果已经访问过页面并且资源已经进行离线存储了,那么浏览器就会使用离线的资源加载页面,然后浏览器会对比新的 manifest 文件与旧的 manifest 文件,如果文件没有发生改变,就不做任何操作,如果文件改变了,就会重新下载文件中的资源并进行离线存储。
离线的情况下,浏览器会直接使用离线存储的资源。
CSS 优化和提高性能的方法有哪些?
加载性能:
(1)css 压缩:将写好的 css 进行打包压缩,可以减小文件体积。
(2)css 单一样式:当需要下边距和左边距的时候,很多时候会选择使用 margin:top 0 bottom 0;但 margin-bottom:bottom;margin-left:left;执行效率会更高。
(3)减少使用 @import,建议使用 link,因为后者在页面加载时一起加载,前者是等待页面加载完成之后再进行加载。
选择器性能:
(1)关键选择器(key selector)。选择器的最后面的部分为关键选择器(即用来匹配目标元素的部分)。CSS 选择符是从右到左进行匹配的。当使用后代选择器的时候,浏览器会遍历所有子元素来确定是否是指定的元素等等;
(2)如果规则拥有 ID 选择器作为其关键选择器,则不要为规则增加标签。过滤掉无关的规则(这样样式系统就不会浪费时间去匹配它们了)。
(3)避免使用通配规则,如*{}计算次数惊人,只对需要用到的元素进行选择。
(4)尽量少的去对标签进行选择,而是用 class。
(5)尽量少的去使用后代选择器,降低选择器的权重值。后代选择器的开销是最高的,尽量将选择器的深度降到最低,最高不要超过三层,更多的使用类来关联每一个标签元素。
(6)了解哪些属性是可以通过继承而来的,然后避免对这些属性重复指定规则。
渲染性能:
(1)慎重使用高性能属性:浮动、定位。
(2)尽量减少页面重排、重绘。
(3)去除空规则:{}。空规则的产生原因一般来说是为了预留样式。去除这些空规则无疑能减少 css 文档体积。
(4)属性值为 0 时,不加单位。
(5)属性值为浮动小数 0.**,可以省略小数点之前的 0。
(6)标准化各种浏览器前缀:带浏览器前缀的在前。标准属性在后。
(7)不使用 @import 前缀,它会影响 css 的加载速度。
(8)选择器优化嵌套,尽量避免层级过深。
(9)css 雪碧图,同一页面相近部分的小图标,方便使用,减少页面的请求次数,但是同时图片本身会变大,使用时,优劣考虑清楚,再使用。
(10)正确使用 display 的属性,由于 display 的作用,某些样式组合会无效,徒增样式体积的同时也影响解析性能。
(11)不滥用 web 字体。对于中文网站来说 WebFonts 可能很陌生,国外却很流行。web fonts 通常体积庞大,而且一些浏览器在下载 web fonts 时会阻塞页面渲染损伤性能。
可维护性、健壮性:
(1)将具有相同属性的样式抽离出来,整合并通过 class 在页面中进行使用,提高 css 的可维护性。
(2)样式与内容分离:将 css 代码定义到外部 css 中。
说一下 vue3.0 你了解多少?
Promise 是什么,解决了什么,之前怎么实现的
为什么需要清除浮动?清除浮动的方式
浮动的定义: 非 IE 浏览器下,容器不设高度且子元素浮动时,容器高度不能被内容撑开。 此时,内容会溢出到容器外面而影响布局。这种现象被称为浮动(溢出)。
浮动的工作原理:
浮动元素脱离文档流,不占据空间(引起“高度塌陷”现象)
浮动元素碰到包含它的边框或者其他浮动元素的边框停留
浮动元素可以左右移动,直到遇到另一个浮动元素或者遇到它外边缘的包含框。浮动框不属于文档流中的普通流,当元素浮动之后,不会影响块级元素的布局,只会影响内联元素布局。此时文档流中的普通流就会表现得该浮动框不存在一样的布局模式。当包含框的高度小于浮动框的时候,此时就会出现“高度塌陷”。
浮动元素引起的问题?
父元素的高度无法被撑开,影响与父元素同级的元素
与浮动元素同级的非浮动元素会跟随其后
若浮动的元素不是第一个元素,则该元素之前的元素也要浮动,否则会影响页面的显示结构
清除浮动的方式如下:
给父级 div 定义
height
属性最后一个浮动元素之后添加一个空的 div 标签,并添加
clear:both
样式包含浮动元素的父级标签添加
overflow:hidden
或者overflow:auto
使用 :after 伪元素。由于 IE6-7 不支持 :after,使用 zoom:1 触发 hasLayout**
对 HTML 语义化的理解
语义化是指根据内容的结构化(内容语义化),选择合适的标签(代码语义化)。通俗来讲就是用正确的标签做正确的事情。
语义化的优点如下:
对机器友好,带有语义的文字表现力丰富,更适合搜索引擎的爬虫爬取有效信息,有利于 SEO。除此之外,语义类还支持读屏软件,根据文章可以自动生成目录;
对开发者友好,使用语义类标签增强了可读性,结构更加清晰,开发者能清晰的看出网页的结构,便于团队的开发与维护。
常见的语义化标签:
absolute 与 fixed 共同点与不同点
共同点:
改变行内元素的呈现方式,将 display 置为 inline-block
使元素脱离普通文档流,不再占据文档物理空间
覆盖非定位文档元素
不同点:
abuselute 与 fixed 的根元素不同,abuselute 的根元素可以设置,fixed 根元素是浏览器。
在有滚动条的页面中,absolute 会跟着父元素进行移动,fixed 固定在页面的具体位置。
评论