面试|80+题复习计划(2022-8)

一、前端技术图谱梳理

二、关于面试心态与简历

1.关于心态

2.关于简历

三、常规部分

1. 前端性能优化?

前端性能优化:减少消耗(资源加载优化、编码优化),提高用户体验。

1、资源加载优化方向

  • ①减少请求数量。 合理规划利用请求,合理利用缓存技术减少不必要的频繁请求。及时性不高的数据可以缓存起来利用, 例如一些基础数据。应用懒加载技术,按需加载,缩短首屏或页面首次加载发起的请求数量,缩短等待和渲染时间。

    再例如,删除列表中的某一条数据的场景,是否每次删除之后立即向服务器发起更新列表的请求? 及时性要求没那么高的场景,其实执行删除接口和前端删除即可,不必每次删除之后都向服务器请求新的列表。

  • ②缩短请求时间。 打包压缩文件,压缩 js 和 css 文件,减小文件体积,缩短加载时间。

  • ③优化脚本加载方式。 script 加载。考虑异步请求资源,合理利用 script 加载方式,script 脚本的执行只在默认的情况下是同步和阻塞的。 script 有 defer 和 async 属性(延迟和异步),这可以改变脚本的执行方式。

    ④优化 css 加载。合理规划 css 的加载引入方式,减少 @import 的使用,页面被加载时,link 会同时被加载, 而 @import 引用的 CSS 会等到页面被加载完再加载。css 尽量放在 head 中会先加载,减少首次渲染时间。

  • ⑤一些用户操作行为用到的资源,可不在初始化时加载,合理延迟或有需要才请求。

2、编码优化方向

  • ①减少重排(reflow)重绘(repaint)

减少不必要的 DOM 深度,例如不必要的嵌套结构。 在 DOM 树中的一个级别进行更改可能会致使该树的所有级别(上至根节点,下至所修改节点的子级)都随之变化。 这会导致花费更多的时间来执行重排。

  • ②尽可能减少 CSS 规则的数量,并删除未使用到的 CSS 规则。一些默认就有的 CSS 规则,就不必写了, 具有继承性的样式,也不必每级节点都写。calc() 之类的计算函数没必要的应该少用。

  • ③关于动画效果。如果您想进行复杂的渲染更改(例如动画),请在流程外执行此操作。 您可以使用 position-absolute 或 position-fixed 来实现此目的。

  • ④关于 css 选择器。避免使用不必要且复杂的 CSS 选择器(尤其是后代选择器), 因为此类选择器需要耗用更多的 CPU 处理能力来执行选择器匹配。 总之不必要的深度,不管是 css 还是 dom 都不是好的选择,这对人和机器都是同样的道理,因为读和理解起来都同样的“费力”。

  • ⑤合理使用虚拟列表技术,降低消耗。

更详细请看导致 JS 缓慢的三主因之重排重绘

  • ⑥函数节流(throttle)或函数去抖(debounce)

使用函数节流(throttle)或函数去抖(debounce),限制某些不必要的行为的的频繁触发。

更详细的函数去抖与节流

2、其他:api、带宽 使用性能更好的 api,优化网络连接等

2. 简述一下你对 HTML 语义化的理解?

合理使用标签:

  • 可读性。代码结构清晰,便于理解,对人和机器的可读性都更好。
  • 可维护和团队协作。清晰语义化的结构,可维护性更高,更有利于团队协作。
  • seo。有利于搜索引擎优化(seo)。更多关于seo 和 meta标签
  • 没有css,也能呈现较好地内容结构和布局效果。

常见语义化标签:h1-h6,header,footer,main,nav,title,article,time,progress,aside,strong,ul,ol 等。

3. html 中的 label 可以用来干什么?

label 有两种使用方式,一是嵌套,二是通过 id 绑定。它可以用于关联绑定表单组件, 浏览器会将用户对 label 关联范围的焦点转移到绑定的表单组件上。

4. HTML 全局属性(global attribute)有哪些?

  • id: 元素 id,同一文档内 id 不能重复,具有唯一性。
  • dir: 设置元素文本方向。
  • lang: 使用的语言
  • style: 行内 css 样式
  • class: 元素的样式类名。
  • title: 元素的提示文本,鼠标移到元素上时显示的一段提示文本
  • data-*: 自定义元素属性。html5 规范提供的 data- 格式来写 html 元素的非标准属性。
  • hidden: 是否显示元素。
  • tabindex: 设置元素的tab键次序
  • dropzone: 设置元素拖放类型(copy, move, link)。
  • draggable: 设置元素是否可拖拽。
  • accesskey: 设置快捷键,通过快捷键可激活相应操作。更多accesskey与快捷键
  • translate: 设置是否翻译元素内容(浏览器兼容性不好)。
  • spellcheck: 是否启动拼写和语法检查。
  • contextmenu: 自定义鼠标右键弹出菜单内容。
  • contenteditable: 设置元素内容是否可编辑。更多contenteditable

5. HTML5 引入什么新的表单属性?

  • url:输入 URL。
  • number:输入数字。
  • email:输入邮箱地址。
  • month:输入年份或月份。
  • date:用于输入(选择)日期。
  • week:输入年份以及该年的第n周。
  • datalist:一组 元素。
  • time:输入时间(小时和分钟,以及可选的秒)。
  • datetime:用于输入日期和时间(小时、分钟、秒和秒的小数)以及时区。
  • range:输入范围。允许用户指定一个数值,该数值必须不小于给定值,并且不得大于另一个给定值。

6. img 上 title 与 alt

title 是在悬浮时展示的提示文字,alt 是在图像无法正常显示时展示的提示文字, 此外 title 是许多 html 标签都有的属性,而 alt 是 img 标签的特殊属性。 当然在低版本ie浏览器中,鼠标悬浮也会显示alt的文字。

更多信息-img的alt和title

7. 你的职业规划是怎样的?

这个问题,在印象里面似乎 hr 问得比较多。实事求是回答完事, 例如会坚持技术路线,往资深架构方向走,也希望拓阔方向,向大前端靠近。

tips:讲个笑话,跟着 JavaScript 走,当它一t天下的时候,也跟着...

8. 你印象最深刻的bug或技术难题是什么?你怎么解决的?

结合自身经历,概括用到的知识技术点,以及解决思路。

9. 从浏览器输入url到页面响应结束,这个过程是怎样的?js会阻塞文档渲染吗?

  • 解析 url 的有效性和合法性;
  • 执行缓存策略,策略内缓存中有则从缓存取并显示;
  • 缓存中没有则发送请求协议,DNS 解析域名,换取映射的 ip 地址;
  • 浏览器和服务器进行TCP连接,进行三次握手;
  • 握手成功正式发起请求,携带请求包,请求获取资源数据包;
  • 服务器接受处理请求包,寻找资源数据,并将资源数据返回给浏览器(当然可能啥也没有,也可能出错);
  • 浏览器接收请求返回的资源数据,尝试解析数据;
  • 浏览器解析返回的资源数据过程: 默认按照排序先后进行解析,加载 head 中的资源等等,例如 css 资源;

加载 script 脚本资源;script 脚本的执行只在默认的情况下是同步和阻塞的。 script 标签可以有 defer 和 async 属性(延迟和异步),这可以改变脚本的执行方式(在支持他们的浏览器)

继续解析后面的标签,文档内容

  • 浏览器渲染页面,同时执行可能的异步请求
  • 响应结束(可能正常显示,也可能异常)

10. 关于 head 标签?head 中必须的标签是?

  • title 标签用于定义文档的标题,它是 head 标签中唯一必需的元素。

  • head 标签用于定义文档的头部。 充当头部容器,可以包含 script 脚本,link 资源,mete 等标签。

  • 可用在 head 中的标签:<title>, <base>, <link>, <style>, <meta>, <script>, <noscript>, <command>。

11. disabled 和 readonly 的区别?

readonly:元素的只读属性,可以防止用户对值进行修改。 但用户仍然可以使用 tab 键切换到该字段,还可以选中或拷贝其文本。 在表单组件 input 中使用 readonly,内容会随着表单提交。

disabled:禁用属性,使元素无法使用和无法操作,无法被选中。 在表单组件 input 中使用 disabled,内容不会再随着表单提交。

二者都可以通过 js 修改其值,从而恢复编辑状态和被选中能力。

12. 常用的 meta 标签有哪些?

<!--
搜索引擎,用于禁止搜索引擎索引本页内容
谷歌、必应、雅虎都支持的 meta robots 标签如下,他们会禁止搜索引擎进行相应的操作:
noindex:不索引本页面。
nofollow:不跟踪本页面上的链接。
nosnippet:不在搜索结果中显示说明文字。
noarchive:不显示快照。
noodp:不使用开放目录中的标题和说明。
-->
<meta name="robots" content="noindex,nofollow"/>


<!-- 关键词,填写网页关键词,优化SEO的重要标签 -->
<meta name="keywords" content="请输入网页关键字,例如:程序员;写代码;高薪;加班严重"/>
<!-- 声明优先使用的浏览器,例如下面是优先使用的是edge和chrome -->
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
<!-- 网页概述,优化SEO的重要标签 -->
<meta name="description" content="请输入网页概述,例如:知识社区,前端技术"/>

13. echarts 实现的背后利用了哪个 html 标签?

利用的是 canvas 标签。

<canvas>是一个可以使用脚本(通常为JavaScript)来绘制图形的 HTML 元素。 例如,它可以用于绘制图表、制作图片构图或者制作简单的(以及不那么简单的)动画。

14. 手写一个年月日时分秒的函数

这是一道笔试题。要求写一个获取年月日时分秒的函数,返回的格式如下:2022-01-07 08:08:08
/**
 * 要求返回的格式如下:2022-01-07 08:08:08
 * @returns {string}
 */
function getDateTime () {
  let data = new Date(),
    year = data.getFullYear(),
    month = data.getMonth() + 1,
    day = data.getDate(),
    hour = data.getHours(),
    min = data.getMinutes(),
    second = data.getSeconds()

  // 当月、日、时、分、秒数字小于10时,补0。
  if (month < 10) {
    month = '0' + month
  }
  if (day < 10) {
    day = '0' + day
  }
  if (hour < 10) {
    hour = '0' + hour
  }
  if (min < 10) {
    min = '0' + min
  }
  if (second < 10) {
    second = '0' + second
  }

  return year + '-' + month + '-' + day + ' ' + hour + ':' + min + ':' + second
}

