├── CSS3.xmind
├── ES6.xmind
├── HTML|CSS面试题.md
├── Http协议.md
├── JS面试题.md
├── JavaScript.xmind
├── JavaScript
└── 垃圾回收机制.md
├── README.md
├── React面试题.md
├── SCSS.md
├── Vue-Router源码.xmind
├── Vue.js.xmind
├── Vue源码.xmind
├── Vue面试题.md
├── Webpack.xmind
├── commonJS与ES6模块化的区别.md
├── jquery.xmind
├── loader与plugin.md
├── package.json.md
├── typescript.xmind
├── webpack面试题.md
├── 包管理器.xmind
├── 四种判断数据类型的方法.md
├── 手写源码部分.md
├── 模块化.xmind
├── 浏览器的渲染原理.md
├── 浏览器面试题.md
└── 页面性能优化.md
/CSS3.xmind:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhh10/Notes/b003a1dfed01e652209094a6b7793e8766f9958a/CSS3.xmind
--------------------------------------------------------------------------------
/ES6.xmind:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhh10/Notes/b003a1dfed01e652209094a6b7793e8766f9958a/ES6.xmind
--------------------------------------------------------------------------------
/HTML|CSS面试题.md:
--------------------------------------------------------------------------------
1 | ### 1. 块级元素、行内块元素、行内元素都有哪些,它们有什么区别
2 | - 块级元素有`div、p、h`等,行内块元素有`img、input`标签,行内元素有`span、text、a`标签。
3 | - 块级元素默认独占一行
4 | - 行内块元素和行内元素默认宽度由自身内容撑开
5 | - 行内块元素可以设置宽高、行高以及顶底边距
6 | - 行内元素不可设置宽高,只能设置水平margin,垂直方向无效
7 |
8 | ### 2. 盒子模型都有哪些
9 | - W3C标准盒模型
10 |
11 | 一个块的总宽度 = width + margin(左右) + padding(左右) + border(左右)
12 |
13 | - IE怪异盒模型
14 |
15 | 一个块的总宽度 = width + margin(左右) width包含了padding左右和border左右值
16 | ```
17 | border-box:box-sizing
18 | ```
19 |
20 | ### 3. 如何让元素隐藏
21 | - `display:none`
22 | - `visibility:hidden`
23 | - `opacity:0`
24 |
25 | `display:none`让整个元素直接消失,会引起页面回流。而`visibility:hidden`和`opacity:0`在网页中的位置还在,只会造成页面重绘,不会引起页面回流。两者的区别在于`opacity`可以用在动画`transition`过渡上,而`visibility`不可以
26 |
27 | ### 4. 响应式布局可以怎么做
28 | 1. `width/height`设置百分比
29 | 2. 设置`vw/vh`
30 | 3. 设置`flex`弹性布局
31 | 4. `rem/em`
32 | 5. 使用媒体查询
33 |
34 | ### 5. 常用的浏览器及其内核
35 | 1. IE: Trident
36 | 2. 火狐: Gecko
37 | 3. Chrome、safari: Webkit
38 | 4. Opera: Presto
39 |
40 | ### 6. 对标签语义化的理解
41 | 1. 合适的标签做合适的事情
42 | 2. 方便后期开发和维护,具有可读性
43 | 3. 丢失样式时能够让页面呈现出清晰的结构
44 | 4. 有利于SEO和搜索引擎建立良好的沟通
45 |
46 | ### 7. img标签的`alt`和`title`
47 | - `alt`: 图片的代替文字
48 | - `title`: 图片的解析文字
49 |
50 | ### 8. CSS如何画一个三角形
51 | ```
52 |
60 |
61 |
62 |
63 | ```
64 | ### 9. 对浏览器内核的理解
65 | 主要分成两部分:
66 | 1. 渲染引擎
67 | 2. JS执行引擎
68 | - 渲染引擎: 负责取得html、img、css,以及计算网页的显示方式,然后输出至显示器。由于不同内核对网页的语法解释会有不同,所以渲染的效果也不相同
69 | - JS执行引擎: 解释和执行JS来实现网页的动态效果
70 |
71 | ### 10. 什么是BFC
72 | ### 11. 表单可以跨域吗?
73 | form表单可以跨域,但是ajax不可以。因为原页面用form提交到另一个域名之后,原页面的脚本无法获取新页面中的内容。所以浏览器认为是安全的。而ajax是可以读取响应内容的,因此浏览器不能允许你这样做。浏览器这个策略的本质是: 一个域名的JS,在未经允许的情况下,不得读取另一个域名的内容,但浏览器并不阻止你向另一个域名发送请求。
74 |
75 | ### 12. 为什么要初始化CSS样式?
76 | 因为浏览器的兼容问题,不同浏览器对有些标签的默认值是不同的,如果没有对CSS初始化往往会出现浏览器之间的页面显示差异。
77 |
78 |
--------------------------------------------------------------------------------
/Http协议.md:
--------------------------------------------------------------------------------
1 | ### 1. 在浏览器地址栏中输入一个页面地址,按下回车键发生了什么?
2 | 1. 浏览器将url地址补充完整:没有书写协议,添加上协议
3 | 2. 浏览器对url地址进行url编码:如果url地址中出现非ASCII字符,则浏览器会对其进行编码
4 | 3. 浏览器构造一个没有消息体的GET请求,发送至服务器,等待服务器的响应,此时浏览器标签页往往会出现一个等待的图标
5 | 4. 服务器接收到请求,将一个HTML页面代码组装到消息体中,响应给浏览器
6 | 5. 浏览器拿到服务器的响应后,丢弃掉当前页面,开始渲染消息体的html代码。浏览器之所以直到这是一个html代码,是因为服务器的响应头指定了消息类型为text/html
7 | 6. 浏览器在渲染页面的过程中,发现有其他的嵌入资源,如CSS、JS、图片等
8 | 7. 浏览器使用不阻塞渲染的方式,重新向服务器发送对该资源的请求,拿到响应结果后根据Content-Type做相应处理
9 | 8. 当所有的资源都已下载并处理后,浏览器触发window.onload事件
10 |
11 | ### 2. AJAX请求
12 | ```
13 | var xhr = new XMLHttpRequest() //创建发送请求的对象
14 | xhr.onreadystatechange = function(){
15 | // 当请求状态发生改变时运行的函数
16 | // 0: 刚刚创建好了请求对象,但还未配置请求(未调用open方法)
17 | // 1: open方法已被调用
18 | // 2: send方法已被调用
19 | // 3: 正在接收服务器的响应消息体
20 | // 4: 服务器响应的所有内容均已接收完毕
21 |
22 | // xhr.responseText: 获取服务器响应的消息体文本
23 |
24 | // xhr.getResponseHeader("Content-Type") 获取响应头Content-Type
25 | }
26 | xhr.setRequestHeader('Content-Type','application/json') //设置请求头
27 | xhr.open('请求方法','URL地址') //配置请求
28 | xhr.send('请求体内容') //构建请求体 发送到服务器
29 | ```
30 | ### 3. get和post的区别
31 | 1. get请求的数据会跟在url后面
32 | 2. post请求把提交的数据放置在http的请求体中
33 | 3. 因为浏览器对url的长度有所限制,所以get请求的传输数据就受到了限制
34 | 4. post方法提交的数据没有限制
35 | 5. post安全性要比get高,因为get提交数据将以明文出现在浏览器中,以key/valu对的序列附加在url中
36 |
37 |
38 |
--------------------------------------------------------------------------------
/JS面试题.md:
--------------------------------------------------------------------------------
1 | ### 1. 下面输出什么?如果是在严格模式下呢?
2 | ```
3 | var a = function(){
4 | this.b = 3
5 | }
6 | var c = new a()
7 | a.prototype.b = 9
8 | var b = 7
9 | a()
10 |
11 | console.log(b) //3
12 | console.log(c.b) //3
13 | ```
14 | 如果是严格模式,那么就会报错,因为严格模式下,`this`指向不是`window`,而是`undefined`。
15 |
16 | ### 2. 输出什么?
17 | ```
18 | var a = 0;
19 | if(true){
20 | var a = 1;
21 | function a(){};
22 | var a = 21;
23 | console.log(a)
24 | }
25 | console.log(a)
26 | // 21 1
27 | ```
28 | 新浏览器为了兼容ES3、ES6
29 | - `{}`块级作用域下的`function`,在全局下只声明,不定义(不赋值)
30 | - `{}`出现`function、const、let`创建一个块级上下文
31 |
32 | ### 3. 不借助变量,交换两个数
33 | ```
34 | function swap(a,b){
35 | a = a + b;
36 | b = a - b;
37 | a = a - b;
38 | return a,b
39 | }
40 | ```
41 |
42 | ### 4. `==`比较,数据转换的规则
43 | ```
44 | console.log([] == false) // true
45 | console.log(![] == false) // true
46 | ```
47 | - 数据类型一样的几个特殊点:
48 | - `{} == {} //false` 对象比较的是堆内存的地址
49 | - `[] == [] //false`
50 | - `NaN == NaN // false`
51 | - 数据类型不一样的转换规则
52 | - `null == undefined //true`
53 | - `字符串 == 对象` 要把对象转换为字符串
54 | - 剩下如果 `==` 两边数据类型不一致,但是需要转换为数字类型在进行比较
55 | - 把其他数据类型转换为布尔值
56 | - 基于以下方式可以把其他数据类型转换为布尔
57 | - `!`转换为布尔值后取反
58 | - `!!` 转换为布尔值
59 | - `Boolean(val)`
60 | - 隐式转换
61 | - 在循环或者条件判断中,条件处理的结果就是布尔类型值
62 |
63 |
64 | **规定: 只有0、NaN、null、undefined、空字符串 五个值变成布尔的false,其余都是true**
65 |
66 | ### 5. 变量赋值
67 | ```
68 | let a = {n:1};
69 | let b = a;
70 | a.x = a = {n:2};
71 | console.log(a.x) // undefined
72 | console.log(b) // {n:1,x:{n:2}}
73 | ```
74 | - **变量赋值都是指针指向过程,先创建值,再创建变量,最后指针关联**
75 | - **带成员访问的优先处理**
76 |
77 | 1. 先创建`{n:1}`,a指向`{n:1}`的地址
78 | 2. b与a指向同一个地址
79 | 3. 先创建一个`{n:2}`的地址
80 | 4. `{n:1}`中的x指向`{n:2}`,然后a的地址更改为`{n:2}`
81 |
82 | ### 6. es5与es6的继承有什么不同?
83 | - es5继承,即原型链继承,先创造子类的实例对象this,然后再把父类的方法添加到this上。
84 | - es6继承,即`class`类继承,子类没有自己的this,是通过`constructor`中的`super`继承父类的this,然后对this进行加工。
85 |
86 | ### 7. 为什么`typeof null`是`object`
87 | 这是一个历史遗留bug,在JS中二进制前三位都是0的话会被判断为`object`,null的二进制表示全为0,所以`typeof null`为`object`
88 |
89 | ### 8. null和undefined的区别
90 | ```
91 | null == undefined //true
92 | null === undefined //false
93 | ```
94 | 1. null的类型是Object类型,代表空值,一个空对象指针。
95 | 2. undefined的类型是undefined类型
96 |
97 | null表示“没有对象”,即此处不应该有值,典型用法是:
98 | 1. 作为函数的参数,表示该函数的参数不是对象
99 | 2. 作为对象原型链的终点
100 |
101 | undefined表示“缺少值”,就是该处应该有一个值,但是还没有定义,典型用法是:
102 | 1. 变量被声明,但还没有赋值
103 | 2. 调用函数时,应该提供的参数没有提供
104 | 3. 对象没有赋值的属性,该属性的值为undefined
105 | 4. 函数没有返回值或者return后面什么都没有(例如Promise的return),返回undefined
106 |
107 | ### 9. 内存泄露
108 | > 不会用到的内存,没有及时释放,就叫做内存泄露
109 |
110 | 内存泄露产生的原因:
111 | 1. 缓存
112 | 有时候为了方便数据的快捷复用,我们会使用缓存,但是缓存必须有一个大小上限才有用。高内存消耗将会导致缓存突破上限,因为缓存内容无法被回收
113 | 2. 计时器引用没有被消除
114 | 当浏览器队列消除不及时,会导致一些作用域变量得不到及时的释放,因而导致内存泄露
115 | 3. 全局变量
116 | 除了常规设置了比较大的对象在全局变量,可能是意外导致的全局变量。例如函数中,没有使用var/let/const定义变量,实际上是定义在`window`上面。
117 | 4. 闭包
118 | 5. 时间监听(例如滑动监听)
119 |
120 | ### 10. 闭包机制
121 | > 函数执行,某些上下文没有被销毁,就是闭包机制。
122 |
123 | **闭包作用**
124 |
125 | 1. 保护作用
126 | 1. 上下文中会有一些私有变量,这些私有变量和外界变量不会冲突
127 | 2. 类似立即执行函数,例如jquery库
128 | 2. 保存作用
129 | 1. 上下文中的某些内容被外界占用后,当前上下文并不会出栈销毁,这样可以把上下文中的信息保存起来。类似柯里化函数
130 |
131 | **闭包优缺点**
132 |
133 | 1. 能保护和保存代码不受污染
134 | 2. 因为闭包会产生不销毁的上下文,这样会导致内存消耗过大,容易造成内存泄露,影响性能。
135 |
136 | ### 11. async/await如何通过同步的方式实现异步?
137 | 内部是通过类似生成器的方式来实现的:
138 | ```
139 | function A(){
140 | return new Promise(()=>{
141 | resolve(2)
142 | },1000)
143 | }
144 | function *B(){
145 | var b = yield A()
146 | var c = yield A()
147 | console.log(b+c)
148 | }
149 | run(B)
150 | function B(func){
151 | var f = func()
152 | var result = f.next()
153 | handle(result)
154 | function handle(result){
155 | if(result.done === true){
156 | return result;
157 | }else{
158 | result.then(res => {
159 | var result = result.next(res)
160 | handle(result)
161 | })
162 | }
163 | }
164 | }
165 | ```
166 | ### 12. Promise 构造函数是同步执行还是异步执行,那么 then 方法呢?
167 | Promise 构造函数是同步执行的,then方法是异步执行
168 |
169 | ### 13. 下面的代码输出结果是多少?
170 | ```
171 | Promise.resolve(1).then(2).then(Promise.resolve(3)).then(console.log)
172 | ```
173 | 输出1: 因为then参数一定是一个函数,如果不是函数,就当没有写,直接跳过
174 |
175 | ### 14. 下面的代码输出结果是多少?
176 | ```
177 | Promise.resolve().then(()=>{return new Error('error!!!')})
178 | .then(res=>{console.log('then',res})
179 | .catch(err =>{console.log('catch',err)})
180 | ```
181 | 输出 `then Error`,只要是`return`,就是`resolve` 只不是这里传递的是`error`对象,只要是`throw`,必然是`reject`,哪怕是`reject 1`
182 |
183 | ### 15. 下面Set结构,打印出的Size值是多少?
184 | ```
185 | let s = new Set()
186 | s.add([1]);
187 | s.add([1]);
188 | console.log(s.size);
189 | // 1
190 | ```
191 | 因为`[1]`和`[1]`地址不同。
192 |
193 | ### 16. JS异步模式
194 | JS语言的执行环境是单线程的,一个任务的执行,必须等待上一个任务执行完毕。如果一个任务执行耗时很长时,后面的任务都必须排队等着,会拖延整个程序的执行,为了解决这个问题,JS语言将任务的执行模式分为两种: 同步和异步。“异步模式”就是前一个任务结束后,不是执行后一个任务,而是执行回调函数,后一个任务无需等待上一个任务结束才执行,程序的执行顺序与任务的排列顺序是不一致的。“异步模式”非常重要,在浏览器端,耗时很长的操作都应该是异步执行,避免浏览器失去响应,例如AJAX操作;而在服务器端,因为执行环境是单线程的,如果允许同步执行所有http请求,性能会大大损耗,很快失去响应,所以也必须使用“异步模式”
195 |
196 | ### 17. JS异步解决方案的发展历程
197 | 1. 回调函数callbacl
198 | ```
199 | setTimeout(()=>{
200 | console.log('hello')
201 | },1000)
202 | ```
203 | 使用回调函数,不能用`try catch`捕获错误,而且容易造成**回调地狱**
204 |
205 | 2. Promise
206 | Promise实现了链式调用,每次`then`或`catch`后都是一个全新的Promise,交给后面的处理函数处理,解决了回调地狱
207 | ```
208 | ajax('http')
209 | .then(res => {
210 | return ajax('http1')
211 | })
212 | .then(res => {
213 | return ajax('http2')
214 | })
215 | .then(res => {
216 | console.log(res)
217 | })
218 | ```
219 | 3. async/await
220 | 不用写一堆then链,处理了回调地狱,结构更加清晰。await将异步代码改造成了同步代码,如果多个操作有依赖性,效果较好。但如果没有依赖性,性能会降低。
221 | ```
222 | async function test(){
223 | await ajax('http1')
224 | await ajax('http2')
225 | await ajax('http3')
226 | }
227 | ```
228 |
--------------------------------------------------------------------------------
/JavaScript.xmind:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhh10/Notes/b003a1dfed01e652209094a6b7793e8766f9958a/JavaScript.xmind
--------------------------------------------------------------------------------
/JavaScript/垃圾回收机制.md:
--------------------------------------------------------------------------------
1 | ### 什么是内存泄露
2 | 程序的运行需要内存。只要程序提出要求,操作系统或者运行时就必须提供内存。
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # mind-Mapping 前端学习的思维导图
2 |
3 | 前端JS、ES6、CSS3、HTML5、模块化、包管理器、Vue、React、Node等知识点的思维导图分享
4 |
5 | ### HTML
6 | - [HTML/CSS面试题](https://github.com/zhh10/Notes/issues/2)
7 | - [页面性能优化](https://github.com/zhh10/Notes/issues/1)
8 | - [Canvas](https://github.com/zhh10/Notes/issues/20)
9 |
10 | ### CSS
11 | - [CSS3思维导图](https://github.com/zhh10/mind-Mapping/blob/master/CSS3.xmind)
12 | - [SCSS](https://github.com/zhh10/Notes/issues/3)
13 |
14 | ### JavaScript
15 | - [JavaScript思维导图](https://github.com/zhh10/mind-Mapping/blob/master/JavaScript.xmind)
16 | - [ES6思维导图](https://github.com/zhh10/mind-Mapping/blob/master/ES6.xmind)
17 | - [四种判断数据类型的方法](https://github.com/zhh10/Notes/issues/4)
18 | - [数组技巧](https://github.com/zhh10/Notes/issues/17)
19 | - [Js严格模式](https://github.com/zhh10/Notes/issues/19)
20 | - [Js面试题](https://github.com/zhh10/Notes/issues/5)
21 | - [手写源码部分](https://github.com/zhh10/Notes/issues/6)
22 |
23 | ### JQuery
24 | - [JQuery思维导图](https://github.com/zhh10/mind-Mapping/blob/master/jquery.xmind)
25 |
26 | ### 浏览器
27 | - [浏览器渲染原理](https://github.com/zhh10/Notes/issues/7)
28 | - [Http协议](https://github.com/zhh10/Notes/issues/8)
29 | - [浏览器面试题](https://github.com/zhh10/Notes/issues/9)
30 |
31 | ### Webpack
32 | - [webpack思维导图](https://github.com/zhh10/mind-Mapping/blob/master/Webpack.xmind)
33 | - [loader与plugin](https://github.com/zhh10/Notes/issues/10)
34 | - [webpack面试题](https://github.com/zhh10/Notes/issues/11)
35 |
36 | ### TypeScript
37 | - [TypeScript思维导图](https://github.com/zhh10/mind-Mapping/blob/master/typescript.xmind)
38 |
39 | ### 包管理器
40 | - [包管理器思维导图](https://github.com/zhh10/mind-Mapping/blob/master/%E5%8C%85%E7%AE%A1%E7%90%86%E5%99%A8.xmind)
41 | - [package.json](https://github.com/zhh10/Notes/issues/12)
42 |
43 | ### 模块化
44 | - [模块化思维导图](https://github.com/zhh10/mind-Mapping/blob/master/%E6%A8%A1%E5%9D%97%E5%8C%96.xmind)
45 | - [commonJS与ES6模块化的区别](https://github.com/zhh10/Notes/issues/13)
46 |
47 | ### Vue.js
48 | - [Vue2思维导图](https://github.com/zhh10/mind-Mapping/blob/master/Vue.js.xmind)
49 | - [Vue-Router源码](https://github.com/zhh10/mind-Mapping/blob/master/Vue-Router%E6%BA%90%E7%A0%81.xmind)
50 | - [Vue2源码](https://github.com/zhh10/mind-Mapping/blob/master/Vue%E6%BA%90%E7%A0%81.xmind)
51 | - [Vue面试题](https://github.com/zhh10/Notes/issues/14)
52 | - [Vue3](https://github.com/zhh10/Notes/issues/26)
53 |
54 | ### React
55 | - React思维导图
56 | - [React面试题](https://github.com/zhh10/Notes/issues/15)
57 |
58 | ### Node.js
59 | - JWT原理详解
60 | - Cookie
61 | - Session
62 | - Cors
63 |
64 | ### 移动端
65 | - [移动端布局](https://github.com/zhh10/Notes/issues/27)
66 | - [移动端事件](https://github.com/zhh10/Notes/issues/28)
67 |
68 | ### Git
69 | - [Git简单操作](https://github.com/zhh10/Notes/issues/21)
70 |
71 | ### 服务端渲染
72 | - [Nuxt.js](https://github.com/zhh10/Notes/issues/30)
73 |
74 | ### 设计模式
75 | - [设计模式](https://github.com/zhh10/Notes/issues/29)
76 |
77 | ### 平时学习
78 | - [图片懒加载及其底层原理](https://github.com/zhh10/Notes/issues/23)
79 | - [前端骨架屏实现](https://github.com/zhh10/Notes/issues/24)
80 | - [axios二次封装和api接口管理规范](https://github.com/zhh10/Notes/issues/22)
81 | - [文件上传和断点续传](https://github.com/zhh10/Notes/issues/25)
82 | - [excel解析与导出](https://github.com/zhh10/Notes/issues/31)
83 | - [JS文件处理](https://github.com/zhh10/Notes/issues/32)
84 |
--------------------------------------------------------------------------------
/React面试题.md:
--------------------------------------------------------------------------------
1 | ### 1. 类组件和函数组件之间的区别是什么?
2 | 区别 | 类组件 | 函数组件
3 | ---|---|---|
4 | 是否有this| 有 | 没有
5 | 是否有生命周期| 有 | 没有
6 | 是否有状态 state| 有 | 没有(hook可以解决)
7 |
8 | 除了上面的区别,函数组件的性能要比类组件高,因为类组件使用的时候要实例化,而函数组件直接执行函数取返回结果即可。为了提高性能,尽量使用函数组件。
9 |
10 | ### 2. state 和 props 区别是什么?
11 | `state`和`props`是普通的JS对象,它们都包含影响渲染输出的信息。
12 | - `state`是组件自己管理数据,控制自己的状态,可以自己修改
13 | - `props`是外部传入的数据参数,不可修改。
14 | - 没有`state`的叫做无状态组件,有`state`的叫做有状态组件。
15 |
16 | ### 3. 在构造函数调用`super`并将`props`作为参数传入的作用是什么?
17 | 在调用`super()`方法之前,子类构造器无法使用`this`饮用。将`props`参数传递给`props`调用的主要原因是在子构造函数中能够通过`this.props`来获取`props`。
18 |
19 | ### 4. 什么是JSX
20 | Facebook引入了一种新的方言`JSX`,将原始HTML模版嵌入到JS代码中,`JSX`代码本身不能被浏览器读取,必须使用`babel`和`webpack`等工具将其转换为传统的JS。
21 |
22 | ### 5. 如何避免组件重复渲染
23 | - `React.memo()`: 可以防止不必要地重新渲染函数组件
24 | - `PureComponent`: 可以防止不必要地重新渲染类组件
25 |
26 | 这两种方法都依赖对传递于对传递给组件的`props`的浅比较,如果`props`没有改变,那么组件将不会重新渲染。
27 |
28 | ### 6. 什么是纯函数
29 | 纯函数是不依赖并且不会在其作用域之外修改变量状态的函数。本质上,纯函数始终在给定相同参数的情况下返回相同结果。
30 |
31 | ### 7. Redux和Vuex
32 | - 共同点: 两者都是处理全局状态的工具库,大致实现思想都是: 全局state保存状态,dispatch或者action改变状态,生成一个newState,整个状态是同步操作。
33 | - 不同点: 最大的区别在于处理异步的不同,Vuex里面需要在mutation进行commit操作,而Redux是通过中间件处理。还有状态改变时,redux是需要创建一个action对象,通过reducer生成新的state,而Vuex是直接在修改状态属性。
34 |
35 |
--------------------------------------------------------------------------------
/SCSS.md:
--------------------------------------------------------------------------------
1 | ### 官网
2 | ```
3 | sass-lang.com/install
4 | ```
5 |
6 | ### 变量 Variables
7 | - $符号
8 | ```
9 | $primary-color:#1259b5;
10 | $primary-border:1px solid $primary-color;
11 |
12 | div.box{
13 | color:$primary-color
14 | }
15 | h1.page-header{
16 | border:$primary-border;
17 | }
18 | ```
19 | ### 嵌套 Nesting
20 | ```
21 | .foo{
22 | display:block;
23 | button{
24 | height:100px;
25 | }
26 | }
27 |
28 | // 翻译成css
29 | .foo{
30 | display:block;
31 | }
32 | .foo button{
33 | height:100px;
34 | }
35 | ```
36 | ### 嵌套时调用父选择器
37 | - &符号
38 | ```
39 | #app{
40 | display:block;
41 | &.foo{
42 | height:100px;
43 | }
44 | }
45 |
46 | // 翻译成css
47 | #app{
48 | display:block
49 | }
50 | #app.foo{
51 | height:100px;
52 | }
53 | ```
54 | ### 嵌套属性
55 | ```
56 | body{
57 | font:{
58 | size:15px;
59 | weight:bold
60 | }
61 | }
62 | .nav{
63 | border:1px solid #000{
64 | left:0;
65 | right:0;
66 | }
67 | }
68 | ```
69 | ### @at-root 不会让你的选择器发生任何嵌套,直接移除了父选择
70 | ```
71 | .foo {
72 | @at-root .bar{
73 | color:gray;
74 | @at-root button{
75 | color:red;
76 | @at-root span{
77 | color:orange;
78 | }
79 | }
80 | }
81 | }
82 |
83 | // 翻译成css
84 | .bar{
85 | color:gray;
86 | }
87 | button{
88 | color:red;
89 | }
90 | span{
91 | color:orange;
92 | }
93 | ```
94 | ### 混合 Mixin
95 | - @mixin
96 | - @include
97 | ```
98 | @mixin 名字(参数1,参数2){
99 | ...
100 | }
101 | ```
102 | ```
103 | @mixin alert{
104 | color:#8a6d3b;
105 | background-color:#fcf8e3;
106 | a{
107 | color:#000;
108 | }
109 | }
110 |
111 | .alert-warning{
112 | @include alert ;
113 | }
114 |
115 | // 翻译成css
116 | .alert-warning{
117 | color:#8a6d3b;
118 | background-color:#fcf8e3;
119 | }
120 | .alert-warning a{
121 | color:#000;
122 | }
123 | ```
124 |
125 | ### Mixin里的参数
126 | ```
127 | @mixin alert($text-color,$background){
128 | color:$text-color;
129 | background-color:$background;
130 | a{
131 | color:darken($text-color,10);
132 | }
133 | }
134 |
135 | .alert-warning{
136 | @include alert(#8a6d3b,#fcf8e3)
137 | }
138 | .alert-info{
139 | @include alert($background:#fcf8e3,$text-color:#8a6d3b)
140 | }
141 | ```
142 | ### @content
143 | ```
144 | @mixin hunhe($block){
145 | display:$block;
146 | @content;
147 | }
148 |
149 | #app{
150 | @include(inline-block);
151 | color:red;
152 | }
153 |
154 | // 翻译成css
155 | #app{
156 | display:inline-block;
157 | color:red;
158 | }
159 | ```
160 | ### 继承/扩展 —— inheritance
161 | - @inheritance
162 | ```
163 | .alert{
164 | padding:15px;
165 | }
166 | .alert-info{
167 | @extend .alert; // 与alert相关的样式也会被继承过来
168 | background:#d9edf7;
169 | }
170 |
171 | //翻译成css
172 | .alert .alert-info{
173 | padding:15px;
174 | }
175 | .alert-info{
176 | background:#d9edf7;
177 | }
178 | ```
179 | ### Partials与@import
180 | - @import 把其他的css文件包含进来
181 | - Particals要用下划线开头,这样不会去编译它
182 | ```
183 | // _base.scss
184 | body{
185 | margin:0;
186 | padding:0;
187 | }
188 | ```
189 | ```
190 | @import "base";
191 | ```
192 | ### 列表
193 | ```
194 | border{
195 | 1px solid #000;
196 | }
197 | padding:{
198 | (5px 10px) (5px 0)
199 | }
200 | padding{
201 | 5px 10px,5px 0
202 | }
203 | ```
204 | ### interpolation
205 | ```
206 | $name:'info';
207 | $attr:'border';
208 | .alert-#{$name}{
209 | #{$attr}-color:#ccc;
210 | }
211 | ```
212 | ### 控制指令 Control Directives
213 | #### @if
214 | ```
215 | @if 条件 {
216 | ...
217 | }
218 | ```
219 | ```
220 | $use-prefixes:true;
221 | .rounded{
222 | @if $use-prefixes{
223 | -webkit-border-radius:5px;
224 | -moz-border-radius:5px;
225 | -ms-border-radius:5px;
226 | -o-border-radius:5px;
227 | }
228 | border-raduis:5px;
229 | }
230 | ```
231 | ```
232 | body{
233 | @if $theme == dark{
234 | background-color:black;
235 | }@else if @theme == light{
236 | background-color:white;
237 | }@else{
238 | background-color:grey;
239 | }
240 | }
241 | ```
242 | #### @for
243 | ```
244 | @for $var from <开始值> through <结束值> {
245 |
246 | }
247 | ```
248 | ```
249 | @for $var from <开始值> to <结束值>{
250 |
251 | }
252 | ```
253 | ```
254 | $columns : 4;
255 | // 值到4的时候停止
256 | @for $i from 1 through $columns{
257 | .col-#{$i}{
258 | width:100%/$columns * $i;
259 | }
260 | }
261 |
262 | // 值到3的时候停止
263 | @for $i from 1 to $columns{
264 | .col-#{$i}{
265 | width:100%/$columns * $i;
266 | }
267 | }
268 | ```
269 | #### @each
270 | ```
271 | @each $var in $list {
272 |
273 | }
274 | ```
275 | ```
276 | $icons: success error warning;
277 | @each $icon in $icons {
278 | .icon-#{$icon}{
279 | background-image:url(../images/icons/#{$icon}.png)
280 | }
281 | }
282 | ```
283 | #### @while
284 | ```
285 | @while 条件{
286 |
287 | }
288 | ```
289 | ```
290 | $li:6;
291 | @while $li>0 {
292 | .item-#{$i}{
293 | width:5px * $i;
294 | }
295 | $i : $i - 2;
296 | }
297 | ```
298 |
299 | ### 用户自定义的函数 function
300 | ```
301 | @function 名称(参数1,参数2){
302 |
303 | }
304 | ```
305 |
306 | ### SCSS map
307 | ```
308 | $map : (
309 | $name:'uzi',
310 | $age:18,
311 | $location:'adc'
312 | )
313 | ```
314 | ### SCSS Maps的函数
315 | - map-get($map,$key)
316 | > 根据给定的key值,返回map中相关的值。
317 | - map-merge($map1,$map2)
318 | > 将两个map合并成一个新的map
319 | - map-remove($map,$key)
320 | > 从map中删除一个key,返回一个新的map
321 | - map-keys($map)
322 | > 返回map中所有的key
323 | - map-values($map)
324 | > 返回 map 中所有的 value。
325 | - map-has-key($map,$key)
326 | > 根据给定的 key 值判断 map 是否有对应的 value 值,如果有返回 true,否则返回 false。
327 | - keywords($args)
328 | > 返回一个函数的参数,这个参数可以动态的设置 key 和 value。
329 |
330 | ### inspect函数
331 | > Maps不能转换为纯CSS。作为变量的值或参数传递给CSS函数将会导致错误,此时可以使用inspect($value) 函数以产生输出字符串。
332 |
333 | #### !default
334 | > 默认变量
335 | > 在变量赋值之前,利用`!default`为变量指定默认值。也就是说,如果在此之前变量已经赋值,那就不使用默认值了。如果没有赋值,则使用默认值。
336 |
337 | ```
338 | $content:"uzi" !default;
339 | #main {
340 | content:$content;
341 | }
342 | // 编译结果
343 |
344 | #main {
345 | content: "shanshan";
346 | }
347 | ```
348 | ### @if @else
349 | ```
350 | @if map-has-key($map,$key){
351 | ....
352 | }@else{
353 | ....
354 | }
355 | ```
356 |
--------------------------------------------------------------------------------
/Vue-Router源码.xmind:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhh10/Notes/b003a1dfed01e652209094a6b7793e8766f9958a/Vue-Router源码.xmind
--------------------------------------------------------------------------------
/Vue.js.xmind:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhh10/Notes/b003a1dfed01e652209094a6b7793e8766f9958a/Vue.js.xmind
--------------------------------------------------------------------------------
/Vue源码.xmind:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhh10/Notes/b003a1dfed01e652209094a6b7793e8766f9958a/Vue源码.xmind
--------------------------------------------------------------------------------
/Vue面试题.md:
--------------------------------------------------------------------------------
1 | ### 1. Vue中key的原理?
2 | 有key便于diff算法的更新,key的唯一性,直接通过新子节点的key查询是否存在于旧子节点中,能让算法更快地找到更新的dom,需要注意的是,key要具有唯一性,而且注意不要使用随机数或者index,因为diff是同级比较。
3 |
4 | ### 2. v-show与v-if有什么区别?使用场景分别是什么?
5 | - v-show控制的是display属性,适合频繁切换;若v-show为false,display为none;若为true,display为原来的值。
6 | - v-if为false,是直接删除节点,有较高的切换开销。
7 |
8 | ### 3. 怎么给Vue定义全局的方法
9 | - 挂载到Vue中的prototype
10 | - 利用全局混入Mixin
11 |
12 | ### 4. 使用Vue渲染大量数据时应该怎么优化?
13 | 使用ES6中的`Object.freeze`,对于data或Vuex里使用freeze冻结了的数据,vue不会做getter和setter的切换,可以让性能大幅提升。
14 |
15 | ### 5. Vue实例会在什么时候被销毁
16 | - v-if为false
17 | - 路由跳转的时候
18 | - 没有使用`keep-alive`的组件切换
19 |
20 | ### 6. keep-alive的理解
21 | `keep-alive`是Vue提供的一个抽象组件,用来对组件进行缓存,从而节省性能。
22 |
23 | ### 7. 虚拟Dom的作用
24 | 虚拟Dom的最终目标是将虚拟节点渲染到视图上,但如果直接使用虚拟节点覆盖旧节点,会有很多不必要的Dom操作,造成性能浪费,为了避免不必要的Dom操作,将虚拟Dom与上一次渲染视图所使用的旧虚拟Dom做对比,找出需要更新的节点进行Dom操作。
25 |
26 | **虚拟Dom的优势**
27 |
28 | - 因为虚拟Dom本质是一个JS对象,具有跨平台的优势:浏览器、小程序、Node
29 | - Dom操作将其耗费性能,而创建一个JS对象性能耗费较低,将Dom对比操作放在JS层,提高了效率
30 |
31 | ### 8. v-if和v-for的优先级是什么,如果这两个同时出现,那应该怎么优化才能得到更好的性能?
32 | v-for的优先级比v-if高,所以会优先v-for,再v-if,如果不处理,性能将造成浪费。
33 |
34 | **解决办法:**
35 |
36 | - 使用template
37 | ```
38 |
39 | {{item}}
40 |
41 | ```
42 | - 使用计算属性
43 |
44 | ### 9. Vue实现强制刷新
45 | - this.$forceUpdate
46 | ```
47 |
48 |
49 | methods:{
50 | reflash(){
51 | this.$forceUpdate()
52 | }
53 | }
54 | ```
55 | - v-if配合$nextTick
56 | ```
57 |
61 |
62 | data(){
63 | reload:true
64 | },
65 | methods:{
66 | reflash(){
67 | this.reload = false
68 | this.$nextTick(()=>{
69 | this.reload = true
70 | })
71 | }
72 | }
73 | ```
74 | ### 10. Vue中的data必须是一个函数
75 | 因为Js的特性导致,在component中,data必须以函数的形式存在,不可以是对象。组件中的data写成一个函数,数据以函数返回值的形式定义,这样在复用组件的时候,都会返回一个新的data,相当于每个组件实例都有自己私有的数据空间,它们只负责各自维护的数据,不会造成混乱。
76 |
77 | ### 11. assets和static的区别
78 |
79 | - 相同点: assets和static两个都是存放静态资源文件,项目中所需要的资源文件图片、字体图标、样式文件都可以放在两个文件中。
80 | - 不同点: assets中存放的静态资源文件在项目文件打包时,会将assets中放置的静态资源文件进行打包上传,会进行压缩体积,代码格式化,而压缩后的静态资源文件最终也会被放置在static文件中跟着index.html一同上传到服务器。static中放置的静态资源文件直接上传至服务器,避免了压缩直接进行上传,因为static中的资源文件没进行打包压缩,所以文件的体积也就相对于assets中打包后的文件提交较大点。在服务器中就会占据更大的空间。
81 |
82 | 第三方的资源文件可以放置在static中,因为这些引入的第三方文件已经经过处理了,我们不再需要处理,直接上传。
83 |
84 | ### 12. 解决Vue初始化页面闪动问题
85 | 在vue初始化之前,由于 div 是不归 vue 管的,所以我们写的代码在还没有解析的情况下会容易出现花屏现象,看到类似于 {{message}} 的字样,虽然一般情况下这个时间很短暂,但是我们还是有必要让解决这个问题的。使用`v-cloak`指令,`v-cloak`这个指令保持在元素上直到关联实例结束编译,可以解决闪烁问题。
86 | ```
87 | [v-cloak]{
88 | display:none
89 | }
90 | ```
91 | ```
92 |
93 | ```
94 | 编译结束,v-cloak消失,display显示正常。
95 | 或者:
96 | ```
97 |
98 | ```
99 | ### 13. Vue中如何检测数组变化?
100 | - 进行劫持的方式,重写数组的方法
101 | - 进行原型链重写,调用数组原API时,会通知依赖更新,如果新进来的值中包含着引用类型,还会继续对其进行监控。
102 |
103 | ### 14. computed不需要deep?
104 | 因为computed内部是放在模版`{{}}`里的,
105 |
--------------------------------------------------------------------------------
/Webpack.xmind:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhh10/Notes/b003a1dfed01e652209094a6b7793e8766f9958a/Webpack.xmind
--------------------------------------------------------------------------------
/commonJS与ES6模块化的区别.md:
--------------------------------------------------------------------------------
1 | ## ES6 与 commonJS的差异
2 | 1. `commonJS`输出的值是值的拷贝,即原来模块中的值改变不会影响已经加载的该值,es6模块化是静态分析,动态引用,输出的是值的引用,值改变,引用也改变,即原来模块中的值改变,则该加载的值也改变。
3 | 2. `commonJS`模块是运行时加载,es6模块是编译时输出接口。
4 | 3. `commonJS`加载的是整个模块,即将所有的接口全部加载进来,es6可以单独加载其中某个接。
5 | 4. `commonJS`中的this指向当前模块,es6模块化的this指向undefined。
6 |
7 | es6模块化运行机制与`commonJS`不一样,JS引擎对脚本静态分析的时候,遇到模块加载命令`import`,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块去取值,es6模块化不会缓存运行结果,而是动态地去加载的模块取值,而且变量总是绑定在其所在的模块。
8 |
9 | ## commonJS 规范
10 | Node在解析JS模块时,会先按文本读取内容,然后将模块内容进行包裹,在外层包裹了一个`function`,传入变量。
11 |
12 | commonJS规范是在代码运行时同步阻塞地加载模块,在执行代码过程中遇到`require(X)`会停下来等待,直到新的模块加载完成后再继续执行接下来的代码。
13 |
14 | ```
15 | function require(modulePath){
16 | //1. 将modulePath转化为绝对路径
17 | // D:\Users\NodeJS\myModule.js
18 | // 2. 判断是否该模块已经有缓存
19 | if(require.cache["D:\User\NodeJS\myModule.js"]){
20 | return require.cache["D:\User\NodeJS\myModule.js"]
21 | }
22 | // 3. 读取文件内容
23 | // 4. 包裹到一个函数中
24 | function _temp(module,exports,require,__dirname,__filename){
25 | console.log("当前模块路径",__dirname)
26 | console.log("当面模块文件",__dirname)
27 | exports.c = 3
28 | module.exports = {
29 | a:1,
30 | b:2
31 | }
32 | this.m = 5
33 | }
34 | // 5. 创建module对象
35 | module.exports = {}
36 | const exports = module.exports
37 |
38 | __temp.call(module.exports, module, exports, require, module.path, module.filename)
39 |
40 | return module.exports;
41 | }
42 | require.cache = {};
43 |
44 | }
45 | ```
46 |
47 | ## commonJS的缓存
48 | > 文件查询挺耗时的,还有在实际开发中,模块可能包含副作用代码,例如在模块顶层执行`addEventListener`,如果require过程中被重复执行多次可能会出现问题。
49 |
50 | commonJS中的缓存可以解决重复查找和重复执行的问题。以绝对路径为`key`,`module`对象为`value`写入`cache`。在读取模块的时候会优先判断是否已在缓存中,如果在,直接返回`module.exports`,如果不在,则会进入模块查找的流程。
51 |
52 | ```
53 | //a.js
54 | module.exports = {
55 | foo:1
56 | }
57 |
58 | // main.js
59 | const a1 = require('./a.js')
60 | a1.foo = 2;
61 |
62 | const a2 = require('./a.js')
63 |
64 |
65 | console.log(a2.foo) //2
66 | console.log(a1 === a2) //true
67 | ```
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/jquery.xmind:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhh10/Notes/b003a1dfed01e652209094a6b7793e8766f9958a/jquery.xmind
--------------------------------------------------------------------------------
/loader与plugin.md:
--------------------------------------------------------------------------------
1 | # loader
2 | ```
3 | module:{
4 | rules:[{
5 | test:/\.js$/,
6 | use:[path.resolve(__dirname,'loader','loader3.js'),
7 | path.resolve(__dirname,'loader','loader2.js'),
8 | path.resolve(__dirname,'loader','loader1.js')]
9 | }]
10 | }
11 | ```
12 | - 正常调用顺序是`loader1,loader2,loader3`,但真正调用的顺序是`loader3(pitch)、loader2(pitch)、loader1(pitch)、loader1、loader2、loader3`,如果其中任何一个`pitching loader`返回了值就相当于它以及它右边的`loader`已经执行完毕
13 | - 如果`loader2 pitch`返回了值,接下来只有`loader3`被执行
14 | - `loader`根据返回值可以分为两种,一种是返回JS代码(有`module.exports`)的`loader`,还有不能作为最左边的其他`loader`
15 |
16 | **loader/loader1.js**
17 | ```
18 | function loader(source){
19 | console.log('loader1')
20 | return source+1
21 | }
22 | loader.pitch = function(remainingRequest,previousRequest,data){
23 | console.log(remainingRequest,previousRequest,data)
24 | data.name = 'pitch1'
25 | console.log('pitch1')
26 | }
27 | module.exports = loader
28 | ```
29 | **loader/loader2.js**
30 | ```
31 | function loader(source){
32 | console.log('loader2')
33 | return source + '//2'
34 | }
35 | loader.pitch = function(remainingRequest,previousRequest,data){
36 | console.log('remainingRequet=',remainingRequest)
37 | console.log('previousRequest=',previousRequest)
38 | console.log('pitch2')
39 | }
40 | module.exports = loader
41 | ```
42 | **loader/loader3.js**
43 | ```
44 | function loader(source){
45 | console.log('loader3')
46 | return source + '//3'
47 | }
48 |
49 | loader.pitch = function(){
50 | console.log('loader3')
51 | }
52 | module.exports = loader
53 | ```
54 |
55 | # plugin
56 | - 是一个独立模块
57 | - 对外暴露一个JS函数
58 | - 函数原型(prototype)上定义了一个注入`compiler`对象的`apply`方法,`apply`函数中需要通过`compiler`对象挂载的`webpack`钩子,钩子的回调中能拿到当前编译的`compilation`对象,如果是异步编译插件中可以拿到回调`callback`
59 | - 完成自定义编译流程并处理`compilation`对象的内部数据
60 | - 如果是异步编程插件的话,数据处理完成后执行`callback`回调
61 |
62 | ## 开发基本形式
63 | ```
64 | class BasicPlugin{
65 | constructor(pluginOptions){
66 | this.options = pluginOptions
67 | }
68 | // 原型(prototype)上定义了一个注入`compiler`对象的`apply`方法
69 | apply(compiler){
70 | compiler.plugin('emit',function(compilation,callback){
71 | console.log(compilation)
72 | callback()
73 | })
74 | }
75 | }
76 | module.exports = BasicPlugin
77 | ```
78 |
79 | ## compiler对象
80 | `compiler`对象是`webpack`的编译器对象,`compiler`对象会在启动`webpack`的时候一次性初始化,`compiler`对象中包含了所有`webpack`可自定义操作的配置,例如 `loader` 的配置,`plugin `的配置,`entry `的配置等各种原始` webpack` 配置等。
81 |
82 | ## compilation对象
83 | compilation对象实例继承于compiler,compilation 对象代表了一次单一的版本 webpack 构建和生成编译资源的过程。当运行 webpack 开发环境中间件时,每当检测到一个文件变化,一次新的编译将被创建,从而生成一组新的编译资源以及新的 compilation 对象。一个 compilation 对象包含了 当前的模块资源、编译生成资源、变化的文件、以及 被跟踪依赖的状态信息。编译对象也提供了很多关键点回调供插件做自定义处理时选择使用。
84 |
85 | Compiler 和 Compilation 的区别在于:Compiler 代表了整个 Webpack 从启动到关闭的生命周期,而 Compilation 只代表一次新的编译。
86 |
--------------------------------------------------------------------------------
/package.json.md:
--------------------------------------------------------------------------------
1 | ### 简单版的package.json
2 |
3 | 当我们新建一个项目时,使用 `yarn init -y `或 `npm init -y` 命令后,在项目目录下会新增一个 `package.json`文件,内容如下:
4 | ```
5 | {
6 | "name": "xxxx", # 项目名称
7 | "version": "1.0.0", # 项目版本(格式:大版本.次要版本.小版本)
8 | "description": "", # 项目描述
9 | "main": "index.js", # 入口文件
10 | "scripts": { # 指定运行脚本命令的 npm 命令行缩写
11 | "test": "echo \"Error: no test specified\" && exit 1"
12 | },
13 | "keywords": [], # 关键词
14 | "author": "", # 作者
15 | "license": "ISC" # 许可证
16 | }
17 | ```
18 | ### 必备属性(`name`&`version`)
19 | - `name`
20 | - `version`
21 |
22 | 组成`npm`模块的唯一标识
23 |
24 | ### name字段
25 | `name`字段不能与其他模块名重复,我们可以执行以下命令查看模块名是否已经被使用:
26 | ```
27 | npm view
28 | ```
29 | ### `version`字段
30 | `npm`包中的模块版本都需要遵循 `SemVer` 规范,该规范的标准版本号采用 X.Y.Z 的格式,其中 X、Y 和 Z 均为非负的整数,且禁止在数字前方补零:
31 | - `X`是主版本号:修改了不可兼容的API
32 | - `Y`是次版本号:新增了向下兼容的功能
33 | - `Z`是修订号:修正了向下兼容的问题
34 |
35 | 当某个版本改动比较大、并非稳定而且可能无法满足预期的兼容性需求时,我们可能要先发布一个**先行版本**。
36 |
37 | 先行版本号可以加到`主版本号.次版本号.修订号`的后面,通过 `-` 号连接一连串以句点分隔的标识符和版本编译信息:
38 | - 内部版本`alpha`
39 | - 公测版本`beta`
40 | - 正式版本的候选版本`rc`即 Release candiate)
41 |
42 | ```
43 | npm view version // 查看某个版本的最新版本
44 |
45 | npm view versions //查看某个版本的所有版本
46 | ```
47 |
48 | ### 描述信息(`description`&`keywords`)
49 | - `description`字段用于添加模块的描述信息,便于用户了解该模块
50 | - `keywords`字段用于给模块添加关键字
51 |
52 | ### 安装项目依赖(`dependencies`&`devDependencies`)
53 | - `dependencies`字段指定了项目`运行`所依赖的模块(生产环境使用)
54 | - `antd`
55 | - `react`
56 | - `moment`
57 | - `devDependencies`字段指定了项目`开发`所需要的模块(开发环境使用)
58 | - `webpack`
59 | - `typescript`
60 | - `babel`
61 | ```
62 | npm install --save //写入dependencies
63 |
64 | npm install --save-dev //写入devDependencies
65 | ```
66 | ```
67 | yarn add //写入dependencies
68 |
69 | yarn add --dev //写入devDependencies
70 | ```
71 |
72 | ### 简化终端命令(scripts)
73 | `scripts` 字段是 `package.json` 中的一种元数据功能,它接受一个对象,对象的属性为可以通过 `npm run` 运行的脚本,值为实际运行的命令(通常是终端命令),如:
74 | ```
75 | "scripts":{
76 | "start":"node index.js"
77 | }
78 | ```
79 | 将终端命令`scripts`字段,既可以记录它们又可以轻松实现重用。
80 |
81 | ### 定义项目入口(`main`)
82 | `main`字段是`package.json`中的另一种元数据功能,它可以用来指定加载的入口文件。假如你的项目是一个`npm`包,当用户安装你的包后,`require('my-module')`返回的是`main`字段中所列出文件的`module.exports`属性。
83 |
84 | 当不指定`main`字段,默认值是模块根目录下面的`index.js`文件。
85 |
86 | ### 指定项目node版本(`engines`)
87 | 有时候,新拉一个项目的时候,由于和其他开发使用的`node`版本不同,导致会出现很多奇奇怪怪的问题(如某些依赖安装报错、依赖安装完项目跑步起来等)。
88 |
89 | 为了实现项目开箱即用的伟大理想,这时候可以使用 `package.json` 的 `engines` 字段来指定项目 `node` 版本:
90 | ```
91 | "engines":{
92 | "node":">= 8.16.0"
93 | }
94 | ```
95 | 该字段也可以指定适用的 npm 版本:
96 | ```
97 | "engines":{
98 | "npm":">= 6.9.0"
99 | }
100 | ```
101 | **需要注意的是,engines属性仅起到一个说明的作用,当用户版本不符合指定值时也不影响依赖的安装。**
102 |
103 | ### 自定义命令(`bin`)
104 | 用过`vue-cli`、`create-react-app`等脚手架的朋友们,就可以使用类似`vue create/create-react-app`之类的命令,其实这和`package.json`中的`bin`字段有关。
105 |
106 | `bin`字段用来指定各个内部命令对应的可执行文件的位置。当`package.json `提供了 `bin` 字段后,即相当于做了一个命令名和本地文件名的映射。
107 |
108 | 当用户安装带有` bin `字段的包时,
109 | - 如果是全局安装,`npm` 将会使用符号链接把这些文件链接到`/usr/local/node_modules/.bin/`;
110 | - 如果是本地安装,会链接到`./node_modules/.bin/`。
111 |
112 | 如果要使用` my-app-cli` 作为命令时,可以配置以下` bin` 字段:
113 | ```
114 | "bin":{
115 | "my-app-cli":"./bin/cli.js"
116 | }
117 | ```
118 | 上面代码指定,`my-app-cli` 命令对应的可执行文件为` bin `子目录下的 `cli.js`,因此在安装了 `my-app-cli` 包的项目中,就可以很方便地利用 npm执行脚本:
119 | ```
120 | "scripts":{
121 | start:"node node_modules/.bin/my-app-cli"
122 | }
123 | ```
124 | 怎么看起来和 `vue create/create-react-app`之类的命令不太像?原因:
125 | - 当需要 `node` 环境时就需要加上` node` 前缀
126 | - 如果加上 `node` 前缀,就需要指定 `my-app-cli` 的路径 -> `node_modules/.bin`,否则 `node my-app-cli`会去查找当前路径下的 `my-app-cli.js`,这样肯定是不对。
127 |
128 | 若要实现像 `vue create/create-react-app`之类的命令一样简便的方式,则可以在上文提到的 `bin` 子目录下可执行文件`cli.js` 中的第一行写入以下命令:
129 | ```
130 | #!/usr/bin/env node
131 | ```
132 | 这行命令的作用是告诉系统用 `node` 解析,这样命令就可以简写成 `my-app-cli` 了。
133 |
134 | ### 开发环境解决跨域问题(proxy)
135 | 在做前后端分离的项目的时候,调用接口时则会遇到遇到跨域的问题,当在开发环境中,可以通过配置`pageage.json`中的`proxy`来解决跨域问题。
136 | ```
137 | {
138 | "proxy":"http://localhost:9800"
139 | // 配置要请求的服务器地址
140 | }
141 | ```
142 | ### 根据开发环境采用不同的全局变量值(自定义字段)
143 | ```
144 | "scripts":{
145 | "start":"NODE_ENV=development node scripts/start.js",
146 | "build":"NODE_ENV=production node scripts/build.js"
147 | }
148 | ```
149 | 项目启动起来后,在代码中我们可以通过`process.env.NODE_ENV`访问到`NODE_ENV`的值
150 | ```
151 | let sentryUrl;
152 | if(process.env.NODE_ENV === 'development'){
153 | sentryUrl = 'xxxxx'
154 | }else{
155 | sentryUrl = 'yyyyy'
156 | }
157 | ```
158 |
--------------------------------------------------------------------------------
/typescript.xmind:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhh10/Notes/b003a1dfed01e652209094a6b7793e8766f9958a/typescript.xmind
--------------------------------------------------------------------------------
/webpack面试题.md:
--------------------------------------------------------------------------------
1 | ### 1. 有哪些常见的Loader,它们是解决什么问题的?
2 |
3 | ### 2. 有哪些常见的Plugin,它们是解决什么问题的?
4 | ### 3. Webpack的构建流程?
5 |
6 | 1. **初始化参数**: 从配置文件中读取参数
7 | 2. **开始编译**: 用参数初始化`compiler`对象,加载所有配置的插件,执行对象的`run`方法开始执行编译。
8 | 3. **确定入口**: 根据配置中的`entry`找出所有的入口文件。
9 | 4. **编译模块**: 从入口文件出发,调用所有配置的Loader对模块进行编译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过本步骤的处理。
10 | 5. **完成模块编译**: 在经过第四步使用Loader编译完所有模块后,得到了每个模块被翻译后的最终内容以及它之间的依赖关系。
11 | 6. **输出资源**: 根据入口文件和模块之间的依赖关系,组装成一个个包含多个模块的`chunk`,再把每个`chunk`转换成一个单独的文件加入到输出列表。
12 | 7. **输出完成**: 在确定后输出内容后,根据配置确定的输出的路径和文件名,把文件内容写入到文件系统中。
13 |
14 | ### 4. 如何利用webpack优化前端性能?
15 | 1. 压缩代码: 删除多余的代码、注释、简化代码的写法等等方式,压缩JS、CSS文件。
16 | 2. 删除死代码: 将代码中永远不会用到的片段删除掉
17 | 3. 提取公共代码
18 |
19 | ### 5. Loader 和 Plugin的不同
20 | **Loader**: Webpack将一切文件视为模块,但是Webpack原生是只能解析JS文件,如果想将其他文件也打包的话,就会用到Loader,所以Loader的作用是让Webpack拥有了加载和解析非JS文件的能力。
21 |
22 | **Plugin**: "插件",Plugin可以扩展Webpack的性能,让Webpack具有更多的灵活性。在Webpack运行的生命周期中会广播出许多事件,Plugin可以监听这些事件,在合适的时机通过Webpack提供的API改变输出结果。
23 |
--------------------------------------------------------------------------------
/包管理器.xmind:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhh10/Notes/b003a1dfed01e652209094a6b7793e8766f9958a/包管理器.xmind
--------------------------------------------------------------------------------
/四种判断数据类型的方法.md:
--------------------------------------------------------------------------------
1 | ### 1. typeOf
2 | - 优点: 使用简单,基本类型都可以有效检验
3 | - 局限性:
4 | 1. `NaN/Infinity`都是数字类型,检验结果都是`number`
5 | 2. `typeof null`的结果是`Object`
6 | 3. `typeof`数组/对象/正则,结果都是`Object`,无法区分数组和对象
7 |
8 | ### 2. instanceof
9 | 检测某个实例是否属于这个类
10 | - 优点: `[] instanceof Array`即可判断数组,弥补`typeof`无法区分数组和对象的缺点
11 | - 局限性:
12 | 1. 要求检测的实例都是对象数据类型
13 | 2. 基本类型的实例无法基于它检测
14 | - 构造函数创建的可以访问: `new String(123) instanceof String`
15 | - 字面量方式创建的不可访问: `"123" instanceof String`
16 | ### 3. constructor
17 | 判断当前实例的`constructor`的属性值是不是预估的类
18 | - 优点: 简单方便
19 | - 局限性:
20 | 1. `constructor`容易被修改,基于它检测存在不稳定性
21 | 2. 自己定义的构造函数生成的类无法被检测
22 |
23 | ### 4. Object.prototype.toString.call
24 | 原理:
25 | 1. 每一种数据类型的构造函数上都有`toString`
26 | 2. 除了`Object.prototype`上的`toString`是返回当前实例所属类的信息(检验数据类型的),其余都是转换为字符串
27 | 3. call把方法中的this指向检测的数据值
28 |
29 | - 优点:
30 | - 可以优先检验任何数据类型的值
31 | - 局限性:
32 | - 不能检验自定义类,只要是自定义类都是`[Object,Object]`
33 |
--------------------------------------------------------------------------------
/手写源码部分.md:
--------------------------------------------------------------------------------
1 | ### 手写`Call`方法
2 | ```
3 | Function.prototype.myCall = function(context,...args){
4 | context = context === undefined ? window : context;
5 | let type = typeof context;
6 | if(type !== 'function' || type !== 'object'){
7 | context = Object(context)
8 | }else{
9 | context = new Object.constructor(context)
10 | }
11 | let key = Symbol('key'),result
12 | context[key] = this
13 | result = context[key](...args)
14 | delete context[key]
15 | return result
16 | }
17 | ```
18 |
19 | ### 手写`bind`方法
20 | ```
21 | Function.prototype.mybind(context,...args){
22 | let self = this
23 | context = context === undefined ? window : context
24 | let type = typeof context
25 | if(type !== 'function' || type !== 'object'){
26 | context = Object(context)
27 | }else{
28 | context = new Object.constructor(context)
29 | }
30 | return function anonymous(...innerargs){
31 | self.call(self,args.concat(innerargs))
32 | }
33 | }
34 | ```
35 | ### 手写`new`方法
36 | - 创建一个实例对象,原型指向`FUNC.prototype`
37 | - 执行代码,this指向实例对象
38 | - 分析结果,如果结果是函数或者对象,直接返回结果
39 | ```
40 | function _new(func,...args){
41 | let obj = {}
42 | obj.__proto__ = func.prototype
43 | const result = func.call(obj,...args)
44 | if(result !== null && /^(object|function)$/.test(typeof func)){
45 | return result
46 | }else{
47 | return obj
48 | }
49 | }
50 | ```
51 |
52 | ### `Object.create`的基本实现
53 | ```
54 | function create(obj){
55 | function F(){}
56 | F.prototype = obj
57 | return new F()
58 | }
59 | ```
60 |
61 | ### `instanceof`实现
62 | ```
63 | function my_instanceof(L,R){
64 | var O = R.prototype
65 | L = L.__proto__
66 | while(true){
67 | if(L === null){
68 | return false
69 | }else if(O === L){
70 | return true
71 | }
72 | L = L.__proto__
73 | }
74 | }
75 | ```
76 |
--------------------------------------------------------------------------------
/模块化.xmind:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhh10/Notes/b003a1dfed01e652209094a6b7793e8766f9958a/模块化.xmind
--------------------------------------------------------------------------------
/浏览器的渲染原理.md:
--------------------------------------------------------------------------------
1 | ### 起源
2 | 浏览器输入url,敲下回车键,客户端就向服务器发送Request请求,经过DNS解析、TCP三次握手四次挥手,然后服务端发送过来Response响应,拿到代码后,浏览器在内存条中开辟一块栈内存stack,用来给代码的执行提供环境,同时分配一个主线程去一行行地解析和执行代码。
3 |
4 | ### 渲染
5 | 执行代码遇到`link`、`image`、`script`、`video`等需要加载外部文件的,都会单独开辟新的线程。这里不要误会,JS是单线程的,但是浏览器是多线程的,不仅有JS引擎,还有GUI渲染、计时器、事件监听等线程。
6 |
7 | ### 事件循环
8 | 浏览器会开辟新的线程去请求css文件,开辟一个新的等待任务队列Task Queue,任务队列中分为微任务和宏任务两种,会先执行完所有的微任务后再执行宏任务。当主线程的代码执行完后,就会去任务队列中将任务放到主线程中执行。
9 |
10 | ### Render Tree
11 | 第一次自上而下走完后只生成DOM树,然后去任务队列中将加载好的CSS资源放到主线程中执行,CSS处理完成生成CSSOM树,DOM树和CSSOM树结合生成Render Tree渲染树。
12 |
13 | ### 回流和重绘
14 | 构建完Render Tree后,会先经过回流(计算它们在设备视口内的确切位置和大小),然后进行重绘(根据渲染树以及回流得到的几何信息,得到节点的绝对像素),最后将像素发送给GPU,展示在页面上。
15 |
16 | #### 1. 回流
17 | 元素的大小或者位置发生了改变
18 | 1. 触发了重新布局
19 | 2. 添加或删除DOM
20 | 3. 元素尺寸发生了变化
21 | 4. 内容发生了变化
22 | 5. 页面一开始渲染
23 | 6. 浏览器窗口尺寸发生了变化
24 |
25 | #### 2. 重绘
26 | 样式的改变(但宽高、大小、位置等不变)
27 |
28 | `outline、visiblity、color、background-bolor`
29 | ### 性能优化
30 | 1. 减少http请求次数和大小
31 | - 资源合并压缩
32 | - 图片懒加载(滚动到哪个位置,才进行请求显示)
33 | - 音视频走流文件(m3u8)
34 | 2. 尽可能地避免重绘/回流
35 | - 放弃传统的DOM操作,基于Vue/React开始数据影响视图模式(虚拟DOM/DOM-diff)
36 | - 分离读写操作
37 | - 样式集中改变
38 | - 动画效果应用到`position`属性为`absoluted`或`fixed`的元素上
39 | > 脱离了文档流,在新的层面上,这时导致的回流对其他元素没有影响
40 | - css3硬件加速
41 | > `transofrm/opacity/filters ...`会触发硬件加速,避免回流
42 |
43 | #### 分离读写操作
44 | 新版浏览器都有**渲染队列机制**,会将改变样式的推入到队列中,直到没有更改样式,只渲染一次。
45 |
46 | `offsetTop offsetLeft offsetWidth offsetHeight clientTop clientLeft clientWidth clientHeight scrollTop scrollLeft scrollWidth scrollHeight getComputedStyle currentStyle`
47 |
48 | 都会刷新渲染队列
49 | ```
50 | box.style.width = '200px'
51 | box.style.height = '100px'
52 | // 因为有渲染队列的存在,只渲染一次
53 |
54 | box.style.width = '200px'
55 | console.log(box.offsetHeight)
56 | // offsetHeight 刷新了渲染队列,导致渲染了两次
57 | box.style.height = '100px'
58 | ```
59 | **解决办法**
60 | 1. 使用`cssText`
61 | ```
62 | box.style.cssText = "width:100px;height:200px"
63 | ```
64 | 2. 样式集中改变
65 | 将样式写在一个`class`类名中
66 | ```
67 | box.style.className = "aa"
68 | ```
69 | 3. 缓存读写
70 | ```
71 | var a = box.clientWidth
72 | var b = box.clientHeight
73 | box.style.width = a + 10 + 'px'
74 | box.style.height = b + 10 + 'px'
75 | ```
76 |
77 | ##### 文档碎片
78 | ```
79 | let frg = document.createDocumentFragment() for(let i=0;i<5;i++){
80 | let newLi = document.createElement('li')
81 | newLi.innerHTML = i;
82 | frg.appendChild(newLi);
83 | }
84 | box.appendChild(frg)
85 | ```
86 | ##### 字符串拼接 ES6模版字符串
87 | ```
88 | let str = ``
89 | for(let i = 0;i<5;i++){
90 | str=`${i}`
91 | }
92 | box.innerHTML = str
93 | ```
94 | ### 扩展 link和@import的区别
95 | - 在渲染过程中遇到引入样式
96 | 1. 浏览器会新开辟一个http的请求线程,专门去服务器加载css样式内容
97 | 2. 此时GUI线程还可以继续向下渲染
98 | 3. 异步操作
99 | - 如果遇到的是@import导入样式
100 | 1. 不会开辟新线程去加载css,而是当前线程去加载
101 | 2. 这样只要css样式没有加载回来,下面的代码都不会执行
102 | 3. 同步操作
103 |
104 | ### 浏览器常用线程
105 | 浏览器是多线程的,但是JS渲染或者页面渲染是单线程的
106 | - GUI渲染线程
107 | - 渲染和绘制页面
108 | - JS引擎线程
109 | - 运行和渲染JS代码
110 | - 事件管制和触发线程
111 | - 定时器管控和触发线程
112 | - 异步http请求线程
113 |
--------------------------------------------------------------------------------
/浏览器面试题.md:
--------------------------------------------------------------------------------
1 | ### 1. 浏览器的主要组成部分是什么?
2 | 1. **用户界面**: 包括地址栏、前进/后退按钮、书签菜单等。
3 | 2. **浏览器引擎**: 在用户界面与呈现引擎之间传送指令。
4 | 3. **呈现引擎**: 负责显示请求的内容。如果请求的内容是HTML,它就负责解析HTML和CSS内容,并将解析后的内容显示在屏幕上。
5 | 4. **网络**: 用于网络调用,比如HTTP请求。
6 | 5. **用户界面引擎**: 用于绘制基本的窗口小部件,比如组合框和窗口。
7 | 6. **JS解释器**: 用于解析和执行JS代码。
8 | 7. **数据存储**: 这是持久层,浏览器需要在硬盘上保存各种数据,例如cookie。HTML5定义了"网络数据库",这是一个完整(但是轻便)的浏览器内数据库。
9 |
10 | ### 2. 为什么JS是单线程的,与异步冲突吗?
11 | JS的单线程是指一个浏览器进程中只有一个JS的执行线程,同一时刻内只会有一段代码在执行。
12 |
13 | 举个例子,假设JS支持多线程操作的话,JS可以操作DOM,那么一个线程正在删除DOM,另外一个线程就在获取DOM数据,这样子明显不合理。
14 |
15 | 异步机制是浏览器的两个或以上常驻线程共同完成的,举个例子,比如异步请求由两个常驻线程,JS执行线程和事件触发线程共同完成的。
16 | - JS执行线程发起异步请求(浏览器会开启一个HTTP请求线程来执行请求,这时JS的任务完成,继续执行线程队列中剩下任务)
17 | - 然后在未来的某一时刻事件触发线程监视到之前的发起的HTTP请求已完成,它就会把完成事件插入到JS执行队列的尾部等待JS处理。
18 |
19 | 比如定时器触发`setTimeout`和`setinterval`,是由**浏览器的定时器线程**执行的定时器计数,然后在定时时间把处理函数的执行请求插入到JS执行队列的尾端。
20 |
21 | 所以JS单线程与异步更多是浏览器行为,之间不冲突。
22 |
23 | ### 3. CSS加载会造成阻塞吗?
24 | - CSS不会阻塞DOM解析,但是会阻塞DOM渲染。
25 | - CSS会阻塞JS执行,并不会阻塞JS文件下载。
26 |
27 | 先讲一讲CSSOM作用
28 | - 提供给JS操作样式表的能力
29 | - 为布局树的合成提供基础的样式信息
30 | - 这个CSSOM体现在DOM中就是`document.styleSheets`
31 |
32 | DOM和CSSOM通常是并行构建的,所以**CSS加载不会阻塞DOM的解析**
33 |
34 | 因为**Render Tree**依赖DOM和CSSOM Tree的,所以它必须等待两者都加载完毕后,完成响应的构建才开始渲染,因此**CSS加载会阻塞DOM渲染**
35 |
36 | **有时候JS需要等到CSS的下载,这是为什么呢?**
37 |
38 | 如果脚本的内容是获取元素的样式、宽高等CSS控制的属性,浏览器是需要计算的,也就是依赖于CSS。浏览器也无法感知脚本内容到底是什么,为了避免样式获取,因此只好等前面所有的样式下载完后,再执行JS。JS文件下载和CSS文件下载是并行的,有时候CSS文件很大,所以JS需要等待。
39 |
40 | 因此,样式表会在后面的JS执行前先加载执行完毕,所以**CSS会阻塞后面JS的执行**
41 |
42 | ### 4. 为什么JS会阻塞页面加载?
43 | 这也是说什么JS文件放在最下面的原因
44 |
45 | 由于JS是可操纵DOM和CSS样式的,如果在修改这些元素属性同时渲染界面(即JS线程和GUI线程同时运行),那么渲染线程前后获得的元素数据就可能不一致了。
46 |
47 | 因此为了防止渲染出现不可预期的结果,浏览器设置**GUI渲染线程与JS引擎为互斥**的关系。
48 |
49 | 当JS引擎执行时,GUI渲染线程就会被挂起,GUI更新会被保存到一个队列中等到引擎线程空闲时立即被执行。
50 |
51 | 当浏览器在执行JS程序的时候,GUI渲染线程就被保存在一个队列中,知道JS程序执行完成,才会接着执行。
52 |
53 | 因此如果JS执行时间过长吗,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉。
54 |
55 | **如果JS文件中没有操作DOM相关的代码,就可以将该JS脚本设置成异步加载,通过async或defer来标记代码**
56 |
57 | ### 5. defer和async的区别?
58 | - 两者都是异步加载外部JS文件,不会阻塞DOM解析
59 | - async是在外部JS加载完成后,浏览器空闲时,Load事件触发前执行,标记为async的脚本并不保证按照制定它们的先后顺序执行,该属性对于内联脚本无作用(即没有src属性的脚本)
60 | - defer是在JS加载完成后,整个文档解析完成后,触发`DOMContentLoaded`事件前执行,如果缺少src属性,该属性不应被使用。
61 |
62 | ### 6. DOMContentLoaded与load的区别?
63 | - `DOMContentLoaded`事件触发时: 仅当DOM解析完成后,不包括样式表,图片等资源。
64 | - `load`事件触发时: 页面上所有的DOM,样式表,脚本,图片等资源已经加载完成。
65 |
66 | > 带async的脚本一定会在load事件执行执行,可能会在`DOMContentLoaded`之前或之后执行。
67 | - 情况1: HTML还没有解析完的时候,async脚本已经加载完了,那么HTML停止解析,去执行脚本,脚本执行完毕后触发`DOMContentLoaded`事件
68 | - 情况2: HTML解析完之后,async脚本才加载完,然后再执行脚本,那么在HTML解析完毕,async脚本还没有加载完的时候触发`DOMContentLoaded`事件
69 |
70 | > script标签中包含defer,那么这一块将不会影响HTML文档的解析,而是等待HTML解析完成后才会执行。而`DOMContentLoaded`只有在defer脚本执行结束后才会被触发。
71 |
72 | - 情况1: HTML还没有解析完成时,defer脚本已经加载完毕,那么defer脚本将等待HTML解析后再执行。defer脚本执行完毕后触发`DOMContentLoaded`事件。
73 | - 情况2: HTML解析完成时,defer脚本还没有加载完毕,那么defer脚本继续加载,加载完成后直接执行,执行完毕后触发`DOMContentLoaded`事件。
74 |
75 | ### 7. 函数节流
76 | 节流的意思是让函数有节制地执行,而不是毫无节制地触发一次就执行一次,在一段时间内,只执行一次。如果在这个单位时间内触发多次函数,只有一次生效。
77 |
78 | 常见应用场景:
79 | 1. 监听滚动事件,比如是否滑到底部自动加载更多。
80 | 2. 鼠标的点击事件,比如`mousedown`只触发一次。
81 |
82 | ### 8. 函数防抖
83 | 在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。
84 |
85 | 核心思想: 每次事件触发都会删除原有定时器,建立新的定时器。通俗意思就是反复触发函数,只认最后一次,从最后一次开始计时。
86 |
87 | 适合应用场景:
88 | 1. search搜索: 用户不断输入值,用防抖来节约AJAX请求,也就是输入框事件。
89 | 2. window触发resize时,不断调整浏览器窗口大小会不断地触发这个事件,用防抖来让其只触发一次。
90 |
91 | ### 9. Cookie的作用
92 | 1. 会话状态管理(如用户登录状态、购物车、游戏分数或其他需要记录的信息)
93 | 2. 个性化设置(如用户自定义设置、主题等)
94 | 3. 浏览器行为跟踪(如跟踪分析用户行为等)
95 |
96 | ### 10. Cookie的缺点
97 | 1. 容量缺陷: Cookie的体积上限只有**4KB**,只能存储少量信息。
98 | 2. 降低性能: Cookie紧跟着域名,不管域名下的某个地址是否需要这个Cookie,请求都会带上这个Cookie,请求数量增加,会造成巨大的浪费。
99 | 3. 安全缺陷: Cookie是以纯文本的形式是在浏览器和服务器中传递,很容易被非法用户获取,当HTTPOnly为false时,Cookie信息还可以直接通过JS脚本读取。
100 |
101 | ### 11. localStorage和sessionStorage
102 | 分类 | 生命周期 | 存储容量 | 存储位置 |
103 | ---|--- |--- |--- |
104 | cookie | 默认保存在内存中,随浏览器关闭失效(若设置过期时间,到期时间后失效) |4KB |保存在客户端,每次请求时都会带上|
105 | localStorage | 理论上永久有效的,除非主动清除 |4.98MB(不同浏览器情况不同,safari2.49MB)|保存在客户端,不与服务器交互。节省网络流量|
106 | sessionStorage | 仅在当前网页会话下有效,关闭页面或浏览器会被清除 |4.98MB(部分浏览器没有限制)|同上|
107 |
108 | **应用场景**:
109 | 1. `localStorage`适合持久化缓存数据。
110 | 2. `sessionStorage`适合
111 | **应用场景**:一次性临时数据保存,存储本次浏览信息记录,这样子页面关闭的话,就不需要这些记录了。
112 |
113 | ### 12. 浏览器缓存
114 | #### 1. 强缓存
115 | - Expires(Http1.0)
116 |
117 | 即过期时间,时间是相对于服务器的时间而言,存在于服务端返回的响应头中,在这个过期时间之前可以直接从缓存里面获取数据,无需再次请求。比如下面这样:
118 |
119 | `Expires:Mon, 29 Jun 2020 11:10:23 GMT`
120 |
121 | 表示该资源在2020年7月29日11:10:23过期,过期时就会重新向服务器发起请求。这个方式有一个问题:`服务器的时间和浏览器的时间可能并不一致`
122 |
123 | - Cache-Control(Http1.1)
124 |
125 | 这个字段采用的时间是过期时间
126 |
127 | `Cache-Control:max-age=6000`
128 |
129 | **注意**
130 | 1. `Expires`和`Cache-Control`同时存在时,优先考虑`Cache-Control`
131 | 2. 当缓存资源失效时,接下来进入协商缓存。
132 |
133 | #### 2. 协商缓存
134 | 强缓存失效后,浏览器在请求头中携带响应的`缓存Tag`来向服务器发送请求,服务器根据对应的tag,来决定是否使用缓存。缓存分为两种,`Last-Modified`和`ETag`。
135 | 1. Last-Modified
136 |
137 | 这个字段表示**最后修改时间**,在浏览器第一次给服务器发送请求后,服务器会在响应头加上这个字段。
138 | 浏览器接收到后,如果再次请求,会在请求头中携带**if-Modified-Since**字段,这个字段也就是服务器传来的最后修改时间。
139 | 服务器拿到请求头中的`if-Modified-Since`的字段后,其实会和这个服务器中**该资源的最后修改时间**对比:
140 |
141 | - 如果请求头中的这个值小于最后修改时间,说明是时候更新了。返回新的资源,跟常规的HTTP请求响应的流程一样。
142 | - 否则返回304,告诉浏览器直接使用缓存。
143 |
144 | 2. ETag
145 | ETag是服务器根据当前文件的内容,对文件生成唯一的标识,比如MD5算法,只要里面的内容有改动,这个值就会修改,服务器通过把响应头把该字段给浏览器。浏览器接受到ETag值,会在下次请求的时候,将这个值作为**If-None-Match**这个字段的内容,发给服务器。
146 |
147 | 服务器接收到**if-None-Match**后,会跟服务器上该资源的**ETag**进行对比:
148 |
149 | - 如果两者一样,返回304,告诉浏览器直接使用缓存
150 | - 如果不一样,说明内容更新了,返回新的资源,跟常规的HTTP请求响应的流程一样
151 |
--------------------------------------------------------------------------------
/页面性能优化.md:
--------------------------------------------------------------------------------
1 | ### 1. base64在html中的优缺点
2 | - 优点:
3 | 1. 网页中使用base64格式的图片时,不用再请求服务器调用图片资源,减少了服务器的请求次数
4 | 2. base64编码的字符串,适用不同平台、不同语言的传输
5 | - 缺点:
6 | 1. 编译后的大小会比原文件大1/3,如果把大图片编码到html/css中,不仅会造成文件体积的增加,影响文件的加载速度,还会增加浏览器对html或css文件解析渲染的时间
7 | 2. 使用base64无法直接缓存,要缓存只能缓存包含base64的文件,比如html或css,这比直接缓存图片要差很多
8 | 3. IE8以下不支持
9 |
10 | ### 2. 图片优化
11 | - 使用base64编码代替图片
12 | - 使用雪碧图 (可以有效减少http请求次数)
13 | - 预加载
14 | - 懒加载(先请求一部分图片,当用户滚动页面时再进一步加载图片)
15 | - 使用css/svg/canvas/iconfont代替图片 (减少图片尺寸,请求数据少)
16 |
--------------------------------------------------------------------------------