面经

职位要求

1、2023届获得本科及以上学历,计算机相关专业;

2、精通HTML、CSS、JS,熟悉页面架构和布局,熟悉HTML5/CSS3等常用技术;

3、熟悉常用UI框架(如bootstrap/pure/kendo等);

4、精通JavaScript、AJAX、DOM、jQuery等技术;

5、熟悉NodeJS,熟练使用Grunt、Gulp、Webpack等构建工具;

6、良好的沟通和团队协作能力、热爱技术、责任心强、能推动技术框架的落地使用。

7、具备MVVM框架开发经验,如React、VueJS、AngularJS等;

8、有 Node.js 或其他后端编程语言经验者优先;

9、有开源作品或者技术博客,社区活跃者优先;

10、具备一定算法基础;

11、掌握常见网络协议和相关的其他底层网络协议的全面知识;

12、能熟练使用git或者SVN;

13、了解常见的web/app/小程序前后端系统架构;

14、能熟练使用MySQL/MongoDB等数据库;

15、有jQuery、node.js等js框架使用及扩展编写经验者优先;

16、了解redis/memcache等缓存中间件者优先;

16、有性能优化方面的经验者优先;

面经

[TOC]

HTML篇

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

用正确的标签做正确的事情。
html 语义化让页面的内容结构化,结构更清晰,便于对浏览器、搜索引擎解析;即使在没有样式 CSS 情况下也以一种文档格式显示,并且是容易阅读的。
搜索引擎的爬虫也依赖于 HTML 标记来确定上下文和各个关键字的权重,利于 SEO;
使阅读源代码的人对网站更容易将网站分块,便于阅读维护理解。

初探 · HTML5语义化 - 知乎 (zhihu.com)

<img>标签上 title 与 alt 属性的区别是什么?

alt 是给搜索引擎识别,在图像无法显示时的替代文本;
title 是关于元素的注释信息,主要是给用户解读。
当鼠标放到文字或是图片上时有 title 文字显示。

href与src的区别?

  • href:指定资源的位置,用于建立当前页面与引用资源之间的关系(链接),
  • src:(source的缩写),指向外部资源的位置,指向的内容将会应用到文档中当前标签所在位置。
  • 遇到href,页面会并行加载后续内容;而src则不同,浏览器需要加载完毕src的内容才会继续往下走。

很多网站不常用table iframe这两个元素,知道原因吗?

因为浏览器页面渲染的时候是从上至下的,而table 和 iframe 这两种元素会改变这样渲染规则,他们是要等待自己元素内的内容加载完才整体渲染。用户体验会很不友好。

HTML5新增了哪些新特性?

html5新特性总结 - 斌果 - 博客园 (cnblogs.com)

  • 新的语义标签

  • 标签 描述
    <header> 定义了文档的头部区域
    <footer> 定义了文档的尾部区域
    <nav> 定义文档的导航
    <section> 定义文档中的节
    <article> 定义文章
    <aside> 定义页面以外的内容
    <details> 定义用户可以看到或者隐藏的额外细节
    <summary> 标签包含details元素的标题
    <dialog> 定义对话框
    <figure> 定义自包含内容,如图表
    <main> 定义文档主内容
    <mark> 定义文档的主内容
    <time> 定义日期/时间
  • 画布(Canvas) API

  • 地理定位(Geolocation) API

  • 本地离线存储 localStorage 长期存储数据,浏览器关闭后数据不丢失;
    sessionStorage 的数据在浏览器关闭后自动删除

  • 新的技术webworker, websocket, Geolocation

  • 拖拽释放API

  • 音频、视频API(audio,video)

  • 表单控件,calendar、date、time、email、url、searc

块级标签,行内标签,行内块标签

  • 块级元素:独占一行,对宽高的属性值生效;如果不给宽度,块级元素就默认为浏览器的宽度,即就是100%宽;

    块标签:包含p、div、ul、ol、li、dl、dt、h1~h6、form;

  • 行内元素:可以多个标签存在一行,对宽高属性值不生效,完全靠内容撑开宽高!

    行内标签:包含a、span、em、i、strong、b、ins、u、label、br;

  • 行内块元素:结合的行内和块级的有点,不仅可以对宽高属性值生效,还可以多个标签存在一行显示;

    行内块标签:img,input,textarea

  • 各种标签之间的转换

    • 块级标签转换为行内标签:display:inline;
    • 行内标签转换为块级标签:display:block;
    • 转换为行内块标签:display:inline-block;

XHTML和HTML的区别

  • html元素必须正确嵌套,不能乱;
  • 属性必须是小写的;
  • 属性值必须加引号;
  • 标签必须有结束,单标签也应该用 “/” 来结束掉;

每个HTML文件里开头都有个很重要的东西,Doctype,知道这是干什么的吗?

声明位于文档中的最前面的位置,处于 标签之前。此标签可告知浏览器文档使用哪种 HTML 或 XHTML 规范。(重点:告诉浏览器按照何种规范解析页面)

你能描述一下渐进增强和优雅降级之间的不同吗?

  • 渐进增强 progressive enhancement:针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验。
  • 优雅降级 graceful degradation:一开始就构建完整的功能,然后再针对低版本浏览器进行兼容。

DOM树和渲染树有什么区别?

答:

  • HTML 经过解析生成 DOM树; CSS经过解析生成Style Rules。 二者一结合生成了渲染树。通过layout计算出DOM要显示的宽高、位置、颜色。 最后渲染在界面上,用户就看到了。
  • 浏览器的渲染过程:
    • 解析 HTML 构建 DOM(DOM 树),并行请求 css/image/js
    • CSS 文件下载完成,开始构建 CSS 树
    • CSS树构建结束后,和 DOM 一起生成渲染树
    • 布局(Layout):计算出每个节点在屏幕中的位置
    • 显示(Painting):通过显卡把页面画到屏幕上
  • DOM树和渲染树的区别:
    • DOM 树与 HTML 标签一一对应,包括 head 和隐藏元素
    • 渲染树不包括 head 和隐藏元素,大段文本的每一个行都是独立节点,每一个节点都有对应的 css 属性
  • 对于一个HTML文档来说,不管是内联还是外链的css,都会阻碍后续的dom渲染,但是不会阻碍后续dom的解析。
  • 当css文件放在中时,虽然css解析也会阻塞后续dom的渲染,但是在解析css的同时也在解析dom,所以等到css解析完毕就会逐步的渲染页面了。

重绘和回流(重排)的区别和关系?

答:

  • 重绘:当渲染树中的元素外观(如:颜色),不影响布局时,产生重绘
  • 回流:当DOM树中的元素的布局(如:尺寸、位置、隐藏/状态)发生改变时,产生重绘回流。
  • 注意:JS 获取 Layout 属性值(如:offsetLeft、scrollTop、getComputedStyle 等)也会引起回流。因为浏览器需要通过回流计算最新值
  • 回流必将引起重绘,而重绘不一定会引起回流。

触发回流的事件有哪些?

  • 添加或删除可见的DOM元素
  • 元素位置改变
  • 元素尺寸改变(包括:内外边距、边框厚度、高度等属性的改变)
  • 内容改变
  • 页面渲染器初始化
  • 浏览器窗口尺寸变化

如何最小化重绘(repaint)和回流(reflow)?

  • 需要要对DOM元素进行复杂操作时,可以先隐藏(display: none),操作后再显示。
  • 需要创建多个 DOM 节点时,使用DocumentFragment创建完后一次性的加入 document,或使用字符串拼接方式构建好对应HTML后再使用innerHTML来修改页面
  • 缓存 Layout 属性值,如:var left = elem.offsetLeft; 这样,多次使用 left 只产生一次回流
  • 避免用 table 布局(table 元素一旦触发回流就会导致 table 里所有的其它元素回流)
  • 避免使用 css 表达式(expression),因为每次调用都会重新计算值(包括加载页面)
  • 尽量使用 css 属性简写,如:用 border 代替 border-width, border-style, border-color
  • 批量修改元素样式:elem.className 和 elem.style.cssText 代替 elem.style.xxx

CSS篇

盒子模型的介绍

盒模型: 内容(content)、填充(padding)、 边框(border)、边界(margin);

类型:IE盒子模型,标准W3C盒子模型

区 别: IE 的 content 部分把 border 和 padding 计算了进去;

css 选择器优先级?

  • 单个选择器:

    !important > 内联样式(比重1000)> ID 选择器(比重100) > 类选择器(比重10) > 标签(比重1) > 通配符 > 继承 > 浏览器默认属性

  • 复合选择器:

CSS中的选择器?

  • *全局匹配
  • 标签选择器
  • 类选择器
  • 伪类选择器
  • ID选择器
  • 派出选择器
  • 属性选择器
  • 关系选择器

水平居中有哪些方式?

  • 行级元素文字居中:text-align: center;

  • 绝对定位元素居中实现:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <style>
    .center-vertical {
    width: 100px;
    height: 100px;
    background: orange;
    position: absolute;
    left: 50%;
    /* margin-left: -50px; */
    /*宽度的一半*/
    transform: translate(-50%, 0);
    }
  • margin: auto;实现绝对定位元素的居中

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    .center-vertical {
    width: 100px;
    height: 100px;
    background: orange;
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    margin: 0 auto;
    }
  • 水平居中,弹性布局:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    body {
    display: flex;
    /* align-items: center; */
    /*定义body的元素垂直居中*/
    justify-content: center;
    /*定义body的元素水平居中*/
    }

    .content {
    width: 300px;
    height: 300px;
    background: orange;
    }
  • 相对定位

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    .content{
    width: 300px;
    height: 300px;
    background: orange;
    margin: 0 auto;/*水平居中*/
    position: relative;/*设置position*/
    top: 50%; /*偏移*/
    /*margin-top: -150px;*/ /*第一种:margin-top*/
    transform: translateY(-50%);/*第二种:transform:转换*/
    }
  • 表格文字居中:

    1
    <td rowspan="2" align="center" valign="middle">

如何实现表格跨行跨列:表格属性colspanrowspan

