Skip to content

Commit ced5081

Browse files
init
0 parents  commit ced5081

35 files changed

+2220
-0
lines changed

.editorconfig

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
root = true
3+
4+
[*]
5+
charset = utf-8
6+
end_of_line = lf
7+
indent_style = space
8+
indent_size = 2
9+
trim_trailing_whitespace = true
10+
insert_final_newnewline = true
11+
singleQuote= true

.gitignore

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/node_modules
2+
**/.temp
3+
**/.cache
4+
.idea
5+
.DS_Store
6+
.vscode

docs/.vuepress/config.js

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
module.exports = {
2+
lang: "zh-CN",
3+
title: "码力全开",
4+
description: "vue react javascript 前端 面试 js",
5+
theme: "@vuepress/default",
6+
themeConfig: {
7+
logo: "https://vuejs.org/images/logo.png",
8+
editLink: false,
9+
home: "/",
10+
navbar: [
11+
// 嵌套 Group - 最大深度为 2
12+
{
13+
text: "前端框架",
14+
children: [
15+
{
16+
text: "React",
17+
children: [
18+
{
19+
text: "源码",
20+
link: "/framework/react/source",
21+
},
22+
],
23+
},
24+
{
25+
text: "Vue",
26+
children: [
27+
{
28+
text: "源码(vue2)",
29+
link: "/framework/vue2-source/source",
30+
},
31+
{
32+
text: 'vue 3',
33+
link: '/framework/vue3'
34+
}
35+
],
36+
},
37+
],
38+
},
39+
{
40+
text: "JavaScript",
41+
children: [
42+
{
43+
text: "语言基础",
44+
children: [
45+
{
46+
text: "原生API",
47+
link: "/js/basic",
48+
},
49+
],
50+
},
51+
{
52+
text: '进阶提升',
53+
children: [
54+
{
55+
text: 'ES6+',
56+
link: "/js/es6"
57+
},
58+
{
59+
text: '设计模式',
60+
link: "/js/design-pattern"
61+
}
62+
]
63+
},
64+
{
65+
text: "函数式编程",
66+
children: [
67+
{
68+
text: "高阶函数",
69+
link: "/js/function/higher-function",
70+
},
71+
],
72+
},
73+
],
74+
},
75+
// {
76+
// text: "前端工程化",
77+
// children: [
78+
// {
79+
// text: "前端工程化",
80+
// children: [
81+
// {
82+
// text: "原生API",
83+
// link: "/js/basic",
84+
// },
85+
// ],
86+
// },
87+
// ],
88+
// },
89+
{
90+
text: "项目构建",
91+
children: [
92+
{
93+
text: "代码打包",
94+
children: [
95+
{
96+
text: "Tree Shaking",
97+
link: "/bundle/treeshaking",
98+
},
99+
],
100+
},
101+
],
102+
}
103+
],
104+
// 侧边栏对象
105+
// 不同子路径下的页面会使用不同的侧边栏
106+
sidebar: "auto",
107+
},
108+
};

docs/.vuepress/public/banner.jpeg

81.5 KB
Loading

docs/.vuepress/public/favicon.ico

264 KB
Binary file not shown.

docs/.vuepress/public/logo.png

69.8 KB
Loading

docs/README.md

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
home: true
3+
heroImage: /banner.jpeg
4+
heroText: 前端资源
5+
tagline: 一起精进前端技术
6+
actionText: 马上开始 →
7+
actionLink: /basic/html
8+
features:
9+
- title:
10+
details: 资源量大
11+
- title:
12+
details: 种类齐全
13+
- title:
14+
details: 详细整理
15+
footer: null
16+
---

docs/bundle/treeshaking/README.md

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
lang: zh-CN
3+
title: tree shaking
4+
description: tree shaking
5+
---
6+
# tree shaking
7+
> 基于 ES Module 规范的 Dead Code Elimination 技术
8+
## 实现的理论基础
9+
ES 模块规范要求所有的导入导出语句只能出现在模块顶层,且导入导出的模块名必须为字符串常量。所以,ESM 下模块之间的依赖关系是确定的,编译工具只需要对 ES Module 做静态分析就可以从代码字面量中推断出模块导出的哪些值未曾被其他模块使用,进而将其标记和删除,以此实现打包产物的优化
10+
## webpack 中的 tree shaking
11+
首先 「标记」 出模块导出值中哪些没有被用过,其次使用 Terser、UglifyJS 等插件删除掉这些没有被用到的导出语句,以此实现完整的 tree shaking 功能
12+
## 实际配置
13+
准备一个 entry.js 和 utils.js
14+
### webpack v4
15+
源码如下:
16+
@[code js](./src/webpack4-treeshaking/enable.js)
17+
打包结果 tree shaking 生效
18+
19+
但当有函数调用时:
20+
@[code js](./src/webpack4-treeshaking/disable.js)
21+
此时的打包结果为:
22+
![](./images/disable00.png)
23+
可以看到,将整个导出的模块代码都打包了进去,包括我们没有用到的 cube 等方法
61 KB
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// entry.js
2+
3+
import obj from './utils';
4+
// console.log(obj.foo);
5+
obj.add(2,3);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// utils.js
2+
const bar = 'bar';
3+
const foo = 'foo';
4+
5+
function add() {}
6+
function cube() {}
7+
8+
export default {
9+
bar, foo, add, cube
10+
}
11+
12+
// entry.js
13+
import obj from './utils';
14+
console.log(obj.foo);

