├── 新技术 ├── PWA.md ├── WebAssembly.md ├── ServiceWorker.md └── hybird.md ├── 5-性能优化 ├── testDemo │ ├── slowServer │ │ ├── slow.js │ │ ├── index.js │ │ ├── js-bottom.html │ │ └── js-header.html │ └── test-DOMContentLoaded.html ├── README.md ├── SEO.md ├── 性能测试.md ├── 雅虎军规.md ├── 编写高性能的Javascript.md ├── 浏览器渲染.md ├── 减少网络请求的次数或时间 │ └── CDN.md ├── 网络传输过程中优化.md └── 从输入URL到页面加载完成的过程.md ├── img ├── ==.png ├── fp.png ├── 666.jpg ├── TCP.png ├── UDP.png ├── brun.png ├── csrf.png ├── etag.png ├── fcp.png ├── fdjl.png ├── file.png ├── pipe.png ├── run.png ├── this.png ├── tls.png ├── vdon.png ├── ysbm.png ├── 流程图.jpg ├── QRcode.jpg ├── aduits.png ├── bdefine.png ├── cache.png ├── csr&ssr.png ├── define.png ├── domattr.png ├── domtree.png ├── dom事件模型.jpg ├── gc-new.png ├── http3.png ├── https.png ├── thank-1.png ├── thank-2.png ├── thank-3.png ├── thank-4.png ├── thank-5.jpg ├── thank-6.jpg ├── vScroll.png ├── webview.png ├── xuanran.png ├── yhjsf.png ├── 输入URL后.png ├── cache-200.png ├── cache-all.png ├── cdncache.png ├── debounce.png ├── example1.png ├── example2.png ├── function.png ├── git-glkz.png ├── git-jlcy.png ├── imgbottom.png ├── prototype.png ├── pureRedux.png ├── aduitsReport.png ├── cache-demo.png ├── cache-from.png ├── cache-github.png ├── cache-reopen.png ├── cache-worker.png ├── cdnnocahche.png ├── etag-match.png ├── fetch&pull.jpg ├── force-cache.png ├── git-3-place.png ├── git-commit.png ├── git-mergep.png ├── git-mergep2.png ├── git-rebease.png ├── http-3-base.webp ├── http-cache.png ├── http2-hpack.jpeg ├── http2-二进制传输.png ├── http2Connet.png ├── httpscrypt.png ├── lifeofframe.jpg ├── performance.png ├── quarticBye.png ├── slideWindow.png ├── stadardBox.png ├── strangeBox.png ├── addressChange.png ├── auditsSuggest.png ├── cache-refresh.png ├── consult-cache.png ├── git-newbranch.png ├── reload-worker.png ├── serviceWorker.png ├── setStateCercle.png ├── thr-handshake.png ├── 1729cf3b0a40a037.png ├── 1729d0dc24e12fcb.png ├── cache-consult-304.png ├── cache-lastmodify.png ├── consult-invalid.png ├── force-cache-use.png ├── git-headpointer.png ├── if-modified-since.png ├── istanbul-lanjie.png ├── performanceTime.png ├── marginSuperposition1.png ├── marginSuperposition2.png ├── marginSuperposition3.png └── marginSuperposition4.png ├── 实用工具与库 ├── 插件 │ ├── README.md │ └── 规范风格.md ├── decorateComponentWithProps.md ├── Formik │ └── README.md └── npm │ └── package-lock.json.md ├── 杂项 ├── 面试 │ ├── 简历.md │ ├── README.md │ └── 自我介绍.md ├── TODO.md ├── 前端资源汇总.md ├── 收到的感谢.md ├── 前端成长.md ├── 如何写技术文章(分享型).md ├── 优雅代码.md └── 前端二进制.md ├── 0-前端基础 ├── CSS │ ├── 动画 │ │ ├── animal.png │ │ ├── transition.html │ │ ├── animation.html │ │ ├── animal.html │ │ └── README.md │ ├── 布局 │ │ ├── Flex.md │ │ ├── BFC两栏布局.html │ │ ├── 三栏-网格布局.html │ │ ├── 三栏-flex.html │ │ ├── 三栏-浮动方案.html │ │ ├── 三栏-绝对定位.html │ │ ├── 三栏-表格布局.html │ │ ├── 双飞翼布局.html │ │ ├── 圣杯布局.html │ │ └── README.md │ ├── 居中元素 │ │ ├── 水平居中 │ │ │ ├── center1.html │ │ │ ├── center2.html │ │ │ ├── center4.html │ │ │ └── center3.html │ │ ├── 垂直居中 │ │ │ ├── center2.html │ │ │ ├── center3.html │ │ │ ├── center1.html │ │ │ ├── center4.html │ │ │ ├── center-in-body.html │ │ │ └── center5.html │ │ └── README.md │ └── CSS选择器.md ├── Web安全 │ ├── SQL注入.md │ ├── CSRF.md │ └── README.md ├── NodeJS │ ├── 异步IO.md │ ├── 核心模块 │ │ ├── process.md │ │ └── path.md │ ├── README.md │ └── npm.md ├── HTML │ └── example.html ├── JS │ ├── this.md │ ├── 事件.md │ ├── 3-运算符.md │ ├── 垃圾回收与内存泄露和优化.md │ ├── 其他题目.md │ ├── ServiceWorker.md │ ├── 作用域.md │ └── 事件队列.md └── 浏览器 │ └── 屏幕刷新率&帧.md ├── 1-前端框架与库 ├── React │ ├── 基础 │ │ ├── Hooks.md │ │ ├── 高阶组件.md │ │ ├── memo.md │ │ ├── PureComponent与Component区别.md │ │ ├── lazy与suspense.md │ │ ├── VDOM.md │ │ └── context.md │ ├── react-router.md │ ├── React中性能优化.md │ ├── Hooks │ │ ├── 其他 hooks.md │ │ ├── 组件复用例子 │ │ │ ├── hooks.jsx │ │ │ ├── class.jsx │ │ │ ├── render-props.jsx │ │ │ └── HOC.jsx │ │ ├── 自定义 hooks.md │ │ ├── README.md │ │ └── hooks 与定时器.md │ ├── React与Vue区别.md │ ├── react-script.md │ ├── Redux.md │ ├── 其他.md │ └── setState.md ├── Webpack │ ├── README.md │ ├── 基本概念 │ │ ├── plugins.md │ │ ├── 安装.md │ │ └── entry 和 output.md │ ├── 高级概念 │ │ ├── sourcemap.md │ │ └── 缓存.md │ └── webpack配置文件.md └── TypeScript │ ├── interface与type.md │ ├── 实用技巧.md │ ├── 接口.md │ └── 装饰器.md ├── 3-编程能力 ├── 函数式编程 │ └── README.md ├── 编程题与分析题 │ ├── 作用域.md │ ├── README.md │ ├── reduce实现map.md │ ├── reduce案例.js │ ├── 实现flatten函数.md │ ├── 两任务并行.md │ ├── name的值是多少.md │ ├── 手写Promise.md │ ├── 尽早按序打印Ajax请求.js │ ├── compose.md │ ├── 柯里化.md │ ├── debounce-demo.js │ ├── bind、apply实现.md │ ├── 类型判断.md │ ├── 实现一个sleep函数.md │ ├── 闭包.md │ ├── this指向.md │ ├── PromiseAll.md │ ├── 防抖节流.md │ ├── 使用Promise封装一个AJAX.md │ ├── deepCopy.js │ ├── 以下代码输出值.md │ └── 异步编程.md └── 算法 │ └── 树的遍历 │ ├── 广度优先遍历.js │ └── 深度优先遍历.js ├── 2-计算机基础 ├── 网络 │ ├── fetch.md │ ├── nginx.md │ ├── UDP.md │ ├── CDN.md │ ├── README.md │ ├── cookie和session.md │ ├── RESTful.md │ ├── Ajax.md │ ├── HTTPS.md │ └── 跨域.md └── 操作系统 │ ├── README.md │ ├── 进程与线程.md │ └── 死锁与银行家算法.md ├── .gitignore ├── 知识模型.md ├── 4-质量保障 └── 监控 │ ├── 错误监控.md │ └── README.md ├── package.json ├── 6-工程架构 ├── ServerLess.md └── BFF.md ├── LICENSE └── README.md /新技术/PWA.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /新技术/WebAssembly.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /新技术/ServiceWorker.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /5-性能优化/testDemo/slowServer/slow.js: -------------------------------------------------------------------------------- 1 | alert("我现在才被加载出来"); 2 | -------------------------------------------------------------------------------- /img/==.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/==.png -------------------------------------------------------------------------------- /img/fp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/fp.png -------------------------------------------------------------------------------- /实用工具与库/插件/README.md: -------------------------------------------------------------------------------- 1 | # 工具插件 2 | 3 | ### TabNine 4 | 5 | 一个机器学习驱动的代码自动补全工具 6 | -------------------------------------------------------------------------------- /img/666.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/666.jpg -------------------------------------------------------------------------------- /img/TCP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/TCP.png -------------------------------------------------------------------------------- /img/UDP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/UDP.png -------------------------------------------------------------------------------- /img/brun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/brun.png -------------------------------------------------------------------------------- /img/csrf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/csrf.png -------------------------------------------------------------------------------- /img/etag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/etag.png -------------------------------------------------------------------------------- /img/fcp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/fcp.png -------------------------------------------------------------------------------- /img/fdjl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/fdjl.png -------------------------------------------------------------------------------- /img/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/file.png -------------------------------------------------------------------------------- /img/pipe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/pipe.png -------------------------------------------------------------------------------- /img/run.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/run.png -------------------------------------------------------------------------------- /img/this.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/this.png -------------------------------------------------------------------------------- /img/tls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/tls.png -------------------------------------------------------------------------------- /img/vdon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/vdon.png -------------------------------------------------------------------------------- /img/ysbm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/ysbm.png -------------------------------------------------------------------------------- /img/流程图.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/流程图.jpg -------------------------------------------------------------------------------- /img/QRcode.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/QRcode.jpg -------------------------------------------------------------------------------- /img/aduits.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/aduits.png -------------------------------------------------------------------------------- /img/bdefine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/bdefine.png -------------------------------------------------------------------------------- /img/cache.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/cache.png -------------------------------------------------------------------------------- /img/csr&ssr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/csr&ssr.png -------------------------------------------------------------------------------- /img/define.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/define.png -------------------------------------------------------------------------------- /img/domattr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/domattr.png -------------------------------------------------------------------------------- /img/domtree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/domtree.png -------------------------------------------------------------------------------- /img/dom事件模型.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/dom事件模型.jpg -------------------------------------------------------------------------------- /img/gc-new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/gc-new.png -------------------------------------------------------------------------------- /img/http3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/http3.png -------------------------------------------------------------------------------- /img/https.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/https.png -------------------------------------------------------------------------------- /img/thank-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/thank-1.png -------------------------------------------------------------------------------- /img/thank-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/thank-2.png -------------------------------------------------------------------------------- /img/thank-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/thank-3.png -------------------------------------------------------------------------------- /img/thank-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/thank-4.png -------------------------------------------------------------------------------- /img/thank-5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/thank-5.jpg -------------------------------------------------------------------------------- /img/thank-6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/thank-6.jpg -------------------------------------------------------------------------------- /img/vScroll.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/vScroll.png -------------------------------------------------------------------------------- /img/webview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/webview.png -------------------------------------------------------------------------------- /img/xuanran.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/xuanran.png -------------------------------------------------------------------------------- /img/yhjsf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/yhjsf.png -------------------------------------------------------------------------------- /img/输入URL后.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/输入URL后.png -------------------------------------------------------------------------------- /img/cache-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/cache-200.png -------------------------------------------------------------------------------- /img/cache-all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/cache-all.png -------------------------------------------------------------------------------- /img/cdncache.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/cdncache.png -------------------------------------------------------------------------------- /img/debounce.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/debounce.png -------------------------------------------------------------------------------- /img/example1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/example1.png -------------------------------------------------------------------------------- /img/example2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/example2.png -------------------------------------------------------------------------------- /img/function.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/function.png -------------------------------------------------------------------------------- /img/git-glkz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/git-glkz.png -------------------------------------------------------------------------------- /img/git-jlcy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/git-jlcy.png -------------------------------------------------------------------------------- /img/imgbottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/imgbottom.png -------------------------------------------------------------------------------- /img/prototype.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/prototype.png -------------------------------------------------------------------------------- /img/pureRedux.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/pureRedux.png -------------------------------------------------------------------------------- /杂项/面试/简历.md: -------------------------------------------------------------------------------- 1 | # 如何写好的技术简历? 2 | 3 | - [是时候更新一下你的简历了](https://zhuanlan.zhihu.com/p/89522100) 4 | -------------------------------------------------------------------------------- /img/aduitsReport.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/aduitsReport.png -------------------------------------------------------------------------------- /img/cache-demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/cache-demo.png -------------------------------------------------------------------------------- /img/cache-from.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/cache-from.png -------------------------------------------------------------------------------- /img/cache-github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/cache-github.png -------------------------------------------------------------------------------- /img/cache-reopen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/cache-reopen.png -------------------------------------------------------------------------------- /img/cache-worker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/cache-worker.png -------------------------------------------------------------------------------- /img/cdnnocahche.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/cdnnocahche.png -------------------------------------------------------------------------------- /img/etag-match.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/etag-match.png -------------------------------------------------------------------------------- /img/fetch&pull.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/fetch&pull.jpg -------------------------------------------------------------------------------- /img/force-cache.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/force-cache.png -------------------------------------------------------------------------------- /img/git-3-place.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/git-3-place.png -------------------------------------------------------------------------------- /img/git-commit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/git-commit.png -------------------------------------------------------------------------------- /img/git-mergep.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/git-mergep.png -------------------------------------------------------------------------------- /img/git-mergep2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/git-mergep2.png -------------------------------------------------------------------------------- /img/git-rebease.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/git-rebease.png -------------------------------------------------------------------------------- /img/http-3-base.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/http-3-base.webp -------------------------------------------------------------------------------- /img/http-cache.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/http-cache.png -------------------------------------------------------------------------------- /img/http2-hpack.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/http2-hpack.jpeg -------------------------------------------------------------------------------- /img/http2-二进制传输.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/http2-二进制传输.png -------------------------------------------------------------------------------- /img/http2Connet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/http2Connet.png -------------------------------------------------------------------------------- /img/httpscrypt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/httpscrypt.png -------------------------------------------------------------------------------- /img/lifeofframe.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/lifeofframe.jpg -------------------------------------------------------------------------------- /img/performance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/performance.png -------------------------------------------------------------------------------- /img/quarticBye.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/quarticBye.png -------------------------------------------------------------------------------- /img/slideWindow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/slideWindow.png -------------------------------------------------------------------------------- /img/stadardBox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/stadardBox.png -------------------------------------------------------------------------------- /img/strangeBox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/strangeBox.png -------------------------------------------------------------------------------- /img/addressChange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/addressChange.png -------------------------------------------------------------------------------- /img/auditsSuggest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/auditsSuggest.png -------------------------------------------------------------------------------- /img/cache-refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/cache-refresh.png -------------------------------------------------------------------------------- /img/consult-cache.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/consult-cache.png -------------------------------------------------------------------------------- /img/git-newbranch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/git-newbranch.png -------------------------------------------------------------------------------- /img/reload-worker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/reload-worker.png -------------------------------------------------------------------------------- /img/serviceWorker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/serviceWorker.png -------------------------------------------------------------------------------- /img/setStateCercle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/setStateCercle.png -------------------------------------------------------------------------------- /img/thr-handshake.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/thr-handshake.png -------------------------------------------------------------------------------- /0-前端基础/CSS/动画/animal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/0-前端基础/CSS/动画/animal.png -------------------------------------------------------------------------------- /1-前端框架与库/React/基础/Hooks.md: -------------------------------------------------------------------------------- 1 | # hooks 2 | 3 | ### 类组件的缺点 4 | 5 | - 难以复用的状态逻辑 6 | - 复杂的生命周期函数 7 | - 混乱的副作用 8 | -------------------------------------------------------------------------------- /img/1729cf3b0a40a037.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/1729cf3b0a40a037.png -------------------------------------------------------------------------------- /img/1729d0dc24e12fcb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/1729d0dc24e12fcb.png -------------------------------------------------------------------------------- /img/cache-consult-304.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/cache-consult-304.png -------------------------------------------------------------------------------- /img/cache-lastmodify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/cache-lastmodify.png -------------------------------------------------------------------------------- /img/consult-invalid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/consult-invalid.png -------------------------------------------------------------------------------- /img/force-cache-use.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/force-cache-use.png -------------------------------------------------------------------------------- /img/git-headpointer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/git-headpointer.png -------------------------------------------------------------------------------- /img/if-modified-since.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/if-modified-since.png -------------------------------------------------------------------------------- /img/istanbul-lanjie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/istanbul-lanjie.png -------------------------------------------------------------------------------- /img/performanceTime.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/performanceTime.png -------------------------------------------------------------------------------- /实用工具与库/插件/规范风格.md: -------------------------------------------------------------------------------- 1 | # 规范与风格 2 | 3 | ### Eslint 4 | 5 | ### Pretter 6 | 7 | ### git-cz 8 | 9 | ### 10 | -------------------------------------------------------------------------------- /img/marginSuperposition1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/marginSuperposition1.png -------------------------------------------------------------------------------- /img/marginSuperposition2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/marginSuperposition2.png -------------------------------------------------------------------------------- /img/marginSuperposition3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/marginSuperposition3.png -------------------------------------------------------------------------------- /img/marginSuperposition4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huyaocode/webKnowledge/HEAD/img/marginSuperposition4.png -------------------------------------------------------------------------------- /杂项/TODO.md: -------------------------------------------------------------------------------- 1 | # TODO 清单 2 | 3 | - [对标阿里 p6 自检](https://mp.weixin.qq.com/s/0Y456nHryt03kmaC8tBXTw) 4 | - 按照自检清单梳理并学习 5 | -------------------------------------------------------------------------------- /3-编程能力/函数式编程/README.md: -------------------------------------------------------------------------------- 1 | # 函数式编程 2 | 3 | https://juejin.im/post/6844903936378273799#heading-31 4 | https://juejin.im/post/6844904034260910094 5 | -------------------------------------------------------------------------------- /1-前端框架与库/Webpack/README.md: -------------------------------------------------------------------------------- 1 | ### webpack 简介 2 | 3 | `webpack`是一个前端模块化打包工具,最开始它只能打包 JS 文件,但是随着 webpack 的发展,他还能打包如 CSS、图片等文件。主要由入口,出口,loader,plugins 四个部分。 4 | -------------------------------------------------------------------------------- /2-计算机基础/网络/fetch.md: -------------------------------------------------------------------------------- 1 | # fetch 2 | 3 | ## fetch 的缺点 4 | 5 | - 只对网络请求报错,对 400,500 都当做成功的请求 6 | - 默认不会带 cookie 7 | - 不支持 abort, 不支持超时控制 8 | - 没办法原生监控请求进度 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage 3 | .nyc_output 4 | .DS_Store 5 | *.log 6 | .vscode 7 | .idea 8 | compiled 9 | .awcache 10 | .rpt2_cache 11 | .pdf 12 | 0练手 13 | test.js -------------------------------------------------------------------------------- /1-前端框架与库/React/react-router.md: -------------------------------------------------------------------------------- 1 | # 路由 2 | 3 | React 中路由主要有两种方式: 4 | 5 | - hash 路由 6 | - history 路由 7 | 8 | [react-router 原理](https://blog.csdn.net/qq_36223144/article/details/83247008) 9 | -------------------------------------------------------------------------------- /0-前端基础/Web安全/SQL注入.md: -------------------------------------------------------------------------------- 1 | # SQL 注入 2 | 3 | 所谓 SQL 注入,就是通过把 SQL 命令插入到 Web 表单提交或输入域名或页面请求的查询字符串,后台执行 SQL 语句时直接把前端传入的字段拿来做 SQL 查询。 4 | 5 | ## 防御 6 | 7 | - 永远不要信任用户的输入。 8 | - 永远不要使用动态拼装 sql 9 | - 不要把机密信息直接存放 10 | -------------------------------------------------------------------------------- /杂项/前端资源汇总.md: -------------------------------------------------------------------------------- 1 | - [GitHub 最全前端资源汇总](http://fenghub.top/front-end-index/index.html) 2 | - [前端进阶之道](https://yuchengkai.cn/) 3 | - [有关 React,你需要知道的一切](https://github.com/hateonion/react-bits-CN) 4 | - [木易杨-壹题](https://muyiy.cn/question/) 5 | -------------------------------------------------------------------------------- /3-编程能力/编程题与分析题/作用域.md: -------------------------------------------------------------------------------- 1 | ```js 2 | function func() { 3 | function a() { 4 | console.log(b); 5 | } 6 | 7 | a(); 8 | const b = "bbb"; 9 | } 10 | 11 | func(); 12 | ``` 13 | 14 | 上面代码会输出什么? 15 | 16 | 答案: 17 | 18 | > ReferenceError: Cannot access 'b' before initialization 19 | -------------------------------------------------------------------------------- /杂项/收到的感谢.md: -------------------------------------------------------------------------------- 1 | ## 收的到感谢 2 | 3 | 满足我的虚荣心,然后也让大家相信文档质量,相信努力会换来收获,我今后把收到的感谢都匿名整理在这里。之前还有好多感谢我都把聊天记录删了,可惜了,我的虚荣心啊~ 4 | 5 | ![](../img/thank-3.png) 6 | 7 | ![](../img/thank-2.png) 8 | 9 | ![](../img/thank-1.png) 10 | 11 | ![](../img/thank-4.png) 12 | 13 | ![](../img/thank-5.jpg) 14 | 15 | ![](../img/thank-6.jpg) 16 | -------------------------------------------------------------------------------- /1-前端框架与库/React/React中性能优化.md: -------------------------------------------------------------------------------- 1 | [React 性能优化](https://segmentfault.com/a/1190000006254212) 2 | 3 | [React 进阶—性能优化](https://segmentfault.com/a/1190000008925295) 4 | 5 | ### 为什么使用 Virtual DOM,直接操作 DOM 的弊端是什么? 6 | 7 | 操作 DOM 是非常昂贵的,因为一个普通的 DOM 上有非常多的属性和方法,页面的性能问题很多都是由 DOM 操作引起的。 8 | 9 | VDOM 的意义在于实现了对 DOM 的抽象,从而配合 Diff 算法来比对新旧状态切换时页面需要更新的最小 DOM 范围。 10 | -------------------------------------------------------------------------------- /0-前端基础/NodeJS/异步IO.md: -------------------------------------------------------------------------------- 1 | # 异步 I/O 2 | 3 | ## 为什么要异步 I/O 4 | 5 | ### 用户体验,快! 6 | 7 | 使用阻塞式加载两个资源时间为 M + N 8 | 9 | 使用异步 I/O 加载两个资源时间为: max(M, N) 10 | 11 | ### 资源分配 12 | 13 | 假设有一堆不相关的任务需要完成,主流有两种 14 | 15 | - 单线程串行依次执行 16 | - 多线程并行执行 17 | 18 | 多线程的代价在于创建线程和执行线程上下文切换的开销较大。在复杂业务中,多线程编程经常面临锁、状态同步等问题,这是多线程的主要诟病。 19 | 20 | 单线程顺序执行比较符合思考顺序,而且易于表达。但串行执行 21 | -------------------------------------------------------------------------------- /3-编程能力/编程题与分析题/README.md: -------------------------------------------------------------------------------- 1 | # 编程题与分析题 2 | 3 | 链接可能不够完整,直接看对应目录 4 | 5 | - [bind、apply 实现](bind、apply实现.md) 6 | - [DOM 树遍历](DOM树遍历.md) 7 | - [README](README.MD) 8 | - [this 指向](this指向.md) 9 | - [异步编程](异步编程.md) 10 | - [深浅拷贝](深浅拷贝.md) 11 | - [类型判断](类型判断.md) 12 | - [观察者模式](观察者模式.md) 13 | - [闭包](闭包.md) 14 | - [防抖节流](防抖节流.md) 15 | - [手写 Promise](手写Promise.md) 16 | -------------------------------------------------------------------------------- /5-性能优化/README.md: -------------------------------------------------------------------------------- 1 | ## 性能优化 2 | 3 | Web 端的性能一般包含两个方面:1.首屏快不快,2. 使用卡不卡。但是不能仅凭感觉,所以会有一些列的[性能指标](./性能指标与计算.md)。 4 | 5 | ### 首屏速度 6 | 7 | 首屏速度可以从「从输入 URL 到页面加载完成」这个过程入手: 8 | 9 | - 通过懒加载、资源压缩等的方式**减少首屏资源的大小** 10 | - 通过预拉取、BFF、模版注入等方式**减少网络请求的次数或时间** 11 | - 通过缓存、CDN、开启Gzip等方式,**在网络传输过程中进行优化** 12 | - 通过 SSR 提前渲染好 HTML,减少首屏UI网络请求次数和渲染耗时 13 | - 最后当资源加载好后,以最快的速度将页面渲染出来 14 | 15 | -------------------------------------------------------------------------------- /1-前端框架与库/React/Hooks/其他 hooks.md: -------------------------------------------------------------------------------- 1 | # 其他 hooks 2 | 3 | ## useLayoutEffect 4 | 5 | useLayoutEffect 的函数签名与 useEffect 相同,但是它会在所有的 DOM 变更之后**同步**调用 effect。在浏览器执行绘制之前,useLayoutEffect 内部的更新计划将被同步刷新。 6 | 7 | useLayoutEffect 相比 useEffect,通过同步执行状态更新可解决一些特性场景下的页面闪烁问题。 8 | 9 | useEffect 可以满足百分之 99 的场景,而且 useLayoutEffect 会阻塞渲染,请谨慎使用。 10 | 11 | 演示例子: https://juejin.im/post/6844904008402862094 12 | -------------------------------------------------------------------------------- /0-前端基础/HTML/example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Document 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /3-编程能力/算法/树的遍历/广度优先遍历.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 广度优先遍历树 3 | * 4 | * 使用: 队列 5 | */ 6 | function widthTravel(tree) { 7 | let queue = []; 8 | let nodeList = []; 9 | tree && queue.push(tree); 10 | while (queue.length) { 11 | let node = queue.shift(); 12 | for (let i = 0; i < node.children.length; i++) { 13 | nodeList.push(node[i]); 14 | } 15 | } 16 | return nodeList; 17 | } 18 | -------------------------------------------------------------------------------- /1-前端框架与库/React/React与Vue区别.md: -------------------------------------------------------------------------------- 1 | # React 与 Vue 区别 2 | 3 | - 上手 4 | - vue - easy 官方做了很多,CSS script 5 | - react ,上手偏难, 6 | - 数据绑定 7 | - vue model 双向的 8 | - react 是单向的 9 | - 模板 10 | - vue H5 模板 11 | - react JSX 12 | - api 13 | - vue 多,计算属性,watch 这种神器 14 | - react 少,更多功能留给社区,比如写个函数还有 bind 以下 15 | - 应用 16 | - vue 适合面向用户的,复杂度稍低一些的 17 | - react 复杂的 18 | - 测试 19 | - react 函数式编程利于测试 20 | -------------------------------------------------------------------------------- /杂项/前端成长.md: -------------------------------------------------------------------------------- 1 | ## 前端成长 2 | 3 | 阿里二面面试官给我讲的一个架构师要做好哪四件事: 4 | 5 | - 选择一个好的挑战(创造价值) 6 | - 把简单的事情想复杂(控制风险,提前预判) 7 | - 把复杂的事情做简单(成本控制,开发效率) 8 | - 把复杂的事情讲简单(内部传承,方便运营) 9 | 10 | 如何做更好的前端? 11 | 12 | - 不要仅仅局限在一些技术上,不要做码农,要更多的了解业务,这样更能够应对项目的变与不变。 13 | - 前端是离用户最近的工程师,要找出一些能够创造价值的事情来做,反过来驱动自己去学习某技术,最后把业务做的更好。 14 | 15 | ### 大佬的故事 16 | 17 | - [阿里P8大佬圣司的前端成长之路](https://mp.weixin.qq.com/s/mtw1-7dLbEYWMuy3ADBc8w) 18 | 19 | -------------------------------------------------------------------------------- /3-编程能力/编程题与分析题/reduce实现map.md: -------------------------------------------------------------------------------- 1 | # 用 reduce 实现 map 的功能 2 | 3 | ```js 4 | Array.prototype.map = function (callback) { 5 | const array = this; 6 | return array.reduce((acc, cur, index) => { 7 | acc.push(callback(cur, index, array)); 8 | return acc; 9 | }, []); 10 | }; 11 | ``` 12 | 13 | 测试: 14 | 15 | ```js 16 | var m = [1, 2, 3, 4, 5].map(function (v, i, arr) { 17 | return v + v; 18 | }); 19 | console.log(m); 20 | ``` 21 | -------------------------------------------------------------------------------- /1-前端框架与库/React/基础/高阶组件.md: -------------------------------------------------------------------------------- 1 | ### 什么是高阶组件,它有哪些运用? 2 | 3 | 高阶组件就是一个函数,接收一个组件,经过处理后返回后的新的组件; 4 | 高阶组件,不是真正意义上的组件,其实是一种模式; 5 | 可以对逻辑代码进行抽离,或者添加某个共用方法; 6 | eg: 7 | 8 | - react-redux :connect 就是一个高阶组件,接收一个 component,并返回一个新的 componet,处理了监听 store 和后续的处理; 9 | - react-router :withrouter 为一个组件注入 history 对象; 10 | 11 | ### 高阶组件和父组件的区别? 12 | 13 | 高阶组件可以重写传入组件的 state,function,props;可以对代码逻辑进行抽离,重写; 14 | 父组件只是控制子组件的 view 层; 15 | 16 | ### redux connect 函数 17 | 18 | TODO 19 | -------------------------------------------------------------------------------- /知识模型.md: -------------------------------------------------------------------------------- 1 | ## 知识模型 2 | 3 | ### 有良好的计算机专业基础 4 | 5 | ##### 有扎实的编码能力且熟悉经典算法与常用数据结构 6 | 7 | - [leet code 初级算法](https://leetcode-cn.com/leetbook/read/top-interview-questions-easy/x2gy9m/) 8 | 9 | ##### 掌握基础的计算机网络知识 10 | 11 | ### 掌握必要的前端基础知识 12 | 13 | - Html 14 | - Css 15 | - Javascript 16 | - React 17 | - Vue 18 | - typescript 19 | 20 | ### 有基本的工程化能力 21 | 22 | 一切能提升前端开发效率,提高前端应用质量的手段和工具都是前端工程化。 23 | 24 | - webpack 25 | - 性能优化 26 | - 测试 27 | 28 | ### 知道常见场景的解决方案 -------------------------------------------------------------------------------- /5-性能优化/SEO.md: -------------------------------------------------------------------------------- 1 | ### 前端需要注意哪些 SEO 2 | 3 | 1. 合理的 title、description、keywords:搜索对着三项的权重逐个减小,title 值强调重点即可,重要关键词出现不要超过 2 次,而且要靠前,不同页面 title 要有所不同;description 把页面内容高度概括,长度合适,不可过分堆砌关键词,不同页面 description 有所不同;keywords 列举出重要关键词即可 4 | 2. 语义化的 HTML 代码,符合 W3C 规范:语义化代码让搜索引擎容易理解网页 5 | 3. 重要内容 HTML 代码放在最前:搜索引擎抓取 HTML 顺序是从上到下,有的搜索引擎对抓取长度有限制,保证重要内容一定会被抓取 6 | 4. 重要内容不要用 js 输出:爬虫不会执行 js 获取内容 7 | 5. 少用 iframe:搜索引擎不会抓取 iframe 中的内容 8 | 6. 非装饰性图片必须加 alt 9 | 7. 提高网站速度:网站速度是搜索引擎排序的一个重要指标 10 | -------------------------------------------------------------------------------- /3-编程能力/编程题与分析题/reduce案例.js: -------------------------------------------------------------------------------- 1 | var array = [ 2 | { 3 | selector: "sss", 4 | rules: "rrrr", 5 | }, 6 | { 7 | selector: "sss2", 8 | rules: "rrr3", 9 | }, 10 | ]; 11 | 12 | function transform(array, key, value) { 13 | return array.reduce((obj, item) => { 14 | obj[item[key]] = (obj[item[key]] || []).concat(item[value]); 15 | return obj; 16 | }, {}); 17 | } 18 | 19 | var tree = transform(array, "selector", "rules"); 20 | 21 | console.log(tree); 22 | -------------------------------------------------------------------------------- /5-性能优化/性能测试.md: -------------------------------------------------------------------------------- 1 | # 性能测试 2 | 3 | ## 测试性能工具 4 | 5 | Chrome 已经提供了一个大而全的性能测试工具 Audits。 6 | ![audits](../../img/aduits.png) 7 | 8 | 选择想测试的功能然后点击 Run audits ,工具就会自动运行帮助我们测试问题并且给出一个完整的报告。 9 | ![报告](../../img/aduitsReport.png) 10 | 11 | 可以看到报告中分别为**性能、体验、SEO** 都给出了打分,并且每一个指标都有详细的评估。 12 | 13 | 评估结束后,工具还提供了一些建议便于我们提高这个指标的分数。 14 | ![建议](../../img/auditsSuggest.png) 15 | 16 | 还有一个 Performance 工具也可以供我们使用。 17 | ![performance](../../img/performance.png) 18 | 在这张图中,我们可以详细的看到每个时间段中浏览器在处理什么事情,哪个过程最消耗时间,便于我们更加详细的了解性能瓶颈。 19 | -------------------------------------------------------------------------------- /1-前端框架与库/React/react-script.md: -------------------------------------------------------------------------------- 1 | # react-script 2 | 3 | 使用`create-react-app`生成的 React 项目是使用`react-script`来运行的,其 package.json 如下: 4 | 5 | ```json 6 | "scripts": { 7 | "start": "react-scripts start", 8 | "build": "react-scripts build", 9 | "test": "react-scripts test", 10 | "eject": "react-scripts eject" 11 | }, 12 | ``` 13 | 14 | ### 源代码 15 | 16 | 命令行相关代码入口位于:`/node_modules/react-scripts/bin/react-scripts.js`,其对应的几个脚本都在`scripts`文件夹中 17 | 18 | ### eject 19 | 20 | 将 react-script 的所有封装内容释放回项目根目录 21 | -------------------------------------------------------------------------------- /3-编程能力/编程题与分析题/实现flatten函数.md: -------------------------------------------------------------------------------- 1 | ## 实现 flatten 函数 2 | 3 | ```js 4 | let arr = [1, 2, [3, 4, 5, [6, 7], 8], 9, 10, [11, [12, 13]]]; 5 | ``` 6 | 7 | ### 迭代版 8 | 9 | 每次拿数组的第一个元素,当判断第一个元素是数组的时候,使用`arrs.unshift(...item)`来 10 | 11 | ```js 12 | function flatten(arr) { 13 | let arrs = [...arr]; 14 | let newArr = []; 15 | while (arrs.length) { 16 | let item = arrs.shift(); 17 | if (Array.isArray(item)) { 18 | arrs.unshift(...item); 19 | } else { 20 | newArr.push(item); 21 | } 22 | } 23 | return newArr; 24 | } 25 | ``` 26 | -------------------------------------------------------------------------------- /1-前端框架与库/Webpack/基本概念/plugins.md: -------------------------------------------------------------------------------- 1 | # plugins 2 | 3 | 使用`plugins`让打包变的便捷,可以在 webpack 打包的某时刻帮做一些事情,他很像一个生命周期函数 4 | 5 | ### html-webpack-plugin 6 | 7 | html-webpack-plugin 会在打包结束后,自动生成一个 html 文件,并把打包生成的 js 自动引入到 HTML 中。 8 | 可以给这个 html 制定一个模板 9 | 10 | ```js 11 | const HtmlWebpackPlugin = require('html-webpack-plugin') 12 | // 插件 13 | plugins: [ 14 | new HtmlWebpackPlugin({ 15 | template: 'src/index.html' 16 | }) 17 | ], 18 | ``` 19 | 20 | ### [clean-webpack-plugin](https://github.com/johnagan/clean-webpack-plugin) 21 | 22 | 帮助打包时先清空 dist 目录 23 | -------------------------------------------------------------------------------- /0-前端基础/CSS/布局/Flex.md: -------------------------------------------------------------------------------- 1 | # Flex 布局 2 | 3 | ## `flex: 1 0 auto`是什么? 4 | 5 | 三个参数分别对应的是 `flex-grow`, `flex-shrink` 和 `flex-basis`,默认值为 `0 1 auto`。 6 | 7 | 即: `flex: 1 0 auto`指尽可能放大元素且默认宽度之和大于容器时也不收缩 8 | 9 | 效果参考: https://codepen.io/welovewebdesign/pen/gKnBC 10 | 11 | ## 属性 12 | 13 | ### flex-grow 14 | 15 | flex-grow 定义项目的放大比例,默认为 0,即如果存在剩余空间,也不放大 16 | 17 | ### flex-shrink 18 | 19 | flex-shrink 属性指定了 flex 元素的缩小比例,默认为 1。flex 元素仅在默认宽度之和大于容器的时候才会发生收缩,其收缩的大小是依据 flex-shrink 的值。 20 | 21 | ### flex-basis 22 | 23 | flex-basis 给上面两个属性分配多余空间之前, 计算项目是否有多余空间, 默认值为 auto, 即项目本身的大小 24 | -------------------------------------------------------------------------------- /杂项/面试/README.md: -------------------------------------------------------------------------------- 1 | ### 如何看待面试 2 | 3 | 考官与考生面对面交谈与观察为主要手段,测评考生的知识、能力、经验等有关素质的考试活动。 4 | 5 | ### 考察重点 6 | 7 | 校招考察的主要是能力和知识,经验是很少的。 8 | 9 | ### 项目问题 10 | 11 | 出现了什么问题,是怎么解决的 12 | 13 | ### 面试环节 14 | 15 | - 一面 16 | - 基础知识 17 | - 围绕知识点进行考察 18 | - 二三面 19 | - 基础上的衍生 20 | - 考察原理 21 | - 让学生 show 一下自己研究的东西 22 | - 三四面 23 | - 负责人的考察 24 | - 整体能力 25 | - HR 面 26 | - 具有一票否决权 27 | - 沟通、性格、潜力 28 | 29 | ### 职位描述分析 30 | 31 | 根据面试时的职位描述来分析面试官会考察你哪些内容。 32 | 33 | ### 技术栈 34 | 35 | 不会的、不熟悉的就不要画蛇添足 36 | 37 | ### 态度 38 | 39 | - 谦虚 40 | - 内心诚实 41 | - 回答灵活 42 | - 回答不要咬定 43 | 44 | -------------------------------------------------------------------------------- /杂项/面试/自我介绍.md: -------------------------------------------------------------------------------- 1 | ## 简历 2 | 3 | - 基本信息、姓名、年龄、手机、邮箱、博客、籍贯 4 | - 学历 5 | - 工作经历,实践-公司-岗位-指责-技术栈-业绩 6 | - 开源项目,Github 说明 7 | 8 | ## 自我陈述 9 | 10 | - 把握面试的沟通方向 11 | - 豁达、自信的适度发挥 12 | 13 | 有的点自己是认证准备过的,当你秀这个的时候不要膨胀,是要面试官欣赏你就够了,你如果在某方面还显得鄙视面试官那就完了。 14 | 15 | ## 回答问题 16 | 17 | 当沿着一个问题问下去,碰到一个自己不会的问题的时候你要说请面试官指点启发一下,或者说我回去思考一下。不要说不懂算了,他会觉得你对技术没有追求。 18 | 19 | 面试时问题会有难有简单,刚开始问简单的问题时不要觉得不屑,一定要把节奏放的平缓。 20 | 21 | 切忌小聪明,要谦虚 22 | 23 | 聊的方向要对,聊项目时越细越好 24 | 25 | 碰到难题不要胆怯,好好思考,不要动不动说不会,要去猜、去思考,心态要平和 26 | 27 | 连续碰到几个答不上来的自己一定不要消极,要积极一些,不然面试官更没有兴趣来和你聊。 28 | 29 | 难度大的面试就算过不了,也要提一些疑问,请教一下,争取在这场面试里收获点什么。 问问面试官应该看哪些资料补一下这些知识点,然后问问补完了是不是还可以再来投这个岗位。 30 | -------------------------------------------------------------------------------- /2-计算机基础/操作系统/README.md: -------------------------------------------------------------------------------- 1 | # 操作系统 2 | 3 | 参考资源:https://frank-lam.github.io/fullstack-tutorial/#/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F 4 | 5 | ### CPU 组成 6 | 7 | CPU 是由运算器和控制器这两个部分组成的。 8 | 9 | 1、运算器由算术逻辑单元(ALU)、累加器、状态寄存器、通用寄存器组等组成。算术逻辑运算单元(ALU)的基本功能为加、减、乘、除四则运算,与、或、非、异或等逻辑操作,以及移位、求补等操作。 10 | 11 | 计算机运行时,运算器的操作和操作种类由控制器决定。运算器处理的数据来自存储器;处理后的结果数据通常送回存储器,或暂时寄存在运算器中。与 Control Unit 共同组成了 CPU 的核心部分。 12 | 13 | 2、控制器分组合逻辑控制器和微程序控制器,两种控制器各有长处和短处。组合逻辑控制器设计麻烦,结构复杂,一旦设计完成,就不能再修改或扩充,但它的速度快。 14 | 15 | 微程序控制器设计方便,结构简单,修改或扩充都方便,修改一条机器指令的功能,只需重编所对应的微程序; 16 | 17 | 要增加一条机器指令,只需在控制存储器中增加一段微程序,但是,它是通过执行一段微程。具体对比如下:组合逻辑控制器又称硬布线控制器,由逻辑电路构成,完全靠硬件来实现指令的功能。 18 | -------------------------------------------------------------------------------- /实用工具与库/decorateComponentWithProps.md: -------------------------------------------------------------------------------- 1 | # decorateComponentWithProps 2 | 3 | 一个简单的工具函数包装你的组件,让它得到额外的参数。 4 | 5 | github: https://github.com/belle-ui/decorateComponentWithProps 6 | 7 | ### 源码 8 | 9 | ```jsx 10 | const decorateComponentWithProps = (EmbeddedComponent, props) => (class extends Component { 11 | render() { 12 | return ( 13 | 14 | ); 15 | } 16 | }); 17 | ``` 18 | 19 | ### 用法 20 | ```ts 21 | const props = { 22 | wine: 'red', 23 | beer: 'ipa', 24 | food: 'spaghetti', 25 | }; 26 | 27 | MyDecoratedComponent = decorateComponentWithProps(MyComponent, props); 28 | ``` -------------------------------------------------------------------------------- /1-前端框架与库/Webpack/基本概念/安装.md: -------------------------------------------------------------------------------- 1 | ## 安装 webpack 2 | 3 | 在项目中安装 4 | 5 | ``` 6 | npm install webpack webpack-cli --save-dev 7 | ``` 8 | 9 | 是否全局安装? 10 | 11 | 如果电脑上有两个项目,一个 webpack3 打包,一个 webpack4 打包。安装后可能导致你 webpack3 的项目无法打包,所以一般都是项目内安装。 12 | 13 | ### webpack-cli 14 | 15 | 使得可以在命令行里使用 webpack 16 | 17 | ### npx 18 | 19 | 项目内安装 webpack 后,直接在终端输入`webpack -v`是不可以的,但是使用`npx webpack -v`就可以。 20 | 21 | ``` 22 | $ webpack -v 23 | > bash: webpack: command not found 24 | $ npx webpack -v 25 | > 4.35.0 26 | ``` 27 | 28 | 这是因为`npx`这个命令可以帮助我们在当前项目的`node_modules`中查找对应的包。 29 | 30 | ### 安装制定版本 webpack 31 | 32 | `npm install webpack@4.16.5 -D` 在包名后加‘@’再加版本号 33 | 查看某包信息,可以运行 `npm info webpack` 34 | -------------------------------------------------------------------------------- /1-前端框架与库/React/Hooks/组件复用例子/hooks.jsx: -------------------------------------------------------------------------------- 1 | function useSize() { 2 | const [size, setSize] = useState([window.innerWidth, window.innerHeight]); 3 | 4 | useEffect(() => { 5 | document.title = size.join("x"); 6 | }); 7 | 8 | const onResize = () => { 9 | setSize([window.innerWidth, window.innerHeight]); 10 | }; 11 | 12 | useEffect(() => { 13 | window.addEventListener("resize", onResize); 14 | return () => { 15 | window.removeEventListener("resize", onResize); 16 | }; 17 | }); 18 | return size; 19 | } 20 | 21 | function App() { 22 | const [width, height] = useSize(); 23 | return ( 24 |
25 | {width} x {height} 26 |
27 | ); 28 | } 29 | -------------------------------------------------------------------------------- /1-前端框架与库/React/Hooks/自定义 hooks.md: -------------------------------------------------------------------------------- 1 | ### 自定义 hooks 2 | 3 | 因为可以自定义 Hooks, 我们可以非常方便的复用状态逻辑。 4 | 5 | ```jsx 6 | // 定时器DEMO 7 | function useCount(defaultCount) { 8 | const [count, setCount] = useState(defaultCount); 9 | const timer = useRef(); 10 | 11 | useEffect(() => { 12 | timer.current = setInterval(() => { 13 | setCount((count) => count + 1); 14 | }, 1000); 15 | }, []); 16 | 17 | useEffect(() => { 18 | if (count >= 10) { 19 | clearInterval(timer.current); 20 | } 21 | }); 22 | return [count]; 23 | } 24 | 25 | function App() { 26 | const [count] = useCount(0); 27 | return ( 28 | <> 29 |

