Skip to content

Latest commit

 

History

History
517 lines (284 loc) · 21.6 KB

二轮答辩.md

File metadata and controls

517 lines (284 loc) · 21.6 KB

小A二轮答辩

在项目过程中可能会使用到的一些知识点汇总

Vue

MVVM

MVVM分为Model、View、ViewModel三者。 Model 代表数据模型,数据和业务逻辑都在Model层中定义; View 代表UI视图,负责数据的展示; ViewModel 负责监听 Model 中数据的改变并且控制视图的更新,处理用户交互操作; ModelView 并无直接关联,而是通过 ViewModel 来进行联系的,ModelViewModel 之间有着双向数据绑定的联系。因此当 Model 中的数据改变时会触发 View 层的刷新,View 中由于用户交互操作而改变的数据也会在 Model 中同步。 这种模式实现了 ModelView 的数据自动同步,因此开发者只需要专注对数据的维护操作即可,而不需要自己操作 dom

img

vue 虚拟 DOM

浏览器在更新DOM节点过程中,操作DOM的代价仍旧是昂贵的,频繁操作还是会出现页面卡顿,影响用户体验。

用 JS 对象模拟DOM节点的好处是,页面的更新可以先全部反映在 JS 对象(虚拟DOM)上,操作内存中的 JS 对象的速度显然要更快,等更新完成后,再直接替换真实 DOM 。

vue双向绑定

基于 mvvm 模型

view 更新 data 很容易,例如input标签的监听事件

主要是 data 更新 view

数据监听器 Observer

Object.defineProperty( ) 对属性设置一个set函数,当数据改变了就会来触发这个函数,所以我们只要将一些需要更新的方法放在这里面就可以实现 data 更新 view 了

解析器 Compile 解析 dom 节点和绑定

订阅者 Watcher 初始化时被添加到订阅器中,在Observer 执行get时添加

订阅器 Dep 负责收集订阅者,然后再属性变化的时候执行对应订阅者的更新函数

img

diff 算法

渲染真实DOM的开销是很大的,比如有时候我们修改了某个数据,如果直接渲染到真实dom上会引起整个dom树的重绘和重排。

根据真实DOM生成一颗virtual DOM,当virtual DOM某个节点的数据改变后会生成一个新的Vnode,然后VnodeoldVnode作对比,发现有不一样的地方就直接修改在真实的DOM上,然后使oldVnode的值为Vnode

diff 的过程就是调用名为patch的函数,比较新旧节点,一边比较一边给真实的DOM打补丁。

Vue-router

路由跳转传递参数的方式

使用 paramsquery

params
this.$router.push({ name: 'news', params: { userId: 123 }});

​ 接收时(在新页面)

this.$route.params.userId

​ 使用 params 时路由跳转必须依据路由名 name 而不能是 路由路径 path ,否则可能导致传递参数失败,拿不到参数。

query
this.$router.push({ path: '/news', query: { userId: 123 }});

​ 接收时(在新页面)

this.$route.params.userId

​ 使用 query 时路由跳转必须依据 路由路径 path 而不能是路由名 name ,否则可能导致传递参数失败,拿不到参数。

注意:和 name 配对的是 params,和 path 配对的是 query

1.命名路由搭配 params,刷新页面参数会丢失2.查询参数搭配 query,刷新页面数据不会丢失

嵌套路由

应用场景:网页在登录过程中,在一个登录页面和注册界面可以使用一个路由,然后在进入界面时使用另一个路由,进入界面后有导航栏,此导航栏路由其他不同的页面,在导航的过程中,导航栏始终保持为同一个组件不变。

介绍方法:

在 router.js 当中

        const routes = [
             { path: '/', redirect: '/home' },
            { 
                path: '/home', 
                component: Home, 
                children:[
                    { path: '/home/login', component: Login},
                    { path: '/home/reg', component: Reg}
                ]
            },
            { path: '/news', component: News}
        ]

Axios