15. TDK 是什么?在前端优化 SEO,应该从哪些方面着手?

①TDK:title 标题标签、description 描述标签、keywords 关键词标签,这三个标签的首字母合体。

②SEO:

  • 合理使用 title、description、keywords: title 标题,description 描述,keywords 关键词的搜索影响权重是逐渐减小的。

title 和 description 的内容应能代表网页内容,不能乱用不被普遍认可的词汇, 不同页面 title、description、keywords应不同, keywords 的关键词,重要的靠前排放。

  • 语义化的 HTML 代码:符合 W3C 规范,语义化代码让搜索引擎容易理解网页。

  • 少用 iframe:搜索引擎不会抓取 iframe 中的内容。

  • 网速:网站网速是搜索引擎排序的一个重要指标

16. html5 的新增元素有哪些?

  • rt HTML Ruby 文本 (<rt>) 元素包含字符的发音,字符在 ruby 注解中出现, 它用于描述东亚字符的发音。这个元素始终在 ruby 元素中使用。
  • nav。 HTML nav 元素表示页面的一部分,其目的是在当前文档或其他文档中提供导航链接。 导航部分的常见示例是菜单,目录和索引。
  • bdi。 HTML 双向隔离元素 ( bdi ) 告诉浏览器的双向算法将其包含的文本与周围的文本隔离, 当网站动态插入一些文本且不知道所插入文本的方向性时,此功能特别有用。
  • main。 HTML main 元素呈现了文档的 body 或应用的主体部分。主体部分由与文档直接相关, 或者扩展于文档的中心主题、应用的主要功能部分的内容组成。
  • mark。 HTML 标记文本元素 ( Mark ) 表示为引用或符号目的而标记或突出显示的文本, 这是由于标记的段落在封闭上下文中的相关性或重要性造成的。
  • meter。 HTML meter 元素用来显示已知范围的标量值或者分数值。
  • aside。 HTML aside 元素表示一个和其余页面内容几乎无关的部分,被认为是独立于该内容的一部分并且可以 被单独的拆分出来而不会使整体受影响。其通常表现为侧边栏或者标注框(call-out boxes)。
  • audio。 HTML audio 元素用于在文档中嵌入音频内容。
  • video。 HTML video 元素 用于在 HTML 或者 XHTML 文档中嵌入媒体播放器,用于支持文档内的视频播放。 你也可以将 video 标签用于音频内容,但是 audio 元素可能在用户体验上更合适。
  • output。 HTML output 标签表示计算或用户操作的结果。
  • canvas。 canvas 元素可被用来通过 JavaScript(Canvas API 或 WebGL API)绘制图形及图形动画。
  • header。 HTML header 元素用于展示介绍性内容,通常包含一组介绍性的或是辅助导航的实用元素。 它可能包含一些标题元素,但也可能包含其他元素,比如 Logo、搜索框、作者名称,等等。
  • footer。 HTML footer 元素表示最近一个章节内容或者根节点(sectioning root )元素的页脚。 一个页脚通常包含该章节作者、版权数据或者与文档相关的链接等信息。
  • dialog。 HTML dialog 元素表示一个对话框或其他交互式组件,例如一个检查器或者窗口。
  • article。 HTML article 元素表示文档、页面、应用或网站中的独立结构,其意在成为可独立分配的或可复用的结构, 如在发布中,它可能是论坛帖子、杂志或新闻文章、博客、用户提交的评论、交互式组件,或者其他独立的内容项目。
  • section。 HTML section 元素表示一个包含在 HTML 文档中的独立部分, 它没有更具体的语义元素来表示,一般来说会有包含一个标题。
  • datalist。 HTML datalist 元素包含了一组option元素,这些元素表示其它表单控件可选值。
  • progress。 HTML中的 progress 元素用来显示一项任务的完成进度。虽然规范中没有规定该元素具体如何显示, 浏览器开发商可以自己决定,但通常情况下,该元素都显示为一个进度条形式。

17. 看下这道题目都输出了啥?

这是一道笔试题。
for(let i=0;i<4;i++){
  i++
  console.log(i) // 打印了 1 和 3
}

18. 介绍下重排(reflow)重绘(repaint),以及如何进行优化。

  • 重排或回流(reflow): 重排是在网络浏览器中执行的一个流程,用于重新计算文档中各元素的位置和几何形状,以便重新呈现该文档的部分内容或全部内容。 会改变文档布局,会引发元素的位置、尺寸发生改变的行为可称为重排。重排比起重绘,在视觉效果上会更明显, 每当操作 DOM 树、更改影响布局的样式、更改元素的 className 属性或更改浏览器窗口大小时,都会发生重排现象。

  • 重绘(repaint): 在不改变文档布局的情况下,文档元素发生的例如背景颜色等外观改变的行为可称为重绘。 根据 Opera 的说法,重绘的成本也很高,但在处理能力较高的现代设备中,可能感觉不明显。

更多信息

19. 列举工作中常用的几个 git 命令?

git rm                       删除工作区文件,并将这次删除放入暂存区
git add                      增加指定文件到暂存区
git init                     新建初始化 git 代码库
git status                   显示有变更的文件
git branch                   列出所有分支
git commit -m [message]      提交暂存区到仓库区,可选填备注信息 message
git checkout -b [branch]     新建分支,并切换到该分支

20. BFC 产生的条件?

  • 根元素()天然就会创建 BFC,iframe 会创建一个 html,所以 iframe 也会天然创建 BFC。
  • 浮动元素(float 值不为 none),float 的默认值是 none。
  • 绝对定位元素(position 值为 absolute 或 fixed),position 的默认值是 static。
  • 行内块元素(display 值为 inline-block)
  • 表格单元格(display 值为 table-cell,HTML表格单元格默认值)
  • 表格标题(display 值为 table-caption,HTML表格标题默认值)
  • 匿名表格单元格元素(display 值为 table、table-row、 table-row-group、table-header-group、 table-footer-group(分别是 HTML table、tr、tbody、thead、tfoot 的默认值)或 inline-table)
  • overflow 值不为 visible、clip 的块元素。overflow 的默认值是 visible。
  • display 值为 flow-root 的元素。flow-root 可以创建一个无副作用的 BFC,就像 html 根元素那样。但需注意 flow-root 的兼容性, 它是一个较新的属性,IE 全系列不支持,Chrome58,Firefox53,Edge79开始支持。
  • contain 值为 layout、content 或 paint 的元素
  • 弹性元素(display 值为 flex 或 inline-flex 元素的直接子元素),如果它们本身既不是flex、grid也不是table容器
  • 网格元素(display 值为 grid 或 inline-grid 元素的直接子元素),如果它们本身既不是flex、grid也不是table容器
  • 多列容器(column-count 或 column-width 值不为 auto,包括column-count 为 1)
  • column-span 值为 all 的元素始终会创建一个新的 BFC,即使该元素没有包裹在一个多列容器中。

21. vue 中组件之间可以怎么样通信。

  • prop 和 emit() 可以通过 prop 和emit()propemit() 通信。在子组件通过 prop 接受父组件传递下来的信息。 父组件可以根据约定的事件名,接受子组件通过 $emit(name,data) 向上派发的事件和传递的信息。

  • refs 和 ref。ref 绑定,refsrefrefrefs 获取组件实例,进而获取组件的属性、方法等信息。

  • Vuex,可以通过 vuex 进行数据交互,状态管理。

  • Bus (中央事件总线)

22. vue 指令中 v-for 和 v-if 哪个优先级更高

当它们处于同一节点,v-for 的优先级比 v-if 高,这意味着 v-if 将分别重复运行于每个 v-for 循环中。
<li v-for="todo in todos" v-if="!todo.isComplete">
  {{ todo }}
</li>

23. 你对 es6 的了解?

es6 又称 es2015,是 js 的标准,它包含了许多新的语言特性和库,是比较大的一次升级。

新增了:

  • “class“
  • “箭头函数“
  • “解构赋值“
  • “字符串模板“
  • “async/await“
  • “引入 module 模块“
  • “generators(生成器)“

24. 假如有10万数据要处理,前端应该怎么处理?

这题应该是想问虚拟列表,嘿,谁还不会点虚拟列表。 10万数据同时渲染的假如太假了,不管啥技术都得是往【时空错位】方向考虑吧?

认真的讲,分页获取分页渲染,也是一个朴素的好方法。初次和面试官见面不好认真,还是虚拟列表吧。

  • 虚拟列表

什么是虚拟列表:只对可见区域进行渲染,对非可见区域中的数据不渲染或部分渲染,以实现减少消耗,提高用户体验的技术。

为啥要用虚拟列表:一是性能优,二是体验丝滑。渲染生成过多的节点,可能会造成页面卡顿,甚至卡死浏览器。 而常规分页的展示效果可能不是想要的,尤其在移动端,用户习惯和偏好,更倾向于上下滑动。

虚拟列表的实现思路:

  • 可视区域固定高度,设置纵向 Y 轴滚动
  • 计算可显示的列表项数量:根据可视区域和列表项高度(rowHeight),计算出可显示的列表项的数目 limit
  • 当滚动条上滑时,计算出滚动的距离 scrollTop
  • 计算出当前起始索引:currentIndex = Math.floor(scrollTop/rowHeight)
  • 计算出最后可显示的索引:endIndex = Math.min(currentIndex+limit, total-1)
  • 渲染可视区域:根据开始位置 startIndex 和 结束位置 endIndex 渲染可视区域

25. git 与 svn 的区别在哪里?

  • git 和 svn 最大的区别在于 git 是分布式的,而 svn 是集中式的。因此我们不能再离线的情况下使用 svn。

  • git 分支上的变更不会影响其他人,svn 分支上的变更会影响到其他人。

  • svn 的指令相对于 git 来说要简单一些,比 git 更容易上手。(没用过svn,git感觉也很容易上手)

  • svn 中的分支是整个版本库复制的一份完整目录,而 git 的分支是指针指向某次提交,因此 git 的分支创建开销更小。

26. 说一说深拷贝?你平时是怎么实现深拷贝的?

  • 浅拷贝:就是将一个对象的内存地址的复制给另一个对象。

  • 深拷贝:先新建一个空对象,内存中创建一个新的地址, 然后把被复制对象的所有可枚举的属性方法一一复制过来。

  • 实现深拷贝的方法