垂直居中几种方式?

  • 单行文本: line-height = height
  • 图片: vertical-align: middle;
  • flex: justify-content:center
  • transform + absolute : top: 50%;left: 50%;transform: translate(-50%, -50%);
  • absolute+margin负值:top: 50%;left: 50%;margin-top: -50px;margin-left: -100px;
  • 相对定位:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    .content {
    width: 300px;
    height: 300px;
    background: orange;
    position: relative;
    /*设置position*/
    top: 50%;
    /*偏移*/
    /*margin-top: -150px;*/
    /*第一种:margin-top*/
    transform: translateY(-50%);
    /*第二种:transform:转换*/
    }
  • 加载顺序:link是先将css文件加载到网页,然后再进行编译。@import是先加载完html结构再加载css文件,如果网速较慢则会影响视觉效果。
  • 兼容性:link是xhtml标签无兼容问题,@import是css2.1提出的所以不支持IE5以前的浏览器。
  • DOM支持:link支持DOM改变样式,@import不支持。

rgba和opacity的透明效果有什么不同?

  • opacity :子元素会继承父元素的 opacity 属性;
  • RGBA :设置的元素的后代元素不会继承不透明属性。

display:none和visibility:hidden的区别?

  • display:none :隐藏对应的元素,在文档布局中不再给它分配空间,它各边的元素会合拢,就当他从来不存在;
  • visibility:hidden :隐藏对应的元素,但是在文档布局中仍保留原来的空间。

有哪些方式可以对一个DOM设置它的CSS样式?

  • 外部样式表,引入一个外部css文件
  • 内部样式表,将css代码放在 标签内部
  • 内联样式,将css样式直接定义在 HTML 元素内部

文档流是什么?

文档流也称为普通流,即网页在解析时,遵循从上向下,从左向右的顺序。

脱离文档流:文档流内的正常元素识别不到这个元素了(脱离文档流的元素相当于平行漂浮在文档流之上)。

标准文档流等级:分为两个等级块级元素和行内元素。

css中的定位机制,共三种:

  1. 正常的文档流
  2. float
  3. postion的absolute
  4. flex

position的值, relative和absolute分别是相对于谁进行定位的?

  • relative:相对定位,相对于自己本身在正常文档流中的位置进行定位。
  • absolute:生成绝对定位,相对于最近一级定位不为static的父元素进行定位。
  • fixed: (老版本IE不支持)生成绝对定位,相对于浏览器窗口或者frame进行定
  • static:默认值,没有定位,元素出现在正常的文档流中。
  • sticky:生成粘性定位的元素,容器的位置根据正常文档流计算得出。

div+css的布局较table布局有什么优点?

  • 改版的时候更方便 只要改css文件。
  • 页面加载速度更快、结构化清晰、页面显示简洁。
  • 表现与结构相分离。
  • 易于优化(seo)搜索引擎更友好,排名更容易靠前。

如何创建块级格式化上下文(block formatting context),BFC有什么用?

  • 什么是BFC?

    ​ BFC格式化上下文,它是一个独立的渲染区域,让处于 BFC内部的元素和外部的元素相互隔离,使内外元素的定位不会相互影响

  • 如何产生BFC?

    1
    2
    display: inline-block
    position: absolute/fixed
  • BFC作用

    ​ BFC最大的一个作用就是:在页面上有一个独立隔离容器,容器内的元素和容器外的元素布局不会相互影响。

CSS3有哪些新特性?

  • 弹性盒模型 display: flex;

  • 颜色透明度 color: rgba(255, 0, 0, 0.75);

  • 圆角 border-radius: 5px;

  • 阴影 box-shadow:3px 3px 3px rgba(0, 64, 128, 0.3);

  • 2d,3d变换;

  • 平滑过渡 transition: all .3s ease-in .1s;

    动画 @keyframes anim-1 {50% {border-radius: 50%;}} animation: anim-1 1s;

  • 新增伪类选择器::checked、:enabled、:disabled

  • 暂略

CSS3动画(简单动画的实现,如旋转等)

​ 依靠CSS3中提出的三个属性:transition、transform、animation

  • transition:定义了元素在变化过程中是怎么样的,包含transition-property、transition-duration、transition-timing-function、transition-delay。
  • transform:定义元素的变化结果,包含rotate、scale、skew、translate。
  • animation:动画定义了动作的每一帧(@keyframes)有什么效果,包括animation-name,animation-duration、animation-timing-function、animation-delay、animation-iteration-count、animation-direction

常见兼容性问题?

  • 浏览器默认的margin和padding不同。解决方案是加一个全局的*{margin:0;padding:0;}来统一。
  • Chrome 中文界面下默认会将小于 12px 的文本强制按照 12px 显示,
    可通过加入 CSS 属性 -webkit-text-size-adjust: none; 解决.

什么是响应式布局?与自适应布局有什么区别?怎么实现?

答:

响应式布局:在实现不同分辨率的终端上浏览网页的不同展示方式。

  • 响应式布局只开发一套代码,通过检测视口的分辨率,针对不同客户端,在客户端做代码处理,来展现不同的布局和内容。
  • 自适应需要开发多套界面,通过检测视口的分辨率,判断当前访问的设备是PC还是手机/平板,从而请求服务层,返回不同的页面。
  • 响应式布局等同于流动网格布局,而自适应等同于使用固定分割点来进行布局。

实现:

  • 媒体查询:使用meta标签或者在style标签中使用@media实现。
  • 百分比布局
  • 视口单位布局:相对于窗口大小布局

什么是iframe框架标签?有什么坏处?

答:元素会创建包含另外一个包含一个文档的内联框架,也是镶嵌在一个网页中的另一个网页。相当于网页中嵌套了一个窗口。

坏处:在实际开发中,尽量减少使用iframe,因为它破坏网站的前进和后退功能,且不利于SEO(抓取关键字)。

JS篇

JS数据位数?

所有 JavaScript 数字均为 64 位(符号位1、阶码11、尾数52)
JavaScript 不是类型语言。
JavaScript 中的所有数字都存储为根为 10 的 64 位(8 比特),浮点数。
可以使用下面代码获取可表示的最大数字:

1
var big = Number.MAX_VALUE; //最大数字1.7976931348623157e+308。

JS数据类型

  • 基本数据类型: Undefined、Null、Boolean、Number 和 String和Symbol
  • 引用数据类型: Object (包括 Object 、Array 、Function)
  • ECMAScript 2015 新增:Symbol(创建后独一无二且不可变的数据类型 )

判断一个值是什么类型的方法

  • typeof 运算符
  • instanceof 运算符
  • Object.prototype.toString.call(xx) 方法

null 和 undefined 的区别?

  • null 表示一个对象被定义了,值为“空值”;
  • undefined 表示不存在这个值。
    • 变量被声明了,但没有赋值时,就等于undefined
    • 调用函数时,应该提供的参数没有提供,该参数等于undefined
    • 对象没有赋值的属性,该属性的值为undefined
    • 函数没有返回值时,默认返回undefined。

“ ===”、“ ==”的区别?

==:当且仅当两个运算数相等时,它返回 true,即不检查数据类型;
===:只有在无需类型转换运算数就相等的情况下,才返回 true,需要检查数据类型;

eval是做什么的?

​ 它的功能是把对应的字符串解析成 JS 代码并运行;
应该避免使用 eval,不安全,非常耗性能(2次,一次解析成 js 语句,一次执行);

var、let、const 区别?

  • var 存在变量提升。
  • let 只能在块级作用域内访问。
  • const 用来定义常量,必须初始化,不能修改(对象特殊)。

new操作符具体干了什么呢?

  • 创建一个新的对象obj
  • 将对象与构建函数的原型通过原型链连接起来
  • 将构建函数中的this绑定到新建的对象obj
  • 根据构建函数返回类型作判断,如果是原始值则被忽略,如果是返回对象,需要正常处理

JSON是什么?

​ JSON的全称是”JavaScript Object Notation”,意思是JavaScript对象表示法,它是一种基于文本,独立于语言的轻量级数据交换格式。

Ajax 是什么? 如何创建一个Ajax?

AJAX 是一种用于创建快速动态网页的技术。通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。而传统的网页(不使用 AJAX)如果需要更新内容,必需重载整个网页面。

  1. 创建XMLHttpRequest对象,也就是创建一个异步调用对象;
  2. 创建一个新的HTTP请求,并指定该HTTP请求的方法、URL及验证信息;
  3. 设置响应HTTP请求状态变化的函数;
  4. 发送HTTP请求;
  5. 获取异步调用返回的数据;
  6. 使用JavaScript和DOM实现局部刷新;

AJAX:异步JavaScript和XML,通过Ajax可以在浏览器中向服务器发请求。

  • 优点:
    • 可以无需刷新页面与服务器进行通信
    • 允许根据用户事件更新部分页面内容
  • Ajax缺点:
    • 没有浏览历史,不能回退
    • 跨域问题
    • SEO不友好(搜索引擎优化,爬虫爬不到)

call()、apply()、bind()方法的区别

callapply可以用来将函数绑定到某个对象,重新定义函数的执行环境(函数体内的this对象的值会被绑定到传入方法中的第一个参数的值);callapplybind都是为了改变某个函数运行时的context,即上下文而存在的,换句话说,就是为了改变函数体内部this的指向。

从定义中也可以看出来,call()apply()的不同点就是接收参数的方式不同

1
2
3
People.call(this, name, age);
People.apply(this, [name, age]);
People.bind(this,name,age)();
  • apply()方法接收两个参数,一个是函数运行的作用域(this),另一个是参数数组。
  • call()方法不一定接受两个参数,第一个参数也是函数运行的作用域(this),但是传递给函数的参数必须列举出来。

innerHTML、innerText、outerHTML的区别?

innerHTML:对象的起始位置到终止位置的全部内容,包括Html标签。
innerText :从起始位置到终止位置的内容,但它去除Html标签。

outerHTML:除了包含innerHTML的全部内容外, 还包含对象标签本身。

documen.write 和 innerHTML 的区别?

  • document.write 只能重绘整个页面;
  • innerHTML 可以重绘页面的一部分;

