7、svg、D3、ES6|Proxy|await、Common与ES6解构变量、TS泛型接口|类继承实例、jQuery、Error错误、日期时间|倒计时|时区区时、数据类型|类数组|数字转化|对象相关with性能、函数之预解释|闭包|内存泄漏、节流去抖|柯里化|点透、循环for、设计模式、业务逻辑接口(4000行)

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
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
一、svg
  <html>
    <head>
      <meta charset="utf-8">
      <title>svg子标签</title>
      <style>
        .color{
          color: rgb(185, 125, 125);
        }
        .fontWeight{
          font-weight: 900;
        }
        .flex{
          display: flex;
        }
        .flex > pre{
          margin: 0;
        }
        .svgUp{ /* svg标签,默认值,width:300px; height:150px */
          width: 500px;
          height: 130px;
        }
        .svgMiddle{ /* svg标签,默认值,width:300px; height:150px */
          width: 500px;
          height: 100px;
        }
        .svgDown{ /* svg标签,默认值,width:300px; height:150px */
          width: 500px;
          height: 80px;
        }
      </style>
    </head>
    <body style="zoom:1">
      <div>
        <div class="fontWeight">SVG</div>
        <div>教程,https://www.cainiaojc.com/svg/svg-tutorial.html</div>
        <div>使用,"<"img src="svg-icon.svg"">"</div>
        <div>坐标,左上角的坐标是0,0--这点特别重要</div> 
      </div>
      <div>
        <div class="fontWeight">一、svg标签下-基本标签-形状</div>
        <div class="flex">
          <pre>
            1、直线
              "<"line x1="0" y1="20" x2="200" y2="70"
                stroke="gray"
                stroke-width="2"
              /">"
            <svg class="svgUp">
              <line x1="0" y1="20" x2="200" y2="70" stroke="gray" stroke-width="2"/>
            </svg>
          </pre>
          <pre>
            2、折线
              "<"polyline points="20,10 30,100 170,50 70,50"
                  style="fill:#ccc;
                    stroke:#000;
                    stroke-width:2"
              /">"
            <svg class="svgUp">
              <polyline points="20,10 30,100 170,50 70,50" style="fill:#ccc;stroke: #000;stroke-width:2"/>
            </svg>
          </pre>
          <pre>
            3、多边形
              "<"polygon points="20,10 30,100 170,50 70,50"
                  style="fill:#ccc;
                    stroke:#000;
                    stroke-width:2"
              /">"
            <svg class="svgUp">
              <polygon points="20,10 30,100 170,50 70,50" style="fill:#ccc; stroke:#000;stroke-width:2"/>
            </svg>
          </pre>
        </div>
        <div class="flex">
          <pre>
            4、矩形
              fill-opacity,属性定义填充颜色透明度(合法的范围是:0到1)
              stroke-opacity,属性定义笔触颜色的透明度(合法的范围是:0到1)
              "<"rect x="20" y="20" width="250" height="40"
                  fill="gray"
              /">"
            <svg class="svgMiddle">
              <rect x="20" y="20" width="250" height="40" fill="gray"/>
            </svg>
          </pre>
          <pre>
            5、圆形
              cx和cy,圆点的x和y坐标,默认为(0,0);r,圆的半径
              "<"circle cx="50" cy="50" r="40"
                  style="fill:gray;"
              /">"
            <svg class="svgMiddle">
              <circle cx="50" cy="50" r="40" style="fill:gray;"/>
            </svg>
          </pre>
          <pre>
            6、椭圆
            cx和cy,圆点的x和y坐标,默认为(0,0);rx和ry,水平和垂直半径
            "<"ellipse cx="110" cy="50" rx="100" ry="40"
                style="fill:grey;"
            /">"
            <svg class="svgMiddle">
              <ellipse cx="110" cy="50" rx="100" ry="40" style="fill:grey;"/>
            </svg>
          </pre> 
        </div>
      </div>
      <div class="flex">
        <div>
          <div class="fontWeight">二、svg标签下-组合标签-形状</div>
          <pre>
            1、示例
              <svg class="svgDown">
                <symbol id="shapeA">
                  <circle cx="0" cy="0" r="60" ></circle>
                </symbol>
                <symbol id="shapeB">
                  <path d="M0 50 L50 0 L50 50 Z" />
                </symbol>
                <defs>
                  <g id="shapeC">
                    <rect x="0" y="0" width="50" height="50" ></rect>
                  </g>
                  <g id="shapeD">
                    <circle cx="24" cy="24" r="24" ></circle>
                    <path d="M0 50 L120 0 L120 50 Z" />
                  </g>
                </defs>
                <use xlink:href="#shapeA" x="0" y="20" ></use>
                <use xlink:href="#shapeB" x="100" y="30" ></use>
                <use xlink:href="#shapeC" x="200" y="30" ></use>
                <use xlink:href="#shapeD" x="300" y="30" ></use>
              </svg>
            附、示例
              <!-- <template>
                <svg :class="svgClass">
                  <use :xlink:href="iconName" :fill="color" />
                </svg>
              </template> -->
          </pre>
          <pre class="color">
            2、标签
              "<"use xlink:href="#shapeA" x="0" y="30"">""<"/use">"
              (1)标签
                A、symbol,定义一个形状,被use引用后显示
                B、defs,定义多个形状,被use引用后显示
                  g,定义多个形状里的一个形状
                C、use,使用形状
              (2)属性
                A、xlink:href,是svg的一种属性,
                  用于定义svg文档中的元素与外部资源之间的链接,包括图片、音频、视频等
          </pre>
        </div>
        <div>
          <div class="fontWeight">三、svg标签下-属性</div>
          <pre>
            1、示例
            <?xml version="1.0" standalone="no"?>
            <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
            <svg
              viewBox="0 0 1024 1024"
              xmlns="http://www.w3.org/2000/svg"
              xmlns:xlink="http://www.w3.org/1999/xlink"
              id="svgID"
              class="icon"
              t="1701073968299"
              version="1.1" 
              width="见下面script"
              height="见下面script"
            >
              <path
                d="
                  M1010.036364 465.454545L539.927273 9.309091c-13.963636-13.963636-41.890909-13.963636-55.854546 0L13.963636 465.454545c-18.618182 13.963636-18.618182 41.890909 0 55.854546 13.963636 13.963636 41.890909 13.963636 55.854546 0l414.254545-395.636364c13.963636-13.963636 41.890909-13.963636 55.854546 0l414.254545 395.636364c13.963636 13.963636 41.890909 13.963636 55.854546 0 18.618182-13.963636 18.618182-41.890909 0-55.854546z
                  M372.363636 698.181818v186.181818c0 27.927273-18.618182 46.545455-46.545454 46.545455H232.727273c-27.927273 0-46.545455-18.618182-46.545455-46.545455v-279.272727c0-27.927273-18.618182-46.545455-46.545454-46.545454s-46.545455 18.618182-46.545455 46.545454v372.363636c0 27.927273 18.618182 46.545455 46.545455 46.545455h279.272727c27.927273 0 46.545455-18.618182 46.545454-46.545455v-186.181818c0-27.927273 18.618182-46.545455 46.545455-46.545454h93.090909c27.927273 0 46.545455-18.618182 46.545455-46.545455s-18.618182-46.545455-46.545455-46.545454H418.909091c-27.927273 0-46.545455 18.618182-46.545455 46.545454z
                  M837.818182 605.090909v279.272727c0 27.927273-18.618182 46.545455-46.545455 46.545455h-93.090909c-27.927273 0-46.545455 18.618182-46.545454 46.545454s18.618182 46.545455 46.545454 46.545455h186.181818c27.927273 0 46.545455-18.618182 46.545455-46.545455v-372.363636c0-27.927273-18.618182-46.545455-46.545455-46.545454s-46.545455 18.618182-46.545454 46.545454z"
                p-id="4219"
                fill="#000"
              ></path>
            </svg>
          </pre>
          <pre class="color">
            2、属性
            "<" 标签内容,免 /">"
              (1)viewBox,svg元素的视图框坐标是x y width height,如"0 0 1024 1024"
              (2)xmlns,xml命名空间,xml namespace,防止来自不同技术的元素发生冲突
              (3)xmlns:xlink,xlink在XML文档中创建超级链接的语言
              (4)id,见下面script
              (5)class,标签的样式
              (6)t,本代码生成时的时间
              (7)version,图片的版本
              (8)width,svg宽,见下面script
              (9)height,svg高,见下面script
            3、附xml标签的属性
              (1)standalone="no",文档会引用一个外部文件,!DOCTYPE后的内容,即为引用的内容
          </pre>
        </div>
        <div>
          <div class="fontWeight">四、path标签下-属性</div>
          <pre>
            1、示例
            <svg class="svgDown">
              <path d="M120 30 L10 80 L250 80 Z" fill="#000" stroke="red" stroke-width="2"/>
            </svg>
          </pre>
          <pre class="color">
            2、属性
              "<"path d="M120 30 L10 80 L250 80 Z"
                  fill="#000" stroke="red" stroke-width="2" /">"
              (1)属性
                A、d,包含所有的绘图命令,见(2)(3)
                B、fill,轮廓内的填充颜色
                C、stroke,轮廓内的描边颜色
                D、stroke-width,轮廓内的描边宽度
                附、关于样式的属性,可以写到class或style里
              (2)常用命令
                A、M:x,y moveto 将笔移动到指定点x,y而不绘图
                B、L:x,y Lineto 绘制一条从当前笔位置到指定点x,y的直线
                C、Z:封闭路径 通过从当前点到第一个点画一条线来封闭路径
              (3)不常用命令
                A、H:X 水平线 画一条水平线到定义的点,(指定的x,笔当前的y)
                C、V:y 垂直线 在由(定义的当前x,指定y)定义的点上画一条垂直线
          </pre>
        </div>
      </div>
      <div class="flex">
        <div>
          <div class="fontWeight">五、mask遮罩</div>
          <pre>
            1、示例
            <svg width="75" height="75" viewBox="0 0 75 75" fill="none" xmlns="http://www.w3.org/2000/svg" >
              <mask id="mask0" x="0" y="0" mask-type="alpha">
                <circle cx="37.5" cy="37.5" r="37.5" fill="#0042DA" />
              </mask>
              <g mask="url(#mask0)"><!-- 属性mask用来引用一个遮罩元素 -->
                <rect x="-30" y="-43" width="131" height="154" fill="#0042DA" />
                <rect x="2.50413" y="120.333" width="81.5597" height="86.4577" rx="2.5"
                  transform="rotate(-52.6423 2.50413 120.333)" stroke="#FED23D" stroke-width="5" />
                <circle cx="76.5" cy="-1.5" r="29" stroke="#FF8E20" stroke-width="5" />
                <path d="M-49.8224 22L-15.5 -40.7879L18.8224 22H-49.8224Z" stroke="#F7F8FF" stroke-width="5" />
              </g>
            </svg>
          </pre>
        </div>
      </div>
    </body>
  </html>
  <script>
    document.getElementById("svgID").setAttribute("width", "50");
    document.getElementById("svgID").setAttribute("height", "50");
  </script>
 
二、D3之基础用法、综合用法、数据平放、数据立放、饼图
1、基础用法(绑定文字)
  <html>
      <head>
          <meta charset="utf-8">
          <title>Hello World</title>
          <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
      </head>
      <body>
          <p></p>
          <p></p>
          <p></p>
      </body>
  </html>
  <script> 
      var dataset = ["sun","moon","you"];
      var body = d3.select("body");
      var p = body.selectAll("p");
      p.data(dataset).text(function(d, i){
          return "I love " + d;
    });
    console.log(d3.range(5));
  </script>
2、综合用法(柱形图,含选择集、数据绑定、比例尺、坐标轴)
  <html>
      <head>
          <meta charset="utf-8">
          <title>Hello World</title>
          <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
          <style>
      .axis path,
      .axis line{
        fill: none;
        stroke: black;
        shape-rendering: crispEdges;
      }
      .axis text {
        font-family: sans-serif;
        font-size: 11px;
      }
      </style>
      </head>
      <body>
      </body>
  </html>
  <script> 
    //画布大小
      var width = 400;
      var height = 400;
      //在 body 里添加一个 SVG 画布  
      var svg = d3.select("body")
      .append("svg")
      .attr("width", width)
      .attr("height", height);
      //画布周边的空白
      var padding = {left:30, right:30, top:20, bottom:20};
      //定义一个数组
      var dataset = [10, 20, 30, 40, 33, 24, 12, 5];
      //x轴的比例尺
      var xScale = d3.scale.ordinal()
      .domain(d3.range(dataset.length))
      .rangeRoundBands([0, width - padding.left - padding.right]);
      //y轴的比例尺
      var yScale = d3.scale.linear()
      .domain([0,d3.max(dataset)])
          .range([height - padding.top - padding.bottom, 0]);   
      //定义x轴
      var xAxis = d3.svg.axis()
      .scale(xScale)
      .orient("bottom");
      //定义y轴
      var yAxis = d3.svg.axis()
      .scale(yScale)
          .orient("left");
      //矩形之间的空白
    var rectPadding = 4;
      //添加矩形元素
      var rects = svg.selectAll(".MyRect")
          .data(dataset)
          .enter()
          .append("rect")
          .attr("class","MyRect")
          .attr("transform","translate(" + padding.left + "," + padding.top + ")")
          .attr("x", function(d,i){
              return xScale(i) + rectPadding/2;
          })
          .attr("y",function(d){
              return yScale(d);
          })
          .attr("width", xScale.rangeBand() - rectPadding )
          .attr("height", function(d){
              return height - padding.top - padding.bottom - yScale(d);
          })
          .attr("fill","steelblue");
      //添加文字元素
      var texts = svg.selectAll(".MyText")
          .data(dataset)
          .enter()
          .append("text")
          .attr("class","MyText")
          .attr("transform","translate(" + padding.left + "," + padding.top + ")")
          .attr("x", function(d,i){
              return xScale(i) + rectPadding/2;
          } )
          .attr("y",function(d){
              return yScale(d);
          })
          .attr("dx",function(){
              return (xScale.rangeBand() - rectPadding)/2;
          })
          .attr("dy",function(d){
              return 20;
          })
          .text(function(d){
              return d;
          })           
          .style({
              "fill":"#FFF",
              "text-anchor":"middle"
          });
      //添加x轴
      svg.append("g")
          .attr("class","axis")
          .attr("transform","translate(" + padding.left + "," + (height - padding.bottom) + ")")
          .call(xAxis);
      //添加y轴
      svg.append("g")
          .attr("class","axis")
          .attr("transform","translate(" + padding.left + "," + padding.top + ")")
          .call(yAxis);
  </script>
3、数据平放
(1)数据平放(无比例尺)
  <html>
      <head>
          <meta charset="utf-8">
          <title>Hello World</title>
          <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
      </head>
      <body>
      </body>
  </html>
  <script> 
    var dataset = [ 250 , 210 , 170 , 130 , 90 ];//数据(表示矩形的宽度)
      var width = 300;//画布的宽度
    var height = 300;//画布的高度
    var svg = d3.select("body")//选择文档中的body元素
      .append("svg")//添加一个svg元素
      .attr("width", width)//设定宽度
      .attr("height", height);//设定高度 
    var rectHeight = 25;//每个矩形所占的像素高度(包括空白)
    svg.selectAll("rect")
      .data(dataset)
      .enter()
      .append("rect")
      .attr("x",20)
      .attr("y",function(d,i){
          return i * rectHeight;
      })
      .attr("width",function(d){
          return d;
      })
      .attr("height",rectHeight-10)
      .attr("fill","steelblue");
  </script>
(2)数据平放(有比例尺)
  <html>
      <head>
          <meta charset="utf-8">
          <title>Hello World</title>
          <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
      </head>
      <body>
      </body>
  </html>
  <script> 
    var dataset = [ 250 , 210 , 170 , 130 , 90 ];//数据(表示矩形的宽度)
    var width = 300;//画布的宽度
    var height = 300;//画布的高度
    var svg = d3.select("body")//选择文档中的body元素
      .append("svg")//添加一个svg元素
      .attr("width", width)//设定宽度
      .attr("height", height);//设定高度 
    var rectHeight = 25;//每个矩形所占的像素高度(包括空白)
    var dataset = [ 2.5 , 2.1 , 1.7 , 1.3 , 0.9 ];
      var linear = d3.scale.linear()
          .domain([0, d3.max(dataset)])
          .range([0, 250]);
      var rectHeight = 25;//每个矩形所占的像素高度(包括空白)
      svg.selectAll("rect")
          .data(dataset)
          .enter()
          .append("rect")
          .attr("x",20)
          .attr("y",function(d,i){
              return i * rectHeight;
          })
          .attr("width",function(d){
              return linear(d);//在这里用比例尺
          })
          .attr("height",rectHeight-10)
          .attr("fill","steelblue");
  </script>
4、数据立放
(1)数据立放(无比例尺)
  <html>
      <head>
          <meta charset="utf-8">
          <title>Hello World</title>
          <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
      </head>
      <body>
      </body>
  </html>
  <script> 
    var dataset = [ 250 , 210 , 170 , 130 , 90 ];//数据(表示矩形的宽度)
      var width = 300;//画布的宽度
    var height = 300;//画布的高度
    var svg = d3.select("body")//选择文档中的body元素
      .append("svg")//添加一个svg元素
      .attr("width", width)//设定宽度
      .attr("height", height);//设定高度 
    var rectHeight = 25;//每个矩形所占的像素高度(包括空白)
    svg.selectAll("rect")
      .data(dataset)
      .enter()
      .append("rect")
      .attr("x",function(d,i){
        return i * rectHeight;
      })
      .attr("y",function(d,i){
        return height - d;
      })
      .attr("width",rectHeight-10)
      .attr("height",function(d){
        return d;
      })
      .attr("fill","steelblue");
  </script>
