前端面试无非包括css、js、框架、项目等几大方面。以下是自己在面试过程中被问到的问题,有的考察js基础,也有比较深入的,理解这些问题不仅仅有助于面试,最重要的是能够在实际过程中尽可能少开发些BUG。现在记个笔记,暂时没有分类,想到哪个记哪个。。
一、url输入浏览器后干了些什么事情?
1.DNS(Domain Name System, 域名系统) 解析
- DNS解析的过程就是寻找哪台机器上有你真正需要的资源过程。
- 当我们在浏览器地址栏中输入一个地址时,例如:baidu.com,其实不是百度网站真正意义上的地址,因为互联网上每一台计算机的唯一标识是他的IP地址,但是IP地址并不方便记忆。
- 所以互联网设计者需要在用户的方便性与可用性做一个权衡,这个权衡就是一个网址到IP地址的转换,这个过程就是DNS解析
- 它(DNS解析)实际上充当了一个翻译的角色,实现了网址到IP地址的转换。当然如果你直接输入的是另一台电脑的IP地址来访问,那么不存在这一步
2.TCP连接(三次握手)
知道了服务器的IP地址,就开始和服务器建立连接了--三次握手
- 第一次握手: 建立连接时,客户端发送syn包(syn=j)到服务器,并进入
SYN_SENT
,等待服务器确认. - 第二次握手: 服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己发送一个SYN包(syn=k),即
SYN+ACK
包,此时服务器进入SYN_RECV
状态 - 第三次握手: 客户端收到服务器的
SYN+ACK
包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED
(TCP链接成功状态),完成三次握手
3.发送HTTP请求
当服务器与主机建立了链接以后,主机开始和服务器进行通信。网页请求是一个单向请求的过程。即一个主机向服务器请求数据,服务器返回相应的数据的过程。浏览器根据URL内容生成HTTP请求,HTTP请求报文是由三部分组成:请求行,请求报头,请求正文。
4.服务器处理请求并返回HTTP报文
服务器接到请求后,会根据HTTP请求中的内容来决定如何获取相应的HTML文件,服务器得到的HTML文件发送给浏览器。HTTP响应报文也是由三部分组成:状态码,响应头,响应报文
状态码
- 1xx: 指示信息,标示请求已接收,急需处理.
- 2xx: 成功信息,标示请求已被成功接收,理解,接收
- 3xx: 重定向,要完成请求必须进行更进一步的操作
- 4xx: 客户端错误,请求有语法错误或请求无法实现
- 5xx: 服务器端错误,服务器未能实现合法的错误
响应头
- 常见的响应头字段有:Server,Connection..
响应报文
- 服务器返回给浏览器的文本信息。HTML,CSS,JS,图片等文件就放在这一部分
5.浏览器解析渲染页面
在浏览器还没有在完全接收HTML文件时便开始渲染网页
在执行HTML中的代码时,根据需要浏览器会继续请求图片、CSS、JavaScript等文件
6.连接结束
7.四次回收连接
- 客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部.FIN=1,其序列号为seq=u(根据前面已经传过来的数据的最后一个序号+1)。此时客户端进入FIN-WAIT-1(终止等待1)状态。TCP规定,FIN报文段即使不携带数据,也要消耗一个序号
- CLOSE-WAIT状态持续期间。服务器收到连接释放报文,发出确认报文ACK=1,ack=u+1,并且带上自己的序列号seq=v此时,服务端就加入了CLOSE-WAIT(关闭-等待)状态。这时连接处于半关闭状态,客户端已经没有数据要发送了。但是服务器若发送数据,客户端仍然接收。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间
- 客户端收到服务器的确认请求后,就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接收服务器发送的最后数据)
- 服务器将最后的数据发送完毕后,就像客户端发送连接释放报文:FIN=1,ack=u+1。由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认
- 客户端收到服务器的连接释放报文后,必须发出确认:ACK=1,ack=w+1。而自己的序列号是seq=u+1,此时客户端进入了TIME-WAIT(时间等待)状态。注意此时TCP连接没有释放,必须经过2MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态
- 服务器只要收到客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次TCP连接。可以看到,服务器结束TCP连接的时间比客户端要更早一些
8.关于TCP三次握手及相关面试题可参考:https://www.cnblogs.com/bj-mr-li/p/11106390.html
二、http协议了解多少?
- 只是了解下的话这篇文章足够:https://www.cnblogs.com/li0803/archive/2008/11/03/1324746.html
- PS:各种请求方式及其含义
请求方式 | 含义 |
---|---|
GET | 请求获取Request-URI所标识的资源 |
POST | 在Request-URI所标识的资源后附加新的数据 |
PUT | 请求服务器存储一个资源,并用Request-URI作为其标识 |
DELETE | 请求服务器删除Request-URI所标识的资源 |
HEAD | 请求获取由Request-URI所标识的资源的响应消息报头 |
TRACE | 请求服务器回送收到的请求信息,主要用于测试或诊断 |
CONNECT | 保留将来使用 |
OPTIONS | 请求查询服务器的性能,或者查询与资源相关的选项和需求 |
PS: OPTIONS
:非简单请求
(对服务器有特殊要求的请求,POST、PUT、DELETE等或CORS跨域时的请求)前发送的预检请求,获取服务器支持的HTTP请求方法;检查服务器的性能
三、webpack打包
https://segmentfault.com/a/1190000016068450
四、性能优化
性能优化太宽泛了,我总结了下自己在实际开发中用到的优化手段,大概有以下几个方面:
- 图片--雪碧图、svg雪碧图、webpack插件优化、第三方工具压缩图片
- 三方库优化--按需加载(lodash、echarts)、懒加载
- CDN引入
- HTML--语义化标签
- JS/TS--代码精简-公共函数封装、页面优化-节流/防抖等、适当运用localStorage和sessionStorage
五、冒泡排序法
- 冒泡排序(更多js排序算法:https://www.cnblogs.com/ybygb-geng/p/9355425.html)
原理:把一个数组中的每一个数从前往后依次进行比较,然后根据大小交换位置,每一轮的比较都确定出一个当轮比较的最大值,最终实现数组的大小排序
var arr = [4,23,100,9,7,49,36,57];
console.log("原始数据:"+arr);
for (var i = 0; i < arr.length-1; i++) { //确定轮数
for (var j = 0; j < arr.length-i-1; j++) { //确定每次比较的次数
if (arr[j] > arr[j+1]) {
tem = arr[j];
arr[j] = arr[j+1];
arr[j+1] = tem;
}
}
console.log("第"+i+"次排序"+arr)
}
console.log("最终排序:"+arr)
console控制台打印如下:
六、一行代码实现数组去重
方法一:ES6中Array新方法Array.from
和Set
数据结构。set的成员都是唯一的 ,其构造函数可以接受一个数组作为参数
let array = Array.from(new Set([1, 1, 1, 2, 3, 2, 4]));
console.log(array);
// => [1, 2, 3, 4]
方法二:使用三方库,如:lodash
var list= [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }];
list = lodash.uniqWith(list, lodash.isEqual)
// => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]
七、解构赋值
- 解构赋值是对赋值运算符的扩展。
- 它针对数组或者对象进行模式匹配,然后对其中的变量进行赋值。
- 在代码书写上简洁且易读,语义更加清晰明了;也方便了复杂对象中数据字段获取。
- 在解构中,有两部分参与:解构的源,解构赋值表达式的右边部分;解构的目标,解构赋值表达式的左边部分
数组模型的解构(Array)
// 基本
let [a, b, c] = [1, 2, 3]; // a = 1 // b = 2 // c = 3
// 可嵌套
let [a, [[b], c]] = [1, [[2], 3]]; // a = 1 // b = 2 // c = 3
// 可忽略
let [a, , b] = [1, 2, 3]; // a = 1 // b = 3
// 不完全解构
let [a = 1, b] = []; // a = 1, b = undefined
// 剩余运算符
let [a, ...b] = [1, 2, 3]; //a = 1 //b = [2, 3]
/* 字符串等 */
// 在数组的解构中,解构的目标若为可遍历对象,皆可进行解构赋值。可遍历对象即实现 Iterator 接口的数据。
let [a, b, c, d, e] = 'hello'; // a = 'h' // b = 'e' // c = 'l' // d = 'l' // e = 'o'
// 解构默认值
let [a = 2] = [undefined]; // a = 2
// 当解构模式有匹配结果,且匹配结果是 undefined 时,会触发默认值作为返回结果。
let [a = 3, b = a] = []; // a = 3, b = 3
let [a = 3, b = a] = [1]; // a = 1, b = 1
let [a = 3, b = a] = [1, 2]; // a = 1, b = 2
// a 与 b 匹配结果为 undefined ,触发默认值:a = 3; b = a =3
// a 正常解构赋值,匹配结果:a = 1,b 匹配结果 undefined ,触发默认值:b = a =1
// a 与 b 正常解构赋值,匹配结果:a = 1,b = 2
对象模型的解构(Object)
// 基本
let { foo, bar } = { foo: 'aaa', bar: 'bbb' }; // foo = 'aaa' // bar = 'bbb'
let { baz : foo } = { baz : 'ddd' }; // foo = 'ddd'
// 可嵌套可忽略
let obj = {p: ['hello', {y: 'world'}] }; let {p: [x, { y }] } = obj; // x = 'hello' // y = 'world' let obj = {p: ['hello', {y: 'world'}] }; let {p: [x, { }] } = obj; // x = 'hello'
// 不完全解构
let obj = {p: [{y: 'world'}] }; let {p: [{ y }, x ] } = obj; // x = undefined // y = 'world'
// 剩余运算符
let {a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40}; // a = 10 // b = 20 // rest = {c: 30, d: 40}
// 解构默认值
let {a = 10, b = 5} = {a: 3}; // a = 3; b = 5; let {a: aa = 10, b: bb = 5} = {a: 3}; // aa = 3; bb = 5;
八、js原型链
- 简单一行代码表示(详见我另一篇文章js原型及原型链):
function Person() {};
var p = new Person();
p.__proto__ === p.contructor.prototype
// p.contructor就是Person,所以上述代码也可以是:
p.__proto__ === Person.prototype
九、 js是同步还是异步,单线程还是多线程,操作原理
JavaScript是一门单线程语言,在最新的HTML5中提出了Web-Worker,但JavaScript是单线程这一核心仍未改变。所以一切JavaScript版的”多线程”都是用单线程模拟出来的。
- 同步和异步任务分别进入不同的执行”场所”,同步的进入主线程,异步的进入Event Table并注册函数。
- 当指定的事情完成时,Event Table会将这个函数移入Event Queue。
- 主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行。
- 上述过程会不断重复,也就是常说的Event Loop(事件循环)。
关于Event Loop:https://segmentfault.com/a/1190000016278115
十、数据结构了解吗?讲一下链表?
数据结构:数组、栈(后进先出)、队列Queue(先进先出)、链表(Linked List)https://www.cnblogs.com/nayek/p/11924204.html
十一、跨域如何解决
纯前端解决:https://segmentfault.com/a/1190000000718840
后端配合解决:https://segmentfault.com/a/1190000003693381
十二、ajax的过程、xmlhttprequest对象
AJAX的原理及实现步骤https://blog.csdn.net/weixin_39194176/article/details/80933777
十三、js实现图片轮播(主要思路?)
https://segmentfault.com/a/1190000018718279
- 图片容器,每张图片都有对应的唯一的编号
- 圆点(用于点击或自动轮播选中)列表容器
- css设置-父级相对,子元素绝对定位
- onload事件监听,默认加载第一张图片,定时或手动滑动时加载目标图片,当前图片隐藏(可通过display:none设置;也可通过图片所在元素left属性设置)
- 自定轮播定时器记得适时清除
十四、js实现DNA链,如下图(主要思路?)
思路:此题考察看css布局、动画相关知识
- 生成两个box(容器,上下分为两部分),分别给每个容器设置3D模式,动画等属性
- 在两个box中生成一定数量的点
- 把box加入body中
关键知识点:
- transform-style: preserve-3d; // 设置3D转化模式
- animation相关
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>JS生成动画</title>
<style type="text/css">
*{
margin: auto;
padding: 0px;
background-color: orange;
}
@keyframes myMove{
from{transform: rotateY(0deg);}/*设置在Y轴上的旋转*/
to{transform: rotateY(360deg);}
}
</style>
</head>
<body οnlοad="init()">
<script>
var i = 0,j = 0;
function init(){
var totalA = 36,deg = 360/totalA;/*指定每个box中a标签的个数*/
for(i = 0;i < 2;i ++){/*生成两个box*/
var box = document.createElement("div");
box.setAttribute("id","box");
box.style.height = "0px";/*隐藏box*/
box.style.marginLeft = "50%";
box.style.marginTop = "2px";
box.style.position = "absolute";
box.style.transformStyle = "preserve-3d";/*设置3D转化模式*/
box.style.animation = "myMove 3s infinite linear alternate";/*为自己的动画设置名字、周期、次数、速度(linear是线性的,速度相同)、来回转(后缀reverse表示反向来回转*/
if(i == 1){
box.style.animation = "myMove 3s infinite linear alternate-reverse";/*第二个box设置反向转*/
}
for(j = 0;j < totalA;j ++){
var newA = document.createElement("a");
newA.style.display = "block";
newA.style.padding = "9px";
newA.style.borderRadius = "50%";
newA.style.backgroundColor = "white";
newA.style.transform = "rotateY(" + j*deg +"deg)translateZ(270px)";/*设置a标签在Y轴上旋转的度数,依次递增;并设置a标签和Z轴(由屏幕从里向外)的距离*/
if(i == 1){
newA.style.backgroundColor = "black";
newA.style.transform = "rotateY(-" + j*deg +"deg)translateZ(270px)";
}
box.appendChild(newA);/*在box中放入a标签*/
}
document.body.appendChild(box);/*在body中放入box*/
}
}
function clear(){
for(i = 0;i < 8;i ++){
var box = document.getElementById("box");/*通过ID获取box*/
box.remove(box.childNodes[0]);/*依次将box移除*/
}
}
setInterval(init,3000);
setInterval(clear,9000);
</script>
</body>
</html>
十五、滚屏加载如何实现?
PS:scrollTop、scrollHeight、offsetTop、offsetHeight等属性解释
https://www.cnblogs.com/wenruo/p/9754576.html
// 主要思路
1.页面初始化时,获取文档高度,记录下当前加载的数据条数,并设置初始值1(第几次滚动)。初始时文档高度为固定值,以后每次滚动,都拿此高度做对比-->如果滚动的距离+页面可视区域高度>初始文档高度×滚动次数,则请求数据,请求完成后保存该组数据,与当前滚动次数存为键值对
2.向上/向下滚动如何判断: 每次滚动,都拿当前滚动条高度与之前的做比较,大了说明向下滚动,反之是向上滚动(滚动次数需实时更新,向下滚动+1,向上滚动-1)。向上滚动不再重新请求数据,直接根据滚动次数从键值对中获取
// 核心代码
$(window).scroll(function () {
// document.documentElement.scrollTop 滚动条的高度
var scrollerh = $(document).scrollTop();
// window.innerHeight 当前窗体可视区域的高度
var viewbody = $(window).height();
// document.body.scrollHeight 整个文档的高度
var allbody = $(document).height();
if (scrollerh + viewbody > allbody - 100) {
alert("加载啊")
}
}
十六、require与import区别?(commonJS与esModule?)
- require是运行时调用,所以可以随处引入;import是编译时调用,必须放在文件开头引入,目前部分浏览器不支持,需要用babel把es6转成es5再执行
- ES6 的模块自动采用严格模式,不管你有没有在模块头部加上
"use strict";
十七、Set 和 Map 数据结构(WeakSet、WeakMap)
Set
类似于数组,但是成员的值都是唯一的,没有重复的值。(Set 内部判断两个值是否不同,使用的算法叫做“Same-value-zero equality”,它类似于精确相等运算符(===
),主要的区别是向 Set 加入值时认为NaN
等于自身,而精确相等运算符认为NaN
不等于自身。)Set
函数可以接受一个数组(或者具有 iterable 接口的其他数据结构)作为参数,用来初始化。WeakSet
结构与Set
类似,也是不重复的值的集合。它与Set
有两个区别- 首先,
WeakSet
的成员只能是对象,而不能是其他类型的值。 - 其次,
WeakSet
中的对象都是弱引用,即垃圾回收机制不考虑WeakSet
对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于WeakSet
之中
- 首先,
Map
类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。WeakMap
结构与Map
结构类似,也是用于生成键值对的集合。区别:WeakMap
只接受对象作为键名(null
除外),不接受其他类型的值作为键名WeakMap
的键名所指向的对象,不计入垃圾回收机制传统对象
:一旦不再需要这两个对象,我们就必须手动删除这个引用,否则垃圾回收机制就不会释放该对象占用的内存;WeakMap
:它的键名所引用的对象都是弱引用,即垃圾回收机制不将该引用考虑在内。因此,只要所引用的对象的其他引用都被清除,垃圾回收机制就会释放该对象所占用的内存。也就是说,一旦不再需要,WeakMap 里面的键名对象和所对应的键值对会自动消失,不用手动删除引用
WeakMap
与Map
在 API 上的区别主要是两个,一是没有遍历操作(即没有keys()
、values()
和entries()
方法),也没有size
属性。因为没有办法列出所有键名,某个键名是否存在完全不可预测,跟垃圾回收机制是否运行相关。这一刻可以取到键名,下一刻垃圾回收机制突然运行了,这个键名就没了,为了防止出现不确定性,就统一规定不能取到键名。二是无法清空,即不支持clear
方法。因此,WeakMap
只有四个方法可用:get()
、set()
、has()
、delete()
。
https://es6.ruanyifeng.com/#docs/set-map#WeakSet
十八、三大框架比较
https://m.html.cn/qa/angular-js/11927.html
十九、react相关
- setState、redux
https://segmentfault.com/bookmark/1230000018347494
- react hook
https://segmentfault.com/a/1190000019966124
- react类组件和函数组件
https://segmentfault.com/a/1190000020861150
- react生命周期
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。