①JSON.parse(JSON.stringify(data)),但对于 function 有缺陷。 (原本我是不太喜欢啥都用第三方库,比如一个日期格式化,一个深拷贝, 但后来一想技术员和研究员终究是不同,读者推荐 lodash 的 clonedeep 实现深拷贝。)

②Object.assign() 实现一层深拷贝。

③解构赋值法实现一层拷贝

④创建新对象 for 循环拷贝,有需要可结合递归。

大都数场景,还是 JSON.parse(JSON.stringify(data)) 实用, 有的人说有性能担忧,但讲真,每个字节所到之处都涉及性能问题吧?

27. http 状态码的 301 表示啥意思?你知道的 http 状态码有哪些?

  • ①状态码的职责:

状态码的职责是当客户端向服务器端发送请求时,描述返回的请求结果。借助状态码,用户可以知道服务器端是正常处理请求,还是出现了错误。

  • ②具体状态码的表示意思:

  • 1XX Informational(信息性状态码) 接收的请求正在处理

  • 2XX Success(成功状态码) 请求正常处理完毕

  • 3XX Redirection(重定向状态码) 需要进行附加操作以完成请求

  • 4XX Client Error(客户端错误状态码) 服务器无法处理请求

  • 5XX Server Error(服务器错误状态码) 服务器处理请求出错

204 No Content,表示请求处理成功,但没有资源可返回。该状态码代表服务器接收的请求已成功处理,
但在返回的响应报文中不含实体的主体部分。另外,也不允许返回任何实体的主体。

206 Partial Content,该状态码表示客户端进行了范围请求,而服务器成功执行了这部分的GET 请求。
响应报文中包含由 Content-Range 指定范围的实体内容。

301 Moved Permanently,永久性重定向。该状态码表示请求的资源已被分配了新的 URI,以后应使用资源现在所指的 URI。

302 Found ,临时性重定向。该状态码表示请求的资源已被分配了新的 URI,希望用户(本次)能使用新的 URI 访问。

303 See Other ,该状态码表示由于请求对应的资源存在着另一个 URI,应使用 GET 方法定向获取请求的资源。

304 Not Modified ,该状态码表示客户端发送附带条件的请求时,服务器端允许请求访问资源,但未满足条件的情况。
304 状态码返回时,不包含任何响应的主体部分。304 虽然被划分在 3XX 类别中,但是和重定向没有关系。
(资源已找到,但不符合请求所附带的添加。好像是说已经找到钱包,但你的请求附带了一个钱包里应有10k金额的条件,
所以不好意思,无法把钱包返回给你。---引《图解HTTP》)

307 Temporary Redirect ,临时重定向。该状态码与 302 Found 有着相同的含义。
尽管 302 标准禁止 POST 变换成 GET,但实际使用时大家并不遵守。

400 Bad Request ,该状态码表示请求报文中存在语法错误。当错误发生时,需修改请求的内容后再次发送请求。
另外,浏览器会像 200 OK 一样对待该状态码。

401 Unauthorized ,该状态码表示发送的请求需要有通过 HTTP 认证(BASIC 认证、DIGEST 认证)的认证信息。
另外若之前已进行过 1 次请求,则表示用户认证失败。

403 Forbidden ,该状态码表明对请求资源的访问被服务器拒绝了。服务器端没有必要给出拒绝的详细理由,
但如果想作说明的话,可以在实体的主体部分对原因进行描述,这样就能让用户看到了。 
未获得文件系统的访问授权,访问权限出现某些问题(从未授权的发送源 IP 地址试图访问)
等列举的情况都可能是发生 403 的原因。

404 Not Found,该状态码表明服务器上无法找到请求的资源。
除此之外,也可以在服务器端拒绝请求且不想说明理由时使用。

500 Internal Server Error,该状态码表明服务器端在执行请求时发生了错误。
也有可能是 Web 应用存在的 bug 或某些临时的故障。

503 Service Unavailable,该状态码表明服务器暂时处于超负载或正在进行停机维护,
现在无法处理请求。如果事先得知解除以上状况需要的时间,最好写入 RetryAfter 首部字段再返回给客户端。

504 Gateway Timeout,网关超时。

28. 你对防抖和节流有了解吗?

函数防抖动(debounce):防止在短时间内过于频繁的执行相同的任务。 当短时间内的频繁是不必要的时候,就可以考虑去抖动,避免资源浪费,或造成不友好的体验。

函数防抖动的原理,主要是利用一次性定时器,延迟任务的执行,在延迟这段时间内, 如果任务再次被触发,则通过 clearTimeout 销毁上一次产生的定时器, 因为定时器的被销毁,之前被延迟执行的任务也会随之被取消执行。 这样就实现了在一定时间内,只执行一次任务。这一次的执行通常是最后一次的触发, 因为此前的触发因为定时器的销毁而被取消了。

多次触发只执行最后一次或许就是和“节流”概念的区别?它两在作用上挺像的,在具体实现上略有不同。 函数防抖(debounce)是短时间内连续多次触发,但只执行最后一次,即是说将多次执行变成了只执行最后一次,执行次数减少。 而节流(throttle)是将短时间的多次执行,变成每隔一段时间执行一次。

更详细的函数防抖(debounce)

29. css 的相对单位有哪些?px 和 em 有什么不同?

  • ① 14种相对单位

② px 和 em 和 rem
px 是 css 中的绝对单位,也是web前端最为常见的单位,它表示像素,他的值不会受其他元素或其他值的影响,
我们可以理解为10px所表示的意义,总是相同的。

em 是相对单位,相对于元素的字号,在 font-size 中使用是相对于父元素的字体大小,
在其他属性中使用是相对于自身的字体大小,如 width。

相对单位的值的表示的大小,受其他东西的影响,比如1em,可能相当于10px的大小,
也可能相当于100px,甚至更高,因为em的实际表示大小是根据父元素而定,
1em表示的是父元素字体大小的一倍,要注意的是虽然只是受父元素的影响,
但父元素也会受它的父元素的影响。

rem是相对单位,相对于根元素的字体大小。

vh 和 vw 都是相对于视口,即设备屏幕可视区域的,这里视口宽高分别被划分为100,
vh 是相对于视口的高度,vw 是相对于视口的宽度。例如一个视口宽高为 1024 * 768,
则1vw,表示视口宽度的1%,即是102.4;1vh表示视口高度的1%,即是76.8。
所以在不同视口大小的设备,1vh所表示的意义是不同的。

30. 用过闭包吗?你对闭包的认识是什么?

Mozilla 上这样解释闭包:一个函数和对其周围状态(lexical environment,词法环境) 的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)。

我对闭包的理解:闭包就是函数内部嵌套了函数。闭包使得可以模拟私有项, 可以使得内部函数可以访问外部函数的属性。非必要不用闭包。

更多信息-学闭包(closure),应该注意什么?

31. js 中的原型链是怎样的?

javaScript 对象有一个指向一个原型对象的链。当试图访问一个对象的属性时,它不仅仅在该对象的自有属性上搜寻, 还会搜寻该对象的原型,以及该对象的原型的原型, 依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。

这种依次层层向上搜索中,遇到的每层的原型所组成的链条就是原型链。

下面通过一个示例来理解继承与原型链
    // 使用语法结构创建的对象
    let obj = {
      a: 'hello',
      fc: function () {
        return this.a + 1
      }
    }
    // obj 这个对象继承了 Object.prototype 上面的所有属性
    // obj 自身没有名为 hasOwnProperty 的属性
    // hasOwnProperty 是 Object.prototype 的属性
    // 因此 obj 继承了 Object.prototype 的 hasOwnProperty
    // Object.prototype 的原型为 null

    // 原型链如下:
    // obj ---> Object.prototype ---> null
    console.log(obj)
    console.log(obj.__proto__)
    console.log(obj.__proto__.__proto__) // null,这就是原型链的终点

    let subObj = Object.create(obj); // 创建的 subObj 本身没有自身的属性,但它继承有 obj 的属性。
    console.log(subObj.fc()); // 3,fc() 继承自 obj
    // 那么此时,我们就说 subObj 是一个继承自 obj 的对象,因为继承,obj 的一些属性被传递给了 subObj,
    // 例如 fc() 就继承自 obj
    // subObj 的原型链是 // subObj ---> obj ---> Object.prototype ---> null
    console.log(subObj)
这是一张打印上面 obj 对象的原型链截图, 打印结果也符合上面关于 obj 对象原型链的结论:obj ---> Object.prototype ---> null

下面是一张打印 subObj 的原型连截图: 打印结果也符合上面关于 subObj 对象原型链的结论:subObj ---> obj ---> Object.prototype ---> null

32. display:none 与 visibility:hidden 的区别是什么?

display: 隐藏元素,不会占据该元素原来的空间。视觉上相对于该元素被移除了,不占有空间位置。 设置 display:none后,元素的宽高等属性会”失效“

visibility: 隐藏元素,仍然占据该元素原来的空间。可能会呈现一部分空白区域。 设置 visibility:hidden 后,仍占据空间位置,视觉上相当于完全透明。

33. 改变盒子模型的 css 属性啥?介绍下盒子模型

①通过 box-sizing 来改变盒子模型,它有两个选项 border-box 和 content-box。

②盒模型:分为内容(content)、填充(padding)、边界(margin)、边框(border)四个部分

③与 css 盒模型有关的一个值得注意属性是 box-sizing。通常 box-sizing 的默认值是 content-box, 而他还有另一个值 border-box。content-box 中,属性 width,height 只包含内容content, 不包含 border 和 padding。border-box 中,属性 width,height 则包含 content、border和padding。

有关计算公式

/** content-box 的宽高计算 **/
box-sizing:content-box
width = width(内容宽度);
height = height(内容高度)
/**  border-box 的宽高计算  **/
box-sizing:border-box
width = width(内容宽度) + padding + border;
height = height(内容高度)  + padding + border

34. 页面引入样式时,使用 @import 和 link 的区别有了解吗?

①来源区别。@import 是 css 的语法,而 link 是 html 的标签。

②加载区别。在加载的时候,@import 引用的 CSS 会在页面加载完成后才会加载 @import 引入的 CSS 样式表, 而 link 引入的 CSS 是在页面加载的同时被加载。

③权重区别。可比较环境下,@import 引用的样式,权重小于 link 引入的样式。

④兼容区别。兼容性上,link 几乎所有浏览器都支持,例如 ie、Firefox、chrome、safari、opera 全版本支持。 而 @import 是 ie 5.5 开始支持。

