前端面试无非包含 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 等文件. 过程同申请 HTML
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 | 申请查问服务器的性能,或者查问与资源相干的选项和需要 |
三、webpack 打包
https://segmentfault.com/a/1190000016068450
四、性能优化
性能优化太宽泛了,我总结了下本人在理论开发中用到的优化伎俩,大略有以下几个方面:
- 图片 – 雪碧图、svg 雪碧图、webpack 插件优化、第三方工具压缩图片
- 三方库优化 – 按需(lodash、echarts)、懒加载
- CDN 引入
- HTML– 语义化标签
- JS/TS– 代码精简 - 公共函数封装、页面优化 - 节流 / 防抖等
五、冒泡排序法
- 冒泡排序(更多 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
Set
数据结构。其相似于数组,然而 它的成员都是惟一的,其构造函数能够承受一个数组作为参数
let array = [1, 1, 1, 1, 2, 3, 4, 4, 5, 3];
let set = new Set(array);
console.log(set);
// => Set {1, 2, 3, 4, 5}
办法二:ES6 中 Array 新函数:
Array.from
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