-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathatom.xml
More file actions
492 lines (258 loc) · 780 KB
/
atom.xml
File metadata and controls
492 lines (258 loc) · 780 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>hh-blog</title>
<subtitle>Learning</subtitle>
<link href="https://hhumar.com/atom.xml" rel="self"/>
<link href="https://hhumar.com/"/>
<updated>2023-06-16T17:09:31.025Z</updated>
<id>https://hhumar.com/</id>
<author>
<name>hh</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>thinkbook加装固态硬盘滑丝全过程</title>
<link href="https://hhumar.com/2023/06/17/thinkbook/"/>
<id>https://hhumar.com/2023/06/17/thinkbook/</id>
<published>2023-06-16T16:16:07.000Z</published>
<updated>2023-06-16T17:09:31.025Z</updated>
<content type="html"><![CDATA[<blockquote><p>已经是上个月的事情了,现在忙完毕业的事情来记录一下</p></blockquote><h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>thinkbook 14+ 13500h 32g版本,存在多余m2硬盘位,恰巧硬盘价格比较低,所以入手了一块2t的爱国者p7000z,自己加装。</p><h2 id="过程"><a href="#过程" class="headerlink" title="过程"></a>过程</h2><h3 id="1-滑丝"><a href="#1-滑丝" class="headerlink" title="1.滑丝"></a>1.滑丝</h3><p>洗手、拆后盖、拔电源、按开机键放电,然后开始拧主板上的m2硬盘位螺丝。</p><p>这里建议拆机最好戴个手套,特别是新机第一次拆,容易划伤。</p><p>然后不出意外的话出意外了,据说是因为这颗螺丝设计不太合理+我自己没有足够重视,拧了几次就螺丝基本没有十字口了,而且纹丝未动。</p><p>最后好在用尖嘴钳夹着螺丝边缘转下来了,但是好戏还在后面。</p><p>装上硬盘后我需要找一颗新的螺丝来固定的我的硬盘,于是我开始在我买的常用笔记本螺丝套装里面找,妄图找一颗螺帽平面边缘足够大能压住硬盘的螺丝。最后勉强找到能压住的m2x5规格的螺丝开始往回拧,但我并不知道这颗螺丝的高度其实超了。好在螺柱底座足够坚硬,没有让我转穿c面?</p><p>但是螺丝拧断在里面了</p><p><img src="/2023/06/17/thinkbook/%E6%BB%91%E4%B8%9D1.jpg" alt="滑丝1"></p><p>于是我只好暂时用铜胶布和耐高温胶布固定着先用,然后火速下单了电磨套装</p><h3 id="2-断柱"><a href="#2-断柱" class="headerlink" title="2.断柱"></a>2.断柱</h3><p>然后电磨到了,我的思路是把断在里面的半颗螺丝磨出一个一字口,再用最小规格螺丝刀拧出来(大致比划了一下螺丝刀头宽度还合适,不会被主板上的螺柱卡住),但是磨的时候不可避免的会同时磨到主板上的螺柱,所以做了一些保护主板不被金属碎屑攻击的保护措施</p><p><img src="/2023/06/17/thinkbook/%E6%BB%91%E4%B8%9D4.jpg" alt="滑丝4"></p><p><img src="/2023/06/17/thinkbook/%E6%BB%91%E4%B8%9D3.jpg" alt="滑丝3"><img src="/2023/06/17/thinkbook/%E6%BB%91%E4%B8%9D5.jpg" alt="滑丝5"></p><p>最后废了九牛二虎之力算是成功取出,不过螺柱上半部也多了两个豁口,取出来的半截螺丝如下<img src="/2023/06/17/thinkbook/%E8%9E%BA%E4%B8%9D7.jpg" alt="螺丝7"></p><h3 id="3-结局"><a href="#3-结局" class="headerlink" title="3.结局"></a>3.结局</h3><p>最后也没找到合适规格的螺丝,把最开始滑丝的螺丝磨了个一字口拧回去了</p><p><img src="/2023/06/17/thinkbook/%E8%9E%BA%E4%B8%9D6.jpg" alt="螺丝6"></p>]]></content>
<summary type="html"><blockquote>
<p>已经是上个月的事情了,现在忙完毕业的事情来记录一下</p>
</blockquote>
<h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>thinkbook </summary>
<category term="生活" scheme="https://hhumar.com/categories/%E7%94%9F%E6%B4%BB/"/>
<category term="Hardware" scheme="https://hhumar.com/tags/Hardware/"/>
</entry>
<entry>
<title>WebGIS</title>
<link href="https://hhumar.com/2023/05/01/WebGIS/"/>
<id>https://hhumar.com/2023/05/01/WebGIS/</id>
<published>2023-04-30T16:58:18.000Z</published>
<updated>2023-04-30T17:02:07.660Z</updated>
<content type="html"><![CDATA[<blockquote><p>持续更新</p></blockquote><h3 id=""><a href="#" class="headerlink" title=""></a></h3><h2 id="基础积累"><a href="#基础积累" class="headerlink" title="基础积累"></a>基础积累</h2><h3 id="飞地"><a href="#飞地" class="headerlink" title="飞地"></a>飞地</h3><p>位于甲行政区境内而隶属于乙行政区的土地,如在北京和天津两市包围中的大厂回族自治县和香河县是河北省的飞地。</p><h3 id="争议地区注意底图完整"><a href="#争议地区注意底图完整" class="headerlink" title="争议地区注意底图完整"></a>争议地区注意底图完整</h3><p>阿克赛钦地区:中印冲突,现为中国实际控制</p><p>藏南地区:中印冲突,现为印度实际控制</p><p>台湾省</p><h3 id="一些文件格式"><a href="#一些文件格式" class="headerlink" title="一些文件格式"></a>一些文件格式</h3><h4 id="ShapeFile"><a href="#ShapeFile" class="headerlink" title="ShapeFile"></a>ShapeFile</h4><p>该格式是 ESRI(美国环境系统研究所,相当于设计圈的 adobe 公司的地位吧)研制的一种工业界的标准交换格式,几乎所有的开源及商业软件均支持,感兴趣的可以官方的ShapeFile文件的白皮书 <a href="https://www.esri.com/content/dam/esrisites/sitecore-archive/Files/Pdfs/library/whitepapers/pdfs/shapefile.pdf">https://www.esri.com/content/dam/esrisites/sitecore-archive/Files/Pdfs/library/whitepapers/pdfs/shapefile.pdf</a> ,它必须至少由三个文件组成:.shp 要素几何、.shx 形状索引、.dbf 属性数据,通常还会包含以下文件:.prj 投影描述:</p><p><img src="/2023/05/01/WebGIS/1644393880770-55aae70d-3c89-4f73-b176-a0e3b222a991.webp" alt="img"></p><p>因此 shapefile 是表示一组文件的集合,所以在使用的过程中通常以压缩包的形式存在,切记拷贝的时候别只拷贝了一个文件!不过这种格式虽然作为标准格式但是也有着一些缺点,通常我们程序员们并不是很偏爱这个格式,这里就不过多介绍。使用上可以通过 <a href="https://github.com/calvinmetcalf/shapefile-js">https://github.com/calvinmetcalf/shapefile-js</a> 等诸多开源库进行转换到 GeoJSON 进行使用。另外推荐一篇很有意思的文章 《Switch from Shapefile》 <a href="http://switchfromshapefile.org/">http://switchfromshapefile.org/</a></p><h4 id="WKT和WKB"><a href="#WKT和WKB" class="headerlink" title="WKT和WKB"></a>WKT和WKB</h4><p>WKT(Well-known Text) 使用文本表达几何对象的一种标记语言。</p><p>WKB(Well-known Binary) 使用二进制表达几何对象的一种标记语言。</p><p>下图分表是使用WKT与GeoJSON分别描述同一几何的差异:</p><p><img src="/2023/05/01/WebGIS/1644395126104-d74245b8-2694-47e8-a00f-81d66eb3925d.webp" alt="img"></p><p>可以看出其主要还是为了表达几何对象,相较 GeoJSON 而言,其无法存储属性数据,这种数据格式在很多数据库中都用以表达几何数据类型,日常开发中可以方便地使用 <a href="https://github.com/cschwarz/wkx">https://github.com/cschwarz/wkx</a> 来进行格式转换。</p><h4 id="TopoJSON"><a href="#TopoJSON" class="headerlink" title="TopoJSON"></a>TopoJSON</h4><p>TopoJSON 是 d3.js 作者发明的一种针对 GeoJSON 的紧凑的压缩格式,虽然在可读性上降低了,但是可以有效减少数据大小,并且保证拓扑上的正确,因其在编码的时候有效消除了冗余,通过共享边的形式存储,并且在存储上可以对整数坐标采用量化压缩,在简化数据需要保证原拓扑关系的时候相当有用,这里不再赘述,更多介绍可以查看作者的 <a href="https://github.com/topojson/topojson">https://github.com/topojson/topojson</a> 这个库。</p><p>DataV 在处理一些省市区下钻数据的时候既要保证省市边界不出现因简化而存在很多细小的缝隙还要保证数据体积足够小,因此使用到了这种数据格式,后面提到的DataV.GeoAtlas 的层级生成器的地理数据绑定默认也以这个格式来导出。</p><h4 id="kml-gt-geojson"><a href="#kml-gt-geojson" class="headerlink" title="kml->geojson"></a>kml->geojson</h4><p>工具mapbox/togeojson,<a href="https://github.com/mapbox/togeojson">https://github.com/mapbox/togeojson</a></p><p>Install it into your path with <code>npm install -g @mapbox/togeojson</code>.</p><pre class="language-none"><code class="language-none">~> togeojson file.kml > file.geojson</code></pre><h5 id="node中"><a href="#node中" class="headerlink" title="node中"></a>node中</h5><p>Install it into your project with <code>npm install --save @mapbox/togeojson</code>.</p><pre class="language-none"><code class="language-none">// using togeojson in nodejsvar tj = require('togeojson'), fs = require('fs'), // node doesn't have xml parsing or a dom. use xmldom DOMParser = require('xmldom').DOMParser;var kml = new DOMParser().parseFromString(fs.readFileSync('foo.kml', 'utf8'));var converted = tj.kml(kml);var convertedWithStyles = tj.kml(kml, { styles: true });</code></pre><h4 id="GLB文件"><a href="#GLB文件" class="headerlink" title="GLB文件"></a>GLB文件</h4><p>GLB文件是以图形语言传输格式(glTF)保存的3D模型,它以二进制格式存储有关3D模型的信息,包括节点层级、摄像机、材质、动画和网格。GLB文件是<a href="https://www.wenjianbaike.com/gltf.html">.GLTF</a>文件的二进制版本。</p><h5 id="GLB文件扩展信息"><a href="#GLB文件扩展信息" class="headerlink" title="GLB文件扩展信息"></a>GLB文件扩展信息</h5><p>glTF是一种高效、可扩展、可互操作的格式,用于传输和加载3D场景和模型。glTF格式的目标包括最大限度地减少文件大小、快速加载、完整的3D场景表示、运行时独立性以及伴随进一步开发的可扩展性。glTF的提出是源自于3D工业和媒体发展的过程中,对3D格式统一化的急迫需求。</p><p>GLB是glTF模型的二进制文件格式表示,它存储了glTF的组件,如JSON、BIN文件和图片。GLB避免了使用glTF格式文件变大的问题,通过压缩,GLB能更快地加载,提供完整的三维场景,且能在未来的开发中扩展。</p><p>GLB作为一个容器,用二进制格式实现glTF的内容,并规避了glTF的一些缺陷。GLB格式的规格说明有提到所有的读写的实现,供应用程序开发。</p><h5 id="GLB文件怎么打开?"><a href="#GLB文件怎么打开?" class="headerlink" title="GLB文件怎么打开?"></a>GLB文件怎么打开?</h5><p>目前很多常用的3D软件可以直接或者通过插件读写glb格式,例如Blender、Maya、3ds Max、Unity等等。</p><h3 id="地图投影"><a href="#地图投影" class="headerlink" title="地图投影"></a>地图投影</h3><p>地理坐标系(Geographic Coordinate System),是使用三维球面来定义地球表面位置,以实现通过经纬度对地球表面点位引用的坐标系。一个地理坐标系包括角度测量单位、本初子午线和参考椭球体三部分。在球面系统中,水平线是等纬度线或纬线。垂直线是等经度线或经线。</p><p>投影坐标系 (Projection coordinatesystem),是平面坐标系统,地图单位通常为米,也称非地球投影坐标系统(notearth),或者是平面坐标。投影坐标系使用基于X,Y值的坐标系统来描述地球上某个点所处的位置。这个坐标系是从地球的近似椭球体投影得到的,它对应于某个地理坐标系。</p><p>地图投影是利用一定数学法则把地球表面的经、纬线转换到平面上的理论和方法。</p><h4 id="不同投影格式转换"><a href="#不同投影格式转换" class="headerlink" title="不同投影格式转换"></a>不同投影格式转换</h4><h5 id="EPSG-3857转换经纬度-EPSG-4326"><a href="#EPSG-3857转换经纬度-EPSG-4326" class="headerlink" title="EPSG:3857转换经纬度(EPSG:4326)"></a>EPSG:3857转换经纬度(EPSG:4326)</h5><p>EPSG:3857是伪墨卡托投影,也被称为球体墨卡托,Web Mercator。它是基于墨卡托投影的,把 WGS84坐标系投影到正方形。 我们前面已经知道 WGS84 是基于椭球体的,但是伪墨卡托投影把坐标投影到球体上,这导致两极的失真变大,但是却更容易计算。这也许是为什么被称为“伪”墨卡托吧。 另外,伪墨卡托投影还切掉了南北85.051129°纬度以上的地区,以保证整个投影是正方形的。 因为墨卡托投影等正形性的特点,在不同层级的图层上物体的形状保持不变,一个正方形可以不断被划分为更多更小的正方形以显示更清晰的细节。 很明显,伪墨卡托坐标系是非常适合显示数据,但是不适合存储数据的,通常我们使用WGS84 存储数据,使用伪墨卡托显示数据。</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// javascript 转换</span><span class="token keyword">function</span> <span class="token function">mercatorTolonlat</span><span class="token punctuation">(</span><span class="token parameter">mercator</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">var</span> lonlat<span class="token operator">=</span><span class="token punctuation">{</span> <span class="token literal-property property">x</span><span class="token operator">:</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token literal-property property">y</span><span class="token operator">:</span><span class="token number">0</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">var</span> x <span class="token operator">=</span> mercator<span class="token punctuation">.</span>x<span class="token operator">/</span><span class="token number">20037508.34</span><span class="token operator">*</span><span class="token number">180</span><span class="token punctuation">;</span> <span class="token keyword">var</span> y <span class="token operator">=</span> mercator<span class="token punctuation">.</span>y<span class="token operator">/</span><span class="token number">20037508.34</span><span class="token operator">*</span><span class="token number">180</span><span class="token punctuation">;</span> y<span class="token operator">=</span> <span class="token number">180</span><span class="token operator">/</span>Math<span class="token punctuation">.</span><span class="token constant">PI</span><span class="token operator">*</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token operator">*</span>Math<span class="token punctuation">.</span><span class="token function">atan</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token function">exp</span><span class="token punctuation">(</span>y<span class="token operator">*</span>Math<span class="token punctuation">.</span><span class="token constant">PI</span><span class="token operator">/</span><span class="token number">180</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token operator">-</span>Math<span class="token punctuation">.</span><span class="token constant">PI</span><span class="token operator">/</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span> lonlat<span class="token punctuation">.</span>x <span class="token operator">=</span> x<span class="token punctuation">;</span> lonlat<span class="token punctuation">.</span>y <span class="token operator">=</span> y<span class="token punctuation">;</span> <span class="token keyword">return</span> lonlat<span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token number">12345678910111213</span></code></pre><h5 id="经纬度-EPSG-4326-转换EPSG-3857"><a href="#经纬度-EPSG-4326-转换EPSG-3857" class="headerlink" title="经纬度(EPSG:4326)转换EPSG:3857"></a>经纬度(EPSG:4326)转换EPSG:3857</h5><p>4326是WGS84的代码</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// javascript 转换</span><span class="token keyword">function</span> <span class="token function">lonLat2Mercator</span><span class="token punctuation">(</span><span class="token parameter">lonlat</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">var</span> mercator <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token literal-property property">x</span><span class="token operator">:</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token literal-property property">y</span><span class="token operator">:</span><span class="token number">0</span><span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">var</span> earthRad <span class="token operator">=</span> <span class="token number">6378137.0</span><span class="token punctuation">;</span> mercator<span class="token punctuation">.</span>x <span class="token operator">=</span> lonlat<span class="token punctuation">.</span>lng <span class="token operator">*</span> Math<span class="token punctuation">.</span><span class="token constant">PI</span> <span class="token operator">/</span> <span class="token number">180</span> <span class="token operator">*</span> earthRad<span class="token punctuation">;</span> <span class="token keyword">var</span> a <span class="token operator">=</span> lonlat<span class="token punctuation">.</span>lat <span class="token operator">*</span> Math<span class="token punctuation">.</span><span class="token constant">PI</span> <span class="token operator">/</span> <span class="token number">180</span><span class="token punctuation">;</span> mercator<span class="token punctuation">.</span>y <span class="token operator">=</span> earthRad <span class="token operator">/</span> <span class="token number">2</span> <span class="token operator">*</span> Math<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token number">1.0</span> <span class="token operator">+</span> Math<span class="token punctuation">.</span><span class="token function">sin</span><span class="token punctuation">(</span>a<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">/</span> <span class="token punctuation">(</span><span class="token number">1.0</span> <span class="token operator">-</span> Math<span class="token punctuation">.</span><span class="token function">sin</span><span class="token punctuation">(</span>a<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> mercator<span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><h4 id="计算指定区域不透水面对应年份面积"><a href="#计算指定区域不透水面对应年份面积" class="headerlink" title="计算指定区域不透水面对应年份面积"></a>计算指定区域不透水面对应年份面积</h4><p>栅格镶嵌-掩膜裁剪-栅格转矢量-矢量重投影(对应分带)-字段计算area-分类统计(DN为类别要求)</p><h2 id="GeoServer"><a href="#GeoServer" class="headerlink" title="GeoServer"></a>GeoServer</h2><p>GeoServer的目标是作为自由和开放的<a href="https://zh.wikipedia.org/w/index.php?title=%E7%A9%BA%E9%97%B4%E6%95%B0%E6%8D%AE%E5%9F%BA%E7%A1%80%E8%AE%BE%E6%96%BD&action=edit&redlink=1">空间数据基础设施</a>中的一分子。正如<a href="https://zh.wikipedia.org/wiki/Apache_HTTP_Server">Apache HTTP Server</a>提供了一个免费开放的网络服务器来发布<a href="https://zh.wikipedia.org/wiki/HTML">HTML</a>一样,GeoServer也打算对地理空间数据做同样的事情。</p><p>在<a href="https://zh.wikipedia.org/wiki/%E8%AE%A1%E7%AE%97_(%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6)">计算</a>领域,GeoServer是一个用<a href="https://zh.wikipedia.org/wiki/Java">Java</a>编写的<a href="https://zh.wikipedia.org/wiki/%E5%BC%80%E6%BA%90%E8%BD%AF%E4%BB%B6">开源</a>服务器,它允许用户共享、处理和编辑<a href="https://zh.wikipedia.org/wiki/%E5%9C%B0%E7%90%86%E4%BF%A1%E6%81%AF%E7%B3%BB%E7%BB%9F">地理空间数据</a>。为了互操作性而设计,它使用<a href="https://zh.wikipedia.org/wiki/%E5%BC%80%E6%BA%90%E6%A0%87%E5%87%86">开源标准</a>发布来自任何主要空间数据源的数据。GeoServer已经发展成为一种将现有信息与<a href="https://zh.wikipedia.org/wiki/Google%E5%9C%B0%E7%90%83">Google地球</a>、<a href="https://zh.wikipedia.org/wiki/NASA_World_Wind">NASA World Wind</a>等虚拟地球仪以及<a href="https://zh.wikipedia.org/wiki/OpenLayers">OpenLayers</a>、<a href="https://zh.wikipedia.org/wiki/Leaflet">Leaflet</a>、<a href="https://zh.wikipedia.org/wiki/Google%E5%9C%B0%E5%9B%BE">Google地图</a>和<a href="https://zh.wikipedia.org/wiki/%E5%BF%85%E5%BA%94%E5%9C%B0%E5%9B%BE">必应地图</a>等基于网络的地图连接起来的简单方法。GeoServer的功能是<a href="https://zh.wikipedia.org/wiki/%E5%BC%80%E6%94%BE%E5%9C%B0%E7%90%86%E7%A9%BA%E9%97%B4%E5%8D%8F%E4%BC%9A">开放地理空间协会</a><a href="https://zh.wikipedia.org/w/index.php?title=Web%E8%A6%81%E7%B4%A0%E6%9C%8D%E5%8A%A1&action=edit&redlink=1">Web要素服务</a>(WFS)标准的<a href="https://zh.wikipedia.org/wiki/%E5%8F%82%E8%80%83%E5%AE%9E%E7%8E%B0">参考实现</a>,同时也实现了<a href="https://zh.wikipedia.org/w/index.php?title=Web%E5%9C%B0%E5%9B%BE%E6%9C%8D%E5%8A%A1&action=edit&redlink=1">Web地图服务</a>(WMS)、<a href="https://zh.wikipedia.org/w/index.php?title=Web%E8%A6%86%E7%9B%96%E6%9C%8D%E5%8A%A1&action=edit&redlink=1">Web覆盖服务</a>(WCS)和<a href="https://zh.wikipedia.org/w/index.php?title=Web%E5%9C%B0%E7%90%86%E4%BF%A1%E6%81%AF%E5%A4%84%E7%90%86%E6%9C%8D%E5%8A%A1&action=edit&redlink=1">Web地理信息处理服务</a>(WPS)规范。</p><h3 id="架构"><a href="#架构" class="headerlink" title="架构"></a>架构</h3><p>GeoServer使用<a href="https://zh.wikipedia.org/wiki/Spring%E6%A1%86%E6%9E%B6">Spring框架</a>,为实现OGC服务的模块提供了请求分发架构。Web管理应用程序使用wicket,允许扩展程序提供其他配置屏幕。该应用程序提供了一个使用<a href="https://zh.wikipedia.org/wiki/Spring_Framework">spring-mvc-framework</a>实现的REST API。</p><p>GeoServer是一个Web应用程序,支持任何常见的<a href="https://zh.wikipedia.org/wiki/Java_Servlet">Servlet容器</a>(<a href="https://zh.wikipedia.org/wiki/Jetty">Jetty</a>作为嵌入式服务器可提供独立发行版)。<a href="https://zh.wikipedia.org/w/index.php?title=GeoWebCache&action=edit&redlink=1">GeoWebCache</a>是与<a href="https://zh.wikipedia.org/w/index.php?title=TileCache&action=edit&redlink=1">TileCache</a>相似的基于Java的缓存组件,与GeoServer捆绑在一起,但可以单独使用。[<a href="https://zh.wikipedia.org/wiki/GeoServer#cite_note-6">6]</a> 同样,GeoServer将GeoTools打包为Java库,但也可以单独使用。[<a href="https://zh.wikipedia.org/wiki/GeoServer#cite_note-7">7]</a></p><p>GeoServer是一个长期存在的应用程序,并且经历了几项体系结构更改。 GeoServer 1.0是围绕STRUTS框架构建的,在GeoServer 2.0迁移到Spring和Wicket。REST API的早期版本在迁移到<a href="https://zh.wikipedia.org/wiki/Spring_Framework">spring-mvc-framework</a>之前使用restlet。</p><h2 id="WebGL"><a href="#WebGL" class="headerlink" title="WebGL"></a>WebGL</h2><p>见另一个专门记录webgl的文档</p><h2 id="WebGIS常用的前端地图框架"><a href="#WebGIS常用的前端地图框架" class="headerlink" title="WebGIS常用的前端地图框架"></a>WebGIS常用的前端地图框架</h2><ol><li>Leaflet<br><a href="https://leafletjs.com/">Leaflet</a> 是最著名的前端地图可视化库,它开源、体积小、结构清晰、简单易用。</li><li>Mapbox GL JS<br><a href="http://www.mapbox.cn/mapbox-gl-js/overview/">Mapbox GL JS</a> 是目前最新潮的前端地图库,它的矢量压缩、动态样式和三维性能令人印象深刻。它本身是开源的,但一般依赖于Mapbox公司提供的底图服务。</li><li>ArcGIS API for JS<br><a href="https://developers.arcgis.com/javascript/latest/">ArcGIS API for JS</a> 是较为学院派的前端地图库,它是ArcGIS开发套件中的一部分,和桌面端和服务器端ArcGIS软件有较好的协作。它不开源且收费不低,在学术场景下较为常用。</li><li>Openlayers<br><a href="https://openlayers.org/">Openlayers</a> 也是常用的前端地图库,它开源,相比于Leaflet更加复杂和完备。</li><li>Cesium<br><a href="https://www.cesium.com/">Cesium</a> 是三维地理可视化的常用库,在大尺度的可视化(地形、建筑、地球)中十分常用。</li><li>百度地图 JS API /百度地图 API GL<br><a href="https://lbsyun.baidu.com/index.php?title=jspopular3.0">百度地图 JS API</a> 是传统的二维地图,百度地图 API GL 是三维地图,它们依赖百度地图提供的后台服务。除了地图服务外还有检索、导航、实时交通等关联服务。开发者有免费的限额。</li><li>高德地图 JS API<br><a href="https://lbs.amap.com/api/javascript-api/summary">高德地图 JS API</a> 与百度类似。</li><li>Google Maps JS API<br><a href="https://developers.google.com/maps/documentation/javascript/overview">谷歌地图 JS API</a> 在境外有更好的数据。</li><li>AntV L7<br><a href="https://antv.vision/zh/">AntV L7</a> 是空间数据可视化库,它可以使用高德地图等协作构建地图可视化。</li><li>Mapbox.js<br><a href="https://docs.mapbox.com/mapbox.js/api/v3.3.1/">Mapbox.js</a> 是 Leaflet 的一个扩展插件(与 Mapbox GL JS 不同)。</li></ol><h2 id="endtag"><a href="#endtag" class="headerlink" title="endtag"></a>endtag</h2>]]></content>
<summary type="html"><blockquote>
<p>持续更新</p>
</blockquote>
<h3 id=""><a href="#" class="headerlink" title=""></a></h3><h2 id="基础积累"><a href="#基础积累" class="heade</summary>
<category term="GIS" scheme="https://hhumar.com/categories/GIS/"/>
<category term="GIS" scheme="https://hhumar.com/tags/GIS/"/>
<category term="Web" scheme="https://hhumar.com/tags/Web/"/>
</entry>
<entry>
<title>Operating System</title>
<link href="https://hhumar.com/2023/03/05/os/"/>
<id>https://hhumar.com/2023/03/05/os/</id>
<published>2023-03-04T16:03:53.000Z</published>
<updated>2023-03-04T16:12:41.670Z</updated>
<content type="html"><![CDATA[<blockquote><p>持续更新</p><p>lab待更新</p></blockquote><h2 id="操作系统概论"><a href="#操作系统概论" class="headerlink" title="操作系统概论"></a>操作系统概论</h2><h3 id="历史"><a href="#历史" class="headerlink" title="历史"></a>历史</h3><h3 id="基础概念"><a href="#基础概念" class="headerlink" title="基础概念"></a>基础概念</h3><h4 id="abstraction"><a href="#abstraction" class="headerlink" title="abstraction"></a>abstraction</h4><p>• <strong>Threads</strong> abstract the CPU.<br>• <strong>Address spaces</strong> abstract memory.<br>• <strong>Files</strong> abstract the disk.<br>• <strong>Processes</strong> abstract of the computer.<br>• <strong>Input/Outputs</strong> abstract the devices</p><p>抽象是简化复杂事务,虚拟化是凭空创造不存在的东西</p><h4 id="文件描述符"><a href="#文件描述符" class="headerlink" title="文件描述符"></a>文件描述符</h4><p>文件描述符在形式上是一个非负整数。 实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。 当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。 在程序设计中,一些涉及底层的程序编写往往会围绕着文件描述符展开。</p><p>文件类型:普通文件(包含用户信息的文件,用户可以对这些文件进行各种操作-添加、修改、删除等),目录文件(包含文件名列表和这些文件相关的其他信息),特殊文件(设备文件,device files,printers,tapes)</p><h3 id="计算机启动"><a href="#计算机启动" class="headerlink" title="计算机启动"></a>计算机启动</h3><p>加电置固定指令地址,执行BIOS固件自检,加载mbr,loader在其中被成功加载,loader加载kernel</p><p>• —> Start BIOS (Basic Input Output System)<br>• —> Check the RAM and basic devices, e.g., keyboard<br>• —> Scan the PCIe and PCI buses to detect all the<br>other devices.<br>• —> Select boot device from CMOS<br>• —> The boot loader starts to find the OS<br>• —> OS is loaded, configures necessary information,<br>and gets the control of the computer</p><h3 id="保护"><a href="#保护" class="headerlink" title="保护"></a>保护</h3><h4 id="cpu保护"><a href="#cpu保护" class="headerlink" title="cpu保护"></a>cpu保护</h4><h4 id="memory保护"><a href="#memory保护" class="headerlink" title="memory保护"></a>memory保护</h4><h4 id="中断保护"><a href="#中断保护" class="headerlink" title="中断保护"></a>中断保护</h4><h3 id="系统调用"><a href="#系统调用" class="headerlink" title="系统调用"></a>系统调用</h3><h4 id="中断处理"><a href="#中断处理" class="headerlink" title="中断处理"></a>中断处理</h4><h5 id="实模式和保护模式"><a href="#实模式和保护模式" class="headerlink" title="实模式和保护模式"></a>实模式和保护模式</h5><p>8086内置4个段寄存器(代码段CS,数据段DS,堆栈段SS,附加段ES),每个段寄存器可以存放一个16位的段地址,在寻址时,处理器首先将段地址左移4位,然后再加上偏移地址,由此得到20位的物理地址(如 1234H:5678H所对应的物理地址为12340H+5678H=179B8H,其中, 1234H:5678H称作逻辑地址或虚地址)。当地址有溢出时(FFFFH:FFFFH 对应的物理地址是FFFF0H+FFFFH=10FFEFH,大于FFFFFH),会发生<strong>回卷</strong>(10FFEFH = FFF0H)。</p><p>如此寻址会产生很多问题。一个段大小最大为2^16=64KiB,并且,所有的段都是可读写的。这意味着不同的段存在着重叠部分(即不同的逻辑地址可以映射到相同的物理地址),无法保证程序的安全性(程序段可被修改),也不具有权限分级(大家都有读写权限,另,那时真的有权限这个概念么)。</p><p>在实模式中,段寄存器保存的是段首地址(左移4位以后),而在保护模式,其中保存的内容称作选择器(selector),其本质是索引(13位,即在表中的偏移量)加TI位(1位,表示是使用GDT还是LDT)和优先级信息(2位,0~3值越小优先级越高)。</p><p> 在寻址时,首先拿出选择器(段寄存器)的高13位作为偏移量(索引),结合TI位找到描述符。取出其中24位长的段首地址信息,再加上偏移量(这个偏移量是段地址:偏移量 中的偏移量,前面提到的描述符表的偏移量是段地址的高13位),得到实际物理地址。</p><p> 简单来说,286保护模式下的寻址步骤是:拿到段寄存器高14位(13+1),查描述符表,得到24位段地址,加上偏移量,得到物理地址。当然,其中还有保护机制,这里没有说明。</p><p>段选择子存在段寄存器中,16位=13位index+1位TI+2位privilege,TI -table indicator位表示该段选择子为全局段还是局部段,RPL 表示该段选择子的特权等级,13位Index表示描述符表中的编号(下标),拿index去段描述符表找段描述符,根据段描述符结构找段基址加偏移量即可。</p><h3 id="顶级会议期刊"><a href="#顶级会议期刊" class="headerlink" title="顶级会议期刊"></a>顶级会议期刊</h3><p>会议</p><p>(SOSP) ACM Symposium on Operating Systems Principles<br>(OSDI) USENIX symposium on Operating Systems Design and Implementation<br>(ASPLOS) ACM International Conference on Architectural Support for Programming<br>Languages and Operating Systems<br>(ATC) USENIX Annual Technical Conference<br>(FAST) USENIX Conference on File and Storage Technologies<br>(Eurosys) Proceedings of the European Conference on Computer Systems<br>(NSDI) USENIX Symposium on Networked Systems Design and Implementation<br>(ISCA) International Symposium on Computer Architecture<br>(MICRO) International Symposium on Microarchitecture</p><p>期刊</p><p>(TOCS) ACM Transactions on Computer Systems<br>(OSR) ACM SIGOPS Operating Systems Review<br>(TOC) IEEE Transactions on Computer<br>(TPDS) IEEE Transactions on Parallel and Distributed Systems</p><h2 id="进程"><a href="#进程" class="headerlink" title="进程"></a>进程</h2><p>进程状态</p><ul><li><code>R</code>(TASK_RUNNING,可执行状态),这个进程是可运行的——要么它正在运行,要么在运行队列中等待运行;</li><li><code>S</code>(TASK_INTERRUPTIBLE,中断状态),这个状态的进程因为等待某事件的发生(比如等待socket连接、等待信号量等)而被挂起,然后当这些事件发生或完成后,对应的等待队列中的一个或多个进程将被唤醒。</li><li><code>D</code>(TASK_UNINTERRUPTIBLE,不可中断状态),在进程接收到信号时,不会被唤醒变成可运行的。除了这一点,该状态和TASK_INTERRUPTIBLE其他部分完全一样,这个状态通常用于进程必须不间断等待或者事件发生的频率很快,并且无法用kill命令关闭处于TASK_UNINTERRUPTIBLE状态的进程。</li><li><code>T</code>(TASK_STOPPED或TASK_TRACED,暂停状态或跟踪状态),该状态表示该进程已经停止执行,并且不具有再次执行的条件。向进程发送一个SIGSTOP信号,它就会因响应该信号而进入TASK_STOPPED状态(除非该进程本身处于TASK_UNINTERRUPTIBLE状态而不响应信号)。而当进程正在被跟踪时,它处于TASK_TRACED状态。</li><li><code>Z</code>(TASK_DEAD或EXIT_ZOMBIE,退出状态),进程在退出的过程中,处于TASK_DEAD状态,如果它的父进程没有收到SIGCHLD信号,故未调用wait(如wait4、waitid)处理函数等待子进程结束,又没有显式忽略该信号,它就一直保持EXIT_ZOMBIE状态。只要父进程不退出,这个EXIT_ZOMBIE状态的子进程就一直存在,这也就是所谓的”僵尸”进程。</li><li><code>X</code>(TASK_DEAD - EXIT_DEAD,退出状态),进程即将被销毁。EXIT_DEAD状态是非常短暂的,几乎不可能通过ps命令捕捉到。</li></ul><p>对应状态码</p><table><thead><tr><th>状态</th><th>定义</th></tr></thead><tbody><tr><td>R</td><td>Running.运行中</td></tr><tr><td>S</td><td>Interruptible Sleep.等待调用</td></tr><tr><td>D</td><td>Uninterruptible Sleep.等待磁盘IO</td></tr><tr><td>T</td><td>Stoped.暂停或者跟踪状态</td></tr><tr><td>X</td><td>Dead.即将被撤销</td></tr><tr><td>Z</td><td>Zombie.进程已经结束,仅映像名留存,所谓的僵尸进程</td></tr><tr><td>W</td><td>Paging.内存交换</td></tr><tr><td>N</td><td>优先级低的进程</td></tr><tr><td><</td><td>优先级高的进程</td></tr><tr><td>s</td><td>进程的领导者</td></tr><tr><td>L</td><td>锁定状态</td></tr><tr><td>l</td><td>多线程状态</td></tr><tr><td>+</td><td>前台进程</td></tr></tbody></table><p><img src="/2023/03/05/os/image-20230220203818283.png" alt="image-20230220203818283"></p><p><img src="/2023/03/05/os/image-20230220203847820.png" alt="image-20230220203847820"></p><h4 id="fork和exec"><a href="#fork和exec" class="headerlink" title="fork和exec"></a>fork和exec</h4><p><strong>父进程中调用fork之前打开的所有描述符在fork返回之后由子进程分享</strong>。我们将看到网络服务器利用了这个特性:父进程调用accept之后调用fork。所接受的已连接套接字随后就在进程与子进程之间共享。通常情况下,子进程接着读写这个已连接套接字,父进程则关闭这个已连接套接字。</p><p>fork的两个典型用法:</p><p>(1)一个进程创建一个自身的副本,这样每个副本都可以在另一个副本执行其他任务的同时处理各自的某个操作。这是网络服务器的典型用法。</p><p>(2)一个进程想要执行另一个程序。既然创建新进程的唯一方法是调用fork,该进程于是首先调用fork创建一个自身的副本,然后其中一个副本(通常是子进程)调用exec把自身替换成新的程序。这是诸如shell之类程序的典型用法。</p><p> fork() 函数用于创建一个新的子进程,该子进程几乎复制了父进程的全部内容,但是,这个新创建的子进程如何执行呢?exec 函数族就提供了一个在进程中启动另一个程序执行的方法。它可以根据指定的文件名或目录名找到可执行文件,并用它来取代原调用进程的数据段、代码段和堆栈段,在执行完之后,原调用进程的内容除了进程号外,其他全部被新的进程替换了。另外,这里的可执行文件既可以是二进制文件,也可以是Linux下任何可执行的脚本文件。</p><p>pid=fork()后,父进程中pid>0,子进程pid=0</p><p> 在 Linux 中使用exec函数族主要有两种情况:</p><p> ● 当进程认为自己不能再为系统和用户做出任何贡献时,就可以调用 exec 函数族中的任意一个函数让自己重生。</p><p> ● 如果一个进程想执行另一个程序,那么它就可以调用 fork() 函数新建一个进程,然后调用 exec 函数族中的任意一个函数,这样看起来就像通过执行应用程序而产生了一个新进程(这种情况非常普遍)。</p><p>exec函数族的6个函数的区别在于:(a)待执行的程序文件是由文件名(filename)还是由路径名(pathname)指定;(b)新程序的参数是一一列出还是由一个指针数组来引用;(c)把调用进程的环境传递给新程序还是给新程序指定新的环境。</p><p> 事实上,这6个函数中真正的系统调用只有execve(),其他5个都是库函数,它们最终都会调用execve()这个系统调用。在使用exec函数族时,一定要加上错误判断语句。exec 很容易执行失败,其中最常见的原因有:</p><p> ① 找不到文件或路径,此时 errno 被设置为 ENOENT。</p><p> ② 数组argv 和envp 忘记用NULL结束,此时,errno被设置为 EFAUL。</p><p> ③ 没有对应可执行文件的运行权限,此时 errno 被设置为EACCES。</p><p>这些函数只有在出错时才返回到调用者,否则,控制将被传递给新程序的起始点,通常就是main函数。</p><p><img src="/2023/03/05/os/img_482b1b02600a23a91f60ec4b6a5b3d93.png" alt="img"></p><p><img src="/2023/03/05/os/img_2c2d6737253b339a8e36de68ecb8f5f7.png" alt="img"></p><p>exec可以更改和继承的包括以下单不限于以下的上下文内容:</p><p>• File descriptors<br>• User/group ID<br>• Process group and session IDs<br>• Current directory<br>• Resource limits<br>• Scheduling priority and affinity</p><h4 id="IDLE进程"><a href="#IDLE进程" class="headerlink" title="IDLE进程"></a>IDLE进程</h4><p>没有处于<code>RUNNABLE</code>状态的进程时切换至内核IDLE进程,该进程调⽤ <code>waitForInterrupt()</code> 执⾏ <code>hlt</code> 指令, <code>hlt</code> 会使得CPU进⼊暂停状态,直到外部硬件中断产⽣</p><p>执⾏流在bootloader中加载并跳转到内核, 然后执⾏⼀系列 的初始化⼯作,等到初始化结束后将会打开中断,此时执⾏流摇身⼀变,成为了实验中 的IDLE进程,等待中断的到来</p><pre class="language-c" data-language="c"><code class="language-c"><span class="token keyword">static</span> <span class="token keyword">inline</span> <span class="token keyword">void</span> <span class="token function">waitForInterrupt</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">asm</span> <span class="token keyword">volatile</span><span class="token punctuation">(</span><span class="token string">"hlt"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token keyword">while</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">waitForInterrupt</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><h4 id="Modeling-Multiprogramming"><a href="#Modeling-Multiprogramming" class="headerlink" title="Modeling Multiprogramming"></a>Modeling Multiprogramming</h4><p>多道程序设计模型</p><h4 id="进程调度"><a href="#进程调度" class="headerlink" title="进程调度"></a>进程调度</h4><p>context switch & CPU switch</p><p><img src="/2023/03/05/os/image-20230220215650198.png" alt="image-20230220215650198"></p><h4 id="进程间通信"><a href="#进程间通信" class="headerlink" title="进程间通信"></a>进程间通信</h4><p>interprocess communication</p><p>典型进程间通信模式</p><ul><li>生产者-消费者模式</li><li>生产者只写,消费者只读</li><li>缓冲区无限大时:生产者不停写,消费者只在缓冲区存在内容时读</li><li>缓冲区有限大:生产者在缓冲区未满时写,消费者只在缓冲区存在内容时读</li></ul><p>两种通信方法:</p><p><img src="/2023/03/05/os/image-20230222155244306.png" alt="image-20230222155244306"></p><ul><li><p>共享内存</p><p>通信由用户程序控制而非操作系统,难点在于内存一致性(同步)</p><p>可用循环数组和两个逻辑指针来表示</p><pre class="language-c" data-language="c"><code class="language-c">item next_produced<span class="token punctuation">;</span> <span class="token keyword">while</span> <span class="token punctuation">(</span>true<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">/* produce an item in next produced */</span> <span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">(</span>in <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">%</span> BUFFER_SIZE<span class="token punctuation">)</span> <span class="token operator">==</span> out<span class="token punctuation">)</span> <span class="token comment">//buffer full</span> <span class="token punctuation">;</span> <span class="token comment">/* do nothing */</span> buffer<span class="token punctuation">[</span>in<span class="token punctuation">]</span> <span class="token operator">=</span> next_produced<span class="token punctuation">;</span> in <span class="token operator">=</span> <span class="token punctuation">(</span>in <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">%</span> BUFFER_SIZE<span class="token punctuation">;</span> <span class="token punctuation">}</span>item next_consumed<span class="token punctuation">;</span> <span class="token keyword">while</span> <span class="token punctuation">(</span>true<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">while</span> <span class="token punctuation">(</span>in <span class="token operator">==</span> out<span class="token punctuation">)</span> <span class="token comment">//buffer empty</span> <span class="token punctuation">;</span> <span class="token comment">/* do nothing */</span> next_consumed <span class="token operator">=</span> buffer<span class="token punctuation">[</span>out<span class="token punctuation">]</span><span class="token punctuation">;</span> out <span class="token operator">=</span> <span class="token punctuation">(</span>out <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">%</span> BUFFER_SIZE<span class="token punctuation">;</span> <span class="token comment">/* consume the item in next consumed */</span> <span class="token punctuation">}</span></code></pre><p>或者用个计数器counter(不能循环)</p><ul><li><p>race condition</p><p>竞争危害/条件,在计算机系统中实现时,可能会因为生产者与消费者采用不同寄存器短时间内调取同一counter值增加和减少而产生counter的错误修改,但第一种方法不会产生这种危害,两个process的工作是解耦的,没有counter联系</p></li></ul></li><li><p>消息传递</p><p>建立通信链接(</p><p>•Hardware bus<br>•Network<br>•Shared memory),通过send/receive传递信息</p><p>直接通信:•send (P , message) – send a message to process P<br>•receive(Q, message) – receive a message from process Q<br>链接自动建立,一个链接对应一对通信进程</p><p>间接通信:mailboxes (also referred to as ports),共享特定端口通信,端口可关联多个进程,每对进程可共享多个通信链路</p><p>链路均可全双工,也可半双工</p><p>阻塞(同步,发送后等待收到才再次发送),非阻塞(异步,send and continue),可搭配组合,接收发送全阻塞时可称为rendezvous(约定)</p><p>异常情况</p></li><li><p>比较:内存共享更快,消息传递需要重复sys调用,但消息传递在分布式系统中更容易实现,不用考虑内存冲突、一致性问题,适用于交换少量数据,多核系统中也更实用</p></li><li><p>例子:POSIX-内存共享,sockets,pipes,named pipes ,signals</p></li></ul><h2 id="线程"><a href="#线程" class="headerlink" title="线程"></a>线程</h2><h4 id="概念"><a href="#概念" class="headerlink" title="概念"></a>概念</h4><p>fork() 等同于 clone(2),2代指SIGCHILD</p><p><code>pthread_atfork(3)</code></p><p>Native POSIX Thread Library (NPTL), a Linux implementation of POSIX thread library</p><p>线程是代表一个独立、可调度任务的一个可执行指令序列的抽象</p><h4 id="motivation-and-usage"><a href="#motivation-and-usage" class="headerlink" title="motivation and usage"></a>motivation and usage</h4><p>解决MTAO(multiple things at once)</p><p>操作系统提供的<strong>并发单位</strong>,抽象来说就是并发(concurrency)机制的体现</p><p>并发不一定并行(parallelism),但是并行一定并发</p><p>semi-process,轻型进程,不同线程共享地址空间,共享所有数据</p><h4 id="model"><a href="#model" class="headerlink" title="model"></a>model</h4><p>一个进程中所有线程共享的item: address space,global variables,open files ,child processes,pending alarms(未决警报),signals and signal handlers,accounting info</p><p>线程单独享有item: program counter(pc),registers,stack,state</p><p><img src="/2023/03/05/os/image-20230223140243880.png" alt="image-20230223140243880"></p><pre class="language-c" data-language="c"><code class="language-c"><span class="token comment">/*basic options*/</span><span class="token function">thread_create</span><span class="token punctuation">(</span>thread<span class="token punctuation">,</span> func<span class="token punctuation">,</span> arg<span class="token punctuation">)</span> <span class="token comment">//creates a new thread in thread, which will execute function func with arguments arg.</span> <span class="token function">thread_yield</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">//calling thread gives up the processor. </span> <span class="token function">thread_join</span><span class="token punctuation">(</span>thread<span class="token punctuation">)</span> <span class="token comment">//wait for thread to finish, get the value thread returned. </span> <span class="token function">thread_exit</span><span class="token punctuation">(</span>ret<span class="token punctuation">)</span> <span class="token comment">//quit the current thread and clean up, make ret available to any successful join (wait for this thread).</span></code></pre><p>TCB(thread control block)</p><p>五个状态:</p><ul><li><p>init</p><p>TCB: Ready List<br>Registers: In TCB</p></li><li><p>ready</p><p>TCB: Ready List<br>Registers: In TCB</p></li><li><p>TCB: Running List<br>Registers: Processor</p></li><li><p>running</p><p>TCB: Running List<br>Registers: Processor</p></li><li><p>waiting</p><p>TCB: Synchronization waiting list<br>Registers: TCB</p></li><li><p>finished</p><p>TCB: Finished List (to pass exit value), then deleted<br>Registers: TCB</p></li></ul><p><img src="/2023/03/05/os/image-20230223162027236.png" alt="image-20230223162027236"></p><h4 id="POSIX"><a href="#POSIX" class="headerlink" title="POSIX"></a>POSIX</h4><p><img src="/2023/03/05/os/image-20230223182454862.png" alt="image-20230223182454862"></p><h4 id="Implementation"><a href="#Implementation" class="headerlink" title="Implementation"></a>Implementation</h4><p>user-level:<img src="/2023/03/05/os/image-20230224004956083.png" alt="image-20230224004956083">thread call,context switch均在user-level,快、可用户自定义调度线程、kernel复杂度低,kernel 单线程;</p><p>缺点在于一个线程阻塞,整个进程阻塞,kernel只能做<strong>次</strong>优化决策( OS modifications to overcome this. ),没有时间中断,当一个进程运行只能yield/exit,其它线程才能切入执行</p><p>kernel-level:<img src="/2023/03/05/os/image-20230224005424349.png" alt="image-20230224005424349"></p><p>内核能掌控线程信息,实现更好调度等优化,当线程频繁阻塞时很重要</p><p>缺点在于 High overhead ,OS更复杂</p><p>hybrid:<img src="/2023/03/05/os/image-20230224005624816.png" alt="image-20230224005624816"></p><p>1对1,多对一</p><p>context switch in kernel threads:</p><p>thread running->switch to kernel->save thread state to TCB->choose new thread(policy decision left to scheduler)->load thread state from TCB->thread running</p><p>引起上下文切换的可能:内部系统调用/异常,外部中断<img src="/2023/03/05/os/image-20230224010419087.png" alt="image-20230224010419087"></p><p>context switch in user threads:</p><p><strong>没有操作系统支持</strong></p><p>•TCBs,就绪列表,完成列表,等待列表-在用户空间</p><p>•线程库调用只是过程调用</p><p>有OS支持:</p><p>•使用上行调用(upcalls)虚拟化中断和异常</p><p>•使用系统调用注册一个信号处理程序(signal handler)</p><p>•中断时,内核暂停进程执行,保存进程P状态并运行内核处理器;完成后:</p><p>•将P的保存状态复制到P的信号堆栈中</p><p>•在信号处理程序中恢复P的执行(load state with PC = &signal_handler;SP -> state on stack)</p><p>•信号处理器将状态从堆栈移动到TCB</p><p>•在就绪列表中恢复其他一些TCB的状态</p><h4 id="Pop-Up"><a href="#Pop-Up" class="headerlink" title="Pop-Up"></a>Pop-Up</h4><p>使用这种弹出式线程的优点是每个新请求都将被快速处理,几乎是即时的(这取决于服务器的当前负载)。<img src="/2023/03/05/os/image-20230224011409711.png" alt="image-20230224011409711"></p><p>To see thread information<br><code>ps -m</code></p><p><code>ps m –o pid,tid,command</code> </p><h2 id="调度"><a href="#调度" class="headerlink" title="调度"></a>调度</h2><h3 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h3><p>Simplified view of scheduling: </p><ul><li>Save process state (to PCB) </li><li><strong>Pick a process to run next</strong> </li><li>Dispatch process</li></ul><h4 id="调度时机"><a href="#调度时机" class="headerlink" title="调度时机"></a>调度时机</h4><p>1.新进程产生</p><p>2.进程死亡并返回exit状态</p><p>3.进程阻塞</p><p>4.I/O 中断</p><p>5.时钟中断,例-抢占式调度程序使用它来替换正在运行的进程</p><h4 id="调度算法类别"><a href="#调度算法类别" class="headerlink" title="调度算法类别"></a>调度算法类别</h4><p>抢占式/非抢占式</p><ol><li>Batch. </li><li>Interactive. </li><li>Real time</li></ol><h4 id="调度算法目标"><a href="#调度算法目标" class="headerlink" title="调度算法目标"></a>调度算法目标</h4><p>总的来说:公平性,cpu高利用率<img src="/2023/03/05/os/image-20230224014748060.png" alt="image-20230224014748060"></p><p>针对不同的系统又有不同的要求</p><h4 id="不同系统下的调度"><a href="#不同系统下的调度" class="headerlink" title="不同系统下的调度"></a>不同系统下的调度</h4><h5 id="批处理系统调度"><a href="#批处理系统调度" class="headerlink" title="批处理系统调度"></a>批处理系统调度</h5><p>• First-Come First-Served<br>• Shortest Job First<br>• Shortest Remaining Time Next</p><h5 id="交互式系统调度"><a href="#交互式系统调度" class="headerlink" title="交互式系统调度"></a>交互式系统调度</h5><p>• Round-Robin Scheduling<br>• Priority Scheduling<br>• Multilevel Queues<br>• Multilevel Feedback Queue<br>• Guaranteed Scheduling<br>• Lottery Scheduling</p><h5 id="实时系统调度"><a href="#实时系统调度" class="headerlink" title="实时系统调度"></a>实时系统调度</h5><p> Time plays an essential role </p><ul><li>having the right answer but having it too late is<br>often just as bad as not having it at all.</li></ul><h4 id="策略和机制"><a href="#策略和机制" class="headerlink" title="策略和机制"></a>策略和机制</h4><h3 id="线程调度"><a href="#线程调度" class="headerlink" title="线程调度"></a>线程调度</h3><h4 id="例子"><a href="#例子" class="headerlink" title="例子"></a>例子</h4><h4 id="评估"><a href="#评估" class="headerlink" title="评估"></a>评估</h4><h2 id="同步"><a href="#同步" class="headerlink" title="同步"></a>同步</h2><h3 id="简介-1"><a href="#简介-1" class="headerlink" title="简介"></a>简介</h3><p>进程/线程同步(并发控制)和数据同步(数据一致性,完整性)</p><p>为什么需要同步?</p><ul><li>线程调度不确定,每次运行程序都可能产生不一样的情况,比如出现不同的并发情况,调度器做出不同决策,cpu以不同频率运行,缓存命中率不同</li><li>编译器/硬件优化,指令重排,影响多线程程序(对单线程基本安全)</li></ul><p>多字操作不是原语(atomic)</p><h3 id="竞争条件"><a href="#竞争条件" class="headerlink" title="*竞争条件"></a>*竞争条件</h3><p>生产者和消费者并发,不同寄存器调用counter旧值</p><h3 id="临界区(Critical-Sections-)"><a href="#临界区(Critical-Sections-)" class="headerlink" title="临界区(Critical Sections )"></a>临界区(Critical Sections )</h3><p>每个进程中访问共享数据资源的一段代码,称为临界区</p><p>当有进程正在执行自己的临界区代码(访问共享数据)时,其它进程不能执行临界区代码</p><p>避免竞态条件的要求:</p><p>1.没有两个进程可以同时在它们的关键区域内。(safety)</p><p>2.对于速度或cpu的数量,不做任何假设(即考虑速度和CPU数量为任何的情况)。</p><p>3.任何运行在其临界区之外的进程都不能阻塞其他进程。(可发展的-progress)</p><p>4.任何进程都不应该永远等待进入临界区域。(活性-liveness)</p><p><img src="/2023/03/05/os/image-20230224204802503.png" alt="image-20230224204802503"></p><h3 id="忙等待互斥(Mutual-Exclusion-with-Busy-Waiting-)"><a href="#忙等待互斥(Mutual-Exclusion-with-Busy-Waiting-)" class="headerlink" title="*忙等待互斥(Mutual Exclusion with Busy Waiting )"></a>*忙等待互斥(Mutual Exclusion with Busy Waiting )</h3><h4 id="实现忙等待互斥的方法"><a href="#实现忙等待互斥的方法" class="headerlink" title="实现忙等待互斥的方法"></a>实现忙等待互斥的方法</h4><ul><li><p>在一个进程进入临界区时禁用中断(弊大于利,长时间禁用中断会产生很多麻烦)</p></li><li><p>设置锁-变量(Lock Variables ),进程进入临界区时把锁变量置为1,把集中在共享变量的问题转移到锁变量上而已</p></li><li><p>Strict Alternation,严格交替<img src="/2023/03/05/os/image-20230224210033056.png" alt="image-20230224210033056">但是也存在问题:当一个进程执行特别快,在另一个进程仍在执行非临界区代码时,这个进程已经接过接力棒执行完自身临界区代码和非临界区代码,回到下一轮临界区入口前,它此时需要阻塞自己等待另一个进程执行完当前轮次和下一轮次(仅有两个进程时的讨论),这就违背了避免竞态条件第三原则——任何执行非临界区进程/线程不得阻塞其它进程/线程。</p></li><li><p>Peterson’s Solution:皮特森方案,连接两个思想:严格交替和锁变量。<img src="/2023/03/05/os/image-20230224212834124.png" alt="image-20230224212834124"></p><p>核心在于turn==process&&interested[other]==true时等待,前者保证多个进程并发时,最先改写turn值的进程会进入临界区,另一个会阻塞,后者保证进入非临界区时,interest会置为false,不会阻塞其它进程</p><p><strong>扩展到N个线程互斥访问一个资源的filter算法[维基百科]</strong></p><pre class="language-none"><code class="language-none">// initializationlevel[N] = { -1 }; // current level of processes 0...N-1waiting[N-1] = { -1 }; // the waiting process of each level 0...N-2// code for process #ifor(l = 0; l < N-1; ++l) { // go through each level level[i] = l; waiting[l] = i; while(waiting[l] == i && (there exists k ≠ i, such that level[k] ≥ l)) { // busy wait }}// critical sectionlevel[i] = -1; // exit section</code></pre><p>数组level表示每个线程的等待级别,最小为0,最高为N-1,-1表示未设置。数组waiting模拟了一个阻塞(忙等待)的线程队列,从位置0为入队列,位置越大则入队列的时间越长。每个线程为了进入临界区,需要在队列的每个位置都经过一次,如果没有更高优先级的线程(考察数组level),cd 或者被后入队列的线程推着走(上述程序waiting[l] ≠ i),则当前线程在队列中向前走过一个位置。可见该算法满足互斥性。</p><p>由filter算法去反思Peterson算法,可见其中的flags(interested)数组表示两个进程的等待级别,而turn变量则是阻塞(忙等待)的线程队列,这个队列只需要容纳一个元素。</p></li></ul><h4 id="TSL指令:忙互斥的硬件实现"><a href="#TSL指令:忙互斥的硬件实现" class="headerlink" title="TSL指令:忙互斥的硬件实现"></a>TSL指令:忙互斥的硬件实现</h4><p>test and set lock (TSL),硬件层面对“test” and “set” the flag的原子性实现</p><p>这个指令读取一个内存地址的内容,存到寄存器中,并在原地址存一个非零值,保证指令过程中其它进程不能访问该内存地址</p><pre class="language-asm" data-language="asm"><code class="language-asm">enter_region: tsl register, flag ; copy flag to register and set flag to 1 cmp register, #0 ;was flag zero? jnz enter_region ;if flag was non zero, lock was set , so loop ret ;return (and enter critical region)leave_region: mov flag, #0 ; store zero in flag ret ;return</code></pre><p>x86中采用XCHG作为代替(原子地交换两个变量的值),作用基本一致<img src="/2023/03/05/os/image-20230224221753125.png" alt="image-20230224221753125"></p><p>以上方法本质都是忙等待:进入临界区前检查,不符合条件循环忙等待。</p><p>会出现priority inversion problem(优先级反转)的问题。</p><p>解决方法:优先级继承协议,允许一个任务继承它正在阻塞的最高优先级任务的优先级</p><p>eg.</p><table><thead><tr><th align="center">Job Name</th><th align="center">Priority</th></tr></thead><tbody><tr><td align="center">H</td><td align="center">High</td></tr><tr><td align="center">M</td><td align="center">Medium</td></tr><tr><td align="center">L</td><td align="center">Low</td></tr></tbody></table><p>假定L获取到共享资源后,H申请该资源不得而被阻塞。优先级继承协议把L的优先级升级到H的级别。M将不能<a href="https://zh.wikipedia.org/wiki/%E6%8A%A2%E5%8D%A0%E5%BC%8F%E5%A4%9A%E4%BB%BB%E5%8A%A1%E5%A4%84%E7%90%86">抢先</a>L因而M被阻塞。当L释放资源后,恢复到低优先级并唤醒H。H有高优先级因而抢先了L的执行权。随后M、L依次恢复执行。</p><h3 id="睡眠和唤醒"><a href="#睡眠和唤醒" class="headerlink" title="睡眠和唤醒"></a>睡眠和唤醒</h3><p>sleep, wakeup 不忙等待,不占用cpu</p><p>均含有参数——匹配sleep和wakeup的内存地址(指定进程)</p><p>生产者和消费者例子:</p><p>生产者向buffer增加item时(消费者减少item)检查buffer中的item count是不是等于n(0),如果是则sleep,否则正常操作;当从0到1(从n到n-1)时wakeup消费者(生产者)</p><pre class="language-c" data-language="c"><code class="language-c"><span class="token keyword">int</span> BUFFER_SIZE <span class="token operator">=</span> <span class="token number">100</span><span class="token punctuation">;</span> <span class="token keyword">int</span> count <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span><span class="token keyword">void</span> <span class="token function">producer</span><span class="token punctuation">(</span><span class="token keyword">void</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">int</span> item<span class="token punctuation">;</span> <span class="token keyword">while</span><span class="token punctuation">(</span>TRUE<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">produce_item</span><span class="token punctuation">(</span><span class="token operator">&</span>item<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// generate next item </span> <span class="token keyword">if</span><span class="token punctuation">(</span>count <span class="token operator">==</span> BUFFER_SIZE<span class="token punctuation">)</span> <span class="token function">sleep</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// if buffer full, go to sleep </span> <span class="token function">enter_item</span><span class="token punctuation">(</span>item<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// put item in buffer </span> count<span class="token operator">++</span><span class="token punctuation">;</span> <span class="token comment">// increment count </span> <span class="token keyword">if</span><span class="token punctuation">(</span>count <span class="token operator">==</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token function">wakeup</span><span class="token punctuation">(</span>consumer<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// was buffer empty? </span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token keyword">void</span> <span class="token function">consumer</span><span class="token punctuation">(</span><span class="token keyword">void</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">int</span> item<span class="token punctuation">;</span> <span class="token keyword">while</span><span class="token punctuation">(</span>TRUE<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span><span class="token punctuation">(</span>count <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token function">sleep</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// if buffer is empty, sleep </span> <span class="token function">remove_item</span><span class="token punctuation">(</span><span class="token operator">&</span>item<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// remove item from buffer </span> count<span class="token operator">--</span><span class="token punctuation">;</span> <span class="token comment">// decrement count </span> <span class="token keyword">if</span><span class="token punctuation">(</span>count <span class="token operator">==</span> BUFFER_SIZE <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token function">wakeup</span><span class="token punctuation">(</span>producer<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// was buffer full? </span> <span class="token function">consume_item</span><span class="token punctuation">(</span><span class="token operator">&</span>item<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// print item </span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre><p>对于唯一的count,会产生类似的竞态条件问题</p><p>The Producer-Consumer Problem with spin lock protect,互斥锁的保护</p><pre class="language-asm" data-language="asm"><code class="language-asm">mutex_lock: TSL REGISTER,MUTEX ;| copy mutex to register and set mutex to 1 CMP REGISTER,#0 ;| was mutex zero? JNE mutex_ lock ;| mutex is busy; loop RET ;| return to caller; critical section entered mutex_unlock: MOVE MUTEX,#0 ;| store a 0 in mutex RET ;| return to caller </code></pre><pre class="language-c" data-language="c"><code class="language-c"><span class="token keyword">int</span> BUFFER_SIZE <span class="token operator">=</span> <span class="token number">100</span><span class="token punctuation">;</span> <span class="token keyword">int</span> count <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">int</span> mutex <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">void</span> <span class="token function">producer</span><span class="token punctuation">(</span><span class="token keyword">void</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">int</span> item<span class="token punctuation">;</span> <span class="token keyword">while</span><span class="token punctuation">(</span>TRUE<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">produce_item</span><span class="token punctuation">(</span><span class="token operator">&</span>item<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// generate next item </span> <span class="token function">mutex_lock</span><span class="token punctuation">(</span>mutex<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span><span class="token punctuation">(</span>count <span class="token operator">==</span> BUFFER_SIZE<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">mutex_unlock</span><span class="token punctuation">(</span>mutex<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">sleep</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">mutex_lock</span><span class="token punctuation">(</span>mutex<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// if buffer full, go to sleep </span> <span class="token function">enter_item</span><span class="token punctuation">(</span>item<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// put item in buffer </span> count<span class="token operator">++</span><span class="token punctuation">;</span> <span class="token comment">// increment count </span> <span class="token keyword">if</span><span class="token punctuation">(</span>count <span class="token operator">==</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token function">wakeup</span><span class="token punctuation">(</span>consumer<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// was buffer empty? </span> <span class="token function">mutex_unlock</span><span class="token punctuation">(</span>mutex<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token comment">//...consumer略</span></code></pre><h3 id="条件变量"><a href="#条件变量" class="headerlink" title="*条件变量"></a>*条件变量</h3><p>一个自动unlock和sleep的原语</p><p>一个同步对象,使线程有效地等待由锁保护的共享状态的更改</p><p>含有三种方法:</p><p>•Wait(ConditionVariable *cv, Lock * lock):自动释放锁(解锁),挂起调用线程的执行(sleep) -唤醒时重新获取锁</p><p>•Signal(ConditionVariable *cv):唤醒一个等待这个条件变量的等待者。如果等待列表中没有线程,则信号不起作用。</p><p>•Broadcast(ConditionVariable *cv):如果有,唤醒所有的等待者</p><pre class="language-c" data-language="c"><code class="language-c"><span class="token keyword">int</span> BUFFER_SIZE <span class="token operator">=</span> <span class="token number">100</span><span class="token punctuation">;</span> <span class="token keyword">int</span> count <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> condition empty<span class="token punctuation">;</span> Condition full<span class="token punctuation">;</span> <span class="token keyword">int</span> mutex <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">void</span> <span class="token function">producer</span><span class="token punctuation">(</span><span class="token keyword">void</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">int</span> item<span class="token punctuation">;</span> <span class="token keyword">while</span><span class="token punctuation">(</span>TRUE<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">produce_item</span><span class="token punctuation">(</span><span class="token operator">&</span>item<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// generate next item </span> <span class="token function">mutex_lock</span><span class="token punctuation">(</span>mutex<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span><span class="token punctuation">(</span>count <span class="token operator">==</span> BUFFER_SIZE<span class="token punctuation">)</span> <span class="token function">wait</span><span class="token punctuation">(</span>full<span class="token punctuation">,</span> mutex<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// if buffer full, unlock, and go to sleep, when wakened -> lock </span> <span class="token function">enter_item</span><span class="token punctuation">(</span>item<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// put item in buffer </span> count<span class="token operator">++</span><span class="token punctuation">;</span> <span class="token comment">// increment count </span> <span class="token keyword">if</span><span class="token punctuation">(</span>count <span class="token operator">==</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token function">signal</span><span class="token punctuation">(</span>empty<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// was buffer empty? </span> <span class="token function">mutex_unlock</span><span class="token punctuation">(</span>mutex<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token comment">//...consumer略</span></code></pre><p>条件变量没有memory,如果一个信号被发送到一个没有线程等待的条件变量,这个信号就会丢失。</p><p>Linux中的实现:an FUTEX (Fast User-space muTEX) approach</p><pre class="language-c" data-language="c"><code class="language-c"><span class="token comment">//当且仅当地址addr的值等于val时,该操作使调用线程进入睡眠状态</span><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string"><stdatomic.h></span></span><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string"><time.h></span></span><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string"><linux/futex.h></span></span><span class="token keyword">int</span> <span class="token function">futex_wait</span><span class="token punctuation">(</span>atomic_int <span class="token operator">*</span>addr<span class="token punctuation">,</span> <span class="token keyword">int</span> val<span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">sys_futex</span><span class="token punctuation">(</span>addr<span class="token punctuation">,</span> val<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token comment">//该操作唤醒在地址addr的futex上等待的线程</span><span class="token keyword">int</span> <span class="token function">futex_wake</span><span class="token punctuation">(</span>atomic_int <span class="token operator">*</span>addr<span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">sys_futex</span><span class="token punctuation">(</span>addr<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><p><img src="/2023/03/05/os/image-20230225013245753.png" alt="image-20230225013245753"></p><p><img src="/2023/03/05/os/image-20230225013301538.png" alt="image-20230225013301538"></p><p>锁的规则-Rules for locks:</p><ul><li><p>Lock is initially free </p></li><li><p>Always acquire before acces sing shared data structure </p></li><li><p>Beginning of procedure! </p></li><li><p>Always release after finishing with shared data </p><ul><li><p>End of procedure! </p></li><li><p>Only the lock holder can release </p><p>DO NOT throw lock for someone else to release</p></li></ul></li><li><p>Never access shared data without lock </p></li><li><p>Danger!</p></li></ul><p>Rules for Condition Variables:</p><ul><li>ALWAYS hold lock when calling wait, signal, broadcast <ul><li>Condition variable is sync FOR shared state </li><li>ALWAYS hold lock when accessing shared state</li></ul></li><li>Condition variable is memoryless <ul><li>If signal when no one is waiting, no operation </li><li>If wait before signal, waiter wakes up</li></ul></li><li>Wait atomically releases lock</li></ul><h3 id="信号量Semaphores"><a href="#信号量Semaphores" class="headerlink" title="*信号量Semaphores"></a>*信号量Semaphores</h3><p>同步变量,一个整数值,无法通过外界访问,只能通过Semaphore操作:初始化,PV原语(P(), (or down() or wait()),检验,V() (or up() or signal()),自增;)</p><p>•如果信号量为正值,则将其视为跟踪有多少“资源”或“未激活的解除阻塞”可用</p><p>•如果信号量为负值,则跟踪有多少线程正在等待资源或解除阻塞</p><p>•提供排序和计数(“剩余”事件/资源)</p><h4 id="P(检验操作)"><a href="#P(检验操作)" class="headerlink" title="P(检验操作)"></a>P(检验操作)</h4><pre class="language-c" data-language="c"><code class="language-c"><span class="token comment">//阻塞版本:递减s,如果结果小于0 则阻塞</span><span class="token function">P</span><span class="token punctuation">(</span>s<span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">--</span>s <span class="token operator"><</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token function">block</span><span class="token punctuation">(</span>s<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token comment">//自旋版本:等s增到正值开始递减</span><span class="token function">P</span><span class="token punctuation">(</span>s<span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token keyword">while</span> <span class="token punctuation">(</span>s <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>s<span class="token operator">--</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><h4 id="V(自增操作)"><a href="#V(自增操作)" class="headerlink" title="V(自增操作)"></a>V(自增操作)</h4><pre class="language-c" data-language="c"><code class="language-c"><span class="token comment">//阻塞版本:递增s,如果结果小于等于0 则解除阻塞(代表此时无可用资源,有线程正在阻塞)</span><span class="token function">V</span><span class="token punctuation">(</span>s<span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">++</span>s <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token function">unblock</span><span class="token punctuation">(</span>s<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token comment">//自旋版本:等s增到正值开始递减</span><span class="token function">V</span><span class="token punctuation">(</span>s<span class="token punctuation">)</span><span class="token punctuation">{</span>s<span class="token operator">++</span><span class="token punctuation">}</span></code></pre><h4 id="生产者消费者版本"><a href="#生产者消费者版本" class="headerlink" title="生产者消费者版本"></a>生产者消费者版本</h4><pre class="language-c" data-language="c"><code class="language-c">semaphore empty <span class="token operator">=</span> N<span class="token punctuation">;</span> <span class="token comment">//可以理解为等待线程队列?</span>semaphore full <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">int</span> mutex <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">void</span> <span class="token function">producer</span><span class="token punctuation">(</span><span class="token keyword">void</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">int</span> item<span class="token punctuation">;</span> <span class="token keyword">while</span><span class="token punctuation">(</span>TRUE<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">produce_item</span><span class="token punctuation">(</span><span class="token operator">&</span>item<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">P</span><span class="token punctuation">(</span>empty<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">mutex_lock</span><span class="token punctuation">(</span>mutex<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">enter_item</span><span class="token punctuation">(</span>item<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">mutex_unlock</span><span class="token punctuation">(</span>mutex<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">V</span><span class="token punctuation">(</span>full<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token keyword">void</span> <span class="token function">consumer</span><span class="token punctuation">(</span><span class="token keyword">void</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">int</span> item<span class="token punctuation">;</span> <span class="token keyword">while</span><span class="token punctuation">(</span>TRUE<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">P</span><span class="token punctuation">(</span>full<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">mutex_lock</span><span class="token punctuation">(</span>mutex<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">remove_item</span><span class="token punctuation">(</span><span class="token operator">&</span>item<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">mutex_unlock</span><span class="token punctuation">(</span>mutex<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">V</span><span class="token punctuation">(</span>empty<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">consume_item</span><span class="token punctuation">(</span><span class="token operator">&</span>item<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre><p>使用了条件变量和互斥锁的信号量版本</p><pre class="language-c" data-language="c"><code class="language-c"><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span><span class="token string"><stdio.h></span></span><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span><span class="token string"><pthread.h></span></span><span class="token keyword">typedef</span> <span class="token keyword">struct</span> <span class="token punctuation">{</span><span class="token keyword">int</span> val<span class="token punctuation">;</span><span class="token keyword">int</span> mutex<span class="token punctuation">;</span>condition cond<span class="token punctuation">;</span><span class="token punctuation">}</span>semaphore<span class="token punctuation">;</span><span class="token keyword">void</span> <span class="token function">init</span><span class="token punctuation">(</span>semaphore <span class="token operator">*</span>s<span class="token punctuation">)</span><span class="token punctuation">{</span> s<span class="token operator">-></span>val <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token keyword">void</span> <span class="token function">P</span><span class="token punctuation">(</span>semaphore <span class="token operator">*</span>s<span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token function">mutex_lock</span><span class="token punctuation">(</span><span class="token operator">&</span><span class="token punctuation">(</span>s<span class="token operator">-></span>mutex<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">if</span> <span class="token punctuation">(</span>s<span class="token operator">-></span>val <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">//wait(ConditionVariables *cv, Lock *lock)</span><span class="token function">wait</span><span class="token punctuation">(</span><span class="token operator">&</span><span class="token punctuation">(</span>s<span class="token operator">-></span>cond<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token operator">&</span><span class="token punctuation">(</span>s<span class="token operator">-></span>mutex<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span>s<span class="token operator">-></span>val<span class="token operator">--</span><span class="token punctuation">;</span><span class="token function">mutex_unlock</span><span class="token punctuation">(</span><span class="token operator">&</span><span class="token punctuation">(</span>s<span class="token operator">-></span>mutex<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token keyword">void</span> <span class="token function">V</span><span class="token punctuation">(</span>semaphore <span class="token operator">*</span>s<span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token function">mutex_lock</span><span class="token punctuation">(</span><span class="token operator">&</span><span class="token punctuation">(</span>s<span class="token operator">-></span>mutex<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> s<span class="token operator">-></span>val<span class="token operator">++</span><span class="token punctuation">;</span> <span class="token function">singal</span><span class="token punctuation">(</span><span class="token operator">&</span><span class="token punctuation">(</span>s<span class="token operator">-></span>cond<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">mutex_unlock</span><span class="token punctuation">(</span><span class="token operator">&</span><span class="token punctuation">(</span>s<span class="token operator">-></span>mutex<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><h4 id="互斥锁、条件变量和信号量之间的区别"><a href="#互斥锁、条件变量和信号量之间的区别" class="headerlink" title="互斥锁、条件变量和信号量之间的区别"></a>互斥锁、条件变量和信号量之间的区别</h4><p>互斥锁用于进入临界区</p><p>条件变量用于睡眠和唤醒,以避免繁忙等待。</p><p>条件变量应该通过互斥锁来使用</p><p>信号量是一种更高的抽象,由条件变量、互斥锁和计数数(表示资源的数量,count number)实现</p><p>信号量可用于I/O设备和等待I/O完成的线程之间的同步通信。</p><p>—通常,硬件通过共享内存数据结构与设备驱动程序通信。</p><p>—该数据结构由硬件和内核同时读写</p><p>如果硬件设备需要提示(attention),例如,因为一个需要处理的网络数据包已经到达,或者磁盘请求已经完成,硬件就会更新共享数据结构并启动中断处理程序。</p><p>—中断处理程序通常很简单:它只是唤醒一个等待的线程并返回。</p><p>一个常见的解决方案是设备中断使用信号量。对于每个设备,分配一个信号量,初始值为0。</p><p>线程(进程)调用P,等待(挂起)设备完成某事。</p><p>设备完成后,中断将调用V,然后线程将再次准备好</p><h4 id="信号量的隐含危害"><a href="#信号量的隐含危害" class="headerlink" title="信号量的隐含危害"></a>信号量的隐含危害</h4><p>使用单独的锁和条件变量类使代码更具自文档性,更易于阅读。(既可以表示锁变量又可以表示条件变量的信号量可能不具有此优势)。</p><p>绑定到锁上的无状态条件变量比信号量(使用整数记录唤醒、休眠或资源的数量)是更好的广义等待抽象。</p><p>在使用信号量、锁、条件变量时,我们应该小心,因为简单的重新排序或缺少解锁都会导致非常糟糕的影响,导致程序行为的不正确。</p><h3 id="Monitors"><a href="#Monitors" class="headerlink" title="Monitors"></a>Monitors</h3><p>一个锁和零个或多个条件变量,用于管理对共享数据的并发访问</p><p>embedded in language:</p><p>•高级数据抽象,统一处理:共享数据,对它的操作,同步和调度</p><p>-数据结构上的所有操作都有一个(隐式)锁</p><p>-一个操作可以放弃控制并等待一个条件</p><p>•监视器是简单和安全的</p><p>-编译器可以检查,锁是隐式的(不能忘记)</p><p>•监视器有两种“等待”队列</p><p>-进入监视器:有一个线程队列等待获得互斥和进入</p><p>-条件变量:每个条件变量有一个线程队列等待相关的条件</p><p>…</p><h3 id="Barriers"><a href="#Barriers" class="headerlink" title="Barriers"></a>Barriers</h3><p>等待所有进程/线程都到达计算点(at point in computation)后再继续</p><p>separate phases of a multi-phase algorithm (多阶段算法的分离阶段)</p><p>二元性和互斥:包括其余所有而非排除其余所有</p><p><img src="/2023/03/05/os/image-20230225124327953.png" alt="image-20230225124327953"></p><p>…</p><h3 id="案例"><a href="#案例" class="headerlink" title="案例"></a>案例</h3><h4 id="作家读者问题"><a href="#作家读者问题" class="headerlink" title="作家读者问题"></a>作家读者问题</h4><p>特点</p><ul><li><p>允许多个线程同时read数据</p></li><li><p>同一时间仅能有一个writer写数据</p></li><li><p>writer写数据时不能有reader</p></li></ul><p>读写锁(RWLock)用来保护共享数据,实现了任意writer间的互斥和任意writer和reader间的互斥</p><p>…</p><ul><li><p>Avoiding Locks: Read-Copy-Update </p><p>reader应当可以选择查看旧值或writer实时更新的新值</p><p>RCU:reader与writer并发运,不显式地与writer同步</p><p>三大基本机制:发布-订阅机制,等待已存在的reader完成,维护最近更新对象的多个版本</p><p>…</p><p>宽限期:等reader读取完数据再删除(覆盖)旧数据</p><p>实现</p><pre class="language-none"><code class="language-none">•Readers disable interrupts on entry –Guarantees they complete critical section in a timely fashion –No read or write lock•Writer –Acquire write lock –Compute new data structure –Publish new version with atomic instruction –Release write lock –Wait for Ume slice on each CPU –Only then, garbage collect old version of data structure</code></pre><p>RCU的局限:</p><p>它适用于Publish-Subscribe更新模式,当数据比较复杂时(比如双链表,需要同时更新两个指针),使用RCU可能比较困难。</p><p>宽限期(grace period)可能太长(RCU提供了一个异步回调函数call_rcu())</p></li></ul><h4 id="哲学家就餐问题"><a href="#哲学家就餐问题" class="headerlink" title="哲学家就餐问题"></a>哲学家就餐问题</h4><p>圆桌,五个哲学家就坐,五盘意大利面,五个叉子放在间隙,每个哲学家需要两个叉子就餐</p><p>每个哲学家会进行以下循环:</p><p>– Think for a while<br>– Get 2 forks<br>– Eat for a while<br>– Put down the forks<br>– Repeat</p><p>设计Get 2 forks的方案</p><p>deadlock和starvation,死锁一定饿死,饿死不一定是死锁,死锁条件更强 。在饥饿状态下,线程在一段不确定的时间内无法取得进展。死锁是饥饿的一种形式,但条件更强:一组线程形成一个循环,其中没有一个线程取得进展,因为每个线程都在等待循环中的其他线程采取行动。</p><p>随即回退值</p><p>哲学家应当能互相沟通,当邻居哲学家正在吃时不应该拿叉子,沟通饿的意愿</p><pre class="language-c" data-language="c"><code class="language-c"><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">define</span> <span class="token macro-name">N</span> <span class="token expression"><span class="token number">5</span> </span><span class="token comment">/* number of philosophers */</span> </span><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">define</span> <span class="token macro-name">LEFT</span> <span class="token expression"><span class="token punctuation">(</span>i−<span class="token number">1</span><span class="token operator">+</span>N<span class="token punctuation">)</span><span class="token operator">%</span>N </span><span class="token comment">/* number of i’s left neighbor */</span> </span><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">define</span> <span class="token macro-name">RIGHT</span> <span class="token expression"><span class="token punctuation">(</span>i<span class="token operator">+</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token operator">%</span>N </span><span class="token comment">/* number of i’s right neighbor */</span> </span><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">define</span> <span class="token macro-name">THINKING</span> <span class="token expression"><span class="token number">0</span> </span><span class="token comment">/* philosopher is thinking */</span> </span><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">define</span> <span class="token macro-name">HUNGRY</span> <span class="token expression"><span class="token number">1</span> </span><span class="token comment">/* philosopher is trying to get forks */</span> </span><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">define</span> <span class="token macro-name">EATING</span> <span class="token expression"><span class="token number">2</span> </span><span class="token comment">/* philosopher is eating */</span></span><span class="token keyword">int</span> state<span class="token punctuation">[</span>N<span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment">/* array to keep track of everyone’s state */</span>semaphore mutex <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token comment">/* mutual exclusion for critical regions */</span> semaphore s<span class="token punctuation">[</span>N<span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment">/* one semaphore per philosopher */</span> <span class="token keyword">void</span> <span class="token function">philosopher</span><span class="token punctuation">(</span><span class="token keyword">int</span> i<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">while</span> <span class="token punctuation">(</span>TRUE<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">think</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">take_forks</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">eat</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">put_forks</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token keyword">void</span> <span class="token function">take_forks</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token comment">/* i: philosopher number, from 0 to N−1 */</span> mutex<span class="token punctuation">.</span><span class="token function">P</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* enter critical region */</span> state<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> HUNGRY<span class="token punctuation">;</span> <span class="token comment">/* record that philosopher i is hungry */</span> <span class="token function">test</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* try to acquire 2 forks */</span> mutex<span class="token punctuation">.</span><span class="token function">V</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* exit critical region */</span> s<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">P</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* block if forks were not acquired */</span><span class="token punctuation">}</span><span class="token keyword">void</span> <span class="token function">put_forks</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token comment">/* i: philosopher number, from 0 to N−1 */</span> mutex<span class="token punctuation">.</span><span class="token function">P</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* enter critical region */</span> state<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> THINKING<span class="token punctuation">;</span> <span class="token comment">/* philosopher has finished eating */</span> <span class="token function">test</span><span class="token punctuation">(</span>LEFT<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* see if left neighbor can now eat */</span> <span class="token function">test</span><span class="token punctuation">(</span>RIGHT<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* see if right neighbor can now eat */</span> mutex<span class="token punctuation">.</span><span class="token function">V</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* exit critical region */</span> <span class="token punctuation">}</span> <span class="token keyword">void</span> <span class="token function">test</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span> <span class="token comment">/* i: philosopher number, from 0 to N−1 */</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>state<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">==</span> HUNGRY <span class="token operator">&&</span> state<span class="token punctuation">[</span>LEFT<span class="token punctuation">]</span> <span class="token operator">!=</span> EATING <span class="token operator">&&</span>state<span class="token punctuation">[</span>RIGHT<span class="token punctuation">]</span> <span class="token operator">!=</span> EATING<span class="token punctuation">)</span> <span class="token punctuation">{</span> state<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> EATING<span class="token punctuation">;</span> s<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">V</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </code></pre><h2 id="死锁"><a href="#死锁" class="headerlink" title="死锁"></a>死锁</h2><h3 id="资源"><a href="#资源" class="headerlink" title="资源"></a>资源</h3><p>可抢占资源和不可抢占资源,前者可从占有进程控制中直接夺走,而不会造成不良影响,后者反之</p><p>死锁通常涉及不可抢占资源,涉及可抢占资源的死锁通常可由重新将进程资源分配给另一个进程解决(因为资源可抢占)。</p><h3 id="死锁介绍"><a href="#死锁介绍" class="headerlink" title="*死锁介绍"></a>*死锁介绍</h3><p>一个集合的进程是死锁当且仅当:</p><ul><li>集合中每个进程均在等待某个事件(每个进程等待事件不必相同)</li><li>这个事件仅能被除当前阻塞进程外的进程触发</li></ul><p><strong>死锁的四个必要条件</strong>(并非充要条件)</p><ul><li><p>互斥(Mutual exclusion):同一时间内,同一资源只能被一个进程使用。(或者有限个进程可以同时使用同一资源,但也可以理解为存在相同的多个资源)</p></li><li><p>持有并等待(Hold and wait):一个持有至少一个资源的进程正在等待获得其他进程持有的额外资源。</p></li><li><p>不可抢占(No preemption):进程所占资源仅能完成任务后自愿释放</p></li><li><p>环路等待(Circular wait condition):存在一个集合{P0, P1,…,Pn},其中n > 1,P0等待P1持有的一个(或多个)资源,P1等待P2持有的一个(或多个)资源,…,Pn - 1等待Pn持有的一个(或多个)资源,Pn等待P0持有的一个(或多个)资源</p></li></ul><p>特殊情况:单进程也可能死锁——递归,此时可改锁为整数,锁自己时递增,解锁递减,为0时才真解锁</p><pre class="language-c" data-language="c"><code class="language-c"><span class="token comment">// Thread A </span>function <span class="token function">callA</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span> lock<span class="token punctuation">.</span><span class="token function">acquire</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">callA</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> lock<span class="token punctuation">.</span><span class="token function">release</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">callA</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><h3 id="建模"><a href="#建模" class="headerlink" title="建模"></a>建模</h3><p>Resource-Allocation Graph资源分配图</p><p>—圆:表示进程。</p><p>—正方形:资源。</p><p>—从资源节点(方形)到流程节点(圆形)的有向弧线表示该资源目前由该流程持有。</p><p>—从进程节点到资源节点的有向弧线表示进程当前正在阻塞等待该资源。</p><p>画有向图,有环则有死锁(同一类型资源有多个时则不一定)</p><h3 id="鸵鸟算法-死锁解决办法"><a href="#鸵鸟算法-死锁解决办法" class="headerlink" title="鸵鸟算法-死锁解决办法"></a>鸵鸟算法-死锁解决办法</h3><p>The ostrich algorithm ,忽略问题也许问题就会消失</p><p>—用于大多数操作系统,包括UNIX</p><p>•检测和恢复。让死锁发生,检测死锁并采取行动。</p><p>•确保系统永远不会进入死锁状态</p><p>-通过仔细分配资源来动态避免。</p><p>-预防,从结构上否定四个必要条件之一。</p><p>鸵鸟算法广泛使用在于死锁的危害和修复死锁所需要付出的代价之间的平衡。</p><h3 id="死锁检测和恢复"><a href="#死锁检测和恢复" class="headerlink" title="*死锁检测和恢复"></a>*死锁检测和恢复</h3><ul><li><p>每种类型一个资源->可以利用环路检测算法进行死锁检测</p><p>深度优先搜索</p><p>1.对于图中的每个节点(N),以N为起始节点执行以下5步。</p><ol start="2"><li>初始化L为空列表,并指定所有弧为未标记。</li><li>将当前节点添加到L的末端,检查节点现在是否出现在L中两次。如果是,则图包含一个循环(列在L中),算法终止</li><li>从给定的节点,看看是否有任何未标记的输出弧线。如果是,请转步骤5;如果没有,请转步骤6。</li><li>随机选取未标记的出弧,标记出来。然后按照新的当前节点,转到步骤3。</li><li>如果这是初始节点,则图中不包含循环,算法终止。否则,含有死锁。删除它并返回到前一个节点</li></ol><p>但是不够优秀,存在很多冗余步骤,理论上复杂度为O(E+V),所有顶点和边均遍历一遍即可。</p></li><li><p>每种类型一个资源每种类型多个资源->环路检测算法失效,需要利用基于资源分配矩阵、请求矩阵、可用向量的算法进行检测</p><p>…没看</p></li><li><p>恢复:抢占(Preemption),回滚(Rollback),杀死进程</p><ul><li>preemption:把资源抢走分配给另一个,原进程挂起,执行结束后再唤醒</li><li>rollback:设置检查点,存储进程状态(内存映像和资源状态,新旧检查点不能覆盖),回滚到占用资源之前的状态</li><li>终止所有涉及死锁的进程,可以一次解决或者每次终止一个(按进程优先级、进程运行时间、资源使用情况、待完成情况)</li></ul></li></ul><h3 id="死锁避免(Deadlock-Avoidance)"><a href="#死锁避免(Deadlock-Avoidance)" class="headerlink" title="*死锁避免(Deadlock Avoidance)"></a>*死锁避免(Deadlock Avoidance)</h3><p>通过合理分配资源来避免死锁(过去,进程一次请求全部资源,如今每次请求一个或几个资源)</p><p>资源轨迹(resource trajectories)</p><h4 id="安全状态(safe)、非安全状态(Unsafe)"><a href="#安全状态(safe)、非安全状态(Unsafe)" class="headerlink" title="安全状态(safe)、非安全状态(Unsafe)"></a>安全状态(safe)、非安全状态(Unsafe)</h4><ul><li><p>现有资源向量E,可用资源向量A,当前分配矩阵C,最大请求矩阵M,请求向量R</p><p><img src="/2023/03/05/os/image-20230225213910159.png" alt="image-20230225213910159"></p></li></ul><p>…</p><h4 id="银行家算法(Banker’s-algorithm)"><a href="#银行家算法(Banker’s-algorithm)" class="headerlink" title="银行家算法(Banker’s algorithm)"></a>银行家算法(Banker’s algorithm)</h4><ul><li><p>检查是否允许请求导致不安全状态。</p><p>如果是,则拒绝请求。如果授予请求导致安全状态,则执行请求。</p></li></ul><p>剩余需求矩阵N,N[i][j] = M[i][j]−C[i][j]</p><p>安全检查算法应:</p><p>1.尝试最坏的情况:让每个进程请求它们所需的最大资源。</p><p>2.调用死锁检测算法,如果它导致死锁,那么它是不安全的。</p><p>3.否则,它是安全的。</p><p>具体操作:</p><p>\1. 寻找一行N,其未满足的资源需求都小于或等于A。如果不存在这样的行,系统将最终死锁。</p><p>\2. 假设所选行的进程请求所需的所有资源并结束。将该进程标记为终止,将其资源添加到A向量。</p><p>3.重复步骤1和2,直到所有进程都标记为终止(安全状态),或者没有可以满足资源需求的进程(死锁)。</p><h3 id="防止死锁"><a href="#防止死锁" class="headerlink" title="防止死锁"></a>防止死锁</h3><p>确保至少有一个条件从未被满足–互斥(Mutual exclusion)、持有并等待(Hold and wait)、不可抢占(No preemption)、环路等待(Circular wait condition)</p><p>…</p><h3 id="其他问题"><a href="#其他问题" class="headerlink" title="其他问题"></a>其他问题</h3><p>…</p><h3 id="摘要"><a href="#摘要" class="headerlink" title="摘要"></a>摘要</h3><p>…</p><h2 id="内存管理"><a href="#内存管理" class="headerlink" title="内存管理"></a>内存管理</h2><h3 id="内存管理的功能"><a href="#内存管理的功能" class="headerlink" title="内存管理的功能"></a>内存管理的功能</h3><p>•当有多个进程正在使用内存和资源时,在主存中处理所有与内存相关的操作和资源</p><p>—跟踪内存的哪些部分正在使用</p><p>—在需要时为进程分配内存,并在它们完成时释放内存</p><p>—保护所需的内存以确保正确的操作</p><p>—扩展物理内存的限制</p><p>•最大化内存利用率和系统吞吐量</p><p>• Control & Efficiency 控制与效率</p><h3 id="虚拟和物理地址空间"><a href="#虚拟和物理地址空间" class="headerlink" title="虚拟和物理地址空间"></a>虚拟和物理地址空间</h3><p>虚地址转换,MMU(Memory-Management Unit ),内存粒度</p><h3 id="进程级、分段和分页"><a href="#进程级、分段和分页" class="headerlink" title="*进程级、分段和分页"></a>*进程级、分段和分页</h3><h4 id="地址转换"><a href="#地址转换" class="headerlink" title="地址转换"></a>地址转换</h4><p>在物理内存中连续地分配地址空间</p><p>Base和Limit (Bound):使用两个特殊的硬件寄存器来定义地址空间(动态重定位-dynamic relocation)•Base:进程在内存中开始的物理地址•Limit:内存区域的长度</p><p>非常简陋,保护几乎没有(粗粒度),不能增加堆栈,不能和其他进程共享代码</p><p>*分页</p><p>–页表和页表项</p><p>–页面共享</p><p>–写时复制 (Copy on Write)</p><p>–转换检测缓冲区/快表 (TLB) 和 TLB Miss</p><p>–有效访问时间</p><p>–多级页表</p><p>–页面大小</p><p><img src="/2023/03/05/os/image-20230226131832095.png" alt="image-20230226131832095"></p><h3 id="虚拟内存"><a href="#虚拟内存" class="headerlink" title="*虚拟内存"></a>*虚拟内存</h3><h4 id="缺页错误-Page-Fault-及其处理流程"><a href="#缺页错误-Page-Fault-及其处理流程" class="headerlink" title="缺页错误 (Page Fault) 及其处理流程"></a>缺页错误 (Page Fault) 及其处理流程</h4><p>处理页面错误的三个主要活动:•服务中断:仔细编码意味着只需要几百条指令•读取页面:大量时间•重新启动进程:少量时间</p><h4 id="页面置换算法"><a href="#页面置换算法" class="headerlink" title="页面置换算法:"></a>页面置换算法:</h4><p>FIFO:替换最老的</p><p>Optimal:替换长时间不使用的页面</p><p>Least Recently Used (LRU):替换在大多数时间内未被使用的页面(需要计数器来统计)</p><p>Approximating LRU (Second Chane, NRU, Aging):</p><ul><li><p>second chance</p><p>•当一个页面被引用(即读或写)时,引用位被设置为1(由硬件)</p><p>•如果要替换的页面有</p><p>•R = 1(最近使用):设置R位为0;</p><p>•R = 0:替换它</p><p>•如果所有页面都被引用,第二次机会= FIFO</p></li><li><p>NRU:通过引用位+修改位(最近未使用,NRU)近似LRU:为那些修改的页面分配更高的优先级,以减少I/O(增强的第二次机会)</p></li><li><p>aging:老化算法</p><p>通过额外的参考位:保持一个软件计数器来跟踪每个页面被引用的频率,并用最小的计数替换页面</p><p>•每个页面对应一个软件计数器</p><p>•在每次时钟中断时</p><p>—计数器每个右移1位</p><p>—R位增加到最左边</p><p>•数值越大表示最近使用的页面</p><p>—选择01110111页面替换,而不是11000100页面</p></li></ul><p>• Demand Paging: bring a page into memory only when it is<br>needed<br>• Prefetching: guess which pages are about to be used, and thus bring it in ahead of time</p><h3 id="工作集模型"><a href="#工作集模型" class="headerlink" title="工作集模型"></a>工作集模型</h3><h4 id="–抖动-Thrashing"><a href="#–抖动-Thrashing" class="headerlink" title="–抖动 (Thrashing)"></a>–抖动 (Thrashing)</h4><p>如果一个进程没有“足够”的页面,页面故障率就会非常高。此时,应降低多路编程的程度,作为换出进程可以释放其帧。</p><p>Thrashing:进程将所有时间用于交换页面(大多数引用会导致页面错误)</p><h4 id="–访问局部性-Principle-of-Locality"><a href="#–访问局部性-Principle-of-Locality" class="headerlink" title="–访问局部性 (Principle of Locality)"></a>–访问局部性 (Principle of Locality)</h4><p>时间、空间</p><p>工作集</p><p>•工作集:页面的集合过程中使用最近的k内存引用——如果整个工作集是在内存中,这一过程会不会引起许多缺点,直到它进入另一个执行阶段,如果可用内存太小,不能容纳整个工作集,抖动发生•跟踪每个进程的工作集,并确保它在内存之前让进程运行,大大降低故障率的页面</p><h3 id="页框的全局和局部分配策略"><a href="#页框的全局和局部分配策略" class="headerlink" title="页框的全局和局部分配策略"></a>页框的全局和局部分配策略</h3><h4 id="需求分页"><a href="#需求分页" class="headerlink" title="需求分页"></a>需求分页</h4><h4 id="页面替换"><a href="#页面替换" class="headerlink" title="页面替换"></a>页面替换</h4><h4 id="页面缓冲"><a href="#页面缓冲" class="headerlink" title="页面缓冲"></a>页面缓冲</h4><h4 id="帧分配"><a href="#帧分配" class="headerlink" title="帧分配"></a>帧分配</h4><h4 id="内存分配"><a href="#内存分配" class="headerlink" title="内存分配"></a>内存分配</h4><p>*连续内存分配 </p><p>当一个程序开始运行时,操作系统决定它应该在物理内存的哪里被加载,并设置base寄存器和limit寄存器(在内存中为它的地址空间寻找空间)•当在进程之间切换时,操作系统必须保存和恢复base-and-limit pair•当用户程序试图非法访问内存(可能会终止进程)时,操作系统必须提供异常处理程序</p><h4 id="空闲空间管理"><a href="#空闲空间管理" class="headerlink" title="空闲空间管理"></a>空闲空间管理</h4><h4 id="动态空间分配算法"><a href="#动态空间分配算法" class="headerlink" title="动态空间分配算法"></a>动态空间分配算法</h4><p>First-Fit:第一次分配足够大的hole,目的是尽可能减少搜索次数</p><p>Next-Fit:跟踪上一次分配的hole,并在上次停止的位置开始第一次匹配的搜索,性能比first-fit略差</p><p>Best-Fit:分配最小的足够大的hole,需要search整个list,可能产生小而无用的hole从而产生浪费</p><p>Worst-Fit:分配最大的洞——也搜索整个列表——也不是一个很好的主意</p><p>Quick-Fit:一些更常见的请求大小维护单独的列表-找到所需大小的hole非常快-但hole应该按大小排序(当进程终止时)</p><h4 id="内部碎片和外部碎片"><a href="#内部碎片和外部碎片" class="headerlink" title="内部碎片和外部碎片"></a>内部碎片和外部碎片</h4><h4 id="地址保护"><a href="#地址保护" class="headerlink" title="地址保护"></a>地址保护</h4><h4 id="内存扩展"><a href="#内存扩展" class="headerlink" title="内存扩展"></a>内存扩展</h4><h2 id="文件系统"><a href="#文件系统" class="headerlink" title="文件系统"></a>文件系统</h2><h3 id="文件系统的功能"><a href="#文件系统的功能" class="headerlink" title="*文件系统的功能"></a>*文件系统的功能</h3><p>为应用程序提供持久的和命名的数据</p><p>•长期信息存储的基本要求-存储非常大量的信息-当进程终止时信息必须存活-多个进程必须能够同时访问信息</p><p>文件系统—为存储提供用户界面,将逻辑块映射到物理—通过允许数据存储、定位和轻松检索来高效访问磁盘</p><h4 id="核心功能"><a href="#核心功能" class="headerlink" title="核心功能"></a>核心功能</h4><p>•持久命名数据:文件和目录-存储直到它被显式删除,即使存储它的计算机崩溃或断电-可以通过文件系统与文件关联的人类可读标识符访问</p><p>•访问和保护:提供打开,读,写和其他操作;协调不同用户对文件的访问</p><p>•磁盘管理:公平高效地使用磁盘空间—为文件分配空间并跟踪空闲空间—快速访问文件</p><p>•可靠性:不能丢失文件数据</p><h3 id="文件"><a href="#文件" class="headerlink" title="*文件"></a>*文件</h3><p>可以创建,读取,写入和删除的字节(由用户定义的类型)的线性数组,一种抽象机制,提供了一种将信息存储在磁盘上并稍后读取的方法</p><h4 id="命名"><a href="#命名" class="headerlink" title="命名"></a>命名</h4><p>人类可读命名,扩展名<img src="/2023/03/05/os/image-20230226005914514.png" alt="image-20230226005914514"></p><h4 id="属性"><a href="#属性" class="headerlink" title="属性"></a>属性</h4><p>类型:常规文件:包含用户信息的文件(ASCII文件:由文本行组成;二进制文件:具有特定程序所知道的一些内部结构);目录文件:用于维护文件系统结构的系统文件;特殊文件:字符(打印机),块(磁带),……•每个操作系统都必须至少识别一种文件类型:它自己的可执行文件</p><p>metadata<img src="/2023/03/05/os/image-20230226010149214.png" alt="image-20230226010149214"></p><p>文件系统应该将文件元数据保存在一个结构中:索引节点(inode) (UNIX中给出的历史名称),驻留在磁盘上,缓存在内存中以加快访问速度</p><h4 id="文件访问"><a href="#文件访问" class="headerlink" title="文件访问"></a>文件访问</h4><p>顺序访问</p><p>read next / write next / reset,最常见,比如复制文件、编译器读取和写入,可以非常快</p><p>随机访问模式</p><p> read n / write n / seek n,包含块数作为参数,不快</p><h4 id="与文件相关的操作"><a href="#与文件相关的操作" class="headerlink" title="与文件相关的操作"></a>与文件相关的操作</h4><p>存储和检索信息的操作</p><p>•Create:宣布文件并设置属性•Delete:释放磁盘空间•Open:将属性和磁盘地址列表提取到主存中进行快速访问•Close:释放内部表空间,强制写入文件的最后一个块•Read:从文件中读取数据(指定需要多少数据并提供缓冲区)•Write:将数据写入文件(在当前位置)•Append:限制写操作的形式•Seek:在文件中重新定位(指定从哪里获取数据)•Get and Set Attributes:读取和更改文件属性•Rename:更改文件名称</p><p>•一些系统只提供了文件操作的最小系统调用集(其他操作可以使用这些操作实现)</p><h4 id="文件描述符-File-Descriptor"><a href="#文件描述符-File-Descriptor" class="headerlink" title="文件描述符 (File Descriptor)"></a>文件描述符 (File Descriptor)</h4><p>由操作系统分配的用于引用文件的唯一编号(每个进程私有)</p><p>•避免解析文件名(在目录中搜索文件名)并检查每次访问的权限</p><p>•执行某些操作的能力</p><p><img src="/2023/03/05/os/image-20230226010902878.png" alt="image-20230226010902878"></p><h4 id="打开文件表-Open-File-Table"><a href="#打开文件表-Open-File-Table" class="headerlink" title="打开文件表 (Open-File Table)"></a>打开文件表 (Open-File Table)</h4><p>进程打开文件时,OS要创建一个存储文件信息的数据结构</p><p>每个进程维护一个打开文件表(由文件描述符索引的数组),表中的每个条目都跟踪文件描述符引用的底层文件、当前偏移量和其他相关详细信息(例如权限)</p><p>per-process open-file table:跟踪所有被进程打开的文件</p><p>system-wide open-file table:跟踪与进程无关的信息,系统维护所有打开文件的信息</p><p>打开文件步骤:在系统打开文件表中寻找这个文件条目(如果没有则在目录中寻找文件名,找到后添加到系统打开文件表中);在每进程文件打开表中创建一个指向系统打开文件表对应条目的条目;自增系统打开文件表的open count(仅有当此变量为0时才能移除对应条目);返回一个指向每进程文件打开表中对应条目的指针</p><p>三个描述文件描述符和打开文件关系的表(Unix中):</p><p>•文件描述符表(每个进程的):每个由进程打开的文件描述符都有一个条目——引用打开文件描述</p><p>•打开文件表(系统):每个打开的文件都有一个条目——文件偏移量,访问模式,状态标志——参考inode对象文件</p><p>•inode表(系统):每个索引节点都有一个条目,文件类型权限,其他属性(大小、时间戳、…</p><h4 id="偏移-Offset"><a href="#偏移-Offset" class="headerlink" title="偏移 (Offset)"></a>偏移 (Offset)</h4><p>对于进程打开的每个文件,操作系统都会跟踪文件偏移量,这决定了下一次读或写将从哪里开始</p><p>•隐式更新(当发生N个字节的读或写时,N被添加到当前偏移量)</p><p>•通过系统调用显式更新:lseek()</p><h3 id="目录"><a href="#目录" class="headerlink" title="*目录"></a>*目录</h3><p>目录操作<img src="/2023/03/05/os/image-20230226100526798.png" alt="image-20230226100526798"></p><ul><li><p>目录的层级结构(在目录中放置目录)</p><p>目录存储人类可读文件名和低级文件索引(inode号)之间的映射</p><p>⟨文件名,文件索引⟩pair的表</p><p>为根目录分配固定的inode号</p></li><li><p>从文件路径名到文件 inode 的转换</p><p>根目录中寻找对应inode,找到对应磁盘block,到磁盘再找inode…</p></li><li><p>硬链接 (Hard Link) 和符号链接 (Symbolic Link)</p><p>新文件链接到旧文件名,同一文件有了多个名字,目录结构是有向无环图</p><p>硬链接依赖inode,每个inode对应一个独一无二的文件,对inode的引用,系统有计数,计数减到0文件就算被删除。unlink()可以减少计数;存在规则:不能跨文件系统链接(inode仅在同一文件系统内唯一),不能链接到目录(防止出现环);文件所有者仅有一个。</p><p>软链接依赖路径名:生产一个存储了链接文件路径的link类型文件;可以跨文件系统,可以递归链接(链接目录、甚至link类型文件)</p></li></ul><p>文件系统挂载(Mount)</p><h3 id="文件系统的布局"><a href="#文件系统的布局" class="headerlink" title="*文件系统的布局"></a>*文件系统的布局</h3><p> Superblock, bitmap, inodes, data blocks</p><p><img src="/2023/03/05/os/image-20230226102518514.png" alt="image-20230226102518514"></p><p>单个物理磁盘可以划分并存储多个卷,也可以将多个物理磁盘组合在一起,使单个卷跨越多个物理磁盘,包含文件系统的分区称为卷</p><p>文件系统维护数据存储的磁盘结构,磁盘分块block:数据区域,inode表区域(文件的metadata),分配结构(存储磁盘已分配信息和空余信息,data region和inode table各一个),superblock(存储文件系统信息,文件系统类型,inode数量,block数量,inode table起始位置,是挂载文件系统时第一个被读取的block)</p><p><img src="/2023/03/05/os/image-20230226103951089.png" alt="image-20230226103951089"></p><p><img src="/2023/03/05/os/image-20230226104228068.png" alt="image-20230226104228068"></p><p>引导块(boot block):引导OS所需的信息,通常是分区的第一个块(如果没有OS则为空)</p><p>主引导记录(MBR):引导计算机的信息</p><p>分区表(Partition Table):每个分区的开始和结束地址(其中一个标记为活动)</p><p>文件系统还需要维护用于数据访问的内存结构(反映和扩展磁盘结构)•挂载表:关于文件系统挂载的信息(挂载点,文件系统类型)•开放文件表:全系统级和每进程级•目录结构:关于最近访问的目录的信息•I/O内存缓冲区:当文件系统块被读取或写入磁盘时保存它们</p><h3 id="文件的组织"><a href="#文件的组织" class="headerlink" title="*文件的组织"></a>*文件的组织</h3><p>文件需要分配磁盘块来存储数据,并具有指向数据块所在位置的结构</p><ul><li><p>Contiguous</p><p>连续分配,每个文件占用一组连续的块</p><p>•只需要第一个块的磁盘地址和块的个数。•可以高效地实现顺序访问。•也可以快速计算任意地址的数据位置</p><p>不灵活,文件创建时就需要指定文件大小,容易产生磁盘碎片。适合DVD和CD-ROM;有的文件系统用extend-based,比block更大,是连续block形成的extend(区段)</p></li><li><p>Linked List</p><p>a linked list of blocks,每个block含有指向next的指针</p><p>没有外部碎片,也只需要第一个block的地址</p><p>缺点在于随机访问慢,指针浪费空间,可靠性不高</p><p>可以采用cluster of blocks改进,但内部可能产生碎片</p></li><li><p>File Allocation Table</p><p>链表分配的变种,用于MS-DOS,把所有指针放进FAT</p><p>每个FAT条目对应一个磁盘block,每个条目包含一个指向代表了相同文件的block的FAT条目的指针,或者文件末尾值</p><p>目录同样可以存储起始块号,提供随机访问(在内存中搜索FAT),用两个这样的表备份</p><p>缺点在与内存开销大(FAT表必须一直在内存中)</p></li><li><p>Indexed (inode 的多级索引设计)</p><p>每个文件都有一个指向块的指针数组(索引block)</p><p>索引块只在相应文件打开时才需要在内存中,大小只跟一次需要打开的最大文件block大小有关(还是可能很大)</p><p>多级索引:可以有间接指针块(不是指向包含用户数据的块,而是指向包含更多指针的块),针对更大文件可以有多重指针块,不平衡树</p><p><img src="/2023/03/05/os/image-20230226110411890.png" alt="image-20230226110411890"></p></li></ul><p>文件碎片-大多数文件都很小(平均200kB)</p><p>最佳的文件组织方法取决于-文件系统的特征-文件访问类型(例如,连续的适合顺序)-…</p><p>考虑要素:快速查找数据进行顺序和/或随机访问-内部和外部碎片-易于实现-支持文件增长-存储开销</p><h3 id="目录的组织"><a href="#目录的组织" class="headerlink" title="*目录的组织"></a>*目录的组织</h3><p>–目录项中包含的信息、不同长度文件名的处理</p><p>⟨file name, file index⟩ mapping</p><p>包含的信息可能为:—整个文件的磁盘地址—第一个块号—inode号</p><p>文件属性(metadata)可以直接存储在目录条目中(固定大小的条目大小),或者每个目录条目只引用一个inode(只有文件名+ inode号)<img src="/2023/03/05/os/image-20230226110854879.png" alt="image-20230226110854879"></p><p>两种组织方法:</p><p>entry长度不一致:条目长度(固定)—属性(固定)—文件名(以特殊字符结束)•当一个文件被删除时,会引入一个可变大小的间隙</p><p>一致:保持所有的文件名在一个堆中•当一个条目被删除,下一个输入的文件将始终适合•文件名不需要从单词边界开始•必须管理堆</p><h3 id="文件系统的性能"><a href="#文件系统的性能" class="headerlink" title="*文件系统的性能"></a>*文件系统的性能</h3><p>如何跟踪哪些索引节点和数据块是空闲的?•当一个新的文件或目录被分配时,文件系统可以为它找到空间;位图bitmap和自由列表free list是两种常见的方法•更复杂的数据结构,如b -树也被使用</p><p>bitmap:每一位代表一个block的状态,能比较容易地找到连续磁盘空间,需要额外空间存储位图</p><p>free list:把空闲空间串成一个链表,让每个块拥有尽可能多的空闲磁盘块号(分组)-对于1KB的块,和4字节的块号,每个块拥有255个空闲块-分配多个空闲块不需要遍历列表;不浪费空间,寻找和分配(需要遍历)比较麻烦;部分block装满,部分不装满(解决频繁I/O造成的性能浪费)</p><p>读文件的步骤:</p><p>•首先,打开文件-遍历路径名并找到所需的inode -读取该inode,执行权限检查,返回文件描述符</p><p>•然后,对于发出的每个读操作-读取inode -读取数据块-写入inode(更新上次访问时间) -在打开的文件表(内存)中更新文件偏移量</p><ul><li><p>缓存 (Cache and Buffering) </p><p>将经常使用的块保留在内存中:如果需要的块在内存中,则不需要I/O就读取它•使用哈希表跟踪给定的块是否存在•当缓存满时必须删除一些块(类似于页面替换问题);提前读取常用block到内存;写延迟,优化写操作(回写和直写);</p></li><li><p>快速文件系统 (FFS)</p><p>disk-awareness的文件系统</p><p>通过在同一个组中放置两个文件,FFS确保访问一个文件后不会导致长时间的磁盘查找</p><p>实现数据局部性原则</p><p>对于文件-将数据块分配到与其inode相同的组中-将同一目录下的所有文件放在它们所在的目录组中</p><p>对于目录-找到已分配目录数量较少(以平衡组间的目录)和空闲inode数量较多(以能够分配一堆文件)的组-将目录数据和inode放在该组中</p></li></ul><h3 id="文件系统的一致性"><a href="#文件系统的一致性" class="headerlink" title="*文件系统的一致性"></a>*文件系统的一致性</h3><p>•对文件系统的更新操作需要多次I/O操作(更新多个数据结构)—崩溃时,一些操作可能完成,一些操作可能丢失•使文件系统处于不一致状态</p><p>写操作步骤:•在文件中追加一个数据块—写入新的数据块—写入文件的inode—写入数据位图</p><p>后两步骤出现崩溃会出现一致性问题</p><ul><li><p>文件系统一致性检查 (fsck)</p><p>File System Consistency Check,在挂载文件系统之前运行(假设在运行时没有文件系统活动),并确保文件系统元数据在内部保持一致</p><p>• Sanity check the superblock<br>• Check validity of free block and bitmaps<br>• Check that inodes are not corrupted<br>• Check inode links<br>• Check for duplicate pointers and bad blocks<br>• Check directories</p><p>•检查超级块•检查空闲块和位图的有效性•检查inode是否损坏•检查inode链接•检查重复的指针和坏块•检查目录</p><p>太慢,对文件系统知识要求高</p></li><li><p>日志文件系统 (Journaling)</p><p>write-ahead logging,覆写结构之前,记录即将进行的操作</p><p>循环日志,日志大小固定,花费高</p><p>元数据日志</p><p><img src="/2023/03/05/os/image-20230226130004974.png" alt="image-20230226130004974"></p></li></ul><h3 id="虚拟文件系统"><a href="#虚拟文件系统" class="headerlink" title="*虚拟文件系统"></a>*虚拟文件系统</h3><h2 id="设备管理"><a href="#设备管理" class="headerlink" title="设备管理"></a>设备管理</h2><h3 id="•-Input-x2F-Output-I-x2F-O-devices"><a href="#•-Input-x2F-Output-I-x2F-O-devices" class="headerlink" title="• Input/Output (I/O) devices"></a>• Input/Output (I/O) devices</h3><p>– How should I/O be integrated into systems?<br>– What are the general mechanisms?</p><h3 id="•-Hard-disk-drive"><a href="#•-Hard-disk-drive" class="headerlink" title="• Hard disk drive"></a>• Hard disk drive</h3><p>– How is the data actually laid out and accessed?<br>– How does disk scheduling improve performance?</p><h3 id="•-RAID"><a href="#•-RAID" class="headerlink" title="• RAID"></a>• RAID</h3><p>– How can we make a large, fast, and reliable storage system?</p><h3 id="I-x2F-O-设备的交互"><a href="#I-x2F-O-设备的交互" class="headerlink" title="*I/O 设备的交互"></a>*I/O 设备的交互</h3><p> Polling, Interrupts, DMA</p><h3 id="磁盘"><a href="#磁盘" class="headerlink" title="*磁盘"></a>*磁盘</h3><p>–寻道时间和旋转延迟</p><p>–磁盘调度算法: First Come First Service (FCFS), Shortest Seek First (SSF), Elevator (SCAN)</p><p>SSF:按轨道排列I/O请求队列,选择最近轨道上的请求先完成,可能造成饿死</p><p>SCAN:简单地在磁盘服务请求上按顺序在磁道上来回移动(就像电梯一样)•一次通过磁盘(从外磁道到内磁道,或从内磁道到外磁道)称为扫描</p><h2 id="汇编文件相关"><a href="#汇编文件相关" class="headerlink" title="汇编文件相关"></a>汇编文件相关</h2><h3 id="至少三个节"><a href="#至少三个节" class="headerlink" title="至少三个节"></a>至少三个节</h3><h4 id="data"><a href="#data" class="headerlink" title=".data"></a>.data</h4><p>程序已初始化的数据,具有初值的变量</p><h4 id="text"><a href="#text" class="headerlink" title=".text"></a>.text</h4><p>包含程序代码,只读节</p><h4 id="bss"><a href="#bss" class="headerlink" title=".bss"></a>.bss</h4><p>包含未初始化变量,不占用空间,操作系统装入时全置为0</p><hr><h3 id="常用指令"><a href="#常用指令" class="headerlink" title="常用指令"></a>常用指令</h3><h4 id="ascii"><a href="#ascii" class="headerlink" title=".ascii"></a>.ascii</h4><pre class="language-asm" data-language="asm"><code class="language-asm">.ascii“string” …</code></pre><p>ascii 表示零个或多个(用逗号隔开)字符串,并把每个字符串(结尾不自动加“\0”字符)中的字符放在连续的地址单元。</p><p>与此类似的 <code>.asciz</code>指令定义的字符串会在结尾处自动加 “\0”字符</p><h4 id="fill"><a href="#fill" class="headerlink" title=".fill"></a>.fill</h4><pre class="language-assembly" data-language="assembly"><code class="language-assembly">.fill repeat [, size , value]</code></pre><p>反复拷贝size个字节,重复repeat次 ,其中size和value是可选的,默认值分别为1和0</p><h4 id="global"><a href="#global" class="headerlink" title=".global"></a>.global</h4><pre class="language-assembly" data-language="assembly"><code class="language-assembly">.global symbol</code></pre><p>使得链接程序(ld)能识别symbol,局部程序中定义了.global symbol,则在与其链接的其它局部程序中也能存取symbol</p><hr><h3 id="内联汇编"><a href="#内联汇编" class="headerlink" title="内联汇编"></a>内联汇编</h3><p>使用内嵌汇编,要先编写汇编指令模板,然后将C语言表达式与指令的操作数相关联,并告诉GCC对这些操作有哪些限制条件。例如下面的汇编语句: </p><p> <code>__asm__ __violate__ ("movl %1,%0" : "=r" (result) : "r" (input));</code> </p><p>“movl %1,%0”是指令模板;“%0”和“%1”代表指令的操作数,称为占位符,“=r”代表它之后是输入变量且需用到寄存器,指令模板后面用小括号括起来的是C语言表达式 ,其中input是输入变量,该指令会完成把input的值复制到result中的操作</p><p>内嵌汇编语法如下:</p><pre class="language-none"><code class="language-none">__asm__( 汇编语句模板: 输出部分: 输入部分: 破坏描述部分);即格式为asm ( "statements" : output_regs : input_regs : clobbered_regs)</code></pre><h2 id="汇编语法相关"><a href="#汇编语法相关" class="headerlink" title="汇编语法相关"></a>汇编语法相关</h2><h3 id="环境语法"><a href="#环境语法" class="headerlink" title="环境语法"></a>环境语法</h3><p>旧版本的GAS把”.code16”解释为“生成32位指令,但是隐式地插入addr32(Address-Size Prefix 67H)和data32(Operand-Size Prefix 66H)指令来使代码工作在实模式下”。</p><p>新版本的GAS把”.code16”解释为“生成看似正确的16位指令”。这要求,当程序员想要使用32位得地址或是数据时,自己显示地插入addr32和data32指令。</p><pre class="language-asm" data-language="asm"><code class="language-asm">data32 addr32 lgdt gdtDesc # loading gdtr, data32, addr32...data32 ljmp $0x08, $start32 # reload code segment selector and ljmp to start32, data32</code></pre><h3 id="条件跳转和其它指令配合"><a href="#条件跳转和其它指令配合" class="headerlink" title="条件跳转和其它指令配合"></a>条件跳转和其它指令配合</h3><p>Intel格式</p><p> 无符号数比较</p><p>基于无符号数比较的跳转如下表所示。操作数的名称反映了表达式中操作数的顺序(比如 leftOp < rightOp)。下表中的跳转仅在比较无符号数值时才有意义。有符号操作数使用不同的跳转指令。</p><table><thead><tr><th>助记符</th><th>说明</th><th>助记符</th><th>说明</th></tr></thead><tbody><tr><td>JA</td><td>大于跳转(若 leftOp > rightOp)</td><td>JB</td><td>小于跳转(若 leftOp < rightOp)</td></tr><tr><td>JNBE</td><td>不小于或等于跳转(与 JA 相同)</td><td>JNAE</td><td>不大于或等于跳转(与 JB 相同)</td></tr><tr><td>JAE</td><td>大于或等于跳转(若 leftOp ≥ rightOp)</td><td>JBE</td><td>小于或等于跳转(若 leftOp ≤ rightOp)</td></tr><tr><td>JNB</td><td>不小于跳转(与 JAE 相同)</td><td>JNA</td><td>不大于跳转(与 JBE 相同)</td></tr></tbody></table><p>有符号数比较</p><p>下表列岀了基于有符号数比较的跳转。下面的指令序列展示了两个有符号数值的比较:</p><table><thead><tr><th>助记符</th><th>说明</th><th>助记符</th><th>说明</th></tr></thead><tbody><tr><td>JG</td><td>大于跳转(若 leftOp > rightOp)</td><td>JL</td><td>小于跳转(若 leftOp < rightOp)</td></tr><tr><td>JNLE</td><td>不小于或等于跳转(与 JG 相同)</td><td>JNGE</td><td>不大于或等于跳转(与 JL 相同)</td></tr><tr><td>JGE</td><td>大于或等于跳转(若 leftOp ≥ rightOp)</td><td>JLE</td><td>小于或等于跳转(若 leftOp ≤ rightOp)</td></tr><tr><td>JNL</td><td>不小于跳转(与 JGE 相同)</td><td>JNG</td><td>不大于跳转(与 JLE 相同)</td></tr></tbody></table><pre class="language-asm" data-language="asm"><code class="language-asm">mov al, +127 ;十六进制数值 7Fhcmp al, -128 ;十六进制数值 80hja Is Above ;不跳转,因为 7Fh < 80hjg IsGreater ;跳转,因为 +127 > -128</code></pre><p>由于无符号数 7Fh 小于无符号数 80h,因此,为无符号数比较而设计的 JA 指令不发生跳转。另一方面,由于 +127 大于 -128,因此,为有符号数比较而设计的 JG 指令发生跳转。</p><p>AT&T格式中则是比较rightOp <em>operator</em> leftOp</p><h3 id="iret"><a href="#iret" class="headerlink" title="iret"></a>iret</h3><p>iret 指令描述为:pop IP pop CS popf</p><p>iret指令执行后,CPU回到执行中断处理程序前的执行点继续执行程序</p><pre class="language-none"><code class="language-none">old_CS = CS pop EIP pop CS pop EFLAGS if(GDT[old_CS].DPL < GDT[CS].DPL) pop ESP pop SS</code></pre><h3 id="jmp指令"><a href="#jmp指令" class="headerlink" title="jmp指令"></a>jmp指令</h3><p>假如标签叫做mylabel,它的地址是0x8048377,而且有个全局变量b,b存储的内容就是mylabel的地址,而b的地址是0x80494A8。</p><p>即有这样的赋值(加载)语句:</p><p>movl $mylabel,%eax //把mylabel的地址加载到eax寄存器中</p><p>movl %eax,b //把mylabel的地址加载到b中</p><p>movl $b,%ebx //把b的地址加载到ebx寄存器中</p><p>我们考虑下面的语句:</p><p>1.jmp mylable</p><p>2.jmp 0x8048377</p><p>3.jmp %eax</p><p>4.jmp *%eax</p><p>5.jmp *(%ebx)</p><p>6.jmp *0x80494A8</p><p>7.jmp *b</p><p>8.jmp $0x5</p><p>这8句jmp语句!分别都做了什么?</p><p>1.不用说,跳转到mylabel标签处继续执行代码,但是,是如何跳转的呢?就是PC加上了mylabel标签处对于jmp处的一个偏移地址!可执行的二进制代码是这样表示的:eb 03,就是说,pc+0x03就可以了。</p><p>2.这里,0x8048377是mylabel的地址,我以前研究过,标签的作用,更他的地址的作用是等效的。所以,这里的执行效果跟1中的相同。但是,还有些不一样!这里的二进制代码成了:e9 03 00 00 00 这里用了32位表示了这个偏移,而在1中,只用了8位!</p><p>3.在编译链接的时候,这句代码会有警告:warning:indirect jmp without ‘*‘。间接跳转没有‘*’符号,但是,执行起来,还是没有错。看一下二进制的可执行文件的代码,发现,给补上了个‘*’号!而且二进制是:ff e0.</p><p>4.其实,4是3的补充版,正常的形式就是4,而三是有警告的被补充的版本。</p><p>5.%ebx是b的地址,那么(%ebx)表示ebx的值为地址,指向的地方。这里指向了b的内容,也就是mylabel的地址!于是,化简后,5也就等效与2,但是,二进制表示是:ff 23。</p><p>6.0x80494A8是b的地址,这里看做内存数,那么实质上,b指向的值是mylabel的地址,于是,化简后同2,二进制代码是:ff 25 a8 94 04 08。</p><p>7.b是标签,代表一个地址,所以,这里同6,二进制代码也同6</p><p>8.这句话是错误的,jmp不支持立即数!</p><h3 id="ljmp"><a href="#ljmp" class="headerlink" title="ljmp"></a>ljmp</h3><p>ljmp的含义是长跳,长跳主要就是重新加载寄存器,32位保护模式主要体现在段寄存器,具有可以参考段选择子和段描述符的概念,如果不用长跳的话,那么段寄存器不会重新加载,后面的取指结果仍然是老段寄存器中的值,当然保护模式不会生效了,Intel手册上有讲可见寄存器和不可见寄存器的篇章,可以看一下,其实实模式就是保护模式的一种权限全开放的特殊情况,就是说段寄存器左移相当于右边添加0,而这添加的0可以看做保护模式的RPL,RPL为0代表Intel的0环,当然是全权限了。</p><p>不过Intel的实模式的概念实属不得已而为之,现在的意义已经不大了,从实模式启动然后跳转到保护模式纯粹是在绕圈子,没有实质的意义,商业上为了保护以前的投资不得不将技术做的没有意义的复杂…</p><h3 id="pushf和popf"><a href="#pushf和popf" class="headerlink" title="pushf和popf"></a>pushf和popf</h3><p>pushf 的功能是将标志寄存器的值压栈,而 popf 是从栈中弹出数据,输出标志寄存器的值。</p><p>具体地说</p><p>pushf:指令将标志寄存器的内容压入堆栈,同时栈顶指针SP减2,这条指令可用来保存全部标志位。<br>popf:指令将栈顶字单元内容送标志寄存器,同时栈顶指针SP加2。</p>]]></content>
<summary type="html"><blockquote>
<p>持续更新</p>
<p>lab待更新</p>
</blockquote>
<h2 id="操作系统概论"><a href="#操作系统概论" class="headerlink" title="操作系统概论"></a>操作系统概论</h2><h3 </summary>
<category term="计算机科学基础" scheme="https://hhumar.com/categories/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6%E5%9F%BA%E7%A1%80/"/>
<category term="OS" scheme="https://hhumar.com/tags/OS/"/>
</entry>
<entry>
<title>我最喜欢的“几”款游戏</title>
<link href="https://hhumar.com/2023/01/09/games/"/>
<id>https://hhumar.com/2023/01/09/games/</id>
<published>2023-01-09T03:09:24.000Z</published>
<updated>2023-01-09T04:56:50.709Z</updated>
<content type="html"><![CDATA[<blockquote><p>记录玩过的值得记录的游戏和想玩的游戏,持续更新</p></blockquote><p>写本文之前我在维基百科上查了电子游戏的分类妄图把我玩过的游戏通过传统的分类来按条理记录,但是查过之后才发现其实我玩的大多数游戏都很难被单独归为某一类,比如大多数游戏同时具有角色扮演RPG元素,又具有动作ACT元素,还会结合策略Strategy元素设计关卡,有的又结合射击Shooter元素作为载体。</p><p>所以在这里不严格区分游戏类别,我参考游戏体量分为大型游戏、中型游戏和小型游戏</p><p>注意:游戏体量只是参考标准,<strong>核心</strong>为<strong>个人游戏感受</strong>。</p><h1 id="大型游戏"><a href="#大型游戏" class="headerlink" title="大型游戏"></a>大型游戏</h1><h3 id="巫师3:狂猎"><a href="#巫师3:狂猎" class="headerlink" title="巫师3:狂猎"></a>巫师3:狂猎</h3><h3 id="GTA5"><a href="#GTA5" class="headerlink" title="GTA5"></a>GTA5</h3><h3 id="消逝的光芒"><a href="#消逝的光芒" class="headerlink" title="消逝的光芒"></a>消逝的光芒</h3><h3 id="消逝的光芒2:人与仁之战"><a href="#消逝的光芒2:人与仁之战" class="headerlink" title="消逝的光芒2:人与仁之战"></a>消逝的光芒2:人与仁之战</h3><h3 id="荒野大镖客2"><a href="#荒野大镖客2" class="headerlink" title="荒野大镖客2"></a>荒野大镖客2</h3><p>Read Dead Redemption 2</p><h3 id="孤岛惊魂3"><a href="#孤岛惊魂3" class="headerlink" title="孤岛惊魂3"></a>孤岛惊魂3</h3><h3 id="正当防卫3"><a href="#正当防卫3" class="headerlink" title="正当防卫3"></a>正当防卫3</h3><h3 id="正当防卫4"><a href="#正当防卫4" class="headerlink" title="正当防卫4"></a>正当防卫4</h3><h3 id="古墓丽影"><a href="#古墓丽影" class="headerlink" title="古墓丽影"></a>古墓丽影</h3><h3 id="文明6"><a href="#文明6" class="headerlink" title="文明6"></a>文明6</h3><h3 id="我的世界"><a href="#我的世界" class="headerlink" title="我的世界"></a>我的世界</h3><p>Minecraft</p><h3 id="泰拉瑞亚"><a href="#泰拉瑞亚" class="headerlink" title="泰拉瑞亚"></a>泰拉瑞亚</h3><p>Terraria</p><h3 id="杀手3"><a href="#杀手3" class="headerlink" title="杀手3"></a>杀手3</h3><h3 id="只狼"><a href="#只狼" class="headerlink" title="只狼"></a>只狼</h3><h3 id="星露谷物语"><a href="#星露谷物语" class="headerlink" title="星露谷物语"></a>星露谷物语</h3><h3 id="英灵神殿"><a href="#英灵神殿" class="headerlink" title="英灵神殿"></a>英灵神殿</h3><h3 id="彩虹六号"><a href="#彩虹六号" class="headerlink" title="彩虹六号"></a>彩虹六号</h3><p>Tom Clancy’s Rainbow Six Siege</p><h3 id="Ready-or-Not"><a href="#Ready-or-Not" class="headerlink" title="Ready or Not"></a>Ready or Not</h3><h3 id="命运2"><a href="#命运2" class="headerlink" title="命运2"></a>命运2</h3><h3 id="泰坦陨落2"><a href="#泰坦陨落2" class="headerlink" title="泰坦陨落2"></a>泰坦陨落2</h3><p>Titanfall 2</p><h3 id="GTFO"><a href="#GTFO" class="headerlink" title="GTFO"></a>GTFO</h3><h3 id="极乐迪斯科"><a href="#极乐迪斯科" class="headerlink" title="极乐迪斯科"></a>极乐迪斯科</h3><p>Disco Elysium</p><h3 id="死亡搁浅"><a href="#死亡搁浅" class="headerlink" title="死亡搁浅"></a>死亡搁浅</h3><p>Death Stranding</p><h3 id="茶杯头"><a href="#茶杯头" class="headerlink" title="茶杯头"></a>茶杯头</h3><p>Cuphead</p><h3 id="双人成行"><a href="#双人成行" class="headerlink" title="双人成行"></a>双人成行</h3><p>It Takes Two</p><h3 id="PUBG"><a href="#PUBG" class="headerlink" title="PUBG"></a>PUBG</h3><h3 id="APEX"><a href="#APEX" class="headerlink" title="APEX"></a>APEX</h3><h3 id="CSGO"><a href="#CSGO" class="headerlink" title="CSGO"></a>CSGO</h3><h3 id="英雄联盟"><a href="#英雄联盟" class="headerlink" title="英雄联盟"></a>英雄联盟</h3><p>League of Legends</p><h3 id="控制"><a href="#控制" class="headerlink" title="控制"></a>控制</h3><p>Control</p><h3 id="战地1"><a href="#战地1" class="headerlink" title="战地1"></a>战地1</h3><h3 id="战地5"><a href="#战地5" class="headerlink" title="战地5"></a>战地5</h3><h3 id="艾尔登法环"><a href="#艾尔登法环" class="headerlink" title="艾尔登法环"></a>艾尔登法环</h3><p>Elder Ring</p><h3 id="僵尸毁灭工程"><a href="#僵尸毁灭工程" class="headerlink" title="僵尸毁灭工程"></a>僵尸毁灭工程</h3><h1 id="中型游戏"><a href="#中型游戏" class="headerlink" title="中型游戏"></a>中型游戏</h1><h3 id="妖精股份有限公司"><a href="#妖精股份有限公司" class="headerlink" title="妖精股份有限公司"></a>妖精股份有限公司</h3><p>Gremlins, Inc.</p><h3 id="Northgard"><a href="#Northgard" class="headerlink" title="Northgard"></a>Northgard</h3><h3 id="森林"><a href="#森林" class="headerlink" title="森林"></a>森林</h3><p>The Forest</p><h3 id="绿色地狱"><a href="#绿色地狱" class="headerlink" title="绿色地狱"></a>绿色地狱</h3><p>Green Hell</p><h3 id="木筏求生"><a href="#木筏求生" class="headerlink" title="木筏求生"></a>木筏求生</h3><p>Raft</p><h3 id="饥荒"><a href="#饥荒" class="headerlink" title="饥荒"></a>饥荒</h3><h3 id="师父"><a href="#师父" class="headerlink" title="师父"></a>师父</h3><p>SIFU</p><h3 id="橡胶强盗"><a href="#橡胶强盗" class="headerlink" title="橡胶强盗"></a>橡胶强盗</h3><p>Rubber Bandits</p><h3 id="客死文兰"><a href="#客死文兰" class="headerlink" title="客死文兰"></a>客死文兰</h3><p>Dead In Vinland</p><h3 id="这是我的战争"><a href="#这是我的战争" class="headerlink" title="这是我的战争"></a>这是我的战争</h3><p>This War of Mine</p><h3 id="缺氧"><a href="#缺氧" class="headerlink" title="缺氧"></a>缺氧</h3><h3 id="揍击排队"><a href="#揍击排队" class="headerlink" title="揍击排队"></a>揍击排队</h3><p>Pummel Party</p><h3 id="糖豆人"><a href="#糖豆人" class="headerlink" title="糖豆人"></a>糖豆人</h3><h3 id="undertale"><a href="#undertale" class="headerlink" title="undertale"></a>undertale</h3><h3 id="传送门2"><a href="#传送门2" class="headerlink" title="传送门2"></a>传送门2</h3><p>Portal2</p><h3 id="装机模拟器"><a href="#装机模拟器" class="headerlink" title="装机模拟器"></a>装机模拟器</h3><h3 id="奥日与黑暗森林"><a href="#奥日与黑暗森林" class="headerlink" title="奥日与黑暗森林"></a>奥日与黑暗森林</h3><p>Ori and the Blind Forest</p><h3 id="奥日与萤火意志"><a href="#奥日与萤火意志" class="headerlink" title="奥日与萤火意志"></a>奥日与萤火意志</h3><p>Ori and the Will of the Wisps</p><h3 id="模拟人生4"><a href="#模拟人生4" class="headerlink" title="模拟人生4"></a>模拟人生4</h3><p>The Sims4</p><h3 id="只只大冒险"><a href="#只只大冒险" class="headerlink" title="只只大冒险"></a>只只大冒险</h3><h3 id="人类一败涂地"><a href="#人类一败涂地" class="headerlink" title="人类一败涂地"></a>人类一败涂地</h3><h1 id="小型游戏"><a href="#小型游戏" class="headerlink" title="小型游戏"></a>小型游戏</h1><h3 id="幸运房东"><a href="#幸运房东" class="headerlink" title="幸运房东"></a>幸运房东</h3><h3 id="吸血鬼幸存者"><a href="#吸血鬼幸存者" class="headerlink" title="吸血鬼幸存者"></a>吸血鬼幸存者</h3><p>Vampire Survivors</p><h3 id="雀魂麻将"><a href="#雀魂麻将" class="headerlink" title="雀魂麻将"></a>雀魂麻将</h3><h3 id="鹅鸭杀"><a href="#鹅鸭杀" class="headerlink" title="鹅鸭杀"></a>鹅鸭杀</h3><h3 id="ALTF4"><a href="#ALTF4" class="headerlink" title="ALTF4"></a>ALTF4</h3><h3 id="Helltaker"><a href="#Helltaker" class="headerlink" title="Helltaker"></a>Helltaker</h3><h3 id="Poly-Bridge"><a href="#Poly-Bridge" class="headerlink" title="Poly Bridge"></a>Poly Bridge</h3><h3 id="Poly-Bridge2"><a href="#Poly-Bridge2" class="headerlink" title="Poly Bridge2"></a>Poly Bridge2</h3><h3 id="拣爱"><a href="#拣爱" class="headerlink" title="拣爱"></a>拣爱</h3><p>LoveChoice</p><h3 id="Notia"><a href="#Notia" class="headerlink" title="Notia"></a>Notia</h3>]]></content>
<summary type="html"><blockquote>
<p>记录玩过的值得记录的游戏和想玩的游戏,持续更新</p>
</blockquote>
<p>写本文之前我在维基百科上查了电子游戏的分类妄图把我玩过的游戏通过传统的分类来按条理记录,但是查过之后才发现其实我玩的大多数游戏都很难被单独归为某一类,比如大多</summary>
<category term="游戏" scheme="https://hhumar.com/categories/%E6%B8%B8%E6%88%8F/"/>
<category term="Games" scheme="https://hhumar.com/tags/Games/"/>
</entry>
<entry>
<title>新冠感染记录</title>
<link href="https://hhumar.com/2023/01/07/covid/"/>
<id>https://hhumar.com/2023/01/07/covid/</id>
<published>2023-01-07T13:20:58.000Z</published>
<updated>2023-01-09T03:10:40.500Z</updated>
<content type="html"><![CDATA[<p>2022.12.21日感染新冠至今已痊愈,特此记录感染历程,希望能帮助到有需要的人。</p><h2 id="记录新冠历程"><a href="#记录新冠历程" class="headerlink" title="记录新冠历程"></a>记录新冠历程</h2><p>12.18一回家发现老妈在发烧,老爸说自己膝盖疼,把带回来的两个抗原给爸妈一测,两个阳性。还好带回来了几包999感冒灵和6粒布洛芬。第二天早上早起去几个药房买了一点感冒中成药,2瓶枇杷露(庆幸还买得到),含对乙酰氨基酚的退烧药一盒,几瓶酒精消毒液。回来看成分知道了原来999感冒冲剂也有对乙酰氨基酚退烧成分。</p><p>12.21晚 感觉怕冷,测了个抗原,阳了,然后开始发烧,晚十点左右烧到38.7,吃了一颗布洛芬之后继续烧了两小时,出了一身汗迷迷糊糊睡着了。</p><p>12.22上午没烧,浑身无力,头晕,鼻塞咳嗽,下午继续发烧,吃了布洛芬然后退烧。晚上睡觉没发烧。</p><p>12.23早6:30烧醒,吃了布洛芬,9:00出汗退烧,咳嗽,鼻塞,浑身无力但稍微好了一点。晚上18:15开始怕冷,而后复烧。到晚十点左右烧到39.2,吃布洛芬,继续烧到00:00,出了一身汗退烧,但头还是发热,浑身无力睡不着至凌晨3:00,睡着。</p><p>12.24,头晕头痛,腰背痛(症状较轻),低烧(低于38),咳嗽鼻塞流涕。</p><p>12.25-1.1,一直咳嗽,鼻塞,有乳白色痰,偶尔有黄色痰,而后渐渐恢复</p><p>1.2喝酒(四瓶啤酒)复咳一天</p><p>至整理记录今日1.7喉咙偶尔感觉有痰但不再咳嗽</p><h2 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h2><p>我在重庆郊县,估计感染的是奥密克戎B.5系毒株,目前又有XBB.1.5系等开始传播,症状尚不详,但综合目前已存在的感染症状,发烧几乎是肯定的,然后是浑身疼痛、浑身无力等,也有的有腹泻呕吐症状,建议家中常备退烧药、电解质饮品、止咳药、止泻药等,有条件可以备测血氧的机器(我没有),血氧低于95%、高烧不退、胸闷气短呼吸困难一定要及时就医。</p><p>没感染的注意运动和补充维生素,不熬夜保持充足睡眠,保持高水平免疫力;感染的同样注意休息,饮食清淡,不要剧烈运动,稳步恢复。</p>]]></content>
<summary type="html"><p>2022.12.21日感染新冠至今已痊愈,特此记录感染历程,希望能帮助到有需要的人。</p>
<h2 id="记录新冠历程"><a href="#记录新冠历程" class="headerlink" title="记录新冠历程"></a>记录新冠历程</h2><p>12.1</summary>
<category term="生活" scheme="https://hhumar.com/categories/%E7%94%9F%E6%B4%BB/"/>
<category term="COVID-19" scheme="https://hhumar.com/tags/COVID-19/"/>
</entry>
<entry>
<title>问题解决</title>
<link href="https://hhumar.com/2022/12/07/problems-solved/"/>
<id>https://hhumar.com/2022/12/07/problems-solved/</id>
<published>2022-12-07T15:49:03.000Z</published>
<updated>2022-12-17T09:46:48.303Z</updated>
<content type="html"><</code></pre><p><img src="/2022/12/07/problems-solved/1235684-20190306202339677-1771970027.png" alt="img"></p><ul><li>Markdown格式下</li><li>路径是相对路径,不能是绝对路径。</li><li>不能改变图形大小</li></ul><p><strong>方法2:</strong></p><pre class="language-none"><code class="language-none">from IPython.display import ImageImage(filename = 'G:/workspace/test/python.jpg', width=100, height=60)</code></pre><p><img src="/2022/12/07/problems-solved/1235684-20190306201733054-1744296739.png" alt="img"></p><p> <strong>方法3:</strong></p><pre class="language-none"><code class="language-none">%%html<img src='python.jpg', width=100, height=60></code></pre><p><img src="/2022/12/07/problems-solved/1235684-20190306202346747-1429605491.png" alt="img"></p><ul><li>路径是相对路径,不能是绝对路径。</li><li>可改变图形大小。</li></ul><p><strong>注意事项:</strong></p><ol><li>网络图片:</li></ol><pre class="language-none"><code class="language-none"></code></pre><p>本地图片(与jupyter文件在同一目录):</p><pre class="language-none"><code class="language-none"> </code></pre><ol start="2"><li><p>前面有”!”符号,无论windows还是linux图片路径都是正斜杠”/“</p></li><li><p>方法3对应的是code模式,图片可以居中</p></li><li><p>调整图片百分比的方法:</p></li></ol><pre class="language-none"><code class="language-none"><img src="python.jpg" width="40%"></code></pre><h2 id="8-Ubuntu设置代理"><a href="#8-Ubuntu设置代理" class="headerlink" title="8.Ubuntu设置代理"></a>8.Ubuntu设置代理</h2><p>原文链接:<a href="https://blog.csdn.net/qq_36383272/article/details/116307665">https://blog.csdn.net/qq_36383272/article/details/116307665</a></p><h3 id="1、虚拟机设置代理"><a href="#1、虚拟机设置代理" class="headerlink" title="1、虚拟机设置代理"></a>1、虚拟机设置代理</h3><p>打开<a href="https://so.csdn.net/so/search?q=Ubuntu&spm=1001.2101.3001.7020">Ubuntu</a>的设置,并点击Network->Network Proxy选择Manual,并填写代理地址。<br><img src="/2022/12/07/problems-solved/20210430175107459.png" alt="在这里插入图片描述"><br><img src="/2022/12/07/problems-solved/20210430175200850.png" alt="在这里插入图片描述"><br>其中ip可以直接在主机上查看。要用<a href="https://so.csdn.net/so/search?q=VMware&spm=1001.2101.3001.7020">VMware</a>那个IP。<br><img src="/2022/12/07/problems-solved/2021043017530624.png" alt="在这里插入图片描述"></p><h3 id="2、VMware设置"><a href="#2、VMware设置" class="headerlink" title="2、VMware设置"></a>2、VMware设置</h3><p>点击虚拟机->设置->硬件->网络适配器->NAT模式<br><img src="/2022/12/07/problems-solved/20210430175546968.png" alt="在这里插入图片描述"></p><p>然后就可以google了。<br><img src="/2022/12/07/problems-solved/20210430175453148.png" alt="在这里插入图片描述"></p><h3 id="3-git设置代理"><a href="#3-git设置代理" class="headerlink" title="3 git设置代理"></a>3 git设置代理</h3><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token function">git</span> config <span class="token parameter variable">--global</span> http.proxy http://192.168.80.1:1080<span class="token function">git</span> config <span class="token parameter variable">--global</span> https.proxy https://192.168.80.1:1080<span class="token number">12</span></code></pre><p>地址就是你主机上的地址和代理端口。</p><h2 id="9-文件夹无法拖动"><a href="#9-文件夹无法拖动" class="headerlink" title="9.文件夹无法拖动"></a>9.文件夹无法拖动</h2><p><a href="https://answers.microsoft.com/zh-hans/windows/forum/all/%E6%A1%8C%E9%9D%A2%E5%9B%BE%E6%A0%87%E4%B8%8D/8c5d4036-eb5d-4a0c-bf21-e2b31d7ca85f">https://answers.microsoft.com/zh-hans/windows/forum/all/%E6%A1%8C%E9%9D%A2%E5%9B%BE%E6%A0%87%E4%B8%8D/8c5d4036-eb5d-4a0c-bf21-e2b31d7ca85f</a></p><p>两个方法:</p><p>1.长按键盘左上角 Esc键几秒后松开即可。(适用)</p><p>2.开始-运行-gpedit.msc—— 用户配置——管理摸板——windows组件——任务计划程序——禁止拖和放,可以设置启用或禁——重启电脑(一定要重启才能生效),重启后拖放的问题即可解决。</p><h2 id="end-tag"><a href="#end-tag" class="headerlink" title="end tag"></a>end tag</h2>]]></content>
<summary type="html"><blockquote>
<p>持续更新</p>
</blockquote>
<blockquote>
<p>此文章解决方法大部分来源于网络,之后会尽量附上原文链接,如有侵权可发邮件至 <a href="mailto:&#116;&#119;&#111;&#x62;&#x69;&</summary>
<category term="生活" scheme="https://hhumar.com/categories/%E7%94%9F%E6%B4%BB/"/>
<category term="problems" scheme="https://hhumar.com/tags/problems/"/>
</entry>
<entry>
<title>计算机系统基础</title>
<link href="https://hhumar.com/2022/12/04/computer-system/"/>
<id>https://hhumar.com/2022/12/04/computer-system/</id>
<published>2022-12-04T15:43:42.000Z</published>
<updated>2022-12-07T15:57:20.174Z</updated>
<content type="html"><![CDATA[<blockquote><p>持续更新</p></blockquote><h3 id=""><a href="#" class="headerlink" title=""></a></h3><h2 id="计算机系统漫游"><a href="#计算机系统漫游" class="headerlink" title="计算机系统漫游"></a>计算机系统漫游</h2><p>信息就是位+上下文,编译系统如何工作:编译系统包括预处理器(<code>cpp</code>,根据库文件修改源代码,文件后缀为.i)、编译器(ccl,翻译为汇编语言文件.s)、汇编器(as将汇编语言翻译成机器语言指令,打包为可重定位目标程序并保存在.o文件中,是二进制文件)和链接器(<code>ld</code>负责处理函数<code>.o</code>文件的合并,得到可执行文件) </p><p>处理器读并解释储存在内存中的指令:总线(传送定长字节块,也叫字/word,字长为4字节即为32位,8字节即为64位),I/O设备(通过控制器或适配器与I/O总线相连),主存(一组动态随机存储器DRAM芯片组成),中央处理单元(处理器-是解释或执行存储在主存中指令的引擎,CPU,核心为一个字大小的寄存器,称为程序计数器PC,PC始终指向主存中的某条机器语言指令,处理器按照指令执行模型执行PC指向的指令,模型由<strong>指令集架</strong>构决定);直接存储技术(DMA)可以使数据不通过存储器直接从磁盘到主存</p><p>高速缓存至关重要:主存空间大速度慢,处理器空间小速度快,高速缓存存储器(cache memory);L1高速缓存和寄存器差不多一样快,L2通过特殊总线连接到处理器,慢5倍,甚至还有L3,它们是通过静态随机访问存储器/SRAM的硬件技术实现的。系统可以获得很大存储器的同时获得很快的访问速度,利用高速缓存的<u>局部性原理</u>(程序具有访问局部区域里的数据和代码的趋势)</p><p>存储设备形成层次结构:从上至下速度越慢,每字节造价越低,容量越大——寄存器,L1L2L3,主存,本地二级存储,远程二级存储。基本思想是上一层作为下一层的高速缓存</p><p>操作系统管理硬件:操作系统有两个基本功能-防止硬件被失控的应用程序滥用,想应用程序提供简单一致的机制来控制复杂而又通常大不相同的低级硬件设备。通过一些抽象概念来实现这些功能-<em>进程、虚拟内存和文件</em>,文件是对I/O设备抽象,虚拟内存是对主存和磁盘I/O设备的抽象,进程是对处理器、主存和I/O设备的抽象进程是操作系统对正在运行的程序的抽象,并发运行是指一个进程的指令和另一个进程的指令是交错执行的-上下文切换可以认为进程是由执行单元-线程组成的虚拟内存,虚拟地址空间由准确定义的区构成,每个区有专门的功能(程序代码和数据,堆,共享库,栈,内核虚拟内存)文件</p><p>系统之间利用网络通信</p><p>重要主题:Amdahl定律-想要显著加速整个系统需要加速整个系统中占比大的部分的速度并发/concurrency和并行/parallelism:并发指一个同时具有多个活动的系统。并行指用并发让系统运行得更快(线程级并发,超线程/同时多线程允许一个CPU执行多个控制流 指令级并行,流水线/pipelining,超标量处理器每时钟周期处理命令数大于1单指令、多数据并行/SIMD并行)抽象</p><h2 id="数据的机器级表示和处理"><a href="#数据的机器级表示和处理" class="headerlink" title="数据的机器级表示和处理"></a>数据的机器级表示和处理</h2><p>信息存储(十六进制表示、字数据大小、寻址和字节顺序):0x开始表示十六进制;小端法(little endian)和大端法(big endian)指存储数据时将数据从高位到低位指为最高有效位到最低有效位,若位数为8倍数时可以分组为字节存储,于是变成最高有效位字节和最低有效位字节,存储时从最低往最高存储则为小端法,从高往低则为大端法。Android和IOS以及大多数Intel兼容机是小端</p><pre class="language-c" data-language="c"><code class="language-c">cpu<span class="token punctuation">.</span>eflags<span class="token punctuation">.</span>CF<span class="token operator">=</span><span class="token function">sign</span><span class="token punctuation">(</span>dest<span class="token punctuation">)</span><span class="token punctuation">;</span>res <span class="token operator">=</span> dest<span class="token punctuation">;</span><span class="token keyword">if</span><span class="token punctuation">(</span>src<span class="token operator">></span><span class="token number">31</span><span class="token punctuation">)</span> src<span class="token operator">=</span>src<span class="token operator">%</span><span class="token number">32</span><span class="token punctuation">;</span><span class="token keyword">while</span><span class="token punctuation">(</span>src<span class="token operator">!=</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">{</span> cpu<span class="token punctuation">.</span>eflags<span class="token punctuation">.</span>CF<span class="token operator">=</span><span class="token function">sign</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span><span class="token punctuation">;</span> res <span class="token operator">=</span> dest <span class="token operator">*</span> <span class="token number">2</span><span class="token punctuation">;</span> src<span class="token operator">--</span><span class="token punctuation">;</span><span class="token punctuation">}</span>cpu<span class="token punctuation">.</span>eflags<span class="token punctuation">.</span>CF<span class="token operator">=</span><span class="token function">sign</span><span class="token punctuation">(</span>src<span class="token punctuation">)</span><span class="token punctuation">;</span>res <span class="token operator">=</span> src <span class="token punctuation">;</span><span class="token keyword">if</span><span class="token punctuation">(</span>dest<span class="token operator">></span><span class="token number">31</span><span class="token punctuation">)</span> dest<span class="token operator">=</span>dest<span class="token operator">%</span><span class="token number">32</span><span class="token punctuation">;</span><span class="token keyword">while</span><span class="token punctuation">(</span>dest<span class="token operator">!=</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">{</span> cpu<span class="token punctuation">.</span>eflags<span class="token punctuation">.</span>CF<span class="token operator">=</span><span class="token function">sign</span><span class="token punctuation">(</span>src<span class="token punctuation">)</span><span class="token punctuation">;</span> res <span class="token operator">=</span> src <span class="token operator">*</span> <span class="token number">2</span><span class="token punctuation">;</span> dest<span class="token operator">--</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><h2 id="程序的转换和机器级表示…"><a href="#程序的转换和机器级表示…" class="headerlink" title="程序的转换和机器级表示…"></a>程序的转换和机器级表示…</h2><p>pa2数据对齐方式,不同数据类型存储位置必须是其长度的倍数,Windows中严格按照次标准,Linux中宽松一些,double和指针等都是4的倍数</p><pre class="language-none"><code class="language-none">long>=int16位机long为4字节,int为2字节,32位机long仍为4字节,int也为4字节,64位机int为4字节,long为8字节,而除指针类型外其它类型数据长度不因环境而改变长度</code></pre><h2 id="程序的链接…"><a href="#程序的链接…" class="headerlink" title="程序的链接…"></a>程序的链接…</h2><p>ld</p><h2 id="程序的执行…"><a href="#程序的执行…" class="headerlink" title="程序的执行…"></a>程序的执行…</h2><h2 id="层次结构存储系统"><a href="#层次结构存储系统" class="headerlink" title="层次结构存储系统"></a>层次结构存储系统</h2><ul><li><p>cache</p><p>SRAM静态随机存取存储器(无需刷新),造价比DRAM高千倍</p></li></ul><h3 id="RAM"><a href="#RAM" class="headerlink" title="RAM"></a>RAM</h3><h4 id="介绍"><a href="#介绍" class="headerlink" title="介绍"></a>介绍</h4><p>RAM,即随机存储器或者易失性存储器,因为断电后就失去保存的数据。</p><p>分为SRAM和DRAM:</p><ul><li>DRAM,即动态随机存储器,一般用于<a href="https://so.csdn.net/so/search?q=%E5%86%85%E5%AD%98&spm=1001.2101.3001.7020">内存</a>,需要不断地刷新电路,否则数据就消失了。</li><li>SRAM,即静态随机存储器,一般用于CPU中的cache(高速缓冲存储器),不需要不停地刷新电路来保存数据。</li></ul><p>特点如下:<br><img src="/2022/12/04/computer-system/ba23c5ed2cd645909f4973aea1261c93.png" alt="在这里插入图片描述"></p><p>下面详细阐述一下区别:</p><h4 id="DRAM和SRAM区别"><a href="#DRAM和SRAM区别" class="headerlink" title="DRAM和SRAM区别"></a>DRAM和SRAM区别</h4><h5 id="1-内部结构不同"><a href="#1-内部结构不同" class="headerlink" title="1. 内部结构不同"></a>1. 内部结构不同</h5><ul><li>SRAM是依靠<strong>触发器存储数据</strong>,每个存储元(存储1bit数据)需要花费<strong>6个晶体管才能存储1 bit</strong> 。所以SRAM的集成度低、占用面积大。</li><li>SRAM在读数据时,就是相当于“查看”寄存器的状态,写数据就是改变寄存器的状态。</li></ul><p>SRAM存储元结构,如下图:<br><img src="/2022/12/04/computer-system/a9136d0957f94b6f93ad90607be111b1.png" alt="在这里插入图片描述"></p><hr><ul><li>DRAM依靠<strong>电容存储</strong>,每个存储元只需要花<strong>1个电容和1个晶体管</strong>。DRAM的数据实际上是存在电容里。但是电容放久了,内部的电容就会越来越少,对外不能形成电位的变化。</li><li>DRAM是通过检测是否有电流来确定存储的数据是1或0,有电流(有电荷存储)时为1,无电流为0。</li></ul><p>DRAM存储元结构,如下图:<br><img src="/computer-system/dc5753f9362141ecad9b81fea817847a.png" alt="在这里插入图片描述"></p><p>注意:</p><p>1.DRAM为什么要不断刷新电路?</p><p>当对DRAM进行读操作的时候需要将电容与外界形成回路,通过检测电流变化判断存储元存储的是1还是0(是1就有电荷流出产生电流,是0则没有)。在进行读操作时,如果原来的数据是1,读完之后电荷顺着电流探测电路流走了,就变成0 了,下次再读的时候就不是原来的数据了。所以在读操作结束后需要刷新电路,重新将数据写回DRAM中。</p><p>此外,电容上的电荷也只能保存2ms左右,所以即便没有发生读写读写操作,也会对DRAM刷新。</p><p>2.多久刷新一次?</p><p>因为,电容上的电荷也只能保存2ms左右,计算机一般每隔2ms也都会进行DRAM刷新。</p><p>3.每次刷新多少存储单元?</p><p>以行为单位,每次刷新一行存储单元。</p><p>4.如何刷新?</p><p>不需要CPU控制,有硬件支持,读出一行的信息后重新写入,占用1个读/写周期。</p><p>5.什么时候刷新?<br><img src="/2022/12/04/computer-system/a151d9cd99084111bb038da3334115dd.png" alt="在这里插入图片描述"></p><h5 id="2-寻址方式不同"><a href="#2-寻址方式不同" class="headerlink" title="2. 寻址方式不同"></a>2. 寻址方式不同</h5><p>SRAM的存取速度很快,但是地址线需要更多,这是因为SRAM和DRAM的寻址方式不同:</p><ul><li>SRAM<strong>同时发送行地址和列地址</strong>,把行地址和列地址拼接起来作为一次读写访问的地址,然后放到地址线上;</li><li>SRAM有可能并没有把行地址和列地址拆分成长度相等的两段,并且行地址线和列地址线都是单独存在;</li><li>DRAM是把行地址和列地址分为长度相等的两段,然后<strong>分两次发送</strong>;</li><li>DRAM可以地址线复用,也就使用同一跟地址线分别发送行地址和列地址,减少了地址线的使用</li></ul><h3 id="ROM"><a href="#ROM" class="headerlink" title="ROM"></a>ROM</h3><p>ROM,即只读存储器或者叫非易失性存储器,因为断电后数据依然能够保存。</p><p>分类如下:<br><img src="/2022/12/04/computer-system/2a1d80c4a7f84c889b33ecdcbb6170bb.png" alt="在这里插入图片描述"></p><h3 id="电可擦除式可编程只读存储器"><a href="#电可擦除式可编程只读存储器" class="headerlink" title="电可擦除式可编程只读存储器"></a>电可擦除式可编程只读存储器</h3><p>EEPROM 是 Electrically Erasable Programmable Read-Only Memory(电可擦除可编程只读存储器)的缩写。您可能想知道,EEPROM 是如何工作的?</p><p>- EEPROM 使用半导体技术存储位,而不是以磁性方式读取和写入信息。</p><p>- EEPROM 不需要任何移动部件,并且像 HDD 存储一样,可以在电源周期中保持其状态。</p><p>- EEPROM 在出现故障前可承受很多次写入周期 — 有些在 10,000 次范围内,有些则高达 1,000,000 次或以上。</p><p>- EEPROM 甚至可以作为现在数据容量为 TB 或以上的 SSD 驱动器中使用的闪存的基础。</p><h4 id="EPROM-vs-EEPROM"><a href="#EPROM-vs-EEPROM" class="headerlink" title="EPROM vs EEPROM"></a>EPROM vs EEPROM</h4><p>从远程无钥匙门禁系统到微控制器板等设备,您都可以找到 EEPROM。虽然 EEPROM 名称中的“电可擦除”部分看起来像是一个空洞的短语,但不要将这种类型的存储器与 “EPROM”混淆,EPROM 是 Erasable Programmable Read-Only Memory(可擦除可编程只读存储器)的缩写。<a href="http://https//www.arrow.com/en/categories/memory/memory-chips/eeprom">EPROM 芯片</a>虽然是非易失性和可重编程的,但需要紫外光来擦除芯片的位。它们还需要电压,而且比我们在对数字电路进行编程时通常看到的电压更高。因此,EPROM 不适合存储会经常更改的信息。</p><h4 id="闪存-vs-SSD"><a href="#闪存-vs-SSD" class="headerlink" title="闪存 vs SSD"></a>闪存 vs SSD</h4><p>闪存是一种专为高速和高存储密度而设计的 EEPROM。因此,<a href="https://www.arrow.com/zh-cn/categories/memory/memory-cards-and-modules/flash-cards">闪存驱动器</a>采用这种技术,就可以在比拇指还小的 U 盘上存储很多千兆字节 (GB) 的数据,这也是它们荣获“拇指驱动器”名称的原因。微型 SD 卡在这种紧凑型设计的基础上更进一步,大概只有缩略图大小,通常可以存储数十甚至数百千兆字节 (GB) 的信息。您可以将更多数据大规模地塞进这种类型的存储器中,也许足以作为计算机的主要存储方式。微型 SD 卡的大小大致相当于一个缩略图,通常可以存储数十甚至数百千兆字节 (GB) 的信息。您可以将更多数据大规模地塞进这种类型的存储器中,也许足以作为计算机的主要存储方式。</p><p>SSD 的使用量已经慢慢赶上了 HDD,尤其是在便携式计算应用中,原因如下:</p><p>1.SSD 驱动器不必旋转到位,这意味着它们可以在几分之一毫秒内随机访问数据。</p><p>2.它们的输入/输出性能水平比 HDD 同类产品高几倍。</p><p>3.由于没有移动部件,能耗更低,可靠性更高,这也是这些驱动器的显著优势。</p><h4 id="EEPROM-和闪存"><a href="#EEPROM-和闪存" class="headerlink" title="EEPROM 和闪存"></a>EEPROM 和闪存</h4><p>flash是用来存储代码的,在运行过程中不能改;EEPROM是用来保存用户数据,运行过程中可以改变,比如一个时钟的闹铃时间初始化设定为12:00,后来在运行中改为6:00,这是保存在EEPROM里,不怕掉电,就算重新上电也不需要重新调整到6:00</p><p>两者都是非易失性存储器<br><strong>FLASH的全称是FLASH EEPROM,但跟常规EEPROM的操作方法不同</strong><br><strong>FLASH和EEPROM的最大区别是FLASH按扇区操作,EEPROM则按字节操作,二者寻址方法不同,存储单元的结构也不同,FLASH的电路结构较简单,同样容量占芯片面积较小,成本自然比EEPROM低,因而适合用作程序存储器,EEPROM则更多的用作非易失的数据存储器。</strong>当然用FLASH做数据存储器也行,但操作比EEPROM麻烦的多,所以更“人性化”的MCU设计会集成FLASH和EEPROM两种非易失性存储器,而廉价型设计往往只有FLASH,早期可电擦写型MCU则都是EEPRM结构,现在已基本上停产了。<br>一般来说eeprom中存放开机是用到的参数,不可丢失的变量等,而FLASH中会存放程序,记录文件等。</p><h3 id="FRAM"><a href="#FRAM" class="headerlink" title="FRAM"></a>FRAM</h3><p>维基百科:<strong>铁电随机存取内存</strong>(Ferroelectric RAM,缩写为FeRAM或FRAM),类似于<a href="https://zh.m.wikipedia.org/wiki/SDRAM">SDRAM</a>,是一种<a href="https://zh.m.wikipedia.org/wiki/%E9%9A%8F%E6%9C%BA%E5%AD%98%E5%8F%96%E5%AD%98%E5%82%A8%E5%99%A8">随机存取存储器</a>技术。但因为它使用了一层有<a href="https://zh.m.wikipedia.org/wiki/%E9%93%81%E7%94%B5%E6%80%A7">铁电性</a>的材料,取代原有的<a href="https://zh.m.wikipedia.org/wiki/%E4%BB%8B%E9%9B%BB%E8%B3%AA">介电质</a>,使得它也拥有<a href="https://zh.m.wikipedia.org/wiki/%E9%9D%9E%E6%8F%AE%E7%99%BC%E6%80%A7%E8%A8%98%E6%86%B6%E9%AB%94">非挥发性内存</a>的功能。<a href="https://zh.m.wikipedia.org/wiki/%E9%BA%BB%E7%9C%81%E7%90%86%E5%B7%A5%E5%A4%A7%E5%AD%A6">麻省理工大学</a><a href="https://zh.m.wikipedia.org/w/index.php?title=%E9%81%94%E5%BE%B7%E5%88%A9%C2%B7%E8%89%BE%E5%80%AB%C2%B7%E5%B7%B4%E5%85%8B&action=edit&redlink=1">达德利·艾伦·巴克</a>(Dudley Allen Buck)在1952年提出的硕士论文中,首次提出了这个概念。它有比<a href="https://zh.m.wikipedia.org/wiki/%E9%97%AA%E5%AD%98">闪存</a>更低的耗电量,还有更高的写入速度,还有更长的读写寿命(大约10¹⁰到10¹⁵次循环,可视作无限寿命)。它在+85℃时可以保存数据十年以上。但是它的缺点是比闪存存储密度低,存储容量限制,和更高的价格。与<a href="https://zh.m.wikipedia.org/wiki/%E5%8A%A8%E6%80%81%E9%9A%8F%E6%9C%BA%E5%AD%98%E5%8F%96%E5%AD%98%E5%82%A8%E5%99%A8">DRAM</a>相比,铁电随机存取器的读操作是破坏性的,因为它需要遵循先写后读架构。</p><p>百度百科:铁电晶体材料的工作原理是: 当我们把电场加载到铁电晶体材料上,晶阵中的中心原子会沿着电场方向运动,到达稳定状态。晶阵中的每个自由浮动的中心原子只有两个稳定状态,一个我们记作逻辑 0,另一个记作逻辑 1。中心原子能在常温﹑没有电场的情况下停留在此状态达一百年以上。 由于在整个物理过程中没有任何原子碰撞,<a href="https://baike.baidu.com/item/%E9%93%81%E7%94%B5%E5%AD%98%E5%82%A8%E5%99%A8/3781126?fromModule=lemma_inlink">铁电存储器</a>(FRAM)拥有高速读写,超低功耗和无限次写入等特性。</p><h2 id="外部I-x2F-O"><a href="#外部I-x2F-O" class="headerlink" title="外部I/O"></a>外部I/O</h2>]]></content>
<summary type="html"><blockquote>
<p>持续更新</p>
</blockquote>
<h3 id=""><a href="#" class="headerlink" title=""></a></h3><h2 id="计算机系统漫游"><a href="#计算机系统漫游" class=</summary>
<category term="计算机科学基础" scheme="https://hhumar.com/categories/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6%E5%9F%BA%E7%A1%80/"/>
<category term="Computer System" scheme="https://hhumar.com/tags/Computer-System/"/>
</entry>
<entry>
<title>GEE开发</title>
<link href="https://hhumar.com/2022/11/29/gee/"/>
<id>https://hhumar.com/2022/11/29/gee/</id>
<published>2022-11-29T04:18:58.000Z</published>
<updated>2022-11-29T07:04:38.603Z</updated>
<content type="html"><![CDATA[<blockquote><p>持续更新</p></blockquote><h3 id=""><a href="#" class="headerlink" title=""></a></h3><h2 id="基础"><a href="#基础" class="headerlink" title="基础"></a>基础</h2><h3 id="初始步骤"><a href="#初始步骤" class="headerlink" title="初始步骤"></a>初始步骤</h3><p>Once Earth Engine is authenticated, you can run the following script to initialize Earth Engine for a new Python session. In general, you will need to initialize Earth Engine for each new Python session, i.e., whenever you open a Jupyter notebook or Python script and want to use Earth Engine. Fortunately, geemap can automatically initialize Earth Engine for you when creating an interactive map, which will be covered in the next chapter. In other words, you rarely need to run ee.Initialize() explicitly.</p><p>开始使用的必须步骤,运行以下代码</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token keyword">import</span> eeee<span class="token punctuation">.</span>Authenticate<span class="token punctuation">(</span><span class="token punctuation">)</span>ee<span class="token punctuation">.</span>Initialize<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token comment"># 当运行以下代码时能正常生成地图则环境配置基本成功</span><span class="token keyword">import</span> geemap<span class="token comment"># 本地运行配置代理端口</span><span class="token comment"># geemap.set_proxy(port='7890')</span>Map<span class="token operator">=</span>geemap<span class="token punctuation">.</span>Map<span class="token punctuation">(</span><span class="token punctuation">)</span>Map</code></pre><h3 id="band-math-or-map-algebra"><a href="#band-math-or-map-algebra" class="headerlink" title="band math or map algebra"></a>band math or map algebra</h3><p>convert an aspect image to radians, then call <code>sin()</code> on it.</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// Load the SRTM image.</span><span class="token keyword">var</span> srtm <span class="token operator">=</span> ee<span class="token punctuation">.</span><span class="token function">Image</span><span class="token punctuation">(</span><span class="token string">'CGIAR/SRTM90_V4'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// Get the aspect (in degrees).</span><span class="token keyword">var</span> aspect <span class="token operator">=</span> ee<span class="token punctuation">.</span>Terrain<span class="token punctuation">.</span><span class="token function">aspect</span><span class="token punctuation">(</span>srtm<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// Convert to radians, compute the sin of the aspect.将 aspect 除以 180,乘以 π,最后取 sin</span><span class="token keyword">var</span> sinImage <span class="token operator">=</span> aspect<span class="token punctuation">.</span><span class="token function">divide</span><span class="token punctuation">(</span><span class="token number">180</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">multiply</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token constant">PI</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">sin</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// Display the result.</span>Map<span class="token punctuation">.</span><span class="token function">addLayer</span><span class="token punctuation">(</span>sinImage<span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token literal-property property">min</span><span class="token operator">:</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token literal-property property">max</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token string">'sin'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>可以手动画 polygon 作为导入变量参与计算。reduceRegion() 方法</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// Compute the mean elevation in the polygon.</span><span class="token keyword">var</span> meanDict <span class="token operator">=</span> srtm<span class="token punctuation">.</span><span class="token function">reduceRegion</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">reducer</span><span class="token operator">:</span> ee<span class="token punctuation">.</span>Reducer<span class="token punctuation">.</span><span class="token function">mean</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token literal-property property">geometry</span><span class="token operator">:</span> polygon<span class="token punctuation">,</span> <span class="token literal-property property">scale</span><span class="token operator">:</span> <span class="token number">90</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// Get the mean from the dictionary and print it.</span><span class="token keyword">var</span> mean <span class="token operator">=</span> meanDict<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'elevation'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token function">print</span><span class="token punctuation">(</span><span class="token string">'Mean elevation'</span><span class="token punctuation">,</span> mean<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>参数:reduceRegion() 是一种可用于 Image 对象的方法(<a href="https://developers.google.com/earth-engine/guides/reducers_reduce_region">learn more about reducing regions here</a>)。其次,方法参数在作为单个参数传递的 JavaScript 对象中提供。 (具体来说,对象的键是方法参数的名称。值是方法的参数)。第三,reducer 参数指定要计算的统计类型,geometry 参数指定计算统计的区域。比例参数是要使用的以米为单位的像素大小。为避免歧义,您在进行缩减时应始终指定比例,因为 Earth Engine 可能无法根据输入自动确定适当的比例(scale)。(<a href="https://developers.google.com/earth-engine/guides/scale">Learn more about scale in Earth Engine</a>)</p><p>返回值:reduceRegion() 的返回值是一个字典,其中键是波段名称,值是波段的像素统计信息。字典上的 get() 方法返回与作为参数提供的键对应的值。在本例中,srtm 图像有一个波段“海拔(elevation)”,因此示例代码从字典中获取该统计数据并打印出来。</p><p>参与计算的区域像元数量超过 maxPixels 时会报错,可以通过在给定参数对象中添加 bestEffort: true 字段或者把 maxPixels 字段值设定为更大的值。</p><h3 id="mosaic"><a href="#mosaic" class="headerlink" title="mosaic"></a>mosaic</h3><p>遥感影像镶嵌,当将一个 image collection 添加到 Map 时会隐式调用 mosaic。</p><p>when you add a collection to the map, Earth Engine implicitly calls <a href="https://developers.google.com/earth-engine/apidocs/ee-imagecollection-mosaic"><code>mosaic()</code></a> on it</p><h3 id="分辨率(scale)"><a href="#分辨率(scale)" class="headerlink" title="分辨率(scale)"></a>分辨率(scale)</h3><p>未主动设置分辨率时,自动为图像原始分辨率,可通过以下查看</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> scale <span class="token operator">=</span> srtm<span class="token punctuation">.</span><span class="token function">projection</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">nominalScale</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token function">print</span><span class="token punctuation">(</span><span class="token string">'SRTM scale in meters'</span><span class="token punctuation">,</span> scale<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>取比原图像分辨率更小的值会自动重采样(happily),更大则尝试从聚合源中获取数据(从图像金字塔数据的更高级别)。Learn more about how Earth Engine handles scale in <a href="https://developers.google.com/earth-engine/guides/scale">this doc</a>.</p><h3 id="reducer"><a href="#reducer" class="headerlink" title="reducer"></a>reducer</h3><p>将 collection 添加到地图时,会默认采用最近的值(selecting the most recent pixel - the one from the latest image in the stack)。使用中值reducer时,可以去除云(具有高值)和阴影(具有低值)</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// Get the median over time, in each band, in each pixel.</span><span class="token keyword">var</span> median <span class="token operator">=</span> l8<span class="token punctuation">.</span><span class="token function">filterDate</span><span class="token punctuation">(</span><span class="token string">'2016-01-01'</span><span class="token punctuation">,</span> <span class="token string">'2016-12-31'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">median</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// Make a handy variable of visualization parameters.</span><span class="token keyword">var</span> visParams <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token literal-property property">bands</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'B4'</span><span class="token punctuation">,</span> <span class="token string">'B3'</span><span class="token punctuation">,</span> <span class="token string">'B2'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token literal-property property">max</span><span class="token operator">:</span> <span class="token number">0.3</span><span class="token punctuation">}</span><span class="token punctuation">;</span><span class="token comment">// Display the median composite.</span>Map<span class="token punctuation">.</span><span class="token function">addLayer</span><span class="token punctuation">(</span>median<span class="token punctuation">,</span> visParams<span class="token punctuation">,</span> <span class="token string">'median'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>masking</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// Load or import the Hansen et al. forest change dataset.</span><span class="token keyword">var</span> hansenImage <span class="token operator">=</span> ee<span class="token punctuation">.</span><span class="token function">Image</span><span class="token punctuation">(</span><span class="token string">'UMD/hansen/global_forest_change_2015'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// Select the land/water mask.</span><span class="token keyword">var</span> datamask <span class="token operator">=</span> hansenImage<span class="token punctuation">.</span><span class="token function">select</span><span class="token punctuation">(</span><span class="token string">'datamask'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// Create a binary mask.</span><span class="token keyword">var</span> mask <span class="token operator">=</span> datamask<span class="token punctuation">.</span><span class="token function">eq</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// Update the composite mask with the water mask.</span><span class="token keyword">var</span> maskedComposite <span class="token operator">=</span> median<span class="token punctuation">.</span><span class="token function">updateMask</span><span class="token punctuation">(</span>mask<span class="token punctuation">)</span><span class="token punctuation">;</span>Map<span class="token punctuation">.</span><span class="token function">addLayer</span><span class="token punctuation">(</span>maskedComposite<span class="token punctuation">,</span> visParams<span class="token punctuation">,</span> <span class="token string">'masked'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>global_forest_change_2015数据中,水体数据值为2,土地为1,no data为0,</p><p>select()选择指定 band</p><p>eq(1)</p><table><thead><tr><th align="left">Usage</th><th align="left">Returns</th></tr></thead><tbody><tr><td align="left"><code>Image.eq(image2)</code></td><td align="left">Image</td></tr></tbody></table><h3 id="注意"><a href="#注意" class="headerlink" title="注意"></a>注意</h3><p>print函数不能一次打印超过 5000 件东西</p><h3 id="JavaScript-API-vs-Python-API"><a href="#JavaScript-API-vs-Python-API" class="headerlink" title="JavaScript API vs. Python API"></a>JavaScript API vs. Python API</h3><p>Earth Engine JavaScript Code Editor<br>● Rich documentation and tutorials<br>● Easy to get started<br>● Built-in interactive mapping functionality<br>● Built-in authentication<br>● Earth Engine Apps<br>● Can’t install additional package</p><p>Earth Engine Python API<br>● Limited documentation and tutorials<br>● Easier language syntax<br>● Easy to share code between scripts<br>● Batch processing (e.g., exporting images)<br>● More IDEs with debugging capability<br>● Numerous Python packages<br>● Many plotting and visualization options<br>● Integration with open-source GIS<br>● Accessing data stored locally<br>● Deep learning</p><h2 id="js-API"><a href="#js-API" class="headerlink" title="js API"></a><code>js API</code></h2><p>好像并不支持es6,那么也没有块作用域,只有函数作用域</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// Instantiate an image with the Image constructor.</span><span class="token comment">// 实例化一个Image对象</span><span class="token keyword">var</span> image <span class="token operator">=</span> ee<span class="token punctuation">.</span><span class="token function">Image</span><span class="token punctuation">(</span><span class="token string">'CGIAR/SRTM90_V4'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// Zoom to a location.</span><span class="token comment">// longitude经度 latitude纬度 放大级别</span>Map<span class="token punctuation">.</span><span class="token function">setCenter</span><span class="token punctuation">(</span><span class="token operator">-</span><span class="token number">112.8598</span><span class="token punctuation">,</span> <span class="token number">36.2841</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Center on the Grand Canyon.</span><span class="token comment">// Display the image on the map.</span>Map<span class="token punctuation">.</span><span class="token function">addLayer</span><span class="token punctuation">(</span>image<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><h3 id="内置对象"><a href="#内置对象" class="headerlink" title="内置对象"></a>内置对象</h3><h4 id="Feature"><a href="#Feature" class="headerlink" title="Feature"></a>Feature</h4><p>A <code>Feature</code> in Earth Engine is defined as a GeoJSON Feature. Specifically, a <code>Feature</code> is an object with a <code>geometry</code> property storing a <code>Geometry</code> object (or null) and a <code>properties</code> property storing a dictionary of other properties.</p><p>两个属性:<code>geometry</code> 储存一个<code>Geometry</code> 对象,<code>properties</code> 储存一个字典-对应其它属性</p><h4 id="Geometry"><a href="#Geometry" class="headerlink" title="Geometry"></a>Geometry</h4><p>& GeometryCollection对象</p><p>没看到对GeometryCollection对象的操作,只有单个Geometry</p><h4 id="Image对象"><a href="#Image对象" class="headerlink" title="Image对象"></a>Image对象</h4><p>Image对象一般含有多个波段(band),每个波段都有其名称、像素值、空间分辨率和投影信息。例如:SRTM 图像有一个波段“海拔(elevation)”。</p><h4 id="Image-Collections"><a href="#Image-Collections" class="headerlink" title="Image Collections"></a>Image Collections</h4><p>一系列image的集合。An image collection refers to a set of Earth Engine images</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> l8 <span class="token operator">=</span> ee<span class="token punctuation">.</span><span class="token function">ImageCollection</span><span class="token punctuation">(</span><span class="token string">'LANDSAT/LC08/C01/T1_TOA'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><h5 id="filter"><a href="#filter" class="headerlink" title="filter"></a>filter</h5><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// 过滤得到与point相交(intersect)的图像</span><span class="token keyword">var</span> spatialFiltered <span class="token operator">=</span> l8<span class="token punctuation">.</span><span class="token function">filterBounds</span><span class="token punctuation">(</span>point<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token function">print</span><span class="token punctuation">(</span><span class="token string">'spatialFiltered'</span><span class="token punctuation">,</span> spatialFiltered<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 添加第二个过滤器以将集合限制为仅包含(acquired) 2015 年获取的图像</span><span class="token keyword">var</span> temporalFiltered <span class="token operator">=</span> spatialFiltered<span class="token punctuation">.</span><span class="token function">filterDate</span><span class="token punctuation">(</span><span class="token string">'2015-01-01'</span><span class="token punctuation">,</span> <span class="token string">'2015-12-31'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token function">print</span><span class="token punctuation">(</span><span class="token string">'temporalFiltered'</span><span class="token punctuation">,</span> temporalFiltered<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p> filterBounds() 的参数是数字化的点,filterDate() 的参数是两个日期,表示为字符串。均为 filter() 方法的快捷方法</p><p>获取单个图像进行分析的另一种更具编程性的方法是对集合进行排序,以获得与某些元数据属性相关的最新、最旧或最佳图像。例如,通过检查打印图像集合中的图像对象,您可能已经观察到一个名为 CLOUD_COVER 的元数据属性。您可以使用该属性在您感兴趣的区域获得 2015 年最少云的图像:</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// This will sort from least to most cloudy.</span><span class="token keyword">var</span> sorted <span class="token operator">=</span> temporalFiltered<span class="token punctuation">.</span><span class="token function">sort</span><span class="token punctuation">(</span><span class="token string">'CLOUD_COVER'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// Get the first (least cloudy) image.</span><span class="token keyword">var</span> scene <span class="token operator">=</span> sorted<span class="token punctuation">.</span><span class="token function">first</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>通过 band 字段指定rgb对应波段</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> visParams <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token literal-property property">bands</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'B4'</span><span class="token punctuation">,</span> <span class="token string">'B3'</span><span class="token punctuation">,</span> <span class="token string">'B2'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token literal-property property">max</span><span class="token operator">:</span> <span class="token number">0.3</span><span class="token punctuation">}</span><span class="token punctuation">;</span>Map<span class="token punctuation">.</span><span class="token function">addLayer</span><span class="token punctuation">(</span>scene<span class="token punctuation">,</span> visParams<span class="token punctuation">,</span> <span class="token string">'true-color composite'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>Displaying image collections,和display image对象类似,每一块显示与当前时间最近的 image</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> l8 <span class="token operator">=</span> ee<span class="token punctuation">.</span><span class="token function">ImageCollection</span><span class="token punctuation">(</span><span class="token string">'LANDSAT/LC08/C01/T1_TOA'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">var</span> landsat2016 <span class="token operator">=</span> l8<span class="token punctuation">.</span><span class="token function">filterDate</span><span class="token punctuation">(</span><span class="token string">'2016-01-01'</span><span class="token punctuation">,</span> <span class="token string">'2016-12-31'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>Map<span class="token punctuation">.</span><span class="token function">addLayer</span><span class="token punctuation">(</span>landsat2016<span class="token punctuation">,</span> visParams<span class="token punctuation">,</span> <span class="token string">'l8 collection'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><h3 id="方法"><a href="#方法" class="headerlink" title="方法"></a>方法</h3><h4 id="Map-addLayer"><a href="#Map-addLayer" class="headerlink" title="Map.addLayer()"></a>Map.addLayer()</h4><p>当您使用 Map.addLayer() 将图像添加到地图时,Earth Engine 需要确定如何将图像波段中的值映射到显示器上的颜色。</p><p>如果将单波段图像添加到地图,默认情况下 Earth Engine 会以灰度显示波段,其中最小值分配给黑色,最大值分配给白色。如果您不指定最小值和最大值,Earth Engine 将使用默认值。例如,您刚刚添加到地图的图像显示为拉伸到数据全范围的灰度图像,或者说带符号的 16 位整数 [-32768, 32767]。 (默认情况下,浮点值波段被拉伸到 [0, 1],8bit值波段被拉伸到 [0, 255])。</p><p>第二个参数 visParams 允许指定要显示的最小值和最大值,是一个对象。第三个参数: the name of the layer that is displayed in the <a href="https://developers.google.com/earth-engine/guides/playground#layer-manager">Layer manager</a>,在图层中显示的名称</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript">Map<span class="token punctuation">.</span><span class="token function">addLayer</span><span class="token punctuation">(</span>image<span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token literal-property property">min</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token literal-property property">max</span><span class="token operator">:</span> <span class="token number">3000</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token string">'custom visualization'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>还可以在对象参数中增加调色板参数</p><p>调色板是一个逗号分隔的颜色字符串列表,这些颜色字符串在可视化参数的最大值和最小值之间线性插值(或根据波段类型的默认值,如前所述)。例如,小于或等于最小值的像素将以列表中的第一种颜色显示;大于或等于最大值的像素将以列表中的最后一种颜色显示。中间颜色被线性拉伸到中间像素值。</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript">Map<span class="token punctuation">.</span><span class="token function">addLayer</span><span class="token punctuation">(</span>image<span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token literal-property property">min</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token literal-property property">max</span><span class="token operator">:</span> <span class="token number">3000</span><span class="token punctuation">,</span> <span class="token literal-property property">palette</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'blue'</span><span class="token punctuation">,</span> <span class="token string">'green'</span><span class="token punctuation">,</span> <span class="token string">'red'</span><span class="token punctuation">]</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token string">'custom palette'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><h4 id="ee-Image-reduceRegion"><a href="#ee-Image-reduceRegion" class="headerlink" title="ee.Image.reduceRegion"></a>ee.Image.reduceRegion</h4><table><thead><tr><th align="left">Usage</th><th align="left">Returns</th></tr></thead><tbody><tr><td align="left"><code>Image.reduceRegion(reducer, geometry, scale,crs, crsTransform, bestEffort, maxPixels, tileScale)</code></td><td align="left">Dictionary</td></tr></tbody></table><h4 id="ee-Terrain-aspect"><a href="#ee-Terrain-aspect" class="headerlink" title="ee.Terrain.aspect"></a>ee.Terrain.aspect</h4><p>从地形 DEM 计算坡向(以度为单位)</p><table><thead><tr><th align="left">Usage</th><th align="left">Returns</th></tr></thead><tbody><tr><td align="left"><code>ee.Terrain.aspect(input)</code></td><td align="left">Image</td></tr></tbody></table><table><thead><tr><th align="left">Argument</th><th align="left">Type</th><th align="left">Details</th></tr></thead><tbody><tr><td align="left"><code>input</code></td><td align="left">Image</td><td align="left">An elevation image, in meters.</td></tr></tbody></table><h4 id="ee-Terrain-slope"><a href="#ee-Terrain-slope" class="headerlink" title="ee.Terrain.slope"></a>ee.Terrain.slope</h4><p>从地形 DEM 计算坡度(以度为单位)</p><p>计算坡度ee.Terrain.slope(input)</p><table><thead><tr><th align="left">Usage</th><th align="left">Returns</th></tr></thead><tbody><tr><td align="left"><code>ee.Terrain.slope(input)</code></td><td align="left">Image</td></tr></tbody></table><table><thead><tr><th align="left">Argument</th><th align="left">Type</th><th align="left">Details</th></tr></thead><tbody><tr><td align="left"><code>input</code></td><td align="left">Image</td><td align="left">An elevation image, in meters.</td></tr></tbody></table><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// Load the SRTM image.</span><span class="token keyword">var</span> srtm <span class="token operator">=</span> ee<span class="token punctuation">.</span><span class="token function">Image</span><span class="token punctuation">(</span><span class="token string">'CGIAR/SRTM90_V4'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// Apply an algorithm to an image.</span><span class="token keyword">var</span> slope <span class="token operator">=</span> ee<span class="token punctuation">.</span>Terrain<span class="token punctuation">.</span><span class="token function">slope</span><span class="token punctuation">(</span>srtm<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// Display the result.</span>Map<span class="token punctuation">.</span><span class="token function">setCenter</span><span class="token punctuation">(</span><span class="token operator">-</span><span class="token number">112.8598</span><span class="token punctuation">,</span> <span class="token number">36.2841</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Center on the Grand Canyon.</span>Map<span class="token punctuation">.</span><span class="token function">addLayer</span><span class="token punctuation">(</span>slope<span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token literal-property property">min</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token literal-property property">max</span> <span class="token operator">:</span><span class="token number">60</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token string">'slope'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><h4 id="print"><a href="#print" class="headerlink" title="print"></a>print</h4><p>在 <strong>Console</strong> tab 打印 image 的元数据信息</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token function">print</span><span class="token punctuation">(</span><span class="token string">'SRTM image'</span><span class="token punctuation">,</span> image<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><h2 id="python-API"><a href="#python-API" class="headerlink" title="python API"></a><code>python API</code></h2><h3 id="colab"><a href="#colab" class="headerlink" title="colab"></a>colab</h3><p>初始操作</p><pre class="language-none"><code class="language-none">pip install geemap</code></pre><p>After geemap has been installed successfully, click the <strong>RESTART RUNTIME</strong> button appearing at the end of the installation log or click on the menu <strong>Runtime > Restart runtime</strong>. Then type the following code in a new cell:</p><pre class="language-none"><code class="language-none">import geemapMap = geemap.Map()Map</code></pre><h3 id="方法-1"><a href="#方法-1" class="headerlink" title="方法"></a>方法</h3><p>geojson转入gee中,转换为FeatureCollection </p><pre class="language-python" data-language="python"><code class="language-python">in_geojson <span class="token operator">=</span> <span class="token punctuation">(</span> <span class="token string">'https://github.com/giswqs/geemap/blob/master/examples/data/countries.geojson'</span><span class="token punctuation">)</span>Map <span class="token operator">=</span> geemap<span class="token punctuation">.</span>Map<span class="token punctuation">(</span><span class="token punctuation">)</span>fc <span class="token operator">=</span> geemap<span class="token punctuation">.</span>geojson_to_ee<span class="token punctuation">(</span>in_geojson<span class="token punctuation">)</span>Map<span class="token punctuation">.</span>addLayer<span class="token punctuation">(</span>fc<span class="token punctuation">.</span>style<span class="token punctuation">(</span><span class="token operator">**</span><span class="token punctuation">{</span><span class="token string">'color'</span><span class="token punctuation">:</span> <span class="token string">'ff0000'</span><span class="token punctuation">,</span> <span class="token string">'fillColor'</span><span class="token punctuation">:</span> <span class="token string">'00000000'</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token string">'Countries'</span><span class="token punctuation">)</span>Map</code></pre><p>url</p><pre class="language-python" data-language="python"><code class="language-python">url <span class="token operator">=</span> <span class="token string">"https://github.com/giswqs/geemap/blob/master/examples/data/countries.zip"</span>geemap<span class="token punctuation">.</span>download_file<span class="token punctuation">(</span>url<span class="token punctuation">)</span></code></pre><p>shp</p><pre class="language-python" data-language="python"><code class="language-python">in_shp <span class="token operator">=</span> <span class="token string">"countries.shp"</span>fc <span class="token operator">=</span> geemap<span class="token punctuation">.</span>shp_to_ee<span class="token punctuation">(</span>in_shp<span class="token punctuation">)</span></code></pre><p>csv</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token keyword">import</span> geopandas <span class="token keyword">as</span> gpdgdf <span class="token operator">=</span> gpd<span class="token punctuation">.</span>read_file<span class="token punctuation">(</span>in_shp<span class="token punctuation">)</span>fc <span class="token operator">=</span> geemap<span class="token punctuation">.</span>gdf_to_ee<span class="token punctuation">(</span>gdf<span class="token punctuation">)</span></code></pre><p>vector</p><pre class="language-python" data-language="python"><code class="language-python">fc <span class="token operator">=</span> geemap<span class="token punctuation">.</span>vector_to_ee<span class="token punctuation">(</span>url<span class="token punctuation">)</span></code></pre>]]></content>
<summary type="html"><blockquote>
<p>持续更新</p>
</blockquote>
<h3 id=""><a href="#" class="headerlink" title=""></a></h3><h2 id="基础"><a href="#基础" class="headerlin</summary>
<category term="GIS" scheme="https://hhumar.com/categories/GIS/"/>
<category term="GIS" scheme="https://hhumar.com/tags/GIS/"/>
<category term="Web" scheme="https://hhumar.com/tags/Web/"/>
<category term="Google Earth Engine" scheme="https://hhumar.com/tags/Google-Earth-Engine/"/>
</entry>
<entry>
<title>Computer Network</title>
<link href="https://hhumar.com/2022/11/07/computer-net/"/>
<id>https://hhumar.com/2022/11/07/computer-net/</id>
<published>2022-11-06T16:40:02.000Z</published>
<updated>2023-02-17T09:43:00.056Z</updated>
<content type="html"><![CDATA[<blockquote><p>持续更新</p></blockquote><p>主要是计算机网络自顶向下方法第七版部分笔记和一些拓展,这位网友的笔记很棒</p><p><a href="https://liuyijian.github.io/vuepressBlog/techNote/basic/network/">https://liuyijian.github.io/vuepressBlog/techNote/basic/network/</a></p><h2 id="计算机网络和因特网概述"><a href="#计算机网络和因特网概述" class="headerlink" title="计算机网络和因特网概述"></a>计算机网络和因特网概述</h2><p>什么是因特网(具体构成和描述、服务描述、协议):端系统通过通信链路(communication link)和分组交换机(packet switch)连接;链路传输速率单位bit/s,端系统间发送信息时发送<strong>分组</strong>(packet),分组交换机最著名的有路由器(router)和链路层交换机(link-layer switch),从发送端系统到接收端系统,一个分组所经历的一系列通信链路和分组交换机称为通过该网络的路径(route/path)。分组交换是存储转发的过程。</p><p>统计多路复用是特殊的时分复用,不固定分配某个时间片给某个用户。分组交换又分为数据报文和虚电路;前者每个数据包都含有完整目标地址,直接发送不建立连接,而虚电路会先走一遍到目标,让报文中携带路径虚电路号而非目标地址。</p><p>RTT(Round-Trip Time)往返时间表示从发送端发送数据开始,到发送端收到来自接收端的确认(接收端收到数据后便立即发送确认,不包含数据传输时间)总共经历的时间。 RTT由三个部分决定:链路的传播时间、末端系统的处理时间、路由器的缓存中的排队和处理时间。</p><p>有连接(虚电路,体现在线路上每一个节点),面向连接(TCP 体现在起点和终点),无连接(数据报文)</p><p>ISP是由多个分组交换机和多段通信链路组成的网络。</p><p>协议(protocol)控制信息的接受和发送,TCP(Transmission Control Protocol,)/IP(Internet Protocol,定义端系统和路由器之间发送和接收的分组格式)协议是最重要的两个。因特网标准(Internet standard)由因特网工程任务组[IETE-Internet Engineering Task Force]研发,IEFC的标准文档称为RFC(Request For Comment)。API(Application Programming Interface,应用程序编程接口)</p><p>协议,网络协议(协议定义了在两个或多个通信实体之间交换的报文格式和次序,以及报文发送和/或接受一条报文或其他事件所采取的动作)</p><p><strong>分布式应用程序</strong>(distributed application)涉及多台相互交换数据的端系统,<strong>基础设施</strong>是应用层之下为分布式应用程序提供服务的网络部分。</p><p>整个互联网包括网络核心、网络边缘和接入网/物理媒体:</p><p>网络核心 core 由大量路由器和网络链路组成,负责数据交换和路由</p><p>网络边缘 edge 包括主机和应用程序(client and server)</p><p>接入网、物理媒体 access 是把网络边缘接入网络核心的有线或无限通信链路</p><p>网络边缘(接入网,物理媒体):物联网-万物互联,端系统又称为主机,可分为client/server,大部分服务器属于data center;access network接入网指将端系统连接到器边缘路由器(edge router)的物理链路,有:</p><p><strong>家庭接入</strong>(<u>DSL数字用户线</u>和<u>电缆</u>最为流行,前者中DSL调制解调器将数字数据转换为高频音通过电话线传输给本地中心局/CO,CO中的数字用户线接入复用器/DSLAM将模拟信号转换回数字形式,分频器分离数据信号和电话信号-频分复用技术;电缆因特网接入,混合光纤同轴/HFC,电缆调制解调器/cable modem,电缆调制解调器端接系统/CMTS;光纤到户/FTTH,有主动光纤网络/<code>AON</code>和被动<code>PON</code>,<code>PON</code>包括<u>光纤网络端接器ONT</u>,连接到分配器splitter,集结光纤之后连接到中心局的<u>光纤线路端接器OLT</u>-提供光信号和电信号的转换,其中分组/packet在分配器处复制,在家庭中先通过路由器连接<code>ONT</code>;还有卫星链路和传统电话线拨号接入,速度慢)</p><p><strong>公司/企业接入</strong>(以太网和<code>WiFi</code>)和广域移动无线(3G、4G、LTE)物理媒体分为导引型媒体(固体媒体如电缆光缆)和非导引型媒体(空气和外层空间,在无线局域网和数字卫星频道),<strong>双绞铜线</strong>-无屏蔽双绞线/UTP常用在建筑物内的计算机网络中/LAN、<strong>同轴电缆</strong>-是两个同心铜导体能被用作导引型共享媒体、<strong>光纤</strong>-导引光脉冲、<strong>陆地无线电信道</strong>、<strong>卫星无线电信道</strong>-同步卫星和近地轨道卫星</p><p>网络核心(分组交换):分组交换-存储转发传输、排队时延和分组丢失</p><p>基础设施提供的网络服务可分为面向连接的服务(TCP服务),无连接服务(UDP服务)</p><p>缓冲区管理和拥塞控制</p><p>多路复用:频分复用、时分复用、波分复用</p><p>不同的分层模型:</p><p>OSI 7层网络模型</p><p>互联网五层参考模型</p><p>计算速率进制为十进制,也就是说1KB=1000B,便于计算</p><h2 id="应用层"><a href="#应用层" class="headerlink" title="应用层"></a>应用层</h2><h3 id="HTTP"><a href="#HTTP" class="headerlink" title="HTTP"></a>HTTP</h3><ul><li>200(OK)- 如果现有资源已被更改</li><li>201(created)- 如果新资源被创建</li><li>202(accepted)- 已接受处理请求但尚未完成(异步处理)</li><li>301(Moved Permanently)- 资源的URI被更新</li><li>303(See Other)- 其他(如,负载均衡)</li><li>400(bad request)- 指代坏请求</li><li>403()- 禁止访问</li><li>404 (not found)- 资源不存在</li><li>406 (not acceptable)- 服务端不支持所需表示</li><li>409 (conflict)- 通用冲突</li><li>412 (Precondition Failed)- 前置条件失败(如执行条件更新时的冲突)</li><li>415 (unsupported media type)- 接受到的表示不受支持</li><li>500 (internal server error)- 通用错误响应</li><li>503 (Service Unavailable)- 服务当前无法处理请求</li></ul><p><img src="/computer-net/HTTP%E5%93%8D%E5%BA%94%E7%8A%B6%E6%80%81%E7%A0%81-1676626958249.jpg" alt="HTTP响应状态码"></p><pre class="language-none"><code class="language-none">GET /cs453/index.html HTTP/1.1<cr><lf>Host: gaia.cs.umass.edu<cr><lf>User-Agent: Mozilla/5.0 (Windows ; U; Windows NT5.1;en-US;rv:1.7.2) Geeko/20040804 Netscape/7.2(ax)<cr><lf>Accept: ex/xml application/xml, applicaion/xhtml+xml text/html ; q=0.9, text./plain;q=0 . 8 , image/png, */* ; q=0 . 5 <cr><lf>Accep-Language en-us, en;q=O.S<cr><lf>AcceptEncoding: zip deflate<cr><lf>Accept-Charset : ISO-8859-1 , utf-8 ; q=0 . 7,* ;q=0 . 7<cr><1f>Keep-Alive:300<cr><lf>Connection: keep-alive<cr><l f><cr><l f></code></pre><h3 id="流水线和长连接"><a href="#流水线和长连接" class="headerlink" title="流水线和长连接"></a>流水线和长连接</h3><p>http 1.1 </p><p>有两个新的模型在 HTTP/1.1 诞生了。首先是长连接模型,它会保持连接去完成多次连续的请求,减少了不断重新打开连接的时间。然后是 HTTP 流水线模型,它还要更先进一些,多个连续的请求甚至都不用等待立即返回就可以被发送,这样就减少了耗费在网络延迟上的时间。</p><h3 id="DNS"><a href="#DNS" class="headerlink" title="DNS"></a>DNS</h3><p>Domain Name System:注册域名的权威服务器的名字记录为ns类型在COM服务器中,然后再将该权威服务器的ip以A类型记录存在COM服务器中,包括以下部件:</p><ul><li>通过DNS服务器组建出的分布式数据库<ul><li>DNS服务器通常是Unix系统上运行Berkley Internet Name Domain(BIND)软件</li><li>DNS服务器有3种类型<ul><li>根DNS服务器:有13个不同的根DNS服务器,但有多于1000个副本分布在世界各地,提供顶级域DNS服务器的IP地址</li><li>顶级域DNS服务器:负责顶级域名,国家域名的维护(如com, org, net, edu, gov等等),提供权威DNS服务器的IP地址</li><li>权威DNS服务器:维护具体网站的DNS记录</li></ul></li></ul></li><li>允许用户访问分布式数据库的应用层协议<ul><li>DNS协议在UDP上运行,默认端口为53</li></ul></li></ul><p>递归查询或者迭代查询:递归查询的请求和响应对象逐层递进,在local server到root server,root server到TLD server,TLD server到 Authoritative server途中,找到即递归返回;迭代查询则由local server分别向后三者依次询问,每次必定会得到找到或者找不到的返回。</p><ul><li><p>DNS服务器存储了资源记录,提供了主机名到IP地址的映射,每个DNS回答报文包含一条或多条资源记录</p></li><li><p>资源记录是一个四元组(Name,Value,Type,TTL)</p><ul><li>TTL:记录的生存时间,决定何时从缓存中删除此记录</li><li>Type:<ul><li>A:Name是主机名,Value是IP地址</li><li>NS:Name是个域,Value是知道如何获取该域中主机IP地址的权威DNS服务器的主机名</li><li>CNAME:Name是主机名,Value是别名为Name的规范主机名</li><li>MX:Name是主机名,Value是别名为Name的邮件服务器的规范主机名</li></ul></li></ul></li><li><p>DNS报文:查询报文和回答报文具有相同的格式</p><ul><li>首部区域(前12字节)<ul><li>Identification:2字节的标识符,会被复制到对查询的回答报文中,以便客户匹配请求和应答</li><li>Flags:<ul><li>1比特的报文类型标志位,查询是0,回答是1</li><li>1比特的权威标志位:若该服务器是权威DNS服务器,则该位为1</li><li>1比特的希望递归标志位:若希望DNS服务器进行递归查询,则该位为1</li></ul></li><li>Numbers<ul><li>指出首部后的4类数据区域出现的数量</li></ul></li></ul></li><li>问题区域:包含名字字段(正在被查询的主机名字),类型字段(如主机地址是与一个名字关联还是与某个邮件服务器关联)</li><li>回答区域:若干条四元组形式的资源记录</li><li>权威区域:包含其他权威服务器的记录</li><li>附加区域:包含其他有帮助的记录</li></ul></li></ul><h3 id="CDN加速"><a href="#CDN加速" class="headerlink" title="CDN加速"></a>CDN加速</h3><p>Content Distribution Network:内容提供商将内容提前上载到CDN服务商的服务器中,用户在访问内容提供商的前端网页时,点击视频链接,会通过域名解析系统(见上文)访问到内容提供商的权威DNS服务器,然后得到其提供的另一个域名-即CDN提供商的权威DNS服务器,该DNS服务器提供 CDN簇选择策略,将早在CDN上载好的 content 的IP地址返回给 local DNS server,然后返回到用户端,用户与其直接建立连接,访问 content 。此时访问到的内容所在的服务器与客户最近,用户还能通过 DASH-动态、自适应流 over HTTP 协议切换视频码率。</p><h3 id="TCP-x2F-UDP套接字编程"><a href="#TCP-x2F-UDP套接字编程" class="headerlink" title="TCP/UDP套接字编程"></a>TCP/UDP套接字编程</h3><p>python3</p><p>TCP</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token operator">//</span>server<span class="token keyword">from</span> socket <span class="token keyword">import</span> <span class="token operator">*</span>serverPort <span class="token operator">=</span> <span class="token number">12000</span>serverSocket <span class="token operator">=</span> socket<span class="token punctuation">(</span>AF_INET<span class="token punctuation">,</span> SOCK_STREAM<span class="token punctuation">)</span><span class="token operator">//</span>SOCK_STREAMserverSocket<span class="token punctuation">.</span>bind<span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">,</span> serverPort<span class="token punctuation">)</span><span class="token punctuation">)</span>serverSocket<span class="token punctuation">.</span>listen<span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">'The Server is ready to receive'</span><span class="token punctuation">)</span><span class="token keyword">while</span> <span class="token boolean">True</span><span class="token punctuation">:</span>connectionSocket<span class="token punctuation">,</span> addr <span class="token operator">=</span> serverSocket<span class="token punctuation">.</span>accept<span class="token punctuation">(</span><span class="token punctuation">)</span> sentence <span class="token operator">=</span> connectionSocket<span class="token punctuation">.</span>recv<span class="token punctuation">(</span><span class="token number">1024</span><span class="token punctuation">)</span><span class="token punctuation">.</span>decode<span class="token punctuation">(</span><span class="token punctuation">)</span> capitalizedSentence <span class="token operator">=</span> sentence<span class="token punctuation">.</span>upper<span class="token punctuation">(</span><span class="token punctuation">)</span> connectionSocket<span class="token punctuation">.</span>send<span class="token punctuation">(</span>capitalizedSentence<span class="token punctuation">.</span>encode<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> connectionSocket<span class="token punctuation">.</span>close<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">//</span>client<span class="token keyword">from</span> socket <span class="token keyword">import</span> <span class="token operator">*</span>serverName <span class="token operator">=</span> <span class="token string">'servername'</span>serverPort <span class="token operator">=</span> <span class="token number">12000</span>clientSocket <span class="token operator">=</span> socket<span class="token punctuation">(</span>AF_INET<span class="token punctuation">,</span> SOCK_STREAM<span class="token punctuation">)</span><span class="token operator">//</span>SOCK_STREAMclientSocket<span class="token punctuation">.</span>connect<span class="token punctuation">(</span><span class="token punctuation">(</span>serverName<span class="token punctuation">,</span> serverPort<span class="token punctuation">)</span><span class="token punctuation">)</span>sentence <span class="token operator">=</span> <span class="token builtin">input</span><span class="token punctuation">(</span><span class="token string">'Input lowercase sentence: '</span><span class="token punctuation">)</span>clientSocket<span class="token punctuation">.</span>send<span class="token punctuation">(</span>sentence<span class="token punctuation">.</span>encode<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>modifiedSentencce <span class="token operator">=</span> clientSocket<span class="token punctuation">.</span>recv<span class="token punctuation">(</span><span class="token number">1024</span><span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">'From Server: '</span><span class="token punctuation">,</span> modifiedSentence<span class="token punctuation">.</span>decode<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>clientSocket<span class="token punctuation">.</span>close<span class="token punctuation">(</span><span class="token punctuation">)</span></code></pre><p>UDP</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token operator">//</span>server<span class="token keyword">from</span> socket <span class="token keyword">import</span> <span class="token operator">*</span>serverPort <span class="token operator">=</span> <span class="token number">12000</span>serverSocket <span class="token operator">=</span> socket<span class="token punctuation">(</span>AF_INET<span class="token punctuation">,</span> SOCK_DGRAM<span class="token punctuation">)</span><span class="token operator">//</span>SOCK_DGRAMserverSocket<span class="token punctuation">.</span>bind<span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">,</span> serverPort<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">'The Server is ready to receive'</span><span class="token punctuation">)</span><span class="token keyword">while</span> <span class="token boolean">True</span><span class="token punctuation">:</span>message<span class="token punctuation">,</span> clientAddress <span class="token operator">=</span> serverSocket<span class="token punctuation">.</span>recvfrom<span class="token punctuation">(</span><span class="token number">2048</span><span class="token punctuation">)</span> modifiedMessage <span class="token operator">=</span> message<span class="token punctuation">.</span>decode<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>upper<span class="token punctuation">(</span><span class="token punctuation">)</span> serverSocket<span class="token punctuation">.</span>sendto<span class="token punctuation">(</span>modifiedMessage<span class="token punctuation">.</span>encode<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> clientAddress<span class="token punctuation">)</span> <span class="token operator">//</span>client<span class="token keyword">from</span> socket <span class="token keyword">import</span> <span class="token operator">*</span>serverName <span class="token operator">=</span> <span class="token string">'hostname'</span>serverPort <span class="token operator">=</span> <span class="token string">'12000'</span>clientSocket <span class="token operator">=</span> socket<span class="token punctuation">(</span>AF_INET<span class="token punctuation">,</span> SOCK_DGRAM<span class="token punctuation">)</span><span class="token operator">//</span>SOCK_DGRAMmessage <span class="token operator">=</span> <span class="token builtin">input</span><span class="token punctuation">(</span><span class="token string">'Input lowercase sentence:'</span><span class="token punctuation">)</span>clientSocket<span class="token punctuation">.</span>sendto<span class="token punctuation">(</span>message<span class="token punctuation">.</span>decode<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>serverName<span class="token punctuation">,</span> serverPort<span class="token punctuation">)</span><span class="token punctuation">)</span>moodifiedMessage<span class="token punctuation">,</span> serverAddress <span class="token operator">=</span> clientSocket<span class="token punctuation">.</span>recvfrom<span class="token punctuation">(</span><span class="token number">2048</span><span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span>modifiedMessage<span class="token punctuation">.</span>decode<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>clientSocket<span class="token punctuation">.</span>close<span class="token punctuation">(</span><span class="token punctuation">)</span></code></pre><p>listen函数</p><pre class="language-none"><code class="language-none">#include<sys/socket.h>int listen ( int sockfd, int backlog )返回: 0──成功, - 1──失败sockfd:backlog:队列等待长度上限</code></pre><p>listen函数使用主动连接套接口变为被连接套接口,使得一个进程可以接受其它进程的请求,从而成为一个服务器进程。在TCP服务器编程中listen函数把进程变为一个服务器,并指定相应的<a href="https://so.csdn.net/so/search?q=%E5%A5%97%E6%8E%A5%E5%AD%97&spm=1001.2101.3001.7020">套接字</a>变为被动连接。</p><p>nmap工具能做端口扫描,针对不同服务返回打开/关闭/不可达的端口列表</p><h2 id="传输层"><a href="#传输层" class="headerlink" title="传输层"></a>传输层</h2><h3 id="复用、解复用"><a href="#复用、解复用" class="headerlink" title="复用、解复用"></a>复用、解复用</h3><h3 id="UDP"><a href="#UDP" class="headerlink" title="UDP"></a>UDP</h3><p>校验和:“回卷”规则的引入,使得“先求反再求和”与“先求和再求反”所得结果一致。回卷指溢出位加回低位直至无溢出。</p><h3 id="TCP"><a href="#TCP" class="headerlink" title="TCP"></a>TCP</h3><p><strong>异步传输模式</strong>(英语:Asynchronous Transfer Mode,ATM),又叫<a href="https://zh.wikipedia.org/w/index.php?title=%E4%BF%A1%E5%85%83%E4%B8%AD%E7%BB%A7&action=edit&redlink=1">信元中继</a>。ATM采用<a href="https://zh.wikipedia.org/wiki/%E7%94%B5%E8%B7%AF%E4%BA%A4%E6%8D%A2">电路交换</a>的方式,它以<a href="https://zh.wikipedia.org/w/index.php?title=%E4%BF%A1%E5%85%83&action=edit&redlink=1">信元</a>(cell)为单位。每个信元长53<a href="https://zh.wikipedia.org/wiki/%E5%AD%97%E8%8A%82">字节</a>,其中报头占了5字节。</p><p>ATM能够比较理想地实现各种<a href="https://zh.wikipedia.org/wiki/QoS">QoS</a>,既能够支持有连接的业务,又能支持无连接的业务。是<a href="https://zh.wikipedia.org/w/index.php?title=%E5%AE%BD%E5%B8%A6ISDN&action=edit&redlink=1">宽带ISDN</a>(<a href="https://zh.wikipedia.org/w/index.php?title=B-ISDN&action=edit&redlink=1">B-ISDN</a>)技术的典范。ATM为一种交换技术,在发送资料时,先将数字资料切割成多个固定长度的数据包,之后利用光纤或DS1/DS3发送。到达目的地后,再重新组合。ATM网络可同时将声音、影像及资料集成在一起。针对各种信息类型,提供最佳的传输环境。</p><h4 id="TCP加速"><a href="#TCP加速" class="headerlink" title="TCP加速"></a>TCP加速</h4><p>单边加速-大多数情况打破互联网公平(例:取消慢启动,直接以窗口速率发送)和双边加速-双边加速器</p><p>透明代理+算法,透明代理用TCP加速器,加速器之间用其它协议例如SCTP</p><h2 id="网络层"><a href="#网络层" class="headerlink" title="网络层"></a>网络层</h2><p>网络层有四个协议:ARP协议,IP协议,ICMP协议,IGMP协议。ARP协议为IP协议提供服务,IP协议为ICMP协议提供服务,ICMP协议为IGMP协议提供服务。</p><h3 id="数据平面"><a href="#数据平面" class="headerlink" title="数据平面"></a>数据平面</h3><p>北向接口:提供给其他厂家或运营商进行接入和管理的接口,即向上提供的接口。</p><p>如网管提供三种北向接口,分别为CORBA(Common Object Request Broker</p><p>Architecture)、SNMP、Syslog北向接口。它们负责向上级网管系统提供基于CORBA、SNMP和Syslog协议的北向接口,支持上级网管系统通过对应的协议接入网管。</p><p>南向接口:管理其他厂家网管或设备的接口,即向下提供的接口。</p><p>SDN控制器对网络的控制主要是通过南向接口协议实现,包括链路发现、拓扑管理、策略制定、表项下发等,其中链路发现和拓扑管理主要是控制其利用南 向接口的上行通道对底层交换设备上报信息进行统一监控和统计;而策略制定和表项下发则是控制器利用南向接口的下行通道对网络设备进行统一控制。</p><p>SDN北向接口是通过控制器向上层业务应用开放的接口,其目标是使得业务应用能够便利地调用底层的网络资源和能力。通过北向接口,网络业务的开发者 能以软件编程的形式调用各种网络资源;同时上层的网络资源管理系统可以通过控制器的北向接口全局把控整个网网络的资源状态,并对资源进行统一调度。因为北 向接口是直接为业务应用服务的,因此其设计需要密切联系业务应用需求,具有多样化的特征。同时,北向接口的设计是否合理、便捷,以便能被业务应用广泛调 用,会直接影响到SDN控制器厂商的市场前景。</p><p>(Northbound/Southbound Interface, 网络拓扑图越往下层级越低, 地图约定俗成上北下南)</p><h4 id="NAT(内网)穿透"><a href="#NAT(内网)穿透" class="headerlink" title="NAT(内网)穿透"></a>NAT(内网)穿透</h4><p>tailscale,zerotier tailscale</p><h3 id="控制平面"><a href="#控制平面" class="headerlink" title="控制平面"></a>控制平面</h3><h4 id="IGP"><a href="#IGP" class="headerlink" title="IGP"></a>IGP</h4><p>Interior Gateway Protocol</p><p>内部</p><ul><li><p>OSPF 开放最短路优先:<a href="https://www.cnblogs.com/cone/p/14933527.html">https://www.cnblogs.com/cone/p/14933527.html</a></p><pre class="language-none"><code class="language-none">WIKI**开放式最短路径优先**(英语:Open Shortest Path First,缩写为 OSPF)是广泛使用的一种路由协议,它属于链路状态路由协议,具有路由变化收敛速度快、无路由环路、支持变长子网掩码(VLSM)和汇总、层次区域划分等优点。OSPF是一种基于[IP协议](https://zh.wikipedia.org/wiki/IP协议)的[路由协议](https://zh.wikipedia.org/wiki/路由协议)。它是大中型网络上使用较为广泛的[IGP](https://zh.wikipedia.org/wiki/内部网关协议)协议。OSPF是对[链路状态路由协议](https://zh.wikipedia.org/w/index.php?title=链路状态路由协议&action=edit&redlink=1)的一种实现,运作于[自治系统](https://zh.wikipedia.org/wiki/自治系统)内部。OSPF分为OSPFv2和OSPFv3两个版本:OSPFv2定义于[RFC 2328](https://tools.ietf.org/html/rfc2328)(1998),支持[IPv4](https://zh.wikipedia.org/wiki/IPv4)网络;而OSPFv3定义于[RFC 5340](https://tools.ietf.org/html/rfc5340)(2008),支持[IPv6](https://zh.wikipedia.org/wiki/IPv6)网络。它采用[戴克斯特拉算法](https://zh.wikipedia.org/wiki/戴克斯特拉算法)来计算[最短路径树](https://zh.wikipedia.org/wiki/最短路径树)。它使用“代价(Cost)”作为路由度量。链路状态数据库(LSDB)用来保存当前[网络拓扑](https://zh.wikipedia.org/wiki/网络拓扑)结构,[路由器](https://zh.wikipedia.org/wiki/路由器)上属于同一区域的链路状态数据库是相同的(属于多个区域的路由器会为每个区域维护一份链路状态数据库)。OSPF提出了“区域(Area)”的概念,一个网络可以由单一区域或者多个区域组成。其中,一个特别的区域被称为骨干区域(Backbone Area),该区域是整个OSPF网络的核心区域,并且所有其他的区域都与之直接连接。所有的内部路由都通过骨干区域传递到其他非骨干区域。所有的区域都必须直接连接到骨干区域,如果不能创建直接连接,那么可以通过[虚链路](https://zh.wikipedia.org/w/index.php?title=虚链路&action=edit&redlink=1)(virtual link)和骨干区域创建[虚拟连接](https://zh.wikipedia.org/w/index.php?title=虚拟连接&action=edit&redlink=1)。同一个[广播域](https://zh.wikipedia.org/wiki/广播域)(Broadcast Domain)的[路由器](https://zh.wikipedia.org/wiki/路由器)或者一个[点对点](https://zh.wikipedia.org/wiki/点对点)(Point To Point)连接的两端的路由器,在发现彼此的时候,创建邻接(Adjacencies)[[注 1\]](https://zh.wikipedia.org/wiki/开放式最短路径优先#cite_note-1)。多路访问网络以及非广播多路访问网络的路由器会选举指定路由器(Designated Router, DR)和备份指定路由器(Backup Designated Router, BDR),DR和BDR作为网络的中心负责路由器之间的信息交换从而降低了网络中的信息流量。OSPF协议同时使用[单播](https://zh.wikipedia.org/wiki/單播)(Unicast)和[组播](https://zh.wikipedia.org/wiki/組播)(Multicast)来发送[Hello包](https://zh.wikipedia.org/w/index.php?title=Hello包&action=edit&redlink=1)和链路状态更新(Link State Updates),使用的组播[地址](https://zh.wikipedia.org/wiki/IP地址)为224.0.0.5和224.0.0.6。与[RIP](https://zh.wikipedia.org/wiki/路由信息协议)和[BGP](https://zh.wikipedia.org/wiki/BGP)不同的是,OSPF协议不使用TCP或者UDP协议而是直接承载在IP协议之上,[IP协议号](https://zh.wikipedia.org/wiki/IP协议号列表)为89。</code></pre></li><li><p>RIP协议,<a href="https://so.csdn.net/so/search?q=RIP&spm=1001.2101.3001.7020">RIP</a>(Routing information Protocol) 是比较古老的动态路由协议,是一种基于距离矢量算法来计算到达目的网络的最佳路径路由协议,RIP报文承载于UDP报文,使用UDP端口520,属于应用层协议。在<a href="https://so.csdn.net/so/search?q=RIP%E5%8D%8F%E8%AE%AE&spm=1001.2101.3001.7020">RIP协议</a>中,路由根据到达目的地的跳数作为路由选择的度量值。<img src="/computer-net/9d3a7f41220246bd98b4acc79650155d-1676626958249.png" alt="img"></p></li><li><p>IS-IS:IS-IS(Intermediate System-to-Intermediate System,中间系统到中间系统)路由协议最初是ISO(the International Organization for Standardization,国际标准化组织)为CLNP(Connection Less Network Protocol,无连接网络协议)设计的一种动态路由协议。现在CLNP网络已经基本不再别使用,但是IS-IS协议由于其优秀性,被保留了下来。</p><p>为了提供对IP路由的支持,通过对IS-IS进行扩充和修改,使IS-IS能够同时应用在TCP/IP和OSI环境中,形成了集成化IS-IS(Integrated IS-IS或Dual IS-IS)。现在提到的IS-IS协议都是指集成化的IS-IS协议,主要用于城域网和承载网。</p><p><a href="https://blog.csdn.net/qq_46254436/article/details/104844159%EF%BC%88%E5%B7%B2%E5%BD%92%E6%A1%A3%E8%87%B3%E8%AF%AD%E9%9B%80%EF%BC%89">https://blog.csdn.net/qq_46254436/article/details/104844159(已归档至语雀)</a></p></li></ul><h4 id="BGP"><a href="#BGP" class="headerlink" title="BGP"></a>BGP</h4><p> <em>BGP</em>(Border GatewayProtocol)是一种在自治系统之间动态交换路由信息的路由协议。</p><h2 id="链路层"><a href="#链路层" class="headerlink" title="链路层"></a>链路层</h2><h3 id="错误检测和纠正"><a href="#错误检测和纠正" class="headerlink" title="错误检测和纠正"></a>错误检测和纠正</h3><p>三种方法</p><h4 id="奇偶校验"><a href="#奇偶校验" class="headerlink" title="奇偶校验"></a>奇偶校验</h4><p>二维奇偶校验</p><h4 id="检验和"><a href="#检验和" class="headerlink" title="检验和"></a>检验和</h4><h4 id="循环冗余检测"><a href="#循环冗余检测" class="headerlink" title="循环冗余检测"></a>循环冗余检测</h4><h3 id="多路访问协议"><a href="#多路访问协议" class="headerlink" title="多路访问协议"></a>多路访问协议</h3><p>三种</p><h4 id="信道划分协议"><a href="#信道划分协议" class="headerlink" title="信道划分协议"></a>信道划分协议</h4><p>时分复用,频分复用,码分多址</p><h4 id="随机接入协议"><a href="#随机接入协议" class="headerlink" title="随机接入协议"></a>随机接入协议</h4><p>Slotted ALOHA</p><p>ALOHA</p><p>CSMA (carrier sense multiple access)载波侦听多路访问</p><p>CSMA/CD(collision detection) 带碰撞检测的CSMA</p><p>CSMA/CA(collision avoid) 带碰撞避免的CSMA</p><h4 id="轮流协议"><a href="#轮流协议" class="headerlink" title="轮流协议"></a>轮流协议</h4><p>polling protocol 轮询协议</p><p>token-passing protocol 令牌传递协议</p><p>例子:DOCSIS</p><h3 id="交换局域网"><a href="#交换局域网" class="headerlink" title="交换局域网"></a>交换局域网</h3><h4 id="ARP协议"><a href="#ARP协议" class="headerlink" title="ARP协议"></a>ARP协议</h4><p>1.ARP(Address Resolution Protocol,地址解析协议):是将ip 地址解析成以太⽹MAC地的协议</p><p>2.ARP 是⼀个独⽴的三层协议,所以ARP 报⽂在向数据链路层传输时不需要经过ip协议的封装,直接⽣成⾃⼰的报⽂。</p><p><img src="/computer-net/image-20230109224420053-1676626958250.png" alt="ARP报⽂"></p><p>硬件类型:占2字节,表⽰ARP 报⽂可以在哪种类型的⽹络上传输,值为1时表⽰以太⽹地址</p><p>上层协议类型: 占2个字节,表⽰硬件地址映射的协议地址类型,映射ip地址时的值为0x0800</p><p>MAC地址长度:占1个字节,表⽰MAC地址长度,以字节为单位,此处为6</p><p>IP协议地址长度:占1个字节,表⽰ip地址长度,以字节为单位,此处为4</p><p>操作类型:占2字节,指定本次ARP报⽂类型,1为ARP请求报⽂,2为ARP应答报⽂</p><p>源MAC地址:占6个字节,发送⽅的硬件地址</p><p>源IP地址:占4个字节</p><p>⽬的MAC“地址:占6个字节,表⽰接收⽅的硬件地址,</p><p>⽬的IP地址:占4个字节</p><p>3.ARP帧</p><p><img src="/computer-net/image-20230109224439780-1676626958250.png" alt="ARP帧"></p><p>⽬的MAC地址:占6个字节,如果时ARP 请求帧,要填上⼴播MAC地址 ff-ff-ff-ff ,其⽬标时⽹络上的主机。</p><p>源MAC地址:占6个字节</p><p>帧类型:占2个字节,表⽰帧封装的上层协议,因为本帧的数据部分是ARP报⽂,直接⽤0x0806(arp协议号)表⽰</p><p>4.ARP映射表</p><p>(1)动态arp 表项:通过ARP报⽂⾃动⽣成和维护</p><p>(2)静态ARP表项:⼿⼯配置(对应设备的ip地址和mac地址绑定)</p><p>静态ARP 表项分为:</p><p>1.长静态ARP表项:同时绑定IP地址、MAC地址、VLAN和端⼝</p><p>2.短静态ARP表项:只配置IP地址和mac</p><h3 id="链路虚拟化"><a href="#链路虚拟化" class="headerlink" title="链路虚拟化"></a>链路虚拟化</h3><p>a network as a link layer</p><h4 id="多协议标签交换"><a href="#多协议标签交换" class="headerlink" title="多协议标签交换"></a>多协议标签交换</h4><p>MPLS</p><p>MPLS signaling,信令</p><pre class="language-none"><code class="language-none">RSVP-TE:基于流量工程扩展的资源预留协议(RSVP-TE:Resource ReSerVation Protocol-Traffic Engineering)基于流量工程扩展的资源预留协议(RSVP-TE)作为 RSVP 协议的一个补充协议,用于为 MPLS 网络建立标签交换路径。这个 RSVP 扩展协议主要用于在有或者没有资源预留的情况下支持明确传送 LSP(中文名为分层服务提供程序。 LSP就是TCP/IP等协议的接口.LSP用在正途上可以方便程序员们编写监视系统网络通讯情况的Sniffer,可是现在常见的LSP都被用于浏览器劫持) 的实例。同时它也支持 LSP 的平滑重新路由、优先权及环路监测。RSVP 协议定义的会话指有明确目的地址及传输层协议的数据流。但当 RSVP 与 MPLS 相结合时,流或者会话的定义具有较大的灵活性和一般性。 LSP 的入口结点使用许多方法来决定给一些数据包分配一个特定的标签。一旦某个标签被分配给一组包,这个标签将会有效地定义通过 LSP 的流。我们将这样的 LSP 看作 LSP 隧道,是因为通过它的流量对沿着标签交换路径的中间结点是不透明的。新的 RSVP 会话、发送方及过滤器说明对象,被称之为 LSP 隧道 IPv4 和 LSP 隧道 IPv6 ,已被用来支持 LSP 隧道特征。从标签交换路径结点的角度来看,这些对象语义上是指基于包独立识别的 LSP 隧道流量,其中这些包是从具有上流发送方结点分配的特定标签值的 PHOP 到会话获取的。事实上,出现在对象名字中的 IPv4 (v6)只表示目的地址是一个 IPv4 (IPv6)地址。一般情况下,当涉及到这些对象时,需要用到限定词“ LSP 隧道”。在某些应用程序中,连接 LSP 隧道组是很有用的,诸如,在重新路由操作期间或者传播流量在复合路径上时,这样的集合被称为 TE 隧道。为了能够鉴定和连接 LSP 隧道,需要携带两个标识符。隧道 ID 是会话对象的一部分,会话对象唯一地定义了一个流量工程隧道。发送方和过滤器说明对象携带一个 LSP ID,发送方(或者过滤器说明)对象结合会话对象唯一定义一个 LSP 隧道。摘自通信人https://baike.c114.com.cn/view.asp?word=RSVP-TE</code></pre><hr><p>路由器转发规则(做题的时候模糊了)</p><ol><li><p>源主机在发起通信之前,将Self IP与目的主机的IP进行比较,如果两者位于同一网段(用子网掩码计算后具有相同的网络号),那么源主机直接向目的主机发送ARP请求,在接收到目的主机的ARP应答后获取对方的MAC地址,然后用对方的MAC地址作为目的MAC进行报文发送,位于同一VLAN(网段)的主机互访时属于这种情况,这是互联的交换机做二层交换转发。</p></li><li><p>当源主机判断目的主机与自己位于不同网段时,它会通过网关来提交报文,即发送ARP请求来获取网关IP地址对应的MAC,在得到网关的ARP应答后,用网关MAC作为报文目的MAC进行报文发送……也就是路由器的某个端口。注意,报文的源IP是源主机IP,目的IP依然是目的主机IP。</p><p>这里1,2步骤都是先进行IP信息封装处理,再通过ARP进行MAC封装处理(先3层,再2层),解包则相反。</p></li><li><p>当网关路由器接收到以太网数据帧时,发现数据帧中的目标MAC地址是自己的某一个端口的物理地址,这时路由器会把以太网数据帧的封装去掉。路由器认为这个IP数据包是要通过自己进行转发,接着它就在匹配路由表(包含目标地址和指向目标地址的指针)。匹配到路由项后,它就将包发往下一条地址。</p><p>路由器转发数据包也是这样,它始终是不会改IP地址的,只会改源/目标MAC。</p></li><li><p><a style="color:red;">万一路由遇到目的MAC是广播地址怎么办?IP的广播有三种:</a></p><p>255.255.255.255叫本地广播,也叫直播,direct broadcast,不跨路由器。</p><p>172.16.33.255叫子网广播,广播给172.16.33.0这个子网,可以跨路由器。</p><p>172.16.255.255叫全子网广播,广播给172.16.0.0这个主网,可以跨路由器。</p><p>路由器是三层设备,可以隔离广播,但并不是所有广播都隔离。事实上只有本地广播路由器才不转发,对于子网广播和全子网广播,路由器是转发的。为什么呢?我们来看255.255.255.255的广播,在MAC的封装中,对应的目的MAC是广播,而子网广播和全子网广播,对应的目的MAC是单播,所以路由器会转发。所以路由器隔离的广播是目的MAC为全1的广播,对于目的MAC是单播的上层广播,路由器是不能隔离的。</p></li><li><p>IP数据包经由路由转发的时候 源/目的IP,源/目的MAC是否发生改变,如何改变?</p><p>A—–(B1-B2)—–(C1-C2)——E</p><p>如上拓扑图为例,B1和B2是路由器B上的两个接口,C1和C2是路由器C上的两个接口,A和E是PC,由主机A向主机E发送数据包,那么在主机A形成的数据包的目的IP就是E的IP,源IP就是主机A的IP地址,目标MAC地址就是B1的MAC地址,源MAC地址就是A的MAC地址。</p><p>由A发给路由器B,B经过重封装后,源IP和目标IP是不变的,源MAC地址变成B2的MAC地址,目标MAC地址变成C1的MAC地址,封装完成发送给路由器C,路由器C接收到数据包后和B做的操作是一样的,源IP和目标IP的不变的,源MAC地址变成C2的MAC地址,目标MAC地址变成主机E的MAC地址,然后发送给主机E,这样E就收到了这个数据包,当恢复数据包的时候就是把收到的数据包的源IP地址(主机A的IP地址)和源MAC地址(接口C2的MAC地址)作为他的目标IP和目标MAC地址。</p></li></ol><hr><h2 id="移动网络"><a href="#移动网络" class="headerlink" title="移动网络"></a>移动网络</h2><h3 id="重要概念"><a href="#重要概念" class="headerlink" title="重要概念"></a>重要概念</h3><p>无线主机,无线链路,基站</p><p>跳数(single hop/multiple hops)和是否有基础设施(ad hoc nets)</p><p>ARQ协议,即自动重传请求(Automatic Repeat-reQuest),是OSI模型中的错误纠正协议之一。 它通过使用确认和重传这两个机制,在不可靠服务的基础上实现可靠的信息传输。 如果发送方在发送后一段时间之内没有收到确认帧,它通常会重新发送。</p><p>无线和移动是两个主题,要加以区别</p><h3 id="wireless-无线"><a href="#wireless-无线" class="headerlink" title="wireless-无线"></a>wireless-无线</h3><p>Wireless links, characteristics-无线链路和其特性</p><p>CDMA code division multiple access码分多址</p><p><img src="/computer-net/image-20230215213634060.png" alt="image-20230215213634060"></p><p><img src="/computer-net/2B45409406E2545E913A98DBFF9_A3C0C5DB_B6B5.jpg" alt="img"></p><h3 id="mobility-移动性"><a href="#mobility-移动性" class="headerlink" title="mobility-移动性"></a>mobility-移动性</h3><h2 id="网络安全"><a href="#网络安全" class="headerlink" title="网络安全"></a>网络安全</h2><h3 id="重要概念-1"><a href="#重要概念-1" class="headerlink" title="重要概念"></a>重要概念</h3><h3 id="密码学原则"><a href="#密码学原则" class="headerlink" title="密码学原则"></a>密码学原则</h3><p>对称加密</p><ul><li><p>DES</p><p><a href="https://www.cnblogs.com/idreamo/p/9333753.html">https://www.cnblogs.com/idreamo/p/9333753.html</a></p><p><img src="/computer-net/1281268-20180720073949486-1474910065.png" alt="img"></p><p><img src="/computer-net/1281268-20180722085234376-365550304.png" alt="img"></p></li></ul><p>非对称加密</p><p>宏观原理可以看<a href="https://www.51cto.com/article/742131.html%EF%BC%88%E5%B7%B2%E5%BD%92%E6%A1%A3%EF%BC%89%EF%BC%8C%E8%A7%A3%E9%87%8A%E5%BE%97%E6%AF%94%E8%BE%83%E9%80%9A%E4%BF%97%EF%BC%8C%E4%B8%8D%E8%BF%87%E4%B9%A6%E4%B8%8A%E7%9A%84%E5%85%AC%E9%92%A5%E7%A7%81%E9%92%A5%E6%98%AF%EF%BC%88n%EF%BC%8Ce%EF%BC%89%E5%92%8C%EF%BC%88n%EF%BC%8Cd%EF%BC%89%EF%BC%8C%E9%9C%80%E8%A6%81%E7%94%84%E5%88%AB">https://www.51cto.com/article/742131.html(已归档),解释得比较通俗,不过书上的公钥私钥是(n,e)和(n,d),需要甄别</a></p><h3 id="HTTPS"><a href="#HTTPS" class="headerlink" title="HTTPS"></a>HTTPS</h3><p>对称加密</p><p>非对称加密</p><h3 id="SSL"><a href="#SSL" class="headerlink" title="SSL"></a>SSL</h3><p>建立在传输层之上的安全协议</p><h3 id="IPsec"><a href="#IPsec" class="headerlink" title="IPsec"></a>IPsec</h3><p>应用在网络层的安全协议</p><p>ESP</p><p>AH</p><h3 id="SA"><a href="#SA" class="headerlink" title="SA"></a>SA</h3><p>security association</p><h2 id="多媒体"><a href="#多媒体" class="headerlink" title="多媒体"></a>多媒体</h2><h2 id="endtag"><a href="#endtag" class="headerlink" title="endtag"></a>endtag</h2>]]></content>
<summary type="html"><blockquote>
<p>持续更新</p>
</blockquote>
<p>主要是计算机网络自顶向下方法第七版部分笔记和一些拓展,这位网友的笔记很棒</p>
<p><a href="https://liuyijian.github.io/vuepressBlog/tech</summary>
<category term="计算机科学基础" scheme="https://hhumar.com/categories/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6%E5%9F%BA%E7%A1%80/"/>
<category term="Web" scheme="https://hhumar.com/tags/Web/"/>
<category term="Network" scheme="https://hhumar.com/tags/Network/"/>
</entry>
<entry>
<title>数据结构和算法</title>
<link href="https://hhumar.com/2022/11/06/ds/"/>
<id>https://hhumar.com/2022/11/06/ds/</id>
<published>2022-11-05T18:09:06.000Z</published>
<updated>2022-11-05T18:14:02.348Z</updated>
<content type="html"><![CDATA[<blockquote><p>持续更新</p></blockquote><h3 id=""><a href="#" class="headerlink" title=""></a></h3><h3 id="三个渐近复杂度符号:"><a href="#三个渐近复杂度符号:" class="headerlink" title="三个渐近复杂度符号:"></a>三个渐近复杂度符号:</h3><p>$\Theta:紧确界\quad O:上界\quad \Omega:下界$</p><h3 id="哨兵"><a href="#哨兵" class="headerlink" title="哨兵"></a>哨兵</h3><p>在首或尾增加哨兵等于目标,循环中寻找目标时不管索引是否超过界限,找到目标再查看索引是哨兵的索引还是真正目标的索引。</p><h3 id="KMP算法"><a href="#KMP算法" class="headerlink" title="KMP算法"></a>KMP算法</h3><p>求模式串的失配链接值是关键。向下取整floor(小于但是最大)和向上取整(大于但是最小)celling</p><h3 id="三元组表的快速转置"><a href="#三元组表的快速转置" class="headerlink" title="三元组表的快速转置"></a>三元组表的快速转置</h3><p>找出原表中每行/每列第一个元素转置后在新表中的位置,记录在<code>cpot[]</code>数组中,<code>num[]</code>数组记录源矩阵中每列非零元素的个数。关键是保持三元组的次序-即按行/按列排序。</p><h3 id="三元组和十字链表"><a href="#三元组和十字链表" class="headerlink" title="三元组和十字链表"></a>三元组和十字链表</h3><p>选用十字链表是为了在稀疏矩阵间需要运算,而两稀疏矩阵非零元素位置差异较大,每次运算都需要移动大量元素的位置,耗时耗力,所以利用链表特性存储稀疏矩阵。</p><h3 id="重连通图"><a href="#重连通图" class="headerlink" title="重连通图"></a>重连通图</h3><p>关节点是指图中某点,当删除此点及其关联边时,图的一个连通分量会被分割为两个或以上连通分量。无关节点的图为重连通图,重连通图中,任一顶点到其它顶点有两条及以上路径。若在连通图上至少需要删除k个顶点才能破坏图的连通性则称图的连通度为k。系统的连通度越高越安全。(电路设施、通信网络、物资运输线路)</p><h3 id="图的最小路径算法"><a href="#图的最小路径算法" class="headerlink" title="图的最小路径算法"></a>图的最小路径算法</h3><h4 id="Dijkstra算法:"><a href="#Dijkstra算法:" class="headerlink" title="Dijkstra算法:"></a>Dijkstra算法:</h4><p>建立最短路径数组,元素值表示当前顶点到数组下标对应顶点的最短距离。同时建立bool数组记录某顶点是否已经被提取过。初始化bool数组为全false,初始化最短路径数组为源点到各顶点直接距离,不存在直接边则距离为无穷大。然后从当前最小距离数组中寻找最小距离,确定这个这个最小的最小距离对应的顶点,将其在bool数组中置为已提取(true)在邻接矩阵中依次比较<u>此顶点到其它<strong>未提取顶点</strong>距离与当前最小的最小距离之和</u>与<u>最小距离数组中对应到各顶点的最小距离</u>,若前者更小则替换之,更新最小距离数组(比较次数每个循环会减一),然后继续寻找最小的最小距离(去除已提取的顶点)。但是这里面没有记录到每个顶点最小距离的相对应路径。可以置路径数组用来记录到达对应数组元素下标的顶点的上一个结点。 path[j] = <code>min_num</code>;<code>path[j]</code>记录<code>d[j]</code>暂时最短路径的最后一个中途节点<code>min_num</code>,表明<code>d[j]</code>最后一段从节点<code>min_num</code>到节点<code>j</code>,而到结点<code>j</code>的路径自然会由其它最短路径记录,由此可以达到记录路径的目的。</p><h3 id="最小生成树算法"><a href="#最小生成树算法" class="headerlink" title="最小生成树算法"></a>最小生成树算法</h3><h4 id="Prim算法"><a href="#Prim算法" class="headerlink" title="Prim算法"></a>Prim算法</h4><p>从任一顶点开始建立顶点集和空边集,利用辅助数组记录当前顶点集到图顶点集各点的最小距离,初始化也即为初始顶点到其余各顶点的距离(数组元素是结构体,包括邻接顶点和最小距离,不存在边时距离记为无穷大,到自己的距离记为0),然后循环n-1次,<em>每次增加一条边和一个顶点,该边是辅助数组中最小的最小距离(增加顶点的形式是把辅助数组对应位置的最小距离置零,增加边是打印该点在数组中的邻接顶点值和该点的值),然后更新辅助数组,用新顶点和图中其它顶点的距离比较当前对应位置最小距离,若更小则更新邻接顶点为当前顶点并更新最小距离,然后重复下一次循环</em>。如此可以保证辅助数组中的最小距离始终是当前顶点集到图中其余顶点的最小距离,并能记录是当前顶点集的哪一个顶点到图中顶点距离最小,如此循环n-1次就能添加完所有的必要边。复杂度为$O(n^2)$,与边数无关,适合稠密图。</p><h4 id="Kruskal算法-避圈法"><a href="#Kruskal算法-避圈法" class="headerlink" title="Kruskal算法(避圈法)"></a>Kruskal算法(避圈法)</h4><p>初始状态最小生成树为n个顶点无边的非连通图,连通分量为n,每次选择代价最小并能减少一个连通分量的边,直至所有顶点共属一个连通分量。需要利用堆对图中所有边按长进行排序,从小到大依次处理,并利用辅助数据结构并查集(数组即可,不同的连通分量记为不同序号值)检查新边的两顶点是否属于同一连通分量。</p><ul><li>破圈法</li><li>索林(<code>Sollin</code>)算法:类似聚类的凝聚法,合并平凡树</li></ul><h3 id="寻找有向图的强连通分量"><a href="#寻找有向图的强连通分量" class="headerlink" title="寻找有向图的强连通分量"></a>寻找有向图的强连通分量</h3><p><code>Tarjan</code>算法</p><h3 id="寻找图的最大匹配"><a href="#寻找图的最大匹配" class="headerlink" title="寻找图的最大匹配"></a>寻找图的最大匹配</h3><p>匈牙利算法</p><h3 id="二叉排序树"><a href="#二叉排序树" class="headerlink" title="二叉排序树"></a>二叉排序树</h3><h3 id="AVL树-二叉平衡树"><a href="#AVL树-二叉平衡树" class="headerlink" title="AVL树(二叉平衡树)"></a>AVL树(二叉平衡树)</h3><p>任意结点左右子树平衡因子满足$-1\leq 平衡因子 \leq 1$</p><h3 id="B树"><a href="#B树" class="headerlink" title="B树"></a>B树</h3><p>2-3树</p><h3 id="B-树:"><a href="#B-树:" class="headerlink" title="B+树:"></a>B+树:</h3><h3 id="求欧拉图中欧拉回路的算法:"><a href="#求欧拉图中欧拉回路的算法:" class="headerlink" title="求欧拉图中欧拉回路的算法:"></a>求欧拉图中欧拉回路的算法:</h3><ul><li>Fleury算法:能不走桥就不走桥</li><li>逐步插入回路法</li></ul><h3 id="货郎担问题:"><a href="#货郎担问题:" class="headerlink" title="货郎担问题:"></a>货郎担问题:</h3><h3 id="利用哈希表的滑动窗口字符串匹配——Robin-Karp算法"><a href="#利用哈希表的滑动窗口字符串匹配——Robin-Karp算法" class="headerlink" title="利用哈希表的滑动窗口字符串匹配——Robin-Karp算法"></a>利用哈希表的滑动窗口字符串匹配——Robin-Karp算法</h3><p>把pattern作整体计算哈希值,类比处理母串,滑动处理。</p><h3 id="Huffman算法"><a href="#Huffman算法" class="headerlink" title="Huffman算法"></a>Huffman算法</h3><p>求带权最优二叉树</p><h3 id="递归思想及原则:"><a href="#递归思想及原则:" class="headerlink" title="递归思想及原则:"></a>递归思想及原则:</h3><ul><li>函数调用其自身(直接的或间接的都算)</li><li>有<strong>明确的终止条件</strong></li></ul><p> 尾递归(函数所做的最后一件事情是一个函数调用(递归的或者非递归的)可以大大减少栈空间的占用</p><h3 id="线段树"><a href="#线段树" class="headerlink" title="线段树"></a>线段树</h3><h3 id="回溯和深度优先搜索dfs"><a href="#回溯和深度优先搜索dfs" class="headerlink" title="回溯和深度优先搜索dfs"></a>回溯和深度优先搜索dfs</h3><p> 遍历所有当前选择(做出选择,记录选择,下一次选择(递归),回退选择)</p><p>1、路径:也就是已经做出的选择。</p><p>2、选择列表:也就是你当前可以做的选择。</p><p>3、结束条件:也就是到达决策树底层,无法再做选择的条件。</p><h3 id="关联分析"><a href="#关联分析" class="headerlink" title="关联分析"></a>关联分析</h3><p>还没看</p><p><a href="https://www.cnblogs.com/LittleHann/p/9398219.html">https://www.cnblogs.com/LittleHann/p/9398219.html</a></p>]]></content>
<summary type="html"><blockquote>
<p>持续更新</p>
</blockquote>
<h3 id=""><a href="#" class="headerlink" title=""></a></h3><h3 id="三个渐近复杂度符号:"><a href="#三个渐近复杂度符号:" </summary>
<category term="计算机科学基础" scheme="https://hhumar.com/categories/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6%E5%9F%BA%E7%A1%80/"/>
<category term="Data Structure" scheme="https://hhumar.com/tags/Data-Structure/"/>
<category term="Algorithm" scheme="https://hhumar.com/tags/Algorithm/"/>
</entry>
<entry>
<title>Vue</title>
<link href="https://hhumar.com/2022/11/05/vue/"/>
<id>https://hhumar.com/2022/11/05/vue/</id>
<published>2022-11-04T16:07:44.000Z</published>
<updated>2022-12-07T16:02:24.009Z</updated>
<content type="html"><![CDATA[<blockquote><p>持续更新</p></blockquote><h3 id=""><a href="#" class="headerlink" title=""></a></h3><h2 id="基础内容"><a href="#基础内容" class="headerlink" title="基础内容"></a>基础内容</h2><p>SFC: Single File Component </p><p><strong>选项式 API</strong> 和<strong>组合式 API</strong></p><p>mustache 语法 (即双大括号<code>{{}}</code>) 只能用于文本插值。</p><p><code>reactive()</code> 只适用于对象 (包括数组和内置类型,如 <code>Map</code> 和 <code>Set</code>)。此外,<code>ref()</code> 可以接受任何值类型,并创建一个对象,在 <code>.value</code> property 下暴露内部值。都创建的是JavaScript proxy</p><p>ref()创建的proxy在其模板渲染上下文的顶层 property 时支持自动解包,</p><p>在 Vue 模板内,JavaScript 表达式可以被使用在如下场景上:</p><ul><li>在文本插值中 (双大括号)</li><li>在任何 Vue 指令 (以 <code>v-</code> 开头的特殊 attribute) attribute 的值中</li><li><strong>计算属性值会基于其响应式依赖被缓存</strong>,比方法更好,不会每次重新渲染都重新计算,只会在响应式依赖更新时重新计算。一个计算属性的声明中描述的是如何根据其他值派生一个值,因此计算函数的职责应该仅为计算和返回该值而非异步请求或者更改DOM。修改计算属性值也没有意义。</li></ul><h2 id="原理"><a href="#原理" class="headerlink" title="原理"></a>原理</h2><pre class="language-none"><code class="language-none">在watcher中调用getter,执行addSub, 将target传入对应的dep; vue的实现本质就是如此Vue中一个发布者observer会被多个订阅者watcher订阅,同时一个订阅者也会订阅多个发布者,是多对多的关系,watcher也可以叫做依赖,依赖于发布者的变化从而执行其绑定的回调,dep可以叫做订阅中心,负责维护订阅列表</code></pre><p>2.x defineProperty 和 3.x Proxy 的区别:</p><p>2.x:</p><ul><li>检测不到对象属性的添加和删除</li><li>数组<code>API</code>方法无法监听到</li><li>需要对每个属性进行遍历监听,如果嵌套对象,需要深层监听,造成性能问题</li></ul><p>3.x</p><ul><li><p><code>Proxy</code>可以直接监听数组的变化(<code>push</code>、<code>shift</code>、<code>splice</code>)</p></li><li><p><code>Proxy</code>直接可以劫持整个对象,并返回一个新对象,我们可以只操作新的对象达到响应式目的</p></li><li><p>当对象嵌套对象时,递归响应式</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">//实现深层响应式</span><span class="token keyword">function</span> <span class="token function">reactive</span><span class="token punctuation">(</span><span class="token parameter">obj</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token keyword">typeof</span> obj<span class="token operator">!==</span><span class="token string">'object'</span> <span class="token operator">||</span> obj<span class="token operator">===</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">return</span> obj<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> observed <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Proxy</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span><span class="token punctuation">{</span> <span class="token function">get</span><span class="token punctuation">(</span>target<span class="token punctuation">,</span>key<span class="token punctuation">,</span>reciver<span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">const</span> res <span class="token operator">=</span> Reflect<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>target<span class="token punctuation">,</span>key<span class="token punctuation">,</span>reciver<span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">getting </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>key<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">:</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>res<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token function">isObject</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span><span class="token operator">?</span><span class="token function">reactive</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span><span class="token operator">:</span>res<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> observed<span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre></li><li><p><code>Proxy</code>有多达13种拦截方法,不限于<code>apply</code>、<code>ownKeys</code>、<code>deleteProperty</code>、<code>has</code>等等,这是<code>Object.defineProperty</code>不具备的</p><p>正因为<code>defineProperty</code>自身的缺陷,导致<code>Vue2</code>在实现响应式过程需要实现其他的方法辅助(如重写数组方法、增加额外<code>set</code>、<code>delete</code>方法)</p></li></ul><h2 id="vue指令"><a href="#vue指令" class="headerlink" title="vue指令"></a>vue指令</h2><ul><li><p>某些指令会需要一个“参数”,在指令名后通过一个冒号隔开做标识。</p><p>可以在绑定的表达式中使用一个组件暴露的方法</p><pre class="language-none"><code class="language-none"><span :title="toTitleDate(date)"> {{ formatDate(date) }}</span></code></pre><p>在指令参数上也可以使用一个 JavaScript 表达式,需要包含在一对方括号内,称作动态参数</p><pre class="language-none"><code class="language-none"><p :[attributename]="attributeValue"></p>//动态参数期望值为字符串或 null ,null 代表显式移除该绑定,在HTML文件中时还要避免大写字母</code></pre><p>修饰符是以点开头的特殊后缀,表明指令需要以一些特殊的方式被绑定。例如 <code>.prevent</code> 修饰符会告知 <code>v-on</code> 指令对触发的事件调用 <code>event.preventDefault()</code></p><pre class="language-none"><code class="language-none"><form @submit.prevent="onSubmit">...</form></code></pre></li><li><p>v-html=”html”</p><p>具有v-html属性的对应标签的innderHTML 会与html变量值保持一致</p></li><li><p>v-bind:attributeName=”varName”给 attribute 绑定一个动态值<br>abbreviated.:attribute=””<br>布尔型attribute根据值为true/false来决定标签行为,下例中 isButtonDisabled 为非false布尔值或空字符串时,元素的disable属性值均为true</p><pre class="language-none"><code class="language-none"><button :disabled="isButtonDisabled">Button</button></code></pre><p>还可以通过不带参数的 v-bind 将包含多个 attribute 的JavaScript 对象绑定到单个元素</p><pre class="language-none"><code class="language-none"><script>const objectOfAttrs = { id: 'container', class: 'wrapper'};</script><template><div v-bind="objectOfAttrs"></div></template></code></pre></li><li><p>v-on:DOMEventName=”funcName”监听DOM事件<br>abbreviated.@DOMEventName=””</p></li><li><p>可以同时使用 v-bind 和 v-on 来在表单的输入元素上创建双向绑定:</p><pre class="language-none"><code class="language-none"><input :value="text" @input="onInput"></code></pre><p>v-model是以上操作的语法糖</p><pre class="language-none"><code class="language-none"><input v-model="text"></code></pre><p>v-model 会将被绑定的值与 <code><input></code> 的值自动同步</p></li><li><p>v-if=”varName”条件渲染DOM元素,为真值时渲染,否则移除该DOM元素</p><pre class="language-none"><code class="language-none"><h1 v-if="awesome">Vue is awesome!</h1></code></pre><p>类似的有v-else和v-else-if可以与其配合使用,一个 <code>v-else</code>和<code>v-else-if</code> 元素必须跟在一个 <code>v-if</code> 或者 <code>v-else-if</code> 元素后面,否则将不会识别它。</p></li><li><p><code>v-show</code><a href="https://cn.vuejs.org/guide/essentials/conditional.html#v-show">#</a></p><p>另一个可以用来按条件显示一个元素的指令是 <code>v-show</code>。其用法基本一样:</p><p>template</p><pre class="language-markup" data-language="markup"><code class="language-markup"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h1</span> <span class="token attr-name">v-show</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>ok<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Hello!<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h1</span><span class="token punctuation">></span></span></code></pre><p>不同之处在于 <code>v-show</code> 会在 DOM 渲染中保留该元素;<code>v-show</code> 仅切换了该元素上名为 <code>display</code> 的 CSS 属性。</p><p><code>v-show</code> 不支持在 <code><template></code> 元素上使用,也不能和 <code>v-else</code> 搭配使用。</p></li><li><p>v-for</p><p>以下代码能创建多个li元素</p><pre class="language-none"><code class="language-none"><li v-for="todo in todos" :key="todo.id"> <input type="checkbox" v-model="todo.done"> ...</li></code></pre><p>key<a href="https://cn.vuejs.org/api/built-in-special-attributes.html#key">#</a></p><p><code>key</code> 这个特殊的 attribute 主要作为 Vue 的虚拟 DOM 算法提示,在比较新旧节点列表时用于识别 vnode。</p><ul><li><p><strong>预期</strong>:<code>number | string | symbol</code></p></li><li><p><strong>详细信息</strong></p><p>在没有 key 的情况下,Vue 将使用一种最小化元素移动的算法,并尽可能地就地更新/复用相同类型的元素。如果传了 key,则将根据 key 的变化顺序来重新排列元素,并且将始终移除/销毁 key 已经不存在的元素。</p><p>同一个父元素下的子元素必须具有<strong>唯一的 key</strong>。重复的 key 将会导致渲染异常。</p><p>最常见的用例是与 <code>v-for</code> 结合:</p><p>template</p><pre class="language-none"><code class="language-none"><ul> <li v-for="item in items" :key="item.id">...</li></ul></code></pre><p>也可以用于强制替换一个元素/组件而不是复用它。当你想这么做时它可能会很有用:</p><ul><li>在适当的时候触发组件的生命周期钩子</li><li>触发过渡</li></ul><p>举例来说:</p><p>template</p><pre class="language-none"><code class="language-none"><transition> <span :key="text">{{ text }}</span></transition></code></pre><p>当 <code>text</code> 变化时,<code><span></code> 总是会被替换而不是更新,因此 transition 将会被触发。</p></li></ul></li></ul><p>readonly 和 shallowreadonly</p><h3 id="模板引用"><a href="#模板引用" class="headerlink" title="模板引用"></a>模板引用</h3><p>为dom元素加上ref属性,在script中命名同名响应式属性即可操作模板</p><pre class="language-markup" data-language="markup"><code class="language-markup"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">setup</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript"><span class="token keyword">import</span> <span class="token punctuation">{</span> ref<span class="token punctuation">,</span> onMounted <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vue'</span><span class="token comment">// 声明一个 ref 来存放该元素的引用</span><span class="token comment">// 必须和模板里的 ref 同名</span><span class="token keyword">const</span> input <span class="token operator">=</span> <span class="token function">ref</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token function">onMounted</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> input<span class="token punctuation">.</span>value<span class="token punctuation">.</span><span class="token function">focus</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">)</span></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>template</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>input</span> <span class="token attr-name">ref</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>input<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>template</span><span class="token punctuation">></span></span></code></pre><h2 id="响应式"><a href="#响应式" class="headerlink" title="响应式"></a>响应式</h2><p>reactive解构赋值便不再具有响应式,但是computed返回的内容是具有响应式的。</p><h2 id="计算属性"><a href="#计算属性" class="headerlink" title="计算属性"></a>计算属性</h2><p>计算属性的计算函数应只做计算而没有任何其他的副作用,一个计算属性的声明中描述的是如何根据其他值派生一个值。同时避免直接修改计算属性值。</p><p>从计算属性返回的值是派生状态。可以把它看作是一个“临时快照”,每当源状态发生变化时,就会创建一个新的快照。更改快照是没有意义的,因此计算属性的返回值应该被视为只读的,并且永远不应该被更改——应该更新它所依赖的源状态以触发新的计算。</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// 组件中</span><span class="token keyword">function</span> <span class="token function">calculateBooksMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> author<span class="token punctuation">.</span>books<span class="token punctuation">.</span>length <span class="token operator">></span> <span class="token number">0</span> <span class="token operator">?</span> <span class="token string">'Yes'</span> <span class="token operator">:</span> <span class="token string">'No'</span><span class="token punctuation">}</span></code></pre><p>也可以同时传入 get 和 set 方法,超过只读范围来刻意产生副作用,此时传递给computed的是带有set和get方法的对象</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">import</span> <span class="token punctuation">{</span> ref<span class="token punctuation">,</span> computed <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vue'</span><span class="token keyword">const</span> firstName <span class="token operator">=</span> <span class="token function">ref</span><span class="token punctuation">(</span><span class="token string">'John'</span><span class="token punctuation">)</span><span class="token keyword">const</span> lastName <span class="token operator">=</span> <span class="token function">ref</span><span class="token punctuation">(</span><span class="token string">'Doe'</span><span class="token punctuation">)</span><span class="token keyword">const</span> fullName <span class="token operator">=</span> <span class="token function">computed</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token comment">// getter</span> <span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> firstName<span class="token punctuation">.</span>value <span class="token operator">+</span> <span class="token string">' '</span> <span class="token operator">+</span> lastName<span class="token punctuation">.</span>value <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// setter</span> <span class="token function">set</span><span class="token punctuation">(</span>newValue<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 注意:我们这里使用的是解构赋值语法</span> <span class="token punctuation">[</span>firstName<span class="token punctuation">.</span>value<span class="token punctuation">,</span> lastName<span class="token punctuation">.</span>value<span class="token punctuation">]</span> <span class="token operator">=</span> newValue<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">' '</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre><h2 id="侦听器"><a href="#侦听器" class="headerlink" title="侦听器"></a>侦听器</h2><p>watch:watch是去监听一个值的变化,然后执行相对应的函数。</p><p>如果监听的数据源是一个 引用类型 时( e.g. <code>Object</code> 、 <code>Array</code> 、 <code>Date</code> … ), <code>value</code> 和 <code>oldValue</code> 是完全相同的,因为指向同一个对象。</p><pre class="language-typescript" data-language="typescript"><code class="language-typescript"><span class="token comment">// watch 部分的 TS 类型</span><span class="token comment">// ...</span><span class="token keyword">export</span> <span class="token keyword">declare</span> <span class="token keyword">function</span> <span class="token generic-function"><span class="token function">watch</span><span class="token generic class-name"><span class="token operator"><</span><span class="token constant">T</span><span class="token punctuation">,</span> Immediate <span class="token keyword">extends</span> Readonly<span class="token operator"><</span><span class="token builtin">boolean</span><span class="token operator">></span> <span class="token operator">=</span> <span class="token boolean">false</span><span class="token operator">></span></span></span><span class="token punctuation">(</span> source<span class="token operator">:</span> WatchSource<span class="token operator"><</span><span class="token constant">T</span><span class="token operator">></span><span class="token punctuation">,</span> cb<span class="token operator">:</span> WatchCallback<span class="token operator"><</span><span class="token constant">T</span><span class="token punctuation">,</span> Immediate <span class="token keyword">extends</span> <span class="token class-name"><span class="token boolean">true</span></span> <span class="token operator">?</span> <span class="token constant">T</span> <span class="token operator">|</span> <span class="token keyword">undefined</span> <span class="token operator">:</span> <span class="token constant">T</span><span class="token operator">></span><span class="token punctuation">,</span> options<span class="token operator">?</span><span class="token operator">:</span> WatchOptions<span class="token operator"><</span>Immediate<span class="token operator">></span><span class="token punctuation">)</span><span class="token operator">:</span> WatchStopHandle</code></pre><p>callback 有三个参数,依次为 value、oldValue、onCleanup清理函数。</p><p>还可以做批量监听,参数以数组形式传入,在回调函数中也以数组形式作为参数传入</p><p><code>watch</code> 的第一个参数可以是不同形式的“数据源”:它可以是一个 ref (包括计算属性)、一个响应式对象、一个 getter 函数、或多个数据源组成的数组:</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">const</span> x <span class="token operator">=</span> <span class="token function">ref</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token keyword">const</span> y <span class="token operator">=</span> <span class="token function">ref</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token comment">// 单个 ref</span><span class="token function">watch</span><span class="token punctuation">(</span>x<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">newX</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">x is </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>newX<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token comment">// getter 函数</span><span class="token function">watch</span><span class="token punctuation">(</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> x<span class="token punctuation">.</span>value <span class="token operator">+</span> y<span class="token punctuation">.</span>value<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">sum</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">sum of x + y is: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>sum<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token comment">// 多个来源组成的数组</span><span class="token function">watch</span><span class="token punctuation">(</span><span class="token punctuation">[</span>x<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> y<span class="token punctuation">.</span>value<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">[</span>newX<span class="token punctuation">,</span> newY<span class="token punctuation">]</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">x is </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>newX<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> and y is </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>newY<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre><p>关于 options</p><table><thead><tr><th>deep</th><th>boolean</th><th>false</th><th>true | false</th><th>是否进行深度监听,适用于监听 ref 响应式引用对象</th></tr></thead><tbody><tr><td>immediate</td><td>boolean</td><td>false</td><td>true | false</td><td>是否立即执行监听回调,包括初始化,为 false 时初始化不调用回调</td></tr><tr><td>flush</td><td>string</td><td>‘pre’</td><td>‘pre’ | ‘post’ | ‘sync’</td><td>控制监听回调的调用时机</td></tr><tr><td>onTrack</td><td>(e) => void</td><td></td><td></td><td>在数据源被追踪时调用</td></tr><tr><td>onTrigger</td><td>(e) => void</td><td></td><td></td><td>在监听回调被触发时调用</td></tr></tbody></table><p>deep在传入为 reactive 时自动开启,可以搭配传入 ref 引用对象使用</p><p>在带有 immediate 选项时,不能在第一次回调时取消该数据源的监听</p><p>定义一个 watch 行为的时候,它会返回一个用来停止监听的函数</p><h2 id="模板引用-1"><a href="#模板引用-1" class="headerlink" title="模板引用"></a>模板引用</h2><p>使用 ref 在dom 中挂载结点,必须使用 xxx.value 才能访问到模板 dom 元素</p><h2 id="组件"><a href="#组件" class="headerlink" title="组件"></a>组件</h2><h3 id="注册"><a href="#注册" class="headerlink" title="注册"></a>注册</h3><p>全局注册和局部注册,3.2之后好像局部注册就够了</p><h3 id="Props"><a href="#Props" class="headerlink" title="Props"></a>Props</h3><p>组件间传递值</p><p>在子组件中定义属性向外暴露,外部组件用 v-bind 传递进来,</p><pre class="language-jsx" data-language="jsx"><code class="language-jsx"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">setup</span><span class="token punctuation">></span></span><span class="token plain-text">const props = defineProps(['foo'])console.log(props.foo) //or// 使用 <script setup>defineProps({ title: String, likes: Number})</span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span></code></pre><p>在ts中</p><pre class="language-tsx" data-language="tsx"><code class="language-tsx"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">setup</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>ts<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text">defineProps<{ title?: string likes?: number}>()</span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span></code></pre><h3 id="透传attrs"><a href="#透传attrs" class="headerlink" title="透传attrs"></a>透传attrs</h3><p>非props,直接赋值</p><h4 id="v-on-监听器继承"><a href="#v-on-监听器继承" class="headerlink" title="v-on 监听器继承#"></a><code>v-on</code> 监听器继承<a href="https://cn.vuejs.org/guide/components/attrs.html#v-on-listener-inheritance">#</a></h4><p>同样的规则也适用于 <code>v-on</code> 事件监听器:</p><p>template</p><pre class="language-none"><code class="language-none"><MyButton @click="onClick" /></code></pre><p><code>click</code> 监听器会被添加到 <code><MyButton></code> 的根元素,即那个原生的 <code><button></code> 元素之上。当原生的 <code><button></code> 被点击,会触发父组件的 <code>onClick</code> 方法。同样的,如果原生 <code>button</code> 元素自身也通过 <code>v-on</code> 绑定了一个事件监听器,则这个监听器和从父组件继承的监听器都会被触发。</p><h4 id="深层组件继承"><a href="#深层组件继承" class="headerlink" title="深层组件继承#"></a>深层组件继承<a href="https://cn.vuejs.org/guide/components/attrs.html#nested-component-inheritance">#</a></h4><p>有些情况下一个组件会在根节点上渲染另一个组件。例如,我们重构一下 <code><MyButton></code>,让它在根节点上渲染 <code><BaseButton></code>:</p><p>template</p><pre class="language-none"><code class="language-none"><!-- <MyButton/> 的模板,只是渲染另一个组件 --><BaseButton /></code></pre><ol><li>透传的 attribute 不会包含 <code><MyButton></code> 上声明过的 props 或是针对 <code>emits</code> 声明事件的 <code>v-on</code> 侦听函数,换句话说,声明过的 props 和侦听函数被 <code><MyButton></code>“消费”了。</li><li>透传的 attribute 若符合声明,也可以作为 props 传入 <code><BaseButton></code>。</li></ol><p>禁用attrs:如果你<strong>不想要</strong>一个组件自动地继承 attribute,你可以在组件选项中设置 <code>inheritAttrs: false</code>。</p><p>管理所有透传attrs</p><p>const attrs = useAttrs();</p><h3 id="事件"><a href="#事件" class="headerlink" title="事件"></a>事件</h3><p>组件直接传递事件,Child.vue 通过 emit 向 Father.vue 触发父组件的事件执行</p><p>和原生 DOM 事件不一样,组件触发的事件<strong>没有冒泡机制</strong>。你只能监听直接子组件触发的事件。平级组件或是跨越多层嵌套的组件间通信,应使用一个外部的事件总线,或是使用一个<a href="https://cn.vuejs.org/guide/scaling-up/state-management.html">全局状态管理方案</a></p><p>defineEmits</p><p>emit</p><pre class="language-typescript" data-language="typescript"><code class="language-typescript"><span class="token operator"><</span>script setup<span class="token operator">></span><span class="token keyword">const</span> emit <span class="token operator">=</span> <span class="token function">defineEmits</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'inFocus'</span><span class="token punctuation">,</span> <span class="token string">'submit'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token keyword">function</span> <span class="token function">buttonClick</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">emit</span><span class="token punctuation">(</span><span class="token string">'submit'</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>script<span class="token operator">></span></code></pre><p>这个 <code>emits</code> 选项还支持对象语法,它允许我们对触发事件的参数进行验证:</p><p>vue</p><pre class="language-none"><code class="language-none"><script setup>const emit = defineEmits({ submit(payload) { // 通过返回值为 `true` 还是为 `false` 来判断 // 验证是否通过 }})</script></code></pre><h3 id="插槽"><a href="#插槽" class="headerlink" title="插槽"></a>插槽</h3><p><slot />写在子组件中供父组件传递dom内容</p><p><code><slot></code> 元素是一个<strong>插槽出口</strong> (slot outlet),标示了父元素提供的<strong>插槽内容</strong> (slot content) 将在哪里被渲染。</p><p>插槽内容可以访问到父组件的数据作用域,<strong>无法访问</strong>子组件的数据</p><h4 id="具名插槽"><a href="#具名插槽" class="headerlink" title="具名插槽"></a>具名插槽</h4><p>带 <code>name</code> 的插槽被称为具名插槽 (named slots)。没有提供 <code>name</code> 的 <code><slot></code> 出口会隐式地命名为“default”</p><p><code>v-slot</code> 有对应的简写 <code>#</code>,因此 <code><template v-slot:header></code> 可以简写为 <code><template #header></code>。其意思就是“将这部分模板片段传入子组件的 header 插槽中”。</p><p>当一个组件同时接收默认插槽和具名插槽时,所有位于顶级的非 <code><template></code> 节点都被隐式地视为默认插槽的内容。</p><p>例子:</p><p>待接收插槽内容的子组件</p><pre class="language-markup" data-language="markup"><code class="language-markup"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>container<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>header</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>slot</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>header<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>slot</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>header</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>main</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>slot</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>slot</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>main</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>footer</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>slot</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>footer<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>slot</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>footer</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></code></pre><p>父组件</p><pre class="language-markup" data-language="markup"><code class="language-markup"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>BaseLayout</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>template</span> <span class="token attr-name">#header</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h1</span><span class="token punctuation">></span></span>Here might be a page title<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h1</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>template</span><span class="token punctuation">></span></span> <span class="token comment"><!-- 隐式的默认插槽 --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span>A paragraph for the main content.<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span>And another one.<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> <span class="token comment"><!-- <template #default> <p>A paragraph for the main content.</p> <p>And another one.</p> </template> --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>template</span> <span class="token attr-name">#footer</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span>Here's some contact info<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>template</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>BaseLayout</span><span class="token punctuation">></span></span></code></pre><p>子组件渲染结果</p><pre class="language-markup" data-language="markup"><code class="language-markup"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>container<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>header</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h1</span><span class="token punctuation">></span></span>Here might be a page title<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h1</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>header</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>main</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span>A paragraph for the main content.<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span>And another one.<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>main</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>footer</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span>Here's some contact info<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>footer</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></code></pre><p>支持动态指令参数</p><pre class="language-markup" data-language="markup"><code class="language-markup"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>template</span> <span class="token attr-name"><span class="token namespace">v-slot:</span>[dynamicSlotName]</span><span class="token punctuation">></span></span> ...<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>template</span><span class="token punctuation">></span></span><span class="token comment"><!-- 缩写为 --></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>template</span> <span class="token attr-name">#[dynamicSlotName]</span><span class="token punctuation">></span></span> ...<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>template</span><span class="token punctuation">></span></span></code></pre><h3 id="依赖注入"><a href="#依赖注入" class="headerlink" title="依赖注入"></a>依赖注入</h3><p>祖先组件中用provide提供依赖,后代任意位置可使用inject注入该依赖</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">//祖先</span><span class="token keyword">const</span> message <span class="token operator">=</span> <span class="token function">ref</span><span class="token punctuation">(</span><span class="token string">'hello'</span><span class="token punctuation">)</span><span class="token function">provide</span><span class="token punctuation">(</span><span class="token string">'message'</span><span class="token punctuation">,</span> message<span class="token punctuation">)</span><span class="token comment">//name, value</span><span class="token comment">//后代</span><span class="token keyword">const</span> message <span class="token operator">=</span> <span class="token function">inject</span><span class="token punctuation">(</span><span class="token string">'message'</span><span class="token punctuation">)</span><span class="token comment">//name</span></code></pre><h2 id="生命周期"><a href="#生命周期" class="headerlink" title="生命周期"></a>生命周期</h2><p>created:html加载完成之前,执行。执行顺序:父组件-子组件</p><p>mounted:html加载完成后执行。执行顺序:子组件-父组件</p><p>methods:事件方法执行</p><p>created():组件实例创建完成,dom还未生成,仅仅触发一次; mounted是挂载vue实例后的钩子函数,仅仅执行一次; activated():在使用时,会用到activated(),keep-live主要目的是可以使用缓存,避免组件重新渲染;</p><p>activated()只要进入页面就会触发</p><p><img src="/2022/11/05/vue/lifecycle_vue3.png" alt="lifecycle_vue3"></p><h2 id="全局API"><a href="#全局API" class="headerlink" title="全局API"></a>全局API</h2><h3 id="nextTick"><a href="#nextTick" class="headerlink" title="nextTick()#"></a>nextTick()<a href="https://cn.vuejs.org/api/general.html#nexttick">#</a></h3><p>等待下一次 DOM 更新刷新的工具方法。</p><ul><li><p><strong>类型</strong></p><pre class="language-typescript" data-language="typescript"><code class="language-typescript"><span class="token keyword">function</span> <span class="token function">nextTick</span><span class="token punctuation">(</span>callback<span class="token operator">?</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">void</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">Promise</span><span class="token operator"><</span><span class="token keyword">void</span><span class="token operator">></span></code></pre></li><li><p><strong>详细信息</strong></p><p>当你在 Vue 中更改响应式状态时,最终的 DOM 更新并不是同步生效的,而是由 Vue 将它们缓存在一个队列中,直到下一个“tick”才一起执行。这样是为了确保每个组件无论发生多少状态改变,都仅执行一次更新。</p><p><code>nextTick()</code> 可以在状态改变后立即使用,以等待 DOM 更新完成。你可以传递一个回调函数作为参数,或者 await 返回的 Promise。</p></li></ul><h2 id="路由vue-router"><a href="#路由vue-router" class="headerlink" title="路由vue-router"></a>路由vue-router</h2><ul><li><p>router-link</p><p>链接,类似a标签,但是自定义组件,使得 Vue Router 可以在不重新加载页面的情况下更改 URL,处理 URL 的生成以及编码</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">//如导航代码</span> <span class="token operator"><</span>router<span class="token operator">-</span>link <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"nav-link"</span> to<span class="token operator">=</span><span class="token string">"ContactUs"</span><span class="token operator">></span>联系我们<span class="token operator"><</span><span class="token operator">/</span>router<span class="token operator">-</span>link<span class="token operator">></span><span class="token number">12</span></code></pre><p>通过router-link可以使<code><router-view/></code>中的显示内容路由(跳转)到<code>src/router/index.js</code>文件中配置的组件中去,这类似于html的a标签中的href(注意:href页面会刷新,在这里则不会),其实这就好比tab选项卡中的头部选项,<code>router-view好比tab选项卡的body选项。</code></p></li><li><p>router-view</p><p>显示与 url 对应的组件</p><p>默认刚进入网页时是’/‘</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token operator"><</span>router<span class="token operator">-</span>view<span class="token operator">></span><span class="token operator"><</span>router<span class="token operator">-</span>view<span class="token operator">/</span><span class="token operator">></span>(命名视图)<span class="token number">1</span><span class="token operator"><</span>router<span class="token operator">-</span>view<span class="token operator">/</span><span class="token operator">></span>(嵌套命名视图)<span class="token number">1</span></code></pre><p><code><router-view></code> 是用来渲染通过路由映射过来的组件,当路径更改时, 其中的内容也会发生更改</p><p><strong>主要应用于单页面中,与<code>router-link</code>配合,渲染<code>router-link</code> 映射过来的组件。</strong></p><p>运作过程:就是几个跳转链接跳到对应的子页面,程序运行的时候,会将<code><template></code>标签里面的内容都注入到App.vue页面中的<code>router-view</code>标签中,从而实现无刷新的路由跳转。</p></li><li><p>createRouter(<strong>RouterOptions</strong> )</p><pre class="language-typescript" data-language="typescript"><code class="language-typescript">RouterOptions <span class="token keyword">extends</span> <span class="token class-name">PathParserOptions</span><span class="token punctuation">{</span>history<span class="token operator">:</span> RouterHistory<span class="token punctuation">;</span>routes<span class="token operator">:</span> RouteRecordRaw<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre></li><li><p>useRoute<a href="https://router.vuejs.org/zh/api/#useroute">#</a></p><p>返回当前路由地址。相当于在模板中使用 <code>$route</code>。必须在 <code>setup()</code> 中调用。</p><p><strong>函数签名:</strong></p><pre class="language-none"><code class="language-none">export declare function useRoute(): RouteLocationNormalized</code></pre><p>useRouter<a href="https://router.vuejs.org/zh/api/#userouter">#</a></p><p>返回 <a href="https://router.vuejs.org/zh/api/#router-properties">router</a> 实例。相当于在模板中使用 <code>$router</code>。必须在 <code>setup()</code> 中调用。</p><p><strong>函数签名:</strong></p><pre class="language-none"><code class="language-none">export declare function useRouter(): Router</code></pre></li><li></li><li><p><a href="https://router.vuejs.org/zh/api/#createwebhistory">createWebHistory()</a></p><p>创建一个 HTML5 历史,即单页面应用程序中最常见的历史记录。应用程序必须通过 http 协议被提供服务。</p><p>可选参数base为托管目录</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token function">createWebHistory</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 没有 base,应用托管在域名 `https://example.com` 的根目录下。</span><span class="token function">createWebHistory</span><span class="token punctuation">(</span><span class="token string">'/folder/'</span><span class="token punctuation">)</span> <span class="token comment">// 给出的网址为 `https://example.com/folder/`</span></code></pre></li><li><p>router.push<a href="https://router.vuejs.org/zh/api/#push">#</a></p><p>通过在历史堆栈中推送一个 entry,以编程方式导航到一个新的 URL。</p><p><strong>函数签名:</strong></p><pre class="language-none"><code class="language-none">push(to: RouteLocationRaw): Promise<NavigationFailure | void | undefined></code></pre><p><em>参数</em></p><table><thead><tr><th>参数</th><th>类型</th><th>描述</th></tr></thead><tbody><tr><td>to</td><td><a href="https://router.vuejs.org/zh/api/#routelocationraw"><code>RouteLocationRaw</code></a></td><td>要导航到的路由地址</td></tr></tbody></table></li></ul><p>ts类型</p><ul><li><p>RouteRecordRaw</p><pre class="language-none"><code class="language-none">export declare type RouteRecordRaw = RouteRecordSingleView | RouteRecordMultipleViews | RouteRecordRedirect;</code></pre></li><li><p>RouteLocationNormalized</p><pre class="language-typescript" data-language="typescript"><code class="language-typescript"><span class="token keyword">export</span> <span class="token keyword">declare</span> <span class="token keyword">interface</span> <span class="token class-name">RouteLocationNormalized</span> <span class="token keyword">extends</span> <span class="token class-name">_RouteLocationBase</span> <span class="token punctuation">{</span> <span class="token comment">/** * Array of {@link RouteRecordNormalized} */</span> matched<span class="token operator">:</span> RouteRecordNormalized<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token keyword">export</span> <span class="token keyword">declare</span> <span class="token keyword">interface</span> <span class="token class-name">_RouteLocationBase</span> <span class="token keyword">extends</span> <span class="token class-name">Pick<span class="token operator"><</span>MatcherLocation<span class="token punctuation">,</span> <span class="token string">'name'</span> <span class="token operator">|</span> <span class="token string">'path'</span> <span class="token operator">|</span> <span class="token string">'params'</span> <span class="token operator">|</span> <span class="token string">'meta'</span><span class="token operator">></span></span> <span class="token punctuation">{</span> <span class="token comment">/** * The whole location including the `search` and `hash`. This string is * percentage encoded. */</span> fullPath<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> <span class="token comment">/** * Object representation of the `search` property of the current location. */</span> query<span class="token operator">:</span> LocationQuery<span class="token punctuation">;</span> <span class="token comment">/** * Hash of the current location. If present, starts with a `#`. */</span> hash<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> <span class="token comment">/** * Contains the location we were initially trying to access before ending up * on the current location. */</span> redirectedFrom<span class="token operator">:</span> RouteLocation <span class="token operator">|</span> <span class="token keyword">undefined</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token keyword">declare</span> <span class="token keyword">interface</span> <span class="token class-name">MatcherLocation</span> <span class="token punctuation">{</span> <span class="token comment">/** * Name of the matched record */</span> name<span class="token operator">:</span> RouteRecordName <span class="token operator">|</span> <span class="token keyword">null</span> <span class="token operator">|</span> <span class="token keyword">undefined</span><span class="token punctuation">;</span> <span class="token comment">/** * Percentage encoded pathname section of the URL. */</span> path<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> <span class="token comment">/** * Object of decoded params extracted from the `path`. */</span> params<span class="token operator">:</span> RouteParams<span class="token punctuation">;</span> <span class="token comment">/** * Merged `meta` properties from all the matched route records. */</span> meta<span class="token operator">:</span> RouteMeta<span class="token punctuation">;</span> <span class="token comment">/** * Array of {@link RouteRecord} containing components as they were * passed when adding records. It can also contain redirect records. This * can't be used directly */</span> matched<span class="token operator">:</span> RouteRecord<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre></li><li><p>Router 属性<a href="https://router.vuejs.org/zh/api/#router-%E5%B1%9E%E6%80%A7">#</a></p><p>currentRoute<a href="https://router.vuejs.org/zh/api/#currentroute">#</a></p><ul><li><p><strong>类型</strong>:Ref<RouteLocationNormalized></p></li><li><p><strong>详细内容</strong>:</p><p>当前路由地址。只读的。</p></li></ul><p>options<a href="https://router.vuejs.org/zh/api/#options">#</a></p><ul><li><p><strong>类型</strong>:<a href="https://router.vuejs.org/zh/api/#routeroptions"><code>RouterOptions</code></a></p></li><li><p><strong>详细内容</strong>:</p><p>创建 Router 时传递的原始配置对象。只读的。</p></li></ul></li></ul><h2 id="状态管理工具"><a href="#状态管理工具" class="headerlink" title="状态管理工具"></a>状态管理工具</h2><h3 id="Vuex"><a href="#Vuex" class="headerlink" title="Vuex"></a>Vuex</h3><p>中大型项目</p><h3 id="Pinia"><a href="#Pinia" class="headerlink" title="Pinia"></a>Pinia</h3><p>小型项目</p><p>一个 Store (如 Pinia)是一个实体,它持有未绑定到您的组件树的状态和业务逻辑。换句话说,<strong>它托管全局状态</strong>。它有点像一个始终存在并且每个人都可以读取和写入的组件。它有<strong>三个概念</strong>,<a href="https://pinia.web3doc.top/core-concepts/state.html">state</a>、<a href="https://pinia.web3doc.top/core-concepts/getters.html">getters</a> 和 <a href="https://pinia.web3doc.top/core-concepts/actions.html">actions</a> 并且可以安全地假设这些概念等同于组件中的“数据”、“计算”和“方法”。</p><p>可以通过调用 store 上的 <code>$reset()</code> 方法将状态 <em>重置</em> 到其初始值:</p><pre class="language-none"><code class="language-none">const store = useStore()store.$reset()</code></pre><h2 id="构建工具"><a href="#构建工具" class="headerlink" title="构建工具"></a>构建工具</h2><h3 id="vite"><a href="#vite" class="headerlink" title="vite"></a>vite</h3><p>Vite 在一个特殊的 <strong><code>import.meta.env</code></strong> 对象上暴露环境变量。这里有一些在所有情况下都可以使用的内建变量:</p><ul><li><strong><code>import.meta.env.MODE</code></strong>: {string} 应用运行的<a href="https://cn.vitejs.dev/guide/env-and-mode.html#modes">模式</a>。<ul><li>默认情况下,开发服务器 (<code>dev</code> 命令) 运行在 <code>development</code> (开发) 模式,而 <code>build</code> 命令则运行在 <code>production</code> (生产) 模式。</li></ul></li><li><strong><code>import.meta.env.BASE_URL</code></strong>: {string} 部署应用时的基本 URL。他由<a href="https://cn.vitejs.dev/config/shared-options.html#base"><code>base</code> 配置项</a>决定。</li><li><strong><code>import.meta.env.PROD</code></strong>: {boolean} 应用是否运行在生产环境。</li><li><strong><code>import.meta.env.DEV</code></strong>: {boolean} 应用是否运行在开发环境 (永远与 <code>import.meta.env.PROD</code>相反)。</li><li><strong><code>import.meta.env.SSR</code></strong>: {boolean} 应用是否运行在 <a href="https://cn.vitejs.dev/guide/ssr.html#conditional-logic">server</a> 上。</li></ul><p>不支持动态读取值。在生产环境中,这些环境变量会在构建时被<strong>静态替换</strong>,例如,动态 key 取值 <code>import.meta.env[key]</code> 是无效的。</p><h4 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h4><ul><li><p>base<a href="https://cn.vitejs.dev/config/shared-options.html#base">¶</a></p><ul><li><strong>类型:</strong> <code>string</code></li><li><strong>默认:</strong> <code>/</code></li></ul><p>开发或生产环境服务的公共基础路径。合法的值包括以下几种:</p><ul><li>绝对 URL 路径名,例如 <code>/foo/</code></li><li>完整的 URL,例如 <code>https://foo.com/</code></li><li>空字符串或 <code>./</code>(用于嵌入形式的开发)</li></ul></li><li><p>plugins<a href="https://cn.vitejs.dev/config/shared-options.html#plugins">¶</a></p><ul><li><strong>类型:</strong> <code>(Plugin | Plugin[] | Promise<Plugin | Plugin[]>)[]</code></li></ul><p>需要用到的插件数组。Falsy 虚值的插件将被忽略,插件数组将被扁平化(flatten)。查看 <a href="https://cn.vitejs.dev/guide/api-plugin.html">插件 API</a> 获取 Vite 插件的更多细节。</p></li><li><p>server</p><ul><li><p>.host<a href="https://cn.vitejs.dev/config/server-options.html#server-host">¶</a></p><ul><li><strong>类型:</strong> <code>string | boolean</code></li><li><strong>默认:</strong> <code>'localhost'</code></li></ul><p>指定服务器应该监听哪个 IP 地址。 如果将此设置为 <code>0.0.0.0</code> 或者 <code>true</code> 将监听所有地址,包括局域网和公网地址。localhost一般用来测试本机,监听本机请求。</p></li><li><p>.port</p><ul><li><strong>类型:</strong> <code>number</code></li><li><strong>默认值:</strong> <code>5173</code></li></ul><p>指定监听端口。注意:如果端口已经被使用,Vite 会自动尝试下一个可用的端口,所以这可能不是开发服务器最终监听的实际端口。</p></li></ul></li></ul><h2 id="UI框架"><a href="#UI框架" class="headerlink" title="UI框架"></a>UI框架</h2><h3 id="element-plus"><a href="#element-plus" class="headerlink" title="element-plus"></a>element-plus</h3><h4 id="el-input"><a href="#el-input" class="headerlink" title="el-input"></a>el-input</h4><h4 id="el-button"><a href="#el-button" class="headerlink" title="el-button"></a>el-button</h4><table><thead><tr><th align="left">属性名</th><th align="left">说明</th><th align="left">类型</th><th align="left">可选值</th><th align="left">默认值</th></tr></thead><tbody><tr><td align="left">size</td><td align="left">尺寸</td><td align="left">string</td><td align="left">large / default /small</td><td align="left">—</td></tr><tr><td align="left">type</td><td align="left">类型</td><td align="left">string</td><td align="left">primary / success / warning / danger / info / <del>text</del></td><td align="left">—</td></tr></tbody></table><p>详见<a href="https://element-plus.gitee.io/zh-CN/component/button.html#button-%E5%B1%9E%E6%80%A7">https://element-plus.gitee.io/zh-CN/component/button.html#button-%E5%B1%9E%E6%80%A7</a></p><h4 id="el-dialog"><a href="#el-dialog" class="headerlink" title="el-dialog"></a>el-dialog</h4><table><thead><tr><th align="left">属性名</th><th align="left">说明</th><th align="left">类型</th><th align="left">可选值</th><th align="left">默认值</th></tr></thead><tbody><tr><td align="left">model-value / v-model</td><td align="left">是否显示 Dialog</td><td align="left">boolean</td><td align="left">—</td><td align="left">—</td></tr><tr><td align="left">title</td><td align="left">Dialog 对话框 Dialog 的标题, 也可通过具名 slot (见下表)传入</td><td align="left">string</td><td align="left">—</td><td align="left">—</td></tr><tr><td align="left">width</td><td align="left">Dialog 的宽度</td><td align="left">string / number</td><td align="left">—</td><td align="left">50%</td></tr><tr><td align="left">fullscreen</td><td align="left">是否为全屏 Dialog</td><td align="left">boolean</td><td align="left">—</td><td align="left">false</td></tr><tr><td align="left">top</td><td align="left">Dialog CSS 中的 margin-top 值</td><td align="left">string</td><td align="left">—</td><td align="left">15vh</td></tr><tr><td align="left">modal</td><td align="left">是否需要遮罩层</td><td align="left">boolean</td><td align="left">—</td><td align="left">true</td></tr><tr><td align="left">lock-scroll</td><td align="left">是否在 Dialog 出现时将 body 滚动锁定</td><td align="left">boolean</td><td align="left">—</td><td align="left">true</td></tr><tr><td align="left">open-delay</td><td align="left">Dialog 打开的延时时间,单位毫秒</td><td align="left">number</td><td align="left">—</td><td align="left">0</td></tr><tr><td align="left">close-delay</td><td align="left">Dialog 关闭的延时时间,单位毫秒</td><td align="left">number</td><td align="left">—</td><td align="left">0</td></tr><tr><td align="left">close-on-click-modal</td><td align="left">是否可以通过点击 modal 关闭 Dialog</td><td align="left">boolean</td><td align="left">—</td><td align="left">true</td></tr><tr><td align="left">close-on-press-escape</td><td align="left">是否可以通过按下 ESC 关闭 Dialog</td><td align="left">boolean</td><td align="left">—</td><td align="left">true</td></tr><tr><td align="left">show-close</td><td align="left">是否显示关闭按钮</td><td align="left">boolean</td><td align="left">—</td><td align="left">true</td></tr><tr><td align="left">before-close</td><td align="left">关闭前的回调,会暂停 Dialog 的关闭. 回调函数内执行 done 参数方法的时候才是真正关闭对话框的时候.</td><td align="left">Function(done) (done 用来关闭 Dialog)</td><td align="left">—</td><td align="left">—</td></tr></tbody></table><p><a href="https://element-plus.gitee.io/zh-CN/component/dialog.html#%E5%B1%9E%E6%80%A7">https://element-plus.gitee.io/zh-CN/component/dialog.html#%E5%B1%9E%E6%80%A7</a></p><h4 id="el-drawer"><a href="#el-drawer" class="headerlink" title="el-drawer*"></a>el-drawer*</h4><h3 id="el-upload"><a href="#el-upload" class="headerlink" title="el-upload*"></a>el-upload*</h3><h4 id="Form"><a href="#Form" class="headerlink" title="Form"></a>Form</h4><p><strong>FormInstance</strong>类型,可以辅助vue3中的ref属性为dom操作提供便利,</p><p>方法</p><ul><li><p>validate</p><pre class="language-typescript" data-language="typescript"><code class="language-typescript"><span class="token comment">//类型</span><span class="token punctuation">(</span>callback<span class="token operator">?</span><span class="token operator">:</span> <span class="token punctuation">(</span>isValid<span class="token operator">:</span> <span class="token builtin">boolean</span><span class="token punctuation">,</span> invalidFields<span class="token operator">?</span><span class="token operator">:</span> ValidateFieldsError<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">void</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token builtin">Promise</span><span class="token operator"><</span><span class="token keyword">void</span><span class="token operator">></span></code></pre></li><li><p>validator:自定义校验规则</p><p>为指定字段定制验证函数</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">const</span> fields <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">field</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token function">validator</span><span class="token punctuation">(</span><span class="token parameter">rule<span class="token punctuation">,</span> value<span class="token punctuation">,</span> callback</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> value <span class="token operator">===</span> <span class="token string">'test'</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">message</span><span class="token operator">:</span> <span class="token string">'Value is not equal to "test".'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">field2</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token function">validator</span><span class="token punctuation">(</span><span class="token parameter">rule<span class="token punctuation">,</span> value<span class="token punctuation">,</span> callback</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>value<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> is not equal to 'test'.</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">arrField</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token function">validator</span><span class="token punctuation">(</span><span class="token parameter">rule<span class="token punctuation">,</span> value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">[</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">'Message 1'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">'Message 2'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre><p>asyncValidator</p><p>详见<a href="https://github.com/yiminghe/async-validator#options">https://github.com/yiminghe/async-validator#options</a></p></li><li><p><strong>FormItemRule</strong></p><pre class="language-typescript" data-language="typescript"><code class="language-typescript"><span class="token keyword">export</span> <span class="token keyword">declare</span> <span class="token keyword">type</span> <span class="token class-name">Arrayable<span class="token operator"><</span><span class="token constant">T</span><span class="token operator">></span></span> <span class="token operator">=</span> <span class="token constant">T</span> <span class="token operator">|</span> <span class="token constant">T</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token keyword">export</span> <span class="token keyword">interface</span> <span class="token class-name">FormItemRule</span> <span class="token keyword">extends</span> <span class="token class-name">RuleItem</span> <span class="token punctuation">{</span> trigger<span class="token operator">?</span><span class="token operator">:</span> Arrayable<span class="token operator"><</span><span class="token builtin">string</span><span class="token operator">></span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token keyword">export</span> <span class="token keyword">interface</span> <span class="token class-name">RuleItem</span> <span class="token punctuation">{</span> type<span class="token operator">?</span><span class="token operator">:</span> RuleType<span class="token punctuation">;</span> required<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">boolean</span><span class="token punctuation">;</span> pattern<span class="token operator">?</span><span class="token operator">:</span> RegExp <span class="token operator">|</span> <span class="token builtin">string</span><span class="token punctuation">;</span> min<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> max<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> len<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> <span class="token keyword">enum</span><span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">Array</span><span class="token operator"><</span><span class="token builtin">string</span> <span class="token operator">|</span> <span class="token builtin">number</span> <span class="token operator">|</span> <span class="token builtin">boolean</span> <span class="token operator">|</span> <span class="token keyword">null</span> <span class="token operator">|</span> <span class="token keyword">undefined</span><span class="token operator">></span><span class="token punctuation">;</span> whitespace<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">boolean</span><span class="token punctuation">;</span> fields<span class="token operator">?</span><span class="token operator">:</span> Record<span class="token operator"><</span><span class="token builtin">string</span><span class="token punctuation">,</span> Rule<span class="token operator">></span><span class="token punctuation">;</span> options<span class="token operator">?</span><span class="token operator">:</span> ValidateOption<span class="token punctuation">;</span> defaultField<span class="token operator">?</span><span class="token operator">:</span> Rule<span class="token punctuation">;</span> transform<span class="token operator">?</span><span class="token operator">:</span> <span class="token punctuation">(</span>value<span class="token operator">:</span> Value<span class="token punctuation">)</span> <span class="token operator">=></span> Value<span class="token punctuation">;</span> message<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">string</span> <span class="token operator">|</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>a<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token builtin">string</span><span class="token punctuation">)</span><span class="token punctuation">;</span> asyncValidator<span class="token operator">?</span><span class="token operator">:</span> <span class="token punctuation">(</span>rule<span class="token operator">:</span> InternalRuleItem<span class="token punctuation">,</span> value<span class="token operator">:</span> Value<span class="token punctuation">,</span> <span class="token function-variable function">callback</span><span class="token operator">:</span> <span class="token punctuation">(</span>error<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">string</span> <span class="token operator">|</span> Error<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">void</span><span class="token punctuation">,</span> source<span class="token operator">:</span> Values<span class="token punctuation">,</span> options<span class="token operator">:</span> ValidateOption<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">void</span> <span class="token operator">|</span> <span class="token builtin">Promise</span><span class="token operator"><</span><span class="token keyword">void</span><span class="token operator">></span><span class="token punctuation">;</span> validator<span class="token operator">?</span><span class="token operator">:</span> <span class="token punctuation">(</span>rule<span class="token operator">:</span> InternalRuleItem<span class="token punctuation">,</span> value<span class="token operator">:</span> Value<span class="token punctuation">,</span> <span class="token function-variable function">callback</span><span class="token operator">:</span> <span class="token punctuation">(</span>error<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">string</span> <span class="token operator">|</span> Error<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">void</span><span class="token punctuation">,</span> source<span class="token operator">:</span> Values<span class="token punctuation">,</span> options<span class="token operator">:</span> ValidateOption<span class="token punctuation">)</span> <span class="token operator">=></span> SyncValidateResult <span class="token operator">|</span> <span class="token keyword">void</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre></li></ul><h3 id="Icon"><a href="#Icon" class="headerlink" title="Icon"></a>Icon</h3><p><a href="https://element-plus.gitee.io/zh-CN/component/icon.html">https://element-plus.gitee.io/zh-CN/component/icon.html</a></p><h4 id="ElMessage"><a href="#ElMessage" class="headerlink" title="ElMessage"></a>ElMessage</h4><p>配置项</p><table><thead><tr><th align="left">属性</th><th align="left">说明</th><th align="left">类型</th><th align="left">默认值</th></tr></thead><tbody><tr><td align="left"><code>message</code></td><td align="left">消息文字</td><td align="left">`string</td><td align="left">VNode</td></tr><tr><td align="left"><code>type</code></td><td align="left">消息类型</td><td align="left">`’success’</td><td align="left">‘warning’</td></tr><tr><td align="left"><code>icon</code></td><td align="left">自定义图标,该属性会覆盖 <code>type</code> 的图标。</td><td align="left">`string</td><td align="left">Component`</td></tr><tr><td align="left"><code>dangerouslyUseHTMLString</code></td><td align="left">是否将 message 属性作为 HTML 片段处理</td><td align="left"><code>boolean</code></td><td align="left"><code>false</code></td></tr><tr><td align="left"><code>custom-class</code></td><td align="left">自定义类名</td><td align="left"><code>string</code></td><td align="left">—</td></tr><tr><td align="left"><code>duration</code></td><td align="left">显示时间,单位为毫秒。 设为 0 则不会自动关闭</td><td align="left"><code>number</code></td><td align="left"><code>3000</code></td></tr><tr><td align="left"><code>show-close</code></td><td align="left">是否显示关闭按钮</td><td align="left"><code>boolean</code></td><td align="left"><code>false</code></td></tr><tr><td align="left"><code>center</code></td><td align="left">文字是否居中</td><td align="left"><code>boolean</code></td><td align="left"><code>false</code></td></tr><tr><td align="left"><code>on-close</code></td><td align="left">关闭时的回调函数, 参数为被关闭的 message 实例</td><td align="left"><code>function</code></td><td align="left">—</td></tr><tr><td align="left"><code>offset</code></td><td align="left">Message 距离窗口顶部的偏移量</td><td align="left"><code>number</code></td><td align="left"><code>20</code></td></tr><tr><td align="left"><code>appendTo</code></td><td align="left">设置组件的根元素</td><td align="left">`string</td><td align="left">HTMLElement`</td></tr><tr><td align="left"><code>grouping</code></td><td align="left">合并内容相同的消息,不支持 VNode 类型的消息</td><td align="left"><code>boolean</code></td><td align="left"><code>false</code></td></tr></tbody></table><p>例子</p><pre class="language-typescript" data-language="typescript"><code class="language-typescript"><span class="token function">ElMessage</span><span class="token punctuation">(</span><span class="token punctuation">{</span> message<span class="token operator">:</span> data<span class="token punctuation">.</span>error<span class="token punctuation">,</span> type<span class="token operator">:</span> <span class="token string">'error'</span><span class="token punctuation">,</span> duration<span class="token operator">:</span> <span class="token number">1.5</span> <span class="token operator">*</span> <span class="token number">1000</span><span class="token punctuation">,</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//显示错误信息</span><span class="token keyword">const</span> <span class="token function-variable function">open4</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> ElMessage<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">'Oops, this is a error message.'</span><span class="token punctuation">)</span><span class="token punctuation">}</span></code></pre><h2 id="底层"><a href="#底层" class="headerlink" title="底层"></a>底层</h2><h3 id="compiler-sfc"><a href="#compiler-sfc" class="headerlink" title="compiler-sfc"></a>compiler-sfc</h3><p>vue的直属目录下有一个 <code>compiler-sfc</code></p><p><code>compiler-sfc</code>,这个文件夹里面的内容主要是能够编译 <code>template</code>,<code>style</code>, <code>script(setup)</code>的字符串,生成对应的内容。</p><p>分别对应的是 <code>compileTemplate</code>,<code>compileStyle</code>, <code>compileScript</code></p>]]></content>
<summary type="html"><blockquote>
<p>持续更新</p>
</blockquote>
<h3 id=""><a href="#" class="headerlink" title=""></a></h3><h2 id="基础内容"><a href="#基础内容" class="heade</summary>
<category term="Frontend" scheme="https://hhumar.com/categories/Frontend/"/>
<category term="Web" scheme="https://hhumar.com/tags/Web/"/>
<category term="Vue" scheme="https://hhumar.com/tags/Vue/"/>
</entry>
<entry>
<title>TypeScript</title>
<link href="https://hhumar.com/2022/11/04/ts/"/>
<id>https://hhumar.com/2022/11/04/ts/</id>
<published>2022-11-03T16:21:24.000Z</published>
<updated>2022-12-07T16:02:20.626Z</updated>
<content type="html"><![CDATA[<blockquote><p>持续更新</p></blockquote><h3 id=""><a href="#" class="headerlink" title=""></a></h3><p><strong>我们需要在类型的严格性和开发的便利性之间掌握平衡</strong></p><p>“reaching the right balance and making the right exceptions is the essence of how successful programming languages are designed.”</p><h2 id="基础"><a href="#基础" class="headerlink" title="基础"></a>基础</h2><p>非严格模式下 undefined 和 null 可以赋值给其他类型的值,也就是可以作为其它类型的子类型</p><p>如果定义的时候没有赋值,不管之后有没有赋值,都会被推断成 <code>any</code> 类型而完全不被类型检查</p><p>typeof 能直接获取元素深层类型</p><pre class="language-typescript" data-language="typescript"><code class="language-typescript"><span class="token keyword">const</span> Message <span class="token operator">=</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> <span class="token string">"jimmy"</span><span class="token punctuation">,</span> age<span class="token operator">:</span> <span class="token number">18</span><span class="token punctuation">,</span> address<span class="token operator">:</span> <span class="token punctuation">{</span> province<span class="token operator">:</span> <span class="token string">'四川'</span><span class="token punctuation">,</span> city<span class="token operator">:</span> <span class="token string">'成都'</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token keyword">type</span> <span class="token class-name">message</span> <span class="token operator">=</span> <span class="token keyword">typeof</span> Message<span class="token punctuation">;</span><span class="token comment">/* type message = { name: string; age: number; address: { province: string; city: string; };}*/</span></code></pre><h4 id="never类型"><a href="#never类型" class="headerlink" title="never类型"></a>never类型</h4><p>never 和 void 之间的区别是void 意味着至少要返回一个 undefined 或者 null ,而 never 意味着不会正常执行到 函数的终点。</p><p>! 特殊用法</p><ul><li>强制链式调用</li></ul><pre class="language-none"><code class="language-none">// 这里 Error对象定义的stack是可选参数,如果这样写的话编译器会提示// 出错 TS2532: Object is possibly 'undefined'.new Error().stack.split('\n');// 我们确信这个字段100%出现,那么就可以添加!,强调这个字段一定存在new Error().stack!.split('\n');</code></pre><ul><li>用在赋值的内容后时,使null和undefined类型可以赋值给其他类型并通过编译</li></ul><pre class="language-none"><code class="language-none">// 由于x是可选的,因此parma.x的类型为number | undefined,无法传递给number类型的y,因此需要用x!interface IDemo { x?: number}let y:numberconst demo = (parma: IDemo) => { y = parma.x! return y}</code></pre><p>? 特殊用法</p><ul><li>当使用A对象属性A.B时,如果无法确定A是否为空,则需要用A?.B,表示当A有值的时候才去访问B属性,没有值的时候就不去访问,如果不使用?则会报错</li></ul><pre class="language-none"><code class="language-none">// 由于函数参数可选,因此parma无法确定是否拥有,所以无法正常使用parma.x,使用parma?.x向编译器假设此时parma不为空且为IDemo类型,同时parma?.x无法保证非空,因此使用parma?.x!来保证了整体通过编译interface IDemo { x: number}let y:numberconst demo = (parma?: IDemo) => { y = parma?.x! console.log(parma?.x) // 只是单纯调用属性时就无需! return y} // 如果使用y = parma!.x!是会报错的,因为当parma为空时,是不拥有x属性的,会报找不到x的错误</code></pre><h3 id="支持接口:"><a href="#支持接口:" class="headerlink" title="支持接口:"></a>支持接口:</h3><p>一个简单的接口,<code>SquareConfig</code>可以有任意数量的属性,并且只要它们不是<code>color</code>和<code>width</code>,那么就无所谓它们的类型是什么。</p><pre class="language-none"><code class="language-none">interface SquareConfig { color?: string; width?: number; [propName: string]: any;}</code></pre><h3 id="定义数组"><a href="#定义数组" class="headerlink" title="定义数组"></a>定义数组</h3><pre class="language-none"><code class="language-none">let arr1: number[] = [1,2,3];let arr2: Array<number> = [1,2,3];元组,元素数量和各位置元素类型确定,均不可违背let arr3: [string,number,boolean] = [1,'1',true];</code></pre><h3 id="联合类型(Union-Types)"><a href="#联合类型(Union-Types)" class="headerlink" title="联合类型(Union Types)"></a>联合类型(Union Types)</h3><p>表示取值可以为多种类型中的一种。</p><p>当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候,我们<strong>只能访问此联合类型的所有类型里共有的属性或方法</strong></p><pre class="language-none"><code class="language-none">function getLength(something: string | number): number { return something.length;}// index.ts(2,22): error TS2339: Property 'length' does not exist on type 'string | number'.// Property 'length' does not exist on type 'number'.</code></pre><p>联合类型的变量在被赋值的时候,会根据类型推论的规则推断出一个类型,确定类型后也就可以使用其特有的属性和方法了。</p><h3 id="函数类型"><a href="#函数类型" class="headerlink" title="函数类型"></a>函数类型</h3><p>支持可选参数</p><pre class="language-none"><code class="language-none">function e(arg1:number,arg2?:number){}</code></pre><p><strong>可选参数后面不允许再出现必需参数</strong></p><p>允许给函数的参数添加默认值,<strong>TypeScript 会将添加了默认值的参数识别为可选参数</strong>,此时上一条限制不再存在</p><pre class="language-none"><code class="language-none">function buildName(firstName: string = 'Tom', lastName: string) { return firstName + ' ' + lastName;}let tomcat = buildName('Tom', 'Cat');let cat = buildName(undefined, 'Cat');</code></pre><p>关于剩余参数,其实也就相当于多一个数组参数在末尾</p><pre class="language-none"><code class="language-none">function push(array: any[], ...items: any[]) { items.forEach(function(item) { array.push(item); });}let a = [];push(a, 1, 2, 3);</code></pre><p>函数定义还支持重载,当输入参数类型不同时按照程序逻辑进行不同的操作</p><pre class="language-none"><code class="language-none">function reverse(x: number): number;function reverse(x: string): string;function reverse(x: number | string): number | string | void { if (typeof x === 'number') { return Number(x.toString().split('').reverse().join('')); } else if (typeof x === 'string') { return x.split('').reverse().join(''); }}</code></pre><h3 id="类型断言"><a href="#类型断言" class="headerlink" title="类型断言"></a>类型断言</h3><pre class="language-none"><code class="language-none">两种写法值 as 类型or<类型>值</code></pre><p>当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候,我们<strong>只能访问此联合类型的所有类型中共有的属性或方法</strong>。但是通过类型断言我们能在还不确定类型的时候就访问其中一个类型特有的属性或方法</p><pre class="language-none"><code class="language-none">interface Cat { name: string; run(): void;}interface Fish { name: string; swim(): void;}function isFish(animal: Cat | Fish) { if (typeof (animal as Fish).swim === 'function') { return true; } return false;}</code></pre><p>即作用为将一个联合类型断言为其中一个类型,同样还有其它作用:将一个父类断言为更加具体的派生类(此种情况下使用 instanceof 可能会更贴切),将任何一个类型断言为 any,将 any 断言为一个具体的类型</p><pre class="language-typescript" data-language="typescript"><code class="language-typescript"><span class="token keyword">class</span> <span class="token class-name">ApiError</span> <span class="token keyword">extends</span> <span class="token class-name">Error</span> <span class="token punctuation">{</span> code<span class="token operator">:</span> <span class="token builtin">number</span> <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token keyword">class</span> <span class="token class-name">HttpError</span> <span class="token keyword">extends</span> <span class="token class-name">Error</span> <span class="token punctuation">{</span> statusCode<span class="token operator">:</span> <span class="token builtin">number</span> <span class="token operator">=</span> <span class="token number">200</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token keyword">function</span> <span class="token function">isApiError</span><span class="token punctuation">(</span>error<span class="token operator">:</span> Error<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>error <span class="token keyword">instanceof</span> <span class="token class-name">ApiError</span><span class="token punctuation">)</span> <span class="token comment">//error as ApiError</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><p>将一个变量断言为 <code>any</code> 可以说是解决 TypeScript 中类型问题的最后一个手段。</p><p><strong>它极有可能掩盖了真正的类型错误,所以如果不是非常确定,就不要使用 <code>as any</code>。</strong></p><pre class="language-typescript" data-language="typescript"><code class="language-typescript"><span class="token keyword">function</span> <span class="token function">getCacheData</span><span class="token punctuation">(</span>key<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">any</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span>window <span class="token keyword">as</span> <span class="token builtin">any</span><span class="token punctuation">)</span><span class="token punctuation">.</span>cache<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token keyword">interface</span> <span class="token class-name">Cat</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span> <span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token keyword">const</span> tom <span class="token operator">=</span> <span class="token function">getCacheData</span><span class="token punctuation">(</span><span class="token string">'tom'</span><span class="token punctuation">)</span> <span class="token keyword">as</span> Cat<span class="token punctuation">;</span>tom<span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p><code>any as</code>上例中调用完 getCacheData 后把返回值限定为 Cat ,明确后续代码中的 tom 类型。</p><p>类型声明比类型断言更加严格,当声明的类型兼容值的类型才使赋值语句成立。而类型断言中等号左边和右边的类型任一兼容对方即可。</p><pre class="language-none"><code class="language-none">interface Animal { name: string;}interface Cat { name: string; run(): void;}const animal: Animal = { name: 'tom'};let tom: Cat = animal;//改为 let tom = animal as Cat; 不会报错// index.ts:12:5 - error TS2741: Property 'run' is missing in type 'Animal' but required in type 'Cat'.</code></pre><h3 id="类与接口"><a href="#类与接口" class="headerlink" title="类与接口"></a>类与接口</h3><p><strong>implements</strong><br>实现,一个新的类,从父类或者接口实现所有的属性和方法,同时可以重写属性和方法,包含一些新的功能</p><p><strong>extends</strong><br>继承,一个新的接口或者类,从父类或者接口继承所有的属性和方法,不可以重写属性,但可以重写方法。</p><p>存在 constructor 时需要在其中调用 super 方法(相当于调用父类的constructor)</p><pre class="language-none"><code class="language-none">interface Alarm { alert(): void;}class Door {}class SecurityDoor extends Door implements Alarm { alert() { console.log('SecurityDoor alert'); }}class Car implements Alarm { alert() { console.log('Car alert'); }}</code></pre><p>抽象类:专用于子类实例化和实现其中的抽象方法,本身不可实例化。抽象类还包括抽象属性(不常用)和抽象方法,不会实现内容,留给子类实现。</p><pre class="language-typescript" data-language="typescript"><code class="language-typescript"><span class="token keyword">abstract</span> <span class="token keyword">class</span> <span class="token class-name">Animal</span><span class="token punctuation">{</span><span class="token keyword">abstract</span> <span class="token function">add</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token keyword">class</span> <span class="token class-name">Dog</span> <span class="token keyword">extends</span> <span class="token class-name">Animal</span><span class="token punctuation">{</span> <span class="token function">add</span><span class="token punctuation">(</span>a<span class="token operator">:</span><span class="token builtin">number</span><span class="token punctuation">,</span>b<span class="token operator">:</span><span class="token builtin">number</span><span class="token punctuation">)</span><span class="token operator">:</span><span class="token builtin">number</span><span class="token punctuation">{</span> <span class="token keyword">return</span> a<span class="token operator">+</span>b<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><h2 id="进阶"><a href="#进阶" class="headerlink" title="进阶"></a>进阶</h2><h3 id="泛型"><a href="#泛型" class="headerlink" title="泛型"></a>泛型</h3><p>指代任意输入的类型,保持在其它地方使用该类型的一致性</p><pre class="language-typescript" data-language="typescript"><code class="language-typescript"><span class="token keyword">function</span> <span class="token generic-function"><span class="token function">swap</span><span class="token generic class-name"><span class="token operator"><</span><span class="token constant">T</span><span class="token punctuation">,</span> <span class="token constant">U</span><span class="token operator">></span></span></span><span class="token punctuation">(</span>tuple<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token constant">T</span><span class="token punctuation">,</span> <span class="token constant">U</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token constant">U</span><span class="token punctuation">,</span> <span class="token constant">T</span><span class="token punctuation">]</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">[</span>tuple<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span> tuple<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token function">swap</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token number">7</span><span class="token punctuation">,</span> <span class="token string">'seven'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// ['seven', 7]</span></code></pre><p>泛型约束可以</p><h2 id="reflection"><a href="#reflection" class="headerlink" title="reflection"></a>reflection</h2><p>proxy 接口</p><pre class="language-text" data-language="text"><code class="language-text">interface ProxyHandler<T extends object> { getPrototypeOf? (target: T): object | null; setPrototypeOf? (target: T, v: any): boolean; isExtensible? (target: T): boolean; preventExtensions? (target: T): boolean; getOwnPropertyDescriptor? (target: T, p: PropertyKey): PropertyDescriptor | undefined; has? (target: T, p: PropertyKey): boolean; get? (target: T, p: PropertyKey, receiver: any): any; set? (target: T, p: PropertyKey, value: any, receiver: any): boolean; deleteProperty? (target: T, p: PropertyKey): boolean; defineProperty? (target: T, p: PropertyKey, attributes: PropertyDescriptor): boolean; ownKeys? (target: T): PropertyKey[]; apply? (target: T, thisArg: any, argArray?: any): any; construct? (target: T, argArray: any, newTarget?: any): object;}interface ProxyConstructor { revocable<T extends object>(target: T, handler: ProxyHandler<T>): { proxy: T; revoke: () => void; }; new <T extends object>(target: T, handler: ProxyHandler<T>): T;}declare var Proxy: ProxyConstructor;</code></pre><h2 id="修饰符"><a href="#修饰符" class="headerlink" title="修饰符"></a>修饰符</h2><h3 id="static"><a href="#static" class="headerlink" title="static"></a>static</h3><p><strong>只属于类自己的,不需要实例化即可引用</strong>,<strong>不能通过new出来的实例访问类的静态变量或方法</strong>,<strong>类中访问自己的静态属性,不能用this,只能用类名。</strong></p><pre class="language-none"><code class="language-none">class Test { static myName: string = "lle"; static changeName(): void { console.log("=========>>>", "hello"); } this.myName = "change name"; ----------->>>>>>>>>> ❌❌❌ 不可以 Test.myName = "change name"; ----------->>>>> ✔️✔️✔️这样就是OK的}Test.changeName(); ------------->>>>>>>>>> ✔️✔️✔️这样就是OK的let instance = new Test();instance.changName(); ----------->>>>>>>>>> ❌❌❌ 不可以</code></pre><h2 id="Utility-Types"><a href="#Utility-Types" class="headerlink" title="Utility Types"></a>Utility Types</h2><pre class="language-typescript" data-language="typescript"><code class="language-typescript"><span class="token comment">/** * Make all properties in T optional */</span><span class="token keyword">type</span> <span class="token class-name">Partial<span class="token operator"><</span><span class="token constant">T</span><span class="token operator">></span></span> <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token punctuation">[</span><span class="token constant">P</span> <span class="token keyword">in</span> <span class="token keyword">keyof</span> <span class="token constant">T</span><span class="token punctuation">]</span><span class="token operator">?</span><span class="token operator">:</span> <span class="token constant">T</span><span class="token punctuation">[</span><span class="token constant">P</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">;</span><span class="token comment">/** * Make all properties in T readonly */</span><span class="token keyword">type</span> <span class="token class-name">Readonly<span class="token operator"><</span><span class="token constant">T</span><span class="token operator">></span></span> <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token keyword">readonly</span> <span class="token punctuation">[</span><span class="token constant">P</span> <span class="token keyword">in</span> <span class="token keyword">keyof</span> <span class="token constant">T</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token constant">T</span><span class="token punctuation">[</span><span class="token constant">P</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">;</span><span class="token comment">/** * From T, pick a set of properties whose keys are in the union K */</span><span class="token keyword">type</span> <span class="token class-name">Pick<span class="token operator"><</span><span class="token constant">T</span><span class="token punctuation">,</span> <span class="token constant">K</span> <span class="token keyword">extends</span> <span class="token keyword">keyof</span> <span class="token constant">T</span><span class="token operator">></span></span> <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token punctuation">[</span><span class="token constant">P</span> <span class="token keyword">in</span> <span class="token constant">K</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token constant">T</span><span class="token punctuation">[</span><span class="token constant">P</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">;</span><span class="token comment">/** * Construct a type with a set of properties K of type T */</span><span class="token keyword">type</span> <span class="token class-name">Record<span class="token operator"><</span><span class="token constant">K</span> <span class="token keyword">extends</span> <span class="token keyword">keyof</span> <span class="token builtin">any</span><span class="token punctuation">,</span> <span class="token constant">T</span><span class="token operator">></span></span> <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token punctuation">[</span><span class="token constant">P</span> <span class="token keyword">in</span> <span class="token constant">K</span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token constant">T</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre><h3 id="Partial-lt-Type-gt"><a href="#Partial-lt-Type-gt" class="headerlink" title="Partial<Type>"></a>Partial<Type></h3><p>构造一个类型,其中 Type 的所有属性都设置为可选。此实用工具将返回一个表示给定 type 的所有子集的类型。</p><pre class="language-typescript" data-language="typescript"><code class="language-typescript"><span class="token keyword">type</span> <span class="token class-name">Coord</span> <span class="token operator">=</span> Partial<span class="token operator"><</span>Record<span class="token operator"><</span><span class="token string">'x'</span> <span class="token operator">|</span> <span class="token string">'y'</span><span class="token punctuation">,</span> <span class="token builtin">number</span><span class="token operator">>></span><span class="token punctuation">;</span><span class="token comment">// 等同于</span><span class="token keyword">type</span> <span class="token class-name">Coord</span> <span class="token operator">=</span> <span class="token punctuation">{</span>x<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span>y<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><h3 id="Pick"><a href="#Pick" class="headerlink" title="Pick"></a>Pick</h3><pre class="language-typescript" data-language="typescript"><code class="language-typescript"><span class="token keyword">type</span> <span class="token class-name">Coord</span> <span class="token operator">=</span> Record<span class="token operator"><</span><span class="token string">'x'</span> <span class="token operator">|</span> <span class="token string">'y'</span><span class="token punctuation">,</span> <span class="token builtin">number</span><span class="token operator">></span><span class="token punctuation">;</span><span class="token keyword">type</span> <span class="token class-name">CoordX</span> <span class="token operator">=</span> Pick<span class="token operator"><</span>Coord<span class="token punctuation">,</span> <span class="token string">'x'</span><span class="token operator">></span><span class="token punctuation">;</span><span class="token comment">// 等用于</span><span class="token keyword">type</span> <span class="token class-name">CoordX</span> <span class="token operator">=</span> <span class="token punctuation">{</span>x<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><h3 id="Required-lt-Type-gt"><a href="#Required-lt-Type-gt" class="headerlink" title="Required<Type>"></a>Required<Type></h3><p>partial的反义,返回给定 type 的超集</p><h3 id="Readonly-lt-Type-gt"><a href="#Readonly-lt-Type-gt" class="headerlink" title="Readonly<Type>"></a>Readonly<Type></h3><p>仅读不可更改类型。<strong>只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候</strong></p><pre class="language-typescript" data-language="typescript"><code class="language-typescript"><span class="token keyword">type</span> <span class="token class-name">Coord</span> <span class="token operator">=</span> Readonly<span class="token operator"><</span>Record<span class="token operator"><</span><span class="token string">'x'</span> <span class="token operator">|</span> <span class="token string">'y'</span><span class="token punctuation">,</span> <span class="token builtin">number</span><span class="token operator">>></span><span class="token punctuation">;</span><span class="token comment">// 等同于</span><span class="token keyword">type</span> <span class="token class-name">Coord</span> <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token keyword">readonly</span> x<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> <span class="token keyword">readonly</span> y<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token comment">// 如果进行了修改,则会报错:</span><span class="token keyword">const</span> c<span class="token operator">:</span> Coord <span class="token operator">=</span> <span class="token punctuation">{</span> x<span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> y<span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>c<span class="token punctuation">.</span>x <span class="token operator">=</span> <span class="token number">2</span><span class="token punctuation">;</span> <span class="token comment">// Error: Cannot assign to 'x' because it is a read-only property.</span></code></pre><h3 id="Record-lt-Keys-Type-gt"><a href="#Record-lt-Keys-Type-gt" class="headerlink" title="Record<Keys, Type>"></a>Record<Keys, Type></h3><p>构造一个对象类型,其属性键为 Keys,其属性值为 Type。此实用工具可用于将一种类型的属性映射到另一种类型。</p><pre class="language-typescript" data-language="typescript"><code class="language-typescript"><span class="token keyword">type</span> <span class="token class-name">Coord</span> <span class="token operator">=</span> Record<span class="token operator"><</span><span class="token string">'x'</span> <span class="token operator">|</span> <span class="token string">'y'</span><span class="token punctuation">,</span> <span class="token builtin">number</span><span class="token operator">></span><span class="token punctuation">;</span><span class="token comment">// 等同于</span><span class="token keyword">type</span> <span class="token class-name">Coord</span> <span class="token operator">=</span> <span class="token punctuation">{</span>x<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span>y<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><h2 id="编译配置"><a href="#编译配置" class="headerlink" title="编译配置"></a>编译配置</h2><p>直接使用以下命令对指定文件进行编译会生成在当前目录下,忽略tsconfig 的配置文件</p><pre class="language-none"><code class="language-none">tsc 指定文件</code></pre><h3 id="tsconfig配置信息"><a href="#tsconfig配置信息" class="headerlink" title="tsconfig配置信息"></a>tsconfig配置信息</h3><p><strong>target –</strong></p><p>就是<a href="https://so.csdn.net/so/search?q=TypeScript&spm=1001.2101.3001.7020">TypeScript</a>文件编译后生成的javascript文件里的语法应该遵循哪个JavaScript的版本。可选项为:<code>"ES5"</code>, <code>"ES6"</code>/ <code>"ES2015"</code>, <code>"ES2016"</code>, <code>"ES2017"</code>或 <code>"ESNext"</code></p><p><strong>module –</strong></p><p>就是你的TypeScript文件中的module,采用何种方式实现,可选项为:<code>"None"</code>, <code>"CommonJS"</code>, <code>"AMD"</code>, <code>"System"</code>, <code>"UMD"</code>, <code>"ES6"</code>或 <code>"ES2015"。</code></p>]]></content>
<summary type="html"><blockquote>
<p>持续更新</p>
</blockquote>
<h3 id=""><a href="#" class="headerlink" title=""></a></h3><p><strong>我们需要在类型的严格性和开发的便利性之间掌握平衡</stron</summary>
<category term="常用编程语言基础知识" scheme="https://hhumar.com/categories/%E5%B8%B8%E7%94%A8%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/"/>
<category term="TypeScript" scheme="https://hhumar.com/tags/TypeScript/"/>
</entry>
<entry>
<title>Frontend Engineering</title>
<link href="https://hhumar.com/2022/11/03/frontend-engineering/"/>
<id>https://hhumar.com/2022/11/03/frontend-engineering/</id>
<published>2022-11-02T17:24:13.000Z</published>
<updated>2022-12-07T15:59:52.815Z</updated>
<content type="html"><![CDATA[<blockquote><p>持续更新</p></blockquote><h3 id=""><a href="#" class="headerlink" title=""></a></h3><h2 id="项目构建"><a href="#项目构建" class="headerlink" title="项目构建"></a>项目构建</h2><h3 id="vue-cli"><a href="#vue-cli" class="headerlink" title="vue cli"></a>vue cli</h3><pre class="language-none"><code class="language-none">npm install -g @vue/clinpm install vue@nextvue create project-name</code></pre><h3 id="vite"><a href="#vite" class="headerlink" title="vite"></a>vite</h3><pre class="language-none"><code class="language-none">npm create vite@latest//oryarn create vite//orpnpm create vite</code></pre><h2 id="包管理"><a href="#包管理" class="headerlink" title="包管理"></a>包管理</h2><p>版本号:x.x.x</p><ul><li><em>主版本号: 当API发生改变,并与之前的版本不兼容的时候</em></li><li><em>次版本号: 当增加了功能,但是向后兼容的时候</em></li><li><em>补丁版本号: 当做了向后兼容的缺陷修复的时候</em></li></ul><h3 id="npm"><a href="#npm" class="headerlink" title="npm"></a>npm</h3><p>Node Package Manager</p><p>dependencies(生产环境)和 devDependencies(开发环境),前者是项目运行时所需要的包,后者是开发时需要的包例如打包项目的 webpack </p><pre class="language-powershell" data-language="powershell"><code class="language-powershell">npm install <span class="token operator">--</span><span class="token function">save-dev</span> packageName<span class="token comment"># 开发环境简写</span>npm i <span class="token operator">-</span>D packageNamenpm install <span class="token operator">--</span>save packageName<span class="token comment"># 生产环境简写,也可以不带S</span>npm i <span class="token operator">-</span>S packageName</code></pre><ul><li><code>devDependencies</code> 里面的依赖只用于开发环境,不用于生产环境。而 <code>dependencies</code> 依赖的包不仅开发环境能使用,生产环境也能使用。</li><li>两种环境的的指定方式是通过配置文件中的<code>NODE_ENV=developement</code>或<code>NODE_ENV=production</code>来指定是开发还是生产环境的。</li><li>使用的一些构建工具例如<code>glup、webpack</code>这些只是在开发中使用的包,上线以后就和他们没关系了,所以将它写入<code>devDependencies</code></li></ul><p>install的tag</p><p>标签可以用来提供一个别名,而不是版本号。</p><p>例如,一个项目可能会选择有多个开发流,并为每个开发流使用不同的标签,例如,stable、beta、dev、canary。</p><p>默认情况下,latest 标签被npm用来识别软件包的当前版本,npm install <pkg>(没有任何@<version>或@<tag>指定符)会安装 latest 标签。通常情况下,项目只对稳定的发布版本使用 latest 标签,而对不稳定的版本(如预发布)使用其他标签。</p><p>下一个标签被一些项目用来标识即将发布的版本。</p><p>除了 latest ,没有任何标签对npm本身有任何特殊意义。</p><p><strong>next标签</strong>:包如果还不够稳定,但是又想给别人测试使用,可以给这种即将上线的包的版本打上next标签。</p><p>install 的 package</p><p>A <code>package</code> is:</p><ul><li>a) a folder containing a program described by a <a href="https://docs.npmjs.com/cli/v8/configuring-npm/package-json"><code>package.json</code></a> file</li><li>b) a gzipped tarball containing (a)</li><li>c) a url that resolves to (b)</li><li>d) a <code><name>@<version></code> that is published on the registry (see <a href="https://docs.npmjs.com/cli/v8/using-npm/registry"><code>registry</code></a>) with (c)</li><li>e) a <code><name>@<tag></code> (see <a href="https://docs.npmjs.com/cli/v8/commands/npm-dist-tag"><code>npm dist-tag</code></a>) that points to (d)</li><li>f) a <code><name></code> that has a “latest” tag satisfying (e)</li><li>g) a <code><git remote url></code> that resolves to (a)</li></ul><p>init package信息:</p><ul><li>“name”:全部小写,没有空格,可以使用下划线或者横线</li><li>“version”: x.x.x 的格式,符合 “语义化版本规则”</li><li>description:描述信息,有助于搜索</li><li>main:入口文件,一般都是 <code>index.js</code></li><li>scripts:支持的脚本,默认是一个空的 <code>test</code></li><li>keywords:关键字,有助于在人们使用 <code>npm search</code>搜索时发现你的项目<code>author</code> :作者信息</li><li>license :默认是 <code>MIT</code></li><li>bugs:当前项目的一些错误信息,如果有的话</li></ul><p>npm run xxx到底干了什么</p><ol><li>运行 npm run xxx的时候,npm 会先在当前目录的 node_modules/.bin 查找要执行的程序,如果找到则运行;</li><li>没有找到则从全局的 node_modules/.bin 中查找,npm i -g xxx就是安装到到全局目录;</li><li>如果全局目录还是没找到,那么就从 path 环境变量中查找有没有其他同名的可执行程序。</li></ol><h4 id="常用命令"><a href="#常用命令" class="headerlink" title="常用命令"></a>常用命令</h4><ul><li><p>npm shrinkwrap</p><p>repurposes <code>package-lock.json</code> into a publishable <code>npm-shrinkwrap.json</code> or simply creates a new one; is unaware of workspaces.</p><ul><li>when run npm install: <code>npm-shrinkwrap.json</code>><code>package-lock.json</code>><code>yarn.lock</code></li></ul></li></ul><h4 id="npx"><a href="#npx" class="headerlink" title="npx"></a>npx</h4><p>一个 CLI 工具,其目的是使安装和管理托管在 npm 注册表中的依赖关系变得容易。</p><p>能够更方便地安装和运行二进制包,并且还能远程运行 **gist(**Github的一个子服务. 最简单的功能就是分享代码片段,例如把一些小型脚本放到Gist方便分享和管理) 和 <strong>github仓库</strong> 。</p><h3 id="yarn"><a href="#yarn" class="headerlink" title="yarn"></a>yarn</h3><ul><li><p>yarn upgrade–interactive</p><p>更新所有包</p></li><li></li></ul><h2 id="前端工程化"><a href="#前端工程化" class="headerlink" title="前端工程化"></a>前端工程化</h2><p>模块化开发,打包引用(分块引用加载速度慢,单块开发难度大,耦合性高)</p><ul><li><p>使用export default命令,为模块指定默认输出,在import导入时可以随意指定值</p><pre class="language-none"><code class="language-none">// 文件 test.jslet k; export default k = 12; // 另一个文件import m from './test'; // 由于 k 是默认导出,所以可以自由使用 import m 替代 import kconsole.log(m); // 输出为 12 </code></pre></li></ul><p>打包(bundle):常见打包工具webpack,rollup,可以根据模块间依赖关系将多个模块合并为一个文件</p><p>组件化:UI组件是一组视图及其交互行为的封装,组件化是将页面(或应用),按组件拆分模块开发,通过组件的组合拼装实现页面。</p><p>Babel:JavaScript编译器,把ES 2015转成低版本JS语法</p><p>css预处理器:支持嵌套和格式复用,如Sass、Less、Stylus,在webpack中增加预处理器loader即可。</p><h3 id="TS编译相关"><a href="#TS编译相关" class="headerlink" title="TS编译相关"></a>TS编译相关</h3><p>搭配 Babel 和 tsc –watch 使用,前者做文件编译,后者负责类型检查</p><pre class="language-json" data-language="json"><code class="language-json"><span class="token comment">// package.json</span><span class="token punctuation">{</span> ... <span class="token comment">// 指定输出文件 dist,指定扩展名 "ts,tsx"</span> <span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"build"</span><span class="token operator">:</span> <span class="token string">"babel src --out-dir dist --extensions \".ts,.tsx\""</span> ... <span class="token property">"check-type"</span><span class="token operator">:</span> <span class="token string">"tsc --watch"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> ... <span class="token property">"devDependencies"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"@babel/cli"</span><span class="token operator">:</span> <span class="token string">"^7.13.16"</span><span class="token punctuation">,</span> <span class="token property">"@babel/core"</span><span class="token operator">:</span> <span class="token string">"^7.13.16"</span><span class="token punctuation">,</span> <span class="token property">"@babel/plugin-proposal-class-properties"</span><span class="token operator">:</span> <span class="token string">"^7.13.0"</span><span class="token punctuation">,</span> <span class="token comment">// 支持类属性</span> <span class="token property">"@babel/plugin-proposal-object-rest-spread"</span><span class="token operator">:</span> <span class="token string">"^7.13.8"</span><span class="token punctuation">,</span> <span class="token comment">// 支持剩余扩展操作符</span> <span class="token property">"@babel/preset-env"</span><span class="token operator">:</span> <span class="token string">"^7.13.15"</span><span class="token punctuation">,</span> <span class="token property">"@babel/preset-typescript"</span><span class="token operator">:</span> <span class="token string">"^7.13.0"</span> <span class="token comment">// 编译 ts 文件</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token comment">// .babellrc</span><span class="token punctuation">{</span> <span class="token property">"presets"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"@babel/preset-env"</span><span class="token punctuation">,</span> <span class="token string">"@babel/preset-typescript"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"plugins"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">"@babel/plugin-proposal-class-properties"</span><span class="token punctuation">,</span> <span class="token string">"@babel/plugin-proposal-object-rest-spread"</span> <span class="token punctuation">]</span><span class="token punctuation">}</span><span class="token comment">// tsconfig.json</span><span class="token punctuation">{</span> ... <span class="token property">"compilerOptions"</span><span class="token operator">:</span><span class="token punctuation">{</span> <span class="token property">"noEmit"</span><span class="token operator">:</span><span class="token boolean">true</span> <span class="token comment">// 不输出文件,只做类型检查</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><p>同时另开终端运行 npm run check-type 即可</p><h3 id="单元测试"><a href="#单元测试" class="headerlink" title="单元测试"></a>单元测试</h3><p>测试金字塔:从低到高是单元测试->服务测试->系统测试,越往上测试数量应该越少</p><p>测试框架:AVA、TAPE、Jasmine、Jest</p><p>测试框架衡量指标:Node端和Browser的支持,并发的支持,库的集成度,社区的活跃度。Jest最常用</p><p>三种编写测试用例形式:<code>xxx.test.js</code>, <code>xxx.spec.js</code>, 或者写到<code>__test__</code>文件夹下,正常<code>.js</code>后缀。</p><pre class="language-none"><code class="language-none">const delay=require('../index');describe('add 方法测试-__test__', ()=>{ test('1+1应该等于2', ()=>{ const res=add(1,1); expect(res).toBe(2); })})</code></pre><p>describe:将几个相关的测试放到一个组中,非必须</p><p>test:别名it,测试用例,是测试的最小单位</p><p>expect:提供大量matcher来判断方法返回值是否符合特定条件</p><p>异步测试避免没有执行到预期代码,在test的执行方法首行加上断言数<code>expect.assertions(num);</code>,主要是针对异步代码的测试。</p><p>并且为了避免过早结束在test末尾添加done()方法,并把test的执行方法调入参数done,表示执行到done()方法后才结束。</p><p>针对返回类型为 promise 直接 return 最后调用测试的结果即可。如下:</p><pre class="language-none"><code class="language-none">const delay=require('../index');test('calllback execute',done=>{ expect.assertions(1); const callback=()=>{ console.log('callback exec'); expect(true).toBe(true); done(); }; delay(callback);});test('calllback execute',()=>{ expect.assertions(1); const callback=()=>1; return delayPromise(callback).then(res => { expect(res).toBe(1); });});</code></pre><p>测试覆盖率:在 <code>package.json</code>文件中把<code>scripts</code>行进行修改</p><pre class="language-none"><code class="language-none">"scripts": { "test": "jest --coverage"//},</code></pre><p>jest方法:</p><ul><li><p>const func = jest.<strong>fn</strong>().<strong>mockReturnValue</strong>(1),生成一个返回值为1的函数。</p></li><li><p>存在库依赖 jest.spyOn 监视库函数</p><pre class="language-none"><code class="language-none">let mockRandom=null;beforeEach(()=>{ mockRandom=jest.spyOn(Math, 'random');})afterEach(()=>{ mockRandom.mockRestore();})//设置库函数返回值//mockRandom.mockReturnValue(value);</code></pre></li><li><p>jest.<strong>mock</strong>(‘’)</p></li></ul><h3 id="代码规范"><a href="#代码规范" class="headerlink" title="代码规范"></a>代码规范</h3><p>Eslint 和 Prettier</p><h2 id="打包之webpack"><a href="#打包之webpack" class="headerlink" title="打包之webpack"></a>打包之webpack</h2><h3 id="基础"><a href="#基础" class="headerlink" title="基础"></a>基础</h3><p>webpack 默认支持处理 JS 与 JSON 文件,其他类型都处理不了,必须借助 Loader 来对不同类型的文件的进行处理。</p><h3 id="配置模块"><a href="#配置模块" class="headerlink" title="配置模块"></a>配置模块</h3><p>Entry:入口,指示 Webpack 应该使用哪个模块,来作为构建其内部 依赖图(dependency graph) 的开始。</p><p>Output:输出结果,告诉 Webpack 在哪里输出它所创建的 bundle,以及如何命名这些文件。</p><h4 id="Module"><a href="#Module" class="headerlink" title="Module"></a>Module</h4><p>模块,在 Webpack 里一切皆模块,一个模块对应着一个文件。Webpack 会从配置的 Entry 开始递归找出所有依赖的模块。</p><p>Chunk:代码块,一个 Chunk 由多个模块组合而成,用于代码合并与分割。</p><p>Loader:模块代码转换器,让webpack能够去处理除了JS、JSON之外的其他类型的文件,并将它们转换为有效 模块,以供应用程序使用,以及被添加到依赖图中。</p><p>Plugin:扩展插件。在webpack运行的生命周期中会广播出许多事件,plugin可以监听这些事件,在合适的时机通过webpack提供的api改变输出结果。常见的有:打包优化,资源管理,注入环境变量。</p><h4 id="Mode"><a href="#Mode" class="headerlink" title="Mode"></a>Mode</h4><p>模式,告知 webpack 使用相应模式的内置优化,默认为 production</p><table><thead><tr><th>选项</th><th>描述</th></tr></thead><tbody><tr><td>development</td><td>开发模式,打包更加快速,省了代码优化步骤</td></tr><tr><td>production</td><td>生产模式,打包比较慢,会开启 tree-shaking 和 压缩代码</td></tr><tr><td>none</td><td>不使用任何默认优化选项</td></tr></tbody></table><p>Browser Compatibility:浏览器兼容性,Webpack 支持所有符合 ES5 标准 的浏览器(IE8以上版本)</p><h3 id="打包流程"><a href="#打包流程" class="headerlink" title="打包流程"></a>打包流程</h3><p>1、读取<code>webpack</code>的配置参数;</p><p>2、启动<code>webpack</code>,创建<code>Compiler</code>对象并开始解析项目;</p><p>3、从入口文件(<code>entry</code>)开始解析,并且找到其导入的依赖模块,递归遍历分析,形成依赖关系树;</p><p>4、对不同文件类型的依赖模块文件使用对应的<code>Loader</code>进行编译,最终转为<code>Javascript</code>文件;</p><p>5、整个过程中<code>webpack</code>会通过发布订阅模式,向外抛出一些<code>hooks</code>,而<code>webpack</code>的插件即可通过监听这些关键的事件节点,执行插件任务进而达到干预输出结果的目的。</p><h2 id="NodeJS"><a href="#NodeJS" class="headerlink" title="NodeJS"></a>NodeJS</h2><h3 id="环境变量"><a href="#环境变量" class="headerlink" title="环境变量"></a>环境变量</h3><ul><li><strong>__dirname</strong>: 返回当前模块文件解析过后所在的文件夹(目录)的绝对路径。</li><li><strong>__filename</strong>: 返回当前模块文件被解析过后的绝对路径。</li></ul><h2 id="设计架构,框架"><a href="#设计架构,框架" class="headerlink" title="设计架构,框架"></a>设计架构,框架</h2><h3 id="前端发展和个人发展"><a href="#前端发展和个人发展" class="headerlink" title="前端发展和个人发展"></a>前端发展和个人发展</h3><p>“全栈开发者”是指“同时掌握前端、后端以及其他网站开发相关技能的开发者”。</p><p>一个“全栈开发者”可能会使用以下技能点:</p><p>前端:JavaScript、H5、CSS3、sass、less、React、Vue、Vite(法语意为”快速的”,发音 /vit/ ,发音同”veet”)、webpack、jest。</p><p>后端:Nodejs/Deno、Go、Java、Spring、Gin、Kafka、Hadoop。</p><p>数据库:MySQL、mongoDB、redis、clickhouse。</p><p>运维:网络协议、CDN、Nginx、ZooKeeper、Docker、Kubernetes。</p><p>值得注意的是,一个优秀的工程师并不是以“栈”数取胜,而取决于你解决了什么层次的问题。</p><blockquote><p>“全栈”或者“专家”仅仅是实现目标的过程状态。吴军在《硅谷来信》中,将工程师划分成五个等级:<img src="/2022/11/03/frontend-engineering/%E5%B7%A5%E7%A8%8B%E5%B8%88%E7%AD%89%E7%BA%A7.jpeg" alt="工程师5个等级.png">从工程师能力模型来看,第一级需要集“天时地利人和”大成,是工程师的最高荣誉。普通人或许可以将目标聚焦在第二、三级。优秀的工程师并不是以“栈”数取胜,更重要的是拥有产品观、全局思维、沟通能力、学习能力、解决问题能力等。<a href="https://juejin.cn/post/7062617190981173278">来源:《来自未来,2022 年的前端人都在做什么?》</a></p></blockquote><p>函数化,专注于前端应该做的事情</p><p>低代码编程,前端是不可或缺的一环</p><h3 id="设计原则"><a href="#设计原则" class="headerlink" title="设计原则"></a>设计原则</h3><p>设计系统:设计价值观=>设计原则=>设计风格规范、组件化Design Token,实现样式代理、资源代理、结构化设计</p><p>框架的作用是为前端UI开发提供另外一种方式,提供良好的代码风格,易于添加测试,组件化开发,服务端和客户端路由</p><p>无极设计规范:原子设计方法论,拆解和组合</p><p>组件化中遇到的问题:组件化不彻底,无基础组件,复用程度低,单位不统一,语法版本规范弱</p><p>MVC,包括视图、控制器、模型</p><h3 id="MVVM"><a href="#MVVM" class="headerlink" title="MVVM"></a>MVVM</h3><p>开发者只需要关心数据结构和视图,抽象层包括视图,视图模型和模型。</p><p>实际应用包括Vue、React、San、小程序</p><p>真正的区别在于,发布订阅模式实现的是一种多对多的关系,在发布者与订阅者之间需要有一个中介者,发布者发布事件名和参数到中间者,中间者向事件集中的订阅者发送参数。<br>而观察者是一种一对多的关系,所有的在同一被观察者身上绑定的观察者只能接受同一个被观察者的消息。</p><p>本质上,观察者模式和发布订阅模式都是对回调函数的松(解)耦合。回调函数是:事件A结束后,执行事件B。观察者模式实现的是:定义好事件A,事件B,通过“观察”这一行为,将事件A和B的因果先后关系关联起来。发布订阅模式实现的是:事件A结束后,发布到事件中心;事件B订阅A,连同后续回调托管到事件中心。事件中心将A和B关联起来。这一过程中,事件A和事件B完全不会受到对方是否存在的影响,是完全解耦合的。</p><h3 id="MTV"><a href="#MTV" class="headerlink" title="MTV"></a>MTV</h3><p>model templates view</p><p>比如 django </p><h2 id="路由"><a href="#路由" class="headerlink" title="路由"></a>路由</h2><h3 id="前端-x2F-后端路由"><a href="#前端-x2F-后端路由" class="headerlink" title="前端/后端路由"></a>前端/后端路由</h3><p>router和route,router 可以理解为一个容器,或者说一种机制,它管理了一组 route。简单来说,route 只是进行了URL和函数的映射,而在当接收到一个URL之后,去路由映射表中查找相应的函数,这个过程由 router 来处理。</p><p>服务器端路由和客户端路由:</p><ul><li>对于服务器来说,当接收到客户端发来的HTTP请求,会根据请求的URL,来找到相应的映射函数,然后执行该函数,并将函数的返回值发送给客户端。在 router 匹配 route 的过程中,不仅会根据URL来匹配,还会根据请求的方法来看是否匹配。如果通过 POST 方法来GET /users的内容,就会找不到正确的路由。</li><li>对于客户端(通常为浏览器)来说,路由的映射函数通常是进行一些DOM的显示和隐藏操作。这样,当访问不同的路径的时候,会显示不同的页面组件。有基于Hash和History API两种</li></ul><p>上述路由和渲染概念相近。</p><p>前端路由——顾名思义,页面跳转的URL规则匹配由前端来控制。而前端路由主要是有两种显示方式:</p><ul><li>带有hash的前端路由,优点是兼容性高。缺点是URL带有<code>#</code>号不好看</li><li>不带hash的前端路由,优点是URL不带<code>#</code>号,好看。缺点是既需要浏览器支持也需要后端服务器支持</li></ul><h3 id="hash-x2F-history路由模式"><a href="#hash-x2F-history路由模式" class="headerlink" title="hash/history路由模式"></a>hash/history路由模式</h3><p>当在url栏中输入新网址,浏览器会直接向服务器请求网址对应的信息。而在已存在网页中点击链接路由时,会进行判断是否需要向服务器请求信息。</p><p><strong>hash</strong>:带 # 的url,浏览器向服务器请求 # 后的地址信息,仅向服务器请求url中 # 之前的地址,再由浏览器获取到的前端脚本处理#后的地址信息</p><p><strong>history</strong>:不带 # ,正常 / 分隔,在已加载页面点击链接进行跳转时不会出现问题,当后端服务器不存在某个路由信息而直接在网址栏输入对其访问会404.</p><h2 id="前后端通信-Axios"><a href="#前后端通信-Axios" class="headerlink" title="前后端通信-Axios"></a>前后端通信-Axios</h2><p>基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。</p><p>一个通信框架,用于服务器交互;当然也可以使用jQuery提供的AJAX通信功能</p><ul><li>ajax最早出现的发送后端请求技术,利用用XMLHttpRequest对象。</li><li>$.ajax是jQuery中的发送后端请求技术,基于原生Ajax的封装。</li><li>Axios不是原生JS的,需要进行安装。它在client-side和server-side都可以使用。也可以在请求和响应阶段进行拦截。它是基于promise对象的。</li><li>Fetch号称是AJAX的替代品,使用了ES6中的promise对象。其参数有点像jQuery.ajax。但是fetch不是对ajax的封装,而是原生js实现的,并没有使用XMLHttpRequest对象。</li></ul><p>axios 中所谓的绝对路径,就是以 <code><scheme>://</code>(协议头)或者 <code>//</code> 开头的URL,除此之外都算先对路径,都会在头部附加 baseURL</p><h3 id="结构信息"><a href="#结构信息" class="headerlink" title="结构信息"></a>结构信息</h3><p>request信息</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token punctuation">{</span> <span class="token comment">// `url` 是用于请求的服务器 URL</span> <span class="token literal-property property">url</span><span class="token operator">:</span> <span class="token string">'/user'</span><span class="token punctuation">,</span> <span class="token comment">// `method` 是创建请求时使用的方法</span> <span class="token literal-property property">method</span><span class="token operator">:</span> <span class="token string">'get'</span><span class="token punctuation">,</span> <span class="token comment">// default</span> <span class="token comment">// `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。</span> <span class="token comment">// 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL</span> <span class="token literal-property property">baseURL</span><span class="token operator">:</span> <span class="token string">'https://some-domain.com/api/'</span><span class="token punctuation">,</span> <span class="token comment">// `transformRequest` 允许在向服务器发送前,修改请求数据</span> <span class="token comment">// 只能用在 'PUT', 'POST' 和 'PATCH' 这几个请求方法</span> <span class="token comment">// 后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 Stream</span> <span class="token literal-property property">transformRequest</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">data<span class="token punctuation">,</span> headers</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 对 data 进行任意转换处理</span> <span class="token keyword">return</span> data<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token comment">// `transformResponse` 在传递给 then/catch 前,允许修改响应数据</span> <span class="token literal-property property">transformResponse</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 对 data 进行任意转换处理</span> <span class="token keyword">return</span> data<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token comment">// `headers` 是即将被发送的自定义请求头</span> <span class="token literal-property property">headers</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token string-property property">'X-Requested-With'</span><span class="token operator">:</span> <span class="token string">'XMLHttpRequest'</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// `params` 是即将与请求一起发送的 URL 参数</span> <span class="token comment">// 必须是一个无格式对象(plain object)或 URLSearchParams 对象</span> <span class="token literal-property property">params</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token constant">ID</span><span class="token operator">:</span> <span class="token number">12345</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// `paramsSerializer` 是一个负责 `params` 序列化的函数</span> <span class="token comment">// (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)</span> <span class="token function-variable function">paramsSerializer</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">params</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> Qs<span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>params<span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token literal-property property">arrayFormat</span><span class="token operator">:</span> <span class="token string">'brackets'</span><span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// `data` 是作为请求主体被发送的数据</span> <span class="token comment">// 只适用于这些请求方法 'PUT', 'POST', 和 'PATCH'</span> <span class="token comment">// 在没有设置 `transformRequest` 时,必须是以下类型之一:</span> <span class="token comment">// - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams</span> <span class="token comment">// - 浏览器专属:FormData, File, Blob</span> <span class="token comment">// - Node 专属: Stream</span> <span class="token literal-property property">data</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">firstName</span><span class="token operator">:</span> <span class="token string">'Fred'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// `timeout` 指定请求超时的毫秒数(0 表示无超时时间)</span> <span class="token comment">// 如果请求话费了超过 `timeout` 的时间,请求将被中断</span> <span class="token literal-property property">timeout</span><span class="token operator">:</span> <span class="token number">1000</span><span class="token punctuation">,</span> <span class="token comment">// `withCredentials` 表示跨域请求时是否需要使用凭证</span> <span class="token literal-property property">withCredentials</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token comment">// default</span> <span class="token comment">// `adapter` 允许自定义处理请求,以使测试更轻松</span> <span class="token comment">// 返回一个 promise 并应用一个有效的响应 (查阅 [response docs](#response-api)).</span> <span class="token function-variable function">adapter</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">config</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">/* ... */</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// `auth` 表示应该使用 HTTP 基础验证,并提供凭据</span> <span class="token comment">// 这将设置一个 `Authorization` 头,覆写掉现有的任意使用 `headers` 设置的自定义 `Authorization`头</span> <span class="token literal-property property">auth</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">username</span><span class="token operator">:</span> <span class="token string">'janedoe'</span><span class="token punctuation">,</span> <span class="token literal-property property">password</span><span class="token operator">:</span> <span class="token string">'s00pers3cret'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// `responseType` 表示服务器响应的数据类型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'</span> <span class="token literal-property property">responseType</span><span class="token operator">:</span> <span class="token string">'json'</span><span class="token punctuation">,</span> <span class="token comment">// default</span> <span class="token comment">// `responseEncoding` indicates encoding to use for decoding responses</span> <span class="token comment">// Note: Ignored for `responseType` of 'stream' or client-side requests</span> <span class="token literal-property property">responseEncoding</span><span class="token operator">:</span> <span class="token string">'utf8'</span><span class="token punctuation">,</span> <span class="token comment">// default</span> <span class="token comment">// `xsrfCookieName` 是用作 xsrf token 的值的cookie的名称</span> <span class="token literal-property property">xsrfCookieName</span><span class="token operator">:</span> <span class="token string">'XSRF-TOKEN'</span><span class="token punctuation">,</span> <span class="token comment">// default</span> <span class="token comment">// `xsrfHeaderName` is the name of the http header that carries the xsrf token value</span> <span class="token literal-property property">xsrfHeaderName</span><span class="token operator">:</span> <span class="token string">'X-XSRF-TOKEN'</span><span class="token punctuation">,</span> <span class="token comment">// default</span> <span class="token comment">// `onUploadProgress` 允许为上传处理进度事件</span> <span class="token function-variable function">onUploadProgress</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">progressEvent</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// Do whatever you want with the native progress event</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// `onDownloadProgress` 允许为下载处理进度事件</span> <span class="token function-variable function">onDownloadProgress</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">progressEvent</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 对原生进度事件的处理</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// `maxContentLength` 定义允许的响应内容的最大尺寸</span> <span class="token literal-property property">maxContentLength</span><span class="token operator">:</span> <span class="token number">2000</span><span class="token punctuation">,</span> <span class="token comment">// `validateStatus` 定义对于给定的HTTP 响应状态码是 resolve 或 reject promise 。如果 `validateStatus` 返回 `true` (或者设置为 `null` 或 `undefined`),promise 将被 resolve; 否则,promise 将被 rejecte</span> <span class="token function-variable function">validateStatus</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">status</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> status <span class="token operator">>=</span> <span class="token number">200</span> <span class="token operator">&&</span> status <span class="token operator"><</span> <span class="token number">300</span><span class="token punctuation">;</span> <span class="token comment">// default</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// `maxRedirects` 定义在 node.js 中 follow 的最大重定向数目</span> <span class="token comment">// 如果设置为0,将不会 follow 任何重定向</span> <span class="token literal-property property">maxRedirects</span><span class="token operator">:</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token comment">// default</span> <span class="token comment">// `socketPath` defines a UNIX Socket to be used in node.js.</span> <span class="token comment">// e.g. '/var/run/docker.sock' to send requests to the docker daemon.</span> <span class="token comment">// Only either `socketPath` or `proxy` can be specified.</span> <span class="token comment">// If both are specified, `socketPath` is used.</span> <span class="token literal-property property">socketPath</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token comment">// default</span> <span class="token comment">// `httpAgent` 和 `httpsAgent` 分别在 node.js 中用于定义在执行 http 和 https 时使用的自定义代理。允许像这样配置选项:</span> <span class="token comment">// `keepAlive` 默认没有启用</span> <span class="token literal-property property">httpAgent</span><span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">http<span class="token punctuation">.</span>Agent</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">keepAlive</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token literal-property property">httpsAgent</span><span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">https<span class="token punctuation">.</span>Agent</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">keepAlive</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token comment">// 'proxy' 定义代理服务器的主机名称和端口</span> <span class="token comment">// `auth` 表示 HTTP 基础验证应当用于连接代理,并提供凭据</span> <span class="token comment">// 这将会设置一个 `Proxy-Authorization` 头,覆写掉已有的通过使用 `header` 设置的自定义 `Proxy-Authorization` 头。</span> <span class="token literal-property property">proxy</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">host</span><span class="token operator">:</span> <span class="token string">'127.0.0.1'</span><span class="token punctuation">,</span> <span class="token literal-property property">port</span><span class="token operator">:</span> <span class="token number">9000</span><span class="token punctuation">,</span> <span class="token literal-property property">auth</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">username</span><span class="token operator">:</span> <span class="token string">'mikeymike'</span><span class="token punctuation">,</span> <span class="token literal-property property">password</span><span class="token operator">:</span> <span class="token string">'rapunz3l'</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// `cancelToken` 指定用于取消请求的 cancel token</span> <span class="token comment">// (查看后面的 Cancellation 这节了解更多)</span> <span class="token literal-property property">cancelToken</span><span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">CancelToken</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">cancel</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">}</span></code></pre><p>response信息</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token punctuation">{</span> <span class="token comment">// `data` 由服务器提供的响应</span> <span class="token literal-property property">data</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// `status` 来自服务器响应的 HTTP 状态码</span> <span class="token literal-property property">status</span><span class="token operator">:</span> <span class="token number">200</span><span class="token punctuation">,</span> <span class="token comment">// `statusText` 来自服务器响应的 HTTP 状态信息</span> <span class="token literal-property property">statusText</span><span class="token operator">:</span> <span class="token string">'OK'</span><span class="token punctuation">,</span> <span class="token comment">// `headers` 服务器响应的头</span> <span class="token literal-property property">headers</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// `config` 是为请求提供的配置信息</span> <span class="token literal-property property">config</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// 'request'</span> <span class="token comment">// `request` is the request that generated this response</span> <span class="token comment">// It is the last ClientRequest instance in node.js (in redirects)</span> <span class="token comment">// and an XMLHttpRequest instance the browser</span> <span class="token literal-property property">request</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><h3 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h3><ul><li><p>changeOrigin:Boolean</p><p>为false时通过前端访问,devServer转发请求时,http request的host头值不会改变,为true时会把host值改为target指定的host</p></li></ul><h3 id="案例"><a href="#案例" class="headerlink" title="案例"></a>案例</h3><p>要求:</p><ol><li>正常请求该有的(跨域携带cookie,token,超时设置)</li><li>请求响应拦截器<ul><li>请求成功,业务状态码200,解析result给我,我不想一层一层的去判断拿数据</li><li>http请求200, 业务状态码非200,说明逻辑判断这是不成功的,那就全局message提示服务端的报错</li><li>http请求非200, 说明http请求都有问题,也全局message提示报错</li><li>http请求或者业务状态码401都做注销操作</li></ul></li><li>全局的loading配置,默认开启,可配置关闭(由于后端的问题,经常会让前端加防抖节流或者loading不让用户在界面上疯狂乱点,行吧行吧,你们的问题前端帮你们解决,你的规矩就是规矩是吧🍜)</li><li>统一文件下载处理 (不要再去各写各的下载了,你写一个,他写一个,一个项目就是这样整的跟屎一样)</li></ol><h2 id="项目开发流程"><a href="#项目开发流程" class="headerlink" title="项目开发流程"></a>项目开发流程</h2><h3 id="一、需求分析"><a href="#一、需求分析" class="headerlink" title="一、需求分析"></a>一、需求分析</h3><p>1、需求评审:</p><pre class="language-none"><code class="language-none">时间:在产品设计完成以后,进入正式的开发流程之前,组织者:产品设计(PM);目的:统一大家对产品的认识,及时发现产品设计缺陷,尽可能降低后续修改需求的频率;参与者:后端开发、前端开发、交互设计、视觉设计;需求来源方(有可能的话)形式:会议</code></pre><p>2、需求分析</p><pre class="language-none"><code class="language-none">分析关键功能、应用场景等;基本上在需求评审和分析阶段就对项目的整体实现方案有个基础设计;对核心功能的实现难度有个清晰的认识、方案不清楚的时候需要提前做好技术调研;一方面可以给出一个比较准确的排期;另一方面避免了自己在真正开发的时候遇到难以解决的方案,推倒重来,非常狼狈</code></pre><h3 id="二、等视觉与交互设计"><a href="#二、等视觉与交互设计" class="headerlink" title="二、等视觉与交互设计"></a>二、等视觉与交互设计</h3><p>(很重要,拿不到交互不给排期)</p><p>话是这么说,一般排期都等不到视觉交互的交付(前端😭啊);</p><p>在这个阶段一般都是要给出项目排期了(多给自己排点填坑的时间)</p><h3 id="三、项目开发"><a href="#三、项目开发" class="headerlink" title="三、项目开发"></a>三、项目开发</h3><p>(项目完成度基本与视觉设计和交互设计保持一致)</p><h3 id="四、预留充分的自测时间"><a href="#四、预留充分的自测时间" class="headerlink" title="四、预留充分的自测时间"></a>四、预留充分的自测时间</h3><p>(测试功能和样式)</p><h3 id="五、前后端联调"><a href="#五、前后端联调" class="headerlink" title="五、前后端联调"></a>五、前后端联调</h3><p>(调接口功能与字段限制);经常需要改接口逻辑、甚至加接口造成前端需要修改对应的校验或功能;时间必须</p><h3 id="六、视觉与交互验收"><a href="#六、视觉与交互验收" class="headerlink" title="六、视觉与交互验收"></a>六、视觉与交互验收</h3><pre class="language-none"><code class="language-none">做好开发和自测;视觉与交互的验收很容易;预留一到两天就ok了</code></pre><h3 id="七:产品验收;"><a href="#七:产品验收;" class="headerlink" title="七:产品验收;"></a>七:产品验收;</h3><pre class="language-none"><code class="language-none">产品验收很重要、往往他们预计的东西跟设计出来的东西效果是不一致的;甚至会因为实际应用情况需要修改产品设计逻辑 ;需要预留一定时间进行修改</code></pre><h3 id="八、提交测试:完成上述步骤之后产品才能提交测试;"><a href="#八、提交测试:完成上述步骤之后产品才能提交测试;" class="headerlink" title="八、提交测试:完成上述步骤之后产品才能提交测试;"></a>八、提交测试:完成上述步骤之后产品才能提交测试;</h3><pre class="language-markdown" data-language="markdown"><code class="language-markdown">保证提测质量(测试周期也会比较长、并且在测试过程中需要及时修改bug、甚至影响业务逻辑的bug需要在一到两个小时之内进行修复)</code></pre><h3 id="九、线上接口回归"><a href="#九、线上接口回归" class="headerlink" title="九、线上接口回归"></a>九、线上接口回归</h3><p>(后端上线以后需要进行线上接口功能回归之后才能进行上线)</p><h3 id="十、新项目的上线前准备"><a href="#十、新项目的上线前准备" class="headerlink" title="十、新项目的上线前准备"></a>十、新项目的上线前准备</h3><p>1、资源申请;</p><p>2、沙盒环境部署测试(需要进行模拟真实的线上部署测试)</p><p>3、线上部署测试(QA进行交付之后、自己需要进行更新迭代测试、保证项目完整可用)</p><h2 id="服务器"><a href="#服务器" class="headerlink" title="服务器"></a>服务器</h2><p>动态网页的生成是基于动态web server的。一个动态网络服务器首先是一台计算机,这个计算机上包含了产生这个网页所需的HTML模板,样式表,其它托管文件和负责调动这些文件的静态HTTP服务器软件,应用服务器软件和数据库软件(通常情况)。后两者会对HTTP服务器打算传送的托管文件进行更新。</p><p>Nginx优点:负载均衡、反向代理、处理静态文件优势。nginx处理静态请求的速度高于apache;</p><p>Apache优点:相对于Tomcat服务器来说处理静态文件是它的优势,速度快。Apache是静态解析,适合静态HTML、图片等。</p><p>Tomcat:动态解析容器,处理动态请求,是编译JSP\Servlet的容器,Nginx有动态分离机制,静态请求直接就可以通过Nginx处理,动态请求才转发请求到后台交由Tomcat进行处理。 </p><p> Apache在处理动态有优势,Nginx并发性比较好,CPU内存占用低,如果rewrite频繁,那还是Apache较适合。</p><p>localStorage生命周期是永久,除非主动清除localStorage信息,否则这些信息将永远存在。存放数据大小为一般为5MB,而且它仅在客户端(即浏览器)中保存,不参与和服务器的通信。</p><p>sessionStorage仅在当前会话下有效,关闭页面或浏览器后被清除。存放数据大小为一般为5MB,而且它仅在客户端(即浏览器)中保存,不参与和服务器的通信。</p><p>cookie机制:如果不在浏览器中设置过期事件,cookie被保存在内存中,生命周期随浏览器的关闭而结束,这种cookie简称为会话cookie。如果在浏览器中设置了cookie的过期事件,cookie会被保存在硬盘中,关闭浏览器后,cookie数据仍然存在,直到过期事件结束才消失。cookie是服务端发给客户端的特殊信息,cookie是以文本的方式保存在客户端,每次请求时都带上它</p>]]></content>
<summary type="html"><blockquote>
<p>持续更新</p>
</blockquote>
<h3 id=""><a href="#" class="headerlink" title=""></a></h3><h2 id="项目构建"><a href="#项目构建" class="heade</summary>
<category term="Frontend" scheme="https://hhumar.com/categories/Frontend/"/>
<category term="Web" scheme="https://hhumar.com/tags/Web/"/>
<category term="Engineering" scheme="https://hhumar.com/tags/Engineering/"/>
</entry>
<entry>
<title>前端基础</title>
<link href="https://hhumar.com/2022/11/02/Frontend/"/>
<id>https://hhumar.com/2022/11/02/Frontend/</id>
<published>2022-11-01T16:40:14.000Z</published>
<updated>2023-04-30T16:54:46.190Z</updated>
<content type="html"><![CDATA[<blockquote><p>持续更新</p></blockquote><h3 id=""><a href="#" class="headerlink" title=""></a></h3><p>“网页大事,为我所控,天下页面,听我号令”——张鑫旭</p><h2 id="web基础知识"><a href="#web基础知识" class="headerlink" title="web基础知识"></a>web基础知识</h2><h3 id="url到页面"><a href="#url到页面" class="headerlink" title="url到页面"></a>url到页面</h3><p>浏览器中的进程</p><table><thead><tr><th>进程</th><th>说明</th></tr></thead><tbody><tr><td>浏览器进程</td><td>负责浏览器各个子进程的通信,处理浏览器界面,包括地址栏等</td></tr><tr><td>渲染进程</td><td>也就是我们看到的图中的标签页进程,也就是我们常说的浏览器内核,v8就在这个进程。主要负责解析html、js、css渲染页面等</td></tr><tr><td>网络进程</td><td>负责发起网络请求,解析返回头信息</td></tr><tr><td>GUI进程</td><td>负责将渲染进程生成的图块转化成位图</td></tr><tr><td>插件进程</td><td></td></tr></tbody></table><p>从输入页面URL到页面渲染完成大致流程为:</p><ul><li><p>地址栏输入信息处理</p><p>判断输入信息是检索信息还是请求URL</p><ul><li>如果是检索的信息,就构建请求搜索的URL,调用浏览器默认的搜索引擎进行检索。</li><li>如果符合URL格式,浏览器主进程就通过IPC通信机制将URL发送给网络进程。<a href="https://www.jianshu.com/p/c1015f5ffa74">进程间通信IPC (InterProcess Communication)</a></li></ul></li><li><p>网络进程发起网络请求</p><ul><li>解析URL,解码</li><li>查找浏览器本地缓存</li><li>无缓存则DNS解析</li><li>建立TCP/IP连接</li><li>发送HTTP请求</li><li>服务器处理请求并返回HTTP报文</li></ul></li><li><p>服务器返回对应资源</p><ul><li>浏览器接收到服务器返回的资源信息,网络进程首先会解析返回的头信息,查看是否有Location字段,如果有的话,再次发起请求,常见例子:请求http的站点,然后重定向到https。</li><li>通过返回头字段<code>Content-Type</code>判断文件类型,如果其他类型,就调用不同的进程处理,如果是html类型,继续处理。</li><li>浏览器根据深度遍历的方式把html节点遍历构建DOM树</li><li>遇到CSS外链,异步加载解析CSS,构建CSS规则树</li><li><strong>遇到script标签,如果是普通JS标签则同步加载并执行,阻塞页面渲染,如果标签上有defer / async属性则异步加载JS资源</strong></li><li>将dom树和CSS DOM树构造成render树</li><li>渲染render树</li></ul></li><li><p>四次挥手,资源传输完毕,断开连接</p></li></ul><p><img src="/%E6%B8%B2%E6%9F%93%E8%BF%9B%E7%A8%8B-1682873589215.png" alt="渲染进程"></p><h3 id="路由"><a href="#路由" class="headerlink" title="路由"></a>路由</h3><h4 id="前端-x2F-后端路由"><a href="#前端-x2F-后端路由" class="headerlink" title="前端/后端路由"></a>前端/后端路由</h4><p>router和route,router 可以理解为一个容器,或者说一种机制,它管理了一组 route。简单来说,route 只是进行了URL和函数的映射,而在当接收到一个URL之后,去路由映射表中查找相应的函数,这个过程由 router 来处理。</p><p>服务器端路由和客户端路由:</p><ul><li>对于服务器来说,当接收到客户端发来的HTTP请求,会根据请求的URL,来找到相应的映射函数,然后执行该函数,并将函数的返回值发送给客户端。在 router 匹配 route 的过程中,不仅会根据URL来匹配,还会根据请求的方法来看是否匹配。如果通过 POST 方法来GET /users的内容,就会找不到正确的路由。</li><li>对于客户端(通常为浏览器)来说,路由的映射函数通常是进行一些DOM的显示和隐藏操作。这样,当访问不同的路径的时候,会显示不同的页面组件。有基于Hash和History API两种</li></ul><p>上述路由和渲染概念相近。</p><p>前端路由——顾名思义,页面跳转的URL规则匹配由前端来控制。而前端路由主要是有两种显示方式:</p><ul><li><p>带有hash的前端路由,优点是兼容性高。缺点是URL带有<code>#</code>号不好看</p><p>URL中 # 及其后面的部分为 hash,前端的router库通过捕捉<code>#</code>号后面的参数、地址,来告诉前端库(比如Vue)渲染对应的页面。这样,不管是我们在浏览器的地址栏输入,或者是页面里通过router的api进行的跳转,都是一样的跳转逻辑。所以这个模式是不需要后端配置其他逻辑的,只要给前端返回<code>http://localhost</code>对应的html,剩下具体是哪个页面,就由前端路由去判断便可。</p></li><li><p>不带hash的前端路由,优点是URL不带<code>#</code>号,好看。缺点是既需要浏览器支持也需要后端服务器支持</p></li></ul><h4 id="hash-x2F-history路由模式"><a href="#hash-x2F-history路由模式" class="headerlink" title="hash/history路由模式"></a>hash/history路由模式</h4><p>基于Hash的路由,兼容性更好;基于History API的路由,更加直观和正式。</p><p>当在url栏中输入新网址,浏览器会直接向服务器请求网址对应的信息。而在已存在网页中点击链接路由时,会进行判断是否需要向服务器请求信息。</p><p><strong>hash</strong>:带 # 的url,浏览器向服务器请求 # 后的地址信息,仅向服务器请求url中 # 之前的地址,再由浏览器获取到的前端脚本处理#后的地址信息</p><p><strong>history</strong>:不带 # ,正常 / 分隔,在已加载页面点击链接进行跳转时不会出现问题,当后端服务器不存在某个路由信息而直接在网址栏输入对其访问会404.</p><blockquote><p>注意:</p><p>当直接访问 / 的时候,两者的行为是一致的,都是返回了 index.html 文件。</p><p>当从 / 跳转到 /#/foobar 或者 /foobar 的时候,也都是正常的,因为此时已经加载了页面以及脚本文件,所以路由跳转正常。</p><p>当直接访问 /#/foobar 的时候,实际上向服务器发起的请求是 /,因此会首先加载页面及脚本文件,接下来脚本执行路由跳转,一切正常。</p><p>当直接访问 /foobar 的时候,实际上向服务器发起的请求也是 /foobar,然而服务器端只能匹配 / 而无法匹配 /foobar,因此会出现404错误。</p><p>因此如果使用了基于History API的路由,需要改造服务器端,使得访问 /foobar 的时候也能返回 index.html 文件,这样当浏览器加载了页面及脚本之后,就能进行路由跳转了。</p></blockquote><h4 id="严格路由"><a href="#严格路由" class="headerlink" title="严格路由"></a>严格路由</h4><p>在很多情况下,会遇到 /foobar 和 /foobar/ 的情况,它们看起来非常类似,然而实际上有所区别,具体的行为也是视服务器设置而定。</p><h4 id="预渲染"><a href="#预渲染" class="headerlink" title="预渲染"></a>预渲染</h4><p>预渲染的概念。也即先在服务端构建出一部分静态的html文件,用于直出浏览器。然后剩下的页面再通过常用的前端渲染来实现。通常我们可以把首页采用预渲染的方式。这个的好处是明显的,兼顾了SEO和服务器的性能要求。不过它无法做到全站SEO,生产构建阶段耗时也会有所提高,这也是遗憾所在。</p><p>关于预渲染,可以考虑使用<a href="https://github.com/chrisvfritz/prerender-spa-plugin">prerender-spa-plugin</a>这个webapck的插件,它的3.x版本开始使用puppeteer来构建html文件了。</p><h3 id="MIME类型"><a href="#MIME类型" class="headerlink" title="MIME类型"></a>MIME类型</h3><table><thead><tr><th><code>text</code></th><th>表明文件是普通文本,理论上是人类可读</th><th><code>text/plain</code>, <code>text/html</code>, <code>text/css, text/javascript</code></th></tr></thead><tbody><tr><td><code>image</code></td><td>表明是某种图像。不包括视频,但是动态图(比如动态 gif)也使用 image 类型</td><td><code>image/gif</code>, <code>image/png</code>, <code>image/jpeg</code>, <code>image/bmp</code>, <code>image/webp</code>, <code>image/x-icon</code>, <code>image/vnd.microsoft.icon</code></td></tr><tr><td><code>audio</code></td><td>表明是某种音频文件</td><td><code>audio/midi</code>, <code>audio/mpeg, audio/webm, audio/ogg, audio/wav</code></td></tr><tr><td><code>video</code></td><td>表明是某种视频文件</td><td><code>video/webm</code>, <code>video/ogg</code></td></tr><tr><td><code>application</code></td><td>表明是某种二进制数据</td><td><code>application/octet-stream</code>, <code>application/pkcs12</code>, <code>application/vnd.mspowerpoint</code>, <code>application/xhtml+xml</code>, <code>application/xml</code>, <code>application/pdf</code></td></tr></tbody></table><p>由类型与子类型两个字符串中间用<code>'/'</code>分隔而组成。不允许空格存在。不敏感大小写。</p><p>对于 text 文件类型若没有特定的 subtype,就使用 <code>text/plain</code>。类似的,二进制文件没有特定或已知的 subtype,即使用 <code>application/octet-stream</code>。</p><p><a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/MIME_types#applicationoctet-stream">application/octet-stream</a>这是应用程序文件的默认值。意思是 <em>未知的应用程序文件 ,</em>浏览器一般不会自动执行或询问执行。</p><p>text/plain文本文件默认值。即使它<em>意味着未知的文本文件</em>,但浏览器认为是可以直接展示的。</p><p><a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/MIME_types#textjavascript">text/javascript </a> text/html text/css</p><p><code>multipart/byteranges</code> 用于把部分的响应报文发送回浏览器</p><h3 id="session和cookie、token"><a href="#session和cookie、token" class="headerlink" title="session和cookie、token"></a>session和cookie、token</h3><p>Session(会话机制,能识别哪个请求由哪个用户发起的机制,生成的能识别用户身份信息的字符串称为 sessionId)是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存在集群、数据库、文件中;</p><p><strong>客户端请求后,由<a href="https://www.zhihu.com/search?q=%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E5%99%A8&search_source=Entity&hybrid_search_source=Entity&hybrid_search_extra=%7B%22sourceType%22:%22answer%22,%22sourceId%22:2064471064%7D">负载均衡器</a>(如 Nginx)来决定到底打到哪台机器</strong></p><p>对应三种解决方案:</p><ul><li>session复制:所有服务器都有,都一样,性能消耗大,冗余大</li><li>session粘连:不同的session(根据ID)放在不同机器上,可靠性低</li><li>session共享:将 session 保存在 redis,<a href="https://www.zhihu.com/search?q=memcached&search_source=Entity&hybrid_search_source=Entity&hybrid_search_extra=%7B%22sourceType%22:%22answer%22,%22sourceId%22:2064471064%7D">memcached</a> 等中间件中,请求到来时,各个机器去这些中间件取一下 session ,多了一次内部连接,消耗了一点性能</li></ul><p>Cookie是客户端保存用户信息的一种机制,用来记录用户的一些信息,也是实现Session的一种方式。每当客户端要与服务端通信时,附送 cookie 可以让服务端识别用户身份,找到对应用户之前保留在服务端的信息。一般由第一次客户端访问服务端时,服务端生成并发送给客户端。</p><p>token:请求方输入自己的用户名,密码,然后 server 据此生成 token,客户端拿到 token 后会保存到本地,之后向 server 请求时在请求头带上此 token 即可。</p><ul><li>server 会有一套校验机制,校验这个 token 是否合法。</li><li>token 本身可以带 uid 信息,解密后就可以获取</li></ul><p>jwt token 主要由三部分组成 ——base64编码</p><ol><li>header:指定了签名算法 </li><li>payload:可以指定用户 id,过期时间等非敏感数据 </li><li>Signature: 签名,server 根据 header 知道它该用哪种签名算法,再用密钥根据此签名算法对 head + payload 生成签名,这样一个 token 就生成了。</li></ol><p>Token 一般是放在 header 的 Authorization 自定义头里,不是放在 Cookie 里的,这主要是为了解决跨域不能共享 Cookie 的问题 ——单点登录SSO,向其中一个网站发送请求,获得token,可以用该token发送给其它信任组网站,方便快捷。但是同样可以放在cookie里。</p><p>缺点:太长了,不太安全,<strong>适合一次性的命令认证,设置一个比较短的有效期</strong></p><p>CSRF 攻击的根本原因在于对于同样域名的每个请求来说,它的 cookie 都会被自动带上,这个是浏览器的机制决定的,所以很多人据此认定 cookie 不安全。<em>CSRF</em>(<em>Cross-site request forgery</em>)跨站请求伪造</p><p>cookie和token都保存在local storage,会被js读取,前者是存储方式,后者是验证方式</p><h3 id="浏览器缓存"><a href="#浏览器缓存" class="headerlink" title="浏览器缓存"></a>浏览器缓存</h3><p>在浏览器中,浏览器会在js和图片等文件解析执行后直接存入内存缓存中,那么当刷新页面时只需直接从内存缓存中读取;而css文件则会存入硬盘文件中,所以每次渲染页面都需要从硬盘读取缓存。</p><p><img src="/web%E7%BC%93%E5%AD%98%E7%B1%BB%E5%9E%8B-1682873589216.png" alt="web缓存类型"></p><p>所谓浏览器缓存其实就是指在本地使用的计算机中开辟一个内存区,同时也开辟一个硬盘区作为数据传输的缓冲区,然后用这个缓冲区来暂时保存用户以前访问过的信息。</p><h4 id="Web-Storage"><a href="#Web-Storage" class="headerlink" title="Web Storage"></a>Web Storage</h4><ul><li><code>sessionStorage</code> 为每一个给定的源(given origin)维持一个独立的存储区域,该存储区域在页面会话期间可用(即只要浏览器处于打开状态,包括页面重新加载和恢复)。</li><li><code>localStorage</code> 同样的功能,但是在浏览器关闭,然后重新打开后数据仍然存在。</li></ul><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">//以下均可设置localStorage</span>localStorage<span class="token punctuation">.</span>colorSetting <span class="token operator">=</span> <span class="token string">'#a4509b'</span><span class="token punctuation">;</span>localStorage<span class="token punctuation">[</span><span class="token string">'colorSetting'</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token string">'#a4509b'</span><span class="token punctuation">;</span>localStorage<span class="token punctuation">.</span><span class="token function">setItem</span><span class="token punctuation">(</span><span class="token string">'colorSetting'</span><span class="token punctuation">,</span> <span class="token string">'#a4509b'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>storage常用方法</p><pre class="language-none"><code class="language-none">Storage.key()该方法接受一个数值 n 作为参数,并返回存储中的第 n 个键名。Storage.getItem()该方法接受一个键名作为参数,返回键名对应的值。Storage.setItem()该方法接受一个键名和值作为参数,将会把键值对添加到存储中,如果键名存在,则更新其对应的值。Storage.removeItem()该方法接受一个键名作为参数,并把该键名从存储中删除。Storage.clear()调用该方法会清空存储中的所有键名。</code></pre><p>浏览器缓存细节:</p><ul><li>浏览器每次发起请求,都会<code>先在浏览器缓存中查找该请求的结果以及缓存标识</code></li><li>浏览器每次拿到返回的请求结果都会<code>将该结果和缓存标识存入浏览器缓存中</code></li></ul><p>强制缓存和协商缓存情况:</p><ul><li>浏览器请求在缓存中找不到缓存结果和缓存标识,则向服务器请求文件,服务器返回文件同时带上缓存标识,客户端把文件缓存到浏览器缓存中,此时是强制缓存范畴。</li><li>浏览器请求在缓存中能找到缓存结果和标识但已经过期,于是携带缓存标识向服务器请求,服务器决定客户端的浏览器缓存是否仍然可用有两种情况:<ul><li>仍可用,返回304,客户端再到浏览器缓存请求读取,返回。</li><li>不可用,返回200和请求结果,客户端再更新浏览器缓存。</li></ul></li><li>能找到浏览器缓存结果和标识且未过期,直接使用。-强制缓存</li></ul><h4 id="强制缓存中的HTTP响应报文字段:"><a href="#强制缓存中的HTTP响应报文字段:" class="headerlink" title="强制缓存中的HTTP响应报文字段:"></a>强制缓存中的HTTP响应报文字段:</h4><p>expires 和 cache-control,作用相似,后者优先级高</p><ul><li><h5 id="Expires"><a href="#Expires" class="headerlink" title="Expires"></a>Expires</h5><p>Expires是HTTP/1.0控制网页缓存的字段,其值为服务器返回该请求结果<code>缓存的到期时间</code>,即再次发起该请求时,如果客户端的时间小于Expires的值时,直接使用缓存结果。</p></li><li><h5 id="Cache-Control"><a href="#Cache-Control" class="headerlink" title="Cache-Control"></a>Cache-Control</h5><p>在HTTP/1.1中,Cache-Control是最重要的规则,主要用于控制网页缓存,主要取值为:</p><ul><li>public:所有内容都将被缓存(客户端和代理服务器都可缓存)</li><li>private:所有内容只有客户端可以缓存,Cache-Control的默认取值</li><li>no-cache:客户端缓存内容,但是是否使用缓存则需要经过协商缓存来验证决定</li><li>no-store:所有内容都不会被缓存,即不使用强制缓存,也不使用协商缓存</li><li>max-age=xxx (xxx is numeric):缓存内容将在xxx秒后失效</li></ul></li></ul><h4 id="协商缓存的两对字段:"><a href="#协商缓存的两对字段:" class="headerlink" title="协商缓存的两对字段:"></a>协商缓存的两对字段:</h4><p>Last-Modified / If-Modified-Since和 Etag / If-None-Match,两对中的每一对的两个字段分别为响应header字段和请求header字段,后面这一对优先级高</p><ul><li><p>Last-Modified / If-Modified-Since</p><p>Last-Modified 是服务器响应报文中记录返回资源最后在服务器中修改时间是的值, If-Modified-Since 是客户端在浏览器缓存中找到的已过期缓存的 Last-Modified 值,携带向服务器请求资源,服务器检查 If-Modified-Since 记录的值是否和自身对应资源的 Last-Modified 相同,如果相同返回304未更改,不相同则返回200和新资源及Last-Modified。</p></li><li><p>Etag / If-None-Match</p><p>Etag 是服务器响应报文返回资源的唯一标识,If-None-Match 是客户端请求向服务器时携带的对应资源在浏览器缓存中记录的 Etag,该资源在浏览器缓存中已过期。服务器收到后比对 If-None-Match 和服务器资源 Etag 是否相同,相同则返回304资源未修改,否则返回200和新资源及对应新 Etag。</p></li></ul><h4 id="刷新对于强缓存和协商缓存的影响"><a href="#刷新对于强缓存和协商缓存的影响" class="headerlink" title="刷新对于强缓存和协商缓存的影响"></a>刷新对于强缓存和协商缓存的影响</h4><ol><li>当ctrl+f5强制刷新网页时,直接从服务器加载,跳过强缓存和协商缓存。</li><li>当f5刷新网页时,跳过强缓存,但是会检查协商缓存。</li><li>浏览器地址栏中写入URL,回车 浏览器发现缓存中有这个文件了,不用继续请求了,直接去缓存拿。(最快)</li></ol><h3 id="Location"><a href="#Location" class="headerlink" title="Location"></a>Location</h3><p>http中的头部字段</p><p><strong><code>Location</code></strong> 首部指定的是需要将页面重新定向至的地址。一般在响应码为 3xx 的响应中才会有意义。</p><p>发送新请求,获取 Location 指向的新页面所采用的方法与初始请求使用的方法以及重定向的类型相关:</p><ul><li><a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status/303"><code>303</code></a> (See Also) 始终引致请求使用 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Methods/GET"><code>GET</code></a> 方法,而,而 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status/307"><code>307</code></a> (Temporary Redirect) 和 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status/308"><code>308</code></a> (Permanent Redirect) 则不转变初始请求中的所使用的方法;</li><li><a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status/301"><code>301</code></a> (Permanent Redirect) 和 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status/302"><code>302</code></a> (Found) 在大多数情况下不会转变初始请求中的方法,不过一些比较早的用户代理可能会引发方法的变更(所以你基本上不知道这一点)。</li></ul><p>状态码为上述之一的所有响应都会带有一个 Location 首部。</p><p>除了重定向响应之外,状态码为 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/201"><code>201</code></a> (Created) 的消息也会带有 Location 首部。它指向的是新创建的资源的地址。</p><p><a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Location"><code>Location</code></a> 与 <code>Content-Location</code>是不同的,前者(<a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Location"><code>Location</code></a> )指定的是一个重定向请求的目的地址(或者新创建的文件的 URL),而后者( <code>Content-Location</code>)指向的是经过内容协商后的资源的直接地址,不需要进行进一步的内容协商。Location 对应的是响应,而 Content-Location 对应的是要返回的实体。</p><h3 id="网络安全"><a href="#网络安全" class="headerlink" title="网络安全"></a>网络安全</h3><h4 id="跨域攻击"><a href="#跨域攻击" class="headerlink" title="跨域攻击"></a>跨域攻击</h4><p><strong>Cross-site request forgery</strong>, also known as <strong>one-click attack</strong> or <strong>session riding</strong> and abbreviated as <strong>CSRF</strong> (sometimes pronounced <em>sea-surf</em>[<a href="https://en.wikipedia.org/wiki/Cross-site_request_forgery#cite_note-Shiflett-1">1]</a>) or <strong>XSRF</strong>, is a type of malicious <a href="https://en.wikipedia.org/wiki/Exploit_(computer_security)">exploit</a> of a <a href="https://en.wikipedia.org/wiki/Website">website</a> where unauthorized commands are submitted from a <a href="https://en.wikipedia.org/wiki/User_(computing)">user</a> that the web application trusts.</p><p><strong>CSRF</strong>/<strong>XSRF</strong></p><p>同源策略:同域名、同协议、同端口</p><h4 id="内容安全策略"><a href="#内容安全策略" class="headerlink" title="内容安全策略"></a>内容安全策略</h4><p>content-security-policy</p><p>配置内容安全策略涉及到添加 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Content-Security-Policy"><code>Content-Security-Policy</code></a> HTTP 头部到一个页面,并配置相应的值,以控制用户代理(浏览器等)可以为该页面获取哪些资源。</p><p>一个策略由一系列策略指令所组成,每个策略指令都描述了一个针对某个特定类型资源以及生效范围的策略。你的策略应当包含一个<a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Content-Security-Policy/default-src"><code>default-src</code></a>策略指令,在其他资源类型没有符合自己的策略时应用该策略 (有关完整列表查看<a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Content-Security-Policy/default-src"><code>default-src</code></a> )。一个策略可以包含 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Content-Security-Policy/default-src"><code>default-src</code></a> 或者 <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src">script-src (en-US)</a> 指令来防止内联脚本运行,并杜绝<code>eval()</code>的使用。 一个策略也可包含一个 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Content-Security-Policy/default-src"><code>default-src</code></a> 或 <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/style-src">style-src </a> 指令去限制来自一个 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/style"><code>style</code></a> 元素或者 style 属性的內联样式。</p><p>例如:</p><p>一个网站管理者想要所有内容均来自站点的同一个源 (不包括其子域名)</p><pre class="language-none"><code class="language-none">Content-Security-Policy: default-src 'self'</code></pre><p>一个网站管理者允许内容来自信任的域名及其子域名 (域名不必须与 CSP 设置所在的域名相同)</p><pre class="language-none"><code class="language-none">Content-Security-Policy: default-src 'self' *.trusted.com</code></pre><p>一个网站管理者允许网页应用的用户在他们自己的内容中包含来自任何源的图片,但是限制音频或视频需从信任的资源提供者 (获得),所有脚本必须从特定主机服务器获取可信的代码。</p><pre class="language-none"><code class="language-none">Content-Security-Policy: default-src 'self'; img-src *; media-src media1.com media2.com; script-src userscripts.example.com</code></pre><p>在这里,各种内容默认仅允许从文档所在的源获取,但存在如下例外:</p><ul><li>图片可以从任何地方加载 (注意 “*” 通配符)。</li><li>多媒体文件仅允许从 media1.com 和 media2.com 加载 (不允许从这些站点的子域名)。</li><li>可运行脚本仅允许来自于 userscripts.example.com。</li></ul><p>一个线上银行网站的管理者想要确保网站的所有内容都要通过 SSL 方式获取,以避免攻击者窃听用户发出的请求。</p><pre class="language-none"><code class="language-none">Content-Security-Policy: default-src https://onlinebanking.jumbobank.com</code></pre><p>该服务器仅允许通过 HTTPS 方式并仅从<code>onlinebanking.jumbobank.com</code>域名来访问文档。</p><p>类似的有Content-Security-Policy-Report-Only头部信息,做测试用途,不会阻止访问但会发送违规信息到 report-uri 指令内容的地址。这意味着两种头部启用报告功能需要在指令中加上 report-uri ,但不加 Report-Only 不仅会发送报告也能同时阻止访问。</p><p>可以有效防止XSS(cross-site scripting)攻击和数据注入攻击。</p><h4 id="OWASP"><a href="#OWASP" class="headerlink" title="OWASP"></a>OWASP</h4><p>是Open Web Application Security Project的缩写,它是一个在线社区,在网络应用安全领域发表文章、方法、文档、工具和技术。</p><p>The Top 10 OWASP vulnerabilities in 2021 are:</p><ul><li>Injection</li><li>Broken authentication</li><li>Sensitive data exposure</li><li>XML external entities (XXE)</li><li>Broken access control</li><li>Security misconfigurations</li><li>Cross site scripting (XSS)</li><li>Insecure deserialization</li><li>Using components with known vulnerabilities</li><li>Insufficient logging and monitoring</li></ul><p><a href="https://sucuri.net/guides/owasp-top-10-security-vulnerabilities-2020/">https://sucuri.net/guides/owasp-top-10-security-vulnerabilities-2020/</a></p><h2 id="http相关"><a href="#http相关" class="headerlink" title="http相关"></a>http相关</h2><h3 id="cookie操作"><a href="#cookie操作" class="headerlink" title="cookie操作"></a>cookie操作</h3><p>服务器使用 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Set-Cookie"><code>Set-Cookie</code></a> 响应头部向用户代理(一般是浏览器)发送 Cookie 信息。一个简单的 Cookie 可能像这样:</p><pre class="language-none"><code class="language-none">Set-Cookie: <cookie 名>=<cookie 值></code></pre><p>服务器响应信息,该头部告知客户端保存 Cookie 信息。</p><pre class="language-none"><code class="language-none">HTTP/1.0 200 OKContent-type: text/htmlSet-Cookie: yummy_cookie=chocoSet-Cookie: tasty_cookie=strawberry[页面内容]</code></pre><p>现在,对该服务器发起的每一次新请求,浏览器都会将之前保存的 Cookie 信息通过 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Cookie"><code>Cookie</code></a> 请求头部再发送给服务器。</p><pre class="language-none"><code class="language-none">GET /sample_page.html HTTP/1.1Host: www.example.orgCookie: yummy_cookie=choco; tasty_cookie=strawberry</code></pre><h4 id="生命周期"><a href="#生命周期" class="headerlink" title="生命周期"></a>生命周期</h4><p>Cookie 的生命周期可以通过两种方式定义:</p><ul><li>会话期 Cookie 是最简单的 Cookie:浏览器关闭之后它会被自动删除,也就是说它仅在会话期内有效。会话期 Cookie 不需要指定过期时间(<code>Expires</code>)或者有效期(<code>Max-Age</code>)。需要注意的是,有些浏览器提供了会话恢复功能,这种情况下即使关闭了浏览器,会话期 Cookie 也会被保留下来,就好像浏览器从来没有关闭一样,这会导致 Cookie 的生命周期无限期延长。</li><li>持久性 Cookie 的生命周期取决于过期时间(<code>Expires</code>)或有效期(<code>Max-Age</code>)指定的一段时间。</li></ul><pre class="language-none"><code class="language-none">Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT;</code></pre><p>还有限制访问、作用域等,详见<a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Cookies">https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Cookies</a></p><h3 id="CA证书和CT校验"><a href="#CA证书和CT校验" class="headerlink" title="CA证书和CT校验"></a>CA证书和CT校验</h3><h2 id="websocket"><a href="#websocket" class="headerlink" title="websocket"></a>websocket</h2><p><a href="https://www.ruanyifeng.com/blog/2017/05/websocket.html%E5%85%A5%E9%97%A8">https://www.ruanyifeng.com/blog/2017/05/websocket.html入门</a></p><p>用于服务端向客户端推送信息,改变传统客户端为了获取服务端频繁更新而需轮询的资源浪费</p><p>它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于<a href="https://en.wikipedia.org/wiki/Push_technology">服务器推送技术</a>的一种。</p><p>其他特点包括:</p><p>(1)建立在 TCP 协议之上,服务器端的实现比较容易。</p><p>(2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。</p><p>(3)数据格式比较轻量,性能开销小,通信高效。</p><p>(4)可以发送文本,也可以发送二进制数据。</p><p>(5)没有同源限制,客户端可以与任意服务器通信。</p><p>(6)协议标识符是<code>ws</code>(如果加密,则为<code>wss</code>),服务器网址就是 URL。</p><p>WebSocket 服务器的实现,可以查看维基百科的<a href="https://en.wikipedia.org/wiki/Comparison_of_WebSocket_implementations">列表</a>。</p><p>常用的 Node 实现有以下三种。</p><ul><li><a href="https://github.com/uWebSockets/uWebSockets">µWebSockets</a></li><li><a href="http://socket.io/">Socket.IO</a></li><li><a href="https://github.com/theturtle32/WebSocket-Node">WebSocket-Node</a></li></ul><h2 id="html"><a href="#html" class="headerlink" title="html"></a><code>html</code></h2><h3 id="基础知识"><a href="#基础知识" class="headerlink" title="基础知识"></a>基础知识</h3><p><code>&lt < &gt > &nbsp/&emsp 空格 &copy 版权 &trade-&reg 商标</code></p><p>清浮动 <code>clear:left/right/both</code> <code>overflow</code>:产生块级作用域</p><p>块级元素block:可以设定宽高,换行排列行内元素inline:只能由内容撑开,同一行排列行内块级元素inline-block:可以摆在同一行且能设定宽高</p><p>calc计算中不同表达式元素必须间隔空格,以区分变量名称和运算符。并且支持混合单位运算。vh单位是视窗大小的百分比。</p><p>布局视口和视觉视口。视口基本上是当前文档的可见部分,</p><p>box-sizing属性可分配值:content box(default),border box;当指定宽度或高度时分别指内容高宽和内容+内边距+边界高宽</p><h4 id="语义化标签"><a href="#语义化标签" class="headerlink" title="语义化标签"></a>语义化标签</h4><p><a href="https://www.w3schools.com/html/html5_semantic_elements.asp">https://www.w3schools.com/html/html5_semantic_elements.asp</a></p><ul><li><article></li><li><aside></li><li><details></li><li><figcaption></li><li><figure></li><li><footer></li><li><header></li><li><main></li><li><mark></li><li><nav></li><li><section></li><li><summary></li><li><time></li></ul><p><img src="/2022/11/02/Frontend/img_sem_elements.gif" alt="HTML Semantic Elements"></p><h4 id="常见行内元素"><a href="#常见行内元素" class="headerlink" title="常见行内元素"></a>常见行内元素</h4><p>遇到父级边界换行,不支持宽高,内容撑开,不支持上下外边距,不正常显示上下外边距,换行被解析</p><p>span,a,strong,i,b,sup,sub,</p><h4 id="块级元素"><a href="#块级元素" class="headerlink" title="块级元素"></a>块级元素</h4><p>默认宽度占满父级,高度为0,自己撑开</p><p>div,h1-h6,p,ul,ol,li</p><h4 id="行内块元素"><a href="#行内块元素" class="headerlink" title="行内块元素"></a>行内块元素</h4><p>遇到父级边界换行,换行被解析,无宽高时内容撑开盒子</p><p>img</p><h3 id="常用标签"><a href="#常用标签" class="headerlink" title="常用标签"></a>常用标签</h3><h4 id="a标签"><a href="#a标签" class="headerlink" title="a标签"></a>a标签</h4><p><a> 标签的 target 属性规定在何处打开链接文档。</p><p>如果在一个 <a> 标签内包含一个 target 属性,浏览器将会载入和显示用这个标签的 href 属性命名的、名称与这个目标吻合的框架或者窗口中的文档。如果这个指定名称或 id 的框架或者窗口不存在,浏览器将打开一个新的窗口,给这个窗口一个指定的标记,然后将新的文档载入那个窗口。从此以后,超链接文档就可以指向这个新的窗口。</p><h5 id="特殊的目标"><a href="#特殊的目标" class="headerlink" title="特殊的目标"></a>特殊的目标</h5><p>有 4 个保留的目标名称用作特殊的文档重定向操作:</p><p>_blank</p><p>浏览器总在一个新打开、未命名的窗口中载入目标文档。</p><p>_self</p><p>这个目标的值对所有没有指定目标的 <a> 标签是默认目标,它使得目标文档载入并显示在相同的框架或者窗口中作为源文档。这个目标是多余且不必要的,除非和文档标题 <base> 标签中的 target 属性一起使用。</p><p>_parent</p><p>这个目标使得文档载入父窗口或者包含来超链接引用的框架的框架集。如果这个引用是在窗口或者在顶级框架中,那么它与目标 _self 等效。</p><p>_top</p><p>这个目标使得文档载入包含这个超链接的窗口,用 _top 目标将会清除所有被包含的框架并将文档载入整个浏览器窗口。</p><p><strong>提示:</strong>这些 target 的所有 4 个值都以下划线开始。任何其他用一个下划线作为开头的窗口或者目标都会被浏览器忽略,因此,不要将下划线作为文档中定义的任何框架 name 或 id 的第一个字符。</p><p>去掉下划线:<strong>text-decoration</strong>:none</p><p>点击不变色:直接设置color属性</p><h4 id="button"><a href="#button" class="headerlink" title="button"></a>button</h4><p>outline: none; //消除默认点击蓝色边框效果</p><h4 id="form标签"><a href="#form标签" class="headerlink" title="form标签"></a>form标签</h4><p>form标签的action属性是一个表单当中必须的属性,action属性规定当提交表单时,向何处发送表单数据。</p><h4 id="hr标签"><a href="#hr标签" class="headerlink" title="hr标签"></a>hr标签</h4><p><hr> 标签在 HTML 页面中创建一条水平线。</p><p>水平分隔线(horizontal rule)可以在<em>视觉上</em>将文档分隔成各个部分。</p><p>不赞成使用任何属性,建议css样式编辑</p><h4 id="input标签"><a href="#input标签" class="headerlink" title="input标签"></a>input标签</h4><pre class="language-none"><code class="language-none"><input type="text" name="catphotourl" placeholder="cat photo URL" required>长下面这样;type限制输入类型,name作为变量名称方便本地调用,placeholder给用户输入暗示,required规定必须有输入元素才能提交表单</code></pre><p><img src="/input%E6%A0%87%E7%AD%BE-1682873589216.png" alt="input标签"></p><p>input标签种类繁多,功能强大,详见<a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/Input">https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/Input</a></p><p>type属性对应值及其作用:<a href="https://blog.csdn.net/VickyTsai/article/details/94839889">https://blog.csdn.net/VickyTsai/article/details/94839889</a></p><table><thead><tr><th>属性值</th><th>用于</th></tr></thead><tbody><tr><td>① text</td><td>定义 <strong>单行的 输入文本</strong> 字段,用户可在其中输入文本。默认宽度为 20 个字符。单行文本字段。换行符 将自动 从输入值中删除。</td></tr><tr><td>② checkbox</td><td>定义 <strong>复选框</strong>。 允许 选择/取消选择 单个值 的复选框。</td></tr><tr><td>③ password</td><td>定义 <strong>密码</strong> 字段。该字段中的字符 被掩码。值被隐藏的 单行文本字段。使用<code>maxlength</code>和<code>minlength</code>属性指定 可输入值的最大长度。</td></tr><tr><td>④ hidden</td><td><strong>隐藏的 输入值</strong>: 定义 隐藏的 输入字段。不显示 但其值 提交给服务器的控件。</td></tr><tr><td>⑤ file</td><td><strong>选择文件</strong>. 定义输入字段和 “浏览”按钮,供 文件上传。允许用户 选择文件的控件。使用<code>accept</code>属性 定义控件 可以选择的 文件类型。</td></tr><tr><td>⑥ button</td><td><strong>无 默认行为的按钮</strong>: 定义 可点击<strong>按钮</strong>(多数情况下,用于通过 JavaScript 启动脚本)。一个没有默认行为的按钮。</td></tr><tr><td>⑦ radio</td><td>定义 <strong>单选 按钮</strong>。一个单选按钮,允许 从多个选项中 选择一个值。</td></tr><tr><td>⑧ reset</td><td>定义 <strong>重置按钮</strong>。重置按钮会 清除表单中的 所有数据。将表单内容重 置为默认值的按钮。</td></tr><tr><td>⑨ submit</td><td>定义 <strong>提交按钮</strong>。提交按钮 会把表单 数据发送到 服务器。提交表单的 按钮。</td></tr><tr><td>⑩ image</td><td><strong>图片提交按钮</strong>: 定义 图像形式的 提交按钮。 一个图形化的 提交按钮。必须使用<code>src</code>属性 定义图像的源,使用<code>alt</code>属性定义 替代文本。可以使用<code>height</code>高度和<code>width</code>宽度属性 以像素为单位 定义图像的大小。</td></tr></tbody></table><p>html5还有新增</p><p>value 属性为 input 元素设定值。</p><p>对于不同的输入类型,value 属性的用法也不同:</p><ul><li>type=”button”, “reset”, “submit” - 定义按钮上的显示的文本</li><li>type=”text”, “password”, “hidden” - 定义输入字段的初始值</li><li>type=”checkbox”, “radio”, “image” - 定义与输入相关联的值</li></ul><p><strong>注释:</strong><input type=”checkbox”> 和 <input type=”radio”> 中必须设置 value 属性。</p><p><strong>注释:</strong>value 属性无法与 <input type=”file”> 一同使用。</p><p>更改样式:</p><ul><li><p>input在获得焦点时外边框不变色</p><pre class="language-none"><code class="language-none">input {outline: none;}</code></pre></li><li><p>更改placeholder样式</p><p>为了兼容不同的浏览器内核:我们要添加不同的前缀:(平时开发的时候需要都添加上)</p><pre class="language-css" data-language="css"><code class="language-css"><span class="token selector">input::input-placeholder</span><span class="token punctuation">{</span><span class="token property">color</span><span class="token punctuation">:</span> red<span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token selector">input::-webkit-input-placeholder</span><span class="token punctuation">{</span>//兼容WebKit browsers(Chrome的内核)<span class="token property">color</span><span class="token punctuation">:</span> red<span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token selector">input::-moz-placeholder</span><span class="token punctuation">{</span>//Mozilla Firefox 4 to 18<span class="token property">color</span><span class="token punctuation">:</span> red<span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token selector">input::-moz-placeholder</span><span class="token punctuation">{</span>//Mozilla Firefox 19+<span class="token property">color</span><span class="token punctuation">:</span> red<span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token selector">input::-ms-input-placeholder</span><span class="token punctuation">{</span>//Internet Explorer 10+<span class="token property">color</span><span class="token punctuation">:</span> red<span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre></li></ul><h4 id="label标签"><a href="#label标签" class="headerlink" title="label标签"></a>label标签</h4><p>label标签可以把input包裹起来,让点击文本和点击按钮都让按钮被点击生效。</p><ul><li>属性for可以将label绑定到for对应value为ID的标签,但是仅表示关联且需和绑定标签相邻,没有什么特殊效果。</li></ul><pre class="language-markup" data-language="markup"><code class="language-markup">For the styling of the page to look similar on mobile as it does on a desktop or laptop, you need to add a meta element with a special content attribute.<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>viewport<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>width=device-width, initial-scale=1.0<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></code></pre><h4 id="link标签"><a href="#link标签" class="headerlink" title="link标签"></a>link标签</h4><p><code>rel</code>属性:此属性命名链接文档与当前文档的关系。type属性:这个属性被用于定义链接的内容的类型。这个属性的值应该是像 text/html,text/css 等 MIME 类型。这个属性常用的用法是定义链接的样式表,最常用的值是表明了 CSS 的 text/css。</p><h4 id="pre"><a href="#pre" class="headerlink" title="pre"></a>pre</h4><p><pre> 标签可定义预格式化的文本。</p><p>被包围在 <pre> 标签 元素中的文本通常会保留空格和换行符。而文本也会呈现为等宽字体。</p><pre> 此标签的一个常见应用就是用来表示计算机的源代码。</pre><h4 id="table"><a href="#table" class="headerlink" title="table"></a>table</h4><p>表格</p><p>包含内容</p><pre class="language-none"><code class="language-none">按照这个顺序:一个可选的 <caption> 元素零个或多个的 <colgroup> 元素一个可选的 <thead> 元素下列任意一个:零个或多个 <tbody>零个或多个 <tr>一个可选的 <tfoot> 元素</code></pre><p><strong><code><caption></code> 元素</strong> (or <em>HTML 表格标题元素</em>) 展示一个表格的标题,它常常作为 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/table">``</a> 的第一个子元素出现,同时显示在表格内容的最前面,但是,它同样可以被 CSS 样式化,所以,它同样可以出现在任何一个一个相对于表格的做任意位置。</p><h4 id="上浮和下沉标签"><a href="#上浮和下沉标签" class="headerlink" title="上浮和下沉标签"></a>上浮和下沉标签</h4><p>需要 <a href="http://www.divcss5.com/html/">html</a> 的上浮上标加html sup标签,需要下浮下标注的内容加html sub标签。<br>1)、需要上浮上标的内容前加<sup>后加</sup>标签<br>2)、需要下浮下标内容前加<sub>后加</sub>标签</p><h3 id="meta"><a href="#meta" class="headerlink" title="meta"></a>meta</h3><p>详见<a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/meta">https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/meta</a></p><ul><li>如果设置了 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/meta#attr-name"><code>name</code></a> 属性,<code>meta</code> 元素提供的是文档级别(<em>document-level</em>)的元数据,应用于整个页面。</li><li>如果设置了 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/meta#attr-http-equiv"><code>http-equiv</code></a> 属性,<code>meta</code> 元素则是编译指令,提供的信息与类似命名的 HTTP 头部相同。</li><li>如果设置了 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/meta#attr-charset"><code>charset</code></a> 属性,<code>meta</code> 元素是一个字符集声明,告诉文档使用哪种字符编码。</li><li>如果设置了 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Global_attributes#itemprop"><code>itemprop</code></a> 属性,<code>meta</code> 元素提供用户定义的元数据。</li></ul><p>meta 元素可用于提供 名称 - 值 对形式的文档元数据,<a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/meta#attr-name"><code>name</code></a> 属性为元数据条目提供名称,而 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/meta#attr-content"><code>content</code></a> 属性提供值。</p><ul><li><code>author</code>:文档作者的名字。</li><li><code>description</code>:一段简短而精确的、对页面内容的描述。一些浏览器,比如 Firefox 和 Opera,将其用作书签的默认描述。</li><li><code>generator</code>:生成此页面的软件的标识符(identifier)。</li><li><code>keywords</code>:与页面内容相关的关键词,使用逗号分隔。</li><li><code>referrer</code>:控制由当前文档发出的请求的 HTTP <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Referer"><code>Referer</code></a> 请求头。也就是请求页面的主机地址信息</li><li><a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/meta/name/theme-color"><code>theme-color</code></a>:表示当前页面的建议颜色,在自定义当前页面从或页面周围的用户界面的显示时,用户代理应当使用此颜色。<code>content</code> 属性应当包含一个有效的 CSS <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/color_value">``</a> 值。</li></ul><h4 id="select和option"><a href="#select和option" class="headerlink" title="select和option"></a>select和option</h4><p>select和option搭配使用</p><pre class="language-markup" data-language="markup"><code class="language-markup"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>pet-select<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Choose a pet:<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>label</span><span class="token punctuation">></span></span>//注意 multiple 和 disable 的用法<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>select</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>pets<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>pet-select<span class="token punctuation">"</span></span> <span class="token attr-name">multiple</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>option</span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token punctuation">"</span></span> <span class="token attr-name">disabled</span><span class="token punctuation">></span></span>--Please choose an option--<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>option</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>option</span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>dog<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Dog<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>option</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>option</span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>cat<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Cat<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>option</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>option</span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>hamster<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Hamster<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>option</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>option</span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>parrot<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Parrot<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>option</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>option</span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>spider<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Spider<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>option</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>option</span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>goldfish<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Goldfish<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>option</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>select</span><span class="token punctuation">></span></span></code></pre><h2 id="css"><a href="#css" class="headerlink" title="css"></a>css</h2><h3 id="基础"><a href="#基础" class="headerlink" title="基础"></a>基础</h3><p>块级元素之间的外边距会发生折叠。这意味着,如果一个具有上边距的元素排在在一个具有下边距的元素之下时,他们之间的间距不会是这两个外边距的和,即外边距会发生折叠,简单来说就是,间距与两个外边距中的较大者一样大。</p><p>外边距叠加:相邻元素间距会按照两者各自外边距大的算</p><p>内联盒子的宽度和高度被忽略了。外边距、内边距和边框是生效的,但它们不会改变其他内容与内联盒子的关系,因此内边距和边框会与段落中的其他单词重叠。</p><p>inline-block却能在设置宽高、内外边距的同时推开其它内联盒子</p><p>盒子四边缩写是从顶边顺时针</p><h3 id="浏览器前缀"><a href="#浏览器前缀" class="headerlink" title="浏览器前缀"></a>浏览器前缀</h3><p>浏览器厂商们有时会给<strong>实验性的或者非标准的 CSS 属性和 JavaScript API</strong> 添加前缀,这样开发者就可以用这些新的特性进行试验,同时(理论上)防止他们的试验代码被依赖,从而在标准化过程中破坏 web 开发者的代码。开发者应该等到浏览器行为标准化之后再使用未加前缀的属性。</p><ul><li><code>-webkit-</code> (谷歌,Safari,新版 Opera 浏览器,以及几乎所有 iOS 系统中的浏览器(包括 iOS 系统中的火狐浏览器);基本上所有基于 WebKit 内核的浏览器)</li><li><code>-moz-</code> (火狐浏览器)</li><li><code>-o-</code> (旧版 Opera 浏览器)</li><li><code>-ms-</code> (IE 浏览器 和 Edge 浏览器)</li></ul><h4 id="var"><a href="#var" class="headerlink" title="var()"></a>var()</h4><p><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/var#%E5%9C%A8_root_%E4%B8%8A%E5%AE%9A%E4%B9%89%EF%BC%8C%E7%84%B6%E5%90%8E%E4%BD%BF%E7%94%A8%E5%AE%83">在 :root 上定义,然后使用它</a></p><pre class="language-css" data-language="css"><code class="language-css"><span class="token comment">/*伪元素*/</span><span class="token selector">:root</span> <span class="token punctuation">{</span> <span class="token property">--main-bg-color</span><span class="token punctuation">:</span> pink<span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token selector">body</span> <span class="token punctuation">{</span> <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--main-bg-color<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><p><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/var#%E5%BD%93%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%80%BC%E6%9C%AA%E5%AE%9A%E4%B9%89%EF%BC%8C%E5%9B%9E%E9%80%80%E5%80%BC%E7%94%9F%E6%95%88">当第一个值未定义,回退值生效</a></p><pre class="language-css" data-language="css"><code class="language-css"><span class="token comment">/* 后备值 */</span><span class="token comment">/* 在父元素样式中定义一个值 */</span><span class="token selector">.component</span> <span class="token punctuation">{</span> <span class="token property">--text-color</span><span class="token punctuation">:</span> #080<span class="token punctuation">;</span> <span class="token comment">/* header-color 并没有被设定 */</span><span class="token punctuation">}</span><span class="token comment">/* 在 component 的样式中使用它: */</span><span class="token selector">.component .text</span> <span class="token punctuation">{</span> <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--text-color<span class="token punctuation">,</span> black<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 此处 color 正常取值 --text-color */</span><span class="token punctuation">}</span><span class="token selector">.component .header</span> <span class="token punctuation">{</span> <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--header-color<span class="token punctuation">,</span> blue<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* 此处 color 被回退到 blue */</span><span class="token punctuation">}</span></code></pre><h3 id="常用长度单位"><a href="#常用长度单位" class="headerlink" title="常用长度单位"></a>常用长度单位</h3><p>相对长度单位</p><table><thead><tr><th align="left">单位</th><th align="left">相对于</th></tr></thead><tbody><tr><td align="left"><code>em</code></td><td align="left">在 font-size 中使用是相对于父元素的字体大小,在其他属性中使用是相对于自身的字体大小,如 width</td></tr><tr><td align="left"><code>ex</code></td><td align="left">字符“x”的高度</td></tr><tr><td align="left"><code>ch</code></td><td align="left">数字“0”的宽度</td></tr><tr><td align="left"><code>rem</code></td><td align="left">根元素的字体大小,html文档中默认字体大小为 16px</td></tr><tr><td align="left"><code>lh</code></td><td align="left">元素的 line-height</td></tr><tr><td align="left"><code>vw</code></td><td align="left">视窗<strong>宽度</strong>的 1%</td></tr><tr><td align="left"><code>vh</code></td><td align="left">视窗<strong>高度</strong>的 1%</td></tr><tr><td align="left"><code>vmin</code></td><td align="left">视窗较小尺寸的 1%</td></tr><tr><td align="left"><code>vmax</code></td><td align="left">视图大尺寸的 1%</td></tr></tbody></table><p>dp是设计领域常用的单位,指虚拟像素,160ppi时1dp=1px,240ppi时1dp=1.5px</p><p>像素密度的英文名称:Pixels Per Inch,简写PPI。像素密度的计算公式为:√(W^2+H^2)/S,其中W和H是分辨率的宽高,S是屏幕尺寸。</p><h3 id="常用属性"><a href="#常用属性" class="headerlink" title="常用属性"></a>常用属性</h3><h4 id="background-clip"><a href="#background-clip" class="headerlink" title="background-clip"></a>background-clip</h4><p><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/background-clip">https://developer.mozilla.org/zh-CN/docs/Web/CSS/background-clip</a></p><p>设置元素的背景(背景图片或颜色)是否延伸到边框、内边距盒子、内容盒子下面。</p><p>如果没有设置背景图片(<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/background-image"><code>background-image</code></a>)或背景颜色(<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/background-color"><code>background-color</code></a>),那么这个属性只有在边框( <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/border"><code>border</code></a>)被设置为非固实(soild)、透明或半透明时才能看到视觉效果(与 <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/border-style"><code>border-style</code></a> 或 <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/border-image"><code>border-image</code></a> 有关),否则,本属性产生的样式变化会被边框覆盖。</p><p>可选值:</p><pre class="language-none"><code class="language-none">border-box</code></pre><p>背景延伸至边框外沿(但是在边框下层)。</p><pre class="language-none"><code class="language-none">padding-box</code></pre><p>背景延伸至内边距(<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/padding"><code>padding</code></a>)外沿。不会绘制到边框处。</p><pre class="language-none"><code class="language-none">content-box</code></pre><p>背景被裁剪至内容区(content box)外沿。</p><p><code>text</code> 实验性</p><p>背景被裁剪成文字的前景色。</p><p>兼容性:在chrome中建议结合-webkit前缀使用</p><p><img src="/2022/11/02/Frontend/image-20230330194001961.png" alt="image-20230330194001961"></p><h4 id="border"><a href="#border" class="headerlink" title="border"></a>border</h4><p>border-width,border-style,border-color缩写</p><p>border-style可选值</p><table><thead><tr><th align="left"><code>none</code></th><th align="left"></th><th align="left">和关键字 <code>hidden</code> 类似,不显示边框。在这种情况下,如果没有设定背景图片,<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/border-width"><code>border-width</code></a> 计算后的值将是 <code>0</code>,即使先前已经指定过它的值。在单元格边框重叠情况下,<code>none</code> 值优先级最低,意味着如果存在其他的重叠边框,则会显示为那个边框。</th></tr></thead><tbody><tr><td align="left"><code>hidden</code></td><td align="left"></td><td align="left">和关键字 <code>none</code> 类似,不显示边框。在这种情况下,如果没有设定背景图片,<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/border-width"><code>border-width</code></a> 计算后的值将是 <code>0</code>,即使先前已经指定过它的值。在单元格边框重叠情况下,<code>hidden</code> 值优先级最高,意味着如果存在其他的重叠边框,边框不会显示。</td></tr><tr><td align="left"><code>dotted</code></td><td align="left"></td><td align="left">显示为一系列圆点。标准中没有定义两点之间的间隔大小,视不同实现而定。圆点半径是 <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/border-width"><code>border-width</code></a> 计算值的一半。</td></tr><tr><td align="left"><code>dashed</code></td><td align="left"></td><td align="left">显示为一系列短的方形虚线。标准中没有定义线段的长度和大小,视不同实现而定。</td></tr><tr><td align="left"><code>solid</code></td><td align="left"></td><td align="left">显示为一条实线。</td></tr><tr><td align="left"><code>double</code></td><td align="left"></td><td align="left">显示为一条双实线,宽度是 <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/border-width"><code>border-width</code></a> 。</td></tr></tbody></table><h4 id="box-shadow"><a href="#box-shadow" class="headerlink" title="box-shadow"></a>box-shadow</h4><p>用于在元素的框架上添加阴影效果,两个长度值为x、y轴偏移量,三个时第三个为blur-radius,第四个为spread-radius</p><ul><li>可选,<code>inset</code>关键字。</li><li>可选,<code><color></code>值。</li><li>若要对同一个元素添加多个阴影效果,请使用逗号将每个阴影规则分隔开。</li></ul><pre class="language-css" data-language="css"><code class="language-css"><span class="token comment">/* x 偏移量 | y 偏移量 | 阴影颜色 */</span><span class="token property">box-shadow</span><span class="token punctuation">:</span> 60px -16px teal<span class="token punctuation">;</span><span class="token comment">/* x 偏移量 | y 偏移量 | 阴影模糊半径 | 阴影颜色 */</span><span class="token property">box-shadow</span><span class="token punctuation">:</span> 10px 5px 5px black<span class="token punctuation">;</span><span class="token comment">/* x 偏移量 | y 偏移量 | 阴影模糊半径 | 阴影扩散半径 | 阴影颜色 */</span><span class="token property">box-shadow</span><span class="token punctuation">:</span> 2px 2px 2px 1px <span class="token function">rgba</span><span class="token punctuation">(</span>0<span class="token punctuation">,</span> 0<span class="token punctuation">,</span> 0<span class="token punctuation">,</span> 0.2<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">/* 插页 (阴影向内) | x 偏移量 | y 偏移量 | 阴影颜色 */</span><span class="token property">box-shadow</span><span class="token punctuation">:</span> inset 5em 1em gold<span class="token punctuation">;</span><span class="token comment">/* 任意数量的阴影,以逗号分隔 */</span><span class="token property">box-shadow</span><span class="token punctuation">:</span> 3px 3px red<span class="token punctuation">,</span> -1em 0 0.4em olive<span class="token punctuation">;</span><span class="token comment">/* 全局关键字 */</span><span class="token property">box-shadow</span><span class="token punctuation">:</span> inherit<span class="token punctuation">;</span><span class="token property">box-shadow</span><span class="token punctuation">:</span> initial<span class="token punctuation">;</span><span class="token property">box-shadow</span><span class="token punctuation">:</span> unset<span class="token punctuation">;</span></code></pre><p>元素设置了border-radius时,转变为圆角阴影</p><h4 id="line-height"><a href="#line-height" class="headerlink" title="line-height"></a>line-height</h4><p><strong><code>line-height</code></strong> <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS">CSS</a> 属性用于设置多行元素的空间量,如多行文本的间距。对于块级元素,它指定元素行盒(line boxes)的最小高度。对于非<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/Replaced_element">替代</a>的 inline 元素,它用于计算行盒(line box)的高度。</p><blockquote><p>可替代元素:它们的内容不受当前文档的样式的影响。CSS 可以影响可替换元素的位置,但不会影响到可替换元素自身的内容。某些可替换元素,例如<iframe>元素,可能具有自己的样式表,但它们不会继承父文档的样式。</p><p>典型可替代元素包括 iframe、img、video、embed等</p></blockquote><h4 id="list-style"><a href="#list-style" class="headerlink" title="list-style"></a>list-style</h4><p>list-style-type,list-style-position,list-style-image 的缩写</p><p>分别可指定列表前符号类型,位置和选用图片时图片的url</p><pre class="language-none"><code class="language-none">{list-style-type:none|disc|circle|square|decimal|lower-roman|upper-roman|lower-alpha|upper-alpha}</code></pre><h4 id="filter"><a href="#filter" class="headerlink" title="filter"></a>filter</h4><p><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/filter#%E8%AF%AD%E6%B3%95">https://developer.mozilla.org/zh-CN/docs/Web/CSS/filter#%E8%AF%AD%E6%B3%95</a></p><p><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS">CSS</a>属性 <strong><code>filter</code></strong> 将模糊或颜色偏移等图形效果应用于元素。滤镜通常用于调整图像、背景和边框的渲染。</p><p>CSS 标准里包含了一些已实现预定义效果的函数。你也可以参考一个 SVG 滤镜,通过一个 URL 链接到 SVG 滤镜元素(<a href="https://developer.mozilla.org/zh-CN/docs/Web/SVG/Element/filter">SVG filter element</a>)。</p><pre class="language-none"><code class="language-none">/* URL to SVG filter */filter: url("filters.svg#filter-id");/* <filter-function> values */filter: blur(5px);filter: brightness(0.4);filter: contrast(200%);filter: drop-shadow(16px 16px 20px blue);filter: grayscale(50%);filter: hue-rotate(90deg);filter: invert(75%);filter: opacity(25%);filter: saturate(30%);filter: sepia(60%);/* Multiple filters */filter: contrast(175%) brightness(3%);/* Use no filter */filter: none;/* Global values */filter: inherit;filter: initial;filter: revert;filter: unset;</code></pre><h4 id="font-smooth"><a href="#font-smooth" class="headerlink" title="font-smooth"></a>font-smooth</h4><p>实际上,Chrome等webkit浏览器使用的是<code>-webkit-font-smoothing</code>,Firefox浏览器下是<code>-moz-osx-font-smoothing</code>,</p><p>相关语法和含义如下:<br><strong>-webkit-font-smoothing</strong></p><ul><li><p><code>none</code></p><p>关闭抗锯齿,字体边缘犀利。</p></li><li><p><code>antialiased</code></p><p>字体像素级平滑,在深色背景上会让文字看起来更细了。</p></li><li><p><code>subpixel-antialiased</code></p><p>字体亚像素级平滑,主要为了在非视网膜设备下更好的显示。</p></li></ul><p><strong>-moz-osx-font-smoothing</strong></p><ul><li><p><code>auto</code></p><p>览器只能选择字体渲染表现。</p></li><li><p><code>grayscale</code></p></li></ul><p>按照我个人的使用经验来看,文字平滑属性<code>font-smoothing</code>在windows设备下好像都是打酱油的,各个属性值看不出差别,或许与显示器的设备像素比有关,在OS X设备下渲染有着明显的效果。</p><h4 id="页面滚动相关"><a href="#页面滚动相关" class="headerlink" title="页面滚动相关"></a>页面滚动相关</h4><p>clientHeight,元素height+上下padding-水平滚动条高度(如果存在);类似有clientwidth</p><p><img src="/2022/11/02/Frontend/dimensions-client.png" alt="img"></p><p>scrollHeight,一个元素内容高度的度量,包括由于溢出导致的视图中不可见内容</p><p><img src="/2022/11/02/Frontend/scrollheight.png" alt="img"></p><p>等于该元素在不使用滚动条的情况下为了适应视口中所用内容所需的最小高度,此时也等于clientHeight,也包括::before和::after这样的伪元素</p><p>offsetHeight/Width 相比client包含边框</p><p>scrollTop,滑过的元素高度离当前视窗元素顶部的距离</p><ul><li>如果一个元素不能被滚动(例如,它没有溢出,或者这个元素有一个”**non-scrollable”**属性), <code>scrollTop</code>将被设置为<code>0</code>。</li><li>设置<code>scrollTop</code>的值小于 0,<code>scrollTop</code> 被设为<code>0</code></li><li>如果设置了超出这个容器可滚动的值,<code>scrollTop</code> 会被设为最大值。</li></ul><h4 id="opacity"><a href="#opacity" class="headerlink" title="opacity"></a>opacity</h4><p>元素透明度,0-1取值,0为完全透明,1为完全不透明</p><h4 id="tabindex"><a href="#tabindex" class="headerlink" title="tabindex"></a>tabindex</h4><p><strong>tabindex</strong> <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Global_attributes">全局属性</a> 指示其元素是否可以聚焦,以及它是否/在何处参与顺序键盘导航(通常使用Tab键,因此得名)。</p><ul><li>tabindex=负值 (通常是 tabindex=“-1”),表示元素是可聚焦的,但是不能通过键盘导航来访问到该元素,用 JS 做页面小组件内部键盘导航的时候非常有用。</li><li><code>tabindex="0"</code> ,表示元素是可聚焦的,并且可以通过键盘导航来聚焦到该元素,它的相对顺序是当前处于的 DOM 结构来决定的。</li><li>tabindex=正值,表示元素是可聚焦的,并且可以通过键盘导航来访问到该元素;它的相对顺序按照<strong>tabindex</strong> 的数值递增而滞后获焦。如果多个元素拥有相同的 <strong>tabindex</strong>,它们的相对顺序按照他们在当前 DOM 中的先后顺序决定。</li></ul><p>键盘事件(发生在聚焦的元素上,可以聚焦的元素tabindex为正值,如果没有为正值的元素建议绑定到document上)。</p><p><strong>tabindex</strong> <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Global_attributes">全局属性</a> 指示其元素是否可以聚焦,以及它是否/在何处参与顺序键盘导航(通常使用Tab键,因此得名)。</p><blockquote><p>Tabindex 有可能成为一个有用的属性。开发人员可以设置当用户在表单(或链接或内容)中切换时焦点在页面上移动的顺序。它成为过分依赖绝对定位且不自然流动的表单和页面的权宜之计。</p><p>–Don’t Use Tabindex Greater than 0</p></blockquote><h4 id="text-decoration"><a href="#text-decoration" class="headerlink" title="text-decoration"></a>text-decoration</h4><p>设置文本样式</p><p><code>text-decoration</code> 这个 CSS 属性是用于设置文本的修饰线外观的(下划线、上划线、贯穿线/删除线 或 闪烁)它是 <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/text-decoration-line"><code>text-decoration-line</code></a>, <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/text-decoration-color"><code>text-decoration-color</code></a>, <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/text-decoration-style"><code>text-decoration-style</code></a>, 和新出现的 <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/text-decoration-thickness"><code>text-decoration-thickness</code></a> 属性的缩写。</p><p>文本修饰属性会延伸到子元素。这意味着如果祖先元素指定了文本修饰属性,子元素则不能将其删除。</p><h5 id="值"><a href="#值" class="headerlink" title="值"></a>值</h5><p><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/text-decoration-line"><code>text-decoration-line</code></a></p><p>文本修饰的位置,如下划线<code>underline</code>,删除线<code>line-through</code></p><p><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/text-decoration-color"><code>text-decoration-color</code></a></p><p>文本修饰的颜色</p><p><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/text-decoration-style"><code>text-decoration-style</code></a></p><p>文本修饰的样式,如波浪线<code>wavy</code>实线<code>solid</code>虚线<code>dashed</code></p><p><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/text-decoration-thickness"><code>text-decoration-thickness</code></a></p><p>文本修饰线的粗细</p><h4 id="title"><a href="#title" class="headerlink" title="title"></a>title</h4><p>任何元素设置此属性后,鼠标悬浮时会生成悬浮框浮现title值字符串</p><h4 id="white-space"><a href="#white-space" class="headerlink" title="white-space"></a>white-space</h4><p>white-space 属性设置如何处理<strong>元素内</strong>的空白。注意:只要写在标签元素内部就算</p><p>可能的值</p><table><thead><tr><th align="left">值</th><th align="left">描述</th></tr></thead><tbody><tr><td align="left">normal</td><td align="left">默认。空白会被浏览器忽略。</td></tr><tr><td align="left">pre</td><td align="left">空白会被浏览器保留。其行为方式类似 HTML 中的 <pre> 标签。</td></tr><tr><td align="left">nowrap</td><td align="left">文本不会换行,文本会在在同一行上继续,直到遇到 <br> 标签为止。</td></tr><tr><td align="left">pre-wrap</td><td align="left">保留空白符序列,但是正常地进行换行。</td></tr><tr><td align="left">pre-line</td><td align="left">合并空白符序列,但是保留换行符。</td></tr><tr><td align="left">inherit</td><td align="left">规定应该从父元素继承 white-space 属性的值。</td></tr></tbody></table><p>例:</p><pre class="language-none"><code class="language-none"><td>{{$t(xxx)}}</td></code></pre><p>这时候i18n文本前后都会有空白,这个属性都能控制。</p><h4 id="z-index"><a href="#z-index" class="headerlink" title="z-index"></a>z-index</h4><p><code>z-index</code> 属性设定了一个定位元素及其后代元素或 flex 项目的 z-order。当元素之间重叠的时候,z-index 较大的元素会覆盖较小的元素在上层进行显示。</p><p>对于一个已经定位的盒子(即其 <code>position</code> 属性值不是 <code>static</code>,这里要注意的是 CSS 把元素看作盒子),<code>z-index</code> 属性指定:</p><ol><li>盒子在当前堆叠上下文中的堆叠层级。</li><li>盒子是否创建一个本地堆叠上下文。</li></ol><p>默认值为auto,可写为整数(比较大小决定堆叠顺序)</p><h4 id="webkit-line-clamp"><a href="#webkit-line-clamp" class="headerlink" title="-webkit-line-clamp"></a>-webkit-line-clamp</h4><p><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/-webkit-line-clamp">https://developer.mozilla.org/zh-CN/docs/Web/CSS/-webkit-line-clamp</a></p><p><strong><code>-webkit-line-clamp</code></strong> CSS 属性可以把<a href="https://developer.mozilla.org/zh-CN/docs/Glossary/Block">块容器</a>中的内容限制为指定的行数。</p><p>它只有在 <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/display"><code>display</code></a> 属性设置成 <code>-webkit-box</code> 或者 <code>-webkit-inline-box</code> 并且 <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/box-orient"><code>box-orient</code></a> 属性设置成 <code>vertical</code>时才有效果。</p><p>在大部分情况下,也需要设置 <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/overflow"><code>overflow</code></a> 属性为 <code>hidden</code>,否则,里面的内容不会被裁减,并且在内容显示为指定行数后还会显示省略号。</p><p>当应用于锚(anchor)元素时,截断可以发生在文本中间,而不必在末尾。</p><p>可选值</p><pre class="language-none"><code class="language-none">none</code></pre><p>这个值表明内容显示不会被限制。</p><p><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/integer"><code>integer</code></a></p><p>这个值表明内容显示了多少行之后会被限制。必须大于 0。</p><h3 id="全局属性"><a href="#全局属性" class="headerlink" title="全局属性"></a>全局属性</h3><p><a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Global_attributes">https://developer.mozilla.org/zh-CN/docs/Web/HTML/Global_attributes</a></p><h3 id="盒模型、正常流"><a href="#盒模型、正常流" class="headerlink" title="盒模型、正常流"></a>盒模型、正常流</h3><p>盒子模型:外边距(<a href="https://so.csdn.net/so/search?q=margin&spm=1001.2101.3001.7020">margin</a>)+ border(边框) + 内边距(padding)+ content(内容)</p><pre class="language-none"><code class="language-none">标准盒子模型,一般浏览器也都默认为标准盒子模型。即:box-sizing:content-box怪异盒子模型,一般根据实际项目需要自行设置。即:box-sizing:border-boxpadding和border的值就不会影响元素的宽高,相当于把padding和border的值都算在content里</code></pre><p>上、下外边框的设置对*不<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/Replaced_element">可替换</a>*内联元素,如 span 和code,无效。</p><h4 id="外边距重叠"><a href="#外边距重叠" class="headerlink" title="外边距重叠"></a>外边距重叠</h4><p>块的<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/margin-top">上外边距 (margin-top)</a>和<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/margin-bottom">下外边距 (margin-bottom)</a>有时合并 (折叠) 为单个边距,其大小为单个边距的最大值 (或如果它们相等,则仅为其中一个),这种行为称为<strong>边距折叠</strong>。</p><p><strong>备注:</strong> 有设定<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/float">float</a>和<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/position#absolute">position=absolute</a>的元素不会产生外边距重叠行为。</p><p>三种情况会产生此问题:</p><ul><li><p>同一层相邻元素之间</p><p>外边距重叠,只会挑选最大边界范围留下,除非后一个元素加上<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/clear">clear-fix 清除浮动</a>。</p></li><li><p>没有内容将父元素和后代元素分开</p><p>如果没有边框<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/border"><code>border</code></a>,内边距<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/padding"><code>padding</code></a>,行内内容,也没有创建<a href="https://developer.mozilla.org/zh-CN/docs/Web/Guide/CSS/Block_formatting_context">块级格式上下文</a>或<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/clear">清除浮动</a>来分开一个块级元素的上边界<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/margin-top"><code>margin-top</code></a> 与其内一个或多个后代块级元素的上边界<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/margin-top"><code>margin-top</code></a>;</p><p>或没有边框,内边距,行内内容,高度,最小高度<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/min-height"><code>min-height</code></a>或 最大高度<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/max-height"><code>max-height</code></a> 来分开一个块级元素的下边界<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/margin-bottom"><code>margin-bottom</code></a>与其内的一个或多个后代后代块元素的下边界<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/margin-bottom"><code>margin-bottom</code></a></p><p>就会出现父块元素和其内后代块元素外边界重叠,重叠部分最终会溢出到父级块元素外面。</p></li><li><p>空的块级元素</p><p>当一个块元素上边界<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/margin-top"><code>margin-top</code></a> 直接贴到元素下边界<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/margin-bottom"><code>margin-bottom</code></a>时也会发生边界折叠。这种情况会发生在一个块元素完全没有设定边框<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/border"><code>border</code></a>、内边距<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/padding"><code>padding</code></a>、高度<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/height"><code>height</code></a>、最小高度<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/min-height"><code>min-height</code></a> 、最大高度<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/max-height"><code>max-height</code></a> 、内容设定为 inline 或是加上<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/clear">clear-fix</a>的时候。</p></li></ul><p>一些需要注意的地方:</p><ul><li>上述情况的组合会产生更复杂的外边距折叠。</li><li>即使某一外边距为 0,这些规则仍然适用。因此就算父元素的外边距是 0,第一个或最后一个子元素的外边距仍然会“溢出”到父元素的外面。</li><li>如果参与折叠的外边距中包含负值,折叠后的外边距的值为最大的正边距与最小的负边距(即绝对值最大的负边距)的和;也就是说如果有 -13px 8px 100px 叠在一起,边界范围就是 100px -13px 的 87px。</li><li>如果所有参与折叠的外边距都为负,折叠后的外边距的值为最小的负边距的值。这一规则适用于相邻元素和嵌套元素。</li></ul><p>以上这些内容都是发生在 Block-Level 的元素,设定 floating 和 absolutely positioned 的元素完全不用担心边界重叠的问题。</p><h3 id="块级格式化上下文"><a href="#块级格式化上下文" class="headerlink" title="块级格式化上下文"></a>块级格式化上下文</h3><p>Web 页面的可视 CSS 渲染的一部分,是块级盒子的布局过程发生的区域,也是浮动元素与其他元素交互的区域</p><p>格式化上下文影响布局,通常,我们会为定位和清除浮动创建新的 BFC,而不是更改布局,因为它将:</p><ul><li>包含内部浮动</li><li>排除外部浮动</li><li>阻止 <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_Box_Model/Mastering_margin_collapsing">外边距重叠</a>!!!</li></ul><p>会创建块级格式化上下文的操作:</p><ul><li>根元素(<code><html></code>)</li><li>浮动元素(<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/float"><code>float</code></a> 值不为 <code>none</code>)</li><li>绝对定位元素(<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/position"><code>position</code></a> 值为 <code>absolute</code> 或 <code>fixed</code>)</li><li>行内块元素(<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/display"><code>display</code></a> 值为 <code>inline-block</code>)</li><li>表格单元格(<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/display"><code>display</code></a> 值为 <code>table-cell</code>,HTML 表格单元格默认值)</li><li>表格标题(<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/display"><code>display</code></a> 值为 <code>table-caption</code>,HTML 表格标题默认值)</li><li>匿名表格单元格元素(<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/display"><code>display</code></a> 值为 <code>table</code>、<code>table-row</code>、 <code>table-row-group</code>、<code>table-header-group</code>、<code>table-footer-group</code>(分别是 HTML table、tr、tbody、thead、tfoot 的默认值)或 <code>inline-table</code>)</li><li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/overflow"><code>overflow</code></a> 值不为 <code>visible</code>、<code>clip</code> 的块元素</li><li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/display"><code>display</code></a> 值为 <code>flow-root</code> 的元素</li><li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/contain"><code>contain</code></a> 值为 <code>layout</code>、<code>content</code> 或 <code>paint</code> 的元素</li><li>弹性元素(<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/display"><code>display</code></a> 值为 <code>flex</code> 或 <code>inline-flex</code> 元素的直接子元素),如果它们本身既不是 <a href="https://developer.mozilla.org/zh-CN/docs/Glossary/Flex_Container">flex</a>、<a href="https://developer.mozilla.org/zh-CN/docs/Glossary/Grid_Container">grid</a> 也不是 <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_Table">table</a> 容器</li><li>网格元素(<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/display"><code>display</code></a> 值为 <code>grid</code> 或 <code>inline-grid</code> 元素的直接子元素),如果它们本身既不是 <a href="https://developer.mozilla.org/zh-CN/docs/Glossary/Flex_Container">flex</a>、<a href="https://developer.mozilla.org/zh-CN/docs/Glossary/Grid_Container">grid</a> 也不是 <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_Table">table</a> 容器</li><li>多列容器(<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/column-count"><code>column-count</code></a> 或 <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/column-width"><code>column-width</code> (en-US)</a> 值不为 <code>auto</code>,包括<code>column-count</code> 为 <code>1</code>)</li><li><code>column-span</code> 值为 <code>all</code> 的元素始终会创建一个新的 BFC,即使该元素没有包裹在一个多列容器中 (<a href="https://github.com/w3c/csswg-drafts/commit/a8634b96900279916bd6c505fda88dda71d8ec51">规范变更</a>, <a href="https://bugs.chromium.org/p/chromium/issues/detail?id=709362">Chrome bug</a>)</li></ul><h3 id="选择器"><a href="#选择器" class="headerlink" title="选择器"></a>选择器</h3><h4 id="优先级"><a href="#优先级" class="headerlink" title="优先级"></a>优先级</h4><p>最近的祖先样式比其他祖先样式优先级高。</p><p>"直接样式"比"祖先样式"优先级高。</p><p>内联样式 > ID 选择器# > 类选择器.class = 属性选择器 = 伪类选择器 > 标签选择器element = 伪元素选择器</p><h4 id="伪类"><a href="#伪类" class="headerlink" title="伪类"></a><strong>伪类</strong></h4><p>添加到选择器的关键字,指定要选择的元素的特殊状态。例如,<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/:hover"><code>:hover</code></a> 可被用于在用户将鼠标悬停在按钮上时改变按钮的颜色。</p><p>:root 这个 CSS <strong>伪类匹配文档树的根元素</strong>。 对于 HTML 来说, :root 表示 <html> 元素,除了 优先级 更高之外,与 html 选择器相同。</p><h4 id="伪元素"><a href="#伪元素" class="headerlink" title="伪元素"></a><strong>伪元素</strong></h4><p>以类似方式表现,不过表现得是像你往标记文本中加入全新的 HTML 元素一样,而不是向现有的元素上应用类。例如<code>::first-line</code></p><h4 id="类选择器"><a href="#类选择器" class="headerlink" title="类选择器"></a>类选择器</h4><p><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS">CSS</a> <strong>类选择器</strong>根据 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTML/Global_attributes#class"><code>class</code></a> 属性的内容匹配元素。</p><pre class="language-none"><code class="language-none">/* 所有含有 class="spacious" 类的元素 */.spacious { margin: 2em;}/* 所有含有 class="spacious" 类的 <li> 元素 */li.spacious { margin: 2em;}/* 所有同时含有“spacious”和“elegant”类的 <li> 元素 *//* 例如 class="elegant retro spacious" */li.spacious.elegant { margin: 2em;}</code></pre><h4 id="相邻兄弟组合器"><a href="#相邻兄弟组合器" class="headerlink" title="相邻兄弟组合器"></a>相邻兄弟组合器</h4><p>+ 作为运算符,介于两个选择器之间,当第二个元素<em>紧跟在</em>第一个元素之后,并且两个元素都是属于同一个父 <a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Element"><code>element</code></a> 的子元素,则第二个元素将被选中。</p><h4 id="子组合器"><a href="#子组合器" class="headerlink" title="子组合器"></a>子组合器</h4><p>> 作为运算符,介于两个选择器之间,当且仅当第二个选择器选择的元素为第一个选择器选择的元素的直接子元素,匹配第二个选择器选择的元素</p><h4 id="后代选择器"><a href="#后代选择器" class="headerlink" title="后代选择器"></a>后代选择器</h4><p><strong>后代组合器</strong>(通常用单个空格(" ")字符表示)组合了两个选择器,如果第二个选择器匹配的元素具有与第一个选择器匹配的祖先(父母,父母的父母,父母的父母的父母等)元素,则它们将被选择。利用后代组合器的选择器称为<em>后代选择器</em>。</p><h4 id="通用兄弟选择器"><a href="#通用兄弟选择器" class="headerlink" title="通用兄弟选择器"></a>通用兄弟选择器</h4><h3 id="flex布局"><a href="#flex布局" class="headerlink" title="flex布局"></a>flex布局</h3><p>flexbox弹性布局,一维布局模型display:flex</p><h4 id="容器属性"><a href="#容器属性" class="headerlink" title="容器属性"></a>容器属性</h4><p>flex-direction:四种摆放方向,垂直和水平的正反</p><ul><li><code>row</code></li><li><code>row-reverse</code></li><li><code>column</code></li><li><code>column-reverse</code></li></ul><p>flex-wrap:指定 flex 元素单行显示还是多行显示。如果允许换行,这个属性允许你控制行的堆叠方向。</p><ul><li><p>nowrap</p><p>flex 的元素被摆放到到一行,这可能导致 flex 容器溢出。<strong>cross-start</strong> 会根据 <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/flex-direction"><code>flex-direction</code></a> 的值等价于 <strong>start</strong> 或 <strong>before</strong>。为该属性的默认值。</p></li><li><p>wrap</p><p>flex 元素 被打断到多个行中。<strong>cross-start</strong> 会根据 <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/flex-direction"><code>flex-direction</code></a> 的值等价于 <strong>start</strong> 或<strong>before</strong>。<strong>cross-end</strong> 为确定的 <strong>cross-start</strong> 的另一端。</p></li><li><p>wrap-reverse</p><p>和 wrap 的行为一样,但是 <strong>cross-start</strong> 和 <strong>cross-end</strong> 互换。</p></li></ul><p>flex-flow:前两个属性的结合</p><p>justify-content:主轴对齐方式。它可能取5个值,具体对齐方式与轴的方向有关。下面假设主轴为从左到右。</p><blockquote><ul><li><code>flex-start</code>(默认值):左对齐</li><li><code>flex-end</code>:右对齐</li><li><code>center</code>: 居中</li><li><code>space-between</code>:两端对齐,项目之间的间隔都相等。</li><li><code>space-around</code>:每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。</li></ul></blockquote><p>align-items:交叉轴对齐方式,它可能取5个值。具体的对齐方式与交叉轴的方向有关,下面假设交叉轴从上到下。</p><blockquote><ul><li><code>flex-start</code>:与交叉轴的起点对齐。</li><li><code>flex-end</code>:与交叉轴的终点对齐。</li><li><code>center</code>:与交叉轴的中点对齐。</li><li><code>space-between</code>:与交叉轴两端对齐,轴线之间的间隔平均分布。</li><li><code>space-around</code>:每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍。</li><li><code>stretch</code>(默认值):轴线占满整个交叉轴。</li></ul></blockquote><p>align-content:定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。</p><p>五种对齐方式:这里的左右是相对于轴方向而言</p><ul><li><code>flex-start</code>(默认值):左对齐</li><li><code>flex-end</code>:右对齐</li><li><code>center</code>: 居中</li><li><code>space-between</code>:两端对齐,项目之间的间隔都相等。</li><li><code>space-around</code>:每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。</li></ul><h4 id="内部元素属性"><a href="#内部元素属性" class="headerlink" title="内部元素属性"></a>内部元素属性</h4><p>order:<code>order</code>属性定义项目的排列顺序。数值越小,排列越靠前,默认为0。</p><p>flex-grow:对容器内剩余空间的处理,为容器内的每个元素进行分配,分配的值依此属性值而定。定义项目的放大比例,默认为<code>0</code>,即如果存在剩余空间,也不放大。</p><p>flex-shrink:对溢出空间的处理,对容器内每个元素的压缩的值依此属性的值而定。属性定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小。</p><p>flex-basis:定义了在分配多余空间之前,项目占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为<code>auto</code>,即项目的本来大小。</p><p>flex:flex属性是<code>flex-grow</code>, <code>flex-shrink</code> 和 <code>flex-basis</code>的简写,默认值为<code>0 1 auto</code>。后两个属性可选。</p><p>align-self:<code>align-self</code>属性允许单个项目有与其他项目不一样的对齐方式,可覆盖<code>align-items</code>属性。默认值为<code>auto</code>,表示继承父元素的<code>align-items</code>属性,如果没有父元素,则等同于<code>stretch</code>。</p><h4 id="注意"><a href="#注意" class="headerlink" title="注意"></a>注意</h4><p>内部或容器position为fixed时会失效</p><h3 id="grid布局"><a href="#grid布局" class="headerlink" title="grid布局"></a>grid布局</h3><p>二维布局。container 和 item</p><h4 id="container属性:"><a href="#container属性:" class="headerlink" title="container属性:"></a>container属性:</h4><ul><li>display:我们通过在元素上声明 <code>display:grid</code> 或 <code>display:inline-grid</code> 来创建一个网格容器。声明 <code>display:grid</code> 则该容器是一个块级元素,设置成 <code>display: inline-grid</code> 则容器元素为行内元素</li><li></li></ul><h4 id="item属性:"><a href="#item属性:" class="headerlink" title="item属性:"></a>item属性:</h4><h3 id="定位position"><a href="#定位position" class="headerlink" title="定位position"></a>定位position</h3><ul><li>static静态定位,默认属性</li><li>relative相对定位,相对于为static父标签的偏移,同时需要指定偏移方向和位移</li><li>absolute绝对定位,相对于不为static父标签的偏移</li><li>fixed固定定位,相对于浏览器窗口的偏移,不随父标签的属性改变而改变</li><li>sticky粘性定位,未滚动到预定位置就是relative,到预定位置就是fixed,实现比如固定在页面顶部的导航栏</li></ul><p>页面的普通流,static 和 relative 都不会更改元素的正常文档流,block 元素还是width 为100%,inline 元素还是宽高无效</p><pre class="language-css" data-language="css"><code class="language-css"><span class="token comment">/*relative示例*/</span><span class="token selector">span</span> <span class="token punctuation">{</span> <span class="token property">background</span><span class="token punctuation">:</span> #b6ff00<span class="token punctuation">;</span> <span class="token property">position</span><span class="token punctuation">:</span> relative<span class="token punctuation">;</span> <span class="token property">top</span><span class="token punctuation">:</span> 10px<span class="token punctuation">;</span> <span class="token property">left</span><span class="token punctuation">:</span> 10px<span class="token punctuation">;</span> <span class="token property">width</span><span class="token punctuation">:</span> 100px<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre><h3 id="浮动float"><a href="#浮动float" class="headerlink" title="浮动float"></a>浮动float</h3><p>float 属性定义元素在哪个方向浮动,常用属性值有 left、right,即向左浮动和向右浮动。设置了 float 的元素,会脱离文档流,然后向左或向右移动,直到碰到父容器的边界或者碰到另一个浮动元素。块级元素会忽略 float 元素,文本和行内元素却会环绕</p><p>会影响自身及后面的元素,不推荐使用有相对应的clear属性,清除浮动,也能影响自身及后面的元素</p><ul><li>left</li><li>right</li></ul><h3 id="transition"><a href="#transition" class="headerlink" title="transition"></a>transition</h3><p>CSS transitions 可以决定哪些属性发生动画效果 (明确地列出这些属性),何时开始 (设置 delay),持续多久 (设置 duration) 以及如何动画 (定义<em>timing function</em>,比如匀速地或先快后慢)。</p><p> <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/transition-property"><code>transition-property</code></a>、<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/transition-duration"><code>transition-duration</code></a>、<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/transition-timing-function"><code>transition-timing-function</code></a> 和 <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/transition-delay"><code>transition-delay</code></a> 的一个<a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Shorthand_properties">简写属性</a>,</p><p><img src="/2022/11/02/Frontend/image-20230309194850683.png" alt="image-20230309194850683"></p><p><code>transition</code>属性可以被指定为一个或多个 CSS 属性的过渡效果,多个属性之间用逗号进行分隔。</p><pre class="language-css" data-language="css"><code class="language-css"><span class="token comment">/* Apply to 1 property */</span><span class="token comment">/* property name | duration */</span><span class="token property">transition</span><span class="token punctuation">:</span> margin-right 4s<span class="token punctuation">;</span><span class="token comment">/* property name | duration | delay */</span><span class="token property">transition</span><span class="token punctuation">:</span> margin-right 4s 1s<span class="token punctuation">;</span><span class="token comment">/* property name | duration | timing function */</span><span class="token property">transition</span><span class="token punctuation">:</span> margin-right 4s ease-in-out<span class="token punctuation">;</span><span class="token comment">/* property name | duration | timing function | delay */</span><span class="token property">transition</span><span class="token punctuation">:</span> margin-right 4s ease-in-out 1s<span class="token punctuation">;</span><span class="token comment">/* Apply to 2 properties */</span><span class="token property">transition</span><span class="token punctuation">:</span> margin-right 4s<span class="token punctuation">,</span> color 1s<span class="token punctuation">;</span><span class="token comment">/* Apply to all changed properties */</span><span class="token property">transition</span><span class="token punctuation">:</span> all 0.5s ease-out<span class="token punctuation">;</span><span class="token comment">/* Global values */</span><span class="token property">transition</span><span class="token punctuation">:</span> inherit<span class="token punctuation">;</span><span class="token property">transition</span><span class="token punctuation">:</span> initial<span class="token punctuation">;</span></code></pre><p>注意,以下情况下transition会失效:</p><p>1.display改变,none时不在文档流中,也就没有过渡效果</p><p>2.设定的元素没有设置初始值(准确的说是初始值为auto),比如left不显示设置为0时初始值为auto,transition值无效</p><p>3.css文件中的transition和js代码中对元素transition的编辑冲突</p><p>...</p><h3 id="transform"><a href="#transform" class="headerlink" title="transform"></a>transform</h3><p><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/transform">https://developer.mozilla.org/zh-CN/docs/Web/CSS/transform</a></p><p><img src="/2022/11/02/Frontend/e4ce35e5361842c987322cf9d0e60ed3.png" alt="在这里插入图片描述"></p><p>x轴:水平向右(x 右边是正值,左边是负值)<br>y轴:垂直向下(y 下面是正值,上面是负值)<br>z轴:垂直屏幕(往外面是正值,往里面是负值)</p><p>旋转,缩放,倾斜或平移给定元素,是通过修改 CSS 视觉格式化模型的坐标空间来实现的。</p><p><img src="/2022/11/02/Frontend/image-20230306200340324.png" alt="image-20230306200340324"></p><p>translate(移动)</p><pre class="language-none"><code class="language-none">transform: translateX(length); /* 仅仅在x轴移动 */transform: translateY(length); /* 仅仅在y轴移动 */transform: translateZ(length); /* 仅仅在z轴移动 单位一般用像素(px)如果是正值,则向我们眼前移动,负值,则向后移动 */transform: translate(x,y); /* 沿着x,y轴同时移动(参数中间用逗号隔开) */transform: translate3d(x,y,z); /* 其中x,y,z分别指向要移动的轴的方向的距离 xyz三个参数不能省略,没有就写0 */</code></pre><p>translate类似定位,不会影响到其他元素的位置<br>对行内标签没有效果<br>translate中的百分比单位是相对于自身元素的width和height的百分比</p><p>rotate(旋转)</p><pre class="language-none"><code class="language-none">transform: rotateX(45deg); /* 沿着x轴正方向旋转45度 左手拇指指着x轴的正方向(右),手指弯曲的方向就是沿着x轴正方向旋转 */transform: rotateY(45deg); /*沿着y轴正方向旋转45度 左手拇指指着y轴的正方向(下),手指弯曲的方向就是沿着y轴正方向旋转 */transform: rotateZ(45deg); /* 沿着z轴正方向旋转45度 */transform: rotate3d(x,y,z,deg); /* 沿着自定义的轴来旋转 沿着x轴缩放n倍 */</code></pre><p> scale(缩放)</p><pre class="language-none"><code class="language-none">transform:scaleX(n); /* 沿着x轴缩放n倍 */transform:scaleY(n); /* 沿着y轴缩放n倍 */transform:scale(n); /* 沿着x,y轴缩放n倍 */</code></pre><p>x,y为盒子宽高的倍数,xy之间用逗号隔开<br>1就是1倍也就是没有变化,小于1会缩小</p><p>scale(缩放)和普通缩放的区别?</p><p>scale(缩放):</p><p>不会影响其他盒子<br>可以设置缩放的中心点</p><p>普通缩放:</p><p>会影响其他盒子<br>盒子高度只能向下延伸</p><p>skew(倾斜)</p><pre class="language-none"><code class="language-none">transform: skewX(45deg); /* 沿着x轴倾斜45度 */transform: skewY(45deg); /* 沿着y轴倾斜45度 */transform: skew(45deg,45deg); /* 沿着xy轴的对角线倾斜45du */perspecstive(透视)</code></pre><p>perspecstive(透视)</p><p><img src="/2022/11/02/Frontend/2fb133b35ac541fabb2a7dd7dc3ac3f3.png" alt="在这里插入图片描述"></p><p>d:透视也叫视距,就是眼睛到屏幕的距离</p><ul><li><p>透视写在被观察元素的父盒子上面</p></li><li><p>单位一般是像素(px)</p></li></ul><p>z:就是z轴,物体距离屏幕的距离,z轴越大(正值),我们看到的物体就越大</p><p>3D呈现</p><pre class="language-none"><code class="language-none">transform-style: flat; /* 子盒子不开启立体空间 */transform-style: preserve-3d; /* 子盒子开启立体空间 */</code></pre><p>控制子盒子是否开始三维立体环境</p><p>代码写给父级,但影响的是子盒子</p><p>综合写法</p><pre class="language-none"><code class="language-none">transform: translate() rotate() scale() ...等 </code></pre><p>其顺序会影转换的效果。(先旋转会改变坐标轴方向,移动放在最前面)</p><h3 id="animation"><a href="#animation" class="headerlink" title="animation"></a>animation</h3><p>动画序列<br>动画是使元素从一种样式逐渐变化为另一种样式的效果。您可以改变任意多的样式任意多的次数。<br>请用百分比来规定变化发生的时间,或用关键词 “from” 和 “to”,等同于 0% 和 100%。<br>0% 是动画的开始,100% 是动画的完成。这样的规则就是动画序列。<br>在 @keyframes 中规定某项 CSS 样式,就能创建由当前样式逐渐改为新样式的动画效果。<br>综合写法<br>animation:动画名称 动画时间 运动曲线 何时开始 播放次数 是否反方向 动画等待或者结束的状态;<br>1<br>注意:综合写法不包括:animation-play-state。如果有多个动画,用逗号隔开</p><p><img src="/2022/11/02/Frontend/image-20230309194723164.png" alt="image-20230309194723164"></p><pre class="language-css" data-language="css"><code class="language-css"><span class="token comment">/*用keyframes 定义动画(类似定义类选择器)*/</span><span class="token atrule"><span class="token rule">@keyframes</span> 动画名称</span> <span class="token punctuation">{</span> <span class="token selector">0%</span><span class="token punctuation">{</span> <span class="token property">width</span><span class="token punctuation">:</span>100px<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">100%</span><span class="token punctuation">{</span> <span class="token property">width</span><span class="token punctuation">:</span>200px<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token comment">/*元素使用动画*/</span><span class="token selector">div</span> <span class="token punctuation">{</span> <span class="token property">width</span><span class="token punctuation">:</span> 200px<span class="token punctuation">;</span> <span class="token property">height</span><span class="token punctuation">:</span> 200px<span class="token punctuation">;</span> <span class="token property">background-color</span><span class="token punctuation">:</span> aqua<span class="token punctuation">;</span> <span class="token property">margin</span><span class="token punctuation">:</span> 100px auto<span class="token punctuation">;</span> <span class="token comment">/* 调用动画 */</span> <span class="token property">animation-name</span><span class="token punctuation">:</span> 动画名称<span class="token punctuation">;</span> <span class="token comment">/* 持续时间 */</span> <span class="token property">animation-duration</span><span class="token punctuation">:</span> 持续时间<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token property">animation</span><span class="token punctuation">:</span> myfirst 5s linear 2s infinite alternate<span class="token punctuation">;</span></code></pre><h3 id="无障碍-aria"><a href="#无障碍-aria" class="headerlink" title="无障碍-aria"></a>无障碍-aria</h3><p><a href="https://developer.mozilla.org/zh-CN/docs/Web/Accessibility/ARIA">https://developer.mozilla.org/zh-CN/docs/Web/Accessibility/ARIA</a></p><h3 id="规则"><a href="#规则" class="headerlink" title="@规则"></a>@规则</h3><p>一个 <strong>at-rule</strong> 是一个<a href="https://developer.mozilla.org/en/CSS/Syntax#CSS_statements">CSS 语句,</a>以 at 符号开头, '<code>@</code>' (<code>U+0040 COMMERCIAL AT</code>), 后跟一个标识符,并包括直到下一个分号的所有内容, '<code>;</code>' (<code>U+003B SEMICOLON</code>), 或下一个 CSS 块,以先到者为准。</p><ul><li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/@charset"><code>@charset</code></a>, 定义样式表使用的字符集。</li><li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/@import"><code>@import</code></a>, 告诉 CSS 引擎引入一个外部样式表。</li><li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/@namespace"><code>@namespace</code></a>, 告诉 CSS 引擎必须考虑 XML 命名空间。</li><li>嵌套 @规则,是嵌套语句的子集,不仅可以作为样式表里的一个语句,也可以用在条件规则组里:<ul><li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/@media"><code>@media</code></a>, 如果满足媒介查询的条件则条件规则组里的规则生效。</li><li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/@page"><code>@page</code></a>, 描述打印文档时布局的变化。</li><li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/@font-face"><code>@font-face</code></a>, 描述将下载的外部的字体。 Experimental</li><li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/@keyframes"><code>@keyframes</code></a>, 描述 CSS 动画的中间步骤 . Experimental</li><li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/@supports"><code>@supports</code></a>, 如果满足给定条件则条件规则组里的规则生效。 Experimental</li><li><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/@document"><code>@document</code></a>, 如果文档样式表满足给定条件则条件规则组里的规则生效。 <em>(推延至 CSS Level 4 规范)</em></li></ul></li></ul><p><strong>条件规则组</strong>. 这些语句使用相同的语法。它们都嵌套语句,或者是<em>规则</em>或者是*@规则*。它们都表达:它们所指的条件 (类型不同) 总等效于 <strong>true</strong> 或者 <strong>false</strong>,如果为 <strong>true</strong> 那么它们里面的语句生效。</p><h3 id="Scss"><a href="#Scss" class="headerlink" title="Scss"></a>Scss</h3><p>Sass3.0之后的进步版本,采用花括号分段而非缩进</p><p><a href="https://sass-lang.com/">Sass: Syntactically Awesome Style Sheets</a></p><p>css的超集</p><p>sass安装,常用命令</p><pre class="language-none"><code class="language-none">//更新sassgem update sass//查看sass版本sass -v//查看sass帮助sass -h</code></pre><h4 id="sass编译"><a href="#sass编译" class="headerlink" title="sass编译"></a>sass编译</h4><ul><li><p>命令行编译</p><p>单文件</p><pre class="language-none"><code class="language-none">sass <要编译的Sass文件路径>/style.scss:<要输出CSS文件路径>/style.css</code></pre><p>多文件</p><p>将项目中“sass”文件夹中所有“.scss”(“.sass”)文件编译成“.css”文件,并且将这些 CSS 文件都放在项目中“css”文件夹中</p><pre class="language-none"><code class="language-none">sass sass/:css/</code></pre></li><li><p>gui</p></li><li><p>自动化</p><p>watch</p><p>来看一个简单的示例,假设我本地有一个项目,我要把项目中“bootstrap.scss”编译出“bootstrap.css”文件,并且将编译出来的文件放在“css”文件夹中,我就可以在我的命令终端中执行:</p><pre class="language-none"><code class="language-none">sass --watch sass/bootstrap.scss:css/bootstrap.css</code></pre><p>一旦我的 bootstrap.scss 文件有任何修改,只要我重新保存了修改的文件,命令终端就能监测,并重新编译出文件</p></li></ul><h4 id="输出方式"><a href="#输出方式" class="headerlink" title="输出方式"></a>输出方式</h4><ol><li><p><strong>嵌套输出方式 nested</strong></p><pre class="language-none"><code class="language-none">//未编译样式.box { width: 300px; height: 400px; &-title { height: 30px; line-height: 30px; }}</code></pre><p>nested 编译排版格式</p><pre class="language-none"><code class="language-none">/*命令行内容,即加上参数--style nested*/sass style.scss:style.css --style nested/*编译过后样式*/.box { width: 300px; height: 400px; } .box-title { height: 30px; line-height: 30px; }</code></pre></li><li><p><strong>展开输出方式 expanded</strong> </p><pre class="language-none"><code class="language-none">/*命令行内容*/sass style.scss:style.css --style expanded/*编译过后样式*/.box { width: 300px; height: 400px;}.box-title { height: 30px; line-height: 30px;}</code></pre></li><li><p><strong>紧凑输出方式 compact</strong> </p><pre class="language-none"><code class="language-none">/*命令行内容*/sass style.scss:style.css --style compact/*编译过后样式*/.box { width: 300px; height: 400px; }.box-title { height: 30px; line-height: 30px; }</code></pre></li><li><p><strong>压缩输出方式 compressed</strong></p><pre class="language-none"><code class="language-none">/*命令行内容*/sass style.scss:style.css --style compressed/*编译过后样式*/.box{width:300px;height:400px}.box-title{height:30px;line-height:30px}</code></pre></li></ol><p>调试:直接在浏览器里修改scss源码即可,现在已自动提供sourcemap</p><h4 id="变量"><a href="#变量" class="headerlink" title="变量"></a>变量</h4><p>变量开头是$,普通变量、局部变量、全局变量</p><p>默认变量在变量后加 !default,在结尾分号之前。其他变量要产生覆盖时需要写在默认变量之前</p><pre class="language-none"><code class="language-none">$content:"softwhy.com";$content: "antzone" !default;#main { content: $content;}</code></pre><p> 编译成css代码如下:</p><pre class="language-none"><code class="language-none">#main { content: "softwhy.com"; }</code></pre><p>!default一个重要的作用就是,如果我们引入的他人scss文件中的变量有默认值的设置,那么我们就可以很灵活的来修改这些默认值,只要在这些导入文件之前引入就一个配置scss文件即可,而无需修改他人的scss文件,例如:</p><pre class="language-none"><code class="language-none">@import "config";@import "variables";@import "mixins";</code></pre><p> 只要将重新配置的变量值写入config.scss文件,即可实现修改variables.scss和mixins.scss中默认变量值。</p><p>在选择器、函数、混合宏...的外面定义的变量为全局变量,作用域概念</p><p>声明变量的准则:</p><ol><li>该值至少重复出现了两次;</li><li>该值至少可能会被更新一次;</li><li>该值所有的表现都与变量有关(非巧合)。</li></ol><h4 id="嵌套"><a href="#嵌套" class="headerlink" title="嵌套"></a>嵌套</h4><p>三种嵌套</p><ul><li><p>选择器嵌套</p><p>&的用法:</p><p>后面紧跟后缀字符时只能位于第一个字符,作为父选择器跟随后缀形成新的复合选择器</p><pre class="language-scss" data-language="scss"><code class="language-scss"><span class="token selector">#main </span><span class="token punctuation">{</span> <span class="token property">color</span><span class="token punctuation">:</span> black<span class="token punctuation">;</span> <span class="token selector"><span class="token parent important">&</span>-sidebar </span><span class="token punctuation">{</span> <span class="token property">border</span><span class="token punctuation">:</span> 1px solid<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><p>编译为</p><pre class="language-css" data-language="css"><code class="language-css"><span class="token selector">#main</span> <span class="token punctuation">{</span> <span class="token property">color</span><span class="token punctuation">:</span> black<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">#main-sidebar</span> <span class="token punctuation">{</span> <span class="token property">border</span><span class="token punctuation">:</span> 1px solid<span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre><p>放在选择器后(中间有空格),取父值(可多层累加)</p><pre class="language-scss" data-language="scss"><code class="language-scss"><span class="token selector">nav </span><span class="token punctuation">{</span> <span class="token selector">a </span><span class="token punctuation">{</span> <span class="token property">color</span><span class="token punctuation">:</span> red<span class="token punctuation">;</span> <span class="token selector">header <span class="token parent important">&</span> </span><span class="token punctuation">{</span> <span class="token property">color</span><span class="token punctuation">:</span>green<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre><p>编译为</p><pre class="language-css" data-language="css"><code class="language-css"><span class="token selector">nav a</span> <span class="token punctuation">{</span> <span class="token property">color</span><span class="token punctuation">:</span> red<span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token selector">header nav a</span> <span class="token punctuation">{</span> <span class="token property">color</span><span class="token punctuation">:</span> green<span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre></li><li><p>属性嵌套</p><pre class="language-scss" data-language="scss"><code class="language-scss"><span class="token selector">.box </span><span class="token punctuation">{</span> <span class="token selector">font: </span><span class="token punctuation">{</span> <span class="token property">size</span><span class="token punctuation">:</span> 12px<span class="token punctuation">;</span> <span class="token property">weight</span><span class="token punctuation">:</span> bold<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre><pre class="language-css" data-language="css"><code class="language-css"><span class="token selector">.box</span> <span class="token punctuation">{</span> <span class="token property">font-size</span><span class="token punctuation">:</span> 12px<span class="token punctuation">;</span> <span class="token property">font-weight</span><span class="token punctuation">:</span> bold<span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre></li><li><p>伪类嵌套</p><pre class="language-none"><code class="language-none">.box{ &:before { content:"伪元素嵌套"; }}</code></pre><p>编译为</p><pre class="language-none"><code class="language-none">.box:before{ content:"伪元素嵌套";}</code></pre></li></ul><h4 id="注释"><a href="#注释" class="headerlink" title="注释"></a>注释</h4><p>Sass 支持标准的 CSS 多行注释 <code>/* */</code>,以及单行注释 <code>//</code>,前者会 被完整输出到编译后的 CSS 文件中,而后者则不会</p><h4 id="mixin"><a href="#mixin" class="headerlink" title="mixin"></a>mixin</h4><p>类似函数,变量参数以 $ 开头,定义用@mixin前缀,调用用@include 前缀</p><pre class="language-scss" data-language="scss"><code class="language-scss"><style type=<span class="token string">'text/scss'</span>><span class="token keyword">@mixin</span> <span class="token function">border-radius</span><span class="token punctuation">(</span><span class="token variable">$radius</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token property">-webkit-border-radius</span><span class="token punctuation">:</span><span class="token variable">$radius</span><span class="token punctuation">;</span> <span class="token property">-moz-border-radius</span><span class="token punctuation">:</span><span class="token variable">$radius</span><span class="token punctuation">;</span> <span class="token property">-ms-border-radius</span><span class="token punctuation">:</span><span class="token variable">$radius</span><span class="token punctuation">;</span> <span class="token property">border-radius</span><span class="token punctuation">:</span><span class="token variable">$radius</span><span class="token punctuation">;</span><span class="token punctuation">}</span> <span class="token selector">#awesome </span><span class="token punctuation">{</span> <span class="token property">width</span><span class="token punctuation">:</span> 150px<span class="token punctuation">;</span> <span class="token property">height</span><span class="token punctuation">:</span> 150px<span class="token punctuation">;</span> <span class="token property">background-color</span><span class="token punctuation">:</span> green<span class="token punctuation">;</span> <span class="token keyword">@include</span> <span class="token function">border-radius</span><span class="token punctuation">(</span>15px<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></style><div id=<span class="token string">"awesome"</span>></div></code></pre><h3 id="Less"><a href="#Less" class="headerlink" title="Less"></a>Less</h3><h4 id="Variables"><a href="#Variables" class="headerlink" title="Variables"></a>Variables</h4><p>变量,@开头,在最外层定义</p><pre class="language-less" data-language="less"><code class="language-less"><span class="token variable">@width<span class="token punctuation">:</span></span> 10px<span class="token punctuation">;</span><span class="token variable">@height<span class="token punctuation">:</span></span> <span class="token variable">@width</span> <span class="token operator">+</span> 10px<span class="token punctuation">;</span><span class="token selector">#header</span> <span class="token punctuation">{</span> <span class="token property">width</span><span class="token punctuation">:</span> <span class="token variable">@width</span><span class="token punctuation">;</span> <span class="token property">height</span><span class="token punctuation">:</span> <span class="token variable">@height</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token comment">//编译为</span><span class="token selector">#header</span><span class="token punctuation">{</span> <span class="token property">width</span><span class="token punctuation">:</span>10px<span class="token punctuation">;</span> <span class="token property">height</span><span class="token punctuation">:</span>20px<span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><h4 id="Mixins"><a href="#Mixins" class="headerlink" title="Mixins"></a>Mixins</h4><p>混合</p><h4 id="Nesting"><a href="#Nesting" class="headerlink" title="Nesting"></a>Nesting</h4><p>嵌套</p><p><code>&</code> 表示当前选择器的父级</p><pre class="language-less" data-language="less"><code class="language-less"><span class="token selector">.clearfix</span> <span class="token punctuation">{</span> <span class="token property">display</span><span class="token punctuation">:</span> block<span class="token punctuation">;</span> <span class="token property">zoom</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span> <span class="token selector">&:after</span> <span class="token punctuation">{</span> <span class="token property">content</span><span class="token punctuation">:</span> <span class="token string">" "</span><span class="token punctuation">;</span> <span class="token property">display</span><span class="token punctuation">:</span> block<span class="token punctuation">;</span> <span class="token property">font-size</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span> <span class="token property">height</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span> <span class="token property">clear</span><span class="token punctuation">:</span> both<span class="token punctuation">;</span> <span class="token property">visibility</span><span class="token punctuation">:</span> hidden<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><h3 id="Stylus"><a href="#Stylus" class="headerlink" title="Stylus"></a>Stylus</h3><h2 id="DOM"><a href="#DOM" class="headerlink" title="DOM"></a>DOM</h2><p>document object model 文档对象模型,HTML的节点树</p><p>接口:Document,Window,Element,</p><p>基本操作分四类:增、删、查、改</p><p>查的方法:获取DOM节点</p><ul><li><p>js中执行document上的成员函数,传入 id、class、tagName等指定条件,获取DOM结点</p></li><li><p>通过css选择器查询DOM结点</p></li><li><p>通过已访问到的DOM节点对象访问其它相关的父子兄弟结点。</p></li><li><p><code>document.getElementById(id)</code></p></li><li><p><code>document.getElementsByTagName(name)</code>,参数是标签名,返回nodelist,类数组</p></li><li><p><a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Document/getElementsByClassName"><code>Document.getElementsByClassName()</code></a>,参数类名,返回nodelist</p></li><li><p><a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Document/querySelector"><code>document.querySelector()</code></a>,参数是css选择器语法,加引号,返回第一个符合选择器语法的element</p></li><li><p><a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Document/querySelectorAll"><code>document.querySelectorAll()</code></a>,参数同上,但返回nodelist</p></li></ul><p>增(例如定位element对象,为其增加子节点)、删(element.remove())、改(Element对象的方法)</p><h3 id="document属性"><a href="#document属性" class="headerlink" title="document属性"></a>document属性</h3><h4 id="documentelement和body"><a href="#documentelement和body" class="headerlink" title="documentelement和body"></a>documentelement和body</h4><h5 id="DTD"><a href="#DTD" class="headerlink" title="DTD"></a>DTD</h5><p>DTD告诉浏览器当前文档用的是什么标记语言,然后浏览器才能正确的根据W3C标准解析文档代码。</p><p>目前htmlDTD有三种类型:</p><ul><li><p>Strict DTD:严格的文档类型定义</p><p>不能包含已过时的元素(或属性)和框架元素。</p></li><li><p>Transitional DTD:过渡的文档类型定义</p><p>能包含已过时的元素和属性但不能包含框架元素。</p></li><li><p>Frameset DTD: 框架集文档类型定义</p><p>能包含已过时的元素和框架元素。</p></li></ul><p>在html文档中定义DTD就是通过!doctype定义,如下,是一个html4.0的过渡DTDhtml文档:</p><pre class="language-markup" data-language="markup"><code class="language-markup"><span class="token doctype"><span class="token punctuation"><!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span> <span class="token name">PUBLIC</span> <span class="token string">"-//W3C//DTD XHTML1.0 Transitional//EN"</span> <span class="token string">"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>html</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>title</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>title</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>html</span><span class="token punctuation">></span></span></code></pre><p>或在html5中:</p><pre class="language-markup" data-language="markup"><code class="language-markup"><span class="token doctype"><span class="token punctuation"><!</span><span class="token doctype-tag">doctype</span> <span class="token name">html</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>html</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>title</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>title</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>html</span><span class="token punctuation">></span></span></code></pre><h5 id="document-documentElement与document-body"><a href="#document-documentElement与document-body" class="headerlink" title="document.documentElement与document.body"></a>document.documentElement与document.body</h5><ul><li>document代表的是整个文档(对于一个网页来说包括整个网页结构),document.documentElement是整个文档节点树的根节点,在网页中即html标签;</li><li>document.body是整个文档DOM节点树里的body节点,网页中即为body标签元素。</li></ul><p>我们常看见如下这种写法获取页面滚动条滚过的长度:</p><pre class="language-dart" data-language="dart"><code class="language-dart"><span class="token keyword">var</span> top <span class="token operator">=</span> document<span class="token punctuation">.</span>documentElement<span class="token punctuation">.</span>scrollTop <span class="token operator">||</span> document<span class="token punctuation">.</span>body<span class="token punctuation">.</span>scrollTop<span class="token punctuation">;</span>或<span class="token keyword">var</span> top <span class="token operator">=</span> document<span class="token punctuation">.</span>documentElement<span class="token punctuation">.</span>scrollTop <span class="token operator">?</span> document<span class="token punctuation">.</span>documentElement<span class="token punctuation">.</span>scrollTop <span class="token punctuation">:</span> document<span class="token punctuation">.</span>body<span class="token punctuation">.</span>scrollTop<span class="token punctuation">;</span></code></pre><p>在文档使用了DTD时,document.body.scrollTop的值为0,此时需要使用document.documentElement.scrollTop来获取滚动条滚过的长度;在未使用DTD定义文档时,使用document.body.scrollTop获取值。</p><h4 id="scrollHeight"><a href="#scrollHeight" class="headerlink" title="scrollHeight"></a>scrollHeight</h4><p>scrollHeight 属性是一个只读属性,它返回该元素的像素高度,高度包含内边距(padding),不包含外边距(margin)、边框(border),是一个整数,单位是像素 px。</p><p>获取 div 元素的高度和宽度,包含内边距(padding):</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> elmnt <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">"content"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">var</span> y <span class="token operator">=</span> elmnt<span class="token punctuation">.</span>scrollHeight<span class="token punctuation">;</span> <span class="token keyword">var</span> x <span class="token operator">=</span> elmnt<span class="token punctuation">.</span>scrollWidth<span class="token punctuation">;</span></code></pre><h3 id="DOM事件"><a href="#DOM事件" class="headerlink" title="DOM事件"></a>DOM事件</h3><p>0级(其实并不存在这个标准),1级(映射文档结构,特定于HTML的对象和方法),2级(增加模块以支持新的接口:追踪文档不同视图的接口、事件及事件处理接口、处理元素css样式的接口、遍历和操作DOM树的接口),3级(增加了以统一的方式加载和保存文档的方法(包含在一个叫 DOM Load and Save 的新模块中),还有验证文档的方法(DOM Validation)),4级(替代 Mutation Events 的 Mutation Observers)</p><ul><li>事件发生,触发设定好的应对函数(事件监听函数),是js和HTML的交互基础,常用的有鼠标事件、触摸事件、键盘事件、媒体事件、剪切板事件、资源事件等</li><li>事件流,三个阶段:事件捕获Capture->目标事件Target->事件冒泡Bubbling onclick和addEventListener的区别,前者不支持一个事件绑定多个事件处理函数,后者支持</li></ul><p>addEventListener的第三个参数为指定事件是否在捕获或冒泡阶段执行,<u>设置为true表示事件在捕获阶段执行,而设置为false表示事件在冒泡阶段执行。</u>默认值为true</p><p>event属性</p><ul><li><code>event.target</code>指向<strong>引起触发事件的元素</strong>,而<code>event.currentTarget</code>则是<strong>事件绑定的元素</strong>。</li></ul><pre class="language-none"><code class="language-none">target.addEventListener(type, listener[, useCapture]);target.removeEventListener(type, listener[, useCapture]);/*方法中包含3个参数,分别是绑定的事件处理属性名称(不包含on)、事件处理函数、是否在捕获时执行事件处理函数*/</code></pre><p>event方法</p><ul><li><p>stopPropagation方法主要用于阻止事件的进一步传播,配合addeventlistener第三个参数可以实现在事件捕获阶段阻止事件向下传播或在事件冒泡阶段阻止事件向上传播</p></li><li><p>preventDefault方法用于取消事件的默认操作,比如a链接的跳转行为和表单自动提交行为就可以用preventDefault方法来取消。</p></li><li><p>和stopPropagation相比,stopImmediatePropagation同样可以阻止事件的传播,不同点在于其还可以把这个元素绑定的同类型事件也阻止了。</p></li></ul><h4 id="键盘事件"><a href="#键盘事件" class="headerlink" title="键盘事件"></a>键盘事件</h4><p>发生在可以聚焦的元素上或者全局,查阅tabindex</p><p>keypress(按下字符键时触发),keydown(按键时,可重复触发),keyup</p><h4 id="鼠标事件"><a href="#鼠标事件" class="headerlink" title="鼠标事件"></a>鼠标事件</h4><h4 id="滑动事件"><a href="#滑动事件" class="headerlink" title="滑动事件"></a>滑动事件</h4><h3 id="虚拟DOM"><a href="#虚拟DOM" class="headerlink" title="虚拟DOM"></a>虚拟DOM</h3><p>Virtual dom, 即虚拟DOM节点。它通过JS的Object对象模拟DOM中的节点,然后再通过特定的render方法将其渲染成真实的DOM节点。</p><p>包含了<code>tag</code>、<code>props</code>、<code>children</code>三个属性。分别代表当前元素的标签名称字符串,当前标签的属性对象,子元素对象数组,也就是说可以无限嵌套。</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript">render方法转换属性时要考虑多种情况。像value、style等属性需要做特殊处理<span class="token keyword">function</span> <span class="token function">createElement</span><span class="token punctuation">(</span><span class="token parameter">type<span class="token punctuation">,</span> props<span class="token punctuation">,</span> children</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Element</span><span class="token punctuation">(</span>type<span class="token punctuation">,</span> props<span class="token punctuation">,</span> children<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token keyword">class</span> <span class="token class-name">Element</span> <span class="token punctuation">{</span> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">type<span class="token punctuation">,</span> props<span class="token punctuation">,</span> children</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>type <span class="token operator">=</span> type<span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>props <span class="token operator">=</span> props<span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>children <span class="token operator">=</span> children<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token keyword">function</span> <span class="token function">render</span><span class="token punctuation">(</span><span class="token parameter">eleObj</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> el <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span>eleObj<span class="token punctuation">.</span>type<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 创建元素</span> <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">let</span> key <span class="token keyword">in</span> eleObj<span class="token punctuation">.</span>props<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 设置属性的方法</span> <span class="token function">setAttr</span><span class="token punctuation">(</span>el<span class="token punctuation">,</span> key<span class="token punctuation">,</span> eleObj<span class="token punctuation">.</span>props<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> eleObj<span class="token punctuation">.</span>children<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token parameter">child</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">// 判断子元素是否是Element类型,是则递归,不是则创建文本节点</span> child <span class="token operator">=</span> <span class="token punctuation">(</span>child <span class="token keyword">instanceof</span> <span class="token class-name">Element</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token function">render</span><span class="token punctuation">(</span>child<span class="token punctuation">)</span> <span class="token operator">:</span> document<span class="token punctuation">.</span><span class="token function">createTextNode</span><span class="token punctuation">(</span>child<span class="token punctuation">)</span><span class="token punctuation">;</span> el<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>child<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> el<span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token keyword">function</span> <span class="token function">setAttr</span><span class="token punctuation">(</span><span class="token parameter">node<span class="token punctuation">,</span> key<span class="token punctuation">,</span> value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">switch</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">case</span> <span class="token string">'value'</span><span class="token operator">:</span> <span class="token comment">// node是一个input或者textarea</span> <span class="token keyword">if</span><span class="token punctuation">(</span>node<span class="token punctuation">.</span>tagName<span class="token punctuation">.</span><span class="token function">toUpperCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">===</span> <span class="token string">'INPUT'</span> <span class="token operator">||</span> node<span class="token punctuation">.</span>tagName<span class="token punctuation">.</span><span class="token function">toUpperCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">===</span> <span class="token string">'TEXTAREA'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> node<span class="token punctuation">.</span>value <span class="token operator">=</span> value<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token comment">// 普通属性</span> node<span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> value<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token keyword">case</span> <span class="token string">'style'</span><span class="token operator">:</span> node<span class="token punctuation">.</span>style<span class="token punctuation">.</span>cssText <span class="token operator">=</span> value<span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token keyword">default</span><span class="token operator">:</span> node<span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> value<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token comment">//renderDom接受 el 真实DOM和target 渲染目标两个参数,负责将真实DOM添加到浏览器上</span><span class="token keyword">function</span> <span class="token function">renderDom</span><span class="token punctuation">(</span><span class="token parameter">el<span class="token punctuation">,</span> target</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> target<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>el<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><h3 id="DOM方法"><a href="#DOM方法" class="headerlink" title="DOM方法"></a>DOM方法</h3><p>getElementsByxxx和querySelector的选择</p><p>前者是动态选择,后者是静态选择</p><ul><li>得到的元素不是需要很麻烦的多次getElementBy..的话,尽量使用getElementBy..,因为他快些。</li><li>得到的元素需要很麻烦的多次getElementBy..组合才能得到的话使用querySelector,方便。</li><li>看实际情况,你决定方便优先还是性能优先,</li></ul><h3 id="DOM-Diff"><a href="#DOM-Diff" class="headerlink" title="DOM Diff"></a>DOM Diff</h3><p>通过<code>JS</code>层面的计算,返回一个patch对象,即补丁对象,再通过特定的操作解析<code>patch</code>对象,完成页面的重新渲染。</p><p>1.用JS对象模拟DOM(虚拟DOM)<br>2.把此虚拟DOM转成真实DOM并插入页面中(render)<br>3.如果有事件发生修改了虚拟DOM,比较两棵虚拟DOM树的差异,得到差异对象(diff)<br>4.把差异对象应用到真正的DOM树上(patch)</p><h2 id="BOM"><a href="#BOM" class="headerlink" title="BOM"></a>BOM</h2><p>Browser Object Model 浏览器对象模型,控制浏览器的行为的接口</p><p>window是浏览器对象模型</p><h3 id="window-history"><a href="#window-history" class="headerlink" title="window.history"></a>window.history</h3><p>详见<a href="https://developer.mozilla.org/zh-CN/docs/Web/API/History_API">https://developer.mozilla.org/zh-CN/docs/Web/API/History_API</a></p><p>History 对象主要有两个属性。</p><ul><li><code>History.length</code>:当前窗口访问过的网址数量(包括当前网页)</li><li><code>History.state</code>:History 堆栈最上层的状态值(详见下文)</li></ul><pre class="language-none"><code class="language-none">// 当前窗口访问过多少个网页window.history.length // 1// History 对象的当前状态// 通常是 undefined,即未设置window.history.state // undefined</code></pre><h4 id="方法"><a href="#方法" class="headerlink" title="方法"></a>方法</h4><p>History.back()、History.forward()、History.go()</p><h3 id="window-location"><a href="#window-location" class="headerlink" title="window.location"></a>window.location</h3><p>window.location 对象所包含的属性</p><table><thead><tr><th align="left">属性</th><th align="left">描述</th></tr></thead><tbody><tr><td align="left">hash</td><td align="left">从井号 (#) 开始的 URL(锚)</td></tr><tr><td align="left">host</td><td align="left">主机名和当前 URL 的端口号</td></tr><tr><td align="left">hostname</td><td align="left">当前 URL 的主机名</td></tr><tr><td align="left">href</td><td align="left">完整的 URL</td></tr><tr><td align="left">pathname</td><td align="left">当前 URL 的路径部分</td></tr><tr><td align="left">port</td><td align="left">当前 URL 的端口号</td></tr><tr><td align="left">protocol</td><td align="left">当前 URL 的协议</td></tr><tr><td align="left">search</td><td align="left">从问号 (?) 开始的 URL(查询部分)</td></tr></tbody></table><p><a href="https://developer.mozilla.org/en-US/docs/Web/API/Location/origin"><code>Location.origin</code> (en-US)</a> 只读</p><p>包含页面来源的域名的标准形式<a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String"><code>DOMString</code></a>。</p><h4 id="hash属性"><a href="#hash属性" class="headerlink" title="hash属性"></a>hash属性</h4><p><a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Location"><code>Location</code></a> 接口的 <strong><code>hash</code></strong> 属性返回一个 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String"><code>USVString</code></a>,其中会包含 URL 标识中的 <code>'#'</code> 和 后面 URL 片段标识符。这里 fragment 不会经过<a href="https://developer.mozilla.org/en-US/docs/Glossary/percent-encoding">百分比编码</a>(URL 编码)。如果 URL 中没有 fragment,该属性会包含一个空字符串,<code>""</code></p><p>通过监听 window 对象的 hashChange 事件实现简单的路由</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript">window<span class="token punctuation">.</span><span class="token function-variable function">onhashchange</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> hash <span class="token operator">=</span> window<span class="token punctuation">.</span>location<span class="token punctuation">.</span>hash <span class="token keyword">var</span> path <span class="token operator">=</span> hash<span class="token punctuation">.</span><span class="token function">substring</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token keyword">switch</span> <span class="token punctuation">(</span>path<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">case</span> <span class="token string">'/'</span><span class="token operator">:</span> <span class="token function">showHome</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">break</span> <span class="token keyword">case</span> <span class="token string">'/users'</span><span class="token operator">:</span> <span class="token function">showUsersList</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">break</span> <span class="token keyword">default</span><span class="token operator">:</span> <span class="token function">show404NotFound</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><h3 id="window-onload"><a href="#window-onload" class="headerlink" title="window.onload"></a>window.onload</h3><h4 id="什么是-window-onload"><a href="#什么是-window-onload" class="headerlink" title="什么是 window.onload"></a>什么是 window.onload</h4><p>window.onload()方法用于在页面加载完毕后立刻执行的操作,即当HTML文档加载完毕后,立刻执行的某个方法。</p><p><strong>window.onload()</strong> 通常用于 元素,在页面完全载入后(包括图片、css文件等等)执行window.onload()里面的函数。</p><ol><li><p>只有一个要执行的函数:</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript">window<span class="token punctuation">.</span>onload <span class="token operator">=</span> funcRef<span class="token punctuation">;</span></code></pre></li></ol><ul><li>funcRef:函数类型的对象引用或者匿名函数</li></ul><p>在页面加载完成后,调用funcRef方法</p><ol start="2"><li><p>有多个要执行的函数:</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript">window<span class="token punctuation">.</span><span class="token function-variable function">onload</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token function">Func1</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">Func2</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">Func3</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token operator">...</span><span class="token operator">...</span><span class="token punctuation">}</span></code></pre></li></ol><p>在页面加载完成后依次执行 Func1、Func2、Func3</p><h4 id="使用window-onload-的好处"><a href="#使用window-onload-的好处" class="headerlink" title="使用window.onload()的好处"></a>使用window.onload()的好处</h4><p>JavaScript 中的函数方法需要在 HTML 文档渲染完成后才可以使用,如果没有渲染完成,此时的 DOM 树是不完整的,这样在调用一些 JavaScript 代码时就可能报出"undefined"错误。</p><h3 id="window-onscroll"><a href="#window-onscroll" class="headerlink" title="window.onscroll"></a>window.onscroll</h3><p>滚动当前页面的时候,添加事件处理函数。</p><p>语法:</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript">window<span class="token punctuation">.</span>onscroll <span class="token operator">=</span> funcRef<span class="token punctuation">;</span></code></pre><ul><li>funcRef是个函数类型的对象引用或者匿名函数.</li></ul><h3 id="resize事件"><a href="#resize事件" class="headerlink" title="resize事件"></a>resize事件</h3><p>当窗口(浏览器)的尺寸大小发生改变时。当用户改变浏览器的大小,或者在不同的屏幕尺寸上加载页面时,resize事件将被触发。在JavaScript中,我们可以使用window.addEventListener('resize', function)来监听resize事件,并执行我们定义的回调函数。</p><p>echarts需要resize</p><h3 id="chrome"><a href="#chrome" class="headerlink" title="chrome"></a>chrome</h3><p>开发者工具下右键刷新有三种刷新模式:</p><ul><li><strong>Normal Reload</strong> (Ctrl + R): 正常刷新,使用缓存数据。等效于 f5</li><li><strong>Hard Reload</strong> (Ctrl + Shift + R):强制浏览器重新下载并加载内容。资源有可能来自于缓存的版本。等效于 ctrl + f5</li><li><strong>Empty Cache and Hard Reload</strong>:完全清除页面的缓存并重新下载所有内容。</li></ul><p><strong>Normal Reload</strong>时浏览器会避免重新下载已缓存的资源,例如JavaScript文件。</p><p><strong>Hard Reload</strong>情况下,浏览器不会使用缓存中的任何内容,所有的内容会被重新下载。这和按Ctrl + F5的效果是一样的。但是如果页面通过重定向加载额外的资源,则有可能会从缓存加载数据。</p><p>选择<strong>Empty Cache and Hard Reload</strong>时,浏览器将首先清空缓存,然后重新下载所有资源。如果网页是通过JavaScript代码动态加载的,使用这种方式将非常有效。</p>]]></content>
<summary type="html"><blockquote>
<p>持续更新</p>
</blockquote>
<h3 id=""><a href="#" class="headerlink" title=""></a></h3><p>“网页大事,为我所控,天下页面,听我号令”——张鑫旭</p>
<h2 id="</summary>
<category term="Frontend" scheme="https://hhumar.com/categories/Frontend/"/>
<category term="Web" scheme="https://hhumar.com/tags/Web/"/>
</entry>
<entry>
<title>Python</title>
<link href="https://hhumar.com/2022/10/31/Python/"/>
<id>https://hhumar.com/2022/10/31/Python/</id>
<published>2022-10-31T01:57:20.000Z</published>
<updated>2023-02-03T15:17:19.600Z</updated>
<content type="html"><![CDATA[<blockquote><p>持续更新</p></blockquote><h3 id=""><a href="#" class="headerlink" title=""></a></h3><h2 id="基础"><a href="#基础" class="headerlink" title="基础"></a>基础</h2><h3 id="变量相关"><a href="#变量相关" class="headerlink" title="变量相关"></a>变量相关</h3><ul><li><p>Numbers(数字)</p><ul><li>int(有符号整型) <em>Python3.X 版本中 long 类型被移除,使用 int 替代。</em></li><li>float(浮点型)<ul><li>float(‘inf’) 表示正无穷 -float(‘inf’) 或 float(‘-inf’) 表示负无穷 其中,inf 均可以写成 Inf</li></ul></li><li>complex(复数)复数由实数部分和虚数部分构成,可以用 a + bj,或者 complex(a,b) 表示, 复数的实部 a 和虚部 b 都是浮点型。</li></ul></li><li><p>String(字符串)</p><ul><li><p>u/U:表示unicode字符串<br>不是仅仅是针对中文, 可以针对任何的字符串,代表是对字符串进行unicode编码。<br>一般英文字符在使用各种编码下, 基本都可以正常解析, 所以一般不带u;但是中文, 必须表明所需编码, 否则一旦编码转换就会出现乱码。<br>建议所有编码方式采用utf-8,即在py文件开头添加: # coding: utf-8</p></li><li><p>r/R:非转义的原始字符串<br>与普通字符相比,其他相对特殊的字符,其中可能包含转义字符,即那些,反斜杠加上对应字母,表示对应的特殊含义的,比如最常见的”\n”表示换行,”\t”表示Tab等。而如果是以r开头,那么说明后面的字符,都是普通的字符了,即如果是“\n”那么表示一个反斜杠字符,一个字母n,而不是表示换行了。<br>以r开头的字符,常用于正则表达式,对应着re模块。</p></li><li><p>F-strings python3.6开始支持,类似js的模板字符串</p><pre class="language-python" data-language="python"><code class="language-python">str_p <span class="token operator">=</span> <span class="token string-interpolation"><span class="token string">f'顺子是</span><span class="token interpolation"><span class="token punctuation">{</span>add_string<span class="token punctuation">(</span><span class="token builtin">str</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token string">'</span></span></code></pre></li></ul></li><li><p>List(列表)</p></li><li><p>Tuple(元组)</p></li><li><p>Dictionary(字典),类似js的map和object结合,键值可以为字符串也可以为number</p></li></ul><p>None 是 NoneType 数据类型的唯一值</p><p>python中除号用/表示,但是和C语言不同的是/得到的值总是<a href="https://so.csdn.net/so/search?q=%E6%B5%AE%E7%82%B9&spm=1001.2101.3001.7020">浮点</a>数,// 两数相除,向下取整</p><p>未声明为非局部变量的变量是只读的,(写入只读变量会在最内层作用域中创建一个 <strong>新的</strong> 局部变量,而同名的外部变量保持不变。)</p><p>空字符串、空列表、空元组、空字典、空集合均为false</p><h3 id="内置类型"><a href="#内置类型" class="headerlink" title="内置类型"></a>内置类型</h3><p><a href="https://docs.python.org/zh-cn/3/library/stdtypes.html?highlight=maketrans#text-sequence-type-str">https://docs.python.org/zh-cn/3/library/stdtypes.html?highlight=maketrans#text-sequence-type-str</a></p><p>数字类型 — <a href="https://docs.python.org/zh-cn/3/library/functions.html#int"><code>int</code></a>, <a href="https://docs.python.org/zh-cn/3/library/functions.html#float"><code>float</code></a>, <a href="https://docs.python.org/zh-cn/3/library/functions.html#complex"><code>complex</code></a></p><p>迭代器类型 — 生成器generator</p><p>序列类型 — <a href="https://docs.python.org/zh-cn/3/library/stdtypes.html?highlight=maketrans#list"><code>list</code></a>, <a href="https://docs.python.org/zh-cn/3/library/stdtypes.html?highlight=maketrans#tuple"><code>tuple</code></a>, <a href="https://docs.python.org/zh-cn/3/library/stdtypes.html?highlight=maketrans#range"><code>range</code></a><a href="https://docs.python.org/zh-cn/3/library/stdtypes.html?highlight=maketrans#sequence-types-list-tuple-range">¶</a></p><p>文本序列类型 — <a href="https://docs.python.org/zh-cn/3/library/stdtypes.html?highlight=maketrans#str"><code>str</code></a><a href="https://docs.python.org/zh-cn/3/library/stdtypes.html?highlight=maketrans#text-sequence-type-str">¶</a></p><p>二进制序列</p><p>集合类型 — set,frozenset</p><p>映射类型 — dict</p><p>…</p><h3 id="常用函数"><a href="#常用函数" class="headerlink" title="常用函数"></a>常用函数</h3><p>list() 可以直接把字符串转为字符数组,split方法则不行</p><p>chr()函数取整数值作为Unicode码转换为字符,ord() 获取单个字符输出 Unicode 码</p><h3 id="操作符"><a href="#操作符" class="headerlink" title="操作符"></a>操作符</h3><table><thead><tr><th></th><th></th></tr></thead><tbody><tr><td>in / not in</td><td>成员运算符</td></tr><tr><td>is / not is</td><td>身份运算符</td></tr></tbody></table><h3 id="基础语句"><a href="#基础语句" class="headerlink" title="基础语句"></a>基础语句</h3><ul><li><p>yield语句:与 return 的差别在于会保留执行状态,下次调用会从上次执行点继续执行</p></li><li><p><code>if</code> 、<code>elif</code> 、<code>else</code>条件控制语句</p><p>支持a<x<b这种连比</p></li><li><p>循环语句:</p><ul><li><p>while……else</p></li><li><p>for循环,start默认为0,step默认为1,<stop,不会等于stop</p><pre class="language-none"><code class="language-none">for i in range(satrt, stop, step): 业务逻辑</code></pre></li></ul><p><code>pass 语句</code> 是 Python 中的空语句,程序执行到此语句直接跳过,不会做任何的操作,仅作占位语句,但它在保持程序结构的完整性方面,有一定价值。</p><ul><li><p>列表推导式效率远高于for循环语句</p><p>out_list = [表达式 for 变量 in 列表 条件判断语句等]</p><pre class="language-none"><code class="language-none">>>> out_list = [i**2 for i in range(10) if i % 2 ==0]>>> out_list[0, 4, 16, 36, 64]</code></pre></li></ul></li><li><p>match…case</p><ul><li>变量名 <code>_</code> 作为 通配符 并确保目标将总是被匹配,是可选的,如果没有又之前 case 未得到匹配,则会执行一个空操作(no-op)</li></ul></li><li><p>try…except…as… 捕获异常</p><pre class="language-none"><code class="language-none">try: a=1+"b"except Exception as e: print(e)</code></pre></li><li><p>lambda函数</p><pre class="language-none"><code class="language-none">lambda arg1,arg2,arg3… :<表达式>lambda x, y: x*y;函数输入是x和y,输出是它们的积x*ylambda:None;函数没有输入参数,输出是Nonelambda *args: sum(args); 输入是任意个数的参数,输出是它们的和(隐性要求是输入参数必须能够进行加法运算)lambda **kwargs: 1;输入是任意键值对参数,输出是1</code></pre></li></ul><h3 id="数据值传递和引用"><a href="#数据值传递和引用" class="headerlink" title="数据值传递和引用"></a>数据值传递和引用</h3><p>字符串,数值,元组均为静态变量,列表,字典为动态变量。一般静态变量值传递为拷贝,动态变量值传递为引用。利用 id() 可以查看变量存储地址。</p><p>注:对静态变量首次传递时也是引用,当需要修改静态变量时,因为静态变量不能改变,所以需要生成一个新的空间存储数据。</p><p>所以更准确地说,python中只有引用传递,只不过静态类型不可改变,要改变对应名称的值只能改变其指向的内存地址。</p><p><strong>is比较的是两个对象的内存地址是否相等,==比较的是两个对象的值是否相等</strong>。</p><pre class="language-python" data-language="python"><code class="language-python">a <span class="token operator">=</span> <span class="token number">1</span>b <span class="token operator">=</span> <span class="token number">1</span>a <span class="token operator">==</span> b <span class="token comment"># True</span>a <span class="token keyword">is</span> b <span class="token comment"># True</span>a <span class="token operator">=</span> <span class="token number">888</span>b <span class="token operator">=</span> <span class="token number">888</span>a <span class="token operator">==</span> b <span class="token comment"># True</span>a <span class="token keyword">is</span> b <span class="token comment"># False</span>a <span class="token operator">=</span> <span class="token string">'hello'</span>b <span class="token operator">=</span> <span class="token string">'hello'</span>a <span class="token keyword">is</span> b <span class="token comment"># True</span>a <span class="token operator">==</span> b <span class="token comment"># True</span>a <span class="token operator">=</span> <span class="token string">'hello world'</span>b <span class="token operator">=</span> <span class="token string">'hello world'</span>a <span class="token operator">==</span> b <span class="token comment"># True</span>a <span class="token keyword">is</span> b <span class="token comment"># False</span></code></pre><p>部分代表小整数的对象都会指向小整数池,类似的,Python解释器中使用了 intern(字符串驻留),使值同样的字符串对象仅仅会保存一份,放在一个字符串储蓄池中,是共用的,如果字符串中有空格,默认不启用intern机制。对字符串储蓄池中的字符串使用 is 和 == 比较会得到相同的结果。</p><p><strong>在shell中,仅有以下划线、数字、字母组成的字符串会被intern。而pycharm中只要是同一个字符串不超过20个字符都被加入到池中</strong></p><p>需要严格根据解释环境判断,在IDLE中id都一样。</p><p>垃圾回收:引用计数,当某个对象在其作用域内不再被其他对象引用的时候,Python 就自动清除对象;</p><p>注意深浅拷贝:</p><ul><li>a.append(tmp)a.append(tmp[:])</li></ul><h3 id="切片"><a href="#切片" class="headerlink" title="切片"></a>切片</h3><p>切片使用2个冒号分隔的3个数字来完成:</p><ul><li>第一个数字表示切片的开始位置,默认为0</li><li>第二个数字表是切片的截止(但不包含)位置(默认为列表长度)</li><li>第三个数字表示切片的步长(默认为1),当步长省略时,顺便可以省略最后一个冒号。</li></ul><p><code>a[:]</code>是深复制,<code>a</code>是浅复制,相当于赋值<code>a</code>的话是赋值了指针,赋值<code>a[:]</code>相当于复制了<code>a</code>对应的那段空间</p><h3 id="解包"><a href="#解包" class="headerlink" title="解包"></a>解包</h3><p>解包赋值,是zip函数的逆操作。</p><h2 id="基础数据结构类型"><a href="#基础数据结构类型" class="headerlink" title="基础数据结构类型"></a>基础数据结构类型</h2><h3 id="效率"><a href="#效率" class="headerlink" title="效率"></a>效率</h3><p>list查询是O(n), set是O(1)</p><p>增删list到最后一个(append, pop)是O(1), 其他的为O(n), set的增删是O(1)</p><p>详见<a href="https://wiki.python.org/moin/TimeComplexity">https://wiki.python.org/moin/TimeComplexity</a></p><h3 id="list"><a href="#list" class="headerlink" title="list"></a>list</h3><p>中括号<code>[]</code>创建一个列表,列表内可含有各种不同类型,包括再嵌套列表。</p><h4 id="方法"><a href="#方法" class="headerlink" title="方法"></a>方法</h4><ul><li><code>append</code>一次添加1个元素,<code>insert</code>在指定位置添加元素</li></ul><pre class="language-python" data-language="python"><code class="language-python">a<span class="token punctuation">.</span>insert<span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">)</span> <span class="token comment"># insert 在索引2处添加元素5</span></code></pre><ul><li><p><code>remove</code>直接删除元素,若被删除元素在列表内重复出现多次,则只删除第一次</p></li><li><p><code>pop</code>方法若不带参数默认删除列表最后一个元素;若带参数则删除此参数代表的索引处的元素</p></li><li><p>remove方法</p><p>移除列表第一个匹配项</p></li></ul><pre class="language-python" data-language="python"><code class="language-python"><span class="token comment">#移除list1中第一个值为1的项</span>list1<span class="token punctuation">.</span>remove<span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span></code></pre><ul><li><p>extend方法</p><p>list.extend(L)</p><p>通过将所有元素追加到已知list来扩充它,相当于a[len(a):]= L</p></li></ul><p>列表封装的其他方法还包括如下:</p><pre class="language-none"><code class="language-none">`clear`,`index`,`count`,`sort`,`reverse`,`copy</code></pre><h3 id="tuple"><a href="#tuple" class="headerlink" title="tuple"></a>tuple</h3><p>元组是一类不允许添加删除元素的特殊列表,也就是一旦创建后续决不允许增加、删除、修改。</p><p><code>()</code>创建元组。</p><h3 id="set"><a href="#set" class="headerlink" title="set"></a>set</h3><p>基本用法 set是一种里面不能含有重复元素的数据结构,这种特性天然的使用于列表的去重。</p><h4 id="创建set"><a href="#创建set" class="headerlink" title="创建set"></a>创建set</h4><p><strong>此为python2语法</strong></p><pre class="language-idl" data-language="idl"><code class="language-idl">>>>x = set('runoob')>>> y = set('google')>>> x, y(set(['b', 'r', 'u', 'o', 'n']), set(['e', 'o', 'g', 'l'])) # 重复的被删除>>> x = set('eleven')>>> y = set('twelve')>>> x,y({'l', 'e', 'n', 'v'}, {'e', 'v', 'l', 't', 'w'})>>> x & y #交集{'l', 'e', 'v'}>>> x | y #并集{'e', 'v', 'n', 'l', 't', 'w'}>>> x - y #差集{'n'}>>> y -x #差集{'t', 'w'}>>> x ^ y #补集{'t', 'n', 'w'}>>> y ^ x #补集{'w', 'n', 't'}</code></pre><p>python3中,除了可以使用 <a href="https://docs.python.org/zh-cn/3.9/library/stdtypes.html?highlight=set#set"><code>set</code></a> 构造器,非空的 set (不是 frozenset) 还可以通过将以逗号分隔的元素列表包含于花括号之内来创建,例如: <code>{'jack', 'sjoerd'}</code>。</p><h4 id="方法-1"><a href="#方法-1" class="headerlink" title="方法"></a>方法</h4><p>摘自菜鸟教程,可能过时,建议查看python doc</p><table><thead><tr><th>方法名</th><th>语法格式</th><th>功能</th><th>实例</th></tr></thead><tbody><tr><td>add()</td><td>set1.add()</td><td>向 set1 集合中添加数字、字符串、元组或者布尔类型</td><td>>>> set1 = {1,2,3} >>> set1.add((1,2)) >>> set1 {(1, 2), 1, 2, 3}</td></tr><tr><td>clear()</td><td>set1.clear()</td><td>清空 set1 集合中所有元素</td><td>>>> set1 = {1,2,3} >>> set1.clear() >>> set1 set() set()才表示空集合,{}表示的是空字典</td></tr><tr><td>copy()</td><td>set2 = set1.copy()</td><td>拷贝 set1 集合给 set2</td><td>>>> set1 = {1,2,3} >>> set2 = set1.copy() >>> set1.add(4) >>> set1 {1, 2, 3, 4} >>> set1 {1, 2, 3}</td></tr><tr><td>difference()</td><td>set3 = set1.difference(set2)</td><td>将 set1 中有而 set2 没有的元素给 set3</td><td>>>> set1 = {1,2,3} >>> set2 = {3,4} >>> set3 = set1.difference(set2) >>> set3 {1, 2}</td></tr><tr><td>difference_update()</td><td>set1.difference_update(set2)</td><td>从 set1 中删除与 set2 相同的元素</td><td>>>> set1 = {1,2,3} >>> set2 = {3,4} >>> set1.difference_update(set2) >>> set1 {1, 2}</td></tr><tr><td>discard()</td><td>set1.discard(elem)</td><td>删除 set1 中的 elem 元素</td><td>>>> set1 = {1,2,3} >>> set1.discard(2) >>> set1 {1, 3} >>> set1.discard(4) {1, 3}</td></tr><tr><td>intersection()</td><td>set3 = set1.intersection(set2)</td><td>取 set1 和 set2 的交集给 set3</td><td>>>> set1 = {1,2,3} >>> set2 = {3,4} >>> set3 = set1.intersection(set2) >>> set3 {3}</td></tr><tr><td>intersection_update()</td><td>set1.intersection_update(set2)</td><td>取 set1和 set2 的交集,并更新给 set1</td><td>>>> set1 = {1,2,3} >>> set2 = {3,4} >>> set1.intersection_update(set2) >>> set1 {3}</td></tr><tr><td>isdisjoint()</td><td>set1.isdisjoint(set2)</td><td>判断 set1 和 set2 是否没有交集,有交集返回 False;没有交集返回 True</td><td>>>> set1 = {1,2,3} >>> set2 = {3,4} >>> set1.isdisjoint(set2) False</td></tr><tr><td>issubset()</td><td>set1.issubset(set2)</td><td>判断 set1 是否是 set2 的子集</td><td>>>> set1 = {1,2,3} >>> set2 = {1,2} >>> set1.issubset(set2) False</td></tr><tr><td>issuperset()</td><td>set1.issuperset(set2)</td><td>判断 set2 是否是 set1 的子集</td><td>>>> set1 = {1,2,3} >>> set2 = {1,2} >>> set1.issuperset(set2) True</td></tr><tr><td>pop()</td><td>a = set1.pop()</td><td>取 set1 中一个元素,并赋值给 a</td><td>>>> set1 = {1,2,3} >>> a = set1.pop() >>> set1 {2,3} >>> a 1</td></tr><tr><td>remove()</td><td>set1.remove(elem)</td><td>移除 set1 中的 elem 元素</td><td>>>> set1 = {1,2,3} >>> set1.remove(2) >>> set1 {1, 3} >>> set1.remove(4) Traceback (most recent call last): File “<pyshell#90>”, line 1, in <module> set1.remove(4) KeyError: 4</td></tr><tr><td>symmetric_difference()</td><td>set3 = set1.symmetric_difference(set2)</td><td>取 set1 和 set2 中互不相同的元素,给 set3</td><td>>>> set1 = {1,2,3} >>> set2 = {3,4} >>> set3 = set1.symmetric_difference(set2) >>> set3 {1, 2, 4}</td></tr><tr><td>symmetric_difference_update()</td><td>set1.symmetric_difference_update(set2)</td><td>取 set1 和 set2 中互不相同的元素,并更新给 set1</td><td>>>> set1 = {1,2,3} >>> set2 = {3,4} >>> set1.symmetric_difference_update(set2) >>> set1 {1, 2, 4}</td></tr><tr><td>union()</td><td>set3 = set1.union(set2)</td><td>取 set1 和 set2 的并集,赋给 set3</td><td>>>> set1 = {1,2,3} >>> set2 = {3,4} >>> set3=set1.union(set2) >>> set3 {1, 2, 3, 4}</td></tr><tr><td>update()</td><td>set1.update(elem)</td><td>添加列表或集合中的元素到 set1</td><td>>>> set1 = {1,2,3} >>> set1.update([3,4]) >>> set1 {1,2,3,4}</td></tr></tbody></table><h3 id="dict"><a href="#dict" class="headerlink" title="dict"></a>dict</h3><p>键值可以为数字、字符串甚至是元祖</p><p>字典可用多种方式来创建:</p><ul><li>使用花括号内以逗号分隔 <code>键: 值</code> 对的方式: <code>{'jack': 4098, 'sjoerd': 4127}</code> or <code>{4098: 'jack', 4127: 'sjoerd'}</code></li><li>使用字典推导式: <code>{}</code>, <code>{x: x ** 2 for x in range(10)}</code></li><li>使用类型构造器: <code>dict()</code>, <code>dict([('foo', 100), ('bar', 200)])</code>, <code>dict(foo=100, bar=200)</code></li></ul><p>元组可以作为 dict 的 key,但列表不能作为元组的 key。这是由于 dict 要求 key 必须是不可变类型,但列表是可变类型,因此列表不能作为元组的 key。</p><p>items()、keys()、values() 分别用于获取字典中的所有 key-value 对、所有 key、所有 value。这三个方法依次返回 dict_items、dict_keys 和 dict_values 对象,Python 不希望用户直接操作这几个方法,但可通过 list() 函数把它们转换成列表。</p><ul><li>dict.has_key(key)<br>如果键在字典dict里返回true,否则返回false</li><li>dict.get(key, default=None) 返回指定键的值,如果值不在字典中返回default值</li></ul><h3 id="deque"><a href="#deque" class="headerlink" title="deque"></a>deque</h3><p>collections.deque()</p><p><em>class</em> <code>collections.``deque</code>([<em>iterable</em>[, <em>maxlen</em>]])</p><ul><li><p><code>append</code>(<em>x</em>)</p><p>添加 <em>x</em> 到右端。</p></li><li><p><code>appendleft</code>(<em>x</em>)</p><p>添加 <em>x</em> 到左端。</p></li><li><p><code>pop</code>()</p><p>移去并且返回一个元素,deque 最右侧的那一个。 如果没有元素的话,就引发一个 <a href="https://docs.python.org/zh-cn/3/library/exceptions.html#IndexError"><code>IndexError</code></a>。</p></li><li><p><code>popleft</code>()</p><p>移去并且返回一个元素,deque 最左侧的那一个。 如果没有元素的话,就引发 <a href="https://docs.python.org/zh-cn/3/library/exceptions.html#IndexError"><code>IndexError</code></a>。</p></li><li><p>Deque对象同样提供了一个只读属性:</p><ul><li><p><code>maxlen</code></p><p>Deque的最大尺寸,如果没有限定的话就是 <code>None</code> 。</p></li></ul></li></ul><h3 id="Counter"><a href="#Counter" class="headerlink" title="Counter"></a>Counter</h3><h3 id="OrderedDict"><a href="#OrderedDict" class="headerlink" title="OrderedDict"></a>OrderedDict</h3><p>collections. 有序字典</p><h3 id="heapq"><a href="#heapq" class="headerlink" title="heapq"></a>heapq</h3><h3 id="defaultdict"><a href="#defaultdict" class="headerlink" title="defaultdict"></a>defaultdict</h3><h3 id="ChainMap"><a href="#ChainMap" class="headerlink" title="ChainMap"></a>ChainMap</h3><h2 id="常用函数、方法"><a href="#常用函数、方法" class="headerlink" title="常用函数、方法"></a>常用函数、方法</h2><pre class="language-none"><code class="language-none">a = '123456'a[2:3]//'3' 冒号前包后不包string.isdigit() //如果 string 只包含数字则返回 True 否则返回 False.</code></pre><h3 id="enumerate"><a href="#enumerate" class="headerlink" title="enumerate()"></a><strong>enumerate()</strong></h3><p>遍历列表(数组),可以同时获取索引和值,下面是例子</p><pre class="language-python" data-language="python"><code class="language-python">arr1 <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">"a"</span><span class="token punctuation">,</span><span class="token string">"b"</span><span class="token punctuation">,</span><span class="token string">"c"</span><span class="token punctuation">,</span><span class="token string">"d"</span><span class="token punctuation">]</span><span class="token keyword">for</span> index<span class="token punctuation">,</span>value <span class="token keyword">in</span> <span class="token builtin">enumerate</span><span class="token punctuation">(</span>arr1<span class="token punctuation">)</span><span class="token punctuation">:</span><span class="token keyword">print</span><span class="token punctuation">(</span>index<span class="token punctuation">,</span>value<span class="token punctuation">)</span><span class="token comment"># 结果</span><span class="token number">0</span> a<span class="token number">1</span> b<span class="token number">2</span> c<span class="token number">3</span> d</code></pre><h3 id="json模块"><a href="#json模块" class="headerlink" title="json模块"></a>json模块</h3><p>把字符串转换成字典对象json.loads()</p><p>把对象转换成字符串json.dumps()</p><p>json.dump(data,file)把字典对象转换成字符串并写入文件</p><p>字符串转换成字典对象时,字符串里只能使用双引号</p><h3 id="‘’-join-拼接字符串"><a href="#‘’-join-拼接字符串" class="headerlink" title="‘’.join() 拼接字符串"></a>‘’.join() 拼接字符串</h3><pre class="language-python" data-language="python"><code class="language-python">arr <span class="token operator">=</span><span class="token punctuation">[</span><span class="token string">"a"</span><span class="token punctuation">,</span><span class="token string">"b"</span><span class="token punctuation">,</span><span class="token string">"c"</span><span class="token punctuation">]</span>arr_str <span class="token operator">=</span> <span class="token string">"-"</span><span class="token punctuation">.</span>join<span class="token punctuation">(</span>arr<span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span>arr_str<span class="token punctuation">)</span><span class="token comment"># 输出结果 a-b-c</span><span class="token string">''</span><span class="token punctuation">.</span>join<span class="token punctuation">(</span>chain<span class="token punctuation">(</span><span class="token operator">*</span>mat<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token operator">//</span>拼接二维矩阵</code></pre><h3 id="math-comb"><a href="#math-comb" class="headerlink" title="math.comb()"></a>math.comb()</h3><p>Python中的method方法用于获取从n个项目中选择k个项目(不重复且无顺序)的方法数量</p><h3 id="os-path-split-‘PATH’"><a href="#os-path-split-‘PATH’" class="headerlink" title="os.path.split(‘PATH’)"></a>os.path.split(‘PATH’)</h3><p>以 “PATH” 中最后一个 ‘/‘ 作为分隔符,分隔后,将索引为0的视为目录(路径),将索引为1的视为文件名</p><h3 id="print"><a href="#print" class="headerlink" title="print"></a>print</h3><p> print(i,end=’\n’),可指定末尾字符,默认为换行</p><h3 id="product"><a href="#product" class="headerlink" title="product"></a>product</h3><p> product(A,B)函数,返回A和B中的元素组成的<a href="https://so.csdn.net/so/search?q=%E7%AC%9B%E5%8D%A1%E5%B0%94%E7%A7%AF&spm=1001.2101.3001.7020">笛卡尔积</a>的元组,具体见如下代码:</p><pre class="language-Python" data-language="Python"><code class="language-Python">import itertoolsfor item in itertools.product([1,2,3,4],[100,200]): print(item) '''(1, 100)(1, 200)(2, 100)(2, 200)(3, 100)(3, 200)(4, 100)(4, 200) '''12345678910111213</code></pre><p> product(list1,list2)依次取出list1中每1个元素,与list2中的每1个元素,组成元组,将所有元组组合成一个列表返回.</p><h3 id="round"><a href="#round" class="headerlink" title="round()"></a>round()</h3><p>四舍五入取整</p><h3 id="sort"><a href="#sort" class="headerlink" title="sort"></a>sort</h3><p>Python 列表有一个内置的 <a href="https://docs.python.org/zh-cn/3.10/library/stdtypes.html#list.sort"><code>list.sort()</code></a> 方法可以直接修改列表。还有一个 <a href="https://docs.python.org/zh-cn/3.10/library/functions.html#sorted"><code>sorted()</code></a> 内置函数,它会从一个可迭代对象构建一个新的排序列表</p><pre class="language-none"><code class="language-none">class Student: def __init__(self, name, grade, age): self.name = name self.grade = grade self.age = age def __repr__(self): return repr((self.name, self.grade, self.age))student_objects = [ Student('john', 'A', 15), Student('jane', 'B', 12), Student('dave', 'B', 10),]</code></pre><p>Operator 模块函数</p><p>上面显示的键函数模式非常常见,因此 Python 提供了便利功能,使访问器功能更容易,更快捷。 <a href="https://docs.python.org/zh-cn/3/library/operator.html#module-operator"><code>operator</code></a> 模块有 <a href="https://docs.python.org/zh-cn/3/library/operator.html#operator.itemgetter"><code>itemgetter()</code></a> 、 <a href="https://docs.python.org/zh-cn/3/library/operator.html#operator.attrgetter"><code>attrgetter()</code></a> 和 <a href="https://docs.python.org/zh-cn/3/library/operator.html#operator.methodcaller"><code>methodcaller()</code></a> 函数。</p><p>使用这些函数,上述示例变得更简单,更快捷:</p><pre class="language-none"><code class="language-none">>>> from operator import itemgetter, attrgetter>>> sorted(student_tuples, key=itemgetter(2))[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]>>> sorted(student_objects, key=attrgetter('age'))[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]</code></pre><p>Operator 模块功能允许<strong>多级排序</strong>。 例如,按 <em>grade</em> 排序,然后按 <em>age</em> 排序:</p><pre class="language-none"><code class="language-none">>>> sorted(student_tuples, key=itemgetter(1,2))[('john', 'A', 15), ('dave', 'B', 10), ('jane', 'B', 12)]>>> sorted(student_objects, key=attrgetter('grade', 'age'))[('john', 'A', 15), ('dave', 'B', 10), ('jane', 'B', 12)]</code></pre><h4 id="升序和降序"><a href="#升序和降序" class="headerlink" title="升序和降序"></a>升序和降序</h4><p><a href="https://docs.python.org/zh-cn/3/library/stdtypes.html#list.sort"><code>list.sort()</code></a> 和 <a href="https://docs.python.org/zh-cn/3/library/functions.html#sorted"><code>sorted()</code></a> 接受布尔值的 <em>reverse</em> 参数。这用于标记降序排序。 例如,要以反向 <em>age</em> 顺序获取学生数据:</p><pre class="language-none"><code class="language-none">>>> sorted(student_tuples, key=itemgetter(2), reverse=True)[('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]>>> sorted(student_objects, key=attrgetter('age'), reverse=True)[('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]</code></pre><h4 id="排序稳定性和排序复杂度"><a href="#排序稳定性和排序复杂度" class="headerlink" title="排序稳定性和排序复杂度"></a>排序稳定性和排序复杂度</h4><p>排序保证是 <a href="https://en.wikipedia.org/wiki/Sorting_algorithm#Stability">稳定</a> 的。 这意味着当多个记录具有相同的键值时,将保留其原始顺序。</p><h3 id="str-isalpha"><a href="#str-isalpha" class="headerlink" title="str.isalpha()"></a>str.isalpha()</h3><p>字符串是否为字母</p><h3 id="str-maketrans-intab-outtab"><a href="#str-maketrans-intab-outtab" class="headerlink" title="str.maketrans(intab.outtab)"></a>str.maketrans(intab.outtab)</h3><ul><li>intab – 字符串中要替代的字符组成的字符串。</li><li>outtab – 相应的映射字符的字符串。</li></ul><p>内建函数: bytearray.maketrans()、bytes.maketrans()、str.maketrans()</p><p>通常和 translate 方法配合使用</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token comment">#!/usr/bin/python3</span> intab <span class="token operator">=</span> <span class="token string">"aeiou"</span>outtab <span class="token operator">=</span> <span class="token string">"12345"</span>deltab <span class="token operator">=</span> <span class="token string">"thw"</span> trantab1 <span class="token operator">=</span> <span class="token builtin">str</span><span class="token punctuation">.</span>maketrans<span class="token punctuation">(</span>intab<span class="token punctuation">,</span>outtab<span class="token punctuation">)</span> <span class="token comment"># 创建字符映射转换表</span>trantab2 <span class="token operator">=</span> <span class="token builtin">str</span><span class="token punctuation">.</span>maketrans<span class="token punctuation">(</span>intab<span class="token punctuation">,</span>outtab<span class="token punctuation">,</span>deltab<span class="token punctuation">)</span> <span class="token comment">#创建字符映射转换表,并删除指定字符</span> test <span class="token operator">=</span> <span class="token string">"this is string example....wow!!!"</span> <span class="token keyword">print</span><span class="token punctuation">(</span>test<span class="token punctuation">.</span>translate<span class="token punctuation">(</span>trantab1<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span>test<span class="token punctuation">.</span>translate<span class="token punctuation">(</span>trantab2<span class="token punctuation">)</span><span class="token punctuation">)</span></code></pre><h3 id="str-split"><a href="#str-split" class="headerlink" title="str.split()"></a>str.split()</h3><p>语法:str.split(str=” “,num=string.count(str))</p><p>参数说明:<br>str: 表示为分隔符,默认为空格,但是不能为空串。若字符串中没有分隔符,则把整个字符串作为列表的一个元素。<br>num:表示分割次数。如果存在参数num,则仅分隔成 num+1 个子字符串。</p><p>默认空格分隔时会忽略分割后的空串,包括\n\t\r (\r\n表示回车换行)</p><pre class="language-none"><code class="language-none">s.split('.',-1) #尽可能多的分隔,与不加num参数相同</code></pre><p>注意:str为不可变对象,所以此方法不会修改原对象,若需处理分割后的字符串需要转储返回值</p><pre class="language-none"><code class="language-none">sNew = str.split()</code></pre><h3 id="str-strip-chars"><a href="#str-strip-chars" class="headerlink" title="str.strip([chars])"></a>str.strip([chars])</h3><p>strip() 方法用于移除<a href="https://so.csdn.net/so/search?q=%E5%AD%97%E7%AC%A6%E4%B8%B2&spm=1001.2101.3001.7020">字符串</a>头尾指定的字符(默认为空格或换行符)或字符序列。</p><p>还有lstrip和rstrip,去除头部或尾部</p><h3 id="和"><a href="#和" class="headerlink" title="* 和 **"></a>* 和 **</h3><ul><li><code>*args</code>:argument用于列表、元组、集合</li><li><code>**kwargs</code>:kwargument用于字典</li></ul><p>1.解包可迭代对象</p><pre class="language-none"><code class="language-none">nums1=[*nums1,*nums2]nums1+=nums2nums1.extend(nums2)</code></pre><p>2.函数可变参数</p><h2 id="regex"><a href="#regex" class="headerlink" title="regex"></a>regex</h2><p>python3.9文档<a href="https://docs.python.org/zh-cn/3.9/library/re.html?highlight=re#module-contents">https://docs.python.org/zh-cn/3.9/library/re.html?highlight=re#module-contents</a></p><p>re.findall(<em>pattern</em>, <em>string</em>, <em>flags=0</em>)</p><p>返回字符串中模式的所有非重叠匹配项,作为字符串列表或元组。该字符串从左到右扫描,并按找到的顺序返回匹配项。结果中包含空匹配项。</p><p>结果取决于模式中捕获组的数量。如果没有组,则返回匹配整个模式的字符串列表。如果只有一个组,则返回匹配该组的字符串列表。如果存在多个组,则返回与组匹配的字符串元组列表。非捕获组不影响结果的形式。</p><pre class="language-none"><code class="language-none">>>>re.findall(r'\bf[a-z]*', 'which foot or hand fell fastest')['foot', 'fell', 'fastest']>>> re.findall(r'(\w+)=(\d+)', 'set width=20 and height=10')[('width', '20'), ('height', '10')]</code></pre><h3 id="re-sub-pattern-repl-string-count-x3D-0-flags-x3D-0"><a href="#re-sub-pattern-repl-string-count-x3D-0-flags-x3D-0" class="headerlink" title="re.sub(pattern, repl, string, count=0, flags=0)"></a>re.sub(<em>pattern</em>, <em>repl</em>, <em>string</em>, <em>count=0</em>, <em>flags=0</em>)</h3><p>返回通过使用 <em>repl</em> 替换在 <em>string</em> 最左边非重叠出现的 <em>pattern</em> 而获得的字符串。 如果样式没有找到,则不加改变地返回 <em>string</em>。 <em>repl</em> 可以是字符串或函数;如为字符串,则其中任何反斜杠转义序列都会被处理。 也就是说,<code>\n</code> 会被转换为一个换行符,<code>\r</code> 会被转换为一个回车符,依此类推。 未知的 ASCII 字符转义序列保留在未来使用,会被当作错误来处理。 其他未知转义序列例如 <code>\&</code> 会保持原样。 向后引用像是 <code>\6</code> 会用样式中第 6 组所匹配到的子字符串来替换。 例如:</p><pre class="language-none"><code class="language-none">>>> re.sub(r'def\s+([a-zA-Z_][a-zA-Z_0-9]*)\s*\(\s*\):',... r'static PyObject*\npy_\1(void)\n{',... 'def myfunc():')'static PyObject*\npy_myfunc(void)\n{'</code></pre><p>如果 <em>repl</em> 是一个函数,那它会对每个非重复的 <em>pattern</em> 的情况调用。这个函数只能有一个 <a href="https://docs.python.org/zh-cn/3.9/library/re.html?highlight=re#match-objects">匹配对象</a> 参数,并返回一个替换后的字符串。比如</p><pre class="language-none"><code class="language-none">>>> def dashrepl(matchobj):... if matchobj.group(0) == '-': return ' '... else: return '-'>>> re.sub('-{1,2}', dashrepl, 'pro----gram-files')'pro--gram files'>>> re.sub(r'\sAND\s', ' & ', 'Baked Beans And Spam', flags=re.IGNORECASE)'Baked Beans & Spam'</code></pre><p>样式可以是一个字符串或者一个 <a href="https://docs.python.org/zh-cn/3.9/library/re.html?highlight=re#re-objects">样式对象</a> 。</p><p>可选参数 <em>count</em> 是要替换的最大次数;<em>count</em> 必须是非负整数。如果省略这个参数或设为 0,所有的匹配都会被替换。 样式的空匹配仅在与前一个空匹配不相邻时才会被替换,所以 <code>sub('x*', '-', 'abxd')</code> 返回 <code>'-a-b--d-'</code> 。</p><p>在字符串类型的 <em>repl</em> 参数里,如上所述的转义和向后引用中,<code>\g<name></code> 会使用命名组合 <code>name</code>,(在 <code>(?P<name>…)</code> 语法中定义) <code>\g<number></code> 会使用数字组;<code>\g<2></code> 就是 <code>\2</code>,但它避免了二义性,如 <code>\g<2>0</code>。 <code>\20</code> 就会被解释为组20,而不是组2后面跟随一个字符 <code>'0'</code>。向后引用 <code>\g<0></code> 把 <em>pattern</em> 作为一整个组进行引用。</p><h3 id="re-subn-pattern-repl-string-count-x3D-0-flags-x3D-0-¶"><a href="#re-subn-pattern-repl-string-count-x3D-0-flags-x3D-0-¶" class="headerlink" title="re.subn(pattern, repl, string, count=0, flags=0)¶"></a>re.subn(<em>pattern</em>, <em>repl</em>, <em>string</em>, <em>count=0</em>, <em>flags=0</em>)<a href="https://docs.python.org/zh-cn/3.9/library/re.html?highlight=re#re.subn">¶</a></h3><p>行为与 <a href="https://docs.python.org/zh-cn/3.9/library/re.html?highlight=re#re.sub"><code>sub()</code></a> 相同,但是返回一个元组 <code>(字符串, 替换次数)</code>.</p><h2 id="作用域"><a href="#作用域" class="headerlink" title="作用域"></a>作用域</h2><p><a href="https://docs.python.org/zh-cn/3/reference/simple_stmts.html#nonlocal"><code>nonlocal</code></a> 语句会使得所列出的名称指向之前在最近的包含作用域中绑定的除全局变量以外的变量。</p><p><a href="https://docs.python.org/zh-cn/3/reference/simple_stmts.html#global"><code>global</code></a> 语句是作用于整个当前代码块的声明。 它意味着所列出的标识符将被解读为全局变量。 要给全局变量赋值不可能不用到 <code>global</code> 关键字,不过自由变量也可以指向全局变量而不必声明为全局变量。</p><p>在 <a href="https://docs.python.org/zh-cn/3/reference/simple_stmts.html#global"><code>global</code></a> 语句中列出的名称不得在同一代码块内该 <code>global</code> 语句之前的位置中使用。</p><p>在 <a href="https://docs.python.org/zh-cn/3/reference/simple_stmts.html#global"><code>global</code></a> 语句中列出的名称不能被定义为形式参数,也不能被作为 <a href="https://docs.python.org/zh-cn/3/reference/compound_stmts.html#with"><code>with</code></a> 语句或 <a href="https://docs.python.org/zh-cn/3/reference/compound_stmts.html#except"><code>except</code></a> 子句的目标,以及 <a href="https://docs.python.org/zh-cn/3/reference/compound_stmts.html#for"><code>for</code></a> 循环的目标列表、<a href="https://docs.python.org/zh-cn/3/reference/compound_stmts.html#class"><code>class</code></a> 定义、函数定义、<a href="https://docs.python.org/zh-cn/3/reference/simple_stmts.html#import"><code>import</code></a> 语句或变量标注等等。</p><pre class="language-none"><code class="language-none">def scope_test(): def do_local(): spam = "local spam" def do_nonlocal(): nonlocal spam spam = "nonlocal spam" def do_global(): global spam spam = "global spam" spam = "test spam" do_local() print("After local assignment:", spam) do_nonlocal() print("After nonlocal assignment:", spam) do_global() print("After global assignment:", spam)scope_test()print("In global scope:", spam)输出:After local assignment: test spamAfter nonlocal assignment: nonlocal spamAfter global assignment: nonlocal spamIn global scope: global spam</code></pre><h2 id="可迭代对象,迭代器,生成器"><a href="#可迭代对象,迭代器,生成器" class="headerlink" title="可迭代对象,迭代器,生成器"></a>可迭代对象,迭代器,生成器</h2><p>常见可迭代对象</p><ol><li>集合或序列类型(如<code>list</code>、<code>tuple</code>、<code>set</code>、<code>dict</code>、<code>str</code>)</li><li>文件对象</li><li>在类中定义了<code>__iter__()</code>方法的对象,可以被认为是 <code>Iterable</code>对象,但自定义的可迭代对象要能在<code>for</code>循环中正确使用,就需要保证<code>__iter__()</code>实现必须是正确的(即可以通过内置<code>iter()</code>函数转成<code>Iterator</code>对象。<code>iter()</code>函数是能够将一个可迭代对象转成迭代器对象,然后在<code>for</code>中使用)</li><li>在类中实现了如果只实现<code>__getitem__()</code>的对象可以通过<code>iter()</code>函数转化成迭代器但其本身不是可迭代对象。所以当一个对象能够在<code>for</code>循环中运行,但不一定是<code>Iterable</code>对象。</li></ol><p><code>可迭代对象(Iteratable Object)</code> 是能够一次返回其中一个成员的对象,<strong>都构建了 <code>__iter__</code> 方法</strong></p><p><code>迭代器(Iterator)</code> 是同时实现<code>__iter__() 与 __next__()</code> 方法的对象。</p><pre class="language-none"><code class="language-none">class IterObj: def __init__(self): self.a = [3, 5, 7, 11, 13, 17, 19] self.n = len(self.a) self.i = 0 def __iter__(self): return iter(self.a) def __next__(self): while self.i < self.n: v = self.a[self.i] self.i += 1 return v else: self.i = 0 raise StopIteration()</code></pre><p>定义生成器两种方法:</p><ol><li>列表生成器——生成器表达式</li><li>使用<code>yield</code>定义生成器函数——生成器函数</li></ol><p>Python 中,包含 yield 关键词的普通函数就是生成器。</p><p>定义二维数组</p><pre class="language-python" data-language="python"><code class="language-python">list_three <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">[</span><span class="token number">0</span> <span class="token keyword">for</span> i <span class="token keyword">in</span> <span class="token builtin">range</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">]</span> <span class="token keyword">for</span> j <span class="token keyword">in</span> <span class="token builtin">range</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">]</span></code></pre><h2 id="类"><a href="#类" class="headerlink" title="类"></a>类</h2><p>对象方法、静态方法、类方法等,归属权分别为obj、cls、cls</p><h3 id="基础-1"><a href="#基础-1" class="headerlink" title="基础"></a>基础</h3><p>当(从结尾处)正常离开类定义时,将创建一个 <em>类对象</em>。 这基本上是一个包围在类定义所创建命名空间内容周围的包装器,原始的(在进入类定义之前起作用的)局部作用域将重新生效,类对象将在这里被绑定到类定义头所给出的类名称</p><p>任何形式为 <code>__spam</code> 的标识符(至少带有两个前缀下划线,至多一个后缀下划线)的文本将被替换为 <code>_classname__spam</code>,其中 <code>classname</code> 为去除了前缀下划线的当前类名称。 这种改写不考虑标识符的句法位置,只要它出现在类定义内部就会进行。__init__类似构造函数</p><pre class="language-none"><code class="language-none">class Student(object): ... def set_score(self, score): self.__score = score</code></pre><p>以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是private变量,所以,不能用<code>__name__</code>、<code>__score__</code>这样的变量名</p><p>t.ppr()等同于Test.ppr(t)</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token keyword">class</span> <span class="token class-name">Test</span><span class="token punctuation">:</span> <span class="token keyword">def</span> <span class="token function">ppr</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">print</span><span class="token punctuation">(</span>self<span class="token punctuation">)</span>t <span class="token operator">=</span> Test<span class="token punctuation">(</span><span class="token punctuation">)</span>t<span class="token punctuation">.</span>ppr<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">#Test.ppr(t)</span><span class="token comment">#没有传参数,error:</span>Traceback <span class="token punctuation">(</span>most recent call last<span class="token punctuation">)</span><span class="token punctuation">:</span> File <span class="token string">"cl.py"</span><span class="token punctuation">,</span> line <span class="token number">6</span><span class="token punctuation">,</span> <span class="token keyword">in</span> <span class="token operator"><</span>module<span class="token operator">></span> t<span class="token punctuation">.</span>ppr<span class="token punctuation">(</span><span class="token punctuation">)</span>TypeError<span class="token punctuation">:</span> ppr<span class="token punctuation">(</span><span class="token punctuation">)</span> takes <span class="token number">0</span> positional arguments but <span class="token number">1</span> was given</code></pre><p>ins,用来表示调用它的类实例</p><p>cls,类</p><p>类本身的方法是函数对象,实例的方法是方法对象,实现原理如下:</p><p>当一个实例的非数据属性被引用时,将搜索实例所属的类。 如果被引用的属性名称表示一个有效的类属性中的函数对象,会通过打包(指向)查找到的实例对象和函数对象到一个抽象对象的方式来创建方法对象:这个抽象对象就是方法对象。 当附带参数列表调用方法对象时,将基于实例对象和参数列表构建一个新的参数列表,并使用这个新参数列表调用相应的函数对象。</p><h3 id="类的继承"><a href="#类的继承" class="headerlink" title="类的继承"></a>类的继承</h3><pre class="language-python" data-language="python"><code class="language-python"><span class="token keyword">class</span> <span class="token class-name">Parent</span><span class="token punctuation">:</span> <span class="token keyword">def</span> <span class="token function">pprt</span><span class="token punctuation">(</span>self<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">print</span><span class="token punctuation">(</span>self<span class="token punctuation">)</span><span class="token keyword">class</span> <span class="token class-name">Child</span><span class="token punctuation">(</span>Parent<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">def</span> <span class="token function">cprt</span><span class="token punctuation">(</span>self<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">print</span><span class="token punctuation">(</span>self<span class="token punctuation">)</span>c <span class="token operator">=</span> Child<span class="token punctuation">(</span><span class="token punctuation">)</span>c<span class="token punctuation">.</span>cprt<span class="token punctuation">(</span><span class="token punctuation">)</span>c<span class="token punctuation">.</span>pprt<span class="token punctuation">(</span><span class="token punctuation">)</span>p <span class="token operator">=</span> Parent<span class="token punctuation">(</span><span class="token punctuation">)</span>p<span class="token punctuation">.</span>pprt<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token comment">#output:</span><span class="token operator"><</span>__main__<span class="token punctuation">.</span>Child <span class="token builtin">object</span> at <span class="token number">0x0000000002A47080</span><span class="token operator">></span><span class="token operator"><</span>__main__<span class="token punctuation">.</span>Child <span class="token builtin">object</span> at <span class="token number">0x0000000002A47080</span><span class="token operator">></span><span class="token operator"><</span>__main__<span class="token punctuation">.</span>Parent <span class="token builtin">object</span> at <span class="token number">0x0000000002A47240</span><span class="token operator">></span></code></pre><h3 id="类中的方法:"><a href="#类中的方法:" class="headerlink" title="类中的方法:"></a>类中的方法:</h3><ul><li><code>__init__</code>方法的第一参数永远是<code>self</code>,表示创建的类<strong>实例本身</strong>,因此,在<code>__init__</code>方法内部,就可以把各种属性绑定到self,因为self就指向创建的实例本身。(2)、有了<code>__init__</code>方法,在创建实例的时候,就不能传入空的参数了,必须传入与<code>__init__</code>方法匹配的参数,但self不需要传,Python解释器会自己把实例变量传进去:</li></ul><p>也分实例属性和类属性,后者所有实例共享</p><p><strong>实例属性访问优先级比类属性高</strong></p><p>千万不要在实例上修改类属性,它实际上并没有修改类属性,而是给实例绑定了一个实例属性。</p><h2 id="其它"><a href="#其它" class="headerlink" title="其它"></a>其它</h2><h3 id="解释器信息"><a href="#解释器信息" class="headerlink" title="解释器信息"></a>解释器信息</h3><p>#!/usr/bin/python</p><p>分成两种情况:</p><p>(1)如果调用 python 脚本时,使用:</p><pre class="language-none"><code class="language-none">python script.py </code></pre><p>#!/usr/bin/python 被忽略,等同于注释</p><p>(2)如果调用python脚本时,使用:</p><pre class="language-none"><code class="language-none">./script.py </code></pre><p>#!/usr/bin/python 指定解释器的路径</p><p>PS:shell 脚本中在第一行也有类似的声明。</p><h3 id="复杂类型注解"><a href="#复杂类型注解" class="headerlink" title="复杂类型注解"></a>复杂类型注解</h3><p>List[int]即由int组成的列表,但是,实际中,只要这个列表中存在nt(其他的可以为任何类型),就不会出现警告</p><h3 id="模块信息"><a href="#模块信息" class="headerlink" title="模块信息"></a>模块信息</h3><p>__name__</p><p>直接执行一段脚本的时候,这段脚本的 **<strong>name</strong>**变量等于 <strong>‘<strong>main</strong>‘<strong>,当这段脚本被导入其他程序的时候,</strong><strong>name</strong></strong> 变量等于脚本本身的名字。</p><h3 id="环境"><a href="#环境" class="headerlink" title="环境"></a>环境</h3><p>anaconda</p><p>一、先创建一个新的虚拟环境</p><p>conda create –name my_test python=3.7#创建一个名称为my_test的虚拟环境</p><p>二、激活虚拟环境</p><p>activate my_test</p><p>三、切换环境</p><p><a href="https://so.csdn.net/so/search?q=conda&spm=1001.2101.3001.7020">conda</a> info –env可以看到所有python环境,前面有个‘*’的代表当前环境:</p><p>1、查看已有的虚拟环境</p><p>conda env list</p><p><img src="/Python/v2-2855cfd302e331d8c9a1ee1dfd84d925_720w.webp" alt="img"></p><p>2、切换到想要的虚拟环境,这里我切换到my_test</p><p>conda activate my_test</p><p>3、在当前环境里安装ipykernel</p><p>conda install ipykernel</p><p><img src="/Python/v2-3fe468e3a7647d138d6054a0c1c641bb_720w.webp" alt="img"></p><p>4、python -m ipykernel install –name my_test</p><p><img src="/Python/v2-abb56915ea64e5583f1dea223876144c_720w.webp" alt="img"></p><p>5、打开jupyter新建一个notebook,如下所示:</p><p><img src="/Python/v2-b6ccaa26c129ca4d0e284b645f74bbde_720w.webp" alt="img"></p><p>克隆产生新环境,移除旧环境达到更改环境名称的目的</p><p><a href="https://so.csdn.net/so/search?q=conda&spm=1001.2101.3001.7020">conda</a> create –name python32(新名字) –clone python321(老名字)</p><p>conda remove –name old_name –all</p><h3 id="mamba"><a href="#mamba" class="headerlink" title="mamba"></a>mamba</h3><p>替代 conda 的包管理系统</p><p>Geemap has several optional dependencies, such as <a href="https://geopandas.org/">GeoPandas</a>, <a href="https://github.com/banesullivan/localtileserver">localtileserver</a>, <a href="https://github.com/gboeing/osmnx">osmnx</a>, <a href="https://github.com/corteva/rioxarray">rioxarray</a> and <a href="https://github.com/cogeotiff/rio-cogeo">rio-cogeo</a>. It can be a bit cumbersome to install these optional dependencies individually. Luckily, these optional dependencies are available through the <a href="https://github.com/giswqs/pygis">pygis</a> Python package, which can be installed with a single command. Since pygis has many dependencies, sometimes it can take a while for conda to resolve dependencies. Therefore, we highly recommend you to install <a href="https://github.com/mamba-org/mamba">Mamba</a>, a fast, robust, and cross-platform package manager. It runs on Windows, macOS, and Linux, and is fully compatible with conda packages and supports most of conda’s commands. The following commands install Mamba and pygis:</p><pre class="language-none"><code class="language-none">conda install -c conda-forge mambamamba install -c conda-forge geemap pygis</code></pre>]]></content>
<summary type="html"><blockquote>
<p>持续更新</p>
</blockquote>
<h3 id=""><a href="#" class="headerlink" title=""></a></h3><h2 id="基础"><a href="#基础" class="headerlin</summary>
<category term="常用编程语言基础知识" scheme="https://hhumar.com/categories/%E5%B8%B8%E7%94%A8%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/"/>
<category term="Python" scheme="https://hhumar.com/tags/Python/"/>
</entry>
<entry>
<title>JavaScript</title>
<link href="https://hhumar.com/2022/10/30/js/"/>
<id>https://hhumar.com/2022/10/30/js/</id>
<published>2022-10-30T07:29:37.000Z</published>
<updated>2022-11-19T15:57:03.121Z</updated>
<content type="html"><![CDATA[<blockquote><p>持续更新</p></blockquote><h2 id="基础"><a href="#基础" class="headerlink" title="基础"></a>基础</h2><pre class="language-markup" data-language="markup"><code class="language-markup">JS和python都是解释型语言,仅需解释器在每次执行时编译并解释执行,编译型语言如c++,Java编译一次后,产生可执行文件可多次执行,效率高<span class="token comment"><!--本地路径/和\是等效的--></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>.\Image\20161025\guo.jpg<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>./Image/20161025/guo.jpg<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>.\Image/20161025/guo.jpg<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>./Image\20161025\guo.jpg<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><span class="token comment"><!--网络文件路径一定要使用正斜杠/--></span></code></pre><p>诞生于1995,出现时用于处理网页中的<strong>前端验证</strong>,发展中遵循ECMAScript标准,完整的JavaScript由三部分组成:<strong>ECMAScript标准,DOM文档对象模型,BOM浏览器对象模型</strong></p><p>解释型语言,无需编译直接运行,动态语言,基于原型的面向对象,写在script标签中,从上到下逐条执行;标识符命名仅可以含有字母、数字、_、$</p><h2 id="变量性质、关键字和特性"><a href="#变量性质、关键字和特性" class="headerlink" title="变量性质、关键字和特性"></a>变量性质、关键字和特性</h2><p>区分大小写,允许Unicode字母、数字和表意文字(意味着可以用汉字定义变量但不推荐)</p><p>当浏览器开辟出供代码执行的栈<a href="https://so.csdn.net/so/search?q=%E5%86%85%E5%AD%98&spm=1001.2101.3001.7020">内存</a>后,代码并没有自上而下立即执行,而是继续做了一些事情:<strong>把当前作用域中所有带var/function关键字的进行提前的声明和定义 => 变量提升机制</strong></p><p>typeof 操作符</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">typeof</span> <span class="token string">'aaa'</span><span class="token punctuation">;</span><span class="token comment">//"string"</span></code></pre><h3 id="let和var的区别"><a href="#let和var的区别" class="headerlink" title="let和var的区别"></a><code>let</code>和<code>var</code>的区别</h3><p> <code>let</code>和<code>const</code>不存在变量提升机制;<code>var</code>允许重复声明,而<code>let</code>不允许重复声明; <code>let</code>能解决<code>typeof</code>检测时出现的暂时性死区问题(<code>let</code>比<code>var</code>更严谨);let创建的全局变量没有给window设置对应的属性;let会产生块级作用域</p><ul><li><code>var</code>声明是全局作用域或函数作用域,而<code>let</code>和<code>const</code>是块作用域。</li><li><code>var</code>变量可以在其范围内更新和重新声明; <code>let</code>变量可以被更新但不能重新声明; <code>const</code>变量既不能更新也不能重新声明。</li><li>它们都被提升到其作用域的顶端。但是,虽然使用变量<code>undefined</code>初始化了<code>var</code>变量,但未初始化<code>let</code>和<code>const</code>变量。</li><li>尽管可以在不初始化的情况下声明<code>var</code>和<code>let</code>,但是在声明期间必须初始化<code>const</code>。</li></ul><p>暂时性死区:在块级顶部到变量正式申明这块区域去访问这个变量的话,直接报错</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> x <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span><span class="token keyword">if</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>x<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//报错而不是到外部引用x</span> <span class="token keyword">let</span> x <span class="token operator">=</span> <span class="token number">2</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><h3 id="六种数据类型"><a href="#六种数据类型" class="headerlink" title="六种数据类型"></a>六种数据类型</h3><p><code>String</code> <code>Number</code> <code>Boolean</code> <code>Undefined</code> <code>Symbol</code> <code>Object</code> </p><p><code>Object</code>为引用数据类型 </p><ul><li><p>Number</p><p>均采用IEEE 754存储数字,会把能转换为整数的小数转换为整数。科学计数法:3.123e7等效于3.123*10^7</p><p>八进制值用0o做前缀,十六进制0x前缀</p><p>浮点值最高精度为1e-17,不宜用js做科学计算</p><p><code>NaN</code>表示<code>Not a Number</code>,数据类型也是<code>Number</code>,有<code>Number.MIN_VALUE</code>=5E-324,<code>Number.MAX_VALUE</code>=1.797e308,还有正无穷 Infinity 和负无穷 -Infinity。函数 isFinite()可以判断数值是不是有限</p><p>isNaN()函数可以判断所给参数是否能转换为数值,不能则返回 true</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token function">isNan</span><span class="token punctuation">(</span><span class="token string">'10'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//返回false,因为能转化为数字</span>num<span class="token punctuation">.</span><span class="token function">toFixed</span><span class="token punctuation">(</span>digits<span class="token punctuation">)</span><span class="token comment">//浮点数规整化,digits为小数点后保留位数</span>Math<span class="token punctuation">.</span><span class="token function">trunc</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">//return the integer portion of a number</span></code></pre><p>即将支持的 BigInt 大数,在number字面量后加上 n 即可。可以表示任意大整数。</p></li><li><p><code>null</code>值用来表示一个为空的对象,<code>typeof null</code>时返回<code>object</code>类型。原则上 null 表示一个空指针</p></li><li><p>string:将其他数据类型转换为String类型:<code>toString</code>方法和<code>String</code>函数,前者不能转换null和undefined类型,后者可以,凡遇字母转换为<code>NaN</code>。 转换为Number类型:Number函数,针对字符串有<code>parseInt</code>和<code>parseFloat</code>,这两个函数遇到其他类型时会先将对象转换为字符串再进行转换。</p><p>toString()方法在用于数值对象时可以接受参数,表示转换为不同进制的数字字符。</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">let</span> num <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>num<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// "10" </span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>num<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// "1010" </span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>num<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token number">8</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// "12" </span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>num<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// "10" </span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>num<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token number">16</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// "a" </span></code></pre><p><em>用加号操作符给一个值加上一个空字符串””也可以将其转换为字符串</em></p><ul><li><p>``反引号,不同于单引号’’和双引号””,可以包裹模板字符串,能够允许嵌入表达式的字符串字面量,嵌入${expression}即可</p></li><li><p>标签函数标签函数 会接收被插值记号分隔后的模板和对每个表达式求值的结果。 标签函数本身是一个常规函数,通过前缀到模板字面量来应用自定义行为。</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">let</span> a <span class="token operator">=</span> <span class="token number">6</span><span class="token punctuation">;</span> <span class="token keyword">let</span> b <span class="token operator">=</span> <span class="token number">9</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">simpleTag</span><span class="token punctuation">(</span><span class="token parameter">strings<span class="token punctuation">,</span> <span class="token operator">...</span>expressions</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>strings<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">const</span> expression <span class="token keyword">of</span> expressions<span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>expression<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token string">'foobar'</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">let</span> taggedResult <span class="token operator">=</span> simpleTag<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span> a <span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> + </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span> b <span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> = </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span> a <span class="token operator">+</span> b <span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span> <span class="token comment">// ["", " + ", " = ", ""] 字符串数组</span><span class="token comment">// 6 </span><span class="token comment">// 9 </span><span class="token comment">// 15 </span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>taggedResult<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// "foobar" </span></code></pre></li><li><p>用模板字面量也可以直接获取原始的模板字面量内容。在标签函数的第一个参数中,存在一个特殊的属性<code>raw</code>,其他地方无法对字符串数组使用。</p></li></ul></li><li><p>Symbol类型:唯一标识符,具有唯一性、隐藏性(用作对象属性名时无法通过object.key访问,而需要定制的object.getOwnPropertySymbols()方法得到对象中所有用作属性名的symbol)</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">let</span> id1 <span class="token operator">=</span> <span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token string">'id'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">let</span> id2 <span class="token operator">=</span> <span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token string">'id'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>id1<span class="token operator">===</span>id2<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//false</span><span class="token keyword">let</span> id3 <span class="token operator">=</span> Symbol<span class="token punctuation">.</span><span class="token function">for</span><span class="token punctuation">(</span><span class="token string">'id'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>id1<span class="token operator">===</span>id3<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//false</span><span class="token keyword">let</span> id4 <span class="token operator">=</span>Symbol<span class="token punctuation">.</span><span class="token function">for</span><span class="token punctuation">(</span><span class="token string">'id'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>id3<span class="token operator">===</span>id4<span class="token punctuation">)</span><span class="token comment">//true</span></code></pre><p>全局注册并登记,使得相同参数注册的值symbol相等。前提是都通过for注册登记。</p></li></ul><p>数字0,空字符串,NaN,空指针null,undefined都可以自动转化为false</p><p>null 其实属于自己的类型 Null,而不属于Object类型,typeof 之所以会判定为 Object 类型,是因为JavaScript 数据类型在底层都是以二进制的形式表示的,二进制的前三位为 0 会被 typeof 判断为对象类型,而 null 的二进制位恰好都是 0 ,因此,null 被误判断为 Object 类型。 <strong>对象被赋值了null 以后,对象对应的堆内存中的值就是游离状态了,GC 会择机回收该值并释放内存。</strong>因此,<strong>需要释放某个对象,就将变量设置为 null,即表示该对象已经被清空,目前无效状态。</strong></p><h2 id="基础语句"><a href="#基础语句" class="headerlink" title="基础语句"></a>基础语句</h2><p>==运算符会做强制类型转换===不会,单引号双引号和python一样,都可以用来包裹字符串,无区别。</p><p>typeof 操作符,返回其后变量或字面量的类型</p><p>+ 能做数字间的加减运算,当任一对象为字符串时会把另一参加运算对象转化为字符串再进行字符串拼接,参与运算对象为 object 或其他类型时会先转换为字符串再按如上规则运算</p><ul><li><p>try{}catch{}finally{}</p><p>1.try中有return, 会先将值暂存,无论finally语句中对该值做什么处理,最终返回的都是try语句中的暂存值。</p><p>2.当try与finally语句中均有return语句,会忽略try中return。</p></li></ul><h3 id="空值合并运算符"><a href="#空值合并运算符" class="headerlink" title="空值合并运算符"></a>空值合并运算符</h3><p><strong>空值合并操作符</strong>(**<code>??</code>**)是一个逻辑操作符,当左侧的操作数为 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/null"><code>null</code></a> 或者 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/undefined"><code>undefined</code></a> 时,返回其右侧操作数,否则返回左侧操作数。</p><p>与[逻辑或操作符(<code>||</code>)不同,逻辑或操作符会在左侧操作数为<a href="https://developer.mozilla.org/zh-CN/docs/Glossary/Falsy">假值</a>时返回右侧操作数。也就是说,如果使用 <code>||</code> 来为某些变量设置默认值,可能会遇到意料之外的行为。比如为假值(例如,<code>''</code> 或 <code>0</code>)时。</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">const</span> foo <span class="token operator">=</span> <span class="token keyword">null</span> <span class="token operator">??</span> <span class="token string">'default string'</span><span class="token punctuation">;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>foo<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// expected output: "default string"</span><span class="token keyword">const</span> baz <span class="token operator">=</span> <span class="token number">0</span> <span class="token operator">??</span> <span class="token number">42</span><span class="token punctuation">;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>baz<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// expected output: 0</span><span class="token keyword">const</span> baz <span class="token operator">=</span> <span class="token number">0</span> <span class="token operator">||</span> <span class="token number">42</span><span class="token punctuation">;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>baz<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// expected output: 42</span></code></pre><p>逻辑空赋值 ??=</p><p>x ??= y ,x为null或undefined时才赋值为右值。</p><h3 id="可选链操作符"><a href="#可选链操作符" class="headerlink" title="可选链操作符"></a>可选链操作符</h3><p>?.TS中遇到过</p><p>判断是否为空</p><h3 id="解构赋值"><a href="#解构赋值" class="headerlink" title="解构赋值"></a>解构赋值</h3><p>ES6 </p><ul><li><p>数组结构赋值:</p><p>只要某种数据结构具有 Iterator 接口,都可以采用数组形式的解构赋值。</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">let</span> <span class="token punctuation">[</span>a<span class="token operator">=</span><span class="token number">1</span><span class="token punctuation">,</span>b<span class="token operator">=</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token operator">=</span><span class="token punctuation">[</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">]</span></code></pre></li><li><p>对象解构赋值:</p><p>注意loc: { start }和loc: start是不一样的,前者把start也作为模式串,而后者只有loc是模式串</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">const</span> node <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">loc</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">start</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">line</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token literal-property property">column</span><span class="token operator">:</span> <span class="token number">5</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">;</span><span class="token keyword">let</span> <span class="token punctuation">{</span> loc<span class="token punctuation">,</span> <span class="token literal-property property">loc</span><span class="token operator">:</span> <span class="token punctuation">{</span> start <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">loc</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">start</span><span class="token operator">:</span> <span class="token punctuation">{</span> line <span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token operator">=</span> node<span class="token punctuation">;</span>line <span class="token comment">// 1</span>loc <span class="token comment">// Object {start: Object}</span>start <span class="token comment">// Object {line: 1, column: 5}</span></code></pre><p>默认值,生效的条件是,对象的属性值严格等于<code>undefined</code>。</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> <span class="token punctuation">{</span>x <span class="token operator">=</span> <span class="token number">3</span><span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token literal-property property">x</span><span class="token operator">:</span> <span class="token keyword">undefined</span><span class="token punctuation">}</span><span class="token punctuation">;</span>x <span class="token comment">// 3var </span><span class="token punctuation">{</span>x <span class="token operator">=</span> <span class="token number">3</span><span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token literal-property property">x</span><span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">}</span><span class="token punctuation">;</span>x <span class="token comment">// null</span></code></pre><p>由于数组本质是特殊的对象,因此可以对数组进行对象属性的解构。</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">let</span> arr <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token keyword">let</span> <span class="token punctuation">{</span><span class="token number">0</span> <span class="token operator">:</span> first<span class="token punctuation">,</span> <span class="token punctuation">[</span>arr<span class="token punctuation">.</span>length <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">:</span> last<span class="token punctuation">}</span> <span class="token operator">=</span> arr<span class="token punctuation">;</span><span class="token comment">//index</span>first <span class="token comment">// 1</span>last <span class="token comment">// 3</span></code></pre></li></ul><h2 id="常用方法"><a href="#常用方法" class="headerlink" title="常用方法"></a>常用方法</h2><h3 id="forEach"><a href="#forEach" class="headerlink" title="forEach"></a>forEach</h3><pre class="language-none"><code class="language-none">// 箭头函数forEach(() => { /* … */ } )forEach((value) => { /* … */ } )forEach((value, key) => { /* … */ } )forEach((value, key, map) => { /* … */ } )// 回调函数forEach(callbackFn)forEach(callbackFn, thisArg)// 内联回调函数forEach(function() { /* … */ })forEach(function(value) { /* … */ })forEach(function(value, key) { /* … */ })forEach(function(value, key, map) { /* … */ })forEach(function(value, key, map) { /* … */ }, thisArg)</code></pre><h2 id="Map和Set"><a href="#Map和Set" class="headerlink" title="Map和Set"></a>Map和Set</h2><ul><li>一个 Object 的键只能是字符串或者 Symbols,但一个 Map 的键可以是任意值。</li><li>Map 的键值对个数可以从 size 属性获取,而 Object 的键值对个数只能手动计算。</li></ul><p>Set 对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用。重复值的元素会被略去。</p><pre class="language-none"><code class="language-none">Set.prototype.add(value)在Set对象尾部添加一个元素。返回该 Set 对象Set.prototype.delete(value)移除值为 value 的元素,并返回一个布尔值来表示是否移除成功。Set.prototype.has(value) 会在此之后返回 false。Set.prototype.has(value)返回一个布尔值,表示该值在 Set 中存在与否。Set.prototype.clear()移除Set对象内的所有元素。Set.prototype.forEach(callbackFn[, thisArg])按照插入顺序,为 Set 对象中的每一个值调用一次 callBackFn。如果提供了thisArg参数,回调中的 this 会是这个参数。Set.prototype.values()返回一个新的迭代器对象,该对象包含 Set 对象中的按插入顺序排列的所有元素的值。</code></pre><p>let newArray = Array.from(set),可以把括号内的对象转换为array并返回</p><pre class="language-none"><code class="language-none">Map.prototype.size返回 Map 对象中的键值对数量。Map.prototype.get(key)返回与 key 关联的值,若不存在关联的值,则返回 undefined。Map.prototype.has(key)返回一个布尔值,用来表明 Map 对象中是否存在与 key 关联的值。Map.prototype.set(key, value)在 Map 对象中设置与指定的键 key 关联的值 value,并返回 Map 对象。Map.prototype.delete(key)移除 Map 对象中指定的键值对,如果键值对存在并成功被移除,返回 true,否则返回 false。调用 delete 后再调用 Map.prototype.has(key) 将返回 false。</code></pre><h3 id="WeakMap"><a href="#WeakMap" class="headerlink" title="WeakMap"></a>WeakMap</h3><p><strong><code>WeakMap</code></strong> 对象是一组键/值对的集合,其中的键是弱引用的。其键必须是对象,而值可以是任意的。</p><p>map API <em>可以</em> 通过使其四个 API 方法共用两个数组(一个存放键,一个存放值)来实现。给这种 map 设置值时会同时将键和值添加到这两个数组的末尾。从而使得键和值的索引在两个数组中相对应。当从该 map 取值的时候,需要遍历所有的键,然后使用索引从存储值的数组中检索出相应的值。</p><p>但是存在两个缺点:</p><ol><li>首先赋值和搜索操作都是 <em>O(*n</em>)* 的时间复杂度(<em>n</em> 是键值对的个数),因为这两个操作都需要遍历全部整个数组来进行匹配。</li><li>另外一个缺点是可能会导致内存泄漏,因为数组会一直引用着每个键和值。这种引用使得垃圾回收算法不能回收处理他们,即使没有其他任何引用存在了。</li></ol><p>相比之下,原生的 <code>WeakMap</code> 持有的是每个键对象的“弱引用”,这意味着在没有其他引用存在时垃圾回收能正确进行。原生 <code>WeakMap</code> 的结构是特殊且有效的,其用于映射的 key _只有_在其没有被回收时才是有效的。</p><p><strong>正由于这样的弱引用,<code>WeakMap</code> 的 key 是不可枚举的</strong>(没有方法能给出所有的 key)。如果 key 是可枚举的话,其列表将会受垃圾回收机制的影响,从而得到不确定的结果。因此,如果你想要这种类型对象的 key 值的列表,你应该使用 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Map"><code>Map</code></a>。</p><ul><li><p><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/WeakMap/delete"><code>WeakMap.prototype.delete(key)</code></a></p><p>删除 WeakMap 中与 <code>key</code> 相关联的值。删除之后, <code>WeakMap.prototype.has(key)</code> 将会返回 <code>false</code>。</p></li><li><p><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/WeakMap/get"><code>WeakMap.prototype.get(key)</code></a></p><p>返回 WeakMap 中与 <code>key</code> 相关联的值,如果 <code>key</code> 不存在则返回 <code>undefined</code>。</p></li><li><p><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/WeakMap/has"><code>WeakMap.prototype.has(key)</code></a></p><p>返回一个布尔值,断言一个值是否已经与 <code>WeakMap</code> 对象中的 <code>key</code> 关联。</p></li><li><p><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/WeakMap/set"><code>WeakMap.prototype.set(key, value)</code></a></p><p>给 <code>WeakMap</code> 中的 <code>key</code> 设置一个 <code>value</code>。该方法返回一个 <code>WeakMap</code> 对象。</p></li></ul><h2 id="数组"><a href="#数组" class="headerlink" title="数组"></a>数组</h2><pre class="language-none"><code class="language-none">pop()删除末尾元素 ,返回移除的数组元素;push(ele)末尾添加元素 ele,返回添加后数组的长度;shift()删除首元素并移动数组位置 ,返回添加后数组的长度;unshift(ele)在数组首位置添加元素ele,返回添加后数组的长度;shift() 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值。unshift方法unshift() 方法将一个或多个元素添加到数组的开头,并返回该数组的新长度(该方法修改原有数组)arr.unshift(element1, ..., elementN)返回其 length 属性值Array.isArray(val):判断val是不是数组Array.prototype 属性表示 Array 构造函数的原型,并允许向所有Array对象添加新的属性和方法。或者说,允许利用prototype向任何对象添加属性和方法,从而应用到对象的所有实例上</code></pre><h3 id="遍历操作"><a href="#遍历操作" class="headerlink" title="遍历操作"></a>遍历操作</h3><p>最常用for (var i = 0; i < a.length; i++) {<br> // Do something with a[i]<br>}</p><p>for (. of array):for (const currentValue of a) {// Do something with currentValue}</p><p>for(. in array):for (var i in a) {// 操作 a[i]}遍历索引,如果直接向 Array.prototype 添加了新的属性,使用这样的循环这些属性也同样会被遍历。不推荐这个循环</p><p>forEach():<br>array.forEach(function(currentValue, index, array) {// 操作 currentValue 或者 array[index]});</p><p>注: forEach() 对于空数组是不会执行回调函数的。</p><h3 id="Array-prototype-at"><a href="#Array-prototype-at" class="headerlink" title="Array.prototype.at()"></a><a href="https://link.segmentfault.com/?enc=gIfegOUoZxxLBOg/nmpAvw==.it+TiWVsG0Y95ewedhlKoMS2CPXZSbhECA0MBePgVHbbS3pnn4r95vxFQo8Wnk+rFcIZQbnMXjwFeEBW9uTMx/mnhkJ0ck8W/V9MIZGB4SZb5GqmV1RLVPtXvNkMw7kq">Array.prototype.at()</a></h3><ul><li>返回at中参数指向的index的数组元素,支持负数</li></ul><h3 id="array-prototype-concat"><a href="#array-prototype-concat" class="headerlink" title="array.prototype.concat()"></a>array.prototype.concat()</h3><p>拼接两个数组</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token function">concat</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token function">concat</span><span class="token punctuation">(</span>value0<span class="token punctuation">)</span><span class="token function">concat</span><span class="token punctuation">(</span>value0<span class="token punctuation">,</span> value1<span class="token punctuation">)</span><span class="token function">concat</span><span class="token punctuation">(</span>value0<span class="token punctuation">,</span> value1<span class="token punctuation">,</span> <span class="token comment">/* … ,*/</span> valueN<span class="token punctuation">)</span></code></pre><p><code>valueN</code> 可选</p><p>数组和/或值,将被合并到一个新的数组中。如果省略了所有 <code>valueN</code> 参数,则 <code>concat</code> 会返回调用此方法的现存数组的一个浅拷贝。详情请参阅下文描述。</p><h3 id="array-indexOf"><a href="#array-indexOf" class="headerlink" title="array.indexOf"></a>array.indexOf</h3><ul><li>判断数组中是否存在某个值,如果存在返回数组元素的下标,否则返回-1</li></ul><h3 id="array-includes-searchElement-fromIndex"><a href="#array-includes-searchElement-fromIndex" class="headerlink" title="array.includes(searchElement[, fromIndex])"></a>array.includes(searchElement[, fromIndex])</h3><ul><li>判断一个数组是否包含一个指定的值,如果存在返回 true,否则返回false。</li></ul><h3 id="reduce-方法"><a href="#reduce-方法" class="headerlink" title="reduce()方法"></a>reduce()方法</h3><p><strong><code>reduce()</code></strong> 方法对数组中的每个元素按序执行一个由您提供的 <strong>reducer</strong> 函数,每一次运行 <strong>reducer</strong> 会将先前元素的计算结果作为参数传入,最后将其结果汇总为单个返回值。</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript">array<span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">total<span class="token punctuation">,</span>currentValue<span class="token punctuation">,</span><span class="token punctuation">[</span>currentIndex<span class="token punctuation">,</span><span class="token punctuation">[</span>arr<span class="token punctuation">]</span><span class="token punctuation">]</span></span><span class="token punctuation">)</span><span class="token punctuation">,</span><span class="token punctuation">[</span>initialValue<span class="token punctuation">]</span><span class="token punctuation">)</span></code></pre><p>reduce() 方法接收一个回调函数作为参数,reduce 为数组中的每一个元素依次执行回调函数,回调函数接受四个参数:初始值(或者上一次回调函数的返回值),当前元素值,当前索引,调用 reduce 的数组。<br>reduce方法的返回值为回调函数最后的返回值。</p><p>如果没有提供initialValue,那么reduce的第一轮回调函数中的“total”就arr[0],“current_Value”就是arr[1],index就是1;</p><p>如果提供initialValue,那么reduce的第一轮回调函数中的“total”就是initialValue,“current_Value”就是arr[0],index就是0。</p><p>所以在使用reduce函数时,回调函数中return最好不要省,而且initialValue也最好不要省!!!</p><h3 id="filter-方法"><a href="#filter-方法" class="headerlink" title="filter() 方法"></a>filter() 方法</h3><p>返回一个新数组,其包含通过所提供函数实现的测试的所有元素。 </p><p>var newArray = arr.filter(callback(element[, index[, array]])[, thisArg])</p><p>上式中 element 必需,后三者都可选,但没传 index 则 array 也不能传</p><p>注:当所过滤的数组是对象数组的情况时,对新返回的数组元素属性做出修改,同时对原数组也会造成影响;当过滤数组为纯数组时,修改不会改变原数组。也就是浅拷贝</p><h3 id="from方法"><a href="#from方法" class="headerlink" title="from方法"></a>from方法</h3><p>Array.from(arrayLike[, mapFn[, thisArg]])参数分别为伪数组对象或可迭代对象,新数组中的每个元素会执行的回调函数,执行回调函数 mapFn 时 this 对象<br>返回一个新的数组实例。</p><p>Array.from(arrayLike[, mapFunction[, thisArg]]):arrayLike:必传参数,想要转换成数组的伪数组对象或可迭代对象。<br>mapFunction:可选参数,mapFunction(item,index){…} 是在集合中的每个项目上调用的函数。返回的值将插入到新集合中。<br>thisArg:可选参数,执行回调函数 mapFunction 时 this 对象。这个参数很少使用。</p><h3 id="array-map-方法"><a href="#array-map-方法" class="headerlink" title="array.map() 方法"></a>array.map() 方法</h3><p>返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值,按照原始数组元素顺序依次处理元素。<br>array_back=array.map(function(currentValue,index,arr), thisValue)</p><p>注:map()方法不会对空数组进行检测;也不会改变原数组</p><p>eg.let arr = new Array( 2 ).fill( 0 ).map( _ => new Array( 3 ) ); //作用类似C语言:int arr[2][3]</p><h3 id="arr-slice-begin-end"><a href="#arr-slice-begin-end" class="headerlink" title="arr.slice([begin[, end]])"></a>arr.slice([begin[, end]])</h3><ul><li><code>begin</code> 可选,可为负。如果 <code>begin</code> 大于<a href="https://so.csdn.net/so/search?q=%E6%95%B0%E7%BB%84&spm=1001.2101.3001.7020">数组</a>长度,返回空数组。slice(-1) 提取最后一个元素,slice(-2)提取最后两个元素,依次类推。前包后不包。<br><a href="https://so.csdn.net/so/search?q=slice&spm=1001.2101.3001.7020">slice</a>() 返回整个数组。</li></ul><h3 id="array-splice-start-deleteCount-item1-item2-…"><a href="#array-splice-start-deleteCount-item1-item2-…" class="headerlink" title="array.splice(start[, deleteCount[, item1[, item2[, …]]]])"></a>array.splice(start[, deleteCount[, item1[, item2[, …]]]])</h3><ul><li>start 指定修改的开始位置(从 0 计数)。如果超出了数组的长度,则从数组末尾开始添加内容;如果是负值,则表示从数组末位开始的第几位(从 -1 计数,这意味着 -n 是倒数第 n 个元素并且等价于 <code>array.length-n</code>);如果负数的绝对值大于数组的长度,则表示开始位置为第 0 位。</li><li>deleteCount :整数,表示要移除的数组元素的个数。如果 <code>deleteCount</code> 大于 <code>start</code> 之后的元素的总数,则从 <code>start</code> 后面的元素都将被删除(含第 <code>start</code> 位)。如果 <code>deleteCount</code> 被省略了,或者它的值大于等于<code>array.length - start</code>(也就是说,如果它大于或者等于<code>start</code>之后的所有元素的数量),那么<code>start</code>之后数组的所有元素都会被删除。如果 <code>deleteCount</code> 是 0 或者负数,则不移除元素。这种情况下,至少应添加一个新元素。</li><li>item:从start位置要添加进数组的元素,不指定时 splice 将只删除元素。</li></ul><p>返回被删除的元素</p><h3 id="arr-sort-compareFn"><a href="#arr-sort-compareFn" class="headerlink" title="arr.sort([compareFn])"></a>arr.sort([compareFn])</h3><p>如果没有指明 <code>compareFn</code> ,那么元素会按照转换为的字符串的诸个字符的 Unicode 位点进行排序。例如 “Banana” 会被排列到 “cherry” 之前。当数字按由小到大排序时,9 出现在 80 之前,但因为(没有指明 <code>compareFn</code>),比较的数字会先被转换为字符串,所以在 Unicode 顺序上 “80” 要比 “9” 要靠前。</p><ul><li>如果 <code>compareFn(a, b)</code> 大于 0 , b 会被排列到 a 之前。</li><li>如果 <code>compareFn(a, b)</code> 小于 0 ,那么 a 会被排列到 b 之前;</li><li>如果 <code>compareFn(a, b)</code> 等于 0 , a 和 b 的相对位置不变。备注: ECMAScript 标准并不保证这一行为,而且也不是所有浏览器都会遵守(例如 Mozilla 在 2003 年之前的版本);</li><li><code>compareFn(a, b)</code> 必须总是对相同的输入返回相同的比较结果,否则排序的结果将是不确定的。</li></ul><h3 id="strArr-join-separator"><a href="#strArr-join-separator" class="headerlink" title="strArr.join(separator)"></a>strArr.join(separator)</h3><ul><li>用输入参数分隔输入字符串数组的每个元素,返回新字符串</li></ul><h2 id="字符串"><a href="#字符串" class="headerlink" title="字符串"></a>字符串</h2><p>可以直接用比较符号比较字符串</p><h3 id="编码"><a href="#编码" class="headerlink" title="编码"></a>编码</h3><p>escape-unescape方法不会对 ASCII 字母和数字进行编码,也不会对下面这些 ASCII 标点符号进行编码: * @ - _ + . / 。其他所有的字符都会被转义序列替换。</p><p>encodeURI-decodeURI对以下在 URI 中具有特殊含义的 ASCII 标点符号,encodeURI() 函数是不会进行转义的: , / ? : @ & = + $ # </p><p>encodeURIComponent-decodeURIComponent该方法不会对 ASCII 字母和数字进行编码,也不会对这些 ASCII 标点符号进行编码: - _ . ! ~ * ‘ ( ) 。其他字符(比如 :;/?:@&=+$,# 这些用于分隔 URI 组件的标点符号),都是由一个或多个十六进制的转义序列替换的。</p><p><strong>1、如果只是<a href="https://www.zhihu.com/search?q=%E7%BC%96%E7%A0%81%E5%AD%97%E7%AC%A6%E4%B8%B2&search_source=Entity&hybrid_search_source=Entity&hybrid_search_extra=%7B%22sourceType%22:%22answer%22,%22sourceId%22:20300871%7D">编码字符串</a>,不和URL有半毛钱关系,那么用escape。</strong></p><p><strong>2、如果你需要编码整个URL,然后需要使用这个URL,那么用encodeURI。</strong></p><p>比如</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token function">encodeURI</span><span class="token punctuation">(</span><span class="token string">"http://www.cnblogs.com/season-huang/some other thing"</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>编码后会变为</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token string">"http://www.cnblogs.com/season-huang/some%20other%20thing"</span><span class="token punctuation">;</span></code></pre><p>其中,空格被编码成了%20。但是如果你用了encodeURIComponent,那么结果变为</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token string">"http%3A%2F%2Fwww.cnblogs.com%2Fseason-huang%2Fsome%20other%20thing"</span></code></pre><p>看到了区别吗,连 “/“ 都被编码了,整个URL已经没法用了。</p><p><strong>3、当你需要编码URL中的参数的时候,那么encodeURIComponent是最好方法。</strong></p><h3 id="String-prototype-charAt-index"><a href="#String-prototype-charAt-index" class="headerlink" title="String.prototype.charAt(index)"></a>String.prototype.charAt(index)</h3><p>指定 <code>index</code> 处字符,参数不在 0 和字符串的 length-1 之间,则返回空字符串</p><h3 id="String-prototype-charCodeAt-index"><a href="#String-prototype-charCodeAt-index" class="headerlink" title="String.prototype.charCodeAt(index)"></a>String.prototype.charCodeAt(index)</h3><p>index:一个大于等于 <code>0</code>,小于字符串长度的整数。如果不是一个数值,则默认为 <code>0</code>。</p><p>返回值:指定 <code>index</code> 处字符的 UTF-16 代码单元值的一个数字;如果 <code>index</code> 超出范围,<code>charCodeAt()</code> 返回 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/NaN"><code>NaN</code></a>。</p><p>如果指定的 <code>index</code> 小于 <code>0</code> 、等于或大于字符串的长度,则 <code>charCodeAt</code> 返回 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/NaN"><code>NaN</code></a>。</p><h3 id="String-fromCharCode"><a href="#String-fromCharCode" class="headerlink" title="String.fromCharCode()"></a>String.fromCharCode()</h3><p>静态 <strong><code>String.fromCharCode()</code></strong> 方法返回由指定的 UTF-16 代码单元序列创建的字符串。</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript">String<span class="token punctuation">.</span><span class="token function">fromCharCode</span><span class="token punctuation">(</span>str<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">charCodeAt</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">+</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre><h3 id="indexOf-和-lastIndexOf"><a href="#indexOf-和-lastIndexOf" class="headerlink" title="indexOf() 和 lastIndexOf()"></a>indexOf() 和 lastIndexOf()</h3><p>使用字符串的 indexOf() 和 lastIndexOf() 方法,可以根据参数字符串,返回指定子字符串的下标位置。这两个方法都有两个参数,说明如下。</p><ul><li>第一个参数为一个子字符串,指定要查找的目标。</li><li>第二个参数为一个整数,指定查找的起始位置,取值范围是 0~length-1。</li></ul><p>对于第二个参数来说,需要注意一下几个特殊情况。</p><ul><li>如果值为负数,则视为 0,相当于从第一个字符开始查找。</li><li>如果省略了这个参数,也将从字符串的第一个字符开始查找。</li><li>如果值大于等于 length 属性值,则视为当前字符串中没有指定的子字符串,返回 -1。</li></ul><h3 id="str-match-reg"><a href="#str-match-reg" class="headerlink" title="str.match(reg)"></a>str.match(reg)</h3><p>/./g</p><p>方法对字符串对象进行检索,返回包含所有匹配结果的数组。而 正则表达式 /./g 匹配的是所有的字符, 所以str.match(/./g)返回的是由字符串str中所有的字符组成的数组,以此达到将字符串转换为数组的目的。 </p><h3 id="str-replace-pattern-replacement"><a href="#str-replace-pattern-replacement" class="headerlink" title="str.replace(pattern, replacement)"></a>str.replace(pattern, replacement)</h3><p>两个参数均为字符串,寻找到模式串替换为后者。</p><h3 id="str-search-regexp"><a href="#str-search-regexp" class="headerlink" title="str.search(regexp)"></a>str.search(regexp)</h3><p>返回 str 中给定正则表达式对应索引</p><h3 id="str-slice-a-b"><a href="#str-slice-a-b" class="headerlink" title="str.slice(a,b)"></a>str.slice(a,b)</h3><p>前包后不包;截取出来的字符串的长度为第二个参数与第一个参数之间的差;若参数值为负数,则将该值加上字符串长度后转为正值;若第一个参数等于大于第二个参数,则返回空字符串.</p><h3 id="str-substring-a-b"><a href="#str-substring-a-b" class="headerlink" title="str.substring(a,b)"></a>str.substring(a,b)</h3><p>前包后不包;若参数值为负数,则将该值转为0;两个参数中,取较小值作为开始位置,截取出来的字符串的长度为较大值与较小值之间的差.</p><h3 id="str-split-separator"><a href="#str-split-separator" class="headerlink" title="str.split(separator)"></a>str.split(separator)</h3><p>分割字符串,返回字符数组</p><h3 id="str-substr-a-length"><a href="#str-substr-a-length" class="headerlink" title="str.substr(a,length)"></a>str.substr(a,length)</h3><p>第一个参数代表开始位置,第二个参数代表截取的长度</p><h2 id="函数"><a href="#函数" class="headerlink" title="函数"></a>函数</h2><h3 id="基础-1"><a href="#基础-1" class="headerlink" title="基础"></a>基础</h3><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> <span class="token function-variable function">avg</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token operator"><=</span><span class="token operator">></span><span class="token keyword">function</span> <span class="token function">avg</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token comment">//js创建函数有两种:一是函数声明function fnName () {…};,二是函数表达式var fnName = function () {…};前者因 js 具有 函数声明提升 所以定义在任何位置均可成功调用,而后者必须等到定义语句被解释后才能正常调用(与 var 的变量定义提升不同)</span><span class="token comment">//还有一种匿名函数:function () {…}; 使用function关键字声明一个函数,但未给函数命名,所以叫匿名函数,匿名函数属于函数表达式,匿名函数有很多作用,赋予一个变量则创建函数,赋予一个事件则成为事件处理程序或创建闭包等等。</span>函数表达式后面可以加括号立即调用该函数,<span class="token operator">*</span><span class="token function">函数声明不可以,只能以fnName</span><span class="token punctuation">(</span><span class="token punctuation">)</span>形式调用<span class="token operator">*</span> 存疑,在控制台中调用成功。是因为在函数定义前面加了运算符,比如用括号包裹,把它也转换为了表达式。<span class="token function">总结一下就是当把函数定义为表达式时总能在后面加上括号来立即调用。</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token function">a</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">var</span> <span class="token function-variable function">a</span><span class="token operator">=</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">(</span><span class="token punctuation">)</span> 三者均能立即调用。</code></pre><p>由 <code>Function</code> 构造函数创建的函数不会创建当前环境的闭包,它们总是被创建于全局环境,因此在运行时它们只能访问全局变量和自己的局部变量,不能访问它们被 <code>Function</code> 构造函数创建时所在的作用域的变量。这一点与使用 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/eval"><code>eval()</code></a> 执行创建函数的代码不同。</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">let</span> a <span class="token operator">=</span> <span class="token number">1</span><span class="token keyword">function</span> <span class="token function">foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>a<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token keyword">function</span> <span class="token function">too</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> a <span class="token operator">=</span> <span class="token number">2</span> <span class="token function">foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token function">too</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 1, not 2</span></code></pre><pre class="language-python" data-language="python"><code class="language-python"><span class="token keyword">lambda</span> x<span class="token punctuation">:</span> x <span class="token operator">*</span> <span class="token number">8</span>let ans<span class="token operator">=</span>x <span class="token operator">=</span><span class="token operator">></span> x<span class="token operator">*</span><span class="token number">8</span><span class="token punctuation">;</span></code></pre><p>js的=>符号类似于lambda</p><pre class="language-none"><code class="language-none">=>是es6中的arrow function语法(x) => x + 6相当于function(x){return x + 6;};const funcname=(args)=>{...}函数调用:funcname(args)</code></pre><p>eval()函数,参数是一个字符串。如果字符串表示的是表达式,<code>eval()</code> 会对表达式进行求值。如果参数表示一个或多个 JavaScript 语句,那么<code>eval()</code> 就会执行这些语句。如果 <code>eval()</code> 的参数不是字符串, <code>eval()</code> 会将参数原封不动地返回。</p><p>永远不要使用eval()</p><h3 id="回调"><a href="#回调" class="headerlink" title="回调"></a>回调</h3><p>嵌套函数可以访问父函数作用域中的变量,可以利用这个特性减少全局变量的数量,有效地防止“污染”你的全局命名空间——你可以称它为“局部全局(local global)”。换种思路,把全局当作整体函数,那么就能形成作用域链(scope chain),嵌套者能访问被嵌套者的变量,反之则不行,寻找变量的定义时总是从当前嵌套层或者说从金字塔的当前区域往外(往下)寻找,就近选择。需要注意的是每个函数的金字塔是不同的,在该函数被定义的时候就已经确定了,所以当在函数内部调用之前已定义的函数时,应当回到那个函数的“金字塔”寻找其所需要的变量,当前函数的作用域不会与产生交集。</p><p>头等函数(first-class functions),可以当作参数被传递的函数。回调函数(callback)是被作为参数传递的函数,注意是函数作为参数,而非函数返回值作为参数,与其对应的是高阶函数,是使用回调函数的函数。</p><p>回调机制包括三方:起始函数,中间函数,回调函数;起始函数调用中间函数,把回调函数作为参数传递给中间函数。起始函数一般是当前运行的主函数,一般隐藏忽略,主要关注回调函数和把回调函数作为参数的中间函数。</p><p>回调实际上有两种:阻塞式回调和延迟式回调。两者的区别在于:阻塞式回调里,回调函数的调用一定发生在起始函数返回之前;而延迟式回调里,回调函数的调用有可能是在起始函数返回之后。</p><h3 id="call、apply和bind"><a href="#call、apply和bind" class="headerlink" title="call、apply和bind"></a>call、apply和bind</h3><p><code>myfunc(...args)<=>myfunc.apply(null,args)</code>展开语法将数组展开为数组元素。<strong>剩余参数</strong>语法允许我们将一个不定数量的参数表示为一个数组,与展开语法恰恰相反,形式为定义函数时<code>function fun1(...theArgs){alert(theArgs.length);}</code>。剩余参数也可以被解构为包含变量,形式为<code>function f(...[a, b, c]) {return a + b + c;}</code>. </p><p><code>apply()</code> 的第一个参数应该是一个被当作 <code>this</code> 来看待的对象。于是这里是全局对象。</p><p><code>apply()</code> 有一个姐妹函数,名叫 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/call"><code>call</code></a>,它也可以允许你设置 <code>this</code>,但它带有一个扩展的参数列表而不是一个数组。</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">function</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>thisArg<span class="token punctuation">,</span> arg1<span class="token punctuation">,</span> arg2<span class="token punctuation">,</span> <span class="token operator">...</span><span class="token punctuation">)</span></code></pre><p>thisArg是函数执行时的 this 对象。call 实现</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token class-name">Function</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">myCall</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">context<span class="token punctuation">,</span><span class="token operator">...</span>args</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 判断调用对象</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> <span class="token keyword">this</span> <span class="token operator">!==</span> <span class="token string">"function"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">"Type error"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">let</span> result <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token comment">// 判断 context 是否传入,如果没有传就设置为 window</span> context <span class="token operator">=</span> context <span class="token operator">||</span> window<span class="token punctuation">;</span>args <span class="token operator">=</span> args <span class="token operator">?</span> args <span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token keyword">const</span> key <span class="token operator">=</span> <span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> context<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">;</span><span class="token comment">//通过隐式绑定的方式调用函数</span> result <span class="token operator">=</span> context<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token operator">...</span>args<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 删除手动增加的属性方法</span> <span class="token keyword">delete</span> context<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment">// 将执行结果返回</span> <span class="token keyword">return</span> result<span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre><p>类似的apply实现</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token class-name">Function</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">myApply</span><span class="token operator">=</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">context<span class="token punctuation">,</span>args</span><span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> <span class="token keyword">this</span> <span class="token operator">!==</span> <span class="token string">"function"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">"Type error"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> args <span class="token operator">=</span> args <span class="token operator">?</span> args <span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">const</span> key <span class="token operator">=</span> <span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> context<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token operator">=</span><span class="token keyword">this</span><span class="token punctuation">;</span> <span class="token keyword">const</span> result <span class="token operator">=</span> context<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token operator">...</span>args<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">delete</span> context<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">return</span> result<span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><p>bind先返回一个绑定了this的函数,再次执行则在this中执行</p><pre class="language-none"><code class="language-none">var a ={name : "Cherry",fn : function (a,b) {console.log( a + b)}}var b = a.fn;b.bind(a,1,2)() // 3</code></pre><p>bind利用apply实现</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token class-name">Function</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">myBind</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">context<span class="token punctuation">,</span> <span class="token operator">...</span>args</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> fn <span class="token operator">=</span> <span class="token keyword">this</span> args <span class="token operator">=</span> args <span class="token operator">?</span> args <span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token keyword">return</span> <span class="token keyword">function</span> <span class="token function">newFn</span><span class="token punctuation">(</span><span class="token parameter"><span class="token operator">...</span>newFnArgs</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span> <span class="token keyword">instanceof</span> <span class="token class-name">newFn</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">fn</span><span class="token punctuation">(</span><span class="token operator">...</span>args<span class="token punctuation">,</span> <span class="token operator">...</span>newFnArgs<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token function">fn</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span>context<span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token operator">...</span>args<span class="token punctuation">,</span><span class="token operator">...</span>newFnArgs<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><h3 id="函数柯里化"><a href="#函数柯里化" class="headerlink" title="函数柯里化"></a>函数柯里化</h3><p>将接受 <strong>n 个参数的 1 个函数改为只接受一个参数的 n 个互相嵌套的函数</strong>,当前置部分参数一致时,可以通过固定前置参数生成指定函数,简化代码。</p><p>对应偏函数是柯里化的宽松情况,不一定需要每一层都只固定一个参数,继承思想即可。</p><h3 id="函数参数的传递"><a href="#函数参数的传递" class="headerlink" title="函数参数的传递"></a>函数参数的传递</h3><p>有值传递和引用传递,基本类型传递值,引用类型(对象)传递对象的地址,如果在函数中对对象重新赋值,则传递进来的地址改变,即在堆中重新分配一段空间,改变传递进来地址的值指向这个新的地址,不影响原对象。</p><pre class="language-none"><code class="language-none">function changeAgeAndReference(person) { person.age = 25; person = { name: "John", age: 50 }; return person;}var personObj1 = { name: "Alex", age: 30};var personObj2 = changeAgeAndReference(personObj1);console.log(personObj1); // -> {name: 'Alex', age: 25}console.log(personObj2); // -> {name: 'John', age: 50}</code></pre><p>对对象的重新赋值在任何地方都是如此:在动态堆中重新分配内存空间并赋值,再把原地址的值改为新对象的地址。</p><p>当一个对象没有对应地址指向时,也就是上一段中原对象的情况,这个对象的内存地址会被回收,这是js的垃圾回收机制</p><p>“如果连续五次垃圾回收之后,内存占用一次比一次大,就有内存泄漏。这就要求实时查看内存占用。”避免内存泄漏的要点在于往后不会使用的变量要及时赋空。</p><h2 id="闭包、词法环境-作用域"><a href="#闭包、词法环境-作用域" class="headerlink" title="闭包、词法环境(作用域)"></a>闭包、词法环境(作用域)</h2><p>一个函数和对其周围状态(<strong>lexical environment,词法环境</strong>)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是<strong>闭包</strong>(<strong>closure</strong>)。</p><ul><li>用于保存私有属性:将不需要对外暴露的属性、函数保存在闭包函数的父函数里,避免外部操作对值的干扰</li><li>避免局部属性污染全局变量空间导致的命名空间混乱</li><li>模块化封装,将对立的功能模块通过闭包进去封装,只暴露较少的 API 供外部应用使用</li></ul><p>缺点:内存消耗,由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题。</p><p>c语言退出函数时局部变量也会退出其作用域,所以难以创建闭包;js创建函数时会保留其能访问的变量的地址,这也是创建闭包的前提所在。</p><p>词法环境有两大成员:<strong>「Environment Record(环境记录)」</strong>,可能为 null 的 <strong>「Outer Lexical Environment(外部词法环境引用)」</strong>。<strong>任何在环境记录中的标识符都可以在当前词法环境直接以标识符形式访问</strong>。</p><p>Environment Record 是一个抽象类,存在三个具体的子类,<strong>「Declarative Environment Record」</strong> ,<strong>「Object Environment Record」</strong>,<strong>「Global Environment Record(全局环境记录)」</strong></p><p>声明式环境记录保存 let、const、function 等非 var 声明标识符,对象式环境记录保存 var 声明标识符。 </p><h3 id="对象式环境记录"><a href="#对象式环境记录" class="headerlink" title="对象式环境记录"></a>对象式环境记录</h3><p>对象式记录也是用于记录标识符与变量的映射,但是它只记录var声明的标识符 ; 并且它有一个关联的绑定对象(binding object)。</p><ul><li><p>在词法环境中,会为对象式环境记录中所有的标识符绑定到绑定对象的同名属性上。<br>例如var number=1000; , 也能够通过window.number形式获取到number的值。</p></li><li><p>反过来也可以,会将绑定对象的所有属性名(自然也必须是能做标识符的)绑定到对象式环境记录中的同名标识符上。<br>例如:window.thousand = 1000; 然后直接以 thousand就能获取到该值(严格模式下报错)</p></li><li><p>每个标识符在绑定后都会直接实例化并初始化为undefined ,如果标识符已经绑定了绑定对象上的原有属性上,那么该变量就是对应属性值 。<br>比如之前的isNaN在声明前使用时就有值,就是这个原因。<br>变量提升也是这个原因造成的。</p></li><li><p>如果标识符已经存在,那么无视之,所以var可以重复声明。</p></li></ul><h3 id="声明式环境记录"><a href="#声明式环境记录" class="headerlink" title="声明式环境记录"></a>声明式环境记录</h3><p>同样的,声明式环境记录也比较特殊,它只记录非var声明的标识符,例如let、const、function……声明的标识符等等。并且它没有关联的绑定对象。</p><ul><li><p>所有声明的标识符(这里应该包含var声明的标识符,但不建立关联)都位于此处。</p></li><li><p>将所有非var声明的标识符实例化,但不初始化,也就是变量处于uninitialized状态。也就是说内存中已经为变量预留出空间,但是还没有和对应的标识符建立绑定关系。</p></li><li><p>在执行上下文的运行(perform状态)阶段,并执行到声明语句时,才会真正初始化并默认赋值为undefined。<br>所以你就懂了,let声明的标识符之前无法访问,就是因为还没有建立绑定。<br>暂存死区的根本原因在此。</p></li><li><p>在声明式环境记录中,<strong>不允许出现重复的标识符</strong>,所以它无法重复。甚至和var声明的标识符冲突。注意,它会在代码加载后的预编译阶段(只能说是运行前,因为JS没有真正的预编译啊……)就已经完成。</p></li></ul><p>全局环境记录包含前两者,是底层记录形式,绑定对象为 window 。</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">f</span><span class="token punctuation">(</span><span class="token parameter">a<span class="token punctuation">,</span>b</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">var</span> t <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">;</span> <span class="token keyword">let</span> sum <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">;</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> sum <span class="token operator">=</span> a<span class="token operator">+</span>b<span class="token punctuation">;</span> <span class="token keyword">var</span> mul <span class="token operator">=</span> a<span class="token operator">*</span>b <span class="token operator">+</span>sum<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> mul<span class="token operator">*</span>t<span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token function">f</span><span class="token punctuation">(</span><span class="token number">20</span><span class="token punctuation">,</span><span class="token number">30</span><span class="token punctuation">)</span> <span class="token comment">// 6500</span><span class="token comment">//词法环境</span>FunctionEnv <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">This</span><span class="token operator">:</span><span class="token operator"><</span>window<span class="token operator">></span> <span class="token literal-property property">outerEnv</span><span class="token operator">:</span><span class="token operator"><</span>GlobalEnv<span class="token operator">></span><span class="token punctuation">,</span> <span class="token literal-property property">ObjRec</span><span class="token operator">:</span><span class="token punctuation">{</span> <span class="token literal-property property">t</span><span class="token operator">:</span><span class="token operator"><</span><span class="token number">10</span><span class="token operator">></span><span class="token punctuation">,</span> <span class="token literal-property property">mul</span><span class="token operator">:</span><span class="token operator"><</span><span class="token number">650</span><span class="token operator">></span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">DecRec</span><span class="token operator">:</span><span class="token punctuation">{</span> <span class="token literal-property property">sum</span><span class="token operator">:</span><span class="token operator"><</span><span class="token number">10</span><span class="token operator">></span> <span class="token punctuation">}</span><span class="token punctuation">}</span>BlockEnv<span class="token operator">=</span><span class="token punctuation">{</span> <span class="token literal-property property">This</span><span class="token operator">:</span><span class="token operator"><</span>window<span class="token operator">></span><span class="token punctuation">,</span> <span class="token literal-property property">outerEnv</span><span class="token operator">:</span><span class="token operator"><</span>FunctionEnv<span class="token operator">></span><span class="token punctuation">,</span> <span class="token literal-property property">DecRec</span><span class="token operator">:</span><span class="token punctuation">{</span> <span class="token literal-property property">sum</span><span class="token operator">:</span><span class="token operator"><</span><span class="token number">50</span><span class="token operator">></span> <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><p>函数属于声明式环境记录是因为存在块级作用域,var 剥离出的环境记录只有全局作用域和函数作用域。</p><p>声明式对应 LexEnv,对象式对应 VarEnv</p><h2 id="面向对象"><a href="#面向对象" class="headerlink" title="面向对象"></a>面向对象</h2><p>this和new</p><pre class="language-none"><code class="language-none">this 使用在函数中时被用来指向当前调用函数的对象,也即在对象上使用. or [] 访问属性或者方法时,this就相当于这个对象,如果没有. or []依附对象进行直接访问时,this将指向全局对象(global object),也即访问全局属性/变量或者方法/函数。Global execution context in scripts:this指全局对象-一个名字叫global的对象Global execution context in modules:this返回undefinednew 创建一个崭新的空对象,然后使用指向那个对象的 this 调用特定的函数,修改this对象的属性。如果你没有使用 new 运算符,构造函数会像其他的常规函数一样被调用,并不会创建一个对象。在这种情况下,this 的指向也是不一样的。</code></pre><p>for … in object 可以遍历对象的所有属性,利用全局对象Object的方法keys可以获得属性名数组,例如有对象实例student,Object.keys(student)为student的所有属性名数组。判断对象是否包含某一属性可以用 in ,’keyName’ in objectName 是bool值。当通过类实例化时,虽然方法可以访问,in也报true,但方法不属于对象本身,而是属于类。</p><p>const objectName={},引用关系不可变,但引用内容可变,意思是仍然可以为对象分配属性。</p><p>类也是对象。js引擎会自动把常量包装成对象,以能使用对应的对象方法。如length等。</p><p>ES6中在对象中添加方法时可以不写key而是直接像下面这样</p><pre class="language-none"><code class="language-none">objectName{...funcName(args...){...}...};same asobjectName{...funcName:function(args...){...}...};λ-calculus</code></pre><p>以下写法在ES6中合法</p><pre class="language-none"><code class="language-none">let obj={name:"hh",age:"13"}let {name,age}=obj;</code></pre><p><code>Object.defineProperty(object, property, methods)</code></p><p>第一个参数是一个对象,第二个参数是给该对象设置的属性名称,第三个参数是配置该属性的方法,比如set/get方法</p><p>在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。</p><h2 id="防抖节流"><a href="#防抖节流" class="headerlink" title="防抖节流"></a>防抖节流</h2><p>防抖:多次连续触发只执行一次</p><p>节流:一段时间内连续触发只执行一次,冷却时间过了可以继续</p><pre class="language-vue" data-language="vue"><code class="language-vue"><template> <div id="content" style="height:150px; line-height:150px; text-align:center; color: #fff;background-color:black; font-size:80px;"> </div></template> <script> let num = 1; const content = document.getElementById('content'); function count() { content.innerHTML = num++; }; content.onmousemove = count;//防抖 非立即执行版function debunce(func,wait,...args){ let timeout; return function(){ const context = this; if(timeout) clearTimeout(timeout); timeout = setTimeout(()=>{ func.apply(context,args); },wait); } } //防抖 立即执行 function debunce(func,wait,...args){ let timeout; return function(){ const context = this; let callNow = !timeout; if(timeout) clearTimeout(timeout); timeout = setTimeout(()=>{ timeout = null; },wait) if(callNow) func.apply(context,args); } } //节流 时间戳立即执行 function throttle(func,wait,...args){ let pre=0; return function(){ const context = this; let now = Date.now(); if(now-pre>=wait){ func.apply(context,args); pre=Date.now(); } } } //节流 延时器延迟执行 function throttle(func,wait,...args){ let timeout=0; return function(){ const context = this; if(!timeout){ timeout=setTimeout(()=>{ timeout=null; func.apply(context,args); },wait); } } }</script></code></pre><h2 id="异步和同步"><a href="#异步和同步" class="headerlink" title="异步和同步"></a>异步和同步</h2><p>异步任务分为宏任务和微任务</p><p><strong>宏任务:</strong>script/外层同步代码,定时器<code>setTimeout</code>,<code>setInterval</code>,node中的setImmediate,<code>事件绑定</code>,<code>回调函数</code>,<code>node中的fs模块</code></p><p><strong>微任务:</strong><code>new Promise().then(回调)</code>,<code>process.nextTick()</code>,<code>async await</code>,<code>Object.observe</code>,<code>MutaionObserver</code></p><p>Event Loop的执行顺序是:</p><ol><li>首先执行执行栈里的任务。</li><li>执行栈清空后,检查微任务(microtask)队列,将可执行的微任务全部执行。</li><li>取宏任务(macrotask)队列中的第一项执行。</li><li>回到第二步。</li></ol><p>await后面的函数会先执行一遍,然后就会跳出整个async函数来执行后面js栈(后面会详述)的代码。等本轮事件循环执行完了之后又会跳回到async函数中等待await后面表达式的返回值。</p><pre class="language-none"><code class="language-none">console.log("script start");async function async1() { await async2(); console.log("async1 end");}async function async2() { console.log("async2 end");}async1();setTimeout(function () { console.log("setTimeout");}, 0);new Promise((resolve) => { console.log("Promise"); resolve();}) .then(function () { console.log("promise1"); }) .then(function () { console.log("promise2"); });console.log("script end");// script start => async2 end => Promise => script end => async1 end=> promise1 => promise2 => setTimeout</code></pre><p>Promise</p><p>第一段调用了Promise构造函数,第二段是调用了promise实例的.then方法。promise的构造函数是同步执行,promise.then中的函数是异步执行。</p><p>promise实例有三种状态:</p><ul><li>pending(待定)</li><li>fulfilled(已执行)/或者也可形象地叫做resolved</li><li>rejected(已拒绝)</li></ul><p>调用resolve和reject能将分别将promise实例的状态变成fulfilled和rejected,只有状态变成已完成(即fulfilled和rejected之一),才能触发状态的回调</p><pre class="language-none"><code class="language-none">let p = new Promise((resolve, reject) => { // 做一些事情 // 然后在某些条件下resolve,或者reject if (/* 条件随便写^_^ */) { resolve() } else { reject() }})p.then(() => { // 如果p的状态被resolve了,就进入这里}, () => { // 如果p的状态被reject})</code></pre><ul><li><p>多个 then() 链式调用,<strong>并不是连续的创建了多个微任务并推入微任务队列</strong>,因为 then() 的返回值必然是一个 Promise,而后续的 then() 是上一步 then() 返回的 Promise 的回调</p></li><li><p>按照规范</p><pre class="language-arcade" data-language="arcade"><code class="language-arcade">async function async1(){ console.log('async1 start') await async2() console.log('async1 end')}</code></pre><p>可以转化为:</p><pre class="language-arcade" data-language="arcade"><code class="language-arcade">function async1(){ console.log('async1 start') return RESOLVE(async2()) .then(() => { console.log('async1 end') });}</code></pre></li><li><p><code>RESOLVE(p)</code>接近于<code>Promise.resolve(p)</code>,不过有微妙而重要的区别:p 如果本身已经是 Promise 实例,Promise.resolve 会直接返回 p 而不是产生一个新 promise;</p></li><li><p>如果<code>RESOLVE(p)</code>严格按照标准,应该产生一个新的 promise,尽管该 promise 确定会 resolve 为 p,<strong>但这个过程本身是异步的</strong>,也就是现在进入 job 队列的是<strong>新 promise 的 resolve 过程</strong>,所以该 promise 的 then 不会被立即调用,而要等到当前 job 队列执行到前述 resolve 过程才会被调用,然后其回调(也就是继续 await 之后的语句)才加入 job 队列,所以时序上就晚了</p></li><li><p>所以上述的 async1 函数我们可以进一步转换一下:</p><pre class="language-arcade" data-language="arcade"><code class="language-arcade">function async1(){ console.log('async1 start') return new Promise(resolve => resolve(async2())) .then(() => { console.log('async1 end') });}</code></pre></li></ul><h2 id="JSON"><a href="#JSON" class="headerlink" title="JSON"></a>JSON</h2><p>JSON对象有两个方法。JSON支持三种类型值:简单值(不包括 undefined ,字符串、数字、null,布尔值均可),对象,数组。也没有分号</p><p>JSON.stringify()</p><p>JSON.parse()</p><h2 id="网络请求和远程资源"><a href="#网络请求和远程资源" class="headerlink" title="网络请求和远程资源"></a>网络请求和远程资源</h2><p>Ajax</p><p>asynchronous JavaScript and XML</p><h3 id="XMLHttpRequest对象-XHR"><a href="#XMLHttpRequest对象-XHR" class="headerlink" title="XMLHttpRequest对象-XHR"></a>XMLHttpRequest对象-XHR</h3><p>XHR对象类型</p><pre class="language-json" data-language="json"><code class="language-json"><span class="token punctuation">{</span> <span class="token comment">//XMR方法</span>open<span class="token operator">:</span>function(method<span class="token punctuation">,</span>url<span class="token punctuation">,</span>isAsync)<span class="token punctuation">,</span><span class="token comment">//必须首先使用的方法</span>setRequestHeader<span class="token operator">:</span>function(HeaderKey<span class="token operator">:</span>string<span class="token punctuation">,</span>HeaderValue<span class="token operator">:</span>any)<span class="token comment">//自定义发送头部的信息,必须在open之后,send之前调用此函数。需要区别于浏览器正常发送头部,因为部分浏览器允许重写默认头部,某些则会引起错误</span>send<span class="token operator">:</span>function(arg)<span class="token punctuation">,</span><span class="token comment">//参数为请求体数据,不存在请求体时参数需显示设置为 null</span><span class="token comment">//readyState变化时自动调用此函数</span>onreadystatechange<span class="token operator">:</span>function()<span class="token punctuation">,</span><span class="token comment">//获取响应头部信息</span>getResponseHeaders<span class="token operator">:</span>function(headerKey<span class="token operator">:</span>string)<span class="token punctuation">,</span>getAllResponseHeaders()<span class="token operator">:</span>function()<span class="token punctuation">,</span><span class="token comment">//send 方法执行得到返回内容之后,这些属性会被填充</span>responseType<span class="token operator">:</span><span class="token string">""</span><span class="token punctuation">,</span>responseText<span class="token operator">:</span><span class="token string">"string"</span><span class="token punctuation">,</span><span class="token comment">//响应体文本</span>responseXML<span class="token operator">:</span>XML DOM<span class="token punctuation">,</span><span class="token comment">//响应类型为 text/xml 或者 application/xml 时返回的包含响应式数据的 XML DOM 文档</span>status<span class="token operator">:</span>statusCode<span class="token punctuation">,</span><span class="token comment">//响应HTTP状态码 2xx表示成功,304表示资源未修改,直接从浏览器缓存读取,此两种情况都表示响应有效</span>statusText<span class="token operator">:</span>'description'<span class="token punctuation">,</span><span class="token comment">//HTTP状态描述信息</span><span class="token comment">//状态属性</span>readyState<span class="token operator">:</span><span class="token number">0</span>|<span class="token number">1</span>|<span class="token number">2</span>|<span class="token number">3</span>|<span class="token number">4</span><span class="token punctuation">,</span><span class="token comment">//五种状态,0表示未调用 open 方法,未初始化,1表示已 open 但未 send,2表示 sent 但未收到响应,3表示收到部分响应 receiving ,4表示完成,已收到所有响应 complete。</span><span class="token comment">//收到响应之前可调用此方法终止异步请求,同时应当取消对该XHR对象的引用</span>abort<span class="token operator">:</span>function()<span class="token punctuation">,</span><span class="token punctuation">}</span></code></pre><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">//创建XHR对象</span><span class="token keyword">let</span> xhr <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">XMLHttpRequest</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//使用XMR对象</span><span class="token comment">//首先必须使用open方法,三个参数依次是请求类型:string,请求URL:string,是否异步:Boolean;这里的URL是相对于代码所在的页面的,必须遵守同源策略(同一域名,同一端口,同一协议),否则抛出安全错误。</span>xhr<span class="token punctuation">.</span><span class="token function">open</span><span class="token punctuation">(</span><span class="token string">'get'</span><span class="token punctuation">,</span><span class="token string">'example.com'</span><span class="token punctuation">,</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>xhr<span class="token punctuation">.</span><span class="token function">setRequestHeader</span><span class="token punctuation">(</span><span class="token string">'myHaeder'</span><span class="token punctuation">,</span><span class="token string">'myValue'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>xhr<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>send时XHR默认会发送的头部字段:</p><ul><li>Accept 浏览器可以处理的内容类型</li><li>Accept-Charset 浏览器支持显示的字符集</li><li>Accept-Encoding 浏览器可以处理的压缩编码类型</li><li>Accept-Language 浏览器使用的语言</li><li>Connection 浏览器与服务器的连接类型</li><li>Cookie 页面中设置的Cookie</li><li>Host 发送请求的页面所在的域</li><li>Referer 发送请求的页面的 URL ,将错就错,正确拼法是 referre</li><li>User-Agent 浏览器的用户代理字符串</li></ul><h4 id="Get请求"><a href="#Get请求" class="headerlink" title="Get请求"></a>Get请求</h4><p>The <code>encodeURIComponent()</code> method <strong>encodes</strong> a URI component. Use the <a href="https://www.w3schools.com/jsref/jsref_decodeuricomponent.asp">decodeURIComponent()</a> function to <strong>decode</strong> an encoded URI component.</p><h4 id="Post请求"><a href="#Post请求" class="headerlink" title="Post请求"></a>Post请求</h4><h3 id="CORS"><a href="#CORS" class="headerlink" title="CORS"></a>CORS</h3><p>跨域资源共享 Cross-origin Resource Share使用场景:</p><ul><li>由 <a href="https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest"><code>XMLHttpRequest</code></a> 或 <a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API">Fetch APIs</a> 发起的跨源 HTTP 请求。</li><li>Web 字体 (CSS 中通过 <code>@font-face</code> 使用跨源字体资源),<a href="https://www.w3.org/TR/css-fonts-3/#font-fetching-requirements">因此,网站就可以发布 TrueType 字体资源,并只允许已授权网站进行跨站调用</a>。</li><li><a href="https://developer.mozilla.org/zh-CN/docs/Web/API/WebGL_API/Tutorial/Using_textures_in_WebGL">WebGL 贴图</a></li><li>使用 <a href="https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D/drawImage"><code>drawImage</code></a> 将 Images/video 画面绘制到 canvas。</li><li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Shapes/Shapes_From_Images">来自图像的 CSS 图形 (en-US)</a></li></ul><p>跨源资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站通过浏览器有权限访问哪些资源。另外,规范要求,对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Methods/GET"><code>GET</code></a> 以外的 HTTP 请求,或者搭配某些 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/MIME_types">MIME 类型</a> 的 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Methods/POST"><code>POST</code></a> 请求),浏览器必须首先使用 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Methods/OPTIONS"><code>OPTIONS</code></a> 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨源请求。服务器确认允许之后,才发起实际的 HTTP 请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(包括 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Cookies">Cookies</a> 和 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Authentication">HTTP 认证</a> 相关数据)。</p><h2 id="接口"><a href="#接口" class="headerlink" title="接口"></a>接口</h2><p>setInterval(); 指每隔多少毫秒执行一次函数。因此它有两个参数,第一个参数为每次执行的函数,第二个参数为毫秒。如setInterval( fn, 16 ),返回值为id,用于标识一个setInterval调用。 </p><p>setTimeout() 方法只运行一次,也就是说当达到设定的时间后就开始运行指定的代码,运行完后就结束了,次数是一次。 setInterval() 是循环执行的,即每达到指定的时间间隔就执行相应的函数或者表达式,只要窗口不关闭或clearInterval() 调用就会无限循环下去。</p><p>date对象,包含一系列获取时间的方法</p><h2 id="Control-abstraction-objects"><a href="#Control-abstraction-objects" class="headerlink" title="Control abstraction objects"></a><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects#control_abstraction_objects">Control abstraction objects</a></h2><p>控制抽象对象</p><ul><li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise"><code>Promise</code></a></li><li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator"><code>Generator</code></a></li><li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/GeneratorFunction"><code>GeneratorFunction</code></a></li><li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncFunction"><code>AsyncFunction</code></a></li><li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncGenerator"><code>AsyncGenerator</code></a></li><li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncGeneratorFunction"><code>AsyncGeneratorFunction</code></a></li></ul><h2 id="Reflection"><a href="#Reflection" class="headerlink" title="Reflection"></a>Reflection</h2><p><strong>Proxy</strong> 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。</p><pre class="language-none"><code class="language-none">const p = new Proxy(target, handler)handler 包含捕捉器(trap)的占位符对象,可译为处理器对象。traps提供属性访问的方法。这类似于操作系统中捕获器的概念。target被 Proxy 代理虚拟化的对象。它常被作为代理的存储后端。根据目标验证关于对象不可扩展性或不可配置属性的不变量(保持不变的语义)。</code></pre><p><strong><code>Proxy.revocable()</code></strong> 方法可以用来创建一个可撤销的代理对象。细节见<a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy/revocable">此处</a>。</p><pre class="language-none"><code class="language-none">Proxy.revocable(target, handler);</code></pre>]]></content>
<summary type="html"><blockquote>
<p>持续更新</p>
</blockquote>
<h2 id="基础"><a href="#基础" class="headerlink" title="基础"></a>基础</h2><pre class="language-markup" data-</summary>
<category term="常用编程语言基础知识" scheme="https://hhumar.com/categories/%E5%B8%B8%E7%94%A8%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/"/>
<category term="JavaScript" scheme="https://hhumar.com/tags/JavaScript/"/>
</entry>
<entry>
<title>回来咯</title>
<link href="https://hhumar.com/2022/10/25/hello-world/"/>
<id>https://hhumar.com/2022/10/25/hello-world/</id>
<published>2022-10-25T07:37:56.643Z</published>
<updated>2022-10-31T01:54:28.172Z</updated>
<content type="html"><![CDATA[<h2 id="杂谈"><a href="#杂谈" class="headerlink" title="杂谈"></a>杂谈</h2><p>老早之前就建好这个站了,不过嫌弃默认样式太丑又不会自定义,所以就没一直用下去</p><p>这次学了一点前端回来捡起来这个站,当作一个安全的备份记录的地方,希望能早点把真真正正自己写的网站弄出来,暂时把这里当作主要阵地。</p>]]></content>
<summary type="html"><h2 id="杂谈"><a href="#杂谈" class="headerlink" title="杂谈"></a>杂谈</h2><p>老早之前就建好这个站了,不过嫌弃默认样式太丑又不会自定义,所以就没一直用下去</p>
<p>这次学了一点前端回来捡起来这个站,当作一个安全的</summary>
<category term="生活" scheme="https://hhumar.com/categories/%E7%94%9F%E6%B4%BB/"/>
<category term="first in all" scheme="https://hhumar.com/tags/first-in-all/"/>
</entry>
</feed>