35. 什么是外边距折叠(margin collapsing)?发生折叠会怎样?

①块的上外边距(margin-top)和下外边距(margin-bottom)有时合并(折叠)为单个边距, 其大小为单个边距的最大值(或如果它们相等,则仅为其中一个),这种行为称为外边距折叠

②外边距折叠(也被翻译为重叠或塌陷)有关的计算:折叠后其大小为单个边距的最大值(或如果它们相等,则仅为其中一个)。

tips:这里说的单个边距的最大值,不是指数学比较上的最大,而是指单个边距距离范围的大小。

  • 同正或同负:选绝对值最大的。

比如 -50px 和 -70px 发生折叠,那么折叠后的值是 70px,因为 -70 的绝对值最大嘛,要是 -50px 和 -50px, 当然此时绝对值最大也是 50px 嘛,所以你只有一个选择 50px。

比如 50px 和 70px 发生折叠,那么折叠后的值是 70px,因为 70 的绝对值最大嘛, 要是 50px 和 50px,当然也选绝对值最大的 50px。

  • 有正有负:最大的正边距与最小的负边距的和。
例如 70px、-50px、20px 发生折叠,那么边界范围就是 70px + (-50px)= 20px。

36. 怎么区分伪类伪元素?常见的伪类伪元素有哪些?

  • 区别:

①css3 以后,为了区分伪类和伪元素,规范伪类使用单冒号,伪元素使用双冒号表示。 (但css2 的伪元素单冒号的写法,仍被许多现代浏览器兼容支持)

②伪类会给页面中已经存在的元素添加一个类(class),伪元素则是添加了一个页面中没有的元素(element), 但需注意这个被添加的元素不会添加到文档树中,只是一种视觉效果。

  • 常见的伪类伪元素

常见伪元素

  • ::after (:after)
  • ::before (:before)
  • ::cue (:cue)
  • ::first-letter (:first-letter)
  • ::first-line (:first-line)
  • ::selection
  • ::slotted()
  • ::spelling-error

常见伪类

  • :hover
  • :active
  • :disabled
  • :first
  • :first-child
  • :first-of-type
  • :not()
  • :required

37. 用过媒体查询 @media 吗?

来自 Mozilla 的关于 @media 的解释:

@media CSS 规则可用于基于一个或多个媒体查询的结果来应用样式表的一部分。 使用它,您可以指定一个媒体查询和一个CSS块,当且仅当该媒体查询与正在使用其内容 的设备匹配时,该CSS块才能应用于该文档。

媒体查询(Media queries)非常实用,尤其是当你想要根据设备的大致类型(如打印设备与带屏幕的设备) 或者特定的特征和设备参数(例如屏幕分辨率和浏览器视窗宽度)来修改网站或应用程序时。

我对 @media 的理解:

因为现实中存在许多不同的设备,不同的设备可能分辨率不同,可能屏幕可见区域也不同。 为了能让同一份网页在不同的设备中,表现得更友好,适配程度更高,于是 css3 设计了 @media。

使得无需修改内容便可以使样式应用于某些特定的设备范围。 例如为打印机、智能手机、阅读器、电脑等不同设备,编写不同的样式表, 通过 @media 识别适配应用对应的样式表。

@media 可以针对不同的屏幕尺寸设置不同的样式,这在设计响应式的页面会非常有用。 例如,通过媒体查询可以识别小型设备并缩小此时的字体大小,在纵向模式下查看页面时增加段落之间的填充, 或者增加触摸屏上按钮的大小,甚至改变布局方式,从而使得页面表现得更友好。

当媒体查询返回为真时,对应的样式表会按照正常的规则被应用生效; 当媒体查询返回为假时,以 link 标签上带有媒体查询的样式表为例,对应的样式表不会被应用,但仍会被下载。

用法示例:
/* 可以放在 style 的顶部,或其他位置 */
@media screen and (min-width: 900px) {
  article {
    padding: 1rem 3rem;
  }
}

/* 嵌套在一组 css 规则中 */
@supports (display: flex) {
  @media screen and (min-width: 900px) {
    article {
      display: flex;
    }
  }
}

38. 在 HTML5 中,哪个方法用于获得用户的当前位置?

这是一道笔试选择题,其他选项不记得了。

navigator.geolocation.getCurrentPosition() 下面是一个使用示例:

/*经验:在 chrome 上需要 https 协议才能成功启用获取地理位置服务,Firefox 则无需。*/
getGeolocation(){
  if ('geolocation' in navigator) {
    /* 地理位置服务可用 */
    console.log('地理位置服务可用')
    navigator.geolocation.getCurrentPosition(function (position) {
      console.dir('回调成功')
      console.dir(position) // 没有输出
      console.dir(position.coords.latitude, position.coords.longitude)
    }, function (error) {
      console.error(error)
    })
  } else {
    /* 地理位置服务不可用 */
    console.error('地理位置服务可用')
  }
}

39. css 中如何引入特殊的外部字体?

@font-face 的 CSS 规则 ,它允许网页开发者为其网页指定在线字体或加载指定的本地字体。 例如某一种漂亮的艺术字体,你的操作系统并没有,然而你希望使用它。 那么,你就可以通过引入该艺术字体的字体文件,然后利用@font-face规则注册字体, 之后你就可以通过 font-family: [注册的字体名称] 来使用引入的字体了。

使用外部字体的三步:①引入字体资源即下载例如ttf的字体文件到本地或使用在线资源, ②@font-face规则注册字体,③根据注册名称和font-family关键字使用字体。

下面是一个示例

@font-face {
    /* 字体名称,可自定义,就像定义一个class名称一样。*/
    font-family: 'hdjx'; 
    /* 字体文件的路径,除了 url()加载字体,也可以通过 local() 加载本地字体 */
    src: url('./HDJXYT.ttf'); 
    /* 字重,就像在普通css中使用它一样,可以选择bold等值 */
    font-weight: normal; /* 字重 */
    /* 字体样式 */
    font-style: normal; /* 字体样式 */
}

40. 可以怎样解决 https 页面访问 http 资源报错?

在使用 https 的访问页面中,引入 http 资源会被浏览器报警告,不同浏览器警告信息可能展现形式不同。

  • 协议相对URl(protocol-relative URL)。

为了解决这个问题,我们可以省略 URL 的协议声明,省略后浏览器照样可以正常引用相应的资源, 这项解决方案称为 protocol-relative URL。

协议相对URl,是指在编写URL时不携带具体的协议类型,URL被访问执行时,根绝一定规则自动使用相对的协议类型。 例如,当人们通过https浏览页面时候,那么不写明具体协议类型的的图片资源URL,就会以https协议访问图片资源; 使用http浏览页面时,使用相对协议URL的资源就会以http请求资源。

使用相对协议URL,可能会是一个好的选择。因为使用相对协议URL,在用http或https浏览页面时, 浏览器都会以相同的协议请求对应的资源,这能较好地避免浏览器关于使用混合协议的警告。 在SSL证书是后面使用的场景中,资源URL也不用更换,意思是说存储起来的资源地址(例如图片地址), 可以不是绝对地址,可以不携带协议类型,甚至连域名都不带也是一种具有可行的方案。

41. 什么是 FOUC? 如何避免?

  • 什么是 FOUC?

FOUC(文档样式短暂失效(Flash of Unstyled Content)),主要指的是样式闪烁的问题, 由于浏览器渲染机制(比如firefox),在 CSS 加载之前,先呈现了 HTML, 就会导致展示出无样式内容,然后样式突然呈现的现象。会出现这个问题的原因主要是 css 加载时间过长, 或者 css 被放在了文档底部。

  • FOUC优化建议

①减少使用@import导入样式表。

②不在文档尾部引入样式。

③尽量使用link标签在head中引入。(当然link标签是一个只能在head中使用的标签,因此使用link必然是在head中的)

42. CSS 样式选择器有哪些?优先级是怎样计算的?

11 种样式选择器

  • 通配符选择器,* 是通配符,表示其下的样式对所有元素生效,但通配符的优先级较低。
  • id选择器,例如 #container
  • 类选择器,例如 .box
  • 标签选择器(类型选择器),例如 div span p 等元素标签,直接以标签名称作为样式选择器
  • 后代选择器,有层级关系的叠加样式选择器,是样式选择器的一种组合使用,例如 div p
  • 子选择器,例如 ul>li 或 div>p,对 ul 直接的子元素 li 设置样式,对 div 的直接子元素 p 设置样式。
  • 伪类选择器,例如 a:hover,当鼠标悬浮于 a 标签时的样式。
  • 伪元素选择器,例如常见的 ::before 和 ::after,单冒号写法也被现代浏览器支持(那是css2的语法)。
  • 相邻兄弟选择器,例如 img + p,样式将对 img 图片后面紧跟着的 p 段落生效。
  • 兄弟选择器,A~B 作用于 A 元素之后所有同层级 B 元素。
  • 属性选择器,通过已经存在的属性名或属性值匹配元素,例如 a[href="example.org"] 或 a[title="一级标题"]。

优先级是如何计算的?

当同一个元素有多个声明的时候,优先级才会有意义。因为每一个直接作用于元素的 CSS 规则总是会接管/覆盖(take over)该元素从祖先元素继承而来的规则。

