diff --git a/404.html b/404.html index 20ec79c..e7034be 100644 --- a/404.html +++ b/404.html @@ -13,8 +13,8 @@
Skip to content

404

PAGE NOT FOUND

But if you don't change your direction, and if you keep looking, you may end up where you are heading.
- + \ No newline at end of file diff --git a/assets/zjw_binary-search.md.4a6149b9.js b/assets/zjw_binary-search.md.4a6149b9.js new file mode 100644 index 0000000..7abae92 --- /dev/null +++ b/assets/zjw_binary-search.md.4a6149b9.js @@ -0,0 +1,64 @@ +import{_ as s,c as n,o as a,R as l}from"./chunks/framework.3876c926.js";const A=JSON.parse('{"title":"二分查找","description":"","frontmatter":{},"headers":[],"relativePath":"zjw/binary-search.md"}'),p={name:"zjw/binary-search.md"},o=l(`

二分查找

基本实现

js
function binarySearch(nums, target) {
+  var left = 0,
+    right = nums.length - 1;
+
+  while (left <= right) {
+    var mid = left + Math.floor((right - left) / 2);
+
+    if (nums[mid] === target) {
+      return mid;
+    } else if (nums[mid] < target) {
+      left = mid + 1;
+    } else if (nums[mid] > target) {
+      right = mid - 1;
+    }
+  }
+
+  return -1;
+}

寻找左侧边界

js
function leftBound(nums, target) {
+  var left = 0,
+    right = nums.length - 1;
+
+  while (left <= right) {
+    var mid = left + Math.floor((right - left) / 2);
+
+    if (nums[mid] === target) {
+      // 向左收缩
+      right = mid - 1;
+    } else if (nums[mid] < target) {
+      left = mid + 1;
+    } else if (nums[mid] > target) {
+      right = mid - 1;
+    }
+  }
+
+  // left = right + 1 退出循环,mid = right + 1 所以 left = mid
+  if (left >= nums.length || nums[left] !== target) {
+    return -1;
+  }
+
+  return left;
+}

寻找右侧边界

js
function rightBound(nums, target) {
+  var left = 0,
+    right = nums.length - 1;
+
+  while (left <= right) {
+    var mid = left + Math.floor((right - left) / 2);
+
+    if (nums[mid] === target) {
+      // 向右收缩
+      left = mid + 1;
+    } else if (nums[mid] < target) {
+      left = mid + 1;
+    } else if (nums[mid] > target) {
+      right = mid - 1;
+    }
+  }
+
+  // right = left - 1 退出循环,mid = left - 1 所以 right = mid
+  if (right < 0 || nums[right] !== target) {
+    return -1;
+  }
+
+  return right;
+}
`,7),t=[o];function e(c,r,F,y,D,C){return a(),n("div",null,t)}const f=s(p,[["render",e]]);export{A as __pageData,f as default}; diff --git a/assets/zjw_binary-search.md.4a6149b9.lean.js b/assets/zjw_binary-search.md.4a6149b9.lean.js new file mode 100644 index 0000000..d7e8551 --- /dev/null +++ b/assets/zjw_binary-search.md.4a6149b9.lean.js @@ -0,0 +1 @@ +import{_ as s,c as n,o as a,R as l}from"./chunks/framework.3876c926.js";const A=JSON.parse('{"title":"二分查找","description":"","frontmatter":{},"headers":[],"relativePath":"zjw/binary-search.md"}'),p={name:"zjw/binary-search.md"},o=l("",7),t=[o];function e(c,r,F,y,D,C){return a(),n("div",null,t)}const f=s(p,[["render",e]]);export{A as __pageData,f as default}; diff --git a/assets/zjw_data-structure.md.8a138e00.js b/assets/zjw_data-structure.md.ff8b49fb.js similarity index 99% rename from assets/zjw_data-structure.md.8a138e00.js rename to assets/zjw_data-structure.md.ff8b49fb.js index 66818a5..dbd4175 100644 --- a/assets/zjw_data-structure.md.8a138e00.js +++ b/assets/zjw_data-structure.md.ff8b49fb.js @@ -1,4 +1,4 @@ -import{_ as s,c as n,o as a,R as l}from"./chunks/framework.3876c926.js";const i=JSON.parse('{"title":"数据结构","description":"","frontmatter":{},"headers":[],"relativePath":"zjw/data-structure.md"}'),p={name:"zjw/data-structure.md"},o=l(`

数据结构

优先队列

js
class PriorityQueue {
+import{_ as s,c as n,o as a,R as l}from"./chunks/framework.3876c926.js";const i=JSON.parse('{"title":"数据结构","description":"","frontmatter":{},"headers":[],"relativePath":"zjw/data-structure.md"}'),p={name:"zjw/data-structure.md"},o=l(`

数据结构

优先队列

js
class PriorityQueue {
   size = 0;
   pq = [];
 
diff --git a/assets/zjw_data-structure.md.8a138e00.lean.js b/assets/zjw_data-structure.md.ff8b49fb.lean.js
similarity index 100%
rename from assets/zjw_data-structure.md.8a138e00.lean.js
rename to assets/zjw_data-structure.md.ff8b49fb.lean.js
diff --git a/assets/zjw_linked-list.md.1759d3cb.js b/assets/zjw_linked-list.md.826dff0c.js
similarity index 98%
rename from assets/zjw_linked-list.md.1759d3cb.js
rename to assets/zjw_linked-list.md.826dff0c.js
index 219824a..9b26d2c 100644
--- a/assets/zjw_linked-list.md.1759d3cb.js
+++ b/assets/zjw_linked-list.md.826dff0c.js
@@ -3,7 +3,7 @@ import{_ as s,c as n,o as a,R as l}from"./chunks/framework.3876c926.js";const i=
   this.next = null;
 }
 
-console.log(build([1, 2, 3]));
js
function build(nums) {
+console.log(build([1, 2, 3]));
js
function build(nums) {
   var dummy = new ListNode();
   var p = dummy;
 
@@ -22,7 +22,7 @@ import{_ as s,c as n,o as a,R as l}from"./chunks/framework.3876c926.js";const i=
   node.next = build(nums, start + 1);
 
   return node;
-}

反转

js
function reverse(head) {
+}

反转

js
function reverse(head) {
   var pre = null,
     cur = head;
 
@@ -105,4 +105,4 @@ import{_ as s,c as n,o as a,R as l}from"./chunks/framework.3876c926.js";const i=
     this.remove(first);
     return first;
   }
-}
`,11),e=[o];function t(c,r,F,y,D,A){return a(),n("div",null,e)}const d=s(p,[["render",t]]);export{i as __pageData,d as default}; +}
`,11),e=[o];function t(c,r,F,y,D,C){return a(),n("div",null,e)}const d=s(p,[["render",t]]);export{i as __pageData,d as default}; diff --git a/assets/zjw_linked-list.md.1759d3cb.lean.js b/assets/zjw_linked-list.md.826dff0c.lean.js similarity index 82% rename from assets/zjw_linked-list.md.1759d3cb.lean.js rename to assets/zjw_linked-list.md.826dff0c.lean.js index 161ec07..7dbe71c 100644 --- a/assets/zjw_linked-list.md.1759d3cb.lean.js +++ b/assets/zjw_linked-list.md.826dff0c.lean.js @@ -1 +1 @@ -import{_ as s,c as n,o as a,R as l}from"./chunks/framework.3876c926.js";const i=JSON.parse('{"title":"链表","description":"","frontmatter":{},"headers":[],"relativePath":"zjw/linked-list.md"}'),p={name:"zjw/linked-list.md"},o=l("",11),e=[o];function t(c,r,F,y,D,A){return a(),n("div",null,e)}const d=s(p,[["render",t]]);export{i as __pageData,d as default}; +import{_ as s,c as n,o as a,R as l}from"./chunks/framework.3876c926.js";const i=JSON.parse('{"title":"链表","description":"","frontmatter":{},"headers":[],"relativePath":"zjw/linked-list.md"}'),p={name:"zjw/linked-list.md"},o=l("",11),e=[o];function t(c,r,F,y,D,C){return a(),n("div",null,e)}const d=s(p,[["render",t]]);export{i as __pageData,d as default}; diff --git a/assets/zjw_sort.md.bdb84827.js b/assets/zjw_sort.md.c1426320.js similarity index 99% rename from assets/zjw_sort.md.bdb84827.js rename to assets/zjw_sort.md.c1426320.js index 5d7a568..2d78e2a 100644 --- a/assets/zjw_sort.md.bdb84827.js +++ b/assets/zjw_sort.md.c1426320.js @@ -59,7 +59,7 @@ import{_ as s,c as n,o as a,R as l}from"./chunks/framework.3876c926.js";const p= } } -Merge.sort([5, 2, 3, 1]);