count: {count}

30 | 31 | ); 32 | } 33 | ``` 34 | -------------------------------------------------------------------------------- /4-质量保障/监控/错误监控.md: -------------------------------------------------------------------------------- 1 | ### 前端错误的分类 2 | 3 | - 资源加载错误 4 | - 代码运行错误 5 | 6 | ### 错误的捕获方式 7 | 8 | 即时运行错误的捕获方式 9 | 10 | - try - catch 11 | - window.onerror 12 | 13 | 资源加载错误 14 | 15 | - object.onerror 16 | - image 标签、script 标签上都可以加 onerror 事件 17 | - 资源加载错误不会冒泡,但会捕获 18 | - performance.getEntries() 19 | - 获取所有已经加载资源的获取时长 20 | - window 对象上通过事件捕获 Error 事件 21 | 22 | 注: addEventLitener('事件类型', function(e){ /_回调函数_/ },捕获 true 或冒泡 false ) 23 | 24 | 一般情况下错误监控都是在捕获的阶段进行。 25 | 26 | ### 跨域的 JS 运行错误 27 | 28 | 因为了,只知道错误,但是无法定位错误信息 29 | 解决方法: 30 | 31 | 1. 客户端,在 script 标签上增加 crossorigin 属性 32 | 2. 服务端,设置 JS 资源响应头 `Access-Control-Allow-Origin: *` 33 | 34 | ### 上报错误信息 35 | 36 | 1. 采用 Ajax 通信上报 37 | 2. 利用 image 对象的 src 属性上报 38 | -------------------------------------------------------------------------------- /1-前端框架与库/React/基础/memo.md: -------------------------------------------------------------------------------- 1 | # memo 2 | 3 | 在类组件中,我们使用`shouldComponentUpdate`来比避免不需要的渲染 4 | 5 | ```JSX 6 | // 使用 shouldComponentUpdate 7 | class Foo { 8 | shouldComponentUpdate(nextProps,nextState) { 9 | if(nextProps.SOME_VALUE === this.props.SOME_VALUE){ 10 | return false 11 | } 12 | return true; 13 | } 14 | render () { 15 | return
{props.SOME_VALUE}
16 | } 17 | } 18 | // 或者直接继承 PureComponent 19 | class Foo extends PureComponent { 20 | render () { 21 | return
{props.SOME_VALUE}
22 | } 23 | } 24 | ``` 25 | 26 | ## 函数组件使用 memo 27 | 28 | 函数组件未来避免比必要更新 29 | 30 | ```jsx 31 | const Foo = memo(function (props) { 32 | return
{props.SOME_VALUE}
; 33 | }); 34 | ``` 35 | -------------------------------------------------------------------------------- /0-前端基础/NodeJS/核心模块/process.md: -------------------------------------------------------------------------------- 1 | # [process](http://nodejs.cn/api/process.htm) 2 | 3 | ### process.cwd() 4 | 5 | cwd()方法可以获得当前执行的路径。和 linux 下的 cwd 一样 6 | 7 | ### process.argv 8 | 9 | `process.argv` 属性返回一个数组,其中包含当启动 Node.js 进程时传入的命令行参数。 10 | 11 | - 数组第一个元素为:node 所安装的路径 12 | - 数组第二个元素为:当前执行文件的路径 13 | - 剩余元素为执行 node 命令时传入的参数 14 | 15 | ### process.argv0 16 | 17 | 保存了 process.argv 数组的第一个值的*引用*,不常用 18 | 19 | ### process.execArgv 20 | 21 | process.execArgv 属性返回当 Node.js 进程被启动时,Node.js 特定的命令行选项(位于 node 后,文件名之前)。 这些选项在 process.argv 属性返回的数组中不会出现。 22 | 23 | ### process.execPath 24 | 25 | 返回启动 Node.js 进程的可执行文件的绝对路径名。基本就是 process.argv 的第一个参数 26 | 27 | ### process.env 28 | 29 | process.env 属性返回包含用户环境的对象。 30 | 31 | #### process.env.PATH 32 | -------------------------------------------------------------------------------- /3-编程能力/编程题与分析题/两任务并行.md: -------------------------------------------------------------------------------- 1 | 要求任务并行完成,同时并行的任务不能超过两个。 2 | 3 | ```js 4 | class Scheduler { 5 | add(promiseCreator) { 6 | // 需要实现 7 | } 8 | } 9 | const timeout = (time) => 10 | new Promise((resolve) => { 11 | console.log("in timeout:", time); 12 | setTimeout(resolve, time); 13 | }); 14 | 15 | const scheduler = new Scheduler(); 16 | 17 | const addTask = (time, order) => { 18 | scheduler.add(() => timeout(time)).then(() => console.log(order)); 19 | }; 20 | 21 | addTask(1000, "1"); 22 | addTask(500, "2"); 23 | addTask(300, "3"); 24 | addTask(400, "4"); 25 | // output: 2 3 1 4 26 | // 一开始,1、2 两个任务进入队列 27 | // 500ms 时,2 完成,输出 2,任务 3 进队 28 | // 800ms 时,3 完成,输出 3,任务 4 进队 29 | // 1000ms 时,1 完成,输出 1 30 | // 1200ms 时,4 完成,输出 4 31 | ``` 32 | -------------------------------------------------------------------------------- /0-前端基础/CSS/动画/transition.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 01-transition 8 | 22 | 23 | 24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /1-前端框架与库/Webpack/基本概念/entry 和 output.md: -------------------------------------------------------------------------------- 1 | # entry 和 output 2 | 3 | ## 入口(entry) 4 | 5 | 入口起点(entry point)指示 webpack 应该使用哪个模块,来作为构建其内部 依赖图(dependency graph) 的开始。进入入口起点后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的。 6 | 7 | entry 可以传入一个字符串或者一个字符串数组. 8 | 9 | 向 entry 属性传入文件路径数组,将创建出一个 多主入口(multi-main entry)。在你想要一次注入多个依赖文件,并且将它们的依赖导向(graph)到一个 chunk 时,这种方式就很有用。 10 | 11 | - [入口和上下文(entry and context)](https://webpack.docschina.org/configuration/entry-context/) 12 | 13 | 多入口 14 | 15 | - [webpack 多入口文件页面打包配置](https://juejin.im/post/6844903545922158599) 16 | 17 | ## 出口(output) 18 | 19 | output 属性告诉 webpack 在哪里输出它所创建的 bundle,以及如何命名这些文件。 20 | 21 | 详细配置: https://webpack.docschina.org/configuration/output/ 22 | 23 | - [filename](https://webpack.docschina.org/configuration/output/#outputfilename) 24 | -------------------------------------------------------------------------------- /3-编程能力/算法/树的遍历/深度优先遍历.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 递归式深度遍历tree 3 | */ 4 | function deepTravel(tree, nodeList = []) { 5 | if (tree) { 6 | nodeList.push(tree); 7 | for (let i of Object.keys(tree.children)) { 8 | deepTravel(tree.children[i], nodeList); 9 | } 10 | } 11 | return nodeList; 12 | } 13 | 14 | /** 15 | * 非递归式 遍历tree 16 | * 17 | * 使用:栈 18 | * 但入栈时是反着把 children 数组 push 入栈的,保证下一次 pop 能拿到左子树元素 19 | */ 20 | function deepTravel(tree) { 21 | let stack = []; 22 | let nodeList = []; 23 | tree && stack.push(tree); 24 | //注意,这里如果 while(stack) 会死循环 25 | while (stack.length) { 26 | let node = stack.pop(); 27 | nodeList.push(node); 28 | for (let i = node.children.length - 1; i >= 0; i--) { 29 | stack.push(node.children[i]); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /0-前端基础/CSS/居中元素/水平居中/center1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 水平元素居中 8 | 9 | 22 | 23 |
24 |
25 | 如果需要居中的元素为常规流中 inline / inline-block 元素,为父元素设置 26 | text-align: center; 27 |
28 |
29 | 30 | 31 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "web-knowledge", 3 | "version": "1.0.0", 4 | "description": "github 链接:[webKnowledge](https://github.com/huyaocode/webKnowledge)", 5 | "main": "index.js", 6 | "scripts": { 7 | "pretter": "prettier --write ." 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/huyaocode/webKnowledge.git" 12 | }, 13 | "keywords": [], 14 | "author": "", 15 | "license": "MIT", 16 | "bugs": { 17 | "url": "https://github.com/huyaocode/webKnowledge/issues" 18 | }, 19 | "homepage": "https://github.com/huyaocode/webKnowledge#readme", 20 | "devDependencies": { 21 | "husky": "^4.2.5", 22 | "prettier": "2.0.5" 23 | }, 24 | "dependencies": { 25 | "husky": "^4.2.5", 26 | "lint-staged": "^10.2.2" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /0-前端基础/CSS/居中元素/垂直居中/center2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 垂直居中 8 | 9 | 22 | 23 |
24 | 要求原生有固定的宽高。
25 | position: absolute;
26 | top 为 calc(50% 剪 一半高) left 为 calc(50% 剪 一半宽) 27 |
28 | 29 | 30 | -------------------------------------------------------------------------------- /0-前端基础/CSS/居中元素/水平居中/center2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 水平元素居中 8 | 9 | 24 | 25 |
26 |
27 | 父元素上设置 text-align: center;
28 | 居中元素上margin 为 auto。 29 |
30 |
31 | 32 | 33 | -------------------------------------------------------------------------------- /3-编程能力/编程题与分析题/name的值是多少.md: -------------------------------------------------------------------------------- 1 | ## 下面的代码会输出什么? 2 | 3 | ```js 4 | function A(name) { 5 | this.name = name || "Tom"; 6 | this.msg = "use 'this.' set in function"; 7 | } 8 | 9 | function B() {} 10 | B.prototype = A; 11 | 12 | var b = new B(); 13 | 14 | console.log(b.name); 15 | console.log(b.msg); 16 | ``` 17 | 18 | 答案是: 19 | 20 | ``` 21 | A 22 | undefined 23 | ``` 24 | 25 | ### 分析 26 | 27 | `b.name`返回 `A`,是因为`b`上面没有`name`属性,他就会沿着原型链向上查找,然而 `b.__proto__` 为`函数A`,每一个函数都有一个属性为 name,其值是函数的名字。 28 | 29 | ```js 30 | function abc() { 31 | /* 这是一个名为'abc'的函数 */ 32 | } 33 | abc.name; // -> 'abc' 34 | ``` 35 | 36 | `b.msg` 为什么是`undefined`哪? 因为`b.__proto__` 是 `函数A`,那怎么修改才能拿到`msg`哪? 37 | 38 | ```js 39 | B.prototype = new A(); 40 | ``` 41 | 42 | 修改后的输出: 43 | 44 | ``` 45 | Tom 46 | VM731:12 use 'this.' set in function 47 | ``` 48 | -------------------------------------------------------------------------------- /1-前端框架与库/React/基础/PureComponent与Component区别.md: -------------------------------------------------------------------------------- 1 | # [何时使用 Component 还是 PureComponent?](https://segmentfault.com/a/1190000014979065) 2 | 3 | 参考链接:https://segmentfault.com/a/1190000014979065 4 | 5 | PureComponent 通过 prop 和 state 的浅比较来实现 shouldComponentUpdate,某些情况下可以用 PureComponent 提升性能 6 | 7 | 所谓浅比较(shallowEqual),即 react 源码中的一个函数,然后根据下面的方法进行是不是 PureComponent 的判断,帮我们做了本来应该我们在 shouldComponentUpdate 中做的事情 8 | 9 | ```js 10 | if (this._compositeType === CompositeTypes.PureClass) { 11 | shouldUpdate = 12 | !shallowEqual(prevProps, nextProps) || !shallowEqual(inst.state, nextState); 13 | } 14 | ``` 15 | 16 | ```js 17 | shouldComponentUpdate(nextProps, nextState) { 18 | return (nextState.person !== this.state.person); 19 | } 20 | ``` 21 | 22 | ### 什么时候不该用? 23 | 24 | PureComponent 中的判断逻辑是浅比较,如果当状态更新时是一个引用对象内部的更新,那么这个时候是不适用的 25 | -------------------------------------------------------------------------------- /1-前端框架与库/React/Hooks/组件复用例子/class.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * 最传统类组件 3 | */ 4 | 5 | class Foo extends React.Component { 6 | state = { 7 | size: [window.innerWidth, window.innerHeight], 8 | }; 9 | 10 | onResize = () => { 11 | this.setState({ size: [window.innerWidth, window.innerHeight] }); 12 | }; 13 | 14 | componentDidMount() { 15 | window.addEventListener("resize", onResize); 16 | document.title = this.state.size.join("x"); 17 | } 18 | 19 | componentWillUnmount() { 20 | window.removeEventListener("resize", onResize); 21 | } 22 | 23 | componentDidUpdate() { 24 | document.title = this.state.size.join("x"); 25 | } 26 | 27 | render() { 28 | const [width, height] = this.state.size; 29 | return ( 30 |
31 | {width} x {height} 32 |
33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /2-计算机基础/操作系统/进程与线程.md: -------------------------------------------------------------------------------- 1 | ## 1. 进程 2 | 3 | 进程是**资源分配**的基本单位,用来管理资源(例如:内存,文件,网络等资源) 4 | 5 | 进程控制块 (Process Control Block, PCB) 描述进程的基本信息和运行状态,所谓的创建进程和撤销进程,都是指对 PCB 的操作。(PCB 是描述进程的数据结构) 6 | 7 | ## 2. 线程 8 | 9 | 线程是**独立调度**的基本单位。 10 | 11 | 一个进程中可以有多个线程,它们共享进程资源。 12 | 13 | QQ 和浏览器是两个进程,浏览器进程里面有很多线程,例如 HTTP 请求线程、事件响应线程、渲染线程等等,线程的并发执行使得在浏览器中点击一个新链接从而发起 HTTP 请求时,浏览器还可以响应用户的其它事件。 14 | 15 | ## 3. 区别 16 | 17 | ### (一)拥有资源 18 | 19 | 进程是资源分配的基本单位,但是线程不拥有资源,线程可以访问隶属进程的资源。 20 | 21 | ### (二)调度 22 | 23 | 线程是独立调度的基本单位,在同一进程中,线程的切换不会引起进程切换,从一个进程内的线程切换到另一个进程中的线程时,会引起进程切换。 24 | 25 | ### (三)系统开销 26 | 27 | 由于创建或撤销进程时,系统都要为之分配或回收资源,如内存空间、I/O 设备等,所付出的开销远大于创建或撤销线程时的开销。类似地,在进行进程切换时,涉及当前执行进程 CPU 环境的保存及新调度进程 CPU 环境的设置,而线程切换时只需保存和设置少量寄存器内容,开销很小。 28 | 29 | ### (四)通信方面 30 | 31 | 进程间通信 (IPC) 需要进程同步和互斥手段的辅助,以保证数据的一致性。而线程间可以通过直接读/写同一进程中的数据段(如全局变量)来进行通信。 32 | -------------------------------------------------------------------------------- /实用工具与库/Formik/README.md: -------------------------------------------------------------------------------- 1 | # Formik 2 | 3 | - [Formik 官网](https://formik.org/) 4 | 5 | Formik 是 React 中构建表单时所用的库,它可以做以下 3 件事: 6 | 7 | 1. 在 Form 的内外都可获取 Form 的 State 8 | 2. 在验证表单时管理错误信息 9 | 3. 处理 Form 的提交操作 10 | 11 | 主要组件有如下: 12 | 13 | - `` 14 | - 构建整个表单的顶层组件,通过自身的 state 维护表单状态(2.0 版本采用 useReducer 维护),收集表单字段,执行校验和提交表单等操作,通过 render 函数或者 children 的方式往下传递 props,使得子组件具备完全访问和控制表单状态的能力; 15 | - `
` 16 | - 是对``标签的简单封装,监听了 form 的 onReset 和 onSubmit 事件; 17 | - `` 18 | - 通过指定 name 属性与 formik 表单状态中具体某个字段建立「同步关系」,这个组件帮我们省去了很多对受控组件的更新操作,如 onChange、onBlur 事件的监听和回调处理。``组件默认渲染为一个 input,同时也可以通过 render 属性或者 children 的方式渲染自己的字段组件,如 select,checkbox,textarea 等。 19 | - `` 20 | - 这个组件可以对一个数组字段进行维护,通过其提供的 props 方法中的 insert 或者 remove 可以方便的增删表单中的某个数组字段里的元素,在进行动态控制表单字段方面很方便,具体示例可以参考后面的多语言输入框的实现。 21 | -------------------------------------------------------------------------------- /2-计算机基础/网络/nginx.md: -------------------------------------------------------------------------------- 1 | # nginx 代理 2 | 3 | ### nginx 基本代理 4 | 5 | ``` 6 | server { 7 | listen 80; 8 | # 访问的域名 9 | server_name test.com; 10 | # 代理请求 11 | location / { 12 | proxy_pass http://127.0.0.1:8888; 13 | # 设置HTTP头中修改host为test.com 14 | proxy_set_header Host $host; 15 | } 16 | } 17 | ``` 18 | 19 | ### nginx 配置缓存 20 | 21 | ``` 22 | # 写在server外 23 | proxy_cache_path cache levels=1:2 keys_zoom=my_cache:10m 24 | ``` 25 | 26 | - cache 27 | - 文件夹名 28 | - levels=1:2 29 | - 设置二级文件夹来存缓存,因为随着文件的越来越多查找速度会越来越慢 30 | - keys_zoom=my_cache:10m 31 | - 申请 10 兆内存来缓存内容 32 | 33 | ``` 34 | server { 35 | listen 80; 36 | server_name test.com; 37 | location / { 38 | proxy_cache my_cache; #在这里写缓存 39 | proxy_pass http://127.0.0.1:8888; 40 | proxy_set_header Host $host; 41 | } 42 | } 43 | ``` 44 | -------------------------------------------------------------------------------- /0-前端基础/CSS/居中元素/垂直居中/center3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 垂直居中 8 | 9 | 23 | 24 |
25 | 不要求原生有固定的宽高。
26 | position: absolute;
27 | top和left 为 50%;
28 | transform: translate(-50%, -50%); 29 |
30 | 31 | 32 | -------------------------------------------------------------------------------- /0-前端基础/CSS/居中元素/水平居中/center4.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 水平元素居中 8 | 9 | 24 | 25 |
26 |
27 | 如果元素positon: relative。 那么 1)为元素设置宽度,2)偏移量设置为 28 | 50%,3)偏移方向外边距设置为元素宽度一半乘以-1 29 |
30 |
31 | 32 | 33 | -------------------------------------------------------------------------------- /3-编程能力/编程题与分析题/手写Promise.md: -------------------------------------------------------------------------------- 1 | # 手写 Promise 2 | 3 | 先看看 Promise 是怎么用的 4 | 5 | ```js 6 | new MyPromise((resolve, reject) => { 7 | setTimeout(() => { 8 | console.log("第一个 resolve"); 9 | resolve(1); 10 | }, 1000); 11 | }) 12 | .then((res) => { 13 | // 返回一个Promise对象 14 | return new Promise((resolve, reject) => { 15 | setTimeout(() => { 16 | console.log("第二个 resolve"); 17 | resolve(res + 2); 18 | }, 2000); 19 | }); 20 | }) 21 | .then((res) => { 22 | console.log(res); 23 | }); 24 | ``` 25 | 26 | 文章: [Promise 实现原理](https://juejin.im/post/5b83cb5ae51d4538cc3ec354) 27 | 28 | 这篇文章是我在掘金上找到一篇高赞,但是很多地方没搞懂,比如 .then 函数直接返回一个 新的 Promise 对象,但是这里面用一个数组来存储即将调用的 then 函数,但调试发现这个数组(\_fulfilledQueues)最多只含一个函数。github 上有 es6-promise 的 源码,但实话写的很复杂。 29 | 30 | // TODO- 等我空了好好理一理逻辑 31 | 32 | ## [pormise 完整代码](./promise.js) 33 | -------------------------------------------------------------------------------- /3-编程能力/编程题与分析题/尽早按序打印Ajax请求.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 接受一个URL数组做参数,并行请求,尽可能块的按照顺序打印内容 3 | */ 4 | 5 | const urlList = [1, 2, 3, 4, 5]; 6 | 7 | loadData(urlList); 8 | 9 | function fetchData(url, succCallback) { 10 | setTimeout(() => { 11 | succCallback("ok: " + url); 12 | }, (Math.random() * 5 * 1000) >> 0); 13 | } 14 | 15 | function loadData(urlList) { 16 | let resArr = [], 17 | doneId = 0; 18 | for (let i = 0; i < urlList.length; i++) { 19 | fetchData(urlList[i], (res) => { 20 | console.log(`${i + 1} has done`); 21 | resArr[i] = res; 22 | outPutRes(resArr); 23 | }); 24 | } 25 | function outPutRes(resArr) { 26 | for (let i = doneId; i < resArr.length; i++) { 27 | if (resArr[i]) { 28 | console.log(resArr[i]); 29 | doneId++; 30 | } else { 31 | break; 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /新技术/hybird.md: -------------------------------------------------------------------------------- 1 | # hybrid 2 | 3 | ### hybrid 是什么,为何会使用 hybrid 4 | 5 | hybrid 即"混合",即前端和客户端的混合开发,某些环节也可能涉及 server 端 6 | 7 | hybird 存在的核心意义在于快速迭代,无需审核 8 | 9 | 具体实现: 10 | 11 | - 前端做好静态网页,将文件交给客户端 12 | - 客户端拿到前端静态网页,以文件形式存储在 app 中 13 | - 客户端在一个 webview 中 14 | - 使用 file 协议加载静态页面 15 | 16 | ### 各技术适用场景 17 | 18 | - 使用 NativeApp 19 | - 体验要求极致,变化不频繁 20 | - 使用 hybrid 21 | - 体验要求高,变化频繁 22 | - 使用 h5 -体验要求低,不常用 23 | 24 | ### hybrid 存在价值 25 | 26 | - 可快速迭代更新 27 | - 体验流畅 28 | - 双端公用一套代码 29 | 30 | ### webview 31 | 32 | - 是 app 中的一个组件。 33 | - 用于加载 h5 页面,即小型浏览器内核 34 | - 只是单纯的展示一个网页界面 35 | 36 | ![webview](../../img/webview.png) 37 | 38 | ### file 协议 39 | 40 | 加载本地的资源 41 | ![file](../../img/file.png) 42 | 43 | ### app 发布后,静态文件如何实时更新? 44 | 45 | - 将静态文件(html,css,js 等)压缩成包,上传到服务端 46 | - 客户端每次启动,都去服务端检查静态文件发布日期 47 | - 如果服务端发布日期晚与客户端使用资源的发布日期,就去下载最新的压缩包 48 | - 下载完成后解压,将现有文件覆盖 49 | -------------------------------------------------------------------------------- /0-前端基础/CSS/居中元素/垂直居中/center1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 垂直居中 8 | 9 | 24 | 25 |
26 | 要求原生有固定的宽高。
27 | position: absolute;
28 | top和left 为 50%;
29 | margin上为高的一半
30 | margin左为宽的一半
31 |
32 | 33 | 34 | -------------------------------------------------------------------------------- /1-前端框架与库/Webpack/高级概念/sourcemap.md: -------------------------------------------------------------------------------- 1 | # sourcemap 2 | 3 | Source map 就是一个信息文件,里面储存着位置信息。也就是说,转换后的代码的每一个位置,所对应的转换前的位置。 4 | 5 | 源文件 6 | 7 | ```js 8 | function sayHello(name) { 9 | if (name.length > 2) { 10 | name = name.substr(0, 1) + "..."; 11 | } 12 | console.log("hello,", name); 13 | } 14 | ``` 15 | 16 | 压缩后 17 | 18 | ```js 19 | function sayHello(name) { 20 | if (name.length > 2) { 21 | name = name.substr(0, 1) + "..."; 22 | } 23 | console.log("hello,", name); 24 | } 25 | sayHello("世界"); 26 | sayHello("第三世界的人们"); 27 | ``` 28 | 29 | map 文件 30 | 31 | ```js 32 | {"version":3,"sources":["log.js","main.js"],"names":["sayHello","name","length","substr","console","log"],"mappings":"AAAA,SAASA,SAASC,MACd,GAAIA,KAAKC,OAAS,EAAG,CACjBD,KAAOA,KAAKE,OAAO,EAAG,GAAK,MAE/BC,QAAQC,IAAI,SAAUJ,MCJ1BD,SAAS,MACTA,SAAS"} 33 | ``` 34 | 35 | ### sourcemap 如何映射源文件? 36 | 37 | TODO 38 | -------------------------------------------------------------------------------- /3-编程能力/编程题与分析题/compose.md: -------------------------------------------------------------------------------- 1 | ## 函数式编程 compose 2 | 3 | 实现以下功能: 4 | 5 | ```js 6 | compose([a, b, c])('参数') 7 | => 8 | a( b( c('参数') ) ) 9 | ``` 10 | 11 | ```js 12 | function compose(funcs) { 13 | var len = funcs.length; 14 | var index = len - 1; 15 | 16 | for (let i = 0; i < len; i++) { 17 | if (typeof funcs[i] !== "function") { 18 | throw new TypeError("Expected function"); 19 | } 20 | } 21 | 22 | return function (...args) { 23 | let result = funcs[index](...args); // 第一次 24 | while (--index >= 0) { 25 | result = funcs[index](result); 26 | } 27 | return result; 28 | }; 29 | } 30 | ``` 31 | 32 | 测试: 33 | 34 | ```js 35 | function a(str) { 36 | return `a ${str}`; 37 | } 38 | function b(str) { 39 | return `b ${str}`; 40 | } 41 | function c(str) { 42 | return `c ${str}`; 43 | } 44 | 45 | const abc = compose([a, b, c]); 46 | abc("huyao"); 47 | ``` 48 | -------------------------------------------------------------------------------- /0-前端基础/CSS/居中元素/垂直居中/center4.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 垂直居中 8 | 9 | 27 | 28 |
29 |
30 | 使用flex居中
31 | 父元素 display: flex;
32 | 居中块: margin: auto; 33 |
34 |
35 | 36 | 37 | -------------------------------------------------------------------------------- /0-前端基础/CSS/居中元素/水平居中/center3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 水平元素居中 8 | 9 | 26 | 27 |
28 |
29 | 如果元素positon: absolute; 那么 0)设置父元素postion: relative 30 | 1)为元素设置宽度,2)偏移量设置为 31 | 50%,3)偏移方向外边距设置为元素宽度一半乘以-1 32 |
33 |
34 | 35 | 36 | -------------------------------------------------------------------------------- /0-前端基础/JS/this.md: -------------------------------------------------------------------------------- 1 | # this 2 | 3 | ### this 的指向有哪几种情况? 4 | 5 | this 代表函数调用相关联的对象,通常页称之为执行上下文。 6 | 7 | 1. 作为函数直接调用,非严格模式下,this 指向 window,严格模式下,this 指向 undefined; 8 | 2. 作为某对象的方法调用,this 通常指向调用的对象。 9 | 3. 使用 apply、call、bind 可以绑定 this 的指向。 10 | 4. 在构造函数中,this 指向新创建的对象 11 | 5. 箭头函数没有单独的 this 值,this 在箭头函数创建时确定,它与声明所在的上下文相同。 12 | 13 | ### 如果对一个函数进行多次 bind,那么上下文会是什么呢? 14 | 15 | ```js 16 | let a = {}; 17 | let fn = function () { 18 | console.log(this); 19 | }; 20 | fn.bind().bind(a)(); // => ? 21 | ``` 22 | 23 | 不管我们给函数 bind 几次,fn 中的 this 永远由第一次 bind 决定,所以结果永远是 window。 24 | 25 | ```js 26 | // fn.bind().bind(a) 等于 27 | let fn2 = function fn1() { 28 | return function () { 29 | return fn.apply(); 30 | }.apply(a); 31 | }; 32 | fn2(); 33 | ``` 34 | 35 | ### 多个 this 规则出现时,this 最终指向哪里? 36 | 37 | 首先,new 的方式优先级最高,接下来是 bind 这些函数,然后是 obj.foo() 这种调用方式,最后是 foo 这种调用方式,同时,箭头函数的 this 一旦被绑定,就不会再被任何方式所改变。 38 | ![this](../../img/this.png) 39 | -------------------------------------------------------------------------------- /5-性能优化/testDemo/test-DOMContentLoaded.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 19 |
20 | 内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容 21 |
22 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /0-前端基础/CSS/动画/animation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | animation 8 | 32 | 33 | 34 |
35 | 36 | 37 | -------------------------------------------------------------------------------- /1-前端框架与库/Webpack/高级概念/缓存.md: -------------------------------------------------------------------------------- 1 | # 缓存 2 | 3 | ## webpack 中的 hash、chunkhash、contenthash 区别 4 | 5 | hash 一般是结合 CDN 缓存来使用,通过 webpack 构建之后,生成对应文件名自动带上对应的 MD5 值。如果文件内容改变的话,那么对应文件哈希值也会改变,对应的 HTML 引用的 URL 地址也会改变,触发 CDN 服务器从源服务器上拉取对应数据,进而更新本地缓存。但是在实际使用的时候,这几种 hash 计算还是有一定区别。 6 | 7 | 1. `hash` 8 |    hash 是跟整个项目的构建相关,只要项目里有文件更改,整个项目构建的 hash 值都会更改,并且全部文件都共用相同的 hash 值 9 | 10 | 2. `chunkhash` 11 | 12 | 采用 hash 计算的话,每一次构建后生成的哈希值都不一样,即使文件内容压根没有改变。这样子是没办法实现缓存效果,我们需要换另一种哈希值计算方式,即 chunkhash。 13 |    chunkhash 和 hash 不一样,它根据不同的入口文件(Entry)进行依赖文件解析、构建对应的 chunk,生成对应的哈希值。我们在生产环境里把一些公共库和程序入口文件区分开,单独打包构建,接着我们采用 chunkhash 的方式生成哈希值,那么只要我们不改动公共库的代码,就可以保证其哈希值不会受影响。 14 | 15 | 3. `contenthash` 16 | 17 | 在使用 chunkhash 的例子中,如果 index.css 被 index.js 引用了,那么就会共用相同的 chunkhash 值。但是这样子有个问题,如果 index.js 更改了代码,css 文件就算内容没有任何改变,由于是该模块发生了改变,导致 css 文件会重复构建。 18 | 19 | 这个时候,我们可以使用 extra-text-webpack-plugin 里的 contenthash 值,保证即使 css 文件所处的模块里就算其他文件内容改变,只要 css 文件内容不变,那么不会重复构建。 20 | -------------------------------------------------------------------------------- /0-前端基础/CSS/居中元素/垂直居中/center-in-body.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 垂直居中 8 | 9 | 27 | 28 |
29 |
30 | 基于视口的垂直居中
31 | 不要求原生有固定的宽高。
32 | 但是这种居中是在整个页面窗口内居中,不是基于父元素
33 |
34 |
35 | 36 | 37 | -------------------------------------------------------------------------------- /0-前端基础/CSS/布局/BFC两栏布局.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | BFC自适应两栏布局 8 | 22 | 23 | 24 |
25 |
26 |