(2)数据立放(有比例尺)
  <html>
      <head>
          <meta charset="utf-8">
          <title>Hello World</title>
          <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
      </head>
      <body>
      </body>
  </html>
  <script> 
    var dataset = [ 250 , 210 , 170 , 130 , 90 ];//数据(表示矩形的宽度)
      var width = 300;//画布的宽度
    var height = 300;//画布的高度
    var svg = d3.select("body")//选择文档中的body元素
      .append("svg")//添加一个svg元素
      .attr("width", width)//设定宽度
      .attr("height", height);//设定高度 
    var rectHeight = 25;//每个矩形所占的像素高度(包括空白)
    var dataset = [ 2.5 , 2.1 , 1.7 , 1.3 , 0.9 ];
      var linear = d3.scale.linear()
          .domain([0, d3.max(dataset)])
          .range([0, 250]);
      var rectHeight = 25;//每个矩形所占的像素高度(包括空白)
      svg.selectAll("rect")
          .data(dataset)
          .enter()
          .append("rect")
          .attr("x",function(d,i){
              return i * rectHeight;
          })
          .attr("y",function(d,i){
              return 250 - linear(d) ;
          })
          .attr("width",rectHeight-10)
          .attr("height",function(d){
              return linear(d);//在这里用比例尺
          })
          .attr("fill","steelblue");
  </script>
5、饼图
  <!DOCTYPE html>
  <html>
    <head>
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
      <title></title>
      <script src="https://cdn.bootcdn.net/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
      <script src="https://cdn.bootcdn.net/ajax/libs/d3/3.2.8/d3.js"></script>
      <script type="text/javascript">
        //准备数据
        var chartData = [
          { label: '漯河', value: 2 },
          { label: '舞阳', value: 3 },
          { label: '郭庄', value: 2 },
          { label: '北京', value: 3 },
          { label: '漯河3', value: 2 },
          { label: '北京3', value: 3 },
          { label: '漯河4', value: 2 },
          { label: '北京4', value: 3 },
          { label: '郭庄2', value: 4 }
        ];
        var colors = [
          '#2484c1',
          '#65a620',
          '#7b6888',
          '#a05d56',
          '#961a1a',
          '#d8d23a',
          '#e98125',
          '#d0743c',
          '#635222'
        ];
        var title = [
          {
            text: 'www.guowenke.tk',
            color: '#333333',
            fontSize: 18,
            font: 'arial'
          }
        ];
        //定义画布大小
        var canvasWidth = 600;
        var canvasHeight = 400;
        $(function () {
          var svg = d3
            .select('#pie')
            .append('svg')
            .attr('width', canvasWidth)
            .attr('height', canvasHeight);
          //标题
          svg
            .selectAll('.title')
            .data(title)
            .enter()
            .append('text')
            .text(function (d) {
              return d.text;
            })
            .attr('class', 'title')
            .attr('fill', function (d) {
              return d.color;
            })
            .style('font-family', function (d) {
              return d.font;
            })
            .attr('x', canvasWidth / 2)
            .attr('y', 30);
          //绘图
          //确定饼图中心
          var pieChartElement = svg
            .append('g')
            .attr(
              'transform',
              'translate(' + canvasWidth / 2 + ',' + canvasHeight / 2 + ')'
            );
 
          //创建弧生成器
          var arc = d3.svg
            .arc()
            .innerRadius(canvasHeight * 0)
            .outerRadius((canvasHeight * 0.8) / 3)
            .startAngle(0)
            .endAngle(function (d) {
              return (d.value / getSumData(chartData)) * 2 * Math.PI;
            });
 
          var arcs = pieChartElement
            .selectAll('g')
            .data(chartData)
            .enter()
            .append('g')
            .attr('transform', function (d, i) {
              var angle = 0;
              if (i > 0) {
                angle = getSegmentAngle(i - 1, chartData, getSumData(chartData));
              }
              return 'rotate(' + angle + ')';
            });
          arcs
            .append('path')
            .attr('fill', function (d, i) {
              return colors[i];//设定弧的颜色
            })
            .attr('d', function (d) {
              return arc(d);//使用弧生成器
            });
 
          //添加标签组
          var outerLabelGroupData = [];
          var lineCoordGroups = [];
          var labels = svg.append('g').attr('class', 'labels');
          var labelGroup = labels
            .selectAll('.labelGroup')
            .data(chartData)
            .enter()
            .append('g')
            .attr('class', 'labelGroup');
          labelGroup.append('text').text(function (d, i) {
            return d.label + ':' + d.value;
          });
          d3.selectAll('.labelGroup')
            .each(function (d, i) {
              var labelGroupDims = $('.labelGroup').get(i).getBBox();
              var angle = getSegmentAngle(i, chartData, getSumData(chartData), {
                midpoint: true
              });
              var originalX = canvasWidth / 2;
              var originalY = canvasHeight / 2 - ((canvasHeight * 0.8) / 3 + 3);
              var newCords = rotate(
                originalX,
                originalY,
                canvasWidth / 2,
                canvasHeight / 2,
                angle
              );
              if (angle > 180) {
                newCords.x -= labelGroupDims.width + 28;
              } else {
                newCords.x += 28;
              }
              outerLabelGroupData[i] = {
                x: newCords.x,
                y: newCords.y,
                w: labelGroupDims.width,
                h: labelGroupDims.height
              };
            })
            .attr('transform', function (d, i) {
              return (
                'translate(' +
                outerLabelGroupData[i].x +
                ',' +
                outerLabelGroupData[i].y +
                ')'
              );
            });
          d3.selectAll('.labelGroup').each(function (d, i) {
            var angle = getSegmentAngle(i, chartData, getSumData(chartData), {
              midpoint: true
            });
            var originalX = canvasWidth / 2;
            var originalY = canvasHeight / 2 - ((canvasHeight * 0.8) / 3 + 3);
            var newCords = rotate(
              originalX,
              originalY,
              canvasWidth / 2,
              canvasHeight / 2,
              angle
            );
            var labelXMargin = 6;
            var originCoords = newCords;
            var heightOffset = outerLabelGroupData[i].h / 5;
            var quarter = Math.floor(angle / 90);
            var midPoint = 4;
            var x2, y2, x3, y3;
            if (quarter === 2 && angle === 180) {
              quarter = 1;
            }
            switch (quarter) {
              case 0:
                x2 =
                  outerLabelGroupData[i].x -
                  labelXMargin -
                  (outerLabelGroupData[i].x - labelXMargin - originCoords.x) / 2;
                y2 =
                  outerLabelGroupData[i].y +
                  (originCoords.y - outerLabelGroupData[i].y) / midPoint;
                x3 = outerLabelGroupData[i].x - labelXMargin;
                y3 = outerLabelGroupData[i].y - heightOffset;
                break;
              case 1:
                x2 =
                  originCoords.x +
                  (outerLabelGroupData[i].x - originCoords.x) / midPoint;
                y2 =
                  originCoords.y +
                  (outerLabelGroupData[i].y - originCoords.y) / midPoint;
                x3 = outerLabelGroupData[i].x - labelXMargin;
                y3 = outerLabelGroupData[i].y - heightOffset;
                break;
              case 2:
                var startOfLabelX =
                  outerLabelGroupData[i].x +
                  outerLabelGroupData[i].w +
                  labelXMargin;
                x2 = originCoords.x - (originCoords.x - startOfLabelX) / midPoint;
                y2 =
                  originCoords.y +
                  (outerLabelGroupData[i].y - originCoords.y) / midPoint;
                x3 =
                  outerLabelGroupData[i].x +
                  outerLabelGroupData[i].w +
                  labelXMargin;
                y3 = outerLabelGroupData[i].y - heightOffset;
                break;
              case 3:
                var startOfLabel =
                  outerLabelGroupData[i].x +
                  outerLabelGroupData[i].w +
                  labelXMargin;
                x2 = startOfLabel + (originCoords.x - startOfLabel) / midPoint;
                y2 =
                  outerLabelGroupData[i].y +
                  (originCoords.y - outerLabelGroupData[i].y) / midPoint;
                x3 =
                  outerLabelGroupData[i].x +
                  outerLabelGroupData[i].w +
                  labelXMargin;
                y3 = outerLabelGroupData[i].y - heightOffset;
                break;
            }
            lineCoordGroups[i] = [
              { x: originCoords.x, y: originCoords.y },
              { x: x2, y: y2 },
              { x: x3, y: y3 }
            ];
          });
          var lineGroups = svg
            .append('g')
            .attr('class', 'lineGroups')
            .style('opacity', 1);
 
          var lineGroup = lineGroups
            .selectAll('.lineGroup')
            .data(lineCoordGroups)
            .enter()
            .append('g')
            .attr('class', 'lineGroup');
          var lineFunction = d3.svg
            .line()
            .interpolate('basis')
            .x(function (d) {
              return d.x;
            })
            .y(function (d) {
              return d.y;
            });
          lineGroup
            .append('path')
            .attr('d', lineFunction)
            .attr('stroke', function (d, i) {
              return colors[i];
            })
            .attr('stroke-width', 1)
            .attr('fill', 'none');
          function rotate(x, y, xm, ym, a) {
            a = (a * Math.PI) / 180;// 转为弧度
            var cos = Math.cos,
              sin = Math.sin,
              xr = (x - xm) * cos(a) - (y - ym) * sin(a) + xm,
              yr = (x - xm) * sin(a) + (y - ym) * cos(a) + ym;
            return { x: xr, y: yr };
          }
          function getSumData(data) {
            var sumData = 0;
            var countData = data.length;
            for (var i = 0; i < countData; i++) {
              sumData += data[i].value;
            }
            return sumData;
          }
          function getSegmentAngle(index, data, sumValue, opts) {
            var options = $.extend(
              {
                compounded: true,
                midpoint: false
              },
              opts
            );
            var currValue = data[index].value;
            var fullValue;
            fullValue = 0;
            for (var i = 0; i <= index; i++) {
              fullValue += data[i].value;
            }
          //值转为角度
            var angle = (fullValue / sumValue) * 360;
            if (options.midpoint) {
              var currAngle = (currValue / sumValue) * 360;
              angle -= currAngle / 2;
            }
            return angle;
          }
        });
      </script>
    </head>
    <body>
      <div id="pie"></div>
    </body>
  </html>
6、拓扑图
  <!DOCTYPE>
  <html>
    <meta charset="utf-8">
    <title>Radial Dendrogram</title>
    <link rel="stylesheet" type="text/css" href="https://unpkg.com/@observablehq/notebook-inspector@1/dist/notebook-inspector-style.css">
    <body>
      <div id="console" style="width: 100%;"></div>
    </body>
  </html>
  <script type="module">
    import { Inspector, Runtime } from "https://unpkg.com/@observablehq/notebook-runtime@1?module";
    //URL: https://observablehq.com/@13716164418/radial-dendrogram
    const m0 = {
      id: "myId",
      variables: [
        {
          inputs: ["md"],
          value: (function (md) {
            return md`# Radial Dendrogram`
          })
        },
        {
          name: "chart",
          inputs: ["tree", "d3", "data", "DOM", "width"],
          value: (function (tree, d3, data, DOM, width) {
            const root = tree(d3.hierarchy(data)
              .sort((a, b) => (a.height - b.height) || a.data.name.localeCompare(b.data.name)));
            const svg = d3.select(DOM.svg(width, width))
              .style("width", "100%")
              .style("height", "auto")
              .style("padding", "10px")
              .style("box-sizing", "border-box")
              .style("font", "10px sans-serif");
            const g = svg.append("g");
            const link = g.append("g")
              .attr("fill", "none")
              .attr("stroke", "#555")
              .attr("stroke-opacity", 0.4)
              .attr("stroke-width", 1.5)
              .selectAll("path")
              .data(root.links())
              .enter().append("path")
              .attr("d", d3.linkRadial().angle(d => d.x).radius(d => d.y));
            const node = g.append("g")
              .attr("stroke-linejoin", "round")
              .attr("stroke-width", 3)
              .selectAll("g")
              .data(root.descendants().reverse())
              .enter().append("g")
              .attr("transform", d => `rotate(${d.x * 180 / Math.PI - 90}) translate(${d.y},0)`);
            node.append("circle")
              .attr("fill", d => d.children ? "#555" : "#999")
              .attr("r", 2.5);
            node.append("text")
              .attr("dy", "0.31em")
              .attr("x", d => d.x < Math.PI === !d.children ? 6 : -6)
              .attr("text-anchor", d => d.x < Math.PI === !d.children ? "start" : "end")
              .attr("transform", d => d.x >= Math.PI ? "rotate(180)" : null)
              .text(d => d.data.name)
              .filter(d => d.children)
              .clone(true).lower()
              .attr("stroke", "white");
            document.body.appendChild(svg.node());
            const box = g.node().getBBox();
            svg.remove()
              .attr("width", box.width)
              .attr("height", box.height)
              .attr("viewBox", `${box.x} ${box.y} ${box.width} ${box.height}`);
            return svg.node();
          })
        },
        {
          name: "data",
          inputs: ["require"],
          value: (function (require) {
            return require("@observablehq/flare")
          })
        },
        {
          name: "width",
          value: (function () {
            return 932
          })
        },
        {
          name: "radius",
          inputs: ["width"],
          value: (function (width) {
            return width / 2
          })
        },
        {
          name: "tree",
          inputs: ["d3", "radius"],
          value: (function (d3, radius) {
            return d3.cluster().size([2 * Math.PI, radius - 100])
          })
        },
        {
          name: "d3",
          inputs: ["require"],
          value: (function (require) {
            return require("d3@5")
          })
        }
      ]
    };
    const notebook = {
      id: "myId",
      modules: [m0]
    };
    export default notebook;
    Runtime.load(notebook, Inspector.into(document.getElementById("console")));
  </script>
 
三、ES6基础
  来源,http://caibaojian.com/es6
1、Set,唯一值数组,ES6提供的新的数据结构,类似于数组,但是成员的值都是唯一的,没有重复的
  (1)并集与去重
    A、并集
      var a = new Set([1, 2, 3]);
      var b = new Set([4, 3, 2]);
      var c = new Set([...a, ...b]); //{1, 2, 3, 4}
      console.log( c ) //Set(4) { 1, 2, 3, 4 }
    B、去重
      var list = new Set([1, 1, 2, 3, 3, 4]); //{1, 2, 3, 4}
      console.log( list ) //Set(4) { 1, 2, 3, 4 }
  (2)交集与有无
    A、交集
      var a = new Set([1, 2, 3]);
      var b = new Set([4, 3, 2]);
      var c = new Set([...a].filter(x => b.has(x))); //{2, 3}
      console.log( c ) //Set(2) { 2, 3 }
    B、有无
      var list = new Set([1,2,3,4])
      var isHas = list.has(2)
    console.log( isHas ) //true;
  (3)添加与删除
    A、添加
      var list=new Set();
      list.add(1)
      list.add(2).add(3).add(3) //3只被添加1次
      console.log( list ) //Set(3) { 1, 2, 3 }
    B、删除
      a、1个
        var list = new Set([1,20,30,40])
        list.delete(30) //删除值为30的元素,这里的30并非下标
        console.log( list ) //Set(3) { 1, 20, 40 }
      b、所有
        var list = new Set([1,2,3,4])
        list.clear()
        console.log( list ) //Set(0) {}
  (4)获取
    A、遍历
      var list = new Set([1,2,3,4])
      for (let item of list) {
        console.log( item )//1 2 3 4
      }
    B、...
      var list = new Set([1,2,3,4])
      list = [...list] //转成数组
      console.log( list ) //[ 1, 2, 3, 4 ]
2、Map,任意键对象,ES6提供的新的数据结构,类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键
  (1)示例1,
    var obj = new Map()
    obj.set(0, "attack_type") //键是数值
    obj.set("age", 20) //键是字符串
    obj.set(undefined, "definition") //键是undefined
    for (const [key, value] of obj) {
      console.log(key, value);
    }
    /* 0 attack_type
      age 20
      undefined definition */
  (2)示例2,子数组的第一个元素表示键(key),第二个元素表示值(value)
    var obj = new Map([['name', '张三'], ['age', 18], ['sex', '男']])
    for (const [key, value] of obj) {
      console.log(key, value);
    }
    /* name 张三
      age 18
      sex 男 */
3、Symbol,ES6提供的新的数据类型
  (1)原生函数,String()、Number()、Boolean()、Array()、Object()、Function()、RegExp()、Date()、Error()、Symbol()
  (2)原始数据类型,未定义(undefined)、空值(null)、布尔值(boolean)、字符串(string)、数值(number)、对象(object)、符号(symbol)
  (3)ES5的对象属性名都是字符串,这容易造成属性名冲突的问题
  (4)symbol表示独一无二的值,"真实值"无法获取,Symbol类型没有字面量,感觉类似于对象的实例
  (5)示例1,A页面和B页面的变量名有可能相同,造成覆盖,因此Symbol的作用不大
    var aaa = Symbol('foo'); //A页面
    var bbb = Symbol('foo'); //B页面
    console.log(aaa === bbb); //false
  (5)示例2,
    let ccc = Symbol.for('foo'); //创建新符号
    let ddd = Symbol.for('foo'); //重用已有符号
    console.log(ccc === ddd); //true
  (6)示例3,
    var s1 = Symbol('foo');
    var s2 = Symbol('bar');
    var s3 = Symbol('baz');
    var s4 = Symbol('qux');
    var sss = { //[属性],会对属性进行读取,并且转换成字符串。[s1]是读取了Symbol的字符串键'foo'
      [s1]: 'foo val'
    };
    //或 sss[s1] = 'foo val';
    console.log(sss); // { [Symbol(foo)]: 'foo val' }
4、解构赋值
  (1)解构对象
    var person = {name: 'zhangsan', address: {province: '江苏', city: '南京'}};
    var {name, address:{province, city}} = person;//有key,无value
    console.log(name, province, city);
  (2)解构数组
    var arr = [1, 2, 3];
    var [a, b, c] = arr;
    console.log(a, b, c);
5、varletconst的区别(变量提升、声明1次、块级作用域)
  (1)变量提升,var有变量提声,letconst没有变量提声
  (2)同一变量的声明次数,var多次,let和const1次
  (3)块级作用域,
    A、var没有块级作用域,{}内外是同一作用域
    B、letconst有块级作用域,{}内外是子父作用域
    C、示例
      if(true){
        let x = 5;
      }else{
        var x = 10;
      }
      console.log(x);
  (4)重新赋值,varlet能重新赋值,const不能重新赋值
    A、const对象变量的组成可以重新赋值