docs/bundle/treeshaking/src/webpack5-treeshaking/enable.js

Whitespace-only changes.

docs/framework/react/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
react

docs/framework/react/source.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
react 源码

docs/framework/vue2-source/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
vue

docs/framework/vue2-source/source.md

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# vue 源码
2+
3+
## 响应式原理
4+
5+
通过数据劫持结合观察者模式,使用 Object.defineProperty 劫持目标对象的属性的 getter 和 setter,在目标对象改变时发送消息给观察者,触发对应回调
6+
7+
### 先来实现 Observer
8+
9+
@[code js{4}](./src//segmentfault//mvvm.js)
10+
此时执行脚本,第四行就会输出变化,这样我们已经可以监听每个数据的变化了,那么监听到变化之后就是怎么通知订阅者了
11+
12+
所以接下来,要用到观察者模式了,发布者持有订阅者,数据变动触发 notify,调用所有订阅者的 update 方法
13+
@[code js{4}](./src//segmentfault//mvvm.js)
14+
15+
那么怎么让目标对象持有观察者呢,**如果一个对象属性的 getter 被触发,则它被访问了,也就是说有地方用到了它**,那这个属性就需要被订阅,即需要被 Watcher 观测,如果它后续发生了改变,则需要通知到 watcher 去执行对应的回调
16+
组件的 render function 执行前,会对数据做响应式化。使用 Object.defineProperty 把对象属性转为 getter 和 setter,并为每个数据添加一个订阅者列表,这个列表会记录所有依赖于这个数据的组件
17+
18+
也就是说,响应式化后的数据相当于发布者
19+
20+
每个组件都对应一个 watcher,这是订阅者的角色
21+
22+
当这个组件的 render function 执行时,都会将本组件的 watcher 放到自己所依赖的响应式数据的订阅者列表里,完成对目标对象的观测,这个过程称为**依赖收集**
23+
24+
当响应式数据发生变化,即目标对象的状态发生了变化,会触发 setter 函数,在其中 notify 该数据的订阅者列表里的 watcher,watcher 会 触发 re-render 来更新视图
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// 原文地址:https://segmentfault.com/a/1190000006599500
2+
var data = { name: "gzz" };
3+
observe(data);
4+
data.name = "zl"; // 就会有输出
5+
6+
function observe(data) {
7+
if (!data || typeof data !== "object") return;
8+
Object.keys(data).forEach((key) => {
9+
defineReactive(data, key, data[key]);
10+
});
11+
}
12+
13+
function defineReactive(data, key, val) {
14+
var dep = new Dep();
15+
observe(val); // 子属性也是对象
16+
Object.defineProperty(data, key, {
17+
enumerable: true,
18+
configurable: false,
19+
get: function () {
20+
Dep.target && dep.addSub(Dep.target);
21+
return val;
22+
},
23+
set: function (newVal) {
24+
if (val === newVal) return;
25+
console.log("哈哈哈,监听到值变化了 ", val, " --> ", newVal);
26+
val = newVal;
27+
dep.notify();
28+
},
29+
});
30+
}
31+
class Dep {
32+
constructor() {
33+
this.subs = [];
34+
}
35+
addSub(sub) {
36+
this.subs.push(sub);
37+
}
38+
notify() {
39+
this.subs.forEach((sub) => sub.update());
40+
}
41+
}
42+
43+
class Watcher {
44+
get(key) {
45+
Dep.target = this;
46+
this.value = data[key]; // 访问一下data的属性,就会触发 getter 劫持,从而添加订阅者
47+
Dep.target = null;
48+
}
49+
}
50+
51+
// 为了提升性能,会先将根节点 el 转换成文档碎片 fragment 进行解析编译操作,解析完成,再将 fragment 添加回原来的真实 dom 节点中
52+
function Compile(el) {
53+
this.$el = this.isElementNode(el) ? el : document.querySelector(el);
54+
if (this.$el) {
55+
this.$fragment = this.node2Fragment(this.$el);
56+
this.init();
57+
this.$el.appendChild(this.$fragment);
58+
}
59+
}
60+
Compile.prototype = {
61+
init: function () {
62+
this.compileElement(this.$fragment);
63+
},
64+
node2Fragment: function (el) {
65+
var fragment = document.createDocumentFragment(),
66+
child;
67+
// 将原生节点拷贝到fragment
68+
while ((child = el.firstChild)) {
69+
fragment.appendChild(child);
70+
}
71+
return fragment;
72+
},
73+
};

docs/framework/vue3/README.md

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
lang: zh-CN
3+
title: vue3
4+
description: 熟练使用 vue3
5+
---
6+
# vue3
7+
## 新的代码组织方式 `Composition API + <script setup>`
8+
```vue
9+
<template>
10+
<div>
11+
<h1 @click="add">{{count}}</h1>
12+
</div>
13+
</template>
14+
15+
<script setup>
16+
import { ref } from "vue";
17+
let count = ref(1)
18+
function add(){
19+
count.value++
20+
}
21+
</script>
22+
23+
<style>
24+
h1 {
25+
color: red;
26+
}
27+
</style>
28+
```
29+
上面的代码简单实现了一个累加器,我们使用 `template` 标签放置模板,`script` 标签放置逻辑代码,并且用 `setup` 标记我们使用 `<script setup>` 语法。**而在 `<script setup>` 标签内定义的变量和函数,都可以直接在模板里使用**
30+
### import { ref } from "vue"
31+
在使用 ref 包裹响应式数据时,注意要修改响应式数据的 value 属性

docs/js/api/README.md

Whitespace-only changes.

docs/js/basic/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
常用api

docs/js/design-pattern/README.md

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
lang: zh-CN
3+
title: 设计模式
4+
description: 设计模式
5+
---
6+
7+
# 行为型设计模式
8+
## [观察者模式](./observer.md)

docs/js/design-pattern/observer.md

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
## 观察者模式
2+
3+
实现一对多关系解耦的行为型设计模式,主要涉及两个角色:
4+
5+
- 观察目标
6+
- 观察者
7+
8+
多个观察者对象同时监听某一个目标对象;当目标对象状态发生变化时,通知所有观察者对象,使他们能够自动更新
9+
10+
被观察的目标对象里持有观察自己的观察者对象,它知道自己被哪些观察者对象订阅,有增加订阅者、通知订阅者、移除订阅者这个三个基本能力,当自身状态发生变化时,通过 notify 方法通知所有的观察者 update
11+
12+
观察者非常简单,它的行为只有两个,被通知和去执行,本质上是接受目标对象的调用,并且这一步在目标对象类里已经做掉了,所以 observer 只需要实现 update 方法,供目标对象调用,在 update 方法中可以执行 observer 自定义的业务代码
13+
14+
### 特点
15+
16+
观察者要**直接订阅**观察目标
17+
18+
@[code js](./src/observer.js)
19+
20+
## 发布订阅模式
21+
22+
小明想买房子,但还没开盘,不过他只需要把自己的手机号留给售楼处,等到楼盘开售,售楼处就会打电话通知他
23+
24+
并且想买房子的不止小明,还有小红、小白等人,售楼处都保存了他们的联系方式,在合适的时间去通知所有顾客
25+
26+
如果再有新的购房者出现,售楼处只需要多保存一个联系方式即可
27+
28+
异步编程
29+
30+
对象之间解耦合
31+
32+
一个对象里保存了一份回调列表
33+
34+
### 特点
35+
36+
### 与发布订阅模式比较
37+
38+
> 发布订阅模式基于一个事件总线,希望接收通知的对象即 subscriber 也就是订阅者通过自定义事件订阅事件总线,发布事件的对象即 publisher 通过发布事件的方式通知各个订阅了该事件的 subscriber
39+
40+
**区别在于**
41+
42+
- 观察者模式中观察了 subject 的一系列 Observer 对象在被通知后只能执行同一个特定的更新方法,而发布订阅模式中则可以基于不同主题去执行不同的自定义事件
43+
- 观察者模式中目标对象和观察者对象之间联系的更紧密,耦合性更高,有很强的依赖关系,目标对象收集和维护观察者,并在状态变化时主动通知观察者更新;发布订阅中则彻底解耦
44+
- 发布订阅在发布者和订阅者之间需要有一个中间人,发布者发布事件名和参数到中间人,中间人像事件的订阅者发送参数

0 commit comments

Comments
 (0)