下面列表中,选择器类型的优先级是递增的:

  • 1.类型选择器(标签选择器)(例如,h1)和伪元素(例如,::before)

  • 2.类选择器 (例如,.example),属性选择器(例如,[type="radio"])和伪类(例如,:hover)

  • 3.ID 选择器(例如,#example)。

  • 4.嵌套组合选择器 多种选择器嵌套组合的优先级,往往比单一的样式选择器优先级更高。 例如 #id > div > p{} 的优先级会比 p{} 和 div > p{} 的优先级更高。

  • 5.内联样式 给元素添加的内联样式 (例如,style="font-weight:bold") 几乎总会覆盖外部样式表的任何样式 , 因此可看作是具有更高的优先级。

  • 6.!important 当在一个样式声明中使用一个 !important 规则时,此声明将覆盖任何其他声明。 当然 !important 可以覆盖 !important,此时需要比较权重。

  • 具体的优先级权重规则略显复杂: 一个选择器的优先级可以说是由四个部分相加 (分量),可以认为是个十百千 — 四位数的四个位数:

千位: 如果声明在 style 的属性(内联样式)则该位得一分。这样的声明没有选择器,所以它得分总是1000。 百位: 选择器中包含ID选择器则该位得一分。 十位: 选择器中包含类选择器、属性选择器或者伪类则该位得一分。 个位: 选择器中包含元素、伪元素选择器则该位得一分。

下面是一个示例表:


tips:可比条件下,写在后面优先级高于写在前面的

tips:可比条件下,同为载入样式,后面载入的优先级更高。

43. var、let 和 const的认识?

var 关键字用于声明全局变量,存在”变量提升“现象,不会抛出异常,默认值会被设置为 undefined。 “变量提升”的存在,使得变量像是声明提前,声明语句被移动到环境的顶部似得。

let 和 const 是 es6 新增的关键字,用于声明局部变量。 const 用于声明常量,它声明的变量只读不可被修改。 let 声明的局部变量可以被修改。

在 ECMAScript 6 中,let 和 const 同样会被提升变量到代码块的顶部但是不会被赋予初始值。 在变量声明之前引用这个变量, 将抛出引用错误(ReferenceError)。 这个变量将从代码块一开始的时候就处在一个“暂时性死区”,直到这个变量被声明为止。

更多信息-变量提升与函数提升

44. 你是怎么处理多文本溢出省略截断的?

  • vue 环境的推荐指令版做法:浏览器兼容性强的单行多行文本溢出截断省略方案

  • 常规做法一:纯 css 样式

/** 单行的处理 **/
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;

/** 多行的处理,不兼容 ie **/
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3; /** 最多显示几行 **/
overflow: hidden;
  • 常规做法二:截取一定长度的字符

截取固定字符数的方式,例如截取120字,超出部分使用省略号替代,不超出则不截取。 这种方式相比方案一,兼容性更好,也有两个缺点: 一是排版效果不够美观,因为英文和数字的单字符占的实际宽度要比中文小, 这会产生省略号可能在行中间甚至行首,而不是统一的在行位。 二是对html字符串不友好,有时接口返回的会是包含html代码的字符串, 截取可能会破坏html字符串的代码结构,例如一个标签被截取部分。

45. css 属性中 height 可以被继承吗?还有哪些属性可以继承?哪些不可以继承?

①height 默认不会被继承(但“继承”是可控制的)。

②可继承与不可继承的样式小结

可继承:

  • ul
  • li
  • dl
  • dd
  • dt
  • color
  • font-size
  • font-family

不可继承 :

  • width
  • height
  • border
  • margin
  • padding

③控制继承

CSS 为控制继承提供了四个特殊的通用属性值。每个css属性都接收这些值。 这意味着,就像 css 盒子模型可以通过改变 box-sizing 的值 (border-box 和 content-box)来改变。 css 属性的继承情况也是可以控制的,例如通过设置值 inherit、initial、unset 和 revert 来控制。
inherit:设置该属性会使子元素属性和父元素相同。实际上,就是 "开启继承".

initial:设置属性值和浏览器默认样式相同。如果浏览器默认样式中未设置且该属性是自然继承的,那么会设置为 inherit。

unset:将属性重置为自然值,也就是如果属性是自然继承那么就是 inherit,否则和 initial一样。

revert:目前仅被很少浏览器支持。

④重设几乎所有属性值

CSS 的 简写(shorthand) 属性 all 可以用于同时将这些继承值中的一个应用于(几乎)所有属性。 它的值可以是其中任意一个(inherit, initial, unset, or revert)。 这是一种撤销对样式所做更改的简便方法,以便回到之前已知的起点。

例如像下面这样:例子中有两个 div,第一个 div 应用了样式选择器 div 的样式, 第二个通过 类选择器 unset-all 设置 all 为 unset,重置了几乎所有样式, 例子中的红色背景和绿色边框都被重置为浏览器默认的白色了。
<div>
    <p>这是一段文字</p>
</div>
<div class="unset-all">
    <p>这是另一段文字,它将被充值样式</p>
</div>
div {
    background-color: red;
    border: 2px solid green;
}

.unset-all {
    all: unset;
}
下面是一张效果图

46. 使用纯 div + css 布局有啥好处?

这是一道笔试题,也许是不好意思当面问出来?

①兼容性更好,因为纯 div + css 的布局设计,会被几乎所有浏览器支持,且效果表现一致性高。

②设备扩展性较好,尤其是在不同的设备上,例如 PowerPoint,手机浏览器,其他终端设备等。

③灵活性较高...

④更有利于搜索引擎SEO?

47. css 样式的匹配顺序是从左到右吗?

不是。 浏览器会从最右边的样式选择器开始,依次向左匹配。最右边的选择器相当于关键选择器(key selector), 浏览器会根据关键选择器从 dom 中筛选出对应的元素,然后再向上遍历相关的父元素,判断是否匹配。

所以组合嵌套选择器时,匹配语句越短越简单,浏览器消耗的时间越短, 同时也应该减少像标签选择器,这样的大范围命中的通配选择器出现在组合嵌套选择器链中, 因为那样会让浏览器做大量的筛选,从而去判断选出匹配的元素。

48. css 的 position 有哪些值?它们表示什么?

  • fixed:固定定位 元素会被移出正常文档流,并不为元素预留空间,而是通过指定元素相对于屏幕视口(viewport)的位置来指定元素位置。 元素的位置在屏幕滚动时不会改变。 (一种有趣的划分,fixed 和 absolute 所作用的元素一样,被划为绝对定位元素(absolutely positioned element))

  • absolute:绝对定位 元素会被移出正常文档流,并不为元素预留空间,通过指定元素相对于最近的非 static 定位祖先元素的偏移, 来确定元素位置。绝对定位的元素可以设置外边距(margins), 且不会与其他边距合并即不会发生外边距折叠(margin collapsing)。

  • relative:相对定位 该关键字下,元素先放置在未添加定位时的位置,再在不改变页面布局的前提下调整元素位置 (因此会在此元素未添加定位时所在位置留下空白)。 position:relative 对 table-*-group, table-row, table-column, table-cell, table-caption 元素无效。

  • sticky:粘性定位 该关键字指定元素使用正常的布局行为,即元素在文档常规流中当前的布局位置。 此时 top, right, bottom, left 和 z-index 属性无效。

49. vue-router 路由的两种模式

  • hash 模式

来自 Vue Router 官网

hash 模式是用 createWebHashHistory() 创建的,它在内部传递的实际 URL 之前使用了一个哈希字符(#)。 由于这部分 URL 从未被发送到服务器,所以它不需要在服务器层面上进行任何特殊处理。 不过,它在 SEO 中确实有不好的影响。如果你担心这个问题,可以使用 HTML5 模式。
  • history 模式
不用担心:要解决这个问题,你需要做的就是在你的服务器上添加一个简单的回退路由。 如果 URL 不匹配任何静态资源,它应提供与你的应用程序中的 index.html 相同的页面。漂亮依旧!

hash 路由模式及其特性:

  • hash 模式是一种把前端路由的路径用井号 # 拼接在真实 url 后面的模式
  • 通过 js 对 location.hash 进行赋值,会改变 url 的 hash 值
  • 可以通过 hashchange 事件监听 hash 值的变化,来控制页面跳转(渲染)
  • 当井号 # 后面的路径发生变化时,会触发 onhashchange 事件
  • url 中的 hash 值只是客户端的内容,当使用包含 hash 值的路由发送请求时,hash 部分不会被发送
  • hash 值的改变会在浏览器访问历史中新增记录,所以可以使用浏览器的前进后退功能

history 路由模式及其特性:

  • html5 提供了 window.history API 来控制 url 变化,主要是 history.pushState() 和 history.replaceState() 它们可以在不刷新浏览器的场景下,操作浏览器历史记录。前者是增加一个历史记录,后者是替换当前历史记录。
  • 通过 popstate 事件可以监听 url 变化,来控制页面跳转(渲染)
  • history.pushState() 和 history.replaceState() 不会触发 popstate 事件

补充:关于 location 跳转的三种方式

location.href='跳转的地址' 跳转页面
location.reload('') 刷新页面
location.replace('') 替换当前页面

hash 模式的缺点是长得“不好看”,history 模式的缺点是,对于单页应用 history 打包部署需要注意配置支持, 当找不到资源的时候应指向 index.html(单页应用的html页面)。

50. html、css 和 js 的注释方式?

这是一道简单的基础笔试题。

js:// 单行注释,/* 多行注释 */

html:<!- -" 注释内容"- ->

css:/* 注释内容 */ ,在一些 css 预处理语言环境中,// 也有注释效果

51. vue.js 的两个核心是什么?

数据驱动和组件化思想

  • 数据驱动

数据驱动是vuejs的核心思想之一,有人称其为vuejs最大的特点。所谓数据驱动就是指数据状态变化时, 自主得去更新与其有依赖的视图。数据驱动的关键在于驱动,这里的驱动是自主的, 生活中有一个词叫做自动化,我简单的认为数据驱动思想,是自动化思想在前端编程自动化上的一种应用, 数据驱动是将对dom的手动操作,自动化了,它根据数据状态的变化,自动更新操作视图。 使用过jQuery的同学应该有体会,数据驱动带来的“自动化”,其实省去了许多操作dom的工作,维护也更加方便。

我对数据驱动的理解,简单总结为以下三点:

①数据驱动是指根据数据状态变化,自主更新视图。

②数据驱动是自动化思想,在前端编程自动化上的应用。

③数据驱动使得操作dom,从手动操作,变成了自动操作,是一种自动化表现。

  • 组件化

vue组件是一种拓展HTML元素,将要展示的内容分成相对独立的拓展HTML元素, 即分成不同组件的过程,或在设计构建视图的编码时,将相对独立的可视区域, 以独立组件的形式构建的过程,就是组件化。

组件化的优点: 每一个组件,可以对应一个viewModel(简写vm,可以是vue实例)。视图页面是组件的容器, 组件化之后,我们可以任意根据需求自由嵌套组合组件,最后形成一个个完整页面。 组件具有高内聚低耦合的特性,那么复用性更好,维护成本更低,提高开发效率,这些优点就呼之欲出了。

52. vue 的双向数据绑定的原理

Vue2 实现双向数据绑定,object 类型数据是通过 Object 的 defineProperty() 实现的, array 类型数据,是通过拦截重写数组的 7 个可操作且会改变数组自身的方法实现的。

Vue3 则是使用 Proxy 代替 Object.defineProperty 和 重写数组。

更多信息-Vue源码解读:02变化侦测篇

53. 谈谈 vue 实例的生命周期,生命周期钩子都有哪些?

tips:vue2

从官网的生命周期图和源码看,可以大致将vue的生命周期分为4个阶段,分别是初始化阶段,模板编译阶段,挂载阶段,销毁阶段。

初始化阶段:为vue实例初始化属性、事件、数据观测等。

模板编译阶段:将模板字符串编译成渲染函数。(该阶段在runtime版本中不存在,因为已经编译好了。)

挂载阶段:将vue实例挂载到指定dom上,即将模板渲染到真实dom中。

销毁阶段:解绑指令,移除事件监听器,销毁子实例。

与vue生命周期密切相关的钩子函数有beforeCreate,created,beforeMount,mounted,beforeUpdate,updated,beforeDestroy,destroyed。 vue的api文档上,一共有11个和生命周期有关的钩子函数,另外三个分别是activated,deactivated,最后一个是vue2.5.0新增的,叫errorCaptured。

更多信息-Vue源码解读:05生命周期篇

54. 请问 v-if 和 v-show 有什么区别?

v-show 是通过改变 css display 属性值实现切换效果, v-if 则是通过直接销毁或创建 dom 元素来达到显示和隐藏的效果。 v-if是真正的条件渲染,当一开始的值为true时才会编译渲染,而v-show不管怎样都会编译,只是简单地css属性切换。

v-if适合条件不经常改变的场景,因为它的切换会重新编译渲染,会创建或销毁 dom 节点,开销较大。 v-show适合切换较为频繁的场景,开销较小。

55. 你对 vue 中 computed 和 watch 了解?

computed 是计算属性,对于任何复杂逻辑,你都应当使用计算属性,这就是它的应用场景, 虽然通过 methods 或 watch 也能完成, 但是 computed 在处理复杂逻辑时更有优势:计算属性是基于它们的响应式依赖进行缓存的。

watch 是侦听属性,虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch 选项提供了一个更通用的方法, 来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。

Vue 提供了一种更通用的方式来观察和响应 Vue 实例上的数据变动:侦听属性。当你有一些数据需要随着其它数据变动而变动时, 你很容易滥用 watch——特别是如果你之前使用过 AngularJS。然而,通常更好的做法是使用计算属性而不是命令式的 watch 回调。

56. vue 指令的常用修饰符有哪些?

  • v-model 的修饰符
.lazy - 取代 input 监听 change 事件

.number - 输入字符串转为有效的数字

.trim - 输入首尾空格过滤
v-on 的修饰符
.stop - 调用 event.stopPropagation()。

.prevent - 调用 event.preventDefault()。

.capture - 添加事件侦听器时使用 capture 模式。

.self - 只当事件是从侦听器绑定的元素本身触发时才触发回调。

.{keyCode | keyAlias} - 只当事件是从特定键触发时才触发回调。

.native - 监听组件根元素的原生事件。

.once - 只触发一次回调。

.left - (2.2.0) 只当点击鼠标左键时触发。

.right - (2.2.0) 只当点击鼠标右键时触发。

.middle - (2.2.0) 只当点击鼠标中键时触发。

.passive - (2.3.0) 以 { passive: true } 模式添加侦听器
v-bind 的修饰符
.prop - 作为一个 DOM property 绑定而不是作为 attribute 绑定。(差别在哪里?)

.camel - (2.1.0+) 将 kebab-case attribute 名转换为 camelCase。(从 2.1.0 开始支持)

.sync (2.3.0+) 语法糖,会扩展成一个更新父组件绑定值的 v-on 侦听器。

57. 移动端混合开发中的 webview 中,h5 和 原生(IOS 或 安卓)是如何通信的?

主要是利用 window 这个全局对象,在上面注册全局方法(函数),并监听来实现的,当然安卓和iOS略有不同。 下面是一个 h5 通知原生支付,并接受原生支付结果回调的示例。
// 通知原生发起支付
function notifyPay(payType, data) {
  const params = JSON.stringify(data);
  window.acceptPayInfo = function (payResult) {//接收原生支付结果
    if (payResult) {
      store.commit("setPayResult", JSON.parse(payResult));
      localStorage.setItem('setPayResult', JSON.parse(payResult));
      Toast.clear();
      Toast('支付结果:' + payResult)
    }
  };
  // 安卓
  if (window.PKAndroid) {
    // 支付宝
    if (payType === 1) {
      window.PKAndroid.alipay(params);
      return
    }
    // 微信
    window.PKAndroid.wxpay(params);
            return
  }
  // ios
  if (window.webkit) {
    //支付宝
    if (payType === 1) {
      window.webkit.messageHandlers.alipay.postMessage(params);
      return
    }

    //微信
    window.webkit.messageHandlers.wxpay.postMessage(params)
  }
}

58. 说一下 vue 中 key 的作用?

key 的特殊 attribute 主要作用在于给节点做唯一标识,以便高效的更新虚拟 DOM。 在新旧 nodes 对比时辨识 VNodes。如果不使用 key, Vue 会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法。 而使用 key 时,它会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素。

有相同父元素的子元素必须有独特的 key。重复的 key 会造成渲染错误。

59. Vue2中,vue 的父组件的 mounted 和 子组件中的 mounted,哪个先执行?created呢?

父子组件中几个钩子的执行顺序。父组件是子组件的容器,从这角度理解,那么应当是父组件先创建,然后才能容纳子组件创建。 而挂载渲染,子组件作为父组件一部分,父组件的挂载渲染完成,应当以子组件为前提。(特例除外)

所以父created 先于 子created执行,子mounted 先于父mounted执行。
加载渲染:
父beforeCreate -> 父created -> 父beforeMount -> 子beforeCreate 
-> 子created -> 子beforeMount -> 子mounted -> 父mounted
 
子组件更新:
父beforeUpdate -> 子beforeUpdate -> 子updated -> 父updated
 
父组件更新:
父beforeUpdate -> 父updated
 
销毁:
父beforeDestroy -> 子beforeDestroy -> 子destroyed -> 父destroyed

60. vue 几个内置属性的执行顺序,data 先还是 methods 先?

几个内置属性的执行顺序依次是 props =》 methods =》 data =》 computed =》 watch。

更多信息-Vue源码解读:05生命周期篇

61. 介绍下 vue 中的 keep-alive

'keep-alive' 用于缓存不活动的组件实例。

'' 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和 '' 相似,'' 是一个抽象组件: 它自身不会渲染一个 DOM 元素,也不会出现在组件的父组件链中。

当组件在 '' 内被切换,它的 'activated' 和 'deactivated' 这两个生命周期钩子函数将会被对应执行。

62. router 和routerroute 有什么不同?

$router 是包括了路由的钩子函数和跳转方法等的路由实例对象,常用于跳转,例如一个携带参数的跳转:

this.$router.push({name: 'detail', query: { id: "12306" }}) 复制代码

route 可用于获取routerouter.push 携带过来的参数,是路由信息对象,包括 name,query,params 等路由信息。例如下面这样使用:

this.id = this.$route.query.id; 复制代码

63. css 怎样穿透样式?穿透符能穿透修改 vue #app 节点外元素的样式吗?

    1. ::v-deep vue3.0 开始,可使用 ::v-deep 替代 /deep/
<style lang="scss" scoped> ::v-deep .el-input { width: 120px;
   } </style> 复制代码
    1. /deep/ vue2 中可使用 /deep/ 穿透样式
<style lang="scss" scoped> /deep/ .el-input { width: 120px;
   } </style> 复制代码

-3. >>> 仅对 css 有效,对于 css 预处理语言,例如 scss、less 不生效。

对于 vue 中 div#app 节点外的元素样式,如果 '' 加上了 scoped,那么此时样式穿透符是不能穿透修改 div#app 节点外的元素样式的。 这是因为 scoped 的作用域仅局限在 div#app 容器内部,所以此时只能修改 div#app 容器内的样式。 例如 el 组件的下拉选的弹出层是 div#app 的兄弟元素,body的子元素,在 '' 中使用样式穿透符修改该弹出层的样式是无效的。

64. vue-router 全局的 afterEach 守卫钩子先执行,还是组件内的 beforeRouteEnter 钩子先执行?

全局后置守卫钩子 afterEach 先执行,组件内的 beforeRouteEnter 钩子后执行。

完整的导航解析流程(来自 vue-router 官网) 1.导航被触发。 2.在失活的组件里调用 beforeRouteLeave 守卫。 3.调用全局的 beforeEach 守卫。 4.在重用的组件里调用 beforeRouteUpdate 守卫(2.2+)。 5.在路由配置里调用 beforeEnter。 6.解析异步路由组件。 7.在被激活的组件里调用 beforeRouteEnter。 8.调用全局的 beforeResolve 守卫(2.5+)。 9.导航被确认。 10.调用全局的 afterEach 钩子。 11.触发 DOM 更新。 12.调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。 复制代码

65. 清除浮动的方式

①使用clear属性清除浮动。

②创建BFC环境,利用BFC的特性,BFC具有 排除外部浮动和包含内部浮动的特性。 例如,通过 display: flow-root, 为元素创建 BFC,从而实现清除元素外部浮动覆盖的影响。

BFC 的产生条件:

  • overflow 值不为 visible、clip 的块元素。overflow 的默认值是 visible。
  • 绝对定位元素(position 值为 absolute 或 fixed),position 的默认值是 static。
  • 弹性元素(display 值为 flex 或 inline-flex 元素的直接子元素),如果它们本身既不是flex、grid也不是table容器。
  • 行内块元素(display 值为 inline-block)
  • display 值为 flow-root 的元素。flow-root 可以创建一个无副作用的 BFC,就像 html 根元素那样。 但需注意 flow-root 的兼容性, 它是一个较新的属性,IE 全系列不支持,Chrome58,Firefox53,Edge79开始支持。

66. 典型的可替换元素有哪些?

html 规范上说可以被视为替换元素的有:audio, canvas, embed, iframe, img, input, object, 和video。

developer.mozilla 上列明的典型的可替换元素只有下面几个:

  • 'iframe'
  • 'video'
  • 'embed'
  • 'img'

而其他元素仅在特定情况下作为可替换元素处理:

  • 'option'
  • 'audio'
  • 'canvas'
  • 'object'
  • 'applet'

HTML 规范也说了元素可替换,因为 "image" 类型的元素就像一样被替换。 但是其他形式的控制元素,包括其他类型的元素,被明确地列为非可替换元素(non-replaced elements)。

所以,如果强调典型的可替换元素,那么 iframe,video,embed,img 更合适作为代表。

67. img 标签是块级元素吗?行内元素和块级元素有哪些?行内元素的 padding 和 margin 设置会生效吗?

行内元素:

span, a, i, br, img, button, input, label, select, textarea

b, big, small, tt, abbr, acronym, cite, code, dfn, em, kbd,

strong, samp, var, bdo, map, object, q, script, sub, sup

以下是 HTML 中所有的块级元素列表(虽然”块级“在新的 HTML5 元素中没有明确定义):

p, div, form, h1-h6, header, footer, ul, ol, table

address, article, aside, blockquote, dd, dl, fieldset, figcaption, figure, hgroup, hr, pre, section,

所以 img 是行业元素,也是典型的可替换元素(replaced element)。

以 span 为例的行内元素的宽高边距有效性: width:无效。 height:无效。 margin:left 和 right 有效,top 和 bottom无效。 padding:left 和 right 有效,top 会覆盖前面的元素,bottom 会和后面的元素重叠。

因为 img 还是可替换元素(replaced element)又称置换元素,所以与 span 不同可设置宽高。

68. js 能改变数组自身的数组方法有哪些?

push(),pop(),shift(),unshift(),splice(),sort(),reverse()是7个可改变自身的数组的方法。 它们主要是通过对数组添加或删除或排序元素,来改变原数组本身。

更多信息-vue源码中重写的7个数组方法

69. 用过 Vue.nextTick 吗?你是怎么理解 Vue.nextTick 的?

用法:在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。

应用场景:因为 vue 是异步执行 dom 更新的,所以当你希望在更新数据之后,操作新的视图, 那么你的操作逻辑应写在 Vue.nextTick(callback) 的回调中,而这个回调会在dom 更新循环结束之后执行。 否则,因为异步更新 dom 的原因,如果你不是在 Vue.nextTick(callback) 的回调中执行操作新视图, 那么可能会发生意外。例如你在 created()钩子 是不能操作 dom 的,但你可以在此调接口更新数据, 如果你此时希望接口更新完毕数据后,接着调用操作 dom 的逻辑,那么最后将这部分操作 dom 的逻辑, 放置在Vue.nextTick(callback) 的回调函数中。

$nextTick 的原理:

70. 用过 Nginx 吗?对 Nginx 有哪些了解?

Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务。 Nginx是由伊戈尔·赛索耶夫为俄罗斯访问量第二的Rambler.ru站点(俄文:Рамблер)开发的.

  • 反向代理,负载均衡。 有时单台服务器,无法满足大量用户同时访问,需要服务集群以支持,保证应用的可用性。 nginx 做反向代理,可以代理分发,可以使得多台服务器能够平均分担负载。

我用到 nginx 的地方是:

  • 一是作为 http 服务器,为我做测试实验,以及一些静态资源提供 http 服务。

  • 二通过 nginx 代理实现跨域。

  • 三是利用 nginx 的代理转发,实现同一域名下部署多个项目。

  • 四是配置黑白名单,限制ip访问 这主要是利用 allow 和 deny 实现

allow xxx.xxx.xxx.xxx; # 允许指定的IP访问,白名单 deny xxx.xxx.xxx.xxx; # 禁止指定的IP访问,黑名单 复制代码

当白名单ip或黑名单ip数量比较多的时候, 可以集中写在 .conf 的文件中,然后通过 include 指令引入

http{ # 禁止 denyip.conf 文件中的ip访问 include /ip/denyip.conf; 
 server{
    location /my-app { # /my-app 下的资源访问白名单: allowip.conf 中的ip include /ip/allowip.conf; 
    }
 }
} 复制代码
  • 五是Nginx配置SLL证书

  • 六是做一些压缩配置

http{ # 开启压缩 on/off gzip on; # 设置要压缩的文件类型 gzip_types image/gif image/png; # 指定压缩级别,值越大压缩程度越高 gzip_comp_level 3; # 指定开启压缩的最小阈值 gzip_min_length 4k; # 指定压缩请求的缓冲数量和大小 gzip_buffers 10 5k; # 可以指定不开启压缩的客户端类型,例如一些低版本的ie本身不支持压缩  gzip_disable "MSIE [1-5]\."; # 指定压缩处理支持的最低 http 版本 gzip_http_version 1.1; } 复制代码

更多信息-Nginx配置-vue项目打包部署篇

71. 使用过 sass 和 less 吗?使用 CSS 预处理语言的优缺点是什么?

优点: 在 CSS 语法的基础上增加了变量 (variables)、嵌套 (nested rules)、混合 (mixins)、导入 (inline imports) 等高级功能, 这些拓展令 CSS 更加强大与优雅。提高样式的可维护性,一定程度上可以提高工作效率。

缺点:浏览器“不认识” css 预处理语言,需要预处理工具转换才能在浏览器上生效,重新编译的耗时可能略微大于原生 css。

72. 介绍下 vuex

官网:Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。 它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

vuex 核心:

  • State。共享的的全局的的属性或状态,主要在 state 中声明存放。

  • Getter。Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。 注意从 Vue 3.0 开始,getter 的结果不再像计算属性一样会被缓存起来。

  • Mutation。更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。 Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的事件类型 (type)和一个回调函数 (handler)。 这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数

  • Action。 Action 类似于 mutation,不同在于:Action 提交的是 mutation,而不是直接变更状态。Action 可以包含任意异步操作。

  • Module。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。 每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割。

73. 几个浏览器 css 兼容性写法

CSS非标准属性。厂商在实现非标准的CSS属性时,通常会加上前缀,甚至在将来会实现的标准也加。当标准被发布后,厂商会将前缀移除。

  • Firefox:-moz-,

  • Chrome和Safari: -webkit-,

  • IE:-ms-,

  • Opera:-o-。

  • 书写建议私有属性(非标准)放在前面,标准属性写在后面

下面是一个示例:

-webkit-transform:rotate(-3deg); /* Chrome/Safari */ -moz-transform:rotate(-3deg); /* Firefox */ -ms-transform:rotate(-3deg); /* IE */ -o-transform:rotate(-3deg); /* Opera */ transform:rotate(-3deg); /* 标准属性写在后面 */ 复制代码

74. js脚本一定会阻塞浏览器渲染文档吗?

不一定。

浏览器解析器遇到script脚本的解析逻辑:

1.情形一:页面中引入的script脚本会阻塞浏览器解析渲染文档。

浏览器解析文档时,默认是按照排列顺序向下解析的,当遇到script标签时,和其他标签元素一样(例如一个div), 会先解析该元素(script脚本),解析完成后再继续向下走完成剩余文档的解析和渲染。也就是说默认情况下,script脚本会阻塞文档的解析渲染。

注意,如果我们的script脚本是放在页面底部的内联脚本,那么它对文档的解析渲染,在结果上影响不大。

但如果script脚本是外部脚本(通过网址引入的那种),那么这个脚本需要下载和解析执行, 这期间会阻塞浏览器对文档的向下解析渲染,直至脚本下载执行完成,才会继续向下解析渲染。如果这个脚本出错了, 可能还会导致整个页面永远无法正常渲染呈现。

注意,DOM树的生成是受JavaScript代码执行影响的,JavaScript代码会“阻塞”页面UI的渲染。

2.情形二:页面中引入的script脚本不会阻塞浏览器解析渲染文档。

情形一中提到的脚本执行的同步和阻塞的情形,是指默认情况下的script脚本加载方式。script标签有两个属性,一个是 defer(暂翻译为延迟), 二是 async(暂翻译为异步,没错,和我们的常见的ajax和axios的异步是一个意思), 这两个属性都可以改变脚本的加载执行方式(在浏览器支持的情况下,这两的兼容性,后面会补充)。

defer(延迟):延迟是指当浏览器解析到 script 脚本时,会继续向下载入和解析文档,等到文档载入解析完成且可以操作文档时,才开始执行脚本。

async(异步):异步是指当浏览器解析到script脚本时,会立刻下载和执行脚本,但同时浏览器解析器也会继续向下解析渲染文档, 不会造成阻塞的现象。这使得脚本可以尽快的被载入执行,这很想我们前端调用post异步接口,并不影响文档的正常解析渲染。

ps:defer 和 async 属性像是在告诉浏览器,链接进来的脚本不会使用 document.write(),也不会生成文档内容, 因此浏览器在下载脚本时可以继续解析和渲染文档。

值得注意的是,使用 defer 属性的脚本,当有多个的时候, 这些脚本会按照他们在文档中排列的顺序载入执行。而使用 async 属性的脚本,当有多个的时候,会顺序开始触发载入, 但谁先完成载入就谁先执行,这就是说,他们的执行顺序可能是无序不确定的。在有的时候知道这点很重要,因为这可能涉及一些有强制顺序的逻辑处理。

更多信息-js脚本一定会阻塞浏览器渲染文档吗?script标签的async和defer属性

75.line-height 如何继承?

父元素的 line-height 写了具体数值,比如 14px,则子元素 line-height 继承该值。 父元素的 line-height 写了比例,比如 2 或 3,则子元素 line-height 也是继承该比例。 父元素的 line-height 写了百分比,比如 300%,则子元素 line-height 继承的是父元素 font-size * 300% 计算出来的值。

76.数据类型与赋值

JavaScript 语言中类型集合由原始值和对象组成,数据类型有哪些?

js 中的 8 种数据类型: 7种原始值:Undefined、 Null、 Boolean、 Number、 String、 Symbol、 BigInt。 对象:Object。

Symbol es6(ECMA2015) 新增的数据类型。 Symbol 的值具有唯一性,常用用法是定义对象的唯一属性名。 BigInt 可以表示任意大小的整数。BigInt,ECMAScript 2020 新增。

不同数据类型赋值情况

数据类型的判断方法?

typeof:能判断原始值类型(Number,String,Boolean)。不能用于精确判断 null、对象、数组,因为都返回 object 。

var value = null; console.log(typeof value, typeof value === 'object'); // object true value = "hello"; console.log(typeof value, typeof value === 'string'); // string true value = 23; console.log(typeof value, typeof value === 'number'); // number true value = false; console.log(typeof value, typeof value === 'boolean'); // boolean true value = [2] console.log(typeof value, typeof value === 'array'); // object false 复制代码

instanceof:能判断对象类型,不能判断原始值数据类型,其内部运行机制是判断在其原型链中能否找到该类型的原型。

var value = "hello"; console.log(value instanceof String); // false, 不能用于判断原始值类型的数据类型 var value = null; console.log(value instanceof Object); // false, 不能用于判断原始值类型的数据类型 value = [11] console.log(value instanceof Array); // true value = {} console.log(value instanceof Object); // true 复制代码
Object.prototype.toString.call():所有原始数据类型都是能判断的,还有 Error 对象,Date 对象等。

判断一个变量是否为数组?

// 方法一:变量 instanceof Array var arr = [1, 2] console.log(arr instanceof Array); // true // 方法二:变量.constructor === Array console.log(arr.constructor === Array) // true // 方法三:Array.isArray(变量) console.log(Array.isArray(arr)) // true // 方法四:利用 isPrototypeOf(变量) console.log(Array.prototype.isPrototypeOf(arr)) 复制代码

77.数组去重

方法一:new Set()结合 拓展符... 简单的数组,去重可以可以利用 es6 的 set 关键字结合拓展符号... 实现

var arr = [1, 2, 'hello', 34, 2, 5, 34, 'hello'] function unique(arr) { return [...new Set(arr)];
} console.log(unique(arr)) // 去重后:[1, 2, 'hello', 34, 5] 复制代码

方法二:数组的 filter 结合 indexOf

var arr = [1, 2, 'hello', 34, 2, 5, 34, 'hello', 2] function unique(arr) { // filter 返回表达式为 true 的数据项 return arr.filter((item, index, array) => { // indexOf 返回的是数组第一个匹配的数据项的下标 // 当前 index 和 indexOf 返回的下标不同,说明有数据项和当前数据项相同 console.log(array.indexOf(item), index); // 0 0 // 1 1 // 2 2 // 3 3 // 1 4 // 5 5 // 3 6 // 2 7 // 1 8 return array.indexOf(item) === index;
  });
} console.log(unique(arr)) // 去重后:[1, 2, 'hello', 34, 5] 复制代码

对于复杂数组的去重,需要确定重复的根据,例如id重复算重复,还是某个或某些key重复才算重复。

/**
 * 根据数组对象的某个字段值去重
 * key 字段的键名,例如[{name:1}] 根据每条数据的name值来去重
 * */ function unique (arr, key) { const res = new Map() return arr.filter(item => !res.has(item[key]) && res.set(item[key], 1))
} 复制代码

78.函数柯里化(Currying)

---来源维基百科 在计算机科学中,柯里化(英语:Currying),又译为卡瑞化或加里化,是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数, 并且返回接受余下的参数而且返回结果的新函数的技术。这个技术由克里斯托弗·斯特雷奇以逻辑学家哈斯凯尔·加里命名的, 尽管它是Moses Schönfinkel和戈特洛布·弗雷格发明的。

在直觉上,柯里化声称“如果你固定某些参数,你将得到接受余下参数的一个函数”。所以对于有两个变量的函数yx,如果固定了 y = 2,则得到有一个变量的函数 2x。

在理论计算机科学中,柯里化提供了在简单的理论模型中,比如:只接受一个单一参数的lambda演算中,研究带有多个参数的函数的方式。

函数柯里化的对偶是 Uncurrying,一种使用匿名单参数函数来实现多参数函数的方法。例如:

所以下面这个例子,到底是 Currying 还是 Uncurrying?

var foo = function(a) { return function(b) { return a * a + b * b;
  }
} // 这样调用上述函数: // (foo(3))(4),或直接foo(3)(4) 复制代码

我看了维基百科的介绍,尤其是还引出了函数柯里化的对偶 Uncurrying,我对函数柯里化更加不解了。 确实难为我一个技术工了,这也许就是技术员和研究员的区别吧。

我的疑惑是上面这个例子到底是 Currying 还是 Uncurrying?我的疑惑在于维基百科中文版的介绍表述, 而后查了一些工程师的关于函数柯里化的解释,大家似乎一致认为,上面的例子就是 Currying, 所以我决定把我的认知统一到这来。

我回忆并查阅了mdn文档和《JavaScript权威指南》第六版,似乎没提到函数柯里化这个概念, 所以我想这可能不是单纯的js中的内容。当然,维基百科中提到,它被归属于计算机科学领域。

认知统一后,加强记忆和理解,小结一下函数柯里化(Currying)的要点特征: 把接受多个参数的函数变换成接受一个参数的函数,并让它返回一个函数去处理剩下的参数。

举例如下:

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>函数柯里化demo</title> </head> <body> <h1>函数柯里化demo</h1> <script> // 一个有名的求和例子:接收多个参数的函数 function add (x, y, z) { return x + y + z
  } // Currying 柯里化的写法:把接受多个参数的函数变成接受单个参数的函数,并返回了匿名函数去处理剩余参数 function addCurrying (x) { return function (y) { return function (z) { return x + y + z
      }
    }
  } console.log(add(1, 2, 3)) // addCurrying 可以这样调用,也可以像后面那样分开调用 console.log(addCurrying(1)(2)(3)) var addCurryingX = addCurrying(1) // 柯里化,接受一个参数x,返回一个处理y的函数 var addCurryingXY = addCurryingX(2) // 接受一个参数y,返回一个处理z的函数 var addCurryingXYZ = addCurryingXY(3) // 接受一个参数z,返回一个值 console.log(addCurryingX) console.log(addCurryingXY) console.log(addCurryingXYZ) </script> </body> 复制代码

