1、浏览器本地存储?
https://juejin.im/post/5d48eac9518825403769d9ad
cookie localStorage sessionStorage
2、web storage和cookie的区别?
a.cokkie的大小是受限的
b.每次你请求一个新的页面的时候cookie都会被发送过去,这样无形中浪费了宽带
c.cookie还需要指定的作用域,不可以跨域调用
d.web storge拥有setitem,getitem等方法,cookie需要前端开发者自己封装setCookie,getCookie
e.cookie的作用是与服务器交互,作为HTTP规范的一部分而存在,而web storge仅仅是为了在本地储存数据
f.IE7,IE6的UserData通过简单的代码封装可以统一到所有的浏览器都支持web storge
3.请描述一下 cookies、 sessionStorage和localstorage区别?
a.localSorge长期存储数据,浏览器关闭数据后不丢失
b.sessionStorage数据在浏览器关闭后自动删除
c.cookie是网站为了标识用户身份而存储在用户本地终端上的数据(通常经过加密)cookie始终在同源的http请求中携带
4、常见的HTTP状态码?
1.200(ok) 一切正常。实体主体中的文档是某资源的表示
2.400 客户端方面的问题。
3.500服务器方面的问题
4.301 当客户端出发的动作引起了资源url的变化时发送此代码
5.404 当客户端所请求的URI不对应于任何资源时,发送此响应代码
6.409 当客户端试图执行一个”会导致一个或多个资源处于不一致状态“的操作时,发送此响应代码
只是常用的几种列举
5、bootstrap响应式实现的原理?
1.百分比布局+媒体查询
2.想要了解更多的可以面向百度
6、Vue请求数据的方式
一、vue-resource 请求数据(vue官方请求)
二、 axios 请求数据
三、fetchJsonp 请求数据
7、如何优化页面,加快页面的加载速度
1.优化DNS查询
减少域名:尽量把所有的资源放在一个域名下。一个域名同时可以发4(IE8)或8个请求(Chrome)。请求文件少,用1个域名,文件多用多个域名。与3权衡。
2.优化TCP协议
TCP连接复用,使用keep-alive:连接回复加上请求头:keep-alive。第一次请求不断开,第二次请求复用。
使用http 2.0版本:多路复用,连接复用率会更高
3. 优化发送HTTP请求
合并JS或CSS文件
inline image:使用data:url scheme来内连图片
减小cookie体积,每个请求都会附带cookie,所以不要滥用cookie。
合理使用CasheControl代替发送HTTP请求
同时发送多个请求(浏览器自带)IE8可以同时请求下载4个的css文件,Chrome可以同时请求下载8个 。
4.优化接受响应
设置Etags:浏览器重复与请求服务器一样的文件,ETag响应304。
Gzip压缩大文件 使用macos gzip,npm server gzipgzip 文件名
其响应头为Content-Encodinging:gzip,先压缩接收到再解压缩。缺点:耗费浏览器CPU,权衡
5.优化DOCTYPE
不能不写,不能写错
6.优化CSS、JS请求
使用CDN:用CDN请求静态资源同时可以增大同时下载数量,内容分发网络(CDN)可以使请求总时间降低,也可以减少cookie
CSS放在head里:使其尽早下载,因为chrome需要下载完所有的css后才渲染页面
JS放在body里的最后:尽早显示整个页面,获取节点。
7.使用懒加载
组件懒加载
constxxx=()=>import('./components/xxx.vue')
路由懒加载
8.优化用户体验
用户看到哪些内容就请求哪些内容
加一个loading动画用户会感觉时间变快
9.减少监听器,使用事件委托
10.优化图片大小
11.减少或合并DOM操作或使用虚拟DOM
12.对大量数据计算使用缓存
13.使用setTimeout降低调用接口频率
8、iframe的优缺点?
iframe的优点:
1.iframe能够原封不动的把嵌入的网页展现出来。
2.如果有多个网页引用iframe,那么你只需要修改iframe的内容,就可以实现调用的每一个页面内容的更改,方便快捷。
3.网页如果为了统一风格,头部和版本都是一样的,就可以写成一个页面,用iframe来嵌套,可以增加代码的可重用。
4.如果遇到加载缓慢的第三方内容如图标和广告,这些问题可以由iframe来解决。
iframe的缺点:
1.会产生很多页面,不容易管理。
2.iframe框架结构有时会让人感到迷惑,如果框架个数多的话,可能会出现上下、左右滚动条,会分散访问者的注意力,用户体验度差。
3.代码复杂,无法被一些搜索引擎索引到,这一点很关键,现在的搜索引擎爬虫还不能很好的处理iframe中的内容,所以使用iframe会不利于搜索引擎优化。
4.很多的移动设备(PDA 手机)无法完全显示框架,设备兼容性差。
5.iframe框架页面会增加服务器的http请求,对于大型网站是不可取的。
分析了这么多,现在基本上都是用Ajax来代替iframe,所以iframe已经渐渐的退出了前端开发。
9、Http与Https的区别
HTTP协议传输的数据都是未加密的,也就是明文的,因此使用HTTP协议传输隐私信息非常不安全,为了保证这些隐私数据能加密传输,于是网景公司设计了SSL(Secure Sockets Layer)协议用于对HTTP协议传输的数据进行加密,从而就诞生了HTTPS。简单来说,HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全。
HTTPS和HTTP的区别主要如下:
1、https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
2、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
3、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
4、http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
10、vuex的属性
1.state:vuex的基本数据,用来存储变量
2.getter:从基本数据(state)派生的数据,相当于state的计算属性
3.mutation:提交更新数据的方法,必须是同步的(如果需要异步使用action)mutation都有一个字符串的事件类型(type)和一个回调函数(handler)回调函数就是我们实际进行状态更改的地方,并且它会接收state作为底一个参数,提交载荷作为第二个参数
4.action:和mutation的功能大致相同,不同之处在于 1.action提交的是mutatio,而不是直接变更状态 2.action可以包含任意异步操作
5.modules:模块化vuex,可以让每一个模块拥有自己的state,mutation,action,getters,使得结构非常清晰,方便管理
12、vue双向绑定的原理
vue.js 则是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
ue的数据双向绑定是通过数据劫持和发布-订阅者功能来实现的
实现步骤:1.实现一个监听者Oberver来劫持并监听所有的属性,一旦有属性发生变化就通知订阅者
2.实现一个订阅者watcher来接受属性变化的通知并执行相应的方法,从而更新视图
3.实现一个解析器compile,可以扫描和解析每个节点的相关指令,并根据初始化模板数据以及初始化相对应的订阅者
13、h5新标签
1.Header:页眉
描述了文档的头部区域,于定义内容的介绍展示区域。
(1)只有必要时使用header,大多数情况下,如果只有h1~h6或hgroup,没有其它需要与之组合在一起的伴生内容,就没有必要用header将它包起来。
(2)header与h1~h6元素中的标题是不能互换的,它们都有各自的语义目的。
(3)不能在header里嵌套footer元素或另一个header,也不能在footer或address元素里嵌套header。
(4)header不一定必须包含nav元素,不过在大多数情况下,如果header包含导航性链接,就可以用nav。
2.nav:标记导航
标签定义导航链接的部分。无论哪种情况,应该仅对文档中重要的链接群使用nav。通常用一个ul元素(无序列表)对链接列表进行标记,除非链接是面包屑链接则使用ol元素(有序列表)。
(1)HTML5不允许将nav嵌套在address元素中。
(2)HTML5规范不推荐对辅助性的页脚链接(使用条款,隐私政策等),所以选择用nav。
3.article:文章标记标签
表示文档、页面、应用或网站中一个独立的容器,原则上是可独立分配或可再用的,即聚合。
(1)article可以嵌套在另一个article里面,只要里面的article与外面的article是部分与整体的关系,但是不能将article嵌套在address元素里。
(2)一个article里包含一个或者多个section元素并是不强制性的。
4.section:区块定义标签
表示的是文档或是应用的一个一般的区块,一般是有一组相似的主题的内容。
(1)section不是一个像div一样的通用容器,因为section表达一定的含义,而div则没有任何语义上的含义。
【特别提醒】如何在article和section中作出选择?
你的内容是适合做聚合的一块独立的内容或一个小组件吗?如果是,使用article。否则使用section。这并不是意味着你必须聚合或芬达article内容,只是其内容适合这样做。
5.aside:定义侧栏标签
表示一部分内容与页面的主题并不是有很大的关系,可以独立存在。aside的例子包括抬升式引用、侧栏、新闻站上列出相关文章的连接框、广告、nav元素组(如博客的友情链接)、商业站上相关产品列表。
(1)如果子啊侧栏中使用一个或多个aside(或将其作为侧栏使用),应在HTML中将他们放在页面主要内容的后面。将重要的内容放在前面有利于SEO和提升可访问性。
(2)对于与内容有关的图像(如图表、图形或带有说明文字的插图),使用figure而非aside。
(3)HTML5不允许将aside嵌套在address元素中。
6.footer:页脚标签
与header标签对应的标签,可以放附录、索引、版权页、许可协议等。
(1)footer元素代表嵌套它的最近的article、aside、nluckquote、body、details、fieldset、figure、nav、section或td元素的页脚。只有当它最近的祖先是body时,它才是整个页面的页脚。
(2)不允许在footer里嵌套header或另一个footer。同时,也不能将footer嵌套在header或address元素里。
14、vue全家桶
vue:主要Vue
vue-router:关于路由方面的配置
vuex:数据共享和缓存用
vue-resource:于后台交互用(现在改为axios 但是axios不是Vue里面的东西)
vue-cli:快速创建项目的脚手架
15、MVVM思想:Vue.js是一套构建用户界面的MVVM框架
1.MVC
Model数据 →View视图 →Controller控制器
2.MVVM
MVVM不算是一种创新
但是其中的ViewModel是一种创新
ViewModel是真正结合前端应用场景的实现
3.如何理解MVVM
MVVM - Model View ViewModel,数据,视图,视图模型
三者与Vue的对应:view对应template,vm对应new Vue({…}),model对应data
三者的关系:view可以通过事件绑定的方式影响model,model可以通过数据绑定的形式影响到view,viewModel是把model和view连起来的连接器
16、合并数组
1、concat
js的Array对象提供了一个叫concat()方法,连接两个或更多的数组,并返回结果。
var c = a.concat(b);//c=[1,2,3,4,5,6];
这里有一个问题,concat方法连接a、b两个数组后,a、b两个数组的数据不变,同时会返回一个新的数组。这样当我们需要进行多次的数组合并时,会造成很大的内存浪费,所以这个方法肯定不是最好的。
2、for循环
大概的思路是:遍历其中一个数组,把该数组中的所有元素依次添加到另外一个数组中。直接上代码:
for(var i in b){
a.push(b[i]);
}
这样的写法可以解决第一种方案中对内存的浪费,但是会有另一个问题:丑!这么说不是没有道理,如果能只用一行代码就搞定,岂不快哉~
3、apply
函数的apply方法有一个特性,那就是func.apply(obj,argv),argv是一个数组。所以我们可以利用这点,直接上代码:a.push.apply(a,b);
调用a.push这个函数实例的apply方法,同时把,b当作参数传入,这样a.push这个方法就会遍历b数组的所有元素,达到合并的效果。
这里可能有点绕,我们可以把b看成[4,5,6],变成这样:a.push.apply(a,[4,5,6]);
然后上面的操作就等同于:a.push(4,5,6);
另外,还要注意两个小问题:
1)以上3种合并方法并没有考虑过a、b两个数组谁的长度更小。
所以好的做法是预先判断a、b两个数组哪个更大,然后使用大数组合并小数组,这样就减少了数组元素操作的次数!
2)有时候我们不希望原数组(a、b)改变,这时就只能使用concat了。
17、垂直居中的方式
.parent {
display: flex;
justify-content: center; //水平居中
align-items: center; //垂直居中
}
18、call,apply,bind的区别?
在JS中,这三者都是用来改变函数的this对象的指向的,他们有什么样的区别呢。
在说区别之前还是先总结一下三者的相似之处:
1、都是用来改变函数的this对象的指向的。
2、第一个参数都是this要指向的对象。
3、都可以利用后续参数传参。
1.call方法调用一个函数, 其具有一个指定的this值和分别地提供的参数(参数的列表)。
注意:该方法的作用和 apply() 方法类似,只有一个区别,就是call()方法接受的是若干个参数的列表,而apply()方法接受的是一个包含多个参数的数组。
functionPerson(name,age){this.name=name;this.age=age;}functionMale(name,age,sex){Person.call(this,name,age);this.sex=sex;}varmen=newMale('john',30,'male');console.log(men.name);//'john'
2.方法调用一个具有给定this值的函数,以及作为一个数组(或类似数组对象)提供的参数。
注意:call()方法的作用和 apply() 方法类似,区别就是call()方法接受的是参数列表,而apply()方法接受的是一个参数数组。
vararr=[1,5,10,20,100];varmax=Math.max.apply(null,arr);console.log(max);//100varmin=Math.min.apply(null,arr);console.log(min);//1
3.bind()方法创建一个新的函数,当这个新的函数被调用时,其this置为提供的值,其参数列表前几项,置为创建时指定的参数序列。
varmodule={x:42,getX:function(){returnthis.x;}}varunboundGetX=module.getX;console.log(unboundGetX());//undefinedvarboundGetX=unboundGetX.bind(module);console.log(boundGetX());//42
19、为什么使用axios?
1.axios:
从 node.js 创建 http 请求
支持 Promise API
客户端支持防止CSRF
提供了一些并发请求的接口(重要,方便了很多的操作)
2.jQuery ajax:
本身是针对MVC的编程,不符合现在前端MVVM
基于原生的XHR开发,XHR本身的架构不清晰,已经有了fetch的替代方案
JQuery整个项目太大,单纯使用ajax却要引入整个JQuery非常的不合理(采取个性化打包的方案又不能享受CDN服务)
20、new操作的过程?
new操作符的基本过程:
1.创建一个新的空对象。
2.将构造函数的作用域赋给它(即this指向它)。
3.新对象增加构造函数的基本方法和属性。
4.返回新对象
21、vuex原理?
Vue Components:Vue组件。HTML页面上,负责接收用户操作等交互行为,执行dispatch方法触发对应action进行回应。• dispatch:操作行为触发方法,是唯一能执行action的方法。
• actions:操作行为处理模块。负责处理Vue Components接收到的所有交互行为。包含同步/异步操作,支持多个同名方法,按照注册的顺序依次触发。向后台API请求的操作就在这个模块中进行,包括触发其他action以及提交mutation的操作。该模块提供了Promise的封装,以支持action的链式触发。
• commit:状态改变提交操作方法。对mutation进行提交,是唯一能执行mutation的方法。
• mutations:状态改变操作方法。是Vuex修改state的唯一推荐方法,其他修改方式在严格模式下将会报错。该方法只能进行同步操作,且方法名只能全局唯一。操作之中会有一些hook暴露出来,以进行state的监控等。
• state:页面状态管理容器对象。集中存储Vue components中data对象的零散数据,全局唯一,以进行统一的状态管理。页面显示所需的数据从该对象中进行读取,利用Vue的细粒度数据响应机制来进行高效的状态更新。
• getters:state对象读取方法。图中没有单独列出该模块,应该被包含在了render中,Vue Components通过该方法读取全局state对象。Vue组件接收交互行为,调用dispatch方法触发action相关处理,若页面状态需要改变,则调用commit方法提交mutation修改state,通过getters获取到state新值,重新渲染Vue Components,界面随之更新。
22、vue怎么实现页面的权限控制?
对于一般稍大一些的后台管理系统,往往有很多个人员需要使用,而不同的人员也对应了不同的权限系统,后端的权限校验保障了系统的安全性,而前端的权限校验则提供了优秀的交互体验。
路由不可见实现方法:
在router.js中的meta字段中加入该路由的访问权限列表auths字段。
{
path: 'edit',
name: 'edit',
meta: {
title: '编辑账户',
auths:['edit_account']
},
component: () => import('pathToComponent/component.vue'),
},
Vue.router中提供了导航守卫,我们这里使用全局前置守卫对路由跳转进行权限校验
router.beforeEach(to,from,next)
参数to是即将进入的路由对象,我们可以在对象中拿到之前在router.js中定义的route对象,并获得auths字段
router.beforeEach((to,from,next)=>{
const hasAuth = function(needAuths,haveAuths){ //判断用户是否拥有权限的function
// implement
}
const havaAuths = []; // 用户拥有的权限列表
if(!hasAuth(to.meta.auths,haveAuths)){
//没有权限重定位到其他页面,往往是401页面
next({replace:true,name:'otherRouteName'})
}
//权限校验通过,跳转至对应路由
next();
})
23、真实DOM和虚拟DOM的区别?
虚拟DOM与真实DOM的区别(注意:需不需要虚拟DOM,其实与框架的DOM操作机制有关):
1.虚拟DOM不会进行排版与重绘操作
2.虚拟DOM进行频繁修改,然后一次性比较并修改真实DOM中需要改的部分(注意!),最后并在真实DOM中进行排版与重绘,减少过多DOM节点排版与重绘损耗
3.真实DOM频繁排版与重绘的效率是相当低的
4.虚拟DOM有效降低大面积(真实DOM节点)的重绘与排版,因为最终与真实DOM比较差异,可以只渲染局部(同2)
使用虚拟DOM的损耗计算:总损耗 = 虚拟DOM增删改 + (与Diff算法效率有关)真实DOM差异增删改 + (较少的节点)排版与重绘
直接使用真实DOM的损耗计算:总损耗 = 真实DOM完全增删改 + (可能较多的节点)排版与重绘
24、怎么解决跨域?
①、response 添加 header
我们在 Servlet 请求返回时添加如下代码:
1//*表示支持所有网站访问,也可以额外配置相应网站2resp.setHeader("Access-Control-Allow-Origin", "*");
②、JSONP 方式
jsonp是服务器与客户端跨源通信的常用方法,特点是简单适用,老式浏览器全部支持,而服务器改造小
它的基本思想是:网页通过添加一个<script>元素,向服务器请求JSON数据,这种做法不受同源政策限制。服务器收到请求后,将数据放在一个指定名字的回到函数里传回来。首先,网页动态插入<script>元素,由他向跨域网址发出请求 元素,向服务器请求JSON数据,这种做法不受同源政策限制。服务器收到请求后,将数据放在一个指定名字的回到函数里传回来。首先,网页动态插入 元素,由它向跨源网址发出请求。 元素,向服务器请求JSON数据,这种做法不受同源政策限制。服务器收到请求后,将数据放在一个指定名字的回到函数里传回来。首先,网页动态插入 元素,由它向跨源网址发出请求。 元素,向服务器请求JSON数据,这种做法不受同源政策限制。服务器收到请求后,将数据放在一个指定名字的回到函数里传回来。首先,网页动态插入 元素,由它向跨源网址发出请求。
<script><br> //动态插入script 标签
var script = document.createElement('script')
script.type = 'text/javascript'
script.src = "http://localhost:8080/login?user=admin&callback=handleCallback"
document.head.appendChild(script)
function handleCallback(res) {//回调函数
console.log(JSON.stringify(res))
}
</script>
当然后台也要配置相关代码
3.后台直接设置
4.CORS跨域资源共享
参考阮一峰老师的文章 http://www.ruanyifeng.com/blog/2016/04/cors.html
5.代理跨域
如webpack 的proxy 代理实现跨域 参考下面的代码
dev: {
env: require('./dev.env'),
port: 8080,
autoOpenBrowser: true,
assetsSubDirectory: 'static',
assetsPublicPath: '/',
proxyTable: {
'/api': {
target: 'http://www.abc.com',//目标接口域名changeOrigin:true,//是否跨域 pathRewrite: {
'^/api': '/api'//重写接口 }
},
cssSourceMap: false}
25、请简述JavaScript中的this?
1.在调用函数时使用new关键字,函数内的this是一个全新的对象。
2.如果apply、call或bind方法用于调用、创建一个函数,函数内的 this 就是作为参数传入这些方法的对象。
3.当函数作为对象里的方法被调用时,函数内的this是调用该函数的对象。比如当obj.method()被调用时,函数内的 this 将绑定到obj对象。
4.如果调用函数不符合上述规则,那么this的值指向全局对象(global object)。浏览器环境下this的值指向window对象,但是在严格模式下('use strict'),this的值为undefined。
5.如果符合上述多个规则,则较高的规则(1 号最高,4 号最低)将决定this的值。
6.如果该函数是 ES2015 中的箭头函数,将忽略上面的所有规则,this被设置为它被创建时的上下文。
26、JS哪些操作会造成内存泄露?
1。意外的全局变量引起的内存泄露
function leak(){
leak="xxx";//leak成为一个全局变量,不会被回收
}
2。闭包引起的内存泄露
3。没有清理的DOM元素引用
4。被遗忘的定时器或者回调
5。子元素存在引起的内存泄露
27、如何确定this指向?
1.this指向的形式4种
a.如果是一般函数,this指向全局对象window;
b.在严格模式下"use strict",为undefined.
c.对象的方法里调用,this指向调用该方法的对象.
d.构造函数里的this,指向创建出来的实例.
2. 改变this指向的方式
以下属于函数的方法
改变this的指向并且执行调用函数
.call(), call(thisScope, arg1, arg2, arg3...)
.apply(), apply(thisScope, [arg1, arg2, arg3...]);两个参数
而bind 改变this的指向,返回的是函数
.bind() bind(thisScope, arg1, arg2, arg3...)
28、箭头函数和普通函数有什么区别?
1.箭头函数相当于匿名函数,是不能作为构造函数的,不能使用new
2.箭头函数不绑定arguments,取而代之用rest参数…解决
3.箭头函数会捕获其所在上下文的this值,作为自己的this值。即箭头函数的作用域会继承自外围的作用域。
4.箭头函数当方法使用的时候没有定义this的绑定
5.使用call()和apply()调用
6.箭头函数没有函数原型
7.箭头函数不能当做Generator函数,不能使用yield关键字
8.箭头函数不能换行
29、怎么理解闭包?
首先闭包表示有权访问另一个函数作用域中的变量的函数,常见的创建闭包的方式是在一个函数中创建另一个函数。
要了解闭包的原理首先要了解函数作用域,接下来从函数作用域推广到闭包的原理。
1、当某个函数被调用时,会创建一个执行环境及相应的作用域链。然后使用arguments和其他参数的值来初始化函数的活动对象。但在作用域链中,外部函数的活动对象始终处于第二位, 外部函数的外部函数的活动对象处于第三位,……以此类推,直至作为作用域的全局执行环境。
2、在函数执行过程中,为读取和写入变量的值,就需要在作用域中查找变量,依次按照内部-》外部-》外部的外部的顺序进行查找。
3、一般来讲,当函数执行完毕之后,局部活动对象就会被销毁,内存中均保存全局作用域(全局执行环境的变量对象),但是,闭包的情况不一样:在另一个函数内部定义的函数会将包含外部函数的活动对象添加到它的作用域链中,函数执行完毕后,其活动对象也不会被销毁,因为内部函数的作用域链仍然在引用这个活动对象。所以当函数执行完毕后,只是执行的作用域链会被销毁,但它的活动对象仍然保留在内存中,知道内部函数被销毁后才销毁。这就是闭包的原理。
注意:由于闭包具有以上特性,所以导致闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存。过度的使用闭包可能会导致内存占用过多,虽然像V8等优化后的js引擎会尝试回收被闭包占用的内存,但还是建议在绝对必要的时候再使用闭包
30、如何实现原型继承?
原型继承
利用原型中的成员可以被和其相关的对象共享这一特性,可以实现继承
1.给原型对象中==添加成员==(通过对象的动态特性) 不是严格意义上的继承
(这里的p对象就继承原型)
2.直接替换原型对象
注意:使用替换原型的方式实现继承的时候,原有原型中的成员就会丢失
3.利用混入的方式给原型对象添加成员