请解释一下 JavaScript 的同源策略?

  • 概念:同源策略是客户端脚本(尤其是Netscape Navigator2.0,其目的是防止某个文档或脚本从多个不同源装载。
  • 所谓“同源”指的是”三个相同“。相同的域名、端口和协议,这三个相同的话就视为同一个域,本域下的JS脚本只能读写本域下的数据资源,无法访问其它域的资源。
  • 同源策略是一种安全协议,指一段脚本只能读取来自同一来源的窗口和文档的属性。

介绍一下闭包和闭包的常用场景?

  1. 闭包是指有权访问另一个函数作用域中的变量的函数,创建闭包常见方式,就是在一个函数的内部创建另一个函数。
  2. 使用闭包主要为了设计私有的方法和变量,闭包的优点是可以避免变量的污染,缺点是闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。
    在js中,函数即闭包,只有函数才会产生作用域的概念。
  • 闭包有三个特性:
    • 函数嵌套函数
    • 函数内部可以引用外部的参数和变量
    • 参数和变量不会被垃圾回收机制回收
  • 应用场景:
    • 创建私有变量
    • 延长变量的生命周期
  • 不适用场景:返回闭包的函数是个非常大的函数
  • 闭包的缺点就是常驻内存,会增大内存使用量,使用不当会造成内存泄漏

javascript的内存(垃圾)回收机制?

  • 垃圾回收器会每隔一段时间找出那些不再使用的内存,然后为其释放内存
  • 一般使用标记清除方法(mark and sweep), 当变量进入环境标记为进入环境,离开环境标记为离开环境
    垃圾回收器会在运行的时候给存储在内存中的所有变量加上标记,然后去掉环境中的变量以及被环境中变量所引用的变量(闭包),在这些完成之后仍存在标记的就是要删除的变量了
  • 还有引用计数方法(reference counting), 在低版本IE中经常会出现内存泄露,很多时候就是因为其采用引用计数方式进行垃圾回收。引用计数的策略是跟踪记录每个值被使用的次数,当声明了一个 变量并将一个引用类型赋值给该变量的时候这个值的引用次数就加1,如果该变量的值变成了另外一个,则这个值得引用次数减1,当这个值的引用次数变为0的时 候,说明没有变量在使用,这个值没法被访问了,因此可以将其占用的空间回收,这样垃圾回收器会在运行的时候清理掉引用次数为0的值占用的空间。

什么是this关键字?有什么作用?怎么改变this指向?

答:它代表函数运行时,自动生成的内部对象,只能由函数内部使用,指向的是这个函数所操作的当前对象。

绑定this的优先级:

1.箭头函数 2.关键字new调用 3.显示调用 4.隐式绑定 5.默认绑定

  • 箭头函数:this的值就是函数创建时候所在的作用域中的this。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    function Person(){
    this.age = 0;
    setTimeout(function () {
    console.log(this.age); // 输出undefined,因为setTimeout由window对象调用。
    }, 1000);
    }
    var p = new Person();

    function Person(){
    this.age = 10;
    setTimeout(()=> {
    console.log(this.age); // 输出10
    }, 1000);
    }
    var p = new Person();
  • new关键字:new这个关键字放在一个函数调用的前面,JS编译器会做这四件事情:

    1
    2
    3
    4
    5
    6
    function foo() { 
    this.baz = "baz";
    console.log(this.bar + " " + baz); // undefined undefined
    }
    var bar = "bar";
    var baz = new foo();
    • 创建一个新的空的对象
    • 把这个对象链接到原型对象上
    • 这个对象被绑定为this
    • 如果这个函数不返回任何东西,默认return this。
  • 默认绑定和隐式绑定:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    function foo() { 
    console.log(this.bar);
    }
    var bar = "bar1";
    var o2 = {bar: "bar2", foo: foo};
    var o3 = {bar: "bar3", foo: foo};
    foo(); // "bar1" – 默认绑定
    o2.foo(); // "bar2" – 隐式绑定
    o3.foo(); // "bar3" – 隐式绑定
  • 显示绑定:如果foo是通过call、apply或者bind调用的,那么这种调用就是显式绑定。这种绑定中,this的指向就是这三个函数中传递的第一个参数。

    1
    2
    3
    4
    5
    6
    7
    8
    function foo() { 
    console.log(this.bar);
    }
    var bar = "bar1";
    var obj = {bar: "bar2"};

    foo(); // "bar1" 默认绑定
    foo.call(obj); // "bar2" 显式绑定,使用obj作为"this"

箭头函数,箭头函数和普通函数的区别?

答:箭头函数是ES6中用来定义函数的新语法。

  • 区别:

    • 箭头函数不会创建自己的this,所以它没有自己的this,它只会从自己的作用域链的上一层继承this。

    • 没有原型,不能通过new关键字调用。

      不可以改变this的绑定,因此,applycall方法其实并不会起作用!!!

    • 不支持arguments对象,所以必须通过命名参数和不定参数(…arg语法)访问函数的参数。

    • 不支持重复的命名参数。

JavaScript原型,原型链 ? 有什么特点?

  • 每个对象都会在其内部初始化一个属性,就是prototype(原型),当我们访问一个对象的属性时,
    如果这个对象内部不存在这个属性,那么他就会去prototype里找这个属性,这个prototype又会有自己的prototype,于是就这样一直找下去,也就是我们平时所说的原型链的概念;
  • 特点:
    JavaScript对象是通过引用来传递的,我们创建的每个新对象实体中并没有一份属于自己的原型副本。当我们修改原型时,与之相关的对象也会继承这一改变。
  1. 对象有属性__proto__,指向该对象的构造函数的原型对象;
  2. 方法除了有属性__proto__,还有属性prototype,prototype指向该方法的原型对象;而它的__proto__通常指向Function.prototype;

什么是闭包?有什么作用?

答:「函数」和「函数内部能访问到的变量」的总和,就是一个闭包。它是JS 函数作用域的副产品。

1
2
3
4
5
6
7
// 最简单的闭包:函数套函数只是为了造出一个局部变量,跟闭包无关
(function (){
let a = 1
function foo(){
console.log(a);
}
})()

作用:用来间接访问一个变量,或者说是隐藏一个变量。

1
2
3
4
5
6
7
8
9
!function(){
var lives = 50
window.奖励一条命 = function(){
lives += 1
}
window.死一条命 = function(){
lives -= 1
}
}()

内存溢出和内存泄露有什么区别?

答:

  • 内存溢出
    • 一种程序运行出现的错误
    • 当程序运行需要的内存超过了剩余的内存时,就抛出内存溢出的错误
  • 内存泄漏:指一块被分配的内存既不能使用,又不能回收,直到浏览器进程结束
    • 占用的内存没有及时释放
    • 内存泄漏积累多了容易导致内存溢出
    • 常见内存泄漏:
      • 意外的全局变量
      • 没有及时清理的计时器或回调函数
      • 闭包

JS数组方法总结

  • Array.from()
  • length属性
  • Array.isArray()
  • Array.fill()
  • Array.copyWith()
  • Array.join()
  • pop() / push()
  • shift() / unshift()
  • sort / reverse
  • Array.concat()
  • Array.splice()
  • Array.indexOf()
  • Array.lastIndexOf()
  • Array.find()
  • Array.forEach()
  • Array.every()
  • Array.some()
  • Array.some()
  • Array.map()
  • Array.forEach()
  • Array.filter()
  • Array.reduce()

字符串方法总结

  • length属性
  • String()转型函数
  • charAt()
  • charCodeAt()
  • fromCharCode()
  • concat()
  • indexOf()
  • lastIndexOf
  • startsWith()
  • endsWith()
  • includes()
  • repeat()
  • trim()
  • toLowerCase()
  • toUpperCase()
  • 正则系列
    • match()
    • replace()

async和promise之间的区别是什么?

答:

  • 相同点:

    • async/await是基于promise实现的,他不能用于普通的回调函数
    • async/await使得异步代码看起来像同步代码
    • async/await与Promise一样,是非阻塞的。
  • 不同点:

    • 函数前面多了一个async关键字。await关键字只能用在async定义的函数内。async函数会引式返回一个promise,改promise的resolve值就是函数return的值。

    • 简洁:使用async和await明显节约了不少代码,不需要.then,不需要写匿名函数处理promise的resolve的值,不需要定义多余的data变量,还避免了嵌套代码。

    • async/await让try/catch 可以同时处理同步和异步错误。try/catch不能处理JSON.parse的错误,因为他在promise中。此时需要.catch,这样的错误处理代码非常冗余。并且,在我们的实际生产代码会更加复杂。

Vue篇

介绍一下VUE,谈谈你对MVVM开发模式的理解?和MVC有什么区别?

  • MVVM
    • MVVM分为Model、View、ViewModel三者;
    • Model 代表数据模型,数据和业务逻辑都在Model层中定义;
    • View 代表UI视图,负责数据的展示;
    • ViewModel 负责监听 Model 中数据的改变并且控制视图的更新,处理用户交互操作;
    • Model 和 View 并无直接关联,而是通过 ViewModel 来进行联系的,Model 和 ViewModel 之间有着双向数据绑定的联系。因此当 Model 中的数据改变时会触发 View 层的刷新,View 中由于用户交互操作而改变的数据也会在 Model 中同步。
    • 这种模式实现了 Model 和 View 的数据自动同步,因此开发者只需要专注对数据的维护操作即可,而不需要自己亲自操作 dom。
  • MVC

你对SPA单页面的理解,它的优缺点分别是什么?如何实现SPA应用呢?

​ SPA(single-page application),翻译过来就是单页应用SPA是一种网络应用程序或网站的模型,它通过动态重写当前页面来与用户交互,这种方法避免了页面之间切换打断用户体验在单页应用中,所有必要的代码(HTMLJavaScriptCSS)都通过单个页面的加载而检索,或者根据需要(通常是为响应用户操作)动态装载适当的资源并添加到页面,页面在任何时间点都不会重新加载。

单页应用优缺点

优点:

  • 具有桌面应用的即时性、网站的可移植性和可访问性
  • 用户体验好、快,内容的改变不需要重新加载整个页面
  • 良好的前后端分离,分工更明确

缺点:

  • 不利于搜索引擎的抓取
  • 首次渲染速度相对较慢

生命周期有哪些?

Vue生命周期总共可以分为8个阶段:创建前后, 载入前后,更新前后,销毁前销毁后,以及一些特殊场景的生命周期。

生命周期 描述
beforeCreate 组件实例被创建之初,组件的属性生效之前
created 组件实例已经完全创建,属性也绑定,但真实 dom 还没有生成,$el 还不可用
beforeMount 在挂载开始之前被调用:相关的 render 函数首次被调用
mounted el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子
beforeUpdate 组件数据发生变化,发生在虚拟 DOM 打补丁之前
updated 组件数据更新之后
beforeDestroy 组件实例销毁之前
destroyed 组件实例销毁之后
activated keep-alive 专属,组件被激活时调用
deactivated keep-alive 专属,组件被销毁时调用
errorCaptured 捕获一个来自子孙组件的错误时被调用

v-if 和 v-show 有什么区别?

  • v-if 是真正的条件渲染,会控制这个 DOM 节点的存在与否。因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建;也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
  • v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 的 “display” 属性进行切换。

你使用过 Vuex 吗?

在Vue中实现集中式状态(数据)管理的一个Vue插件,对vue应用中多个组件的共享状态进行集中式的管理(读/写数据或方法),也是一种组件间通信的方式,且适用于任意组件间通信。

computed 和 watch 的区别和运用的场景?

  • computed: 是计算属性,依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会重新计算 computed 的值;
  • watch: 更多的是「观察」的作用,类似于某些数据的监听回调 ,每当监听的数据变化时都会执行回调进行后续操作;
  • 运用场景:
    • 当我们需要进行数值计算,并且依赖于其它数据时,应该使用 computed,因为可以利用 computed 的缓存特性,避免每次获取值时,都要重新计算;
    • 当我们需要在数据变化时执行异步或开销较大的操作时,应该使用 watch,使用 watch 选项允许我们执行异步操作 ( 访问一个 API ),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。

直接给一个数组项赋值,Vue 能检测到变化吗?

由于 JavaScript 的限制,Vue 不能检测到以下数组的变动:

  • 当你利用索引直接设置一个数组项时,例如:vm.items[indexOfItem] = newValue
  • 当你修改数组的长度时,例如:vm.items.length = newLength
  • 为了解决第一个问题,Vue 提供了以下操作方法:

    1
    2
    3
    4
    5
    6
    // Vue.set
    Vue.set(vm.items, indexOfItem, newValue)
    // vm.$set,Vue.set的一个别名
    vm.$set(vm.items, indexOfItem, newValue)
    // Array.prototype.splice
    vm.items.splice(indexOfItem, 1, newValue)
  • 为了解决第二个问题,Vue 提供了以下操作方法:

    1
    2
    // Array.prototype.splice
    vm.items.splice(newLength)

Vue 的父组件和子组件生命周期钩子函数执行顺序?

  • 加载渲染过程 :
    父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate -> 子 created -> 子 beforeMount -> 子 mounted -> 父 mounted
  • 子组件更新过程 :
    父 beforeUpdate -> 子 beforeUpdate -> 子 updated -> 父 updated
  • 父组件更新过程 :
    父 beforeUpdate -> 父 updated
  • 销毁过程 :
    父 beforeDestroy -> 子 beforeDestroy -> 子 destroyed -> 父 destroyed

组件中 data 为什么是一个函数?

  • 因为组件是用来复用的,且 JS 里对象是引用关系,如果组件中 data 是一个对象,那么这样作用域没有隔离,子组件中的 data 属性值会相互影响。
  • 如果组件中 data 选项是一个函数,那么每个实例可以维护一份被返回对象的独立的拷贝,组件实例之间的 data 属性值不会互相影响;而 new Vue 的实例,是不会被复用的,因此不存在引用对象的问题。

v-model 的原理?

我们在 vue 项目中主要使用 v-model 指令在表单 input、textarea、select 等元素上创建双向数据绑定,我们知道 v-model 本质上不过是语法糖,v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件:

  • text 和 textarea 元素使用 value 属性和 input 事件;
  • checkbox 和 radio 使用 checked 属性和 change 事件;
  • select 字段将 value 作为 prop 并将 change 作为事件。

Vue 组件间通信有哪几种方式?

  1. props/$emit(父传子/子传父)
  2. $emit/$on(全局事件总线)
  3. vuex(实现集中式状态(数据)管理的插件)

对于 vue3.0 特性你有什么了解的吗?

网络篇

梳理50道经典计算机网络面试题

TCP 传输的三次握手、四次挥手策略

  • 三次握手:

    为了准确无误地吧数据送达目标处,TCP协议采用了三次握手策略。用TCP协议把数据包送出去后,TCP不会对传送后的情况置之不理,他一定会向对方确认是否送达,握手过程中使用TCP的标志:SYN和ACK

    • 发送端首先发送一个带SYN的标志的数据包给对方
    • 接收端收到后,回传一个带有SYN/ACK标志的数据包以示传达确认信息
    • 最后,发送端再回传一个带ACK的标志的数据包,代表“握手”结束
  • 如在握手过程中某个阶段莫名中断,TCP协议会再次以相同的顺序发送相同的数据包


  • 断开一个TCP连接需要“四次挥手”
    • 第一次挥手:主动关闭方发送一个FIN,用来关注主动方到被动关闭方的数据传送,也即是主动关闭方告诫被动关闭方:我已经不会再给你发数据了(在FIN包之前发送的数据,如果没有收到对应的ACK确认报文,主动关闭方依然会重发这些数据)。但是,此时主动关闭方还可以接受数据
    • 第二次挥手:被动关闭方收到FIN包后,发送一个ACK给对方,确认序号收到序号 +1(与SYN相同,一个 FIN占用一个序号)
    • 第三次挥手:被动关闭方发送一个 FIN。用来关闭被动关闭方到主动关闭方的数据传送,也就是告诉主动关闭方,我的数据也发送完了,不会给你发送数据了
    • 第四次挥手:主动关闭方收到FIN后,发送一个ACK给被动关闭方,确认序号为收到序号+1,至此,完成四次挥手。

CRSF攻击?

答:Cross-site request forgery, 跨站请求伪造。是指黑客引诱用户打开黑客的网站,在黑客的网站中,利用用户的登录状态发起跨站请求。

HTTP常见的状态码?

  • 100 Continue 请求者应当继续提出请求。服务器返回此代码表示已收到请求的第一部分,正在等待其余部分。
  • 200 OK 正常返回信息
  • 201 Created 请求成功并且服务器创建了新的资源。
  • 202 Accepted 服务器已接受请求,但尚未处理。
  • 204 NO CONTENT - [DELETE]:用户删除数据成功。
  • 301 Moved Permanently 请求的网页已永久移动到新位置。
  • 302 Found 临时性重定向,请求的网页暂时被移动到了新位置。
  • 303 See Other 临时性重定向,请求的资源在其它的URl上,且总是使用 GET 请求新的 URI。
  • 304 Not Modified 自从上次请求后,请求的网页未修改过。(web缓存机制——协商缓存)
  • 400 Bad Request 服务器无法理解请求的格式。
  • 401 Unauthorized 请求要求身份验证。
  • 403 Forbidden 权限不够而禁止访问。
  • 404 Not Found 找不到如何与 URI 相匹配的资源。
  • 406 Not Acceptable 表示客户端无法解析服务端返回的内容。
  • 410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
  • 422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。
  • 500 Internal Server Error 最常见的服务器端错误,无法完成请求。
  • 501 Not Implemented 服务器不认识或者不支持对应的请求方法
  • 503 Service Unavailable 服务器端暂时无法处理请求(可能是过载或维护)。
  • 504 Gateway Time-out 网页请求超时,浏览网站网页所发出的请求没有反应或者未响应
  • 505:HTTP版本不支持

HTTP 和 HTTPS,为什么HTTPS安全?

  • HTTP协议通常承载与 TCP协议之上,在HTTP和TCP之间添加一个安全协议层(TSL/SSL),这个时候,就成了我们常说的HTTPS
  • 默认HTTP的端口号为80,HTTPS的端口号为443
  • 因为网络请求需要中间有很多的服务器路由的转发,中间的节点都可能篡改信息,而如果使用HTTPS,密钥在你和终点站才有,https之所有说比http安全,是因为他利用ssl/tls协议传输。包含证书,流量转发,负载均衡,页面适配,浏览器适配,refer传递等,保障了传输过程的安全性。

HTTP1.0和HTTP1.1、HTTP2.0有什么区别,了解过HTTP3.0吗?

答:HTTP协议是无状态协议,不需要维护客户机先前的状态信息。

  • HTTP1.0:每个TCP连接上只传送一个对象,下载多个对象需要建立多个TCP连接

    HTTP1.0使用非持久HTTP连接。

    只有GET(请求指定页面信息,并返回实体主体)、POST(输入值在请求报文的实体主体中被上载到服务器)、HEAD(服务器收到请求时,用HTTP报文进行响应,但不返回请求对象)请求方法

  • HTTP1.1:一个TCP连接上可以传送多个对象,默认使用持久HTTP连接,可以减少三次握手的开销。而且它是带流水线的,允许客户端不用等待上一次请求结果返回,就可以发出下一次请求,但服务器端必须按照接收到客户端请求的先后顺序依次回送响应结果。

    HTTP1.0是没有host域的,HTTP1.1才支持这个参数,因为一台物理服务器可以存在多个虚拟主机,请求消息中如果没有host域会报告一个错误(400 Bad Request)。

    新增OPTIONS(返回服务器针对特定资源所支持的HTTP请求方法,也可以利用向web服务器发送*的请求来测试服务器的功能性)、PUT(文件在实体主体中被上载到URL字段指定的路径)、DELETE(删除URL字段指定的文件)、TRACE、CONNECT方法。

    新增错误状态码

  • 多路复用:HTTP2.0使用了多路复用的技术,做到同一个连接并发处理多个请求,而且并发请求的数量比HTTP1.1大了好几个数量级。当然HTTP1.1也可以多建立几个TCP连接,来支持处理更多并发的请求,但是创建TCP连接本身也是有开销的。TCP连接有一个预热和保护的过程,先检查数据是否传送成功,一旦成功过,则慢慢加大传输速度。因此对应瞬时并发的连接,服务器的响应就会变慢。所以最好能使用一个建立好的连接,并且这个连接可以支持瞬时并发的请求。HTTP 2.0是并行执行,一个请求超时并不会影响其他请求。

    解决了队头阻塞问题

    头部压缩:HTTP1.1不支持header数据的压缩,HTTP2.0使用HPACK算法对header的数据进行压缩,这样数据体积小了,在网络上传输就会更快。

    二进制分帧协议

  • HTTP3.0是基于UDP作为传输层协议改进而来的。

HTTP报文格式?

答:

状态行:协议版本字段、状态码、相应状态信息

首部行:

空行:必要

实体主体:信息

了解过SSL协议吗?有什么作用?

答:TCP和UDP网络传输是明文传输,而SSL全称是安全套接字层,是应用层协议,可以提供加密的TCP连接,需要进行端点认证,在保证数据完整性的同时确保安全。

URI和URL有什么区别?

答:

  • URI:统一资源标志符

  • URL:统一资源定位符

URL是URI的子集,起到了URI的作用,是URI不一定是URL,但是是URL一定是URI。

POST和GET两种请求方法的区别?

get:安全幂等

post:不安全不幂等

HTTP协议下常用的7种请求方法

  • GET:发出请求从服务器获取一份文档;
  • HEAD:同GET但只从服务器获取文档的首部;
  • POST:向服务器发送带要处理的数据,并可以接收处理过后的数据;
  • PUT:将请求的主体部分存储在服务器上;
  • TRACE:对可能经过代理服务器传送到服务器上去的报文进行追踪;
  • OPTIONS:请求Web服务器告知其支持的各种功能;
  • DELETE:从服务器上删除一份文档;

TCP与UDP的区别?

TCP (Transmission Control Protocol)和UDP(User Datagram Protocol)协议属于传输层协议,它们之间的区别包括:

  • TCP是面向连接的,UDP是无连接的;
  • TCP是可靠的,UDP是不可靠的;
  • TCP只支持点对点通信,UDP支持一对一、一对多、多对一、多对多的通信模式;
  • TCP是面向字节流的,UDP是面向报文的;
  • TCP有拥塞控制机制;UDP没有拥塞控制,适合媒体通信;
  • TCP首部开销(20个字节)比UDP的首部开销(8个字节)要大;
  • UDP没有流量控制机制

什么是 HTTP 协议无状态协议?怎么解决Http协议无状态协议?

每次HTTP请求都是独立的,无相关的,默认不需要保存上下文信息的。

HTTP 的这种特性有优点也有缺点:

  • 优点:解放了服务器,每一次的请求“点到为止”,不会造成不必要的连接占用
  • 缺点:每次请求会传输大量重复的内容信息,并且,在请求之间无法实现数据的共享

解决方案:使用Cookie技术

  • cookie头部行在HTTP响应消息中
  • cookie头部行在HTTP请求消息中
  • cookie文件保存在用户主机并被浏览器管理
  • cookie也保存在Web站点的后端数据库

你能不能讲一讲什么是浏览器缓存,为什么我们要引入缓存,具体可以分为哪些?

答:浏览器缓存就是当我们第一次访问网站时,浏览器会将网站部分资源拷贝副本存储到本地,再次访问时,就会直接使用使用副本响应请求。

引入缓存是为了直接从本地缓存获取相关资源,加速网页后续加载速度,而不是重新向服务器发起请求,以此提升用户体验,同时也降低了服务器的读取磁盘压力。

image-20220124180442717

image-20220124181248263
  • 上图有:
    • cdn缓存
    • 代理服务器缓存
    • 客户端缓存
      • http缓存
        • 强缓存
        • 协商缓存
      • 本地存储
        • localStorage
        • sessionStorage
        • cookie
        • IndexedDB(数据库缓存)
          • 允许存储大批量数据,能建立索引,不属于关系型数据库(不支持SQL查询),更加接近NoSQL数据库。
        • appCache(应用层缓存)

http缓存

答:

三级缓存架构:

  • 先在内存中查找,如果有,直接加载。

  • 如果内存中不存在,则在硬盘中查找,如果有直接加载。

  • 如果硬盘中也没有,那么就进行网络请求。

    请求获取的资源缓存到硬盘和内存。

http缓存分为强缓存和协商缓存。

  • 强缓存主要使用ExpiresCache-Control两个头字段,两者同时存在Cache-Control优先级更高。当命中强缓存的时候,客户端不会再请求,而是直接从本地缓存中读取内容,并返回HTTP状态码200

    • Expires:响应头,代表资源过期时间,是一个GMT格式的标准时间。

      当客户端请求服务器时,服务器会返回资源的同时还会带上响应头Expires,表示资源过期具体时间,如果客户端在过期时间之前再次获取该资源,就不需要请求服务器了,可以直接在缓存中获取。

      • 使用Expires强缓存优点:
        • 过期时间内,为用户节省流量
        • 减少了服务器重复读取磁盘文件的压力
      • 使用Expires强缓存的缺点:
        • 缓存过期后,服务器不管文件有没有变化,会再次请求服务器。
        • 缓存过期时间是一个具体地时间,依赖于客户端地时间,如果时间不准确或者被改动缓存也会随之受到影响。
    • Cache-Control响应头中常用字段的具体含义:

      • max-age:用来设置资源(representations)可以被缓存多长时间,单位为秒;

      • s-maxage:和max-age是一样的,不过它只针对代理服务器缓存而言;

      • public:指示响应可被任何缓存区缓存;

      • private:只能针对个人用户,而不能被代理服务器缓存;

      • no-cache:强制客户端直接向服务器发送请求,也就是说每次请求都必须向服务器发送。服务器接收到请求,然后判断资源是否变更,是则返回新内容,否则返回304,未变更。这个很容易让人产生误解,使人误以为是响应不被缓存。实际上Cache-Control: no-cache是会被缓存的,只不过每次在向客户端(浏览器)提供响应数据时,缓存都要向服务器评估缓存响应的有效性。

      • no-store:禁止一切缓存(这个才是响应不被缓存的意思)。

  • 协商缓存主要有四个头字段If-modified-sinceLast-Modified一组,EtagIf-None-Match一组,当两组同时存在,以Etag、if-None-Match为主。当命中协商缓存,服务器返回HTTP状态码304,让客户端直接从本地缓存里读取文件。

    • If-Modified-Since

      请求头,资源最近修改时间,由服务器告诉服务器。其实就是第一次访问服务端返回的Last-Modified值

    • Last-Modified

      响应头,资源最近修改时间,由服务器告诉浏览器

    • Etag

      响应头,资源标识,由服务器告诉浏览器。

    • If-none-match

      请求头,缓存资源标识,由浏览器告诉服务器。其实就是第一次访问服务端返回的Etag的值。

    If-Modified-Since和Last-Modified

    当客户端第一次请求服务器时,服务端就会返回一个Last-Modified响应头,该字段是一个标准时间。客户端请求服务器时会带上If-Modified-Since请求字段,该字段值就是服务器返回的Last-Modified的值。服务器接收后就会比较这两个值是否一样,一样返回304,让客户端从缓存中读取,不一样就会返回新文件给客户端并更新Last-Modified响应头字段。

    优点:当缓存有效时服务器不会返回文件给客户端,而是直接返回304状态码,让客户端从缓存中获取文件。大大节省了流量和带宽以及服务器的压力。

    缺点:Last-Modified过期时间只能精确到秒。如果同一秒既修改了文件又获取文件,客户端是获取不到最新文件的。

    Etag和If-None-Match

    为了解决文件修改时间只能精确到秒带来的问题,我们引入Etag响应头。Etag是由文件修改时间与文件大小计算而成,只有当文件/文件内容或修改时间变了Etag的值才会发生改变。

    当客户端第一次请求服务器时,服务端会返回一个Etag响应头,客户端请求服务器的时候会带上If-None-Match请求字段,该字段的值就是服务器返回的Etag值。服务器接收到请求后会比较两个值是否一样,一样就返回304,让客户端从缓存中读取,不一样就返回新文件给客户端并更新Etag响应头字段的值。

  • 扩展

    • 缓存失效:引入缓存固然是好事,能大大提升响应速度以及减轻服务端的压力,但是也会出现一些问题,比如我们明明更新了系统版本,为什么客户端依然看到的还是老文件,不同时代有不同的解决方案。

      • 旧方案:通过人工自己修改文件名或者在文件名后带上版本号、时间戳,这样客户端就会当新文件请求并使用,之前的强缓存就算在有效期内也会失效。

        1
        <script src="http://randy.js?version=1.1.1> </script>
      • 新方案:在现在的构建阶段基本上都不需要人工操作了,都是使用构建工具比如Wbpack、Gulp、Grunt等构建工具自动构建。比如在使用Webpack构建的时候,会根据文件名或文件内容自动计算hash值来给文件命名,当内容或文件名发生改变的时候,构建出来的文件名也一定会不一样,这样也解决了强缓存还在有效期内的问题。

      • img

    • 缓存配置:如果我们使用Ngnix作为web服务器,有:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      location / {

      # 其它配置
      ...

      if ($request_uri ~* .*[.](js|css|map|jpg|png|svg|ico)$) {
      #非html缓存1个月
      add_header Cache-Control "public, max-age=2592000";
      }

      if ($request_filename ~* ^.*[.](html|htm)$) {
      #html文件使用协商缓存
      add_header Cache-Control "public, no-cache";
      }
      }
    • 缓存位置

      按缓存位置分类我们可以分为memory cache、disk cache、Service Worker三类,我们可以在 Chrome 的开发者工具中,Network -> Size 一列看到一个请求最终的处理方式:如果是大小 (多少 K, 多少 M 等) 就表示是网络请求,否则会列出 from memory cachefrom disk cachefrom ServiceWorker就表示命中了缓存。

      • memory cache 是内存中的缓存,(与之相对 disk cache 就是硬盘上的缓存)。按照操作系统的常理:先读内存,再读硬盘。

        微信截图_20220119110918.png

      • disk cache 也叫 HTTP cache,顾名思义是存储在硬盘上的缓存,因此它是持久存储的,是实际存在于文件系统中的。而且它允许相同的资源在跨会话,甚至跨站点的情况下使用,例如两个站点都使用了同一张图片。

        微信截图_20220119110855.png

      • 上述的缓存策略以及缓存/读取/失效的动作都是由浏览器内部判断进行的,我们只能设置响应头的某些字段来告诉浏览器,而不能自己操作。service work给予了我们另外一种更加灵活,可以直接的操作方式。我们可以从 Chrome 的 Application找到Service Workers。这个缓存是永久性的,即关闭 TAB 或者浏览器,下次打开依然还在(而 memory cache 不是)。有两种情况会导致这个缓存中的资源被清除:手动调用 API cache.delete(resource) 或者容量超过限制,被浏览器全部清空。

一般HTML文件使用协商缓存,图片、js、css等使用强缓存。

DNS解析过程

  • 首先搜索浏览器自身的DNS缓存,如果存在,则域名解析到此完成。
  • 如果浏览器自身的缓存里面没有找到对应的条目,那么会尝试读取操作系统的hosts文件看是否存在对应的映射关系,如果存在,则域名解析到此完成。
  • 如果本地hosts文件不存在映射关系,则查找本地DNS服务器(ISP服务器,或者自己手动设置的DNS服务器),如果存在,域名到此解析完成。
  • 如果本地DNS服务器还没找到的话,它就会向根服务器发出请求,进行递归查询。

什么是Resful API风格?

答:比较成熟的API设计理论。

  • 协议:API与用户的通信协议,总是使用Https协议。

  • 域名:尽量部署在专用域名下,如果确定api很简单,不会有进一步扩展,可以考虑放在主域名下。

    1
    2
    https://api.example.com
    https://example.org/api/
  • 版本:将版本号放入url或HTTP头部信息中。

    1
    https://api.example.com/v1/
  • 路径:API具体的网址。在RESful架构中,每个网址代表一种资源,所以网址中不能有动词,只能有名词,而且所用的名词往往与数据库表格名对应,而且API中名词应该用复数,因为数据库中表都是同种记录的”集合“。

    举例来说,有一个API提供动物园(zoo)的信息,还包括各种动物和雇员的信息,则它的路径应该设计成下面这样。

    1
    2
    3
    https://api.example.com/v1/zoos
    https://api.example.com/v1/animals
    https://api.example.com/v1/employees
  • 常用的HTTP动词:

    1
    2
    3
    4
    5
    6
    7
    GET(SELECT):从服务器取出资源(一项或多项)。
    POST(CREATE):在服务器新建一个资源。
    PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。
    PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。
    DELETE(DELETE):从服务器删除资源。
    HEAD:获取资源的元数据。
    OPTIONS:获取信息,关于资源的哪些属性是客户端可以改变的。

    例子

    1
    2
    3
    4
    5
    6
    7
    8
    GET /zoos:列出所有动物园
    POST /zoos:新建一个动物园
    GET /zoos/ID:获取某个指定动物园的信息
    PUT /zoos/ID:更新某个指定动物园的信息(提供该动物园的全部信息)
    PATCH /zoos/ID:更新某个指定动物园的信息(提供该动物园的部分信息)
    DELETE /zoos/ID:删除某个动物园
    GET /zoos/ID/animals:列出某个指定动物园的所有动物
    DELETE /zoos/ID/animals/ID:删除某个指定动物园的指定动物
  • 过滤信息

    如果记录数量很多,服务器不可能都将它们返回给用户。API应该提供参数,过滤返回结果。

    下面是一些常见的参数:

    1
    2
    3
    4
    5
    ?limit=10:指定返回记录的数量
    ?offset=10:指定返回记录的开始位置。
    ?page=2&per_page=100:指定第几页,以及每页的记录数。
    ?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序。
    ?animal_type_id=1:指定筛选条件

    参数的设计允许存在冗余,即允许API路径和URL参数偶尔有重复。比如,GET /zoo/ID/animals GET /animals?zoo_id=ID的含义是相同的。

  • 状态码(略)

  • 错误处理

    如果状态码是4xx,就应该向用户返回出错信息。一般来说,返回的信息中将error作为键名,出错信息作为键值即可。

    1
    2
    3
    {
    error: "Invalid API key"
    }
  • 返回结果

    针对不同操作,服务器向用户返回的结果应该符合以下规范。

    1
    2
    3
    4
    5
    6
    GET /collection:返回资源对象的列表(数组)
    GET /collection/resource:返回单个资源对象
    POST /collection:返回新生成的资源对象
    PUT /collection/resource:返回完整的资源对象
    PATCH /collection/resource:返回完整的资源对象
    DELETE /collection/resource:返回一个空文档
  • API身份认证使用OAuth2.0框架

    服务器返回的数据格式,尽量使用JSON,避免使用XML。

谈谈session、token、cookie?

  • Cookie是服务器发送到用户浏览器,并保存在浏览器本地的一小块文本串数据。它会在浏览器下次向同一服务器再发起请求时,被携带发送到服务器。通常,它用于告知服务端两个请求是否来自同一浏览器,一样用于保持用户的登录状态等。Cookie使基于无状态的 HTTP 协议记录稳定的状态信息成为了可能。

  • session指的就是服务器和客户端一次会话的过程。 Session利用Cookie进行信息处理的,当用户首先进行了请求后,服务端就在用户浏览器上创建了一个Cookie,当这个Session结束时,其实就是意味着这个Cookie就过期了。Session对象存储着特定用户会话所需的属性及配置信息。

对比cookie和session:

  • 存储位置不一样,Cookie 保存在客户端,Session 保存在服务器端。
  • 有效期不同,Cookie 可设置为长时间保持,比如我们经常使用的默认登录功能,Session 一般有效时间较短,客户端关闭或者 Session 超时都会失效。
  • 隐私策略不同,Cookie 存储在客户端,比较容易遭到不法获取,早期有人将用户的登录名和密码存储在 Cookie 中导致信息被窃取;Session 存储在服务端,安全性相对 Cookie 要好一些。
  • token

    由于使用session来保持会话状态需要服务器保存session数据,不但需要保存大量数据,而且这对于分布式集群服务很不友好,因为不可能每个服务器都存一份用户session,所以引入了不用服务器存储的token机制。

    服务器只需要保存签名密文即可,用户登录成功后,将一些信息,如token有效期等(header\payload\signature),使用加密算法加密后返回给客户端即可,客户端以后每次请求带上token即可,服务器接到token后使用加密密钥进行验证,验证通过即说明用户身份。

session是空间换时间,token是时间换空间

SQL 注入

SQL注入就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。

XSS 攻击

跨站脚本攻击,XSS是一种经常出现在web应用中的计算机安全漏洞,与SQL注入一起成为web中最主流的攻击方式。XSS是指恶意攻击者利用网站没有对用户提交数据进行转义处理或者过滤不足的缺点,进而添加一些脚本代码嵌入到web页面中去,使别的用户访问都会执行相应的嵌入代码,从而盗取用户资料、利用用户身份进行某种动作或者对访问者进行病毒侵害的一种攻击方式。类型:存储型 、反射型 、DOM型XSS

反射型XSS原理:img

反射型XSS的脚本被解析的地方是浏览器,而存储型XSS的脚本被解析的地方是服务器。

OSI 网络体系结构与 TCP/IP 协议模型

​ OSI 是一个理论上的网络通信模型,而 TCP/IP 则是实际上的网络通信标准。

什么是跨域问题?怎么解决?

答:这是由同源策略导致的,是对JavaScript实施的安限制条件,浏览器在请求资源的时候,需要满足同源协议,SOP,就是:协议,域名、端口号必须一致。

  • 解决:

    • JSONP

      1
      2
      3
      let script = document.createElement('script');
      script.src = '请求地址';
      document.appendChild(script);
    • vue脚手架中,可以配置代理服务器。

    • vue.config.js

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      module.exports = {
      devServer:{
      proxy:{
      '/api':{
      target: 'http://localhost:5000',
      pathRewrite: {'^/api': ""} //重写请求url
      }
      }
      }
      }
    • 后端解决CORS,官方解决方案

      原生node.js

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      //设置允许跨域的域名,*代表允许任意域名跨域
      app.all("*", function (req, res, next) {
      res.header("Access-Control-Allow-Origin", "*"); //允许的header类型
      res.header("Access-Control-Allow-Headers", "content-type"); //跨域允许的请求方式
      res.header("Access-Control-Allow-Methods", "DELETE,PUT,POST,GET,OPTIONS");
      if (req.method.toLowerCase() == "options") res.send(200);
      //让options尝试请求快速结束
      else next();
      });

      // res.setHeader()也可以。

      express中间件

      1
      2
      3
      4
      5
      var express = require('express')
      var cors = require('cors')
      var app = express()

      app.use(cors())
    • Ngnix反向代理服务器

在浏览器地址栏输入一个url到得到html,将经过哪些步骤?

答:本地DNS服务器=>返回IP地址=>发送HTTP请求=>三次握手=>返回html=>构建DOM树=>请求js/img/css,构建CSS规则树=>CSSOM+DOM Tree得到渲染树=>渲染(layout + painting)

传输层与链路层

路由器与交换机:

  • 同一局域网上的主机或路由器的IP地址中的网络号必须相同
  • 交换机互连的网络仍然是一个局域网,只能有一个网络号。
  • 路由器总是具有两个或两个以上IP地址。
  • 路由器是网络层设备(IP),交换机是链路层设备(MAC)

子网掩码:

  • 子网掩码用来确定网络地址(包括网络号和子网号)和主机地址的长度。

主机名->ip地址->ARP协议:

  • DNS域名系统:将主机名解析到IP地址。

  • DNS为在因特网中任何地方的主机解析主机名。

  • ARP地址解析协议:将IP地址解析到MAC地址。

    img

  • ARP只为在同一个LAN上的节点解析IP地址。

在交互过程中如果数据传送完了,还不想断开连接怎么办,怎么维持?

在 HTTP 中响应体的 Connection 字段指定为keep-alive

HTTP 如何实现长连接?在什么时候会超时?HTTP 如何实现长连接?

HTTP分为长连接和短连接,其实本质上说的是TCP的长短连接。TCP连接是一个双向的通道,它是可以保持一段时间不关闭的,因此TCP连接才有真正的长连接和短连接这一个说法。

  • 长连接是指的是TCP连接,而不是HTTP连接。

  • TCP 长连接可以复用一个TCP连接来发起多次HTTP请求,这样可以减少资源消耗,比如一次请求HTML,短连接可能还需要请求后续的JS/CSS/图片等

要实现HTTP长连接,在响应头设置Connection为keep-alive,HTTP1.1 默认是长连接,而HTTP 1.0协议也支持长连接,但是默认是关闭的。

HTTPS工作流程

  • 用户在浏览器里输入一个https网址,然后连接到server的443端口。

  • 服务器必须要有一套数字证书,可以自己制作,也可以向组织申请,区别就是自己颁发的证书需要客户端验证通过。这套证书其实就是一对公钥和私钥。

  • 服务器将自己的数字证书(含有公钥)发送给客户端。

  • 客户端收到服务器端的数字证书之后,会对其进行检查,如果不通过,则弹出警告框。如果证书没问题,则生成一个密钥(对称加密),用证书的公钥对它加密。

  • 客户端会发起HTTPS中的第二个HTTP请求,将加密之后的客户端密钥发送给服务器。

  • 服务器接收到客户端发来的密文之后,会用自己的私钥对其进行非对称解密,解密之后得到客户端密钥,然后用客户端密钥对返回数据进行对称加密,这样数据就变成了密文。

  • 服务器将加密后的密文返回给客户端。

  • 客户端收到服务器发返回的密文,用自己的密钥(客户端密钥)对其进行对称解密,得到服务器返回的数据。

对称加密和非对称加密

  • 对称加密:加密密匙 = 解密密钥的加密方式。

  • 非对称加密:加密密匙 != 解密密钥的加密方式。

为什么要三次握手、四次挥手

握手:

  • 三次握手:两次握手,服务器无法知道客户端的同意建立连接请求是否成功被接收,同时客户端也需要初始化服务器的序号。

  • 四次握手:多余开销,反复确认没有意义。

挥手:

  • 第一段是客户端告知服务器结束,服务器表示收到结束消息
  • 第二段是服务器告知客户端自己也没有什么需要处理的东西了,可以结束此次连接,然后客户端表示收到。

四次挥手后客户端为什么要等待2MSL才进入CLOSED?

答:

  • 1个 MSL 保证四次挥手中主动关闭方最后的 ACK 报文能最终到达对端
  • 1个 MSL 保证对端没有收到 ACK 那么进行重传的 FIN 报文能够到达

TCP报文首部字段

20字节

img

Git篇

什么是Git?

​ Git 是分布式版本控制系统(DVCS)。它可以跟踪文件的更改,并允许你恢复到任何特定版本的更改。

Git 是用什么语言编写的?

​ Git使用 C 语言编写。 GIT 很快,C 语言通过减少运行时的开销来做到这一点。

git pull 和 git fetch 有什么区别?

git pull 命令从中央存储库中提取特定分支的新更改或提交,并更新本地存储库中的目标分支。

git fetch 也用于相同的目的,但它的工作方式略有不同。当你执行 git fetch 时,它会从所需的分支中提取所有新提交,并将其存储在本地存储库中的新分支中。如果要在目标分支中反映这些更改,必须在 git fetch 之后执行git merge。只有在对目标分支和获取的分支进行合并后才会更新目标分支。

什么是 git stash?

git stash 会将你的工作目录,即修改后的跟踪文件和暂存的更改保存在一堆未完成的更改中,你可以随时重新应用这些更改。

什么时候使用git rebase代替git merge?

使用变基时,意味着使用另一个分支作为集成修改的新基础。一般只有在完全自信且为了使历史分支记录更为清晰的时候使用。

提交时发生冲突,你能解释冲突是如何产生的吗?你是如何解决的?

​ 开发过程中,我们都有自己的特性分支,所以冲突发生的并不多,但也碰到过。诸如公共类的公共方法,我和别人同时修改同一个文件,他提交后我再提交就会报冲突的错误。
发生冲突,在IDE里面一般都是对比本地文件和远程分支的文件,然后把远程分支上文件的内容手工修改到本地文件,然后再提交冲突的文件使其保证与远程分支的文件一致,这样才会消除冲突,然后再提交自己修改的部分。
​ 发生冲突,也可以使用命令:

  • 通过git stash命令,把工作区的修改提交到栈区,目的是保存工作区的修改;
  • 通过git pull命令,拉取远程分支上的代码并合并到本地分支,目的是消除冲突;
  • 通过git stash pop命令,把保存在栈区的修改部分合并到最新的工作空间中;

IP分类

网络号 + 主机号,使用子网掩码来区分

网络体系架构中每一层含有的协议

img

MAC地址和IP地址不是用一个就行了,干嘛要两个都用?

答:

ip地址是动态的,MAC地址是静态的。

如果只使用MAC地址,那么管理起来就很麻烦,因为如果有ip地址,网络号就能区分不同局域网,如果只有MAC地址,就很麻烦,因为局域网需要记录局域网下的所有MAC地址;

如果只有IP地址,那也不行,因为主机的ip是可变的,使用ip并不能唯一标识一台主机,因为通信中途ip可能变化。(发送方、路由ip、接收方mac)

git 如何撤销 commit、git commit 提交之后如何取消本次提交?

可以先用 git reflog 查看历史提交记录

软撤销 –soft
本地代码不会变化,只是 git 转改会恢复为 commit 之前的状态。

不删除工作空间改动代码,撤销 commit,不撤销 git add .

1
git reset --soft HEAD~1

表示撤销最后一次的 commit ,1 可以换成其他更早的数字

硬撤销
本地代码会直接变更为指定的提交版本,慎用

删除工作空间改动代码,撤销 commit,撤销 git add .

注意完成这个操作后,就恢复到了上一次的commit状态。

1
git reset --hard HEAD~1

使用过git cherry-pick,有什么作用?

​ 命令git cherry-pick可以把branch A的commit复制到branch B上。

​ 在branch B上进行命令操作:

1
git cherry-pick commitId

杂项篇

常见的浏览器内核有哪些

  • 浏览器内核主要分成两部分:渲染引擎(layout engineer或Rendering Engine)和JS引擎。
    • 渲染引擎:负责取得网页的内容(HTML、XML、图像等等)、整理讯息(例如加入CSS等),以及计算网页的显示方式,然后会输出至显示器或打印机。浏览器的内核的不同对于网页的语法解释会有不同,所以渲染的效果也不相同。所有网页浏览器、电子邮件客户端以及其它需要编辑、显示网络内容的应用程序都需要内核。
    • JS引擎则:解析和执行javascript来实现网页的动态效果。
  • 常见内核:
    • Trident 内核:IE, MaxThon, TT, The World, 360, 搜狗浏览器等。[又称 MSHTML]
    • Gecko 内核:FireFox
    • Webkit 内核:Safari, Chrome等。 [ Chrome的:Blink(WebKit 的分支)]

网页前端性能优化的方式有哪些?

  1. 图片懒加载/组件懒加载;

  2. 压缩 css, js, 图片;

  3. 减少 http 请求次数, 合并 css、js 、合并图片(雪碧图);

  4. 浏览器缓存;

  5. 样式表置顶、脚本置低

    • 加载并发数是有上限的,js和css混合放置,会导致css的延迟,会导致页面闪动,所以js要置底
    • css放在header中,阻塞页面的渲染,css加载完,再加载dom,放置页面样式跳变,从而保证渲染一步到位
    • css不会阻塞后面js并发加载,但会阻塞js的执行。如果js放在header中,会阻塞html的渲染。
  6. 使用CDN

    内容分发网络(CDN)是位于不同地理位置的服务器组成的网络。每个服务器都拥有所有网站的文件副本。当用户请求文件和网页时,就可以直接从就近的网站服务器获取相应资源(也可以是从负载最小的服务器)。你可以使用Amazon cloud front 或者MaxCDN为网站开启CDN加速。

  7. 减少dom元素数量(Vue);

  8. 事件委托其实就是利用JS事件冒泡机制把原本需要绑定在子元素的响应事件(click、keydown……)委托给父元素,让父元素担当事件监听的职务。事件代理的原理是DOM元素的事件冒泡。

  • 共同点:都是保存在浏览器端,且同源的。
  • 区别:
    1. cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递。而sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存。
    2. 存储大小限制也不同,cookie数据不能超过4k;sessionStorage和localStorage 虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大。
    3. 数据有效期不同,sessionStorage:仅在当前浏览器窗口关闭前有效,自然也就不可能持久保持;localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;cookie只在设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭。
    4. 作用域不同,sessionStorage不在不同的浏览器窗口中共享,即使是同一个页面;localStorage 在所有同源窗口中都是共享的;cookie也是在所有同源窗口中都是共享的。

在css/js代码上线之后开发人员经常会优化性能,从用户刷新网页开始,一次js请求一般情况下有哪些地方会有缓存处理?

  • DNS缓存

    全称 Domain Name System ,即域名系统

  • CDN缓存

    全称 Content Delivery Network,即内容分发网络(缓存服务器)

  • 浏览器缓存

  • 服务器缓存

网页从输入网址到渲染完成经历了哪些过程?

大致可以分为如下7步:

  • 输入网址;
  • 发送到DNS服务器,并获取域名对应的web服务器对应的ip地址;
  • 与web服务器建立TCP连接;
  • 浏览器向web服务器发送http请求;
  • web服务器响应请求,并返回指定url的数据(或错误信息,或重定向的新的url地址);
  • 浏览器下载web服务器返回的数据及解析html源文件;
  • 生成DOM树,解析css和js,渲染页面,直至显示完成;

Cookie的设置以及在响应报文的位置

cookie信息位于headers的set-cookie字段。有多少个cookie信息加入就有多少个set-cookie字段。客户端接收到cookie后就将cookie存储在本地固定位置。

线程与进程的联系与区别?

  • 进程:程序在执行过程中分配和管理资源的基本单位,是资源分配的最小单位,并拥有自己的独立地址空间;
  • 线程:线程是进程中执行运算的最小单位,是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行;
  • 进程和线程的关系:
    • 一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。
    • 资源分配给进程,同一进程的所有线程共享该进程的所有资源。
    • 处理机分给线程,即真正在处理机上运行的是线程。
    • 线程在执行过程中,需要协作同步。不同进程的线程间要利用消息通信的办法实现同步。线程是指进程内的一个执行单元,也是进程内的可调度实体.
    • 线程作为调度和分配的基本单位,进程作为拥有资源的基本单位

协程是未来的趋势,谈一谈协程

  • 协程与线程的关系类似于进程与线程的关系,协程运行在线程上

  • 并没有增加线程数量,只是在线程的基础之上通过分时复用的方式运行多个协程

  • 协程切换只在用户态实现,切换代价比线程从用户态到内核态代价小得多
    系统只知道线程的存在,不知道协程的存在

  • 协程调用阻塞IO操作的时候,操作系统会让线程进入阻塞状态,当前的协程和其它绑定在该线程之上的协程都会陷入阻塞而得不到调度

  • 需要配合异步I/O才能发挥最大作用

数据库篇

什么是事务?事务四大特性?

​ 事务是对数据库中一系列操作进行统一的回滚或者提交的操作,主要用来保证数据的完整性和一致性。

  • 原子性(Atomicity):
    原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。
  • 一致性(Consistency):
    事务开始前和结束后,数据库的完整性约束没有被破坏。比如A向B转账,不可能A扣了钱,B却没收到。
  • 隔离性(Isolation):
    隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。
  • 持久性(Durability):
    持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

事务的并发问题?

数据库语言

SQL语言共分为四大类:

  • 数据查询语言DQL
  • 数据操纵语言DML
  • 数据定义语言DDL
  • 数据控制语言DCL。

1. 数据查询语言DQL

数据查询语言DQL基本结构是由SELECT子句,FROM子句,WHERE子句组成的查询块:

SELECT
FROM
WHERE

2 .数据操纵语言DML

数据操纵语言DML主要有三种形式:

  1. 插入:INSERT
  2. 更新:UPDATE
  3. 删除:DELETE

3. 数据定义语言DDL

数据定义语言DDL用来创建数据库中的各种对象—–表、视图、索引、同义词、聚簇等如:
CREATE TABLE/VIEW/INDEX/SYN/CLUSTER

表 视图 索引 同义词 簇

DDL操作是隐性提交的!不能rollback

4. 数据控制语言DCL

数据控制语言DCL用来授予或回收访问数据库的某种特权,并控制数据库操纵事务发生的时间及效果,对数据库实行监视等。如:

  1. GRANT:授权。
  2. ROLLBACK [WORK] TO [SAVEPOINT]:回退到某一点。回滚—ROLLBACK;回滚命令使数据库状态回到上次最后提交的状态。其格式为:
    SQL>ROLLBACK;
  3. COMMIT [WORK]:提交。

事务的隔离级别

  1. 第一种隔离级别:Read uncommitted(读未提交)

    如果一个事务已经开始写数据,则另外一个事务不允许同时进行写操作,但允许其他事务读此行数据。
    

    解决了更新丢失,但还是可能会出现脏读

  2. 第二种隔离级别:Read committed(读提交)

    ​ 如果是一个读事务(线程),则允许其他事务读写,如果是写事务将会禁止其他事务访问该行数据。

    解决了更新丢失和脏读问题

  3. 第三种隔离级别:Repeatable read(可重复读取)

    ​ 可重复读取是指在一个事务内,多次读同一个数据,在这个事务还没结束时,其他事务不能访问该数据(包括了读写),这样就可以在同一个事务内两次读到的数据是一样的,因此称为是可重复读隔离级别,读取数据的事务将会禁止写事务(但允许读事务),写事务则禁止任何其他事务(包括了读写)。

    解决了更新丢失、脏读、不可重复读、但是还会出现幻读

  4. 第四种隔离级别:Serializable(可序化)

    提供严格的事务隔离,它要求事务序列化执行,事务只能一个接着一个地执行,但不能并发执行。

    解决了更新丢失、脏读、不可重复读、幻读(虚读)

事务的并发问题

1、脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据

2、不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果因此本事务先后两次读到的数据结果会不一致。

3、幻读:幻读解决了不重复读,保证了同一个事务里,查询的结果都是事务开始时的状态(一致性)。

例如:事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作 这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。 而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有跟没有修改一样,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读。

什么是死锁?

​ 死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。

产生死锁的四个必要条件:

  • 互斥条件:一个资源每次只能被一个进程使用。
  • 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
  • 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
  • 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

主观篇

你都做过什么项目呢?具体聊某一个项目中运用的技术?

你遇到过比较难的技术问题是?你是如何解决的?

常使用的库有哪些?常用的前端开发工具?开发过什么应用或组件?

除了前端以外还了解什么其它技术么?你最最厉害的技能是什么?

对前端开发工程师这个职位是怎么样理解的?它的前景会怎么样?

前端是最贴近用户的程序员,前端的能力就是能让产品从 90分进化到 100 分,甚至更好。

你的优点是什么?缺点是什么?

手写源码篇

实现原生ajax

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
let ajax = {
get: function(url,callback){
let xhr = new XMLHttpRequest();
/*
xhr.timeout = 1000;// 毫秒
xhr.ontimeout = function(){}
*/
xhr.open('get',url);
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status == 200 || xhr.status == 304){
// 304为有缓存情况下服务端的一种响应
callback(xhr.responseText);
}
}
xhr.send();
},
post: function(url,,data,callback){
let xhr = new XMLHttpRequest();
xhr.open('post',url);
xhr.send(data);
xhr.onreadystatechange = function(){
if(readyState==4&&xhr.state==200 || xhr.state==304){
callback(xhr.responseText);
}
}
}
}

