├── .DS_Store
├── 示例代码
├── JSONs
│ ├── .vscode
│ │ └── settings.json
│ ├── index.html
│ └── index.js
├── .DS_Store
├── PostMessage
│ ├── index
│ │ ├── .vscode
│ │ │ └── settings.json
│ │ └── index.html
│ └── other
│ │ └── index.html
├── ESNext
│ ├── .DS_Store
│ ├── modules
│ │ ├── main.js
│ │ └── index.html
│ ├── 01.basic
│ │ └── index.js
│ ├── 03.异步操作
│ │ ├── generator.js
│ │ └── async-await.js
│ └── 02.Proxy
│ │ └── index.js
├── requestAnimationFrame
│ ├── index.css
│ ├── index.html
│ └── index.js
├── doms
│ ├── js
│ │ ├── lib.js
│ │ └── index.js
│ └── index.html
├── Object
│ ├── index.js
│ └── index.html
├── Event
│ ├── index.js
│ └── index.html
├── BrowserCaches
│ ├── 02_localStorage
│ │ ├── index.js
│ │ └── index.html
│ ├── 01_Cookie
│ │ ├── index.js
│ │ ├── index.html
│ │ └── Cookies.js
│ └── 03_indexDB
│ │ ├── index.html
│ │ ├── index.js
│ │ └── utils.js
├── DesignPatterns
│ ├── 01.工厂模式.js
│ ├── 03.观察者模式.js
│ ├── 04.发布订阅者模式.js
│ └── 02.单例模式.js
├── Basic
│ └── 01_基础语法.js
├── Eventloops
│ └── index.js
├── DebounceAndThrottle
│ └── index.html
└── Promise
│ └── 01.基础用法
│ └── index.js
├── IMGS
├── rAF.gif
├── 任务队列.png
├── .DS_Store
├── extends.png
├── rect.jpeg
├── ec_stack.png
├── location.jpeg
├── nodeTree.png
├── part_2_1.png
├── part_2_2.jpg
├── part_3_8.jpeg
├── part_3_9.jpeg
├── part_6_1.jpeg
├── part_6_2.jpeg
├── part_6_3.jpeg
├── part_6_4.jpeg
├── part_6_5.jpeg
├── part_6_6.jpeg
├── part_6_8.png
├── useragent.jpg
├── bom_location.png
├── bom_screen.png
├── part_10_14.jpeg
├── part_10_15.jpeg
├── part_10_16.jpeg
├── part_10_17.jpeg
├── part_3_10.jpeg
├── post_message.png
├── scope_word.png
├── flowOfEvents.jpeg
├── page_renders.jpeg
├── execution_stack.gif
├── indexDB_examples.jpg
├── js_life_circles.png
└── prototype-chain.png
├── 思维导图
├── .DS_Store
├── DOM树.xmind
├── 任务队列.xmind
├── 渲染进程.xmind
└── 运行生命周期.xmind
├── 第08章 Symbol.md
├── 第12章 定时器与延迟函数.md
├── 第15章 异常处理.md
├── 第11章 BOM.md
├── 第17章 requestAnimationFrame.md
├── 第16章 事件循环.md
├── 第14章 正则表达式.md
├── 第13章 浏览器缓存.md
├── 第03章 数值.md
├── 第18章 设计模式.md
├── 第10章 事件.md
├── README.md
├── 第02章 程序结构.md
├── 第08章 内置对象.md
├── 第09章 DOM.md
└── 第04章 字符串.md
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/.DS_Store
--------------------------------------------------------------------------------
/示例代码/JSONs/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "liveServer.settings.port": 5501
3 | }
--------------------------------------------------------------------------------
/IMGS/rAF.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/IMGS/rAF.gif
--------------------------------------------------------------------------------
/IMGS/任务队列.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/IMGS/任务队列.png
--------------------------------------------------------------------------------
/IMGS/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/IMGS/.DS_Store
--------------------------------------------------------------------------------
/IMGS/extends.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/IMGS/extends.png
--------------------------------------------------------------------------------
/IMGS/rect.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/IMGS/rect.jpeg
--------------------------------------------------------------------------------
/思维导图/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/思维导图/.DS_Store
--------------------------------------------------------------------------------
/思维导图/DOM树.xmind:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/思维导图/DOM树.xmind
--------------------------------------------------------------------------------
/思维导图/任务队列.xmind:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/思维导图/任务队列.xmind
--------------------------------------------------------------------------------
/思维导图/渲染进程.xmind:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/思维导图/渲染进程.xmind
--------------------------------------------------------------------------------
/示例代码/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/示例代码/.DS_Store
--------------------------------------------------------------------------------
/IMGS/ec_stack.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/IMGS/ec_stack.png
--------------------------------------------------------------------------------
/IMGS/location.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/IMGS/location.jpeg
--------------------------------------------------------------------------------
/IMGS/nodeTree.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/IMGS/nodeTree.png
--------------------------------------------------------------------------------
/IMGS/part_2_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/IMGS/part_2_1.png
--------------------------------------------------------------------------------
/IMGS/part_2_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/IMGS/part_2_2.jpg
--------------------------------------------------------------------------------
/IMGS/part_3_8.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/IMGS/part_3_8.jpeg
--------------------------------------------------------------------------------
/IMGS/part_3_9.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/IMGS/part_3_9.jpeg
--------------------------------------------------------------------------------
/IMGS/part_6_1.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/IMGS/part_6_1.jpeg
--------------------------------------------------------------------------------
/IMGS/part_6_2.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/IMGS/part_6_2.jpeg
--------------------------------------------------------------------------------
/IMGS/part_6_3.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/IMGS/part_6_3.jpeg
--------------------------------------------------------------------------------
/IMGS/part_6_4.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/IMGS/part_6_4.jpeg
--------------------------------------------------------------------------------
/IMGS/part_6_5.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/IMGS/part_6_5.jpeg
--------------------------------------------------------------------------------
/IMGS/part_6_6.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/IMGS/part_6_6.jpeg
--------------------------------------------------------------------------------
/IMGS/part_6_8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/IMGS/part_6_8.png
--------------------------------------------------------------------------------
/IMGS/useragent.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/IMGS/useragent.jpg
--------------------------------------------------------------------------------
/思维导图/运行生命周期.xmind:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/思维导图/运行生命周期.xmind
--------------------------------------------------------------------------------
/示例代码/PostMessage/index/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "liveServer.settings.port": 5501
3 | }
--------------------------------------------------------------------------------
/IMGS/bom_location.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/IMGS/bom_location.png
--------------------------------------------------------------------------------
/IMGS/bom_screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/IMGS/bom_screen.png
--------------------------------------------------------------------------------
/IMGS/part_10_14.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/IMGS/part_10_14.jpeg
--------------------------------------------------------------------------------
/IMGS/part_10_15.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/IMGS/part_10_15.jpeg
--------------------------------------------------------------------------------
/IMGS/part_10_16.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/IMGS/part_10_16.jpeg
--------------------------------------------------------------------------------
/IMGS/part_10_17.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/IMGS/part_10_17.jpeg
--------------------------------------------------------------------------------
/IMGS/part_3_10.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/IMGS/part_3_10.jpeg
--------------------------------------------------------------------------------
/IMGS/post_message.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/IMGS/post_message.png
--------------------------------------------------------------------------------
/IMGS/scope_word.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/IMGS/scope_word.png
--------------------------------------------------------------------------------
/示例代码/ESNext/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/示例代码/ESNext/.DS_Store
--------------------------------------------------------------------------------
/IMGS/flowOfEvents.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/IMGS/flowOfEvents.jpeg
--------------------------------------------------------------------------------
/IMGS/page_renders.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/IMGS/page_renders.jpeg
--------------------------------------------------------------------------------
/IMGS/execution_stack.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/IMGS/execution_stack.gif
--------------------------------------------------------------------------------
/IMGS/indexDB_examples.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/IMGS/indexDB_examples.jpg
--------------------------------------------------------------------------------
/IMGS/js_life_circles.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/IMGS/js_life_circles.png
--------------------------------------------------------------------------------
/IMGS/prototype-chain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lihongyao/JavaScript/HEAD/IMGS/prototype-chain.png
--------------------------------------------------------------------------------
/示例代码/ESNext/modules/main.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: Lee
3 | * @Date: 2023-05-08 18:21:03
4 | * @LastEditors: Lee
5 | * @LastEditTime: 2023-05-08 18:21:59
6 | * @Description:
7 | */
8 | console.log('模块化');
9 |
--------------------------------------------------------------------------------
/示例代码/requestAnimationFrame/index.css:
--------------------------------------------------------------------------------
1 | .progress {
2 | width: 300px;
3 | height: 10px;
4 | border-radius: 12px;
5 | background: #eee;
6 | margin-bottom: 16px;
7 | }
8 | .v {
9 | height: 100%;
10 | background: cornflowerblue;
11 | border-radius: 12px;
12 | }
--------------------------------------------------------------------------------
/示例代码/ESNext/01.basic/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: Lee
3 | * @Date: 2023-05-30 10:54:59
4 | * @LastEditors: Lee
5 | * @LastEditTime: 2023-05-30 11:32:40
6 | * @Description:
7 | */
8 |
9 | // -- 解构
10 | // 1. 交换值
11 | let x = 10, y = 20;
12 | [x, y] = [y, x];
13 | console.log(x, y);
14 |
15 |
16 | // -- Map
17 |
18 |
--------------------------------------------------------------------------------
/示例代码/doms/js/lib.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: Lee
3 | * @Date: 2022-03-29 17:22:47
4 | * @LastEditors: Lee
5 | * @LastEditTime: 2022-11-29 15:31:10
6 | */
7 |
8 | function showDomInfos(sel) {
9 | const el = document.querySelector(sel);
10 | console.table({
11 | nodeName: el.nodeName,
12 | nodeValue: el.nodeValue,
13 | nodeType: el.nodeType,
14 | });
15 | }
16 |
--------------------------------------------------------------------------------
/示例代码/Object/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: Lee
3 | * @Date: 2022-11-29 10:44:31
4 | * @LastEditors: Lee
5 | * @LastEditTime: 2022-11-29 11:43:40
6 | * @Description:
7 | */
8 |
9 | var o1 = { name: '张三' };
10 | var o2 = { major: '软件技术', name: '李四' };
11 |
12 | var result = Object.assign(o1, o2);
13 |
14 | console.log(result); // {name: '李四', major: '软件技术'}
15 | console.log(result === o1);
16 |
--------------------------------------------------------------------------------
/示例代码/Event/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: Lee
3 | * @Date: 2022-12-01 16:05:40
4 | * @LastEditors: Lee
5 | * @LastEditTime: 2022-12-01 17:04:32
6 | * @Description:
7 | */
8 | var button = document.querySelector('.button');
9 |
10 | // -- 添加事件监听
11 | button.addEventListener('click', handler, false);
12 | // -- 移除事件监听
13 | button.removeEventListener('click', handler, false);
14 |
15 | function handler() {
16 | console.log('Hello');
17 | }
18 |
19 |
--------------------------------------------------------------------------------
/示例代码/ESNext/03.异步操作/generator.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: Lee
3 | * @Date: 2023-05-30 17:47:18
4 | * @LastEditors: Lee
5 | * @LastEditTime: 2023-05-30 17:54:56
6 | * @Description:
7 | */
8 |
9 | function* generator1() {
10 | yield 'Hello';
11 | yield 'World';
12 | }
13 |
14 | function* generator2() {
15 | yield* generator1();
16 | yield '!';
17 | }
18 |
19 | // 遍历组合的生成器
20 | const iterator = generator2();
21 | for (const item of iterator) {
22 | console.log(item); // Hello, World, !
23 | }
24 |
--------------------------------------------------------------------------------
/示例代码/Object/index.html:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | Objects
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/示例代码/JSONs/index.html:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | JSON - testing
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/示例代码/ESNext/modules/index.html:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | 模块化
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/示例代码/BrowserCaches/02_localStorage/index.js:
--------------------------------------------------------------------------------
1 | var key = '';
2 | var value = '';
3 |
4 | function onKeyChange(event) {
5 | key = event.target.value;
6 | }
7 | function onValueChange(event) {
8 | value = event.target.value;
9 | }
10 |
11 | function onSetItem() {
12 | console.log(localStorage.setItem(key, value));
13 | }
14 |
15 | function onGetItem() {
16 | console.log(localStorage.getItem(key));
17 | }
18 |
19 | function onRemoveItem() {
20 | console.log(localStorage.removeItem(key));
21 | }
22 |
23 | function onClear() {
24 | console.log(localStorage.clear());
25 | }
26 |
--------------------------------------------------------------------------------
/示例代码/Event/index.html:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | Document
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/示例代码/DesignPatterns/01.工厂模式.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: Lee
3 | * @Date: 2023-05-06 16:59:30
4 | * @LastEditors: Lee
5 | * @LastEditTime: 2023-05-06 16:59:35
6 | * @Description:
7 | */
8 | function createPerson(name, age) {
9 | return {
10 | name: name,
11 | age: age,
12 | sayHello: function () {
13 | console.log(
14 | `Hello, my name is ${this.name} and I'm ${this.age} years old.`
15 | );
16 | },
17 | };
18 | }
19 |
20 | const person1 = createPerson('John', 30);
21 | const person2 = createPerson('Jane', 25);
22 |
23 | person1.sayHello(); // 输出:Hello, my name is John and I'm 30 years old.
24 | person2.sayHello(); // 输出:Hello, my name is Jane and I'm 25 years old.
25 |
--------------------------------------------------------------------------------
/示例代码/Basic/01_基础语法.js:
--------------------------------------------------------------------------------
1 | var value = 2;
2 | var foo = {
3 | value: 1,
4 | };
5 | function bar(name, job) {
6 | return {
7 | value: this.value,
8 | name,
9 | job,
10 | };
11 | }
12 |
13 | // var r = bar.call(foo, "Alice", "Web Front-end Engineer");
14 | // console.log(r); // → { value: 1, name: 'Alice', job: 'Web Front-end Engineer' }
15 |
16 | var r = bar.apply(this, ["Alice", "Web Front-end Engineer"]); /** this 指向window, 所以this.value = 2 */
17 | console.log(r); // → {value: 2, name: 'Alice', job: 'Web Front-end Engineer'}
18 |
19 | // var func = bar.bind(foo, "Alice", "Web Front-end Engineer"); /** 返回新函数 */
20 | // console.log(func()); // → { value: 1, name: 'Alice', job: 'Web Front-end Engineer' }
21 |
--------------------------------------------------------------------------------
/示例代码/BrowserCaches/01_Cookie/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: Lee
3 | * @Date: 2022-12-05 09:25:40
4 | * @LastEditors: Lee
5 | * @LastEditTime: 2022-12-05 10:56:03
6 | * @Description:
7 | */
8 |
9 | var key = '';
10 | var value = '';
11 |
12 | function onKeyChange(event) {
13 | key = event.target.value;
14 | }
15 | function onValueChange(event) {
16 | value = event.target.value;
17 | }
18 | function onGetCookies() {
19 | console.log(docCookies.getItem(key));
20 | }
21 | function onSetCookies() {
22 | if (!key || !value) return;
23 | console.log(docCookies.setItem(key, value));
24 | }
25 | function onRemoveCookies() {
26 | console.log(docCookies.removeItem(key));
27 | }
28 |
29 | function onGetKeys() {
30 | console.log(docCookies.keys());
31 | }
32 |
--------------------------------------------------------------------------------
/示例代码/requestAnimationFrame/index.html:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | requestAnimationFrame
14 |
15 |
16 |
17 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/示例代码/PostMessage/other/index.html:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | OTHER PAGE
17 |
18 |
19 |
20 | Sub window recived message is:
21 |
22 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/示例代码/doms/index.html:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | DOMs
14 |
15 |
16 | 成都哈戳戳科技有限公司
17 |
18 | - 教学部
19 | - 教务部
20 | - 市场部
21 | - 咨询部
22 | - 行政部
23 | - 财务部
24 |
25 | 成都市高新区新川科技园A区
26 | DOMs
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/示例代码/ESNext/03.异步操作/async-await.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: Lee
3 | * @Date: 2023-03-07 20:31:44
4 | * @LastEditors: Lee
5 | * @LastEditTime: 2023-03-07 20:39:25
6 | * @Description:
7 | */
8 |
9 | // -- 线程休眠
10 | /*function sleep(seconds) {
11 | return new Promise((resolve) => setTimeout(() => resolve(seconds), seconds));
12 | }
13 |
14 | async function test() {
15 | console.log(1);
16 | await sleep(2000);
17 | console.log(2);
18 | }
19 | test();*/
20 |
21 | // -- async & await 是否可以取代Promise --- 不可以
22 | function sleep(seconds) {
23 | return new Promise((resolve) => {
24 | setTimeout(() => {
25 | console.log(Math.random());
26 | resolve();
27 | }, seconds);
28 | });
29 | }
30 |
31 | // -- 串行执行
32 | // -- 省市区
33 | async function test() {
34 | await sleep(1000);
35 | await sleep(1000);
36 | await sleep(1000);
37 | }
38 |
39 | // -- 并发执行 -- 还是得用Promise.all
40 | async function test() {
41 | const tasks = [];
42 | for (let i = 0; i < 3; i++) {
43 | tasks.push(sleep(1000));
44 | }
45 | await Promise.all(tasks);
46 | }
47 |
48 | test();
49 |
--------------------------------------------------------------------------------
/示例代码/BrowserCaches/02_localStorage/index.html:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | Web Storage
17 |
18 |
19 |
20 |
21 | 键:
22 |
23 |
24 |
25 | 值:
26 |
27 |
28 |
31 |
34 |
37 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/示例代码/BrowserCaches/01_Cookie/index.html:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | Cookie
16 |
17 |
18 |
19 |
20 | 键:
21 |
22 |
23 |
24 | 值:
25 |
26 |
27 |
30 |
33 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/示例代码/PostMessage/index/index.html:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | INDEX PAGE
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
45 |
46 |
--------------------------------------------------------------------------------
/示例代码/DesignPatterns/03.观察者模式.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: Lee
3 | * @Date: 2023-05-06 17:17:18
4 | * @LastEditors: Lee
5 | * @LastEditTime: 2023-05-06 17:24:29
6 | * @Description:
7 | */
8 |
9 | // 1.创建一个被观察者(Subject)对象,它包含一个观察者(Observer)列表和一些方法来添加、删除和通知观察者。
10 | class Subject {
11 | constructor() {
12 | this.observers = [];
13 | }
14 |
15 | addObserver(observer) {
16 | this.observers.push(observer);
17 | }
18 | removeObserver(observer) {
19 | const index = this.observers.indexOf(observer);
20 | if (index !== -1) {
21 | this.observers.splice(index, 1);
22 | }
23 | }
24 | notifyObservers(data) {
25 | for (const observer of this.observers) {
26 | observer.update(data);
27 | }
28 | }
29 | }
30 |
31 | // 2.创建一个观察者对象,它包含一个 update 方法,用于接收来自被观察者的通知。
32 | class Observer {
33 | constructor() {}
34 | update(data) {
35 | console.log(`Received data:${data}`);
36 | }
37 | }
38 |
39 | // 3.创建一个被观察者实例和多个观察者实例,并将观察者添加到被观察者的观察者列表中。
40 | const subject = new Subject();
41 | const observer1 = new Observer();
42 | const observer2 = new Observer();
43 |
44 | subject.addObserver(observer1);
45 | subject.addObserver(observer2);
46 |
47 | // 4.调用被观察者的 notifyObservers 方法,通知所有观察者更新。
48 | subject.notifyObservers(JSON.stringify({ message: 'Hello' }));
49 |
--------------------------------------------------------------------------------
/示例代码/BrowserCaches/03_indexDB/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | IndexDB
8 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/示例代码/Eventloops/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: Lee
3 | * @Date: 2023-05-06 16:14:03
4 | * @LastEditors: Lee
5 | * @LastEditTime: 2023-05-06 16:33:09
6 | * @Description:
7 | */
8 |
9 |
10 |
11 | // → 示例1
12 | // console.log('start');
13 | // setTimeout(function cb() {
14 | // console.log('setTimeout1');
15 | // });
16 |
17 | // console.log('message');
18 |
19 | // setTimeout(function cb1() {
20 | // console.log('setTimeout2');
21 | // }, 0);
22 |
23 | // console.log('end');
24 |
25 |
26 |
27 |
28 | // → 示例2
29 | // console.log('start');
30 |
31 | // setTimeout(() => {
32 | // console.log('setTimeout');
33 | // }, 0);
34 |
35 | // Promise.resolve()
36 | // .then(() => {
37 | // console.log('promise1');
38 | // })
39 | // .then(() => {
40 | // console.log('promise2');
41 | // });
42 |
43 | // console.log('end');
44 |
45 | // → 示例3
46 | // console.log('start'); // 同步代码,立即执行
47 |
48 | // setTimeout(function () {
49 | // console.log('timeout1'); // 宏任务
50 | // }, 5);
51 |
52 | // new Promise((resolve) => {
53 | // console.log('promise1'); // 同步代码,立即执行
54 | // resolve();
55 | // setTimeout(() => console.log('timeout2'), 5); // 宏任务
56 | // }).then(function () {
57 | // console.log('then1'); // 微任务
58 | // });
59 |
60 | // console.log('end'); // 同步代码,立即执行
61 |
62 | // start → promise1 → end → then1 → timeout1 → timeout2
63 |
64 |
65 |
--------------------------------------------------------------------------------
/示例代码/DesignPatterns/04.发布订阅者模式.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: Lee
3 | * @Date: 2023-05-06 17:40:30
4 | * @LastEditors: Lee
5 | * @LastEditTime: 2023-05-06 18:04:25
6 | * @Description:
7 | */
8 | class EventBus {
9 | constructor() {
10 | this.listeners = {};
11 | }
12 |
13 | on(event, listener) {
14 | if (!this.listeners[event]) {
15 | this.listeners[event] = [];
16 | }
17 | this.listeners[event].push(listener);
18 | }
19 |
20 | emit(event, ...args) {
21 | const listeners = this.listeners[event];
22 | if (listeners) {
23 | listeners.forEach((listener) => {
24 | listener(...args);
25 | });
26 | }
27 | }
28 |
29 | removeListener(event, listenerToRemove) {
30 | const listeners = this.listeners[event];
31 | if (listeners) {
32 | this.listeners[event] = listeners.filter(
33 | (listener) => listener !== listenerToRemove
34 | );
35 | }
36 | }
37 |
38 | removeAllListeners(event) {
39 | delete this.listeners[event];
40 | }
41 | }
42 |
43 | const bus = new EventBus();
44 |
45 | const listenerFunction = (args) => {
46 | console.log(args);
47 | };
48 |
49 | // 1. 添加一个监听器
50 | bus.on('click', listenerFunction);
51 | // 2. 触发事件
52 | bus.emit('click', 'Hello');
53 | // 3. 删除监听器
54 | bus.removeListener('click', listenerFunction);
55 | // 4. 删除所有监听器
56 | bus.removeAllListeners('click');
57 |
--------------------------------------------------------------------------------
/示例代码/DesignPatterns/02.单例模式.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: Lee
3 | * @Date: 2023-05-06 17:02:57
4 | * @LastEditors: Lee
5 | * @LastEditTime: 2023-05-06 17:09:31
6 | * @Description:
7 | */
8 |
9 | // const Singleton = (function () {
10 | // let instance;
11 |
12 | // function createInstance() {
13 | // const object = new Object({ name: 'John' });
14 | // return object;
15 | // }
16 |
17 | // return {
18 | // getInstance: function () {
19 | // if (!instance) {
20 | // instance = createInstance();
21 | // }
22 | // return instance;
23 | // },
24 | // };
25 | // })();
26 |
27 | // const instance1 = Singleton.getInstance();
28 | // const instance2 = Singleton.getInstance();
29 |
30 | // console.log(instance1 === instance2); // true
31 |
32 | class Singleton {
33 | constructor() {
34 | if (Singleton.instance) {
35 | return Singleton.instance;
36 | }
37 | Singleton.instance = this;
38 | }
39 |
40 | static getInstance() {
41 | if (Singleton.instance) {
42 | return Singleton.instance;
43 | }
44 | return new Singleton();
45 | }
46 | }
47 |
48 | const instance1 = new Singleton();
49 | const instance2 = new Singleton();
50 | const instance3 = Singleton.getInstance();
51 | const instance4 = Singleton.getInstance();
52 | console.log(instance1 === instance2); // true
53 | console.log(instance3 === instance4); // true
54 |
--------------------------------------------------------------------------------
/示例代码/doms/js/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: Lee
3 | * @Date: 2022-03-29 17:12:53
4 | * @LastEditors: Lee
5 | * @LastEditTime: 2022-11-30 10:44:25
6 | */
7 |
8 | // -- 查找DOM
9 | // 1. 根据ID查找
10 | console.log(document.getElementById('company'));
11 | // 2. 根据name属性查找
12 | console.log(document.getElementsByName('address'));
13 | // 3. 根据类名查找
14 | console.log(document.getElementsByClassName('departments'));
15 | // 4. 根据标签名查找
16 | console.log(document.getElementsByTagName('li'));
17 | // 5. 根据CSS选择器查找
18 | console.log(document.querySelector('#company'));
19 | console.log(document.querySelectorAll('.departments li'));
20 |
21 | var list = document.querySelector('.departments');
22 | console.log(list.previousElementSibling);
23 | console.log(list.previousSibling);
24 | console.log(list.nextElementSibling);
25 | console.log(list.nextSibling);
26 | console.log(list.parentElement);
27 | console.log(list.parentNode);
28 | console.log(list.children);
29 | console.log(list.childElementCount);
30 | console.log(list.childNodes);
31 | console.log(list.firstElementChild);
32 | console.log(list.lastElementChild);
33 |
34 | // -- 节点操作
35 | // 1. 创建节点
36 | const el = document.createElement('div');
37 | const attr = document.createAttribute('class');
38 | const fragment = document.createDocumentFragment();
39 |
40 | const li = document.createElement('li');
41 | li.textContent = '纪检部';
42 | // list.appendChild(li);
43 | // list.append(li);
44 | list.prepend(li);
45 |
46 |
47 |
--------------------------------------------------------------------------------
/第08章 Symbol.md:
--------------------------------------------------------------------------------
1 | # 概述
2 |
3 | [Symbol](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Symbol) 是 ES6 引入的一种原始数据类型,其主要作用是生成 **唯一且不可变** 的标识符。
4 |
5 | `Symbol()` 函数会返回 **symbol** 类型的值,该类型具有静态属性和静态方法。它的静态属性会暴露几个内建的成员对象;它的静态方法会暴露全局的 symbol 注册,且类似于内建对象类,但作为构造函数来说它并不完整,因为它不支持语法:"`new Symbol()`"。
6 |
7 | # 应用场景
8 |
9 | Symbol 的常见应用场景包括:
10 |
11 | 1. **作为对象的唯一属性名**:Symbol 能确保对象属性的唯一性,避免因属性名重复导致的意外覆盖。
12 |
13 | ```js
14 | const id = Symbol('id');
15 | const obj = {
16 | [id]: '12345'
17 | };
18 | ```
19 |
20 | 2. **实现私有属性或方法**:通过 Symbol 定义的属性在常规遍历(如 `for...in` 或 `Object.keys()`)中不可见,可用于模拟私有成员。
21 |
22 | ```js
23 | const _privateMethod = Symbol('privateMethod');
24 | class MyClass {
25 | [_privateMethod]() {
26 | // 私有方法逻辑
27 | }
28 | }
29 | ```
30 |
31 | 3. **定义唯一常量值**:Symbol 的不可重复特性使其适合表示需要严格区分的常量。
32 |
33 | ```js
34 | const LOG_LEVEL = {
35 | DEBUG: Symbol('debug'),
36 | INFO: Symbol('info'),
37 | ERROR: Symbol('error')
38 | };
39 | ```
40 |
41 | 4. **利用内置 Symbol 值扩展对象行为**:ES6 提供了如 `Symbol.iterator`、`Symbol.toStringTag` 等内置 Symbol,用于自定义对象的语言原生行为(如迭代、类型标签等)。
42 |
43 | ```js
44 | const obj = {
45 | [Symbol.toStringTag]: 'MyObject'
46 | };
47 | console.log(obj.toString()); // 输出:[object MyObject]
48 | ```
49 |
50 | # 注意事项
51 |
52 | 1. Symbol 属性无法通过 `Object.keys()` 或 `for...in` 遍历,需使用 `Object.getOwnPropertySymbols()` 获取。
53 | 2. Symbol 的核心价值在于 **属性唯一性**、**代码封装性** 和 **对象行为扩展性**,合理使用可提升代码健壮性并减少命名冲突风险。
--------------------------------------------------------------------------------
/示例代码/requestAnimationFrame/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: Lee
3 | * @Date: 2022-12-07 17:03:47
4 | * @LastEditors: Lee
5 | * @LastEditTime: 2022-12-12 11:42:35
6 | * @Description:
7 | */
8 |
9 | /****************
10 | * 1.页面可见性:visibilitychange
11 | */
12 | window.addEventListener(
13 | 'visibilitychange',
14 | () => {
15 | console.log('document.hidden = ' + document.hidden);
16 | },
17 | false
18 | );
19 |
20 | /****************
21 | * 2.使用·动画
22 | */
23 | // -- 获取DOM元素
24 | let progress = document.querySelector('.v');
25 | // -- 记录步长
26 | let step;
27 | // -- 记录回调函数
28 | let handlerId;
29 | // -- 动画帧回调函数
30 | function render() {
31 | step++;
32 | progress.style.width = `${step}%`;
33 | if (step < 100) {
34 | handlerId = window.requestAnimationFrame(render);
35 | }
36 | }
37 | // -- 点击Loading按钮时触发,调用动画效果
38 | function onLoading() {
39 | step = 0;
40 | progress.style.width = '0%';
41 | render();
42 | }
43 | // -- 点击Stop按钮时触发,停止动画
44 | function onStop() {
45 | cancelAnimationFrame(handlerId);
46 | }
47 |
48 | /****************
49 | * 3.使用·函数节流
50 | */
51 | /*window.onmousemove = ({ clientX, clientY }) => {
52 | requestAnimationFrame(() => {
53 | console.log(clientX, clientY);
54 | });
55 | };*/
56 |
57 | /****************
58 | * 4.使用·分帧初始化
59 | */
60 | /*class A {}
61 | class B {}
62 | class C {}
63 | class D {}
64 | var lazyLoadList = [A, B, C, D];
65 | lazyLoadList.forEach((module) => {
66 | window.requestAnimationFrame(() => {
67 | new module();
68 | });
69 | });*/
70 |
71 |
--------------------------------------------------------------------------------
/示例代码/DebounceAndThrottle/index.html:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | 函数防抖与节流
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/示例代码/JSONs/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: Lee
3 | * @Date: 2022-11-29 13:46:56
4 | * @LastEditors: Lee
5 | * @LastEditTime: 2022-11-29 14:11:15
6 | * @Description:
7 | */
8 |
9 | /// 语法形式:JSON.stringify(value[, replacer[, space]])
10 |
11 | /// -- 转换
12 |
13 | var person = {
14 | name: '张三',
15 | age: 30,
16 | sex: '男',
17 | job: '前端工程师',
18 | };
19 |
20 | // 1. 转换对象
21 | console.log(JSON.stringify(person));
22 | // → {"name":"张三","age":30,"sex":"男","job":"前端工程师"}
23 |
24 | // 2. 转换普通值
25 | console.log(JSON.stringify('成都')); // → "成都"
26 | console.log(JSON.stringify(1)); // → "1"
27 | console.log(JSON.stringify(true)); // → "true"
28 | console.log(JSON.stringify(null)); // → "null"
29 |
30 | // 3. 指定replacer参数为:函数
31 | console.log(
32 | JSON.stringify(person, (key, value) => {
33 | // -- 过滤属性值为 number 类型的 key-value 对
34 | return typeof value === 'number' ? undefined : value;
35 | })
36 | );
37 | // → {"name":"张三","sex":"男","job":"前端工程师"}
38 |
39 | // 4. 指定replacer参数为:数组
40 | console.log(JSON.stringify(person, ['name', 'age']));
41 | // → {"name":"张三","age":30}
42 |
43 | // 5. 指定space(美化输出)
44 | console.log(JSON.stringify(person, null, 2));
45 |
46 | /*{
47 | "name": "张三",
48 | "age": 30,
49 | "sex": "男",
50 | "job": "前端工程师"
51 | }*/
52 |
53 | // -- 特性1
54 | console.log(JSON.stringify(() => {}));
55 | console.log(JSON.stringify(Symbol('Tag')));
56 | console.log(JSON.stringify(undefined));
57 |
58 | // -- 特性2
59 | console.log(
60 | JSON.stringify({
61 | name: new String('张三'),
62 | age: new Number(30),
63 | checked: new Boolean(false),
64 | })
65 | );
66 | // → {"name":"张三","age":30,"checked":false}
67 |
68 | // -- 特性五
69 | console.log(
70 | JSON.stringify({
71 | name: '张三',
72 | job: '前端工程师',
73 | toJSON: function () {
74 | return `${this.name} - ${this.job}`;
75 | },
76 | })
77 | );
78 |
79 | // → 张三 - 前端工程师
--------------------------------------------------------------------------------
/示例代码/ESNext/02.Proxy/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: Lee
3 | * @Date: 2023-05-30 16:31:23
4 | * @LastEditors: Lee
5 | * @LastEditTime: 2023-05-30 16:45:14
6 | * @Description:
7 | */
8 |
9 | // const object = { name: '张三', job: '前端工程师' };
10 | // const p = new Proxy(object, {
11 | // get(target, property, receiver) {
12 | // const value = target[property];
13 | // if (value) {
14 | // return value;
15 | // } else {
16 | // throw new ReferenceError(`Property ${property} does not exist.`);
17 | // }
18 | // },
19 | // });
20 |
21 | // console.log(p.name); // 张三
22 | // console.log(p.major); // ReferenceError: Property major does not exist.
23 |
24 | // const car = {
25 | // _brand: '东风本田',
26 | // color: '珍珠白',
27 | // };
28 | // const p = new Proxy(car, {
29 | // get(target, property, receiver) {
30 | // // 实现私有属性的保护
31 | // if (/^_/.test(property)) {
32 | // throw new Error(`私有属性 ${property} 不可访问.`);
33 | // }
34 | // return Reflect.get(target, property, receiver);
35 | // },
36 | // });
37 |
38 | // console.log(p.color); // 珍珠白
39 | // console.log(p._brand); // Error: 私有属性 _brand 不可访问.
40 |
41 | const api = {
42 | _appsecret: '5732e4c9db7ff9f7',
43 | appID: 'wx1695393264bf7d',
44 | wx: 'gh_133b3cd88m3a',
45 | };
46 |
47 | const p = new Proxy(api, {
48 | get(target, property, receiver) {
49 | if (/^_/.test(property)) {
50 | console.log(`私有属性 ${property} 不支持访问.`);
51 | return null;
52 | }
53 | return Reflect.get(target, property, receiver);
54 | },
55 | set(target, property, value, receiver) {
56 | if (/^_/.test(property)) {
57 | console.log(`私有属性 ${property} 不支持赋值.`);
58 | return null;
59 | }
60 | return Reflect.set(target, property, value, receiver);
61 | },
62 | });
63 |
64 | console.log(p.appID); // - 5732e4c9db7ff9f7
65 | console.log(p._appsecret); // - 有属性 _appsecret 不支持访问.
66 |
--------------------------------------------------------------------------------
/示例代码/Promise/01.基础用法/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: Lee
3 | * @Date: 2023-05-08 19:42:43
4 | * @LastEditors: Lee
5 | * @LastEditTime: 2023-05-08 20:25:11
6 | * @Description:
7 | */
8 |
9 | // 1. 基础用法
10 | const login = (username, password) => {
11 | return new Promise((resolve, reject) => {
12 | /** 模拟异步操作 */
13 | setTimeout(() => {
14 | if (username === 'admin' && password === '123') {
15 | resolve();
16 | } else {
17 | reject();
18 | }
19 | }, 2000);
20 | });
21 | };
22 | login('admin', '123').then(
23 | () => {
24 | console.log('成功');
25 | },
26 | (error) => {
27 | console.log('失败');
28 | }
29 | );
30 |
31 | // 2. then
32 |
33 | // -- 改变值
34 | const promise = new Promise((resolve) => resolve('ACDB'));
35 | promise
36 | .then((resp) => {
37 | console.log(resp); // → ACDB
38 | return resp.split('');
39 | })
40 | .then((letters) => {
41 | console.log(letters); // → [ 'A', 'C', 'D', 'B' ]
42 | return letters.sort();
43 | })
44 | .then((sorted) => {
45 | console.log(sorted); // → [ 'A', 'B', 'C', 'D' ]
46 | return sorted.join('');
47 | })
48 | .then((result) => {
49 | console.log(result); // → ABCD
50 | });
51 |
52 | // 3. catch
53 |
54 | login()
55 | .then(() => {
56 | console.log('Login success.');
57 | })
58 | .catch((error) => {
59 | console.log('Login failure.');
60 | });
61 |
62 | // 4. Promise.all
63 | // const promise1 = Promise.resolve(3);
64 | // const promise2 = 42;
65 | // const promise3 = new Promise((resolve, reject) => {
66 | // setTimeout(() => {
67 | // resolve('foo');
68 | // }, 100);
69 | // });
70 |
71 | // Promise.all([promise1, promise2, promise3]).then((values) => {
72 | // console.log(values); // 输出:[ 3, 42, 'foo' ]
73 | // });
74 |
75 | // 5. Promise.race
76 | const promise1 = new Promise((resolve, reject) => {
77 | setTimeout(resolve, 500, 'one');
78 | });
79 |
80 | const promise2 = new Promise((resolve, reject) => {
81 | setTimeout(resolve, 100, 'two');
82 | });
83 |
84 | Promise.race([promise1, promise2]).then((value) => {
85 | console.log(value);
86 | // Both resolve, but promise2 is faster
87 | });
88 | // Expected output: "two"
89 |
--------------------------------------------------------------------------------
/示例代码/BrowserCaches/03_indexDB/index.js:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | // 数据库版本号
5 | const version = 1;
6 |
7 | // 初始化数据库
8 | const db = new DB("db-learns", version, { students: "id" });
9 |
10 | // 新增数据
11 | async function onAdd() {
12 | if (!_name.value || !_age.value || !_job.value || !_city.value) {
13 | _tips.textContent = "温馨提示:请完善信息";
14 | return;
15 | }
16 | try {
17 | const id = await db.add("students", {
18 | id: Date.now().toString(),
19 | name: _name.value,
20 | age: +_age.value,
21 | job: _job.value,
22 | city: _city.value,
23 | });
24 | console.log(`新增成功,ID:${id}`);
25 | _tips.textContent = "新增成功!";
26 | } catch (error) {
27 | console.error("新增失败:", error);
28 | _tips.textContent = "新增失败!";
29 | }
30 | }
31 |
32 | // 删除数据
33 | async function onDelete() {
34 | if (!_flag.value) {
35 | _tips.textContent = "温馨提示:请填写操作标识(ID)";
36 | return;
37 | }
38 | try {
39 | const resp = await db.delete("students", _flag.value);
40 | console.log(`删除结果:${resp}`);
41 | _tips.textContent = "删除成功!";
42 | } catch (error) {
43 | console.error("删除失败:", error);
44 | _tips.textContent = "删除失败!";
45 | }
46 | }
47 |
48 | // 更新数据
49 | async function onPut() {
50 | if (!_name.value || !_age.value || !_job.value || !_city.value || !_flag.value) {
51 | _tips.textContent = "温馨提示:请完善信息";
52 | return;
53 | }
54 | try {
55 | const id = await db.put("students", {
56 | id: _flag.value,
57 | name: _name.value,
58 | age: +_age.value,
59 | job: _job.value,
60 | city: _city.value,
61 | });
62 | console.log(`更新成功,ID:${id}`);
63 | _tips.textContent = "更新成功!";
64 | } catch (error) {
65 | console.error("更新失败:", error);
66 | _tips.textContent = "更新失败!";
67 | }
68 | }
69 |
70 | // 查询数据
71 | async function onGet() {
72 | if (!_flag.value) {
73 | _tips.textContent = "温馨提示:请填写操作标识(ID)";
74 | return;
75 | }
76 | try {
77 | const resp = await db.get("students", _flag.value);
78 | console.log("查询结果:", resp);
79 | _tips.textContent = resp ? `查询成功:${JSON.stringify(resp)}` : "无此记录!";
80 | } catch (error) {
81 | console.error("查询失败:", error);
82 | _tips.textContent = "查询失败!";
83 | }
84 | }
85 |
86 | // 遍历数据
87 | async function onEach() {
88 | try {
89 | const resp = await db.each("students");
90 | console.log("所有数据:", resp);
91 | _tips.textContent = "遍历成功,查看控制台日志!";
92 | } catch (error) {
93 | console.error("遍历失败:", error);
94 | _tips.textContent = "遍历失败!";
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/第12章 定时器与延迟函数.md:
--------------------------------------------------------------------------------
1 | # 概述
2 |
3 | 在实际开发中,我们可能需要延迟执行某个操作,比如页面加载后延迟 n 秒弹出广告,或者定期执行某些任务,比如轮询、倒计时等。这些场景可以通过 **setTimeout** 和 **setInterval** 来实现。
4 |
5 | # 延时函数
6 |
7 | ## 语法
8 |
9 | 语法形式:
10 |
11 | ```js
12 | setTimeout(callback, delay);
13 | ```
14 |
15 | 语法解读:
16 |
17 | - `callback`:回调函数,在 delay 毫秒后执行
18 | - `delay`:延迟时间(单位:毫秒)
19 |
20 | ## 代码示例
21 |
22 | ```js
23 | console.log("Loading...");
24 | setTimeout(() => console.log("Respect ~"), 2000);
25 | console.log("...");
26 | /*
27 | Loading...
28 | ...
29 | Respect ~ */
30 | ```
31 |
32 | > **注意**:setTimeout 是异步执行的,不会阻塞线程。
33 |
34 | ## 取消延时
35 |
36 | 如果在延时执行前决定取消 setTimeout,可以使用 `clearTimeout()`:
37 |
38 | ```javascript
39 | console.log("Loading...");
40 | const timer = setTimeout(() => console.log("Respect ~"), 2000);
41 | console.log("...");
42 | clearTimeout(timer); // 取消延时
43 | ```
44 |
45 | # 定时器
46 |
47 | ## 语法
48 |
49 | 语法形式:
50 |
51 | ```javascript
52 | setInterval(callback, interval);
53 | ```
54 |
55 | 语法解读:
56 |
57 | - `callback`:每 interval 毫秒执行一次的函数
58 | - `interval`:时间间隔(单位:毫秒)
59 |
60 | ## 代码示例
61 |
62 | ```js
63 | let count = 10;
64 | const timer = setInterval(() => {
65 | console.log(--count);
66 | if (count === 0) {
67 | console.log("时间到!");
68 | clearInterval(timer); // 清除定时器
69 | }
70 | }, 1000);
71 | ```
72 |
73 | # 扩展应用
74 |
75 | ## 倒计时
76 |
77 | 思路:
78 |
79 | - 计算**目标时间**与**当前时间**的毫秒差
80 |
81 | - 转换为 天:时:分:秒
82 |
83 | 实现:
84 |
85 | ```js
86 | const countdown = (targetDate, callback) => {
87 | const format = (v) => v.toString().padStart(2, "0");
88 | const timer = setInterval(() => {
89 | const ms = targetDate - new Date();
90 | if (ms > 0) {
91 | const day = format(Math.floor(ms / 1000 / 60 / 60 / 24));
92 | const hours = format(Math.floor((ms / 1000 / 60 / 60) % 24));
93 | const minutes = format(Math.floor((ms / 1000 / 60) % 60));
94 | const seconds = format(Math.floor((ms / 1000) % 60));
95 | callback({ day, hours, minutes, seconds });
96 | } else {
97 | clearInterval(timer);
98 | }
99 | }, 1000);
100 | };
101 |
102 | // 使用示例
103 | countdown(new Date("2025-10-01"), ({ day, hours, minutes, seconds }) => {
104 | console.log(`距离2023年国庆还有 ${day}天 ${hours}时 ${minutes}分 ${seconds}秒`);
105 | });
106 | ```
107 |
108 | ## 函数防抖(Debounce)
109 |
110 | ### 概念
111 |
112 | 高频事件触发 n 秒后才执行函数,如果 n 秒内再次触发,则重新计时。
113 |
114 | ### 应用场景
115 |
116 | - **搜索输入框**:用户停止输入 n 秒后才请求接口
117 | - **窗口大小调整**:用户停止拖拽 n 秒后重新渲染
118 |
119 | ### 实现
120 |
121 | 思路:每次触发事件时都取消之前的延时调用方法
122 |
123 | ```js
124 | const debounce = (callback, delay = 500) => {
125 | let timer;
126 | return (...args) => {
127 | clearTimeout(timer);
128 | timer = setTimeout(() => callback.apply(this, args), delay);
129 | };
130 | };
131 |
132 | // 使用示例
133 | document.querySelector("input").oninput = debounce(() => {
134 | console.log("__Search__");
135 | }, 800);
136 | ```
137 |
138 | ## 函数节流
139 |
140 | ### 概念
141 |
142 | 高频事件触发时,每 n 秒内只执行一次。
143 |
144 | ### 应用场景
145 |
146 | - **滚动事件(onscroll)**:避免过度触发影响性能
147 | - **窗口调整(onresize)**:避免频繁执行
148 |
149 | ### 3.3. 实现
150 |
151 | 思路:每次触发事件时都判断当前是否有等待执行的延时函数
152 |
153 | ```js
154 | const throttle = (callback, delay = 500) => {
155 | // 1. 设置一个开关
156 | let isOn = true;
157 | return (...args) => {
158 | // 2. 如果当前正在执行某个任务,则忽略
159 | if (!isOn) return;
160 | // 3. 更新开关状态
161 | isOn = false;
162 | // 4. 启用定时器
163 | setTimeout(() => {
164 | callback.apply(this, args);
165 | isOn = true;
166 | }, delay);
167 | };
168 | };
169 |
170 | // 使用示例
171 | window.onresize = throttle((event) => {
172 | console.log(event.target.innerWidth, event.target.innerHeight);
173 | }, 1000);
174 | ```
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
--------------------------------------------------------------------------------
/示例代码/BrowserCaches/01_Cookie/Cookies.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: Lee
3 | * @Date: 2022-12-05 09:52:11
4 | * @LastEditors: Lee
5 | * @LastEditTime: 2023-05-04 14:41:12
6 | * @Description:
7 | */
8 |
9 | /*\
10 | |*|
11 | |*| :: cookies.js ::
12 | |*|
13 | |*| A complete cookies reader/writer framework with full unicode support.
14 | |*|
15 | |*| https://developer.mozilla.org/zh-CN/docs/Web/API/Document/cookie
16 | |*|
17 | |*| This framework is released under the GNU Public License, version 3 or later.
18 | |*| http://www.gnu.org/licenses/gpl-3.0-standalone.html
19 | |*|
20 | |*| Syntaxes:
21 | |*|
22 | |*| * docCookies.setItem(name, value[, end[, path[, domain[, secure]]]])
23 | |*| * docCookies.getItem(name)
24 | |*| * docCookies.removeItem(name[, path], domain)
25 | |*| * docCookies.hasItem(name)
26 | |*| * docCookies.keys()
27 | |*|
28 | \*/
29 |
30 | class DocCookies {
31 | /**
32 | * 得到Cookie
33 | * 读取一个 cookie。如果 cookie 不存在返回null。
34 | * @param {string} name 读取的 cookie 名。
35 | * @returns
36 | */
37 | static getItem(name) {
38 | return (
39 | decodeURIComponent(
40 | document.cookie.replace(
41 | new RegExp(
42 | '(?:(?:^|.*;)\\s*' +
43 | encodeURIComponent(name).replace(/[-.+*]/g, '\\$&') +
44 | '\\s*\\=\\s*([^;]*).*$)|^.*$'
45 | ),
46 | '$1'
47 | )
48 | ) || null
49 | );
50 | }
51 |
52 | /**
53 | * 写入Cookie
54 | * 创建或覆盖一个 cookie
55 | * @param {string} name 要创建或覆盖的 cookie 的名字
56 | * @param {any} value cookie 的值
57 | * @param {any} expires 过期时间,例如一年为 60*60*24*365(可选)
58 | * @param {string} path 存储路径,默认为当前文档位置的路径(可选)
59 | * @param {string} domain 存储域名,默认为当前文档位置的路径的域名部分(可选)
60 | * @param {boolean} secure cookie 只会被 https 传输(可选)
61 | * @returns
62 | */
63 | static setItem(name, value, expires, path, domain, secure) {
64 | if (!name || /^(?:expires|max\-age|path|domain|secure)$/i.test(name)) {
65 | return false;
66 | }
67 | var sExpires = '';
68 | if (expires) {
69 | switch (expires.constructor) {
70 | case Number:
71 | sExpires =
72 | expires === Infinity
73 | ? '; expires=Fri, 31 Dec 9999 23:59:59 GMT'
74 | : '; max-age=' + expires;
75 | break;
76 | case String:
77 | sExpires = '; expires=' + expires;
78 | break;
79 | case Date:
80 | sExpires = '; expires=' + expires.toUTCString();
81 | break;
82 | }
83 | }
84 | document.cookie =
85 | encodeURIComponent(name) +
86 | '=' +
87 | encodeURIComponent(value) +
88 | sExpires +
89 | (domain ? '; domain=' + domain : '') +
90 | (path ? '; path=' + path : '') +
91 | (secure ? '; secure' : '');
92 | return true;
93 | }
94 |
95 | /**
96 | * 移除Cookie
97 | * 删除一个 cookie
98 | * @param {string} name 要移除的 cookie 名
99 | * @param {string} path 存储路径,默认为当前文档位置的路径(可选)
100 | * @param {string} domain 存储域名,默认为当前文档位置的路径的域名部分(可选)
101 | * @returns
102 | */
103 | static removeItem(name, path, domain) {
104 | if (!name || !this.hasItem(name)) {
105 | return false;
106 | }
107 | document.cookie =
108 | encodeURIComponent(name) +
109 | '=; expires=Thu, 01 Jan 1970 00:00:00 GMT' +
110 | (domain ? '; domain=' + domain : '') +
111 | (path ? '; path=' + path : '');
112 | return true;
113 | }
114 |
115 | /**
116 | * 检测 Cookie
117 | * 检查一个 cookie 是否存在
118 | * @param {string} name 要检查的 cookie 名
119 | * @returns
120 | */
121 | static hasItem(name) {
122 | return new RegExp(
123 | '(?:^|;\\s*)' +
124 | encodeURIComponent(name).replace(/[-.+*]/g, '\\$&') +
125 | '\\s*\\='
126 | ).test(document.cookie);
127 | }
128 |
129 | /**
130 | * 得到所有 cookie 的列表
131 | * @returns
132 | */
133 | static keys() {
134 | var aKeys = document.cookie
135 | .replace(/((?:^|\s*;)[^\=]+)(?=;|$)|^\s*|\s*(?:\=[^;]*)?(?:\1|$)/g, '')
136 | .split(/\s*(?:\=[^;]*)?;\s*/);
137 | for (var nIdx = 0; nIdx < aKeys.length; nIdx++) {
138 | aKeys[nIdx] = decodeURIComponent(aKeys[nIdx]);
139 | }
140 | return aKeys;
141 | }
142 | }
143 |
144 | window.docCookies = DocCookies;
145 |
--------------------------------------------------------------------------------
/第15章 异常处理.md:
--------------------------------------------------------------------------------
1 | # Errow
2 |
3 | 在 JavaScript 解析或执行过程中,一旦发生错误,引擎就会抛出一个错误对象。JavaScript 原生提供了 Error 构造函数,所有抛出的错误都是这个构造函数的实例。
4 |
5 | **创建 Error 实例**
6 |
7 | Error 构造函数接受一个参数,表示错误提示信息,可以从实例的 message 属性读取该信息。
8 |
9 | ```javascript
10 | const err = new Error("Validation failed!");
11 | console.log(err.message);
12 | // → "Validation failed!"
13 | ```
14 |
15 | # 原生错误类型
16 |
17 | Error 对象是 JavaScript 中最基本的错误类型,在其基础上,JavaScript 还定义了 6 种派生错误类型:
18 |
19 | 1. SyntaxError:语法错误
20 |
21 | 当 JavaScript 代码违反语法规则时,会抛出 SyntaxError。
22 |
23 | ```js
24 | const 1a = 10;
25 | // ❌ Uncaught SyntaxError: Unexpected token '1'
26 |
27 | if (true) {
28 | console.log('Hi);
29 | }
30 | // ❌ Uncaught SyntaxError: Invalid or unexpected token
31 | ```
32 |
33 | 2. ReferenceError:引用错误
34 |
35 | 当访问的变量未定义或不可用时,会抛出 ReferenceError。
36 |
37 | ```js
38 | console.log(foo);
39 | // ❌ Uncaught ReferenceError: foo is not defined
40 | ```
41 |
42 | 3. TypeError:类型错误
43 |
44 | 当对变量执行不适当的操作(例如调用 undefined 变量为函数)时,会抛出 TypeError。
45 |
46 | ```js
47 | const bar = new 'Hello';
48 | // ❌ Uncaught TypeError: "Hello" is not a constructor
49 |
50 | const foo = {};
51 | foo.test();
52 | // ❌ Uncaught TypeError: foo.test is not a function
53 | ```
54 |
55 | 4. RangeError:范围错误
56 |
57 | 当值超出允许的范围时,会抛出 RangeError。
58 |
59 | ```js
60 | function recursive() {
61 | return recursive();
62 | }
63 | recursive();
64 | // ❌ Uncaught RangeError: Maximum call stack size exceeded
65 | ```
66 |
67 | 5. URIError:URI 处理错误
68 |
69 | 当全局 URI 处理函数(如 decodeURI、encodeURI)传入不正确的参数时,会抛出 URIError。
70 |
71 | ```js
72 | decodeURI('%');
73 | // ❌ Uncaught URIError: URI malformed
74 | ```
75 |
76 | 6. EvalError:`eval()` 函数中的错误
77 |
78 | 在 `eval()` 相关操作中,如果出现错误,可能会抛出 EvalError(现代浏览器基本不会抛出该错误)。
79 |
80 | # 异常处理方案
81 |
82 | ## throw
83 |
84 | throw 语句用于手动抛出异常,当程序运行过程中遇到无法继续执行的错误时,可以抛出异常中断程序执行,并提示错误信息。
85 |
86 | ```javascript
87 | throw new Error("异常提示信息");
88 | throw "异常提示信息"; // 也可以抛出字符串,但不推荐
89 | ```
90 |
91 | **console.assert()**
92 |
93 | `console.assert(condition, message)` 允许根据条件是否满足来输出异常信息,但不会中断程序执行。
94 |
95 | ```javascript
96 | const age = 12;
97 | console.assert(age > 18, "未满18岁!"); // 控制台输出:Assertion failed: 未满18岁!
98 | ```
99 |
100 | ## try…catch 捕获异常
101 |
102 | try...catch 语句用于捕获和处理可能抛出的异常,如果 try 块中的代码抛出异常,则会跳转到 catch 块执行相应的处理逻辑。
103 |
104 | ```javascript
105 | try {
106 | alertt("Hello, World!"); // 语法错误
107 | } catch (err) {
108 | console.error("错误警告:" + err.message);
109 | }
110 | ```
111 |
112 | > **注意**:try...catch 只能捕获同步代码的错误,无法捕获异步代码中的异常(如 setTimeout、Promise 等)。
113 |
114 | ## finally 代码块
115 |
116 | 无论 try 代码块是否抛出异常,finally 代码块都会执行,常用于资源释放或收尾操作。
117 |
118 | ```javascript
119 | try {
120 | console.log("执行 try 代码块");
121 | throw new Error("异常发生");
122 | } catch (err) {
123 | console.error("捕获错误:" + err.message);
124 | } finally {
125 | console.log("无论是否发生异常,都会执行 finally 代码块");
126 | }
127 | ```
128 |
129 | ## Promise.catch() 处理异步异常
130 |
131 | 在 Promise 对象中,可以使用 .catch() 方法捕获 reject 产生的异常。
132 |
133 | ```js
134 | fetch('invalid-url')
135 | .then(response => response.json())
136 | .catch(error => console.error("捕获到异常:", error));
137 | ```
138 |
139 | ## Window.onerror 捕获全局异常
140 |
141 | window.onerror 可以用于捕获未被 try...catch 处理的异常(仅适用于同步代码)。
142 |
143 | ```js
144 | window.onerror = function(message, source, lineno, colno, error) {
145 | console.error("全局错误:", message, "at", source, ":", lineno, ":", colno);
146 | return true; // 返回 true 以防止默认的错误提示
147 | };
148 |
149 | throw new Error("测试全局错误捕获");
150 | ```
151 |
152 | > **注意**:window.onerror 不能捕获 try...catch 内部已处理的错误。
153 |
154 | ## unhandledrejection 捕获未处理的 Promise 异常
155 |
156 | 对于 Promise 产生但未 catch 处理的错误,可以使用 unhandledrejection 事件捕获。
157 |
158 | ```js
159 | window.addEventListener("unhandledrejection", event => {
160 | console.error("捕获到未处理的 Promise 错误:", event.reason);
161 | });
162 |
163 | Promise.reject("未处理的异常");
164 | ```
165 |
166 | # 最佳实践
167 |
168 | 1. **使用 try...catch 处理同步代码异常**
169 |
170 | ```js
171 | try {
172 | riskyOperation();
173 | } catch (error) {
174 | console.error("发生错误:", error.message);
175 | }
176 | ```
177 |
178 | 2. **在 Promise 中使用 .catch() 处理异步异常**
179 |
180 | ```js
181 | fetchData().catch(error => console.error("请求失败:", error));
182 | ```
183 |
184 | 3. **使用 finally 进行资源清理**
185 |
186 | ```js
187 | function processData() {
188 | try {
189 | console.log("正在处理数据...");
190 | } finally {
191 | console.log("清理操作完成");
192 | }
193 | }
194 | processData();
195 | ```
196 |
197 | 4. **使用 window.onerror 捕获未处理的同步错误**
198 |
199 | ```js
200 | window.onerror = function(message, source, lineno, colno, error) {
201 | console.error("全局错误:", message);
202 | };
203 | ```
204 |
205 | 5. **使用 window.addEventListener("unhandledrejection", callback) 处理未捕获的 Promise 错误**
206 |
207 | ```js
208 | window.addEventListener("unhandledrejection", event => {
209 | console.error("未处理的 Promise 错误:", event.reason);
210 | });
211 | ```
212 |
213 | 6. **避免 throw 字符串,使用 Error 对象**
214 |
215 | ```js
216 | throw new Error("请提供有效的参数");
217 | ```
218 |
--------------------------------------------------------------------------------
/第11章 BOM.md:
--------------------------------------------------------------------------------
1 | # 概述
2 |
3 | > The Browser Object Model(BOM) allows JavaScript to "talk to" the browser.
4 |
5 | **BOM**(**B**rowers **O**bject **M**odel,浏览器对象模型)是浏览器为js提供的一个API(**A**pplication **P**rogramming **I**nterface,应用编程接口),所以它不是原生js提供的。通过BOM我们可以访问和设置浏览器的一些属性和函数。
6 |
7 | BOM 的大部分操作都依赖于全局对象 window,由于它是全局对象,因此访问其子对象的属性和方法时可以省略 window,例如 window.console.log() 可简写为 console.log()。
8 |
9 | ## window 对象的主要子对象
10 |
11 | - **document**:文档对象
12 | - **frames**:浏览器的框架对象
13 | - **history**:浏览器历史记录对象
14 | - **location**:当前页面的位置信息
15 | - **navigator**:浏览器信息对象
16 | - **screen**:屏幕信息对象
17 |
18 | 此外,window 还提供了一些常见的方法,例如:
19 |
20 | - alert()、open()、close()
21 | - setTimeout()、clearTimeout()
22 | - setInterval()、clearInterval()
23 |
24 | 虽然 BOM 没有官方标准,但随着 Web 发展,各大浏览器厂商已在许多 BOM 相关功能上达成共识,使得大多数现代浏览器都能支持常见的 BOM 操作。
25 |
26 | ## window 对象的多种表示方式
27 |
28 | 在全局环境下,以下变量都指向 window:
29 |
30 | - **window**
31 | - **this**
32 | - **self**
33 | - **frames**
34 |
35 | 在 Chrome 控制台输入 window.(注意最后的 .),可以查看 window 下的所有属性和方法。由于其包含大量内容,掌握全部并不现实,我们只需了解常用部分即可。
36 |
37 | # 窗口属性 *
38 |
39 | 浏览器窗口的相关属性对于响应式设计至关重要,尤其是在支持从智能手表(160×160)到 4K 屏幕(4096×2160)的设备时,合理调整布局是前端开发中的难点。除了 CSS 框架,我们也可以借助 BOM 提供的窗口属性进行适配。
40 |
41 | 浏览器窗口相关的主要属性有以下(数值表示的单位统一为像素):
42 |
43 | 
44 |
45 | 1. innerWidth、innerHeight:浏览器视口的宽高(包含滚动条)
46 | 2. outerWidth、outerHeight:浏览器窗口的整体宽高
47 | 3. pageXOffset、pageYOffset:页面滚动的偏移量(等价于 scrollLeft 和 scrollTop)
48 | 4. screenX、screenY(或 screenLeft、screenTop):浏览器窗口相对于屏幕的坐标
49 |
50 | > **注意**:innerWidth、innerHeight 等属性都包含滚动条的宽度,且这些属性是只读的,会随窗口大小变化而动态更新。
51 |
52 | 如果要隐藏滚动条,可以使用以下 CSS 代码:
53 |
54 | ```css
55 | body::-webkit-scrollbar {
56 | display: none;
57 | }
58 | ```
59 |
60 | # 窗口方法 *
61 |
62 | **基本窗口操作**
63 |
64 | - `open(url?, target?)`:打开新窗口
65 | - `close()`:关闭当前窗口
66 |
67 | **其他窗口方法**
68 |
69 | - `print()`:打印当前页面
70 | - `getSelection() `:获取选中的文本
71 |
72 | 【实例 1】获取选中内容
73 |
74 | ```html
75 |
76 |
曾经沧海难为水,除却巫山不是云。
77 |
取次花丛懒回顾,半缘修道半缘君。
78 |
79 | 您选中的内容是:
80 | ```
81 |
82 | ```js
83 | const oDiv = document.querySelector('#selBox');
84 | const oSel = document.querySelector('#selRes');
85 | oDiv.onmouseup = function() {
86 | // 获取选中对象
87 | var selObj = getSelection();
88 | // 将选中对象转为字符串
89 | var selTxt = selObj.toString();
90 | oSel.innerHTML = "您选中的内容是:“" + selTxt + "”";
91 | }
92 | ```
93 |
94 | 示例中使用 mouseup 事件来触发选中文本的获取。
95 |
96 | # 窗口对象
97 |
98 | ## 1. document
99 |
100 | document 主要用于操作 DOM,具体内容可参考标准 DOM 操作相关文档。
101 |
102 | ## 2. frames
103 |
104 | 在Ajax不盛行的年代,\