6、箭头函数和普通函数的区别(new、arguments、this、call、apply、prototype、Generator、yield),
  (1)arguments,用rest参数…解决,
    A、报错
      let foo = () => {
        console.log(arguments)
      }
      foo(1, 2, 3)
    B、不报错
      let foo = (...args) => {
        console.log(args)
      }
      foo(1, 2, 3)
      //[1, 2, 3]
  (2)参数个数
    A、0或多个参数,需要用() //var fn=()=>5
    B、1个参数,不需要() //var fn=v=>v
  (3)分句个数
    附:var 变量=(参数)=>函数体
    A、多个分句,用{}和return
    B、1个分句,不用{}和return
    C、1个分句,返回值为对象,用({})
  (4)this,宿主对象的this
    A、示例一
      var value = 6;
      var obj = {
        value: 5,
        fn: function fnIn() {
          setTimeout(() => {
            console.log(this.value); //5,宿主对象为fn,其this为obj
          });
        },
      };
      obj.fn();
    B、示例二
      var value = 6;
      var obj = {
        value: 5,
        fn: () => {
          console.log(this.value); //6,宿主对象为obj,其this为window
        },
      };
      obj.fn();
  (5)call和apply,对this没有影响
  (6)不能使用new,不能作为构造函数,
  (7)没有原型属性,prototype,
  (8)不能做Generator函数,不能使用yield关键字,
7、访问器属性
   来源,https://blog.csdn.net/weixin_44410783/article/details/110223586
  (1)ES6对象
    通过getset定义一个属性,代替内部属性被外部访问
    var obj = {
      _num : 0,
      set num(value){//有且仅有一个参数
        this._num = value;
      },
      get num(){//不能有参数,必须返回内容
        return this._num;
      }
    }
    console.log( obj.num );
    obj.num = 1;
    console.log( obj.num );
  (2)ES6类
    class Emp{
      constructor(name,age){
        this.name=name;
        this.age=age;
        Object.defineProperty(this,"_eage",{
          value:this.age,
          writable:true,
          enmerable:false,
          configurable:false
        })
      }
      get age(){
        return this._eage;
      }
      set age(v){
        if(v>18){
          this._eage=v
        }else{
          throw Error("禁");
        }
      }
    }
    var e=new Emp('tom',28)
    console.log(e)
    e.age=49
    console.log(e.age)
8、模板字符串
  (1)在模板字符串html中,用`<div>${ /* 注释内容 */'' }</div>`加注释
  (2)在模板字符串js中,用`${变量}`加变量
 
四、ES6进阶
附、Proxy对象与Reflect对象的方法的方法一一对应
1、Proxy,代理,内部拦截,Proxy必须针对Proxy实例进行操作,否则Proxy不起作用,
   示例1、const proxy = new Proxy(target, handler);
   示例2、
    var obj = {};
    var thisObj = new Proxy(obj, {
      get: function (target, key, receiver) {
        console.log(obj === target); //true
        if (key === 4) {
          return 5;
        }
        return 6;
      },
      set: function (target, key, value, receiver) {
        return Reflect.set(target, key, value, receiver);
      },
      has: function (target, key) {
        if (key[0] === "c") {
          return false;
        }
        return key in target;
      },
    });
    thisObj.count = 1;
    console.log(thisObj.count);
    console.log("count" in thisObj);
  (1)Proxy.apply(target, object, args)
    拦截 Proxy 实例作为函数调用的操作,比如proxy(...args)、proxy.call(object, ...args)、proxy.apply(...) 。
  (2)Proxy.construct(target, args)
    拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(...args)。
  (3)Proxy.defineProperty(target, propKey, propDesc)
    拦截Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs),返回一个布尔值。
  (4)Proxy.deleteProperty(target, propKey)
    拦截delete proxy[propKey]的操作,返回一个布尔值。
  (5)Proxy.get(target, propKey, receiver)
    拦截对象属性的读取,比如proxy.starFunction 和 proxy['starFunction']。
    如果propKey属性部署了读取函数,则读取函数的this绑定receiver(一个对象)。
  (6)Proxy.getOwnPropertyDescriptor(target, propKey)
    拦截Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象。
  (7)Proxy.getPrototypeOf(target)
    拦截Object.getPrototypeOf(proxy),返回一个对象。
  (8)Proxy.has(target, propKey)
    拦截propKey in proxy的操作,以及对象的hasOwnProperty方法,返回一个布尔值。
  (9)Proxy.isExtensible(target)
    拦截Object.isExtensible(proxy),返回一个布尔值。
  (10)Proxy.ownKeys(target)
    拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy),返回一个数组。
    该方法返回对象所有自身的属性,而Object.keys()仅返回对象可遍历的属性。
  (11)Proxy.preventExtensions(target)
    拦截Object.preventExtensions(proxy),返回一个布尔值。
  (12)Proxy.set(target, propKey, value, receiver)
    拦截对象属性的设置,比如proxy.starFunction = v或proxy['starFunction'] = v,返回一个布尔值。
  (13)Proxy.setPrototypeOf(target, proto)
    拦截Object.setPrototypeOf(proxy, proto),返回一个布尔值。
    如果目标对象是函数,那么还有两种额外操作可以拦截。
   另外,vue2用Object.defineProperty实现双向绑定,vue3用Proxy实现双向绑定
2、Reflect,反映,外部操纵,
   示例1、Reflect.method(target, ...args);
   示例2、
    function func1(a, b, c) {
      this.sum = a + b + c;
    }
    const args = [1, 2, 3];
    const object1 = new func1(...args);
    const object2 = Reflect.construct(func1, args);
    console.log(object2.sum);//expected output: 6
    console.log(object1.sum);//expected output: 6
  (1)Reflect.apply(fun,thisArg,args)
    等同于Function.prototype.apply.call(fun,thisArg,args)。一般来说,如果要绑定一个函数的this对象,可以这样写fn.apply(obj, args),但是如果函数定义了自己的apply方法,就只能写成Function.prototype.apply.call(fn, obj, args),采用Reflect对象可以简化这种操作。
    console.log(Reflect.apply(Math.floor, undefined, [1.75]));//expected output: 1
  (2)Reflect.construct(target, args)
    等同于new target(...args),这提供了一种不使用new,来调用构造函数的方法。
  (3)Reflect.deleteProperty(obj, name)
    等同于delete obj[name]。
  (4)Reflect.get(target, name, receiver)
    查找并返回target对象的name属性,如果没有该属性,则返回undefined
    如果name属性部署了读取函数,则读取函数的this绑定receiver
  (5)Reflect.getPrototypeOf(obj)
    读取对象的__proto__属性,对应Object.getPrototypeOf(obj)
  (6)Reflect.has(obj, name)
    等同于name in obj
  (7)Reflect.ownKeys(target)查找并返回target对象的所有属性,包括不可枚举属性和象征属性
    等同于Object.getOwnPropertyNames(target)
  (8)Reflect.set(target, name, value, receiver)
    设置target对象的name属性为value。如果name属性设置了赋值函数,则赋值函数的this绑定receiver
  (9)Reflect.setPrototypeOf(obj, newProto)
    设置对象的__proto__属性,对应Object.setPrototypeOf(obj, newProto)。
3、Iterator(遍历器)
  (1)以下遍历器(迭代器)模拟代码
    function createIterator(items) {
      var i = 0;
      return {
          next: function() {
              var done = (i >= items.length);
              var value = done ? undefined : items[i++] ;
              return {
                  done: done,
                  value: value
              };
          }
      };
    }
    var iterator = createIterator([1, 2, 3]);
    console.log(iterator.next()); //"{ value: 1, done: false }"
    console.log(iterator.next()); //"{ value: 2, done: false }"
    console.log(iterator.next()); //"{ value: 3, done: false }"
    console.log(iterator.next()); //"{ value: undefined, done: true }"
  (2)JavaScript原有的表示“集合”的数据结构,主要是数组(Array)和对象(Object),ES6又添加了Map和Set。
    这样四种数据结构只要部署了Iterator接口,就是”可遍历的“(iterable)。
    ES6规定,一个数据结构只要具有Symbol.iterator属性,就可以认为是“可遍历的”(iterable)。
    const obj = {
      [Symbol.iterator] : function () {
        return {
          next: function () {
            return {
              value: 1,
              done: true
            };
          }
        };
      }
    };
    上面代码中,对象obj是可遍历的(iterable),因为具有Symbol.iterator属性。
4、Generator 函数(生成器)
  (1)Generator函数有两个特征
    A、function关键字与函数名之间有一个星号
    B、函数体内部使用yield(即“产出”)语句,定义不同的内部状态
  (2)调用Generator函数后,该函数并不执行,返回的是一个指向内部状态的指针对象,也就是遍历器对象(Iterator Object)
  (3)调用遍历器对象的next方法,使得指针移向下一个状态
  (4)也就是说,每次调用next方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个yield语句(或return语句)为止。
  (5)换言之,Generator函数是分段执行的,yield语句是暂停执行的标记,而next方法可以恢复执行。
  (6)示例1
    function* starFunction(one) {
      console.log(one);
      var two = 2 * (yield one + 1); //6,7
      console.log("1111111111111111111111111111111");
      console.log(two);
      var three = yield 2 * two; //4,8
      console.log("2222222222222222222222222222222");
      console.log(three);
      var four = yield 2 * three; //2,4
      console.log("3333333333333333333333333333333");
      console.log(four);
      console.log(one, two, three, four);
      console.log("4444444444444444444444444444444");
      return one + two + three + four;
    }
    var useFunction = starFunction(6);
    console.log(useFunction.next());
    console.log(useFunction.next(2));
    console.log(useFunction.next(2));
    console.log(useFunction.next(2));
    next第1次执行,返回“第1个yield语句的计算结果”;
    next第2次执行,返回“第2个yield语句的计算结果”,传入的参数取代“第1个yield语句的计算结果”;
    next第3次执行,返回“第3个yield语句的计算结果,传入的参数取代“第2个yield语句的计算结果””;
    next第n次执行时,如果没有第n个yield语句,那就一直执行到return,如果没有return,就返回undefined。
  (7)示例2 
    来源:http://www.ruanyifeng.com/blog/2015/04/generator.html
    Fetch模块返回的是一个Promise对象,因此要用then方法调用下一个next方法。
    var fetch = require('node-fetch');
    function* generatorFn(){
      var urlA = 'https://api.github.com/users/githubA';
      var urlB = 'https://api.github.com/users/githubB';
      yield fetch(urlA);
      yield fetch(urlB);
    }
    var generatorOne = generatorFn();
    var result = generatorOne.next();
    result.value.then(function(data){
      return data.json();
    }).then(function(data){
      generatorOne.next(data);
    });
  (8)如果想要第一次调用next方法时,就能够输入值,可以在Generator函数外面再包一层。如下
    function wrapper(generatorFunction) {
      return function (num) {
        let generatorObject = generatorFunction(num);
        generatorObject.next();
        return generatorObject;
      };
    }
    const wrapped = wrapper(function* starFunction(a) {
      console.log(a);
      var b = 2 * (yield a + 1); //6,7
      console.log("1111111111111111111111111111111");
      console.log(b);
      var c = yield 2 * b; //4,8
      console.log("2222222222222222222222222222222");
      console.log(c);
      var d = yield 2 * c; //2,4
      console.log("3333333333333333333333333333333");
      console.log(d);
      console.log(a, b, c, d);
      console.log("4444444444444444444444444444444");
      return a + b + c + d;
    });
    var b = wrapped(6);
    console.log(b.next(2));
    console.log(b.next(2));
    console.log(b.next(2));
5、async和await
  (1)嵌套回调、Promise、Generators不够优雅,
  (2)从外向里,使用async-await-Promise-resolve,
    resolve的参数是await的返回值,
    async的返回值是async的then参数的参数
  (3)await语句只能在async函数内部使用,该语句的异步执行结束后,才能执行下面的语句
    示例一、
      function thisPromise(x) {
        return new Promise(function (resolve) {
          //此处把x(加工后)作为参数向后台发送请求
          setTimeout(function () {
            //此处获得后台返回结果并加工为x+50,通过resolve暴露出去
            resolve(x + 50);
          }, 500);
        });
      }
      async function thisAdd(x) { //var thisAdd = async function(x) {
        var a = await thisPromise(20);
        var b = await thisPromise(30);
        //此处可以加工a,b
        return x + a + b; //这个结果作为参数传给后面的success
      }
      thisAdd(10).then(function (total) {
        console.log(total); //1秒后,出打印结果160
      });
    示例二、
      router.beforeEach(async(to, from, next) => {
        if (getToken()) {
          if (to.path === '/login') {
            next({ path: '/' });
          } else {
            if (userInfo) {
              next();
            } else {
              try {
                await userStore.getInfo();
              } catch (error) {
                 
              }
            }
          }
        } else {
         
        }
      });
   
五、CommonJS与ES6模块(含AMD、CMD、UMD)
1、CommonJS中模块规范(在后台nodejs开发中使用,在前端框架处理兼容时使用)
  (1)导出模块 module.exports = obj;
  (2)导入模块 var example = require('./example.js'); var area = example.area;//使用模块
  (3)CommonJS 规范主要特点
    来源,https://blog.csdn.net/jieyucx/article/details/131548528
    A、模块化代码:CommonJS 允许将代码按功能或逻辑分类成独立的模块,每个模块只负责特定的功能,使代码更加可维护和可复用。
    B、缓存代码:CommonJS 规范提供了模块的加载和缓存机制,可以确保模块只会被加载一次,避免重复加载和执行,提高性能。
    C、隔离命名空间:每个模块都有自己独立的作用域,不会与其他模块中的变量和函数冲突,有效避免命名冲突。
    D、跨平台使用:CommonJS 规范不限于在浏览器中使用,也可以在其他 JavaScript 运行环境中使用,如 Node.js 等。
  (4)module.exports和exports的区别
    A、初始化
      a、module.exports = {}
      b、exports = module.exports
    B、赋值操作
      a、exports重新赋值后,不再指向module.exports
      b、外部引入的是module.exports所指的对象
    C、正确使用
      a、module.exports.fn = function() {}
      b、exports.fn = function() {}
2、ES6中模块示例
  注、as后面为本文件使用名称
  (1)默认导出和导入
    A、导出,mathUtils.js,只能导出1次
      export default {
        add,
        subtract,
        multiply
      };//下面是错误用法
      export default add;
      export default subtract;
      export default multiply;
    B、导入,导入时可以自定义名称
      import mathUtils from './mathUtils.js';
  (2)*导出和导入
    A、导出,namedUtils.js
      export {
        add,
        subtract,
        multiply
      };//下面是正确用法
      export add;
      export subtract;
      export multiply;
    B、导入,使用通配符导入整个模块,并将其解构为abc1,ABC1
      import * as namedUtils from "./abc";
      //以下进一步使用,两种任选一种
      //import {add,subtract,multiply} = namedUtils;
      //namedUtils.add,namedUtils.subtract,namedUtils.multiply
  (3)普通导出和导入
    A、导出,mathUtils.js,可以导出多次
      const add = (a, b) => a + b;
      const subtract = (a, b) => a - b;
      const multiply = (a, b) => a * b;
      export {
        add,
        subtract,
        multiply
      };//此效果等同于下面效果
      export add;
      export subtract;
      export multiply;
    B、导入,导入时使用相同的名称,必须使用--------花括号
      import { add, subtract, multiply } from './mathUtils.js';
  (4)默认和普通同时导入
    A、import mathUtils, { add1, subtract1 } from './mathUtils.js';
  (5)*和普通同时导入
    A、import a from './d.js'; // 导入默认导出
    B、import * as rest from './d.js'; // 导入除了默认导出之外的所有变量
  (6)改名导出和导入
    A、导出
      export {abc as abc1, ABC as ABC1}
    B、导入
      import {abc1,ABC1} from "./abc";
      import {abc1 as abc2, ABC1 as ABC2} from "./abc";
3、ESModule和CommonJS的区别
  (1)语法不同
    A、ESModule用export(没有s)和import导出和导入,import在编译时加载,必须放在开头
    B、CommonJS用module.exports和require导出和导入,require在运行时加载,可以放在任何位置
    C、import和‌require可以代替对方使用
  (2)注意
    A、都可以在现代浏览器中使用
    B、早期的node要用vue-loader把.vue文件转为ES6模块
    C、2019年发布的node13.2.0,开始支持ES6模块,此后package.json中无需添加vue-loader依赖
4、AMD、CMD、UMD模块规范
  (1)AMD和require.js,AMD依赖模块加载跳过所有异步,运行后面的回调函数,
    运行中所有依赖模块的语句,都定义在另一个回调函数中,等到加载完成之后,这个回调函数才会运行
    A、定义模块
      define("abc", ["a", "b", "c", 'd'], function (a, b, c, d) {
        var a = require('a');
      });
    B、引用模块
      require(['abc','def'],function(abc,def){});
  (2)CMD和sea.js,在回调函数里,需要某个依赖,才会加载这个依赖
    A、定义模块
      define("abc", ["a", "b", "c", 'd'], function (require, exports, module) {
        var a = require('a');
      });
    B、引用模块
      require("abc")
  (3)UMD用于判断代码运行环境
    A、UMD,Universal Module Definition,通用模块定义
    B、UMD实例
      (function fn(root, factory) {
        if(typeof exports === 'object' && typeof module === 'object'){//非原生CommonJS环境下,如nodejs环境
          module.exports = factory();
        }else if(typeof define === 'function' && define.amd){//AMD环境下,如requirejs加载器
          define([], factory);
        }else if(typeof define === "function" && define.cmd){//CMD环境下,如seajs加载器,一个模块就是一个文件
          define([], factory);
        }else if(typeof exports === 'object'){//原生CommonJS环境下
          exports["aaa"] = factory();
        }else if(typeof self === 'object'){//使用了web worker技术的服务器环境,不会影响页面的性能。
          self["aaa"] = factory();
        }else if(typeof global === 'object'){//如果所有的全局环境变量都统一为global
          self["aaa"] = factory();
        }else{//其它环境下,如window
          root["aaa"] = factory();
        }      
      })(this, function() {})
  