函数柯里化的作用:

  • 参数复用
  • 延迟计算
  • 动态生成函数

79.高阶函数

高阶函数英文叫 Higher-order function。高阶函数是对其他函数进行操作的函数,操作可以是将它们作为参数, 或者返回它们。简单总结为高阶函数是一个接收函数作为参数或者将函数作为返回输出的函数

js内置的高阶函数:Array.prototype.map,Array.prototype.filter,Array.prototype.reduce 和 Array.prototype.sort

vue 中 的 nextTick

80.vue2 data 为啥是函数而不是对象?

vue 中 data 必须是函数是为了保证组件的独立性和可复用性, 组件中实例化的,组件的 data 是函数,函数返回一个对象,计算机会给这个对象分配一个内存地址。 这样,每次实例化 data 返回的对象,就会被分配不同的内存地址。而不是指向同一个内存地址。 这样数据就具备了独立性,不同实例的 data 状态改变也就不会有相互影响, 从而保证了组件的独立性和可复用性。

居中的几种实现方式

水平居中和垂直居中

离职原因

关于 css 动画 和 GPU

手写深拷贝

javascript:this

模块化、服务端渲染、用原型链处理过的实际问题

构建工具

webpack 等

mvvm 和 mvc

函数编程与面向对象编程

函数式编程(Functional Programming, FP)

