冒泡排序 :依次比较相邻的两个值,如果后面的比前面的小,则将小的元素排前面。依照这个规则进行多次递减的迭代,直到顺序正确。
快速排序 :取一个中间值,通过这个之间值和数组中的树相比,比它小的放左边,比它大的放右边,再依次递归左侧和右侧的数组,以此达到排序目的。
插入排序:1.从数组的第二个数据开始往前比较,如果 符合条件(比前面的大或者小,自定义),则让他们交换位置。2.然后再用第三个数和第二个比较,符合则交换,但是此处还得继续往前比较,
比如有 5个数8,15,20,45, 17,17比45小,需要交换,但是17也比20小,也要交换,当不需 要和15交换以后,说明也不需要和15前面的数据比较了,肯定不需要交换,因为前 面的数据都是有序的。
通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应的位置并插入。
computed和watch的区别
计算属性是基于它们的响应式依赖进行缓存的,页面重新渲染值不变,计算属性会立即返回之前的计算结果,不必再次执行函数,
watch 观察的作用,每当监听数据变化时都会执行回调进行后续操作, 页面重新渲染时值不变化也会执行
vue 的双向绑定的原理是什么(常考)
vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的 setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
具体步骤: 第一步:需要 observe 的数据对象进行递归遍历,包
括子属性对象的属性,都加上 setter 和 getter 这样的话,给这个
对象的某个值赋值,就会触发 setter,那么就能监听到了数据变
化
Observe:利用Object.defineProperty数据劫持data,所以vue不能新增属性必须事先定义,model->vm.data
第⼆步:compile 解析模板指令,将模板中的变量替换成数据,
然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函
数,添加监听数据的订阅者,⼀旦数据有变动,收到通知,更新
视图
Compile:在文档碎片中操作dom节点,遍历正则匹配替换data属性,view->vm.$el
第三步:Watcher 订阅者是 Observer 和 Compile 之间通信的桥
梁,主要做的事情是:
在自身实例化时往属性订阅器(dep)里面添加自己
自身必须有一个 update()⽅法
待属性变动 dep.notice()通知时,能调自身的 update() 方
法,并触发 Compile 中绑定的回调,则功成身退。
Dep&&Watcher:利用发布订阅模式链接view和model
vue的响应原理
当一个vue实例创建时,vue会遍历Data选项的属性,用object.dafineproperty将他们转化成getter/seeter并且在内部追踪相关依赖,在属性被访问和修好时通知变化。每个组件实例都有相应的watcher程序实例,他会在组件渲染过程中把属性记录为依赖,之后当依赖项setter被调用时,会通知watcher重新计算,从而致使它关联的组件得以更新
https://www.cnblogs.com/fundebug/p/responsive-vue.html
什么是 mvvm?
MVVM 是 Model-View-ViewModel 的缩写。mvvm 是一种设计思想。Model 层代表数据模型;View 代表视图组件,ViewModel 是一个同步 View 和 Model 的对象。ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来
怎么实现MVVM
脏值检查:angularangular.js 是通过脏值检测的方式比对数据是否有变更,来决定是否更新视图。
数据劫持:使用Object.defineProperty()方法把这些vm.data属性全部转成setter、getter方法。
Vue中MVVM组成部分
mvvm 和 mvc 区别?
mvc 中 Controller 演变成 mvvm 中的 viewModel。mvvm 主要解决了 mvc 中大量的 DOM 操作使页面渲染性能降低,加载速度变慢,影响用户体验。*
vue 的优点是什么?
低耦合。视图(View)可以独立于 Model 变化和修改,⼀个
ViewModel 可以绑定到不同的"View"上,当 View 变化的时
候 Model 可以不变,当 Model 变化的时候 View 也可以不
变。
可重复性。你可以把这些视图逻辑放在1个 ViewModel 里面,让很多 view 重复这段视图逻辑。
独立开发。开发人员可以专注于业务逻辑和数据的开发
(ViewModel),设计人员可以专注于⻚⾯设计,使⽤
Expression Blend 可以很容易设计界⾯并⽣成 xml 代码。
可测试。现在测试可以针对ViewModel 来写。
请详细说下你对 vue 生命周期的理解?
答:总共分为 8 个阶段创建前/后,加载前/后,更新前/后,销毁
前/后。
创建阶段
beforeCreate
实例刚在内存中被创建出来,此时,还没有初始化好data和methods属性。
created
实例已经在内存中创建完毕,此时data和methods已经创建完成,此时还没有开始编译模板。
挂载阶段
beforeMount
此时已经完成了模板的编译,但是还没有挂载到页面中。
mounted
此时已经将编译好的模板挂载到了页面指定的容器中显示。
运行阶段
boforeUpdate
状态更新之前执行此类函数,此时data中的状态值是最新的,但是界面上显示的数据还是旧的,因为此时还没有开始重新渲染DOM节点。
updated
实例更新完毕之后调用此函数,此时data中的状态值和页面上显示的数据都已经完成了更新,界面已经被重新渲染好了。
销毁阶段
beforeDestroy
实例销毁之前调用,在这一步,实例仍然完全可用。
destroyed
Vue实例销毁后调用,调用后Vue实例指示的所有东西都会解除绑定,所有的事件监听器都会被移除,所有的子实例也会被销毁。
前端性能优化
一般情况下, WEB 前端指网站业务逻辑之前的部分,包括浏览器加载、网站视图模型、图片服
务、 CDN 服务等,主要优化手段有浏览器访问、使用反向代理、 CDN 等。
- 减少 HTTP 请求,合理设置浏览器缓存
- 启用压缩
HTML 、 CSS 、 JavaScript 文件启用 GZip 压缩可以达到较好的结果。 - CSS 放在页面最上部, JavaScript 放最下面
让浏览器尽快下载 CSS 文件渲染页面。 - 图片懒加载
在页面加载的时候只加载第一屏图片,当用户往后滚动屏幕时再加载后续图片。 - 异步请求 CallBack
将一些行为样式提取出来,慢慢加载信息的内容。 - 减少 Cookie 传输
一方面, Cookie 包含在每次请求和响应中,太大的 Cookie 会严重影响数据传输,因此哪些数
据需要写入 Cookie 需要慎重考虑,尽量减少 Cookie 中传输的数据量。
另一方面,对于某些静态资源的访问,如 CSS 、 JS 等,发送 Cookie 没有意义,可以考虑静态
资源使用独立域名访问,避免请求静态资源时发送 Cookie ,减少 Cookie 传输次数。 - JavaScript 代码优化
- DOM 优化 HTML Collection HTML 收集器,返回的是一个数组内容信息。
在脚本中 document.images 、 document.forms 、 getElementsByTagName() 返回的都是
HTML Collection 类型的集合,在平时使用的时候大多将它作为数组来使用,因为它有
length 属性,也可以使用索引访问每一个元素。不过在访问性能上则比数组要差很多,原因是
这个集合并不是一个静态的结果,它表示的仅仅是一个特定的查询,每次访问该集合时都会重新
执行这个查询从而更新查询结果。所谓的“访问集合” 包括读取集合的 length 属性、访问集合中
的元素。
因此,当你需要遍历 HTML Collection 的时候,尽量将它转为数组后再访问,以提高性能。即
使不转换为数组,也请尽可能少的访问它,例如在遍历的时候可以将 length 属性、成员保存到
局部变量后再使用局部变量。 - 慎用 with with(obj){ p = 1}; 代码块的行为实际上是修改了代码块中的执行环境 ,将 obj 放在了其作
用域链的最前端,在 with 代码块中访问非局部变量是都是先从 obj 上开始查找,如果没有再依
次按作用域链向上查找,因此使用 with 相当于增加了作用域链长度。而每次查找作用域链都是
要消耗时间的,过长的作用域链会导致查找性能下降。
因此,除非你能肯定在 with 代码中只访问 obj 中的属性,否则慎用 with ,替代的可以使用局
部变量缓存需要访问的属性。 - 避免使用 eval 和 Function
每次 eval 或 Function 构造函数作用于字符串表示的源代码时,脚本引擎都需要将源代码转换
成可执行代码。这是很消耗资源的操作 —— 通常比简单的函数调用慢 100倍以上。
eval 函数效率特别低,由于事先无法知晓传给 eval 的字符串中的内容, eval 在其上下文中解
释要处理的代码,也就是说编译器无法优化上下文,因此只能有浏览器在运行时解释代码。这对
性能影响很大。
Function 构造函数比 eval 略好,因为使用此代码不会影响周围代码,但其速度仍很慢。
此外,使用 eval 和 Function 也不利于 Javascript 压缩工具执行压缩。 - 减少作用域链查找
在循环中需要注意的问题。
如果在循环中需要访问非本作用域下的变量时请在遍历之前用局部变量缓存该变量,并在遍历结
束后再重写那个变量,这一点对全局变量尤其重要,因为全局变量处于作用域链的最顶端,访问
时的查找次数是最多的。 - 数据访问
JavaScript 中的数据访问包括直接量 (字符串、正则表达式 )、变量、对象属性以及数组,其中
对直接量和局部变量的访问是最快的,对对象属性以及数组的访问需要更大的开销。
当出现以下情况时,建议将数据放入局部变量:
对任何对象属性的访问超过 1 次。
对任何数组成员的访问次数超过 1 次。
另外,还应当尽可能的减少对对象以及数组深度查找。 - 字符串拼接 在 Javascript 中使用 + 号来拼接字符串效率是比较低的,因为每次运行都会开辟新的内存并生
成新的字符串变量,然后将拼接结果赋值给新变量。与之相比更为高效的做法是使用数组的
join 方法,即将需要拼接的字符串放在数组中最后调用其 join 方法得到结果。不过由于使用数
组也有一定的开销,因此当需要拼接的字符串较多的时候可以考虑用此方法。 - CDN 加速
CDN(contentdistribute network,内容分发网络)的本质仍然是一个缓存,而且将数据缓存在离
用户最近的地方,使用户以最快速度获取数据,即所谓网络访问第一跳。 - 反向代理
传统代理服务器位于浏览器一侧,代理浏览器将 http 请求发送到互联网上,而反向代理服务器
位于网站机房一侧,代理网站 web 服务器接收 http 请求
组件之间的传值?
- 父组件与子组件传值
父组件通过标签上自定义传值
子组件通过props方法接受数据 - 子组件向父组件传递数据
//子组件通过$emit方法传递参数
懒加载(按需加载路由)(常考)
webpack 中提供了 require.ensure()来实现按需加载。以前引⼊
路由是通过 import 这样的⽅式引⼊,改为 const 定义的⽅式进⾏
引⼊。
不进行页面按需加载引入方式:
import home from ‘…/…/common/home.vue’
进行页面按需加载的引入方式:
equire-ensure
说明: require.ensure在需要的时候才下载依赖的模块,当参数指定的模块都下载下来了(下载下来的模块还没执行),便执行参数指定的回调函数。require.ensure会创建一个chunk,且可以指定该chunk的名称,如果这个chunk名已经存在了,则将本次依赖的模块合并到已经存在的chunk中,最后这个chunk在webpack构建的时候会单独生成一个文件。
语法: require.ensure(dependencies: String[], callback: function([require]), [chunkName: String])
dependencies: 依赖的模块数组
callback: 回调函数,该函数调用时会传一个require参数
chunkName: 模块名,用于构建时生成文件时命名使用
注意点:requi.ensure的模块只会被下载下来,不会被执行,只有在回调函数使用require(模块名)后,这个模块才会被执行。
图片懒加载
内联图片
最常见的懒加载方式就是利用<img>
标签。懒加载图片时,我们利用JavaScript检查<img>
标签是否在视窗中。如果在,<img>
在这里插入代码片的src(有时候是srcset)就会设置为目标图片的url。
利用intersection observer
document.addEventListener("DOMContentLoaded", function() {
var lazyImages = [].slice.call(document.querySelectorAll("img.lazy"));
if ("IntersectionObserver" in window) {
let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
let lazyImage = entry.target;
lazyImage.src = lazyImage.dataset.src;
lazyImage.srcset = lazyImage.dataset.srcset;
lazyImage.classList.remove("lazy");
lazyImageObserver.unobserve(lazyImage);
}
});
});
lazyImages.forEach(function(lazyImage) {
lazyImageObserver.observe(lazyImage);
});
} else {
// Possibly fall back to a more compatible method here
}
});
<img class="lazy" src="placeholder-image.jpg" data-src="image-to-lazy-load-1x.jpg" data-srcset="image-to-lazy-load-2x.jpg 2x, image-to-lazy-load-1x.jpg 1x" alt="I'm an image!">
vuex 是什么
vue 框架中状态管理。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 应用的核心就是 store(仓库)
在 main.js 引入store,注入。新建了一个目录 store,…… export 。
场景有:单页应用中,组件之间的状态音乐播放、登录状态、加入购物车
vuex 有哪几种属性
有 5 种,
state:状态中心
getter:获取状态
mutation:同步更改状态
action:异步更改状态
module:将state分成多个modules,便于管理
vuex 的 store 特性是什么
vuex 就是一个仓库,仓库里放了很多对象。其中 state 就是数据源存放地,对应于一般 vue 对象里面的 data
state 里面存放的数据是响应式的,vue 组件从 store 读取数据,若是 store 中的数据发生改变,依赖这相数据的组件也会发生更新
它通过 mapState 把全局的 state 和 getters 映射到当前组件
的 computed 计算属性
vuex 的 getter 特性是什么
getter 可以对 state 进行计算操作,它就是 store 的计算属性
虽然在组件内也可以做计算属性,但是 getters 可以在多给
件之间复用
如果一个状态只在一个组件内使用,可以不用 getters
vuex 的 mutation 特性是什么
action 类似于 muation, 不同在于:action 提交的是
mutation,而不是直接变更状态
action 可以包含任意异步操作
vuex 原理
vuex 仅仅是作为 vue 的⼀个插件⽽存在,不像 Redux,MobX 等
库可以应⽤于所有框架,vuex 只能使⽤在 vue 上,很⼤的程度是
因为其⾼度依赖于 vue 的 computed 依赖检测系统以及其插件系
统,
vuex 整体思想诞⽣于 flux,可其的实现⽅式完完全全的使⽤了 vue
⾃身的响应式设计,依赖监听、依赖收集都属于 vue 对对象
Property set get ⽅法的代理劫持。最后⼀句话结束 vuex ⼯作原
理,vuex 中的 store 本质就是没有 template 的隐藏着的 vue 组
件;
路由
就是SPA(单页应用)的路径管理器。再通俗的说,vue-router就是WebApp的链接路径管理系统。
vue-router是Vue.js官方的路由插件,它和vue.js是深度集成的,适合用于构建单页面应用。vue的单页面应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来。传统的页面应用,是用一些超链接来实现页面切换和跳转的。在vue-router单页面应用中,则是路径之间的切换,也就是组件的切换。路由模块的本质 就是建立起url和页面之间的映射关系
单页面应用(SPA)的核心之一是: 更新视图而不重新请求页面;vue-router在实现单页面前端路由时,提供了两种方式:Hash模式和History模式;根据mode参数来决定采用哪一种方式。
1、Hash模式:
vue-router 默认 hash 模式 —— 使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。 hash(#)是URL 的锚点,代表的是网页中的一个位置,单单改变#后的部分,浏览器只会滚动到相应位置,不会重新加载网页,也就是说hash 出现在 URL 中,但不会被包含在 http 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面;同时每一次改变#后的部分,都会在浏览器的访问历史中增加一个记录,使用”后退”按钮,就可以回到上一个位置;所以说Hash模式通过锚点值的改变,根据不同的值,渲染指定DOM位置的不同数据。hash 模式的原理是 onhashchange 事件(监测hash值变化),可以在 window 对象上监听这个事件。
2、History模式:
我们可以用路由的 history 模式,只需要在配置路由规则时,加入"mode: ‘history’",
//main.js文件中
const router = new VueRouter({
mode: 'history',
routes: [...]
})
这种模式充分利用了html5 history interface 中新增的 pushState() 和 replaceState() 方法。这两个方法应用于浏览器记录栈,在当前已有的 back、forward、go 基础之上,它们提供了对历史记录修改的功能。只是当它们执行修改时,虽然改变了当前的 URL ,但浏览器不会立即向后端发送请求。
动态路由
一个“路径参数”使用冒号 : 标记。使用 this.$route.params获取
active-class 是哪个组件的属性?
vue-router 模块的 router-link 组件。用来做选中样式的切换.
嵌套路由怎么定义?
路由之间跳转?
3、使用路由模块来实现页面跳转的方式
方式1:直接修改地址栏
方式2:this.$router.push(‘路由地址’)
方式3:<router-link to="路由地址"></router-link>
vue-router 有哪几种导航钩子?
三种
全局导航钩子
router.beforeEach(to, from, next),
router.beforeResolve(to, from, next),
router.afterEach(to, from ,next)
组件内钩子
beforeRouteEnter,
beforeRouteUpdate,
beforeRouteLeave
单独路由独享组件
beforeEnter
导航被触发。
在失活的组件里调用 beforeRouteLeave 守卫。
调用全局的 beforeEach 守卫。
在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
在路由配置里调用 beforeEnter。
解析异步路由组件。
在被激活的组件里调用 beforeRouteEnter。
调用全局的 beforeResolve 守卫 (2.5+)。
导航被确认。
调用全局的 afterEach 钩子。
触发 DOM 更新。
调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。
网页从打开到加载
1. DNS 解析
浏览器首先搜索浏览器自身缓存的 DNS 记录。
如果浏览器缓存中没有找到需要的记录或记录已过期,则搜索 hosts 文件和操作缓存。
如果在 hosts 文件和操作系统缓存中没有找到需要的记录或记录已经过期,则向域名解析服
务器发送解析请求。
如果域名解析服务器也没有该域名的记录,则开始 递归 + 迭代 解析。
获取域名对应的IP后,一步步向上返回,直到返回给浏览器。
浏览器获取到 url 的 IP 地址。
2. 发起TCP请求
建立TCP连接的过程就是三次握手过程:
- 客户端向服务器端发送连接请求的报文。
- 服务器端收到请求后,同意建立连接,向客户端发送确认报文。
- 客户端收到服务器端的确认报文后,再次向服务器端发出报文,确认已收到确认报文。
- 浏览器与服务器已经建立了TCP连接,开始进行通信。
3. 浏览器向服务器发送http请求
例如:浏览器发出取文件指令GET。
4. 负载均衡
什么是负载均衡?当一台服务器无法支持大量的用户访问时,将用户分摊到两个或多个服务器上
的方法叫负载均衡。 - 如果我们的平台配备了负载均衡的话,前一步 DNS 解析获得的IP地址应该是我们 Nginx 负
载均衡服务器的 IP 地址。所以,我们的浏览器将我们的网页请求发送到了 Nginx 负载均
衡服务器上。 - Nginx 根据我们设定的分配算法和规则,选择一台后端的真实 Web 服务器,与之建立
TCP 连接、并转发我们浏览器发出去的网页请求。 - Web 服务器收到请求,产生响应,并将网页发送给 Nginx 负载均衡服务器。
- Nginx 负载均衡服务器将网页传递给 filters 链处理,之后发回给我们的浏览器。
5. 服务器响应http请求,将请求的指定资源发送给浏览器
6. 浏览器释放TCP连接
建立TCP连接的过程就是四次挥手过程: - 浏览器向服务器发送释放连接报文。
- 服务器收到释放报文后,发出确认报文,然后将服务器上未传送完的数据发送完。
- 服务器数据传输完成后,向浏览器发送释放连接请求。
- 浏览器收到报文后,发出确认,然后等待一段时间后,释放TCP连接。
7. 浏览器渲染 1. 浏览器根据页面内容,生成 DOM Tree 。根据 CSS 内容,生成 CSS Rule Tree (规则树)。
调用 JS 执行引擎执行 JS 代码。 - 根据 DOM Tree 和 CSS Rule Tree 生成 Render Tree (呈现树)。 3. 根据 Render Tree 渲染网页。
自定义指令(v-check, v-focus) 的方法有哪些? 它有 哪些钩子函数? 还有哪些钩子函数参数
全局定义指令:在 vue 对象的 directive 方法里面有两个参
数, 一个是指令名称, 另一个是函数。
组件内定义指令:directives
钩子函数: bind(绑定事件出发)、inserted(节点插入时候触
发)、update(组件内相关更新)
钩子函数参数: el、binding
axios
**进入了很多人的目光中。
axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端,本质上也是对原生XHR的封装,只不过它是Promise的实现版本,
axios是请求后端资源的模块
描述使⽤它实现登录功能的流程
npm i axios -S
如果发送的是跨域请求,需在配置⽂件中 config/index.js 进⾏配
置
符合最新的ES规范,它本身具有以下特征:
1.从浏览器中创建 XMLHttpRequest
2.支持 Promise API
3.客户端支持防止CSRF
4.提供了一些并发请求的接口(重要,方便了很多的操作)
5.从 node.js 创建 http 请求
6.拦截请求和响应
7.转换请求和响应数据
8.取消请求
9.自动转换JSON数据
PS:防止CSRF:就是让你的每个请求都带一个从cookie中拿到的key, 根据浏览器同源策略,假冒的网站是拿不到你cookie中得key的,这样,后台就可以轻松辨别出这个请求是否是用户在假冒网站上的误导输入,从而采取正确的策略。
(1)
XMLHttpRequest 对象用于在后台与服务器交换数据。
XMLHttpRequest 对象是开发者的梦想,因为您能够:
在不重新加载页面的情况下更新网页
在页面已加载后从服务器请求数据
在页面已加载后从服务器接收数据
在后台向服务器发送数据
所有现代的浏览器都支持 XMLHttpRequest 对象。
创建 XMLHttpRequest 对象
所有现代浏览器 (IE7+、Firefox、Chrome、Safari 以及 Opera) 都内建了 XMLHttpRequest 对象。
通过一行简单的 JavaScript 代码,我们就可以创建 XMLHttpRequest 对象。
创建 XMLHttpRequest 对象的语法:
xmlhttp=new XMLHttpRequest();
v-if 和 v-show区别
2.区别
(1)手段:
v-if 是动态的向DOM树内添加或者删除DOM元素;
v-show 是通过设置DOM元素的display样式属性控制显隐;
(2)编译过程:
v-if 切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件;
v-show只是简单的基于css切换;
(3)编译条件:
v-if 是惰性的,如果初始条件为假,则什么也不做;只有在条件第一次变为真时才开始局部编译(编译被缓存?编译被缓存后,然后再切换的时候进行局部卸载);
v-show 是在任何条件下(首次条件是否为真)都被编译,然后被缓存,而且DOM元素保留;
(4)性能消耗:
v-if 有更高的切换消耗;
v-show 有更高的初始渲染消耗;
(5)使用场景:
v-if 适合运营条件不大可能改变;
v-show 适合频繁切换。
1.共同点
v-if 和 v-show 都可以动态地显示DOM元素