六、TS知识(typeScript)
 附、ts在线运行
 (1)https://typescript.jsrun.net/
 (2)https://www.json.cn/run/typescript/
 (3)https://www.bejson.com/runcode/typescript
 附、泛型,https://www.tslang.cn/docs/handbook/generics.html
1、符号(不是修饰符)
  (1)交叉类型&
    A、&用于创建交叉类型,合并多个类型的属性
    B、如果一个值的类型是交叉类型A&B,那么该值必须同时满足类型A和类型B的要求
      type A = { propA: number };
      type B = { propB: string };
      type C = A & B;
      // 结果类型 C
      // { propA: number, propB: string }
  (2)联合类型|
    A、|用于创建联合类型,表示一个值的类型可以是多个类型之一
    B、如果一个值的类型是联合类型A|B,那么该值可以是类型A或者类型B中的任意一种
      type A = { propA: number };
      type B = { propB: string };
      type C = A | B;
      // 结果类型 C
      // { propA: number } | { propB: string }
  (3)??
    A组、
      console.log(null || 1) //1
      console.log(null ?? 1) //1
    B组、
      console.log(undefined || 1) //1
      console.log(undefined ?? 1) //1
    C组、
      console.log(0 || 1) //1
      console.log(0 ?? 1) //0
  (4)?.
    var ss = null;
    console.log(ss?.qqq)// undefined
    var ss = {qqq:1};
    console.log(ss?.qqq)// 1
  (5)?:
    email?: string; // 可选属性
2、泛型,延迟指定的数据类型,“<XXX>”放在变量的后面(在定义时、在使用时)
  (1)不用泛型定义
    A、写法1
      function identity(arg: number): number {
        return arg;
      }
      console.log(identity(3));
    B、写法二
      function identity(arg: any): any {
        return arg;
      }
      console.log(identity(3));
  (2)泛型的定义与执行
    function identity<T>(arg: T): T { //可以没有“: T”。泛型-参数-返回值类型(可以缺失)-函数体
      return arg;
    }
    let output = identity<string>("myString");
    let output = identity("myString");
  (3)泛型函数,延迟指定(参数和返回值)的数据类型
    A、泛型函数的普通类型<T>
      function createArray<T>(length: number, value: T): Array<T> {
        let result: T[] = [];
        for (let i = 0; i < length; i++) {
          result[i] = value;
        }
        return result;
      }
      console.log( createArray<string>(3, 'x') );
      /*
      //ts函数,不用泛型,如下
      //写法1,用function定义
        var createArray = function(length: number, value: string){
          let result = [];
          for (let i = 0; i < length; i++) {
            result[i] = value;
          }
          return result;
        }
        console.log( createArray(3, 'x') );
      //写法2,用=>定义,无参数
        var createArray = () => {
          let result = [];
          for (let i = 0; i < 3; i++) {
            result[i] = 'x';
          }
          return result;
        }
        console.log( createArray() );
      //写法3,用=>定义,有参数,普通
        var createArray = (length: number, value: string) => {
          let result = [];
          for (let i = 0; i < length; i++) {
            result[i] = value;
          }
          return result;
        }
        console.log( createArray(3, 'x') );
      //写法4,用=>定义,有参数,解构
        export default ({ command, mode }: ConfigEnv): UserConfig => {
          ({ command, mode }: ConfigEnv),这部分是函数的参数。接收对象,对象的类型为ConfigEnv,解构出两个属性command和mode
          UserConfig => {},这部分是函数的返回值。类型是UserConfig
          return {};
        };
      */
    B、泛型函数的默认类型<T = string>
      function createArray<T = string>(length: number, value: T): Array<T> {
        let result: T[] = [];
        for (let i = 0; i < length; i++) {
          result[i] = value;
        }
        return result;
      }
      console.log( createArray<string>(3, 'x') );
    C、泛型函数的执行
      type FilePreview = {
        data: FilePreviewData;
        mime: string;
        name: string;
        preview: string;
        type: string;
      };
      const [previews, setPreviews] = createSignal<FilePreview[]>([],{});
      //FilePreview[],数组的每项必须包含FilePreview
      //createSignal,它的泛型可能-没限制参数,只限制返回值
  (4)泛型类
    A、TypeScript的核心原则之一是对值进行类型检查
    B、在TypeScript里,接口的作用就是为这些类型命名和为代码定义契约
    C、declare关键字通常用于声明不需要编译的实体,例如全局变量、函数、对象等
    D、泛型类普通写法-无参
      class GenericNumber<T> {
        zeroValue: T;
        add: (x: T, y: T) => T;
      }
      let myGenericNumber = new GenericNumber<number>();
      myGenericNumber.zeroValue = 0;
      myGenericNumber.add = function(x, y) { return x + y; };
      console.log( myGenericNumber.zeroValue );
      console.log( myGenericNumber.add(2, 3) );
    E、泛型类普通写法-有参
      class Persons<T> {
        private value: T;
        aaa: T;
        constructor(value: T) {
          this.value = value;
        }
        getValue(): T {
          return this.value;
        }
      }
      const one = new Persons<string>("小美");
      one.aaa = '字符串';
      console.log(one.aaa);
      console.log(one.getValue());
      console.log('---------------------');
      const two = new Persons<number[]>([1, 2, 3]);
      two.aaa = [3,3,3];
      console.log(two.aaa);
      console.log(two.getValue());
    F、泛型约束
      interface Lengthwise {
        length: number;
      }
      function loggingIdentity<T extends Lengthwise>(arg: T): T {
        console.log(arg.length);
        return arg;
      }
    G、对泛型进行约束,只允许这个函数传入那些包含length属性的变量
    H、我们定义一个接口来描述约束条件。创建一个包含.length属性的接口,使用这个接口和extends关键字来实现约束
3、接口,数据结构和数据类型的规范,“:XXX”放在变量的后面(在定义时)
  (1)不用接口规范
    function printLabel(labelledObj: { label: string }) {
      console.log(labelledObj.label);
    }
    let myObj = { size: 10, label: "Size 10 Object" };
    printLabel(myObj);
  (2)接口的定义与使用
    A、定义1
      type SquareConfig = {
        color?: string;
        width?: number;
      }
      type ShortTextInputProps = {//案例来源,chat-embed项目下ShortTextInput.tsx文件
        ref: HTMLInputElement | HTMLTextAreaElement | undefined;
        onInput: (value: string) => void;
        fontSize?: number;
        disabled?: boolean;
      } & Omit<JSX.TextareaHTMLAttributes<HTMLTextAreaElement>, 'onInput'>;
      //Omit<Type, Keys>创建新类型,从现有类型(Type)中排除指定属性(Keys)
    B、定义2
      interface SquareConfig {
        color?: string;
        width?: number;
      }
    C、使用
      function createSquare(config: SquareConfig): {color: string; area: number} {
        let newSquare = {color: "white", area: 100};
        if (config.color) {
          newSquare.color = config.color;
        }
        if (config.width) {
          newSquare.area = config.width * config.width;
        }
        return newSquare;
      }
      console.log( createSquare({}) );
      console.log( createSquare({color: "black"}) );
  (3)数组的接口
    A、var numbers: number[] = [1, 2, 3, 4, 5];
    B、var numbers: Array<number> = [1, 2, 3, 4, 5];
    C、var numbers = [1, 2, 3, 4, 5];
    D、ts声明自定义类型的数组示例
      interface Teacher {
        name: string;
        age: number;
        speciality: string;
      }
      let teachers: Teacher[] = [
        { name: 'Alice', age: 30, speciality: 'Mathematics' },
        { name: 'Bob', age: 35, speciality: 'Physics' },
        { name: 'Charlie', age: 32, speciality: 'Chemistry' }
      ];
      teachers.forEach((teacher) => {
        console.log(`Name: ${teacher.name}, Age: ${teacher.age}, Speciality: ${teacher.speciality}`);
      });
  (4)对象的接口
    A、写法1
      interface User {
        name: string;
        age: number;
        email?: string; // 可选属性
      }
      let user: User = {
        name: 'Alice',
        age: 25
      };
      console.log( user );
    B、写法2,百度-TypeScript的类型声明 Record
      说明:
       a、Record类型是一个通用的类型,用于创建一个对象类型,其中所有的属性都有相同的值类型
       b、Record接收两个类型参数,第一个是键的类型,第二个是值的类型
      示例:
        type UserRecord = Record<string, string>;
        const user: UserRecord = {
          name: 'Alice',
          age: '30',
          job: 'Developer'
        };
        console.log( user );
    C、写法3,百度-overrideConfig?: Record<string, unknown>;
      示例1:为这个可选属性提供一个值
        let config: { overrideConfig?: Record<string, unknown> } = {
          overrideConfig: {
            key1: 'value1',
            key2: 42,
            key3: true
          }
        };
      示例2:不想提供任何值,只需要声明这个可选属性
        let config: { overrideConfig?: Record<string, unknown> } = {
          // overrideConfig is optional
        };
      示例3:在后面的代码中设置或修改这个属性
        let config: { overrideConfig?: Record<string, unknown> } = {};
        config.overrideConfig = {
          key1: 'value1',
          key2: 42,
          key3: true
        };
    D、写法4,真实案例(改编)
      示例1:可运行
        type IncomingInput = {
          conversation_id?: string;
          messages?: {}[]; //由对象组成的数组
          question?: string;
          //uploads?: FileUpload[];
          overrideConfig?: Record<string, unknown>;
          socketIOClientId?: string;
          chatId?: string;
          fileName?: string;
          leadEmail?: string;
        };
        type MessageRequest = {
          chatflowid?: string;
          apiHost?: string;
          body?: IncomingInput;
        }; 
        const body: IncomingInput = {
          conversation_id: 'conversation_id()', //chatId()  724b8f8a385411efb642e43d1a3ceb2
          messages: [
            {
              role : "user",
              content : 'value',
            }
          ]
        };
        const obj: MessageRequest = {
          chatflowid: 'string',
          apiHost: 'string',
          body: body
        }
        console.log( obj );
      示例2:不可运行,注意函数的参数默认值
        export const sendMessageQuery = ({ chatflowid, apiHost = 'http://localhost:3000', body }: MessageRequest) =>
          sendRequest<any>({
            method: 'POST',
            url: `${apiHost}/api/v1/prediction/${chatflowid}`,
            //url: 'http://172.20.35.35/v1/api/completion',
            body,
          });
  (5)函数的接口
    interface User {
      name: string;
      age: number;
      email?: string; // 可选属性
    }
    function createUser(userData: User): User{
      return {
        id: userData.id,
        name: userData.name,
        isActive: userData.isActive,
      };
    }
    const newUser = createUser({ id: 1, name: 'Alice', isActive: true });
    console.log(newUser);
4、泛型接口
  (1)写法1
    interface CreateArrayFunc {
      <T>(length: number, value: T): Array<T>;
    }
    let createArray: CreateArrayFunc;
    createArray = function<T>(length: number, value: T): Array<T> {
      let result: T[] = [];
      for (let i = 0; i < length; i++) {
        result[i] = value;
      }
      return result;
    }
    console.log(createArray(3,'x'));
  (2)写法2
    interface CreateArrayFunc<T> { //有<T>
      (length: number, value: T): Array<T>;
    }
    let createArray: CreateArrayFunc<string>; //有<string>
    createArray = function<T>(length: number, value: T): Array<T> {
      let result: T[] = [];
      for (let i = 0; i < length; i++) {
        result[i] = value;
      }
      return result;
    }
    console.log(createArray(3,'x'));
 
七、ES6和TS的类、继承、实例
  附、两者的共同特征
    A、继承:super是父类的构造函数,必须首先调用
    B、static:(子)类都可以获取
1、ES6的类、继承、实例
  (1)static函数:类调用,this指向类;子类调用,this指向子类
  (2)普通函数:实例调用,this指向实例;子实例调用,this指向子实例
  (3)示例:
    class Parent {
      constructor(x, y) {
        this.x = x;
        this.y = y;
      }
      static name = "animal";
      static age = "20";
      static getY() {
        console.log('通过父类访问静态,this就是父类,this === Parent',);
        console.log('通过子类访问静态,this就是子类,this === Son',);
      }
      getX() {
        console.log('通过父类实例访问普通,this就是父类实例,this === parent',);
        console.log('通过子类实例访问普通,this就是子类实例,this === son',);
      }
    }
    class Son extends Parent {
      constructor(...props) {
        super(...props);
        this.z = 4;
      }
    }
    Son.getY();
    console.log( "-----------以上类访问,以下实例访问-----------" );
    new Son(2,3).getX();
2、TS的类、继承、实例
  知识来源,https://www.tslang.cn/docs/handbook/classes.html
  代码运行,https://www.json.cn/run/typescript/
  附、没有重叠,have no overlap
  附、修饰符(限制数据的使用范围) //普通函数,无修饰符,默认为public
    A、公共public:(子)类内可访问、(子)实例可访问
    B、受保protected:(子)类内可访问
    C、私有private:类内可访问
  (1)static函数:类调用,this指向类;子类调用,this不指向任何
  (2)普通函数:实例调用,this指向实例;子实例调用,this不指向任何
  (3)示例:
    class Parent {
      public publicA: string = 'aaa';
      protected protectedA: string = '';
      private privateA: string;
      constructor(publicA: string, protectedA: string) {
        this.publicA = publicA;
        this.protectedA = protectedA;
        this.privateA = 'privateA';
        console.log( '私有属性只能在自身的类内访问,如'+this.privateA );
      };
      static sayHello() {
        console.log('通过父类访问静态,this就是父类,this === Parent',);
        console.log('通过子类访问静态,this不是子类,this != Son',);
      }
      sayWorld() {
        console.log('通过父类访问静态,this就是父类,this === parent',);
        console.log('通过子类访问静态,this不是子类,this != son',);
      }
    }
    class Son extends Parent {
      public publicB: string;
      protected protectedB: string;
      private privateB: string;
      constructor(publicC: string, protectedC: string, privateC: string) {
        super(publicC,protectedC);
        console.log("子类可-以访问:"+this.publicA+",public")
        console.log("子类可-以访问:"+this.protectedA+",protected")
        console.log("子类不-可访问:私有,private")
        this.publicB = publicC;
        this.protectedB = protectedC;
        this.privateB = privateC;
        console.log("类内可-以访问:"+this.publicB+",public")
        console.log("类内可-以访问:"+this.protectedB+",protected")
        console.log("类内可-以访问:"+this.privateB+",private")
      }
    }
    Son.sayHello();
    var son = new Son("公共", "保护", "私有");
    son.sayWorld()
    console.log('通过实例,只能访问('+son.publicA+'-'+son.publicB+')属性');
 
八、jQuery知识
1、四种宽
  (1)width():其宽度范围是所匹配元素的宽度width;
  (2)innerWidth():其宽度范围是所匹配元素的宽度width+padding;
  (3)outerWidth():其宽度范围是所匹配元素的宽度width+padding+border;
  (4)outerWidth(true)其宽度范围是所匹配元素的宽度width+padding+border+margin;
2、attr和prop
   附、总说明
    A、2011年,jQuery.1.6.1发布,在本版本及以后的版本中
    B、设置和获取-自定义属性用attr
    C、设置和获取-固有属性用prop
    D、其它的不要深究
  (1)低版本
    <!DOCTYPE html>
    <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>jquery.1.5.1及以前</title>
        <script src="https://cdn.bootcdn.net/ajax/libs/jquery/1.5.1/jquery.js"></script> 
      </head>
      <body>
        <pre>
          <h3><input type="checkbox" id="check" checked=""  aaa="aaa"/>jquery.1.5.1及以前</h3>
            input type="checkbox" id="check" aaa="aaa" checked=""
            1、checked="",初始化时,不管如何赋值,只要出现,就是选中
            2、attr可以设置、获取固有属性、自定义属性
              (1)设置固有属性,
                $('#check').attr('checked',false)//不选中
                $('#check').attr('checked','')//不选中
                $('#check').attr('checked','111')//选中
                $('#check').attr('checked',true)//选中
              (2)获取固有属性,
                console.log($('#check').attr('checked'));//true
                console.log($('#check').attr('checked',false).attr('checked'));//false
                console.log($('#check').attr('checked','').attr('checked'));//false
                console.log($('#check').attr('checked','111').attr('checked'));//true
                console.log($('#check').attr('checked',true).attr('checked'));//true
              (3)获取自定义属性,console.log($('#check').attr('aaa'));//aaa
            3、prop不存在
              (1)console.log($('#check').prop);//undefined
        </pre>
      </body>
    </html>
    <script type="text/javascript">
      console.log($('#check').attr('checked'));//true
      console.log($('#check').attr('checked',false).attr('checked'));//false
      console.log($('#check').attr('checked','').attr('checked'));//false
      console.log($('#check').attr('checked','111').attr('checked'));//true
      console.log($('#check').attr('checked',true).attr('checked'));//true
    </script> 
  (2)高版本
    <!DOCTYPE html>
    <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>jquery.1.6.1及以后</title>
        <script src="https://cdn.bootcdn.net/ajax/libs/jquery/1.6.1/jquery.js"></script>   
      </head>
      <body>
        <pre>
          <h3><input type="checkbox" id="check" checked=""  aaa="aaa"/>jquery.1.6.1及以后</h3>
            input type="checkbox" id="check" aaa="aaa" checked=""
            1、checked="",不管如何赋值,只要出现,就是选中
            2、attr可以设置、获取自定义属性、固有属性;
              (1)设置固有属性,
                $('#check').attr('checked',false)//不选中
                $('#check').attr('checked','')//选中
                $('#check').attr('checked','111')//选中
                $('#check').attr('checked',true)//选中
              (2)获取固有属性,
                console.log($('#check').attr('checked'));//checked
                console.log($('#check').attr('checked',false).attr('checked'));//undefined
                console.log($('#check').attr('checked','').attr('checked'));//undefined
                console.log($('#check').attr('checked','111').attr('checked'));//undefined
                console.log($('#check').attr('checked',true).attr('checked'));//checked
              (3)获取自定义属性,
                console.log($('#check').attr('aaa'));//aaa
            3、prop可以设置、获取固有属性;
              (1)设置固有属性,
                $('#check').prop('checked',false)//不选中
                $('#check').prop('checked','')//不选中
                $('#check').prop('checked','111')//选中
                $('#check').prop('checked',true)//选中
              (2)获取固有属性,
                console.log($('#check').prop('checked'));//true
                console.log($('#check').prop('checked',false).prop('checked'));//false
                console.log($('#check').prop('checked','').prop('checked'));//false
                console.log($('#check').prop('checked','111').prop('checked'));//true
                console.log($('#check').prop('checked',true).prop('checked'));//true
              (3)获取自定义属性,
                console.log($('#check').prop('aaa'));//undefined
        </pre>
      </body>
    </html>
    <script type="text/javascript">
    </script>
