Vue相关
1. Vue相应式原理[9]
vue渲染过程: new Vue -> init -> mount -> compile -> render -> vdom -> DOM
-
- init: 对所有属性做reactive化,为一个属性绑定getter函数,setter函数和Dep对象(防止无限递归)
const dep = new Dep();
Object.defineProperty(obj, key) {
get() {
...
dep.depend();
return value;
}
set(newVal) {
...
val = newVal;
dep.notify;
}
}
-
- Mount: 对每一个component新建一个watcher对象
-
- 依赖收集: watcher的constructor会在创建的同时调用updateComponent -> updateComponent里面会调用render(渲染虚拟DOM)和update(更新真实DOM)函数 -> 触发组件内所有属性的getter —> dep.deppend/watcher.addDep中会把彼此加入自己的list里面
-
- 派发更新: reactive化属性变更后,dep.notify会循环通知list里所有绑定的watcher,由watcher去重新渲染更新页面
-
特殊情况: 由于绑定发生在页面渲染的最开始,后续加入的元素无法监听。数组的索引不是属性,难以绑定。可以用Vue.set来解决。
2. 手写数据劫持/Proxy[9]
- Vue 2.0 Object.property:
<span id = "spanName"></span>
let obj = {
name: '';
}
let newObj = JSON.parse(JSON.stringify(obj));//模拟新建一个Dep()
Object.defineProperty(obj, 'name', {
getter() {
//dep.depend();
return newObj.name;
},
setter(val) {
if (val == newObj.name) return;
newObj.val = val;
notify();
}
})
function notify() {//模拟Dep.notify()
spanName.innerHTML = obj.name;
}
- Vue 3.0 proxy: 优势:
- 直接监听对象而非属性
- 可以监听数组变化
- 有13种拦截方法,适用范围更广 劣势: 兼容性差,IE9之前的浏览器无法支持
3. 对比MVVM/MVC/MVP[9]
- MVC:Model/View/Controller 数据更新->视图更新->业务逻辑更新,单向数据绑定,需要对视图层变化进行额外操作
- MVP:Model/View/Presenter 增加Presenter当做视图层和数据层的中介,但是p层比较臃肿
- MVVM: 通过数据劫持和观察者模式监听视图层变化并用setter数据,并且在数据更改的时候用getter来获取数据从而实现双向绑定,在MVC的基础上增加了v-model/v-bind来监听数据更新
4. Vuex[4]
5. Diff算法,虚拟dom[4]
页面由DOM树构成,当某个部分被更改时对应的DOM节点也会发生更改,我们需要找到两个树之间最小修改值来其高效率
- 传统:通过循环递归对每个节点一次对比,N个树节点的复杂度O(N^3)
- diff算法:Facebook在React中提出,复杂度O(N),大致有三个策略
- tree diff:因为DOM节点跨层移动特别少,只对前后树进行分层对比,只需要O(N)的时间,如果真的跨层就删除旧的,生成新的
- Component diff:由于不同类的组件生成的树形状不同,当发现类型不同的时候直接替换整个组件节省效率
- element diff:同一层级下用唯一id来区分,相当于hashmap,查找效率非常高 总的来说是用低复杂度来处理高概率发生的事件,对于低概率事件直接add/remove
6. vue-router原理/分类/刷新[2]
-
1.hash: SPA单页面应用为了提高用户体验,在页面交互的时候不会刷新页面,而是直接在页面内进行更新。14 年以前url路由是添加在#后面,hash值变化的时候不会向浏览器发送请求,但是会触发hashchange事件,从而触发页面更新组件。
-
2.history模式: 2014年,HTML5/history API标准发布,新增了pushState/replaceState/popState,和hash原理相同,没有#更加美观,但是会发送请求给服务器,需要额外的处理。
7. Vue通信方式:父子/非父子[3]
props/vue自定义事件/消息订阅与发布/vuex/slot/eventBus/ref
- props:一般属性子向父,函数属性是父向子
- 自定义事件:事件绑定+$emit回调,只能子向父
- 订阅发布: 比如PubSub可以适用于任何场景
- vuex: 适用于所有场景,管理更方便
- slot: 实现父向子传递带数据的标签
CSS相关
1.移动端适配方案 [2]
- media媒体查询针对不同媒体定义不同样式
- rem/em根据字体大小改变
- vw/vh根据视窗大小自适应
- flex盒模型也可以实现一些具体操作
2.自适应布局/左边固定右边自适应 [2]
- flex布局:左边设为 0 0 20, (order: -1) 右边 flex:1自适应
- 左:float,width:100%,padding-left:200px;右:float,margin:-100%
- calc自动计算宽度
- table
- grid
3.选择器种类及优先级/解析方式[3]
- !important;
- 行内样式 1000
- ID选择器 100
- 类/伪类 10
- 元素/伪元素 1
- 通配符选择器/父子/后代 0
4.盒模型/基于哪个点[2]
主要分为标准盒模型,怪异盒模型,弹性盒子,标准盒模型以content宽高为基准,在真实开发中容易造成bug,可以用boxing-size:border-box改为怪异盒模型。
5.水平居中/水平垂直居中[2]
水平:
- text-alian: center
- margin: 0 auto
- left: 50%, absolute, translateX(-%50)
- left: 50%, absolute, margin-left:-(宽度/2)
- flex,justify-content:center 水平垂直居中:
- flex:justify-content, align-item
- top:50%, left:50%, transform
- top:0;left:0;right:0;bottom:0;margin:auto
- display:table-cell;vertival-align:middle; text-align:center
网络相关
1. http缓存/离线缓存/协商缓存/强缓存/304[9]
缓存: 浏览器对之前请求过的文件进行缓存,以便下一次访问可以重复使用,节省带宽,提升访问速度,减缓服务器压力。
- 强缓存:浏览器根据请求头里expires/cache-control判断缓存是否过期,如果没有过期直接使用强缓存不发送请求。
- 协商缓存:如果强缓存失效会向服务器发送请求,并携带ETag(分布式系统ETag不同且last-modified需要保持一致)和Last-Modified/If-Modified-Since询问是否更改,如果服务器返回304(Not Modified),则直接读取缓存
- 如果缓存全部失效则向服务器发起请求
2. HTTP状态码[3]
- 200 请求成功
- 301 永久重定向
- 302 临时重定向
- 304 未修改,可以从浏览器缓存读取
- 400 Request语法错误
- 401 未授权
- 403 拒绝提供服务
- 404 无法找到请求资源
- 500 服务器内部错误
- 503 服务器宕机
3. 输入域名到页面展现过程[3]
-> 解析URL,生成HTTP报文 -> 递归逐层读取DNS缓存,解析成IP地址,并动态寻找最快路由路径 -> 进行ARP解析,通过IP地址和子网掩码解析出ARP -> 进行三次握手 -> Nginx反向代理接受到请求 -> 向CDN请求静态资源 -> 将动态资源请求分发到Tomcat/Apache -> 去redis/Mysql中请求资源并逐层返回 -> 浏览器接收到静态文件以后进行渲染
4. TCP如何保证链接安全[3]
- 效验和,通过Hash值来确定字段正确
- 序列号,保证传输顺序和去重
- 应答机制,三次握手确认连接成功
- 超时重传
- 滑动窗口/慢启动,防止拥堵丢包
- 四次挥手,确定传输完成
5. DNS查询过程[2]
查看浏览器缓存->查看本机缓存->查看本地DNS服务器->查看根域名服务器... 依次向上逐层寻找
6. 浏览器加载页面过程[2]
浏览器是多进程的:主进程/第三方插件进程/GPU进程/渲染进程... 渲染进程是多线程的:
- GUI渲染线程:解析HTML/CSS构建DOM树/CSS树,进行计算和绘制
- JS引擎线程:单线程,解析JS脚本,运行代码,进行回流重绘,把异步操作放入事件队列
- 消息队列线程:根据微任务/宏任务依次解析和运行
7. HTTP2/HTTP1区别[4]
- 1.二进制:原来是文本格式,二进制更高效,更准确
- 2.多路传输:传输更高效
- 3.报头压缩:由于TCP的三次握手,和数据分装报头开销很大
- 4.服务器推送:服务器可以分析浏览器的需求直接推送资源,减少延迟
8.跨域的几种方法/jsonp的实现[5]
跨域主要是由于前后端分离和同源策略,同源策略是指必须在同IP,同协议,同端口才能够顺利获取资源
第一阶段: jsonp跨域,由于scirpt,link,img等标签请求可以忽略跨域协议,可以在发送请求的时候动态生成script标签,只能用于get请求,大小有限制。
第二阶段: iframe跨域
第三阶段: CROS, 服务器端可以通过配置Access-Control-Allow来允许跨域访问,然后在第一次访问后返回token,之后每次访问携带token来确定身份。
-
开发:可以在package.json中,利用webapck的devServer用proxy代理转发,由于proxy和我们是同源的,所以请求可以成功
-
上线:可以由后端进行nginx反向代理
function jsonp (url, data={}, callback='callback') {
data.callback = callback
let params = []
for (let key in data) {
params.push(key + '=' + data[key])
}
let script = document.creatElement('script')
script.src = url + '?'+ params.join('&')
documnet.body.appendChild(script)
return new Promise ((resole, reject) => {
window[callback] = (data) => {
try {
resolve(data)
} catch {
reject(data)
} finally {
console.log(script)
script.parentNode.removeChild(script)
}
}
})
}
jsonp('www.google.com', {
page: 1,
cate: 'recommand'
}, jsoncallback).then(data => {
console.log(data)
})
9. HTTPS理解/为什么慢?[4]🆕
10. ISO模型[3]🆕
11. get/post请求区别[3]🆕
JS相关/编程
1. eventLoop/异步编程原理[7]
JS是单线程的,会一行一行运行js代码,当我们需要进行ajax请求或者其他耗时的请求时会阻塞后面代码执行。由于浏览器的渲染进程是多线程的,我们可以把这些请求放入任务队列里异步处理,等主线任务全都运行完毕之后再把事件队列处理好的数据进行处理。
任务队列:先微任务(promise/async)/后宏任务
2. 手写函数节流/防抖[5]
节流: 在一段时间内只运行一次函数
function throttle(fn, delay) {
var lastTime = 0;
return function() {
var nowTime = Date.time();
if (nowTime > lastTime + delay) {
fn();
lastTime = nowTime;
}
}
}
document.onscroll = throttle(function(){console.log(1)}, 200)
//相当于把document.onscroll的this指向改为throttle,之后每次获取之前的lastTime
防抖: 在一段时间内频繁触发只按照最后一次执行
function debounce(fn, delay) {
var timer = null;
return function() {
clearTimeout(timer);
timer = setTimeOut(function() {
fn.apply(this)
}, delay)
}
}
3. 实现带并发限制的scheduler[5]
class Scheduler{
constructor() {
this.tasks = []
this.running = 0
}
add(promiseCreator) {
retrun new Promise(resolve => {
this.tasks.push(() => promiseCreator().then(resolve));
runTask();
})
}
runTask() {
if (running >= 2) return
let task = tasks.shift()
if (task) {
this.running++;
task.then(() => {
this.concurrent -= 1
this.runTask()
})
}
}
}
4. 对闭包的理解/闭包的用处[4]
Js分为全局作用域,函数作用域,eval作用域(可忽略)。我们在函数作用域可以调用全局作用域的属性,但是在全局作用域无法调用函数作用域属性。这时我们可以通过返回回调函数来保证函数在执行结束以后不被GC销毁,相当于一个接口或者说连通器。
- 安全访问函数内部属性
- 属性私有化/不污染全局变量
- 函数内部变量长期存在,但是需要手动释放内存
5. this指向/call/apply/bind/手写bind[3]
- 默认绑定:全局调用/没有指定调用者则默认为window
- 隐式绑定:自动绑定调用自己的Object
- 硬绑定:call/apply,指定this对象
- 构造函数绑定:创造出的实例化对象指向构造函数对象
bind/apply实现
6. 匹配URL正则/匹配后缀的正则[3]
7. 实现异步sleep函数[2]
async function test() {
console.log('Hello')
await sleep(1000)
console.log('world!')
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
8. 原型链[4]
const person = new Person();
person.proto == Person.prototype Person.prototype.proto == Object.prototype 当我们访问对象实例的属性时,如果找不到就通过_proto_去原型对象里面逐层查找
9. 数据类型检测方式/隐式类型转化/手写函数[4]🆕
10. Js继承方式/应用场景[3]🆕
1.原型链继承 // Child.prototype = new Parent(); 2.call继承 // 在Child方法Parent.call(this) 3.实例继承 // var p = new Parent() 4.拷贝继承 5.组合继承 6.类继承
ES6
1. Promise理解 [5]
2. let/var/const区别[4]
- var: 可以重新声明,重新赋值,会变量提升,作用域范围不可控
- let: 不能重新声明,可以重新赋值,不会变量提升,会形成块级作用域
- const: 不能重新声明,不能重新复制,不会变量提升,会形成块级作用域
3. ES6新属性/结构赋值[4]
let/const/promise/解构赋值/箭头函数
4. 实现promise.all[2]🆕
1、接收一个 Promise 实例的数组或具有 Iterator 接口的对象, 2、如果元素不是 Promise 对象,则使用 Promise.resolve 转成 Promise 对象 3、如果全部成功,状态变为 resolved,返回值将组成一个数组传给回调 4、只要有一个失败,状态就变为 rejected,返回值将直接传递给回调all() 的返回值也是新的 Promise 对象
function promiseAll(promises) {
return new Promise(function(resolve, reject) {
if (!isArray(promises)) {
return reject(new TypeError('arguments must be an array'));
}
var resolvedCounter = 0;
var promiseNum = promises.length;
var resolvedValues = new Array(promiseNum);
for (var i = 0; i < promiseNum; i++) {
(function(i) {
Promise.resolve(promises[i]).then(function(value) {
resolvedCounter++
resolvedValues[i] = value
if (resolvedCounter == promiseNum) {
return resolve(resolvedValues)
}
}, function(reason) {
return reject(reason)
})
})(i)
}
})
}
5. 箭头函数和普通函数区别[2]🆕
箭头函数也可以看作是简洁版的匿名函数。不过箭头函数最大的优点在于,普通函数的回调函数的this默认指向window。箭头函数的this默认指向调用自己的函数的this。
杂项
1. Websocket原理[7]
2. webpack原理/loader[8]
3. 前端性能优化/渲染优化/资源优化[4]
资源优化:
- CDN
- 资源压缩,nginx会自动开启
- 浏览器缓存机制
渲染优化:
- 雪碧图(基本不用了)
- CSS放头,js防尾(现在自动打包基本不用了)
- 懒加载
- keep-alive在页面跳转以后不立马销毁组件,相当于缓存
- 懒加载/预加载HTTP2.0
- 首屏加载
4. hooks原理/缺点 [4]
5. 快排[3]
随机找基准点,比我大的放左边,比我小的放右边