BFC 两栏布局

27 |

28 | 左侧块浮动到左边,但是因为是浮动块,右侧块高度一旦超过左侧块后文字就会出现在左侧的下方,因为没有块把它挡住。 29 |

30 |

31 | 解决办法: 32 | 让右侧块变为BFC文字就不会横过去。因为BFC元素不与Float元素相重叠。 33 |

34 |
35 | 36 | 37 | -------------------------------------------------------------------------------- /2-计算机基础/网络/UDP.md: -------------------------------------------------------------------------------- 1 | # UDP 2 | 3 | UDP(User Datagram Protocol),又叫用户数据报协议。 4 | UDP 是一个无连接的、不可靠、基于数据报的传输协议。UDP 只是报文(报文可以理解为一段段的数据)的搬运工,不会对报文进行任何拆分和拼装操作。 5 | 6 | 具体来说 7 | 8 | - 在发送端,应用层将数据传递给传输层,UDP 只会给数据怎加一个 UDP 头标识一下这是 UDP,然后就传递给网络层了,不进行任何拆分。 9 | - 在接收端,网络层将数据传递给传输层,UDP 只取出 IP 报文头就传递给应用层,不进行任何拼装。 10 | 11 | 特点: 12 | 13 | - 面向报文 14 | - 不可靠传输 15 | - 高效 16 | 17 | 应用场景: 18 | 当强调输出性能而非完整性时,如音频和多媒体的实时传输。有个视频流传输协议 RTP 的实时传输就是基于 UDP 封装而来的。 19 | 20 | ### 不可靠性 21 | 22 | 1. UDP 是**无连接**的,也就是说同学不需要建立和断开链接。 23 | 2. UDP 是不可靠的。它不会去备份数据,也不关心对方是否能收到数据。 24 | 3. UDP**没有拥塞控制**,一直以恒定的速度发送数据,即使网络条件不好,也不进行速率调整。 造成的弊端就是在网络条件不好时可能导致丢包。 25 | 26 | ### 高效性 27 | 28 | 因为 UDP 没有 TCP 那么复杂,不需要保证数据不丢失且有序到达。所以 UDP 的头部开销小,只有八字节,相比 TCP 的至少二十字节要少得多,在传输数据报文时是很高效的。 29 | 30 | UDP 包头部包含了以下几个数据 31 | 32 | - 两个十六位的端口号,分别为源端口(可选字段)和目标端口 33 | - 整个数据报文的长度 34 | - 整个数据报文的检验和(IPv4 可选 字段),该字段用于发现头部信息和数据中的错误 35 | 36 | ![UDP Header](../../img/UDP.png) 37 | 38 | ### 传输方式 39 | 40 | 支持一对一,一对多,多对多,多对一的方式,也就是说 UDP 提供了单播,多播,广播的功能。 41 | -------------------------------------------------------------------------------- /0-前端基础/CSS/居中元素/垂直居中/center5.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 垂直居中 8 | 9 | 27 | 28 |
29 |
30 | 使用flex居中
31 | 父元素 display: flex;
32 | justify-content: center;
33 | align-items: center;
34 |
35 |
36 | 37 | 38 | -------------------------------------------------------------------------------- /3-编程能力/编程题与分析题/柯里化.md: -------------------------------------------------------------------------------- 1 | # curry 2 | 3 | 柯里化(英语:Currying),又称为部分求值,是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回一个新的函数的技术,新函数接受余下参数并返回运算结果。 4 | 5 | 实现一个 add 方法,使计算结果能够满足如下预期: 6 | 7 | ```js 8 | add(1)(2)(3) = 6; 9 | add(1, 2)(3) = 10; 10 | ``` 11 | 12 | 实现方法: 做一个闭包,返回一个函数,这个函数每次执行会改写闭包里面记录参数的数组。当这个函数判断参数个数够了,就去执行它。 13 | 14 | ```js 15 | function curry(func) { 16 | // 存储已传入参数 17 | let _args = []; 18 | 19 | // 做一个闭包 20 | function _curry(...args) { 21 | // 把参数合并 22 | _args = _args.concat(args); 23 | 24 | // 如果参数够了就执行 25 | if (_args.length >= func.length) { 26 | const result = func(..._args); 27 | _args = []; 28 | return result; 29 | } 30 | // 继续返回此函数 31 | else { 32 | return _curry; 33 | } 34 | } 35 | return _curry; 36 | } 37 | ``` 38 | 39 | ```js 40 | // 测试代码 41 | function add1(a, b, c) { 42 | return a + b + c; 43 | } 44 | let testAdd = curry(add1); 45 | console.log(testAdd(1)(2)(3)); 46 | console.log(testAdd(1, 2)(3)); 47 | console.log(testAdd(1)(2, 3)); 48 | ``` 49 | -------------------------------------------------------------------------------- /3-编程能力/编程题与分析题/debounce-demo.js: -------------------------------------------------------------------------------- 1 | // 频繁触发时,清楚对应的定时器,然后再开一个定时器,delay秒后执行 2 | function debounce(handler, delay) { 3 | delay = delay || 300; 4 | var timer = null; 5 | 6 | return function () { 7 | var _self = this, 8 | _args = arguments; 9 | 10 | clearTimeout(timer); 11 | timer = setTimeout(function () { 12 | handler.apply(_self, _args); 13 | }, delay); 14 | }; 15 | } 16 | 17 | // 不希望被频繁调用的函数 18 | function add(counterName) { 19 | console.log(counterName + ": " + this.index++); 20 | } 21 | 22 | // 需要的上下文对象 23 | let counter = { 24 | index: 0, 25 | }; 26 | 27 | // 防抖的自增函数,绑定上下文对象counter 28 | let db_add = debounce(add, 10).bind(counter); 29 | 30 | // 每隔500ms频繁调用3次自增函数,但因为防抖的存在,这3次内只调用一次 31 | setInterval(function () { 32 | db_add("someCounter1"); 33 | db_add("someCounter2"); 34 | db_add("someCounter3"); 35 | }, 500); 36 | 37 | /** 38 | * 预期效果: 39 | * 40 | * 每隔500ms,输出一个自增的数 41 | * 即打印: 42 | someCounter3: 0 43 | someCounter3: 1 44 | someCounter3: 2 45 | someCounter3: 3 46 | */ 47 | -------------------------------------------------------------------------------- /1-前端框架与库/React/Redux.md: -------------------------------------------------------------------------------- 1 | ### redux 简介 2 | 3 | redux 是一个应用数据流框架,主要是解决了组件间状态共享的问题,原理是集中式管理,主要有三个核心方法,`action,store,reducer` 4 | 5 | 工作流程是: 6 | 7 | - view 用 actionCreator 创建一个 action,里面可能包含一些数据 8 | - 使用 store 的 dispatch 方法将 acion 传入 store 9 | - store 将 action 与旧的 state 转发给 reducer 10 | - reducer 深拷贝 state,并返回一个新的 state 给 store 11 | - store 接收并更新 state 12 | - 使用 store.subscribe 订阅更新,重新 render 组件 13 | 14 | ### reducer 为什么是纯函数? 15 | 16 | 从本质上讲,纯函数的定义如下:不修改函数的输入值,依赖于外部状态(比如数据库,DOM 和全局变量),同时对于任何相同的输入有着相同的输出结果。 17 | ![](../../img/pureRedux.png) 18 | 19 | 阅读源码可以看到,Redux 接收一个给定的 state(对象),然后通过循环将 state 的每一部分传递给每个对应的 reducer。如果有发生任何改变,reducer 将返回一个新的对象。如果不发生任何变化,reducer 将返回旧的 state。 20 | 21 | Redux 只通过比较新旧两个对象的存储位置来比较新旧两个对象是否相同(也就是 Javascript 对象浅比较)。如果你在 reducer 内部直接修改旧的 state 对象的属性值,那么新的 state 和旧的 state 将都指向同一个对象。因此 Redux 认为没有任何改变,返回的 state 将为旧的 state。 22 | 23 | 深比较在真实的应用当中代价昂贵,因为通常 js 的对象都很大,同时需要比较的次数很多。 24 | 25 | 因此一个有效的解决方法是作出一个规定:无论何时发生变化时,开发者都要创建一个新的对象,然后将新对象传递出去。同时,当没有任何变化发生时,开发者发送回旧的对象。也就是说,新的对象代表新的 state。 使用了新的策略之后,你能够比较两个对象通过使用!==比较两个对象的存储位置而不是比较两个对象的所有属性。 26 | -------------------------------------------------------------------------------- /1-前端框架与库/React/Hooks/组件复用例子/render-props.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * 用一个函数属性的执行结果,来当作自己的渲染结果 3 | */ 4 | 5 | class Resizeable extends Component { 6 | state = { 7 | size: [window.innerWidth, window.innerHeight], 8 | }; 9 | 10 | onResize = () => { 11 | this.setState({ 12 | size: [window.innerWidth, window.innerHeight], 13 | }); 14 | }; 15 | 16 | componentDidMount() { 17 | window.addEventListener("resize", this.onResize); 18 | document.title = this.state.size.join("x"); 19 | } 20 | 21 | componentWillUnmount() { 22 | window.removeEventListener("resize", this.onResize); 23 | } 24 | 25 | componentDidUpdate() { 26 | document.title = this.state.size.join("x"); 27 | } 28 | 29 | render() { 30 | return this.props.render(this.state.size); 31 | } 32 | } 33 | 34 | class Foo extends Component { 35 | render() { 36 | const [width, height] = this.props.size; 37 | return ( 38 |
39 | {width} x {height} 40 |
41 | ); 42 | } 43 | } 44 | 45 | } />; 46 | -------------------------------------------------------------------------------- /3-编程能力/编程题与分析题/bind、apply实现.md: -------------------------------------------------------------------------------- 1 | ### 自封装 bind 方法 2 | 3 | - 因为 bind 的使用方法是 某函数.bind(某对象,...剩余参数) 4 | - 所以需要在 Function.prototype 上进行编程 5 | - 将传递的参数中的某对象和剩余参数使用 apply 的方式在一个回调函数中执行即可 6 | - 要在第一层获取到被绑定函数的 this,因为要拿到那个函数用 apply 7 | 8 | ```js 9 | /** 10 | * 简单版本 11 | */ 12 | Function.prototype.myBind = (that, ...args) => { 13 | const funcThis = this; 14 | return function (..._args) { 15 | return funcThis.apply(that, args.concat(_args)); 16 | }; 17 | }; 18 | ``` 19 | 20 | ### 自封装一个 apply 21 | 22 | - 首先要先原型上即 Function.prototype 上编程 23 | - 需要拿到函数的引用, 在这里是 this 24 | - 让 传入对象.fn = this 25 | - 执行 传入对象.fn(传入参数) 26 | - 返回执行结果 27 | 28 | ```js 29 | Function.prototype.myApply = function (context) { 30 | if (typeof this !== "function") { 31 | throw new TypeError("Error"); 32 | } 33 | context = context || window; 34 | context.fn = this; 35 | let result; 36 | // 处理参数和 call 有区别 37 | if (arguments[1]) { 38 | result = context.fn(...arguments[1]); 39 | } else { 40 | result = context.fn(); 41 | } 42 | delete context.fn; 43 | return result; 44 | }; 45 | ``` 46 | -------------------------------------------------------------------------------- /3-编程能力/编程题与分析题/类型判断.md: -------------------------------------------------------------------------------- 1 | ### 实现一个类型判断函数 2 | 3 | 1. 判断 null 4 | 2. 判断基础类型 5 | 3. 使用`Object.prototype.toString.call(target)`来判断**引用类型** 6 | 7 | 注意: 一定是使用`call`来调用,不然是判断的 Object.prototype 的类型 8 | 之所以要先判断是否为基本类型是因为:虽然`Object.prototype.toString.call()`能判断出某值是:number/string/boolean,但是其实在包装的时候是把他们先转成了对象然后再判断类型的。 但是 JS 中包装类型和原始类型还是有差别的,因为对一个包装类型来说,typeof 的值是 object 9 | 10 | ```javascript 11 | /** 12 | * 类型判断 13 | */ 14 | function getType(target) { 15 | //先处理最特殊的Null 16 | if (target === null) { 17 | return "null"; 18 | } 19 | //判断是不是基础类型 20 | const typeOfT = typeof target; 21 | if (typeOfT !== "object") { 22 | return typeOfT; 23 | } 24 | //肯定是引用类型了 25 | const template = { 26 | "[object Object]": "object", 27 | "[object Array]": "array", 28 | "[object Function]": "function", 29 | // 一些包装类型 30 | "[object String]": "object - string", 31 | "[object Number]": "object - number", 32 | "[object Boolean]": "object - boolean", 33 | }; 34 | const typeStr = Object.prototype.toString.call(target); 35 | return template[typeStr]; 36 | } 37 | ``` 38 | -------------------------------------------------------------------------------- /3-编程能力/编程题与分析题/实现一个sleep函数.md: -------------------------------------------------------------------------------- 1 | ## 实现一个 sleep 函数 2 | 3 | 比如 sleep(1000) 意味着等待 1000 毫秒,可从 Promise、Generator、Async/Await 等角度实现 4 | 5 | ### Promise 6 | 7 | ```js 8 | const sleep = (time) => { 9 | new Promise((resolve) => { 10 | setTimeout(resolve, time); 11 | }); 12 | }; 13 | 14 | sleep(1000).then(() => { 15 | console.log(1); 16 | }); 17 | ``` 18 | 19 | ### Generator 20 | 21 | ```js 22 | function* sleep(time) { 23 | yield new Promise((resolve) => { 24 | setTimeout(resolve, time); 25 | }); 26 | } 27 | sleep(1000) 28 | .next() 29 | .value.then(() => { 30 | console.log(1); 31 | }); 32 | ``` 33 | 34 | ### async 35 | 36 | ```js 37 | async function sleep(time, func) { 38 | await new Promise((resolve) => setTimeout(resolve, time)); 39 | return func(); 40 | } 41 | sleep(1000, () => { 42 | console.log(1); 43 | }); 44 | ``` 45 | 46 | ### ES5 47 | 48 | ```js 49 | function sleep(callback, time) { 50 | if (typeof callback === "function") setTimeout(callback, time); 51 | } 52 | 53 | function output() { 54 | console.log(1); 55 | } 56 | sleep(output, 1000); 57 | ``` 58 | -------------------------------------------------------------------------------- /6-工程架构/ServerLess.md: -------------------------------------------------------------------------------- 1 | ## Serverless 2 | 3 | ### 什么是Serverless 4 | 5 | 要说Serverless是什么,直译过来就是无服务器。Serverless 是指构建和运行**不需要管理服务器**的应用程序的概念。 6 | 7 | CloudFlare对其定义: 8 | 9 | 无服务器计算是一种**按需提供后端服务**的方法。无服务器提供程序允许用户编写和部署代码,而不必担心底层基础结构。尽管称为无服务器,但仍使用物理服务器,但开发人员无需了解它们。从无服务器供应商处获得后端服务的公司将根据其计算费用,而不必保留和支付固定数量的带宽或服务器数量,因为该服务是**自动扩展**的。 10 | 11 | ### 为什么需要 ServerLess 12 | 13 | 微信小程序出现后,开发者在小程序开发完后,只要去开发者平台点下上传就完成了前端部署,要做的只是部署后端服务。 14 | 15 | 后端服务运维是一件很麻烦的事情,我们能不能懒一点,把这个后端服务也部署到别人那里,当然有,那就是阿里云,腾讯云。我们要做的只是把我们本地调试好的后台服务部署上去。 16 | 17 | 但是我们能不能更懒一点,就别去部署了,直接就在别人那里开发前端和后端的应用,我们要做的就是按照别人定的规则来开发前后端应用就好,开发完后直接把两个都上传上去就行了。基于这种想法云开发serverless云端一体化就应运而生了。 18 | 19 | 其实这种想法大大的降低了前端开发人员进入后端开发的门槛,和前端开发人员中所谓的全栈工程师不谋而合 20 | 21 | ### ServerLess 的组成 22 | 23 | Serverless = Faas (Function as a service) + Baas (Backend as a service) 24 | 25 | ![img](/Users/bytedance/Documents/self/webKnowledge/img/1729cf3b0a40a037.png) 26 | 27 | ### 云函数(Faas) 28 | 29 | FaaS(Function-as-a-Service)是服务商提供一个平台、提供给用户开发、运行管理这些函数的功能,而无需搭建和维护基础框架,是一种事件驱动由消息触发的函数服务 30 | 31 | ![img](/Users/bytedance/Documents/self/webKnowledge/img/1-20210413133231936) 32 | 33 | -------------------------------------------------------------------------------- /6-工程架构/BFF.md: -------------------------------------------------------------------------------- 1 | ## BFF 2 | 3 | BFF(Backend For Frontend),用中文解释就是服务于前端的后端。 4 | 5 | 流程图 6 | 7 | ### 有什么用? 8 | 9 | 作为**适配层**、**API聚合层**。 10 | 11 | **适配层** 12 | 13 | 如果我们的接口同时提供给`web`、`移动端`使用,`移动端`仅用来采集数据以及数据的展示,而`web`端大多数场景是用来管理数据,因为不同端点的业务有所不同,所以每一个端的接口复用度不会太高。 14 | 15 | 例子:比如PC端页面设计的API需要支持移动端,发现现有接口从设计到实现都与桌面UI展示需求强相关,无法简单适应移动端的展示需求 ,就好比PC端一个新闻推荐接口,接口字段PC端都需要,而移动端呢H5不需要,这个时候根据不同终端在BFF层做调整,同时也可以进行不同的(或更少的)API调用(聚合)来减少http请求。 16 | 17 | **API聚合层** 18 | 19 | 后端同学追求解藕,因为后端可能不止一个服务,但多个服务之间有时只是有简单的业务上关系,如果能引入BFF这中间层,就使得两边可以独立变化。 20 | 21 | 例子1:用户上传头像后,用户信息的头像信息要更新,用户的头像图片需要存。如果存图片是单独一个服务,头像信息又是另一个服务,通过 BFF 就可以解决。 22 | 23 | 例子2:比如一个用户进入页面时往往都会拉很多数据,比如他会先打请求拉自己的用户信息,再打请求拉用户的一些配置,然后页面再渲染,这样页面的首屏时间就变得缓慢。而如果引入BFF这中间层,让 BFF 层把该拿的数据合并为一个请求就返回回来,那么首屏速度就会加快。 24 | 25 | ### BFF的痛点 26 | 27 | - 维护问题:需要维护各种 BFF 应用。以往前端也不需要关心并发,现在并发压力却集中到了 BFF 上 28 | - 链路复杂:流程变得繁琐,BFF引入后,要同时走前端、服务端的研发流程,多端发布、互相依赖,导致流程繁琐 29 | 30 | ### 有什么方案可以解决传统BFF痛点? 31 | 32 | - 包括解决前端需要关心应用的负载均衡、备份冗灾、监控报警等一些列运维部署的操作 33 | - 如何统一管理和运维,提高发布速度、降低运维成本 34 | 35 | 答案是:`Serverless` -------------------------------------------------------------------------------- /1-前端框架与库/React/基础/lazy与suspense.md: -------------------------------------------------------------------------------- 1 | # Lazy 与 Suspense 2 | 3 | ## lazy 4 | 5 | React.lazy 接受一个函数,这个函数需要动态调用 import()。它必须返回一个 Promise,该 Promise 需要 resolve 一个 defalut export 的 React 组件。 6 | 7 | ```js 8 | const OtherComponent = React.lazy(() => import("./OtherComponent")); 9 | ``` 10 | 11 | lazy 函数用来将组件模块的导入行为封装为 React 组件。封装的是组件导入行为,而不是组件本身。而且导入意味着网络请求。 12 | 13 | ## Suspense 14 | 15 | lazy 必须配合 Suspense 来一起使用,因为在异步加载的过程中,这个空白档必须要给 React 提供一个 loading 的组件 16 | 注意: 17 | 18 | - Suspense 的 fallback 属性必须传入一个 React 实例,即一个 JSX 19 | 20 | ## ErrorBoundary 21 | 22 | 当 React 的异步组件加载出错时,页面就会报错。它利用了`componentDidCatch`这个生命周期函数来。 23 | 24 | ## 例子 25 | 26 | ```jsx 27 | const About = lazy( 28 | () => 29 | new Promise((resolve, reject) => { 30 | setTimeout(() => { 31 | resolve(import(/* webpackChunkName:"about" */ "./About.jsx")); 32 | }, 2000); 33 | }) 34 | ); 35 | 36 | class App extends Component { 37 | render() { 38 | return ( 39 |
40 | Loading...
}> 41 | 42 | 43 | 44 | ); 45 | } 46 | } 47 | ``` 48 | -------------------------------------------------------------------------------- /0-前端基础/CSS/布局/三栏-网格布局.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 网格布局 8 | 30 | 31 | 32 |
33 | 34 |
35 |

表格布局

36 |

父元素display: table;并且宽度为100%

37 |

每一个子元素display: table-cell;

38 |

左右两侧添加宽度,中间不加宽度

39 |
40 | 41 |
42 | 43 | 44 | -------------------------------------------------------------------------------- /0-前端基础/CSS/布局/三栏-flex.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 34 | 35 | 36 |
37 | 38 |
39 |

flex布局解决方案

40 |

包裹这个3个块的父元素display: flex; 中间的元素flex: 1;

41 |
42 | 43 |
44 | 45 | 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 胡耀 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /1-前端框架与库/React/Hooks/组件复用例子/HOC.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * 高阶组件复用逻辑 3 | * 4 | * 调用方便 5 | */ 6 | 7 | function resizeable(Child) { 8 | return class Wrapper extends React.Component { 9 | state = { 10 | size: [window.innerWidth, window.innerHeight], 11 | }; 12 | 13 | onResize = () => { 14 | this.setState({ 15 | size: [window.innerWidth, window.innerHeight], 16 | }); 17 | }; 18 | 19 | componentDidMount() { 20 | window.addEventListener("resize", this.onResize); 21 | document.title = this.state.size.join("x"); 22 | } 23 | 24 | componentWillUnmount() { 25 | window.removeEventListener("resize", this.onResize); 26 | } 27 | 28 | componentDidUpdate() { 29 | document.title = this.state.size.join("x"); 30 | } 31 | 32 | render() { 33 | const size = this.state.size; 34 | return ; 35 | } 36 | }; 37 | } 38 | 39 | class Foo extends React.Component { 40 | render() { 41 | const [width, height] = this.props.size; 42 | return ( 43 |
44 | {width} x {height} 45 |
46 | ); 47 | } 48 | } 49 | 50 | const WrapperedFoo = resizeable(Foo); 51 | -------------------------------------------------------------------------------- /0-前端基础/CSS/布局/三栏-浮动方案.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 33 | 34 | 35 | 36 | 37 |
38 |

浮动解决方案

39 |

方法:left和right写在center前面,并且分别左右浮动;

40 |

41 | 中间的这个div因为是块级元素,所以在水平方向上按照他的包容块自动撑开。 42 |

43 |

简单,但是中心部分过长下面会溢出,然后文字就会跑到两边去。

44 |
45 | 46 | 47 | -------------------------------------------------------------------------------- /0-前端基础/JS/事件.md: -------------------------------------------------------------------------------- 1 | # 事件机制 2 | 3 | ### 事件触发三阶段 4 | 5 | 事件触发有三个阶段: 6 | 7 | - window 往事件触发处传播,遇到注册的捕获事件会触发 8 | - 传播到事件触发处时触发注册的事件 9 | - 从事件触发处往 window 传播,遇到注册的冒泡事件会触发 10 | 11 | 事件触发一般来说会按照上面的顺序进行,但是也有特例,如果给一个 body 中的子节点同时注册冒泡和捕获事件,事件触发会按照注册的顺序执行。 12 | 13 | ### 注册事件 14 | 15 | 通常使用 addEventListener 注册事件,该函数的第三个参数可以是布尔值,也可以是对象。第三个参数默认值为 false,决定了注册的事件是捕获事件(ture 为)还是冒泡事件。 16 | 17 | 一般来说,如果我们只希望事件只触发在目标上,这时候可以使用 stopPropagation 来阻止事件的进一步传播。通常我们认为 stopPropagation 是用来阻止事件冒泡的,其实该函数也可以阻止捕获事件。stopImmediatePropagation 同样也能实现阻止事件,但是还能阻止该事件目标执行别的注册事件。 18 | 19 | ### target 和 currentTarget 20 | 21 | 在了解上述的事件传递的三个阶段后,我们来梳理事件对象中容易混淆的两个属性:target 和 currentTarget 。 22 | 23 | target 是触发事件的某个具体的对象,只会出现在事件机制的目标阶段,即“谁触发了事件,谁就是 target ”。 24 | currentTarget 是绑定事件的对象。 25 | 26 | ### [取消默认操作](https://wiki.jikexueyuan.com/project/brief-talk-js/event-cancellation-and-prevent-bubbles.html) 27 | 28 | 取消默认操作 29 | w3c 的方法是 e.preventDefault(),IE 则是使用 e.returnValue = false; 30 | 31 | ```js 32 | function cancelHandler(event) { 33 | var event = event || window.event; //用于IE 34 | if (event.preventDefault) event.preventDefault(); //标准技术 35 | if (event.returnValue) event.returnValue = false; //IE 36 | return false; //用于处理使用对象属性注册的处理程序 37 | } 38 | ``` 39 | -------------------------------------------------------------------------------- /0-前端基础/CSS/布局/三栏-绝对定位.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 绝对定位三栏布局 8 | 33 | 34 | 35 | 36 | 37 |
38 |

绝对定位解决方案

39 |

左右区域分别postion:absolute,固定到左右两边

40 |

中间区域postion:absolute;left:300px; right: 300px

41 |

给总的宽度加一个min-width,不然缩小窗口会有毛病

42 |
43 | 44 | 45 | -------------------------------------------------------------------------------- /5-性能优化/testDemo/slowServer/index.js: -------------------------------------------------------------------------------- 1 | const http = require("http"); 2 | const fs = require("fs"); 3 | 4 | const hostname = "127.0.0.1"; 5 | const port = 3000; 6 | 7 | const server = http.createServer((req, res) => { 8 | //加载很慢的JS放在头部 9 | if (req.url === "/header") { 10 | fs.readFile("./js-header.html", "utf8", (err, data) => { 11 | res.statusCode = 200; 12 | res.setHeader("Content-Type", "text/html"); 13 | res.end(data); 14 | }); 15 | } 16 | 17 | //加载很慢的JS放在尾部 18 | if (req.url === "/bottom") { 19 | fs.readFile("./js-bottom.html", "utf8", (err, data) => { 20 | res.statusCode = 200; 21 | res.setHeader("Content-Type", "text/html"); 22 | res.end(data); 23 | }); 24 | } 25 | 26 | if (req.url === "/slow.js") { 27 | fs.readFile("./slow.js", "utf8", (err, data) => { 28 | setTimeout(() => { 29 | res.statusCode = 200; 30 | res.setHeader("Content-Type", "application/javascript"); 31 | res.end(data); 32 | }, 2000); 33 | }); 34 | } 35 | }); 36 | 37 | server.listen(port, hostname, () => { 38 | console.log(`加载很慢的JS放在头部 http://${hostname}:${port}/header`); 39 | console.log(`加载很慢的JS放在尾部 http://${hostname}:${port}/bottom`); 40 | }); 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 前端知识总结 2 | 3 | github 链接:[webKnowledge](https://github.com/huyaocode/webKnowledge) 4 | 5 | 这是我在平时学习与开发过程中收集整理的知识点,查漏补缺,扎实基础。 6 | 7 | ## 为什么我要维护这个知识库? 8 | 9 | 由于前端的知识面实在是太广了,而且又很杂。网上的文章都是都是一篇一篇的,不成体系,经常出现对于一个问题上网一搜有好多篇文章,但他们写的侧重点又不一样,对于同一个问题的描述也可能不一致。 10 | 11 | 所以我想维护一个前端的知识库,把一个优秀的前端**应该知道的**、**有深度的**知识都梳理出来,让整个前端知识成体系,让单个知识点有深度。 12 | 13 | 当我看到对一个问题有更好的文章时,我就可以把它加入到我的知识库中,那我对这个模块的知识了解就更成体系了,而不是看了一篇好文,给他点个赞,加入收藏夹就算了。 14 | 15 | 但是,由于前端的知识面真的太广了,我诚邀你一起来和我维护这个知识库,因为我知道很多同学还是以我这个知识库来学习的。大家一起把这个知识库做好,那么大家最后想再查的时候也就很方便。可以直接给我在 issue 里面说 XX 文章很好,让我整理一下,或者提 PR,或者微信联系我,我们一起把某些模块梳理清楚。 16 | 17 | ## 前端学习交流群 18 | 19 | 平时大家会在里面发技术文章,不打广告。群二维码就不放出来了,因为有打广告的机器人会加。想进群的加我微信: `hu-xxss` 我拉你进群 20 | 21 | ## 内推 22 | 23 | [关于内推你需要知道的事](https://github.com/huyaocode/webKnowledge/issues/8) 24 | 25 | 所有城市、职位均可内推,我**负责帮你填写推荐语,可随时找我查询内推进度**,也可以帮你修改或检查简历,如果临时有变化,也可找我帮联系 HR。 26 | 27 | ### 校招职位 28 | 29 | 投递链接: 字节跳动校招内推码: **MHQXH13** 30 | 投递链接: https://jobs.toutiao.com/s/edvfTo9 31 | 32 | ### 社招职位 33 | 34 | 投递链接: https://job.toutiao.com/s/edvyFaw 35 | 36 | ### **2022 实习内推** 37 | 38 | 投递链接: [2022 闪电内推实习生招募计划](https://jobs.bytedance.com/referral/mobile/lightning-referral?category=&location=&type=3&token=MzsxNjQ0NjUzMjE2MjIwOzY4NDQxODc3ODEzMjYxNjE0MTY7MA) 39 | -------------------------------------------------------------------------------- /0-前端基础/CSS/布局/三栏-表格布局.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 表格布局 8 | 35 | 36 | 37 |
38 | 39 |
40 |

表格布局

41 |

父元素display: table;并且宽度为100%

42 |

每一个子元素display: table-cell;

43 |

左右两侧添加宽度,中间不加宽度

44 |
45 | 46 |
47 | 48 | 49 | -------------------------------------------------------------------------------- /0-前端基础/CSS/布局/双飞翼布局.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 双飞翼布局 8 | 45 | 46 | 47 |
中心区
48 |
left
49 |
right
50 | 51 | 52 | -------------------------------------------------------------------------------- /2-计算机基础/网络/CDN.md: -------------------------------------------------------------------------------- 1 | # CDN 2 | 3 | CDN(Content Delivery Network,内容分发网络)是构建在现有互联网基础之上的一层智能虚拟网络,通过在网络各处部署节点服务器,实现将源站内容分发至所有 CDN 节点,使用户可以就近获得所需的内容。CDN 服务缩短了用户查看内容的访问延迟,提高了用户访问网站的响应速度与网站的可用性,解决了网络带宽小、用户访问量大、网点分布不均等问题。 4 | 5 | ## 加速原理 6 | 7 | 当用户访问使用 CDN 服务的网站时,本地 DNS 服务器通过 CNAME 方式将最终域名请求重定向到 CDN 服务。CDN 通过一组预先定义好的策略(如内容类型、地理区域、网络负载状况等),将当时能够最快响应用户的 CDN 节点 IP 地址提供给用户,使用户可以以最快的速度获得网站内容。使用 CDN 后的 HTTP 请求处理流程如下: 8 | 9 | ### CDN 节点有缓存场景 10 | 11 | ![cdncache](../../img/cdncache.png) 12 | 13 | 1. 用户在浏览器输入要访问的网站域名,向本地 DNS 发起域名解析请求。 14 | 2. 域名解析的请求被发往网站授权 DNS 服务器。 15 | 3. 网站 DNS 服务器解析发现域名已经 CNAME 到了 www.example.com.c.cdnhwc1.com。 16 | 4. 请求被指向 CDN 服务。 17 | 5. CDN 对域名进行智能解析,将响应速度最快的 CDN 节点 IP 地址返回给本地 DNS。 18 | 6. 用户获取响应速度最快的 CDN 节点 IP 地址。 19 | 7. 浏览器在得到速度最快节点的 IP 地址以后,向 CDN 节点发出访问请求。 20 | 8. CDN 节点将用户所需资源返回给用户。 21 | 22 | ### CDN 节点无缓存场景 23 | 24 | ![无缓存](../../img/cdnnocahche.png) 25 | 26 | 1. 用户在浏览器输入要访问的网站域名,向本地 DNS 发起域名解析请求。 27 | 2. 域名解析的请求被发往网站授权 DNS 服务器。 28 | 3. 网站 DNS 服务器解析发现域名已经 CNAME 到了 www.example.com.c.cdnhwc1.com。 29 | 4. 请求被指向 CDN 服务。 30 | 5. CDN 对域名进行智能解析,将响应速度最快的 CDN 节点 IP 地址返回给本地 DNS。 31 | 6. 用户获取响应速度最快的 CDN 节点 IP 地址。 32 | 7. 浏览器在得到速度最快节点的 IP 地址以后,向 CDN 节点发出访问请求。 33 | 8. CDN 节点回源站拉取用户所需资源。 34 | 9. 将回源拉取的资源缓存至节点。 35 | 10. 将用户所需资源返回给用户。 36 | 37 | PS:CNAME 别名解析是将域名指向一个网址(域名) 38 | -------------------------------------------------------------------------------- /0-前端基础/CSS/布局/圣杯布局.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 实现三栏水平布局之圣杯布局 6 | 47 | 48 | 49 |
50 |
main
51 |
left
52 |
right
53 |
54 | 55 | 56 | -------------------------------------------------------------------------------- /3-编程能力/编程题与分析题/闭包.md: -------------------------------------------------------------------------------- 1 | # 闭包问题 2 | 3 | ### 循环中赋值为引用的问题 4 | 5 | ```js 6 | for (var i = 1; i < 5; i++) { 7 | setTimeout(function timer() { 8 | console.log(i); 9 | }, i * 1000); 10 | } 11 | ``` 12 | 13 | 解决方法有 3 种 14 | 15 | 第一种,使用`立即执行函数`方式 16 | 17 | ```js 18 | for (var i = 1; i < 5; i++) { 19 | (fuction(j){ 20 | setTimeout(function timer() { 21 | console.log(j) 22 | }, j * 1000) 23 | })(i) 24 | } 25 | ``` 26 | 27 | 第二种,使用 ES6 的`let` 28 | 29 | ```js 30 | for (let i = 1; i < 5; i++) { 31 | setTimeout(function timer() { 32 | console.log(i); 33 | }, i * 1000); 34 | } 35 | ``` 36 | 37 | 第三种,使用`setTimeout的第三个参数` 38 | 39 | ```js 40 | for (var i = 1; i < 5; i++) { 41 | setTimeout( 42 | function timer(j) { 43 | console.log(j); 44 | }, 45 | i * 1000, 46 | i 47 | ); 48 | } 49 | ``` 50 | 51 | ### 计数器 52 | 53 | 实现一个 foo 函数 可以这么使用: 54 | 55 | ```js 56 | a = foo(); 57 | b = foo(); 58 | c = foo(); 59 | // a === 1;b === 2;c === 3; 60 | foo.clear(); 61 | d = foo(); //d === 1; 62 | ``` 63 | 64 | ```js 65 | function myIndex() { 66 | var index = 1; 67 | 68 | function foo() { 69 | return index++; 70 | } 71 | 72 | foo.clear = function () { 73 | index = 1; 74 | }; 75 | return foo; 76 | } 77 | 78 | var foo = myIndex(); 79 | ``` 80 | -------------------------------------------------------------------------------- /5-性能优化/雅虎军规.md: -------------------------------------------------------------------------------- 1 | # 雅虎军规 2 | 3 | [雅虎军规](https://developer.yahoo.com/performance/rules.html?guccounter=1) 4 | 5 | - 网络部分 6 | - 尽量减少 HTTP 请求数 7 | - 合并文件 8 | - 雪碧图 9 | - 小图 Base64 10 | - 减少 DNS 查找 11 | - 开启 DNS 预解析 12 | - 使用 CND 静态资源服务器 13 | - 避免重定向 14 | - 杜绝 404 15 | - 缓存 16 | - 配置 ETags 17 | - 实体标签(ETags),是服务器和浏览器用来决定浏览器缓存中组件与源服务器中的组件是否匹配的一种机制 18 | - 添上 Expires 或者 Cache-Control HTTP 头 19 | - 使用外链的方式引入 JS 和 CSS(缓存) 20 | - 内容部分 21 | - 按需加载组件 22 | - 预加载组件 23 | - 减少 DOM 元素的数量 24 | - 尽量少用 iframe 25 | - 压缩 JavaScript 和 CSS(代码层面) 26 | - CSS 部分 27 | - 避免使用 CSS 表达式 28 | - 选择``而不是`@import` 29 | - 避免使用滤镜 30 | - 把样式表放在顶部 31 | - JS 部分 32 | - 把脚本放在底部 33 | - 去除重复脚本 34 | - 减少 DOM 访问 35 | - 图片部分 36 | - 选用合适的图片格式 37 | - 雪碧图中间少留空白 38 | - 不要用 HTML 缩放图片,要小图就去加载小图 39 | - 用小的可缓存的 favicon.ico 40 | - cookie 41 | - 给 cookie 减肥 42 | - 清除不必要的 cookie 43 | - cookie 尽可能小 44 | - 设置好合适的域 45 | - 合适的有效期 46 | - 把静态资源放在不含 cookie 的域下 47 | - 当浏览器发送对静态图像的请求时,cookie 也会一起发送,而服务器根本不需要这些 cookie。 48 | - 移动端 49 | - 保证所有组件都小于 25K 50 | - 把组件打包到一个复合文档里 51 | - 服务器 52 | - 开启 Gzip 等压缩 53 | - 避免图片 src 属性为空(为空浏览器也会向服务器发送另一个请求) 54 | - 对 Ajax 用 GET 请求 55 | - 尽早清空缓冲区 56 | - 使用 CDN(内容分发网络) 57 | - 内容分发网络(CDN)是一组分散在不同地理位置的 web 服务器,用来给用户更高效地发送内容。 58 | -------------------------------------------------------------------------------- /2-计算机基础/网络/README.md: -------------------------------------------------------------------------------- 1 | # 网络知识 2 | 3 | ## [Ajax](Ajax.md) 4 | 5 | ## [HTTP](HTTP.md) 6 | 7 | ## [TCP](TCP.md) 8 | 9 | ## [UDP](UDP.md) 10 | 11 | ## [跨域](./跨域.md) 12 | 13 | ## [缓存](缓存.md) 14 | 15 | ## [cookie 和 session](cookie和session.md) 16 | 17 | ## [从输入 URL 到页面加载完成的过程](从输入URL到页面加载完成的过程.md) 18 | 19 | ## [HTTPS](HTTPS.md) 20 | 21 | ### OSI 七层协议 22 | 23 | - 应用层 24 | - 为应用提供通信服务 25 | - 表示层 26 | - 定义数据格式以及加密 27 | - 会话层 28 | - 定义了如何开始、控制、结束一个会话,包括对多个双向消息的控制和管理。 29 | - 传输层 30 | - 选择差错恢复协议还是无差错恢复协议 31 | - TCP、UDP 32 | - 网络层 33 | - 端到端包传输。 34 | - 路由选择、包分解成更小的包 35 | - 数据链路层 36 | - 定义单个链路上如何传输数据 37 | - 物理层 38 | - 传输介质相关 39 | 40 | ### DNS 解析 41 | 42 | DNS 的作用就是通过域名查询到具体的 IP。 43 | 44 | 1. 操作系统会首先在本地缓存中查询 45 | 2. 没有的话会去系统配置的 DNS 服务器中查询 46 | 3. 如果这时候还没得话,会直接去 DNS 根服务器查询,这一步查询会找出负责 com 这个一级域名的服务器 47 | 4. 然后去该服务器查询 google 这个二级域名 48 | 5. 接下来三级域名的查询其实是我们配置的,你可以给 www 这个域名配置一个 IP,然后还可以给别的三级域名配置一个 IP 49 | 50 | 以上介绍的是 DNS 迭代查询,还有种是递归查询,区别就是前者是由客户端去做请求,后者是由系统配置的 DNS 服务器做请求,得到结果后将数据返回给客户端。 51 | 52 | ### 前后端如何通信 53 | 54 | - Ajax 55 | - WebSocket 56 | - CORS 57 | 58 | ### websocket 59 | 60 | 在单个 TCP 连接上进行全双工通讯的协议。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建**持久性**的连接,并进行**双向**数据传输。 61 | 62 | - Socket.onopen 连接建立时触发 63 | - Socket.onmessage 客户端接收服务端数据时触发 64 | - Socket.onerror 通信发生错误时触发 65 | - Socket.onclose 连接关闭时触发 66 | -------------------------------------------------------------------------------- /0-前端基础/CSS/居中元素/README.md: -------------------------------------------------------------------------------- 1 | # 居中 2 | 3 | ### 如何竖直居中一个元素 4 | 5 | 参考代码: [CSS/居中元素/垂直居中](https://github.com/huyaocode/webKnowledge/tree/master/CSS/%E5%B1%85%E4%B8%AD%E5%85%83%E7%B4%A0/%E5%9E%82%E7%9B%B4%E5%B1%85%E4%B8%AD) 6 | 7 | #### 被居中元素宽高固定 8 | 9 | 1. 绝对定位,top 和 left 为 50%, margin 的 left 和 top 为自身宽高一半 10 | 11 | ```css 12 | .center { 13 | position: absolute; 14 | top: 50%; 15 | left: 50%; 16 | margin-left: -9rem; 17 | margin-top: -5rem; 18 | } 19 | ``` 20 | 21 | 2. 绝对定位,top 和 lefe 为父元素一半剪自身一半 22 | 23 | ```css 24 | .center { 25 | position: absolute; 26 | top: calc(50% - 5em); 27 | left: calc(50% - 9em); 28 | } 29 | ``` 30 | 31 | #### 被居中元素宽高不定 32 | 33 | 3. 使用 CSS3 的 `transform`将位置在中心点平移自身宽高一半 34 | 35 | ```css 36 | .center { 37 | position: absolute; 38 | top: 50%; 39 | left: 50%; 40 | transform: translate(-50%, -50%); 41 | } 42 | ``` 43 | 44 | 4. 使用 flex 布局居中 45 | 46 | ```css 47 | .wrapper { 48 | display: flex; 49 | } 50 | .center { 51 | margin: auto; 52 | } 53 | ``` 54 | 55 | 5. flex 布局,父元素指定子元素居中。 56 | 57 | ```css 58 | .wrapper { 59 | display: flex; 60 | align-items: center; 61 | justify-content: center; 62 | } 63 | ``` 64 | 65 | #### 在浏览器窗口中居中 66 | 67 | 基于视口的垂直居中。不要求原生有固定的宽高,但是这种居中是在整个页面窗口内居中,不是基于父元素 68 | 69 | ```css 70 | .center { 71 | margin: 50vh auto; 72 | transform: translateY(-50%); 73 | } 74 | ``` 75 | -------------------------------------------------------------------------------- /0-前端基础/Web安全/CSRF.md: -------------------------------------------------------------------------------- 1 | # CSRF 跨站请求伪造 2 | 3 | (Cross Site Request Forgy) 4 | 打开同一浏览器时其他的网站对本网站造成的影响。原理就是攻击者构造出一个后端请求地址,诱导用户点击或者通过某些途径自动发起请求。如果用户是在登录状态下的话,后端就以为是用户在操作,从而进行相应的逻辑。 5 | ![原理](../../img/csrf.png) 6 | 7 | 举个例子,用户同时打开了 A 网站和钓鱼网站。 假设 A 网站中有一个通过 GET 请求提交用户评论的接口,那么攻击者就可以在钓鱼网站中加入一个图片,图片的地址就是评论接口。 8 | 9 | ```html 10 | 11 | ``` 12 | 13 | ## CSRF 攻击原理 14 | 15 | 1. 用户登录 A 网站 16 | 2. A 网站确认身份(给客户端 cookie) 17 | 3. B 网站页面向 A 网站发起请求(带上 A 网站身份) 18 | 19 | ## CSRF 防御 20 | 21 | 1. Get 请求不对数据进行修改 22 | 2. 不让第三方网站访问到用户 Cookie 23 | 3. 阻止第三方网站请求接口 24 | 4. 请求时附带验证信息,比如验证码或者 Token 25 | 26 | - SameSite 27 | - 可以对 Cookie 设置 SameSite 属性。该属性表示 Cookie 不随着跨域请求发送,可以很大程度减少 CSRF 的攻击,但是该属性目前并不是所有浏览器都兼容。 28 | - Token 验证 29 | - cookie 是发送时自动带上的,而不会主动带上 Token,所以在每次发送时主动发送 Token 30 | - Referer 验证 31 | - 对于需要防范 CSRF 的请求,我们可以通过验证 Referer 来判断该请求是否为第三方网站发起的。 32 | - 隐藏令牌 33 | - 主动在 HTTP 头部中添加令牌信息 34 | 35 | 禁止第三方网站带 cookies 36 | 37 | [same-site](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Cookies#SameSite_Cookies)属性。 设置只有同一站点的请求才能携带 cookie 38 | 39 | ## CSRF 蠕虫 40 | 41 | 如果某个用户打开了被攻击网页,并且用户同时访问了攻击者的网页。 42 | 那么攻击者的网页就会使用用户的身份发送一些请求,并且常用用户的身份发布一些评论或文章,里面包含攻击者的网页链接。如果其他用户看到了这个用户的这条评论,都甚至可以不点击,其他用户也会被盗用身份发送一些恶意请求。这样病毒的传播就会越来越快,影响越来越大。 43 | 44 | ## CSRF 攻击危害 45 | 46 | - 利用用户登录态 47 | - 用户不知情 48 | - 完成业务请求 49 | - 50 | - 盗取用户资金 51 | - 冒充用户发帖背锅 52 | - 损坏网站名誉 53 | -------------------------------------------------------------------------------- /1-前端框架与库/TypeScript/interface与type.md: -------------------------------------------------------------------------------- 1 | # Typescript 中的 interface 和 type 2 | 3 | ## 相同点 4 | 5 | - 都可以描述一个对象或者函数 6 | - 都允许拓展(extends) 7 | 8 | ## 不同点 9 | 10 | ### type 可以而 interface 不行 11 | 12 | - type 声明的方式可以定义组合类型,交叉类型,原始类型。 13 | 14 | ```js 15 | // 基本类型别名 16 | type Name = string 17 | 18 | // 联合类型 19 | interface Dog { 20 | wong(); 21 | } 22 | interface Cat { 23 | miao(); 24 | } 25 | 26 | type Pet = Dog | Cat 27 | // 具体定义数组每个位置的类型 28 | type PetList = [Dog, Pet] 29 | ``` 30 | 31 | - type 语句中还可以使用 typeof 获取实例的 类型进行赋值 32 | 33 | ```js 34 | // 当你想获取一个变量的类型时,使用 typeof 35 | let div = document.createElement("div"); 36 | type B = typeof div; 37 | ``` 38 | 39 | - 其他操作 40 | 41 | ```js 42 | type StringOrNumber = string | number; 43 | type Text = string | { text: string }; 44 | type NameLookup = Dictionary; 45 | type Callback = (data: T) => void; 46 | type Pair = [T, T]; 47 | type Coordinates = Pair; 48 | type Tree = T | { left: Tree, right: Tree }; 49 | ``` 50 | 51 | ### interface 可以而 type 不行 52 | 53 | - interface 能够声明合并 54 | 55 | ```js 56 | interface User { 57 | name: string 58 | age: number 59 | } 60 | 61 | interface User { 62 | sex: string 63 | } 64 | 65 | /* 66 | User 接口为 { 67 | name: string 68 | age: number 69 | sex: string 70 | } 71 | */ 72 | ``` 73 | 74 | - 一个函数,如果想使用`函数名.值`的方式,只能 interface 75 | 76 | 参考:https://juejin.im/post/5c2723635188252d1d34dc7d 77 | -------------------------------------------------------------------------------- /0-前端基础/NodeJS/README.md: -------------------------------------------------------------------------------- 1 | # NodeJS 2 | 3 | ## NodeJS 特点 4 | 5 | - 非阻塞式的异步 I/O 6 | - Node.js 中采用了非阻塞型 I/O 机制,因此在执行了访问文件的代码之后,Nodejs 不会阻塞在那里等待文件获取完成,而是把这件事交给底层操作系统,使用回调函数的方式来处理异步的 IO,立即转而执行其它的代码, 7 | - 事件轮询 8 | - Nodejs 接收到的事件会放到事件队列中,而不是立即执行它,当 NodeJS 当前代码执行完后他会检查事件队列中是否有事件,如果有,他会取出来依次执行 9 | - 单线程 10 | - Node.js 不为每个客户连接创建一个新的线程,而仅仅使用一个线程。当有用户连接了,就触发一个内部事件,通过非阻塞 I/O、事件驱动机制,让 Node.js 程序宏观上也是并行的 11 | - 优点:不会死锁、不用像多线程那样处处在意同步问题、没有线程切换带来的性能上的开销 12 | - 缺点:多核 CPU 需单独开子线程、错误会使得整个应用退出、大量计算会占用 CPU 从而无法调用异步 I/O 13 | - 擅长 I/O 密集型 14 | - 主要体现在 Node 利用事件轮询的方式处理事件,而不是单开一个线程来为每一个请求服务 15 | - 不擅长 CPU 密集型业务 16 | - 由于 Node 单线程,如果长时间运行计算将导致 CPU 不能释放,使得后续 I/O 无法发起。(解决办法是分解大型运算为多个小任务,不阻塞 I/O 发起) 17 | 18 | ### global 对象 19 | 20 | 与在浏览器端不同,浏览器端将希望全局访问的对象挂到 window 上,而 nodejs 则将希望全局访问的对象挂到 global 对象上 21 | 22 | - CommonJS 23 | - Buffer、process、console 24 | - timer 定时器相关 25 | 26 | ### setImmediate()、setTimeout(fn, 0) 与 process.nextTick() 27 | 28 | 两个都是传入一个回调函数,当同步事件执行完之后马上执行。 29 | 30 | 执行顺序依次是: 31 | 32 | - process.nextTick() 33 | - 将回调函数加入到 当前执行栈的尾部,任务队列之前 34 | - setTimeout(fn, 0) 35 | - 回调函数加入到 任务队列尾部。即使是 0,也会又 4ms 的延时 36 | - setImmediate() 37 | - 将回调函数插入到任务队列的最末尾,也不会造成阻塞,但不妨碍其他的异步事件 38 | 39 | ```js 40 | setImmediate(() => { 41 | console.log("setImmediate"); 42 | }); 43 | 44 | setTimeout(() => { 45 | console.log("setImmediate"); 46 | }, 0); 47 | 48 | process.nextTick(() => { 49 | console.log("next"); 50 | }); 51 | ``` 52 | -------------------------------------------------------------------------------- /0-前端基础/CSS/动画/animal.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 47 | 48 | 49 |
50 | 51 | 52 | -------------------------------------------------------------------------------- /1-前端框架与库/React/其他.md: -------------------------------------------------------------------------------- 1 | # 其他 2 | 3 | ## React 升级到 17.0 版本的变化(No New Features) 4 | 5 | ### 更改事件委托 6 | 7 | 在 React 17 中,React 将不再向 document 添加事件处理器。而会将事件处理器附加到渲染 React 树的根 DOM 节点中。 8 | 9 | 更改原因: 10 | 11 | - 现在可以更加安全地进行新旧版本 React 树的嵌套 12 | - React 嵌入使用其他技术构建的应用程序变得更加容易 13 | - 事件冒泡更接近常规 DOM 14 | 15 | ### 其他重大更改 16 | 17 | - onScroll 事件不再冒泡,以防止出现一些混淆。 18 | - React 的 onFocus 和 onBlur 事件已在底层切换为原生的 focusin 和 focusout 事件。它们更接近 React 现有行为,有时还会提供额外的信息。 19 | - 捕获事件(例如,onClickCapture)现在使用的是实际浏览器中的捕获监听器。 20 | 21 | #### 去除事件池 22 | 23 | React 17 中移除了"event pooling(事件池)"。它并不会提高现代浏览器的性能,甚至还会使开发者一头雾水: 24 | 25 | ```js 26 | function handleChange(e) { 27 | setData((data) => ({ 28 | ...data, 29 | // This crashes in React 16 and earlier: 30 | text: e.target.value, 31 | })); 32 | } 33 | ``` 34 | 35 | 这是因为 React 在旧浏览器中重用了不同事件的事件对象,以提高性能,并将所有事件字段在它们之前设置为 null。在 React 16 及更早版本中,使用者必须调用 e.persist()才能正确的使用该事件,或者正确读取需要的属性。此代码可以按照预期效果执行。在 React 17 中,旧的事件池优化操作已被完成删除,因此,使用者可以在需要时读取事件字段 36 | 37 | #### 副作用清理时机 38 | 39 | 大多数副作用(effect)不需要延迟刷新视图,因此 React 在屏幕上反映出更新后立即异步执行它们(在极少数情况下,你需要一种副作用来阻止重绘。例如,如果需要获取尺寸和位置,请使用 `useLayoutEffect`)。 40 | 41 | 在 React 17 中,副作用清理函数会异步执行 —— 如果要卸载组件,则清理会在视图更新后运行。 42 | 43 | #### 返回一致的 undefined 错误 44 | 45 | 在 React 17 中,forwardRef 和 memo 组件的行为会与常规函数组件和 class 组件保持一致。在返回 undefined 时会报错 46 | 47 | 参考: https://juejin.im/post/6859738814602280973 48 | 49 | ### 底层算法更新 - 启发式更新算法 50 | 51 | 文章链接: https://mp.weixin.qq.com/s/VBg7C-QaYAlcMDTlmysYnA 52 | -------------------------------------------------------------------------------- /0-前端基础/JS/3-运算符.md: -------------------------------------------------------------------------------- 1 | ### || 操作符 2 | 3 | 1. 只要有一个条件为 true 时,结果就为 true; 4 | 2. 当两个条件都为 false 时,结果才为 false; 5 | 3. 当一个条件为 true 时,后面的条件不再判断 6 | 7 | 注意:当数值参与逻辑或运算时,结果为 true,会返回第一个为真的值;如果结果为 false,会返回第二个为假的值; 8 | 9 | ### == 操作符 10 | 11 | 对于 == 来说,如果对比双方的类型不一样的话,就会进行类型转换 12 | 13 | 判断流程: 14 | 15 | 1. 首先会判断两者类型是否相同。相同的话就是比大小了 16 | 2. 类型不相同的话,那么就会进行类型转换 17 | 3. 会先判断是否在对比 null 和 undefined,是的话就会返回 true 18 | 4. 判断两者类型是否为 string 和 number,是的话就会将字符串转换为 number 19 | 20 | ```js 21 | 1 == '1' 22 | ↓ 23 | 1 == 1 24 | ``` 25 | 26 | 5. 判断其中一方是否为 boolean,是的话就会把 boolean 转为 number 再进行判断 27 | 28 | ```js 29 | '1' == true 30 | ↓ 31 | '1' == 1 32 | ↓ 33 | 1 == 1 34 | ``` 35 | 36 | 6. 判断其中一方是否为 object 且另一方为 string、number 或者 symbol,是的话就会把 object 转为原始类型再进行判断 37 | 38 | ```js 39 | '1' == { a: 'b' } 40 | ↓ 41 | '1' == '[object Object]' 42 | ``` 43 | 44 | 7. 两边都是对象的话,那么只要不是同一对象的不同引用,都为 false 45 | 46 | 注意,只要出现 NaN,就一定是 false,因为就连 NaN 自己都不等于 NaN 47 | 对于 NaN,判断的方法是使用全局函数 `isNaN()` 48 | 49 | ### === 操作符 50 | 51 | 不转类型,直接判断类型和值是否相同。 52 | 但是 NaN === NaN 还是 false 53 | 54 | ### && 操作符 55 | 56 | 1. 两边条件都为 true 时,结果才为 true; 57 | 2. 如果有一个为 false,结果就为 false; 58 | 3. 当第一个条件为 false 时,就不再判断后面的条件 59 | 60 | 注意:当数值参与逻辑与运算时,结果为 true,那么会返回的会是第二个为真的值;如果结果为 false,返回的会是第一个为假的值。 61 | 62 | ```js 63 | `${false && "adsf"}`; 64 | // -> "false" 65 | false === (false && "a"); 66 | // -> true 67 | true && 3; 68 | // -> 3 69 | false && 3; 70 | // -> false 71 | ``` 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /0-前端基础/JS/垃圾回收与内存泄露和优化.md: -------------------------------------------------------------------------------- 1 | [【V8 引擎】浅析 Chrome V8 引擎中的垃圾回收机制和内存泄露优化策略](https://segmentfault.com/a/1190000019584487) 2 | 3 | ## 垃圾回收机制 4 | 5 | ### 如何判断回收内容 6 | 7 | 如何确定哪些内存需要回收,哪些内存不需要回收,这是垃圾回收期需要解决的最基本问题。我们可以这样假定,**一个对象为活对象当且仅当它被一个根对象 或另一个活对象指向**。根对象永远是活对象,它是被浏览器或 V8 所引用的对象。被局部变量所指向的对象也属于根对象,因为它们所在的作用域对象被视为根对 象。全局对象(Node 中为 global,浏览器中为 window)自然是根对象。浏览器中的 DOM 元素也属于根对象。 8 | 9 | ### V8 回收策略 10 | 11 | 新生代的对象为存活时间较短的对象,老生代中的对象为存活时间较长或常驻内存的对象。分别对新生代和老生代使用 不同的垃圾回收算法来提升垃圾回收的效率。对象起初都会被分配到新生代,当新生代中的对象满足某些条件(后面会有介绍)时,会被移动到老生代(晋升)。 12 | 13 | ### 新生代算法 14 | 15 | 在新生代空间中,内存空间分为两部分,分别为 From 空间和 To 空间。在这两个空间中,必定有一个空间是使用的,另一个空间是空闲的。新分配的对象会被放入 From 空间中,当 From 空间被占满时,新生代 GC 就会启动了。算法会检查 From 空间中存活的对象并复制到 To 空间中,如果有失活的对象就会销毁。当复制完成后将 From 空间和 To 空间互换,这样 GC 就结束了。 16 | ![](../../img/gc-new.png) 17 | 18 | ### 老生代算法 19 | 20 | 老生代中的对象一般存活时间较长且数量也多,使用了两个算法,分别是标记清除算法和标记压缩算法。 21 | 22 | 在讲算法前,先来说下什么情况下对象会出现在老生代空间中: 23 | 24 | 1. 新生代中的对象是否已经经历过一次 Scavenge 算法,如果经历过的话,会将对象从新生代空间移到老生代空间中。 25 | 2. To 空间的对象占比大小超过 25 %。在这种情况下,为了不影响到内存分配,会将对象从新生代空间移到老生代空间中。 26 | 27 | ## 内存泄露和优化 28 | 29 | ### 什么是内存泄露? 30 | 31 | 存泄露是指程序中已分配的堆内存由于某种原因未释放或者无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统奔溃等后果。 32 | 33 | ### 常见的内存泄露的场景 34 | 35 | - 缓存 36 | - 作用域未释放(闭包) 37 | - 没有必要的全局变量 38 | - 无效的 DOM 引用 39 | - 定时器未清除 40 | - 事件监听为空白 41 | 42 | ### 内存泄露优化 43 | 44 | 1. 在业务不需要的用到的内部函数,可以重构到函数外,实现解除闭包。 45 | 2. 避免创建过多的生命周期较长的对象,或者将对象分解成多个子对象。 46 | 3. 避免过多使用闭包。 47 | 4. 注意清除定时器和事件监听器。 48 | 5. nodejs 中使用 stream 或 buffer 来操作大文件,不会受 nodejs 内存限制。 49 | -------------------------------------------------------------------------------- /2-计算机基础/网络/cookie和session.md: -------------------------------------------------------------------------------- 1 | # cookie 和 session 2 | 3 | ## 应用场景 4 | 5 | cookie: 6 | 登录网站,第一天输入用户名密码登录了,第二天再打开很多情况下就直接打开了。这个时候用到的一个机制就是 cookie。 7 | 8 | session: 9 | session 一个场景是购物车,添加了商品之后客户端处可以知道添加了哪些商品,而服务器端如何判别呢,所以也需要存储一些信息就用到了 session。 10 | 11 | ## cookie 12 | 13 | 服务器通过设置`set-cookie`这个响应头,将 cookie 信息返回给浏览器,浏览器将响应头中的 cookie 信息保存在本地,当下次向服务器发送 HTTP 请求时,浏览器会自动将保存的这些 cookie 信息添加到请求头中。 14 | 15 | 通过 cookie,服务器就会识别出浏览器,从而保证返回的数据是这个用户的。 16 | 17 | - 通过`set-cookie`设置 18 | - 下次请求会自动带上 19 | - 键值对,可设置多个 20 | 21 | ### cookie 属性 22 | 23 | - max-age 24 | - 过期时间有多长 25 | - 默认在浏览器关闭时失效 26 | - expires 27 | - 到哪个时间点过期 28 | - secure 29 | - 表示这个 cookie 只会在 https 的时候才会发送 30 | - HttpOnly 31 | - 设置后无法通过在 js 中使用 document.cookie 访问 32 | - 保障安全,防止攻击者盗用用户 cookie 33 | - domain 34 | - 表示该 cookie 对于哪个域是有效的。 35 | 36 | ## session 37 | 38 | - 存放在服务器的一种用来存放用户数据的类似 HashTable 的结构 39 | - 浏览器第一次发送请求时,服务器自动生成了 HashTable 和 SessionID 来唯一标识这个 hash 表,并将 sessionID 存放在 cookie 中通过响应发送到浏览器。浏览器第二次发送请求会将前一次服务器响应中的 sessionID 随着 cookie 发送到服务器上,服务器从请求中提取 sessionID,并和保存的所有 sessionID 进行对比,找到这个用户对应的 hash 表。 40 | - 一般这个值是有时间限制的,超时后销毁,默认 30min 41 | - 当用户在应用程序的 web 页面间挑转时,存储在 session 对象中的变量不会丢失而是在整个用户会话中一直存在下去。 42 | - session 依赖于 cookie,因为 sessionID 是存放在 cookie 中的。 43 | 44 | ## sesssion 与 cookie 的区别 45 | 46 | - cookie 存在客户端,session 存在于服务端。 47 | - cookie 在客户端中存放,容易伪造,不如 session 安全 48 | - session 会消耗大量服务器资源,cookie 在每次 HTTP 请求中都会带上,影响网络性能 49 | - 域的支持范围不一样,比方说 a.com 的 Cookie 在 a.com 下都能用,而 www.a.com 的 Session 在 api.a.com 下都不能用 50 | -------------------------------------------------------------------------------- /0-前端基础/JS/其他题目.md: -------------------------------------------------------------------------------- 1 | ### 用 Array 的 reduce 方法实现 map 方法(头条一面) 2 | 3 | ### 求一个字符串的字节长度 4 | 5 | 假设:一个英文字符占用一个字节,一个中文字符占用两个字节 6 | 7 | ```js 8 | function GetBytes(str) { 9 | var len = str.length; 10 | var bytes = len; 11 | for (var i = 0; i < len; i++) { 12 | if (str.charCodeAt(i) > 255) bytes++; 13 | } 14 | return bytes; 15 | } 16 | alert(GetBytes("你好,as")); 17 | ``` 18 | 19 | ### 数组扁平化 20 | 21 | 数组扁平化是指将一个多维数组变为一维数组 22 | 23 | ```js 24 | [1, [2, 3, [4, 5]]]------ > [1, 2, 3, 4, 5]; 25 | ``` 26 | 27 | 递归法: 28 | 29 | ```js 30 | function flatten(arr) { 31 | let res = []; 32 | arr.map((item) => { 33 | if (Array.isArray(item)) { 34 | res = res.concat(flatten(item)); 35 | } else { 36 | res.push(item); 37 | } 38 | }); 39 | return res; 40 | } 41 | ``` 42 | 43 | ### 手写原生 ajax 44 | 45 | 简单 GET 请求 46 | 47 | ```js 48 | function ajax(url, cb) { 49 | let xhr; 50 | if (window.XMLHttpRequest) { 51 | xhr = new XMLHttpRequest(); 52 | } else { 53 | xhr = ActiveXObject("Microsoft.XMLHTTP"); 54 | } 55 | xhr.onreadystatechange = function () { 56 | if (xhr.readyState == 4 && xhr.status == 200) { 57 | cb(xhr.responseText); 58 | } 59 | }; 60 | xhr.open("GET", url, true); 61 | xhr.send(); 62 | } 63 | ``` 64 | 65 | POST 请求则需要设置`RequestHeader`告诉后台传递内容的编码方式以及在 send 方法里传入对应的值 66 | 67 | ```js 68 | xhr.open("POST", url, true); 69 | xhr.setRequestHeader(("Content-Type": "application/x-www-form-urlencoded")); 70 | xhr.send("key1=value1&key2=value2"); 71 | ``` 72 | -------------------------------------------------------------------------------- /5-性能优化/编写高性能的Javascript.md: -------------------------------------------------------------------------------- 1 | ### 常见编码规范 2 | 3 | - 将 js 脚本放在页面底部,加快渲染页面 4 | - 将 js 脚本将脚本成组打包,减少请求 5 | - 使用非阻塞方式下载 js 脚本 6 | - 尽量使用局部变量来保存全局变量 7 | - 遵循严格模式:"use strict"; 8 | - 尽量减少使用闭包 9 | - 减少对象成员嵌套 10 | - 缓存 DOM 节点访问 11 | - 避免使用 eval()和 Function()构造器 12 | - 尽量使用直接量取创建对象和数组 13 | - 最小化重绘(repaint)和回流(reflow) 14 | 15 | ### 为什么 JS 要放到 body 尾部? 16 | 17 | 如果 JS 需要绑定操作 DOM,那么放在 header 中如果处理不当就不会绑定到 DOM 18 | 19 | **JS 引擎是独立于渲染引擎存在的。**我们的 JS 代码在文档的何处插入,就在何处执行。当 HTML 解析器遇到一个 script 标签时,它会暂停渲染过程,将控制权交给 JS 引擎。JS 引擎对内联的 JS 代码会直接执行,对外部 JS 文件还要先获取到脚本、再进行执行。等 JS 引擎运行完毕,浏览器又会把控制权还给渲染引擎,继续 CSSOM 和 DOM 的构建。 20 | 21 | 浏览器之所以让 JS 阻塞其它的活动,是因为它不知道 JS 会做什么改变,担心如果不阻止后续的操作,会造成混乱。 22 | 23 | 结论: 24 | 25 | - **如果 JS 在 header 中,浏览器会阻塞并等待 JS 加载完毕并执行** 26 | - **如果 JS 在 body 尾部,览器会进行一次提前渲染,从而提前首屏出现时间** 27 | 28 | 参考 demo: 执行`/性能优化/testDemo/slowServer/index.js`,注意查看终端 29 | 30 | ### 非核心代码的异步加载 31 | 32 | - 动态脚本加载 33 | - 使用 JS 创建一个 script 标签再插入到页面中 34 | - defer(IE) 35 | - 整个 HTML**解析完**后才会执行,如果是多个,按照加载顺序依次执行 36 | - async 37 | - **加载完**之后立即执行,如果是多个,执行和加载顺序无关 38 | 39 | ### header 中 meta 40 | 41 | 兼容性配置,让 IE 使用最高级的 Edge 渲染,如果有 chrome 就使用 chrome 渲染。 42 | 43 | ```html 44 | 45 | ``` 46 | 47 | 如果是双核浏览器,优先使用 webkit 引擎 48 | 49 | ```html 50 | 51 | ``` 52 | 53 | ### 使用节流和防抖 54 | 55 | ### 懒加载 56 | 57 | 懒加载的原理就是只加载自定义区域(通常是可视区域,但也可以是即将进入可视区域)内需要加载的东西。 58 | 对于图片来说,先设置图片标签的 src 属性为一张占位图或为空,将真实的图片资源放入一个自定义属性中,当进入自定义区域时,就将自定义属性替换为 src 属性,这样图片就会去下载资源,实现了图片懒加载。 59 | -------------------------------------------------------------------------------- /1-前端框架与库/React/基础/VDOM.md: -------------------------------------------------------------------------------- 1 | - VDOM 是什么?为什么会存在 VDOM? 2 | - VDOM 如何应用,核心 API 是什么 3 | - 介绍 diff 算法 4 | 5 | ### VDOM 是什么?为什么会存在 VDOM? 6 | 7 | 在 MVVM 开发方式中,页面的变化都是用数据去驱动的,而数据更新后,到底要去改那一块的 DOM 哪? 8 | 虽然可以先删除那个部分再按照当前新的数据去重新生成一个新的页面或生成那一个部分(jQuery 做法),但是这样肯定非常耗费性能的。 9 | 而且 JS 操作 DOM 是非常复杂,JS 操作 DOM 越多,控制与页面的耦合度就越高,代码越难以维护。 10 | 11 | 虚拟 DOM,即用 JS 对象来描述 DOM 树结构,Diff 算法则是找旧 VDOM 与新的 VDOM 的最小差异,然后再把差异渲染出来 12 | 13 | ![DOM](../../img/domtree.png) 14 | ![vdom](../../img/vdon.png) 15 | 16 | 描述一个 DOM 节点 17 | 18 | - tag 标签名 19 | - attrs DOM 属性键值对 20 | - childen DOM 字节点数组 或 文本内容 21 | 22 | [如何理解虚拟 DOM?-zhihu](https://www.zhihu.com/question/29504639?sort=created) 23 | 24 | ### 为什么 DOM 操作慢? 因为属性太多了 25 | 26 | ![domattr](../../img/domattr.png) 27 | 28 | ### vdom 如何应用,核心 API 是什么 29 | 30 | - 创建虚拟节点 31 | - h('标签名', {...属性...}, [...子元素...]) 32 | - h('标签名', {...属性...}, '文本内容') 33 | - 将 VNode 添加到一个 DOM 元素内 34 | - patch(DOM_obj, vnode); 35 | - 用一个新的 vnode 来和旧的 vnode 进行比较,得出新旧 dom 的差异 36 | - patch(vnode, newVnode) 37 | 38 | ### diff 算法 39 | 40 | 对比 Vdom 树差异的算法 41 | [React 的 diff 算法](https://segmentfault.com/a/1190000000606216) 42 | 43 | #### 同层比对 44 | 45 | 新旧状态的比对时采用同层比对,当发现某节点不一致了直接替换该节点的子树。而不管它的子树是不是真的改动了。 46 | 47 | #### key 值的使用 48 | 49 | 在列表循环的时候 React 会要求每一个列表项有一个**独一无二**,**稳定的 key 值**,它的目的是为了当状态改变时新旧状态的每一个列表项能够对应起来,方便比对。 50 | 51 | Keys 是 React 用于追踪哪些列表中元素被修改、被添加或者被移除的辅助标识。 52 | Diff 算法中 React 会借助元素的 Key 值来判断该元素是新近创建的还是被移动而来的元素,从而减少不必要的元素重渲染。此外,React 还需要借助 Key 值来判断元素与本地状态的关联关系 53 | 54 | #### 合并操作 55 | 56 | 调用 component 的 setState 方法的时候, React 将其标记为 dirty.到每一个事件循环结束, React 检查所有标记 dirty 的 component 重新绘制 57 | -------------------------------------------------------------------------------- /0-前端基础/NodeJS/核心模块/path.md: -------------------------------------------------------------------------------- 1 | # path 2 | 3 | path 模块提供用于处理文件路径和目录路径的实用工具。 4 | 5 | ### normalize、join、resolve 6 | 7 | - path.normalize() 方法规范化给定的 path,解析 '..' 和 '.' 片段。 8 | 9 | ```js 10 | path.normalize("/foo/bar//baz/asdf/quux/.."); 11 | // 返回: '/foo/bar/baz/asdf' 12 | ``` 13 | 14 | - path.join 方法使用平台特定分隔符作为定界符将所有给定的 path 片段连接在一起,然后生成规范的路径 15 | 16 | ```js 17 | path.join("/foo", "bar", "baz/asdf", ".."); 18 | // 返回: '/foo/bar/baz/asdf' 19 | ``` 20 | 21 | - path.resolve([...paths])把一个相对路径解析成一个绝对路径。 22 | 23 | ```js 24 | [path.join([...paths])](path.resolve('wwwroot', 'static_files/png/', '../gif/image.gif'); 25 | // 如果当前工作目录是 /home/myself/node, 26 | // 则返回 '/home/myself/node/wwwroot/static_files/gif/image.gif') 27 | ``` 28 | 29 | ### basename、dirname、extname 30 | 31 | - basename 32 | - 文件名.拓展名 33 | - dirname 34 | - 所在的文件夹 35 | - extname 36 | - 拓展名是什么 37 | 38 | ``` 39 | ┌─────────────────────┬────────────┐ 40 | │ dir │ base │ 41 | ├──────┬ ├──────┬─────┤ 42 | │ root │ │ name │ ext │ 43 | " / home/user/dir / file .txt " 44 | └──────┴──────────────┴──────┴─────┘ 45 | ``` 46 | 47 | ### parse 与 format 48 | 49 | - parse 是将字符串形式的文件路径给解析成一个包含 root, dir, base, name, ext 属性的对象 50 | - format 则是将这个对象代表的路径转成字符串形式,与 parse 相反 51 | 52 | 如果有了一个路径指向修改其中的一个内容,那么就可以使用 parse 转成对象然后修改后使用 format 在转成一个新路径。 53 | 54 | 当为 pathObject 提供属性时,注意以下组合,其中一些属性优先于另一些属性: 55 | 56 | - 如果提供了 pathObject.dir,则忽略 pathObject.root。 57 | - 如果 pathObject.base 存在,则忽略 pathObject.ext 和 pathObject.name。 58 | 59 | ### sep、delimiter、win32、posix 60 | 61 | - sep 提供平台特定的路径片段分隔符: 62 | - Windows 上是 \;POSIX 上是 / 63 | -------------------------------------------------------------------------------- /杂项/如何写技术文章(分享型).md: -------------------------------------------------------------------------------- 1 | # 如何写技术文章(分享型) 2 | 3 | ## 选择合理的内容 4 | 5 | 选择合理的内容技术那么多,到底哪种适合写哪种不适合写? 6 | 常见的适合成文的内容有: 7 | 8 | - 新出现的技术 9 | - 工程中解决问题的方法 10 | - 高深问题的剖析 11 | - 被大多数人忽略的重要细节 12 | 13 | 文章内容的范围不宜过大,写大而全的东西对作者的水平要求非常高且需要消耗大量精力。如果真想写,也请先把思路理清,与有经验的人交流之后再下笔。 14 | 一个小技巧是:在写文章之前,先把自己想写的主题用搜索引擎中搜一下,考虑自己是否有信心有能力超过已有文章。如果没有相关文章,那么可以先写入门级的内容,根据社区反馈逐步深入。 15 | 16 | ## 确保内容的准确性 17 | 18 | 自己挑选的写作内容多是自己摸透了的东西,但是在细节上可能有模糊不清的地方。注意,你模糊不清的地方也正是许多人看此文的动机,务必查阅文献将此处叙述清楚!但又不可沉溺于细节之中,以能讲明白上下文为宜(更深入的细节适合另起一文)。另外,类似选型、对比、趋势一类的文章,对行业整体的把握也非常重要,在表达自己的观点之前,应该充分了解其它人的看法,尤其是和自己观点相左的看法。 19 | 20 | ## 文章结构 21 | 22 | 优秀文章套路基本相似,问题文章则各有各的缺点。这里我用“起承转合”四字来概括基本套路。 23 | 24 | ### “起” 25 | 26 | 忘了是谁说的,好的开头是成功的一半。 27 | 一般来说,在文章开头,你需要交代写作缘起,如业务遭遇痛点、线上神秘 bug 等。 28 | 而后,简要介绍文章将从哪些方面展开、达到什么目的,而读者能从中获得何种收获。 29 | 30 | ### “承” 31 | 32 | 承接开头,开始按事先整理的大纲,切入正题。可以开始详细介绍相关场景、探索解决方案的历程。 33 | 需要注意的是,始终不能忘记目标受众。根据目标受众特点,注意在必要的地方,提供必要的背景知识,如某项技术的发展历史及相关术语介绍。 34 | 35 | ### “转” 36 | 37 | 经过前面的充分铺垫,话题转入突破阶段。可以详细介绍你所寻找到的突破方案及其效果。如有多种方案,建议同时列出,并加以对比。 38 | 39 | ### “合” 40 | 41 | 回顾全文,适当总结: 42 | 43 | - 文章解决了什么问题? 44 | - 还可以进行哪些方向的探索? 45 | - 有何不足之处? 46 | - 展望未来 47 | 48 | ## 注意事项 49 | 50 | 在写作过程中,有一些细节需要注意。 51 | 切忌以下问题 52 | 53 | - 罗列大量术语:全无背景介绍,直接开始罗列一堆概念 54 | - 粘贴长篇代码:大篇幅引用代码,影响阅读体验 55 | - 风格变化无常:时而严肃、学术风,时而卖萌、抖机灵 56 | - 内容贪图简便:使用代码块、图片或 blockquote 完全取代正文 57 | 58 | ## 总结 59 | 60 | 总的来说,一篇优秀的技术文需要有: 61 | 62 | - 简洁朴实的标题 63 | - 不易重复的内容 64 | - 内容表述准确 65 | - 细节描述清析 66 | - 良好的格式和排版 67 | 68 | 成文之后,须通读一遍文章。将自己代入读者的思维,边读边考虑在没有为写作本文而学习的知识的前提下,能否读懂文章。 69 | 70 | ## 参考链接 71 | 72 | 1. https://juejin.im/post/6858621112277237767 73 | 2. https://juejin.im/post/6844903504922804238 74 | -------------------------------------------------------------------------------- /实用工具与库/npm/package-lock.json.md: -------------------------------------------------------------------------------- 1 | # package-lock.json 2 | 3 | 概括很简单,就是锁定安装时的包的版本号,并且需要上传到 git,以保证其他人在 npm install 时大家的依赖能保证一致。 4 | 5 | 根据官方文档,这个 package-lock.json 是在 `npm install`时候生成一份文件,用以记录当前状态下实际安装的各个 npm package 的具体来源和版本号。 6 | 7 | 它有什么用呢?因为 npm 是一个用于管理 package 之间依赖关系的管理器,它允许开发者在 pacakge.json 中间标出自己项目对 npm 各库包的依赖。你可以选择以如下方式来标明自己所需要库包的版本 8 | 9 | 这里举个例子: 10 | 11 | ```json 12 | "dependencies": { 13 | "@types/node": "^8.0.33", 14 | }, 15 | ``` 16 | 17 | 这里面的 向上标号^是定义了向后(新)兼容依赖,指如果 types/node 的版本是超过 8.0.33,并在大版本号(8)上相同,就允许下载最新版本的 types/node 库包,例如实际上可能运行 npm install 时候下载的具体版本是 8.0.35。 18 | 19 | 大多数情况这种向新兼容依赖下载最新库包的时候都没有问题,可是因为 npm 是开源世界,各库包的版本语义可能并不相同,有的库包开发者并不遵守严格这一原则:相同大版本号的同一个库包,其接口符合兼容要求。这时候用户就很头疼了:在完全相同的一个 nodejs 的代码库,在不同时间或者不同 npm 下载源之下,下到的各依赖库包版本可能有所不同,因此其依赖库包行为特征也不同有时候甚至完全不兼容。 20 | 21 | 因此 npm 最新的版本就开始提供自动生成 package-lock.json 功能,为的是让开发者知道只要你保存了源文件,到一个新的机器上、或者新的下载源,只要按照这个 package-lock.json 所标示的具体版本下载依赖库包,就能确保所有库包与你上次安装的完全一样。 22 | 23 | [package-lock.json | 官方文档](https://docs.npmjs.com/files/package-lock.json) 24 | 25 | ### semver 语义化版本号变更 26 | 27 | `^` 是 npm 默认的版本符号, 当你使用 npm install --save 时, npm 会自动在 package 中添加^加上版本号. 例如: npm install --save angular 会在 package.json 中添加"angular": "^1.3.15".这个符号会告诉 npm 可以安装 1.3.15 或者一个大于它的版本, 但是要是主版本 1 下的版本. 28 | 29 | `~` 同样被用来做 npm 得版本控制, 例如~1.3.15, 代表了 npm 可以安装 1.3.15 或者更高的版本, 与^的区别在于, ~的版本只能开始于次版本号 1.3. 它们的作用域不同. 你可以通过 npm config set save-prefix='~'将~设置为默认符号. 30 | 31 | `>`符号主要是用来指定可以安装 beta 版本. 32 | 33 | [semver 版本号 | 官方文档](https://semver.org/lang/zh-CN/) 34 | 35 | `devDependencies` 节点下的模块是我们在开发时需要用的,比如项目中使用的 gulp ,压缩 css、js 的模块。这些模块在我们的项目部署后是不需要的,所以我们可以使用 -save-dev 的形式安装 36 | -------------------------------------------------------------------------------- /0-前端基础/CSS/布局/README.md: -------------------------------------------------------------------------------- 1 | # 布局 2 | 3 | ## Flex 布局 4 | 5 | [Flex - 阮一峰 (语法篇)](http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html) 6 | [Flex - 阮一峰 (实战篇)](http://www.ruanyifeng.com/blog/2015/07/flex-examples.html) 7 | 8 | ## grid 网格布局 9 | 10 | [grid 网格布局](https://www.imooc.com/article/28513) 11 | 12 | ## 三栏布局 13 | 14 | 假设高度已知,请写出三栏布局,其中左右栏宽 300px,中间自适应 15 | 16 | ### 圣杯布局 17 | 18 | 要求:三列布局;中间宽度自适应,两边内容定宽。 19 | 20 | 好处:重要的内容放在文档流前面可以优先渲染 21 | 22 | 原理:利用相对定位、浮动、负边距布局,而不添加额外标签 23 | 24 | 实现方式: 25 | 26 | main 部分首先要放在 container 的最前部分。然后是 left,right 27 | 28 | 1.将三者都 float:left , 再加上一个 position:relative (因为相对定位后面会用到) 29 | 30 | 2.main 部分 width:100%占满 31 | 32 | 3.此时 main 占满了,所以要把 left 拉到最左边,使用 margin-left:-100% 33 | 34 | 4.这时 left 拉回来了,但会覆盖 main 内容的左端,要把 main 内容拉出来,所以在外围 container 加上 padding:0 220px 0 200px 35 | 36 | 5.main 内容拉回来了,right 也跟着过来了,所以要还原,就对 left 使用相对定位 left:-200px 同理,right 也要相对定位还原 right:-220px 37 | 38 | 6.到这里大概就自适应好了。如果想 container 高度保持一致可以给 left main right 都加上 min-height:130px 39 | 40 | ### 双飞翼布局 41 | 42 | 原理:主体元素上设置左右边距,预留两翼位置。左右两栏使用浮动和负边距归位。 43 | 44 | 左翅 left 有 200px,右翅 right..220px.. 身体 main 自适应未知 45 | 46 | 1.html 代码中,main 要放最前边,left right 47 | 48 | 2.将 main left right 都 float:left 49 | 50 | 3.将 main 占满 width:100% 51 | 52 | 4.此时 main 占满了,所以要把 left 拉到最左边,使用 margin-left:-100% 同理 right 使用 margin-left:-220px 53 | 54 | (这时可以直接继续上边圣杯布局的步骤,也可以有所改动) 55 | 56 | 5.main 内容被覆盖了吧,除了使用外围的 padding,还可以考虑使用 margin。 57 | 58 | 给 main 增加一个内层 div-- main-inner, 然后 margin:0 220px 0 200px 59 | 60 | ### 响应式设计和布局 61 | 62 | 在不同设备上正常使用,一般主要处理屏幕大小问题 63 | 64 | - 隐藏 + 折行 + 自适应空间 65 | - rem 做单位 66 | - viewport 67 | - width=divice-width, 68 | - 媒体查询 69 | -------------------------------------------------------------------------------- /1-前端框架与库/TypeScript/实用技巧.md: -------------------------------------------------------------------------------- 1 | # 实用技巧 2 | 3 | ### 让数组的值作为联合类型 4 | 5 | ```ts 6 | const COLOR = ["red", "green", "blue"] as const; 7 | type ColorType = typeof COLOR[number]; // "red" | "green" | "blue" 8 | ``` 9 | 10 | ### 让对象的 key 值为联合类型 11 | 12 | ```ts 13 | type ColorType = "red" | "green" | "blue"; 14 | 15 | type colorsCall = { 16 | [color in ColorType]: () => void; 17 | }; 18 | 19 | // colorsCall 的类型: 20 | { 21 | red: () => void; 22 | green: () => void; 23 | blue: () => void; 24 | } 25 | ``` 26 | 27 | ### Record 28 | 29 | 以 typeof 格式快速创建一个类型,此类型包含一组指定的属性且都是必填。 30 | 31 | ```ts 32 | type Coord = Record<"x" | "y", number>; 33 | 34 | // 等同于 35 | type Coord = { 36 | x: number; 37 | y: number; 38 | }; 39 | ``` 40 | 41 | KV都是 string 的健值对 42 | 43 | ```ts 44 | type StingKV = Record 45 | ``` 46 | 47 | ### 范型 48 | 49 | [Playground](https://www.typescriptlang.org/play?#code/FASwdgLgpgTgZgQwMZQAQAUA2CwHkBGAVlEhAOogQAWAcgK4C2+sAagpnWgN7CqoDaAaygBPAFyoAzhBjgA5gF0JYRsxgBuYAF9gwJAHsw01NGMBeVAB4AKqigAPaGAAmkjNjxES5SrVWt2TgA+AApeKQgEGAgAZUjoCWsAGmAASlQzINQePgMjfUwoADpMfTkQ6SjY+KhU7V1waHhkNAAxfX1s8IRlfw1w-F6mWE0dPUNjOA6Jds6LHNQe1ABGFL5B1AAmeuBTCBCp-VSgA) 50 | 51 | ```ts 52 | interface PlanObjectWithNumberValue { 53 | [key: string]: number; 54 | } 55 | 56 | const test = (startState: T) => { 57 | console.log(startState); 58 | }; 59 | 60 | interface Foo { 61 | a: number; 62 | b: number; 63 | } 64 | 65 | const foo: Foo = { 66 | a: 1, 67 | b: 2, 68 | }; 69 | 70 | // 这里会报错 71 | test(foo); 72 | ``` 73 | 74 | 报错解法: 75 | 76 | 1. 让 Foo 也继承 PlanObjectWithNumberValue 77 | 2. 使用 Record 78 | -------------------------------------------------------------------------------- /5-性能优化/testDemo/slowServer/js-bottom.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 13 | 14 | 15 |
16 | 内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容 17 |
18 |
19 | 内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容 20 |
21 |
22 | 内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容 23 |
24 |
25 | 内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容 26 |
27 |
28 | 内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容 29 |
30 |
31 | 内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容 32 |
33 |
34 | 内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容 35 |
36 |
37 | 内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容 38 |
39 |
40 | 内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容 41 |
42 |
43 | 内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容 44 |
45 |
46 | 内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容 47 |
48 |
49 | 内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容 50 |
51 |
52 | 内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容 53 |
54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /5-性能优化/testDemo/slowServer/js-header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 14 | 15 | 16 | 17 | 18 |
19 | 内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容 20 |
21 |
22 | 内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容 23 |
24 |
25 | 内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容 26 |
27 |
28 | 内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容 29 |
30 |
31 | 内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容 32 |
33 |
34 | 内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容 35 |
36 |
37 | 内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容 38 |
39 |
40 | 内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容 41 |
42 |
43 | 内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容 44 |
45 |
46 | 内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容 47 |
48 |
49 | 内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容 50 |
51 |
52 | 内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容 53 |
54 |
55 | 内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容 56 |
57 | 58 | 59 | -------------------------------------------------------------------------------- /杂项/优雅代码.md: -------------------------------------------------------------------------------- 1 | # 优雅代码 2 | 3 | ### If 语句 4 | 5 | bad 6 | 7 | ```js 8 | if (value === "duck" || value === "dog" || value === "cat") { 9 | // ... 10 | } 11 | ``` 12 | 13 | good 14 | 15 | ```js 16 | const options = ["duck", "dog", "cat"]; 17 | if (options.includes(value)) { 18 | // ... 19 | } 20 | ``` 21 | 22 | ### 提前退出机制 23 | 24 | ```js 25 | function handleEvent(event) { 26 | if (event) { 27 | const target = event.target; 28 | if (target) { 29 | // ... 30 | } 31 | } 32 | } 33 | ``` 34 | 35 | 使用提前退出,减少嵌套 36 | 37 | ```js 38 | function handleEvent(event) { 39 | if (!event || !event.target) { 40 | return; 41 | } 42 | // ... 43 | } 44 | ``` 45 | 46 | ### 返回数组 47 | 48 | 如果一个函数只有少量几个返回值,但调用方在使用此函数时大概率会将返回的值改名,那就返回数组 49 | 50 | bad 51 | 52 | ```js 53 | const useState = () => { 54 | return { 55 | state, 56 | setState, 57 | }; 58 | }; 59 | ``` 60 | 61 | good 62 | 63 | ```js 64 | // 函数 65 | const useState = () => { 66 | return [state, setState]; 67 | }; 68 | 69 | // 调用 70 | const [data, setData] = useState(); 71 | ``` 72 | 73 | ### 使用 Map 来代替静态的 switch case 74 | 75 | 如果明确知道映射关系,如 TS 类型定义好了。并且没有什么计算逻辑,就可以使 Map 提示代码整洁度。 76 | 77 | bad 78 | 79 | ```js 80 | const getTranslate = (en) => { 81 | switch (en) { 82 | case "apple": 83 | return "苹果"; 84 | case "banana": 85 | return "香蕉"; 86 | case "orange": 87 | return "橘子"; 88 | } 89 | }; 90 | ``` 91 | 92 | good 93 | 94 | ```js 95 | const translateMap = { 96 | apple: "苹果", 97 | banana: "香蕉", 98 | orange: "橘子", 99 | }; 100 | const getTranslate = (en) => { 101 | return translateMap[en]; 102 | }; 103 | ``` 104 | -------------------------------------------------------------------------------- /0-前端基础/JS/ServiceWorker.md: -------------------------------------------------------------------------------- 1 | # Service Worker 2 | 3 | Service Worker 是运行在浏览器背后的独立线程,一般可以用来实现缓存功能。使用 Service Worker 的话,传输协议必须为 HTTPS。因为 Service Worker 中涉及到请求拦截,所以必须使用 HTTPS 协议来保障安全。 4 | 5 | Service Worker 实现缓存功能一般分为三个步骤:首先需要先注册 Service Worker,然后监听到 install 事件以后就可以缓存需要的文件,那么在下次用户访问的时候就可以通过拦截请求的方式查询是否存在缓存,存在缓存的话就可以直接读取缓存文件,否则就去请求数据。以下是这个步骤的实现: 6 | 7 | ```js 8 | // index.js 9 | if (navigator.serviceWorker) { 10 | navigator.serviceWorker 11 | .register("sw.js") 12 | .then(function (registration) { 13 | console.log("service worker 注册成功"); 14 | }) 15 | .catch(function (err) { 16 | console.log("servcie worker 注册失败"); 17 | }); 18 | } 19 | // sw.js 20 | // 监听 `install` 事件,回调中缓存所需文件 21 | self.addEventListener("install", (e) => { 22 | e.waitUntil( 23 | caches.open("my-cache").then(function (cache) { 24 | return cache.addAll(["./index.html", "./index.js"]); 25 | }) 26 | ); 27 | }); 28 | 29 | // 拦截所有请求事件 30 | // 如果缓存中已经有请求的数据就直接用缓存,否则去请求数据 31 | self.addEventListener("fetch", (e) => { 32 | e.respondWith( 33 | caches.match(e.request).then(function (response) { 34 | if (response) { 35 | return response; 36 | } 37 | console.log("fetch source"); 38 | }) 39 | ); 40 | }); 41 | ``` 42 | 43 | 打开页面,可以在开发者工具中的 Application 看到 Service Worker 已经启动了 44 | ![](../../img/serviceWorker.png) 45 | 46 | 在 Cache 中也可以发现我们所需的文件已被缓存 47 | ![](../../img/cache-worker.png) 48 | 49 | 当我们重新刷新页面可以发现我们缓存的数据是从 Service Worker 中读取的 50 | ![](../../img/reload-worker.png) 51 | 52 | ### 好文链接 53 | 54 | - https://www.zcfy.cc/article/service-worker-what-are-you-mariko-kosaka-1927.html 55 | - https://juejin.im/post/5ba0fe356fb9a05d2c43a25c 56 | - https://juejin.im/post/5bf3f656e51d45338e084044 57 | - https://juejin.im/post/5bf3f6b2e51d45360069e527 58 | -------------------------------------------------------------------------------- /1-前端框架与库/React/Hooks/README.md: -------------------------------------------------------------------------------- 1 | # React Hooks 2 | 3 | Hook 是一些可以让你在函数组件里“钩入” React state 及生命周期等特性的函数。Hook 不能在 class 组件中使用 4 | 5 | ### Hook 使用规则 6 | 7 | - 只能在函数最外层调用 Hook。不可在循环、条件判断或者子函数中调用。 8 | - 调用`useState`时,大家都是调用这个函数,React 怎么知道应该在渲染的时候给你返回哪个值呢? 其 9 | - 只能在 React 的函数组件或自定义的 Hook 中调用 Hook。不要在其他 JavaScript 函数中调用。 10 | 11 | 可以使用`eslint-plugin-react-hooks`来检测,在 Webpack 中添加配置如下: 12 | 13 | ```json 14 | "eslintConfig": { 15 | "extends": "react-app", 16 | "plugins": [ 17 | "react-hooks" 18 | ], 19 | "rules": { 20 | "react-hooks/rules-of-hooks":"error" 21 | } 22 | }, 23 | ``` 24 | 25 | ### Hook 如何把调用和组件联系起来的? 26 | 27 | React 保持对当先渲染中的组件的追踪。多亏了 Hook 规范,我们得知 Hook 只会在 React 组件中被调用(或自定义 Hook —— 同样只会在 React 组件中被调用)。 28 | 29 | 每个组件内部都有一个「记忆单元格」列表。它们只不过是我们用来存储一些数据的 JavaScript 对象。当你用 useState() 调用一个 Hook 的时候,它会读取当前的单元格(或在首次渲染时将其初始化),然后把指针移动到下一个。这就是多个 useState() 调用会得到各自独立的本地 state 的原因。 30 | 31 | ### 类组件不足 32 | 33 | - 状态逻辑难以复用 34 | - 缺少复用机制 35 | - 不方便封装逻辑,使用渲染属性和高阶组件也有缺点 36 | - 渲染属性和高阶组件导致层级冗余 37 | - 无论是高阶组件还是渲染属性,都相当与在原来的组件之上增加了新的组件层次。尤其是在 Chrome 调试器上会看到为了服用逻辑而添加的狠多组件层级,显得十分臃肿。不仅是调试体验问题、也存在着运行性能的问题 38 | - 趋向复杂时难以维护 39 | - 生命周期函数函数混杂不相干逻辑 40 | - 相关逻辑代码经常会打散到不同生命周期中 41 | - this 指向困扰 42 | - 内联函数需要绑定 this, 否则每次渲染都创建一个箭头函数 43 | - 类成员函数不能保证 this 44 | 45 | ### hooks 优势 46 | 47 | - 函数组件无类实例 this 问题 48 | 49 | - hooks 是函数组件环境,所有逻辑都在函数内部,没有实例化概念,无复杂的 this 问题 50 | 51 | - 自定义 Hook 函数方便复用状态逻辑 52 | 53 | - hooks 指的是在函数内部调用的特殊函数,我们可以自定义 hooks 函数,在 hooks 函数内部,依旧可以调用 useState 和 useEffect 等 hooks 函数。这样就可以非常高效的将可复用逻辑提取出来 54 | 55 | - 副作用的关注点分离 56 | - hooks 天生优化了副作用代码逻辑 57 | - 每个 useEffect 来实现一个逻辑,不同逻辑写在不同的 useEffect 中,比冗在同一生命周期中好很多 58 | - 以前副作用大都是写在生命函数周期中 59 | - 副作用: 60 | - 发送网络请求 61 | - 访问原始 DOM 元素 62 | - 访问本地存储 63 | - 绑定解绑事件 64 | -------------------------------------------------------------------------------- /3-编程能力/编程题与分析题/this指向.md: -------------------------------------------------------------------------------- 1 | # this 指向 2 | 3 | ### 头条一面 4 | 5 | 请分别写出下面题目的答案。 6 | 7 | ```js 8 | function Foo() { 9 | getName = function () { 10 | console.log(1); 11 | }; 12 | return this; 13 | } 14 | Foo.getName = function () { 15 | console.log(2); 16 | }; 17 | Foo.prototype.getName = function () { 18 | console.log(3); 19 | }; 20 | var getName = function () { 21 | console.log(4); 22 | }; 23 | 24 | function getName() { 25 | console.log(5); 26 | } 27 | 28 | //请写出以下输出结果: 29 | Foo.getName(); //-> 2 Foo对象上的getName() ,这里不会是3,因为只有Foo的实例对象才会是3,Foo上面是没有3的 30 | getName(); //-> 4 window上的getName,console.log(5)的那个函数提升后,在console.log(4)的那里被重新赋值 31 | Foo().getName(); //-> 1 在Foo函数中,getName是全局的getName,覆盖后输出 1 32 | getName(); //-> 1 window中getName(); 33 | new Foo.getName(); //-> 2 Foo后面不带括号而直接 '.',那么点的优先级会比new的高,所以把 Foo.getName 作为构造函数 34 | new Foo().getName(); //-> 3 此时是Foo的实例,原型上会有输出3这个方法 35 | ``` 36 | 37 | ### 箭头函数中的 this 判断 38 | 39 | 箭头函数里面的 this 是继承它作用域父级的 this, 即声明箭头函数处的 this 40 | 41 | ```js 42 | let a = { 43 | b: function () { 44 | console.log(this); 45 | }, 46 | c: () => { 47 | console.log(this); 48 | }, 49 | }; 50 | 51 | a.b(); // a 52 | a.c(); // window 53 | 54 | let d = a.b; 55 | d(); // window 56 | ``` 57 | 58 | ### this 判断 下面输出为多少? 59 | 60 | ```js 61 | var name1 = 1; 62 | 63 | function test() { 64 | let name1 = "kin"; 65 | let a = { 66 | name1: "jack", 67 | fn: () => { 68 | var name1 = "black"; 69 | console.log(this.name1); 70 | }, 71 | }; 72 | return a; 73 | } 74 | 75 | test().fn(); // ? 76 | ``` 77 | 78 | 答案: 输出 1 79 | 80 | 因为 fn 处绑定的是箭头函数,箭头函数并不创建 this,它只会从自己的作用域链的上一层继承 this。这里它的上一层是 test(),非严格模式下 test 中 this 值为 window。 81 | 82 | - 如果在绑定 fn 的时候使用了 function,那么答案会是 'jack' 83 | - 如果第一行的 var 改为了 let,那么答案会是 undefind, 因为 let 不会挂到 window 上 84 | -------------------------------------------------------------------------------- /1-前端框架与库/TypeScript/接口.md: -------------------------------------------------------------------------------- 1 | # 接口 2 | 3 | 描述对象、函数、类,接口中描述的属性都必须包含,但对象有其他一些属性、接口未定义不会报错。 4 | 5 | ```js 6 | interface LabelledValue { 7 | label: string; 8 | } 9 | 10 | function printLabel(labelledObj: LabelledValue) { 11 | console.log(labelledObj.label); 12 | } 13 | ``` 14 | 15 | ### 可选属性 16 | 17 | ```js 18 | interface SquareConfig { 19 | color?: string 20 | width?: number 21 | } 22 | ``` 23 | 24 | ### 只读属性 25 | 26 | ```js 27 | interface Point { 28 | readonly x: number 29 | readonly y: number 30 | } 31 | ``` 32 | 33 | ### 可索引的类型 34 | 35 | 描述了对象索引的类型,还有相应的索引返回值类型。 36 | 37 | ```js 38 | interface StringArray { 39 | [index: number]: string; 40 | } 41 | 42 | let myArray: StringArray; 43 | myArray = ["Bob", "Fred"]; 44 | ``` 45 | 46 | ### 继承接口 47 | 48 | 继承接口,使得接口可分割到更多重用的模块里。 49 | 50 | ```js 51 | interface Shape { 52 | color: string; 53 | } 54 | 55 | interface Square extends Shape { 56 | sideLength: number; 57 | } 58 | ``` 59 | 60 | ### 混合类型 61 | 62 | 在函数上定义一些属性 63 | 64 | ```js 65 | interface Counter { 66 | (start: number): string 67 | interval: number 68 | reset(): void 69 | } 70 | 71 | function getCounter(): Counter { 72 | let counter = (function (start: number) { }) as Counter 73 | counter.interval = 123 74 | counter.reset = function () { } 75 | return counter 76 | } 77 | 78 | let c = getCounter() 79 | c(10) 80 | c.reset() 81 | c.interval = 5.0 82 | ``` 83 | 84 | ### 类继承接口 85 | 86 | 实现接口 87 | 88 | ```js 89 | interface ClockInterface { 90 | currentTime: Date; 91 | } 92 | 93 | class Clock implements ClockInterface { 94 | currentTime: Date; 95 | constructor(h: number, m: number) {} 96 | } 97 | ``` 98 | 99 | ### 接口继承类 100 | 101 | 会继承类的成员但不包括其实现。 接口同样会继承到类的 private 和 protected 成员。 这意味着当你创建了一个接口继承了一个拥有私有或受保护的成员的类时,这个接口类型只能被这个类或其子类所实现(implement)。 102 | -------------------------------------------------------------------------------- /3-编程能力/编程题与分析题/PromiseAll.md: -------------------------------------------------------------------------------- 1 | # Promise.all 2 | 3 | Promise.all 接收一个 promise 对象的数组作为参数,当这个数组里的所有 promise 对象全部变为 resolve 或 有 reject 状态出现的时候,它才会去调用 .then 方法,它们是并发执行的。 4 | 5 | ### Promise.all 简介 6 | 7 | Promise.all(promiseArray) 方法是 Promise 对象上的静态方法,该方法的作用是将多个 Promise 对象实例包装,生成并返回一个新的 Promise 实例。 8 | 9 | 参数:promiseArray,是一个 Promise 实例数组 10 | 11 | ```js 12 | var p1 = Promise.resolve(1), 13 | p2 = Promise.reject(2), 14 | p3 = Promise.resolve(3); 15 | Promise.all([p1, p2, p3]) 16 | .then(function (results) { 17 | //then方法不会被执行 18 | console.log(results); 19 | }) 20 | .catch(function (e) { 21 | //catch方法将会被执行,输出结果为:2 22 | console.log(2); 23 | }); 24 | ``` 25 | 26 | promise 数组中所有的 promise 实例都变为 resolve 的时候,该方法才会返回,并将所有结果传递 results 数组中。promise 数组中任何一个 promise 为 reject 的话,则整个 Promise.all 调用会立即终止,并返回一个 reject 的新的 promise 对象。 27 | 28 | ### 总结 promise.all 的特点 29 | 30 | 1. 接收一个 Promise 实例的数组或具有 Iterator 接口的对象, 31 | 2. 如果元素不是 Promise 对象,则使用 Promise.resolve 转成 Promise 对象 32 | 3. 如果全部成功,状态变为 resolved,返回值将组成一个数组传给回调 33 | 4. 只要有一个失败,状态就变为 rejected,返回值将直接传递给回调 34 | all() 的返回值也是新的 Promise 对象 35 | 36 | ### 实现 Promise.all 方法 37 | 38 | ```js 39 | function promiseAll(promises) { 40 | return new Promise(function (resolve, reject) { 41 | if (isArray(promises)) { 42 | return reject(new Error("Promises must be an array")); 43 | } 44 | var resolvedCount = 0; 45 | var promiseNum = promises.length; 46 | var resloveValue = []; 47 | for (let i = 0; i < promiseNum; i++) { 48 | Promise.resolve(promises[i]).then( 49 | (value) => { 50 | resloveValue[i] = value; 51 | resolvedCount++; 52 | if (resolvedCount === promiseNum) { 53 | return resloveValue; 54 | } 55 | }, 56 | (reason) => { 57 | return reject(reason); 58 | } 59 | ); 60 | } 61 | }); 62 | } 63 | ``` 64 | -------------------------------------------------------------------------------- /0-前端基础/NodeJS/npm.md: -------------------------------------------------------------------------------- 1 | # 包与 npm 2 | 3 | ### 包结构 4 | 5 | 包实际上是一个存档文件,及一个目录直接打包为.zip 或 tar.gz 格式的文件,安装后解压还原为目录。完全符合 CommonJS 规范的包目录应该包含如下这些文件。 6 | 7 | - package.json 8 | - 包描述文件 9 | - bin 10 | - 存放可执行二进制文件的目录 11 | - lib 12 | - 用于存放 JavaScript 代码目录 13 | - doc 14 | - 用于存放文档的目录 15 | - test 16 | - 用于存放单元测试用例的代码 17 | 18 | ### package.json 19 | 20 | CommonJS 为起定义了一些必需的字段。 21 | 22 | - name 23 | - 包名。唯一的,避免对外发布时命名冲突 24 | - description 25 | - 包简介 26 | - version 27 | - 版本号 28 | - keywords 29 | - 关键词数组,用于做分类搜索 30 | - maintainers 31 | - 包维护者列表 32 | 33 | 权限认证 34 | 35 | - contributors 36 | - 贡献者列表 37 | - bugs 38 | - 一个可以反馈 bug 的页面或邮件 39 | - licenses 40 | - 包所使用的许可证列表 41 | - repositories 42 | - 托管源代码的文件位置 43 | - **dependencies** 44 | - 当前包所依赖的包列表 45 | - directories 46 | - 包目录说明 47 | - implements 48 | - 实现规范的列表 49 | - scripts 50 | - 脚本说明对象 51 | - 被包管理器永安里安装、编译、测试、卸载包 52 | 53 | 补充 54 | 55 | - author 56 | - 包作者 57 | - bin 58 | - 一些包作者希望包可以作为命令行工具使用。配置好 bin 字段后,可通过 `npm install ... -g`将脚本添加到执行路径 59 | - main 60 | - 模块引入方法 require()在引入包时,会优先检查这个字段,并将其作为包中其余模块的入口。 61 | - devDependencies 62 | - 一些模块只在开发时需要依赖。可配置这个属性 63 | 64 | ### npm 常用功能 65 | 66 | - 查看帮助 67 | 68 | - npm -v 69 | - npm 70 | - npm -h 71 | - quick help on 72 | - npm -l 73 | - display full usage info 74 | - npm faq 75 | - npm help 76 | 77 | - 安装依赖 78 | - npm install ... 79 | - 他会在当前目录下创建 node_moudles,然后在下面创建 ... 目录,接着将包解压到这个目录下 80 | - npm install ... -g 81 | - 全局模块安装。并不意味着可以从任何地方 require()来引入它 82 | - -给 其实是将一个包安装为全局可用的可执行命令。他根据包描述文件中 bin 字段配置,将实际脚本链接到与 Node 可执行文件相同的路径下 83 | - 从本地安装 84 | - 本地安装只需指明 npm 指明 package.json 文件所在的位置即可 85 | 86 | npm 钩子命令 87 | package.json 中 script 字段的提出就是让包在安装或者卸载等过程中提供钩子机制 88 | 89 | ```js 90 | "script": { 91 | "preinstall": "xxx.js", 92 | "install": "xxx.js", 93 | "uninstall": "xxx.js", 94 | "test": "xxx.js" 95 | } 96 | ``` 97 | -------------------------------------------------------------------------------- /5-性能优化/浏览器渲染.md: -------------------------------------------------------------------------------- 1 | ### 浏览器的渲染过程,DOM 树和渲染树的区别? 2 | 3 | ![xuanran.png](../../img/xuanran.png) 4 | 5 | HTML 经过解析生成 DOM 树; CSS 经过解析生成  Style Rules。 二者一结合生成了 Render Tree。 6 | 通过 layout 计算出 DOM 要显示的宽高、位置、颜色。 7 | 最后渲染在界面上,用户就看到了 8 | 9 | 浏览器的渲染过程: 10 | 11 | - 解析 HTML 构建 DOM(DOM 树),并行请求 css/image/js 12 | - CSS 文件下载完成,开始构建 CSSOM(CSS 树) 13 | - CSSOM 构建结束后,和 DOM 一起生成 Render Tree(渲染树) 14 | - 布局(Layout):计算出每个节点在屏幕中的位置 15 | - 显示(Painting):通过显卡把页面画到屏幕上 16 | 17 | DOM 树 和 渲染树 的区别: 18 | 19 | - DOM 树与 HTML 标签一一对应,包括 head 和隐藏元素 20 | - 渲染树不包括 head 和隐藏元素,大段文本的每一个行都是独立节点,每一个节点都有对应的 css 属性 21 | 22 | ### CSS 会阻塞 DOM 解析吗? 23 | 24 | 对于一个 HTML 文档来说,不管是内联还是外链的 css,都会阻碍后续的 dom 渲染,但是不会阻碍后续 dom 的解析。 25 | 26 | 当 css 文件放在中时,虽然 css 解析也会阻塞后续 dom 的渲染,但是在解析 css 的同时也在解析 dom,所以等到 css 解析完毕就会逐步的渲染页面了。 27 | 28 | ### 重绘和回流(重排)的区别和关系? 29 | 30 | - 重绘:当渲染树中的元素**外观**(如:颜色)发生改变,不影响布局时,产生重绘 31 | - 回流:当渲染树中的元素的**布局**(如:尺寸、位置、隐藏/状态状态)发生改变时,产生重绘回流 32 | - 注意:JS 获取 Layout 属性值(如:offsetLeft、scrollTop、getComputedStyle 等)也会引起回流。因为浏览器需要通过回流计算最新值 33 | - 回流必将引起重绘,而重绘不一定会引起回流 34 | 35 | DOM 结构中的各元素都有自己的盒子,这些都需要浏览器根据各种样式来计算并更具结果将元素放到它该出现的位置,这个过程叫 reflow 36 | 37 | 触发 reflow 38 | 39 | - 添加或删除可见的 DOM 元素。 40 | - 元素位置改变。 41 | - 元素的尺寸改变(包括:内外边距、边框厚度、宽度、高度等属性的改变)。 42 | - 内容改变。 43 | - 页面渲染器初始化。 44 | - 浏览器窗口尺寸改变。 45 | 46 | ### 如何最小化重绘(repaint)和回流(reflow)? 47 | 48 | 以下几个操作会导致性能问题: 49 | 50 | - 改变 window 大小 51 | - 改变字体 52 | - 添加或删除样式 53 | - 文字改变 54 | - 定位或者浮动 55 | - 盒模型 56 | 57 | 解决方法: 58 | 59 | - 需要要对 DOM 元素进行复杂的操作时,可以先隐藏(display:"none"),操作完成后再显示 60 | - 需要创建多个 DOM 节点时,使用 DocumentFragment 创建完后一次性的加入 document,或使用字符串拼接方式构建好对应 HTML 后再使用 innerHTML 来修改页面 61 | - 缓存 Layout 属性值,如:var left = elem.offsetLeft; 这样,多次使用 left 只产生一次回流 62 | - 避免用 table 布局(table 元素一旦触发回流就会导致 table 里所有的其它元素回流) 63 | - 避免使用 css 表达式(expression),因为每次调用都会重新计算值(包括加载页面) 64 | - 尽量使用 css 属性简写,如:用 border 代替 border-width, border-style, border-color 65 | - 批量修改元素样式:elem.className 和 elem.style.cssText 代替 elem.style.xxx 66 | -------------------------------------------------------------------------------- /0-前端基础/Web安全/README.md: -------------------------------------------------------------------------------- 1 | # web 安全 2 | 3 | 安全性主要分为两大块。 4 | 私密性:不被非法获取和利用。 5 | 可靠性:不丢失、不损坏、不被篡改 6 | 7 | ### 攻击类型 8 | 9 | - [XSS](./XSS.md) 跨站脚本攻击 10 | - [CSRF](./CSRF.md) 跨站请求伪造 11 | - [SQL 注入](./SQL注入.md) 12 | - 点击劫持 13 | - 中间人攻击 14 | 15 | ### 核心 16 | 17 | - 基本概念 18 | - 攻击原理 19 | - 防御措施 20 | 21 | ### 安全问题 22 | 23 | - 用户身份被盗用 24 | - 用户密码泄露 25 | - 用户资料被盗取 26 | - 网站数据库泄露 27 | 28 | ### 同源政策及其规避方法 29 | 30 | 同源要求 31 | 32 | - 协议相同 33 | - 域名相同 34 | - 端口相同 35 | 36 | 限制范围 37 | 38 | - cookie、localstorage 和 indexDB 无法读取 39 | - DOM 无法获得 40 | - Ajax 请求不能发送 41 | 42 | 参考链接: [浏览器同源政策](https://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html) 43 | 44 | ## 点击劫持 45 | 46 | 点击劫持是一种视觉欺骗的攻击手段。攻击者将需要攻击的网站通过 iframe 嵌套的方式嵌入自己的网页中,并将 iframe 设置为透明,在页面中透出一个按钮诱导用户点击。 47 | 48 | 对于这种攻击方式,推荐防御的方法有两种。 49 | 50 | - X-FRAME-OPTIONS 51 | - JS 防御 52 | 53 | ### X-FRAME-OPTIONS 54 | 55 | `X-FRAME-OPTIONS` 是一个 HTTP 响应头,在现代浏览器有一个很好的支持。这个 HTTP 响应头 就是为了防御用 iframe 嵌套的点击劫持攻击。 56 | 57 | 该响应头有三个值可选,分别是 58 | 59 | - `DENY`,表示页面不允许通过`iframe`的方式展示 60 | - `SAMEORIGIN`,表示页面可以在相同域名下通过`iframe`的方式展示 61 | - `ALLOW-FROM`,表示页面可以在指定来源的`iframe`中展示 62 | 63 | ### JS 防御 64 | 65 | 对于某些低版本浏览器来说,并不能支持上面的这种方式,那我们只有通过 JS 的方式来防御点击劫持了。 66 | 67 | ```html 68 | 69 | 74 | 75 | 76 | 84 | 85 | ``` 86 | 87 | ## 中间人攻击 88 | 89 | 中间人攻击是攻击方同时与服务端和客户端建立起了连接,并让对方认为连接是安全的,但是实际上整个通信过程都被攻击者控制了。攻击者不仅能获得双方的通信信息,还能修改通信信息。 90 | 91 | 通常来说不建议使用公共的 Wi-Fi,因为很可能就会发生中间人攻击的情况。如果你在通信的过程中涉及到了某些敏感信息,就完全暴露给攻击方了。 92 | 93 | 当然防御中间人攻击其实并不难,只需要增加一个安全通道来传输信息。HTTPS 就可以用来防御中间人攻击,但是并不是说使用了 HTTPS 就可以高枕无忧了,因为如果你没有完全关闭 HTTP 访问的话,攻击方可以通过某些方式将 HTTPS 降级为 HTTP 从而实现中间人攻击。 94 | -------------------------------------------------------------------------------- /1-前端框架与库/Webpack/webpack配置文件.md: -------------------------------------------------------------------------------- 1 | ## webpack 配置文件 2 | 3 | ### webpack.config.js 4 | 5 | webpack.config.js 是 webpack 的默认打包配置文件。也可以`npx webpack --config 配置文件名`手动设置 6 | 7 | ```js 8 | /** 9 | * Wepack配置接口 10 | */ 11 | const path = require("path"); 12 | 13 | module.exports = { 14 | // 打包模式 15 | mode: "production", 16 | // 入口 17 | entry: "./index.js", 18 | // 出口 19 | output: { 20 | filename: "bundle.js", 21 | // path 后必须是一个绝对位置 22 | path: path.resolve(__dirname, "bundle"), 23 | }, 24 | }; 25 | ``` 26 | 27 | 其中`entry: "./index.js"`是一个简写, 28 | 29 | ``` 30 | entry: { 31 | main: "./index.js" 32 | } 33 | ``` 34 | 35 | ### mode 36 | 37 | 打包模式,有生产环境与发布环境两种,默认是发布环境。 38 | 39 | - production 40 | - 代码被压缩为一行 41 | - development 42 | - 代码不被压缩 43 | 44 | 当没有显示制定时会输出下面内容: 45 | 46 | > WARNING in configuration 47 | > 48 | > The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment. 49 | > You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/ 50 | 51 | ### 多入口 52 | 53 | 最后都会讲其写入到 html 的 script 标签中 54 | 55 | ```js 56 | entry:{ 57 | main: 'a/index.js', 58 | sub: 'b/main.js' 59 | } 60 | // 多个入口是不可打包为同一个JS的, 61 | output: { 62 | filename: '[name].js' 63 | } 64 | ``` 65 | 66 | ### 为打包出的 JS 加前缀 67 | 68 | 比如静态资源都放在 CDN 上,那么希望打包出 srcipt 的 src 是一个 http 地址 69 | 可这样做: 70 | 71 | ``` 72 | output: { 73 | publicPath: 'http://cdn.cn' 74 | filename: '[name].js' 75 | } 76 | ``` 77 | 78 | ### devtool 79 | 80 | devtool 就是去配置 sourcemap,方便调试,能准确定位到代码错误 81 | 82 | - cheap 83 | - 定位到行,不定位到列(提示性能) 84 | - module 85 | - 把依赖模块中的代码一并做映射 86 | - eval 87 | - 使用 eval 形式做 sourcemap 映射 88 | - inline 89 | - 行内的映射关系 90 | 91 | 最好的配置: 92 | 93 | ```js 94 | // 开发时 95 | devtool: 'cheap-module-eval-source-map', 96 | // 线上环境: 97 | devtool: 'cheap-module-source-map' 98 | ``` 99 | -------------------------------------------------------------------------------- /2-计算机基础/网络/RESTful.md: -------------------------------------------------------------------------------- 1 | # RESTful 2 | 3 | REST (Representational State Transfer),中文意思是:表述性状态转移。 一组架构约束条件和原则,如果一个架构符合 REST 的约束条件和原则,我们就称它为 RESTful 架构。 4 | 5 | RESTful 基本概念 6 | 7 | - 在 REST 中,一切的内容都被认为是一种资源 8 | - 每个资源都由 URI 唯一标识 9 | - 使用统一的接口处理资源请求(POST/GET/PUT/DELETE/HEAD) 10 | - 无状态(每次请求之前是无关联,没有 session ) 11 | 12 | ## 理解 RESTful 13 | 14 | 下面我们结合 REST 原则,围绕资源展开讨论,从资源的定义、获取、表述、关联、状态变迁等角度,列举一些关键概念并加以解释。 15 | 16 | - 资源与 URI 17 | - 统一资源接口 18 | - 资源的表述 19 | - 资源的链接 20 | - 状态的转移 21 | 22 | ### 资源和 URI 23 | 24 | - 使用 `/` 来表示资源的层级关系 25 | - 使用 `?` 用来过滤资源 26 | - 使用 `_` 或者 `-` 让 URI 的可读性更好 27 | - `,` 或 `;` 可以用来表示同级资源的关系 28 | 29 | ### 统一资源接口 30 | 31 | | 请求方法 | 描述 | 32 | | -------- | ---------------------------------------------------------------- | 33 | | GET | 获取某个资源。 幂等(取多少次结果都没有变化) | 34 | | POST | 创建一个新的资源 | 35 | | PUT | 替换某个已有的资源(更新操作) , 幂等(更新多次只保存一个结果) | 36 | | DELETE | 删除某个资源 | 37 | | HEAD | 主要用于确认 URL 的有效性以及资源更新的日期时间等 | 38 | | PATCH | 新引入的,对 PUT 方法的补充,用来对已知资源进行局部更新 | 39 | 40 | ### 资源表述 41 | 42 | 客户端获取的只是资源的表述而已。资源在外界的具体呈现,可以有多种表述(或成为表现、表示)形式,在客户端和服务端之间传送的也是资源的表述,而不是资源本身。文本资源可以采用 html、xml、json 等格式,图片可以使用 PNG 或 JPG 展现出来。 43 | 44 | 资源的表述包括数据和描述数据的元数据,例如,HTTP 头 “Content-Type” 就是这样一个元数据属性。 45 | 46 | 那么客户端如何知道服务端提供哪种表述形式呢? 47 | 48 | 答案是可以通过 HTTP 内容协商,客户端可以通过 Accept 头请求一种特定格式的表述,服务端则通过 Content-Type 告诉客户端资源的表述形式。 49 | 50 | MIME 类型 51 | 52 | accept: text/xml html 文件 53 | 54 | Content-Type 告诉客户端资源的表述形式 55 | 56 | ### 资源的链接 57 | 58 | 超媒体即应用状态引擎(可以做多层链接) 59 | 60 | https://api.github.com/repos/github 61 | 62 | ``` 63 | { 64 | "message": "Not Found", 65 | "documentation_url": "https://developer.github.com/v3" 66 | } 67 | ``` 68 | 69 | ### 状态转移 70 | 71 | 服务器端不应该保存客户端状态。 72 | 73 | 应用状态 -> 服务器端不保存应用状态 74 | 75 | 访问订单 根据接口去查询 76 | 77 | 访问商品 查询 78 | -------------------------------------------------------------------------------- /3-编程能力/编程题与分析题/防抖节流.md: -------------------------------------------------------------------------------- 1 | ### 防抖 debounce 2 | 3 | 函数防抖就是在函数需要频繁触发的情况下,只有足够的空闲时间,才执行一次。 4 | 5 | 典型应用 6 | 7 | - 百度搜索框在输入稍有停顿时才更新推荐热词。 8 | - 拖拽 9 | 10 | ```js 11 | function debounce(handler, delay) { 12 | delay = delay || 300; 13 | var timer = null; 14 | 15 | return function () { 16 | var _self = this, 17 | _args = arguments; 18 | 19 | clearTimeout(timer); 20 | timer = setTimeout(function () { 21 | handler.apply(_self, _args); 22 | }, delay); 23 | }; 24 | } 25 | ``` 26 | 27 | 防抖函数为什么要记录`this`和参数的例子: [debounce-demo.js](./debounce-demo.js) 28 | 29 | ### 节流 throttle 30 | 31 | 一个函数只有在大于执行周期时才执行,周期内调用不执行。好像水滴积攒到一定程度才会触发一次下落一样。 32 | 33 | 典型应用: 34 | 35 | - 抢券时疯狂点击,既要限制次数,又要保证先点先发出请求 36 | - 窗口调整 37 | - 页面滚动 38 | 39 | ```js 40 | function throttle(handler, wait) { 41 | wait = wait || 300; 42 | var lastTime = 0; 43 | 44 | return function () { 45 | var _self = this, 46 | _args = arguments; 47 | 48 | var nowTime = new Date().getTime(); 49 | if (nowTime - lastTime > wait) { 50 | handler.apply(_self, _args); 51 | lastTime = nowTime; 52 | } 53 | }; 54 | } 55 | ``` 56 | 57 | 复杂但好用版: 58 | 59 | ```js 60 | function throttle(fn, interval, context, firstTime) { 61 | let timer; 62 | firstTime = typeof firstTime !== "undefined" ? firstTime : true; 63 | return function () { 64 | let args = arguments; 65 | let __me = this; 66 | if (typeof context !== "undefined") { 67 | __me = context; 68 | } 69 | 70 | if (firstTime) { 71 | fn.apply(__me, args); 72 | return (firstTime = false); 73 | } 74 | 75 | if (timer) { 76 | return false; 77 | } 78 | 79 | timer = setTimeout(function () { 80 | clearTimeout(timer); 81 | timer = null; 82 | 83 | fn.apply(__me, args); 84 | }, interval); 85 | }; 86 | } 87 | ``` 88 | 89 | ### 节流与防抖的本质 90 | 91 | 以闭包的形式存在,通过对事件对应的回调函数进行包裹、以自由变量的形式缓存时间信息,最后用**定时器**或**时间差**来控制事件的触发频率。 92 | ![fdjl](../../img/fdjl.png) 93 | -------------------------------------------------------------------------------- /0-前端基础/JS/作用域.md: -------------------------------------------------------------------------------- 1 | # 作用域相关问题 2 | 3 | ### 下面的代码打印什么内容,为什么? 4 | 5 | ```js 6 | // 情况 1 7 | 8 | // 情况 2 9 | var b = 10; 10 | var c = function b() { 11 | b = 20; 12 | console.log(b) 13 | } 14 | c() 15 | 16 | // 上面两种都打印: 17 | ƒ b() { 18 | b = 20; 19 | console.log(b) 20 | } 21 | ``` 22 | 23 | b 函数(函数表达式定义函数)是一个相当于用 const 定义的常量,内部无法进行重新赋值,如果在严格模式下,会报错"Uncaught TypeError: Assignment to constant variable." 24 | 25 | ### 简单改造下面的代码,使之分别打印 10 和 20 26 | 27 | ```js 28 | var b = 10; 29 | (function b() { 30 | b = 20; 31 | console.log(b); 32 | })(); 33 | ``` 34 | 35 | 打印 10: 36 | 37 | ```js 38 | var b = 10; 39 | (function b(b) { 40 | window.b = 20; 41 | console.log(b); 42 | })(b); 43 | ``` 44 | 45 | ```js 46 | var b = 10; 47 | (function b() { 48 | b.b = 20; 49 | console.log(b); 50 | })(); 51 | ``` 52 | 53 | 打印 20: 54 | 55 | ```js 56 | var b = 10; 57 | (function b(b) { 58 | b = 20; 59 | console.log(b); 60 | })(); 61 | ``` 62 | 63 | ```js 64 | var b = 10; 65 | (function b() { 66 | var b = 20; 67 | console.log(b); 68 | })(); 69 | ``` 70 | 71 | ### 下面代码输出什么 72 | 73 | ```js 74 | var a = 10; 75 | (function () { 76 | console.log(a); 77 | a = 5; 78 | console.log(window.a); 79 | var a = 20; 80 | console.log(a); 81 | })(); 82 | ``` 83 | 84 | 依次输出:undefined -> 10 -> 20 85 | 86 | 解析: 87 | 88 | 在立即执行函数中,var a = 20; 语句定义了一个局部变量 a,**由于 js 的变量声明提升机制**,局部变量 a 的声明会被提升至立即执行函数的函数体最上方,且由于这样的提升并不包括赋值,因此第一条打印语句会打印 undefined,最后一条语句会打印 20。 89 | 90 | 由于全局的 var 会挂载到 window 对象下,并且立即执行函数里面有变量提示。 91 | ‘a = 5;’这条语句执行时,局部的变量 a 已经声明,因此它产生的效果是对局部的变量 a 赋值,此时 window.a 依旧是最开始赋值的 10 92 | 93 | ### var 变量定义提升 94 | 95 | ```js 96 | var name = "Tom"; 97 | (function () { 98 | if (typeof name == "undefined") { 99 | var name = "Jack"; 100 | console.log("Goodbye " + name); 101 | } else { 102 | console.log("Hello " + name); 103 | } 104 | })(); 105 | ``` 106 | 107 | 输出: 'Goodbye Jack' 108 | -------------------------------------------------------------------------------- /0-前端基础/浏览器/屏幕刷新率&帧.md: -------------------------------------------------------------------------------- 1 | ## 屏幕刷新率 2 | 3 | - 目前大多数设备的屏幕刷新率为 60 次/秒 4 | - 浏览器渲染动画或页面的每一帧的速率也需要跟设备屏幕的刷新率保持一致 5 | 6 | - 页面是一帧一帧绘制出来的,当每秒绘制的帧数(FPS)达到 60 时,页面是流畅的,小于这个值时,用户会感觉到卡顿 7 | - 每个帧的预算时间是 16.66 毫秒 (1 秒/60) 8 | - 1s 60 帧,所以每一帧分到的时间是 1000/60 ≈ 16 ms。所以我们书写代码时力求不让一帧的工作量超过 16ms 9 | 10 | ## 帧 11 | 12 | - 一帧就是一幅静止的画面,连续的帧就形成动画 13 | 14 | - 每个帧的开头包括样式计算、布局和绘制 15 | - JavaScript 执行 Javascript 引擎和页面渲染引擎在同一个渲染线程,GUI 渲染和 Javascript 执行两者是互斥的 16 | 17 | - 如果某个任务执行时间过长,浏览器会推迟渲染 18 | 19 | ![](../../img/lifeofframe.jpg) 20 | 21 | ## 事件循环 22 | 23 | 为了协调事件,用户交互,脚本,渲染,网络任务等,浏览器必须使用事件循环。 24 | 25 | ### 流程 26 | 27 | 1. 从任务队列中取出一个**宏任务**并执行。 28 | 29 | 2. 检查**微任务**队列,执行并清空微任务队列,如果在微任务的执行中又加入了新的微任务,也会在这一步一起执行。 30 | 31 | 3. 进入更新渲染阶段,判断是否需要渲染,这里有一个 `rendering opportunity` 的概念,也就是说不一定每一轮 event loop 都会对应一次浏览器渲染,要根据屏幕刷新率、页面性能、页面是否在后台运行来共同决定,通常来说这个渲染间隔是固定的。(所以多个 task 很可能在一次渲染之间执行) 32 | 33 | - 浏览器会尽可能的保持帧率稳定,例如页面性能无法维持 60fps(每 16.66ms 渲染一次)的话,那么浏览器就会选择 30fps 的更新速率,而不是偶尔丢帧。 34 | - 如果浏览器上下文不可见,那么页面会降低到 4fps 左右甚至更低。 35 | - 如果满足以下条件,也会跳过渲染: 36 | - 浏览器判断更新渲染不会带来视觉上的改变。 37 | - `map of animation frame callbacks` 为空,也就是帧动画回调为空,可以通过 `requestAnimationFrame` 来请求帧动画。 38 | 39 | 4. 如果上述的判断决定本轮不需要渲染,那么下面的几步也不会继续运行: 40 | 41 | > This step enables the user agent to prevent the steps below from running for other reasons, for example, to ensure certain tasks are executed immediately after each other, with only microtask checkpoints interleaved (and without, e.g., animation frame callbacks interleaved). Concretely, a user agent might wish to coalesce timer callbacks together, with no intermediate rendering updates. 42 | > 有时候浏览器希望两次「定时器任务」是合并的,他们之间只会穿插着 microTask 的执行,而不会穿插屏幕渲染相关的流程(比如 requestAnimationFrame,下面会写一个例子)。 43 | 44 | 5. 对于需要渲染的文档,如果窗口的大小发生了变化,执行监听的`resize`方法。 45 | 46 | 6. 对于需要渲染的文档,如果页面发生了滚动,执行 `scroll` 方法。 47 | 48 | 7. 对于需要渲染的文档,执行帧动画回调,也就是`requestAnimationFrame`的回调。 49 | 50 | 8. 对于需要渲染的文档, 执行`IntersectionObserver`的回调。 51 | 52 | 9. 对于需要渲染的文档,重新渲染绘制用户界面。 53 | 54 | 10. 判断 `task` 队列和 `microTask` 队列是否都为空,如果是的话,则进行 `Idle` 空闲周期的算法,判断是否要执行 `requestIdleCallback` 的回调函数。 55 | -------------------------------------------------------------------------------- /3-编程能力/编程题与分析题/使用Promise封装一个AJAX.md: -------------------------------------------------------------------------------- 1 | # 使用 Promise 封装一个 AJAX 2 | 3 | ### ajax 的 xhr 对象的 7 个事件 4 | 5 | - onloadstart 6 | - 开始 send 触发 7 | - onprogress 8 | - 从服务器上下载数据每 50ms 触发一次 9 | - onload 10 | - 得到响应 11 | - onerror 12 | - 服务器异常 13 | - onloadend 14 | - 请求结束,无论成功失败 15 | - onreadystatechange 16 | - xhr.readyState 改变使触发 17 | - onabort 18 | - 调用 xhr.abort 时触发 19 | 20 | ### 实现代码 21 | 22 | ```js 23 | const ajax = (obj) => { 24 | return new Promise((resolve, reject) => { 25 | let method = obj.method || "GET"; 26 | 27 | // 创建 xhr 28 | let xhr; 29 | if (window.XMLHTTPRequest) { 30 | xhr = new XMLHTTPRequest(); 31 | } else { 32 | xhr = new ActiveXObject("Microsoft.XMLHTTP"); 33 | } 34 | // 超时 35 | xhr.ontimeout = function () { 36 | reject({ 37 | errorType: "timeout_error", 38 | xhr: xhr, 39 | }); 40 | }; 41 | // 报错 42 | xhr.onerror = function () { 43 | reject({ 44 | errorType: "onerror", 45 | xhr: xhr, 46 | }); 47 | }; 48 | // 监听 statuschange 49 | xhr.onreadystatechange = function () { 50 | if (xhr.readState === 4) { 51 | if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) { 52 | resolve(xhr.responseText); 53 | } else { 54 | reject({ 55 | errorType: "onerror", 56 | xhr: xhr, 57 | }); 58 | } 59 | } 60 | }; 61 | 62 | // 发送请求 63 | if (method === "POST") { 64 | xhr.open("POST", obj.url, true); 65 | xhr.responseType = "json"; 66 | xhr.setRequestHeader("Accept", "application/json"); 67 | xhr.send(JSON.parse(obj.data)); 68 | } else { 69 | let query = ""; 70 | for (let key in obj.data) { 71 | query += `&${encodeURIComponent(key)}=${encodeURIComponent( 72 | obj.data[key] 73 | )}`; 74 | } 75 | // The substring() method returns the part of the string between the start and end indexes, or to the end of the string. 76 | query.substring(1); 77 | xhr.open("GET", obj.url, +"?" + query, true); 78 | xhr.send(); 79 | } 80 | }); 81 | }; 82 | ``` 83 | -------------------------------------------------------------------------------- /4-质量保障/监控/README.md: -------------------------------------------------------------------------------- 1 | # 前端监控 2 | 3 | 前端监控包括行为监控、异常监控、性能监控。 4 | 5 | ### 前端产生异常的原因主要分 5 类: 6 | 7 | - 逻辑错误 8 | - 业务逻辑判断条件错误 9 | - 事件绑定顺序错误 10 | - 调用栈时序错误 11 | - 错误的操作 js 对象 12 | - 数据类型错误 13 | - 将 null 视作对象读取 property 14 | - 将 undefined 视作数组进行遍历 15 | - 将字符串形式的数字直接用于加运算 16 | - 函数参数未传 17 | - 语法句法错误 18 | - 网络错误 19 | - 请求过慢 20 | - 服务端未返回数据但仍 200,前端按正常进行数据遍历 21 | - 提交数据时网络中断 22 | - 服务端 500 错误时前端未做任何错误处理 23 | - 系统错误 24 | - 内存不够用 25 | - 磁盘塞满 26 | - 壳不支持 API 27 | - 不兼容 28 | 29 | ## 异常采集 30 | 31 | ### 采集内容 32 | 33 | 当异常出现的时候,我们需要知道异常的具体信息,根据异常的具体信息来决定采用什么样的解决方案。在采集异常信息时,可以遵循 4W 原则: 34 | 35 | **WHO did WHAT and get WHICH exception in WHICH environment?** 36 | 37 | a. 用户信息 38 | 39 | 出现异常时该用户的信息,例如该用户在当前时刻的状态、权限等,以及需要区分用户可多终端登录时,异常对应的是哪一个终端。 40 | 41 | b. 行为信息 42 | 43 | 用户进行什么操作时产生了异常:所在的界面路径;执行了什么操作;操作时使用了哪些数据;当时的 API 吐了什么数据给客户端;如果是提交操作,提交了什么数据;上一个路径;上一个行为日志记录 ID 等。 44 | 45 | c. 异常信息 46 | 47 | 产生异常的代码信息:用户操作的 DOM 元素节点;异常级别;异常类型;异常描述;代码 stack 信息等。 48 | 49 | d. 环境信息 50 | 51 | 网络环境;设备型号和标识码;操作系统版本;客户端版本;API 接口版本等。 52 | 53 | ### 异常捕获 54 | 55 | 前端捕获异常分为全局捕获和单点捕获。全局捕获代码集中,易于管理;单点捕获作为补充,对某些特殊情况进行捕获,但分散,不利于管理。 56 | 57 | ### 全局捕获 (依赖工具自动捕获) 58 | 59 | 通过全局的接口,将捕获代码集中写在一个地方,可以利用的接口有: 60 | 61 | window.addEventListener(‘error’) / window.addEventListener(“unhandledrejection”) / document.addEventListener(‘click’) 等 62 | 框架级别的全局监听,例如 aixos 中使用 interceptor 进行拦截,vue、react 都有自己的错误采集接口 63 | 通过对全局函数进行封装包裹,实现在在调用该函数时自动捕获异常 64 | 对实例方法重写(Patch),在原有功能基础上包裹一层,例如对 console.error 进行重写,在使用方法不变的情况下也可以异常捕获 65 | 66 | ### 单点捕获(主动上报) 67 | 68 | 在业务代码中对单个代码块进行包裹,或在逻辑流程中打点,实现有针对性的异常捕获: 69 | 70 | try…catch 71 | 专门写一个函数来收集异常信息,在异常发生时,调用该函数 72 | 专门写一个函数来包裹其他函数,得到一个新函数,该新函数运行结果和原函数一模一样,只是在发生异常时可以捕获异常 73 | 74 | ## 监控与通知 75 | 76 | 对异常进行统计和分析只是基础,而在发现异常时可以推送和告警,甚至做到自动处理,才是一个异常监控系统应该具备的能力。 77 | 78 | ### 自定义触发条件的告警 79 | 80 | a. 监控实现 81 | 82 | 当日志信息进入接入层时,就可以触发监控逻辑。当日志信息中存在较为高级别的异常时,也可以立即出发告警。告警消息队列和日志入库队列可以分开来管理,实现并行。 83 | 84 | 对入库日志信息进行统计,对异常信息进行告警。对监控异常进行响应。所谓监控异常,是指:有规律的异常一般而言都比较让人放心,比较麻烦的是突然之间的异常。例如在某一时段突然频繁接收到 D 级异常,虽然 D 级异常是不紧急一般重要,但是当监控本身发生异常时,就要提高警惕。 85 | 86 | b. 自定义触发条件 87 | 88 | 除了系统开发时配置的默认告警条件,还应该提供给日志管理员可配置的自定义触发条件,如: 89 | 90 | - 日志内含有什么内容时 91 | - 日志统计达到什么度、量时 92 | - 向符合什么条件的用户告警 93 | -------------------------------------------------------------------------------- /1-前端框架与库/React/setState.md: -------------------------------------------------------------------------------- 1 | # [深入 setState 机制](https://github.com/sisterAn/blog/issues/26) 2 | 3 | ### 异步更新 4 | 5 | 考虑到性能问题,setState 使用一个**队列机制**来更新 state。 6 | 当执行 setState 时,会将需要更新的 state**浅合并**后放入状态队列,不会立即更新 state。而如果不使用 setState,而直接修改 state 的值就不会放入状态队列,下一次调用 setState 对状态队列进行更新的时候可能会造成不可预知的错误。 7 | 8 | 例子: 9 | 10 | ```js 11 | // 假设 state.count === 0 12 | this.setState({ count: state.count + 1 }); 13 | this.setState({ count: state.count + 1 }); 14 | this.setState({ count: state.count + 1 }); 15 | // state.count === 1, 而不是 3 16 | ``` 17 | 18 | 本质上等同于: 19 | 20 | ```js 21 | // 假设 state.count === 0 22 | Object.assign( 23 | state, 24 | { count: state.count + 1 }, 25 | { count: state.count + 1 }, 26 | { count: state.count + 1 } 27 | ); 28 | // {count: 1} 29 | ``` 30 | 31 | **解决方法**为: **传递一个签名为 (state, props) => newState 的函数作为参数。** 向 setState 中传入函数时,这个函数不会被浅合并,一定会执行,是一个原子性更新操作。 32 | 33 | ```js 34 | // 正确用法 35 | this.setState((prevState, props) => ({ 36 | count: prevState.count + props.increment, 37 | })); 38 | ``` 39 | 40 | ### setState 循环调用风险 41 | 42 | 但,如果在`shouldComponentUpdate`或`componentWillUpdate` 方法里调用 this.setState 方法,就会造成崩溃。 43 | ![](../../img/setStateCercle.png) 44 | 45 | ### 何时同步?何时异步? 46 | 47 | 如果是由 React 引发的事件处理(比如通过 onClick 引发的事件处理),调用 setState 不会同步更新 this.state,除此之外的 setState 调用会同步执行 this.state。 48 | 所谓“除此之外”,指的是绕过 React 通过 addEventListener 直接添加的事件处理函数,还有通过 setTimeout/setInterval 产生的异步调用。而这一切都是因为一个非常核心的概念--事务 49 | 50 | ```js 51 | class Example extends React.Component { 52 | constructor() { 53 | super(); 54 | this.state = { 55 | val: 0 56 | }; 57 | } 58 | 59 | componentDidMount() { 60 | this.setState({val: this.state.val + 1}); 61 | console.log(this.state.val); // 第 1 次 log 62 | 63 | this.setState({val: this.state.val + 1}); 64 | console.log(this.state.val); // 第 2 次 log 65 | 66 | setTimeout(() => { 67 | this.setState({val: this.state.val + 1}); 68 | console.log(this.state.val); // 第 3 次 log 69 | 70 | this.setState({val: this.state.val + 1}); 71 | console.log(this.state.val); // 第 4 次 log 72 | }, 0); 73 | } 74 | 75 | render() { 76 | return null; 77 | } 78 | }; 79 | 80 | 答案是 0 0 2 3 81 | ``` 82 | -------------------------------------------------------------------------------- /0-前端基础/JS/事件队列.md: -------------------------------------------------------------------------------- 1 | ### 为什么 JavaScript 是单线程? 2 | 3 | JavaScript 语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。那么,为什么 JavaScript 不能有多个线程呢?这样能提高效率啊。 4 | 5 | JavaScript 的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript 的主要用途是与用户互动,以及操作 DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定 JavaScript 同时有两个线程,一个线程在某个 DOM 节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准? 6 | 7 | 所以,为了避免复杂性,从一诞生,JavaScript 就是单线程,这已经成了这门语言的核心特征,将来也不会改变。 8 | 9 | 为了利用多核 CPU 的计算能力,HTML5 提出 Web Worker 标准。允许 JavaScript 脚本创建多个线程,但是子线程完全受主线程控制,且不得操作 DOM。所以,这个新标准并没有改变 JavaScript 单线程的本质。 10 | 11 | ### Event Loop 12 | 13 | 参考地址:[Event Loop 这个循环你晓得么?(附 GIF 详解)-饿了么前端](https://zhuanlan.zhihu.com/p/41543963) 14 | 15 | ### **任务队列的本质** 16 | 17 | - 所有同步任务都在主线程上执行,形成一个**执行栈**(execution context stack)。 18 | - 主线程之外,还存在一个”**任务队列**”(task queue)。只要异步任务有了运行结果,就在”任务队列”之中放置一个事件。 19 | - 一旦”执行栈”中的所有同步任务执行完毕,系统就会读取”任务队列”,看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。 20 | - 主线程不断重复上面的第三步。 21 | 22 | ### 异步任务 23 | 24 | - setTimeOut、setInterval 25 | - DOM 事件 26 | - Promise 27 | 28 | ### JavaScript 实现异步编程的方法? 29 | 30 | - 回调函数 31 | - 事件监听 32 | - 发布/订阅 33 | - Promises 对象 34 | - Async 函数[ES7] 35 | 36 | ### 关于 setTimeOut、setImmediate、process.nextTick()的比较 37 | 38 | #### setTimeout() 39 | 40 | 将事件插入到了事件队列,必须等到当前代码(执行栈)执行完,主线程才会去执行它指定的回调函数。 41 | 当主线程时间执行过长,无法保证回调会在事件指定的时间执行。 42 | 浏览器端每次 setTimeout 会有 4ms 的延迟,当连续执行多个 setTimeout,有可能会阻塞进程,造成性能问题。 43 | 44 | #### setImmediate() 45 | 46 | 事件插入到事件队列尾部,主线程和事件队列的函数执行完成之后立即执行。和 setTimeout(fn,0)的效果差不多。 47 | 服务端 node 提供的方法。浏览器端最新的 api 也有类似实现:window.setImmediate,但支持的浏览器很少。 48 | 49 | #### process.nextTick() 50 | 51 | 插入到事件队列尾部,但在下次事件队列之前会执行。也就是说,它指定的任务总是发生在所有异步任务之前,当前主线程的末尾。 52 | 大致流程:当前”执行栈”的尾部–>下一次 Event Loop(主线程读取”任务队列”)之前–>触发 process 指定的回调函数。 53 | 服务器端 node 提供的办法。用此方法可以用于处于异步延迟的问题。 54 | 可以理解为:此次不行,预约下次优先执行。 55 | 56 | ### [浏览器的 Tasks、microtasks、 queues 和 schedules](https://github.com/sisterAn/blog/issues/21) 57 | 58 | #### Promise 59 | 60 | Promise 本身是同步的立即执行函数, 当在 executor 中执行 resolve 或者 reject 的时候, 此时是异步操作, 会先执行 then/catch 等,当主栈完成后,才会去调用 resolve/reject 中存放的方法执行,打印 p 的时候,是打印的返回结果,一个 Promise 实例。 61 | 62 | #### async await 63 | 64 | Async/Await 就是一个自执行的 generate 函数。利用 generate 函数的特性把异步的代码写成“同步”的形式。 65 | 66 | async 函数返回一个 Promise 对象,当函数执行的时候,一旦遇到 await 就会先返回,等到触发的异步操作完成,再执行函数体内后面的语句。可以理解为,是让出了线程,跳出了 async 函数体。 67 | -------------------------------------------------------------------------------- /5-性能优化/减少网络请求的次数或时间/CDN.md: -------------------------------------------------------------------------------- 1 | # CDN 的缓存与回源机制解析 2 | 3 | CDN (Content Delivery Network,即内容分发网络)指的是一组分布在各个地区的服务器。这些服务器存储着数据的副本,因此服务器可以根据哪些服务器与用户距离最近,来满足数据的请求。 CDN 提供快速服务,较少受高流量影响。 4 | 5 | ### CDN 的核心功能 6 | 7 | CDN 的核心点有两个,一个是**缓存**,一个是**回源**。 8 | 9 | - “缓存”就是说我们把资源 copy 一份到 CDN 服务器上这个过程 10 | - “回源”就是说 CDN 发现自己没有这个资源(一般是缓存的数据过期了),转头向根服务器(或者它的上层服务器)去要这个资源的过程。 11 | 12 | ### CDN 与前端性能优化 13 | 14 | CDN 往往被用来**存放静态资源**。 15 | 16 | “根服务器”本质上是业务服务器,它的核心任务在于生成"动态页面"或返回"非纯静态页面"(需要计算的)。业务服务器仿佛一个车间,车间里运转的机器轰鸣着为我们产出所需的资源;相比之下,CDN 服务器则像一个仓库,它只充当资源的“栖息地”和“搬运工”。 17 | 18 | 所谓**静态资源**,就是**像 JS、CSS、图片等不需要业务服务器进行计算即得的资源**。而**动态资源**,顾名思义是需要**后端实时动态生成的资源**,较为常见的就是 JSP、ASP 或者依赖服务端渲染得到的 HTML 页面。 19 | 20 | 什么是**非纯静态资源**呢?它是**指需要服务器在页面之外作额外计算的 HTML 页面**。具体来说,当我打开某一网站之前,该网站需要通过权限认证等一系列手段确认我的身份、进而决定是否要把 HTML 页面呈现给我。这种情况下 HTML 确实是静态的,但它**和业务服务器的操作耦合**,我们把它丢到 CDN 上显然是不合适的。 21 | 22 | ### CDN 的实际应用 23 | 24 | 静态资源本身具有访问频率高、承接流量大的特点,因此静态资源加载速度始终是前端性能的一个非常关键的指标。 25 | 26 | 首先,CDN 服务器域名与业务服务器域名不一致。 27 | 28 | 例如淘宝,业务服务器域名为“www.taobao.com”,而 CDN 服务器的域名是“g.alicdn.com” 29 | 30 | > Cookie 是紧跟域名的。同一个域名下的所有请求,都会携带 Cookie。大家试想,如果我们此刻仅仅是请求一张图片或者一个 CSS 文件,我们也要携带一个 Cookie 跑来跑去(关键是 Cookie 里存储的信息我现在并不需要),这是一件多么劳民伤财的事情。Cookie 虽然小,请求却可以有很多,随着请求的叠加,这样的不必要的 Cookie 带来的开销将是很大的。 31 | 32 | 同一个域名下的请求会不分青红皂白地携带 Cookie,而静态资源往往并不需要 Cookie 携带什么认证信息。把静态资源和主页面置于不同的域名下,完美地避免了不必要的 Cookie 的出现! 33 | 34 | ### CDN 典型构成 35 | 36 | 从功能上看,典型的 CDN 系统由分发服务系统,负载均衡系统和运营管理系统组成。 37 | 38 | #### 分发服务系统 39 | 40 | 最基本的工作单元就是 Cache 设备,cache(边缘 cache)**负责直接响应最终用户的访问请求**,把缓存在本地的内容快速地提供给用户。同时 cache 还**负责与源站点进行内容同步**,把更新的内容以及本地没有的内容从源站点获取并保存在本地,([webhook](https://blog.csdn.net/starter_____/article/details/79255536))。Cache 设备的数量、规模、总服务能力是衡 量一个 CDN 系统服务能力的最基本的指标。 41 | 42 | #### 负载均衡系统 43 | 44 | 主要功能是负责对所有发起服务请求的用户进行访问调度,确定提供给用户的最终实际访问地址。两级调度体系分为全局负载均衡(GSLB)和本 地负载均衡(SLB)。GSLB 主要根据用户就近性原则,通过对每个服务节点进行“最优”判断,确定向用户提供服务的 cache 的物理位置。SLB 主要负责节点内部的设备负载均衡。 45 | 46 | #### 运营管理系统 47 | 48 | 分为运营管理和网络管理子系统,负责处理业务层面的与外界系统交互所必须的收集、整理、交付工作,包含客户管理、产品管理、计费管理、统计分析等功能。 49 | 50 | 负责为用户提供内容服务的 cache 设备应部署在物理上的网络边缘位置,即 CDN 边缘层。CDN 系统中负责全局性管理和控制的设备组成中心层(二级缓存),中心层同时保存着最多的内容副本,当边缘层设备未命中时,会向中心层请求,如果在中心层仍未命中,则需要中心层向源站 回源(如果是流媒体,代价很大)。 51 | 52 | CDN 骨干点和 CDN POP 点在功能上不同,中心和区域节点一般称为骨干点,主要作为内容分发和边缘未命中时的服务点;边缘节点又被称为 POP(point of presence)节点,CDN POP 点主要作为直接向用户提供服务的节点。 53 | -------------------------------------------------------------------------------- /3-编程能力/编程题与分析题/deepCopy.js: -------------------------------------------------------------------------------- 1 | function getEmpty(o) { 2 | if (Object.prototype.toString.call(o) === "[object Object]") { 3 | return {}; 4 | } 5 | if (Object.prototype.toString.call(o) === "[object Array]") { 6 | return []; 7 | } 8 | return o; 9 | } 10 | 11 | function deepCopyBFS(origin) { 12 | let queue = []; 13 | let map = new Map(); // 记录出现过的对象,用于处理环 14 | 15 | let target = getEmpty(origin); 16 | if (target !== origin) { 17 | queue.push([origin, target]); 18 | map.set(origin, target); 19 | } 20 | 21 | while (queue.length) { 22 | let [ori, tar] = queue.shift(); 23 | for (let key in ori) { 24 | // 处理环状 25 | if (map.get(ori[key])) { 26 | tar[key] = map.get(ori[key]); 27 | continue; 28 | } 29 | 30 | tar[key] = getEmpty(ori[key]); 31 | if (tar[key] !== ori[key]) { 32 | queue.push([ori[key], tar[key]]); 33 | map.set(ori[key], tar[key]); 34 | } 35 | } 36 | } 37 | 38 | return target; 39 | } 40 | 41 | function deepCopyDFS(origin) { 42 | let stack = []; 43 | let map = new Map(); // 记录出现过的对象,用于处理环 44 | 45 | let target = getEmpty(origin); 46 | if (target !== origin) { 47 | stack.push([origin, target]); 48 | map.set(origin, target); 49 | } 50 | 51 | while (stack.length) { 52 | let [ori, tar] = stack.pop(); 53 | for (let key in ori) { 54 | // 处理环状 55 | if (map.get(ori[key])) { 56 | tar[key] = map.get(ori[key]); 57 | continue; 58 | } 59 | 60 | tar[key] = getEmpty(ori[key]); 61 | if (tar[key] !== ori[key]) { 62 | stack.push([ori[key], tar[key]]); 63 | map.set(ori[key], tar[key]); 64 | } 65 | } 66 | } 67 | 68 | return target; 69 | } 70 | 71 | // test 72 | [deepCopyBFS, deepCopyDFS].forEach((deepCopy) => { 73 | console.log(deepCopy({ a: 1 })); 74 | console.log(deepCopy([1, 2, { a: [3, 4] }])); 75 | console.log( 76 | deepCopy(function () { 77 | return 1; 78 | }) 79 | ); 80 | console.log( 81 | deepCopy({ 82 | x: function () { 83 | return "x"; 84 | }, 85 | val: 3, 86 | arr: [1, { test: 1 }], 87 | }) 88 | ); 89 | 90 | let circle = {}; 91 | circle.child = circle; 92 | console.log(deepCopy(circle)); 93 | }); 94 | -------------------------------------------------------------------------------- /5-性能优化/网络传输过程中优化.md: -------------------------------------------------------------------------------- 1 | ### 对于 HTTP1.1 ,减少 HTTP 请求 2 | 3 | 如果服务端还是 HTTP 1.1 协议,那么浏览器并发的 HTTP 请求是由数量限制的(比如桌面浏览器并发请求可能是 8 个,手机浏览器是 6 个),如果一下子并发的几十个请求那么会有很多请求会停下来等,等前面的请求好了下一个再进去,这样就延长了整个页面的加载时间。 4 | 5 | ### 对于 HTTP 2 ,拆包,充分利用缓存 6 | 7 | 如果服务端已经开启了 http2,那么不存在并发请求的限制。 8 | 9 | ### 拆包,充分利用缓存 10 | 11 | 项目中有很多依赖库如 React、lodash ,它们的版本是基本不会发生变化的。将这些不会发生变化的包单独拆出来,加上缓存,那么二次请求时这些不变的包都不会被拉取,这样就可以提升网站整体的性能。 12 | 13 | ### 压缩资源文件减小请求大小 14 | 15 | 文件大小越小当然加载速度就越快。 16 | 可对代码进行压缩,去掉空格、注释、变量替换,在传输时,使用 gzip 等压缩方式也可以降低资源文件的大小。 17 | 18 | ### 缓存分类 19 | 20 | - 强缓存 21 | - 直接从浏览器缓存中读取,不去后台查询是否过期 22 | - `Exprise` 过期时间 23 | - `Cache-Control:max-age=3600` 过期秒数 24 | - 协商缓存 25 | - 每次使用缓存之前先去后台确认一下 26 | - `Last-Modified` `If-Modified-Since` 上次修改时间 27 | - `Etag` `If-None-Match` 28 | - 如何区别 29 | - 是否设置了`no-cache` 30 | 31 | ### 利用缓存机制,尽可能使用缓存减少请求 32 | 33 | 浏览器是有缓存机制的,在返回资源的时候设置一个 cache-control 设置过期时间,在过期时间内浏览器会默认使用本地缓存。 34 | 35 | 但缓存机制也存在一定的问题,因为网站开发是阶段性的,隔一段时间会发布一个新的版本。因为 HTTP 请求是根据 url 来定位的,如果资源文件名的 url 没有发生更改那么浏览器还是会使用缓存,这个时候怎么办那? 36 | 这时就需要一个缓存更新机制来让修改过的文件具有一个新的名字。 37 | 最简单的方法就是在 url 后加一个时间戳,但是这会导致只要有新的版本发布就会重新获取所有的新资源。 38 | 一个现代流行的方法就是根据文件计算一个 hash 值,这个 hash 值是根据文件的更新变化而变化的。 当浏览器获取文件时如果这个文件名有更新那么就会请求新的文件。 39 | 40 | ### DNS 预解析 41 | 42 | 现代浏览器在 DNS Prefetch 上做了两项工作: 43 | 44 | 1. html 源码下载完成后,会解析页面的包含链接的标签,提前查询对应的域名 45 | 46 | 2. 对于访问过的页面,浏览器会记录一份域名列表,当再次打开时,会在 html 下载的同时去解析 DNS 47 | 48 | **自动解析** 49 | 50 | 浏览器使用超链接的 href 属性来查找要预解析的主机名。当遇到 a 标签,浏览器会自动将 href 中的域名解析为 IP 地址,这个解析过程是与用户浏览网页并行处理的。但是为了确保安全性,在 HTTPS 页面中不会自动解析 51 | 52 | **手动解析** 53 | 54 | ```html 55 | 预解析某域名 56 | 57 | 58 | 强制开启HTTPS下的DNS预解析 59 | 60 | ``` 61 | 62 | ### CDN 63 | 64 | CDN 的原理是尽可能的在各个地方分布机房缓存数据。 65 | 66 | 因此,我们可以将静态资源尽量使用 CDN 加载,由于浏览器对于单个域名有并发请求上限,可以考虑使用多个 CDN 域名。并且对于 CDN 加载静态资源需要注意 CDN 域名要与主站不同,否则每次请求都会带上主站的 Cookie,平白消耗流量。 67 | 68 | ### 预加载 69 | 70 | 在开发中,可能会遇到这样的情况。有些资源不需要马上用到,但是希望尽早获取,这时候就可以使用预加载。 71 | 72 | 预加载其实是声明式的 fetch ,强制浏览器请求资源,并且不会阻塞 onload 事件,可以使用以下代码开启预加载。 73 | 74 | 预加载可以一定程度上降低首屏的加载时间,因为可以将一些不影响首屏但重要的文件延后加载,唯一缺点就是兼容性不好。 75 | 76 | ```html 77 | 78 | ``` 79 | 80 | ### 预渲染 81 | 82 | 可以通过预渲染将下载的文件预先在后台渲染,可以使用以下代码开启预渲染。 83 | 84 | ### 图片优化 85 | 86 | - 不用图片。很多时候会使用到很多修饰类图片,其实这类修饰图片完全可以用 CSS 去代替。 87 | - 对于移动端按理说,图片不需要加载原图,可请求裁剪好的图片 88 | - 小图使用 base64 格式 89 | - 将多个图标文件整合到一张图中(雪碧图) 90 | - 采用正确的图片格式 91 | - 对于能够显示 WebP 格式的浏览器尽量使用 WebP 格式。因为 WebP 格式具有更好的图像数据压缩算法,能带来更小的图片体积,而且拥有肉眼识别无差异的图像质量,缺点就是兼容性并不好 92 | - 色彩很多的使用 JPEG 93 | - 色彩种类少的使用 PNG,有的可用 SVG 代替 94 | -------------------------------------------------------------------------------- /1-前端框架与库/React/Hooks/hooks 与定时器.md: -------------------------------------------------------------------------------- 1 | # hooks 与定时器 2 | 3 | 在 hooks 中使用了定时器对于新手来说往往会出错,本文将介绍并剖析。 4 | 5 | ## 错误的定时器用法 6 | 7 | ```js 8 | function Counter() { 9 | let [count, setCount] = useState(0); 10 | 11 | useEffect(() => { 12 | setInterval(() => { 13 | setCount(count + 1); 14 | }, 1000); 15 | }, []); 16 | 17 | return

{count}

; 18 | } 19 | ``` 20 | 21 | 页面上的 count 永远是 1,因为 useEffect 的依赖数组重没有包含 count。导致定时器中 count 永远是第一次渲染时的值,即 0 。页面上一直为 0+1 = 1 22 | 23 | ```js 24 | function Counter() { 25 | let [count, setCount] = useState(0); 26 | 27 | useEffect(() => { 28 | setInterval(() => { 29 | setCount(count + 1); 30 | }, 1000); 31 | }, [count]); 32 | 33 | return

{count}

; 34 | } 35 | ``` 36 | 37 | 现在在依赖数组中加入了 count,页面上的数值不一直为 1 了, 38 | 但是过不了一会儿,页面上的数字就会开始闪烁。 39 | 这是因为每次 count 变化后,都重新去运行了一遍 useEffect,导致生成了非常多的定时器。页面上结果为: 40 | 41 | - 0 + 1 42 | - 1 + 1 43 | - 2 + 1 44 | - 3 + 1 45 | - 4 + 1 46 | - ... 47 | 48 | 所以数字在闪烁。 49 | 50 | ## 正确的定时器设置 51 | 52 | ```js 53 | function Counter() { 54 | let [count, setCount] = useState(0); 55 | 56 | useEffect(() => { 57 | let id = setInterval(() => { 58 | setCount(count + 1); 59 | }, 1000); 60 | 61 | return () => clearInterval(id); 62 | }, [count]); 63 | 64 | return

{count}

; 65 | } 66 | ``` 67 | 68 | 每下一次渲染前都用 useEffect 的 return 销毁掉之前生成的 定时器。 69 | 70 | 不过这样是比较耗费性能的,每一次加一都要执行一遍创建和销毁定时器。可以使用箭头函数的方式来更新 count。 71 | 72 | ```js 73 | function Counter() { 74 | let [count, setCount] = useState(0); 75 | 76 | useEffect(() => { 77 | let id = setInterval(() => { 78 | setCount((count) => count + 1); 79 | }, 1000); 80 | 81 | return () => clearInterval(id); 82 | }, []); 83 | 84 | return

{count}

; 85 | } 86 | ``` 87 | 88 | ## 思考这样能不能实现定时器效果? 89 | 90 | ```js 91 | function Counter() { 92 | let [count, setCount] = useState(0); 93 | 94 | useEffect(() => { 95 | let id = setInterval(() => { 96 | setCount(count + 1); 97 | }, 1000); 98 | return () => clearInterval(id); 99 | }); 100 | 101 | return

{count}

; 102 | } 103 | ``` 104 | 105 | 答案是:会。 106 | 看似没有把 count 放入依赖数组中,但不使用依赖数组的情况下,useEffect 会在第一次渲染之后和每次更新之后都会执行。这就使得每次渲染都能拿到最新的 count 值,这样就能实现定时器效果了。 107 | 108 | 不过,这会导致一个非常隐蔽的 BUG,参见 Dan 的博客:https://overreacted.io/zh-hans/making-setinterval-declarative-with-react-hooks/#%E7%AC%AC%E4%B8%80%E6%AC%A1%E5%B0%9D%E8%AF%95 109 | 110 | 原因: setInterval 和它们不一样。当我们执行 clearInterval 和 setInterval 时,它们会进入时间队列里,如果我们频繁重渲染和重执行 effects,interval 有可能没有机会被执行! 111 | -------------------------------------------------------------------------------- /2-计算机基础/操作系统/死锁与银行家算法.md: -------------------------------------------------------------------------------- 1 | ## 死锁 2 | 3 | ### 死锁概念、产生原因 4 | 5 | 死锁是指多个进程循环等待彼此占有的资源而无限期的僵持等待下去的局面。原因是: 6 | 7 | - 系统提供的资源太少了,远不能满足并发进程对资源的需求 8 | - 进程推进顺序不合适,互相占有彼此需要的资源,同时请求对方占有的资源,往往是程序设计不合理 9 | 10 | ### 死锁产生的必要条件 11 | 12 | 需要同时具有以下四个条件: 13 | 14 | - 互斥条件:即某个资源在一段时间内只能由一个进程占有,不能同时被两个或两个以上的进程占有 15 | - 不可抢占条件:进程所获得的资源在未使用完毕之前,资源申请者不能强行的从资源占有者手中夺取资源,而只能由该资源的占有者进程自行释放 16 | - 占有且等待条件:进程至少已经占有了一个资源,但又申请了一个新的被其他进程所占有的资源,此时处于等待状态 17 | - 循环等待条件:若干个进程形成环形链,每个都占用对方申请的下一个资源 18 | 19 | ## 死锁的处理策略 20 | 21 | 为使系统不发生死锁,必须设法破坏产生死锁的四个必要条件之一,或者允许死锁产生,但当死锁发生时能检测出思索,并有能力实现恢复。 22 | 一般有死锁的预防、死锁避免、死锁的检测与恢复三种方法。 23 | 24 | 1. 死锁预防:破坏导致死锁必要条件中的任意一个就可以预防死锁。例如,要求用户申请资源时一次性申请所需要的全部资源,这就破坏了保持和等待条件;将资源分层,得到上一层资源后,才能够申请下一层资源,它破坏了环路等待条件。预防通常会降低系统的效率。 25 | 2. 死锁避免:避免是指进程在每次申请资源时判断这些操作是否安全,例如,使用银行家算法。死锁避免算法的执行会增加系统的开销。 26 | 3. 死锁检测:死锁预防和避免都是事前措施,而死锁的检测则是判断系统是否处于死锁状态,如果是,则执行死锁解除策略。 27 | 4. 死锁解除:这是与死锁检测结合使用的,它使用的方式就是剥夺。即将某进程所拥有的资源强行收回,分配给其他的进程。 28 | 29 | ### 死锁预防: 30 | 31 | - 打破互斥条件:允许进程同时访问资源(有些资源就是不可以同时访问的,无实用价值) 32 | - 打破不可抢占条件:比如给进程设置优先级,高优先级的可以抢占资源(实现困难,降低系统性能) 33 | - 打破占有且等待条件:实行资源预分配策略,即进程在运行前一次性的向系统申请它所需要的全部资源(不可预测资源的使用,利用率低,降低并发性) 34 | - 破坏循环等待条件:采用这种策略,即把资源事先分类编号,按号分配,使进程在申请,占用资源时不会形成环路。所有进程对资源的请求必须严格按资源序号递增的顺序提出(限制和编号实现困难,增加系统开销,有些资源暂时不用也需要先申请,增加了进程对资源的占用时间) 35 | 36 | ### 死锁避免 37 | 38 | 允许进程动态的申请资源,但系统在进行资源分配前,应先计算此次资源分配的安全性。若此次分配不会导致系统进入不安全状态,则将资源你分配给进程,否则,让进程等待。 39 | 40 | 所谓安全状态,是指系统能按某种进程推进顺序,为每个进程分配其所需的资源,直至满足每个进程对资源的最大需求,是每个进程都可以顺序的完成。此时成 P1P2P3...为安全序列,如果系统无法找到一个安全序列,则称系统处于不安全状态。 41 | 42 | 并非所有的不安全状态都是死锁状态,但当系统进入不安全状态后,便可能进入死锁状态;反之,只要系统处于安全状态,系统便可以避免进入死锁状态。 43 | **银行家算法**是最著名的死锁避免算法。 44 | 45 | ### 死锁的检测 46 | 47 | 资源分配图&&死锁定理 48 | 49 | ### 死锁解除 50 | 51 | 1. 资源剥夺法。挂起某些思索进程,并抢占它的资源,将这些资源分配给其他的死锁进程。但应防止被挂起的进程长时间得不到资源时,而处于资源匮乏的状态。 52 | 2. 进程撤销法。强制撤销一个或一部分进程并剥夺这些进程的资源。撤销的原则可以按进程的优先级和撤销进程代价的高低进行。 53 | 3. 进程回退法。让一个或多个进程回退到足以回避死锁的地步,进程回退时资源释放资源而不是被剥夺。要求系统保持进程的历史信息,设置还原点。 54 | 55 | ## 银行家算法 56 | 57 | 当一个进程申请使用资源的时候,银行家算法通过先**试探分配**给该进程资源,然后通过安全性算法**判断分配后的系统是否处于安全状态**,若不安全则试探分配作废,让该进程继续等待。 58 | ![](../../img/yhjsf.png) 59 | 60 | - 银行家算法中的进程: 61 | 62 | - 包含进程 Pi 的需求资源数量(也是**最大需求资源数量**,MAX) 63 | - **已分配**给该进程的资源 A(Allocation) 64 | - **还需要**的资源数量 N(Need=M-A) 65 | 66 | - Available 为**空闲资源数量**,即资源池(注意:资源池的剩余资源数量+已分配给所有进程的资源数量=系统中的资源总量) 67 | 68 | 假设资源 P1 申请资源,银行家算法先试探的分配给它(当然先要看看当前资源池中的资源数量够不够)。 69 | 若申请的资源数量小于等于 Available,然后接着判断分配给 P1 后剩余的资源,能不能使进程队列的某个进程执行完毕,若没有进程可执行完毕,则系统处于不安全状态(即此时没有一个进程能够完成并释放资源,随时间推移,系统终将处于死锁状态)。 70 | 71 | 若有进程可执行完毕,则假设回收已分配给它的资源(剩余资源数量增加),把这个进程标记为可完成,并继续判断队列中的其它进程,若所有进程都可执行完毕,则系统处于安全状态,并根据可完成进程的分配顺序生成安全序列。 72 | 73 | 如{P0,P3,P2,P1}表示将申请后的剩余资源 Work 先分配给 P0 74 | –> 75 | 回收(Work+已分配给 P0 的 A0=Work) 76 | –> 77 | 分配给 P3–>回收(Work+A3=Work) 78 | –> 79 | 分配给 P2 80 | –> 81 | ······ 82 | 满足所有进程 83 | 84 | 如此就可避免系统存在潜在死锁的风险。 85 | -------------------------------------------------------------------------------- /2-计算机基础/网络/Ajax.md: -------------------------------------------------------------------------------- 1 | # Ajax 2 | 3 | [Ajax | MDN](https://developer.mozilla.org/zh-CN/docs/Web/Guide/AJAX) 4 | 5 | AJAX 是异步的 JavaScript 和 XML(Asynchronous JavaScript And XML)。简单点说,就是使用 XMLHttpRequest 对象与服务器通信。 它可以使用 JSON,XML,HTML 和 text 文本等格式发送和接收数据。AJAX 最吸引人的就是它的“异步”特性,也就是说他可以在不重新刷新页面的情况下与服务器通信,交换数据,或更新页面。 6 | 7 | ### 创建一个简单的 Ajax 8 | 9 | - 创建 XMLHttpRequest 对象 10 | 11 | ```js 12 | if (window.XMLHttpRequest) { 13 | // Mozilla, Safari, IE7+ ... 14 | httpRequest = new XMLHttpRequest(); 15 | } else if (window.ActiveXObject) { 16 | // IE 6 and older 17 | httpRequest = new ActiveXObject("Microsoft.XMLHTTP"); 18 | } 19 | ``` 20 | 21 | - 绑定 onreadystatechange 事件 22 | 23 | ```js 24 | httpRequest.onreadystatechange = function () { 25 | // Process the server response here. 26 | }; 27 | ``` 28 | 29 | - 向服务器发送请求 30 | 31 | ```js 32 | httpRequest.open("GET", "http://www.example.org/some.file", true); 33 | httpRequest.send(); 34 | ``` 35 | 36 | 完整的例子 37 | 38 | ```js 39 | function ajax(url, cb) { 40 | let xhr; 41 | if (window.XMLHttpRequest) { 42 | xhr = new XMLHttpRequest(); 43 | } else { 44 | xhr = ActiveXObject("Microsoft.XMLHTTP"); 45 | } 46 | xhr.onreadystatechange = function () { 47 | if (xhr.readyState == 4 && xhr.status == 200) { 48 | cb(xhr.responseText); 49 | } 50 | }; 51 | xhr.open("GET", url, true); 52 | xhr.send(); 53 | } 54 | ``` 55 | 56 | ### httpRequest.readyState 的值 57 | 58 | - 0 (未初始化) or (请求还未初始化) 59 | - 1 (正在加载) or (已建立服务器链接) 60 | - 2 (加载成功) or (请求已接受) 61 | - 3 (交互) or (正在处理请求) 62 | - 4 (完成) or (请求已完成并且响应已准备好) 63 | 64 | ### 访问服务端返回的数据 65 | 66 | - httpRequest.responseText 67 | - 服务器以文本字符的形式返回 68 | - httpRequest.responseXML 69 | - 以 XMLDocument 对象方式返回,之后就可以使用 JavaScript 来处理 70 | 71 | ### GET 注意事项 72 | 73 | - 如果不设置响应头 `Cache-Control: no-cache` 浏览器将会把响应缓存下来而且再也不无法重新提交请求。你也可以添加一个总是不同的 GET 参数,比如时间戳或者随机数 (详情见 [bypassing the cache](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#Bypassing_the_cache)) 74 | 75 | ### POST 请求 76 | 77 | POST 请求则需要设置`RequestHeader`告诉后台传递内容的编码方式以及在 send 方法里传入对应的值 78 | 79 | ```js 80 | xhr.open("POST", url, true); 81 | xhr.setRequestHeader(("Content-Type": "application/x-www-form-urlencoded")); 82 | xhr.send("key1=value1&key2=value2"); 83 | ``` 84 | 85 | ### Ajax 与 cookie 86 | 87 | - ajax 会自动带上同源的 cookie,不会带上不同源的 cookie 88 | - 可以通过前端设置 withCredentials 为 true, 后端设置 Header 的方式让 ajax 自动带上不同源的 cookie,但是这个属性对同源请求没有任何影响。会被自动忽略。 89 | 90 | [withCredentials | MDN](https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest/withCredentials) 91 | 92 | ```js 93 | var xhr = new XMLHttpRequest(); 94 | xhr.open("GET", "http://example.com/", true); 95 | xhr.withCredentials = true; 96 | xhr.send(null); 97 | ``` 98 | -------------------------------------------------------------------------------- /3-编程能力/编程题与分析题/以下代码输出值.md: -------------------------------------------------------------------------------- 1 | ### 对象引用问题 - 1 2 | 3 | ```js 4 | var a = { n: 1 }; 5 | var b = a; 6 | a.x = a = { n: 2 }; 7 | 8 | console.log(a.x); // --> undefined 9 | console.log(b.x); // --> {n: 2} 10 | ``` 11 | 12 | 1. **优先级**。`.`的优先级高于`=`,所以先执行 a.x,堆内存中的{n: 1}就会变成{n: 1, x: undefined},改变之后相应的 b.x 也变化了,因为指向的是同一个对象。 13 | 2. **赋值操作是从右到左**,所以先执行 a = {n: 2},a 的引用就被改变了,然后这个返回值又赋值给了 a.x,需要注意的是这时候 a.x 是第一步中的{n: 1, x: undefined}那个对象,其实就是 b.x,相当于 b.x = {n: 2} 14 | 15 | ### 对象引用问题 - 2 16 | 17 | ```js 18 | function changeObjProperty(o) { 19 | o.siteUrl = "http://www.baidu.com"; 20 | o = new Object(); 21 | o.siteUrl = "http://www.google.com"; 22 | } 23 | let webSite = new Object(); 24 | changeObjProperty(webSite); 25 | console.log(webSite.siteUrl); 26 | ``` 27 | 28 | 答案: "http://www.baidu.com" 29 | 原因: o = new Object() 这句代码切断了原本对 o 的引用 30 | 31 | ### ['1', '2', '3'].map(parseInt) 答案是多少? 32 | 33 | 答案 [1, NaN, NaN] 34 | 35 | map 会给函数传递 3 个参数: (elem, index, array),当相与: 36 | 37 | ```js 38 | ["1", "2", "3"].map((item, index) => { 39 | return parseInt(item, index); 40 | }); 41 | ``` 42 | 43 | parseInt 接收两个参数(sting, radix),其中 radix 代表进制。省略 radix 或 radix = 0,则数字将以十进制解析 44 | 45 | 因此,map 遍历 ["1", "2", "3"],相应 parseInt 接收参数如下 46 | 47 | ```js 48 | parseInt("1", 0); // 1 49 | parseInt("2", 1); // NaN 50 | parseInt("3", 2); // NaN 51 | ``` 52 | 53 | ### 考 Symble 54 | 55 | ```js 56 | // example 1 57 | var a={}, b='123', c=123; 58 | a[b]='b'; 59 | a[c]='c'; 60 | console.log(a[b]); 61 | 62 | --------------------- 63 | // example 2 64 | var a={}, b=Symbol('123'), c=Symbol('123'); 65 | a[b]='b'; 66 | a[c]='c'; 67 | console.log(a[b]); 68 | 69 | --------------------- 70 | // example 3 71 | var a={}, b={key:'123'}, c={key:'456'}; 72 | a[b]='b'; 73 | a[c]='c'; 74 | console.log(a[b]); 75 | ``` 76 | 77 | ```js 78 | // example 1 79 | var a = {}, 80 | b = "123", 81 | c = 123; 82 | a[b] = "b"; 83 | 84 | // c 的键名会被转换成字符串'123',这里会把 b 覆盖掉。 85 | a[c] = "c"; 86 | 87 | // 输出 c 88 | console.log(a[b]); 89 | // example 2 90 | var a = {}, 91 | b = Symbol("123"), 92 | c = Symbol("123"); 93 | 94 | // b 是 Symbol 类型,不需要转换。 95 | a[b] = "b"; 96 | 97 | // c 是 Symbol 类型,不需要转换。任何一个 Symbol 类型的值都是不相等的,所以不会覆盖掉 b。 98 | a[c] = "c"; 99 | 100 | // 输出 b 101 | console.log(a[b]); 102 | // example 3 103 | var a = {}, 104 | b = { key: "123" }, 105 | c = { key: "456" }; 106 | 107 | // b 不是字符串也不是 Symbol 类型,需要转换成字符串。 108 | // 对象类型会调用 toString 方法转换成字符串 [object Object]。 109 | a[b] = "b"; 110 | 111 | // c 不是字符串也不是 Symbol 类型,需要转换成字符串。 112 | // 对象类型会调用 toString 方法转换成字符串 [object Object]。这里会把 b 覆盖掉。 113 | a[c] = "c"; 114 | 115 | // 输出 c 116 | console.log(a[b]); 117 | ``` 118 | -------------------------------------------------------------------------------- /2-计算机基础/网络/HTTPS.md: -------------------------------------------------------------------------------- 1 | # HTTPS 2 | 3 | http 默认采用 80 作为通讯端口,对于传输采用不加密的方式,https 默认采用 443,对于传输的数据进行加密传输。 4 | 5 | ## 密码学基础 6 | 7 | 明文: 明文指的是未被加密过的原始数据。 8 | 9 | 密文:明文被某种加密算法加密之后,会变成密文,从而确保原始数据的安全。密文也可以被解密,得到原始的明文。 10 | 11 | 密钥:密钥是一种参数,它是在明文转换为密文或将密文转换为明文的算法中输入的参数。密钥分为对称密钥与非对称密钥,分别应用在对称加密和非对称加密上。 12 | 13 | ### 对称加密 14 | 15 | 对称加密又叫做私钥加密,即信息的发送方和接收方使用同一个密钥去加密和解密数据。对称加密的特点是算法公开、加密和解密速度快,适合于对大数据量进行加密,常见的对称加密算法有 DES、3DES、TDEA、Blowfish、RC5 和 IDEA。 16 | 17 | ``` 18 | 其加密过程如下:明文 + 加密算法 + 私钥 => 密文 19 | 解密过程如下:密文 + 解密算法 + 私钥 => 明文 20 | ``` 21 | 22 | 对称加密中用到的密钥叫做私钥,私钥表示个人私有的密钥,即该密钥不能被泄露。 23 | 24 | 其加密过程中的私钥与解密过程中用到的私钥是同一个密钥,这也是称加密之所以称之为“对称”的原因。由于对称加密的算法是公开的,所以一旦私钥被泄露,那么密文就很容易被破解,所以对称加密的缺点是密钥安全管理困难。 25 | 26 | ### 非对称加密 27 | 28 | 非对称加密也叫做公钥加密。非对称加密与对称加密相比,其安全性更好。对称加密的通信双方使用相同的密钥,如果一方的密钥遭泄露,那么整个通信就会被破解。而非对称加密使用一对密钥,即公钥和私钥,且二者成对出现。私钥被自己保存,不能对外泄露。公钥指的是公共的密钥,任何人都可以获得该密钥。用公钥或私钥中的任何一个进行加密,用另一个进行解密。 29 | 30 | - **被公钥加密过的密文只能被私钥解密**,过程如下: 31 | 32 | ``` 33 | 明文 + 加密算法 + 公钥 => 密文, 密文 + 解密算法 + 私钥 => 明文 34 | ``` 35 | 36 | - **被私钥加密过的密文只能被公钥解密**,过程如下: 37 | 38 | ``` 39 | 明文 + 加密算法 + 私钥 => 密文, 密文 + 解密算法 + 公钥 => 明文 40 | ``` 41 | 42 | 由于加密和解密使用了两个不同的密钥,这就是非对称加密“非对称”的原因。 43 | 非对称加密的缺点是加密和解密花费时间长、速度慢,只适合对少量数据进行加密。 44 | 在非对称加密中使用的主要算法有:RSA、Elgamal、Rabin、D-H、ECC(椭圆曲线加密算法)等。 45 | 46 | ## HTTPS 通信过程 47 | 48 | **HTTPS 协议 = HTTP 协议 + SSL/TLS 协议**,在 HTTPS 数据传输的过程中,需要用 SSL/TLS 对数据进行加密和解密,需要用 HTTP 对加密后的数据进行传输,由此可以看出 HTTPS 是由 HTTP 和 SSL/TLS 一起合作完成的。 49 | 50 | **SSL**的全称是 Secure Sockets Layer,即安全套接层协议,是为网络通信提供安全及数据完整性的一种安全协议。SSL 协议在 1994 年被 Netscape 发明,后来各个浏览器均支持 SSL,其最新的版本是 3.0。 51 | 52 | **TLS**的全称是 Transport Layer Security,即安全传输层协议,最新版本的 TLS(Transport Layer Security,传输层安全协议)是 IETF(Internet Engineering Task Force,Internet 工程任务组)制定的一种新的协议,它建立在 SSL 3.0 协议规范之上,是 SSL 3.0 的后续版本。在 TLS 与 SSL3.0 之间存在着显著的差别,主要是它们所支持的加密算法不同,所以 TLS 与 SSL3.0 不能互操作。虽然 TLS 与 SSL3.0 在加密算法上不同,但是在我们理解 HTTPS 的过程中,我们可以把 SSL 和 TLS 看做是同一个协议。 53 | 54 | HTTPS 为了兼顾安全与效率,**同时使用了对称加密和非对称加密**。数据是被对称加密传输的,对称加密过程需要客户端的一个密钥,为了确保能把该密钥安全传输到服务器端,采用非对称加密对该密钥进行加密传输,总的来说,**对数据进行对称加密,对称加密所要使用的密钥通过非对称加密传输**。 55 | 56 | ![加密](../../img/httpscrypt.png) 57 | 58 | HTTPS 在传输的过程中会涉及到三个密钥: 59 | 60 | - 服务器端的公钥和私钥,用来进行非对称加密 61 | - 客户端生成的随机密钥,用来进行对称加密 62 | 63 | 一个 HTTPS 请求实际上包含了两次 HTTP 传输,可以细分为 8 步。 64 | 65 | 1. 客户端向服务器发起 HTTPS 请求,连接到服务器的 443 端口 66 | 2. 服务器端有一个密钥对,即公钥和私钥,是用来进行非对称加密使用的,服务器端保存着私钥,不能将其泄露,公钥可以发送给任何人。 67 | 3. 服务器将自己的公钥发送给客户端。 68 | 4. 客户端收到服务器端的公钥之后,会对公钥进行检查,验证其合法性,如果发现发现公钥有问题,那么 HTTPS 传输就无法继续。严格的说,这里应该是验证服务器发送的数字证书的合法性。如果公钥合格,那么客户端会生成一个随机值,这个随机值就是用于进行对称加密的密钥,我们将该密钥称之为 client key,即客户端密钥,这样在概念上和服务器端的密钥容易进行区分。然后用服务器的公钥对客户端密钥进行非对称加密,这样客户端密钥就变成密文了,至此,HTTPS 中的第一次 HTTP 请求结束。 69 | 5. 客户端会发起 HTTPS 中的第二个 HTTP 请求,将加密之后的客户端密钥发送给服务器。 70 | 6. 服务器接收到客户端发来的密文之后,会用自己的私钥对其进行非对称解密,解密之后的明文就是客户端密钥,然后用客户端密钥对数据进行对称加密,这样数据就变成了密文。 71 | 7. 然后服务器将加密后的密文发送给客户端。 72 | 8. 客户端收到服务器发送来的密文,用客户端密钥对其进行对称解密,得到服务器发送的数据。这样 HTTPS 中的第二个 HTTP 请求结束,整个 HTTPS 传输完成。 73 | 74 | 原文链接:https://www.jianshu.com/p/14cd2c9d2cd2 75 | -------------------------------------------------------------------------------- /5-性能优化/从输入URL到页面加载完成的过程.md: -------------------------------------------------------------------------------- 1 | ### 从输入 URL 到页面加载完成的过程 2 | 3 | [参考链接](https://segmentfault.com/a/1190000006879700) 4 | 5 | ![输入URL后.png](../../img/输入URL后.png) 6 | 7 | 1. 在浏览器地址栏输入 URL 8 | 2. 判断是否有永久重定向(301) 9 | 1. 如果有,直接跳转到对应 URL 10 | 3. 浏览器查看资源是否有**强缓存**,有则直接使用,如果是**协商缓存**则需要到服务器进行校验资源是否可用 11 | 1. 检验新鲜通常有两个 HTTP 头进行控制`Expires`和`Cache-Control`: 12 | - HTTP1.0 提供 Expires,值为一个绝对时间表示缓存新鲜日期 13 | - HTTP1.1 增加了 Cache-Control: max-age=,值为以秒为单位的最大新鲜时间 14 | 4. 浏览器**解析 URL**获取协议,主机,端口,path 15 | 5. 浏览器**组装一个 HTTP(GET)请求报文** 16 | 6. **DNS 解析**,查找过程如下: 17 | 1. 浏览器缓存 18 | 2. 本机缓存 19 | 3. hosts 文件 20 | 4. 路由器缓存 21 | 5. ISP DNS 缓存 22 | 6. DNS 查询(递归查询 / 迭代查询) 23 | 7. **端口建立 TCP 链接**,三次握手如下: 24 | 1. 客户端发送一个 TCP 的**SYN=1,Seq=X**的包到服务器端口 25 | 2. 服务器发回**SYN=1, ACK=X+1, Seq=Y**的响应包 26 | 3. 客户端发送**ACK=Y+1, Seq=Z** 27 | 8. TCP 链接建立后**发送 HTTP 请求** 28 | 9. 服务器接受请求并解析,将请求转发到服务程序,如虚拟主机使用 HTTP Host 头部判断请求的服务程序 29 | 10. 服务器检查**HTTP 请求头是否包含缓存验证信息**如果验证缓存新鲜,返回**304**等对应状态码 30 | 11. 处理程序读取完整请求并准备 HTTP 响应,可能需要查询数据库等操作 31 | 12. 服务器将**响应报文通过 TCP 连接发送回浏览器** 32 | 13. 浏览器接收 HTTP 响应,然后根据情况选择**关闭 TCP 连接或者保留重用,关闭 TCP 连接的四次挥手如下**: 33 | 1. 主动方发送**Fin=1, Ack=Z, Seq= X**报文 34 | 2. 被动方发送**ACK=X+1, Seq=Z**报文 35 | 3. 被动方发送**Fin=1, ACK=X, Seq=Y**报文 36 | 4. 主动方发送**ACK=Y, Seq=X**报文 37 | 14. 浏览器检查响应状态吗:是否为 1XX,3XX, 4XX, 5XX,这些情况处理与 2XX 不同 38 | 15. 如果资源可缓存,**进行缓存** 39 | 16. 对响应进行**解码**(例如 gzip 压缩) 40 | 17. 根据资源类型决定如何处理(假设资源为 HTML 文档) 41 | 18. **解析 HTML 文档,构件 DOM 树,下载资源,构造 CSSOM 树,执行 js 脚本**,这些操作没有严格的先后顺序,以下分别解释 42 | 19. **构建 DOM 树**: 43 | 1. **Tokenizing**:根据 HTML 规范将字符流解析为标记 44 | 2. **Lexing**:词法分析将标记转换为对象并定义属性和规则 45 | 3. **DOM construction**:根据 HTML 标记关系将对象组成 DOM 树 46 | 20. 解析过程中遇到图片、样式表、js 文件,**启动下载** 47 | 21. 构建**CSSOM 树**: 48 | 1. **Tokenizing**:字符流转换为标记流 49 | 2. **Node**:根据标记创建节点 50 | 3. **CSSOM**:节点创建 CSSOM 树 51 | 22. **[根据 DOM 树和 CSSOM 树构建渲染树](https://developers.google.com/web/fundamentals/performance/critical-rendering-path/render-tree-construction)**: 52 | 1. 从 DOM 树的根节点遍历所有**可见节点**,不可见节点包括:1)`script`,`meta`这样本身不可见的标签。2)被 css 隐藏的节点,如`display: none` 53 | 2. 对每一个可见节点,找到恰当的 CSSOM 规则并应用 54 | 3. 发布可视节点的内容和计算样式 55 | 23. **js 解析如下**: 56 | 1. 浏览器创建 Document 对象并解析 HTML,将解析到的元素和文本节点添加到文档中,此时**document.readystate 为 loading** 57 | 2. HTML 解析器遇到**没有 async 和 defer 的 script 时**,将他们添加到文档中,然后执行行内或外部脚本。这些脚本会同步执行,并且在脚本下载和执行时解析器会暂停。这样就可以用 document.write()把文本插入到输入流中。**同步脚本经常简单定义函数和注册事件处理程序,他们可以遍历和操作 script 和他们之前的文档内容** 58 | 3. 当解析器遇到设置了**async**属性的 script 时,开始下载脚本并继续解析文档。脚本会在它**下载完成后尽快执行**,但是**解析器不会停下来等它下载**。异步脚本**禁止使用 document.write()**,它们可以访问自己 script 和之前的文档元素 59 | 4. 当文档完成解析,document.readState 变成 interactive 60 | 5. 所有**defer**脚本会**按照在文档出现的顺序执行**,延迟脚本**能访问完整文档树**,禁止使用 document.write() 61 | 6. 浏览器**在 Document 对象上触发 DOMContentLoaded 事件** 62 | 7. 此时文档完全解析完成,浏览器可能还在等待如图片等内容加载,等这些**内容完成载入并且所有异步脚本完成载入和执行**,document.readState 变为 complete,window 触发 load 事件 63 | 24. **显示页面**(HTML 解析过程中会逐步显示页面) 64 | -------------------------------------------------------------------------------- /0-前端基础/CSS/动画/README.md: -------------------------------------------------------------------------------- 1 | # CSS 动画 2 | 3 | - 位置 - 平移 4 | - 方向 - 旋转 5 | - 大小 - 缩放 6 | - 透明度 7 | - 其他 - 线形变换 8 | 9 | ### 前端动画怎么做 10 | 11 | - animation 过渡动画 12 | - transition 过渡动画 13 | - JS 原生控制 DOM 位置 14 | - canvas 绘制动画 15 | 16 | ### transition 过渡动画 17 | 18 | 用来控制过渡的时间,使用过渡的属性,过渡效果曲线,过渡的延时 19 | 20 | 要求元素的状态必须有变化,即某 CSS 值变化时发生的动画 21 | 22 | - transition-property 23 | - 规定设置过渡效果的 CSS 属性的名称。 24 | - transition-duration 25 | - 规定完成过渡效果需要多少秒或毫秒。 26 | - transition-timing-function 27 | - 规定速度效果的速度曲线。 28 | - transition-delay 29 | - 定义过渡效果何时开始 30 | 31 | 在 chrome 的调试窗口按下 esc 在下面出现一个框框,选择 animation 就可以看到动画面板了 32 | 33 | ```css 34 | div { 35 | width: 100px; 36 | height: 100px; 37 | background: blue; 38 | transition: width 2s, background 1s; 39 | } 40 | div:hover { 41 | background: orange; 42 | width: 300px; 43 | } 44 | ``` 45 | 46 | ### transition-timing-function 47 | 48 | - ease 慢速开始,然后变快,然后慢速结束 49 | - ease-in 慢速开始 50 | - ease-out 慢结束 51 | - ease-in-out 52 | - linear 53 | - cubic-bezier(a,b,c,d) 54 | 55 | bezier 曲线在线效果网址 [cubic-bezier.com](http://cubic-bezier.com) 56 | 57 | ### animation 关键帧动画 58 | 59 | 相当于多个补间动画组合到一起 60 | 61 | 与 transition 不同的是,他可以让元素自己动,而不要求某值的改变来触发动画 62 | 63 | `animation: name duration timing-function delay iteration-count direction;` 64 | 65 | - animation-name 66 | - 规定需要绑定到选择器的 keyframe 名称。 67 | - animation-duration 68 | - 规定完成动画所花费的时间,以秒或毫秒计 69 | - animation-timing-function 70 | - 动画的速度曲线 71 | - animation-delay 72 | - 动画开始之前的延迟 73 | - animation-iteration-count 74 | - n | infinit 75 | - 动画应该播放的次数 76 | - animation-direction 77 | - normal | alternate 78 | - 是否应该轮流反向播放动画 79 | - animation-play-state 80 | - 可用于暂停动画 81 | - animation-fill-mode 82 | - forwards 动画停了就保持最后的那个状态 83 | - backwards 动画停了还得反着做一遍回去 84 | - 在动画执行之前和之后如何给动画的目标应用样式。 85 | 86 | ```css 87 | #one { 88 | width: 50px; 89 | height: 50px; 90 | background-color: orange; 91 | animation: run; 92 | animation-delay: 0.5s; 93 | animation-duration: 2s; 94 | animation-fill-mode: forwards; 95 | } 96 | @keyframes run { 97 | 0% { 98 | width: 100px; 99 | } 100 | 50% { 101 | width: 400px; 102 | background-color: blue; 103 | } 104 | 100% { 105 | width: 800px; 106 | } 107 | } 108 | ``` 109 | 110 | ### 逐帧动画 111 | 112 | 关键帧之间是有补间的,会选一个效果过渡过去,而逐帧动画则是每个 keyframe 之间没有过渡,直接切换过去 113 | 参考[猎豹奔跑](./animal.html) 114 | 关键是使用下面这行 CSS 115 | `animation-timing-function: steps(1);` 116 | 这个 step 是指定关键帧之间需要有几个画面 117 | 118 | ### 过渡动画和关键帧动画的区别 119 | 120 | - 过渡动画需要有状态变化 121 | - 关键帧动画不需要状态变化 122 | - 关键帧动画能控制更精细 123 | 124 | ### CSS 动画的性能 125 | 126 | - CSS 动画不差 127 | - 部分情况下优于 JS 128 | - JS 可以做到更精细 129 | - 含高危属性,会让性能变差 (如 box-shadow) 130 | 131 | ### display 属性 132 | 133 | 当改变元素 display 属性时,过渡属性 transition 失效。 134 | 135 | 原因: 136 | display:none 的时候,页面文档流中将不会存在该元素。transition 无法对一个从有到无的元素产生过渡效果。 137 | 138 | 解决方法: 139 | 140 | 1. 改变元素的宽/高为 0px,达到隐藏的目的。 141 | 2. 使用 visibility 替代 display。 142 | 3. react 使用 react-transition-group 实现 143 | -------------------------------------------------------------------------------- /0-前端基础/CSS/CSS选择器.md: -------------------------------------------------------------------------------- 1 | ### CSS 选择器分类 2 | 3 | - 标签选择 4 | - id 选择器 5 | - class 选择器 6 | - 后代选择 (div a) 7 | - 子代选择 (div > p) 8 | - 相邻选择 (div + p) 9 | - 通配符选择 (\*) 10 | - 否定选择器 :not(.link){} 11 | - 属性选择器 12 | - 伪类选择器 13 | - 伪元素选择器 ::before{} 14 | 15 | ### CSS3 属性选择器 16 | 17 | | 选择器 | 描述 | 18 | | ------------------- | ------------------------------------------------------------ | 19 | | [attribute] | 用于选取带有指定属性的元素。 | 20 | | [attribute=value] | 用于选取带有指定属性和值的元素。 | 21 | | [attribute~=value] | 用于选取属性值中包含指定词汇的元素。 | 22 | | [attribute\|=value] | 用于选取带有以指定值开头的属性值的元素,该值必须是整个单词。 | 23 | | [attribute^=value] | 匹配属性值以指定值开头的每个元素。 | 24 | | [attribute$=value] | 匹配属性值以指定值结尾的每个元素。 | 25 | | [attribute*=value] | 匹配属性值中包含指定值的每个元素。 | 26 | 27 | ### CSS3 伪类选择器 28 | 29 | [伪类 | MDN](https://developer.mozilla.org/zh-CN/docs/Web/CSS/Pseudo-classes#%E6%A0%87%E5%87%86%E4%BC%AA%E7%B1%BB%E7%B4%A2%E5%BC%95) 30 | 常用: 31 | 32 | - :hover 33 | - :focus 34 | - :after 在元素之前添加内容,也可以用来做清除浮动。 35 | - :before 在元素之后添加内容 36 | - :enabled 选择器匹配每个已启用的元素(大多用在表单元素上)。 37 | - :disabled 控制表单控件的禁用状态。 38 | - :checked 单选框或复选框被选中 39 | - ::selection 用户选中的区域 40 | - :empty 一般用来隐藏内部什么都没有的元素 41 | - :not(selecter) 42 | - 43 | - p:first-of-type 44 | - p:last-of-type 45 | - p:only-of-type 46 | - p:nth-of-type(n) 47 | - p:nth-last-of-type(n) 48 | - 49 | - :nth-child(n) 50 | - :nth-last-child(n) 51 | - p:only-child 52 | 53 | ### 伪类和伪元素区别 54 | 55 | - 伪类值一种状态 比如:hover 56 | - 伪元素是一个真实存在的元素,他可以有样式有内容 57 | 58 | ### iconfont 原理 59 | 60 | - 利用编码让图标编为一个字符 61 | - 引入字体 62 | - 利用 before 伪元素向页面中插入一个文字 63 | 64 | ### css 定义的权重 65 | 66 | - !important 优先级最高,但也会被权重高的 important 所覆盖 67 | - 行内样式总会覆盖外部样式表的任何样式(除了!important) 68 | - 单独使用一个选择器的时候,不能跨等级使 css 规则生效 69 | - 如果两个权重不同的选择器作用在同一元素上,权重值高的 css 规则生效 70 | - 如果两个相同权重的选择器作用在同一元素上:以后面出现的选择器为最后规则 71 | - 权重相同时,与元素距离近的选择器生 72 | 73 | 一句话总结: 74 | !important > 行内样式 > ID 选择器 > (类选择器 | 属性选择器 | 伪类选择器 ) > 元素选择器 > \* 75 | ![大鱼吃小鱼](http://image.zhangxinxu.com/image/blog/201208/specifishity1-1.png) 76 | 77 | ### 浏览器解析 CSS 78 | 79 | `.wrapper div > p` CSS 中,浏览器查找元素是通过选择权从后往前找的, 这样做的目的是加快 CSS 解析速度,从后往前,排除法 80 | 81 | [浏览器解析 css 选择器的规则](https://blog.csdn.net/qq_21397815/article/details/72874932) 82 | 83 | ### 怎样美化一个 checkbox ? 84 | 85 | - 让原本的勾选框隐藏 86 | - `input + label` 背景图没选中 87 | - `input:checked + label` 背景图选中 88 | 89 | ```css 90 | .checkbox input { 91 | display: none; 92 | } 93 | .checkbox input + label { 94 | background: url(./没选中.png) left center no-repeat; 95 | background-size: 20px 20px; 96 | padding-left: 20px; 97 | } 98 | .checkbox input:checked + label { 99 | background-image: url(./选中.png); 100 | } 101 | ``` 102 | 103 | ```html 104 |
105 | 106 | 107 |
108 | ``` 109 | -------------------------------------------------------------------------------- /3-编程能力/编程题与分析题/异步编程.md: -------------------------------------------------------------------------------- 1 | ### promise 与 setTimeout 判断执行顺序 2 | 3 | promise 和 setTimeout 都会将事件放入异步队列,但 setTimeout 即便是写 0,也会有 4ms 的延迟 4 | 5 | ```js 6 | console.log("begin"); 7 | 8 | setTimeout(() => { 9 | console.log("setTimeout 1"); 10 | 11 | Promise.resolve() 12 | .then(() => { 13 | console.log("promise 1"); 14 | setTimeout(() => { 15 | console.log("setTimeout2"); 16 | }); 17 | }) 18 | .then(() => { 19 | console.log("promise 2"); 20 | }); 21 | 22 | new Promise((resolve) => { 23 | console.log("a"); 24 | resolve(); 25 | }).then(() => { 26 | console.log("b"); 27 | }); 28 | }, 0); 29 | console.log("end"); 30 | ``` 31 | 32 | 答案 33 | 34 | ``` 35 | begin 36 | end 37 | setTimeout 1 38 | a 39 | promise 1 40 | b 41 | promise 2 42 | setTimeout2 43 | ``` 44 | 45 | ### async 函数的使用 46 | 47 | ```js 48 | function repeat(func, times, wait) {} 49 | // 输入 50 | const repeatFunc = repeat(alert, 4, 3000); 51 | 52 | // 输出 53 | // 会alert4次 helloworld, 每次间隔3秒 54 | repeatFunc("hellworld"); 55 | // 会alert4次 worldhellp, 每次间隔3秒 56 | repeatFunc("worldhello"); 57 | ``` 58 | 59 | 我自己的实现,没有成功。这种实现是 setTimeout 新建了两个,然而只清理了一个。 60 | 61 | ```js 62 | function repeat(func, times, wait) { 63 | var timer = null; 64 | var count = 0; 65 | return function (...args) { 66 | timer = setInterval(function () { 67 | func.apply(null, args); 68 | count++; 69 | console.log("count", count, "times", times); 70 | if (count >= times) { 71 | clearInterval(timer); 72 | } 73 | }, wait); 74 | }; 75 | } 76 | // 输入 77 | const repeatFunc = repeat(console.log, 4, 3000); 78 | // 输出 79 | // 会alert4次 helloworld, 每次间隔3秒 80 | repeatFunc("hellworld"); 81 | // 会alert4次 worldhellp, 每次间隔3秒 82 | repeatFunc("worldhello"); 83 | ``` 84 | 85 | 正确解法:使用 async/await 来实现 86 | 87 | ```js 88 | async function wait(seconds) { 89 | return new Promise((res) => { 90 | setTimeout(res, seconds); 91 | }); 92 | } 93 | 94 | function repeat(func, times, s) { 95 | return async function (...args) { 96 | for (let i = 0; i < times; i++) { 97 | func.apply(null, args); 98 | await wait(s); 99 | } 100 | }; 101 | } 102 | 103 | let log = console.log; 104 | let repeatFunc = repeat(log, 4, 3000); 105 | repeatFunc("HelloWorld"); 106 | repeatFunc("WorldHello"); 107 | ``` 108 | 109 | ### async 执行练习 110 | 111 | - await 后面的才是异步的,之前都是同步的 112 | 113 | ```js 114 | async function async1() { 115 | console.log("async1 start"); // 2 116 | await async2(); 117 | console.log("async1 end"); // 6 118 | } 119 | 120 | async function async2() { 121 | console.log("async2"); // 3 122 | } 123 | 124 | console.log("script start"); // 1 125 | 126 | setTimeout(function () { 127 | console.log("setTimeout"); // 8 128 | }, 0); 129 | 130 | async1(); 131 | 132 | new Promise(function (resolve) { 133 | console.log("promise1"); // 4 134 | resolve(); 135 | }).then(function () { 136 | console.log("promise2"); // 7 137 | }); 138 | 139 | console.log("script end"); // 5 140 | ``` 141 | -------------------------------------------------------------------------------- /1-前端框架与库/TypeScript/装饰器.md: -------------------------------------------------------------------------------- 1 | # 装饰器 2 | 3 | 装饰器函数(Decorator)用于给对象在运行期间动态的增加某个功能,职责等,装饰器本身是一个函数。 4 | 5 | ## 类装饰器 6 | 7 | 类装饰器接受的参数是构造函数。通过下面的方法可以让装饰后的类获取到装饰器中定义的方法,否则无此方法提示。 8 | 9 | ```ts 10 | function testDecorator() { 11 | return function any>(constructor: T) { 12 | return class extends constructor { 13 | name = "xiansheng"; 14 | getName() { 15 | return this.name; 16 | } 17 | }; 18 | }; 19 | } 20 | 21 | const Test = testDecorator()( 22 | class { 23 | name: string; 24 | constructor(name: string) { 25 | this.name = name; 26 | } 27 | } 28 | ); 29 | 30 | const test = new Test("haha"); 31 | console.log(test.getName()); 32 | ``` 33 | 34 | ## 类中方法的装饰器 35 | 36 | - 普通方法,target 对应的是类的 prototype 37 | - 静态方法,target 对应的是类的构造函数 38 | 39 | ```ts 40 | function getNameDecorator( 41 | target: any, 42 | key: string, 43 | descriptor: PropertyDescriptor 44 | ) { 45 | // console.log(target, key); 46 | // descriptor.writable = true; 47 | descriptor.value = function () { 48 | return "decorator"; 49 | }; 50 | } 51 | 52 | class Test { 53 | name: string; 54 | constructor(name: string) { 55 | this.name = name; 56 | } 57 | @getNameDecorator 58 | getName() { 59 | return this.name; 60 | } 61 | } 62 | 63 | const test = new Test("haha"); 64 | console.log(test.getName()); 65 | // -> decorator 66 | ``` 67 | 68 | ## 类的访问器装饰器 69 | 70 | ```ts 71 | function visitDecorator( 72 | target: any, 73 | key: string, 74 | descriptor: PropertyDescriptor 75 | ) { 76 | descriptor.writable = false; 77 | } 78 | 79 | class Test { 80 | private _name: string; 81 | constructor(name: string) { 82 | this._name = name; 83 | } 84 | get name() { 85 | return this._name; 86 | } 87 | @visitDecorator 88 | set name(name: string) { 89 | this._name = name; 90 | } 91 | } 92 | 93 | const test = new Test("hu"); 94 | test.name = "yao"; // 报错 95 | console.log(test.name); 96 | ``` 97 | 98 | ## 属性的装饰器 99 | 100 | - 可返回 descriptor 101 | - target 上修改的是原型上属性 102 | 103 | ```ts 104 | function nameDecorator1(target: any, key: string): any { 105 | const descriptor: PropertyDescriptor = { 106 | writable: false, 107 | }; 108 | return descriptor; 109 | } 110 | 111 | // 修改的并不是实例上的 name, 而是原型上的 name 112 | function nameDecorator2(target: any, key: string): any { 113 | target[key] = 20; 114 | } 115 | 116 | // name 放在实例上 117 | class Test { 118 | @nameDecorator1 119 | name = "a"; 120 | @nameDecorator2 121 | age = 18; 122 | } 123 | 124 | const test = new Test(); 125 | console.log((test as any).__proto__.name); 126 | ``` 127 | 128 | ## 参数装饰器 129 | 130 | ```ts 131 | // 原型,方法名,参数所在的位置 132 | function paramDecorator(target: any, method: string, paramIndex: number) { 133 | console.log(target, method, paramIndex); 134 | } 135 | 136 | class Test { 137 | getInfo(name: string, @paramDecorator age: number) { 138 | console.log(name, age); 139 | } 140 | } 141 | 142 | const test = new Test(); 143 | test.getInfo("a", 20); 144 | ``` 145 | -------------------------------------------------------------------------------- /1-前端框架与库/React/基础/context.md: -------------------------------------------------------------------------------- 1 | # context 与 contextType 2 | 3 | ## context 上下文 4 | 5 | context 提供一种方式,能够让属性在后代组件树中直接获取,而不是一层一层的传递。 6 | 7 | context 会在属性值变化时重新渲染 Consumer 下面的元素 8 | 9 | 多个 Provider 可以嵌套起来使用 10 | 11 | 不过这种方式可能使组件失去独立性,复用更困难。 12 | 13 | ### API 14 | 15 | - createContext(defaultValue) 16 | - 创建 context 对象的唯一方式, 17 | - defaultValue 是在找不到 provider 提供值时使用,做业务不会用。写单测可能用 18 | - `` 19 | - 提供属性 20 | - `` 21 | - 消费属性 22 | - Consumer 可以使用多次 23 | - Consumer 不能并列用,要嵌套用 24 | - 函数组件也可以传递 25 | 26 | ## contextType 27 | 28 | 挂载在 class 上的 contextType 属性会被重赋值为一个由 React.createContext() 创建的 Context 对象。这能让你使用 this.context 来消费 Context 上的那个值。你可以在任何生命周期中访问到它,包括 render 函数中。 29 | 30 | ```JSX 31 | class Another extends Component { 32 | static contextType = SOMEContext; 33 | render() { 34 | let battery = this.context; 35 | return

{battery}

; 36 | } 37 | } 38 | ``` 39 | 40 | ## demo 41 | 42 | ```jsx 43 | import React, { Component, createContext } from "react"; 44 | 45 | // Battery 电池 46 | const BatteryContext = createContext(); 47 | const OnlineContext = createContext(); 48 | 49 | function Extra() { 50 | return ( 51 | 52 | {(online) => ( 53 |
54 | 测试已经 consumer 过的属性是否还能继续使用 Online: {String(online)} 55 |
56 | )} 57 |
58 | ); 59 | } 60 | 61 | class Another extends Component { 62 | static contextType = BatteryContext; 63 | render() { 64 | let battery = this.context; 65 | return

{battery}

; 66 | } 67 | } 68 | 69 | function Leaf() { 70 | return ( 71 | 72 | {(battery) => ( 73 |
74 | 75 | {(online) => ( 76 |
77 |

78 | Battery: {battery}, Online: {String(online)} 79 |

80 | 81 | 82 |
83 | )} 84 |
85 |
86 | )} 87 |
88 | ); 89 | } 90 | 91 | function Middle() { 92 | return ; 93 | } 94 | 95 | class App extends Component { 96 | state = { battery: 60, online: false }; 97 | render() { 98 | const { battery, online } = this.state; 99 | return ( 100 | 101 | 102 | 108 | 109 | 115 | 116 | 117 | 118 | ); 119 | } 120 | } 121 | 122 | export default App; 123 | ``` 124 | -------------------------------------------------------------------------------- /2-计算机基础/网络/跨域.md: -------------------------------------------------------------------------------- 1 | ### 跨域通信的方式 2 | 3 | - JSONP 4 | - CORS 5 | - Hash 6 | - postMessage 7 | - WebSoket 8 | 9 | ### 同源策略 10 | 11 | - 端口相同 12 | - 域名相同 13 | - 协议相同 14 | 15 | 例子:`http://www.example.com/dir/page.html` 这个网址,协议是`http`,域名是`www.example.com`,端口是`80` 16 | 17 | 同源政策的目的,是为了保证用户信息的安全,防止恶意的网站窃取数据。**是浏览器做的努力** 18 | 19 | ### 同源策略限制范围 20 | 21 | - Cookie、LocalStorage 和 IndexDB 无法读取 22 | - DOM 无法获得 23 | - AJAX 请求不能发送 24 | 25 | ### CROS 跨域资源请求 26 | 27 | CORS(Cross-origin resource sharing)跨域资源请求 28 | 29 | 浏览器在请求一个跨域资源的时候,如果是跨域的 Ajax 请求,他会在请求头中加一个`origin`字段,但他是不知道这个资源服务端是否允许跨域请求的。浏览器会发送到服务端,如果服务器返回的头中没有`'Access-Control-Allow-Origin': '对应网址或 * '` 的话,那么浏览器就会把请求内容给忽略掉,并且在控制台报错 30 | 31 | ### CORS 限制 32 | 33 | 允许的请求方法 34 | 35 | - GET 36 | - POST 37 | - HEAD 38 | 39 | 允许的 Content-Type 40 | 41 | - text/plain 42 | - multipart/form-data 43 | - application/x-www-form-ulencoded 44 | 45 | 其他类型的请求方法和 Content-Type 需要通过**预请求验证**后然后才能发送 46 | 47 | ### CORS 预请求 48 | 49 | 跨域资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站有权限访问哪些资源。另外,规范要求,对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求。 50 | 51 | 服务器在 HTTP header 中加入允许请求的方法和 Content-Type 后,其他指定的方法和 Content-Type 就可以成功请求了 52 | 53 | ``` 54 | 'Access-Control-Allow-Headers': '允许Content-Type' 55 | 'Access-Control-Allow-Methods': '允许的请求方法' 56 | 'Access-Control-Max-Age': '预请求允许其他方法和类型传输的时间' 57 | ``` 58 | 59 | ### JSONP 跨域 60 | 61 | 浏览器上虽然有同源限制,但是像 srcipt 标签、link 标签、img 标签、iframe 标签,这种**在标签上通过 src 地址来加载一些内容的时候浏览器是允许进行跨域请求的**。 62 | 63 | 所以 JSONP 的原理就是: 64 | 65 | - 创建一个 script 标签,这个 script 标签的 src 就是请求的地址; 66 | - 这个 script 标签插入到 DOM 中,浏览器就根据 src 地址访问服务器资源 67 | - 返回的资源是一个文本,但是因为是在 script 标签中,浏览器会执行它 68 | - 而这个文本恰好是函数调用的形式,即函数名(数据),浏览器会把它当作 JS 代码来执行即调用这个函数 69 | - 只要提前约定好这个函数名,并且这个函数存在于 window 对象中,就可以把数据传递给处理函数。 70 | 71 | ### Hash 值跨域通信 72 | 73 | 背景:在页面 A 下提供 iframe 或 frame 嵌入了跨域的页面 B 74 | 75 | 容器页面 -> 嵌入页通信: 76 | 77 | 在 A 页面中改变 B 的 url 中的 hash 值,B 不会刷新,但是 B 可以用过`window.onhashchange`事件监听到 hash 变化 78 | 79 | ### postMessage 通信 80 | 81 | ```js 82 | // 窗口A中 83 | window.postMessage("data", "http://A.com"); 84 | // 窗口B中 85 | window.addEventListener("message", function (event) { 86 | console.log(event.origin); // http://A.com 87 | console.log(event.source); // A 对象window引用 88 | console.log(event.data); // 数据 89 | }); 90 | ``` 91 | 92 | ### WebSoket 跨域通信 93 | 94 | ```js 95 | var ws = new WebSocket("wss://echo.websoket.org"); //这个是后端端口 96 | 97 | ws.onopen = function (evt) { 98 | ws.send("some message"); 99 | }; 100 | 101 | ws.onmessage = function (evt) { 102 | console.log(evt.data); 103 | }; 104 | 105 | ws.onclose = function (evt) { 106 | console.log("连接关闭"); 107 | }; 108 | ``` 109 | 110 | ### document.domain 111 | 112 | 该方式只能用于二级域名相同的情况下,比如 a.test.com 和 b.test.com 适用于该方式。 113 | 114 | 只需要给页面添加 document.domain = 'test.com' 表示二级域名都相同就可以实现跨域 115 | 116 | ### localhost 与 127.0.0.1 117 | 118 | - localhost 等于 127.0.0.1,不过 localhost 是域名,127.0.0.1 是 IP 地址 119 | - localhost 和 127.0.0.1 不需要联网,都是本机访问 120 | 121 | 注意:localhost 和 127.0.0.1 虽然都指向本机,但也属于**跨域**, 122 | (配置 localhost 出现 CORS 时,可尝试改为 127.0.0.1) 123 | -------------------------------------------------------------------------------- /杂项/前端二进制.md: -------------------------------------------------------------------------------- 1 | ## 二进制 2 | 3 | ### 通过 accept 限制上传文件类型 4 | 5 | 在日常工作中,文件上传是一个很常见的功能。在某些情况下,我们希望能限制文件上传的类型,比如限制只能上传 PNG 格式的图片。针对这个问题,我们会想到通过 `input` 元素的 `accept` 属性来限制上传的文件类型: 6 | 7 | ```html 8 | 9 | ``` 10 | 11 | 这种方案虽然可以满足大多数场景,但如果用户把 JPEG 格式的图片后缀名更改为 `.png` 的话,就可以成功突破这个限制。因为通过 **文件后缀名或文件的 MIME 类型** 并不能识别出正确的文件类型。我们可以通过读取文件的二进制数据来识别正确的文件类型。 12 | 13 | ### 如何通过二进制查看图片的类型 14 | 15 | **计算机并不是通过图片的后缀名来区分不同的图片类型,而是通过 Magic Number 来区分。** 对于某一些类型的文件,起始的几个字节内容都是固定的,根据这几个字节的内容就可以判断文件的类型。 16 | 17 | 常见图片类型对应的 Magic Number 如下表所示: 18 | 19 | | 文件类型 | 文件后缀 | 魔数 | 20 | | :------- | :------- | :------------------------ | 21 | | JPEG | jpg/jpeg | 0xFF D8 FF | 22 | | PNG | png | 0x89 50 4E 47 0D 0A 1A 0A | 23 | | GIF | gif | 0x47 49 46 38(GIF8) | 24 | | BMP | bmp | 0x42 4D | 25 | 26 | #### readBuffer 函数 27 | 28 | 在获取文件对象后,我们可以通过 FileReader API 来读取文件的内容。因为我们并不需要读取文件的完整信息,所以阿宝哥封装了一个 `readBuffer` 函数,用于读取文件中指定范围的二进制数据。 29 | 30 | ```javascript 31 | function readBuffer(file, start = 0, end = 2) { 32 | return new Promise((resolve, reject) => { 33 | const reader = new FileReader(); 34 | reader.onload = () => { 35 | resolve(reader.result); 36 | }; 37 | reader.onerror = reject; 38 | reader.readAsArrayBuffer(file.slice(start, end)); 39 | }); 40 | } 41 | ``` 42 | 43 | #### 检测 PNG 图片类型 44 | 45 | 对于 PNG 类型的图片来说,该文件的前 8 个字节是 **0x89 50 4E 47 0D 0A 1A 0A**。因此,我们在检测已选择的文件是否为 PNG 类型的图片时,只需要读取前 8 个字节的数据,并逐一判断每个字节的内容是否一致。基于前面定义的 `readBuffer` 和 `check` 函数,我们就可以实现检测 PNG 图片的功能: 46 | 47 | ##### 代码 48 | 49 | HTML 代码 50 | 51 | ```html 52 |
53 | 选择文件: 54 |

