MVC:MVC即model-view-controller(模型-视图-控制器)是项目的一种分层架构思想,它把复杂的业务逻辑,抽离为职能单一的小模块,每个模块看似相互独立,其实又各自有相互依赖关系。它的好处是:保证了模块的智能单一性,方便程序的开发、维护、耦合度低。
mvvm:MVVM:MVVM即Model-View-ViewModel,(模型-视图-控制器)它是一种双向数据绑定的模式,用viewModel来建立起model数据层和view视图层的连接,数据改变会影响视图,视图改变会影响数据
vue.js是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
具体步骤:
第一步:需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上setter和getter这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化
第二步:compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图
第三步:Watcher订阅者是Observer和Compile之间通信的桥梁,主要做的事情是:
1、在自身实例化时往属性订阅器(dep)里面添加自己
2、自身必须有一个update()方法
3、待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退。
第四步:MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化->视图更新;视图交互变化(input)->数据model变更的双向绑定效果。
vue实例从创建到销毁的过程就是生命周期。
也就是从开始创建、初始化数据、编译模板、挂在dom->渲染、更新->渲染、准备销毁、销毁在等一系列过程
另外三个生命周期函数不常用
keep-alive主要用于保留组件状态或避免重新渲染。
activated只有在keep-alive组件激活时调用。
deactivated只有在keep-alive组件停用时调用。
一、创建前/后
在beforeCreate生命周期函数执行的时候,data和method还没有初始化
在created生命周期函数执行的时候,data和method已经初始化完成
二、渲染前/后
在beforeMount生命周期函数执行的时候,已经编译好了模版字符串、但还没有真正渲染到页面中去
在mounted生命周期函数执行的时候,已经渲染完,可以看到页面
三、数据更新前/后
在beforeUpdate生命周期函数执行的时候,已经可以拿到最新的数据,但还没渲染到视图中去。
在updated生命周期函数执行的时候,已经把更新后的数据渲染到视图中去了。
四、销毁前/后
在beforeDestroy生命周期函数执行的时候,实例进入准备销毁的阶段、此时data、methods、指令等还是可用状态
在destroyed生命周期函数执行的时候,实例已经完成销毁、此时data、methods、指令等都不可用
v-if是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建,操作的实际上是dom元素的创建或销毁。
v-show就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于CSS进行切换它操作的是display:none/block属性。
一般来说,v-if有更高的切换开销,而v-show有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用v-show较好;如果在运行时条件很少改变,则使用v-if较好。
asyncawait是es7里面的新语法、它的作用就是async用于申明一个function是异步的,而await用于等待一个异步方法执行完成。它可以很好的替代promise中的then
async函数返回一个Promise对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。
concat()方法用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。
**findIndex()**方法返回数组中满足提供的测试函数的第一个元素的索引。否则返回-1。
**includes()**方法用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回true,否则返回false。
**indexOf()**方法返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-1。(通常用它判断数组中有没有这个元素)
**pop()**方法从数组中删除最后一个元素,并返回该元素的值。此方法更改数组的长度。
**push()**方法将一个或多个元素添加到数组的末尾,并返回该数组的新长度。
**shift()**方法从数组中删除第一个元素,并返回该元素的值。此方法更改数组的长度。
unshift()方法将一个或多个元素添加到数组的开头,并返回该数组的新长度(该方法修改原有数组)。
splice()方法通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组。
由被删除的元素组成的一个数组。如果只删除了一个元素,则返回只包含一个元素的数组。如果没有删除元素,则返回空数组。
**reverse()**方法将数组中元素的位置颠倒,并返回该数组。该方法会改变原数组。
**every()**方法测试一个数组内的所有元素是否都能通过某个指定函数的测试。它返回一个布尔值。
**filter()**方法创建一个新数组,其包含通过所提供函数实现的测试的所有元素。
**forEach()**方法对数组的每个元素执行一次提供的函数。
**some()**方法测试是否至少有一个元素可以通过被提供的函数方法。该方法返回一个Boolean类型的值。
charAt()方法从一个字符串中返回指定的字符。
concat()方法将一个或多个字符串与原字符串连接合并,形成一个新的字符串并返回。
includes()方法用于判断一个字符串是否包含在另一个字符串中,根据情况返回true或false。
match()方法检索返回一个字符串匹配正则表达式的的结果。
原字符串不会改变。
slice()方法提取某个字符串的一部分,并返回一个新的字符串,且不会改动原字符串。
**substr()**方法返回一个字符串中从指定位置开始到指定字符数的字符。
trim()方法会从一个字符串的两端删除空白字符。在这个上下文中的空白字符是所有的空白字符(space,tab,no-breakspace等)以及所有行终止符字符(如LF,CR)。
每一个实例对象上有一个proto属性,指向的构造函数的原型对象,构造函数的原型
对象也是一个对象,也有proto属性,这样一层一层往上找的过程就形成了原型链。
闭包(closure)指有权访问另一个函数作用域中变量的函数。简单理解就是,一个作用
域可以访问另外一个函数内部的局部变量。
functionfn(){varnum=10;functionfun(){console.log(num);}returnfun;}varf=fn();f();作用:延长变量作用域、在函数的外部可以访问函数内部的局部变量,容易造成内层泄露,因为闭包中的局部变量永远不会被回收
一、原型链继承
特点:1、实例可继承的属性有:实例的构造函数的属性,父类构造函数属性,父类原型的属性。(新实例不会继承父类实例的属性!
缺点:1、新实例无法向父类构造函数传参。
2、继承单一。
3、所有新实例都会共享父类实例的属性。(原型上的属性是共享的,一个实例修改了原型属性,另一个实例的原型属性也会被修改!)
二、借用构造函数继承
重点:用.call()和.apply()将父类构造函数引入子类函数(在子类函数中做了父类函数的自执行(复制))
特点:1、只继承了父类构造函数的属性,没有继承父类原型的属性。
2、解决了原型链继承缺点1、2、3。
3、可以继承多个构造函数属性(call多个)。
4、在子实例中可向父实例传参。
缺点:1、只能继承父类构造函数的属性。
2、无法实现构造函数的复用。(每次用每次都要重新调用)
3、每个新实例都有父类构造函数的副本,臃肿。
三、组合继承(组合原型链继承和借用构造函数继承)(常用)
重点:结合了两种模式的优点,传参和复用
特点:1、可以继承父类原型上的属性,可以传参,可复用。
2、每个新实例引入的构造函数属性是私有的。
缺点:调用了两次父类构造函数(耗内存),子类的构造函数会代替原型上的那个父类构造函数。
四、原型式继承
重点:用一个函数包装一个对象,然后返回这个函数的调用,这个函数就变成了个可以随意增添属性的实例或对象。object.create()就是这个原理。
特点:类似于复制一个对象,用函数来包装。
缺点:1、所有实例都会继承原型上的属性。
2、无法实现复用。(新实例属性都是后面添加的)
五、class类实现继承
通过extends和super实现继承
六、寄生式继承
重点:就是给原型式继承外面套了个壳子。
优点:没有创建自定义类型,因为只是套了个壳子返回对象(这个),这个函数顺理成章就成了创建的新对象。
缺点:没用到原型,无法复用。
权限验证:通过token获取用户对应的权限,动态根据用户的权限算出其对应有权限的路由,通过router.addRoutes动态挂载这些路由。
具体思路:
我司现在就是前端来控制页面级的权限,不同权限的用户显示不同的侧边栏和限制其所能进入的页面(也做了少许按钮级别的权限控制),后端则会验证每一个涉及请求的操作,验证其是否有该操作的权限,每一个后台的请求不管是get还是post都会让前端在请求header里面携带用户的token,后端会根据该token来验证用户是否有权限执行该操作。若没有权限则抛出一个对应的状态码,前端检测到该状态码,做出相对应的操作。
使用vuex管理路由表,根据vuex中可访问的路由渲染侧边栏组件。
具体实现:
调用router.addRoutes(store.getters.addRouters)添加用户可访问的路由。
ES6是2015年推出的一个新的版本、这个版本相对于ES5的语法做了很多的优化、例如:新增了let、const
let和const具有块级作用域,不存在变量提升的问题。新增了箭头函数,简化了定义函数的写法,同时可以巧用箭头函数的this、(注意箭头函数本身没有this,它的this取决于外部的环境),新增了promise解决了回调地域的问题,新增了模块化、利用import、export来实现导入、导出。新增了结构赋值,ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。新增了class类的概念,它类似于对象。
页面上的标签都对应具体的虚拟dom对象(虚拟dom就是js对象),循环中,如果没有唯一key,页面上删除一条标签,由于并不知道删除的是那一条!所以要把全部虚拟dom重新渲染,如果知道key为x标签被删除掉,只需要把渲染的dom为x的标签去掉即可!
每个组件都是Vue的实例。组件共享data属性,当data的值是同一个引用类型的值时,改变其中一个会影响其他
利用子绝父相定位的方式来实现
#container{width:500px;height:500px;position:relative;}#center{width:100px;hight:100px;position:absolute;top:50%;left:50%;margin-top:-50px;margin-left:-50px;}利用Css3的transform,可以轻松的在未知元素的高宽的情况下实现元素的垂直居中。
#container{position:relative;}#center{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);}flex
#container{display:flex;justify-content:center;align-items:center;}#center{}18、平时都是用什么实现跨域的?jsonp:利用
JSONP优点是简单兼容性好,可用于解决主流浏览器的跨域数据访问的问题。缺点是仅支持get方法具有局限性,不安全可能会遭受XSS攻击。
服务器接收到请求后,需要进行特殊的处理:把传递进来的函数名和它需要给你的数据拼接成一个字符串,例如:传递进去的函数名是show,它准备好的数据是show('我不爱你')。
CORS:跨域资源共享(CORS)是一种机制;当一个资源访问到另外一个资源(这个资源放在
不同的域名或者不同的协议或者端口),资源就会发起一个跨域的HTTP请求需要浏览器和服务器同时支持;
1、普通函数中的this指向window
2、定时器中的this指向window
3、箭头函数没有this,它的this指向取决于外部环境、
4、事件中的this指向事件的调用者
5、构造函数中this和原型对象中的this,都是指向构造函数new出来实例对象
6、类class中的this指向由constructor构造器new出来的实例对象
7、自调用函数中的this指向window
递归:如果一个函数在内部可以调用其本身,那么这个函数就是递归函数。简单理解:函
数内部自己调用自己,这个函数就是递归函数
优点:结构清晰、可读性强
缺点:效率低、调用栈可能会溢出,其实每一次函数调用会在内存栈中分配空间,而每个进程的栈的容量是有限的,当调用的层次太多时,就会超出栈的容量,从而导致栈溢出。->性能
vue实例最后会挂载在body标签里面,所以我们在vue中是获取不了body标签的,如果要使用body标签的话需要用原生的方式获取
浅拷贝:创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。
深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢并且花销较大。拷贝前后两个对象互不影响。
js是一个单线程、异步、非阻塞I/O模型、eventloop事件循环的执行机制
所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务。异步任务指的是,不进入主线程、而进入"任务队列"(taskqueue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
_.cloneDeep深度拷贝
_.reject根据条件去除某个元素。
_.drop(array,[n=1])作用:将array中的前n个元素去掉,然后返回剩余的部分.
get、post、put、delete等
WebPack是一个模块打包工具,你可以使用WebPack管理你的模块依赖,并编绎输出模块们所需的静态文件。它能够很好地管理、打包Web开发中所用到的HTML、Javascript、CSS以及各种静态文件(图片、字体等),让开发过程更加高效。对于不同类型的资源,webpack有对应的模块加载器。webpack模块打包器会分析模块间的依赖关系,最后生成了优化且合并后的静态资源
babel可以帮助我们转换一些当前浏览器不支持的语法,它会把这些语法转换为低版本的语法以便浏览器识别。
set是es6提供的一种新的数据结构,它类似于数组,但是成员的值都是唯一的。
map是es6提供的一种新的数据结构,它类似于对象,也是键值对的集合,但是键的范围不仅限于字符串,各种类型的值都可以当做键。也就是说,Object结构提供了“字符串—值”的对应,Map结构提供了“值—值”的对应,是一种更完善的Hash结构实现。如果你需要“键值对”的数据结构,Map比Object更合适。
为什么要清除浮动,因为浮动的盒子脱离标准流,如果父盒子没有设置高度的话,下面的盒子就会撑上来。
1.额外标签法(在最后一个浮动标签后,新加一个标签,给其设置clear:both;)(不推荐)
2.父级添加overflow属性(父元素添加overflow:hidden)(不推荐)
3.使用after伪元素清除浮动(推荐使用)
.clearfix:after{/*伪元素是行内元素正常浏览器清除浮动方法*/content:"";display:block;height:0;clear:both;visibility:hidden;}.clearfix{*zoom:1;/*ie6清除浮动的方式*号只有IE6-IE7执行,其他浏览器不执行*/}4.使用before和after双伪元素清除浮动
.clearfix:after,.clearfix:before{content:"";display:table;}.clearfix:after{clear:both;}.clearfix{*zoom:1;}33、常见的布局方法有哪些?他们的优缺点是什么?页面布局常用的方法有浮动、定位、flex、grid网格布局、栅格系统布局
浮动:
绝对定位
flex布局(CSS3中出现的)
网格布局(grid)
利用网格布局实现的一个左右300px中间自适应的布局
优点:可以适用于多端设备
computed计算属性就是为了简化template里面模版字符串的计算复杂度、防止模版太过冗余。它具有缓存特性
除此之外,有点很重要的区别是:计算属性不能执行异步任务,计算属性必须同步执行。也就是说计算属性不能向服务器请求或者执行异步任务。如果遇到异步任务,就交给侦听属性。watch也可以检测computed属性。
父向子传值主要通过的是props属性来传值,props只读
ES6引入新的原始数据类型Symbol,表示独一无二的值
es6中的class可以把它看成是es5中构造函数的语法糖,它简化了构造函数的写法,类的共有属性放到constructor里面
在标准盒子模型中,width和height指的是内容区域的宽度和高度。增加内边距、边框和外边距不会影响内容区域的尺寸,但是会增加元素框的总尺寸。
IE盒子模型中,width和height指的是内容区域+border+padding的宽度和高度。
Promise是异步编程的一种解决方案.简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise是一个对象,可以从改对象获取异步操作的消息。
它可以解决回调地狱的问题,也就是异步深层嵌套问题
/*1.Promise基本使用我们使用new来构建一个PromisePromise的构造函数接收一个参数,是函数,并且传入两个参数:resolve,reject,分别表示异步操作执行成功后的回调函数和异步操作执行失败后的回调函数*/varp=newPromise(function(resolve,reject){//2.这里用于实现异步任务setTimeoutsetTimeout(function(){varflag=false;if(flag){//3.正常情况resolve('hello');}else{//4.异常情况reject('出错了');}},100);});//5Promise实例生成以后,可以用then方法指定resolved状态和reject状态的回调函数//在then方法中,你也可以直接return数据而不是Promise对象,在后面的then中就可以接收到数据了p.then(function(data){console.log(data)},function(info){console.log(info)});###43、vue-cli2.0和3.0有什么区别?
3.0把配置webpack的文件隐藏了,如果需要配置它需要创建一个vue.config.js文件,3.0是2018.10月出来的
箭头函数没有自己的this,this指向定义箭头函数时所处的外部执行环境的this
即时调用call/apply/bind也无法改变箭头函数的this
箭头函数本身没有名字
箭头函数不能new,会报错
箭头函数没有arguments,在箭头函数内访问这个变量访问的是外部执行环境的arguments
箭头函数没有prototype
点击事件300MS延迟问题解决方案:下载fastclick的包
H5页面窗口自动调整到设备宽度,并禁止用户缩放页面
POST:一般用于修改服务器上的资源,对所发送的信息没有限制。
GET方式需要使用Request.QueryString来取得变量的值,而POST方式通过Request.Form来获取变量的值,也就是说Get是通过地址栏来传值,而Post是通过提交表单来传值。
然而,在以下情况中,请使用POST请求:
无法使用缓存文件(更新服务器上的文件或数据库)
向服务器发送大量数据(POST没有数据量限制)
发送包含未知字符的用户输入时,POST比GET更稳定也更可靠
所谓同源策略是浏览器的一种安全机制,来限制不同源的网站不能通信。同源就是域名、协议、端口一致。
1xx表示HTTP请求已经接受,继续处理请求2xx表示HTTP请求已经处理完成(200)3xx表示把请求访问的URL重定向到其他目录(304资源没有发生变化,会重定向到本地资源)4xx表示客户端出现错误(403禁止访问、404资源不存在)5xx表示服务端出现错误
BFC(块级格式化上下文),一个创建了新的BFC的盒子是独立布局的,盒子内元素的布局不会影响盒子外面的元素。在同一个BFC中的两个相邻的盒子在垂直方向发生margin重叠的问题。
BFC是值浏览器中创建了一个独立的渲染区域,该区域内所有元素的布局不会影响到区域外元素的布局,这个渲染区域只对块级元素起作用
js的数据类型分为基本数据类型(string、number、boolean、null、undefined、symbol)和复杂数据类型
基本数据类型的特点:直接存储在栈中的数据
复杂数据类型的特点:存储的是该对象在栈中引用,真实的数据存放在堆内存里
01.浏览器查找域名对应的IP地址(DNS查询:浏览器缓存->系统缓存->路由器缓存->ISPDNS缓存->根域名服务器)
02.浏览器向Web服务器发送一个HTTP请求(TCP三次握手)
04.浏览器跟踪重定向地址,请求另一个带www的网址
05.服务器处理请求(通过路由读取资源)
06.服务器返回一个HTTP响应(报头中把Content-type设置为'text/html')
07.浏览器进DOM树构建
08.浏览器发送请求获取嵌在HTML中的资源(如图片、音频、视频、CSS、JS等)
09.浏览器显示完成页面
10.浏览器发送异步请求
CSRF(Cross-siterequestforgery):跨站请求伪造。
方法一、Token验证:(用的最多)
方法二:隐藏令牌:
方法二和方法一有点像,本质上没有太大区别,只是使用方式上有区别。
方法三、Referer验证:
XSS(CrossSiteScripting)``:跨域脚本攻击。
1.编码:
对用户输入的数据进行HTMLEntity编码。
如上图所示,把字符转换成转义字符。
Encode的作用是将$var`等一些字符进行转化,使得浏览器在最终输出结果上是一样的。
比如说这段代码:
2、过滤:
3、校正
备注:我们应该去了解一下DOMParse这个概念,它的作用是把文本解析成DOM结构。
比较常用的做法是,通过第一步的编码转成文本,然后第三步转成DOM对象,然后经过第二步的过滤。
区别一:
区别二:(原理的区别)
共同点:都可以改变this指向;不同点:call和apply会调用函数,并且改变函数内部this指向.call和apply传递的参数不一样,call传递参数使用逗号隔开,apply使用数组传递bind不会调用函数,可以改变函数内部this指向.应用场景