-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
1349 lines (921 loc) · 168 KB
/
Copy pathindex.html
File metadata and controls
1349 lines (921 loc) · 168 KB
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
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<meta name="theme-color" content="#222"><meta name="generator" content="Hexo 5.4.0">
<link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
<link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
<link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
<link rel="mask-icon" href="/images/logo.svg" color="#222">
<link rel="stylesheet" href="/css/main.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css" integrity="sha256-CTSx/A06dm1B063156EVh15m6Y67pAjZZaQc89LLSrU=" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.1.1/animate.min.css" integrity="sha256-PR7ttpcvz8qrF57fur/yAx1qXMFJeJFiA6pSzWi0OIE=" crossorigin="anonymous">
<script class="next-config" data-name="main" type="application/json">{"hostname":"example.com","root":"/","images":"/images","scheme":"Muse","darkmode":false,"version":"8.18.2","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12},"copycode":{"enable":false,"style":null},"fold":{"enable":false,"height":500},"bookmark":{"enable":false,"color":"#222","save":"auto"},"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"stickytabs":false,"motion":{"enable":true,"async":false,"transition":{"menu_item":"fadeInDown","post_block":"fadeIn","post_header":"fadeInDown","post_body":"fadeInDown","coll_header":"fadeInLeft","sidebar":"fadeInUp"}},"prism":false,"i18n":{"placeholder":"Searching...","empty":"We didn't find any results for the search: ${query}","hits_time":"${hits} results found in ${time} ms","hits":"${hits} results found"}}</script><script src="/js/config.js"></script>
<meta property="og:type" content="website">
<meta property="og:title" content="Hexo">
<meta property="og:url" content="http://example.com/index.html">
<meta property="og:site_name" content="Hexo">
<meta property="og:locale" content="en_US">
<meta property="article:author" content="Ladyfish">
<meta name="twitter:card" content="summary">
<link rel="canonical" href="http://example.com/">
<script class="next-config" data-name="page" type="application/json">{"sidebar":"","isHome":true,"isPost":false,"lang":"en","comments":"","permalink":"","path":"index.html","title":""}</script>
<script class="next-config" data-name="calendar" type="application/json">""</script>
<title>Hexo</title>
<noscript>
<link rel="stylesheet" href="/css/noscript.css">
</noscript>
</head>
<body itemscope itemtype="http://schema.org/WebPage" class="use-motion">
<div class="headband"></div>
<main class="main">
<div class="column">
<header class="header" itemscope itemtype="http://schema.org/WPHeader"><div class="site-brand-container">
<div class="site-nav-toggle">
<div class="toggle" aria-label="Toggle navigation bar" role="button">
</div>
</div>
<div class="site-meta">
<a href="/" class="brand" rel="start">
<i class="logo-line"></i>
<h1 class="site-title">Hexo</h1>
<i class="logo-line"></i>
</a>
</div>
<div class="site-nav-right">
<div class="toggle popup-trigger" aria-label="Search" role="button">
</div>
</div>
</div>
</header>
<aside class="sidebar">
<div class="sidebar-inner sidebar-overview-active">
<ul class="sidebar-nav">
<li class="sidebar-nav-toc">
Table of Contents
</li>
<li class="sidebar-nav-overview">
Overview
</li>
</ul>
<div class="sidebar-panel-container">
<!--noindex-->
<div class="post-toc-wrap sidebar-panel">
</div>
<!--/noindex-->
<div class="site-overview-wrap sidebar-panel">
<div class="site-author animated" itemprop="author" itemscope itemtype="http://schema.org/Person">
<p class="site-author-name" itemprop="name">Ladyfish</p>
<div class="site-description" itemprop="description"></div>
</div>
<div class="site-state-wrap animated">
<nav class="site-state">
<div class="site-state-item site-state-posts">
<a href="/archives/">
<span class="site-state-item-count">20</span>
<span class="site-state-item-name">posts</span>
</a>
</div>
<div class="site-state-item site-state-tags">
<span class="site-state-item-count">17</span>
<span class="site-state-item-name">tags</span>
</div>
</nav>
</div>
</div>
</div>
</div>
</aside>
</div>
<div class="main-inner index posts-expand">
<div class="post-block">
<article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
<link itemprop="mainEntityOfPage" href="http://example.com/2024/05/03/webWorker/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar.gif">
<meta itemprop="name" content="Ladyfish">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="Hexo">
<meta itemprop="description" content="">
</span>
<span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
<meta itemprop="name" content="undefined | Hexo">
<meta itemprop="description" content="">
</span>
<header class="post-header">
<h2 class="post-title" itemprop="name headline">
<a href="/2024/05/03/webWorker/" class="post-title-link" itemprop="url">web worker</a>
</h2>
<div class="post-meta-container">
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar"></i>
</span>
<span class="post-meta-item-text">Posted on</span>
<time title="Created: 2024-05-03 16:37:17 / Modified: 17:00:57" itemprop="dateCreated datePublished" datetime="2024-05-03T16:37:17+08:00">2024-05-03</time>
</span>
</div>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h3 id="1-简介"><a href="#1-简介" class="headerlink" title="1.简介"></a>1.简介</h3><p>当网页运行JavaScript代码时,它是在一个单一的线程中执行的,这意味着在执行某些长时间运行的任务时,会导致界面卡顿或不响应。为了解决这个问题,HTML5引入了Web Worker API,允许在后台运行脚本,以便执行计算密集型任务,而不会阻塞用户界面。</p>
<p>Web Worker具有以下特点:</p>
<ol>
<li><strong>多线程执行:</strong> Web Worker允许在单独的线程中运行JavaScript代码,这使得可以在后台执行耗时任务,而不会影响到主线程的运行,从而保持用户界面的流畅性和响应性。</li>
<li><strong>独立于主线程:</strong> Web Worker运行在与主页面代码分离的独立线程中,它们无法访问主线程的DOM,也无法直接操作页面上的元素。这种隔离性确保了主线程与Web Worker之间的互不干扰,避免了死锁和竞态条件等问题。</li>
<li><strong>通信机制:</strong> 主线程与Web Worker之间可以通过消息传递进行通信。主线程使用<code>postMessage()</code>方法发送消息给Web Worker,而Web Worker内部通过<code>self.onmessage</code>监听消息,然后执行相应的操作。Web Worker也可以通过<code>postMessage()</code>方法将结果或其他信息发送回主线程。</li>
<li><strong>受限环境:</strong> 由于Web Worker无法访问主线程的DOM和全局变量,它们在执行环境上是受限的,例如无法直接操作页面上的元素或使用某些浏览器特定的API。这样的限制使得Web Worker主要用于纯计算任务,而不是处理用户界面。</li>
</ol>
<h3 id="2-示例代码"><a href="#2-示例代码" class="headerlink" title="2.示例代码"></a>2.示例代码</h3><p>以下是一个简单的Web Worker示例代码,该示例将计算斐波那契数列的前n项:</p>
<p>当用户在输入框中输入要计算的斐波那契数列的项数并点击“开始计算”按钮时,将会触发startWorker()函数。该函数首先检查浏览器是否支持Web Worker,然后创建一个新的Web Worker实例并将输入值传递给它。Web Worker在计算完斐波那契数列后,将结果发送回主页面,并更新页面上的结果部分。</p>
<p>HTML文件:</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"><!DOCTYPE <span class="meta-keyword">html</span>></span></span><br><span class="line"><span class="tag"><<span class="name">html</span> <span class="attr">lang</span>=<span class="string">"en"</span>></span></span><br><span class="line"><span class="tag"><<span class="name">head</span>></span></span><br><span class="line"><span class="tag"><<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">"UTF-8"</span>></span></span><br><span class="line"><span class="tag"><<span class="name">meta</span> <span class="attr">name</span>=<span class="string">"viewport"</span> <span class="attr">content</span>=<span class="string">"width=device-width, initial-scale=1.0"</span>></span></span><br><span class="line"><span class="tag"><<span class="name">title</span>></span>Web Worker 示例<span class="tag"></<span class="name">title</span>></span></span><br><span class="line"><span class="tag"></<span class="name">head</span>></span></span><br><span class="line"><span class="tag"><<span class="name">body</span>></span></span><br><span class="line"><span class="tag"><<span class="name">h1</span>></span>计算斐波那契数列<span class="tag"></<span class="name">h1</span>></span></span><br><span class="line"><span class="tag"><<span class="name">p</span>></span>请输入要计算的斐波那契数列的项数:<span class="tag"></<span class="name">p</span>></span></span><br><span class="line"><span class="tag"><<span class="name">input</span> <span class="attr">type</span>=<span class="string">"number"</span> <span class="attr">id</span>=<span class="string">"input"</span> <span class="attr">value</span>=<span class="string">"10"</span>></span></span><br><span class="line"><span class="tag"><<span class="name">button</span> <span class="attr">onclick</span>=<span class="string">"startWorker()"</span>></span>开始计算<span class="tag"></<span class="name">button</span>></span></span><br><span class="line"><span class="tag"><<span class="name">p</span> <span class="attr">id</span>=<span class="string">"result"</span>></span><span class="tag"></<span class="name">p</span>></span></span><br><span class="line"></span><br><span class="line"><span class="tag"><<span class="name">script</span>></span><span class="javascript"></span></span><br><span class="line"><span class="javascript"><span class="function"><span class="keyword">function</span> <span class="title">startWorker</span>(<span class="params"></span>) </span>{</span></span><br><span class="line"><span class="javascript"> <span class="keyword">var</span> input = <span class="built_in">document</span>.getElementById(<span class="string">"input"</span>).value;</span></span><br><span class="line"><span class="javascript"> <span class="keyword">if</span>(<span class="keyword">typeof</span>(Worker) !== <span class="string">"undefined"</span>) {</span></span><br><span class="line"><span class="javascript"> <span class="keyword">if</span>(<span class="keyword">typeof</span>(w) == <span class="string">"undefined"</span>) {</span></span><br><span class="line"><span class="javascript"> w = <span class="keyword">new</span> Worker(<span class="string">"worker.js"</span>);</span></span><br><span class="line"><span class="javascript"> }</span></span><br><span class="line"><span class="javascript"> w.postMessage(input);</span></span><br><span class="line"><span class="javascript"> w.onmessage = <span class="function"><span class="keyword">function</span>(<span class="params">event</span>) </span>{</span></span><br><span class="line"><span class="javascript"> <span class="built_in">document</span>.getElementById(<span class="string">"result"</span>).innerHTML = <span class="string">"结果:"</span> + event.data;</span></span><br><span class="line"><span class="javascript"> };</span></span><br><span class="line"><span class="javascript"> } <span class="keyword">else</span> {</span></span><br><span class="line"><span class="javascript"> <span class="built_in">document</span>.getElementById(<span class="string">"result"</span>).innerHTML = <span class="string">"抱歉,您的浏览器不支持 Web Workers。"</span>;</span></span><br><span class="line"><span class="javascript"> }</span></span><br><span class="line"><span class="javascript">}</span></span><br><span class="line"><span class="javascript"></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"><span class="tag"></<span class="name">body</span>></span></span><br><span class="line"><span class="tag"></<span class="name">html</span>></span></span><br></pre></td></tr></table></figure>
<p>worker.js:(在这里定义了web worker的工作内容)</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">calculateFibonacci</span>(<span class="params">n</span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> a = <span class="number">0</span>, b = <span class="number">1</span>, temp;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i < n; i++) {</span><br><span class="line"> temp = a;</span><br><span class="line"> a = a + b;</span><br><span class="line"> b = temp;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> a;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">self.onmessage = <span class="function"><span class="keyword">function</span>(<span class="params">event</span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> result = calculateFibonacci(event.data);</span><br><span class="line"> self.postMessage(result);</span><br><span class="line">};</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p><code>self.onmessage</code>在Web Worker内部会在接收到消息时被调用。当主线程通过<code>worker.postMessage()</code>向Web Worker发送消息时,Web Worker内部的<code>self.onmessage</code>会被触发,并且传入一个事件对象作为参数,该事件对象包含发送的消息在<code>event.data</code>中。</p>
<p>在上述示例中,当Web Worker收到主线程发送的要计算的斐波那契数列项数时,它会执行计算,并将结果通过<code>self.postMessage()</code>发送回主线程。主线程接收到这个消息后,会触发在<code>w.onmessage</code>中定义的回调函数,从而处理来自Web Worker的结果。</p>
<p>简单来说就是主线程向子线程postMessage()会触发子线程的onmessage。同样的子线程向主线程postMessage()也会触发主线程的onmessage。显而易见postMessage的参数会作为被触发的onmessage的参数执行相应动作。</p>
<h3 id="3-总结"><a href="#3-总结" class="headerlink" title="3.总结"></a>3.总结</h3><ol>
<li>web worker是html5中提出来的为了解决单线程阻塞问题的一个新API。</li>
<li>可以使用该API创建多个子线程。子线程完全受主线程控制并且不能操作DOM。</li>
<li>子线程和主线程之间使用postMessage和onmessage进行通信。</li>
</ol>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
</div>
<div class="post-block">
<article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
<link itemprop="mainEntityOfPage" href="http://example.com/2024/04/16/git%E6%8F%90%E4%BA%A4%E8%A7%84%E8%8C%83/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar.gif">
<meta itemprop="name" content="Ladyfish">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="Hexo">
<meta itemprop="description" content="">
</span>
<span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
<meta itemprop="name" content="undefined | Hexo">
<meta itemprop="description" content="">
</span>
<header class="post-header">
<h2 class="post-title" itemprop="name headline">
<a href="/2024/04/16/git%E6%8F%90%E4%BA%A4%E8%A7%84%E8%8C%83/" class="post-title-link" itemprop="url">git提交规范</a>
</h2>
<div class="post-meta-container">
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar"></i>
</span>
<span class="post-meta-item-text">Posted on</span>
<time title="Created: 2024-04-16 22:04:44 / Modified: 22:16:38" itemprop="dateCreated datePublished" datetime="2024-04-16T22:04:44+08:00">2024-04-16</time>
</span>
</div>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<p>feat: 新功能(feature)</p>
<p>fix: 修补bug</p>
<p>docs: 文档(documentation)</p>
<p>style: 格式(不影响代码运行的变动)</p>
<p>refactor: 重构(即不是新增功能,也不是修改bug的代码变动)</p>
<p>chore: 构建过程或辅助工具的变动</p>
<p>revert: 撤销,版本回退</p>
<p>perf: 性能优化</p>
<p>test:测试</p>
<p>improvement: 改进</p>
<p>build: 打包</p>
<p>ci: 持续集成</p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
</div>
<div class="post-block">
<article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
<link itemprop="mainEntityOfPage" href="http://example.com/2024/03/10/this/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar.gif">
<meta itemprop="name" content="Ladyfish">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="Hexo">
<meta itemprop="description" content="">
</span>
<span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
<meta itemprop="name" content="undefined | Hexo">
<meta itemprop="description" content="">
</span>
<header class="post-header">
<h2 class="post-title" itemprop="name headline">
<a href="/2024/03/10/this/" class="post-title-link" itemprop="url">this的四种绑定规则,你都知道吗?</a>
</h2>
<div class="post-meta-container">
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar"></i>
</span>
<span class="post-meta-item-text">Posted on</span>
<time title="Created: 2024-03-10 15:59:04 / Modified: 22:10:09" itemprop="dateCreated datePublished" datetime="2024-03-10T15:59:04+08:00">2024-03-10</time>
</span>
</div>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<p>《你不知道的JavaScript》系列二——–<code>this</code>绑定详解</p>
<h3 id="关于this的误解"><a href="#关于this的误解" class="headerlink" title="关于this的误解"></a>关于<code>this</code>的误解</h3><h4 id="1-指向自身"><a href="#1-指向自身" class="headerlink" title="1.指向自身"></a>1.指向自身</h4><p>不管是JavaScript新手开发者还是之前已经接触过其他语言的开发者,都很容易将this理解为指向函数自身。下面简单的例子将证明this远远不止字面意思的这么简单:</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">foo</span>(<span class="params">num</span>)</span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"foo:"</span>+num);</span><br><span class="line"> <span class="comment">//希望用count来记录foo被调用的次数</span></span><br><span class="line"> <span class="built_in">this</span>.count++;</span><br><span class="line">}</span><br><span class="line">foo.count = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">let</span> i=<span class="number">0</span>;i<<span class="number">5</span>;i++){</span><br><span class="line"> foo(i);</span><br><span class="line">}</span><br><span class="line"><span class="comment">//foo:0</span></span><br><span class="line"><span class="comment">//foo:1</span></span><br><span class="line"><span class="comment">//foo:2</span></span><br><span class="line"><span class="comment">//foo:3</span></span><br><span class="line"><span class="comment">//foo:4</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//见证奇迹的时候到了</span></span><br><span class="line"><span class="built_in">console</span>.log(foo.count);<span class="comment">//0 ———— WTF!!?</span></span><br></pre></td></tr></table></figure>
<p>从上面代码的输出可以看出从字面意思来理解this是错误的,那如果我增加的count属性和预期的不一样,那我增加的count哪去了?看看下图就一目了然了</p>
<p><img src="/image/image-20240310165509618.png" alt="image-20240310165509618"></p>
<h4 id="2-指向函数的作用域"><a href="#2-指向函数的作用域" class="headerlink" title="2.指向函数的作用域"></a>2.指向函数的作用域</h4><p>需要明确的是,this在任何情况下都不指向函数的词法作用域。在JavaScript内部,作用域确实是与对象类似,可见的标识符都是它的属性,但是作用域“对象”无法通过JavaScript代码访问,它存在与JavaScript引擎内部————《你不知道的JavaScript》</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">foo</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="keyword">var</span> a=<span class="number">2</span>;</span><br><span class="line"> <span class="built_in">this</span>.bar();</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">bar</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="built_in">this</span>.a);</span><br><span class="line">}</span><br><span class="line">foo();<span class="comment">//ReferenceError: a is not defined</span></span><br></pre></td></tr></table></figure>
<p>这段代码试图使用this来联通foo()和bar()的词法作用域,从而让bar()可以访问foo()作用域里面的变量a。这是不可能实现的,我们不能使用this来引用一个词法作用域内部的东西。</p>
<p><strong>每当你想要把词法作用域和this的查找混合使用时,一定要提醒自己,这是无法实现的</strong></p>
<h3 id="this到底是什么"><a href="#this到底是什么" class="headerlink" title="this到底是什么"></a><code>this</code>到底是什么</h3><p>当一个函数被调用时,会创建一个活动记录(执行上下文)。这个记录会包含函数在哪里被调用(调用栈)、函数的调用方法、传入的参数等信息。<code>this</code>就是记录的其中一个属性,会在函数执行的过程中用到。</p>
<p>调用栈:为了到达当前执行位置所调用的所有函数</p>
<p>调用位置:在当前正在执行的函数的前一个调用中</p>
<h3 id="this的四条绑定规则"><a href="#this的四条绑定规则" class="headerlink" title="this的四条绑定规则"></a><code>this</code>的四条绑定规则</h3><h4 id="1-默认绑定"><a href="#1-默认绑定" class="headerlink" title="1.默认绑定"></a>1.默认绑定</h4><p>独立函数调用时使用默认绑定规则,绑定到全局对象(非严格模式)或者undefined(严格模式)</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">foo</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="built_in">this</span>.a);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">var</span> a = <span class="number">2</span>;</span><br><span class="line">foo(); <span class="comment">// 2</span></span><br></pre></td></tr></table></figure>
<p>分析上述代码:</p>
<p>①:在代码中,foo()是直接使用不带任何修饰的函数引用进行调用的,一次只能使用默认绑定,无法使用其他规则。<br>②:上述代码执行在非严格模式下,因此this绑定到了全局对象上<br>③:this.a被解析为全局变量a,打印2</p>
<p>Tips:只有在非严格模式下调用foo(),默认绑定才能绑定到全局对象</p>
<h4 id="2-隐式绑定"><a href="#2-隐式绑定" class="headerlink" title="2.隐式绑定"></a>2.隐式绑定</h4><p>当调用位置有上下文对象,或者说是否被某个对象拥有或者包含时,考虑隐式绑定。</p>
<p>这个说法非常抽象,具体还是需要通过代码来进行讲解:</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">foo</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="built_in">this</span>.a);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> obj = {</span><br><span class="line"> <span class="attr">a</span>:<span class="number">2</span>,</span><br><span class="line"> <span class="attr">foo</span>:foo</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">obj.foo(); <span class="comment">// 2</span></span><br></pre></td></tr></table></figure>
<p>在上述代码中,调用位置会使用obj上下文来引用函数,因此隐式绑定规则会把函数调用中的this绑定到这个上下文对象,因此<code>this.a</code>和<code>obj.a</code>是一样的</p>
<p>Tips:对象属性引用链中只有最顶层或者说最后一层会影响调用位置</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">foo</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="built_in">this</span>.a);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> obj2 = {</span><br><span class="line"> <span class="attr">a</span>:<span class="number">333</span>,</span><br><span class="line"> <span class="attr">foo</span>:foo</span><br><span class="line">};</span><br><span class="line"><span class="keyword">var</span> obj1 = {</span><br><span class="line"> <span class="attr">a</span>:<span class="number">222</span>,</span><br><span class="line"> <span class="attr">obj2</span>:obj2</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">obj1.obj2.foo(); <span class="comment">// 333</span></span><br></pre></td></tr></table></figure>
<h5 id="隐式丢失"><a href="#隐式丢失" class="headerlink" title="==隐式丢失=="></a>==隐式丢失==</h5><p>隐式丢失是非常常见的this绑定问题,也就是说被隐式绑定的函数丢失绑定对象,应用默认绑定,将this绑定到全局对象(严格模式)或者undefined(非严格模式)上;</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">foo</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="built_in">this</span>.a);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">var</span> obj = {</span><br><span class="line"> <span class="attr">a</span>:<span class="number">2</span>,</span><br><span class="line"> <span class="attr">foo</span>:foo</span><br><span class="line">};</span><br><span class="line"><span class="keyword">var</span> bar = obj.foo;</span><br><span class="line"><span class="keyword">var</span> a = <span class="string">"糟糕,我是全局对象"</span>;</span><br><span class="line">bar(); <span class="comment">// "糟糕,我是全局对象"</span></span><br></pre></td></tr></table></figure>
<p>虽然bar是obj.foo的一个引用,但是实际上,它引用的是foo函数本身,因此此时的bar()其实是一个不带任何修饰符的函数调用,因此应用了默认绑定。值得注意的是,参数传递就是一种隐式赋值,因此在回调函数中,绑定的this也是全局对象。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">foo</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="built_in">this</span>.a);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">var</span> obj = {</span><br><span class="line"> <span class="attr">a</span>:<span class="number">2</span>,</span><br><span class="line"> <span class="attr">foo</span>:foo</span><br><span class="line">}</span><br><span class="line"><span class="keyword">var</span> a = <span class="string">"糟糕,我是全局对象"</span>;</span><br><span class="line"><span class="built_in">setTimeout</span>(obj.foo,<span class="number">1000</span>); <span class="comment">// "糟糕,我是全局对象"</span></span><br></pre></td></tr></table></figure>
<h4 id="3-显式绑定"><a href="#3-显式绑定" class="headerlink" title="3.显式绑定"></a>3.显式绑定</h4><p>使用call()、apply()直接指定this的绑定对象,称之为显式绑定。</p>
<p>显式绑定的两个应用:</p>
<h5 id="(1)硬绑定"><a href="#(1)硬绑定" class="headerlink" title="(1)硬绑定"></a>(1)硬绑定</h5><p>观察以下代码,无论之后如何调用函数bar,它总会手动在obj上调用foo</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">foo</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="built_in">this</span>.a);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">var</span> obj = {</span><br><span class="line"> <span class="attr">a</span>:<span class="number">2</span></span><br><span class="line">}</span><br><span class="line"><span class="keyword">var</span> bar = <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{</span><br><span class="line"> foo.call(obj);</span><br><span class="line">}</span><br><span class="line">bar(); <span class="comment">// 2</span></span><br><span class="line"><span class="built_in">setTimeout</span>(bar,<span class="number">100</span>); <span class="comment">// 2</span></span><br><span class="line"><span class="comment">//硬绑定的bar不可能再修改它的this</span></span><br><span class="line">bar.call(<span class="built_in">window</span>); <span class="comment">// 2</span></span><br></pre></td></tr></table></figure>
<p>由于硬绑定是一种非常常用的模式,所以在ES5中提供了内置的方法<code>Funtion.prototype.bind</code>,bind()会返回一个硬绑定的新函数,它会将参数设置为this的上下文。</p>
<h5 id="2-API调用的上下文"><a href="#2-API调用的上下文" class="headerlink" title="(2)API调用的上下文"></a>(2)API调用的上下文</h5><p>第三方库的许多函数,以及JavaScript语言和宿主环境中许多新的内置函数,都提供了一个可选的参数,通常称之为“上下文”(context),作用和bind()一样,确保回调函数可以使用指定的this</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">foo</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="built_in">console</span>.log(el,<span class="built_in">this</span>.id);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">var</span> obj = {</span><br><span class="line"> <span class="attr">id</span> : <span class="string">"awesome"</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//调用foo的时候把this绑定到obj上</span></span><br><span class="line">[<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>].forEach(foo,obj);</span><br><span class="line"><span class="comment">//1 awesome 2 awesome 3 awesome</span></span><br></pre></td></tr></table></figure>
<h4 id="4-new绑定"><a href="#4-new绑定" class="headerlink" title="4.new绑定"></a>4.new绑定</h4><p>使用new来调用函数,会自动执行下面的操作:</p>
<ol>
<li>创建一个全新的对象</li>
<li>这个新对象会被执行原型连接</li>
<li>这个新对象会绑定到函数调用的this</li>
<li>如果这个函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象</li>
</ol>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">foo</span>(<span class="params">a</span>)</span>{</span><br><span class="line"> <span class="built_in">this</span>.a = a;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">var</span> bar = <span class="keyword">new</span> foo(<span class="number">2</span>);</span><br><span class="line"><span class="built_in">console</span>.log(bar.a); <span class="comment">// 2</span></span><br></pre></td></tr></table></figure>
<p>使用new来调用foo()时,我们会构建一个新对象并将它绑定到foo()调用的this上。</p>
<h4 id="5-四条绑定规则的优先级"><a href="#5-四条绑定规则的优先级" class="headerlink" title="5.四条绑定规则的优先级"></a>5.四条绑定规则的优先级</h4><p>优先级:new绑定>显式绑定>隐式绑定>默认绑定</p>
<h4 id="6-绑定例外"><a href="#6-绑定例外" class="headerlink" title="6.绑定例外"></a>6.绑定例外</h4><h5 id="1-被忽略的this"><a href="#1-被忽略的this" class="headerlink" title="(1)被忽略的this"></a>(1)被忽略的this</h5><p>如果将null或者undefined作为this的绑定对象传入call、apply或者bind中时,这些值会被忽略,应用默认绑定规则</p>
<h5 id="2-间接引用"><a href="#2-间接引用" class="headerlink" title="(2)间接引用"></a>(2)间接引用</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">foo</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="built_in">this</span>.a);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">var</span> a = <span class="number">2</span>;</span><br><span class="line"><span class="keyword">var</span> o = {</span><br><span class="line"> <span class="attr">a</span> : <span class="number">3</span>,</span><br><span class="line"> <span class="attr">foo</span> : foo</span><br><span class="line">};</span><br><span class="line"><span class="keyword">var</span> p = {</span><br><span class="line"> <span class="attr">a</span> : <span class="number">4</span></span><br><span class="line">};</span><br><span class="line">o.foo(); <span class="comment">// 3</span></span><br><span class="line">p.foo = o.foo;</span><br><span class="line">p.foo(); <span class="comment">// 2 </span></span><br></pre></td></tr></table></figure>
<p>赋值表达式<code>p.foo = o.foo;</code>的返回值是目标函数的引用,因此调用位置是foo()而不是p.foo()或者o.foo。因此此处应用的是默认绑定</p>
<h5 id="3-箭头函数"><a href="#3-箭头函数" class="headerlink" title="(3)箭头函数"></a>(3)箭头函数</h5><p>箭头函数不适用this的四种绑定规则,而是根据外层作用域来决定this,并且箭头函数的绑定无法修改,new也不行!</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">foo</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="function">(<span class="params">a</span>) =></span> {</span><br><span class="line"> <span class="comment">//this继承自foo()</span></span><br><span class="line"> <span class="built_in">console</span>.log(<span class="built_in">this</span>.a);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">var</span> obj1 = {</span><br><span class="line"> <span class="attr">a</span>:<span class="number">2</span></span><br><span class="line">}</span><br><span class="line"><span class="keyword">var</span> obj2 = {</span><br><span class="line"> <span class="attr">a</span>:<span class="number">3</span></span><br><span class="line">}</span><br><span class="line"><span class="keyword">var</span> bar = foo.call(obj1);</span><br><span class="line">bar.call(obj2); <span class="comment">// 2</span></span><br></pre></td></tr></table></figure>
<h4 id="7-总结"><a href="#7-总结" class="headerlink" title="7.总结"></a>7.总结</h4><ol>
<li><p>函数是否在new中调用?如果是的话this绑定的是新创建的对象</p>
<p><code>var bar = new foo();</code></p>
</li>
<li><p>函数是否通过call、apply显式绑定或者bind硬绑定?如果是的话,this绑定的是指定对象</p>
<p><code>var bar = foo.call(obj2);</code></p>
</li>
<li><p>函数是否在某个上下文对象中调用(隐式绑定)?如果是的话,this绑定的是上下文对象</p>
<p><code>var bar = obj1.foo()</code></p>
</li>
<li><p>如果以上都不是的话,使用默认绑定。在严格模式下,绑定到undefined,非严格模式下,绑定到全局对象</p>
<p><code>var bar = foo()</code></p>
</li>
</ol>
<p>需要注意的是有些调用,特别是赋值,可能会在无意中使用默认绑定标准。并且箭头函数不会使用四条标准的绑定规则,而是根据当前的词法作用域来决定this。</p>
<h4 id="8-课后习题"><a href="#8-课后习题" class="headerlink" title="8.课后习题"></a>8.课后习题</h4><h5 id="1"><a href="#1" class="headerlink" title="1."></a>1.</h5><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> object = {</span><br><span class="line"> <span class="attr">message</span>: <span class="string">'Hello, World!'</span>,</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="title">getMessage</span>(<span class="params"></span>)</span> {</span><br><span class="line"> <span class="keyword">const</span> message = <span class="string">'Hello, Earth!'</span>;</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">this</span>.message;</span><br><span class="line"> }</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(object.getMessage()); <span class="comment">// ??</span></span><br></pre></td></tr></table></figure>
<h5 id="2"><a href="#2" class="headerlink" title="2."></a>2.</h5><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Pet</span>(<span class="params">name</span>) </span>{</span><br><span class="line"> <span class="built_in">this</span>.name = name;</span><br><span class="line"></span><br><span class="line"> <span class="built_in">this</span>.getName = <span class="function">() =></span> <span class="built_in">this</span>.name;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> cat = <span class="keyword">new</span> Pet(<span class="string">'Fluffy'</span>);</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(cat.getName()); </span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> { getName } = cat;</span><br><span class="line"><span class="built_in">console</span>.log(getName()); </span><br></pre></td></tr></table></figure>
<h5 id="3"><a href="#3" class="headerlink" title="3."></a>3.</h5><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> object = {</span><br><span class="line"> <span class="attr">message</span>: <span class="string">'Hello, World!'</span>,</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="title">logMessage</span>(<span class="params"></span>)</span> {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="built_in">this</span>.message);</span><br><span class="line"> }</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="built_in">setTimeout</span>(object.logMessage, <span class="number">1000</span>);</span><br></pre></td></tr></table></figure>
<h5 id="4"><a href="#4" class="headerlink" title="4."></a>4.</h5><p>如何调用<code>logMessage</code>函数,让它打印 <code>"Hello, World!"</code> ?</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> object = {</span><br><span class="line"> <span class="attr">message</span>: <span class="string">'Hello, World!'</span></span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">logMessage</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="built_in">this</span>.message);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h5 id="5"><a href="#5" class="headerlink" title="5."></a>5.</h5><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> object = {</span><br><span class="line"> <span class="attr">who</span>: <span class="string">'World'</span>,</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="title">greet</span>(<span class="params"></span>)</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="string">`Hello, <span class="subst">${<span class="built_in">this</span>.who}</span>!`</span>;</span><br><span class="line"> },</span><br><span class="line"></span><br><span class="line"> <span class="attr">farewell</span>: <span class="function">() =></span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="string">`Goodbye, <span class="subst">${<span class="built_in">this</span>.who}</span>!`</span>;</span><br><span class="line"> }</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(object.greet());</span><br><span class="line"><span class="built_in">console</span>.log(object.farewell());</span><br></pre></td></tr></table></figure>
<h5 id="6"><a href="#6" class="headerlink" title="6."></a>6.</h5><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> length = <span class="number">4</span>;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">callback</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="built_in">this</span>.length);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> object = {</span><br><span class="line"> <span class="attr">length</span>: <span class="number">5</span>,</span><br><span class="line"> <span class="function"><span class="title">method</span>(<span class="params">callback</span>)</span> {</span><br><span class="line"> callback();</span><br><span class="line"> }</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">object.method(callback, <span class="number">1</span>, <span class="number">2</span>);</span><br></pre></td></tr></table></figure>
<h5 id="7"><a href="#7" class="headerlink" title="7."></a>7.</h5><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> length = <span class="number">4</span>;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">callback</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="built_in">this</span>.length);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> object = {</span><br><span class="line"> <span class="attr">length</span>: <span class="number">5</span>,</span><br><span class="line"> <span class="function"><span class="title">method</span>(<span class="params"></span>)</span> {</span><br><span class="line"> <span class="built_in">arguments</span>[<span class="number">0</span>]();</span><br><span class="line"> }</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">object.method(callback, <span class="number">1</span>, <span class="number">2</span>);</span><br></pre></td></tr></table></figure>
<h5 id="答案"><a href="#答案" class="headerlink" title="答案"></a>答案</h5><ol>
<li><p><code>'Hello, World!'</code></p>
<p> 隐式调用,此时的this绑定object上</p>
</li>
<li><p><code>'Fluffy'</code> 和 <code>'Fluffy'</code></p>
<p>当函数作为构造函数<code>new Pet('Fluffy')</code>调用时,构造函数内部的<code>this</code>等于构造的对象</p>
<p><code>Pet</code>构造函数中的<code>this.name = name</code>表达式在构造的对象上创建<code>name</code>属性。</p>
<p><code>this.getName = () => this.name</code>在构造的对象上创建方法<code>getName</code>。而且由于使用了箭头函数,箭头函数内部的<code>this</code>值等于外部作用域的<code>this</code>值, 即 <code>Pet</code>。</p>
<p>调用<code>cat.getName()</code>以及<code>getName()</code>会返回表达式<code>this.name</code>,其计算结果为<code>'Fluffy'</code>。</p>
</li>
<li><p><code>undefined</code></p>
<p>object.logMessage作为回调函数实际上引用的是logMessage函数本身,因此此时的logMessage()其实是一个不带任何修饰符的函数调用,因此应用了默认绑定。</p>
</li>
<li><p>显式绑定or硬绑定</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">message: <span class="string">'Hello, World!'</span></span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">logMessage</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="built_in">this</span>.message); <span class="comment">// logs 'Hello, World!'</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// Using func.call() method</span></span><br><span class="line">logMessage.call(object);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Using func.apply() method</span></span><br><span class="line">logMessage.apply(object);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Creating a bound function</span></span><br><span class="line"><span class="keyword">const</span> boundLogMessage = logMessage.bind(object);</span><br><span class="line">boundLogMessage();</span><br></pre></td></tr></table></figure></li>
<li><p><code>'Hello, World!'</code> 和 <code>'Goodbye, undefined!'</code></p>
<p>当调用<code>object.greet()</code>时,在<code>greet()</code>方法内部,<code>this</code>值等于 object,因为<code>greet</code>是一个常规函数。因此<code>object.greet()</code>返回<code>'Hello, World!'</code>。</p>
<p>但是<code>farewell()</code>是一个箭头函数,箭头函数中的<code>this</code>值总是等于外部作用域中的<code>this</code>值。</p>
<p><code>farewell()</code>的外部作用域是全局作用域,它是全局对象。因此<code>object.farewell()</code>实际上返回<code>'Goodbye, ${window.who}!'</code>,它的结果为<code>'Goodbye, undefined!'</code>。</p>
</li>
<li><p>4</p>
<p><code>callback()</code>是在<code>method()</code>内部使用常规函数调用来调用的。由于在常规函数调用期间的<code>this</code>值等于全局对象,所以<code>this.length</code>结果为<code>window.length</code>。</p>
<p>第一个语句<code>var length = 4</code>,处于最外层的作用域,在全局对象 <code>window</code> 上创建一个属性<code>length</code>。</p>
</li>
<li><p>3</p>
</li>
</ol>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
</div>
<div class="post-block">
<article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
<link itemprop="mainEntityOfPage" href="http://example.com/2024/03/07/closure/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar.gif">
<meta itemprop="name" content="Ladyfish">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="Hexo">
<meta itemprop="description" content="">
</span>
<span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
<meta itemprop="name" content="undefined | Hexo">
<meta itemprop="description" content="">
</span>
<header class="post-header">
<h2 class="post-title" itemprop="name headline">
<a href="/2024/03/07/closure/" class="post-title-link" itemprop="url">模块与闭包</a>
</h2>
<div class="post-meta-container">
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar"></i>
</span>
<span class="post-meta-item-text">Posted on</span>
<time title="Created: 2024-03-07 22:57:08" itemprop="dateCreated datePublished" datetime="2024-03-07T22:57:08+08:00">2024-03-07</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar-check"></i>
</span>
<span class="post-meta-item-text">Edited on</span>
<time title="Modified: 2024-03-08 23:31:10" itemprop="dateModified" datetime="2024-03-08T23:31:10+08:00">2024-03-08</time>
</span>
</div>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<p>最近重新翻读《你不知道的JavaScript》有感,进行系列记录,本文适合已经对闭包和模块有些许理解的同学阅读~</p>
<p>下面复习一下闭包</p>
<p>闭包的定义:当函数可以记住并访问所在的词法作用域时,就产生了闭包;闭包使得函数即使是在当前词法作用域之外执行也可以继续访问定义时的词法作用域。</p>
<h4 id="1-探讨模块与闭包之间的关系"><a href="#1-探讨模块与闭包之间的关系" class="headerlink" title="1.探讨模块与闭包之间的关系"></a>1.探讨模块与闭包之间的关系</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">CoolModule</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="keyword">var</span> something = <span class="string">"cool"</span>;</span><br><span class="line"> <span class="keyword">var</span> another = [<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>];</span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">doSomething</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="built_in">console</span>.log(something);</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">doAnother</span></span>{</span><br><span class="line"> <span class="built_in">console</span>.log(another.join(<span class="string">'!'</span>));</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> {</span><br><span class="line"> <span class="attr">doSomething</span>:doSomething,</span><br><span class="line"> <span class="attr">doAnother</span>:doAnother</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<p>观察以上代码我们可以发现:</p>
<ol>
<li>CoolModule()只是一个函数,必须调用才能创建一个模块实例,如果不进行调用,内部作用域和闭包都无法被创建</li>
<li>CoolModule()返回一个对象,该对象含有对内部函数而不是内部数据变量的引用,内部数据变量保持隐藏且私有的状态,我们可以把这个返回的对象看作本质上是模块的公共API</li>
<li>doSomething和doAnother函数具有涵盖模块实例内部作用域的闭包</li>
</ol>
<p>综上所述,模块模式需要两个条件:</p>
<ol>
<li>必须要有外部的封闭函数,该函数至少被调用一次(每次调用都会创建一个新的模块实例)</li>
<li>封闭函数必须返回至少一个内部函数,这样内部函数才能在私有作用域中形成闭包,并且可以访问或者修改私有的状态</li>
</ol>
<h4 id="2-现代模块机制"><a href="#2-现代模块机制" class="headerlink" title="2.现代模块机制"></a>2.现代模块机制</h4><p>将上述的模块定义封装进一个友好API里,代码很优雅,我觉得很值得学习</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> MyModules = (<span class="function"><span class="keyword">function</span> <span class="title">Manager</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> modules = {}</span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">define</span>(<span class="params">name, deps, impl</span>) </span>{</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i < deps.length; i++) {</span><br><span class="line"> <span class="comment">//遍历依赖队列,使用模块中的实际依赖进行重新赋值</span></span><br><span class="line"> deps[i] = modules[deps[i]]</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//调用函数,并且使用依赖</span></span><br><span class="line"> modules[name] = impl.apply(impl, deps)</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">get</span>(<span class="params">name</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> modules[name]</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> {</span><br><span class="line"> <span class="attr">define</span>: define,</span><br><span class="line"> <span class="attr">get</span>: get,</span><br><span class="line"> }</span><br><span class="line"> })()</span><br><span class="line"> MyModules.define(<span class="string">'bar'</span>, [], <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">hello</span>(<span class="params">who</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="string">'helloooooo'</span> + who</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> { <span class="attr">hello</span>: hello }</span><br><span class="line"> })</span><br><span class="line"> MyModules.define(<span class="string">'foo'</span>, [bar], <span class="function"><span class="keyword">function</span> (<span class="params">bar</span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> hungry = <span class="string">'hipoo'</span></span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">awesome</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(bar.hello(hungry).toUpperCase())</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> {</span><br><span class="line"> <span class="attr">awesome</span>: awesome,</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line"></span><br><span class="line"> <span class="keyword">var</span> bar = MyModules.get(<span class="string">'bar'</span>)</span><br><span class="line"> <span class="keyword">var</span> foo = MyModules.get(<span class="string">'foo'</span>)</span><br><span class="line"> <span class="built_in">console</span>.log(bar.hello(<span class="string">'hipoo'</span>))</span><br><span class="line"> foo.awesome()</span><br></pre></td></tr></table></figure>
<p>直接看上面的代码可能会有点难以理解,下面我搭配debug跟大家一起看看~</p>
<p><img src="/image/image-20240308112101523.png" alt="image-20240308112101523"></p>
<p>从上图可以看到调用了get函数同时也持有了get函数对原始定义作用域的引用(可以看到私有的变量modules及我们添加在上面的bar和foo)这就是闭包的效果,同时暴露公共API(<code>define</code>和<code>get</code>)得以对隐藏且私有的内部数据变量进行访问或修改。</p>
<p>其次,该段代码的核心<code>modules[name] = impl.apply(impl, deps)</code>可以做到使用模块中与传递进来的依赖队列同名的依赖模块传递到函数中,实现函数调用。</p>
<p>相信我,以上代码看着简单写起来可不简单哦~不仅要熟悉掌握闭包的使用还要熟悉模块模式该设计模式,所以建议大家认真看看,最好自己动手写写ヾ(•ω•`)o</p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
</div>
<div class="post-block">
<article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
<link itemprop="mainEntityOfPage" href="http://example.com/2024/03/03/virtualList/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar.gif">
<meta itemprop="name" content="Ladyfish">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="Hexo">
<meta itemprop="description" content="">
</span>
<span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
<meta itemprop="name" content="undefined | Hexo">
<meta itemprop="description" content="">
</span>
<header class="post-header">
<h2 class="post-title" itemprop="name headline">
<a href="/2024/03/03/virtualList/" class="post-title-link" itemprop="url">不是,是谁还在傻傻遍历生成成千上万个DOM?</a>
</h2>
<div class="post-meta-container">
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar"></i>
</span>
<span class="post-meta-item-text">Posted on</span>
<time title="Created: 2024-03-03 22:39:39 / Modified: 22:43:31" itemprop="dateCreated datePublished" datetime="2024-03-03T22:39:39+08:00">2024-03-03</time>
</span>
</div>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<p>虚拟列表赶紧用起来,轻轻松松解决超多重复DOM节点造成的卡顿~</p>
<p>以下有三种不同级别的虚拟列表,分别针对生成的重复DOM节点是固定高度、不同高度和动态变化高度~</p>
<h3 id="1-基础段位:固定高度"><a href="#1-基础段位:固定高度" class="headerlink" title="1.基础段位:固定高度"></a>1.基础段位:固定高度</h3><p><img src="/image/tutieshi_640x594_13s.gif" alt="tutieshi_640x594_13s"></p>
<p>虚拟列表的原理其实就是以下几条:</p>
<p>①一个外层盒子提供滚动事件</p>
<p>②外层盒子中装的第一个是platform,一个空盒子,这个空盒子的高度是列表如果真实渲染应该有的高度,作用是为了撑开外层盒子,提供滚动条</p>
<p>②外层盒子中装的第二个是展示列表盒子,这个盒子中放置所有现在应该出现在页面上的列表项和前后缓冲区。该盒子采用绝对定位,top值根据滚动位置实时改变,让展示列表不论怎么滚动一直出现在页面上</p>
<p>④酌情给一些在页面展示之前之后的缓冲区,防止因为用户滚动过快而造成的空白</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br></pre></td><td class="code"><pre><span class="line"><template></span><br><span class="line"> <div class="virtualBox" @scroll="scrollEvent" ref="virtualBox"></span><br><span class="line"> <div class="platform" :style="{ height: platformHeight + 'px' }"></span><br><span class="line"> </div></span><br><span class="line"> <div class="trueBox" :style="{ top: top + 'px' }"></span><br><span class="line"> <div v-for="(key, value) in showData" class="itemBox" ref="itemBox"></span><br><span class="line"> <button>看起来{{ key }} 其实我是{{ value }}</button></span><br><span class="line"> </div></span><br><span class="line"> </div></span><br><span class="line"> </div></span><br><span class="line"></template></span><br><span class="line"></span><br><span class="line"><script></span><br><span class="line">export default {</span><br><span class="line"> name: 'WebFront',</span><br><span class="line"> data() {</span><br><span class="line"> return {</span><br><span class="line"> listData: [],//真实列表Data</span><br><span class="line"> count: 100,//真实列表项的个数,我这里为了展示手动赋值,真是使用直接获取Data长度即可</span><br><span class="line"> platformHeight:0//platform的高度</span><br><span class="line"> showData: [],//被展示的列表Data</span><br><span class="line"> startIndex: 0,//开始截取listData的Index</span><br><span class="line"> showNum: 1,//页面高度可以展示几个列表项</span><br><span class="line"> top: 0,//展示列表盒子绝对定位的top值</span><br><span class="line"> catchFrontNum: 4, //前缓冲区的数量</span><br><span class="line"> catchBackNum: 4,//后缓冲区的数量</span><br><span class="line"> itemHeight: 0,//列表项的高度</span><br><span class="line"> }</span><br><span class="line"> },</span><br><span class="line"> methods: {</span><br><span class="line"> scrollEvent(e) {</span><br><span class="line"> let scrollTop = e.target.scrollTop//获取滚动的距离</span><br><span class="line"> this.startIndex = Math.ceil(scrollTop / this.itemHeight)//滚动距离除以列表项的高度得到应该展示的列表项Index</span><br><span class="line"> this.startIndex =</span><br><span class="line"> this.startIndex < this.catchFrontNum</span><br><span class="line"> ? 0</span><br><span class="line"> : this.startIndex - this.catchFrontNum//设置前缓冲区</span><br><span class="line"> //对展示的数组进行截取</span><br><span class="line"> this.showData = this.listData.slice(</span><br><span class="line"> this.startIndex,</span><br><span class="line"> this.startIndex + this.showNum + this.catchBackNum + this.catchFrontNum</span><br><span class="line"> )</span><br><span class="line"> //绝对定位的展示列表项盒子的top值</span><br><span class="line"> this.top = this.startIndex * this.itemHeight</span><br><span class="line"> },</span><br><span class="line"> },</span><br><span class="line"> mounted() {</span><br><span class="line"> const virtualBox = this.$refs.virtualBox // 获取到最外层盒子</span><br><span class="line"> let itemBox = document.getElementsByClassName('itemBox')[0]</span><br><span class="line"> this.itemHeight = itemBox.offsetHeight//获取列表项</span><br><span class="line"> this.platformHeight = this.count * this.itemHeight</span><br><span class="line"> this.showNum = Math.ceil(virtualBox.clientHeight / this.itemHeight)//外层盒子的可视高度除以列表项高度可以得到展示数量</span><br><span class="line"> this.showData = this.listData.slice(</span><br><span class="line"> this.startIndex,</span><br><span class="line"> this.startIndex + this.showNum + this.catchBackNum+ this.catchFrontNum</span><br><span class="line"> )</span><br><span class="line"> },</span><br><span class="line"> created() {</span><br><span class="line"> //做一些假数据用于展示</span><br><span class="line"> let i = 0</span><br><span class="line"> for (i = 0; i < 100; i++) {</span><br><span class="line"> this.listData[i] = '我是' + i</span><br><span class="line"> }</span><br><span class="line"> this.showData = this.listData.slice(0, 20)</span><br><span class="line"> },</span><br><span class="line">}</span><br><span class="line"></script></span><br><span class="line"><style scoped></span><br><span class="line">.trueBox {</span><br><span class="line"> position: absolute;</span><br><span class="line"> top: 0;</span><br><span class="line">}</span><br><span class="line">.itemBox {</span><br><span class="line"> height: 50px;</span><br><span class="line"> background-color: green;</span><br><span class="line"> display: flex;</span><br><span class="line"> align-items: center;</span><br><span class="line"> justify-content: center;</span><br><span class="line"> padding: 10px;</span><br><span class="line">}</span><br><span class="line">.platform {</span><br><span class="line"> background-color: red;</span><br><span class="line">}</span><br><span class="line">.virtualBox {</span><br><span class="line"> height: 85vh;</span><br><span class="line"> overflow: scroll;</span><br><span class="line"> position: relative;</span><br><span class="line">}</span><br><span class="line"></style></span><br></pre></td></tr></table></figure>
<h3 id="2-进阶段位:不同高度"><a href="#2-进阶段位:不同高度" class="headerlink" title="2.进阶段位:不同高度"></a>2.进阶段位:不同高度</h3><p><img src="/image/tutieshi_640x657_7s.gif" alt="tutieshi_640x594_13s"></p>
<p>与固定高度不同,列表项的高度是不固定的,所以会出现以下这些难点:</p>
<p>①无法通过页面高度除以列表项高度得到应当展示的数量,也就是展示列表的长度</p>
<p>②无法通过滚动了的高度scrollTop除以列表项高度得到此时应该展示的列表项Index</p>
<p>③无法直接通过ListData的长度乘以列表项高度得到platform的高度</p>
<p>对于以上难点我们的解决方案:</p>
<p>①设置一个预告高度,用于计算页面展示的数量,该预估高度建议偏小,避免出现页面展示数量不够的情况</p>
<p>②设置一个position数组,计算并存储每一个列表项的top\bottom\height值,通过比较scrollTop和列表项的position可以得到此时应该展示的列表项Index</p>
<p>③通过position数组获取最后一个列表项的bottom值,即为platform的高度</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br></pre></td><td class="code"><pre><span class="line"><template></span><br><span class="line"> <div class="virtualBox" @scroll="scrollEvent" ref="virtualBox"></span><br><span class="line"> <div class="platform" :style="{ height: platformHeight + 'px' }"></span><br><span class="line"> <!-- 这是假的容器,作用:撑开盒子和提供滚动效果 --></span><br><span class="line"> </div></span><br><span class="line"> <div class="trueBox" :style="{ top: top + 'px' }"></span><br><span class="line"> <div</span><br><span class="line"> v-for="(item, key) in showData"</span><br><span class="line"> class="itemBox"</span><br><span class="line"> ref="items"</span><br><span class="line"> :id="item.id"</span><br><span class="line"> :key="item.id"</span><br><span class="line"> ></span><br><span class="line"> 看着第{{ key }}个 其实第{{ item.id }}个</span><br><span class="line"> {{ item.value }}</span><br><span class="line"> </div></span><br><span class="line"> </div></span><br><span class="line"> </div></span><br><span class="line"></template></span><br><span class="line"></span><br><span class="line"><script></span><br><span class="line">export default {</span><br><span class="line"> name: 'WebFront',</span><br><span class="line"> data() {</span><br><span class="line"> return {</span><br><span class="line"> position: [],</span><br><span class="line"> listData: [],</span><br><span class="line"> platformHeight: 0,</span><br><span class="line"> count: 100,</span><br><span class="line"> scrollTop: 0,</span><br><span class="line"> showData: [],</span><br><span class="line"> startIndex: 0,</span><br><span class="line"> showNum: 0,</span><br><span class="line"> top: 0,</span><br><span class="line"> estimatedItemHeight: 100,//预设高度</span><br><span class="line"> }</span><br><span class="line"> },</span><br><span class="line"> methods: {</span><br><span class="line"> updateItemsSize() {</span><br><span class="line"> //更新列表项高度</span><br><span class="line"> let nodes = this.$refs.items</span><br><span class="line"> nodes.forEach((node) => {</span><br><span class="line"> let rect = node.getBoundingClientRect()</span><br><span class="line"> let height = rect.height</span><br><span class="line"> let index = parseInt(node.id)</span><br><span class="line"> let oldHeight = this.position[index].height</span><br><span class="line"> let dValue = oldHeight - height</span><br><span class="line"> if (dValue) {</span><br><span class="line"> this.position[index].bottom = this.position[index].bottom - dValue</span><br><span class="line"> this.position[index].height = height</span><br><span class="line"> for (let k = index + 1; k < this.position.length; k++) {</span><br><span class="line"> this.position[k].top = this.position[k - 1].bottom</span><br><span class="line"> this.position[k].bottom = this.position[k].bottom - dValue</span><br><span class="line"> }</span><br><span class="line"> this.platformHeight = this.position[this.position.length - 1].bottom</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line"> },</span><br><span class="line"> findStartIndex(scrollTop, list) {</span><br><span class="line"> //根据滚动高度scrollTop找到此时的startIndex</span><br><span class="line"> for (let i = 0, len = list.length; i < len; i++) {</span><br><span class="line"> if (list[i].top > scrollTop) {</span><br><span class="line"> return i - 1</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> return list.length - 1</span><br><span class="line"> },</span><br><span class="line"> scrollEvent(e) {</span><br><span class="line"> this.updateItemsSize()</span><br><span class="line"> this.scrollTop = e.target.scrollTop</span><br><span class="line"> let index = this.findStartIndex(this.scrollTop, this.position)</span><br><span class="line"> this.startIndex =</span><br><span class="line"> index < this.listData.length - 1 - this.showNum</span><br><span class="line"> ? index</span><br><span class="line"> : this.listData.length - 1 - this.showNum</span><br><span class="line"> //至少保留showNum个列表项</span><br><span class="line"> this.showData = this.listData.slice(</span><br><span class="line"> this.startIndex,</span><br><span class="line"> this.startIndex + this.showNum + 2</span><br><span class="line"> )</span><br><span class="line"> this.top = this.position[this.startIndex].top</span><br><span class="line"> },</span><br><span class="line"> createString(num) {</span><br><span class="line"> let str = ''</span><br><span class="line"> for (let i = 0; i < num; i++) {</span><br><span class="line"> str += 'aa'</span><br><span class="line"> }</span><br><span class="line"> return str</span><br><span class="line"> },</span><br><span class="line"> },</span><br><span class="line"> mounted() {</span><br><span class="line"> this.position = this.listData.map((item, index) => ({</span><br><span class="line"> index,</span><br><span class="line"> top: index * this.estimatedItemHeight,</span><br><span class="line"> bottom: (index + 1) * this.estimatedItemHeight,</span><br><span class="line"> height: this.estimatedItemHeight,</span><br><span class="line"> }))</span><br><span class="line"> this.platformHeight = this.position[this.position.length - 1].bottom</span><br><span class="line"> this.showNum = Math.ceil(</span><br><span class="line"> this.$refs.virtualBox.clientHeight / this.estimatedItemHeight</span><br><span class="line"> )</span><br><span class="line"> this.showData = this.listData.slice(</span><br><span class="line"> this.startIndex,</span><br><span class="line"> this.startIndex + this.showNum + 2</span><br><span class="line"> )</span><br><span class="line"> },</span><br><span class="line"> created() {</span><br><span class="line"> let i = 0</span><br><span class="line"> for (i = 0; i < 100; i++) {</span><br><span class="line"> this.listData[i] = {}</span><br><span class="line"> this.listData[i].value = this.createString(</span><br><span class="line"> Math.floor(Math.random() * 100)</span><br><span class="line"> )</span><br><span class="line"> this.listData[i].id = i</span><br><span class="line"> }</span><br><span class="line"> this.showData = this.listData.slice(0, 20)</span><br><span class="line"> },</span><br><span class="line">}</span><br><span class="line"></script></span><br><span class="line"><style scoped></span><br><span class="line">.trueBox {</span><br><span class="line"> position: absolute;</span><br><span class="line"> top: 0;</span><br><span class="line">}</span><br><span class="line">.itemBox {</span><br><span class="line"> background-color: green;</span><br><span class="line"> display: block;</span><br><span class="line"> line-height: 100%;</span><br><span class="line"> word-break: break-all;</span><br><span class="line"> width: 100px;</span><br><span class="line"> padding: 10px;</span><br><span class="line"> border: 2px purple solid;</span><br><span class="line">}</span><br><span class="line">.platform {</span><br><span class="line"> background-color: red;</span><br><span class="line">}</span><br><span class="line">.virtualBox {</span><br><span class="line"> height: 85vh;</span><br><span class="line"> overflow: scroll;</span><br><span class="line"> position: relative;</span><br><span class="line">}</span><br><span class="line"></style></span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h3 id="3-高阶段位:变化高度"><a href="#3-高阶段位:变化高度" class="headerlink" title="3.高阶段位:变化高度"></a>3.高阶段位:变化高度</h3><p>这种情况可能出现在比如列表项因为太长而设置了展开/收缩按钮,此时列表项的高度是动态发生变化的,这种情况和上一种情况差不多,区别只在于这种情况只需要在点击按钮的时候将position更新即可~所以在这里不做代码演示啦</p>
<h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>了解了原理要写出来还是不难的~但我个人感觉有的时候前端的进阶难就难在止步于此,现在的浏览器性能好,可能写N个DOM都不会卡顿,很难会有觉悟自己去写一个虚拟列表来试试看性能是不是更好。希望自己永不止步,永远进步</p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
</div>
<div class="post-block">
<article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
<link itemprop="mainEntityOfPage" href="http://example.com/2024/03/02/valueOf&toString/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar.gif">
<meta itemprop="name" content="Ladyfish">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="Hexo">
<meta itemprop="description" content="">
</span>
<span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
<meta itemprop="name" content="undefined | Hexo">
<meta itemprop="description" content="">
</span>
<header class="post-header">
<h2 class="post-title" itemprop="name headline">
<a href="/2024/03/02/valueOf&toString/" class="post-title-link" itemprop="url">在你不知道的地方JS偷偷调用了valueOf和toString!</a>
</h2>
<div class="post-meta-container">
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar"></i>
</span>
<span class="post-meta-item-text">Posted on</span>
<time title="Created: 2024-03-02 20:34:43 / Modified: 21:08:25" itemprop="dateCreated datePublished" datetime="2024-03-02T20:34:43+08:00">2024-03-02</time>
</span>
</div>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<p>JavaScript中valueOf、toString的隐式调用</p>
<p>在你不知道的地方JS偷偷调用了valueOf和toString!</p>
<h3 id="一、问题引入"><a href="#一、问题引入" class="headerlink" title="一、问题引入"></a>一、问题引入</h3><p>你知道执行以下三种情况,控制台会打印什么吗?</p>
<h4 id="(1)情况一:方法的返回值为1"><a href="#(1)情况一:方法的返回值为1" class="headerlink" title="(1)情况一:方法的返回值为1"></a>(1)情况一:方法的返回值为1</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">Array</span>.prototype.toString = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'array-----调用toString方法'</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span></span><br><span class="line">}</span><br><span class="line"><span class="built_in">Array</span>.prototype.valueOf = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'array-----调用valueOf方法'</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span></span><br><span class="line">}</span><br><span class="line"><span class="built_in">Function</span>.prototype.toString = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'function-----调用toString方法'</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span></span><br><span class="line">}</span><br><span class="line"><span class="built_in">Function</span>.prototype.valueOf = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'function-----调用valueOf方法'</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> arr = <span class="keyword">new</span> <span class="built_in">Array</span>()</span><br><span class="line"><span class="keyword">let</span> fn = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'函数内打印'</span>)</span><br><span class="line">}</span><br><span class="line"><span class="built_in">console</span>.log(arr)</span><br><span class="line"><span class="built_in">console</span>.log(fn)</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">'console.log-----'</span> + arr)</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">'console.log-----'</span> + fn)</span><br></pre></td></tr></table></figure>
<h4 id="(2)情况二:方法无返回值"><a href="#(2)情况二:方法无返回值" class="headerlink" title="(2)情况二:方法无返回值"></a>(2)情况二:方法无返回值</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">Array</span>.prototype.toString = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'array-----调用toString方法'</span>)</span><br><span class="line">}</span><br><span class="line"><span class="built_in">Array</span>.prototype.valueOf = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'array-----调用valueOf方法'</span>)</span><br><span class="line">}</span><br><span class="line"><span class="built_in">Function</span>.prototype.toString = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'function-----调用toString方法'</span>)</span><br><span class="line">}</span><br><span class="line"><span class="built_in">Function</span>.prototype.valueOf = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'function-----调用valueOf方法'</span>)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> arr = <span class="keyword">new</span> <span class="built_in">Array</span>()</span><br><span class="line"><span class="keyword">let</span> fn = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'函数内打印'</span>)</span><br><span class="line">}</span><br><span class="line"><span class="built_in">console</span>.log(arr)</span><br><span class="line"><span class="built_in">console</span>.log(fn)</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">'console.log-----'</span> + arr)</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">'console.log-----'</span> + fn)</span><br></pre></td></tr></table></figure>
<h4 id="(3)情况三:方法返回值为一个匿名函数"><a href="#(3)情况三:方法返回值为一个匿名函数" class="headerlink" title="(3)情况三:方法返回值为一个匿名函数"></a>(3)情况三:方法返回值为一个匿名函数</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">Array</span>.prototype.toString = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'array-----调用toString方法'</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{}</span><br><span class="line">}</span><br><span class="line"><span class="built_in">Array</span>.prototype.valueOf = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'array-----调用valueOf方法'</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{}</span><br><span class="line">}</span><br><span class="line"><span class="built_in">Function</span>.prototype.toString = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'function-----调用toString方法'</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{}</span><br><span class="line">}</span><br><span class="line"><span class="built_in">Function</span>.prototype.valueOf = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'function-----调用valueOf方法'</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> arr = <span class="keyword">new</span> <span class="built_in">Array</span>()</span><br><span class="line"><span class="keyword">let</span> fn = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'函数内打印'</span>)</span><br><span class="line">}</span><br><span class="line"><span class="built_in">console</span>.log(arr)</span><br><span class="line"><span class="built_in">console</span>.log(fn)</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">'console.log-----'</span> + arr)</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">'console.log-----'</span> + fn)</span><br></pre></td></tr></table></figure>
<p>控制台输出如下,你答对了吗?</p>
<h4 id="控制台输出结果:"><a href="#控制台输出结果:" class="headerlink" title="控制台输出结果:"></a>控制台输出结果:</h4><p><img src="/image/image-20220809115757055.png" alt="image-20220809115757055.png"></p>
<p><img src="/image/image-20220809115923874.png" alt="image-20220809115923874"></p>
<p><img src="/image/image-20220809115959212.png" alt="image-20220809115757055.png"></p>
<p>全对的大佬可以出门左转了,出现错误的同学请继续往下看~</p>
<h3 id="二、具体情况分析"><a href="#二、具体情况分析" class="headerlink" title="二、具体情况分析"></a>二、具体情况分析</h3><p>针对直接使用cosole.log打印单独的对象,打印语句一在三种情况下都发挥正常。但是往下看,打印语句二<code>console.log(fn)</code></p>
<p><img src="/image/image-20220809121806237.png" alt="image-20220809121806237"></p>
<p><img src="/image/image-20220809121817987.png" alt="image-20220809121817987"></p>
<p><img src="/image/image-20220809121828969.png" alt="image-20220809121828969"></p>
<ul>
<li> 方法返回值为1:打印函数体,自动调用toString()</li>
<li> 方法无返回值(undefined):打印函数体,自动调用toString()</li>
<li> 方法返回匿名函数:打印函数体,自动调用toString()之后调用valueOf()</li>
</ul>
<p>从上面的结果中我们猜测,当打印的内容为函数时,会在内部隐式调用toString(),如果toString()返回基本数据类型,则数据转换到此为止。如果返回对象数据类型,则在toString()之后还会调用valueOf()。</p>
<p>打印语句3和4:</p>
<p><img src="/image/image-20220809121901299.png" alt="image-20220809121901299"><img src="/image/image-20220809121914502.png" alt="image-20220809121914502"><img src="/image/image-20220809121925724.png" alt="image-20220809121925724"></p>
<ul>
<li> 方法返回值为1:自动调用valueOf(),打印valueOf()返回值</li>
<li> 方法无返回值(undefined):自动调用valueOf(),打印valueOf()返回值</li>
<li> 方法返回匿名函数:自动调用valueOf()之后调用toString(),报错</li>
</ul>
<p>有报错最好~从报的错误开始入手</p>
<p>TypeError: Cannot convert object to primitive value</p>
<p>翻译:不能将对象转换为原始值<br>查阅资料发现引用类型向原始类型转换遵循ToPrimitive规则</p>
<h4 id="⭐️ToPrimitive规则"><a href="#⭐️ToPrimitive规则" class="headerlink" title="⭐️ToPrimitive规则"></a>⭐️ToPrimitive规则</h4><p>是引用类型向原始类型转变的规则,它遵循先valueOf后toString的模式期望得到一个原始类型。如果还是没法得到一个原始类型,就会抛出 TypeError。</p>
<h3 id="三、总结"><a href="#三、总结" class="headerlink" title="三、总结"></a>三、总结</h3><h4 id="1-明确转换类型:"><a href="#1-明确转换类型:" class="headerlink" title="1.明确转换类型:"></a>1.明确转换类型:</h4><p>如alert,console.log明确引用类型是要转换为字符串类型,那么采用的策略是先toString后valueOf。</p>
<h4 id="2-不明确转换类型:"><a href="#2-不明确转换类型:" class="headerlink" title="2.不明确转换类型:"></a>2.不明确转换类型:</h4><p>如隐式类型转换,那么采用ToPrimitive规则,遵循先valueOf后toString的模式期望得到一个原始类型。</p>
<h4 id="MDN中valueOf-方法的返回值:"><a href="#MDN中valueOf-方法的返回值:" class="headerlink" title="MDN中valueOf()方法的返回值:"></a>MDN中valueOf()方法的返回值:</h4><p><img src="/image/image-20220809110411560.png" alt="image-20220809110411560"></p>
<h4 id="toString方法返回值"><a href="#toString方法返回值" class="headerlink" title="toString方法返回值"></a>toString方法返回值</h4><p><img src="/image/20190719180630686.png" alt="20190719180630686"></p>
<h4 id="3-返回值:"><a href="#3-返回值:" class="headerlink" title="3.返回值:"></a>3.返回值:</h4><p>在复写这两个函数时,函数返回值起着关键作用,可以决定调用几个方法和最后函数的返回值。好好利用这一特点与隐式自动调用的模式,助力成为装逼达人!</p>
<h4 id="4-注意点:"><a href="#4-注意点:" class="headerlink" title="4.注意点:"></a>4.注意点:</h4><p>alert会将两个方法最后得到的原始类型值进行返回</p>
<p><img src="/image/image-20220809113133100.png" alt="image-20220809113133100"><br>但是console.log不会,还是返回函数体。</p>
<p>其他引用类型类似,可以自己动手试试。</p>
<h3 id="四、问题"><a href="#四、问题" class="headerlink" title="四、问题"></a>四、问题</h3><p>对于console.log这个操作不太理解,使用alert阻塞。可以看到先提示调用方法,但是确认完alert弹窗之后,居然console.log打印语句出现在了上面。实在是不理解,希望有懂的大佬不吝赐教。</p>
<p><img src="/image/image-20220809153623938.png" alt="image-20220809153623938"> <img src="C:\Users\吴佳愉\AppData\Roaming\Typora\typora-user-images\image-20220809153646505.png" alt="image-20220809153646505"></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">Array</span>.prototype.toString = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'array-----调用toString方法'</span>)</span><br><span class="line"> alert(<span class="string">'array-----调用toString方法'</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span></span><br><span class="line">}</span><br><span class="line"><span class="built_in">Array</span>.prototype.valueOf = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'array-----调用valueOf方法'</span>)</span><br><span class="line"> alert(<span class="string">'array-----调用valueOf方法'</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span></span><br><span class="line">}</span><br><span class="line"><span class="built_in">Function</span>.prototype.toString = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'function-----调用toString方法'</span>)</span><br><span class="line"> alert(<span class="string">'function-----调用toString方法'</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span></span><br><span class="line">}</span><br><span class="line"><span class="built_in">Function</span>.prototype.valueOf = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'function-----调用valueOf方法'</span>)</span><br><span class="line"> alert(<span class="string">'function-----调用valueOf方法'</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span></span><br><span class="line">}</span><br><span class="line"><span class="keyword">let</span> arr = <span class="keyword">new</span> <span class="built_in">Array</span>()</span><br><span class="line"><span class="keyword">let</span> fn = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'函数内打印'</span>)</span><br><span class="line">}</span><br><span class="line"><span class="built_in">console</span>.log(arr);</span><br><span class="line"><span class="built_in">console</span>.log(fn);</span><br></pre></td></tr></table></figure>
<h3 id="五、踩坑心得"><a href="#五、踩坑心得" class="headerlink" title="五、踩坑心得"></a>五、踩坑心得</h3><p>事情是这样的,学习的时候看到一篇文章,对照着文章中的进行实践操作却得不到一样的结果,于是顺藤摸瓜摸出了这么多瓜。。。从柯里化到隐式调用到隐式类型转换。</p>
<p><img src="/image/image-20220809094045150.png" alt="image-20220809094045150"></p>
<h3 id="六、参考:"><a href="#六、参考:" class="headerlink" title="六、参考:"></a>六、参考:</h3><ul>
<li> <a target="_blank" rel="noopener" href="https://www.cnblogs.com/aNd1coder/archive/2013/03/09/2951959.html">https://www.cnblogs.com/aNd1coder/archive/2013/03/09/2951959.html</a></li>
<li> <a target="_blank" rel="noopener" href="https://www.jb51.net/article/32327.htm">https://www.jb51.net/article/32327.htm</a></li>
</ul>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
</div>
<div class="post-block">
<article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
<link itemprop="mainEntityOfPage" href="http://example.com/2023/12/11/nodejs-nvm%E5%AE%89%E8%A3%85/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar.gif">
<meta itemprop="name" content="Ladyfish">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="Hexo">
<meta itemprop="description" content="">
</span>
<span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
<meta itemprop="name" content="undefined | Hexo">
<meta itemprop="description" content="">
</span>
<header class="post-header">
<h2 class="post-title" itemprop="name headline">
<a href="/2023/12/11/nodejs-nvm%E5%AE%89%E8%A3%85/" class="post-title-link" itemprop="url">nodejs nvm安装</a>
</h2>
<div class="post-meta-container">
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar"></i>
</span>
<span class="post-meta-item-text">Posted on</span>
<time title="Created: 2023-12-11 15:47:20" itemprop="dateCreated datePublished" datetime="2023-12-11T15:47:20+08:00">2023-12-11</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar-check"></i>
</span>
<span class="post-meta-item-text">Edited on</span>
<time title="Modified: 2024-03-02 21:08:34" itemprop="dateModified" datetime="2024-03-02T21:08:34+08:00">2024-03-02</time>
</span>
</div>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<p>记录一下今天安装nvm过程遇到的一些问题~</p>
<p>nvm是一个node的版本管理工具,很适合我这种需要很多node版本的人</p>
<p>我的安装步骤:</p>
<ol>
<li>卸载原有的nodejs,我这一步卸得太干净了。。。把之前下的包都删掉了,悲伤悲伤(;´д`)ゞ 其实可以不用卸载原有的nodejs的,nvm可以将现有的nodejs添加到管理中的</li>
<li><a target="_blank" rel="noopener" href="https://github.com/coreybutler/nvm-windows/releases">nvm下载地址</a></li>
<li>安装完成后使用<code>nvm -v</code>检查一下nvm是否安装成功</li>
<li>安装成功后就可以使用以下命令使用啦:<ul>
<li>nvm on:开启nvm的nodejs版本管理</li>
<li>nvm intall <version>:安装指定版本</li>
<li>nvm use <version>:使用指定版本</li>
<li>nvm list [available]:显示已安装的列表。可选参数available,显示可安装的所有版本。list可简化为ls。</li>
<li>nvm uninstall <version>:卸载指定版本</li>
<li>nvm off:关闭nvm的nodejs版本管理</li>
</ul>
</li>
</ol>
<p>遇到的问题一:无法创建文件夹</p>
<p><img src="/image/image-20231211155947870.png" alt="image-20231211155947870"></p>
<p>解决办法:使用管理员身份打开cmd即可,给程序创建文件夹的权限</p>
<p>遇到的问题二:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">PS C:\Users\asus\Desktop\visual_sense_3d>npm i cnpm -g</span><br><span class="line">npm ERR! code ETIMEDOUT</span><br><span class="line">npm ERR! errno ETIMEDOUT</span><br><span class="line">npm ERR! network request to https://registry.npmjs.org/graceful-readlink failed, reason: connect ETIMEDOUT 104.16.25.35:443</span><br><span class="line">npm ERR! network This is a problem related to network connectivity.</span><br><span class="line">npm ERR! network In most cases you are behind a proxy or have bad network settings.</span><br><span class="line">npm ERR! network</span><br><span class="line">npm ERR! network If you are behind a proxy, please make sure that the</span><br><span class="line">npm ERR! network 'proxy' config is set properly. See: 'npm help config'</span><br><span class="line"> </span><br><span class="line">npm ERR! A complete log of this run can be found in:</span><br><span class="line">npm ERR! C:\Users\Deshun\AppData\Roaming\npm-cache\_logs\2023-12-01T03_09_36_539Z-debug.log</span><br></pre></td></tr></table></figure>
<p>解决方法:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">1.查看npm镜像设置</span><br><span class="line">npm config get registry</span><br><span class="line">2.将npm设置为淘宝镜像</span><br><span class="line">npm config set registry https://registry.npm.taobao.org</span><br><span class="line">3.再次查看npm镜像设置</span><br><span class="line">npm config get registry</span><br></pre></td></tr></table></figure>
<p>应该是由于我前面安装nvm的时候在setting.txt文件中已经修改了node的镜像为taobao,所以在这个地方也要对应修改</p>
<p>安装完毕,美美用起nvm,真的很方便,随意丝滑切换node版本( ̄︶ ̄*))</p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
</div>
<div class="post-block">
<article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
<link itemprop="mainEntityOfPage" href="http://example.com/2023/11/22/chrome-devtools/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar.gif">
<meta itemprop="name" content="Ladyfish">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="Hexo">
<meta itemprop="description" content="">
</span>
<span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
<meta itemprop="name" content="undefined | Hexo">
<meta itemprop="description" content="">
</span>
<header class="post-header">
<h2 class="post-title" itemprop="name headline">
<a href="/2023/11/22/chrome-devtools/" class="post-title-link" itemprop="url">chrome-devtools > Application</a>
</h2>
<div class="post-meta-container">
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar"></i>
</span>
<span class="post-meta-item-text">Posted on</span>
<time title="Created: 2023-11-22 12:45:18 / Modified: 15:26:17" itemprop="dateCreated datePublished" datetime="2023-11-22T12:45:18+08:00">2023-11-22</time>
</span>
</div>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h3 id="Application-gt-Manifest"><a href="#Application-gt-Manifest" class="headerlink" title="Application > Manifest"></a>Application > Manifest</h3><p><img src="https://wd.imgix.net/image/NJdAV9UgKuN8AhoaPBquL7giZQo1/t2qbshH5F1g24IcsNbZz.png?auto=format" alt="清单窗格。"></p>
<p>:sunflower:作用:</p>
<p>当你希望用户能够将该引用程序添加到Mac OS上的“应用程序”文件夹、Windows上的“开始”菜单以及Android和IOS上的主屏幕时,需要一个Web应用程序清单。设置应用程序清单后,可以打开devtools中的Manifest中检验配置是否正确。</p>
<p>:sunflower:编写Web应用程序清单:</p>
<p>清单文件可采用任何名称,但通常命名为 <code>manifest.json</code>,并从根目录(网站的顶级目录)提供。该规范建议该扩展项应为 <code>.webmanifest</code>,但浏览器也支持 <code>.json</code> 扩展项。</p>
<p>创建清单后,将 <code><link></code> 标记添加到渐进式 Web 应用的所有页面。例如:</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">link</span> <span class="attr">rel</span>=<span class="string">"manifest"</span> <span class="attr">href</span>=<span class="string">"/manifest.json"</span>></span></span><br></pre></td></tr></table></figure>
<p>具体的Manifest编写规则和配置项如下:<a target="_blank" rel="noopener" href="https://web.dev/articles/add-manifest?hl=zh-cn">https://web.dev/articles/add-manifest?hl=zh-cn</a></p>
<h3 id="Application-gt-Service-Worker"><a href="#Application-gt-Service-Worker" class="headerlink" title="Application > Service Worker"></a>Application > Service Worker</h3><p><img src="https://wd.imgix.net/image/NJdAV9UgKuN8AhoaPBquL7giZQo1/TATykdak02rXVcKINPJ5.png?auto=format" alt="Service Worker 窗格。"></p>
<p>在该位置我们对Service Worker进行检查和调试</p>
<p>:sunflower:Service Worker :</p>
<p>本质上充当位于 Web 应用程序、浏览器和网络(如果可用)之间的代理服务器。除其他外,它们的目的是创建有效的离线体验、拦截网络请求并根据网络是否可用采取适当的操作,以及更新服务器上的资产。它们还允许访问推送通知和后台同步 API。</p>
<p>:sunflower:特性:</p>
<ol>
<li>没有DOM访问权限</li>
<li>无法动态导入JS模块,如果在Service Worker全局范围内调用<code>import().</code>则会抛出异常,但允许使用<code>import</code>语句进行静态导入</li>
<li>Service Worker被设计为完全异步,在与主JavaScript不同的线程上运行,因此它是非阻塞的,所以同步XHR和Web Storage等API无法在Service Worker内部进行使用</li>
<li>仅允许通过HTTPS运行</li>
</ol>
<p>具体编写Service Worker参考如下:<a target="_blank" rel="noopener" href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API">https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API</a></p>
<h3 id="Application-gt-LocalStorage"><a href="#Application-gt-LocalStorage" class="headerlink" title="Application > LocalStorage"></a>Application > LocalStorage</h3><p>localStorage 用于长久保存整个网站的数据,保存的数据没有过期时间,直到手动去删除。</p>
<p><strong>:hatched_chick:localStorage 的优势</strong></p>
<ul>
<li> 1、localStorage 拓展了 cookie 的 4K 限制。</li>
<li> 2、localStorage 会可以将第一次请求的数据直接存储到本地,这个相当于一个 5M 大小的针对于前端页面的数据库,相比于 cookie 可以节约带宽,但是这个却是只有在高版本的浏览器中才支持的。</li>
</ul>