快速排序

js
function quickSort(nums) {
+Merge.sort([5, 2, 3, 1]);

快速排序

js
function quickSort(nums) {
   // 洗牌降低退化成一个链表的概率
   shuffle(nums);
   sort(nums, 0, nums.length - 1);
diff --git a/assets/zjw_sort.md.bdb84827.lean.js b/assets/zjw_sort.md.c1426320.lean.js
similarity index 100%
rename from assets/zjw_sort.md.bdb84827.lean.js
rename to assets/zjw_sort.md.c1426320.lean.js
diff --git a/assets/zjw_webpack.md.2388b9aa.js b/assets/zjw_webpack.md.f23ad039.js
similarity index 82%
rename from assets/zjw_webpack.md.2388b9aa.js
rename to assets/zjw_webpack.md.f23ad039.js
index d60a768..8a5e4ba 100644
--- a/assets/zjw_webpack.md.2388b9aa.js
+++ b/assets/zjw_webpack.md.f23ad039.js
@@ -1,4 +1,4 @@
-import{_ as a,c as s,o as l,R as o}from"./chunks/framework.3876c926.js";const h=JSON.parse('{"title":"webpack 总览","description":"","frontmatter":{},"headers":[],"relativePath":"zjw/webpack.md"}'),e={name:"zjw/webpack.md"},n=o(`

webpack 总览

loader 用于转换某些类型的模块,插件则用于扩展 webpack 功能,通过注入钩子参与构建流程

构建流程

  1. 初始化参数
  2. 通过参数初始化 Compiler 对象,加载所有配置的插件,执行 run 方法开始编译
  3. 根据 entry 递归找到所有依赖,并根据文件类型,使用配置 loader 处理文件
  4. 完成所有模块转换后,构建依赖图
  5. 根据依赖图组装成一个个包含多模块的 chunk,再把 chunk 加入输出列表(插件最后修改输出内容时机)
  6. 根据配置确定输出内容的路径与文件名,写入文件系统

打包速度优化(简言之:减少打包量、并行、缓存、预构建)

  • 缩小处理文件
    • resolve.alias:直接指定打包好的代码(仅开发)
    • 优化 loader 配置:开启缓存、include 减少匹配文件
    • 减少文件匹配路径:resolve 匹配规则
    • 优化解析规则:module.noParse 指定不使用模块化解析文件
    • 按需加载
    • 懒编译
  • 并行打包
  • 构建缓存
  • 模块联邦

webpack HRM 原理

webpack-dev-server 向网页注入用于连接开发服务的客户端代码,在代码变更时编译出新的补丁文件,发送到网页执行

当模块变更后,更新事件会向上传递,直到某层接受了当前变化的模块,就会调用 callback 去执行自定义逻辑。当上抛到最外层没有被接受,就会刷新整个网页

js
if (module.hot) {
+import{_ as a,c as s,o as l,R as o}from"./chunks/framework.3876c926.js";const h=JSON.parse('{"title":"webpack 总览","description":"","frontmatter":{},"headers":[],"relativePath":"zjw/webpack.md"}'),e={name:"zjw/webpack.md"},n=o(`

webpack 总览

loader 用于转换某些类型的模块,插件则用于扩展 webpack 功能,通过注入钩子参与构建流程

构建流程

  1. 初始化参数
  2. 通过参数初始化 Compiler 对象,加载所有配置的插件,执行 run 方法开始编译
  3. 根据 entry 递归找到所有依赖,并根据文件类型,使用配置 loader 处理文件
  4. 完成所有模块转换后,构建依赖图
  5. 根据依赖图组装成一个个包含多模块的 chunk,再把 chunk 加入输出列表(插件最后修改输出内容时机)
  6. 根据配置确定输出内容的路径与文件名,写入文件系统

打包速度优化(简言之:减少打包量、并行、缓存、预构建)

  • 缩小处理文件
    • resolve.alias:直接指定打包好的代码(仅开发)
    • 优化 loader 配置:开启缓存、include 减少匹配文件
    • 减少文件匹配路径:resolve 匹配规则
    • 优化解析规则:module.noParse 指定不使用模块化解析文件
    • 按需加载
    • 懒编译
  • 并行打包
  • 构建缓存
  • 模块联邦

webpack4 打包速度优化文档【旧】

webpack HRM 原理

webpack-dev-server 向网页注入用于连接开发服务的客户端代码,在代码变更时编译出新的补丁文件,发送到网页执行

当模块变更后,更新事件会向上传递,直到某层接受了当前变化的模块,就会调用 callback 去执行自定义逻辑。当上抛到最外层没有被接受,就会刷新整个网页

js
if (module.hot) {
   module.hot.accept(['./App'], () => {
     render(<App />, window.document.getElementById('app'));
   });
@@ -6,4 +6,4 @@ import{_ as a,c as s,o as l,R as o}from"./chunks/framework.3876c926.js";const h=
   // 用正则去匹配要用该 loader 转换的 CSS 文件
   test: /\\.css$/,
   use: ['style-loader', 'css-loader?minimize']
-}
  • use 属性由 loader 名称组成的数组,loader 从后往前执行
  • 每个 loader 可以通过 URL querystring 方式传入参数,也可以通过对象形式传入 { loader: 'css-loader', options: { minimize: true } }
  • 内联方式使用 loader,import '!style-loader!css-loader?minimize!./styles.css'
`,19),p=[n];function t(r,c,i,F,y,D){return l(),s("div",null,p)}const m=a(e,[["render",t]]);export{h as __pageData,m as default}; +}
  • use 属性由 loader 名称组成的数组,loader 从后往前执行
  • 每个 loader 可以通过 URL querystring 方式传入参数,也可以通过对象形式传入 { loader: 'css-loader', options: { minimize: true } }
  • 内联方式使用 loader,import '!style-loader!css-loader?minimize!./styles.css'

loader 执行循序

`,21),p=[n];function t(r,c,i,F,y,d){return l(),s("div",null,p)}const m=a(e,[["render",t]]);export{h as __pageData,m as default}; diff --git a/assets/zjw_webpack.md.2388b9aa.lean.js b/assets/zjw_webpack.md.f23ad039.lean.js similarity index 64% rename from assets/zjw_webpack.md.2388b9aa.lean.js rename to assets/zjw_webpack.md.f23ad039.lean.js index 2a13ee0..d569913 100644 --- a/assets/zjw_webpack.md.2388b9aa.lean.js +++ b/assets/zjw_webpack.md.f23ad039.lean.js @@ -1 +1 @@ -import{_ as a,c as s,o as l,R as o}from"./chunks/framework.3876c926.js";const h=JSON.parse('{"title":"webpack 总览","description":"","frontmatter":{},"headers":[],"relativePath":"zjw/webpack.md"}'),e={name:"zjw/webpack.md"},n=o("",19),p=[n];function t(r,c,i,F,y,D){return l(),s("div",null,p)}const m=a(e,[["render",t]]);export{h as __pageData,m as default}; +import{_ as a,c as s,o as l,R as o}from"./chunks/framework.3876c926.js";const h=JSON.parse('{"title":"webpack 总览","description":"","frontmatter":{},"headers":[],"relativePath":"zjw/webpack.md"}'),e={name:"zjw/webpack.md"},n=o("",21),p=[n];function t(r,c,i,F,y,d){return l(),s("div",null,p)}const m=a(e,[["render",t]]);export{h as __pageData,m as default}; diff --git a/hashmap.json b/hashmap.json index 76442e4..e2dc401 100644 --- a/hashmap.json +++ b/hashmap.json @@ -1 +1 @@ -{"zjw_bfc.md":"bf39e00f","zjw_binary-tree.md":"b08eff68","zjw_data-structure.md":"8a138e00","zjw_koa-middleware.md":"5b834bb2","zjw_linked-list.md":"1759d3cb","zjw_react-router.md":"b0bc65d4","zjw_sandbox.md":"0865631e","zjw_babel-plugin-import.md":"b3fe9f86","zjw_webpack.md":"2388b9aa","zjw_前端常见手写代码.md":"2bdbb8db","zjw_babel-plugin-taro-page-hoc.md":"c5b8e797","zjw_webpack-pack-optimization.md":"bd8e6393","zjw_sort.md":"bdb84827","zjw_transform-tree.md":"4415d31c","index.md":"ecf03cad","zjw_(0_fn)().md":"90153474","zjw_api-cache.md":"47c00025","zjw_auto-test.md":"eaf268b9"} +{"zjw_babel-plugin-taro-page-hoc.md":"c5b8e797","zjw_babel-plugin-import.md":"b3fe9f86","zjw_bfc.md":"bf39e00f","zjw_(0_fn)().md":"90153474","index.md":"ecf03cad","zjw_linked-list.md":"826dff0c","zjw_api-cache.md":"47c00025","zjw_binary-tree.md":"b08eff68","zjw_auto-test.md":"eaf268b9","zjw_react-router.md":"b0bc65d4","zjw_binary-search.md":"4a6149b9","zjw_前端常见手写代码.md":"2bdbb8db","zjw_koa-middleware.md":"5b834bb2","zjw_sort.md":"c1426320","zjw_data-structure.md":"ff8b49fb","zjw_webpack.md":"f23ad039","zjw_sandbox.md":"0865631e","zjw_transform-tree.md":"4415d31c","zjw_webpack-pack-optimization.md":"bd8e6393"} diff --git a/index.html b/index.html index 3c64fcd..760d537 100644 --- a/index.html +++ b/index.html @@ -15,9 +15,9 @@ - - + + \ No newline at end of file diff --git a/zjw/(0,fn)().html b/zjw/(0,fn)().html index eadfa02..3ad8886 100644 --- a/zjw/(0,fn)().html +++ b/zjw/(0,fn)().html @@ -15,7 +15,7 @@ -
Skip to content
大纲

从模块编译结果学习 (0,fn)() 用法

例如下面示例代码

js
export function say(name) {
+    
Skip to content
大纲

从模块编译结果学习 (0,fn)() 用法

例如下面示例代码

js
export function say(name) {
   return `hello ${name}`;
 }
js
import { say } from './hello.js';
 say('world');

当我们使用 babel 编译后,出现如下结果

js
var _hello = require('./hello.js');
@@ -32,8 +32,8 @@
 moduleA.say();
 // undefined
 (0, moduleA.say)();

这样调用后,等于函数 say 在 b 模块上下文下执行,从而保证执行上下文的正确

- + \ No newline at end of file diff --git a/zjw/api-cache.html b/zjw/api-cache.html index a5b11e8..e5b2a02 100644 --- a/zjw/api-cache.html +++ b/zjw/api-cache.html @@ -15,7 +15,7 @@ -
Skip to content
大纲

请求缓存

在 PaaS 组件或者路由中间件内发起的重复请求,多数情况下可以通过请求缓存合并成一个请求

需求

  • 扩展现有请求方法
  • 合并同一时间内的重复请求

定义缓存结构

js
export class MapCache {
+    
Skip to content
大纲

请求缓存

在 PaaS 组件或者路由中间件内发起的重复请求,多数情况下可以通过请求缓存合并成一个请求

需求

  • 扩展现有请求方法
  • 合并同一时间内的重复请求

定义缓存结构

js
export class MapCache {
   map = new Map();
 
   static getKey(parmas) {
@@ -70,8 +70,8 @@
 
 // 使用缓存
 request({ url: 'http://api.twitter.com', params: { a: 1 } }, true);
- + \ No newline at end of file diff --git a/zjw/auto-test.html b/zjw/auto-test.html index fb9d590..ad8e20d 100644 --- a/zjw/auto-test.html +++ b/zjw/auto-test.html @@ -15,7 +15,7 @@ -
Skip to content
大纲

前端自动化测试

现状

技术选型

技术选择:jest+@testing-library/react+playwright

bash
yarn add -D jest @playwright/test babel-jest jest-environment-jsdom react-test-renderer @testing-library/react @types/jest

cypress 使用中的问题

流程与规范

目录与命名规范

  • 单元测试一般放在对应目录的 __tests__文件夹下,命名为测试代码的文件名中加 .test
  • e2e 测试放在根目录 e2e 下,命名 xxxx.test.ts

组件测试

typescript
import { render } from '@testing-library/react';
+    
Skip to content
大纲

前端自动化测试

现状

技术选型

技术选择:jest+@testing-library/react+playwright

bash
yarn add -D jest @playwright/test babel-jest jest-environment-jsdom react-test-renderer @testing-library/react @types/jest

cypress 使用中的问题

流程与规范

目录与命名规范

  • 单元测试一般放在对应目录的 __tests__文件夹下,命名为测试代码的文件名中加 .test
  • e2e 测试放在根目录 e2e 下,命名 xxxx.test.ts

组件测试

typescript
import { render } from '@testing-library/react';
 import IncPrice from '.';
 
 jest.mock('antd-mobile/es/utils/native-props', () => {
@@ -128,9 +128,9 @@
 
     postMsgToQw(msg);
   }
-}

完整例子:https://github.com/dobble11/daydayup-playground/tree/main/vite-react-playwright

- +}

完整例子:https://github.com/dobble11/daydayup-playground/tree/main/vite-react-playwright

+ \ No newline at end of file diff --git a/zjw/babel-plugin-import.html b/zjw/babel-plugin-import.html index fd249f0..eb61b80 100644 --- a/zjw/babel-plugin-import.html +++ b/zjw/babel-plugin-import.html @@ -15,7 +15,7 @@ -
Skip to content
大纲

实现导入转换 babel 插件

转换 antd 导入为按需加载,例如

js
import { Button } from 'antd'
+    
Skip to content
大纲

实现导入转换 babel 插件

转换 antd 导入为按需加载,例如

js
import { Button } from 'antd'
 
 ⬇️    ⬇️     ⬇️
 import Button from 'antd/es/button'
@@ -97,8 +97,8 @@
 }

遇到的问题

  • @babel/cli 默认只编译 js 文件,会忽略 ts 文件,需要设置 --extensions '.ts'"presets": ["@babel/preset-typescript"](.babelrc)
  • ts 文件下应用插件不生效,由于 @babel/preset-typescript onlyRemoveTypeImports 选项默认值为 false 移除未使用的导入,可以设置为 true 仅移除类型导入,或者使用导入变量,例如
diff
import { Button, Card } from 'antd';
 
 + console.log(Button, Card)

相关资源

- + \ No newline at end of file diff --git a/zjw/babel-plugin-taro-page-hoc.html b/zjw/babel-plugin-taro-page-hoc.html index 85a09ac..d52a22a 100644 --- a/zjw/babel-plugin-taro-page-hoc.html +++ b/zjw/babel-plugin-taro-page-hoc.html @@ -15,7 +15,7 @@ -
Skip to content
大纲

如何解决 Taro 页面无法异步渲染问题

当使用 Taro 开发时,要实现拦截页面渲染做一些异步操作(例如单点登录,前置检查等)

举个自动登录场景,当访问页面链接上带有登录凭证 (ticket) 时,需要调用后端接口实现登录操作,在请求过程中展示一个 loading 样式,我们很容易想到通过入口组件(app.tsx)去拦截子元素(this.props.children)渲染实现

Taro H5 端实现

tsx
class App extends Component {
+    
Skip to content
大纲

如何解决 Taro 页面无法异步渲染问题

当使用 Taro 开发时,要实现拦截页面渲染做一些异步操作(例如单点登录,前置检查等)

举个自动登录场景,当访问页面链接上带有登录凭证 (ticket) 时,需要调用后端接口实现登录操作,在请求过程中展示一个 loading 样式,我们很容易想到通过入口组件(app.tsx)去拦截子元素(this.props.children)渲染实现

Taro H5 端实现

tsx
class App extends Component {
   state = {
     loading: false,
   };
@@ -121,8 +121,8 @@
 ⬇️     ⬇️     ⬇️
 import __hoc__ from 'src/component/hoc'
 export default __hoc__(Home)

更完整的实现:https://github.com/epeejs/babel-plugin-taro-page-hoc

- + \ No newline at end of file diff --git a/zjw/bfc.html b/zjw/bfc.html index 210176f..5a21d46 100644 --- a/zjw/bfc.html +++ b/zjw/bfc.html @@ -15,9 +15,9 @@ -
Skip to content
大纲

块级格式化上下文(Block Formatting Context)

它决定了元素如何对其内容进行定位,以及与其它元素的关系和相互作用

简单解析:BFC 创建一个完全独立的布局环境,让空间里子元素不会影响到外面布局

用于定位与清除浮动

  • 包含内部浮动
  • 排除外部浮动
  • 阻止外边距重叠

创建 BFC 的主要方式

  • html 元素(display: flow-root)
  • 定位与布局方式,position:absolutefixed;float:值不为 none;display:inline-blocktableflexgrid
  • 溢出行为,overflow 值不为 visible 的块元素

扩展

两栏布局,一列固定宽度,一列自适应

  • float + BFC 或 margin-left
  • absolute + margin-left
  • inline-block 设置 width:<percentage>
  • table
  • flex
  • grid

float + BFC 或 margin-left (父元素高度塌陷问题)

absolute + margin-left

inline-block(内联块之间空白符会当作一个字符,可以通过 font-size:0 消除)

table(未设置宽的一列自动填充剩余空间)

flex

grid

代码仓库:https://github.com/dobble11/daydayup-playground/blob/main/two-col-layout/index.html

- +
Skip to content
大纲

块级格式化上下文(Block Formatting Context)

它决定了元素如何对其内容进行定位,以及与其它元素的关系和相互作用

简单解析:BFC 创建一个完全独立的布局环境,让空间里子元素不会影响到外面布局

用于定位与清除浮动

  • 包含内部浮动
  • 排除外部浮动
  • 阻止外边距重叠

创建 BFC 的主要方式

  • html 元素(display: flow-root)
  • 定位与布局方式,position:absolutefixed;float:值不为 none;display:inline-blocktableflexgrid
  • 溢出行为,overflow 值不为 visible 的块元素

扩展

两栏布局,一列固定宽度,一列自适应

  • float + BFC 或 margin-left
  • absolute + margin-left
  • inline-block 设置 width:<percentage>
  • table
  • flex
  • grid

float + BFC 或 margin-left (父元素高度塌陷问题)

absolute + margin-left

inline-block(内联块之间空白符会当作一个字符,可以通过 font-size:0 消除)

table(未设置宽的一列自动填充剩余空间)

flex

grid

代码仓库:https://github.com/dobble11/daydayup-playground/blob/main/two-col-layout/index.html

+ \ No newline at end of file diff --git a/zjw/binary-search.html b/zjw/binary-search.html new file mode 100644 index 0000000..502f033 --- /dev/null +++ b/zjw/binary-search.html @@ -0,0 +1,86 @@ + + + + + + 二分查找 | daydayup + + + + + + + + + + + +
Skip to content
大纲
+ + + + \ No newline at end of file diff --git a/zjw/binary-tree.html b/zjw/binary-tree.html index 0d297b2..bf42828 100644 --- a/zjw/binary-tree.html +++ b/zjw/binary-tree.html @@ -15,7 +15,7 @@ -
Skip to content
大纲

二叉树

  • 满二叉树(完美二叉树):除了叶节点,每个节点度都为 2
  • 完全二叉树:除去最后一层为满二叉树,且最后一层节点从左到右分布
  • 完满二叉树:除了叶子结点之外的每一个结点都有两个孩子结点

满二叉树

完全二叉树

完满二叉树

高度为 H 的一棵满 K 叉树,其节点总数为等比数列求和公式 (K^H - 1)/(K - 1),用 Big O 表示就是 O(K^H)

满二叉树的节点数为 2^h - 1,节点总数为 n 的满二叉树高度为 log (n+1)

完全二叉树层序遍历结果还原

tree.jpg

补充成完全二叉树的层序遍历结果:[3,9,20,null,null,15,7]

代码实现

js
function TreeNode(val, left, right) {
+    
Skip to content
大纲

二叉树

  • 满二叉树(完美二叉树):除了叶节点,每个节点度都为 2
  • 完全二叉树:除去最后一层为满二叉树,且最后一层节点从左到右分布
  • 完满二叉树:除了叶子结点之外的每一个结点都有两个孩子结点

满二叉树

完全二叉树

完满二叉树

高度为 H 的一棵满 K 叉树,其节点总数为等比数列求和公式 (K^H - 1)/(K - 1),用 Big O 表示就是 O(K^H)

满二叉树的节点数为 2^h - 1,节点总数为 n 的满二叉树高度为 log (n+1)

完全二叉树层序遍历结果还原

tree.jpg

补充成完全二叉树的层序遍历结果:[3,9,20,null,null,15,7]

代码实现

js
function TreeNode(val, left, right) {
   this.val = val === undefined ? 0 : val;
   this.left = left === undefined ? null : left;
   this.right = right === undefined ? null : right;
@@ -94,8 +94,8 @@
 function buildTree(preorder, inorder) {
   return build(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1);
 }
- + \ No newline at end of file diff --git a/zjw/data-structure.html b/zjw/data-structure.html index 97270d9..658af6d 100644 --- a/zjw/data-structure.html +++ b/zjw/data-structure.html @@ -10,12 +10,12 @@ - + -
Skip to content
大纲

数据结构

优先队列

js
class PriorityQueue {
+    
Skip to content
大纲

数据结构

优先队列

js
class PriorityQueue {
   size = 0;
   pq = [];
 
@@ -186,8 +186,8 @@
     return this.maxq[0];
   }
 }

优点:单调递增或递减,时间复杂度 O(1),可以按先进先出顺序
缺点:不能获取完整数据(由于删除中间元素)

- + \ No newline at end of file diff --git a/zjw/koa-middleware.html b/zjw/koa-middleware.html index f617207..509ffb5 100644 --- a/zjw/koa-middleware.html +++ b/zjw/koa-middleware.html @@ -15,7 +15,7 @@ -
Skip to content
大纲

实现 koa 中间件

koa 中间件具备以下特点

  • 每个中间件接受 next 函数,控制继续向下个中间件执行
  • next(error) 调用时,抛出异常,中断调用栈
  • await next() 前代码按中间件正序运行,后面代码按逆序运行(即洋葱模型)

例如,实现 run 函数,输出以下结果

ts
run(() => {
+    
Skip to content
大纲

实现 koa 中间件

koa 中间件具备以下特点

  • 每个中间件接受 next 函数,控制继续向下个中间件执行
  • next(error) 调用时,抛出异常,中断调用栈
  • await next() 前代码按中间件正序运行,后面代码按逆序运行(即洋葱模型)

例如,实现 run 函数,输出以下结果

ts
run(() => {
   console.log('run task');
   return Promise.resolve(1);
 }, [
@@ -77,8 +77,8 @@
 // run task
 // 1 leave
 // 2 leave

可以发现,entry 代码是按正确循序执行,但是 leave 代码,由于第二个中间件 await next() 后面代码添加成微任务,退出第一个中间件 next 调用,执行接下来语句,所以先输出 “1 leave”,再执行微任务,输出 “2 leave”

- + \ No newline at end of file diff --git a/zjw/linked-list.html b/zjw/linked-list.html index 5938f87..9b747b6 100644 --- a/zjw/linked-list.html +++ b/zjw/linked-list.html @@ -10,17 +10,17 @@ - + -
Skip to content
大纲

链表

构建

js
function ListNode(val) {
+    
Skip to content
大纲

链表

构建

js
function ListNode(val) {
   this.val = val;
   this.next = null;
 }
 
-console.log(build([1, 2, 3]));
js
function build(nums) {
+console.log(build([1, 2, 3]));
js
function build(nums) {
   var dummy = new ListNode();
   var p = dummy;
 
@@ -39,7 +39,7 @@
   node.next = build(nums, start + 1);
 
   return node;
-}

反转

js
function reverse(head) {
+}

反转

js
function reverse(head) {
   var pre = null,
     cur = head;
 
@@ -123,8 +123,8 @@
     return first;
   }
 }
- + \ No newline at end of file diff --git a/zjw/react-router.html b/zjw/react-router.html index 6f00f84..9603b2e 100644 --- a/zjw/react-router.html +++ b/zjw/react-router.html @@ -15,7 +15,7 @@ -
Skip to content
大纲

react-router 实现

history

  • pushState 与 replaceState 改变路由,不会触发路由事件

  • 监听路由改变事件(只在浏览器行为下触发,前进后退、history 方法 forward、back、go)

    window.addEventListener('popstate',function(e){ // 监听改变 })

    需要修改 nginx 支持路由重定向到 index.html

nginx
location / {
+    
Skip to content
大纲

react-router 实现

history

  • pushState 与 replaceState 改变路由,不会触发路由事件

  • 监听路由改变事件(只在浏览器行为下触发,前进后退、history 方法 forward、back、go)

    window.addEventListener('popstate',function(e){ // 监听改变 })

    需要修改 nginx 支持路由重定向到 index.html

nginx
location / {
    try_files $uri $uri/ /index.html;
  }

hash

  • location.hash 设置改变路由

  • onhashchange 监听路由改变

    window.addEventListener('onhashchange',function(e){ // 监听改变 })

js
function push(path) {
   location.hash = path;
@@ -26,8 +26,8 @@
 
   location.replace(href + '#' + path);
 }

总结

v5 版本:路由改变 history 创建新的 location 对象,Router 监听 history 触发的事件,并更新 RouterContext 的 location 值,触发 Switch 匹配 Route 并渲染

图片来源:https://juejin.cn/post/6886290490640039943

- + \ No newline at end of file diff --git a/zjw/sandbox.html b/zjw/sandbox.html index e789bc1..2cc67b1 100644 --- a/zjw/sandbox.html +++ b/zjw/sandbox.html @@ -15,7 +15,7 @@ -
Skip to content
大纲

实现一个不能操作 DOM 的环境

实现一

通过 with 语句限制内部代码访问的上下文,再代理 window 对象

js
function sandbox(code, options) {
+    
Skip to content
大纲

实现一个不能操作 DOM 的环境

实现一

通过 with 语句限制内部代码访问的上下文,再代理 window 对象

js
function sandbox(code, options) {
   const { blackList, ctx } = options;
   const innerCtx = new Proxy(ctx, {
     has(target, prop) {
@@ -34,8 +34,8 @@
   blackList: ['document'],
   ctx: window,
 });
- + \ No newline at end of file diff --git a/zjw/sort.html b/zjw/sort.html index 6a27479..34212a9 100644 --- a/zjw/sort.html +++ b/zjw/sort.html @@ -10,12 +10,12 @@ - + -
Skip to content
大纲

排序算法

冒泡排序

javascript
function bubbleSort(nums) {
+    
Skip to content
大纲

排序算法

冒泡排序

javascript
function bubbleSort(nums) {
   var n = nums.length;
   var temp, didSwap;
 
@@ -76,7 +76,7 @@
   }
 }
 
-Merge.sort([5, 2, 3, 1]);

快速排序

js
function quickSort(nums) {
+Merge.sort([5, 2, 3, 1]);

快速排序

js
function quickSort(nums) {
   // 洗牌降低退化成一个链表的概率
   shuffle(nums);
   sort(nums, 0, nums.length - 1);
@@ -181,9 +181,9 @@
     // 下沉小元素
     maxHeapify(nums, largest, len);
   }
-}
- +}
+ \ No newline at end of file diff --git a/zjw/transform-tree.html b/zjw/transform-tree.html index 9152796..745e70a 100644 --- a/zjw/transform-tree.html +++ b/zjw/transform-tree.html @@ -15,7 +15,7 @@ -
Skip to content
大纲

扁平数据结构转换成树

input

js
let arr = [
+    
Skip to content
大纲

扁平数据结构转换成树

input

js
let arr = [
   { id: 1, name: '部门1', pid: 0 },
   { id: 2, name: '部门2', pid: 1 },
   { id: 3, name: '部门3', pid: 1 },
@@ -75,8 +75,8 @@
 
   return result;
 }

结论

  • 递归时间复杂度:O(n logk n) 最坏情况下(k=1)等于 n^2,空间复杂度 O(n)
  • Map 时间复杂度:O(n) 空间复杂度 O(n)

当 n 越大时采用实现二更优

- + \ No newline at end of file diff --git a/zjw/webpack-pack-optimization.html b/zjw/webpack-pack-optimization.html index 81fe139..fdcec93 100644 --- a/zjw/webpack-pack-optimization.html +++ b/zjw/webpack-pack-optimization.html @@ -15,7 +15,7 @@ -
Skip to content
大纲

webpack 打包速度优化

webpack 是个模块化打包工具,所以影响打包速度的因素主要取决于打包量。

我们将从减少打包量和 webpack 配置优化两方面讲解优化方法。

减少打包量

1.模块按需引入

例如 antd、echarts、lodash 都支持按需引入,其它支持请查看各包使用文档

diff
! lodash
+    
Skip to content
大纲

webpack 打包速度优化

webpack 是个模块化打包工具,所以影响打包速度的因素主要取决于打包量。

我们将从减少打包量和 webpack 配置优化两方面讲解优化方法。

减少打包量

1.模块按需引入

例如 antd、echarts、lodash 都支持按需引入,其它支持请查看各包使用文档

diff
! lodash
 -import _ from 'lodash';
 +import _map from 'lodash/map';
 
@@ -109,8 +109,8 @@
 +    })
   ]
 };
  • 修改 index.html 添加 dll 包的引用
diff
+  <script src="%PUBLIC_URL%/static/js/vendor.dll.js"></script>

注:如果报公共库找不到,先检查 public/static/js/vendor.dll.js 是否存在,否则先构建公共库 npm run build:dll,如果修改或升级预编译的模块也需要重新构建公共库

升级 webpack 等构建工具

- + \ No newline at end of file diff --git a/zjw/webpack.html b/zjw/webpack.html index a65da58..abac3d7 100644 --- a/zjw/webpack.html +++ b/zjw/webpack.html @@ -10,12 +10,12 @@ - + -
Skip to content
大纲

webpack 总览

loader 用于转换某些类型的模块,插件则用于扩展 webpack 功能,通过注入钩子参与构建流程

构建流程

  1. 初始化参数
  2. 通过参数初始化 Compiler 对象,加载所有配置的插件,执行 run 方法开始编译
  3. 根据 entry 递归找到所有依赖,并根据文件类型,使用配置 loader 处理文件
  4. 完成所有模块转换后,构建依赖图
  5. 根据依赖图组装成一个个包含多模块的 chunk,再把 chunk 加入输出列表(插件最后修改输出内容时机)
  6. 根据配置确定输出内容的路径与文件名,写入文件系统

打包速度优化(简言之:减少打包量、并行、缓存、预构建)

  • 缩小处理文件
    • resolve.alias:直接指定打包好的代码(仅开发)
    • 优化 loader 配置:开启缓存、include 减少匹配文件
    • 减少文件匹配路径:resolve 匹配规则
    • 优化解析规则:module.noParse 指定不使用模块化解析文件
    • 按需加载
    • 懒编译
  • 并行打包
  • 构建缓存
  • 模块联邦

webpack HRM 原理

webpack-dev-server 向网页注入用于连接开发服务的客户端代码,在代码变更时编译出新的补丁文件,发送到网页执行

当模块变更后,更新事件会向上传递,直到某层接受了当前变化的模块,就会调用 callback 去执行自定义逻辑。当上抛到最外层没有被接受,就会刷新整个网页

js
if (module.hot) {
+    
Skip to content
大纲

webpack 总览

loader 用于转换某些类型的模块,插件则用于扩展 webpack 功能,通过注入钩子参与构建流程

构建流程

  1. 初始化参数
  2. 通过参数初始化 Compiler 对象,加载所有配置的插件,执行 run 方法开始编译
  3. 根据 entry 递归找到所有依赖,并根据文件类型,使用配置 loader 处理文件
  4. 完成所有模块转换后,构建依赖图
  5. 根据依赖图组装成一个个包含多模块的 chunk,再把 chunk 加入输出列表(插件最后修改输出内容时机)
  6. 根据配置确定输出内容的路径与文件名,写入文件系统

打包速度优化(简言之:减少打包量、并行、缓存、预构建)

  • 缩小处理文件
    • resolve.alias:直接指定打包好的代码(仅开发)
    • 优化 loader 配置:开启缓存、include 减少匹配文件
    • 减少文件匹配路径:resolve 匹配规则
    • 优化解析规则:module.noParse 指定不使用模块化解析文件
    • 按需加载
    • 懒编译
  • 并行打包
  • 构建缓存
  • 模块联邦

webpack4 打包速度优化文档【旧】

webpack HRM 原理

webpack-dev-server 向网页注入用于连接开发服务的客户端代码,在代码变更时编译出新的补丁文件,发送到网页执行

当模块变更后,更新事件会向上传递,直到某层接受了当前变化的模块,就会调用 callback 去执行自定义逻辑。当上抛到最外层没有被接受,就会刷新整个网页

js
if (module.hot) {
   module.hot.accept(['./App'], () => {
     render(<App />, window.document.getElementById('app'));
   });
@@ -23,9 +23,9 @@
   // 用正则去匹配要用该 loader 转换的 CSS 文件
   test: /\.css$/,
   use: ['style-loader', 'css-loader?minimize']
-}
  • use 属性由 loader 名称组成的数组,loader 从后往前执行
  • 每个 loader 可以通过 URL querystring 方式传入参数,也可以通过对象形式传入 { loader: 'css-loader', options: { minimize: true } }
  • 内联方式使用 loader,import '!style-loader!css-loader?minimize!./styles.css'
- +}
  • use 属性由 loader 名称组成的数组,loader 从后往前执行
  • 每个 loader 可以通过 URL querystring 方式传入参数,也可以通过对象形式传入 { loader: 'css-loader', options: { minimize: true } }
  • 内联方式使用 loader,import '!style-loader!css-loader?minimize!./styles.css'

loader 执行循序

+ \ No newline at end of file diff --git "a/zjw/\345\211\215\347\253\257\345\270\270\350\247\201\346\211\213\345\206\231\344\273\243\347\240\201.html" "b/zjw/\345\211\215\347\253\257\345\270\270\350\247\201\346\211\213\345\206\231\344\273\243\347\240\201.html" index 2c9893a..ae9d24a 100644 --- "a/zjw/\345\211\215\347\253\257\345\270\270\350\247\201\346\211\213\345\206\231\344\273\243\347\240\201.html" +++ "b/zjw/\345\211\215\347\253\257\345\270\270\350\247\201\346\211\213\345\206\231\344\273\243\347\240\201.html" @@ -15,7 +15,7 @@ -
Skip to content
大纲

前端常见手写代码

防抖

用于用户频繁触发某个事件(如输入搜索),避免函数被频繁执行,最近一次触发需要等待一定的时间间隔才会被执行,如果期间再次触发执行,则重置定时器,直到停止触发等待足够时间

js
function debounce(fn, delay) {
+    
Skip to content
大纲

前端常见手写代码

防抖

用于用户频繁触发某个事件(如输入搜索),避免函数被频繁执行,最近一次触发需要等待一定的时间间隔才会被执行,如果期间再次触发执行,则重置定时器,直到停止触发等待足够时间

js
function debounce(fn, delay) {
   var timer;
 
   return function () {
@@ -307,8 +307,8 @@
 // Wake up after 10
 // Hi! This is Hank!
 // Eat dinner
- + \ No newline at end of file