原理

Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。

  1. 请求拦截器 请求拦截器的作用是在请求发送前进行一些操作,例如在每个请求体里加上token,统一做了处理如果以后要改也非常容易。
axios.interceptors.request.use(function (config) {
    // 在发送请求之前做些什么,例如加入token
    .......
    return config;
  }, function (error) {
    // 对请求错误做些什么
    return Promise.reject(error);
  });
  1. 响应拦截器 响应拦截器的作用是在接收到响应后进行一些操作,例如在服务器返回登录状态失效,需要重新登录的时候,跳转到登录页。
axios.interceptors.response.use(function (response) {
    // 在接收响应做些什么,例如跳转到登录页
    ......
    return response;
  }, function (error) {
    // 对响应错误做点什么
    return Promise.reject(error);
  });

axios的特点有哪些?

一、Axios 是一个基于 promise 的 HTTP 库,支持promise所有的 API 二、它可以拦截请求和响应 三、它可以转换请求数据和响应数据,并对响应回来的内容自动转换成 JSON 类型的数据 四、安全性更高,客户端支持防御 XSRF

Webpack

一、webpack的打包原理 识别入口文件 通过逐层识别模块依赖(Commonjs、amd或者es6的import,webpack都会对其进行分析,来获取代码的依赖) webpack做的就是分析代码,转换代码,编译代码,输出代码 最终形成打包后的代码

二、什么是loader loader是文件加载器,能够加载资源文件,并对这些文件进行一些处理,诸如编译、压缩等,最终一起打包到指定的文件中

  1. 处理一个文件可以使用多个loader,loader的执行顺序和配置中的顺序是相反的,即最后一个loader最先执行,第一个loader最后执行
  2. 第一个执行的loader接收源文件内容作为参数,其它loader接收前一个执行的loader的返回值作为参数,最后执行的loader会返回此模块的JavaScript源码

三、什么是plugin 在webpack运行的生命周期中会广播出许多事件,plugin可以监听这些事件,在合适的时机通过webpack提供的API改变输出结果。

四、loader和plugin的区别 对于loader,它是一个转换器,将A文件进行编译形成B文件,这里操作的是文件,比如将A.scss转换为A.css,单纯的文件转换过程 plugin是一个扩展器,它丰富了webpack本身,针对是loader结束后,webpack打包的整个过程,它并不直接操作文件,而是基于事件机制工作,会监听webpack打包过程中的某些节点,执行广泛的任务

常考的面试问题

css 选择器权重

  1. 第一等:代表内联样式,如: style=””,权值为1000。
  2. 第二等:代表ID选择器,如:#content,权值为0100。
  3. 第三等:代表类,伪类和属性选择器,如.content,权值为0010。
  4. 第四等:代表元素选择器和伪元素选择器,如div p,权值为0001。
  5. 通配符、子选择器、相邻选择器等的。如*、>、+,权值为0000。
  6. 继承的样式没有权值。

!important 的作用是提升优先级,加了这句的样式的优先级是最高的

箭头函数和普通函数

  1. 箭头函数是匿名函数,不能作为构造函数,不能使用new。
  2. 箭头函数不绑定arguments,取而代之用rest参数...解决
  3. this的作用域不同,箭头函数不绑定this,会捕获其所在的上下文的this值,作为自己的this值。
  4. 箭头函数没有原型属性

图片懒加载原理

图片懒加载的实现原理:将图片的地址放在 data-set 属性中,由于图片并没有在 src 中,并不会发送 http 请求。比较图片到整个页面距离(Y)和 页面滑动的距离 (X) + 浏览器可视区域的大小(Z) ,Y小于两者之和,则图片就显示出来,将图片的 data-set 属性换为 src 属性

eventloop 事件循环

JavaScript 是一门单线程语言,同步和异步任务分别进入不同的执行环境,同步的进入主线程,即主执行栈,异步的进入任务队列。主线程内的任务执行完毕为空,会去任务队列读取对应的任务,推入主线程执行。 上述过程的不断重复就是我们说的 Event Loop (事件循环)。

