javaScript
1.1.Ajax原理是什么?如何实现?
由客户端请求ajax引擎,由ajax引擎请求服务器,服务器处理完数据后将结果返回给ajax引擎,由ajax引擎决定着将结果写入客户端的什么位置。
ajax引擎的核心对象是XMLHttpRequest
- 原生
- jquery简化后的
- 浏览器自带的fetch
- axios可以
Ajax的原理:
Ajax的原理简单来说通过XmlHttpRequest对象来向服务器发异步请求,从服务器获得数据,然后⽤JavaScript来操作DOM⽽更新⻚⾯。
实现 Ajax异步交互需要服务器逻辑进⾏配合,需要完成以下步骤:
- 创建 Ajax的核⼼对象 XMLHttpRequest对象
- 通过 XMLHttpRequest 对象的 open() ⽅法与服务端建⽴连接
- 构建请求所需的数据内容,并通过XMLHttpRequest 对象的 send() ⽅法发送给服务器端
- 通过 XMLHttpRequest 对象提供的 onreadystatechange 事件监听服务器端你的通信状态
- 接受并处理服务端向客户端响应的数据结果
- 将处理结果更新到 HTML⻚⾯中
举例:
ajax({
type: 'post',
dataType: 'json',
data: {},
url: 'https://xxxx',
success: function(text,xml){//请求成功后的回调函数 console.log(text)
},
fail: function(status){请求失败后的回调函数 console.log(status)
}
})
1.2.数组的常用方法有哪些?
**splice()**万能法
- 添加:数组名.splice(下标,删除元素的个数,添加的元素)
- 删除:splice(下标index,删除元素的个数)
- 替换:数组名.splice(下标index,删除元素的个数,添加元素值)
添加:
前三种是对原数组产⽣影响的增添⽅法,第四种则不会对原数组产⽣影响push()unshift()splice()concat()
push() 数组后面/末尾添加 数组名.push(要添加的元素)
unshift() 数组前面/头部添加 数组名.unshift(要添加的元素)
**splice()**万能法 数组名.splice(下标,删除元素的个数,添加的元素)
concat 连接,合并数组 ⾸先会创建⼀个当前数组的副本,然后再把它的参数添加到副本末尾,最后返回这个新构建的数组,不会影响原始数组
删除:
下⾯三种都会影响原数组,最后⼀项不影响原数组:
pop()shift()splice()slice()
改:
即修改原来数组的内容,常⽤splice,
splice() 传⼊三个参数,分别是开始位置,要删除元素的数量,要插⼊的任意多个元素,返回删除元素的数组,对原数组产⽣影响
查:
即查找元素,返回元素坐标或者元素值。
indexOf() includes() find()
indexOf()返回要查找的元素在数组中的位置,如果没找到则返回 -1
includes()返回要查找的元素在数组中的位置,找到返回true,否则false
find()返回第⼀个匹配的元素
排序方法
-
**reverse()**数组反转 【数组名.reverse();】
-
**sort()**排序 【数组名.sort()】当()里没有参数的时候,按照编码排序
语法:数组名.sort( function(a,b){ return a-b;//从小到大排序 return b-a;//从大到小排序 } )
转换方法:
-
**join()=>**把数组转化为字符串
-
split()=>字符串转数组**【字符串名.split(“分隔符”)】**
迭代⽅法:都是对数组每⼀项都运⾏传⼊的函数,
- some()=>如果有⼀项函数返回 true ,则这个⽅法返回 true
- every()=>如果对每⼀项函数都返回 true ,则这个⽅法返回 true
- raduce()=>
- forEach()=>没有返回值,数组进行遍历
- map()=>返回由每次函数调⽤的结果构成的数组,没有return时,对数组的遍历。有return时,返回一个新数组,该新数组的元素是经过过滤(逻辑处理)过的函数。有返回值
- filter()=>函数返回 true 的项会组成数组之后返回,筛选,过滤
1.3.bind、call、apply 区别?如何实现⼀个bind?
1.三者都可以改变函数的this对象指向,
三者第⼀个参数都是this要指向的对象,如果如果没有这个参数或参数为undefined或null,则默认指向全局window三者都可以传参,但是apply是数组,⽽call是参数列表,且apply和call是⼀次性传⼊参数,
⽽bind可以分为多次传⼊bind是返回绑定this之后的函数,apply、call 则是⽴即执⾏(手动实现bind:声明一个函数…)
2.实现bind的步骤,我们可以分解成为三部分:
- 修改this指向
- 动态传递参数
- 兼容new关键字
4.如何实现一个深拷贝?
// 总结:
// 浅复制:仅仅是指向被复制的内存地址,如果原地址发生改变,那么浅复制出来的对象也会相应的改变。特点:只复制一层 。方法有: Object.assign(), es6中的展开运行符{…a,…b} var in 遍历对象,进行单层赋值
// 深复制:在计算机中开辟一块新的内存地址用于存放复制的对象。特点:可复制多层 。方法有 JSON.parse(JSON.stringify(obj)) ,递归深拷贝*
*// 相关链接:https://segmentfault.com/q/1010000008815500 对象的深度合并
对象展开运算符并不是深拷贝,而是浅拷贝
浅拷贝会立即改变,深拷贝不会被影响
5.event loop 事件循环机制
//调用优化级 :1.同步(promise里除了resolve的.then是异步请求。其它写的都是同步)>异步(微任务[promise,async,await,axios]>宏任务[定时器,事件函数,ajax],异步)
浅拷贝会立即改变,深拷贝不会被影响
//调用优化级 1.同步(promise里除了resolve的.then是异步请求。其它写的都是同步)>异步(微任务[promise,async,await,axios]>宏任务[定时器,事件函数,ajax])
// 总结:
// 深拷贝其它方法 JSON.parse(JSON.stringify(obj)) 缺点:不能复制RegExp、Error,undefined,日期对象等
// 浅复制:仅仅是指向被复制的内存地址,如果原地址发生改变,那么浅复制出来的对象也会相应的改变。特点:只复制一层 。方法有: Object.assign(), es6中的展开运行符{…a,…b} var in 遍历对象,进行单层赋值
// 深复制:在计算机中开辟一块新的内存地址用于存放复制的对象。特点:可复制多层 。方法有 JSON.parse(JSON.stringify(obj)) ,递归深拷贝
// 相关链接:https://segmentfault.com/q/1010000008815500 对象的深度合并
let是块级作用域
1.4 Javascript本地存储的⽅式有哪些?区别及应⽤场景
本地存储存储的是字符串,存对象用json.stringfly()来转化,获取是,用json.parse()来转化
javaScript本地存储(也称本地缓存)的⽅法我们主要讲述以下四种:
- cookie
- sessionStorage
- localStorage
- indexedDB
cookie在每次请求中都会被发送,如果不使⽤ HTTPS并对其加密,其保存的信息很容易被窃取,导致安全⻛险。举个例⼦,在⼀些使⽤ cookie保持登录态的⽹站上,如果 cookie被窃取,他⼈很容易利⽤你的 cookie来假扮成你登录⽹站
关于cookie常⽤的属性如下:
- Expires ⽤于设置 Cookie 的过期时间
- Max-Age ⽤于设置在 Cookie 失效之前需要经过的秒数(优先级⽐Expires⾼)
- Domain指定了 Cookie 可以送达的主机名
- Path指定了⼀个 URL路径,这个路径必须出现在要请求的资源的路径中才可以发送 Cookie ⾸部
- 标记为 Secure的 Cookie只应通过被HTTPS协议加密过的请求发送给服务端通过上述,我们可以看到cookie⼜开始的作⽤并不是为了缓存⽽设计出来,只是借⽤了cookie的特性实现缓存
关于cookie的使⽤如下:document.cookie = ‘名字=值’;
关于cookie的修改,⾸先要确定domain和path属性都是相同的才可以,其中有⼀个不同得时候都会创建出⼀个新的cookie
最后cookie的删除,最常⽤的⽅法就是给cookie设置⼀个过期的事件,这样cookie过期后会被浏览器删除
localStorageHTML5新⽅法,IE8及以上浏览器都兼容:
特点
- ⽣命周期:持久化的本地存储,除⾮主动删除数据,否则数据是永远不会过期的
- 存储的信息在同⼀域中是共享的
- 当本⻚操作(新增、修改、删除)了localStorage的时候,本⻚⾯不会触发storage事件,但是别的⻚⾯会触发storage事件。
- ⼤⼩:5M(跟浏览器⼚商有关系)
- localStorage本质上是对字符串的读取,如果存储内容多的话会消耗内存空间,会导致⻚⾯变卡
- 受同源策略的限制
设置:localStorage.setItem(‘username’,‘cfangxu’);
获取:localStorage.getItem(‘username’)
获取键名:localStorage.key(0) //获取第⼀个键名
删除:localStorage.removeItem(‘username’)
⼀次性清除所有存储:localStorage.clear()
localStorage 也不是完美的,它有两个缺点:
- ⽆法像Cookie⼀样设置过期时间
- 只能存⼊字符串,⽆法直接存对象
sessionStorage
唯⼀不同的是⽣命周期,⼀旦⻚⾯(会话)关闭,sessionStorage 将会删除数据
IndexedDB提供了⼀个解决⽅案优点:
- 储存量理论上没有上限
- 所有操作都是异步的,相⽐ LocalStorage 同步操作性能更⾼,尤其是数据量较⼤时
- 原⽣⽀持储存JS的对象
- 是个正经的数据库,意味着数据库能⼲的事它都能⼲
缺点:
- 操作⾮常繁琐
- 本身有⼀定⻔槛
区别
关于cookie、sessionStorage、localStorage三者的区别主要如下:
- 存储⼤⼩:cookie数据⼤⼩不能超过4k,sessionStorage和localStorage虽然也有存储⼤⼩的限制,但⽐cookie⼤得多,可以达到5M或更⼤
- 有效时间:localStorage存储持久数据,浏览器关闭后数据不丢失除⾮主动删除数据; sessionStorage数据在当前浏览器窗⼝关闭后⾃动删除;cookie设置的cookie过期时间之前⼀直有效,即使窗⼝或浏览器关闭
- 数据与服务器之间的交互⽅式,cookie的数据会⾃动的传递到服务器,服务器端也可以写cookie到客户端; sessionStorage和localStorage不会⾃动把数据发给服务器,仅在本地保存
应⽤场景
- 标记⽤户与跟踪⽤户⾏为的情况,推荐使⽤cookie
- 适合⻓期保存在本地的数据(令牌),推荐使⽤localStorage
- 敏感账号⼀次性登录,推荐使⽤sessionStorage
- 存储⼤量数据的情况、在线⽂档(富⽂本编辑器)保存编辑历史的情况,推荐使⽤indexedDB
1.5说说你对闭包的理解?闭包使⽤场景?
闭包概念:内部函数访问外部函数的变量,这种函数嵌套函数的形式
优点: 外部函数的变量会存储在内存中,可以避免全局变量的污染
缺点: 容易造成内存泄露,每调用一次都会产生一个新的闭包
适⽤场景:封装组件,for循环和定时器结合使⽤,for循环和dom事件结合导航栏获取下标的使⽤
作用:隔离作用域,避免全局变量的污染
1.6 深拷⻉浅拷⻉的区别?如何实现⼀个深拷⻉?
基本类型数据保存在在栈内存中引⽤类型数据保存在堆内存中,
引⽤数据类型的变量是⼀个指向堆内存中实际对象的引⽤,存在栈中
基本数据类型存储的是地址(基本数据类型存储在栈中)
引用数据类型存储的是堆,就是指向(引用数据类型存储在堆中)
浅拷⻉
浅拷⻉,指的是创建新的数据,这个数据有着原始数据属性值的⼀份精确拷⻉
如果属性是基本类型,拷⻉的就是基本类型的值。如果属性是引⽤类型,拷⻉的就是内存地址
即浅拷⻉是拷⻉⼀层,深层次的引⽤类型则共享内存地址
在JavaScript中,存在浅拷⻉的现象有:
- Object.assign
- Array.prototype.slice(),
- Array.prototype.concat()
- 使⽤拓展运算符实现的复制
深拷⻉
深拷⻉开辟⼀个新的栈,两个对象属完成相同,但是对应两个不同的地址,修改⼀个对象的属性,不会改变另⼀个对象的属性
常⻅的深拷⻉⽅式有:不能拷贝正则(空)
- _.cloneDeep()
- jQuery.extend()
- JSON.stringify()
- ⼿写循环递归(不要再原对象上去改变)
- instance of(Object)判断是否是对象
// 总结:
…扩展符(一般是浅拷贝,但有时也可以来进行深拷贝)
// 浅复制:仅仅是指向被复制的内存地址,如果原地址发生改变,那么浅复制出来的对象也会相应的改变。特点:只复制一层 。方法有: Object.assign(), es6中的展开运行符{…a,…b} var in 遍历对象,进行单层赋值
- 深复制:在计算机中开辟一块新的内存地址用于存放复制的对象。特点:可复制多层 。方法有 JSON.parse(JSON.stringify(obj)) ,递归深拷贝()**
JSON.stringify(obj)把对象转化为字符串
相关链接:https://segmentfault.com/q/1010000008815500 对象的深度合并*
*对象展开运算符并不是深拷贝,而是浅拷贝
浅拷贝会立即改变,深拷贝不会被影响
4.为什么在项目中data需要使用return返回数据呢?
不使用return包裹的数据会在项目的全局可见,会造成变量污染;使用return包裹后数据中变量只在当前组件中生效,不会影响其他组件。
当一个组件被定义, data 必须声明为返回一个初始数据对象的函数,因为组件可能被用来创建多个实例。如果 data 仍然是一个纯粹的对象,则所有的实例将共享引用同一个数据对象!通过提供 data 函数,每次创建一个新实例后,我们能够调用 data 函数,从而返回初始数据的一个全新副本数据对象。独立空间,防止作用域的污染(闭包)
1.7 说说JavaScript中的数据类型?存储上的差别?
在JavaScript中,我们可以分成两种类型:
- 基本类型
- 复杂类型
两种类型的区别是:存储位置不同:
- 基本数据类型存储在栈中, Number String boolean Undifined null symbol
- 引⽤类型的对象存储于堆中, 引用数据类型 Array Object Function Date Regexp
数据类型的判断
-
typeof 对于基本数据类型判断是没有问题的,但是遇到引用数据类型(如:Array)是不起作用
-
instanceof 判断 new 关键字创建的引用数据类型,不考虑 null 和 undefined(这两个比较特殊)以对象字面量创建的基本数据类型=>(判断出来的是true和false)
-
constructor 似乎完全可以应对基本数据类型和引用数据类型 但如果声明了一个构造函数,并且把他的原型指向了 Array 的原型,所以这种情况下,constructor 也显得力不从心
-
Object.prototype.toString.call() 完美的解决方案=>返回字符串
-
jquery.type()
如果对象是undefined或null,则返回相应的“undefined”或“null”。
那些特殊数据类型的返回值
-
typeOf(undifined) ----- //undefind**********
-
typeOf(null) ----- //object**********
-
typeOf([]) ----- //object**********
-
typeOf({}) -----//object********
-
typeOf(NaN) ----- //number**********
-
typeOf(string||boolean||object||number||Array||date||Regexp) ----- //function
-
typeOf(true||false) ----- //boolean
-
typeOf(‘123’) -----------//string
-
typeOf(123) ------------//number
-
[] InstanceOf Array — //true****************
-
[] instanceOf Object — //true*****************
-
var obj=new String();
console.log(typeOf(obj)); ----//object
-
var fn=function(){};
console.log(typeOf(fn));-----//function
console.log(typeOf(class c{})); —//function
1.8 什么是防抖和节流?有什么区别?如何实现?
作⽤:本质上是优化⾼频率执⾏代码的⼀种⼿段
防抖(相较于节流,滚动会卡)=>(滚动的时候还会清除定时器,所以就会卡) =>*不管频繁触发多少,某一段时间内只执行一次(是有延迟的),*一定时间内,只进行最后一次
触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间 (一秒之后执行)
-
思路:
动作绑定事件,动作发生后一定时间后触发事件,在这段时间内,如果该动作又发生,则重新等待一定时间再触发事件。 -
代码实现:
防抖如果需要⽴即执⾏,可加⼊第三个参数⽤于判断,
节流(相较于防抖,滚动会更流畅一些)=>间隔一段时间执行。(定时器加开关)
高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率 (间隔一段时间再执行)
- 思路:
动作绑定事件,动作发生后一段时间后触发事件,在这段时间内,如果动作又发生,则无视该动作,直到事件执行完后,才能重新触发。 - 代码实现:
- 完成节流可以使⽤时间戳与定时器的写法
- 使⽤时间戳写法,事件会⽴即执⾏,停⽌触发后没有办法再次执⾏
- 使⽤定时器写法,delay毫秒后第⼀次执⾏,第⼆次事件停⽌触发后依然会再⼀次执⾏
- 可以将时间戳写法的特性与定时器写法的特性相结合,实现⼀个更加精确的节流。
相同点:
- 都可以通过使⽤ setTimeout 实现
- ⽬的都是,降低回调执⾏频率。节省计算资源
不同点:
- 函数防抖,在⼀段连续操作结束后,处理回调,利⽤clearTimeout和 setTimeout实现。函数节流,在⼀段连续操作中,每⼀段时间只执⾏⼀次,频率较⾼的事件中使⽤来提⾼性能
- 函数防抖关注⼀定时间连续触发的事件,只在最后执⾏⼀次,⽽函数节流⼀段时间内只执⾏⼀次
- 例如,都设置时间频率为500ms,在2秒时间内,频繁触发函数,节流,每隔 500ms 就执⾏⼀次。防抖,则不管调动多少次⽅法,在2s后,只会执⾏⼀次
结合应用场景
debounce(防抖)防抖在连续的事件,只需触发⼀次回调的场景有:
- 搜索框搜索输⼊。只需⽤户最后⼀次输⼊完,再发送请求
- ⼿机号、邮箱验证输⼊检测
search搜索联想词,用户在不断输入值时,用防抖来节约请求资源。
. throttle(节流)节流在间隔⼀段时间执⾏⼀次回调的场景有:(平滑的过渡)
- 滚动加载,加载更多或滚到底部监听
鼠标不断点击触发,mousedown(单位时间内只触发一次),拖拽
window触发resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次
监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断
1.9 解释下什么是事件代理?应⽤场景
事件代理
(也称事件委托,通俗来讲,就是把⼀个元素响应事件的函数委托到另⼀个元素
事件流的都会经过三个阶段: 捕获阶段 -> ⽬标阶段 -> 冒泡阶段,⽽事件委托就是在冒泡阶段完成
事件委托,通过event来实现事件委托
会把⼀个或者⼀组元素的事件委托到它的⽗层或者更外层元素上,真正绑定事件的是外层元 素,⽽不是⽬标元素
当事件响应到⽬标元素上时,会通过事件冒泡机制从⽽触发它的外层元素的绑定事件上,然后在外层元 素上去执⾏函数
-
原理:给父元素注册事件,利用事件冒泡,当子元素的事件触发,会冒泡到父元素,然后去控制相应的子元素。
-
作用:我们只操作了一次 DOM ,提高了程序的性能。动态新创建的子元素,也拥有事件。
-
怎么实现事件委托
//jquery
$(“父选择器”).on(“事件名”,“子选择器”,回调函数)
//js
//js的事件委托或者事件代理
优点
减少整个⻚⾯所需的内存,提升整体性能,动态绑定,减少重复⼯作
-
方便,如果子元素很多的情况下不用单个去添加事件
-
如果动态的添加元素,不用单独的去绑定
-
能用事件委托的事件 click 键盘事件等
应用场景:
如果我们有⼀个列表,列表之中有⼤量的列表项,我们需要在点击列表项的时候响应⼀个事件
如果给每个列表项⼀⼀都绑定⼀个函数,那对于内存消耗是⾮常⼤的
这时候就可以事件委托,把点击事件绑定在⽗级元素ul上⾯,然后执⾏事件的时候再去匹配⽬标元素
举个例⼦:下⾯html结构中,点击input可以动态添加元素使⽤事件委托
使⽤事件委托,在动态绑定事件的情况下是可以减少很多重复⼯作的.
拖拽,通过event (e.target)来知道是哪一个目标元素(event是事件机制)
代码:
在function里面用addEventListener来给父元素绑定事件,绑定之后,通过e.target来知道是哪一个目标元素(e.target就是event.target=>其中event是事件机制),来委托
事件委托存在两⼤优点:
- 减少整个⻚⾯所需的内存,提升整体性能
- 动态绑定,减少重复⼯作
但是使⽤事件委托也是存在局限性:
- focus、blur=>获取焦点,失去焦点这些事件没有事件冒泡机制,所以⽆法进⾏委托绑定事件
- mousemove、mouseout=>鼠标的移入,移出这样的事件,虽然有事件冒泡,但是只能不断通过位置去计算定位,对性能消耗⾼,因此也是不适合于事件委托的
如果把所有事件都⽤事件代理,可能会出现事件误判,即本不该被触发的事件被绑定上了事件
1.10 说说你对事件循环(Event Loop)的理解?
//调用优化级 :1.同步(promise里除了resolve的.then是异步请求。其它写的都是同步)>异步(微任务[promise的.then,async,await,axios])(微任务后进,先执行)>宏任务[定时器,事件函数(onclick),ajax],异步)=>(宏任务先进,后执行)
JavaScript是⼀⻔单线程的语⾔,意味着同⼀时间内只能做⼀件事,但是这并不意味着单线程就是阻塞,⽽实现单线程⾮阻塞的⽅法就是事件循环
在JavaScript中,所有的任务都可以分为
- 同步任务:⽴即执⾏的任务,同步任务⼀般会直接进⼊到主线程中执⾏
- 异步任务:异步执⾏的任务,⽐如ajax⽹络请求,setTimeout定时函数等
同步任务进⼊主线程,即主执⾏栈,异步任务进⼊任务队列,主线程内的任务执⾏完毕为空,会去任务队列读取对应的任务,推⼊主线程执⾏。不断重复过程的就事件循环
宏任务与微任务
异步任务执⾏顺序,事件队列其实是⼀个“先进先出”的数据结构,排在前⾯的事件会优先被主线程读取
异步任务还可以细分为微任务与宏任务
微任务
⼀个需要异步执⾏的函数,执⾏时机是在主函数执⾏结束之后、当前宏任务结束之前常⻅的微任务有:
- Promise.then
- MutaionObserver
- Object.observe(已废弃;Proxy 对象替代)
- process.nextTick(Node.js)
宏任务
宏任务的时间粒度⽐较⼤,执⾏的时间间隔是不能精确控制的,对⼀些⾼实时性的需求就不太符合常⻅的宏任务有:
- script (可以理解为外层同步代码)
- setTimeout/setInterval
- UI rendering/UI事件
- postMessage、MessageChannel
- setImmediate、I/O(Node.js)
它的执⾏机制是:
执⾏⼀个宏任务,如果遇到微任务就将它放到微任务的事件队列中当前宏任务执⾏完成后,会查看微任务的事件队列,然后将⾥⾯的所有微任务依次执⾏完
async与await
async 是异步的意思,await则可以理解为 async wait。所以可以理解async就是⽤来声明⼀个异步⽅法,⽽ await是⽤来等待异步⽅法执⾏
不管await后⾯跟着的是什么,await都会阻塞后⾯的代码
await 会阻塞下⾯的代码(即加⼊微任务队列),先执⾏ async外⾯的同步代码,同步代码执⾏完,再回到 async 函数中,再执⾏之前阻塞的代码
1.11 Javascript如何实现继承?
JS继承实现⽅式也很多,主要分ES5和ES6继承的实现
ES5三种⽅法 主要是基于prototype来实现的,
⼀是原型链继承:即 B.prototype=new A() =>继承方法
⼆是借⽤构造函数继承(call或者apply的⽅式继承=>apply是数组,call是参数列表)=>继承属性 (子类.call)
三是组合继承是结合第⼀种和第⼆种⽅式=>(结合后,属性和方法都可以继承)
function B(name,age) {
A.call(this,name,age)
}
ES6继承是⽬前主流的继承⽅式,⽤class定义类,⽤extends继承类,⽤ super()表示⽗类,其中需要有constructor构造函数
创建B类并继承A类
class B extends A {//extends继承分类的方法
constructor() {//构造函数
super() //表示⽗类
}
}
1.12说说 JavaScript 中内存泄漏的⼏种情况?
- 不再用到的内存,没有及时释放,就叫做内存泄漏(memory leak)。
**内存泄漏(Memory leak)**是在计算机科学中,由于疏忽或错误造成程序未能释放已经不再使⽤的内存
1.DOM/BOM 对象泄漏
2.script 中存在对DOM/BOM 对象的引用导致
3.Javascript 对象泄漏
4.通常由闭包导致,比如事件处理回调,导致DOM对象和脚本中对象双向引用,这个时常见的泄漏原因
常⻅内存泄露情况=>会造成电脑的卡死,宕机
- 定时器也常会造成内存泄露
- 意外的全局变量**(另⼀种意外的全局变量可能由 this 创建,使⽤严格模式,可以避免意外的全局变量)**
- 闭包,维持函数内局部变量,使其得不到释放(大量闭包)
- 没有清理对DOM元素的引⽤同样造成内存泄露
- 使⽤事件监听addEventListener监听的时候,在不监听的情况下使⽤removeEventListener取消对事件监听
- for循环
- 代码不规范,死循环
内存泄露多数属于程序本身设计问题,有以下几种解决方法:
1)从程序内部重新编译。养成良好的编码习惯,尽量在涉及内存的程序段,检测出内存泄露。
2)结束程序,内存自然就会被操作系统回收。
3)重新启动电脑后,立刻恢复。
1.13 说说new操作符具体⼲了什么?
在JavaScript中,new操作符⽤于创建⼀个给定构造函数的实例对象
new关键字主要做了以下的⼯作:
- 创建⼀个新的对象obj
- 将对象与构建函数通过原型链连接起来
- 将构建函数中的this绑定到新建的对象obj上
- 根据构建函数返回类型作判断,如果是原始值则被忽略,如果是返回对象,需要正常处理(必须返回)
function mynew(Func, ...args) {
// 1.创建⼀个新对象
const obj = {}
// 2.新对象原型指向构造函数原型对象
obj.__proto__ = Func.prototype
// 3.将构建函数的this指向新对象
let result = Func.apply(obj, args)
// 4.根据返回值判断
return result instanceof Object ? result : obj
}
1.14 说⼀下JavaScript原型,原型链的理解?
javascript原型与原型链
原型:
- prototype
每个函数都有一个prototype属性,被称为显示原型
2._ proto _
每个实例对象都会有_ proto _属性,其被称为隐式原型
每一个实例对象的隐式原型_ proto _属性指向自身构造函数的显式原型prototype
- constructor
每个prototype原型都有一个constructor属性,指向它关联的构造函数。
原型链:
获取对象属性时,如果对象本身没有这个属性,那就会去他的原型__proto__上去找,如果还查不到,就去找原型的原型,一直找到最顶层(Object.prototype)为止。Object.prototype对象也有__proto__属性值为null。
这里需要注意的是Object是属于原型链的顶层,所有构造函数的的prototype都指向 Object.prototype
1.15 如何实现上拉加载,下拉刷新?
上拉加载:
上拉加载的本质是页面触底,或者快要触底时的动作
scrollTop + clientHeight >= scrollHeight
scrollTop:滚动视窗的高度距离window顶部的距离,它会随着往上滚动而不断增加,初始值是0,它是一个变化的值
clientHeight:它是一个定值,表示屏幕可视区域的高度;
scrollHeight:页面不能滚动时是不存在的,body长度超过window时才会出现,所表示body所有元素的长度
下拉刷新:
下拉刷新的本质是页面本身置于顶部时,用户下拉时需要触发的动作
onTouchstart ++
pagenum++
监听原生touchstart事件,记录其初始位置的值,e.touches[0].pageY;
监听原生touchmove事件,记录并计算当前滑动的位置值与初始位置值的差值,大于0表示向下拉动,并借助CSS3的translateY属性使元素跟随手势向下滑动对应的差值,同时也应设置一个允许滑动的最大值;
监听原生touchend事件,若此时元素滑动达到最大值,则触发callback,同时将translateY重设为0,元素回到初始位置
1.16 说说ES6新增特性都有哪些?
ES6新增特性常⽤的主要有:let/const,箭头函数,模板字符串,解构赋值(后台返回的data可能有好多),扩展操作符(…,可以合并数组,用来把数组展开,浅拷贝【…】,合并对象),模块的导⼊(import)和导出(export default/export),Promise,还有⼀些数组字符串的扩展⽅法,其实有很多,我平时常⽤的就这些
let/const:
-
和var的区别
- let只在代码块中有效 var是全局的
- var可以重复的定义变量 let只能声明一次
- var存在变量的提升 let不存在变量提升
-
const 定义常量的 一般定义特殊的值或者配置文件中的变量
常量是定义完成后不能改变的量,常量名一般情况下大写
箭头函数:
箭头函数:没有this指向,取决于外层环境,上下文,谁进就指向谁。
模板字符串:
用反引号(`)标识,它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。
数组新增:find findIndex Array.from()
字符串新增的函数:
includes 包含 如果包含返回true 否则返回false
startPad(目标位数,填充的是什么)前 填充
endPad(目标位数,填充的是什么) 后填充
promise
概念:Promise对象代表一个异步操作, 它表示一个在未来完成的异步操作
promise 有三个状态
有三种状态: pending(进行中)\fulfilled(已成功)\rejected(已失败)
状态改变只有两种情况: pending==>fulfilled || pending==>rejected
参数
promise有两个参数resolve || reject 是两个回调函数
常用****API
all()和race() (.then(), .catch(), .all(), .race())
1.17 说说你对作⽤域链的理解?
一段代码起作用的范围 分为全局作用域和局部作用域和块级作用域
全局作⽤域
任何不在函数中或是⼤括号中声明的变量,都是在全局作⽤域下,全局作⽤域下声明的变量可以在程序的任意位置访问
函数作⽤域
函数作⽤域也叫局部作⽤域,如果⼀个变量是在函数内部声明的它就在⼀个函数作⽤域下⾯。这些变量只能在函数内部访问,不能在函数以外去访问(闭包可以拿到函数内部的变量)
块级作⽤域
ES6引⼊了let和const关键字,和var关键字不同,在⼤括号中使⽤let和const声明的变量存在于块级作⽤域中。在⼤括号之外不能访问这些变量
作用域链:
函数内部使用变量,先从当前函数查找,如果找不到,则继续向父级查找,如果还找不到继续往上一级查找,最后找到window对象,如果还找不到,
则报错提示变量不存在,这种链条关系就是作用域链
1.18 谈谈this对象的理解?
this 的指向有哪些,谈谈你对this理解?
1、普通函数中的this指向window
2、定时器中的this指向window
3、箭头函数没有this,它的this指向取决于外部环境、(上下文,指向离他最近的)
4、事件中的this指向事件的调用者
5、 构造函数中this和原型对象中的this,都是指向构造函数new 出来实例对象
6、类 class中的this 指向由constructor构造器new出来的实例对象
7、自调用函数中的this 指向window
2.4 SPA首屏加载慢?
什么是首屏加载?
⾸屏时间(First Contentful Paint),指的是浏览器从响应⽤户输⼊⽹址地址,到⾸屏内容渲染完成的
时间,此时整个⽹⻚不⼀定要全部渲染完成,但需要展示当前视窗需要的内容
⾸屏加载可以说是⽤户体验中最重要的环节
加载慢的原因?
在⻚⾯渲染的过程,导致加载速度慢的因素可能如下:
- ⽹络延时问题
- 资源⽂件体积是否过⼤
- 资源是否重复发送请求去加载了
- 加载脚本的时候,渲染内容堵塞了
解决方案:
常⻅的⼏种SPA⾸屏优化⽅式:
- 减⼩⼊⼝文件体积(在vue-router配置路由的时候,采⽤动态加载路由的形式)
- 静态资源本地缓存
- UI框架按需加载
- 图⽚资源的压缩
- 组件重复打包
- 开启GZip压缩
- 使⽤SSR
2.5通过process.env.NODE_ENV区分生产环境
production:生产
1.19 你是怎么理解ES6中 Promise的?使⽤场景?
概念:Promise对象代表一个异步操作, 它表示一个在未来完成的异步操作
promise 有三个状态
有三种状态: pending(进行中)*fulfilled(已成功)*rejected(已失败)
状态改变只有两种情况: pending==>fulfilled || pending==>rejected
参数
promise有两个参数resolve ||. reject 是两个回调函数
- resolve函数的作⽤是,将Promise对象的状态从“未完成”变为“成功”(.then)
- reject函数的作⽤是,将Promise对象的状态从“未完成”变为“失败”
常用****API
all()和race() (.then(), .catch(), .all(), .race())
promise解决异步操作的优点:
-
链式操作减低了编码难度
-
代码可读性明显增强
总结:
总结:什么是promise?
解决地狱回调问题,把异步的请求结果转化为同步的执行
它可以进行链式调用
有三种状态分别是 :pending 初始状态,进行中 fulfilled 成功状态,请求成功了 rejected 失败状态,请求失败了 Promise的状态一旦改变,就不会再变,任何时候都可以得到这个结果,状态不可以逆,只能由 pending变成fulfilled或者由pending变成rejected。
promise有哪些API方法:.then(),.catch(),.finally(),.all(),.race()
.then()走成功=》里面是方法,代表请求成功或失败执行的回调
.catch()走失败
.finally()不论是成功还是失败,都会执行
.all()=》通过构造函数来调用,**应用场景:**有一个失败就都会失败。后边一个接口依赖前面多个接口都成功了
有一个失败就都失败
.race()有一个成功就成功
应用场景:封装ajax,axios的get,post封装,微信小程序中封装wx.request(),uniapp开发中uni.request() ,封装网络请求
如axios 。。。
es6中new Promise() 作用把异步请求改成同步执行
一:基础用法:
// console.dir(Promise) //可查看对象上的所有属性与方法
//内部放异步请求的内容 ajax ,成功的通过resolve回调出去,失败的通过reject回调出去
//then里面是方法,代表请求成功或失败执行的回调
二:promise应用
promise应用-里面放网络请求,把异步请求结果变成链式调用执行
//1.ajax请求数据-成功或者失败方法是在内部执行的。如果请求成功的数据外面要用时,外面是拿不到的,因为它是一个函数。
//2.1 promise可把异步的执行改成同步。把请求成功的数据,通过回调函数拿到外面执行
//通过then,把异步执行弄成同步执行
//返回的对象{},里面有then方法,代表的请求成功,或失败
//2.2 工作中,因为接口地址经常变。可用函数把promise在次封装下,外面传入接口地址。其实就是大家常用的axios的原理,内部封装
//axios的原理-内部封装
三. ajax请求多个数据,如果后面数据依赖前面数据-会有痛点,产生回调地狱问题
//3.1
//第二个接口数据依赖第一个接口数据,不优雅
//第三个接口数据又依赖第二个接口数据,不优雅。俗称回调地狱问题
//3.2 Promise解决回调地狱问题
//通过promise封装ajax方法
//3.3 多个请求也可用 Promise.all()方法-返回的是数组,需要展开下拿到每个值。有一个失败,都会失败。应用场景:后边一个接口依赖前面多个接口都成功了
应用场景:
解决地狱回调问题(多层异步,可以进行链式调用),封装ajax这种异步请求,微信小程序的封装wx.request(),(函数,里面要有返回return),以及axios的get,post实现;
在一些网络请求中,用promise封装,
核心:promise的resolve把.then()与.catch()
先new一个promise对象,里面有两个参数:resolve和reject(其中,.then走成功的,.reject走失败)
.then()走成功=》里面是方法,代表请求成功或失败执行的回调
.catch()走失败
.finally()不论是成功还是失败,都会执行
.all()=》通过构造函数来调用,**应用场景:**有一个失败就都会失败。后边一个接口依赖前面多个接口都成功了
有一个失败就都失败
.race()有一个成功就成功
//all()
Promise.all([
getAjax('data/json.txt'),
]).then(
function(res=>{
var [a,b]=res
console.log("全成功",a,b)
},
)
)
new Promise(
function (resolve, reject) {
// 一段耗时的异步操作
resolve('成功') // 数据处理完成
// reject('失败') // 数据处理出错
}
).then(
(res) => {console.log(res)}, // 成功
(err) => {console.log(err)} // 失败
)
2.5 es7的异步处理 async与await
async,await与省略了链式的结果。可以有多个await
把异步请求变成同步执行,async放在最近函数外调用,返回promise请求。缺点:如果出错了,会影响后续代码的执行,如果没有catch错误处理需要用try来处理
- async 可以把普通的函数改成异步函数,调用都是一样的,返回的是一个promise对象
- async配合await使用是一个阻塞的异步方法结果
* async
* 返回一个promise对象, 无论函数内部是否有await都会返回promise对象
* 函数内部return返回的值, 会成为then回调函数的第一个参数
* 函数内部如果出现错误,会被then的第二个参数或catch所捕获
* await
等待异步的结果
* 只能在async函数中出现, 普通函数直接使用会报错
* 正常情况下, await后面是一个Promise对象, 返回该对象的结果.
* 如果await后面不是Promise对象, 就直接返回对应的值
async await
async 函数返回一个 Promise 对象,可以使用 then 方法添加回调函数。
await只能和async搭配使用 异步函数同步化
1.20 说说var、let、const之间的区别?
let/const:
和var的区别
- let只在代码块中有效 var是全局的
- var可以重复的定义变量 let只能声明一次
- var存在变量的提升 let不存在变量提升
const 定义常量的 一般定义特殊的值或者配置文件中的变量
常量是定义完成后不能改变的量,常量名一般情况下大写
var、let、const三者区别可以围绕下⾯五点展开:变量提升暂时性死区块级作⽤域重复声明修改声明的变量使⽤
1.21 说说javaScript原⽣有⼏种绑定事件⽅式?具体如何实现?
JS原⽣绑定事件主要为三种:
-
⼀是html事件处理程序 ()
-
⼆是DOM0级事件处理程序
-
三是DOM2级事件处理程序
-
其中:html事件现在早已不⽤了(行内事件),就是在html各种标签上直接添加事件,类似于css的⾏内样式,缺点是不好维护,因为散落在标签中,也就是耦合度太⾼例如:点我
-
第⼆类是DOM0级事件,⽬前在PC端⽤的还是⽐较多的绑定事件⽅式,兼容性也好,主要是先获取dom元素,然后直接给dom元素添加事件(先获取dom元素,然后给他绑定事件)
例如:
var btn=document.getElementById(‘id元素’) btn.onclick=function() { //要处理的事件逻辑 }
DOM0事件如何移除呢?很简单:btn.οnclick=null;置为空就⾏ 优点:兼容性好 缺点:只⽀持冒泡,不⽀持捕获
-
第三类是DOM2级事件(利用addEventListener来绑定事件;removeEventListener来移除事件),移动端⽤的⽐较多,也有很多优点,提供了专⻔的绑定和移除⽅法例如:
var btn=document.getElementById(‘id元素’) //绑定事件 btn.addEventListener(‘click’,绑定的事件处理函数名,false) //移除事件 btn.removeEventListener(‘click’,要移除的事件处理函数名,false)
优点:⽀持给个元素绑定多个相同事件,⽀持冒泡和捕获事件机制
事件冒泡:从里到外
怎么阻止事件冒泡 vue和原生都得知道:e.stopPropagation();
捕获:从外到里
-
1.22 说说jQuery有哪些选择器和常⽤查找⽅法?
jQuery选择器有:
基本选择器 层级选择器 内容选择器 过滤选择器 属性过滤选择器 子元素过滤选择器 表单属性过滤选择器
1、查找后代和子元素
找到后代find()
直接子元素children()
2、查找祖先和父元素
祖先parents()
父元素parent()
3、查找所有同辈
Siblings()
4、查找紧跟后面的兄弟和后面所有的兄弟
Next()紧跟兄弟
nextAll()后面所有的兄弟
5、查找紧跟前面的兄弟以及前面所有的兄弟
Prev()紧跟前面的兄弟
prevAll()前面所有的兄弟
6、eq(index)根据索引找元素
- 基本
- #id element .class * selector1,selector2,selectorN
- 层次选择器:
- ancestor descendant parent > child prev + next prev ~ siblings
- 基本过滤器选择器
- :first :last :not :even :odd :eq :gt :lt :header :animated
- 内容过滤器选择器
- :contains :empty :has :parent
- 可⻅性过滤器选择器
- :hidden :visible
- 属性过滤器选择器
- [attribute] [attribute=value] [attribute!=value] [attribute^=value] [attribute$=value] [attribute*=value] [attrSel1][attrSel2][attrSelN]
- ⼦元素过滤器选择器
- :nth-child :first-child :last-child :only-child
- 表单选择器
- :input :text :password :radio :checkbox :submit :image :reset :button :file :hidden
- 表单过滤器选择器
- :enabled :disabled :checked :selected
常⽤查找⽅法有:
find() children() filtereq() parent() parents() cloest() …
1.23 判断JS数据类型的⽅法有哪些?
完美解决方案返回 [object …]
④ Object.prototype.toString.call();
console.log(Object.prototype.toString.call(1)); //[object Number] console.log(Object.prototype.toString.call(“1”)); //[object String] console.log(Object.prototype.toString.call(true)); //[object Boolean] console.log(Object.prototype.toString.call([])); //[object Array] console.log(Object.prototype.toString.call(function(){})); //[object Function] console.log(Object.prototype.toString.call({})); //[object Object]
1.24 for…in 迭代和 for…of 有什么区别
1、 推荐在循环对象属性的时候,使用 for…in,在遍历数组的时候的时候使用for…of。
2、for…in 循环出的是 key,for…of 循环出的是 value
3、for…of 不能循环普通的对象,需要通过和 Object.keys()搭配使用
三:网络安全
3.1web常见的攻击方式有哪些?如何防御?
Web攻击(WebAttack)是针对⽤户上⽹⾏为或⽹站服务器等设备进⾏攻击的⾏为如植⼊恶意代码,修改⽹站权限,获取⽹站⽤户隐私信息等等Web应⽤程序的安全性是任何基于Web业务的重要组成部分。
我们常⻅的Web攻击⽅式有:
-
XSS (Cross Site Scripting) 跨站脚本攻击
- XSS 即中⽂名称为:跨站脚本攻击。XSS的重点不在于跨站点,⽽在于脚本的执⾏。
- XSS的原理是: 恶意攻击者在web⻚⾯中会插⼊⼀些恶意的script代码。当⽤户浏览该⻚⾯的时候,那么嵌⼊到web⻚⾯中script代码会执⾏,因此会达到恶意攻击⽤户的⽬的。
-
CSRF(Cross-site request forgery)跨站请求伪造
- CSRF跨站请求伪造:攻击者诱导受害者进⼊第三⽅⽹站,在第三⽅⽹站中,向被攻击⽹站发送跨站请求
- 利⽤受害者在被攻击⽹站已经获取的注册凭证,绕过后台的⽤户验证,达到冒充⽤户对被攻击的⽹站执⾏某项操作的⽬
- 受害者登录a.com,并保留了登录凭证(Cookie)
- 攻击者引诱受害者访问了b.com
- b.com 向 a.com 发送了⼀个请求:a.com/act=xx。浏览器会默认携带a.com的Cookie
- a.com接收到请求后,对请求进⾏验证,并确认是受害者的凭证,误以为是受害者⾃⼰发送的请求
- a.com以受害者的名义执⾏了act=xx
- 攻击完成,攻击者在受害者不知情的情况下,冒充受害者,让a.com执⾏了⾃⼰定义的操作
- CSRF的特点
- 攻击⼀般发起在第三⽅⽹站,⽽不是被攻击的⽹站。被攻击的⽹站⽆法防⽌攻击发⽣
- 攻击利⽤受害者在被攻击⽹站的登录凭证,冒充受害者提交操作;⽽不是直接窃取数据
- 整个过程攻击者并不能获取到受害者的登录凭证,仅仅是“冒⽤”
- 跨站请求可以⽤各种⽅式:图⽚URL、超链接、CORS、Form提交等等。部分请求⽅式可以直接嵌⼊在第三⽅论坛、⽂章中,难以进⾏追踪
-
SQL注⼊攻击
- sql被攻击的原因是:sql语句伪造参数,然后对参数进⾏拼接后形成xss攻击的sql语句。最后会导致数据库被攻击了。
- 防范的⽅法:1. 我们可以使⽤预编译语句(PreparedStatement,这样的话即使我们使⽤sql语句伪造成参数,到了服务端的时候,这个伪造sql语句的参数也只是简单的字符,并不能起到攻击的作⽤。2. 数据库中密码不应明⽂存储的,可以对密码使⽤md5进⾏加密
四:网络相关
4.1说说地址栏输入URL敲下回车后发生了什么?
-
dns解析 解析到ip地址(将域名解析到IP地址,)
-
根据id地址访问服务器
-
发送 HTTP 请求
-
服务器收到请求返回数据
-
客户端的浏览器接受数据 渲染数据
\1. DNS 解析(将域名解析到IP地址)
\2. TCP 连接(找具体的文件,找到主机,找到文件,找静态文件。。。)
\3. 发送 HTTP 请求(请求服务器的IP地址)
\4. 服务器处理请求并返回需要的数据
\5. 浏览器解析渲染页面(找到HTML和css将它渲染成dom,将它重绘来渲染页面)
\6. 连接结束
-
URL解析
- ⾸先判断你输⼊的是⼀个合法的URL 还是⼀个待搜索的关键词,并且根据你输⼊的内容进⾏对应操作
-
DNS 查询
- 因特网上作为域名和地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的IP数串。通过主机名,最终得到该主机名对应的IP地址的过程叫做域名解析(或主机名解析)
-
TCP 连接
-
HTTP 请求
-
响应请求
-
⻚⾯渲染
2.6try用来解决asynchronous,await的问题在js中try用来捕获 (放网络请求可能会出错),catch(捕获错误)
2.7 mixin?
css
4.1. css动画
filter 过滤=》里面的参数可以有blur(就是模糊)
animation-name | 规定需要绑定到选择器的 keyframe 名称。。 |
---|---|
animation-duration | 规定完成动画所花费的时间,以秒或毫秒计。(3s) |
animation-timing-function | 规定动画的速度曲线。(linear) |
animation-delay | 规定在动画开始之前的延迟。(3s) |
animation-iteration-count | 规定动画应该播放的次数。(infinine无限循环,forwards到头停止) |
animation-direction | 规定是否应该轮流反向播放动画。 |
通过animation: linear(匀速) infint(无限循环)
用@keyframes来定义动画,from是开始状态,to是结束状态,通过animation来用(自动执行的动画)
transition(过渡动画,需要辅助操作)
过渡属性:tranfrom=>translate(位移,x轴y轴平移,会引起重绘),rotate(旋转),scale(缩放)
transform-origin:left bottom 设置旋转中心点
简写的姿势排序 @keyframes name : 动画名; duration 持续时间 ;timing-function 动画频率 ;delay 延迟多久开始 ;iteration-count 循环次数; direction 动画方式,往返还是正向 fill-mode 一般用来处理停留在某一帧 play-state running 开始,paused 暂停 …
4.2.H5新增特性和css3新增特性?
1.⾸先 html5 为了更好的实践 web 语义化,增加了 header,footer,nav,aside,section 等语义 化标签,
2.在表单⽅⾯,为了增强表单,为 input 增加了 color,email,data ,range 等类型,
3.在存储⽅⾯,提供了 sessionStorage,localStorage,和离线存储,通过这些存储⽅式⽅便数 据在客户端的存储和获取,
4.在多媒体⽅⾯规定了⾳频和视频元素 audio 和 vedio,另外还 有地理定位,canvas 画布,拖放,多线程编程的 web worker 和 websocket协议
5.css3新增特性: CSS3 边框如 border-radius,box-shadow 等; CSS3 背景如 background-size,background-origin 等; CSS3 2D,3D 转换如 transform 等; CSS3 动画如 animation 等,rgba,opacity,flex布局
display:flex; /*设置弹性盒子*/
flex-direction: /*设置弹性盒子方向;*/
flex-wrap:/*设置是否换行*/
justify-content:, /*设置主轴对齐方式;*/
align-items: /*设置侧轴对齐方式;*/
rgba背景透明,只作用于当前元素
opacity背景文字一起透明,具有继承性
transparent 是颜色的一种,这种颜色叫透明色
background-Origin属性指定background-position属性应该是相对位置。
4.3.BFC的理解?
理解:块级格式化上下文
BFC原理
1.内部的Box会在垂直方向,一个接一个地放置
2.在BFC垂直方向的边距会发生重叠
3.BFC的区域不会与float区域的box重叠
4.BFC是一个页面上的独立的容器,外面的元素不会影响bfc里的元素,反过来,里面的也不会影响外面的
5.计算BFC高度的时候,浮动元素也会参与计算
触发BFC
1.浮动元素,float 除 none 以外的值
2.定位元素,position(absolute,fixed) (破森申)(阿婆死楼特) (非渴死的)
3.display 为以下值 inline-block,table-cell,table-caption(卡普神)
4.overflow 除了 visible(v 则 包) 以外的值(hidden,auto,scroll)
使用场景 清除浮动,创建BFC
4.4说说你对盒模型的理解?
盒模型其实就是浏览器把⼀个个标签都看成⼀个矩形盒⼦,每个盒⼦都由:内容、内边距、边框、外边距四部分组成.
盒模型分为,标准盒模型和怪异盒模型
区别: 标准盒模型的宽高只包含内容,不包含其他部分
怪异盒模型的宽高包含了内容、内边距和边框部分
通过box-sizing属性设置盒模型
border-box //怪异盒模型content-box //标准盒模型
4.5如何实现元素⽔平垂直居中?
已知宽高
绝对定位 top:50%;left;50%;margin负的自身宽高的一半
未知宽高
绝对定位 上下左右(0)margin:auto;
父元素设置flex弹性盒,然后使用justify-content: center,align-items: center居中
4.6如何实现两栏布局,右侧⾃适应?三栏布局中间⾃适应呢?
两栏:方案一使用浮动
左侧盒子设置宽高进行左浮
右侧盒子margin-left:左侧盒子的宽度,width:auto
方案二使用flex布局
大盒子设置弹性盒子,里面左侧盒子设置固定宽度,右侧flex:1
三栏
方案一使用浮动
左侧盒子设置宽高进行左浮,右侧盒子设置宽高进行右浮
中间盒子width:auto,margin空出左右宽度
方案二使用flex布局
大盒子设置弹性盒子,里面左侧盒子设置固定宽度,中间flex:1,右侧盒子设置固定宽度
4.7CSS如何画⼀个三⻆形?原理是什么?
宽高设置为0,四个边框设置10px 实线 透明色,
然后三角形想要那个方向就给那个方向的边框添加颜色
原理:边框实际上并不是⼀个直线,如果我们将四条边设置不同的颜⾊,将边框逐渐放⼤,可以得到每条边框都是⼀个梯形,然后隐藏其 余三个边,就能得到一个三角形
4.8说说em/px/rem/vh/vw区别?
px:绝对单位,⻚⾯按精确像素展示
em:相对单位,相对于⽗节点的字体⼤⼩,如果⾃身定义了 font-size 按⾃身来计算,整个⻚⾯内1em 不是⼀个固定的值
rem:相对单位,相对根节点 html 的字体⼤⼩来计算
vh、vw:主要⽤于⻚⾯视⼝⼤⼩布局,在⻚⾯布局上更加⽅便简单
4.9css3动画
transition: 过渡动画transition-property: 属性
transition-duration: 间隔
transition-timing-function: 曲线
transition-delay: 延迟常用钩子:
transitionendanimation-name: 动画名称,对应@keyframes animation-duration: 间隔animation-timing-function: 曲线animation-delay: 延迟: 次数infinite: 循环动画: 方向alternate: 反向播放: 静止模式forwards: 停止时,保留最后一帧backwards: 停止时,回到第一帧both: 同时运用 forwards / backwards常用钩子: animationend动画属性: 尽量使用动画属性进行动画,能拥有较好的性能表现translate scale rotate skew opacity color
4.10 display:none与visibility:hidden的区别?
display:none 不显示对应的元素,在文档布局中不再分配空间(回流+重绘)
visibility:hidden 隐藏对应元素,在文档布局中仍保留原来的空间(重绘)
( 回流:从新加载页面
重绘:重新调用css
区别:回流必将引起重绘,而重绘不一定会引起回流。)
4.11、文字超出隐藏
overflow:hidden; //文字超出隐藏
text-overflow:ellipsis;//用省略号“…”隐藏超出范围的文本
white-space:nowrap;//超出不换行
-webkit-line-clamp: 2;/*用来限制在一个块元素显示的文本的行数。*/
-webkit-box-orient: vertical;/*必须结合的属性 ,设置或检索伸缩盒对象的子元素的排列方式 。*/
4.12 、渐进增强,优雅降级 (-webkit兼容低版本浏览器,没有-webkit就是兼容高版本浏览器)
优雅降级:先写最新版本的浏览器的外观样式,再考虑兼容问题,兼容旧版本的浏览器(兼容旧版本浏览器有-webkit的样式);
渐进增强:先保证基本功能的实现,再考虑样式问题,兼容新版本的浏览器(新版本浏览器没有-webkit)
4.13、什么是css hack? ie6,7,8的hack分别是什么?
答案:针对不同的浏览器写不同的CSS code的过程,就是CSS hack。
示例如下:
#test{
background-color:yellow; /ie8/ (感叹号!)
+background-color:pink; /ie7/ (加号+)
background-color:orange; /ie6/ } (下划线)
更好的方式是使用IE条件判断语句:
<!–[if lte IE 6]>
内容
<![endif]–>
等
什么是CSS Hack?
CSS hack是通过在CSS样式中加入一些特殊的符号,让不同的浏览器识别不同的符号(什么样的浏览器识别什么样的符号是有标准的,CSS hack就是让你记住这个标准),以达到应用不同的CSS样式的目的。
Hack常见的有三种形式:
CSS属性Hack、CSS选择符Hack以及IE条件注释Hack, Hack主要针对IE浏览器。
1、属性级Hack:比如IE6能识别下划线“_
”和星号“*
”,IE7能识别星号“*
”,但不能识别下划线”_
”,而firefox两个都不能认识。
2、选择符级Hack:比如IE6能识别*html .class{}
,IE7能识别*+html .class{}
或者*:first-child+html .class{}
。
3、IE条件注释Hack:IE条件注释是微软IE5开始就提供的一种非标准逻辑语句。比如针对所有IE:<!-[if IE]><!-您的代码-><![endif]>
,针对IE6及以下版本:<!-[if it IE 7]><!-您的代码-><![endif]->
,这类Hack不仅对CSS生效,对写在判断语句里面的所有代码都会生效。
PS:条件注释只有在IE浏览器下才能执行,这个代码在非IE浏览下被当做注释视而不见。可以通过IE条件注释载入不同的CSS、JS、HTML和服务器代码等。
4.14、rgba、opacity、transparent透明效果有什么区别?
rgba背景透明,只作用于当前元素
opacity背景文字一起透明,具有继承性
transparent 是颜色的一种,这种颜色叫透明色
4.15、position的值有哪些?
static: 静态定位 默认值
relative:相对定位
absolute:绝对定位
fixed:固定定位
4.16、CSS3 新增伪类选择器有哪些?
p:first-of-type /选择属于其父元素的首个元素/
p:last-of-type /选择属于其父元素的最后元素/
p:only-of-type /选择属于其父元素唯一的元素/
:nth-of-type(n) 匹配第n个同类型的元素
:nth-child(n) 匹配第n个元素
4.17、css的渐变为为几种
-
线性渐变 向下/向上/向左/向右/对角方向
background-image: linear-gradient(direction, color-stop1, color-stop2, ...);
-
径向渐变 由它们的中心定义
background-image: radial-gradient(shape size at position, start-color, ..., last-color);
4.18、rgba()和opacity的透明效果有什么区别?
rgba()和opacity都能实现透明效果,但最大的不同是opacity作用于元素,以及元素内的所有内容的透明度,而rgba()只作用于元素的颜色或起背景色
设置rgba透明的元素的子元素不会继承透明效果
4.19、flex布局
display:flex; /设置弹性盒子/
flex-direction: /设置弹性盒子方向;/row(默认)行 | column 纵向
flex-wrap:/设置是否换行/nowrap(默认)不换行 | wrap换行
justify-content:, /设置主轴对齐方式;
/ flex-start(默认) | center | space-between | space-around ;
align-items: /设置侧轴对齐方式;
/flex-start | flex-end | center | baseline | stretch(默认)
**flex : 1 ;**宽高自适应
4.20、一个页面中有大量的图片(大型电商网站),加载很慢,你有哪些方法优化这些图片的加载,给用户更好的体验
图片懒加载
如果图片为css图片,可以使用CSSsprite,SVGsprite,Iconfont、Base64等技术。
vue相关
1. MVC、MVP与MVVM模式
MVC:
MVC是应用最广泛的软件架构之一,
一般MVC分为:Model( 模型 )、Controller( 控制器 )、View( 视图 )。这主要是基于分层的目的,让彼此的职责分开。View 一般通过 Controller 来和 Model 进行联系。Controller是 Model 和 View 的协调者,View和Model不直接联系。基本联系都是单向的。
1、View 传送指令到 Controller
2、Controller 完成业务逻辑后,要求 Model 改变状态
3、Model 将新的数据发送到 View,用户得到反馈
MVP:
MVP 模式将 Controller 改名为 Presenter,同时改变了通信方向。
1、各部分之间的通信,都是双向的。
2、View 与 Model 不发生联系,都通过 Presenter 传递【。
3、View 非常薄,不部署任何业务逻辑,称为"被动视图"(Passive View),即没有任何主动性,而 Presenter非常厚,所有逻辑都部署在那里。
MVVM :
MVVM 是把 MVC 的 Controller 和 MVP 的 Presenter 改成了 ViewModel。
View 的变化会自动更新到 ViewModel,ViewModel 的变化也会自动同步到 View上显示。这种自动同步是因为 ViewModel 中的属性实现了 Observer,当属性变更时都能触发对应的操作。
MVVM与MVC:
MVVM:双向数据绑定,响应式更新,脱离了查找数据的麻烦(view代表了视图层)=》(直接更新试图,双向绑定减少dom操作,性能提高)
MVC:单向数据流(angla或者jquery)
2 .MVVM模式的优点以及与MVC模式的区别
MVVM模式的优点:
1、低耦合:视图(View)可以独立于 Model 变化和修改,一个 ViewModel 可以绑定到不同的"View"上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。
2、可重用性:你可以把一些视图逻辑放在一个ViewModel里面,让很多 view 重用这段视图逻辑。
3、独立开发:开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计。
4、可测试:界面素来是比较难于测试的,而现在测试可以针对ViewModel来写。
MVVM 和 MVC 的区别:
mvc 和 mvvm 其实区别并不大。都是一种设计思想。
主要区别
mvc 中 Controller演变成 mvvm 中的 viewModel,mvvm 通过数据来显示视图层而不是节点操作。mvvm主要解决了: mvc中大量的DOM 操作使页面渲染性能降低,加载速度变慢,影响用户体验。
MVVM缺点:是单页面,(SSR通过服务器渲染每个路由组件渲染每个页面,一个页面生成多个页面)
3.常见的实现MVVM数据绑定的做法有哪些?
实现数据绑定的做法有大致如下几种:
发布者-订阅者模式(backbone.js)脏值检查(angular.js)数据劫持(vue.js)
发布者-订阅者模式:
般通过sub, pub的方式实现数据和视图的绑定监听,更新数据方式通常做法是 vm.set(‘property’, value)。这种方式现在毕竟太low了,我们更希望通过 vm.property = value这种方式更新数据,同时自动更新视图,于是有了下面两种方式。
脏值检查:
angular.js 是通过脏值检测的方式比对数据是否有变更,来决定是否更新视图,
最简单的方式就是通过 setInterval() 定时轮询检测数据变动,
angular只有在指定的事件触发时进入脏值检测,
数据劫持:
vue.js 则是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
4.Object.defineProperty()方法的作用是什么?
Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。
语法:
Object.defineProperty(obj, prop, descriptor)
参数说明:
obj:必需。目标对象
prop:必需。需定义或修改的属性的名字
descriptor:必需。目标属性所拥有的特性
返回值:
传入函数的对象。即第一个参数obj
针对属性,我们可以给这个属性设置一些特性,比如是否只读不可以写;是否可以被for…in或Object.keys()遍历。
给对象的属性添加特性描述,目前提供两种形式:数据描述和存取器描述。
5. vue.js的两个核心是什么?
数据驱动,也叫双向数据绑定。
Vue.js数据观测原理在技术实现上,利用的是ES5Object.defineProperty和存储器属性: getter和setter(所以只兼容IE9及以上版本),可称为基于依赖收集的观测机制。核心是VM,即ViewModel,保证数据和视图的一致性。
组件系统。
.vue组件的核心选项:
1、模板(template):模板声明了数据和最终展现给用户的DOM之间的映射关系。
2、初始数据(data):一个组件的初始数据状态。对于可复用的组件来说,这通常是私有的状态。
3、接受的外部参数(props):组件之间通过参数来进行数据的传递和共享。
4、方法(methods):对数据的改动操作一般都在组件的方法内进行。
5、生命周期钩子函数(lifecycle hooks):一个组件会触发多个生命周期钩子函数,最新2.0版本对于生命周期函数名称改动很大。
6、私有资源(assets):Vue.js当中将用户自定义的指令、过滤器、组件等统称为资源。一个组件可以声明自己的私有资源。私有资源只有该组件和它的子组件可以调用。等等。
6.生命周期
6.1 什么是vue生命周期?
Vue实例有一个完整的生命周期,也就是从开始创建、初始化数据、编译模板、挂载Dom、渲染→更新→渲染、销毁等一系列过程,我们称这是Vue的生命周期。通俗说就是Vue实例从创建到销毁的过程,就是生命周期。
6.2 vue生命周期钩子函数都有哪些?分别是什么意思?
总共分为8个阶段创建前/后,载入前/后,更新前/后,销毁前/后。
- 创建前/后: 在beforeCreated阶段,vue实例的挂载元素el还没有。在created阶段,vue实例的数据对象data有了,el还没有.
- 载入前/后:在beforeMount阶段,vue实例的$el和data都初始化了,但还是挂载之前为虚拟的dom节点,data.message还未替换。在mounted阶段,vue实例挂载完成,data.message成功渲染。
- 更新前/后:当data变化时,会触发beforeUpdate和updated方法。
- 销毁前/后:在执行destroy方法后,对data的改变不会再触发周期函数,说明此时vue实例已经解除了事件监听以及和dom的绑定,但是dom结构依然存在
6.3 vue生命周期的作用是什么?
生命周期中有多个事件钩子,让我们在控制整个 vue 实例的过程时更容易形成好的逻辑.
6.4 第一次页面加载会触发哪几个钩子?
第一次加载会触发 beforeCreate、created、beforeMount、mounted
6.5 简述每个周期具体适合哪些场景?
生命周期钩子的一些使用方法:
- beforecreate : 可以在这加个loading事件,在加载实例时触发
- created : 初始化完成时的事件写在这里,如在这结束loading事件,异步请求也适宜在这里调用
- mounted : 挂载元素,获取到DOM节点 updated : 如果对数据统一处理,在这里写上相应函数
- beforeDestroy : 可以做一个确认停止事件的确认框 nextTick : 更新数据后立即操作dom
6.6 created和mounted的区别?
- created:在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图。
- mounted:在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作。
6.7 vue获取数据在哪个周期函数?
- 看实际情况,一般在 created(或beforeRouter) 里面就可以,如果涉及到需要页面加载完成之后的话就用 mounted。
- 在created的时候,视图中的html并没有渲染出来,所以此时如果直接去操作html的dom节点,一定找不到相关的元素
- 而在mounted中,由于此时html已经渲染出来了,所以可以直接操作dom节点,(此时document.getelementById 即可生效了)
3.父组件和子组件之间的生命周期执行顺序
初次渲染就会触发的生命周期:
- beforeCreate() , created()
- beforeMount() , mounted()
组件的调用顺序都是先父传子,渲染完成的顺序是先子传父。组件的销毁操作是先父后子,销毁完成的顺序是先子后父。
加载渲染过程 子组件在父组件的beforeMount和Mounted之间渲染
父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
子组件更新过程
父beforeUpdate->子beforeUpdate->子updated->父updated
父组件更新过程
- 影响到子组件: - 父beforeUpdate -> 子beforeUpdate->子updated -> 父updted
- 不影响子组件: - 父beforeUpdate -> 父updated
销毁过程
- 父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
4.如何理解vue中的单向数据流
\1. Vue 的单向数据流:
指数据一般从父组件传到子组件,子组件没有权利直接修改父组件传来的数据,即子组件从 props 中直接获取的数据,只能请求父组件修改数据再传给子组件。父级属性值的更新会下行流动到子组件中。
\2. 为什么不能子组件直接修改父组件传来的值呢?
不可以改变,组件会被复用,vue有单向数据流。(如果一定要改变,可以对原数据深拷贝一份,不改变原数据)
父组件的值可能会不断发生变化,那么如果我们子组件对父组件传来的值比如说 props 有一个 number,子组件收到了 number=1,在收到后,子组件直接改变number 的值为 5,去做些事情,但还未做时父组件数据更新了,传过来一个值 3,也就是说子组件刚将其变为 5,父组件又把它变成了 3,可能影响子组件的使用。说的官方一些,就是父组件的值更新时,子组件中 props 的值也会发生更新。
\3. 在子组件中直接用 v-model 绑定父组件传过来的数据是不合理的,如果希望修改父组件传给子组件的值:
(1)在子组件 data 中创建一个变量获取 props 中的值,再改变这个 data 中的值。
(2)子组件使用 $emit 发出一个事件,让父组件接收去修改这个值。
5. vue中用过哪些修饰符?这两个什么 意思 .sync .lazy
.sync 修饰符 其实就是一个语法糖
- vue中 :子组件不能修改props 外部数据
- vue中: $emit 可以触发事件并传参
- vue中: $event可以获取 $emit 的参数
6. created 和 mounted的应用场景
mounted主要做渲染(已经可以看到dom了)。
网络请求,直接渲染
因此,在created
中,是无法进行DOM操作的,而mounted
可以获取渲染出来的所有属性值。
created:在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图。
mounted:在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作。
7.https://blog.csdn.net/crazyxiaoyuge/article/details/108322400 mixins用法,如果遇到同名方法和data属性,优先级是组件的高
8. 在组件中为什么data是函数不是对象?
data:独立空间,防止作用域的污染。
Vue 中的 data 是一个对象类型,对象类型的数据是按 引用传值
的。这样会导致所有组件的实例都 共享
同一份数据,这是不对的,我们要的是每个组件实例都是独立的所以为了解决对象类型数据共享的问题,我们需要将 data 定义成一个函数,每个实例需要通过调用函数生成一个独立的数据对象
9.伪类与伪选择器,伪元素
10. 重排,重绘
浮动float会引起重排(整个dom的渲染)
定位引起重排(消耗性能大)
背景元素,宽高=》重绘
11 $set
12. 如何实现链式调用
了解vue3嘛,说下大概用法?双向绑定vue2和vue3的区别
vue项目中,接手别人代码的,如何去分析?
vue如何调试,js如何调试
13. unpoud背后是:
14.真实DOM:前期的document,creatment等等都是真实Dom,比较消耗性能。
虚拟DOM:通过vue把它编译成真实dom,=>方法中有(标签,属性,子属性)=》通过appendchild追加到真实的页面上=>好处:就是diff算法
diff算法:较、真实dom与xunidom的差异,结合虚拟DOM性能高。(diff算法的核心是:patch)
js构建真正DOM;当某一个节点变更时,(patch函数需要两个参数)
15. 如果使用history路由,就要使用nginx反向代理软件:帮我们把监听端口号指向指定不同的网站(也可以配置跨域 属性:proxy_pass )
vue.confg.js中的跨域只在开发阶段使用,在上线阶段就不好使了
16.vue中如何实现动画?
transtion标签=》属性:通过name属性来定义,在名字里面写属性=》
17. 前端实现的分页
就是后台返回所有的数据,没有返回页数,就用total除以pagesize。
18.
前端。。。
19.跨域
开发环境下:代理
代理(Proxy)也称⽹络代理,是⼀种特殊的⽹络服务,允许客户端通过这个服务与服务器进⾏⾮直接的连接。⼀些⽹关、路由器等⽹络设备具备⽹络代理功能。⼀般认为代理服务有利于保障⽹络终端的隐私或安全,防⽌攻击
上线环境下:cors(后端把Access-Control-Allow-Origin加*)
CORS (Cross-Origin Resource Sharing,跨域资源共享)是⼀个系统,它由⼀系列传输的HTTP头组成,这些HTTP头决定浏览器是否阻⽌前端 JavaScript 代码获取跨域请求的响应。CORS 实现起来⾮常⽅便,只需要增加⼀些 HTTP 头,让服务器能声明允许的访问来源只要后端实现了 CORS,就实现了跨域
运维/后台:反向代理跨域 在服务器配置一个基地址
jsonp:get请求,后台返回jsonp的一个格式。这就是jsonp
script的src属性不受同源策略的限制;将不同源的服务器端请求地址写在 script 标签的 src 属性中,get请求
JSONP(JSON with Padding)是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题
代理跨域:通过node来提供一个服务
如果使用history路由,就要使用nginx反向代理软件:帮我们把监听端口号指向指定不同的网站(也可以配置跨域 属性:proxy_pass )
vue.confg.js中的跨域只在开发阶段使用,在上线阶段就不好使了
20 组件递归
必须要有name名字属性,
必须要有退出条件if条件(v-if)
21. 双向绑定?
vue的双向绑定分为vue2的双向绑定及vue3的双向绑定
vue2的object.defineProperty
vue2的双向绑定用object.defineProperty来实现数据的双向绑定;而vue3采用Proxy来实现数据的双向绑定。这两种双向绑定都是基于数据劫持来实现的。
数据劫持就是当访问或者是设置对象属性时,来触发相应的函数,并且返回设置属性的值。
数据劫持的优势:不需要进行显式调用,vue的双向绑定原理就是基于数据劫持+发布者订阅者模式来实现的;通过属性的劫持,可以精准获得变化的内容,这部分不需要额外的diff操作,减少性能的消耗。
vue3的proxy
- 直接监听对象⽽⾮属性;
- 直接监听数组的变化;
- Proxy返回⼀个新对象,可以只操作新对象达到⽬的,⽽Object.defineProperty只能遍历对象属性直接修改(需要⽤深拷⻉进⾏修改)
- Proxy作为新标准将受到浏览器⼚商重点持续的性能优化。
- 相比于vue2.x,使用proxy的优势如下
- 1 defineProperty只能监听某个属性,不能对全对象监听
- 2 可以省去for in、闭包等内容来提升效率(直接绑定整个对象即可)
- 3 可以监听数组,不用再去单独的对数组做特异性操作
- vue3.x可以检测到数组内部数据的变化
小程序
6.1 小程序的code码:相当于手机号的验证码,有效期只有5分钟
6.2、微信appid、openid、unionid的区别和关联
appid
application identification (简称appid)
翻译一下就是某个应用的标识(id)
比如说在一个公众号主体下 你不仅可以拥有h5网站,小程序,小游戏,企业微信等等,这些都有一个单独的appid
openid
每一个应用下面每一个用户下都有一个唯一的openid,用来标识此用户在此应用下面的身份标识(类型用户表里面的唯一主键)
unionid
同一主体下,不同的应用他们之间确定唯一身份的标识就是unionid
三者关系
就好比电信,联通,移动等价于appid
你在他们旗下都拥有一个手机号,这个手机号等价于openid
但是你如果想确认这3个手机号都是同一人,只能通过身份证来确认,身份证等价于unionid
6.3 wx.re…(重定向页面)
6.4 小程序如何实现一个promise的封装?
export default({url, data}) => {
return new Promise((resolve, reject) => {
wx.request({
url,
data,
header: {},
success: res => {
resolve(res)
},
fail: err => {
reject(err)
}
})
})
}
//先new一个promise对象,里面resolve跟reject两个对象,箭头返回wx.request()方法,里面有url,data数据,headers头协议,还有success成功后的回调以及fail失败后的回调,如果成功就用resolve返回数据,失败就用reject返回失败的回调。
面试题
5.2 style-loader
帮我们把打包文件转化为数据流的格式
5.3 cookie由服务器产生,发送到客户端,(客户端存储到本地cookie)
通过settoken发送到后端
5.4 post传输体。传输方式?
5.5了解nginx嘛,说说nginx它有什么作用?nginx是反向代理软件,它可以监听不同端口ip地址指向服务器里不同目录,达到同一个ip地址不同端口号访问不同网站目的。
1.具体配置有 server {
listen 80; # 监听的端口
server_name 117.112.115.208; # 你的域名或ip
location / { # 访问路径配置
root /www/wwwroot/test; # 服务器里对应的网站目录
try_files $uri $uri/ /index.html; # 此处可以配置history模式对应路径
index index.html index.htm; # 默认首页
}
- nginx它还可以配置上线跨域
location /api/ { # 代理路径跟你项目里一致
proxy_pass http://106.15.179.105/api; # 具体代理哪个跨域地址,相当于vue.config.js里devsever里的target
}
5.5了解nginx嘛,说说nginx它有什么作用?nginx是反向代理软件,它可以监听不同端口ip地址指向服务器里不同目录,达到同一个ip地址不同端口号访问不同网站目的。
1.具体配置有 server {
listen 80; # 监听的端口
server_name 117.112.115.208; # 你的域名或ip
location / { # 访问路径配置
root /www/wwwroot/test; # 服务器里对应的网站目录
try_files $uri $uri/ /index.html; # 此处可以配置history模式对应路径
index index.html index.htm; # 默认首页
}
- nginx它还可以配置上线跨域
location /api/ { # 代理路径跟你项目里一致
proxy_pass http://106.15.179.105/api; # 具体代理哪个跨域地址,相当于vue.config.js里devsever里的target
}
5.6双向绑定的原理 -设计模式-发布订阅者模式的原理
Object.defineProperty(
set:function(
){}, //设置值
get:fucion(){} //直接就能获取到值?采用的-发布订阅者模式。
)
https://www.cnblogs.com/TomXu/archive/2012/03/02/2355128.html
5.7本地存储如何设置过期时间?
在添加本地存储的时候,加入时间字段,取出来时,用 当前时间 - 存入时间 >= 自定义过期时间 示例:
localStorage.setItem(‘cates’, { time: Date.now(), data: this.data.cates })
if (Date.now() - cates.time > 1000 * 300 == true)
5.8对数据量大不常更新的数据进行缓存处理?
-请求成功后存储数据,页面加载时读取数据,如果时间过期,重新请求数据。明天实现对分类数据的缓存
5.9Cookie是由服务器端生成,发送给用户端User-Agent,浏览器会将Cookie的key/value保存到本地电脑某个目录下的文本文件内,下次请求同一网站时就发送该Cookie给服务器。
5.10 微信支付开通流程
(ps:注意:想要上线使用微信支付,必须要是公司账号微信认证过的!)
一: 微信公众平台-登录老板(公司)账号-微信认证(具有公司资质的)
二: 申请微信商户号-用老板微信扫描申请-公司(上传公司资质)-申请下来-登陆老板开发者账号-填加老板的appid账号或者开发者appid与商户号关联起来
三.微信公众平台-登录老板(公司)账号-成员管理-填加自己的微信小程序账号appid(开发权限)
https://blog.csdn.net/itxiaolong3/article/details/104365892 微信支付商户号申请流程
5.11 vue 中 的 $nextTick 和settimeout执行顺序?
事件循坏vent Loop中,每一次循环称为tick,每一次tick的任务如下:
执行栈选择最先进入队列的宏任务(一般都是script),执行其同步代码直至结束;
检查是否存在微任务,有则会执行至微任务队列为空;
如有必要会渲染页面;
开始下一轮tick,执行宏任务中的异步代码(setTimeout的回调等)。
<br>
宏任务与微任务
宏任务(macrotask)
宿主(Node、浏览器)发起的任务;
在ES6规范中,将其称为task;
script、setTimeout、setInterval、I/O、UI rendering、postMessage、MessageChannel、setImmediate
微任务(microtask)
JS引擎发起的任务;
在ES6规范中,将其称为jobs;
Promise、MutaionObserver、process.nextTick
// 先执行同步在执行异步 => 执行$nextTick返回promise,执行timeout (promise比timeout快)
// 事件循环机制: 同步 => 微任务 => 渲染页面 => 开始下一轮,执行宏任务中的异步代码(setTimeout的回调等)
// 为什么promise比timeout快 https://blog.csdn.net/weixin_34365635/article/details/91421326
// 1. start
// 2. end
// 3. nextTick
// 4. nextTick2
// 5.nextTick2
// 6.timeout
// 7.timeout2
5.12 后台管理系统中的权限管理是怎么实现的?
登录:
登录:当用户填写完账号和密码后向服务端验证是否正确,验证通过之后,服务端会返回一个token,拿到token之后(我会将这个token存贮到cookie中,保证刷新页面后能记住用户登录状态),前端会根据token再去拉取一个 user_info 的接口来获取用户的详细信息(如用户权限,用户名等等信息)。
权限验证:
权限验证:通过token获取用户对应的 权限,动态根据用户的 权限算出其对应有权限的路由,通过 router.addRoutes 动态挂载这些路由。具体思路:咱们写那个后台管理系统登录成功后,服务端会返回一个 token(该token的是一个能唯一标示用户身份的一个key),之后我们将token存储在本地存储中之中,这样下次打开页面或者刷新页面的时候能记住用户的登录状态,不用再去登录页面重新登录了。
注意:
ps:为了保证安全性,我公司现在后台所有token有效期都是Session,就是当浏览器关闭了就丢失了。重新打开游览器都需要重新登录验证,后端也会在每周固定一个时间点重新刷新 token,让后台用户全部重新登录一次,确保后台用户不会因为电脑遗失或者其它原因被人随意使用账号。
用户登录成功之后,我们会在全局钩子 router.beforeEach 中拦截路由,判断是否已获得token,在获得token之后我们就要去获取用户的基本信息了页面会先从 cookie 中查看是否存有 token,没有,就走一遍上一部分的流程重新登录,如果有token, 就会把这个 token 返给后端去拉取user_info,保证用户信息是最新的。 当然如果是做了单点登录得功能的话,用户信息存储在本地也是可以的。当你一台电脑登录时,另一台会被提下线,所以总会重新登录获取最新的内容。
先说一说我权限控制的主体思路,前端会有一份路由表,它表示了每一个路由可访问的权限。当用户登录之后,通过 token 获取用户的 role ,动态根据用户的 role 算出其对应有权限的路由,再通过 router.addRoutes 动态挂载路由。但这些控制都只是页面级的,说白了前端再怎么做权限控制都不是绝对安全的,后端的权限验证是逃不掉的。我司现在就是前端来控制页面级的权限,不同权限的用户显示不同的侧边栏和限制其所能进入的页面(也做了少许按钮级别的权限控制),后端则会验证每一个涉及请求的操作,验证其是否有该操作的权限,每一个后台的请求不管是 get 还是 post 都会让前端在请求 header 里面携带用户的 token,后端会根据该 token 来验证用户是否有权限执行该操作。若没有权限则抛出一个对应的状态码,前端检测到该状态码,做出相对应的操作。使用vuex管理路由表,根据vuex中可访问的路由渲染侧边栏组件。
具体实现:
具体实现:创建vue实例的时候将vue-router挂载,但这个时候vue-router挂载一些登录或者不用权限的公用的页面。当用户登录后,获取用role,将role和路由表每个页面的需要的权限作比较,生成最终用户可访问的路由表。调用router.addRoutes(store.getters.addRouters)添加用户可访问的路由。使用vuex管理路由表,根据vuex中可访问的路由渲染侧边栏组件。
5.13 后端接口 管理平台
show doc 接口平台
swagger 接口平台(java后台)
5.14 jsonp通过动态生成脚本标签,里面放置src标签(=》原理)(生成script标签,追加到body中,数据通过window…)
5.15 通过resize自动改变图标的大小
5.16 websocket让我们的接口实时请求,还不影响性能,让接口轮询。
首页,分类,搜索,我的,详情(加入购物车)
5.17 分配权限的思路
分配角色-思路1.点击时显示弹框,拿当前行数据(可通过作用域插槽传过来),进行回显 2.下拉列表,select绑定父数据,option子项绑定value,获取当前下拉值 ,下拉改变事件,用@change,来获取每个id 3.提交接口-获取用户id,角色id
5.18 动画animation与transform的区别
一个是自动执行(animation),一个是手动执行(transform过渡)
5.19 设计模式
发布订阅者模式 mvvm
5.20 首屏优化?
在vue.config.js中:
publicPath:’./’;
console.log()去除(配置的插件)
chainWebpack中,如果是开发环境,把项目中用过的别名和包名抽离出来,不打包(如此体积就小了 )
路由懒加载:都会打包到app文件,把首页不需要的路由单独打包出来。
通过路由动态导入 (引导webpack动态导入)
开启图片资源的压缩
通过NODE_ENV区分开发环境与生产环境(新建.env.development与.env.production文件)
5.21 vue3 hooks响应式更新
5, webSocket 保持连接,实时刷新更新数据,不损耗性能
5.22 常见的版本控制工具
1. Git
Git是目前世界上最先进的分布式版本控制系统,使用Git和Gitlab搭建版本控制环境是现在互联网公司最流行的版本控制方式
简介:
Git是一个免费的开源分布式版本控制系统,旨在快速高效地处理从小型到大型项目的所有事务。
Git易于学习,占用内存小,具有闪电般快速的性能。
2. SVN
TortoiseSVN是一款非常易于使用的跨平台的 版本控制/版本控制/源代码控制软件。它基于Apache Subversion(SVN)® ; TortoiseSVN为Subversion提供了一个简单易用的用户界面。
3. HG
Mercurial是一个免费的分布式源代码管理工具。它可以有效地处理任何规模的项目,并提供简单直观的界面。Mercurial 是一种轻量级分布式版本控制系统,采用 Python 语言实现,易于学习和使用,扩展性强。
4. CVS–Concurrent Versions System,
CVS是版本控制系统,是源配置管理(SCM)的重要组成部分。使用它,您可以记录源文件和文档的历史记录。老牌的版本控制系统,它是基于客户端/服务器的行为使得其可容纳多用户,构成网络也很方便。这一特性使得CVS成为位于不同地点的人同时处理数据文件(特别是程序的源代码)时的首选。
1.更轻松的管理。传统的版本控制系统使用集中式的 repository,一些和repository
相关的管理就只能由管理员一个人进行。由于采用了分布式的模型,Mercurial 中就没有这样的困扰,每个用户管理自己的 repository
,管理员只需协调同步这些repository
。
2.更健壮的系统。分布式系统比集中式的单服务器系统更健壮,单服务器系统一旦服务器出现问题整个系统就不能运行了,分布式系统通常不会因为一两个节点而受到影响。
3.对网络的依赖性更低。由于同步可以放在任意时刻进行,Mercurial 甚至可以离线进行管理,只需在有网络连接时同步。
5. VSS-- Visual Source Safe
此工具是Microsoft提供的,是使用的相当普遍的工具之一,他可以与VS.net进行无缝集成,成为了独立开发人员和小型开发团队所适合的工具,基本上Window平台上开发的中小型企业,当规模较大后,其性能通常是无法忍受的,对分支与并行开发支持的比较有限。
其相关的外挂支持工具为SAW,SOS.
5.23 扩展运算符与rest剩余参数什么意思,及其应用场景。
1. 扩展运算符 …
可以将一个数组转为用逗号分隔的参数序列。把一个大元素给打散成一个个单独的小元素。
1.1 某些场景可以替代apply
在使用Math.max()求数组的最大值时,ES5可以通过 apply 做到(不友好且繁琐的方式);
扩展运算符可用于数组的析构,优雅的解决了这个问题。
1.2 代替数组的push、concat 等方法
1.3 拷贝数组或对象
无论是像克隆数组还是对象,先用化骨绵掌之扩展运算符,将其打散,之后再拼装的到一起就可以了,多么简单易用。
1.4 将伪数组转化为数组
扩展运算符可以将一个类似数组的对象将其转为真正的数组,原因就在于 NodeList 对象实现了 Iterator。
注意:使用扩展运算符将伪数组转换为数组有局限性,这个类数组必须得有默认的迭代器且伪可遍历的。
2. rest 剩余参数
rest元素和展开元素相反,展开元素会“展开”数组变成多个元素,剩余元素会收集多个元素和“压缩”成一个
单一的元素。
说的通俗点,有点像吸星大法,收集多个元素,压缩成单一的元素 。
rest参数用于获取函数的多余参数,这样就不需要使用arguments对象了。rest参数搭配的变量是一个数组,该变
量将多余的参数放入数组中。
2.1 rest 参数代替arguments变量
2.2 与解构赋值组合使用
总结:
1 . 扩展运算符和rest运算符是逆运算
扩展运算符:数组=>分割序列
rest运算符:分割序列=>数组
2. 扩展运算符应用场景
由于其繁琐的语法,apply 方法使用起来并不是很方便。当需要拿一个数组的元素作为函数调用的参数时,
扩展运算符是一个不错的选择。
扩展运算符还改善了数组字面量的操作,你可以更方便的初始化、连接、复制数组了。
使用析构赋值你可以提取数组的一部分。通过与迭代器协议的组合,你可以以一种更灵活的方式使用该表达式。
3. rest运算符应用场景
rest运算符主要是处理不定数量参数,rest参数使得收集参数变得非常简单。它是类数组对象arguments一个合理的替代品。
rest参数还可以与解构赋值组合使用。
在实际项目中灵活应用扩展运算符、rest运算符,能写出更精简、易读性高的代码。
5.24 es6新增的数据结构Set,Map代表什么意思
Set
是一种叫做集合的数据结构,Map
是一种叫做字典的数据结构
1. Set
Set
是es6
新增的数据结构,类似于数组,但是成员的值都是唯一的,没有重复的值,我们一般称为集合
Set
本身是一个构造函数,用来生成 Set 数据结构
const s = new Set();
5.24.1.1 增删改查
Set
的实例关于增删改查的方法:
- add()
- delete()
- has()
- clear()
add
添加某个值,返回 Set
结构本身
当添加实例中已经存在的元素,set
不会进行处理添加 如: s.add(1).add(2).add(2); // 2只被添加了一次
delete
删除某个值,返回一个布尔值,表示删除是否成功 如:s.delete(1)
has()
返回一个布尔值,判断该值是否为Set
的成员 如:s.has(2)
clear()
清除所有成员,没有返回值 如:s.clear()
5.24.1.1 遍历
Set实例遍历的方法有如下:
关于遍历的方法,有如下:
keys():返回键名的遍历器
values():返回键值的遍历器
entries():返回键值对的遍历器
forEach():使用回调函数遍历每个成员
Set的遍历顺序就是插入顺序
keys方法、values方法、entries方法返回的都是遍历器对象
forEach()`用于对每个成员执行某种操作,没有返回值,键值、键名都相等,同样的`forEach`方法有第二个参数,用于绑定处理函数的`this
扩展运算符和Set
结构相结合实现数组或字符串去重
实现并集、交集、和差集
2. Map
Map
类型是键值对的有序列表,而键和值都可以是任意类型
Map
本身是一个构造函数,用来生成 Map
数据结构 如: const m = new Map()
增删改查
Map
结构的实例针对增删改查有以下属性和操作方法:
- size 属性
- set()
- get()
- has()
- delete()
- clear()
size
size
属性返回 Map 结构的成员总数。
set()
设置键名key
对应的键值为value
,然后返回整个 Map 结构
如果key
已经有值,则键值会被更新,否则就新生成该键
同时返回的是当前Map
对象,可采用链式写法
get()
get方法读取
key对应的键值,如果找不到
key,返回
undefined
has()
has
方法返回一个布尔值,表示某个键是否在当前 Map 对象之中
delete()
delete方法删除某个键,返回
true。如果删除失败,返回
false
clear() clear
方法清除所有成员,没有返回值
遍历
Map
结构原生提供三个遍历器生成函数和一个遍历方法:
- keys():返回键名的遍历器
- values():返回键值的遍历器
- entries():返回所有成员的遍历器
- forEach():遍历 Map 的所有成员
遍历顺序就是插入顺序
5.25 技术栈
vue, …
5.26 http状态码有哪些
- 1xx:指示信息–表示请求已接收,继续处理
- 2xx:成功–表示请求已被成功接收、理解、接受
- 3xx:重定向–要完成请求必须进行更进一步的操作
- 4xx:客户端错误–请求有语法错误或请求无法实现
- 5xx:服务器端错误–服务器未能实现合法的请求
5.27 按钮权限
按钮权限
从接口请求过来的数据 是一个数组 数组中有权限的数据 然后将这些数据存储到本地 然后通过自定义指令directives 然后这个自定义指令里面有一个bind钩子函数 这个bind是当绑定到元素上之后触发的钩子函数 其中有两个形参 el和bindings 其中el是当前元素 binding是它的一些属性 首先通过本地存储获取到所有的按钮权限 然后通过bindings.value获取到对应的权限 然后通过includes方法判断需要的权限是否是全部权限的一部分 如果不是的话就先将它隐藏 然后将它删除(在定时器里删除 因为这个自定义指令里面的bind会在渲染页面之前触发 所以我们需要将它放在这样一个宏任务里面
- 不同的用户进来,后台会返回一个按钮权限的列表
- 前端写一个自定义的指令,通过指令函数来获取按钮权限列表跟页面传入过来的是否能匹配的上,如果匹配不上,就不显示这个按钮(用display:none给它隐藏删除掉)
- 给所有组件的按钮绑定自定义指令,去实现按钮的权限控制
- 这样就进行了更细一步的按钮控制
5.28 动态路由
动态路由
权限管理根据不同的角色进入后台管理的时候 左侧菜单栏的权限是不同的 根据后台返回的树形结构tree在router.js中先将请求过来的数据导入进来 将数据进行一个递归的方法 将里面的子级children遍历出来 然后再用addRoutes方法添加到 动态路由里面 然后将获取过来的数据保存到vuex中 然后再从左侧菜单栏直接获取本地存储的数据
数组去重:new Set()返回对象,用array.from来转为数组
5.29 vue中权限管理
vue中权限管理
权限是干什么的 权限是对特定资源的访问许可,所谓权限控制,也就是确保⽤户只能访问到被分配的资源⽽前端权限归根结底是请求的发起权,请求的发起可能有下⾯两种形式触发 ⻚⾯加载触发(也需要后台返回权限列表,根据权限列表渲染) ⻚⾯上的按钮点击触发(根据后台返回的数据决定按钮是否显示或者禁用)
实现的目标 路由⽅⾯,⽤户登录后只能看到⾃⼰有权访问的导航菜单,也只能访问⾃⼰有权访问的路由地址,否则将跳转 404 提示⻚,视图⽅⾯: ⽤户只能看到⾃⼰有权浏览的内容和有权操作的控件
怎么实现
接口的token认证
左侧菜单权限 后台返回权限列表 前台根据返回的显示定义路由
通过前台的路由配置,
可以通过在路由的配置文件中添加meta属性,记录每个路由的权限列表,然后拿到用户的权限进行比对
用户登录成功后,获取权限列表,动态生成路由配置文件,通过this.$router.addRoutes()动态添加
可以给视图的控件设置权限 根据用户从后台返回来的信息,决定这个按钮是否被禁用或者不显示
动态路由
权限管理根据不同的角色进入后台管理的时候 左侧菜单栏的权限是不同的 根据后台返回的树形结构tree在router.js中先将请求过来的数据导入进来 将数据进行一个递归的方法 将里面的子级children遍历出来 然后再用addRoutes方法添加到 动态路由里面 然后将获取过来的数据保存到vuex中 然后再从左侧菜单栏直接获取本地存储的数据
按钮权限
- 不同的用户进来,后台会返回一个按钮权限的列表
- 前端写一个自定义的指令,通过指令函数来获取按钮权限列表跟页面传入过来的是否能匹配的上,如果匹配不上,就不显示这个按钮(用display:none给它隐藏删除掉)
- 给所有组件的按钮绑定自定义指令,去实现按钮的权限控制
- 这样就进行了更细一步的按钮控制
动态路由
权限管理会根据不同的角色进入后台管理的时候 返回的左侧菜单栏的权限是不同的 (返回的树形结构tree)创建一个js文件,引入到main.js文件里面,先进行路由拦截,然后进行一个函数把请求过来的数据进行一个循环,判断是否有子级,如果有就继续循环,直到没有这个子级,循环子级里面的数据,声明一个空数组,把子级里面的数据进行拼接,成为路径,然后添加到空数组里面,addRoute是一个动态添加路由的方法,把已经获取到数据的数组添加到动态路由里面,然后保存在vuex,左侧菜单栏可以通过获取vuex里面的数据来进行渲染
5.30 虚拟dom
真实dom就是vnode(节点属性,内容),
vue里面
虚拟dom:虚拟节点,不会真正挂载到页面,创建元素,属性等追加到页面
diff:比较节点,达到双向数据绑定
标签等等都是dom
dom分为元素,属性,文本
虚拟 生成虚拟节点vnode
5.31
基本数据类型:引用数据类型:
Vue3
8.1 vue3语法合成型API(Composition API)?
1. 使用 reactive 绑定数据
- 1.reactive方法,直接传入一个对象 state ,这个对象就是 proxy 拦截的对象
- 2.然后再把这个 state 对象直接 return 出去就能被调用
- 3.在 temolate 中使用 state.msg 来访问
- 4.在 js 中也使用 state.msg 来访问
2. setup()函数 完成父子通信
3. 使用 ref、toRefs 绑定数据
- 1.使用 ref 直接声明一个 proxy 响应式对象 msg
- 2.然后把这个 msg 对象直接 return 出去
- 3.在 template 中直接使用 {undefined{msg}}
- 4.注意:在 js 中需要使用 msg.value
4. watch、watchEffect 数据[监听]
5. 生命周期
- setup() :开始创建组件之前,在beforeCreate和created之前执行。创建的是data和method
- onBeforeMount() : 组件挂载到节点上之前执行的函数。
- onMounted() : 组件挂载完成后执行的函数。
- onBeforeUpdate(): 组件更新之前执行的函数。
- onUpdated(): 组件更新完成之后执行的函数。
- onBeforeUnmount(): 组件卸载之前执行的函数。
- onUnmounted(): 组件卸载完成后执行的函数
- 若组件被包含,则多出下面两个钩子函数。
- onActivated(): 被包含在中的组件,会多出两个生命周期钩子函数。被激活时执行 。
- onDeactivated(): 比如从 A组件,切换到 B 组件,A 组件消失时执行。
Vue2--------------vue3
beforeCreate -> setup()
created -> setup()
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeDestroy -> onBeforeUnmount ......
destroyed -> onUnmounted ......
activated -> onActivated
deactivated -> onDeactivated
vue3如何使用axios
-
安装
vue add axios
-
删除main.js
import './plugins/axios
-
//使用 import axios from "axios"; onMounted(() => { fetch(); }); function fetch() { axios.get("http://jsonplaceholder.typicode.com/users").then((res) => { console.log(res); }); }
8.2 vue2与vue3双向数据绑定的区别?
原理:
vue3.0双向数据绑定Proxy
没有 this…来代替this,cont…
8.3 vue3脚手架的使用?
8.4 vue3 ElementPlus Admin后台管理系统(二次开发)
8.5 双向绑定
在vue的2.x版本中⽤object.defineProperty来实现双向数据绑定原理,⽽在vue3.0版本中⽤Proxy这个对象来代替object.defineProperty实现数据的双向绑定。但是换汤不换药,这俩种数据双向绑定都是基于数据劫持来实现的。 数据劫持:当访问或者设置对象的属性的时候,触发相应的函数,并且返回设置属性的值。 1.VUE2.0通过Object.defineProperty来劫持对象属性的getter和setter操作,当数据发⽣变化时发出通知 2.VUE3.0通过Proxy来劫持数据,当数据发⽣变化时发出通知
proxy相较于object.defineProperty的优势直接监听对象⽽⾮属性,直接监听数组的变化,拦截⽅式较多(有13种⽅式)Proxy返回⼀个新对象,可以只操作新对象达到⽬的,⽽Object.defineProperty只能遍历对象属性直接修改(需要⽤深拷⻉进⾏修改)Proxy作为新标准将受到浏览器⼚商重点持续的性能优化
///
错题
5.22 常见的版本控制工具
1. Git
Git是目前世界上最先进的分布式版本控制系统,使用Git和Gitlab****搭建版本控制环境是现在互联网公司最流行的版本控制方式 简介: Git****是一个免费的开源分布式版本控制系统,旨在快速高效地处理从小型到大型项目的所有事务。 Git****易于学习,占用内存小,具有闪电般快速的性能。
2. SVN
TortoiseSVN是一款非常易于使用的跨平台的 版本控制/版本控制/源代码控制软件。它基于Apache Subversion(SVN)® ; TortoiseSVN为Subversion提供了一个简单易用的用户界面。
3. HG
Mercurial是一个免费的分布式源代码管理工具。它可以有效地处理任何规模的项目,并提供简单直观的界面。Mercurial 是一种轻量级分布式版本控制系统,采用 Python 语言实现,易于学习和使用,扩展性强。
4. CVS–Concurrent Versions System**,**
CVS是版本控制系统,是源配置管理(SCM)的重要组成部分。使用它,您可以记录源文件和文档的历史记录。老牌的版本控制系统,它是基于客户端/服务器的行为使得其可容纳多用户,构成网络也很方便。这一特性使得CVS成为位于不同地点的人同时处理数据文件(特别是程序的源代码)时的首选。
1.更轻松的管理。传统的版本控制系统使用集中式的 repository,一些和repository相关的管理就只能由管理员一个人进行。由于采用了分布式的模型,Mercurial 中就没有这样的困扰,每个用户管理自己的 repository,管理员只需协调同步这些repository。 2.更健壮的系统。分布式系统比集中式的单服务器系统更健壮,单服务器系统一旦服务器出现问题整个系统就不能运行了,分布式系统通常不会因为一两个节点而受到影响。 3.对网络的依赖性更低。由于同步可以放在任意时刻进行,Mercurial 甚至可以离线进行管理,只需在有网络连接时同步。
5. VSS-- Visual Source Safe
此工具是Microsoft提供的,是使用的相当普遍的工具之一,他可以与VS.net进行无缝集成,成为了独立开发人员和小型开发团队所适合的工具,基本上Window平台上开发的中小型企业,当规模较大后,其性能通常是无法忍受的,对分支与并行开发支持的比较有限。
其相关的外挂支持工具为SAW,SOS.
5.23 扩展运算符与rest剩余参数什么意思,及其应用场景。
1. 扩展运算符 …
可以将一个数组转为用逗号分隔的参数序列。把一个大元素给打散成一个个单独的小元素。
1.1 某些场景可以替代****apply
在使用Math.max()求数组的最大值时,ES5可以通过 apply 做到(不友好且繁琐的方式);
扩展运算符可用于数组的析构,优雅的解决了这个问题。
1.2 **代替数组的push、**concat 等方法
1.3 拷贝数组或对象
无论是像克隆数组还是对象,先用化骨绵掌之扩展运算符,将其打散,之后再拼装的到一起就可以了,多么简单易用。
1.4 将伪数组转化为数组
扩展运算符可以将一个类似数组的对象将其转为真正的数组,原因就在于 NodeList 对象实现了 Iterator。
注意:使用扩展运算符将伪数组转换为数组有局限性,这个类数组必须得有默认的迭代器且伪可遍历的。
2. rest 剩余参数
rest元素和展开元素相反,展开元素会“展开”数组变成多个元素,剩余元素会收集多个元素和“压缩”成一个
单一的元素。
说的通俗点,有点像吸星大法,收集多个元素,压缩成单一的元素 。
rest参数用于获取函数的多余参数,这样就不需要使用arguments对象了。rest参数搭配的变量是一个数组,该变
量将多余的参数放入数组中。
2.1 rest 参数代替arguments变量
2.2 与解构赋值组合使用
总结:
1 . 扩展运算符和rest运算符是逆运算
扩展运算符:数组=>分割序列
rest运算符:分割序列=>数组
2. 扩展运算符应用场景
由于其繁琐的语法,apply 方法使用起来并不是很方便。当需要拿一个数组的元素作为函数调用的参数时,
扩展运算符是一个不错的选择。
扩展运算符还改善了数组字面量的操作,你可以更方便的初始化、连接、复制数组了。
使用析构赋值你可以提取数组的一部分。通过与迭代器协议的组合,你可以以一种更灵活的方式使用该表达式。
3. rest****运算符应用场景
rest运算符主要是处理不定数量参数,rest参数使得收集参数变得非常简单。它是类数组对象arguments一个合理的替代品。
rest****参数还可以与解构赋值组合使用。
在实际项目中灵活应用扩展运算符、rest运算符,能写出更精简、易读性高的代码。
5.24 es6新增的数据结构Set,Map****代表什么意思
Set是一种叫做集合的数据结构,Map是一种叫做字典的数据结构
1. Set
Set是es6新增的数据结构,类似于数组,但是成员的值都是唯一的,没有重复的值,我们一般称为集合
Set本身是一个构造函数,用来生成 Set 数据结构
const s = new Set();
5.24.1.1 增删改查
Set的实例关于增删改查的方法:
- add()
- delete()
- has()
- clear()
add
添加某个值,返回 Set 结构本身
当添加实例中已经存在的元素,set不会进行处理添加 如: s.add(1).add(2).add(2); // 2只被添加了一次
delete
删除某个值,返回一个布尔值,表示删除是否成功 如:s.delete(1)
has()
返回一个布尔值,判断该值是否为Set的成员 如:s.has(2)
clear()
清除所有成员,没有返回值 如:s.clear()
5.24.1.1 遍历
Set实例遍历的方法有如下:
关于遍历的方法,有如下:
keys():返回键名的遍历器
values():返回键值的遍历器
entries():返回键值对的遍历器
forEach():使用回调函数遍历每个成员
Set的遍历顺序就是插入顺序
keys方法、values方法、entries方法返回的都是遍历器对象
forEach()用于对每个成员执行某种操作,没有返回值,键值、键名都相等,同样的
forEach方法有第二个参数,用于绑定处理函数的
this
扩展运算符和Set 结构相结合实现数组或字符串去重
实现并集、交集、和差集
2. Map
Map类型是键值对的有序列表,而键和值都可以是任意类型
Map本身是一个构造函数,用来生成 Map 数据结构 如: const m = new Map()
增删改查
Map 结构的实例针对增删改查有以下属性和操作方法:
- size 属性
- set()
- get()
- has()
- delete()
- clear()
size
size属性返回 Map 结构的成员总数。
set()
设置键名key对应的键值为value,然后返回整个 Map 结构
如果key已经有值,则键值会被更新,否则就新生成该键
同时返回的是当前Map对象,可采用链式写法
get()
get方法读取key对应的键值,如果找不到key,返回undefined
has()
has方法返回一个布尔值,表示某个键是否在当前 Map 对象之中
delete()
delete方法删除某个键,返回true。如果删除失败,返回false
clear() clear方法清除所有成员,没有返回值
遍历
Map结构原生提供三个遍历器生成函数和一个遍历方法:
- keys():返回键名的遍历器
- values():返回键值的遍历器
- entries():返回所有成员的遍历器
- forEach():遍历 Map 的所有成员
遍历顺序就是插入顺序
封装组件 虚拟dom以及什么是真实dom mixin与js的不同 微信支付流程 $nextTist new操作符
Mixinjs中有生命周期,而普通js里面没有生命周期
1.vue组件的核心选项:
1、模板(template):模板声明了数据和最终展现给用户的DOM之间的映射关系。
2、初始数据(data):一个组件的初始数据状态。对于可复用的组件来说,这通常是私有的状态。
3、接受的外部参数(props):组件之间通过参数来进行数据的传递和共享。
4、方法(methods):对数据的改动操作一般都在组件的方法内进行。
5、生命周期钩子函数(lifecycle hooks):一个组件会触发多个生命周期钩子函数,最新2.0版本对于生命周期函数名称改动很大。
6、私有资源(assets):Vue.js当中将用户自定义的指令、过滤器、组件等统称为资源。一个组件可以声明自己的私有资源。私有资源只有该组件和它的子组件可以调用。等等。
2 虚拟dom以及什么是真实dom
虚拟dom:利用js来表示真实的dom元素,好处是可以快速地渲染,更新元素,提高浏览器的性能。
Diff算法:基础虚拟dom完成节点更新的方法
用js来表示一个真实的dom树结构,创建一个虚拟dom对象,
当数据发生改变的时候,再创建一个虚拟dom对象;
比较新旧对象的差异,将最新结果更新到真实的dou树结构上。
虚拟dom就是通过vue,把它编译成真实dom,这个方法中有(标签,属性以及子属性),通过appendchild追加到真实的页面上
什么是虚拟DOM(virtual DOM):
所谓的虚拟 dom,也就是我们常说的虚拟节点,
它是通过JS的Object对象模拟DOM中的节点
然后再通过特定的render(渲染)方法将其渲染成真实的DOM的节点。
为什么使用虚拟DOM:
使用js操作DOM时(增删改查等等),那么DOM元素的变化自然会引起页面的回流(重排)
或者重绘,页面的DOM重绘自然会导致页面性能下降,那么如何尽可能的去减少DOM的操作
是框架需要考虑的一个重要问题!
真实dom:
DOM(Document Object Model,文档对象模型)是 JavaScript 操作 HTML 的接口.
文档对象模型(DOM)是一个独立于语言的,用于操作XML和HTML文档的接口程序(API)。在浏览器中,主要用来与HTML文档打交道,同样也用在web程序中获取XML文档,并使用DOM API用来访问文档中的数据。
真实DOM和虚拟DOM的区别:
1.虚拟DOM不会进行排版与重绘操作
2.真实DOM频繁排版与重绘的效率是相当低
3.虚拟DOM进行频繁修改,然后一次性比较(使用diff算法)并修改真实DOM中需要改的部分,
最后并在真实DOM中进行排版与重绘,减少过多DOM节点排版与重绘损耗
4.虚拟DOM有效降低了重绘与排版的次数,因为,最终把虚拟dom与真实DOM比较差异,
可以只渲染局部
3 说说new操作符具体⼲了什么?
new关键字主要做了以下的⼯作:
· 创建⼀个新的对象obj
· 将对象与构建函数通过原型链连接起来
· 将构建函数中的this绑定到新建的对象obj上
· 根据构建函数返回类型作判断,如果是原始值则被忽略,如果是返回对象,需要正常处理(必须返回)
4. Vue中的$nextTick有什么作⽤?
通过 this.$nextTick
我们可以注册一个回调函数,这个回调函数会在下次 DOM 更新结束之后执行
Vue的数据更新是采用延迟异步更新
的,就是说当我们修改了数据之后,页面并不会马上就更新,如果这个时候我们通过DOM操作来获取数据的话,获取的还是之前的旧的数据,这个时候我们就可以使用$nextTick方法。延时dom渲染。延时的定时器,异步延时,例如:滚动
n e x t T i c k 与 nextTick 与 nextTick与set的区别:
n e x t T i c k 是 在 下 一 次 d o m 更 新 后 执 行 , nextTick是在下一次dom更新后执行, nextTick是在下一次dom更新后执行,set是给响应式对象增加新属性时,为了让新属性也拥有响应式时使用的。
$set设置后vue内部会进行数据加工处理,而这些操作消耗时间,所以是异步的,这就是说他还没加工完下一行代码马上操作这个dom节点可能数据是上一次没改变的数据,nexttick就可以等待数据改变了,dom也渲染完成了再执行。
$nextTick 用来知道什么时候DOM更新完成的**,只是让你的操作在视图更新后才执行而已**
s e t ∗ ∗ ∗ ∗ 刷 新 试 图 , 更 新 视 图 ∗ ∗ ∗ ∗ 语 法 : ∗ ∗ ∗ ∗ t h i s . set** **刷新试图,更新视图** **语法:****this. set∗∗∗∗刷新试图,更新视图∗∗∗∗语法:∗∗∗∗this.set(this.data,”key”,value’)
$nextTick把同步变为异步,延时异步,就是settimeout就是异步
$nexttick并不是真正意义上的更新视图,而是等视图更新后再执行某些操作
This.$nextTick方法应用场景:需要在视图更新之后,基于新的视图进行操作。
5. mixin, ?mixin与普通js的区别?
**Mixin
是面向对象程序设计语言中的类,提供了方法的实现。其他类可以访问mixin
**类的方法而不必成为其子类
Mixin
类通常作为功能模块使用,在需要该功能时“混入”****,有利于代码复用又避免了多继承的复杂
mixin
****(混入),提供了一种非常灵活的方式,来分发 Vue
组件中的可复用功能。
本质其实就是一个js对象,它可以包含我们组件中任意功能选项,如data、components、methods、created、computed等等
我们只要将共用的功能以对象的方式传入 mixins****选项中,当组件使用 mixins对象时所有mixins****对象的选项都将被混入该组件本身的选项中来
在日常的开发中,我们经常会遇到在不同的组件中经常会需要用到一些相同或者相似的代码,这些代码的功能相对独立
这时,可以通过Vue的mixin功能将相同或者相似的代码提出来
Mixinjs中有生命周期,而普通js里面没有生命周期
Minxins
Vue.mixin()=>用use****来使用
6. 微信小程序的支付功能
先判断有没有token值,没有的话,就 跳转到授权登录页面,来获取token值。
有了token值后,就创建订单,获取订单编号
使用wx.login()方法,获取用户临时的支付凭证code码…
7. 组件封装,如弹窗组件
使用Vue.extend方法创建一个组件,然后使用Vue.component方法注册组件。子组件需要数据,可以在props中接受定义。而子组件修改好数据后,想把数据传递给父组件。可以采用emit方法。
弹窗组件的封装-布局分为顶部标题,中间内容区,底部确定区,不确定的内容用插槽代替。首先要对外扩展宽,高,标题,遮罩层等属性,方法有关闭回调方法,动画方法等。通过方法控制属性
8. 回流与重绘
html加载时,DOM tree与css样式一起渲染成了render tree;
回流:
回流是render tree里面的一部分,因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。这就是回流。每个页面至少需要一次回流,在页面第一次加载时,需要构建render tree,一定会有回流的。在回流的时候,浏览器会让渲染树中受到影响的部分失效,来重新构建这部分的渲染树;回流完成之后,浏览器就会重新绘制受影响的部分到屏幕里,这个过程就是重绘。
重绘
重绘:render tree里的一些元素需要更新属性,但是这些属性只会影响元素的外观,风格,不会影响布局的,比如background-color。这就叫重绘。
区别:
回流必定会引起重绘,而重绘不一定引起回流。例如:只改变颜色的时候就会引起重绘不会引起回流。
当页面布局与几何属性改变的时候,就会需要回流。例如:添加或者删除可见的DOM元素,元素位置改变,元素尺寸改变——边距、填充、边框、宽度和高度,内容改变。
9. 强缓存与协商缓存
浏览器缓存的作⽤是什么?
缓存可以减少冗余的数据传输。节省了⽹络带宽,从⽽更快的加载⻚⾯。缓存降低了服务器的要求,从⽽服务器更快的响应
缓存的资源⽂件到什么地⽅?
-
emory cache: 它是将资源⽂件缓存到内存中。等下次请求访问的时候不需要重新下载资源,⽽是直接从内存中读取数据。
-
disk cache: 它是将资源⽂件缓存到硬盘中。等下次请求的时候它是直接从硬盘中读取
浏览器缓存分为2种:强制缓存和协商缓存
协商缓存的标识⼜有2种:ETag/if-None-Match 和 Last-Modified/if-Modify-Since
-
ETag/if-None-Match
ETag则是对当前请求的资源做⼀个唯⼀的标识。标识可以是⼀个字符串,⽂件的size,hash等。只要能够合理标识资源的唯⼀性并能验证是否修改过就可以了。
-
Last-Modified/if-Modify-Since
前端代码打包后生成的静态资源发布到静态服务器上面,然后,我们就需要对这些静态的资源做一些运维的设置。其中:gzip跟设置缓存是最必不可少的。这两个是直接影响用户体验跟网站性能的。
缓存的优点:
减少了不必要的数据传输,节省带宽
减少服务器的负担,提升网站性能
加快了客户端加载网页的速度
用户体验友好
缺点:
资源如果有改变但是客户端不及时更新会造成用户获取信息滞后,如果老版本有bug的话,情况会更加糟糕。
所以,为了避免设置缓存错误,掌握缓存的原理对于我们工作中去更加合理的配置缓存是非常重要的。
强缓存
- cache-control: max-age=xxxx,public
客户端和代理服务器都可以缓存该资源;
客户端在xxx秒的有效期内,如果有请求该资源的需求的话就直接读取缓存,statu code:200 ,如果用户做了刷新操作,就向服务器发起http请求 - cache-control: max-age=xxxx,private
只让客户端可以缓存该资源;代理服务器不缓存
客户端在xxx秒内直接读取缓存,statu code:200 - cache-control: max-age=xxxx,immutable
客户端在xxx秒的有效期内,如果有请求该资源的需求的话就直接读取缓存,statu code:200 ,即使用户做了刷新操作,也不向服务器发起http请求 - cache-control: no-cache
跳过设置强缓存,但是不妨碍设置协商缓存;一般如果你做了强缓存,只有在强缓存失效了才走协商缓存的,设置了no-cache就不会走强缓存了,每次请求都回询问服务端。 - cache-control: no-store
不缓存,这个会让客户端、服务器都不缓存,也就没有所谓的强缓存、协商缓存了。
协商缓存
请求资源时,把用户本地该资源的 etag 同时带到服务端,服务端和最新资源做对比。
如果资源没更改,返回304,浏览器读取本地缓存。
如果资源有更改,返回200,返回最新的资源。
如何设置强缓存与协商缓存?
10. 数组中的…是展开数组,对象中的…是展开对象,函数中的…是剩余参数
11. 状态码
【200 (请求成功) 一般用于get或post请求
201 (已创建) 成功请求并创建了新的资源
400 (错误请求) 服务器不理解请求的语法
401 (未授权) 请求要求身份验证,对于需要登录的网页,服务器可能返回此响应
402 (保留) 将来使用
403 (禁止) 服务器拒绝请求
404 (未找到) 服务器找不到请求的网页
500 (服务器错误) 服务器不支持请求的功能,无法完成请求】
12. vue3中 父子传参,有没有this,watch,没有管道符,没有过滤器,常用的生命周期,常用属性及方法
13. 团队的规范 插件
14. 你们分页如何实现的?
分页分为前端分页和后端分页,我们项目中主要是后台分页:后台接口要求传入当前页数pagenum,每页条数pagesize。后台会返回总条数total,当前页数pagenum。使用elment分页组件实现分页样式,当条数改变时传入条数提交接口,当页数改变时传入页数提交接口 ,然后重新调用数据方法进行渲染
15. vue封装组件概念?
vue封装组件概念:
想要封装好一个组件,一定要熟练掌握这三个技能,父组件 —> 子组件传值(props)、子组件 —> 父组件传值(
e
m
i
t
)
、
以
及
插
槽
(
s
l
o
t
)
;
对
于
一
个
独
立
的
组
件
来
说
,
p
r
o
p
s
是
用
来
为
组
件
内
部
注
入
核
心
的
内
容
;
emit)、以及插槽(slot);对于一个独立的组件来说,props是用来为组件内部注入核心的内容;
emit)、以及插槽(slot);对于一个独立的组件来说,props是用来为组件内部注入核心的内容;emit用来使这个独立的组件通过一些逻辑来融入其他组件中。举个具体点的例子,假如你要做一辆车,车轮是要封装的一个独立组件,props指的就是根据整个车的外形你可以给轮子设置一些你想要的且符合车风格的花纹,图案等;而$emit的作用则是让这些轮子能够和整辆车完美契合的运作起来。
16. 动态路由如何实现?
1.在全局路由守卫中,先判断token值有没有。有的话先看是否存储过,如果存储过直接,页面调用渲染,如果没有,就请求接口,把路由表存储下 。除非没有token,跳转登录页面
2.路由表里-把那些常规路由(不需要权限的路由,事先都写到路由表里)。把需要权限的路由通过router.addRoute()动态填加到对应的子路由里 。
3.动态填加的路由需要处理下。因为后端传给你的是树状结构,前端需要把树结构处理成列表结构(通过递归,不断的获取路径,名字那些信息),填加到路由表里。
17. 按钮权限实现思路?
1.不同用户进来,后台会返回一个按钮权限列表
2.在前端写自定义指令,在指令函数里里获取按钮权限列表跟页面传入的那个是否匹配,如果匹配不上就不显示该按钮(通过display,none把当前节点隐藏删除掉)。这样当达到了更细一级的按钮控制
18. 对数据量大不常更新的数据进行缓存处理?
请求成功后存储数据,页面加载时读取数据,如果时间过期,重新请求数据。明天实现对分类数据的缓存
19. 微信支付开通流程?
微信支付开通流程(!!!注意想要上线使用微信支付,必须得是公司账号微信认证过):
一.微信公众平台-登录老板(公司)账号-微信认证(公司资质)
二.申请微信商户号-用老板微信扫描申请-公司(上传公司资质)-申请下来-登录老板开发者账号-填加老板的appid账号或者开发者appid与商户号关联起来
三.微信公众平台-登录老板(公司)账号-成员管理-填加自己的微信小程序账号appid(开发权限)
20. 小程序如何实现一个promise的封装?
export default({url, data}) => {
return new Promise((resolve, reject) => {
wx.request({
url,
data,
header: {},
success: res => {
resolve(res)
},
fail: err => {
reject(err)
}
})
})
}
//先new一个promise对象,里面resolve跟reject两个对象,箭头返回wx.request()方法,里面有url,data数据,headers头协议,还有success成功后的回调以及fail失败后的回调,如果成功就用resolve返回数据,失败就用reject返回失败的回调。
21.
echarts
echarts大屏可视化项目,常见面试题:
1.echarts的用法?
下载echarts包,导入echarts
1.1 定义div容器必须设置宽高
1.2 查找该dom,引入echarts,进行init初始化该dom
1.3然后查找对应图表option配置,最后加入到setOption()方法里
2.echarts图表如何根据屏幕响应式缩放?
监听浏览器窗口的 resize 方法,可以添加多个图表
window.addEventListener(‘resize’, () => {
myChart.resize();
// myChart2.resize();
// myChart3.resize();
})
3.你还知道哪些数据可视化图表库?
Echarts(百度的,PC端用的多)-https://echarts.apache.org/examples/zh/index.html
AntV(阿里的,移动端用的多)-https://antv-f2.gitee.io/zh/examples/gallery
Highcharts(国外公司),D3.js(国外公司)
相关扩展文章-https://blog.csdn.net/qq_15041931/article/details/105942934
4.echarts如何实现实时更新数据?
可采用websocket长链接实时更新,
websocket基础概念-https://www.ruanyifeng.com/blog/2017/05/websocket.html
B站视频Echarts+websocket实时数据交互-https://www.bilibili.com/video/BV1Q64y1B7g5
5.echarts数据量大时如何进行优化?
可通过appendData异步加载,分片加载数据
参考文章-https://lockdatav.blog.csdn.net/article/details/109022138
webpack
webpack中文文档-https://webpack.docschina.org/concepts/
webpack配置-项目中常在vue.config.js配置:
1.代理跨域配置
module.exports = {
//代理跨域
devServer: {
proxy:{
target:""
}
}
}
2.可配置别名
chainWebpack:config=>{
入口
config.entry(),
//别名
resolve:{}
}
3.可配置各种loader-各种编译插件
//配置各种loader
module: {
rules: [{ test: /.txt$/, use: ‘vue-loader’ }],
},
4.插件-webapck的插件-可执行更多的任务
//HtmlWebpackPlugin 插件-它会把打包好的js,css自动插入到index.html
const HtmlWebpackPlugin = require(‘html-webpack-plugin’); // 通过 npm 安装
plugins: [new HtmlWebpackPlugin({ template: ‘./src/index.html’ })],
打包上线中引入 babel-plugin-transform-remove-console,移除所有 console信息
5.模式(mode)-mode里可配置区分生产环境,开发环境
module.exports = {
mode: ‘production’,
};
webpack打包流程:
1.首先通过配置的entry入口,找到入口文件main.js
2.通过配置的各种loader(css-loader配合正则找所有css样式文件,file-loader配合正则找图片文件转成base64,vue-loader找所有.vue文件 )统一打包成.css的和.js的chunk文件
3.通过插件(html-webpack-plugin插件)把这种chunk文件(打包生成的文件)自动嵌入到index.html里