-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsearch.xml
1294 lines (623 loc) · 456 KB
/
search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
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
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>「精通以太坊」第二章👉🏻Ethereum Basics</title>
<link href="/2019/03/19/%E3%80%8C%E7%B2%BE%E9%80%9A%E4%BB%A5%E5%A4%AA%E5%9D%8A%E3%80%8D%E2%98%9E%E7%AC%AC%E4%BA%8C%E7%AB%A0/"/>
<url>/2019/03/19/%E3%80%8C%E7%B2%BE%E9%80%9A%E4%BB%A5%E5%A4%AA%E5%9D%8A%E3%80%8D%E2%98%9E%E7%AC%AC%E4%BA%8C%E7%AB%A0/</url>
<content type="html"><![CDATA[<h3 id="以太坊基础"><a href="#以太坊基础" class="headerlink" title="以太坊基础"></a>以太坊基础</h3><h4 id="控制和责任"><a href="#控制和责任" class="headerlink" title="控制和责任"></a>控制和责任</h4><p>每个用户都能控制自己的密钥,密钥是专属于个人的,这种控制带来了很大的责任。如果你丢失了你的密钥,你将无法获得资金和合约。没有人可以帮助你重新获得访问权 - 你的资金将永远锁定。</p><h4 id="以太坊货币单位"><a href="#以太坊货币单位" class="headerlink" title="以太坊货币单位"></a>以太坊货币单位</h4><p>以太 ether </p><p>以太被细分为更小的单位,最小单位为wei。</p><p>1 ether = 10^18^wei </p><p>💡以太坊是制度(是公链),以太才是货币</p><font style="color:white;background:mediumseagreen;padding:3px 6px;font-weight:bold;line-height:28px">单位名</font><p>wei => wei</p><p>Kwei => babbage</p><p>Mwei => lavelace</p><p>Gwei => shannon</p><p>MicroEther => szabo</p><p>MilliEther => finney</p><p>ether => ether</p><p>Kether => grand</p><p>Mether</p><h4 id="以太坊钱包"><a href="#以太坊钱包" class="headerlink" title="以太坊钱包"></a>以太坊钱包</h4><p>以太坊钱包是通往以太坊的门户。</p><p>钱包管理你的密钥,并可代表你创建广播和交易。</p><p>MetaMask 浏览器扩展钱包</p><p>Jaxx 多平台 多币种 钱包</p><p>MyEtherWallet(MEW) 基于web的钱包</p><p>MainEthereumNetwork 以太坊主网 正式的 真正的ETH</p><p>Ropsten Test Network 以太坊公开测试网 POW共识机制</p><p>Kovan Test Network 以太坊公开测试网 “Aura”协议的权威证明POA(proof-of-authority) 共识机制</p><p>Rinkeby Test Network 以太坊公开测试网 “Clique”协议的POA 共识机制</p><p>localhost8545 连接到与浏览器在同一台计算机上运行的节点</p><h4 id="世界计算机"><a href="#世界计算机" class="headerlink" title="世界计算机"></a>世界计算机</h4><p>事实上,加密货币功能是服务于以太坊作为世界计算机的功能 — 一个去中心化的智能合约平台。</p><p>以太坊货币旨在用于支付 运行的智能合约(EVM上运行的计算机程序)。</p><p>EVM是一个全球性单例,运作方式就是一个全球性的单实例计算机,无处不在。</p><p>以太坊网络上的每个节点运行EVM的本地副本以验证合约执行,以太坊区块链记录该世界计算机在处理交易和智能合约时变化的状态。</p><h4 id="外部所有账户和合约账户"><a href="#外部所有账户和合约账户" class="headerlink" title="外部所有账户和合约账户"></a>外部所有账户和合约账户</h4><p>钱包中创建的账户类型为EOA(Externally Owned Account),管理私人密钥的账户,控制对资金或合约的访问。</p><p>合约账户由以太坊区块链记录,由EVM执行的软件程序的逻辑所拥有和控制。</p><blockquote><p>这两种账户永远存在的重要区别在于:</p><p>人们通过外部账户做出决定,而软件通过合约账户做出决定。</p></blockquote><p>EOA和合约共同点:都有一个地址,都可以发送和接收ether。</p><p>当交易的目标地址(to)为合约地址时,会导致合约在EVM中运行,并将交易作为其输入。</p><p>除了ether外,交易还可以包含数据,用于指示合约中要运行的<font color="dodgerblue" style="font-weight:bold">特定方法以及传递给该方法的参数</font>。通过这种方式,交易可调用合约方法。</p><p>e.g. ethereumjs-tx库 构造的交易 value为ether,data为合约函数名转16进制+函数参数转16进制</p><p>合约还可以产生调用其他合约的交易,建立更复杂的执行路径。</p><h4 id="区块链上创建合约"><a href="#区块链上创建合约" class="headerlink" title="区块链上创建合约"></a>区块链上创建合约</h4><p>在区块链上注册合约 涉及一个特殊交易,其目标地址是0x0000000000000000000000000000000000000000,也称为zero address。零地址是一个特殊地址,告诉以太坊你想注册一个合约。</p><h4 id="与合约交互"><a href="#与合约交互" class="headerlink" title="与合约交互"></a>与合约交互</h4><p>以太坊合约运行在名为EVM的虚拟机内。它们是由一个特殊的交易创建的,该交易提交它们的字节码以记录在区块链中。一旦他们在区块链上创建,他们就拥有一个以太坊地址,就像钱包一样。</p><p>只要有人将交易发送到(to)合约地址,就会导致合约在EVM中运行,并将交易作为其输入。</p><p>发送到合约地址的交易可能包含ether或数据。如果包含ether就将其存入合约余额,如果包含数据则代表指定一个命名函数并调用它,同时将参数传递给该函数。</p><p>如果将交易发送到合约地址(向合约发ether),不指定调用哪个函数的数据,将调用默认函数(fallback)。</p><p>注意💡 需要在合约中声明fallback | function() external payable{//可不写函数体}</p><p>否则无法直接给合约转账</p><h6 id="Thanks-for-reading-未完待续🌪"><a href="#Thanks-for-reading-未完待续🌪" class="headerlink" title="Thanks for reading. 未完待续🌪"></a>Thanks for reading. 未完待续🌪</h6><hr>]]></content>
<categories>
<category> BlockChain </category>
<category> Ethereum </category>
<category> 「精通以太坊」 </category>
</categories>
<tags>
<tag> Ethereum </tag>
<tag> BlockChain </tag>
<tag> Mastering Ethereum </tag>
</tags>
</entry>
<entry>
<title>「精通以太坊」第一章👉🏻What is Ethereum</title>
<link href="/2019/03/09/%E3%80%8C%E7%B2%BE%E9%80%9A%E4%BB%A5%E5%A4%AA%E5%9D%8A%E3%80%8D%E2%98%9E%E7%AC%AC%E4%B8%80%E7%AB%A0/"/>
<url>/2019/03/09/%E3%80%8C%E7%B2%BE%E9%80%9A%E4%BB%A5%E5%A4%AA%E5%9D%8A%E3%80%8D%E2%98%9E%E7%AC%AC%E4%B8%80%E7%AB%A0/</url>
<content type="html"><![CDATA[<h3 id="什么是以太坊"><a href="#什么是以太坊" class="headerlink" title="什么是以太坊"></a>什么是以太坊</h3><p>以太网是“世界计算机”。</p><p>以太坊是一个状态机,有两个基本功能</p><ol><li>全局可访问的单例状态</li><li>将更改应用于该状态的虚拟机</li></ol><p>以太坊是一个开源的、全球的、去中心化的计算架构,执行智能合约程序。使用区块链来同步和存储系统状态,使用加密货币ether来计量和约束执行资源的成本。</p><h3 id="区块链的组件"><a href="#区块链的组件" class="headerlink" title="区块链的组件"></a>区块链的组件</h3><p>公链通常包含以下组件:</p><ul><li>传播交易和包含已验证交易区块的点对点网络</li><li>状态机中实现的一系列共识机制</li><li>消息,已交易的形式表示,代表状态转移。</li><li>根据共识机制处理交易的状态机</li><li>分布式数据库,记录所有状态转移的日志</li><li>共识算法,通过强制参与者竞争并使用共识机制约束他们。</li><li>上述内容的一个或多个开源软件的实现。</li></ul><h3 id="以太坊开发的四个阶段"><a href="#以太坊开发的四个阶段" class="headerlink" title="以太坊开发的四个阶段"></a>以太坊开发的四个阶段</h3><p>前言Frontier => 家园Homestead => 大都会Metropolis => 宁静Serenity</p><p>中间的硬分叉代号:</p><ul><li>冰河时代Ice Age</li><li>DAO</li><li>蜜桔前哨Tangerine Whistle</li><li>假龙Spurious Dragon</li><li>拜占庭Byzantium</li><li>君士坦丁堡Constaninople</li></ul><p>Ice Age:引入指数级难度增长的一个难题,激励了到权益证明机制的过渡。</p><p>DAO:恢复被破坏的DAO合约的硬分叉,导致以太坊分裂为以太坊经典和以太坊两个竞争系统。</p><p>Tangerine Whistle:改变某些IO秘籍操作的燃气计算方法和清除拒绝服务攻击累计状态的硬分叉。</p><p>Spurious Dragon:解决更多拒绝服务攻击向量和另一种状态清楚的硬分叉,包括转播攻击保护机制。</p><blockquote><p>以太坊不仅追踪货币所有权的状态,还追踪通用数据存储的状态转换。通常我们指的是任何可以表示为key-value tuple的数据。</p></blockquote><h3 id="以太坊的组件"><a href="#以太坊的组件" class="headerlink" title="以太坊的组件"></a>以太坊的组件</h3><p>Ethereum中包含的系统组件:</p><ul><li><p>P2P Network</p></li><li><p>Consensus rules</p><p>以太坊的共识规则</p></li><li><p>Transactions</p><p>以太坊交易,包括发送者,接受者,值和数据负载等。</p></li><li><p>State Machine</p><p>状态机。以太坊的状态转移由Ethereum虚拟机(EVM)处理,这是一个执行bytecode(机器语言指令)的基于栈的虚拟机。智能合约以高级语言(如Solidity)编写,并编译为字节码以便在EVM上执行。</p></li><li><p>Blockchain</p><p>以太坊的区块链作为database(Google的LevelDB)存储在每个节点上,该区块链在称为梅克尔帕特里夏树(MPT,Merkle Patricia Tree)的序列化哈希数据结构中 包含交易和系统状态。</p></li><li><p>Consensus Algorithm</p><p>共识算法,以太坊目前使用Ethash的工作量证明算法,将来会过渡到称为Casper的权益证明(POS)系统。</p></li><li><p>Clients</p><p>以太坊有几个可操作的客户端软件实现,最突出的是Go-Ethereum(Geth)和Parity。</p></li></ul><h3 id="参考文献"><a href="#参考文献" class="headerlink" title="参考文献"></a>参考文献</h3><p>以太坊黄皮书:<a href="https://ethereum.github.io/yellowpaper/paper.pdf" target="_blank" rel="noopener">https://ethereum.github.io/yellowpaper/paper.pdf</a></p><p>以太坊褐皮书(为耿冠发的读者以不太正式的语言重写黄皮书):<a href="https://github.com/chronaeon/beigepaper" target="_blank" rel="noopener">https://github.com/chronaeon/beigepaper</a></p><p>翻译版:<a href="http://www.fanyigou.net/doc/waitTranslateActivity.htm" target="_blank" rel="noopener">http://www.fanyigou.net/doc/waitTranslateActivity.htm</a></p><p>以太坊状态机 —— 一个“Awesome”资源列表 <a href="https://github.com/ethereum/wiki/wiki/Ethereum-Virtual-Machine-(EVM)-Awesome-List" target="_blank" rel="noopener">https://github.com/ethereum/wiki/wiki/Ethereum-Virtual-Machine-(EVM)-Awesome-List</a></p><p>Merkle Patricia Trees: <a href="https://github.com/ethereum/wiki/wiki/Patricia-Tree" target="_blank" rel="noopener">https://github.com/ethereum/wiki/wiki/Patricia-Tree</a></p><p>Ethash 工作量证明共识算法: <a href="https://github.com/ethereum/wiki/wiki/Ethash" target="_blank" rel="noopener">https://github.com/ethereum/wiki/wiki/Ethash</a></p><p>Casper 权益证明 v1 实现指南: <a href="https://github.com/ethereum/research/wiki/Casper-Version-1-Implementation-Guide" target="_blank" rel="noopener">https://github.com/ethereum/research/wiki/Casper-Version-1-Implementation-Guide</a></p><h3 id="从通用区块链到去中心化应用-ÐApps"><a href="#从通用区块链到去中心化应用-ÐApps" class="headerlink" title="从通用区块链到去中心化应用(ÐApps)"></a>从通用区块链到去中心化应用(ÐApps)</h3><p>以太坊作为一种可用于各种用途的通用区块链,但很快以太坊的愿景扩展为开发去中心化应用(DApps)的平台。DApps代表比智能合约更广阔的视角。</p><p>DApp是基于开放的|去中心化的|点对点基础架构服务的Web应用程序。</p><p>DApp至少包含以下部分:</p><ul><li>区块链上的智能合约</li><li>一个Web前端用户界面</li></ul><p>此外,许多DApp还包括其他去中心化组件,例如:</p><ul><li>去中心化P2P存储协议和平台</li><li>去中心化P2P消息传递协议和平台</li></ul><p>web3.js将js应用程序与以太坊区块链连接起来,web3.js库还包含换一个<font style="color:white;background:mediumseagreen;padding:3px 6px;font-weight:bold;line-height:28px">名为Swarm的P2P存储网络接口</font>和一个<font style="color:white;background:mediumseagreen;padding:3px 6px;font-weight:bold;line-height:28px">名为Whisper的P2P消息传递服务</font>。</p><p><img src="web3suite.png" alt="jfx1387719327203632199"></p><h3 id="以太坊的开发文化"><a href="#以太坊的开发文化" class="headerlink" title="以太坊的开发文化"></a>以太坊的开发文化</h3><ul><li>在比特币中,开发以保守原则为指导:所有变化都经过仔细研究,以确保现有系统都不会中断。大部分情况下,只有在向后兼容时才会执行更改。允许现有客户“选择加入”,但如果他们决定不升级,将继续运作。</li><li>在以太坊中,开发文化的重点是速度和创新。这个咒语是“快速行动,解决事情”。如果需要进行更改,即使这意味着使之前的假设失效,破坏兼容性或强制客户端进行更新,也会执行更改。以太坊的开发文化的特点是快速创新,快速进化和愿意参与实验。</li></ul><p>对开发者来说,意味着你必须保持灵活性和持续学习,随着一些潜在的假设变化,随时准备重建你的基础设施。以太坊开发人员面临的一个重大挑战是将代码部署到不可变账本与仍然在快速发展的开发平台之间的内在矛盾。</p><p>你不能简单地“<strong>升级</strong>”你的智能合约,你必须准备部署新的智能合约、迁移用户、应用程序和资金,并重新开始😀</p><p>最终以太坊核心协议的开发速度将会放慢,其接口将会变得固定。但与此同时创新是推动原则,你最好跟上脚步,没人会为你放慢速度!</p><h3 id="为什么学习以太坊"><a href="#为什么学习以太坊" class="headerlink" title="为什么学习以太坊?"></a>为什么学习以太坊?</h3><p>区块链具有非常陡峭的学习曲线,因为他们将多个学科融合到了一个领域:编程,信息安全,密码学,经济学,分布式系统,对等网络,智能合约等。</p><p>以太坊使这一学习曲线变得平缓,你马上就可以开始!</p><p>但是当你学习并开始更深入的观察时,总会有另一层复杂性和奇迹!🔮</p><p>以太坊是学习区块链的绝佳平台,它构建了一个庞大的开发者社区。</p><p>以太坊是为开发者开发的<strong><em>开发者的区块链</em></strong>。</p><h6 id="Thanks-for-reading-未完待续🌪"><a href="#Thanks-for-reading-未完待续🌪" class="headerlink" title="Thanks for reading. 未完待续🌪"></a>Thanks for reading. 未完待续🌪</h6><hr>]]></content>
<categories>
<category> BlockChain </category>
<category> Ethereum </category>
<category> 「精通以太坊」 </category>
</categories>
<tags>
<tag> Ethereum </tag>
<tag> BlockChain </tag>
<tag> Mastering Ethereum </tag>
</tags>
</entry>
<entry>
<title>「精通以太坊」☞必备术语表</title>
<link href="/2019/03/08/%E3%80%8C%E7%B2%BE%E9%80%9A%E4%BB%A5%E5%A4%AA%E5%9D%8A%E3%80%8D%E2%98%9E%E5%BF%85%E5%A4%87%E6%9C%AF%E8%AF%AD%E8%A1%A8/"/>
<url>/2019/03/08/%E3%80%8C%E7%B2%BE%E9%80%9A%E4%BB%A5%E5%A4%AA%E5%9D%8A%E3%80%8D%E2%98%9E%E5%BF%85%E5%A4%87%E6%9C%AF%E8%AF%AD%E8%A1%A8/</url>
<content type="html"><![CDATA[<h3 id="From-《精通以太坊》-Mastering-Ethereum-☞术语表"><a href="#From-《精通以太坊》-Mastering-Ethereum-☞术语表" class="headerlink" title="From 《精通以太坊》(Mastering Ethereum)☞术语表"></a>From 《精通以太坊》(Mastering Ethereum)☞术语表</h3><h4 id="account"><a href="#account" class="headerlink" title="account"></a>account</h4><p>包含: </p><ul><li>nonce (EOA中代表交易序号 从0开始;CA中nonce一直为1,源码中看设为1后就不再改变,参考以太坊EVM笔记)</li></ul><p>合约账户CA(contract account)或外部账户EOA(externally owned account)</p><ul><li>balance</li><li>storageRoot 存储树的树根hash MPT树</li><li>codeHash EOA的为空串的hash值而不是空</li></ul><h5 id="address"><a href="#address" class="headerlink" title="address"></a>address</h5><p>代表一个EOA或一个合约</p><p>160位 即40位16进制数</p><p>ECDSA公钥的Keccak散列最右边160位</p><h5 id="断言Assert"><a href="#断言Assert" class="headerlink" title="断言Assert"></a>断言Assert</h5><p>消耗所有gas,并恢复所有更改,严重错误或异常,永远不该发生的才使用assert</p><h5 id="BIP"><a href="#BIP" class="headerlink" title="BIP"></a>BIP</h5><p>比特币改进协议</p><p>bitcoin improvement proposals 比如助记词等相关的BIP39</p><p>相应地有EIP</p><h5 id="区块"><a href="#区块" class="headerlink" title="区块"></a>区块</h5><p>包含区块头区块体,</p><h5 id="区块链"><a href="#区块链" class="headerlink" title="区块链"></a>区块链</h5><p>由特定系统验证的一系列区块,以太坊没有块大小限制,改为用gasLimit来限制区块的内容</p><h5 id="拜占庭分叉"><a href="#拜占庭分叉" class="headerlink" title="拜占庭分叉"></a>拜占庭分叉</h5><p>拜占庭是大都会阶段的两大分叉之一,包含EIP-649</p><ul><li>大都会难度炸弹延迟</li><li>区块奖励减少</li></ul><p>区块奖励由5个减少到3个</p><h5 id="君士坦丁堡"><a href="#君士坦丁堡" class="headerlink" title="君士坦丁堡"></a>君士坦丁堡</h5><p>大都会阶段的第二部分,2018年中期计划。预计将包括切换到混合工作证明/权益证明共识算法。</p><h5 id="编译"><a href="#编译" class="headerlink" title="编译"></a>编译</h5><p>将高级语言(如solidity)编写的代码 转换为 低级语言(如EVM字节码)</p><h5 id="共识"><a href="#共识" class="headerlink" title="共识"></a>共识</h5><p>网络上大多数节点,在其本地验证的最佳区块链中都有相同的区块的情况。</p><p>不同于共识机制。</p><h5 id="共识机制"><a href="#共识机制" class="headerlink" title="共识机制"></a>共识机制</h5><p>完整节点为了与其他节点保持一致,遵循的区块验证规则。</p><h5 id="DAO"><a href="#DAO" class="headerlink" title="DAO"></a>DAO</h5><p>去中心化自治组织 decentralised autonomous organization</p><p>没有层级管理的公司或组织</p><h5 id="The-DAO"><a href="#The-DAO" class="headerlink" title="The DAO"></a>The DAO</h5><p>该项目合约2016年6月遭到黑客攻击,最终在第1192000个区块激起了硬分叉,恢复了被攻击的DAO合约,导致分叉为以太坊和以太坊经典。</p><h5 id="DApp"><a href="#DApp" class="headerlink" title="DApp"></a>DApp</h5><p>去中心化应用 decentralized application</p><ul><li>狭义上,它至少是智能合约和web用户界面</li><li>广义上,DApp是一个基于开放式、分散式、点对点基础架构服务的web应用程序。<ul><li>许多DApp包括去中心化存储/消息协议和平台。</li></ul></li></ul><h5 id="difficulty难度"><a href="#difficulty难度" class="headerlink" title="difficulty难度"></a>difficulty难度</h5><p>控制工作量证明的难度,需要多少计算</p><h5 id="数字签名-digital-signature"><a href="#数字签名-digital-signature" class="headerlink" title="数字签名 digital signature"></a>数字签名 digital signature</h5><p>数字签名算法是一个过程,用户使用私钥为文档生成称为签名的短字符串数据,以便具有签名、文档和响应公钥的任何人,都可以验证:</p><ol><li>该文件由特定私钥所有者“签名” 不可伪造</li><li>该文件签署后未被修改 不可篡改</li></ol><h5 id="ECDSA"><a href="#ECDSA" class="headerlink" title="ECDSA"></a>ECDSA</h5><p>椭圆曲线数字签名算法 以太坊中使用的加密算法</p><h5 id="EIP"><a href="#EIP" class="headerlink" title="EIP"></a>EIP</h5><p>以太坊改进建议 ethereum improvement proposals</p><p>EIP向以太坊社区提供信息的设计文档,描述新功能,或处理过程、环境。</p><p>参考: <a href="https://github.com/ethereum/EIPs" target="_blank" rel="noopener">https://github.com/ethereum/EIPs</a></p><h5 id="熵-Entropy"><a href="#熵-Entropy" class="headerlink" title="熵 Entropy"></a>熵 Entropy</h5><p>密码学领域,表示可预测性的缺乏或随机性水平。生成秘密信息(如私钥)时,算法通常依赖高熵源来确保输出不可预测。</p><p>web3创建账户的方法 参数即为熵</p><p>web3.eth.accounts.create([entropy])</p><h5 id="ENS"><a href="#ENS" class="headerlink" title="ENS"></a>ENS</h5><p>Ethereum Name Service</p><p>以太坊名称服务,建立在以太坊区块链上的域名系统。</p><h5 id="Ethash"><a href="#Ethash" class="headerlink" title="Ethash"></a>Ethash</h5><p>以太坊1.0的工作量证明算法。 </p><h5 id="Ether-以太"><a href="#Ether-以太" class="headerlink" title="Ether 以太"></a>Ether 以太</h5><p>以太坊生态系统中使用的货币,执行智能合约时承担燃气费用。</p><h5 id="Event"><a href="#Event" class="headerlink" title="Event"></a>Event</h5><p>event事件 允许EVM日志工具的使用,可用来在DApp用户界面中调用JavaScript回调来监听这些事件。</p><h5 id="EVM"><a href="#EVM" class="headerlink" title="EVM"></a>EVM</h5><p>以太坊虚拟器,Ethereum Vitrual Machine,基于栈的,执行字节码的虚拟机。</p><h5 id="回调方法-Fallback-function"><a href="#回调方法-Fallback-function" class="headerlink" title="回调方法 Fallback function"></a>回调方法 Fallback function</h5><p>默认的方法,当缺少数据或声明的方法名时执行</p><h5 id="水龙头Faucet"><a href="#水龙头Faucet" class="headerlink" title="水龙头Faucet"></a>水龙头Faucet</h5><p>一个网站,为在测试网上做测试的开发人员提供免费测试的以太币。</p><h5 id="前沿Frontier"><a href="#前沿Frontier" class="headerlink" title="前沿Frontier"></a>前沿Frontier</h5><p>以太坊的试验开发阶段,2015.7~2016.3</p><h5 id="Ganache"><a href="#Ganache" class="headerlink" title="Ganache"></a>Ganache</h5><p>私有以太坊区块链,你可以在上面进行测试,执行命令,在控制区块链如何运作时检查状态。</p><h5 id="燃气Gas"><a href="#燃气Gas" class="headerlink" title="燃气Gas"></a>燃气Gas</h5><p>以太坊用于执行智能合约的虚拟燃料。以太坊虚拟机使用会计机制来衡量天然气的消耗量并限制计算资源的消耗。燃气是执行智能合约的每条指令产生的计算单位。燃气与以太币挂钩。</p><h6 id="Gas-Limit"><a href="#Gas-Limit" class="headerlink" title="Gas Limit"></a>Gas Limit</h6><p>区块gas limit定义了整个区块中所有交易允许消耗的最大燃气量。</p><p>交易gas limit也叫startgas,gas消耗超过startgas则操作会被回滚,但交易费仍然收取。</p><h5 id="geth"><a href="#geth" class="headerlink" title="geth"></a>geth</h5><p>go语言版本以太坊。</p><h5 id="Hard-Fork-硬分叉"><a href="#Hard-Fork-硬分叉" class="headerlink" title="Hard Fork 硬分叉"></a>Hard Fork 硬分叉</h5><p>区块链中的一种永久性分歧,通常发生在非升级节点无法验证升级节点创建的遵循新共识机制规则的区块时。</p><h5 id="HD-wallet-分层确定性钱包"><a href="#HD-wallet-分层确定性钱包" class="headerlink" title="HD wallet 分层确定性钱包"></a>HD wallet 分层确定性钱包</h5><p>使用 分层确定性密钥生成/分层确定性地址机制 的电子钱包。 BIP32协议</p><h5 id="HD-wallet-seed-分层确定性钱包种子"><a href="#HD-wallet-seed-分层确定性钱包种子" class="headerlink" title="HD wallet seed 分层确定性钱包种子"></a>HD wallet seed 分层确定性钱包种子</h5><p>HD钱包中资或根种子 可能是一个很短的值,用作生成hd钱包的主私钥和主链码的种子。</p><p>钱包种子可以用助记词表示。</p><h5 id="家园-Homestead"><a href="#家园-Homestead" class="headerlink" title="家园 Homestead"></a>家园 Homestead</h5><p>以太坊的第一个发展阶段,于2016年3余额再1150000区块启动。</p><h5 id="内部交易-也叫消息-Internal-transaction-message"><a href="#内部交易-也叫消息-Internal-transaction-message" class="headerlink" title="内部交易(也叫消息) Internal transaction(message)"></a>内部交易(也叫消息) Internal transaction(message)</h5><p>从一个合约地址发送到另一个 合约地址 或 EOA 的交易。</p><p>一个EOA发起的则是外部交易。</p><h5 id="Keccak256"><a href="#Keccak256" class="headerlink" title="Keccak256"></a>Keccak256</h5><p>以太坊使用的加密哈希方法, Keccak256 被标准化为 SHA-3。</p><h5 id="KDF密钥推导方法"><a href="#KDF密钥推导方法" class="headerlink" title="KDF密钥推导方法"></a>KDF密钥推导方法</h5><p>被keystore格式使用,防止对密码加密的暴力破解、字典或🌈彩虹表攻击。</p><h5 id="keystore文件"><a href="#keystore文件" class="headerlink" title="keystore文件"></a>keystore文件</h5><p>json编码的文件,包含一个私钥,被一个密码加密,以提供更高的安全性。</p><h5 id="LevelDB"><a href="#LevelDB" class="headerlink" title="LevelDB"></a>LevelDB</h5><p>一种开源的磁盘键值对存储系统,轻量的、单一目标的持久化库,支持很多平台。</p><h5 id="库-Library"><a href="#库-Library" class="headerlink" title="库 Library"></a>库 Library</h5><p>以太坊中的库,是特殊类型的合约,没有用于支付的方法,没有fallback方法,没有数据存储store。不能接收或存储以太,不能存储数据。 其他合约可以调用只读计算。</p><h5 id="轻量级客户端-lightweight-client"><a href="#轻量级客户端-lightweight-client" class="headerlink" title="轻量级客户端 lightweight client"></a>轻量级客户端 lightweight client</h5><p>一个以太坊客户端,不存储区块链的本地副本,也不验证区块和交易。提供了钱包的功能,可以创建和广播交易。</p><h5 id="消息-message"><a href="#消息-message" class="headerlink" title="消息 message"></a>消息 message</h5><p>内部交易,未被序列化,只在EVM中发送。</p><h5 id="大都会阶段-Metropolis-Stage"><a href="#大都会阶段-Metropolis-Stage" class="headerlink" title="大都会阶段 Metropolis Stage"></a>大都会阶段 Metropolis Stage</h5><p>以太坊的第三个开发阶段,2017.10启动。</p><h5 id="矿工Miner"><a href="#矿工Miner" class="headerlink" title="矿工Miner"></a>矿工Miner</h5><p>通过大量的哈希计算,为新的区块寻找有效的工作量证明解的网络节点。</p><h5 id="Mist"><a href="#Mist" class="headerlink" title="Mist"></a>Mist</h5><p>以太坊基金会创建的第一个以太坊浏览器,还包含一个基于浏览器的钱包。Mist运行完整节点,提供完整的DApp浏览器,支持基于Swarm的存储和ENS地址。</p><h5 id="Network"><a href="#Network" class="headerlink" title="Network"></a>Network</h5><p>将交易和区块传播到每个以太坊节点的对等网络。</p><h5 id="Node"><a href="#Node" class="headerlink" title="Node"></a>Node</h5><p>参与到对等网络的软件客户端。</p><h5 id="随机数Nonce"><a href="#随机数Nonce" class="headerlink" title="随机数Nonce"></a>随机数Nonce</h5><p>以太坊中用到两类nonce</p><ul><li>账户nonce 一个账户的交易计数</li><li>工作量证明随机数 用于获得工作证明的区块中的随机值(取决于当前难度)</li></ul><h5 id="Ommer-叔叔"><a href="#Ommer-叔叔" class="headerlink" title="Ommer 叔叔"></a>Ommer 叔叔</h5><p>当前块的爷爷的儿子,但不是当前块的父亲,和父亲同级。</p><p>对父节点的兄弟姐妹节点的性别中立的称呼,也可表示为“叔叔”。</p><h5 id="POS权益证明"><a href="#POS权益证明" class="headerlink" title="POS权益证明"></a>POS权益证明</h5><p>proof of stake</p><p>权益证明要求用户证明一定数量的加密货币(网络中的“股份”)的所有权,以便能参与交易验证。</p><h5 id="POW工作量证明"><a href="#POW工作量证明" class="headerlink" title="POW工作量证明"></a>POW工作量证明</h5><p>proof of work</p><p>一份需要大量计算才能找到的数据证明。以太坊中,矿工必须找到符合网络难度目标的Ethash算法的数字解决方案。</p><h5 id="收据Receipt"><a href="#收据Receipt" class="headerlink" title="收据Receipt"></a>收据Receipt</h5><p>以太坊客户端返回的数据,表示特定交易的结果,包括交易的哈希、区块号、使用的gas、部署合约地址。</p><h5 id="重入攻击"><a href="#重入攻击" class="headerlink" title="重入攻击"></a>重入攻击</h5><p>当攻击者合约调用受害者合约的方法时,可以重复这种攻击。withdraw(),在对该合约函数的原始调用完成之前,再次调用withdraw()方法,持续递归调用他自己。递归调用可以通过攻击者合约的callback方法实现。攻击者必须执行的唯一技巧是在用完燃气之前中断递归调用,并避免盗用的以太被还原。</p><h5 id="require"><a href="#require" class="headerlink" title="require"></a>require</h5><p>提供了一种停止执行和恢复状态更改的方式,不会消耗所有的gas。</p><p>应当使用require函数来确保满足有效条件,例如输入、合约状态变量、验证调用外部合约的返回值。</p><p>在<font style="color:white;background:mediumseagreen;padding:3px 6px;font-weight:bold;line-height:28px">拜占庭网络</font>升级前,有两种方式来还原交易:</p><ul><li>耗尽燃气(gas)</li><li>执行无效指令</li></ul><p>但是这两个选项都消耗完所有剩余gas。</p><h5 id="revert"><a href="#revert" class="headerlink" title="revert"></a>revert</h5><p>处理与require相同的情况,也会返还gas。有些更复杂的逻辑,可以用revert,例如代码有一些ifelse逻辑流程,用revert更好。返回上一步</p><p>require(msg.sender==owner);</p><p>相当于 if(msg.sender!=owner){revert();}</p><h5 id="RLP"><a href="#RLP" class="headerlink" title="RLP"></a>RLP</h5><p>Recursive Length Prefix,递归长度前缀。</p><p>是一种编码标准,用于编码和序列化任意复杂度和长度的对象(数据结构)。</p><h5 id="私钥-Private-Key"><a href="#私钥-Private-Key" class="headerlink" title="私钥 Private Key"></a>私钥 Private Key</h5><p>允许以太坊用户通过创建数字签名证明账户或合约的所有权的加密数字。</p><h5 id="SHA"><a href="#SHA" class="headerlink" title="SHA"></a>SHA</h5><p>安全哈希算法,Secure Hash Algorithm。一系列加密哈希函数。</p><h5 id="selfdestruct"><a href="#selfdestruct" class="headerlink" title="selfdestruct"></a>selfdestruct</h5><p>自毁。一旦执行自毁操作,存储在合约地址的剩余ether会被发送到另一个地址,并将存储和代码从状态中移除。</p><p>以前称作suicide,EIP6之后,重命名为selfdestruct。</p><p>selfdestruct(addr) 销毁后ether转给addr</p><h5 id="宁静-Serenity"><a href="#宁静-Serenity" class="headerlink" title="宁静 Serenity"></a>宁静 Serenity</h5><p>以太坊第四个 即最后一个开发阶段。还不确定计划发布日期。</p><h5 id="智能合约"><a href="#智能合约" class="headerlink" title="智能合约"></a>智能合约</h5><p>以太坊的计算框架上执行的程序。</p><h5 id="Swarm"><a href="#Swarm" class="headerlink" title="Swarm"></a>Swarm</h5><p>一种去中心化P2P的存储网络。与Web3和Whisper共同使用于构建DApps。</p><h5 id="测试网Testnet"><a href="#测试网Testnet" class="headerlink" title="测试网Testnet"></a>测试网Testnet</h5><p>测试网络用于模拟以太坊主网的一些行为。</p><h5 id="交易-transaction"><a href="#交易-transaction" class="headerlink" title="交易 transaction"></a>交易 transaction</h5><p>由EOA账户签署的提交到以太坊区块链的数据,并以特定地址为目标。交易包含源数据,例如交易的燃气限额(gas limit)。</p><h5 id="Truffle"><a href="#Truffle" class="headerlink" title="Truffle"></a>Truffle</h5><p>一个最常用的以太坊开发框架。包含一些NodeJS包,可以使用NPM进行安装。</p><h5 id="图灵完备"><a href="#图灵完备" class="headerlink" title="图灵完备"></a>图灵完备</h5><p>一切可计算的问题都能够被计算。有能力执行if/goto/循环类操作。</p><h5 id="Wallet"><a href="#Wallet" class="headerlink" title="Wallet"></a>Wallet</h5><p>管理你所拥有的密钥/账户的软件。作为访问和控制以太坊账户并与智能合约交互的界面。请注意,密钥不需要存储在你的钱包中,并且可以从脱机存储(usb或纸张)中检索以提高安全性。</p><p>并不存储实际的硬币或代币。</p><h5 id="Web3"><a href="#Web3" class="headerlink" title="Web3"></a>Web3</h5><p>web的第三个版本。Web3代表了Web应用程序的新愿景和焦点:</p><p>从中心化控制和管理的应用程序到基于去中心化协议的应用程序。</p><h5 id="Wei"><a href="#Wei" class="headerlink" title="Wei"></a>Wei</h5><p>以太ether的最小单位</p><p>10^18^wei = 1ether</p><p>1Gwei = 10^9^wei</p><h5 id="Whisper"><a href="#Whisper" class="headerlink" title="Whisper"></a>Whisper</h5><p>一种去中心化P2P消息系统。与Web3和Swarm一起用于构建DApps。</p><h5 id="Zero-address"><a href="#Zero-address" class="headerlink" title="Zero address"></a>Zero address</h5><p>零地址。特殊的以太坊地址,所有20个位都为0。</p><h6 id="Thanks-for-reading-未完待续🌪"><a href="#Thanks-for-reading-未完待续🌪" class="headerlink" title="Thanks for reading. 未完待续🌪"></a>Thanks for reading. 未完待续🌪</h6><hr>]]></content>
<categories>
<category> BlockChain </category>
<category> Ethereum </category>
<category> 「精通以太坊」 </category>
</categories>
<tags>
<tag> Ethereum </tag>
<tag> BlockChain </tag>
<tag> Mastering Ethereum </tag>
</tags>
</entry>
<entry>
<title>JavaScriptのES6☞Proxy</title>
<link href="/2019/03/07/JavaScript%E3%81%AEES6%E2%98%9EProxy/"/>
<url>/2019/03/07/JavaScript%E3%81%AEES6%E2%98%9EProxy/</url>
<content type="html"><![CDATA[<p>代理可以理解为拦截层,外界想要访问目标对象的时候,需要通过这个拦截层。</p><p>起到控制和授权的作用</p><p>举个🌰:</p><p>例如在家想访问公司的内网</p><p>例如明星的经纪人,无法直接联系到明星,只能通过经纪人间接联系到明星。</p><p>Proxy(target,handleFunctionObject)</p><p>处理函数对象,</p><p>有getter和setter,分别拦截读取操作和写入操作</p><p>有has,deleteProperty,拦截in操作和delete操作</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><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> famousStar = {</span><br><span class="line">name: <span class="string">"fanbingbing"</span>,</span><br><span class="line"> age: <span class="string">"34"</span>,</span><br><span class="line"> phone: <span class="string">"88888888"</span>,</span><br><span class="line"> _time: <span class="string">"2019"</span></span><br><span class="line">}</span><br><span class="line"><span class="keyword">let</span> starAgent = <span class="keyword">new</span> <span class="built_in">Proxy</span>(famousStar,{</span><br><span class="line"> <span class="comment">//target为目标,key为目标属性</span></span><br><span class="line"> <span class="comment">//读取操作</span></span><br><span class="line"> <span class="keyword">get</span>:function(target,key){</span><br><span class="line"> <span class="keyword">if</span>(key===<span class="string">"phone"</span>){</span><br><span class="line"> <span class="comment">//经纪人不会告诉你明星自己的真正号码</span></span><br><span class="line"> <span class="keyword">return</span> <span class="string">"agent:1383838"</span></span><br><span class="line"> };</span><br><span class="line"> <span class="keyword">if</span>(key===<span class="string">"price"</span>){</span><br><span class="line"> <span class="comment">//明星本身没有price属性,经纪人弄了个100万出场费</span></span><br><span class="line"> <span class="keyword">return</span> <span class="number">1000000</span></span><br><span class="line"> };</span><br><span class="line"> <span class="comment">//不需要特殊处理的,直接返回target(明星)的key(本身属性)</span></span><br><span class="line"> <span class="keyword">return</span> target[key];</span><br><span class="line"> },</span><br><span class="line"> <span class="comment">//value为设置的值</span></span><br><span class="line"> <span class="comment">//赋值操作</span></span><br><span class="line"> <span class="keyword">set</span>:function(target,key,value){</span><br><span class="line"> <span class="keyword">if</span>(value < <span class="number">1000000</span>){</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">"100万一口价,低了免谈!"</span>)</span><br><span class="line"> }<span class="keyword">else</span>{</span><br><span class="line"> <span class="comment">//当famousStar上有了新的属性,那么starAgent也会有这个属性</span></span><br><span class="line"> target[key] = value;</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"> },</span><br><span class="line"> <span class="comment">//拦截in操作符,看明星是否有这个属性;特殊地,has并不会拦截for...in循环!</span></span><br><span class="line"> has:<span class="function"><span class="keyword">function</span>(<span class="params">target,key</span>)</span>{</span><br><span class="line"> <span class="comment">//打印了这一句说明走了has拦截</span></span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"请联系agent:1383838"</span>)</span><br><span class="line"> <span class="keyword">if</span>(key === <span class="string">"customPrice"</span>){</span><br><span class="line"> <span class="keyword">return</span> target[key];</span><br><span class="line"> <span class="comment">//其实会转为布尔值,所以可以写成 return true</span></span><br><span class="line"> <span class="comment">//除了customPrice以外的所有属性都被拦截了 都是false</span></span><br><span class="line"> }<span class="keyword">else</span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> },</span><br><span class="line"> <span class="comment">//拦截delete操作</span></span><br><span class="line"> deleteProperty: <span class="function"><span class="keyword">function</span>(<span class="params">target,key</span>)</span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"听说你想删除属性?"</span>)</span><br><span class="line"> <span class="comment">//可删除_开头的属性</span></span><br><span class="line"> <span class="keyword">if</span>(key.indexOf(<span class="string">"_"</span>)==<span class="number">0</span>){</span><br><span class="line"> <span class="keyword">delete</span> target[key];</span><br><span class="line"> <span class="comment">//不写会返回false</span></span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line"> }<span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> }</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(starAgent.phone); <span class="comment">//读取操作被proxy拦截了</span></span><br><span class="line"><span class="built_in">console</span>.log(starAgent.price); <span class="comment">//明星没有的属性但经纪人有拦截,也可以访问到经纪人提供的</span></span><br><span class="line"><span class="built_in">console</span>.log(starAgent.name); <span class="comment">//经纪人没特殊拦截的属性,读到明星原本属性</span></span><br><span class="line"><span class="built_in">console</span>.log(starAgent.age); <span class="comment">//经纪人没特殊拦截的属性,读到明星原本属性</span></span><br><span class="line"></span><br><span class="line">starAgent.customPrice = <span class="number">1080000</span>;</span><br><span class="line"><span class="built_in">console</span>.log(starAgent.customPrice); <span class="comment">//1080000</span></span><br><span class="line"></span><br><span class="line">starAgent.customPrice = <span class="number">666666</span>;</span><br><span class="line"><span class="built_in">console</span>.log(starAgent.customPrice); <span class="comment">//报错了! 100万一口价,低了免谈!</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">"====has======"</span>)</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">"customPri"</span> <span class="keyword">in</span> starAgent)</span><br><span class="line"></span><br><span class="line"><span class="keyword">delete</span>(starAgent[name]); <span class="comment">//并没有删除成功 会打印false</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">delete</span>(starAgent[<span class="string">"_time"</span>]); <span class="comment">//删除成功了 特殊命名 所以必须加引号</span></span><br><span class="line"><span class="comment">//or delete(starAgent._time)</span></span><br></pre></td></tr></table></figure><p>Proxy支持的所有操作,可在Reflect对象上看</p><p>所以Reflect中的操作都可以使用</p><p>例如:</p><p>let obj = {a:1,b:2}</p><p>console.log(Reflect.get(obj,‘a’));</p><p>console.log(Reflect.has(obj,‘a’));</p>]]></content>
<categories>
<category> FrontEnd </category>
<category> JavaScript </category>
</categories>
<tags>
<tag> JavaScript </tag>
<tag> ES6 </tag>
</tags>
</entry>
<entry>
<title>JavaScriptのES6☞Map&Set</title>
<link href="/2019/03/05/JavaScript%E3%81%AEES6%E2%98%9EMap-Set/"/>
<url>/2019/03/05/JavaScript%E3%81%AEES6%E2%98%9EMap-Set/</url>
<content type="html"><![CDATA[<h3 id="Map映射-类似对象"><a href="#Map映射-类似对象" class="headerlink" title="Map映射 类似对象"></a>Map映射 类似对象</h3><p>对象的问题:</p><p>var m = {}</p><p>var x = {id:1},</p><p> y = {id:2};</p><p>m[x] = ‘foo’;m[y]=‘bar’</p><p>console.log(m[x]);</p><p>console.log(m[y]);</p><p>打印出来啥? 这就是对象的问题</p><p>所以有了Map</p><p>Map不会将键转为string([object Object])</p><h4 id="初始化"><a href="#初始化" class="headerlink" title="初始化"></a>初始化</h4><p>var map = new Map([‘name1’,‘zhangsan’],[‘name2’,‘lisi’]);</p><p>//相当于 map.set(‘name1’,‘zhangsan’).set(‘name2’,‘lisi’);</p><p>实现方式: 用到了对象解构/数组解构</p><p>var items = [[‘name1’,‘zhangsan’],[‘name2’,‘lisi’]];</p><p>var m = new Map;</p><p>items.forEach(([key,value])=>m.set(key,value));</p><p>数组元素item为[xx,yy] 对应 [key,value] key value相当于解构</p><h4 id="set方法支持链式操作"><a href="#set方法支持链式操作" class="headerlink" title="set方法支持链式操作"></a>set方法支持链式操作</h4><p>let map = new Map()</p><p>map.set(‘key1’,‘value1’).set(‘key2’,’value2’)</p><h4 id="遍历方式-具备Symbol-iterator接口"><a href="#遍历方式-具备Symbol-iterator接口" class="headerlink" title="遍历方式 (具备Symbol.iterator接口)"></a>遍历方式 (具备Symbol.iterator接口)</h4><p>for(let v of map){console.log(v)} v的格式是[key,value] 所以可解构</p><p>相当于for(let [key,value] of map){console.log(key,value)}</p><p>相当于for(let [key,value] of map.entries())</p><p>v of map 用的迭代方式是 v of map.entries()</p><p>Map.prototype[Symbol.iterator] === Map.prototype.entries //true</p><p>注意对比 set用的是 set.values()方法 (因为set只需要值,map需要键值)</p><blockquote><h4 id="WeakMap"><a href="#WeakMap" class="headerlink" title="WeakMap"></a>WeakMap</h4></blockquote><p><strong>特征</strong></p><ul><li>不存在遍历方法,无法遍历</li><li>键名只能是对象,值可以是其他类型</li><li>弱引用:如果没有其他地方引用WeakMap的键(对象),就会被系统回收</li></ul><h4 id="坑🕳"><a href="#坑🕳" class="headerlink" title="坑🕳"></a>坑🕳</h4><p>注意对象和对象不相等,所以</p><p>map.set([5],555);//map.get([5]) 得到的是undefined!</p><p>map.set({k:‘v’},666); //map.get({k:‘v’}) 得到的是undefined!</p><p>如果想拿到值,需要指定为同一地址</p><p>var a = [5]; map.set(a,555); map.get(a) //这样就可以拿到555</p><h3 id="Set集合-类似数组"><a href="#Set集合-类似数组" class="headerlink" title="Set集合 类似数组"></a>Set集合 类似数组</h3><h4 id="Set初始化"><a href="#Set初始化" class="headerlink" title="Set初始化"></a>Set初始化</h4><p>var set = new Set(); set.add(5); set.add(7);</p><p>相当于 var set = new Set([5,7]); //将数组作为参数</p><h4 id="数组去重"><a href="#数组去重" class="headerlink" title="数组去重"></a>数组去重</h4><p>var set = new Set(array);</p><p>var newArray = Array.from(set);</p><p>//var newArray = Array.from(new Set(array));</p><p>或者</p><p>var newArray = […new Set(array)];</p><p>Set变数组的方法:</p><ol><li><p>Array.from(set)</p></li><li><p>[…set]</p></li></ol><h4 id="add方法支持链式调用"><a href="#add方法支持链式调用" class="headerlink" title="add方法支持链式调用"></a>add方法支持链式调用</h4><p>var set = new Set();</p><p>set.add(1).add(2); //add方法返回的仍然是set结构,所以可链式调用。</p><p>注意💡</p><p>delete和clear方法 不支持链式调用</p><p>delete返回布尔值 删除成功或失败</p><p>set.has(1) //判断是否含有元素1</p><p>set.clear() //清空集合</p><p>set.delete(v) //删除集合中某个元素</p><h4 id="遍历方式-具备Symbol-iterator接口-1"><a href="#遍历方式-具备Symbol-iterator接口-1" class="headerlink" title="遍历方式 (具备Symbol.iterator接口)"></a>遍历方式 (具备Symbol.iterator接口)</h4><p>for(let i of set) //1 2 3 “g”</p><p>for(let i of set.keys()) // 1 2 3 “g”</p><p>for(let i of set.values()) // 1 2 3 “g”</p><p>for(let i of set.entries()) //[1,1] [2,2] [3,3] [‘g’,‘g’]</p><p>Set集合中 元素的键名和键值相当于是相同的 都是元素的值</p><p>Set.prototype[Symbol.iterator] === Set.prototype.values //true</p><p>说明i of set调用的是 set.values()的方法</p><p>set.forEach((value,key,arr)=>console.log(value,key,arr))</p><p>value和key是一致的 而不是像数组索引(0,1,2,3)</p><h4 id="求交集,并集,差集"><a href="#求交集,并集,差集" class="headerlink" title="求交集,并集,差集"></a>求交集,并集,差集</h4><p>let a = new Set([1,2,3])</p><p>let b = new Set([2,3,4])</p><p>并集:</p><p>let union = new Set([…a,…b])</p><p>交集:</p><p>let intersect = new Set([…a].filter(v=>b.has(v))) b有才丢入filter</p><p>差集:</p><p>a差b</p><p>let difference = new Set([…a].filter(v=>!b.has(v))) b没有丢入filter</p><h4 id="注意问题"><a href="#注意问题" class="headerlink" title="注意问题"></a>注意问题</h4><p>var set = new Set([undefined,undefined,null,null,true,1,NaN,NaN,{},{},[],[]])</p><p>es6中 认为两个NaN是相等的 </p><p>注意{}和{},[]和[] 由于地址不同 是不相等的 所以都是唯一的</p><p>所以set中含有</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">Set</span>{{},{},[],[]}</span><br></pre></td></tr></table></figure><font style="color:white;background:mediumseagreen;padding:3px 6px;font-weight:bold;line-height:28px">操作是实时的,例如在console.log打印后再删除元素,但是看控制台可能却是删除元素后的结果,说明操作是实时影响到结果的。</font><p>所以后面的操作可能影响到前面使用时的结果,要注意。</p><blockquote><h4 id="WeakSet"><a href="#WeakSet" class="headerlink" title="WeakSet"></a>WeakSet</h4></blockquote><p><strong>特征</strong></p><ul><li>没有遍历方法,无法遍历</li><li>成员只能是对象,只能add对象</li><li>弱引用:如果没有其他地方引用WeakSet的元素(对象),就会被系统回收</li></ul><p><strong>冷</strong>🕳</p><p>let arr = [1,2,3,4]</p><p>console.log(arr.map(parseInt)) //打印出[1,NaN,NaN,NaN]</p><p>接收的参数是 1,0 2,1 3,2 4,3</p><p>即parseInt(1,0) | parseInt(2,1) 将1转为0进制</p><p>将2转为1进制 将3转为2进制 将4转为3进制</p>]]></content>
<categories>
<category> FrontEnd </category>
<category> JavaScript </category>
</categories>
<tags>
<tag> JavaScript </tag>
<tag> ES6 </tag>
<tag> 数据结构 </tag>
</tags>
</entry>
<entry>
<title>永恒のOP</title>
<link href="/2019/02/22/%E6%B0%B8%E6%81%92%E3%81%AEOP/"/>
<url>/2019/02/22/%E6%B0%B8%E6%81%92%E3%81%AEOP/</url>
<content type="html"><![CDATA[<h2 id="紫罗兰永恒花园OP"><a href="#紫罗兰永恒花园OP" class="headerlink" title="紫罗兰永恒花园OP"></a>紫罗兰永恒花园OP</h2><p>心中永恒不变的花园。</p><blockquote><p>我的眼睛虽被夜色遮蔽,夜空之中却闪耀着繁星。</p></blockquote><video controls src="violet.mp4" width="720" height="405"><br></video>]]></content>
<categories>
<category> Entertain </category>
</categories>
<tags>
<tag> ACG </tag>
<tag> 紫罗兰永恒花园 </tag>
</tags>
</entry>
<entry>
<title>工具类合约或库的使用</title>
<link href="/2019/02/22/%E5%B7%A5%E5%85%B7%E7%B1%BB%E5%90%88%E7%BA%A6%E6%88%96%E5%BA%93%E7%9A%84%E4%BD%BF%E7%94%A8/"/>
<url>/2019/02/22/%E5%B7%A5%E5%85%B7%E7%B1%BB%E5%90%88%E7%BA%A6%E6%88%96%E5%BA%93%E7%9A%84%E4%BD%BF%E7%94%A8/</url>
<content type="html"><![CDATA[<h5 id="方法一"><a href="#方法一" class="headerlink" title="方法一"></a>方法一</h5><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">contract Console {</span><br><span class="line"> event LogUint(string, uint);</span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">log</span>(<span class="params">string s , uint x</span>) <span class="title">internal</span> </span>{</span><br><span class="line"> emit LogUint(s, x);</span><br><span class="line"> }</span><br><span class="line">event LogInt(string, int);</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">log</span>(<span class="params">string s , int x</span>) <span class="title">internal</span> </span>{</span><br><span class="line">emit LogInt(s, x);</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>引用时,import “./Console.sol”</p><p>contract myContract is Console{ </p><p>log(“timeNow”,now); </p><p>}</p><h5 id="方法二"><a href="#方法二" class="headerlink" title="方法二"></a>方法二</h5><p>把工具功能写成库library,如下</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">library Console {</span><br><span class="line"> event LogUint(string, uint);</span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">log</span>(<span class="params">string s , uint x</span>) <span class="title">internal</span> </span>{</span><br><span class="line"> emit LogUint(s, x);</span><br><span class="line"> }</span><br><span class="line"> event LogInt(string, int);</span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">log</span>(<span class="params">string s , int x</span>) <span class="title">internal</span> </span>{</span><br><span class="line"> emit LogInt(s, x);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>==注意==</p><p>在library中我们不能定义任何storage类型的变量。因为library只是意味着代码的重用而不是进行state的状态管理。使用前再查询确认下。</p><hr><p>引用时,import {Console} from “./Console.sol”</p><p>contract myContract {</p><p> Console.log(“timeNew”,now);</p><p>}</p><p>访问library中的数据或方法时,使用点,libraryName.xxx来访问。</p>]]></content>
<categories>
<category> BlockChain </category>
<category> Solidity </category>
</categories>
<tags>
<tag> Ethereum </tag>
<tag> Solidity </tag>
<tag> BlockChain </tag>
</tags>
</entry>
<entry>
<title>Solidity学习笔记</title>
<link href="/2019/01/26/Solidity%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
<url>/2019/01/26/Solidity%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/</url>
<content type="html"><![CDATA[<h5 id="通识"><a href="#通识" class="headerlink" title="通识"></a>通识</h5><p>一个字节对应8位(8个二进制位) 1B(Byte)对应8b(bit)</p><p>一个十六进制位对应4个二进制位(2^4^=16)</p><p>所以==一个字节对应2个十六进制位==</p><p>bytes32 32字节长,对应64位十六进制数 即256bit</p><p>address 20字节长,对应40位十六进制数【160位二进制,相当于uint160】</p><p>地址是 address 长度为40位(加上开头0x就42位)</p><p>私钥|公钥 bytes32 长度为64位</p><h5 id="基本类型"><a href="#基本类型" class="headerlink" title="基本类型"></a>基本类型</h5><p>string 字符串,utf-8编码</p><p>bool</p><p>int 有符号整数</p><p>uint 无符号整数</p><p>address 16进制,一共有40位数(不包括开头0x)</p><h5 id="整数"><a href="#整数" class="headerlink" title="整数"></a>整数</h5><p>uint8 8位无符号整数,0~2^8^-1(255)</p><p>uint16</p><p>…</p><p>uint256</p><p>以8为步长,uint相当于uint256</p><p>int类似</p><h5 id="引用类型"><a href="#引用类型" class="headerlink" title="引用类型"></a>引用类型</h5><p>int[8] 定长数组</p><p>type[] 动态数组(多种类型),length长度,push加入元素</p><p>struct 结构体 <strong>可见性只能为internal,不支持自己声明</strong></p><p>mapping(key => value) 映射表 (即kv键值对) mapping(type1=>type2) map; map[key]对应value</p><blockquote><p>「如何判断某个key是否存在mapping中」,其实是为了输入不合法的key时能给与提示,否则只是返回缺省值或者没反应 肯定不合适。</p><p>具体可见合约HMS/InfoManagement.sol</p><p>有个比较耗gas的方法</p><p>把mapping的value也做一个数组,value[] values;数组中需要有map的key(即id)</p><p>传入参数为input_id</p><p>for(uint i=0;i<values.length;i++){</p><p> if(input_id==values[i].id){则说明input_id确实存在于mapping中的}</p><p>}</p></blockquote><blockquote><p>💡特别注意:</p><p>==!!!!入参和出参支持结构体,结构体数组,数组,映射!!!!== 0.5.0 666</p><p>想支持结构体或结构体数组 开头要添加pragma experimental ABIEncoderV2;</p><p>传入或返回映射的写法 returns(mapping(uint=>uint) memory(或storage))</p><p>切记传入或返回映射只能在==internal方法==或==library库方法==中</p><p>传入或返回数组returns(uint[] memory) 当可见性为internal时,可为storage(少用)</p><p>传入或返回结构体returns(structName memory) 当可见性为internal时,可为storage(少用)</p><p>传入或返回结构体数组returns(structName[] memory) 当可见性为internal时,可为storage(少用)</p><p>具体可见HMS/InfoManagement.sol,拿方法getCustomerIDs()来试验</p></blockquote><p>==结构体==</p><p>目前可能性只能为internal,而且不能显示地写出来!</p><p>struct CustomerInfo</p><p>mapping(uint=>CustomerInfo) cinfos</p><p>切记数组添加元素必须用push,不能array[1]=xxx,array[2]=xxx,不是mapping,是序列化的,一定要一个个来!</p><p>结构体添加可以structA.name=xxx</p><p>mapping添加可以 address[name]=“myName”</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></pre></td><td class="code"><pre><span class="line">CustomerInfo memory hotelAdmin = CustomerInfo({</span><br><span class="line"> customerName:<span class="string">"Administrator"</span>,</span><br><span class="line"> customerID:customers.length,</span><br><span class="line"> customerAge:<span class="number">666</span>,</span><br><span class="line"> isCrime:<span class="literal">false</span>});</span><br><span class="line">CustomerInfo memory hotemAdmin = CustomerInfo(<span class="string">"Admin"</span>,<span class="number">1</span>,<span class="number">666</span>,<span class="literal">false</span>);</span><br></pre></td></tr></table></figure><p>新建结构体必须加memory,因为新建的结构体未属于状态变量。</p><p>若是将已经存在的状态变量结构体赋值给新声明的结构体,可以用storage</p><p>如 CustomerInfo storage newguest = customers[0];</p><p>💡tips: 新建结构体不是storage,无所谓啊,把他添加进属于状态变量的某个数组里头,他就成状态变量啦。</p><p>solidity结构体初始化 不需要new 不像js</p><p>Person ap = Person(172,‘Satoshi’);</p><p>==bytes== 动态分配大小的字节数组</p><p>bytes byt; byt.length byt[0],可访问长度和某个下标</p><p>bytes32 字节数组</p><p>bytes32 写一个的时候可以简写0x1234,必须为==偶数位==,后面自动补0</p><p>💡初始化数组方法:</p><p>uint[] memory values = new uint[](3);</p><p>内存数组必须用长度参数创建,创建一个长度为3的数组</p><p>需要试一试5.0中的最新改动</p><h5 id="数据位置"><a href="#数据位置" class="headerlink" title="数据位置"></a>数据位置</h5><p>storage 保存在状态树中,成员变量一般位于此处|全局变量</p><p>memory 参数、局部变量一般位于此处</p><p>有的变量可以使用修饰符来改变变量位置,但是==状态变量不可改变位置==。</p><p>两个不同位置的引用变量,会导致深拷贝警告</p><p>memory 值传递,拷贝,不改变源数据</p><p>storage 引用传递,相当于指针,会改变源数据</p><p>强制指定的数据位置:</p><ul><li>外部函数的参数(不包括返回参数): calldata</li><li>状态变量: storage</li></ul><p>默认数据位置:</p><ul><li>函数参数(包括返回参数): memory</li><li>所有其它局部变量: storage</li></ul><blockquote><p>函数参数默认为memory,想显示声明数据位置的只能为struct|array|mapping</p><p>三种数据类型,其他数据类型都不可加memory或storage声明</p><p>最新版本!string类型的函数参数需要显示增加memory声明</p></blockquote><p>注意💡: ==函数中结构体和数组的声明和赋值==需要显示标为storage或者memory,不声明会报warning(默认为storage),而其他类型(包括mapping)都不能带storage或memory声明。</p><p>函数中无法声明临时mapping,mapping一定会作为状态变量存在的,函数中声明mapping也需要初始化而且要将一个状态变量mapping(A)赋值给他,这时用声明的mapping相当于在用mappingA了。</p><p>合约中函数外的声明都是状态变量,都存在storage中,不能显示加上memory或storage声明。</p><p>Person p = persons[_index];<br>p.age = _age;</p><p>//改变age会影响原来的值</p><p>Person memory p = persons[_index];<br>p.age = _age;</p><p>//改变age不会影响原来的值</p><p>例子:<a href="https://cryptozombies.io/zh/lesson/3/chapter/12" target="_blank" rel="noopener">https://cryptozombies.io/zh/lesson/3/chapter/12</a></p><p>批量删除数组元素,有两种方法,第一种符合直觉,但是特别费gas</p><ul><li><p>方法需要传入storage数组参数,数组的删除项后面的每个项都往前挪一位(即重新赋值),然后再将数组长度减1。</p><p>因为需要修改storage变量,每动一项都要消耗gas,贵</p></li><li><p>方法二:由于外部调用view函数免费,可以用for循环遍历整个数组把符合要求的挑出来构建出数组,这样会便宜的多得多。(需要做if判断)</p></li></ul><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></pre></td><td class="code"><pre><span class="line">uint a;</span><br><span class="line">uint b;</span><br><span class="line">uint c;</span><br><span class="line"><span class="comment">// 这样来做批量赋值:</span></span><br><span class="line">(a, b, c) = (<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>)</span><br></pre></td></tr></table></figure><h5 id="内建对象"><a href="#内建对象" class="headerlink" title="内建对象"></a>内建对象</h5><p>==<strong>block</strong>==</p><p>block.blockhash(uint blockNumber) returns (bytes32) 指定块的哈希</p><p>block.coinbase (address) 当前块矿工地址</p><p>block.difficulty (uint) 当前块难度值</p><p>block.gaslimit (uint) 当前块gaslimit</p><p>block.number (uint) 当前块块号(区块高度)</p><p>block.timestamp (uint) 当前块时间戳</p><p>==<strong>msg</strong>==</p><p>调用方法时,会给方法传递一个msg属性</p><p>msg.data (byte) 完整的calldata</p><p>msg.gas (uint) 剩余gas</p><p>msg.sender (address)当前消息的发送者</p><p>msg.sig (bytes4) 呼叫数据的前四个字节(即功能标识符)</p><p>msg.value (uint) 发送的消息的数量(发送的token数量)</p><p>==now==</p><p>即block.timestap的别名 当前块时间戳</p><p>==address==</p><p>\<address>.balance</p><p>\<address>.transfer(uint256 amount) 发送指定数量ether到地址,失败时抛异常,</p><p>\<address>.send(uint256 amount) returns (bool) </p><p>发送指定数量ether到地址,失败时返回false</p><p>\<address>.call(…) returns (bool)</p><p>\<address>.callcode(…) returns (bool)</p><p>\<address>.delegatecall(…) returns (bool)</p><p>getBalance()方法</p><p>return this.balance;</p><p>更安全的写法是return address(this).balance;</p><p>this代表当前合约的地址,合约地址!</p><p>msg.sender代表当前调用人的地址,外部账户地址!</p><p>==tx==</p><ul><li><p><strong>tx.gasprice (uint)</strong> gas价格</p></li><li><p><strong>tx.origin (address)</strong> 交易的发送者(全调用链)</p><p>Solidity有一个全局变量tx.origin,它遍历整个调用堆栈,并返回原先发送调用(或事务)的帐户地址。</p><p>如果一个函数的调用者规定必须为外部账户,然而这个合约B是被其他合约A部署的,这时用msg.sender会获得外部账户地址而不是合约地址,如果使用tx.origin则可以获得最先部署合约A的外部账户的地址了。</p><p>不过要注意安全问题,一般较少使用。</p><p>有一个判断require(msg.sender==tx.origin)什么含义呢?</p></li></ul><h5 id="内置函数"><a href="#内置函数" class="headerlink" title="内置函数"></a>内置函数</h5><p>addmod(uint x,uint y,uint k) returns (uint) (x+y)%k</p><p>mulmod(uint x,uint y,uint k) returns (uint) (x*y)%k</p><p>keccak256(…) returns(bytes32)</p><p>变参,可传多个参数</p><p>sha3 keccak256别名</p><p>assert(bool condition)</p><p>require(bool condition)</p><p>revert();</p><p>assert比较自信,断言此事不发生,发生会惩罚 扣光所有gas</p><p>require比较温和,如果条件不满足,退回剩余gas,用的更多</p><p>revert主动退回gas,if/else判断后使用</p><p>assert多用于判断非状态变量</p><p>assert可考虑放在函数结尾部分用于验证之前的操作结果的正确性</p><p>solidity内部有this,address(this)</p><p>selfdestruct(address) 销毁合约,address是收益人(销毁后钱转给)</p><h5 id="随机数生成方法"><a href="#随机数生成方法" class="headerlink" title="随机数生成方法"></a>随机数生成方法</h5><p>keccak256函数:</p><p>uint random = uint(keccak256(block.difficulty,now));</p><p>blockhash法:</p><p>uint random = uint(block.blockhash(block.number-1)); //?待查</p><p>不像js,变量的赋值|函数的执行 不能直接写在合约中的,而是写在函数中,这些操作是可能需要消耗gas的。或者写在js中?</p><h4 id="函数"><a href="#函数" class="headerlink" title="函数"></a>函数</h4><h5 id="函数声明"><a href="#函数声明" class="headerlink" title="函数声明"></a>函数声明</h5><p>定义</p><p>修饰</p><p>调用</p><p>返回值(可以多个,<strong><em>最多7个</em></strong>,可省略名字) 可return (v0,v1,…,vn)</p><p>fallback(匿名函数)</p><h5 id="函数修饰符"><a href="#函数修饰符" class="headerlink" title="函数修饰符"></a>函数修饰符</h5><p>💡 切记区分可见性(可调用的位置)和能不能看见函数内容是不同的</p><p>调用其他合约(除继承外)需要先获得一个其他合约实例c,然后c.functionxx()</p><blockquote><p>💡</p><ul><li>函数声明时默认为<strong><code>public</code></strong>类型,和显示声明为<strong><code>public</code></strong>类型的函数一样,都可供外部访问。</li><li>构造函数大部分情况下都声明为<code>public</code>类型。</li><li>所有在合约内的东西对外部的观察者来说都是可见的,将某些东西标记为<strong><code>private</code></strong>仅仅阻止了其它合约来进行访问(调用)和修改,但并不能阻止其它人看到相关的信息[可以看到函数是干啥的,函数体里头有啥内容,但是没法调用,没法改]。</li><li>可见性的标识符的定义位置,==对于变量声明来说是在类型的后面==,==对于函数声明来说是在参数列表和返回关键字(returns)中间==。</li><li>状态变量声明时,默认为<strong><code>internal</code></strong>类型,只有显示声明为<strong><code>public</code></strong>类型的状态变量才会自动生成一个和状态变量同名的<strong><code>get</code></strong>函数以供外部获取当前状态变量的值。状态变量无法声明为<code>external</code>类型。</li></ul></blockquote><h6 id="可见性-不刻意声明时有默认值"><a href="#可见性-不刻意声明时有默认值" class="headerlink" title="可见性 不刻意声明时有默认值"></a>可见性 不刻意声明时有默认值</h6><p>函数可见性默认为public</p><p>状态变量可见性默认为internal 无法声明为external</p><p>结构体默认为internal 且无法加任何其他的可见性声明</p><table><thead><tr><th>修饰符</th><th>意义</th><th style="text-align:center">分类</th></tr></thead><tbody><tr><td>public</td><td>任何人(包括儿子)可以调用(同一个sol文件内部可以直接调用,其他文件需要import引入)该函数,和private互斥</td><td style="text-align:center">调用控制类</td></tr><tr><td>private</td><td>只有该合约能调用(儿子都不可),和public互斥</td><td style="text-align:center">调用控制类</td></tr><tr><td>external</td><td>外部函数。内部不可访问(可this),外部正常访问,子类可继承。</td><td style="text-align:center">调用控制类</td></tr><tr><td>internal</td><td>内部函数。内部正常访问,外部无法访问,子类可继承。</td><td style="text-align:center">调用控制类</td></tr><tr><td>view</td><td>合约不修改状态变量,和constant一样</td><td style="text-align:center">状态变量访问控制类</td></tr><tr><td>constant</td><td>合约不修改状态变量,和constant一样</td><td style="text-align:center">状态变量访问控制类</td></tr><tr><td>pure</td><td>合约不但不修改,也不读取状态变量</td><td style="text-align:center">状态变量访问控制类</td></tr><tr><td>payable</td><td>涉及eth(其他token不算)的转移操作需要加上这个</td><td style="text-align:center">资金控制类</td></tr><tr><td>自定义修饰符</td><td>自定义修饰符号modifier</td><td style="text-align:center">自定义控制类</td></tr></tbody></table><p>函数中有transfer、send等方法,则需要加上payable修饰</p><p>合约中的struct数组的可见性只支持internal(默认值,不需要写),不能声明其他可见性!!(新版本也看下)</p><p>==external调用注意==</p><p>合约内或后代合约(继承)需要用this方式调用,此外合约外部直接用合约实例调即可。b.externalFn();</p><p>==函数返回值return用法==</p><ol><li><p>function .. returns (type _result){…;_result = xxx;}</p><p>定义出参时加上变量名,函数体不写return</p></li><li><p>function .. returns (type){…;return result;}</p><p>定义出参时不加变量名,函数体写return</p></li></ol><p>函数若声明成private私有的,remix右侧工具栏是无法看到和调用的;声明成external和public才可以。</p><p>view和constant在remix中为蓝色的,pure可用于计算(只是传参,不关心别的)</p><p>public变量会自动生成一个同名查询函数,蓝色。</p><p>查询最好带上view,因为不消耗gas啊,给力</p><p>函数多个返回值,只想取后面的返回值的方法:</p><blockquote><p>(,,,,,result) = functionA();</p></blockquote><p>==return在哪看==</p><ol><li>在控制台debug的decoded output字段看</li><li>在右侧工具窗口debugger页签的Solidity State看所有状态,这儿可以看到</li><li>如果带上view修饰符,直接在右侧界面可以看,调用方法后就在函数名下可以看到</li></ol><p>==!注意注意!==</p><p>view和pure的函数 被合约外部(即外部账户)调用时不花费gas</p><p>但它们被内部其他函数调用时 会耗费gas (取决于主调函数)</p><h5 id="require-assert-revert"><a href="#require-assert-revert" class="headerlink" title="require assert revert"></a>require assert revert</h5><p>if(msg.sender==owner){</p><p>//dosomething</p><p>}else{</p><p> revert();</p><p>}</p><p>不满足条件会revert回滚</p><p>更好的写法</p><p>require(msg.sender\==owner)//或assert(msg.sender==owner)</p><p>//dosomething</p><p>效果一样,但更简洁更语义化</p><h5 id="事件"><a href="#事件" class="headerlink" title="事件"></a>事件</h5><p>可用于打日志</p><p>在logs项中的event字段可以看到事件中定义了的参数</p><p>声明:</p><p>Event BidEvent(address _myAddr,uint _myMoney)</p><p>使用:</p><p>在函数中发射 emit BidEvent(myAddr,myMoney); </p><h5 id="数组"><a href="#数组" class="headerlink" title="数组"></a>数组</h5><p>push方法只能对变长数组使用</p><p>如果想用delete删数组元素,也用变长数组吧</p><h5 id="字符串"><a href="#字符串" class="headerlink" title="字符串"></a>字符串</h5><p>abi.encodePacked(a,b) 连接两个字符串</p><h5 id="web3-js"><a href="#web3-js" class="headerlink" title="web3.js"></a>web3.js</h5><p>RPC方式访问以太坊网络</p><blockquote><p>资料:<br><a href="http://cw.hubwiz.com/card/c/web3.js-1.0/1/4/7/" target="_blank" rel="noopener">http://cw.hubwiz.com/card/c/web3.js-1.0/1/4/7/</a></p></blockquote><p>view蓝色的 用call来调用?</p><p>红色的不带view的 用send来调用?</p><p>==调用关键点==</p><p>连接到以太坊</p><p>已知合约ABI</p><p>已知合约地址(通过ABI也可以部署新合约) 知道ABI和合约地址可以获得合约实例</p><p>以太坊客户端支持rpc</p><ol><li><p>创建合约对象</p></li><li><p>通过合约地址和合约abi获得合约实例</p></li><li><p>调用合约中的方法</p><p>实例.methods.functionName().call()</p></li></ol><p>或者methods.functionName().send()</p><p>call可以不用from和gas,send必须有from和gas</p><p>call(function(){})</p><p>send({},function(){})</p><h6 id="At-Address-加载已部署合约"><a href="#At-Address-加载已部署合约" class="headerlink" title="At Address 加载已部署合约"></a>At Address 加载已部署合约</h6><p>之前部署过的合约,有数据,</p><h5 id="import引入的用法"><a href="#import引入的用法" class="headerlink" title="import引入的用法"></a>import引入的用法</h5><ul><li>import “./xxx.sol”</li><li></li></ul><h5 id="库library的用法"><a href="#库library的用法" class="headerlink" title="库library的用法"></a>库library的用法</h5><ol><li><p>import {Console} from “./Console.sol”; //Console为library名字</p><p>使用时Console.log(xxx) 调用库名.方法</p></li><li><p>import “./AddressUtils.sol”;</p><p>合约内 using AddressUtils for address; 然后address类型自带方法isContract</p><p>使用时isContract(addrxxx) 或者 addrxx.isContract()?</p></li></ol><h5 id="solidity-0-5-0那些事"><a href="#solidity-0-5-0那些事" class="headerlink" title="solidity 0.5.0那些事"></a>solidity 0.5.0那些事</h5><p><a href="https://www.colabug.com/4931922.html" target="_blank" rel="noopener">https://www.colabug.com/4931922.html</a></p><ul><li>地址分为address和address payable,必须显式声明了payable才可以transfer send</li><li>external 的函数参数(普通类型数组!类型)需显式声明为 calldata,其他按各自规则来。</li><li>keccak256(abi.encodePacked(a,b,c)) 必须加上abi.encodePacked</li><li>bytes32无法转为uint8,但是可以转为uint(即uint256)</li><li>uint和uint8 一起运算可能会被禁止</li><li>selfdestruct参数的地址a必须为address payable,因为要把钱打到a那儿,payable才可以接收钱。</li><li>最新版本!string类型的函数参数需要显示增加memory声明</li></ul>]]></content>
<categories>
<category> BlockChain </category>
<category> Solidity </category>
</categories>
<tags>
<tag> Ethereum </tag>
<tag> Solidity </tag>
<tag> BlockChain </tag>
<tag> 智能合约 </tag>
</tags>
</entry>
<entry>
<title>npm常用知识点</title>
<link href="/2019/01/22/npm%E5%B8%B8%E7%94%A8%E7%9F%A5%E8%AF%86%E7%82%B9/"/>
<url>/2019/01/22/npm%E5%B8%B8%E7%94%A8%E7%9F%A5%E8%AF%86%E7%82%B9/</url>
<content type="html"><![CDATA[<p>第三方模块商店</p><p><a href="http://www.npmjs.com" target="_blank" rel="noopener">www.npmjs.com</a></p><p>npm文档</p><p>docs.npmjs.com</p><p><a href="http://www.npmjs.cn" target="_blank" rel="noopener">www.npmjs.cn</a></p><p>别人用node或者javascript写的工具模块</p><p>包版本格式一般为</p><p>主版本号.次版本号.修正版本号</p><p>重大更新 | 功能升级 | bug修复</p><p>==最常用命令==</p><ul><li>npm search | 例如: npm search jquery</li><li>npm install(npm i) npm i <a href="mailto:[email protected]" target="_blank" rel="noopener">[email protected]</a> 有多种模式<ul><li>本地模式</li><li>本地开发模式</li><li>全局模式</li></ul></li><li>npm update xx 更新xx包到当前主版本号的最新版本,一般不会更新主版本号</li></ul><p>==npm安装模式==</p><p>默认npm i 模块名 等同于 npm -save|-S 模块名</p><p> | 本地模式 => 信息记录到package.json的dependencies</p><p>npm i -D|-develop 模块名 | 本地开发模式=> 信息记录到package.json的devDependenies</p><p>npm i -g 模块名 | 全局安装 </p><p>全局安装后在 AppData\Roaming\npm\node_modules windows</p><p>或/usr/local/lib/node_modules unix或linux</p><p>项目代码中要使用的包使用本地模式</p><p>在项目开发过程中使用的而且非代码本身使用的包使用的模式为开发模式,比如各种辅助工具(例如babel、webpack、eslint等)</p><blockquote><p>💡注意事项</p><p>npm i 模块xx (-S);</p><p>对模块xx而言</p><ul><li>模块xx的dependencies会随模块一起下载,模块xx的devDependencies不会随模块一起下载</li></ul><p>对自身项目所在文件夹而言</p><ul><li>自身项目的packagejson中会将模块xx加入dependencies</li></ul><hr><p>npm i 模块yy -D</p><p>对模块xx而言</p><ul><li>模块xx的dependencies会随模块一起下载,模块xx的devDependencies不会随模块一起下载</li></ul><p>对自身项目所在文件夹而言</p><ul><li>自身项目的packagejson中会将模块xx加入devDependencies</li></ul><hr><p>npm i</p><p>==当前所在项目文件夹下的packagejson中的无论dependencies或devDependencies全都一股脑下载下来==</p><p>所以,如果平时下载的第三方模块没有包含依赖的工具库内容时,你可以直接到第三方模块目录底下打命令npm i ,所有的依赖包括dependencies和devDependencies都会被下载下来,供你学习或使用。</p><p>或者你用npm i -D 结果是一样的</p></blockquote><p>npm run xxx</p><p>xxx是package.json中的scripts字段中的某个对象,是一些较长命令的缩写,可以简洁地运行命令又避免了麻烦地书写一长串带参数的命令。</p><p>相当于运行script中的命令</p><h5 id="package-lock-json-和-package-json"><a href="#package-lock-json-和-package-json" class="headerlink" title="package-lock.json 和 package.json"></a>package-lock.json 和 package.json</h5><h6 id="package-lock-json"><a href="#package-lock-json" class="headerlink" title="package-lock.json"></a>package-lock.json</h6><p>加速已安装过的包的安装速度</p><p>锁定安装版本,避免直接改package.json,利于包管理</p><p>package.json是锁定大版本号(第一版本号),每次npm install仍然会更新最新的小版本号</p><p>这时使用package-lock.json就锁定全部版本号,不会因为npm install导致包的版本号变动</p><p>如果还是想更新npm包,就只能用这种方法,npm install <a href="mailto:[email protected]" target="_blank" rel="noopener">[email protected]</a>(或者@latest)</p><h6 id="package-json"><a href="#package-json" class="headerlink" title="package.json"></a>package.json</h6><p>该文件是用来描述目录类型的模块或第三方模块(第三方模块也是按照目录进行组织的)</p><p>如果一个模块下有package.json文件,首先读取package.json的文件,读取这个文件中的main字段对应的文件路径,</p><p>如果没有package.json文件,则默认读取该文件夹路径下的index.js</p><p>安装或卸载完第三方模块,会同时更新package.json的dependencies项中的内容,增加或删除。</p><figure class="highlight json"><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><br><span class="line"> <span class="attr">"name"</span>:</span><br><span class="line"> <span class="string">"version"</span>:</span><br><span class="line"> <span class="string">"main"</span>:</span><br><span class="line"> <span class="string">"dependencies"</span>:{</span><br><span class="line"> <span class="attr">"jquery"</span>: <span class="string">"^3.3.1"</span></span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>npm run xxx</p><p>xxx是package.json中的scripts字段中的某个对象,是一些较长命令的缩写,可以简洁地运行命令又避免了麻烦地书写一长串带参数的命令。</p><p>相当于运行script中的命令</p><p>创建方式:</p><ul><li>手动创建</li><li>npm init(交互式) | npm init -y(直接生成)</li></ul><p>name和version两个字段是==必须必须有的==</p><h5 id="常用工具"><a href="#常用工具" class="headerlink" title="常用工具"></a>常用工具</h5><p>path库</p><p>livereload 不用手动刷新页面 自动重启前端</p><p>supervisor 不用手动重新打指令开服务器 自动重启后端</p><p>nrm 切换下载源</p><p>http-server -c-1 启动简易服务器</p><h5 id="发布一个npm包"><a href="#发布一个npm包" class="headerlink" title="发布一个npm包"></a>发布一个npm包</h5><p>==package.json是必须的==</p><p>npm官网注册账号</p><p>npm login | 输入用户名 密码</p><p>定位到当前目录然后 npm publish</p><p>在官网就可以搜索到啦</p><p>npm unpublish 下架指定的包</p>]]></content>
<categories>
<category> Web </category>
<category> NPM </category>
</categories>
<tags>
<tag> Web </tag>
<tag> Node.js </tag>
<tag> NPM </tag>
</tags>
</entry>
<entry>
<title>聊聊geth和私链节点</title>
<link href="/2019/01/20/%E8%81%8A%E8%81%8Ageth%E5%92%8C%E7%A7%81%E9%93%BE%E8%8A%82%E7%82%B9/"/>
<url>/2019/01/20/%E8%81%8A%E8%81%8Ageth%E5%92%8C%E7%A7%81%E9%93%BE%E8%8A%82%E7%82%B9/</url>
<content type="html"><![CDATA[<h5 id="创世区块"><a href="#创世区块" class="headerlink" title="创世区块"></a>创世区块</h5><figure class="highlight"><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></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">"config"</span>: {</span><br><span class="line"> //区块链的ID,你随便给一个就可以</span><br><span class="line"> "chainId": 21,</span><br><span class="line"> //下面三个参数暂时不知道干啥的</span><br><span class="line"> //等我知道了补上,或者有哪位大神知道</span><br><span class="line"> //可以在评论里指点我,谢谢</span><br><span class="line"> "homesteadBlock": 0,</span><br><span class="line"> "eip155Block": 0,</span><br><span class="line"> "eip158Block": 0</span><br><span class="line"> },</span><br><span class="line"> //用来预置账号以及账号的以太币数量,应该也就是所谓的预挖</span><br><span class="line"> //我这里不需要预挖,所以给了个空对象</span><br><span class="line"> //如果需要可以这样加</span><br><span class="line"> //"alloc": {</span><br><span class="line"> //"0x0000000000000000000000000000000000000001": {"balance": "111111111"},</span><br><span class="line"> //"0x0000000000000000000000000000000000000002": {"balance": "222222222"}</span><br><span class="line"> //}</span><br><span class="line"> "alloc" : {},</span><br><span class="line"> //币基地址,也就是默认的钱包地址,因为我没有地址,所以全0,为空</span><br><span class="line"> //后面运行Geth后创建新账户时,如果Geth发现没有币基地址,会默认将第一个账户的地址设置为币基地址</span><br><span class="line"> //也就是矿工账号</span><br><span class="line"> "coinbase" : "0x0000000000000000000000000000000000000000",</span><br><span class="line"> //挖矿难度,你可以随便控制哦,这里设置的难度比较小,因为我喜欢钱来得快</span><br><span class="line"> "difficulty" : "0x20000", //可以用小点的0x4000</span><br><span class="line"> //0x2ffffd大概 一分钟5~10个</span><br><span class="line"> //附加信息,随便填个文本或不填也行,类似中本聪在比特币创世块中写的报纸新闻</span><br><span class="line"> "extraData" : "",</span><br><span class="line"> //gas最高限制,以太坊运行交易,合约等所消耗的gas最高限制,这里设置为最高</span><br><span class="line"> "gasLimit" : "0x2fefd8", //0xffffff为最高</span><br><span class="line"> //64位随机数,用于挖矿,注意他和mixhash的设置需要满足以太坊黄皮书中的要求</span><br><span class="line"> //直接用我这个也可以</span><br><span class="line"> "nonce" : "0x0000000000000042",</span><br><span class="line"> //与nonce共同用于挖矿,注意他和nonce的设置需要满足以太坊黄皮书中的要求</span><br><span class="line"> "mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",</span><br><span class="line"> //上一个区块的Hash值,因为是创世块,石头里蹦出来的,没有在它前面的,所以是0</span><br><span class="line"> "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",</span><br><span class="line"> //创世块的时间戳,这里给0就好</span><br><span class="line"> "timestamp" : "0x00"</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>初始化创世节点:</p><p>geth –datadir ./data init genesis.json</p><p>启动节点</p><p>geth –datadir ./data –networkid 15 –port 30303 –rpc –rpcaddr 0.0.0.0 –rpcport 8545 –rpcapi ‘db,net,eth,web3,personal’ –rpccorsdomain ‘*’ –nat “any” –nodiscover console</p><p>💡 <font style="color:white;background:mediumseagreen;padding:3px 6px;font-weight:bold;line-height:28px">千万注意引号是英文的 特别坑</font></p><h5 id="GETH命令参数详解"><a href="#GETH命令参数详解" class="headerlink" title="GETH命令参数详解"></a>GETH命令参数详解</h5><table><thead><tr><th>geth命令参数</th><th>参数含义</th></tr></thead><tbody><tr><td>console</td><td>指启动节点后启用交互式js命令行</td></tr><tr><td>datadir</td><td>指定数据存放目录</td></tr><tr><td>networkid</td><td>以太坊网络标识符,1代表主网,3Ropsten,4Rinkeby,34都为测试网,<br>默认为1,填个大点的代表私有链</td></tr><tr><td>port</td><td>网卡监听端口号,不同计算机节点通过这个连接</td></tr><tr><td>–rpc</td><td>启用http-rpc服务器,允许远程指令访问</td></tr><tr><td>rpcaddr 0.0.0.0</td><td>允许任意有效的ip地址连接</td></tr><tr><td>rpcport</td><td>http-rpc服务器监听端口,即geth启动rpc服务的端口为8545(默认值)</td></tr><tr><td>rpcapi</td><td>提供的可供调用的api模块</td></tr><tr><td>rpccorsdomain</td><td>可以跨域访问的域名列表 (浏览器想连接上geth需要有此项),<br>*代表所有</td></tr><tr><td>nat</td><td>端口映射机制,默认any</td></tr><tr><td>nodiscover</td><td>禁用节点发现机制(手动添加节点)</td></tr><tr><td>–identity</td><td>自定义节点名‘name’</td></tr><tr><td>–dev</td><td>开发者模式,自动分配一个不需要解锁的账户而且会得自动挖矿</td></tr></tbody></table><font style="color:white;background:mediumseagreen;padding:3px 6px;font-weight:bold;line-height:28px">注意</font><p>–dev 使用POA共识网络,默认预分配一个开发者账户并且会自动开启挖矿。–dev可以不用创世块初始化</p><p>创世块中调节挖矿难度</p><p>–dev.period value | value为开发者模式下挖矿周期(0 = 仅在交易时)(默认: 0)</p><blockquote><p>geth –datadir ./data –networkid 15 –port 30303 –rpc –rpcaddr 0.0.0.0 –rpcport 8545 –rpcapi ‘db,net,eth,web3,personal’ –rpccorsdomain ‘*’ –nat “any” –nodiscover –identity “superman285” console 2>gethprint.log</p></blockquote><p>信息不打印在命令行中,而是输出到gethprint.log文件中,</p><p>这时如果用miner.start() 会打出null而不是true,但是也开始挖矿了</p><p>geth命令参数详解:<a href="http://www.cnblogs.com/tinyxiong/p/7918706.html" target="_blank" rel="noopener">http://www.cnblogs.com/tinyxiong/p/7918706.html</a></p><p>geth的控制台可以定义变量,用js语法,可用var</p><font style="color:white;background:mediumseagreen;padding:3px 6px;font-weight:bold;line-height:28px">常用:</font><p>eth.accounts | eth.accounts[index]</p><p>eth.blockNumber</p><p>eth.getBalance(eth.accounts[0])</p><p>personal.newAccount(“password”)</p><p>personal.unlockAccount(address) | 可以address = eth.accounts[0]</p><p>miner.start() | miner.stop()</p><p>转账</p><p>eth.sendTransaction({from:user1,to:user2,value:web3.toWei(10,“ether”)})</p><p>转账10个eth,需要挖矿才能确认交易</p><p>单位换算</p><p>web3.toWei(10,“ether”)</p><p>geth指令 启动节点时如果带了 –dev 开发者模式 可以不用创世块genesis block来初始化 ?</p>]]></content>
<tags>
<tag> Ethereum </tag>
<tag> BlockChain </tag>
</tags>
</entry>
<entry>
<title>node简单基础</title>
<link href="/2019/01/15/node%E7%AE%80%E5%8D%95%E5%9F%BA%E7%A1%80/"/>
<url>/2019/01/15/node%E7%AE%80%E5%8D%95%E5%9F%BA%E7%A1%80/</url>
<content type="html"><![CDATA[<h5 id="webserver"><a href="#webserver" class="headerlink" title="webserver"></a>webserver</h5><p>Nginx 下载好对应系统版本安装,命令行开启,就相当于启动服务器了</p><p>nginx配置conf文件</p><p>root html路径修改下即可</p><p>nginx -c conf/myselfconf.conf</p><p>这时就自己可以通过localhost或127.0.0.1访问</p><p>查下自己公网ip 其他机器可通过这个访问</p><h5 id="node"><a href="#node" class="headerlink" title="node"></a>node</h5><p>操作文件系统/网络/数据/进程 等 而不是bom和dom</p><h6 id="模块化"><a href="#模块化" class="headerlink" title="模块化"></a>模块化</h6><p>require方法返回的是module.exports对象(与exports是一样的,全等,相当于省略了module的写法)</p><p>如果不给module.exports添加内容,那返回的就是{} 空对象</p><p>==module.__dirname(目录)== | ==module.__filename(目录及文件名)== | module.require</p><p>模块内的module就相当于浏览器中的window,可以省略</p><p>数据冲突问题,依赖问题</p><p>node的顶层全局对象为global,模块顶层对象为module,global.a 全部模块都可以访问</p><p>每一个文件都是一个模块,每个模块有自己的独立作用域,模块内的数据自己私有</p><p>每个独立模块都有一个内置对象 module,该对象存储和提供与当前模块有关的一些信息</p><p>每一个模块对象module下有一个属性exports,默认为空对象,该对象为导出对象,可以把模块中的局部变量等数据挂载到该对象下,require方法返回的值就是被加载模块的exports对象</p><p>exports.a = a; 这时返回值就是{a:2}(exports对象)</p><p>require</p><p>每个模块下都有一个模块对象module,同时该模块下有一些属性和方法:</p><p>exports: 导出模块私有数据</p><p>require: 加载模块</p><p>commonJS 模块化</p><h5 id="模块加载"><a href="#模块加载" class="headerlink" title="==模块加载=="></a>==模块加载==</h5><p>require(‘./2’)或require(‘./2.js’) 会执行2.js,同时会返回一个值,</p><p>require一个json返回 对象? 学习下</p><p>模块也可以通过目录形式来组织, let dir = require(‘./miaov’) 默认加载的是./miaov/index.js</p><p>默认情况下会加载目录模块下的index.js 作为目录模块的入口,如果不想的话,准备一个package.json文件</p><p>==package.json== 模块说明文件</p><p>name 模块名称 | version 模块版本 | main 模块入口文件</p><p>{</p><p> “name”: “miaov”,</p><p> “version”: “1.0.0”,</p><p> “main”: “fn.js” //改变默认加载的入口文件</p><p>}</p><h6 id="使用require时导入模块的顺序"><a href="#使用require时导入模块的顺序" class="headerlink" title="使用require时导入模块的顺序"></a>使用require时导入模块的顺序</h6><p>如果一个模块下有package.json文件,首先读取package.json的文件,读取这个文件中的main字段对应的文件路径,</p><p>如果没有package.json文件,则默认读取该文件夹路径下的index.js</p><p>💡注意:如果既没有index.js也没有package.json(或main字段),则会报错:cannot find module</p><p>==两种路径的方式==</p><p>自己的文件/文件夹模块 require形式为./|../之类打头 let my = require(‘./mydir’)</p><p>第三方模块 require形式不以./|../之类路径符号打头 let jquery = require(‘jquery’)</p><p>./导入的是本地文件/文件夹模块</p><p>不带./导入的是核心模块(例如require(‘fs’))或第三方模块(在node_modules)</p><p>为防止自己的项目模块和第三方模块混合,node中约定了一个特殊目录,mode_modules目录存放第三方模块</p><blockquote><p>第三方模块查找逻辑:</p><p>先在本层目录的node_modules目录找,找不到的话到父亲的node_modules目录</p><p>直到找到最顶层的node_modules目录</p><p>最终会找到 /users/superman285/.node_modules目录下</p><p>如果还找不到就要找node源码了(即核心模块)</p></blockquote>]]></content>
<categories>
<category> BackEnd </category>
<category> Node.js </category>
</categories>
<tags>
<tag> 基础 </tag>
<tag> Node.js </tag>
</tags>
</entry>
<entry>
<title>流行的Koa框架</title>
<link href="/2019/01/14/%E6%B5%81%E8%A1%8C%E7%9A%84Koa%E6%A1%86%E6%9E%B6/"/>
<url>/2019/01/14/%E6%B5%81%E8%A1%8C%E7%9A%84Koa%E6%A1%86%E6%9E%B6/</url>
<content type="html"><![CDATA[<h5 id="Koa框架-一个http框架"><a href="#Koa框架-一个http框架" class="headerlink" title="Koa框架 一个http框架"></a>Koa框架 一个http框架</h5><p>Koa其实就是对node原生http对象的二次包装,提供了更好的接口和结构,方便使用和维护。</p><p>具体API <a href="https://koa.bootcss.com/" target="_blank" rel="noopener">https://koa.bootcss.com/</a></p><p>Koa本身超级简单,也没自带路由,可以借助别人实现的第三方中间件,来配合使用。</p><p>例如路由 : koa-router</p><p>第三方中间件大全:<a href="https://github.com/koajs/koa/wiki" target="_blank" rel="noopener">https://github.com/koajs/koa/wiki</a></p><p>常用:</p><p>koa-static-cache 静态资源代理</p><p>koa-router 路由</p><p>nunjucks 模板引擎</p><p>koa2-cors 解决跨域问题</p><p>在服务器端app.js</p><p>const cors = require(‘koa2-cors’);</p><p>app.use(cors()); //放在route前</p><p>app.use(router.routes());</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="keyword">const</span> Koa = <span class="built_in">require</span>(<span class="string">'koa'</span>);<span class="comment">//可确认下koa版本是否是2</span></span><br><span class="line"><span class="comment">//相当于const http = require('http');</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//创建一个经过Koa包装的http服务器</span></span><br><span class="line"><span class="keyword">const</span> app = <span class="keyword">new</span> Koa();</span><br><span class="line"><span class="comment">//相当于 const app = new http.Server();| 或 http.createServer();</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//监听指定端口</span></span><br><span class="line">app.listen(<span class="number">80</span>);</span><br></pre></td></tr></table></figure><p>Koa帮我们重新包装了http对象(包成app对象),并处理了很多通用数据和方法,并把这些数据和方法挂到了app的一个属性下面==app.context== context为了方便一般可简写为ctx</p><p>没有请求的时候打印(直接打印只能用dir)app.context 是空对象,还没有数据过来</p><p>==一般不会直接调用app.context,因为该对象没有经过处理,而是要通过中间件函数的第一个参数去掉用==</p><p>有请求的时候,中间件函数就会执行,同时Koa会解析数据并赋值给app.context,把它作为当前执行的中间件的第一个参数传入进来</p><p>这样使用:</p><p>app.use(ctx=>{console.log(ctx)})</p><p>context下包含的对象,请求响应两大对象 就同http一样</p><ul><li>request对象</li><li>response对象 |响应(输出)|</li><li>app对象</li></ul><p>context对象下还有一些属性是request和response的映射</p><p>e.g </p><p>context.response.body === context.body</p><p>context.request.header === context.header</p><p>为了写起来简便,很多request和response下的对象都直接挂在了context下。</p><p>==注意==</p><p>ctx.body是ctx.response.body 是响应的正文,是服务器发给客户端的!</p><p>ctx.request.body 并不一样 这是请求的正文,是客户端发给服务器的!</p><p>context.request.url</p><p>context.response.body = “</p><h1>hello</h1>”|“{a:1,b:2}”|“hello world”<p></p><p>帮你自动辨别你提供的数据,智能地设置content-type为html/json/plain (相当于MIME),不用麻烦你自己再判断</p><h6 id="中间件的内涵"><a href="#中间件的内涵" class="headerlink" title="中间件的内涵"></a>中间件的内涵</h6><p>一个http服务器主要做的事情流程是如何的?</p><ul><li>解析请求 -> 处理数据 -> 返回数据</li></ul><p>Koa框架帮助我们处理第一步的请求解析并封装到app对象里面以供后续使用且同时帮我们处理数据的返回,比如根据处理好的数据返回不一样的Content-Type</p><p>中间的步骤是数据处理,数据的处理就和业务是相关的(你有什么具体需求Koa肯定不知道的),Koa就无能为力了</p><blockquote><p>中间件</p><p>==中间件可以理解为对用户请求进行处理(或过滤等)的一个东西,不会直接对前端进行响应,而是将处理结果往下传递,就是中间处理数据的一个部件==</p><p>需要我们处理的步骤在中间(处理数据这个步骤),那么我们只需要通过某种方式把我们需要的事情注册到Koa中间件的列表中,当Koa处理完成解析请求后,就会自动的执行我们注册的中间件,执行完中间件后就会自动调用返回数据的代码</p></blockquote><p>深度理解中间件的执行顺序,next的作用</p><p><a href="https://segmentfault.com/q/1010000011033764" target="_blank" rel="noopener">https://segmentfault.com/q/1010000011033764</a></p><p>洋葱圈模型,这个也可以适用于事件冒泡机制啊哈哈</p><p>一个js文件里头 不是所有有use的地方 都需要看到next 没有next就影响其他use了 ==并不是!==</p><p>这个函数得是中间件 你才需要next! 比如访问静态页面或访问路由 不需要向下next了 就不算中间件?</p><p>中间件本质就是一个函数</p><p>注册中间件</p><p>app.use(function(){</p><p>}); </p><p>//可以处理代理、跨域、负载等各种各样的问题 ssr服务器端渲染</p><p>中间件的next方法是异步的,需要加上await</p><p>Koa解决跨域简单写法</p><p>app.use( async (ctx,next) => {</p><p>ctx.set(‘Access-Control-Allow-Origin’,‘*’); await next();</p><p>})</p><p>中间件模拟 深度</p><p><a href="https://segmentfault.com/a/1190000016707059" target="_blank" rel="noopener">https://segmentfault.com/a/1190000016707059</a></p><h5 id="Koa框架应用"><a href="#Koa框架应用" class="headerlink" title="Koa框架应用"></a>Koa框架应用</h5><p>==路径开头的斜线非常非常重要==</p><h6 id="静态资源代理-koa-static-cache"><a href="#静态资源代理-koa-static-cache" class="headerlink" title="静态资源代理 koa-static-cache"></a>静态资源代理 koa-static-cache</h6><p>某些特定路径 走静态资源代理</p><p>其他路径 走服务器路由逻辑</p><blockquote><p>需要访问静态资源时(例如html啊 图片啊之类)使用静态资源代理 否则打开服务器它不知道读哪个目录 想把目录当成一个服务器 访问里头的静态资源 就需要做这一步</p><p>否则读不到静态资源</p><p>切记: 访问时要正确路径/xxx.html 千万别漏了(动态路由不需要,这儿静态的千万别弄错)</p><p>dir设置静态资源所在目录 要加.</p><p>prefix设置你想要加的前缀 不设置也行的 不加.</p><p>访问动态资源可使用路由koa-router 配合前端的get请求的url</p></blockquote><p>KoaStaticCache(dir[,options][,files]) 包装函数写法 返回一个函数</p><p>dir:指定要处理的静态文件(html)存放目录,当用户访问某个url时</p><p>options为对象,可以修改</p><p>max-age 最长缓存时间| 是否压缩(gzip) | 前缀(prefix,设置url前缀) | dynamic(是否动态读取)</p><p>例如prefix:/public 则需要请求/public/index.html才可以访问</p><p>prefix的作用是 可以区分开静态资源和需要动态处理的资源 加上前缀才可以正常访问</p><p>dynamic 是否动态读取,默认为false</p><p>accept-encoding为支持的编码(gzip更常用)</p><p>访问同一个url时</p><ul><li><p>静态资源: 如果资源内容不改变,那么访问这个url得到的内容不会有任何变化</p><p>例如css啊 图片啊 部分js代码(特效之类)等</p></li><li><p>动态资源: 同一个url可能会根据不同的处理得到==不一样==的内容 </p><p>举个栗子🌰 ctx.body = “”+Math.random() 每次访问同一个url得到的内容可能都不一样</p></li></ul><p>静态资源可以利用直接读取文件并返回的方式处理,例如利用koa-static-cache</p><p>动态资源需要具体的处理逻辑,根据不同的url返回不一样的内容</p><p>动态资源的url可能量也很大,为了更好地处理这些动态资源url,我们需要使用==路由==,例如koa-router</p><p>==Koa框架帮我们处理了请求,处理了输出==</p><p>向客户端返回数据是通过 http=> end()方法来实现的</p><p>把ctx.body作为返回值, 相当于.end(ctx.body)</p><p>所以不需要在中间件中手动调用end方法,只需要给ctx.body赋值</p><p>然而中间件很多都是异步操作,如果不做特殊操作 .end方法不会等异步操作完成才调用,所以那时调用会是 not found (那时ctx.body是undefined)</p><p>如果 await fn(); .end(ctx.body); 这样就会等fn执行有结果后 才会调end</p><h6 id="路由-koa-router"><a href="#路由-koa-router" class="headerlink" title="路由 koa-router"></a>路由 koa-router</h6><p>路由:即映射,内容分发,一个url与某个函数的绑定 形成一种关系</p><p>为我们的url 绑定对应的 处理函数</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></pre></td><td class="code"><pre><span class="line">router.use(<span class="string">'/'</span>,ctx=>{})</span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">*use不会处理请求方法,任何的请求method都会走use,不区分get|post,类似统一入口</span></span><br><span class="line"><span class="comment">*url部分也不是相等,而是包含,use判断的是是否包含'/',只要前缀为'/'都会走use</span></span><br><span class="line"><span class="comment">*get与use的区别是get时路径必须为相等关系,而use时路径包含即可</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//use的作用,例如可以做一个用户统一验证,要么给每个get的/user做个验证,要么在use给/user做验证即可。</span></span><br><span class="line"></span><br><span class="line">router.get(<span class="string">'/'</span>,ctx=>{</span><br><span class="line"> ctx.body=<span class="string">"首页"</span>;</span><br><span class="line">})</span><br><span class="line">router.get(<span class="string">'/user'</span>,ctx=>{</span><br><span class="line"> ctx.body=<span class="string">"用户"</span>;</span><br><span class="line">})</span><br><span class="line"><span class="comment">/*把设置好的路由对象挂到指定的app对象上,app接收到请求后会把请求转发给router.routes()中间件</span></span><br><span class="line"><span class="comment">* app -> router -> 根据不同url执行不同的绑定函数</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line">app.use(router.routes())</span><br></pre></td></tr></table></figure><blockquote><p>💡注意</p><p>多个中间件函数只会默认执行第一个,后续的中间件函数需要我们手动调用</p><p>中间件函数的第二个参数是一个next方法,调用该方法就可以执行下一个匹配的中间件</p><p>d</p><p>router.use(‘/user’,(ctx,next)=>{</p><p> //判断</p><p> next();</p><p>})</p></blockquote><p>redirect方法 重定向(不设置默认为302) | 重定向分为 301永久重定向 , 302临时重定向</p><p>router.redirect(‘/login’,‘/login1’,302); //临时设置login重定向到login1,参数也可以设置为301</p><p>prefix设置前缀,省去后面重复写的时候麻烦</p><p>const router = new KoaRouter({</p><p> prefix: “/user”</p><p>});</p><p>==path-to-regexp==</p><p>/:id 表示/后面面的值是不固定的,所有符合</p><p>温习下2小时处视频内容,模板字符串,对象解构,find用法等知识点,</p><p>模板字符串支持表达式,不支持语句</p><p>可以这么写${users.map(user=>\<li>\</li>).join(‘’)}</p><h6 id="nunjucks-模板引擎"><a href="#nunjucks-模板引擎" class="headerlink" title="nunjucks 模板引擎"></a>nunjucks 模板引擎</h6><p>渲染工作是在后端进行的</p><p>let str = tpl.renderString(‘</p><h1>Hello </h1>’,{username:xxxx})<p></p>代表变量 类似es6中的${var}<br><br><br><br>管道符| 管道符前的内容作为参数传给管道符后的函数 例如<h5 id="文件上传模块-koa-multer"><a href="#文件上传模块-koa-multer" class="headerlink" title="文件上传模块 koa-multer"></a>文件上传模块 koa-multer</h5><p>storage配置</p><p>封装的file属性 fieldname | originalname | encoding | mimetype</p>]]></content>
<categories>
<category> BackEnd </category>
<category> Koa </category>
</categories>
<tags>
<tag> Node.js </tag>
<tag> Koa </tag>
</tags>
</entry>
<entry>
<title>Vuex和VueRouter</title>
<link href="/2019/01/12/Vuex%E5%92%8CVueRouter/"/>
<url>/2019/01/12/Vuex%E5%92%8CVueRouter/</url>
<content type="html"><![CDATA[<h5 id="VueRouter-vue前端路由"><a href="#VueRouter-vue前端路由" class="headerlink" title="VueRouter vue前端路由"></a>VueRouter vue前端路由</h5><p>vue页面开发中 每一个要实现的独立页面内容都是通过组件来完成的</p><p>router 路由管理者 新建Vue对象需要配置此项</p><p>route 单个路由 对象</p><p>routes 路由们 (定义路由组件关系映射关系的数组)</p><p>routes[route1,route2]</p><p>route{name:xx,path:yy,component:zz} path即url,component即组件名,name不是必须的</p><p>router的组件 router-view router-link</p><p>router-view : 相当于占位符,用于展示与当前url匹配的组件内容(route对象中的component)</p><p>总是忘记 router-view怎么运作,记清楚了!! 浏览器url <=> router.js匹配关系</p><p>router-view就 表示 在浏览器url中的路径 匹配到的显示内容 对应关系在router.js中看</p><p>默认是/ 那就对应的router.js中的 / 路径对应的component</p><p>如果是/about 就对应router.js中的 /about对应的component</p><p>router-link : 会被渲染成a标签,但是会增加click事件,阻止默认行为(跳转和发请求),</p><p>根据hash模式或history模式进行不同处理;</p><p>history模式增加pushState事件,hash模式用上了onhashchange事件(回顾下确定)</p><p>切记 把url放在地址栏然后回车 是通过浏览器发请求给后端 如果没有配后端路由 就会挂掉</p><p>但是在页面上点击标签 就没有给后端发请求</p><p>动态路由</p><p>path-to-regexp模式 path: ‘/:id’</p><p>$route 当前路由信息 包括path、params等属性</p><p>$router 为new出来的router对象实例</p><p>传数据</p><p>$route.params.id </p><p>$route.query.id 通过查询参数?</p><p>router-link激活的类名 router-link-active(包含匹配) router-link-exact-active(精确匹配)</p><p>==💡坑点:==</p><p>可能需要默认选中项(第一项)进行精确匹配,其他项进行包含匹配</p><p>默认项router-link标签加上属性exact即变成精确匹配</p><p>router-link tag属性 不默认渲染成a 而是渲染成写在tag后的标签</p><p>==嵌套路由两个核心==</p><p>routes选项中设置路由的包含关系,在某个route对象中设置children routes数组</p><p>子路由组件出现在父级路由组件页面中的哪个位置</p><p>==命名路由== 更方便以后管理和修改路径</p><p>==命名视图== router-view起名 一个页面可能包含多个页面组合 用name来标识他们</p><p>==重定向==</p><p>{path:‘/list’,redirect:‘/l’} 访问list时重定向到l</p><h6 id="路由组件传参"><a href="#路由组件传参" class="headerlink" title="路由组件传参"></a>路由组件传参</h6><p>在一个组件中复用另一个组件,都统一从props中拿,而不是从$route.params或\$route.query中拿</p><h6 id="路由守卫"><a href="#路由守卫" class="headerlink" title="路由守卫"></a>路由守卫</h6><p>最全解释:</p><p><a href="https://router.vuejs.org/zh/guide/advanced/navigation-guards.html" target="_blank" rel="noopener">https://router.vuejs.org/zh/guide/advanced/navigation-guards.html</a></p><p>==全局前置守卫== 导航被确认之前</p><p>router.beforeEach((to,from,next)=>{//路由跳转前的业务逻辑})</p><p>next()调用 才可以正常跳转到路由页</p><p>当路由发生变化时,全局beforeEach就会被触发,</p><p>我们可以在这个函数中加入一些业务处理,例如权限验证,如果通过则调用next进入目标路由页</p><p>demo例子: 登录验证 如果没登录 点其他页都跳到登录页,登录了就正常跳转</p><p>to 即将要进入的目标 ==路由对象==</p><p>from 当前正要离开的 ==路由对象== 如果name看不出来可以看它的fullPath来判断是哪个路由</p><p>==全局后置守卫== 导航被确认之后</p><p>router.afterEach</p><p>==单独路由独享的守卫==</p><p>某一个路由想做一些与全局无关的事情 多个路由的话用全局守卫</p><p>路由对象中配置beforeEnter(to,from,next){}</p><p>{name:xx,path:yy,component:zz,beforeEnter(to,from,next){}}</p><p>与在全局用路由守卫 然后单个路由加上meta</p><p>多个里头有一个有特殊需求 可以用路由独享守卫</p><p>多个里头有多个有特殊需求 可以用全局守卫+ 多个路由元信息</p><h6 id="路由元信息meta"><a href="#路由元信息meta" class="headerlink" title="路由元信息meta"></a>路由元信息meta</h6><p>在路由中配置</p><p>加入可供查看的一些路由的信息 做一些批量xx或者批量不xx的工作</p><h6 id="路由跳转"><a href="#路由跳转" class="headerlink" title="路由跳转"></a>路由跳转</h6><p>router.push({name: ‘login’}) 跳转到login路由页</p><p>在路由守卫中可以简写为 next({name:‘login’})</p><h6 id="组件内的守卫"><a href="#组件内的守卫" class="headerlink" title="组件内的守卫"></a>组件内的守卫</h6><p>类似生命周期</p><p>to from next</p><p>beforeRouteEnter 不能获取this!!! 因为组件都没渲染出来呢!! 用to就相当于this.$route了</p><p>这里头的next(function(vm){}) function参数vm就相当于组件对象实例!</p><p>beforeRouteUpdate 例如 /login/:id 这种 由login/1切换到login/2 就走了beforeRouteUpdate</p><p>beforeRouteLeave</p><p>写了的话 一定要处理好调用next()的条件和逻辑!! 否则无法正常执行</p><p>不写的话 相当于默认都无条件调了next() 没有特殊判断逻辑</p><h6 id="路由监听"><a href="#路由监听" class="headerlink" title="路由监听"></a>路由监听</h6><p>watch: { ‘$route’(to,from){}} </p><h5 id="VueX状态管理"><a href="#VueX状态管理" class="headerlink" title="VueX状态管理"></a>VueX状态管理</h5><p>不同组件之间想共享数据方式</p><ul><li><p>把数据向上层提,提到多个组件的上层,大家都能访问</p><p>需要修改时往上汇报$emit 父亲来改,可能需要不停地向上坑爹</p></li><li><p>vuex状态管理 多个组件都需要使用的公有数据 提到仓库中</p></li></ul><p>把应用中需要公用的数据都交给一个人管理,使用时不需要层层传递,扁平化</p><p>这时不要定义data(){}</p><p>定义computed计算属性 </p><p>当仓库的数据发生改变时,该计算属性也会更新 (用data的话数据变了可能不会对应更新)</p><p>return this.$store.state.dataA</p><p>不要直接修改state中的数据,而是提供修改数据的方法放在mutations中</p><p>==💡易错点==</p><p>methods中的方法 向vuex commit时,只能有两个参数,第一个参数为vuex中的方法名,第二个参数为对象</p><p>如果有多个参数必须包含在对象中</p><p>然后vuex中的mutations的方法的参数也写成对象形式</p><p>==state==</p><p>存储原始数据的位置</p><p>==过程==</p><p>通过Vuex.Store创建一个存储数据的仓库</p><p>new Vue时配置加入store 关联起来 然后就可以通过this.$store访问仓库啦</p><p>组件就不用自己调methods了</p><p>通知仓库Store去处理就可以了</p><p>this.$store.commit(‘eventName’,payload)</p><p>或 commit({type:‘eventName’,payload})</p><p>==仓库的处理方法统一在mutations对象中== 放同步操作和不需要返回值的操作</p><p>mutation => commit</p><blockquote><p>💡注意:</p><p>mutation处理同步任务,但是但是它不会返回任何的值(即使写个return 1),其实能处理异步任务但不能返回异步结果</p></blockquote><p>修改仓库数据的方法在这儿</p><p>mutations对象的方法 第一个参数为state 然后可以改state中的数据,第二个参数为传入来的参数</p><p>第二个参数叫载荷Payload (传进来的实际参数)</p><p>==actions== 放异步操作和需要返回值的操作</p><p>action => dispatch</p><p>可接受异步任务处理,可以返回异步结果</p><p>==getter== 用于store的计算属性</p><p>存放提供派生数据 有点类似计算属性computed: 用法也类似</p><p>getters: { data(state){} }</p><p>使用: this.$store.getters.data</p><hr><p>不要data了 把需要多个地方共享的数据 放在Store对象的state中</p><p>属于单向绑定</p><blockquote><p>问题 虚拟dom</p><p>vue中的数据变了 并不会导致所有标签重新渲染 不会渲染整个dom 节省dom操作</p><p>跟数据有关的dom才会改变,其他的会继续复用 不会更改</p><p>有时候会有坑 有时不希望有这种复用性</p><p>例如</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></pre></td><td class="code"><pre><span class="line">> <span class="tag"><<span class="name">ul</span>></span></span><br><span class="line">> <span class="tag"><<span class="name">li</span> <span class="attr">v-for</span> = <span class="string">'user in users'</span>></span></span><br><span class="line">> <span class="tag"><<span class="name">input</span> <span class="attr">type</span>=<span class="string">'checkbox'</span>></span></span><br><span class="line">> <span class="tag"><<span class="name">span</span>></span>{{user.username}}<span class="tag"></<span class="name">span</span>></span></span><br><span class="line">> <span class="tag"></<span class="name">li</span>></span></span><br><span class="line">> <span class="tag"></<span class="name">ul</span>></span></span><br><span class="line">></span><br></pre></td></tr></table></figure></blockquote><blockquote><p>比如有三组数据:</p><p>随机方法改变user数组的排序,然后调用随机方法时,只有span(涉及了user数据)会重新渲染</p><p>其他dom都不会重新渲染,所以即使你给老的user1打上check,随机之后user2成了第一位,但是老user1的check并不会跟user1一起变位置,而是仍然在位置一,相当于user2前加了check</p><p>d</p><p>解决方式: 加上一个vue自带的v-bind属性 :key=‘’ </p><p>而且key不能重复!!! key不能使用数组index!!! 一定要一个新增的id!!!</p><p>给user对象新加一个字段id :key=‘user.id’ 这样就会给每个user数据挂钩上了id</p><p>check就会跟随span的随机变化而一起变了 </p><p>所以经常会看到key相关的提示</p></blockquote>]]></content>
<categories>
<category> FrontEnd </category>
<category> Vue </category>
</categories>
<tags>
<tag> JavaScript </tag>
<tag> Vue </tag>
</tags>
</entry>
<entry>
<title>Vue的lifecycle</title>
<link href="/2019/01/06/Vue%E7%9A%84lifecycle/"/>
<url>/2019/01/06/Vue%E7%9A%84lifecycle/</url>
<content type="html"><![CDATA[<h5 id="Vue生命周期"><a href="#Vue生命周期" class="headerlink" title="Vue生命周期"></a>Vue生命周期</h5><p>从初始化到调用结束</p><p><img src="vuelifecycle.png" alt="vuelifecycle"></p><p>实例创建完成后立即调用created 实例已经完成以下配置:数据观测(object observer) 属性和方法计算 </p><p>created阶段时 $el还不存在</p><p>mounted阶段时 $el就有了</p><p>vm.$mount(el) 手动指定挂载对象</p><p>template指定的模板优先于el的outerHTML</p><p>如果没有template选项,会将el.outerHTML作为template (outerHTML包括自身标签 而不是只是儿子)</p><p>注💡:</p><p>模板不同于视图</p><p>模板+数据=>编译后得到视图(用户看到的)</p><p>vue实例的生命周期,vue实例本质上也是组件,根组件</p><p>组件的生命周期:</p><p>动态组件切换时 例如有ma切换到mb,mb挂载前先销毁了ma再成功挂载好mb</p><p>beforeCreate->created->beforeMount->beforeDestroy->destroyed->mounted</p><p>==keep-alive==</p><p>不会将组件反复地重新创建和销毁,而是缓存起来,切换新组件时就不会destroy老组件,切换到老组件不会重新创建和挂载</p><p>有特殊需求时可以使用</p><p>生命周期activated和deactivated 针对keep-alive而言的</p><p>当切换组件时 activated新组件 deactivated老组件</p>]]></content>
<categories>
<category> FrontEnd </category>
<category> Vue </category>
</categories>
<tags>
<tag> Vue </tag>
<tag> 生命周期 </tag>
</tags>
</entry>
<entry>
<title>Vue基础</title>
<link href="/2019/01/04/Vue%E5%9F%BA%E7%A1%80/"/>
<url>/2019/01/04/Vue%E5%9F%BA%E7%A1%80/</url>
<content type="html"><![CDATA[<h5 id="设计模式-mvvm"><a href="#设计模式-mvvm" class="headerlink" title="设计模式 mvvm"></a>设计模式 mvvm</h5><p>m: model 数据 界面中展示的或应用中使用的数据</p><p>v: view 视图 用户看到的界面</p><p>vm: view-model 中间人 处理数据与界面之间的相关逻辑(处理v和m的交互)</p><p>new Vue得到一个vue对象 后续的数据管理和视图的渲染更新这些操作都是通过这个Vue对象来完成的</p><p>初始化Vue中的属性<br>el:指定当前vue对象处理的范围,通过el指定的内容将被当前Vue对象管理,</p><p>可使用选择器指定,要在这个范围内才能管理和使用data的数据</p><p>data:存放当前Vue实例管理的应用中的所有数据</p><h5 id="模板语法"><a href="#模板语法" class="headerlink" title="模板语法"></a>模板语法</h5><p>插值语法 <code>双花括号-插值**表达式**-双花括号</code> Mustache写法双大括号</p><p>表达式:能产生结果(值)的公式 ==变量|函数调用|数学运算==等</p><p>语句: 一个行为,例如if for之类</p><p><code>双花括号-val-双花括号</code> 如果val是对象 vue会默认将val转为JSON格式</p><p>相当于<code>双花括号-JSON.stringfy(val)-双花括号</code></p><h5 id="vue指令"><a href="#vue指令" class="headerlink" title="vue指令"></a>vue指令</h5><p>指令填充的是表达式</p><p>v-开头的一种特殊属性 行间 vue内置了很多指令 我们还可以自定义指令</p><p>v-for = “(val,idx) in array”</p><p>v-show是改变display属性(存在于页面上) 需要频繁切换时使用</p><p>v-if是是否渲染元素(不满足时这个元素直接不存在)</p><blockquote><p>v-text和v-html</p></blockquote><p>v-text=”title” 这个title代表的是变量(表达式) 是data中title的值</p><p>如果想要title字符串 可以写为 v-text=“‘title’”</p><p>v-html更新元素的innerHTML 危险 容易导致xss攻击 可以识别html语法</p><p>v-html=“content” //data中content=“<code>\<strong>I am strong\</strong></code>”</p><p>v-text相当于更新元素的innerText 纯文本</p><blockquote><p>v-bind </p></blockquote><p>想把数据作为标签的某个特定属性</p><p>把表达式的值绑定到指定的参数属性中</p><p>v-bind:value=“title” //title是表达式 是data中定义的变量</p><p>==简写形式== 只有冒号 去掉v-bind</p><p>:value=“title”</p><p>当想传入一个对象而不是字符串时,用v-bind写法</p><p>:value = “{title:‘super’}”</p><p>针对class和style使用v-bind时又有特殊用法</p><p>v-bind动态改变class 使用三目运算符</p><p>或用对象写法 作用等同三目</p><p>对于class和style还有特殊待遇,可用数组形式和对象形式</p><p>v-bind:</p><p>v-bind:class=“[class1,class2,class3]”</p><p>v-bind:style=“{color:activeColor,background:bgColor}”</p><p>或“[colorObject,bgObject]” colorObject和bgObject是定义在data中的对象</p><blockquote><p>v-on</p></blockquote><p>v-on:click= 简写 @click=</p><p>vue中的click相当于js中的onclick 后面跟函数名 不带() 与原生html的onclick(带括号)区分</p><p>vue中的函数默认都指向当前vue对象</p><p>原因是在函数中用this可以很方便的去调用vue实例对象下的其他数据,例如data中的数据</p><p>data中的数据和methods中的函数,都可以通过实例对象进行直接访问</p><p>Vue在初始化时把data、methods中的属性和方法都直接挂载到了实例对象上</p><p>把data中的methods中的数据直接挂在了实例对象上</p><p>this.dataProp1(不用this.data.dataProp1)</p><p>this.methodFn1()(不用this.methods.methodFn1())</p><p>想拿到事件元素event怎么拿?通过第一个参数</p><p>methods中的方法的第一个参数就是事件对象</p><p>==特殊地==</p><p>v-on:click=“fn4()” 并不会立即调用 vue会智能地判断 还是会等到点击时才触发</p><p>如果在v-on处用了带括号的写法,必须显式地声明事件参数 否则不会获取到事件对象</p><p>v-on:click=“fn4($event)”</p><p>假设Vue对象中methods:function click(p1,p2){console.log(p1,p2)};</p><p>v-on不同写法有以下几种情况:顺序很重要</p><ul><li>v-on:click=‘click’ 这时会自动将第一个参数视为事件对象 //MouseEvent{} undefined</li><li>v-on:click=‘click(1)’ 这时就没事件对象啥事了 当做正常参数了 //1 undefined</li><li>v-on:click=‘click($event)’ 显示调事件参数 //MouseEvent{} undefined</li><li>v-on:click=‘click(1,$event) 两个参数都生效 //1 MouseEvent{}</li></ul><p>==事件修饰符== 不同指令有不同修饰符 有的指令无修饰符</p><p>@click.修饰符=“函数名” 也可以不跟函数 只是触发事件修饰符</p><p>@contextmenu.prevent 阻止右键弹出菜单的默认行为</p><p>stop 阻止冒泡 相当于stopPropagation()</p><p>capture 捕获 相当于把原生addEventListener中第三个参数设置为true 事件设为捕获</p><p>prevent 阻止默认行为</p><p>once 绑定一次</p><p>self 只有点自己才会触发 </p><p>passive(消极的) true表示永不调用preventDefault 为false即可以preventDefault</p><p>self:给父亲设置@click.self后,点击儿子是不会触发父亲方法的(没设置之前是可以触发的)</p><blockquote><p>v-model 双向绑定</p></blockquote><p>简单滴说:</p><p>双向绑定 = 单向绑定 + UI 事件监听</p><p>例子:</p><p><a href="http://js.jirengu.com/duzo/1/edit?html,console,output" target="_blank" rel="noopener">http://js.jirengu.com/duzo/1/edit?html,console,output</a></p><blockquote><p>表单💡</p></blockquote><p>数据单向绑定(v-bind) model -> view </p><p>当js中的数据变化了,视图上显示的数据也会重新渲染</p><p>数据双向绑定(v-model) model <-> view </-></p><p>当js中的数据变化,视图上的数据也会变化</p><p>当视图的数据发生变化,js中的数据也发生变化</p><p>不同的标签 v-model绑定的标签属性不一样 智能地绑</p><p>input:text v-model 绑定的是value</p><p>input:checkbox v-model 绑定的是checked</p><p>input:radio v-model 绑定的是checked</p><p>input单个checkbox v-model 绑定checked 布尔值</p><p>input多个checkbox v-model绑定数组 value出现在了数组中则被选中</p><p>input多个radio v-model绑定字符串 哪个radio被选中 就显示哪个radio的value值</p><p>select多个option v-model绑定字符串 哪个option被选中 就显示哪个option的innerText(文本内容)</p><p>.lazy修饰符 input变化时不会实时更新 而是失去焦点时再更新</p><p>.number 用户输入的值转为数值类型(原本默认为string)</p><p>.trim 去除首尾空白字符</p><h6 id="自定义指令"><a href="#自定义指令" class="headerlink" title="自定义指令"></a>自定义指令</h6><p>指令是以属性方式出现在元素上的,有特殊前缀,v-指令名称</p><p>指令时作用于 使用当前指令的元素上的 当一个元素使用某个指令以后 该指令会对当前使用它的元素产生一些特定效果 具体的效果由当前指令的具体代码去实现</p><p>Vue.directive(id,[definition]) 方法定义全局指令</p><p>id:指令名称 使用时需要带v-前缀,定义时不用带v-前缀</p><p>defnition:指令定义 具体定义、指令配置</p><p>钩子函数:指令的执行过程中不同阶段调用的不同函数</p><p>==5个钩子==: bind inserted update componentUpdated unbind</p><p><a href="https://cn.vuejs.org/v2/guide/custom-directive.html" target="_blank" rel="noopener">https://cn.vuejs.org/v2/guide/custom-directive.html</a></p><p>注意💡 bind函数只执行一次,在初始化时指令绑定到元素上的瞬间执行,即使值再改 不会重新绑定的</p><p>第一次绑定并不算update 一般大逻辑写在bind中 update改变小值</p><p>如果bind函数和update函数想共享变量 可以把变量挂载这些函数的第一个参数上(即dom元素对象)</p><p>或者通过dataset来共享数据</p><p>bind函数的第一个参数为元素 第二个参数binding为对象 里头有一些属性</p><p>根据binding来配置自定义指令的值</p><p>如果想自动重新绑定类似v-model那样 就不用bind函数钩子 用update钩子</p><p>focus不生效的原因:</p><p>focus不能放在bind和update中,要放在inserted狗子中</p><p>bind vue还没解析完</p><h5 id="data中的数据"><a href="#data中的数据" class="headerlink" title="data中的数据"></a>data中的数据</h5><p>data中一般放原始数据 </p><p>派生数据一般放 computed中 是通过计算或其他值换算来的</p><p>计算属性 会动态地受其他值影响 其他值变了 它动态地改变 很智能</p><p>==注意==</p><p>computed对象中为方法,返回计算后的结果</p><p>对应的html中<code>双花括号--双花括号</code>中的数据为方法名</p><p>html: </p><p><code>\<p>双花括号-methodA-双花括号\</p></code></p><p>js:</p><p>data:{message:‘hello’}</p><p>computed: {</p><p>methodA: return this.message.substr(1)</p><p>}</p><p>如果用v-model绑定了数据 computed方法中必须配上get()和set()</p><p>因为v-model是双向绑定 用户也可能改数据 导致computed属性发生改变</p><p>如果是v-bind就说明只是读取值 不会改值 就不用写get()和set() 默认为get()</p><p>直接return xxxxx</p><p>注💡 </p><p>一般来说 computed属性都是派生来的 由其他属性计算得来的 而不是直接手动改</p><h5 id="侦听器"><a href="#侦听器" class="headerlink" title="侦听器"></a>侦听器</h5><p>watch</p><p>监听的属性名要与data中的数据同名</p><p>watch:{</p><p> a(){ //a为data中的属性}</p><p>}</p><p>当有的数据 是异步变化而不是立即得到结果的可能要用到监听watch</p><h5 id="vue-router-前端路由"><a href="#vue-router-前端路由" class="headerlink" title="vue-router 前端路由"></a>vue-router 前端路由</h5><p>注💡 页面切换的请求千万不要让浏览器发请求(这样会让浏览器来渲染了)</p><p>要让vue来渲染</p><p>模式 url的# hash是不会导致页面刷新发请求的</p><p>单页面SPA和多页面MPA SPA通过#hash 后端通过x1.html/x2.html</p><p><a href="https://juejin.im/post/5a0ea4ec6fb9a0450407725c" target="_blank" rel="noopener">https://juejin.im/post/5a0ea4ec6fb9a0450407725c</a></p><p>历史记录方式要处理比较多情况 比如判断别人是浏览器直接打开访问的 比如 localhost/a</p><p>可能要加个header 然后判断方式不是ajax时</p><p> 可能还需要后端支持 </p><p>因为不带hash了 所以可能需要后端路由</p><p>可以局部刷新 局部渲染 用户体验比较流程</p>]]></content>
<categories>
<category> FrontEnd </category>
<category> Vue </category>
</categories>
<tags>
<tag> JavaScript </tag>
<tag> 基础 </tag>
<tag> Vue </tag>
</tags>
</entry>
<entry>
<title>MySql简单使用备注</title>
<link href="/2019/01/03/MySql%E7%AE%80%E5%8D%95%E4%BD%BF%E7%94%A8%E5%A4%87%E6%B3%A8/"/>
<url>/2019/01/03/MySql%E7%AE%80%E5%8D%95%E4%BD%BF%E7%94%A8%E5%A4%87%E6%B3%A8/</url>
<content type="html"><![CDATA[<p>安装MySQL(mac版)</p><p>两种方式</p><ul><li>官网下载community mysql server最新版dmg</li><li>使用homebrew方式安装 命令brew mysql</li></ul><p>第一种不推荐,极力推荐第二种</p><p>第一种可能导致使用mysql.preference开不起来服务器,点击无反应</p><p>第二种直接在命令行进行开启数据库服务</p><blockquote><p>mysql.server start</p></blockquote><p>关闭数据库服务</p><blockquote><p>mysql.server stop</p></blockquote><p>连接数据库</p><blockquote><p>mysql -u root -p</p><p>回车后跳过输入密码 直接连接</p><p>show databases; 可以查看所有数据库</p></blockquote><p>或者输个密码123456</p><p>可视化工具推荐Navicat for MySQL</p><p>create table notesContent(noteid int not null primary key,uid int not null,text varchar(255) not null);</p><h5 id="linux开启关闭数据库-找半天-晕"><a href="#linux开启关闭数据库-找半天-晕" class="headerlink" title="linux开启关闭数据库 找半天 晕"></a>linux开启关闭数据库 找半天 晕</h5><p>sudo apt-get install mysql-server 安装</p><p><a href="https://www.cnblogs.com/sancong/p/6280094.html" target="_blank" rel="noopener">https://www.cnblogs.com/sancong/p/6280094.html</a></p><p>mysql -u root -p</p><p>sudo service mysql start</p><p>sudo service mysql stop</p><p>sudo service mysql restart</p><h6 id="一些坑"><a href="#一些坑" class="headerlink" title="一些坑"></a>一些坑</h6><p>node index启动时报错</p><font color="dark"><strong>Client does not support authentication protocol requested by server;</strong></font><p>是数据库的问题</p><p>设置个初始密码可以搞定</p><p><a href="https://www.cnblogs.com/zichuan/p/9203129.html" target="_blank" rel="noopener">https://www.cnblogs.com/zichuan/p/9203129.html</a></p><p>sequelize库的坑</p><p>如果报Data too long for column ‘xxx’ at row 1</p><p>如果是数据库的问题,就给数据库表设置text或longtext类型而不是varchar</p><p>如果是sequelize的问题,就不要设置sequelize.STRING,而是设置sequelize.TEXT</p>]]></content>
<categories>
<category> Web </category>
<category> 数据库 </category>
</categories>
<tags>
<tag> Web </tag>
<tag> MySql </tag>
<tag> 数据库 </tag>
</tags>
</entry>
<entry>
<title>Promise手札</title>
<link href="/2019/01/02/Promise%E6%89%8B%E6%9C%AD/"/>
<url>/2019/01/02/Promise%E6%89%8B%E6%9C%AD/</url>
<content type="html"><![CDATA[<h5 id="同步异步"><a href="#同步异步" class="headerlink" title="同步异步"></a>同步异步</h5><p>script标签加载方式为同步阻塞方式,所以一般放在body最后</p><p>最新es版本 script标签增加了async属性 可设置为true 则为异步加载</p><p>createElement创建script对象加载 为异步非阻塞模式</p><h5 id="先记住写法"><a href="#先记住写法" class="headerlink" title="先记住写法"></a>先记住写法</h5><p>new Promise(function(resolve,reject){dosomething(异步代码)})</p><p>==等价于==</p><p>new Promise((resolve,reject)=>{dosomething(异步代码)})</p><p>Promise为js内置的构造函数,构造的Promise对象是==专门用于处理异步任务的管理工具==</p><blockquote><p>Promise并不是将异步变为同步</p><p>而是提供了一种异步代码的管理方式,将嵌套关系(回调地狱)变为平行关系</p></blockquote><h5 id="Promise状态"><a href="#Promise状态" class="headerlink" title="Promise状态"></a>Promise状态</h5><blockquote><p><strong>Promise的状态是不可逆的,一旦状态发生改变就永远无法还原(你手动也改不了)</strong></p></blockquote><p>Promise如何管理异步代码?</p><p>它为每一个任务都维护了一个内部状态,我们可根据异步代码的执行结果去动态改变Promise的内部状态,从而实现后续代码的调用</p><p>(是我们手动改变状态,不是Promise自己维护的,如果我们不去手动改,<strong>永远都是初始状态pending</strong>)</p><ul><li>pending - 初始状态 既非成功 也非失败 在等待</li><li>resolved - 操作成功 通过resolve(xx)方法 之后调用then方法</li><li>rejected - 操作失败 通过reject(yy)方法 之后调用catch方法</li></ul><p>resolve和reject函数调用类似事件对象event,需要传入进new Promise的参数中才可调用!</p><p>Promise的状态被修改后 就会调用后续的then、catch方法 </p><p>Promise中的异步任务什么时候 可以继续向下执行 全凭你吩咐 看你什么时候改Promise的状态</p><p>(看你什么时候调resolve或reject方法)</p><p>特殊写法:return Promise.resolve(xx) | return Promise.reject(yy)</p><p>这个写法既改变了PromiseStatus也改变了PromiseValue</p><h5 id="Promise对象的then方法"><a href="#Promise对象的then方法" class="headerlink" title="Promise对象的then方法"></a>Promise对象的then方法</h5><p>then方法可接收两个函数作为参数,第一个表示resolved,第二个表示rejected</p><p>如果只接收了一个函数 那么就是成功</p><p>then方法的参数函数只能接收一个值</p><p>let p1 = new Promise((resolve,reject)=>{dosomething;resolve();})</p><p>p1.then(()=>{},()=>{})</p><p>如果p1是resolved状态则走then方法中的第一个函数体,</p><p>如果p1是rejected状态则走then方法中的第二个函数体。</p><p>💡注:</p><p>如果在调用resolve(par1)或reject(par2)方法时传入了参数值par,par可以被传递到then方法中使用哦,par就赋给了Promise内部的PromiseValue</p><p>p1.then(par1=>{},par2=>{})par1为resolve状态的PromiseValue,par2为rejected状态的PromiseValue</p><p>==同一个Promise对象==的then方法都是同级(相当于并发或并行)的,类似addEventListener事件注册机制</p><p>p1.then(xx=>{yy1});p1.then(xx=>{yy2})</p><blockquote><p><strong>then方法也是有默认返回值的</strong></p><hr><p>p1对象的then方法返回一个新的Promise对象p2(不同于p1)</p><p><strong><em>大坑:</em></strong></p><p>一旦你调用了then或catch方法而且里头有传函数作为参数(即使函数体为空!),但你没有手动return new Promise和在里头更改status和value的话</p><p>那then或catch之后一定会给你返回这么一个Promise: <resolved>: undefined</resolved></p><p>因为then第一个参数代表resolve,而catch其实相当于then(undefined,xxx)</p><p>不信你去试试 例如p2 = p1.then(()=>{},x=>{console.log(x)})</p><p>p3=p2.catch(y=>{console.log(y)})</p><p>==小坑==</p><p>如果你在函数体结尾写了return 2;返回值并不是2,而是</p><p>Promise {<resolved>: 2} 没想到吧.</resolved></p><p>所以可以动手造一个new Promise作为返回值,在这个new Promise中根据需求手动设定状态</p><p>切记这个手动造的新Promise得传入参数resolve或reject</p></blockquote><p>then方法可以链式调用,最好每个then中都动手构造new Promise作为返回值,根据需求来改变状态,</p><p>但是最后一个then不需要手动构造了,因为后续没有要执行的代码了</p><h6 id="catch"><a href="#catch" class="headerlink" title="catch"></a>catch</h6><p>catch相当于then的一种特殊情况的一个语法糖 也是可以链式调用滴</p><p>p1.then(()=>{},x=>{y}) => p1.then(undefined,x=>{y})</p><p>=> p1.catch(x=>{y}) 都是等价的</p><p>想链式调用多个catch 中间一定要手动返回new Promise且reject(val)</p><p>p1.catch(x=>{}).catch(x=>{}).catch(x=>{});</p><h6 id="finally"><a href="#finally" class="headerlink" title="finally"></a>finally</h6><p>如果你想在 promise 执行完毕后无论其结果怎样都做一些处理或清理时,可以在链式调用末尾使用finally</p><p>p1.then().then().finally(()=>{})</p><h5 id="Promise多任务处理"><a href="#Promise多任务处理" class="headerlink" title="Promise多任务处理"></a>Promise多任务处理</h5><ul><li><p>Promise.all</p><p>当参数中所有Promise都到达了成功状态(resolved)才可以执行后续的then</p><p>一个任务依赖多个任务的处理结果时可用</p><p>let p1 = new Promise(xx;resolve(p1v)); let p2 = new Promise(yy;resolve(p2v));</p><p>Promise.all([p1,p2]).then(val=>{//拿到p1和p2结果后才执行的代码})</p><p>then中的val值为数组,数组元素为前面异步任务的值(即p1和p2 传给resolve函数的值)PromiseValue</p><p>val->[p1v,p2v]</p></li><li><p>Promise.race</p><p>当参数中的Promise但凡有一个到达了成功状态(resolved)就可以执行后续的then</p><p>一个任务依赖于多个任务中任意一个处理结果时可用</p><p>Promise.race([p1,p2]).then(v=>{})</p><p>then中的v代表的是最先完成的Promise对象的PromiseValue(p1和p2中先完成的那个传给resolve函数的值)</p></li></ul><hr><p>then中处理返回值方案选择(需不需要手动return新Promise呢?):</p><ol><li><p>then中没有异步代码|逻辑处理或不需要向下传值了,我们只需要用then默认返回的promise即可</p><p>默认返回的promise的状态继承自上个promise的状态(new Promise过来的或then过来的)</p></li><li><p>如果then中有异步代码 或者需要向下传值,我们就需要手动返回new Promise</p></li></ol><ul><li><p>如果仅仅需要传个值 简洁地用return Promise.resolve(val)或Promise.reject(val) 即可</p></li><li><p>如果除了传值可能还有更复杂的异步任务和逻辑要处理,就使用</p><p>return new Promise(resolve=>{</p><p>//dosomething;</p><p>resolve(val)</p><p>})</p></li></ul><blockquote><p>几段代码读懂promise特性 <a href="https://www.jb51.net/article/119630.htm" target="_blank" rel="noopener">https://www.jb51.net/article/119630.htm</a></p></blockquote><h6 id="💡补充知识点-js内置属性-prop-双方括号"><a href="#💡补充知识点-js内置属性-prop-双方括号" class="headerlink" title="💡补充知识点:js内置属性[[prop]] 双方括号"></a>💡补充知识点:js内置属性[[prop]] 双方括号</h6><p>[[PromiseStatus]]和[[PromiseValue]]</p><p>均为js内置属性,这种双方括号属性无法直接进行读或写操作,只能通过特定方法来进行读写操作。</p><p>特定方法来了:</p><p>Promise.resolve(1) 就相当于把promise的status设置为resolved,PromiseValue设为1</p><p>想读取PromiseValue只能 Promise.resolve(‘hello’).then(res=>{console.log(res)})</p><p>then中才可以打印出‘hello’</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></pre></td><td class="code"><pre><span class="line">(<span class="keyword">async</span> ()=>{</span><br><span class="line"> <span class="keyword">let</span> res = <span class="keyword">await</span> <span class="built_in">Promise</span>.resolve(<span class="string">'hello'</span>);</span><br><span class="line"> <span class="built_in">console</span>.log(res);</span><br><span class="line">})()</span><br><span class="line"><span class="comment">//注意console.log(res)要紧跟在await后才有效</span></span><br></pre></td></tr></table></figure><p>Promise.resolve() 则 Promise为 resolved:undefined</p><p>==注意==</p><p>var er = Promise.reject(‘err2’) 会改变PromiseStatus为rejected和PromiseValue为‘err’</p><p>但是会报错 Uncaught (in promise) err2</p><p>还是得处理下错误</p><h5 id="async和await-很甜的语法糖"><a href="#async和await-很甜的语法糖" class="headerlink" title="async和await 很甜的语法糖"></a>async和await 很甜的语法糖</h5><p>若将函数声明为async,一般没写return的函数原本默认返回undefined,加了async声明后默认返回值为Promise对象: Promise {<resolved>: undefined}</resolved></p><p>若在async函数末尾return x ,返回的仍然是Promise对象</p><p>Promise {<resolved>: x}</resolved></p><p>await后面是一个Promise对象</p><p>等待Promise的状态发生改变(且需要是resolve) 才进行后续操作 await后面的值 会被赋值给‘=’左侧的变量</p><p>await不能单独使用,需要在async函数中使用</p><p>await后的Promise对象如果reject了 那整个async函数会中断执行</p><p>若可能变为reject,需要将await所在语句放在try catch语句中</p><p>回调函数 (err,result)=>{}</p><p>换await写的话 用try catch来处理</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">f</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">await</span> <span class="built_in">Promise</span>.reject(<span class="string">'出错了'</span>);</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'上面已经出错了'</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">await</span> <span class="built_in">Promise</span>.resolve(<span class="string">'hello world'</span>);</span><br><span class="line"> } <span class="keyword">catch</span>(e) {</span><br><span class="line"> <span class="built_in">console</span>.log(e);</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>打印出‘出错了’ 后面代码不再执行;如果不适用try catch语句 会爆红错误</p><p>❌ Uncaught (in promise) 出错了</p><p>注意💡</p><p>let foo = await getFoo();</p><p>let bar = await getBar();</p><p>这种写法是会顺序执行的 bar会等foo拿到之后再拿 </p><p>(如果then是这种写法 p1.thenxxx;p1.thenyyy;则是并发执行)</p><p>这时就靠Promise.all了</p><p>let [foo, bar] = await Promise.all([getFoo(), getBar()]);</p><p>这个时候foo和bar就是会并发执行了 两个Promise包成了一个</p><p>但是会等到两个结果都拿到</p>]]></content>
<categories>
<category> FrontEnd </category>
<category> JavaScript </category>
<category> Promise </category>
</categories>
<tags>
<tag> JavaScript </tag>
<tag> Promise </tag>
</tags>
</entry>
<entry>
<title>git常用技能点</title>
<link href="/2018/12/25/git%E5%B8%B8%E7%94%A8%E6%8A%80%E8%83%BD%E7%82%B9/"/>
<url>/2018/12/25/git%E5%B8%B8%E7%94%A8%E6%8A%80%E8%83%BD%E7%82%B9/</url>
<content type="html"><![CDATA[<h5 id="给他人直接提交权限,团队写作方式"><a href="#给他人直接提交权限,团队写作方式" class="headerlink" title="给他人直接提交权限,团队写作方式"></a>给他人直接提交权限,团队写作方式</h5><p>自己的github中某个项目,Settings-Collaborators</p><p>Add collaborators的input输入框中,填入别人用户名,然后上方会多出用户</p><p>这时点击==Copy invite link==,然后发送给被邀请方</p><p>被邀请方访问这个邀请链接,然后点击按钮==Accept invitation==即可接受邀请</p><p>然后被邀请方git clone下来项目仓库,更改之后就可以直接提交commit啦</p><h5 id="git-pull相当于git-fetch和git-mergt的合集"><a href="#git-pull相当于git-fetch和git-mergt的合集" class="headerlink" title="git pull相当于git fetch和git mergt的合集"></a>git pull相当于git fetch和git mergt的合集</h5><p>相当于走了下面三步,将远程的master合并到本地master,对本地master进行了改变</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></pre></td><td class="code"><pre><span class="line">git fetch origin master</span><br><span class="line">git log -p master..origin/master</span><br><span class="line">git merge origin/master</span><br></pre></td></tr></table></figure><p>merge相当于一个新的提交记录</p><p>但是push并不等于merge,将本地master内容merge到远程origin/master上确实已经改变了远程origin/master内容,但是他们的位置还是差1,本地master[ahead1],远程origin/master[behind 1]</p><h5 id="git回滚和撤销"><a href="#git回滚和撤销" class="headerlink" title="git回滚和撤销"></a>git回滚和撤销</h5><ol><li>没add 没commit</li></ol><p>当进行一个操作,且没add时,可以用checkout . 进行撤销。可定位到当前的目录 撤销</p><p>或者指定文件 cheout filename 来撤销某个文件</p><ol><li>add了 没commit</li></ol><p>git reset head filename(可选,不写就是回滚目录所有)</p><ol><li>add了 commit了</li></ol><p>当进行一个操作,且add和commit了,可以用revert commitID 进行回滚。(commitID在log中查看)</p><p>然后需要push?</p><h5 id="branch分支相关"><a href="#branch分支相关" class="headerlink" title="branch分支相关"></a>branch分支相关</h5><p>git branch branchB 创建分支B</p><p>git checkout branchB 切换到分支branchB</p><p>或者合并为命令 git checkout -b branchB 创建并切换到分支branchB</p><p>git branch 查看所有分支,当前分支会标*号</p><p>git branch -d branchA 删除分支A</p><p>git merge branchC 合并branchC分支到当前分支 相当于git merge branchX to this</p><p>==远程分支检出(checkout)时自动进入分离HEAD状态==</p><h6 id="本地与远程master分支"><a href="#本地与远程master分支" class="headerlink" title="本地与远程master分支"></a>本地与远程master分支</h6><p>master代表本地master分支,origin/master代表远程master分支</p><p>远程master分支表示</p><p>* (HEAD detached at origin/master)</p><p> master</p><p>本地master分支表示</p><p>* master</p><p>合并之前可以先用命令 git checkout master|git checkout origin/master来切换分支查看内容</p><h5 id="冲突conflict"><a href="#冲突conflict" class="headerlink" title="冲突conflict"></a>冲突conflict</h5><p>当A和B都在修改文件,A提交后B不知道,B改了自己的也提交,这时就会出现提交失败,需要先pull。</p><p>然后B进行pull操作后,就出现了conflict冲突,然后B进行修改,把特殊符号行删除,修改成所需内容,然后再add和commit和push即可。</p><h5 id="fork-pull-request-「不加入团队协作者collaborator的协作方式,即跨团队协作」"><a href="#fork-pull-request-「不加入团队协作者collaborator的协作方式,即跨团队协作」" class="headerlink" title="fork + pull request 「不加入团队协作者collaborator的协作方式,即跨团队协作」"></a>fork + pull request 「不加入团队协作者collaborator的协作方式,即跨团队协作」</h5><p>fork成为独属自己的仓库,自己可以随意改动随意提交</p><p>add,commit,push之后,可以发起pull request</p><p>New pull request -> Create pull request</p><p>切记切记</p><p>==base fork 是自己的==</p><p>==head fork 是别人的==</p><p>更新fork仓库的方法:<a href="https://www.jianshu.com/p/8ab6ef7ce5e3" target="_blank" rel="noopener">https://www.jianshu.com/p/8ab6ef7ce5e3</a></p><p>学习video:<a href="https://www.bilibili.com/video/av24736323/?p=41" target="_blank" rel="noopener">https://www.bilibili.com/video/av24736323/?p=41</a></p><h5 id="clone和fork区别"><a href="#clone和fork区别" class="headerlink" title="clone和fork区别"></a>clone和fork区别</h5><p>clone是把远程仓库给同步到本地,会生成一个与远程同步的本地仓库 remote->local</p><p>而fork呢 是将别人的仓库复制一份作为自己的远程仓库 remote->remote,想直接操作的话要先clone到本地</p><p>即fork+clone</p><h5 id="学习视频"><a href="#学习视频" class="headerlink" title="学习视频"></a>学习视频</h5><p><a href="https://www.bilibili.com/video/av24736323" target="_blank" rel="noopener">https://www.bilibili.com/video/av24736323</a></p><p>互动学习:<a href="https://learngitbranching.js.org/" target="_blank" rel="noopener">https://learngitbranching.js.org/</a></p>]]></content>
<categories>
<category> Web </category>
<category> Git </category>
</categories>
<tags>
<tag> Git </tag>
</tags>
</entry>
<entry>
<title>关于前端模块化</title>
<link href="/2018/12/24/%E5%85%B3%E4%BA%8E%E5%89%8D%E7%AB%AF%E6%A8%A1%E5%9D%97%E5%8C%96/"/>
<url>/2018/12/24/%E5%85%B3%E4%BA%8E%E5%89%8D%E7%AB%AF%E6%A8%A1%E5%9D%97%E5%8C%96/</url>
<content type="html"><![CDATA[<h5 id="几种模块化方式"><a href="#几种模块化方式" class="headerlink" title="几种模块化方式"></a>几种模块化方式</h5><ul><li><p>CommonJS 基于js,适用于后端的模块化系统 基于文件系统的模块加载器</p><p>前端浏览器是无法操作文件系统的</p></li><li><p>适用于前端(浏览器环境)的模块化系统</p><ul><li><p>AMD异步模块定义</p></li><li><p>CMD通用模块定义</p></li><li><p>UMD统一模块定义(对AMD和UMD的统一)</p><p>再包装了一层,支持AMD|CMD|CommonJS或window</p></li></ul></li><li><p>ES6 Module</p></li></ul><p>AMD 前置依赖 </p><p>CMD 后置依赖/就近依赖</p><p>古老的加载方式 script标签 要考虑依赖顺序加载问题 如果多了 就要爆炸了</p><h6 id="AMD"><a href="#AMD" class="headerlink" title="AMD"></a>AMD</h6><p>引入RequireJS文件</p><p>script标签的data-main属性 入口文件 加载完src后 会自动加载data-main对应文件</p><p>使用define定义模块</p><p>define(function(){})或define({key:value,key2:value2})</p><p>如入口模块定义setup方法函数</p><p>某些功能模块定义可能要用到的对象(键值对)</p><p>define([文件路径1,文件路径2],function(param1,param2){})</p><p>文件路径中的函数return一个返回值x(要显式地写出return),param就代表这个返回值x</p><p>路径1return值对应param1,路径2return值对应param2</p><p>defind(function(require,export,module){})</p><p>这种方式require和export的用法基本等同于nodejs中的用法</p><p>就不在参数中写路径了 而是let xx = require(yy)</p><p>require引入 export导出</p><h5 id="UMD"><a href="#UMD" class="headerlink" title="UMD"></a><strong>UMD</strong></h5><p>本质 带参数的IIFE立即执行函数</p><p>(function(a,b){console.log(‘我立即执行’)</p><p>//多种判断 支持amd cmd commonjs等</p><p>}(this,function(){</p><p>//具体代码,例如jQ的实现 dosomething</p><p>//function \$(){};return \$;</p><p>}))</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">(function(){console.log('我立即执行')})()</span><br><span class="line">等价于</span><br><span class="line">(function(){console.log('我立即执行')}())</span><br></pre></td></tr></table></figure><h5 id="es6原生模块化"><a href="#es6原生模块化" class="headerlink" title="es6原生模块化"></a>es6原生模块化</h5><p>引入的script标签 加上type属性 type = ‘module’ 浏览器才支持 模块化</p><p>看到import和export中的{} 想到对象解构 就好理解很多了</p><p>export导出</p><ul><li><p>无值导出 (例如给window弄了个全局对象或只是操作不产生值) 即不出现export</p></li><li><p>默认导出(default) ==一个模块只能导出一个默认值== export default 10; </p><p>default也是module对象的一个属性</p><p>这时default相当于变量名字</p><p>export default obj; ✅</p><p>export obj; ❌</p></li><li><p>基于名字的导出 exports var x = 1;exports var y = 2;</p></li><li><p>导出列表</p></li></ul><p>导出多个值的方式</p><p>导出一个对象|使用命名导出|使用列表导出</p><p>import导入</p><ul><li>无值导入 import ‘./tools.js’ 导入整个文件 而不是从整个文件中取某个值</li><li>默认导入 import a from ‘./tools.js’</li><li>基于名字的导入(使用对象解构) import {x,y} from ‘./tools.js’</li></ul><p>import a,{x,y} from ‘./tools.js’ | import b,{* as tool} from ‘./tools.js’</p><p>此处的a和b就相当于default</p><p>当b模块中出现了和a模块中相同的变量名,c中想同时引入a和b的变量,变量名又冲突怎么办?</p><p>js语法是不允许量词都import同名变量的</p><p>方法: 借助as生成别名 | 借助*+as生成整个对象 然后对象.变量名使用</p><p>import a as fna from ‘./tools.js’ 以fna的名义使用tools.js中的a</p><p>==main.js==</p><p>import a from ‘./tools.js’</p><p>concols.log(a)</p><p>==tools.js==</p><p>export default 10;</p><blockquote><p>注意事项</p></blockquote><p>最好不要前后端都引用同一个js</p><p>export和module.export不要一起出现在同一文件</p><p>后端只能用module.export和require</p><p>前端能用export|import 也能用module.export require</p><p>如果有通用模块,最好前后端区分开两个文件,然后前端部分引前端的,后端部分引后端的</p>]]></content>
<categories>
<category> FrontEnd </category>
</categories>
<tags>
<tag> JavaScript </tag>
<tag> ES6 </tag>
<tag> 编程思想 </tag>
<tag> 前端模块化 </tag>
</tags>
</entry>
<entry>
<title>AJAX笔记</title>
<link href="/2018/12/23/AJAX%E7%AC%94%E8%AE%B0/"/>
<url>/2018/12/23/AJAX%E7%AC%94%E8%AE%B0/</url>
<content type="html"><![CDATA[<h5 id="发请求"><a href="#发请求" class="headerlink" title="发请求"></a>发请求</h5><p>用form表单 get或post请求</p><p>用a标签 get请求</p><ol><li><p>基于js的请求 即xhr xmlhttpserver</p><p>不会重新渲染整个页面</p></li></ol><p>通过queryString方式 既可以post也可以get</p><p>如果用正文方式 只能post</p><p>获取表单元素的小技巧:</p><p>form.username</p><p>username为表单内标签的name</p><p>获取到了name为username的input元素</p><blockquote><p>发请求的方式</p><ul><li><p>通过url (path,例如localhost/login这种)</p></li><li><p>通过url的queryString (?xxx=yyy) 受长度限制不能传大数据,只能传字符串,</p><p>有缓存/历史记录/编码urlencoded格式问题</p></li><li><p>通过请求头信息传 例如发content-type 发cookie等</p></li><li><p>通过请求正文传 不支持get 要用post</p></li></ul></blockquote><p>path和queryString都基于url,会受到url长度限制</p><p>大数据可以用正文传</p><p>==提交==</p><ol><li>使用form表单,表单中的button(需要唯一?)或input(submit)自带提交功能</li><li>不适用form表单,使用ajax提交,或者使用form表单但是给button或input(submit)取消默认行为 preventDefault</li></ol><blockquote><p>Ajax是JS提交请求而不是浏览器提交请求 不用重新渲染整个页面</p><p>即无刷新提交</p></blockquote><h5 id="代码示例-创-开-发-载"><a href="#代码示例-创-开-发-载" class="headerlink" title="代码示例 创 开 发 载"></a>代码示例 创 开 发 载</h5><p>//创建</p><p>let xhr = new XMLHttpRequest();</p><p>//发送前的准备工作,open(method,url,async) 开启</p><p>//async参数默认为true,异步的</p><p>xhr.open(‘get’,‘/checkUserName?username=’+this.value,true);</p><p>//发送请求 发送</p><p>xhr.send();</p><p>console.log(1);</p><p>如果open参数设置为同步的,后面所有事情都需要等待请求完成才会处理后面的事情</p><p>会阻塞后续所有行为,如果请求没回来 所有操作都无效</p><p>onload事件绑定发生在事件完成之后,所以 onload就不生效了,事件都结束了 over了</p><p>解决方法:将onload放到send之前,这样就先触发onload再触发,再打印1</p><p>//响应完成(即下载完成)后触发的事件 加载 </p><p>//响应完成后,服务端返回的信息会保存在xhr对象下response属性下</p><p>xhr.onload = function(){</p><p> console.log(this.response)</p><p> userNameMessageEle.innerHTML = this.response;</p><p>}</p><hr><p>一般都使用异步,</p><p>除非后续操作或行为严重依赖于ajax请求返回后的结果,才需要用同步,但是基本废弃了</p><p>参数同步和异步</p><p>两种情况:</p><ul><li><p>异步,将onload加载放在打印1之后,结果是先打印1再拿到返回结果;</p><p>将onload加载放在send之前,结果是先打印1再拿到返回结果;</p></li><li><p>同步,将onload加载放在打印1之后,就只会打印1但拿不到返回结果了,因为还没等到拿到就已经结束了 (一定避免这种情况) </p><p>它只在请求完成后触发一次,没触发就算了 不会等你了 而不是一直不停地申请触发</p><p>将onload加载放在send之前,结果是先拿到返回结果再打印1。</p></li></ul><blockquote><p>求稳妥,可以先写onload,再写send</p></blockquote><p>==注意==</p><p>提交数据方式</p><p>若通过queryString提交的数据只支持url编码字符串(urlencoded)</p><p>通过正文发送,提交的数据支持多种格式(纯文本|url编码|formData等等),需要在发送的请求头中设置提交的数据的content-type</p><p>queryString方式 open的url参数带查询参数即可,send()不用带参数,简单四步 创开发载</p><p>正文方式 </p><p>xhr.setRequestHeader(‘content-type’,‘application/x-www-form-urlencoded’)</p><p>xhr.send(‘content=’ + content.value)</p><hr><p>后端代码:</p><p>接口名为checkUserName</p><p>router.get(‘/checkUserName’,async ctx=>{</p><p> let {username} = ctx.request.query;</p><p> if(username==‘’){</p><p> ctx.body = ‘用户名不能为空’;</p><p> return;</p><p> }</p><p>let sql1 = “select * from users where username=?”</p><p>let [[user]] = await db.query(sql1,)</p><p> ctx.body = “可以注册”</p><p>})</p><p>不同提示对应前端不同颜色的文字,比如可以注册和不能注册</p><p>后端经常这么处理 返回一个约定好的数据结构json</p><p>{“code”:number}</p><p>ctx.body = {</p><p> code: 1,</p><p> message: ‘用户名不能为空’</p><p>}</p><p>ctx.body = {</p><p> code: 2,</p><p> message: ‘用户名已经被注册’</p><p>}</p><p>ctx.body = {</p><p> code: 0,</p><p> message: ‘可以注册’</p><p>}</p><p>koa框架自动会将对象转为json格式(当把对象赋给body时)</p><p>xhr.send()</p><p>get方式不支持正文提交 所以send后面不写参数</p><p>post方式支持正文提交,send后可加参数 (提交的内容)</p><p>post提交一般需要设置头信息</p><p>xhr.setRequestHeader(‘content-type’,‘application/json’)</p><p>map相当于开了个循环</p><p>keys.map((key,index)=>{</p><p> return key+‘=’+values[index]</p><p>})</p><p>==知识点==</p><p>前端处理后端传来的各种类型的数据</p><p>如果是json,需要</p><p>let data = JSON.parse(xhr.response); //转成对象格式,方便使用</p><p>如果是string,就这么用</p><p>如果是xxx</p><p>根据content-type来判断数据类型,从而使用不同处理方法,可借助MIME来处理不同类型</p><p>xhr.getAllResponseHeaders() 把整个响应头返回</p><p>xhr.getResponseHeader(‘content-type’) 返回响应头指定的某个属性</p><p>整个响应头包括:connection,content-length,content-type</p><p>urlencoded格式发data写法:</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></pre></td><td class="code"><pre><span class="line">xhr.setRequestHeader(<span class="string">'content-type'</span>, <span class="string">'application/x-www-form-urlencoded'</span>);</span><br><span class="line">xhr.send(<span class="string">'content='</span> + content.value+<span class="string">"&singerid="</span>+<span class="built_in">window</span>.location.href.split(<span class="string">'/'</span>)[<span class="number">4</span>]);</span><br></pre></td></tr></table></figure><h5 id="通识-同步-异步"><a href="#通识-同步-异步" class="headerlink" title="通识:同步 | 异步"></a>通识:同步 | 异步</h5><p>有些操作是需要花费时间去完成,比如下载电影->看电影</p><p>同步:盯着电影下载完成后 再看电影</p><p>异步:后台静默下载(同时做些其他事情),当电影下载完成后会通知下载完成了</p><p>阻塞/非阻塞 </p><p>一件事情一件事情地做,阻塞(一件事情做完后再做另外一件),非阻塞(一件事情没做完就可以做别的)</p><p>同步/异步</p><p>事情的通知方式,自己主动观察(同步) | 自动通知(异步)</p><h5 id="ajax框架"><a href="#ajax框架" class="headerlink" title="ajax框架"></a>ajax框架</h5><ul><li>jQuery</li><li>axios | 在vue中很常用</li></ul><p>自己封装一个ajax框架</p><p>let opts = Object.assign({method:‘get’,url:‘’,data:‘’})</p><h6 id="jQuery"><a href="#jQuery" class="headerlink" title="jQuery"></a>jQuery</h6><p>jq头信息默认是urlencoded,有时返回的是json,但是一看头信息还是urlencoded(不匹配)</p><p>可以用contentType字段指定发给服务器的头信息的content-type (请求头)</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><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></pre></td><td class="code"><pre><span class="line">$.ajax({</span><br><span class="line"> type: <span class="string">"GET"</span>,</span><br><span class="line"> url: <span class="string">'/checkUserName_login'</span>,</span><br><span class="line"> data: {</span><br><span class="line"> username: <span class="keyword">this</span>.value</span><br><span class="line"> },</span><br><span class="line"> <span class="comment">//url: '/checkUserName_login?username='+this.value,</span></span><br><span class="line"> contentType: <span class="string">'application/x-www-form-urlencoded; charset=UTF-8'</span>,</span><br><span class="line"> dataType: <span class="string">"text"</span>, <span class="comment">//可不写,jq根据MIME信息智能判断</span></span><br><span class="line"> success: <span class="function"><span class="keyword">function</span>(<span class="params">data,status,jqxhr</span>)</span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'data:'</span>);</span><br><span class="line"> <span class="built_in">console</span>.log(data);</span><br><span class="line"> <span class="comment">/*console.log('status:');</span></span><br><span class="line"><span class="comment"> console.log(status);</span></span><br><span class="line"><span class="comment"> console.log('xhr:');</span></span><br><span class="line"><span class="comment"> console.log(xhr);*/</span></span><br><span class="line"> }</span><br><span class="line"> })</span><br></pre></td></tr></table></figure><p><a href="https://www.jquery123.com/jQuery.ajax/" target="_blank" rel="noopener">https://www.jquery123.com/jQuery.ajax/</a></p><p>可写在对象中的属性</p><p>success的回调函数有三个参数</p><p>服务器返回的数据,状态,xhr对象</p><p>xhr对象有很多可用属性和方法,可借助这儿的参数获得</p><p>==注意点==</p><p>data为对象,内容为键值对形式</p><p>在get请求中,data将作为queryString附加到url之后(例如?username=‘superman’)</p><p>或者这种写法: url: ‘/api?username=’+this.value</p><p>data写法更好</p><p>queryString采用以下两种写法都行,jq做了智能的封装,能判断各种类型,很聪明</p><figure class="highlight plain"><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">data: 'username='+this.value,</span><br><span class="line">//对象写法或string写法都可以,因为jq做了智能的处理,支持各种格式</span><br><span class="line">data: {</span><br><span class="line"> username: this.value</span><br><span class="line">},</span><br></pre></td></tr></table></figure><h6 id="axios框架"><a href="#axios框架" class="headerlink" title="axios框架"></a>axios框架</h6><p>这个框架功能比之jQ的ajax更简单简洁 明晰 专一为ajax而生</p><p>使用说明: <a href="https://www.kancloud.cn/yunye/axios/234845" target="_blank" rel="noopener">https://www.kancloud.cn/yunye/axios/234845</a></p><p>里头借用了一个很好的框架 qs</p><p>url解析,queryString和对象互转</p><p>request header 的content-type默认为json,与jq不同</p><p>格式:</p><p>axios({</p><p> url: ‘’,</p><p> method: ‘’,</p><p> data:{</p><p> },</p><p> headers: {‘content-type’:‘application/json’}</p><p> timeout: 1000</p><p>})</p><p>这儿的data没有jQ的智能,只能适用于post|put|patch,没有jq的作为get的queryString功能</p><p>想使用get+查询参数 只能用url方式</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">url: <span class="string">'/checkUserName?username='</span>+<span class="keyword">this</span>.value,</span><br></pre></td></tr></table></figure><p>axios中想使用queryString也可以,但是不是放在data中,而是放在params字段</p><p>params: {username:‘wzc’,password:‘123’}</p><p>其实axios区分更合理,axios把正文和queryString区分开了,</p><p>分为data和params</p><p>跨域相关的配置</p><ul><li>withCredentials</li><li>proxy</li></ul>]]></content>
<categories>
<category> Web </category>
</categories>
<tags>
<tag> JavaScript </tag>
<tag> HTTP </tag>
<tag> AJAX </tag>
</tags>
</entry>
<entry>
<title>ES6务必掌握内容</title>
<link href="/2018/12/22/ES6%E5%8A%A1%E5%BF%85%E6%8E%8C%E6%8F%A1%E5%86%85%E5%AE%B9/"/>
<url>/2018/12/22/ES6%E5%8A%A1%E5%BF%85%E6%8E%8C%E6%8F%A1%E5%86%85%E5%AE%B9/</url>
<content type="html"><![CDATA[<h5 id="class类"><a href="#class类" class="headerlink" title="class类"></a>class类</h5><p>类中默认自带constructor</p><p><code>constructor</code>方法默认返回实例对象(即<code>this</code>),完全可以指定返回另外一个对象。</p><p>实例属性写法 以下两种写法等价</p><p>class A {</p><p> prop1 = 1;</p><p>constructor(){</p><p> this.prop2 = 2;</p><p>}</p><p>}</p><p>静态属性 两种写法 static目前能用不?</p><ul><li>class A{static pro = 1;} 好像用不了</li><li>类外面 A.pro = 1; 可用</li></ul><p>类的私有属性 属性前加#</p><h5 id="模板字符串"><a href="#模板字符串" class="headerlink" title="模板字符串"></a>模板字符串</h5><p>`我的天我是${god}` god为变量</p><h5 id="解构赋值"><a href="#解构赋值" class="headerlink" title="解构赋值"></a>解构赋值</h5><p>用于数组或对象,等号左边一个变量时默认取等号右边数组或对象中的第一个</p><p>var [[a]] = [[1],2] //a=1 ,等同于 写法[[a],]</p><p>var {x} = {x:1,y:2} //x=1 对象无序,不同于数组,没有占位符写法,对应上属性名即可</p><p>var [a] = [[1],2] //a=[1]</p><p>var [,a] = [[1],2] //a=2</p><p>var {,y} = {x:1,y:2} //报错</p><p>var {y} = {x:1,y:2} //y=2</p><h5 id="对象的增强"><a href="#对象的增强" class="headerlink" title="对象的增强"></a>对象的增强</h5><ul><li>对象中的属性简写</li><li>对象中的方法简写</li><li>对象属性名可使用表达式 e.g. obj[‘my’+‘name’]</li></ul><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> name = <span class="string">'miaomiao'</span></span><br><span class="line"><span class="keyword">var</span> obj = {</span><br><span class="line"> name,<span class="comment">//相当于name:name</span></span><br><span class="line"> getName(){<span class="built_in">console</span>.log(<span class="keyword">this</span>.name)}</span><br><span class="line"> <span class="comment">//相当于</span></span><br><span class="line"> <span class="comment">//getName: function(){console.log(this.name)}</span></span><br><span class="line"> <span class="comment">//或getName: function getName(){console.log(this.name)}</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><h6 id="对象展开运算符…"><a href="#对象展开运算符…" class="headerlink" title="对象展开运算符…"></a>对象展开运算符…</h6><p>…obj 相当于把obj展开 去掉花括号 => a:1,b:2</p><p>var obj = {a:1,b:2}</p><p>let a={x:1,y:2};<br>let b={z:3};<br>let ab={…a,…b};<br>ab //{x:1,y:2,z:3}</p><p>一个很容易懵的操作</p><p>…func({xxx})</p><p>func是函数名 意思是拿到func({xxx})的执行结果返回值 再用…展开!</p><p>超级详细解读:</p><p><a href="https://segmentfault.com/a/1190000016571785" target="_blank" rel="noopener">https://segmentfault.com/a/1190000016571785</a></p><h5 id="forEach循环-其实是es5的"><a href="#forEach循环-其实是es5的" class="headerlink" title="forEach循环 (其实是es5的)"></a>forEach循环 (其实是es5的)</h5><p>arr.forEach(val=>{//do something}) 循环的结果是值而非索引</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> obj = {<span class="string">'0'</span>:<span class="string">'a'</span>,<span class="string">'1'</span>:<span class="string">'b'</span>,<span class="string">'2'</span>:<span class="string">'c'</span>};</span><br><span class="line"></span><br><span class="line"><span class="built_in">Object</span>.keys(obj).forEach(<span class="function"><span class="params">key</span>=></span>{<span class="built_in">console</span>.log(key,obj[key])})</span><br></pre></td></tr></table></figure><h5 id="forEach引申出的-数组和遍历相关的方法"><a href="#forEach引申出的-数组和遍历相关的方法" class="headerlink" title="forEach引申出的 数组和遍历相关的方法"></a>forEach引申出的 数组和遍历相关的方法</h5><p>forEach map filter find findIndex</p><p>some every</p><p>==共同点==</p><p>五个方法均把函数作为参数,然后这个函数的第一个param为元素值,第二个param为元素索引</p><p>arr.method((value,index)=>{});</p><p>==差异点==</p><p>forEach无返回值 一般是根据需要进行循环操作 其他四项均有返回值</p><p>map的函数 return后的语句作为返回值塞入新结果数组中 生成新数组</p><p>filter的函数 return后的语句作为判断条件 满足条件的原数组元素 塞入新结果数组中</p><p>find的函数 return后的语句作为判断条件 满足条件的原数组第一个元素 为新返回结果</p><p>findIndex的函数 return后的语句作为判断条件 满足条件的原数组第一个元素的索引 为新返回结果</p><p>some和every return后跟的是判断条件 返回值是true或false </p><p>every需要数组每个值都满足条件</p><p>some需要数组中至少一个值满足条件</p><p><strong>举个</strong>🌰</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="keyword">var</span> arr = [<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>]</span><br><span class="line"><span class="keyword">var</span> nr1 = arr.forEach(<span class="function">(<span class="params">x,y</span>)=></span>{<span class="keyword">return</span> x+y}) <span class="comment">//nr1 = undefined</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> nr2 = arr.map(<span class="function">(<span class="params">x,y</span>)=></span>{<span class="keyword">return</span> x+y}) <span class="comment">// nr2 = [1,3,5,7,9]</span></span><br><span class="line"><span class="keyword">var</span> nr2_2 = arr.map(<span class="function">(<span class="params">x,y</span>)=></span>{<span class="keyword">return</span> x><span class="number">2</span>}) <span class="comment">//nr2_2 = [false,false,true,true,true] 把x>2的判断结果布尔值塞进了新结果数组</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> nr3 = arr.filter(<span class="function">(<span class="params">x,y</span>)=></span>{<span class="keyword">return</span> x+y}) <span class="comment">// nr3 = [1,2,3,4,5] x+y这个语句肯定是真 全都满足</span></span><br><span class="line"><span class="keyword">var</span> nr3_2 = arr.map(<span class="function">(<span class="params">x,y</span>)=></span>{<span class="keyword">return</span> x><span class="number">2</span>}) <span class="comment">// nr3_2 = [3,4,5] 只有3、4、5满足x>2为true</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> nr4 = arr.find(<span class="function">(<span class="params">x,y</span>)=></span>{<span class="keyword">return</span> x+y}) <span class="comment">//nr4 = 1 x+y这个语句肯定是真 全都满足 取第一个为1</span></span><br><span class="line"><span class="keyword">var</span> nr4_2 = arr.find(<span class="function">(<span class="params">x,y</span>)=></span>{<span class="keyword">return</span> x><span class="number">2</span>}) <span class="comment">//nr4_2 = 3 只有3、4、5满足,取第一个为3</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> nr5 = arr.findIndex(<span class="function">(<span class="params">x,y</span>)=></span>{<span class="keyword">return</span> x+y}) <span class="comment">//nr5 = 0 x+y这个语句肯定是真 全都满足 取第一个的索引</span></span><br><span class="line"><span class="keyword">var</span> nr5_2 = arr.findIndex(<span class="function">(<span class="params">x,y</span>)=></span>{<span class="keyword">return</span> x><span class="number">2</span>}) <span class="comment">//nr5_2 = 2 只有3、4、5满足,取第三个的索引</span></span><br></pre></td></tr></table></figure><h5 id="各种循环"><a href="#各种循环" class="headerlink" title="各种循环"></a>各种循环</h5><p>forEach 用于数组,不可直接用于对象/字符串</p><p>arr.forEach((value,index)=>{}) 函数中的参数第一个为值,第二个为索引</p><p>for…in… 取到的是索引 可用于数组/字符串,==可直接用于对象==</p><p>for(let index in arr){console.log(index)}</p><p>vue中的for in取到的是值</p><p>for…of… 取到的是值 可用于数组/字符串,不直接用于对象</p><p>for(let val of str){console.log(val)}</p><p>不能直接作用于对象,但是对象有返回数组的方法呀,返回key或value的数组</p><p>Object.keys(obj) | Object.values(obj)</p><p>然后再对这俩数组使用for即可</p><p>for…of… 是比较新的方法</p><h5 id="Object-assign"><a href="#Object-assign" class="headerlink" title="Object.assign"></a>Object.assign</h5><p>Object.assign(目标对象,源对象1,源对象2…)</p><p>把源对象塞进目标对象中,key不同名则添加,有同名key则覆盖,后面的覆盖前面的</p><p>有一个黑科技用法</p><p>Object.assign({},源1,源2…)</p><h5 id="find方法"><a href="#find方法" class="headerlink" title="find方法"></a>find方法</h5><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> arr = [<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>,<span class="number">6</span>,<span class="number">7</span>];</span><br><span class="line"><span class="keyword">var</span> ar = arr.find(<span class="function"><span class="keyword">function</span>(<span class="params">elem</span>)</span>{</span><br><span class="line"> <span class="keyword">return</span> elem><span class="number">5</span>;</span><br><span class="line"> });</span><br><span class="line"><span class="comment">//更优美的写法</span></span><br><span class="line"><span class="keyword">var</span> ar = arr.find(<span class="function"><span class="params">elem</span>=></span>elem><span class="number">5</span>)</span><br><span class="line"><span class="comment">//同样结果的 var ar = arr.find(elem=>elem==5)</span></span><br><span class="line"> <span class="built_in">console</span>.log(ar);<span class="comment">//6 ,注意是6 而不是true 找不到则返回undefined</span></span><br></pre></td></tr></table></figure><p>还有附送的findIndex方法 返回的第一个符合判断条件的元素的索引</p><p>注意💡</p><p>符合判断条件的第一个是从左到右开始判断 即从索引0开始</p><h5 id="伪数组改造为真数组方法"><a href="#伪数组改造为真数组方法" class="headerlink" title="伪数组改造为真数组方法"></a>伪数组改造为真数组方法</h5><p>很多js获取到的内容为伪数组,例如arguments、HTMLCollection、NodeList等</p><p>Array.prototype.slice.call(arguments|HTMLCollection|NodeList)返回一个真数组</p><p>即可改造成功,相当于获取到伪数组中所有带数字索引的项 </p><p>相当于xxxxx.slice.call(arg,0)</p><p>更绝的方法:</p><p>var arr = […NodeList|HTMLCollection|arguments] 可以试试 记得加[]</p><p>或var arr = Array.from(arguments)</p><h5 id="import和export"><a href="#import和export" class="headerlink" title="import和export"></a>import和export</h5><p>import {A} from ‘./xxx’</p><p>import C from ‘./yyy’</p><p>export {A,B} 或 export default C</p><h5 id="箭头函数"><a href="#箭头函数" class="headerlink" title="箭头函数"></a>箭头函数</h5><p>是匿名的</p><p>一个参数,有返回值时的简写</p><p>name=>result</p><p><strong>注意💡</strong></p><p>返回值为对象时,如果不写return,要加个小括号以区分</p><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></pre></td><td class="code"><pre><span class="line">name => ( { <span class="string">'user'</span> : name } );</span><br><span class="line">name => {<span class="keyword">return</span> { <span class="string">'user'</span> : name } };</span><br></pre></td></tr></table></figure><p>对象中定义方法</p><p>data(){return {user:name}}</p><p>data: ()=>({user:name})</p><p>data: ()=>{return {user:name}}</p><p>==这几种写法是一样的==</p><h5 id="set-键不重复"><a href="#set-键不重复" class="headerlink" title="set 键不重复"></a>set 键不重复</h5><p>超速去重</p><p>let newArr = Array.from(new Set(oldArr));</p><p>Set构造函数返回一个对象,且key不重复</p><p>Array.from将类数组对象、可迭代对象转为数组</p><h5 id="Array-of"><a href="#Array-of" class="headerlink" title="Array.of"></a>Array.of</h5><p>以前有个坑</p><p>var arr = new Array(4) | 与 Array(4) 含义一模一样</p><p>讲道理 应该生成[4],结果生成[empty✖️4]</p><p>所以多了Array.of</p><p>var arr = Array.of(4) //终于生成 [4]了</p><p>此处不能用new 因为Array.of不是构造函数</p>]]></content>
<categories>
<category> FrontEnd </category>
<category> JavaScript </category>
</categories>
<tags>
<tag> JavaScript </tag>
<tag> ES6 </tag>
</tags>
</entry>
<entry>
<title>网络请求相关知识点</title>
<link href="/2018/12/18/%E7%BD%91%E7%BB%9C%E8%AF%B7%E6%B1%82%E7%9B%B8%E5%85%B3%E7%9F%A5%E8%AF%86%E7%82%B9/"/>
<url>/2018/12/18/%E7%BD%91%E7%BB%9C%E8%AF%B7%E6%B1%82%E7%9B%B8%E5%85%B3%E7%9F%A5%E8%AF%86%E7%82%B9/</url>
<content type="html"><![CDATA[<h5 id="不刷新的请求方式"><a href="#不刷新的请求方式" class="headerlink" title="不刷新的请求方式"></a>不刷新的请求方式</h5><ul><li>SRJ 无刷新局部更新页面 server render javascript</li><li>大名鼎鼎的AJAX</li><li>iframe 在iframe里刷新 不影响当前页面</li><li>image也可以发请求 只能发get请求 不需要刻意将image appendChild到body中</li><li>script可以发请求 只能发get请求 一定要 appendChild到body中</li></ul><p>黑科技 iframe|script|image发请求 <a href="https://xiedaimala.com/tasks/d282131e-2ef0-4789-88d7-bba63496876b/video_tutorials/ca0b38c7-41fd-46a9-9780-be6067272e6e" target="_blank" rel="noopener">https://xiedaimala.com/tasks/d282131e-2ef0-4789-88d7-bba63496876b/video_tutorials/ca0b38c7-41fd-46a9-9780-be6067272e6e</a></p><h5 id="发请求"><a href="#发请求" class="headerlink" title="发请求"></a>发请求</h5><p>form发请求 会刷新或新开页面</p><p>a发get请求 会刷新或新开页面</p><p>img发get请求 只能以图片形式展示</p><p>link发get请求 只能以css、favicon形式展示</p><p>script发get请求 只能以脚本形式运行</p><blockquote><p>iframe代码示例</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></pre></td><td class="code"><pre><span class="line">> <span class="tag"><<span class="name">form</span> <span class="attr">action</span>=<span class="string">"/pay"</span> <span class="attr">method</span>=<span class="string">"post"</span> <span class="attr">target</span>=<span class="string">"result"</span>></span></span><br><span class="line">> <span class="tag"><<span class="name">input</span> <span class="attr">type</span>=<span class="string">"submit"</span> <span class="attr">value</span>=<span class="string">"付款"</span>></span></span><br><span class="line">> <span class="tag"></<span class="name">form</span>></span></span><br><span class="line">> <span class="tag"><<span class="name">iframe</span> <span class="attr">src</span>=<span class="string">"about:blank"</span> <span class="attr">name</span>=<span class="string">"result"</span> <span class="attr">frameborder</span>=<span class="string">"0"</span> <span class="attr">height</span>=<span class="string">"100"</span>></span><span class="tag"></<span class="name">iframe</span>></span></span><br><span class="line">></span><br></pre></td></tr></table></figure></blockquote><blockquote><p>这时是在iframe中刷新,不会影响原页面体验</p></blockquote><blockquote><p>image发请求</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="keyword">let</span> image = <span class="built_in">document</span>.createElement(<span class="string">'img'</span>)</span><br><span class="line">> image.src = <span class="string">'/pay'</span></span><br><span class="line">> image.onload = <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{<span class="comment">//请求成功}</span></span><br><span class="line">> image.onerror=<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{<span class="comment">//请求失败}</span></span><br><span class="line">></span><br></pre></td></tr></table></figure></blockquote><blockquote><p>//请求用状态码 response.statusCode来判断 2开头成功 4开头失败</p><p>//浏览器比较聪明 只是设置200状态码还不认为成功</p><p>必须response.write(fs.readFileSync(‘./真图.jpg’)) </p><p>Content-Type设为image/jpg 才可以onload成功</p></blockquote><blockquote><p>script发请求</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></pre></td><td class="code"><pre><span class="line">> <span class="keyword">let</span> script = <span class="built_in">document</span>.createElement(<span class="string">'script'</span>)</span><br><span class="line">> script.src = <span class="string">'/pay'</span></span><br><span class="line">> script.onload = <span class="function"><span class="keyword">function</span>(<span class="params">e</span>)</span>{e.currentTarget.remove()<span class="comment">//请求成功}</span></span><br><span class="line">> script.onerror=<span class="function"><span class="keyword">function</span>(<span class="params">e</span>)</span>{e.currentTarget.remove()<span class="comment">//请求失败}</span></span><br><span class="line">> <span class="comment">//清除标签以免每次请求都多生成一个 浪费性能</span></span><br><span class="line">></span><br></pre></td></tr></table></figure></blockquote><blockquote><p>服务器端写</p><p>response.setHeader(‘Content-Type’,‘application/javascript’)</p><p>response.statusCode=200</p><p>response.write(‘amount.innerText-=1’)//直接写js代码传回给前端加载</p><p>这个技术SRJ 无刷新局部更新页面 server render javascript</p></blockquote><h5 id="queryString"><a href="#queryString" class="headerlink" title="queryString"></a>queryString</h5><p>查询字符串</p><p>url问号❓后的数据为queryString 查询参数</p><p>queryString内容是key=value形式组成的数据,多个key=value使用&拼接</p><p>queryString传输的内容是有限制的,会把内容转成urlencode编码进行传输</p><blockquote><p>queryString和http的请求方式没有任何关系,他只是url中的一部分!</p></blockquote><p>所以get和post都可以用queryString,post使用queryString后端也可以读到!ctx.query可以读到</p><p>任何请求都可以带queryString 查询参数</p><p>get也可以提交 不过语义化最好只是用来查询</p><h5 id="form表单"><a href="#form表单" class="headerlink" title="form表单"></a>form表单</h5><p>form action填服务器请求地址</p><p>表单会根据action、method、enctype属性拼接请求的url,同时会自动根据表单内容拼接queryString部分</p><p>queryString传输的内容有限制,会把内容转成urlencode编码格式进行传输</p><p>urlencode</p><p>url长度有限制,大的数据不推荐使用queryString来传输,较大的数据(比如几千个字符)推荐使用http正文进行传输</p><p>Koa的ctx.query可以查出queryString</p><h5 id="请求方式"><a href="#请求方式" class="headerlink" title="请求方式"></a>请求方式</h5><p>get | post | put | delete | patch | head 等</p><p>不同的请求方法有不同的传输方式和响应规则</p><blockquote><p>MDN资料:<a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Methods" target="_blank" rel="noopener">https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Methods</a></p></blockquote><blockquote><p>精华笔记:/Users/superman285/Programmer/饥人谷前端/前端学前基础/HTTP相关姿势.md</p></blockquote><p>请求:请求行 请求头 请求体</p><p>响应:状态行 响应头 响应体</p><p>head只有响应头,没有响应体</p><p>get方法:不支持正文数据传输(没有主体),应该只被用于获取数据</p><p>这个方法对服务器来说是安全的,因为不会修改服务器的数据和状态,一般为读,</p><p>但对用户来说可能不安全,查询参数可能会明文暴露密码。</p><p>get方法通过koa-router的get方法中ctx.query可以查queryString</p><p>post方法:应该被用于提交数据</p><p>提交的数据会放在正文中,正文中的数据格式依赖</p><p>post方法通过koa-router的post方法中ctx.request.body(ctx.body)可以查</p><p>需要解析正文的话要安装 koa-body-parser</p><h5 id="FormData"><a href="#FormData" class="headerlink" title="FormData"></a>FormData</h5><p>多媒体 图片音乐视频等文件的上传 使用二进制格式 使用FormData</p><p>如果有formData对象 不需要手动设置请求头的content-type</p><p>let fd = new FormData();</p><p>//fd.append(‘username’,30); 普通数据</p><p>重要💡 input.value值并不是文件二进制数据,只是路径和文件名</p><p>//fd.append(‘file1’,input.files[0]) //提交文件数据</p><p>//input为取到的input元素 当input加上行内属性multiple时 可以多选文件上传</p><p>input.files 为类数组 数字索引对应相应文件</p><p>input.files[0]才是真正要提交的文件数据</p><p>content-type: multipart/form-data</p><p>xhr的upload对象 有事件 可以监听上传相关事件 例如进度</p>]]></content>
<categories>
<category> Web </category>
</categories>
<tags>
<tag> HTTP </tag>
<tag> Web </tag>
<tag> 网络知识 </tag>
</tags>
</entry>
<entry>
<title>跨域方案浅析</title>
<link href="/2018/12/18/%E8%B7%A8%E5%9F%9F%E6%96%B9%E6%A1%88%E6%B5%85%E6%9E%90/"/>
<url>/2018/12/18/%E8%B7%A8%E5%9F%9F%E6%96%B9%E6%A1%88%E6%B5%85%E6%9E%90/</url>
<content type="html"><![CDATA[<h4 id="跨域"><a href="#跨域" class="headerlink" title="跨域"></a>跨域</h4><p>后续过来补充</p><p>http</p><p>协议域名端口</p><p>当一个源 请求另一个源的数据 请求是没问题的</p><p>但是响应以后 浏览器会做同源验证 如果浏览器发现请求的源于当前接收数据的源不一致</p><p>那浏览器就会拒绝接收数据</p><p>服务端响应头 该响应的资源是否被允许被给定的origin共享</p><p>Access-Control-Allow-Origin</p><p>服务器端设置响应头的这个字段 可以被前端某些源访问</p><p>找一个东西替代ajax发送跨域请求</p><ul><li>能发http请求</li><li>不受跨域影响</li><li>能够处理接收到的数据</li></ul><p>例如img link script</p><p>script是最优选择</p><p>script加载后 会被浏览器js引擎自动执行里头的代码 </p><p>script两种加载方式</p><ol><li>\<script src="1.js">\</script></li></ol><p>这种加载方式是同步的,加载完成才执行后面的代码</p><ol><li><p>let scriptEle = document.createElement(‘script’)</p><p>scriptEle.src = “xxx.api”</p><p>document.body.appendChild(scriptEle)</p><p>console.log(1)</p></li></ol><p>这种动态加载方式是异步的,没加载完就会执行后续代码,解决方式:加载完成后再调</p><p>scriptEle.onload = ()=>{console.log(1)}</p><h5 id="JSONP-json-with-pending"><a href="#JSONP-json-with-pending" class="headerlink" title="JSONP json with pending"></a>JSONP json with pending</h5><p>JSONP 是一种<br>【请求一段 JS 脚本,把执行这段脚本的结果当做数据】</p><p>jsonp是通过script发送的请求,只能是get,不可能带其他字段不可能带正文呀,因为script标签只有src源</p><h5 id="后端代理-这个是最强的-后端发请求-不涉及跨域问题-后端无同源策略"><a href="#后端代理-这个是最强的-后端发请求-不涉及跨域问题-后端无同源策略" class="headerlink" title="后端代理 这个是最强的 (后端发请求 不涉及跨域问题 后端无同源策略"></a>后端代理 这个是最强的 (后端发请求 不涉及跨域问题 后端无同源策略</h5><p>服务端也可以发送http请求 例如node的http模块 </p><p>const req = http.request(‘<a href="http://localhost:8080/getdata’,res=>{" target="_blank" rel="noopener">http://localhost:8080/getdata’,res=>{</a></p><p>res.on(‘data’,chunk=>{console.log(chunk)})</p><p>res.on(‘end’,chunk->{console.log(‘数据接收完成’)})</p><p>})</p><p>//发送</p><p>req.write(‘’);</p><p>req.end();</p><p>vue-proxyTable 简单配置 changeOrigin: true</p><p>最新的vue-cli3.0 配置好像是proxy而不是proxyTable?</p><h5 id="CORS"><a href="#CORS" class="headerlink" title="CORS"></a>CORS</h5><p>Cross-Origin Resource Sharing 跨来源资源共享</p><hr><p>koa使用第三方模块 koa2-cors</p><p><a href="https://www.jianshu.com/p/5b3acded5182" target="_blank" rel="noopener">https://www.jianshu.com/p/5b3acded5182</a></p><p>其实自己手动配置也可以</p>]]></content>
<categories>
<category> Web </category>
</categories>
<tags>
<tag> 跨域 </tag>
</tags>
</entry>
<entry>
<title>浏览器存储方式</title>
<link href="/2018/12/17/%E6%B5%8F%E8%A7%88%E5%99%A8%E5%AD%98%E5%82%A8%E6%96%B9%E5%BC%8F/"/>
<url>/2018/12/17/%E6%B5%8F%E8%A7%88%E5%99%A8%E5%AD%98%E5%82%A8%E6%96%B9%E5%BC%8F/</url>
<content type="html"><![CDATA[<h5 id="localStorage"><a href="#localStorage" class="headerlink" title="localStorage"></a>localStorage</h5><ul><li><p>(同域)同源策略限制</p><p>请求与相应的协议、域名、端口都相同 </p><p>不同的域存储的内容不能互相访问(例如存在qq.com的不能访问存在baidu.com的)</p></li></ul><ul><li><p>存储的内容都是字符串格式,</p><p>注意对象转字符串时可能会变object Object,所以要借助JSON.stringfy和parse方法,数组为了安全也借助JSON的方法。</p></li><li><p>有一个全局事件,storage事件,当storage数据发生改变的时候(增删改等)就会触发</p><p>当前页面触发的storage事件只能由其他页面监听</p><p>当前页面自己对storage进行操作不会触发storage事件,是一种广播特性事件</p><p>用于实现页面间的一些通信或交互效果</p><p>要通过window.addEventListener(‘storage’,()=>{})调用</p><p>💡 注意这个事件可能不支持本地file协议,可能要用服务器环境才行</p></li></ul><ul><li>生命周期:存储的数据永久存在(其实在硬盘里),刷新页面并不会丢失,除非你强制删除他们</li></ul><h5 id="sessionStorage"><a href="#sessionStorage" class="headerlink" title="sessionStorage"></a>sessionStorage</h5><p>除了生命周期以外,其他特性和使用方法一致</p><p>==sessionStorage和localStorage区别==</p><ul><li>同源访问区别</li></ul><p>localStorage同一个域下多个页面文件可互通(e.g baidu.com/a.html和baidu.com/b.html),但是sessionStorage同一个域下多个页面文件不可互通(localhost/a.html和localhost/b.html不可互通)</p><ul><li>storage事件区别</li></ul><p>sessionStorage不支持storage事件</p><ul><li>生命周期区别</li></ul><p>localStorage永久保存,sessionStorage临时保存(浏览器关闭或者页签关闭又再开后就没掉了)</p><h5 id="cookie"><a href="#cookie" class="headerlink" title="cookie"></a>cookie</h5><p>cookie和storage==最大最大的区别==: cookie用于前后端交互,storage更多地用作纯前端存储 cookie用于用户状态存储</p><p>cookie会主动在http请求中进行传输(自动) 这是<strong>特性</strong></p><p>服务器端可以把一些非正文数据通过头信息中的cookie字段传给客户端(浏览器)</p><p>浏览器每次发送请求时会主动把请求相同域下的cookie数据通过头信息发给服务器</p><p>storage也可以在http请求中传输,但是需要手动传给服务器</p><p>cookie使用场景: 用户的登录状态</p><p>http协议的特点:无状态协议,多次请求之间不会有任何关联,即每次请求都是独立的</p><p>对服务器来说,第二次请求并不知道你第一次请求过啥,并不知道客户端干过啥</p><p>举个🌰 </p><p>/login - 服务器验证通过了</p><p>/ 再次发请求 服务器并不认为你已经登录过</p><p>用户登录系统,其实就是希望在多次服务器请求之间能共享一种状态(登录成功的数据)(就像前端的localStorage那样共享)</p><p>服务器验证通过后,需要保存当前登录的该用户的状态数据,这个数据不能只保存在服务器</p><p>我们需要把这样的凭证信息保存到当前发请求的客户端上,这个数据很多时候都不在正文(body)里,我们会把这个数据通过头信息发给客户端(而不是body) -> Set-Cookie (服务器给客户端)</p><p>当浏览器从头信息中获取到Set-Cookie时就会主动存储在浏览器cookie中,以后的同域请求也会主动把cookie中的数据通过头信息发送给服务器 ->cookie (客户端给服务器)</p><p>通常会把比较敏感的数据cookie(例如密码和一些用户资料等)进行加密,和设置当前cookie的http-only属性为true,表示这个cookie只能用于http传输,不能通过js更改(浏览器中可以直接改)</p><p>一级域名指一个点,二级域名二个点,三级域名三个点</p><p>baidu.com 一级域名</p><p><a href="http://www.baidu.com" target="_blank" rel="noopener">www.baidu.com</a> 二级域名</p><p>a.super.baidu.com 三级域名</p><h6 id="cookie配置项"><a href="#cookie配置项" class="headerlink" title="cookie配置项"></a>cookie配置项</h6><p>==path==</p><p>cookie可以设置域,cookie除了按照域名进行存储外(如baidu.com和qq.com),还可以按路径进行存储(如baidu.com/a ),子域即斜线后带东西</p><p>子域(路径)的访问类似js作用域,比如cookieA设定了baidu.com/a,那么baidu.com访问不到,baidu.com/a才访问得到;cookieB设定了baidu.com,那么baidu.com和baidu.com/a都可以访问到。</p><p>==expires/max-age==</p><p>expires设置cookie到期时间 值为Date对象格式</p><p>max-age设置cookie有效期,值为number单位秒</p><p>expires过时了,现在推荐使用max-age</p><p>ctx.cookies.set(‘username’,‘myname’,{</p><p> domain: “baidu.com”,</p><p> path: ‘/a’,</p><p> maxAge: 3600,</p><p> httpOnly: false</p><p>})</p><p>==httpOnly==</p><p>默认为true,无法通过js去操作cookies,只有浏览器自己可以操作cookies</p><p>cookie的格式 不太方便使用 可以借助别人的插件或者自己封装下格式和方法</p><p>==cookie的删除==</p><p>前端没有直接删除方法,将max-age设置为0或-1</p><p>后端koa可以 ctx.cookies.set(‘usname’,null)</p><p>a链接无法发出post请求,需要表单form</p><p>a链接可以发get请求</p>]]></content>
<categories>
<category> FrontEnd </category>
</categories>
<tags>
<tag> JavaScript </tag>
<tag> 浏览器相关 </tag>
</tags>
</entry>
<entry>
<title>正则表达式必备</title>
<link href="/2018/12/16/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%BF%85%E5%A4%87/"/>
<url>/2018/12/16/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%BF%85%E5%A4%87/</url>
<content type="html"><![CDATA[<h5 id="正则表达式-规则表达式-regular-expression-简称RegExp"><a href="#正则表达式-规则表达式-regular-expression-简称RegExp" class="headerlink" title="正则表达式(规则表达式) regular expression 简称RegExp"></a>正则表达式(规则表达式) regular expression 简称RegExp</h5><p>正则字面量里头没有数字和变量的概念,/1/中的1也是字符串 [10]匹配的是1或0;[1-20]匹配的是0或1或2</p><p>定义:</p><p>一种用于描述某种字符串规则的表达式,内置提供了很多种规则,我们根据这些内置的规则进行组合</p><p>js中正则是通过一个对象来创建的。正则是基于字符的操作</p><ol><li><p>创建对象方式 new RegExp(‘’) 或new RegExp(变量)</p><p>第一个参数为字符串,内部会根据这个字符串构造出一个正则对象</p></li><li><p>字面量方式 // 不支持变量</p></li></ol><p>「字面量的意思是它平时长啥样子,你就可以用啥样子去创建它,比如数组是“[]”」</p><p>正则就是用于无法简单地用几句话(或确定的字面量)描述出来的场景,处理一些模糊(不那么精确)的需求。</p><p>普通字符</p><p>元字符(特殊字符)</p><p>模式(修饰符)</p><p>正则组成:普通字符 + 特殊字符(元字符) + 修饰符(模式)</p><h6 id="使用场景"><a href="#使用场景" class="headerlink" title="使用场景"></a>使用场景</h6><p>==字符串方法== mssr 主体为字符串,==参数可以为正则==</p><ul><li>match 匹</li><li>search 找</li><li>split 分</li><li>replace 换</li></ul><p>search 返回参数字符在字符串中首次出现位置,类似indexOf;但更牛的是参数可用正则</p><p>‘strabc’.search(/\d/)</p><p>replace 查找到的字符替换为xx,返回替换后的字符串</p><p>‘strabc’.replace(/\d/,‘*’)</p><p>替换的新内容参数可以是函数,函数的第一个参数为匹配的完整内容,第二个参数为</p><p>split 根据字符串中某个字符切开</p><p>‘2a1sdfdfs34as1’.split(/\d+/g)->[“”, “a”, “sdfdfs”, “as”, “”] 切记如果数字在开头分割后会结果会出现空字符串</p><p>match 匹配到的内容返回成一个数组</p><p>‘str2ab3c’.match(/\d/) -> </p><p>==正则对象方法== te特别地 两个</p><ul><li>test 字符串中有满足正则的内容,就返回true,否则false</li><li>exec 类似字符串的match方法接正则表达式,但和match主体、参数反过来写</li></ul><p>exec方法只会执行一次,然后下一次会继续上次的结果找(没刷新页面),即使加了g也是一次。</p><p>string的match方法不一样,他会执行多次。</p><p>💡区别:exec方法不加修饰符g影响的是lastIndex(即上次匹配后返回的下标),如果不加g,每次都是从头开始匹配,如果加了g,就从上次的位置开始匹配;用循环匹配时,必须加g呀!或者干脆不用exec还是用match吧</p><h6 id="修饰符-模式"><a href="#修饰符-模式" class="headerlink" title="修饰符(模式)"></a>修饰符(模式)</h6><p>默认情况,正则的匹配是懒惰模式,满足一次匹配后就不动了</p><p>g: 代表全局,一直匹配到匹不到了,找到所有匹配才停止。</p><p>主要用于搜索和替换,</p><p>i: 代表忽略大小写去匹配 但是打印出来不会改变大小写</p><p>m: 把str看成多行的,每一行(带\n)都会匹配,而不是只匹配最开始和最末尾</p><p>s: dotall模式,.现在也可以匹配换行符了 singleline es8</p><p>u: unicode模式,.现在可以匹配unicode字符集了</p><p>y: sticky,粘性模式:匹配正则中lastIndex属性指定位置的</p><p>字符,并且如果没有匹配也不尝试从任何后续的索引中进</p><p>行匹配。例如多次调用exec,每次从上次位置之后一个开始找,这个符合就拿出来,不符合拉倒不找了。</p><h6 id="中括号"><a href="#中括号" class="headerlink" title="中括号"></a>中括号</h6><p>中括号内的.代表是字面含义,而不是任意一个字符</p><h6 id="转义符"><a href="#转义符" class="headerlink" title="转义符"></a>转义符</h6><p>两层含义</p><ol><li>把普通字符转为有特殊含义的字符(例如字符串中的t,n等)</li><li>把有特殊含义的字符转为字面量含义(例如正则中的. ? * + 之类, - 横划线容易漏)</li></ol><h6 id="行首、行尾、换行符都是不可见-不可描述-字符"><a href="#行首、行尾、换行符都是不可见-不可描述-字符" class="headerlink" title="行首、行尾、换行符都是不可见(不可描述)字符"></a>行首、行尾、换行符都是不可见(不可描述)字符</h6><p>‘strabc’.replace(/^/,‘*’) -> 结果不是替换掉s,而是替换掉行首一个看不到的东西,*strabc</p><h6 id="零宽单词边界-b"><a href="#零宽单词边界-b" class="headerlink" title="零宽单词边界 \b"></a>零宽单词边界 \b</h6><p>对\w生效,当\w的左侧或\w的右侧不再是\w,就匹配成功</p><p>‘str(abc’.replace(/\b/,‘*’) -> ‘*str*(*abc’</p><h6 id="分组-子项-用括号"><a href="#分组-子项-用括号" class="headerlink" title="分组(子项) 用括号"></a>分组(子项) 用括号</h6><p>str.match(/(ab)(c)d/)</p><p>命名分组/(ab)(?\<name>c)d/</name></p><p>然后子项c会出现在结果数组的groups属性中,访问:result.groups.small</p><p>捕获子项 ()</p><p>非捕获子项 (?:) (只想让括号有分组提高优先级功能,不想让他被捕获到对象子项中(不出现在结果的数组中))</p><p>match和exec中使用</p><p>零宽断言/预查</p><p>断言的内容不会出现在匹配结果中(match出来结果看不到,replace时不会被替换)</p><p>==正向断言==</p><p>肯定:我断言我之后必定出现符合==条件是condShe的她==(我和她都是判断条件),但是替换的时候只替换我,不替换她。(我受伤就好,请别打扰她) me(?=condShe)</p><p>否定:我断言我之后必定出现符合==条件不是condShe的她==(我和她都是判断条件),但是替换的时候只替换我,不替换她。(我受伤就好,请别打扰她) me(?!condShe)</p><p>正向断言是跟在后面的,断言我后面会出现的 (?=) (?!)</p><p>负向断言是断言我前面会出现的 (es9新特性) (?<=) (?<!)</p><blockquote><p>捕获与零宽断言区别:</p><p>捕获:捕获的内容出现在输出结果中但不出现在子项结果(不在数组的子项)中</p><p>零宽断言:断言内容完全不会出现在匹配结果中</p></blockquote><p>反向引用</p><p>\1表示的是引用第1个子项的内容(即必须和第一个子项的内容保持一致,例如(a)\1相当于匹配aa,但出来的子项还是a)</p><p>\2表示引用第2个子项的内容</p><p>\n n为正则表达式从左开始数第n个括号</p><p>但不会影响子项个数,这个反向引用并不算作子项。</p><h6 id="量词"><a href="#量词" class="headerlink" title="量词"></a>量词</h6><p>💡 注意贪婪模式与非贪婪模式</p><p>{x}匹配x次;等价于{x-y,x}或{x,x+y}? | 贪婪模式与知足模式</p><p>+:1到多 | *:0到多 | ?:0到1</p><p>+, *, ? 自己都属于贪婪模式 (在==满足自身设定时==)尽可能多地匹配</p><ul><li><code>*?</code>: 表示某个模式出现0次到多次,匹配时采用非贪婪模式。只匹配0次(相当于不匹配)</li><li><code>+?</code>: 表示某个模式出现1次到多次,匹配时采用非贪婪模式。只匹配1次</li><li><code>??</code>: 表示某个模式出现0次到1次,匹配时采用非贪婪模式。匹配0次(相当于不匹配)</li></ul><blockquote><p>记住一句话,一个符号加上?就变成知足模式了,满足条件时尽可能少地匹配</p><p>贪婪非贪婪是match后体现在结果上,但是如果是test,不管是出现少或多次都会为true</p></blockquote><p>几个例子:</p><p>‘bbac’.match(/ba*/g)</p><p>‘baabac’.match(/ba*/g)</p><p>‘baabac’.match(/ba??/g)</p><p>‘baaaaabac’.match(/ba{3,5}?/)</p><h5 id="☠️坑点☠️"><a href="#☠️坑点☠️" class="headerlink" title="☠️坑点☠️"></a>☠️坑点☠️</h5><ol><li><p>match全局匹配g修饰会忽略子表达式的捕获项,即只返回结果,看不到子项了,也不继承lastIndex</p></li><li><p>正则的exec方法使用g修饰是有点残疾的,他忽略了g修饰符的多次匹配特性,但增加了继承上次查找位置的特性(lastIndex是下次匹配从该位置开始查找,会继承),也保留了子项的捕获</p><p>这个可用于==循环匹配(用循环让她有g的效果,记得带上g),而且可以打出子项,match打不出子项==</p></li><li><p>量词加上?(最多加1个)可以变为非贪婪模式,??代表匹配0次。</p></li><li><p>==行首和行尾其实都可以想象为一个不可见(不可描述)的字符,用\^和$去匹配他==,不要想成\^a为以a开头,不好理解。</p></li><li><p>正则字面量//中没有数字和变量的概念,都是字符串。[10]匹配1或0而不是10</p></li><li><p>匹配1个中文字符[\u4e00-\u9fa5]</p></li><li><p>[.]字符簇中的点代表的是真的点</p></li><li><p>转义符两层含义:把普通字符转为有特殊含义的字符或把有特殊含义的字符转为字面量含义。</p></li><li><p>断言的内容不会出现在匹配结果中(match出来结果看不到,replace时不会被替换)。</p></li><li><p>写匹配规则时因为一般都需要添加上行首行尾符^和$。</p></li><li><p>用new RegExp构造正则的时候()括号中不用写//字面量了,而是用引号,然后这个时候\w之类的特殊字符需要再加一个\来转义,要写为\\w,(‘\\w+’,‘i’)正确写法</p></li><li><p>\s\S或者\w\W或者\d\D什么意思?[ab]代表a或b,\s\S代表空白(换行空格tab等)或者非空白,即匹配所有字符!而且比点.还要多,点不匹配换行。\w\W|\d\D也有同样的作用。</p></li></ol><h5 id="xss-跨站脚本攻击"><a href="#xss-跨站脚本攻击" class="headerlink" title="xss: 跨站脚本攻击"></a>xss: 跨站脚本攻击</h5><p>如果不对一些数据进行过滤的话,会导致该数据被执行(如果该数据是一段可被浏览器执行的脚本)</p><p>用正则做匹配处理,处理尖括号</p><p>input.value.replace(/<|>/g,function(a){</p><p>if(a==“<”){return ‘<code>&lt;</code>’}elseif(a\==“>”){return ‘<code>&gt;</code>’}</p><p>})</p>]]></content>
<categories>
<category> FrontEnd </category>
<category> 正则表达式 </category>
</categories>
<tags>
<tag> JavaScript </tag>
<tag> 正则表达式 </tag>
</tags>
</entry>
<entry>
<title>jQuery初步</title>
<link href="/2018/12/15/jQuery%E5%88%9D%E6%AD%A5/"/>
<url>/2018/12/15/jQuery%E5%88%9D%E6%AD%A5/</url>
<content type="html"><![CDATA[<h2 id="简单嗦嗦"><a href="#简单嗦嗦" class="headerlink" title="简单嗦嗦"></a>简单嗦嗦</h2><p>jq的方法多是对集合内多元素自动循环然后 挨个执行的,很多方法都可批量操作,省得再套个for循环</p><p>jq对象:w.fn.init[x]</p><p>💡注意:jq事件的this指向的还是原生的dom元素,而不是jq包装对象,需要用jq方法的话再加个$包装下,这样用:\$(this),这样就让this外加了层jq包装,就可以用jq方法了。</p><p>jq和原生混用是没问题的,不存在冲突。</p><p>jQuery最最常用的</p><table><thead><tr><th>常用方法</th><th>作用</th></tr></thead><tbody><tr><td>on</td><td>类似原生中的addEventListener</td></tr><tr><td>(‘p’).index(‘*’)</td><td>类似原生的indexOf,p在所有元素中的索引号</td></tr><tr><td>eq(i)\</td><td>get(i)</td><td>获取索引为i的元素,eq为jq包装的,get为原生获得的</td></tr><tr><td>.click\</td><td>.hover (function(){})</td><td>点击触发事件,鼠标移入触发事件</td></tr><tr><td>text()\</td><td>html()\</td><td>val()</td><td>类原生的innerText,innerHTML,value(表单用),可get和set</td></tr><tr><td>attr(‘s1’[,‘news1’])\</td><td>prop(‘s2’)</td><td>获取或设置某标签的某属性,可以写成对象形式设置多个值<br>例如attr({“href”:“baidu.com”,“title”:“baidu”})<br>attr可用于所有属性,prop用于固有属性</td></tr><tr><td>append(ctx)\</td><td>prepend(ctx)</td><td>在元素内部的末尾/元素内部开头 插入内容</td></tr><tr><td>after(ctx)\</td><td>before(ctx)</td><td>在元素前面/元素后面 插内容 「元素外部」</td></tr><tr><td></td><td></td></tr><tr><td></td></tr></tbody></table><p>on 类似原生js的addEventListener</p><p>\$.each(arr,(index,val)=>{}) 类似forEach,jQ中第一个参数是索引第二个参数是值,原生js中反过来,第一个是值第二个是索引</p><p>jq的动画使用的是一种队列形式</p><p>jq内部会维护一个动画队列,当我们调用动画相关方法时,并非立即执行这个动画,而是会把这个方法添加到动画队列中,当队列中某个动画执行完成以后,该动画会从队列中删除,并从队列取出下一个动画。</p><p>如果写两个animate方法,相当于调用两次,串行而不是并行的</p><p>$(‘div’).animate({width:200},1000).animate({height:100},1000)</p><p>用stop方法可以停止当前正在运行的动画,不带参数的话,stop()</p><p>stop(param1,param2) 第一个参数是 是否清空动画队列(清空后所有后续动画都不再播放) 默认false</p><p>第二个参数是 是否到达动画结束状态点,填是则stop后立即到那个状态(若param1为true后续动画不再播放所以不会到后续状态) 默认true</p><p>eq(i) 代表索引 就同[i]</p><p>jq 数值可以不带单位</p><p>jq中的csshooks,jQuery对象下有一些静态属性:jQuery.cssNumber</p><p>保存了一些设置好的属性,每一个属性都是布尔值,</p><p>当jq要给元素的样式添加数字类型的值时,jq会现在jQuery.cssNumber中查找要添加的属性是否存在,如果存在而且值为true,name添加的属性处理成不带单位的数字值</p><p>为true不带单位的话会自动补单位,为false一定要带单位</p><p>也可以自定义?</p><p>$.cssHooks:当我们通过jq去给css设置属性的时候回执行的钩子函数</p><p>有点像对象的defineProperty</p><p>$.cssHooks.cssAttr = {</p><p> get(element){},</p><p> set(element,value){}</p><p>}</p><p>方便扩展,类似cssNumber,出现新属性后可针对不同浏览器进行兼容</p><p>jQuery插件写法:过程式转为对象式,写一个单独的js文件</p><p>给原型链上增加方法 jQuery.fn == jQuery.prototype == \$.fn == \$.prototype</p><p>两种扩展,一种给原型扩展,二种给jQuery类扩展(静态扩展,e.g jQuery.),</p><p>给jQuery类的原型对象上添加新方法(不直接操作原型),jq提供了专门用于扩展原型的方法,$.fn.extend</p><figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line">$.fn.extend({</span><br><span class="line">//对象中的每一项都会被添加到jquery原型上</span><br><span class="line">a(){console.log('a function')},</span><br><span class="line">b(){},</span><br><span class="line">drag(){</span><br><span class="line"> //this指向调用这个方法的jq对象,例如$('.box').drag的this就是$('.box')</span><br><span class="line"> this.on('mousedown',function(e){</span><br><span class="line"> //因为不是箭头函数,this指向当前触发mousedown的原生元素</span><br><span class="line"> let x = e.clientX - this.offsetLeft;</span><br><span class="line"> let y = e.clientY - this.offsetTop;</span><br><span class="line"> $(document).on('mousemove',event=>{</span><br><span class="line"> $(this).css({</span><br><span class="line"> left: e.clientX - x,</span><br><span class="line"> top: e.clientY - y</span><br><span class="line"> });</span><br><span class="line"> });</span><br><span class="line"> $(document).on('mouseup',event=>{</span><br><span class="line"> //off类似removeEventListener</span><br><span class="line"> $(document).off('');</span><br><span class="line"> });</span><br><span class="line"> </span><br><span class="line"> })</span><br><span class="line">}</span><br><span class="line">})</span><br></pre></td></tr></table></figure><p>$(‘.box’).drag();</p><p>静态扩展:不是在protype中扩展了,直接在jQ类上扩展</p><p>\$.extend({</p><p> qq(str){</p><p> </p><p> }</p><p>});</p><p>使用: \$.qq(‘12419312’)</p><p>==事件问题==</p><p>addEventListener原生匿名函数,无法直接removeEventListener,因为其实两个地方的代表的是两个不同的匿名函数。</p><p>jQ有个好用的东西,on 和 off</p><p>xx.on(‘click’,()=>{});</p><p>//取消所有click观察者对象数组中的函数,所有click事件都清除了!</p><p>xx.off(‘click’)</p><p>click: {</p><p>observes:[],</p><p>a:{observes:[]},</p><p>b:{observes:[]}</p><p>}</p><p>如果想只取消某一个click事件,给事件之下再加个属性</p><p>xx.on(‘click.event1’,()=>{})</p><p>xx.off(‘click.event1’) 这样就只是清除event1点击事件,不影响其他点击事件了</p>]]></content>
<categories>
<category> FrontEnd </category>
<category> jQuery </category>
</categories>
<tags>
<tag> jQuery </tag>
</tags>
</entry>
<entry>
<title>面向对象</title>
<link href="/2018/12/14/%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1/"/>
<url>/2018/12/14/%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1/</url>
<content type="html"><![CDATA[<h5 id="this指向"><a href="#this指向" class="headerlink" title="this指向"></a>this指向</h5><p>1.默认绑定规则 指向window或global</p><p>2.隐式绑定规则,谁调用 this指谁 (fn()相当于window调用;xx.fn()相当于xx调用,this指向xx)</p><p>3.显示绑定规则,call/apply |bind</p><p> 显示指定了this</p><p> call(obj,a,b) apply(obj,[a,b]) bind(this,a,b)</p><p>4.new, this指向了new出来的实例 new最大 优先级最高</p><blockquote><p>优先级: new>显示绑定>隐式绑定>默认绑定</p></blockquote><p>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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Modal</span></span>{</span><br><span class="line">render(){</span><br><span class="line"> button.onclick = <span class="keyword">this</span>.close.bind(<span class="keyword">this</span>);</span><br><span class="line">}</span><br><span class="line">close(){<span class="keyword">this</span>.xxxx.remove()<span class="comment">//关闭};</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>bind的作用是修改&绑定this指向(bind是作用于函数上的方法)。上述代码,this原本指向button,但是bind(this)中的this指的是当前上下文的this(即Modal创建的对象实例),所以this.close.bind(this)中两个this都被指向了Modal创建的对象实例。</p><h5 id="基本功"><a href="#基本功" class="headerlink" title="基本功"></a>基本功</h5><blockquote><p>某种类型的 字面量形式创建和new+构造函数创建的区别</p><p>1.字面量形式创建,出来就是那种类型;new 构造函数创建,出来时为object对象类型!</p><p>2.new方式会划出新的一片内存空间,而且因为是对象,存在堆内存中;</p><p> 字面量方式是看以前有没同样的值,有就直接引用,没有才创建(设计模式Flyweight)</p><p>但是:例如st=new String(“st”)创建出来的内容类型为object,</p><p>结果st.__proto__ === String.prototype | st.__proto__!\=\=Object.prototype</p><p>资料:参考学习</p><p><a href="https://blog.csdn.net/duansale/article/details/74951091?utm_source=blogxgwz8" target="_blank" rel="noopener">https://blog.csdn.net/duansale/article/details/74951091?utm_source=blogxgwz8</a></p><p>构造函数与字面量形式创建区别</p><p><a href="https://www.jb51.net/article/133346.htm" target="_blank" rel="noopener">https://www.jb51.net/article/133346.htm</a> 函数带new不带new</p></blockquote><p>function Person(x,y){this.x = x;this.y=y;}</p><p>var personA = Person(1,2); 这个personA相当于执行Person(x,y)后的返回值</p><p>var personB = new Person(1,2); 相当于用Person构造函数构造了一个Person类型(实际上没Person类型,而是万能的Object类型)</p><p>personB为 => Person {x: 1, y: 2} </p><h5 id="面向过程与面向对象"><a href="#面向过程与面向对象" class="headerlink" title="面向过程与面向对象"></a>面向过程与面向对象</h5><p>面向过程-考虑点:这个事情怎么?步骤如何?过程是怎么样的?</p><p>面向对象-考虑面:这个事情有什么特点?涉及哪些方面?该如何划分?</p><h5 id="面向对象特征"><a href="#面向对象特征" class="headerlink" title="面向对象特征"></a>面向对象特征</h5><ul><li>抽象-抽取事物的共性部分,是面向对象设计的一个重要步骤</li><li>封装-通过类的形式对抽象内容进行实现的过程</li><li>继承-子类可以直接使用父类的部分数据和方法,同时可以有选择地扩展</li><li>多态-同一类对象调用相同方法可表现出不同行为或不同形态</li></ul><h6 id="抽象"><a href="#抽象" class="headerlink" title="抽象"></a>抽象</h6><p>==共性==</p><ul><li>外观-属性(名词或形容词)</li><li>功能-方法(动词)</li></ul><h6 id="封装"><a href="#封装" class="headerlink" title="封装"></a>封装</h6><p>通过类型构造出来的一个具体实例</p><p>类相当于图纸,对象是图纸做出来的一个实际物件</p><h6 id="继承-一般子类不允许修改父类,-先抽象成对象A和对象B,对比对象A和对象B,他们想死的部分又可以抽象出来,成为父亲,这就是继承。"><a href="#继承-一般子类不允许修改父类,-先抽象成对象A和对象B,对比对象A和对象B,他们想死的部分又可以抽象出来,成为父亲,这就是继承。" class="headerlink" title="继承(一般子类不允许修改父类,) 先抽象成对象A和对象B,对比对象A和对象B,他们想死的部分又可以抽象出来,成为父亲,这就是继承。"></a>继承(一般子类不允许修改父类,) 先抽象成对象A和对象B,对比对象A和对象B,他们想死的部分又可以抽象出来,成为父亲,这就是继承。</h6><p>模态框</p><p>通过继承的方式得到父类的所有特性,子类可以使用父级的部分属性和方法,而且可以扩展。</p><p>extends</p><p>当一个子类重写了构造函数,name子类构造函数中必须通过super调用父类构造函数,否则报错。</p><p>如果子类没重写构造函数(不去改动constructor),则不需要调用</p><p>继承了父类特性以后,可以加上子类自己的一些逻辑(属性和方法)</p><p>super代表父类</p><p>设计模式</p><p>单例,工厂,订阅者,</p><h5 id="构造函数"><a href="#构造函数" class="headerlink" title="构造函数"></a>构造函数</h5><p>js中面向对象并不是基于类的,es6的class只是语法糖,引擎在解析的时候还是会把class解析成es6之前的构造函数。typeof一个class就可以看出来,实际上是function</p><p>class Person => function Person</p><p>class Person中的constructor函数 => 转换后的function Person</p><p>class Person{constructor(){console.log(111)}}</p><p>function Person(){console.log(111)}</p><p>以上两者是同义的</p><p>() 放在末尾为函数调用运算符</p><p>==new 一元运算符== 核心作用:实例化对象</p><p>new的运算数是一个函数</p><p>function Person()</p><p>var p1 = new Person | var p2 = new Person()</p><p>当函数没有参数时,这两种写法是一毛一样的!</p><p>构造器是用来创建对象的函数,如果一个函数返回的是对象,他就是一个构造函数。</p><p>💡</p><blockquote><p>用new+函数方式赋值给变量,会隐式返回一个对象,不需要刻意写return,</p><ul><li>如果没有return或刻意写的return不是一个对象的时候,返回一个默认对象</li><li>显式return的是一个对象的时候,返回你刻意写的return</li></ul><p>通过new执行的函数,函数内的this即执行这个函数完成后返回的对象。</p></blockquote><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> _this;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">fn</span>(<span class="params"></span>)</span>{</span><br><span class="line"><span class="built_in">console</span>.log(<span class="keyword">this</span>);</span><br><span class="line"> _this = <span class="keyword">this</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">let</span> f1 = <span class="keyword">new</span> fn()</span><br><span class="line"><span class="built_in">console</span>.log(f1==_this) <span class="comment">//这两个其实是相等的,可以试试</span></span><br></pre></td></tr></table></figure><p>==有的函数不能new,例如Symbol,无法new Symbol== 或者静态方法(直接用类型调用的,例如Object.keys)都无法new</p><h5 id="包装对象"><a href="#包装对象" class="headerlink" title="包装对象"></a>包装对象</h5><p>数据类型:基础数据类型 | 复合数据类型</p><p>对象是由其他简单数据类型综合而成的一种复合数据。</p><p>对象这样的数据才有属性和方法;虽然简单数据类型没有属性和方法,但对这些数据进行的操作是很常见的需求,例如“abc”.length</p><p>三个构造函数 Number String Boolean,通过这三个构造函数创建出来与三种简单类型数据相似的包装对象,类型为object</p><p>字面量形式创建的简单类型,为了能使它们也能通过调用属性和方法的方式来操作(像对象这样),</p><p>当我们调用一个普通数据类型的某个属性或方法时,js会根据这个普通数据所拥有的类型对实例化对应的构造函数,并以这个普通数据值作为参数,实例化一个与之对应的对象,再调用这个对象对应的属性或方法,且返回这个属性或方法的值。</p><p>str = ‘abc’</p><p>str.length => string类型 => (new String(str)).length</p><p>let str3 = “abc” | let str4 = new String(“abc”)</p><p>str3.a = 10; str4.a = 10;</p><p>打印str3.a和str4.a 结果是啥?</p><p>str3.a 根本无法添加属性,打印str3.a 其实是打印一个临时创建的对象的a (new String(str3)).a</p><p>那肯定是 嗯 你懂的</p>]]></content>
<categories>
<category> FrontEnd </category>
</categories>
<tags>
<tag> JavaScript </tag>
<tag> 编程思想 </tag>
</tags>
</entry>
<entry>
<title>原型&原型链简记</title>
<link href="/2018/12/13/%E5%8E%9F%E5%9E%8B-%E5%8E%9F%E5%9E%8B%E9%93%BE%E7%AE%80%E8%AE%B0/"/>
<url>/2018/12/13/%E5%8E%9F%E5%9E%8B-%E5%8E%9F%E5%9E%8B%E9%93%BE%E7%AE%80%E8%AE%B0/</url>
<content type="html"><![CDATA[<p>可结合另一篇”JS中的对象和原型” 一起食用</p><h5 id="proto-隐式原型-类型为function或者object"><a href="#proto-隐式原型-类型为function或者object" class="headerlink" title="__proto__ 隐式原型 类型为function或者object"></a>__proto__ 隐式原型 类型为function或者object</h5><p>构造函数的隐式原型为function,对象的隐式原型为object</p><p>==告诉你这是一个什么类型的东东,它是由什么构造出来的==</p><p>==所有函数的隐式原型都是一样的!包括构造函数非构造函数,也包括匿名函数!!有一个除外:有继承关系的,A继承自B,那A和B的隐式原型不一样!!A的隐式原型为B,B隐式原型才为那个匿名函数表示== </p><p>有继承关系的A和B(B是爸爸,A继承自B)</p><p>这时有关原型的属性 A先向B看齐,B再向Object看齐</p><p>A.prototype.__proto__ == B.prototype 「A的原型由B构造而来」</p><p>B.prototype.__proto__ == Object.prototype</p><hr><p>A.__proto__ == B</p><p>函数的隐式原型是一个匿名函数的表示</p><blockquote><p>切记💡</p><p>function(){}.__proto__ != function(){}</p></blockquote><p>Object的隐式原型是一个匿名函数表示(类型为function),而这个匿名函数的隐式原型相当于一个空对象的隐式原型(类型为对象,但这个隐式原型是非空的对象)!</p><p>Object.__proto__.__proto__==={}.__proto__</p><p>Object.__proto__.__proto__===new Object().__proto__</p><p>但是Object.__proto__并不等于{}或new Object()</p><p>一个对象被创建时,会自动为当前对象添加一个属性: __proto__</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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">fn1</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="comment">//js自己干了这个事情,给对象加上原型</span></span><br><span class="line"> <span class="comment">//this.__proto__ = fn1.prototype;</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>调用对象的属性或方法时,</p><ol><li>js会首先在该对象自身上查找是否存在改属性或方法</li><li>该对象自身不存在该属性或方法时,会自动去该对象的__proto__找,如果还没有就再往下一层的__proto__找,找到最后一层,没有就算啦。</li></ol></blockquote><p>prototype是一个对象</p><p>xiaohua.constructor 可以看出xiaohua的构造函数Cat,相当于xiaohua.__proto__.constructor</p><p>Cat.prototype.constructor == Cat</p><p>方法的原型对象的构造函数是自己,方法构造出方法的原型对象</p><p>[1,2,3].constructor => Array | [1,2,3].__proto__.constructor</p><h5 id="prototype-类型为对象"><a href="#prototype-类型为对象" class="headerlink" title="prototype 类型为对象"></a>prototype 类型为对象</h5><p>==函数的原型对象,介绍它的孩子们(实例们)是什么类型的东东,由什么构造来,即孩子们的隐式原型。==</p><p>Object === Object.prototype.constructor</p><p>改原型的时候,不要把构造函数覆盖掉了,最好不要直接把对象赋值给prototype,用assign方法更好</p><p>Object.assign(Cat.prototype,{x:10}); </p><p>Object.prototype都找不到就不用再往下看了,永远找不到了</p><p>Object.prototype.__proto__ = null 已经到空了</p><p>继承是依靠原型链来的 </p><p>Cat.prototype.__proto__ == Animal.prototype</p><p>Cat.__proto__==Animal</p><h6 id="原型链查找方法"><a href="#原型链查找方法" class="headerlink" title="原型链查找方法"></a>原型链查找方法</h6><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Animal</span></span>{eat(){<span class="built_in">console</span>.log(‘吃’);}};</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Cat</span> <span class="keyword">extends</span> <span class="title">Animal</span></span>{</span><br><span class="line"><span class="keyword">constructor</span>(name){</span><br><span class="line"><span class="keyword">super</span>();</span><br><span class="line"><span class="keyword">this</span>.name=name;</span><br><span class="line">};</span><br><span class="line">miao(){</span><br><span class="line"><span class="built_in">console</span>.log(“喵喵喵”)</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="keyword">let</span> xiaohua = <span class="keyword">new</span> Cat(“xiaohua”);</span><br><span class="line">xiaohua.eat();</span><br><span class="line">💡开始查找💡</span><br><span class="line">xiaohua.__proto__ 即 Cat.prototype</span><br><span class="line">=>Cat.prototype.__proto__ 即 Animal.prototype ( Cat.__proto__==Animal)</span><br><span class="line">=>Animal.prototype.__proto__ 即 <span class="built_in">Object</span>.prototype (Animal的prototype也是对象,肯定是由<span class="built_in">Object</span>构造)</span><br><span class="line">=><span class="built_in">Object</span>.prototype.__proto__ =>为<span class="literal">null</span> 找不到了</span><br><span class="line"></span><br><span class="line">Animal.prototype是对象,由<span class="built_in">Object</span>构造,<span class="built_in">Object</span>是最顶层的对象构造器了,再没有哪个比<span class="built_in">Object</span>更高层的对象构造器了</span><br></pre></td></tr></table></figure><h5 id="属于类的属性或方法-静态属性-静态方法"><a href="#属于类的属性或方法-静态属性-静态方法" class="headerlink" title="属于类的属性或方法 静态属性|静态方法"></a>属于类的属性或方法 静态属性|静态方法</h5><p>这些属性/方法是和prototype同级的,所以类的实例没法找到这些属性/方法</p><p>Cat.type=“猫”</p><p>let xiaohua = new Cat(‘xiaohua’);</p><p>xiaohua.type 到xiaohua.__proto__(Cat.prototype)找,找不到,因为type和prototype是同级关系。</p><h5 id="对象包装器"><a href="#对象包装器" class="headerlink" title="对象包装器"></a>对象包装器</h5><h5 id="附"><a href="#附" class="headerlink" title="附"></a>附</h5><p>class改造为原生写法</p><p>class Animal { eat(){console.log(‘吃’);}}</p><p>=>function Animal(){} Animal.prototype.eat = function(){console.log(‘吃’);}</p>]]></content>
<categories>
<category> FrontEnd </category>
<category> JavaScript </category>
</categories>
<tags>
<tag> JavaScript </tag>
<tag> 前端知识 </tag>
</tags>
</entry>
<entry>
<title>Web3库使用</title>
<link href="/2018/12/02/Web3%E5%BA%93%E4%BD%BF%E7%94%A8/"/>
<url>/2018/12/02/Web3%E5%BA%93%E4%BD%BF%E7%94%A8/</url>
<content type="html"><![CDATA[<h5 id="Web3的provider提供器"><a href="#Web3的provider提供器" class="headerlink" title="Web3的provider提供器"></a>Web3的provider提供器</h5><ul><li>HttpProvider: HTTP服务提供器已经被弃用,因为它不支持订阅。不支持subscribe?</li><li>WebsocketProvider: Websocket服务提供器是用于传统的浏览器中的标准方法。</li><li>IpcProvider: 当运行一个本地节点时,IPC服务提供器用于node.js下的DApp环境,该方法提供最安全的连接。</li></ul><p>var Web3 = require(‘web3’);</p><p>var web3 = new Web3(new Web3.providers.HttpProvider(‘<a href="http://localhost:8545’)" target="_blank" rel="noopener">http://localhost:8545’)</a>)</p><p>httpprovider更稳,错误更少</p><p>web3的public属性的状态变量 会生成getter方法</p><p>这个getter方法 的返回值一般为string格式 例如uint或address的 不过也不一定</p><p>然后web3调用合约方法 的from 的账户地址 一般为 string类型</p><p>js中拿到的地址 一般为string类型</p><h6 id="判断是否为地址类型"><a href="#判断是否为地址类型" class="headerlink" title="判断是否为地址类型"></a>判断是否为地址类型</h6><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">web3.utils.isAddress(addr)</span><br></pre></td></tr></table></figure><h6 id="判断账户类型"><a href="#判断账户类型" class="headerlink" title="判断账户类型"></a>判断账户类型</h6><p>getCode返回的是一个promise对象,需要对结果进行处理才可以</p><p>web3.eth.getCode(address [, defaultBlock][, callback])</p><p>参数:</p><ul><li><code>address</code>:String - 要读取代码的地址</li><li><code>defaultBlock</code>:Number|String - 可选,使用该参数覆盖web3.eth.defaultBlock属性值</li><li><code>callback</code>:Function - 可选的回调函数,其第一个参数为错误对象,第二个参数为结果</li></ul><p>返回值:</p><p>一个Promise对象,其解析值为指定地址处的代码字符串。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> addrCorrect = <span class="literal">false</span>;</span><br><span class="line">web3.eth.getCode(transTarget.value, <span class="function"><span class="keyword">function</span> (<span class="params">err, result</span>) </span>{</span><br><span class="line"> <span class="keyword">if</span> (!err) {</span><br><span class="line"> <span class="keyword">var</span> code = result;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"代码:"</span> + code);</span><br><span class="line"> <span class="keyword">if</span> (code != <span class="string">"0x0"</span>) {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"代码不为空"</span>);</span><br><span class="line"> <span class="built_in">console</span>.log(code);</span><br><span class="line"> addrCorrect = <span class="literal">false</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> addrCorrect = <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"错误:"</span> + err);</span><br><span class="line"> }</span><br><span class="line">}).then(判断addrCorrect然后进行后续步骤)</span><br></pre></td></tr></table></figure><h6 id="构造合约实例"><a href="#构造合约实例" class="headerlink" title="构造合约实例"></a>构造合约实例</h6><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> web3 = <span class="keyword">new</span> Web3(<span class="keyword">new</span> Web3.providers.HttpProvider(<span class="string">"http://127.0.0.1:7545"</span>));</span><br><span class="line"><span class="keyword">var</span> showhandContract = <span class="keyword">new</span> web3.eth.Contract(abi,contractAddr);</span><br></pre></td></tr></table></figure><p>调用方法使用send或call</p><p>所有view或pure方法使用call</p><p>所有非view或非pure方法使用send</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> accountInterval = setInterval(<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="comment">// 检查账户是否切换</span></span><br><span class="line"> <span class="keyword">if</span> (web3.eth.accounts[<span class="number">0</span>] !== userAccount) {</span><br><span class="line"> userAccount = web3.eth.accounts[<span class="number">0</span>];</span><br><span class="line"> <span class="comment">// 调用一些方法来更新界面</span></span><br><span class="line"> updateInterface();</span><br><span class="line"> }</span><br><span class="line">}, <span class="number">100</span>);</span><br></pre></td></tr></table></figure><h6 id="事件event相关"><a href="#事件event相关" class="headerlink" title="事件event相关"></a>事件event相关</h6><p>好资料:<a href="https://cryptozombies.io/zh/lesson/6/chapter/9" target="_blank" rel="noopener">https://cryptozombies.io/zh/lesson/6/chapter/9</a></p><p><a href="http://cw.hubwiz.com/card/c/web3.js-1.0/1/4/13/" target="_blank" rel="noopener">http://cw.hubwiz.com/card/c/web3.js-1.0/1/4/13/</a></p><p>事件的参数都是可选项</p><p>==订阅合约事件和订阅区块链上的特定事件==</p><p>💡订阅合约声明的事件(event声明 emit触发)</p><p>contractObj.events.EventA() </p><p>订阅指定的合约事件EventA(事件名为EventA)</p><p>💡订阅区块链的特定事件</p><p><a href="http://cw.hubwiz.com/card/c/web3.js-1.0/1/3/5/" target="_blank" rel="noopener">http://cw.hubwiz.com/card/c/web3.js-1.0/1/3/5/</a></p><p>web3.eth.subscribe(type,[,options][,callback])</p><p>e.g. web3.eth.subscribe(‘logs’,{address:_from})</p><p>订阅来自_from的日志</p><p>subscribe订阅类型type有:</p><ul><li>logs 订阅日志 一定一定要options,callback可选</li><li>syncing 订阅同步事件 无options,callback可选</li><li>newBlockHeaders 订阅新区块头生成事件 无options,callback可选</li><li>pendingTransactions 订阅处于pending状态的交易 无options,callback可选</li></ul><p>==indexed关键字==</p><p>如果需要筛选数据,需要添加indexed关键字</p><p>event Transfer(address indexed _from,address indexed _to);</p><p>event Test(uint indexed _num)</p><p>使用如下:</p><p>contractObj.events.Transfer({filter:{_to:userAccount}})</p><p>过滤出_to为userAccount的所有事件</p><p>contractObj.events.Test({filter:{_num:[12,13]}})</p><p>过滤出_num为12或13的所有事件</p><p>==回调函数==</p><p>contractObj.events.Test(function(err,event){</p><p>console.log(err)//第一个参数为错误</p><p>console.log(event)//第二个参数为事件对象</p><p>})</p><p>==事件触发器 on==</p><ul><li>data 接收到新事件时触发</li><li>changed 事件从区块链上移除时触发</li><li>error 发生错误时触发</li></ul><p>可链式调用</p><p>contractObj.events.EventA().on(‘data’,function(event){</p><p> console.log(event)</p><p>})</p><blockquote><p>还有一个很好用的库推荐,Ether.js 适用于钱包、交易等场景,后续会做个笔记</p></blockquote><p>Web3 签名交易要配合 EthereumJS-tx使用</p><p>推荐使用Ether.js或者truffle家的 truffle-HDWallet-Provider</p>]]></content>
<categories>
<category> BlockChain </category>
<category> Ethereum </category>
</categories>
<tags>
<tag> JavaScript </tag>
<tag> Ethereum </tag>
<tag> Web3 </tag>
</tags>
</entry>
<entry>
<title>ERC标准</title>
<link href="/2018/11/22/ERC%E6%A0%87%E5%87%86/"/>
<url>/2018/11/22/ERC%E6%A0%87%E5%87%86/</url>
<content type="html"><![CDATA[<h3 id="ERC20标准"><a href="#ERC20标准" class="headerlink" title="ERC20标准"></a>ERC20标准</h3><p>一个合约</p><p>包含6个未实现的方法(都带返回值),包含两个事件</p><p>==方法==</p><p>totalSupply 返回token总发行量</p><p>balanceOf 查看_owner的余额(不是以太余额,而是你发行token的余额)</p><p>transfer 转出value数量的token给目标to,参数没有from(from其实是调用者msg.sender)</p><p>返回值为转账成功或失败</p><p>approve (==spender==,value^1^) 调用者(msg.sender)授权一个人spender(挥霍者)可以从自己账中调用value数量的token(即代表自己去使用value数量的token)。spender可以是普通账户,也可以是智能合约。</p><p>transferFrom (from,to,value^2^) ,供==spender==调用的函数(其实代币拥有者owner也可以调用?)。spender可将from(approve时的授权方,即approve时的msg.sender,一般是部署合约者)授权的value^1^数量内的value^2^(value^2^<=value^1^)数量的token转给to;from与调用transfefFrom的msg.sender不同,from是aprrove时的msg.sender</p><p>from为token的当前所有人,</p><blockquote><p>核心围绕着spender挥霍者,挥霍者在approve被授权,在transferFrom可以调用花钱</p></blockquote><p>allowance (owner,spender) 查看owner授权给spender的剩余token数(返回uint),若授权100,spender用掉了50(把这50转走了),再查allowance就为50。owner一般为合约部署者</p><p>Transfer事件,转账的from、to和value,成功调用转账时触发该事件</p><p>Approval事件,授权时的owner(拥有者)、spender(挥霍者)和value,成功调用approve时触发该事件</p><p>看下文解释:</p><p><a href="https://www.jianshu.com/p/a5158fbfaeb9" target="_blank" rel="noopener">https://www.jianshu.com/p/a5158fbfaeb9</a></p><p><a href="https://www.wdzj.com/hjzs/ptsj/20180909/773772-1.html" target="_blank" rel="noopener">https://www.wdzj.com/hjzs/ptsj/20180909/773772-1.html</a></p><p>transfer和transferFrom和approve的返回值bool,其实在实现中只用到true,require来判条件,因为用if来判断true或false,被web3调用是无法取到返回值的(JVM可以在log看到(decoded ouput{0}),web3就无法在log看到了),用了function(err,result)的话肯定是没有err的,if判断不成立返回false并不会导致err,所以相当于判断失效了,仍然要用require,具体范本实现见下面例子。</p><p>==特别地== 如果方法是pure或view的 web3是可以取到返回值的,因为相当于从本地获取</p><p>即使用了if判断 但是result并不是返回值 而是这笔交易的相关信息,</p><p>blockHash,blockNumber,contractAddress,status,transactionHash等等信息</p><p>规范的实现erc20接口的例子:</p><p>[openzeppelin]<a href="https://github.com/OpenZeppelin/openzeppelin-solidity/blob/9b3710465583284b8c4c5d2245749246bb2e0094/contracts/token/ERC20/ERC20.sol" target="_blank" rel="noopener">https://github.com/OpenZeppelin/openzeppelin-solidity/blob/9b3710465583284b8c4c5d2245749246bb2e0094/contracts/token/ERC20/ERC20.sol</a></p><p>[consensys]<a href="https://github.com/ConsenSys/Tokens/blob/fdf687c69d998266a95f15216b1955a4965a0a6d/contracts/eip20/EIP20.sol" target="_blank" rel="noopener">https://github.com/ConsenSys/Tokens/blob/fdf687c69d998266a95f15216b1955a4965a0a6d/contracts/eip20/EIP20.sol</a></p><blockquote><p>转账</p><ul><li>判断余额符合条件</li><li>溢出检查</li><li>事件通知</li></ul></blockquote><h3 id="ERC721"><a href="#ERC721" class="headerlink" title="ERC721"></a>ERC721</h3><p>ERC721为非同质化代币,唯一(不可分割)资产</p><p>Non-Fungible Tokens”,翻译为不可互换的Token, 英文简写为”NFT”</p><p>ERC721不同于ERC20,他是接口而不是合约</p><p>erc20中的转移数量value到了erc721中,变成了tokenId(唯一标识)</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></pre></td><td class="code"><pre><span class="line">interface ERC721 {</span><br><span class="line"> <span class="comment">//查看owner拥有的token数量</span></span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">balanceOf</span>(<span class="params">address _owner</span>) <span class="title">external</span> <span class="title">view</span> <span class="title">returns</span> (<span class="params">uint256</span>);</span></span><br><span class="line"><span class="function">//返回某<span class="title">tokenId</span>对应的账户地址,一个<span class="title">tokenId</span>对应唯一资产</span></span><br><span class="line"><span class="function"> <span class="title">function</span> <span class="title">ownerOf</span>(<span class="params">uint256 _tokenId</span>) <span class="title">external</span> <span class="title">view</span> <span class="title">returns</span> (<span class="params">address</span>);</span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function"> <span class="title">function</span> <span class="title">safeTransferFrom</span>(<span class="params">address _from, address _to, uint256 _tokenId, bytes data</span>) <span class="title">external</span> <span class="title">payable</span>;</span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function"> <span class="title">function</span> <span class="title">safeTransferFrom</span>(<span class="params">address _from, address _to, uint256 _tokenId</span>) <span class="title">external</span> <span class="title">payable</span>;</span></span><br><span class="line"><span class="function">//将<span class="title">from</span>的<span class="title">tokenId</span>转移到<span class="title">to</span>,此处不是数量,而是某一个<span class="title">tokenId</span></span></span><br><span class="line"><span class="function"> <span class="title">function</span> <span class="title">transferFrom</span>(<span class="params">address _from, address _to, uint256 _tokenId</span>) <span class="title">external</span> <span class="title">payable</span>;</span></span><br><span class="line"><span class="function">//授予地址<span class="title">_approved</span>具有<span class="title">tokenId</span>的控制权</span></span><br><span class="line"><span class="function"> <span class="title">function</span> <span class="title">approve</span>(<span class="params">address _approved, uint256 _tokenId</span>) <span class="title">external</span> <span class="title">payable</span>;</span></span><br><span class="line"><span class="function">//将调用者所有资产都授权或取消授权(<span class="params">授权给</span>)</span></span><br><span class="line"><span class="function"> <span class="title">function</span> <span class="title">setApprovalForAll</span>(<span class="params">address _operator, bool _approved</span>) <span class="title">external</span>;</span></span><br><span class="line"><span class="function">//查询<span class="title">tokenId</span>授权给了谁,若无授权会返回地址0?</span></span><br><span class="line"><span class="function"> <span class="title">function</span> <span class="title">getApproved</span>(<span class="params">uint256 _tokenId</span>) <span class="title">external</span> <span class="title">view</span> <span class="title">returns</span> (<span class="params">address</span>);</span></span><br><span class="line"><span class="function">//查看<span class="title">owner</span>是否将所有资产都授权给<span class="title">operator</span></span></span><br><span class="line"><span class="function"> <span class="title">function</span> <span class="title">isApprovedForAll</span>(<span class="params">address _owner, address _operator</span>) <span class="title">external</span> <span class="title">view</span> <span class="title">returns</span> (<span class="params">bool</span>);</span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function"> <span class="title">event</span> <span class="title">Transfer</span>(<span class="params">address indexed _from, address indexed _to, uint256 indexed _tokenId</span>);</span></span><br><span class="line"><span class="function"> <span class="title">event</span> <span class="title">Approval</span>(<span class="params">address indexed _owner, address indexed _approved, uint256 indexed _tokenId</span>);</span></span><br><span class="line"><span class="function"> <span class="title">event</span> <span class="title">ApprovalForAll</span>(<span class="params">address indexed _owner, address indexed _operator, bool _approved</span>);</span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function">}</span></span><br></pre></td></tr></table></figure><p>设计数据结构时,考虑要实现的方法中传入参数、传出参数之间的关系,参数的个数,从而设计数据结构,是无映射关系呢还是一重映射关系,或是多重映射关系。</p>]]></content>
<categories>
<category> BlockChain </category>
<category> Ethereum </category>
</categories>
<tags>
<tag> Ethereum </tag>
<tag> ERC </tag>
<tag> Solidity </tag>
</tags>
</entry>
<entry>
<title>简单说说DOM和BOM</title>
<link href="/2018/11/12/%E7%AE%80%E5%8D%95%E8%AF%B4%E8%AF%B4DOM%E5%92%8CBOM/"/>
<url>/2018/11/12/%E7%AE%80%E5%8D%95%E8%AF%B4%E8%AF%B4DOM%E5%92%8CBOM/</url>
<content type="html"><![CDATA[<h3 id="DOM"><a href="#DOM" class="headerlink" title="DOM"></a>DOM</h3><p>document object model</p><p>顶层对象document</p><p>文档对象模型,结构图如下:</p><p><img src="DOMStruct.png" alt="DOM结构图"></p><p>document.documentElement 获取到整个html即root</p><font style="color:white;background:mediumseagreen;padding:3px 6px;font-weight:bold;line-height:28px">节点类型nodeType</font> 返回数字<br><br>元素节点 1 标签<br><br>属性节点 2 他们的属性<br><br>文本节点 3 他们的文本 text<br><br>注释节点 8 comment<br><br>文档节点 9 document<br><br><br><br>获取属性节点<br><br>e.g. element.getAttributeNode(“width”) 行间属性<br><br><br><br>获取文本节点<br><br>e.g. span.firshChild<br><br><br><br><font style="color:white;background:mediumseagreen;padding:3px 6px;font-weight:bold;line-height:28px">节点名称nodeName</font><p>元素节点返回大写标签名(string类型);属性节点返回属性名;文本节点返回#text</p><font style="color:white;background:mediumseagreen;padding:3px 6px;font-weight:bold;line-height:28px">节点内容nodeValue</font><p>属性节点的为属性值,文本节点的为文本内容,元素节点的为null</p><font style="color:white;background:mediumseagreen;padding:3px 6px;font-weight:bold;line-height:28px">节点关系</font><p>父子关系:上下级</p><p>兄弟关系:同级</p><p>祖先关系:当前节点上面所有节点统称</p><p>子孙关系:当前节点下面所有节点统称</p><p>想拿到所有后代用 <code>祖先</code>.getElementsByTagName(“”);</p><font style="color:white;background:mediumseagreen;padding:3px 6px;font-weight:bold;line-height:28px">定位祖先节点</font><p>element.offsetParent 距离元素最近的有定位属性的祖先节点</p><p>如果祖先都没有定位,那么会获取到body</p><font style="color:white;background:mediumseagreen;padding:3px 6px;font-weight:bold;line-height:28px">儿子节点</font><p>childNodes:获取一个元素下的所有子节点(只获取到儿子一级),包括文本节点、注释节点</p><p>children:获取一个元素下的所有==子<strong>元素节点</strong>== (只获取到儿子一级)</p><p>firstChild:获取第一个子节点(包括三种节点)</p><p>lastChild:获取最后一个子节点(包括三种节点)</p><font style="color:white;background:mediumseagreen;padding:3px 6px;font-weight:bold;line-height:28px">父亲节点</font><p>parentNode:获取一个元素的父节点</p><p>parentElement 不好用 只在ie可用</p><font style="color:white;background:mediumseagreen;padding:3px 6px;font-weight:bold;line-height:28px">兄弟节点</font><p>nextSibling:获取当前元素的下一个兄弟节点(包括元素、文本、注释节点)</p><p>nextElementSibling:获取当前元素的下一个兄弟元素节点</p><p>previousSibling:获取当前元素的上一个兄弟节点(包括元素、文本、注释节点)</p><p>previousElementSibling:获取当前元素的上一个兄弟元素节点</p><p>获取不到节点返回null</p><font style="color:white;background:mediumseagreen;padding:3px 6px;font-weight:bold;line-height:28px">创建节点</font><p>父节点.appendChild(element)</p><p>父节点.insertBefore(insertElement,beforeWhichElement) 待插入元素,要插到哪个元素之前f</p><p>若第二个参数为null(相当于父亲没有儿子),则直接插入,此时效果同appendChild</p><p>法一:</p><p>var son = document.createElement(“标签名字”)</p><p>son.innerHTML=val</p><p>father.appendChild(son)</p><p>法二:</p><p>father.innerHTML += “\<li>” + val + “\</li>”</p><blockquote><p>针对子节点ChildNode的接口 都是插入到父亲底下,和son同级</p></blockquote><p>son.before(xx) 将xx插入到son之前\<xx>\<son></son></xx></p><p>son.after(yy) 将yy插入到son之后\<son>\<yy></yy></son></p><font style="color:white;background:mediumseagreen;padding:3px 6px;font-weight:bold;line-height:28px">替换节点</font><p>father.replaceChild(newElement,oldElement) 应该先判断oldElement是否存在</p><p>son.replaceWith(newElement) | p.replaceWith(span)</p><font style="color:white;background:mediumseagreen;padding:3px 6px;font-weight:bold;line-height:28px">删除节点</font><ul><li>father.removeChild(element)</li><li>要删的元素本身.remove()</li></ul><h5 id="你可能不知道的坑💣"><a href="#你可能不知道的坑💣" class="headerlink" title="你可能不知道的坑💣"></a>你可能不知道的坑💣</h5><p>HTMLCollection <font color="dark"><strong>V.S</strong></font> NodeList</p><p>相同点: </p><ul><li><p>这两者都是伪数组,真对象</p></li><li><p>这两者都是动态的,若dom发生了变化,之前获取到的HTMLCollection或NodeList也会随之变化</p></li><li><p>两者都有item方法,可以通过索引来获取到数组中的元素,如collection.item(0)</p><p>HTMLCollection的item方法参数只能为数字,代表索引;</p><p>NodeList的item方法参数只能为数字,代表索引。</p></li></ul><p>区别:</p><ul><li><p>HTMLCollection包含的是元素节点Element,NodeList顾名思义包含的是所有类型的节点(包括文本节点|属性节点|注释节点等等)</p></li><li><p>HTMLCollection多了一个namedItem方法,参数可以为id或name(表单元素的name),若id与name同名,以id优先。</p></li><li><p>通过querySelectorAll方法返回的是NodeList 这个方法返回的内容很全</p><p>通过getElementsByXXX方法返回的是HTMLCollection 方法名都告诉你了 getElements</p><p>所以只返回元素节点</p></li></ul><font style="color:white;background:mediumseagreen;padding:3px 6px;font-weight:bold;line-height:28px">重点来了</font><p>HTMLCollection和NodeList都是动态的,具有实时性。</p><p>通过getElementsByxxx 返回的集合是动态的 实时的</p><p>But,通过querySelectorAll 返回的集合却是静态的 不具有实时性 (很特殊的一点)</p><p>举个🌰</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></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">body</span>></span></span><br><span class="line"><span class="tag"><<span class="name">div</span> <span class="attr">id</span>=<span class="string">"outer"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">p</span> <span class="attr">class</span>=<span class="string">"p"</span>></span>我是1<span class="tag"></<span class="name">p</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">p</span> <span class="attr">class</span>=<span class="string">"p"</span>></span>我是2<span class="tag"></<span class="name">p</span>></span></span><br><span class="line"><span class="tag"></<span class="name">div</span>></span></span><br><span class="line"></span><br><span class="line"><span class="tag"><<span class="name">script</span>></span><span class="undefined"></span></span><br><span class="line"><span class="javascript"> <span class="keyword">let</span> qps = <span class="built_in">document</span>.querySelectorAll(<span class="string">".p"</span>);</span></span><br><span class="line"><span class="javascript"> <span class="keyword">let</span> gps = <span class="built_in">document</span>.getElementsByClassName(<span class="string">"p"</span>);</span></span><br><span class="line"><span class="javascript"> <span class="keyword">let</span> newp = <span class="built_in">document</span>.createElement(<span class="string">"p"</span>);</span></span><br><span class="line"><span class="javascript"> newp.classList = <span class="string">'p'</span>;</span></span><br><span class="line"><span class="javascript"> newp.innerHTML = <span class="string">'我是3'</span>;</span></span><br><span class="line"><span class="undefined"> outer.appendChild(newp);</span></span><br><span class="line"><span class="javascript"> <span class="built_in">console</span>.log(qps);</span></span><br><span class="line"><span class="javascript"> <span class="built_in">console</span>.log(gps);</span></span><br><span class="line"><span class="undefined"></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></pre></td></tr></table></figure><p>qps打印出的是NodeList,里头只有<strong>2个元素</strong></p><p>gps打印出的是HTMLCollection,里头有<strong>3个元素</strong></p><blockquote><p>说明querySelector获取到的是当时的元素,后续的变化不会影响获取到的值了</p><p>而getElementsByXXX获取到的是动态的值,后续的变化实时反应影响到值,使用的时候已经不是当时获取到的值了</p></blockquote><p>所以按照需求选择方案</p><p>如果想安全点 不会受后面改变dom影响之前获取到的元素的使用的 就用querySelector</p><h3 id="BOM"><a href="#BOM" class="headerlink" title="BOM"></a>BOM</h3><p>browser object model 顶层对象是window</p><h6 id="window常用方法"><a href="#window常用方法" class="headerlink" title="window常用方法"></a>window常用方法</h6><ul><li>alert</li><li>confirm 返回值true|false</li><li>setInterval() | clearInterval()</li><li>setTimeout() | clearTimeout()</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> timerID = setTimeout(fn,<span class="number">1000</span>);</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">fn</span>(<span class="params"></span>)</span>{xxxx;clearTimeout(timerID);}</span><br></pre></td></tr></table></figure><ul><li><p>open([页面地址],[打开方式])</p><p>打开方式:_self本窗口打开 _blank新窗口打开 _parent</p><p>不写页面地址默认打开blank,不写打开方式默认是_blank</p><p>返回值:新窗口的window对象</p><p>前端会涉及跨域问题,若页面地址写一个百度的网址,是无法对百度网址的窗口对象直接进行操作的,因为跨了域。 </p></li><li><p>close() 火狐无法关闭本窗口,除非设置某个值为true(about:config dom.allow.xxx)</p></li></ul><h6 id="window下的四大金刚"><a href="#window下的四大金刚" class="headerlink" title="window下的四大金刚"></a><font style="color:white;background:mediumseagreen;padding:3px 6px;font-weight:bold;line-height:28px">window下的四大金刚</font></h6><blockquote><p>四个对象</p><p>navigator | location | history | screen</p></blockquote><ul><li><p>navigator 浏览器信息</p><p>navigator.userAgent</p><p>1操作系统</p><p>2渲染内核</p><p>3浏览器版本</p></li><li><p>location 页面URL相关信息</p><p>location.href 页面地址</p><p>location.hash 锚点 获取地址栏从#开始到后面的内容,包括#,格式为<font style="color:white;background:mediumseagreen;padding:3px 6px;font-weight:bold;line-height:28px">string</font></p><p>从#开始截止到下一个特殊符号前,例如?</p><p>神奇之处:这个hash不会因为页面刷新和被刷掉,刷新之后仍赖在地址栏上</p><p>使用:添加hash后,判断当hash为某个值时,状态为xx,这个xx状态就不会因为刷新页面而消失了。</p><ol><li>通过a标签添加hash值 <a href=“#11” 点击a标签就给地址加上了#1</li><li>通过js代码添加hash值 location.hash = xx; 设置时忽略#,不用写#</li><li></li></ol><p>location.search 获取地址栏从?开始到后面的内容,包括?,格式为<font style="color:white;background:mediumseagreen;padding:3px 6px;font-weight:bold;line-height:28px">string</font></p><p>从?开始截止到下一个特殊符号前,例如#</p><p>添加方法:</p><ol><li>通过a标签添加search值 <a href=“?why” 点击a标签 #11就消失了,末尾加上了?why</li><li>用js代码添加search值的话,会加在#11之前,无法达到取消#不刷新(即重新刷新)的目的。</li></ol></li><li><p>screen 屏幕对象</p><p>height | width 获取屏幕的宽度和高度,包括顶部地址栏和工具栏</p><p>availHeight | availWidth 获取屏幕的可用宽度和可用高度,不包括顶部地址栏和工具栏</p><p>availHeight<height 但 availWidth==width</p><p>对比:</p><p>document.documentElement.clientWidth/clientHeight 可视窗口的宽高,会随着拖动浏览器变化</p></li></ul>]]></content>
<categories>
<category> FrontEnd </category>
<category> JavaScript </category>
</categories>
<tags>
<tag> JavaScript </tag>
<tag> DOM </tag>
<tag> BOM </tag>
</tags>
</entry>
<entry>
<title>JS中的对象和原型</title>
<link href="/2018/11/02/JS%E4%B8%AD%E7%9A%84%E5%AF%B9%E8%B1%A1%E5%92%8C%E5%8E%9F%E5%9E%8B/"/>
<url>/2018/11/02/JS%E4%B8%AD%E7%9A%84%E5%AF%B9%E8%B1%A1%E5%92%8C%E5%8E%9F%E5%9E%8B/</url>
<content type="html"><![CDATA[<h2 id="JS里的对象"><a href="#JS里的对象" class="headerlink" title="JS里的对象"></a>JS里的对象</h2><h3 id="对象"><a href="#对象" class="headerlink" title="对象"></a>对象</h3><blockquote><p>对象就是一组键值对(key-value)集合,是无序的复合数据集合。类似map结构。</p></blockquote><p>一个对象的键值对之间,用逗号分隔。</p><p>💫键名如果是数值,会被自动转为字符串。</p><p>如果键名不符合标识名的条件(比如第一个字符为数字,或者含有空格或运算符),且也不是数字,则必须加上引号,否则会报错。</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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 报错</span></span><br><span class="line"><span class="keyword">var</span> obj = {</span><br><span class="line"> <span class="number">1</span>p: <span class="string">'Hello World'</span></span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="comment">// 不报错</span></span><br><span class="line"><span class="keyword">var</span> obj = {</span><br><span class="line"> <span class="string">'1p'</span>: <span class="string">'Hello World'</span>,</span><br><span class="line"> <span class="string">'h w'</span>: <span class="string">'Hello World'</span>,</span><br><span class="line"> <span class="string">'p+q'</span>: <span class="string">'Hello World'</span></span><br><span class="line">};</span><br></pre></td></tr></table></figure><p>对象两种调用属性方式,obj.pro | obj[‘pro’]。在上面这个栗子,只能用[‘’]的方式调用。</p><p>对象的每一个键名又称为“属性”(property),它的“键值”可以是任何数据类型。如果一个属性的值为函数,通常把这个属性称为“方法”,它可以像函数那样调用。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> obj = {</span><br><span class="line"> p: <span class="function"><span class="keyword">function</span> (<span class="params">x</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="number">2</span> * x;</span><br><span class="line"> }</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">obj.p(<span class="number">1</span>) <span class="comment">// 2</span></span><br><span class="line">obj[<span class="string">"p"</span>](<span class="number">1</span>) <span class="comment">// 2 ,第二种调用方法</span></span><br></pre></td></tr></table></figure><h4 id="表达式还是语句?"><a href="#表达式还是语句?" class="headerlink" title="表达式还是语句?"></a>表达式还是语句?</h4><p>如果行首是一个大括号,它到底是表达式还是语句?</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">{ <span class="attr">foo</span>: <span class="number">123</span> }</span><br></pre></td></tr></table></figure><p>JavaScript 引擎读到上面这行代码,会发现可能有两种含义。第一种可能是,这是一个表达式,表示一个包含<code>foo</code>属性的对象;第二种可能是,这是一个语句,表示一个代码区块,里面有一个标签<code>foo</code>,指向表达式<code>123</code>。</p><font style="color:white;background:mediumseagreen;padding:3px 6px;font-weight:bold;">外面加上圆括号,理解为对象;不加圆括号,理解为代码块。</font><p>这种差异在<code>eval</code>语句(作用是对字符串求值)中反映得最明显。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">eval</span>(<span class="string">'{foo: 123}'</span>) <span class="comment">// 123</span></span><br><span class="line"><span class="built_in">eval</span>(<span class="string">'({foo: 123})'</span>) <span class="comment">// {foo: 123}</span></span><br></pre></td></tr></table></figure><p>没有圆括号,<code>eval</code>将其理解为一个代码块;加上圆括号以后,就理解成一个对象。</p><h4 id="属性的操作"><a href="#属性的操作" class="headerlink" title="属性的操作"></a>属性的操作</h4><h5 id="读取属性"><a href="#读取属性" class="headerlink" title="读取属性"></a>读取属性</h5><p>点运算符和方括号运算符。</p><figure class="highlight plain"><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">var obj = {</span><br><span class="line"> p: 'Hello World'</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">obj.p // "Hello World"</span><br><span class="line">obj['p'] // "Hello World"</span><br></pre></td></tr></table></figure><p>上面代码分别采用点运算符和方括号运算符,读取属性<code>p</code>。</p><p>请注意,如果使用方括号运算符,键名必须放在引号里面,否则会被当作变量处理。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> foo = <span class="string">'bar'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> obj = {</span><br><span class="line"> foo: <span class="number">1</span>,</span><br><span class="line"> bar: <span class="number">2</span></span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">obj.foo <span class="comment">// 1</span></span><br><span class="line">obj[foo] <span class="comment">// 2</span></span><br></pre></td></tr></table></figure><p>方括号更加灵活多样,方括号运算符内部还可以使用表达式,点号不行。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">obj[<span class="string">'hello'</span> + <span class="string">' world'</span>]</span><br><span class="line">obj[<span class="number">3</span> + <span class="number">3</span>]</span><br></pre></td></tr></table></figure><p>数字键可以不加引号,因为自动转为字符串。数字键不能用点运算符,会被当成小数点,报错。</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">var</span> obj = {</span><br><span class="line"> <span class="number">0.7</span>: <span class="string">'Hello World'</span></span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">obj[<span class="string">'0.7'</span>] <span class="comment">// "Hello World"</span></span><br><span class="line">obj[<span class="number">0.7</span>] <span class="comment">// "Hello World"</span></span><br><span class="line">obj<span class="number">.0</span><span class="number">.7</span> <span class="comment">//报错,不可用点运算符。</span></span><br></pre></td></tr></table></figure><h5 id="属性的赋值"><a href="#属性的赋值" class="headerlink" title="属性的赋值"></a>属性的赋值</h5><p>点运算符和方括号运算符,除了读取,还可用于赋值。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> obj = {};</span><br><span class="line"></span><br><span class="line">obj.foo = <span class="string">'Hello'</span>;</span><br><span class="line">obj[<span class="string">'bar'</span>] = <span class="string">'World'</span>;</span><br></pre></td></tr></table></figure><p>JavaScript 允许<font style="color:white;background:mediumseagreen;padding:3px 6px;font-weight:bold;">属性的“后绑定”</font>,也就是说,你可以在任意时刻新增属性,没必要在定义对象的时候,就定义好属性。</p><h5 id="查看所有属性"><a href="#查看所有属性" class="headerlink" title="查看所有属性"></a>查看所有属性</h5><p><code>Object.keys</code>,查看一个对象本身的所有属性(所有‘键’),返回的是一个数组(Array)。</p><p>💡 技巧:想查看一个对象中有多少个键,使用<code>Object.keys(objxx).length</code>方法即可。</p><p>(或Object.keys(objxx)[‘length’])</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">var</span> obj = {</span><br><span class="line"> key1: <span class="number">1</span>,</span><br><span class="line"> key2: <span class="number">2</span></span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="built_in">Object</span>.keys(obj);</span><br><span class="line"><span class="comment">// ['key1', 'key2']</span></span><br></pre></td></tr></table></figure><h5 id="delete命令"><a href="#delete命令" class="headerlink" title="delete命令"></a>delete命令</h5><p>用于删除对象的某个属性,删除成功后返回true</p><p>删除存在或不存在的属性,都会返回true;只有一种情况,该属性存在而且不得删除,delete才会返回false。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> obj = { <span class="attr">p</span>: <span class="number">1</span> };</span><br><span class="line"><span class="built_in">Object</span>.keys(obj) <span class="comment">// ["p"]</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">delete</span> obj.p <span class="comment">// true</span></span><br><span class="line">obj.p <span class="comment">// undefined</span></span><br><span class="line"><span class="built_in">Object</span>.keys(obj) <span class="comment">// []</span></span><br></pre></td></tr></table></figure><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">var</span> obj = <span class="built_in">Object</span>.defineProperty({}, <span class="string">'p'</span>, {</span><br><span class="line"> value: <span class="number">123</span>,</span><br><span class="line"> configurable: <span class="literal">false</span></span><br><span class="line">});</span><br><span class="line"></span><br><span class="line">obj.p <span class="comment">// 123</span></span><br><span class="line"><span class="keyword">delete</span> obj.p <span class="comment">// false</span></span><br></pre></td></tr></table></figure><p>上面代码之中,对象<code>obj</code>的<code>p</code>属性是不能删除的,所以<code>delete</code>命令返回<code>false</code>(关于<code>Object.defineProperty</code>方法的介绍,请看《标准库》的 Object 对象一章)。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> obj = {};</span><br><span class="line"><span class="keyword">delete</span> obj.toString <span class="comment">// true</span></span><br><span class="line">obj.toString <span class="comment">// function toString() { [native code] }</span></span><br></pre></td></tr></table></figure><p>另外,需要注意的是,<code>delete</code>命令只能删除对象本身的属性,无法删除继承的属性(关于继承参见《面向对象编程》章节)。</p><p>上面代码中,<code>toString</code>是对象<code>obj</code>继承的属性,虽然<code>delete</code>命令返回<code>true</code>,但该属性并没有被删除,依然存在。这个例子还说明,即使<code>delete</code>返回<code>true</code>,该属性依然可能读取到值。</p><h5 id="in运算符"><a href="#in运算符" class="headerlink" title="in运算符"></a>in运算符</h5><p><code>in</code>运算符用于检查对象是否包含某个属性(注意,检查的是键名,不是键值),如果包含就返回<code>true</code>,否则返回<code>false</code>。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> obj = { <span class="attr">p</span>: <span class="number">1</span> };</span><br><span class="line"><span class="string">'p'</span> <span class="keyword">in</span> obj <span class="comment">// true</span></span><br></pre></td></tr></table></figure><p>不能识别哪些属性是对象自身的,哪些属性是继承的。<code>toString</code>方法不是对象<code>obj</code>自身的属性,而是继承的属性。但是,<code>in</code>运算符不能识别,对继承的属性也返回<code>true</code>。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> obj = {};</span><br><span class="line"><span class="string">'toString'</span> <span class="keyword">in</span> obj <span class="comment">// true</span></span><br></pre></td></tr></table></figure><h5 id="for…in循环"><a href="#for…in循环" class="headerlink" title="for…in循环"></a>for…in循环</h5><p>该循环用来遍历一个对象的全部属性。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> obj = {<span class="attr">a</span>: <span class="number">1</span>, <span class="attr">b</span>: <span class="number">2</span>, <span class="attr">c</span>: <span class="number">3</span>};</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">var</span> i <span class="keyword">in</span> obj) {</span><br><span class="line"> <span class="built_in">console</span>.log(obj[i]); | <span class="built_in">console</span>.log(i)</span><br><span class="line">}</span><br><span class="line"><span class="comment">// 1 | a</span></span><br><span class="line"><span class="comment">// 2 | b</span></span><br><span class="line"><span class="comment">// 3 | c</span></span><br></pre></td></tr></table></figure><p>下面是一个使用<code>for...in</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><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="keyword">var</span> obj = {</span><br><span class="line"> x: <span class="number">1</span>,</span><br><span class="line"> y: <span class="number">2</span></span><br><span class="line">};</span><br><span class="line"><span class="keyword">var</span> props = [];</span><br><span class="line"><span class="keyword">var</span> i = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">var</span> p <span class="keyword">in</span> obj) {</span><br><span class="line"> props[i++] = p</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">props <span class="comment">// ['x', 'y']</span></span><br></pre></td></tr></table></figure><p>对象<code>obj</code>继承了<code>toString</code>属性,该属性不会被<code>for...in</code>循环遍历到,因为它默认是“不可遍历”的。</p><font style="color:white;background:mediumseagreen;padding:3px 6px;font-weight:bold;">hasOwnProperty</font><p>判断某个属性是不是对象自身的属性(还是继承的?),返回真假。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> person = { <span class="attr">name</span>: <span class="string">'老张'</span> };</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">var</span> key <span class="keyword">in</span> person) {</span><br><span class="line"> <span class="keyword">if</span> (person.hasOwnProperty(key)) {</span><br><span class="line"> <span class="built_in">console</span>.log(key);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="comment">// name</span></span><br></pre></td></tr></table></figure><p>以上总结From 『js标准参考教程』</p><hr><p>全局对象 global</p><p>在浏览器中,global为window</p><font style="color:white;background:mediumseagreen;padding:3px 6px;font-weight:bold;">window的属性分为两类</font><ul><li>ECMAScript规定 (标准化) parseInt | parseFloat</li><li>私有的(只有某些浏览器有,没有标准) <ul><li>alert 弹框提示</li><li>prompt 用户填写</li><li>confirm 确认</li><li>console 开发者</li><li>document (文档) DOM</li><li>history (浏览器) BOM</li></ul></li></ul><p>window的属性或方法,使用时可以省略window</p><p>window常用API</p><p>Window.Number() | String() | Boolean() | Object()</p><p>setTimeout (控制台打出的数字是指计时器序号)</p><p>var a = new Number(1); 这时 a的类型为object对象,而不是数字</p><h4 id="常用API"><a href="#常用API" class="headerlink" title="常用API"></a>常用API</h4><blockquote><p><strong>Number()</strong></p></blockquote><p>直接声明1和new Number的区别</p><p>var n1 = 1; 数字1 栈内存</p><p>var n2 = new Number(1); 对象1 栈内存存地址,堆内存有各种属性方法和值</p><p>temp = new Number(n1); temp.toString();</p><p>然后把temp干掉,把temp.toString()返回表达式n1.toString()</p><p>js之父上述后 让n1简单数字 也可以用对象的属性和方法了</p><p>切记:临时对象temp会对抹杀,普通类型.xxx时 是引入了一个临时对象temp,这次用完立马抹杀</p><p>把简单类型当成对象使用时,都是转成了临时对象temp,用完立刻抹杀。</p><p>charAt(index) 获取index索引的字符</p><p>charCodeAt(index) index索引字符对应的Unicode编码</p><p>Var s = “abcd”; s0 = s.charAt(0); s1 = s.charCodeAt(0);</p><p>则s0为“a”,s1为97,s2=s.charCodeAt(0).toString(16),为97的十六进制数61</p><blockquote><p><strong>String()</strong></p></blockquote><blockquote><p><strong>trim</strong></p></blockquote><p><strong>裁剪左右两边的多余空格</strong></p><p>s1 = ‘ heell ’</p><p>s1.trim() - s1 = ‘heell’</p><blockquote><p><strong>concat</strong></p></blockquote><p><strong>连接两个字符串</strong></p><p>s1 = ‘hello’; s2 = ‘world’;</p><p>console.log(s1.concat(s2));‘helloworld’</p><blockquote><p><strong>slice</strong></p></blockquote><p><strong>切片</strong></p><p>slice(start,num),从索引start号开始,切出num片</p><p>s1 = “hello”</p><p>s1.slice(1,2) - “el”</p><blockquote><p><strong>replace</strong></p></blockquote><p><strong>替换</strong></p><p>s1.replace(‘e’,‘o’) - s1 = hollo (替换第一个?)</p><p>常用API可见MDN useful string methods</p><blockquote><p><strong>Boolean()</strong></p></blockquote><p>5个falsy值,0 | NaN | “” | null | undefined </p><p>其他全都是true,<font style="color:white;background:mediumseagreen;padding:3px 6px;font-weight:bold;">所有对象均为true</font>,包括false对象</p><p>⚠️注意:</p><p>对象和对象一般都不相等,因为他们地址不一样。即使指向的东西的值一样。</p><h2 id="JS里的原型"><a href="#JS里的原型" class="headerlink" title="JS里的原型"></a>JS里的原型</h2><h4 id="公用属性——原型"><a href="#公用属性——原型" class="headerlink" title="公用属性——原型"></a>公用属性——原型</h4><p>共用属性 toString | valueOf</p><p>为了减少内存浪费,不用每个对象里头都存一个toString</p><p>对象不存 toString和valueOf,但是可以调用</p><p>有一个隐藏的key,__proto__</p><p>__proto__ 存的是一个地址,指向那些共用属性 toString|valueOf </p><p>⚠️注意:</p><p>Number更复杂,__proto__中还套了一层__proto__,第二层__proto__才是指向的所有对象共有的属性,第一层__proto__是含有Number独有的属性</p><p>String和Boolean与Number类似,__proto__中还套了一层__proto__</p><p>结构像一棵树,Object的共有属性(Object.prototype)相当于树根,</p><p>Object.prototype-> 对象的共有属性,也就是实例对象的__proto__对应的值</p><p>原型即共有属性的意思</p><p>var o1 = new Object();</p><p>o1.__proto__ === Object.prototype ✅ </p><p>其实对象也有两层__proto__,第二层__proto__为null(注意不是undefined)</p><p>o1.__proto__.__proto__ === null</p><p>var n1 = new Number(1);</p><p>n1.__proto__ === Number.prototype</p><p>n1.__proto__.__proto__ === Object.prototype</p><font style="color:white;background:mediumseagreen;padding:3px 6px;font-weight:bold;line-height:28px">某个实例访问属性,如果该实例的构造函数的prototype没有这个属性,就会往更下一层的__proto__(即Object的共有属性)去找,有的话就可调用成功,如果还是没有就返回undefined。</font><p>例如上文的 n1.hasOwnProperty就是往下一层的__proto__中找的属性,是对象才有的公共属性。</p><p>var __ = new __</p><p>var后的为对象,new后面的为函数对象</p><p>__proto__是对象的属性,prototype是函数的属性</p><p>对象.__proto__ === 函数.prototype</p><blockquote><p><strong>总结</strong></p><p><strong><font color="dared">对象.__proto__ == 该对象的构造函数.prototype</font></strong></p><p>__proto__是对象的属性,prototype是函数的属性</p><p><code>Object</code>| <code>String</code>| <code>Number</code>| <code>Boolean</code>| <code>Function</code>都是构造函数</p><p>否</p><p>Object.__proto__ === Function.__proto__</p><p>原型对象prototype的所有属性和方法,都能被实例对象共享。</p><p>原型对象的作用,就是定义所有实例对象共享的属性和方法。</p><p>实例对象的__proto__指向原型对象;</p><p>构造函数的prototype指向原型对象;</p><p>原型对象的constructor指向构造函数</p><p>(即Object===Object.prototype.constructor)</p><p>将一个东西当成函数,则用xx.prototype去获取他的原型</p><p>将一个东西当成对象,则用xx.__proto__去获取他的原型。</p><p>(functionxx.prototype是一个对象,obj.__proto__也是一个对象)</p><p>使用__proto__相当于使用一个访问器,</p><p>e.g. obj.__proto__ 相当于 Object.getPrototypeOf(obj)</p></blockquote><p>class A extends B{}</p><p>A.prototype.__proto__ == B.prototype 「A的原型由B构造而来」</p> <font style="color:white;background:mediumseagreen;padding:3px 6px;font-weight:bold;line-height:2">特殊的Function</font><p>Fuction的构造函数也是Function,</p><p>Function.constructor === Function</p><blockquote><p>所以Function.__proto__ === Function.prototype</p><p>即Object.getPrototypeOf(Function)===Function.prototype</p></blockquote><p>全等号左侧的Function被当成对象,而右侧的Function被当做函数。</p><p>Function是Function的构造函数,</p><p>相当于var obj = new Object();</p><p>obj.__proto__===Object.prototype</p><p>Object是obj的构造函数</p><blockquote><p>Function.prototype.__proto__ = Object.prototype</p></blockquote><p>Function.prototype也是一个对象,对象的__proto__属性即对象的构造函数Object的prototype。</p><p>⚠️注意:</p><font color="dared"><strong>Object是所有所有对象的构造函数,而Function是所有所有函数对象(typeof xx为function)的构造函数。</strong></font><p>所以Object(Object是一个函数对象)的构造函数也是Function,则</p><blockquote><p>Object.__proto__ === Function.prototype </p><p>Object.__proto__ === Function.__proto__</p></blockquote><p>附上一张图总结:</p><p><img src="prototype.jpg" alt="prototype"></p><p>引自思否<a href="https://segmentfault.com/a/1190000014717972" target="_blank" rel="noopener">https://segmentfault.com/a/1190000014717972</a></p>]]></content>
<tags>
<tag> JavaScript </tag>
<tag> 前端知识 </tag>
</tags>
</entry>
<entry>
<title>geth相关命令</title>
<link href="/2018/10/22/geth%E7%9B%B8%E5%85%B3%E5%91%BD%E4%BB%A4/"/>
<url>/2018/10/22/geth%E7%9B%B8%E5%85%B3%E5%91%BD%E4%BB%A4/</url>
<content type="html"><![CDATA[<p>geth指令 如果带了 –dev 开发者模式 可以不用创世块genesis block初始化</p><p>创世区块</p><figure class="highlight"><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></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">"config"</span>: {</span><br><span class="line"> //区块链的ID,你随便给一个就可以</span><br><span class="line"> "chainId": 21,</span><br><span class="line"> //下面三个参数暂时不知道干啥的</span><br><span class="line"> //等我知道了补上,或者有哪位大神知道</span><br><span class="line"> //可以在评论里指点我,谢谢</span><br><span class="line"> "homesteadBlock": 0,</span><br><span class="line"> "eip155Block": 0,</span><br><span class="line"> "eip158Block": 0</span><br><span class="line"> },</span><br><span class="line"> //用来预置账号以及账号的以太币数量,应该也就是所谓的预挖</span><br><span class="line"> //我这里不需要预挖,所以给了个空对象</span><br><span class="line"> //如果需要可以这样加</span><br><span class="line"> //"alloc": {</span><br><span class="line"> //"0x0000000000000000000000000000000000000001": {"balance": "111111111"},</span><br><span class="line"> //"0x0000000000000000000000000000000000000002": {"balance": "222222222"}</span><br><span class="line"> //}</span><br><span class="line"> "alloc" : {},</span><br><span class="line"> //币基地址,也就是默认的钱包地址,因为我没有地址,所以全0,为空</span><br><span class="line"> //后面运行Geth后创建新账户时,如果Geth发现没有币基地址,会默认将第一个账户的地址设置为币基地址</span><br><span class="line"> //也就是矿工账号</span><br><span class="line"> "coinbase" : "0x0000000000000000000000000000000000000000",</span><br><span class="line"> //挖矿难度,你可以随便控制哦,这里设置的难度比较小,因为我喜欢钱来得快</span><br><span class="line"> "difficulty" : "0x20000", //可以用小点的0x4000</span><br><span class="line"> //0x2ffffd大概 一分钟5~10个</span><br><span class="line"> //附加信息,随便填个文本或不填也行,类似中本聪在比特币创世块中写的报纸新闻</span><br><span class="line"> "extraData" : "",</span><br><span class="line"> //gas最高限制,以太坊运行交易,合约等所消耗的gas最高限制,这里设置为最高</span><br><span class="line"> "gasLimit" : "0x2fefd8", //0xffffff为最高</span><br><span class="line"> //64位随机数,用于挖矿,注意他和mixhash的设置需要满足以太坊黄皮书中的要求</span><br><span class="line"> //直接用我这个也可以</span><br><span class="line"> "nonce" : "0x0000000000000042",</span><br><span class="line"> //与nonce共同用于挖矿,注意他和nonce的设置需要满足以太坊黄皮书中的要求</span><br><span class="line"> "mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",</span><br><span class="line"> //上一个区块的Hash值,因为是创世块,石头里蹦出来的,没有在它前面的,所以是0</span><br><span class="line"> "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",</span><br><span class="line"> //创世块的时间戳,这里给0就好</span><br><span class="line"> "timestamp" : "0x00"</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>初始化创世节点:</p><p>geth –datadir ./data init genesis.json</p><p>启动节点</p><p>geth –datadir ./data –networkid 15 –port 30303 –rpc –rpcaddr 0.0.0.0 –rpcport 8545 –rpcapi ‘db,net,eth,web3,personal’ –rpccorsdomain ‘*’ –nat “any” –nodiscover console</p><p>💡 ==千万注意引号是英文的 特别坑==</p><table><thead><tr><th>geth命令参数</th><th>参数含义</th></tr></thead><tbody><tr><td>console</td><td>指启动节点后启用交互式js命令行</td></tr><tr><td>datadir</td><td>指定数据存放目录</td></tr><tr><td>networkid</td><td>以太坊网络标识符,1代表主网,3Ropsten,4Rinkeby,34都为测试网,<br>默认为1,填个大点的代表私有链</td></tr><tr><td>port</td><td>网卡监听端口号,不同计算机节点通过这个连接</td></tr><tr><td>–rpc</td><td>启用http-rpc服务器,允许远程指令访问</td></tr><tr><td>rpcaddr 0.0.0.0</td><td>允许任意有效的ip地址连接</td></tr><tr><td>rpcport</td><td>http-rpc服务器监听端口,即geth启动rpc服务的端口为8545(默认值)</td></tr><tr><td>rpcapi</td><td>提供的可供调用的api模块</td></tr><tr><td>rpccorsdomain</td><td>可以跨域访问的域名列表 (浏览器想连接上geth需要有此项),<br>*代表所有</td></tr><tr><td>nat</td><td>端口映射机制,默认any</td></tr><tr><td>nodiscover</td><td>禁用节点发现机制(手动添加节点)</td></tr><tr><td>–identity</td><td>自定义节点名‘name’</td></tr><tr><td>–dev</td><td>开发者模式,自动分配一个不需要解锁的账户而且会得自动挖矿</td></tr></tbody></table><p>==注意==</p><p>–dev 使用POA共识网络,默认预分配一个开发者账户并且会自动开启挖矿。–dev可以不用创世块初始化</p><p>创世块中调节挖矿难度</p><p>–dev.period value | value为开发者模式下挖矿周期(0 = 仅在交易时)(默认: 0)</p><blockquote><p>geth –datadir ./data –networkid 15 –port 30303 –rpc –rpcaddr 0.0.0.0 –rpcport 8545 –rpcapi ‘db,net,eth,web3,personal’ –rpccorsdomain ‘*’ –nat “any” –nodiscover –identity “superman285” console 2>gethprint.log</p></blockquote><p>信息不打印在命令行中,而是输出到gethprint.log文件中,</p><p>这时如果用miner.start() 会打出null而不是true,但是也开始挖矿了</p><p>geth命令参数详解:<a href="http://www.cnblogs.com/tinyxiong/p/7918706.html" target="_blank" rel="noopener">http://www.cnblogs.com/tinyxiong/p/7918706.html</a></p><p>geth的控制台可以定义变量,用js语法,可用var</p><p>==常用:==</p><p>eth.accounts | eth.accounts[index]</p><p>eth.blockNumber</p><p>eth.getBalance(eth.accounts[0])</p><p>personal.newAccount(“password”)</p><p>personal.unlockAccount(address) | 可以address = eth.accounts[0]</p><p>miner.start() | miner.stop()</p><p>转账</p><p>eth.sendTransaction({from:user1,to:user2,value:web3.toWei(10,“ether”)})</p><p>转账10个eth,需要挖矿才能确认交易</p><p>单位换算</p><p>web3.toWei(10,“ether”)</p>]]></content>
<categories>
<category> BlockChain </category>
<category> Ethereum </category>
</categories>
<tags>
<tag> Ethereum </tag>
<tag> BlockChain </tag>
<tag> geth </tag>
</tags>
</entry>
<entry>
<title>聊聊JS中的数据类型转换和内存图</title>
<link href="/2018/10/18/%E8%81%8A%E8%81%8AJS%E4%B8%AD%E7%9A%84%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E8%BD%AC%E6%8D%A2%E5%92%8C%E5%86%85%E5%AD%98%E5%9B%BE/"/>
<url>/2018/10/18/%E8%81%8A%E8%81%8AJS%E4%B8%AD%E7%9A%84%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E8%BD%AC%E6%8D%A2%E5%92%8C%E5%86%85%E5%AD%98%E5%9B%BE/</url>
<content type="html"><![CDATA[<h2 id="JS中的类型转换-amp-内存图-amp-GC-amp-深拷贝"><a href="#JS中的类型转换-amp-内存图-amp-GC-amp-深拷贝" class="headerlink" title="JS中的类型转换&内存图&GC&深拷贝"></a>JS中的类型转换&内存图&GC&深拷贝</h2><h3 id="类型转换"><a href="#类型转换" class="headerlink" title="类型转换"></a>类型转换</h3><table><thead><tr><th>左👉右</th><th>number</th><th>string</th><th>boolean</th><th>null</th><th>undefined</th><th>object</th></tr></thead><tbody><tr><td><strong>number</strong></td><td></td><td>n.toString()<br>(6).toString()<br>或var num = 6;<br>num.toString()</td><td>Boolean(n)</td><td></td><td></td><td></td></tr><tr><td><strong>string</strong></td><td>Number(‘str’)</td><td></td><td>Boolean()</td><td></td><td></td><td></td></tr><tr><td><strong>boolean</strong></td><td>Number(true)</td><td>.toString()</td><td></td><td></td><td></td><td></td></tr><tr><td><strong>null</strong></td><td>Number()<br>转为0</td><td>无法用toString</td><td>Boolean()</td><td></td><td></td><td></td></tr><tr><td><strong>undefined</strong></td><td>Number()<br>转为NaN</td><td>无法用toString</td><td>Boolean()</td><td></td><td></td><td></td></tr><tr><td><strong>object</strong></td><td>对象和函数转为NaN,数组看情况</td><td>使用toString<br>‘[object Object]’</td><td>Boolean()</td><td></td><td></td></tr></tbody></table><p>🛵<strong>老司机妙招</strong></p><font style="color:white;background:mediumseagreen;padding:3px 6px;font-weight:bold;">快速转换成string类型:xx + ‘’==</font><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="number">1</span>+<span class="string">''</span> <span class="comment">//'1'</span></span><br><span class="line"><span class="literal">true</span>+<span class="string">''</span> <span class="comment">//'true'</span></span><br><span class="line"><span class="literal">undefined</span>+<span class="string">''</span> <span class="comment">//'undefined'</span></span><br><span class="line">({}) + <span class="string">''</span> <span class="comment">//猜猜输出啥</span></span><br><span class="line">{} + <span class="string">''</span> <span class="comment">//猜猜输出啥</span></span><br></pre></td></tr></table></figure><font style="color:white;background:mediumseagreen;padding:3px 6px;font-weight:bold;">快速转换成boolean类型:!!xx</font><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="literal">undefined</span> <span class="comment">//false</span></span><br><span class="line">!!<span class="literal">null</span> <span class="comment">//false</span></span><br><span class="line">!!<span class="number">6</span> <span class="comment">//true</span></span><br><span class="line">!!<span class="number">0</span> <span class="comment">//false</span></span><br><span class="line">!!<span class="string">'s'</span> <span class="comment">//true</span></span><br><span class="line">!!<span class="string">" "</span> <span class="comment">//空格字符串输出true</span></span><br><span class="line">!!<span class="string">''</span> <span class="comment">//猜猜输出啥</span></span><br><span class="line">!!{} <span class="comment">//猜猜输出啥</span></span><br><span class="line">!![] <span class="comment">//猜猜输出啥</span></span><br></pre></td></tr></table></figure><font style="color:white;background:mediumseagreen;padding:3px 6px;font-weight:bold;">快速转换成number类型:</font><ul><li><font style="color:white;background:mediumseagreen;padding:3px 6px;font-weight:bold;">xx - 0</font></li><li><font style="color:white;background:mediumseagreen;padding:3px 6px;font-weight:bold;">+xx</font></li></ul><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="string">'s'</span><span class="comment">//NaN</span></span><br><span class="line">+<span class="string">'12'</span><span class="comment">//12</span></span><br><span class="line">+<span class="string">'1s'</span><span class="comment">//NaN</span></span><br><span class="line">+[]<span class="comment">//猜一猜</span></span><br><span class="line">+[<span class="number">123</span>]<span class="comment">//123</span></span><br><span class="line">+[<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>]<span class="comment">//NaN</span></span><br><span class="line">+{}<span class="comment">//猜一猜</span></span><br><span class="line">+<span class="literal">null</span><span class="comment">//猜一猜</span></span><br><span class="line">+<span class="literal">undefined</span><span class="comment">//猜一猜</span></span><br></pre></td></tr></table></figure><h5 id="转换方法总结"><a href="#转换方法总结" class="headerlink" title="转换方法总结"></a>转换方法总结</h5><blockquote><p><strong>转换为字符串的方法</strong></p></blockquote><ul><li><p>String(x)</p></li><li><p>x.toString()</p></li><li><p><strong>区别</strong></p><ul><li><p>.toString()不可用于null和undefined而String()可以。</p></li><li><p><code>注:</code>数字或对象使用toString方法需要加上括号,否则报错</p><p>666.toString()❌ (666).toString() ✔</p><p>{}.toString() ❌ ({}).toString() ✔</p></li><li><p>.toString可支持将数字转为不同进制字符串,例如(2).toString(2)//“10”</p><p>可支持.toString(2)|.toString(8)|.toString(10)括号内不写默认为10|.toString(16)</p></li></ul></li><li><p>x+‘’</p></li></ul><blockquote><p><strong>转换为数字的方法</strong></p></blockquote><ul><li>Number(xx)</li><li>parseInt(xx)</li><li>parseFloat(xx)</li><li>xx - 0</li><li>+xx</li></ul><p>❗ <strong>注意ParseInt</strong></p><p>完整写法是parseInt(value,radix),value为要被解析的值,radix为基数。</p><blockquote><font color="darkorenge">parseInt会(从左到右)从第一个字符开始解析,直到碰到了无法解析为数字的东西(如unicode字母等),前面的解析出来多少是多少,打印出多少。</font><p>例如:</p><p>parseInt(‘0b110’) //输出0</p><p>parseInt([1,2,3]) //输出1</p></blockquote><p>含义是将参数value看作radix进制数,返回十进制数值。例如:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">parseInt</span>(<span class="string">'123'</span>, <span class="number">5</span>) <span class="comment">// 将'123'看作5进制数,返回十进制数38 => 1*5^2 + 2*5^1 + 3*5^0 = 38</span></span><br></pre></td></tr></table></figure><font style="color:white;background:mediumseagreen;padding:3px 6px;font-weight:bold;">易错点</font><p>先回顾下二进制、八进制、十六进制数表示:</p><blockquote><p><font color="deeppink"><strong>0b开头代表二进制</strong></font> <strong>|</strong> <font color="deeppink"><strong>0开头代表八进制</strong></font> <strong>|</strong> <font color="deeppink"><strong>0x开头代表十六进制</strong></font> (字母大小写均可)</p></blockquote><p>在没有指定基数radix或者基数为<code>0</code>时,有以下处理</p><ul><li><p>当参数value为<font color="darkorenge"><strong>数字</strong></font>时:</p><ul><li>以0b开头,则基数是2(二进制)</li><li>以0开头,则基数是8(八进制)</li><li>以0x开头,则基数是16(十六进制)</li></ul><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></pre></td><td class="code"><pre><span class="line"><span class="built_in">parseInt</span>(<span class="number">017</span>) 相当于<span class="built_in">parseInt</span>(<span class="number">017</span>,<span class="number">10</span>)|<span class="built_in">parseInt</span>(<span class="number">017</span>,<span class="number">0</span>)</span><br><span class="line">也相当于直接在浏览器控制台输入 <span class="number">017</span> 得出一个数值</span><br><span class="line"><span class="built_in">parseInt</span>(<span class="number">017</span>) <span class="comment">//15 , 1*8^1+7*8^0 = 15</span></span><br><span class="line"><span class="number">017</span> <span class="comment">//15 , 浏览器将其视为了八进制数,所以转换成十进制数后得到15</span></span><br><span class="line"><span class="number">0789</span> <span class="comment">//789,由于到达了8,浏览器会智能地将它视为十进制数,输出789</span></span><br><span class="line"><span class="built_in">parseInt</span>(<span class="number">017</span>,<span class="number">8</span>) <span class="comment">//13,因为浏览器自动将017转为15,所以其实是parseInt(15,8),得到13</span></span><br><span class="line"><span class="built_in">parseInt</span>(<span class="number">17</span>,<span class="number">8</span>) <span class="comment">//15,因为没有0开头,不知道他是八进制数,所以用给的radix参数来当作8进制数处理</span></span><br><span class="line"> <span class="comment">//即 1*8^1+7*8^0 = 15 ,相当于parseInt(017)</span></span><br></pre></td></tr></table></figure></li><li><p>当参数value为<font color="darkorenge"><strong>字符串</strong></font>时:</p><ul><li>以0b开头,并不会被识别为二进制,而是将b当为字符,所以解析到b之前中断,输出0</li><li>以0开头,<strong>基数是10</strong>(十进制)或8(八进制),ES5规定为10,但可能有的浏览器仍为8,一般用10</li><li>以0x开头,则基数是16(十六进制)</li><li>其他任何开头视为基数10(十进制)</li></ul><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></pre></td><td class="code"><pre><span class="line"><span class="built_in">parseInt</span>(<span class="string">'0b111'</span>) <span class="comment">//输出0</span></span><br><span class="line"><span class="built_in">parseInt</span>(<span class="string">'0789'</span>) <span class="comment">//789,视为十进制,若为八进制是不会出现8和9的</span></span><br><span class="line"><span class="built_in">parseInt</span>(<span class="string">'0789'</span>,<span class="number">8</span>) <span class="comment">//7,浏览器自动将'0789'转为了789,只能解析出小于8的,所以是7</span></span><br><span class="line"><span class="built_in">parseInt</span>(<span class="string">'0x178'</span>) <span class="comment">//376,1*16^2+7*16+8*1=376,相当于parseInt('0x178',16)</span></span><br><span class="line"><span class="built_in">parseInt</span>(<span class="string">'0x178'</span>,<span class="number">10</span>) <span class="comment">//0,若视为其他进制,则x越不过去,解析到x前停下,所以是0</span></span><br><span class="line">傻傻分不清楚:</span><br><span class="line"><span class="built_in">parseInt</span>(<span class="string">'0x011'</span>,<span class="number">16</span>) <span class="comment">//17,1*16^1+1*16^0=17</span></span><br><span class="line"><span class="built_in">parseInt</span>(<span class="number">0x011</span>,<span class="number">16</span>) <span class="comment">//23 , 0x011自动被转为了17,所以是parseInt(17,16),1*16+7*1=23</span></span><br></pre></td></tr></table></figure></li></ul><p>有很多坑,具体可以看MDN资料:</p><blockquote><p><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/parseInt" target="_blank" rel="noopener">https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/parseInt</a></p></blockquote><blockquote><p><strong>转换为布尔值的方法</strong></p></blockquote><ul><li>Boolean(x)</li><li>!!x</li></ul><font style="color:white;background:mediumseagreen;padding:3px 6px;font-weight:bold;">记忆</font><p>只有0|NaN|‘’|undefined|null 是<code>5</code>个falsy值,转成boolean为false,其他<code>所有</code>都会转成true</p><p><code>所有对象</code>转为boolean都为true,包括空对象、空数组、空函数等</p><font style="color:white;background:mediumseagreen;padding:3px 6px;font-weight:bold;">注意</font><p>对象中</p><p>var obj = {null:0,undefined:0}</p><p>obj[null]==obj[‘null’]\==obj.null //都打印出0,null自动转换为了‘null’</p><p>obj[undefined]==obj[‘undefined’]\==obj.undefined//都打出0,undefined自动转成了‘undefined’</p><h3 id="内存图"><a href="#内存图" class="headerlink" title="内存图"></a>内存图</h3><p>js内存分配</p><p>js引擎将内存分成两大块</p><p>代码区:存代码 a </p><p>数据区:‘1’ 2 {}</p><p>栈内存(stack)和堆内存(heap)</p><p>栈内存可以存基本类型的值或者对应堆内存的地址</p><p>堆内存可以存复杂类型的值(如对象),对象属性的值又可以是地址,这个地址再对应heap中的地址所对应的内容。</p><p>js中数字是以64位浮点数存的</p><p>64位(2^64^)可以表示目前市面上任意大小内存的任一个地址</p><p>js存字符,每个字符16位</p><p>数字64,字符16(后来更新了)</p><p>var a = 2</p><p>先进行变量提升</p><p>若用栈内存按顺序存对象object,一旦要改对象的属性或者新增属性,就需要把之前对象后面的数据往后挪,特别的麻烦。所以只存一个地址,例如是100,100对应堆内存中的100号内存位置,这儿存着整个对象。</p><p>然后如果要改对象属性或者给对象加属性,直接根据地址100找到堆内存对应位置,然后修改或添加即可。</p><p>新加对象的话,就在栈内存新存一个地址,例如是200。则地址100对应对象obj1,地址200对应对象obj2。</p><blockquote><p>若写一个对象赋值语句obj2 = obj1</p><p>然后对象的赋值实际上是将obj1对应的地址赋到了obj2那个位置,然后两个栈内存位置存的地址都是100了,obj1和obj2都指向了100。并没有多出的拷贝。见下图:</p><p><img src="memorypic.png" alt="memorypic"></p></blockquote><p>不同数据类型的存储</p><ul><li>简单数据类型<ul><li>直接存在Stack栈内存 num|str|symbol|bool|null|undefined</li></ul></li><li>复杂数据类型<ul><li>把Heap堆内存地址存到Stack栈,内容存在Heap堆内存中 object对象</li></ul></li></ul><blockquote><p>变量跟对象的关系是引用关系,没有直接存你,而是存的你的地址。</p><p>var obj={name:frank} //变量obj是对象的引用,obj存的是对象的地址而不是对象的值本身</p></blockquote><p>❗ <strong>切记</strong></p><p>赋值,等于号只做一件事情,就是把等于号右边的东西存到等于号左边的东西里头。</p><p>赋值必须先确定等号右边的值,然后再开始赋值。</p><p>例子:</p><p>var a = {name:‘a’};</p><p>b = a;</p><p>b = {name:‘b’};</p><p>console.log(a.name); //画内存图</p><p>将新对象赋给b 改的是b存的地址,而不会改heap中原有的内容</p><p>将新数字(或其他基本类型)赋给b 则b位置存的地址会被新的值覆盖掉</p><blockquote><p>几个题目例子,用内存图弄清对象的赋值</p><p><code>基本类型之间的赋值</code></p><p><img src="copy1.png" alt="copy1"></p><p><code>直接赋值给对象</code></p><p><img src="copy2.png" alt="copy2"></p><p><code>赋值给对象的属性</code></p><p><img src="copy3.png" alt="copy3"></p><p><code>将基本类型值赋值给原来的对象</code></p><p><img src="copy4.png" alt="copy4"></p></blockquote><p>var a ={};a.self=a; a.self.self.self.self可以取到么? //可以</p><p>其实heap里头只有一个对象,从stack找到heap,然后self的值addr33又找到了heap中33号地址位置的东西(就是自己),然后不停地调自己。</p><p><img src="objself.png" alt="objself"></p><p>若是var a = {self:a};a.self.self.self //就会报错,</p><p>因为赋值操作必须先确定右边的值,而第一次右边的值中的a是undefined 所以 a = {self:undefined};</p><p>再来一次a = {self:a};就会变成 a = {self:{self:undefined}},再打一次就会再嵌套一层,不打就停在那一层。</p><p>❗ <strong>坑</strong>🕳</p><p>alert会调用toString()方法</p><p>a.x = a ={n:2};</p><p>先确定a,而不是从右往左算到最后才确定a,一开始就确定好了a,然后a={n:2}时会再把a存的地址改了</p><blockquote><p>多复习回顾几次:</p><p><a href="https://xiedaimala.com/tasks/61db0dcc-71d4-4f0c-822d-5f24ff0dd128/video_tutorials/22579fe7-206c-411f-a8e1-5786501bf481" target="_blank" rel="noopener">https://xiedaimala.com/tasks/61db0dcc-71d4-4f0c-822d-5f24ff0dd128/video_tutorials/22579fe7-206c-411f-a8e1-5786501bf481</a></p></blockquote><hr><h3 id="GC垃圾回收"><a href="#GC垃圾回收" class="headerlink" title="GC垃圾回收"></a>GC垃圾回收</h3><h5 id="GC-Garbage-Collecation"><a href="#GC-Garbage-Collecation" class="headerlink" title="GC:Garbage Collecation"></a>GC:Garbage Collecation</h5><blockquote><p><strong>🖊核心</strong></p><p>如果一个对象没有被引用,他就是垃圾,将会被回收。</p></blockquote><p>有人罩着就不回收,没人罩着就回收。</p><p><img src="trash.png" alt="trash"></p><p>若页面关闭了,document的click事件对应的function全成了垃圾。</p><p>但ie有bug,不会回收,可加以下代码解决</p><p>window.onunload = function(){document.body.onclick = null;}</p><p>题目1</p><p>hard1</p><p><img src="hard1.png" alt="hard1"></p><p>题目2</p><p>var fn = function(){}</p><p>document.body.onclick = fn</p><p>fn = null</p><p>问function是不是垃圾</p><p><img src="hard2.png" alt="hard2"></p><p>var fn = function(){}</p><p>document.body.onclick = fn</p><p>fn = null</p><p>document.body.onclick = null</p><p>问function是不是垃圾</p><p><img src="hard3.png" alt="hard3"></p><h3 id="深拷贝-VS-浅拷贝"><a href="#深拷贝-VS-浅拷贝" class="headerlink" title="深拷贝 VS 浅拷贝"></a>深拷贝 VS 浅拷贝</h3><blockquote><p>深拷贝</p></blockquote><p>var a = 1;</p><p>var b = a;</p><p>b变不影响a,深拷贝</p><p>基本类型的赋值,为深拷贝</p><blockquote><p>浅拷贝</p></blockquote><p>var a = {name:‘a’}</p><p>var b = a</p><p>b.name = ‘b’</p><p>a.name //也是b</p><p>b变a也变,浅拷贝</p><p>对象的深拷贝,见下图</p><p><img src="deepcopy.png" alt="deepcopy"></p><p>深拷贝如何实现,请听下回分解</p>]]></content>
<tags>
<tag> JavaScript </tag>
<tag> 前端知识 </tag>
</tags>
</entry>
<entry>
<title>谈谈JS中的数据</title>
<link href="/2018/10/17/%E8%B0%88%E8%B0%88JS%E4%B8%AD%E7%9A%84%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B/"/>
<url>/2018/10/17/%E8%B0%88%E8%B0%88JS%E4%B8%AD%E7%9A%84%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B/</url>
<content type="html"><![CDATA[<h2 id="JS里的数据"><a href="#JS里的数据" class="headerlink" title="JS里的数据"></a>JS里的数据</h2><h3 id="JS黑历史"><a href="#JS黑历史" class="headerlink" title="JS黑历史"></a>JS黑历史</h3><p>1991 李爵士 www</p><p>1992 李爵士同事 CSS</p><p>1993 W3C</p><p>1995 网景 Netscape => Navigator</p><p>Branden Eich JS之父,设计了js初版 Mocha</p><p>改名Mocha=>LiveScript=>JavaScript</p><p>网景和Sun达成协议,出品一门脚本语言。</p><p>几年后 Unicode和UTF-8发布 (JS在这之前就出现了,所以它的编码有bug)</p><p>1996 MS->IE => JScript 想抢占市场</p><p>后来 浏览器市场占有 ms打败了网景</p><p>网景开源浏览器 => Firefox 项目</p><p> IE5.5 MS推出JS发请求功能</p><p>2004 Gmail,网页上的程序 JS被正式认为是一门编程语言了(可以开发项目)</p><p>网景为了对抗微软的脚本,向ECMA(欧洲计算机制造协会)申报标准</p><p>标准名为 ECMAScript(因为javascript商标已经被注册了,不可用)</p><p>JS的一些缺点:全局变量(没有模块化)、标准库(内置代码少) | ES3以及之前</p><p>ECMAScript5 做了个小升级 步子比较小</p><p>ECMAScript6 做了比较给力的升级 可以视为现代编程语言了</p><p>很多来源于Rails社区的CoffeeScript社区</p><blockquote><p><strong>JS之父对JS的评价</strong></p><p>原创之处并不优秀,</p><p>优秀之处并非原创!</p></blockquote><p>目前JS每年一更 </p><p>ES7 | ES8 | ES Next</p><blockquote><p>ES5新特性汇总:<a href="https://zhuanlan.zhihu.com/p/24336831?refer=study-fe" target="_blank" rel="noopener">https://zhuanlan.zhihu.com/p/24336831?refer=study-fe</a></p><p>ES6新特性汇总:<a href="https://zhuanlan.zhihu.com/p/24570791" target="_blank" rel="noopener">https://zhuanlan.zhihu.com/p/24570791</a></p></blockquote><p><code>JS学习路径推荐</code></p><p>先学核心ES3,小升级到ES5,再学习ES6(稍微要多花点时间精力)</p><p>没有纳入规范的js语法,可能就先用上了,例如Chrome支持了y1、然后firefox也支持了y1’、IE也支持了y1’’</p><p>ECMA一看大家都支持了,就把他纳入规范。</p><p>或者例如Chrome支持x1,firefox不支持,可以通过Babel来转义。</p><hr><h3 id="JS数据类型"><a href="#JS数据类型" class="headerlink" title="JS数据类型"></a>JS数据类型</h3><p><strong>7种数据类型</strong></p><ul><li>number 数字</li><li>string 字符串</li><li>boolean 布尔值</li><li>object 对象</li><li>null</li><li>undefined</li><li>symbol 符号</li></ul><p>注:array和function并不是数据类型,他们都属于object对象</p><blockquote><p>object对象为复杂类型,其他6种都为基本类型(简单类型)</p></blockquote><h5 id="number数字"><a href="#number数字" class="headerlink" title="number数字"></a>number数字</h5><p>十进制数表示:</p><p>1 | .1 | 1.23e2(代表1.23*10^2^)</p><p>二进制:0b开头,e.g 0b11代表3</p><p>八进制:0开头, e.g 011代表9</p><p>十六进制:0x开头,e.g 0x11代表17</p><h5 id="string字符串"><a href="#string字符串" class="headerlink" title="string字符串"></a>string字符串</h5><blockquote><p>由于发布在unicode和utf-8之前的历史原因,JS只能支持到两个字节的unicode字符</p></blockquote><p>空字符串:‘’ | “” 长度为0</p><p>空格字符串:‘ ’ | “ ” 长度为1</p><p>回车也占长度</p><p>例如:</p><p>var str=`12345<br>67890`</p><p>str长度是11,因为有回车,输出是<br>12345<br>67890</p><blockquote><p><strong><em>转义</em></strong></p><p>符号前加\ 意为这个符号不是结束,而是我想显示出来的符号<br>转义符不占长度</p><p>想显示一个单引号的方法:</p><p>var a = “‘”<br>var a = ‘\‘’</p><p>多行字符串(抄袭命令行,\再加回车来表示换行)</p><p>var str = ‘a\ //此处\代表不是结束<br> b’</p><p>常用转义:<br><code>\0</code> :null(<code>\u0000</code>)</p><p><code>\b</code> :后退键(<code>\u0008</code>)</p><p><code>\f</code> :换页符(<code>\u000C</code>)</p><p><code>\n</code> :换行符(<code>\u000A</code>)</p><p><code>\r</code> :回车键(<code>\u000D</code>)</p><p><code>\t</code> :制表符(<code>\u0009</code>)</p><p><code>\v</code> :垂直制表符(<code>\u000B</code>)</p><p><code>\'</code> :单引号(<code>\u0027</code>)</p><p><code>\"</code> :双引号(<code>\u0022</code>)</p><p><code>\\</code> :反斜杠(<code>\u005C</code>)<br>\加空格 转义 为空格</p></blockquote><h5 id="boolean"><a href="#boolean" class="headerlink" title="boolean"></a>boolean</h5><p>两个值 true | false</p><p>a&&b 两个为真则为真,其中一个为假则为假</p><p>a||b 两个为假则为假,其中一个为真则为真</p><h5 id="null和undefined"><a href="#null和undefined" class="headerlink" title="null和undefined"></a>null和undefined</h5><font color="white" style="font-weight:bold;background:#4EEE94"> 区别 </font><ul><li>【语法】变量未赋值,则为undefined 不是null。</li><li>【惯例】<ul><li>有一个object对象,现在不想赋值。推荐可初始化为null。 </li><li>有一个非object对象,现在不想赋值。推荐可初始化为undefined。</li></ul></li></ul><h5 id="对象object"><a href="#对象object" class="headerlink" title="对象object"></a>对象object</h5><p>对象是复杂类型,由基本类型组成。</p><p>简单类型的组合。</p><h6 id="创建对象方式"><a href="#创建对象方式" class="headerlink" title="创建对象方式"></a>创建对象方式</h6><ul><li>var ob = {};</li><li>var ob2 = new Object();</li><li>var ob3 = Object.create(Object.prototype);</li></ul><h6 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h6><p>person[‘name’] <strong>一定要有单引号,否则被视为变量名</strong></p><p>person.name <strong>key符合标识符规范的时候才可以这么用,切记!</strong></p><p>❗ <strong>注意</strong></p><p>空字符串也可以作为对象的key,使用方式为person[‘’]=‘superman’</p><p>如果key不加单引号,就必须遵循标识符规则(不可以数字开头,中间无空格,必须符合变量名规则)</p><blockquote><ul><li>第一个字符,可以是任意 Unicode 字母(包括英文字母和其他语言的字母),以及美元符号(<code>$</code>)和下划线(<code>_</code>)。</li><li>第二个字符及后面的字符,除了 Unicode 字母、美元符号和下划线,还可以用数字<code>0-9</code>。</li></ul></blockquote><p>所以9a不可以作为key,但是‘9a’可以作为key。使用person[‘9a’]</p><blockquote><p>对象的键为字符串类型,将其他类型作为key,会转为字符串类型。</p></blockquote><p>对象自己可以作为某个key的value,例如:</p><p>var person = {age:18,self:person},但是第一次定义后打印person是{age:18,self:undefined}</p><p>再定义一次var person = {age:18,self:person},</p><p>然后打印就成了{age:18,self:{age:18,self:undefined}},一次次的递归。</p><p>对象中的方法</p><p>delete person[‘name’] //把key和value都删除了,返回true说明删除成功</p><p>‘name’ in person //成false了</p><p>person.name = undefined //相当于只是把’name’对应的value删除了,key还在。</p><blockquote><p>for…in…</p><p>可以遍历对象中的key,但注意输出的key是随即顺序不是固定顺序</p><p>for(var key in person){console.log(key);}</p><p>遍历对象中的value则用以下写法:</p><p>for(var key in person){console.log(person[key]);}</p><p>//注意不是person.key,因为key是获取到的字符串,person.key相当于person[‘key’]肯定是错误的</p><p>一起打印使用:</p><p>console.log(key,person[key])</p></blockquote><p>typeof 返回类型名字符串</p><p>缺陷:</p><ol><li>typeof null //‘object’</li><li>typeof function //‘function’</li></ol>]]></content>