3、实例无new构建
  (function(window) {
    var jQuery = function(selector, context) {
      return new jQuery.prototype.init(selector, context, rootjQuery);
    },
    jQuery.prototype = {
      init: function( elem, options, prop, end, easing, unit ) {
        this.elem = elem;
        this.prop = prop;
        this.easing = easing || jQuery.easing._default;
        this.options = options;
        this.start = this.now = this.cur();
        this.end = end;
        this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
      },
    }
    jQuery.prototype.init.prototype = jQuery.prototype;
  })(window);
 
九、jQuery示例
1、jQuery实现鼠标跟随
  说明,
    (1)所谓鼠标跟随,一般就是指鼠标移到哪张图片上,那该张图片的放大图片就会出现,并且放大图片会随着鼠标在该张图片上移动而移动。
  <!DOCTYPE html>
  <html lang="en">
  <head>
    <meta charset="UTF-8">
    <title></title>
    <style>
      * {
        margin: 0;
        padding: 0;
      }
      img {
        border: none;
      }
      .box {
        width: 660px;
        position: relative;
      }
      .box .mark {
        position: absolute;
        width: 400px;
        height: 300px;
        display: none;
      }
      .box .mark img {
        width: 100%;
      }
      .box img {
        width: 150px;
        float: left;
        margin: 5px;
      }
    </style>
  </head>
  <body>
  <div class="box" id="box">
    <img src="http://www.qdfuns.com/misc.php?mod=attach&genre=editor&aid=e95708d565639d99576ae7cb00729334"
      realImg="http://www.qdfuns.com/misc.php?mod=attach&genre=editor&aid=5328802dc943fc046e109f70359add0a" alt=""/>
    <img src="http://www.qdfuns.com/misc.php?mod=attach&genre=editor&aid=9e5459a7c0098c27adf4bdd73889caa9"
      realImg="http://www.qdfuns.com/misc.php?mod=attach&genre=editor&aid=846f4d1987765dc4cfd5a06fcdd2dcc1" alt=""/>
    <img src="http://www.qdfuns.com/misc.php?mod=attach&genre=editor&aid=3cd1c8e301007f0c94850139ac79cb5a"
      realImg="http://www.qdfuns.com/misc.php?mod=attach&genre=editor&aid=747bf3f7092ebd2b0bf9fcd27e28bbe5" alt=""/>
    <img src="http://www.qdfuns.com/misc.php?mod=attach&genre=editor&aid=f391169b2cf678aa6fd253cf40d9821d"
      realImg="http://www.qdfuns.com/misc.php?mod=attach&genre=editor&aid=fec8d2f20fad1f28d540337a831e89d0" alt=""/>
    <div id="mark" class="mark"><img src="" alt=""/></div>
  </div>
  <script src="http://s0.kuaizhan.com/res/skin/js/lib/jquery-2.0.3.min.js"></script>
  <script>
    //1.鼠标移入哪张图片的时候,让他对应的大图显示;
    //2.当鼠标在img中移动的时候,大图跟着走;
    var $box=$('.box');
    var $aImg=$box.children('img');
    var $mark=$('.mark');
    var $offset=$box.offset();
    $aImg.mouseover(function(){
      //当鼠标移入每张图片的时候,让mark显示,并且,让mark里面的img标签,src属性值为当前这个图片的realImg属性上拿到的值;
      $mark.show().find('img').attr('src',$(this).attr('realImg'));
    });
    $aImg.mousemove(function(e){
      //拿鼠标的x坐标,减去$box距离body的left位置;
      var left= e.clientX-$offset.left+10;
      var top= e.clientY-$offset.top+10;
      $mark.css({left:left,top:top})
    });
    $aImg.mouseout(function(){
      $mark.hide();
    })
  </script>
  </body>
  </html>
2、jQuery实现文档树效果
  <!DOCTYPE html>
  <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title></title>
      <style>
        * {
          margin: 0;
          padding: 0;
          list-style: none;
        }
        .box {
          width: 250px;
          height: auto;
          padding: 20px;
          background: lightgrey;
          margin: 0 auto;
        }
        .box li {
          line-height: 30px;
          /*注意:height没有被设置,可以根据实际需要自动调整*/
          position: relative;
        }
        .box li em {
          position: absolute;
          left: 0;
          top: 7px;
          width: 16px;
          height: 16px;
          background-image: url("");
          background-size: 100%;
          cursor: pointer;
        }
        .box li em.open {
          background-image: url("");
          background-size: 100%;
        }
        .box li span {
          padding-left: 20px;
          /*因为span前面的em已经绝对定位,脱离文档流了,所以span的左边界直达 li*/
        }
        .box ul {
          display: none;
        }
        .two {
          margin-left: 20px;
        }
        .three {
          margin-left: 40px;
        }
        .four {
          margin-left: 40px;
        }
        /*ul.box下的li显示,其中有折叠的li加em;
        ul.box下的ul隐藏,其内部的li是没法显示的*/
      </style>
    </head>
    <body>
    <ul class="box">
      <li><em></em><span>第一级第一个</span>
        <ul class="two">
          <li><span>第二级第一个</span></li>
          <li><em></em><span>第二级第二个</span>
            <ul class="three">
              <li><em></em><span>第三级第一个</span>
                <ul class="four">
                  <li><span>第四级第一个</span></li>
                  <li><span>第四级第二个</span></li>
                </ul>
              </li>
              <li><span>第三级第二个</span></li>
            </ul>
          </li>
          <li><em></em><span>第二级第三个</span>
            <ul class="three">
              <li><span>第三级第一个</span></li>
              <li><span>第三级第二个</span></li>
            </ul>
          </li>
        </ul>
      </li>
      <li><em></em><span>第一级第一个</span>
        <ul class="two">
          <li><span>第二级第一个</span></li>
          <li><em></em><span>第二级第二个</span>
            <ul class="three">
              <li><em></em><span>第三级第一个</span>
                <ul class="four">
                  <li><span>第四级第一个</span></li>
                  <li><span>第四级第二个</span></li>
                </ul>
              </li>
              <li><span>第三级第二个</span></li>
            </ul>
          </li>
        </ul>
      </li>
    </ul>
    <script src="http://s0.kuaizhan.com/res/skin/js/lib/jquery-2.0.3.min.js"></script>
    <script>
      /*思路:
        * 1.让前面有em的span加上小手效果;
        * 2.点击span or em的时候,看他父容器下是否有ul,如果有,让其显示,否则,隐藏
        * */
      var $box=$('.box');
      var $aSpan=$box.find('span');
      //1.让前面有em的span加上小手效果;
      $aSpan.each(function(index,item){
        //if($(item).prev().length){ $(item).css('cursor','pointer');};思路1:
        $(item).prev('em').next('span').css('cursor','pointer'); //思路2:
      });
      //2.点击span or em的时候,看他父容器下是否有ul,如果有,让其显示,否则,隐藏
      $box.click(function(e){
        //当点击的事件源是em or span的时候,我们看其父级下是否有ul
        //如果有:展开让其闭合,闭合就让其展开;
        if(e.target.tagName.toLowerCase()=='em' || e.target.tagName.toLowerCase()=='span'){
          var $parent=$(e.target).parent();
          var $ul=$parent.children('ul');
          if($ul){
            if($ul.css('display')=='block'){//展开,让其闭合
              //当闭合的时候,让当前容器下,所有的em都移除open,所有的ul都隐藏;
              $parent.find('ul').hide();
              $parent.find('em').removeClass('open');
            }else{ //闭合让其展开
              $ul.show();
              $parent.children('em').addClass('open');
     
            }
          }
        }
      })
    </script>
    </body>
  </html>
3、jQuery方法扩展(选项卡)
  说明,
    (1)在jQuery上扩展方法,通过点击实现选项卡的切换。本实例在jQuery的类上扩展,即$.extend({chooseCard:函数}),通过$.chooseCard('#box')调用;
    (2)有别于$.fn.extend({chooseCard:函数})扩展,通过$().chooseCard('#box')调用。
  <!DOCTYPE html>
  <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Title</title>
      <style>
        * {
          margin: 0;
          padding: 0;
        }
        .box {
          width: 312px;
          border: 2px red solid;
          margin: 0 auto;
        }
        ul {
          overflow: hidden;
        }
        li {
          list-style: none;
          background: red;
          float: left;
          width: 100px;
          height: 30px;
          line-height: 30px;
          text-align: center;
          border: 2px solid orange;
        }
        li.on {
          background: green;
        }
        .box div {
          background: green;
          display: none;
          width: 312px;
          height: 200px;
          font-size: 30px;
          border-top: none;
        }
        .box div.on {
          display: block;
        }
      </style>
    </head>
    <body>
    <div class="box" id="box">
        <ul>
          <li class="">中国</li>
          <li>日本</li>
          <li>韩国</li>
        </ul>
        <div class="on">中国是老大</div>
        <div>日本是老二</div>
        <div>韩国是老三</div>
    </div>
    <script src="http://s0.kuaizhan.com/res/skin/js/lib/jquery-2.0.3.min.js"></script>
    <script>
      (function ($) {
        $.extend({
          chooseCard: function (idStr) {
            var $box = $(idStr);
            var $li = $box.find("li");
            console.log($li);
            var $aDiv = $box.find("div");
            $li.click(function () {
              $(this)
                .css({ height: "32px", "border-bottom": "none" })
                .siblings("li")
                .css({ height: "30px", "border-bottom": "2px solid orange" });
              $(this).addClass("on").siblings("li").removeClass("on");
              $aDiv
                .eq($(this).index())
                .addClass("on")
                .siblings("div")
                .removeClass("on");
            });
          },
        });
      })(jQuery);
    </script>
    <script>
      $(function(){
        $.chooseCard('#box');
      })
    </script>
    </body>
  </html>
4、jQuery复选框全选、反选(<input type='checkbox'/>)
  说明,
    (1)获取复选框状态:$("#allSelect").prop("checked")
    (2)改变复选框状态:$("#allSelect").prop("checked",false)
    (3)翻转复选框状态:item.checked = !item.checked;
    (4)判断复选框是否被选中:if ($(this).is(':checked'))
    (5)找到所有被选中的复选框:myDiv.find("input:checked");
    (6)获取所有复选框:$("#single input:checkbox")或$("#single input[type=checkbox]");
    (7)获取所有被选中的复选框:$("#single input:checkbox:checked")或$("#single input[type=checkbox]:checked");
  <!DOCTYPE html>
  <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Title</title>
      <script type="text/javascript" src="https://cdn.bootcss.com/jquery/1.9.0/jquery.js"></script>
    </head>
    <body>
      <span>全选</span><input type="checkbox" id="allSelect"><br>
      <span>反选</span><input type="checkbox" id="reverseSelect">
      <div id="single">
        <input type="checkbox">
        <input type="checkbox">
        <input type="checkbox">
        <input type="checkbox">
      </div>
    </body>
  </html>
  <script>
    $("#allSelect").click(function () {
      $("#single")
        .children()
        .each(function (index, item) {
          item.checked = $("#allSelect").prop("checked");
        });
      $("#reverseSelect").prop("checked", false);
    });
    $("#reverseSelect").click(function () {
      $("#single")
        .children()
        .each(function (index, item) {
          item.checked = !item.checked;
        });
      $("#reverseSelect").prop("checked", true);
      singleInput();
    });
    $("#single")
      .children()
      .click(function (index, item) {
        $("#reverseSelect").prop("checked", false);
        singleInput();
      });
    function singleInput() {
      if (
        $("#single input:checkbox:checked").length ==
        $("#single input:checkbox").length
      ) {
        $("#allSelect").prop("checked", true);
      } else {
        $("#allSelect").prop("checked", false);
      }
    }
  </script>
  
十、Error对象详解
 来源:https:www.jb51.net/article/124210.htm
1、说明,解释器会为每个错误情形创建并抛出一个Error对象,并包含该错误的描述信息
2、常用词汇
  (1)Invalid,无效的
  (2)malformed,畸形的,格式不正确的
  (3)Uncaught,未捕获的
  (4)Unexpected,意外的
  (5)escape sequence,转译序列
3、七种错误
  (1)EvalError,eval错误,eval()函数没有正确执行
  (2)RangeError,范围错误,参数超范围,例如
    A、[].length = -5
      a、Uncaught RangeError: Invalid array length
      b、未捕获的范围错误:无效的数组长度
  (3)ReferenceError,引用错误,例如
    A、console.log(b)
      a、Uncaught ReferenceError: b is not defined
      b、未捕获的引用错误:b没有被定义
  (4)SyntaxError,语法错误,例如
    A、var 1
      a、Uncaught SyntaxError: Unexpected number
      b、未捕获的语法错误:意外的数字
      c、变量名首字符不应该为数字
    B、var 1a
      a、Uncaught SyntaxError: Invalid or unexpected token
      b、未捕获的语法错误:无效的或意外的标记
      c、变量名以数字开始了
    C、new Object()
      a、Uncaught SyntaxError: Invalid or unexpected token
      b、未捕获的语法错误:无效的或意外的标记
      c、半角括号写成全角括号了
    D、function = 5
      a、Uncaught SyntaxError: Unexpected token =
      b、未捕获的语法错误:意外的标记=
      c、function后面不应该是=
    E、console.log(1+2)
      a、Uncaught SyntaxError: missing ) after argument list
      b、未捕获的语法错误:在参数列表后,缺少)
      c、+为中文加号
    F、if(true)
      a、Uncaught SyntaxError: Unexpected end of input
      b、未捕获的语法错误:输入意外结束
      c、后面应该有花括号
    G、JSON.parse(function(){})
      a、Uncaught SyntaxError: Unexpected token u in JSON at position 1
      b、未捕获的语法错误:意外的标记u
    H、json.parse(jsonData)
      a、Uncaught (in promise) SyntaxError: "[object Object]" is not valid JSON
      b、未捕获(承诺中)语法错误:“[object Object]”不是有效的JSON
      c、jsonData多了不必要的回车、最后一个逗号、不必要的双引号
    I、.js文件中的路径转义(\)错误
      a、Uncaught SyntaxError: Invalid Unicode escape sequence
      b、未捕获的语法错误:无效的Unicode转义序列
    J、eval("{\"name\":\"123\"}"),将json字符串转换为json对象
      a、Uncaught SyntaxError: Unexpected token ':'
      b、未捕获的语法错误:意外的标记:
      c、正确的用法为,
        console.log( eval("("+"{\"name\":\"123\"}"+")") );
        console.log( eval("("+"[{\"name\":\"123\"}]"+")") );
        console.log( eval("[{\"name\":\"123\"}]") );
  (5)TypeError,类型错误,例如(7)
    A、123()
      a、Uncaught TypeError: 123 is not a function
      b、未捕获的类型错误:123不是一个函数
    B、new 456
      a、Uncaught TypeError: 456 is not a constructor
      b、未捕获的类型错误:456不是一个构造函数
  (6)URIError,URI错误,例如(7)
    A、decodeURI("%")
      a、Uncaught URIError: URI malformed(畸形的) at decodeURI
      b、未捕获的URI错误:decodeURI处URI格式不正确
  (7)手动抛错,中断代码执行如
    throw new Error("提示文字")
4、其它报错
  (1)Parsing error: Unexpected token解析错误:意外符号通常是eslint解析错误
5、错误处理
  try{
    如果此处代码运行不出错,则catch函数不会执行
    如果此处代码运行出错,则自动生成错误信息对象error传给catch函数,
  }catch(error){
    此处通过error.message读出错误信息
  }finally{
    无论 try/catch 结果如何都会执行此处的代码块
  }
 
十一、Date日期时间
1、new Date()、GMT时间、UTC时间
  (1)在浏览器上返回当地时间,如“Tue Dec 17 2024 14:24:26 GMT+0800 (中國標準時間)”
    A、GMT+0800 (中國標準時間),是说明文字,意思是,左侧时间早GMT时间8小时
    B、GMT时间
      a、Greenwich Mean Time,格林尼治标准时间,以英国伦敦格林尼治天文台为基准,受地球自转和季节变化的影响
      b、全球统一的时间标准之一,本地时间可以通过该时间和时区转换
  (2)在服务器上返回UTC时间,如“2024-12-17T06:17:48.399Z”
    A、T,日期和时间的分隔符
    B、.399,秒的小数部分
    C、Z,是说明文字,意思是,左侧时间是UTC时间
    D、UTC时间
      a、Coordinated Universal Time,协调世界时,以原子钟为基准,不受地球自转和季节变化的影响
      b、全球统一的时间标准之一,本地时间可以通过该时间和时区转换
  (3)UTC和GMT的关系,
    A、UTC是在GMT基础上发展而来,比GMT更精确
    B、不涉及高精度时间要求的情况下,UTC和GMT可以视为相同
  (4)获取当前毫秒数的6种方法:
    var str0 = Date.now();
    var str1 = +new Date();
    var str2 = new Date() - 0;
    var str3 = new Date() * 1; //实际示例,new Date(addOrEditForm.value.startTime) < new Date()
    var str4 = new Date().getTime();
    var str5 = new Date().valueOf();
    var str = [str0, str1, str2, str3, str4, str5];
    for (var i = 0; i < str.length; i++) {
      console.log(i, str[i]);
    }
  (5)年龄计算,
    function getAge(birthYear){
      var nowYear = new Date().getFullYear();
      var age = nowYear - birthYear;
      var text = '此人出生于' + birthYear + '年,今年' + age + '岁';
      return text;
    }
    console.log( getAge(1955) );