55 |
56 | ``` 57 | 58 | JS 代码 59 | 60 | ```javascript 61 | // 逐字节比对工具函数 62 | function check(headers) { 63 | return (buffers, options = { offset: 0 }) => 64 | headers.every( 65 | (header, index) => header === buffers[options.offset + index] 66 | ); 67 | } 68 | // 检测 PNG 函数 69 | const isPNG = check([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]); 70 | 71 | 72 | const realFileElement = document.querySelector("#realFileType"); 73 | 74 | async function handleChange(event) { 75 | const file = event.target.files[0]; 76 | const buffers = await readBuffer(file, 0, 8); 77 | const uint8Array = new Uint8Array(buffers); 78 | realFileElement.innerText = `${file.name}文件的类型是:${ 79 | isPNG(uint8Array) ? "image/png" : file.type 80 | }`; 81 | } 82 | ``` 83 | 84 | 检测 JEPG 类型 `isJPEG` 函数: 85 | 86 | ```javascript 87 | const isJPEG = check([0xff, 0xd8, 0xff]) 88 | ``` 89 | 90 | 检测 PDF 类型 91 | 92 | PDF 文件的头 4 个字节的是 **0x25 50 44 46**,对应的字符串是 **%PDF**。为了让用户能更直观地辨别出检测的类型,可定义了一个 `stringToBytes` 函数: 93 | 94 | ```javascript 95 | function stringToBytes(string) { 96 | return [...string].map((character) => character.charCodeAt(0)); 97 | } 98 | ``` 99 | 100 | 基于 `stringToBytes` 函数,我们就可以很容易的定义一个 `isPDF` 函数,具体如下所示: 101 | 102 | ```javascript 103 | const isPDF = check(stringToBytes("%PDF")); 104 | ``` 105 | 106 | --------------------------------------------------------------------------------