计算机著名定论:

程序 = 数据结构 + 算法

无论什么编程范式,都要处理数据结构和算法。如果把算法看成某种逻辑行为,那么程序 = 数据 + 行为。

...

四、高阶部分

关于设计模式

关于设计原则

开闭原则,单一职责

开闭原则,在面向对象编程领域中,规定“软件中的对象(类,模块,函数等等)应该对于扩展是开放的, 但是对于修改是封闭的”,这意味着一个实体是允许在不改变它的源代码的前提下变更它的行为。 该特性在产品化的环境中是特别有价值的,在这种环境中,改变源代码需要代码审查, 单元测试以及诸如此类的用以确保产品使用质量的过程。遵循这种原则的代码在扩展时并不发生改变,因此无需上述的过程。 (__摘自百科)

...

关于算法

冒泡算法、折半算法...

五、写在后面

tips:学识有限,难免错漏,仅供参考。

“尽管八股的意义重牢笼而轻选材,尽管直接编织牢笼的大多非是资本而正是打工人,然而现实如此, 一时又难以改变,因为我们没有有力的工会,八小时工作制在李da钊先生时期就旗帜鲜明的提出,很遗憾先人不再,后人少有智勇...终是思想未达,仍需努力”

我信条是:“一个普通程序员,努力上进,也想,活在当下。” 抱怨这也不行,那也不行,不如一起加油,在梦里做一个改变世界的“天下第一等程序员”,相信新一代的程序员会带来新的风气。

