-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlocal-search.xml
397 lines (186 loc) · 440 KB
/
local-search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>React组件通信</title>
<link href="/2025/01/17/React%E7%BB%84%E4%BB%B6%E9%80%9A%E4%BF%A1/"/>
<url>/2025/01/17/React%E7%BB%84%E4%BB%B6%E9%80%9A%E4%BF%A1/</url>
<content type="html"><![CDATA[<h1>React组件通信</h1><blockquote><p>随着 2019 年 2 月 React 稳定版 hooks 在 16.8 版本发布,涌现了越来越多的 “hooks 时代” 的状态管理库(如 zustand),“class 时代” 的状态管理库(如 redux)也全面拥抱了 hooks。无一例外,它们都聚焦于解决 组件通信 的问题 🤔</p></blockquote><ul><li>组件通信的方式有哪些?</li><li>这么多的状态管理库要怎么选?</li><li>可变状态 or 不可变状态?</li></ul><p>截至目前,React 中组件间的通信方式一共有 5 种,</p><ul><li>props 和 callback</li><li>Context(官方)</li><li>Event Bus(事件总线)</li><li>ref 传递</li><li>状态管理库(如:redux、mobx、zustand、recoil、valtio、jotai、hox 等)</li></ul><p>接下来一个一个介绍一下</p><h2 id="props和-callback">props和 callback</h2><p>props 和 callback 是 React 中组件通信最基本的方式,也是最常用的方式。</p><p>React 组件最基础的通信方式是使用 props 来传递信息,props 是只读的,每个父组件都可以提供 props 给它的子组件,从而将一些信息传递给它,这里的信息可以是,</p><ul><li>JSX 标签信息,如 className、src、alt、width 和 height 等</li><li>对象或其他任意类型的值</li><li>父组件中的 state</li><li>children</li><li>balabala…</li></ul><p>一般情况在“父传子” 的通信场景下使用 props,下面是一个 props 通信的例子</p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><code class="hljs jsx"><span class="hljs-keyword">import</span> <span class="hljs-title class_">React</span>, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;<br><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">Parent</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">const</span> [count, setCount] = useState<number>(<span class="hljs-number">0</span>);<br><br> <span class="hljs-keyword">return</span> (<br> <span class="language-xml"><span class="hljs-tag"><></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =></span> setCount(count + 1)}>Add<span class="hljs-tag"></<span class="hljs-name">button</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">Child</span> <span class="hljs-attr">count</span>=<span class="hljs-string">{count}</span>></span>Children<span class="hljs-tag"></<span class="hljs-name">Child</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"></></span></span><br> );<br>}<br><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">Child</span>(<span class="hljs-params">props</span>) {<br> <span class="hljs-comment">// 解构 props</span><br> <span class="hljs-keyword">const</span> { count, children } = props;<br><br> <span class="hljs-keyword">return</span> (<br> <span class="language-xml"><span class="hljs-tag"><></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">p</span>></span> parent: {count}<span class="hljs-tag"></<span class="hljs-name">p</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">p</span>></span>Received children from parent: {children}<span class="hljs-tag"></<span class="hljs-name">p</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"></></span></span><br> );<br>}<br><br></code></pre></td></tr></table></figure><p>callback 回调函数也可以是props<br>利用 callback 回调函数,子组件可以向父组件传递信息,来一个 callback 通信的🌰</p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs jsx"><span class="hljs-keyword">function</span> <span class="hljs-title function_">Parent</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">const</span> [count, setCount] = useState<number>(<span class="hljs-number">0</span>);<br><br> <span class="hljs-keyword">return</span> (<br> <span class="language-xml"><span class="hljs-tag"><></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =></span> setCount(count + 1)}>Add<span class="hljs-tag"></<span class="hljs-name">button</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">Child</span> <span class="hljs-attr">updateCount</span>=<span class="hljs-string">{(value)</span> =></span> setCount(value)}>Children<span class="hljs-tag"></<span class="hljs-name">Child</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"></></span></span><br> );<br>}<br><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">Child</span>(<span class="hljs-params">props</span>) {<br> <span class="hljs-keyword">const</span> { updateCount } = props;<br> <br> <span class="hljs-keyword">return</span> <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =></span> updateCount(count + 1)}>Add<span class="hljs-tag"></<span class="hljs-name">button</span>></span></span>;<br>}<br></code></pre></td></tr></table></figure><p>此外,如果多个组件需要共享 state,且层级不是太复杂时,我们通常会考虑 状态提升<br>实现的思路是:<br>将公共 state 向上移动到它们的最近共同父组件中<br>再使用 props 传递给子组件<br><img src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/dd435d248bfe4407b4199abd9c7e2bea~tplv-k3u1fbpfcp-zoom-in-crop-mark:1512:0:0:0.awebp?" alt=""><br>这时候一般会发现一个问题<br>在多级嵌套组件的场景下,使用 props 进行通信是一件成本极高的事情<br>你要一直穿穿穿<br>所以context就应运而生了 😎</p><h2 id="Context">Context</h2><p>react官方对于context的使用场景是</p><blockquote><p>使用 Context 看起来非常诱人!<br>然而,这也意味着它也太容易被过度使用了。<em>如果你只想把一些 props 传递到多个层级中,这并不意味着你需要把这些信息放到 context 里。</em><br>在使用 context 之前,你可以考虑以下几种替代方案:</p><ol><li>从 传递 props 开始。 如果你的组件看起来不起眼,那么通过十几个组件向下传递一堆 props 并不罕见。这有点像是在埋头苦干,但是这样做可以让哪些组件用了哪些数据变得十分清晰!维护你代码的人会很高兴你用 props 让数据流变得更加清晰。</li><li>抽象组件并 将 JSX 作为 children 传递 给它们。 如果你通过很多层不使用该数据的中间组件(并且只会向下传递)来传递数据,这通常意味着你在此过程中忘记了抽象组件。举个例子,你可能想传递一些像 posts 的数据 props 到不会直接使用这个参数的组件,类似 <code><Layout posts={posts} /></code>。取而代之的是,让 Layout 把 children 当做一个参数,然后渲染 <code><Layout><Posts posts={posts} /></Layout></code>。这样就减少了定义数据的组件和使用数据的组件之间的层级。<br>如果这两种方法都不适合你,再考虑使用 context。</li></ol></blockquote><p><img src="https://camo.githubusercontent.com/e58c76397f171c4d8b42c4f1ab30ccc8ff24f5a0116df2ee86d84473d9e00368/68747470733a2f2f70332d6a75656a696e2e62797465696d672e636f6d2f746f732d636e2d692d6b3375316662706663702f39623061653466366232626434663730383131373032313631363338323166357e74706c762d6b3375316662706663702d7a6f6f6d2d696e2d63726f702d6d61726b3a313531323a303a303a302e6177656270" alt="context"><br>Context 让父组件可以为它下面的整个组件树提供数据,这在一些特定的场景下非常有用,比如,</p><ul><li>主题:可以在应用顶层放一个 context provider,并在需要调整其外观的组件中使用该 context</li><li>全局的共享信息:如当前登录的用户信息,将它放到 context 中可以方便地在树中任何位置读取</li><li>路由:大多数路由解决方案在内部使用 context 保存当前路由,用于判断链接是否处于活动状态</li></ul><p>需要注意的是,使用 Context 我们需要考量具体的场景,因为 Context 本身存在以下问题,</p><ul><li>context 的值一旦变化,所有依赖该 context 的组件全部都会 force update</li><li>context 会穿透 React.memo 和 shouldComponentUpdate 的对比</li></ul><p>此外,对于异步请求和数据间的联动,Context 也没有提供任何 API 支持,如果使用 Context,需要自己做一些封装。</p><h2 id="ref">ref</h2><p>使用 ref 可以访问到由 React 管理的 DOM 节点,ref 一般适用以下的场景,</p><p>管理焦点,获取子组件的值,文本选择或媒体播放<br>触发强制动画<br>集成第三方 DOM 库</p><p>ref 也是组件通信的一种方案,通过 ref 可以获取子组件的实例,以 input 元素的输入值为例,</p><figure class="highlight tsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><code class="hljs tsx"><span class="hljs-keyword">import</span> <span class="hljs-title class_">React</span>, { useRef, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;<br><br><span class="hljs-keyword">interface</span> <span class="hljs-title class_">ChildProps</span> {<br> <span class="hljs-attr">inputRef</span>: <span class="hljs-title class_">React</span>.<span class="hljs-property">RefObject</span><<span class="hljs-title class_">HTMLInputElement</span>>;<br>}<br><br><span class="hljs-keyword">const</span> <span class="hljs-title class_">Child</span>: <span class="hljs-title class_">React</span>.<span class="hljs-property">FC</span><<span class="hljs-title class_">ChildProps</span>> = <span class="hljs-function">(<span class="hljs-params">{ inputRef }</span>) =></span> <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">input</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{inputRef}</span> /></span></span>;<br><br><span class="hljs-keyword">const</span> <span class="hljs-title class_">Parent</span>: <span class="hljs-title class_">React</span>.<span class="hljs-property">FC</span> = <span class="hljs-function">() =></span> {<br> <span class="hljs-keyword">const</span> [text, setText] = useState<<span class="hljs-built_in">string</span>>(<span class="hljs-string">""</span>);<br> <span class="hljs-keyword">const</span> inputRef = useRef<<span class="hljs-title class_">HTMLInputElement</span>>(<span class="hljs-literal">null</span>);<br><br> <span class="hljs-keyword">const</span> <span class="hljs-title function_">handleClick</span> = (<span class="hljs-params"></span>) => {<br> <span class="hljs-keyword">if</span> (inputRef.<span class="hljs-property">current</span>) {<br> <span class="hljs-title function_">setText</span>(inputRef.<span class="hljs-property">current</span>.<span class="hljs-property">value</span>);<br> }<br> };<br><br> <span class="hljs-keyword">return</span> (<br> <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">Child</span> <span class="hljs-attr">inputRef</span>=<span class="hljs-string">{inputRef}</span> /></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleClick}</span>></span>Get Input Value<span class="hljs-tag"></<span class="hljs-name">button</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">p</span>></span>Input Value: {text}<span class="hljs-tag"></<span class="hljs-name">p</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"></<span class="hljs-name">div</span>></span></span><br> );<br>};<br><br></code></pre></td></tr></table></figure><h2 id="状态管理库">状态管理库</h2><p>好啦 上述的组件通信方案都有自己的使用场景 但是 如果项目复杂度很高 组件很多 组件通信就会变得很复杂 这时候就需要状态管理库了<br>React 的状态管理库一直以来都是 React 生态中非常内卷的一个领域<br>介绍一下比较常用的几个</p><h3 id="redux">redux</h3><p>Redux 是一个基于 Flux 架构的一种实现,遵循“单向数据流”和“不可变状态模型”的设计思想</p><p>这个简单介绍一下 flux架构<br>Flux将一个应用分成四个部分。</p><ul><li>View: 视图层</li><li>Action(动作):视图层发出的消息(比如mouseClick)</li><li>Dispatcher(派发器):用来接收Actions、执行回调函数</li><li>Store(数据层):用来存放应用的状态,一旦发生变动,就提醒Views要更新页面</li></ul><p><img src="https://www.ruanyifeng.com/blogimg/asset/2016/bg2016011503.png" alt="flux"></p><blockquote><p>Flux 的最大特点,就是数据的"单向流动"。</p></blockquote><ol><li>用户访问 View</li><li>View 发出用户的 Action</li><li>Dispatcher 收到 Action,要求 Store 进行相应的更新</li><li>Store 更新后,发出一个"change"事件</li><li>View 收到"change"事件后,更新页面</li></ol><p>上面过程中,数据总是"单向流动",任何相邻的部分都不会发生数据的"双向流动"。这保证了流程的清晰</p><h4 id="通过-Action-Reducer-Store-的工作流程实现状态的管理,具有以下的优点,">通过 Action-Reducer-Store 的工作流程实现状态的管理,具有以下的优点,</h4><ul><li>可预测和不可变状态,行为稳定可预测、可运行在不同环境</li><li>单一 store ,单项数据流集中管理状态,在做 撤销/重做、 状态持久化 等场景有天然优势</li><li>成熟的开发调试工具,Redux DevTools 可以追踪到应用的状态的改变</li></ul><p>使用 Redux 就得遵循他的设计思想,包括其中的 “三大原则”,</p><ul><li>使用单一 store 作为数据源</li><li>state 是只读的,唯一改变 state 的方式就是触发 action</li><li>使用纯函数来执行修改,接收之前的 state 和 action,并返回新的 state</li></ul><p>下面有一个简单的demo</p><figure class="highlight tsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><code class="hljs tsx"><span class="hljs-keyword">import</span> <span class="hljs-title class_">React</span> <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;<br><span class="hljs-keyword">import</span> { createStore, combineReducers } <span class="hljs-keyword">from</span> <span class="hljs-string">"redux"</span>;<br><span class="hljs-keyword">import</span> { <span class="hljs-title class_">Provider</span>, useSelector, useDispatch } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-redux"</span>;<br><br><span class="hljs-comment">// 定义 action 类型</span><br><span class="hljs-keyword">const</span> <span class="hljs-variable constant_">INCREMENT</span> = <span class="hljs-string">"INCREMENT"</span>;<br><span class="hljs-keyword">const</span> <span class="hljs-variable constant_">DECREMENT</span> = <span class="hljs-string">"DECREMENT"</span>;<br><br><span class="hljs-comment">// 定义 action 创建函数</span><br><span class="hljs-keyword">const</span> <span class="hljs-title function_">increment</span> = (<span class="hljs-params"></span>) => ({ <span class="hljs-attr">type</span>: <span class="hljs-variable constant_">INCREMENT</span> });<br><span class="hljs-keyword">const</span> <span class="hljs-title function_">decrement</span> = (<span class="hljs-params"></span>) => ({ <span class="hljs-attr">type</span>: <span class="hljs-variable constant_">DECREMENT</span> });<br><br><span class="hljs-comment">// 定义 reducer</span><br><span class="hljs-keyword">const</span> <span class="hljs-title function_">counter</span> = (<span class="hljs-params">state = <span class="hljs-number">0</span>, action: { <span class="hljs-keyword">type</span>: <span class="hljs-built_in">string</span> }</span>) => {<br> <span class="hljs-keyword">switch</span> (action.<span class="hljs-property">type</span>) {<br> <span class="hljs-keyword">case</span> <span class="hljs-attr">INCREMENT</span>:<br> <span class="hljs-keyword">return</span> state + <span class="hljs-number">1</span>;<br> <span class="hljs-keyword">case</span> <span class="hljs-attr">DECREMENT</span>:<br> <span class="hljs-keyword">return</span> state - <span class="hljs-number">1</span>;<br> <span class="hljs-attr">default</span>:<br> <span class="hljs-keyword">return</span> state;<br> }<br>};<br><br><span class="hljs-comment">// 创建 store</span><br><span class="hljs-keyword">const</span> rootReducer = <span class="hljs-title function_">combineReducers</span>({ counter });<br><span class="hljs-keyword">const</span> store = <span class="hljs-title function_">createStore</span>(rootReducer);<br><br><span class="hljs-comment">// 定义 Counter 组件</span><br><span class="hljs-keyword">const</span> <span class="hljs-title class_">Counter</span>: <span class="hljs-title class_">React</span>.<span class="hljs-property">FC</span> = <span class="hljs-function">() =></span> {<br> <span class="hljs-keyword">const</span> count = <span class="hljs-title function_">useSelector</span>(<span class="hljs-function">(<span class="hljs-params">state: { counter: <span class="hljs-built_in">number</span> }</span>) =></span> state.<span class="hljs-property">counter</span>);<br> <span class="hljs-keyword">const</span> dispatch = <span class="hljs-title function_">useDispatch</span>();<br><br> <span class="hljs-keyword">return</span> (<br> <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">h2</span>></span>Counter: {count}<span class="hljs-tag"></<span class="hljs-name">h2</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =></span> dispatch(increment())}>add<span class="hljs-tag"></<span class="hljs-name">button</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =></span> dispatch(decrement())}>dec<span class="hljs-tag"></<span class="hljs-name">button</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"></<span class="hljs-name">div</span>></span></span><br> );<br>};<br><br><span class="hljs-comment">// 使用 Provider 包裹根组件</span><br><span class="hljs-keyword">const</span> <span class="hljs-title class_">App</span>: <span class="hljs-title class_">React</span>.<span class="hljs-property">FC</span> = <span class="hljs-function">() =></span><br> <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">Provider</span> <span class="hljs-attr">store</span>=<span class="hljs-string">{store}</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">Counter</span> /></span></span><br><span class="language-xml"> <span class="hljs-tag"></<span class="hljs-name">Provider</span>></span></span><br></code></pre></td></tr></table></figure><p>可以看到,由于没有规定如何处理异步加上相对约定式的设计,导致 Redux 存在以下的一些问题,</p><p>陡峭的学习曲线,副作用扔给中间件来处理,导致社区一堆中间件,学习成本陡然增加<br>大量的模版代码,包括 action、action creator 等大量和业务逻辑无关的模板代码<br>性能问题,状态量大的情况下,state 更新会影响所有组件,每个 action 都会调用所有 reducer</p><p>虽然 Redux 一致尝试致力解决上述部分问题,比如后面推出的 redux toolkit,但即便如此,对于开发者(尤其是初学者)而言,仍然有比较高的学习成本和心智负担。<br>相比之下我还是更推荐zustand</p><h2 id="zustand">zustand</h2><p>zustand 是一个轻量级的状态管理库,经过 Gzip 压缩后仅 954B 大小,<br>zustand 凭借其函数式的理念,优雅的 API 设计,成为 2021 年 Star 数增长最快的 React 状态管理库,</p><p>与 redux 的理念类似,zustand 也是基于不可变状态模型和单向数据流,区别在于,</p><ul><li>redux 需要包装一个全局 / 局部的 Context Provider,而 zustand 不用</li><li>redux 基于 reducers 纯函数更新状态,zustand 通过类原生 useState 的 hooks 语法,更简单灵活</li><li>zustand 中的状态更新是同步的,不需要异步操作或中间件</li></ul><p>zustand 的心智模型非常简单,包含一个发布订阅器和渲染层,工作原理如下</p><p><img src="https://camo.githubusercontent.com/259b5a04bd2ce117a36babaabfda622ac60e8a81a2f7e286965e73980d882b89/68747470733a2f2f70312d6a75656a696e2e62797465696d672e636f6d2f746f732d636e2d692d6b3375316662706663702f38366262633438393732623634353034386463643938623134663434373732377e74706c762d6b3375316662706663702d77617465726d61726b2e696d6167653f" alt="zustand"><br>其中 Vanilla 层是发布订阅模式的实现,提供了<code>setState</code>、<code>subscribe</code> 和 <code>getState</code> 方法,React 层是 Zustand 的核心,实现了 reselect 缓存和注册事件的 listener 的功能,并且通过 <code>forceUpdate</code> 对组件进行重渲染,发布订阅相信大家都比较了解了,我们重点介绍下渲染层。<br>首先思考一个问题,React hooks 语法下,我们如何让当前组件刷新?<br>是不是只需要利用 useState 或 useReducer 这类 hook 的原生能力即可,调用第二个返回值的 dispatch 函数,就可以让组件重新渲染,这里 zustand 选择的是 useReducer,</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs ts"><span class="hljs-keyword">const</span> [, forceUpdate] = <span class="hljs-title function_">useReducer</span>(<span class="hljs-function">(<span class="hljs-params">c</span>) =></span> c + <span class="hljs-number">1</span>, <span class="hljs-number">0</span>) <span class="hljs-keyword">as</span> [<span class="hljs-built_in">never</span>, <span class="hljs-function">() =></span> <span class="hljs-built_in">void</span>]<br></code></pre></td></tr></table></figure><p>有了 forceUpdate 函数,接下来的问题就是什么时候调用 forceUpdate<br>参考一下zustand源码</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><code class="hljs ts"><span class="hljs-comment">// create 函数实现</span><br><span class="hljs-comment">// api 本质就是就是 createStore 的返回值,也就是 Vanilla 层的发布订阅器</span><br><span class="hljs-keyword">const</span> <span class="hljs-attr">api</span>: <span class="hljs-title class_">CustomStoreApi</span> = <span class="hljs-keyword">typeof</span> createState === <span class="hljs-string">'function'</span> ? <span class="hljs-title function_">createStore</span>(createState) : createState<br><br><span class="hljs-comment">// 这里的 useIsomorphicLayoutEffect 是同构框架常用 API 套路,在前端环境是 useLayoutEffect,在 node 环境是 useEffect</span><br><span class="hljs-title function_">useIsomorphicLayoutEffect</span>(<span class="hljs-function">() =></span> {<br> <span class="hljs-keyword">const</span> <span class="hljs-title function_">listener</span> = (<span class="hljs-params"></span>) => {<br> <span class="hljs-keyword">try</span> {<br> <span class="hljs-comment">// 拿到最新的 state 与上一次的 compare 函数</span><br> <span class="hljs-keyword">const</span> nextState = api.<span class="hljs-title function_">getState</span>()<br> <span class="hljs-keyword">const</span> nextStateSlice = selectorRef.<span class="hljs-title function_">current</span>(nextState)<br> <span class="hljs-comment">// 判断前后 state 值是否发生了变化,如果变化调用 forceUpdate 进行一次强制刷新</span><br> <span class="hljs-keyword">if</span> (!equalityFnRef.<span class="hljs-title function_">current</span>(currentSliceRef.<span class="hljs-property">current</span> <span class="hljs-keyword">as</span> <span class="hljs-title class_">StateSlice</span>, nextStateSlice)) {<br> stateRef.<span class="hljs-property">current</span> = nextState<br> currentSliceRef.<span class="hljs-property">current</span> = nextStateSlice<br> <span class="hljs-title function_">forceUpdate</span>()<br> }<br> } <span class="hljs-keyword">catch</span> (error) {<br> erroredRef.<span class="hljs-property">current</span> = <span class="hljs-literal">true</span><br> <span class="hljs-title function_">forceUpdate</span>()<br> }<br> }<br> <span class="hljs-comment">// 订阅 state 更新</span><br> <span class="hljs-keyword">const</span> unsubscribe = api.<span class="hljs-title function_">subscribe</span>(listener)<br> <span class="hljs-keyword">if</span> (api.<span class="hljs-title function_">getState</span>() !== stateBeforeSubscriptionRef.<span class="hljs-property">current</span>) {<br> <span class="hljs-title function_">listener</span>()<br> }<br> <span class="hljs-keyword">return</span> unsubscribe<br>}, [])<br><br></code></pre></td></tr></table></figure><p>我们首先从第 24 行 <code>api.subscribe(listener)</code> 开始,这里先创建了 <code>listener</code> 的订阅,这就使得任何的 <code>setState</code> 调用都会触发 <code>listener</code> 的执行,接着回到 <code>listener</code> 函数的内部,利用 <code>api.getState()</code> 拿到了最新 state,以及上一次的 compare 函数 equalityFnRef,然后执行比较函数后判断值前后是否发生了改变,如果改变则调用 <code>forceUpdate</code> 进行一次强制刷新。<br>这就是 zustand 渲染层的原理,简单而精巧,zustand 实现状态共享的方式本质是将状态保存在一个对象里</p><p>tips:</p><ul><li>useEffect 是异步执行的,而 useLayoutEffect 是同步执行的。</li><li>useEffect 的执行时机是浏览器完成渲染之后,而 useLayoutEffect 的执行时机是浏览器把内容真正渲染到界面之前</li></ul><h2 id="小结">小结</h2><p>都 2025 年了,对于 React 组件的通信,我们有太多可选的方式<br>对于选型可以参考下面的大致的思路,</p><p>如果组件间需要共享 state,且层级不是太复杂时,我们通常会考虑状态提升<br>Context 更适合存储一些全局的共享信息,如主题,用户登陆信息等<br>ref 更适用于管理焦点,获取子组件的值,触发强制动画,第三方 DOM 库集成等场景<br>如果你习惯了不可变更新,可以考虑生态丰富的 redux 和轻量的 zustand<br>如果你习惯了类 Vue 的响应式可变模型,mobx 和 valtio 可能更适合<br>如果你想尝试原子状态的方案,recoil 和 jotai 是个不错的选择(recoil已经被gank了 据说有内存泄漏问题🤣)<br>如果你想基于 custom hook 实现状态持久化和共享,hox 可能更适合</p>]]></content>
<tags>
<tag>React</tag>
</tags>
</entry>
<entry>
<title>大二上总结</title>
<link href="/2025/01/14/%E5%A4%A7%E4%BA%8C%E4%B8%8A%E6%80%BB%E7%BB%93/"/>
<url>/2025/01/14/%E5%A4%A7%E4%BA%8C%E4%B8%8A%E6%80%BB%E7%BB%93/</url>
<content type="html"><![CDATA[<h1>2024年终总结</h1><blockquote><p>为什么越长大,越觉得时间过得很快?是人老得快了,还是时钟的指针走快了?</p></blockquote><h2 id="关于过去">关于过去</h2><p>过去的一年半对我自身而言来说感觉是还是做出一些东西来的</p><p>至少在我为止努力的领域还算做的顺利</p><p>大一成功加入了木犀 转专业</p><p>大二也是走马上任了 今天是mini的第三天 不知道24级最后会做出什么样子的东西</p><p>短短一年,来也匆匆去也匆匆,这一年,发生了许多事情,相应地,我也成长了许多</p><p>感觉大学确实会训练到自己的能力 不仅仅是学习方面 也根本不是学习方面</p><p>我有时总会想这世界是一个巨大的地球online游戏 每一步都是预定好的</p><p>你虽然不知道会发生什么 但是其实已经是注定好的了</p><p>关于过去的一年半 感觉干了很多事情</p><p>在此罗列一下 在脑海里就可以想起来的</p><p><strong>学生工作:</strong></p><ul><li>信管融媒体</li><li>计算机青协</li><li>校会学创小喽喽</li><li>校会学创纯牛马</li></ul><p>无他 感觉干了很多其实目前看来没有用的事情 不知道未来会如何看</p><p>其他方面最最最最重要的可能就是加入木犀了</p><p>非常感谢木犀的老登点将点到我喽</p><p>经过一年多从老登处学习 也到了我要教小登的时候了</p><p>希望我这一年能把匣子 课栈 茶馆顺利推荐下去吧</p><p>如果有希望的解决飞书认证</p><p>再为团队的基础建设做一下贡献</p><p>我有的时候总会在想目前的教育体制究竟想培养出什么的样子的人?</p><p>听话的人 我想不是</p><p>有独立思考能力的人 我想也不是</p><p>反正我应该不是不符合教育体制想培养出来的那种人吧</p><p>在目前教育体制内 总是要向上爬</p><p>保研总是占了主旋律 但是我常常思考这是谁规定的</p><p>保研一定是最好的出路了</p><p>还好高数太低了保不了研(</p><p><strong>每个人都是第一次活一辈子,可人和人是不一样的,有的人生下来就和开了挂一样,有钱开朗,家庭温馨,一路上会遇到很多有趣的人,很多朋友,老了跟人吹牛都有很多故事可讲,成为别人眼中酷酷的老头或者老婆婆,对这样的人来说,每件往事都很珍贵,但也都没那么珍贵没,就像她可能会在意这周的演唱会,会激动的好几天睡不着抢票,做规划,要是抢不到也没有什么大不了,她可以飞到另一个城市去看下周的演唱会,但有些人不一样,他们一辈子就呆在一片很小很小的地方,一共认识不了几个人,没有几个人会真正在乎他,也没有几件他真正在乎的事</strong></p><p>目前只希望走好自己的路吧</p><h2 id="关于未来">关于未来</h2><p>未来其实留给自己的时间不多喽</p><p>既然已经确定了就业这条路 估计剩余的时间已经是倒计时了</p><p>下学期还有那么多b课 (tnnd 为什么要修满25个个性发展 真是逆天政策</p><p>在这里订一些小目标吧</p><ol><li><p>学会时间管理</p><p>感觉自己很多的时间都在浪费 在为数不多的时间里 要开始好好利用喽</p><p>听说 滴答清单不错 等下试试😋</p></li><li><p>暑期找到一段实习</p><blockquote><p>做梦都想去: 字节字节字节 (但是俗话说得好</p><p>字节人不可能同时拥有offer和自卑</p><p>预期:美团 大疆 mmt</p><p>最次:烂完了 考研去吧</p></blockquote></li><li><p>深入前端</p><p>无论是八股 还是一些react底层原理 但是还是非常值得去看看</p><p>上次看react的hooks时候感觉就很草率 需要好好看看了</p></li><li><p>leetcode</p><p>算法 太痛了 10月其实学过一段时间 但是估计现在也不记得什么了</p><p>寒假开始一天两道题!</p><p>学dp dp dp 我可太爱动态规划了 就是不会</p></li><li><p>关于团队</p></li></ol><p>带好24级 做好主管应该做的</p><p>匣子! 在写了在写了 不知道未来的rn生态会如何</p><ol start="6"><li>关于恋爱</li></ol><p>嘻嘻 嘻嘻 嘻嘻 学姐真是可爱啊</p><p>多陪陪她吧 无论最后如何 大三那一年基本上是要分开的 趁着大二下这段时间多陪陪她</p><ol start="7"><li><p>旅行</p><p>中国这么大 25年争取多出去看看 找到一个自己最喜欢的城市 目前是杭州</p><p>但是不知道阿里还有没有offer在了 😭</p></li><li><p>嗷 差点给学分绩忘记了</p><p>大二上学分绩还是不错的啊 希望未来一年差不多保持这个水平就好喽</p><p>但是下学期的课还是小重要的 计网好好学 (好好听估计是不太现实了</p><p>多去上课?</p></li><li><p>多看书</p></li></ol><p>一直说看书 也买了很多书 但是一直没看 也该静下来多看看书了</p><ol start="10"><li><p>写周报 对自己每周的进度做一个report</p><p>别摆烂</p></li></ol><p>好了 虽然但是也不知道为什么要写这玩意 越写压力越大</p><p>感觉自己还有很多要做的</p><p>虽然但是</p><blockquote><p>一定会出人头地的 对吧</p><p>一定会做出点成绩的 对吧</p><p>是吧 syj</p></blockquote>]]></content>
</entry>
<entry>
<title>TCP-1</title>
<link href="/2024/11/29/TCP-1/"/>
<url>/2024/11/29/TCP-1/</url>
<content type="html"><![CDATA[<h1>TCP-1</h1><blockquote><p>因为最近在准备七牛云的面试</p><p>这家公司也比较重视网络方面的东西</p><p>所以就重看了一次</p></blockquote><h2 id="TCP-基本认识">TCP 基本认识</h2><h3 id="TCP-头格式有哪些?">TCP 头格式有哪些?</h3><h4 id="先来看看-TCP-头的格式😋">先来看看 TCP 头的格式😋</h4><p><img src="https://cdn.xiaolincoding.com//mysql/other/format,png-20230309230534096.png" alt="TCP 头格式"></p><p>着重看一下彩色的部分</p><p>**序列号:**在建立连接时由计算机生成的随机数作为其初始值,通过SYN包传给接收端主机,每发送一次数据,就「累加」一次该「数据字节数」的大小。<strong>用来解决网络包乱序问题。</strong></p><p><strong>确认应答号</strong>:指下一次「期望」收到的数据的序列号,发送端收到这个确认应答以后可以认为在这个序号以前的数据都已经被正常接收。<strong>用来解决丢包的问题。</strong></p><p><strong>控制位:</strong></p><ul><li><em>ACK</em>:该位为 <code>1</code> 时,「确认应答」的字段变为有效,TCP 规定除了最初建立连接时的 <code>SYN</code> 包之外该位必须设置为 <code>1</code> 。</li><li><em>RST</em>:该位为 <code>1</code> 时,表示 TCP 连接中出现异常必须强制断开连接。</li><li><em>SYN</em>:该位为 <code>1</code> 时,表示希望建立连接,并在其「序列号」的字段进行序列号初始值的设定。</li><li><em>FIN</em>:该位为 <code>1</code> 时,表示今后不会再有数据发送,希望断开连接。当通信结束希望断开连接时,通信双方的主机之间就可以相互交换 <code>FIN</code> 位为 1 的 TCP 段。</li></ul><h3 id="为什么需要-TCP-协议?TCP-工作在哪一层?">为什么需要 TCP 协议?TCP 工作在哪一层?</h3><p><code>IP</code> 层是「不可靠」的,它不保证网络包的交付、不保证网络包的按序交付、也不保证网络包中的数据的完整性。</p><p><img src="https://camo.githubusercontent.com/8314740fec316b499229a56d8dc008d7929e931d2a22cdac6e82a94052164438/68747470733a2f2f696d67636f6e766572742e6373646e696d672e636e2f6148523063484d364c79396a5a473475616e4e6b5a577870646e4975626d56304c32646f4c336870595739736157356a6232526c6369394a6257466e5a556876633351794c7956464f435642525356424d5356464e795642525355354e7956464e69553551795643515356464e795643524355354d5356464e7956435169553551793955513141744a5555304a5549344a5467354a5555324a5546444a5545784a5555324a5468474a5545784a5555324a5467354a5468434a5555314a546b794a5468444a5555314a546c434a546c434a5555324a5546444a5545784a5555324a5468444a5545314a5555324a5467354a5468434c7a6375616e426e3f782d6f73732d70726f636573733d696d6167652f666f726d61742c706e67" alt="OSI 参考模型与 TCP/IP 的关系"></p><p>如果需要保障网络数据包的可靠性,那么就需要由上层(传输层)的 <code>TCP</code> 协议来负责。</p><p>因为 TCP 是一个工作在<strong>传输层</strong>的<strong>可靠</strong>数据传输的服务,它能确保接收端接收的网络包是<strong>无损坏、无间隔、非冗余和按序的。</strong></p><h3 id="什么是-TCP?🤔">什么是 TCP?🤔</h3><p>TCP 是<strong>面向连接的、可靠的、基于字节流</strong>的传输层通信协议。</p><p><img src="https://camo.githubusercontent.com/2e5e8126e1b733214b37dd029f1bbdc2ee7682056f366538997ef2dfcc9a1847/68747470733a2f2f696d67636f6e766572742e6373646e696d672e636e2f6148523063484d364c79396a5a473475616e4e6b5a577870646e4975626d56304c32646f4c336870595739736157356a6232526c6369394a6257466e5a556876633351794c7956464f435642525356424d5356464e795642525355354e7956464e69553551795643515356464e795643524355354d5356464e7956435169553551793955513141744a5555304a5549344a5467354a5555324a5546444a5545784a5555324a5468474a5545784a5555324a5467354a5468434a5555314a546b794a5468444a5555314a546c434a546c434a5555324a5546444a5545784a5555324a5468444a5545314a5555324a5467354a5468434c7a6775616e426e3f782d6f73732d70726f636573733d696d6167652f666f726d61742c706e67" alt="img"></p><p>说人话就是✋</p><ol><li>一定是 一对一的连接的 不可以一个主机同时向多个主机发送消息</li><li>无论网络链路中出现了什么样的变化,TCP都可以保证一个报文一定能够到达接收端</li><li>用户消息通过 TCP 协议传输时,消息可能会被操作系统「分组」成多个的 TCP 报文,如果接收方的程序如果不知道「消息的边界」,是无法读出一个有效的用户消息的。并且 TCP 报文是「有序的」,当「前一个」TCP 报文没有收到的时候,即使它先收到了后面的 TCP 报文,那么也不能扔给应用层去处理,同时对「重复」的 TCP 报文会自动丢弃。</li></ol><h3 id="什么是-TCP-连接?">什么是 TCP 连接?</h3><p>首先要知道什么是连接?</p><p>简单来说就是,<strong>用于保证可靠性和流量控制维护的某些状态信息,这些信息的组合,包括 Socket、序列号和窗口大小称为连接。</strong></p><p><img src="https://camo.githubusercontent.com/ccbea2787abd663464b9b9145d207b926d71e4fe2ef3183ecaaf8fa2532767ab/68747470733a2f2f696d67636f6e766572742e6373646e696d672e636e2f6148523063484d364c79396a5a473475616e4e6b5a577870646e4975626d56304c32646f4c336870595739736157356a6232526c6369394a6257466e5a556876633351794c7956464f435642525356424d5356464e795642525355354e7956464e69553551795643515356464e795643524355354d5356464e7956435169553551793955513141744a5555304a5549344a5467354a5555324a5546444a5545784a5555324a5468474a5545784a5555324a5467354a5468434a5555314a546b794a5468444a5555314a546c434a546c434a5555324a5546444a5545784a5555324a5468444a5545314a5555324a5467354a5468434c7a6b75616e426e3f782d6f73732d70726f636573733d696d6167652f666f726d61742c706e67" alt="img"></p><p>所以我们可以知道,建立一个 TCP 连接是需要客户端与服务端达成上述三个信息的共识。</p><ul><li><strong>Socket</strong>:由 IP 地址和端口号组成</li><li><strong>序列号</strong>:用来解决乱序问题等</li><li><strong>窗口大小</strong>:用来做流量控制</li></ul><h3 id="如何唯一确定一个-TCP-连接呢?">如何唯一确定一个 TCP 连接呢?</h3><p>TCP 四元组可以唯一的确定一个连接,四元组包括如下:</p><ul><li>源地址</li><li>源端口</li><li>目的地址</li><li>目的端口</li></ul><p><img src="https://camo.githubusercontent.com/39c54e4e60de15cad8fd57b4a15a192305adbd7da66c19140013c73ff4882434/68747470733a2f2f696d67636f6e766572742e6373646e696d672e636e2f6148523063484d364c79396a5a473475616e4e6b5a577870646e4975626d56304c32646f4c336870595739736157356a6232526c6369394a6257466e5a556876633351794c7956464f435642525356424d5356464e795642525355354e7956464e69553551795643515356464e795643524355354d5356464e7956435169553551793955513141744a5555304a5549344a5467354a5555324a5546444a5545784a5555324a5468474a5545784a5555324a5467354a5468434a5555314a546b794a5468444a5555314a546c434a546c434a5555324a5546444a5545784a5555324a5468444a5545314a5555324a5467354a5468434c7a45774c6d70775a773f782d6f73732d70726f636573733d696d6167652f666f726d61742c706e67" alt="TCP 四元组"></p><p>源地址和目的地址的字段(32 位)是在 IP 头部中,作用是通过 IP 协议发送报文给对方主机。</p><p>源端口和目的端口的字段(16 位)是在 TCP 头部中,作用是告诉 TCP 协议应该把报文发给哪个进程。</p><blockquote><p>有一个 IP 的服务端监听了一个端口,它的 TCP 的最大连接数是多少?</p></blockquote><p>服务端通常固定在某个本地端口上监听,等待客户端的连接请求。</p><p>因此,客户端 IP 和端口是可变的,其理论值计算公式如下</p><p><strong>最大TCP连接数=客户端IP数 X 客户端端口数</strong> 🐶</p><p>对 IPv4,客户端的 IP 数最多为 <code>2</code> 的 <code>32</code> 次方,客户端的端口数最多为 <code>2</code> 的 <code>16</code> 次方,也就是服务端单机最大 TCP 连接数,约为 <code>2</code> 的 <code>48</code> 次方。</p><p>当然,服务端最大并发 TCP 连接数远不能达到理论上限,会受以下因素影响:</p><ul><li><p>文件描述符限制</p><p>每个 TCP 连接都是一个文件,如果文件描述符被占满了,会发生 Too many open files。Linux 对可打开的文件描述符的数量分别作了三个方面的限制:😡</p><ul><li><strong>系统级</strong>:当前系统可打开的最大数量</li><li><strong>用户级</strong>:指定用户可打开的最大数量</li><li><strong>进程级</strong>:单个进程可打开的最大数量</li></ul></li><li><p><strong>内存限制</strong>,每个 TCP 连接都要占用一定内存,操作系统的内存是有限的,如果内存资源被占满后,会发生 OOM。</p></li></ul><h3 id="UDP-和-TCP-有什么区别呢?分别的应用场景是?">UDP 和 TCP 有什么区别呢?分别的应用场景是?</h3><p>UDP 不提供复杂的控制机制,利用 IP 提供面向「无连接」的通信服务。</p><p>那就是没有刚才说的那些诸多要求,所以UDP协议就会简单很多</p><p>头部只有 <code>8</code> 个字节(64 位),UDP 的头部格式如下:</p><p><img src="https://camo.githubusercontent.com/4975a046583b498f222b3af29b1fd745d04259ae296a42396cbc6d07254a640d/68747470733a2f2f696d67636f6e766572742e6373646e696d672e636e2f6148523063484d364c79396a5a473475616e4e6b5a577870646e4975626d56304c32646f4c336870595739736157356a6232526c6369394a6257466e5a556876633351794c7956464f435642525356424d5356464e795642525355354e7956464e69553551795643515356464e795643524355354d5356464e7956435169553551793955513141744a5555304a5549344a5467354a5555324a5546444a5545784a5555324a5468474a5545784a5555324a5467354a5468434a5555314a546b794a5468444a5555314a546c434a546c434a5555324a5546444a5545784a5555324a5468444a5545314a5555324a5467354a5468434c7a45794c6d70775a773f782d6f73732d70726f636573733d696d6167652f666f726d61742c706e67" alt="UDP 头部格式"></p><ul><li>目标和源端口:主要是告诉 UDP 协议应该把报文发给哪个进程。</li><li>包长度:该字段保存了 UDP 首部的长度跟数据的长度之和。</li><li>校验和:校验和是为了提供可靠的 UDP 首部和数据而设计,防止收到在网络传输中受损的 UDP 包。</li></ul><p><strong>TCP 和 UDP 区别:</strong></p><p><em>1. 连接</em></p><ul><li>TCP 是面向连接的传输层协议,传输数据前先要建立连接。</li><li>UDP 是不需要连接,即刻传输数据。</li></ul><p><em>2. 服务对象</em></p><ul><li>TCP 是一对一的两点服务,即一条连接只有两个端点。</li><li>UDP 支持一对一、一对多、多对多的交互通信</li></ul><p><em>3. 可靠性</em></p><ul><li>TCP 是可靠交付数据的,数据可以无差错、不丢失、不重复、按序到达。</li><li>UDP 是尽最大努力交付,不保证可靠交付数据。</li></ul><p><em>4. 拥塞控制、流量控制</em></p><ul><li>TCP 有拥塞控制和流量控制机制,保证数据传输的安全性。</li><li>UDP 则没有,即使网络非常拥堵了,也不会影响 UDP 的发送速率。</li></ul><p><em>5. 首部开销</em></p><ul><li>TCP 首部长度较长,会有一定的开销,首部在没有使用「选项」字段时是 <code>20</code> 个字节,如果使用了「选项」字段则会变长的。</li><li>UDP 首部只有 8 个字节,并且是固定不变的,开销较小。</li></ul><p><em>6. 传输方式</em></p><ul><li>TCP 是流式传输,没有边界,但保证顺序和可靠。</li><li>UDP 是一个包一个包的发送,是有边界的,但可能会丢包和乱序。</li></ul><p><em>7. 分片不同</em></p><ul><li>TCP 的数据大小如果大于 MSS 大小,则会在传输层进行分片,目标主机收到后,也同样在传输层组装 TCP 数据包,如果中途丢失了一个分片,只需要传输丢失的这个分片。</li><li>UDP 的数据大小如果大于 MTU 大小,则会在 IP 层进行分片,目标主机收到后,在 IP 层组装完数据,接着再传给传输层。</li></ul><p>说了这么多这两个玩意一般在什么情况下使用捏🧪</p><p><strong>TCP 和 UDP 应用场景:</strong></p><p>由于 TCP 是面向连接,能保证数据的可靠性交付,因此经常用于:</p><ul><li><code>FTP</code> 文件传输;</li><li>HTTP / HTTPS;</li></ul><p>由于 UDP 面向无连接,它可以随时发送数据,再加上 UDP 本身的处理既简单又高效,因此经常用于:</p><ul><li>包总量较少的通信,如 <code>DNS</code> 、<code>SNMP</code> 等;</li><li>视频、音频等多媒体通信;</li><li>广播通信</li></ul><p>那他们的区别有很多,为什么会如此区别捏?🤔</p><blockquote><p>为什么 UDP 头部没有「首部长度」字段,而 TCP 头部有「首部长度」字段呢?</p></blockquote><p>原因是 TCP 有<strong>可变长</strong>的「选项」字段,而 UDP 头部长度则是<strong>不会变化</strong>的,无需多一个字段去记录 UDP 的首部长度。</p><blockquote><p>为什么 UDP 头部有「包长度」字段,而 TCP 头部则没有「包长度」字段呢?</p></blockquote><p>先说说 TCP 是如何计算负载数据长度:</p><p><a href="https://camo.githubusercontent.com/6f672e62b6f5951dd5c3e58392d0a6985072d3c2fe9523e275b5fba87268f78c/68747470733a2f2f696d67636f6e766572742e6373646e696d672e636e2f6148523063484d364c79396a5a473475616e4e6b5a577870646e4975626d56304c32646f4c336870595739736157356a6232526c6369394a6257466e5a556876633351794c7956464f435642525356424d5356464e795642525355354e7956464e69553551795643515356464e795643524355354d5356464e7956435169553551793955513141744a5555304a5549344a5467354a5555324a5546444a5545784a5555324a5468474a5545784a5555324a5467354a5468434a5555314a546b794a5468444a5555314a546c434a546c434a5555324a5546444a5545784a5555324a5468444a5545314a5555324a5467354a5468434c7a457a4c6d70775a773f782d6f73732d70726f636573733d696d6167652f666f726d61742c706e67"><img src="https://camo.githubusercontent.com/6f672e62b6f5951dd5c3e58392d0a6985072d3c2fe9523e275b5fba87268f78c/68747470733a2f2f696d67636f6e766572742e6373646e696d672e636e2f6148523063484d364c79396a5a473475616e4e6b5a577870646e4975626d56304c32646f4c336870595739736157356a6232526c6369394a6257466e5a556876633351794c7956464f435642525356424d5356464e795642525355354e7956464e69553551795643515356464e795643524355354d5356464e7956435169553551793955513141744a5555304a5549344a5467354a5555324a5546444a5545784a5555324a5468474a5545784a5555324a5467354a5468434a5555314a546b794a5468444a5555314a546c434a546c434a5555324a5546444a5545784a5555324a5468444a5545314a5555324a5467354a5468434c7a457a4c6d70775a773f782d6f73732d70726f636573733d696d6167652f666f726d61742c706e67" alt="img"></a></p><p>其中 IP 总长度 和 IP 首部长度,在 IP 首部格式是已知的。TCP 首部长度,则是在 TCP 首部格式已知的,所以就可以求得 TCP 数据的长度。</p><p>这时候有个小问题:“UDP 也是基于 IP 层的呀,那 UDP 的数据长度也可以通过这个公式计算呀?那为什么还要有「包长度」呢?”</p><p>如此一想 确实感觉 UDP 的「包长度」是冗余的</p><p>目前有两种说法</p><ul><li>第一种说法:因为为了网络设备硬件设计和处理方便,首部长度需要是 <code>4</code> 字节的整数倍。如果去掉 UDP 的「包长度」字段,那 UDP 首部长度就不是 <code>4</code> 字节的整数倍了,所以我觉得这可能是为了补全 UDP 首部长度是 <code>4</code> 字节的整数倍,才补充了「包长度」字段。</li><li>第二种说法:如今的 UDP 协议是基于 IP 协议发展的,而当年可能并非如此,依赖的可能是别的不提供自身报文长度或首部长度的网络层协议,因此 UDP 报文首部需要有长度字段以供计算</li></ul>]]></content>
</entry>
<entry>
<title>React技术揭秘——理念2</title>
<link href="/2024/10/26/React-%E5%BA%95%E5%B1%82-2/"/>
<url>/2024/10/26/React-%E5%BA%95%E5%B1%82-2/</url>
<content type="html"><![CDATA[<h1>React16的新架构</h1><p>React16架构可以分为三层:</p><ul><li>Scheduler(调度器)—— 调度任务的优先级,高优任务优先进入<strong>Reconciler</strong></li><li>Reconciler(协调器)—— 负责找出变化的组件</li><li>Renderer(渲染器)—— 负责将变化的组件渲染到页面上</li></ul><p>可以看到,相较于React15,React16中新增了<strong>Scheduler(调度器)</strong>,让我们来了解下他。</p><h3 id="Scheduler(调度器)💇">Scheduler(调度器)💇</h3><p>既然我们以浏览器是否有剩余时间作为任务中断的标准,那么我们需要一种机制,当浏览器有剩余时间时通知我们。</p><p>其实部分浏览器已经实现了这个API,这就是<a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Window/requestIdleCallback">requestIdleCallback</a>。但是由于以下因素,<code>React</code>放弃使用:</p><ul><li>浏览器兼容性</li><li>触发频率不稳定,受很多因素影响。比如当我们的浏览器切换tab后,之前tab注册的<code>requestIdleCallback</code>触发的频率会变得很低</li></ul><p>基于以上原因,<code>React</code>实现了功能更完备的<code>requestIdleCallback</code>polyfill,这就是<strong>Scheduler</strong>。除了在空闲时触发回调的功能外,<strong>Scheduler</strong>还提供了多种调度优先级供任务设置。</p><blockquote><p><a href="https://github.com/facebook/react/blob/1fb18e22ae66fdb1dc127347e169e73948778e5a/packages/scheduler/README.md">Scheduler</a>是独立于<code>React</code>的库</p></blockquote><h3 id="Reconciler(协调器)">Reconciler(协调器)</h3><p>我们知道,在React15中<strong>Reconciler</strong>是递归处理虚拟DOM的。让我们看看<a href="https://github.com/facebook/react/blob/1fb18e22ae66fdb1dc127347e169e73948778e5a/packages/react-reconciler/src/ReactFiberWorkLoop.new.js#L1673">React16的Reconciler</a>。</p><p>我们可以看见,更新工作从递归变成了可以中断的循环过程。每次循环都会调用<code>shouldYield</code>判断当前是否有剩余时间。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">/** <span class="hljs-doctag">@noinline</span> */</span><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">workLoopConcurrent</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-comment">// Perform work until Scheduler asks us to yield</span><br> <span class="hljs-keyword">while</span> (workInProgress !== <span class="hljs-literal">null</span> && !<span class="hljs-title function_">shouldYield</span>()) {<br> workInProgress = <span class="hljs-title function_">performUnitOfWork</span>(workInProgress);<br> }<br>}<br></code></pre></td></tr></table></figure><p>那么React16是如何解决中断更新时DOM渲染不完全的问题呢?</p><p>在React16中,<strong>Reconciler</strong>与<strong>Renderer</strong>不再是交替工作。当<strong>Scheduler</strong>将任务交给<strong>Reconciler</strong>后,<strong>Reconciler</strong>会为变化的虚拟DOM打上代表增/删/更新的标记,类似这样:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> <span class="hljs-title class_">Placement</span> = <span class="hljs-comment">/* */</span> <span class="hljs-number">0b0000000000010</span>;<br><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> <span class="hljs-title class_">Update</span> = <span class="hljs-comment">/* */</span> <span class="hljs-number">0b0000000000100</span>;<br><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> <span class="hljs-title class_">PlacementAndUpdate</span> = <span class="hljs-comment">/* */</span> <span class="hljs-number">0b0000000000110</span>;<br><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> <span class="hljs-title class_">Deletion</span> = <span class="hljs-comment">/* */</span> <span class="hljs-number">0b0000000001000</span>;<br></code></pre></td></tr></table></figure><blockquote><p>全部的标记见<a href="https://github.com/facebook/react/blob/1fb18e22ae66fdb1dc127347e169e73948778e5a/packages/react-reconciler/src/ReactSideEffectTags.js">这里</a></p></blockquote><p>整个<strong>Scheduler</strong>与<strong>Reconciler</strong>的工作都在内存中进行。只有当所有组件都完成<strong>Reconciler</strong>的工作,才会统一交给<strong>Renderer</strong>。</p><blockquote><p>你可以在<a href="https://zh-hans.reactjs.org/docs/codebase-overview.html#fiber-reconciler">这里</a>看到<code>React</code>官方对React16新<strong>Reconciler</strong>的解释</p></blockquote><h3 id="Renderer(渲染器)">Renderer(渲染器)</h3><p><strong>Renderer</strong>根据<strong>Reconciler</strong>为虚拟DOM打的标记,同步执行对应的DOM操作。</p><p><code>state.count = 1</code>,每次点击按钮<code>state.count++</code></p><p>列表中3个元素的值分别为1,2,3乘以<code>state.count</code>的结果</p><p>在React16架构中整个更新流程为:</p><p><img src="https://react.iamkasong.com/img/process.png" alt="更新流程"></p><p>其中红框中的步骤随时可能由于以下原因被中断:</p><ul><li>有其他更高优任务需要先更新</li><li>当前帧没有剩余时间</li></ul><p>由于红框中的工作都在内存中进行,不会更新页面上的DOM,所以即使反复中断,用户也不会看见更新不完全的DOM</p><blockquote><p>接下来看看Fiber是什么?<br>他和Reconciler或者说和React之间是什么关系</p></blockquote><h1>fiber架构的心智模型</h1><blockquote><p>React核心团队成员Sebastian Markbåge(React Hooks的发明者)曾说:我们在React中做的就是践行代数效应(Algebraic Effects)。<br>那么,代数效应是什么呢?他和React有什么关系呢。</p></blockquote><h2 id="什么是代数效应">什么是代数效应</h2><p><code>代数效应</code>是<code>函数式编程</code>中的一个概念,用于将<code>副作用</code>从<code>函数</code>调用中分离。</p><p>接下来我们用<code>虚构的语法</code>来解释。</p><p>假设我们有一个函数<code>getTotalPicNum</code>,传入2个<code>用户名称</code>后,分别查找该用户在平台保存的图片数量,最后将图片数量相加后返回。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">function</span> <span class="hljs-title function_">getTotalPicNum</span>(<span class="hljs-params">user1, user2</span>) {<br> <span class="hljs-keyword">const</span> picNum1 = <span class="hljs-title function_">getPicNum</span>(user1);<br> <span class="hljs-keyword">const</span> picNum2 = <span class="hljs-title function_">getPicNum</span>(user2);<br><br> <span class="hljs-keyword">return</span> picNum1 + picNum2;<br>}<br></code></pre></td></tr></table></figure><p>在<code>getTotalPicNum</code>中,先别关注<code>getPicNum</code>的实现,只在乎“获取到两个数字后将他们相加的结果返回”这一过程。</p><p>接下来我们来实现<code>getPicNum</code>。</p><p>"用户在平台保存的图片数量"是保存在服务器中的。所以,为了获取该值,我们需要发起异步请求。</p><p>为了尽量保持<code>getTotalPicNum</code>的调用方式不变,我们首先想到了使用<code>async await</code>:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">async</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">getTotalPicNum</span>(<span class="hljs-params">user1, user2</span>) {<br> <span class="hljs-keyword">const</span> picNum1 = <span class="hljs-keyword">await</span> <span class="hljs-title function_">getPicNum</span>(user1);<br> <span class="hljs-keyword">const</span> picNum2 = <span class="hljs-keyword">await</span> <span class="hljs-title function_">getPicNum</span>(user2);<br><br> <span class="hljs-keyword">return</span> picNum1 + picNum2;<br>}<br></code></pre></td></tr></table></figure><p>但是,<code>async await</code>是有<code>传染性</code>的 —— 当一个函数变为<code>async</code>后,这意味着调用他的函数也需要是<code>async</code>,这破坏了<code>getTotalPicNum</code>的同步特性。</p><p>有没有什么办法能保持<code>getTotalPicNum</code>保持现有调用方式不变的情况下实现异步请求呢?</p><p>没有。不过我们可以<code>虚构</code>一个。</p><p>我们虚构一个类似<code>try...catch</code>的语法 —— <code>try...handle</code>与两个操作符<code>perform</code>、<code>resume</code>。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">function</span> <span class="hljs-title function_">getPicNum</span>(<span class="hljs-params">name</span>) {<br> <span class="hljs-keyword">const</span> picNum = perform name;<br> <span class="hljs-keyword">return</span> picNum;<br>}<br><br><span class="hljs-keyword">try</span> {<br> <span class="hljs-title function_">getTotalPicNum</span>(<span class="hljs-string">'shanyujia'</span>, <span class="hljs-string">'react'</span>);<br>} handle (who) {<br> <span class="hljs-keyword">switch</span> (who) {<br> <span class="hljs-keyword">case</span> <span class="hljs-string">'shanyujia'</span>:<br> resume <span class="hljs-keyword">with</span> <span class="hljs-number">230</span>;<br> <span class="hljs-keyword">case</span> <span class="hljs-string">'react'</span>:<br> resume <span class="hljs-keyword">with</span> <span class="hljs-number">122</span>;<br> <span class="hljs-attr">default</span>:<br> resume <span class="hljs-keyword">with</span> <span class="hljs-number">0</span>;<br> }<br>}<br></code></pre></td></tr></table></figure><p>当执行到<code>getTotalPicNum</code>内部的<code>getPicNum</code>方法时,会执行<code>perform name</code>。</p><p>此时函数调用栈会从<code>getPicNum</code>方法内跳出,被最近一个<code>try...handle</code>捕获。类似<code>throw Error</code>后被最近一个<code>try...catch</code>捕获。</p><p>类似<code>throw Error</code>后<code>Error</code>会作为<code>catch</code>的参数,<code>perform name</code>后<code>name</code>会作为<code>handle</code>的参数。</p><p>与<code>try...catch</code>最大的不同在于:当<code>Error</code>被<code>catch</code>捕获后,之前的调用栈就销毁了。而<code>handle</code>执行<code>resume</code>后会回到之前<code>perform</code>的调用栈。</p><p>对于<code>case 'kaSong'</code>,执行完<code>resume with 230;</code>后调用栈会回到<code>getPicNum</code>,此时<code>picNum === 230</code></p><blockquote><p>注意⚠️</p><p>再次申明,<code>try...handle</code>的语法是虚构的,看看<code>代数效应</code>的思想。</p></blockquote><p>总结一下:<code>代数效应</code>能够将<code>副作用</code>(例子中为<code>请求图片数量</code>)从函数逻辑中分离,使函数关注点保持纯粹。</p><p>并且,从例子中可以看出,<code>perform resume</code>不需要区分同步异步。</p><h2 id="代数效应在React中的应用">代数效应在React中的应用</h2><p>那么<code>代数效应</code>与<code>React</code>有什么关系呢?最明显的例子就是<code>Hooks</code>。</p><p>对于类似<code>useState</code>、<code>useReducer</code>、<code>useRef</code>这样的<code>Hook</code>,我们不需要关注<code>FunctionComponent</code>的<code>state</code>在<code>Hook</code>中是如何保存的,<code>React</code>会为我们处理。</p><p>我们只需要假设<code>useState</code>返回的是我们想要的<code>state</code>,并编写业务逻辑就行。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">function</span> <span class="hljs-title function_">App</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">const</span> [num, updateNum] = <span class="hljs-title function_">useState</span>(<span class="hljs-number">0</span>);<br> <br> <span class="hljs-keyword">return</span> (<br> <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =></span> updateNum(num => num + 1)}>{num}<span class="hljs-tag"></<span class="hljs-name">button</span>></span></span> <br> )<br>}<br></code></pre></td></tr></table></figure><h2 id="代数效应与Generator">代数效应与Generator</h2><p>从<code>React15</code>到<code>React16</code>,协调器(<code>Reconciler</code>)重构的一大目的是:将老的<code>同步更新</code>的架构变为<code>异步可中断更新</code>。</p><p><code>异步可中断更新</code>可以理解为:<code>更新</code>在执行过程中可能会被打断(浏览器时间分片用尽或有更高优任务插队),当可以继续执行时恢复之前执行的中间状态。</p><p>这就是<code>代数效应</code>中<code>try...handle</code>的作用。</p><p>其实,浏览器原生就支持类似的实现,这就是<code>Generator</code>。</p><p>但是<code>Generator</code>的一些缺陷使<code>React</code>团队放弃了他:</p><ul><li>类似<code>async</code>,<code>Generator</code>也是<code>传染性</code>的,使用了<code>Generator</code>则上下文的其他函数也需要作出改变。这样心智负担比较重。</li><li><code>Generator</code>执行的<code>中间状态</code>是上下文关联的。</li></ul><p>看看下面的🌰</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">function</span>* <span class="hljs-title function_">doWork</span>(<span class="hljs-params">A, B, C</span>) {<br> <span class="hljs-keyword">var</span> x = <span class="hljs-title function_">doExpensiveWorkA</span>(A);<br> <span class="hljs-keyword">yield</span>;<br> <span class="hljs-keyword">var</span> y = x + <span class="hljs-title function_">doExpensiveWorkB</span>(B);<br> <span class="hljs-keyword">yield</span>;<br> <span class="hljs-keyword">var</span> z = y + <span class="hljs-title function_">doExpensiveWorkC</span>(C);<br> <span class="hljs-keyword">return</span> z;<br>}<br></code></pre></td></tr></table></figure><p>每当浏览器有空闲时间都会依次执行其中一个<code>doExpensiveWork</code>,当时间用尽则会中断,当再次恢复时会从中断位置继续执行。</p><p>只考虑“单一优先级任务的中断与继续”情况下<code>Generator</code>可以很好的实现<code>异步可中断更新</code>。</p><p>但是当我们考虑“高优先级任务插队”的情况,如果此时已经完成<code>doExpensiveWorkA</code>与<code>doExpensiveWorkB</code>计算出<code>x</code>与<code>y</code>。</p><p>此时<code>B</code>组件接收到一个<code>高优更新</code>,由于<code>Generator</code>执行的<code>中间状态</code>是上下文关联的,所以计算<code>y</code>时无法复用之前已经计算出的<code>x</code>,需要重新计算。</p><p>如果通过<code>全局变量</code>保存之前执行的<code>中间状态</code>,又会引入新的复杂度。</p><p>基于这些原因,<code>React</code>没有采用<code>Generator</code>实现<code>协调器</code>。</p><h2 id="代数效应与Fiber">代数效应与Fiber</h2><p><code>Fiber</code>并不是计算机术语中的新名词,他的中文翻译叫做<code>纤程</code>,与进程(Process)、线程(Thread)、协程(Coroutine)同为程序执行过程。</p><p>在很多文章中将<code>纤程</code>理解为<code>协程</code>的一种实现。在<code>JS</code>中,<code>协程</code>的实现便是<code>Generator</code>。</p><p>所以,我们可以将<code>纤程</code>(Fiber)、<code>协程</code>(Generator)理解为<code>代数效应</code>思想在<code>JS</code>中的体现。</p><p><code>React Fiber</code>可以理解为:</p><p><code>React</code>内部实现的一套状态更新机制。支持任务不同<code>优先级</code>,可中断与恢复,并且恢复后可以复用之前的<code>中间状态</code>。</p><p>其中每个任务更新单元为<code>React Element</code>对应的<code>Fiber节点</code>。</p><p>接下来,康康<code>Fiber架构</code>的实现</p><h2 id="Fiber的起源">Fiber的起源</h2><blockquote><p>最早的<code>Fiber</code>官方解释来源于<a href="https://github.com/acdlite/react-fiber-architecture">2016年React团队成员Acdlite的一篇介绍</a>。</p></blockquote><p>在<code>React15</code>及以前,<code>Reconciler</code>采用递归的方式创建虚拟DOM,递归过程是不能中断的。如果组件树的层级很深,递归会占用线程很多时间,造成卡顿。</p><p>为了解决这个问题,<code>React16</code>将<strong>递归的无法中断的更新</strong>重构为<strong>异步的可中断更新</strong>,由于曾经用于递归的<strong>虚拟DOM</strong>数据结构已经无法满足需要。于是,全新的<code>Fiber</code>架构应运而生。</p><h2 id="Fiber的含义">Fiber的含义</h2><p><code>Fiber</code>包含三层含义:</p><ol><li>作为架构来说,之前<code>React15</code>的<code>Reconciler</code>采用递归的方式执行,数据保存在递归调用栈中,所以被称为<code>stack Reconciler</code>。<code>React16</code>的<code>Reconciler</code>基于<code>Fiber节点</code>实现,被称为<code>Fiber Reconciler</code>。</li><li>作为静态的数据结构来说,每个<code>Fiber节点</code>对应一个<code>React element</code>,保存了该组件的类型(函数组件/类组件/原生组件…)、对应的DOM节点等信息。</li><li>作为动态的工作单元来说,每个<code>Fiber节点</code>保存了本次更新中该组件改变的状态、要执行的工作(需要被删除/被插入页面中/被更新…)。</li></ol><h2 id="Fiber的结构">Fiber的结构</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">function</span> <span class="hljs-title function_">FiberNode</span>(<span class="hljs-params"></span><br><span class="hljs-params"> tag: WorkTag,</span><br><span class="hljs-params"> pendingProps: mixed,</span><br><span class="hljs-params"> key: <span class="hljs-literal">null</span> | string,</span><br><span class="hljs-params"> mode: TypeOfMode,</span><br><span class="hljs-params"></span>) {<br> <span class="hljs-comment">// 作为静态数据结构的属性</span><br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">tag</span> = tag;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">key</span> = key;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">elementType</span> = <span class="hljs-literal">null</span>;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">type</span> = <span class="hljs-literal">null</span>;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">stateNode</span> = <span class="hljs-literal">null</span>;<br><br> <span class="hljs-comment">// 用于连接其他Fiber节点形成Fiber树</span><br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">return</span> = <span class="hljs-literal">null</span>;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">child</span> = <span class="hljs-literal">null</span>;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">sibling</span> = <span class="hljs-literal">null</span>;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">index</span> = <span class="hljs-number">0</span>;<br><br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">ref</span> = <span class="hljs-literal">null</span>;<br><br> <span class="hljs-comment">// 作为动态的工作单元的属性</span><br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">pendingProps</span> = pendingProps;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">memoizedProps</span> = <span class="hljs-literal">null</span>;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">updateQueue</span> = <span class="hljs-literal">null</span>;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">memoizedState</span> = <span class="hljs-literal">null</span>;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">dependencies</span> = <span class="hljs-literal">null</span>;<br><br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">mode</span> = mode;<br><br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">effectTag</span> = <span class="hljs-title class_">NoEffect</span>;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">nextEffect</span> = <span class="hljs-literal">null</span>;<br><br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">firstEffect</span> = <span class="hljs-literal">null</span>;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">lastEffect</span> = <span class="hljs-literal">null</span>;<br><br> <span class="hljs-comment">// 调度优先级相关</span><br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">lanes</span> = <span class="hljs-title class_">NoLanes</span>;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">childLanes</span> = <span class="hljs-title class_">NoLanes</span>;<br><br> <span class="hljs-comment">// 指向该fiber在另一次更新时对应的fiber</span><br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">alternate</span> = <span class="hljs-literal">null</span>;<br>}<br></code></pre></td></tr></table></figure><h3 id="作为架构来说">作为架构来说</h3><p>每个Fiber节点有个对应的<code>React element</code>,多个<code>Fiber节点</code>是怎么连接形成树呢?用下面三个属性:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 指向父级Fiber节点</span><br><span class="hljs-variable language_">this</span>.<span class="hljs-property">return</span> = <span class="hljs-literal">null</span>;<br><span class="hljs-comment">// 指向子Fiber节点</span><br><span class="hljs-variable language_">this</span>.<span class="hljs-property">child</span> = <span class="hljs-literal">null</span>;<br><span class="hljs-comment">// 指向右边第一个兄弟Fiber节点</span><br><span class="hljs-variable language_">this</span>.<span class="hljs-property">sibling</span> = <span class="hljs-literal">null</span>;<br></code></pre></td></tr></table></figure><p>举个例子,如下的组件结构:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">function</span> <span class="hljs-title function_">App</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">return</span> (<br> <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span></span><br><span class="language-xml"> i am</span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">span</span>></span>KaSong<span class="hljs-tag"></<span class="hljs-name">span</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"></<span class="hljs-name">div</span>></span></span><br> )<br>}<br></code></pre></td></tr></table></figure><p><img src="https://react.iamkasong.com/img/fiber.png" alt=""></p><blockquote><p>这里需要提一下,为什么父级指针叫做<code>return</code>而不是<code>parent</code>或者<code>father</code>呢?因为作为一个工作单元,<code>return</code>指节点执行完<code>completeWork</code>(本章后面会介绍)后会返回的下一个节点。子<code>Fiber节点</code>及其兄弟节点完成工作后会返回其父级节点,所以用<code>return</code>指代父级节点。</p></blockquote><h3 id="作为静态的数据结构">作为静态的数据结构</h3><p>作为一种静态的数据结构,保存了组件相关的信息:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// Fiber对应组件的类型 Function/Class/Host...</span><br><span class="hljs-variable language_">this</span>.<span class="hljs-property">tag</span> = tag;<br><span class="hljs-comment">// key属性</span><br><span class="hljs-variable language_">this</span>.<span class="hljs-property">key</span> = key;<br><span class="hljs-comment">// 大部分情况同type,某些情况不同,比如FunctionComponent使用React.memo包裹</span><br><span class="hljs-variable language_">this</span>.<span class="hljs-property">elementType</span> = <span class="hljs-literal">null</span>;<br><span class="hljs-comment">// 对于 FunctionComponent,指函数本身,对于ClassComponent,指class,对于HostComponent,指DOM节点tagName</span><br><span class="hljs-variable language_">this</span>.<span class="hljs-property">type</span> = <span class="hljs-literal">null</span>;<br><span class="hljs-comment">// Fiber对应的真实DOM节点</span><br><span class="hljs-variable language_">this</span>.<span class="hljs-property">stateNode</span> = <span class="hljs-literal">null</span>;<br></code></pre></td></tr></table></figure><h3 id="作为动态的工作单元">作为动态的工作单元</h3><p>作为动态的工作单元,<code>Fiber</code>中如下参数保存了本次更新相关的信息,我们会在后续的更新流程中使用到具体属性时再详细介绍</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 保存本次更新造成的状态改变相关信息</span><br><span class="hljs-variable language_">this</span>.<span class="hljs-property">pendingProps</span> = pendingProps;<br><span class="hljs-variable language_">this</span>.<span class="hljs-property">memoizedProps</span> = <span class="hljs-literal">null</span>;<br><span class="hljs-variable language_">this</span>.<span class="hljs-property">updateQueue</span> = <span class="hljs-literal">null</span>;<br><span class="hljs-variable language_">this</span>.<span class="hljs-property">memoizedState</span> = <span class="hljs-literal">null</span>;<br><span class="hljs-variable language_">this</span>.<span class="hljs-property">dependencies</span> = <span class="hljs-literal">null</span>;<br><br><span class="hljs-variable language_">this</span>.<span class="hljs-property">mode</span> = mode;<br><br><span class="hljs-comment">// 保存本次更新会造成的DOM操作</span><br><span class="hljs-variable language_">this</span>.<span class="hljs-property">effectTag</span> = <span class="hljs-title class_">NoEffect</span>;<br><span class="hljs-variable language_">this</span>.<span class="hljs-property">nextEffect</span> = <span class="hljs-literal">null</span>;<br><br><span class="hljs-variable language_">this</span>.<span class="hljs-property">firstEffect</span> = <span class="hljs-literal">null</span>;<br><span class="hljs-variable language_">this</span>.<span class="hljs-property">lastEffect</span> = <span class="hljs-literal">null</span>;<br></code></pre></td></tr></table></figure><p>如下两个字段保存调度优先级相关的信息,会在讲解<code>Scheduler</code>时介绍。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 调度优先级相关</span><br><span class="hljs-variable language_">this</span>.<span class="hljs-property">lanes</span> = <span class="hljs-title class_">NoLanes</span>;<br><span class="hljs-variable language_">this</span>.<span class="hljs-property">childLanes</span> = <span class="hljs-title class_">NoLanes</span>;<br></code></pre></td></tr></table></figure><p>注意</p><p>在2020年5月,调度优先级策略经历了比较大的重构。以<code>expirationTime</code>属性为代表的优先级模型被<code>lane</code>取代。可以看看<a href="https://github.com/facebook/react/pull/18796">这个PR</a></p><p>那么<code>Fiber树</code>和页面呈现的<code>DOM树</code>有什么关系,<code>React</code>又是如何更新<code>DOM</code>的呢?</p><p>且听下回分解! (写不动了)🥱</p><h2 id="复活!-补上">复活! 补上</h2><p>我们现在知道了Fiber是什么,知道Fiber节点可以保存对应的DOM节点。<br>相应的,Fiber节点构成的Fiber树就对应DOM树。<br>那么如何更新DOM呢?这需要用到被称为“双缓存”的技术。</p>]]></content>
</entry>
<entry>
<title>React技术揭秘——理念</title>
<link href="/2024/10/06/React-%E5%BA%95%E5%B1%82/"/>
<url>/2024/10/06/React-%E5%BA%95%E5%B1%82/</url>
<content type="html"><![CDATA[<h1>React理念</h1><blockquote><p>感觉就是看了看大概的系统理念 里面还有好多api什么的还没具体去看🤔</p></blockquote><h2 id="React理念">React理念</h2><p>我们可以从官网看到<code>React</code>的理念:</p><blockquote><p>我们认为,React 是用 JavaScript 构建<strong>快速响应</strong>的大型 Web 应用程序的首选方式</p></blockquote><p>可见,关键是实现<code>快速响应</code>。那么制约<code>快速响应</code>的因素是什么呢?</p><p>我们日常使用 App,浏览网页时,有两类场景会制约<code>快速响应</code>:</p><ul><li>当遇到大计算量的操作或者设备性能不足使页面掉帧,导致卡顿。</li><li>发送网络请求后,由于需要等待数据返回才能进一步操作导致不能快速响应。</li></ul><p>这两类场景可以概括为:</p><ul><li>CPU 的瓶颈</li><li>IO 的瓶颈</li></ul><p><code>React</code>是如何解决这两个瓶颈的呢?🤔</p><h3 id="CPU的瓶颈">CPU的瓶颈</h3><p>当项目变得庞大、组件数量繁多时,就容易遇到 CPU 的瓶颈。</p><p>考虑如下 🌰,我们向视图中渲染 3000 个<code>li</code></p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs jsx"><span class="hljs-keyword">function</span> <span class="hljs-title function_">App</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">const</span> len = <span class="hljs-number">3000</span>;<br> <span class="hljs-keyword">return</span> (<br> <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">ul</span>></span></span><br><span class="language-xml"> {Array(len)</span><br><span class="language-xml"> .fill(0)</span><br><span class="language-xml"> .map((_, i) => (</span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">li</span>></span>{i}<span class="hljs-tag"></<span class="hljs-name">li</span>></span></span><br><span class="language-xml"> ))}</span><br><span class="language-xml"> <span class="hljs-tag"></<span class="hljs-name">ul</span>></span></span><br> );<br>}<br><br><span class="hljs-keyword">const</span> rootEl = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">"#root"</span>);<br><span class="hljs-title class_">ReactDOM</span>.<span class="hljs-title function_">render</span>(<span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">App</span> /></span></span>, rootEl);<br></code></pre></td></tr></table></figure><p>主流浏览器刷新频率为 60Hz,即每(1000ms / 60Hz)16.6ms 浏览器刷新一次。</p><p>我们知道,JS 可以操作 DOM,<code>GUI渲染线程</code>与<code>JS线程</code>是互斥的。所以<strong>JS 脚本执行</strong>和<strong>浏览器布局、绘制</strong>不能同时执行。</p><p>在每 16.6ms 时间内,需要完成如下工作:</p><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs markdown">JS脚本执行 ----- 样式布局 ----- 样式绘制<br></code></pre></td></tr></table></figure><p>当 JS 执行时间过长,超出了 16.6ms,这次刷新就没有时间执行<strong>样式布局</strong>和<strong>样式绘制</strong>了。</p><p>在 Demo 中,由于组件数量繁多(3000 个),JS 脚本执行时间过长,页面掉帧,造成卡顿。</p><p>如何解决这个问题呢?</p><p>答案是:在浏览器每一帧的时间中,预留一些时间给 JS 线程,<code>React</code>利用这部分时间更新组件(可以看到,在<a href="https://github.com/facebook/react/blob/1fb18e22ae66fdb1dc127347e169e73948778e5a/packages/scheduler/src/forks/SchedulerHostConfig.default.js#L119">源码</a>中,预留的初始时间是 5ms)。</p><p>当预留的时间不够用时,<code>React</code>将线程控制权交还给浏览器使其有时间渲染 UI,<code>React</code>则等待下一帧时间到来继续被中断的工作。</p><blockquote><p>这种将长任务分拆到每一帧中,像蚂蚁搬家一样一次执行一小段任务的操作,被称为<code>时间切片</code>(time slice)</p></blockquote><p>接下来我们开启<code>Concurrent Mode</code>(目前我知道开启后会启用<code>时间切片</code>😭):</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 通过使用ReactDOM.unstable_createRoot开启Concurrent Mode</span><br><span class="hljs-comment">// ReactDOM.render(<App/>, rootEl);</span><br><span class="hljs-title class_">ReactDOM</span>.<span class="hljs-title function_">unstable_createRoot</span>(rootEl).<span class="hljs-title function_">render</span>(<span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">App</span> /></span></span>);<br></code></pre></td></tr></table></figure><p>此时我们的长任务被拆分到每一帧不同的<code>task</code>中,<code>JS脚本</code>执行时间大体在<code>5ms</code>左右,这样浏览器就有剩余时间执行<strong>样式布局</strong>和<strong>样式绘制</strong>,减少掉帧的可能性。</p><p>所以,解决<code>CPU瓶颈</code>的关键是实现<code>时间切片</code>,而<code>时间切片</code>的关键是:将<strong>同步的更新</strong>变为<strong>可中断的异步更新</strong>。</p><h3 id="IO的瓶颈">IO的瓶颈</h3><p><code>网络延迟</code>是前端开发者无法解决的。如何在<code>网络延迟</code>客观存在的情况下,减少用户对<code>网络延迟</code>的感知?</p><p><code>React</code>给出的答案是<a href="https://zh-hans.reactjs.org/docs/concurrent-mode-intro.html#putting-research-into-production">将人机交互研究的结果整合到真实的 UI 中</a>。</p><p>这里康康业界人机交互最顶尖的苹果如何处理的捏</p><p>在 IOS 系统中:</p><p>点击“设置”面板中的“通用”,进入“通用”界面</p><p><img src="https://react.iamkasong.com/img/legacy-move.gif" alt="ios1"></p><p>作为对比,再点击“设置”面板中的“Siri 与搜索”,进入“Siri 与搜索”界面:</p><p><img src="https://react.iamkasong.com/img/concurrent-mov.gif" alt=""></p><p>能感受到两者体验上的区别么?</p><p>事实上,点击“通用”后的交互是同步的,直接显示后续界面。而点击“Siri 与搜索”后的交互是异步的,需要等待请求返回后再显示后续界面。但从用户感知来看,这两者的区别微乎其微。</p><p>这里的窍门在于:点击“Siri 与搜索”后,先在当前页面停留了一小段时间,这一小段时间被用来请求数据。</p><p>当“这一小段时间”足够短时,用户是无感知的。如果请求时间超过一个范围,再显示<code>loading</code>的效果。</p><p>试想如果我们一点击“Siri 与搜索”就显示<code>loading</code>效果,即使数据请求时间很短,<code>loading</code>效果一闪而过。用户也是可以感知到的。</p><p>为此,<code>React</code>实现了<a href="https://zh-hans.reactjs.org/docs/concurrent-mode-suspense.html">Suspense</a>功能及配套的<code>hook</code>——<a href="https://zh-hans.reactjs.org/docs/concurrent-mode-reference.html#usedeferredvalue">useDeferredValue</a>。</p><p>(这两个还没看具体怎么用 只是知道有这样一个东西)</p><p>而在源码内部,为了支持这些特性,同样需要将<strong>同步的更新</strong>变为<strong>可中断的异步更新</strong>。</p><h2 id="React15">React15</h2><p><code>React</code>从 v15 升级到 v16 后重构了整个架构。康康 v15,看看他为什么不能满足<strong>快速响应</strong>的理念,以至于被重构。</p><h3 id="React15-架构">React15 架构</h3><p>React15 架构可以分为两层:</p><ul><li>Reconciler(协调器)—— 负责找出变化的组件</li><li>Renderer(渲染器)—— 负责将变化的组件渲染到页面</li></ul><h3 id="Reconciler(协调器)">Reconciler(协调器)</h3><p>我们知道,在<code>React</code>中可以通过<code>this.setState</code>、<code>this.forceUpdate</code>、<code>ReactDOM.render</code>等 API 触发更新。</p><p>每当有更新发生时,<strong>Reconciler</strong>会做如下工作:</p><ul><li>调用函数组件、或 class 组件的<code>render</code>方法,将返回的 JSX 转化为虚拟 DOM</li><li>将虚拟 DOM 和上次更新时的虚拟 DOM 对比</li><li>通过对比找出本次更新中变化的虚拟 DOM</li><li>通知<strong>Renderer</strong>将变化的虚拟 DOM 渲染到页面上</li></ul><h3 id="Renderer(渲染器)">Renderer(渲染器)</h3><p>由于<code>React</code>支持跨平台,所以不同平台有不同的<strong>Renderer</strong>。我们前端最熟悉的是负责在浏览器环境渲染的<strong>Renderer</strong> —— <a href="https://www.npmjs.com/package/react-dom">ReactDOM</a>。</p><p>除此之外,还有:</p><ul><li><a href="https://www.npmjs.com/package/react-native">ReactNative</a>渲染器,渲染 App 原生组件</li><li><a href="https://www.npmjs.com/package/react-test-renderer">ReactTest</a>渲染器,渲染出纯 Js 对象用于测试</li><li><a href="https://www.npmjs.com/package/react-art">ReactArt</a>渲染器,渲染到 Canvas, SVG 或 VML (IE8)</li></ul><p>在每次更新发生时,<strong>Renderer</strong>接到<strong>Reconciler</strong>通知,将变化的组件渲染在当前宿主环境。</p><h2 id="React15-架构的缺点">React15 架构的缺点</h2><p>在<strong>Reconciler</strong>中,<code>mount</code>的组件会调用<a href="https://github.com/facebook/react/blob/15-stable/src/renderers/dom/shared/ReactDOMComponent.js#L498">mountComponent</a>,<code>update</code>的组件会调用<a href="https://github.com/facebook/react/blob/15-stable/src/renderers/dom/shared/ReactDOMComponent.js#L877">updateComponent</a>。这两个方法都会递归更新子组件。</p><h3 id="递归更新的缺点"><a href="https://react.iamkasong.com/preparation/oldConstructure.html#%E9%80%92%E5%BD%92%E6%9B%B4%E6%96%B0%E7%9A%84%E7%BC%BA%E7%82%B9">#</a>递归更新的缺点</h3><p>由于递归执行,所以更新一旦开始,中途就无法中断。当层级很深时,递归更新时间超过了 16ms,用户交互就会卡顿。</p><p>刚才已经提出了解决办法——用<strong>可中断的异步更新</strong>代替<strong>同步的更新</strong>。那么 React15 的架构支持异步更新么?</p><p><img src="https://react.iamkasong.com/img/v15.png" alt=""></p><p>我们可以看到,<strong>Reconciler</strong>和<strong>Renderer</strong>是交替工作的,当第一个<code>li</code>在页面上已经变化后,第二个<code>li</code>再进入<strong>Reconciler</strong>。</p><p>由于整个过程都是同步的,所以在用户看来所有 DOM 是同时更新的。</p><p>让我来试试,模拟一下,如果中途中断更新会怎么样?</p><p><img src="https://react.iamkasong.com/img/dist.png" alt=""></p><p>当第一个<code>li</code>完成更新时中断更新,即步骤 3 完成后中断更新,此时后面的步骤都还未执行。</p><p>用户本来期望<code>123</code>变为<code>246</code>。实际却看见更新不完全的 DOM!(即<code>223</code>)</p><p>基于这个原因,<code>React</code>决定重写整个架构。</p>]]></content>
</entry>
<entry>
<title>2024年前端组第一次机试题目</title>
<link href="/2024/10/02/2024%E5%89%8D%E7%AB%AF%E7%AC%AC%E4%B8%80%E6%AC%A1%E6%9C%BA%E8%AF%95/"/>
<url>/2024/10/02/2024%E5%89%8D%E7%AB%AF%E7%AC%AC%E4%B8%80%E6%AC%A1%E6%9C%BA%E8%AF%95/</url>
<content type="html"><![CDATA[<h1>2024年前端组第一次机试题目</h1><h2 id="说在前面的一些悄悄话">说在前面的一些悄悄话</h2><blockquote><p>欢迎大家来参加前端机试, 相信能来参加的你一定是对自己负责的好同学! 请发挥你的聪明才智, 展示你的近期所学, 全力完成下面的题目吧!</p><p>⚠️: 不能在搜索引擎上直接搜索题目, 例如: xxxx效果如何实现? 如有发现, 学长学姐会对你扣分哦</p><p>其中有两道题是附加题 大家记得注意看<br>附加题23必做,24选做!!!</p><p>但是有什么突然忘记了可以呼叫老东西 老东西会根据情况进行一些提示<br>最后有几篇参考文档</p></blockquote><h2 id="1-神奇的树🌲">1.神奇的树🌲</h2><p>为了庆祝圣诞节 我们决定画一棵树来进行气氛上的烘托<br>下面有请你来帮助我们!<br>效果图如下:</p><p><img src="/img/tree.png" alt="树"></p><h2 id="2-好闪!-这是什么!alt-text">2.好闪! 这是什么!<img src="%E9%85%B7.gif" alt="alt text"></h2><p>因为本人朋友喜欢粉嫩的东西,故出了这道花里胡哨的题<br>颜色大小都可以随自己喜好,方法不限,尽可能还原,只要实现以下效果</p><p><img src="/img/%E9%85%B7.gif" alt="酷"></p><blockquote><p>注意事项⚠️</p><ul><li>在鼠标触控表格是有颜色的变化 颜色你自己随意喽 别太丑就好喽</li></ul></blockquote><p>效果如下:</p><h2 id="3-popup领域大神">3.popup领域大神</h2><p>超级无敌的学长让你帮他实现一个特效</p><p><img src="/img/%E6%8A%BD%E5%B1%89.gif" alt="popup"></p><blockquote><p>要求💊</p><ul><li>触碰到按钮时候是有颜色变化的</li><li>退出抽屉时候也是有颜色变化的</li><li>进入和退出的时候丝滑一些捏</li></ul></blockquote><h2 id="4-超级无敌的托马斯大回旋">4.超级无敌的托马斯大回旋</h2><p>这个 logo 是哥们 mini 项目的 logo,也是出自于本人的设计组朋友(快来加入木犀,以后和朋友一起美美写项目</p><blockquote><p>需要实现的要点<br>鼠标移入时顺时针旋转360度,而且还要有其他变化哦(注意仔细观察)</p></blockquote><p><img src="/img/%E5%A4%A7%E5%9B%9E%E6%97%8B1.gif" alt="大旋转"><br>图片在这自提<br><img src="/img/logo.png" alt="logo"></p><h2 id="5-会蹦迪的小球">5.会蹦迪的小球</h2><p>请实现如下特效</p><p><img src="/img/%E4%BC%9A%E8%B9%A6%E8%BF%AA%E7%9A%84%E5%B0%8F%E7%90%83.gif" alt="我 跳跳跳"></p><h2 id="6-哥们-这真不难吧">6.哥们 这真不难吧</h2><blockquote><p> <em>要求:</em></p><p> <em>1:页脚居中且不随页面滑动</em></p><p> <em>2:回到顶部:图片随页面滑动,距离顶部和底部底部某一距离时不再随页面滑动</em><br><em>3: 响应式布局 当页面减小到一定宽度 页面发生变化</em></p></blockquote><p><img src="/img/%E5%93%8D%E5%BA%94%E5%BC%8F%E5%B8%83%E5%B1%80.gif" alt="响应式布局"></p><h2 id="7-什么?!-你也玩吃豆人-附加题">7.什么?! 你也玩吃豆人(附加题)</h2><p>请实现如下特效</p><blockquote><p>这道题看着比较复杂但是拆分开还是不是很难滴~<br>提示:1.可以从css画图形角度来画出"嘴巴"<br>2.以下HTML代码可以作为参考,但是如果有其他实现方法也是可以滴✌🏻<br>PS:动画实在搞不出来可以先画个"嘴巴"和"豆豆"上去,这个也是有步骤分的🥳</p></blockquote><p><img src="/img/%E5%90%83%E8%B1%86%E4%BA%BA.gif" alt="吃豆人"></p><h2 id="8-算法-启动!!!-附加题">8.算法 启动!!!(附加题)</h2><h2 id="第一题">第一题</h2><p>给你一个整数 <code>x</code> ,如果 <code>x</code> 是一个回文整数,返回 <code>true</code> ;否则,返回 <code>false</code> 。</p><p>回文数 是指正序(从左向右)和倒序(从右向左)读都是一样的整数。</p><ul><li>例如,<code>121</code> 是回文,而 <code>123</code> 不是。</li></ul><p><strong>示例 1:</strong></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs js">输入:x = <span class="hljs-number">121</span><br>输出:<span class="hljs-literal">true</span><br></code></pre></td></tr></table></figure><p><strong>示例 2:</strong></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs js">输入:x = -<span class="hljs-number">121</span><br>输出:<span class="hljs-literal">false</span><br>解释:从左向右读, 为 -<span class="hljs-number">121</span> 。 从右向左读, 为 <span class="hljs-number">121</span>- 。因此它不是一个回文数。<br></code></pre></td></tr></table></figure><p><strong>示例 3:</strong></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs js">输入:x = <span class="hljs-number">10</span><br>输出:<span class="hljs-literal">false</span><br>解释:从右向左读, 为 <span class="hljs-number">01</span> 。因此它不是一个回文数。<br></code></pre></td></tr></table></figure><p><strong>提示:</strong></p><ul><li><code>-231 <= x <= 231 - 1</code></li></ul><h4 id="目前已经有的结构">目前已经有的结构</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> {<span class="hljs-type">number</span>} <span class="hljs-variable">x</span></span><br><span class="hljs-comment"> * <span class="hljs-doctag">@return</span> {<span class="hljs-type">boolean</span>}</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">var</span> isPalindrome = <span class="hljs-keyword">function</span>(<span class="hljs-params">x</span>) {<br><br>};<br></code></pre></td></tr></table></figure><h2 id="第二题">第二题</h2><p>给你一个链表,删除链表的倒数第 <code>n</code> 个结点,并且返回链表的头结点。</p><h4 id="目前已经有的结构-v2">目前已经有的结构</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Definition for singly-linked list.</span><br><span class="hljs-comment"> * function ListNode(val, next) {</span><br><span class="hljs-comment"> * this.val = (val===undefined ? 0 : val)</span><br><span class="hljs-comment"> * this.next = (next===undefined ? null : next)</span><br><span class="hljs-comment"> * }</span><br><span class="hljs-comment"> */</span><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> {<span class="hljs-type">ListNode</span>} <span class="hljs-variable">head</span></span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> {<span class="hljs-type">number</span>} <span class="hljs-variable">n</span></span><br><span class="hljs-comment"> * <span class="hljs-doctag">@return</span> {<span class="hljs-type">ListNode</span>}</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">var</span> removeNthFromEnd = <span class="hljs-keyword">function</span>(<span class="hljs-params">head, n</span>) {<br><br>};<br></code></pre></td></tr></table></figure><p><strong>示例1</strong></p><p><img src="https://assets.leetcode.com/uploads/2020/10/03/remove_ex1.jpg" alt="img"></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs js">输入:head = [<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">4</span>,<span class="hljs-number">5</span>], n = <span class="hljs-number">2</span><br>输出:[<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">5</span>]<br></code></pre></td></tr></table></figure><p><strong>示例 2:</strong></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs js">输入:head = [<span class="hljs-number">1</span>], n = <span class="hljs-number">1</span><br>输出:[]<br></code></pre></td></tr></table></figure><p><strong>示例 3:</strong></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs js">输入:head = [<span class="hljs-number">1</span>,<span class="hljs-number">2</span>], n = <span class="hljs-number">1</span><br>输出:[<span class="hljs-number">1</span>]<br></code></pre></td></tr></table></figure><p><strong>提示:</strong></p><ul><li>链表中结点的数目为 <code>sz</code></li><li><code>1 <= sz <= 30</code></li><li><code>0 <= Node.val <= 100</code></li><li><code>1 <= n <= sz</code></li></ul><h1>参考文档</h1><h2 id="animation">animation</h2><p><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS">https://developer.mozilla.org/zh-CN/docs/Web/CSS</a>) <strong>animation</strong> 属性是 <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/animation-name"><code>animation-name</code></a>,<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/animation-duration"><code>animation-duration</code></a>, <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/animation-timing-function"><code>animation-timing-function</code></a>,<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/animation-delay"><code>animation-delay</code></a>,<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/animation-iteration-count"><code>animation-iteration-count</code></a>,<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/animation-direction"><code>animation-direction</code></a>,<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/animation-fill-mode"><code>animation-fill-mode</code></a> 和 <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/animation-play-state"><code>animation-play-state</code></a> 属性的一个简写属性形式。</p><h2 id="尝试一下"><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/animation#%E5%B0%9D%E8%AF%95%E4%B8%80%E4%B8%8B">尝试一下</a></h2><iframe class="interactive is-default-height" height="200" src="https://interactive-examples.mdn.mozilla.net/pages/css/animation.html" title="MDN Web Docs Interactive Example" allow="clipboard-write" loading="lazy" data-readystate="complete" style="box-sizing: border-box; border: none; max-width: 100%; width: 765.711px; background-color: var(--background-secondary); border-radius: var(--elem-radius); color: var(--text-primary); height: 375px; margin: 1rem 0px; padding: 0px;"></iframe><h2 id="语法"><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/animation#%E8%AF%AD%E6%B3%95">语法</a></h2><p>css</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs css"><span class="hljs-comment">/* @keyframes duration | easing-function | delay |</span><br><span class="hljs-comment">iteration-count | direction | fill-mode | play-state | name */</span><br><span class="hljs-attribute">animation</span>: <span class="hljs-number">3s</span> ease-in <span class="hljs-number">1s</span> <span class="hljs-number">2</span> reverse both paused slidein;<br><br><span class="hljs-comment">/* @keyframes duration | easing-function | delay | name */</span><br><span class="hljs-attribute">animation</span>: <span class="hljs-number">3s</span> linear <span class="hljs-number">1s</span> slidein;<br><br><span class="hljs-comment">/* two animations */</span><br><span class="hljs-attribute">animation</span>:<br> <span class="hljs-number">3s</span> linear slidein,<br> <span class="hljs-number">3s</span> ease-out <span class="hljs-number">5s</span> slideout;<br></code></pre></td></tr></table></figure><p><code>animation</code> 属性用来指定一组或多组动画,每组之间用逗号相隔。</p><p>每个动画定义中的值的顺序,对于区分 <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/animation-name"><code>animation-name</code></a> 值与其他关键字也很重要。解析时,对于除 <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/animation-name"><code>animation-name</code></a> 之外的有效的关键字,必须被前面的简写中没有找到值的属性所接受。此外,在序列化时,<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/animation-name"><code>animation-name</code></a> 与以及其他属性值做区分等情况下,必须输出其他属性的默认值。</p><h3 id="语法-v2"><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/animation#%E8%AF%AD%E6%B3%95_2">语法</a></h3><figure class="highlight gherkin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br></pre></td><td class="code"><pre><code class="hljs gherkin">animation = <br> <span class="hljs-variable"><single-animation></span><span class="hljs-comment"># </span><br><br><span class="hljs-variable"><single-animation></span> = <br> <span class="hljs-variable"><time [0s,∞]></span> ||<br> <span class="hljs-variable"><easing-function></span> ||<br> <span class="hljs-variable"><time></span> ||<br> <span class="hljs-variable"><single-animation-iteration-count></span> ||<br> <span class="hljs-variable"><single-animation-direction></span> ||<br> <span class="hljs-variable"><single-animation-fill-mode></span> ||<br> <span class="hljs-variable"><single-animation-play-state></span> ||<br> [ none |<span class="hljs-string"> <keyframes-name> ] </span><br><span class="hljs-string"></span><br><span class="hljs-string"><easing-function> = </span><br><span class="hljs-string"> <linear-easing-function> </span>|<br> <span class="hljs-variable"><cubic-bezier-easing-function></span> |<span class="hljs-string"></span><br><span class="hljs-string"> <step-easing-function> </span><br><span class="hljs-string"></span><br><span class="hljs-string"><single-animation-iteration-count> = </span><br><span class="hljs-string"> infinite </span>|<br> <span class="hljs-variable"><number [0,∞]></span> <br><br><span class="hljs-variable"><single-animation-direction></span> = <br> normal |<span class="hljs-string"></span><br><span class="hljs-string"> reverse </span>|<br> alternate |<span class="hljs-string"></span><br><span class="hljs-string"> alternate-reverse </span><br><span class="hljs-string"></span><br><span class="hljs-string"><single-animation-fill-mode> = </span><br><span class="hljs-string"> none </span>|<br> forwards |<span class="hljs-string"></span><br><span class="hljs-string"> backwards </span>|<br> both <br><br><span class="hljs-variable"><single-animation-play-state></span> = <br> running |<span class="hljs-string"></span><br><span class="hljs-string"> paused </span><br><span class="hljs-string"></span><br><span class="hljs-string"><keyframes-name> = </span><br><span class="hljs-string"> <custom-ident> </span>|<br> <span class="hljs-variable"><string></span> <br><br><span class="hljs-variable"><linear-easing-function></span> = <br> linear |<span class="hljs-string"></span><br><span class="hljs-string"> <linear()> </span><br><span class="hljs-string"></span><br><span class="hljs-string"><cubic-bezier-easing-function> = </span><br><span class="hljs-string"> ease </span>|<br> ease-in |<span class="hljs-string"></span><br><span class="hljs-string"> ease-out </span>|<br> ease-in-out |<span class="hljs-string"></span><br><span class="hljs-string"> <cubic-bezier()> </span><br><span class="hljs-string"></span><br><span class="hljs-string"><step-easing-function> = </span><br><span class="hljs-string"> step-start </span>|<br> step-end |<span class="hljs-string"></span><br><span class="hljs-string"> <steps()> </span><br><span class="hljs-string"></span><br><span class="hljs-string"><linear()> = </span><br><span class="hljs-string"> linear( [ <number> && <percentage>{0,2} ]# ) </span><br><span class="hljs-string"></span><br><span class="hljs-string"><cubic-bezier()> = </span><br><span class="hljs-string"> cubic-bezier( [ <number [0,1]> , <number> ]#{2} ) </span><br><span class="hljs-string"></span><br><span class="hljs-string"><steps()> = </span><br><span class="hljs-string"> steps( <integer> , <step-position>? ) </span><br><span class="hljs-string"></span><br><span class="hljs-string"><step-position> = </span><br><span class="hljs-string"> jump-start </span>|<br> jump-end |<span class="hljs-string"></span><br><span class="hljs-string"> jump-none </span>|<br> jump-both |<span class="hljs-string"></span><br><span class="hljs-string"> start </span>|<br> end <br></code></pre></td></tr></table></figure><h2 id="示例"><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/animation#%E7%A4%BA%E4%BE%8B">示例</a></h2><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs html"><span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"view_port"</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"polling_message"</span>></span>Listening for dispatches<span class="hljs-tag"></<span class="hljs-name">div</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"cylon_eye"</span>></span><span class="hljs-tag"></<span class="hljs-name">div</span>></span><br><span class="hljs-tag"></<span class="hljs-name">div</span>></span><br></code></pre></td></tr></table></figure><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><code class="hljs css"><span class="hljs-selector-class">.polling_message</span> {<br> <span class="hljs-attribute">color</span>: white;<br> <span class="hljs-attribute">float</span>: left;<br> <span class="hljs-attribute">margin-right</span>: <span class="hljs-number">2%</span>;<br>}<br><br><span class="hljs-selector-class">.view_port</span> {<br> <span class="hljs-attribute">background-color</span>: black;<br> <span class="hljs-attribute">height</span>: <span class="hljs-number">25px</span>;<br> <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;<br> <span class="hljs-attribute">overflow</span>: hidden;<br>}<br><br><span class="hljs-selector-class">.cylon_eye</span> {<br> <span class="hljs-attribute">background-color</span>: red;<br> <span class="hljs-attribute">background-image</span>: <span class="hljs-built_in">linear-gradient</span>(<br> to right,<br> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.9</span>) <span class="hljs-number">25%</span>,<br> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.1</span>) <span class="hljs-number">50%</span>,<br> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.9</span>) <span class="hljs-number">75%</span><br> );<br> <span class="hljs-attribute">color</span>: white;<br> <span class="hljs-attribute">height</span>: <span class="hljs-number">100%</span>;<br> <span class="hljs-attribute">width</span>: <span class="hljs-number">20%</span>;<br><br> -webkit-<span class="hljs-attribute">animation</span>: <span class="hljs-number">4s</span> linear <span class="hljs-number">0s</span> infinite alternate move_eye;<br> <span class="hljs-attribute">animation</span>: <span class="hljs-number">4s</span> linear <span class="hljs-number">0s</span> infinite alternate move_eye;<br>}<br><br><span class="hljs-keyword">@-webkit-keyframes</span> move_eye {<br> <span class="hljs-selector-tag">from</span> {<br> <span class="hljs-attribute">margin-left</span>: -<span class="hljs-number">20%</span>;<br> }<br> <span class="hljs-selector-tag">to</span> {<br> <span class="hljs-attribute">margin-left</span>: <span class="hljs-number">100%</span>;<br> }<br>}<br><span class="hljs-keyword">@keyframes</span> move_eye {<br> <span class="hljs-selector-tag">from</span> {<br> <span class="hljs-attribute">margin-left</span>: -<span class="hljs-number">20%</span>;<br> }<br> <span class="hljs-selector-tag">to</span> {<br> <span class="hljs-attribute">margin-left</span>: <span class="hljs-number">100%</span>;<br> }<br>}<br></code></pre></td></tr></table></figure><h2 id="keyframes">@keyframes</h2><p>关键帧 <strong><code>@keyframes</code></strong> <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/At-rule">at-rule</a> 规则通过在动画序列中定义关键帧(或 waypoints)的样式来控制 CSS 动画序列中的中间步骤。和 <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_transitions">转换 transition</a> 相比,关键帧 keyframes 可以控制动画序列的中间步骤</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs css"><span class="hljs-keyword">@keyframes</span> slidein {<br> <span class="hljs-selector-tag">from</span> {<br> <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translateX</span>(<span class="hljs-number">0%</span>);<br> }<br><br> <span class="hljs-selector-tag">to</span> {<br> <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translateX</span>(<span class="hljs-number">100%</span>);<br> }<br>}。<br></code></pre></td></tr></table></figure><p>要使用关键帧,先创建一个带名称的 <code>@keyframes</code> 规则,以便后续使用 <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/animation-name"><code>animation-name</code></a> 属性将动画同其关键帧声明匹配。每个 <code>@keyframes</code> 规则包含多个关键帧,也就是一段样式块语句,每个关键帧有一个百分比值作为名称,代表在动画进行中,在哪个阶段触发这个帧所包含的样式。</p><p>可以按任意顺序列出关键帧百分比;它们将按照其应该发生的顺序来处理。</p><h3 id="让关键帧序列生效"><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/@keyframes#%E8%AE%A9%E5%85%B3%E9%94%AE%E5%B8%A7%E5%BA%8F%E5%88%97%E7%94%9F%E6%95%88">让关键帧序列生效</a></h3><p>如果一个关键帧规则没有指定动画的开始或结束状态(也就是,<code>0%</code>/<code>from</code> 和<code>100%</code>/<code>to</code>,浏览器将使用元素的现有样式作为起始/结束状态。这可以用来从初始状态开始元素动画,最终返回初始状态。</p><p>如果在关键帧的样式中使用了不能用作动画的属性,那么这些属性会被忽略掉,支持动画的属性仍然是有效的,不受波及。</p><h3 id="重复定义"><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/@keyframes#%E9%87%8D%E5%A4%8D%E5%AE%9A%E4%B9%89">重复定义</a></h3><p>如果多个关键帧使用同一个名称,以最后一次定义的为准。 <code>@keyframes</code> 不存在层叠样式 (cascade) 的情况,所以动画在一个时刻(阶段)只会使用一个的关键帧的数据。</p><p>如果一个 @keyframes 内的关键帧的百分比存在重复的情况,则 @keyframes 规则中该百分比的所有关键帧都将用于该帧。如果多个关键帧指定了相同的百分比值,则 @keyframes 规则内是可以使用层叠样式的。</p><h3 id="属性个数不定"><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/@keyframes#%E5%B1%9E%E6%80%A7%E4%B8%AA%E6%95%B0%E4%B8%8D%E5%AE%9A">属性个数不定</a></h3><p>如果一个关键帧中没有出现其他关键帧中的属性,那么这个属性将使用插值(不能使用插值的属性除外,这些属性会被忽略掉)。例如:</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs css"><span class="hljs-keyword">@keyframes</span> identifier {<br> <span class="hljs-number">0%</span> {<br> <span class="hljs-attribute">top</span>: <span class="hljs-number">0</span>;<br> <span class="hljs-attribute">left</span>: <span class="hljs-number">0</span>;<br> }<br> <span class="hljs-number">30%</span> {<br> <span class="hljs-attribute">top</span>: <span class="hljs-number">50px</span>;<br> }<br> <span class="hljs-number">68%</span>,<br> <span class="hljs-number">72%</span> {<br> <span class="hljs-attribute">left</span>: <span class="hljs-number">50px</span>;<br> }<br> <span class="hljs-number">100%</span> {<br> <span class="hljs-attribute">top</span>: <span class="hljs-number">100px</span>;<br> <span class="hljs-attribute">left</span>: <span class="hljs-number">100%</span>;<br> }<br>}<br><br></code></pre></td></tr></table></figure><h3 id="同一关键帧中的相同属性被重复定义"><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/@keyframes#%E5%90%8C%E4%B8%80%E5%85%B3%E9%94%AE%E5%B8%A7%E4%B8%AD%E7%9A%84%E7%9B%B8%E5%90%8C%E5%B1%9E%E6%80%A7%E8%A2%AB%E9%87%8D%E5%A4%8D%E5%AE%9A%E4%B9%89">同一关键帧中的相同属性被重复定义</a></h3><p>如果某一个关键帧出现了重复的定义,且重复的关键帧中的 CSS 属性值不同,则以最后一次定义的属性为准。例如:</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs css"><span class="hljs-keyword">@keyframes</span> identifier {<br> <span class="hljs-number">0%</span> {<br> <span class="hljs-attribute">top</span>: <span class="hljs-number">0</span>;<br> }<br> <span class="hljs-number">50%</span> {<br> <span class="hljs-attribute">top</span>: <span class="hljs-number">30px</span>;<br> <span class="hljs-attribute">left</span>: <span class="hljs-number">20px</span>;<br> }<br> <span class="hljs-number">50%</span> {<br> <span class="hljs-attribute">top</span>: <span class="hljs-number">10px</span>;<br> }<br> <span class="hljs-number">100%</span> {<br> <span class="hljs-attribute">top</span>: <span class="hljs-number">0</span>;<br> }<br>}<br></code></pre></td></tr></table></figure><p>上面这个例子中,<code>50%</code> 关键帧中分别最后设置的属性 <code>top: 10px</code> 和 <code>left: 20px</code> 是有效的,但是其他的属性会被忽略。</p><h3 id="关键帧中的-important"><a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/@keyframes#%E5%85%B3%E9%94%AE%E5%B8%A7%E4%B8%AD%E7%9A%84_!important">关键帧中的 <code>!important</code></a></h3><p>关键帧中出现的 <code>!important</code> 将会被忽略。</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><code class="hljs css"><span class="hljs-keyword">@keyframes</span> important1 {<br> <span class="hljs-selector-tag">from</span> {<br> <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">50px</span>;<br> }<br> <span class="hljs-number">50%</span> {<br> <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">150px</span> <span class="hljs-meta">!important</span>;<br> } <span class="hljs-comment">/* 忽略 */</span><br> <span class="hljs-selector-tag">to</span> {<br> <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">100px</span>;<br> }<br>}<br><br><span class="hljs-keyword">@keyframes</span> important2 {<br> <span class="hljs-selector-tag">from</span> {<br> <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">50px</span>;<br> <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">100px</span>;<br> }<br> <span class="hljs-selector-tag">to</span> {<br> <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">150px</span> <span class="hljs-meta">!important</span>; <span class="hljs-comment">/* 忽略 */</span><br> <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">50px</span>;<br> }<br>}<br><br></code></pre></td></tr></table></figure>]]></content>
</entry>
<entry>
<title>YOLO初体验</title>
<link href="/2024/08/29/YOLO%E5%88%9D%E4%BD%93%E9%AA%8C/"/>
<url>/2024/08/29/YOLO%E5%88%9D%E4%BD%93%E9%AA%8C/</url>
<content type="html"><![CDATA[<h1>YOLO初体验</h1><p>也是炼上丹了</p><p>这篇可能主要是记录一些方法 可能跟之前写的分享不太一样</p><p>yolo训练阶段</p><p>验证模型</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs python">yolo detect val data=YOLOv8_cs/datasets/page_seg/page_icon.yaml model=YOLOv8_cs/runs/detect/best.pt batch=<span class="hljs-number">4</span><br></code></pre></td></tr></table></figure><p>训练自己的数据集 我这个用的是coco128数据集的格式</p><p>首先要有 img文件夹 放自己要训练的图片</p><p>然后你需要 在label文件夹 放出自己标注出来的txt</p><p>然后还需要写个解释文件</p><p>belike:</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><code class="hljs yaml"><span class="hljs-comment"># Ultralytics YOLOv5 🚀, AGPL-3.0 license</span><br><span class="hljs-comment"># COCO128 dataset https://www.kaggle.com/ultralytics/coco128 (first 128 images from COCO train2017) by Ultralytics</span><br><span class="hljs-comment"># Example usage: python train.py --data coco128.yaml</span><br><span class="hljs-comment"># parent</span><br><span class="hljs-comment"># ├── yolov5</span><br><span class="hljs-comment"># └── datasets</span><br><span class="hljs-comment"># └── coco128 ← downloads here (7 MB)</span><br><br><span class="hljs-comment"># Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..]</span><br><span class="hljs-attr">path:</span> <span class="hljs-string">/Users/shanyujia/学习资料/课外学习/开源之夏/inula-code-generator/YOLOv8_cs/datasets/page_seg</span> <span class="hljs-comment"># dataset root dir</span><br><span class="hljs-attr">train:</span> <span class="hljs-string">images/train</span> <span class="hljs-comment"># train images (relative to 'path') 128 images</span><br><span class="hljs-attr">val:</span> <span class="hljs-string">images/train</span> <span class="hljs-comment"># val images (relative to 'path') 128 images</span><br><span class="hljs-attr">test:</span> <span class="hljs-comment"># test images (optional)</span><br><br><span class="hljs-comment"># Classes</span><br><span class="hljs-attr">names:</span><br> <span class="hljs-attr">0:</span> <span class="hljs-string">Header</span><br> <span class="hljs-attr">1:</span> <span class="hljs-string">Footer</span><br> <span class="hljs-attr">2:</span> <span class="hljs-string">Navbar</span><br> <span class="hljs-attr">3:</span> <span class="hljs-string">Sidebar</span><br> <span class="hljs-attr">4:</span> <span class="hljs-string">Button</span><br> <span class="hljs-attr">5:</span> <span class="hljs-string">Text</span><br> <span class="hljs-attr">6:</span> <span class="hljs-string">Image</span><br> <span class="hljs-attr">7:</span> <span class="hljs-string">Input</span><br> <span class="hljs-attr">8:</span> <span class="hljs-string">Checkbox</span><br> <span class="hljs-attr">9:</span> <span class="hljs-string">Radio</span><br> <span class="hljs-attr">10:</span> <span class="hljs-string">Dropdown</span><br> <span class="hljs-attr">11:</span> <span class="hljs-string">Form</span><br> <span class="hljs-attr">12:</span> <span class="hljs-string">Link</span><br> <span class="hljs-attr">13:</span> <span class="hljs-string">Table</span><br> <span class="hljs-attr">14:</span> <span class="hljs-string">Card</span><br> <span class="hljs-attr">15:</span> <span class="hljs-string">Modal</span><br> <span class="hljs-attr">16:</span> <span class="hljs-string">Icon</span><br> <span class="hljs-attr">17:</span> <span class="hljs-string">Logo</span><br> <span class="hljs-attr">18:</span> <span class="hljs-string">Slider</span><br> <span class="hljs-attr">19:</span> <span class="hljs-string">Search</span><br> <span class="hljs-attr">20:</span> <span class="hljs-string">Select</span><br> <span class="hljs-attr">21:</span> <span class="hljs-string">Video</span><br> <span class="hljs-attr">22:</span> <span class="hljs-string">Pagination</span><br> <span class="hljs-attr">23:</span> <span class="hljs-string">Carousel</span><br> <span class="hljs-attr">24:</span> <span class="hljs-string">Tabs</span><br></code></pre></td></tr></table></figure><p>然后执行训练命令</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs routeros">yolo detect train <span class="hljs-attribute">data</span>=datasets/button.v3i.yolov8/data.yaml <span class="hljs-attribute">model</span>=yolov8n.yaml <span class="hljs-attribute">pretrained</span>=ultralytics/yolov8n.pt <span class="hljs-attribute">epochs</span>=100 <span class="hljs-attribute">batch</span>=4 <span class="hljs-attribute">lr0</span>=0.01 <span class="hljs-attribute">resume</span>=<span class="hljs-literal">True</span><br></code></pre></td></tr></table></figure>]]></content>
</entry>
<entry>
<title>Docker</title>
<link href="/2024/08/18/Docker/"/>
<url>/2024/08/18/Docker/</url>
<content type="html"><![CDATA[<h1>Docker</h1><h2 id="Docker简介">Docker简介</h2><p>Docker是一个用于 build run share 应用程序的平台</p><p>将应用程序+依赖+balabala全部打包!!</p><h2 id="和虚拟机区别">和虚拟机区别</h2><p>Docker VS 虚拟机</p><p>虚拟机需要占用大量资源 CPU,内存</p><p>虚拟机启动一个完整的操作系统</p><p>可能只需要Web服务器</p><p>Docker和容器是两个概念</p><p>Docker是容器一种实现 是一个容器化的解决和平台</p><h2 id=""></h2>]]></content>
</entry>
<entry>
<title>js类型转换</title>
<link href="/2024/08/17/js%E7%B1%BB%E5%9E%8B%E8%BD%AC%E6%8D%A2/"/>
<url>/2024/08/17/js%E7%B1%BB%E5%9E%8B%E8%BD%AC%E6%8D%A2/</url>
<content type="html"><![CDATA[<h1><code>Javascript</code>隐式类型转换</h1><h2 id="类型都有什么">类型都有什么</h2><ul><li>Number</li><li>String</li><li>Boolean</li><li>Null</li><li>Undefined</li><li>Object</li><li>Symbol (ES2015)</li><li>BigInt (ESNext stage 4)</li></ul><p>是不是感觉还有Function,毕竟能用<strong>typeof</strong>获取到?不,函数、数组都是Object的子类型。</p><p>类型分为<code>基本类型</code>和<code>复合类型</code>两种,除了对象,其它都是基本类型</p><h3 id="接下来有请重量级嘉宾">接下来有请重量级嘉宾</h3><h2 id="To-Primitive">To Primitive</h2><p>结构:toPrimitive(input: <strong>any</strong>, preferedType?: <strong>‘string’ |‘number’</strong>)<br>作用:内部方法,将任意值转换成原始值</p><p>转换规则:</p><ol><li>如果是基本类型,则不处理。</li><li>调用<code>valueOf()</code>,并确保返回值是基本类型。</li><li>如果没有valueOf这个方法或者valueOf返回的类型不是基本类型,那么对象会继续调用<code>toString()</code>方法。</li><li>如果同时没有valueOf和toString方法,或者返回的都不是基本类型,那么直接抛出<code>TypeError</code>异常。</li></ol><blockquote><p>注意:如果<strong>preferedType=string</strong>,那么2、3顺序调换</p></blockquote><p>接着,我们看下各个对象的转换实现</p><table><thead><tr><th>对象</th><th>valueOf()</th><th>toString()</th><th>默认 preferedType</th></tr></thead><tbody><tr><td>Object</td><td>原值</td><td>“[object Object]”</td><td>Number</td></tr><tr><td>Function</td><td>原值</td><td>“function xyz() {…}”</td><td>Number</td></tr><tr><td>Array</td><td>原值</td><td>“x,y,z”</td><td>Number</td></tr><tr><td>Date</td><td>数字</td><td>“Sat May 22 2021…”</td><td>String</td></tr></tbody></table><ol><li>数组的toString()可以等效为<code>join(",")</code>,遇到null, undefined都被忽略,遇到symbol直接报错,遇到无法ToPrimitive的对象也报错。</li><li>使用<code>模板字符串</code>或者使用<code>String(...)</code>包装时,preferedType=string,即优先调用 .toString()。</li><li>使用<code>减法</code>或者<code>Number(...)</code>包装时,preferedType=number,即优先调用<code>.valueOf()</code></li></ol><p>接下来看几个🌰</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs javascript">[<span class="hljs-number">1</span>, <span class="hljs-literal">null</span>, <span class="hljs-literal">undefined</span>, <span class="hljs-number">2</span>].<span class="hljs-title function_">toString</span>() === <span class="hljs-string">'1,,,2'</span>;<br><br><span class="hljs-comment">// Uncaught TypeError: Cannot convert a Symbol value to a string</span><br>[<span class="hljs-number">1</span>, <span class="hljs-title class_">Symbol</span>(<span class="hljs-string">'x'</span>)].<span class="hljs-title function_">toString</span>()<br><br><span class="hljs-comment">// Uncaught TypeError: Cannot convert object to primitive value</span><br>[<span class="hljs-number">1</span>, <span class="hljs-title class_">Object</span>.<span class="hljs-title function_">create</span>(<span class="hljs-literal">null</span>)].<span class="hljs-title function_">toString</span>()<br></code></pre></td></tr></table></figure><h2 id="ToNumber">ToNumber</h2><p>一些特殊值转为数字的例子,等下要用到</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-title class_">Number</span>(<span class="hljs-string">"0"</span>) === <span class="hljs-number">0</span>;<br><span class="hljs-title class_">Number</span>(<span class="hljs-string">""</span>) === <span class="hljs-number">0</span>;<br><span class="hljs-title class_">Number</span>(<span class="hljs-string">" "</span>) === <span class="hljs-number">0</span>;<br><span class="hljs-title class_">Number</span>(<span class="hljs-string">"\n"</span>) === <span class="hljs-number">0</span>;<br><span class="hljs-title class_">Number</span>(<span class="hljs-string">"\t"</span>) === <span class="hljs-number">0</span>;<br><span class="hljs-title class_">Number</span>(<span class="hljs-literal">null</span>) === <span class="hljs-number">0</span>;<br><span class="hljs-title class_">Number</span>(<span class="hljs-literal">false</span>) === <span class="hljs-number">0</span>;<br><span class="hljs-title class_">Number</span>(<span class="hljs-literal">true</span>) === <span class="hljs-number">1</span>;<br><span class="hljs-title class_">Number</span>(<span class="hljs-literal">undefined</span>); <span class="hljs-comment">// NaN</span><br><span class="hljs-title class_">Number</span>(<span class="hljs-string">"x"</span>); <span class="hljs-comment">// NaN</span><br></code></pre></td></tr></table></figure><h2 id="加减法-±">加减法 ±</h2><p>加减法运算中遵循了一些隐式转换规则:</p><h5 id="遇到对象先执行ToPrimitive转换为基本类型">遇到对象先执行ToPrimitive转换为基本类型</h5><ul><li><strong>加法</strong>(+)运算,preferedType是默认值</li><li><strong>减法</strong>(-)运算,preferedType是Number</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">// {}.toString() === "[object Object]"</span><br><span class="hljs-number">1</span> + {} === <span class="hljs-string">"1[object Object]"</span><br><br><span class="hljs-comment">// [2, 3].toString() === "2,3"</span><br><span class="hljs-number">1</span> + [<span class="hljs-number">2</span>, <span class="hljs-number">3</span>] === <span class="hljs-string">"12,3"</span><br>[<span class="hljs-number">1</span>] + [<span class="hljs-number">2</span>, <span class="hljs-number">3</span>] === <span class="hljs-string">"1,2,3"</span><br><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">test</span>(<span class="hljs-params"></span>) {}<br><span class="hljs-comment">// test.toString() === "function test() {}"</span><br><span class="hljs-number">10</span> + test === <span class="hljs-string">"10function test() {}"</span><br></code></pre></td></tr></table></figure><h5 id="非字符串-非字符串,两边都会先ToNumber">非字符串 + 非字符串,两边都会先ToNumber</h5><p>这里的非字符串都是指基本类型,因为对象会先执行ToPrimitive变成基础类型</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-number">1</span> + <span class="hljs-literal">true</span> === <span class="hljs-number">2</span><br><span class="hljs-number">1</span> + <span class="hljs-literal">false</span> === <span class="hljs-number">1</span><br><span class="hljs-number">1</span> + <span class="hljs-literal">null</span> === <span class="hljs-number">1</span><br><span class="hljs-number">1</span> + <span class="hljs-literal">null</span> + <span class="hljs-literal">false</span> + <span class="hljs-number">1</span> === <span class="hljs-number">2</span><br><span class="hljs-number">1</span> + <span class="hljs-literal">undefined</span> <span class="hljs-comment">// NaN</span><br><span class="hljs-number">1</span> + <span class="hljs-literal">undefined</span> + <span class="hljs-literal">false</span> <span class="hljs-comment">// NaN</span><br><span class="hljs-number">1</span> + <span class="hljs-literal">undefined</span> + [<span class="hljs-number">1</span>] === <span class="hljs-string">"NaN1"</span><br><span class="hljs-number">1</span> + <span class="hljs-literal">undefined</span> + <span class="hljs-string">"1"</span> === <span class="hljs-string">"NaN1"</span><br><span class="hljs-literal">null</span> + <span class="hljs-literal">null</span> === <span class="hljs-number">0</span><br><br><span class="hljs-comment">// 1 + false</span><br><span class="hljs-number">1</span> + ![] === <span class="hljs-number">1</span><br><span class="hljs-number">1</span> + !{} === <span class="hljs-number">1</span><br>!{} + !{} === <span class="hljs-number">0</span><br></code></pre></td></tr></table></figure><p><strong>1 + undefined + [1] === “NaN1”</strong></p><p>•<strong>1 + undefined</strong> <strong>部分</strong>:</p><p>•如前所述,1 + undefined 的结果是 NaN。</p><p>•<strong>NaN + [1]</strong>:</p><p>•[1] 是一个数组对象,当数组对象与非字符串类型相加时,JavaScript会调用它的 toString() 方法,将数组转换为字符串。</p><p>•[1].toString() 返回 “1”。</p><p>•因此,NaN + [1] 等同于 NaN + “1”。</p><p>•NaN 被隐式转换为字符串 “NaN”,然后与 “1” 进行字符串连接。</p><h5 id="任意值-任意值,一律执行ToNumber,进行数字运算。">任意值 - 任意值,一律执行ToNumber,进行数字运算。</h5><p>此时的 preferedType === number</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-number">3</span> - <span class="hljs-number">1</span> === <span class="hljs-number">2</span><br><span class="hljs-number">3</span> - <span class="hljs-string">'1'</span> === <span class="hljs-number">2</span><br><span class="hljs-string">'3'</span> - <span class="hljs-number">1</span> === <span class="hljs-number">2</span><br><span class="hljs-string">'3'</span> - <span class="hljs-string">'1'</span> - <span class="hljs-string">'2'</span> === <span class="hljs-number">0</span><br><br><span class="hljs-comment">// [].toString() => "" => Number(...) => 0</span><br><span class="hljs-number">3</span> - [] === <span class="hljs-number">3</span><br><br><span class="hljs-comment">// {}.toString() => "[object Object]" => Number(...) => NaN</span><br><span class="hljs-number">3</span> - {} <span class="hljs-comment">// NaN</span><br><br><span class="hljs-comment">// Date的默认preferedType === string</span><br><span class="hljs-keyword">var</span> date = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Date</span>();<br>date.<span class="hljs-property">toString</span> = <span class="hljs-function">() =></span> <span class="hljs-string">'str'</span>;<br>date.<span class="hljs-property">valueOf</span> = <span class="hljs-function">() =></span> <span class="hljs-number">123</span>;<br><br>date + <span class="hljs-number">1</span> === <span class="hljs-string">'str1'</span>;<br>date - <span class="hljs-number">1</span> = <span class="hljs-number">122</span>;<br></code></pre></td></tr></table></figure><p>再看<code>[] + {}</code>,这样是不是就easy</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs javascript">[].<span class="hljs-title function_">toString</span>() === <span class="hljs-string">""</span>;<br>{}.<span class="hljs-title function_">toString</span>() === <span class="hljs-string">"[object Object]"</span>;<br><br>[] + {} === <span class="hljs-string">"[object Object]"</span>;<br></code></pre></td></tr></table></figure><h5 id="在最前面时可能不再是对象">{} 在最前面时可能不再是对象</h5><p>不是对象是什么?别急,看看经典的例子</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs javascript">{} + [] === <span class="hljs-number">0</span>;<br>{ <span class="hljs-attr">a</span>: <span class="hljs-number">2</span> } + [] === <span class="hljs-number">0</span>;<br></code></pre></td></tr></table></figure><p>这啥玩意?说好的"[object Object]"呢?</p><p>好吧,这是<code>{}</code>其实代表的是<strong>代码块</strong>,最后就变成了<code>+ []</code>,根据前面的原则,数组先被转换成字符串<code>""</code>,接着因为+x的运算,字符串被转成数字<code>0</code>。</p><p>那 { a: 2 } 总该是对象了吧?其实这时候<code>a</code>不是代表对象属性,而是被当成了标签(label),标签这东西IE6就已经有了。所以如果我们写成对象是会报错的,逗号要改成分号才能通过编译。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">// Uncaught SyntaxError: Unexpected token ':'</span><br>{ <span class="hljs-attr">a</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">b</span>: <span class="hljs-number">3</span> } + []<br><br><span class="hljs-comment">// 分号OK</span><br>{ <span class="hljs-attr">a</span>: <span class="hljs-number">2</span>; <span class="hljs-attr">b</span>: <span class="hljs-number">3</span> } + [] === <span class="hljs-number">0</span>;<br></code></pre></td></tr></table></figure><h5 id="symbol不能加减">symbol不能加减</h5><p>如果在表达式中有symbol类型,那么就会直接报错。比如<code>1 + Symbol("x")</code>报错如下:</p><figure class="highlight livecodeserver"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs livecodeserver">Uncaught TypeError: Cannot <span class="hljs-built_in">convert</span> <span class="hljs-keyword">a</span> Symbol <span class="hljs-built_in">value</span> <span class="hljs-built_in">to</span> <span class="hljs-keyword">a</span> <span class="hljs-built_in">number</span><br></code></pre></td></tr></table></figure><h2 id="宽松相等">宽松相等 ==</h2><p>相等于全等都需要对类型进行判断,当类型不一致时,宽松相等会触发隐式转换。下面介绍规则:</p><h5 id="对象-对象,类型一致则不做转换">对象 == 对象,类型一致则不做转换</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs javascript">{} != {}<br>[] != {}<br>[] != []<br></code></pre></td></tr></table></figure><h5 id="对象-基本值,对象先执行ToPrimitive转换为基本类型">对象 == 基本值,对象先执行ToPrimitive转换为基本类型</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">// 小心代码块</span><br><span class="hljs-string">"[object Object]"</span> == {}<br>[] == <span class="hljs-string">""</span><br>[<span class="hljs-number">1</span>] == <span class="hljs-string">"1"</span><br>[<span class="hljs-number">1</span>,<span class="hljs-number">2</span>] == <span class="hljs-string">"1,2"</span><br></code></pre></td></tr></table></figure><h5 id="布尔值-非布尔值,布尔值先转换成数字,再按数字规则操作">布尔值 == 非布尔值,布尔值先转换成数字,再按数字规则操作</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">// [] => "" => Number(...) => 0</span><br><span class="hljs-comment">// false => 0</span><br>[] == <span class="hljs-literal">false</span><br><br><span class="hljs-comment">// [1] => "1" => 1</span><br><span class="hljs-comment">// true => 1</span><br>[<span class="hljs-number">1</span>] == <span class="hljs-literal">true</span><br><br><span class="hljs-comment">// [1,2] => "1,2" => NaN</span><br><span class="hljs-comment">// true => 1</span><br>[<span class="hljs-number">1</span>,<span class="hljs-number">2</span>] != <span class="hljs-literal">true</span><br><br><span class="hljs-string">"0"</span> == <span class="hljs-literal">false</span><br><span class="hljs-string">""</span> == <span class="hljs-literal">false</span><br></code></pre></td></tr></table></figure><h5 id="数字-字符串,字符串ToNumber转换成数字">数字 == 字符串,字符串ToNumber转换成数字</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-string">"2"</span> == <span class="hljs-number">2</span><br>[] == <span class="hljs-number">0</span><br>[<span class="hljs-number">1</span>] == <span class="hljs-number">1</span><br><span class="hljs-comment">// [1,2].toString() => "1,2" => Number(...) => NaN</span><br>[<span class="hljs-number">1</span>,<span class="hljs-number">2</span>] != <span class="hljs-number">1</span><br></code></pre></td></tr></table></figure><h5 id="null、undefined、symbol">null、undefined、symbol</h5><p>null、undefined与任何非自身的值对比结果都是false,但是<code>null == undefined</code> 是一个特例。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-literal">null</span> == <span class="hljs-literal">null</span><br><span class="hljs-literal">undefined</span> == <span class="hljs-literal">undefined</span><br><span class="hljs-literal">null</span> == <span class="hljs-literal">undefined</span><br><br><span class="hljs-literal">null</span> != <span class="hljs-number">0</span><br><span class="hljs-literal">null</span> != <span class="hljs-literal">false</span><br><br><span class="hljs-literal">undefined</span> != <span class="hljs-number">0</span><br><span class="hljs-literal">undefined</span> != <span class="hljs-literal">false</span><br><br><span class="hljs-title class_">Symbol</span>(<span class="hljs-string">'x'</span>) != <span class="hljs-title class_">Symbol</span>(<span class="hljs-string">'x'</span>)<br></code></pre></td></tr></table></figure><h2 id="对比">对比 < ></h2><p>对比不像相等,可以严格相等(===)防止类型转换,对比一定会存在隐式类型转换。</p><h5 id="对象总是先执行ToPrimitive为基本类型">对象总是先执行ToPrimitive为基本类型</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs javascript">[] < [] <span class="hljs-comment">// false</span><br><span class="hljs-comment">// => "" < "" </span><br>[] <= {} <span class="hljs-comment">// true</span><br><span class="hljs-string">""</span> <= <span class="hljs-string">"[object Object]"</span> <br>({} < {}) <span class="hljs-comment">// false</span><br>({} <= {}) <span class="hljs-comment">// true</span><br></code></pre></td></tr></table></figure><p>后面这两个还挺有说法的</p><p><strong>{} < {}</strong></p><p>•<strong>代码块 vs 表达式</strong>:</p><p>•在没有括号的情况下,{} 被解释为一个代码块而不是对象字面量。</p><p>•因此,{} < {} 被解释为一个空代码块 < 一个对象字面量的比较。</p><p>•由于第一个 {} 被当作代码块,< 运算符之后的 {} 实际上是一个语法错误,因为它看起来像一个对象字面量的定义,但没有有效的上下文。</p><p><strong>实际上</strong>,{} < {} 在大多数情况下会导致语法错误,但在某些环境中,可能解释为 false,因为 JavaScript 不能比较两个代码块。</p><p>加上括号就是</p><p>({} < {}):{} 被解释为对象字面量,并且 () 括起来确保 {} < {} 作为对象字面量被正确解析。</p><p>在这种情况下,{} 转换为 “[object Object]”,而 “[object Object]” < “[object Object]” 为 false,因为任何两个相同的字符串比较都是 false。</p><p><strong>{} <= {}</strong></p><p>•<strong>代码块 vs 表达式</strong>:</p><p>•和上面一样,{} <= {} 被解释为一个代码块 < 一个对象字面量的比较。</p><p>•由于 <= 运算符和 < 运算符一样,可能导致语法错误或无效的比较。</p><p><strong>实际上</strong>,{} <= {} 也可能会导致语法错误或被解释为 true 在某些特定的解析环境中,虽然理论上它是不被允许的。</p><h5 id="任何一边出现非字符串的值,则一律转换成数字做对比">任何一边出现非字符串的值,则一律转换成数字做对比</h5><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">// ["06"] => "06" => 6</span><br>[<span class="hljs-string">"06"</span>] < <span class="hljs-number">2</span> <span class="hljs-comment">// false </span><br><br>[<span class="hljs-string">"06"</span>] < <span class="hljs-string">"2"</span> <span class="hljs-comment">// true</span><br>[<span class="hljs-string">"06"</span>] > <span class="hljs-number">2</span> <span class="hljs-comment">// true</span><br><br><span class="hljs-number">5</span> > <span class="hljs-literal">null</span> <span class="hljs-comment">// true</span><br>-<span class="hljs-number">1</span> < <span class="hljs-literal">null</span> <span class="hljs-comment">// true</span><br><span class="hljs-number">0</span> <= <span class="hljs-literal">null</span> <span class="hljs-comment">// true</span><br><br><span class="hljs-number">0</span> <= <span class="hljs-literal">false</span> <span class="hljs-comment">// true</span><br><span class="hljs-number">0</span> < <span class="hljs-literal">false</span> <span class="hljs-comment">// false</span><br><br><span class="hljs-comment">// undefined => Number(...) => NaN</span><br><span class="hljs-number">5</span> > <span class="hljs-literal">undefined</span> <span class="hljs-comment">// false</span><br></code></pre></td></tr></table></figure><h2 id="To-Boolean">To Boolean</h2><p>既然是总结,那么可能还要讲一下布尔值的隐式转换。这个还是比较常见的,我们来看下有哪些地方会使用到:</p><ul><li>if(…)</li><li>for(;…😉</li><li>while(…)</li><li>do while(…)</li><li>… ? :</li><li>||</li><li>&&</li></ul><p>既然知道会转换,那么什么值是真值,什么值是假值呢?换个思路,假值以外都是真值。看看哪些是<strong>假值</strong>:</p><ul><li>undefined</li><li>null</li><li>false</li><li>+0</li><li>-0</li><li>NaN</li><li>“”</li></ul><h2 id="总结">总结</h2><p>对象都需要先ToPrimitive转成基本类型,除非是宽松相等(==)时两个对象做对比。</p><ul><li>+ 没有字符串就全转数字</li><li>- 全转数字,preferedType===Number</li><li>== 同类型不转,数字优先,布尔全转数字,null、undefined、symbol不转</li><li><> 数字优先,除非两边都是字符串</li></ul>]]></content>
<tags>
<tag>Javascript</tag>
</tags>
</entry>
<entry>
<title>eslint</title>
<link href="/2024/08/04/eslint/"/>
<url>/2024/08/04/eslint/</url>
<content type="html"><![CDATA[<h1>eslint小妙招🍶</h1><h1>1. 基本使用</h1><ol><li>项目安装eslint:<code>yarn add eslint -D</code>;</li><li>初始化eslint配置:eslint --init;</li><li>检测eslint:运行eslint;</li></ol><h2 id="1-1-基本参数">1.1 基本参数</h2><p>eslint配置参数的方式有两种,一种是通过配置文件,一种是通过命令行;配置文件的参数不一定包含命令行的,为了方便查看和使用,<strong>推荐优先在配置中配置</strong>;</p><h3 id="1-1-1-eslintrc参数">1.1.1 .eslintrc参数</h3><p>详情请查看<a href="https://link.juejin.cn?target=https%3A%2F%2Feslint.org%2Fdocs%2Fuser-guide%2Fconfiguring%2Fconfiguration-files%23configuration-file-formats">eslint.org/docs/user-g…</a>;</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br></pre></td><td class="code"><pre><code class="hljs javascript">javascript<br><br> 代码解读<br>复制代码<span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span> = {<br><span class="hljs-comment">// 若项目中有多个子项目,且每个项目都会有.eslintrc,子项目会一直向上查找所有的.eslintrc,直到找到root:true的eslintrc,再将所有的.eslintrc合并</span><br><span class="hljs-string">'root'</span>: <span class="hljs-literal">true</span>,<br><span class="hljs-comment">// 对环境定义的一组全局变量的预设 详细看:https://eslint.org/docs/user-guide/configuring/language-options#specifying-environments</span><br><span class="hljs-string">'env'</span>: {<br><span class="hljs-comment">// 浏览器全局变量</span><br><span class="hljs-attr">browser</span>: <span class="hljs-literal">true</span>,<br><span class="hljs-comment">// Node.js 全局变量和作用域</span><br><span class="hljs-attr">node</span>: <span class="hljs-literal">true</span>,<br><span class="hljs-comment">// CommonJS全局变量和CommonJS作用域</span><br><span class="hljs-attr">commonjs</span>: <span class="hljs-literal">true</span>,<br><span class="hljs-comment">// 启用除模块之外的所有ECMAScript 6功能</span><br><span class="hljs-attr">es6</span>: <span class="hljs-literal">true</span><br>},<br><span class="hljs-comment">// 将数据提供给每一个将被执行的规则</span><br><span class="hljs-string">"settings"</span>: {<br><span class="hljs-string">"sharedData"</span>: <span class="hljs-string">"Hello"</span><br>},<br><span class="hljs-comment">// 继承另一个配置文件的所有特性</span><br><span class="hljs-string">'extends'</span>: [<br><span class="hljs-string">'eslint:recommended'</span>,<br><span class="hljs-string">'plugin:@typescript-eslint/recommended'</span><br>],<br><span class="hljs-comment">// 插件,向ESLint添加各种扩展,可以定义规则,环境或配置的第三方模块</span><br><span class="hljs-string">'plugins'</span>: [<br><span class="hljs-string">'@typescript-eslint'</span><br>],<br><span class="hljs-comment">// 全局变量</span><br><span class="hljs-string">'globals'</span>: {<br><span class="hljs-comment">// false、readable、readonly 这 3 个是等价的,表示变量只可读不可写;</span><br><span class="hljs-comment">// true、writeable、writable 这 3 个是等价的,表示变量可读可写;</span><br><span class="hljs-string">'$'</span>: <span class="hljs-literal">true</span>,<br><span class="hljs-string">'console'</span>: <span class="hljs-literal">false</span><br>},<br><span class="hljs-comment">// 解释器</span><br><span class="hljs-string">'parser'</span>: <span class="hljs-string">'@typescript-eslint/parser'</span>,<br><span class="hljs-comment">// 解释器的配置</span><br><span class="hljs-string">'parserOptions'</span>: {<br><span class="hljs-comment">// 代码模块类型,可选script(默认),module</span><br><span class="hljs-string">'sourceType'</span>: <span class="hljs-string">'module'</span>,<br><span class="hljs-comment">// 指定ECMAScript版本,默认为5</span><br><span class="hljs-string">'ecamVersion'</span>: <span class="hljs-number">6</span>,<br><span class="hljs-comment">// 额外的语言特性,所有选项默认都是 false</span><br><span class="hljs-string">'ecmaFeatures'</span>: {<br><span class="hljs-comment">// 是否允许 return 语句出现在 global 环境下</span><br><span class="hljs-string">'globalReturn'</span>: <span class="hljs-literal">true</span>,<br><span class="hljs-comment">// 是否开启全局 script 模式</span><br><span class="hljs-string">'impliedStrict'</span>: <span class="hljs-literal">true</span>,<br><span class="hljs-comment">// 是否启用 JSX</span><br><span class="hljs-string">'jsx'</span>: <span class="hljs-literal">true</span>,<br><span class="hljs-comment">// 是否启用对实验性的objectRest/spreadProperties的支持</span><br><span class="hljs-string">'experimentalObjectRestSpread'</span>: <span class="hljs-literal">false</span><br>}<br>},<br><span class="hljs-comment">// 规则</span><br><span class="hljs-string">'rules'</span>: {<br><span class="hljs-comment">// 禁止使用 alert</span><br><span class="hljs-string">'no-alert'</span>: <span class="hljs-string">'off'</span>,<br><span class="hljs-comment">// 逗号前面没有空格 后面有空格</span><br><span class="hljs-string">'comma-spacing'</span>: [<span class="hljs-number">2</span>, {<br><span class="hljs-string">'before'</span>: <span class="hljs-literal">false</span>, <span class="hljs-string">'after'</span>: <span class="hljs-literal">true</span><br>}],<br>}<br>};<br></code></pre></td></tr></table></figure><h3 id="1-1-2-命令行参数">1.1.2 命令行参数</h3><p>详情请查看<a href="https://link.juejin.cn?target=http%3A%2F%2Feslint.cn%2Fdocs%2Fuser-guide%2Fcommand-line-interface">eslint.cn/docs/user-g…</a>;</p><figure class="highlight lua"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><code class="hljs lua">lua<br><br> 代码解读<br>复制代码eslint [options] file.js [file.js] [dir]<br><br>Basic configuration:<br> <span class="hljs-comment">--no-eslintrc 禁止使用配置文件.eslintrc.*</span><br> -c, <span class="hljs-comment">--config path::String 指定使用.eslintrc.*配置文件的路径(可以不是这个名字)</span><br> <span class="hljs-comment">--env [String] 指定环境</span><br> <span class="hljs-comment">--ext [String] 指定JavaScript文件扩展名,默认值:.js</span><br> <span class="hljs-comment">--global [String] 定义全局变量</span><br> <span class="hljs-comment">--parser String 指定解析器</span><br> <span class="hljs-comment">--parser-options Object 指定解析器配置</span><br> <span class="hljs-comment">--resolve-plugins-relative-to path::String 应该从中解析插件的文件夹,默认为CWD</span><br><br>Specifying rules <span class="hljs-keyword">and</span> plugins:<br> <span class="hljs-comment">--rulesdir [path::String] 使用其他规则的目录</span><br> <span class="hljs-comment">--plugin [String] 指定插件</span><br> <span class="hljs-comment">--rule Object 指定规则</span><br><br>Fixing problems:<br> <span class="hljs-comment">--fix 自定修复eslint问题</span><br> <span class="hljs-comment">--fix-dry-run 自动修复问题但不保存对文件的更改</span><br> <span class="hljs-comment">--fix-type Array 指定要应用的修复类型(问题、建议、布局)</span><br><br>Ignoring files:<br> <span class="hljs-comment">--ignore-path path::String 指定忽略的路径 即指定一个文件作为.eslintignore</span><br> <span class="hljs-comment">--no-ignore 禁用忽略文件和模式的使用</span><br> <span class="hljs-comment">--ignore-pattern [String] 要忽略的文件模式(除了.eslintignore中的文件)</span><br><br>Using <span class="hljs-built_in">stdin</span>:<br> <span class="hljs-comment">--stdin <STDIN>上提供的Lint代码-默认值:false</span><br> <span class="hljs-comment">--stdin-filename String 指定STDIN的文件名</span><br><br>Handling warnings:<br> <span class="hljs-comment">--quiet 仅报告错误-默认值:false</span><br> <span class="hljs-comment">--max-warnings Int 触发退出代码的警告次数-默认值:-1</span><br><br>Output:<br> -o, <span class="hljs-comment">--output-file path::String 指定要将报告写入的文件</span><br> -f, <span class="hljs-comment">--format String 使用特定的输出格式-默认值:stylish</span><br> <span class="hljs-comment">--color, --no-color 强制启用/禁用颜色</span><br><br>Inline configuration comments:<br> <span class="hljs-comment">--no-inline-config 防止注释更改配置或规则</span><br> <span class="hljs-comment">--report-unused-disable-directives 添加错误信息给未被使用的eslint-disable指令</span><br><br>Caching:<br> <span class="hljs-comment">--cache 仅检查已更改的文件-默认值:false</span><br> <span class="hljs-comment">--cache-file path::String 缓存文件的路径,不推荐使用:使用--cache-location - 默认值:.eslintcache</span><br> <span class="hljs-comment">--cache-location path::String 缓存文件或目录的路径</span><br><br>Miscellaneous:<br> <span class="hljs-comment">--init 运行配置初始化向导-默认值:false</span><br> <span class="hljs-comment">--debug 输出调试信息</span><br> -h, <span class="hljs-comment">--help 显示help文档</span><br> -v, <span class="hljs-comment">--version 输出版本号</span><br> <span class="hljs-comment">--print-config path::String 打印给定文件的配置</span><br></code></pre></td></tr></table></figure><h2 id="2-2-常用参数概念补充">2.2 常用参数概念补充</h2><h3 id="2-2-1-解析器">2.2.1 解析器</h3><ol><li>esprima:eslint早期使用的解析器;</li><li>espree:基于esprema v1.2.2开发,现在默认的解析器;</li><li>@babel/eslint-parser:js高级语法的解析器;</li><li>@typescript-eslint/parser:ts的解析器;</li></ol><h3 id="2-2-2-规则配置">2.2.2 规则配置</h3><ol><li>“off” 或 0: 关闭规则;</li><li>“warn” 或 1: 开启规则,使用警告级别的错误:warn (不会导致程序退出);</li><li>“error” 或 2: 开启规则,使用错误级别的错误:error (当被触发的时候,程序会退出);</li></ol><h3 id="2-2-3-extends支持的配置类型">2.2.3 extends支持的配置类型</h3><ol><li>eslint开头:ESLint官方扩展;</li><li>plugin开头:插件类型扩展;和configs里面配置的一一对应;</li><li>eslint-config开头:npm包,使用时可省略前缀eslint-config-;</li><li>文件路径;</li></ol><p><strong>常用扩展:</strong></p><ol><li>eslint:recommended:ESLint内置的推荐规则,即 ESLint Rules 列表中打了钩的那些规则;</li><li>eslint:all:ESLint 内置的所有规则;</li><li>eslint-config-standard:standard 的 JS 规范;</li><li>eslint-config-prettier:关闭和 ESLint 中以及其他扩展中有冲突的规则;</li><li>eslint-plugin-vue:vue官方eslint配置插件,配置共享有:<ol><li>plugin:vue/base:基础;</li><li>plugin:vue/essential:必不可少的;</li><li>plugin:vue/recommended:推荐的;</li><li>plugin:vue/strongly-recommended:强烈推荐;</li></ol></li></ol><h2 id="2-3-配置不需要lint的文件或目录">2.3 配置不需要lint的文件或目录</h2><p>可以在.eslintignore中指定对应的文件或目录,以达到eslint执行时不检测(eslint本身是忽略node_modules和bower_components的);如:</p><figure class="highlight lua"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs lua">lua<br><br> 代码解读<br>复制代码mock<br>build/*.js<br><span class="hljs-built_in">config</span>/*.js<br></code></pre></td></tr></table></figure><h2 id="ESLint配置共享">ESLint配置共享</h2><p>每个团队的规范是不一样的,公司内部希望每个产品线的规范一致,那么可以将配置分享出来打成npm包,以供不同团队直接配置使用;</p><p><strong>如何写一个配置共享?</strong></p><ol><li>创建一个文件夹,名称为eslint-config-myconfig;</li><li>执行<code>yarn init -y</code>;(模块名必须以eslint-config-开头,项目文件名称随意);</li><li>创建index.js,里面写入需要分享的.eslintrc.js的配置;</li><li>用 <a href="https://link.juejin.cn?target=https%3A%2F%2Fdocs.npmjs.com%2Ffiles%2Fpackage.json%23peerdependencies">peerDependencies</a> 字段声明依赖的 ESLint(明确插件需要 ESLint 才能正常运行);</li><li>发包即可;</li></ol><p><strong>PS</strong>:发包形式写插件都支持@scope/eslint-xxx-xxx形式,<a href="https://link.juejin.cn?target=https%3A%2F%2Fdocs.npmjs.com%2Fcli%2Fv7%2Fusing-npm%2Fscope%2F">详情</a>;</p><p><strong>如何使用上面的包?</strong></p><ol><li>安装包,如: <code>yarn add eslint-config-myconfig -D</code>;</li><li>在项目中的.eslintrc中配置extends配置,具体查看基本使用;</li></ol><h1>2 <a href="https://link.juejin.cn?target=http%3A%2F%2Feslint.cn%2Fdocs%2Fdeveloper-guide%2Fworking-with-plugins">ESLint插件</a></h1><h2 id="2-1-ESLint插件是什么?">2.1 ESLint插件是什么?</h2><p>插件可向ESLint添加各种扩展,是可定义规则,环境、处理器或配置的第三方模块;</p><p><strong>如何自定义一个ESLint插件?</strong></p><p>使用<a href="https://link.juejin.cn?target=https%3A%2F%2Fwww.npmjs.com%2Fpackage%2Fgenerator-eslint">generator-eslint</a>创建一个项目,该项目的模块名需以eslint-plugin-开头,使用的时候,则是去掉eslint-plugin-;</p><p>如npm包名:eslint-plugin-myplugin;</p><h3 id="2-1-1-定义规则">2.1.1 定义规则</h3><p>规则:eslint检测的规则方式;<br>定义方式:规定必须暴露一个rules对象;</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br></pre></td><td class="code"><pre><code class="hljs javascript">javascript<br><br> 代码解读<br>复制代码<span class="hljs-comment">// 这是插件的index.js</span><br><span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span> = {<br><span class="hljs-attr">rules</span>: {<br><span class="hljs-string">'my-rule'</span>: {<br><span class="hljs-comment">// 规则的一些数据配置</span><br><span class="hljs-attr">meta</span>: {<br><span class="hljs-comment">// 规则的类型 "problem"、"suggestion" 或 "layout"</span><br><span class="hljs-attr">type</span>: <span class="hljs-string">'suggestion'</span>,<br><span class="hljs-comment">// 文档信息 自定义规则或插件中可省略,对eslint核心规则是必须的</span><br><span class="hljs-attr">docs</span>: {<br><span class="hljs-attr">description</span>: <span class="hljs-string">'规则的简短描述,在eslint规则首页展示'</span>,<br><span class="hljs-attr">category</span>: <span class="hljs-string">'规则在规则首页处于的分类'</span>,<br><span class="hljs-attr">recommended</span>: <span class="hljs-literal">true</span>, <span class="hljs-comment">// "extends": "eslint:recommended"属性是否启用该规则</span><br><span class="hljs-attr">url</span>: <span class="hljs-string">'https://eslint.org/docs/rules/no-extra-semi'</span> <span class="hljs-comment">// 访问完整文档的 url</span><br>},<br><span class="hljs-comment">// 打开修复功能,如果没有 fixable 属性,即使规则实现了 fix 功能,ESLint 也不会进行修复。如果规则不是可修复的,就省略 fixable 属性</span><br><span class="hljs-attr">fixable</span>: <span class="hljs-string">'code'</span>,<br><span class="hljs-comment">// 指定该规则对应的配置,用于验证配置的选项是否有效</span><br><span class="hljs-attr">schema</span>: [<br> {<br> <span class="hljs-string">"enum"</span>: [<span class="hljs-string">"always"</span>, <span class="hljs-string">"never"</span>]<br> },<br> {<br> <span class="hljs-string">"type"</span>: <span class="hljs-string">"object"</span>,<br> <span class="hljs-string">"properties"</span>: {<br> <span class="hljs-string">"exceptRange"</span>: {<br> <span class="hljs-string">"type"</span>: <span class="hljs-string">"boolean"</span><br> }<br> },<br> <span class="hljs-string">"additionalProperties"</span>: <span class="hljs-literal">false</span><br> }<br> ]<br>},<br><span class="hljs-comment">// create 返回一个对象,对象的格式是key对应一个回调方法;这个对象包含了ESLint在遍历JavaScript代码的AST树(ESTree定义的AST)时,用来访问节点的方法。</span><br><span class="hljs-comment">// context 当前执行eslint时的上下文对象,其中包含了各种相关数据,如eslint的配置信息、当前遍历节点的信息、报告问题的方法等;</span><br><span class="hljs-attr">create</span>: <span class="hljs-keyword">function</span> (<span class="hljs-params">context</span>) {<br><span class="hljs-keyword">return</span> {<br><span class="hljs-comment">// callback functions</span><br><span class="hljs-title class_">ReturnStatement</span>: <span class="hljs-keyword">function</span> (<span class="hljs-params">node</span>) {<br><span class="hljs-comment">// at a ReturnStatement node while going down</span><br>},<br><span class="hljs-comment">// at a function expression node while going up:</span><br><span class="hljs-string">'FunctionExpression:exit'</span>: <span class="hljs-keyword">function</span> <span class="hljs-title function_">checkLastSegment</span> (node) {<br><span class="hljs-comment">// report problem for function if last code path segment is reachable</span><br>},<br><span class="hljs-string">'ArrowFunctionExpression:exit'</span>: <span class="hljs-keyword">function</span> <span class="hljs-title function_">checkLastSegment</span> (node) {<br><span class="hljs-comment">// report problem for function if last code path segment is reachable</span><br>},<br><span class="hljs-attr">onCodePathStart</span>: <span class="hljs-keyword">function</span> (<span class="hljs-params">codePath, node</span>) {<br><span class="hljs-comment">// at the start of analyzing a code path</span><br>},<br><span class="hljs-attr">onCodePathEnd</span>: <span class="hljs-keyword">function</span> (<span class="hljs-params">codePath, node</span>) {<br><span class="hljs-comment">// at the end of analyzing a code path</span><br>}<br>};<br>}<br>}<br>}<br>};<br></code></pre></td></tr></table></figure><p>使用方式:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs javascript">javascript<br><br> 代码解读<br>复制代码<span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span> = {<br> <span class="hljs-string">"plugins"</span>: [<span class="hljs-string">"myplugin"</span>],<br> <span class="hljs-string">"rules"</span>: {<br> <span class="hljs-string">"myplugin/my-rule"</span>: [<span class="hljs-number">2</span>, <span class="hljs-string">"never"</span>, { <span class="hljs-string">"exceptRange"</span>: <span class="hljs-literal">true</span> }],<br> }<br>}<br></code></pre></td></tr></table></figure><h4 id="2-1-1-1-rules的参数">2.1.1.1 rules的参数</h4><p>rules的meta参数是填写一些基本信息,create参数中的value是用于执行检测AST规则的回调方法;</p><p><strong>create的context参数:</strong></p><ol><li>id:在.eslintrc的rules中配置的规则名称,如上面使用方式中的<code>myplugin/my-rule</code>;</li><li>options:在.eslintrc的rules中配置的规则参数,如上面例子的结果是:[“never”, {exceptRange: true}]</li><li>report:用于发布警告或错误的,在回调中判断调用;<a href="https://link.juejin.cn?target=http%3A%2F%2Feslint.cn%2Fdocs%2Fdeveloper-guide%2Fworking-with-rules%23contextreport">具体参数</a>;</li></ol><p><strong>create的return对象:</strong></p><ul><li>如果一个 key 是个节点类型或 selector,在 <strong>向下</strong> 遍历树时,ESLint 调用 <strong>visitor</strong> 函数;</li><li>如果一个 key 是个节点类型或 selector,并带有 <strong>:exit</strong>,在 <strong>向上</strong> 遍历树时,ESLint 调用 <strong>visitor</strong> 函数;</li><li>如果一个 key 是个事件名字,ESLint 为<a href="https://link.juejin.cn?target=http%3A%2F%2Feslint.cn%2Fdocs%2Fdeveloper-guide%2Fcode-path-analysis">代码路径分析</a>调用 <strong>handler</strong> 函数;</li></ul><p><strong>节点类型:</strong> AST的节点类型;</p><p>具体如下:</p><table><thead><tr><th>序号</th><th>类型原名称</th><th>中文名称</th><th>描述</th></tr></thead><tbody><tr><td>1</td><td>Program</td><td>程序主体</td><td>整段代码的主体</td></tr><tr><td>2</td><td>VariableDeclaration</td><td>变量声明</td><td>声明一个变量,例如 var let const</td></tr><tr><td>3</td><td>FunctionDeclaration</td><td>函数声明</td><td>声明一个函数,例如 function</td></tr><tr><td>4</td><td>ExpressionStatement</td><td>表达式语句</td><td>通常是调用一个函数,例如 console.log()</td></tr><tr><td>5</td><td>BlockStatement</td><td>块语句</td><td>包裹在 {} 块内的代码,例如 if (condition){var a = 1;}</td></tr><tr><td>6</td><td>BreakStatement</td><td>中断语句</td><td>通常指 break</td></tr><tr><td>7</td><td>ContinueStatement</td><td>持续语句</td><td>通常指 continue</td></tr><tr><td>8</td><td>ReturnStatement</td><td>返回语句</td><td>通常指 return</td></tr><tr><td>9</td><td>SwitchStatement</td><td>Switch 语句</td><td>通常指 Switch Case 语句中的 Switch</td></tr><tr><td>10</td><td>IfStatement</td><td>If 控制流语句</td><td>控制流语句,通常指 if(condition){}else{}</td></tr><tr><td>11</td><td>Identifier</td><td>标识符</td><td>标识,例如声明变量时 var identi = 5 中的 identi</td></tr><tr><td>12</td><td>CallExpression</td><td>调用表达式</td><td>通常指调用一个函数,例如 console.log()</td></tr><tr><td>13</td><td>BinaryExpression</td><td>二进制表达式</td><td>通常指运算,例如 1+2</td></tr><tr><td>14</td><td>MemberExpression</td><td>成员表达式</td><td>通常指调用对象的成员,例如 console 对象的 log 成员</td></tr><tr><td>15</td><td>ArrayExpression</td><td>数组表达式</td><td>通常指一个数组,例如 [1, 3, 5]</td></tr><tr><td>16</td><td>NewExpression</td><td>New 表达式</td><td>通常指使用 New 关键词</td></tr><tr><td>17</td><td>AssignmentExpression</td><td>赋值表达式</td><td>通常指将函数的返回值赋值给变量</td></tr><tr><td>18</td><td>UpdateExpression</td><td>更新表达式</td><td>通常指更新成员值,例如 i++</td></tr><tr><td>19</td><td>Literal</td><td>字面量</td><td>字面量</td></tr><tr><td>20</td><td>BooleanLiteral</td><td>布尔型字面量</td><td>布尔值,例如 true false</td></tr><tr><td>21</td><td>NumericLiteral</td><td>数字型字面量</td><td>数字,例如 100</td></tr><tr><td>22</td><td>StringLiteral</td><td>字符型字面量</td><td>字符串,例如 vansenb</td></tr><tr><td>23</td><td>SwitchCase</td><td>Case 语句</td><td>通常指 Switch 语句中的 Case</td></tr></tbody></table><p>可以顺便看下vue的节点类型:<a href="https://link.juejin.cn?target=https%3A%2F%2Fgithub.com%2Fvuejs%2Fvue-eslint-parser%2Fblob%2Fmaster%2Fsrc%2Fast%2Fnodes.ts">github.com/vuejs/vue-e…</a></p><p><strong>选择器(selector)</strong> :是一个字符串,可用于匹配抽象语法树(AST)中的节点。这对于描述代码中的特定语法模式非常有用。选择器不限于对单个节点类型进行匹配。例如,选择器"VariableDeclarator > Identifier"将匹配所有具有VariableDeclarator的Identifier。<a href="https://link.juejin.cn?target=http%3A%2F%2Feslint.cn%2Fdocs%2Fdeveloper-guide%2Fselectors">详情</a>;</p><p><strong>事件</strong>:分析代码路径所触发的事件;</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br></pre></td><td class="code"><pre><code class="hljs javascript">javascript<br><br> 代码解读<br>复制代码<span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span> = <span class="hljs-keyword">function</span>(<span class="hljs-params">context</span>) {<br><span class="hljs-keyword">return</span> {<br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 这在分析代码路径的开始时被调用,此时,代码路径对象只有初始段。</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> {<span class="hljs-type">CodePath</span>} <span class="hljs-variable">codePath</span> - The new code path.</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> {<span class="hljs-type">ASTNode</span>} <span class="hljs-variable">node</span> - The current node.</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@returns</span> {<span class="hljs-type">void</span>}</span><br><span class="hljs-comment"> */</span><br><span class="hljs-string">"onCodePathStart"</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">codePath, node</span>) {<br><span class="hljs-comment">// do something with codePath</span><br>},<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 这在分析代码路径的末尾被调用。此时,代码路径对象已经完成。</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> {<span class="hljs-type">CodePath</span>} <span class="hljs-variable">codePath</span> - The completed code path.</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> {<span class="hljs-type">ASTNode</span>} <span class="hljs-variable">node</span> - The current node.</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@returns</span> {<span class="hljs-type">void</span>}</span><br><span class="hljs-comment"> */</span><br><span class="hljs-string">"onCodePathEnd"</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">codePath, node</span>) {<br><span class="hljs-comment">// do something with codePath</span><br>},<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 这在创建代码路径段时调用。</span><br><span class="hljs-comment"> * 这意味着代码路径是分叉或合并的。</span><br><span class="hljs-comment"> * 在这段时间内,该段具有先前的段,并且已被判断为可到达或不可到达。</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> {<span class="hljs-type">CodePathSegment</span>} <span class="hljs-variable">segment</span> - The new code path segment.</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> {<span class="hljs-type">ASTNode</span>} <span class="hljs-variable">node</span> - The current node.</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@returns</span> {<span class="hljs-type">void</span>}</span><br><span class="hljs-comment"> */</span><br><span class="hljs-string">"onCodePathSegmentStart"</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">segment, node</span>) {<br><span class="hljs-comment">// do something with segment</span><br>},<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 这是在代码路径段离开时调用的。</span><br><span class="hljs-comment"> * 此时还没进入下个阶段。</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> {<span class="hljs-type">CodePathSegment</span>} <span class="hljs-variable">segment</span> - The leaved code path segment.</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> {<span class="hljs-type">ASTNode</span>} <span class="hljs-variable">node</span> - The current node.</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@returns</span> {<span class="hljs-type">void</span>}</span><br><span class="hljs-comment"> */</span><br><span class="hljs-string">"onCodePathSegmentEnd"</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">segment, node</span>) {<br><span class="hljs-comment">// do something with segment</span><br>},<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 在代码路径段被循环时调用的。</span><br><span class="hljs-comment"> * 通常每段在创建时都有以前的段,</span><br><span class="hljs-comment"> * Usually segments have each previous segments when created,</span><br><span class="hljs-comment"> * but when looped, a segment is added as a new previous segment into a</span><br><span class="hljs-comment"> * existing segment.</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * This is called when a code path segment was looped.Usually segments have each previous segments when created,but when looped, a segment is added as a new previous segment into aexisting segment.</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * 当循环代码路径段时调用此函数。通常创建段时,段具有每个先前段,但循环时,段作为新的先前段添加到现有段中。</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> {<span class="hljs-type">CodePathSegment</span>} <span class="hljs-variable">fromSegment</span> - A code path segment of source.</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> {<span class="hljs-type">CodePathSegment</span>} <span class="hljs-variable">toSegment</span> - A code path segment of destination.</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> {<span class="hljs-type">ASTNode</span>} <span class="hljs-variable">node</span> - The current node.</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@returns</span> {<span class="hljs-type">void</span>}</span><br><span class="hljs-comment"> */</span><br><span class="hljs-string">"onCodePathSegmentLoop"</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">fromSegment, toSegment, node</span>) {<br><span class="hljs-comment">// do something with segment</span><br>}<br>};<br>};<br></code></pre></td></tr></table></figure><p><a href="https://link.juejin.cn?target=http%3A%2F%2Feslint.cn%2Fdocs%2Fdeveloper-guide%2Fcode-path-analysis">eslint.cn/docs/develo…</a></p><h3 id="2-1-2-定义环境">2.1.2 定义环境</h3><p>环境:就是某一组配置,比如jquery里面所有的全局变量;</p><p>插件的环境可定义以下对象:<br><strong>globals:</strong> 同配置文件中的globals一样。<br><strong>parserOptions:</strong> 同配置文件中的parserOptions一样。</p><p>定义方式:必须暴露environments对象;</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs javascript">javascript<br><br> 代码解读<br>复制代码<span class="hljs-comment">// 这是插件的index.js</span><br><span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span> = {<br> <span class="hljs-attr">environments</span>: {<br> <span class="hljs-attr">jquery</span>: {<br> <span class="hljs-attr">globals</span>: {<br> <span class="hljs-attr">$</span>: <span class="hljs-literal">false</span><br> },<br> <span class="hljs-attr">parserOptions</span>: {<br> }<br> }<br> }<br>};<br></code></pre></td></tr></table></figure><p>使用方式:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs javascript">javascript<br><br> 代码解读<br>复制代码<span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span> = {<br> <span class="hljs-string">"plugins"</span>: [<span class="hljs-string">"myplugin"</span>],<br> <span class="hljs-string">"env"</span>: {<br> <span class="hljs-string">"myplugin/jquery"</span>: <span class="hljs-literal">true</span>,<br> }<br>}<br></code></pre></td></tr></table></figure><h3 id="2-1-3-定义处理器">2.1.3 定义处理器</h3><p>eslint只能检测js,如果是其他文件则需要配置自定义处理器;<br>定义方式:必须暴露processors,以文件后缀为key,包含以文件内容和文件名作为参数的函数,并返回一个要检测的字符串数组;</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><code class="hljs javascript">javascript<br><br> 代码解读<br>复制代码<span class="hljs-comment">// 这是插件的index.js</span><br><span class="hljs-comment">// processor-name</span><br><span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span> = {<br><span class="hljs-attr">processors</span>: {<br><br><span class="hljs-comment">// 不同后缀名 (.js, .jsx, .html, etc.)</span><br><span class="hljs-string">".ext"</span>: {<br><span class="hljs-comment">// 获取文件的文本和文件名</span><br><span class="hljs-attr">preprocess</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">text, filename</span>) {<br><br><span class="hljs-comment">// 在这里,您可以去掉任何非JS内容,并将其拆分为多个字符串以进行lint</span><br><span class="hljs-keyword">return</span> [string]; <span class="hljs-comment">// return an array of strings to lint</span><br>},<br><br><span class="hljs-comment">// 获取Message[][]和文件名</span><br><span class="hljs-attr">postprocess</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params">messages, filename</span>) {<br><span class="hljs-comment">// `messages`参数是一个包含消息对象的二维数组,其中每个数组项的第一个参数包含了preprocess()方法返回的文本相关的lint消息数组</span><br><span class="hljs-comment">// postprocess 方法接受一个二维数组,包含检测消息和文件名。输入数组中的每一项都对应从 preprocess 方法返回的部分。preprocess 方法必须调整所有错误的位置,使其与原始的未处理的代码中的位置相对应,并将它们聚合成一个打平的数组并返回。</span><br><span class="hljs-comment">// 返回你想保留的一维数组</span><br><span class="hljs-keyword">return</span> messages[<span class="hljs-number">0</span>];<br>},<br><br><span class="hljs-attr">supportsAutofix</span>: <span class="hljs-literal">true</span> <span class="hljs-comment">// (optional, defaults to false)</span><br>}<br>}<br>};<br></code></pre></td></tr></table></figure><p>使用方式:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs javascript">javascript<br><br> 代码解读<br>复制代码<span class="hljs-comment">// 方式一:统一</span><br><span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span> = {<br> <span class="hljs-string">"plugins"</span>: [<span class="hljs-string">"myplugin"</span>],<br> <span class="hljs-string">"processor"</span>: <span class="hljs-string">"myplugin/processor-name"</span><br>}<br><span class="hljs-comment">// 方式二:为特定类型的文件指定处理器</span><br><span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span> = {<br> <span class="hljs-string">"plugins"</span>: [<span class="hljs-string">"myplugin"</span>],<br> <span class="hljs-string">"overrides"</span>: [<br> {<br> <span class="hljs-string">"files"</span>: [<span class="hljs-string">"*.md"</span>],<br> <span class="hljs-string">"processor"</span>: <span class="hljs-string">"a-plugin/markdown"</span><br> },<br> {<span class="hljs-comment">// 在 config 部分为命名代码块指定其他配置</span><br> <span class="hljs-string">"files"</span>: [<span class="hljs-string">"**/*.md/*.js"</span>],<br> <span class="hljs-string">"rules"</span>: {<br> <span class="hljs-string">"strict"</span>: <span class="hljs-string">"off"</span><br> }<br> }<br> ]<br><br></code></pre></td></tr></table></figure><h1>工程化最佳使用方案</h1><p>项目的工程化可以提升开发效率,减少一些容易避免的错误;下面推荐一些和eslint搭配的好用的工具:</p><p>有时间找个项目试试水😃</p><ol><li><p><a href="https://link.juejin.cn?target=https%3A%2F%2Fwww.npmjs.com%2Fpackage%2Fhusky">husky</a>:commit之前执行eslint命令,如果eslint没过,则commit失败;</p></li><li><p><a href="https://link.juejin.cn?target=https%3A%2F%2Fwww.npmjs.com%2Fpackage%2Flint-staged">lint-staged</a>:跑husky的hooks只针对拿到的staged文件;</p></li><li><p><a href="https://link.juejin.cn?target=https%3A%2F%2Fprettier.io%2F">prettier</a>:修改代码风格,只管代码风格,不管一些低级问题;如果有一些配置和eslint冲突了,可以配合<a href="https://link.juejin.cn?target=https%3A%2F%2Fwww.npmjs.com%2Fpackage%2Feslint-plugin-prettier">eslint-plugin-prettier</a>和eslint一起使用;</p></li></ol>]]></content>
</entry>
<entry>
<title>Typescript namespace</title>
<link href="/2024/07/12/Typescript%20namespace/"/>
<url>/2024/07/12/Typescript%20namespace/</url>
<content type="html"><![CDATA[<h1>Typescript namespace</h1><p>namespace 是一种将相关代码组织在一起的方式,中文译为“命名空间”。</p><p>它出现在 ES 模块诞生之前,作为 TypeScript 自己的模块格式而发明的。但是,自从有了 ES 模块,官方已经不推荐使用 namespace 了。</p><h2 id="基本用法">基本用法</h2><p>namespace 用来建立一个容器,内部的所有变量和函数,都必须在这个容器里面使用。</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs ts"><span class="hljs-keyword">namespace</span> <span class="hljs-title class_">Utils</span> {<br> <span class="hljs-keyword">function</span> <span class="hljs-title function_">isString</span>(<span class="hljs-params">value: <span class="hljs-built_in">any</span></span>) {<br> <span class="hljs-keyword">return</span> <span class="hljs-keyword">typeof</span> value === <span class="hljs-string">"string"</span>;<br> }<br><br> <span class="hljs-comment">// 正确</span><br> <span class="hljs-title function_">isString</span>(<span class="hljs-string">"yes"</span>);<br>}<br><br><span class="hljs-title class_">Utils</span>.<span class="hljs-title function_">isString</span>(<span class="hljs-string">"no"</span>); <span class="hljs-comment">// 报错</span><br></code></pre></td></tr></table></figure><p>上面示例中,命名空间<code>Utils</code>里面定义了一个函数<code>isString()</code>,它只能在<code>Utils</code>里面使用,如果用于外部就会报错。</p><p>如果要在命名空间以外使用内部成员,就必须为该成员加上<code>export</code>前缀,表示对外输出该成员。</p><figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs typescript"><span class="hljs-keyword">namespace</span> <span class="hljs-title class_">Utility</span> {<br> <span class="hljs-keyword">export</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">log</span>(<span class="hljs-params">msg: <span class="hljs-built_in">string</span></span>) {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(msg);<br> }<br> <span class="hljs-keyword">export</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">error</span>(<span class="hljs-params">msg: <span class="hljs-built_in">string</span></span>) {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">error</span>(msg);<br> }<br>}<br><br><span class="hljs-title class_">Utility</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"Call me"</span>);<br><span class="hljs-title class_">Utility</span>.<span class="hljs-title function_">error</span>(<span class="hljs-string">"maybe!"</span>);<br></code></pre></td></tr></table></figure><p>上面示例中,只要加上<code>export</code>前缀,就可以在命名空间外部使用内部成员。</p><p>编译出来的js代码长这个样🤔</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs ts"><span class="hljs-keyword">var</span> <span class="hljs-title class_">Utility</span>;<br><br>(<span class="hljs-keyword">function</span> (<span class="hljs-params">Utility</span>) {<br> <span class="hljs-keyword">function</span> <span class="hljs-title function_">log</span>(<span class="hljs-params">msg</span>) {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(msg);<br> }<br> <span class="hljs-title class_">Utility</span>.<span class="hljs-property">log</span> = log;<br> <span class="hljs-keyword">function</span> <span class="hljs-title function_">error</span>(<span class="hljs-params">msg</span>) {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">error</span>(msg);<br> }<br> <span class="hljs-title class_">Utility</span>.<span class="hljs-property">error</span> = error;<br>})(<span class="hljs-title class_">Utility</span> || (<span class="hljs-title class_">Utility</span> = {}));<br></code></pre></td></tr></table></figure><p>上面代码中,命名空间<code>Utility</code>变成了 JavaScript 的一个对象,凡是<code>export</code>的内部成员,都成了该对象的属性。</p><p>这就是说,namespace 会变成一个值,保留在编译后的代码中。这一点要小心,它不是纯的类型代码。</p><p>namespace 内部还可以使用<code>import</code>命令输入外部成员,相当于为外部成员起别名。当外部成员的名字比较长时,别名能够简化代码</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs ts"><span class="hljs-keyword">namespace</span> <span class="hljs-title class_">Utils</span> {<br> <span class="hljs-keyword">export</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">isString</span>(<span class="hljs-params">value: <span class="hljs-built_in">any</span></span>) {<br> <span class="hljs-keyword">return</span> <span class="hljs-keyword">typeof</span> value === <span class="hljs-string">"string"</span>;<br> }<br>}<br><br><span class="hljs-keyword">namespace</span> <span class="hljs-title class_">App</span> {<br> <span class="hljs-keyword">import</span> isString = <span class="hljs-title class_">Utils</span>.<span class="hljs-property">isString</span>;<br><br> <span class="hljs-title function_">isString</span>(<span class="hljs-string">"yes"</span>);<br> <span class="hljs-comment">// 等同于</span><br> <span class="hljs-title class_">Utils</span>.<span class="hljs-title function_">isString</span>(<span class="hljs-string">"yes"</span>);<br>}<br></code></pre></td></tr></table></figure><p>上面示例中,<code>import</code>命令指定在命名空间<code>App</code>里面,外部成员<code>Utils.isString</code>的别名为<code>isString</code>。</p><p><code>import</code>命令也可以在 namespace 外部,指定别名</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs ts"><span class="hljs-keyword">namespace</span> <span class="hljs-title class_">Shapes</span> {<br> <span class="hljs-keyword">export</span> <span class="hljs-keyword">namespace</span> <span class="hljs-title class_">Polygons</span> {<br> <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Triangle</span> {}<br> <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Square</span> {}<br> }<br>}<br><br><span class="hljs-keyword">import</span> polygons = <span class="hljs-title class_">Shapes</span>.<span class="hljs-property">Polygons</span>;<br><br><span class="hljs-comment">// 等同于 new Shapes.Polygons.Square()</span><br><span class="hljs-keyword">let</span> sq = <span class="hljs-keyword">new</span> polygons.<span class="hljs-title class_">Square</span>();<br></code></pre></td></tr></table></figure><p>上面示例中,<code>import</code>命令在命名空间<code>Shapes</code>的外部,指定<code> Shapes.Polygons</code>的别名为<code>polygons</code>。</p><p>namespace 可以嵌套 💁♂️</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs ts"><span class="hljs-keyword">namespace</span> <span class="hljs-title class_">Utils</span> {<br> <span class="hljs-keyword">export</span> <span class="hljs-keyword">namespace</span> <span class="hljs-title class_">Messaging</span> {<br> <span class="hljs-keyword">export</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">log</span>(<span class="hljs-params">msg: <span class="hljs-built_in">string</span></span>) {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(msg);<br> }<br> }<br>}<br><br><span class="hljs-title class_">Utils</span>.<span class="hljs-property">Messaging</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"hello"</span>); <span class="hljs-comment">// "hello"</span><br></code></pre></td></tr></table></figure><p>上面示例中,命名空间<code>Utils</code>内部还有一个命名空间<code>Messaging</code>。注意,如果要在外部使用<code>Messaging</code>,必须在它前面加上<code>export</code>命令。</p><p>使用嵌套的命名空间,必须从最外层开始引用,比如<code>Utils.Messaging.log()</code>。</p><p>namespace 不仅可以包含实义代码,还可以包括类型代码。</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs ts"><span class="hljs-keyword">namespace</span> N {<br> <span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> <span class="hljs-title class_">MyInterface</span> {}<br> <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">MyClass</span> {}<br>}<br></code></pre></td></tr></table></figure><p>上面代码中,命令空间<code>N</code>不仅对外输出类,还对外输出一个接口,它们都可以用作类型。</p><p>namespace 与模块的作用是一致的,都是把相关代码组织在一起,对外输出接口。区别是一个文件只能有一个模块,但可以有多个 namespace。由于模块可以取代 namespace,而且是 JavaScript 的标准语法,还不需要编译转换,所以建议总是使用模块,替代 namespace。</p><p>如果 namespace 代码放在一个单独的文件里,那么引入这个文件需要使用三斜杠的语法。</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs ts"><span class="hljs-comment">/// <reference path = "SomeFileName.ts" /></span><br></code></pre></td></tr></table></figure><p>PS: 三斜杠指令是特殊注释,为编译器提供有关如何处理文件的说明。这些指令以三个连续斜杠 (<code>///</code>) 开头,通常放置在 TypeScript 文件的顶部,对运行时行为没有影响。</p><p>三斜杠指令用于引用外部依赖项、指定模块加载行为、启用/禁用某些编译器功能等等。</p>]]></content>
</entry>
<entry>
<title>浏览器插件入门</title>
<link href="/2024/06/02/%E6%B5%8F%E8%A7%88%E5%99%A8%E6%8F%92%E4%BB%B6%E5%85%A5%E9%97%A8/"/>
<url>/2024/06/02/%E6%B5%8F%E8%A7%88%E5%99%A8%E6%8F%92%E4%BB%B6%E5%85%A5%E9%97%A8/</url>
<content type="html"><![CDATA[<h1>浏览器插件</h1><p>开源之夏有点被导师pua到了 所以准备换了个项目 还是一个社区的项目</p><p>这个项目主要是对浏览器插件优化</p><h2 id="浏览器插件基本项目结构">浏览器插件基本项目结构</h2><p>先看看基本结构吧 基本上都会有一个<code>mainfest.json</code> 跟<code>package.json</code>基本上我感觉是一样的作用</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs json"><span class="hljs-punctuation">{</span><br> <span class="hljs-comment">// 插件名称</span><br> <span class="hljs-attr">"name"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"Hello Extensions"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-comment">// 插件的描述</span><br> <span class="hljs-attr">"description"</span> <span class="hljs-punctuation">:</span> <span class="hljs-string">"Base Level Extension"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-comment">// 插件的版本</span><br> <span class="hljs-attr">"version"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"1.0"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-comment">// 配置插件程序的版本号,主流版本是2,最新是3</span><br> <span class="hljs-attr">"manifest_version"</span><span class="hljs-punctuation">:</span> <span class="hljs-number">2</span><br><span class="hljs-punctuation">}</span><br><br></code></pre></td></tr></table></figure><p>我们经常会点击右上角插件图标时弹出一个小窗口的页面,焦点离开时就关闭了,一般做一些临时性的交互操作;在配置文件中新增<code>browser_action</code>字段,配置popup弹框:</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs json"><span class="hljs-punctuation">{</span><br> <span class="hljs-attr">"name"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"Hello Extensions"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"description"</span> <span class="hljs-punctuation">:</span> <span class="hljs-string">"Base Level Extension"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"version"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"1.0"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"manifest_version"</span><span class="hljs-punctuation">:</span> <span class="hljs-number">2</span><span class="hljs-punctuation">,</span><br> <span class="hljs-comment">// 新增popup弹框</span><br> <span class="hljs-attr">"browser_action"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span><br> <span class="hljs-attr">"default_popup"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"popup.html"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"default_icon"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"popup.png"</span><br> <span class="hljs-punctuation">}</span><br><span class="hljs-punctuation">}</span><br></code></pre></td></tr></table></figure><p>然后创建我们的弹框页面panel.html:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs html">html复制代码<span class="hljs-tag"><<span class="hljs-name">html</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">body</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">h1</span>></span>Hello Extensions<span class="hljs-tag"></<span class="hljs-name">h1</span>></span><br> <span class="hljs-tag"></<span class="hljs-name">body</span>></span><br><span class="hljs-tag"></<span class="hljs-name">html</span>></span><br></code></pre></td></tr></table></figure><p>点击图标后,插件显示panel.html</p><h2 id="后台background">后台background</h2><p>们也发现了,popup页面只能做临时性的交互操作,用完就关了,不能存储信息或者和其他标签页进行交互等等;这时就需要用到background(后台),它是一个常驻的页面,它的生命周期是插件中所有类型页面中最长的;它随着浏览器的打开而打开,随着浏览器的关闭而关闭,所以通常把需要一直运行的、启动就运行的、全局的代码放在background里面。</p><p>在<code>mainfest.json</code>添加路径</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs json"><span class="hljs-attr">"background"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span><br> <span class="hljs-attr">"script"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span><br> <span class="hljs-string">"background.js"</span><br> <span class="hljs-punctuation">]</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"persistent"</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">true</span></span><br><span class="hljs-punctuation">}</span><span class="hljs-punctuation">,</span><br></code></pre></td></tr></table></figure><p>这样基本上结构就差不多了</p><h2 id="实现查看组件属性和查看状态管理状态的功能">实现查看组件属性和查看状态管理状态的功能</h2><p>这个就是开源之夏的第一个任务喽</p><p>感觉就是React的那个插件的功能</p><p>我去看了看react的源码</p><p>感觉操作就是需要先获取到组件的状态 然后看状态管理器的状态</p><p>然后监听后台管理器的消息 然后在显示的html中加上显示的部分</p><p>在content-Script中新增⼀个stateManager.ts⽂件 以便捕获和发送组件状态和状态管理器信息</p><p>哦这里补充一下 一般会有一个content-script文件夹</p><p>官方定义是</p><p>content-scripts(内容脚本)是在网页上下文中运行的文件。通过使用标准的文档对象模型(DOM),它能够读取浏览器访问的网页的详细信息,对其进行更改,并将信息传递给其父级插件。内容脚本相对于background还是有一些访问API上的限制,它可以直接访问以下chrome的API:</p><ul><li>i18n</li><li>storage</li><li>runtime:<ul><li>connect</li><li>getManifest</li><li>getURL</li><li>id</li><li>onConnect</li><li>onMessage</li><li>sendMessage</li></ul></li></ul><p>我的理解就是监听监听监听 传信号信号信号 💬</p><p>基本上用的都是chrome的<code>api</code></p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><code class="hljs ts"><span class="hljs-keyword">let</span> mockComponentState = { <span class="hljs-attr">exampleComponent</span>: { <span class="hljs-attr">state</span>: <span class="hljs-string">'active'</span> } };<br><span class="hljs-keyword">let</span> mockStateManagerInfo = { <span class="hljs-attr">exampleStateManager</span>: { <span class="hljs-attr">state</span>: <span class="hljs-string">'initialized'</span> } };<br> chrome.<span class="hljs-property">runtime</span>.<span class="hljs-title function_">sendMessage</span>({ <span class="hljs-attr">type</span>: <span class="hljs-string">'updateComponentState'</span>, <span class="hljs-attr">state</span>: <br>mockComponentState });<br> chrome.<span class="hljs-property">runtime</span>.<span class="hljs-title function_">sendMessage</span>({ <span class="hljs-attr">type</span>: <span class="hljs-string">'updateStateManagerInfo'</span>, <span class="hljs-attr">stateManager</span>: <br>mockStateManagerInfo });<br><span class="hljs-comment">//钩子到框架特定的 API 获取真实的组件状态和状态管理器信息</span><br>(<span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">const</span> originalSetState = <span class="hljs-title class_">YourFramework</span>.<span class="hljs-property">Component</span>.<span class="hljs-property"><span class="hljs-keyword">prototype</span></span>.<span class="hljs-property">setState</span>;<br> <span class="hljs-title class_">YourFramework</span>.<span class="hljs-property">Component</span>.<span class="hljs-property"><span class="hljs-keyword">prototype</span></span>.<span class="hljs-property">setState</span> = <span class="hljs-keyword">function</span> (<span class="hljs-params">newState, callback</span>) {<br> chrome.<span class="hljs-property">runtime</span>.<span class="hljs-title function_">sendMessage</span>({ <span class="hljs-attr">type</span>: <span class="hljs-string">'updateComponentState'</span>, <span class="hljs-attr">state</span>: <br><span class="hljs-variable language_">this</span>.<span class="hljs-property">state</span> });<br> <span class="hljs-keyword">return</span> originalSetState.<span class="hljs-title function_">apply</span>(<span class="hljs-variable language_">this</span>, <span class="hljs-variable language_">arguments</span>);<br> };<br> })();<br> (<span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">const</span> originalDispatch = <span class="hljs-title class_">YourFramework</span>.<span class="hljs-property">store</span>.<span class="hljs-property">dispatch</span>;<br> <span class="hljs-title class_">YourFramework</span>.<span class="hljs-property">store</span>.<span class="hljs-property">dispatch</span> = <span class="hljs-keyword">function</span> (<span class="hljs-params">action</span>) {<br> chrome.<span class="hljs-property">runtime</span>.<span class="hljs-title function_">sendMessage</span>({ <span class="hljs-attr">type</span>: <span class="hljs-string">'updateStateManagerInfo'</span>, <span class="hljs-attr">stateManager</span>: <br><span class="hljs-title class_">YourFramework</span>.<span class="hljs-property">store</span>.<span class="hljs-title function_">getState</span>() });<br> <span class="hljs-keyword">return</span> originalDispatch.<span class="hljs-title function_">apply</span>(<span class="hljs-variable language_">this</span>, <span class="hljs-variable language_">arguments</span>);<br> };<br> })();<br></code></pre></td></tr></table></figure><p><code>chrome.runtime.sendMessage</code> 是 Chrome 扩展程序中的一种方法,用于从扩展程序中的一个部分向另一个部分发送消息,例如从内容脚本向后台脚本发送消息。</p><h3 id="用法">用法</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js">chrome.<span class="hljs-property">runtime</span>.<span class="hljs-title function_">sendMessage</span>(extensionId, message, options, responseCallback);<br></code></pre></td></tr></table></figure><ul><li><code>extensionId</code>(可选):字符串类型。指定接收消息的扩展程序的ID。如果消息是发送到本扩展程序,可以省略此参数。</li><li><code>message</code>:任意类型。发送的消息内容,可以是任何JSON序列化类型的数据。</li><li><code>options</code>(可选):对象类型。包含额外的选项,比如 <code>includeTlsChannelId</code>(布尔值)。</li><li><code>responseCallback</code>(可选):函数类型。一个函数,当收到响应消息时调用,传入一个参数 <code>response</code>,该参数是响应的消息。</li></ul><p>然后在content-Script的<code>index.ts</code>中引入使用</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs ts"> <span class="hljs-comment">//监听来自 background 的消息</span><br>chrome.<span class="hljs-property">runtime</span>.<span class="hljs-property">onMessage</span>.<span class="hljs-title function_">addListener</span>(<span class="hljs-keyword">function</span> (<span class="hljs-params">message, sender, sendResponse</span>) {<br> <span class="hljs-comment">//该方法可以监听页面 contentScript 和插件的消息</span><br> <span class="hljs-comment">// 没有 tab 信息说明消息来自插件</span><br> <span class="hljs-keyword">if</span> (!sender.<span class="hljs-property">tab</span> <span class="hljs-title function_">checkMessage</span>(message, <span class="hljs-title class_">DevToolBackground</span>)) {<br> <span class="hljs-title function_">changeSource</span>(message, <span class="hljs-title class_">DevToolContentScript</span>);<br> <span class="hljs-comment">// 传递消息给页面</span><br> <span class="hljs-variable language_">window</span>.<span class="hljs-title function_">postMessage</span>(message, <span class="hljs-string">'*'</span>);<br> }<br> <span class="hljs-title function_">sendResponse</span>({ <span class="hljs-attr">status</span>: <span class="hljs-string">'ok'</span> });<br> });<br></code></pre></td></tr></table></figure><p>他自己写的源码中有个什么window对象不能直接通过 contentScript 代码修改,只能通过添加 js 代码往页面 window 注入 hook 这玩意还没看懂 等要是选上慢慢来吧</p>]]></content>
<categories>
<category>浏览器插件</category>
</categories>
</entry>
<entry>
<title>blog</title>
<link href="/2024/05/12/blog/"/>
<url>/2024/05/12/blog/</url>
<content type="html"><![CDATA[]]></content>
</entry>
<entry>
<title>Typescript-declare</title>
<link href="/2024/05/12/Typescript-declare/"/>
<url>/2024/05/12/Typescript-declare/</url>
<content type="html"><![CDATA[<h1>declare 关键字</h1><p>最近在做那个开源之夏 然后要用到这个declare 进行类型检查就正好写一篇啦 (其实还有很多不会的)👼</p><p>本来想写<code>JSX</code>的自定义接口来着 但是没准备看懂 所以写了这个</p><h2 id="简介">简介</h2><p>declare 关键字用来告诉编译器,某个类型是存在的,可以在当前文件中使用🛩️</p><p>它的主要作用,就是让当前文件可以使用其他文件声明的类型。举例来说,自己的脚本使用外部库定义的函数,编译器会因为不知道外部函数的类型定义而报错,这时就可以在自己的脚本里面使用<code>declare</code>关键字,告诉编译器外部函数的类型。这样的话,编译单个脚本就不会因为使用了外部类型而报错。</p><p>declare 关键字可以描述以下类型。</p><ul><li>变量(const、let、var 命令声明)</li><li>type 或者 interface 命令声明的类型</li><li>class</li><li>enum</li><li>函数(function)</li><li>模块(module)</li><li>命名空间(namespace)</li></ul><p>declare 关键字的重要特点是,它只是通知编译器某个类型是存在的,不用给出具体实现。比如,只描述函数的类型,不给出函数的实现,如果不使用<code>declare</code>,这是做不到的。</p><p>declare 只能用来描述已经存在的变量和数据结构,不能用来声明新的变量和数据结构。另外,所有 declare 语句都不会出现在编译后的文件里面。</p><h2 id="declare-variable">declare variable</h2><p>declare 关键字可以给出外部变量的类型描述。</p><p>举例来说,当前脚本使用了其他脚本定义的全局变量<code>x</code>。</p><figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs typescript">x = <span class="hljs-number">123</span>; <span class="hljs-comment">// 报错</span><br></code></pre></td></tr></table></figure><p>上面示例中,变量<code>x</code>是其他脚本定义的,当前脚本不知道它的类型,编译器就会报错。</p><p>这时使用 declare 命令给出它的类型,就不会报错了。</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs ts"><span class="hljs-keyword">declare</span> <span class="hljs-keyword">let</span> <span class="hljs-attr">x</span>:<span class="hljs-built_in">number</span>;x = <span class="hljs-number">1</span>;<br></code></pre></td></tr></table></figure><p>如果 declare 关键字没有给出变量的具体类型,那么变量类型就是<code>any</code>。</p><figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs typescript"><span class="hljs-keyword">declare</span> <span class="hljs-keyword">let</span> x;x = <span class="hljs-number">1</span>;<br></code></pre></td></tr></table></figure><p>上面示例中,变量<code>x</code>的类型为<code>any</code>。</p><p>下面的例子是脚本使用浏览器全局对象<code>document</code>。</p><figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs typescript"><span class="hljs-keyword">declare</span> <span class="hljs-keyword">var</span> <span class="hljs-variable language_">document</span>;<span class="hljs-variable language_">document</span>.<span class="hljs-property">title</span> = <span class="hljs-string">'Hello'</span>;<br></code></pre></td></tr></table></figure><p>上面示例中,declare 告诉编译器,变量<code>document</code>的类型是外部定义的(具体定义在 TypeScript 内置文件<code>lib.d.ts</code>)。</p><p>如果 TypeScript 没有找到<code>document</code>的外部定义,这里就会假定它的类型是<code>any</code>。</p><p>注意,declare 关键字只用来给出类型描述,是纯的类型代码,不允许设置变量的初始值,即不能涉及值。</p><figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs typescript"><span class="hljs-comment">// 报错 </span><br><span class="hljs-keyword">declare</span> <span class="hljs-keyword">let</span> <span class="hljs-attr">x</span>:<span class="hljs-built_in">number</span> = <span class="hljs-number">1</span>;<br></code></pre></td></tr></table></figure><p>上面示例中,declare 设置了变量的初始值,结果就报错了。</p><h2 id="declare-function">declare function</h2><p>declare 关键字可以给出外部函数的类型描述。</p><figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs typescript"><span class="hljs-keyword">declare</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">sayHello</span>(<span class="hljs-params">name:<span class="hljs-built_in">string</span></span>):<span class="hljs-built_in">void</span>;<br><span class="hljs-title function_">sayHello</span>(<span class="hljs-string">'zzx'</span>);<br></code></pre></td></tr></table></figure><p>上面示例中,declare 命令给出了<code>sayHello()</code>的类型描述,因此可以直接使用它。</p><p>注意,这种单独的函数类型声明语句,只能用于<code>declare</code>命令后面。一方面,TypeScript 不支持单独的函数类型声明语句;另一方面,declare 关键字后面也不能带有函数的具体实现。</p><figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs typescript"><span class="hljs-comment">// 报错 </span><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">sayHello</span>(<span class="hljs-params"> name:<span class="hljs-built_in">string</span></span>):<span class="hljs-built_in">void</span>;<span class="hljs-keyword">function</span> <span class="hljs-title function_">sayHello</span>(<span class="hljs-params">name</span>) { <span class="hljs-keyword">return</span> <span class="hljs-string">'你好,'</span> + name;}<br></code></pre></td></tr></table></figure><p>上面示例中,单独写函数的类型声明就会报错。</p><h2 id="declare-class">declare class</h2><p>declare 给出 class 的描述描述写法如下。</p><figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs typescript"><span class="hljs-keyword">declare</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Animal</span> { <span class="hljs-title function_">constructor</span>(<span class="hljs-params">name:<span class="hljs-built_in">string</span></span>); <span class="hljs-title function_">eat</span>():<span class="hljs-built_in">void</span>; <span class="hljs-title function_">sleep</span>():<span class="hljs-built_in">void</span>;}<br></code></pre></td></tr></table></figure><p>下面是一个复杂一点的例子。</p><figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs typescript"><span class="hljs-keyword">declare</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">C</span> { <br> <span class="hljs-comment">// 静态成员 </span><br> <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-title function_">s0</span>():<span class="hljs-built_in">string</span>; <br> <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-attr">s1</span>:<span class="hljs-built_in">string</span>; <br> <span class="hljs-comment">// 属性 </span><br> <span class="hljs-keyword">public</span> <span class="hljs-attr">a</span>:<span class="hljs-built_in">number</span>; <br> <span class="hljs-keyword">private</span> <span class="hljs-attr">b</span>:<span class="hljs-built_in">number</span>; <br> <span class="hljs-comment">// 构造函数 </span><br> <span class="hljs-title function_">constructor</span>(<span class="hljs-params">arg:<span class="hljs-built_in">number</span></span>); <br> <span class="hljs-comment">// 方法 </span><br> <span class="hljs-title function_">m</span>(<span class="hljs-attr">x</span>:<span class="hljs-built_in">number</span>, <span class="hljs-attr">y</span>:<span class="hljs-built_in">number</span>):<span class="hljs-built_in">number</span>; <br> <span class="hljs-comment">// 存取器 </span><br> <span class="hljs-keyword">get</span> <span class="hljs-title function_">c</span>():<span class="hljs-built_in">number</span>; <span class="hljs-keyword">set</span> <span class="hljs-title function_">c</span>(<span class="hljs-params">value:<span class="hljs-built_in">number</span></span>); <br> <span class="hljs-comment">// 索引签名 </span><br> [<span class="hljs-attr">index</span>:<span class="hljs-built_in">string</span>]:<span class="hljs-built_in">any</span>;<br>}<br></code></pre></td></tr></table></figure><p>同样的,declare 后面不能给出 Class 的具体实现或初始值。</p><h2 id="declare-module,declare-namespace">declare module,declare namespace</h2><p>如果想把变量、函数、类组织在一起,可以将 declare 与 module 或 namespace 一起使用。</p><figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs typescript"><span class="hljs-keyword">declare</span> <span class="hljs-keyword">namespace</span> <span class="hljs-title class_">AnimalLib</span> { <br> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Animal</span> { <br> <span class="hljs-title function_">constructor</span>(<span class="hljs-params">name:<span class="hljs-built_in">string</span></span>); <br> <span class="hljs-title function_">eat</span>():<span class="hljs-built_in">void</span>; <br> <span class="hljs-title function_">sleep</span>():<span class="hljs-built_in">void</span>; } <br> <span class="hljs-keyword">type</span> <span class="hljs-title class_">Animals</span> = <span class="hljs-string">'Fish'</span> | <span class="hljs-string">'Dog'</span>;}<br><span class="hljs-comment">// 或者</span><br><span class="hljs-keyword">declare</span> <span class="hljs-variable language_">module</span> <span class="hljs-title class_">AnimalLib</span> <br>{ <span class="hljs-keyword">class</span> <span class="hljs-title class_">Animal</span> <br>{ <span class="hljs-title function_">constructor</span>(<span class="hljs-params">name:<span class="hljs-built_in">string</span></span>); <br> <span class="hljs-title function_">eat</span>(): <span class="hljs-built_in">void</span>; <br> <span class="hljs-title function_">sleep</span>(): <span class="hljs-built_in">void</span>; <br> } <br> <span class="hljs-keyword">type</span> <span class="hljs-title class_">Animals</span> = <span class="hljs-string">'Fish'</span> | <span class="hljs-string">'Dog'</span>;}<br></code></pre></td></tr></table></figure><p>这个栗子中 declare 关键字给出了 module 或 namespace 的类型描述。</p><p>declare module 和 declare namespace 里面,加不加 export 关键字都可以。</p><figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs typescript"><span class="hljs-keyword">declare</span> <span class="hljs-keyword">namespace</span> <span class="hljs-title class_">Foo</span> { <span class="hljs-keyword">export</span> <span class="hljs-keyword">var</span> <span class="hljs-attr">a</span>: <span class="hljs-built_in">boolean</span>;}<span class="hljs-keyword">declare</span> <span class="hljs-variable language_">module</span> <span class="hljs-string">'io'</span> { <span class="hljs-keyword">export</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">readFile</span>(<span class="hljs-params">filename:<span class="hljs-built_in">string</span></span>):<span class="hljs-built_in">string</span>;}<br></code></pre></td></tr></table></figure><p>上面示例中,namespace 和 module 里面使用了 export 关键字。</p><p>declare 关键字的另一个用途,是为外部模块添加属性和方法时,给出新增部分的类型描述。</p><figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs typescript"><span class="hljs-keyword">import</span> { <span class="hljs-title class_">Foo</span> <span class="hljs-keyword">as</span> <span class="hljs-title class_">Bar</span> } <span class="hljs-keyword">from</span> <span class="hljs-string">'moduleA'</span>;<span class="hljs-keyword">declare</span> <span class="hljs-variable language_">module</span> <span class="hljs-string">'moduleA'</span> { <span class="hljs-keyword">interface</span> <span class="hljs-title class_">Bar</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_">Foo</span> { <span class="hljs-attr">custom</span>: { <span class="hljs-attr">prop1</span>:<span class="hljs-built_in">string</span>; } }}<br></code></pre></td></tr></table></figure><p>上面示例中,从模块<code>moduleA</code>导入了<code>Foo</code>接口,将其重命名为<code>Bar</code>,并用 declare 关键字为<code>Bar</code>增加一个属性<code>custom</code>。</p><p>下面是另一个例子。一个项目有多个模块,可以在一个模型中,对另一个模块的接口进行类型扩展。</p><figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs typescript"><span class="hljs-comment">// a.ts</span><br><span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> A { <span class="hljs-attr">x</span>: <span class="hljs-built_in">number</span>;}<br><span class="hljs-comment">// b.ts</span><br><span class="hljs-keyword">import</span> { A } <span class="hljs-keyword">from</span> <span class="hljs-string">'./a'</span>;<br><span class="hljs-keyword">declare</span> <span class="hljs-variable language_">module</span> <span class="hljs-string">'./a'</span> { <br> <span class="hljs-keyword">interface</span> A { <span class="hljs-attr">y</span>: <span class="hljs-built_in">number</span>; }}<br><span class="hljs-keyword">const</span> <span class="hljs-attr">a</span>:A = { <span class="hljs-attr">x</span>: <span class="hljs-number">0</span>, <span class="hljs-attr">y</span>: <span class="hljs-number">0</span> };<br></code></pre></td></tr></table></figure><p>上面示例中,脚本<code>a.ts</code>定义了一个接口<code>A</code>,脚本<code>b.ts</code>为这个接口添加了属性<code>y</code>。<code>declare module './a' {}</code>表示对<code>a.ts</code>里面的模块,进行类型声明,而同名 interface 会自动合并,所以等同于扩展类型。</p><p>使用这种语法进行模块的类型扩展时,有两点需要注意:</p><p>(1)<code>declare module NAME</code>语法里面的模块名<code>NAME</code>,跟 import 和 export 的模块名规则是一样的,且必须跟当前文件加载该模块的语句写法(上例<code>import { A } from './a'</code>)保持一致。</p><p>(2)不能创建新的顶层类型。也就是说,只能对<code>a.ts</code>模块中已经存在的类型进行扩展,不允许增加新的顶层类型,比如新定义一个接口<code>B</code>。</p><p>(3)不能对默认的<code>default</code>接口进行扩展,只能对 export 命令输出的命名接口进行扩充。这是因为在进行类型扩展时,需要依赖输出的接口名。</p><p>某些第三方模块,原始作者没有提供接口类型,这时可以在自己的脚本顶部加上下面一行命令。</p><figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs typescript"><span class="hljs-keyword">declare</span> <span class="hljs-variable language_">module</span> <span class="hljs-string">"模块名"</span>;<br><span class="hljs-comment">// 例子declare module "hot-new-module";</span><br></code></pre></td></tr></table></figure><p>加上上面的命令以后,外部模块即使没有类型,也可以通过编译。但是,从该模块输入的所有接口都将为<code>any</code>类型。</p><p>declare module 描述的模块名可以使用通配符。</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs ts"><span class="hljs-keyword">declare</span> <span class="hljs-variable language_">module</span> <span class="hljs-string">'my-plugin-*'</span> { <br> <span class="hljs-keyword">interface</span> <span class="hljs-title class_">PluginOptions</span> { <br> <span class="hljs-attr">enabled</span>: <span class="hljs-built_in">boolean</span>; <br> <span class="hljs-attr">priority</span>: <span class="hljs-built_in">number</span>; <br> } <br> <span class="hljs-keyword">function</span> <span class="hljs-title function_">initialize</span>(<span class="hljs-params">options: PluginOptions</span>): <span class="hljs-built_in">void</span>; <br> <span class="hljs-keyword">export</span> = initialize;<br>}<br></code></pre></td></tr></table></figure><p>上面示例中,模块名<code>my-plugin-*</code>表示适配所有以<code>my-plugin-</code>开头的模块名(比如<code>my-plugin-logger</code>)。</p>]]></content>
</entry>
<entry>
<title>Javascript忍者秘籍blog-1</title>
<link href="/2024/04/21/Javascript%E5%BF%8D%E8%80%85%E7%A7%98%E7%B1%8Dblog-1/"/>
<url>/2024/04/21/Javascript%E5%BF%8D%E8%80%85%E7%A7%98%E7%B1%8Dblog-1/</url>
<content type="html"><![CDATA[<h1><code>Javascript</code>忍者秘籍(一)</h1><p>最近一直都在看这本书 感觉之前的js底子太差了 看这本书回顾一下吧(感觉有些概念都是没听过的)🌵</p><p>这篇主要写第四章理解函数调用的东西吧</p><p>调用函数时,隐式的函数参数 this 和 arguments 会被静默的传递给函数,可以像函数体内显式声明的参数一样使用</p><p><code>this</code> 表示调用函数的上下文对象</p><p><code>arguments</code> 表示函数调用过程中传递的所有参数。通过 arguments 参数可以访问 函数调用过程中传递的实际参数。</p><p>函数调用的方式 对 函数的隐式参数有很大的影响🍶</p><h3 id="1-隐式函数参数">1.隐式函数参数</h3><h4 id="arguments参数"><code>arguments</code>参数</h4><p>arguments参数表示传入函数的所有参数的集合。</p><p>使用arguments.length属性来获取传递给函数的实际参数个数。</p><p>通过数组下标的方式访问到arguments参数中的每个参数值,如arguments[2]将获取第三个参数。</p><p>arguments是一个类数组对象,不可以对arguments对象使用数组的方法。</p><p>在非严格模式下,arguments对象是函数参数的别名,修改arguments对象会影响对应的函数实参,反之亦然。</p><p>arguments作为参数别名使用时,会影响代码可读性,应该避免使用参数别名修改参数。在严格模式下通过arguments修改参数是不起作用的</p><h4 id="this参数"><code>this</code>参数</h4><p>this表示函数上下文,即与函数调用相关联的对象。(还是有很多抽象小题的 经典this指向问题)💢</p><p>但是,在<code>javascript</code>中,将一个函数作为方法调用仅仅是函数的一种调用方式。this参数是由函数的<strong>定义方式</strong>和<strong>调用方式</strong>决定</p><h3 id="2-函数调用方式">2.函数调用方式</h3><p>基本上是4种</p><ol><li>作为函数直接被调用;<code>myfunc()</code></li><li>作为方法关联在一个对象上,实现面向对象编程;<code>obj.myfunc()</code></li><li>作为构造函数调用,实例化一个对象;<code>new Myfunc()</code></li><li>通过函数的apply和call方法</li></ol><h4 id="作为函数被直接调用">作为函数被直接调用</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">/*函数定义作为函数被调用*/</span><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">aa</span>(<span class="hljs-params"></span>){<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-variable language_">this</span>)<br>}<br><span class="hljs-title function_">aa</span>(); <span class="hljs-comment">//=>object.window</span><br><span class="hljs-comment">/*函数表达式作为函数被调用*/</span><br><span class="hljs-keyword">let</span> bb = <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>){<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-variable language_">this</span>)<br>}<br><span class="hljs-title function_">bb</span>(); <span class="hljs-comment">//=>object.window</span><br><span class="hljs-comment">/*立即调用函数表达式作为函数被调用*/</span><br>(<span class="hljs-keyword">function</span>(<span class="hljs-params"></span>){<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-variable language_">this</span>)})();<br><span class="hljs-comment">//=>object.window</span><br><br></code></pre></td></tr></table></figure><h4 id="作为对象方法被调用">作为对象方法被调用</h4><p>当一个函数被赋值一个对象的属性,并且通过对象属性引用的方式调用函数时,函数会作为对象的方法被调用。 作为对象方法调用的函数this值与对象关联,通过this可以访问所关联对象的其他方法和属性</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">function</span> <span class="hljs-title function_">aa</span>(<span class="hljs-params"></span>){<span class="hljs-keyword">return</span> <span class="hljs-variable language_">this</span>}<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-title function_">aa</span>()==<span class="hljs-variable language_">window</span>);<br><span class="hljs-comment">//=>true</span><br><span class="hljs-keyword">var</span> obj1 = {}<br>obj1.<span class="hljs-property">aa</span> = aa;<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(obj1.<span class="hljs-title function_">aa</span>()==obj1);<br><span class="hljs-comment">//=>true</span><br><span class="hljs-keyword">var</span> obj2 = {}<br>obj2.<span class="hljs-property">bb</span> = aa;<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(obj2.<span class="hljs-title function_">bb</span>()==obj2);<br><span class="hljs-comment">//=>true</span><br></code></pre></td></tr></table></figure><h4 id="作为构造函数调用">作为构造函数调用</h4><p>在函数调用之前加上关键字new,即为构造函数调用。</p><p>构造函数目的是用来创建和初始化一个新对象,然后将这个对象作为构造函数的返回值</p><p>使用关键字new调用函数会触发以下几个动作:🍔</p><ol><li>创建一个新的空对象;</li><li>该对象作为this参数传递给构造函数,成为构造函数的上下文;</li><li>新构造的对象作为new运算符的返回值。</li><li>如果构造函数返回一个对象,则该对象将作为整个表达式的返回值,而传入构造函数的this将被丢弃。</li><li>如果构建函数返回的是非对象类型,则忽略返回值,返回新创建的对象。</li></ol><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">function</span> <span class="hljs-title function_">Ninja</span>(<span class="hljs-params"></span>){<br> <span class="hljs-comment">//这里的this表示Ninja函数的上下文</span><br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">skulk</span> = <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>){<br> <span class="hljs-comment">//这里的this表示该匿名函数的上下文</span><br> <span class="hljs-keyword">return</span> <span class="hljs-variable language_">this</span>;<br> }<br>}<br><span class="hljs-comment">//skulk以对象的方式调用是,返回值是其关联的对象</span><br><span class="hljs-keyword">var</span> ninja1 = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Ninja</span>();<br><span class="hljs-keyword">var</span> ninja2 = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Ninja</span>();<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(ninja1.<span class="hljs-title function_">skulk</span>() == ninja1);<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(ninja2.<span class="hljs-title function_">skulk</span>() == ninja2);<br><span class="hljs-comment">// skulk复制给一个变量后,直接调用函数时,非严格模式下skulk返回的值是window</span><br><span class="hljs-keyword">var</span> skulk = ninja2.<span class="hljs-property">skulk</span>;<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-title function_">skulk</span>() == <span class="hljs-variable language_">window</span>);<br><br></code></pre></td></tr></table></figure><h4 id="通过apply与call方法调用">通过apply与call方法调用</h4><p>javascript提供了可以显示指定任何对象作为函数的上下文的函数调用方式。每个函数都存在apply和call方法。通过apply与call方法来设置函数的上下文。</p><h5 id="call函数">call函数</h5><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">function</span>.<span class="hljs-title function_">call</span>(context, arg1, arg2, ...)<br></code></pre></td></tr></table></figure><p><code>context</code> 是指定函数中的 <code>this</code> 关键字指向的对象,<code>arg1</code>, <code>arg2</code>, … 是传递给函数的参数</p><h5 id="apply函数">apply函数</h5><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">function</span>.<span class="hljs-title function_">apply</span>(context, [argsArray])<br></code></pre></td></tr></table></figure><p><code>context</code> 是指定函数中的 <code>this</code> 关键字指向的对象,<code>argsArray</code> 是一个数组,其中包含要传递给函数的参数</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">function</span> <span class="hljs-title function_">juggle</span>(<span class="hljs-params"></span>){<br> <span class="hljs-keyword">var</span> result = <span class="hljs-number">0</span>;<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">var</span> n=<span class="hljs-number">0</span>; n<<span class="hljs-variable language_">arguments</span>.<span class="hljs-property">length</span>; n++){<br> result+=<span class="hljs-variable language_">arguments</span>[n]<br> }<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">result</span> = result;<br>}<br><br><span class="hljs-keyword">var</span> ninja1 = {};<br><span class="hljs-keyword">var</span> ninja2 = {};<br><br>juggle.<span class="hljs-title function_">apply</span>(ninja1, [<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">4</span>,<span class="hljs-number">5</span>])<br>juggle.<span class="hljs-title function_">call</span>(ninja2, <span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">4</span>,<span class="hljs-number">5</span>, <span class="hljs-number">6</span>)<br><br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(ninja1.<span class="hljs-property">result</span> == <span class="hljs-number">15</span>)<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(ninja2.<span class="hljs-property">result</span> == <span class="hljs-number">21</span>) <br></code></pre></td></tr></table></figure><p>apply和call功能类似,唯一的不同在于如何传递参数。apply和call第一个参数作为函数的上下文,apply第二个参数是一个包含参数值的数组。call可以传入任意数量参数,作为函数的参数。</p><h4 id="总结">总结!!!</h4><h5 id="总结四种函数的调用方式对this取值的影响">总结四种函数的调用方式对this取值的影响</h5><ul><li>如果作为函数调用,在非严格模式下,this指向全局window对象;在严格模式下,this指向undefined。</li><li>作为方法调用,this通常指向调用的对象</li><li>作为构造函数调用,this指向新创建的对象。</li><li>通过call或apply调用,this指向call或apply的第一个参数。</li></ul><h3 id="3-this指向问题-天天被拷打版">3.<code>this</code>指向问题! (天天被拷打版)</h3><h4 id="在全局作用域">在全局作用域</h4><p><code>this->window</code></p><h4 id="在普通函数中">在普通函数中</h4><p>谁调用我 this指向谁</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">var</span> obj = {<br> <span class="hljs-attr">fn1</span>:<span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-variable language_">this</span>); <br> },<br> <span class="hljs-attr">fn2</span>:<span class="hljs-keyword">function</span>(<span class="hljs-params"></span>){<br> <span class="hljs-title function_">fn3</span>() <br> }<br> }<br> <span class="hljs-keyword">function</span> <span class="hljs-title function_">fn3</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-variable language_">this</span>); <br> }<br> <span class="hljs-title function_">fn3</span>();<span class="hljs-comment">//this->window</span><br> obj.<span class="hljs-title function_">fn1</span>();<span class="hljs-comment">//this->obj</span><br> obj.<span class="hljs-title function_">fn2</span>();<span class="hljs-comment">//this->window</span><br><br></code></pre></td></tr></table></figure><h4 id="箭头函数的this">箭头函数的this</h4><p>箭头函数没有自己的this,箭头函数的this就是上下文中定义的this,因为箭头函数没有自己的this所以不能用做构造函数。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">var</span> div = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">'div'</span>); <br> <span class="hljs-keyword">var</span> o={<br> <span class="hljs-attr">a</span>:<span class="hljs-keyword">function</span>(<span class="hljs-params"></span>){<br> <span class="hljs-keyword">var</span> arr=[<span class="hljs-number">1</span>];<br> <span class="hljs-comment">//就是定义所在对象中的this</span><br> <span class="hljs-comment">//这里的this—>o</span><br> arr.<span class="hljs-title function_">forEach</span>(<span class="hljs-function"><span class="hljs-params">item</span>=></span>{<br> <span class="hljs-comment">//所以this -> o</span><br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-variable language_">this</span>);<br> })<br> },<br> <span class="hljs-comment">//这里的this指向window o是定义在window中的对象</span><br> <span class="hljs-attr">b</span>:<span class="hljs-function">()=></span>{<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-variable language_">this</span>);<br> },<br> <span class="hljs-attr">c</span>:<span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-variable language_">this</span>);<br> }<br> }<br> div.<span class="hljs-title function_">addEventListener</span>(<span class="hljs-string">'click'</span>,<span class="hljs-function"><span class="hljs-params">item</span>=></span>{<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-variable language_">this</span>);<span class="hljs-comment">//this->window 这里的this就是定义上文window环境中的this</span><br> });<br> o.<span class="hljs-title function_">a</span>(); <span class="hljs-comment">//this->o</span><br> o.<span class="hljs-title function_">b</span>();<span class="hljs-comment">//this->window</span><br> o.<span class="hljs-title function_">c</span>();<span class="hljs-comment">//this->o 普通函数谁调用就指向谁</span><br><br></code></pre></td></tr></table></figure><h4 id="事件绑定中的this">事件绑定中的this</h4><p>基本上都是指向this->事件源的😆</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">var</span> div = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelector</span>(<span class="hljs-string">'div'</span>); <br> div.<span class="hljs-title function_">addEventListener</span>(<span class="hljs-string">'click'</span>,<span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-variable language_">this</span>); <span class="hljs-comment">//this->div</span><br> });<br> <br> div.<span class="hljs-property">onclick</span> = <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-variable language_">this</span>) <span class="hljs-comment">//this->div</span><br> }<br><br></code></pre></td></tr></table></figure><h4 id="定时器的this">定时器的this</h4><p>定时器中采用回调函数作为处理函数 回调函数的this->window</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs js"> <span class="hljs-built_in">setInterval</span>(<span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-variable language_">this</span>); <span class="hljs-comment">//this->window </span><br> },<span class="hljs-number">500</span>)<br> <br> <span class="hljs-built_in">setTimeout</span>(<span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-variable language_">this</span>); <span class="hljs-comment">//this->window </span><br> },<span class="hljs-number">500</span>)<br><span class="hljs-number">442</span><br></code></pre></td></tr></table></figure><h4 id="构造函数的this">构造函数的this</h4><p>构造函数配合new使用, 而new关键字会将构造函数中的this指向实例化对象,所以构造函数中的this->实例化对象</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">function</span> <span class="hljs-title function_">Person</span>(<span class="hljs-params">name,age</span>) {<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">name</span> = name;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">age</span> = age;<br> }<br> <span class="hljs-keyword">var</span> person1 = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Person</span>();<br> person1.<span class="hljs-property">name</span> = <span class="hljs-string">'ggb'</span>;<br> person1.<span class="hljs-property">age</span> = <span class="hljs-number">21</span>;<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(person1);<span class="hljs-comment">//Person {name: "ggb", age: 21}</span><br> <span class="hljs-keyword">var</span> person2 = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Person</span>();<br> person2.<span class="hljs-property">name</span> = <span class="hljs-string">'syj'</span>;<br> person2.<span class="hljs-property">age</span> = <span class="hljs-number">19</span>;<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(person2);<span class="hljs-comment">// Person {name: "syj", age: 19}</span><br><br></code></pre></td></tr></table></figure>]]></content>
<categories>
<category>javascript</category>
</categories>
</entry>
<entry>
<title>Git宝典</title>
<link href="/2024/04/11/Git%E5%AE%9D%E5%85%B8/"/>
<url>/2024/04/11/Git%E5%AE%9D%E5%85%B8/</url>
<content type="html"><![CDATA[<h1>Git宝典</h1><p>其实这次mini对我自身来说 学到了很多 技术这里就先不说了 终于意识到了git在多人协作写一个大项目的重要性 😆</p><h3 id="啥是Git">啥是Git</h3><p>我对<code>Git</code>这个东西的理解就是 在进行大型项目的开发时候 你不可能单兵作战 一般是有好多好多人一起的 这个时候怎么进行每个人之间的汇总勒</p><p>这个时候 就要用到<code>Git</code>了</p><p>说点官方的话术就是😒</p><p>Git 是一个开源的分布式版本控制系统,用于敏捷高效地处理项目</p><h3 id="Git是怎么工作的呢❓">Git是怎么工作的呢❓</h3><p>如图</p><p><img src="https://www.ruanyifeng.com/blogimg/asset/2015/bg2015120901.png" alt="img"></p><p>具体都是什么意思勒</p><ul><li>Workspace:工作区 (就是你电脑能看到的)</li><li>Index / Stage:暂存区 (一般是在.<code>git</code>目录下的<code>index</code>文件下)</li><li>Repository:仓库区(或本地仓库)</li><li>Remote:远程仓库</li></ul><h3 id="Git咋使用呢">Git咋使用呢</h3><h4 id="1-第一步肯定是新建Git库喽-🆕">1.第一步肯定是新建Git库喽 🆕</h4><p>有两种方法</p><p>1️⃣直接新建!</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">git init<br></code></pre></td></tr></table></figure><p>2️⃣克隆下来一个已经存在的库</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">git clone "url"<br></code></pre></td></tr></table></figure><h4 id="2-基本操作">2.基本操作</h4><p>该说不说这玩意真多啊😡</p><table><thead><tr><th><code>git add</code></th><th><code>添加文件到暂存区</code></th></tr></thead><tbody><tr><td><code>git status</code></td><td><code>查看仓库当前的状态 显示有变更的文件</code></td></tr><tr><td><code>git commit</code></td><td><code>提交暂存区到本地仓库</code></td></tr><tr><td><code>git mv</code></td><td><code>移动或重命名工作区文件</code></td></tr><tr><td><code>git log</code></td><td><code>查看历史提交记录</code></td></tr><tr><td><code>git blame</code></td><td><code>以列表形式查看指定文件的历史修改记录</code></td></tr><tr><td><code>git remote</code></td><td><code>远程仓库操作</code></td></tr><tr><td><code>git fetch</code></td><td><code>从远程获取代码库</code></td></tr><tr><td><code>git pull</code></td><td><code>下载远程代码并合并</code></td></tr><tr><td><code>git push</code></td><td><code>上传远程代码并合并 添加文件到本地暂存区</code></td></tr></tbody></table><ul><li><p>添加文件到暂存区</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs shell">git add 文件名 //这样是添加某个问价<br>git add . //添加该目录下所有未被忽略的文件<br></code></pre></td></tr></table></figure><p>Tips:一般都忽略什么呢?🤔</p><p>一般都会忽略你的node_modules文件夹 因为依赖太多多多多了</p><p></p></li><li><p>提交更改到本地仓库</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">git commit -m "说明"<br></code></pre></td></tr></table></figure><p>这个说明也是有规范滴</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs shell">feat - 新功能 feature<br>fix - 修复 bug<br>docs - 文档注释<br>style - 代码格式(不影响代码运行的变动)<br>refactor - 重构、优化(既不增加新功能,也不是修复bug)<br>perf - 性能优化<br>test - 增加测试<br>chore - 构建过程或辅助工具的变动<br>revert - 回退<br>build - 打包<br></code></pre></td></tr></table></figure><p>就像</p><p><img src="https://img2.imgtp.com/2024/04/13/LVOmRtNs.png" alt="git commit规范.png"></p></li></ul><p>这样写commit的话 就能非常清楚的看到你每次提交了一些什么</p><ul><li><p>分支管理</p><p>创建分支</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">git branch (分支名)<br></code></pre></td></tr></table></figure><p>切换分支</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">git checkout (分支名)<br></code></pre></td></tr></table></figure><p>创建新的分支并且立即切换到该分支</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">git checkout -b (分支名)<br></code></pre></td></tr></table></figure><p>合并分支</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">git merge<br></code></pre></td></tr></table></figure><p>列出分支</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs shell">//列出本地分支<br>git branch<br>//列出全部分支(包括远程分支)<br>git branch -a<br></code></pre></td></tr></table></figure><p>删除分支</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs shell">git branch -d (分支名)<br></code></pre></td></tr></table></figure></li></ul><h3 id="多人协作">多人协作</h3><p>在进行一个大型项目的时候 该怎么使用Git呢</p><p>就是刘总经常说的提PR了 😧</p><p>怎么提呢</p><p>首先你需要找到你用的大型项目仓库</p><p>然后fork!!!</p><p><img src="https://img2.imgtp.com/2024/04/13/6LtBRn7z.png" alt="fork.png"></p><p>然后回到你自己仓库</p><p>就能看到你的本地仓库了</p><ul><li><img src="https://img2.imgtp.com/2024/04/13/OnfI0lWy.png" alt="本地仓库.png"></li></ul><p>怎么提PR勒 🤔</p><p>点击你本地Contribute按钮 然后Open Pull Request</p><p><img src="https://img2.imgtp.com/2024/04/13/NuoY09og.png" alt="pr.png"></p><p>就可以跟本地一样写说明喽 标准也是跟commit的标准差不多的</p><p>小小小Tips:</p><p>在执行<code>git push</code>之前,为了防止远程仓库已有其他人提交的更改与你的更改产生冲突,要先执行<code>git pull</code>拉取远程仓库的代码,如果显示确有冲突,就要在本地手动更改冲突,可利用ide解决。 如果没有冲突,就可以直接推送。如果有冲突,解决冲突后重新执行<code>git add和git commit</code> ,再推送到远程仓库</p><p>就像</p><p><img src="https://img2.imgtp.com/2024/04/13/xIbOddt2.png" alt="git 手动操作.png"></p><p>基本上Git常用的就这些勒 好像博客也可以用Github Actions自动部署 以后有时间试试</p><p>😸</p>]]></content>
<categories>
<category>开发基础</category>
</categories>
</entry>
<entry>
<title>浅学webpack</title>
<link href="/2024/03/23/%C7%B3%D1%A7webpack/"/>
<url>/2024/03/23/%C7%B3%D1%A7webpack/</url>
<content type="html"><![CDATA[<h1>webpack原理(一)</h1><h3 id="1-啥是webpack捏❔">1.啥是webpack捏❔</h3><p>本质上,<strong>webpack</strong> 是一个用于现代 JavaScript 应用程序的 <em>静态模块打包工具</em>。当 webpack 处理应用程序时,它会在内部从一个或多个入口点构建一个 <a href="https://www.webpackjs.com/concepts/dependency-graph/">依赖图(dependency graph)</a>,然后将你项目中所需的每一个模块组合成一个或多个 <em>bundles</em>,它们均为静态资源,用于展示你的内容</p><h3 id="2-webpack主要流程">2.webpack主要流程</h3><p>感觉webpack可以分成三部分</p><ul><li><strong>构建的核心流程</strong></li><li><strong>loader 的作用</strong></li><li><strong>plugin 架构与常用套路</strong></li></ul><h3 id="3-核心流程解析-😆">3.核心流程解析 😆</h3><p>首先得知道这玩意最核心的功能是什么的吧</p><p>就像他官网说的一样</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs word">At its core, webpack is a static module bundler for modern JavaScript applications.<br></code></pre></td></tr></table></figure><p>也就是将各种类型的资源,包括图片、css、js等,转译、组合、拼接、生成 JS 格式的 bundler 文件</p><p><img src="https://img2.imgtp.com/2024/03/23/6xbAXLks.png" alt="屏幕截图 2024-03-23 012454.png"></p><p>这个过程核心完成了 <strong>[内容转换+资源合并]</strong> 两种功能</p><p>实际上包含三个阶段</p><ul><li><h4 id="初始化阶段:">初始化阶段:</h4></li></ul><ol><li><strong>初始化参数</strong>:从配置文件、 配置对象、Shell 参数中读取,与默认配置结合得出最终的参数</li><li><strong>创建编译器对象</strong>:用上一步得到的参数创建 <code>Compiler</code> 对象</li><li><strong>初始化编译环境</strong>:包括注入内置插件、注册各种模块工厂、初始化 RuleSet 集合、加载配置的插件等</li><li><strong>开始编译</strong>:执行 <code>compiler</code> 对象的 <code>run</code> 方法</li><li><strong>确定入口</strong>:根据配置中的 <code>entry</code> 找出所有的入口文件,调用 <code>compilition.addEntry</code> 将入口文件转换为 <code>dependence</code> 对象</li></ol><ul><li><h4 id="构建阶段:">构建阶段:</h4></li></ul><ol><li><strong>编译模块(make)</strong>:根据 <code>entry</code> 对应的 <code>dependence</code> 创建 <code>module</code> 对象,调用 <code>loader</code> 将模块转译为标准 JS 内容,调用 JS 解释器将内容转换为 AST 对象,从中找出该模块依赖的模块,再 递归 本步骤直到所有入口依赖的文件都经过了本步骤的处理</li><li><strong>完成模块编译</strong>:上一步递归处理所有能触达到的模块后,得到了每个模块被翻译后的内容以及它们之间的 <strong>依赖关系图</strong></li></ol><ul><li><h4 id="生成阶段:">生成阶段:</h4></li></ul><ol><li><strong>输出资源(seal)</strong>:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 <code>Chunk</code>,再把每个 <code>Chunk</code> 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会</li><li><strong>写入文件系统(emitAssets)</strong>:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统</li></ol><p><img src="https://img2.imgtp.com/2024/03/23/czXM2g2f.png" alt="屏幕截图 2024-03-23 012530.png"></p><p>接下来说说细节部分吧 对上面一些听起来很高级的名词解释一手 :happy:</p><ul><li><p><code>Entry</code>:编译入口,webpack 编译的起点</p></li><li><p><code>Compiler</code>:编译管理器,webpack 启动后会创建 <code>compiler</code> 对象,该对象一直存活知道结束退出</p><p>这玩意记录了webpack运行环境的所有信息 插件可以通过它获取到webpack配置信息,像<code>entry output module</code>等配置</p></li><li><p><code>Compilation</code>:单次编辑过程的管理器,比如 <code>watch = true</code> 时,运行过程中只有一个 <code>compiler</code> 但每次文件变更触发重新编译时,都会创建一个新的 <code>compilation</code> 对象</p><p>它储存了当前的模块资源、编译生成的资源、变化的文件、以及被跟踪依赖的状态信息</p></li><li><p><code>Dependence</code>:依赖对象,webpack 基于该类型记录模块间依赖关系</p></li><li><p><code>Module</code>:webpack 内部所有资源都会以“module”对象形式存在,所有关于资源的操作、转译、合并都是以 “module” 为基本单位进行的</p></li><li><p><code>Chunk</code>:编译完成准备输出时,webpack 会将 <code>module</code> 按特定的规则组织成一个一个的 <code>chunk</code>,这些 <code>chunk</code> 某种程度上跟最终输出一一对应</p></li><li><p><code>Loader</code>:资源内容转换器,其实就是实现从内容 A 转换 B 的转换器</p></li><li><p><code>Plugin</code>:webpack构建过程中,会在特定的时机广播对应的事件,插件监听这些事件,在特定时间点介入编译过程</p></li></ul><h3 id="4-Plugin解析">4.<code>Plugin</code>解析</h3><p>看插件之前 首先想三个问题</p><p>什么是插件</p><p>什么时间点会有什么钩子被触发</p><p>在钩子回调中,如何影响编译状态</p><h4 id="What-什么是插件🚘">What: 什么是插件🚘</h4><p>先从形态上来看 插件是个带有<code>apply</code>函数的类</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">class</span> <span class="hljs-title class_">SomePlugin</span> {<br><span class="hljs-title function_">apply</span>(<span class="hljs-params">compiler</span>){<br>}<br>}<br></code></pre></td></tr></table></figure><p><code>apply</code> 函数运行时会得到参数 <code>compiler</code> ,以此为起点可以调用 <code>hook</code> 对象注册各种钩子回调,例如: <code>compiler.hooks.make.tapAsync</code> ,这里面 <code>make</code> 是钩子名称,<code>tapAsync</code> 定义了钩子的调用方式,webpack 的插件架构基于这种模式构建而成,插件开发者可以使用这种模式在钩子回调中,插入特定代码。webpack 各种内置对象都带有 <code>hooks</code> 属性,比如 <code>compilation</code> 对象:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">class</span> <span class="hljs-title class_">SomePlugin</span> {<br> <span class="hljs-title function_">apply</span>(<span class="hljs-params">compiler</span>) {<br> compiler.<span class="hljs-property">hooks</span>.<span class="hljs-property">thisCompilation</span>.<span class="hljs-title function_">tap</span>(<span class="hljs-string">'SomePlugin'</span>, <span class="hljs-function">(<span class="hljs-params">compilation</span>) =></span> {<br> compilation.<span class="hljs-property">hooks</span>.<span class="hljs-property">optimizeChunkAssets</span>.<span class="hljs-title function_">tapAsync</span>(<span class="hljs-string">'SomePlugin'</span>, <span class="hljs-function">()=></span>{});<br> })<br> }<br>}<br></code></pre></td></tr></table></figure><h4 id="When-什么时候会触发钩子-📦">When: 什么时候会触发钩子 📦</h4><p>官网对钩子的说明都比较简短</p><p>直接看几个例子吧</p><p><code>compiler.hooks.compilation</code> :</p><ul><li>时机:启动编译创建出 compilation 对象后触发</li><li>参数:当前编译的 compilation 对象</li><li>示例:很多插件基于此事件获取 compilation 实例</li></ul><p><code>compiler.hooks.make</code>:</p><ul><li>时机:正式开始编译时触发</li><li>参数:同样是当前编译的 <code>compilation</code> 对象</li><li>示例:webpack 内置的 <code>EntryPlugin</code> 基于此钩子实现 <code>entry</code> 模块的初始化</li></ul><p><code>compilation.hooks.optimizeChunks</code> :</p><ul><li>时机: <code>seal</code> 函数中,<code>chunk</code> 集合构建完毕后触发</li><li>参数:<code>chunks</code> 集合与 <code>chunkGroups</code> 集合</li><li>示例: <code>SplitChunksPlugin</code> 插件基于此钩子实现 <code>chunk</code> 拆分优化</li></ul><p><code>compiler.hooks.done</code>:</p><ul><li>时机:编译完成后触发</li><li>参数: <code>stats</code> 对象,包含编译过程中的各类统计信息</li><li>示例: <code>webpack-bundle-analyzer</code> 插件基于此钩子实现打包分析</li></ul><p>看这个钩子时候我直接看 触发时机 传递参数 示例代码</p><p>首先看触发时机勒</p><p>触发时机是与webpack工作过程紧密相关的,大体上从启动到结束,<code>compiler</code>对象逐次触发以下钩子</p><p><img src="https://img2.imgtp.com/2024/03/23/1p0WM3NF.png" alt="屏幕截图 2024-03-23 012707.png"></p><p>而<code>compilation</code>对象逐次触发:</p><p><img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/de1f0d05a1274e6d86959b60a3d98742~tplv-k3u1fbpfcp-zoom-in-crop-mark:1512:0:0:0.awebp" alt="image (1).png"></p><p>就都是嘟嘟嘟嘟嘟嘟长串 😓</p><p>我自己的理解是 这个时机就是几个情况</p><ul><li>创建出这个对象触发</li><li>正式开始编译就触发</li><li>函数构建完毕后触发</li></ul><p>传递参数</p><p>我在他的配置里没怎么找到 感觉无非传点modules之类的东西</p><p>示例代码</p><p>webpack这钩子实话实说</p><p>抽象程度是小大的 我感觉最好的学习办法 就是查询其他插件中如何使用这些钩子 不然你就看吧 一看一个不吱声😭</p><h4 id="How-如何影响编译状态捏">How 如何影响编译状态捏</h4><p>webpack的插件体系跟平常看到的不太一样 hooks回调由webpack决定何时 以何种方式 而在hooks回调内部可以直接修改状态 调用上下文api等方式webpack产生 一些影响</p><p>举个🏮子</p><p><code>EntryPlugin</code>插件</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">class</span> <span class="hljs-title class_">EntryPlugin</span> {<br> <span class="hljs-title function_">apply</span>(<span class="hljs-params">compiler</span>) {<br> compiler.<span class="hljs-property">hooks</span>.<span class="hljs-property">compilation</span>.<span class="hljs-title function_">tap</span>(<br> <span class="hljs-string">"EntryPlugin"</span>,<br> <span class="hljs-function">(<span class="hljs-params">compilation, { normalModuleFactory }</span>) =></span> {<br> compilation.<span class="hljs-property">dependencyFactories</span>.<span class="hljs-title function_">set</span>(<br> <span class="hljs-title class_">EntryDependency</span>,<br> normalModuleFactory<br> );<br> }<br> );<br><br> compiler.<span class="hljs-property">hooks</span>.<span class="hljs-property">make</span>.<span class="hljs-title function_">tapAsync</span>(<span class="hljs-string">"EntryPlugin"</span>, <span class="hljs-function">(<span class="hljs-params">compilation, callback</span>) =></span> {<br> <span class="hljs-keyword">const</span> { entry, options, context } = <span class="hljs-variable language_">this</span>;<br><br> <span class="hljs-keyword">const</span> dep = <span class="hljs-title class_">EntryPlugin</span>.<span class="hljs-title function_">createDependency</span>(entry, options);<br> compilation.<span class="hljs-title function_">addEntry</span>(context, dep, options, <span class="hljs-function">(<span class="hljs-params">err</span>) =></span> {<br> <span class="hljs-title function_">callback</span>(err);<br> });<br> });<br> }<br>}<br></code></pre></td></tr></table></figure><p>在这里面 webpack会将上下文信息以参数或<code>this</code>形式传递给钩子回调用</p><p>在回调中可以调用上下文对象的方法或者直接修改上下文对象属性的方式,对原定的流程产生 side effect。所以想纯熟地编写插件,除了要理解调用时机,还需要了解我们可以用哪一些api,例如:</p><ul><li><code>compilation.addModule</code>:添加模块,可以在原有的 <code>module</code> 构建规则之外,添加自定义模块</li><li><code>compilation.emitAsset</code>:直译是“提交资产”,功能可以理解将内容写入到一个特定路径</li><li><code>compilation.addEntry</code>:添加入口,功能上与直接定义 <code>entry</code> 配置相同</li><li><code>module.addError</code>:添加编译错误信息</li></ul><h3 id="5-Loader介绍">5.Loader介绍</h3><p>看一下<code>loader</code>在编译流程中的生效位置</p><p><img src="https://img2.imgtp.com/2024/03/23/IYzGYIPf.png" alt="屏幕截图 2024-03-23 012734.png"></p><p>在这个流程图里,<code>runloaders</code>会调用用户所配置的loader集合读取,转移资源,前面的内容可以千奇百怪👽</p><p>但是转译之后一般都是输出Javascript文本,webpack才可以继续处理模块依赖</p><p>理解了这个基本逻辑,loader职责基本上也知道了 就是把内容A =>内容B</p>]]></content>
<categories>
<category>webpack</category>
</categories>
</entry>
<entry>
<title>自定义React hooks</title>
<link href="/2024/03/08/%E8%87%AA%E5%AE%9A%E4%B9%89React%20Hooks/"/>
<url>/2024/03/08/%E8%87%AA%E5%AE%9A%E4%B9%89React%20Hooks/</url>
<content type="html"><![CDATA[<h1>自定义<code>React Hooks</code></h1><h3 id="1-为什么会出现hooks这个东西捏-❓">1.为什么会出现<code>hooks</code>这个东西捏 ❓</h3><p>刚看<code>hooks</code> 就出现了这个问题 <code>hooks</code>出现的意义在哪里呢</p><p><code>hooks</code>能解决什么问题</p><p><code>React</code>中组件有两种写法 一种类组件 一种函数组件</p><p>但是函数组件相对于类组件来说有一个小小滴缺点 就是没有<code>state</code> 😔</p><p>所以<code>hooks</code>就应运而生勒😀</p><p><code>hooks</code>是一类特殊的函数 允许在React的函数式组件中"钩入"状态,生命周期等其他<code>React</code>的特性</p><p>提供了一种无需类组件的方式,使得现在在函数式组件中可以使用像 <code>this.state</code>,<code>this.props</code>的概念勒🌵</p><h3 id=""></h3><h3 id="2-那hooks都这么厉害了-为什么还要有自定义的hooks捏❔">2.那<code>hooks</code>都这么厉害了 为什么还要有自定义的<code>hooks</code>捏❔</h3><p>正常的<code>useState</code>接受两个参数</p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs jsx"><span class="hljs-keyword">const</span> [state,setState]=<span class="hljs-title function_">useState</span>(<span class="hljs-string">''</span>)<br></code></pre></td></tr></table></figure><p>正常在类组件中<code>setState</code>会支持两个参数: 一个是更新后的<code>state</code>或者回调式更新的<code>state</code> 另一个参数是更新后的回调函数</p><p><code>tips</code>:什么是回调函数😓</p><p>回调 (callback) 是<strong>作为参数传递给另一个函数的函数</strong> ,并在被调用函数执行完毕后被调用</p><p>个人的小理解: 回调函数就是先定义了<code>functionA</code>然后再定义了<code>functionB</code></p><p>但是在使用时候先用了<code>functionB</code> 并且把<code>functionA</code>当成了参数给了<code>functionB</code></p><p><code>useState</code> hook并不直接支持像类组件中的<code>setState</code>方法那样可以接收第二个参数作为回调函数。<code>useState</code> hook返回的更新函数只能用于更新状态,并且不会提供回调函数的选项</p><p>所以自定义<code>hooks</code>就出现啦</p><h3 id="3-来自定义useState吧🍶">3.来自定义<code>useState</code>吧🍶</h3><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs jsx"><span class="hljs-keyword">const</span> <span class="hljs-title function_">useStatePro</span> =(<span class="hljs-params">initState</span>)=>{<br> <span class="hljs-keyword">const</span> [state,setState]=<span class="hljs-title function_">useState</span>(initState);<br> <span class="hljs-comment">//存储一手回调函数</span><br> <span class="hljs-keyword">const</span> isUpdate=<span class="hljs-title function_">useRef</span>()<br> <span class="hljs-comment">//定义一个新函数喽 (接受一个新状态和一个回调函数)</span><br> <span class="hljs-keyword">const</span> <span class="hljs-title function_">setStatePro</span> =(<span class="hljs-params">newState,cb</span>)=>{<br> <span class="hljs-comment">//使用setState更新状态 把回调函数储存在current里 </span><br> <span class="hljs-comment">//如果newState是个函数的情况下 就计算新状态 </span><br> <span class="hljs-title function_">setState</span>(<br> <span class="hljs-function"><span class="hljs-params">prev</span>=></span>{<br> isUpdate.<span class="hljs-property">current</span>=cb<br> <span class="hljs-keyword">return</span> <span class="hljs-keyword">typeof</span> newState=<span class="hljs-string">'function'</span> ? <span class="hljs-title function_">newState</span>(prev):newState<br> }<br> )<br> }<br> <span class="hljs-comment">//检查一下current有无回调函数 有就直接执行</span><br> <span class="hljs-title function_">useEffect</span>(<span class="hljs-function">()=></span>{<br> <span class="hljs-keyword">if</span>(isUpdate.<span class="hljs-property">current</span>)<br> {<br><span class="hljs-keyword">return</span> isUpdate.<span class="hljs-title function_">current</span>()<br> }<br> })<br> <span class="hljs-keyword">return</span> [state,useStatePro]<br>}<br></code></pre></td></tr></table></figure><p>这样就实现了<code>useState</code>的功能 但是多了一个在状态更新后执行回调函数的功能</p><h3 id="4-自定义一个更新函数useUpdate">4.自定义一个更新函数<code>useUpdate</code></h3><p>如果正常使用<code>hooks</code>想让组件重新渲染 一般是要更新state的</p><p>但是有的时候可能一个state掌握着好几个组件的生死大权😈</p><p>不能就为了一个小小的组件就让state作出无意义的更新</p><p>这时候可以想想能不能定义一个更新的<code>hooks</code>来优雅一些实现组件的强制更新</p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs jsx"><span class="hljs-keyword">const</span> <span class="hljs-title function_">Update</span>=(<span class="hljs-params"></span>)=>{<br> <span class="hljs-keyword">const</span> [,setFlag]=<span class="hljs-title function_">useState</span>()<br> <span class="hljs-keyword">const</span> <span class="hljs-title function_">update</span>=(<span class="hljs-params"></span>)=>{<br> <span class="hljs-comment">//更新一手时间</span><br> <span class="hljs-title function_">setFlag</span>(<span class="hljs-title class_">Date</span>.<span class="hljs-title function_">now</span>())<br> }<br> <span class="hljs-keyword">return</span> update<br>}<br></code></pre></td></tr></table></figure><p>发现这个函数返回了一个函数 这个函数就是用来强制更新的</p><p>咋使用他捏💅</p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs jsx"><span class="hljs-keyword">const</span> <span class="hljs-title function_">Time</span>=(<span class="hljs-params"></span>)=>{<br> <span class="hljs-keyword">const</span> update=<span class="hljs-title function_">useUpdate</span>();<br> <span class="hljs-keyword">return</span>(<br> {<span class="hljs-title class_">Date</span>.<span class="hljs-title function_">now</span>()}<br> <div><span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">button</span> <span class="hljs-attr">onCLick</span>=<span class="hljs-string">{update}</span>></span>更新喽<span class="hljs-tag"></<span class="hljs-name">button</span>></span></span></div><br> )<br>}<br></code></pre></td></tr></table></figure><h3 id="5-自定义hooks实现redux">5.自定义hooks实现<code>redux</code></h3><p><code>Redux</code>目前来说还是常用的管理状态的工具 但是<code>Redux</code>需要遵守的规则和步骤有点小多😡</p><p>所以来制作一个属于自己的<code>Redux</code></p><h4 id="1-首先先把应用接口做好">1.首先先把应用接口做好</h4><p>在顶部引入<code>Provider</code>组件为所有的儿孙组件提供所有数据源<code>store</code></p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs jsx"><span class="hljs-keyword">import</span> <span class="hljs-title class_">React</span> <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;<br><span class="hljs-keyword">import</span> <span class="hljs-title class_">ReactDOM</span>, {render} <span class="hljs-keyword">from</span> <span class="hljs-string">'react-dom'</span>;<br><span class="hljs-keyword">import</span> <span class="hljs-title class_">App</span> <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/App'</span><br><span class="hljs-keyword">import</span> <span class="hljs-title class_">Provider</span> <span class="hljs-keyword">from</span> <span class="hljs-string">'./store/provider'</span><br><span class="hljs-comment">// 挂载节点</span><br><span class="hljs-title function_">render</span>((<br> <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">Provider</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">App</span>/></span></span><br><span class="language-xml"> <span class="hljs-tag"></<span class="hljs-name">Provider</span>></span></span><br>), <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">getElementById</span>(<span class="hljs-string">'app'</span>)<br>)<br></code></pre></td></tr></table></figure><h4 id="2-然后就可以开始设计store啦-happy">2.然后就可以开始设计<code>store</code>啦:happy:</h4><p>首先就是数据项</p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><code class="hljs jsx"><span class="hljs-comment">//初始化数据</span><br><span class="hljs-keyword">const</span> initState={<br> <span class="hljs-attr">count</span>:<span class="hljs-number">0</span>;<br>}<br><span class="hljs-comment">//reducer 处理器</span><br><span class="hljs-keyword">const</span> <span class="hljs-title function_">reducer</span> =(<span class="hljs-params">state,action</span>)=>{<br> <span class="hljs-keyword">const</span>{type,payload}=action<br> <span class="hljs-keyword">switch</span>(type){<br> <span class="hljs-keyword">case</span><span class="hljs-string">'ADD_COUNT'</span>:<span class="hljs-keyword">return</span>{...state ,<span class="hljs-attr">count</span>:state.<span class="hljs-property">count</span>+<span class="hljs-number">1</span>}<br> <span class="hljs-keyword">default</span> : <span class="hljs-keyword">return</span> state;<br> }<br>}<span class="hljs-comment">// 创建上下文</span><br><span class="hljs-keyword">const</span> <span class="hljs-title class_">Context</span> = <span class="hljs-title class_">React</span>.<span class="hljs-title function_">createContext</span>()<br><span class="hljs-keyword">const</span> <span class="hljs-title function_">Provider</span> = (<span class="hljs-params">props</span>) => {<br><span class="hljs-keyword">const</span> [state, dispatch] = <span class="hljs-title function_">useReducer</span>(reducer, initState)<br><span class="hljs-keyword">return</span> (<br> <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">Context.Provider</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{{state,</span> <span class="hljs-attr">dispatch</span>}}></span></span><br><span class="language-xml"> {props.children}</span><br><span class="language-xml"> <span class="hljs-tag"></<span class="hljs-name">Context.Provider</span>></span></span><br>)<br>}<br><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> { <span class="hljs-title class_">Context</span>, <span class="hljs-title class_">Provider</span> }<br><br></code></pre></td></tr></table></figure><p>在这个数据项中可以看出 initState<code> </code>reducer<code>的定义和使用</code>redux`是一模一样的</p><p>重点看下面的创建的上下文 首先通过<code>React.createContext()</code>创建一个空的上下文</p><p>然后定义<code>Provider</code>这个组件 在内部用<code>useReducer</code>把<code>reducer</code>和初始化的<code>initState</code>传入进去</p><p>返回的<code>state</code>和<code>dispatch</code>提供到<code>Provider</code>作为数据源</p><p>数据项聚合一下</p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><code class="hljs jsx"><span class="hljs-comment">// 聚合count、todo这些数据项</span><br><span class="hljs-keyword">const</span> providers = [<br> <span class="hljs-title class_">Count</span>.<span class="hljs-property">Provider</span>,<br> <span class="hljs-title class_">Todo</span>.<span class="hljs-property">Provider</span><br>];<br><span class="hljs-comment">// 递归包裹Provider</span><br><span class="hljs-keyword">const</span> <span class="hljs-title function_">ProvidersComposer</span> = (<span class="hljs-params">props</span>) => (<br> props.<span class="hljs-property">providers</span>.<span class="hljs-title function_">reduceRight</span>(<span class="hljs-function">(<span class="hljs-params">children, Parent</span>) =></span> (<br> <span class="hljs-keyword">return</span> <span class="hljs-title class_">Parent</span>({children})<br> ), props.<span class="hljs-property">children</span>)<br>)<br><span class="hljs-keyword">const</span> <span class="hljs-title function_">Provider</span> = (<span class="hljs-params">props</span>) => {<br><span class="hljs-keyword">return</span> (<br> <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">ProvidersComposer</span> <span class="hljs-attr">providers</span>=<span class="hljs-string">{providers}</span>></span></span><br><span class="language-xml"> {props.children}</span><br><span class="language-xml"> <span class="hljs-tag"></<span class="hljs-name">ProvidersComposer</span>></span></span><br>)<br>}<br><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-title class_">Provider</span><br></code></pre></td></tr></table></figure><p>最后出来的组件结构: <code>Provider > Context.Provider > Context.Provider > App</code> 我们通过ProviderComposer进行递归包裹,把每个<code>Provider</code>进行一层一层的包裹 这里使用了<code>parent({children})</code>替代了<code><Parent>{children}</Parent></code>,这样的做法可以减少一层嵌套结构。</p><p>如何使用捏💩</p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><code class="hljs jsx"><span class="hljs-keyword">import</span> <span class="hljs-title class_">React</span>, { useContext, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;<br><span class="hljs-comment">// 引入count数据源</span><br><span class="hljs-keyword">import</span> <span class="hljs-title class_">CountStore</span> <span class="hljs-keyword">from</span> <span class="hljs-string">'@/store/modules/count'</span><br><br><span class="hljs-keyword">const</span> <span class="hljs-title function_">App</span> = (<span class="hljs-params">props</span>) => {<br> <span class="hljs-comment">// 通过useContext使用Count这个store的上下文</span><br> <span class="hljs-keyword">const</span> {state, dispatch} = <span class="hljs-title function_">useContext</span>(<span class="hljs-title class_">CountStore</span>.<span class="hljs-property">Context</span>)<br> <span class="hljs-comment">// 每秒更新count</span><br> <span class="hljs-title function_">useEffect</span>(<span class="hljs-function">() =></span> {<br> <span class="hljs-built_in">setInterval</span>(<span class="hljs-function">() =></span> {<br> <span class="hljs-title function_">dispatch</span>({ <span class="hljs-attr">type</span>: <span class="hljs-string">'ADD_COUNT'</span> })<br> }, <span class="hljs-number">1000</span>);<br> }, [])<br> <br> <span class="hljs-keyword">return</span> (<br> <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'app'</span>></span></span><br><span class="language-xml"> {JSON.stringify(state)}</span><br><span class="language-xml"> <span class="hljs-tag"></<span class="hljs-name">div</span>></span></span><br> )<br>}<br><br><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-title class_">App</span><br><br></code></pre></td></tr></table></figure><p>这样就实现啦一个小型<code>redux</code> 感觉比正常的<code>redux</code>会好用一些捏</p>]]></content>
<categories>
<category>React</category>
</categories>
</entry>
<entry>
<title>React hook</title>
<link href="/2024/02/17/React%20hook/"/>
<url>/2024/02/17/React%20hook/</url>
<content type="html"><![CDATA[<h1><code>React hook</code></h1><h3 id="Hook-的优势">Hook 的优势</h3><ul><li>Hook 使你在无需改变组件结构的情况下复用状态逻辑(自定义 Hook)</li><li>Hook 将组件中互相关联的部分拆分成更小的函数(比如设置订阅或请求数据)</li><li>Hook 使你在非 class 的情况下可以使用更多的 React 特性</li></ul><h3 id="Hook-使用规则">Hook 使用规则</h3><p>Hook 就是 <code>Javascript</code> 函数,使用它们时有两个额外的规则:</p><ul><li>只能在<strong>函数外层</strong>调用 Hook,不要在循环、条件判断或者子函数中调用</li><li>只能在 <strong>React 的函数组件</strong> 和<strong>自定义 Hook</strong> 中调用 Hook。不要在其他 JavaScript 函数中调用</li></ul><p>在组件中 React 是通过判断 Hook 调用的顺序来判断某个 state 对应的 <code>useState</code>的,所以必须保证 Hook 的调用顺序在多次渲染之间保持一致,React 才能正确地将内部 state 和对应的 Hook 进行关联</p><h2 id="useState"><code>useState</code></h2><p><code>useState</code> 可以使函数组件像类组件一样拥有 <code>state</code>,函数组件通过 <code>useState</code> 可以让组件重新渲染,更新视图</p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs jsx"><span class="hljs-keyword">const</span> [ ①state , ②dispatch ] = <span class="hljs-title function_">useState</span>(③initData)<br></code></pre></td></tr></table></figure><p>① <code>state</code>,目的提供给 <code>UI</code> ,作为渲染视图的数据源</p><p>② <code>dispatchAction</code>(setState) 改变 state 的函数,可以理解为推动函数组件渲染的渲染函数</p><p>③ <code>initData</code> 有两种情况,第一种情况是非函数,将作为 state 初始化的值。 第二种情况是函数,函数的返回值作为 <code>useState</code> 初始化的值</p><p>基础用法</p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs jsx"><span class="hljs-keyword">const</span> <span class="hljs-title function_">DemoState</span> = (<span class="hljs-params">props</span>) => {<br> <span class="hljs-comment">/* number为此时state读取值 ,setNumber为派发更新的函数 */</span><br> <span class="hljs-keyword">let</span> [number, setNumber] = <span class="hljs-title function_">useState</span>(<span class="hljs-number">0</span>) <span class="hljs-comment">/* 0为初始值 */</span><br> <span class="hljs-keyword">return</span> (<span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">span</span>></span>{ number }<span class="hljs-tag"></<span class="hljs-name">span</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{</span> ()=></span> {</span><br><span class="language-xml"> setNumber(number+1)</span><br><span class="language-xml"> console.log(number) /* 这里的number是不能够即使改变的 */</span><br><span class="language-xml"> } } ><span class="hljs-tag"></<span class="hljs-name">button</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"></<span class="hljs-name">div</span>></span></span>)<br>}<br></code></pre></td></tr></table></figure><p><strong>``useState 注意事项`:</strong></p><p>① 在函数组件一次执行上下文中,state 的值是固定不变的</p><p>② 如果两次 <code>dispatchAction</code> 传入相同的 state 值,那么组件就不会更新</p><p>③ 当触发 <code>dispatchAction</code> 在当前执行上下文中获取不到最新的 <code>state</code>, 只有在下一次组件 rerender 中才能获取到。</p><h2 id="useReducer"><code>useReducer</code></h2><p>组件中可能有多个位置包括了对某个状态的修改操作</p><p><code>useReducer</code>用于统一管理状态的操作方式</p><p>使用 <code>useReducer</code> 还能给那些会触发深更新的组件做性能优化,因为父组件可以向子组件传递 <code>dispatch</code> 而不是回调函数</p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs jsx"><span class="hljs-keyword">const</span>[state,dispatch]= useReducer (countReducer,<span class="hljs-number">0</span>)<br></code></pre></td></tr></table></figure><p>① 更新之后的 state 值。</p><p>② 派发更新的 dispatch 函数, 本质上和 <code>useState</code> 的 dispatch是一样的。</p><p>③ 一个函数<code>countReducer</code> 常规reducer里面的 state 和action</p><p>准备一个用来进行状态功能管理的函数</p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><code class="hljs jsx"><span class="hljs-keyword">function</span> <span class="hljs-title function_">countReducer</span> (state,action)<br><span class="hljs-comment">//state reducer管理状态的是哪个</span><br><span class="hljs-comment">//action 对这个状态进行哪些操作</span><br>{<br> <span class="hljs-keyword">switch</span>(action.<span class="hljs-property">type</span>)<br> {<br> <span class="hljs-keyword">case</span><span class="hljs-string">"increment"</span> :<span class="hljs-keyword">return</span> state+<span class="hljs-number">1</span><br> <span class="hljs-keyword">case</span> <span class="hljs-string">"decrement"</span>:<span class="hljs-keyword">return</span> state-<span class="hljs-number">1</span> <br> <span class="hljs-attr">default</span>:<br> <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Error</span>()<br> }<br>}<br><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">App</span> ()<br>{<br> <span class="hljs-comment">//state 状态当前值</span><br> <span class="hljs-comment">//dispatch 用来进行状态修改的触发器 (函数值) </span><br> <span class="hljs-keyword">const</span> [state,dispath]=<span class="hljs-title function_">useReducer</span>(countReducer,<span class="hljs-number">0</span>)<br> <span class="hljs-keyword">const</span> <span class="hljs-title function_">handleIncrement</span>=(<span class="hljs-params"></span>)=><span class="hljs-title function_">dispath</span>({<span class="hljs-attr">type</span>:<span class="hljs-string">"increment"</span>})<br> <span class="hljs-keyword">const</span> <span class="hljs-title function_">handleDecrement</span>=(<span class="hljs-params"></span>)=><span class="hljs-title function_">dispath</span>({<span class="hljs-attr">type</span>:<span class="hljs-string">"decrement"</span>})<br> <span class="hljs-keyword">return</span> (<br> <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleIncrement}</span>></span>-<span class="hljs-tag"></<span class="hljs-name">button</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">span</span>></span>{state}<span class="hljs-tag"></<span class="hljs-name">span</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleDecrement}</span>></span>+<span class="hljs-tag"></<span class="hljs-name">button</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"></<span class="hljs-name">div</span>></span></span><br> )<br>}<br></code></pre></td></tr></table></figure><h2 id="useSyncExternalStore"><code>useSyncExternalStore</code></h2><p>不懂以后再说</p><h2 id="useTransition"><code>useTransition</code></h2><p>别急</p><h2 id="useDeferredValue"><code>useDeferredValue</code></h2><p>你也别急</p><h2 id="useEffect"><code>useEffect</code></h2><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs jsx"><span class="hljs-title function_">useEffect</span>(<span class="hljs-function">()=></span>{<br> <span class="hljs-keyword">return</span> destory<br>},dep)<br></code></pre></td></tr></table></figure><p>第一个参数<code>callback</code>返回的 <code>destroy</code> 作为下一次<code>callback</code>执行之前调用 用于清楚上一次<code>callback</code>产生的副作用</p><p>第二个参数作为依赖项,是一个数组,可以有多个依赖项,依赖项改变,执行上一次callback 返回的 <code>destory</code> ,和执行新的 effect 第一个参数 callback</p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><code class="hljs jsx"><span class="hljs-comment">/* 模拟数据交互 */</span><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">getUserInfo</span>(<span class="hljs-params">a</span>){<br> <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve</span>)=></span>{<br> <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">()=></span>{ <br> <span class="hljs-title function_">resolve</span>({<br> <span class="hljs-attr">name</span>:a,<br> <span class="hljs-attr">age</span>:<span class="hljs-number">16</span>,<br> }) <br> },<span class="hljs-number">500</span>)<br> })<br>}<br><span class="hljs-keyword">const</span> <span class="hljs-title function_">Demo</span> = (<span class="hljs-params">{ a }</span>) => {<br> <span class="hljs-keyword">const</span> [ userMessage , setUserMessage ] :any= <span class="hljs-title function_">useState</span>({})<br> <span class="hljs-keyword">const</span> div= <span class="hljs-title function_">useRef</span>()<br> <span class="hljs-keyword">const</span> [number, setNumber] = <span class="hljs-title function_">useState</span>(<span class="hljs-number">0</span>)<br> <span class="hljs-comment">/* 模拟事件监听处理函数 */</span><br> <span class="hljs-keyword">const</span> <span class="hljs-title function_">handleResize</span> =(<span class="hljs-params"></span>)=>{}<br> <span class="hljs-comment">/* useEffect使用 ,这里如果不加限制 ,会是函数重复执行,陷入死循环*/</span><br> <span class="hljs-title function_">useEffect</span>(<span class="hljs-function">()=></span>{<br> <span class="hljs-comment">/* 请求数据 */</span><br> <span class="hljs-title function_">getUserInfo</span>(a).<span class="hljs-title function_">then</span>(<span class="hljs-function"><span class="hljs-params">res</span>=></span>{<br> <span class="hljs-title function_">setUserMessage</span>(res)<br> })<br> <span class="hljs-comment">/* 定时器 延时器等 */</span><br> <span class="hljs-keyword">const</span> timer = <span class="hljs-built_in">setInterval</span>(<span class="hljs-function">()=></span><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-number">666</span>),<span class="hljs-number">1000</span>)<br> <span class="hljs-comment">/* 操作dom */</span><br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(div.<span class="hljs-property">current</span>) <span class="hljs-comment">/* div */</span><br> <span class="hljs-comment">/* 事件监听等 */</span><br> <span class="hljs-variable language_">window</span>.<span class="hljs-title function_">addEventListener</span>(<span class="hljs-string">'resize'</span>, handleResize)<br> <span class="hljs-comment">/* 此函数用于清除副作用 */</span><br> <span class="hljs-keyword">return</span> <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>){<br> <span class="hljs-built_in">clearInterval</span>(timer) <br> <span class="hljs-variable language_">window</span>.<span class="hljs-title function_">removeEventListener</span>(<span class="hljs-string">'resize'</span>, handleResize)<br> }<br> <span class="hljs-comment">/* 只有当props->a和state->number改变的时候 ,useEffect副作用函数重新执行 ,如果此时数组为空[],证明函数只有在初始化的时候执行一次相当于componentDidMount */</span><br> },[ a ,number ])<br> <span class="hljs-keyword">return</span> (<span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{div}</span> ></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">span</span>></span>{ userMessage.name }<span class="hljs-tag"></<span class="hljs-name">span</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">span</span>></span>{ userMessage.age }<span class="hljs-tag"></<span class="hljs-name">span</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{</span> ()=></span> setNumber(1) } >{ number }<span class="hljs-tag"></<span class="hljs-name">div</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"></<span class="hljs-name">div</span>></span></span>)<br>}<br><br></code></pre></td></tr></table></figure><p>如上在 <code>useEffect</code> 中做的功能如下:</p><ul><li>① 请求数据。</li><li>② 设置定时器,延时器等。</li><li>③ 操作 <code>Dom </code></li><li>④ 注册事件监听器, 事件绑定</li><li>⑤ 还可以清除定时器,延时器,解绑事件监听器等。</li></ul><h2 id="useLayoutEffect"><code>useLayoutEffect</code></h2><p>别急</p><h2 id="useInsertionEffect"><code>useInsertionEffect</code></h2><p>你也别急</p><h2 id="useContext"><code>useContext</code></h2><p>可以用<code>useContext</code> 来获取父级组件传递过来的<code>context</code>的值</p><p>这个当前值就是最近的父级组件<code>Provider</code> 设置的<code>value</code>值 ,</p><p><code>useContext</code> 参数一般是由<code>createContext</code>方式创建的,也可以父级上下文<code>context</code>传递的(参数是<code>context</code> )</p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs jsx"><span class="hljs-keyword">const</span> contextValue = <span class="hljs-title function_">useContext</span>(context)<br></code></pre></td></tr></table></figure><p><code>useContext</code> 接受一个参数 一般都是 context 对象,返回值为 context 对象内部保存的 value 值</p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs jsx"><span class="hljs-comment">/* 用useContext方式 */</span><br><span class="hljs-keyword">const</span> <span class="hljs-title function_">DemoContext</span> = (<span class="hljs-params"></span>)=> {<br> <span class="hljs-keyword">const</span> value= <span class="hljs-title function_">useContext</span>(<span class="hljs-title class_">Context</span>)<br> <span class="hljs-comment">/* my name is alien */</span><br><span class="hljs-keyword">return</span> <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span> my name is { value.name }<span class="hljs-tag"></<span class="hljs-name">div</span>></span></span><br>}<br><br><span class="hljs-comment">/* 用Context.Consumer 方式 */</span><br><span class="hljs-keyword">const</span> <span class="hljs-title function_">DemoContext1</span> = (<span class="hljs-params"></span>)=>{<br> <span class="hljs-keyword">return</span> <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">Context.Consumer</span>></span></span><br><span class="language-xml"> {/* my name is alien */}</span><br><span class="language-xml"> { (value)=> <span class="hljs-tag"><<span class="hljs-name">div</span>></span> my name is { value.name }<span class="hljs-tag"></<span class="hljs-name">div</span>></span> }</span><br><span class="language-xml"> <span class="hljs-tag"></<span class="hljs-name">Context.Consumer</span>></span></span><br>}<br><br><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ()=>{<br> <span class="hljs-keyword">return</span> <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">Context.Provider</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">name:</span>'<span class="hljs-attr">alien</span>' , <span class="hljs-attr">age:18</span> }} ></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">DemoContext</span> /></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">DemoContext1</span> /></span></span><br><span class="language-xml"> <span class="hljs-tag"></<span class="hljs-name">Context.Provider</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"></<span class="hljs-name">div</span>></span></span><br>}<br><br></code></pre></td></tr></table></figure><h2 id="useRef"><code>useRef</code></h2><p><code>useRef</code> 可以用来获取元素,缓存状态,接受一个状态 <code>initState</code> 作为初始值,返回一个 ref 对象 cur, cur 上有一个 current 属性就是 ref 对象需要获取的内容</p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs jsx"><span class="hljs-keyword">const</span> cur = <span class="hljs-title class_">React</span>.<span class="hljs-title function_">useRef</span>(initState)<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(cur.<span class="hljs-property">current</span>)<br></code></pre></td></tr></table></figure><p><code>useRef</code> 创建的 ref 对象就是一个普通的对象,而 <code>useRef()</code> 和自建一个 <code>{current: ...}</code> 对象的唯一区别是,<code>useRef</code> 会在每次渲染时返回同一个 ref 对象</p><h3 id="useRef-基础用法:"><code>useRef 基础用法:</code></h3><p><code>useRef</code>来获取DOM节点</p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs jsx"><span class="hljs-keyword">const</span> <span class="hljs-title function_">DemoUseRef</span> = (<span class="hljs-params"></span>)=>{<br> <span class="hljs-keyword">const</span> dom= <span class="hljs-title function_">useRef</span>(<span class="hljs-literal">null</span>)<br> <span class="hljs-keyword">const</span> <span class="hljs-title function_">handerSubmit</span> = (<span class="hljs-params"></span>)=>{<br> <span class="hljs-comment">/* <div >表单组件</div> dom 节点 */</span><br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(dom.<span class="hljs-property">current</span>)<br> }<br> <span class="hljs-keyword">return</span> <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span></span><br><span class="language-xml"> {/* ref 标记当前dom节点 */}</span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{dom}</span> ></span>表单组件<span class="hljs-tag"></<span class="hljs-name">div</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span>=></span>handerSubmit()} >提交<span class="hljs-tag"></<span class="hljs-name">button</span>></span> </span><br><span class="language-xml"> <span class="hljs-tag"></<span class="hljs-name">div</span>></span></span><br>}<br><br></code></pre></td></tr></table></figure><p>useRef 保存状态</p><p>可以利用 useRef 返回的 ref 对象来保存状态,只要当前组件不被销毁,那么状态就会一直存在</p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs jsx"><span class="hljs-keyword">const</span> status = <span class="hljs-title function_">useRef</span>(<span class="hljs-literal">false</span>)<br><span class="hljs-comment">/* 改变状态 */</span><br><span class="hljs-keyword">const</span> <span class="hljs-title function_">handleChangeStatus</span> = (<span class="hljs-params"></span>) => {<br> status.<span class="hljs-property">current</span> = <span class="hljs-literal">true</span><br>}<br></code></pre></td></tr></table></figure><h2 id="useImperativeHandle"><code>useImperativeHandle</code></h2><p>这什么玩意</p><h2 id="useMemo"><code>useMemo</code></h2><p>useMemo 可以在函数组件 render 上下文中同步执行一个函数逻辑,这个函数的返回值可以作为一个新的状态缓存起来。那么这个 hooks 的作用就显而易见了</p><p>场景一:在一些场景下,需要在函数组件中进行大量的逻辑计算,那么我们不期望每一次函数组件渲染都执行这些复杂的计算逻辑,所以就需要在 useMemo 的回调函数中执行这些逻辑,然后把得到的产物(计算结果)缓存起来就可以了。</p><p>场景二:React 在整个更新流程中,<code>diff</code> 起到了决定性的作用,比如 <code>Context</code> 中的 <code>provider</code> 通过 <code>diff value</code> 来判断是否更新</p><h3 id="useMemo-基础介绍:"><code>useMemo 基础介绍:</code></h3><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs jsx"><span class="hljs-keyword">const</span> cacheSomething = <span class="hljs-title function_">useMemo</span>(create,deps)<br></code></pre></td></tr></table></figure><p>① create:第一个参数为一个函数,函数的返回值作为缓存值,如上 demo 中把 Children 对应的 element 对象,缓存起来。</p><p>② deps: 第二个参数为一个数组,存放当前 useMemo 的依赖项,在函数组件下一次执行的时候,会对比 deps 依赖项里面的状态,是否有改变,如果有改变重新执行 create ,得到新的缓存值。</p><p>③ <code>cacheSomething</code>:返回值,执行 create 的返回值。如果 deps 中有依赖项改变,返回的重新执行 create 产生的值,否则取上一次缓存值。</p><h3 id="useMemo-基础用法:"><code>useMemo 基础用法:</code></h3><p>派生新状态:</p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs jsx"><span class="hljs-keyword">function</span> <span class="hljs-title function_">Scope</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">const</span> keeper = <span class="hljs-title function_">useKeep</span>()<br> <span class="hljs-keyword">const</span> { cacheDispatch, cacheList, hasAliveStatus } = keeper<br> <br> <span class="hljs-comment">/* 通过 useMemo 得到派生出来的新状态 contextValue */</span><br> <span class="hljs-keyword">const</span> contextValue = <span class="hljs-title function_">useMemo</span>(<span class="hljs-function">() =></span> {<br> <span class="hljs-keyword">return</span> {<br> <span class="hljs-attr">cacheDispatch</span>: cacheDispatch.<span class="hljs-title function_">bind</span>(keeper),<br> <span class="hljs-attr">hasAliveStatus</span>: hasAliveStatus.<span class="hljs-title function_">bind</span>(keeper),<br> <span class="hljs-attr">cacheDestory</span>: <span class="hljs-function">(<span class="hljs-params">payload</span>) =></span> cacheDispatch.<span class="hljs-title function_">call</span>(keeper, { <span class="hljs-attr">type</span>: <span class="hljs-variable constant_">ACTION_DESTORY</span>, payload })<br> }<br> <br> }, [keeper])<br> <span class="hljs-keyword">return</span> <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">KeepaliveContext.Provider</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{contextValue}</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"></<span class="hljs-name">KeepaliveContext.Provider</span>></span></span><br>}<br><br></code></pre></td></tr></table></figure><p>如上通过 <code>useMemo</code> 得到派生出来的新状态 <code>contextValue</code> ,只有 keeper 变化的时候,才改变 Provider 的 value</p><h2 id="useCallback"><code>useCallback</code></h2><p>这个好像有点急 但是先别急</p><h2 id="useDebugValue"><code>useDebugValue</code></h2><p>这什么玩意</p><h2 id="useId"><code>useId</code></h2><p>看不懂思密达</p><h2 id="自定义hook"><code>自定义hook</code></h2><p>别急</p>]]></content>
<categories>
<category>React</category>
</categories>
</entry>
<entry>
<title>组件通信</title>
<link href="/2024/02/17/%E7%BB%84%E4%BB%B6%E9%80%9A%E4%BF%A1/"/>
<url>/2024/02/17/%E7%BB%84%E4%BB%B6%E9%80%9A%E4%BF%A1/</url>
<content type="html"><![CDATA[<h1><code>React组件通信</code></h1><p>组件</p><p><code>dom</code>组件 <code>react</code>支持的<code>html</code>和<code>svg</code>标签</p><h3 id="props"><code>props</code></h3><p>什么是<code>props</code> <code>html</code>属性的功能</p><p><code>dom</code>属性</p><p>类名 <code>className</code></p><p>样式</p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs jsx">style={<br> {<br> <span class="hljs-attr">width</span>:<span class="hljs-string">'100vh'</span>,<br> <span class="hljs-attr">height</span>:<span class="hljs-number">100</span>,<br> <span class="hljs-attr">backgroundColor</span>:<span class="hljs-string">'grey'</span><br> <span class="hljs-comment">//带-的写成驼峰</span><br>}<br>}<br></code></pre></td></tr></table></figure><p>也可以书写变量</p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs jsx"><span class="hljs-keyword">const</span> imgStyle={<br> <span class="hljs-attr">width</span>:<span class="hljs-string">'100vh'</span>,<br> <span class="hljs-attr">height</span>:<span class="hljs-number">100</span>,<br> <span class="hljs-attr">backgroundColor</span>:<span class="hljs-string">'grey'</span><br>}<br><span class="hljs-keyword">return</span>(<br> <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">img</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{imgStyle}/</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"></<span class="hljs-name">div</span>></span></span>)<br></code></pre></td></tr></table></figure><p><code>jsx</code>展开语法</p><p>把所有属性书写为一个变量</p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs jsx"><span class="hljs-keyword">import</span> image <span class="hljs-keyword">from</span> <span class="hljs-string">'./logo.svg'</span><br><span class="hljs-keyword">const</span> imgData={<br> className=<span class="hljs-string">'small'</span>,<br> <span class="hljs-attr">style</span>:{<br> <span class="hljs-attr">width</span>:<span class="hljs-string">'100vh'</span>,<br> <span class="hljs-attr">height</span>:<span class="hljs-number">100</span>,<br> <span class="hljs-attr">backgroundColor</span>:<span class="hljs-string">'grey'</span><br>} }<br><span class="hljs-keyword">return</span>(<br> <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">img</span></span></span><br><span class="hljs-tag"><span class="language-xml"> //<span class="hljs-attr">src标签不能提出</span></span></span><br><span class="hljs-tag"><span class="language-xml"> <span class="hljs-attr">src</span>=<span class="hljs-string">{image}</span></span></span><br><span class="hljs-tag"><span class="language-xml"> {<span class="hljs-attr">...imgData</span>}</span></span><br><span class="hljs-tag"><span class="language-xml"> /></span></span><br><span class="language-xml"> <span class="hljs-tag"></<span class="hljs-name">div</span>></span></span><br>)<br></code></pre></td></tr></table></figure><p>自定义组件<code>react的props</code></p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><code class="hljs jsx"><span class="hljs-keyword">function</span> <span class="hljs-title function_">Artcile</span>(<span class="hljs-params"></span>)<br>{<br> <span class="hljs-keyword">return</span>(<br> <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">h2</span>></span>111<span class="hljs-tag"></<span class="hljs-name">h2</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">p</span>></span>222<span class="hljs-tag"></<span class="hljs-name">p</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"></<span class="hljs-name">div</span>></span></span><br> )<br>}<br><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">App</span>(<span class="hljs-params"></span>)<br>{<br> <span class="hljs-keyword">return</span>(<br> <span class="language-xml"><span class="hljs-tag"><></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">Article</span>/></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">Article</span>/></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">Article</span>/></span> </span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">Article</span>/></span> </span><br><span class="language-xml"> <span class="hljs-tag"></></span></span><br><br><br> )<br>}<br></code></pre></td></tr></table></figure><p>如果对组件的结构逻辑 样式复用</p><p>内容不复用的话 可以写成</p><p>对组件内容定制</p><p>步骤</p><p>1.对父元素(上面的<code>App</code>)进行请求 请求功能所需要的数据</p><p>2.创建组件</p><p>3.把数据传给组件</p><p>父组件向子组件传普通值</p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><code class="hljs jsx"><span class="hljs-keyword">function</span> <span class="hljs-title function_">Detail</span>(<span class="hljs-params"></span>)<br>{<br> <span class="hljs-keyword">return</span>(<br> <span class="language-xml"><span class="hljs-tag"><></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">p</span>></span>{content}<span class="hljs-tag"></<span class="hljs-name">p</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">p</span>></span>状态:{active?'显示':'隐藏'}<span class="hljs-tag"></<span class="hljs-name">p</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"></></span></span><br> )<br>}<br><span class="hljs-keyword">function</span> <span class="hljs-title function_">Artcile</span>(<span class="hljs-params">{acticleData}</span>)<br><span class="hljs-comment">//采用解构</span><br>{<br> <span class="hljs-keyword">return</span>(<br> <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">h2</span>></span>{title}<span class="hljs-tag"></<span class="hljs-name">h2</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">Detail</span> {<span class="hljs-attr">...articleData</span>}</span></span><br><span class="hljs-tag"><span class="language-xml"> ></span><span class="hljs-tag"></<span class="hljs-name">Detail</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"></<span class="hljs-name">div</span>></span></span><br> )<br> <span class="hljs-comment">//此时Article没用到content和active</span><br> <span class="hljs-comment">//但是Detail用到了 可以在Article先不传 直接传给Detail</span><br>}<br><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">App</span>(<span class="hljs-params"></span>)<br>{<span class="hljs-keyword">const</span> articleData={<br> <span class="hljs-attr">title</span>:<span class="hljs-string">'1'</span>,<br> <span class="hljs-attr">detailData</span>:{<br> <span class="hljs-attr">content</span>:<span class="hljs-string">'1'</span>,<span class="hljs-attr">active</span>:<span class="hljs-literal">true</span><br>}<br>}<br> <span class="hljs-keyword">return</span>(<br> <span class="language-xml"><span class="hljs-tag"><></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">Article</span></span></span><br><span class="hljs-tag"><span class="language-xml"> {<span class="hljs-attr">...acticleData</span>}</span></span><br><span class="hljs-tag"><span class="language-xml"> /></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">Article</span></span></span><br><span class="hljs-tag"><span class="language-xml"> <span class="hljs-attr">title</span>=<span class="hljs-string">"2"</span></span></span><br><span class="hljs-tag"><span class="language-xml"> <span class="hljs-attr">content</span>=<span class="hljs-string">"2"</span></span></span><br><span class="hljs-tag"><span class="language-xml"> <span class="hljs-attr">active</span></span></span><br><span class="hljs-tag"><span class="language-xml"> /></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">Article</span></span></span><br><span class="hljs-tag"><span class="language-xml"> <span class="hljs-attr">title</span>=<span class="hljs-string">"3"</span></span></span><br><span class="hljs-tag"><span class="language-xml"> <span class="hljs-attr">content</span>=<span class="hljs-string">"3"</span></span></span><br><span class="hljs-tag"><span class="language-xml"> <span class="hljs-attr">active</span></span></span><br><span class="hljs-tag"><span class="language-xml"> /></span> </span><br><span class="language-xml"> <span class="hljs-tag"></></span></span><br><br><br> )<br>}<br></code></pre></td></tr></table></figure><p>父组件向子组件传<code>jsx</code></p><p>插槽 <code>jsx</code>作为<code>props</code>传给子组件</p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><code class="hljs jsx"><span class="hljs-keyword">function</span> <span class="hljs-title function_">List</span> ({children,title,footer= <br> <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span>默认底部<span class="hljs-tag"></<span class="hljs-name">div</span>></span></span>})<br><span class="hljs-comment">//此时footer需要一个默认值</span><br>{<br> <span class="hljs-keyword">return</span>(<br> <span class="language-xml"><span class="hljs-tag"><></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">h2</span>></span>{title}<span class="hljs-tag"></<span class="hljs-name">h2</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">ul</span>></span></span><br><span class="language-xml"> {children}</span><br><span class="language-xml"> <span class="hljs-tag"></<span class="hljs-name">ul</span>></span></span><br><span class="language-xml"> {footer}</span><br><span class="language-xml"><span class="hljs-tag"></></span></span><br>)<br>}<br><span class="hljs-comment">//如果需要在列表加元素</span><br><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">App</span> ()<br>{<br> <span class="hljs-keyword">return</span> (<br> <span class="language-xml"><span class="hljs-tag"><></span></span><br><span class="language-xml"> //之前是通过props传递 现在通过children</span><br><span class="language-xml"> //自动接受组件开始和接受的内容</span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">List</span></span></span><br><span class="hljs-tag"><span class="language-xml"> <span class="hljs-attr">title</span>=<span class="hljs-string">"列表1"</span></span></span><br><span class="hljs-tag"><span class="language-xml"> <span class="hljs-attr">footer</span>=<span class="hljs-string">{</span></span></span><br><span class="hljs-tag"><span class="language-xml"> <<span class="hljs-attr">p</span>></span>这是底部内容1<span class="hljs-tag"></<span class="hljs-name">p</span>></span></span><br><span class="language-xml"> }></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">li</span>></span>内容1<span class="hljs-tag"></<span class="hljs-name">li</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">li</span>></span>内容2<span class="hljs-tag"></<span class="hljs-name">li</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">li</span>></span>内容3<span class="hljs-tag"></<span class="hljs-name">li</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"></<span class="hljs-name">List</span>></span></span><br><span class="language-xml"></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">List</span></span></span><br><span class="hljs-tag"><span class="language-xml"> <span class="hljs-attr">title</span>=<span class="hljs-string">"列表2"</span></span></span><br><span class="hljs-tag"><span class="language-xml"> <span class="hljs-attr">footer</span>=<span class="hljs-string">{</span><<span class="hljs-attr">p</span>></span>这是底部内容2<span class="hljs-tag"></<span class="hljs-name">p</span>></span>}></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">li</span>></span>内容A<span class="hljs-tag"></<span class="hljs-name">li</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">li</span>></span>内容B<span class="hljs-tag"></<span class="hljs-name">li</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">li</span>></span>内容C<span class="hljs-tag"></<span class="hljs-name">li</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"></<span class="hljs-name">List</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">List</span></span></span><br><span class="hljs-tag"><span class="language-xml"> <span class="hljs-attr">title</span>=<span class="hljs-string">"列表3"</span></span></span><br><span class="hljs-tag"><span class="language-xml"> //<span class="hljs-attr">此时没设置footer会显示默认值</span></span></span><br><span class="hljs-tag"><span class="language-xml"> ></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">li</span>></span>内容X<span class="hljs-tag"></<span class="hljs-name">li</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">li</span>></span>内容Y<span class="hljs-tag"></<span class="hljs-name">li</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">li</span>></span>内容Z<span class="hljs-tag"></<span class="hljs-name">li</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"></<span class="hljs-name">List</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"></></span></span><br> )<br>}<br></code></pre></td></tr></table></figure><p>子组件向父组件传值</p><p>父组件给子组件一个自定义事件的设置 再通过事件触发后向父组件传递参数来设置</p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><code class="hljs jsx"><span class="hljs-keyword">function</span> <span class="hljs-title function_">Detail</span> ({onActive}){<br> <span class="hljs-comment">//希望告诉父组件内部状态 在handleClick函数使用的变更 所以在handleClick加入onACtive事件并传入status</span><br> <span class="hljs-keyword">const</span> [status,setStatus]=<span class="hljs-title function_">useState</span>(<span class="hljs-literal">false</span>)<br> <span class="hljs-keyword">function</span> <span class="hljs-title function_">handleClick</span>(<span class="hljs-params"></span>)<br> {<br> <span class="hljs-title function_">setStatus</span>(!status)<br> <span class="hljs-title function_">onActive</span>(status)<br> <span class="hljs-comment">//每次状态变更 传递一个新值 传递到function App()</span><br> }<br> <span class="hljs-keyword">return</span> (<br> <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span></span><br><span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleClick}</span>></span>按钮<span class="hljs-tag"></<span class="hljs-name">button</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">p</span> </span></span><br><span class="hljs-tag"><span class="language-xml"> <span class="hljs-attr">style</span>=<span class="hljs-string">{{display;staus?</span></span></span><br><span class="hljs-tag"><span class="language-xml"> '<span class="hljs-attr">block</span>'<span class="hljs-attr">:</span>'<span class="hljs-attr">none</span>'}}></span></span><br><span class="language-xml"> Detail的内容<span class="hljs-tag"></<span class="hljs-name">p</span>></span></span><br><span class="language-xml"></span><br><span class="language-xml"> <span class="hljs-tag"></<span class="hljs-name">div</span>></span></span><br> )<br>}<br><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">App</span>(<span class="hljs-params"></span>){<br> <span class="hljs-keyword">function</span> <span class="hljs-title function_">handleActive</span>(<span class="hljs-params">status</span>){<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(status)<br> }<br> <span class="hljs-keyword">return</span>(<br> <span class="language-xml"><span class="hljs-tag"><></span></span><br><span class="language-xml"> //如果希望父组件能接受子组件的状态的话需要给子组件设置一个自定义属性(onActive)可以理解为事件 用代码决定在何时触发</span><br><span class="language-xml"> </span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">Detail</span></span></span><br><span class="hljs-tag"><span class="language-xml"> <span class="hljs-attr">onActive</span>=<span class="hljs-string">{handleActive}</span>></span><span class="hljs-tag"></<span class="hljs-name">Detail</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"></></span></span><br> <br> )<br>}<br></code></pre></td></tr></table></figure><p>同级组件传值</p><p>在父组件进行中转</p><p>多层级传值</p><p>提供了一个多级属性穿透的hook</p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br></pre></td><td class="code"><pre><code class="hljs jsx"><span class="hljs-keyword">import</span> {useState} <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span><br><span class="hljs-keyword">export</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">Section</span> ({children})<br>{<br> <span class="hljs-comment">//获取上一级level</span><br> <span class="hljs-keyword">const</span> level=<span class="hljs-title function_">useContext</span>(<span class="hljs-title class_">LevelContext</span>)<br> <span class="hljs-keyword">return</span> (<br> <br> <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">section</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"section"</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">LevelContect.Provider</span> </span></span><br><span class="hljs-tag"><span class="language-xml"> <span class="hljs-attr">value</span>=<span class="hljs-string">{</span></span></span><br><span class="hljs-tag"><span class="language-xml"> <span class="hljs-attr">level</span>+<span class="hljs-attr">1</span> </span></span><br><span class="hljs-tag"><span class="language-xml"> }></span></span><br><span class="language-xml"> {children}<span class="hljs-tag"></<span class="hljs-name">LevelContect.Provider</span>></span></span><br><span class="language-xml"> </span><br><span class="language-xml"> <span class="hljs-tag"></<span class="hljs-name">section</span>></span></span><br> )<br>}<br><span class="hljs-keyword">export</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">Heading</span>(<span class="hljs-params">{level,children}</span>)<br>{<br> <span class="hljs-keyword">const</span> level=<span class="hljs-title function_">useContext</span>(<span class="hljs-title class_">LevelContext</span>)<br><span class="hljs-comment">//设置之后此时全为h1(若默认值是1)</span><br><span class="hljs-comment">//但是h1和section嵌套会使h1显示出从大到小的样式</span><br> <span class="hljs-keyword">switch</span>(level){<br> <span class="hljs-keyword">case</span> <span class="hljs-number">1</span>:<br> <span class="hljs-keyword">return</span> <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">h1</span>></span>{children}<span class="hljs-tag"></<span class="hljs-name">h1</span>></span></span><br> <span class="hljs-keyword">case</span> <span class="hljs-number">2</span>:<br> <span class="hljs-keyword">return</span> <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">h2</span>></span>{children}<span class="hljs-tag"></<span class="hljs-name">h2</span>></span></span><br> <span class="hljs-keyword">case</span> <span class="hljs-number">3</span>:<br> <span class="hljs-keyword">return</span> <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">h3</span>></span>{children}<span class="hljs-tag"></<span class="hljs-name">h3</span>></span></span><br> <span class="hljs-keyword">case</span> <span class="hljs-number">4</span>:<br> <span class="hljs-keyword">return</span> <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">h4</span>></span>{children}<span class="hljs-tag"></<span class="hljs-name">h4</span>></span></span><br> <span class="hljs-keyword">case</span> <span class="hljs-number">4</span>:<br> <span class="hljs-keyword">return</span> <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">h4</span>></span>{children}<span class="hljs-tag"></<span class="hljs-name">h4</span>></span></span><br> <span class="hljs-keyword">case</span> <span class="hljs-number">5</span>:<br> <span class="hljs-keyword">return</span> <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">h5</span>></span>{children}<span class="hljs-tag"></<span class="hljs-name">h5</span>></span></span><br> <span class="hljs-keyword">case</span> <span class="hljs-number">6</span>:<br> <span class="hljs-keyword">return</span> <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">h6</span>></span>{children}<span class="hljs-tag"></<span class="hljs-name">h6</span>></span></span><br> } <br>}<br><span class="hljs-keyword">const</span> <span class="hljs-title class_">LevelContext</span>=<span class="hljs-title function_">createContext</span>(<span class="hljs-number">0</span>)<br><span class="hljs-comment">//不能直接用 通过useContext</span><br><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">App</span> (){<br> <span class="hljs-keyword">return</span>(<br> <span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">div</span>></span></span><br><span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">section</span>></span></span><br><span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">Heading</span> ></span>主标题<span class="hljs-tag"></<span class="hljs-name">Heading</span>></span></span><br><span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">section</span>></span></span><br><span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">Heading</span> ></span>副标题<span class="hljs-tag"></<span class="hljs-name">Heading</span>></span></span><br><span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">Heading</span> ></span>副标题<span class="hljs-tag"></<span class="hljs-name">Heading</span>></span></span><br><span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">Heading</span> ></span>副标题 <span class="hljs-tag"></<span class="hljs-name">Heading</span>></span></span><br><span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">section</span>></span></span><br><span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">Heading</span>></span>子标<span class="hljs-tag"></<span class="hljs-name">Heading</span>></span></span><br><span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">Heading</span>></span>子标<span class="hljs-tag"></<span class="hljs-name">Heading</span>></span></span><br><span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">Heading</span> ></span>子标<span class="hljs-tag"></<span class="hljs-name">Heading</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">section</span>></span> </span><br><span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">Heading</span> ></span>子子标题<span class="hljs-tag"></<span class="hljs-name">Heading</span>></span></span><br><span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">Heading</span>></span>子子标题<span class="hljs-tag"></<span class="hljs-name">Heading</span>></span></span><br><span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">Heading</span> ></span>子子标题<span class="hljs-tag"></<span class="hljs-name">Heading</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">section</span>></span></span><br><span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">Heading</span> ></span>子子子标题<span class="hljs-tag"></<span class="hljs-name">Heading</span>></span></span><br><span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">Heading</span> ></span>子子子标题<span class="hljs-tag"></<span class="hljs-name">Heading</span>></span></span><br><span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">Heading</span> ></span>子子子标题<span class="hljs-tag"></<span class="hljs-name">Heading</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">section</span>></span>></span><br><span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">Heading</span> ></span>子子子子标题 <span class="hljs-tag"></<span class="hljs-name">Heading</span>></span></span><br><span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">Heading</span> ></span>子子子子标题 <span class="hljs-tag"></<span class="hljs-name">Heading</span>></span></span><br><span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">Heading</span> ></span>子子子子标题 <span class="hljs-tag"></<span class="hljs-name">Heading</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"></<span class="hljs-name">section</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"></<span class="hljs-name">section</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"></<span class="hljs-name">section</span>></span> </span><br><span class="language-xml"> <span class="hljs-tag"></<span class="hljs-name">section</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"></<span class="hljs-name">section</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"></<span class="hljs-name">section</span>></span></span><br><span class="language-xml"> <span class="hljs-tag"></<span class="hljs-name">div</span>></span></span>)<br>}<br></code></pre></td></tr></table></figure><p><code>Ps:</code>可能会出现都是<code>h1</code>标签但是大小却不同的情况</p><p><code>section</code> 和<code>h1</code>嵌套时候自然出现的状态</p><p>如何更改<code>useContext</code>能够获取到的level信息</p><p><code>useContext</code>创建的对象<code>LevelContext</code>提供一个<code>Provider</code></p><p>给<code>context</code>提供值的一个方式</p>]]></content>
<categories>
<category>React</category>
</categories>
</entry>
<entry>
<title>Javascript-class类</title>
<link href="/2023/12/16/Javascript-class%E7%B1%BB/"/>
<url>/2023/12/16/Javascript-class%E7%B1%BB/</url>
<content type="html"><![CDATA[<h1><code>Javascript</code>-class类</h1><h3 id="类的定义">类的定义</h3><p>有两个组成部分</p><p>类表达式和类声明</p><p>每个类中包含了一个特殊的方法 <code>constructor()</code>,它是类的构造函数,这种方法用于创建和初始化一个由 <code>class</code> 创建的对象</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">//类声明</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span> {<br><span class="hljs-title function_">constructor</span>(<span class="hljs-params">name,age</span>)<br> {<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">name</span>=name;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">age</span>=age;<br> }<br>}<br><span class="hljs-comment">//类表达式</span><br><span class="hljs-keyword">const</span> B=<span class="hljs-keyword">class</span>{<br><span class="hljs-title function_">constructor</span>(<span class="hljs-params">name,age</span>)<br> {<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">name</span>=name<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">age</span>=age<br> }<br>}<br></code></pre></td></tr></table></figure><p>以上创造了一个类 叫<code>A</code></p><p>初始化了两个参数 <code>name , age</code></p><h3 id="使用类">使用类</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> a1=<span class="hljs-keyword">new</span> A (<span class="hljs-string">'shanyujia'</span>,<span class="hljs-number">18</span>)<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(a1)<br><span class="hljs-comment">// =>{ name: 'shanyujia', age: 18 }</span><br></code></pre></td></tr></table></figure><p>基于这个类去创造这个类的实例</p><p>基于这个对象生成 结构相同 内部数据不同的对象形式</p><h3 id="自定义方法">自定义方法</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span> {<br> <span class="hljs-title function_">constructor</span>(<span class="hljs-params">name,age</span>)<br> {<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">name</span>=name;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">age</span>=age;<br> }<br> <span class="hljs-title function_">introduce</span>(<span class="hljs-params"></span>){<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">`我的名字是<span class="hljs-subst">${<span class="hljs-variable language_">this</span>.name}</span>,我的年龄是<span class="hljs-subst">${<span class="hljs-variable language_">this</span>.age}</span> `</span>)<br> }<br>}<br>a1.<span class="hljs-title function_">introduce</span>()<br><span class="hljs-comment">// => 我的名字是shanyujia,我的年龄是18</span><br></code></pre></td></tr></table></figure><h3 id="类的继承">类的继承</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">class</span> <span class="hljs-title class_">B</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_ inherited__">A</span>{<br> <span class="hljs-title function_">constructor</span>(<span class="hljs-params">name,age,sex</span>){<br> <span class="hljs-comment">//如果希望继承A的属性 写一个super的调用</span><br> <span class="hljs-comment">//调用父类的constructor 将属性也在B类生成</span><br> <span class="hljs-variable language_">super</span>(name,age)<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">sex</span>=sex<br> }<br> <span class="hljs-title function_">sayHello</span>(<span class="hljs-params"></span>){<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'你好我是'</span>+<span class="hljs-variable language_">this</span>.<span class="hljs-property">name</span>)<br> }<br>}<br><span class="hljs-keyword">const</span> b1=<span class="hljs-keyword">new</span> <span class="hljs-title function_">B</span>(<span class="hljs-string">'张三'</span>,<span class="hljs-number">20</span>,<span class="hljs-string">'男'</span>)<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(b1)<br>b1.<span class="hljs-title function_">sayHello</span>()<br>b1.<span class="hljs-title function_">introduce</span>()<br><span class="hljs-comment">/*{ name: '张三', age: 20, sex: '男' }</span><br><span class="hljs-comment">我的名字是张三,我的年龄是20</span><br><span class="hljs-comment">你好我是张三*/</span><br></code></pre></td></tr></table></figure>]]></content>
<categories>
<category>Javascript</category>
</categories>
</entry>
<entry>
<title>Javascript 函数</title>
<link href="/2023/12/09/Javascript-%E5%87%BD%E6%95%B0/"/>
<url>/2023/12/09/Javascript-%E5%87%BD%E6%95%B0/</url>
<content type="html"><![CDATA[<h1>JavaScript 函数</h1><h3 id="1-typeof">1.<code>typeof</code></h3><p>会产生一个字符串的值,内容是给定值的具体类型</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-keyword">typeof</span> <span class="hljs-number">4.5</span>)<br><span class="hljs-comment">// → number</span><br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-keyword">typeof</span> <span class="hljs-string">"x"</span>)<br><span class="hljs-comment">// → string</span><br></code></pre></td></tr></table></figure><h3 id="2-prompt">2.<code>prompt</code></h3><p>包含一函数,个显示一个小对话框,请求用户输入</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-title function_">prompt</span>(<span class="hljs-string">"Enter passcode"</span>);<br></code></pre></td></tr></table></figure><h3 id="3-cosole-log">3.<code>cosole.log</code></h3><p>输出值</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">let</span> x = <span class="hljs-number">30</span>;<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"the value of x is"</span>, x);<br><span class="hljs-comment">// → the value of x is 30</span><br></code></pre></td></tr></table></figure><h3 id="4-Math-max">4.<code>Math.max</code></h3><p>接受任意数量的参数并返回最大</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-title class_">Math</span>.<span class="hljs-title function_">max</span>(<span class="hljs-number">2</span>, <span class="hljs-number">4</span>));<br><span class="hljs-comment">// → 4</span><br></code></pre></td></tr></table></figure><h3 id="5-Math-min">5.<code>Math.min</code></h3><p>跟Math.max相反</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-title class_">Math</span>.<span class="hljs-title function_">min</span>(<span class="hljs-number">2</span>, <span class="hljs-number">4</span>) + <span class="hljs-number">100</span>);<br><span class="hljs-comment">// → 102</span><br></code></pre></td></tr></table></figure><h3 id="6-Number-isNaN">6.<code>Number.isNaN</code></h3><p>仅当它给出的参数是<code>NaN</code>时才返回<code>true</code></p><p>当你给它一个不代表有效数字的字符串时</p><p><code>Number</code>函数恰好返回<code>NaN</code></p><h3 id="7-函数定义">7.函数定义</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">function</span> <span class="hljs-title function_">square</span>(<span class="hljs-params">x</span>)<br>{<br><span class="hljs-keyword">return</span> x*x;<br>}<br></code></pre></td></tr></table></figure><p>以关键字<code>function</code>起始的表达式创建</p><p>函数有一组参数(例子中只有<code>x</code>)和一个主体</p><p>它包含调用该函数时要执行的语句</p><p><code>return</code> 决定 函数返回值</p><p>没有<code>return</code>的函数 返回<code>undefined</code></p><h3 id="8-箭头函数">8.箭头函数</h3><p><code>=></code></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> <span class="hljs-title function_">square1</span> = (<span class="hljs-params">x</span>) => { <span class="hljs-keyword">return</span> x * x; };<br><span class="hljs-keyword">const</span> <span class="hljs-title function_">square2</span> = x => x * x;<br></code></pre></td></tr></table></figure><p>箭头出现在参数列表之后,然后是函数主体</p><p>表达的意思类似于 这个输入(参数)产生这个结果(主体)</p><h3 id="9-push">9.push</h3><p>将值添加到数组的末尾</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">let</span> sequence = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>];<br>sequence.<span class="hljs-title function_">push</span>(<span class="hljs-number">4</span>);<br>sequence.<span class="hljs-title function_">push</span>(<span class="hljs-number">5</span>);<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(sequence);<br><span class="hljs-comment">// → [1, 2, 3, 4, 5]</span><br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(sequence.<span class="hljs-title function_">pop</span>());<br><span class="hljs-comment">// → 5</span><br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(sequence);<br><span class="hljs-comment">// → [1, 2, 3, 4]</span><br></code></pre></td></tr></table></figure><h3 id="10-pop"><code>10.pop</code></h3><p>与push相反 删除数组中最后的一个值并将其返回</p><h3 id="11-delete"><code>11.delete</code></h3><p>一元运算符</p><p>当应用于对象属性时,将从对象中删除指定的属性</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">let</span> anObject = {<span class="hljs-attr">left</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">right</span>: <span class="hljs-number">2</span>};<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(anObject.<span class="hljs-property">left</span>);<br><span class="hljs-comment">// → 1</span><br><span class="hljs-keyword">delete</span> anObject.<span class="hljs-property">left</span>;<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(anObject.<span class="hljs-property">left</span>);<br><span class="hljs-comment">// → undefined</span><br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"left"</span> <span class="hljs-keyword">in</span> anObject);<br><span class="hljs-comment">// → false</span><br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"right"</span> <span class="hljs-keyword">in</span> anObject);<br><span class="hljs-comment">// → true</span><br></code></pre></td></tr></table></figure><h3 id="12-in"><code>12.in</code></h3><p>二元运算符 会告诉你该对象是否具有名称为它的属性</p><p>将属性设置为 undefined 和实际删除它的区别在于</p><p>在设置为undefined的时候 对象仍然具有属性 只是没有意义</p><p>删除它时 属性不再存在 <code>in</code> 会返回 <code>false</code></p><h3 id="13-Object-keys">13.<code>Object.keys</code></h3><p>给它一个对象 它返回一个字符串数组 -对象的属性名称</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-title class_">Object</span>.<span class="hljs-title function_">keys</span>({<span class="hljs-attr">x</span>: <span class="hljs-number">0</span>, <span class="hljs-attr">y</span>: <span class="hljs-number">0</span>, <span class="hljs-attr">z</span>: <span class="hljs-number">2</span>}));<br><span class="hljs-comment">// → ["x", "y", "z"]</span><br></code></pre></td></tr></table></figure><h3 id="14-Object-assgin"><code>14.Object.assgin</code></h3><p>可以将一个对象的所有属性复制到另一个对象中</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">let</span> objectA = {<span class="hljs-attr">a</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">b</span>: <span class="hljs-number">2</span>};<br><span class="hljs-title class_">Object</span>.<span class="hljs-title function_">assign</span>(objectA, {<span class="hljs-attr">b</span>: <span class="hljs-number">3</span>, <span class="hljs-attr">c</span>: <span class="hljs-number">4</span>});<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(objectA);<br><span class="hljs-comment">// → {a: 1, b: 3, c: 4}</span><br></code></pre></td></tr></table></figure><h3 id="15-Math-sqrt"><code>15.Math.sqrt</code></h3><p>平方根函数</p><h3 id="16-unshift"><code>16.unshift</code></h3><p>在数组开头添加元素</p><h3 id="17-shift"><code>17.shift</code></h3><p>在数组的开头删除元素</p><p><code>remember("groceries")</code>将任务添加到队列的末尾</p><p><code>getTask()</code>从队列中获取(并删除)第一个项目</p><p><code>rememberUrgently</code>函数也添加任务 .</p><p>但将其添加到队列的前面而不是队列的后面</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">let</span> todoList = [];<br><span class="hljs-keyword">function</span> <span class="hljs-title function_">remember</span>(<span class="hljs-params">task</span>) {<br> todoList.<span class="hljs-title function_">push</span>(task);<br>}<br><span class="hljs-keyword">function</span> <span class="hljs-title function_">getTask</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">return</span> todoList.<span class="hljs-title function_">shift</span>();<br>}<br><span class="hljs-keyword">function</span> <span class="hljs-title function_">rememberUrgently</span>(<span class="hljs-params">task</span>) {<br> todoList.<span class="hljs-title function_">unshift</span>(task);<br>}<br></code></pre></td></tr></table></figure><h3 id="18-lastIndexOf"><code>18.lastIndexOf</code></h3><p>跟<code>indexof</code> 类似 <code>indexof</code>从数组第一个元素开始搜索</p><p><code>lastIndexOf</code> 从最后一个元素向前搜索</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>([<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>].<span class="hljs-title function_">indexOf</span>(<span class="hljs-number">2</span>));<br><span class="hljs-comment">// → 1</span><br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>([<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>].<span class="hljs-title function_">lastIndexOf</span>(<span class="hljs-number">2</span>));<br><span class="hljs-comment">// → 3</span><br></code></pre></td></tr></table></figure><h3 id="19-Math">19.<code>Math</code></h3><p><code>Math.max</code>最大值</p><p><code>Math.min</code>最小值</p><p><code>Math.sqrt</code>平方根</p><p><code>Math.random</code>生成一个随机数 范围在 0(包括)到 1(不包括)之间</p><p><code>Math.PI</code>表示数字<code>π</code></p><p><code>Math.floor</code>向下取整到与当前数字最接近的整数</p><p><code>Math.ceil</code>向上取整</p><p><code>Math.abs</code>取数字的绝对值</p><p><code>Math.round</code>四舍五入</p>]]></content>
<categories>
<category>Javascript</category>
</categories>
</entry>
<entry>
<title>javascript1</title>
<link href="/2023/11/27/javascript%E7%9F%A5%E8%AF%86%E7%82%B9/"/>
<url>/2023/11/27/javascript%E7%9F%A5%E8%AF%86%E7%82%B9/</url>
<content type="html"><![CDATA[<h3 id="javascript第一章">javascript第一章</h3><h5 id="一元运算符">一元运算符</h5><hr><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-keyword">typeof</span> <span class="hljs-number">4.5</span>)<br> <span class="hljs-comment">//输出 number</span><br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-keyword">typeof</span> <span class="hljs-string">"x"</span>)<br><span class="hljs-comment">//输出 string</span><br></code></pre></td></tr></table></figure><p>typeof生成一个字符串值 得出你给它的值的类型名</p><h5 id="布尔值">布尔值</h5><p>有两个值 <code>true</code> 和 <code>false</code></p><p>生成布尔值的方法</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-variable language_">console</span>.<span class="hljs-property">log</span> (<span class="hljs-number">3</span>><span class="hljs-number">2</span>)<br><span class="hljs-comment">// true</span><br><span class="hljs-variable language_">console</span>.<span class="hljs-property">log</span> (<span class="hljs-number">3</span><<span class="hljs-number">2</span>)<br><span class="hljs-comment">// false</span><br></code></pre></td></tr></table></figure><p>符号 > 和 < 表示 “大于”和“小于” 二元运算符</p><p>返回的结果是一个布尔值,表示其运算是否为真。</p><p>也可以用这种方法比较字符串</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"Aardvark"</span> < <span class="hljs-string">"Zoroaster"</span>)<br><span class="hljs-comment">// → true</span><br></code></pre></td></tr></table></figure><p>在 JavaScript 中,只有一个值不等于其自身,那就是NaN(非数值)</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-variable language_">console</span>.<span class="hljs-property">log</span> (<span class="hljs-title class_">NaN</span> == <span class="hljs-title class_">NaN</span>)<br><span class="hljs-comment">// → false</span><br></code></pre></td></tr></table></figure><p>NaN用于表示非法运算的结果</p><p>逻辑运算符</p><p><code>&&</code> 运算符表示逻辑与,该运算符是二元运算符,只有当赋给它的两个值均为<code>true</code>时其结果才是真</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-literal">true</span> && <span class="hljs-literal">false</span>)<br><span class="hljs-comment">// → false</span><br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-literal">true</span> && <span class="hljs-literal">true</span>)<br><span class="hljs-comment">// → true</span><br></code></pre></td></tr></table></figure><p><code>||</code>运算符表示逻辑或。当两个值中任意一个为<code>true</code>时,结果就为真</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-literal">false</span> || <span class="hljs-literal">true</span>)<br><span class="hljs-comment">// → true</span><br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-literal">false</span> || <span class="hljs-literal">false</span>)<br><span class="hljs-comment">// → false</span><br></code></pre></td></tr></table></figure><p>优先级问题</p><p><code>||</code>优先级最低,其次是<code>&&</code>,然后是比较运算符(<code>>,==,<</code>)</p><p>最后是其他运算符</p><p>三元预算符</p><p><code>A?B:C</code></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-literal">true</span> ? <span class="hljs-number">1</span> : <span class="hljs-number">2</span>);<br><span class="hljs-comment">// → 1</span><br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-literal">false</span> ? <span class="hljs-number">1</span> : <span class="hljs-number">2</span>);<br><span class="hljs-comment">// → 2</span><br></code></pre></td></tr></table></figure><p>被叫做条件运算符</p><p>问号左面的值挑选一个值</p><p>它为 <code>true</code> 是 选择中间的值</p><p>它为<code>false</code> 是选择右面的值</p><h5 id="空值">空值</h5><p><code>null</code> <code>undefined</code></p><p>表示不存在有意义的值</p><p>两者差别不大</p>]]></content>
<categories>
<category>Javascript</category>
</categories>
</entry>
<entry>
<title>my new post</title>
<link href="/2023/11/20/C%E8%AF%AD%E8%A8%80%E5%87%BD%E6%95%B0/"/>
<url>/2023/11/20/C%E8%AF%AD%E8%A8%80%E5%87%BD%E6%95%B0/</url>
<content type="html"><![CDATA[<h2 id="ctype-h">ctype.h</h2><h5 id="1-isascii">1.isascii()</h5><p>判断是不是在0-127</p><p>是ASCII 是1</p><p>不是ASCII 是0</p><h5 id="2-isalpha">2.isalpha</h5><p>小写2 大写1 不是字母0</p><h5 id="3-isdigit">3.isdigit</h5><p>是不是十进制</p><p>0-9 返回非0</p><p>不然返回0</p><h5 id="4-isalnum">4.isalnum()</h5><p>是不是字母或者数字</p><p>是返回非0 不是返回0</p><h5 id="5-isblank">5.isblank()</h5><p>是不是空白字符</p><p>是 输出非0</p><p>不是 输出0</p><h5 id="6-isspace">6.isspace()</h5><p>是不是空白字符</p><p>‘ ’ or ‘\t’ or ‘ \r’ or ‘ \n’ or ‘ \v ’or ‘\f ’</p><h5 id="7-islower">7.islower()</h5><p>是不是小写字母</p><p>是为 非零 不是为0</p><h5 id="8-isupper">8.isupper()</h5><p>是不是大写字母</p><p>是 非零 不是零</p><h5 id="9-toupper">9.toupper()</h5><p>转换为大写字母</p><p>touppper(‘a’)</p><h5 id="10-tolower">10.tolower()</h5><p>转换为小写字母</p><p>tolower(‘A’)</p><h5 id=""></h5>]]></content>
<categories>
<category>C++</category>
</categories>
</entry>
</search>