2、Date的参数
  if(true){
    var array = [
      "2017-6-2",
      "2017-6-2 12:00:00",
      "2017/6/2",
      "2017/6/2 12:00:00",
      "6 2,2017",
      "6 2,2017 12:00:00",
      "6,2,2017",
      "6,2,2017 12:00:00",
      "Jun 2,2017",
      "Jun 2,2017 12:00:00",
      "Jun,2,2017",
      "Jun,2,2017 12:00:00",
      "Jun/2/2017",
      "Jun/2/2017 12:00",
    ];
    for (var i = 0; i < array.length; i++) {
      var date = new Date(array[i]);
      var zero = i === 0? "1、\n": "";
      var str = zero+"参数为:"+array[i]+ ",你获取的年、月、日分别是:"+date.getFullYear()+ "、"+date.getMonth()+"、"+date.getDate();
      console.log(str);
    }
    console.log( "-----以上,系统把“字符串”参数按照“实际”的年月日处理,返回系统的年月日,此观点论据如上面注释-----" );
    console.log( "--------------------------------------------------------------------------------" );
    console.log( "-----以下,系统把“数字”参数按照“系统”的数据处理,返回系统的年月日,此观点论据如下面注释-----" );
  }
  if(true){
    var date1 = new Date();
    var year1 = date1.getFullYear();
    var month1 = date1.getMonth();
    var day1 = date1.getDate();
    var str1 = "1、\n参数为:"+"空,系统把无参默认为系统的现在,返回系统现在的年月日:"+year1+ "、"+month1+"、"+day1;
    console.log(str1);
  }
  if(true){
    var milliseconds = new Date().getTime();
    var date2 = new Date(milliseconds);
    var year2 = date2.getFullYear();
    var month2 = date2.getMonth();
    var day2 = date2.getDate();
    var str2 = "2、\n参数为:1个数字,把从系统获取的现在的“毫秒数”作为参数传给系统,获取的仍然是系统现在的年月日:"+year2+ "、"+month2+"、"+day2;
    console.log(str2);
  }
  if(true){
    var date0 = new Date();
    var year0 = date0.getFullYear();
    var month0 = date0.getMonth();
    var day0 = date0.getDate();
    var hour0 = date0.getHours();
    var minute0 = date0.getMinutes();
    var second0 = date0.getSeconds();
    var ary = [year0, month0, day0, hour0, minute0, second0];
    var date3 = new Date(...ary);
    var year3 = date3.getFullYear();
    var month3 = date3.getMonth();
    var day3 = date3.getDate();
    var str3 = "3、\n参数为:n个数字,把从系统获取的现在的“年月日”作为参数传给系统,获取的仍然是系统现在的年月日:"+year3+ "、"+month3+"、"+day3;
    console.log(str3);
    console.log( "--------------------------------------------------------------------------------" );
    console.log( "-----注意,系统月份比实际月份小1" );
  }
  if(true){
    for( var date = -2; date < 3; date++ ){
      var month = 5 ;
      var newDate = new Date(2020, month, date);
      var monthStr = '此时的参数是:' + month + '、'+ date;
      var dateStr = '此时的月日是:' + newDate.getMonth() + '、'+ newDate.getDate();
      console.log( monthStr, dateStr );
    }
  }
3、获取当前浏览器的时区
  function getTimezoneOffset(){
    var date = new Date();
    var offset = date.getTimezoneOffset();//世界标准时间-本地区时=分钟差
    var local = '';
    var timezone = '';
    var isFlag = false;
    var obj = {
      '东': [-60, -120, -180, -240, -300, -360, -420, -480, -540, -600, -660, -720],
      '西': [60, 120, 180, 240, 300, 360, 420, 480, 540, 600, 660, 720],
    }
    for(var key in obj){
      if(obj[key].indexOf(offset) > -1){
        isFlag = true;
        local = key;
        break;
      }
    }
    if(isFlag){
      timezone = '你目前处于' + local + Math.abs(offset / 60) + '区';
    }else{
      timezone = '你目前处于0时区';
    }
    return timezone;
  };   
  console.log( getTimezoneOffset() );
3、在任意地方获取任意经度的区时(不是地方时)
  function getLocalTime( longitude ){
    // 验证,https://time.org.cn/,点击“切换”,选择“东经/西经”、输入经度、点击“确定”
    if(typeof longitude != 'number'){
      return '错误提示:经度必须是一个数字'
    }
    if(longitude < -180 || longitude > 180){
      return '错误提示:经度必须在 -180 到 180 之间'
    }
    function addZero(num){
      return num < 10 ? '0'+num : num;
    }
    function addZero2(num){
      var length = num.toString().length;
      return ['', '00'+num, '0'+num, num][length] ;
    }
    // 以下规定,longitude的值,为负表示西经,为正表示东经
    var sign = longitude > 0 ? 1 : -1;
    var textFront = longitude == 0 ? '' : longitude < 0 ?  '西经' : '东经';
    var textBack = longitude == 0 ? '经线' :'';
    var textFull = '在'+textFront+addZero2(Math.abs(longitude))+'度'+textBack+',现在的区时是:';
    // 以下获取,目标时区
    if(longitude < 0) longitude = -longitude;
    var timezone = Math.floor(longitude / 15) ;
    var oneHour = longitude % 15 > 7.5 ? 1 : 0;
    var targetZone = timezone+oneHour;
    // 以下获取,当地日期对象
    var date = new Date();
    // 以下获取,当地到UTC的毫秒数
    var localToUtcMill  = date.getTimezoneOffset() * 60 * 1000; //把分钟转换为毫秒
    // 以下获取,UTC到目标的毫秒数
    var utcToTargetMill = targetZone * sign * 60 * 60 * 1000; //把小时转换为毫秒
    // 以下获取,当地到目标的毫秒数
    var localToTargetMill = localToUtcMill+utcToTargetMill;
    // 以下获取,目标的毫秒数
    var targetMill = date.getTime()+localToTargetMill;
    // 以下获取,目标的年、月、日、时、分、秒
    var targetDate = new Date(targetMill);
    var targetYear = targetDate.getFullYear();
    var targetMonth = addZero(targetDate.getMonth()+1) ;
    var targetDay = addZero(targetDate.getDate()) ;
    var targetHour = addZero(targetDate.getHours()) ;
    var targetMinute = addZero(targetDate.getMinutes()) ;
    var targetSecond = addZero(targetDate.getSeconds()) ;
    var targetDateTime = targetYear+'-'+targetMonth+'-'+targetDay+' '+targetHour+':'+targetMinute+':'+targetSecond;
    // 以下返回,最终结果
    return textFull+targetDateTime
  };
  for( var i = -180; i <= 220; i+=15 ) {
    console.log( getLocalTime(i) );
  }
4、Day.js使用示例
  <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Day.js使用示例</title>
      <style></style>
      <script src="https://cdn.jsdelivr.net/npm/dayjs/dayjs.min.js"></script>
    </head>
    <body>
      <h1>多次刷新浏览器后,在控制台看Day.js的使用效果</h1>
    </body>
    <script>
      // import { ElMessage, dayjs } from 'element-plus'
      var date = new Date();
      console.log('注意:', 'dayjs、add、format的参数');
      console.log('“指定的日期时间”与“指定的日期时间”是否“相等”', dayjs(date).isSame(date));
      console.log('“指定的日期时间”与“指定的日期时间”是否“相等”', dayjs('2024-01-08').isSame('2024-01-08'));
      console.log('“指定的日期时间”与“指定的日期时间”是否“相等”', dayjs('2024-01-08 16:32:42').isSame('2024-01-08 16:32:41'));
      console.log('前1年的日期和时间', dayjs().add(-1, 'year').format('YYYY-MM-DD HH:mm:ss'));
      console.log('前1月的日期和时间', dayjs().add(-1, 'month').format('YYYY-MM-DD HH:mm:ss'));
      console.log('前1天的日期和时间', dayjs().add(-1, 'day').format('YYYY-MM-DD HH:mm:ss'));
      console.log('当天日期和时间-服务端', dayjs().format('YYYY-MM-DD HH:mm:ss'));
      console.log('当天日期和时间-客户端', dayjs().format('YYYY年MM月DD日 HH时mm分ss秒'));
      console.log('后1天的日期和时间', dayjs().add(1, 'day').format('YYYY-MM-DD HH:mm:ss'));
      console.log('后1月的日期和时间', dayjs().add(1, 'month').format('YYYY-MM-DD HH:mm:ss'));
      console.log('后1年的日期和时间', dayjs().add(1, 'year').format('YYYY-MM-DD HH:mm:ss'));
    </script>
  </html>
5、获取日期和时长
  <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>获取日期和时长</title>
      <style>
        .display{
          padding: 50px;
          line-height: 50px;
        }
      </style>
    </head>
    <body>
      <div class="display">
        <div id="durationId1"></div>
        <div id="datetimeId1"></div>
      </div>
      <div class="display">
        <div id="datetimeId2"></div>
        <div id="durationId2"></div>
      </div>
    </body>
    <script>
      //以下,定义函数-获取日期
      function newDatetime(outMilliseconds) {
        function addZero(number) {
          return number.toString()[1] ? number : "0" + number;
        }
        var now = new Date();
        var nowMilliseconds = now.getTime();
        var distance = nowMilliseconds + outMilliseconds;
        var dateNew = new Date(distance);
        var year  = dateNew.getFullYear();
        var month  = addZero(dateNew.getMonth() + 1);
        var date = addZero(dateNew.getDate());
        var hour = addZero(dateNew.getHours());
        var minute = addZero(dateNew.getMinutes());
        var second = addZero(dateNew.getSeconds());
        var obj = {};
        obj.client = year + "年" + month + "月" + date + "日" + hour + "时" + minute + "分" + second + "秒";
        obj.server = year + "-" + month + "-" + date + " " + hour + ":" + minute + ":" + second;
        return obj
      }
      //以下,定义函数-获取时长
      function durationTime(datetime) {
        function addZero(number) {
          return number.toString()[1] ? number : "0" + number;
        }
        var now = new Date();
        var nowMilliseconds = now.getTime();
        var outMilliseconds = new Date(datetime).getTime();
        var distance = nowMilliseconds - outMilliseconds;
        if(distance < 0) distance = -distance;
        var seconds = Math.floor(distance/1000)
        var day = Math.floor(seconds / 86400);
        var hour = Math.floor((seconds % 86400) / 3600);
        var minute = Math.floor(((seconds % 86400) % 3600) / 60);
        var second = Math.floor(((seconds % 86400) % 3600) % 60);
        var client = "";
        var server = "";
        var obj = {};
        if (day > 0) {
          client += day + "天";
          server += day + " ";
        }
        if (day > 0 || hour > 0) {
          client += addZero(hour) + "小时";
          server += addZero(hour) + ":";
        }
        if (day > 0 || hour > 0 || minute > 0) {
          client += addZero(minute) + "分";
          server += addZero(minute) + ":";
        }
        if (day > 0 || hour > 0 || minute > 0 || second > 0) {
          client += addZero(second) + "秒";
          server += addZero(second);
        }
        obj.client = client;
        obj.server = server;
        return obj
      }
      //以下,定义函数-服务端写法改为客户端写法
      function serverToClient(dateTime) {
        dateTime = dateTime.replace('-', "年").replace('-', "月").replace(' ', "日")
        dateTime = dateTime.replace(':', "时").replace(':', "分") + "秒"
        return dateTime
      }
      // 以下,获取日期
      var durationStr = '1000 * 60 * 60 * 24'; //为正获取未来时间,为负获取过去时间,为0获取当前时间
      var durationNum = eval(durationStr);
      var durationEle1 = document.getElementById('durationId1');
      var datetimeEle1 = document.getElementById('datetimeId1');
      // 以下,获取时长
      var datetimeStr = '2022-02-24 11:00:00'; //早于现在为持续时长,晚于现在为倒计时;
      var datetimeDesc = '<br>开始的<b>俄乌战争</b>,到现在';
      var datetimeEle2 = document.getElementById('datetimeId2');
      var durationEle2 = document.getElementById('durationId2');
      function interval() {
        var now = newDatetime(0).client;//durationEle1.textContent
        durationEle1.innerHTML = '距现在<br>'+ now + '<br>' + durationNum + '(' + durationStr + ')毫秒,是';
        datetimeEle1.innerHTML = newDatetime(durationNum).client;
        datetimeEle2.innerHTML = '北京时间<br>'+ serverToClient(datetimeStr) + datetimeDesc + '<br>' + now + '<br>已经持续了';
        durationEle2.innerHTML = durationTime(datetimeStr).client;
      }
      interval()
      // 以下,开启定时器
      setInterval(function(){
        interval()
      },1000);
      // 以下,
    </script>
  </html>
5、是4的子级,可以删除
  <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>俄乌战争持续时长</title>
      <style>
        .display{
          padding: 50px;
          line-height: 50px;
        }
      </style>
    </head>
    <body>
      <div class="display">
        <div id="datetimeId2"></div>
        <div id="durationId2"></div>
      </div>
    </body>
    <script>
      function nowDatetime() {
        function addZero(number) {
          return number.toString()[1] ? number : "0" + number;
        }
        var now = new Date();
        var year  = now.getFullYear();
        var month  = addZero(now.getMonth() + 1);
        var date = addZero(now.getDate());
        var hour = addZero(now.getHours());
        var minute = addZero(now.getMinutes());
        var second = addZero(now.getSeconds());
        var client = year + "年" + month + "月" + date + "日" + hour + "时" + minute + "分" + second + "秒";
        return client
      }
      function durationTime(datetime) {
        function addZero(number) {
          return number.toString()[1] ? number : "0" + number;
        }
        var now = new Date();
        var nowMilliseconds = now.getTime();
        var outMilliseconds = new Date(datetime).getTime();
        var distance = nowMilliseconds - outMilliseconds;
        if(distance < 0) distance = -distance;
        var seconds = Math.floor(distance/1000)
        var day = Math.floor(seconds / 86400);
        var hour = Math.floor((seconds % 86400) / 3600);
        var minute = Math.floor(((seconds % 86400) % 3600) / 60);
        var second = Math.floor(((seconds % 86400) % 3600) % 60);
        var client = "";
        if (day > 0) client += day + "天";
        if (day > 0 || hour > 0) client += addZero(hour) + "小时";
        if (day > 0 || hour > 0 || minute > 0) client += addZero(minute) + "分";
        if (day > 0 || hour > 0 || minute > 0 || second > 0) client += addZero(second) + "秒";
        return client
      }
      function serverToClient(dateTime) {
        dateTime = dateTime.replace('-', "年").replace('-', "月").replace(' ', "日")
        dateTime = dateTime.replace(':', "时").replace(':', "分") + "秒"
        return dateTime
      }
      var str = '2022-02-24 11:00:00';
      var desc = '<br>开始的<b>俄乌战争</b>,到现在<br>';
      var datetimeEle2 = document.getElementById('datetimeId2');
      var durationEle2 = document.getElementById('durationId2');
      function interval() {
        datetimeEle2.innerHTML = '北京时间<br>'+ serverToClient(str) + desc + nowDatetime()
        durationEle2.innerHTML = '已经持续了<br>' + durationTime(str);
      }
      interval()
      setInterval(function(){
        interval()
      },1000);
    </script>
  </html>
 
十二、js数据类型与四种检测方法
 来源:https://www.cnblogs.com/dushao/p/5999563.html
1、数据类型
  (1)5种基本数据类型:number、string、boolean、undefined(变量声明未赋值)、null(变量声明赋此值,typeof'object')
  (2)2种引用数据类型:函数、对象(Array、Arguments、Object、Date、Error、RegExp)
  (3)使用从未声明的变量a,报错为"a is not defined"
  (4)x=x+5;
    在数学领域,x是未知数,下一步移项
    在计算机领域,x是变量,下一步右边的计算结果、赋值给左边
  (5)null与对象
    var value;
    console.log( value == null ) // 为true,则value为null
    console.log( typeof value == "object" && value ) // 为true,则value为普通对象
  (6)操作符(运算符)
    A、常见操作符,如,算术操作符、比较操作符、逻辑操作符、赋值操作符、位操作符、
    B、其他操作符,如,instanceof、typeofvoid、三元操作符
    C、B中的前3个,都有两种效果相同的写法,以void为例,‘void 0’和‘void(0)’
    D、void(0),计算但不返回值,等同于undefined,
    E、html示例,<a href="javascript:void(0)">单击此处什么也不会发生</a>,
    F、js示例,console.log(void(0) === undefined) //true
2、arguments,实参的副本
  (1)数据类型是类数组,对象的一种,Arguments与、Array、Object、Date、Error、RegExp、Function、类似
    A、模拟如下
      var argument = {
        0: 'param0',
        1: 'param1',
        2: 'param2',
        length: 3,
      }
    B、使用前,应通过Array.prototype.slice.call(arguments)转换为数组,
    C、数组方法slice的伪定义
      Array.prototype.slice = function(start,end){
        var result = new Array();
        start = start || 0;
        end = end || this.length; // 如A,当this指向arguments时,this.length即end为3
        for(var i = start; i < end; i++){
          result.push(this[i]);// 如A,分别是,this[0]、this[1]、this[2],没有this['length']
        }
        return result;
      }
  (2)arguments的数据类型检测
    function fn(){
      console.log( arguments );//[Arguments] { '0': 8, '1': 8, '2': 8 }
      console.log( '以下用对象的方法操作arguments:');
      console.log( '1:',Object.keys(arguments) );//[ '0', '1', '2' ],
      console.log( '2:',Object.values(arguments) );//[ 8, 8, 8 ]
      console.log( '3:',arguments.hasOwnProperty(0) );//true
      console.log( '4:',arguments.hasOwnProperty('0') );//true
      console.log( '5:',arguments.hasOwnProperty('length') );//true
      console.log( '以下用数组的方法操作arguments:');
      console.log( '6:',arguments.length );//3
      console.log( '7:',Array.prototype.slice.call(arguments)  );//[ 8, 8, 8 ]
      console.log( '以下检测arguments的数据类型:');
      console.log( '8:',typeof arguments === 'object' );//object
      console.log( '9:',arguments instanceof Object) // true
      console.log( '10:',arguments.constructor === Object) // true
      console.log( '11:',Object.prototype.toString.call(arguments));//[object Arguments]
      console.log( '以下检测-其它引用数据-的数据类型:');
      console.log( '12:',Object.prototype.toString.call([ 8, 8, 8 ]));//[object Array]
      console.log( '13:',Object.prototype.toString.call({ '0': 8, '1': 8, '2': 8 }));//[object Object]
      console.log( '14:',Object.prototype.toString.call(new Object()));//[object Object]
      console.log( '15:',Object.prototype.toString.call(new Date()));//[object Date]
      console.log( '16:',Object.prototype.toString.call(new Error()));//[object Error]
      console.log( '17:',Object.prototype.toString.call(/test/));//[object RegExp]
      console.log( '18:',Object.prototype.toString.call(function(){}));//[object Function]
    }
    fn(8,8,8)
