├── 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 | 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 |
58 |
这是页面内容
59 | 60 |
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 | --------------------------------------------------------------------------------