├── docs ├── http │ ├── https.md │ ├── http3.md │ ├── http2.md │ ├── http-headers.md │ ├── SPDY.md │ └── index.md ├── javascript │ ├── class.md │ ├── function │ │ ├── function-named.md │ │ ├── function-anonymous.md │ │ ├── function-declaration.md │ │ ├── function-arrow.md │ │ ├── function-constructor.md │ │ └── function-callback.md │ ├── object │ │ ├── date.md │ │ ├── math.md │ │ └── index.md │ ├── data-structure │ │ ├── index.md │ │ ├── object.md │ │ ├── string.md │ │ └── number.md │ ├── pure-function.md │ ├── useful │ │ ├── currying.md │ │ ├── new.md │ │ ├── front-route.md │ │ ├── memory.md │ │ ├── throttle.md │ │ ├── debounce.md │ │ └── deep-copy.md │ ├── index.md │ ├── module.md │ ├── term.md │ ├── variable │ │ └── variable-private.md │ ├── inherit │ │ ├── inherit-dynamic-proto.md │ │ ├── inherit-stable-structure.md │ │ ├── inherit-mixin.md │ │ └── inherit-parasitic-structure.md │ ├── regex.md │ ├── switch.md │ ├── context │ │ ├── bind.md │ │ ├── index.md │ │ ├── call.md │ │ └── apply.md │ ├── eventloop.md │ ├── base.md │ ├── scoped │ │ ├── index.md │ │ └── closure.md │ ├── this.md │ ├── common-use-api.md │ ├── keyword.md │ ├── __proto__.md │ ├── blob.md │ ├── promise.md │ ├── static-method.md │ ├── bom.md │ └── type.md ├── bundler │ ├── babel │ │ └── index.md │ ├── vite │ │ └── index.md │ ├── webpack │ │ ├── index.md │ │ └── webpack-dev-server.md │ └── rollup │ │ └── index.md ├── frontend │ ├── v8 │ │ ├── v8.md │ │ ├── build-gn.md │ │ ├── event-loop-libuv.md │ │ ├── thread-pool-libuv.md │ │ ├── source-code.md │ │ ├── garbage.md │ │ └── index.md │ ├── security │ │ ├── xss.md │ │ ├── index.md │ │ ├── csrf.md │ │ └── cookie.md │ ├── svg │ │ └── index.md │ ├── es6 │ │ ├── string.md │ │ ├── index.md │ │ ├── const-let.md │ │ ├── arrow.md │ │ ├── reflect.md │ │ └── symbol.md │ ├── canvas │ │ └── index.md │ ├── pwa │ │ └── index.md │ ├── webgl │ │ └── index.md │ └── performance │ │ └── index.md ├── public │ ├── demos │ │ ├── js │ │ │ ├── simulate │ │ │ │ ├── myLazy.js │ │ │ │ ├── README.md │ │ │ │ ├── myEventEmitter.js │ │ │ │ ├── myJSON-parse.js │ │ │ │ ├── myGetPrototypeOf.js │ │ │ │ ├── myJSON-stringify.js │ │ │ │ ├── myWatcher.js │ │ │ │ ├── mySubscribe.js │ │ │ │ ├── myNew.js │ │ │ │ ├── myCurring.js │ │ │ │ ├── myThrottle.js │ │ │ │ ├── myBind.js │ │ │ │ ├── myCall.js │ │ │ │ ├── myDecoration.js │ │ │ │ ├── myApply.js │ │ │ │ ├── mySymbol.js │ │ │ │ ├── myDebounce.js │ │ │ │ ├── myInstanceOf.js │ │ │ │ ├── myCreate.js │ │ │ │ ├── myClass.js │ │ │ │ └── promise-class-all.js │ │ │ ├── es6 │ │ │ │ ├── class.js │ │ │ │ └── this.js │ │ │ ├── params-limit.js │ │ │ ├── algorithm │ │ │ │ ├── normal │ │ │ │ │ ├── dynamic-climb-start.js │ │ │ │ │ ├── greedy-coin-change.js │ │ │ │ │ ├── dynamic-fibonacci.js │ │ │ │ │ ├── backtrack-combine.js │ │ │ │ │ ├── divide-maxSubArray.js │ │ │ │ │ ├── greedy-cookie-index.js │ │ │ │ │ ├── backtrack-full-sort.js │ │ │ │ │ ├── greedy-activity-selection.js │ │ │ │ │ ├── dynamic-knapsack.js │ │ │ │ │ ├── divide-quick-sort.js │ │ │ │ │ ├── divide-merge-sort.js │ │ │ │ │ └── backtrack-solveSudoku.js │ │ │ │ └── sort │ │ │ │ │ ├── pop-sort.js │ │ │ │ │ ├── shell-sort.js │ │ │ │ │ ├── fast-sort.js │ │ │ │ │ ├── insert-sort.js │ │ │ │ │ ├── counting-sort.js │ │ │ │ │ ├── merge-sort.js │ │ │ │ │ ├── select-sort.js │ │ │ │ │ └── heap-sort.js │ │ │ ├── extends │ │ │ │ └── prototype-extends.js │ │ │ ├── currring.js │ │ │ ├── binary-search-sort-2.js │ │ │ ├── test_function_name_anonymous_arrow.js │ │ │ ├── document.js │ │ │ ├── deep-copy.js │ │ │ ├── promise-function.js │ │ │ ├── publish-subscribe.js │ │ │ └── promise-class.js │ │ ├── html │ │ │ ├── promise.html │ │ │ ├── curve.html │ │ │ ├── aVue.html │ │ │ ├── closure.html │ │ │ ├── base64AndSrcImage.html │ │ │ ├── debug-sort.html │ │ │ ├── flex-left_center_right-layout.html │ │ │ ├── margin-left_center_right-layout-3.html │ │ │ ├── margin-left_center_right-layout.html │ │ │ ├── margin-left_center_right-layout-2.html │ │ │ ├── float-left_center_right-layout.html │ │ │ ├── vue-demo.html │ │ │ ├── box-model.html │ │ │ ├── margin-left_center_right-layout-4.html │ │ │ ├── input.html │ │ │ ├── index.html │ │ │ └── waterfall.html │ │ ├── reflect.js │ │ ├── proxy.js │ │ ├── fib.js │ │ ├── tests │ │ │ └── promise-class-all.spec.js │ │ ├── qij.js │ │ └── css │ │ │ └── main.min.css │ ├── favicon.ico │ ├── favicon.png │ └── images │ │ ├── fib.jpg │ │ ├── src.jpg │ │ ├── src-2.jpg │ │ ├── ie-leak.GIF │ │ ├── isArray.jpg │ │ ├── http │ │ ├── cache-304.png │ │ └── baidu-cache.png │ │ ├── time-complex.png │ │ ├── vue-prototype.png │ │ ├── isTypeSupported.jpg │ │ ├── css │ │ ├── float-case-1-scroll.png │ │ ├── flex-right-center-right.png │ │ ├── float-left-center-right.png │ │ ├── position-left-center-right.png │ │ ├── margin(pref)-left-center-right.png │ │ ├── margin(pref)-left-center-right-1.png │ │ └── margin(pref)-left-center-right-2.png │ │ ├── html │ │ ├── border-box-children.png │ │ ├── border-box-parent.png │ │ ├── content-box-parent.png │ │ └── content-box-children.png │ │ └── javascript ├── backend │ ├── rust │ │ ├── index.md │ │ ├── tokio │ │ │ └── index.md │ │ └── actix-web │ │ │ └── install.md │ ├── nginx │ │ ├── config.md │ │ ├── proxy.md │ │ └── index.md │ ├── deno │ │ └── index.md │ └── node │ │ ├── index.md │ │ └── fs.md ├── skill │ ├── github-auth.md │ ├── alipay.md │ ├── wechat-pay.md │ ├── index.md │ └── cors.md ├── framework │ ├── react │ │ └── index.md │ ├── vue │ │ ├── index.md │ │ ├── vue3.md │ │ └── parser-vue.md │ └── nuxt │ │ └── index.md ├── interview │ ├── 2018-8-15.md │ ├── 2018-9-19.md │ ├── 2018-alibaba.md │ ├── 2018-netease.md │ ├── 2018-other-mid.md │ ├── 2018-9-18.md │ ├── 2020-other.md │ ├── 2020-alibaba.md │ ├── 2020-12.md │ ├── 2018-12.md │ ├── 2018-9-11.md │ ├── index.md │ └── 2018-8-31.md ├── about.md ├── guide.md ├── .vitepress │ ├── global.d.ts │ └── theme │ │ ├── index.ts │ │ └── plugins │ │ └── vitepress-plugin-mermaid.ts ├── typescript │ └── index.md ├── leetcode │ ├── index.md │ ├── 14-longest-common-prefix.md │ └── 67-addBinary.md ├── css │ ├── animation.md │ └── css3.md ├── html │ ├── html5.md │ └── index.md ├── reference.md ├── keyword.md ├── index.md └── algorithm │ └── index.md ├── .gitignore ├── .markdownlint.json ├── .env.d.ts ├── tsconfig.json ├── package.json ├── scripts ├── readme-rename-index.js └── deploy.sh ├── .github └── workflows │ └── deploy.yml └── README.md /docs/http/https.md: -------------------------------------------------------------------------------- 1 | # HTTPS 2 | -------------------------------------------------------------------------------- /docs/javascript/class.md: -------------------------------------------------------------------------------- 1 | # 类 2 | -------------------------------------------------------------------------------- /docs/bundler/babel/index.md: -------------------------------------------------------------------------------- 1 | # Babel -------------------------------------------------------------------------------- /docs/frontend/v8/v8.md: -------------------------------------------------------------------------------- 1 | # V8 引擎 2 | -------------------------------------------------------------------------------- /docs/bundler/vite/index.md: -------------------------------------------------------------------------------- 1 | # Vite TODO 2 | -------------------------------------------------------------------------------- /docs/frontend/security/xss.md: -------------------------------------------------------------------------------- 1 | # xss 2 | -------------------------------------------------------------------------------- /docs/public/demos/js/simulate/myLazy.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/backend/rust/index.md: -------------------------------------------------------------------------------- 1 | # Rust 该部分属于后端部分 2 | -------------------------------------------------------------------------------- /docs/frontend/v8/build-gn.md: -------------------------------------------------------------------------------- 1 | # V8 build-gn 2 | -------------------------------------------------------------------------------- /docs/javascript/function/function-named.md: -------------------------------------------------------------------------------- 1 | # 具名函数 -------------------------------------------------------------------------------- /docs/javascript/object/date.md: -------------------------------------------------------------------------------- 1 | # Date 对象 2 | -------------------------------------------------------------------------------- /docs/javascript/object/math.md: -------------------------------------------------------------------------------- 1 | # Math 对象 2 | -------------------------------------------------------------------------------- /docs/public/demos/js/simulate/README.md: -------------------------------------------------------------------------------- 1 | # 手动实现 -------------------------------------------------------------------------------- /docs/public/demos/js/simulate/myEventEmitter.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/public/demos/js/simulate/myJSON-parse.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/skill/github-auth.md: -------------------------------------------------------------------------------- 1 | ## github 授权登录 2 | -------------------------------------------------------------------------------- /docs/framework/react/index.md: -------------------------------------------------------------------------------- 1 | # React 2 | 3 | - TODO -------------------------------------------------------------------------------- /docs/javascript/data-structure/index.md: -------------------------------------------------------------------------------- 1 | # 数据结构 2 | -------------------------------------------------------------------------------- /docs/javascript/data-structure/object.md: -------------------------------------------------------------------------------- 1 | # 对象 2 | -------------------------------------------------------------------------------- /docs/javascript/data-structure/string.md: -------------------------------------------------------------------------------- 1 | # 字符串 2 | -------------------------------------------------------------------------------- /docs/public/demos/js/simulate/myGetPrototypeOf.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/public/demos/js/simulate/myJSON-stringify.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/frontend/v8/event-loop-libuv.md: -------------------------------------------------------------------------------- 1 | # Event loop 事件循环 2 | -------------------------------------------------------------------------------- /docs/javascript/function/function-anonymous.md: -------------------------------------------------------------------------------- 1 | # 匿名函数 2 | -------------------------------------------------------------------------------- /docs/javascript/function/function-declaration.md: -------------------------------------------------------------------------------- 1 | # 函数声明 -------------------------------------------------------------------------------- /docs/frontend/v8/thread-pool-libuv.md: -------------------------------------------------------------------------------- 1 | # Thread Pool 线程池 2 | -------------------------------------------------------------------------------- /docs/javascript/function/function-arrow.md: -------------------------------------------------------------------------------- 1 | # 箭头函数 2 | 3 | TODO -------------------------------------------------------------------------------- /docs/http/http3.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | # HTTP3 5 | -------------------------------------------------------------------------------- /docs/skill/alipay.md: -------------------------------------------------------------------------------- 1 | ## 支付宝支付开发 2 | 3 | > 已申请了支付宝开发者账号 9-17,有空再去看看。 -------------------------------------------------------------------------------- /docs/framework/vue/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | # Vue 5 | -------------------------------------------------------------------------------- /docs/public/demos/js/simulate/myWatcher.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 观察者模式 3 | */ 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .idea 3 | .vscode 4 | dist 5 | debug.log 6 | cache -------------------------------------------------------------------------------- /docs/bundler/webpack/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | # Webpack 5 | -------------------------------------------------------------------------------- /docs/public/demos/js/simulate/mySubscribe.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 手动订阅模式 3 | */ 4 | -------------------------------------------------------------------------------- /docs/skill/wechat-pay.md: -------------------------------------------------------------------------------- 1 | ## 微信支付开发 2 | 3 | > 已申请了微信开发者账号 9-17,有空再去看看。 4 | -------------------------------------------------------------------------------- /docs/backend/nginx/config.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | # Nginx Config 5 | -------------------------------------------------------------------------------- /docs/backend/nginx/proxy.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | # Nginx Proxy 5 | -------------------------------------------------------------------------------- /docs/interview/2018-8-15.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | # 2018 年8月15日面试题 5 | -------------------------------------------------------------------------------- /docs/interview/2018-9-19.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | 5 | # 2018 年9月19日面试题 6 | -------------------------------------------------------------------------------- /docs/http/http2.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | 5 | ## HTTP2 6 | 7 | - 多路传输能够解决线端阻塞问题 -------------------------------------------------------------------------------- /docs/javascript/pure-function.md: -------------------------------------------------------------------------------- 1 | # 纯函数是什么? 2 | 3 | - 不改变全局 4 | - 返回结果只依赖参数 5 | - 不引起副作用 6 | -------------------------------------------------------------------------------- /docs/interview/2018-alibaba.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | 5 | # 2018 年阿里资深 web 前端面试试题 6 | -------------------------------------------------------------------------------- /docs/interview/2018-netease.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | 5 | # 2018 年网易高级 web 前端面试题 6 | -------------------------------------------------------------------------------- /docs/bundler/webpack/webpack-dev-server.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | # Webpack-dev-server 5 | -------------------------------------------------------------------------------- /docs/interview/2018-other-mid.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | 5 | # 2018 年中级/高级 web 前端面试题 6 | -------------------------------------------------------------------------------- /docs/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veaba/web-advanced/HEAD/docs/public/favicon.ico -------------------------------------------------------------------------------- /docs/public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veaba/web-advanced/HEAD/docs/public/favicon.png -------------------------------------------------------------------------------- /docs/public/images/fib.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veaba/web-advanced/HEAD/docs/public/images/fib.jpg -------------------------------------------------------------------------------- /docs/public/images/src.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veaba/web-advanced/HEAD/docs/public/images/src.jpg -------------------------------------------------------------------------------- /docs/backend/rust/tokio/index.md: -------------------------------------------------------------------------------- 1 | # Tokio 2 | 3 | ## Link 4 | 5 | - [Tokio 中文](https://tokio-zh.github.io/) 6 | -------------------------------------------------------------------------------- /docs/public/images/src-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veaba/web-advanced/HEAD/docs/public/images/src-2.jpg -------------------------------------------------------------------------------- /docs/javascript/useful/currying.md: -------------------------------------------------------------------------------- 1 | # 柯里化 2 | 3 | 把接受多个参数的函数变换成为接受一个单一的参数的函数 4 | 5 | `foo(a,b,c)` => `foo(abc)` 6 | -------------------------------------------------------------------------------- /docs/public/images/ie-leak.GIF: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veaba/web-advanced/HEAD/docs/public/images/ie-leak.GIF -------------------------------------------------------------------------------- /docs/public/images/isArray.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veaba/web-advanced/HEAD/docs/public/images/isArray.jpg -------------------------------------------------------------------------------- /docs/about.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | 5 | # 关于 6 | 7 | 此网站是[@veaba](https://github.com/veaba) 个人技术点笔记梳理。 8 | -------------------------------------------------------------------------------- /docs/http/http-headers.md: -------------------------------------------------------------------------------- 1 | # HTTP Headers 2 | 3 | - [HTTP Headers](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers) -------------------------------------------------------------------------------- /docs/public/images/http/cache-304.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veaba/web-advanced/HEAD/docs/public/images/http/cache-304.png -------------------------------------------------------------------------------- /docs/public/images/time-complex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veaba/web-advanced/HEAD/docs/public/images/time-complex.png -------------------------------------------------------------------------------- /docs/public/images/vue-prototype.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veaba/web-advanced/HEAD/docs/public/images/vue-prototype.png -------------------------------------------------------------------------------- /docs/framework/vue/vue3.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | 5 | # vue.datav.ai 6 | 7 | - [vue.datav.ai](https://vue.datav.ai) 8 | -------------------------------------------------------------------------------- /docs/guide.md: -------------------------------------------------------------------------------- 1 | --- 2 | outline: deep 3 | editLink: true 4 | footer: false 5 | --- 6 | 7 | # 目录指南 8 | 9 | 10 | -------------------------------------------------------------------------------- /docs/public/images/http/baidu-cache.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veaba/web-advanced/HEAD/docs/public/images/http/baidu-cache.png -------------------------------------------------------------------------------- /docs/public/images/isTypeSupported.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veaba/web-advanced/HEAD/docs/public/images/isTypeSupported.jpg -------------------------------------------------------------------------------- /docs/http/SPDY.md: -------------------------------------------------------------------------------- 1 | ## SPDY 2 | 3 | - 4 | - 5 | -------------------------------------------------------------------------------- /docs/public/images/css/float-case-1-scroll.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veaba/web-advanced/HEAD/docs/public/images/css/float-case-1-scroll.png -------------------------------------------------------------------------------- /docs/public/images/html/border-box-children.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veaba/web-advanced/HEAD/docs/public/images/html/border-box-children.png -------------------------------------------------------------------------------- /docs/public/images/html/border-box-parent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veaba/web-advanced/HEAD/docs/public/images/html/border-box-parent.png -------------------------------------------------------------------------------- /docs/public/images/html/content-box-parent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veaba/web-advanced/HEAD/docs/public/images/html/content-box-parent.png -------------------------------------------------------------------------------- /docs/public/images/html/content-box-children.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veaba/web-advanced/HEAD/docs/public/images/html/content-box-children.png -------------------------------------------------------------------------------- /docs/.vitepress/global.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'vitepress-script-preview' { 2 | import { Plugin } from 'vite' 3 | export const codePreviewPlugin: Plugin 4 | } -------------------------------------------------------------------------------- /docs/public/images/css/flex-right-center-right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veaba/web-advanced/HEAD/docs/public/images/css/flex-right-center-right.png -------------------------------------------------------------------------------- /docs/public/images/css/float-left-center-right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veaba/web-advanced/HEAD/docs/public/images/css/float-left-center-right.png -------------------------------------------------------------------------------- /docs/typescript/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | 5 | # TypeScript 6 | 7 | - [泛型](generics) 8 | 9 | 10 | -------------------------------------------------------------------------------- /docs/public/images/css/position-left-center-right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veaba/web-advanced/HEAD/docs/public/images/css/position-left-center-right.png -------------------------------------------------------------------------------- /docs/public/demos/js/es6/class.js: -------------------------------------------------------------------------------- 1 | /*********************** 2 | * @name JS 3 | * @author veaba 4 | * @date 2019/8/9 0009 上午 11:22 5 | ***********************/ 6 | -------------------------------------------------------------------------------- /docs/public/images/css/margin(pref)-left-center-right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veaba/web-advanced/HEAD/docs/public/images/css/margin(pref)-left-center-right.png -------------------------------------------------------------------------------- /docs/public/images/javascript/__proto__/obj-__proto__.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veaba/web-advanced/HEAD/docs/public/images/javascript/__proto__/obj-__proto__.png -------------------------------------------------------------------------------- /docs/interview/2018-9-18.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | 5 | # 2018 年9月18日面试题 6 | 7 | 发生两次 header 的 key 记不住的问题: 8 | 9 | - 2018年9月18 10 | - 2025年8月14日 11 | -------------------------------------------------------------------------------- /docs/leetcode/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | navbar: auto 4 | --- 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /docs/public/images/css/margin(pref)-left-center-right-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veaba/web-advanced/HEAD/docs/public/images/css/margin(pref)-left-center-right-1.png -------------------------------------------------------------------------------- /docs/public/images/css/margin(pref)-left-center-right-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veaba/web-advanced/HEAD/docs/public/images/css/margin(pref)-left-center-right-2.png -------------------------------------------------------------------------------- /docs/framework/nuxt/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | 5 | # Nuxt 6 | 7 | ## AsyncData() 8 | 9 | - 导致 session id 不一致 10 | - 刷新都没有了 11 | 12 | ## Nuxt.conf.js 13 | -------------------------------------------------------------------------------- /docs/interview/2020-other.md: -------------------------------------------------------------------------------- 1 | # 2020 其他面试题常见题 2 | 3 | ## 快速创建 100 个 1 的数组 4 | 5 | > 确实没有想到可以 Array(100) 这样使用,[empty × 100] 6 | 7 | ```js 8 | Array(100).fill(1); 9 | ``` 10 | -------------------------------------------------------------------------------- /docs/javascript/data-structure/number.md: -------------------------------------------------------------------------------- 1 | # 数字 Number 2 | 3 | - 除法。先转为数字再进行除法操作 4 | 5 | ```js 6 | console.log('40' % 7); // 等于多少? 取模 7 | console.log('40' / 7); // 等于多少? 取模 8 | ``` 9 | -------------------------------------------------------------------------------- /docs/javascript/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | 5 | # JavaScript 学习指南/目录 6 | 7 | > 基于本人学习经历,尝试写一篇零基础的 JavaScript 新手指南 8 | 9 | 10 | -------------------------------------------------------------------------------- /docs/public/demos/js/params-limit.js: -------------------------------------------------------------------------------- 1 | const list1 = [1, 2]; 2 | const list2 = [3, 4]; 3 | list1.push.apply(list1, list2); 4 | console.info('list1:', list1); 5 | console.info('list2:', list2); -------------------------------------------------------------------------------- /docs/frontend/svg/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | 5 | # SVG 6 | 7 | - 不依赖分辨率 8 | - 支持事件处理器 9 | - 适合大型渲染区域的应用程序 (如:Google map) 10 | - 复杂度高,会减慢渲染速度,太依赖 DOM 11 | - 不适合游戏应用 12 | -------------------------------------------------------------------------------- /docs/javascript/module.md: -------------------------------------------------------------------------------- 1 | # 模块化 2 | 3 | - [参考](https://yuchengkai.cn/docs/frontend/#%E6%A8%A1%E5%9D%97%E5%8C%96) 4 | 5 | ## CommonJS 6 | 7 | `CommonJS` Node 独有规范 8 | 9 | ## AMD 10 | -------------------------------------------------------------------------------- /docs/javascript/term.md: -------------------------------------------------------------------------------- 1 | # 术语 2 | 3 | [[toc]] 4 | 5 | ## IIFE 6 | 7 | - [MDN IIFE](https://developer.mozilla.org/zh-CN/docs/Glossary/IIFE) 8 | 9 | - Immediately-Invoked Function Expression,立即调用函数表达式。 10 | -------------------------------------------------------------------------------- /docs/frontend/es6/string.md: -------------------------------------------------------------------------------- 1 | ## 字符串 2 | 3 | ### 模板字符串无法的打印 symbol 4 | 5 | ```js 6 | const sy1 = Symbol(11); 7 | 8 | console.log(sy1); 9 | 10 | console.log(`${sy1}`); // `Cannot convert a Symbol value to a string` 11 | ``` 12 | -------------------------------------------------------------------------------- /docs/javascript/useful/new.md: -------------------------------------------------------------------------------- 1 | # new 2 | 3 | ## new 操作符 4 | 5 | 1. 创建一个新对象 6 | 2. 构造函数的作用域赋值给新对象,this 指向这个新对象 7 | 3. 执行构造函数代码,为这个新对象添加属性 8 | 4. 返回新对象 9 | [查看更多 js 中的 new() 到底做了些什么??](https://www.cnblogs.com/faith3/p/6209741.html) 10 | -------------------------------------------------------------------------------- /.markdownlint.json: -------------------------------------------------------------------------------- 1 | { 2 | "MD033": { 3 | "allowed_elements": [ 4 | "Badge", 5 | "Catalog" 6 | ] 7 | }, 8 | "MD013": { 9 | "line_length": 250 10 | }, 11 | "MD024":{ 12 | "siblings_only": true 13 | } 14 | } -------------------------------------------------------------------------------- /docs/skill/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | 5 | # 业务技巧相关 6 | 7 | ## RESTful 与 GraphQL 比较 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/frontend/security/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | 5 | # web 安全问题 6 | 7 | ## CSRFs 8 | 9 | ## XSS 10 | 11 | ## DDOS 12 | 13 | ## CSP (内容安全策略) 14 | 15 | 16 | 17 | ## SQL 注入 18 | 19 | ## https 20 | 21 | ## DNS 劫持 22 | -------------------------------------------------------------------------------- /docs/frontend/canvas/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | 5 | # Canvas 6 | 7 | - 依赖分辨率 8 | - 不支持事件处理器 9 | - 弱文本渲染能力 10 | - 能够以图片形式保存结果 11 | - 最适合图片密集型的游戏,对象被频繁重绘 12 | - 逐像素进行渲染 13 | - 图形被绘制完成,就不会继续被浏览器关注,如果位置发生变化,需要重新绘制 14 | - `canvas` 不可以通过浏览器提供的接口获取到 TODO 15 | - `drawImage` 贴图受跨域限制 16 | 17 | ## RequestAnimationFrame 18 | -------------------------------------------------------------------------------- /docs/public/demos/html/promise.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /docs/public/demos/html/curve.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/javascript/useful/front-route.md: -------------------------------------------------------------------------------- 1 | # 前端路由 2 | 3 | > API,利用两个 API 修改 URL,而不会引起页面的刷新 4 | 5 | - 方式一 pushState ajax 6 | - history.pushState 增加一条新的记录 7 | - history.replaceState 替换当前的历史记录 8 | - 方式二 hash+ajax 9 | - “#” 锚点,web 不会解析 hash,“#” 后面,web 服务会被自动忽略 10 | - js 可以通过 location.hash 读取,解析后可以实现响应不同的路径逻辑 11 | - hashchange 监听 hash 变化触发事件 12 | -------------------------------------------------------------------------------- /docs/public/demos/js/simulate/myNew.js: -------------------------------------------------------------------------------- 1 | function myNew(fn, ...args) { 2 | const obj = Object.create(fn.prototype); 3 | const result = fn.apply(obj, args); 4 | return typeof result === 'object' ? result : obj; 5 | } 6 | 7 | function fn(name) { 8 | this.name = name; 9 | } 10 | 11 | const x = myNew(fn, '6666'); 12 | 13 | console.log(x.name); 14 | -------------------------------------------------------------------------------- /docs/javascript/function/function-constructor.md: -------------------------------------------------------------------------------- 1 | # 构造函数 2 | 3 | - 相同构造函数出来的两个实例不相等,但其子属性、方法相同 4 | 5 | ```js 6 | class Colors { 7 | getColor() { 8 | } 9 | } 10 | 11 | const a = new Colors(); 12 | const b = new Colors(); 13 | 14 | console.log("compare instance=>", a === b); // false 15 | console.log("compare method=>", a.getColor === b.getColor); // true 16 | ``` 17 | -------------------------------------------------------------------------------- /docs/css/animation.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | 5 | # Animation 6 | 7 | 8 | ## css 动画有几种方式? 9 | 10 | - transition 过渡 11 | - animation 关键帧动画 12 | - transform 变换 13 | - JavaScript 辅助更换 css class 来实现 14 | - SVG 动画 15 | - CSS filters 16 | - Motion Path(实验性) 17 | 18 | ## 常见的 css 动画库 19 | 20 | - [animate.css](https://animate.style/) 21 | - [GSAP](https://gsap.com/) 22 | - 等等 -------------------------------------------------------------------------------- /.env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | declare module '@vue/theme/config' { 4 | import { UserConfig } from 'vitepress' 5 | const config: () => Promise 6 | export default config 7 | } 8 | 9 | declare module '@vue/theme/highlight' { 10 | const createHighlighter: () => Promise<(input: string) => string> 11 | export default createHighlighter 12 | } 13 | -------------------------------------------------------------------------------- /docs/frontend/es6/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | 5 | # Es6 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | ## Generator 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /docs/javascript/variable/variable-private.md: -------------------------------------------------------------------------------- 1 | # 私有变量 2 | 3 | > 如何让外部的函数访问到内部的变量和设置 4 | 5 | - 通过构造函数的方式 6 | 7 | ```js 8 | function Main(name) { 9 | this.getName = function () { 10 | return name; 11 | }; 12 | this.setName = function (value) { 13 | name = value; 14 | }; 15 | } 16 | var p1 = new Main('李四'); 17 | console.log(p1.getName()); 18 | p1.setName('王五'); 19 | console.log(p1.getName()); 20 | ``` 21 | -------------------------------------------------------------------------------- /docs/javascript/inherit/inherit-dynamic-proto.md: -------------------------------------------------------------------------------- 1 | # 创建对象-动态原型模式 2 | 3 | > 缺点 4 | 5 | - 不能使用字面量重写原型,否则会切断联系 6 | > 通过 if 来判断 7 | 8 | ## 动态原型 9 | 10 | ```js 11 | function Fn(name, age, job) { 12 | this.name = name; 13 | this.age = age; 14 | this.job = job; 15 | if (typeof this.sayName !== 'function') { 16 | Fn.prototype.sayName = function () { 17 | return this.name; 18 | }; 19 | } 20 | } 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/public/demos/js/es6/this.js: -------------------------------------------------------------------------------- 1 | const x = () => { 2 | console.log(this.a); 3 | }; 4 | 5 | function t() { 6 | this.a = 22; 7 | x(); 8 | } 9 | 10 | t(); 11 | 12 | let person = { 13 | name: "jike", 14 | init: function() { 15 | //为body添加一个点击事件,看看这个点击后的this属性有什么不同 16 | document.body.onclick = () => { 17 | alert(this.name); //?? this在浏览器默认是调用时的对象,可变的? 18 | }; 19 | }, 20 | }; 21 | person.init(); 22 | -------------------------------------------------------------------------------- /docs/javascript/useful/memory.md: -------------------------------------------------------------------------------- 1 | # 内存指向 2 | 3 | ```js 4 | const obj={} 5 | function A(){ 6 | return obj 7 | } 8 | 9 | const a = new A() 10 | 11 | const b = new A() 12 | 13 | console.log(a===b) ? // true 14 | 15 | ``` 16 | 17 | 函数每次都返回新的空对象,而不是 `return` 指向的全局变量 18 | 19 | ```js 20 | function A(){ 21 | return {} 22 | } 23 | 24 | const a = new A() 25 | 26 | const b = new A() 27 | 28 | console.log(a===b) ? // false 29 | 30 | ``` 31 | -------------------------------------------------------------------------------- /docs/public/demos/html/aVue.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Title 8 | 9 | 10 | 11 | 12 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/javascript/regex.md: -------------------------------------------------------------------------------- 1 | [//]: # (TODO) 2 | 3 | # 正则 4 | 5 | 一种用于字符串处理的方法 6 | 7 | ## 正则 RegExp 对象 8 | 9 | ### test 方法 10 | 11 | ### toString 方法 12 | 13 | ### exec 方法 14 | 15 | ## 字符串的正则方法 16 | 17 | ### replace 替换 18 | 19 | ### search 搜索 20 | 21 | ### match 多个 22 | 23 | ### split 分割 24 | 25 | ## 正则的修饰符 26 | 27 | ## 正则的方括号 28 | 29 | ## 正则的元字符 30 | 31 | ## 正则的量词 32 | 33 | ## 常用实例 34 | 35 | ### 匹配电话号码 36 | 37 | ### 匹配身份证 38 | 39 | ### url 处理 40 | -------------------------------------------------------------------------------- /docs/public/demos/js/algorithm/normal/dynamic-climb-start.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 动态规划(Dynamic Programming,DP)是一种通过把原问题分解为相对简单的子问题, 3 | * 并保存子问题的解来避免重复计算,从而解决复杂问题的算法策略。 4 | */ 5 | 6 | 7 | function climbStairs(n) { 8 | if (n <= 2) { 9 | return n; 10 | } 11 | let dp = new Array(n + 1); 12 | dp[1] = 1; 13 | dp[2] = 2; 14 | for (let i = 3; i <= n; i++) { 15 | dp[i] = dp[i - 1] + dp[i - 2]; 16 | } 17 | return dp[n]; 18 | } 19 | 20 | // 测试 21 | console.log(climbStairs(5)); -------------------------------------------------------------------------------- /docs/skill/cors.md: -------------------------------------------------------------------------------- 1 | ## 跨域问题 2 | 3 | > 4 | 5 | - JSONP 跨域 6 | - **缺点:只支持 get、不支持 post** 7 | - 传递函数名 8 | - document.domain 9 | > 引入 iframe 时候,无法使用 js 交互操作 10 | - 使用 document.domain 将主页面和子页面都设置为相同的域名就可以了 11 | - **缺点:设置成自身或更高一级的父级,且主域必须相同** 12 | - 原因: 13 | - postMessage 跨文档通信 API,跨窗口通信 14 | - window.name 进行跨域 15 | - 跨资源共享 (CORS) 16 | - > IE10 17 | - 依赖服务端改造 header 18 | - nginx 代理跨域 19 | - nodejs 中间件代理跨域 20 | - websocket 协议跨域 21 | > 22 | -------------------------------------------------------------------------------- /docs/public/demos/reflect.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @desc Reflect 反射,可以使用Object安全性底层的方法 3 | * 4 | */ 5 | var obj=new Proxy(obj,{ 6 | get(target,name){ 7 | console.log('get',target,name) 8 | return Reflect.get(target,name) 9 | }, 10 | deleteProperty(target,name){ 11 | console.log('delete ',name) 12 | return Reflect.deleteProperty(target,name) 13 | }, 14 | has(target,name){ 15 | console.log('has',name) 16 | return Reflect.has(target,name) 17 | } 18 | }) -------------------------------------------------------------------------------- /docs/css/css3.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | 5 | # CSS3 6 | 7 | ## css3 8 | 9 | ### anination-timing-function 10 | 11 | - `linear` 匀速 12 | - `ease` 默认,低速开始,加快,结束前变慢 13 | - `ease-in` 低速开始 14 | - `ease-out` 低速结束 15 | - `ease-in-out` 动画以低速开始和结束 16 | - `cubic-bezier(n,n,n,n)` 可能值范围 0 - 1 17 | 18 | ### padding-top 19 | 20 | - 默认值,0 21 | 22 | ### maring-top 23 | 24 | - 默认值 0 25 | 26 | ### border-top-width 27 | 28 | - 默认值 medium 定义中等上边框 29 | 30 | ### outline-width 31 | 32 | - 默认值 medium 定义中等上边框 33 | -------------------------------------------------------------------------------- /docs/frontend/pwa/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | 5 | # PWA 6 | 7 | ## Service worker 工作线程,子线程 8 | 9 | > 2014 年 5 月提出,前身是 Application Cache `被移除` 10 | 11 | - Application Cache 指定缓存策略 app.appcache 12 | - 不能直接访问/操作 DOM 特定的 API 13 | - `全局`Promise/Fetch API/Cache API 14 | - 生命周期内,需要时,直接唤醒,不需要则自动休眠,不随浏览器窗口关闭、站点的关闭而失效 15 | - 离线内容可控 16 | - 一旦安装,永远存活,除非手动卸载 17 | - 必须 HTTPS,除非本地环境下 18 | - 广泛使用 Promise 19 | - 生命周期 20 | Register - > Install -> activated 21 | - 组织结构 22 | - 注册 sw 是一个脚本文件 `延时注册` 23 | - 工作时候的 sw 又是另外一个脚本文件 24 | -------------------------------------------------------------------------------- /docs/public/demos/js/simulate/myCurring.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 柯里化 3 | */ 4 | 5 | /** 6 | * 参数复用 7 | * */ 8 | function multiply(a, b) { 9 | return a * b; 10 | } 11 | 12 | // 柯里化函数 13 | const curriedMultiply = (a) => (b) => a * b; 14 | 15 | // 固定第一个参数为 5 16 | const multiplyBy5 = curriedMultiply(5); 17 | 18 | // 多次使用 multiplyBy5 19 | console.log(multiplyBy5(3)); // 输出 15 20 | console.log(multiplyBy5(4)); // 输出 20 21 | 22 | 23 | /** 24 | * 柯里化函数 25 | * 使用场景 26 | * - 参数复用 27 | * - 延迟执行 28 | * - 函数组合 29 | * - 事件处理 30 | * - 提高代码可测试性 31 | */ -------------------------------------------------------------------------------- /docs/public/demos/js/simulate/myThrottle.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 节流函数 3 | * - 一定时间才执行一次,无论多少次 4 | * - 上传文件进度 5 | * - windows.resize 6 | * - input 查询 7 | * 8 | * */ 9 | 10 | const throttle = (fn, wait = 50) => { 11 | let pre = 0; 12 | 13 | return function(...args) { 14 | let now = new Date(); 15 | if (now - pre > wait) { 16 | pre = now; 17 | fn.apply(this, args); 18 | } 19 | }; 20 | }; 21 | 22 | const fn = throttle(() => { 23 | console.log(new Date()); 24 | }); 25 | 26 | document.addEventListener("scroll", fn); 27 | -------------------------------------------------------------------------------- /docs/html/html5.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | 5 | # HTML5 6 | 7 | ## 知识点 8 | 9 | - initial-scale 表示的是初始缩放比例 10 | - minimum-scale 表示允许用户缩放到最小比例 11 | - width=device-width 表示网页宽度为设备屏幕宽度 12 | 13 | ## 不支持 14 | 15 | - `rel` 16 | 17 | ## 标签 18 | 19 | ## 拖放 20 | 21 | ## 地理定位 22 | 23 | ## video 24 | 25 | ## audio 26 | 27 | ## input 28 | 29 | ## 表单元素 30 | 31 | ## 表单属性 32 | 33 | ## 语义元素 34 | 35 | ## web 存储 36 | 37 | ## web SQL 38 | 39 | ## 应用程序缓存 40 | 41 | ## web Workers 42 | 43 | ## SSE 44 | 45 | ## Websocket 46 | 47 | ## 代码规范 48 | -------------------------------------------------------------------------------- /docs/javascript/inherit/inherit-stable-structure.md: -------------------------------------------------------------------------------- 1 | # 稳妥构造继承 2 | 3 | 创建对象-稳妥构造函数模式 4 | 5 | ## 稳妥构造 6 | 7 | > 特点: 8 | 9 | 1. 遵从寄生构造函数类似模式 10 | 2. 新创建对象方法的实例不引用 this 11 | 3. 不适用 new 操作调用构造函数 12 | 4. 丢掉无关属性或者说是丢掉无效入参 13 | 5. 没有其他方式可以访问其数据成员 14 | 6. 为安全性考虑的 js 设计模式 15 | 16 | ```js 17 | function durable(name, age, job) { 18 | var obj = {}; 19 | // todo 定义私有变量和属性 20 | obj.sayName = function () { 21 | console.log(name); 22 | }; 23 | return obj; 24 | } 25 | // use 26 | var p1 = durable('柳十', '41', 'CFO管钱的'); 27 | p1.sayName(); 28 | ``` 29 | -------------------------------------------------------------------------------- /docs/javascript/inherit/inherit-mixin.md: -------------------------------------------------------------------------------- 1 | # 混淆继承 2 | 3 | 创建对象-混淆大法!组合使用构造函数 +原型模式!`目前最广泛,最好的方式` 4 | 5 | > 构造函数写属性,方法则用原型继承 6 | 7 | ```js 8 | function Fn(name, age, job) { 9 | this.name = name; 10 | this.age = age; 11 | this.job = job; 12 | this.test = ['man', 'woman']; 13 | } 14 | Fn.prototype = { 15 | constructor: Fn, 16 | sayName() { 17 | return this.name; 18 | }, 19 | }; 20 | var p1 = new Fn('xsa', 'tt', 'te'); 21 | var p2 = new Fn('xsa2', 'tt2', 'te2'); 22 | p1.test.push('son'); 23 | console.info(p1.test === p2.test); 24 | ``` 25 | -------------------------------------------------------------------------------- /docs/public/demos/js/simulate/myBind.js: -------------------------------------------------------------------------------- 1 | Function.prototype.myBind = function (context, ...args) { 2 | const self = this; 3 | return (...innerArgs) => { 4 | // new 关键字 5 | if (this instanceof self) { 6 | console.info('is new'); 7 | return new self(...args, ...innerArgs); 8 | } 9 | 10 | console.info('no new'); 11 | return self.call(context, ...args, ...innerArgs); 12 | }; 13 | }; 14 | const fn = function (a, b) { 15 | console.info(a, b); 16 | }; 17 | 18 | const fnBind = fn.myBind(null, 1, 2); 19 | 20 | fnBind(); 21 | -------------------------------------------------------------------------------- /docs/public/demos/js/simulate/myCall.js: -------------------------------------------------------------------------------- 1 | Function.prototype.myCall = function (context, [...args]) { 2 | if (context === null || context === undefined) { 3 | context = this || window; 4 | } else { 5 | context = Object(context); // 如果不是对象类型?则转为对象,以此保证 this 是个 对象 6 | } 7 | const fn = Symbol('myCall'); 8 | context[fn] = this; 9 | 10 | let ret = context[fn](...args); 11 | delete context[fn]; 12 | return ret; 13 | }; 14 | 15 | const fn = function (a, b) { 16 | console.info(a, b); 17 | }; 18 | 19 | const fnBind = fn.myCall(null, [1, 2]); 20 | -------------------------------------------------------------------------------- /docs/backend/deno/index.md: -------------------------------------------------------------------------------- 1 | # Deno docs 2 | 3 | - [官网](https://deno.land/) 4 | - [说明书](https://github.com/denoland/deno/tree/master/docs) 5 | - [API](https://doc.deno.land/https/github.com/denoland/deno/releases/latest/download/lib.deno.d.ts) 6 | - [deno-docs](https://github.com/veaba/deno-docs) 7 | - 使用官方文档做 i18n,并支持双语,vuepress 架构 8 | - 自动更新文档,并将需要更新的片段文件推送到/veaba/deno-docs 仓库的 issues 里面让作者对应手动更新 9 | - 目前约定 1 周更新一次文档 10 | - 脚本可以使用 deno 或者 python 来写 11 | - 自动翻译自动部署 12 | - 模块 13 | - [标准库](https://deno.land/std/) 14 | - [第三方库](https://deno.land/x/) 15 | -------------------------------------------------------------------------------- /docs/frontend/webgl/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | 5 | # WebGL 6 | 7 | 摘自 MDN: 8 | 9 | > WebGL 是一种 JavaScript API。用于任何兼容 Web 浏览器中呈现交互式 3D 和 2D。WebGL 通过一个与 Open ES 2.0 相符的 API,可以在 Canvas 元素中使用。 10 | 11 | (意味着,做一些嵌入式支持的话,其他设备是可以支持) 12 | 13 | ## 浏览器支持 14 | 15 | - Firefox 4 + 16 | - Google Chrome 9+ 17 | - Opera 12+ 18 | - Safari 5.1 + 19 | - Internet Explore 11+ 20 | 21 | ## 标准接口 22 | 23 | ## 拓展 24 | 25 | ## 事件 26 | 27 | ## 常量和类型 28 | 29 | - WebGL 常量 30 | - WebGL 类型 31 | 32 | ## WebGL 2 33 | -------------------------------------------------------------------------------- /docs/interview/2020-alibaba.md: -------------------------------------------------------------------------------- 1 | # 一次阿里巴巴面试经历的总结 2 | 3 | 实在是没有准备这一次,太被动了。 4 | 5 | > 做一下理论知识可能比较好,尽快实践能力很棒,但也只是入职之后才体现出来。(实践能力优于理论能力或许不是一次正确的表达方式) 6 | 7 | ::: tip 8 | 还是老老实实去看 Vue3 源码吧 9 | ::: 10 | 11 | ## V8 引擎的垃圾回收机制 12 | 13 | - [浅谈 Chrome V8 引擎中的垃圾回收机制-参考一些文档](https://www.cnblogs.com/liangdaye/p/4654734.html) 14 | 15 | ### 遇到什么问题 16 | 17 | ### 怎么解决 18 | 19 | ### 还有什么问题 20 | 21 | ## vue 相关 22 | 23 | ### get、set 24 | 25 | ### vue 的 get set 的依赖收集,依赖是在 get 上做的还是 set 上做 26 | 27 | ## 客户端 Vue 与 SSR 有什么区别 28 | 29 | ### 如何实习 SSR 组件渲染 30 | 31 | ### 路由怎么找到组件来渲染 32 | -------------------------------------------------------------------------------- /docs/public/demos/js/algorithm/normal/greedy-coin-change.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 贪心算法是一种在每一步选择中都采取当前状态下的最优决策,从而希望最终得到全局最优解的算法策略。 3 | * 虽然贪心算法并不总是能得到全局最优解,但在许多问题上它可以提供高效且近似最优的解决方案。 4 | * 假设你有无限数量的硬币,硬币面额为 [1, 5, 10, 25](美分),要找给顾客 amount 美分,求最少需要多少枚硬币。 5 | */ 6 | 7 | function coinChange(amount) { 8 | const coins = [25, 10, 5, 1]; 9 | let count = 0; 10 | for (let coin of coins) { 11 | count += Math.floor(amount / coin); 12 | amount %= coin; 13 | } 14 | return count; 15 | } 16 | 17 | // 测试 18 | const amount = 63; 19 | console.log(coinChange(amount)); // 输出 6 20 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "dist", 4 | "target": "esnext", 5 | "module": "esnext", 6 | "moduleResolution": "bundler", 7 | "esModuleInterop": true, 8 | "resolveJsonModule": true, 9 | "allowJs": true, 10 | "strict": true, 11 | "noUnusedLocals": true, 12 | "skipLibCheck": true, 13 | "jsx": "preserve", 14 | "baseUrl": ".", 15 | "paths": { 16 | "@theme/*": [".vitepress/theme/*"] 17 | } 18 | }, 19 | "include": ["env.d.ts", "docs/.vitepress/**/*", "docs/.vitepress/global.d.ts"] 20 | } -------------------------------------------------------------------------------- /docs/public/demos/js/algorithm/normal/dynamic-fibonacci.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 动态规划(Dynamic Programming,DP)是一种通过把原问题分解为相对简单的子问题, 3 | * 并保存子问题的解来避免重复计算,从而解决复杂问题的算法策略。 4 | * 5 | * 0 - 1 背包问题:有 n 个物品,每个物品有重量 weights 和价值 values,背包的容量为 capacity。每个物品只能使用一次,求能装入背包的最大价值。 6 | */ 7 | 8 | 9 | function fibonacci(n) { 10 | if (n <= 1) { 11 | return n; 12 | } 13 | let dp = new Array(n + 1); 14 | dp[0] = 0; 15 | dp[1] = 1; 16 | for (let i = 2; i <= n; i++) { 17 | dp[i] = dp[i - 1] + dp[i - 2]; 18 | } 19 | return dp[n]; 20 | } 21 | 22 | // 测试 23 | console.log(fibonacci(10)); -------------------------------------------------------------------------------- /docs/frontend/v8/source-code.md: -------------------------------------------------------------------------------- 1 | # todo 检出 V8 源码 2 | 3 | - [原文](https://v8.dev/docs/source-code) 4 | 5 | 本文档说明如何在本地检出 V8 源代码。如果您只想在线浏览源代码,请使用以下链接: 6 | 7 | - [阅览](https://chromium.googlesource.com/v8/v8/) 8 | - [浏览 bleeding edge](https://chromium.googlesource.com/v8/v8/+/master) 9 | - [变更](https://chromium.googlesource.com/v8/v8/+log/master) 10 | 11 | ## 使用 GIT 12 | 13 | ## 说明 14 | 15 | ## 保持更新 16 | 17 | ## 发送审核代码 18 | 19 | ## 提交 20 | 21 | ## 实验工作 22 | 23 | ### 从 codeReview 创建实验工作 24 | 25 | ### 从本地分支创建实验工作 26 | 27 | ### 可用的 arguments 28 | 29 | ### 查看 try 服务器 30 | 31 | ## 源码分支 32 | -------------------------------------------------------------------------------- /docs/frontend/es6/const-let.md: -------------------------------------------------------------------------------- 1 | ## let、const 2 | 3 | - let 4 | 5 | - 不可重复声明变量 6 | - 暂时临时死域 7 | - 作用域块 8 | 9 | - const 10 | 11 | - 必须先赋值 12 | - 不可重复声明变量 13 | - 对于纯数字、字符、等基本结构的话,不可更改,但可以更改数组里面的元素、对象里面的 key 14 | - 只能去改变引用类型 (object array),无法取改变基本类型 (`boolean`、`number`、`string`、`null`、`undefined`、`symbol`、`bigint` (Chrome 67+开始)) 15 | 16 | - var 17 | 18 | - var 声明,存在变量提升问题 19 | - var 是全局变量声明的方式 20 | 21 | ```js 22 | for (var i = 0; i < 5; i++) { 23 | } 24 | console.info(i); // 5 25 | 26 | for (let i = 0; i < 5; i++) { 27 | } 28 | console.info(i); // 抛出未定义 且 for 括号和 大括号是不同的作用域 29 | ``` -------------------------------------------------------------------------------- /docs/public/demos/js/extends/prototype-extends.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 原型继承 3 | */ 4 | 5 | function Parent() { 6 | this.name = 'parent'; 7 | } 8 | 9 | Parent.prototype.say = function () { 10 | console.log('hello'); 11 | }; 12 | 13 | function Child() { 14 | this.age = 18; 15 | } 16 | 17 | Child.prototype = Object.create(Parent.prototype); // Child 继承 Parent 18 | Child.prototype.constructor = Child; // 重置 constructor 19 | Child.prototype.cook = function () { 20 | console.log('cook'); 21 | }; 22 | 23 | // 此时, child 函数将拥有 cook 和 say 方法 24 | let child = new Child(); 25 | child.cook(); 26 | child.say(); 27 | -------------------------------------------------------------------------------- /docs/interview/2020-12.md: -------------------------------------------------------------------------------- 1 | # 2020 年 12 月面试题 2 | 3 | ## 原型与原型链的关系 4 | 5 | ## APP bridge 通信 6 | 7 | bridge 中原生应用与 `JavaScript` bridge 通信原理是什么? 8 | 9 | > 实际上,我不太懂这个题目的出题人是什么居心。 10 | 11 | 于是回答:通过共享浏览器 window 作用域,H5 给 window 放数据,原生调用浏览器 window 来获取。 12 | 13 | 搜了下大致的描述: 14 | 15 | 1. H5 中的 `JavaScript` 发起请求,在 android 的 WebViewClient.shouldOverrideUrlLoading 方法中拦截 URL 请求,判断是否为接口调用 16 | 17 | 2. android 通过 webView.addJavascriptInterface 方法向 windows 对象中注入原生代码,然后 H5 在 `JavaScript` 中调用相应的方法 18 | 19 | 3. 选择 prompt,console.log,alert 等方法作为通信的接口 20 | -------------------------------------------------------------------------------- /docs/reference.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | 5 | # 引用 6 | 7 | > 索引关于本作知识引用来源 sub 标签 8 | 9 | 1. [搜狐 - 如何减少 HTML 页面回流与重绘 (Reflow & Repaint)](http://www.sohu.com/a/111695367_466959) 10 | 2. [闭包的应用场景一林枫山博客](https://www.cnblogs.com/star-studio/archive/2011/06/22/2086493.html) 11 | 3. [IE 内存泄漏问题总结](https://blog.csdn.net/rootes/article/details/8784240) 12 | 4. [绑定-this-的方法](https://wangdoc.com/javascript/oop/this.html#%E7%BB%91%E5%AE%9A-this-%E7%9A%84%E6%96%B9%E6%B3%95) 13 | 5. [es6-proxy](https://es6.ruanyifeng.com/#docs/proxy) 14 | 6. [尚未录入-web 大前端面试——JavaScript](https://juejin.im/post/5e93deb46fb9a03c77620c13) 15 | -------------------------------------------------------------------------------- /docs/public/demos/js/simulate/myDecoration.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 伪代码,需要转码才可以执行~ 3 | */ 4 | // 装饰器函数 5 | function log(target, name, descriptor) { 6 | const originalMethod = descriptor.value; 7 | descriptor.value = function (...args) { 8 | console.log(`调用方法 ${name},参数为:`, args); 9 | const result = originalMethod.apply(this, args); 10 | console.log(`方法 ${name} 执行完毕,结果为:`, result); 11 | return result; 12 | }; 13 | return descriptor; 14 | } 15 | 16 | class MyClass { 17 | @log 18 | add(a, b) { 19 | return a + b; 20 | } 21 | } 22 | 23 | // 使用 24 | const myClass = new MyClass(); 25 | myClass.add(2, 3); 26 | -------------------------------------------------------------------------------- /docs/public/demos/html/closure.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 8 | 9 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /docs/public/demos/js/simulate/myApply.js: -------------------------------------------------------------------------------- 1 | Function.prototype.myApply = function (context, ...args) { 2 | context = Object(context); // 如果不是对象类型?则转为对象,以此保证 this 是个 对象 3 | 4 | // context 创建一个 symbol 的key,并赋值 this 5 | const fn = Symbol('myApply'); 6 | context[fn] = this; 7 | // 然后 调用 context[fn]() 8 | let ret = undefined; 9 | 10 | if (args) { 11 | ret = context[fn](...args); 12 | } else { 13 | ret = context[fn](); 14 | } 15 | 16 | // 删除这个函数 17 | delete context[fn]; 18 | // 返回结果 19 | return ret; 20 | }; 21 | 22 | const fn = function (a, b) { 23 | console.info(a, b); 24 | }; 25 | 26 | fn.myApply(null, 1, 2); 27 | -------------------------------------------------------------------------------- /docs/javascript/function/function-callback.md: -------------------------------------------------------------------------------- 1 | # 回调 2 | 3 | ## 函数式回调 4 | 5 | 每一步是下一步的结果 6 | 7 | ```js 8 | function doStep1(init, callback) { 9 | const result = init + 1; 10 | callback(result); 11 | } 12 | function doStep2(init, callback) { 13 | const result = init + 2; 14 | callback(result); 15 | } 16 | function doStep3(init, callback) { 17 | const result = init + 3; 18 | callback(result); 19 | } 20 | function doOperation() { 21 | doStep1(0, (result1) => { 22 | doStep2(result1, (result2) => { 23 | doStep3(result2, (result3) => { 24 | console.log(`结果:${result3}`); 25 | }); 26 | }); 27 | }); 28 | } 29 | doOperation(); 30 | ``` 31 | -------------------------------------------------------------------------------- /docs/public/demos/js/currring.js: -------------------------------------------------------------------------------- 1 | // 柯里化 Currying 2 | 3 | function add() { 4 | const args = Array.prototype.slice.call(arguments); 5 | 6 | console.log("args=>", args); 7 | 8 | // 闭包特性,收集所有参数值 9 | const adder = function() { 10 | args.push(...args); 11 | return adder; 12 | }; 13 | console.log("args2=>", args); 14 | 15 | // toString 隐式转换 16 | 17 | console.log("adder==>", adder); 18 | adder.toString = function() { 19 | return args.reduce((left, right) => { 20 | return left + right; 21 | }); 22 | }; 23 | return adder; 24 | } 25 | 26 | const a = add(1, 5454)(1); 27 | 28 | const b = add(2, 5454)(1)(8588); 29 | console.log(a, b); 30 | -------------------------------------------------------------------------------- /docs/public/demos/js/simulate/mySymbol.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 核心逻辑:函数的 return 出参不一样 3 | */ 4 | // 创建一个计数器 5 | let symbolCounter = 0; 6 | 7 | // 创建一个函数来生成唯一的标识符 8 | function mySymbol() { 9 | const uniqueId = `mySymbol_${symbolCounter++}`; 10 | return { 11 | toString: function () { 12 | return uniqueId; 13 | }, 14 | valueOf: function () { 15 | return uniqueId; 16 | } 17 | }; 18 | } 19 | 20 | // 使用自定义的mySymbol 21 | let sym1 = mySymbol(); 22 | let sym2 = mySymbol(); 23 | 24 | console.log(sym1 === sym2); // false 25 | console.log(sym1.toString()); // mySymbol_0 26 | console.log(sym2.toString()); // mySymbol_1 27 | 28 | -------------------------------------------------------------------------------- /docs/public/demos/js/algorithm/normal/backtrack-combine.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 回溯算法 -组合问题 3 | * 回溯算法是一种通过尝试所有可能的路径来解决问题的算法策略。在遇到不可行的路径时, 4 | * 它会回退到上一个决策点,尝试其他路径,直到找到解决方案或遍历完所有可能的路径。 5 | */ 6 | function combine(n, k) { 7 | const result = []; 8 | const path = []; 9 | 10 | function backtrack(start) { 11 | if (path.length === k) { 12 | result.push([...path]); 13 | return; 14 | } 15 | for (let i = start; i <= n; i++) { 16 | path.push(i); 17 | backtrack(i + 1); 18 | path.pop(); 19 | } 20 | } 21 | 22 | backtrack(1); 23 | return result; 24 | } 25 | 26 | // 测试 27 | const n = 4; 28 | const k = 2; 29 | console.log(combine(n, k)); 30 | -------------------------------------------------------------------------------- /docs/public/demos/js/binary-search-sort-2.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 二分查找方法1:通过非递归的方式, 3 | * 1. 先找到中间值 4 | * 2. 通过中间值比较,大的在右,小的放左 5 | * 3. 再在两边分别寻找中间值,吃持续以上操作 6 | * (最多Lon2N) 7 | * 根据, 8 | */ 9 | function binarySearchTwo(data, dest) { 10 | let low = 0; 11 | let high = data.length - 1; 12 | 13 | while (low <= high) { 14 | const mid = Math.floor((high + low) / 2); 15 | if (data[mid] == dest) { 16 | return mid; 17 | } 18 | if (dest > data[mid]) { 19 | low = mid + 1; 20 | } else { 21 | high = mid - 1; 22 | } 23 | } 24 | return undefined; 25 | } 26 | 27 | const arr = [1, 3, 5, 7, 9, 10]; 28 | 29 | console.log(binarySearchTwo(arr, 5)); 30 | -------------------------------------------------------------------------------- /docs/interview/2018-12.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | 5 | # 2018 年 12 月份面试题 6 | 7 | 1. 阅读代码,立即执行函数 8 | 9 | > 运算符的优先级 10 | 11 | ```js 12 | /**1*/ 13 | var name1 ='World!'; 14 | (function(){ 15 | console.log(this); 16 | if(typeof name1 === 'undefined'){ 17 | var name1 ='JACK'; 18 | console.log('hello,'+name1) 19 | }else{ 20 | console.log('Goodbye' + name1) 21 | } 22 | })(); 23 | 24 | /**2 运算符的优先级*/ 25 | var val= "hello"; 26 | console.log ('Value is' +(val==="hello")?'Something':'Nothing'); 27 | 28 | ``` 29 | 30 | ## 为什么其他语言不能使用 set? 31 | 32 | ## transform 和 display none 回流问题 33 | -------------------------------------------------------------------------------- /docs/public/demos/js/test_function_name_anonymous_arrow.js: -------------------------------------------------------------------------------- 1 | /*********************** 2 | * @name JS 3 | * @author veaba 4 | * @date 2019/8/20 0020 下午 5:38 5 | ***********************/ 6 | 7 | console.time('具名函数'); 8 | var a=[66,99,44].map(function hello(item) { 9 | return item*2 10 | }); 11 | console.timeEnd('具名函数'); 12 | 13 | 14 | // 不清楚和以下有什么区别: 15 | 16 | console.time('匿名函数'); 17 | var b =[66,99,44].map(function(item) { 18 | return item*2 19 | }); 20 | console.timeEnd('匿名函数'); 21 | 22 | 23 | // 而如果使用箭头函数,则为: 24 | 25 | console.time('箭头函数'); 26 | var c=[66,99,44].map(item=>item*2); 27 | console.timeEnd('箭头函数'); 28 | 29 | 30 | // 测试结果发现函数的执行时间: 箭头函数<匿名函数<具名函数 31 | // -9007199254710991——9007199254710991 -------------------------------------------------------------------------------- /docs/public/demos/js/algorithm/sort/pop-sort.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 冒泡排序 3 | * 1. 比较相邻的两个元素,如果前者比后者大 4 | * 2. 第一轮结束,最后一个是最大值 5 | * 3. 开始第二轮,最后一个最大的了,可不参与比较,巧用 `arr.length-i-1` 6 | * 7 | * 8 | */ 9 | 10 | var arr = [12, 12, 15, 445, 451, 12, 123456, 61, 20, 136, 4856, 1, 0]; 11 | // 12, 12, 15,445, 12, 451,61, 20, 136,4856, 1, 0,123456 12 | //[12, 12, 15,451, 12, 445,61, 123456, 136,4856, 1, 0, 20] 13 | 14 | for (let i = 0; i < arr.length; i++) { 15 | for (let j = 0; j < arr.length - i - 1; j++) { 16 | console.log("j=>", i, j); 17 | if (arr[i] > arr[j]) { 18 | const temp = arr[i]; 19 | arr[i] = arr[j]; 20 | arr[j] = temp; 21 | } 22 | } 23 | } 24 | 25 | console.log("arr==>", arr); 26 | -------------------------------------------------------------------------------- /docs/keyword.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | 5 | # 关键词 6 | 7 | ## 未来需要了解的内容 8 | 9 | - [this](/javascript/this) 10 | - [冒泡算法](/algorithm/bubbing) 11 | - [继承](/javascript/inherit/index) 12 | - react 13 | - 小程序/微信/百度/快应用/支付宝 14 | - [闭包](javascript/scoped/closure.md) 15 | - js 垃圾回收机制 16 | - [深拷贝](/javascript/#深拷贝) 17 | - [浅拷贝](/javascript/#浅拷贝) 18 | - class 19 | - Generator 20 | - webGl 21 | - [防抖](/javascript/useful/debounce) 22 | - [节流](/javascript/useful/throttle) 23 | - canvas 24 | - [proxy](frontend/es6/proxy) 25 | - node 中 commonJs 与 ES6 module 26 | - node eventLoop 27 | - BFC 28 | - 词法作用域 29 | - 执行上下文 30 | - 全局执行上下文 31 | - 函数执行上下文 32 | - `eval` 执行上下文 33 | - AST:抽象语法树。(abstract syntax tree) 34 | - CORS:跨域资源共享。(Cross-Origin Resource Sharing) 35 | -------------------------------------------------------------------------------- /docs/public/demos/html/base64AndSrcImage.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | base64 与 src 引入图片的比较 7 | 8 | 9 | 10 | 11 | 12 | 13 |

