js的事件循环机制:
JS是单线程的,也就是说它只有一个主线程,主线程执行完执行栈的任务后去检查异步的任务队列,如果异步事件触发,就将其加到主线程的执行栈。 主线程从"任务队列"中读取事件,不断循环的过程,就形成了Event Loop(事件循环)
首先是调用栈,执行耗时较短的操作,耗时较长的操作先放置到任务队列中,任务队列又分为宏任务(macro-task)和微任务(micro-task),微任务中队列中放置的是 promise.then、aysnc、await 这样操作,宏任务队列中放置的是 setTimeout、ajax、onClick事件,等调用栈的任务执行完成再轮询微任务队列,微任务队列中任务执行完成之后再执行宏任务。 不阻塞主进程的程序放入调用栈中,压入栈底,执行完了就会弹出,如果是函数,那么执行完函数里所有的内容才会弹出,而阻塞主进程的程序放入任务队列中,他们需要“排队”依次执行。
闭包
定义:一个函数有权访问另一个函数作用域中的变量。
理解:在一个函数内声明了变量a,同时还创建了一个内部函数,然后通过内部函数访问外部函数的局部变量a,最后执行外部函数,这一整个过程就是一个闭包的应用。
产生条件:函数嵌套,内部函数引用了外部函数的变量,执行外部函数。
用途:隐藏局部变量;延长局部变量的生命周期;让外部函数可以访问到内部函数的局部变量
闭包在内部函数定义时产生(而不是调用的时候产生的),在嵌套的内部函数成为垃圾对象时死亡。
包含闭包的函数对象设为null
缺点:1)常驻内存,增大内存使用量2)使用不当会造成内存泄漏
解决:及时释放内存,将引用内层函数对象的变量赋值为null
闭包的应用:
1)使用for循环给页面中的多个dom节点添加事件时(也可以用let代替)
2)防抖节流
3)柯里化函数**
【是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回一個新函数,用来接受余下的参数】
防抖节流
防抖: 对于短时间内连续触发的事件(上面的滚动事件),防抖让事件处理函数某个时间期限内只执行一次,只需要判断最后一次的变化情况。
- 如果在某个时间内没有再次触发滚动事件,那么就执行函数
- 如果在某个时间内再次触发滚动事件,那么当前的计时取消,重新开始计时
实现:既然前面都提到了计时,那实现的关键就在于setTimeout这个函数,由于还需要一个变量来保存计时,考虑维护全局纯净,可以借助闭包来实现
节流:
短时间内大量触发同一事件,那么在函数执行一次之后,该函数在指定的时间期限内不再工作,直至过了这段时间才重新生效**
原型和原型链
原型:分为隐式原型和显式原型。 每个构造函数创建的时候都有一个prototype属性,指向另一个对象,也就是他的原型对象。这个原型对象中的所有属性和方法都会被构造函数的实例所继承。
隐式原型:构成原型链,实现基于原型的继承。
显式原型:每个函数创建后都默认拥有一个显式原型,用来实现基于原型的继承和属性的共享。
1.每个对象都具有一个__proto__属性;
2.每个构造函数都有一个prototype属性,指向他的原型对象prototype
3.每个实例对象的__proto__属性指向自身构造函数的prototype原型对象;
原型链:当访问一个对象的某一个属性时候,会在他自身上面找,找不到,再去他的隐式原型上查找,还没有找到,就会在构造函数的prototype的隐式原型上找,沿着隐式原型链,直到Object.prototype.__proto__为null时停止。
ES5的继承
原型链继承-> 将子类的原型对象指向父类的实例(不能直接实现多继承) Son.prototype = new Father() 利用对象的形式修改了原型对象之后、一定要利用constructor指到原来的构造对象 Son.prototype.constructor =Son
借用构造函数继承-> call方法改变this指向,也就是函数上下文实现继承(不能继承原型链) Father.call(this,name,age)
组合继承-> 传参和复用
跨域
1)jsonp 利用script的src属性,前端定义一个回调函数,并将其拼接在src中的get请求后面,发送给服务端,服务端将对应的数据通过这个回调函数的参数返回给前端,前端执行这个回调函数就可以解决跨域问题,成功获取数据。
2)CORS
跨域资源共享,可以让AJAX实现跨域访问;CORS允许一个域上的网络应用向另一个域提交跨域AJAX请求。
服务器设置Access-Control-Allow-Origin HTTP响应头之后,浏览器将会允许跨域请求.
就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功,还是应该失败。
3)nginx正向代理隐藏了客户端 nginx反向代理接口跨域隐藏了服务端
同源策略仅是针对浏览器的安全策略。服务器端调用HTTP接口只是使用HTTP协议,不需要同源策略,也就不存在跨域问题。 实现思路:通过Nginx配置一个代理服务器域名与domain1相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域访问。
vue-router路由模式,hash和histroy区别
vue路由配置里的mode选项来配置hash和histroy,并且vue默认就是hash模式
hash模式下,url后面会自带一个#,它的原理主要是利用onhashchange事件,监听hash变化,比如点击浏览器的前几后退就会触发
另外,hash虽然出现在url里面,但是它并不会被包括在HTTP请求中,对后端完全没有影响,也就是说,改变hash不会重新加载页面
histroy的话,可以随便修改path,但是如果服务器中没有相应的响应和资源,就会报404
所以需要和后端配合去配置一下apache或者是nginx的url重定向,重定向到首页路由就可以。
keep-alive用过吗,使用场景,项目中使用过吗?
实现组件缓存,当组件切换时候、不会对当前组件进行卸载。
常用属性include/exclude 允许组件有条件的进行缓存
生命周期activited,deactived永安里得知当前组件是否处于活跃状态
使用场景:前进刷新,后退缓存用户浏览数据 商品列表页面 =>点击进入详情页=> 后退到列表页 要缓存列表原来数据 重新进入列表页面 => 获取最新的数据
nextTick?
nextTick(),是将回调函数延迟在下一次dom更新数据后调用,
简单的理解是:当数据更新并在dom中渲染后,自动执行这个函数
适用场景:
1.更改数据后当你想立即使用js操作新的视图的时候需要使用它
2.在使用某个第三方插件时 ,希望在vue生成的某些dom动态发生变化时重新应用该插件,也会用到该方法,这时候就需要在 $nextTick 的回调函数中执行重新应用插件的方法
3.created操作必须放在nextTick里面
methods和computed的区别
写法不同:计算属性以对象的方式创建,以属性的方式去调用
而methods方法必须采用 方法() 调用的形式 计算属性computed支持依赖自动缓存,当依赖不变的时候,computed的值不会重新计算。 methods不论data变化与否都会重新调用
使用场景:methods一般就用于定义普通函数,computed是如果你数据改变的时候要做一些计算就用它,computed是在dom加载后马上执行的,比如赋值。而methods中的函数,则必须要有一定的触发条件,比如点击。
computed和watch区别
watch用于对于变量的监听 computed用于对data变量的计算再输出 每次值发生改变,watch就会监听,computed计算属性也会重新计算
一个监听属性只能监听一个属性的变化,如果要同时监听多个,就要写多个监听属性,而计算属性可以同时监听多个数据的变化。
watch
watch 对data 的数据监听回调,当依赖的 data 的数据变化,就会执行回调,在回调中会传入 newVal 和 oldVal两个参数。Vue 实例将会在实例化时调用 $watch(),遍历 watch 对象的每一个属性。
watch的使用场景是: 当在data中的某个数据发生变化时, 我们需要做一些操作, 或者当需要在数据变化时执行异步或开销较大的操作时. 我们就可以使用watch来进行监听。
computed
computed看上去是方法,但是实际上是计算属性,它会根据你所依赖的数据动态显示新的计算结果。计算属性computed支持依赖自动缓存,当依赖不变的时候,computed的值不会重新计算,减少模板中的计算逻辑。
使用场景:
当页面中有某些数据依赖其他数据进行变动的时候,可以使用计算属性
数据变化时执行异步或开销较大的操作,随时修改状态的变化,可以使用watch
promise、generator,async
Promise
Promise有三种状态:pending(进行中)、resolved(成功)、rejected(失败)
Promise对象的缺点:
- 无法取消Promise,一旦新建它就会立即执行,无法中途取消。
- 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
- 当处于Pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
- Promise 真正执行回调的时候,定义 Promise 那部分实际上已经走完了,所以 Promise 的报错堆栈上下文不太友好。
Generator
Generator 是ES6引入的新语法,Generator是一个可以暂停和继续执行的函数。
简单的用法,可以当做一个Iterator来用,进行一些遍历操作。复杂一些的用法,他可以在内部保存一些状态,成为一个状态机。
Generator 基本语法包含两部分:函数名前要加一个星号;函数内部用 yield 关键字返回值。
- yield,表达式本身没有返回值,或者说总是返回undefined。
- next,方法可以带一个参数,该参数就会被当作上一个yield表达式的返回值。
Async
Async 是 Generator 的一个语法糖。
async 对应的是 * 。
await 对应的是 yield 。
async/await 自动进行了 Generator 的流程控制。
- 注意:若明确是当前函数内部需要异步转同步执行,再使用async。原因:babel会识别并将async编译成promise,造成编译后代码量增加。
为什么Async/Await更好?
- 使用async函数可以让代码简洁很多,不需要像Promise一样需要些then,不需要写匿名函数处理Promise的resolve值,也不需要定义多余的data变量,还避免了嵌套代码。
- 错误处理:Async/Await 让 try/catch 可以同时处理同步和异步错误。
JSON
Json是一种轻量级的数据交换格式。通俗的说,在我们许多项目中,前后端之间的数据通信格式就是Json。 后端在取到数据对数据进行加工之后,将此数据序列化转为Json格式,然后将此Json格式的数据返回给前端,前端拿到Json之后会进行反序列化,也就是将Json文件转为原来的数据。然后经过一系列操作渲染到页面上。
Set和Map
Set:
- 成员唯一、无序且不重复。
- [value, value],键值与键名是一致的(或者说只有键值,没有键名)。
- 可以遍历,方法有:add、delete、has。
Map:
- 本质上是键值对的集合,类似集合。
- 可以遍历,方法很多可以跟各种数据格式转换。
5.判断数组的方法,
instanceof 操作符判断
用法:arr instanceof Array
对象构造函数的 constructor判断
用法:arr.constructor === Array Object的每个实例都有构造函数 constructor,用于保存着用于创建当前对象的函数
Array.isArray
Object.getPrototypeOf
用法:Object.getPrototypeOf(arr) === Array.prototype
6.数组的常用方法
| 方法名 | 对应版本 | 功能 | 原数组是否改变 |
|---|---|---|---|
| pop() | ES5- | 删除最后一位,并返回删除的数据 | y |
| shift() | ES5- | 删除第一位,并返回删除的数据 | y |
| unshift() | ES5- | 在第一位新增一或多个数据,返回长度 | y |
| push() | ES5- | 在最后一位新增一或多个数据,返回长度 | y |
| reverse() | ES5- | 反转数组,返回结果 | y |
| sort() | ES5- | 排序(字符规则),返回结果 | y |
| splice() | ES5- | 删除指定位置,并替换,返回删除的数据 | y |
| valueOf() | ES5- | 返回数组对象的原始值 | n |
| indexOf() | ES5 | 查询并返回数据的索引 | n |
| lastIndexOf() | ES5 | 反向查询并返回数据的索引 | n |
| forEach() | ES5 | 参数为回调函数,会遍历数组所有的项,回调函数接受三个参数,分别为value,index,self;没有返回值 | n |
| map() | ES5 | 同forEach,同时回调函数返回数据,组成新数组由map返回 | n |
| filter() | ES5 | 同forEach,同时回调函数返回布尔值,为true的数据组成新数组由filter返回 | n |
| every() | ES5 | 同forEach,同时回调函数返回布尔值,全部为true,由every返回true | n |
| some() | ES5 | 同forEach,同时回调函数返回布尔值,只要由一个为true,由some返回true | n |
| reduce() | ES5 | 归并,同forEach,迭代数组的所有项,并构建一个最终值,由reduce返回 | n |
| reduceRight() | ES5 | 反向归并,同forEach,迭代数组的所有项,并构建一个最终值,由reduceRight返回 | n |
| concat() | ES5- | 合并数组,并返回合并之后的数据 | n |
| join() | ES5- | 使用分隔符,将数组转为字符串并返回 | n |
| slice() | ES5- | 截取指定位置的数组,并返回 | n |
| toString() | ES5- | 直接转为字符串,并返回 | n |
es6新增的数组方法
静态方法:
Array.from()将类数组对象或者是可遍历对象转化为数组 Array.of()将一组值转化为数组
实例方法: copyWithin() Array.prototype.copyWithin(target, start , end )
从 satrt索引位置直到数组end的成员,复制到从target 位开始的位置,并且覆盖原来位置的数值。
find() 和 findIndex()
用于找出第一个符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。如果没有符合条件的成员,则返回undefined
返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1。
fill()
fill方法填充数组,用于将参数一填充到第二个参数起始位置和结束位置之前。
['a', 'b', 'c'].fill(7, 1, 2)
// ['a', 7, 'c']
上面代码表示,`fill`方法从 1 号位开始,向原数组填充 7,到 2 号位之前结束。
entries(),keys() 和 values() includes() Array.prototype.includes方法返回一个布尔值,表示某个数组是否包含给定的值 flat(),flatMap()
Array.prototype.flat()用于将嵌套的数组“拉平”,变成一维的数组。默认参数为1,拉平一层,拉平几层参数就为几,如果不管有多少层嵌套,都要转成一维数组,可以用Infinity关键字作为参数。
flatMap()方法对原数组的每个成员执行一个函数(相当于执行Array.prototype.map()),然后对返回值组成的数组执行flat()方法。
7.深浅拷贝区别和实现方法
浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。
深拷贝会另外创造一个一模一样的对象,新对象跟元对象不共享内存,修改新对象不会改变原对象。
如何实现深拷贝?
JSON.parse(JSON.stringify(obj))
以递归方式使用for in 方法来实现深拷贝
第三方库lodash的_.cloneDeep方法
如何实现浅拷贝
通过Object.assign( ) 简单实现
.通过 for in方法
通过 扩展运算符 ... 方法
vue事件修饰符
(1).stop // 阻止事件继续传播 即阻止它的捕获和冒泡过程
(2).prevent //阻止默认事件发生 即event.preventdefault():
(3)capture // 添加事件监听器时使用事件捕获模式,即在捕获模式下触发
(4).self //当前元素自身时触发处理函数时才会触发函数
(5).once //只触发一次
h5新特性:
语义标签 header footer nav section article main ;增强型表单 input输入特性 color,date,email tel ;视频和音频 audio video ;Canvas绘图;SVG绘图;地理定位 getCurrentPosition()方法来获取用户的位置。以实现“LBS服务”;拖放API;WebWorker;WebStorage;WebSocket
对js的理解
弱类型的脚本语言;前端后台语言;解释型语言,不需要编译,直接由浏览器或者nodejs提供的js解释器去解析;从上往下顺序执行。
主要由ECMAScript,dom和bom三部分组成
EACMAScript就是一些基本语法和对象,dom文档对象模型,浏览器提供给js操作html的api,Bom浏览器对象模型,浏览器提供给js操作浏览器的api。
WebWorker &&js单线程
WebWorker允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。
why单线程?
作为浏览器脚本语言,JavaScript的主要做交互,以及操作DOM。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器就不知道应该以哪个线程为准。
WebStorage:sessionStorage 和localStorage
Web Storage分为两种: sessionStorage 和localStorage
sessionStorage将数据保存在session中,浏览器关闭也就没了;而localStorage则一直将数据保存在客户端本地。
sessionstorage和localStorage有用过吗?哪些数据可以存在localStorage?为什么用sessionStorage来存token
应用场景:
sessionStorage应用场景关闭浏览器用户信息要清掉
localStorage应用场景 适合长期保存在本地的数据 可以用于存储该浏览器对该页面的访问次数
sessionStorage、localStorage在多标签页面里面能够共享吗?
通过点击链接(或者用了 window.open)打开的新标签页之间是属于同一个 session 的,但新开一个标签页总是会初始化一个新的 session,即使网站是一样的,它们也不属于同一个 session。
cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递。
sessionStorage和localStorage不与服务器通信,不会自动把数据发给服务器,仅在本地保存。
数据大小不同
(cookie数据还有路径(path)的概念,可以限制cookie只属于某个路径下。)
存储大小限制也不同,cookie数据不能超过4k,同时因为每次http请求都会携带cookie,所以cookie只适合保存很小的数据,如会话标识。
sessionStorage和localStorage 虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大。
③数据有效期不同
sessionStorage:仅在当前浏览器窗口关闭前有效,不能持久保持;
localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;
cookie只在设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭。
④作用域不同
sessionStorage不在不同的浏览器窗口中共享,即使是同一个页面;
localStorage在所有同源窗口中都是共享的;
cookie也是在所有同源窗口中都是共享的。
WebSocket、应用场景
H5出的新协议 浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输
特点:
(1)握手阶段采用HTTP协议,默认端口是80和443
(2)建立在TCP协议基础之上,和http协议同属于应用层
应用场景:比如多媒体聊天,投票页面,不刷新就可以查看到投票情况
- 提供多个用户相互交流
- 展示服务器端经常变动的数据
websocket和轮询的区别
轮询:
特点:每隔一段时间不断向后端发送请求 缺点:消耗大 有延迟
1.js数据类型
5(+2)+3
基本数据类型(5)string number boolean null undefined
es6新增 symbol 本质上是一种唯一标识符,可用作对象的唯一属性名,这样其他人就不会改写或覆盖你设置的属性值
BigInt可以表示任意大的整数解决一些超出最大最小值范围的一些数失去精度的问题
引用数据类型(3)
object array function
2.null和undefined区别
null是空对象,undefined是未定义
undefined一般用于基本数据类型的声明但未定义;null一般用于引用数据类型,表示空对象
undefined不是关键字,而null是关键字一个变量可以声明为undefined,但不可以是null
还有特殊的一点,typeof(null)是Object
==和===
相等 和全等 ==会进行一个自动类型提升
3.解释0.1+0.2 !=0.3
主要是浮点数精度不够导致的
计算机只认识二进制,所以进行计算的时候、需要将0.1和0.2去转化为二进制的形式,但是浮点数用二进制表示的话,他们又是一个无穷小数,所以先把他们加起来之后,需要按照浮点数小数位的限制去做一个截断,最后转换为十进制,整个过程就会产生误差,导致0.1+0.2 !=0.3
如果想让他们相等有两种方式:
1) 去除浮点数再比较,toFixed四舍五入;
2)对比小数相等,两数相减绝对值<Number.EPSILON(极小常量)则相等
内存泄漏和内存溢出
内存溢出:
一种程序运行出现的错误
当程序运行需要的内存超过了剩余的内存时、会抛出内存溢出的错误
内存泄漏:
占用的内存没有及时释放(程序是可运行的)
内存泄漏积累多了就容易导致内存溢出
常见的内存泄漏:
- 意外的全局变量
- 没有及时清理的计时器或者回调函数
- 闭包
css部分
opacity、display、visiblity区别
1 opacity=0,不透明度 该元素隐藏起来了,但不会改变页面布局,并且,如果该元素已经绑定一些事件,如click事件,那么点击该区域,也能触发点击事件的 2 visibility=hidden,可见度 该元素隐藏起来了,但不会改变页面布局,但是不会触发该元素已经绑定的事件 3 display=none, 把元素隐藏起来,并且会改变页面布局,可以理解成在页面中把该元素删除掉一样
盒模型
使用box-sizing来设置
分类:内容盒子和边框盒子
content-box w3c标准盒子 宽度为内容宽度
盒子总宽度 = margin + border + padding + width border-box
ie盒子 宽度为内容宽度+padding+border宽度
盒子总宽度 = width +margin
行内元素和块级元素
行内元素:不独占一行,宽高由内容决定,默认不可以设置宽高
跨级元素:独占一行,高度由内容决定,宽度是父元素得100%,可以设置宽高
title和alt
title是提示信息,alt是在加载失败时、代替显示的信息
css文字属性
font-weight,font-style,font-size,color,font-family
css文本属性
text-decoration,text-align,text-transfrom:uppercase,lowercase,capitalize;(首字母大写)
text-indent首行缩进,text-shadow
文字光影/光圈怎么实现
text-shadow: h-shadow v-shadow blur color;
伪类和伪元素
伪类用于定义元素的特殊状态。
例如,它可以用于:
- 设置鼠标悬停在元素上时的样式
- 为已访问和未访问链接设置不同的样式
- 设置元素获得焦点时的样式
伪元素用于设置元素指定部分的样式。
例如,它可用于:
- 设置元素的首字母、首行的样式
- 在元素的内容之前或之后插入内容
css动画效果
使用@keyframes 定义动画,关键帧可以使用关键字from~to,也可以使用0%~100%
配置动画 animation-name 动画的名字 @keyframes定义的动画的名字 animation-duration 动画持续的时间 单位 s、ms,默认为0s animation-iteration-count 动画迭代次数 数字、infinite(无限循环) animation-delay 动画延迟执行时间 animation-direction 动画方向 animation-timing-function 动画的速度曲线
说一下css行内、内联、外联样式表的区别,你用的是什么?为什么要用外部样式表?
外联CSS是一个单独的文件,可以作用于多个页面,在修改的时候可以针对性地修改某一块区域,达到多个页面样式同时变更,相较于内联CSS和页级CSS,可维护性好,省去了到每个页面修改的步骤,提高了开发效率,同时一定程度提高了性能。
浏览器渲染流程。为什么js文件放到css文件的后面?
加载js文件会停止对dom的创建,而且js加载完会立即执行,同时会阻塞后面资源的加载
浏览器渲染流程:
浏览器将获取的HTML文档解析成DOM树。
处理CSS标记,构成层叠样式表模型CSSOM(CSS Object Model)。
将DOM和CSSOM合并为渲染树(rendering tree),代表一系列将被渲染的对象。
渲染树的每个元素包含的内容都是计算过的,它被称之为布局layout。浏览器使用一种流式处理的方法,只需要一次绘制操作就可以布局所有的元素。
将渲染树的各个节点绘制到屏幕上,这一步被称为绘制。
3.CSS样式继承
我们设置上级(父级)的CSS样式,上级(父级)及以下的子级(下级)都具有此属性。 一般只有文字文本具有继承特性,如文字大小、文字加粗、文字颜色、字体等。
3.css3新特性
过渡transition,和hover、下拉菜单配合使用,过渡动画,不会生硬。
动画 animation
文字 文字阴影text-shadow 超出之后显示省略号 (禁止换行,wdite-space:nowrap;超出隐藏:overflow:hidden;超出以后省略号:text-overflow)
选择器 nth-child(n) frist-child
选择器:
优先级
!Important>行内样式>ID选择器>类选择器>元素>通配符>继承>浏览器默认属性
核心选择器 标签选择器 id选择器 类选择器 普遍选择器
层次选择器 后代选择器 子代选择器 相邻同胞选择器 一般同胞选择器
多选择器 1)逗号选择器 2)组合选择器
属性选择器
伪类选择器
伪元素选择器
1垂直居中水平居中
已知居中元素的宽高
子绝父相+ top:50%;+margin-top:-50px;
未知居中元素的宽高 子绝父相+top: 50%;transform: translateY(-50%);
父元素display: table-cell+vertical-align: middle;
知不知道宽高均可以用flex:
利用flex
/*垂直居中 项目在主轴上的对齐方式 */
justify-content: center;
/* 水平居中 项目在交叉轴上的对齐方式*/ align-items: center;
flex
任何一个容器都可以指定为flex布局,包括行内元素,他的子元素被称为项目
容器属性:flex-direction flex-wrap flex-flow justify-content align-items align-content
项目属性:order flex-grow flex-shrink flex-basis flex align-self
说一下对css的理解、css的编程规范
CSS(Cascading Style Sheet,层叠样式表)
利用CSS继承减少代码量
利用外联样式引入,可以复用并且容易修改
提取重复样式
响应式布局和css的哪个属性相关
vw/vh
rem单位无论嵌套层级如何,都只相对于浏览器的根元素(HTML元素)的font-size
@media媒体查询
两栏布局 左边固定 右边灵活 用flex 实现 不用flex实现
flex
父盒子设为display:flex,左边盒子固定宽度,右边盒子flex:1 填充满剩余空间
左边float: left+ 右边margin-left float使左边的元素脱离文档流,右边的元素可以和左边的元素显示在同一行,设置margin-left让右边的元素不覆盖掉左边的元素
Vue
v-model原理?
双向数据绑定,主要是使用数据劫持和发布者-订阅者模式来做的,利用Object.define.property去劫持各个属性的setter、getter,然后当数据发生变化发送消息给订阅者,触发响应的监听回调。
组件中的data为什么是个函数?
因为对象是一个引用数据类型,如果data是一个对象的情况下会造成所有组件共用一个data。而当data是一个函数的情况下,每次函数执行完毕后都会返回一个新的对象,这样的话每个组件都会维护一份独立的对象(data)
为什么data必须return?
组件是一个可复用的实例,当你引用一个组件的时候,组件里的data是一个普通的对象,所有用到这个组件的都引用的同一个data,就会造成数据污染。
将data封装成函数后,在实例化组件的时候,我们只是调用了data函数生成的数据副本,避免了数据污染。
v-show和v-if对比
1.共同点
条件渲染,都是动态显示DOM元素
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适合频繁切换。
如果v-show作用的元素,css文件中display:none,通过v-show进行设置不能显示该元素;
父组件调用子组件的方法:
refs调用
在子组件中添加ref,然后再通过this.$refs去调用
父组件调用子组件方法这一操作放到那个生命周期合适?父组件调用子组件方法放到那拿不到?
必须要在从mounted开始拿,才能拿得到里面的Dom元素
但是会存在拿不到、显示undefined的情况,如果在updated拿是100%会拿到的
$refs定位不到的主要原因是因为v-if、v-for、v-show这些语句如果依赖父组件传来的参数的话,该该参数是在mounted()阶段子还没获取得到~~~~!!!!
如果想要真正地在DOM加载完成后拿到数据,就需要调用VUE的全局api : this.$nextTick(() => {})
如果说mounted阶段是加载阶段,那么updated阶段则是完成了数据更新到DOM的阶段(对加载回来的数据进行处理),此时,ref、数据等等全部都挂载到DOM结构上去,在update阶段使用this.$refs.xxx,就100%能找到该DOM节点。
updated与mounted不同的是,在每一次的DOM结构更新,vue都会调用一次updated(){}钩子函数!,而mounted仅仅只执行一次而已
简单来说,只要在调试的时候,能看到元素的存在,在updated阶段都可以使用this.$refs.xxx找到对应的DOM节点!
vue中组件传参
(1)、用法上的
刚query要用path来引入,params要用name来引入,接收参数都是类似的,分别是this.route.params.name。
注意接收参数的时候,已经是router
(2)、展示上的
query更加类似于我们ajax中get传参,params则类似于post,说的再简单一点,query在浏览器地址栏中显示参数,params则不显示
(3)、params是路由的一部分,必须要有。query是拼接在url后面的参数,没有也没关系。
params一旦设置在路由,params就是路由的一部分,如果这个路由有params传参,但是在跳转的时候没有传这个参数,会导致跳转失败或者页面会没有内容。
(4)、params、query不设置也可以传参,params不设置的时候,刷新页面或者返回参数会丢失,这一点的在上面说过了
vue组件通信
props和$emit
-
父传子:父组件传递msg数据给子组件,通过v-bind绑定msg,子组件中直接可以用props接收绑定的数据
-
子传父:子组件触发相应的事件,通过on监听对应的事件 接收子组件传递的数据
EventBus-中央事件总线
EventBus通过新建一个Vue事件bus对象,通过bus.$emit触发事件,bus.$on监听触发的事件。
listeners
provide和inject
在父组件中通过 provider 来提供属性,然后在子组件中通过 inject 来注入变量。不论子组件有多深,只要调用了 inject 那么就可以注入在 provider 中提供的数据,而不是局限于只能从当前父组件的 prop 属性来获取数据,只要在父组件的生命周期内,子组件都可以调用。
children
$parent 就是父组件的实例对象,而 $children 就是当前实例的直接子组件实例
vuex
当组件进行数据修改的时候我们需要调用dispatch来触发actions里面的方法。actions里面的每个方法中都会有一个commit方法,当方法执行的时候会通过commit来触发mutations里面的方法进行数据的修改。mutations里面的每个函数都会有一个state参数,这样就可以在mutations里面进行state的数据修改,当数据修改完毕后,会传导给页面。页面的数据也会发生改变
五大属性
state => 基本数据 getters => 从基本数据派生的数据 mutations => 提交更改数据的方法,同步! actions => 像一个装饰器,包裹mutations,使之可以异步。 modules => 模块化Vuex
vue生命周期
创建期间的生命周期函数:
beforeCreate:实例刚在内存中被创建出来,此时,还没有初始化好 data 和 methods 属性
-
created:实例已经在内存中创建OK,此时 data 和 methods 已经创建OK,此时还没有开始 编译模板 beforeMount:此时已经完成了模板的编译,但是还没有挂载到页面中
- mounted:此时,已经将编译好的模板,挂载到了页面指定的容器中显示
-
运行期间的生命周期函数:
- beforeUpdate:状态更新之前执行此函数, 此时 data 中的状态值是最新的,但是界面上显示的 数据还是旧的,因为此时还没有开始重新渲染DOM节点
- updated:实例更新完毕之后调用此函数,此时 data 中的状态值 和 界面上显示的数据,都已经完成了更新,界面已经被重新渲染好了!
-
销毁期间的生命周期函数:
- beforeDestroy:实例销毁之前调用。在这一步,实例仍然完全可用。
- destroyed:Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。
vue中key的作用
需要使用key来给每个节点做一个唯一标识,通过对比新旧节点的key来判断节点是否改变,用key就可以大大提高渲染效率。
http
状态码:
1xx:指示信息--表示请求已接收,继续处理。 2xx:成功--表示请求已被成功接收、理解、接受。 3xx:重定向--要完成请求必须进行更进一步的操作。 4xx:客户端错误--请求有语法错误或请求无法实现。 5xx:服务器端错误--服务器未能实现合法的请求。
2开头的表示成功 一般见到的就是200 3开头的表示重定向 301永久重定向 302临时重定向 304表示可以在缓存中取数据(协商缓存) 4开头表示客户端错误 403跨域 404请求资源不存在 5开头表示服务端错误 500
http缓存方式
http缓存指的是: 当客户端向服务器请求资源时,会先抵达浏览器缓存,如果浏览器有“要请求资源”的副本,就可以直接从浏览器缓存中提取而不是从原始服务器中提取这个资源。
- 浏览器在请求某一资源时,会先获取该资源缓存的header信息,判断是否命中强缓存,若命中直接从缓存中获取资源信息,包括缓存header信息;本次请求根本就不会与服务器进行通信
- 如果没有命中强缓存,浏览器会发送请求到服务器,请求会携带第一次请求返回的有关缓存的header字段信息,由服务器根据请求中的相关header信息来比对结果是否协商缓存命中 ;若命中协商缓存,则服务器返回新的响应header信息更新缓存中的对应header信息,但是并不返回资源内容,它会告知浏览器可以直接从缓存获取;否则就把返回最新的资源内容
| ** 获取资源形式** | 状态码 | 发送请求到服务器 | |
|---|---|---|---|
| 强缓存 | 从缓存取 | 200(from cache) | 否,直接从缓存取 |
| 协商缓存 | 从缓存取 | 304(not modified) | 是,正如其名,通过服务器来告知缓存是否可用 |
http请求过程
1.域名解析
浏览器首先从URL中解析出域名,然后根据域名查询DNS,获取到域名对应的IP地址。
2.发起TCP的3次握手
浏览器用这个IP地址与服务器建立TCP连接,如果用的是HTTPS,还有完成TLS / SSL的握手。
3.建立TCP连接后发起http请求
在建立好连接以后呢,构造HTTP请求,在构造请求的过程中,要填充少量至HTTP头部
4.服务器响应http请求,浏览器得到html代码
然后通过这个TCP连接发起HTTP请求,当服务器收到这个HTTP请求以后,返回给浏览器以HTTP页面作为包体的HTTP响应。
5.浏览器解析html代码,并请求html代码中的资源(如js、css、图片等)
浏览器渲染引擎解析响应,根据此响应中其他的超链接(js / css / img)等资源再次发起HTTP请求。
6.浏览器对页面进行渲染呈现给用户
建立tcp过程,三次握手
过程:
一、域名解析 一般我们访问的url都是域名,例如:www.baidu.com,需要将其解析为服务器IP才能进行访问。搜索浏览器自身的DNS缓存;搜索操作系统自身的DNS缓存;读取hosts文件;如果以上都没有查找到要访问的url,就向DNS服务器发起一个DNS解析请求; 二、建立连接:TCP三次握手建立连接。
三、发起HTTP请求 四、服务器响应请求返回结果 五、浏览器得到HTML标签 六、浏览器解析HTML中的js/css等资源 七、浏览器对页面进行渲染 八、断开连接 四次挥手断开连接。
why3次握手?
客户端向服务器发送请求报文(sequence),告诉服务器,想要建立连接;** 服务器听到连接请求报文后,如果同意建立连接,则向客户端发送确认(发送确认acknowledge和sequence); 客户端接收到之后,发送确认(向服务器发送确认acknowledge); 此时,客户端与服务器确认可以互相传送消息。**
三次是保证双方互相明确对方能收能发的最低值。当客户端收到连接同意的应答后,还要向服务端发送一个确认报文段,表示服务端发来的连接同意应答已经成功收到。
为什么连接建立需要三次握手,而不是两次握手?
防止失效的连接请求报文段被服务端接收,从而产生错误。
why4次挥手 ?
TCP连接是全双工通信的,而断开时双方都需要确定两个问题:自己是否还有数据要发送,对端是否还有数据要发送,而四次挥手正好在双方同步了这两个问题。
第一次挥手:client告诉server自己的数据已全部发送,client可以回收发送缓冲区,server可以回收接收缓冲区 第二次挥手:server告诉client自己收到了关闭信息 第三次挥手:server告诉client自己的数据已全部发送,server可以回收发送缓冲区,client可以回收接收缓冲区 第四次挥手:client告诉server自己收到了关闭信息 可以发现,四次挥手同样一次都不能少,如果少了其中任何一次,总有一方不能可靠的通知对方自己的数据已发送完毕,因此,连接不可能可靠的断开,TCP也就成了不可靠的协议。
一个HTTP请求报文由请求行(request line)、请求头部(header)、空行和请求数据4个部分组成
请求行分为三个部分:请求方法、请求地址和协议版本
HTTP响应报文主要由状态行、响应头部、空行以及响应数据组成。
状态行由3部分组成,分别为:协议版本,状态码,状态码描述。
8.https建立请求连接过程
客户端向服务端发送一个招呼报文(hello),包括自己支持的ssl版本,加密算法等信息。 服务端回复一个招呼报文(hi),包括自己支持的ssl版本,加密算法等信息。 服务端发送自己经过CA认证的公开密钥。 服务端向CA认证机构发送自己的公开密钥(FPkey)。 CA认证机构使用自己的私有秘钥给FPkey加上签名返回给服务端。 服务端发送结束招呼报文,ssl第一次握手结束。 客户端使用FPkey对自己的随机密码串(Ckey)进行加密并发送给服务端。 客户端首先使用CA的公开秘钥对FPkey的签名进行认证,确认秘钥未被替换。 客户端发送提示报文,后续报文将使用Ckey进行加密。 客户端发送finished报文,表示该次发送结束。 后续是否通信取决于客户端的finished报文能否被服务端成功解密。 服务端发送提示报文,表示他之后的报文也是用Ckey进行加密。 服务端发送finished报文,至此ssl握手结束,成功建立ssl连接。 客户端开始发送http请求报文。 建立tcp连接,开始传输数据。 服务端发送http回复报文。 客户端发送断开连接报文,并断开tcp连接。
http\https相关* 1、HTTPS 协议需要到 CA (Certificate Authority,证书颁发机构)申请证书,一般免费证书较少,因而需要一定费用。(以前的网易官网是http,而网易邮箱是 https 。)
2、HTTP 是超文本传输协议,信息是明文传输,HTTPS 则是具有安全性的 SSL 加密传输协议。
3、HTTP 和 HTTPS 使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
4、HTTP 的连接很简单,是无状态的。HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议,比 HTTP 协议安全。(无状态的意思是其数据包的发送、传输和接收都是相互独立的。无连接的意思是指通信双方都不长久的维持对方的任何信息。)\
跨域问题、怎么解决
跨域:当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域
解决方案:
1、 通过jsonp跨域
通过动态创建script,再请求一个带参网址实现跨域通信。原理:把js、css,img等静态资源分离到另一台独立域名的服务器上,在html页面中再通过相应的标签从不同域名下加载静态资源,而被浏览器允许
Jsonp返回回来的东西你怎么调用?
2、 document.domain + iframe跨域 3、 location.hash + iframe 4、 window.name + iframe跨域 5、 postMessage跨域 6、 跨域资源共享(CORS) 7、 nginx代理跨域
跨域原理: 同源策略是浏览器的安全策略,不是HTTP协议的一部分。服务器端调用HTTP接口只是使用HTTP协议,不会执行JS脚本,不需要同源策略,也就不存在跨越问题。
实现思路:通过nginx配置一个代理服务器(域名与domain1相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域登录。
8、 nodejs中间件代理跨域
9. get post
GET把参数包含在URL中,POST通过request body传递参数
GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
GET请求在URL中传送的参数是有长度限制的,而POST没有。
对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
4.说一下定位position 属性的五个值:
- [static]
- [relative]
- [fixed])
- [absolute]
- [sticky]
7.变量提升
:变量声明会被提升到作用域的最顶端
全局作用域中声明的变量会提升至全局最顶层,
函数内声明的变量只会提升至该函数作用域最顶层
函数提升只会提升函数声明,而不会提升函数表达式。
函数声明的优先级高于变量声明的优先级
回调函数的理解
本质上就是函数作为参数
2.回调函数的特点
(1)自己定义的函数(2)你没有调用(3)最终它执行了
3.常见的回调函数
(1)DOM事件回调函数 (2)定时器回调函数 (3)ajax请求回调函数(4)生命周期回调函数
6.DOM操作
获取节点:getElementById() ,getElementsByTagName(),getElementsByClassName()
删除节点:removeChild
创建元素document.createElement(); 创建文本节点document.createTextNode();
7.事件冒泡,如何阻止事件冒泡
事件冒泡 :当一个元素接收到事件的时候 会把他接收到的事件传给自己的父级,一直到window
事件捕获:事件捕获会从document开始触发,一级一级往下传递,依次触发,直到target事件为止。
事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。
例如,click事件会一直冒泡到document层次。也就是说,我们可以为整个页面指定一个onclick事件处理程序,而不必给每个可单击的元素分别添加事件处理程序
15.vue3里与vue2的一些改变
vue2采用面向对象编程的思想,vue3则采用函数式编程的思想。
vue3修改了虚拟dom的算法
(即diff算法 - 比对虚拟dom有没有变化)
vue2需要diff所有的虚拟dom节点,而vue3参考了SVELTE框架的思想,先分层次-然后找不变化的层-针对变化的层进行diff,更新速度不会再受template大小的影响,而是仅由可变的内容决定。
数据双向绑定:
关于数据双向绑定的实现,vue2 采用了defineProperty,而vue3则采用了proxy。
优点:
- 使用proxy不污染源对象,会返回一个新对象,defineProperty是注入型的,会破坏源对象
- 使用proxy只需要监听整个源对象的属性,不需要循环使用Object.defineProperty监听对象的属性
- 使用proxy可以获取到对象属性的更多参数,使用defineProperty只能获取到监听属性的新值newvalue
diff算法
- 当页面的数据发生变化时,Diff算法只会比较同一层级的节点。
- 如果节点类型不同,直接干掉前面的节点,再创建并插入新的节点,不会再比较这个节点的子节点了。
- 如果节点类型相同,则会重新设置该节点的属性,从而实现节点的更新。
jquery中选择器
jquery的基本选择器
基本选择器是JQuery最常用的选择器,也是最简单的选择器,它通过元素id、class和标签名来查找DOM元素。
在网页中id只能使用一次,即id具有唯一性,但class是允许重复使用的。
jquery层次选择器
层次选择器通过DOM元素间的层次关系来获取元素,主要的层次关系包括父子、后代、相邻、兄弟关系。
jquery过滤选择器
过滤选择器主要是通过特定的过滤规则来筛选出所需的DOM元素,过滤规则与CSS中的伪类选择器语法相同,即选择器都以一个冒号(:)开头
jquery表单选择器
利用表单选择器我们可以极其方便地获取表单的某个或某类型的元素。 (":text")
5.jquery封装过组件吗
6.jquery为什么可以链式调用
return this
在每个方法后面加了一个return this。
如果没有加上return this语句的话,那么执行完一个函数之后,会默认返回undefined,这个是js内部自己隐式添加的。返回undefined的时候,再调用另一个方法肯定就会报错,因为undefined是没有方法的。
2、为什么要返回this? 因为在一个对象里面,this指向的是对象本身,而我们连续调用方法的时候,这些方法都是在对象内部定义的,所以this是可以访问到这些方法。
项目中滑动页面时数据怎么取
-
设置一个标志位用来判断数据是否在加载中
-
将滚动区域设置成 overfow:auto(显示滚动条)
-
给滚动区域加入监听事件并绑定ref属性 来获取DOM实例
-
当鼠标滚动到底部时,加载数据
4.1 如果此时 标志位为true则 直接退出,不进行此时数据加载//已经滚动的距离加页面的高度等于整个内容区高度时,视为接触到底部 //scrollTop 获取到顶部的滚动距离 // clientHeight 表示页面视口高度 // scrollHeight 页面内容的高度
-
2.call()、apply(),应用场景
当一个对象需要调用另外一个对象里面的方法的时候就可以用到call和apply,call和Apply可以理解成是继承另外一个对象的方法,
call和apply作用都是改变this的指向,区别就是apply传递的参数必须得是参数列表的形式传递,而call则直接多个参数传递