1.算法题:实现一个链接,可以新增节点,删除节点
function insert(head, n ,val) {
var node = {
val: val,
next: null
}
if (head == null) {
return node
}
if (n === 0) {
node.next = head;
return node;
}
var p = head;
for(var i=0; i<n-1; i++){
p = p.next;
}
node.next = p.next;
p.next = node;
return head;
}
function remove(head, n) {
if (!head) {
return null;
}
if (head === 0) {
return head.next;
}
var p = head;
for(var i=0; i<n-1; i++) {
p = head.next;
}
p.next = p.next.next;
return head;
}
2.实现一个instanceof方法
function myInstanceOf(left, right) {
if (typeof left !== 'object' || left == null) {
return false;
}
let pro = Object.getPrototypeOf(left);
while(true) {
if (pro === null) {
return false;
}
if (pro === right.prototype) {
return true;
}
pro = Object.getPrototypeOf(pro);
}
}
3.响应式布局怎么实现 rem布局 flex布局
rem
(function(doc, win) {
var docE1 = doc.documentElement,
resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
recalc = function() {
var clientWidth = docE1.clientWidth;
if (!clientWidth) return;
docE1.style.fontSize = clientWidth / 7.5 + 'px';
}
if(!doc.addEventListener) return;
win.addEventListener(resizeEvt, recalc, false);
doc.addEventListener('DOMContentLoaded', recalc, false);
})(document, window)
4.事件循环机制
- 1.一开始整段脚本作为第一个宏任务执行
- 2.执行过程中同步代码直接执行,宏任务进入宏任务队列,微任务进入微任务队列
- 3.当前宏任务执行完出队,检查微任务队列,如果有则依次执行,直到微任务队列为空
- 4.执行浏览器 UI 线程的渲染工作
- 5.检查是否有Web worker任务,有则执行
- 6.执行队首新的宏任务,回到2,依此循环,直到宏任务和微任务队列都为空
5.设计模式:观察-订阅者模式 与 观察者模式的区别
6. https过程
HTTPS协议=HTTP协议+SSL/TLS协议,数据传输的过程中,需要使用SSl/TLS协议对数据进行加密和解密,需要用HTTP对加密后的数据进行传输,由此可以看出HTTPS是由HTTP和SSL/TLS一起合作完成的。
- HTTPS为了兼顾安全与效率,同时使用了对称加密和非对称加密。
- 数据是被对称加密传输的,对称加密过程需要客户端的一个密钥, 为了确保能把该密钥安全传输到服务器端,采用非对称加密对该密钥进行加密传输,
- 总的来说,对数据进行对称加密,对称加密所要使用的密钥通过非对称加密传输。
为什么要使用对称加密?
原因:非对称加密基于大数运算,比如大素数或者椭圆曲线,是复杂的数学难题,所以消耗计算量,运算速度慢。除了慢,可能还有一个缺点就是需要更多的位数,相同强度的对称密钥要比非对称密钥短。对称密钥一般都128位、256位,而rsa一般要2048位,不过椭圆曲线的会短一点
7.http2的优化点
-
头部压缩: 采用HPACK算法,在客户端和服务端两端建立“字典”,用索引号表示重复的字符串, 还采用哈夫曼编码来压缩整数和字符串,可以到达50%-90%的高压缩率。
-
多路复用: 采用二进制分帧传输,不存在先后关系, 因此也就不会有等待排队,也就没有了HTTP 的对头阻塞问题。 通信双方都可以给对分发送二进制帧, 这种二进制帧的双向传输的序列,也叫做流。 HTTP/2用流来在一个TCP连接上来进行数据帧的通信, 这就是多路复用的概念。
-
设置请求优先级: 在二进制帧当中还有其它的一些字段, 实现了优先级和流量控制等功能
-
服务器推送 服务器不再是完全被动地响应请求,也可以新建“流”主动向客户端发送消息。
8.介绍csrf以及应对手段
CSRF 攻击就是黑客利用了用户的登录状态,并通过第三方的站点来做一些坏事
应对手段:
-
1.充分利用好 Cookie 的 SameSite 属性。 我们可以针对实际情况将一些关键的 Cookie 设置为 Strict 或者 Lax 模式, 这样在跨站点请求时,这些关键的 Cookie 就不会被发送到服务器,从而使得黑客的 CSRF 攻击失效。
-
- 验证请求的来源站点。 HTTP 请求头中的 Referer 和 Origin 属性 服务器的策略是优先判断 Origin,如果请求头中没有包含 Origin 属性, 再根据实际情况判断是否使用 Referer 值
-
- CSRF Token
第一步,在浏览器向服务器发起请求时,服务器生成一个 CSRF Token。 CSRF Token 其实就是服务器生成的字符串,然后将该字符串植入到返回的页面中。 第二步,在浏览器端如果要发起转账的请求,那么需要带上页面中的 CSRF Token, 然后服务器会验证该 Token 是否合法。如果是从第三方站点发出的请求, 那么将无法获取到 CSRF Token 的值,所以即使发出了请求, 服务器也会因为 CSRF Token 不正确而拒绝请求。
- CSRF Token
9.优化白屏的方式
- 提取第三方库,第三方依赖文件以及打包文件放进CDN服务器
- 对路由进行懒加载
- 首页白屏添加骨架屏或loading(仅仅是优化体验)
- 优化 webpack 减少模块打包体积,code-split 按需加载
- 服务端渲染,在服务端事先拼装好首页所需的 html
- 服务端开启gzip压缩
- element-ui等UI框架按需引入
- 打包文件分包,提取公共文件包
- 使用文件名增加hash名,解决新版本需要清除依赖的问题
- 代码压缩
- 压缩图片文件,减少文件体积
- 图片资源放进CDN服务器
- 使用CSS精灵图
10.继承与组合的优缺点
11.http缓存
1.先判断强缓存是否生效: 控制强缓存的字段分别是Expires和Cache-Control(优先级较高),
Expires:是HTTP/1.0控制网页缓存的字段, 值为服务器返回该请求结果缓存的到期时间
即再次发起该请求时,如果客户端的时间小于Expires的值时,直接使用缓存结果。
到了HTTP/1.1,Expire已经被Cache-Control替代
Cache-Control:主要取值
。 public:所有内容都将被缓存(客户端和代理服务器都可缓存)
。 private: 所有内容只有客户端可以缓存,Cache-Control的默认取值
。 no-cache:客户端缓存内容,但是是否使用缓存则需要经过协商缓存来验证决定
。 no-store:所有内容都不会被缓存,即不使用强制缓存,也不使用协商缓存
。 max-age=xxx (xxx is numeric):缓存内容将在xxx秒后失效
内存缓存(from memory cache)和硬盘缓存(from disk cache)
。内存缓存(from memory cache):内存缓存具有两个特点,分别是快速读取和时效性:
。快速读取:内存缓存会将编译解析后的文件,直接存入该进程的内存中,
占据该进程一定的内存资源,以方便下次运行使用时的快速读取。
。时效性:一旦该进程关闭,则该进程的内存则会清空。
。硬盘缓存(from disk cache):硬盘缓存则是直接将缓存写入硬盘文件中,
读取缓存需要对该缓存存放的硬盘文件进行I/O操作,然后重新解析该缓存内容,读取复杂,速度比内存缓存慢。
在浏览器中,浏览器会在js和图片等文件解析执行后直接存入内存缓存中,
那么当刷新页面时只需直接从内存缓存中读取(from memory cache);
而css文件则会存入硬盘文件中,所以每次渲染页面都需要从硬盘读取缓存(from disk cache)。
2.协商缓存
协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,
由服务器根据缓存标识决定是否使用缓存的过程
控制协商缓存的字段分别有:Last-Modified/If-Modified-Since 和 Etag/If-None-Match(优先级高)
Last-Modified / If-Modified-Since:
Last-Modified是服务器响应请求时,返回该资源文件在服务器最后被修改的时间。
If-Modified-Since则是客户端再次发起该请求时,携带上次请求返回的Last-Modified值,
通过此字段值告诉服务器该资源上次请求返回的最后被修改时间。
服务器收到该请求,发现请求头含有If-Modified-Since字段,
则会根据If-Modified-Since的字段值与该资源在服务器的最后被修改时间做对比,
若服务器的资源最后被修改时间大于If-Modified-Since的字段值,则重新返回资源,状态码为200;
否则则返回304,代表资源无更新,可继续使用缓存文件
Etag / If-None-Match :
Etag是服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成)。
If-None-Match是客户端再次发起该请求时,携带上次请求返回的唯一标识Etag值,
通过此字段值告诉服务器该资源上次请求返回的唯一标识值。
服务器收到该请求后,发现该请求头中含有If-None-Match,
则会根据If-None-Match的字段值与该资源在服务器的Etag值做对比,一致则返回304,代表资源无更新,
继续使用缓存文件;不一致则重新返回资源文件,状态码为200,
总结:
强制缓存优先于协商缓存进行,若强制缓存(Expires和Cache-Control)生效则直接使用缓存,
若不生效则进行协商缓存(Last-Modified / If-Modified-Since和Etag / If-None-Match),
协商缓存由服务器决定是否使用缓存,若协商缓存失效,那么代表该请求的缓存失效,
重新获取请求结果,再存入浏览器缓存中;生效则返回304,继续使用缓存
12.require 与 import 的区别
- 1.原生浏览器不支持 require/exports,可使用支持 CommonJS 模块规范的 Browsersify、webpack 等打包工具,它们会将 require/exports 转换成能在浏览器使用的代码。
- 2.import/export 在浏览器中无法直接使用,我们需要在引入模块的
- 3.即使 Node.js 13.2+ 已经支持 import/export,Node.js官方不建议在正式环境使用,目前可以使用 babel 将 ES6 的模块系统编译成 CommonJS 规范(注意:语法一样,但具体实现还 是require/exports)
-
- require/exports 是运行时动态加载,import/export 是静态编译
-
- require/exports 输出的是一个值的拷贝,import/export 模块输出的是值的引用
-
- ES6 模块可以在 import 引用语句前使用模块,CommonJS 则需要先引用后使用
-
- import/export 只能在模块顶层使用,不能在函数、判断语句等代码块之中引用;require/exports 可以
-
- 是否采用严格模式
- import/export 导出的模块默认调用严格模式。
- require/exports 默认不使用严格模式,可以自定义是否使用严格模式
13.箭头函数的实现
14.vue的双向绑定
-
- Data通过observer转换成了getter/setter的形式来追踪变化。
-
- 当外界通过Watcher读取数据时,会触发getter从而将Watch添加到依赖中。
-
- 当数据发生了变化时,会触发setter,从而向Dep中的依赖(即Watcher)发送通知
-
- Watcher接收到通知后,会向外界发送通知,变化通知到外界后可能会触发视图更新, 也有可能触发用户的某个回调函数等。
二面
1.离职原因
2.对 ts 的使用情况
3.观察者模式
4.单例模式
5.归并排序
function mergeSort(arr) {
const len = arr.length;
if (len <= 1 ) {
return arr;
}
let mid = Math.floor(len / 2);
let leftArr = mergeSort(arr.slice(0,mid));
let rightArr = mergeSort(arr.slice(mid, len));
arr = mergeArr(leftArr, rightArr);
return arr;
}
function mergeArr(arr1, arr2){
let i = 0;
let j = 0;
let len1 = arr1.length;
let len2 = arr2.length;
let res = [];
while(i<len1 && j<len2) {
if (arr1[i] < arr2[j]) {
res.push(arr1[i])
i++;
} else {
res.push(arr2[j])
j++;
}
}
if (i<len1) {
return res.concat(arr1.slice(i));
} else {
return res.concat(arr2.slice(j));
}
}
6.快速排序
function quickSort(arr, left=0; right=arr.length - 1) {
if (arr.lenth > 1) {
const lineIndex = partition(arr,left, right);
if (left < lineIndex -1) {
quickSort(arr,left,lineIndex -1);
}
if (right > lineIndex) {
quickSort(arr,lineIndex,right);
}
}
return arr;
}
function partition(arr, left, right) {
let i = left;
let j = right;
let pivotValue = arr[Math.floor(left + (right-left)/2)];
if (i<=j) {
while(arr[i] < pivotValue) {
i++
}
while(arr[j] > pivotValue) {
j++
}
if (i<=j) {
swap(arr,i,j);
i++;
j--;
}
}
return i;
}
function swap(arr,i,j){
[arr[i],arr[j]] = [arr[j],arr[i]];
}
7.this 的使用
- 1.在普通函数中使用 this, this代表全局对象window。
- 2.作为一个对象的方法调用,此时this指的是调用它的那个对象。
- 3.作为一个构造函数被调用,此时this指代new出来的那个对象。
- 4.call调用 ,call方法的作用是改变函数的调用对象,此方法的第一个参数为改变后调用这个函数的对象,this指的是第一个参数,如果不传参数,默认指的是全局对象window。
8.对 Http3 的了解
采用 QUIC 协议: HTTP/3 选择了一个折衷的方法——UDP 协议, 基于 UDP 实现了类似于 TCP 的多路数据流、传输可靠性等功能,我们把这套功能称为 QUIC 协议
HTTP/3 中的 QUIC 协议集合了以下几点功能:
- 1.实现了类似 TCP 的流量控制、传输可靠性的功能
- 2.集成了 TLS 加密功能
-
- 实现了 HTTP/2 中的多路复用功能。 和 TCP 不同,QUIC 实现了在同一物理连接上可以有多个独立的逻辑数据流。 实现了数据流的单独传输,就解决了 TCP 中队头阻塞的问题。
9.http2的优化点
(参考上面的)
10. 网络攻防 1. 主要有哪些问题 2. Xss 主要针对哪些字符进行转化
1.Xss: XSS 攻击就是黑客往页面中注入恶意脚本,然后将页面的一些重要数据上传到恶意服务器。 常见的三种攻击模式:1.存储型XSS攻击 2.反射性XSS攻击 3.基于DOM的XSS攻击
主要有三种防范策略: 第一种是通过服务器对输入的内容进行过滤或者转码, 第二种是充分利用好 CSP, 第三种是使用 HttpOnly 来保护重要的 Cookie 信息
2.Csrf(参看上面)