比较 响应式 媒体查询情况下,base64 与 src 的区别

14 | 15 |
16 |
17 |
18 |
19 | 20 |

子级的focus 让父级产生变化

21 |
22 |
bbbbb child
23 |
24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /docs/public/demos/js/algorithm/normal/divide-maxSubArray.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 分治算法(Divide and Conquer Algorithm)是一种常用的算法策略, 3 | * 它将一个复杂的问题分解成多个规模较小、相互独立且形式相同的子问题, 4 | * 然后分别解决这些子问题,最后将子问题的解合并起来得到原问题的解。 5 | * 6 | * 给定一个整数数组 nums,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 7 | */ 8 | 9 | function maxSubArray(nums) { 10 | if (nums.length === 1) { 11 | return nums[0]; 12 | } 13 | 14 | let maxEndingHere = nums[0]; 15 | let maxSoFar = nums[0]; 16 | 17 | for (let i = 1; i < nums.length; i++) { 18 | maxEndingHere = Math.max(nums[i], maxEndingHere + nums[i]); 19 | maxSoFar = Math.max(maxSoFar, maxEndingHere); 20 | } 21 | 22 | return maxSoFar; 23 | } 24 | 25 | // 测试 26 | const nums = [-2, 1, -3, 4, -1, 2, 3, -5, 4]; 27 | console.log(maxSubArray(nums)); // 输出 6 28 | -------------------------------------------------------------------------------- /docs/public/demos/js/algorithm/normal/greedy-cookie-index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 贪心算法是一种在每一步选择中都采取当前状态下的最优决策,从而希望最终得到全局最优解的算法策略。 3 | * 虽然贪心算法并不总是能得到全局最优解,但在许多问题上它可以提供高效且近似最优的解决方案。 4 | * 5 | * 有一群孩子和一堆饼干,每个孩子有一个饥饿度,每个饼干都有一个大小。每个孩子只能吃一个饼干, 6 | * 且只有当饼干的大小大于等于孩子的饥饿度时,孩子才能吃饱。求最多能有多少个孩子吃饱。 7 | */ 8 | 9 | function findContentChildren(g, s) { 10 | g.sort((a, b) => a - b); 11 | s.sort((a, b) => a - b); 12 | let childIndex = 0; 13 | let cookieIndex = 0; 14 | while (childIndex < g.length && cookieIndex < s.length) { 15 | if (s[cookieIndex] >= g[childIndex]) { 16 | childIndex++; 17 | } 18 | cookieIndex++; 19 | } 20 | return childIndex; 21 | } 22 | 23 | // 测试 24 | const g = [1, 2, 3]; 25 | const s = [1, 1]; 26 | console.log(findContentChildren(g, s)); // 输出 1 27 | -------------------------------------------------------------------------------- /docs/javascript/inherit/inherit-parasitic-structure.md: -------------------------------------------------------------------------------- 1 | # 寄生构造继承 2 | 3 | 创建对象-寄生构造函数模式 4 | 5 | > 比工厂模式多了一个 new,使用工厂模式 new 出来 6 | 7 | ## 寄生构造 8 | 9 | 特点: 10 | 11 | 1. 返回的对象与构造函数或者与构造函数的原型属性之间没有关系 `[1]` 12 | 2. 构造函数 return 的对象与构造函数外部创建的对象没有什么不同 `[2]` 13 | 3. 不能使用 instanceof 操作符确定对象类型 14 | 4. 在红宝石上书,不推荐此模式 15 | 16 | ```js 17 | function factory(name, age, job) { 18 | // const obj=Object.create({})//带有普通对象的__proto__ 类似 const obj = new Object() 19 | // const obj=Object.create(null)//则没有_proto__! 20 | const obj = {}; //此处不一定是Object对象,可以是Array对象,具体看业务操作 21 | obj.age = age; 22 | obj.name = name; 23 | obj.job = job; 24 | obj.sayName = function () { 25 | return this.name; 26 | }; 27 | return obj; 28 | } 29 | //use 30 | const p = new factory('张三', '28', '前端狗'); 31 | ``` 32 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "test": "jest", 4 | "dev": "vitepress dev docs --port 5174", 5 | "build": "vitepress build docs", 6 | "preview": "vitepress preview docs", 7 | "lint": "zhlint --fix docs/**/*.md" 8 | }, 9 | "dependencies": { 10 | "vitepress": "1.6.3", 11 | "vitepress-mermaid-renderer": "^1.0.14", 12 | "vitepress-script-preview": "^0.0.10", 13 | "vue": "^3.5.17" 14 | }, 15 | "devDependencies": { 16 | "@types/node": "^24.0.7", 17 | "jest": "^30.0.3", 18 | "typescript": "^5.8.3", 19 | "zhlint": "^0.8.2" 20 | }, 21 | "pnpm": { 22 | "ignoredBuiltDependencies": [ 23 | "@parcel/watcher", 24 | "core-js", 25 | "esbuild", 26 | "highlight.js", 27 | "vuepress" 28 | ] 29 | } 30 | } -------------------------------------------------------------------------------- /docs/javascript/switch.md: -------------------------------------------------------------------------------- 1 | # switch 语句 2 | 3 | - switch 4 | - case 必须紧接着跟值/变量/简单表达式/&&/function,不确定能使用|| 5 | 6 | ```js 7 | // 以下产生一个 bug,不管怎么样使用关键字 name 声明一个值,只能是 string 类型!!! 8 | var name = '22'; 9 | var tt = '22'; 10 | var name1 = 22; 11 | var tt1 = 22; 12 | // demo1 13 | switch (name) { 14 | // 终止错误,合并两个条件 15 | case '22': 16 | case 'AbortError': 17 | default: 18 | console.info('NotFoundError:找不到满足错误的类型'); 19 | } 20 | //demo2 21 | switch (name) { 22 | // 终止错误,合并两个条件 23 | case tt: 24 | case 'AbortError': 25 | default: 26 | console.info('NotFoundError:找不到满足错误的类型'); 27 | } 28 | //demo3 29 | switch (name1) { 30 | // 终止错误,合并两个条件,数值为 number 类型时候,无法进入此条件 31 | case tt1: 32 | case 'AbortError': 33 | default: 34 | console.info('NotFoundError:找不到满足错误的类型'); 35 | } 36 | ``` -------------------------------------------------------------------------------- /docs/public/demos/js/algorithm/sort/shell-sort.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 希尔排序 3 | * 4 | * 1. 先将整个待排序的记录序列分割成为若干子序列 5 | * 2. 分别直接插入序列 6 | * 希尔排序(Shell Sort)是插入排序的一种改进版本,也称为 “缩小增量排序”。 7 | * 它通过将原始数据集合分割成若干个较小的子序列, 8 | * 对每个子序列进行插入排序,从而使数据逐步变得有序。 9 | */ 10 | function shellSort(arr) { 11 | let n = arr.length; 12 | let gap = Math.floor(n / 2); // 初始增量 13 | 14 | while (gap > 0) { 15 | for (let i = gap; i < n; i++) { 16 | let temp = arr[i]; 17 | let j = i; 18 | while (j >= gap && arr[j - gap] > temp) { 19 | arr[j] = arr[j - gap]; 20 | j -= gap; 21 | } 22 | arr[j] = temp; 23 | } 24 | gap = Math.floor(gap / 2); // 缩小增量 25 | } 26 | return arr; 27 | } 28 | 29 | // 测试 30 | let array = [64, 34, 25, 12, 22, 11, 90]; 31 | console.log(shellSort(array)); 32 | -------------------------------------------------------------------------------- /docs/javascript/context/bind.md: -------------------------------------------------------------------------------- 1 | # Bind 函数 2 | 3 | ## 说明 4 | 5 | ::: tip 6 | bind 新函数,不会立即执行。 7 | ::: 8 | 9 | ## 特性 10 | 11 | - 创建一个新的函数。 12 | - 新函数的 `this` 是 `bind` 的第一个参数 13 | - 其余参数作为新函数的参数使用 14 | 15 | ```js 16 | const bind = function () { 17 | return function () { 18 | // do something 19 | }; 20 | }; 21 | ``` 22 | 23 | - 因为 bind 每次都生成一个函数。所以需要注意以下: 24 | 25 | ```js 26 | const githubObject = { 27 | setRepo() { 28 | console.info('hello'); 29 | }, 30 | }; 31 | // bad case 32 | const ele = document.querySelector('xx'); 33 | ele.addEventListener('click', githubObject.setRepo.bind(githubObject)); 34 | 35 | // good case 36 | const listener = githubObject.setRepo.bind(githubObject); 37 | ele.addEventListener('click', listener); 38 | 39 | // 否则无法 remove 事件监听 40 | ele.removeEventListener('click', listener); 41 | ``` 42 | -------------------------------------------------------------------------------- /docs/public/demos/js/algorithm/sort/fast-sort.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 快速排序 3 | * 对冒泡算法的改进 4 | * 第一趟: 5 | * - 一部分: 比另外部分都要小,递归调用 6 | * - 另外一部分:递归调用 7 | * 在两边都实行快速排序 8 | * 9 | */ 10 | 11 | function fastSort(el) { 12 | if (el.length <= 1) return el; 13 | // 向下取整获得中间数 14 | const halfIndex = Math.floor(el.length / 2); 15 | const pivot = el.splice(halfIndex, 1)[0]; 16 | const left = []; 17 | const right = []; 18 | for (let i = 0; i < el.length; i++) { 19 | if (el[i] < pivot) { 20 | left.push(el[i]); 21 | } else { 22 | right.push(el[i]); 23 | } 24 | } 25 | console.log("===>", { halfIndex, pivot, left, right }); 26 | return fastSort(left).concat([pivot], fastSort(right)); 27 | } 28 | 29 | const arr = [12, 12, 15, 445, 451, 12, 123456, 61, 20, 136, 4856, 1, 0]; 30 | 31 | console.log(fastSort(arr)); 32 | -------------------------------------------------------------------------------- /docs/backend/rust/actix-web/install.md: -------------------------------------------------------------------------------- 1 | # 安装 2 | 3 | 安装 Rust 4 | 5 | 因为 `actix-web` 是一个 Rust 框架,所以你需要 Rust 来开始使用它。如果你还没有,我们建议你使用 `rustup` 来管理你的 Rust 安装。 6 | 7 | 官方的 Rust 指南有一个很好的开始部分。我们目前至少需要 Rust1.39,所以请确保你运行 `rustup update` 以获得最新和最新的 Rust 版本。 8 | 特别是本指南将假设你实际运行 Rust 1.39 或更高版本。 9 | 10 | 安装 actix-web 11 | 12 | 多亏了 Rust 的 `cargo` 管理器,你不需要显式地安装 `actix-web`。相信它,就解放你自己了。对于不太可能使用 `actix-web` 开发版本的情况,可以直接依赖 git 存储库。 13 | 14 | 发行版本: 15 | 16 | ```toml 17 | [dependencies] 18 | actix-web = "2.0" 19 | ``` 20 | 21 | 开发版本: 22 | 23 | ```toml 24 | [dependencies] 25 | actix-web = { git = "https://github.com/actix/actix-web" } 26 | ``` 27 | 28 | ## 潜入 29 | 30 | 这里有两条路可以走,你可以按照指南进行操作,或者如果你非常不耐烦,你可能希望查看我们广泛的示例存储库并运行包含的示例。例如,下面是如何运行的基本示例: 31 | 32 | ```cmd 33 | git clone https://github.com/actix/examples 34 | cd examples/basics 35 | cargo run 36 | ``` 37 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: home 3 | 4 | sidebar: false 5 | actionText: 立即阅读 → 6 | actionLink: /guide.html 7 | icpText: veaba/web-advanced-frond-end 8 | icpLink: https://github.com/veaba/web-advanced-frond-end 9 | 10 | hero: 11 | name: web advanced 12 | text: 前端工程师进阶指南 13 | text-size: 1.5 14 | tagline: 从入门到失业,仅需颈椎发作 15 | actions: 16 | - theme: brand 17 | text: 开始阅读 18 | link: /javascript/ 19 | - theme: alt 20 | text: 指南目录 21 | link: /guide 22 | - theme: alt 23 | text: GitHub 24 | link: https://github.com/veaba/web-advanced 25 | 26 | features: 27 | - icon: 📝 28 | title: 开源(Open Source) 29 | details: Github开源文档 30 | - icon: 📥 31 | title: 可视化 + 低门槛 32 | details: 最终的目的,期望将概念性的东西可视化,方便记忆。 33 | - icon: 🚀 34 | title: TODO 基于实际的例子 35 | details: 以实践为标准 36 | --- 37 | -------------------------------------------------------------------------------- /docs/javascript/context/index.md: -------------------------------------------------------------------------------- 1 | # 上下文 2 | 3 | ## 概念 4 | 5 | - `apply`、`call`、`bind` 三个方法改变上下文。 6 | - 在 `ES6` 中的箭头函数里,`apply`、`call`、`bind` 不起作用 7 | 8 | ## apply 方法 9 | 10 | `apply` 方法。调用一个函数,具有指定 this 的值,以及作为一个数组提供的参数。[MDN 查看更多](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/apply) 11 | 12 | ## bind 方法 13 | 14 | `bind` 方法。创建一个新的函数。被调用时,其 this 关键字设置为提供的值,在调用时新函数时,在任何提供之前一个给定的参数序列。[MDN 查看更多](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) 15 | 16 | ## call 方法 17 | 18 | `call` 方法。调用一个函数,具有一个指定 this 值和分别地提供参数 [MDN 查看更多](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/call) 19 | 20 | 语法 `function.call(thisObj,args...)`,如果 thisObj 是 null,则是全局对象,args 作为参数传递给 `function` 21 | 22 | 23 | -------------------------------------------------------------------------------- /docs/javascript/eventloop.md: -------------------------------------------------------------------------------- 1 | # EventLoop 2 | 3 | ## JavaScript 事件 4 | 5 | 分为两种事件类型: 6 | 7 | - 宏任务 (macro-task)/Task 中的异步任务: 8 | 9 | - setTimeout 10 | - setInterval 11 | - setImmediate (Node) 12 | - requestAnimationFrame(browser) 13 | - I/O 14 | - UI rendering(browser) 15 | 16 | - 微任务 (micro-task)/jobs 中的异步任务: 17 | - process.nextTick(node,limit=1000) 18 | - Promise 19 | - Object.observe 20 | - MutationObserve 21 | 22 | 事件的执行顺序:先 `宏任务` ——> `微任务`。 23 | 24 | 任务中有 `同步任务` 和 `异步任务`: 25 | 26 | - ——> 同步的进入主线程 27 | - ——> 异步进入 event table 并注册函数 28 | - ——> 异步完成后 29 | - ——> 将回调放入 event queue (宏任务和微任务是不同的 event queue),此时不执行异步快里的代码 30 | - ——> 同步任务完成后,从 event queue 读取事件放入主线程 31 | - ——> 回调函数可能包含不同的任务,因此循环执行上述 32 | 33 | ## Node 34 | 35 | - 略 36 | 37 | ## reference 38 | 39 | - [带你彻底弄懂 Event Loop](https://segmentfault.com/a/1190000016278115) 40 | -------------------------------------------------------------------------------- /docs/public/demos/js/algorithm/normal/backtrack-full-sort.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 回溯算法 - 全排列 3 | * 回溯算法是一种通过尝试所有可能的路径来解决问题的算法策略。在遇到不可行的路径时, 4 | * 它会回退到上一个决策点,尝试其他路径,直到找到解决方案或遍历完所有可能的路径。 5 | * 给定一个不包含重复数字的数组,返回所有可能的全排列。 6 | */ 7 | function permute(nums) { 8 | const result = []; 9 | const used = new Array(nums.length).fill(false); 10 | const path = []; 11 | 12 | function backtrack() { 13 | if (path.length === nums.length) { 14 | result.push([...path]); 15 | return; 16 | } 17 | for (let i = 0; i < nums.length; i++) { 18 | if (used[i]) continue; 19 | path.push(nums[i]); 20 | used[i] = true; 21 | backtrack(); 22 | path.pop(); 23 | used[i] = false; 24 | } 25 | } 26 | 27 | backtrack(); 28 | return result; 29 | } 30 | 31 | // 测试 32 | const nums = [1, 2, 3]; 33 | console.log(permute(nums)); 34 | -------------------------------------------------------------------------------- /docs/public/demos/js/algorithm/normal/greedy-activity-selection.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 贪心算法是一种在每一步选择中都采取当前状态下的最优决策,从而希望最终得到全局最优解的算法策略。 3 | * 虽然贪心算法并不总是能得到全局最优解,但在许多问题上它可以提供高效且近似最优的解决方案。 4 | * 假设有一组活动,每个活动都有开始时间和结束时间,你需要选择尽可能多的活动,使得这些活动之间没有时间冲突。 5 | */ 6 | 7 | function activitySelection(activities) { 8 | activities.sort((a, b) => a.end - b.end); 9 | let selected = []; 10 | let lastEnd = -1; 11 | for (let activity of activities) { 12 | if (activity.start >= lastEnd) { 13 | selected.push(activity); 14 | lastEnd = activity.end; 15 | } 16 | } 17 | return selected; 18 | } 19 | 20 | // 测试 21 | const activities = [ 22 | { start: 1, end: 3 }, 23 | { start: 2, end: 4 }, 24 | { start: 3, end: 5 }, 25 | { start: 5, end: 7 }, 26 | { start: 3, end: 8 } 27 | ]; 28 | const result = activitySelection(activities); 29 | console.log(result); -------------------------------------------------------------------------------- /docs/public/demos/js/algorithm/sort/insert-sort.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 插入排序 3 | * 4 | * 1. 从第一个元素开始,可以认为已被排序 5 | * 2. 取出下一个元素,在已排序的元素序列中从后往前扫描 6 | * 3. 如果该元素(已排序)大于新元素,则将该元素移到下一个位置 7 | * 4. 重复3,直到找到已排序的元素小于或者等于新元素的位置 8 | * 5. 新元素插入到下一个位置中 9 | * 6. 重复步骤2 10 | */ 11 | 12 | function insertSort(els) { 13 | // 从第二个元素开始,即i=1 14 | for (let i = 1; i < els.length; i++) { 15 | // 后一个小于前一个,当前的值小于前面的 16 | if (els[i] < els[i - 1]) { 17 | const currentItem = els[i]; 18 | let j = i - 1; 19 | els[i] = els[j]; // 把前面的值给当前的 20 | // 比大小,找到被插入元素所在的位置 21 | while (j >= 0 && currentItem < els[j]) { 22 | els[j + 1] = els[j]; 23 | j--; 24 | } 25 | els[j + 1] = currentItem; 26 | } 27 | } 28 | return els; 29 | } 30 | 31 | const arr = [12, 12, 15, 445, 451, 12, 123456, 61, 20, 136, 4856, 1, 0]; 32 | 33 | console.log(insertSort(arr)); 34 | -------------------------------------------------------------------------------- /docs/public/demos/js/algorithm/normal/dynamic-knapsack.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 动态规划(Dynamic Programming,DP)是一种通过把原问题分解为相对简单的子问题, 3 | * 并保存子问题的解来避免重复计算,从而解决复杂问题的算法策略。 4 | * 5 | * 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? 6 | */ 7 | 8 | function knapsack(capacity, weights, values) { 9 | let n = weights.length; 10 | let dp = new Array(n + 1).fill(0).map(() => new Array(capacity + 1).fill(0)); 11 | 12 | for (let i = 1; i <= n; i++) { 13 | for (let w = 0; w <= capacity; w++) { 14 | if (weights[i - 1] > w) { 15 | dp[i][w] = dp[i - 1][w]; 16 | } else { 17 | dp[i][w] = Math.max(dp[i - 1][w], dp[i - 1][w - weights[i - 1]] + values[i - 1]); 18 | } 19 | } 20 | } 21 | return dp[n][capacity]; 22 | } 23 | 24 | // 测试 25 | let capacity = 5; 26 | let weights = [2, 3, 4, 5]; 27 | let values = [3, 4, 5, 6]; 28 | console.log(knapsack(capacity, weights, values)); 29 | -------------------------------------------------------------------------------- /scripts/readme-rename-index.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | 4 | function renameReadmeToIndexSync(directory) { 5 | const files = fs.readdirSync(directory, { withFileTypes: true }); 6 | 7 | files.forEach((file) => { 8 | const fullPath = path.join(directory, file.name); 9 | 10 | if (file.isDirectory()) { 11 | renameReadmeToIndexSync(fullPath); 12 | } else if (file.isFile() && file.name.toLowerCase() === 'readme.md') { 13 | const newPath = path.join(directory, 'index.md'); 14 | 15 | try { 16 | fs.renameSync(fullPath, newPath); 17 | console.log(`Renamed: ${fullPath} -> ${newPath}`); 18 | } catch (err) { 19 | console.error(`Error renaming ${fullPath} to ${newPath}:`, err); 20 | } 21 | } 22 | }); 23 | } 24 | 25 | // 使用示例 26 | const targetDirectory = './docs'; 27 | renameReadmeToIndexSync(targetDirectory); 28 | -------------------------------------------------------------------------------- /docs/frontend/v8/garbage.md: -------------------------------------------------------------------------------- 1 | --- 2 | mermaidTheme: forest 3 | --- 4 | 5 | # V8 垃圾回收机制 6 | 7 | ## keyword 8 | 9 | - `堆` 10 | - `栈` 11 | - `基本类型` 12 | - `引用类型` 13 | - `新生代` 14 | - `老生代` 15 | - `生存时间长` 16 | - `生存时间短` 17 | - `Scavenge` 18 | - `Mark sweep & Mark Compact` 19 | - `from-space` 20 | - `to-space` 21 | - `root set` 22 | - `对象可达性` 23 | - `标记阶段` 24 | - `清理阶段` 25 | - `内存碎片` 26 | - `全停顿` 27 | - `Stop The World` 28 | - `Orinoco` 29 | - `Incremental marking` 30 | - `增量标记` 31 | - `lazy sweeping` 32 | - `懒性清理` 33 | - `Concurrent` 34 | - `并发` 35 | - `并行` 36 | - `Parallel` 37 | - `副垃圾回收器` 38 | - `主垃圾回收器` 39 | - `` 40 | 41 | ## 引用 42 | 43 | - [深入理解 Chrome V8 垃圾回收机制](https://juejin.cn/post/6876638765025067015) 44 | 45 | ## 基本类型和引用类型在内存中 46 | 47 | 48 | 49 | ```txt 50 | +------------+ +--------------+ 51 | | 栈 | ---- | 堆 | 52 | +------------+ +--------------+ 53 | ``` 54 | -------------------------------------------------------------------------------- /docs/public/demos/js/simulate/myDebounce.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @desc 无论多少次都是用最后一次 3 | * 4 | */ 5 | function debounce(fn, wait = 50) { 6 | let timer = null; 7 | return function (...args) { 8 | if (timer) clearTimeout(timer); 9 | timer = setTimeout(() => { 10 | fn.apply(this, args); 11 | }, wait); 12 | }; 13 | } 14 | 15 | const betterFn = debounce(() => { 16 | console.log('go to ==>'); 17 | }, 200); 18 | 19 | // document.addEventListener('scroll', betterFn); 20 | 21 | /** ***************** */ 22 | 23 | function myDebounce(fn, wait = 50) { 24 | let timer = null; 25 | 26 | debugger 27 | return (...args) => { 28 | debugger 29 | console.log('hah=>', args); 30 | if (timer) clearTimeout(timer); 31 | timer = setTimeout(() => { 32 | fn.apply(this, args); 33 | }, wait); 34 | }; 35 | } 36 | 37 | const betterFn1 = myDebounce(() => { 38 | console.log('go to ==>'); 39 | }, 200); 40 | 41 | betterFn1(111,222) -------------------------------------------------------------------------------- /docs/public/demos/js/algorithm/normal/divide-quick-sort.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 分治算法(Divide and Conquer Algorithm)是一种常用的算法策略, 3 | * 它将一个复杂的问题分解成多个规模较小、相互独立且形式相同的子问题, 4 | * 然后分别解决这些子问题,最后将子问题的解合并起来得到原问题的解。 5 | * 6 | * 快速排序也是基于分治思想,通过选择一个基准元素,将数组分为两部分,使得左边部分的元素都小于等于基准元素,右边部分的元素都大于等于基准元素,然后分别对左右两部分进行排序。 7 | */ 8 | 9 | function quickSort(arr) { 10 | if (arr.length <= 1) { 11 | return arr; 12 | } 13 | 14 | // 选择基准元素 15 | const pivot = arr[Math.floor(arr.length / 2)]; 16 | const left = []; 17 | const right = []; 18 | const equal = []; 19 | 20 | for (let num of arr) { 21 | if (num < pivot) { 22 | left.push(num); 23 | } else if (num > pivot) { 24 | right.push(num); 25 | } else { 26 | equal.push(num); 27 | } 28 | } 29 | 30 | return [...quickSort(left),...equal,...quickSort(right)]; 31 | } 32 | 33 | // 测试 34 | const array2 = [38, 27, 43, 3, 9, 82, 10]; 35 | console.log(quickSort(array2)); -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: deploy status 2 | on: 3 | push: 4 | branches: 5 | - master 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | 11 | strategy: 12 | matrix: 13 | node-version: [20.x] 14 | 15 | steps: 16 | - uses: actions/checkout@v1 17 | - name: 步骤:第一步 -> 设置环境 18 | uses: actions/setup-node@v1 19 | with: 20 | node-version: ${{ matrix.node-version }} 21 | 22 | - name: 步骤:第二步 -> 安装依赖 23 | run: | 24 | npm install 25 | npm run build 26 | env: 27 | CI: true 28 | 29 | - name: 步骤:第三步 -> 部署脚本 30 | env: 31 | ACCESS_TOKEN_DEPLOY: ${{secrets.ACTIONS_ACCESS_TOKEN_WEB_CI }} 32 | PUBLISH_BRANCH: gh-pages 33 | PUBLISH_DIR: ./docs/.vitepress/dist 34 | CNAME: web.veaba.me 35 | run: | 36 | chmod +x ./scripts/deploy.sh 37 | bash ./scripts/deploy.sh 38 | -------------------------------------------------------------------------------- /docs/public/demos/js/simulate/myInstanceOf.js: -------------------------------------------------------------------------------- 1 | /* 2 | 当使用 a instanceof b 时,JavaScript 引擎会按照以下步骤进行判断: 3 | 首先获取 a 的原型,即 a.__proto__。 4 | 然后获取 b 的原型属性,即 b.prototype。 5 | 接着检查 a.__proto__ 是否与 b.prototype 相等。如果相等,则 a instanceof b 返回 true。 6 | 如果不相等,就继续沿着 a 的原型链向上查找,即检查 a.__proto__.__proto__ 是否与 b.prototype 相等,以此类推 7 | 直到找到相等的情况或者到达原型链的顶端(null)。如果到达原型链顶端仍未找到相等的情况,则 a instanceof b 返回 false。 8 | */ 9 | function myInstanceOf(a, b) { 10 | let proto = Object.getPrototypeOf(a); 11 | let prototype = b.prototype; 12 | 13 | while (true) { 14 | debugger 15 | if (proto === null) { 16 | return false; 17 | } 18 | if (proto === prototype) { 19 | return true; 20 | } 21 | debugger 22 | proto = Object.getPrototypeOf(proto); 23 | } 24 | } 25 | 26 | // 测试 27 | let arr = []; 28 | // console.log(myInstanceOf(arr, Array)); // true 29 | // console.log(myInstanceOf(arr, Object)); // true 30 | console.log(myInstanceOf(arr, Function)); // false 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # web advanced 2 | 3 | > 进阶 web 高级前端知识体系:来自个人的面试经历、学习笔记、参考大神们的 blog,以及常见面试题!不代表内容的正确性!!!!有一部分还在带着问号!以下内容是随手记下的笔记,还在学习..。 by@veaba 4 | 5 | --- 6 | 7 | ![deploy](https://github.com/veaba/web-advanced/actions/workflows/deploy.yml/badge.svg) 8 | 9 | 使用 Vuepress 重新构建静态网站,舒爽体验阅读,请访问:https://web.veaba.me 10 | 11 | > 本项目使用 vuepress-actions 构建,详情请查看:,仅支持 vuepress 1.x 12 | 13 | 部分内容尚未补充完成!! 14 | 15 | - [interview-rspress](https://github.com/veaba/interview-rspress) private 16 | 17 | ## todo 翻译工具 18 | 19 | - 开发工具,同步官方数据-todo 20 | - 一些 api 21 | - 自动生成 node 最新版文档目录 22 | - copy 一份后,自动翻译 23 | - 参考以前的 Tensorflow-docs 项目 24 | - 使用 vuepress 自带的在本页面生成目录在文章前面 25 | - 扫描未翻译的段落、同步更新请求操作 26 | 27 | ## 写作 28 | 29 | ### 使用 vitepress-script-preview 插件 30 | 31 | ```shell 32 | 33 | ::: script-preview 34 | console.log('hello world') 35 | ::: 36 | 37 | ``` -------------------------------------------------------------------------------- /docs/framework/vue/parser-vue.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | 5 | # 解析 Vue.js 文件 6 | 7 | ## config 8 | 9 | ### optionMergeStrategies 10 | 11 | `Object.create(null)` 12 | 13 | ### silent 14 | 15 | 是否警告 16 | 17 | ### productionTip 18 | 19 | 开发环境提示 20 | 21 | ### devtools 22 | 23 | 是否启动 devtools 工具 24 | 25 | ### performance 26 | 27 | 是否记录性能 28 | 29 | ### errorHandler 30 | 31 | 错误处理程序中的错误 32 | 33 | ### warnHandler 34 | 35 | 警告处理程序观察家警告说 36 | 37 | ### ignoreElements 38 | 39 | 忽略某些自定义元素 40 | 41 | ### keyCodes 42 | 43 | 用户自定有 v-on 的别名 44 | 45 | ### isReservedTag 46 | 47 | 检查是否是保留的 tag,以便不能注册为组件,可能被覆盖 48 | 49 | ### isReservedAttr 50 | 51 | 可能被覆盖,检查一个属性是否保留,以便它不能作为一个组件 52 | 53 | ### isUnknownElement 54 | 55 | 未知的元素 56 | 57 | ### getTagNamespace 58 | 59 | 获取元素的命名空间 60 | 61 | ### parsePlatformTagName 62 | 63 | 解析为特定平台真正的标签名称。 64 | 65 | ### mustUseProp 66 | 67 | 检查是否必须值,与平台相关 68 | 69 | ### \_lifecycleHooks 70 | 71 | 暴露原因遗留 72 | 73 | ## 大量的工具类函数 74 | -------------------------------------------------------------------------------- /docs/javascript/base.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | 5 | # 基础 6 | 7 | JavaScript 是起初是运行在浏览器网页里面的代码,后发展为可以跨平台的编程语言,目前是运行在浏览器、服务器(Node、Deno 8 | 等)里的编程语言,是目前具有最广泛程序员掌握的编程语言。 9 | 10 | 可以开发但不限于,`网页`、`小程序`、`App`、`服务端语言`、`脚本`等等。 11 | 12 | ## 概念 13 | 14 | JavaScript 组成: 15 | 16 | - ECMAScript 语法核心 17 | - DOM 文档模型对象 18 | - BOM 浏览器模型对象 19 | 20 | ## 常见产品 21 | 22 | | 产品类型 | 网站 | 23 | |--------|-------------| 24 | | 社交产品 | | 25 | | 微博 | weibo.com | 26 | | 小红书 | xiaohongshu | 27 | | 搜索引擎产品 | | 28 | | Google | google.com | 29 | | Baidu | baidu.com | 30 | | 混合式场景 | | 31 | | alipay | 部分 | 32 | | 小程序 | 部分 | 33 | 34 | 等等。 35 | 36 | ## 数据类型 37 | 38 | 39 | 40 | ## 上下文 41 | 42 | 43 | 44 | ## 方法 45 | 46 | 47 | 48 | ## 继承 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /docs/public/demos/js/algorithm/sort/counting-sort.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 计数排序 3 | * 1. 该方法使用了一个额外的数组C,这意味着增加了内存空间, 4 | * 2. 第 i 个元素是待排序数组A中值,等于 i 的元素的个数 5 | * 3. 然后根据C数组 来将 A中的元素排到正确的位置 6 | * 4. 只能对整数进行排序 7 | */ 8 | function countingSort(data) { 9 | console.time("counting=>"); 10 | var len = data.length; 11 | var B = []; 12 | var C = []; 13 | var min = (max = data[0]); 14 | 15 | for (let i = 0; i < len; i++) { 16 | min = min <= data[i] ? min : data[i]; 17 | max = max >= data[i] ? max : data[i]; 18 | 19 | C[data[i]] = C[data[i]] ? C[data[i]] + 1 : 1; 20 | } 21 | 22 | 23 | for (let j = min; j < max; j++) { 24 | C[j + 1] = (C[j + 1] || 0) + (C[j] || 0); 25 | } 26 | 27 | for (let k = len - 1; k >= 0; k--) { 28 | debugger 29 | B[C[data[k]] - 1] = data[k]; 30 | C[data[k]]--; 31 | } 32 | console.timeEnd("counting=>"); 33 | return B 34 | } 35 | 36 | 37 | var arr = [9, 8, 6, 4, 5, 3, 2]; 38 | 39 | console.log("===>", countingSort(arr)); 40 | -------------------------------------------------------------------------------- /docs/public/demos/html/debug-sort.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 8 | 9 | 33 | 34 | -------------------------------------------------------------------------------- /docs/public/demos/js/document.js: -------------------------------------------------------------------------------- 1 | //document.close() 2 | function createDoc(){ 3 | var doc=document.open("text/html","replace"); 4 | var txt="学习 HTML DOM 很有趣!"; 5 | doc.write(txt); 6 | doc.close(); 7 | } 8 | 9 | // replaceChild() 10 | function replaceChild(){ 11 | var textnode=document.createTextNode("Water"); 12 | var item=document.getElementById("myList").childNodes[0]; 13 | item.replaceChild(textnode,item.childNodes[0]); 14 | } 15 | 16 | // appendChild 17 | function appendChild (){ 18 | var node=document.createElement("LI"); 19 | var textnode=document.createTextNode("Water"); 20 | node.appendChild(textnode); 21 | document.getElementById("myList").appendChild(node); 22 | } 23 | 24 | // insertBefore 25 | 26 | function insertBefore(){ 27 | var a=document.createElement('a'); 28 | a.href='sb'; 29 | a.textContent='sbsbsbbs' 30 | var sping= document.querySelector('li:nth-child(4)') 31 | document.querySelector('ul').insertBefore(a,sping) 32 | } -------------------------------------------------------------------------------- /docs/javascript/context/call.md: -------------------------------------------------------------------------------- 1 | # Call 函数 2 | 3 | ## 说明 4 | 5 | ::: tip 6 | call 会立即执行。 7 | ::: 8 | 9 | ## 特性 10 | 11 | - 入参是一个 `(a,b,c)` 的列表形式,记忆方式, `C` 类似括号 `(`。 12 | - `call` 的第一个参数就是 `this` 所要指向的那个对象,后面的参数则是函数调用时所需的参数。 13 | - 应用:调用对象的原生方法 14 | 15 | ```js 16 | var obj = {}; 17 | obj.hasOwnProperty('toString'); // false 18 | 19 | // 覆盖掉继承的 hasOwnProperty 方法 20 | obj.hasOwnProperty = function () { 21 | return true; 22 | }; 23 | obj.hasOwnProperty('toString'); // true 24 | 25 | Object.prototype.hasOwnProperty.call(obj, 'toString'); // false 26 | ``` 27 | 28 | ## call 与 apply 区别 29 | 30 | - call 入参是 `独立参数`,如 `fn("click","touch")` 31 | - apply 入参是 `数组`,如 `fn(["click","touch"])`,否则无法被读取到 32 | 33 | ```js 34 | function github(param1, param2) { 35 | console.info(param1, param2); 36 | } 37 | const repoObject = { repo: 'veaba/web-advanced' }; 38 | const authorObject = { author: 'veaba' }; 39 | fn.apply(null, [authorObject], repoObject); // {author: 'veaba'}, undefined 40 | 41 | fn.apply(null, repoObject, [authorObject]); // undefined undefined 42 | ``` 43 | -------------------------------------------------------------------------------- /docs/public/demos/js/algorithm/sort/merge-sort.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 归并排序,一种稳定的排序方法 3 | * 1. 已有序的子序列合并 4 | * 2. 得到完全有序的序列 5 | * 3. 先让每个子序列有序 6 | * 4. 在让子序列段间有序 7 | * 8 | */ 9 | 10 | function mergeSort(data) { 11 | let len = data.length; 12 | if (len < 2) { 13 | return data; 14 | } 15 | var middle = Math.floor(len / 2); 16 | var left = data.slice(0, middle); 17 | var right = data.slice(middle); 18 | return merge(mergeSort(left), mergeSort(right)); 19 | } 20 | 21 | function merge(left, right) { 22 | var result = []; 23 | console.time("mergeSort=>"); 24 | while (left.length && right.length) { 25 | if (left[0] <= right[0]) { 26 | result.push(left.shift()); 27 | } else { 28 | result.push(right.shift()); 29 | } 30 | } 31 | while (left.length) { 32 | result.push(left.shift()); 33 | } 34 | while (right.length) { 35 | result.push(right.shift()); 36 | } 37 | console.timeEnd("mergeSort=>"); 38 | return result; 39 | } 40 | var arr = [9, 8, 6, 4, 5, 3, 2]; 41 | 42 | console.log("===>", mergeSort(arr)); 43 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/index.ts: -------------------------------------------------------------------------------- 1 | import DefaultTheme from 'vitepress/theme'; 2 | import { h, nextTick } from 'vue'; 3 | import type { Theme } from 'vitepress'; 4 | import Catalog from './components/Catalog.vue'; 5 | import 'vitepress-script-preview/components/style.css'; 6 | import { CodePreview } from 'vitepress-script-preview/components'; 7 | import { createMermaidRenderer } from 'vitepress-mermaid-renderer'; 8 | import 'vitepress-mermaid-renderer/dist/style.css'; 9 | 10 | export default { 11 | extends: DefaultTheme, 12 | Layout() { 13 | return h(DefaultTheme.Layout, null, { 14 | Catalog: () => h(Catalog), 15 | }); 16 | }, 17 | enhanceApp({ app, router }) { 18 | app.component('Catalog', Catalog); 19 | app.component('CodePreview', CodePreview); 20 | 21 | const mermaidRenderer = createMermaidRenderer(); 22 | mermaidRenderer.initialize(); 23 | 24 | if (router) { 25 | router.onAfterRouteChange = () => { 26 | nextTick(() => mermaidRenderer.renderMermaidDiagrams()); 27 | }; 28 | } 29 | }, 30 | } satisfies Theme; 31 | -------------------------------------------------------------------------------- /docs/public/demos/js/deep-copy.js: -------------------------------------------------------------------------------- 1 | /** 2 | * deep copy 3 | * target copy to source 4 | * 1. 假设都是对象 5 | */ 6 | function deepCopy(target) { 7 | let result; 8 | 9 | if (typeof target === "object") { 10 | // 数组 11 | if (Array.isArray(target)) { 12 | // null 13 | } else if (target == null) { 14 | result = null; 15 | 16 | // function 17 | } else if (Object.prototype.toString.call(target) == "[object Function]") { 18 | } else if (Object.prototype.toString.call(target) === "[object Object]") { 19 | result = {}; 20 | 21 | for (let key in target) { 22 | result[key] = deepCopy(target[key]) 23 | } 24 | } 25 | // Date 26 | // RegExp 27 | else { 28 | result = target; 29 | } 30 | // object 31 | } else { 32 | result = target; 33 | } 34 | 35 | return result; 36 | } 37 | 38 | var a = { 39 | a: "a object", 40 | name: "a", 41 | }; 42 | 43 | var b = { 44 | b: "b object", 45 | name: "b", 46 | }; 47 | 48 | const newOne = deepCopy(a); 49 | 50 | console.log("newOne=>", newOne); 51 | -------------------------------------------------------------------------------- /docs/http/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | 5 | # HTTP 协议 6 | 7 | 8 | 9 | 10 | ## REST API 和客户端库的区别 11 | 12 | `来源于一项API服务对比的页面,` 13 | 14 | | 用例 | REST API | 客户端库 | 15 | | -------------------------------------------------------- | -------- | ---------------------- | 16 | | 转换短语音音频,例如无中间结果的命令(音频长度 < 15 秒) | 是 | 是 | 17 | | 转换长音频(> 15 秒) | 否 | 是 | 18 | | 流式传输具有所需中间结果的音频 | 否 | 是 | 19 | | 了解使用 LUIS 从音频转换的文本 | 是 | 是 | 20 | | 是不是 HTTP | 是 | 不一定,比如 WebSocket | 21 | 22 | 23 | ## http 和 https 的比较 24 | 25 | 26 | ## HTTP1.1 和 HTTP2.0 比较 27 | 28 | 1. HTTP2.0 采用二进制格式,而非文本格式 29 | 30 | - 二进制解析更高效 31 | 32 | 2. HTTP2.0 `完全多路复用`,而非有序并阻塞,仅需一个连接即可并行 33 | 34 | - `多路复用是什么意思?` 35 | 36 | 3. 使用报头压缩,HTTP2.0 降低了开销 37 | 38 | 4. HTTP2.0 让服务器可以将响应主动 “推送” 到客户端缓存中 39 | 40 | -------------------------------------------------------------------------------- /docs/public/demos/html/flex-left_center_right-layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 左中右布局 Flex 7 | 27 | 28 | 29 |
30 |
31 | Left 32 |
33 |
34 | Center Flex 35 | 布局是轴线布局,只能指定"项目"针对轴线的位置,可以看作是一维布局。 36 |
37 |
38 | Right 39 |
40 |
41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /docs/public/demos/js/promise-function.js: -------------------------------------------------------------------------------- 1 | /*********************** 2 | * @name JS 3 | * @author veaba 4 | * @date 2018/4/2 5 | ***********************/ 6 | 7 | //P(fn) fn typeof 为function 手写简单的 promise 8 | 9 | // 1 3 4 2 5 10 | function P(fn) { 11 | console.info("P promise"); 12 | var value = null; 13 | var events = []; 14 | this.then = function(f) { 15 | events.push(f); 16 | return this; 17 | }; 18 | function resolve(newValue) { 19 | var f = events.shift(); 20 | f(newValue, resolve); 21 | } 22 | fn(resolve); 23 | } 24 | 25 | function a() { 26 | debugger; 27 | console.info("function a"); 28 | return new P(function(resolve) { 29 | console.log("ge1"); 30 | setTimeout(function() { 31 | console.log("get2"); 32 | resolve(1); 33 | }, 6000); 34 | }); 35 | } 36 | a() 37 | .then(function(value, resolve) { 38 | console.log("get3"); 39 | setTimeout(function() { 40 | console.log("get 4"); 41 | resolve(2); 42 | }, 3000); 43 | }) 44 | .then(function(value, resolve) { 45 | console.log("get 5:" + value); 46 | }); 47 | -------------------------------------------------------------------------------- /docs/public/demos/html/margin-left_center_right-layout-3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 三栏布局,右浮动在 center 元素之前 8 | 39 | 40 | 41 | 42 |
43 |
左边左边左边左边
44 |
右右边右边右边边
45 |
46 | 中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间 47 |
48 |
49 | 50 | 51 | -------------------------------------------------------------------------------- /docs/public/demos/html/margin-left_center_right-layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 38 | 39 | 40 |
41 |
中间
42 |
左边
43 |
右边
44 |
45 | 46 | 47 | -------------------------------------------------------------------------------- /docs/public/demos/js/algorithm/sort/select-sort.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 选择排序 3 | * 4 | * 1. 在未排序的序列中找到最小(大)的元素, 5 | * 2. 存放到排序序列的起始位置 6 | * 3. 再从剩余的未排序元素中继续寻找最小(大) 7 | * 4. 排到已排序序列的末尾 8 | * 9 | */ 10 | 11 | function selectionSort(data) { 12 | console.time("selectionSort"); 13 | const len = data.length; 14 | let minIndex = null; 15 | let temp = null; 16 | for (let i = 0; i < len; i++) { 17 | minIndex = i; 18 | for (let j = i + 1; j < len; j++) { 19 | // 前者比后者 20 | if (arr[j] < arr[minIndex]) { 21 | // 寻找最小值 22 | minIndex = j; // 将最小的索引保存 23 | } 24 | } 25 | // 前后两个交换位置 26 | console.log( 27 | "交换位置的索引是:(", 28 | i, 29 | minIndex + ")======>", 30 | `所对应的值做交换:(${arr[i]},${arr[minIndex]})` 31 | ); 32 | temp = arr[i]; 33 | arr[i] = arr[minIndex]; 34 | // console.log("arr[minIndex]===>", minIndex, arr[minIndex]); 35 | arr[minIndex] = temp; 36 | console.info("此时arr==>", arr); 37 | } 38 | console.timeEnd("selectionSort"); 39 | return arr; 40 | } 41 | 42 | var arr = [9, 8, 6, 4, 5, 3, 2]; 43 | 44 | console.log("===>", selectionSort(arr)); 45 | -------------------------------------------------------------------------------- /docs/public/demos/js/publish-subscribe.js: -------------------------------------------------------------------------------- 1 | // 所有一切都在对象中完成 2 | const eventEmitter = {}; 3 | 4 | // 缓存列表,调度中心 5 | eventEmitter.list = {}; 6 | 7 | // on 方法添加fn 缓存 ==> 订阅者注册事件到调度中心 8 | // 订阅处理 9 | eventEmitter.on = function(eventName, fn) { 10 | eventEmitter.list[eventName] 11 | ? eventEmitter.list[eventName].push(fn) 12 | : (eventEmitter.list[eventName] = [fn]); 13 | 14 | console.log("订阅事件==>list", eventEmitter.list); 15 | }; 16 | 17 | // 发布者发布事件到调度中心,调度中心执行代码 18 | eventEmitter.emit = function(...args) { 19 | console.log("arg=>", args); 20 | const list = eventEmitter.list; 21 | const eventName = args[0]; 22 | const publishContent = args[args.length - 1]; 23 | 24 | if (list[eventName]) { 25 | const fns = list[eventName]; 26 | for (let i = 0; i < fns.length; i++) { 27 | fns[i].call(this, publishContent); 28 | } 29 | } 30 | }; 31 | 32 | // off 取消订阅 33 | eventEmitter.off = function() { 34 | eventEmitter.list = []; 35 | }; 36 | 37 | function user1(content) { 38 | console.log("user1 subscribe=>", content); 39 | } 40 | 41 | // 订阅 42 | 43 | eventEmitter.on("art", user1); 44 | 45 | eventEmitter.emit("art", "ddd"); 46 | -------------------------------------------------------------------------------- /docs/public/demos/proxy.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @desc Proxy 代理 实验 3 | * @todo Proxy第一个参数是干啥的? 4 | * @param 5 | * 6 | */ 7 | 8 | // const targetObj = {}; 9 | // const handler = { 10 | // get: function(target, propKey, receiver) { 11 | // console.log('getting===>',propKey); 12 | // return Reflect.get(target, propKey, receiver); 13 | // }, 14 | // set: function(target, propKey, value, receiver) { 15 | // console.log('setting===>',propKey); 16 | // return Reflect.set(target, propKey, value, receiver); 17 | // /* 18 | // set(target,prop,value){ 19 | // target[prop] = value 20 | 21 | // } 22 | // */ 23 | // }, 24 | // }; 25 | 26 | // const obj = new Proxy(targetObj, handler); 27 | // obj.aa=22 28 | // console.log(obj); 29 | 30 | 31 | /** Handler array */ 32 | const arrayData = [ 33 | {name:"Lee"}, 34 | {name:"Lisa"}, 35 | {name:"rookie"}, 36 | ] 37 | 38 | const proxy = new Proxy(arrayData,{ 39 | get(target,prop){ 40 | return target[prop] 41 | }, 42 | set(target,prop,value){ 43 | target[prop]=value 44 | } 45 | }) 46 | 47 | console.log(arrayData[1]) 48 | console.log(proxy[2]) -------------------------------------------------------------------------------- /docs/public/demos/html/margin-left_center_right-layout-2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 三栏布局,三left浮动,center 在首位 6 | 38 | 39 | 40 |
41 |
中间
42 |
左边
43 |
右边
44 |
45 | 46 | -------------------------------------------------------------------------------- /docs/frontend/es6/arrow.md: -------------------------------------------------------------------------------- 1 | ## 箭头函数 2 | 3 | > 4 | 5 | - 箭头函数 this 是父作用域的 this,不是调用时的 this 6 | - 如何知道当前的父作用域 7 | 8 | - 箭头函数不能作为构造函数,不能使用 new 9 | 10 | - 箭头函数没有 arguments 和 caller、callee 11 | 12 | - 箭头函数通过 call、apply 调用不会改变 this 指向,只会入参 13 | 14 | - 箭头函数没有原型属性 15 | 16 | ```js 17 | const fn = () => { 18 | }; 19 | console.log(fn.prototype); 20 | ``` 21 | 22 | - 箭头函数不能作为 Generator 函数,不能使用 yield 关键字 23 | 24 | - 箭头函数返回对象需要加括号 25 | 26 | - 箭头函数不能在 ES6 class 中声明的方法为实例方法,不是原型方法 27 | 28 | ```js 29 | //demo1 30 | class Super { 31 | sayName() { 32 | //do some thing here 33 | } 34 | } 35 | 36 | //通过Super.prototype可以访问到sayName方法,这种形式定义的方法,都是定义在prototype上 37 | var a = new Super(); 38 | var b = new Super(); 39 | a.sayName === b.sayName; //true 40 | //所有实例化之后的对象共享 prototype 上的sayName方法 41 | 42 | //demo2 43 | class Super { 44 | sayName = () => { 45 | //do some thing here 46 | }; 47 | } 48 | 49 | //通过Super.prototype访问不到sayName方法,该方法没有定义在prototype上 50 | var a = new Super(); 51 | var b = new Super(); 52 | a.sayName === b.sayName; //false 53 | //实例化之后的对象各自拥有自己的sayName方法,比demo1需要更多的内存空间 54 | ``` 55 | 56 | - 多重箭头函数是高阶函数,相当于内嵌函数,就是闭包函数 57 | -------------------------------------------------------------------------------- /docs/backend/node/index.md: -------------------------------------------------------------------------------- 1 | # Node.js 2 | 3 | - [如何正确的学习 Node.js](https://cnodejs.org/topic/5ab3166be7b166bb7b9eccf7) 4 | - [v14.2.0](https://nodejs.org/dist/latest-v14.x/docs/api/) 5 | 6 | ::: tip 7 | 使用 python 脚本,或者 js 脚本来完成这项爬取+翻译工作 8 | ::: 9 | 10 | ## 目录 (v14.2.0) 11 | 12 | - Assertion Testing 13 | - Async Hooks 14 | - [Buffer]() 15 | - C++ Addons 16 | - C/C++ Addons with N-API 17 | - C++ Embedder API 18 | - Child Processes 19 | - [Cluster]() 20 | - [Command Line Options]() 21 | - [Console]() 22 | - [Crypto]() 23 | - [Debugger]() 24 | - Deprecated APIs 25 | - [DNS]() 26 | - Domain 27 | - [ECMAScript Modules]() 28 | - Errors 29 | - [Events]() 30 | - File System 31 | - Globals 32 | - HTTP 33 | - HTTP/2 34 | - HTTPS 35 | - Inspector 36 | - Internationalization 37 | - [Modules]() 38 | - [Net]() 39 | - [OS]() 40 | - [Path]() 41 | - Performance Hooks 42 | - Policies 43 | - Process 44 | - Punycode 45 | - Query Strings 46 | - Readline 47 | - [REPL]() 48 | - Report 49 | - [Stream]() 50 | - String Decoder 51 | - Timers 52 | - [TLS/SSL]() 53 | - Trace Events 54 | - [TTY]() 55 | - UDP/Datagram 56 | - URL 57 | - Utilities 58 | - [V8]() 59 | - [VM]() 60 | - WASI 61 | - [Worker Threads]() 62 | - [Zlib]() 63 | -------------------------------------------------------------------------------- /docs/public/demos/html/float-left_center_right-layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 左中右布局 7 | 31 | 32 | 33 |
34 |
35 | Left 36 |
37 |
38 | Center 39 | Flex 布局是轴线布局,只能指定"项目"针对轴线的位置,可以看作是一维布局。 40 |
41 |
42 | Right 43 |
44 |
45 | 46 | 47 | -------------------------------------------------------------------------------- /docs/public/demos/js/simulate/myCreate.js: -------------------------------------------------------------------------------- 1 | function myObjectCreate(proto, propertiesObject) { 2 | if (typeof proto!== 'object' && typeof proto!== 'function') { 3 | throw new TypeError('The first argument must be an object or null'); 4 | } 5 | 6 | // 创建一个临时构造函数 7 | function F() {} 8 | 9 | // 将临时构造函数的原型指向 proto 10 | F.prototype = proto; 11 | 12 | // 使用临时构造函数创建新对象 13 | let obj = new F(); 14 | 15 | // 如果提供了 propertiesObject,则为新对象定义属性 16 | if (propertiesObject!== undefined) { 17 | Object.defineProperties(obj, propertiesObject); 18 | } 19 | 20 | // 如果 proto 为 null,则手动设置 obj 的 __proto__ 为 null 21 | if (proto === null) { 22 | Object.setPrototypeOf(obj, null); 23 | } 24 | 25 | return obj; 26 | } 27 | 28 | // 测试 29 | let parent = { 30 | name: 'parent', 31 | sayHello: function () { 32 | console.log('Hello from parent'); 33 | } 34 | }; 35 | 36 | let child = myObjectCreate(parent, { 37 | age: { 38 | value: 10, 39 | writable: true, 40 | enumerable: true, 41 | configurable: true 42 | } 43 | }); 44 | 45 | console.log(child.name); // 输出 'parent' 46 | child.sayHello(); // 输出 'Hello from parent' 47 | console.log(child.age); // 输出 10 -------------------------------------------------------------------------------- /docs/public/demos/html/vue-demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Title 8 | 9 | 10 | 11 |
12 | {{message}} 13 | 14 | 15 | {{title}} 16 | 17 | 18 | 19 |
    20 |
  • {{item.text}}
  • 21 |
22 | 23 | 24 |
{{who}}----
25 |
26 | 27 | 28 | 29 | 30 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /docs/javascript/scoped/index.md: -------------------------------------------------------------------------------- 1 | # 作用域 2 | 3 | ## 几个作用域 4 | 5 | - `函数作用域` 6 | - `全局作用域` 7 | - `暂时性死域`,es6 引入,与 `let`、`const` 关联,创建了块级作用域 8 | 9 | ## 作用域定义 10 | 11 | - 什么叫作用域? 12 | - 怎么改变作用域? 13 | 14 | - `js 没有作用域块`,导致 var 声明时是全局作用域。但如果是 let 声明,情况就不一样。let 让变量有了作用域。 15 | - 可以使用过匿名函数来解决,模仿块级作用域 16 | 17 | > 以下代码让很感到困惑 18 | 19 | ```js 20 | if (1) { 21 | var ha = 'hello,world!'; 22 | } 23 | console.log(ha); //得到多少? 24 | ``` 25 | 26 | > 但如果是 let 开头的话,就不一样了 27 | 28 | ```js 29 | if (1) { 30 | let ha = 'hello world'; 31 | } 32 | console.log(ha); 33 | ``` 34 | 35 | > 这也就是能解释了,为什么当使用 var 声明 for 循环出来后,总是最后一个值的原因 (let 则相反) 36 | 37 | ```js 38 | for (var i = 0; i < 5; i++) {} 39 | console.log(i); 40 | ``` 41 | 42 | ::: tip 43 | 44 | 所以优秀的代码,其实可以这样去避免,更优秀的就是别用 `var` 45 | 46 | ::: 47 | 48 | ```js 49 | for (var i = 0; i < 5; i++) {} 50 | console.log(i); 51 | i = null; 52 | ``` 53 | 54 | ::: tip 55 | 函数内部,相当于一个作用域 56 | ::: 57 | 58 | ```js 59 | /*demo1*/ 60 | const test = function () { 61 | var t = 'hello'; 62 | return t + ',world!'; 63 | }; 64 | test(); 65 | console.log(t); // 66 | 67 | /*demo2*/ 68 | const test2 = function () { 69 | t2 = 'hello'; 70 | return t2 + ',world!'; 71 | }; 72 | test2(); 73 | console.log(t2); //可以访问到 74 | ``` 75 | -------------------------------------------------------------------------------- /docs/public/demos/js/algorithm/sort/heap-sort.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 堆排序 4 | * @TODO 以下代码会引发无限递归 5 | * 1. 利用堆这种数据结构所设计的一种排序算法 6 | * 2. 堆积是近似完全二叉树的结构 7 | * 3. 满足堆积的性质 8 | * 4. 子节点的键值或索引总是 小于(或大于)它的父节点 9 | * 10 | */ 11 | 12 | function heapSort(data){ 13 | console.time('heapSort') 14 | var heapSize = data.length,temp; 15 | 16 | for(let i = Math.floor(heapSize)/2-1;i>=0;i++){ 17 | heapify(data,i,heapSize) 18 | } 19 | 20 | // 堆排序 21 | for (let j=heapSize-1;j<=i;j--){ 22 | temp=data[0] 23 | data[0]=data[j] 24 | data[j]=temp 25 | heapity(data,0,--heapSize) 26 | } 27 | console.timeEnd('heapSort') 28 | return data 29 | } 30 | 31 | function heapify(data,x,len){ 32 | var l = 2*x+1 33 | var r = 2*x+2 34 | largest = x 35 | temp=null 36 | if(ldata[largest]){ 37 | largest=l 38 | } 39 | 40 | if(rdata[largest]){ 41 | largest=r 42 | } 43 | if(largest!=x){ 44 | temp=data[x] 45 | data[x]=data[largest] 46 | data[largest]=temp 47 | heapity(data,largest,len) 48 | } 49 | } 50 | 51 | 52 | var arr = [9, 8, 6, 4, 5, 3, 2]; 53 | 54 | console.log("===>", heapSort(arr)); 55 | -------------------------------------------------------------------------------- /docs/public/demos/js/algorithm/normal/divide-merge-sort.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 分治算法(Divide and Conquer Algorithm)是一种常用的算法策略, 3 | * 它将一个复杂的问题分解成多个规模较小、相互独立且形式相同的子问题, 4 | * 然后分别解决这些子问题,最后将子问题的解合并起来得到原问题的解。 5 | * 6 | * 归并排序是一种典型的分治算法,它将一个数组分成两个子数组,分别对这两个子数组进行排序,然后将排好序的子数组合并成一个有序的数组。 7 | */ 8 | 9 | function mergeSort(arr) { 10 | if (arr.length <= 1) { 11 | return arr; 12 | } 13 | 14 | // 分割数组 15 | const mid = Math.floor(arr.length / 2); 16 | const left = arr.slice(0, mid); 17 | const right = arr.slice(mid); 18 | 19 | // 递归排序子数组 20 | const sortedLeft = mergeSort(left); 21 | const sortedRight = mergeSort(right); 22 | 23 | // 合并两个有序子数组 24 | return merge(sortedLeft, sortedRight); 25 | } 26 | 27 | function merge(left, right) { 28 | let result = []; 29 | let leftIndex = 0; 30 | let rightIndex = 0; 31 | 32 | while (leftIndex < left.length && rightIndex < right.length) { 33 | if (left[leftIndex] < right[rightIndex]) { 34 | result.push(left[leftIndex]); 35 | leftIndex++; 36 | } else { 37 | result.push(right[rightIndex]); 38 | rightIndex++; 39 | } 40 | } 41 | 42 | return result.concat(left.slice(leftIndex)).concat(right.slice(rightIndex)); 43 | } 44 | 45 | // 测试 46 | const array = [38, 27, 43, 3, 9, 82, 10]; 47 | console.log(mergeSort(array)); 48 | -------------------------------------------------------------------------------- /docs/public/demos/html/box-model.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 24 | 25 | 26 |
27 |
28 |
29 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /docs/public/demos/js/simulate/myClass.js: -------------------------------------------------------------------------------- 1 | // 定义一个函数来模拟类 2 | function createClass(constructor, methods, staticMethods) { 3 | // 为构造函数添加原型方法 4 | if (methods) { 5 | Object.keys(methods).forEach((methodName) => { 6 | constructor.prototype[methodName] = methods[methodName]; 7 | }); 8 | } 9 | 10 | // 为构造函数添加静态方法 11 | if (staticMethods) { 12 | Object.keys(staticMethods).forEach((methodName) => { 13 | constructor[methodName] = staticMethods[methodName]; 14 | }); 15 | } 16 | 17 | return constructor; 18 | } 19 | 20 | // 模拟一个类 21 | function Person(name, age) { 22 | this.name = name; 23 | this.age = age; 24 | } 25 | 26 | // 类的实例方法 27 | const personMethods = { 28 | sayHello() { 29 | console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`); 30 | } 31 | }; 32 | 33 | // 类的静态方法 34 | const personStaticMethods = { 35 | fromJSON(json) { 36 | return new Person(json.name, json.age); 37 | } 38 | }; 39 | 40 | // 创建模拟的类 41 | const MyPerson = createClass(Person, personMethods, personStaticMethods); 42 | 43 | // 创建实例 44 | let person = new MyPerson('Alice', 30); 45 | person.sayHello(); // 输出: Hello, my name is Alice and I'm 30 years old. 46 | 47 | // 调用静态方法 48 | let newPerson = MyPerson.fromJSON({ name: 'Bob', age: 25 }); 49 | newPerson.sayHello(); // 输出: Hello, my name is Bob and I'm 25 years old. -------------------------------------------------------------------------------- /docs/public/demos/html/margin-left_center_right-layout-4.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 浮动三栏布局示例 7 | 45 | 46 | 47 | 48 |
49 |
50 |

左侧边栏

51 |

固定宽度200px

52 |
53 | 54 |
55 |

主要内容

56 |

中间栏宽度自适应,会填满剩余空间。

57 |

这是页面的主要内容区域,包含最重要的信息。

58 |
59 | 60 |
61 |

右侧边栏

62 |

固定宽度200px

63 |
64 |
65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /docs/public/demos/html/input.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 29 | 30 | 31 | 32 | 38 |
    39 |
  • 1
  • 40 |
  • 2
  • 41 |
  • 3
  • 42 |
  • 4
  • 43 |
  • 5
  • 44 |
  • 6
  • 45 |
  • 7
  • 46 |
  • 8
  • 47 |
  • 9
  • 48 |
  • 10
  • 49 |
50 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /docs/frontend/security/csrf.md: -------------------------------------------------------------------------------- 1 | # CSRF 2 | 3 | Cross site request forgery (跨站请求伪造)。 4 | 5 | 例如,登录微博账号后,copy 某个 xhr 请求的 `curl`,丢到控制台或是复制所有 cookie 之类的数据丢到 `Postman` 中,这就是跨站请求伪造 (`CSRF`)。 6 | 7 | 第三方引导发出的 `cookie`,称为第三方 `cookie`,可用于 `CSRF` 攻击,还可以用于用户追踪等营销行为 8 | 9 | ## 例子 10 | 11 | 1. facebook 在第三方网站插入一张看不见的图片 12 | 13 | ```html 14 | 15 | ``` 16 | 17 | 这时候访问这个图片,就会带上 cookie,facebook 知道你的 `ip` 等等数据 18 | 19 | ## 原理 20 | 21 | 大多数情况下,被第三方网站或者 `js` 脚本获取到 `cookie`,所以防御的手段之一就是防止 `cookie` 被获取。 22 | 23 | ## 防御 24 | 25 | ### 敏感信息都是用 `POST` 26 | 27 | - 就算是 copy 参数也很多,步骤比 get 还多 28 | - 如果网站存在 `xss` 漏洞,都很费劲 29 | 30 | 比如构造一个 `from` 表单 31 | 32 | ```html 33 |
34 | 35 |
36 | 39 | ``` 40 | 41 | 在 console 执行 script 部分代码,如果有 from,会直接跳到百度 (或许与 Chrome) 设置默认引擎有关系。 42 | 43 | 尝试在 firefox 中打开阮老师 blog,会网页提示:`留言提交失败。原因:Invalid request` 44 | 45 | ### 将 Cookie 设置为 `HttpOnly` 46 | 47 | 对应 header 是:`Set-Cookie: hello=world;httponly` 48 | 49 | - `JavaScript` 脚本将无法读取 `cookie` 信息 50 | 51 | ### 将 Cookie 设置为 `SameHttp` 52 | 53 | ### 增加 token 54 | 55 | 原理:增加攻击者所不能伪造的信息,且不中存在于 `cookie` 中,重点是 `token` 的保密性、随机性。 56 | 57 | - 比如放在 `Token-Csrf: abcdef` 58 | 59 | - token 服务端生成,有一定的有效期 60 | 61 | ::: info 62 | 但这种方式,实际上,也躲不过直接复制信息到 `postman` 63 | ::: 64 | 65 | ### 根据 `referer` 判断 66 | 67 | - 用于验证发起请求是否是合法的网站 68 | -------------------------------------------------------------------------------- /docs/frontend/v8/index.md: -------------------------------------------------------------------------------- 1 | # V8 引擎 2 | 3 | ## 相关链接 4 | 5 | - [v8 官网](https://v8.dev/docs/) 6 | - [Chromium](https://github.com/chromium/chromium) 7 | 8 | ## 文档 9 | 10 | V8 是 Google 的开源高性能 JavaScript 和 WebAssembly 引擎,用 C++编写。它用于 Chrome 和 Node.js 等。 11 | 12 | 此文档旨在针对那些希望在应用程序中使用 `V8` 的 C++开发人员,以及对 V8 的设计和性能感兴趣的人。 13 | 本文档向您介绍了 `V8`,而其余的文档则向您展示了如何在代码中使用 `V8`,并描述了它的一些设计细节,还提供了一组用于测量 `V8` 性能的 JavaScript 基准。 14 | 15 | ## 目录 16 | 17 | - 从源码构建 `V8` 18 | - [`V8` 源码检出](/frontend/v8/source-code) 19 | - [通过 GN 构建](/frontend/v8/build-gn) 20 | - `ARM/Android` 的交叉编译与调试 21 | - `iOS` 交叉编译 22 | - `GUI` 和 `IDE` 安装 23 | - 贡献 24 | - `V8` 公共 `API` 及其稳定性 25 | - 成为 `V8` 的提交者 26 | - 提交者的责任 27 | - Blink web 测试 (也称布局测试) 28 | - 评估代码覆盖率 29 | - 发布进程 30 | - 设计评审指南 31 | - 实现和发布 `JavaScript/WebAssembly` 语言特性 32 | - `WebAssembly` 特性的暂存和装运清单 33 | - 二分查找算法 34 | - 端口处理 35 | - 合并&补丁 36 | - Node.js 整合构建 37 | - 报告安全性 bug 38 | - 在本地运行基准测试 39 | - 测试 40 | - 分流 issues 41 | - 调试 42 | - 用模拟器进行 Arm 调试 43 | - `ARM/Android` 的交叉编译与调试 44 | - 用 `GDB` 调试内置代码 45 | - 通过 `V8` 检查器协议进行调试 46 | - `GDB JIT` 编译接口集成 47 | - 调查内存泄漏 48 | - 堆栈跟踪 API 49 | - 使用 `D8` 50 | - 嵌入 V8 51 | - 嵌入 V8 指南 52 | - 版本号 53 | - 内置函数 54 | - i18n 支持 55 | - 不受信任的代码缓解? 56 | - 高级选项 57 | - 点火开关? 58 | - 发动机? 59 | - 扭矩用户手册? 60 | - 内置写入扭矩 61 | - 编写 CSA 内置 62 | - 添加新的 `WebAssembly` 操作码 63 | - 编写可优化的 JavaScript 64 | - 使用 `V8` 的基于样本的探查器 65 | - 在 `V8` 中剖析 Chromium 66 | - 在 V8 中使用 Linux 性能 67 | - 跟踪 V8 68 | - 使用运行时调用统计信息 69 | -------------------------------------------------------------------------------- /docs/javascript/this.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | 5 | # This 6 | 7 | ## 概念 8 | 9 | - this 总是指向函数的直接调用者 (非间接) 10 | - 有 new 关键字,指 new 出来的那个对象 (构造函数的实例,一般) 11 | - 事件中,指触发这个事件的对象。 12 | - 特殊的。IE 中的 attachEvent 的 this 总是指向全局的 window 13 | - 闭包中 `this` 是 window 对象 14 | - dom 实例,this 指向这个 dom 对象实例 15 | 16 | ## 立即执行函数中的 this 指向问题 17 | 18 | ```js 19 | var obj = { 20 | a: function () { 21 | console.log('this==>', this); 22 | return this.b; 23 | }, 24 | b: 2020, 25 | }; 26 | (function () { 27 | console.log('=======>', typeof arguments[0]()); // 因为这里的this 是windows,windows 没有变量b,所以是undefined 28 | })(obj.a); 29 | ``` 30 | 31 | > this 竟然不是上一个函数对象 32 | 33 | - 自动取得两个特殊的变量 34 | - 内部搜索到 this arguments 时,只会搜索到其活动对象为止,因此 `永远不可能直接访问外部函数的中的两个变量` 35 | 36 | ```js 37 | var name = 'I am window'; 38 | var object = { 39 | name: 'I am object', 40 | getName: function () { 41 | return function () { 42 | console.log(this); 43 | return this.name; 44 | }; 45 | }, 46 | }; 47 | console.log(object.getName()()); //竟然是window!!! 48 | ``` 49 | 50 | > `将外部作用域中的this 对象,保存在一个闭包能够访问到的变量力,就可以让闭包访问到该对象了`!! 51 | 52 | ```js 53 | var name = 'I am window'; 54 | var object = { 55 | name: 'I am object', 56 | getName: function () { 57 | var that = this; 58 | return function () { 59 | console.log(this); 60 | return that.name; 61 | }; 62 | }, 63 | }; 64 | //demo1 65 | var object = { 66 | name: 'I am object', 67 | getName: function () { 68 | return function () { 69 | console.log(this); 70 | return that.name; 71 | }.call(this); //bind 、call 72 | }, 73 | }; 74 | ``` 75 | -------------------------------------------------------------------------------- /docs/public/demos/fib.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * @desc 斐波那契数列 学习,递归函数解析 4 | * 5 | */ 6 | function fib(n){ 7 | if(n<2){ 8 | return 1 9 | } 10 | console.info(fib(n-1)+fib(n-2)); 11 | debugger 12 | return fib(n-1)+fib(n-2) 13 | }; 14 | fib(8) 15 | // 入参 8 16 | ```js 17 | 1 fib(7)+fib(6) 18 | 2 fib(6)+fib(5) + fib(5)+fib(4) 19 | 3 fib(5)+fib(4) + fib(4)+fib(3) + fib(4)+fib(3) + fib(3)+fib(2) 20 | 4 fib(4)+fib(3) + fib(3)+fib(2) + fib(3)+fib(2) + fib(2)+fib(1) + fib(3)+fib(2) + fib(2)+fib(1) + fib(2)+fib(1) + fib(1)+fib(0) 21 | 5 fib(3)+fib(2) + fib(2)+fib(1) + fib(2)+fib(1) + fib(1)+fib(0) + fib(2)+fib(1) + fib(1)+fib(0) + fib(1)+fib(0) + fib(1) + fib(2)+fib(1) + fib(1)+fib(0) + fib(1)+fib(0) + fib(1)+ fib(1)+fib(0) + fib(1) + fib(1) + fib(0) 22 | 6 fib(2)+fib(1) + fib(1)+fib(0) + fib(1)+fib(0) + fib(1) + fib(1)+fib(0) + fib(1) + fib(1)+fib(0) + fib(1)+fib(0) + fib(1) + fib(1)+fib(0) + fib(1)+fib(0) + fib(1) + fib(1)+fib(0) +fib(1) + fib(1)+fib(0) + fib(1)+fib(0) + fib(1)+ fib(1)+fib(0) + fib(1) + fib(1) + fib(0) 23 | 7 fib(1)+fib(0) + fib(1) + fib(1)+fib(0) + fib(1)+fib(0) + fib(1) + fib(1)+fib(0) + fib(1) + fib(1)+fib(0) + fib(1)+fib(0) + fib(1) + fib(1)+fib(0) + fib(1)+fib(0) + fib(1) + fib(1)+fib(0) +fib(1) + fib(1)+fib(0) + fib(1)+fib(0) + fib(1)+ fib(1)+fib(0) + fib(1) + fib(1) + fib(0) 24 | 8 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 25 | 9 去掉空格之后 我们得到一个结果 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1 = 34 26 | ``` -------------------------------------------------------------------------------- /docs/javascript/common-use-api.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | 5 | # 一些常用的 API 6 | 7 | ## document.querySelector API 8 | 9 | > 2018 年 11 月 29 日,在一家面试到这个 API,我清晰的笃定说其实这个 API 是可以像 JQuery 一样使用 css 的选择器的,去选择第四的 li 标签,然后被驳回了,说只能用 document.querySelectorAll 10 | > 但通过测试来看,其实是可以的。 11 | 12 | ```js 13 | document.querySelector('#app > div > ul > li:nth-child(4)'); 14 | /*或者*/ 15 | document.querySelector('li:nth-child(3)'); 16 | ``` 17 | 18 | ## XMLHttpRequest 19 | 20 | 属于 Http API 的一个范畴,使用的时候,需要实例化 XMLHttpRequest 对象 21 | 22 | - 如何发起 http 请求,在通用 js 环境下?步骤如下: 23 | 1. new XMLHttpRequest 一个对象 24 | 2. open 25 | 1. methods 26 | 2. 路径 27 | 28 | ```js 29 | //一段通过纯文本发送请求个服务器 30 | function send() { 31 | var request = new XMLHttpRequst(); 32 | request.open('POST', '/login.php'); //post 数据 33 | request.setRequestHeader('Content-Type', 'text/plain;charset=UTF-8'); 34 | request.send('say hello world'); 35 | } 36 | 37 | // 一段超时的代码 38 | //js权威指南p503 39 | 40 | /*XMLHttpRequest 兼容ie6*/ 41 | 42 | /*如果不存在,判断IE下不支持非标准的xmlHttpRequest*/ 43 | if (window.XMLHttpRequest === undefined) { 44 | window.XMLHttpRequest = function () { 45 | try { 46 | //可用,则返回ActiveX对象的最新版本 47 | return new ActiveXObject('Msxml3.XMLHTTP.6.0'); 48 | } catch (e1) { 49 | try { 50 | // 否则,退回到较旧的版本 51 | return new ActiveXObject('Msxml3.XMLHTTP.3.0'); 52 | } catch (e2) { 53 | //否则,都没有的话,抛出错误 54 | throw new Error('不支持XMLHttpRequest'); 55 | } 56 | } 57 | }; 58 | } 59 | ``` 60 | 61 | - 可以实现上传文件进度的监控,在 js 权威指南/p501 有写道,可以监控 HTTP 上传的进度 62 | - 设置超时 63 | - 同源策略不允许 XMLHttpRequest 进行跨域请求 64 | - withCredentitails boolean 值,该值的存在是为了测试是否支持 CORS@2 特性一种方法 65 | -------------------------------------------------------------------------------- /docs/javascript/object/index.md: -------------------------------------------------------------------------------- 1 | ## js 三大对象 2 | 3 | [SegmentFault 查看更多,作者 Adrain`](https://segmentfault.com/a/1190000011467723) 4 | 5 | ## 本地对象 6 | 7 | - 与宿主无关,独立于宿主环境的 ECMAScript 实现提供的对象 8 | - ECMA-262 定义的类 (引用类型) 9 | - 该类引用类型在运行过程中需要通过 new 创建所需的实例对象 10 | - 包含 `Object`、`Array`、`Date`、`RegExp`、`Function`、`Boolean`、`Number`、`String` 等 11 | 12 | ## 宿主对象 13 | 14 | - 由 ECMAScript 实现的宿主环境提供的对象,包含两个大类,一个是宿主提供,一个是自定义类对象 15 | - 所有非本地对象都是宿主对象 16 | - 嵌入网页的 js 来讲,宿主就是浏览器提供的对象,包括 `window` 和 `Document` 17 | - 所有 DOM 和 BOM 对象都属于宿主对象 18 | 19 | ## 内置对象 20 | 21 | - 与宿主无关,独立于宿主环境的 ECMAScript 实现提供的对象 22 | - ECMAScript 程序开始执行前就存在,本身就是实例化内置对象,无需实例化 23 | - 内置对象是本地对象的子集 24 | - 包含 `Global` 和 `Math` 25 | - ECMAScript 5 中新增了 `JSON` 这个存在于全局的内置对象 26 | 27 | ## 静态方法 28 | 29 | - [more detail](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object) 30 | 31 | | 方法名 | 描述 | 32 | | --------------------------------------- | ---------------------------------------------------- | 33 | | `Object.getPrototypeOf(obj)` | 返回指定对象的原型 | 34 | | `Object.setPrototypeOf(obj, prototype)` | 设置指定对象的原型 | 35 | | `Object.seal(obj)` | 不能添加新属性,也不能删除现有属性,可以修改已有属性 | 36 | | `Object.freeze(obj)` | 冻结对象,比 seal 更严 | 37 | | `Object.isSealed(obj)` | 检查对象是否被密封 | 38 | | `Object.isFrozen(obj)` | 检查对象是否被冻结 | 39 | | | | 40 | -------------------------------------------------------------------------------- /docs/public/demos/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Document 9 | 10 | 11 | 12 | 13 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /docs/javascript/keyword.md: -------------------------------------------------------------------------------- 1 | # 关键字 2 | 3 | - 如果使用关键字 name 声明一个值,只能是 string 类型!!! 4 | 5 | ## 关键字、保留字分类 6 | 7 | - 操作符关键字 8 | - `instanceof` 9 | - `typeof` 10 | - `delete` 11 | - 类型关键字 12 | - 语法关键字 13 | 14 | - `break` 15 | - `do` 16 | - `case` 17 | - `else` 18 | - `new` 19 | - `catch` 20 | - `finally` 21 | - `return` 22 | - `continue` 23 | - `for` 24 | - `switch` 25 | - `while` 26 | - `debugger *` 27 | - `this` 28 | - `with` 设置特定对象中的作用域 29 | - `in` 30 | - `try` 31 | 32 | ```js 33 | const s = 'Hello'; 34 | with (s) { 35 | console.log(length); 36 | } 37 | // with 语句是运行缓慢的代码块,尤其是在已设置了属性值时。大多数情况下,如果可能,最好避免使用它。 38 | ``` 39 | 40 | - `default` 41 | - `if` 42 | - `throw` 43 | 44 | - 声明关键字 45 | 46 | - `function` 47 | - `void` 48 | - `var` 49 | 50 | - 算术操作符 51 | 52 | ### ECMA-262 保留字 53 | 54 | - `abstract` 55 | - `enum` 56 | - `int` 57 | - `short` 58 | - `boolean` 59 | - `export` 60 | - `interface` 61 | - `static` 62 | - `byte` 63 | - `extends` 64 | - `long` 65 | - `super` 66 | - `char` 67 | - `final` 68 | - `native` 69 | - `synchronized` 70 | - `class` 71 | - `float` 72 | - `package` 73 | - `throws` 74 | - `const` 75 | - `goto` 76 | - `private` 77 | - `transient` 78 | - `debugger` 79 | - `implements` 80 | - `protected` 81 | - `volatile` 82 | - `double` 83 | - `import` 84 | - `public` 85 | 86 | ### 第五版非严格模式下缩减为 87 | 88 | - `class` 89 | - `enum` 90 | - `extends` 91 | - `super` 92 | - `const` 93 | - `export` 94 | - `import` 95 | 96 | ### 严格模式下,保留字限制 97 | 98 | - `implements` 99 | - `package` 100 | - `public` 101 | - `interface` 102 | - `private` 103 | - `static` 104 | - `let` 105 | - `protected` 106 | - `yield` 107 | -------------------------------------------------------------------------------- /docs/leetcode/14-longest-common-prefix.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | navbar: auto 4 | --- 5 | 6 | # 14. 最长公共前缀 7 | 8 | 编写一个函数来查找字符串数组中的最长公共前缀。 9 | 10 | 如果不存在公共前缀,返回空字符串 “”。 11 | 12 | 示例 1: 13 | 14 | ```shell 15 | 16 | 输入:strs = ["flower","flow","flight"] 17 | 输出:"fl" 18 | ``` 19 | 20 | 示例 2: 21 | 22 | ```shell 23 | 输入:strs = ["dog","panda","car"] 24 | 输出:"" 25 | ``` 26 | 27 | 解释:输入不存在公共前缀。 28 | 29 | 提示: 30 | 31 | - 1 <= strs.length <= 200 32 | - 0 <= strs[i].length <= 200 33 | - strs[i] 如果非空,则仅由小写英文字母组成 34 | 35 | ## 解题思考 36 | 37 | 1. 必须全部满足 38 | 2. 首先处理边界问题,如果数组为空,则返回空字符串 39 | 3. 在实际例子中,如果先查找最短的字符串作为基准,通常来说是一个安全的做法 40 | 41 | ### 暴力解法 42 | 43 | ```js 44 | /** 45 | * 查找字符串数组中的最长公共前缀 46 | * @param {string[]} strs - 字符串数组 47 | * @return {string} 最长公共前缀 48 | */ 49 | function longestCommonPrefix(strs) { 50 | if (!strs || strs.length === 0) return ''; 51 | 52 | // 以第一个字符串作为基准 53 | let prefix = strs[0]; 54 | 55 | for (let i = 1; i < strs.length; i++) { 56 | // 逐个比较当前字符串与prefix的公共部分 57 | while (strs[i].indexOf(prefix) !== 0) { 58 | // 如果不匹配,则缩短prefix 59 | prefix = prefix.substring(0, prefix.length - 1); 60 | // 如果prefix为空,则直接返回 61 | if (prefix === '') return ''; 62 | } 63 | } 64 | 65 | return prefix; 66 | } 67 | ``` 68 | 69 | ### 最小字符串作为基准 70 | 71 | ```js 72 | function longestCommonPrefixOptimized(strs) { 73 | if (!strs || strs.length === 0) return ''; 74 | 75 | // 找到数组中最短的字符串 76 | let shortest = strs.reduce((min, str) => (str.length < min.length ? str : min), strs[0]); 77 | 78 | // 从最短字符串开始比较 79 | for (let i = 0; i < shortest.length; i++) { 80 | const char = shortest[i]; 81 | for (const str of strs) { 82 | if (str[i] !== char) { 83 | return shortest.substring(0, i); 84 | } 85 | } 86 | } 87 | 88 | return shortest; 89 | } 90 | ``` 91 | -------------------------------------------------------------------------------- /docs/public/demos/tests/promise-class-all.spec.js: -------------------------------------------------------------------------------- 1 | const PromiseClass = require("../html/promise-class-all"); 2 | describe("Promise/then", () => { 3 | it("1. Promise 实例第一个 then是可以执行", () => { 4 | const p = new PromiseClass(function(resolve, reject) { 5 | setTimeout(function() { 6 | resolve("success!", "这个是忽略的参数"); 7 | // resolve("failed!", "这个是忽略的参数"); 8 | }, 2000); 9 | }); 10 | p.then((one) => { 11 | expect(one).to("success!"); 12 | }); 13 | }); 14 | 15 | it("2. Promise 实例第二个 then 的值应该是undefined", () => { 16 | const p = new PromiseClass(function(resolve, reject) { 17 | setTimeout(function() { 18 | resolve("success!", "这个是忽略的参数"); 19 | // resolve("failed!", "这个是忽略的参数"); 20 | }, 2000); 21 | }); 22 | p.then((one) => { 23 | expect(one).to("success!"); 24 | }).then((two) => { 25 | expect(two).toBe(undefined); 26 | }); 27 | }); 28 | it("3. Promise 实例第二个 then 的值应该是 return 到下一个then", () => { 29 | const p = new PromiseClass(function(resolve, reject) { 30 | setTimeout(function() { 31 | resolve("success!", "这个是忽略的参数"); 32 | // resolve("failed!", "这个是忽略的参数"); 33 | }, 2000); 34 | }); 35 | p.then((one) => { 36 | expect(one).to("success!"); 37 | return 1; 38 | }).then((two) => { 39 | expect(two).toBe(1); 40 | }); 41 | }); 42 | 43 | // TODO 44 | it("4. Promise 实例第一个 then 的第二个参数为catch", () => { 45 | const p = new PromiseClass(function(resolve, reject) { 46 | setTimeout(function() { 47 | resolve("success!", "这个是忽略的参数"); 48 | // resolve("failed!", "这个是忽略的参数"); 49 | }, 2000); 50 | }); 51 | p.then((one) => { 52 | expect(one).to("success!"); 53 | return 1; 54 | }).then((two) => { 55 | expect(two).toBe(1); 56 | }); 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /docs/frontend/security/cookie.md: -------------------------------------------------------------------------------- 1 | # Cookie 2 | 3 | 有关 Cookie 安全的问题 4 | 5 | 有关 [SameSite](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Set-Cookie/SameSite) 问题 6 | 7 | ## SameSite 8 | 9 | 三个属性: 10 | 11 | - `Strict` (严格) 12 | 13 | - `Lax` (松懈) 14 | 15 | - `None` (无) 16 | 17 | ### `Strict` 18 | 19 | 将完全禁止第三方 `Cookie`,跨站点时候,不会发送 `Cookie`,只有当前网页 URL 与请求目标一致时才会带上 `Cookie`。 20 | 21 | 也就是 **`同站检查`** 的意思。 22 | 23 | ```shell 24 | Set-cookie:CookieName=CookieValue; SameSite=Strict 25 | ``` 26 | 27 | 这个 `Strict` 过于严格,导致很多子链接跳转都被不带 `cookie` 28 | 29 | ### `Lax` 30 | 31 | 大多数是否,不发送第三方 `Cookie`,除了导航到目标网站的 `Get` 请求。 32 | 33 | ```shell 34 | Set-cookie: CName=CValue; SameSite=Lax 35 | ``` 36 | 37 | 导航到目标的 `Get` 请求,有三种情况,a 链接,预加载,get 表单。 38 | 39 | | 请求类型 | 实例 | 正常情况 | Lax | 40 | | ---------- | ------------------------------------------ | -------- | -------- | 41 | | a 标签连接 | `...` | 发送 | 发送 | 42 | | 预加载 | `/` | 发送 | 发送 | 43 | | GET 表单 | `from method="GET" actions="">...` | 发送 | 发送 | 44 | | POST 表单 | `from method="POST" actions="">...` | 发送 | 不发送 | 45 | | iframe | `` | 发送 | 不发送 | 46 | | AJAX | `$.get(...)` | 发送 | 不发送 | 47 | | Image | ` 首先,这次面试印象很浅,其次对方需求,说不上来,怎么讲,就是有点鄙视对方的意思。有些术语,问到的,看出来对方不严谨。但部分面试题,还是可以学习的 8 | 9 | ## CommonJS AMD CMD 10 | 11 | 12 | 13 | ## 前端工程化 14 | 15 | - 模块化 16 | - `js` 模块化:CommonJS/AMD/CMD/es6 module 17 | - `css` 模块化:Sass/Less/Stylus/css module 3.资源模块化:JS 管理文件关系 18 | 19 | - 组件化 20 | - UI 组件 21 | - 业务组件 22 | 23 | - 规范化 24 | - 编码规范。 25 | - 联调规范。 26 | - 文件命名。 27 | - 样式管理规范。 28 | - git 规范 29 | - code review 30 | 31 | - 自动化 32 | - webpack 33 | - Jenkins 34 | 35 | ## 前端自动化 36 | 37 | ## vue/的生命周期 38 | 39 | ## vue/props 是怎么实现的?跨域 40 | 41 | ## 如何处理文件上传的进度条 42 | 43 | ## 从零开始构建项目 44 | 45 | ## webpack 了解 46 | 47 | ## node.js 的 stream 流? 48 | 49 | ## 跨域 50 | 51 | ## http/https/http2.0 52 | 53 | > 用 node.js 启动 https 服务 54 | 55 | ```js 56 | const https = require('https'); 57 | const fs = require('fs'); 58 | 59 | const options = { 60 | key: fs.readFileSync('test/fixtures/keys/agent2-key.pem'), 61 | cert: fs.readFileSync('test/fixtures/keys/agent2-cert.pem'), 62 | }; 63 | 64 | https 65 | .createServer(options, (req, res) => { 66 | res.writeHead(200); 67 | res.end('hello world\n'); 68 | }) 69 | .listen(8000); 70 | ``` 71 | 72 | > 用 node.js 启动 http2 服务 73 | 74 | ```js 75 | const http2 = require('http2'); 76 | const fs = require('fs'); 77 | const server = http2.createSecureServer({ 78 | key: fs.readFileSync('./localhost-private-key.pem'), 79 | cert: fs.readFileSync('./localhost-cert.pem'), 80 | }); 81 | server.on('error', (err) => console.error(err)); 82 | 83 | server.on('stream', (stream, headers) => { 84 | // stream is a Duplex 85 | stream.respond({ 86 | 'content-type': 'text/html', 87 | ':status': 200, 88 | }); 89 | stream.end('

Hello world

'); 90 | }); 91 | 92 | server.listen(8443); 93 | ``` 94 | 95 | ## 普通函数和构造函数的区别 96 | 97 | ## web 前端安全和常见的 web 安全问题 98 | -------------------------------------------------------------------------------- /scripts/deploy.sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | # 基于Github Actions 前端部署脚本 3 | set -e 4 | # 检查Actions目录配置 5 | if [ -z "${PUBLISH_DIR}" ]; then 6 | echo "【致命错误】:workflows尚未设置 PUBLISH_DIR" 7 | exit 1 8 | fi 9 | 10 | # 检查设置的目录是否存在,不存在直接退出 11 | if [ -d "$(pwd)${PUBLISH_DIR}" ]; then 12 | echo "【致命错误】:PUBLISH_DIR 尚未生成" 13 | exit 1 14 | fi 15 | 16 | # 检查要发布的分支名称 17 | if [ -z "${PUBLISH_BRANCH}" ]; then 18 | print_error "【致命错误】:没有发现 PUBLISH_BRANCH" 19 | exit 1 20 | fi 21 | 22 | # 进入到build的目录 23 | cd "${PUBLISH_DIR}" # dist 24 | 25 | # 为gh-pages 生成CNAME,发现使用别人提供的脚本,生成的竟然是小写的CNAME文件,所以改为小写的,使用脚本写入 26 | 27 | # 设置CNAME 28 | if [ -n "${CNAME}" ]; then 29 | echo "${CNAME}">CNAME 30 | fi 31 | 32 | # 格式化的输出 33 | function print_error() { 34 | echo -e "\e[31mERROR: ${1}\e[m" 35 | } 36 | 37 | function print_info() { 38 | echo -e "\e[36mINFO: ${1}\e[m" 39 | } 40 | 41 | # 配置仓库地址 42 | if [ -n "${EXTERNAL_REPOSITORY}" ]; then 43 | PUBLISH_REPOSITORY=${EXTERNAL_REPOSITORY} 44 | else 45 | PUBLISH_REPOSITORY=${GITHUB_REPOSITORY} 46 | fi 47 | 48 | # 配置ssh 49 | if [ -n "${ACCESS_TOKEN_DEPLOY}" ]; then 50 | echo "设置 ACCESS_TOKEN_DEPLOY" 51 | SSH_DIR="${HOME}/.ssh" 52 | mkdir "${SSH_DIR}" 53 | ssh-keyscan -t rsa github.com >"${SSH_DIR}/known_hosts" 54 | echo "${ACCESS_TOKEN_DEPLOY}" >"${SSH_DIR}/id_rsa" 55 | chmod 400 "${SSH_DIR}/id_rsa" 56 | remote_repo="git@github.com:${PUBLISH_REPOSITORY}.git" 57 | fi 58 | 59 | # 跳过配置personal_token 和 github_token 60 | remote_branch="${PUBLISH_BRANCH}" 61 | 62 | # 配置git 63 | git init 64 | git checkout --orphan "${remote_branch}" # 积累无数次commit,不算分支 65 | 66 | git config user.name "${GITHUB_ACTOR}" 67 | git config user.email "${GITHUB_ACTOR}@users.noreply.github.com" 68 | 69 | git remote rm origin || true 70 | git remote add origin "${remote_repo}" 71 | 72 | # 更改时间 73 | cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime 74 | 75 | # git提交 76 | git add . 77 | push_time="$(date '+%Y-%m-%d %H:%M:%S')" 78 | git commit -m "【部署成功】:${push_time}" 79 | 80 | git push origin -f "${PUBLISH_BRANCH}" 81 | 82 | print_info "${GITHUB_SHA} 漂亮!部署成功: ${push_time}" 83 | -------------------------------------------------------------------------------- /docs/backend/nginx/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | 5 | # Nginx 6 | 7 | > https://blog.csdn.net/tsummerb/article/details/79248015 对 nginx 正向、反向带来写的比较好的文章 8 | 9 | ## nginx 的正向代理? 10 | 11 | > 我忘记是 2018 年在哪一家公司面试了,面试官问我,你知道什么是 nginx 正向代理?我楞了下,说不知道,后面想一直知道这个知识点。直到我直到这个知识点后,傻楞了,我一个前端知道个锤子 nginx 正向代理啊,我去!算了,本着学习的心态,不想回忆起这个沙雕面试官了。 12 | 13 | - 正向代理最大的特点是客户端非常明确要访问的服务器地址;服务器只清楚请求来自哪个代理服务器,而不清楚来自哪个具体的客户端;正向代理模式屏蔽或者隐藏了真实客户端信息。 14 | - 内网服务主动要求请求外网的地址服务,内网服务->访问->外网。((⊙_⊙)?,所以我 ssh 到服务器 curl 百度,也算了) 15 | - (`应该可以本来按着a 页面返回给用户,结果我让百度页面返回给用户?恩?`) 16 | - 以通过代理软件访问 facebook 这样的例子,比较形象 17 | 18 | ```txt 19 | server{ 20 | resolver 8.8.8.8 21 | } 22 | ``` 23 | 24 | ## nginx 的反向代理? 25 | 26 | - proxy_pass 27 | - upstream 28 | - 外网主动请求内网服务,外网->请求->内网服务 29 | - 请求的来源也就是客户端是明确的,但是请求具体由哪台服务器处理的并不明确了,nginx 扮演的就是一个反向代理角色 30 | - 用户去访问淘宝,但返回给用户的内容的服务器,可能来自浙江,可能来自北京 31 | 32 | ## nginx 负载均衡 33 | 34 | - 硬件负载均衡 35 | - 软件负载均衡 36 | 37 | > 与硬件主机实现一种消息队列分发机智 38 | 39 | - 负载均衡调度算法 40 | - weight 轮询 41 | > 皇帝翻牌子比较形象了!可以设定一些权重,来增加获得宠幸的几率,被打入冷宫的 out 出局。。。 42 | - ip_hash 43 | > 客户端 ip 的 hash 匹配,一个固定 ip 从会访问到同一个后端,一定程度解决了集群下,session 共享问题 44 | - fair 45 | > 智能调整算法调度?动态的根据后端服务器的请求处理处理的响应时间,进行均衡的分配,响应时间短的,分配到的几率高,长的,分配的少!需要安装 upstream_fair 模块 46 | - url_hash 47 | > 根据 url+hash 结果,每次请求的 url 都指定到后端固定服务器,nginx 作为静态服务器下,提高缓存效率。需要安装 hash 软件包 48 | 49 | ## 一段基于 vue 项目 nginx 配置文件 50 | 51 | ```txt 52 | { 53 | worker_processes 1; 54 | events { 55 | worker_connections 1024; 56 | } 57 | http { 58 | include mime.types; 59 | default_type application/octet-stream; 60 | sendfile on; 61 | keepalive_timeout 65; 62 | server { 63 | listen 80; 64 | server_name localhost; 65 | 66 | location / { 67 | root F:\baidu\dist; 68 | try_files $uri $uri/ @router; 69 | index index.html; 70 | } 71 | 72 | location @router { 73 | rewrite ^.*$ /index.html last; 74 | } 75 | location ^~/api/{ 76 | proxy_pass http://www.baidu.com/; 77 | } 78 | } 79 | } 80 | } 81 | 82 | ``` 83 | 84 | ## 一段基于 nuxt 项目的 nginx 配置文件 85 | -------------------------------------------------------------------------------- /docs/javascript/context/apply.md: -------------------------------------------------------------------------------- 1 | # Apply 函数 2 | 3 | ## 说明 4 | 5 | ::: tip 6 | apply 会立即执行。 7 | ::: 8 | 9 | ## 特性 10 | 11 | - 最多入参 `65536` 个参数,即 `2^16` 12 | - 假如数组的长度很长。切块后循环传入目标方法 13 | 14 | ## 数组添加到另一个数组 15 | 16 | - 数组 `list1`,数组 `list2` 17 | - `list1` 里面含有 `list2` 的元素,`list2` 不变 18 | 19 | ```js 20 | const list1 = [1, 3]; 21 | const list2 = [2, 4]; 22 | list1.push.apply(list1, list2); 23 | console.info('list1:', list1); 24 | console.info('list2:', list2); 25 | ``` 26 | 27 | ## 变更入参类型 28 | 29 | ```js 30 | // 最大值 31 | const waitSortedList = [12, 1, 456, 6, 16]; 32 | const max = Math.max.apply(null, waitSortedList); 33 | console.info(max); 34 | 35 | // 最小值 36 | const min = Math.min.apply(null, waitSortedList); 37 | console.info(min); 38 | ``` 39 | 40 | ### 将数组空元素转为 `undefined` 41 | 42 | ```js 43 | const arr = [54654, , 55]; 44 | const result = Array.apply(null, arr); 45 | console.info(result); //[ 54654, undefined, 55 ] 46 | ``` 47 | 48 | 等同于下面几种方式: 49 | 50 | `Array.from()` 实现 51 | 52 | ```js 53 | const arr = [54654, , 55]; 54 | const result = Array.from(arr); 55 | ``` 56 | 57 | `...` 拓展符实现: 58 | 59 | ```js 60 | const arr = [54654, , 55]; 61 | const result = [...arr]; 62 | ``` 63 | 64 | `concat()` 实现: 65 | 66 | ```js 67 | const arr = [54654, , 55]; 68 | const result = [].concat(arr); 69 | ``` 70 | 71 | ## 链接构造器 72 | 73 | ### 转换类数组对象 74 | 75 | ```js 76 | Array.prototype.slice.apply({ 0: 1, length: 1 }); // [1] 77 | Array.prototype.slice.apply({ 0: 1, length: 99 }); // (99) [1, empty × 98] 78 | ``` 79 | 80 | ### 绑定回调函数的对象 81 | 82 | ```js 83 | // TODO 84 | ``` 85 | 86 | ## call 与 apply 区别 87 | 88 | - call 入参是 `独立参数`,如 `fn("click","touch")` 89 | - apply 入参是 `数组`,如 `fn(["click","touch"])`,否则无法被读取到 90 | 91 | ```js 92 | function github(param1, param2) { 93 | console.info(param1, param2); 94 | } 95 | const repoObject = { repo: 'veaba/web-advanced' }; 96 | const authorObject = { author: 'veaba' }; 97 | fn.apply(null, [authorObject], repoObject); // {author: 'veaba'}, undefined 98 | 99 | fn.apply(null, repoObject, [authorObject]); // undefined undefined 100 | ``` 101 | -------------------------------------------------------------------------------- /docs/public/demos/html/waterfall.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 图片瀑布流 7 | 20 | 21 | 22 |
23 | 24 | 62 | 63 | -------------------------------------------------------------------------------- /docs/javascript/useful/throttle.md: -------------------------------------------------------------------------------- 1 | # 节流函数 Throttle 2 | 3 | ## 概念 4 | 5 | - 节省的意思,均匀的执行,固定频率执行 6 | 7 | - 跟水龙头一个概念,开一次,流水,关一次,停水,不管后面来了多少 8 | 9 | - 某个函数一定时间间隔内 (如 3s) 执行一次,在 3s 内无视后来产生的**函数调用请求** 10 | 11 | - 马老师被叫去打闪电五连鞭,3s 内打一次,不管叫多少次,他只能 3s 内打一次 12 | 13 | ## 场景 14 | 15 | 关心执行过程 16 | 17 | 1. window.onresize(),跟防抖一样也可以适用 18 | 19 | 2. `scroll` 场景下,`mousemove()`,跟防抖一样也可以适用 20 | 21 | 3. 上传进度 22 | 23 | 4. input 实时查询,每隔 x s 发送一次请求,服务端是限流 (Rate limit) 24 | 25 | 5. 游戏帧频率 26 | 27 | 6. 高频点击,如抢购 28 | 29 | ## 实现 30 | 31 | ```js 32 | const throttle = (fn, wait = 50) => { 33 | let pre = 0; 34 | 35 | return function (...args) { 36 | let now = new Date(); 37 | if (now - pre > wait) { 38 | pre = now; 39 | fn.apply(this, args); 40 | } 41 | }; 42 | }; 43 | 44 | const betterFn = throttle(() => { 45 | console.log('log'); 46 | }, 1000); 47 | 48 | // 每 10 毫秒执行一次 betterFn 函数,但是只有时间差大于 1000 时才会执行 fn 49 | setInterval(betterFn, 10); 50 | ``` 51 | 52 | 或者方案 2: 53 | 54 | ```js 55 | // 56 | function throttle(f, wait) { 57 | let timer; 58 | return (...args) => { 59 | if (timer) { 60 | return; 61 | } 62 | timer = setTimeout(() => { 63 | f(...args); 64 | timer = null; 65 | }, wait); 66 | }; 67 | } 68 | ``` 69 | 70 | 71 | ## 同时使用 72 | 73 | ### 滚动场景 74 | 75 | ```js 76 | // 示例代码 77 | const handleScroll = () => { 78 | // 节流:限制检查频率 79 | throttle(() => { 80 | // 防抖:当用户停止滚动一段时间后执行 81 | debounce(checkIfReachBottom, 300)(); 82 | }, 200)(); 83 | }; 84 | 85 | window.addEventListener('scroll', handleScroll); 86 | ``` 87 | 88 | ### 实时搜索 89 | 90 | ```js 91 | const fetchSuggestions = () => { 92 | // 节流:限制最小请求间隔为500ms 93 | throttle(() => { 94 | // 防抖:用户停止输入300ms后执行 95 | debounce(actualFetch, 300)(); 96 | }, 500)(); 97 | }; 98 | 99 | searchInput.addEventListener('input', fetchSuggestions); 100 | ``` 101 | 102 | ```js 103 | const handleResize = () => { 104 | throttle(() => { 105 | debounce(calculateLayout, 200)(); 106 | }, 100)(); 107 | }; 108 | 109 | window.addEventListener('resize', handleResize); 110 | ``` 111 | 112 | ### 窗口大小调整 113 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/plugins/vitepress-plugin-mermaid.ts: -------------------------------------------------------------------------------- 1 | // from https://github.com/mermaid-js/mermaid/ 2 | import type { MarkdownRenderer } from 'vitepress'; 3 | 4 | const MermaidExample = (md: MarkdownRenderer) => { 5 | const defaultRenderer = md.renderer.rules.fence; 6 | 7 | if (!defaultRenderer) { 8 | throw new Error('defaultRenderer is undefined'); 9 | } 10 | 11 | md.renderer.rules.fence = (tokens, index, options, env, slf) => { 12 | const token = tokens[index]; 13 | const language = token.info.trim(); 14 | if (language.startsWith('mermaid')) { 15 | const key = index; 16 | return ` 17 | 18 | 23 | 24 | 27 | 28 | `; 29 | } else if (language === 'warning') { 30 | return `

WARNING

${token.content}}

`; 31 | } else if (language === 'note') { 32 | return `

NOTE

${token.content}}

`; 33 | } else if (language === 'regexp') { 34 | // shiki doesn't yet support regexp code blocks, but the javascript 35 | // one still makes RegExes look good 36 | token.info = 'javascript'; 37 | // use trimEnd to move trailing `\n` outside if the JavaScript regex `/` block 38 | token.content = `/${token.content.trimEnd()}/\n`; 39 | return defaultRenderer(tokens, index, options, env, slf); 40 | } else if (language === 'jison') { 41 | return `
42 | 43 | jison 44 |
45 |       ${token.content.replace(//g, '>')}
46 |       
47 |
`; 48 | } 49 | 50 | return defaultRenderer(tokens, index, options, env, slf); 51 | }; 52 | }; 53 | 54 | export default MermaidExample; -------------------------------------------------------------------------------- /docs/javascript/__proto__.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | 5 | # `__proto__` 6 | 7 | ```js 8 | const obj = { 9 | a: 2, 10 | b: 3, 11 | }; 12 | 13 | console.log(obj.__proto__); 14 | ``` 15 | 16 | ::: details 如下: 17 | 18 | ![obj-__proto__](/images/javascript/__proto__/obj-__proto__.png) 19 | 20 | ::: 21 | 22 | ## 获取原型 `[[getPrototypeOf]]` 23 | 24 | - console.log(obj.`__proto__`) 25 | - console.log(Object.getPrototypeOf(obj)) 26 | - console.log(Object.prototype) 27 | 28 | ## 设置原型 `[[setPrototypeOf]]` 29 | 30 | ```js 31 | Object.setPrototypeOf(obj, { c: 22 }); 32 | ``` 33 | 34 | 重新打印: 35 | 36 | ```js 37 | console.log(obj); // { a: 2, b: 3 } 38 | 39 | // 在原型链上,则可以获得 c 属性 40 | console.log(obj.c); // 22 41 | ``` 42 | 43 | ## 获取对象的可拓展性 `[[isExtensible]]` 44 | 45 | ```js 46 | console.log(Object.isExtensible(obj)); // true 47 | 48 | Object.freeze(obj); 49 | console.log(Object.isExtensible(obj)); // false 50 | 51 | // seal 不可修改、不可删除,可复写,可枚举 52 | Object.seal(obj); //封闭对象 53 | obj.c = 999; 54 | console.log(obj); // 此时不会被写入 55 | 56 | // freeze 不可写 只读 57 | ``` 58 | 59 | ## 获取自有属性 `[[getOwnProperty]]` 60 | 61 | - 返回自有属性 62 | 63 | ```js 64 | const obj = { 65 | a: 2, 66 | b: 3, 67 | }; 68 | Object.setPrototypeOf(obj, { c: 22 }); 69 | console.log(Object.getOwnPropertyNames(obj)); // ['a','b'] 70 | ``` 71 | 72 | ## 禁止拓展对象 `[[preventExtensions]]` 73 | 74 | ```js 75 | const obj = { 76 | a: 2, 77 | b: 3, 78 | }; 79 | Object.preventExtensions(obj); // 禁止添加,可删,可改 80 | obj.d = 2; 81 | console.log(obj); 82 | ``` 83 | 84 | ## 拦截对象操作 `[[defineProperty]]` 85 | 86 | ```js 87 | const obj = { 88 | a: 2, 89 | b: 3, 90 | }; 91 | Object.defineProperty(obj); 92 | ``` 93 | 94 | ## 判断是否是自身属性 `[[hasOwnProperty]]` 95 | 96 | ```js 97 | console.log(obj.hasOwnProperty('a')); // 返回布尔值,可用于深拷贝 98 | ``` 99 | 100 | ## [[get]] 101 | 102 | ```js 103 | console.log('c' in obj); // 方法 1 104 | console.log(obj.c); // 方法 2 105 | ``` 106 | 107 | ## [[set]] 108 | 109 | ```js 110 | obj.a = 2; // 方法 1 111 | obj['a'] = 2; // 方法 2 112 | ``` 113 | 114 | ## delete 115 | 116 | ```js 117 | delete obj.a; 118 | ``` 119 | 120 | ## enum 121 | 122 | ```js 123 | for (let k in obj) { 124 | console.log(k); 125 | } 126 | ``` 127 | 128 | ## 获取键集合 `[[ownPropertyKeys]]` 129 | 130 | ```js 131 | Object.keys(obj); 132 | ``` 133 | 134 | ## 声明过程 135 | 136 | ```js 137 | function a() {} 138 | 139 | const a = function () {}; 140 | ``` 141 | 142 | ## new 过程 143 | 144 | ```js 145 | function T {} 146 | const t = new T() 147 | ``` 148 | -------------------------------------------------------------------------------- /docs/algorithm/index.md: -------------------------------------------------------------------------------- 1 | # 算法 2 | 3 | ## 时间复杂度 4 | 5 | **量级**: 6 | 7 | - 常数阶 O(1) 8 | ↓ 9 | - 对数阶 O(logN) 10 | ↓ 11 | - 线性阶 O(n) 12 | ↓ 13 | - 平方阶 O(n2) 14 | ↓ 15 | - 立方阶 O(n3) 16 | ↓ 17 | - K 次方阶 O(n^k) 18 | ↓ 19 | - 指数阶 O(2^n) 20 | ↓ 21 | 22 | 越下面,执行的效率越低。 23 | 24 | ![](/images/time-complex.png) 25 | 26 | **常数节**:时间复杂度只有 O(1) 27 | 28 | ```js 29 | var a = 0; 30 | 31 | var b = 0; 32 | 33 | a++; 34 | 35 | // or 此处的时间复杂度也是 O(n) 常数阶 36 | 37 | function total() { 38 | let sum = 0; 39 | for (let i = 0; i < 100; i++) { 40 | sum++; 41 | } 42 | } 43 | 44 | // O(n2) 45 | 46 | function total() { 47 | let sum = 0; 48 | for (let i = 0; i < 100; i++) { 49 | for (let j = 0; j < 100; j++) { 50 | sum++; 51 | } 52 | } 53 | } 54 | 55 | // 特殊的比较 O(m+n),无法比较n 、m 大小 56 | 57 | function total3(n, m) { 58 | let sum = 0; 59 | for (let i = 0; i < n; i++) { 60 | sum += i; 61 | } 62 | let sum2 = 0; 63 | for (let j = 0; j < m; i++) { 64 | sum2 += i; 65 | } 66 | return sum + sum2; 67 | } 68 | 69 | // 特殊的比较 O(n*m) 70 | function total4(n, m) { 71 | let sumN = 0; 72 | let sumM = 0; 73 | for (let i = 0; i < n; i++) { 74 | sumN += i; 75 | for (let j = 0; j < m; j++) { 76 | sumM += j; 77 | } 78 | } 79 | return sumN * sumM; 80 | } 81 | ``` 82 | 83 | **线性阶 O(n)**: 84 | 85 | **对数阶 O(logN)**: 86 | 87 | ```js 88 | function total() { 89 | let sum = 0; 90 | let i = 1; 91 | while (i <= n) { 92 | sum += 1; 93 | i = i * 2; 94 | } 95 | } 96 | 97 | function total2() { 98 | let sum = 0; 99 | for (let i = 0; i < n; i = i * 2) { 100 | sum += 1; 101 | } 102 | } 103 | ``` 104 | 105 | `2x=n` => `x=log2n`,这两者的时间复杂度为 O(log2n) 106 | 107 | ## 空间复杂度 108 | 109 | 空间复杂度:表示算法的存储空间和数据规模之间的关系 110 | 111 | ```js 112 | // 根据时间复杂度推算,忽略常数量级,每次数组都申请一个空间存储量,此时的空间复杂度为 O(n) 113 | function initArray(n) { 114 | const arr = []; 115 | for (let i = 0; i < n; i++) { 116 | arr[i]; 117 | } 118 | } 119 | ``` 120 | 121 | **0(1) 空间复杂度**: 122 | **O(n) 空间复杂度**: 123 | 124 | ```js 125 | function total(n) { 126 | let sum = 0; 127 | for (let i = 0; i <= n; i++) { 128 | sum += i; 129 | } 130 | return sum; 131 | } 132 | 133 | total(10); //45 134 | ``` 135 | 136 | 时间复杂度:O(n),但是,显然这里的时间复杂度是高了。 137 | 138 | ```js 139 | // 通过调整算法后,时间复杂度仅为 0(1) 140 | function total(n) { 141 | const sum = (n * (n + 1)) / 2; 142 | return n; 143 | } 144 | ``` 145 | 146 | 显然可以比较 `O(n)` > `O(1)`,这是算法的魅力,提高效率。 147 | **O(n2) 空间复杂度**: 148 | -------------------------------------------------------------------------------- /docs/javascript/useful/debounce.md: -------------------------------------------------------------------------------- 1 | # 防抖函数 debounce 2 | 3 | ## 概念 4 | 5 | - 无论触发多少次回调,都只执行最后一次,停止出发后才执行 6 | 7 | - 通俗说,抖掉,等新的一次,重新计算的意思 8 | 9 | - 注意:这里的抖动停止表示你停止了触发这个函数,从这个时间点开始计算,当间隔时间等于你设定时间,才会执行里面的回调函数。 10 | 11 | - 如果你一直在触发这个函数并且两次触发间隔小于设定时间,则一定不会到回调函数那一步。 12 | 13 | - 延滞性,最后一个函数触发后,过指定时间才开始执行 14 | 15 | ## 场景 16 | 17 | “适合停顿后触发的场景”,关心最终结果 18 | 19 | 1. 窗口大小调整 `resize`,窗口大小会频繁触发,可以按照特定时间获取到指定值,节流函数也适用 20 | 21 | 2. 懒加载监听计算 `scroll` 位置,按一定时间频率获取,节流函数也适用 22 | 23 | 3. input 查询,确保只有最后一次的更改有效,实际应用中,需要注意时间间隔的差异,并根据实际情况找出最佳数值 24 | 25 | 4. 防止按钮重复点击,短时间只允许提交一次,防止重复提交 26 | 27 | 5. 自动保存问题,当富文本编辑器在用户停止不动后,自动保存。 28 | 29 | ## 实现 30 | 31 | 重点是在 `clearTimeout` 32 | 33 | **方案 1**: 34 | 35 | ```js 36 | function debounce(fn, wait = 50) { 37 | let timer = null; 38 | return function (...args) { 39 | if (timer) clearTimeout(timer); 40 | timer = setTimeout(() => { 41 | fn.apply(this, args); 42 | }, wait); 43 | }; 44 | } 45 | 46 | const betterFn = debounce(() => { 47 | console.log('go to ==>'); 48 | }, 200); 49 | 50 | document.addEventListener('scroll', betterFn); 51 | ``` 52 | 53 | **方案 2**: 54 | 55 | - 具备立即执行的特性 56 | 57 | ```js 58 | function debounce(fn, wait = 50, im) { 59 | let timer = null; 60 | return function (...args) { 61 | if (timer) clearTimeout(timer); 62 | if (!timer && im) { 63 | fn.apply(this, args); 64 | } 65 | timer = setTimeout(() => { 66 | fn.apply(this, args); 67 | }, wait); 68 | }; 69 | } 70 | 71 | const betterFn = debounce( 72 | () => { 73 | console.log('go to ==>'); 74 | }, 75 | 200, 76 | true 77 | ); 78 | 79 | document.addEventListener('scroll', betterFn); 80 | ``` 81 | 82 | ## 同时使用 83 | 84 | ### 滚动场景 85 | 86 | ```js 87 | // 示例代码 88 | const handleScroll = () => { 89 | // 节流:限制检查频率 90 | throttle(() => { 91 | // 防抖:当用户停止滚动一段时间后执行 92 | debounce(checkIfReachBottom, 300)(); 93 | }, 200)(); 94 | }; 95 | 96 | window.addEventListener('scroll', handleScroll); 97 | ``` 98 | 99 | ### 实时搜索 100 | 101 | ```js 102 | const fetchSuggestions = () => { 103 | // 节流:限制最小请求间隔为500ms 104 | throttle(() => { 105 | // 防抖:用户停止输入300ms后执行 106 | debounce(actualFetch, 300)(); 107 | }, 500)(); 108 | }; 109 | 110 | searchInput.addEventListener('input', fetchSuggestions); 111 | ``` 112 | 113 | ```js 114 | const handleResize = () => { 115 | throttle(() => { 116 | debounce(calculateLayout, 200)(); 117 | }, 100)(); 118 | }; 119 | 120 | window.addEventListener('resize', handleResize); 121 | ``` 122 | 123 | ### 窗口大小调整 124 | -------------------------------------------------------------------------------- /docs/public/demos/js/promise-class.js: -------------------------------------------------------------------------------- 1 | // Reference :https://segmentfault.com/a/1190000038433512 2 | 3 | class PromiseClass { 4 | constructor(exec) { 5 | this.status = "pending"; // 等待中 6 | this.value = undefined; 7 | this.reason = undefined; 8 | this.onFulfilled = undefined; 9 | this.onRejected = undefined; 10 | this.onFulFilledList = []; // 等待的函数与列表? 11 | this.onRejectedList = []; // 拒绝的列表 12 | 13 | try { 14 | // todo 15 | exec(this.resolve, this.reject); 16 | } catch (error) { 17 | this.reject(error); 18 | } 19 | } 20 | 21 | // resolve 函数 22 | resolve(value) { 23 | if (this.status === "pending") { 24 | this.status = "fulfilled"; 25 | this.value = value; 26 | this.onFulFilledList.forEach((item) => item()); //每项函数都是执行 27 | } 28 | } 29 | // reject 函数 30 | reject(reason) { 31 | if (this.status === "pending") { 32 | this.status = "rejected"; 33 | this.reason = reason; 34 | this.onRejectedList.forEach((item) => item()); 35 | } 36 | } 37 | 38 | // then 39 | 40 | then(onFulfilled, onRejected) { 41 | let result = null; 42 | if (this.status === "fulfilled" && onFulfilled) { 43 | result = onFulfilled(this.value); 44 | return PromiseClass.resolve(result); //返回新的一个promise 45 | } 46 | 47 | if (this.status === "rejected" && onRejected) { 48 | result = onRejected(this.reason); 49 | return PromiseClass.resolve(result); 50 | } 51 | 52 | if (this.status === "pending") { 53 | onFulfilled && this.onFulFilledList.push(() => onFulfilled(this.value)); // 如果存在,则到栈里 54 | onRejected && this.onRejectedList.push(() => onRejected(this.reason)); 55 | } 56 | } 57 | } 58 | 59 | PromiseClass.resolve = function(value) { 60 | if (typeof value === "object" && value.then) { 61 | return value; 62 | } else { 63 | return new PromiseClass((resolve) => { 64 | resolve(value); 65 | }); 66 | } 67 | }; 68 | 69 | PromiseClass.all = function(list) { 70 | return new PromiseClass((resolve, reject) => { 71 | let result = []; 72 | let count = 0; 73 | for (let i = 0; i < list.length; i++) { 74 | if (typeof list[i] === "object" && list[i].then) { 75 | PromiseClass.resolve(list[i]).then((data) => { 76 | result[i] = data; 77 | count++; 78 | }, reject); 79 | } else { 80 | result[i] = list[i]; 81 | count++; 82 | } 83 | } 84 | 85 | if (count === list.length) { 86 | resolve(result); 87 | } 88 | }); 89 | }; 90 | 91 | // TODO:PromiseClass.race 只要一个成功,全部resolve 92 | 93 | // TODO:PromiseClass finally,不管成功失败,回调都执行,执行之后,依然可以then 94 | -------------------------------------------------------------------------------- /docs/interview/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | 5 | # 面试题 6 | 7 | ## 个人总结 8 | 9 | - 知所以然,不知所以然。(必须在常见的问题上,得到深入的理解和应用) 10 | 11 | - 必须需要作足准备 (几次的面试都很被动,打个措手不及) 12 | 13 | - 深入你使用主流框架的源码来理解 14 | 15 | ## css 16 | 17 | - 两种盒子模型分别说一下 18 | 19 | - 如何垂直居中 20 | 21 | - flex 怎么用?常用属性有什么? 22 | 23 | - BFC 是什么? 24 | 25 | - css 选择器优先级 26 | 27 | - 清除浮动 28 | - 原因? 29 | - 解决方案 30 | 31 | ## js 32 | 33 | - ES6 语法有什么?分别怎么用? 34 | - 必考:ES 6 语法知道哪些,分别怎么用? 35 | - 必考 Promise、Promise.all、Promise.race 分别怎么用? 36 | - 必考:手写函数防抖和函数节流 37 | - 必考:手写 AJAX 38 | - 必考:这段代码里的 this 是什么?6. 必考:闭包/立即执行函数是什么? 39 | - 必考:什么是 JSONP,什么是 CORS,什么是跨域?8. 常考:async/await 怎么用,如何捕获异常? 40 | - 常考:如何实现深拷贝? 41 | - 常考:如何用正则实现 trim()? 42 | - 常考:不用 class 如何实现继承?用 class 又如何实现?12. 常考:如何实现数组去重? 43 | - 放弃:==相关题目 (反着答) 44 | - 送命题:手写一个 Promise 45 | - (a==1&&a==2&&a==3) 可能为 true 吗?为什么 46 | - js 垃圾回收机制 47 | - EventLoop 48 | - apply call bind 49 | - [源码实现更新完毕](https://www.bilibili.com/read/cv7903371) 50 | - 手写原生 call bind apply 51 | - defineProperty 和 Proxy 区别? - defineProperty 劫持数据 -> 对象做拓展 - obj 是空对象 - 单个处理 property - proxy 返回代理对象数据劫持 -> 代理 - target 是已有的 property - 无属性名 - 全局性处理 property - 代理改,被代理也会被改 - 支持对数组的代理 - 支持对函数的代理 52 | 53 | - [【前端面试必备】Vue2 与 Vue3 核心之 ‘响应式原理’](https://www.bilibili.com/video/BV1Dk4y127Ha?p=1) 54 | - [前端进阶之道](https://yuchengkai.cn/docs/frontend/#%E5%86%85%E7%BD%AE%E7%B1%BB%E5%9E%8B) 55 | 56 | ## DOM 57 | 58 | 1. 必考:事件委托 59 | 2. 曾考:用 mouse 事件写一个可拖曳的 div 60 | 61 | ## HTTP 62 | 63 | 1. 必考:HTTP 状态码知道哪些?分别什么意思? 64 | 2. 大公司必考:HTTP 缓存有哪几种? 65 | 3. 必考:GET 和 POST 的区别 66 | 4. Cookie v.s.LocalStorage v.s。SessionStorage V.S。Session 67 | 68 | ## 框架 Vue 69 | 70 | 1. 必考:watch 和 computed 和 methods 区别是什么? 71 | 2. 必考:Vue 有哪些生命周期钩子函数?分别有什么用? 72 | 3. 必考:Vue 如何实现组件间通信? 73 | 4. 必考:Vue 数据响应式怎么做到的? 74 | 5. 必考:Vue.set 是做什么用的? 75 | 6. Vuex 你怎么用的? 76 | 7. VueRouter 你怎么用的? 77 | 8. 路由守卫是什么? 78 | 79 | ## 框架 React 80 | 81 | 1. 必考:受控组件对比非受控组件 82 | 2. 必考:React 有哪些生命周期函数?分别有什么用?(Ajax 请求放在哪个阶段?) 83 | 3. 必考:React 如何实现组件间通信? 84 | 4. 必考:shouldComponentUpdate 有什么用? 85 | 5. 必考:虚拟 DOM 是什么? 86 | 6. 必考:什么是高阶组件? 87 | 7. React diff 的原理是什么? 88 | 8. 必考 Redux 是什么? 89 | 90 | ## TypeScript 91 | 92 | - 说一下泛类型 93 | 1.never 类型是什么? 94 | 2.TypeScript 比起 JavaScript 有什么优点? 95 | 96 | ## Webpack 97 | 98 | 1. 必考:有哪些常见 loader 和 plugin,你用过哪些?2. 英语题:loader 和 plugin 的区别是什么?3. 必考:如何按需加载代码?4. 必考:如何提高构建速度?5. 转义出的文件过大怎么办? 99 | 上面五题请看这个不错的参考:https://zhuanlan.zhihu.com/p/44438844 100 | 101 | ## 安全 102 | 103 | - 什么是 XSS? 104 | - 解决: 105 | 106 | - 什么是 CSRF 107 | - 解决: 108 | 109 | ## Promise 110 | 111 | [Reference](https://segmentfault.com/a/1190000038433512) 112 | 113 | ```js 114 | 115 | ``` 116 | -------------------------------------------------------------------------------- /docs/public/demos/qij.js: -------------------------------------------------------------------------------- 1 | 2 | // let ob = { 3 | // '1': '∞', 4 | // '2': 'abc', 5 | // '3': 'def', 6 | // '4': 'ghi', 7 | // '5': 'jkl', 8 | // '6': 'mno', 9 | // '7': 'pqrs', 10 | // '8': 'tuv', 11 | // '9': 'wxyz', 12 | // '0': '+', 13 | // '*': ' ', 14 | // '↑': '#' 15 | // } 16 | // let arrNum = [1, 2, 3, 4, 5, 6, 7, 8, 9, '*', '0', '↑'];//∞ + ' ' # 17 | // function func(string) { 18 | // let stringData = (string.toString()).split('') //切割为数组 19 | // let len = stringData.length || 1; 20 | // let arrCount = [] 21 | // // 入参多少次数据? 22 | // for (let i = 0; i < len; i++) { 23 | // let tempArr = ob[stringData[i]].split('')//值的数组 24 | // arrCount.push(tempArr) 25 | // } 26 | // console.info(arrCount) 27 | // return arrCount 28 | // } 29 | // func(194) 30 | 31 | 32 | 33 | /*********************************************/ 34 | // var arr = []; 35 | // var a = ['b', 'c']; var b = ['e', 'f', 'g','h']; 36 | // for (let i = 0; i < 2; i++) { 37 | // for (let k = 0; k < b.length; k++) { 38 | // arr.push(a[i]+b[k]) 39 | // }; 40 | // }; 41 | // console.info(arr) 42 | 43 | // ['a']、 ['b','c']、['d','e','f'] abd,abe,abf,acd,ace,acf= 2x3=6的长度 44 | 45 | let arr1 = [['∞'], ['w', 'x', 'y', 'z'], ['g', 'h', 'i']] 46 | let temp = [] 47 | function p1(arr) { 48 | let s = '' 49 | for (let i = 0; i < arr.length; i++) { 50 | s = s + arr[i] 51 | temp.push(s) 52 | return p1(arr[i]) 53 | } 54 | } 55 | p1(arr1) 56 | 57 | 58 | 59 | // Math.round(Math.random())?Math.round(Math.random()):Math.round(Math.random())-1 60 | 61 | /**数据动态绑定基本实现 **/ 62 | let obj = { 63 | key_1: 1, 64 | key_2: 2 65 | } 66 | function func(key) { 67 | console.info(key + '的值子发生变化' + this[key]) 68 | } 69 | 70 | function bindData(obj, func) { 71 | for (let item in obj) { 72 | Object.defineProperty(obj, item, { 73 | get: function () { 74 | return obj.item; 75 | }, 76 | set: function (value) { 77 | obj.item = value; 78 | func.bind(obj)(item); 79 | } 80 | }) 81 | } 82 | } 83 | bindData(obj, func) 84 | obj.key_1 = 2;//此时自动输出 变化为2 85 | obj.key_2 = 1 //此时自动输出变化为1 86 | 87 | /** 对json 数据结构进行处理,要求找到child 超过两个的name值 **/ 88 | 89 | let data={ 90 | name:'jack', 91 | child:[ 92 | {name:'jack1'}, 93 | {name:'jack2',child:[ 94 | {name:'jack2_1',child:{name:'jack2-1-1'}}, 95 | {name:'jack2_2'} 96 | ]}, 97 | {name:'jack3',child:{name:'jack3-1'}} 98 | ] 99 | }; 100 | Object.keys(data)//只能取同级的keys值 -------------------------------------------------------------------------------- /docs/frontend/es6/reflect.md: -------------------------------------------------------------------------------- 1 | 2 | ## Reflect 3 | 4 | > 现阶段一些方法同时部署到 Object、Reflect 对象上,未来某些方法只能从 Reflect 上获取,比如 Object.defineProperty 5 | 6 | - 合理化取值。比如 Object.defineProperty(obj,name,desc) 在无法定义属性时,报错,但 Reflect.defineProperty(obj,name,desc) 会返回 false 7 | 8 | ```js 9 | // 旧的方法 10 | try { 11 | Object.defineProperty(target, property, attributes); 12 | // 成功的取值 13 | } catch (e) { 14 | // 失败 15 | } 16 | 17 | if (Reflect.defineProperty(target, property, attributes)) { 18 | // 成功 19 | } else { 20 | // 失败 21 | } 22 | ``` 23 | 24 | - `Object` 操作都变成了函数行为,而不是一个操作符 25 | 26 | ```js 27 | // 旧的写法 28 | 'assign' in Object; //true 29 | // 新写法 30 | Reflect.has(Object, 'assign'); //true 31 | 32 | // 旧的delete 操作符 33 | var obj = { 34 | name: 'Old', 35 | }; 36 | delete obj.name; 37 | 38 | // 新的函数式操作方法 39 | Reflect.deleteProperty(obj, 'name'); 40 | ``` 41 | 42 | - Reflect 对象的方法和 Proxy 对象的方法一一对象,只要在 Proxy 有,Reflect 就会有。 43 | - 不管 Proxy 怎么修改默认行为,总可以在 Reflect 上获取默认行为 44 | 45 | ```js 46 | var obj = new Proxy(obj, { 47 | get(target, name) { 48 | console.log('get', target, name); 49 | return Reflect.get(target, name); 50 | }, 51 | deleteProperty(target, name) { 52 | console.log('delete ', name); 53 | return Reflect.deleteProperty(target, name); 54 | }, 55 | has(target, name) { 56 | console.log('has', name); 57 | return Reflect.has(target, name); 58 | }, 59 | }); 60 | ``` 61 | 62 | - proxy 的拦截操作,内部的偶调用对应的 Reflect 方法,保证原生行为能够正常执行 63 | - 易阅读 64 | 65 | ```js 66 | // old 67 | Function.prototype.apply.call(Math.floor, undefined, [1.6]); //1 68 | 69 | // new 70 | Reflect.apply(Math.floor, undefined, [1.6]); //1 71 | ``` 72 | 73 | ### Reflect 静态方法:一共 13 个 74 | 75 | - **Reflect.apply(target,thisArg,args)** 76 | - **Reflect.construct(target,args)** 77 | - **Reflect.get(target,name,receiver)** 78 | - **Reflect.set(target,name,value,receiver)** 79 | - **Reflect.defineProperty(target,name,dec)** 80 | - **Reflect.deleteProperty(target,name)** 81 | - **Reflect.has(target,name)** 82 | - **Reflect.ownKeys(target)** 83 | - **Reflect.isExtensible(target)** 84 | - **Reflect.preventExtensions(target)** 85 | - **Reflect.getOwnPropertyDescriptor(target,name)** 86 | - **Reflect.getPrototypeOf(target)** 87 | - **Reflect.setPrototypeOf(target,prototype)** 88 | 89 | ### 使用 Proxy 实现观察者模式 90 | 91 | 观察者模式 (Observer mode) 92 | 93 | ```js 94 | const queueObservers = new Set(); 95 | const observer = (fn) => queueObservers.add(fn); 96 | 97 | function set(target, key, value, receiver) { 98 | const result = Reflect.set(target, key, value, receiver); 99 | queueObservers.forEach((ob) => ob()); 100 | return result; 101 | } 102 | ``` 103 | 104 | 先定义一个 Set 集合,所有观察者函数都放进这个集合,observable 函数返回对象的代理,拦截赋值操作,拦截函数 set 中,启动执行所有观察者 105 | -------------------------------------------------------------------------------- /docs/public/demos/js/simulate/promise-class-all.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 1. TODO 如何实现链式调用 4 | * 2. Promise 实例有三个方法 5 | * - then 6 | * - catch 7 | * - finally 8 | * 3. Promise 有6个静态方法 9 | * 4. 10 | * static #fns 私有静态 11 | * static fns 公有静态 12 | * 13 | */ 14 | class PromiseClass { 15 | static thenList = []; 16 | static catchList = []; 17 | constructor(fn) { 18 | this.fns = [fn]; 19 | this.thenList = []; 20 | // console.log("fn=>", fn); 21 | // console.log("typeof fn=>", typeof fn); 22 | // console.log("typeof fns=>", typeof this.fns); 23 | // console.log("this=>", this); 24 | 25 | fn.call(null, PromiseClass.resolved); // 通过call 显式转移内部的 param 26 | fn.call(null, PromiseClass.rejected); // 通过call 显式转移内部的 param 27 | } 28 | static resolved(...args) { 29 | const resolveParam = args[0]; 30 | // PromiseClass.then.call(this, resolveParam); 31 | 32 | PromiseClass.thenList.shift().call(this, resolveParam); 33 | 34 | for (let i = 0; i < PromiseClass.thenList.length; i++) { 35 | const returnThen = PromiseClass.thenList[i]; 36 | console.log("returnThen=>", returnThen.call(this, returnThen)); 37 | } 38 | } 39 | static rejected(...args) { 40 | const rejectParam = args[0]; 41 | for (let i = 0; i < PromiseClass.catchList.length; i++) { 42 | PromiseClass.catchList[i].call(this, rejectParam); 43 | } 44 | } 45 | 46 | /** 47 | * @desc promise instance method: then 48 | * @TODO 这个then 是在 resolve 里面异步后再被动执行的 49 | * 50 | */ 51 | then(...args) { 52 | const thenParam = args[0]; 53 | PromiseClass.thenList.push(thenParam); 54 | return this; 55 | } 56 | 57 | /** 58 | * @desc promise instance method: catch 59 | * @TODO 60 | * 61 | */ 62 | catch(...args) { 63 | const catchParam = args[0]; 64 | PromiseClass.catchList.push(catchParam); 65 | return this; 66 | } 67 | 68 | /** 69 | * @desc promise instance method: finally 70 | * @TODO 71 | * 72 | */ 73 | finally() {} 74 | 75 | /** 76 | * @TODO 77 | * 78 | */ 79 | static all(arg) { 80 | console.log("this", arg); 81 | } 82 | static resolve() {} 83 | /** 84 | * @TODO 85 | * 86 | */ 87 | static reject() {} 88 | /** 89 | * @TODO 90 | * 91 | */ 92 | static race() {} 93 | /** 94 | * @TODO 95 | * 96 | */ 97 | static any() {} 98 | /** 99 | * @TODO 100 | * 101 | */ 102 | static finally() {} 103 | /** 104 | * @TODO 105 | * 106 | */ 107 | static allSettled() {} 108 | } 109 | 110 | // PromiseClass.all(11); 111 | 112 | // console.log(PromiseClass); 113 | 114 | /** 115 | * Promise 内部的如何调用 resolve 这个两个参数? 116 | * @Test 如果then里不return res 为undefined 117 | * 118 | */ 119 | 120 | module.exports = PromiseClass; 121 | -------------------------------------------------------------------------------- /docs/backend/node/fs.md: -------------------------------------------------------------------------------- 1 | ## fs 2 | 3 | > 不建议在调用 fs.open()、fs.readFile() 或 fs.writeFile() 之前使用 fs.access() 检查文件的可访问性。这样做会引入竞争条件,因为其他进程可能会在两个调用之间更改文件的状态。相反,用户代码应该直接打开、读取或写入文件,并处理在文件无法访问时引发的错误。 4 | 5 | - `.unlink()` 删除文件异步 6 | 7 | ```js 8 | const fs = require('fs'); 9 | fs.unlink('./tmp/hello.js', (err) => { 10 | if (err) throw err; 11 | console.log('删除成功'); 12 | }); 13 | ``` 14 | 15 | - `.unlinkSync()` 删除文件,同步 16 | 17 | ```js 18 | const fs = require('fs'); 19 | try { 20 | fs.unlinkSync('./tmp/hello.js'); 21 | console.log('删除成功'); 22 | } catch (err) { 23 | console.log(err, '删除失败'); 24 | } 25 | ``` 26 | 27 | - `.rename()` 28 | 29 | ```js 30 | fs.rename('./tmp/hello.js', './tmp/world.js', (err) => { 31 | if (err) throw err; 32 | console.log('rename done'); 33 | }); 34 | ``` 35 | 36 | - `.open()` 完成操作后,需要关闭描述符,否则可能导致内存泄漏 37 | - `wx` flag 38 | - `r` 39 | 40 | 线程池 41 | 42 | > 除了 fs.FSWatcher() 和显式同步的方法之外,都使用了 `libuv` 线程池,这对于某些应用程序可能会产生其他负面性能问题,详见 http://nodejs.cn/api/cli.html#cli_uv_threadpool_size_size 43 | 44 | - `fs.FSWatcher()` 45 | > 成功调用一个 fs.watch 方法都会返回一个新的 fs.FSWatcher 对象 46 | - `fs.access(path,[.mode],callback)` 47 | - `fs.Dirent` 类 48 | - `.dirent.isBlockDevice()` boolean 49 | 50 | ```js 51 | const fs = require('fs'); 52 | fs.open('./tmp/hello.js', 'r', (err, fd) => { 53 | if (err) throw err; 54 | fs.fstat(fd, (err1, stat) => { 55 | if (err1) throw err1; 56 | //文件属性 57 | console.log(stat); 58 | 59 | //关闭文件描述符 60 | fs.close(fd, (errC) => { 61 | if (errC) throw errC; 62 | console.loh('关闭'); 63 | }); 64 | }); 65 | }); 66 | ``` 67 | 68 | - `fs.ReadStream` 类 69 | - `fs.WriteSteam` 类 70 | - `fs.Stats` 类 71 | - `fs.stat()` 72 | 73 | ```js 74 | fs.stat('./tmp/world.js', (err, stats) => { 75 | if (err) throw err; 76 | conosle.log(stats); 77 | }); 78 | ``` 79 | 80 | - `fs.lsate()` 81 | - `.fstat` 82 | 83 | ```js 84 | fs.fstat(fd, (err1, stat) => { 85 | if (err1) throw err1; 86 | //文件属性 87 | console.log(stat); 88 | //关闭文件描述符 89 | fs.close(fd, (errC) => { 90 | if (errC) throw errC; 91 | console.log('关闭'); 92 | }); 93 | }); 94 | ``` 95 | 96 | - `fs.close()` 97 | - `fs.appendFile(path,data[,options],callback)` 98 | > 异步地将数据追加到文件中,如果文件不存在,则创建该文件,`data` 可以使字符串或者 `Buffer` 99 | 100 | ```js 101 | fs.appendFile('/tmp.append.txt', 'hello world append file for node.js fs.appendFile function' + new Date(), (err) => { 102 | if (err) throw err; 103 | }); 104 | ``` 105 | 106 | > 异步方法,顺序无法保证 107 | 108 | ```js 109 | fs.rename('./tmp/hello.js', './tmp/world.js', (err) => { 110 | if (err) throw err; 111 | console.log('rename done'); 112 | }); 113 | //stat可能在rename 之前, 114 | fs.stat('./tmp/world.js', (err, stats) => { 115 | if (err) throw err; 116 | conosle.log(stats); 117 | }); 118 | ``` 119 | 120 | > 方法时,在回调内部 121 | -------------------------------------------------------------------------------- /docs/javascript/blob.md: -------------------------------------------------------------------------------- 1 | # Blob 对象 2 | 3 | `Blob` 是一个表示不可变、原始数据的类文件对象。 4 | 5 | 可以按文本、二进制格式进行读取,重要的是可以为别的格式。 6 | 7 | ## base64 转 blob 8 | 9 | ```js 10 | const file = dataURLtoFile(item, new Date());this.uploadFile(file); 11 | /** 12 | * @desc base64转换 blob文件 13 | * */ 14 | const dataURLtoFile(dataUrl) { 15 | let arr = dataUrl.split(','), mime = arr[0].match(/:(.*?);/)[1]; 16 | const base64Str = atob(arr[1]); 17 | const n = base64Str.length; 18 | const u8arr = new Uint8Array(n); 19 | while (n--) { 20 | u8arr[n] = base64Str.charCodeAt(n); 21 | } 22 | return new Blob([u8arr], {type: mime}); 23 | }, 24 | /** 25 | * @desc 上传图片 26 | * */ 27 | const uploadFile(file) { 28 | const formData = new FormData(); 29 | formData.append('file', file); 30 | $ajaxPost('/api/work/upload', formData, { 31 | headers: { 32 | 'content-Type': 'multipart/form-data' 33 | } 34 | }) 35 | .then(res => { 36 | if (res && res.code === 0) { 37 | this.workData.screenShots.push(res.data.url); 38 | } 39 | }) 40 | .catch(err => { 41 | console.info(err); 42 | }); 43 | }, 44 | ``` 45 | 46 | ## json 转为 blob 47 | 48 | ```js 49 | const json = { a: 1, b: 2 }; 50 | 51 | const blob = new Blob([JSON.stringify(json, null, 2)], { type: 'application/json' }); 52 | 53 | // blob 为 {size:22, type:"application/json"} 54 | // await blob.text() 为 '{\n "a": 1,\n "b": 2\n}' 55 | ``` 56 | 57 | ## 字符串转为 blob 并返回对象的 URL 58 | 59 | 将一段字符串转为 blob 并生成 URL 下载 60 | 61 | ```js 62 | const novelData = 'hello world'; 63 | const blob = new Blob([novelData], { type: 'text/plain' }); 64 | const objectURL = URL.createObjectURL(blob); 65 | 66 | const downloadLink = document.createElement('a'); 67 | downloadLink.textContent = 'download.txt'; 68 | downloadLink.href = objectURL; 69 | downloadLink.download = 'download.txt'; 70 | 71 | const downloadContainer = document.querySelector('.download'); 72 | if (downloadContainer) { 73 | downloadContainer.appendChild(downloadLink); 74 | } 75 | 76 | // Remember to revoke the object URL when it's no longer needed to free memory 77 | downloadLink.addEventListener('click', () => { 78 | setTimeout(() => URL.revokeObjectURL(objectURL), 100); 79 | }); 80 | ``` 81 | 82 | ## 从 blob 中提取数据 83 | 84 | blob 对象本身不包含数据,它只是保存了数据的引用。要提取 blob 中的数据,需要使用 FileReader 对象。 85 | 86 | ```js 87 | const reader = new FileReader(); 88 | 89 | reader.addEventListener('loadend', () => { 90 | // reader.result 包含 blob 中的数据 91 | }); 92 | 93 | reader.readAsArrayBuffer(blob); 94 | ``` 95 | 96 | ## 从 Response 中读取 97 | 98 | ```js 99 | const text = await new Response(blob).text(); 100 | ``` 101 | 102 | 或者: 103 | 104 | ```js 105 | const text = await blob.text(); 106 | // 配合其他 API 如 fetch 使用 107 | ``` 108 | -------------------------------------------------------------------------------- /docs/javascript/promise.md: -------------------------------------------------------------------------------- 1 | # Promise 2 | 3 | [promise-class](https://github.com/veaba/web-advanced/blob/master/demos/js/promise-class.js) 4 | 5 | ```js 6 | // Reference :https://segmentfault.com/a/1190000038433512 7 | 8 | class PromiseClass { 9 | constructor(exec) { 10 | this.status = "pending"; // 等待中 11 | this.value = undefined; 12 | this.reason = undefined; 13 | this.onFulfilled = undefined; 14 | this.onRejected = undefined; 15 | this.onFulFilledList = []; // 等待的函数与列表? 16 | this.onRejectedList = []; // 拒绝的列表 17 | 18 | try { 19 | // todo 20 | exec(this.resolve, this.reject); 21 | } catch (error) { 22 | this.reject(error); 23 | } 24 | } 25 | 26 | // resolve 函数 27 | resolve(value) { 28 | if (this.status === "pending") { 29 | this.status = "fulfilled"; 30 | this.value = value; 31 | this.onFulFilledList.forEach((item) => item()); //每项函数都是执行 32 | } 33 | } 34 | // reject 函数 35 | reject(reason) { 36 | if (this.status === "pending") { 37 | this.status = "rejected"; 38 | this.reason = reason; 39 | this.onRejectedList.forEach((item) => item()); 40 | } 41 | } 42 | 43 | // then 44 | 45 | then(onFulfilled, onRejected) { 46 | let result = null; 47 | if (this.status === "fulfilled" && onFulfilled) { 48 | result = onFulfilled(this.value); 49 | return PromiseClass.resolve(result); //返回新的一个promise 50 | } 51 | 52 | if (this.status === "rejected" && onRejected) { 53 | result = onRejected(this.reason); 54 | return PromiseClass.resolve(result); 55 | } 56 | 57 | if (this.status === "pending") { 58 | onFulfilled && this.onFulFilledList.push(() => onFulfilled(this.value)); // 如果存在,则到栈里 59 | onRejected && this.onRejectedList.push(() => onRejected(this.reason)); 60 | } 61 | } 62 | } 63 | 64 | PromiseClass.resolve = function(value) { 65 | if (typeof value === "object" && value.then) { 66 | return value; 67 | } else { 68 | return new PromiseClass((resolve) => { 69 | resolve(value); 70 | }); 71 | } 72 | }; 73 | 74 | PromiseClass.all = function(list) { 75 | return new PromiseClass((resolve, reject) => { 76 | let result = []; 77 | let count = 0; 78 | for (let i = 0; i < list.length; i++) { 79 | if (typeof list[i] === "object" && list[i].then) { 80 | PromiseClass.resolve(list[i]).then((data) => { 81 | result[i] = data; 82 | count++; 83 | }, reject); 84 | } else { 85 | result[i] = list[i]; 86 | count++; 87 | } 88 | } 89 | 90 | if (count === list.length) { 91 | resolve(result); 92 | } 93 | }); 94 | }; 95 | 96 | // TODO:PromiseClass.race 只要一个成功,全部resolve 97 | 98 | // TODO:PromiseClass finally,不管成功失败,回调都执行,执行之后,依然可以then 99 | ``` 100 | -------------------------------------------------------------------------------- /docs/frontend/performance/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | 5 | # 性能提升 6 | 7 | 网页性能管理详解 ——阮一峰 http://www.ruanyifeng.com/blog/2015/09/web-page-performance-in-depth.html 8 | 9 | ## 前端常见的性能优化请求手段 10 | 11 | 加快资源的加载速度,减少白屏事件 12 | 13 | - CDN 内容分发 14 | - css Sprite 图片合并 15 | - Compress/Gzip 资源文件压缩 16 | - Async/Defer 异步加载 17 | - HTTP Cache HTTP 缓存 18 | .... 19 | 20 | ## html/css 重绘回流 (Repaint、Reflow) 21 | 22 | - display:none 不会发生回流和重绘 23 | - 回流一定触发重绘,重绘不一定会触发回流 24 | - 复杂动画,使用 `position: absolute` 使其脱离文档流 25 | - css3 硬件加速 (GPU 加速) 26 | - css3 硬件加速下以下属性不会发生重绘回流: 27 | - transform 28 | - opacity 29 | - filters 30 | - 使用 fixed 和 absolute,如果修改 css 不会发生回流 31 | 32 | ### 重绘 (repaint) 33 | 34 | ### 回流 (reflow) 35 | 36 | 回流 (reflow):布局引擎为 frame (框架) 计算图形的过程,一个 frame 回流会导致所有父节点以及后续元素都会回流。 37 | 38 | - 理论上发生回流的原因 39 | - 初始化 (initial)。dom 载入后第一次回流,遍历所有 frame 40 | - 渐进 (incremental)。一个 frame 发生渐进 reflow 时,前面没变,自己内部发生变化。 41 | - 改变大小。容器边界发生变化,内部没变,复用内部状态 42 | - 样式改变。整个 frame 都会遍历 43 | - dirty。(脏的) 已缓存了多个子元素的渐进回流时。 44 | - 具体的操作原因: 45 | - 窗口大小变化 46 | - 更改文档默认字体 47 | - 样式表改变 48 | - 元素内容变化,尤其是输入控件 49 | - input textarea 50 | - dom 操作 51 | - 渐进回流,会使浏览器将渐进队列冲洗,立即执行回流 52 | - offsetWidth、offsetHeight 计算。整个可视区域大小,包括 border scrollBar 在内 53 | - width、height 计算。 54 | - clientWidth 计算内部可视区域大小。 55 | - scrollTop 计算。元素内容向上滚动了多少像素。 56 | - scrollHeight 计算。元素内容的高度,包括溢出的部分 57 | - 避免回流 58 | - 避免逐项更改 style 59 | - 避免循环操作 dom 60 | - 避免循环读取 offsetLeft 等属性,并在循环之前存起来 61 | - 绝对定位具有复杂变化的动画元素。position:absolute 脱离文档流,否则会引起父元素以及后续元素的大量回流。css3 transition 性能不错 62 | 63 | ```js 64 | // 一次bad 的demo 65 | 66 | var dom = document.body.style; 67 | dom.padding = '2px'; // 回流+重绘 68 | dom.border = '1px solid'; // 回流+重绘 69 | dom.border = 'blue'; // 重绘 70 | dom.backgroundColor = '#ccc'; // 重绘 71 | dom.fontSize = '14px'; // 重绘+回流 72 | document.body(document.createTextNode('hello world!')); 73 | ``` 74 | 75 | 解决办法 76 | 77 | 1. 写 style 更改 class 78 | 79 | ```js 80 | document.body.className = 'dom'; 81 | ``` 82 | 83 | ```html 84 | .dom { padding:2px; border:1px solid; background-color:#ccc; font-size:14px } 85 | ``` 86 | 87 | 2. 一次添加全部的 style 操作 88 | 89 | ```js 90 | var dom = document.body.style; 91 | dom = 'padding:2px;border:1px solid;background-color:#ccc;font-size:14px'; 92 | ``` 93 | 94 | 重绘 (repaint):发生在元素的可见性发生变化时产生重新渲染的现象,回流必然引起重绘: 95 | 96 | - background 97 | - color 98 | 99 | ## 常见的内存泄露的问题 100 | 101 | ### 闭包在 IE9 之前的版本会导致一些特殊的问题。 102 | 103 | ```js 104 | // 内存泄漏 105 | function click1() { 106 | let element = document.querySelector('.test'); 107 | element.onclick = function () { 108 | console.log(element.id); 109 | }; 110 | } 111 | // fix 版本 112 | function click2() { 113 | let element2 = document.querySelector('.test'); 114 | let id = element2.id; // 引用赋值,消除变量循环引用 115 | element2.onclick = function () { 116 | console.log(id); 117 | }; 118 | // 设置为null,解除对DOM对象的引用,减少计数 119 | element2 = null; 120 | } 121 | ``` 122 | -------------------------------------------------------------------------------- /docs/javascript/scoped/closure.md: -------------------------------------------------------------------------------- 1 | # 闭包 2 | 3 | - 如何调试闭包函数中返回的变量值,假设已上线,不可更改原始代码 4 | 5 | ```js 6 | const fn = (function () { 7 | const closeData = { 8 | age: 28, 9 | job: 'web', 10 | }; 11 | return { 12 | run: function (key) { 13 | return closeData[key]; 14 | }, 15 | }; 16 | })(); 17 | 18 | // 如果获取完整的 closeData呢? 19 | fn.run('web'); 20 | 21 | // 劫持原始对象的get 22 | Object.defineProperty(Object.prototype, 'all', { 23 | get: function () { 24 | return this; 25 | }, 26 | }); 27 | 28 | // 获取所有 29 | fn.run('all'); 30 | ``` 31 | 32 | 或: 33 | 34 | ```js 35 | Object.prototype.__defineGetter__('get', function () { 36 | return this; 37 | }); 38 | 39 | console.log(o.run('get')); 40 | ``` 41 | 42 | - JavaScript 语言中,只有函数内部的子函数才能读取局部变量。 43 | 44 | - `JavaScript` 特有链式作用域 (chain scope) 有关系,子对象会父级以上查找作用域变量。 45 | - 父作用域对子对象可见,反之不行 46 | 47 | - 闭包能够读取其他函数内部变量的函数 48 | 49 | ## 定义 50 | 51 | A 函数返回函数 B,且返回的函数调用 A 的变量 52 | 53 | ```js 54 | function A() { 55 | const a = 1; 56 | return function B() { 57 | console.log(a); 58 | }; 59 | } 60 | 61 | // A()() 62 | ``` 63 | 64 | ## 常见 65 | 66 | ```js 67 | for (var i = 1; i <= 5; i++) { 68 | setTimeout(() => { 69 | console.log(i); 70 | }, i * 1000); 71 | } 72 | ``` 73 | 74 | setTimeout 是异步函数,会先把循环全部执行完毕。 75 | 76 | **1. 使用闭包解决:** 77 | 78 | ```js 79 | for (var i = 1; i <= 5; i++) { 80 | ((j) => { 81 | setTimeout(() => { 82 | console.log(j); 83 | }, j * 1000); 84 | })(i); 85 | } 86 | ``` 87 | 88 | **2. setTimeout 第三个参数:** 89 | 90 | ```js 91 | for (var i = 1; i <= 5; i++) { 92 | setTimeout( 93 | (i) => { 94 | console.log(i); 95 | }, 96 | i * 1000, 97 | i 98 | ); 99 | } 100 | ``` 101 | 102 | **3. 使用 let 声明,形成块级作用域:** 103 | 104 | ```js 105 | for (let i = 1; i <= 5; i++) { 106 | setTimeout(() => { 107 | console.log(i); 108 | }, i * 1000); 109 | } 110 | ``` 111 | 112 | ## 解决与避免 113 | 114 | ## 场景 115 | 116 | 1. 允许不带参数的函数 `setTimeout` 调用 117 | 118 | ```js 119 | function fn(a) { 120 | function f2() { 121 | console.log(a); 122 | } 123 | } 124 | const fun = fn(2); 125 | 126 | setTimeout(fn, 2000); 127 | ``` 128 | 129 | 2. 回调 130 | 131 | ```js 132 | function onSize(size) { 133 | return function () { 134 | document.border.style.fontSize = size + 'px'; 135 | }; 136 | } 137 | 138 | const size16 = onSize(16); 139 | document.body.onclick = size16; 140 | ``` 141 | 142 | ## 如何消除闭包? 143 | 144 | - TODO 解除变量的引用? 145 | 146 | ```js 147 | const arrayDeepLevel = (function () { 148 | let level = -1; 149 | return function (array) { 150 | if (Array.isArray(array)) { 151 | for (let item of array) { 152 | if (Array.isArray(item)) { 153 | arrayDeepLevel(item); 154 | } 155 | } 156 | level++; 157 | return level; 158 | } 159 | }; 160 | })(); 161 | ``` 162 | 163 | ## 引用 164 | 165 | - [阮一峰 - 学习 Javascript 闭包 (Closure)](http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html) 166 | -------------------------------------------------------------------------------- /docs/javascript/static-method.md: -------------------------------------------------------------------------------- 1 | [//]: # (TODO) 2 | 3 | # 静态方法 4 | 5 | - 疑问:比较 MediaSource.prototype 与 Array.isArray() 6 | 7 | Array.isArray() `静态方法?`,可在 chrome 打印出来并不是灰色 8 | ![Array.isArray()](/images/isArray.jpg) 9 | 10 | MediaSource.isTypeSupported() `静态方法`,在 chrome 打印出来是亮色 11 | ![MediaSource.isTypeSupported](/images/isTypeSupported.jpg) 12 | 13 | | 类型或者构造函数 | arguments | caller | length | name | prototype | **proto** | [[Scopes]] | 14 | |--------------|-----------|--------|--------|---------|-----------|-----------|------------| 15 | | String | | | 1 | String | | | | 16 | | Boolean | | | 1 | Boolean | | | | 17 | | Number | | | 1 | Number | | | | 18 | | Object | | | 1 | Object | | | | 19 | | Array | | | 1 | Array | | | | 20 | | Symbol | | | 0 | Symbol | | | | 21 | | MediaSources | | | | | | | | 22 | | | | | | | | | 23 | 24 | ## String 方法 25 | 26 | - `fromCharCode` 27 | - `raw` 28 | 29 | ## Boolean 30 | 31 | ## Number 32 | 33 | - `EPSILON:2.220446049250313e-16` 34 | - `MAX_SAFE_INTEGER: 9007199254740991` 35 | - `MAX_VALUE:1.7976931348623157e+308` 36 | - `MIN_SAFE_INTEGER: -9007199254740991` 37 | - `MIN_VALUE:5e-324` 38 | - `NEGATIVE_INFINITY: -Infinity` 39 | - `NaN: NaN` 40 | - `POSITIVE_INFINITY: Infinity` 41 | - `isFinite()` 42 | - `isInteger()` 43 | - `isNaN()` 44 | - `isSafeInteger()` 45 | - `parseFloat()` 46 | - `parseInt()` 47 | 48 | ## Object 49 | 50 | - `assign()` 51 | - `create()` 52 | - `defineProperties()` 53 | - `defineProperty()` 54 | - `entries()` 55 | - `freeze()` 56 | - `getOwnPropertyDescriptor()` 57 | - `getOwnPropertyDescriptors()` 58 | - `getOwnPropertyNames()` 59 | - `getOwnPropertySymbols()` 60 | - `getPrototypeOf()` 61 | - `is()` 62 | - `isExtensible()` 63 | - `isFrozen()` 64 | - `isSealed()` 65 | - `keys()` 66 | - `preventExtensions()` 67 | - `seal()` 68 | - `setPrototypeOf()` 69 | - `values()` 70 | 71 | ## Array 72 | 73 | - `from()` 74 | - `isArray()` 75 | - `of()` 76 | - `Symbol(Symbol.species)` 77 | - `get Symbol(Symbol.species):()` 78 | 79 | ## Symbol 80 | 81 | - `asyncIterator` 82 | - `for()` 83 | - `hadInstance` 84 | - `isConcatSpreadable` 85 | - `iterator` 86 | - `keyFor()` 87 | - `match` 88 | - `replace` 89 | - `search` 90 | - `species` 91 | - `split` 92 | - `toPrimitive` 93 | - `toStringTag` 94 | - `unscopables` 95 | 96 | ## WebSocket 97 | 98 | - `CLOSED:3` 99 | - `CLOSING:2` 100 | - `OPEN:1` 101 | - `CONNECTING:0` 102 | 103 | ## MediaSources 104 | 105 | - `isTypeSupported()` 静态方法 106 | 107 | ## Audio 108 | 109 | ## Vidio 110 | 111 | ## Canvas 112 | -------------------------------------------------------------------------------- /docs/bundler/rollup/index.md: -------------------------------------------------------------------------------- 1 | # Rollup 2 | 3 | - umd 4 | - iife 5 | - cjs 6 | 7 | > rollup src\app.ts --file build.js --format cjs 8 | 9 | ## cjs 10 | 11 | ```js 12 | import { createServer } from "http"; 13 | import { Server } from "socket.io"; 14 | 15 | const httpServer = createServer(); 16 | const io = new Server(httpServer, { cors: true }); 17 | 18 | io.on("connection", (socket) => { 19 | console.log(socket.id); 20 | }); 21 | 22 | httpServer.listen(8080, () => { 23 | console.log("listen 8080"); 24 | }); 25 | ``` 26 | 27 | ==> 28 | 29 | ```js 30 | "use strict"; 31 | 32 | var http = require("http"); 33 | var socket_io = require("socket.io"); 34 | 35 | const httpServer = http.createServer(); 36 | const io = new socket_io.Server(httpServer, { cors: true }); 37 | 38 | io.on("connection", (socket) => { 39 | console.log(socket.id); 40 | }); 41 | 42 | httpServer.listen(8080, () => { 43 | console.log("listen 8080"); 44 | }); 45 | ``` 46 | 47 | ## umd 48 | 49 | > 50 | 51 | ```js 52 | import { createServer } from "http"; 53 | import { Server } from "socket.io"; 54 | 55 | const httpServer = createServer(); 56 | const io = new Server(httpServer, { cors: true }); 57 | 58 | io.on("connection", (socket) => { 59 | console.log(socket.id); 60 | }); 61 | 62 | httpServer.listen(8080, () => { 63 | console.log("listen 8080"); 64 | }); 65 | 66 | ``` 67 | 68 | ===> 69 | 70 | ```js 71 | (function (global, factory) { 72 | typeof exports === 'object' && typeof module !== 'undefined' ? factory(require('http'), require('socket.io')) : 73 | typeof define === 'function' && define.amd ? define(['http', 'socket.io'], factory) : 74 | (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.http, global.socket_io)); 75 | }(this, (function (http, socket_io) { 'use strict'; 76 | 77 | const httpServer = http.createServer(); 78 | const io = new socket_io.Server(httpServer, { cors: true }); 79 | 80 | io.on("connection", (socket) => { 81 | console.log(socket.id); 82 | }); 83 | 84 | httpServer.listen(8080, () => { 85 | console.log("listen 8080"); 86 | }); 87 | 88 | }))); 89 | 90 | ``` 91 | 92 | ## iife 93 | - 立即执行 94 | > rollup src\app.ts --file build.js --format iife 95 | 96 | ```js 97 | import { createServer } from "http"; 98 | import { Server } from "socket.io"; 99 | 100 | const httpServer = createServer(); 101 | const io = new Server(httpServer, { cors: true }); 102 | 103 | io.on("connection", (socket) => { 104 | console.log(socket.id); 105 | }); 106 | 107 | httpServer.listen(8080, () => { 108 | console.log("listen 8080"); 109 | }); 110 | 111 | ``` 112 | 113 | ```js 114 | (function (http, socket_io) { 115 | 'use strict'; 116 | 117 | const httpServer = http.createServer(); 118 | const io = new socket_io.Server(httpServer, { cors: true }); 119 | 120 | io.on("connection", (socket) => { 121 | console.log(socket.id); 122 | }); 123 | 124 | httpServer.listen(8080, () => { 125 | console.log("listen 8080"); 126 | }); 127 | 128 | }(http, socket_io)); 129 | 130 | ``` -------------------------------------------------------------------------------- /docs/html/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | 5 | # HTML 6 | 7 | - [Docs Glossary](https://developer.mozilla.org/zh-CN/docs/Glossary) 8 | 9 | ## 知识点 10 | 11 | - 带 id 属性的 DOM 元素有什么副作用? 12 | - 创建同名的全局变量 13 | - `clientWidth`:`height` + `padding` 14 | - `offsetHeight`: `height` + `padding` + `border` 15 | - w3c 标准盒模型中,默认情况下,块元素的总宽度 = content 16 | - HTML5 事件可以触发多次 17 | - `link` 与 `@import` 区别 18 | 19 | ## 盒子模型 20 | 21 | ### 标准盒子模型 22 | 23 | 标准盒子模型宽度:content 24 | 25 | - 默认使用 border-box 26 | 27 | ```html 28 | 29 | 30 | 31 | 32 | Document 33 | 50 | 51 | 52 |
53 |
54 |
55 | 56 | 57 | ``` 58 | 59 | - parent 60 | 61 | - 总 width:width + margin-left + margin-right 62 | - 总 height:width + margin-left + margin-right 63 | - 实际 content:width - border*2- padding*2=160 64 | 65 | ![border-box-parent](/images/html/border-box-parent.png) 66 | 67 | - children 68 | - 总 width:width - border*2- padding*2= 200-40=160 69 | - 总 height:height - border*2- padding*2= 200-40=160 70 | 71 | ![border-box-children](/images/html/border-box-children.png) 72 | 73 | ### IE 盒子模型 74 | 75 | - IE 盒子模型:`(margin+padding+border)\*2+width` 76 | - 默认使用 content-box 77 | 78 | ```html 79 | 80 | 81 | 82 | 83 | Document 84 | 101 | 102 | 103 |
104 |
105 |
106 | 107 | 108 | ``` 109 | 110 | - parent 111 | 112 | - 总 width:margin*2+border*2+padding*2+width=200+20*2+10*2+10*2=280 113 | - 总 height:margin*2+border*2+padding*2+height=200+20*2+10*2+10*2=280 114 | 115 | ![content-box-parent](/images/html/content-box-parent.png) 116 | 117 | - children 118 | - 总 width:parent width = 200 119 | - 总 height:parent height = 200 120 | 121 | ![content-box-children](/images/html/content-box-children.png) 122 | -------------------------------------------------------------------------------- /docs/interview/2018-8-31.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | 5 | # 2018 年 8 月 31 日面试题 6 | 7 | ## 以下代码运行结果 8 | 9 | 符合预期?(还是没看懂这道题目!) 10 | 11 | - 目前测试的结果是,入参大于 100 + 300 的时候,time span 的打印时间会在 0.0x 毫秒以下,否则 100ms 左右 12 | 13 | ```js 14 | /*demo1*/ 15 | function f1() { 16 | console.time('time span'); 17 | } 18 | function f2() { 19 | console.timeEnd('time span'); 20 | } 21 | setTimeout(f1, 100); 22 | setTimeout(f2, 200); 23 | function waitForMs1(n) { 24 | var now = Date.now(); 25 | while (Date.now() - now < n) {} 26 | } 27 | 28 | waitForMs1(500); 29 | /*demo2*/ 30 | function f3() { 31 | console.time('time span'); 32 | } 33 | function f4() { 34 | console.timeEnd('time span'); 35 | } 36 | setTimeout(f3, 1000); 37 | setTimeout(f4, 2000); 38 | function waitForMs2(n) { 39 | var now = Date.now(); 40 | while (Date.now() - now < n) {} 41 | } 42 | waitForMs2(500); 43 | ``` 44 | 45 | ::: tip 46 | 当时选的打印是约 500.077ms!回来一跑代码还是没看懂。 47 | 可以理解为?? 48 | ::: 49 | 50 | ## 以下哪个结果为真? 51 | 52 | - A. null instanceof Object 53 | - B. null == undefined 54 | - C. NaN ==NaN 55 | - D. false == undefined 56 | 57 | 1. `instanceof` 用法 58 | 59 | - 用于测试其原型链上是否存在一个构造函数的 prototype 属性。 60 | - 检测 constructor.prototype 是否存在参数 object 的原型链 61 | - 语法 `object instanceof constructor` 62 | - 最好分辨的是,使用关键字 `new` 出来 63 | 64 | ```js 65 | console.info({} instanceof Object); /*true*/ 66 | console.info(3 instanceof Number); /*false*/ 67 | ``` 68 | 69 | ## 关于 dom 事件流的表述哪些不正确? 70 | 71 | - A. 事件流包含两个阶段:事件捕获阶段,事件冒泡阶段 72 | - B. IE 跟标准浏览器对于 DOM 事件流实现不一样 73 | - C. 假设 parentEle 是 childEle 的父节点,绑定事件:parentEl.addEventListener('click',fn1.false), 74 | 和 childEle.addEventListener('click',fn2,false),当点击 childEle 的时候,fn1 先于 fn2 触发 75 | - D. addEventListener 第三个参数 true 代表支持捕获,false 代表不支持捕获 76 | 77 | ## 关于原型的说法不正确的是? 78 | 79 | ```js 80 | function a1(name, age) { 81 | this.name = name; 82 | this.age = age; 83 | } 84 | a1.prototype = { 85 | name: 'children', 86 | hasOwnerProperty: function () { 87 | return false; 88 | }, 89 | }; 90 | ``` 91 | 92 | - A.js 对象用两个不同的属性,一种是自身属性,另外一种是原型链上的继承的属性 `√` 93 | - B.instance.name == 'xx' 为 true `问题应该是这个,因为this指向,导致undefined,除非构造函数的时候入参` 94 | 95 | ```js 96 | var a = new a1('children')就可以 97 | ``` 98 | 99 | - C.instance.hasOwnProperty('age')结果是 false `√` 100 | - D.所有对象都继承来自 Object.prototype `√` 101 | 102 | ## 写程序 103 | 104 | 参考 105 | 基本相同的题目来源 106 | 107 | 1. 对象 A 直接调用对象 B 的某个方法,实现交互逻辑。但导致的问题是 A 和 B 紧密耦合,修改 B 可能造成 A 调用 B 的方法失效。 108 | 2. 为了解决耦合问题,设计为: 109 | 对象 A 生成消息->将消息通知给一个消息处理器 (Observable)->消息处理器将消息传递给 B 具体的调用过程变成: 110 | 111 | ```js 112 | A.emit('message', data); 113 | B.on('message', function (data) {}); 114 | ``` 115 | 116 | 请实现,消息代理功能。补充完成: 117 | 118 | ```js 119 | function EventEmitter() {} 120 | ``` 121 | 122 | ## js 写一个 ajax get 请求 123 | 124 | > emm,无数次都会被问到的面试题。 125 | 126 | ```js 127 | const xhr = new XMLHttpRequest(); 128 | xhr.open('GET', 'http://baidu.com', false); 129 | xhr.send('hello'); 130 | console.log(xhr.responseText); 131 | ``` 132 | -------------------------------------------------------------------------------- /docs/javascript/bom.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | --- 4 | 5 | # BOM 对象 6 | 7 | ## window 对象 8 | 9 | - 浏览器窗口 10 | 11 | ## Location 对象 12 | 13 | ::: info 14 | 是 window 对象也是 document 对象。其中 search 不实用,需要改造函数来实现 15 | ::: 16 | 17 | ::: tip 18 | 可以对这个对象增加新属性,但无法对原来的属性值作出随意变更赋值。 19 | ::: 20 | 21 | | 属性或方法 | 值 | 描述 | 22 | | --------------- | ------------------------------------- | -------------------------- | 23 | | ancestorOrigins | | | 24 | | hash | | | 25 | | hostname | `www.baidu.com` | | 26 | | href | `https://www.baidu.com/#dsad?dsd=dsd` | | 27 | | origin | `https://www.baidu.com` | | 28 | | pathname | `/` | | 29 | | protocol | `https` | | 30 | | search | | | 31 | | `assign(url)` | | 生成一个 `location` 并跳转 | 32 | | `reload()` | | | 33 | | `replace()` | | 传递 `true` ,则强制刷新 | 34 | | `toString()` | | | 35 | 36 | 往往通过 `query-string` 的 npm 库来增强使用, 37 | 38 | ## Navigator 对象 39 | 40 | ::: tip 41 | 可以去往这个对象增加新属性,但无法对原来的属性值作出随意变更赋值。 42 | 43 | 可以使用 `Object.defineProperty(navigator,'userAgent',{value:'foo'})` 来修改 44 | ::: 45 | 46 | - chrome 和 firefox 参数都有自己的,相同的属性或者同属性的值挺少的。 47 | - node 去判断用户代理字段的特征值,类似这种 npm 库 [`user-agent`](https://www.npmjs.com/package/user-agent) 48 | - 红宝石书中有一段检查浏览器、厂商、平台、操作系统的完全代码 49 | 50 | ## Screen 对象 51 | 52 | > 用处不大,表明客户端的能力,DPI 之类屏幕像素宽高等 53 | 54 | ## History 对象 55 | 56 | > 无法得知浏览过的 url,但可以通过实现前进和后退 57 | 58 | - go(-) 59 | 60 | | 属性或方法 | 值 | 描述 | 61 | | ----------- | -------------------------- | ---------------------- | 62 | | `go(1)` | 整数 | 整数,前进,负数,后退 | 63 | | `back()` | | 等同于 go(负数) | 64 | | `forward()` | | 等同于 go(正数) | 65 | | length | 整数,0 就是第一个目标页面 | 表示历史记录有几条 | 66 | 67 | ## 存储对象 68 | 69 | - `sessionStorage` 会话存储 70 | - `localStorage` 本地存储 71 | 72 | | 属性或方法 | 描述 | 实例 | 73 | | ------------------------ | ---- | ---- | 74 | | length | | | 75 | | `key(n)` | | | 76 | | `getItem(keyName)` | | | 77 | | `setItem(keyName,value)` | | | 78 | | `removeItem(keyName)` | | | 79 | | `clear()` | | | 80 | 81 | ### 比较 82 | 83 | `Cookie`、`Session`、`localStorage` 比较 84 | 85 | | 差异 | Cookie | Session | LocalStorage | 86 | | -------- | -------------- | -------------- | ------------ | 87 | | 存储 | 5K | 5M | 5M | 88 | | 生命周期 | 浏览器访问期间 | 浏览器访问期间 | 永久有效 | 89 | -------------------------------------------------------------------------------- /docs/javascript/type.md: -------------------------------------------------------------------------------- 1 | # 数据类型 2 | 3 | ## 基本类型 4 | 5 | | 数据类型 | 描述 | 6 | |--------------------------------------|------| 7 | | `null` | 基本类型 | 8 | | `undefined` | 基本类型 | 9 | | `string` | 基本类型 | 10 | | `number` | 基本类型 | 11 | | `boolean` | 基本类型 | 12 | | `symbol` | 基本类型 | 13 | | `bigint` | 基本类型 | 14 | | `object` | 引用类型 | 15 | | `function` | 引用类型 | 16 | | `array` | 引用类型 | 17 | 18 | :v: 19 | :u: 20 | :e: 21 | 22 | ## 类型转换 23 | 24 | ### 类型判断 25 | 26 | ```js 27 | const nul = null; 28 | const undefine = undefined; 29 | const bool = true; 30 | const num = 2020; 31 | const str = 'hello world'; 32 | const sys = Symbol(2020); 33 | ``` 34 | 35 | **typeof 判断**: 36 | 37 | ```js 38 | const nul = null; 39 | const undefine = undefined; 40 | const bool = true; 41 | const num = 2020; 42 | const str = 'hello world'; 43 | const sys = Symbol(2020); 44 | 45 | const obj = {name: 'hello'}; 46 | const fn = function () { 47 | }; 48 | const arr = [2020, 12, 20]; 49 | 50 | console.log(typeof nul); // object 51 | console.log(typeof undefine); //undefined 52 | console.log(typeof bool); //boolean 53 | console.log(typeof num); // number 54 | console.log(typeof str); // string 55 | console.log(typeof sys); // symbol 56 | 57 | console.log(typeof obj); // object 58 | console.log(typeof fn); // function 59 | console.log(typeof arr); // object 60 | ``` 61 | 62 | **instanceof**: 63 | 64 | - 用于检测引用类型,如 `array`、`object`、`function` 65 | 66 | ```js 67 | console.log(obj instanceof Object); // true 68 | console.log(fn instanceof Function); // true 69 | console.log(arr instanceof Array); // true 70 | ``` 71 | 72 | **constructor**: 73 | 74 | - 由于 `constructor` 是可被改变的,所以在这种方式并不安全 75 | 76 | ```js 77 | console.log(bool.constructor === Boolean); // true 78 | console.log(number.constructor === Number); // true 79 | console.log(str.constructor === String); // true 80 | console.log(obj.constructor === Object); // true 81 | console.log(fn.constructor === Function); // true 82 | console.log(arr.constructor === Array); // true 83 | console.log(sys.constructor === Symbol); // true 84 | 85 | console.log(nul.constructor === null); // error 86 | console.log(undefine.constructor === undefined) // error 87 | ``` 88 | 89 | **Object.prototype.toString.call**: 90 | 91 | - 较为安全判断 `js` 数据类型 92 | 93 | ```js 94 | console.log(Object.prototype.toString.call(nul)); // [object Null] 95 | console.log(Object.prototype.toString.call(undefine)); // [object Undefined] 96 | console.log(Object.prototype.toString.call(bool)); // [object Boolean] 97 | console.log(Object.prototype.toString.call(num)); // [object Number] 98 | console.log(Object.prototype.toString.call(str)); // [object String] 99 | console.log(Object.prototype.toString.call(sys)); // [object Symbol] 100 | console.log(Object.prototype.toString.call(obj)); // [object Object] 101 | console.log(Object.prototype.toString.call(fn)); // [object Function] 102 | console.log(Object.prototype.toString.call(arr)); // [object Array] 103 | ``` 104 | -------------------------------------------------------------------------------- /docs/leetcode/67-addBinary.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: auto 3 | navbar: auto 4 | --- 5 | 6 | # 67. 二进制求和 7 | 8 | 给你两个二进制字符串 a 和 b ,以二进制字符串的形式返回它们的和。 9 | 10 | 示例 1: 11 | 12 | ```shell 13 | 输入:a = "11", b = "1" 14 | 输出:"100" 15 | ``` 16 | 17 | ```shell 18 | 示例 2: 19 | 20 | 输入:a = "1010", b = "1011" 21 | 输出:"10101" 22 | `` 23 | ``` 24 | 25 | ## 解题思路 26 | 27 | - 先补齐缺失的位数 28 | - 从后往前索引使用 parseInt 相加,并记录当前进制 29 | 30 | ```js 31 | var addBinary = function (a, b) { 32 | const len = Math.max(a.length, b.length); // 获取最大长度是谁 33 | 34 | // 拉齐长度 35 | if (a.length < b.length) { 36 | a = '0'.repeat(b.length - a.length) + a; 37 | } else if (a.length > b.length) { 38 | b = '0'.repeat(a.length - b.length) + b; 39 | } 40 | 41 | // 存一下进制 42 | let radix = 0; 43 | 44 | let ab = ''; 45 | 46 | for (let index = len; index > 0; index--) { 47 | const i = index - 1; 48 | const aVal = a[i]; 49 | const bVal = b[i]; 50 | 51 | const currentVal = parseInt(aVal) + parseInt(bVal); 52 | 53 | // 思考下面的过程,逐个区分所有场景 54 | if (currentVal === 2 && radix === 1) { 55 | ab = '1' + ab; 56 | radix = 1; 57 | } else if (currentVal === 2 && radix === 0) { 58 | ab = '0' + ab; 59 | radix = 1; 60 | } else if (currentVal === 1 && radix === 1) { 61 | ab = '0' + ab; 62 | radix = 1; 63 | } else if (currentVal === 1 && radix === 0) { 64 | ab = '1' + ab; 65 | radix = 0; 66 | } else if (currentVal === 0 && radix === 1) { 67 | ab = '1' + ab; 68 | radix = 0; 69 | } else if (currentVal === 0 && radix === 0) { 70 | ab = '0' + ab; 71 | radix = 0; 72 | } 73 | if (i === 0 && radix === 1) { 74 | ab = '1' + ab; 75 | } 76 | } 77 | return ab; 78 | }; 79 | ``` 80 | 81 | 代码精简: 82 | 83 | - 默认进制为 0 84 | - 先加上进制,如果大于 1 则 进制 留存 1 否则 0 85 | - 计算最后一个索引的进制,如果 i === 0 且 进制为 1 则 加入 1 86 | - `sum % 2`,确认当前的值是什么,获得整除余数 87 | - `0 % 2 = 0` 88 | - `1 % 2 = 1` 89 | - `2 % 2 = 0` 90 | - `3 % 2 = 1` 91 | 92 | ```js 93 | var addBinary = function (a, b) { 94 | const len = Math.max(a.length, b.length); // 获取最大长度是谁 95 | 96 | // 拉齐长度 97 | if (a.length < b.length) { 98 | a = '0'.repeat(b.length - a.length) + a; 99 | } else if (a.length > b.length) { 100 | b = '0'.repeat(a.length - b.length) + b; 101 | } 102 | 103 | // 存一下进制 104 | let radix = 0; 105 | 106 | let ab = ''; 107 | 108 | for (let index = len; index > 0; index--) { 109 | const i = index - 1; 110 | const sum = parseInt(a[i]) + parseInt(b[i]) + radix; 111 | 112 | ab = (sum % 2) + ab; 113 | radix = sum > 1 ? 1 : 0; 114 | 115 | if (i === 0 && radix === 1) { 116 | ab = '1' + ab; 117 | } 118 | } 119 | return ab; 120 | }; 121 | ``` 122 | 123 | 优化的代码: 124 | 125 | ```js 126 | var addBinary = function (a, b) { 127 | let i = a.length - 1; 128 | let j = b.length - 1; 129 | let carry = 0; 130 | let result = []; 131 | 132 | while (i >= 0 || j >= 0 || carry > 0) { 133 | const digitA = i >= 0 ? parseInt(a[i--]) : 0; 134 | const digitB = j >= 0 ? parseInt(b[j--]) : 0; 135 | const sum = digitA + digitB + carry; 136 | 137 | result.unshift(sum % 2); 138 | carry = sum >> 1; // 等同于 Math.floor(sum / 2) 139 | } 140 | 141 | return result.join(''); 142 | }; 143 | ``` 144 | -------------------------------------------------------------------------------- /docs/frontend/es6/symbol.md: -------------------------------------------------------------------------------- 1 | # ES6 Symbol 枚举 2 | 3 | ## 概念 4 | 5 | - 属于 ES6 新的数据类型,与 `null`、`undefined`、`boolean`、`string`、`number` 这个五个一起被称为 `JavaScript` 六大基本数据类型。 6 | 7 | - `symbol` 是一种基本类型,不是对象,不用 `new` 产生。 8 | 9 | - 同时,它也不能被添加属性。 10 | 11 | **可通过 `Object.prototype.toString.call()`** 来判断其类型:`[object Symbol]` 12 | 13 | ## 用途 14 | 15 | **原因**:`es5` 对象的属性名是字符串,这容易造成属性名冲突。 16 | 17 | **解决**:`es6` 引入一种新的方法,确保对象上的每个属性名都是独一无二的 18 | 19 | ## 用法 20 | 21 | 参数:`string`、`object`,会被始终转为字符串,这里的参数仅仅作为描述 22 | 23 | 相同的参数,它的返回值也是不相同的。 24 | 25 | ```js 26 | const s1 = Symbol("he"); 27 | const s2 = Symbol("he"); 28 | 29 | console.log(s1 == s2); // false 30 | console.log(s1 === s2); // false 31 | ``` 32 | 33 | ## 约束 34 | 35 | - 无法与其他类型计算 36 | 37 | ```js 38 | const pluSy = Symbol("plus"); 39 | 40 | console.log(pluSy + "?"); 41 | ``` 42 | 43 | - **可被显式转为字符** 44 | 45 | ```js 46 | const st = Symbol("hello"); 47 | console.log(String(st)); // Symbol(hello) 48 | console.log(st.toString()); // Symbol(hello) 49 | ``` 50 | 51 | - **symbol 值可被转为布尔值,但不能转为数值** 52 | 53 | ```js 54 | const sy = Symbol(); 55 | console.log(Boolean(sy)); // true 56 | console.log(!sy); // false 57 | 58 | console.log(Number(sy)); // error 59 | console.log(sy + 2020); // error 60 | ``` 61 | 62 | - **symbol 值作为对象属性名是,无法使用点运算符** 63 | 64 | ```js 65 | const sy = Symbol(); 66 | const obj = {}; 67 | obj.sy = "hello world"; 68 | 69 | console.log(obj["sy"]); // "hello world" 70 | console.log(obj[sy]); // undefined 71 | ``` 72 | 73 | - **始终放在中括号中** 74 | 75 | ## 场景 76 | 77 | **唯一属性值**: 78 | 79 | ```js 80 | const sy = Symbol(); 81 | 82 | // 写法 1 83 | const obj = { 84 | [sy]: "world", 85 | }; 86 | 87 | // 写法 2 88 | obj[sy] = "hello"; 89 | 90 | // 写法 3 91 | Object.defineProperty(obj, sy, { value: "define value" }); 92 | 93 | console.log(obj[sy]); 94 | ``` 95 | 96 | **消除魔术字符串**: 97 | 98 | 魔术字符串值得是,在代码中多次出现,与代码形成耦合的某个具体的字符或数值。 99 | 100 | ```js 101 | function getArea(shape, ops) { 102 | let area = 0; 103 | 104 | switch (shape) { 105 | case "Triangle": // 魔术字符串 106 | area = 0.5 * ops.width * ops.height; 107 | break; 108 | } 109 | return area; 110 | } 111 | 112 | console.log(getArea("Triangle", { width: 90, height: 60 })); // 两次都出现这个字符串 `Triangle` 113 | ``` 114 | 115 | 常用的办法就是写成一个变量。 116 | 117 | ```js 118 | const obj = { 119 | triangle: "Triangle", 120 | }; 121 | function getArea(shape, ops) { 122 | let area = 0; 123 | 124 | switch (shape) { 125 | case obj.triangle: // 魔术字符串 126 | area = 0.5 * ops.width * ops.height; 127 | break; 128 | } 129 | return area; 130 | } 131 | 132 | console.log(getArea(obj.triangle, { width: 90, height: 60 })); // 两次都出现这个字符串 `Triangle` 133 | ``` 134 | 135 | 此时,消除了强耦合。 136 | 137 | 但这里的 `obj.triangle` 等于那个值不重要,只要确保不和其他 `obj` 属性值冲突即可。 138 | 139 | 所以,这里特别适用 `Symbol` 140 | 141 | ```js 142 | const obj = { 143 | triangle: Symbol(), 144 | }; 145 | function getArea(shape, ops) { 146 | let area = 0; 147 | 148 | switch (shape) { 149 | case obj.triangle: // 魔术字符串 150 | area = 0.5 * ops.width * ops.height; 151 | break; 152 | } 153 | return area; 154 | } 155 | 156 | console.log(getArea(obj.triangle, { width: 90, height: 60 })); // 两次都出现这个字符串 `Triangle` 157 | ``` 158 | 159 | **属性名的遍历**: 160 | 161 | ## 方法或属性 162 | 163 | - `Symbol.prototype.description` 164 | 165 | - `Symbol.for()` 166 | 167 | - `Symbol.keyFor()` 168 | 169 | - `Symbol.hasInstance` 170 | 171 | - `Symbol.isConcatSpreadable` 172 | 173 | - `Symbol.species` 174 | 175 | - `Symbol.match` 176 | 177 | - `Symbol.replace` 178 | 179 | - `Symbol.search` 180 | 181 | - `Symbol.split` 182 | 183 | - `Symbol.iterator` 184 | 185 | - `Symbol.toPrimitive` 186 | 187 | - `Symbol.toStringTag` 188 | 189 | - `Symbol.unscopables` 190 | -------------------------------------------------------------------------------- /docs/public/demos/css/main.min.css: -------------------------------------------------------------------------------- 1 | @media screen and (min-width: 1200px){.base64{width:32px;height:32px;background:url("data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wgARCAAgAHADASIAAhEBAxEB/8QAGgABAAMBAQEAAAAAAAAAAAAAAAIEBQEDBv/EABYBAQEBAAAAAAAAAAAAAAAAAAABAv/aAAwDAQACEAMQAAAB+/qW6O83uRyca2WTE2PLJsGjLE2wABUtrFW0lqysCv33EJgAB//EACAQAAMAAQQCAwAAAAAAAAAAAAECAwAEEhMUECAyNED/2gAIAQEAAQUCxXbs4CCPK0m53Dd7L91vhEvOIs/PzvNGfUCXK8M0rDteyo3ZxNPKZGmkrLCalYTQJFJ5tG/8f//EABYRAQEBAAAAAAAAAAAAAAAAACABEf/aAAgBAwEBPwGvH//EABgRAAIDAAAAAAAAAAAAAAAAAAEgAhFB/9oACAECAQE/AY64NP8A/8QAJxAAAQMDAQcFAAAAAAAAAAAAAQIRIQASMQMEEBMgIkGBMkBxcsH/2gAIAQEABj8CpaHgDc4kchCVpURljimcOO3PqfUUfitnVxHCmFrRSGKzprLSA3jvWoV3cQB7CI8VqOFtblVv5VhSFdLpGmml+u5SQSSgjnWtoI3C1OMTigoJxIkxRjMSXogAtiS9dIPkvRX3Me0//8QAIhABAAIBBAICAwAAAAAAAAAAAREhADFBUXEgYTChQJGx/9oACAEBAAE/IcQylQzQlwEglib+Gm/EK9sFRa5lZ8EvusayM8UJNt/vGMyZF0v8N8nrJkZ3Rt2/rGaW1oh9T0xUiyeDRiIvkwE8rhFfJRx5gZSg4giOjjoxGAtOgsGMAl2MdCaxAGw1dOCdDrGKEUevF7YyshqVUcXtgYCoT6PxP//aAAwDAQACAAMAAAAQ5Iww8889MMcc88//xAAYEQADAQEAAAAAAAAAAAAAAAABESAhcf/aAAgBAwEBPxA9HbLK/wD/xAAZEQEAAgMAAAAAAAAAAAAAAAABESBBUcH/2gAIAQIBAT8QIktdLqEM3//EAB8QAQEAAwEAAgMBAAAAAAAAAAERACExUSBBYZHwQP/aAAgBAQABPxDKMJdNK7b3FEQA2r9Yb8ROgeI/Z8FBXHksgHXHvmAsAEEHinSx/Xz/AIHuf1PMhNEyGlQbELUd0ag2KbCCDHvqh3PrOJ+RQdDF2LR9whO5LnQjRIVqKTriP2oYArSfQnHWBMvjW75QIV0Ptvzgwt02jvXcNqhE/GaZkM+TeInUBa+uW8aKiiNkBroA/RiLN0Bj6DRPINHmXQvGjytn4EMl+YjYcC1B4ayPG03aKE59v+T/2Q==")}.src{width:32px;height:32px;background:url("../../docs/.vuepress/public/images/src.jpg") no-repeat}}@media screen and (max-width: 750px){.base64{width:32px;height:32px;background:url("data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wgARCAAxAEEDASIAAhEBAxEB/8QAGgABAAMBAQEAAAAAAAAAAAAAAAIDBgUEAf/EABkBAQADAQEAAAAAAAAAAAAAAAACAwQBBf/aAAwDAQACEAMQAAAB+e6u3RK32Y7R1Vyqz+g7wRlfJFxLRZ3XRhhuBu+BDzp63nd5fkKL/lu6lJWt7fE+2R1mU6N9ef1ce2nPu8kZNtIAAAAAH//EACMQAAIBBAIBBQEAAAAAAAAAAAECAwAEERIQExQVICElMEH/2gAIAQEAAQUCErsaWNnrw5aaNk9qJoCCFnTV/U/rrdNnAJWsis8NAGtpY9lwdoo9VWALbUy5fQ8KdlvYcHrHZYw5LHVazW44tJvh0Dr0t3vmGETSNFX95jvGWvKi2luRKokVR+n/xAAgEQACAgEDBQAAAAAAAAAAAAABAgADEgQQERMhMDFC/9oACAEDAQE/AbHCjmLblFuBbDbiN3gbpEqZp0+zFYqeRM9rac4hrFRU+/B//8QAHhEAAgICAgMAAAAAAAAAAAAAAAECEQMQEhMwMUH/2gAIAQIBAT8BnJfC2Xq0TE601Z1wGrOJLHl7VJevB//EACkQAAECBAQEBwAAAAAAAAAAAAEAAhESMUEDEBNhICFRgSIjMDJCceH/2gAIAQEABj8CgAMuS+K58UbFRsVXzvb+qNgibDKuYw9kWmqhdBgqjh7ZbXzB6rVHdTrVPZE9OHTNbItNCtK68DaBYjHHfig8TKaQzUUpaYbFUc779X//xAAjEAABBAEEAgMBAAAAAAAAAAABABEhMRBBUWFxkaEgMOGx/9oACAEBAAE/IXwBQdpvhGIDsllFfkjER2C/xHyalCjZGBR2/wCq10xX/wCqajIxODJCL4TNxipBEDymjsHorSbMyaK5eyo0EknPOCg3t4UujAA9A6aAwYXv2rlOAYEKAvQPggLIXfgRfw80AmBitIsz8bqDEYA5R8TjVd17x/IzRcINAb0Vx6lFIyAv7fSJBQZzFbfb/9oADAMBAAIAAwAAABCDogT773jnzpvv0333333/xAAeEQEAAgEEAwAAAAAAAAAAAAABABExITBB8FFhwf/aAAgBAwEBPxBO8EAWTy9AXEtCCnETE44crO6OmT3LRLg1XiEgWxp92P/EAB0RAAMAAgIDAAAAAAAAAAAAAAABESFhEDAxQfD/2gAIAQIBAT8Q9VEUyhZx8bjwhPBW0UmT6pBBsOXZ2pvHR//EACcQAQABAwIGAgIDAAAAAAAAAAERACExQVEQYXGBkaGx8CDRMMHx/9oACAEBAAE/EBrZyf3RgmOqEFRIhMQx7zWZf2nPxTIQTEMesfjBS77lTPiNCpn5pnLJI3tT9r3x/X35oHLJK3vSZtBoRZj44CGgOJPt5K/1uECQDlC897z1pZEcX0K1/td5282pUBcW1PpWRgFrlPa0dOCWGdfhc2c1v0rmcF8AIepRY4QNEw97eK07S2c3WLVcRlk1XL2v5pwISnocMWOrFfRHAfDynRt1+6UHRQFa22Tq9L0om7UkOBhz52zNLPCJMAiPkPEcM28zvxFBERkTSgISxPyb1kdsNSd6SOwwAw3lUUWrBUbkCpjXmRxj+L//2Q==")} .src{width:32px;height:32px;background:url("../../docs/.vuepress/public/images/src-2.jpg") no-repeat}}.a{width:200px;height:200px;padding:50px;border:1px solid yellow} .a .b{width:100%;height:100%;border:1px solid green} .a .b:hover{background:#3f1b1b} .a .c+.b:hover{background:yellowgreen} 2 | -------------------------------------------------------------------------------- /docs/javascript/useful/deep-copy.md: -------------------------------------------------------------------------------- 1 | # 深浅拷贝 2 | 3 | 由于 `JavaScript` 存在值引用的数据类型,如 Object、Array,存在了赋值过程,被一同改变值的引用 4 | 5 | ```js 6 | const a = { name: 'Li' }; 7 | 8 | const b = a; 9 | 10 | b.name = 'Sa'; 11 | 12 | console.log(a, b); // 两者都是 Sa 13 | ``` 14 | 15 | ## 差异化 16 | 17 | ||浅拷贝|深拷贝| 18 | |---|---|---| 19 | |基本类型|复制|复制| 20 | |引用类型|只复制引用|复制| 21 | |复制范围|复制对象本身|递归复制对象所有类型的字段| 22 | |与原对象比较|共享数据|完全独立| 23 | |修改应用|会被影响|不会影响| 24 | |适用结构|简单|复杂| 25 | |`Object.assign`|✅|❎| 26 | |`拓展符...`|✅|❎| 27 | |`slice()`|✅|❎| 28 | |`concat()`|✅|❎| 29 | 30 | ### slice 浅拷贝用法 31 | 32 | ```js 33 | let originalArray = [1, 2, 3, { value: 4 }]; 34 | let copiedArray = originalArray.slice(); 35 | 36 | console.log(copiedArray); // 输出: [1, 2, 3, { value: 4 }] 37 | 38 | // 修改原始数组 39 | originalArray[3].value = 5; 40 | 41 | console.log(originalArray); // 输出: [1, 2, 3, { value: 5 }] 42 | console.log(copiedArray); // 输出: [1, 2, 3, { value: 5 }] 43 | 44 | // 修改原始数组中的 基本类型 45 | originalArray[3].value = 11; 46 | 47 | console.log(originalArray); // 输出: [11, 2, 3, { value: 5 }] 48 | console.log(copiedArray); // 输出: [1, 2, 3, { value: 5 }] 49 | ``` 50 | 51 | ## 浅拷贝 52 | 53 | 仅处理第一个层级 54 | 55 | **通过 `Object.assign` 解决**: 56 | 57 | ```js 58 | const a = { name: 'Li' }; 59 | const b = Object.assign({}, a); 60 | // 此时将 a 的值赋给 b 61 | b.name = 'Sa'; // 再改变 b 的值,a 不会被改变 62 | console.log(a, b); 63 | ``` 64 | 65 | **通过对象展开符 `...`**: 66 | 67 | ```js 68 | const a = { name: 'Li' }; 69 | const b = { ...a }; 70 | b.name = 'Sa'; 71 | console.log(a, b); 72 | ``` 73 | 74 | ## 深拷贝 75 | 76 | **通过 `JSON.parse(JSON.stringify(obj))`**: 77 | 78 | ```js 79 | const a = { 80 | name: 'Li', 81 | location: { 82 | country: 'China', 83 | }, 84 | }; 85 | 86 | const b = JSON.parse(JSON.stringify(a)); 87 | 88 | b.location.country = 'Thailand'; 89 | 90 | console.log(a, b); 91 | ``` 92 | 93 | 弊端: 94 | 95 | - 忽略 `undefined` 96 | - 忽略 `symbol` 97 | - 无法序列化函数 98 | - 不能解决循环应用的对象 99 | 100 | ```js 101 | let obj = { 102 | a: 1, 103 | b: { 104 | c: 2, 105 | d: 3, 106 | }, 107 | }; 108 | obj.c = obj.b; 109 | obj.e = obj.a; 110 | obj.b.c = obj.c; 111 | obj.b.d = obj.b; 112 | obj.b.e = obj.b.c; 113 | const newObj = JSON.parse(JSON.stringify(obj)); 114 | console.log(newObj); 115 | ``` 116 | 117 | ### lodash 深克隆 118 | 119 | [lodash deepClone](https://lodash.com/docs##cloneDeep) 120 | 121 | 一种通过浏览器提供的深拷贝机制 122 | 123 | ```js 124 | function structuralClone(obj) { 125 | return new Promise((resolve) => { 126 | const { port1, port2 } = new MessageChannel(); 127 | port2.onmessage = (ev) => resolve(ev.data); 128 | port1.postMessage(obj); 129 | }); 130 | } 131 | 132 | var obj = { 133 | a: 1, 134 | b: { 135 | c: obj, 136 | }, 137 | }( 138 | // 注意该方法是异步的 139 | // 可以处理 undefined 和循环引用对象 140 | async () => { 141 | const clone = await structuralClone(obj); 142 | } 143 | )(); 144 | ``` 145 | 146 | 实例: 147 | 148 | ```js 149 | /** 150 | * deep copy 151 | * target copy to source 152 | * 1. 假设都是对象 153 | */ 154 | function deepCopy(target) { 155 | let result; 156 | 157 | if (typeof target === 'object') { 158 | // 数组 159 | if (Array.isArray(target)) { 160 | // null 161 | } else if (target == null) { 162 | result = null; 163 | 164 | // function 165 | } else if (Object.prototype.toString.call(target) == '[object Function]') { 166 | } else if (Object.prototype.toString.call(target) === '[object Object]') { 167 | result = {}; 168 | 169 | for (let key in target) { 170 | result[key] = deepCopy(target[key]); 171 | } 172 | } 173 | // Date 174 | // RegExp 175 | else { 176 | result = target; 177 | } 178 | // object 179 | } else { 180 | result = target; 181 | } 182 | 183 | return result; 184 | } 185 | 186 | const a = { 187 | a: 'a object', 188 | name: 'a', 189 | }; 190 | 191 | const b = { 192 | b: 'b object', 193 | name: 'b', 194 | }; 195 | 196 | const newOne = deepCopy(a); 197 | 198 | console.log('newOne=>', newOne); 199 | ``` 200 | --------------------------------------------------------------------------------