JavaScript 是一门单线程语言,异步操作都是放到事件循环队列里面,等待主执行栈来执行的,并没有专门的异步执行线程。

手写防抖节流

debounce
function debounce(fn, delay){
    var timeout = null;
    return function(){
        clearTimeout(timeout);
        timeout = setTimeout(()=>{
            fn.apply(this, arguments)
        }, delay)
    }
}
throttle
function throttle(fn, delay){
    let canRun = true;
    return function(){
        if(!canRun) return;
        canRun = false;
        setTimeout(()=>{
            fn.apply(this, arguments)
            canRun = true
        }, delay)
    }
}

Token

1、Token的引入:Token是在客户端频繁向服务端请求数据,服务端频繁的去数据库查询用户名和密码并进行对比,判断用户名和密码正确与否,并作出相应提示,在这样的背景下,Token便应运而生。

2、Token的定义:Token是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后,服务器生成一个Token便将此Token返回给客户端,以后客户端只需带上这个Token前来请求数据即可,无需再次带上用户名和密码。

3、使用Token的目的:Token的目的是为了减轻服务器的压力,减少频繁的查询数据库,使服务器更加健壮。

TCP 和 UDP

TCP

TCP 是面向连接的、可靠的流协议。

TCP 连接过程(三次握手)

  1. 客户端向服务端发送连接请求报文段。该报文段中包含自身的 数据通讯初始序号 。请求发送后,客户端便进入 SYN-SENT 状态。
  2. 服务端收到连接请求报文段后,如果同意连接,则会发送一个应答,该应答中也会包含自身的数据通讯初始序号,发送完成后便进入 SYN-RECEIVED 状态。
  3. 当客户端收到连接同意的应答后,还要向服务端发送一个确认报文。客户端发完这个报文段后便进入 ESTABLISHED 状态,服务端收到这个应答后也进入 ESTABLISHED 状态,此时连接建立成功。

TCP 断开过程 (四次握手)

  1. 若客户端 A 认为数据发送完成,则它需要向服务端 B 发送连接释放请求。
  2. B 收到连接释放请求后,会告诉应用层要释放 TCP 链接。然后会发送 ACK 包,并进入 CLOSE_WAIT 状态,此时表明 A 到 B 的连接已经释放,不再接收 A 发的数据了。但是因为 TCP 连接是双向的,所以 B 仍旧可以发送数据给 A。
  3. B 如果此时还有没发完的数据会继续发送,完毕后会向 A 发送连接释放请求,然后 B 便进入 LAST-ACK 状态。
  4. A 收到释放请求后,向 B 发送确认应答,此时 A 进入 TIME-WAIT 状态。该状态会持续 2MSL(最大段生存期,指报文段在网络中生存的时间,超时会被抛弃) 时间,若该时间段内没有 B 的重发请求的话,就进入 CLOSED 状态。当 B 收到确认应答后,也便进入 CLOSED 状态。

特点:

  1. 面向连接
  2. 仅支持单播传输
  3. 面向字节流
  4. 可靠传输
  5. TCP提供全双工通信
UDP

UDP 协议全称是用户数据报协议,在网络中它与TCP协议一样用于处理数据包,是一种无连接的协议。

特点

  1. 面向无连接
  2. 有单播,多播,广播的功能
  3. 不可靠性
  4. 头部开销小,传输数据报文时是很高效的。
  5. UDP 是面向报文的
对比
UDP TCP
是否连接 无连接 面向连接
是否可靠 不可靠传输,不使用流量控制和拥塞控制 可靠传输,使用流量控制和拥塞控制
连接对象个数 支持一对一,一对多,多对一和多对多交互通信 只能是一对一通信
传输方式 面向报文 面向字节流
首部开销 首部开销小,仅8字节 首部最小20字节,最大60字节
适用场景 适用于实时应用(IP电话、视频会议、直播等) 适用于要求可靠传输的应用,例如文件传输
  • TCP向上层提供面向连接的可靠服务 ,UDP向上层提供无连接不可靠服务。
  • 虽然 UDP 并没有 TCP 传输来的准确,但是也能在很多实时性要求高的地方有所作为
  • 对数据准确性要求高,速度可以相对较慢的,可以选用TCP