3、四种检测方式   
  附、被检测的数据
    var myNull = null;
    var myUndefined = undefined;
    var myString = "string";
    var myNumber = 222;
    var myBoolean = true;
    var myFunction = function(){};
    var myArray= [1,2,3];
    var myObject = {a:1};
    var myRegexp = /test/;
    var myDate = new Date();
    var myError = new Error();
    console.log("(1)以下用typeof检测,返回值是字符串")
    console.log(typeof myNull === 'object') // true
    console.log(typeof myUndefined === 'undefined') // true
    console.log( '----------------------------------------' );
    console.log(typeof myString === 'string') // true
    console.log(typeof myNumber === 'number') // true
    console.log(typeof myBoolean === 'boolean') // true
    console.log(typeof myFunction === 'function') // true
    console.log(typeof myArray === 'object') // true
    console.log(typeof myObject === 'object') // true
    console.log(typeof myRegexp === 'object') // true
    console.log(typeof myDate === 'object') // true
    console.log(typeof myError === 'object') // true
    console.log( '----------------------------------------' );
    var obj = {
      1: 'one',
    }
    for(var attr in obj){
      console.log( typeof attr );//为什么是string,不是number
    }
    console.log("(2)以下用instanceof检测,返回值是布尔")
    console.log(new String() instanceof String) // true 
    console.log(new Number() instanceof Number) // true 
    console.log(new Boolean() instanceof Boolean) // true 
    console.log( '----------------------------------------' );
    console.log(myString instanceof String) // false
    console.log(myNumber instanceof Number) // false 
    console.log(myBoolean instanceof Boolean) // false 
    console.log(myFunction instanceof Function) // true 
    console.log(myArray instanceof Array) // true
    console.log(myObject instanceof Object) // true
    console.log(myRegexp instanceof RegExp) // true
    console.log(myDate instanceof Date) // true
    console.log(myError instanceof Error) // true
    console.log("(3)以下用constructor检测,返回值是类")
    console.log(myString.constructor === String) // true
    console.log(myNumber.constructor === Number) // true
    console.log(myBoolean.constructor === Boolean) // true
    console.log(myFunction.constructor === Function) // true 
    console.log(myArray.constructor === Array) // true
    console.log(myObject.constructor === Object) // true
    console.log(myRegexp.constructor === RegExp) // true
    console.log(myDate.constructor === Date) // true
    console.log(myError.constructor === Error) // true
    console.log("(4)以下用prototype检测,返回值是字符串")
    console.log(Object.prototype.toString.call(myNull) === "[object Null]") // true;
    console.log(Object.prototype.toString.call(myUndefined) === "[object Undefined]") // true;
    console.log( '----------------------------------------' );
    console.log(Object.prototype.toString.call(myString) === "[object String]") // true;
    console.log(Object.prototype.toString.call(myNumber) === "[object Number]") // true;
    console.log(Object.prototype.toString.call(myBoolean) === "[object Boolean]") // true;
    console.log(Object.prototype.toString.call(myFunction) === "[object Function]") // true;
    console.log(Object.prototype.toString.call(myArray) === "[object Array]") // true;
    console.log(Object.prototype.toString.call(myObject) === "[object Object]") // true;
    console.log(Object.prototype.toString.call(myRegexp) === "[object RegExp]") // true;
    console.log(Object.prototype.toString.call(myDate) === "[object Date]") // true;
    console.log(Object.prototype.toString.call(myError) === "[object Error]") // true;
 
十三、数字转化
原文地址:https://yq.aliyun.com/ziliao/92498?spm=5176.8246799.blogcont.20.cUDmIE
1、Number()
  (1)如果是Boolean值,truefalse值将分别被转换为1和0。
  (2)如果是数字值,只是简单的传入和返回。
  (3)如果是null值,返回0。
  (4)如果是undefined,返回NaN。
  (5)如果是字符串:
    A、如果字符串中只包含数字时,将其转换为十进制数值,忽略前导0
    B、如果字符串中包含有效浮点格式,如“1.1”,将其转换为对应的浮点数字,忽略前导0
    C、如果字符串中包含有效的十六进制格式,如“0xf”,将其转换为相同大小的十进制数值
    D、如果字符串为空,将其转换为0
    E、如果字符串中包含除上述格式之外的字符,则将其转换为NaN
  (6)如果是对象,则调用对象的valueOf()方法,然后依照前面的规则转换返回的值。
    如果转换的结果是NaN,则调用对象的toString()方法,然后再依照前面的规则转换返回的字符串值。
    var num1 = Number("Hello world");//NaN
    var num2 = Number("");//0
    var num3 = Number("0000011"); //11
2、parseInt(数字字符串,进制)
  (1)空字符串,返回NaN
  (2)忽略字符串前面的空格,直到找到第一个非空格字符,第一个小数点后面的字符被忽略
    A、如果第一个字符不是数字或者负号,返回NaN
    B、如果第一个字符是数字字符,继续解析第二个字符,直到解析完所有后续字符串或者遇到了一个非数字字符
  (3)进制,默认10
  (4)示例
    var num1 = parseInt("AF",16); //175
    var num2 = parseInt("AF");//NaN
    var num3 = parseInt("10",2); //2(按照二进制解析)
    var num4 = parseInt("sdasdad");//NaN