一起加油吧,努力建设自己的思想体系和技术体系。下面是之前写的几个字,祝愿我们都能马到功成, 可以开心的过好每一个今天,无论风雪。





#Python##面试复盘##前端#
全部评论
80左右的复习计划
点赞 回复 分享
发布于 2022-10-23 16:08 河南

相关推荐

11-18 17:08
已编辑
广东金融学院 前端工程师
#软件开发笔面经# 1.为什么考虑做前端?2.js数据类型3.0==true是不是正确的?为什么?4.基本和引用数据类型在存储上有什么区别?5.什么是闭包?为什么内部变量不会被销毁?6.闭包有什么好处?有缺点?7.var&nbsp;let&nbsp;const有什么区别?&nbsp;8.for循环用var和let定义i,&nbsp;console.log(i)有什么区别?9.箭头函数和function函数有什么区别?10.如何更改this指向?11.apply&nbsp;call&nbsp;bind的区别12.在滑动页面时&nbsp;,&nbsp;会一直触发某事件&nbsp;,&nbsp;如何降低触发频率?13.用next.js+react&nbsp;和&nbsp;纯react写项目有什么区别?14.这两种方案写单页面时有什么不一样?有哪些痛点?15.服务端渲染和客户端渲染是什么?16.如何在react父子组件之间传参?子组件如何控制父组件的属性?跨层级如何传参?17.异步是靠什么实现的?es6新增了什么来实现异步?18.你怎么理解promise?内部有几种状态?在写代码时如何处理这三种状态?19.遇到多个接口需要处理时,&nbsp;会出现多个then嵌套,&nbsp;如何解决这种嵌套情况?(接口之间存在依赖关系)20.foreach和map有什么区别?reduce是用来干嘛的?21.some和any是用来干嘛的?那&nbsp;filter&nbsp;呢?&nbsp;find?22.浮动流和布局流是什么?会分别用在哪些方面?23.现在有一个数组,&nbsp;数组里面有n个元素,&nbsp;每个奇数项的颜色是绿色,&nbsp;偶数项是红色,&nbsp;可以用什么方法来实现?24.重排和重绘是什么?25.你是怎么理解虚拟DOM的? #软件开发笔面经#
查看25道真题和解析 软件开发笔面经
点赞 评论 收藏
分享
评论
20
90
分享
牛客网
牛客企业服务