实现防抖节流函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
function showTop() {
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
console.log('滚动条位置:' + scrollTop);
}
// 防抖
function debounce(fn, delay) {
let timer = null; //借助闭包
return function () {
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(fn, delay) // 简化写法
}
}
// 使用
window.onscroll = debounce(showTop, 1000); // 为了方便观察效果我们取个大点的间断值,实际使用根据需要来配置

// 节流
function throttle(fn,delay){
let valid = true;
return function(){
if(!valid) return false;
valid = false;
setTimeout(()=>{
valid = true;
fn();
},delay)
}
}
// 使用
window.onscroll = throttle(showTop,1000)

手写call、apply、bind方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Function.prototype.myCall = function(fn,obj,...args){
// 当obj为null或者是undefined时,设置默认值
if(!obj) obj = window;
let flag = Symbol();
obj[flag] = fn;
const res = obj[flag](...args);
delete obj[flag]
return res;
}

Function.prototype.myApply = function(fn,obj,args){
if(!obj) obj = window;
let flag = new Symbol();
obj[flag] = fn;
const res = obj[flag](...args);
delete obj[flag];
return res;
}

Function.prototype.myApply = function(fn,obj,...args1){
return function(...args2){
return myCall(fn,obj,[...args1,...args2]);
}
}

手写深拷贝

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function deepClone(obj) {
let cloneObj;
if (obj && typeof obj !== 'object') {
// 基本数据类型,直接返回
cloneObj = obj;
} else if (obj && typeof obj === 'object') {
// 数组或对象时,进行深入;
cloneObj = Array.isArray(obj) ? [] : {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
cloneObj[key] = deepClone(obj[key]);
}
}
}
return cloneObj;
}

