一、html#
1. 页面导入样式时,使用 link 和 @import 有什么区别?#
1 属性差别。link 属于 XHTML 标签,而 @import 完全是 CSS 提供的语法规则。
link 标签除了可以加载 CSS 外,还可以做很多其它的事情,rel 属性 preload,icon 等,@import 就只能加载 CSS 了。
2 加载顺序的差别。当一个页面被加载的时候(就是被浏览者浏览的时候),link 引用的 CSS 会同时被加载,而 @import 引用的 CSS 会等到页面全部被下载完再被加载。所以有时候浏览 @import 加载 CSS 的页面时开始会没有样式(就是闪烁),网速慢的时候还挺明显.
3 兼容性的差别。由于 @import 是 CSS2.1 提出的所以老的浏览器不支持,@import 只有在 IE5 以上的才能识别,而 link 标签无此问题。
4 使用 dom 控制样式时的差别。当使用 javascript 控制 dom 去改变样式的时候,只能使用 link 标签,因为 @import 不是 dom 可以控制的。
二、css#
1. 双飞燕布#
(1)中间 flex: 1
(2)html
<div class="content">
<div class="content-left">left</div>
<div class="content-middle">middle</div>
<div class="content-right">right</div>
</div>
css
.content{
display: flex;
}
.content-left{
flex: 0 0 200px;
width: 200px;
height: 200px;
background-color: red;
}
.content-middle{
flex: 1;
width: 100%;
height: 200px;
background-color: green;
min-width: 700px;
}
.content-right{
flex: 0 0 200px;
width: 200px;
height: 200px;
background-color: blue;
}
实现效果:
(3)flex 设置成 1
当 flex 取值为一个非负数字,则该数字为 flex-grow 值,flex-shrink 取 1,flex-basis 取 0%,如下是等同的:
.item {flex: 1;} .item { flex-grow: 1; flex-shrink: 1; flex-basis: 0%; }
2. 标准盒模型和怪异盒模型#
(1)标准盒模型
总长 = width+padding(左右)+border(左右)+margin(左右)
在标准盒模型中,当 width 不变时,padding(左右)和 borde(左右)的改变都是要改变总长的。
(2)怪异盒模型
总长 = width+margin(左右)
在怪异盒模型的总长中 width 的大小不变时,padding(左右)和 border(左右)的改变只在 width 中变化,不会改变总长的。
(3)
当设置 box-sizing时,为标准模式,也是默认模式;
当设置为 box-sizing时,为怪异模式;
3.Sass 和 Less 是什么?有什么区别?大家为什么要使用他们?#
三、javascript#
1.return 、break 和 continue 的区别和作用#
(1)return 关键字并不是专门用于跳出循环的,return 的功能是结束一个方法
与 continue 和 break 不同的是,return 直接结束整个方法,不管这个 return 处于多少层循环之内
(2)continue 的功能和 break 有点类似,区别是 continue 只是中止本次循环,接着开始下一次循环。而 break 则是完全中止循环。
(3)break 用于完全结束一个循环,跳出循环体
2. 从输入 URL 到页面展示的详细过程#
1. 用户输入 url 到 浏览器拿到服务端返回的数据
第一部分:
(1)通过 DNS 解析获得网址的对应 IP 地址
1. 首先查看本地 hosts 文件
2. 发出一个 DNS 请求到本地 DNS 服务器 (查询它的缓存记录 — 递归的方式进行查询)
3. 本地 DNS 服务器还要向 DNS 根服务器进行查询 (返回域名服务器地址 — 迭代过程)
4. 本地 DNS 服务器向域名的解析服务器发出请求,这时就能收到一个域名和 IP 地址对应关系,本地 DNS 服务器不仅要把 IP 地址返回给用户电脑,还要把这个对应关系保存在缓存中
(2)浏览器与服务器 TCP 三次握手
- 第一次握手:客户端 A 将标志位 SYN 置为 1, 随机产生一个值为 seq=J(J 的取值范围为 = 1234567)的数据包到服务器,客户端 A 进入 SYN_SENT 状态,等待服务端 B 确认;
- 第二次握手:服务端 B 收到数据包后由标志位 SYN=1 知道客户端 A 请求建立连接,服务端 B 将标志位 SYN 和 ACK 都置为 1,ack=J+1,随机产生一个值 seq=K,并将该数据包发送给客户端 A 以确认连接请求,服务端 B 进入 SYN_RCVD 状态。
- 第三次握手:客户端 A 收到确认后,检查 ack 是否为 J+1,ACK 是否为 1,如果正确则将标志位 ACK 置为 1,ack=K+1,并将该数据包发送给服务端 B,服务端 B 检查 ack 是否为 K+1,ACK 是否为 1,如果正确则连接建立成功,客户端 A 和服务端 B 进入 ESTABLISHED 状态,完成三次握手,随后客户端 A 与服务端 B 之间可以开始传输数据了。
(3)服务器的永久重定向响应,浏览器跟踪重定向地址。
(4)服务器处理请求,并返回响应
2. 浏览器拿到数据 到 浏览器渲染
(5)浏览器拿到数据 到 浏览器渲染构建 dom 树 -> 构建 render 树 -> 布局 render 树 -> 绘制 render 树 这个讲的很不错:从输入 URL 到页面展示的详细过程
3.TCP 四次挥手#
(1)
- 第一次挥手:Client 发送一个 FIN,用来关闭 Client 到 Server 的数据传送,Client 进入 FIN_WAIT_1 状态。
- 第二次挥手:Server 收到 FIN 后,发送一个 ACK 给 Client,确认序号为收到序号 + 1(与 - SYN 相同,一个 FIN 占用一个序号),Server 进入 CLOSE_WAIT 状态。
- 第三次挥手:Server 发送一个 FIN,用来关闭 Server 到 Client 的数据传送,Server 进入 LAST_ACK 状态。
- 第四次挥手:Client 收到 FIN 后,Client 进入 TIME_WAIT 状态,接着发送一个 ACK 给 Server,确认序号为收到序号 + 1,Server 进入 CLOSED 状态,完成四次挥手。
(2)为什么建立连接是三次握手,而关闭连接却是四次挥手呢? 这是因为服务端在 LISTEN 状态下,收到建立连接请求的 SYN 报文后,把 ACK 和 SYN 放在一个报文里发送给客户端。而关闭连接时,当收到对方的 FIN 报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方也未必全部数据都发送给对方了,所以己方可以立即 close,也可以发送一些数据给对方后,再发送 FIN 报文给对方来表示同意现在关闭连接,因此,己方 ACK 和 FIN 一般都会分开发送。
TCP 四次挥手及相关
TCP 第四次挥手为什么要等待 2MSL
tcp 三次握手四次挥手详情
4. reflow (回流) 和 repain (重绘)#
(1)DOM 节点中的各个元素都是以盒模型的形式存在,这些都需要浏览器去计算其位置和大小等,这个过程称为 relow; 当盒模型的位置,大小以及其他属性,如颜色,字体,等确定下来之后,浏览器便开始绘制内容,这个过程称为 repain。
(2)引起回流:添加或者删除可见的 DOM 元素,元素位置改变,元素尺寸改变 —— 边距、填充、边框、宽度和高度,内容改变
引起重绘:颜色,背景改变
(3)关系:回流必将引起重绘,而重绘不一定会引起回流
5. 节流和防抖#
(1)防抖
触发事件后在 100 秒内执行一次,如果在 n100 秒内又触发了事件,则会重新计算函数执行时间
例如搜索框输入时实时搜索
(2)节流,
就是指连续触发事件,一段时间内只执行一次函数。
短信验证码,发送一次,60s 后才能再次发送
6. 脱离文档流有哪些#
(1)脱离文档流:
float
position
position: fixed
(2)怎么恢复文档流:
对于 float 的元素,对父级元素可以使用 overflow:hidden
clear:both
(3)position这个属性并没有脱离文档流的,所以元素本身所占的位置会保留
7. 事件循环#
(1)JS 浏览器事件循环机制:
Javascript 的事件分为同步任务和异步任务,遇到同步任务就放在执行栈中执行,而碰到异步任务就放到任务队列之中,等到执行栈执行完毕之后再去执行任务队列之中的事件。
(2)node.js 事件循环
node.js 事件循环 — 整体结构
node.js 事件循环 — 辅助理解
git 中关于 node 事件循环
node11 前后(前,宏所有任务后微任务 11 后,宏任务执行后对应的微任务)
大体的 task(宏任务)执行顺序是这样的:
timers 定时器:本阶段执行已经安排的 setTimeout () 和 setInterval () 的回调函数。
pending callbacks 待定回调:执行延迟到下一个循环迭代的 I/O 回调。
idle, prepare:仅系统内部使用。
poll 轮询:检索新的 I/O 事件;执行与 I/O 相关的回调(几乎所有情况下,除了关闭的回调函数,它们由计时器和 setImmediate () 排定的之外),其余情况 node 将在此处阻塞。
check 检测:setImmediate () 回调函数在这里执行。
close callbacks 关闭的回调函数:一些准备关闭的回调函数,如:socket.on (‘close’, …)。
(3)宏任务,微任务
宏任务和微任务的分类
执行顺序的案例
宏任务和微任务
8. 垃圾回收机制#
(1) l 垃圾回收:在某些变量(例如局部变量)在不参与运行时,就需要系统回收被占用的内存空间,称为垃圾回收
(2) 内存泄漏:某些情况下,不再用到的变量所占内存没有及时释放,导致程序运行中,内存越占越大,极端情况下可导致系统崩溃、服务器宕机。
(3) 常用的垃圾回收方法:标记清除、引用计数。
1. 引用计数:记录每个值被引用的次数。引用时 + 1,这个值引用的变量又取得了另外一个值 - 1,当这个引用次数变成 0 时,就会释放那些引用次数为 0 的值所占的内存。
引用计数有个最大的问题: 循环引用。
解决:手动解除引用(手动置为 null)
2. 标记清除
垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记。然后,它会去掉环境中的变量以及被环境中的变量引用的标记。
垃圾收集器完成内存清除工作,销毁那些带标记的值,并回收他们所占用的内存空间。
(4) 减少 JavaScript 中的垃圾回收?
对象尽量复用
循环优化,在循环中的函数表达式,能复用最好放到循环外面。
(5) 避免内存泄漏?
1. 意外的全局变量
bar 没被声明,会变成一个全局变量,在页面关闭之前不会被释放。
2. 被遗忘的计时器或回调函数
3. 闭包
将事件处理函数定义在外部,解除闭包
4. 没有清理的 DOM 元素引用
有时,保存 DOM 节点内部数据结构很有用。假如你想快速更新表格的几行内容,把每一行 DOM 存成字典(JSON 键值对)或者数组很有意义。此时,同样的 DOM 元素存在两个引用:一个在 DOM 树中,另一个在字典中。将来你决定删除这些行时,需要把两个引用都清除。
9.js 封装成插件#
(1)我的封装
圆环绘制
水印背景
(2)封装思路及注意事项
封装参考
封装参考
个人思路补充:
1. 我个人一般先是面向过程编程,然后基本功能实现之后,在改造为面向对象编程
2. 一般有以下几个基本步骤:
① 创建一个构造函数
② 变量改为属性
③ 函数改为原型方法(有些实现某块具体功能的代码也可抽离成原型方法)
④ 更正某些不正确的 this 指向
10.promise.catch 与 try catch 的区别#
(1)try/catch 无法捕获 promise.reject 的问题,原因是 try catch里面不能拦截异步代码
function f2() {
try {
Promise.reject('出错了');
} catch(e) {
console.log(e)
}
}
f2() //Uncaught (in promise)
解决:
(1.1)用 async await
async function f() {
try {
await Promise.reject('出错了')
} catch(e) {
console.log(e)
}
}
f() // 出错了
(1.2) promise.catch()
function f2() {
try {
Promise.reject('出错了').catch(err => {
console.log('2', err)
});
console.log('1')
} catch (e) {
console.log(e)
}
}
f2()
(1.3)try/catch 无法捕获 promise.reject 的问题
(2)拦截顺序
(2.1)reject 后的东西,一定会进入 then 中的第二个回调,如果 then 中没有写第二个回调,则进入 catch
(2.2)resolve 的东西,一定会进入 then 的第一个回调,肯定不会进入 catch
(2.3)关于 promise 中 reject 和 catch 的问题
11. 数据精度 0.001+ 0.002 != 0.003#
(1)原因:
JS 遵循 IEEE 754 规范,采用双精度存储(double precision),占用 64 bit;
可以知道看似有穷的数字,在计算机的二进制表示里却是无穷的,由于存储位数限制因此存在 “舍去”,精度丢失就发生了;
(2)解决:
(2.1)对于精度要求不高
Math.floor 向下取整
Math.ceil 向上取整
Math.round 四舍五入
toFixed () 取几位小数
(2.2)对于简单计算的
利用乘法变成整数,再利用除法得出结果
或者自己封装方法进行计算
(2.3)第三方库 Math.js 和 big.js
Math.js
官网
github
案例
12. 数据持久化存储方案(localstorage)#
localstorage
vuex
indexDB
13. 箭头函数的弊端#
(1)没有原型属性
(1)不能使用 new 命令
(2)不能是使用 arguments
(3)不能当作 generator 函数,不能使用 yield 命令
14.http1 与 http2 区别 以及 http 和 https 的区别#
http1 与 http2 区别 以及 http 和 https 的区别
15.promise 与 async,await 的区别#
16.es6 常用的内容(heihei 上总结较全可做补充)#
(1)es6 其他
es6 其他
(2)es6 新增基本数据类型 Symbol
es6 新增基本数据类型 Symbol
四、vue#
1.vue 中为什么 data 是函数不是对象#
data 是对象的话,会发生多个地方的相同组件操作同一个 Data 属性,导致数据混乱
是函数的话返回的是独立的全新的数据,不会相互影响(只有函数 {} 构成作用域)
2.vue 组件之间通信方式#
1.props 传递数据
适用场景:父组件传递数据给子组件
- (emit 触发自定义事件)
适用场景:子组件传递数据给父组件
3.EventBus
使用场景:兄弟组件传值
兄弟组件通过 e m i t 触 发 自 定 义 事 件 , emit 触发自定义事件, emit 触发自定义事件,emit 第二个参数为传递的数值
另一个兄弟组件通过 $on 监听自定义事件
4.vuex,状态管理工具
5.provide 与 inject
在祖先组件定义 provide 属性,返回传递的值
在后代组件通过 inject 接收组件传递过来的值
6.pubsub.js
// 发布消息
PubSub.publish (‘deleteTodo’, index); //deleteTodo 一定要与订阅方名称一样,index 是通信的具体数据
PubSub.subscribe(‘deleteTodo’,(msg,index)=>{
this.deleteTodo (index) // 调用 deleteTodo 方法执行真正的业务逻辑
});
3. 观察者模式与订阅模式: 区别与体现#
(1)观察者模式和发布订阅模式最大的区别就是发布订阅模式有个事件调度中心。
(2)
(3)观察者模式中观察者和目标直接进行交互,而发布订阅模式中统一由调度中心进行处理,订阅者和发布者互不干扰。这样一方面实现了解耦,还有就是可以实现更细粒度的一些控制。比如发布者发布了很多消息,但是不想所有的订阅者都接收到,就可以在调度中心做一些处理,类似于权限控制之类的。还可以做一些节流操作。
观察者模式与订阅模式
4. 双向数据绑定之(剖析 observer,Dep,watch 三者关系)#
(1)observer
总结:Observer 的作用是对整个 Data 进行监听,在 Observer 类内部通过 defineReactive(里边是 Object.defineProperty)方法劫持 data 的每一个属性的 getter 和 setter,
详情:Observer 类主要干了以下几件事:
1. 给 data 绑定一个__ob__属性,用来存放 Observer 实例,避免重复绑定
2. 如果 data 是 Object, 遍历对象的每一个属性进行 defineReactive 绑定
3. 如果 data 是 Array, 则需要对每一个成员进行 observe。vue.js 会重写 Array 的 push、pop、shift、unshift、splice、sort、reverse 这 7 个方法,保证之后 pop/push 等操作进去的对象也有进行双向绑定. (具体代码参见 observer/array.js)
(2)dep
Dep 是一个发布者,依赖收集之后 Dep 中会有一个 subs 存放一个或多个观察者,在数据变更的时候通知所有的 watcher
(3) 总结下(1)(2)
Dep 和 Observer 的关系就是 Observer 监听整个 data,遍历 data 的每个属性给每个属性绑定 defineReactive 方法劫持 getter 和 setter, 在 getter 的时候往 Dep 类里塞依赖(dep.depend),在 setter 的时候通知所有 watcher 进行 update (dep.notify)
(4) Watcher
watcher 接受到通知之后,会通过回调函数进行更新
watcher 需要实现以下两个作用:
1.dep.depend () 的时候往 dep 里添加自己;
2.dep.notify () 的时候调用 watcher.update () 方法,对视图进行更新;
源码解读 - 三者关系最易理解 *
辅助理解 1
辅助理解 2— 不同角度理解
5.diff 算法#
(1)Virtual Dom 只会对同一个层级的元素进行对比
(2)vue 是先根据真实 DOM 生成一颗 virtual DOM ,当 virtual DOM 某个节点的数据改变后会生成一个新的 Vnode ,然后 Vnode 和 oldVnode 作对比,发现有不一样的地方就直接修改在真实的 DOM 上,然后使 oldVnode 的值为 Vnode ,来实现更新节点。
(3)原理简述
)先去同级比较,然后再去比较子节点
)先去判断一方有子节点一方没有子节点的情况
)比较都有子节点的情况
)递归比较子节点
(4)原理图
(5)指针对比策略
新前与旧前
新后与旧后
新后与旧前(新前指向的节点,移动的旧后之后)
新前与旧后(新前指向的节点,移动的旧前之前)
(未命中时,循环中有 - 更改 ;循环中无 - 插入)
diff 算法
(6)源码总结:
(1)看两个是否是同一个元素,如果不是则用 Vnode 替换 oldVnode。patchVnode 会比较这两个节点,判断 Vnode 和 oldVnode 是否指向同一个对象,如果是,那么直接 return,复用老的真是元素。(2)如果不是会用新的子节点和旧的字节做比较。如果他们都有文本节点并且不相等,那么将 el 的文本节点设置为 Vnode 的文本节点;如果两个都有子节点的情况下会调用 updateChildren 方法比较他们的子节点;只有新的节点有子节点而旧节点没有子节点,就会把新增的子节点插入到旧的 dom 中;如果当前新的节点中没有子节点,旧的中有子节点,然后就会把旧的节点删除掉;
(3)updateChildren 方法中,先定义了四对指针,先比较新的和旧的第一个子节点是否一样,如果一样会移动前面两个指针,以此类推,如果比对最后新的节点多了一个子节点就把它插入旧的中。如果开始第一个子节点不一样就从后面开始进行比较(从尾子节点开始比较),比到最后把新增的节点插入到旧的 dom 中。还有这种情况就是头和尾节点都不相等的情况下,用当前的头和旧的尾节点进行比较,如果一样就把旧的尾节点移到前面去,然后将旧的尾指针向前移动一位,当前头指针移动到下一个子节点上。另一种就是用旧的结尾和新的开头节点进行比较,四种比较策略。如果存在 key,就会拿的当前子节点的 key 去旧的子节点中找,如果找到就将它移动到旧节点的前面,然后就将指针移向当前节点的第二个子节点上,以此类推,如果当前子节点没有就将它直接插入到旧的节点中,最后把旧的节点中多余出的子节点删除掉。
6.vue 的模板解析流程及原理#
(1)模板解析 - 较全
(4)模板解析详细过程 - 解析器,优化器,代码生成器 - 补充 1
(5)模板解析详细过程 - 解析器,优化器,代码生成器 - 补充 2
(6)模板解析详细过程 - 解析器,优化器,代码生成器 - 思路很清晰
自己的思路(总计以上):
1. 解析器 parser
(1)将模板字符串会扔到 parseHTML 函数中的 while 中去循环,然后 一段一段的截取,直到最后截没了,这时就解析成了 element AST。
(2)start 方法(每当解析到标签的开始位置时,触发该函数)
(3)end 方法(每当解析到标签的结束位置时,触发该函数)
(4)每截取一段标签的开头就 push 到 stack 中,解析到标签的结束就 pop 出来,stack 就是用来记录一个层级关系,记录 DOM 的深度。
(5)charts 方法(每当解析到文本时,触发该函数)
(6)comment 方法(解析到注释执行)
2. 优化器 optimizer
(1)优化器的目标是找出那些静态节点并打上标记
(2)
每次重新渲染的时候不需要为静态节点创建新节点;
在 Virtual DOM 中 patching 的过程可以被跳过;
(3)主要方法
isStatic 方法(判断是否是静态节点)
markStatic 方法(标记静态节点)
markStaticRoots 方法(标记静态根节点)
3. 代码生成器 code generator
(1)生成 render 函数代码字符串
(2)主要方法
genData 根据 AST 上当前节点上都有什么属性,然后针对不同的属性做一些不同的处理(例如 atrrs 和 props 会调用 genProps 进行处理),最后拼出一个字符串
genChildren 中生成 children 的过程其实就是循环 AST 中当前节点的 children
7.vue 的整体流程#
第一步:解析模板成 render 函数
第二步:响应式开始监听
第三步:首次渲染,显示页面,且绑定依赖
第四步:data 属性变化,触发 rerender
8.vue 搭建脚手架#
9. 列表返回,在当前位置,并且页面中不会有很多 dom 元素#
10.v-model 传入的是子组件,监听 change#
11. 伪类和伪元素的区别#
12. $emit 的实现原理#
13.Promise 原理及手写实现#
promise 最全 1
promise 最全 2
promise 简介版本
14. 父子组件嵌套,生命周期执行顺序#
父 beforeCreate->
父 created->
父 beforeMount->
子 beforeCreate->
子 created->
子 beforeMount->
子 mounted->
父 mounted
对应问题的解决方法看一下连接
vue 父子组件执行顺序 1
vue 父子组件执行顺序 2
15. 移动端 1px 像素问题#
16.webpack 打包优化及自己编写 loader#
17.rem 和 vh,vw 的区别和使用#
18. 宏任务和微任务(是什么,区别)#
19. 前端请求,请求头中的内容#
.css 动画 (案例)#
. 如何做技术选型#
方便
技术实力
20.vue 混入#
(1)混入官网
(2)混入实战案例
(3)注意点(优先级):
钩子函数,方法,数据对象,局部混入,全局混入
五、react#
六、小程序#
七、webpack#
1.webpack 的面试题#
1.webpack 面试汇总
webpack – loader 和 plugin 原理及区别
webpack 常用的 Loader:
css-loader:加载 CSS,支持模块化、压缩、文件导入等特性
style-loader:把 CSS 代码注入到 JavaScript 中,通过 DOM 操作去加载 CSS。
file-loader:把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件
url-loader:能在文件很小 (8KB) 的情况下以 base64 的方式把文件内容注入到代码中去
image-loader:加载并且压缩图片文件
babel-loader:把 ES6 转换成 ES5
eslint-loader:通过 ESLint 检查 JavaScript 代码
source-map-loader:加载额外的 Source Map 文件,以方便断点调试
有哪些常见的 Plugin
html-webpack-plugin 就是生成 html 文件。
Optimize CSS Assets Webpack Plugin 一个优化 \ 减少 CSS 资源的 Webpack 插件。
uglifyjs-webpack-plugin:压缩 js
commons-chunk-plugin:提取公共代码
clean-webpack-plugin 用于在 building 之前删除你以前 build 过的文件,清楚 dist 中重复的文件
HotModuleReplacementPlugin 热更新
define-plugin:定义环境变量
ProvidePlugin 可以在任何地方自动加载模块而不需要 import 或 require 方法
2.Loader 和 Plugin 的不同?
(1)不同的作用
Loader 直译为 "加载器"。Webpack 将一切文件视为模块,但是 webpack 原生是只能解析 js 文件,如果想将其他文件也打包的话,就会用到 loader。 所以 Loader 的作用是让 webpack 拥有了加载和解析非 JavaScript 文件的能力。
Plugin 直译为 "插件"。Plugin 可以扩展 webpack 的功能,让 webpack 具有更多的灵活性。 在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。
(2)不同的用法
Loader 在 module.rules 中配置,也就是说他作为模块的解析规则而存在。 类型为数组,每一项都是一个 Object,里面描述了对于什么类型的文件(test),使用什么加载 (loader) 和使用的参数(options)
Plugin 在 plugins 中单独配置。 类型为数组,每一项是一个 plugin 的实例,参数都通过构造函数传入。
3.webpack 生命周期(事件节点)
(1)option 初始化
(2)compile 开始编译
(3)make 分析入口文件创建模块对象
(4)build-module 构建模块
(5)after-compile 完成所有模块构建,结束编译过程
(6)emit , compiler 开始输出生成的 assets, 插件最后有机会修改 assets
(7)after-emit 输出完成
4.webpack 代码分割
(1) webpack 配置文件中的 entry 字段添加新的入口:
如果入口 chunks 之间包含重复的模块,那些重复模块都会被引入到各个 bundle 中
这种方法不够灵活,并且不能将核心应用程序逻辑进行动态拆分代码
举个例子,index 和 another 这两个入口文件都包含了 lodash 这个模块,那分割出来的两个 bundle 都会包含 lodash 这个模块,冗余了。解决这个问题就需要 CommonsChunkPlugin 插件。
(2)CommonsChunkPlugin
把业务代码,和第三方模块代码分割开了。
(3) import () 语法
传入模块的路径,import () 会返回一个 Promise。这个模块就会被当作分割点。意味着这个模块和它的子模块都会被分割成一个单独的 chunk。
5.webpack 打包优化
时间和空间两个方面
webpack 打包优化的完美解决方案
空间:
(1) CommonsChunk
webpack 建议使用 CommonsChunk 来单独打包第三方库
缺点:CommonsChunk 虽然可以减少包的大小,但存在问题是:即使代码不更新,每次重新打包,vendor 都会重新生成,不符合我们分离第三方包的初衷。
(2)Externals
相比于前者,webpack 提供 Externals 的方法,可以通过外部引用的方法,引入第三方库: jquery
无法解决以下问题:
import xxx from 'react/src/xx';
webpack 遇到此问题时,会重新打包 react 代码
(3)DLL & DllReference
只要第三方库没有变化,之后的每次 build 都只需要去打包自己的业务代码,解决 Externals 多次引用问题
时间:
(4)优化 loader 配置
4.1 缩小文件匹配范围 (include/exclude)
通过排除 node_modules 下的文件 从而缩小了 loader 加载搜索范围 高概率命中文件
4.2 缓存 loader 的执行结果 (cacheDirectory)
cacheDirectory 是 loader 的一个特定的选项,默认值是 false。指定的目录 (use: ‘babel-loader?cacheDirectory=cacheLoader’) 将用来缓存 loader 的执行结果,减少 webpack 构建时 Babel 重新编译过程。如果设置一个空值 (use: ‘babel-loader?cacheDirectory’) 或 true (use: ‘babel-loader?cacheDirectory=true’) 将使用默认的缓存目录 (node_modules/.cache/babel-loader),如果在任何根目录下都没有找到 node_modules 目录,将会降级回退到操作系统默认的临时文件目录。
(5)resolve 优化配置
5.1 优化模块查找路径 resolve.modules
Webpack 的 resolve.modules 配置模块库(即 node_modules)所在的位置,在 js 里出现 import ‘vue’ 这样不是相对、也不是绝对路径的写法时,会去 node_modules 目录下找。但是默认的配置,会采用向上递归搜索的方式去寻找,但通常项目目录里只有一个 node_modules,且是在项目根目录,为了减少搜索范围,可以直接写明 node_modules 的全路径;同样,对于别名 (alias) 的配置,亦当如此:
5.2resolve.alias 配置路径别名
5.3resolve.extensions
当引入模块时不带文件后缀 webpack 会根据此配置自动解析确定的文件后缀
导出语句尽可能带上后缀
(6)module.noParse
用了 noParse 的模块将不会被 loaders 解析,所以当我们使用的库如果太大,并且其中不包含 import require、define 的调用,我们就可以使用这项配置来提升性能,让 Webpack 忽略对部分没采用模块化的文件的递归解析处理。
(7)HappyPack
HappyPack 是让 webpack 对 loader 的执行过程,从单一进程形式扩展为多进程模式,也就是将任务分解给多个子进程去并发的执行,子进程处理完后再把结果发送给主进程。从而加速代码构建 与 DLL 动态链接库结合来使用更佳。
(8)ParallelUglifyPlugin
这个插件可以帮助有很多入口点的项目加快构建速度。把对 JS 文件的串行压缩变为开启多个子进程并行进行 uglify。
(9)Tree Shaking
剔除 JavaScript 中用不上的代码
八、http#
1.URL 和 URI 有什么区别?#
URI 是统一资源标识符,相当于一个人身份证号码
Web 上可用的每种资源如 HTML 文档、图像、视频片段、程序等都是一个来 URI 来定位的
URI 一般由三部组成
①存放资源的主机名
②访问资源的命名机制
③资源自身的名称,由路径表示,着重强调于资源。
URL 是统一资源定位符,相当于一个人的家庭住址
URL 是 Internet 上用来描述信息资源的字符串,
URL 一般由三部组成
①协议 (或称为服务方式)
②存有该资源的主机 IP 地址 (有时也包括端口号)
③主机资源的具体地址。如目录和文件名等
九、性能优化#
1. 浏览器:渲染进程 有哪些线程#
(1)概念:
进程:是系统进行资源分配基本单位
线程:线程是进程中的一个实体,是被系统独立调度和分派的基本单位
关系:进程由单个或多个线程组成;多个线程之间是可以相互协作完成工作的;同一个进程中各个线程之间共享同一块内存空间
(2)浏览器的多进程:
浏览器的进程大概分为以下这几种:
1,浏览器主进程 (Browser 进程):控制 chrome 的地址栏,书签栏,返回和前进按钮,同时还有浏览器的不可见部分,例如网络请求和文件访问
2,第三方插件进程:每种插件一个进程,插件运行时才会创建
3,浏览器渲染进程(浏览器内核,内部是多线程的):负责界面渲染,脚本执行,事件处理等
4,GPU 进程:最多一个,用于 3D 绘制
(3)浏览器的渲染进程(浏览器的内核)
浏览器内核是通过取得页面内容,整理信息,计算和组合最终输出可视化的图像结果,通常也被视为浏览器渲染进程。Chrome 浏览器为每个 Tab 页面单独启用进程,因此每个 tab 网页都有其独立的渲染引擎实例。有些渲染进程会被浏览器自己的优化机制进行合并。
(4)浏览器内核是多线程的
1.GUI 线程
负责渲染浏览器界面,GUI 更新会被保存在一个队列中等到 JS 引擎空闲时立即被执行,当界面需要重绘或由于某种操作引发的 reflow 时,该线程就会执行。
2.js 引擎线程
也称为 JS 内核,负责处理 JavaScript 脚本程序,JS 引擎一直等待着任务队列中任务的到来,然后加以处理,一个 Tab 页中无论什么时候都只有一个 JS 线程在运行 JS 程序
3. 定时触发器线程 (多个定时器时是否会有多个定时触发线程)
传说中的 setInterval 与 setTimeout 所在线程,计数线程,浏览器定时计数器并不是由 JS 引擎计数的。
4. 事件触发线程
属于浏览器而不是 JS 引擎,当 JS 引擎执行代码块如 setTimeOut 时(也可来自浏览器内核的其他线程,如鼠标点击、AJAX 异步请求等),会将对应任务添加到事件线程中。当对应的事件符合触发条件被触发时,该线程会把是事件添加到待处理队列的队尾,等待 JS 引擎的处理。
5. 异步 http 请求线程
XMLHttpRequest 在连接后是通过浏览器新开的一个线程请求。当检测到状态更新时,如果没有设置回调函数,异步线程就产生状态 变更事件,将这个回调再放入事件队列中,等待 JS 引擎执行。
浏览器:渲染进程 有哪些线程 — 全面版本
浏览器:渲染进程 有哪些线程 — 补充版本
2. 浏览器缓存机制#
(1)浏览器缓存机制
当浏览器再次访问一个已经访问过的资源时,它会这样做:
1. 看看是否命中强缓存,如果命中,就直接使用缓存了。
2. 如果没有命中强缓存,就发请求到服务器检查是否命中协商缓存。
3. 如果命中协商缓存,服务器会返回 304 告诉浏览器使用本地缓存。
4. 否则,返回最新的资源。
(2)浏览器缓存
1.sessionStorage
优点:可以临时存储,关闭页面标签自动回收,不支持跨页面交互
缺点:只能作为临时存储,不能存储持久化
2.localStorage(存储大小一般为 5M)
优点:用于长久保存整个网站的数据,保存的数据没有过期时间,直到手动去删除。
缺点:存在大小限制,IE8 以上的 IE 版本才支持这个属性;目前所有的浏览器中都会把 localStorage 的值类型限定为 string 类型,这个在对我们日常比较常见的 JSON 对象类型需要一些转换
3.cookie(谷歌可以存储的大小约 4kb)
优点:兼容性最好,几乎所有的浏览器都支持
缺点:大小有限制,而且每次发送请求,请求头里会带着 cookie 一起发过去,现在基本大多数登录的合法性验证都是用 cookie 验证的
4.userData
优点:出现的时间比 sessionStorage 要早
缺点:IE 专门的存储方式,存储大小有限,单个文件的大小限制是 128KB,一个域名下总共可以保存 1024KB 的文件,文件个数应该没有限制。在受限站点里这两个值分别是 64KB 和 640KB
3. 常用的设计模式有哪些#
1. 单例模式:构造方法私有化,让除了自己类能创建,其他类都不能创建。
优: 在单例模式中,活动的单例只有一个实例,对单例类的所有实例化得到的都是相同的一个实例。这样就 防止其它对象对自己的实例化,确保所有的对象都访问一个实例
缺:不适用于变化的对象
2.工厂模式:就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。
优:明确了各自的职责和权利,有利于整个软件体系结构的优化。
缺:不能自由的添加新的类,则就需要改变工厂类了
3.代理模式:一个类代表另一个类的功能
优:对公共接口进行代理
缺:并不是所有类都有接口,对于没有实现接口的类,便无法使用该方方式实现动态代理
4.观察者模式:发布-订阅(Publish/Subscribe)模式
[设计模式](https://www.cnblogs.com/yueguanguanyun/p/9584501.html)
[设计模式补充](https://blog.csdn.net/shadowfall/article/details/112001884)
4. 进程 - 线程 - 协程 - 纤程#
1. 进程 - 系统进行资源分配的基本单位
2. 线程 - 独立运行和调度的基本单位
3. 协程 - 是用户模式下的轻量级线程,协程的调度完全有应用程序来控制
4. 纤程 - 为了帮助各公司更快、更正确地将他们的代码移植到 Windows,Microsoft 在操作系统中增加了纤程(Fiber);纤程是更轻量级的线程,一个线程可以包含一个或多个纤程 ;纤程是在用户模式下实现的。
进程 线程 协程 管程 纤程 概念对比理解
十、node#
node 面试题 1
node 面试题 3
node 面试题 4
未整理
十一、算法#
十二、前端其他#
1.webpack
2.axios
3. 前端跨域(牧)#
跨域详解
总结:
协议,域名,端口,有一个不一致就是跨域
解决方案:
(1)document.domain+iframe 跨域
(2)JSONP 的 CallBack(script 标签的 src 属性并不被同源策略所约束)
(3)CORS 跨域资源共享(Access-Control-Allow-Origin: *)
(4)Nginx 反向代理
# Nginx代理服务器
server {
listen 80;
server_name www.hahaha.com;
location / {
# 反向代理地址
proxy_pass http://www.hahaha1.com:9999;
# 修改Cookie中域名
proxy_cookie_domain www.hahaha1.com www.hahaha.com;
index index.html index.htm;
# 前端跨域携带了Cookie,所以Allow-Origin配置不可为*
add_header Access-Control-Allow-Origin http://www.hahaha.com;
add_header Access-Control-Allow-Credentials true;
}
}
4. 常见 linux 命令(牧)#
Linux 常用命令及分类
Linux 命令 - 菜鸟
总结:
(1)ls -a
列出目录所有文件
(2)cd [目录名]
切换当前目录至
(3)pwd
查看当前路径
(4)mkdir t
当前工作目录下创建名为 t 的文件夹
(5)rmdir
删除空目录
(6)rm
-r 递归删除,可删除子目录及文件
-f 强制删除
删除文件
(7)mv
移动或重命名
(8)cp
拷贝文件
(9)cat
查看文件内容
(10)tar
用来压缩和解压文件
(11)ps -A
显示当前所有进程
(12)kill
杀掉进程
(13)ping
测试网络连通
5. 全局作用域中,用 const 和 let 声明的变量不在 window 上,那到底在哪里?如何去获取?#
参考详情
总结:
(1)在 ES6 中,全局对象的属性和全局变量脱钩,但是为了保持兼容性,旧的不变,所以 var、function 声明的全局变量依然可以在 window 对象上看到,而 let、const 声明的全局变量在 window 对象上看不到
(2)在全局作用域中,用 let 和 const 声明的全局变量并没有在全局对象中,只是一个块级作用域(Script)中
(3)let、const 以及 var 的区别是什么
参考一
参考二
1.var 存在变量提升;let,const 没有变量提升(var,;et,const)
2.var 定义的变量,可以跨块访问,不能跨函数访问;let,const:当前块级作用域内(var,;et,const)
3.let,cont 无法重复声明 (let,const)
4.const 声明的是基础类型(String,Number,boolean,null,undefined)时,该变量无法改变,且声明时必须初始化,否则会报错。但是声明引用类型时,则只有指向的地址无法改变,该变量可以改变。(const)
6.Vue 中 computed 和 watch 的区别#
计算属性 computed :
1. 支持缓存,只有依赖数据发生改变,才会重新进行计算
2. 不支持异步,当computed内有异步操作时无效,无法监听数据的变化
3.computed 属性值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data中声明过或者父组件传递的props中的数据通过计算得到的值
3. 如果一个属性是由其他属性计算而来的,这个属性依赖其他属性,是一个多对一或者一对一,一般用computed
5.如果computed属性属性值是函数,那么默认会走get方法;函数的返回值就是属性的属性值;在computed中的,属性都有一个get和一个set方法,当数据变化时,调用set方法。 侦听属性watch:
1. 不支持缓存,数据变,直接会触发相应的操作;
2.watch支持异步;
3.监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值;
2. 当一个属性发生变化时,需要执行对应的操作;一对多;
3. 监听数据必须是data中声明过或者父组件传递过来的props中的数据,当数据变化时,触发其他操作,函数有两个参数,
immediate:组件加载立即触发回调函数执行,
deep: 深度监听,为了发现对象内部值的变化,复杂类型的数据时使用,例如数组中的对象内容的改变,注意监听数组的变动不需要这么做。注意:deep无法监听到数组的变动和对象的新增,参考vue数组变异,只有以响应式的方式触发才会被监听到。
7.vue-router 的两种模式(hash 和 history)及区别#
参考
1.hash: # (本质是 window.location.href);history(html 新增)
2.hash - 比如这个 URL:http://www.abc.com/#/hello,hash 的值为 #/hello. 它的特点在于:hash 虽然出现在 URL 中,但不会被包括在 HTTP 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面。;history - 利用了 HTML5 History Interface 中新增的 pushState () 和 replaceState()方法
3. 调用 history.pushState () 相比于直接修改 hash ,存在以下优势:
1:pushState () 设置的新 URL 可以是与当前 URL 同源的任意 URL;而 hash 只可修改 #后面的部分,因此只能设置与当前 URL 同文档的 URL;
2:pushState () 设置的新 URL 可以与当前 URL 一模一样,这样也会把记录添加到栈中;而 hash 设置的新值必须与原来不一样才会触发动作将记录添加到栈中;
3:pushState () 通过 stateObject 参数可以添加任意类型的数据到记录中;而 hash 只可添加短字符串;
4:pushState () 可额外设置 title 属性供后续使用。
4. 存在以下劣势
1:hash 模式下,仅 hash 符号之前的内容会被包含在请求中,如http://www.abc.com, 因此对于后端来说,即使没有做到对路由的全覆盖,也不会返回 404 错误。
2:history 模式下,前端的 URL 必须和实际向后端发起请求的 URL 一致。如 htttp://www.abc.com/book/id。如果后端缺少对 /book/id 的路由处理,将返回 404 错误
8.HTTP 与 HTTPS 的区别#
- HTTPS 和 HTTP 的区别主要如下:
1、https 协议需要到 ca 申请证书,一般免费证书较少,因而需要一定费用。
2、http 是超文本传输协议,信息是明文传输,https 则是具有安全性的 ssl 加密传输协议。
3、http 和 https 使用的是完全不同的连接方式,用的端口也不一样,前者是 80,后者是 443。
4、http 的连接很简单,是无状态的;HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、 身份认证的网络协议,比 http 协议安全。
2. 客户端在使用 HTTPS 方式与 Web 服务器通信时有以下几个步骤,如图所示。
(1)客户使用 https 的 URL 访问 Web 服务器,要求与 Web 服务器建立 SSL 连接。
(2)Web 服务器收到客户端请求后,会将网站的证书信息(证书中包含公钥)传送一份给客户端。
(3)客户端的浏览器与 Web 服务器开始协商 SSL 连接的安全等级,也就是信息加密的等级。
(4)客户端的浏览器根据双方同意的安全等级,建立会话密钥,然后利用网站的公钥将会话密钥加密,并传送给网站。
(5)Web 服务器利用自己的私钥解密出会话密钥。
(6)Web 服务器利用会话密钥加密与客户端之间的通信。
9.pt,px,rem 和 em 之间区别总结#
参考一
参考二
1.px(pixel)
像素,是屏幕上显示数据的最基本的点,表示相对大小 (不同分辨率上 px 显示不同)
2.pt(point)
印刷行业常用的单位 (磅),等于 1/72 英寸,表示绝对长度
3.em
em 是相对长度单位,基于父级元素的 font-size 计算字体大小。
4.rem
相对于 html 根元素的
5.rem 和 vw,wh 的区别?
10. 如何给电话号码隐藏中间几位,变成星号,你能想出几种方法#
1. 正则替换
phonenumber.replaceAll("(\d{3})\d{4}(\d{4})","$1****$2");
2. 字符串截取拼接
substring () 方法用于提取字符串中介于两个指定下标之间的字符。
var str = ‘13812347829’; // 该号码是乱打出来的,如有侵权,请联系博主删除!
this.phoneNumber = str.substring(0,3)+’****’+str.substring(7,11);
11. 前端图片格式有哪些?这几种图片格式的区别?哪些格式可以设置透明图,哪些图片可以动态展示#
参考 1
参考 2
1.PNG
优点:
透明无损压缩;
渐进显示和流式读写;
缺点:
色彩支持少 (PNG8、PNG16、PNG32);
ie6 不支持 png24 透明效果。
2.Jpeg(jpg)
不支持透明,
不支持动画,
隔行渐进显示,
Jpeg 是最适 web 上面的摄影图片,
3.Gif
透明性,
支持动画,
无损耗性,
间隔渐进显示,
4.SVG
易于修改和编辑,
SVG 图形格式可以用来动态生成图形(可用 SVG 动态生成具有交互功能的地图,嵌入网页中,并显示给终端用户)
矢量图形,文件比较小,同时也能提供高清晰的画面,适合于直接打印或输出
12.svg 图片怎么显示#
1.tag 的 src
此时:大多数浏览器不会加载 SVG 自身引用的文件 (其他图像,外部脚本,字体文件等)
2. 使用 Object 或 iframe 导入 SVG 图像
<object type="image/svg+xml" data="example.svg" class="example">
My Example SVG
</object>
<iframe src="example.svg" class="example"></iframe>
作为应用程序对象引入的 SVG 文件尺寸和作为引入时类似,并且不会继承定义在父文档中的任何样式。
但是,与不同的是,此方式可是包含外部文件,且脚本可以在 object 和父文档之间进行通信。
3. 使用内联 SVG
<!DOCTYPE html>
<html>
<body>
<svg>
...
</svg>
</body>
</html>
直接嵌入的 SVG 会继承父文档的样式,默认情况下采用 inline 的方式进行显示。
链接:https://www.cnblogs.com/sese/p/8669746.html
https://segmentfault.com/a/1190000004447771
13. 事件代理和事件委托#
1. 举例:收快递
(1)一是三个人在公司门口等快递;二是委托给前台代为签收。
(2)老员工代收,新员工也可以代收
2. 事件委托是利用事件的冒泡原理来实现的,事件从最深的节点开始,然后逐步向上传播事件;
例:给 ul 中的每一个 li 添加点击事件,只需要将事件委托给 父元素 ul;
不需要给每一个 li 绑定点击事件;
当 li 被点击时,由于冒泡原理,事件就会冒泡到 ul 上,因为 ul 上有点击事件,所以事件就会触发;
当前所有的 li 和动态添加的 li 元素都实现了委托;
3. 一、事件捕获阶段,二、事件目标阶段,三、事件冒泡阶段
- 1. 管理的函数变少了。 2. 可以方便地动态添加和修改元素,不需要因为元素的改动而修改事件绑定。 3.JavaScript 和 DOM 节点之间的关联变少了,这样也就减少了因循环引用而带来的内存泄漏发生的概率。
14. 引用类型和基本数据类型的区别#
1.(1)js 常用的基本数据类型包括 undefined、null、number、boolean、string;
(2)js 的引用数据类型也就是对象类型 Object,比如:Object、array、function、data 等;
(3)
var num=10;// 值类型,值在栈上
var obj={};// 复杂类型,对象在堆,地址 (引用) 在栈
2. 数据类型判断
(1)typeof
对于基本类型,除 null(返回 object) 以外,均可以返回正确的结果。
对于引用类型,除 function 以外,一律返回 object 类型。
对于 function 返回 function 类型。
(2)instanceof
instanceof 一般检测数组
[] instanceof Object;// true
[] instanceof Array;// true
所以有弊端
(3)Object.prototype.toString 可以准确 判断类型
15. 前端 call,apply,bind 的区别#
1,call ()、apply ()、bind () 都是用来改变 this 指向
2.(1)调用: bind 返回新函数,需要调用执行
call 和 apply 不返回新函数,直接调用
(2)参数
obj.myFun.call (db,‘成都’,‘上海’); // 德玛 年龄 99 来自 成都去往上海
obj.myFun.apply (db,[‘成都’,‘上海’]); // 德玛 年龄 99 来自 成都去往上海
obj.myFun.bind (db,‘成都’,‘上海’)(); // 德玛 年龄 99 来自 成都去往上海
apply 第二个参数是数组
16. 不借助第三个变量,怎么交换变量#
1. 算数运算
a = a + b;
b = a - b; // b = (a +b)-b,即 b = a
a = a - b; // a = (a+b)-a
2. 位运算 异或
a = a^b;
b = a^b; //b = (a ^ b)^b, 即 b=a;
a = a^b; // a = (a ^ b)^a
17.keep-alive,如何使用,缓存数量有限制吗#
1. 作用:缓存组件,避免组件重新渲染
2. 使用:
(1)include - 字符串或正则表达式。只有名称匹配的组件会被缓存。
exclude - 字符串或正则表达式。任何名称匹配的组件都不会被缓存。
max - 数字。最多可以缓存多少组件实例。
<keep-alive include="home">
<router-view></router-view>
</keep-alive>
(2)路由中添加字段,在 keep-alive 处动态判断
3. 如果缓存的组件想要清空数据或者执行初始化方法,在加载组件的时候调用 activated 钩子函数,如下:
activated: function () {
this.data = ‘'
}
18.export 和 export default#
1. 希望外部能够读取模块内部的某个变量,就必须使用 export 关键字输出该变量
2.export 导出多个 多次使用, 导入时使用大花括号按需引入
3.export default 使用一次匿名导出,导入时可以任意起名
19. 用递归计算一个数的阶乘#
def f(x):
if x >= 1:
return x*f(x-1) #自己调用自己,6得不行
else:
return 1 #防止进入死循环
a = int(input("请输入一个数字"))
print(f(a))
结果输出:
请输入一个数字5
120
Process finished with exit code 0
19. 扩展运算符#
1. 取出可遍历的每一项,拷贝到当前对象之中
2. 用法:
(1)数组(扩展运算符)
1.1 解构赋值
如果将扩展运算符用于数组赋值,只能放在参数的最后一位,否则会报错。
const [first, ...rest] = [1, 2, 3, 4, 5];
first // 1
rest // [2, 3, 4, 5]
const [first, ...rest] = [];
first // undefined
rest // []:
const [first, ...rest] = ["foo"];
first // "foo"
rest // []
1.2 复制数组
1.3 合并数组
(2) 对象
拓展运算符(…)用于取出 参数对象 所有 可遍历属性 然后拷贝到当前对象。
let person = {name: "Amy", age: 15};
let someone1 = { name: "Mike", age: 17,...person};
console.log(someone1); //{name: "Amy", age: 15}
(3)函数
函数不确定参数个数
20. 深浅拷贝#
深浅拷贝都是对于引用数据类型而言的;
浅拷贝就只是复制对象的引用,拷贝后的对象发生变化,原对象也会发生变化。只有深拷贝才是真正地对对象的拷贝;
常见的浅拷贝:
concat()、
slice()
Object.assign()、
扩展运算
深拷贝:
JSON.stringify/parse 缺点: undefined、任意的函数以及 symbol 值,在序列化过程中会被忽略
递归遍历,判断数据类型,直到是基本数据类型时在进行赋值
21. 变异数组#
触发数组的响应式
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
22 . 原型 && 原型链#
当试图得到一个对象的属性时,如果这个对象本身不存在这个属性,那么就会去它构造函数的’prototype’属性中去寻找。那又因为’prototype’属性是一个对象,所以它也有一个’_ _ proto_ _' 属性。
23. 继承的实现#
1、原型链继承
子类的__proto__指向父类的一个实例
缺点: 首先呢是无法实现多继承,其次主要因为来自原型对象的所有属性被所有实例共享,而且创建子类实例时,无法向父类构造函数传参,要想为子类新增属性和方法,必须要在 Student.prototype = new Person () 之后执行,不能放到构造器中。
function father(phone,sex){
this.phone = phone;
this.sex = sex;
this.say = function(){
console.log("这是你爹的方法");
}
}
function son(name,age){
this.name = name;
this.age = age;
this.eat = function(){
console.log("吃");
}
}
son.prototype = new father("110","女");
var tomCat = new son("tomcat",15);
2. 构造函数继承
子类内部调用父类方法,并通过 call 改变它的作用域,指向子类的 this,从而把父类的方法拿过来。
缺点:就是它的实力不是父类的实例,而且只能继承父类的属性,父类的原型上的无法继承,无法实现函数复用,
function father2(phone,sex){
this.phone = phone;
this.sex = sex;
this.say = function(){
console.log("这是你爹的方法");
}
}
function son2(name,age){
father2.call(this,"120","男")
this.name = name;
this.age = age;
this.eat = function(){
console.log("吃");
}
}
var jerui = new son2("tomcat",15);
console.log(jerui);
3. 原型链 + 构造函数的组合继承
通过构造函数继承属性,通过原型继承方法
缺点:调用了两次父类构造函数,生成了两份实例
4. 组合继承优化
通过父类原型和子类原型指向同一对象,子类可以继承到父类的公有方法当做自己的公有方法,而且不会初始化两次实例方法 / 属性,避免的组合继承的缺点。
5.ES6 中的 class 继承
class 可以通过 extends 关键字实现继承,还可以通过 static 关键字定义类的静态方法。
ES5 的继承,实质是先创造子类的实例对象 this,然后再将父类的方法添加到 this 上面(Parent.apply (this))。ES6 的继承机制完全不同,实质是先将父类实例对象的属性和方法,加到 this 上面(所以必须先调用 super 方法),然后再用子类的构造函数修改 this。
需要注意的是,class 关键字只是原型的语法糖,JavaScript 继承仍然是基于原型实现的。
24. 作用域 && 作用域链#
1. 在 Javascript 中,作用域分为 全局作用域 和 函数作用域
全局作用域:
代码在程序的任何地方都能被访问,window 对象的内置属性都拥有全局作用域。
函数作用域:
在固定的代码片段才能被访问
2. 获取一个变量的值
首先在当前作用域中没有查到值,就会向上级作用域去查,直到查到全局作用域,这么一个查找过程形成的链条就叫做作用域链。
25.nginx 常见的面试题#
十三、最新#
十四、后端#
node
koa2
十五、牧原#
十六、安全#
1.XSS#
(1)跨站脚本攻击(XSS)通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。(例如输入框输入)
(2)常用的 XSS 攻击手段和目的有:
1、盗用 cookie,获取敏感信息。
2、利用植入 Flash,通过 crossdomain 权限设置进一步获取更高权限。
3、利用 iframe、XMLHttpRequest 等方式,以(被攻击)用户的身份执行一些管理动作,或执行一些一般的如发微博、加好友、发私信等操作。
(3)防御:
1.HttpOnly 防止劫取 cookie
2. 用户的输入检查
3. 服务器的输出检查
2.csrf#
(1)跨站请求伪造(CSRF)是一种挟制用户在当前已登录的 Web 应用程序上执行非本意的操作的攻击方法。攻击者盗用了你的身份,以你的名义发送恶意请求,对服务器来说这个请求是完全合法的,但是却完成了攻击者所期望的一个操作,比如以你的名义发送邮件、发消息,盗取你的账号,添加系统管理员,甚至于购买商品、虚拟货币转账等。
(2)防御:
1. 验证 HTTP Referer 字段;
2.token 验证
3. 验证码