@HTTP协议相关
URL回车后发生什么?
- URL解析: 协议段 + 域名/IP段 + 端口段(HTTP协议默认端口80/HTTPS协议默认端口443)+ 路径段 + 查询参数段 + 哈希段;浏览器执行URL解析;
- DNS查询:域名映射为IP+端口;IP=宇宙中的唯一主机(host);端口=该主机上的唯一进程(应用程序);
- TCP连接:宗旨稳定连接+可靠传输;三次握手实现稳定连接;四次挥手实现可靠传输;稳定连接=服客双方确保彼此能发能收;可靠传输=服客双方确保对方数据发送完毕才能断开连接;三次挥手图形=客户端出发的N字形;四次挥手=客户端出发的V字形+服务端出发的V字形;
- HTTP请求发送:请求报文的构成=请求行+请求头+空行+请求体;
- HTTP响应返回:响应报文的构成=状态行+响应头+响应体;
- TCP连接断开:要经历四次挥手;
- 浏览器渲染页面:要会画渲染示意图;
简述TCP原理
- 宗旨稳定连接+可靠传输;
- 三次握手实现稳定连接;
- 四次挥手实现可靠传输;
- 稳定连接=服客双方确保彼此能发能收;
- 可靠传输=服客双方确保对方数据发送完毕才能断开连接;
- 三次挥手图形=客户端出发的N字形;
- 四次挥手=客户端出发的V字形+服务端出发的V字形;
- PS:一蹴而就原则:三次握手和四次挥手都必须一次性完成,否则作废重来;
- PS:UDP=没有握手加挥手=连接+收发+断开=注重性能;
- PS:TCP/UDP工作在OSI七层网络模型的传输层;
- PS:OSI七层网络模型=物数网(IP)传(TCP/UDP)会表应(HTTP/FTP/SMTP)
GET请求与POST请求异同
- 数据携带方式:GET只能是查询参数;POST/PUT/PATCH还可以请求体携带数据;
- 数据量:查询参数K级别;请求体携带数据量理论上无限;
- 安全性:查询参数(完全暴露)不能携带敏感数据;请求体中的数据相对安全;
- 安全性:HTTPS协议接近绝对安全;HTTPS协议的通信数据全部使用加密;
- PS: HTTPS协议使用非对称加密; 服务器持有公钥(网站证书),客户端给服务器发送的数据使用该公钥加密;服务端用自己配对的私钥解密;
HTTP常见的状态码有哪些?
- 100+=请求继续;
- 200+=请求成功;200=请求成功
- 300+=重定向;301=永久重定向;302=临时重定向;304=资源未更改(滚回去用缓存);
- 400=客户端错误;401=未授权;403=禁止访问;404=路径未找到(域名存在但路径不存在);
- 500=服务端错误;500=服务端错误;
- 追问1:具体解释一下304的含义;
- 追问2:具体解释一下404;
- 追问3: 301与302具体有何区别;
- 追问4:你平时是如何调试网络通信错误的;
JWT(JsonWebToken)鉴权原理
- 单点登录:单点登录,多点开花;A服务器上登录并发放token + B服务器上可以效验 + AB服务器必须持有相同的秘钥
- 荷载加密:token构成 = 头 + 荷载 + 签名;签名由【头 + 荷载 + 秘钥】三合一计算而来;截获并篡改token中的任意片段都会导致token效验失败
- VS cookie:cookie无法实现单点登录;cookie需要自行加密
Ajax如何实现跨域
- 服务端支持跨域:配置响应头
Access-Control-Allow-Origin = 允许跨域访问的前端 - JSONP:用script/src得到服务端响应的
callback(jsonData)在前端执行 - 使用代理:在具有代理功能的服务器上(Nginx)配置代理,访问代理地址 = 访问目标地址
location /a {
proxy_pass 需要跨域访问的b地址
}
@JS基础
什么是事件委托
- 概念:子元素委托事件给父元素去处理;
- 好处:节约内存+方便管理+防内存泄漏;
- 节约内存:事件监听器的数量少;
- 方便管理:无需考虑子元素动态增减时事件监听器的动态增减问题;
- 防内存泄露:子元素被删除时无需删除其对应的事件监听器;
- PS:追问=哪些情形会造成内存泄露?
ES6有哪些新特性?
变量层面:
- let:var弊病=变量提升+重复声明+作用域穿透;
- const:通常将不希望修改地址的对象声明为常量;
数据结构层面
- 数组:解构+展开;
- 对象:解构+展开+简写;
- 字符串:模板字符串;
- Map:方便增删改产的键值对存储器;
- Set: 有序且不重复的元素集;
函数层面
- 箭头函数:this从父级作用域继承;
- PS:this的可能情形;
类层面
- class系列语法:class(构造函数+原型属性) + constructor(构造函数) + static静态成员 + super调用父类方法;super(name)调用父类构造器; super.xxx()调用父类实例方法;
请说出10个请求头
- Accept:客户端想要的数据类型
- Accept-Encoding:客户端想要的压缩编码
- Cookie:客户端携带的用户信息
- If-None-Match:客户端携带上次的数据指纹
- If-Modified-Since:携带上次数据的最后的更新时间
- User-Agent:客户端浏览器信息
- Origin:客户端地址
- Content-Type:请求体的数据类型
- Content-Length:请求体的数据字节长度
- Accept-Language:客户端想要的语言
- Host:服务器地址
请说出10个响应头
- Content-Type:服务端返回的数据类型
- Content-Encoding:服务端响应的压缩编码
- Set-Cookie:服务端给客户端写的Cookie
- Last-Modified:数据的最后更新时间
- E-tag:数据指纹
- Server:服务器的信息
- Access-Control-Allow-Origin:服务端允许谁跨域访问它
- Content-Type:响应体的数据类型
- Content-Length:响应体的数据字节长度
- Content-Language:响应体的语言
- Data:服务器响应时间
什么是深拷贝/浅拷贝
- 浅拷贝:引用数据类型赋值给别人(包括调用函数时实参给形参赋值)= 地址被拷贝 = 修改任何副本都会影响其他副本
- 浅拷贝示例
const obj2 = obj或fn(obj) - 深拷贝:将对象中的所有key-value递归拷贝给另外一个对象,递归到每一个叶子结点(即value是基本数据类型或函数),深拷贝的副本修改互相不影响
什么是值传递/引用传递
- 值传递:基本数据类型赋值给比人,包括调用函数时作为入参传递
- 应用传递:引用数据类型赋值给别人,包括调用函数时作为入参传递
- 值传递示例
let num2 = num或fn(num) - 引用传递示例
let obj2 = obj或fn(obj)
this的所有可能情形
- 普通函数的this就是调用者;(显式主语+无主语时为window+DOM事件监听器的主语恒为事件源e.currentTarget)
- 箭头函数的this从父级作用域继承;
- 普通函数可以通过 fn.call/apply/bind 绑定this
- 构造器里的this为正在构建的实例
- 实例方法中的this为当前实例
- 静态方法中的this为当前类
谈谈对事件传播/派发机制的理解
- 解决事件发生时具体由谁处理的问题
- 具体解决方案可从三方面入手,即:指定传播方向 + 按需设置一级到多级监听器 + 设置传播断点
- 指定传播方向:dom.addEventListener(type, handler, useCapture)最后一个如蝉true即使用捕获,否则使用冒泡,默认冒泡
- 设置断点:e.stopPropagation()
内存泄露的可能情形有哪些?
- 用完的事件监听器:DOM元素删除时忘记删除其事件监听器;
- 用完的事件监听器:离开页面时没有释放各种事件监听器;(div.onclick=null,div.removeEventListener...)
- 用完的定时器:定时器用完没有clear;
- 用完的全局变量:用完没释放的全局变量(obj=null)
- 用完的闭包:用完未释放的闭包(innerFn = null)
- 总结:【用毕未释放】的【事件监听器】+【定时器】+【全局变量】+【闭包】;
谈谈对闭包的理解
- 广义闭包:凡返回引用数据的函数,在其返回值被引用期间,期执行空间无法被释放,客观上形成一个零食在封闭作用域,即函数闭包
- 狭义闭包:即返回函数的函数,外层函数通常作为内层函数的状态缓存区
- 函数式编程:闭包是函数式编程的基础,可以派生出诸多玩法
- 释放闭包:闭包会导致算法的时间和空间开销增大,用完后一定要释放,否则会形成内存泄漏
- 释放方式:
let ret = enclosure()用完后ret = null,无人引用闭包的返回值闭包就能释放了
深拷贝 VS 浅拷贝
- 浅拷贝:复制地址 + 相互影响
const bojCopy = obj - 摄拷贝:递归拷贝对象的所有key-value + 直到叶子节点 + 互不影响
const objCopy = deepCopy(obj)
值传递 VS 引用传递
- 值传递:基本数据类型(number, string, boolean, null, undefined)+ 赋值给别人 + 值拷贝 + 互不影响
const numCopy = num;fn(num)基本数据类型的实参传递给形参走的是值传递/值拷贝 - 引用传递:引用数据类型 + 赋值给别人(包括实参给形参赋值) + 地址的浅拷贝 + 相互影响
const objCopy = obj/fn(obj)
前端有哪些数据存储方式
- cookie:4K级别 + 键值存储 + 主要用于前后端共享用户信息
- localStorage/sessionStorage:50M级别 + 键值存储 + 前端独享 + 缓存业务数据(以减少网络请求次数)
@面向对象
typeof 与 instanceof 区别
- typeof主要用于判断基本数据类型,对于引用数据类型只能识别为function或object
- instanceof判断某个对象是否是某类的实例或后代实例
- 张三 instanceof Person或(Animal,Object)结果都是true
JS如何实现继承
- 以父类的实例挂载到子类的原型身上
字符串有哪些常用API?
- slice:截取字符串(含头不含尾)
- split:根据传入的切割符切割字符串,返回数组
- indexOf:指定字符串中寻找字符串所在位置的下标
- concat:拼接字符串
- charAt:根据下标获取字符的位置
- trim:去掉字符串头尾的空格
- toUpperCase:将字符串转成大写
- toLowerCase:将字符串转成小写
- replace:替换字符串
obj.replace('AAA','***') - search:查找第一个匹配的字符串下标
- substring:截取字符串(含头含尾)
obj.substring(0,3) - endsWith:字符串必须以特定的值结尾(返回boolean值)
obj.endsWith('taobao.com')
数组常用API
- push:数组末尾追加一个元素
- pop:删除数组末尾的一个元素
- unshift:在数组前面追加一个元素
- shift:删除数组最前面的一个元素
- splice:根据下标删除特定下标位置的内容(可删除,可追加)
arr.splice(0, 1, 90) - reverse:反转数组
- sort:数组排序
降序:arr.sort((a, b) => b - a)``升序:arr.sort((a, b) => a - b) - concat:拼接数组
- join:将数组每一项转换成字符串
- indexOf:根据下标查找数组中对应的元素
- forEach:遍历数组
arr.forEach(item => console.log(item)) - map:映射数组,对数组中的每一项进行操作,返回新数组`arr.map(item => Math.pow(item, 2))
- filter:过滤数组`arr.filter(item => item % 3 == 0)
- slice:截取数组(含头不含尾)
- every:判断数组中所有元素是否都符合条件
arr.every(item => item % 3 == 0) - some:判断是否有一项或者多项都满足条件
arr.some(item => item % 3 == 0) - rednce:累加数组中的数据
arr.rednce((pv,cv) => pv + cv) - includes:判断数组中是否有某个值
正则API
- 普通创建正则(常用)
const reg = /hello/ig - new 创建正则
const reg = new RegExp('hello', 'ig') - exec() 每次捕获一次,加g的时候是捕获全部的内容,不加g的时候只捕获第一个
let str = 'abc';
const reg = /(a)(b)(c)/;
console.log( reg.exec(str));
// ["abc", "a", "b", "c", index: 0, input: "abc"]
// 其中 "a" "b" "c" 都是第一次匹配到的"abc" 拆分的小分组
- test() 判断正则是否成立,返回值为true或者false
let str="aass1d"
const reg=/\d/g
const r=reg.test(str)
console.log(r) //true
//返回值为true或者false
- match()
const reg = /\d+/g;
let str = 'abc123de45fgh6789qqq111';
str.match(reg)
// ["123", "45", "6789", "111"]
//受小分组的影响 且也受g的影响
- search() 返回第一条自己的索引位置
let str="aass1zd"
const reg=/\d/g
const r= str.search(reg);
console.log(r) // 4
- replace() 替换方法,一代新词换旧词
let str3="a1ass11zd"
const reg=/\d+/g
const r3= str3.replace(reg,"1111")
console.log(r3,"replace") //a1111ass1111zd
@Git
Git常用命令
- 日常三件套:添加受控、提交、推远程
git add .git commit -m "日志"git push -u origin master - stash 暂存(不能达到提交要求的)
- resset / resvert 版本回退
- mege / rebase 合并其他分支
- fetch / pull 拉去远程仓库内容
Git怎么回退版本
- git reset --hard 版本ID = 暴力回退到指定版本,其后的历史记录被销毁
- git revert 版本ID = 否定特定版本的空闲 = 将这个版本以前的版本合并到HEAD中来,形成一个最新的快照
- 暴力回退在有充分把握的情况下简单粗暴高效
- revert不销毁任何一次提交的历史记录,更加稳妥
pull与fetch的区别
- pull将远程仓库的所有更新(分支 + 快照)同步到笨地仓库,并直接将origin / xxx合并到工作区里面的xxx分支,有覆盖未提交的风险
- fetch仅同步远程仓库的所有更新(分支 + 快照)同步到本地仓库,而不更新工作区内容
- git pull = git fetch + git merge origin / xxx
merge与rebase的区别
- merge xxx 立足当前,将目标分支xxx的代码兼容并合并进来
- rebase xxx 以xxx的最新提交为底,与当前分支的每次提交一一形成合并版本
- merge 是一步到位的暴力合并,没有过程信息
- rebase 是逐快的慢慢合并,过程记录完整
- merg 简单厨宝,rebase精细一些
那些命令可能形成冲突
- git merge xxx 当前分支兼容并合并其他分支
- git stash pop 暂存区顶部代码与工作区分支合并
- git revert xxx 目标快照的上一快照与HEAD节点合并
- git rebase xx 道理和merge
- git pull 远程分支origin / xxx与工作区中的xxx合并
@Vue八股文
说说对Vue的理解
- MVVM:VM层相当于MVC中的C层中的一部分特定职能,实时监控和读取数据层的修改并将其映射到视图层,所以VM层专干数据驱动视图的活
- 响应式:与VM本质相同提法有区别,还是数据驱动视图,声明响应式的数据,当数据变化时自动驱动视图更新
- 组件化开发
- 虚拟DOM与diff算法
Vue3的响应式与Vue2有什么区别
- Vue2监听数据变化使用数据劫持