深拷贝浅拷贝

深拷贝和浅拷贝最根本的区别在于是否真正获取一个对象的复制实体,而不是引用。

假设B复制了A,修改A的时候,看B是否发生变化:

如果B跟着也变了,说明是浅拷贝,拿人手短!(修改堆内存中的同一个值)

如果B没有改变,说明是深拷贝,自食其力!(修改堆内存中的不同的值)

迭代实现深拷贝

跨域和解决方案

跨域是浏览器的一个特性,就是浏览器从一个“域”向另一个“域”的服务器发出请求,来访问另一个“域”上的资源。但是,由于请求的文件可能会存在恶意攻击,浏览器并不允许直接访问另一个“域”上的资源,只能访问同一个“域”上的资源,这个就是“同源策略”。而所谓的“同源”,指的是“协议、域名、端口号”一致。

JSONP

ajax请求受同源策略影响,不允许进行跨域请求,而script标签src属性中的链接却可以访问跨域的js脚本,利用这个特性,服务端不再返回JSON格式的数据,而是返回一段调用某个函数的js代码,在src中进行了调用,这样实现了跨域。

只能处理GET请求

CORS

Cross-Origin Resource Sharing

CORS 新增了一组 HTTP 首部字段,允许服务器声明哪些源站通过浏览器有权限访问哪些资源

对于简单请求,浏览器向服务器发起的request header中,会有一个origin字段,表示当前的“源”,服务器返回的response header中,会有一个Access-Control-Allow-Origin字段,里面写明允许那些“源”,浏览器发现两者一致,或者服务器允许所有的“源”,那么跨域成功!

CORS方法在老式浏览器上不可行

反向代理

跨域只是浏览器向服务器发送请求的时候,浏览器的限制。而服务器和服务器之间是没有跨域的限制的。反向代理是利用代理服务器接收到请求之后,转发给真正的服务器,并把结果返回到浏览器上。

BFC

BFC 就是让元素成为一个个独立的块,他们之间互不影响,通俗一点来讲,可以把 BFC 理解为一个封闭的大箱子,箱子内部的元素无论如何翻江倒海,都不会影响到外部。

解决了一些 外边距重叠,包裹浮动元素,自适应布局等问题

HTTP 和 HTTPS

HTTPS 开发的主要目的,是提供对网站服务器的身份认证,保护交换数据的隐私与完整性。

  • HTTP 明文传输,数据都是未加密的,安全性较差,HTTPS(SSL+HTTP) 数据传输过程是加密的,安全性较好。
  • 使用 HTTPS 协议需要到 CA(Certificate Authority,数字证书认证机构) 申请证书,一般免费证书较少,因而需要一定费用。证书颁发机构如:Symantec、Comodo、GoDaddy 和 GlobalSign 等。
  • HTTP 页面响应速度比 HTTPS 快,主要是因为 HTTP 使用 TCP 三次握手建立连接,客户端和服务器需要交换 3 个包,而 HTTPS除了 TCP 的三个包,还要加上 ssl 握手需要的 9 个包,所以一共是 12 个包。
  • http 和 https 使用的是完全不同的连接方式,用的端口也不一样,前者是 80,后者是 443。
  • HTTPS 其实就是建构在 SSL/TLS 之上的 HTTP 协议,所以,要比较 HTTPS 比 HTTP 要更耗费服务器资源。

前端安全问题

  • XSS攻击

攻击者通过在目标网站上注入恶意脚本并运行,获取用户的敏感信息如 Cookie、SessionID等,影响网站与用户数据安全。(转义)

  • CSRF攻击

跨站请求伪造,攻击者盗用受害人身份,以受害人的名义发送恶意请求。(验证码)

  • SQL注入