let per = [{ name: 'tom' }, { name: 'jack' }, { tan: 'ke' }];
let res = deepClone(per);
console.log(res);
res[1].name = 'kate';
console.log(res, per);

手写Promise封装

1
2
3
4
5
6
7
8
9
10
11
function ajax(url,methods,data){
return new Promise((resolve,reject)=>{
let xhr = new XMLHttpRequest();
xhr.open(url,methods);
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.readystate == 4&&xhr.status == 200 || xhr.stauts == 304) resolve(xhr.reponseText);
else reject(xhr.responseText);
}
})
}

项目篇

什么是防抖和节流?

答:场景:比如监听用户滚动滚轮事件,再比如用户反复点击某个功能按钮的时候。

  • 防抖(debounce):事件触发后,等待一定时间,若没有触发相同事件,则执行回调,否则清除计时器,重新计时。
    • 页面resize事件,当浏览器窗口被调整到一个新的高度或宽度时,就会触发resize事件,根据最终结果页面呈现情况进行DOM渲染。
  • 节流(throttle):在回调函数在某一时间段内只执行一次。
    • 应用:搜索框下面的参考,要支持输入实时搜索可以使用节流方案。
  • 可以使用lodash.js库实现防抖节流。

项目中有没有遇到什么难点、问题?

答:

  • 切换页面,刷新页面,如何保证维持用户登录状态的问题,因为vuex是临时数据。如果选择保存密码。

    登录时,如果选择保存密码,往cookie / localStorge中存储;如果没有保存密码,就往sessionStorge存储。存储cookie是使用js-cookie库实现的。如果vuex中的token和

    每次请求前,请求拦截器都会尝试给头部设置cookie字段,如果没有cookie字段,就会报错,代表当前状态为未登录,需要登录。

  • 实现不同用户浏览不同的页面:使用前置路由守卫,后置路由守卫用来实现页签改变,只需要给每个路由设置meta原属性即可。

  • event.preventDefault();  //阻止默认行为 ( 表单提交 )
    

    点击登录后会默认跳转,需要阻止默认行为

使用的插件:vuex、vue-router、js-cookie、nprogress

node.js篇章

NodeJS的特点:它是一个Javascript运行环境 依赖于Chrome V8引擎进行代码解释 事件驱动 非阻塞I/O 轻量、可伸缩,适于实时数据交互应用,单进程,单线程。