3、parseFloat((数字字符串,无)
  (1)空字符串,返回NaN
  (2)忽略字符串前面的空格,直到找到第一个非空格字符,第二个小数点后面的字符被忽略
    A、如果第一个字符不是数字或者负号,返回NaN
    B、如果第一个字符是数字字符,继续解析第二个字符,直到解析完所有后续字符串或者遇到了一个非数字字符
  (3)进制,只解析十进制,因此它没有第二个参数指定基数的用法
  (4)如果字符串中包含的是一个可解析为正数的数(没有小数点,或者小数点后都是零),返回整数
  (5)示例
    var num1 = parseFloat("123AF"); //123
    var num2 = parseFloat("0xA");//0
    var num3 = parseFloat("22.5");  //22.5
    var num4 = parseFloat("22.3.56");//22.3
    var num5 = parseFloat("0908.5"); //908.5
    parseInt() 和parseFloat() 的区别在于:
    parseFloat() 所解析的字符串中第一个小数点是有效的,而parseInt() 遇到小数点会停止解析,因为小数点并不是有效的数字字符。
    parseFloat() 始终会忽略前导的零,十六进制格式的字符串始终会被转换成0,
    而parseInt() 第二个参数可以设置基数,按照这个基数的进制来转换。
4、customParseInt:字符串类型的数字转换成数字类型的数字、数字类型的数字和字符串类型的非数字保持原样
  function customParseInt(num) {
    var tempNum = parseInt(num);
    if (typeof tempNum === 'number' && !isNaN(tempNum)) {
      return tempNum;
    }
    return num;
  };
  console.log(customParseInt(1))
  console.log(customParseInt("1"))
  console.log(customParseInt("闪烁"))
4、整型范围
  (1)有负号整型范围
    Int8:[-128:127]
    Int16:[-32768:32767]
    Int32:[-2147483648:2147483647]
    Int64:[-9223372036854775808:9223372036854775807]
  (2)无负号整型范围
    UInt8:[0:255]
    UInt16:[0:65535]
    UInt32:[0:4294967295]
    UInt64:[0:18446744073709551615]
 
十四、对象相关
1、三个基本特征
  (1)封装,可以隐藏实现细节,使得代码模块化,实现代码重用
  (2)继承,可以扩展已存在的代码模块(类),实现代码重用
  (3)多态,实现接口重用
2、对象基本概念(面对对象编程)
  (1)类,是以函数的形式来定义的,函数也是一个对象,函数对象都有一个子对象prototype
    function Abc(){}; Abc.prototype.aaa = function(){};
  (2)实例,通过new创建一个类的实例对象,
    var abc = new Abc(); abc.__proto__.aaa
  (3)原型链,构造函数原型与实例对象之间的连接,类的属性prototype对象的成员都是实例对象的成员,
    可以通过实例的属性__proto__获取,访问对象的一个属性或方法的时候,
    如果这个对象没有这个方法或属性,那么Javascript引擎将会访问这个对象的__proto__属性所指向的对象,
    若仍不能找到,就会继续向上查找,直到Object对象,还没找到该属性,则返回undefined
    console.log(Abc.prototype ===  abc.__proto__)//true
    console.log(Abc.prototype.aaa ===  abc.__proto__.aaa)//true
    console.log(aaa.__proto__.__proto__ === Object.prototype)//true
3、特殊原型链示例
  var obj = {}
  function fn(){}
  (1)函数类或对象类或普通函数的原型
    Object.prototype={};
    Function.prototype={};
    fn.prototype = {};
  (2)函数类或对象类或普通函数或普通对象_所在类的原型
    Function.__proto__ === Function.prototype
    Object.__proto__ === Function.prototype
    fn.__proto__ === Function.prototype;
    obj.__proto__ === Object.prototype;
  (3)函数类或对象类或普通函数或普通对象_所在类的原型_之所在类的原型...
    Function.__proto__.__proto__ === Function.prototype.__proto__ === Object.prototype
    Object.__proto__.__proto__ === Function.prototype.__proto__ === Object.prototype
    Function.__proto__.__proto__.__proto__ === Function.prototype.__proto__.__proto__ === Object.prototype.__proto__ === null
    Object.__proto__.__proto__.__proto__ === Function.prototype.__proto__.__proto__ === Object.prototype.__proto__ === null
  (4)原型链继承
    Drag.prototype.__proto__ = EventEmitter.prototype;//这是更安全的继承方法,一般在Node里都是采用这种方式实现继承。IE不支持
    Drag.prototype = new EventEmitter;//相对这种方式来说,上边的写法更安全
4、with语句与性能检测
  (1)缺点,可能会导致数据泄漏到全局作用域    
  (2)with语句,将代码的作用域设置到一个特定的对象中
    console.time('这是性能检测,参数必须一样');
      var foo = {
        bar: {
          data: {
            x: 0,
            y: 0,
            z: 0,
          }
        }
      }
      //1、以下不用with分别打点,赋值与获取
        foo.bar.data.x = 1111;
        foo.bar.data.y = 2222;
        foo.bar.data.z = 3333;
        console.log( foo.bar.data.x, foo.bar.data.y, foo.bar.data.z );
      //2、以下用1个with打点,赋值与获取
        with(foo.bar.data){
          x = 111;
          y = 222;
          z = 333;
        }
        with(foo.bar.data){
          console.log( x, y, z );
        }
      //3、以下用3个with连用,赋值与获取
        with(foo)with(bar)with(data){
          x = 11;
          y = 22;
          z = 33;
        }
        with(foo)with(bar)with(data){
          console.log( x, y, z );
        }
    console.timeEnd('这是性能检测,参数必须一样');
5、多态
   附、同一操作作用于不同的对象上面,可以产生不同的执行结果。比如你说“叫”,鸭子听了会发出“嘎嘎声”,鸡听了会发出“咯咯声”。
  (1)非多态代码示例
    var makeSound = function(animal) {
      if(animal instanceof Duck) {
        console.log('嘎嘎嘎');
      } else if (animal instanceof Chicken) {
        console.log('咯咯咯');
      }
    }
    var Duck = function(){}
    var Chiken = function() {};
    makeSound(new Chicken());
    makeSound(new Duck());
  (2)多态的代码示例
    var makeSound = function(animal) {
      animal.sound();
    }
    var Duck = function(){}
    Duck.prototype.sound = function() {
      console.log('嘎嘎嘎')
    }
    var Chiken = function() {};
    Chiken.prototype.sound = function() {
      console.log('咯咯咯')
    }
    makeSound(new Chicken());
    makeSound(new Duck());
    另外,组件化开发的组件就相当于一个“对象”,一个操作“封装”成一个函数,通过调用内置方法“继承”内部的功能,“多态”没有体现
6、创建对象
  (1)工厂模式:
    function creatAnimal(name,age) {
      var animal = new Object();
      animal.name = name;
      animal.age = age;
      animal.eat = function(){
        this.name + "会吃饭"
      }
      return animal
    }
    var dog = creatAnimal('小狗','2')
    console.log(dog);
  (2)构造函数模式:
    function Animal(name, age) {
      this.name = name;
      this.age = age;
    }
    this.prototype.eat = function () {
      console.log(this.name + "会吃饭");
    }
    var dog = creatAnimal('小狗','2')
    console.log(dog);
7、Object.create(proto[, propertiesObject])
  (1)参数,
    A、proto:原型
    B、propertiesObject:属性
  (2)返回值,新对象
  (3)实例
    var prototype = { proto: 'proto' };
    var props = {
      attr: {
        enumerable: true,
        value: 'attr'
      }
    };
    var obj = Object.create( prototype, props )
    console.log( obj )
    console.log( obj.attr )
    console.log( obj.proto )
    console.log( obj.__proto__ === prototype, 'obj.__proto__ === prototype' )
8、Object.defineProperty(myObject, prop, descriptor)
  来源,https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
  (1)参数,
    A、myObject要定义或修改的属性所在的对象
    B、prop要定义或修改的属性的名称
    C、descriptor要定义或修改的属性的描述符,共4个,
  (2)返回值,myObject
  (3)作用,定义或者修改myObject的属性
  (4)共享-描述符
    A、configurable,默认为false。为true时,prop可删,描述符可改
    B、enumerable,默认为false。为true时,prop可枚举
  (5)数据-描述符,和访问器描述符不能并存
    A、value,属性值,可以是数值、对象、函数等,默认为undefined
    B、writable,默认为false。为true时,prop可重写
  (6)访问器-描述符,和数据描述符不能并存
    A、get,属性的getter函数,当访问prop时,会调用此函数,该函数的返回值被用作属性值,默认为undefined。
    B、set,属性的setter函数,当属性值被修改时,会调用此函数,该函数接受1个参数,默认为undefined。
  (7)示例
    A、数据-描述符
      var myObj = { thisValue: 5 };
      Object.defineProperty(myObj, "key", {
        configurable: false,
        enumerable: false,
        value: 'myValue',
        writable: true,
      });
      myObj.key = 'youValue';
      console.log(myObj.key);
    B、访问器-描述符
      var myObj = { thisValue: 5 };
      Object.defineProperty(myObj, "key", {
        configurable: false,
        enumerable: false,
        get: function () {
          console.log(this);
          return key+2;
        },
        set: function (value) {
          console.log(this);
          key = value + 1;
        },
      });
      myObj.key = 5;
      console.log(myObj.key);
    C、访问器-描述符
      var eric={
        ename:"艾力克",
        eage:25
      };
      Object.defineProperties(eric,{
        _eage:{
          value:eric.eage,
          writable:true
        },
        eage:{
          get:function(){
            return this._eage;
          },
          set:function(value){
            if(value>=18 && value<=65){
              this._eage=value;
            }else{
              throw Error("年龄必须介于18~65岁之间");
            }
          },
          enumerable:true,
          configurable:false
        }
      });
      console.log(eric.eage);//25
      eric.eage=18;
      console.log(eric.eage);//18
      eric.eage=16;
      console.log(eric.eage);//超出范围,报错
  (8)vue响应式相关代码
    function def(obj, key, val, enumerable) {
      Object.defineProperty(obj, key, {
        configurable: true,
        enumerable: !!enumerable,
        value: val,
        writable: true,
      });
    }
    Object.defineProperty(obj, key, {
      configurable: true,
      enumerable: true,
      get: function reactiveGetter() {
        var value = getter ? getter.call(obj) : val;
        return value;
      },
      set: function reactiveSetter(newVal) {
        var value = getter ? getter.call(obj) : val;
        dep.notify();
      },
    });
 
十五、函数相关
1、相关定义
  (1)函数:一段可以重复使用的代码块
  (2)高阶函数:操作其他函数的函数,比如map、forEach
  (3)重载:Java一个函数可以有多个定义,只要这每个定义的签名(参数的类型和数量)不同即可。JS没有签名,所以不能重载
  (4)预解释:在代码执行之前,JavaScript引擎会先对代码进行一次扫描,将变量声明和函数声明提升到当前作用域的顶部
  (5)闭包:能够读取其他函数内部变量的函数,即函数里的函数;好处,避免污染全局变量;坏处,有可能造成内存泄漏;
2、内存泄漏的情形
  (1)意外的全局变量
  (2)未解除的事件监听器
  (3)未移除的定时器或回调函数
  (4)闭包,一个函数作为函数的执行结果被一个变量引用
3、函数执行(函数调用)方式
  (1)直接调用;
    function aaa (){
      return '返回值' //return row.text = "发布",先给变量赋值,再返回变量
    }
    aaa ()
  (2)对象调用;
  (3)new调用;
  (4)call、apply调用
  (5)自执行
    A、开始+、-、!、void
      !function () {
        console.log(444);
      }();
    B、前面()
      (function () {
        console.log(222);
      })();
    C、外部()
      (function () {
        console.log(111);
      }());
    D、外部[] 
      [function () {
        console.log(333);
      }()];
    E、示例,减少全局变量
      示例1、
        for(var i=0; i<aBtn.length; i++){
          (function(index){
            aBtn[index].onclick=function click(){
              alert(index);
            }
          })(i);
        }
      示例2、
        for(var i=0; i<6; i++){
          (function(index){
            setTimeout(function(){
              console.log(i);
              console.log(index);
            })
          })(i);
        }
      示例3、
        (function (allFn) { //连续3次自执行
          allFn()
        })(function () {
          return (function outerFn(m) {
            function recursion(n) {
              console.log( n );
              return n
            }
            recursion(m)
            return recursion
          })(1)(16)
        });
   附、变量滞后,预解释与执行顺序
    function n() { //第3步执行
      console.log(o);
    }
    var o = {}; //第1步执行
    n() //第2步执行
 
十六、节流、去抖、柯里化、点透
1、函数节流(throttle):不重新开始计时。
  var last = 0;//上次点击时间
  function clickIt(li) {
    var curr = +new Date();
    if (curr - last < 2000) {//2秒钟
      return
    }else{
      last = curr;
    }
    //执行逻辑
  }
2、函数去抖(debounce):重新开始计时。
  var last = 0;//上次点击时间
  function clickIt(li) {
    var curr = +new Date();
    if (curr - last < 2000) {//2秒钟
      last = curr;
      return
    }
    //执行逻辑
  }
3、柯里化函数:函数里面返回函数,函数执行过后再执行,第一次执行公共部分
  (1)示例一
    js 如何实现sum(2,3)===sum(2)(3)
    function sum() {
      var arguments0 = arguments[0];
      if (arguments.length === 1) {
        return function (arguments1) {
          return arguments0 + arguments1;
        }
      }
      if (arguments.length === 2) {
        return arguments[0] + arguments[1]
      }
    }
    console.log(sum(2,3)==sum(2)(3));
  (2)示例2
    function fn(a, b) {
      return function inner(type) {
        let res
        switch (type) {
          case '+': res = a + b; break;
          case '-': res = a - b; break;
          case '*': res = a * b; break;
          case '/': res = a / b; break;
        }
        return res
      }
    }
    var f = fn(100, 200)// f 接受到的就是 inner 函数
    console.log(f('+'))
    console.log(f('-'))
    console.log(f('*'))
    console.log(f('/'))
4、点透
  (1)为什么移动端浏览器的click事件延迟300毫秒执行?
    A、原因:要观察用户是否进行第2次点击,进而判断用户是想单击页面,还是想双击缩放页面
  (2)点透发生的情形:
    A、click移动端浏览器的元素,立即触发touch事件,
    B、如果touch事件的执行结果是该元素从文档树上消失,a或input元素出现
    C、那么300ms后click事件会发生在a或input元素上
    D、这个现象给人的感觉就是“点透”了
  (3)点透的解决方案:
    A、在touch事件里,延迟执行touch事件的代码或阻止默认的click事件
    B、定时器延迟
      ele.addEventListener("touchend",function (event) {
          setTimeout(function () {
              ele.style.display="none";
          },400);
      });
      //以下zepto的tap事件点透解决
      ele.on("touchend", function () {
          setTimeout(function () {
            $("#alertBox").hide();
          }, 350);
      });
    C、阻止默认事件
      ele.addEventListener("touchend",function (event) {
          ele.style.display="none";
          event.preventDefault();
      });
      //以下zepto的tap事件点透解决
      ele.on("touchend", function (e) {
          $("#alertBox").hide();
          e.preventDefault();
      });
 
十七、循环
附、JS的逗号,用来将多个表达式连接为一个表达式,新表达式的值为最后一个表达式的值
1、for循环三种写法
  for (语句 1; 语句 2; 语句 3){
    //被执行的代码块
    //语句1:在循环前执行
    //语句2:循环的条件
    //语句3:在循环后执行,缺失不会报错
  }
  (1)写法一
    for(var i=0;i<10;i++){
      console.log(i);
      //如果我们用for循环要输出0到9,我们可以这么写
  }
  (2)写法二
    for(var i=10;i-=2;){//循环条件(为真时)、循环方式(递减),合二为一
      console.log(i);
      //在语句2中,如果返回true循环会继续执行。在js中0,null,undefined,false,'',””作为条件判断时,其结果为false,也就说当i--到0的时候就是false,循环就终止了。
    }
  (3)写法三
    var rules = [-2, -1, 0, 2, 1];
    for (var i = 0, rule; rule = rules[i++];) {
      console.log(rule);
      //var i = 0, rule;这是声明变量,是语句1,在循环前执行;
      //rule = rules[i++];这是循环的条件,是语句2;当成为undefined时就会终止循环。
    }
  (4)只终止内层
      for (var i = 0; i < 10; i++) {
        for (var j = 0; j < 10; j++) {
          if (i > 3) { // j > 3; i === j
            break;
          }
          console.log(i, j)
        }
      }
  (5)多条件同时成立
    A、外部可读
      for(var i=0,j=0; i<10,j<6; i++,j++){//i<10,j<6;同时成立
        var k=j+i;
      }
      console.log(i,j,k);//6,6,10
    B、外部不可读
      for(let i=0,j=0; i<10,j<6; i++,j++){
        let k=j+i;
      }
      console.log(i,j,k);//i is not defined
2、while循环
  (1)执行代码放在while前的do
    var i = 0;
    do {
      i++;
      console.log(i)
    }
    while (i < 4);
  (2)执行代码放在while
    var i=4;
    while (i--) {//条件
      console.log(i)
    }
    
十八、JS设计模式
来源:https://www.cnblogs.com/younghxp/p/16397059.html
扩展:https://blog.csdn.net/qq_41311259/article/details/119254280
  包含:(1)策略模式(2)单例模式(3)代理模式(4)模板模式(5)享元模式(6)装饰器模式(7)观察者模式(8)发布-订阅模式
  联想:车模、想装、担待
1、策略模式,算法使用与算法本身分离开来,避免“多重平行条件”选择语句,代码复用性高
  另外,“多重嵌套条件”选择语句,仍然需要if-else嵌套或递归函数,不能使用策略模式
  (1)策略模式1
    let strategies = {
      'S': function (salary) {
        return salary * 4
      },
      'A': function (salary) {
        return salary * 3
      },
      'B': function (salary) {
        return salary * 2
      },
    }
    function calculateBouns (level, salary) {
      return strategies[level](salary);
    }
    console.log(calculateBouns('S', 20000))
    console.log(strategies[level](salary))
  (2)策略模式2
    var message = [
      [!roleName,'角色名称不能为空!'],
      [!selfName,'注册名称不能为空!'],
      [outIds.length === rolesNum,'当前状态不能为空!'],
    ]
    for(var index = 0; index < message.length; index++){
      if(message[index][0]){
        return layer.open({
          title: '系统信息',
          content: message[index][1],
          skin: 'layui-ext-yourskin'
        });
      }
    }
  (3)策略模式3
    //下面情形,用策略模式,不管范围有多少种,都只需1+2个判断,不用策略模式,则需要n+2个判断
    var num = 400;
    var msg = '';
    var rang = [
      [0, 100, '检测数据' + num + '处于[0-100)之间'],
      [100, 200, '检测数据' + num + '处于[100-200)之间'],
      [200, 300, '检测数据' + num + '处于[200-300)之间'],
      [300, 400, '检测数据' + num + '处于[300-400)之间'],
      [400, 500, '检测数据' + num + '处于[400-500)之间'],
      [500, 600, '检测数据' + num + '处于[500-600)之间'],
      [600, 700, '检测数据' + num + '处于[600-700)之间'],
    ];
    var tip = {
      front: '检测数据' + num + '小于' + rang[0][0],
      back: '检测数据' + num + '大于' + rang[rang.length - 1][1]
    }
    for (var i = 0; i < rang.length; i++) {
      if (i == 0 && num < rang[i][0]) {
        msg = tip.front;
        break;
      }
      if (i == rang.length - 1 && num > rang[i][1]) {
        msg = tip.back;
        break;
      }
      if (num >= rang[i][0] && num < rang[i][1]) {
        msg = rang[i][2];
        break;
      }
    }
    console.log(msg)
2、单例模式,一个类仅有一个实例,提供访问他的全局api,如VueX,React-redux
  (1)惰性创建单例
    var createDiv = (function () {
      var instance;
      return function () {
        if (!instance) {
          var div = document.createElement('div');
          div.innerHTML = '我是登录窗口';
          div.style.display = 'none';
          document.body.appendChild(div);
          instance = div;
        }
        return instance
      }
    })()
    button.addEventListener('click', function () {
      let div = createDiv();
      div.style.display = 'block';
    })
  (2)Class创建单例
    class Singleton {
      constructor (name) {
        this.name = name
      }
      static getInstance (name) {//静态方法
        if (!this.instance) {
          this.instance = new Singleton(name)
        }
        return this.instance
      }
    }
    let a = Singleton.getInstance('a1');
    let b = Singleton.getInstance('b2');
    console.log(a == b)//true
3、代理模式,为一个对象提供一个占位符,以便控制对它的访问;
  (1)不使用代理加载图片
    function myImage(id,src){
      var imgNode = document.createElement("img");
      imgNode.src = src;
      document.getElementById(id).appendChild(imgNode);
       
    };
    myImage.setSrc("id","pic.png");
  (2)使用代理加载图片
    function myImage(id,src,load){
      //src:图片较大,下载慢,后出现
      //load:图片较小,下载快,先占位
      var imgNode = document.createElement("img");
      imgNode.src = load;
      document.getElementById(id).appendChild(imgNode);
      var img = new Image();
      img.src = src;
      img.onload = function(){
        imgNode.setSrc(img.src);
      };
       
    };
    myImage.setSrc("id","loading.gif","pic.png");
  (3)图片加载出错处理
    $timeout(function () {
      var thisImg = new Image();
      thisImg.src = $scope.r_g_company.logoPage.logo.src;
      thisImg.onerror= function() {
        $scope.r_g_company.logoPage.logo.src = $scope.r_g_company.logoPage.logo.srcCY
      }
    },1000);
    $.get('/app_v3/oem/info?' +new Date().getTime()).then(function (res) {
      $scope.r_g_company.logoPage.logo.src = '/audit-html/static/img/cy_oem/logo.png';
    }).catch(function(){
      $scope.r_g_company.logoPage.logo.src = '/audit-html/static/img/cy_oem/logo.png';
      $scope.r_g_company.logoPage.logo.srcCY = '/audit-html/static/img/cy_tech/logo.png';
    });
4、模板模式,实现方式为继承
  function Sport() {}
  Sport.prototype = {
    constructor: Sport,
    init: function() {
      this.stretch();
      this.deepBreath(); 
    },
    stretch: function() {
      console.log('拉伸');
    },
    deepBreath: function() {
      console.log('深呼吸');
    },
  };
  function Basketball() {};
  Basketball.prototype = new Sport();
  Basketball.prototype.start = function() {
    console.log('先投上几个三分');
  };
  basketball.init();
5、享元模式,减少对象的数量
  function Health(sex) {
    this.name = name;
    this.sex = sex;
    this.age = age;
    this.height = height;
    this.weight = weight;
  }
  Health.prototype.judge = function(name) {
    HealthManager.updateHealthData(name, this);
    var ret = name + ': ';
    if (this.sex === 'male') {
      ret += this.judgeMale();
    } else {
      ret += this.judgeFemale();
    }
  };
  Health.prototype.judgeMale = function() {
    var ratio = this.height / this.weight;
    return this.age > 20 ? (ratio > 3.5) : (ratio > 2.8);
  };
  Health.prototype.judgeFemale = function() {
    var ratio = this.height / this.weight;
    return this.age > 20 ? (ratio > 4) : (ratio > 3);
  };
  var HealthFactory = {
    objs: {},
    create: function(sex) {
      if (!this.objs[sex]) {
        this.objs[sex] = new Health(sex);
      }
      return this.objs[sex];
    }
  };
  var HealthManager = {
    healthData: {},
    add: function(name, sex, age, height, weight) {
      var health = HealthFactory.create(sex);
      // 存储变化的数据
      this.healthData[name] = {
        age: age,
        height: height,
        weight: weight
      };
      return health;
    },
    // 从存储的数据中获取,更新至当前正在使用的对象
    updateHealthData: function(name, obj) {
      var healthData = this.healthData[name];
      for (var item in healthData) {
        if (healthData.hasOwnProperty(item)) {
          obj[item] = healthData[item];
        }
      }
    }
  };
  var one = HealthManager.add('A', 'male', 18, 160, 80);
  var two = HealthManager.add('B', 'male', 21, 180, 70);
  one.judge('A'); // A: false
  two.judge('B'); // B: false
6、装饰器模式,在原来方法的基础上,添加一些新功能,有点类似代理模式,实际用于ajax请求的拦截器等
  (1)创建主类
    class Circle {
      draw() {
        console.log('画一个圆形');
      }
    }
  (2)创建装饰器
    class Decorator {
      constructor(circle) {
        this.circle = circle;
      }
      draw() {
        this.circle.draw();
        this.setRedBorder(circle);
      }
      setRedBorder(circle) {
        console.log('画一个红色边框');
      }
    }
  (3)使用装饰器
    let circle = new Circle();
    let decorator = new Decorator(circle);
    decorator.draw();
7、观察者模式
  (1)观察者类
    class Observer {
      //name需要观察的参数
      //callback 观察的参数达到边界条件触发的事件
      constructor(name, callback) {
        this.name = name;
        this.callback = callback;
      }
    }
  (2)被观察者类
    class Subject {
      //未传值初始为空
      constructor(state) {
        //初始状态
        this.state = state;
        //观察者方法队列
        this.observsers = [];
      }
      //设置自己的状态
      setState(val) {
      //告诉观察者目前改变成了什么状态
        var that = this;
        this.state = val;
        //同时需要把自己身上的观察者方法全部触发
        this.observsers.map(function(item){
          //item是每一个观察者,每一个观察者是一个对象
          item.callback(that.state);
        })
      }
      //添加观察者
      addObserver(observer) {
        //把观察者传递进来
        this.observsers.push(observer);
      }
      //删除观察者
      removeObserver(observer) {
        //过滤出来非当前观察者的观察者
        this.observsers = this.observsers.filter(function(obs){
          return obs !== observer;
        });
      }
    }
  (3)使用
    let obj = {
      name: "abc"
    };
    //创建观察者与被观察者
      //创建观察者
        const observer = new Observer('watchName', function(newState){
          console.log(newState);
        });
      //创建一个被观察者
        const subject = new Subject(obj.name);
      //添加一个观察者
        subject.addObserver(observer);
      //触发观察者方法
        subject.setState('123');
8、发布-订阅模式
  (1)发布者
    class Publisher {
      constructor(name, channel) {
        this.name = name;
        this.channel = channel;
      }
      //添加目录
      addTopic(topicName) {
        this.channel.addTopic(topicName);
      }
      //取消添加
      removeTopic(topicName) {
        this.channel.removeTopic(topicName);
      }
      //发布晨报
      publish(topicName) {
        this.channel.publish(topicName);
      }
    }
  (2)订阅者
    class Subscriber {
      constructor(name, channel) {
        this.name = name;
        this.channel = channel;
      }
      //订阅目录
      subscribe(topicName) {
        this.channel.subscribeTopic(topicName, this);
      }
      //取消订阅
      unSubscribe(topicName) {
        this.channel.unSubscribeTopic(topicName, this);
      }
      //接收发布后,更新
      update(topic) {
        console.log(`${topic}已经送到${this.name}家了`);
      }
    }
  (3)第三方平台
    class Channel {
      constructor() {
        this.topics = {};
      }
      //发布者在平台添加目录
      addTopic(topicName) {
        this.topics[topicName] = [];
      }
      //发布者取消添加
      removeTopic(topicName) {
        delete this.topics[topicName];
      }
      //订阅者订阅目录
      subscribeTopic(topicName, sub) {
        if (this.topics[topicName]) {
          this.topics[topicName].push(sub);
        }
      }
      //订阅者取消订阅
      unSubscribeTopic(topicName, sub) {
        this.topics[topicName].forEach(function(item, index){
          if (item === sub) {
            this.topics[topicName].splice(index, 1);
          }
        });
      }
      //平台通知某个目录下所有订阅者
      publish(topicName) {
        this.topics[topicName].forEach(function(item){
          item.update(topicName);//发布的内容-传给-订阅者的函数
        });
      }
    }
  (4)应用
    A、定义1个调度中心channel
        var channel = new Channel();
    B、定义2个发布者publisher1、publisher2
        var publisher1 = new Publisher("发布者1", channel);
        var publisher2 = new Publisher("发布者2", channel);
    C、定义3个订阅者subscriber1、subscriber2、subscriber3
      var subscriber1 = new Subscriber("订阅者1", channel);
      var subscriber2 = new Subscriber("订阅者2", channel);
      var subscriber3 = new Subscriber("订阅者3", channel);
    D、2家发布者在平台上添加了晨报1、晨报2和晨报3三种晨报,如{'晨报1':[]}
      publisher1.addTopic("晨报1");
      publisher1.addTopic("晨报2");
      publisher2.addTopic("晨报3");
      publisher2.removeTopic("晨报3");//取消添加
    E、3个订阅者在平台上订阅了晨报,将自己的实例注入到数组中,如{'晨报1':[thisInstance1]}
      subscriber1.subscribe("晨报1");
      subscriber2.subscribe("晨报1");
      subscriber2.subscribe("晨报3");
      subscriber3.subscribe("晨报2");
      subscriber3.subscribe("晨报3");
      subscriber3.unSubscribe("晨报3");//取消订阅
    F、发布者推送某个主题,遍历订阅者,并执行订阅者如thisInstance1的update函数
      publisher1.publish("晨报1");
      publisher1.publish("晨报2");
      publisher2.publish("晨报3");
  (5)观察者模式与发布订阅模式的区别
    A、观察者模式,为紧耦合,只有两个角色,目标对象维护观察者对象,并通知观察者
    B、发布订阅模式,为松耦合,有三个角色,多了一个第三方平台,目标对象和观察者对象,通过第三方平台进行通信
  (6)Vue的基本原理,运用发布-订阅模式,具体可查看手写vue2.x原理:https://gitee.com/younghxp/vue2-data-response
 
十九、业务逻辑
附、接口:url、method、参数、返回值
注、软件一般分为三个层次:表现层、业务逻辑层、数据层
1、表现层:负责界面展示
2、业务逻辑层:接收表现层的请求,向数据层请求数据,将数据返给表现层
  (1)业务,应用程序中的具体任务。前端程序员不仅要关注展示,还应关注业务,弄清不同业务之间的关系
  (2)业务逻辑,应用程序中,实现具体任务的代码
3、数据层:负责数据存储、读取
  
  

  

posted @   WEB前端工程师_钱成  阅读(3627)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示