├── 17.手写redux
├── readme.md
├── index1.js
├── redux.js
├── index2.js
├── index4.js
├── index3.js
└── index.js
├── 6.Promise、Async
├── age.txt
├── name.txt
├── test.js
└── promise._all.js
├── 8.React和Vue中key的问题
└── 1.性能对比.html
├── .gitignore
├── 11.webpack原理
├── loader
│ ├── dist
│ │ ├── index.md
│ │ └── main.js
│ ├── src
│ │ └── index.js
│ ├── package.json
│ ├── asyncLoader.js
│ ├── syncLoader.js
│ ├── webpack.config.js
│ └── demo-webpack-plugin.js
├── .vscode
│ └── settings.json
├── babel
│ ├── src
│ │ ├── add.js
│ │ ├── minus.js
│ │ └── index.js
│ ├── index.html
│ ├── dist
│ │ └── bundle.js
│ └── bundle.js
└── demo
│ ├── src
│ ├── add.js
│ ├── minus.js
│ └── index.js
│ ├── .vscode
│ └── settings.json
│ ├── index.html
│ ├── package.json
│ └── bundle.js
├── img
├── 12.png
├── ss.png
├── 12.1.png
├── BFS.png
└── DFS.png
├── 28.手写call函数
├── 1.js
├── 1.html
└── reade.md
├── 4.深拷贝和浅拷贝
├── 8.js
├── 浅拷贝
│ ├── 1.js
│ ├── 3.js
│ └── 2.js
├── 6.js
├── 4.js
├── 3.js
├── 7.js
├── 2.js
├── 1.js
├── 5.js
├── 10.js
└── 9.js
├── 13.Vue2.0和Vue3.0的响应式原理
├── 07.优劣势.js
├── 05.Proxy支持监控数组.js
├── 06.Proxy嵌套的支持.js
├── 01.defineProperty.js
├── 04.Proxy.js
├── 02.defineProperty监听数据的变化.js
└── 03.defineProperty监听数据的变化.js
├── 14.手写async函数
├── demo
│ ├── 1.js
│ └── 2.js
├── 1.js
├── 3.js
├── 4.js
├── 2.js
├── async.md
└── async的副本.md
├── 30.最长连续递增子序列
└── 1.js
├── 29.字符串相加
└── 1.js
├── 25.合并数组
└── 1.index.js
├── 2.发布订阅者和观察者
├── 发布订阅者.js
└── 观察者模式.js
├── 16.最大公共前缀
└── index.js
├── 20.反转二叉树
└── index.js
├── 21.字符串的全排列
└── index.js
├── 27.数组转为树
└── 1.js
├── 7.Vue自定义事件原理
├── 3.原理分析.js
├── 1.自定义事件的基本用法.html
└── 2.事件总线.html
├── 19.对象扁平化
└── index.js
├── 10.Vue和React路由原理
├── hash.html
└── history.html
├── 3.防抖和节流
└── 防抖和截流.html
├── 23.虚拟DOM转为真实DOM
└── 1.html
├── 26.控制最大并发数
└── 1.js
├── 18.使用setTimeout实现setInterval
└── readme.md
├── 15.使用Es6提供的构造函数Proxy实现数据绑定
└── 1.html
├── 1.广度优先遍历和深度优先遍历
└── 广度优先遍历和深度优先遍历.html
├── 22.ES5实现B继承A
└── index.js
└── README.md
/17.手写redux/readme.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/6.Promise、Async/age.txt:
--------------------------------------------------------------------------------
1 | 18
--------------------------------------------------------------------------------
/6.Promise、Async/name.txt:
--------------------------------------------------------------------------------
1 | 铁蛋儿
--------------------------------------------------------------------------------
/8.React和Vue中key的问题/1.性能对比.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | .DS_Store
3 |
4 | node_modules/
5 |
--------------------------------------------------------------------------------
/11.webpack原理/loader/dist/index.md:
--------------------------------------------------------------------------------
1 | this is a demo for plugin
--------------------------------------------------------------------------------
/img/12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tie-Dan/Algo/HEAD/img/12.png
--------------------------------------------------------------------------------
/img/ss.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tie-Dan/Algo/HEAD/img/ss.png
--------------------------------------------------------------------------------
/img/12.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tie-Dan/Algo/HEAD/img/12.1.png
--------------------------------------------------------------------------------
/img/BFS.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tie-Dan/Algo/HEAD/img/BFS.png
--------------------------------------------------------------------------------
/img/DFS.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tie-Dan/Algo/HEAD/img/DFS.png
--------------------------------------------------------------------------------
/28.手写call函数/1.js:
--------------------------------------------------------------------------------
1 | let arr = []
2 | arr.length = 0
3 |
4 | console.log(arr[0])
--------------------------------------------------------------------------------
/11.webpack原理/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "git.ignoreLimitWarning": true
3 | }
--------------------------------------------------------------------------------
/11.webpack原理/babel/src/add.js:
--------------------------------------------------------------------------------
1 | export default (a, b) => {
2 | return a + b
3 | }
--------------------------------------------------------------------------------
/11.webpack原理/demo/src/add.js:
--------------------------------------------------------------------------------
1 | export default (a, b) => {
2 | return a + b
3 | }
--------------------------------------------------------------------------------
/11.webpack原理/loader/src/index.js:
--------------------------------------------------------------------------------
1 | // index.js
2 | console.log('我要学好前端,因为学好前端可以: ')
--------------------------------------------------------------------------------
/11.webpack原理/demo/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "git.ignoreLimitWarning": true
3 | }
--------------------------------------------------------------------------------
/11.webpack原理/babel/src/minus.js:
--------------------------------------------------------------------------------
1 | export const minus = (a, b) => {
2 | return a - b
3 | }
--------------------------------------------------------------------------------
/11.webpack原理/demo/src/minus.js:
--------------------------------------------------------------------------------
1 | export const minus = (a, b) => {
2 | return a - b
3 | }
--------------------------------------------------------------------------------
/4.深拷贝和浅拷贝/8.js:
--------------------------------------------------------------------------------
1 | // for...in 会追踪原型链上的属性,
2 | // 而其它三种方法(Object.keys、Reflect.ownKeys 和 JSON 方法)都不会追踪原型链上的属性:
--------------------------------------------------------------------------------
/11.webpack原理/demo/src/index.js:
--------------------------------------------------------------------------------
1 | import add from './add.js'
2 | import {
3 | minus
4 | } from './minus.js'
5 | const sum = add(1, 2)
6 | const divison = minus(2, 1)
7 | console.log(sum)
8 | console.log(divison)
--------------------------------------------------------------------------------
/11.webpack原理/babel/src/index.js:
--------------------------------------------------------------------------------
1 | import add from './add.js'
2 | import {
3 | minus
4 | } from './minus.js'
5 |
6 | const sum = add(1, 2)
7 | const division = minus(2, 1)
8 | console.log('sum>>>>>', sum)
9 | console.log('division>>>>>', division)
--------------------------------------------------------------------------------
/4.深拷贝和浅拷贝/浅拷贝/1.js:
--------------------------------------------------------------------------------
1 | let target = {}
2 | let obj = {
3 | a: {
4 | b: 3
5 | }
6 | };
7 | Object.assign(target, obj);
8 | console.log(target); //{a:1}
9 |
10 | obj.a.b = 1;
11 |
12 | console.log(obj); //{a:2}
13 | console.log(target); //{a:1}
--------------------------------------------------------------------------------
/6.Promise、Async/test.js:
--------------------------------------------------------------------------------
1 | new Promise(function (resolve, reject) {
2 | setTimeout(() => {
3 | throw new Error("Whoops!");
4 | }, 1000);
5 | }).catch(alert);
6 | // 正如本章所讲, 函数代码周围有个“ 隐式的
7 | // try..catch”。 所以, 所有同步错误都会得到处理。
8 |
9 | // 但是这里的错误并不是在 executor 运行时生成的, 而是在稍后生成的。 因此, promise 无法处理它。
--------------------------------------------------------------------------------
/11.webpack原理/loader/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "loader",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC"
12 | }
13 |
--------------------------------------------------------------------------------
/4.深拷贝和浅拷贝/6.js:
--------------------------------------------------------------------------------
1 | // 键值不是字符串而是 Symbol
2 |
3 | var test = {}
4 | let sym = Symbol('我是一个Symbol')
5 | test[sym] = 'symbol'
6 |
7 | let result = deepClone(test)
8 | console.log(result)
9 | console.log(result[sym] === test[sym])
10 | // 拷贝失败了, 为什么?
11 |
12 | // 因为 Symbol 是一种特殊的数据类型, 它最大的特点便是独一无二, 所以它的深拷贝就是浅拷贝
--------------------------------------------------------------------------------
/11.webpack原理/loader/asyncLoader.js:
--------------------------------------------------------------------------------
1 | const loaderUtils = require('loader-utils')
2 | module.exports = function (source) {
3 | const options = loaderUtils.getOptions(this)
4 | const asyncfunc = this.async()
5 | setTimeout(() => {
6 | console.log(source)
7 | asyncfunc(null, source)
8 | }, 200)
9 | }
--------------------------------------------------------------------------------
/4.深拷贝和浅拷贝/浅拷贝/3.js:
--------------------------------------------------------------------------------
1 | let obj = {
2 | a: 1,
3 | b: {
4 | c: 1
5 | }
6 | }
7 | let obj2 = {
8 | ...obj
9 | };
10 | obj.a = 2;
11 | console.log(obj); //{a:2,b:{c:1}}
12 | console.log(obj2); //{a:1,b:{c:1}}
13 |
14 | obj.b.c = 2;
15 | console.log(obj); //{a:2,b:{c:2}}
16 | console.log(obj2); //{a:1,b:{c:2}}
--------------------------------------------------------------------------------
/11.webpack原理/babel/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | demo
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/11.webpack原理/demo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/13.Vue2.0和Vue3.0的响应式原理/07.优劣势.js:
--------------------------------------------------------------------------------
1 | // 优势:
2 | // Proxy 的第二个参数可以有 13 种拦截方法,
3 | // 比 Object.defineProperty() 要更加丰富,
4 | // Proxy 作为新标准受到浏览器厂商的重点关注和性能优化,
5 | // 相比之下 Object.defineProperty() 是一个已有的老方法。
6 | // Proxy返回的是一个新对象,我们可以只操作新的对象达到目的,
7 | // 而Object.defineProperty只能遍历对象属性直接修改。
8 | // 劣势:
9 | // Proxy 的兼容性不如 Object.defineProperty() 可是使用 polyfill 来处理兼容性
--------------------------------------------------------------------------------
/4.深拷贝和浅拷贝/浅拷贝/2.js:
--------------------------------------------------------------------------------
1 | let obj1 = {
2 | a: {
3 | b: 1
4 | },
5 | sym: Symbol(1)
6 | };
7 | Object.defineProperty(obj1, 'innumerable', {
8 | value: '不可枚举属性',
9 | enumerable: false
10 | });
11 | let obj2 = {};
12 |
13 | Object.assign(obj2, obj1)
14 |
15 | obj1.a.b = 2;
16 | console.log('obj1', obj1);
17 | console.log('obj2', obj2);
--------------------------------------------------------------------------------
/11.webpack原理/demo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "demo",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "webpack": "^4.43.0",
14 | "webpack-cli": "^3.3.11"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/14.手写async函数/demo/1.js:
--------------------------------------------------------------------------------
1 | const getData = () =>
2 | new Promise(resolve => setTimeout(() => resolve("data"), 1000))
3 |
4 | async function test() {
5 | const data = await getData()
6 | console.log('data: ', data);
7 | const data2 = await getData()
8 | console.log('data2: ', data2);
9 | return 'success'
10 | }
11 |
12 | // 这样的一个函数 应该再1秒后打印data 再过一秒打印data2 最后打印success
13 | test().then(res => console.log(res))
--------------------------------------------------------------------------------
/11.webpack原理/loader/syncLoader.js:
--------------------------------------------------------------------------------
1 | // module.exports = function (source) {
2 | // console.log('source>>>>', source)
3 | // return source
4 | // }
5 |
6 | // syncLoader.js
7 | const loaderUtils = require('loader-utils')
8 | module.exports = function (source) {
9 | const options = loaderUtils.getOptions(this)
10 | console.log(options.message)
11 | // 可以传递更详细的信息
12 | this.callback(null, source) // 或者retrun都行
13 | }
--------------------------------------------------------------------------------
/14.手写async函数/1.js:
--------------------------------------------------------------------------------
1 | const getData = () => new Promise(resolve =>
2 | setTimeout(() => resolve("data"), 1000)
3 | )
4 |
5 | async function test() {
6 | const data = await getData()
7 | console.log('data: ', data);
8 | const data2 = await getData()
9 | console.log('data2: ', data2);
10 | return 'success'
11 | }
12 |
13 |
14 | // 这样的一个函数 应该再1秒后打印data 再过一秒打印data2 最后打印success
15 | test().then(res => console.log(res))
--------------------------------------------------------------------------------
/17.手写redux/index1.js:
--------------------------------------------------------------------------------
1 | //需要监听的值
2 | let data = 0;
3 | //所有依赖的对列
4 | let listenters = [];
5 | //收集依赖方法
6 | function subscribe(listener) {
7 | listenters.push(listener);
8 | }
9 | //用来重写数据的赋值操作,添加通知所有依赖的操作
10 | function changeData(val) {
11 | data = val;
12 | listenters.forEach((v, i) => {
13 | v();
14 | })
15 | }
16 | //我们主动收集一下需要通知的依赖
17 | subscribe(() => {
18 | console.log("监听到数据变化");
19 | })
20 | //改变监听的值
21 | changeData(1)
22 |
--------------------------------------------------------------------------------
/30.最长连续递增子序列/1.js:
--------------------------------------------------------------------------------
1 | let findLength = function (nums) {
2 | let res = 0 // 最大子序列的长度
3 | let len = nums.length
4 | let count = 1
5 | if (len === 1) return 1// 只有一个返回1
6 | for (let i = 1; i < len; i++) {
7 | // 如果当前数小于等于它前面的数,说明不是连续递增序列,重新计算
8 | if (nums[i] <= nums[i - 1]) {
9 | count = 1
10 | } else {
11 | count++ // 如果满足递增 那就继续增加
12 | }
13 | res = Math.max(count, res) // 每次重新赋值 选最大那个
14 | }
15 | return res
16 | }
17 |
18 | console.log(findLength([1, 3, 3, 5, 6, 4, 7]))
--------------------------------------------------------------------------------
/29.字符串相加/1.js:
--------------------------------------------------------------------------------
1 | let addStrings = function (num1, num2) {
2 | let res = ''
3 | let carry = 0
4 | let i1 = num1.length - 1
5 | let i2 = num2.length - 1
6 | while (i1 >= 0 || i1 >= 0) {
7 | const x = i1 >= 0 ? num1[i1] - '0' : 0
8 | const y = i2 >= 0 ? num2[i2] - '0' : 0
9 | const sum = x + y + carry
10 | res += (sum % 10)
11 | carry = Math.floor(sum / 10)
12 | i1--
13 | i2--
14 | }
15 | if (carry) res += carry
16 | return res.split("").reverse().join("")
17 |
18 | }
19 |
20 | console.log(addStrings('199', '188'))
--------------------------------------------------------------------------------
/13.Vue2.0和Vue3.0的响应式原理/05.Proxy支持监控数组.js:
--------------------------------------------------------------------------------
1 | let arr = [1, 2, 3]
2 | let proxy = new Proxy(arr, {
3 | get(target, key, receiver) {
4 | console.log('get', key)
5 | return Reflect.get(target, key, receiver)
6 | },
7 | set(target, key, value, receiver) {
8 | console.log('set', key, value)
9 | return Reflect.set(target, key, value, receiver)
10 | }
11 | })
12 | proxy.push(4)
13 | // 能够打印出很多内容
14 | // get push (寻找 proxy.push 方法)
15 | // get length (获取当前的 length)
16 | // set 3 4 (设置 proxy[3] = 4)
17 | // set length 4 (设置 proxy.length = 4)
--------------------------------------------------------------------------------
/25.合并数组/1.index.js:
--------------------------------------------------------------------------------
1 | let ad = [1, 3, 5, 6, 7, 13, 14, 15, 16, 20, 33]
2 | let ap = [3, 4, 6, 8, 9, 13, 17, 18, 19]
3 |
4 | // 合并后的数组
5 |
6 | let between = []
7 |
8 | function transforNew() {
9 | // 直接循环次数为两个数组的总长度
10 | while (ad.length + ap.length) {
11 | // 如果有一个数组添加完 就break
12 | if (ad.length < 1 || ap.length < 1) {
13 | // 则剩余的数组合并到between
14 | between = between.concat(ad.length < 1 ? ap : ad)
15 | break
16 | }
17 | between.push(ad[0] >= ap[0] ? ap.shift() : ad.shift())
18 | }
19 | return between
20 | }
21 |
22 | console.log(transforNew(ad, ap))
--------------------------------------------------------------------------------
/4.深拷贝和浅拷贝/4.js:
--------------------------------------------------------------------------------
1 | // 3. lodash中深拷贝的实现
2 | // Lodash是一个轻量级的JavaScript工具函数库, 它方便了日常开发中对数据的操作, 提高了开发效率。
3 | // 著名的 lodash 中的 cloneDeep 方法同样是使用 Reflect 法 实现的,
4 | // 只不过它支持的对象种类更多, 具体的实现过程读者可以参考 lodash 的 baseClone 方法。
5 | // lodash可以完成array、 object、 date、 regexp的深拷贝, 但
6 |
7 | // function 和 error 仍然不可拷贝
8 |
9 | // https://github.com/lodash/lodash/blob/master/.internal/baseClone.js
10 | // 日常开发中,通常会对数据,特别是数组和对象进行各种读写等操作:
11 | // 比如去重,拷贝,合并,过滤,求交集,求和等等。根据平时开发中对数据的操作,
12 | const _ = require('lodash')
13 | const obj = {
14 | a: 1
15 | }
16 | obj.loopObj = obj
17 | const obj1 = _.cloneDeep(obj)
18 | console.log(obj1 === obj)
--------------------------------------------------------------------------------
/2.发布订阅者和观察者/发布订阅者.js:
--------------------------------------------------------------------------------
1 | // on是订阅 emit是发布
2 | let e = {
3 | _callback: [],
4 | on(callback) {
5 | // 订阅一件事 当这件事发生的时候 触发对应的函数
6 | // 订阅 就是将函数放到数组中
7 | this._callback.push(callback);
8 | },
9 | emit(value) {
10 | this._callback.forEach(method => {
11 | method(value);
12 | });
13 | }
14 | };
15 | // 订阅
16 | e.on(function (value) {
17 | console.log(value + ":张三的订阅");
18 | });
19 | // 订阅
20 | e.on(function (value) {
21 | console.log(value + ":李四的订阅");
22 | });
23 | // 订阅
24 | e.on(function (value) {
25 | console.log(value + ":王五的订阅");
26 | });
27 | // 发布
28 | e.emit('发布')
--------------------------------------------------------------------------------
/17.手写redux/redux.js:
--------------------------------------------------------------------------------
1 | function createStore() {
2 | let state; // state记录所有状态
3 | let listeners = []; // 保存所有注册的回调
4 |
5 | function subscribe(callback) {
6 | listeners.push(callback); // subscribe就是将回调保存下来
7 | }
8 |
9 | // dispatch就是将所有的回调拿出来依次执行就行
10 | function dispatch(action) {
11 | state = reducer(state, action);
12 | for (let i = 0; i < listeners.length; i++) {
13 | const listener = listeners[i];
14 | listener();
15 | }
16 | }
17 |
18 | // getState直接返回state
19 | function getState() {
20 | return state;
21 | }
22 |
23 | // store包装一下前面的方法直接返回
24 | const store = {
25 | subscribe,
26 | dispatch,
27 | getState
28 | }
29 |
30 | return store;
31 | }
--------------------------------------------------------------------------------
/16.最大公共前缀/index.js:
--------------------------------------------------------------------------------
1 | function longestCommonPrefix(strs) {
2 | // write code here
3 | if (strs.length === 0 || strs === null) {
4 | return ""
5 | }
6 | let maxid = strs[0].length - 1;
7 |
8 | for (let i = 1; i < strs.length; i++) {
9 |
10 | indx = -1; //下标flag
11 |
12 | while (indx < maxid && indx < strs[i].length - 1) {
13 | if (strs[0].charAt(indx + 1) === strs[i].charAt(indx + 1)) {
14 | indx++
15 | } else {
16 | break;
17 | }
18 | }
19 |
20 | if (indx === -1) {
21 | return ""
22 | }
23 | maxid = indx;
24 | }
25 | return strs[0].substring(0, maxid + 1);
26 | }
27 |
28 | console.log(longestCommonPrefix(["abca", "abc", "abca", "abc", "abcc"]))
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/11.webpack原理/demo/bundle.js:
--------------------------------------------------------------------------------
1 | // 1. 获取模块内容
2 | const fs = require("fs");
3 | const parser = require("@babel/parser");
4 | const path = require("path");
5 | const traverse = require("@babel/traverse").default;
6 | // 获取文件内容的函数
7 | const getModuleInfo = (file) => {
8 | const body = fs.readFileSync(file, "utf-8");
9 | const ast = parser.parse(body, {
10 | sourceType: "module", // 表示解析Es6模块
11 | });
12 | const deps = {}; // 收集依赖路径
13 |
14 | traverse(ast, {
15 | ImportDeclaration({ node }) {
16 | const dirname = path.dirname(file);
17 | const abspath = "./" + path.join(dirname, node.source.value);
18 | deps[node.source.value] = abspath;
19 | },
20 | });
21 | console.log(deps);
22 | };
23 | getModuleInfo("./src/index.js");
24 |
--------------------------------------------------------------------------------
/4.深拷贝和浅拷贝/3.js:
--------------------------------------------------------------------------------
1 | // 序列化反序列化法 使用JSON对象的parse和stringify方法来实现深拷贝
2 | function deepClone(obj) {
3 | let _obj = JSON.stringify(obj),
4 | objClone = JSON.parse(_obj);
5 | return objClone
6 | }
7 | let obj1 = {
8 | a: {
9 | b: 1
10 | }
11 | };
12 | Object.defineProperty(obj1, 'innumerable', {
13 | value: '不可枚举属性',
14 | enumerable: false
15 | });
16 | let obj2 = deepClone(obj1)
17 | console.log(obj1)
18 | console.log(obj2)
19 | // 它也只能深拷贝对象和数组,对于其他种类的对象,会失真。
20 | // 这种方法比较适合平常开发中使用,因为通常不需要考虑对象和数组之外的类型。
21 |
22 | // 拷贝的对象的值中如果有函数,undefined,symbol则经过JSON.stringify()序列化后的JSON字符串中这个键值对会消失
23 | // 无法拷贝不可枚举的属性, 无法拷贝对象的原型链
24 | // 拷贝Date引用类型会变成字符串
25 | // 拷贝RegExp引用类型会变成空对象
26 | // 对象中含有NaN、 Infinity和 - Infinity, 则序列化的结果会变成null
27 | // 无法拷贝对象的循环应用(即obj[key] = obj)
--------------------------------------------------------------------------------
/4.深拷贝和浅拷贝/7.js:
--------------------------------------------------------------------------------
1 | /*
2 | 但如果这时我们使用 Reflect 实现的版本:
3 | 成功了,因为 for...in 无法获得 Symbol 类型的键,而 Reflect 是可以获取的。
4 |
5 | 当然,我们改造一下 for...in 实现也可以:
6 |
7 | */
8 | function deepClone(obj) {
9 | if (!isObject(obj)) {
10 | throw new Error('obj 不是一个对象!')
11 | }
12 |
13 | let isArray = Array.isArray(obj)
14 | let cloneObj = isArray ? [] : {}
15 | let symKeys = Object.getOwnPropertySymbols(obj)
16 | // console.log(symKey)
17 | if (symKeys.length > 0) {
18 | symKeys.forEach(symKey => {
19 | cloneObj[symKey] = isObject(obj[symKey]) ? deepClone(obj[symKey]) : obj[symKey]
20 | })
21 | }
22 | for (let key in obj) {
23 | cloneObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key]
24 | }
25 |
26 | return cloneObj
27 | }
--------------------------------------------------------------------------------
/17.手写redux/index2.js:
--------------------------------------------------------------------------------
1 | function createStore() {
2 | //需要监听的值
3 | let data = 0;
4 | //所有依赖的对列
5 | let listenters = [];
6 | //收集依赖方法
7 | function subscribe(listener) {
8 | listenters.push(listener);
9 | }
10 | //用来重写数据的赋值操作,添加通知所有依赖的操作
11 | function dispatch(val) {
12 | data = val;
13 | listenters.forEach((v, i) => {
14 | v();
15 | })
16 | }
17 | function getState() {
18 | return data
19 | }
20 | return {
21 | subscribe,
22 | dispatch,
23 | getState
24 | }
25 |
26 | }
27 | let store = createStore()
28 | //我们主动收集一下需要通知的依赖
29 | store.subscribe(() => {
30 | console.log("监听到数据变化");
31 | })
32 | console.log("改变前----" + store.getState());//改变前----0
33 | store.dispatch(1);
34 | console.log("改变后----" + store.getState());//改变后----1
35 |
36 |
--------------------------------------------------------------------------------
/4.深拷贝和浅拷贝/2.js:
--------------------------------------------------------------------------------
1 | // 循环递归法2
2 | function isObject(o) {
3 | return (typeof o === 'object' || typeof o === 'function') && o !== null
4 | }
5 |
6 | function deepClone(obj) {
7 | if (!isObject(obj)) {
8 | throw new Error('obj 不是一个对象!')
9 | }
10 |
11 | let isArray = Array.isArray(obj)
12 | let cloneObj = isArray ? [...obj] : {
13 | ...obj
14 | }
15 | // Reflect.ownKeys 返回对象的所有属性
16 | Reflect.ownKeys(cloneObj).forEach(key => {
17 | cloneObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key]
18 | })
19 |
20 | return cloneObj
21 | }
22 |
23 | let sym = Symbol('我是一个Symbol')
24 | let obj1 = {
25 | a: {
26 | b: 1,
27 |
28 | },
29 | }
30 | obj1[sym] = 111
31 | let obj2 = deepClone(obj1)
32 | console.log(obj1)
33 | console.log(obj2)
--------------------------------------------------------------------------------
/20.反转二叉树/index.js:
--------------------------------------------------------------------------------
1 | const obj = {
2 | 'id': '4',
3 | 'left': {
4 | 'id': '2',
5 | 'left': {
6 | 'id': '1',
7 | 'left': null,
8 | 'right': null
9 | },
10 | 'right': {
11 | 'id': '3',
12 | 'left': null,
13 | 'right': null
14 | }
15 | },
16 | 'right': {
17 | 'id': '7',
18 | 'left': {
19 | 'id': '6',
20 | 'left': null,
21 | 'right': null
22 | },
23 | 'right': {
24 | 'id': '9',
25 | 'left': null,
26 | 'right': null
27 | }
28 | }
29 | }
30 |
31 |
32 | function invertTree(root) {
33 | if (root !== null) {
34 | let temp = root.left
35 | root.left = root.right
36 | root.right = temp
37 | invertTree(root.left)
38 | invertTree(root.right)
39 | }
40 | return root
41 | }
42 |
43 | console.log(invertTree(obj))
--------------------------------------------------------------------------------
/21.字符串的全排列/index.js:
--------------------------------------------------------------------------------
1 | // > 'abc'
2 |
3 | // > ['abc', 'acb', 'bac', 'bca', 'cab', 'cba']
4 | // [][abc]
5 | // [a][bc]
6 | // [ab][c]
7 | // [abc][]
8 | // [ac][b]
9 | // [acb][]
10 |
11 | function pre(s) {
12 | let res = []
13 | s = s.split('').sort((a, b) => {
14 | return a > b ? 1 : -1
15 | }).join('')
16 | const dfs = (curr, store) => {
17 | // 1. 是否满足条件添加
18 | if (!store.length) {
19 | return res.push(curr)
20 | }
21 | for (let i = 0; i < store.length; i++) {
22 | if (i > 0 && store[i] === store[i - 1]) continue
23 | // 3. 递归 dfs
24 | console.log(curr + store[i], store.slice(0, i) + store.slice(i + 1))
25 | dfs(curr + store[i], store.slice(0, i) + store.slice(i + 1))
26 | }
27 |
28 | }
29 | dfs('', s)
30 | return res
31 | }
32 |
33 | console.log(pre('abc'))
--------------------------------------------------------------------------------
/13.Vue2.0和Vue3.0的响应式原理/06.Proxy嵌套的支持.js:
--------------------------------------------------------------------------------
1 | // Proxy 也是不支持嵌套的, 这点和 Object.defineProperty() 是一样的。
2 | // 因此也需要通过逐层遍历来解决。 Proxy 的写法是在 get 里面递归调用 Proxy 并返回
3 | let obj = {
4 | info: {
5 | name: '铁蛋儿',
6 | blogs: ['webpack', 'gulp', 'babel']
7 | }
8 | }
9 | let handler = {
10 | get(target, key, receiver) {
11 | console.log('get', key)
12 | // 递归创建并返回
13 | if (typeof target[key] === 'object' && target[key] !== null) {
14 | return new Proxy(target[key], handler)
15 | }
16 | return Reflect.get(target, key, receiver)
17 | },
18 | set(target, key, value, receiver) {
19 | console.log('set', key, value)
20 | return Reflect.set(target, key, value, receiver)
21 | }
22 | }
23 | let proxy = new Proxy(obj, handler)
24 | // 以下两句都能够进入 set
25 | proxy.info.name = '小白龙'
--------------------------------------------------------------------------------
/14.手写async函数/3.js:
--------------------------------------------------------------------------------
1 | const getData = () => new Promise(resolve => setTimeout(() => resolve('data'), 1000));
2 |
3 | function* testG() {
4 | const data = yield getData();
5 | console.log('data: ', data);
6 | const data2 = yield getData();
7 | console.log('data2: ', data2);
8 | return 'success';
9 | }
10 |
11 |
12 |
13 | function co(generator) {
14 | return new Promise((resolve, reject) => {
15 | const gen = generator();
16 |
17 | function next(...param) {
18 | let tmp = gen.next(...param);
19 | if (tmp.done) {
20 | resolve(tmp.value);
21 | return;
22 | }
23 | tmp.value.then((...ret) => {
24 | next(...ret);
25 | })
26 | }
27 | next();
28 | })
29 | }
30 |
31 | co(testG).then((res) => {
32 | console.log(res);
33 | })
--------------------------------------------------------------------------------
/27.数组转为树/1.js:
--------------------------------------------------------------------------------
1 | const data = [
2 | { id: 1, parentId: null },
3 | { id: 2, parentId: 1 },
4 | { id: 3, parentId: 1 },
5 | { id: 4, parentId: 2 },
6 | { id: 5, parentId: 2 },
7 | { id: 6, parentId: 3 }
8 | ]
9 |
10 | function createNode(id, data) {
11 | // data中去查找根节点下有哪些子节点
12 | const childData = data.filter(({ parentId }) => parentId === id)
13 |
14 | // 重写节点
15 |
16 | const node = {
17 | id,
18 | children: childData.reduce((acc, cur) => {
19 | acc.push(createNode(cur.id, data))
20 | return acc;
21 | }, [])
22 | }
23 | return node
24 | }
25 |
26 | function getTree(data) {
27 | // 获取到哪个是根节点
28 | const rootNodeData = data.find(({ parentId }) => parentId === null)
29 |
30 | if (!rootNodeData) {
31 | throw new Error('数据中找不到根的节点')
32 | }
33 |
34 | // 从根节点开始创建,构建树形结构
35 | return createNode(rootNodeData.id, data)
36 | }
37 |
38 | console.log(JSON.stringify(getTree(data)))
--------------------------------------------------------------------------------
/11.webpack原理/loader/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | const DemoWebpackPlugin = require('./demo-webpack-plugin')
3 | module.exports = {
4 | mode: 'development',
5 | plugins: [
6 | new DemoWebpackPlugin()
7 | ],
8 | entry: {
9 | main: './src/index.js'
10 | },
11 | output: {
12 | path: path.resolve(__dirname, 'dist'),
13 | filename: '[name].js'
14 | },
15 | resolveLoader: {
16 | // loader路径查找顺序从左往右
17 | modules: ['node_modules', './']
18 | },
19 | module: {
20 | rules: [{
21 | test: /\.js$/,
22 | use: [{
23 | loader: 'syncLoader',
24 | options: {
25 | message: '走上人生巅峰'
26 | }
27 | },
28 | {
29 | loader: 'asyncLoader'
30 | }
31 | ]
32 | }]
33 | }
34 | }
--------------------------------------------------------------------------------
/4.深拷贝和浅拷贝/1.js:
--------------------------------------------------------------------------------
1 | // 循环递归法1
2 | function isObject(obj) {
3 | return (typeof obj === 'object' || typeof obj === 'function') && obj !== null
4 | }
5 | // 迭代递归法:深拷贝对象与数组
6 | function deepClone(obj) {
7 | if (!isObject(obj)) {
8 | throw new Error('obj 不是一个对象!')
9 | }
10 |
11 | let isArray = Array.isArray(obj)
12 |
13 | let cloneObj = isArray ? [] : {}
14 |
15 | for (let key in obj) {
16 | cloneObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key]
17 | }
18 |
19 | return cloneObj
20 | }
21 | let sym = Symbol('我是一个Symbol')
22 | let obj1 = {
23 | a: {
24 | b: 1,
25 |
26 | },
27 | }
28 | obj1[sym] = 111
29 | let obj2 = deepClone(obj1)
30 | console.log(obj1)
31 | console.log(obj2)
32 | /*
33 | 深拷贝是针对引用类型的, 在进行深拷贝之前, 我们应该先知道js中有哪些引用类型,
34 | js中引用类型目前有六种: object, array, date, regexp,
35 | function, err。 下面的两种方法只能实现object, array的深拷贝。
36 | 循环递归法 function、Date、RegExp 和Error无法复制 因为它们有特殊的构造函数。
37 | */
--------------------------------------------------------------------------------
/2.发布订阅者和观察者/观察者模式.js:
--------------------------------------------------------------------------------
1 | // 被观察者 (小宝宝)
2 | class Subject {
3 | constructor(name) {
4 | this.name = name;
5 | this.state = "开心"; // 被观察者的状态
6 | this.observers = []; // 存放观察者
7 | }
8 | // 需要将观察者放到自己的身上
9 | attach(ther) {
10 | this.observers.push(ther);
11 | }
12 | // 更新被观察者的状态
13 | setState(state) {
14 | this.state = state;
15 | this.observers.forEach(ther => {
16 | ther.update(this);
17 | });
18 | }
19 | }
20 | // 观察者
21 | class Observer {
22 | constructor(name) {
23 | this.name = name;
24 | }
25 | // 等会被观察者的状态发生变化会调用这个方法
26 | update(subject) {
27 | console.log(this.name + ":" + subject.name + "当前状态是" + subject.state);
28 | }
29 | }
30 | let bady = new Subject("小宝宝");
31 | let father = new Observer("爸爸");
32 | let mother = new Observer("妈妈");
33 | bady.attach(father);
34 | bady.attach(mother);
35 | bady.setState("不开心");
36 | bady.setState("饿了");
--------------------------------------------------------------------------------
/7.Vue自定义事件原理/3.原理分析.js:
--------------------------------------------------------------------------------
1 | // 事件中心
2 | vm._events = {
3 | a: [fn],
4 | b: [fn, fn]
5 | }
6 | Vue.prototype.$on = function (event, fn) {
7 | var vm = this;
8 | if (Array.isArray(event)) {
9 | for (var i = 0, l = event.length; i < l; i++) {
10 | vm.$on(event[i], fn);
11 | }
12 | } else {
13 | (vm._events[event] || (vm._events[event] = [])).push(fn);
14 | }
15 | return vm
16 | };
17 |
18 | Vue.prototype.$emit = function (event) {
19 | var vm = this;
20 | var cbs = vm._events[event]; // 根据事件名找对应数组也是回调集合
21 | if (cbs) {
22 | var args = toArray(arguments, 1);
23 | for (var i = 0, l = cbs.length; i < l; i++) {
24 | cbs[i].apply(vm, args)
25 | }
26 | }
27 | return vm
28 | };
29 | // 监听事件
30 | vm.$on(['a', 'b'], function (data) {
31 | // data是传过来的数据
32 | })
33 | vm.$on('b', function (data) {
34 | // data是传过来的数据
35 | })
36 | // 触发事件
37 | vm.$emit('b', this.data)
--------------------------------------------------------------------------------
/17.手写redux/index4.js:
--------------------------------------------------------------------------------
1 | function createStore(reducer) {
2 | let data = 0;
3 | let listenters = [];
4 |
5 | function subscribe(listener) {
6 | listenters.push(listener);
7 | }
8 | //修改 store. dispatch方法,告诉它修改 state 的时候,按照我们的计划修改
9 | function dispatch(action) {
10 | data = reducer(data, action);
11 | listenters.forEach((v, i) => {
12 | v();
13 | });
14 | }
15 | function getState(params) {
16 | return data;
17 | }
18 | return {
19 | subscribe,
20 | dispatch,
21 | getState
22 | };
23 | }
24 |
25 | function reducer(state, action) {
26 | switch (action.type) {
27 | case 'INCREMENT':
28 | return ++state
29 | default:
30 | return state;
31 | }
32 | }
33 | //告诉 store,我的修改计划是什么
34 | let store = createStore(reducer);
35 | store.subscribe(() => {
36 | // console.log("监听到数据变化");
37 | });
38 | let action = {
39 | type: "INCREMENT"
40 | }
41 | store.dispatch(action);
42 | console.log(store.getState());//1
43 |
--------------------------------------------------------------------------------
/11.webpack原理/loader/demo-webpack-plugin.js:
--------------------------------------------------------------------------------
1 | class DemoWebpackPlugin {
2 | constructor() {
3 | console.log('plugin init')
4 | }
5 | // compiler是webpack实例
6 | apply(compiler) {
7 | // 一个新的编译(compilation)创建之后(同步)
8 | // compilation代表每一次执行打包,独立的编译
9 | compiler.hooks.compile.tap('DemoWebpackPlugin', compilation => {
10 | console.log('123')
11 | })
12 | // 生成资源到 output 目录之前(异步)
13 | compiler.hooks.emit.tapAsync('DemoWebpackPlugin', (compilation, fn) => {
14 | console.log('456')
15 | compilation.assets['index.md'] = {
16 | // 文件内容
17 | source: function () {
18 | return 'this is a demo for plugin'
19 | },
20 | // 文件尺寸
21 | size: function () {
22 | return 25
23 | }
24 | }
25 | fn()
26 | })
27 | }
28 | }
29 |
30 | module.exports = DemoWebpackPlugin
--------------------------------------------------------------------------------
/4.深拷贝和浅拷贝/5.js:
--------------------------------------------------------------------------------
1 | /*
2 | 对象成环怎么办?
3 | 我们给 test 加一个 loopObj 键,值指向自身:
4 | test.loopObj = test
5 | 这时我们使用第一种方法中的 for..in 实现和 Reflect 实现都会栈溢出:
6 |
7 | 环对象深拷贝报错
8 | 而使用第二种方法也会报错:
9 |
10 |
11 | 但 lodash 却可以得到正确结果:
12 |
13 |
14 | 因为 lodash 使用的是栈把对象存储起来了,如果有环对象,就会从栈里检测到,
15 | 从而直接返回结果,悬崖勒马。这种算法思想来源于 HTML5 规范定义的结构化克隆算法,
16 | 它同时也解释了为什么 lodash 不对 Error 和 Function 类型进行拷贝。
17 |
18 |
19 | 当然,设置一个哈希表存储已拷贝过的对象同样可以达到同样的目的:
20 | */
21 |
22 |
23 | function deepClone(obj, hash = new WeakMap()) {
24 | if (!isObject(obj)) {
25 | return obj
26 | }
27 | // 查表
28 | if (hash.has(obj)) return hash.get(obj)
29 |
30 | let isArray = Array.isArray(obj)
31 | let cloneObj = isArray ? [] : {}
32 | // 哈希表设值
33 | hash.set(obj, cloneObj)
34 |
35 | let result = Object.keys(obj).map(key => {
36 | return {
37 | [key]: deepClone(obj[key], hash)
38 | }
39 | })
40 | return Object.assign(cloneObj, ...result)
41 | }
42 |
43 | //这里我们使用 WeakMap 作为哈希表,因为它的键是弱引用的,而我们这个场景里键恰好是对象,需要弱引用。
--------------------------------------------------------------------------------
/13.Vue2.0和Vue3.0的响应式原理/01.defineProperty.js:
--------------------------------------------------------------------------------
1 | /**
2 | Object.defineProperty(obj, prop, descriptor)
3 | 参数1:obj: 要在其上定义属性的对象。
4 | 参数2:prop: 要定义或修改的属性的名称。
5 | 参数3:descriptor: 将被定义或修改的属性的描述符(包含数据描述符和存取描述符)。
6 | **/
7 | //数据描述符
8 | let obj1 = {};
9 | Object.defineProperty(obj1, "key", {
10 | //该属性对应的值,默认为 undefined。
11 | value: 1,
12 | //属性的 writable 为 true 时,该属性才能被赋值运算符改变。默认为 false。
13 | writable: true,
14 | //属性的 enumerable 为 true 时,
15 | //该属性才能够出现在对象的枚举属性中。默认为 false。
16 | enumerable: true,
17 | //属性的configurable 为 true 时,
18 | //该属性描述符才能够被改变,也能够被删除。默认为 false。
19 | configurable: true,
20 | });
21 |
22 | console.log(obj1);
23 |
24 | // 存取描述符
25 | let obj2 = {};
26 | let value;
27 | Object.defineProperty(obj2, "key", {
28 | // 数据描述符.....
29 | get: function () {
30 | console.log("执行了获取操作");
31 |
32 | return value;
33 | },
34 | set: function (newValue) {
35 | console.log("执行了设置操作");
36 |
37 | value = newValue + "真帅!!!!";
38 | },
39 | });
40 | //执行get
41 | console.log(obj2.key);
42 | //执行set
43 | obj2.key = "铁蛋儿";
--------------------------------------------------------------------------------
/13.Vue2.0和Vue3.0的响应式原理/04.Proxy.js:
--------------------------------------------------------------------------------
1 | // let pro = new Proxy(target, handler);
2 | // new Proxy相当于创建了一个Proxy实例,
3 | // target为所要拦截的目标对象,
4 | // handler也是一个对象, 里面定义的是对拦截对象所要进行的拦截方法。
5 |
6 | // 针对对象: 针对整个对象,而不是对象的某个属性
7 | // 支持数组: 不需要对数组的方法进行重载,省去了重写数组的方法
8 | // 嵌套支持: get里面递归调用Proxy并返回
9 | // 不需要对keys 进行遍历。这解决Object.defineProperty() 的第二个问题.Proxy 是针对整个 obj 的。
10 | // 所以 obj 内部包含的所有的 key ,都可以走进 set。(省了一个 Object.keys() 的遍历)
11 |
12 |
13 | // 另外 Reflect.get 和 Reflect.set 可以理解为类继承里的super,即调用原来的方法
14 |
15 |
16 | // Reflect.get():获取对象身上某个属性的值,类似于 target[name]。
17 | // Reflect.set():将值分配给属性的函数,返回一个Boolean,如果更新成功,则返回true
18 | let obj = {
19 | name: '铁蛋儿',
20 | age: 30
21 | }
22 | let handler = {
23 | get(target, key, receiver) {
24 | console.log('get', key)
25 | return Reflect.get(target, key, receiver)
26 | },
27 | set(target, key, value, receiver) {
28 | console.log('set', key, value)
29 | return Reflect.set(target, key, value, receiver)
30 | }
31 | }
32 | let proxy = new Proxy(obj, handler)
33 | proxy.name = '小白龙' // set name 小白龙
34 | proxy.age = 18 // set age 18
--------------------------------------------------------------------------------
/17.手写redux/index3.js:
--------------------------------------------------------------------------------
1 | function createStore() {
2 | //需要监听的值
3 | let data = 0;
4 | //所有依赖的对列
5 | let listenters = [];
6 | //收集依赖方法
7 | function subscribe(listener) {
8 | listenters.push(listener);
9 | }
10 | //用来重写数据的赋值操作,添加通知所有依赖的操作
11 | function dispatch(val) {
12 | data = val;
13 | listenters.forEach((v, i) => {
14 | v();
15 | })
16 | }
17 | function getState() {
18 | return data
19 | }
20 | return {
21 | subscribe,
22 | dispatch,
23 | getState
24 | }
25 |
26 | }
27 | let store = createStore()
28 | //我们主动收集一下需要通知的依赖
29 | store.subscribe(() => {
30 | console.log("监听到数据变化");
31 | })
32 | console.log("改变前----" + store.getState());//改变前----0
33 | store.dispatch(1);
34 | console.log("改变后----" + store.getState());//改变后----1
35 |
36 | //状态会自增
37 | // setInterval(() => {
38 | // let count = store.getState();
39 | // count++
40 | // console.log(store.getState());
41 | // store.dispatch(count);
42 | // }, 1000)
43 |
44 | // console.log(store.getState());//0
45 | setInterval(() => {
46 | let count = store.getState();
47 | count++
48 | console.log(store.getState());
49 | store.dispatch(count);
50 | }, 1000)
51 | store.dispatch("abc");
52 |
--------------------------------------------------------------------------------
/19.对象扁平化/index.js:
--------------------------------------------------------------------------------
1 | let obj = {
2 | a: 'a',
3 | b: [1, { c: true }, [3]],
4 | d: { e: undefined, f: 3 },
5 | g: null,
6 | }
7 | // {
8 | // a: "a",
9 | // b[0]: 1,
10 | // b[1].c: true,
11 | // b[2][0]: 3,
12 | // d.f: 3
13 |
14 | // }
15 |
16 | function test(obj) {
17 | const res = {}
18 | function _test(obj, prev = null) {
19 | // 数组
20 | if (Array.isArray(obj)) {
21 | for (const index in obj) {
22 | const val = obj[index]
23 | if (val instanceof Object) {
24 | _test(val, `${prev ? prev : +''}[${index}]`)
25 | } else {
26 | res[`${prev ? prev : +''}[${index}]`] = val
27 | }
28 | }
29 | return
30 | }
31 |
32 | // 对象
33 | for (const key in obj) {
34 | if (typeof obj[key] === 'object') {
35 | // null
36 | if (obj[key] !== null) {
37 | _test(obj[key], `${prev ? prev + '.' : ''}${key} `)
38 | }
39 | } else {
40 | // undefined
41 | if (obj[key] !== undefined) {
42 | res[`${prev ? prev + '.' : ''}${key} `] = obj[key]
43 | }
44 | }
45 | }
46 | }
47 | _test(obj)
48 | return res
49 | }
50 |
51 |
52 | console.log(test(obj))
--------------------------------------------------------------------------------
/13.Vue2.0和Vue3.0的响应式原理/02.defineProperty监听数据的变化.js:
--------------------------------------------------------------------------------
1 | // 监听的数据
2 | let obj = {
3 | name: '铁蛋儿',
4 | age: 1,
5 | arr: ['张三', '李四', '王五'],
6 | job: {
7 | code: 'FE'
8 | }
9 | }
10 |
11 | // 封装监听数据变化的函数
12 | function defineProperty(obj, key, val) {
13 | observer(val)
14 | Object.defineProperty(obj, key, {
15 | get() {
16 | // 读取方法
17 | console.log('读取', key, '成功')
18 | return val
19 | },
20 | set(newval) {
21 | // 赋值监听方法
22 | if (newval === val) return
23 | // 遍历监听数据的每一项
24 | observer(newval)
25 | console.log('监听赋值成功', newval)
26 | val = newval
27 | // 可以执行渲染操作
28 | }
29 | })
30 | }
31 |
32 | function observer(obj) {
33 | if (typeof obj !== 'object' || obj == null) {
34 | return
35 | }
36 | for (const key in obj) {
37 | // 给对象中的每一项都设置响应式
38 | defineProperty(obj, key, obj[key])
39 | }
40 | }
41 |
42 | observer(obj)
43 |
44 |
45 | // obj.name = '小白龙'
46 |
47 | // obj.job.code = 'server'
48 |
49 | // obj.name = {
50 | // sname: '欧巴'
51 | // }
52 | // obj.name.sname = '欧巴铁蛋儿'
53 |
54 | obj.arr[3] = 1
55 | // obj.arr.push([1,[2,[3]]])
--------------------------------------------------------------------------------
/6.Promise、Async/promise._all.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs')
2 | const util = require('util')
3 | let readFile = util.promisify(fs.readFile)
4 |
5 | let isPromise = (x) => {
6 | if ((typeof x === 'object' && x != null) || typeof x === 'function') {
7 | if (typeof x.then === 'function') {
8 |
9 | return true
10 | }
11 | }
12 | return false;
13 | }
14 |
15 | Promise.all = (promises) => {
16 | console.log('all')
17 | return new Promise((resolve, reject) => {
18 | let arr = []
19 | let idx = 0
20 | let promisesData = (value, index) => {
21 | arr[index] = value
22 | if (++idx === promises.length) {
23 | resolve(arr)
24 | }
25 | }
26 | for (let i = 0; i < promises.length; i++) {
27 | let x = promises[i]
28 | if (isPromise(x)) {
29 | x.then(y => {
30 | promisesData(y, i)
31 | }, reject)
32 | } else {
33 | promisesData(x, i)
34 | }
35 | }
36 | })
37 | }
38 |
39 | Promise.all([1, readFile('./name.txt', 'utf-8'), readFile('./age.txt', 'utf-8'), 3])
40 | .then(data => {
41 | console.log(data)
42 | })
--------------------------------------------------------------------------------
/10.Vue和React路由原理/hash.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
9 |
10 |
11 |
12 |
13 | - home
14 | - about
15 |
16 |
17 |
18 |
19 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/17.手写redux/index.js:
--------------------------------------------------------------------------------
1 | function createStore() {
2 | // 需要监听的值
3 | let data = 0
4 |
5 | // 收集依赖
6 | let listenters = []
7 |
8 | // 收集依赖的方法
9 | function subscribe(listenter) {
10 | listenters.push(listenter)
11 | }
12 |
13 | // 发生改变通知左右依赖项
14 | function dispatch(action) {
15 | data = reducer(data, action)
16 | listenters.forEach((v, i) => {
17 | v()
18 | })
19 | }
20 | // 获取状态
21 | function getState() {
22 | return data
23 | }
24 | return {
25 | subscribe,
26 | dispatch,
27 | getState
28 | }
29 | }
30 | function reducer(state, action) {
31 | switch (action.type) {
32 | case "TIEDAN":
33 | return ++state
34 | default:
35 | return state
36 | }
37 | }
38 |
39 | const store = createStore()
40 | store.subscribe(() => {
41 | console.log('监听的数据发生变化了')
42 | })
43 | // console.log('改变前' + store.getState())
44 | // // 改变监听的值
45 | // store.dispatch(1)
46 |
47 | // console.log('改变后' + store.getState())
48 |
49 | // setInterval(() => {
50 | // let count = store.getState()
51 | // count++
52 | // console.log(store.getState())
53 | // store.dispatch(count)
54 | // }, 1000)
55 | // store.dispatch('tiedan')
56 | let action = {
57 | type: "TIEDAN"
58 | }
59 |
60 |
61 | store.dispatch(action)
62 |
63 | console.log(store.getState())
--------------------------------------------------------------------------------
/3.防抖和节流/防抖和截流.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
9 |
10 |
11 |
42 |
43 |
44 |
45 |
46 |