面试不断总结分析,分类总结,最新总结,但是记住万变不离其宗
基础+原理+算法全套而已
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可以控制的。
(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%; }
(1)标准盒模型
总长=width+padding(左右)+border(左右)+margin(左右)
在标准盒模型中,当width不变时,padding(左右)和borde(左右)的改变都是要改变总长的。
(2)怪异盒模型
总长=width+margin(左右)
在怪异盒模型的总长中width的大小不变时,padding(左右)和border(左右)的改变只在width中变化,不会改变总长的。
(3)
当设置box-sizing:content-box时,为标准模式,也是默认模式;
当设置为box-sizing:border-box时,为怪异模式;
(1)sass-less
(2)sass文档
(1)return关键字并不是专门用于跳出循环的,return的功能是结束一个方法
与continue和break不同的是,return直接结束整个方法,不管这个return处于多少层循环之内
(2)continue的功能和break有点类似,区别是continue只是中止本次循环,接着开始下一次循环。而break则是完全中止循环。
(3)break用于完全结束一个循环,跳出循环体
1.用户输入url 到 浏览器拿到服务端返回的数据
第一部分:
(1)通过DNS解析获得网址的对应IP地址
1.首先查看本地 hosts 文件
2.发出一个 DNS请求到本地DNS服务器(查询它的缓存记录—递归的方式进行查询)
3.本地DNS服务器还要向DNS根服务器进行查询(返回域名服务器地址—迭代过程)
4.本地DNS服务器向域名的解析服务器发出请求,这时就能收到一个域名和IP地址对应关系,本地DNS服务器不仅要把IP地址返回给用户电脑,还要把这个对应关系保存在缓存中
(2)浏览器与服务器TCP三次握手
这个讲的很不错:从输入URL到页面展示的详细过程
(1)
这是因为服务端在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。而关闭连接时,当收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方也未必全部数据都发送给对方了,所以己方可以立即close,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送。
TCP四次挥手及相关
TCP第四次挥手为什么要等待2MSL
tcp三次握手四次挥手详情
(1)DOM节点中的各个元素都是以盒模型的形式存在,这些都需要浏览器去计算其位置和大小等,这个过程称为relow;当盒模型的位置,大小以及其他属性,如颜色,字体,等确定下来之后,浏览器便开始绘制内容,这个过程称为repain。
(2)引起回流:添加或者删除可见的DOM元素,元素位置改变,元素尺寸改变——边距、填充、边框、宽度和高度,内容改变
引起重绘:颜色,背景改变
(3)关系:回流必将引起重绘,而重绘不一定会引起回流
(1)防抖
触发事件后在 100 秒内执行一次,如果在 n100秒内又触发了事件,则会重新计算函数执行时间
例如搜索框输入时实时搜索
(2)节流,
就是指连续触发事件,一段时间内只执行一次函数。
短信验证码,发送一次,60s后才能再次发送
(1)脱离文档流:
float
position:absolute
position: fixed
(2)怎么恢复文档流:
对于float 的元素,对父级元素可以使用overflow:hidden
clear:both
(3)position:relative这个属性并没有脱离文档流的,所以元素本身所占的位置会保留
(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)宏任务,微任务
宏任务和微任务的分类
执行顺序的案例
宏任务和微任务
(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 树中,另一个在字典中。将来你决定删除这些行时,需要把两个引用都清除。
(1)我的封装
圆环绘制
水印背景
(2)封装思路及注意事项
封装参考
封装参考
个人思路补充:
1.我个人一般先是面向过程编程,然后基本功能实现之后,在改造为面向对象编程
2.一般有以下几个基本步骤:
① 创建一个构造函数
② 变量改为属性
③ 函数改为原型方法(有些实现某块具体功能的代码也可抽离成原型方法)
④ 更正某些不正确的this指向
(1)try/catch无法捕获promise.reject的问题,原因是try catch里面不能拦截异步代码
function f2() {
try {
Promise.reject('出错了');
} catch(e) {
console.log(e)
}
}
f2() //Uncaught (in promise)
解决:
(1.1)用async aweit
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的问题
(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
案例
big.js
官网
github
localstorage
vuex
indexDB
(1)没有原型属性
(1)不能使用new命令
(2)不能是使用arguments
(3)不能当作generator函数,不能使用yield命令
http1与http2区别 以及http和https的区别
promise与async,await的区别
(1)es6其他
es6其他
(2)es6新增基本数据类型Symbol
es6新增基本数据类型Symbol
data是对象的话,会发生多个地方的相同组件操作同一个Data属性,导致数据混乱
是函数的话返回的是独立的全新的数据,不会相互影响(只有函数{}构成作用域)
1.props传递数据
适用场景:父组件传递数据给子组件
2. (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方法执行真正的业务逻辑
});
(1)观察者模式和发布订阅模式最大的区别就是发布订阅模式有个事件调度中心。
(2)
(3)观察者模式中观察者和目标直接进行交互,而发布订阅模式中统一由调度中心进行处理,订阅者和发布者互不干扰。这样一方面实现了解耦,还有就是可以实现更细粒度的一些控制。比如发布者发布了很多消息,但是不想所有的订阅者都接收到,就可以在调度中心做一些处理,类似于权限控制之类的。还可以做一些节流操作。
观察者模式与订阅模式
(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—不同角度理解
(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去旧的子节点中找,如果找到就将它移动到旧节点的前面,然后就将指针移向当前节点的第二个子节点上,以此类推,如果当前子节点没有就将它直接插入到旧的节点中,最后把旧的节点中多余出的子节点删除掉。
(1)模板解析-较全
(2)模板解析-补充-一般指令vs事件指令
(3)模板解析详细过程-解析器,优化器,代码生成器
(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
第一步:解析模板成 render 函数
第二步:响应式开始监听
第三步:首次渲染,显示页面,且绑定依赖
第四步:data 属性变化,触发 rerender
promise最全1
promise最全2
promise简介版本
父beforeCreate->
父created->
父beforeMount->
子beforeCreate->
子created->
子beforeMount->
子mounted->
父mounted
对应问题的解决方法看一下连接
vue父子组件执行顺序1
vue父子组件执行顺序2
方便
技术实力
(1)混入官网
(2)混入实战案例
(3)注意点(优先级):
钩子函数,方法,数据对象,局部混入,全局混入
react面试题
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代码分割
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中用不上的代码
URI是统一资源标识符,相当于一个人身份证号码
Web上可用的每种资源如HTML文档、图像、视频片段、程序等都是一个来URI来定位的
URI一般由三部组成
①存放资源的主机名
②访问资源的命名机制
③资源自身的名称,由路径表示,着重强调于资源。
URL 是统一资源定位符,相当于一个人的家庭住址
URL是Internet上用来描述信息资源的字符串,
URL一般由三部组成
①协议(或称为服务方式)
②存有该资源的主机IP地址(有时也包括端口号)
③主机资源的具体地址。如目录和文件名等
(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引擎执行。
浏览器:渲染进程 有哪些线程—全面版本
浏览器:渲染进程 有哪些线程—补充版本
(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
1.进程 -系统进行资源分配的基本单位
2.线程-独立运行和调度的基本单位
3.协程-是用户模式下的轻量级线程,协程的调度完全有应用程序来控制
4.纤程-为了帮助各公司更快、更正确地将他们的代码移植到Windows,Microsoft 在操作系统中增加了纤程(Fiber);纤程是更轻量级的线程,一个线程可以包含一个或多个纤程 ;纤程是在用户模式下实现的。
进程 线程 协程 管程 纤程 概念对比理解
node面试题1
node面试题3
node面试题4
未整理
1.webpack
2.axios
跨域详解
总结:
协议,域名,端口,有一个不一致就是跨域
解决方案:
(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;
}
}
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
测试网络连通
参考详情
总结:
(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)
计算属性computed :
侦听属性watch:
参考
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错误
参考
1. 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服务器利用会话密钥加密与客户端之间的通信。
参考一
参考二
1.px(pixel)
像素,是屏幕上显示数据的最基本的点,表示相对大小(不同分辨率上px显示不同)
2.pt(point)
印刷行业常用的单位(磅),等于1/72英寸,表示绝对长度
3.em
em是相对长度单位,基于父级元素的font-size计算字体大小。
4.rem
相对于html根元素的
5.rem和vw,wh的区别?
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);
参考1
参考2
1.PNG
优点:
透明无损压缩;
渐进显示和流式读写;
缺点:
色彩支持少 (PNG8、PNG16、PNG32);
ie6不支持png24透明效果。
2.Jpeg(jpg)
不支持透明,
不支持动画,
隔行渐进显示,
Jpeg是最适web上面的摄影图片,
3.Gif
透明性,
支持动画,
无损耗性,
间隔渐进显示,
4.SVG
易于修改和编辑,
SVG图形格式可以用来动态生成图形(可用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
1.举例:收快递
(1)一是三个人在公司门口等快递;二是委托给前台代为签收。
(2)老员工代收,新员工也可以代收
2.事件委托是利用事件的冒泡原理来实现的,事件从最深的节点开始,然后逐步向上传播事件;
例:给ul中的每一个li添加点击事件,只需要将事件委托给 父元素ul;
不需要给每一个li绑定点击事件;
当li被点击时,由于冒泡原理,事件就会冒泡到ul上,因为ul上有点击事件,所以事件就会触发;
当前所有的 li和动态添加的li元素都实现了委托;
3.一、事件捕获阶段,二、事件目标阶段,三、事件冒泡阶段
4. 1.管理的函数变少了。 2.可以方便地动态添加和修改元素,不需要因为元素的改动而修改事件绑定。 3.JavaScript和DOM节点之间的关联变少了,这样也就减少了因循环引用而带来的内存泄漏发生的概率。
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可以准确 判断类型
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第二个参数是数组
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
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 = ‘'
}
1.希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量
2.export 导出多个 多次使用, 导入时使用大花括号按需引入
3.export default 使用一次匿名导出,导入时可以任意起名
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
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)函数
函数不确定参数个数
深浅拷贝都是对于引用数据类型而言的;
浅拷贝就只是复制对象的引用,拷贝后的对象发生变化,原对象也会发生变化。只有深拷贝才是真正地对对象的拷贝;
常见的浅拷贝:
concat()、
slice()
Object.assign()、
扩展运算
深拷贝:
JSON.stringify/parse 缺点: undefined、任意的函数以及 symbol 值,在序列化过程中会被忽略
递归遍历,判断数据类型,直到是基本数据类型时在进行赋值
触发数组的响应式
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
当试图得到一个对象的属性时,如果这个对象本身不存在这个属性,那么就会去它构造函数的’prototype’属性中去寻找。那又因为’prototype’属性是一个对象,所以它也有一个’_ _ proto_ _'属性。
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继承仍然是基于原型实现的。
1.在 Javascript 中,作用域分为 全局作用域 和 函数作用域
全局作用域:
代码在程序的任何地方都能被访问,window 对象的内置属性都拥有全局作用域。
函数作用域:
在固定的代码片段才能被访问
2.获取一个变量的值
首先在当前作用域中没有查到值,就会向上级作用域去查,直到查到全局作用域,这么一个查找过程形成的链条就叫做作用域链。
nginx高级1
nginx高级2
node
koa2
面试题一 csdn
面试题二 牛客
(1)跨站脚本攻击(XSS)通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。(例如输入框输入)
(2)常用的XSS攻击手段和目的有:
1、盗用cookie,获取敏感信息。
2、利用植入Flash,通过crossdomain权限设置进一步获取更高权限。
3、利用iframe、XMLHttpRequest等方式,以(被攻击)用户的身份执行一些管理动作,或执行一些一般的如发微博、加好友、发私信等操作。
(3)防御:
1.HttpOnly防止劫取cookie
2.用户的输入检查
3.服务器的输出检查
(1)跨站请求伪造(CSRF)是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。攻击者盗用了你的身份,以你的名义发送恶意请求,对服务器来说这个请求是完全合法的,但是却完成了攻击者所期望的一个操作,比如以你的名义发送邮件、发消息,盗取你的账号,添加系统管理员,甚至于购买商品、虚拟货币转账等。
(2)防御:
1.验证 HTTP Referer 字段;
2.token验证
3.验证码
面经1