通过Web应用接口注入SQL语法,破坏原有SQL结构,达到攻击行为。

前端如何优化网站性能

  1. 减少 HTTP 请求数量
  • CSS Sprites:国内俗称 CSS 精灵,这是将多张图片合并成一张图片达到减少 HTTP 请求的一种解决方案,可以通过 CSS background 属性来访问图片内容。这种方案同时还可以减少图片总字节数。

  • 合并 CSS 和 JS 文件:现在前端有很多工程化打包工具,如:grunt、gulp、webpack等。为了减少 HTTP 请求数量,可以通过这些工具再发布前将多个 CSS 或者 多个 JS 合并成一个文件。

  • 采用 lazyLoad:俗称懒加载,可以控制网页上的内容在一开始无需加载,不需要发请求,等到用户操作真正需要的时候立即加载出内容。这样就控制了网页资源一次性请求数量。

  1. 利用浏览器缓存 浏览器缓存是将网络资源存储在本地,等待下次请求该资源时,如果资源已经存在就不需要到服务器重新请求该资源,直接在本地读取该资源。

  2. 减少重排(Reflow) 基本原理:重排是 DOM 的变化影响到了元素的几何属性(宽和高),浏览器会重新计算元素的几何属性,会使渲染树中受到影响的部分失效,浏览器会验证 DOM 树上的所有其它结点的 visibility 属性,这也是 Reflow 低效的原因。如果 Reflow 的过于频繁,CPU 使用率就会急剧上升。

  3. 控制资源文件加载优先级

    浏览器在加载 HTML 内容时,是将 HTML 内容从上至下依次解析,解析到 link 或者 script 标签就会加载 href 或者 src 对应链接内容,为了第一时间展示页面给用户,就需要将 CSS 提前加载,不要受 JS 加载影响。 一般情况下都是 CSS 在头部,JS 在底部。

网页从输入网址到渲染完成经历了哪些过程

  1. 输入网址;
  2. 发送到DNS服务器,并获取域名对应的web服务器对应的ip地址;
  3. 与web服务器建立TCP连接;
  4. 浏览器向web服务器发送http请求;
  5. web服务器响应请求,并返回指定url的数据(或错误信息,或重定向的新的url地址);
  6. 浏览器下载web服务器返回的数据及解析html源文件;
  7. 生成DOM树,解析css和js,渲染页面,直至显示完成;

关于项目

说出你的项目亮点

  1. 追求复用
  2. 合理使用防抖节流
  3. 增强用户体验(加载,提示,弹框)
  4. 使用 sass
  5. 相对于 cookie 加密,我使用了 localStorage ,但需要防止 XSS 攻击获取到用户账号密码。

项目优化方案

  1. 使用雪碧图/精灵图,利用background-position显示想要的图片,为了有效地减少服务器接受和发送请求的次数,提高页面的加载速度。

    1. 使用图片懒加载
    2. 尽量压缩 css 和 js 文件大小,尽量要求算法的复杂度低。
    3. 采用less或者sass

说一个你在项目开发遇到的困难,怎么解决的。

在博客详细页面无法刷新,一刷新就出错

原因:博客详细里的内容来自上一个博客数组里面的某一个元素(对象),我把他放入了全局当中,刷新之后全局中的内容就清空了。

解决方案 1 :在点入博客详细的时候就把这个元素里的所以内容存入本地存储,在博客详细页面进行读取在渲染到页面上,在离开博客详细页面的时候要回收本地存储内博客的内容,有垃圾回收意识,这样刷新之后应该就能够照常看见博客详细的问题了,这是我能想到的解决方案之一。

解决方案 2 :后端写多一个接口根据博客查询博客内容,在进入博客详细的时候直接传一个 id 参数 然后再通过 id 查询拿到数据渲染到页面。

解决方案 3:放在路由当中,query

答辩一些没有掌握的地方

路由守卫

vue 常用的跨域方式

组件的生命周期

TypeScript

Proxy