经过几个月的准备和无数次的一轮游,终于获得了理想的实习。
这几个月里参与了腾讯,YY,字节等一系列公司的面试,个人感觉前端这个岗位在校招时期的面试内容还是非常基础的,并且有些问题的出现频率非常高,好好准备的话进大厂的机会还是很大的。
现在想回过头好好梳理下自己这几个月做的一些笔记和面试中总结的一些常见问题。一个是希望自己能在整理的过程中继续夯实自己掌握的基础知识,同时也希望能对其他正在准备面试的同学有一些帮助。
****↓↓↓想了想这段话要写在前面↓↓↓
我也只是一个刚开始学前端没有太长时间的小白,这次写的只是我在准备校招面试的过程中比较重要的内容,算是类似学习笔记一样的东西,可能不会非常全面。并且很多内容依然理解的不是很深入甚至应该说只看了个皮毛,如果存在错误请各位大佬及时指出,我也非常希望能在交流当中不断查缺补漏,提升自己。
并且这本身就是个类似笔记之类的东西,我会尽量找到我看过的参考链接放在每个文章的末尾,希望各位不要介意。
HTML
操作dom节点的基础方法
1. 获取节点
a) document.getElementById() 第一个id相符合的节点
b) document.getElementsByTagName() 返回符合标签的数组
c) document.getElementsByClassName() 返回符合类名的数组
d) document.getElementsByName() 返回符合名字的数组
e) node.children/node.childNodes 返回子节点数组
f) node.parentNode/node.offsetParent 返回父节点
g) node.firstChild、node.lastChild 返回第一个和最后一个子节点
h) node.nextElementSibling返回下一个节点
i) node.previousElementSibling 返回上一个节点
2. 删除节点
Node.remove()
parentNode.removeChild(子节点)
3. 增加节点
parentNode.appendChild(childNode)
parentNode.insertBefore(newChild,oldChild)
4. 创建节点
document.createElement(“tagName”)
document.createTextNode(“text”)
5. 替换节点
parentNode.replaceChild(newChild,oldChild)
6. 复制节点
node.clone(true/false) true为深复制,false为浅复制
7. 操作节点属性
Node.setAttribute(“属性名”,”值”)
Node.classList.add(“class名”,。。。) 新增class给节点
Node.classList.remove(“class名”,。。。) 移除节点的class
Node.classList.contains(“class名”) 判断是否含有某个class
Node.style.属性名=”值” 修改节点的style
defer和async对script标签的不同影响
正常情况下,浏览器遇到script标签的时候会将GUI线程挂起,先加载执行完脚本,再重启GUI线程,但是可以通过defer和async字段来进行控制
如图所示
蓝色是网络读取,红色是执行时间,绿色是html解析
defer和async都可以让浏览器在加载脚本的时候并行解析html文件,区别在于加载完成之后。
Defer会按顺序读取执行,并且会等到html解析完成再按顺序执行
而async是加载完成后立刻执行,并且是谁先加载完就先执行,不会按照出现顺序执行
H5新内容
- 有一些新的语义标签比如、,利于页面更好的语义化,有利于SEO
- 提供了sessionStorage、LocalStorage等存储方式
- 新增了离线web应用功能
- Input元素新增了表单属性,之前input中的name和value要和表单一起提交,需要用form表单包含住所有input一起提交,现在的input元素新增了form属性,可以直接绑定在某个表单上,不一定要包含在表单中
同时Input元素还增加了placeholder、autofocus等属性,type增加了email等选项 - 新增了视频(video)和音频(audio)功能
- 新增了Canvas绘图功能
- 支持websocket 连接后可以进行全双工通讯,允许服务器主动向客户端推送数据
- 新增了Web workers,可以在后台独立运行脚本,不会影响页面性能
CSS
display属性
一般来讲比较常问的就是display为block和inline-block
对于内行元素来讲设置宽高是无效的,并且无法设置左右的margin,只能设置上下的margin
如果将内行元素display设置为block的话就可以设置其宽和高
设置为inline-block的话会让流将元素当做内行元素看待,但是元素本身属于块元素,可以设置高度等属性
BFC
特性:
- 处于BFC内部的盒子会在垂直方向一个接一个的放置
- 内部的box之间的垂直距离由margin决定,同一个BFC中的盒子垂直之间会发生margin重叠
- 形成了BFC的区域不会与浮动元素重叠(不会被浮动的元素遮盖)
- BFC元素计算高度的时候会将内部的浮动元素纳入计算
形成BFC的情况:
- 页面根元素
- 浮动元素(float不为none)
- 绝对定位元素(position为absolute或fixed)
- 内行块元素,表格单元格,表格标题等(display:inline-box,table-cell,table-caption)
- 网格元素,弹性布局的直接子元素(display:flex,grid)
- Display设置为flow-root
- Overflow的值不为visible的元素
- 多列容器(column-count或column-width不为auto)
元素居中
- 纯利用margin居中
将元素的margin设置为auto可达到水平居中的效果(需要是块级元素)
将父元素的display设置为flex,再将元素margin设置为auto则水平和垂直同时居中 - 利用绝对定位和margin居中(需要知道元素尺寸)
先将元素用absolute绝对定位,left和top设置为50%,再将margin-top和margin-left设置为自身宽高的一半的负数 - 利用绝对定位和transform居中
子元素使用absolute绝对定位,并且将left和top分别设置为50%,然后对子元素设置transform:translate(-50%,-50%)自动往回偏移自己的一半尺寸 - flex布局居中
父元素设置为flex布局,并且将justify-content和align-item设置为center - 利用父元素line-height设置垂直居中
将父元素行高设置为父元素自身高度,子元素实现垂直居中
选择器优先级
!important——style——id选择器——类、伪类、属性选择器——元素选择器、伪元素——继承属性——通配符选择器
css层叠
- 何时产生层叠上下文
1. 根元素、
2. 设置z-index为具体数值(auto不行)
3. CSS3中一些新属性(比如opacity不为1,transform不为none,父元素为flex布局同时自己的z-index不为auto) - 层叠顺序
层叠上下文的background——z-index为负数——普通block盒子——float盒子——inline/inline-block盒子——z-index为零或者auto——z-index大于零
伪类与伪元素
- 伪类
UI伪类——可以用于向选择器添加特殊的效果,常用的比如hover、visited
结构伪类——当html元素存在某种结构的时候应用的样式 比如 :nth-child(n)
- 伪元素
可以大致理解为“只能通过添加一个新标签才能实现的效果,只用class和style无法实现”,常用的比如 ::before和 ::after等
animation与transition制作动画
flex布局
此处建议直接看阮一峰老师的博客
www.ruanyifeng.com/blog/2015/0…
www.ruanyifeng.com/blog/2015/0…
重排与重绘
普通图层和复合图层
浏览器渲染图层分为两大类:普通图层和复合图层
普通文档流内算是一个复合图层,即使是absolute和fixed也算在这个默认复合层内
可以通过硬件加速的形式声明一个新的复合图层,这样可以单独分配一个资源
一个复合图层内的改变不会影响到其他复合层的变化
声明复合层的办法:
- translate3d/translate
- opacity属性/过渡动画
- video iframe canvas等元素
因为复合图层不影响默认图层,所以可以避免整个页面重绘从而提高性能
但是不要大量使用,不然会大量占用资源反而变卡
opacity:0,visibility:hidden,display:none的区别
- opacity:0
会让子节点也无法显示
会提升为合成层,开启硬件加速
元素不会从流中消失,只是透明,但是占位置并且可以点击
- display:none
会让子元素也无法显示
让元素直接从流中消失,不占位置也不能点击
会引起重排
- visibility:hidden
子元素可以设置visibility:visible来显示
元素被隐藏,元素不会从流中消失,看不见但是会占空间,但是无法被点击
会引起重绘但是不会引起重排
JS
事件流
原型链
1. 如何判断是否为某个原型的实例
a) Console.log(实例 instanceof 原型)——是的话返回true
b) Console.log(原型.prototype.isPrototypeOf(实例))——是的话返回true
c) Console.log(原型.constructor == 构造函数)——是的话返回true
d) 通过判断Object.getPrototype(实例)来判断
2. 单独用原型链继承的问题
a) 原型链包含引用类型时,引用类型会被所有实例共享
b) 创建子类型的时候无法向父类构造函数传参
3. 弥补原型链继承问题的方法,借用构造函数继承
此方法下原型链中引用类型不再被共享,创建子类型也能向父构造函数传参
存在问题:
父类的方法需要在构造函数中定义才能被子类继承,直接向父类prototype添加的函数和变量无法被子类访问
4. 弥补借用构造函数继承问题的方法,组合继承
基本思想为用原型链实现对原型属性和方法的继承,通过借用构造函数来实现对实例属性的继承,这样就可以调用父类原型的函数了
存在问题:
调用了两次构造函数(call一次,new一次),造成了不必要的消耗
5. 减少调用两次构造函数开销的方法,组合寄生继承
// 实现继承的函数
function extend(subClass,supClass) {
// 复制出一个父类原型对象
let prototype = Object(supClass.prototype)
prototype.constructor = subClass;
// 将这个对象的构造函数绑定为子类构造函数
subClass.prototype = prototype;
// 子类的原型设置为这个对象
}
基本思想,用父类的prototype创建一个新对象,用子类的构造函数作为此对象的构造函数,再将子类构造函数指向此原型。相比于组合继承,create直接复制了父类的prototype而没有再去调用父类构造函数,因此节省了资源
js实现继承的不同方法
this指针
promise async
event loop
变量隐式转换
call apply bind 方法
执行上下文以及变量对象等内容
闭包
New一个对象的过程
发布者和订阅者的原理
深拷贝与浅拷贝
es6的一些新内容
手动实现一些函数
小知识点
计网
OSI七层模型
1. 应用层
其它层封装好的接口,用户在此进行操作包括FTP,DNS,SMTP,HTTP等协议
2. 表示层
数据格式的转化,数据加密压缩等
3. 会话层
建立、管理、维护会话
4. 传输层
建立、管理、维护端到端的链接 TCP UDP
5. 网络层
IP选址以及路由选择
6. 数据链路层
提供介质访问,将数据分成帧,包含查错等功能
7. 物理层
传输透明比特流
TCP/IP模型
TCP/IP是互联网相关各种协议的总称,这些协议可以分为四层
应用层——向用户提供应用程序,HTTP/FTP/DNS等在此层
传输层——负责对报文进行分组和重组,TCP和UDP位于此层
网络层——负责路由选择,将报文发送给目标网络或主机,IP位于此层
链路层——传输有地址的帧,有错误检测功能,二进制数据形式传输
什么是跨域及解决方法
请求方式以及状态码
http1.x 到 http2.0 的变化
- HTTP1.1相对于HTTP1的区别
1. 增加了控制缓存的字段
HTTP1中只是使用if-modified-since和expires来作为缓存判断标准
HTTP1.1增加了e-tag,if-none-match等字段来控制缓存
2. 优化了带宽的使用
HTTP1中不支持断点续传,有时虽然用户只申请一部分内容但是会传输整个文件,这就造成了带宽的浪费
HTTP1.1引入了range请求头,允许只请求资源的某个部分,返回码为206
3. 增加了新的错误响应码
409——请求的资源与资源当前资源状态发生冲突
410——资源永久删除
。。。
4. HOST头可以指定主机名了
HTTP1中认为一个服务器只能绑定唯一的IP,所以请求中并没有包含主机名
后来一台机器可以同时运行多个虚拟主机并且共享同一个ip地址
HTTP1.1头部增加了host头,可以指定主机名
5. 开始支持长连接
HTTP1中建立一次连接只能发送一个请求
HTTP1.1中默认开启长连接(connection:keep-alive),一次握手可以传送多个请求,但是每个请求需要等待上一个请求完成后才能发送
- HTTP2.0相对于HTTP1.1区别
1. 二进制传输
HTTP1.X是基于文本传输,不够健壮
HTTP2.0用二进制传输,非常健壮
将报文分为帧来进行传送(报头帧、优先级帧、数据帧)
帧结构:帧长、帧类型、帧类型相关布尔标识、保留位、stream identifier(用于流控)、主体内容
2. 多路复用
连接可以共享,每个请求对应一个id,数个请求同时发送,即使其中一个任务耗时较长,也不会影响其他链接正常执行
(因为不再存在请求阻塞的问题,所以对http2来说,雪碧图,合并文件等优化方式显得没有那么重要了)
3. Header压缩
Header中包含了大量信息,并且每次可能会重复发送,HTTP2.0使用encoder来减少header大小,双方都保存一个header的cache,拿到过后对应解码就好
4. 服务端推送
HTTP1.1只能由客户端发请求然后服务器回复,HTTP2.0中服务器端可以主动推送内容给客户端
一些后续可能用到的资源服务器可以先主动推送给客户端,之后客户端要用的时候直接从缓存中拿(可以拒收)
https原理的简单介绍
不使用SSL/TLS的HTTP通信会有三个风险:
- 被窃听
- 被篡改
- 被冒充
使用了SSL/TLS是为了解决这三个风险:
- 信息加密传播,无法被监听
- 有校验机制,要是被篡改内容双方可以发现
- 用身份证书来防止冒充
HTTPS握手顺序:
- 客户端发请求,内容包括
- 支持的TLS协议版本 比如1.0
- 客户端生成的随机数,稍后用于生成对话秘钥
- 客户端支持的加密方法
- 客户端支持的压缩方法
客户端发送的信息中不包括服务器的域名,所以理论上服务器只能有一个网站,所以一般一台服务器只有一张数字证书。不过之后TLS协议加入了扩展字段,允许客户端向服务器提供请求的域名
2. 服务器回应,内容包括
- 一个服务器生成的随机数,之后用于生成对话秘钥
- 确认要使用的加密方法
- 服务器证书
- 可能还会要求客户端提供客户证书来验证客户身份
3. 客户端回应之前会先验证服务器证书,验证是否是可信机构颁布,证书域名和实际域名是否一致,证书是否过期等。没问题则从证书取出服务器公钥,回复如下信息:
- 一个随机数,用服务器公钥加密,防止被窃听
- 编码改变通知,表示随后信息都将用双方商定的加密方法和秘钥发送
- 客户端握手结束通知
- 如果服务器要求客户端验证身份的话,客户端在这一步也会发送证书等信息
4. 服务器收到了客户端的回应后,会用前面生成的三个随机数生成本次会话所用的会话秘钥,然后向客户端发送以下信息:
- 编码改变通知,同样表示之后双方都用商定好的加密方式和秘钥发送
- 服务器结束握手
常用请求头和返回头
强缓存与协商缓存
- 强缓存
强缓存会在发送http请求之前进行检测,要是命中则不需要再进行http请求
在http1中强缓存用Expires设置过期时间,设置的是到期时间
在http1.1中强缓存可以在Cache-Control中设置max-age来设置缓存生存时间 存在缺点:可能强缓存的时间没到服务器资源就改变了,用户看到的就是旧页面 - 协商缓存
需要发请求确认,通过在请求头中加入tag让服务器来判断是否过期
第一种tag:last-modified 和 if-modified-since
在第一次请求资源后服务器返回资源时响应头带有last-modified,表示此资源最后修改时间,浏览器后续请求的时候用if-modified-since带上这个时间,让服务器判断这个时间之后是否改动过,未改动过就返回304,改动过就返回200和新资源,并更新last-modified
第二种tag:ETag
ETag是文件唯一的标识,如果文件改动过的话ETag也会变化,第一次请求后服务器返回资源和资源的ETag,浏览器下一次请求的时候用if-none-match带上这个值,服务器要是找到这个etag的文件就说明没改动过,返回304,找不到则返回200状态码、新的资源和新的etag(etag优先级比last-modified要高)
TCP和UDP的区别
UDP全称为用户数据报协议,在网络中与TCP一样用于处理数据报,是一种无连接协议,位于传输层。UDP有不提供数据包分组、组装以及不能对数据报进行排序的缺点,也就是说无法知道报文是否安全到达。
UDP特点:
1. 面向无连接,不像TCP那样需要三次握手四次挥手,想发就发,并且单纯是搬运数据,不对报文进行任何的拆解和拼装。UDP拿到要发送的数据直接加了个UDP头就传递给网络层了,接收端也单纯除去UDP头就传递给应用层
2. 有单播,多播,广播的功能,可以一对多,多对多,多对一的发送数据。
3. UDP是面向报文的,如同第一点,除了加个报头UDP不会对报文进行任何操作,所以应用程序必须选择合适大小的报文
4. 不可靠性。UDP是无连接的,想发就发,收到什么数据就向外面发送,不备份也不关心对方是否收到,并且没好友拥塞通知,会一直以恒定的速度发送数据。网络条件不好的情况下很容易导致丢包,但是对于某些实时性要求很高的场景比如电话会议就很适合用UDP
5. 头部开销很小,传输报文很高效。UDP头部如下:
a) 俩十六位端口号(源端口号可选)
b) 数据报文长度
c) 数据报文校验和(IPv4可选)
TCP协议全称是传输控制协议,是一种面向连接的、可靠的、基于字节流的传输层通信协议。每一次数据传输都以三次握手开头,以四次挥手结尾。
TCP协议特点:
1. 面向连接,发送数据之前必须在两端建立连接(三次握手)这样为数据的可靠传输打下基础
2. 仅支持单播,每条TCP连接只能有两个端点,不支持多播和广播
3. 面向字节流传输,不像UDP那样面向报文。
4. 传输可靠,用TCP的段编号和确认好可以判断丢包和误码,只要接收方返回了一个包的编号的ACK就代表成功了,不然会被重传
5. 有拥塞控制。慢启动等算法当网络拥塞的时候TCP会减小向网络注入数据的速率
6. 全双工通信,TCP的通信双方在任何时候都能发数据,两端都有缓存。
简单总结:
UDP是无链接并且面向报文的,应用层发下来一个报文他加一个UDP头部就直接发出去了,没有一些重传机制也不会考虑网络是否拥塞、接收端是否有能力接收,所以UDP不是很可靠并且容易出现丢包等情况,并且UDP支持单播、多播、广播,可以一对一、一对多的发送数据。
TCP面向连接并且是分段进行传输,每一个段会打上编号用于判断丢包和误码,要是没有被确认接收可以重传,这保证了tcp的可靠性。并且tcp有拥塞控制,当网络不好的时候可以调整数据传输速率。Tcp仅支持单播通信。
host,referer,origin的区别
浏览器
浏览器不同的线程
1. GUI渲染线程
负责渲染浏览器界面,解析HTML、css、计算布局、绘制等。当页面需要重排或者重绘的时候该线程就会执行。
与JS线程互斥,JS线程执行的时候GUI线程会被挂起,等JS引擎空闲的时候立即执行。
2. JS引擎线程
JS内核,负责处理JS脚本程序。一个tab页面一直只有一个js线程在运行。
由于JS线程与GUI互斥,过长的JS执行时间会导致页面渲染不连贯。
3. 事件触发线程
归属于浏览器而不是JS引擎,用于控制事件循环。Js引擎执行setTimeout等代码块的时候会把任务添加到事件线程中。当某条件触发的时候,此线程把事件添加到待处理队列末尾等待JS引擎处理。
4. 定时器线程
setTimeout和setInterval所在的线程,用于计时并触发定时(添加到事件队列中等js引擎空闲则执行)
5. 异步http请求线程
检测到状态变更的时候如果设置了回调函数,就产生变更事件,将回调放入事件队列等待js引擎执行
BOM对象
浏览器加载并渲染页面的过程
VUE
vue双向数据流实现原理
vue响应式原理
diff算法的简单逻辑
computed和watch的区别
生命周期及相应钩子函数
vuex
vue中组件通信方法
vue路由
一些小知识点
性能优化技巧
懒加载和预加载
dom操作优化
防抖和节流
针对vue生成的app.js文件大小的优化
安全问题
CSRF和XSS攻击
杂项
sessionStorage,localStorage以及cookie的区别
在浏览器中输入url后发生了什么
-
当我们输入完url的时候浏览器会开始构建请求行,检测域名是否合法,合法就将任务交给网络请求线程
-
构建好请求先去检测强缓存(expires和cache-control)是否有效(不是发网络请求),如果无效就开始进行DNS域名解析,如果之前访问过这个URL的话浏览器会将解析后的IP地址保存下来,就可以直接命中。没有的话就要去运营商或者DNS服务器找
-
拿到DNS的IP地址过后就开始构建HTTP请求,开始三次握手建立稳定连接
SYN----SYN ACK----ACK -
建立好三次握手之后,TCP协议会将HTTP报文切割并且编码为一个个数据报,转交给网络层方便传输
-
服务器收到数据后,先将报文还原成完整的,这个时候会校验是否有权限,是否设置了缓存、缓存是否过期等,如果设置了协商缓存(if-none-match和if-modified-since)并且命中,会返回304通知浏览器用缓存内容
-
收到返回后浏览器开始解析请求的文件,先调用GUI线程解析HTML和CSS文件,将HTML文件生成DOM树,对CSS文件进行格式化和标准化生成CSSOM树,最后合并生成DOM树。虽然HTML和CSS文件的解析互不影响,但是会影响最后合成树的生成速度,所以CSS文件不要用 @important ,这会让css解析完毕之后再去加载对应资源
-
因为GUI线程和JS线程是互斥的,所以当解析到script标签的时候会挂起GUI线程从而阻塞渲染。最好不要用async,因为异步加载完js过后会立刻执行
-
将图层生成绘制指令,生成图块和位图,最后显示页面