-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlocal-search.xml
898 lines (425 loc) · 346 KB
/
local-search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>读《识人攻略》</title>
<link href="/2023/12/16/%E8%AF%BB%E3%80%8A%E8%AF%86%E4%BA%BA%E6%94%BB%E7%95%A5%E3%80%8B/"/>
<url>/2023/12/16/%E8%AF%BB%E3%80%8A%E8%AF%86%E4%BA%BA%E6%94%BB%E7%95%A5%E3%80%8B/</url>
<content type="html"><![CDATA[<p>结合自己的工作场景,以下是读书笔记</p><h2 id="推拖者"><a href="#推拖者" class="headerlink" title="推拖者"></a>推拖者</h2><h3 id="什么是公事公办"><a href="#什么是公事公办" class="headerlink" title="什么是公事公办"></a>什么是公事公办</h3><p>公和私,就是从谁的利益出发来做决定。从公司利益出发来行事、做决定就是公办;反之从个人或小团体利益出发就是私心</p><h3 id="判断对方是不是推脱者"><a href="#判断对方是不是推脱者" class="headerlink" title="判断对方是不是推脱者"></a>判断对方是不是推脱者</h3><p>可以直接求助</p><blockquote><p>报销流程被卡在财务那里了,被对方说资料不符合规范。可以直接求助:那您觉得应该补充哪些材料呢,能给我讲讲吗?如果回复不知道,那就是推脱者</p></blockquote><h3 id="如何对付推脱者"><a href="#如何对付推脱者" class="headerlink" title="如何对付推脱者"></a>如何对付推脱者</h3><p>推脱的四个原因:害怕担责、无利不起早、显示存在感、给你下马威</p><h4 id="害怕担责"><a href="#害怕担责" class="headerlink" title="害怕担责"></a>害怕担责</h4><p>直接请对方领导或自己领导出面</p><h4 id="无利不起早"><a href="#无利不起早" class="headerlink" title="无利不起早"></a>无利不起早</h4><p>请对方吃饭、送礼、分享成绩</p><h4 id="显示存在感"><a href="#显示存在感" class="headerlink" title="显示存在感"></a>显示存在感</h4><p>给对方戴高帽子、多去称赞对方专业性,让对方高抬贵手</p><h4 id="给你下马威"><a href="#给你下马威" class="headerlink" title="给你下马威"></a>给你下马威</h4><p>工作时候,据理力争,一定不能顺着他的意。工作之外,展露善意小动作、比如送零食、小礼物</p><h2 id="盗卖恩情者"><a href="#盗卖恩情者" class="headerlink" title="盗卖恩情者"></a>盗卖恩情者</h2><p>有的人帮了忙、经常挂在嘴上,时刻提醒对方,想让对方表示感激</p><h3 id="盗卖恩情的危害"><a href="#盗卖恩情的危害" class="headerlink" title="盗卖恩情的危害"></a>盗卖恩情的危害</h3><p>1、影响内心自洽、过多的人情债会造成心理负担</p><p>2、伤害人际关系,让别人误会你的成绩名不副实</p><h3 id="如何对付盗卖恩情者"><a href="#如何对付盗卖恩情者" class="headerlink" title="如何对付盗卖恩情者"></a>如何对付盗卖恩情者</h3><h4 id="你卖恩情我不接"><a href="#你卖恩情我不接" class="headerlink" title="你卖恩情我不接"></a>你卖恩情我不接</h4><p>如果不清楚状况,就大大方方提问:“这事我还真不知道,具体怎么回事?你能详细讲一讲吗?”</p><h4 id="谦逊、客气、不办事"><a href="#谦逊、客气、不办事" class="headerlink" title="谦逊、客气、不办事"></a>谦逊、客气、不办事</h4><p>硬气心肠,可以客气,但一定不要被对方顺着鼻子走</p><h4 id="直接提要求"><a href="#直接提要求" class="headerlink" title="直接提要求"></a>直接提要求</h4><p>如果不是领导,直接提要求:“这些陈年往事不要再提了”</p><h2 id="压制者"><a href="#压制者" class="headerlink" title="压制者"></a>压制者</h2><p>类似于PUA,每句话都要贬低别人,抬高自己</p><h3 id="对付压制者"><a href="#对付压制者" class="headerlink" title="对付压制者"></a>对付压制者</h3><h4 id="防守技能"><a href="#防守技能" class="headerlink" title="防守技能"></a>防守技能</h4><p>对方贬损你时,直接出招:“我不觉得啊!”。只要情绪不被带着走,就轮到他着急了</p><blockquote><p>对方说你胖,你丑,娶不到媳妇,直接回怼:“我不觉得啊”</p></blockquote><h4 id="反击手段"><a href="#反击手段" class="headerlink" title="反击手段"></a>反击手段</h4><p>清楚明白的表达:“你这么评价我,让我很不舒服/受伤”。对方只是个损鬼,不是禽兽,只要这么说了,应该会有所收敛</p><h4 id="挖坑行为"><a href="#挖坑行为" class="headerlink" title="挖坑行为"></a>挖坑行为</h4><p>压制者是无差别攻击所有人,因此你可以转移目标,“我觉得那谁谁谁就很棒”</p>]]></content>
<tags>
<tag>书籍</tag>
</tags>
</entry>
<entry>
<title>系统开发基础</title>
<link href="/2023/12/12/%E7%B3%BB%E7%BB%9F%E5%BC%80%E5%8F%91%E5%9F%BA%E7%A1%80/"/>
<url>/2023/12/12/%E7%B3%BB%E7%BB%9F%E5%BC%80%E5%8F%91%E5%9F%BA%E7%A1%80/</url>
<content type="html"><![CDATA[<h2 id="软件开发模型"><a href="#软件开发模型" class="headerlink" title="软件开发模型"></a>软件开发模型</h2><h3 id="瀑布模型"><a href="#瀑布模型" class="headerlink" title="瀑布模型"></a>瀑布模型</h3><p>瀑布模型是将软件生命周期中的各个活动规定为依<code>线性顺序</code>链接的若干阶段的模型,包括需求分析、设计、编码、运行与维护</p><p>特点:<code>管理成本低</code>,每个阶段都有对应的产物,<code>一旦发生错误,整个项目推倒重新开始</code></p><p>适用于:<code>需求明确的项目</code>,或二次开发,或对于数据处理类型的项目</p><h3 id="V模型"><a href="#V模型" class="headerlink" title="V模型"></a>V模型</h3><p>强调测试贯穿项目始终,而不是集中在测试阶段。是一种<code>测试的开发模型</code></p><h3 id="喷泉模型"><a href="#喷泉模型" class="headerlink" title="喷泉模型"></a>喷泉模型</h3><p>典型的面向对象的模型</p><p>特点:迭代、无间隙。会将软件开发划分为多个阶段,但<code>各个阶段无明显界限</code>,并且可以迭代交叉</p><h3 id="原形模型"><a href="#原形模型" class="headerlink" title="原形模型"></a>原形模型</h3><p>适用于:<code>需求不明确场景</code>,可以帮助用户明确需求</p><h3 id="增量模型"><a href="#增量模型" class="headerlink" title="增量模型"></a>增量模型</h3><p>可以有多个可用的版本,<code>核心功能最先完成</code>,在此基础上,每轮迭代会有新的增量发布,核型功能可以得到充分测试</p><p>特点:每一个增量均发布一个可操作的产品</p><h3 id="螺旋模型"><a href="#螺旋模型" class="headerlink" title="螺旋模型"></a>螺旋模型</h3><p>引入了<code>风险分析</code>。结合了瀑布模型和演化模型的优点</p><p>特点:由制定计划、风险分析、实施工程、客户评估这一循环组成。它最初从概念项目开始第一个螺旋。属于面向对象开发模型,强调风险引入</p><h3 id="统一过程"><a href="#统一过程" class="headerlink" title="统一过程"></a>统一过程</h3><p>特点:用例驱动、以架构为中心、迭代和增量。把一个项目分为四个不同的阶段</p><ul><li>构思阶段:用户沟通和计划活动,强调<code>定义和细化用例</code></li><li>细化阶段:用户沟通和建模活动,重点是创建分析和设计模型,强调<code>类的定义和体系结构</code>的表示</li><li>构建阶段:将<code>设计转化为实现</code>,进行集成和测试</li><li>移交阶段:产品发布给用户进行测试评价,收集用户意见,再迭代修改产品</li></ul><h3 id="敏捷开发"><a href="#敏捷开发" class="headerlink" title="敏捷开发"></a>敏捷开发</h3><p>是一种以人为核心、迭代、循环渐进的开发方法</p><p>适用于:<code>小团队和小项目</code>,<code>小步快跑</code>思想</p><p>常见的敏捷开发方法:</p><ul><li>极限编程法:4大价值观、5大原则、12个最佳实践</li><li>水晶法:每一个不同的项目都需要一套<code>不同的策略、约定和方法论</code></li><li>开放式源码:程序开发人员在地域上分布广</li><li>并列争球法:按<code>需求的优先级</code>来实现产品。多个小组并行迪递增实现产品</li><li>功用驱动开发方法:开发成员人尽其用,快速开发功能。开发人员分为<code>首席程序员</code>和<code>类程序员</code></li><li>自适应软件开发:猜测、合作与学习</li></ul><p>极限编程法:</p><ul><li>4大价值观:沟通、简单、反馈、勇气</li><li>5大原则:快速反馈、简单性假设、逐步修改、提倡更改、优质工作</li></ul>]]></content>
<tags>
<tag>软件设计</tag>
</tags>
</entry>
<entry>
<title>常用算法时间复杂度</title>
<link href="/2023/12/05/%E5%B8%B8%E7%94%A8%E7%AE%97%E6%B3%95%E6%97%B6%E9%97%B4%E5%A4%8D%E6%9D%82%E5%BA%A6/"/>
<url>/2023/12/05/%E5%B8%B8%E7%94%A8%E7%AE%97%E6%B3%95%E6%97%B6%E9%97%B4%E5%A4%8D%E6%9D%82%E5%BA%A6/</url>
<content type="html"><![CDATA[<p>常见的算法复杂度排名</p><blockquote><p>O(1) < O(log2n) < O(n) < O(nlog2n) < O(n^2) < O(n^3) < O(2^n)</p></blockquote><h2 id="复杂度对应的经典场景"><a href="#复杂度对应的经典场景" class="headerlink" title="复杂度对应的经典场景"></a>复杂度对应的经典场景</h2><h3 id="O-log2n"><a href="#O-log2n" class="headerlink" title="O(log2n)"></a>O(log2n)</h3><p>二分查找</p><h3 id="O-nlog2n"><a href="#O-nlog2n" class="headerlink" title="O(nlog2n)"></a>O(nlog2n)</h3><p>堆排序:要对n个元素进行排序,每次排序都要构建一个大顶堆or小顶堆,复杂度为 log2n,因此总复杂度为 <code>nlog2n</code></p><h3 id="O-n-2"><a href="#O-n-2" class="headerlink" title="O(n^2)"></a>O(n^2)</h3><p>for循环</p><h3 id="O-2-n"><a href="#O-2-n" class="headerlink" title="O(2^n)"></a>O(2^n)</h3><p>自顶向下的动态规划法</p><h2 id="排序算法"><a href="#排序算法" class="headerlink" title="排序算法"></a>排序算法</h2><p><img src="https://pic.imgdb.cn/item/656f1ad5c458853aef18f264.jpg" alt="常见的排序算法复杂度"></p>]]></content>
<tags>
<tag>算法</tag>
</tags>
</entry>
<entry>
<title>《活着》</title>
<link href="/2021/12/11/%E3%80%8A%E6%B4%BB%E7%9D%80%E3%80%8B/"/>
<url>/2021/12/11/%E3%80%8A%E6%B4%BB%E7%9D%80%E3%80%8B/</url>
<content type="html"><![CDATA[<p>前段时间把余华的《活着》看完了,一直在纠结要不要写点什么。</p><p>最终我还是逼自己写了,就算感悟不深刻,但能让我写时重新回味一遍那也是好的。</p><p>这是我第一次读余华的小说,在读之前我也看了在某瓣的评论,多数人都觉得这部作品太苦了,是看一次哭一次。</p><p>我读完之后并没有非常深刻的体会,没有直击心灵。每个读者的生活际遇不同,感悟不同。至少于我而言,生活阅历不够,看的太少,没有经历过战争和文革那段中国的致暗时代,无法和富贵的悲惨命运产生共鸣。因此在阅读时,更多的是抱着一种看故事的心态。</p><p>富贵年轻时,家里家产倒也富裕,是个地主,却染上了嫖和赌。因为赌博把家里的家产败光了,连祖屋都被别人收了去还债。他老爹被活活气死。后来因为去找医生给母亲看病,不料被国名党抓了壮丁,在战场上认识了老全和春生。经过九死一生,终于回到了家里。本以为日子可以平淡的过下去,厄运总是在富贵踹口气时再次降临。富贵的母亲在他回家之前就病死了,他女儿凤霞因病成了哑巴,他的儿子有庆被抽血抽死了,女儿凤霞难产死了,家珍也因伤心过度在不久之后死了。就连他的女婿二喜也在干活中,被水泥板夹死了,孙子苦根被活活撑死了。春生也受不了文革的批斗,上吊死了。富贵的家人,挚友都离他而去,最后只剩他和一头老牛相伴。</p><p>难怪李健都说:“《活着》这本书,看一次哭一次”。但在我看来,余华冷冰冰的文字读来虽苦,但莫名的温暖。</p><p>富贵年轻时确实是个渣男无疑了,吃喝嫖赌就占了俩。富贵的妻子家珍,是有钱人家的女儿,却没有大小姐的做派,对富贵从来都是逆来顺受,他在外面胡闹,只是心里打鼓,从不说他什么。尽管富贵落魄了,也陪着他一生共苦难。要说富贵这辈子最幸运的事,就是娶了家珍吧。他的儿女凤霞和有庆,从小也替富贵分忧。凤霞虽然聋哑,但也承担了家里的重活,力气比富贵还大,有庆每天天不亮就割草喂羊,鞋是跑坏了一双又一双,后来索性就不穿鞋了。富贵的偏头女婿二喜,也在凤霞死后,带他如亲生父亲,和他相互扶持。苦根这孩子虽然年纪小,却聪明伶利,给富贵带来不少欢乐。</p><p>《活着》讲述了眼泪的宽广和丰富;讲述了绝望的不存在;讲述了人是为了活着本身而活着,而不是为了活着之外的任何事物而活着。这本书读来,富贵是悲惨的,但也能从中看到温情,能够在漫漫的黑暗中感受到点点的光芒,这就是《活着》的价值吧。</p>]]></content>
<tags>
<tag>书籍</tag>
</tags>
</entry>
<entry>
<title>tapable实现</title>
<link href="/2021/11/22/tapable%E5%AE%9E%E7%8E%B0/"/>
<url>/2021/11/22/tapable%E5%AE%9E%E7%8E%B0/</url>
<content type="html"><![CDATA[<p>tapable有以下9种钩子</p><ul><li><p>SyncHook</p></li><li><p>SyncBailHook</p></li><li><p>SyncLoopHook</p></li><li><p>SyncWaterfallHook</p></li><li><p>AsyncParallelHook</p></li><li><p>AsyncParallelBailHook</p></li><li><p>AsyncSeriesHook</p></li><li><p>AsyncSeriesBailHook</p></li><li><p>AsyncSeriesWaterfallHook</p></li></ul><h3 id="SyncHook"><a href="#SyncHook" class="headerlink" title="SyncHook"></a>SyncHook</h3><h4 id="用法:"><a href="#用法:" class="headerlink" title="用法:"></a>用法:</h4><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> { SyncHook } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'tapable'</span>);<span class="hljs-keyword">const</span> hook = <span class="hljs-keyword">new</span> SyncHook([<span class="hljs-string">'arg1'</span>, <span class="hljs-string">'arg2'</span>, <span class="hljs-string">'arg3'</span>]);<span class="hljs-comment">// 注册两个监听函数,tap方法的第一个参数没有实际意义,只是用来做标识</span>hook.tap(<span class="hljs-string">'yxfan'</span>, <span class="hljs-function">(<span class="hljs-params">say</span>) =></span> { <span class="hljs-built_in">console</span>.log(say, <span class="hljs-string">': yxfan'</span>);});hook.tap(<span class="hljs-string">'cheney'</span>, <span class="hljs-function">(<span class="hljs-params">say</span>) =></span> { <span class="hljs-built_in">console</span>.log(say, <span class="hljs-string">' : cheney'</span>)});<span class="hljs-comment">// 触发</span>hook.call(<span class="hljs-string">'hello'</span>)<span class="hljs-comment">// 打印</span><span class="hljs-comment">// hello : yxfan</span><span class="hljs-comment">// hello : cheney</span></code></pre></div><h4 id="实现:"><a href="#实现:" class="headerlink" title="实现:"></a>实现:</h4><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SyncHook</span> </span>{ <span class="hljs-function"><span class="hljs-title">constructor</span>(<span class="hljs-params">args</span>)</span> { <span class="hljs-comment">// </span> <span class="hljs-built_in">this</span>.tasks = []; } <span class="hljs-comment">// 订阅</span> <span class="hljs-function"><span class="hljs-title">tap</span>(<span class="hljs-params">name, task</span>)</span> { <span class="hljs-built_in">this</span>.tasks.push(task); } <span class="hljs-comment">// 发布</span> <span class="hljs-function"><span class="hljs-title">call</span>(<span class="hljs-params">...args</span>)</span> { <span class="hljs-built_in">this</span>.tasks.forEach(<span class="hljs-function"><span class="hljs-params">task</span> =></span> { task(...args); }); }}<span class="hljs-built_in">module</span>.exports = SyncHook;</code></pre></div><h3 id="SyncBailHook"><a href="#SyncBailHook" class="headerlink" title="SyncBailHook"></a>SyncBailHook</h3><p>SyncBailHook同步熔断保险钩子,即return一个非undefined的值,则不再继续执行后面的监听函数</p><h4 id="用法:-1"><a href="#用法:-1" class="headerlink" title="用法:"></a>用法:</h4><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> { SyncBailHook } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'tapable'</span>);<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Test</span> </span>{ hooks = { <span class="hljs-attr">arch</span>: <span class="hljs-keyword">new</span> SyncBailHook([<span class="hljs-string">'arg1'</span>]) }}<span class="hljs-keyword">const</span> test = <span class="hljs-keyword">new</span> Test();test.hooks.arch.tap(<span class="hljs-string">'yxfan'</span>, <span class="hljs-function">(<span class="hljs-params">say</span>) =></span> { <span class="hljs-built_in">console</span>.log(say, <span class="hljs-string">': yxfan'</span>); <span class="hljs-keyword">return</span> <span class="hljs-string">'yxfan 今天调休啦'</span>; <span class="hljs-comment">// 不会继续执行下面的事件</span> <span class="hljs-comment">// return undefined 则继续往下执行</span>})test.hooks.arch.tap(<span class="hljs-string">'cheney'</span>, <span class="hljs-function">(<span class="hljs-params">say</span>) =></span> { <span class="hljs-built_in">console</span>.log(say, <span class="hljs-string">': cheney'</span>);})test.hooks.arch.call(<span class="hljs-string">'hello'</span>)<span class="hljs-comment">// 打印:hello : yxfan</span></code></pre></div><h4 id="实现:-1"><a href="#实现:-1" class="headerlink" title="实现:"></a>实现:</h4><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SyncBailHook</span> </span>{ <span class="hljs-function"><span class="hljs-title">constructor</span>(<span class="hljs-params">args</span>)</span> { <span class="hljs-built_in">this</span>.tasks = []; } <span class="hljs-comment">// 订阅</span> <span class="hljs-function"><span class="hljs-title">tap</span>(<span class="hljs-params">name, task</span>)</span> { <span class="hljs-built_in">this</span>.tasks.push(task); } <span class="hljs-comment">// 发布</span> <span class="hljs-function"><span class="hljs-title">call</span>(<span class="hljs-params">...args</span>)</span> { <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i < <span class="hljs-built_in">this</span>.tasks.length; i++) { <span class="hljs-keyword">const</span> result = <span class="hljs-built_in">this</span>.tasks[i](...args); <span class="hljs-keyword">if</span> (result) <span class="hljs-keyword">return</span> } }}<span class="hljs-built_in">module</span>.exports = SyncBailHook;</code></pre></div><h3 id="SyncWaterfallHook"><a href="#SyncWaterfallHook" class="headerlink" title="SyncWaterfallHook"></a>SyncWaterfallHook</h3><p>SyncWaterfallHook 瀑布钩子,上一个监听函数的返回值,作为下一个监听函数的参数,像瀑布一样传递参数</p><h4 id="用法:-2"><a href="#用法:-2" class="headerlink" title="用法:"></a>用法:</h4><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> { SyncWaterfallHook } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'tapable'</span>);<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Test</span> </span>{ hooks = { <span class="hljs-attr">arch</span>: <span class="hljs-keyword">new</span> SyncWaterfallHook([<span class="hljs-string">'arg1'</span>]) }}<span class="hljs-keyword">const</span> test = <span class="hljs-keyword">new</span> Test();test.hooks.arch.tap(<span class="hljs-string">'yxfan'</span>, <span class="hljs-function">(<span class="hljs-params">say</span>) =></span> { <span class="hljs-built_in">console</span>.log(say, <span class="hljs-string">': yxfan'</span>); <span class="hljs-keyword">return</span> <span class="hljs-string">'yxfan ok'</span>})test.hooks.arch.tap(<span class="hljs-string">'cheney'</span>, <span class="hljs-function">(<span class="hljs-params">data</span>) =></span> { <span class="hljs-built_in">console</span>.log(data); <span class="hljs-keyword">return</span> <span class="hljs-string">'cheney ok'</span>})test.hooks.arch.tap(<span class="hljs-string">'xiaopa'</span>, <span class="hljs-function">(<span class="hljs-params">data</span>) =></span> { <span class="hljs-built_in">console</span>.log(data);})test.hooks.arch.call(<span class="hljs-string">'hello'</span>)<span class="hljs-comment">// 打印如下:</span><span class="hljs-comment">// hello : yxfan</span><span class="hljs-comment">// yxfan ok</span><span class="hljs-comment">// cheney ok</span></code></pre></div><h4 id="实现:-2"><a href="#实现:-2" class="headerlink" title="实现:"></a>实现:</h4><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SyncWaterfallHook</span> </span>{ <span class="hljs-function"><span class="hljs-title">constructor</span>(<span class="hljs-params">...args</span>)</span> { <span class="hljs-built_in">this</span>.tasks = []; } <span class="hljs-function"><span class="hljs-title">tap</span>(<span class="hljs-params">name, task</span>)</span> { <span class="hljs-built_in">this</span>.tasks.push(task); } <span class="hljs-function"><span class="hljs-title">call</span>(<span class="hljs-params">...args</span>)</span> { <span class="hljs-keyword">const</span> [first, ...other] = <span class="hljs-built_in">this</span>.tasks; <span class="hljs-keyword">let</span> result = first(...args); other.reduce(<span class="hljs-function">(<span class="hljs-params">pre, next</span>) =></span> { <span class="hljs-keyword">let</span> ret = next(pre); <span class="hljs-keyword">if</span> (ret) <span class="hljs-keyword">return</span> ret; <span class="hljs-keyword">return</span> result; }, result); }}<span class="hljs-built_in">module</span>.exports = SyncWaterfallHook;</code></pre></div><h3 id="SyncLoopHook"><a href="#SyncLoopHook" class="headerlink" title="SyncLoopHook"></a>SyncLoopHook</h3><p>SyncLoopHook 只要监听函数不返回undefined,就循环执行该监听函数</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> { SyncLoopHook } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'tapable'</span>);<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Test</span> </span>{ hooks = { <span class="hljs-attr">arch</span>: <span class="hljs-keyword">new</span> SyncLoopHook([<span class="hljs-string">'arg1'</span>, <span class="hljs-string">'arg2'</span>]) }}<span class="hljs-keyword">let</span> index = <span class="hljs-number">0</span>;<span class="hljs-keyword">const</span> test = <span class="hljs-keyword">new</span> Test();test.hooks.arch.tap(<span class="hljs-string">'yxfan'</span>, <span class="hljs-function">(<span class="hljs-params">say</span>) =></span> { <span class="hljs-built_in">console</span>.log(say, <span class="hljs-string">': yxfan'</span>, index); <span class="hljs-keyword">return</span> ++index === <span class="hljs-number">3</span> ? <span class="hljs-literal">undefined</span> : <span class="hljs-string">'wait a moment'</span>})test.hooks.arch.tap(<span class="hljs-string">'cheney'</span>, <span class="hljs-function">(<span class="hljs-params">say</span>) =></span> { <span class="hljs-built_in">console</span>.log(say, <span class="hljs-string">': cheney'</span>);})test.hooks.arch.call(<span class="hljs-string">'hello'</span>)<span class="hljs-comment">// 打印如下:</span><span class="hljs-comment">// hello : yxfan 0</span><span class="hljs-comment">// hello : yxfan 1</span><span class="hljs-comment">// hello : yxfan 2</span><span class="hljs-comment">// hello : cheney</span></code></pre></div><h4 id="实现:-3"><a href="#实现:-3" class="headerlink" title="实现:"></a>实现:</h4><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SyncLoopHook</span> </span>{ <span class="hljs-function"><span class="hljs-title">constructor</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-built_in">this</span>.tasks = []; } <span class="hljs-function"><span class="hljs-title">tap</span>(<span class="hljs-params">name, task</span>)</span> { <span class="hljs-built_in">this</span>.tasks.push(task); } <span class="hljs-function"><span class="hljs-title">call</span>(<span class="hljs-params">...args</span>)</span> { <span class="hljs-built_in">this</span>.tasks.forEach(<span class="hljs-function"><span class="hljs-params">task</span> =></span> { <span class="hljs-keyword">let</span> result; <span class="hljs-keyword">do</span> { result = task(...args) } <span class="hljs-keyword">while</span>(result != <span class="hljs-literal">undefined</span>) }) }}<span class="hljs-built_in">module</span>.exports = SyncLoopHook;</code></pre></div><h3 id="AsyncParallelHook"><a href="#AsyncParallelHook" class="headerlink" title="AsyncParallelHook"></a>AsyncParallelHook</h3><p>AsyncParallelHook 异步并行钩子</p><p>tapable库中,有三种事件注册方式: </p><ul><li>tap -同步注册 </li><li>tapAsync-异步注册,接受第二个参数cb ,cb方法调用表示改事件执行完了 </li><li>tapPromise-接受一个参数Promise</li></ul><p>有三种事件发布方式:</p><ul><li>call</li><li>callAsync</li><li>promise</li></ul><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-comment">/**</span><span class="hljs-comment"> * tapable库中,有三种注册方式 tap -同步注册 tapAsync-异步注册,接受第二个参数cb tapPromise-一个参数Promise</span><span class="hljs-comment"> */</span><span class="hljs-keyword">const</span> { AsyncParallelHook } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'tapable'</span>);<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Hook</span> </span>{ <span class="hljs-function"><span class="hljs-title">constructor</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-built_in">this</span>.hooks = { <span class="hljs-attr">arch</span>: <span class="hljs-keyword">new</span> AsyncParallelHook([<span class="hljs-string">'arg1'</span>]) } } <span class="hljs-comment">// 注册监听函数</span> <span class="hljs-function"><span class="hljs-title">subscribe</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-built_in">this</span>.hooks.arch.tapAsync(<span class="hljs-string">'primary'</span>, <span class="hljs-function">(<span class="hljs-params">name, cb</span>) =></span> { <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =></span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'初级前端:'</span>, name); cb() }, <span class="hljs-number">1000</span>) }) <span class="hljs-built_in">this</span>.hooks.arch.tapAsync(<span class="hljs-string">'intermediate'</span>, <span class="hljs-function">(<span class="hljs-params">name, cb</span>) =></span> { <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =></span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'中级前端:'</span>, name); cb() }, <span class="hljs-number">1000</span>) }) <span class="hljs-built_in">this</span>.hooks.arch.tapAsync(<span class="hljs-string">'senior'</span>, <span class="hljs-function">(<span class="hljs-params">name, cb</span>) =></span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'高级前端:'</span>, name); cb() }) } <span class="hljs-comment">// 执行监听函数</span> <span class="hljs-function"><span class="hljs-title">publish</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-built_in">this</span>.hooks.arch.callAsync(<span class="hljs-string">'yxfan'</span>, <span class="hljs-function">() =></span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'封神啦!'</span>); }) }}<span class="hljs-keyword">const</span> hook = <span class="hljs-keyword">new</span> Hook;hook.subscribe();hook.publish();</code></pre></div><p>因为是异步并行钩子,所以一秒后一次性打印:“初级前端: yxfan”,“中级前端: yxfan”,“高级前端: yxfan”,异步都执行完了,最后才打印“封神啦!”</p><p>用tapPromise比较简单,注意用<code>tapPromise</code>注册监听函数,触发时要用<code>promise</code></p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HookPromise</span> </span>{ <span class="hljs-function"><span class="hljs-title">constructor</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-built_in">this</span>.hooks = { <span class="hljs-attr">arch</span>: <span class="hljs-keyword">new</span> AsyncParallelHook([<span class="hljs-string">'arg1'</span>]) } } <span class="hljs-comment">// 注册监听函数</span> <span class="hljs-function"><span class="hljs-title">subscribe</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-built_in">this</span>.hooks.arch.tapPromise(<span class="hljs-string">'primary'</span>, <span class="hljs-function">(<span class="hljs-params">name</span>) =></span> { <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function"><span class="hljs-params">resolve</span> =></span> { <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =></span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'初级前端:'</span>, name); resolve() }, <span class="hljs-number">1000</span>) }) }) <span class="hljs-built_in">this</span>.hooks.arch.tapPromise(<span class="hljs-string">'intermediate'</span>, <span class="hljs-function">(<span class="hljs-params">name</span>) =></span> { <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function"><span class="hljs-params">resolve</span> =></span> { <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =></span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'中级前端:'</span>, name); resolve() }, <span class="hljs-number">1000</span>) }) }) <span class="hljs-built_in">this</span>.hooks.arch.tapPromise(<span class="hljs-string">'senior'</span>, <span class="hljs-function">(<span class="hljs-params">name</span>) =></span> { <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function"><span class="hljs-params">resolve</span> =></span> { <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =></span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'高级前端:'</span>, name); resolve() }, <span class="hljs-number">1000</span>) }) }) } <span class="hljs-comment">// 执行监听函数</span> <span class="hljs-function"><span class="hljs-title">publish</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-built_in">this</span>.hooks.arch.promise(<span class="hljs-string">'yxfan'</span>).then(<span class="hljs-function">() =></span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'封神啦!'</span>); }) }}<span class="hljs-keyword">const</span> hook = <span class="hljs-keyword">new</span> HookPromise();hook.subscribe();hook.publish();</code></pre></div><h4 id="实现:-4"><a href="#实现:-4" class="headerlink" title="实现:"></a>实现:</h4><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AsyncParallelHook</span> </span>{ <span class="hljs-function"><span class="hljs-title">constructor</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-built_in">this</span>.tasks = []; } <span class="hljs-function"><span class="hljs-title">tapAsync</span>(<span class="hljs-params">name, task</span>)</span> { <span class="hljs-built_in">this</span>.tasks.push(task); } <span class="hljs-function"><span class="hljs-title">callAsync</span>(<span class="hljs-params">...args</span>)</span> { <span class="hljs-keyword">const</span> endCb = args.pop(); <span class="hljs-keyword">let</span> index = <span class="hljs-number">0</span>; <span class="hljs-keyword">const</span> done = <span class="hljs-function">() =></span> { index++; <span class="hljs-keyword">if</span> (index === <span class="hljs-built_in">this</span>.tasks.length) { endCb(); } } <span class="hljs-built_in">this</span>.tasks.forEach(<span class="hljs-function"><span class="hljs-params">task</span> =></span> { task(...args, done) }); } <span class="hljs-function"><span class="hljs-title">tapPromise</span>(<span class="hljs-params">name, task</span>)</span> { <span class="hljs-built_in">this</span>.tasks.push(task); } <span class="hljs-function"><span class="hljs-title">promise</span>(<span class="hljs-params">...args</span>)</span> { <span class="hljs-keyword">let</span> promiseTasks = <span class="hljs-built_in">this</span>.tasks.map(<span class="hljs-function"><span class="hljs-params">task</span> =></span> task(...args)); <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.all(promiseTasks); }}<span class="hljs-built_in">module</span>.exports = AsyncParallelHook;</code></pre></div><h3 id="AsyncSeriesHook"><a href="#AsyncSeriesHook" class="headerlink" title="AsyncSeriesHook"></a>AsyncSeriesHook</h3><p>AsyncSeriesHook 异步串行钩子</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> { AsyncSeriesHook } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'tapable'</span>);<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Hook</span> </span>{ <span class="hljs-function"><span class="hljs-title">constructor</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-built_in">this</span>.hooks = { <span class="hljs-attr">arch</span>: <span class="hljs-keyword">new</span> AsyncSeriesHook([<span class="hljs-string">'arg1'</span>]) } } <span class="hljs-comment">// 注册监听函数</span> <span class="hljs-function"><span class="hljs-title">subscribe</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-built_in">this</span>.hooks.arch.tapAsync(<span class="hljs-string">'primary'</span>, <span class="hljs-function">(<span class="hljs-params">name, cb</span>) =></span> { <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =></span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'初级前端:'</span>, name); cb() }, <span class="hljs-number">1000</span>) }) <span class="hljs-built_in">this</span>.hooks.arch.tapAsync(<span class="hljs-string">'intermediate'</span>, <span class="hljs-function">(<span class="hljs-params">name, cb</span>) =></span> { <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =></span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'中级前端:'</span>, name); cb() }, <span class="hljs-number">1000</span>) }) <span class="hljs-built_in">this</span>.hooks.arch.tapAsync(<span class="hljs-string">'senior'</span>, <span class="hljs-function">(<span class="hljs-params">name, cb</span>) =></span> { <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =></span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'高级前端:'</span>, name); cb() }, <span class="hljs-number">1000</span>) }) } <span class="hljs-comment">// 执行监听函数</span> <span class="hljs-function"><span class="hljs-title">publish</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-built_in">this</span>.hooks.arch.callAsync(<span class="hljs-string">'yxfan'</span>, <span class="hljs-function">() =></span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'封神啦!'</span>); }) }}<span class="hljs-keyword">const</span> hook = <span class="hljs-keyword">new</span> Hook();hook.subscribe();hook.publish();</code></pre></div><p>因为是串行钩子,所以依次间隔1秒打印:“初级前端: yxfan”,“中级前端: yxfan”,“高级前端: yxfan”,异步都执行完了,最后才打印“封神啦!”</p><p>同理用tapPromise的情况</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HookPromise</span> </span>{ <span class="hljs-function"><span class="hljs-title">constructor</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-built_in">this</span>.hooks = { <span class="hljs-attr">arch</span>: <span class="hljs-keyword">new</span> AsyncSeriesHook([<span class="hljs-string">'arg1'</span>]) } } <span class="hljs-comment">// 注册监听函数</span> <span class="hljs-function"><span class="hljs-title">subscribe</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-built_in">this</span>.hooks.arch.tapPromise(<span class="hljs-string">'primary'</span>, <span class="hljs-function">(<span class="hljs-params">name</span>) =></span> { <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve</span>) =></span> { <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =></span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'初级前端:'</span>, name); resolve() }, <span class="hljs-number">1000</span>) }) }) <span class="hljs-built_in">this</span>.hooks.arch.tapPromise(<span class="hljs-string">'intermediate'</span>, <span class="hljs-function">(<span class="hljs-params">name</span>) =></span> { <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve</span>) =></span> { <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =></span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'中级前端:'</span>, name); resolve() }, <span class="hljs-number">1000</span>) }) }) <span class="hljs-built_in">this</span>.hooks.arch.tapPromise(<span class="hljs-string">'senior'</span>, <span class="hljs-function">(<span class="hljs-params">name</span>) =></span> { <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve</span>) =></span> { <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =></span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'高级前端:'</span>, name); resolve() }, <span class="hljs-number">1000</span>) }) }) } <span class="hljs-comment">// 执行监听函数</span> <span class="hljs-function"><span class="hljs-title">publish</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-built_in">this</span>.hooks.arch.promise(<span class="hljs-string">'yxfan'</span>) .then(<span class="hljs-function">() =></span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'封神啦!'</span>); }) }}<span class="hljs-keyword">const</span> hookPromise = <span class="hljs-keyword">new</span> HookPromise();hookPromise.subscribe();hookPromise.publish();</code></pre></div><h4 id="实现:-5"><a href="#实现:-5" class="headerlink" title="实现:"></a>实现:</h4><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AsyncSeriesHook</span> </span>{ <span class="hljs-function"><span class="hljs-title">constructor</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-built_in">this</span>.tasks = []; } <span class="hljs-function"><span class="hljs-title">tapAsync</span>(<span class="hljs-params">name, task</span>)</span> { <span class="hljs-built_in">this</span>.tasks.push(task); } <span class="hljs-function"><span class="hljs-title">callAsync</span>(<span class="hljs-params">...args</span>)</span> { <span class="hljs-keyword">const</span> endCb = args.pop(); <span class="hljs-keyword">let</span> index = <span class="hljs-number">0</span>; <span class="hljs-comment">// 递归</span> <span class="hljs-keyword">let</span> next = <span class="hljs-function">() =></span> { <span class="hljs-keyword">if</span> (index === <span class="hljs-built_in">this</span>.tasks.length) { <span class="hljs-keyword">return</span> endCb(); } <span class="hljs-keyword">let</span> task = <span class="hljs-built_in">this</span>.tasks[index]; index++; task(...args, next); } next(); } <span class="hljs-function"><span class="hljs-title">tapPromise</span>(<span class="hljs-params">name, task</span>)</span> { <span class="hljs-built_in">this</span>.tasks.push(task); } <span class="hljs-function"><span class="hljs-title">promise</span>(<span class="hljs-params">...args</span>)</span> { <span class="hljs-keyword">const</span> [first, ...others] = <span class="hljs-built_in">this</span>.tasks; <span class="hljs-keyword">return</span> others.reduce(<span class="hljs-function">(<span class="hljs-params">pre, next</span>) =></span> { <span class="hljs-keyword">return</span> pre.then(<span class="hljs-function">() =></span> next(...args)); }, first(...args)); }}<span class="hljs-built_in">module</span>.exports = AsyncSeriesHook;</code></pre></div><h3 id="AsyncSeriesWaterfallHook"><a href="#AsyncSeriesWaterfallHook" class="headerlink" title="AsyncSeriesWaterfallHook"></a>AsyncSeriesWaterfallHook</h3><p>AsyncSeriesWaterfallHook 异步串行瀑布钩子,像瀑布一样的传递参数</p><p>注意:cb方法接受两个参数,第一个参数是错误信息,为null时,数据流向下,不为null则表示出错了,后续事件都不执行,直接执行callAsync的回调。第二个参数就要传递的数据</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> { AsyncSeriesWaterfallHook } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../real-tapable'</span>);<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Hook</span> </span>{ <span class="hljs-function"><span class="hljs-title">constructor</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-built_in">this</span>.hooks = { <span class="hljs-attr">arch</span>: <span class="hljs-keyword">new</span> AsyncSeriesWaterfallHook([<span class="hljs-string">'arg1'</span>]) } } <span class="hljs-comment">// 注册监听函数</span> <span class="hljs-function"><span class="hljs-title">subscribe</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-built_in">this</span>.hooks.arch.tapAsync(<span class="hljs-string">'primary'</span>, <span class="hljs-function">(<span class="hljs-params">name, cb</span>) =></span> { <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =></span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'初级前端:'</span>, name); cb(<span class="hljs-literal">null</span>, <span class="hljs-string">'cheney'</span>) }, <span class="hljs-number">1000</span>) }) <span class="hljs-built_in">this</span>.hooks.arch.tapAsync(<span class="hljs-string">'intermediate'</span>, <span class="hljs-function">(<span class="hljs-params">data, cb</span>) =></span> { <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =></span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'中级前端:'</span>, data); cb(<span class="hljs-string">'error'</span>, <span class="hljs-string">'xiaopa'</span>) <span class="hljs-comment">// 出错啦,senior事件不会执行</span> }, <span class="hljs-number">1000</span>) }) <span class="hljs-built_in">this</span>.hooks.arch.tapAsync(<span class="hljs-string">'senior'</span>, <span class="hljs-function">(<span class="hljs-params">data, cb</span>) =></span> { <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =></span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'高级前端:'</span>, data); cb(<span class="hljs-literal">null</span>) }, <span class="hljs-number">1000</span>) }) } <span class="hljs-comment">// 执行监听函数</span> <span class="hljs-function"><span class="hljs-title">publish</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-built_in">this</span>.hooks.arch.callAsync(<span class="hljs-string">'yxfan'</span>, <span class="hljs-function">() =></span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'封神啦!'</span>); }) }}<span class="hljs-keyword">const</span> hook = <span class="hljs-keyword">new</span> Hook();hook.subscribe();hook.publish();</code></pre></div><p>依次间隔1秒打印:”初级前端: yxfan”,“中级前端: yxfan”,“封神啦!”</p><p>用<code>tapPromise</code>注册事件:</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HookPromise</span> </span>{ <span class="hljs-function"><span class="hljs-title">constructor</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-built_in">this</span>.hooks = { <span class="hljs-attr">arch</span>: <span class="hljs-keyword">new</span> AsyncSeriesWaterfallHook([<span class="hljs-string">'arg1'</span>]) } } <span class="hljs-comment">// 注册监听函数</span> <span class="hljs-function"><span class="hljs-title">subscribe</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-built_in">this</span>.hooks.arch.tapPromise(<span class="hljs-string">'primary'</span>, <span class="hljs-function">(<span class="hljs-params">name</span>) =></span> { <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve</span>) =></span> { <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =></span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'初级前端:'</span>, name); resolve(<span class="hljs-string">'cheney'</span>) }, <span class="hljs-number">1000</span>) }) }) <span class="hljs-built_in">this</span>.hooks.arch.tapPromise(<span class="hljs-string">'intermediate'</span>, <span class="hljs-function">(<span class="hljs-params">data</span>) =></span> { <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =></span> { <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =></span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'中级前端:'</span>, data); <span class="hljs-comment">// resolve('xiaopa')</span> reject() }, <span class="hljs-number">1000</span>) }) }) <span class="hljs-built_in">this</span>.hooks.arch.tapPromise(<span class="hljs-string">'senior'</span>, <span class="hljs-function">(<span class="hljs-params">data</span>) =></span> { <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =></span> { <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =></span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'高级前端:'</span>, data); resolve() }, <span class="hljs-number">1000</span>) }) }) } <span class="hljs-comment">// 执行监听函数</span> <span class="hljs-function"><span class="hljs-title">publish</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-built_in">this</span>.hooks.arch.promise(<span class="hljs-string">'yxfan'</span>) .then(<span class="hljs-function">() =></span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'封神啦!'</span>); }) }}<span class="hljs-keyword">const</span> hookPromise = <span class="hljs-keyword">new</span> HookPromise();hookPromise.subscribe();hookPromise.publish();</code></pre></div><h4 id="实现:-6"><a href="#实现:-6" class="headerlink" title="实现:"></a>实现:</h4><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AsyncSeriesWaterfallHook</span> </span>{ <span class="hljs-function"><span class="hljs-title">constructor</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-built_in">this</span>.tasks = []; } <span class="hljs-function"><span class="hljs-title">tapAsync</span>(<span class="hljs-params">name, task</span>)</span> { <span class="hljs-built_in">this</span>.tasks.push(task); } <span class="hljs-function"><span class="hljs-title">callAsync</span>(<span class="hljs-params">...args</span>)</span> { <span class="hljs-keyword">const</span> endCb = args.pop(); <span class="hljs-keyword">let</span> index = <span class="hljs-number">0</span>; <span class="hljs-comment">// 递归</span> <span class="hljs-keyword">let</span> next = <span class="hljs-function">(<span class="hljs-params">err, data</span>) =></span> { <span class="hljs-keyword">let</span> task = <span class="hljs-built_in">this</span>.tasks[index]; <span class="hljs-keyword">if</span> (!task || err) <span class="hljs-keyword">return</span> endCb(); <span class="hljs-keyword">if</span> (index == <span class="hljs-number">0</span>) { task(...args, next); } <span class="hljs-keyword">else</span> { task(data, next); } index++; } next(); } <span class="hljs-function"><span class="hljs-title">tapPromise</span>(<span class="hljs-params">name, task</span>)</span> { <span class="hljs-built_in">this</span>.tasks.push(task); } <span class="hljs-function"><span class="hljs-title">promise</span>(<span class="hljs-params">...args</span>)</span> { <span class="hljs-keyword">const</span> [first, ...others] = <span class="hljs-built_in">this</span>.tasks; <span class="hljs-keyword">return</span> others.reduce(<span class="hljs-function">(<span class="hljs-params">pre, next</span>) =></span> { <span class="hljs-keyword">return</span> pre.then(<span class="hljs-function">(<span class="hljs-params">data</span>) =></span> next(data)); }, first(...args)); }}<span class="hljs-built_in">module</span>.exports = AsyncSeriesWaterfallHook;</code></pre></div><p><a href="https://gitee.com/fanxiaopa/tabaple">代码地址</a></p>]]></content>
<tags>
<tag>webpack</tag>
</tags>
</entry>
<entry>
<title>读《成事心法》Part1</title>
<link href="/2021/10/31/%E8%AF%BB%E3%80%8A%E6%88%90%E4%BA%8B%E5%BF%83%E6%B3%95%E3%80%8BPart1/"/>
<url>/2021/10/31/%E8%AF%BB%E3%80%8A%E6%88%90%E4%BA%8B%E5%BF%83%E6%B3%95%E3%80%8BPart1/</url>
<content type="html"><![CDATA[<p>我为什么要读这本书,因为看中了书名“成事”二字,心里纠结着到底要不要买这本书。为何纠结呢,因为我还没看完《孙子兵法》,一本书没看完就去看另一本书,这种就像猴子搬苞谷,看到啥就搬啥,搬啥也漏啥。</p><p>但我最后还是从同事手里拿来看了,这还是另一个同事离职时转赠给他的,被我给截胡了。看这本书我是带有目的的,希望能通过这种方法论让自己能成事,持续成事,持续成大事。</p><p>第一章讲的是<code>知己</code>,想在想想,我真到了解自己吗?能够掌控自己的情绪吗?能够平衡工作和生活吗?</p><h3 id="成大事无捷径"><a href="#成大事无捷径" class="headerlink" title="成大事无捷径"></a>成大事无捷径</h3><p>在成大事无捷径篇,作者反复提到成名无需太早,成名太早,有可能会影响将来的后劲。</p><blockquote><p>工作是场马拉松,有可能你要拿十年,二十年看待,给自己一个学习,实践的过程。你以为懂了,很有可能你还没有真懂,让你迅速上位之后,你德不配位,你会被这个位子,被自己的名声累坏。</p></blockquote><p>在快节奏的今天,多数人都是浮躁的,看到机会就上,往往却忽略了德是否配位。你的品行德行配不配的上你的位置,自己几斤几两要搞清楚,弄明白。</p><p>曾国藩曾说过:“凡是皆用困知勉行功夫,不可求名太骤,求效太捷也”。做事,应该慢慢来做,努力来做,知道这件事情很难,一点一点去克服,不能求成名太早,也不能一味求快。就拿换工作这事儿来说,从毕业到现在,你跳过几次槽,换过几家公司,在每家公司呆了多久,当然如果你碰到坑人的公司那就另说,说到底也怪你当初没擦亮眼镜。为什么HR不愿招段时间内跳槽多的人,因为他们浮躁,不稳定,会给企业增加一定的风险。</p><p>路漫漫其修远兮,自己的职业道路才刚刚开始,静下心来,戒掉浮躁,走慢点,走稳点。</p><h3 id="掌控情绪"><a href="#掌控情绪" class="headerlink" title="掌控情绪"></a>掌控情绪</h3><p>在工作中,我自认为我情绪管理的还不错,直到在项目提测时,产品提出要修改需求。我当时内心万马崩腾(想问候他家大爷!),尽管刻意抑制,但我能明显的感觉到别人能从我此刻的面部表情中看到我的心理,还是修行不够,历练不够。每次到下班时,有bug来了,我都不由得心慌起来,还是不够镇定,大不了下楼吃个饭,晚上继续搞,没啥大不了的。这种心慌情绪,特别在项目提测当天尤为明显,千万别来bug,千万别来bug,千万别来bug,重要的事说三遍!可是该来的还是来,并不会因为你叫他别来,他就不来,所以焦虑的心绪并不会改变结果,只是徒增烦恼罢了。</p><p>在书中掌控情绪篇,我并没有学到一定的方法论,但是我对这句话印象特别深刻:“要把愤怒当成一个要克服的难题,心跟上,身体也就快了”。要珍惜每一次愤怒的机会,因为每一次愤怒都是对自身心态的考验,如果能这样想,那倒是能消火不少。</p><p>如有朝一日我能达到“临事静对猛虎,事了闲看落花”的境界,何愁不成事,何愁不成大事。</p><h3 id="得志行天下,不得志则多读书"><a href="#得志行天下,不得志则多读书" class="headerlink" title="得志行天下,不得志则多读书"></a>得志行天下,不得志则多读书</h3><p>要说我大学期间最大的遗憾是什么,那就是没有多读书,回过头来看,自己大学期间读的书屈指可数,才导致现如今的我精神境界如此匮乏,身上还是这么油腻俗气。现如今我想做出改变,得志行天下,不得志则能独善其身。要想独善其身,方法就是要多读书。“书中自有颜如玉,书中自有千钟粟”,书不仅能带来精神愉悦,还能为成事做好必要的准备。</p><p>在书中看到一幅对联:</p><blockquote><p>时间数百年旧家无非积德,天下第一件好事还是读书</p></blockquote>]]></content>
<tags>
<tag>书籍</tag>
</tags>
</entry>
<entry>
<title>公告</title>
<link href="/2021/10/24/Notice/"/>
<url>/2021/10/24/Notice/</url>
<content type="html"><![CDATA[<h3 id="关于迁移"><a href="#关于迁移" class="headerlink" title="关于迁移"></a>关于迁移</h3><p>想要把写文章这件事持续的做下去,初心是技术,但不局限于技术,也有对生活、书籍甚至是电影的感悟。</p><p>为了能专注于写文章,决定采用第三方平台,相比于知乎、掘金、CSDN,我更喜欢简洁又不失功能的语雀。</p><p>链接地址🔗: <a href="https://www.yuque.com/yxfan-2put5/blog">我的新空间</a></p>]]></content>
<tags>
<tag>公告</tag>
</tags>
</entry>
<entry>
<title>https</title>
<link href="/2021/10/03/https%E5%8A%A0%E5%AF%86/"/>
<url>/2021/10/03/https%E5%8A%A0%E5%AF%86/</url>
<content type="html"><![CDATA[<h3 id="对称加密"><a href="#对称加密" class="headerlink" title="对称加密"></a>对称加密</h3><p>起初yxfan和cheney之间的通信都是明文的,这无疑是在网络上裸奔啊。任何一个人都能监听他们之间的通信,打开数据包,窥探隐私。</p><p>后来yxfan说,要不我们在发送消息之前,先把消息加密,到我们手里时再用密钥解密,这样就算被中间人劫持了他也看不懂。</p><p>接发双方用同一个密钥的加密方式就叫<code>对称加密</code>。如图所示:</p><img style="display: block ;margin: 0 auto;height: 15rem" src="/images/https加密/对称加密.png"/><p>这有点像谍战片里接发电报,双方事先约定好一套密码本,通信时都用的数字代码,这样一来就算被敌人拦截,他们也无从下手。</p><p>万一被叛徒出卖,密码本被敌人发现了,之前约定的方式肯定有暴露的风险,现在急需一套新的密码本,但是怎么传给远在潜伏区的同志们呢?只能派人携带密码本突破重重封锁,带到潜伏区。</p><p>当然了,现在传送密钥不用流血牺牲,但成本也是不小的,因为你不能直接将密钥通过网络传输,有暴露的风险,在传输过程中。一旦被中间人劫持到密钥,接发双方之间的通信内容,也会被中间人一收眼底。难道就没有更好更安全到方法了吗?</p><h3 id="非对称加密(RSA)"><a href="#非对称加密(RSA)" class="headerlink" title="非对称加密(RSA)"></a>非对称加密(RSA)</h3><p>和对称加密不同的是,RSA算法有一对密钥,分别为<code>公钥</code>和<code>私钥</code>,顾名思义公钥是大家都知道的,咱地球人都知道;私钥可得保存好了,只有咱自个儿知道。有趣的是,用公钥加密的数据,只有对应的私钥才能解;用私钥加密的数据,只有对应的公钥才能解。</p><img style="display: block ;margin: 0 auto;height: 15rem" src="/images/https加密/公钥和私钥.png"/><p>现在我们可以用这种方式安全的通信了。以yxfan给cheney发消息为例,</p><ul><li>1、cheney先把自己的公钥发给yxfan,</li><li>2、yxfan拿到了cheney的公钥后,yxfan将消息用公钥加密,传输给cheney,传输过程中就算被中间人劫持了,也无法解密,因为他没有私钥啊,傻眼了吧</li><li>3、cheney收到消息后,用自个儿的私钥解密,成功读取到数据</li></ul><img style="display: block ;margin: 0 auto;height: 25rem" src="/images/https加密/非对称加密.png"/><p>RSA算法也有弊端,加密和解密的速度有点慢,与对称加密算法相比要慢百倍有余</p><h3 id="非对称加密-对称加密"><a href="#非对称加密-对称加密" class="headerlink" title="非对称加密+对称加密"></a>非对称加密+对称加密</h3><p>回到最初的问题上,我们就是想要一个密钥来加密通信而已,对称加密的加解密比较快,但是对称密钥可能被截取,而非对称加解密较安全,但速度堪忧。那为啥不把两者相结合呢:</p><ul><li>我生成一个密钥,通过RSA方式安全的传送给你</li><li>你收到密钥后,我们后续就用这个密钥来对称加密通信</li></ul><p>如此,即解决了密钥的传输问题,有解决了RSA速度慢的问题</p><h3 id="中间人劫持"><a href="#中间人劫持" class="headerlink" title="中间人劫持"></a>中间人劫持</h3><p>如果cheney给yxfan发公钥的时候,被一个中间人截取了cheney的公钥,然后把自己的公钥发给了yxfan,冒充cheney。导致yxfan发的消息都用了中间人的公钥加密,中间人马上就能通过自己的私钥解密,这不就看到消息了吗?</p><p>这个中间人解密后,还可以用cheney的公钥加密,发给cheney,cheney和yxfan根本意识不到通信已被窥探,还以为在安全传输呢。</p><img style="display: block ;margin: 0 auto;height: 25rem" src="/images/https加密/中间人劫持.png"/><p>问题是出在公钥的分发上,虽然公钥是公开的,但是别有用心的人还是可以截取干坏事。</p><h3 id="数字签名"><a href="#数字签名" class="headerlink" title="数字签名"></a>数字签名</h3><p>回到最初的问题上:怎么安全保护密钥?这一次的公钥是公开的,必须保证这个公钥一定得是cheney的,而不是别人的。</p><p>我们现实生活中有公证中心,我们也可以模拟一个具有公信力的认证中心,给cheney颁发一个证书,里面就包括了公钥,如此一来我们直接获取证书就可以了。</p><p>有了以上的经验,万一在证书传输过程中,被中间人篡改了怎么办?(这些坏人总是无孔不入!)</p><p>数字签名闪亮✨登场</p><p>cheney把自己的公钥和个人信息,通过一种Hash算法生成一个消息摘要。这种Hash有种特性,只要输入数据有一点变化,生成的消息摘要就有巨变,这样可以防止别人篡改原有内容。</p><p>尽管不能篡改了,中间人索性把整个原始信息都给替换了,我们仍然分辨不出来啊。</p><p>可恶的中间人,真是坏透了。方法总比困难多,cheney让有公信力的认证中心(CA)把自己生成的消息摘要通过CA私钥加密生成数字签名。</p><p>除此之外,认证中心还能够把原始信息和数字签名合在一起形成数字证书。流程如下图:</p><img style="display: block ;margin: 0 auto;height: 20rem" src="/images/https加密/数字证书.png"/><p>当cheney把自己的证书发给yxfan时,yxfan用同样的Hash算法把证书中的原始信息生成一个消息摘要,紧接着用CA的公钥对证书中的签名进行解密,用新的消息摘要和解密后的消息摘要两者对比,如果一样,则没有被篡改,就可以顺利拿到cheney的公钥了,如此一来公钥的分发就解决啦!后续的加密工作就可以开始了。</p><img style="display: block ;margin: 0 auto;height: 10rem" src="/images/https加密/验证数字证书.png"/><h3 id="https流程图"><a href="#https流程图" class="headerlink" title="https流程图"></a>https流程图</h3><p>一个简化版的HTTPS流程图如下图所示:</p><img style="display: block ;margin: 0 auto;height: 30rem" src="/images/https加密/https流程图.png"/>]]></content>
<tags>
<tag>https</tag>
</tags>
</entry>
<entry>
<title>useEffect & useLayoutEffect的区别</title>
<link href="/2021/09/17/useEffect-useLayoutEffect%E7%9A%84%E5%8C%BA%E5%88%AB/"/>
<url>/2021/09/17/useEffect-useLayoutEffect%E7%9A%84%E5%8C%BA%E5%88%AB/</url>
<content type="html"><![CDATA[<h4 id="先说结论:"><a href="#先说结论:" class="headerlink" title="先说结论:"></a>先说结论:</h4><p>两者执行时机不同,<code>useEffect</code>在渲染之后异步执行;<code>useLayoutEffect</code>在渲染之前同步执行,如果执行复杂的操作,会阻塞页面渲染</p><ul><li> 1、useLayoutEffect和componentDidMount和componentDidUpdate触发时机一致(都在在DOM修改后且浏览器渲染之前),会阻塞浏览器渲染!</li><li>2、useEffect执行时机是commit阶段后异步执行(可理解为浏览器渲染之后),不会阻塞浏览器渲染</li></ul>]]></content>
</entry>
<entry>
<title>one day</title>
<link href="/2021/09/08/one-day/"/>
<url>/2021/09/08/one-day/</url>
<content type="html"><![CDATA[<div style="width:100%;height: 500px;margin: 0 auto"><iframe style="height:100%;width:100%" src='https://player.youku.com/embed/XNTgwNDQ1NjI0OA==' frameborder='allowfullscreen' allowfullscreen="true"></iframe>居然有广告。。。</div>]]></content>
<tags>
<tag>杂记</tag>
</tags>
</entry>
<entry>
<title>设计模式小结</title>
<link href="/2021/08/10/js%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E5%B0%8F%E7%BB%93/"/>
<url>/2021/08/10/js%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E5%B0%8F%E7%BB%93/</url>
<content type="html"><![CDATA[<h2 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h2><p>设计模式分为一下三种类型</p><p>1、创建型:描述如何创建对象,将对象的创建和使用分离</p><ul><li>工厂模式(分隔变与不变,即个性与共性)</li><li>单例模式(只能被实例化一次,唯一性)</li><li>原型模式(实现数据/方法的共享)</li></ul><p>2、结构型:让对象做更多的事</p><ul><li>装饰器模式(给类或方法,添加额外功能)</li><li>适配器模式</li><li>代理模式</li></ul><p>3、行为型:关注对象之间通讯,描述对象相互协作,以及怎样分配职责</p><ul><li>观察者模式(组件通讯,解耦)</li><li>迭代器模式(用的不多,就是遍历)</li></ul>]]></content>
<tags>
<tag>js设计模式</tag>
</tags>
</entry>
<entry>
<title>迭代器模式</title>
<link href="/2021/08/03/%E8%BF%AD%E4%BB%A3%E5%99%A8%E6%A8%A1%E5%BC%8F/"/>
<url>/2021/08/03/%E8%BF%AD%E4%BB%A3%E5%99%A8%E6%A8%A1%E5%BC%8F/</url>
<content type="html"><![CDATA[<h2 id="迭代器模式"><a href="#迭代器模式" class="headerlink" title="迭代器模式"></a>迭代器模式</h2><h3 id="Iterator(迭代器)"><a href="#Iterator(迭代器)" class="headerlink" title="Iterator(迭代器)"></a>Iterator(迭代器)</h3><p>要成为可迭代对象,必须要实现<code>@iterator</code>方法,这个方法可以通过<code>Symbol.iterator</code>属性(可能在原型对象上)访问到。</p><p>因此可以通过有没有<code>Symbol.iterator</code>属性来判断是能不能进行遍历。</p><table><thead><tr><th>值</th><th>属性</th></tr></thead><tbody><tr><td>Symbol.itarator</td><td>一个无参数的函数,返回一个满足迭代器协议的可迭代对象(遍历器)</td></tr></tbody></table><p>下面这些语法要使用可迭代对象</p><ul><li>for…of..循环</li><li>展开语法(数组、函数参数)</li><li>yield *</li><li>结构赋值</li></ul><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-comment">// 以yield* 为例</span><span class="hljs-keyword">let</span> generator = <span class="hljs-function"><span class="hljs-keyword">function</span>* (<span class="hljs-params"></span>) </span>{ <span class="hljs-keyword">yield</span> <span class="hljs-number">1</span>; <span class="hljs-keyword">yield</span>* obj; <span class="hljs-comment">// obj是个可迭代对象,obj为代码块3定义的</span> <span class="hljs-keyword">yield</span> <span class="hljs-number">5</span>;};<span class="hljs-keyword">var</span> iterator = generator();iterator.next(); <span class="hljs-comment">// {value: 1, done: false}</span>iterator.next(); <span class="hljs-comment">// {value: 'yxfan', done: false}</span>iterator.next(); <span class="hljs-comment">// {value: 18, done: false}</span>iterator.next(); <span class="hljs-comment">// {value: 5, done: false}</span></code></pre></div><p>下面这些数据结构内置可迭代对象,他们的原型对象都实现了<code>@iterator</code>方法</p><ul><li>String</li><li>Array</li><li>Map</li><li>Set</li><li>函数的arguments对象</li><li>NodeList (document.querySelectorAll)</li><li>HTMLCollection (document.getElementBy….)</li><li><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/TypedArray"><code>TypedArray</code></a></li></ul><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> arr = [<span class="hljs-string">'a'</span>, <span class="hljs-string">'b'</span>, <span class="hljs-string">'c'</span>]; <span class="hljs-comment">// 1</span><span class="hljs-keyword">const</span> iterator = arr[<span class="hljs-built_in">Symbol</span>.iterator](); <span class="hljs-comment">// 2</span>iterator.next(); <span class="hljs-comment">// { value: 'a', done: false }</span>iterator.next(); <span class="hljs-comment">// { value: 'b', done: false }</span>iterator.next(); <span class="hljs-comment">// { value: 'c', done: false }</span>iterator.next(); <span class="hljs-comment">// { value: undefined, done: true }</span></code></pre></div><p>由于Array原生就具备遍历器接口,所以在2处可以通过<code>Symbol.iterator</code>属性访问到生成遍历器的函数,并调用,得到遍历器<code>iterator</code> </p><p>因为对象没有内置遍历器接口,因此要用<code>for...of</code>在对象上,就得手动实现<code>Symbol.iterator</code></p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> obj = { <span class="hljs-attr">name</span>: <span class="hljs-string">'yxfan'</span>, <span class="hljs-attr">age</span>: <span class="hljs-number">18</span>};obj[<span class="hljs-built_in">Symbol</span>.iterator] = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{ <span class="hljs-keyword">const</span> keys = <span class="hljs-built_in">Object</span>.keys(obj); <span class="hljs-keyword">let</span> index = <span class="hljs-number">0</span>; <span class="hljs-comment">// 老必包了</span> <span class="hljs-keyword">return</span> { <span class="hljs-attr">next</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{ <span class="hljs-keyword">const</span> object = { <span class="hljs-attr">value</span>: obj[keys[index]], <span class="hljs-attr">done</span>: index < keys.length ? <span class="hljs-literal">false</span> : <span class="hljs-literal">true</span> } index++; <span class="hljs-keyword">return</span> object; } }}<span class="hljs-keyword">const</span> iterator = obj[<span class="hljs-built_in">Symbol</span>.iterator]();<span class="hljs-built_in">console</span>.log(iterator.next()); <span class="hljs-comment">// {value: "yxfan", done: false}</span><span class="hljs-built_in">console</span>.log(iterator.next()); <span class="hljs-comment">// {value: 18, done: false}</span><span class="hljs-built_in">console</span>.log(iterator.next()); <span class="hljs-comment">// {value: 18, done: true}</span><span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> o <span class="hljs-keyword">of</span> obj) { <span class="hljs-built_in">console</span>.log(o); <span class="hljs-comment">// 依次打印 yxfan 18</span>}</code></pre></div><p>上面这个例子中,手动的给<code>obj</code>对象设置了<code>Symbol.iterator</code>属性,其值为一个生成器函数。这样我们就可以像<code>for..of..</code>数组一样,去<code>for...of...</code>对象啦!</p><h3 id="Generator(生成器)"><a href="#Generator(生成器)" class="headerlink" title="Generator(生成器)"></a>Generator(生成器)</h3><h4 id="与Iterator接口的关系"><a href="#与Iterator接口的关系" class="headerlink" title="与Iterator接口的关系"></a>与Iterator接口的关系</h4><p>任意一个对象的<code>[Symbol.iterator]</code>方法,等于该对象的遍历器生成函数,调用生成函数,会返回一个遍历器对象。</p><p>而<code>generator</code>函数就是遍历器生成函数,因此可以把<code>generator</code>函数赋值给<code>[Symbol.iterator]</code> </p><p>来改造上一个例子:</p><div class="code-wrapper"><pre><code class="hljs javascript"> <span class="hljs-keyword">const</span> obj = { <span class="hljs-attr">name</span>: <span class="hljs-string">'yxfan'</span>, <span class="hljs-attr">age</span>: <span class="hljs-number">18</span>, * [<span class="hljs-built_in">Symbol</span>.iterator]() { <span class="hljs-keyword">let</span> index = <span class="hljs-number">0</span>; <span class="hljs-keyword">const</span> keys = <span class="hljs-built_in">Object</span>.keys(<span class="hljs-built_in">this</span>); <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> k <span class="hljs-keyword">of</span> keys) { <span class="hljs-keyword">yield</span> [k, <span class="hljs-built_in">this</span>[k]]; } } };<span class="hljs-keyword">const</span> iterator = obj[<span class="hljs-built_in">Symbol</span>.iterator]();<span class="hljs-built_in">console</span>.log(iterator.next()); <span class="hljs-comment">// {value: ['name', 'yxfan'], done: false}</span><span class="hljs-built_in">console</span>.log(iterator.next()); <span class="hljs-comment">// {value: ['age', 18], done: false}</span><span class="hljs-built_in">console</span>.log(iterator.next()); <span class="hljs-comment">// {value: undefined, done: true}</span><span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> [key, value] <span class="hljs-keyword">of</span> obj) { <span class="hljs-built_in">console</span>.log(key, value); <span class="hljs-comment">// name yxfan age 18</span>}</code></pre></div><p>利用<code>generator</code>我们不用在<code>[Symbol.iterator]</code>中部署<code>next</code>方法直接用<code>yield</code>给出每一步的返回值即可</p><p><code>generator</code>方法会返回一个遍历器,遍历器的<code>next</code>方法运行逻辑如下</p><ol><li>遇到<code>yield</code>表达式,就暂停执行后面的操作,并将紧跟在<code>yield</code>后面表达式的值,作为返回对象的<code>value</code></li><li>下一次调用<code>next</code>方法时,继续往下执行,直到遇到下一个<code>yield</code>表达式</li><li>如果没有遇到新的<code>yield</code>表达式值,就一直运行到函数结束,直到<code>return</code>语句为止,并将<code>return</code>语句后面的表达式的值,作为返回的对象的<code>value</code>属性值。</li><li>如果该函数没有<code>return</code>语句,则返回的对象的<code>value</code>属性值为<code>undefined</code>。</li></ol><p><code>generator</code>函数不会立即执行</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> * <span class="hljs-title">g</span>(<span class="hljs-params"></span>) </span>{<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'我不会立即执行喔'</span>);}<span class="hljs-keyword">const</span> iterator = g();<span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =></span> {<span class="hljs-built_in">console</span>.log(iterator.next()); }, <span class="hljs-number">2000</span>);</code></pre></div><p>如果<code>g()</code>是个普通函数,一经调用则会马上输出log,但是这个是个<code>generator</code>函数,调用时会返回遍历器对象,我尝试着打印一下<code>iterator</code></p><img src="/images/js设计模式/迭代器模式.png" alt="image-20210803174539826" style="zoom:67%;" /><p>只有调用<code>next</code>时函数<code>g</code>才会执行</p><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>该篇主要是说<code>迭代器模式</code>,因此<code>Iterator</code>和<code>generator</code>只是稍微提了一下,跟详实的可看<a href="https://es6.ruanyifeng.com/#docs/generator#next-%E6%96%B9%E6%B3%95%E7%9A%84%E5%8F%82%E6%95%B0">ES6</a></p><p>by the way,迭代器模式在实际开发中用的并不多,但还是得知道是怎么实现的(方便面试)</p>]]></content>
<tags>
<tag>js设计模式</tag>
</tags>
</entry>
<entry>
<title>观察者模式</title>
<link href="/2021/07/30/%E8%A7%82%E5%AF%9F%E8%80%85%E6%A8%A1%E5%BC%8F/"/>
<url>/2021/07/30/%E8%A7%82%E5%AF%9F%E8%80%85%E6%A8%A1%E5%BC%8F/</url>
<content type="html"><![CDATA[<p>说起<code>观察者模式</code>,离不开<code>发布者</code>和<code>订阅者</code> 。</p><p>举个生活中的例子:刷微博</p><p>我们会在微博中关注一些博主,当这些博主要更新内容时,会将内容发布到平台上,平台再将内容推送给我们。</p><p>我们就是<code>订阅者</code>,<code>博主</code>则是发布者。</p><h3 id="使用场景"><a href="#使用场景" class="headerlink" title="使用场景"></a>使用场景</h3><p>组件通信、消息监听、</p><h3 id="代码中的实现"><a href="#代码中的实现" class="headerlink" title="代码中的实现"></a>代码中的实现</h3><p>简易版的<span id="anchor">观察者模式</span></p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-comment">// 发布者类</span><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Publisher</span> </span>{ <span class="hljs-function"><span class="hljs-title">constructor</span>(<span class="hljs-params">name</span>)</span> { <span class="hljs-built_in">this</span>.name = name; <span class="hljs-built_in">this</span>.observers = [] } <span class="hljs-comment">// 增加订阅者</span> <span class="hljs-function"><span class="hljs-title">add</span>(<span class="hljs-params">observer</span>)</span> { <span class="hljs-built_in">this</span>.observers.push(observer); } <span class="hljs-comment">// 取消订阅</span> <span class="hljs-function"><span class="hljs-title">remove</span>(<span class="hljs-params">observer</span>)</span> { <span class="hljs-keyword">const</span> index = <span class="hljs-built_in">this</span>.observers.findIndex(<span class="hljs-function"><span class="hljs-params">o</span> =></span> o === observer); <span class="hljs-built_in">this</span>.observers.splice(index, <span class="hljs-number">1</span>); } <span class="hljs-comment">// 发布消息</span> <span class="hljs-function"><span class="hljs-title">notify</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-built_in">this</span>.observers.forEach(<span class="hljs-function"><span class="hljs-params">observer</span> =></span> { observer.do(<span class="hljs-built_in">this</span>.name); }); }}<span class="hljs-comment">// 订阅者类</span><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Observe</span> </span>{ <span class="hljs-function"><span class="hljs-title">constructor</span>(<span class="hljs-params">name</span>)</span> { <span class="hljs-built_in">this</span>.name = name; } <span class="hljs-function"><span class="hljs-title">do</span>(<span class="hljs-params">name</span>)</span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-built_in">this</span>.name}</span>又看到<span class="hljs-subst">${name}</span>的新瓜啦!`</span>) }}<span class="hljs-keyword">const</span> yxfan = <span class="hljs-keyword">new</span> Observe(<span class="hljs-string">'yxfan'</span>);<span class="hljs-keyword">const</span> xiaopa = <span class="hljs-keyword">new</span> Observe(<span class="hljs-string">'xiaopa'</span>);<span class="hljs-keyword">const</span> krisWu = <span class="hljs-keyword">new</span> Publisher(<span class="hljs-string">'吴亦凡'</span>);krisWu.add(yxfan);krisWu.add(xiaopa);krisWu.notify();</code></pre></div><p><code>yxfan</code>和<code>xiaopa</code>订阅了<code>krisWu</code>的动态,所以当<code>krisWu</code>发布新瓜时,两位订阅者就能接受到。</p><p>所以打印:<code>yxfan又看到吴亦凡的新瓜啦!`` xiaopa又看到吴亦凡的新瓜啦!</code></p><p>原谅我不厚道的笑了。。。</p><h3 id="实现Event-Emitter"><a href="#实现Event-Emitter" class="headerlink" title="实现Event Emitter"></a>实现Event Emitter</h3><p><code>Emitter</code>在开发中经常用(典型的事件发布者-订阅者模式),不管是<code>Vue</code>合适<code>React</code>,涉及到组件通信时,用<code>Emitter</code>将会方便许多(父子组件通信大可不必)。</p><p>下面实现一个简易版的<code>Emitter</code></p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Emitter</span> </span>{ <span class="hljs-comment">// 事件对象</span> handlers = {} <span class="hljs-comment">// 添加事件</span> <span class="hljs-function"><span class="hljs-title">on</span>(<span class="hljs-params">eventName, cb</span>)</span> { <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.handlers[eventName]) { <span class="hljs-built_in">this</span>.handlers[eventName].push(cb); } <span class="hljs-keyword">else</span> { <span class="hljs-built_in">this</span>.handlers[eventName] = [cb]; } } <span class="hljs-comment">// 触发事件</span> <span class="hljs-function"><span class="hljs-title">emit</span>(<span class="hljs-params">eventName, ...params</span>)</span> { <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.handlers[eventName]) { <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.handlers[eventName].forEach(<span class="hljs-function"><span class="hljs-params">cb</span> =></span> { cb(...params); }); } <span class="hljs-keyword">throw</span> <span class="hljs-string">`<span class="hljs-subst">${eventName}</span>事件不存在`</span> } <span class="hljs-comment">// 删除事件</span> <span class="hljs-function"><span class="hljs-title">remove</span>(<span class="hljs-params">eventName</span>)</span> { <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.handlers[eventName]) { <span class="hljs-keyword">return</span> <span class="hljs-keyword">delete</span> <span class="hljs-built_in">this</span>.handlers[eventName]; } <span class="hljs-keyword">throw</span> <span class="hljs-string">`<span class="hljs-subst">${eventName}</span>事件不存在`</span> } <span class="hljs-comment">// 单次监听器,用完即删除</span> <span class="hljs-function"><span class="hljs-title">once</span>(<span class="hljs-params">eventName, cb</span>)</span> { <span class="hljs-built_in">this</span>.on(eventName, <span class="hljs-function">(<span class="hljs-params">...args</span>) =></span> { cb(...args); <span class="hljs-built_in">this</span>.remove(eventName); }); }}<span class="hljs-keyword">const</span> emitter = <span class="hljs-keyword">new</span> Emitter();<span class="hljs-built_in">window</span>.emitter = emitter;<span class="hljs-built_in">window</span>.emitter.on(<span class="hljs-string">'emit-test'</span>, <span class="hljs-function">() =></span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`中国又夺冠🏆啦`</span>)});<span class="hljs-built_in">window</span>.emitter.on(<span class="hljs-string">'emit-test'</span>, <span class="hljs-function">(<span class="hljs-params">num</span>) =></span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`现在金牌<span class="hljs-subst">${num}</span>枚`</span>)});<span class="hljs-keyword">try</span> { <span class="hljs-built_in">window</span>.emitter.emit(<span class="hljs-string">'emit-test'</span>, <span class="hljs-number">15</span>); <span class="hljs-built_in">console</span>.log(emitter) <span class="hljs-built_in">window</span>.emitter.remove(<span class="hljs-string">'emit-test'</span>); <span class="hljs-built_in">window</span>.emitter.emit(<span class="hljs-string">'emit-test'</span>, <span class="hljs-number">15</span>);} <span class="hljs-keyword">catch</span> (e) { <span class="hljs-built_in">console</span>.error(e)}</code></pre></div><p>打印结果:</p><div class="code-wrapper"><pre><code class="hljs javascript">中国又夺冠🏆啦现在金牌<span class="hljs-number">15</span>枚Emitter { <span class="hljs-attr">handlers</span>: {}}emit-test事件不存在</code></pre></div><p>原理很简单,从始至终只需将<code>Emitter</code>实例化一次,并挂载在<code>window</code>上,使得任何地方都可以访问到。</p><p>监听时只需要把<code>事件名</code>丢进缓存池<code>handles</code>中,做一个<code>eventName</code>和<code>cb</code>的映射,触发时找到缓存池中的<code>eventName</code>并运行该映射下的方法即可。</p><h3 id="观察者模式与发布者-订阅者模式"><a href="#观察者模式与发布者-订阅者模式" class="headerlink" title="观察者模式与发布者-订阅者模式"></a>观察者模式与发布者-订阅者模式</h3><p>上述例子中分别实现了<code>观察者模式</code>和<code>发布者-订阅者模式</code>,好像两者并没有什么区别。</p><blockquote><p>上述模式都是为了实现模块间的解耦,但<code>观察者模式</code>又没有完全解耦。被观察者必须去维护一套观察者的集合,这些观察者必须实现统一的方法供被观察者调用,两者之间还是有着说不清、道不明的关系。</p></blockquote><p>我们用上述两个例子来分析这段话</p><p><code>1、被观察者必须去维护一套观察者的集合</code></p><p>krisWu.add(yxfan); krisWu.add(xiaopa); 被观察者<code>krisWu</code>是知道它的观察者有哪些的,并调用<code>add()</code>把观察者<code>yxfan</code>和<code>xiaopa</code>添加进了自己的观察者集合<code>observers</code>中。</p><p><code>2、观察者必须实现统一的方法供被观察者调用</code></p><p>观察者<code>yxfan</code>和<code>xiaopa</code>中都有<code>do()</code> 在被观察者<code>krisWu</code>的<code>notify()</code>中调用。</p><p>而发布者-订阅者就没有那么多戏了,<code>发布者</code>并不知道它的<code>订阅者</code>有哪些,事件的注册和触发都发生在第三方平台上(事件总线),实现了完全的解耦。</p><p>区分这两者模式,就看有木有用到第三方平台。</p>]]></content>
<tags>
<tag>js设计模式</tag>
</tags>
</entry>
<entry>
<title>装饰器模式</title>
<link href="/2021/07/22/%E8%A3%85%E9%A5%B0%E5%99%A8%E6%A8%A1%E5%BC%8F/"/>
<url>/2021/07/22/%E8%A3%85%E9%A5%B0%E5%99%A8%E6%A8%A1%E5%BC%8F/</url>
<content type="html"><![CDATA[<h2 id="装饰器模式"><a href="#装饰器模式" class="headerlink" title="装饰器模式"></a>装饰器模式</h2><h3 id="使用场景"><a href="#使用场景" class="headerlink" title="使用场景"></a>使用场景</h3><p>当对象不能满足现有的功能时,和类一样遵守“开放封闭”原则。只能扩展,不能修改。</p><p>此时可以用装饰器模式,能够给对象添加额外的功能。对象加上它,就像开了挂!</p><p>在使用react+dva时,经常会这么写</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;<span class="hljs-keyword">import</span> { connect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-redux"</span>;@connect(<span class="hljs-function"><span class="hljs-params">state</span> =></span> ({<span class="hljs-attr">data</span>: state[namespace].data}))<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">component</span> </span>{...}</code></pre></div><p>第一次见到这种写法时,内心直呼:这是什么牛马!静下心来仔细一想,嗨!这不就是装饰器嘛。</p><h3 id="装饰类"><a href="#装饰类" class="headerlink" title="装饰类"></a>装饰类</h3><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addStatic</span>(<span class="hljs-params">key, value</span>) </span>{ <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">target</span>) </span>{ target[key] = value; } }@addStatic(<span class="hljs-string">'chip'</span>, <span class="hljs-string">'m1'</span>)<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Mac</span> </span>{}<span class="hljs-built_in">console</span>.log(Mac.chip); <span class="hljs-comment">// m1</span></code></pre></div><p>可以看到addStatic方法有两个参数,目的是给类设置一个静态属性。Mac类本身可没有这个功能喔,完全是装饰器赋予它的。</p><p><code>addStatic</code>里面又return了一个function,这个function的形参target就是我们的Mac类。巧妙的用了必包的方式将参数传递给了目标类。</p><blockquote><p>装饰器对类的行为的改变,是代码编译时发生的,而不是在运行时。这意味着装饰器能够在编译阶段运行代码。可以这么说,装饰器本身就是编译时执行的函数。</p></blockquote><h3 id="装饰方法"><a href="#装饰方法" class="headerlink" title="装饰方法"></a>装饰方法</h3><p>在公司的脚手架中经常看到有这样一种写法</p><div class="code-wrapper"><pre><code class="hljs javascript">@controller(<span class="hljs-string">"/api"</span>)<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IssueTask</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">sword</span>.<span class="hljs-title">Controller</span> </span>{ @get(<span class="hljs-string">"/param"</span>) <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-title">getParam</span>(<span class="hljs-params"></span>)</span> { ...异步请求 }}</code></pre></div><p>这不就是即装饰了类,又装饰了方法嘛(内心os:差点晕过去,这是什么神仙写法!)</p><p>装饰类我们只需关注第一个参数<code>target</code>,而装饰方法有三个参数(前两个参数没有什么luan用)</p><p>在之前的例子上改造一下,添加一个name方法,由于log内容太多,这里做个记号,下面单独列出。</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getType</span>(<span class="hljs-params">type</span>) </span>{ <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">target, name, descriptor</span>) </span>{ <span class="hljs-built_in">console</span>.log(target, name, descriptor); <span class="hljs-comment">// ①</span> <span class="hljs-keyword">const</span> oldValue = descriptor.value; <span class="hljs-comment">// 将之前的方法保存下来,方便下面调用</span> descriptor.value = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{ <span class="hljs-comment">// 目标方法重写了</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`我是<span class="hljs-subst">${type}</span>芯片`</span>, <span class="hljs-built_in">arguments</span>); <span class="hljs-comment">// ②</span> <span class="hljs-keyword">return</span> oldValue.apply(<span class="hljs-built_in">this</span>, <span class="hljs-built_in">arguments</span>); <span class="hljs-comment">// 最后一定要调用之前保存的方法</span> } }}<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Mac</span> </span>{ price = <span class="hljs-string">'100'</span> @getType(<span class="hljs-string">'m1'</span>) <span class="hljs-function"><span class="hljs-title">name</span>(<span class="hljs-params">unit</span>)</span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'价格是:'</span>, <span class="hljs-built_in">this</span>.price + unit); <span class="hljs-comment">// ③</span> }}<span class="hljs-keyword">const</span> m = <span class="hljs-keyword">new</span> Mac();m.name(<span class="hljs-string">'$'</span>);</code></pre></div><p>①处打印了三个形参,<code>target</code>还是类本身,<code>name</code>是装饰的方法名,<code>descriptor</code>是装饰方法的访问器属性</p><div class="code-wrapper"><pre><code class="hljs javascript">Mac{} <span class="hljs-string">'name'</span> { <span class="hljs-attr">value</span>: [<span class="hljs-built_in">Function</span>: name], <span class="hljs-attr">writable</span>: <span class="hljs-literal">true</span>, <span class="hljs-attr">enumerable</span>: <span class="hljs-literal">false</span>, <span class="hljs-attr">configurable</span>: <span class="hljs-literal">true</span> }</code></pre></div><p>②处打印了参数列表,这里可以做一些额外的功能。arguments是④处调用时的实参</p><div class="code-wrapper"><pre><code class="hljs java">我是m1芯片 [Arguments] { <span class="hljs-string">'0'</span>: <span class="hljs-string">'$'</span> }</code></pre></div><p>③处是正常的打印</p><div class="code-wrapper"><pre><code class="hljs javascript">价格是: <span class="hljs-number">100</span>$</code></pre></div><p><code>注意</code>:装饰方法时,一定要把<code>descriptor.value</code>做一次保存,这么做的目的是为了装饰的目标方法不被丢失,因为我们重写了方法,这个方法里面可以做一些额为的事,并且在最后要调用那个之前被保存的目标方法,并<code>return</code>掉!</p><p>如果同一个类或者方法有多个装饰器,会像剥洋葱一样,先从外到内进入,然后由内向外执行。</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">dec</span>(<span class="hljs-params">id</span>)</span>{ <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'evaluated'</span>, id); <span class="hljs-keyword">return</span> <span class="hljs-function">(<span class="hljs-params">target, property, descriptor</span>) =></span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'executed'</span>, id);}<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Example</span> </span>{ @dec(<span class="hljs-number">1</span>) @dec(<span class="hljs-number">2</span>) <span class="hljs-function"><span class="hljs-title">method</span>(<span class="hljs-params"></span>)</span>{}}<span class="hljs-comment">// evaluated 1</span><span class="hljs-comment">// evaluated 2</span><span class="hljs-comment">// executed 2</span><span class="hljs-comment">// executed 1</span></code></pre></div><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>装饰器就是给类或方法添加额外功能的!</p><h3 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h3><p>装饰器模式还处于提案过程,没办法在浏览器或node中直接使用,需要用<code>babel</code>转译一次</p><p>安装以下依赖(开发环境即可)</p><div class="code-wrapper"><pre><code class="hljs javascript">@babel/cli@babel/core@babel/preset-env@babel/plugin-proposal-decorators</code></pre></div><p>新建<code>.babelrc</code>文件,添加以下内容</p><div class="code-wrapper"><pre><code class="hljs javascript">{ <span class="hljs-string">"assumptions"</span>: { <span class="hljs-string">"setPublicClassFields"</span>: <span class="hljs-literal">true</span> }, <span class="hljs-string">"plugins"</span>: [ [<span class="hljs-string">"@babel/plugin-proposal-decorators"</span>, { <span class="hljs-string">"legacy"</span>: <span class="hljs-literal">true</span> }], [<span class="hljs-string">"@babel/plugin-proposal-class-properties"</span>] ]}</code></pre></div><p>修改<code>package.json</code>文件</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-string">"scripts"</span>: { <span class="hljs-string">"test"</span>: <span class="hljs-string">"echo \"Error: no test specified\" && exit 1"</span>, + <span class="hljs-string">"build"</span>: <span class="hljs-string">"babel index.js -d dist"</span> },</code></pre></div><p>完成后直接<code>npm run build</code>命令即可</p><p>babel会将index.js文件转译一次,输出到<code>dist</code>文件夹下,直接<code>node</code>dist下的文件就好了</p><p>以上配置只能用与学习,不能用与实际开发中!</p>]]></content>
<tags>
<tag>js设计模式</tag>
</tags>
</entry>
<entry>
<title>原型模式</title>
<link href="/2021/07/20/%E5%8E%9F%E5%9E%8B%E6%A8%A1%E5%BC%8F/"/>
<url>/2021/07/20/%E5%8E%9F%E5%9E%8B%E6%A8%A1%E5%BC%8F/</url>
<content type="html"><![CDATA[<h2 id="原型模式"><a href="#原型模式" class="headerlink" title="原型模式"></a>原型模式</h2><h3 id="作用"><a href="#作用" class="headerlink" title="作用"></a>作用</h3><p>原型模式是为了解决每个对象独占方法的问题,可以使得多个对象公用同一套方法和属性。</p><blockquote><p>事实上,在JAVA中,确实存在原型模式相关的克隆接口规范。但在 JavaScript 中,我们使用原型模式,并不是为了得到一个副本,而是为了得到与构造函数(类)相对应的类型的实例、实现数据/方法的共享。克隆是实现这个目的的方法,但克隆本身并不是我们的目的。 –修言</p></blockquote><h3 id="原型-amp-原型链"><a href="#原型-amp-原型链" class="headerlink" title="原型&原型链"></a>原型&原型链</h3><p>原型编程范式的核心思想就是<strong>用实例来描述对象,用实例作为定义对象和继承的基础</strong>。这离不开原型和原型链。</p><h4 id="原型"><a href="#原型" class="headerlink" title="原型"></a>原型</h4><p>在js中每个构造函数都有一个<code>prototype</code>属性,指向该构造函数的原型对象,而这个原型对象的<code>constructor</code>属性指回构造函数。实例化对象可通过<code>__proto__</code>访问到原型对象。</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">People</span>(<span class="hljs-params">name, age</span>) </span>{<span class="hljs-built_in">this</span>.name = name; <span class="hljs-built_in">this</span>.aage = age;}People.prototype = { <span class="hljs-attr">eat</span>: <span class="hljs-function">() =></span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'吃炒河粉'</span>) }<span class="hljs-keyword">const</span> yxfan = <span class="hljs-keyword">new</span> People(<span class="hljs-string">'yxfan'</span>, <span class="hljs-number">18</span>);yxfan.__proto__.constructor <span class="hljs-comment">// 指回构造函数People</span></code></pre></div><h4 id="原型链"><a href="#原型链" class="headerlink" title="原型链"></a>原型链</h4><p>试试以下的方法</p><div class="code-wrapper"><pre><code class="hljs javascript">yxfan.eat() <span class="hljs-comment">// 输出:吃炒河粉</span></code></pre></div><p>明明yxfan这个对象里面只有<code>name</code>和<code>age</code>属性,并没有<code>eat</code>方法啊,那是哪里来的呢?</p><p>这是因为该实例对象里面没有我们想要的属性/方法,就会去原型对象上找,找到最好,没找到的话就又去原型对象的原型对象上去找。。。</p><p>之所以能这样一层一层的往上找,是因为实例对象通过<code>__proto__</code>将原型对象和原型对象的原型对象串联起来了,这样形成的一条链条就是原型链。</p><h4 id="Object-create"><a href="#Object-create" class="headerlink" title="Object.create"></a>Object.create</h4><p>Object.create方式是原型模式的天然实现</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> people = {<span class="hljs-attr">eat</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{}, <span class="hljs-attr">work</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{}}<span class="hljs-keyword">const</span> man = <span class="hljs-built_in">Object</span>.create(people)<span class="hljs-built_in">console</span>.log(yxfan) <span class="hljs-comment">// {}</span></code></pre></div><p>此时打印出man是一个空对象,因为Object.create方法的第二个参数没有值,便无法设置新对象的属性值。而eat和work方法,可以在新对象的原型上访问到。</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-built_in">console</span>.log(man.__proto__) <span class="hljs-comment">// {eat: ƒ, work: ƒ}</span></code></pre></div><p>我们给Object.create方法设置第二个参数</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> yxfan = <span class="hljs-built_in">Object</span>.create(people, {<span class="hljs-attr">phone</span>: { <span class="hljs-attr">value</span>: <span class="hljs-string">'1303659...'</span>, <span class="hljs-attr">writable</span>:<span class="hljs-literal">true</span>, <span class="hljs-comment">// 可修改的</span> <span class="hljs-attr">enumerable</span>:<span class="hljs-literal">true</span>, <span class="hljs-comment">// 可遍历的</span> <span class="hljs-attr">configurable</span>:<span class="hljs-literal">false</span> <span class="hljs-comment">// 不能修改访问期属性</span> }, <span class="hljs-attr">age</span>: { <span class="hljs-attr">value</span>: <span class="hljs-number">18</span>, <span class="hljs-attr">writable</span>:<span class="hljs-literal">true</span>, <span class="hljs-attr">enumerable</span>:<span class="hljs-literal">true</span>, <span class="hljs-attr">configurable</span>:<span class="hljs-literal">false</span> }});<span class="hljs-built_in">console</span>.log(yxfan) <span class="hljs-comment">// { phone: '1303659...', age: 18 }</span></code></pre></div><p>注意,在设置第二个参数的属性时,是要用访问器属性定义的。</p><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>1、原型模式的核心思想就是用实例来描述对象,用实例来描述对象,用实例来描述对象!!!</p><p>2、原型模式的目的是实现数据/方法的共享</p>]]></content>
<tags>
<tag>js设计模式</tag>
</tags>
</entry>
<entry>
<title>单例模式</title>
<link href="/2021/07/14/%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F/"/>
<url>/2021/07/14/%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F/</url>
<content type="html"><![CDATA[<h3 id="单例模式"><a href="#单例模式" class="headerlink" title="单例模式"></a>单例模式</h3><h4 id="定义"><a href="#定义" class="headerlink" title="定义"></a>定义</h4><p>在单例模式中,一个类只能被实例化一次,即使被实例化(被new)多次,也只返回第一次的实例对象。因此该模式用两个特点:唯一性和全局可访问。</p><h4 id="应用场景"><a href="#应用场景" class="headerlink" title="应用场景"></a>应用场景</h4><p>一般应用于以下场景:</p><ul><li>全局的配置</li><li>全局维护一个状态(vuex,redux)等</li></ul><h4 id="实现一个单例模式"><a href="#实现一个单例模式" class="headerlink" title="实现一个单例模式"></a>实现一个单例模式</h4><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Programmer</span> </span>{<span class="hljs-keyword">static</span> <span class="hljs-function"><span class="hljs-title">getInstance</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-keyword">if</span> (!Programmer.instance) { Programmer.instance = <span class="hljs-keyword">new</span> Programmer(); } <span class="hljs-keyword">return</span> Programmer.instance; } <span class="hljs-function"><span class="hljs-title">coding</span>(<span class="hljs-params"></span>)</span> { .... }}<span class="hljs-keyword">const</span> A = Programmer.getInstance();<span class="hljs-keyword">const</span> B = Programmer.getInstance();A === B <span class="hljs-comment">// true;</span></code></pre></div><p>通过instance来判断Programmer是否曾被实例化过,如果被实例化了就返回之前的对象,反之,则实例化一个新对象,并用instance记录下来。</p><p>通过必包实现:</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ProgrammerBase</span> </span>{}<span class="hljs-keyword">const</span> Programmer = (<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{<span class="hljs-keyword">let</span> instance = <span class="hljs-literal">null</span>; <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{ <span class="hljs-keyword">if</span> (!instance) { instance = <span class="hljs-keyword">new</span> ProgrammerBase(); } <span class="hljs-keyword">return</span> instance; }})();<span class="hljs-keyword">const</span> A = <span class="hljs-keyword">new</span> Programmer();<span class="hljs-keyword">const</span> B = <span class="hljs-keyword">new</span> Programmer();A === B <span class="hljs-comment">// true</span></code></pre></div>]]></content>
<tags>
<tag>js设计模式</tag>
</tags>
</entry>
<entry>
<title>工厂模式</title>
<link href="/2021/07/11/%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F/"/>
<url>/2021/07/11/%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F/</url>
<content type="html"><![CDATA[<h3 id="构造器"><a href="#构造器" class="headerlink" title="构造器"></a>构造器</h3><h4 id="funciton"><a href="#funciton" class="headerlink" title="funciton"></a>funciton</h4><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Student</span>(<span class="hljs-params">name, sex, age</span>) </span>{<span class="hljs-built_in">this</span>.name = name; <span class="hljs-built_in">this</span>.sex = sex; <span class="hljs-built_in">this</span>.age = age;}</code></pre></div><h4 id="class"><a href="#class" class="headerlink" title="class"></a>class</h4><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Student</span> </span>{ <span class="hljs-function"><span class="hljs-title">constructor</span>(<span class="hljs-params">name, sex, age</span>)</span> { <span class="hljs-built_in">this</span>.name = name; <span class="hljs-built_in">this</span>.sex = sex; <span class="hljs-built_in">this</span>.age = age; } <span class="hljs-function"><span class="hljs-title">work</span>(<span class="hljs-params"></span>)</span> { .... }}</code></pre></div><h3 id="简单工厂"><a href="#简单工厂" class="headerlink" title="简单工厂"></a>简单工厂</h3><p>闭上眼想一想什么是工厂模式,工厂怎么理解?</p><p>工厂就好比餐厅的后厨,送进去的是原材料,产出的是一盘盘色香味俱全的菜肴。</p><p>工厂模式里面不一定要用到构造器,它只是一个描述对象创建的过程。</p><p>比如,现在有一个员工的构造函数,它描述了一些共性(name,age),work则是个性</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Personnel</span>(<span class="hljs-params">name, age, work</span>) </span>{<span class="hljs-built_in">this</span>.name = name; <span class="hljs-built_in">this</span>.age = age; <span class="hljs-built_in">this</span>.work = work;}</code></pre></div><p>通过以下的function,将承载共性的Personsonnel类和个性化的逻辑判断写在了一起,我们使用时,直接进行传参就可以了。</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Factory</span>(<span class="hljs-params">name, age, career</span>) </span>{ <span class="hljs-keyword">let</span> work = <span class="hljs-string">''</span>; <span class="hljs-keyword">switch</span>(career) { <span class="hljs-keyword">case</span> <span class="hljs-string">'boss'</span>: work = <span class="hljs-string">'drink tea'</span>; <span class="hljs-keyword">case</span> <span class="hljs-string">'manager'</span>: work = <span class="hljs-string">'rowing water'</span>; <span class="hljs-keyword">case</span> <span class="hljs-string">'programmer'</span>: work = <span class="hljs-string">'coding leet code'</span>; .... } <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Personnel(name, age, work);}</code></pre></div><p>工厂模式其实就是将创建对象的过程单独封装起来了,我们不关心它内部是怎么封装的,只关心它最后的实例结果。</p><h3 id="抽象工厂"><a href="#抽象工厂" class="headerlink" title="抽象工厂"></a>抽象工厂</h3><p>开放封闭原则:对扩展开放,对修改封闭(软件实体:类,模块,函数,只能扩展,不能修改)</p><p>这里以生产笔记本电脑为例</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NoteComputerFactory</span> </span>{<span class="hljs-comment">// 这里提供系统的接口</span> <span class="hljs-function"><span class="hljs-title">createOs</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'抽象工厂方法不能被直接调用,我需要被重写'</span>) } <span class="hljs-comment">// 这里提供硬件接口</span> <span class="hljs-function"><span class="hljs-title">createHardWare</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'抽象工厂方法不能被直接调用,我需要被重写'</span>) }}</code></pre></div><p>上面这个类,就是抽象工厂,只描述了一些通用能力(共性),不允许直接被调用,说白了就是定规矩的。</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-comment">// 具体工厂继承自抽象工厂</span><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SpecificFactory</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">NoteComputerFactory</span> </span>{<span class="hljs-function"><span class="hljs-title">createOs</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> MacOs(); } <span class="hljs-function"><span class="hljs-title">createHardWare</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> HardWare(); }}</code></pre></div><p>上面这个类则是具体工厂,抽象工厂不干活,那就具体工厂来干。</p><p>上述类中,用到了MacOs和HardWare两个构造函数,分别用来生成具体的操作系统和硬件实例。像这种被我们拿来用与new出具体对象的类,叫做具体产品类。我们又可以把具体产品类抽离出共性。比如Mac系统和Android系统都有一个共同的功能:能够操作硬件。因此,可以用抽象产品类来申明这一类产品应该具有的基本功能。</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-comment">// 定义操作系统这类产品的抽象产品类</span><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Os</span> </span>{<span class="hljs-function"><span class="hljs-title">controlOs</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'抽象产品方法不能被直接调用,我需要被重写'</span>); }}<span class="hljs-comment">// 定义具体操作系统的具体产品类</span><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MacOs</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Os</span> </span>{<span class="hljs-function"><span class="hljs-title">controlOs</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'我用Mac的方式操作系统'</span>); }}<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WindowOs</span> <span class="hljs-title">entends</span> <span class="hljs-title">Os</span> </span>{ <span class="hljs-function"><span class="hljs-title">controlOs</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'我用windows的方式操作系统'</span>); }}</code></pre></div><p>这样我们就可以生产一台mac笔记本</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> myMac = <span class="hljs-keyword">new</span> SpecificFactory(); <span class="hljs-comment">// 这是我的mac</span><span class="hljs-keyword">const</span> M1 = myMac.createOs(); <span class="hljs-comment">// 让他拥有操作系统</span>M1.controlOs(); <span class="hljs-comment">// 我用Mac的方式操作系统</span></code></pre></div><p>如果有一天SpecificFactory过气了,要产出新的款式,我们不需要修改抽象工厂NoteComputerFactory,只需扩展它的种类</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NewFactory</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">NoteComputerFactory</span>() </span>{ <span class="hljs-function"><span class="hljs-title">createOs</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-comment">// 操作系统实现代码 } createHardWare() { // 硬件系统实现代码 }}</span></code></pre></div><p>这样,就不会对原有的系统造成潜在的风险,开放封闭就实现了。</p><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>简单工厂和抽象的相同点都是去分隔系统中变与不变的部分。在简单工厂使用场景点,共性更容易抽离。而抽象工厂本质上处理的也是类,这些类又可以划分成等级,我们必须对共性做更特别的处理,使用抽象类降低扩展的成本。同时对类的性质做划分,有了以下四个关键角色:</p><ul><li><p><strong>抽象工厂</strong></p><p>抽象类,不能用于生成具体实例,用与生成最终产品的共性。每一个抽象工厂对应的这一类的产品,被称为产品族。</p></li><li><p><strong>具体工厂</strong></p><p>用与生成产品族中一个具体的产品。它继承自抽象工厂,实现了抽象工厂里的申明的那些方法,用与创建具体产品的类。</p></li><li><p><strong>抽象产品</strong></p><p>抽象类,不能用与生成具体实例。具体工厂里面实现的接口,会依赖一些类,将这些类共性抽离,就得到了抽象产品类。</p></li><li><p><strong>具体产品</strong></p><p>用于生成产品族里的一个具体的产品所依赖的更细粒度的产品。</p></li></ul><p><strong>说白了,抽象工厂的定义就是超级工厂创建创建其他工厂。</strong></p>]]></content>
<tags>
<tag>js设计模式</tag>
</tags>
</entry>
<entry>
<title>视口相关的宽高度</title>
<link href="/2021/01/16/%E8%A7%86%E5%8F%A3%E7%9B%B8%E5%85%B3%E7%9A%84%E5%AE%BD%E9%AB%98%E5%BA%A6/"/>
<url>/2021/01/16/%E8%A7%86%E5%8F%A3%E7%9B%B8%E5%85%B3%E7%9A%84%E5%AE%BD%E9%AB%98%E5%BA%A6/</url>
<content type="html"><![CDATA[<blockquote><p>屏幕的高宽度</p></blockquote><div style="text-align: center; margin-bottom: 20px"> <img src="/images/shikou/screen_width_z.png" style="width:500px;margin: 0 auto;" /></div><blockquote><p>window.innerWidth / innerHeight 浏览器窗口可视区域大小,包括滚动条</p></blockquote><div style="text-align: center; margin-bottom: 20px"> <img src="/images/shikou/inner_width_z.png" style="width:500px;margin: 0 auto;" /></div><blockquote><p>document.documentElement.clientWidth 视口尺寸,不包含滚动条</p></blockquote><div style="text-align: center;margin-bottom: 20px"> <img src="/images/shikou/client_width_z.png" style="width:500px;margin: 0 auto;" /></div><blockquote><p>document.documentElement.offsetWidth / offsetHeight<br><code><html></code> 元素真实尺寸;但是在IE中,表示视口尺寸;</p></blockquote><div style="text-align: center;margin-bottom: 20px"> <img src="/images/shikou/offset_width_z.png" style="width:500px;margin: 0 auto;" /></div><blockquote><p>window.pageXOffset 页面滚动的偏移量</p></blockquote><div style="text-align: center;margin-bottom: 20px"> <img src="/images/shikou/page_offset_z.png" style="width:500px;margin: 0 auto;" /></div><p class="note note-info">参考文章:https://www.quirksmode.org/mobile/viewports.html</p>]]></content>
<tags>
<tag>视口</tag>
<tag>浏览器</tag>
</tags>
</entry>
<entry>
<title>读《代码整洁之道-边界》</title>
<link href="/2021/01/11/%E4%BB%A3%E7%A0%81%E6%95%B4%E6%B4%81%E4%B9%8B%E9%81%93_%E8%BE%B9%E7%95%8C/"/>
<url>/2021/01/11/%E4%BB%A3%E7%A0%81%E6%95%B4%E6%B4%81%E4%B9%8B%E9%81%93_%E8%BE%B9%E7%95%8C/</url>
<content type="html"><![CDATA[<p>最近公司的leader们在组织我们新员工读《代码整洁之道》这本书,希望几年后公司的整体代码质量上升一个新台阶。每人领取一章并分享,而我领的章节是《边界》</p><h3>使用第三方代码</h3><p>在开发中,我们经常要使用第三方API提供的能力,第三方要求广度(普适性),而我们往往只用来满足一些特定的需求(集中性)。</p><p>以ECMAScript 6 中的 MAp 为例。Map有着以下广阔的API和丰富的功能。</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-built_in">Map</span>.prototype.set(key, value);<span class="hljs-built_in">Map</span>.prototype.get(key);<span class="hljs-built_in">Map</span>.prototype.delete(key);<span class="hljs-built_in">Map</span>.prototype.clear();...</code></pre></div><p>简单场景:生成一个Map对象,设置一个键值对,并获取它</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-comment">// 代码一</span><span class="hljs-keyword">const</span> p = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Map</span>();p.set(<span class="hljs-string">'name'</span>, <span class="hljs-string">'yxfan'</span>);p.get(<span class="hljs-string">'name'</span>);<span class="hljs-comment">// 代码二</span><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Person</span> </span>{ <span class="hljs-function"><span class="hljs-title">constructor</span>(<span class="hljs-params"></span>)</span>{ <span class="hljs-built_in">this</span>.person = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Map</span>(); } <span class="hljs-function"><span class="hljs-title">set</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-built_in">this</span>.person.set(<span class="hljs-string">'name'</span>, <span class="hljs-string">'yxfan'</span>); } <span class="hljs-function"><span class="hljs-title">get</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.person.get(<span class="hljs-string">'name'</span>); }}<span class="hljs-keyword">const</span> p = <span class="hljs-keyword">new</span> Person();p.set();p.get(<span class="hljs-string">'name'</span>);</code></pre></div><p>思考:代码一和代码二的区别?代码二有什么好处?<br>代码一的Map提供了太多的可操作空间<br>代码二将丰富的接口隐藏了,只保留了满足特定需求的接口,从而避免了误用<br>就正如书中所说:如果你要使用类似Map这样的边界接口,就把它保留在类或近亲类中。避免从公共API中返回边界接口,或将边界接口作为参数传递给公共API。</p><h3>浏览和学习边界</h3><p>在开发过程中,我们往往都要使用到第三方库。我们没有测试第三方代码的职责,但也要使用第三方代码编写小测试,以此来更好的理解第三方代码,比如写一个echart栗子</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> myChart = echarts.init(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'echart-container'</span>));<span class="hljs-keyword">const</span> option = { <span class="hljs-attr">title</span>: { <span class="hljs-attr">text</span>: <span class="hljs-string">'ECharts 入门示例'</span> }, <span class="hljs-attr">tooltip</span>: {}, <span class="hljs-attr">legend</span>: { <span class="hljs-attr">data</span>: [<span class="hljs-string">'销量'</span>] }, <span class="hljs-attr">xAxis</span>: { <span class="hljs-attr">data</span>: [<span class="hljs-string">"衬衫"</span>, <span class="hljs-string">"羊毛衫"</span>, <span class="hljs-string">"雪纺衫"</span>, <span class="hljs-string">"裤子"</span>, <span class="hljs-string">"高跟鞋"</span>, <span class="hljs-string">"袜子"</span>] }, <span class="hljs-attr">yAxis</span>: {}, <span class="hljs-attr">series</span>: [{ <span class="hljs-attr">name</span>: <span class="hljs-string">'销量'</span>, <span class="hljs-attr">type</span>: <span class="hljs-string">'bar'</span>, <span class="hljs-attr">data</span>: [<span class="hljs-number">5</span>, <span class="hljs-number">20</span>, <span class="hljs-number">36</span>, <span class="hljs-number">10</span>, <span class="hljs-number">10</span>, <span class="hljs-number">20</span>] }]}myChart.setOption(option);</code></pre></div><p>写完这个测试我们就知道怎么去使用echarts了,包括怎么样去初始化和配置它,然后我们就可以按照所学到的知识把echarts封装成一个我们自己的类,这样的它的边界就变成我们想要的样子。</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Echart</span> </span>{ <span class="hljs-function"><span class="hljs-title">constructor</span>(<span class="hljs-params">container</span>)</span> { <span class="hljs-built_in">this</span>.myChart = echarts.init(container); } <span class="hljs-function"><span class="hljs-title">setOption</span>(<span class="hljs-params">option</span>)</span> { <span class="hljs-built_in">this</span>.myChart.setOption(option); } <span class="hljs-function"><span class="hljs-title">clear</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-built_in">this</span>.myChart.clear(); }}<span class="hljs-keyword">const</span> myChart = <span class="hljs-keyword">new</span> Echart(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'echart-container'</span>));myChart.setOption(option);</code></pre></div><h3>设配器模式</h3><p>适配器模式定义:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。<br>在开发中有许多这样的场景:当试图调用模块或者对象的某个接口时,却发现这个接口的格式并不符合目前的需求。这时候有两种解决办法,第一种是修改原来的接口实现,但如果原来的模块很复杂,或者拿到的模块是一段别人编写的经过压缩的代码,修改原接口就显得不太现实了。第二种办法是创建一个适配器,将原接口转换为我们希望的另一个接口,我们只需要和适配器打交道。</p><p>例子1:</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-comment">// 老接口</span><span class="hljs-keyword">const</span> oldStudent = (<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{ <span class="hljs-keyword">return</span> [ { <span class="hljs-attr">name</span>: <span class="hljs-string">'Tom'</span>, <span class="hljs-attr">age</span>: <span class="hljs-number">22</span> }, { <span class="hljs-attr">name</span>: <span class="hljs-string">'yxfan'</span>, <span class="hljs-attr">age</span>: <span class="hljs-number">18</span> } ]})()<span class="hljs-comment">// 期望的新接口是以下形式</span>{ <span class="hljs-attr">Tom</span>: <span class="hljs-number">22</span>, <span class="hljs-attr">yxfan</span>: <span class="hljs-number">18</span>}<span class="hljs-comment">// 采用适配器思想</span><span class="hljs-keyword">const</span> adapter = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">oldStudent</span>) </span>{ <span class="hljs-keyword">const</span> obj = {}; <span class="hljs-keyword">for</span>(<span class="hljs-keyword">let</span> student <span class="hljs-keyword">of</span> oldStudent) { obj[student.name] = student.age; }}<span class="hljs-built_in">console</span>.log(adapter(oldStudent));</code></pre></div><p>例子2:我们要用到Phone这个工具类,但是目前Phone工具类并不符合我们现在的需求,因此我们要创建一个适配器(PhoneAdapter),在原有功能的基础上,添加新功能</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Phone</span> </span>{ <span class="hljs-function"><span class="hljs-title">constructor</span>(<span class="hljs-params">name</span>)</span> { <span class="hljs-built_in">this</span>.phoneName = name; } <span class="hljs-function"><span class="hljs-title">photo</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-built_in">this</span>.phoneName}</span>有拍照功能`</span>); } <span class="hljs-function"><span class="hljs-title">call</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-built_in">this</span>.phoneName}</span>有打电话功能`</span>); }}<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PhoneAdapter</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Phone</span> </span>{ <span class="hljs-function"><span class="hljs-title">constructor</span>(<span class="hljs-params">name</span>)</span> { <span class="hljs-built_in">super</span>(name); } <span class="hljs-function"><span class="hljs-title">batteryCharger</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-built_in">this</span>.phoneName}</span>有充电器`</span>); }}<span class="hljs-keyword">const</span> phone = <span class="hljs-keyword">new</span> PhoneAdapter(<span class="hljs-string">'iphone12'</span>);phone.photo(); <span class="hljs-comment">// iphone12有拍照功能</span>phone.call(); <span class="hljs-comment">// iphone12有打电话功能</span>phone.batteryCharger(); <span class="hljs-comment">// iphone12有充电器</span></code></pre></div><p>优点:<br>1、可以让任何两个没有关联的类一起运行<br>2、提高类的复用性<br>3、灵活性好</p><p>缺点:过多地使用适配器,会让系统非常零乱,不易整体进行把握。<br>适配器模式本质上是一个亡羊补牢的模式,它解决的是现存的两个接口之间不兼容的问题,我们不应该在软件的初期开发阶段就使用该模式;如果在设计之初我们就能够统筹的规划好接口的一致性,那么适配器就应该尽量减少使用。</p><h3>总结</h3>1、学习性测试毫无成本,我们不要在生产代码中试验新东西,而是编写测试来遍历和理解第三方代码,帮助我们对API的理解<p>2、要想边界整洁,不能过多的依靠第三方代码,我们可以通过代码中少数几处引用第三方边界接口的位置来管理第三方边界,免得日后受第三方代码控制<br>3、处理边界问题时,我们可以用新类包装第三方api,用Adapter模式将第三方提供的接口转化为我们自己的接口;</p>]]></content>
<tags>
<tag>书籍</tag>
</tags>
</entry>
<entry>
<title>React不常用的生命周期</title>
<link href="/2020/12/16/React%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F/"/>
<url>/2020/12/16/React%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F/</url>
<content type="html"><![CDATA[<p>React16.3之后的生命周期:<br><img style="margin:0 auto;" src="/images/lifeCycle.png" /><br>几个不常用的生命周期:</p><h4 id="getDerivedStateFromProps-props-state"><a href="#getDerivedStateFromProps-props-state" class="headerlink" title="getDerivedStateFromProps(props, state)"></a>getDerivedStateFromProps(props, state)</h4><blockquote><p>使用场景:在初始化组件数据时,我们想要将组件接收的参数props中的数据添加到组件内部中的state中去, 期望组件响应 props 的变化。</p></blockquote><p>执行过程:该回调会在render之前执行,返回一个对象来更新state,或者返回null,什么也不进行更新。</p><p>栗子:将props中的数据添加到state中去</p><div class="code-wrapper"><pre><code class="hljs javascript">state = { <span class="hljs-attr">c</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">t</span>: <span class="hljs-number">2</span>}<span class="hljs-keyword">static</span> <span class="hljs-function"><span class="hljs-title">getDerivedStateFromProps</span>(<span class="hljs-params">props, state</span>)</span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'变化了111111111'</span>, props, state); <span class="hljs-keyword">return</span> { <span class="hljs-attr">c</span> : props.count } <span class="hljs-comment">// return null 不更新任何内容</span>}</code></pre></div><h4 id="shouldComponentUpdate-nextProps-nextState"><a href="#shouldComponentUpdate-nextProps-nextState" class="headerlink" title="shouldComponentUpdate(nextProps, nextState)"></a>shouldComponentUpdate(nextProps, nextState)</h4><blockquote><p>使用场景:直接决定 React 的组件是否进行更新</p></blockquote><p>无论是与当前的 props 还是与当前的 state 进行比较,最终总是会得出一个 true 或者是 false,来决定组件是否更新(render)。</p><p>栗子:</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-function"><span class="hljs-title">shouldComponentUpdate</span>(<span class="hljs-params">nextProps, nextState</span>)</span> { <span class="hljs-keyword">if</span>(....) { <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>; <span class="hljs-comment">// 不render</span> } <span class="hljs-keyword">else</span> { <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span> <span class="hljs-comment">// 要render</span> }}</code></pre></div><h4 id="getSnapshotBeforeUpdate-prevProps-prevState"><a href="#getSnapshotBeforeUpdate-prevProps-prevState" class="headerlink" title="getSnapshotBeforeUpdate(prevProps, prevState)"></a>getSnapshotBeforeUpdate(prevProps, prevState)</h4><blockquote><p>使用场景: 这个方法能够使得组件可以在可能更改之前从 DOM 捕获一些信息,比如滚动的位置等等。</p></blockquote><p>注意,这个方法的返回值会作为第三个参数,传给<code>componentDidUpdate(nextPros, nextState, snapshot)</code>;<br>该方法必须返回一个值或者是返回null</p><p>栗子:</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ScrollingList</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span> </span>{ <span class="hljs-function"><span class="hljs-title">constructor</span>(<span class="hljs-params">props</span>)</span> { <span class="hljs-built_in">super</span>(props); <span class="hljs-built_in">this</span>.listRef = React.createRef(); } <span class="hljs-function"><span class="hljs-title">getSnapshotBeforeUpdate</span>(<span class="hljs-params">prevProps, prevState</span>)</span> { <span class="hljs-comment">// 捕获滚动的位置,以便后面进行滚动 注意返回的值</span> <span class="hljs-keyword">if</span> (prevProps.list.length < <span class="hljs-built_in">this</span>.props.list.length) { <span class="hljs-keyword">const</span> list = <span class="hljs-built_in">this</span>.listRef.current; <span class="hljs-keyword">return</span> list.scrollHeight - list.scrollTop; } <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>; } <span class="hljs-function"><span class="hljs-title">componentDidUpdate</span>(<span class="hljs-params">prevProps, prevState, snapshot</span>)</span> { <span class="hljs-comment">// 如果有 snapshot 会进行滚动的调整,这样子就不会立即将之前的内容直接弹上去</span> <span class="hljs-keyword">if</span> (snapshot !== <span class="hljs-literal">null</span>) { <span class="hljs-keyword">const</span> list = <span class="hljs-built_in">this</span>.listRef.current; list.scrollTop = list.scrollHeight - snapshot; } } <span class="hljs-function"><span class="hljs-title">render</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-keyword">return</span> ( <span class="xml"><span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{this.listRef}</span>></span>{/* ...contents... */}<span class="hljs-tag"></<span class="hljs-name">div</span>></span></span> ); }}</code></pre></div>]]></content>
<tags>
<tag>React</tag>
</tags>
</entry>
<entry>
<title>Hook</title>
<link href="/2020/09/02/HOOK/"/>
<url>/2020/09/02/HOOK/</url>
<content type="html"><![CDATA[<h3 id="Hook简介"><a href="#Hook简介" class="headerlink" title="Hook简介"></a>Hook简介</h3><p>了解react的同鞋都知道,react组件有两种编写方式,即类组件和函数式组件。<br>函数式组件代码看起来更简洁,但是没有办法维护自身状态,<br>因此Hook的出现可以让我们在不编写class的情况下使用state以及其他的react特性。</p><h3 id="State-Hook"><a href="#State-Hook" class="headerlink" title="State Hook"></a>State Hook</h3><p>useState方法必须要从react中引入,该方法接收一个参数(state的初始值),会返回一个数组,数组中第一个元素是当前状态(state),第二个元素是更新状态的函数</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Example</span>(<span class="hljs-params"></span>) </span>{ <span class="hljs-comment">// 声明一个叫 "count" 的 state 变量 </span> <span class="hljs-keyword">const</span> [count, setCount] = useState(<span class="hljs-number">0</span>); <span class="hljs-keyword">return</span> ( <span class="xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span></span><span class="xml"> <span class="hljs-tag"><<span class="hljs-name">p</span>></span>You clicked {count} times<span class="hljs-tag"></<span class="hljs-name">p</span>></span></span><span class="xml"> <span class="hljs-tag"><<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =></span> setCount(count + 1)}></span><span class="xml"> Click me</span><span class="xml"> <span class="hljs-tag"></<span class="hljs-name">button</span>></span></span><span class="xml"> <span class="hljs-tag"></<span class="hljs-name">div</span>></span></span> );}</code></pre></div><p>我们尝试这把这段代码转化成class写法:</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Example</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span> </span>{ <span class="hljs-function"><span class="hljs-title">constructor</span>(<span class="hljs-params">props</span>)</span> { <span class="hljs-built_in">super</span>(props); <span class="hljs-built_in">this</span>.state = { <span class="hljs-attr">count</span>: <span class="hljs-number">0</span> }; } <span class="hljs-function"><span class="hljs-title">render</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-keyword">return</span> ( <span class="xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span></span><span class="xml"> <span class="hljs-tag"><<span class="hljs-name">p</span>></span>You clicked {this.state.count} times<span class="hljs-tag"></<span class="hljs-name">p</span>></span></span><span class="xml"> <span class="hljs-tag"><<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =></span> this.setState({ count: this.state.count + 1 })}></span><span class="xml"> Click me</span><span class="xml"> <span class="hljs-tag"></<span class="hljs-name">button</span>></span></span><span class="xml"> <span class="hljs-tag"></<span class="hljs-name">div</span>></span></span> ); }}</code></pre></div><p>当我们要声明多个state时:</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> [value, setValue] = useState({ <span class="hljs-attr">valA</span>: <span class="hljs-number">0</span>, <span class="hljs-attr">valB</span>: <span class="hljs-number">1</span>})</code></pre></div><h3 id="Effect-Hook"><a href="#Effect-Hook" class="headerlink" title="Effect Hook"></a>Effect Hook</h3><blockquote><p>useEffect Hook看做<code>componentDidMount</code>,<code>componentDidUpdate</code>和<code>componentWillUnmount</code>这三个函数的组合。</p></blockquote><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">import</span> React, { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Example</span>(<span class="hljs-params"></span>) </span>{ <span class="hljs-keyword">const</span> [count, setCount] = useState(<span class="hljs-number">0</span>); useEffect(<span class="hljs-function">() =></span> { <span class="hljs-built_in">document</span>.title = <span class="hljs-string">`You clicked <span class="hljs-subst">${count}</span> times`</span>; }); <span class="hljs-keyword">return</span> ( <span class="xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span></span><span class="xml"> <span class="hljs-tag"><<span class="hljs-name">p</span>></span>You clicked {count} times<span class="hljs-tag"></<span class="hljs-name">p</span>></span></span><span class="xml"> <span class="hljs-tag"><<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =></span> setCount(count + 1)}></span><span class="xml"> Click me</span><span class="xml"> <span class="hljs-tag"></<span class="hljs-name">button</span>></span></span><span class="xml"> <span class="hljs-tag"></<span class="hljs-name">div</span>></span></span> );}</code></pre></div><p>等价的class写法</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Example</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span> </span>{ <span class="hljs-function"><span class="hljs-title">constructor</span>(<span class="hljs-params">props</span>)</span> { <span class="hljs-built_in">super</span>(props); <span class="hljs-built_in">this</span>.state = { <span class="hljs-attr">count</span>: <span class="hljs-number">0</span> }; } <span class="hljs-function"><span class="hljs-title">componentDidMount</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-built_in">document</span>.title = <span class="hljs-string">`You clicked <span class="hljs-subst">${<span class="hljs-built_in">this</span>.state.count}</span> times`</span>; } <span class="hljs-function"><span class="hljs-title">componentDidUpdate</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-built_in">document</span>.title = <span class="hljs-string">`You clicked <span class="hljs-subst">${<span class="hljs-built_in">this</span>.state.count}</span> times`</span>; } <span class="hljs-function"><span class="hljs-title">render</span>(<span class="hljs-params"></span>)</span> { <span class="hljs-keyword">return</span> ( <span class="xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span></span><span class="xml"> <span class="hljs-tag"><<span class="hljs-name">p</span>></span>You clicked {this.state.count} times<span class="hljs-tag"></<span class="hljs-name">p</span>></span></span><span class="xml"> <span class="hljs-tag"><<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =></span> this.setState({ count: this.state.count + 1 })}></span><span class="xml"> Click me</span><span class="xml"> <span class="hljs-tag"></<span class="hljs-name">button</span>></span></span><span class="xml"> <span class="hljs-tag"></<span class="hljs-name">div</span>></span></span> ); }}</code></pre></div><blockquote><p><strong>useEffect 做了什么?</strong><br>通过使用这个 Hook,你可以告诉 React 组件需要在渲染后执行某些操作。React 会保存你传递的函数(我们将它称之为 “effect”),并且在执行 DOM 更新之后调用它。在这个 effect 中,我们设置了 document 的 title 属性,不过我们也可以执行数据获取或调用其他命令式的 API。</p></blockquote><blockquote><p><strong>为什么在组件内部调用 useEffect?</strong><br>将 useEffect 放在组件内部让我们可以在 effect 中直接访问 count state 变量(或其他 props)。我们不需要特殊的 API 来读取它 —— 它已经保存在函数作用域中。Hook 使用了 JavaScript 的闭包机制,而不用在 JavaScript 已经提供了解决方案的情况下,还引入特定的 React API。</p></blockquote><blockquote><p><strong>useEffect 会在每次渲染后都执行吗?</strong><br>是的,默认情况下,它在第一次渲染之后和每次更新之后都会执行。(我们稍后会谈到如何控制它。)你可能会更容易接受 effect 发生在“渲染之后”这种概念,不用再去考虑“挂载”还是“更新”。React 保证了每次运行 effect 的同时,DOM 都已经更新完毕。</p></blockquote><h4 id="需清楚的effect"><a href="#需清楚的effect" class="headerlink" title="需清楚的effect"></a>需清楚的effect</h4><p>useEffect可以替代生命周期的 <code>componentDidMount</code>,<code>componentDidUpdate</code>和<code>componentWillUnmount</code><br>常常会遇到这种情形:在 componentDidMount 中监听resize事件,那么在组件卸载时,必须移除resize事件</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">import</span> React, {useState, useEffect} <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">UseEffect</span>(<span class="hljs-params"></span>) </span>{ <span class="hljs-keyword">const</span> [count, setCount] = useState(<span class="hljs-number">0</span>); <span class="hljs-keyword">const</span> resize = <span class="hljs-function">() =></span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'窗口改变啦'</span>); } useEffect(<span class="hljs-function">() =></span> { <span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">'resize'</span>, resize) <span class="hljs-keyword">return</span> <span class="hljs-function">() =></span> { <span class="hljs-built_in">window</span>.removeEventListener(<span class="hljs-string">'resize'</span>, resize); } }) <span class="hljs-keyword">return</span> ( <span class="xml"><span class="hljs-tag"><<span class="hljs-name">h2</span>></span></span><span class="xml"> useeffect测试</span><span class="xml"> <span class="hljs-tag"></<span class="hljs-name">h2</span>></span></span> )}<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> UseEffect</code></pre></div><p>等价的class组件</p><div class="code-wrapper"><pre><code class="hljs javascript">resize = <span class="hljs-function">() =></span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'窗口改变啦'</span>);}<span class="hljs-function"><span class="hljs-title">componentDidMount</span>(<span class="hljs-params"></span>)</span>{ <span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">'resize'</span>,<span class="hljs-built_in">this</span>.resize)}<span class="hljs-function"><span class="hljs-title">componentWillUnmount</span>(<span class="hljs-params"></span>)</span>{ <span class="hljs-built_in">window</span>.removeEventListener(<span class="hljs-string">'resize'</span>, resize);}</code></pre></div><p>这里useEffect方法中的参数(箭头函数)里返回了一个函数,这就是effect的清除机制</p><blockquote><p><strong>为什么要在 effect 中返回一个函数?</strong><br>这是 effect 可选的清除机制。每个 effect 都可以返回一个清除函数。如此可以将添加和移除订阅的逻辑放在一起。它们都属于 effect 的一部分。</p></blockquote><blockquote><p><strong>React 何时清除 effect?</strong><br> React 会在组件卸载的时候执行清除操作。正如之前学到的,effect 在每次渲染的时候都会执行。这就是为什么 React 会在执行当前 effect 之前对上一个 effect 进行清除。我们稍后将讨论为什么这将助于避免 bug以及如何在遇到性能问题时跳过此行为。</p></blockquote><h4 id="跳过Effect进行性能优化"><a href="#跳过Effect进行性能优化" class="headerlink" title="跳过Effect进行性能优化"></a>跳过Effect进行性能优化</h4><p>因为useEffect会在每次更新渲染后执行,着就会导致一个性能问题。在 class 组件中,我们可以通过在 componentDidUpdate 中添加对 prevProps 或 prevState 的比较逻辑解决:</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-function"><span class="hljs-title">componentDidUpdate</span>(<span class="hljs-params">prevProps, prevState</span>)</span> { <span class="hljs-keyword">if</span> (prevState.count !== <span class="hljs-built_in">this</span>.state.count) { <span class="hljs-built_in">document</span>.title = <span class="hljs-string">`You clicked <span class="hljs-subst">${<span class="hljs-built_in">this</span>.state.count}</span> times`</span>; }}</code></pre></div><p>只有在state中的count改变时,才修改document的title<br>在hook中实现:</p><div class="code-wrapper"><pre><code class="hljs javascript">useEffect(<span class="hljs-function">() =></span> { <span class="hljs-built_in">document</span>.title = <span class="hljs-string">`You clicked <span class="hljs-subst">${count}</span> times`</span>;}, [count]); <span class="hljs-comment">// 仅在 count 更改时更新</span></code></pre></div><p>上面这个示例中,我们传入 [count] 作为第二个参数。这个参数是什么作用呢?如果 count 的值是 5,而且我们的组件重渲染的时候 count 还是等于 5,React 将对前一次渲染的 [5] 和后一次渲染的 [5] 进行比较。因为数组中的所有元素都是相等的(5 === 5),React 会跳过这个 effect,这就实现了性能的优化。</p><h3 id="useMemo-amp-memo"><a href="#useMemo-amp-memo" class="headerlink" title="useMemo & memo"></a>useMemo & memo</h3><p><code>useMemo()</code>和<code>memo</code>方法总是让我有点分不清楚</p><ul><li><code>memo()</code>指的是一个组件是否重复渲染,可以优化性能</li><li><code>useMemo()</code>指的是一段函数逻辑是否重复执行</li></ul><h4 id="memo"><a href="#memo" class="headerlink" title="memo"></a>memo</h4><p>父组件:</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Father</span>(<span class="hljs-params"></span>) </span>{ <span class="hljs-keyword">const</span> [count, setCount] = useState(<span class="hljs-number">0</span>); <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">add</span>(<span class="hljs-params"></span>)</span>{ setCount(count + <span class="hljs-number">1</span>) } <span class="hljs-keyword">return</span> ( <span class="xml"><span class="hljs-tag"><></span></span><span class="xml"> 父组件:计数:{count}</span><span class="xml"> <span class="hljs-tag"><<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{add}</span>></span>加一<span class="hljs-tag"></<span class="hljs-name">button</span>></span> <span class="hljs-tag"><<span class="hljs-name">br</span>/></span></span><span class="xml"> <span class="hljs-tag"><<span class="hljs-name">Son</span> /></span></span><span class="xml"> <span class="hljs-tag"></></span></span> )}<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Father</code></pre></div><p>子组件:</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">import</span> React, { memo, useMemo } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;<span class="hljs-keyword">const</span> Son = memo(<span class="hljs-function">(<span class="hljs-params">prop</span>) =></span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'子组件渲染了'</span>); <span class="hljs-keyword">return</span> ( <span class="xml"><span class="hljs-tag"><></span> </span><span class="xml"> 这是子组件</span><span class="xml"> <span class="hljs-tag"></></span></span> )})<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Son</code></pre></div><p>效果:点击加一按钮,控制台没有输出,因为子组件没有重复渲染</p><blockquote><p>分析:正常情况下,父组件中的state改变了,会引起re-render,不管子组件有没有依赖父组件的状态,都会被re-render,<br> 但是这里用了memo()方法,子组件不依赖于父组件的状态,即使父组件状态更新了,子组件也能保持不变,不用重复渲染,因此节约性能</p></blockquote><h4 id="useMemo"><a href="#useMemo" class="headerlink" title="useMemo"></a>useMemo</h4><p>父组件:</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Father</span>(<span class="hljs-params"></span>) </span>{ <span class="hljs-keyword">const</span> [count, setCount] = useState(<span class="hljs-number">0</span>); <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">add</span>(<span class="hljs-params"></span>)</span>{ setCount(count + <span class="hljs-number">1</span>) } <span class="hljs-keyword">return</span> ( <span class="xml"><span class="hljs-tag"><></span></span><span class="xml"> 父组件:计数:{count}</span><span class="xml"> <span class="hljs-tag"><<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{add}</span>></span>加一<span class="hljs-tag"></<span class="hljs-name">button</span>></span> <span class="hljs-tag"><<span class="hljs-name">br</span>/></span></span><span class="xml"> <span class="hljs-tag"><<span class="hljs-name">Son</span> <span class="hljs-attr">count</span>=<span class="hljs-string">{count}/</span>></span></span><span class="xml"> <span class="hljs-tag"></></span></span> )}<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Father</code></pre></div><p>子组件:</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">import</span> React, { memo, useMemo } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;<span class="hljs-keyword">const</span> Son = memo(<span class="hljs-function">(<span class="hljs-params">prop</span>) =></span> {<span class="hljs-keyword">const</span> [anotherCount, setAnotherCount] = useState(<span class="hljs-number">0</span>); <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'子组件渲染了'</span>);<span class="hljs-keyword">const</span> useMemoTest = useMemo(<span class="hljs-function">() =></span> {<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'useMemo方法执行了'</span>)}, [anotherCount]) <span class="hljs-keyword">return</span> ( <span class="xml"><span class="hljs-tag"><></span> </span><span class="xml"> 这是子组件{useMemoTest()}</span><span class="xml"> <span class="hljs-tag"></></span></span> )})<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Son</code></pre></div><p>效果:点击加一按钮,控制台输出:’子组件渲染了’</p><blockquote><p>分析:子组件依赖了父组件的count,所以父组件的count改变时,引起子组件的re-render;<br> 正常情况re-render会调用useMemoTest()方法,但是却没有打印信息;<br> 因为这里用了useMemo()方法,它只有在第二个参数[anotherCount]改变时,才执行useMemoTest()</p></blockquote>]]></content>
<tags>
<tag>React</tag>
</tags>
</entry>
<entry>
<title>雏鹰起飞</title>
<link href="/2020/08/09/%E9%9B%8F%E9%B9%B0%E9%AB%98%E9%A3%9E/"/>
<url>/2020/08/09/%E9%9B%8F%E9%B9%B0%E9%AB%98%E9%A3%9E/</url>
<content type="html"><![CDATA[<h3 id="记2020年7月15日-7月24日深圳培训"><a href="#记2020年7月15日-7月24日深圳培训" class="headerlink" title="记2020年7月15日~7月24日深圳培训"></a>记2020年7月15日~7月24日深圳培训</h3><h4 id="以下视频密码均为2020"><a href="#以下视频密码均为2020" class="headerlink" title="以下视频密码均为2020"></a>以下视频密码均为2020</h4><h3>2020年的夏天</h3>从校园到职场,从学生到职场人,这个夏天不一般也更加值得纪念。一百多人从国内各个地方、海外留学而来,因为锐明,我们相聚深圳。我万万没想到居然能在毕业之际,再次穿上迷彩服,过一把“军训的瘾”。睡着上下铺,卡着时间点叫室友下楼集合,就如同时光倒退,回到了大一!<div style="width:90%;height: 400px;margin: 0 auto"><iframe style="height:100%;width:100%" src='https://player.youku.com/embed/XNDc3MDk2ODQ5Ng=='></iframe></div>结营那天晚上,玩得很嗨,每人一份半糖冰奶茶,零食管够。每个拓展小组要出一个节目,我们这组出的情景喜剧“Love”。没错,我就在最后面和队友们群魔乱舞<div style="width:90%;height: 400px;margin: 0 auto"><iframe style="height:100%;width:100%" src='https://player.youku.com/embed/XNDc4ODk2MTE4NA=='></iframe></div>这是那天晚上最让我感到惊喜的一个节目:过7月集体生日。因为我是阴历5月的生日,所以我就准备在台下“看好戏”,没想到突然教叫到我的名字,这才意识到入职时我填的是7月,就是喜欢突然被cue。<div style="width:90%;height: 400px;margin: 0 auto"><iframe style="height:100%;width:100%" src='https://player.youku.com/embed/XNDc4ODk1MzkzMg=='></iframe></div>]]></content>
<tags>
<tag>杂记</tag>
</tags>
</entry>
<entry>
<title>历经千帆,归来少年</title>
<link href="/2020/08/09/%E5%8E%86%E7%BB%8F%E5%8D%83%E5%B8%86%EF%BC%8C%E5%BD%92%E6%9D%A5%E5%B0%91%E5%B9%B4/"/>
<url>/2020/08/09/%E5%8E%86%E7%BB%8F%E5%8D%83%E5%B8%86%EF%BC%8C%E5%BD%92%E6%9D%A5%E5%B0%91%E5%B9%B4/</url>
<content type="html"><![CDATA[<p>毕业,就像一个大大的句号,从此,我们告别了一段纯真的青春,一段年少轻狂的岁月,一个充满幻想的时代……<br>回顾四年大学生活,从开始的新鲜兴奋,到中间的迷茫徘徊,又到突然的觉醒,再到最后的来回奔波,这其中的感觉,汇聚一起,慢慢发酵,变成一种历久弥新,醇香的味道。毕业的当下,谈起毕业,不可避免的略带伤感。这伤感,不仅有感叹时间的飞逝,也有离愁别绪,更有青春的无奈蹉跎。大学生活,收获了什么,改变了什么,又失去了什么,所有的体会都在毕业的当下,变得浓烈而澎湃。</p><h3 id="壹"><a href="#壹" class="headerlink" title="壹"></a>壹</h3><p>大一是青涩的,初进校园,一切都是新鲜的,好奇的。班级,学生会,社团我一个不落。还记得当初在文艺部时,和129合唱队队员们一起在寒冷的黑夜中开嗓;还记得为了低御寒冷,和室友在开水房排了半个小时队,只为给合唱队队员们递上一杯热水;还记得当时运气感爆棚,和队友获得了理工杯羽毛球男子双打三等奖,这一切的一起,历历在目,恍如昨日。</p><h3 id="叁"><a href="#叁" class="headerlink" title="叁"></a>叁</h3><p>大三是充实的,这一年,没有了大一大二的轻狂和激动,更多开始思考和规划自己的人生。这一年,我有幸成为了一名班主任助理,带着师弟师妹们一起熟悉校园,和他们一起成长。</p><p>也是在这一年,我光荣的成为了一名中共预备党员,对个人的人生理想和发展目标,有了相对成熟的认识和定位。</p><h3 id="肆"><a href="#肆" class="headerlink" title="肆"></a>肆</h3><p>大四是忙碌的,要在找工作实习的同时,兼顾学校的各项工作安排,经常两座城市来回跑,在外面呆久了,回到最熟悉的校园,心中是止不住的激动和喜悦。<br>尚未佩妥剑,转眼便江湖,大学四年马上就要结束了,在这四年的学习生活中,我学习到了很多知识,专业知识方面更是有了很大的提高,在大学的这一段时光将是我这一生当中最宝贵的财富,是不断超越自我的历程。在这最后的阶段,我衷心的向各位老师和我的同学表示我最衷心的感谢,感谢他们在这四年当中对我的帮助和关心。</p><p>我期待遇见一个更好的自己、也期待在以后的日子可以遇见一个更好的你们。</p><div style="width:90%;height: 400px;margin: 0 auto"><iframe style="height:100%;width:100%" src='https://player.youku.com/embed/XNDc4ODk2ODkzMg=='></iframe></div>]]></content>
<tags>
<tag>杂记</tag>
</tags>
</entry>
<entry>
<title>Promise</title>
<link href="/2020/08/05/Promise/"/>
<url>/2020/08/05/Promise/</url>
<content type="html"><![CDATA[<h3 id="Promise三种状态"><a href="#Promise三种状态" class="headerlink" title="Promise三种状态"></a>Promise三种状态</h3><ol><li><p><code>pending</code>: 未解决,当调用任意一个任务函数时,暂时处于pending状态,是不会去执行下一个任务的。</p></li><li><p><code>resolve</code>: 当前任务执行完,且执行成功,任务函数内部会手动调用resolve()函数。Promise对象会将任务的状态改为resolve状态。死循环发现状态变为resolve,则自动i++,找到集合中排在当前位移的下一个位置的任务函数执行。并在此将状态改为pending。直到当前任务执行完,才判断是否可以继续。</p></li><li><p><code>reject</code>: 如果当前任务执行过程中出错了,无法继续向后执行,则任务函数中会先手动调用reject()函数。Promise对象将任务的状态转为reject。死循环发现任务的状态变为reject,则不再继续循环,而是退出循环,执行最后一个catch的内容。</p></li></ol><h3 id="then的作用"><a href="#then的作用" class="headerlink" title=".then的作用"></a>.then的作用</h3><p>then不是调用函数的意思,是收集后面任务的作用。</p><p>一边收集后面的函数,一边调用第一个函数。</p><p>利用状态机制来顺序执行任务<br><img src="/images/promise/promise.jpg" style="width:80%;margin: 0 auto;" /><br>执行过程是由状态来决定的:</p><blockquote><ol><li>当调用第一个函数时,状态为pending,(我在执行着呢,后面两个函数给我等着)</li><li>第一个函数执行完,调用door(resolve)函数(相当于只改变了状态),状态从pending变为fulfilled(办妥 了,解决了)或者resolve (解决)</li><li>执行第二个ran函数,状态迅速从fulfilled改为pending,当ran里面调door(resolve)时,状态由pending改为fulfilled,接着调用第三个函数</li><li>在执行函数中,有第二个门 reject,通常用于报告错误用的,reject里面包含错误信息(实参),并传递给catch里面的函数的形参e接收,后续的函数不执行</li></ol></blockquote><h3 id="常用的Promise"><a href="#常用的Promise" class="headerlink" title="常用的Promise"></a>常用的Promise</h3><h4 id="Promise-all"><a href="#Promise-all" class="headerlink" title="Promise.all()"></a>Promise.all()</h4><p>多个异步任务同时执行,不必按顺序执行</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-built_in">Promise</span>.all([work1(), work2(), work3()]).then(....)</code></pre></div><h4 id="Promise-race"><a href="#Promise-race" class="headerlink" title="Promise.race()"></a>Promise.race()</h4><p>该方法同样是将多个Promise实例包装成一个新的Promise实例</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> p = <span class="hljs-built_in">Promise</span>.race([p1, p2, p3]);</code></pre></div><p>上面代码中,只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。</p><p>栗子:</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> p = <span class="hljs-built_in">Promise</span>.race([ fetch(<span class="hljs-string">'/resource-that-may-take-a-while'</span>), <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">resolve, reject</span>) </span>{ <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =></span> reject(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'request timeout'</span>)), <span class="hljs-number">5000</span>) })]);p.then(<span class="hljs-built_in">console</span>.log).catch(<span class="hljs-built_in">console</span>.error);</code></pre></div><p>上面代码中,如果 5 秒之内fetch方法无法返回结果,变量p的状态就会变为rejected,从而触发catch方法指定的回调函数。</p>]]></content>
<tags>
<tag>js</tag>
<tag>Promise</tag>
</tags>
</entry>
<entry>
<title>Linux之文件权限与目录管理</title>
<link href="/2020/08/04/Linux%E4%B9%8B%E6%96%87%E4%BB%B6%E6%9D%83%E9%99%90%E4%B8%8E%E7%9B%AE%E5%BD%95%E9%85%8D%E7%BD%AE/"/>
<url>/2020/08/04/Linux%E4%B9%8B%E6%96%87%E4%BB%B6%E6%9D%83%E9%99%90%E4%B8%8E%E7%9B%AE%E5%BD%95%E9%85%8D%E7%BD%AE/</url>
<content type="html"><![CDATA[<h2 id="文件全权限与目录配置"><a href="#文件全权限与目录配置" class="headerlink" title="文件全权限与目录配置"></a>文件全权限与目录配置</h2><p>此篇文章是由思维导图转换而成,只是想单纯的试验一下这个转换功能,嘻嘻🤭。</p><p><a href="/images/linux/Linux.xmind" download="Linux.xmind">❤点击我下载脑图</a></p><h3 id="任何一个文件都有三种身份的个别权限"><a href="#任何一个文件都有三种身份的个别权限" class="headerlink" title="任何一个文件都有三种身份的个别权限"></a>任何一个文件都有三种身份的个别权限</h3><ul><li><p>User:文件拥有者</p><p>Linux是多人多任务的系统,常常会有很多人同时使用这部主机来进行工作,考虑到隐私权,只有文件拥有着才能看与修改这个文件。</p></li><li><p>Group:群组</p><p>经过简易的文件权限设定,就能限制非自己团队的其他人不能阅览文件,自己的团队成员可以阅览和修改。如果还有私人文件,还可以设定为团队成员看不到的文件数据</p><p>相当于:一个家里面有很多个卧室,只有自己家人能进家里的客厅和卧室,别人是不能进入的。这个家就是个群组。</p></li><li><p>Others:其他人</p></li></ul><h3 id="文件权限"><a href="#文件权限" class="headerlink" title="文件权限"></a>文件权限</h3><ul><li><p>Linux文件属性</p><p>先【su - 】指令切换身份成root,再下达【ls -al】指令;</p><div class="code-wrapper"><pre><code> 如有一个文件的类型与权限数据为:【-rwxr-xr--】 先将整个类型与数据分开查阅,整理十个字符 [-] [rwx] [r-x] [r--] 1 234 567 890</code></pre></div><p>1:代表这个文件的类型:</p><div class="code-wrapper"><pre><code> [d] 则为目录 [-] 则是文件 [l] 则是连结档 [b] 可供存储的接口设备 [c] 串行端口设备,键盘鼠标等</code></pre></div><p>234:拥有者的权限,本例中是可读可写可执行;<br>567:群组的权限,本例中是可读可执行;<br>890:其他用户权限,本例中是可读;</p></li><li><p>文件权限的重要性</p><ul><li>系统保护功能</li><li>团队开发软件或数据共享功能</li></ul></li><li><p>改变文件属性与权限</p><ul><li><p>改表所属群组:【chgrp】</p><p>【chgrp users 文件名】<br>将文件名所在的群组修改成 users</p></li><li><p>改变文件拥有者:【chown】</p><p>【chown -[R] 账号名称 文件或目录】<br>【chown -[R] 账号名称:组名 文件或目录】</p><p>栗子:将test.cfg的拥有着改为bin这个账号<br>【chown bin test.cfg】</p><p>将teest.cfg的拥有者和群组改回root<br>【chown root:root test.cfg】</p></li><li><p>改变文件权限:【chmod】</p><p>改变权限的方式有两种:数字和符号</p><div class="code-wrapper"><pre><code> 1.数字类型改变文件权限: r:4;w:2;x:1;</code></pre></div><p>每种身份的三个权限分数需要相加,栗如:【-rwxrwx—】分数是:<br>owner = rwx = 4+2+1 = 7;<br>group = rwx = 4 +2 + 1 = 7;<br>others = — = 0 + 0 + 0 = 0;<br>更改语法:<br>【chmod [-R] 分值 文件或目录】<br>如果要将.bashrc这个文件设定为启用,下达:【chmod 777 .bashrc】</p><div class="code-wrapper"><pre><code> 2.符号类型改变文件权限</code></pre></div><p>九个权限分别是:user,group,others三种身份,可以用:u,g,o来代表三种身份的权限,此外a代表all,即全部的身份。<br>1.设定一个文件权限是(用=号):【-rwxr-xr-x】<br>【chmod u=rwx,go=rx .bashrc】<br>2.增加文件权限(用+号):原权限:【-rwxr-xr-x】,<br>执行:【chmod a+w .bashrc】<br>权限更改为:【-rwxrwxrwx】<br>3.去掉权限(用-号):原权限 【-rwxrwxrwx】<br>执行:【chmod a-w .bashrc】<br>权限更改为:【-r-xr-xr-x】</p></li></ul></li><li><p>Linux文件种类与扩展名</p><ul><li><p>文件种类</p><ul><li><p>正规文件</p><p>就是一般我们在进行存取的类型的文件,在由 【ls -al】所显示出来的属性方面,第一个字符为【-】,比如:【-rwxrwx-rwx】</p><ul><li>纯文本文档(ASCII)</li><li>二进制文件(binary)</li><li>数据格式文件(data)</li></ul></li><li><p>目录</p></li><li><p>连结档</p><p>类似于Windows系统底下的快捷方式,第一个属性为【l】例如:【lrwxrwxrwx】</p></li><li><p>设备与装置文件</p><ul><li><p>区块设备档</p><p>第一个属性为:【b】。一些存储数据,以提供系统随机存取的接口设备。比如:硬盘与软盘!</p></li><li><p>字符设备文件</p><p>第一个属性为:【c】;一些串行端口的接口设备,比如键盘、鼠标等。这些设备的特色就是一次性读取,不能截断输出。你不能让鼠标跳到另一个画面,而是连续性滑动到另一个地方。</p></li></ul></li><li><p>资料接口文件</p><p>第一个属性为【s】;这种类型文件通常被用在网络上的数据承接。</p></li><li><p>数据输送文件</p><p>第一个属性是:【p】;他主要的目的是在解决多个程序的同时存取一个文件所造成的错误问题。</p></li></ul></li><li><p>文件扩展</p><ul><li><p>.sh</p><ul><li>脚本或处理文件</li></ul></li><li><p>*Z, *.tar, *.zip, *.tgz</p><ul><li>经过打包的压缩文件</li></ul></li><li><p>*.html, *.php </p><ul><li>网页相关的文件</li></ul></li></ul></li></ul></li></ul><h3 id="目录配置"><a href="#目录配置" class="headerlink" title="目录配置"></a>目录配置</h3><ul><li><p>FHS要求必须要存在的目录</p><ul><li><p>/bin</p><p>/bin放置的是单人维护模式下还能被操作的指令。在/bin底下的指令可以被root与一般账号所使用,主要有cat、chmod、chown、date、mv、mkdir、cp、bash等指令</p></li><li><p>/boot</p><p>主要放置开机会使用到的文件</p></li><li><p>/dev</p><p>任何接装置与接口设备都是以文件的型态存在与这个目录的;只要透过存取这个目录底下的的某个文件,就等于存取某个装置了</p></li><li><p>/etc</p><p>系统主要的配置文件都放置在这个目录,比如人员的账号密码文件、各种服务的启始档</p></li><li><p>/lib</p><p>放置的是系统开机时会用到的函数库</p></li><li><p>/media</p><p>放置的是可移除的装置,包括软盘、光盘、DVD</p></li><li><p>/mnt</p></li><li><p>/opt</p></li><li><p>/run</p></li><li><p>/sbin</p></li><li><p>/srv</p><p>一些网络服务启动之后,这些服务要采取的数据目录</p></li><li><p>/tmp</p><p>让一般用户或者正在执行的程序暂时存放文件的地方。这个目录是任何人都能存取的。重要数据不能放在这儿。</p></li><li><p>/usr</p></li><li><p>/var</p></li></ul></li><li><p>FHS建议可以存在的目录</p><ul><li><p>/home</p><p>系统默认的用户家目录。在新增一个一般使用者账号时,默认的用户家目录都会规范到这里来。家目录有两种代号:<br>1、 ~:代表目前这个用户的家目录<br>2、 ~dmtsai:代表dmtsai的家目录</p></li><li><p>/lib<qual></p></li><li><p>/root</p></li></ul></li><li><p>目录树</p></li><li><p>绝对路径与相对路径</p><ul><li><p>绝对路径</p><ul><li>以根目录开始写起:/home/dmtsai/.bashrc</li></ul></li><li><p>相对路径</p><ul><li>例如:./dmtsai</li></ul></li></ul></li></ul><h2 id="Linux文件与目录管理"><a href="#Linux文件与目录管理" class="headerlink" title="Linux文件与目录管理"></a>Linux文件与目录管理</h2><h3 id="目录与路径"><a href="#目录与路径" class="headerlink" title="目录与路径"></a>目录与路径</h3><ul><li><p>常见的处理目录指令</p><ul><li><p>【cd】变化目录</p></li><li><p>【pwd】显示当前目录</p></li><li><p>【mkdir】建立一个新的目录</p></li><li><p>【rmdir】删除一个空的目录</p><p>注意:rmdir只能删除空目录<br>如果想要目录的所有东西都杀掉,用【rm -r test】</p></li></ul></li></ul><h3 id="文件与目录管理"><a href="#文件与目录管理" class="headerlink" title="文件与目录管理"></a>文件与目录管理</h3><ul><li>【ls】文件与目录的检视</li><li>【cp】,【rm】,【mv】复制、删除与移动</li></ul>]]></content>
<tags>
<tag>Linux</tag>
</tags>
</entry>
<entry>
<title>Linux</title>
<link href="/2020/07/11/Linux/"/>
<url>/2020/07/11/Linux/</url>
<content type="html"><![CDATA[<h3 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h3><p>今年因为疫情的影响,找工作似乎没有往年那么轻松(往年轻不轻松咱也不知道啊,毕竟没找过哈哈)。我们应届毕业生也面临着不小的压力,幸运的是,我经过一轮笔试,四轮面试终于被一家我自认为还比较满意的公司录取了。截至目前已经报道一个月了,其中有件事我,印象特别深刻。有一次把前端程序打包丢给后端部署在Linux服务器上,奈何项目怎么也启动不起来,为了排错,后端让我去Linux服务器上看日志,我当时就懵了,寻思着这操作我也没整过啊,急忙向导师求助,只见他三下五除二的功夫就将问题解决了。他告诉我:“早期程序员是不分前后端的,不要把自己局限在前端上,什么东西都要去接触一点,不然就只做前端这点事,以后会没饭吃的!” 我下来仔细一寻思,也确实是这么回事,所以近期的目标就放在了Linux身上。</p><h3 id="应用场景"><a href="#应用场景" class="headerlink" title="应用场景"></a>应用场景</h3><h4 id="企业环境应用"><a href="#企业环境应用" class="headerlink" title="企业环境应用"></a>企业环境应用</h4><h5 id="网络服务器"><a href="#网络服务器" class="headerlink" title="网络服务器"></a>网络服务器</h5><p>这是Linux当前最热门的应用!Linux上面的网络功能特别的稳定与强大!此外,由于GNU计划与Linux的GPL授权模式,让很多的优秀软件在Linux上面发展,且这些在Linux上面的服务器软件几乎都是自由软件。因此,作为一部网络服务器,Linux绝对是上上之选,这也是Linux的强项。</p><h5 id="金融数据库、大型企业网管环境"><a href="#金融数据库、大型企业网管环境" class="headerlink" title="金融数据库、大型企业网管环境"></a>金融数据库、大型企业网管环境</h5><p>目前很多金融业界都已经使用Linux来作为他们的关键任务应用。关键任务应用就是最重要的业务,比如投资者的账户数据,这些数据大都使用数据库系统来作为存取接口。很多金融业都把这么重要的任务交给Linux了。</p><h5 id="学术机构的高效能运算任务"><a href="#学术机构的高效能运算任务" class="headerlink" title="学术机构的高效能运算任务"></a>学术机构的高效能运算任务</h5><p>由于学术机构的研究通常要自行开发软件,对开发环境的操作系统需求非常迫切。由于Linux的创造者本身就是个性能癖,所以Linux有强大的运算能力,并且Linux具有支持度相当广泛的GCC编译软件,因此Linux在这方面的优势相当明显。</p><h4 id="个人环境应用"><a href="#个人环境应用" class="headerlink" title="个人环境应用"></a>个人环境应用</h4><p>个人环境的应用主要分三个方面:</p><ul><li>桌面计算机</li><li>手持系统(PDA,手机)<br>Android其实就是Linux核心的一支;<br>现在手机的主流操作系统是Linux分支出来的Andriod;</li><li>嵌入式系统<br>操作系统直接嵌入到产品中,用户不应该主动更改这个操作系统</li></ul><h4 id="云端应用"><a href="#云端应用" class="headerlink" title="云端应用"></a>云端应用</h4><p>分为两个方面:</p><ul><li>云程序<br> 云程序的底层就是Linux,而云程序搭建出来的虚拟机,内容也是Linux操作系统;<br> 虚拟机指的就是在一部实体主机上面仿真出多个逻辑上完全独立的硬件,这些硬件可以安装一部逻辑完全独立的操作系统;</li><li>端设备</li></ul><p><a href="/images/linux/Linux.png" download="Linux.png">❤点击我下载图片</a></p><img src="/images/linux/Linux.png" style="width:100%;margin: 0 auto;" />]]></content>
<tags>
<tag>Linux</tag>
</tags>
</entry>
<entry>
<title>this指向</title>
<link href="/2020/06/15/this%E6%8C%87%E5%90%91/"/>
<url>/2020/06/15/this%E6%8C%87%E5%90%91/</url>
<content type="html"><![CDATA[<p>this在开发中的重要性这里就不说了,咱们直接来讨论出现this的几种情形</p><ul><li>obj.fun()<br>fun函数中的this指向调用者obj</li><li> fun() 或 (function(){ … })() 或 setTimeout(function(){ … }, ms)<br>里面的this指向window</li><li> new Fun()<br>this指向正在创建的对象</li><li> arr.forEach/map(() => {this})<br>这里面不管是普通函数还是箭头函数this都指向window</li><li>btn.onclick=function(){ this->btn }<div class="code-wrapper"><pre><code>btn.addEventListener("click",function(){ this->btn })$btn.on("click",function(){ this->btn })$btn.click(function(){ this->btn })</code></pre></div></li><li>Array.prototype.sum=function(){this}<br>this->将来调用sum的.前的数组家子对象</li><li>只要new Vue中的this,一律指向当前的new Vue对象</li></ul><p>这样直接看概念可能有点晦涩,这里上一个例子</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">var</span> name = <span class="hljs-string">'window'</span><span class="hljs-keyword">var</span> person1 = { <span class="hljs-attr">name</span>: <span class="hljs-string">'person1'</span>, <span class="hljs-attr">show1</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{ <span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">this</span>.name) }, <span class="hljs-attr">show2</span>: <span class="hljs-function">() =></span> <span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">this</span>.name), <span class="hljs-attr">show3</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{ <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{ <span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">this</span>.name) } }, <span class="hljs-attr">show4</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{ <span class="hljs-comment">// console.log(this)</span> <span class="hljs-keyword">return</span> <span class="hljs-function">() =></span> <span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">this</span>.name) }}<span class="hljs-keyword">var</span> person2 = { <span class="hljs-attr">name</span>: <span class="hljs-string">'person2'</span> }person1.show1() <span class="hljs-comment">// person1</span>person1.show1.call(person2) <span class="hljs-comment">//person2</span>person1.show2() <span class="hljs-comment">// window</span>person1.show2.call(person2) <span class="hljs-comment">// window </span>person1.show3()() <span class="hljs-comment">// window</span>person1.show3().call(person2) <span class="hljs-comment">// person2</span>person1.show3.call(person2)() <span class="hljs-comment">// window</span>person1.show4()() <span class="hljs-comment">// person1</span>person1.show4().call(person2) <span class="hljs-comment">// person1 </span>person1.show4.call(person2)() <span class="hljs-comment">// person2</span></code></pre></div><p>答案既注释<br>我们来分析一下:<br>person1.show1()和person1.show1.call(person2)这两个都不用细说,前者this指向函数调用者‘person1’;后者使用call改变了this指向,相当于是用person2调用了person1的show1方法,故this指向调用者person2;</p><p>person1.show2()这里是个箭头函数,注意箭头函数中的this是定义时就被确定的,指向执行上下文,即window;<br>而person1.show2.call(person2)即使调用了call来改变this指向,但是this在定义时就被确定了,因此call无效</p><p>person1.show3()(),先执行show3方法,会返回一个普通函数,全局再调用这个普通函数,因此this指向window;<br>person1.show3().call(person2),先执行show3方法,返回一个普通函数,但是此时用了call,相当于是person2在调用这个普通函数,因此this指向person2<br>person1.show3.call(person2)(),此时相当于是person2在调用person1的show3方法,会返回一个普通函数,全局再调用它,因此this指向window</p><p>person1.show4()(),person1先调用show4方法,会返回一个箭头函数,注意箭头函数中的this是继承上下文而来的,而此时上下文的this指向person1,因此this指向person1;<br>person1.show4().call(person2) ,person1先调用show4方法,还是会返回一个箭头函数,即使用call也不能改变this指向,因为它在定义时就被确定了;还是指向上下文,即person1;<br>person1.show4.call(person2)(),用person2调用person1的show4方法,此时箭头函数的上下文是person2,因此this指向person2;</p><p>总而言之,言而总之记住一句话:</p><blockquote><p><span style="color:red">箭头函数内部是没有this的,也就是说,箭头函数里面的this会继承自外部的this,判断箭头函数指向问题时,不要看被谁调用的,而是看在哪儿<br>定义的!!!</span></p></blockquote>]]></content>
<tags>
<tag>js</tag>
</tags>
</entry>
<entry>
<title>DOM与IE在事件处理上的区别</title>
<link href="/2020/02/10/DOM%E7%9A%84%E6%B5%8F%E8%A7%88%E5%99%A8%E5%85%BC%E5%AE%B9%E6%80%A7%E9%97%AE%E9%A2%98/"/>
<url>/2020/02/10/DOM%E7%9A%84%E6%B5%8F%E8%A7%88%E5%99%A8%E5%85%BC%E5%AE%B9%E6%80%A7%E9%97%AE%E9%A2%98/</url>
<content type="html"><![CDATA[<h3 id="事件模型"><a href="#事件模型" class="headerlink" title="事件模型"></a>事件模型</h3><h4 id="DOM:3个阶段"><a href="#DOM:3个阶段" class="headerlink" title="DOM:3个阶段"></a>DOM:3个阶段</h4><ul><li>1.由外向内:捕获</li><li>2.触发</li><li>3.由内向外:冒泡</li></ul><h4 id="IE8:2两个阶段"><a href="#IE8:2两个阶段" class="headerlink" title="IE8:2两个阶段"></a>IE8:2两个阶段</h4><ul><li>1.触发</li><li>2.由内向外:冒泡</li></ul><p>如图:DOM与IE8事件模型的比较<br><img src='/images/DOM&IE8.png'></p><h3 id="事件绑定"><a href="#事件绑定" class="headerlink" title="事件绑定"></a>事件绑定</h3><p>在DOM中:elem.addEventListener(‘click’,function(){},false)<br>注意:第三个参数 capture:是否在捕获阶段就提前触发,默认为false,一般省略;</p><p>在IE8中:elem.attachEvent(‘onclick’,function(){})</p><h3 id="事件移除"><a href="#事件移除" class="headerlink" title="事件移除"></a>事件移除</h3><p>在DOM中:ele.removeEventListener(‘click’,function(){},false)<br>在IE8中:ele.detachEvent(‘onclick’,function(){})</p><h3 id="获得事件对象的方法"><a href="#获得事件对象的方法" class="headerlink" title="获得事件对象的方法"></a>获得事件对象的方法</h3><p>在DOM中:ele.addEventListener(‘click’,function(e){e->event})<br>在IE8中:不会自动传入时间对象e,事件对象event始终保持在一个全局变量window.event中<br>elem.attachEvent(‘onclick’,function(){ var e = window.event })</p><h3 id="获得目标元素"><a href="#获得目标元素" class="headerlink" title="获得目标元素"></a>获得目标元素</h3><p>在DOM中:e.target<br>在IE8中:window.event.srcElement<br>兼容所有浏览器的写法:</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">var</span> target = e.target || <span class="hljs-built_in">window</span>.event.srcElement;</code></pre></div><h3 id="阻止冒泡"><a href="#阻止冒泡" class="headerlink" title="阻止冒泡"></a>阻止冒泡</h3><p>在DOM中:e.stopPropagation()<br>在IE8中:window.event.cancelBubble = true<br>兼容所有浏览器的写法:</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">if</span>(<span class="hljs-built_in">window</span>.event.cancelBubble != <span class="hljs-literal">undefined</span>) { <span class="hljs-built_in">window</span>.event.cancelBubble = <span class="hljs-literal">true</span> <span class="hljs-comment">//IE8</span>}<span class="hljs-keyword">else</span> { e.stopProoagation() }</code></pre></div><h3 id="阻止默认行为"><a href="#阻止默认行为" class="headerlink" title="阻止默认行为"></a>阻止默认行为</h3><p>在DOM中:e.preventDefault()<br>在IE8中:事件处理函数中:window.event.returnValue = false<br>兼容所有浏览器的写法:</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">if</span>(<span class="hljs-keyword">typeof</span> e.preventDefault !== <span class="hljs-string">'function'</span>) { <span class="hljs-built_in">window</span>.event.returnValue = <span class="hljs-literal">false</span> <span class="hljs-comment">//IE8</span>}<span class="hljs-keyword">else</span> { e.preventDefault()}</code></pre></div><h3 id="案例"><a href="#案例" class="headerlink" title="案例"></a>案例</h3><p>定义一个函数,可以支持所有浏览器中的处理函数绑定</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">bindEvent</span>(<span class="hljs-params">elem, eventName, handler</span>) </span>{ <span class="hljs-keyword">if</span>(<span class="hljs-keyword">typeof</span> elem.attachEvent!==<span class="hljs-string">'function'</span>){ <span class="hljs-comment">//DOM</span> elem.addEventListener(eventName, handler) }<span class="hljs-keyword">else</span>{ <span class="hljs-comment">//IE8</span> elem.attachEvent(<span class="hljs-string">'on'</span>+eventName, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{ <span class="hljs-comment">//this -> elem</span> <span class="hljs-keyword">var</span> e = <span class="hljs-built_in">window</span>.event e.target = e.srcElement; handler.call(<span class="hljs-built_in">this</span>,e) }) }}bindEvent(btn, <span class="hljs-string">'click'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">e</span>)</span>{ <span class="hljs-comment">//this 当前事件冒泡到的父元素</span> <span class="hljs-keyword">var</span> target = e.target <span class="hljs-comment">//目标元素</span>})</code></pre></div>]]></content>
<tags>
<tag>DOM</tag>
</tags>
</entry>
<entry>
<title>Vue.$set解决视图不更新</title>
<link href="/2020/01/08/Vue-set%E8%A7%A3%E5%86%B3%E8%A7%86%E5%9B%BE%E4%B8%8D%E6%9B%B4%E6%96%B0/"/>
<url>/2020/01/08/Vue-set%E8%A7%A3%E5%86%B3%E8%A7%86%E5%9B%BE%E4%B8%8D%E6%9B%B4%E6%96%B0/</url>
<content type="html"><![CDATA[<h3 id="问题"><a href="#问题" class="headerlink" title="问题"></a>问题</h3><p>实际开发时,遇到过这种情况,我们给data中的一个对象添加新属性时,视图层却不更新</p><div class="code-wrapper"><pre><code class="hljs javascript"><div id=<span class="hljs-string">"app"</span>> <span class="xml"><span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"(item, i) of user"</span> <span class="hljs-attr">:key</span>=<span class="hljs-string">"i"</span>></span></span><span class="xml"> 姓名:{{item.name}}</span><span class="xml"> 年龄:{{item.age}}</span><span class="xml"> <span class="hljs-tag"><<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"change(i)"</span>></span>爱好<span class="hljs-tag"></<span class="hljs-name">button</span>></span></span><span class="xml"> <span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"item.love"</span>></span></span><span class="xml"> 爱好:吃饭</span><span class="xml"> <span class="hljs-tag"></<span class="hljs-name">div</span>></span></span><span class="xml"> <span class="hljs-tag"></<span class="hljs-name">div</span>></span></span></div><span class="xml"><span class="hljs-tag"><<span class="hljs-name">script</span>></span><span class="javascript"></span></span><span class="javascript"><span class="xml"> <span class="hljs-keyword">var</span> vue = <span class="hljs-keyword">new</span> Vue({</span></span><span class="javascript"><span class="xml"> <span class="hljs-attr">el</span>: <span class="hljs-string">'#app'</span>,</span></span><span class="javascript"><span class="xml"> data () {</span></span><span class="javascript"><span class="xml"> <span class="hljs-keyword">return</span> {</span></span><span class="javascript"><span class="xml"> <span class="hljs-attr">user</span>:[</span></span><span class="javascript"><span class="xml"> { <span class="hljs-attr">name</span>:<span class="hljs-string">'fan'</span>, <span class="hljs-attr">age</span>:<span class="hljs-number">20</span> },</span></span><span class="javascript"><span class="xml"> { <span class="hljs-attr">name</span>:<span class="hljs-string">'lijing'</span>, <span class="hljs-attr">age</span>:<span class="hljs-number">30</span> },</span></span><span class="javascript"><span class="xml"> { <span class="hljs-attr">name</span>:<span class="hljs-string">'yucheng'</span>, <span class="hljs-attr">age</span>:<span class="hljs-number">40</span> },</span></span><span class="javascript"><span class="xml"> { <span class="hljs-attr">name</span>:<span class="hljs-string">'rongxin'</span>, <span class="hljs-attr">age</span>:<span class="hljs-number">50</span> }</span></span><span class="javascript"><span class="xml"> ]</span></span><span class="javascript"><span class="xml"> }</span></span><span class="javascript"><span class="xml"> },</span></span><span class="javascript"><span class="xml"> <span class="hljs-attr">methods</span>: {</span></span><span class="javascript"><span class="xml"> <span class="hljs-function"><span class="hljs-title">change</span>(<span class="hljs-params">i</span>)</span>{</span></span><span class="javascript"><span class="xml"> <span class="hljs-built_in">this</span>.user.forEach(<span class="hljs-function">(<span class="hljs-params">value, index</span>)=></span>{</span></span><span class="javascript"><span class="xml"> <span class="hljs-keyword">if</span>(index === i){</span></span><span class="javascript"><span class="xml"> <span class="hljs-comment">//相当于添加一个新属性</span></span></span><span class="javascript"><span class="xml"> <span class="hljs-built_in">this</span>.user[i].love = !value.love</span></span><span class="javascript"><span class="xml"> }</span></span><span class="javascript"><span class="xml"> })</span></span><span class="javascript"><span class="xml"> }</span></span><span class="javascript"><span class="xml"> }</span></span><span class="javascript"><span class="xml"> })</span></span><span class="javascript"><span class="xml"></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span></span></code></pre></div><p>最初item.love是undefined,点击事件触发后,给item.love赋值为true,相当于给对象新添了一个love属性,但是视图层却没更新</p><p>由于受JavaScript的限制,vue.js不能监听对象属性的添加和删除,因为在vue组件初始化的过程中,会调用getter和setter方法,所以该属性必须是存在在data中,视图层才会响应该数据的变化</p><h3 id="解决"><a href="#解决" class="headerlink" title="解决"></a>解决</h3><p>使用vue.set(obj, key, value)方法</p><div class="code-wrapper"><pre><code class="hljs javascript">methods: { <span class="hljs-function"><span class="hljs-title">change</span>(<span class="hljs-params">i</span>)</span>{ <span class="hljs-built_in">this</span>.user.forEach(<span class="hljs-function">(<span class="hljs-params">value,index</span>)=></span>{ <span class="hljs-keyword">if</span>(index === i){ <span class="hljs-built_in">this</span>.$set(<span class="hljs-built_in">this</span>.user[i], <span class="hljs-string">'love'</span>, !value.love) }<span class="hljs-keyword">else</span>{ <span class="hljs-built_in">this</span>.$set(<span class="hljs-built_in">this</span>.user[index], <span class="hljs-string">'love'</span>, value.love) } }) } }</code></pre></div>]]></content>
<tags>
<tag>vue</tag>
</tags>
</entry>
<entry>
<title>keep-alive与activated</title>
<link href="/2020/01/06/keep-alive%E4%B8%8Eactivated/"/>
<url>/2020/01/06/keep-alive%E4%B8%8Eactivated/</url>
<content type="html"><![CDATA[<h3 id="keep-alive组件"><a href="#keep-alive组件" class="headerlink" title="keep-alive组件"></a>keep-alive组件</h3><p>当组件在进行切换时,你有时候想保持这些组件的状态,以避免反复重渲染导致的性能问题。<br>keep-alive组件可以缓存组件的内容,避免组件反复加载,影响效率</p><p>比如:我们缓存一个页面<br>在router.js或router/index.js中,在需要缓存的路由上添加meta:{ keepAlive:true }</p><div class="code-wrapper"><pre><code class="hljs javascript">...<span class="hljs-keyword">const</span> routes = [... { <span class="hljs-attr">path</span>: <span class="hljs-string">'/'</span>, <span class="hljs-attr">name</span>: <span class="hljs-string">'home'</span>, <span class="hljs-attr">component</span>: Home, <span class="hljs-attr">meta</span>:{ <span class="hljs-attr">keepAlive</span>:<span class="hljs-literal">true</span> } },...]...</code></pre></div><p>注意:meta不能改名,因为meta是路由对象专门定义,用来保存自定义属性值的配置项;但是keepAlive是自定义的属性名,可以改名。</p><p>在App.vue中</p><div class="code-wrapper"><pre><code class="hljs html">...<span class="hljs-tag"><<span class="hljs-name">keep-alive</span>></span> <span class="hljs-comment"><!-- 需要缓存的路由 --></span> <span class="hljs-tag"><<span class="hljs-name">router-view</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"$route.meta.keepAlive"</span> /></span><span class="hljs-tag"></<span class="hljs-name">keep-alive</span>></span> <span class="hljs-comment"><!-- 不需要缓存的路由 --></span><span class="hljs-tag"><<span class="hljs-name">router-view</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"!$route.meta.keepAlive"</span> /></span>...</code></pre></div><p>除此之外,你也可以用在动态组件上</p><div class="code-wrapper"><pre><code class="hljs html"><span class="hljs-comment"><!-- 失活的组件将会被缓存!--></span><span class="hljs-tag"><<span class="hljs-name">keep-alive</span>></span> <span class="hljs-tag"><<span class="hljs-name">component</span> <span class="hljs-attr">v-bind:is</span>=<span class="hljs-string">"currentTabComponent"</span>></span><span class="hljs-tag"></<span class="hljs-name">component</span>></span><span class="hljs-tag"></<span class="hljs-name">keep-alive</span>></span></code></pre></div><h3 id="activated"><a href="#activated" class="headerlink" title="activated"></a>activated</h3><p>当引入keep-alive 的时候,页面第一次进入,钩子的触发顺序:<br>created-> mounted-> activated,退出时触发deactivated。<br>当再次进入(前进或者后退)时,只触发activated。</p><p>比如在vue脚手架中path为“/”的 home组件</p><div class="code-wrapper"><pre><code class="hljs javascript">...<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span>{ ... <span class="hljs-function"><span class="hljs-title">activated</span>(<span class="hljs-params"></span>)</span>{ <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'home组件激活'</span>) }, <span class="hljs-function"><span class="hljs-title">deactivated</span>(<span class="hljs-params"></span>)</span>{ <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'home组件失活'</span>) } ...}...</code></pre></div><p>在另一个path为“/about”的 about组件中</p><div class="code-wrapper"><pre><code class="hljs javascript">...<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span>{ ... <span class="hljs-function"><span class="hljs-title">activated</span>(<span class="hljs-params"></span>)</span>{ <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'about组件激活'</span>) } ...}...</code></pre></div><p>特别注意:<br>activated和deactivated钩子只能和keep-alive配合使用</p>]]></content>
<tags>
<tag>vue</tag>
</tags>
</entry>
<entry>
<title>vue中父子组件互调方法</title>
<link href="/2020/01/01/vue%E4%B8%AD%E7%88%B6%E5%AD%90%E7%BB%84%E4%BB%B6%E4%BA%92%E8%B0%83%E6%96%B9%E6%B3%95/"/>
<url>/2020/01/01/vue%E4%B8%AD%E7%88%B6%E5%AD%90%E7%BB%84%E4%BB%B6%E4%BA%92%E8%B0%83%E6%96%B9%E6%B3%95/</url>
<content type="html"><![CDATA[<p>在做项目时,只记得vue组件可以传递值,却忽略了组件之间也可以传递方法</p><p>我们先说说ref这个特殊属性:<br>ref 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs 对象上。如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例<br><a href="https://cn.vuejs.org/v2/api/#ref">官方文档解释</a></p><h3 id="父组件调用子组件的方法"><a href="#父组件调用子组件的方法" class="headerlink" title="父组件调用子组件的方法"></a>父组件调用子组件的方法</h3><p>当父调用子的方法时,要用到ref这个特殊属性<br>父组件:</p><div class="code-wrapper"><pre><code class="hljs javascript"><template><span class="xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span></span><span class="xml"> <span class="hljs-tag"><<span class="hljs-name">h1</span>></span>这是父组件<span class="hljs-tag"></<span class="hljs-name">h1</span>></span></span><span class="xml"> <span class="hljs-tag"><<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"go"</span>></span>调用子组件方法<span class="hljs-tag"></<span class="hljs-name">button</span>></span></span><span class="xml"> <span class="hljs-tag"><<span class="hljs-name">hr</span>></span></span><span class="xml"> <span class="hljs-tag"><<span class="hljs-name">child</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">"c"</span>></span><span class="hljs-tag"></<span class="hljs-name">child</span>></span></span><span class="xml"><span class="hljs-tag"></<span class="hljs-name">div</span>></span></span><span class="xml"><span class="hljs-tag"></<span class="hljs-name">template</span>></span></span><span class="xml"><span class="hljs-tag"><<span class="hljs-name">script</span>></span><span class="javascript"></span></span><span class="javascript"><span class="xml"><span class="hljs-keyword">import</span> child <span class="hljs-keyword">from</span> <span class="hljs-string">'../components/child'</span></span></span><span class="javascript"><span class="xml"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {</span></span><span class="javascript"><span class="xml"> <span class="hljs-attr">components</span>:{</span></span><span class="javascript"><span class="xml"> child</span></span><span class="javascript"><span class="xml"> },</span></span><span class="javascript"><span class="xml"> <span class="hljs-attr">methods</span>:{</span></span><span class="javascript"><span class="xml"> <span class="hljs-function"><span class="hljs-title">go</span>(<span class="hljs-params"></span>)</span>{</span></span><span class="javascript"><span class="xml"> <span class="hljs-comment">//this.$refs.c指向child这个组件</span></span></span><span class="javascript"><span class="xml"> <span class="hljs-built_in">this</span>.$refs.c.childMethod()</span></span><span class="javascript"><span class="xml"> }</span></span><span class="javascript"><span class="xml"> }</span></span><span class="javascript"><span class="xml">}</span></span><span class="javascript"><span class="xml"></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span></span></code></pre></div><p>子组件:</p><div class="code-wrapper"><pre><code class="hljs javascript"><template><span class="xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span></span><span class="xml"> <span class="hljs-tag"><<span class="hljs-name">h3</span>></span>这是子组件<span class="hljs-tag"></<span class="hljs-name">h3</span>></span> </span><span class="xml"><span class="hljs-tag"></<span class="hljs-name">div</span>></span></span></template><span class="xml"><span class="hljs-tag"><<span class="hljs-name">script</span>></span><span class="javascript"></span></span><span class="javascript"><span class="xml"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {</span></span><span class="javascript"><span class="xml"> <span class="hljs-attr">methods</span>:{</span></span><span class="javascript"><span class="xml"> <span class="hljs-function"><span class="hljs-title">childMethod</span>(<span class="hljs-params"></span>)</span>{</span></span><span class="javascript"><span class="xml"> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'这是子组件中的方法'</span>)</span></span><span class="javascript"><span class="xml"> }</span></span><span class="javascript"><span class="xml"> }</span></span><span class="javascript"><span class="xml">}</span></span><span class="javascript"><span class="xml"></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span></span></code></pre></div><p>该结果是:当点击‘调用子组件方法’这个按钮时,则会在控制台输出‘这是子组件中的方法’</p><h3 id="子组件调用父组件的方法时"><a href="#子组件调用父组件的方法时" class="headerlink" title="子组件调用父组件的方法时"></a>子组件调用父组件的方法时</h3><p>当子调用父的方法时,分为以下三种情况</p><h4 id="1-子组件通过使用this-parent-xxx"><a href="#1-子组件通过使用this-parent-xxx" class="headerlink" title="1.子组件通过使用this.$parent.xxx"></a>1.子组件通过使用this.$parent.xxx</h4><p>父组件</p><div class="code-wrapper"><pre><code class="hljs javascript"><template><span class="xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span></span><span class="xml"> <span class="hljs-tag"><<span class="hljs-name">h1</span>></span>这是父组件<span class="hljs-tag"></<span class="hljs-name">h1</span>></span></span><span class="xml"> <span class="hljs-tag"><<span class="hljs-name">child</span>></span><span class="hljs-tag"></<span class="hljs-name">child</span>></span></span><span class="xml"><span class="hljs-tag"></<span class="hljs-name">div</span>></span></span></template><span class="xml"><span class="hljs-tag"><<span class="hljs-name">script</span>></span><span class="javascript"></span></span><span class="javascript"><span class="xml"><span class="hljs-keyword">import</span> child <span class="hljs-keyword">from</span> <span class="hljs-string">'../components/child'</span></span></span><span class="javascript"><span class="xml"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {</span></span><span class="javascript"><span class="xml"> <span class="hljs-attr">components</span>:{</span></span><span class="javascript"><span class="xml"> child</span></span><span class="javascript"><span class="xml"> },</span></span><span class="javascript"><span class="xml"> <span class="hljs-attr">methods</span>:{</span></span><span class="javascript"><span class="xml"> <span class="hljs-function"><span class="hljs-title">fatherMethod</span>(<span class="hljs-params"></span>)</span>{</span></span><span class="javascript"><span class="xml"> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'这是父组件中的方法'</span>)</span></span><span class="javascript"><span class="xml"> }</span></span><span class="javascript"><span class="xml"> }</span></span><span class="javascript"><span class="xml">}</span></span><span class="javascript"><span class="xml"></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span></span></code></pre></div><p>子组件</p><div class="code-wrapper"><pre><code class="hljs javascript"><template><span class="xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span></span><span class="xml"> <span class="hljs-tag"><<span class="hljs-name">h3</span>></span>这是子组件<span class="hljs-tag"></<span class="hljs-name">h3</span>></span> </span><span class="xml"> <span class="hljs-tag"><<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"goFa"</span>></span>调用父组件中的方法<span class="hljs-tag"></<span class="hljs-name">button</span>></span></span><span class="xml"><span class="hljs-tag"></<span class="hljs-name">div</span>></span></span></template><span class="xml"><span class="hljs-tag"><<span class="hljs-name">script</span>></span><span class="javascript"></span></span><span class="javascript"><span class="xml"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {</span></span><span class="javascript"><span class="xml"> <span class="hljs-attr">methods</span>:{</span></span><span class="javascript"><span class="xml"> <span class="hljs-function"><span class="hljs-title">goFa</span>(<span class="hljs-params"></span>)</span>{</span></span><span class="javascript"><span class="xml"> <span class="hljs-comment">//this.$parent指向父组件</span></span></span><span class="javascript"><span class="xml"> <span class="hljs-built_in">this</span>.$parent.fatherMethod()</span></span><span class="javascript"><span class="xml"> }</span></span><span class="javascript"><span class="xml"> }</span></span><span class="javascript"><span class="xml">}</span></span><span class="javascript"><span class="xml"></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span></span></code></pre></div><p>该结果是:当在子组件中点击‘调用父组件中的方法’这个按钮时,则会在控制台输出‘这是父组件中的方法’</p><h4 id="2-子组件通过使用this-emit-‘xxx’"><a href="#2-子组件通过使用this-emit-‘xxx’" class="headerlink" title="2.子组件通过使用this.$emit(‘xxx’)"></a>2.子组件通过使用this.$emit(‘xxx’)</h4><p>跟子传值给父组件是一样的道理,通过触发父组件中的一个自定义事件,从而触发这个自定义事件的处理函数<br>父组件:</p><div class="code-wrapper"><pre><code class="hljs javascript"><template><span class="xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span></span><span class="xml"> <span class="hljs-tag"><<span class="hljs-name">h1</span>></span>这是父组件<span class="hljs-tag"></<span class="hljs-name">h1</span>></span></span><span class="xml"> <span class="hljs-tag"><<span class="hljs-name">child</span> @<span class="hljs-attr">fatherMethod</span>=<span class="hljs-string">'fatherMethods'</span>></span><span class="hljs-tag"></<span class="hljs-name">child</span>></span></span><span class="xml"><span class="hljs-tag"></<span class="hljs-name">div</span>></span></span></template><span class="xml"><span class="hljs-tag"><<span class="hljs-name">script</span>></span><span class="javascript"></span></span><span class="javascript"><span class="xml"><span class="hljs-keyword">import</span> child <span class="hljs-keyword">from</span> <span class="hljs-string">'../components/child'</span></span></span><span class="javascript"><span class="xml"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {</span></span><span class="javascript"><span class="xml"> <span class="hljs-attr">components</span>:{</span></span><span class="javascript"><span class="xml"> child</span></span><span class="javascript"><span class="xml"> },</span></span><span class="javascript"><span class="xml"> <span class="hljs-attr">methods</span>:{</span></span><span class="javascript"><span class="xml"> <span class="hljs-function"><span class="hljs-title">fatherMethods</span>(<span class="hljs-params">data</span>)</span>{</span></span><span class="javascript"><span class="xml"> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'这是父组件中的方法'</span>,data)</span></span><span class="javascript"><span class="xml"> }</span></span><span class="javascript"><span class="xml"> }</span></span><span class="javascript"><span class="xml">}</span></span><span class="javascript"><span class="xml"></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span></span></code></pre></div><p>子组件:</p><div class="code-wrapper"><pre><code class="hljs javascript"><template><span class="xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span></span><span class="xml"> <span class="hljs-tag"><<span class="hljs-name">h3</span>></span>这是子组件<span class="hljs-tag"></<span class="hljs-name">h3</span>></span> </span><span class="xml"> <span class="hljs-tag"><<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"goFa"</span>></span>调用父组件中的方法<span class="hljs-tag"></<span class="hljs-name">button</span>></span></span><span class="xml"><span class="hljs-tag"></<span class="hljs-name">div</span>></span></span></template><span class="xml"><span class="hljs-tag"><<span class="hljs-name">script</span>></span><span class="javascript"></span></span><span class="javascript"><span class="xml"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {</span></span><span class="javascript"><span class="xml"> <span class="hljs-attr">methods</span>:{</span></span><span class="javascript"><span class="xml"> <span class="hljs-function"><span class="hljs-title">goFa</span>(<span class="hljs-params"></span>)</span>{</span></span><span class="javascript"><span class="xml"> <span class="hljs-built_in">this</span>.$emit(<span class="hljs-string">'fatherMethod'</span>,<span class="hljs-string">'haha'</span>)</span></span><span class="javascript"><span class="xml"> }</span></span><span class="javascript"><span class="xml"> }</span></span><span class="javascript"><span class="xml">}</span></span><span class="javascript"><span class="xml"></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span></span></code></pre></div><p>该结果是:当在子组件中点击‘调用父组件中的方法’这个按钮时,则会在控制台输出‘这是父组件中的方法 haha’</p><h4 id="3-父组件把方法名传给子组件,在子组件里调用这个方法"><a href="#3-父组件把方法名传给子组件,在子组件里调用这个方法" class="headerlink" title="3.父组件把方法名传给子组件,在子组件里调用这个方法"></a>3.父组件把方法名传给子组件,在子组件里调用这个方法</h4><p>该方法原理类似于父传值给子,在父组件设置自定义属性,并在子组件通过props接收这个属性;<br>但注意:这里传递方法,必须要设置props</p><div class="code-wrapper"><pre><code class="hljs javascript"><template><span class="xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span></span><span class="xml"> <span class="hljs-tag"><<span class="hljs-name">h1</span>></span>这是父组件<span class="hljs-tag"></<span class="hljs-name">h1</span>></span></span><span class="xml"> <span class="hljs-tag"><<span class="hljs-name">child</span> <span class="hljs-attr">:fatherMethod</span>=<span class="hljs-string">'fatherMethods'</span>></span><span class="hljs-tag"></<span class="hljs-name">child</span>></span></span><span class="xml"><span class="hljs-tag"></<span class="hljs-name">div</span>></span></span></template><span class="xml"><span class="hljs-tag"><<span class="hljs-name">script</span>></span><span class="javascript"></span></span><span class="javascript"><span class="xml"><span class="hljs-keyword">import</span> child <span class="hljs-keyword">from</span> <span class="hljs-string">'../components/child'</span></span></span><span class="javascript"><span class="xml"></span></span><span class="javascript"><span class="xml"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {</span></span><span class="javascript"><span class="xml"> <span class="hljs-attr">components</span>:{</span></span><span class="javascript"><span class="xml"> child</span></span><span class="javascript"><span class="xml"> },</span></span><span class="javascript"><span class="xml"> <span class="hljs-attr">methods</span>:{</span></span><span class="javascript"><span class="xml"> <span class="hljs-function"><span class="hljs-title">fatherMethods</span>(<span class="hljs-params">data</span>)</span>{</span></span><span class="javascript"><span class="xml"> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'这是父组件中的方法'</span>,data)</span></span><span class="javascript"><span class="xml"> }</span></span><span class="javascript"><span class="xml"> }</span></span><span class="javascript"><span class="xml">}</span></span><span class="javascript"><span class="xml"></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span></span></code></pre></div><p>子组件:</p><div class="code-wrapper"><pre><code class="hljs javascript"><template><span class="xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span></span><span class="xml"> <span class="hljs-tag"><<span class="hljs-name">h3</span>></span>这是子组件<span class="hljs-tag"></<span class="hljs-name">h3</span>></span> </span><span class="xml"> <span class="hljs-tag"><<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"goFa"</span>></span>调用父组件中的方法<span class="hljs-tag"></<span class="hljs-name">button</span>></span></span><span class="xml"><span class="hljs-tag"></<span class="hljs-name">div</span>></span></span></template><span class="xml"><span class="hljs-tag"><<span class="hljs-name">script</span>></span><span class="javascript"></span></span><span class="javascript"><span class="xml"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {</span></span><span class="javascript"><span class="xml"> <span class="hljs-comment">//这里必须设置props</span></span></span><span class="javascript"><span class="xml"> <span class="hljs-attr">props</span>:{</span></span><span class="javascript"><span class="xml"> <span class="hljs-attr">fatherMethod</span>: {</span></span><span class="javascript"><span class="xml"> <span class="hljs-attr">type</span>: <span class="hljs-built_in">Function</span>,</span></span><span class="javascript"><span class="xml"> <span class="hljs-attr">default</span>: <span class="hljs-literal">null</span></span></span><span class="javascript"><span class="xml"> }</span></span><span class="javascript"><span class="xml"> },</span></span><span class="javascript"><span class="xml"> <span class="hljs-attr">methods</span>:{</span></span><span class="javascript"><span class="xml"> <span class="hljs-function"><span class="hljs-title">goFa</span>(<span class="hljs-params"></span>)</span>{</span></span><span class="javascript"><span class="xml"> <span class="hljs-built_in">this</span>.fatherMethod(<span class="hljs-string">'haha'</span>)</span></span><span class="javascript"><span class="xml"> }</span></span><span class="javascript"><span class="xml"> }</span></span><span class="javascript"><span class="xml">}</span></span><span class="javascript"><span class="xml"></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span></span></code></pre></div><p>该结果是:当在子组件中点击‘调用父组件中的方法’这个按钮时,则会在控制台输出‘这是父组件中的方法 haha’</p>]]></content>
<tags>
<tag>vue</tag>
</tags>
</entry>
<entry>
<title>DNS与CDN</title>
<link href="/2019/12/30/DNS%E4%B8%8ECDN/"/>
<url>/2019/12/30/DNS%E4%B8%8ECDN/</url>
<content type="html"><![CDATA[<h3 id="DNS"><a href="#DNS" class="headerlink" title="DNS"></a>DNS</h3><p>DNS(Domain Name System,<span style="color:#2196F3">域名系统</span> ),万维网上作为域名和IP地址相互映射的一个<span style="color:#2196F3">分布式数据库</span>,能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的IP数串。通过域名,最终得到该域名对应的IP地址的过程叫做域名解析(或主机名解析)。DNS协议运行在<span style="color:#2196F3">UDP</span>协议之上,使用端口号53。</p><p><a href="https://blog.csdn.net/yonggeit/article/details/88175022">DNS缓存</a></p><h3 id="CDN"><a href="#CDN" class="headerlink" title="CDN"></a>CDN</h3><p>注意:http缓存是浏览器端缓存,cdn是服务器端缓存。</p><p>http缓存是浏览器端缓存,cdn是服务器端缓存。<br>CDN的全称是Content Delivery Network,即内容分发网络。CDN是构建在网络之上内容分发网络,依靠在各地部署的缓存服务器,通过中心平台的负载均衡/内容分发/调度等功能模块,使用户可以就近获取所需要的内容,从而达到降低网络用塞,提高系统访问速度的技术。CDN的关键技术是内容存储和分发技术。</p><p>CDN的思路是:通过在网络各处放节点服务器,这个服务器构成在现有网络基础之上的一层智能虚拟网络,CDN能够将用户的请求分发到距离用户最近的服务器节点上,提高用户访问速度。比如:100台CDN服务器分布在全国各地,如果从广东访问,会从最近的节点返回资源,这就是核心。</p><h4 id="完整的CDN工作流程:"><a href="#完整的CDN工作流程:" class="headerlink" title="完整的CDN工作流程:"></a>完整的CDN工作流程:</h4><img style="margin:0 auto;" src="/images/CDN.png" /><h4 id="访问流程详解:"><a href="#访问流程详解:" class="headerlink" title="访问流程详解:"></a>访问流程详解:</h4><p>(1)当用户点击网站页面上的内容URL,经过本地DNS系统解析,DNS系统会最终将域名的解析权交给CNAME指向的CDN专用DNS服务器。</p><p>(2)CDN的DNS服务器将CDN的全局负载均衡设备IP地址返回用户。</p><p>(3)用户向CDN的全局负载均衡设备发起内容URL访问请求。</p><p>(4)CDN全局负载均衡设备根据用户IP地址,以及用户请求的内容URL,选择一台用户所属区域的区域负载均衡设备,告诉用户向这台设备发起请求。</p><p>(5)区域负载均衡设备会为用户选择一台合适的缓存服务器提供服务,选择的依据包括:根据用户IP地址,判断哪一台服务器距用户最近;根据用户所请求的URL中携带的内容名称,判断哪一台服务器上有用户所需内容;查询各个服务器当前的负载情况,判断哪一台服务器尚有服务能力。基于以上这些条件的综合分析之后,区域负载均衡设备会向全局负载均衡设备返回一台缓存服务器的IP地址。</p><p>(6)全局负载均衡设备把服务器的IP地址返回给用户。</p><p>(7)用户向缓存服务器发起请求,缓存服务器响应用户请求,将用户所需内容传送到用户终端。如果这台缓存服务器上并没有用户想要的内容,而区域均衡设备依然将它分配给了用户,那么这台服务器就要向它的上一级缓存服务器请求内容,直至追溯到网站的源服务器将内容拉到本地。<br><img src="/images/CDN2.png" alt="CDN"></p>]]></content>
<tags>
<tag>Http</tag>
</tags>
</entry>
<entry>
<title>TypeScript中的泛型</title>
<link href="/2019/12/24/TypeScript%E4%B8%AD%E7%9A%84%E6%B3%9B%E5%9E%8B/"/>
<url>/2019/12/24/TypeScript%E4%B8%AD%E7%9A%84%E6%B3%9B%E5%9E%8B/</url>
<content type="html"><![CDATA[<h3 id="什么是泛型"><a href="#什么是泛型" class="headerlink" title="什么是泛型"></a>什么是泛型</h3><p>软件工程中,我们不仅要创建一致的定义良好的API,同时也要考虑可重用性。 组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能。</p><p>在像C#和Java这样的语言中,可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据。 这样用户就可以以自己的数据类型来使用组件。</p><p>通俗理解:泛型就是解决 类 接口 方法的复用性、以及对不特定数据类型的支持(类型校验)</p><p>我们用 T 来表示泛型,当然也可以用其他字母表示</p><h3 id="泛型类"><a href="#泛型类" class="headerlink" title="泛型类"></a>泛型类</h3><p>我们举一个例子,找数组中最小的元素,它可以是number,也可以是string</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MinClas</span><<span class="hljs-title">T</span>></span>{ public list:T[]=[]; add(value:T):<span class="hljs-keyword">void</span>{ <span class="hljs-built_in">this</span>.list.push(value); } min():T{ <span class="hljs-keyword">var</span> minNum=<span class="hljs-built_in">this</span>.list[<span class="hljs-number">0</span>]; <span class="hljs-keyword">for</span>(<span class="hljs-keyword">var</span> i=<span class="hljs-number">0</span>;i<<span class="hljs-built_in">this</span>.list.length;i++){ <span class="hljs-keyword">if</span>(minNum><span class="hljs-built_in">this</span>.list[i]){ minNum=<span class="hljs-built_in">this</span>.list[i]; } } <span class="hljs-keyword">return</span> minNum; }}<span class="hljs-comment">/*实例化类 并且制定了类的T代表的类型是number*/</span><span class="hljs-keyword">var</span> m1=<span class="hljs-keyword">new</span> MinClas<number>(); m1.add(<span class="hljs-number">11</span>);m1.add(<span class="hljs-number">3</span>);m1.add(<span class="hljs-number">2</span>);alert(m1.min()) <span class="hljs-comment">// 2</span><span class="hljs-comment">/*实例化类 并且制定了类的T代表的类型是string*/</span><span class="hljs-keyword">var</span> m2=<span class="hljs-keyword">new</span> MinClas<string>(); m2.add(<span class="hljs-string">'c'</span>);m2.add(<span class="hljs-string">'a'</span>);m2.add(<span class="hljs-string">'v'</span>);alert(m2.min()) <span class="hljs-comment">// 'a'</span></code></pre></div><p>注意:T 表示泛型,它具体指什么类型是调用这个方法的时候决定的</p><h3 id="泛型接口"><a href="#泛型接口" class="headerlink" title="泛型接口"></a>泛型接口</h3><p>泛型解决、类、接口、方法的复用性<br>而接口是一种规范的定义,它定义了行为和动作的规范(约束)</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-comment">//定义一个方法接口</span>interface ConfigFn{ <T>(value:T):T;}<span class="hljs-keyword">var</span> getData:ConfigFn=<span class="hljs-function"><span class="hljs-keyword">function</span><<span class="hljs-title">T</span>>(<span class="hljs-params">value:T</span>):<span class="hljs-title">T</span></span>{ <span class="hljs-keyword">return</span> value;}<span class="hljs-comment">//此时给出了泛型的具体类型</span>getData<string>(<span class="hljs-string">'张三'</span>);getData<string>(<span class="hljs-number">1243</span>); <span class="hljs-comment">//错误</span></code></pre></div><p>当然也可以这样写,两者等效</p><div class="code-wrapper"><pre><code class="hljs javascript">interface ConfigFn<T>{ (value:T):T;}<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getData</span><<span class="hljs-title">T</span>>(<span class="hljs-params">value:T</span>):<span class="hljs-title">T</span></span>{ <span class="hljs-keyword">return</span> value;}<span class="hljs-comment">//此时给出了泛型的具体类型</span><span class="hljs-keyword">var</span> myGetData:ConfigFn<string>=getData; myGetData(<span class="hljs-string">'20'</span>); <span class="hljs-comment">/*正确*/</span>myGetData(<span class="hljs-number">20</span>) <span class="hljs-comment">//错误</span></code></pre></div><h3 id="泛型接口和泛型类混合"><a href="#泛型接口和泛型类混合" class="headerlink" title="泛型接口和泛型类混合"></a>泛型接口和泛型类混合</h3><p>注意:要实现泛型接口 这个类也应该是一个泛型类<br>定义一个操作数据库的库 支持 Mysql Mssql MongoDb:</p><div class="code-wrapper"><pre><code class="hljs javascript">interface DBI<T>{ add(info:T):boolean; update(info:T,<span class="hljs-attr">id</span>:number):<span class="hljs-keyword">void</span>;}<span class="hljs-comment">//定义一个操作mysql数据库的类 </span><span class="hljs-comment">//注意:要实现泛型接口 这个类也应该是一个泛型类</span><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MysqlDb</span><<span class="hljs-title">T</span>> <span class="hljs-title">implements</span> <span class="hljs-title">DBI</span><<span class="hljs-title">T</span>></span>{ <span class="hljs-function"><span class="hljs-title">constructor</span>(<span class="hljs-params"></span>)</span>{ <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'数据库建立连接'</span>); } <span class="hljs-comment">//必须实现接口的方法</span> add(info: T): boolean { <span class="hljs-built_in">console</span>.log(info); <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>; } <span class="hljs-comment">//必须实现接口的方法 </span> update(info: T, <span class="hljs-attr">id</span>: number): <span class="hljs-keyword">void</span> { <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Method not implemented."</span>); }}<span class="hljs-comment">//操作用户表 定义一个User类和数据表做映射</span><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span></span>{ <span class="hljs-attr">username</span>:string | <span class="hljs-literal">undefined</span>; password:string | <span class="hljs-literal">undefined</span>;}<span class="hljs-keyword">var</span> u=<span class="hljs-keyword">new</span> User();u.username=<span class="hljs-string">'张三111'</span>;u.password=<span class="hljs-string">'123456'</span>;<span class="hljs-keyword">var</span> oMysql=<span class="hljs-keyword">new</span> MysqlDb<User>(); <span class="hljs-comment">//类作为参数来约束数据传入的类型 </span>oMysql.add(u);<span class="hljs-comment">//User {username: "张三111", password: "123456"}</span></code></pre></div>]]></content>
<tags>
<tag>TypeScript</tag>
</tags>
</entry>
<entry>
<title>typescript数据类型</title>
<link href="/2019/12/21/typescript%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B/"/>
<url>/2019/12/21/typescript%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B/</url>
<content type="html"><![CDATA[<p>typescript中为了使编写的代码更规范,更有利于维护,增加了类型校验,在typescript中主要给我们提供了以下数据类型</p><ul><li>布尔类型(boolean)</li><li>数字类型(number)</li><li>字符串类型(string)</li><li>数组类型(array)</li><li>元组类型(tuple)</li><li>枚举类型(enum)</li><li>任意类型(any)</li><li>null 和 undefined</li><li>void类型</li><li>never类型</li></ul><h3 id="布尔类型(boolean)"><a href="#布尔类型(boolean)" class="headerlink" title="布尔类型(boolean)"></a>布尔类型(boolean)</h3><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">var</span> flag:boolean=<span class="hljs-literal">true</span>;<span class="hljs-comment">// flag=123; //错误</span>flag=<span class="hljs-literal">false</span>; <span class="hljs-comment">//正确</span><span class="hljs-built_in">console</span>.log(flag);</code></pre></div><h3 id="数字类型(number)"><a href="#数字类型(number)" class="headerlink" title="数字类型(number)"></a>数字类型(number)</h3><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">var</span> num:number=<span class="hljs-number">123</span>;num=<span class="hljs-number">456</span>;<span class="hljs-built_in">console</span>.log(num); <span class="hljs-comment">//正确</span>num=<span class="hljs-string">'str'</span>; <span class="hljs-comment">//错误</span></code></pre></div><h3 id="字符串类型-string"><a href="#字符串类型-string" class="headerlink" title="字符串类型(string)"></a>字符串类型(string)</h3><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">var</span> str:string=<span class="hljs-string">'this is ts'</span>;str=<span class="hljs-string">'haha'</span>; <span class="hljs-comment">//正确</span>str=<span class="hljs-literal">true</span>; <span class="hljs-comment">//错误</span></code></pre></div><h3 id="数组类型-array"><a href="#数组类型-array" class="headerlink" title="数组类型(array)"></a>数组类型(array)</h3><p>ts中定义数组有两种方式</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-comment">// 1.第一种定义数组的方式</span><span class="hljs-keyword">var</span> arr:number[]=[<span class="hljs-number">11</span>,<span class="hljs-number">22</span>,<span class="hljs-number">33</span>];<span class="hljs-built_in">console</span>.log(arr);<span class="hljs-comment">// 2.第二种定义数组的方式</span><span class="hljs-keyword">var</span> arr:<span class="hljs-built_in">Array</span><number>=[<span class="hljs-number">11</span>,<span class="hljs-number">22</span>,<span class="hljs-number">33</span>];<span class="hljs-built_in">console</span>.log(arr)</code></pre></div><h3 id="元组类型-tuple-属于数组的一种"><a href="#元组类型-tuple-属于数组的一种" class="headerlink" title="元组类型(tuple) 属于数组的一种"></a>元组类型(tuple) 属于数组的一种</h3><p>元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。 比如,你可以定义一对值分别为string和number类型的元组。</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">var</span> arr:<span class="hljs-built_in">Array</span><number>=[<span class="hljs-number">11</span>,<span class="hljs-number">22</span>,<span class="hljs-number">33</span>]; <span class="hljs-built_in">console</span>.log(arr)<span class="hljs-comment">//元祖类型</span><span class="hljs-keyword">let</span> arr:[number,string];arr = [<span class="hljs-number">123</span>,<span class="hljs-string">'this is ts'</span>]; <span class="hljs-comment">//正确</span>arr = [<span class="hljs-string">'this is ts'</span>,<span class="hljs-number">123</span>]; <span class="hljs-comment">//错误</span></code></pre></div><p>当访问一个越界的元素,会使用联合类型替代:</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-comment">//x[3] 不存在,不知道它的类型</span>x[<span class="hljs-number">3</span>] = <span class="hljs-string">'world'</span>; <span class="hljs-comment">// OK, 字符串可以赋值给(string | number)类型</span><span class="hljs-built_in">console</span>.log(x[<span class="hljs-number">5</span>].toString()); <span class="hljs-comment">// OK, 'string' 和 'number' 都有 toString</span>x[<span class="hljs-number">6</span>] = <span class="hljs-literal">true</span>; <span class="hljs-comment">// Error, 布尔不是(string | number)类型</span></code></pre></div><h3 id="枚举类型-enum"><a href="#枚举类型-enum" class="headerlink" title="枚举类型(enum)"></a>枚举类型(enum)</h3><p>在程序中用自然语言中有相应含义的单词来代表某一状态,则程序就很容易阅读和理解。</p><div class="code-wrapper"><pre><code class="hljs javascript">enum Flag {success=<span class="hljs-number">1</span>,error=<span class="hljs-number">2</span>};<span class="hljs-keyword">let</span> s:Flag=Flag.success;<span class="hljs-built_in">console</span>.log(s);<span class="hljs-comment">//1</span>enum Flag {success=<span class="hljs-number">1</span>,error=<span class="hljs-number">2</span>};<span class="hljs-keyword">let</span> f:Flag=Flag.error;<span class="hljs-built_in">console</span>.log(f);<span class="hljs-comment">//2</span></code></pre></div><p>如果标识符没有赋值 它的值就是下标:</p><div class="code-wrapper"><pre><code class="hljs javascript">enum Color {blue,red,<span class="hljs-string">'orange'</span>};<span class="hljs-keyword">var</span> c:Color=Color.red; <span class="hljs-built_in">console</span>.log(c); <span class="hljs-comment">//1 </span> <span class="hljs-regexp">/当有些有值时,有些没值时/</span>enum Color {blue,red=<span class="hljs-number">3</span>,<span class="hljs-string">'orange'</span>};<span class="hljs-keyword">var</span> c:Color=Color.red;<span class="hljs-built_in">console</span>.log(c); <span class="hljs-comment">//3</span><span class="hljs-keyword">var</span> c:Color=Color.orange;<span class="hljs-built_in">console</span>.log(c); <span class="hljs-comment">//4</span><span class="hljs-keyword">var</span> d:string=Color[<span class="hljs-number">4</span>]<span class="hljs-built_in">console</span>.log(d) <span class="hljs-comment">// orange</span>enum Err {<span class="hljs-string">'undefined'</span>=-<span class="hljs-number">1</span>,<span class="hljs-string">'null'</span>=-<span class="hljs-number">2</span>,<span class="hljs-string">'success'</span>=<span class="hljs-number">1</span>};<span class="hljs-keyword">var</span> e:Err=Err.success;<span class="hljs-built_in">console</span>.log(e);<span class="hljs-comment">//1</span></code></pre></div><h3 id="任意类型-any"><a href="#任意类型-any" class="headerlink" title="任意类型(any)"></a>任意类型(any)</h3><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">var</span> num:any=<span class="hljs-number">123</span>;num=<span class="hljs-string">'str'</span>;num=<span class="hljs-literal">true</span>;<span class="hljs-built_in">console</span>.log(num)<span class="hljs-comment">//true</span></code></pre></div><h3 id="null-和-undefined"><a href="#null-和-undefined" class="headerlink" title="null 和 undefined"></a>null 和 undefined</h3><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">var</span> num:number; <span class="hljs-comment">//必须要赋一个值</span><span class="hljs-built_in">console</span>.log(num) <span class="hljs-comment">//输出:undefined 报错</span><span class="hljs-keyword">var</span> num:<span class="hljs-literal">undefined</span>;<span class="hljs-built_in">console</span>.log(num) <span class="hljs-comment">//输出:undefined //正确</span></code></pre></div><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">var</span> num:number | <span class="hljs-literal">undefined</span>;num=<span class="hljs-number">123</span>;<span class="hljs-built_in">console</span>.log(num);<span class="hljs-comment">//123</span> <span class="hljs-comment">//定义没有赋值就是undefined</span><span class="hljs-keyword">var</span> num:number | <span class="hljs-literal">undefined</span>;<span class="hljs-built_in">console</span>.log(num); <span class="hljs-comment">//undefined</span></code></pre></div><p>一个元素可能是 number类型 可能是null 可能是undefined</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">var</span> num:number | <span class="hljs-literal">null</span> | <span class="hljs-literal">undefined</span>;num=<span class="hljs-number">1234</span>;<span class="hljs-built_in">console</span>.log(num) <span class="hljs-comment">//1234</span></code></pre></div><h3 id="void"><a href="#void" class="headerlink" title="void"></a>void</h3><p>typescript中的void表示没有任何类型,一般用于定义方法的时候方法没有返回值。</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-comment">//typescript中 </span><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">run</span>(<span class="hljs-params"></span>):<span class="hljs-title">void</span></span>{ <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'run'</span>)}run();<span class="hljs-comment">//错误写法</span><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">run</span>(<span class="hljs-params"></span>):<span class="hljs-title">undefined</span></span>{ <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'run'</span>)}run();</code></pre></div><h3 id="never类型"><a href="#never类型" class="headerlink" title="never类型"></a>never类型</h3><p>是其他类型 (包括 null 和 undefined)的子类型,代表从不会出现的值。<br>这意味着声明never的变量只能被never类型所赋值。</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">var</span> a:never;<span class="hljs-comment">// a=123; //错误的写法</span>a=(<span class="hljs-function">()=></span>{ <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'错误'</span>);})()</code></pre></div>]]></content>
<tags>
<tag>TypeScript</tag>
</tags>
</entry>
<entry>
<title>初识commander.js</title>
<link href="/2019/12/17/%E5%88%9D%E8%AF%86commander-js/"/>
<url>/2019/12/17/%E5%88%9D%E8%AF%86commander-js/</url>
<content type="html"><![CDATA[<p>commander.js 是 express 框架的开发者号称无所不能的 TJ 大神写的工具包,用于快捷开发命令行工具,提高项目的开发效率。<a href="https://github.com/tj/commander.js/blob/master/Readme_zh-CN.md">commander.js 官网地址</a></p><h3 id="初识命令行工具"><a href="#初识命令行工具" class="headerlink" title="初识命令行工具"></a>初识命令行工具</h3><p>下面是npm安装全局包的实例</p><div class="code-wrapper"><pre><code class="hljs javascript">npm install commander -g</code></pre></div><p>上述命令行代码由三部分组成:</p><ul><li>npm 命令行工具名称</li><li>install 指令,后面的 commander 为该指令携带的参数</li><li>-g 选项</li></ul><h3 id="定义命令行工具能够提供哪些选项"><a href="#定义命令行工具能够提供哪些选项" class="headerlink" title="定义命令行工具能够提供哪些选项"></a>定义命令行工具能够提供哪些选项</h3><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">var</span> program = <span class="hljs-built_in">require</span>(<span class="hljs-string">'commander'</span>);program.option(flag, desc, fn, defaultValue)</code></pre></div><p>通过 option 方法我们可以定义命令行工具提供哪些选项,这些选项可以带参数,我们可以对参数进行自定义的再处理,我们还可以给参数赋值默认值。</p><ul><li>flag 必填。定义命令行参数能够提供哪些参数;</li><li>desc 非必填。对参数进行描述;</li><li>fn 非必填。是一个函数;</li><li>defaultValue 非必填。默认值;</li><li><> 符号表示参数必填,不填会报错;</li><li>[] 符号表示参数非必填。</li></ul><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-comment">// 表示命令行提供 -i 参数,--install 参数是 -i 的别名,二者作用相同</span><span class="hljs-comment">// 如果指令用到了这个参数,那么 program.install 的值就变成 true,否则为 false</span>program.option(<span class="hljs-string">'-i, --install'</span>)</code></pre></div><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-comment">// 第二个参数是对选项 -i 的描述信息</span>program.option(<span class="hljs-string">'-i, --install <packagename>'</span>, <span class="hljs-string">'install some package'</span>)</code></pre></div><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-comment">// 更改 program.install 的值,变成 handle 函数的返回值</span><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handle</span> (<span class="hljs-params">arg</span>) </span>{ <span class="hljs-comment">// 这里的 arg 等于选项后面跟着的参数 packagename 的值</span> <span class="hljs-comment">// 对 arg 处理然后返回处理后的值 afterarg,如将参数转换为数组并返回</span> <span class="hljs-keyword">return</span> arg.split(<span class="hljs-string">','</span>);}<span class="hljs-comment">// 第三个参数为函数,名称可以任意取值</span>program.option(<span class="hljs-string">'-i, --install <packagename>'</span>, <span class="hljs-string">'install some package'</span>, handle)</code></pre></div><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-comment">// 如果第三个参数不是函数而是字符串,表示是 packagename 的默认值,packagename 如果不输入值,就赋值默认值</span>program.option(<span class="hljs-string">'-i, --install <packagename>'</span>, <span class="hljs-string">'install some package'</span>, <span class="hljs-string">'commander'</span>)</code></pre></div><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handle</span> (<span class="hljs-params">arg</span>) </span>{ <span class="hljs-comment">// 处理后返回值</span>}<span class="hljs-comment">// 第三个参数是函数,第四个参数依然是 packagename 的默认值,如果 packagename 没有值,</span><span class="hljs-comment">// 就会将第一个参数的值赋值给 packagename,再将 packagename 作为参数传给 handle 函数</span>program.option(<span class="hljs-string">'-i, --install <packagename>'</span>, <span class="hljs-string">'install some package'</span>, handle, <span class="hljs-string">'commander'</span>)</code></pre></div><h3 id="案例"><a href="#案例" class="headerlink" title="案例"></a>案例</h3><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">var</span> program = <span class="hljs-built_in">require</span>(<span class="hljs-string">'commander'</span>);<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">delfun</span> (<span class="hljs-params">arg</span>) </span>{ <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'接收到的参数 packagename 为'</span> + arg); <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'可以对参数 arg 进行处理并返回'</span>); <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'返回值同时会赋值给 program.delete 属性'</span>);}program .version(<span class="hljs-string">'0.0.1'</span>) .option(<span class="hljs-string">'-i, --install [packagename]'</span>, <span class="hljs-string">'install some package'</span>) .option(<span class="hljs-string">'-u, --update [packagename]'</span>, <span class="hljs-string">'update some package'</span>) .option(<span class="hljs-string">'-d, --del [packagename]'</span>, <span class="hljs-string">'delete some package'</span>, delfun, <span class="hljs-string">'defval'</span>) .parse(process.argv);<span class="hljs-comment">// 命令行中使用到的参数会变成 true 进行标识,没有使用到的参数标识值为 false</span><span class="hljs-keyword">if</span> (program.install) <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'调用了 -i 参数,我们可以对 -i 参数做具体处理'</span>)<span class="hljs-keyword">if</span> (program.update) <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'调用了 -u 参数,我们可以对 -u 参数做具体处理'</span>)<span class="hljs-keyword">if</span> (program.del) <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'调用了 -d 参数,我们可以对 -d 参数做具体处理'</span>)<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'验证 program.delete 属性值:'</span>, program.del);</code></pre></div><p><a href="https://my.oschina.net/dkvirus/blog/1204210">完整的博客</a></p>]]></content>
<tags>
<tag>commander</tag>
</tags>
</entry>
<entry>
<title>使用js实现MQTT</title>
<link href="/2019/12/17/%E4%BD%BF%E7%94%A8js%E5%AE%9E%E7%8E%B0MQTT/"/>
<url>/2019/12/17/%E4%BD%BF%E7%94%A8js%E5%AE%9E%E7%8E%B0MQTT/</url>
<content type="html"><![CDATA[<p>MQTT是一个长连接的通讯应用层协议,最大的特点是数据精简、消息可靠、Publish-Subscribe模式灵活易用。MQTT已经成为IoT传输的标准协议,应用非常广泛。</p><p>MQTT被广泛使用的一个重要的原因是MQTT的生态非常完善,同时也支持JavaScript。因此下图所示的所有链路和模块,都可以通过JavaScript实现。<br><img src="/images/mqtt.png" alt="avatar"></p><h3 id="JavaScript在MQTT架构中常用的框架"><a href="#JavaScript在MQTT架构中常用的框架" class="headerlink" title="JavaScript在MQTT架构中常用的框架"></a>JavaScript在MQTT架构中常用的框架</h3><p>mosca(<a href="https://github.com/mcollina/mosca%EF%BC%89">https://github.com/mcollina/mosca)</a><br>mosca是一个用JavaScript实现的MQTT Broker。不仅如此,mosca还增加了对数据库,如Redis、MongoDB的支持,用来实现消息数据的存储。</p><p>MQTT.js(<a href="https://github.com/mqttjs/MQTT.js%EF%BC%89">https://github.com/mqttjs/MQTT.js)</a><br>MQTT.js是官网推荐的JavaScript实现的Client端。</p><p>KOA和Express<br>这两者都是非常主流的Node版本的Server,简单易用。</p><h3 id="Broker端的实现"><a href="#Broker端的实现" class="headerlink" title="Broker端的实现"></a>Broker端的实现</h3><p>如果在公司的局域网开发,则可以忽略这一步</p><ul><li>1.安装mosca。</li></ul><div class="code-wrapper"><pre><code class="hljs javascript">nmp install mosca --save</code></pre></div><ul><li>2.启动mosca。这里需要注意,如果本地没有配置MongoDB,则需要把ascoltatore中的内容全部注释掉。</li></ul><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">var</span> mosca = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mosca'</span>);<span class="hljs-keyword">var</span> ascoltatore = { <span class="hljs-comment">//using ascoltatore</span> <span class="hljs-comment">// type: 'mongo',</span> <span class="hljs-comment">// url: 'mongodb://localhost:27017/mqtt',</span> <span class="hljs-comment">// pubsubCollection: 'ascoltatori',</span> <span class="hljs-comment">// mongo: {}</span>};<span class="hljs-keyword">var</span> settings = { <span class="hljs-attr">port</span>: <span class="hljs-number">1883</span>, <span class="hljs-attr">backend</span>: ascoltatore};<span class="hljs-keyword">var</span> server = <span class="hljs-keyword">new</span> mosca.Server(settings);server.on(<span class="hljs-string">'clientConnected'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">client</span>) </span>{ <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'client connected'</span>, client.id);});<span class="hljs-comment">// fired when a message is received</span>server.on(<span class="hljs-string">'published'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">packet, client</span>) </span>{ <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Published'</span>, packet.payload); <span class="hljs-comment">//{"clientId":"mqttjs_02fea7b4","topic":"/tips"}</span> <span class="hljs-comment">// console.log('>>>packet', packet); //{"clientId":"mqttjs_02fea7b4","topic":"/tips"}</span>});server.on(<span class="hljs-string">'ready'</span>, setup);<span class="hljs-comment">// fired when the mqtt server is ready</span><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setup</span>(<span class="hljs-params"></span>) </span>{ <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Mosca server is up and running'</span>);}</code></pre></div><p>代码完成后,启动文件,本地的一个Broker就跑在localhost的1883端口上了。</p><h3 id="Client端发布实现"><a href="#Client端发布实现" class="headerlink" title="Client端发布实现"></a>Client端发布实现</h3><p>Client使用MQTT.js实现<br>当我们发布一个topic时,要用到publish方法,该方法第一个参数为字符串格式的topic<br>第二个参数可有可无,为字符串格式的消息内容</p><ul><li>1.安装</li></ul><div class="code-wrapper"><pre><code class="hljs javascript">npm install mqtt --save</code></pre></div><ul><li>2.启动</li></ul><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">var</span> mqtt = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mqtt'</span>);<span class="hljs-comment">//创建一个链接</span><span class="hljs-keyword">var</span> client = mqtt.connect(<span class="hljs-string">'mqtt://localhost:1883'</span>);<span class="hljs-comment">//链接成功时</span>client.on(<span class="hljs-string">'connect'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{ <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'>>> connected'</span>) <span class="hljs-comment">// client.subscribe('/tips')</span> <span class="hljs-built_in">setInterval</span>( <span class="hljs-comment">//定时发布消息</span> <span class="hljs-function">()=></span>{client.publish(<span class="hljs-string">'/temperature'</span>, <span class="hljs-string">'30'</span>);}, <span class="hljs-number">3000</span> );})<span class="hljs-comment">//链接错误时</span>client.on(<span class="hljs-string">'error'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{ <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'链接错误'</span>)})<span class="hljs-comment">//链接关闭时</span>client.on(<span class="hljs-string">'close'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{ <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'已关闭链接'</span>)})</code></pre></div><h3 id="Client端订阅实现"><a href="#Client端订阅实现" class="headerlink" title="Client端订阅实现"></a>Client端订阅实现</h3><p>订阅者要订阅一个topic,可以按条件筛选topic<br>注意,message是按照buffer格式传递的,所以要解析出数据</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">var</span> mqtt = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mqtt'</span>);<span class="hljs-comment">//创建一个链接</span><span class="hljs-keyword">var</span> client = mqtt.connect(<span class="hljs-string">'mqtt://localhost:1883'</span>);<span class="hljs-comment">//链接成功时</span>client.on(<span class="hljs-string">'connect'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{ <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'>>> connected'</span>) <span class="hljs-comment">//订阅一个topic</span> client.subscribe(<span class="hljs-string">'/temperature'</span>)})<span class="hljs-comment">//链接错误时</span>client.on(<span class="hljs-string">'error'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{ <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'链接错误'</span>)})<span class="hljs-comment">//链接关闭时</span>client.on(<span class="hljs-string">'close'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{ <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'已关闭链接'</span>)})<span class="hljs-comment">//当有消息时</span>client.on(<span class="hljs-string">'message'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">topic, message</span>) </span>{ <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'topic'</span>) <span class="hljs-comment">// /temperature</span> <span class="hljs-comment">// message is Buffer</span> <span class="hljs-built_in">console</span>.log(message.toString()) <span class="hljs-comment">// 30</span> <span class="hljs-comment">//消息传递完成后可以取消订阅</span> client.unsubscribe(<span class="hljs-string">'/temperature'</span>)})</code></pre></div><p>该案例是一个比较简单的通信案例:<br>A发布一个消息,B来订阅这个消息<br>同样的,A和B也可以既发布消息,也可以订阅消息</p><p><a href="https://blog.csdn.net/tangxiaoyin/article/details/73743166">戳此处👀别人家的博客</a></p>]]></content>
<tags>
<tag>MQTT</tag>
</tags>
</entry>
<entry>
<title>vue中的组件通信</title>
<link href="/2019/12/01/vue%E4%B8%AD%E7%9A%84%E7%BB%84%E4%BB%B6%E9%80%9A%E4%BF%A1/"/>
<url>/2019/12/01/vue%E4%B8%AD%E7%9A%84%E7%BB%84%E4%BB%B6%E9%80%9A%E4%BF%A1/</url>
<content type="html"><![CDATA[<p>vue中的组件通信无论是在做项目,还是笔试面试时都很重要</p><p>下面我们来说一说vue组件通信的三种情况</p><h3 id="父-gt-子"><a href="#父-gt-子" class="headerlink" title="父->子"></a>父->子</h3><p>父子组件通信是利用自定义属性传值,该情形分为两步:</p><ul><li>1.在父组件中,将子组件需要的成员绑定给一个自定义的属性。</li><li>2.在子组件中,通过props获得父组件放在子组件中的自定义属性值。</li></ul><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-comment">//父组件</span>Vue.component(<span class="hljs-string">'todo'</span>,{ <span class="hljs-attr">template</span>:<span class="hljs-string">`</span><span class="hljs-string"> <div></span><span class="hljs-string"> <h1>代办任务列表</h1></span><span class="hljs-string"> <todo-add></todo-add></span><span class="hljs-string"> <todo-list :msg='tasks'></todo-list></span><span class="hljs-string"> </div></span><span class="hljs-string"> `</span>, <span class="hljs-function"><span class="hljs-title">data</span>(<span class="hljs-params"></span>)</span>{ <span class="hljs-keyword">return</span> { <span class="hljs-attr">tasks</span>:[<span class="hljs-string">"吃饭"</span>,<span class="hljs-string">"睡觉"</span>,<span class="hljs-string">"打亮亮"</span>] } }, <span class="hljs-attr">components</span>:{ todoAdd, todoList }})</code></pre></div><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-comment">//子组件</span><span class="hljs-keyword">var</span> todoList={ <span class="hljs-attr">template</span>:<span class="hljs-string">`</span><span class="hljs-string"> <ul ></span><span class="hljs-string"> <todo-item v-for='(t,i) of tasks' :key='t' :t="t" :i="i"</span><span class="hljs-string"> :tasks="tasks"></span><span class="hljs-string"> </todo-item></span><span class="hljs-string"> </ul></span><span class="hljs-string"> `</span>, <span class="hljs-attr">props</span>:[<span class="hljs-string">'msg'</span>], <span class="hljs-attr">components</span>:{ todoItem }}</code></pre></div><h3 id="子-gt-父"><a href="#子-gt-父" class="headerlink" title="子->父"></a>子->父</h3><p>子->父是自定义事件传值,分飞两步:</p><ul><li>1.在父组件中,自定义一个事件,并绑定好事件处理函数</li><li>2.在子组件中,在自己的事件处理函数中通过$emit触发父组件的自定义事件,并传参</li></ul><div class="code-wrapper"><pre><code class="hljs html"><span class="hljs-comment"><!--父组件--></span><span class="hljs-tag"><<span class="hljs-name">template</span>></span><span class="hljs-tag"><<span class="hljs-name">div</span>></span> <span class="hljs-tag"><<span class="hljs-name">div</span>></span>{{fa}}<span class="hljs-tag"></<span class="hljs-name">div</span>></span> <span class="hljs-tag"><<span class="hljs-name">sun</span> @<span class="hljs-attr">show</span>=<span class="hljs-string">"showon"</span>></span><span class="hljs-tag"></<span class="hljs-name">sun</span>></span><span class="hljs-tag"></<span class="hljs-name">div</span>></span><span class="hljs-tag"></<span class="hljs-name">template</span>></span><span class="hljs-tag"><<span class="hljs-name">script</span>></span><span class="javascript"></span><span class="javascript"><span class="hljs-keyword">import</span> sun <span class="hljs-keyword">from</span> <span class="hljs-string">"./child.vue"</span></span><span class="javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {</span><span class="javascript"> <span class="hljs-function"><span class="hljs-title">data</span>(<span class="hljs-params"></span>)</span>{</span><span class="javascript"> <span class="hljs-keyword">return</span>{</span><span class="javascript"> <span class="hljs-attr">fa</span>:<span class="hljs-string">"这是父组件的值"</span></span><span class="javascript"> }</span><span class="javascript"> },</span><span class="javascript"> <span class="hljs-attr">methods</span>:{</span><span class="javascript"> <span class="hljs-function"><span class="hljs-title">showon</span>(<span class="hljs-params">data</span>)</span>{</span><span class="javascript"> <span class="hljs-built_in">this</span>.fa=data</span><span class="javascript"> }</span><span class="javascript"> },</span><span class="javascript"> <span class="hljs-attr">components</span>:{</span><span class="javascript"> sun</span><span class="javascript"> }</span><span class="javascript">}</span><span class="javascript"></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span></code></pre></div><div class="code-wrapper"><pre><code class="hljs html"><span class="hljs-comment"><!--子组件--></span><span class="hljs-tag"><<span class="hljs-name">template</span>></span> <span class="hljs-tag"><<span class="hljs-name">div</span>></span> <span class="hljs-tag"><<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"change"</span>></span>传递<span class="hljs-tag"></<span class="hljs-name">button</span>></span> <span class="hljs-tag"></<span class="hljs-name">div</span>></span><span class="hljs-tag"></<span class="hljs-name">template</span>></span><span class="hljs-tag"><<span class="hljs-name">script</span>></span><span class="javascript"></span><span class="javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {</span><span class="javascript"> <span class="hljs-attr">methods</span>:{</span><span class="javascript"> <span class="hljs-function"><span class="hljs-title">change</span>(<span class="hljs-params"></span>)</span>{</span><span class="javascript"> <span class="hljs-built_in">this</span>.$emit(<span class="hljs-string">"show"</span>,<span class="hljs-string">"这是子组件的内容"</span>)</span><span class="javascript"> }</span><span class="javascript"> }</span><span class="javascript">}</span><span class="javascript"></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span></code></pre></div><h3 id="兄弟之间传值"><a href="#兄弟之间传值" class="headerlink" title="兄弟之间传值"></a>兄弟之间传值</h3><p>该情况有点特殊,分为三步:</p><ul><li>1.在脚手架中创建一个公共的new Vue实例;用来保存事件,并关联到任何一个组件的处理函数上</li><li>2.数据的接受方组件,在自己加载完成后,向公共实例上添加一个自定义的事件,事件要绑定上自己的一个处理函数</li><li>3.发送方要在自己的事件处理函数中,找到公共实例对象,用$emit()触发别人提前在bus上绑定好的事件,并传参</li></ul><p>1.单独创建一个bus.js</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">import</span> Vue <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span><span class="hljs-comment">//一个公共的new Vue实例</span><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">new</span> Vue();</code></pre></div><p>2.main.js中</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">import</span> bus <span class="hljs-keyword">from</span> <span class="hljs-string">'./bus'</span><span class="hljs-comment">//放在原型对象上,任何一个组件都可以访问</span>Vue.prototype.bus=bus;Vue.config.productionTip = <span class="hljs-literal">false</span><span class="hljs-keyword">new</span> Vue({ router, store, <span class="hljs-attr">render</span>: <span class="hljs-function"><span class="hljs-params">h</span> =></span> h(App)}).$mount(<span class="hljs-string">'#app'</span>)</code></pre></div><p>3.数据的接受方,用$on向公共实例上添加一个自定义事件,并绑上自己的处理函数</p><div class="code-wrapper"><pre><code class="hljs html"><span class="hljs-tag"><<span class="hljs-name">template</span>></span> <span class="hljs-tag"><<span class="hljs-name">ul</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"todo-list"</span>></span> <span class="hljs-tag"><<span class="hljs-name">todo-item</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"(task,i) of tasks"</span> <span class="hljs-attr">:key</span>=<span class="hljs-string">"i"</span> <span class="hljs-attr">:i</span>=<span class="hljs-string">"i"</span>></span> <span class="hljs-tag"><<span class="hljs-name">template</span> <span class="hljs-attr">slot</span>=<span class="hljs-string">"task"</span>></span>{{task}}<span class="hljs-tag"></<span class="hljs-name">template</span>></span> <span class="hljs-tag"></<span class="hljs-name">todo-item</span>></span> <span class="hljs-tag"></<span class="hljs-name">ul</span>></span><span class="hljs-tag"></<span class="hljs-name">template</span>></span><span class="hljs-tag"><<span class="hljs-name">script</span>></span><span class="javascript"></span><span class="javascript"><span class="hljs-keyword">import</span> todoItem <span class="hljs-keyword">from</span> <span class="hljs-string">"./TodoItem"</span></span><span class="javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {</span><span class="javascript"> <span class="hljs-function"><span class="hljs-title">data</span>(<span class="hljs-params"></span>)</span>{</span><span class="javascript"> <span class="hljs-keyword">return</span> {</span><span class="javascript"> <span class="hljs-attr">tasks</span>:[<span class="hljs-string">'吃饭'</span>,<span class="hljs-string">'睡觉'</span>,<span class="hljs-string">"打亮亮"</span>]</span><span class="javascript"> }</span><span class="javascript"> },</span><span class="javascript"> <span class="hljs-function"><span class="hljs-title">created</span>(<span class="hljs-params"></span>)</span>{</span><span class="javascript"> <span class="hljs-comment">//回调中的函数this指window,所以必须用bind永久绑定当前组件</span></span><span class="javascript"> <span class="hljs-built_in">this</span>.bus.$on(<span class="hljs-string">"add_task"</span>,<span class="hljs-built_in">this</span>.add.bind(<span class="hljs-built_in">this</span>))</span><span class="javascript"> },</span><span class="javascript"> <span class="hljs-attr">methods</span>:{</span><span class="javascript"> <span class="hljs-function"><span class="hljs-title">add</span>(<span class="hljs-params">task</span>)</span>{</span><span class="javascript"> <span class="hljs-built_in">this</span>.tasks.push(task);</span><span class="javascript"> }</span><span class="javascript"> },</span><span class="javascript"> <span class="hljs-attr">components</span>:{</span><span class="javascript"> todoItem</span><span class="javascript"> }</span><span class="javascript">}</span><span class="javascript"></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span></code></pre></div><p>4.数据的发送方,用$emit触发别人在公共实例上绑定好的事件,并传参</p><div class="code-wrapper"><pre><code class="hljs html"><span class="hljs-tag"><<span class="hljs-name">template</span>></span> <span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"todo-add"</span>></span> <span class="hljs-tag"><<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"task"</span>></span><span class="hljs-tag"><<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"add"</span>></span>+<span class="hljs-tag"></<span class="hljs-name">button</span>></span> <span class="hljs-tag"></<span class="hljs-name">div</span>></span><span class="hljs-tag"></<span class="hljs-name">template</span>></span><span class="hljs-tag"><<span class="hljs-name">script</span>></span><span class="javascript"></span><span class="javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {</span><span class="javascript"> <span class="hljs-function"><span class="hljs-title">data</span>(<span class="hljs-params"></span>)</span>{</span><span class="javascript"> <span class="hljs-keyword">return</span> {</span><span class="javascript"> <span class="hljs-attr">task</span>:<span class="hljs-string">""</span></span><span class="javascript"> }</span><span class="javascript"> },</span><span class="javascript"> <span class="hljs-attr">methods</span>:{</span><span class="javascript"> <span class="hljs-function"><span class="hljs-title">add</span>(<span class="hljs-params"></span>)</span>{</span><span class="javascript"> <span class="hljs-built_in">this</span>.bus.$emit(<span class="hljs-string">"add_task"</span>,<span class="hljs-built_in">this</span>.task);</span><span class="javascript"> <span class="hljs-built_in">this</span>.task=<span class="hljs-string">""</span>;</span><span class="javascript"> }</span><span class="javascript"> }</span><span class="javascript">}</span><span class="javascript"></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span></code></pre></div>]]></content>
<tags>
<tag>vue</tag>
</tags>
</entry>
<entry>
<title>React中的数据绑定</title>
<link href="/2019/11/27/React%E4%B8%AD%E7%9A%84%E5%8F%8C%E5%90%91%E6%95%B0%E6%8D%AE%E7%BB%91%E5%AE%9A/"/>
<url>/2019/11/27/React%E4%B8%AD%E7%9A%84%E5%8F%8C%E5%90%91%E6%95%B0%E6%8D%AE%E7%BB%91%E5%AE%9A/</url>
<content type="html"><![CDATA[<p>React中没有指令的概念,故v-model、ngModel都没有;使用“受控组件”来实现双向数据绑定的功能</p><h3 id="条件渲染"><a href="#条件渲染" class="headerlink" title="条件渲染"></a>条件渲染</h3><p>使用内容绑定一个函数(该函数中根据条件返回不同的JSX片段)</p><div class="code-wrapper"><pre><code class="hljs html">printWelcome(){if(...) return (<span class="hljs-tag"><<span class="hljs-name">div</span>></span>...<span class="hljs-tag"></<span class="hljs-name">div</span>></span>)else return (<span class="hljs-tag"><<span class="hljs-name">p</span>></span>...<span class="hljs-tag"></<span class="hljs-name">p</span>></span>)}<span class="hljs-tag"><<span class="hljs-name">div</span>></span>{ this.printWelcome() }<span class="hljs-tag"></<span class="hljs-name">div</span>></span></code></pre></div><p>当然你在项目中也可以这样写:</p><div class="code-wrapper"><pre><code class="hljs html">import React from 'react'export default class App extends React.Component{ constructor(){ super() this.state={ todoList:["eat","play","dance","xixi"], } } render(){ return( <span class="hljs-tag"><<span class="hljs-name">div</span>></span> <span class="hljs-tag"><<span class="hljs-name">h1</span>></span>代办事项列表<span class="hljs-tag"></<span class="hljs-name">h1</span>></span> { (()=>{ if(this.state.todoList.length===0){ //可以采用匿名函数自调用的方式,返回一个JSX片段 return <span class="hljs-tag"><<span class="hljs-name">p</span>></span>当前没有代办事项<span class="hljs-tag"></<span class="hljs-name">p</span>></span> } })() } <span class="hljs-tag"></<span class="hljs-name">div</span>></span> ) }}</code></pre></div><h3 id="循环渲染"><a href="#循环渲染" class="headerlink" title="循环渲染"></a>循环渲染</h3><p>前提:React中的内容绑定如果绑定了数组的话,会自动把每个元素提取出来作为当前父节点的子节点——利用此特性,只需要把数组转换为JSX数组直接做内容绑定即可</p><div class="code-wrapper"><pre><code class="hljs html">import React from 'react'export default class App extends React.Component{ constructor(){ super() this.state={ todoList:["eat","play","dance","xixi"], } } render(){ return( <span class="hljs-tag"><<span class="hljs-name">div</span>></span> <span class="hljs-tag"><<span class="hljs-name">h1</span>></span>代办事项列表<span class="hljs-tag"></<span class="hljs-name">h1</span>></span> <span class="hljs-tag"><<span class="hljs-name">ul</span>></span> { this.state.todoList.map((todo,i)=>{ //遍历数组实现循环渲染 return( <span class="hljs-tag"><<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{i}</span>></span> {i+1}-{todo} <span class="hljs-tag"></<span class="hljs-name">li</span>></span> ) }) } <span class="hljs-tag"></<span class="hljs-name">ul</span>></span> <span class="hljs-tag"></<span class="hljs-name">div</span>></span> ) }}</code></pre></div><h3 id="双向数据绑定"><a href="#双向数据绑定" class="headerlink" title="双向数据绑定"></a>双向数据绑定</h3><p>提示:React中没有指令的概念,故v-model、ngModel都没有;使用“受控组件”来实现双向数据绑定的功能</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-comment">//方向1:Model=>View,状态数据绑定到表单输入元素的value</span><span class="hljs-function"><span class="hljs-title">constructor</span>(<span class="hljs-params"></span>)</span>{ <span class="hljs-built_in">super</span>() <span class="hljs-built_in">this</span>.state = { <span class="hljs-attr">userInput</span>: <span class="hljs-string">''</span> }}<input value={ <span class="hljs-built_in">this</span>.state.userInput }/><span class="hljs-comment">//方向2:View=>Model,表单输入事件反过来要影响状态</span>doChange = <span class="hljs-function">(<span class="hljs-params"> e </span>)=></span>{ <span class="hljs-built_in">this</span>.setState({ <span class="hljs-attr">userInput</span>: e.target.value })}<input onChange={<span class="hljs-built_in">this</span>.doChange} value={ <span class="hljs-built_in">this</span>.state.userInput }/></code></pre></div><h3 id="todoList"><a href="#todoList" class="headerlink" title="todoList"></a>todoList</h3><p>下面我们将条件渲染、循环渲染、和双向数据绑定联合起来实现代办事项列表</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">App</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span></span>{ <span class="hljs-function"><span class="hljs-title">constructor</span>(<span class="hljs-params"></span>)</span>{ <span class="hljs-built_in">super</span>() <span class="hljs-built_in">this</span>.state={ <span class="hljs-attr">todoList</span>:[<span class="hljs-string">"eat"</span>,<span class="hljs-string">"play"</span>,<span class="hljs-string">"dance"</span>,<span class="hljs-string">"xixi"</span>], <span class="hljs-attr">userInput</span>:<span class="hljs-string">''</span> } } change=<span class="hljs-function">(<span class="hljs-params">e</span>)=></span>{ <span class="hljs-built_in">this</span>.setState({ <span class="hljs-attr">userInput</span>:e.target.value }) } add=<span class="hljs-function">()=></span>{ <span class="hljs-keyword">let</span> todoList=<span class="hljs-built_in">this</span>.state.todoList todoList.push(<span class="hljs-built_in">this</span>.state.userInput) <span class="hljs-built_in">this</span>.setState({ <span class="hljs-attr">todoList</span>:todoList, <span class="hljs-attr">userInput</span>:<span class="hljs-string">''</span> }) } <span class="hljs-function"><span class="hljs-title">delete</span>(<span class="hljs-params">i</span>)</span>{ <span class="hljs-keyword">let</span> todoList=<span class="hljs-built_in">this</span>.state.todoList todoList.splice(i,<span class="hljs-number">1</span>) <span class="hljs-built_in">this</span>.setState({<span class="hljs-attr">todoList</span>:todoList}) } <span class="hljs-function"><span class="hljs-title">render</span>(<span class="hljs-params"></span>)</span>{ <span class="hljs-keyword">return</span>( <span class="xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span></span><span class="xml"> <span class="hljs-tag"><<span class="hljs-name">h1</span>></span>代办事项列表<span class="hljs-tag"></<span class="hljs-name">h1</span>></span></span><span class="xml"> <span class="hljs-tag"><<span class="hljs-name">hr</span>/></span></span><span class="xml"> <span class="hljs-tag"><<span class="hljs-name">input</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{this.change}</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{this.state.userInput}</span> /></span></span><span class="xml"> <span class="hljs-tag"><<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{this.add}</span>></span>添加事项<span class="hljs-tag"></<span class="hljs-name">button</span>></span></span><span class="xml"> { //条件渲染</span><span class="xml"> (()=>{</span><span class="xml"> if(this.state.todoList.length===0){</span><span class="xml"> return <span class="hljs-tag"><<span class="hljs-name">p</span>></span>当前没有代办事项<span class="hljs-tag"></<span class="hljs-name">p</span>></span></span><span class="xml"> }</span><span class="xml"> })()</span><span class="xml"> }</span><span class="xml"> <span class="hljs-tag"><<span class="hljs-name">ul</span>></span></span><span class="xml"> { //循环渲染</span><span class="xml"> this.state.todoList.map((todo,i)=>{</span><span class="xml"> return(</span><span class="xml"> <span class="hljs-tag"><<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{i}</span>></span></span><span class="xml"> {i+1}-{todo}</span><span class="xml"> <span class="hljs-comment"><!-- 此时delete方法要传递参数,因此立即调用该函数--></span></span><span class="xml"> <span class="hljs-tag"><<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span>=></span>{this.delete(i)}}>删除<span class="hljs-tag"></<span class="hljs-name">button</span>></span></span><span class="xml"> <span class="hljs-tag"></<span class="hljs-name">li</span>></span></span><span class="xml"> )</span><span class="xml"> })</span><span class="xml"> }</span><span class="xml"> <span class="hljs-tag"></<span class="hljs-name">ul</span>></span></span><span class="xml"> <span class="hljs-tag"></<span class="hljs-name">div</span>></span></span> ) }}</code></pre></div>]]></content>
<tags>
<tag>React</tag>
</tags>
</entry>
<entry>
<title>vue中的watch(深度监听)</title>
<link href="/2019/11/25/vue%E4%B8%AD%E7%9A%84watch-%E6%B7%B1%E5%BA%A6%E7%9B%91%E5%90%AC/"/>
<url>/2019/11/25/vue%E4%B8%AD%E7%9A%84watch-%E6%B7%B1%E5%BA%A6%E7%9B%91%E5%90%AC/</url>
<content type="html"><![CDATA[<p>让人容易忽视的是,watch中有两个属性,一个方法,分别是immediate,deep属性和handler方法</p><h3 id="handler方法和immediate属性"><a href="#handler方法和immediate属性" class="headerlink" title="handler方法和immediate属性"></a>handler方法和immediate属性</h3><p>我们先来看一段代码</p><div class="code-wrapper"><pre><code class="hljs html"><span class="hljs-tag"><<span class="hljs-name">div</span>></span> <span class="hljs-tag"><<span class="hljs-name">p</span>></span>FullName: {{fullName}}<span class="hljs-tag"></<span class="hljs-name">p</span>></span> <span class="hljs-tag"><<span class="hljs-name">p</span>></span>FirstName: <span class="hljs-tag"><<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"firstName"</span>></span><span class="hljs-tag"></<span class="hljs-name">p</span>></span><span class="hljs-tag"></<span class="hljs-name">div</span>></span>new Vue({ el: '#root', data: { firstName: 'Dawei', lastName: 'Lou', fullName: '' }, watch: { firstName(newName, oldName) { this.fullName = newName + ' ' + this.lastName; } } })</code></pre></div><p>上面的代码的效果是,当我们输入firstName后,wacth监听每次修改变化的新值,然后计算输出fullName。</p><p>这里 watch 的一个特点是,最初绑定的时候是不会执行的,要等到 firstName 改变时才执行监听计算。那我们想要一开始就让他最初绑定的时候就执行改怎么办呢?我们需要修改一下我们的 watch 写法,修改过后的 watch 代码如下:</p><div class="code-wrapper"><pre><code class="hljs javascript">watch: { <span class="hljs-attr">firstName</span>: { <span class="hljs-function"><span class="hljs-title">handler</span>(<span class="hljs-params">newName, oldName</span>)</span> { <span class="hljs-built_in">this</span>.fullName = newName + <span class="hljs-string">' '</span> + <span class="hljs-built_in">this</span>.lastName; }, <span class="hljs-comment">// 代表在wacth里声明了firstName这个方法之后立即先去执行handler方法</span> <span class="hljs-comment">//而不是等待改变后</span> <span class="hljs-attr">immediate</span>: <span class="hljs-literal">true</span> }}</code></pre></div><p>我们给 firstName 绑定了一个handler方法,之前我们写的 watch 方法其实默认写的就是这个handler,Vue.js会去处理这个逻辑,最终编译出来其实就是这个handler。</p><p>而immediate:true代表如果在 wacth 里声明了 firstName 之后,就会立即先去执行里面的handler方法,如果为 false就跟我们以前的效果一样,不会在绑定的时候就执行。</p><h3 id="deep属性"><a href="#deep属性" class="headerlink" title="deep属性"></a>deep属性</h3><p>watch 里面还有一个属性 deep,默认值是 false,代表是否深度监听,比如我们 data 里有一个obj属性:</p><div class="code-wrapper"><pre><code class="hljs html"><span class="hljs-tag"><<span class="hljs-name">div</span>></span> <span class="hljs-tag"><<span class="hljs-name">p</span>></span>obj.a: {{obj.a}}<span class="hljs-tag"></<span class="hljs-name">p</span>></span> <span class="hljs-tag"><<span class="hljs-name">p</span>></span>obj.a: <span class="hljs-tag"><<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"obj.a"</span>></span><span class="hljs-tag"></<span class="hljs-name">p</span>></span><span class="hljs-tag"></<span class="hljs-name">div</span>></span>new Vue({ el: '#root', data: { obj: { a: 123 } }, watch: { obj: { handler(newName, oldName) { console.log('obj.a changed'); }, immediate: true } } })</code></pre></div><p>当我们改变input框中的属性时,控制台不会输出’obj.a changed’,因为此时监听的是obj这个对象(地址一直未改变),所以obj里面的属性的添加或删除并不会触发监听</p><p>当我们要满足这个需求时,deep属性就派上用场了!</p><div class="code-wrapper"><pre><code class="hljs javascript">watch: { <span class="hljs-attr">obj</span>: { <span class="hljs-comment">//当监听的是一个引用类型的值时,newValue和oldValue相同</span> <span class="hljs-function"><span class="hljs-title">handler</span>(<span class="hljs-params">newName, oldName</span>)</span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'obj.a changed'</span>); }, <span class="hljs-attr">immediate</span>: <span class="hljs-literal">true</span>, <span class="hljs-attr">deep</span>: <span class="hljs-literal">true</span> }}</code></pre></div><p>deep的意思就是深入观察,监听器会一层层的往下遍历,给对象的所有属性都加上这个监听器,但是这样性能开销就会非常大了,任何修改obj里面任何一个属性都会触发这个监听器里的 handler。</p><p>为了优化,我们可以使用字符串形式监听:</p><div class="code-wrapper"><pre><code class="hljs javascript">watch: { <span class="hljs-string">'obj.a'</span>: { <span class="hljs-function"><span class="hljs-title">handler</span>(<span class="hljs-params">newName, oldName</span>)</span> { <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'obj.a changed'</span>); }, <span class="hljs-attr">immediate</span>: <span class="hljs-literal">true</span>, <span class="hljs-comment">//deep: true</span> }}</code></pre></div><p>这样Vue.js才会一层一层解析下去,直到遇到属性a,然后才给a设置监听函数。</p><p>注意:当监听的是一个引用类型的值时,newValue和oldValue相同</p><p><a href="https://www.cnblogs.com/yesu/p/9546458.html">戳此处👀别人家的博客</a></p>]]></content>
<tags>
<tag>vue</tag>
</tags>
</entry>
<entry>
<title>vuex中辅助函数</title>
<link href="/2019/11/24/vuex%E4%B8%AD%E8%BE%85%E5%8A%A9%E5%87%BD%E6%95%B0/"/>
<url>/2019/11/24/vuex%E4%B8%AD%E8%BE%85%E5%8A%A9%E5%87%BD%E6%95%B0/</url>
<content type="html"><![CDATA[<p><span>在正规的公司开发中很少用:</span></p><p>this.$store.commit(“xxx”),this.$store.dispatch(“xxx”),this.$store.state.xxx,因为这样显得十分累赘,所以此时就推荐用辅助函数来替代。</p><p>以下三个例子都公用一个store.js</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-keyword">import</span> Vue <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span><span class="hljs-keyword">import</span> Vuex <span class="hljs-keyword">from</span> <span class="hljs-string">'vuex'</span><span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>Vue.use(Vuex)<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">new</span> Vuex.Store({ <span class="hljs-attr">state</span>: { <span class="hljs-attr">uname</span>:<span class="hljs-string">""</span> }, <span class="hljs-attr">mutations</span>: { <span class="hljs-comment">//专门负责修改state中的变量</span> <span class="hljs-function"><span class="hljs-title">setUname</span>(<span class="hljs-params">state,uname</span>)</span>{ state.uname=uname; } }, <span class="hljs-attr">actions</span>: { <span class="hljs-comment">//专门负责发送异步ajax请求,从服务器端获取数据</span> <span class="hljs-function"><span class="hljs-title">login</span>(<span class="hljs-params">context,user</span>)</span>{ <span class="hljs-comment">//context代表整个vuex对象</span> (<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{ <span class="hljs-keyword">var</span> result=<span class="hljs-keyword">await</span> axios.get(<span class="hljs-string">"/users/signin"</span>,{ <span class="hljs-attr">params</span>:user }); context.commit(<span class="hljs-string">"setUname"</span>,result.data.uname); })() } }, <span class="hljs-attr">modules</span>: { }})</code></pre></div><h3 id="mapState"><a href="#mapState" class="headerlink" title="mapState"></a>mapState</h3><p>当一个组件需要获取多个状态时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用 mapState 辅助函数帮助我们生成<span style="color:red">计算属性</span>,让你少按几次键:</p><div class="code-wrapper"><pre><code class="hljs html"><span class="hljs-tag"><<span class="hljs-name">template</span>></span> <span class="hljs-tag"><<span class="hljs-name">h1</span> <span class="hljs-attr">v-else</span>></span>Welcome {{uname}}<span class="hljs-tag"></<span class="hljs-name">h1</span>></span><span class="hljs-tag"></<span class="hljs-name">template</span>></span><span class="hljs-tag"><<span class="hljs-name">script</span>></span><span class="javascript"></span><span class="javascript"><span class="hljs-keyword">import</span> {mapState} <span class="hljs-keyword">from</span> <span class="hljs-string">"vuex"</span></span><span class="javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {</span><span class="javascript"> <span class="hljs-attr">computed</span>:{</span><span class="javascript"> <span class="hljs-comment">// 使用对象展开运算符将此对象混入到外部对象中</span></span><span class="javascript"> ...mapState([<span class="hljs-string">"uname"</span>])</span><span class="javascript"> }</span><span class="javascript">}</span><span class="javascript"></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span></code></pre></div><h3 id="mapMutation"><a href="#mapMutation" class="headerlink" title="mapMutation"></a>mapMutation</h3><div class="code-wrapper"><pre><code class="hljs html"><span class="hljs-tag"><<span class="hljs-name">template</span>></span> <span class="hljs-tag"><<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"logout"</span>></span>注销<span class="hljs-tag"></<span class="hljs-name">button</span>></span><span class="hljs-tag"></<span class="hljs-name">template</span>></span><span class="hljs-tag"><<span class="hljs-name">script</span>></span><span class="javascript"></span><span class="javascript"> <span class="hljs-keyword">import</span> {mapMutations} <span class="hljs-keyword">from</span> <span class="hljs-string">"vuex"</span></span><span class="javascript"></span><span class="javascript"> <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {</span><span class="javascript"> <span class="hljs-attr">methods</span>:{</span><span class="javascript"> <span class="hljs-function"><span class="hljs-title">logout</span>(<span class="hljs-params"></span>)</span>{</span><span class="javascript"> <span class="hljs-built_in">this</span>.setUname(<span class="hljs-string">""</span>);</span><span class="javascript"> },</span><span class="javascript"> <span class="hljs-comment">//和其他方法同级</span></span><span class="javascript"> ...mapMutations([<span class="hljs-string">"setUname"</span>])</span><span class="javascript"> <span class="hljs-comment">//setUname(uname){ this.$store.commit("setName",uanme) }</span></span><span class="javascript"> }</span><span class="javascript"></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span></code></pre></div><h3 id="mapActions"><a href="#mapActions" class="headerlink" title="mapActions"></a>mapActions</h3><div class="code-wrapper"><pre><code class="hljs html"><span class="hljs-tag"><<span class="hljs-name">template</span>></span> <span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"home"</span>></span> 用户名:<span class="hljs-tag"><<span class="hljs-name">input</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"uname"</span>></span><span class="hljs-tag"><<span class="hljs-name">br</span>></span> 密码:<span class="hljs-tag"><<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"upwd"</span>></span><span class="hljs-tag"><<span class="hljs-name">br</span>></span> <span class="hljs-tag"><<span class="hljs-name">button</span> @<span class="hljs-attr">click</span>=<span class="hljs-string">"myLogin"</span>></span>登录<span class="hljs-tag"></<span class="hljs-name">button</span>></span> <span class="hljs-tag"></<span class="hljs-name">div</span>></span><span class="hljs-tag"></<span class="hljs-name">template</span>></span><span class="hljs-tag"><<span class="hljs-name">script</span>></span><span class="javascript"></span><span class="javascript"><span class="hljs-keyword">import</span> {mapActions} <span class="hljs-keyword">from</span> <span class="hljs-string">"vuex"</span></span><span class="javascript"></span><span class="javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {</span><span class="javascript"> <span class="hljs-attr">name</span>: <span class="hljs-string">'home'</span>,</span><span class="javascript"> <span class="hljs-function"><span class="hljs-title">data</span>(<span class="hljs-params"></span>)</span>{</span><span class="javascript"> <span class="hljs-keyword">return</span> {</span><span class="javascript"> <span class="hljs-attr">uname</span>:<span class="hljs-string">"dingding"</span>,</span><span class="javascript"> <span class="hljs-attr">upwd</span>:<span class="hljs-string">"123456"</span></span><span class="javascript"> }</span><span class="javascript"> },</span><span class="javascript"> <span class="hljs-attr">methods</span>:{</span><span class="javascript"> <span class="hljs-function"><span class="hljs-title">myLogin</span>(<span class="hljs-params"></span>)</span>{</span><span class="javascript"> <span class="hljs-built_in">this</span>.login({<span class="hljs-comment">//给user</span></span><span class="javascript"> <span class="hljs-attr">uname</span>:<span class="hljs-built_in">this</span>.uname,</span><span class="javascript"> <span class="hljs-attr">upwd</span>:<span class="hljs-built_in">this</span>.upwd</span><span class="javascript"> });</span><span class="javascript"> },</span><span class="javascript"> ...mapActions([<span class="hljs-comment">//去vuex的actions中取出名为login的函数放到此地</span></span><span class="javascript"> <span class="hljs-string">"login"</span><span class="hljs-comment">//,"logout","registor"</span></span><span class="javascript"> ])</span><span class="javascript"> <span class="hljs-comment">/**</span></span><span class="hljs-comment"><span class="javascript"> 原方法:</span></span><span class="hljs-comment"><span class="javascript"> * login(user){ </span></span><span class="hljs-comment"><span class="javascript"> * this.$store.dispatch("login",user)</span></span><span class="hljs-comment"><span class="javascript"> * },</span></span><span class="hljs-comment"><span class="javascript"> */</span></span><span class="javascript"> }</span><span class="javascript">}</span><span class="javascript"></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span></code></pre></div>]]></content>
<tags>
<tag>vuex</tag>
</tags>
</entry>
<entry>
<title>json-server</title>
<link href="/2019/11/23/json-server/"/>
<url>/2019/11/23/json-server/</url>
<content type="html"><![CDATA[<p><a href="https://blog.csdn.net/lhjuejiang/article/details/81475993">别人家的博客</a></p><h3 id="什么是json-server"><a href="#什么是json-server" class="headerlink" title="什么是json-server"></a>什么是json-server</h3><p>一个在前端本地运行,专门模拟后端接口地址的可以存储json数据的简易版server。</p><ul><li>今后,都是前后端分离方式开发</li><li>前后端是完全独立的两个项目</li><li>前后端两个项目是并行开发,也就是说前端项目开发时,后端接口还没开发好呢</li></ul><h3 id="json-server的安装"><a href="#json-server的安装" class="headerlink" title="json-server的安装"></a>json-server的安装</h3><p>全局环境下安装</p><div class="code-wrapper"><pre><code class="hljs javascript">npm install -g json-server</code></pre></div><h3 id="json-server的使用"><a href="#json-server的使用" class="headerlink" title="json-server的使用"></a>json-server的使用</h3><h4 id="1-定义db-json文件"><a href="#1-定义db-json文件" class="headerlink" title="1.定义db.json文件"></a>1.定义db.json文件</h4><p>基本格式如下</p><div class="code-wrapper"><pre><code class="hljs javascript">{ <span class="hljs-string">"接口名1"</span>: [ { 第一个数据对象的属性和值}, ... ... ], <span class="hljs-string">"接口名2"</span>:[ { 数据对象的属性和值 }, ... ... ]}</code></pre></div><p>在db.json文件所在目录,运行json-server</p><div class="code-wrapper"><pre><code class="hljs javascript">json-server --watch --port <span class="hljs-number">5050</span> db.json</code></pre></div><h4 id="2-get请求"><a href="#2-get请求" class="headerlink" title="2.get请求"></a>2.get请求</h4><p>get请求专门用于查询数据直接输入:<a href="http://localhost:5050/index">http://localhost:5050/index</a></p><p>当get请求携带参数时</p><ul><li><a href="http://localhost:5050/details/1%EF%BC%8C%E7%9B%B4%E6%8E%A5%E5%8F%AA%E8%BF%94%E5%9B%9Eid%E4%B8%BA1%E7%9A%84%E4%B8%80%E4%B8%AA%E5%95%86%E5%93%81%E5%AF%B9%E8%B1%A1">http://localhost:5050/details/1,直接只返回id为1的一个商品对象</a></li><li><a href="http://localhost:5050/details?id=1%EF%BC%8C%E5%8D%B4%E8%BF%94%E5%9B%9E%E4%B8%80%E4%B8%AA%E6%95%B0%E7%BB%84%EF%BC%8C%E5%8C%85%E5%90%AB%E6%9F%A5%E8%AF%A2%E5%88%B0%E7%9A%84%E7%BB%93%E6%9E%9C%E5%AF%B9%E8%B1%A1">http://localhost:5050/details?id=1,却返回一个数组,包含查询到的结果对象</a></li></ul><p>解决:定义一个路由翻译文件:<span style="color:red">routes.json</span>,他可以将服务器端的路由翻译成json-server的路由</p><div class="code-wrapper"><pre><code class="hljs javascript"><span class="hljs-comment">//routes.json文件中</span> { <span class="hljs-string">"/details\\?id=:id"</span>: <span class="hljs-string">"/details/:id"</span> }</code></pre></div><p>但是服务器端不是用id检索的,都是用lid检索的,为了和服务器端的接口统一应该写成:</p><div class="code-wrapper"><pre><code class="hljs javascript">{ <span class="hljs-string">"/details\\?lid=:id"</span>: <span class="hljs-string">"/details/:id"</span>}</code></pre></div><p><span style="color:red">注意:启动json-server时加载自定义路由</span></p><div class="code-wrapper"><pre><code class="hljs javascript">json-server --watch --port <span class="hljs-number">5050</span> --routes routes.json db.json</code></pre></div><p><span style="font-size:25px">模糊检索</span></p><p>如果希望与服务器端kws参数保持一致,也可用自定义路由将title_like转化为kws:</p><div class="code-wrapper"><pre><code class="hljs javascript">{ <span class="hljs-string">"/products\\?kws=:a"</span>:<span class="hljs-string">"/products?title_like=:a"</span>}</code></pre></div><h4 id="3-post请求"><a href="#3-post请求" class="headerlink" title="3.post请求"></a>3.post请求</h4><p>该请求专门用于插入数据</p><div class="code-wrapper"><pre><code class="hljs javascript">$(<span class="hljs-string">"#postBtn"</span>).click(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{ $.ajax({ <span class="hljs-attr">type</span>: <span class="hljs-string">'post'</span>, <span class="hljs-attr">url</span>: <span class="hljs-string">'http://localhost:3003/fruits'</span>, <span class="hljs-attr">data</span>: { <span class="hljs-attr">name</span>: $(<span class="hljs-string">"#fruitName"</span>).val(), <span class="hljs-attr">price</span>: $(<span class="hljs-string">"#fruitPrice"</span>).val() }, <span class="hljs-attr">success</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">data</span>)</span>{ <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"post success"</span>) }, <span class="hljs-attr">error</span>:<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{ alert(<span class="hljs-string">"post error"</span>) } })})</code></pre></div><h4 id="4-put请求"><a href="#4-put请求" class="headerlink" title="4.put请求"></a>4.put请求</h4><p>该请求专门用于修改数据</p><div class="code-wrapper"><pre><code class="hljs javascript">$(<span class="hljs-string">"#putBtn"</span>).click(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{ $.ajax({ <span class="hljs-attr">type</span>: <span class="hljs-string">'put'</span>, <span class="hljs-attr">url</span>: <span class="hljs-string">'http://localhost:3003/fruits/'</span>+ $(<span class="hljs-string">"#putId"</span>).val(), <span class="hljs-attr">data</span>: { <span class="hljs-attr">price</span>: $(<span class="hljs-string">"#putPrice"</span>).val() }, <span class="hljs-attr">success</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">data</span>)</span>{ <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"put success"</span>) }, <span class="hljs-attr">error</span>:<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{ alert(<span class="hljs-string">"put error"</span>) } })})</code></pre></div><h4 id="5-delete请求"><a href="#5-delete请求" class="headerlink" title="5.delete请求"></a>5.delete请求</h4><p>专门用于删除数据</p><div class="code-wrapper"><pre><code class="hljs javascript">$(<span class="hljs-string">"#delOne"</span>).click(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{ $.ajax({ <span class="hljs-attr">type</span>: <span class="hljs-string">'delete'</span>, <span class="hljs-attr">url</span>: <span class="hljs-string">'http://localhost:3003/fruits/'</span>+ $(<span class="hljs-string">"#delId"</span>).val(), <span class="hljs-attr">success</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">data</span>)</span>{ <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"del success"</span>) }, <span class="hljs-attr">error</span>:<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{ alert(<span class="hljs-string">"del error"</span>) } })})</code></pre></div><h3 id="强调"><a href="#强调" class="headerlink" title="强调"></a>强调</h3><ul><li>如果只是修改json文件的内容,不用重启服务器</li><li>post,put,delete操作都是直接修改硬盘上的db.json文件,所以,修改前,一定做好备份!</li></ul>]]></content>
<tags>
<tag>json-server</tag>
</tags>
</entry>
<entry>
<title>web实时通信</title>
<link href="/2019/11/21/web%E5%AE%9E%E6%97%B6%E9%80%9A%E4%BF%A1/"/>
<url>/2019/11/21/web%E5%AE%9E%E6%97%B6%E9%80%9A%E4%BF%A1/</url>
<content type="html"><![CDATA[<h3 id="Web端即时通讯技术"><a href="#Web端即时通讯技术" class="headerlink" title="Web端即时通讯技术"></a>Web端即时通讯技术</h3><p>即时通讯技术简单的说就是实现这样一种功能:服务器端可以即时地将数据的更新或变化反应到客户端,例如消息即时推送等功能都是通过这种技术实现的。</p><p>但是在Web中,由于浏览器的限制,实现即时通讯需要借助一些方法。这种限制出现的主要原因是,一般的Web通信都是浏览器先发送请求到服务器,服务器再进行响应完成数据的现实更新。</p><h3 id="实现Web端即时通讯的方法"><a href="#实现Web端即时通讯的方法" class="headerlink" title="实现Web端即时通讯的方法"></a>实现Web端即时通讯的方法</h3><p>它们大体可以分为两类,一种是在<span style="color:red">HTTP基础</span>上实现的,包括短轮询、长轮询(comet)和SSE;</p><p>另一种不是在HTTP基础上实现是,即WebSocket。</p><h4 id="1-短轮询"><a href="#1-短轮询" class="headerlink" title="1.短轮询"></a>1.短轮询</h4><p>短轮询的基本思路就是<span style="color:#49b94d;">浏览器每隔一段时间向浏览器发送http请求,服务器端在收到请求后,不论是否有数据更新,都直接进行响应。</span>这种方式实现的即时通信,本质上还是浏览器发送请求,服务器接受请求的一个过程,通过让客户端不断的进行请求,使得客户端能够模拟实时地收到服务器端的数据的变化。</p><p>这种方式的优点是比较简单,易于理解,实现起来也没有什么技术难点。缺点是显而易见的,这种方式由于需要不断的建立http连接,严重浪费了服务器端和客户端的资源。尤其是在客户端,距离来说,如果有数量级想对比较大的人同时位于基于短轮询的应用中,那么每一个用户的客户端都会疯狂的向服务器端发送http请求,而且不会间断。人数越多,服务器端压力越大,这是很不合理的。</p><p>因此短轮询不适用于那些同时在线用户数量比较大,并且很注重性能的Web应用。</p><h4 id="2-长轮询-comet"><a href="#2-长轮询-comet" class="headerlink" title="2.长轮询(comet)"></a>2.长轮询(comet)</h4><p>comet指的是,<span style="color:#49b94d;">当服务器收到客户端发来的请求后,不会直接进行响应,而是先将这个请求挂起,然后判断服务器端数据是否有更新。如果有更新,则进行响应,如果一直没有数据,则到达一定的时间限制(服务器端设置)后关闭连接。</span></p><p>长轮询和短轮询比起来,明显减少了很多不必要的http请求次数,相比之下节约了资源。长轮询的缺点在于,连接挂起也会导致资源的浪费。</p><h4 id="3-SSE"><a href="#3-SSE" class="headerlink" title="3.SSE"></a>3.SSE</h4><p>SSE是HTML5新增的功能,全称为<span style="color:red">Server-SentEvents</span>。它可以允许服务推送数据到客户端。SSE在本质上就与之前的长轮询、短轮询不同,虽然都是基于http协议的,但是轮询需要客户端先发送请求。</p><p>而SSE最大的特点就是<span style="color:#49b94d;">不需要客户端发送请求,可以实现只要服务器端数据有更新,就可以马上发送到客户端</span>。</p><p>SSE的优势很明显,它不需要建立或保持大量的客户端发往服务器端的请求,节约了很多资源,提升应用性能。</p><h4 id="4-WebSocket"><a href="#4-WebSocket" class="headerlink" title="4.WebSocket"></a>4.WebSocket</h4><p>WebSocket是HTML5定义的一个新协议,与传统的http协议不同,<span style="color:red">该协议可以实现服务器与客户端之间全双工通信</span>。</p><p>简单来说,<span style="color:#49b94d;">首先需要在客户端和服务器端建立起一个连接,这部分需要http,连接一旦建立,客户端和服务器端就处于平等的地位,可以相互发送数据,不存在请求和响应的区别。</span></p><p>WebSocket的优点是实现了双向通信,缺点是服务器端的逻辑非常复杂。现在针对不同的后台语言有不同的插件可以使用。</p><h3 id="4四种Web即时通信技术比较"><a href="#4四种Web即时通信技术比较" class="headerlink" title="4四种Web即时通信技术比较"></a>4四种Web即时通信技术比较</h3><p>从兼容性角度考虑,短轮询>长轮询>长连接SSE>WebSocket</p><p>从性能方面考虑,WebSocket>长连接SSE>长轮询>短轮询</p>]]></content>
<tags>
<tag>web通信</tag>
</tags>
</entry>
<entry>
<title>vue中computed和watch的比较</title>
<link href="/2019/11/20/vue%E4%B8%ADcomputed%E5%92%8Cwatch%E7%9A%84%E6%AF%94%E8%BE%83/"/>
<url>/2019/11/20/vue%E4%B8%ADcomputed%E5%92%8Cwatch%E7%9A%84%E6%AF%94%E8%BE%83/</url>
<content type="html"><![CDATA[<h3 id="computed:"><a href="#computed:" class="headerlink" title="computed:"></a>computed:</h3><div class="code-wrapper"><pre><code class="hljs html"><span class="hljs-tag"><<span class="hljs-name">template</span>></span> <span class="hljs-tag"><<span class="hljs-name">div</span>></span> <span class="hljs-tag"><<span class="hljs-name">p</span>></span>{{ reversedMessage }}<span class="hljs-tag"></<span class="hljs-name">p</span>></span> <span class="hljs-tag"></<span class="hljs-name">div</span>></span><span class="hljs-tag"></<span class="hljs-name">template</span>></span> <span class="hljs-tag"><<span class="hljs-name">script</span>></span><span class="javascript"></span><span class="javascript"> <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {</span><span class="javascript"> <span class="hljs-attr">name</span>: <span class="hljs-string">'test1'</span>,</span><span class="javascript"> data () {</span><span class="javascript"> <span class="hljs-keyword">return</span> {</span><span class="javascript"> <span class="hljs-attr">message</span>: <span class="hljs-string">'hello world'</span>,</span><span class="javascript"> <span class="hljs-attr">number</span>: <span class="hljs-number">1</span></span><span class="javascript"> }</span><span class="javascript"> },</span><span class="javascript"> <span class="hljs-attr">computed</span>: {</span><span class="javascript"> <span class="hljs-comment">// 字符串反转</span></span><span class="javascript"> reversedMessage () {</span><span class="javascript"> <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.message.split(<span class="hljs-string">''</span>).reverse().join(<span class="hljs-string">''</span>) + <span class="hljs-built_in">this</span>.number</span><span class="javascript"> }</span><span class="javascript"> }</span><span class="javascript"> }</span><span class="javascript"></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span></code></pre></div><p>在computed中定义的每一个计算属性,都会被<strong style="color:red">缓存</strong>起来,只有当计算属性里面依赖的一个或多个属性变化了,才会重新计算当前计算属性的值。上面的代码片段中,在reversedMessage中,它依赖了message和number这两个属性,一旦其中一个变化了,reversedMessage会立刻重新计算输出新值。</p><p> vue会缓存计算属性的计算结果,只要依赖的其它属性值不变,即使多次使用计算属性,就不会重复计算,效率更高。</p><p> 而vue不会缓存函数的执行结果,所以如果多次调用函数,会导致重复计算!</p><p>watch是属性监听器,一般用来监听属性的变化(也可以用来监听计算属性函数),并做一些逻辑。</p><h3 id="watch:"><a href="#watch:" class="headerlink" title="watch:"></a>watch:</h3><div class="code-wrapper"><pre><code class="hljs html"><span class="hljs-tag"><<span class="hljs-name">template</span>></span> <span class="hljs-tag"><<span class="hljs-name">div</span>></span> <span class="hljs-tag"><<span class="hljs-name">p</span>></span>{{ this.number }}<span class="hljs-tag"></<span class="hljs-name">p</span>></span> <span class="hljs-tag"></<span class="hljs-name">div</span>></span><span class="hljs-tag"></<span class="hljs-name">template</span>></span> <span class="hljs-tag"><<span class="hljs-name">script</span>></span><span class="javascript"></span><span class="javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {</span><span class="javascript"> <span class="hljs-attr">name</span>: <span class="hljs-string">'test1'</span>,</span><span class="javascript"> data () {</span><span class="javascript"> <span class="hljs-keyword">return</span> {</span><span class="javascript"> <span class="hljs-attr">number</span>: <span class="hljs-number">1</span></span><span class="javascript"> }</span><span class="javascript"> },</span><span class="javascript"> created () {</span><span class="javascript"> <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =></span> {</span><span class="javascript"> <span class="hljs-built_in">this</span>.number = <span class="hljs-number">100</span></span><span class="javascript"> }, <span class="hljs-number">2000</span>)</span><span class="javascript"> },</span><span class="javascript"> <span class="hljs-attr">watch</span>: {</span><span class="javascript"> number (newVal, oldVal) {</span><span class="javascript"> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'number has changed: '</span>, newVal)</span><span class="javascript"> }</span><span class="javascript"> }</span><span class="javascript">}</span><span class="javascript"></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span></code></pre></div><p>watch是专门监听一个变量的变化,只要变量值发生变化,就自动触发的函数。</p><h3 id="总结:"><a href="#总结:" class="headerlink" title="总结:"></a>总结:</h3><p>computed和watch的使用场景并不一样,</p><ul><li><p>computed的话是<span style="color:red">通过几个数据的变化,来影响一个数据</span>,computed是在HTML DOM加载后马上执行的,如赋值;</p></li><li><p>而watch的话,<span style="color:red">是可以一个数据的变化,去影响多个数据</span>。watch用于观察Vue实例上的数据变动。对应一个对象,键是观察表达式,值是对应回调。</p></li><li><p>另外,methods则必须要有<span style="color:red">一定的触发条件才能执行</span>,如点击事件</p></li><li><p>如果更关心执行过程时,<span style="color:red">不关心结果时,首选函数!</span></p></li><li><p>如果更关心计算结果,<span style="color:red">不关心过程时,首选计算属性。</span></p></li></ul>]]></content>
<tags>
<tag>vue</tag>
</tags>
</entry>
<entry>
<title>closure</title>
<link href="/2019/11/19/closure/"/>
<url>/2019/11/19/closure/</url>
<content type="html"><![CDATA[<h3 id="closure-闭包"><a href="#closure-闭包" class="headerlink" title="closure 闭包"></a>closure 闭包</h3><p>在JS中,变量的作用域属于函数作用域,在函数执行后作用域就会被清理、内存也随之回收,但是由于闭包是建立在一个函数内部的子函数,由于其可访问上级作用域的原因,即使上级函数执行完,作用域也不会随之销毁,这时的子函数——也就是闭包,便拥有了访问上级作用域中的变量的权限,即使上级函数执行完后作用域内的值也不会被销毁。</p><p>从以下几句话中来明确概念:</p><h4 id="变量作用域:"><a href="#变量作用域:" class="headerlink" title="变量作用域:"></a>变量作用域:</h4><p>全局变量 在 全局范围内可用,存在于全局作用域中,在js任何代码中可见<br>局部变量 只 存在 函数体内,在局部作用域中使用<br>函数作用域 在函数体内的所有变量可以使用</p><h3 id="作用域链:"><a href="#作用域链:" class="headerlink" title="作用域链:"></a>作用域链:</h3><p>定义一个函数时, 会保存一个作用域链;<br>对于嵌套函数来说,每内调用一次外部函数,都会创建一个新的作用域链;<br>每次外部函数的调用,内部的代码相同,但其作用域链不同</p><h3 id="js垃圾回收机制:"><a href="#js垃圾回收机制:" class="headerlink" title="js垃圾回收机制:"></a>js垃圾回收机制:</h3><p>js具有自动垃圾回收机制,会定期把不再使用的变量销毁,释放其占用的内存;<br>(只会销毁局部变量,全局变量的生命周期只有在页面或浏览器关闭时才会结束)</p>]]></content>
<tags>
<tag>js</tag>
</tags>
</entry>
<entry>
<title>事件队列</title>
<link href="/2019/11/19/%E4%BA%8B%E4%BB%B6%E9%98%9F%E5%88%97/"/>
<url>/2019/11/19/%E4%BA%8B%E4%BB%B6%E9%98%9F%E5%88%97/</url>
<content type="html"><![CDATA[<h3 id="首先-单线程、多线程"><a href="#首先-单线程、多线程" class="headerlink" title="首先 单线程、多线程"></a>首先 单线程、多线程</h3><p>浏览器解释引擎 对js 脚本进行解析</p><p>主要执行交互行为 对 dom 节点进行操作</p><p>js为单线程,不会存在同时对一个dom元素进行多种同时操作</p><p>但js脚本可创建多线程,子线程受浏览器主线程操作,进入任务队列排队,等待调用</p><h3 id="任务队列"><a href="#任务队列" class="headerlink" title="任务队列"></a>任务队列</h3><p>单线程导致一个任务结束,才能执行下一个任务</p><p>任务队列排队 空闲,会导致 CPU 闲置 ,因此将任务分为两种:同步、异步</p><p>任务队列或又称为消息队列, 回调函数、ajax、事件函数、定时器 都存放在任务队列中</p><p>任务队列:先进先出,某些事件在调用时,才会进入主线程</p><h3 id="同步、异步"><a href="#同步、异步" class="headerlink" title="同步、异步"></a>同步、异步</h3><p>同步指一件事情完成、才会执行下一件事情</p><p>异步指浏览器解释引擎 在做一件事的同时,调用闲置的CPU 处理另外一件事情 如:ajax 请求</p><p>浏览器主进程会 执行 同步任务 ,闲置CPU 调取 任务队列,加载异步 事件 或 函数 进入执行栈 ,执行。</p>]]></content>
<tags>
<tag>js</tag>
</tags>
</entry>
<entry>
<title>vue中的绑定语法</title>
<link href="/2019/11/10/vue%E4%B8%AD%E7%9A%84%E7%BB%91%E5%AE%9A%E8%AF%AD%E6%B3%95/"/>
<url>/2019/11/10/vue%E4%B8%AD%E7%9A%84%E7%BB%91%E5%AE%9A%E8%AF%AD%E6%B3%95/</url>
<content type="html"><![CDATA[<h1 id="一、绑定语法:"><a href="#一、绑定语法:" class="headerlink" title="一、绑定语法:"></a>一、绑定语法:</h1><ol><li>什么是绑定语法: 就是在HTML中标记可能发生变化的位置的语法——学名: Interpolation 插值语法</li><li>何时: 只要元素的内容中,某个位置可能随变量自动变化时,就要用绑定语法标记</li></ol><h1 id="二、指令"><a href="#二、指令" class="headerlink" title="二、指令:"></a>二、指令:</h1><ol><li>v-bind:<div class="code-wrapper"><pre><code class="hljs javascript"><div id=<span class="hljs-string">"app"</span>> <span class="xml"><span class="hljs-tag"><<span class="hljs-name">h1</span>></span>空气净化器<span class="hljs-tag"></<span class="hljs-name">h1</span>></span></span> <span class="xml"><span class="hljs-tag"><<span class="hljs-name">h2</span>></span>{{pm25}}<span class="hljs-tag"></<span class="hljs-name">h2</span>></span></span> <h2>{{pm25<100?'img/1.png': pm25<200?'img/2.png': pm25<300?'img/3.png': 'img/4.png'}}</h2> //属性名前有:"就变成了{} <img :src="pm25<100?'img/1.png': pm25<200?'img/2.png': pm25<300?'img/3.png': 'img/4.png'"> </div> <script> var vm=new Vue({ el:"#app", data:{ pm25:180 } }); setInterval(function(){ //vm.data.pm25= vm.pm25=Math.random()*400 },2000)</script></code></pre></div></li><li>控制显示隐藏:<br>控制两个元素根据条件二选一显示隐藏<br><元素1 v-if=”条件”><br><元素2 v-else><br> a. 结果: 每当new Vue扫描页面时,或者data中变量发生更改时,都会自动计算v-if=后的条件表达式的值。如果v-if=”true”,则显示元素1,不显示元素2。否则如果v-if=”false”,则不显示元素1,改为显示元素2<br> b. 原理: 如果v-if=”true”,则删除元素2,保留元素1<ul><li>如果v-if=”false”,则删除元素1,保留元素2<br>c. 强调:</li><li>v-else后不要写=和属性值!</li><li>v-if和v-else两个元素之间禁止插入其他元素!</li></ul></li></ol>]]></content>
<tags>
<tag>vue</tag>
</tags>
</entry>
<entry>
<title>vue的生命周期</title>
<link href="/2019/10/27/vue%E7%9A%84%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F/"/>
<url>/2019/10/27/vue%E7%9A%84%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F/</url>
<content type="html"><![CDATA[<ul><li><h3 id="1-什么是组件的生命周期"><a href="#1-什么是组件的生命周期" class="headerlink" title="1. 什么是组件的生命周期:"></a>1. 什么是组件的生命周期:</h3><p> 每个组件在加载过程中所经历的阶段</p></li><li><h3 id="2-为什么使用组件的生命周期"><a href="#2-为什么使用组件的生命周期" class="headerlink" title="2. 为什么使用组件的生命周期:"></a>2. 为什么使用组件的生命周期:</h3><p> 我们经常需要在组件加载过程中自动执行一项操作,比如: 希望组件加载完,自动发送ajax请求获取数据<br>但是在单页面中,因为只有一个index.html页面在首次加载,之后更换”页面”, index.html是不换的,且DOM树也不需要整棵更新,所以DOMContentLoaded和window.onload都不能用,都不会反复触发! </p></li><li><h3 id="3-何时使用?"><a href="#3-何时使用?" class="headerlink" title="3.何时使用?"></a>3.何时使用?</h3><p> 今后,只要希望在组件加载的过程中自动执行一项任务时,都要在对应的生命周期中执行操作,而不是在页面的加载后执行。</p></li><li><h3 id="4-包括以下几个阶段?"><a href="#4-包括以下几个阶段?" class="headerlink" title="4.包括以下几个阶段?"></a>4.包括以下几个阶段?</h3><p> (1). 创建阶段(create):<br> a. 创建组件对象,同时创建组件中的data对象。此时已经可以发送ajax请求了<br> b. 暂时还未创建虚拟DOM树,所以,在这个阶段不能执行DOM操作!<br>注意:此阶段只有data对象,没有虚拟dom树<br> (2). 挂载阶段(mount): 创建虚拟DOM树,将数据内容渲染到页面上显示。此时既可以发ajax请求,又可以执行DOM操作。<br> <em><strong><strong><strong><strong><strong><strong>首次加载到此结束</strong></strong></strong></strong></strong></strong></em>******<br> (3). 更新阶段(update): 只有data中的模型数据被更新时,才会触发更新阶段<br> (4). 销毁阶段(destroy): 只有主动调用$destroy()函数删除一个组件时,才会触发销毁阶段。</p></li><li><h3 id="5-钩子函数"><a href="#5-钩子函数" class="headerlink" title="5.钩子函数"></a>5.钩子函数</h3><p> (1). 什么是钩子函数: 绑定在生命周期各个阶段,自动触发的特殊的回调函数。<br> (2). 包括: 每个阶段,一前一后,都有两个钩子函数</p><div class="code-wrapper"><pre><code class="hljs javascript"> <span class="hljs-function"><span class="hljs-title">beforeCreate</span>(<span class="hljs-params"></span>)</span>{ ... }a. create阶段 <span class="hljs-function"><span class="hljs-title">created</span>(<span class="hljs-params"></span>)</span>{ ... ajax ... } <span class="hljs-function"><span class="hljs-title">beforeMount</span>(<span class="hljs-params"></span>)</span>{ ... }b. mount阶段 <span class="hljs-function"><span class="hljs-title">mounted</span>(<span class="hljs-params"></span>)</span>{ ... ajax ... 或 DOM操作 ...} <span class="hljs-function"><span class="hljs-title">beforeUpdate</span>(<span class="hljs-params"></span>)</span>{ ... }c. update阶段 <span class="hljs-function"><span class="hljs-title">updated</span>(<span class="hljs-params"></span>)</span>{ ... } <span class="hljs-function"><span class="hljs-title">beforeDestroy</span>(<span class="hljs-params"></span>)</span>{ ... }d. destroy阶段 <span class="hljs-function"><span class="hljs-title">destroyed</span>(<span class="hljs-params"></span>)</span>{ ... }</code></pre></div></li><li><h3 id="6-如何使用钩子函数:"><a href="#6-如何使用钩子函数:" class="headerlink" title="6. 如何使用钩子函数:"></a>6. 如何使用钩子函数:</h3><div class="code-wrapper"><pre><code class="hljs javascript">组件对象{ <span class="hljs-function"><span class="hljs-title">data</span>(<span class="hljs-params"></span>)</span>{ <span class="hljs-keyword">return</span> { ... } }, <span class="hljs-attr">methods</span>:{ ... }, <span class="hljs-attr">watch</span>:{ ... }, <span class="hljs-attr">computed</span>:{ ... }, <span class="hljs-attr">components</span>:{ ... }, <span class="hljs-function"><span class="hljs-title">beforeCreate</span>(<span class="hljs-params"></span>)</span>{ ... }, <span class="hljs-function"><span class="hljs-title">created</span>(<span class="hljs-params"></span>)</span>{ ... ajax ... }, <span class="hljs-function"><span class="hljs-title">beforeMount</span>(<span class="hljs-params"></span>)</span>{ ... }, <span class="hljs-function"><span class="hljs-title">mounted</span>(<span class="hljs-params"></span>)</span>{ ... ajax ... }, <span class="hljs-function"><span class="hljs-title">beforeUpdate</span>(<span class="hljs-params"></span>)</span>{ ... }, <span class="hljs-function"><span class="hljs-title">updated</span>(<span class="hljs-params"></span>)</span>{ ... }, <span class="hljs-function"><span class="hljs-title">beforeDestroy</span>(<span class="hljs-params"></span>)</span>{ ... }, <span class="hljs-function"><span class="hljs-title">destroyed</span>(<span class="hljs-params"></span>)</span>{ ... }}</code></pre></div></li></ul>]]></content>
<tags>
<tag>vue</tag>
</tags>
</entry>
</search>