-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathatom.xml
More file actions
271 lines (149 loc) · 164 KB
/
atom.xml
File metadata and controls
271 lines (149 loc) · 164 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>codeMario</title>
<subtitle>逆风赶路,不负众望</subtitle>
<link href="https://codemariosec.github.io/atom.xml" rel="self"/>
<link href="https://codemariosec.github.io/"/>
<updated>2022-06-20T14:28:05.745Z</updated>
<id>https://codemariosec.github.io/</id>
<author>
<name>codeMario</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>剑指 Offer 24.反转链表</title>
<link href="https://codemariosec.github.io/2022/06/20/%E5%89%91%E6%8C%87%20Offer%2024.%20%E5%8F%8D%E8%BD%AC%E9%93%BE%E8%A1%A8/"/>
<id>https://codemariosec.github.io/2022/06/20/%E5%89%91%E6%8C%87%20Offer%2024.%20%E5%8F%8D%E8%BD%AC%E9%93%BE%E8%A1%A8/</id>
<published>2022-06-20T14:26:01.000Z</published>
<updated>2022-06-20T14:28:05.745Z</updated>
<content type="html"><![CDATA[<blockquote><p>定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。</p></blockquote><span id="more"></span><h3 id="示例"><a href="#示例" class="headerlink" title="示例"></a>示例</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">输入: 1->2->3->4->5->NULL</span><br><span class="line">输出: 5->4->3->2->1->NULL</span><br></pre></td></tr></table></figure><h3 id="题解"><a href="#题解" class="headerlink" title="题解"></a>题解</h3><p>反转链表可以用迭代(双指针)或递归两种方法实现</p><h4 id="方法一:迭代(双指针)"><a href="#方法一:迭代(双指针)" class="headerlink" title="方法一:迭代(双指针)"></a>方法一:迭代(双指针)</h4><p>总体思想是遍历链表,在访问各节点时修改<code>next</code>引用指向。</p><p><strong>时间复杂度:</strong> 遍历链表使用线性大小时间为<em>O</em>(<em>N</em>)。</p><p><strong>空间复杂度:</strong> 变量 <code>pre</code> 和 <code>cur</code> 使用常数大小额外空间为<em>O</em>(1)。</p><ol><li>分别初始化cur、pre,分别指向头结点和null。</li></ol><p><img src="https://codemario-picgo.oss-cn-shenzhen.aliyuncs.com/img/image-20220620214702035.png" alt="image-20220620214702035"></p><ol><li><p>链表指向是单向的,在改变当前节点指向并指向前序节点<code>pre</code>时,当前节点<code>cur</code>和后续节点之间的指向会断开,为了避免这种情况,我们需要在改变节点指向之前设置<code>tmp</code>值将<code>cur</code>的后续节点保存下来。</p><p><img src="https://codemario-picgo.oss-cn-shenzhen.aliyuncs.com/img/image-20220620220138711.png" alt="image-20220620220138711"></p></li><li><p>暂存当前节点,并访问下一个节点。</p><p><img src="https://codemario-picgo.oss-cn-shenzhen.aliyuncs.com/img/image-20220620220423973.png" alt="image-20220620220423973"></p></li><li><p><code>tmp</code>保存<code>cur</code>的后续节点。</p><p><img src="https://codemario-picgo.oss-cn-shenzhen.aliyuncs.com/img/image-20220620220535284.png" alt="image-20220620220535284"></p></li><li><p><strong>以下操作同上~~</strong>,最终得到以下结果</p><p><img src="https://codemario-picgo.oss-cn-shenzhen.aliyuncs.com/img/image-20220620220739273.png" alt="image-20220620220739273"></p></li></ol><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> {</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> <span class="function">ListNode* <span class="title">reverseList</span><span class="params">(ListNode* head)</span> </span>{</span><br><span class="line"> ListNode *cur = head, *pre = <span class="literal">nullptr</span>;</span><br><span class="line"> <span class="keyword">while</span>(cur != <span class="literal">nullptr</span>) {</span><br><span class="line"> ListNode* tmp = cur->next; <span class="comment">// 暂存后继节点 cur.next</span></span><br><span class="line"> cur->next = pre; <span class="comment">// 修改 next 引用指向</span></span><br><span class="line"> pre = cur; <span class="comment">// pre 暂存 cur</span></span><br><span class="line"> cur = tmp; <span class="comment">// cur 访问下一节点</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> pre;</span><br><span class="line"> }</span><br><span class="line">};</span><br></pre></td></tr></table></figure><h4 id="方法二:递归"><a href="#方法二:递归" class="headerlink" title="方法二:递归"></a>方法二:递归</h4><p> 使用递归的方法去遍历链表,当越过尾节点后终止递归,在回溯时候修改各节点<code>next</code>引用指向。</p><p>需要注意以下几点:</p><ul><li>在<code>recur(cur, pre)</code> 递归函数中,当 <code>cur</code> 为空,则返回尾节点<code>pre</code>(即反转链表的头节点)</li><li>递归后继节点,记录返回值(即反转链表的头节点)为 <code>res</code></li><li>修改当前节点 <code>cur</code>引用指向前驱节点<code>pre</code>;</li><li>返回反转链表的头节点<code>res</code>;</li></ul><p><strong>时间复杂度:</strong> 遍历链表使用线性大小时间为 <em>O</em>(<em>N</em>) 。<br><strong>空间复杂度 :</strong> 遍历链表的递归深度达到<em>N</em> ,系统使用额外空间大小为<em>O</em>(<em>N</em>) 。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> {</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> <span class="function">ListNode* <span class="title">reverseList</span><span class="params">(ListNode* head)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">recur</span>(head, <span class="literal">nullptr</span>); <span class="comment">// 调用递归并返回</span></span><br><span class="line"> }</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"> <span class="function">ListNode* <span class="title">recur</span><span class="params">(ListNode* cur, ListNode* pre)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (cur == <span class="literal">nullptr</span>) <span class="keyword">return</span> pre; <span class="comment">// 终止条件</span></span><br><span class="line"> ListNode* res = <span class="built_in">recur</span>(cur->next, cur); <span class="comment">// 递归后继节点</span></span><br><span class="line"> cur->next = pre; <span class="comment">// 修改节点引用指向</span></span><br><span class="line"> <span class="keyword">return</span> res; <span class="comment">// 返回反转链表的头节点</span></span><br><span class="line"> }</span><br><span class="line">};</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><blockquote>
<p>定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。</p>
</blockquote></summary>
<category term="LeetCode" scheme="https://codemariosec.github.io/categories/LeetCode/"/>
<category term="LeetCode" scheme="https://codemariosec.github.io/tags/LeetCode/"/>
<category term="linked list" scheme="https://codemariosec.github.io/tags/linked-list/"/>
</entry>
<entry>
<title>剑指 Offer 06.从尾到头打印链表</title>
<link href="https://codemariosec.github.io/2022/06/18/%E5%89%91%E6%8C%87%20Offer%2006.%20%E4%BB%8E%E5%B0%BE%E5%88%B0%E5%A4%B4%E6%89%93%E5%8D%B0%E9%93%BE%E8%A1%A8/"/>
<id>https://codemariosec.github.io/2022/06/18/%E5%89%91%E6%8C%87%20Offer%2006.%20%E4%BB%8E%E5%B0%BE%E5%88%B0%E5%A4%B4%E6%89%93%E5%8D%B0%E9%93%BE%E8%A1%A8/</id>
<published>2022-06-18T14:15:01.000Z</published>
<updated>2022-06-18T14:21:34.669Z</updated>
<content type="html"><![CDATA[<blockquote><p>输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。</p></blockquote><span id="more"></span><h3 id="示例"><a href="#示例" class="headerlink" title="示例"></a>示例</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">输入:head = [1,3,2]</span><br><span class="line">输出:[2,3,1]</span><br></pre></td></tr></table></figure><h3 id="题解"><a href="#题解" class="headerlink" title="题解"></a>题解</h3><p> 这道题主体思想是访问链表中的元素并设法倒序输出结果。</p><h4 id="方法一:递归法"><a href="#方法一:递归法" class="headerlink" title="方法一:递归法"></a>方法一:递归法</h4><p> 利用递归的方法先递推至链表末端,在回溯时依次将节点值加入列表,即可实现链表值的倒序输出。</p><p>需要注意的是:</p><ul><li>程序总是要有执行完毕的时候,当<code>head == nullptr</code>时,代表超越了链表尾节点,返回空列表</li></ul><p><strong>时间复杂度:</strong>遍历链表,递归<em>N</em>次。</p><p><strong>空间复杂度:</strong>系统递归需要使用<em>O</em>(<em>N</em>)的栈空间。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> {</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> <span class="function">vector<<span class="keyword">int</span>> <span class="title">reversePrint</span><span class="params">(ListNode* head)</span> </span>{</span><br><span class="line"> <span class="built_in">recur</span>(head);</span><br><span class="line"> <span class="keyword">return</span> res;</span><br><span class="line"> }</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"> vector<<span class="keyword">int</span>> res;</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">recur</span><span class="params">(ListNode* head)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span>(head == <span class="literal">nullptr</span>) <span class="keyword">return</span>;</span><br><span class="line"> <span class="built_in">recur</span>(head->next);</span><br><span class="line"> res.<span class="built_in">push_back</span>(head->val);</span><br><span class="line"> }</span><br><span class="line">};</span><br></pre></td></tr></table></figure><h4 id="方法二:迭代器反转法"><a href="#方法二:迭代器反转法" class="headerlink" title="方法二:迭代器反转法"></a>方法二:迭代器反转法</h4><p> 链表只能从前往后访问每个节点,因为要倒序输出各节点值,所以我们也可以借助<code>reverse()</code>函数实现链表值的倒序输出。</p><p>需要注意的是:</p><ul><li>当<code>head != nullptr</code>时,从前往后依次访问节点并将其添加到res容器中去</li></ul><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> {</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> <span class="function">vector<<span class="keyword">int</span>> <span class="title">reversePrint</span><span class="params">(ListNode* head)</span> </span>{</span><br><span class="line"> vector<<span class="keyword">int</span>> res;</span><br><span class="line"> <span class="keyword">while</span>(head != <span class="literal">nullptr</span>)</span><br><span class="line"> {</span><br><span class="line"> res.<span class="built_in">push_back</span>(head->val);</span><br><span class="line"> head = head->next;</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">reverse</span>(res.<span class="built_in">begin</span>(), res.<span class="built_in">end</span>());</span><br><span class="line"> <span class="keyword">return</span> res;</span><br><span class="line"> }</span><br><span class="line">};</span><br></pre></td></tr></table></figure><h4 id="方法三:辅助栈法"><a href="#方法三:辅助栈法" class="headerlink" title="方法三:辅助栈法"></a>方法三:辅助栈法</h4><p> 链表只能从前往后访问每个节点,因为要倒序输出各节点值,我们可以借助栈来实现。</p><p><strong>时间复杂度:</strong> 入栈和出栈共使用<em>O</em>(<em>N</em>)时间。<br><strong>空间复杂度:</strong> 辅助栈 stack 和数组 res 共使用<em>O</em>(<em>N</em>)的额外空间。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> {</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> <span class="function">vector<<span class="keyword">int</span>> <span class="title">reversePrint</span><span class="params">(ListNode* head)</span> </span>{</span><br><span class="line"> stack<<span class="keyword">int</span>> stk;</span><br><span class="line"> <span class="keyword">while</span>(head != <span class="literal">nullptr</span>) {</span><br><span class="line"> stk.<span class="built_in">push</span>(head->val);</span><br><span class="line"> head = head->next;</span><br><span class="line"> }</span><br><span class="line"> vector<<span class="keyword">int</span>> res;</span><br><span class="line"> <span class="keyword">while</span>(!stk.<span class="built_in">empty</span>()) {</span><br><span class="line"> res.<span class="built_in">push_back</span>(stk.<span class="built_in">top</span>());</span><br><span class="line"> stk.<span class="built_in">pop</span>();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> res;</span><br><span class="line"> }</span><br><span class="line">};</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><blockquote>
<p>输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。</p>
</blockquote></summary>
<category term="LeetCode" scheme="https://codemariosec.github.io/categories/LeetCode/"/>
<category term="LeetCode" scheme="https://codemariosec.github.io/tags/LeetCode/"/>
<category term="stack" scheme="https://codemariosec.github.io/tags/stack/"/>
<category term="linked list" scheme="https://codemariosec.github.io/tags/linked-list/"/>
</entry>
<entry>
<title>剑指 Offer 30.包含 min 函数的栈</title>
<link href="https://codemariosec.github.io/2022/06/18/%E5%89%91%E6%8C%87%20Offer%2030.%20%E5%8C%85%E5%90%AB%20min%20%E5%87%BD%E6%95%B0%E7%9A%84%E6%A0%88/"/>
<id>https://codemariosec.github.io/2022/06/18/%E5%89%91%E6%8C%87%20Offer%2030.%20%E5%8C%85%E5%90%AB%20min%20%E5%87%BD%E6%95%B0%E7%9A%84%E6%A0%88/</id>
<published>2022-06-18T06:13:01.000Z</published>
<updated>2022-06-18T06:21:20.980Z</updated>
<content type="html"><![CDATA[<blockquote><p>定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。</p></blockquote><span id="more"></span><h3 id="示例"><a href="#示例" class="headerlink" title="示例"></a>示例</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">MinStack minStack = new MinStack();</span><br><span class="line">minStack.push(-2);</span><br><span class="line">minStack.push(0);</span><br><span class="line">minStack.push(-3);</span><br><span class="line">minStack.min(); --> 返回 -3.</span><br><span class="line">minStack.pop();</span><br><span class="line">minStack.top(); --> 返回 0.</span><br><span class="line">minStack.min(); --> 返回 -2.</span><br></pre></td></tr></table></figure><h3 id="题解"><a href="#题解" class="headerlink" title="题解"></a>题解</h3><p> 实现能够得到栈的最小元素min函数,需要遍历栈中所有元素,这一过程复杂度为<em>O</em>(<em>N</em>),题目要求min函数的复杂度是<em>O</em>(1),我们可以通过分别定义两栈<code>stk</code>和<code>stk_min</code>来实现,其中<code>stk</code>用来存入<code>push</code>进来的栈元素,<code>stk_min</code>用来存储<code>stk</code>中最小值,<code>stk</code>中的最小元素始终对应着<code>stk_min</code>中的栈顶元素,min函数只需返回<code>stk_min</code>中的栈顶元素即可。</p><p>设计该数据结构时我们需要注意以下几点:</p><ul><li><code>push(x)</code>函数中,在元素x压入<code>stk</code>后,如果<code>stk_min</code>为空则将元素x压入<code>stk_min</code>,如果<code>stk_min</code>不为空,则判断<code>stk_min</code>中当前栈顶元素是否小于元素x,如果小于则返回<code>stk_min</code>中的栈顶元素,反之返回元素x,将当前的值压入<code>stk_min</code>中。</li><li><code>pop()</code>函数中要将<code>stk</code>和<code>stk_min</code>中对应的最小值元素同时弹出。</li></ul><figure class="highlight c++"><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MinStack</span> {</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> stack<<span class="keyword">int</span>> stk, stk_min;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/** initialize your data structure here. */</span></span><br><span class="line"> <span class="built_in">MinStack</span>() {}</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">push</span><span class="params">(<span class="keyword">int</span> x)</span> </span>{</span><br><span class="line"> stk.<span class="built_in">push</span>(x);</span><br><span class="line"> <span class="keyword">if</span> (!stk_min.<span class="built_in">empty</span>())</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> num = stk_min.<span class="built_in">top</span>() < x ? stk_min.<span class="built_in">top</span>():x;</span><br><span class="line"> stk_min.<span class="built_in">push</span>(num);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> </span><br><span class="line"> {</span><br><span class="line"> stk_min.<span class="built_in">push</span>(x);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">pop</span><span class="params">()</span> </span>{</span><br><span class="line"> stk.<span class="built_in">pop</span>();</span><br><span class="line"> stk_min.<span class="built_in">pop</span>();</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">int</span> <span class="title">top</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> stk.<span class="built_in">top</span>();</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">int</span> <span class="title">min</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> stk_min.<span class="built_in">top</span>();</span><br><span class="line"> }</span><br><span class="line">};</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><blockquote>
<p>定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。</p>
</blockquote></summary>
<category term="LeetCode" scheme="https://codemariosec.github.io/categories/LeetCode/"/>
<category term="LeetCode" scheme="https://codemariosec.github.io/tags/LeetCode/"/>
<category term="stack" scheme="https://codemariosec.github.io/tags/stack/"/>
</entry>
<entry>
<title>剑指 Offer 09. 用两个栈实现队列</title>
<link href="https://codemariosec.github.io/2022/06/18/%E5%89%91%E6%8C%87Offer%2009.%E7%94%A8%E4%B8%A4%E4%B8%AA%E6%A0%88%E5%AE%9E%E7%8E%B0%E9%98%9F%E5%88%97/"/>
<id>https://codemariosec.github.io/2022/06/18/%E5%89%91%E6%8C%87Offer%2009.%E7%94%A8%E4%B8%A4%E4%B8%AA%E6%A0%88%E5%AE%9E%E7%8E%B0%E9%98%9F%E5%88%97/</id>
<published>2022-06-18T05:18:01.000Z</published>
<updated>2022-06-18T06:21:08.357Z</updated>
<content type="html"><![CDATA[<blockquote><p>用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )。</p></blockquote><span id="more"></span><h3 id="示例"><a href="#示例" class="headerlink" title="示例"></a>示例</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">输入:</span><br><span class="line">["CQueue","appendTail","deleteHead","deleteHead"]</span><br><span class="line">[[],[3],[],[]]</span><br><span class="line">输出:[null,null,3,-1]</span><br><span class="line"></span><br><span class="line">输入:</span><br><span class="line">["CQueue","deleteHead","appendTail","appendTail","deleteHead","deleteHead"]</span><br><span class="line">[[],[],[5],[2],[],[]]</span><br><span class="line">输出:[null,-1,null,null,5,2]</span><br></pre></td></tr></table></figure><h3 id="题解"><a href="#题解" class="headerlink" title="题解"></a>题解</h3><p> 两栈实现一个队列,appendTail需要实现队列尾部插入整数,deleteHead需要实现队列头部删除整数,因为栈的数据结构特征是<strong>先进后出</strong>,所以栈底元素无法直接被删除,如要删除需要将其上方的元素进行出栈操作,使用两栈实现列表倒序操作可以实现此功能,顺应两栈实现一队列。</p><p> 分别定义<code>stk1</code>和<code>stk2</code>两栈,将元素压入<code>stk1</code>中,执行删除操作要循环执行<code>stk1</code>元素出栈将其添加入栈到<code>stk2</code>中,实现了<code>stk2</code>中元素为<code>stk1</code>中元素的倒序,<code>stk2</code>中栈首的元素弹出即为删除<code>stk1</code>中栈底元素,即删除队列头部元素。 </p><p>在<code>deleteHead()</code>我们需要注意以下情况:</p><ul><li>当<code>stk2</code>不为空时,<code>stk2</code>中依然有已完成倒序的元素,因此要直接返回<code>stk2</code>的栈顶元素。</li><li>当<code>stk1</code>为空时,两栈都为空,无元素返回-1。</li><li>当<code>stk1</code>不为空时,将<code>stk1</code>元素全部压到<code>stk2</code>中,实现元素倒序,并返回<code>stk2</code>的栈顶元素。</li></ul><p><strong>时间复杂度:</strong><code>appendTail()</code>函数为<em>O</em>(1) ;<code>deleteHead()</code> 函数在 <em>N</em> 次队首元素删除操作中总共需完成 <em>N</em> 个元素的倒序。</p><p><strong>空间复杂度 O(N) :</strong> 最差情况下,<code>stk1</code> 和 <code>stk2</code> 共保存 <em>N</em> 个元素。</p><figure class="highlight c++"><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">CQueue</span> {</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> stack<<span class="keyword">int</span>> stk1, stk2;</span><br><span class="line"> <span class="built_in">CQueue</span>() {}</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">appendTail</span><span class="params">(<span class="keyword">int</span> value)</span> </span>{</span><br><span class="line"> stk1.<span class="built_in">push</span>(value);</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">int</span> <span class="title">deleteHead</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (!stk2.<span class="built_in">empty</span>())</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> stack_top = stk2.<span class="built_in">top</span>();</span><br><span class="line"> stk2.<span class="built_in">pop</span>();</span><br><span class="line"> <span class="keyword">return</span> stack_top; </span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (stk1.<span class="built_in">empty</span>())</span><br><span class="line"> <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">while</span> (!stk1.<span class="built_in">empty</span>())</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> stack_top = stk1.<span class="built_in">top</span>();</span><br><span class="line"> stk1.<span class="built_in">pop</span>();</span><br><span class="line"> stk2.<span class="built_in">push</span>(stack_top);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">int</span> stack_top = stk2.<span class="built_in">top</span>();</span><br><span class="line"> stk2.<span class="built_in">pop</span>();</span><br><span class="line"> <span class="keyword">return</span> stack_top;</span><br><span class="line"> }</span><br><span class="line">};</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><blockquote>
<p>用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )。</p>
</blockquote></summary>
<category term="LeetCode" scheme="https://codemariosec.github.io/categories/LeetCode/"/>
<category term="LeetCode" scheme="https://codemariosec.github.io/tags/LeetCode/"/>
<category term="stack" scheme="https://codemariosec.github.io/tags/stack/"/>
</entry>
<entry>
<title>论gcc编译工具的基本使用</title>
<link href="https://codemariosec.github.io/2022/06/15/%E8%AE%BAgcc%E7%BC%96%E8%AF%91%E5%B7%A5%E5%85%B7%E7%9A%84%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8/"/>
<id>https://codemariosec.github.io/2022/06/15/%E8%AE%BAgcc%E7%BC%96%E8%AF%91%E5%B7%A5%E5%85%B7%E7%9A%84%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8/</id>
<published>2022-06-14T16:00:01.000Z</published>
<updated>2022-06-14T16:33:09.819Z</updated>
<content type="html"><![CDATA[<h1 id="一、什么是GCC编译器"><a href="#一、什么是GCC编译器" class="headerlink" title="一、什么是GCC编译器"></a>一、什么是GCC编译器</h1><p> GCC是由GNU开发的编程语言编译器,GNU编译器套件包括C、C++、Objective-C、Java、Ada 和 Go 语言前端,也包括了这些语言的库(如 libstdc++,libgcj等),它可以完成上述编程语言从源文件向运行在特定CPU硬件上的目标代码的转换,GCC不仅功能非常强大,而且结构也很灵活,具有良好的便携性和跨平台支持。</p><span id="more"></span><h1 id="二、GCC-G-安装命令"><a href="#二、GCC-G-安装命令" class="headerlink" title="二、GCC/G++安装命令"></a>二、GCC/G++安装命令</h1><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo apt install gcc g++ </span><br></pre></td></tr></table></figure><p>安装好后可以通过以下命令来查看gcc/g++版本,确定是否安装成功</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><span class="line">gcc -v# 查看gcc版本</span><br><span class="line">g++ -v# 查看g++版本</span><br></pre></td></tr></table></figure><h1 id="三、GCC编译工具支持的文件类型"><a href="#三、GCC编译工具支持的文件类型" class="headerlink" title="三、GCC编译工具支持的文件类型"></a>三、GCC编译工具支持的文件类型</h1><div class="table-container"><table><thead><tr><th style="text-align:center">文件后缀</th><th style="text-align:center">说明</th></tr></thead><tbody><tr><td style="text-align:center">.c</td><td style="text-align:center">C语言源程序</td></tr><tr><td style="text-align:center">.a</td><td style="text-align:center">由目标文件构成的档案库文件</td></tr><tr><td style="text-align:center">.C/.cc/.cxx</td><td style="text-align:center">C++源程序</td></tr><tr><td style="text-align:center">.h</td><td style="text-align:center">源程序包含的头文件</td></tr><tr><td style="text-align:center">.i</td><td style="text-align:center">C源代码文件且不应该对其执行预处理</td></tr><tr><td style="text-align:center">.ii</td><td style="text-align:center">C++源代码文件且不应该对其执行预处理</td></tr><tr><td style="text-align:center">.m</td><td style="text-align:center">Objective-C源程序</td></tr><tr><td style="text-align:center">.o</td><td style="text-align:center">编译后的目标文件</td></tr><tr><td style="text-align:center">.s</td><td style="text-align:center">汇编语言源代码文件</td></tr><tr><td style="text-align:center">.S</td><td style="text-align:center">经过预编译的汇编程序</td></tr></tbody></table></div><h1 id="四、GCC使用方法"><a href="#四、GCC使用方法" class="headerlink" title="四、GCC使用方法"></a>四、GCC使用方法</h1><p>gcc是基于Linux平台下的C语言编译器,其基本的使用语法如下。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gcc [option | fileName] [fileName] [destination fileName]</span><br></pre></td></tr></table></figure><p>g++是基于Linux平台下的C++语言编译器,其基本的使用语法如下。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">g++ [option | fileName] [fileName] [destination fileName]</span><br></pre></td></tr></table></figure><h1 id="五、GCC编译工具工作流程"><a href="#五、GCC编译工具工作流程" class="headerlink" title="五、GCC编译工具工作流程"></a>五、GCC编译工具工作流程</h1><p> gcc由C源代码文件生成可执行文件的过程不仅仅是编译的过程,而是要经历以下步骤。</p><p><img src="https://codemario-picgo.oss-cn-shenzhen.aliyuncs.com/img/gcc.drawio.png" alt="gcc.drawio"></p><p>这里我们以helloworld.c文件为例来阐述gcc的工作流程。</p><p>源文件代码如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><stdio.h></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> NUM 20</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span> </span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">char</span> s[NUM]=<span class="string">"\0"</span>;</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Please enter the content.\n"</span>);</span><br><span class="line"> fgets(s, NUM, <span class="built_in">stdin</span>);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%s"</span>, s);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>(1)预处理阶段</strong></p><p> 预处理过程中,将源代码文件中包含的各种头文件以及预编译语句等展开生成后缀以.i结尾的文件。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gcc -E helloworld.c -o helloworld.i</span><br></pre></td></tr></table></figure><p>编译生成的<code>helloworld.i</code>文件内容如图所示:</p><p><img src="https://codemario-picgo.oss-cn-shenzhen.aliyuncs.com/img/helloworld-i.png" alt="helloworld-i" style="zoom:67%;" /></p><p><strong>(2)编译阶段</strong></p><p> 将预处理后以.i结尾的文件编译生成后缀以.s结尾的汇编语言代码文件。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gcc -S helloworld.i -o helloworld.s</span><br></pre></td></tr></table></figure><p>编译生成的<code>helloworld.s</code>文件内容如图所示:</p><p><img src="https://codemario-picgo.oss-cn-shenzhen.aliyuncs.com/img/helloworld-s.png" alt="helloworld-s" style="zoom:67%;" /></p><p><strong>(3)汇编阶段</strong></p><p> 将以.s为后缀的汇编语言文件经过汇编后生成后缀以.o结尾的目标文件。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gcc -c helloworld.s -o helloworld.o</span><br></pre></td></tr></table></figure><p>编译生成的<code>helloworld.o</code>文件内容如图所示:</p><p><img src="https://codemario-picgo.oss-cn-shenzhen.aliyuncs.com/img/helloworld-o.png" alt="helloworld-o" style="zoom:67%;" /></p><p> 打开文件我们看到其中的的内容是由各种特殊字符组成,汇编阶段的工作是将汇编语言的代码转换为机器码,这部分代码是可以直接被计算机所执行的,我们通过<code>file helloworld.o</code>指令查看一下该文件的类型。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">helloworld.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped</span><br></pre></td></tr></table></figure><p>我们可以得知该文件的文件格式是elf格式,elf格式的文件我们可以使用<code>readelf</code>工具查看其中内容。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">readelf -a helloworld.o</span><br></pre></td></tr></table></figure><p><img src="https://codemario-picgo.oss-cn-shenzhen.aliyuncs.com/img/readelfhelloworld-o.png" alt="readelfhelloworld-o" style="zoom:67%;" /></p><p><strong>(4)链接阶段</strong></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><span class="line">gcc helloworld.o -o helloworld</span><br></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><span class="line">gcc helloworld.c -o helloworld</span><br></pre></td></tr></table></figure><p><strong>运行结果</strong></p><p><img src="https://codemario-picgo.oss-cn-shenzhen.aliyuncs.com/img/result.png" alt="result" /></p><p> 在上述的执行过程中,我们还需要知道的是,在链接阶段,链接的方式有两种,一种是<strong>静态链接</strong>,另一种是<strong>动态链接</strong>。</p><p> 其中<strong>静态链接</strong>是在gcc链接执行代码后面加上 <code>--static</code>选项,静态链接在gcc链接时就会将程序所用到的库打包到自己的可执行程序中,无需依赖外部环境,程序兼容性比较好,但是生成的程序比较大。</p><p> <strong>动态链接</strong>是在程序运行时将外部的代码库动态加载到内存中,在gcc链接时不会将代码打包到可执行程序中,生成的程序比较小。gcc的编译链接时候默认是以动态链接的方式加载的。我们可以使用<code>ldd</code>工具去查看动态文件的库依赖。</p><p><img src="https://codemario-picgo.oss-cn-shenzhen.aliyuncs.com/img/%E5%8A%A8%E6%80%81%E9%93%BE%E6%8E%A5%E5%BA%93%E4%BE%9D%E8%B5%96.png" alt="动态链接库依赖" /></p><p> 我们由此可以得知通过动态链接生成的helloworld依赖于库文件linux-vdso.so.1、libc.so.6 以及ld-linux-x86-64.so.2。</p><p> 我们可以分别以静态链接和动态链接的方式去编译链接上面的程序,并去查看一下两种方式生成的可执行文件的大小。</p><p><img src="https://codemario-picgo.oss-cn-shenzhen.aliyuncs.com/img/%E9%9D%99%E6%80%81%E9%93%BE%E6%8E%A5%E5%8A%A8%E6%80%81%E9%93%BE%E6%8E%A5%E7%94%9F%E6%88%90%E7%9A%84%E6%96%87%E4%BB%B6%E5%A4%A7%E5%B0%8F%E5%AF%B9%E6%AF%94.png" alt="静态链接动态链接生成的文件大小对比"></p><p> 动态链接生成的可执行文件大小为17k,静态链接生成的可执行文件大小为852k。</p><h1 id="六、GCC常用参数选项"><a href="#六、GCC常用参数选项" class="headerlink" title="六、GCC常用参数选项"></a>六、GCC常用参数选项</h1><div class="table-container"><table><thead><tr><th style="text-align:center">gcc编译选项</th><th style="text-align:center">说明</th></tr></thead><tbody><tr><td style="text-align:center">-E</td><td style="text-align:center">预处理指定的源文件,不进行编译</td></tr><tr><td style="text-align:center">-S</td><td style="text-align:center">编译指定的源文件,但是不进行汇编</td></tr><tr><td style="text-align:center">-c</td><td style="text-align:center">编译、汇编指定的源文件,但是不进行链接</td></tr><tr><td style="text-align:center">-o [file1] [file2] / [file2] -o [file1]</td><td style="text-align:center">将文件 file2 编译成可执行文件 file1</td></tr><tr><td style="text-align:center">-I directory</td><td style="text-align:center">指定 include 包含文件的搜索目录</td></tr><tr><td style="text-align:center">-g</td><td style="text-align:center">在编译的时候,生成调试信息,该程序可以被调试器调试</td></tr><tr><td style="text-align:center">-D</td><td style="text-align:center">在程序编译的时候,指定一个宏</td></tr><tr><td style="text-align:center">-w</td><td style="text-align:center">不生成任何警告信息</td></tr><tr><td style="text-align:center">-Wall</td><td style="text-align:center">生成所有警告信息</td></tr><tr><td style="text-align:center">-On</td><td style="text-align:center">n的取值范围:0~3。编译器的优化选项的4个级别,-O0表 示没有优化,-O1为缺省值,-O3优化级别最高</td></tr><tr><td style="text-align:center">-l</td><td style="text-align:center">在程序编译的时候,指定使用的库</td></tr><tr><td style="text-align:center">-L</td><td style="text-align:center">指定编译的时候,搜索的库的路径</td></tr><tr><td style="text-align:center">-fPIC/fpic</td><td style="text-align:center">生成与位置无关的代码</td></tr><tr><td style="text-align:center">-shared</td><td style="text-align:center">生成共享目标文件,通常用在建立共享库时</td></tr><tr><td style="text-align:center">-std</td><td style="text-align:center">指定C的执行版本,如:-std=c99,gcc默认的版本是GNU C</td></tr></tbody></table></div>]]></content>
<summary type="html"><h1 id="一、什么是GCC编译器"><a href="#一、什么是GCC编译器" class="headerlink" title="一、什么是GCC编译器"></a>一、什么是GCC编译器</h1><p> GCC是由GNU开发的编程语言编译器,GNU编译器套件包括C、C++、Objective-C、Java、Ada 和 Go 语言前端,也包括了这些语言的库(如 libstdc++,libgcj等),它可以完成上述编程语言从源文件向运行在特定CPU硬件上的目标代码的转换,GCC不仅功能非常强大,而且结构也很灵活,具有良好的便携性和跨平台支持。</p></summary>
<category term="C/C++" scheme="https://codemariosec.github.io/categories/C-C/"/>
<category term="gcc" scheme="https://codemariosec.github.io/tags/gcc/"/>
<category term="C/C++" scheme="https://codemariosec.github.io/tags/C-C/"/>
</entry>
<entry>
<title>Pcap文件详解</title>
<link href="https://codemariosec.github.io/2022/05/12/pcap%E6%96%87%E4%BB%B6%E6%A0%BC%E5%BC%8F%E8%AF%A6%E8%A7%A3/"/>
<id>https://codemariosec.github.io/2022/05/12/pcap%E6%96%87%E4%BB%B6%E6%A0%BC%E5%BC%8F%E8%AF%A6%E8%A7%A3/</id>
<published>2022-05-12T07:49:38.000Z</published>
<updated>2022-06-03T06:53:50.330Z</updated>
<content type="html"><![CDATA[<h1 id="Pcap文件详解"><a href="#Pcap文件详解" class="headerlink" title="Pcap文件详解"></a>Pcap文件详解</h1><h2 id="一、简介"><a href="#一、简介" class="headerlink" title="一、简介"></a>一、简介</h2><p> pcap文件是一种常用的数据报存储格式,里面的数据按照特定的规格存储和解析。</p><p> 一般来说使用普通的笔记本打开的pcap文件显示的是乱码,所以我们需要使用支持16进制格式的工具去查看该文件,这里使用<a href="https://hexed.it/">https://hexed.it/</a> 这个在线网站去查看。</p><span id="more"></span><h2 id="二、文件格式"><a href="#二、文件格式" class="headerlink" title="二、文件格式"></a>二、文件格式</h2><p><img src="https://codemario-picgo.oss-cn-shenzhen.aliyuncs.com/img/%E6%96%87%E4%BB%B6%E6%A0%BC%E5%BC%8F%E6%9E%84%E6%88%90.png" alt="文件格式构成"></p><p> pcag文件格式主要是由文件头-数据包头1-数据包1-数据包头2-数据包2这类格式组成。其中文件头只有一个,数据包头和数据包可以有多个,如下图所示。</p><p><img src="https://codemario-picgo.oss-cn-shenzhen.aliyuncs.com/img/%E6%96%87%E4%BB%B6%E6%A0%BC%E5%BC%8F%E6%9E%84%E6%88%90%E8%AF%A6%E6%83%85.png" alt="文件格式构成详情"></p><p> 每个pcap文件只有一个文件头,里面包含7个字段,总共占24(B)字节。</p><h3 id="1-Pcap-Header"><a href="#1-Pcap-Header" class="headerlink" title="1.Pcap Header"></a>1.Pcap Header</h3><table><thead><tr><th align="center">header field</th><th align="center">size</th><th align="center">explain</th></tr></thead><tbody><tr><td align="center">Magic</td><td align="center">4B</td><td align="center">标记文件开始,并用来识别文件和字节顺序</td></tr><tr><td align="center">Major</td><td align="center">2B</td><td align="center">当前Pcap文件的主要版本号,一般为0x0200</td></tr><tr><td align="center">Minor</td><td align="center">2B</td><td align="center">当前Pcap文件的次要版本号,一般为0x0400</td></tr><tr><td align="center">ThisZone</td><td align="center">4B</td><td align="center">当地的标准事件,如果用的是GMT则全零,一般全零</td></tr><tr><td align="center">SigFlags</td><td align="center">4B</td><td align="center">时间戳的精度,一般为全零</td></tr><tr><td align="center">SnapLen</td><td align="center">4B</td><td align="center">所抓获的数据包的最大长度</td></tr><tr><td align="center">LinkType</td><td align="center">4B</td><td align="center">数据链路类型</td></tr></tbody></table><h3 id="2-Packet-Header"><a href="#2-Packet-Header" class="headerlink" title="2.Packet Header"></a>2.Packet Header</h3><table><thead><tr><th align="center">header field</th><th align="center">size</th><th align="center">explain</th></tr></thead><tbody><tr><td align="center">Timestamp</td><td align="center">4B</td><td align="center">时间戳高位,精确到seconds</td></tr><tr><td align="center">Timestamp</td><td align="center">4B</td><td align="center">时间戳低位,能够精确到microseconds</td></tr><tr><td align="center">Caplen</td><td align="center">4B</td><td align="center">即抓取到的数据帧长度,由此可以得到下一个数据帧的位置。</td></tr><tr><td align="center">Len</td><td align="center">4B</td><td align="center">实际的数据帧长度</td></tr></tbody></table><h3 id="3-Packet-Data"><a href="#3-Packet-Data" class="headerlink" title="3.Packet Data"></a>3.Packet Data</h3><p> Packet是链路层的数据帧,其长度是Packet Header中定义的Caplen值,所以Packet Data的长度为Caplen。</p><h3 id="4-案例"><a href="#4-案例" class="headerlink" title="4.案例"></a>4.案例</h3><p> 打开文件后如图所示(这里截取前面的部分)</p><p><img src="https://codemario-picgo.oss-cn-shenzhen.aliyuncs.com/img/demo_1.png" alt="demo_1"></p><h4 id="Pcap-Header"><a href="#Pcap-Header" class="headerlink" title="Pcap Header"></a>Pcap Header</h4><p><img src="https://codemario-picgo.oss-cn-shenzhen.aliyuncs.com/img/pacp_header.png" alt="pacp_header"></p><table><thead><tr><th align="center">header field</th><th align="center">value</th></tr></thead><tbody><tr><td align="center">Magic</td><td align="center">0XD4C3B2A1</td></tr><tr><td align="center">Major</td><td align="center">0X0002</td></tr><tr><td align="center">Minor</td><td align="center">0X0004</td></tr><tr><td align="center">ThisZone</td><td align="center">0X00000000</td></tr><tr><td align="center">SigFlags</td><td align="center">0X00000000</td></tr><tr><td align="center">SnapLen</td><td align="center">0X00040000</td></tr><tr><td align="center">LinkType</td><td align="center">0X00000001</td></tr></tbody></table><h4 id="Packet-Header"><a href="#Packet-Header" class="headerlink" title="Packet Header"></a>Packet Header</h4><p><img src="https://codemario-picgo.oss-cn-shenzhen.aliyuncs.com/img/packet_header.png" alt="packet_header"></p><table><thead><tr><th align="center">header field</th><th align="center">value</th></tr></thead><tbody><tr><td align="center">Timestamp</td><td align="center">0X6279C37B</td></tr><tr><td align="center">Timestamp</td><td align="center">0X0009EDB4</td></tr><tr><td align="center">Caplen</td><td align="center">0X00000042</td></tr><tr><td align="center">Len</td><td align="center">0X00000042</td></tr></tbody></table><h4 id="Packet-Data"><a href="#Packet-Data" class="headerlink" title="Packet Data"></a>Packet Data</h4><p><img src="https://codemario-picgo.oss-cn-shenzhen.aliyuncs.com/img/packet_data.png" alt="packet_data"></p><p> 数据包大小为0X00000042 = 66B</p>]]></content>
<summary type="html"><h1 id="Pcap文件详解"><a href="#Pcap文件详解" class="headerlink" title="Pcap文件详解"></a>Pcap文件详解</h1><h2 id="一、简介"><a href="#一、简介" class="headerlink" title="一、简介"></a>一、简介</h2><p> pcap文件是一种常用的数据报存储格式,里面的数据按照特定的规格存储和解析。</p>
<p> 一般来说使用普通的笔记本打开的pcap文件显示的是乱码,所以我们需要使用支持16进制格式的工具去查看该文件,这里使用<a href="https://hexed.it/">https://hexed.it/</a> 这个在线网站去查看。</p></summary>
<category term="网络" scheme="https://codemariosec.github.io/categories/%E7%BD%91%E7%BB%9C/"/>
<category term="Pcap" scheme="https://codemariosec.github.io/tags/Pcap/"/>
</entry>
<entry>
<title>Linux操作系统密码破解</title>
<link href="https://codemariosec.github.io/2022/01/31/Linux%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%AF%86%E7%A0%81%E7%A0%B4%E8%A7%A3/"/>
<id>https://codemariosec.github.io/2022/01/31/Linux%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%AF%86%E7%A0%81%E7%A0%B4%E8%A7%A3/</id>
<published>2022-01-30T18:11:51.000Z</published>
<updated>2022-06-03T06:53:27.784Z</updated>
<content type="html"><![CDATA[<h1 id="注:该文章中使用到的方法只用于学习交流,切勿用于非法途径!!!"><a href="#注:该文章中使用到的方法只用于学习交流,切勿用于非法途径!!!" class="headerlink" title="注:该文章中使用到的方法只用于学习交流,切勿用于非法途径!!!"></a>注:该文章中使用到的方法只用于学习交流,切勿用于非法途径!!!</h1><span id="more"></span><h2 id="1-下载owasp"><a href="#1-下载owasp" class="headerlink" title="1.下载owasp"></a>1.下载owasp</h2><p><img src="https://codemario-picgo.oss-cn-shenzhen.aliyuncs.com/img/%E4%BA%8C-1.1%20%E5%8E%BBowasp%E5%AE%98%E7%BD%91%E4%B8%8B%E8%BD%BDowasp.png" alt="二-1.1 去owasp官网下载owasp"></p><h2 id="2-将owasp添加到VMware中"><a href="#2-将owasp添加到VMware中" class="headerlink" title="2.将owasp添加到VMware中"></a>2.将owasp添加到VMware中</h2><p><img src="https://codemario-picgo.oss-cn-shenzhen.aliyuncs.com/img/%E4%BA%8C-2%20%E5%B0%86owasp%E6%B7%BB%E5%8A%A0%E5%88%B0VMware%E4%B8%AD.png" alt="二-2 将owasp添加到VMware中"></p><h2 id="3-启动owasp"><a href="#3-启动owasp" class="headerlink" title="3.启动owasp"></a>3.启动owasp</h2><h2 id="4-使用ifconfig查看自己的owasp当前的ip地址,在kali中打开浏览器试的去访问一下该ip是否可以正常使用"><a href="#4-使用ifconfig查看自己的owasp当前的ip地址,在kali中打开浏览器试的去访问一下该ip是否可以正常使用" class="headerlink" title="4.使用ifconfig查看自己的owasp当前的ip地址,在kali中打开浏览器试的去访问一下该ip是否可以正常使用"></a>4.使用ifconfig查看自己的owasp当前的ip地址,在kali中打开浏览器试的去访问一下该ip是否可以正常使用</h2><h2 id="5-可以正常使用"><a href="#5-可以正常使用" class="headerlink" title="5.可以正常使用"></a>5.可以正常使用</h2><p><img src="https://codemario-picgo.oss-cn-shenzhen.aliyuncs.com/img/%E4%BA%8C-4%20owasp%E9%A6%96%E9%A1%B5.png" alt="二-4 owasp首页"></p><h2 id="6-在kali中使用自带的medusa工具去破解owasp的密码"><a href="#6-在kali中使用自带的medusa工具去破解owasp的密码" class="headerlink" title="6.在kali中使用自带的medusa工具去破解owasp的密码"></a>6.在kali中使用自带的medusa工具去破解owasp的密码</h2><p><strong>注意:在使用medusa之前需要先去生成一个密码字典,来方便我们对其进行破解,密码字典的生成可以使用Crunch工具或John工具。</strong></p><h3 id="6-1-输入以下指令开始破解"><a href="#6-1-输入以下指令开始破解" class="headerlink" title="6.1 输入以下指令开始破解"></a>6.1 输入以下指令开始破解</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">1 medusa -h [目标ip地址] -u [用户名] -P [密码字典] -M [目标使用的协议]</span><br></pre></td></tr></table></figure><p><img src="https://codemario-picgo.oss-cn-shenzhen.aliyuncs.com/img/%E4%BA%8C-6%20%E7%A0%B4%E8%A7%A3owasp%E5%AF%86%E7%A0%81.png" alt="二-6 破解owasp密码"></p><h3 id="最终破解成功"><a href="#最终破解成功" class="headerlink" title="最终破解成功"></a>最终破解成功</h3><h1 id="注:该文章中使用到的方法只用于学习交流,切勿用于非法途径!!!-1"><a href="#注:该文章中使用到的方法只用于学习交流,切勿用于非法途径!!!-1" class="headerlink" title="注:该文章中使用到的方法只用于学习交流,切勿用于非法途径!!!"></a>注:该文章中使用到的方法只用于学习交流,切勿用于非法途径!!!</h1>]]></content>
<summary type="html"><h1 id="注:该文章中使用到的方法只用于学习交流,切勿用于非法途径!!!"><a href="#注:该文章中使用到的方法只用于学习交流,切勿用于非法途径!!!" class="headerlink" title="注:该文章中使用到的方法只用于学习交流,切勿用于非法途径!!!"></a>注:该文章中使用到的方法只用于学习交流,切勿用于非法途径!!!</h1></summary>
<category term="信息安全" scheme="https://codemariosec.github.io/categories/%E4%BF%A1%E6%81%AF%E5%AE%89%E5%85%A8/"/>
<category term="kali" scheme="https://codemariosec.github.io/tags/kali/"/>
</entry>
<entry>
<title>使用kali去破解windows主机密码</title>
<link href="https://codemariosec.github.io/2022/01/31/%E4%BD%BF%E7%94%A8kali%E5%8E%BB%E7%A0%B4%E8%A7%A3windows%E4%B8%BB%E6%9C%BA%E5%AF%86%E7%A0%81/"/>
<id>https://codemariosec.github.io/2022/01/31/%E4%BD%BF%E7%94%A8kali%E5%8E%BB%E7%A0%B4%E8%A7%A3windows%E4%B8%BB%E6%9C%BA%E5%AF%86%E7%A0%81/</id>
<published>2022-01-30T18:10:05.000Z</published>
<updated>2022-06-03T06:53:36.783Z</updated>
<content type="html"><![CDATA[<p>通常windows电脑中都设有开机密码,而其系统通常都是默认关闭3389端口的,并且设置了防火墙,以防黑客有机可乘去控制电脑。如果我们需要去破解对方windows的密码,就需要进行以下操作,在这里我们在VMware中使用win7和kali模拟过程。</p><span id="more"></span><h1 id="注:该文章中使用到的方法只用于学习交流,切勿用于非法途径!!!"><a href="#注:该文章中使用到的方法只用于学习交流,切勿用于非法途径!!!" class="headerlink" title="注:该文章中使用到的方法只用于学习交流,切勿用于非法途径!!!"></a>注:该文章中使用到的方法只用于学习交流,切勿用于非法途径!!!</h1><h2 id="1-开启win7的3389端口(远程桌面端口)"><a href="#1-开启win7的3389端口(远程桌面端口)" class="headerlink" title="1. 开启win7的3389端口(远程桌面端口)"></a>1. 开启win7的3389端口(远程桌面端口)</h2><p>3389端口是Windows的远程桌面的服务端口,可以通过这个端口,用”远程桌面”等连接工具来连接到远程的服务器,在连接成功后,输入系统管理员的用户名和密码后,就可以操作远程的电脑,因此远程服务器一般都将这个端口修改数值或者关闭。</p><h3 id="1-1-打开控制面板"><a href="#1-1-打开控制面板" class="headerlink" title="1.1 打开控制面板"></a>1.1 打开控制面板</h3><p><img src="https://codemario-picgo.oss-cn-shenzhen.aliyuncs.com/img/1.1%20%E7%82%B9%E5%87%BB%E6%8E%A7%E5%88%B6%E9%9D%A2%E6%9D%BF.png" alt="1.1 点击控制面板"></p><h3 id="1-2-点击远程设置"><a href="#1-2-点击远程设置" class="headerlink" title="1.2 点击远程设置"></a>1.2 点击远程设置</h3><p><img src="https://codemario-picgo.oss-cn-shenzhen.aliyuncs.com/img/1.2%20%E7%82%B9%E5%87%BB%E8%BF%9C%E7%A8%8B%E8%AE%BE%E7%BD%AE.png" alt="1.2 点击远程设置"></p><h3 id="1-3-选择运行任意版本远程桌面的计算机连接(默认是不允许连接到这台计算机)"><a href="#1-3-选择运行任意版本远程桌面的计算机连接(默认是不允许连接到这台计算机)" class="headerlink" title="1.3 选择运行任意版本远程桌面的计算机连接(默认是不允许连接到这台计算机)"></a>1.3 选择运行任意版本远程桌面的计算机连接(默认是不允许连接到这台计算机)</h3><p><img src="https://codemario-picgo.oss-cn-shenzhen.aliyuncs.com/img/1.3%20%E9%80%89%E6%8B%A9%E8%BF%90%E8%A1%8C%E4%BB%BB%E6%84%8F%E7%89%88%E6%9C%AC%E8%BF%9C%E7%A8%8B%E6%A1%8C%E9%9D%A2%E7%9A%84%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%BF%9E%E6%8E%A5.png" alt="1.3 选择运行任意版本远程桌面的计算机连接"></p><h2 id="2-打开cmd输入Firewall-cpl指令打开防火墙设置"><a href="#2-打开cmd输入Firewall-cpl指令打开防火墙设置" class="headerlink" title="2. 打开cmd输入Firewall.cpl指令打开防火墙设置"></a>2. 打开cmd输入Firewall.cpl指令打开防火墙设置</h2><p><img src="https://codemario-picgo.oss-cn-shenzhen.aliyuncs.com/img/1.4%20%E6%89%93%E5%BC%80cmd%E8%BE%93%E5%85%A5Firewall.cpl%E6%8C%87%E4%BB%A4%E6%89%93%E5%BC%80%E9%98%B2%E7%81%AB%E5%A2%99%E8%AE%BE%E7%BD%AE.png" alt="1.4 打开cmd输入Firewall.cpl指令打开防火墙设置"></p><h3 id="2-1-点击打开或关闭防火墙"><a href="#2-1-点击打开或关闭防火墙" class="headerlink" title="2.1 点击打开或关闭防火墙"></a>2.1 点击打开或关闭防火墙</h3><p><img src="https://codemario-picgo.oss-cn-shenzhen.aliyuncs.com/img/1.5%20%E7%82%B9%E5%87%BB%E6%89%93%E5%BC%80%E6%88%96%E5%85%B3%E9%97%AD%E9%98%B2%E7%81%AB%E5%A2%99.png" alt="1.5 点击打开或关闭防火墙"></p><h3 id="2-2-两个选项都选择关闭防火墙"><a href="#2-2-两个选项都选择关闭防火墙" class="headerlink" title="2.2 两个选项都选择关闭防火墙"></a>2.2 两个选项都选择关闭防火墙</h3><p><img src="https://codemario-picgo.oss-cn-shenzhen.aliyuncs.com/img/1.6%20%E4%B8%A4%E4%B8%AA%E9%80%89%E9%A1%B9%E9%83%BD%E9%80%89%E6%8B%A9%E5%85%B3%E9%97%AD%E9%98%B2%E7%81%AB%E5%A2%99.png" alt="1.6 两个选项都选择关闭防火墙"></p><h2 id="3-在kali中使用自带的nmap工具去扫描win7主机所在ip地址范围内的所有ip地址,查看同网段内的主机的3389端口是开放的"><a href="#3-在kali中使用自带的nmap工具去扫描win7主机所在ip地址范围内的所有ip地址,查看同网段内的主机的3389端口是开放的" class="headerlink" title="3.在kali中使用自带的nmap工具去扫描win7主机所在ip地址范围内的所有ip地址,查看同网段内的主机的3389端口是开放的"></a>3.在kali中使用自带的nmap工具去扫描win7主机所在ip地址范围内的所有ip地址,查看同网段内的主机的3389端口是开放的</h2><h3 id="3-1-输入以下命令开启扫描"><a href="#3-1-输入以下命令开启扫描" class="headerlink" title="3.1 输入以下命令开启扫描"></a>3.1 输入以下命令开启扫描</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nmap -p 3389 [要扫描的ip地址范围,比如192.168.1.1-255]</span><br></pre></td></tr></table></figure><h3 id="3-2-看到主机ip为192-168-178-131的3389端口已启动"><a href="#3-2-看到主机ip为192-168-178-131的3389端口已启动" class="headerlink" title="3.2 看到主机ip为192.168.178.131的3389端口已启动"></a>3.2 看到主机ip为192.168.178.131的3389端口已启动</h3><p><img src="https://codemario-picgo.oss-cn-shenzhen.aliyuncs.com/img/3.1%20%E4%BD%BF%E7%94%A8nmap%E6%89%AB%E6%8F%8F%E7%AB%AF%E5%8F%A3%E6%9F%A5%E7%9C%8B%E5%90%8C%E4%B8%80%E4%B8%AA%E7%BD%91%E6%AE%B5%E4%B8%AD%E5%93%AA%E4%BA%9B%E7%AB%AF%E5%8F%A3%E6%98%AF%E5%BC%80%E6%94%BE%E7%9A%84.png" alt="3.1 使用nmap扫描端口查看同一个网段中哪些端口是开放的"></p><h2 id="4-使用Crunch或John等工具生成密码字典,为后面使用hydra工具去破解win7密码做准备工作"><a href="#4-使用Crunch或John等工具生成密码字典,为后面使用hydra工具去破解win7密码做准备工作" class="headerlink" title="4. 使用Crunch或John等工具生成密码字典,为后面使用hydra工具去破解win7密码做准备工作"></a>4. 使用Crunch或John等工具生成密码字典,为后面使用hydra工具去破解win7密码做准备工作</h2><h2 id="5-使用hydra工具去破解win7所登录账户的密码"><a href="#5-使用hydra工具去破解win7所登录账户的密码" class="headerlink" title="5.使用hydra工具去破解win7所登录账户的密码"></a>5.使用hydra工具去破解win7所登录账户的密码</h2><h3 id="5-1-输入以下命令去破解"><a href="#5-1-输入以下命令去破解" class="headerlink" title="5.1 输入以下命令去破解"></a>5.1 输入以下命令去破解</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hydra -l [windows的账户名] -P [密码字典] rdp://[win7的ip地址]</span><br></pre></td></tr></table></figure><h2 id="最终破解成功"><a href="#最终破解成功" class="headerlink" title="最终破解成功"></a>最终破解成功</h2><h1 id="注:该文章中使用到的方法只用于学习交流,切勿用于非法途径!!!-1"><a href="#注:该文章中使用到的方法只用于学习交流,切勿用于非法途径!!!-1" class="headerlink" title="注:该文章中使用到的方法只用于学习交流,切勿用于非法途径!!!"></a>注:该文章中使用到的方法只用于学习交流,切勿用于非法途径!!!</h1><h3 id=""><a href="#" class="headerlink" title=""></a></h3>]]></content>
<summary type="html"><p>通常windows电脑中都设有开机密码,而其系统通常都是默认关闭3389端口的,并且设置了防火墙,以防黑客有机可乘去控制电脑。如果我们需要去破解对方windows的密码,就需要进行以下操作,在这里我们在VMware中使用win7和kali模拟过程。</p></summary>
<category term="信息安全" scheme="https://codemariosec.github.io/categories/%E4%BF%A1%E6%81%AF%E5%AE%89%E5%85%A8/"/>
<category term="kali" scheme="https://codemariosec.github.io/tags/kali/"/>
</entry>
<entry>
<title>Web前端_JavaScriptDay10_函数</title>
<link href="https://codemariosec.github.io/2022/01/31/Web%E5%89%8D%E7%AB%AF-JavaScriptDay10-%E5%87%BD%E6%95%B0/"/>
<id>https://codemariosec.github.io/2022/01/31/Web%E5%89%8D%E7%AB%AF-JavaScriptDay10-%E5%87%BD%E6%95%B0/</id>
<published>2022-01-30T18:09:09.000Z</published>
<updated>2022-06-03T06:53:21.352Z</updated>
<content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p> 无论是什么程序设计语言,函数都是重要的一部分内容,在实际开发过程中有很多语法的表达和功能的实现都来源于函数。不过与其它语言不同的是,JavaScript是通过函数来实现面向对象的特性并非通过专门的面向对象语法去实现的,因为JavaScript没有属于自己的专门的面向对象语法,所以函数在JavaScript中更是重中之重。</p><span id="more"></span><h1 id="一、函数的介绍"><a href="#一、函数的介绍" class="headerlink" title="一、函数的介绍"></a>一、函数的介绍</h1><h2 id="1-什么是函数?"><a href="#1-什么是函数?" class="headerlink" title="1.什么是函数?"></a>1.什么是函数?</h2><p> 函数是执行特定任务的代码块,之后通过调用函数实现特定任务功能的实现。</p><h2 id="2-函数的组成部分"><a href="#2-函数的组成部分" class="headerlink" title="2.函数的组成部分"></a>2.函数的组成部分</h2><ul><li>关键字function。</li><li>函数名称。</li><li>函数所需要的参数,参数可以是0个,也可以是多个,参数之间要用逗号分隔。</li><li>函数执行的代码块,即函数体。</li><li>返回值语句return,函数通常都会有返回值,如果某个函数没有显式的返回值,默认返回值为undefined。</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">1 function sum(number1,number2) {</span><br><span class="line">2 var sum = number1 + number2;</span><br><span class="line">3 return sum;</span><br><span class="line">4 }</span><br></pre></td></tr></table></figure><h2 id="3-如何去调用函数?"><a href="#3-如何去调用函数?" class="headerlink" title="3.如何去调用函数?"></a>3.如何去调用函数?</h2><p> 在明白了函数的组成部分后,我们就可以成功创建函数了。不过这只是第一步,在我们创建函数之后要想去使用函数还需去调用函数,因为函数不调用的话是不会执行的。</p><p> 调用函数的方法是在函数名加传递参数的括号即可。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">function sum(number1,number2) {</span><br><span class="line"> var sum = number1 + number2;</span><br><span class="line"> return sum;</span><br><span class="line">}</span><br><span class="line">var result = sum(5,4);</span><br><span class="line">console.log(result); //9</span><br></pre></td></tr></table></figure><h2 id="4-关于函数中的参数"><a href="#4-关于函数中的参数" class="headerlink" title="4.关于函数中的参数"></a>4.关于函数中的参数</h2><p> 定义函数的时候我们可能会设置函数所需要的调用参数,这个参数的设定不是必须的,可以选择不设定。如果设定了调用参数,在调用函数的时候就必须要传递相关的参数值,程序才能正常执行。如果没有传递相关的参数值,未被传递参数值的地方就会默认为undefined。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">//函数中设置了调用参数但是在调用函数的过程中并未去传递相关参数值导致的结果。</span><br><span class="line">function sum1(number) {</span><br><span class="line"> return number;</span><br><span class="line">}</span><br><span class="line">var result1 = sum1();</span><br><span class="line">console.log(result1); //undefined</span><br><span class="line"></span><br><span class="line">//函数中漏传参数导致参数+undefined得到NaN。</span><br><span class="line">function sum2(number1,number2) {</span><br><span class="line"> return number1 + number2;</span><br><span class="line">}</span><br><span class="line">var result2 = sum2(1);</span><br><span class="line">console.log(result2); //NaN</span><br></pre></td></tr></table></figure><p> 参数分为<strong>形式参数</strong>和<strong>实际参数</strong>两种,其中形式参数是指定义函数时所用到的参数,实际参数是指在调用函数时所传递的参数。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">function sum(number1,number2) {</span><br><span class="line"> var sum = number1 + number2;</span><br><span class="line"> return sum;</span><br><span class="line">}</span><br><span class="line">var result = sum(5,4,3,2,1); //JavaScript只会解析5和4这两个值,最后输出结果9,其它会被忽略</span><br><span class="line">console.log(result);</span><br></pre></td></tr></table></figure><p> 不过我们可以使用arguments变量在函数中去调用并返回接受的所有参数,arguments变量是内建变量,在每个函数中都能调用。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">function args() {</span><br><span class="line"> return arguments;</span><br><span class="line">}</span><br><span class="line">var result = args(5,4,3,2,1,true,"A",'b');</span><br><span class="line">//Arguments(8) [5, 4, 3, 2, 1, true, "A", "b", callee: ƒ,Symbol(Symbol.iterator): ƒ]</span><br><span class="line">console.log(result);</span><br></pre></td></tr></table></figure><p> 通过arguments可以对参数进行求和运算。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">function sum() {</span><br><span class="line"> var result = 0;</span><br><span class="line"> for(var i = 0 ; i < arguments.length ; i++) {</span><br><span class="line"> result += arguments[i];</span><br><span class="line"> }</span><br><span class="line"> return result;</span><br><span class="line">}</span><br><span class="line">var res = sum(5,4,3,2,1);</span><br><span class="line">console.log(res); //15</span><br></pre></td></tr></table></figure><h1 id="二、parseInt"><a href="#二、parseInt" class="headerlink" title="二、parseInt()"></a>二、parseInt()</h1><p> parseInt()会将接收到任何输入值转换为整数类型输出,通常都是输入字符串,转换失败则返回NaN。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"> 1 var a = parseInt("5a7b6");</span><br><span class="line"> 2 console.log(a); //5</span><br><span class="line"> 3 var b = parseInt("1024");</span><br><span class="line"> 4 console.log(b); //1024</span><br><span class="line"> 5 var c = parseInt("abc1024");</span><br><span class="line"> 6 console.log(c); //NaN</span><br><span class="line"> 7 var d = parseInt("3.14");</span><br><span class="line"> 8 console.log(d); //3</span><br><span class="line"> 9 var e = parseInt("0124");</span><br><span class="line">10 console.log(e); //124</span><br><span class="line">11 var f = parseInt("0x1024");</span><br><span class="line">12 console.log(f); //4132</span><br></pre></td></tr></table></figure><p> parseInt(string,radix)中可以传两个值,第一个值可以解析的是字符串,第二个值解析的是数字的基数,即设定函数所要被解析的数据类型,其中可以传递的进制值范围在2~36之间,如果以”0x”开头第二参数则默认指定为16进制数。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">1 var a = parseInt("0x1024");</span><br><span class="line">2 console.log(a); //4132</span><br></pre></td></tr></table></figure><p> <strong>注意:在这个函数的应用过程中我们会发现一个很有趣的现象,如果以“0x”开头的数字第二参数默认指定为16进制数,那么按道理以“0”开头的数字第二参数应该会被默认指定为8进制数,但是在现实中并不是这样的。如果我们使用parseInt()函数反而得不到这个结果,以“0”开头的数字最终会忽略0而被解析0后面的数字为10进制的数值。因为ECMAScript5移除了8进制的默认表示法,这种做法是避免了在8进制解析和10进制解析时候的混淆。</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">1 var a = parseInt("0124");</span><br><span class="line">2 console.log(a); //124</span><br></pre></td></tr></table></figure><h1 id="三、parseFloat"><a href="#三、parseFloat" class="headerlink" title="三、parseFloat()"></a>三、parseFloat()</h1><p> 上面我们学习了parseInt()的使用,parseFloat()的使用与parseInt()是基本相同的,区别在于parseFloat()只能将输入值转换为十进制数,所以这个函数只能传入一个参数。而且parseFloat()解析的字符串返回的是一个浮点数。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">1 var a = parseFloat("3.14a");</span><br><span class="line">2 console.log(a); //3.14</span><br><span class="line">3 var b = parseFloat("3.14");</span><br><span class="line">4 console.log(b); //3.14</span><br><span class="line">5 var c = parseFloat("1.230800");</span><br><span class="line">6 console.log(c); //1.2308</span><br><span class="line">7 var d = parseFloat("ab12c");</span><br><span class="line">8 console.log(d); //NaN</span><br></pre></td></tr></table></figure><p> parseFloat()可以接受指数形式的数据。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">1 var a = parseFloat("123e-2");</span><br><span class="line">2 console.log(a); //1.23</span><br><span class="line">3 var b = parseFloat("1e5");</span><br><span class="line">4 console.log(b); //100000</span><br></pre></td></tr></table></figure><h1 id="四、isNaN"><a href="#四、isNaN" class="headerlink" title="四、isNaN()"></a>四、isNaN()</h1><p> 使用isNaN()函数可用于检查参数是否是非数字值。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">1 console.log(isNaN(1024)); //false</span><br><span class="line">2 console.log(isNaN(-1024)); //false</span><br><span class="line">3 console.log(isNaN(1.024)); //false</span><br><span class="line">4 console.log(isNaN(-1.024)); //false</span><br><span class="line">5 console.log(isNaN(2024-2)); //false</span><br><span class="line">6 console.log(isNaN(0)); //false</span><br><span class="line">7 console.log(isNaN("JavaScript")); //true</span><br><span class="line">8 console.log(isNaN("2021/01/01")); //true</span><br></pre></td></tr></table></figure><p> 使用isNaN()函数可以检测parseInt()和parseFloat()是否成功调用。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"> 1 var a = isNaN(parseInt("0x1024"));</span><br><span class="line"> 2 console.log(a); //false</span><br><span class="line"> 3 var b = isNaN(parseFloat("1.1"));</span><br><span class="line"> 4 console.log(b); //false</span><br><span class="line"> 5 var c = isNaN(parseInt("1.2"));</span><br><span class="line"> 6 console.log(c); //false</span><br><span class="line"> 7 var d = isNaN(parseInt("ac1024"));</span><br><span class="line"> 8 console.log(d); //true</span><br><span class="line"> 9 var e = isNaN(parseFloat("ac1024"));</span><br><span class="line">10 console.log(e); //true</span><br></pre></td></tr></table></figure><p> 值得一提的是,NaN自己不存在等值的概念,所以NaN == NaN返回的是false。</p><h1 id="五、isFinite"><a href="#五、isFinite" class="headerlink" title="五、isFinite()"></a>五、isFinite()</h1><p> isFinite()可以检查输入的是否是一个非Infifnity非NaN的数字。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">1 console.log(isFinite(Infinity)); //false</span><br><span class="line">2 console.log(isFinite(-Infinity)); //false</span><br><span class="line">3 console.log(isFinite(1024)); //true</span><br><span class="line">4 console.log(isFinite(1e308)); //true</span><br><span class="line">5 console.log(isFinite(-1e308)); //true</span><br><span class="line">6 console.log(isFinite(1e309)); //false</span><br><span class="line">7 console.log(isFinite(-1e309)); //false</span><br></pre></td></tr></table></figure><h1 id="六、eval"><a href="#六、eval" class="headerlink" title="六、eval()"></a>六、eval()</h1><p> eval()函数会将输入的字符串当做JavaScript代码执行。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">eval('var a = 1;');</span><br><span class="line">console.log(a); //1</span><br></pre></td></tr></table></figure><h1 id="七、变量的作用域"><a href="#七、变量的作用域" class="headerlink" title="七、变量的作用域"></a>七、变量的作用域</h1><p> 在JavaScript中,变量的作用域是以函数作为作用域的,即变量如果是在某个函数定义的,该变量在函数以外的地方是不可见的。如果该变量是定义在if或者for这样的代码块中,它在代码块之外是可见的。定义在所有函数之外的变量是全局变量,定义在函数中的变量是局部变量。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"> 1 var number1 = 1;</span><br><span class="line"> 2 function f() {</span><br><span class="line"> 3 var number2 = 4;</span><br><span class="line"> 4 number1++;</span><br><span class="line"> 5 console.log(number2); //4</span><br><span class="line"> 6 return number1;</span><br><span class="line"> 7 }</span><br><span class="line"> 8 console.log(number1); //1</span><br><span class="line"> 9 var result = f();</span><br><span class="line">10 console.log(result); //2</span><br><span class="line">11 console.log(number2); //Uncaught ReferenceError: number2 is not defined</span><br></pre></td></tr></table></figure><p> 由以上示例可以看出函数f()可以访问number1,number1是全局变量,而在函数体外number2无法被访问,因为number2是局部变量,局部变量只能在本函数中被访问。<br> 但是,在JavaScript中总有一些令人比较惊讶的现象。如果在声明变量的时候没有去使用关键字变量去定义相关变量的话,该变量会被默认为全局变量。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">1 var number1 = 1;</span><br><span class="line">2 function f() {</span><br><span class="line">3 number2 = 2;</span><br><span class="line">4 }</span><br><span class="line">5 f();</span><br><span class="line">6 console.log(number2); //2</span><br></pre></td></tr></table></figure><h1 id="八、匿名函数"><a href="#八、匿名函数" class="headerlink" title="八、匿名函数"></a>八、匿名函数</h1><p> 没有名字的函数被称为匿名函数。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">1 var a = function() {</span><br><span class="line">2 return 2;</span><br><span class="line">3 }</span><br><span class="line">4 var b = function(x) {</span><br><span class="line">5 return x;</span><br><span class="line">6 }</span><br></pre></td></tr></table></figure><p> 形如以上的示例就是匿名函数。当匿名函数不被赋值给变量去单独使用的时候,这类函数有两种用法:</p><ul><li>可以将匿名函数作为参数传递给其它函数,这样接收方函数可以利用传递的函数完成某些事情。</li><li>可以去定义某个匿名函数执行某些一次性任务。</li><li>在后面的内容中我们会用到这些用法。</li></ul><h1 id="九、回调函数"><a href="#九、回调函数" class="headerlink" title="九、回调函数"></a>九、回调函数</h1><h2 id="1-回调函数与匿名回调函数"><a href="#1-回调函数与匿名回调函数" class="headerlink" title="1.回调函数与匿名回调函数"></a>1.回调函数与匿名回调函数</h2><p> 函数A传递给函数B,函数B来执行函数A的时候,A就是一个回调函数。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">1 function sum(a) {</span><br><span class="line">2 return a();</span><br><span class="line">3 }</span><br><span class="line">4 var result = sum( </span><br><span class="line">5 function() {</span><br><span class="line">6 return 1;</span><br><span class="line">7 }</span><br><span class="line">8 ); </span><br><span class="line">9 console.log(result); //1</span><br></pre></td></tr></table></figure><p> 也可以使用回调函数进行进行加法运算。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"> 1 function sum(a,b,c) {</span><br><span class="line"> 2 return a() + b() + c();</span><br><span class="line"> 3 }</span><br><span class="line"> 4 var result = sum(</span><br><span class="line"> 5 </span><br><span class="line"> 6 function() {</span><br><span class="line"> 7 return 1;</span><br><span class="line"> 8 },</span><br><span class="line"> 9 function() {</span><br><span class="line">10 return 2.5;</span><br><span class="line">11 },</span><br><span class="line">12 function() {</span><br><span class="line">13 return 3;</span><br><span class="line">14 }</span><br><span class="line">15 ); </span><br><span class="line">16 console.log(result); //6.5</span><br></pre></td></tr></table></figure><p> 我们看到这两个示例中在调用sum的时候都是使用了匿名函数,而且这些匿名函数也是一个回调函数,这样的函数我们称之为匿名回调函数。</p><h2 id="2-什么情况下使用回调函数?"><a href="#2-什么情况下使用回调函数?" class="headerlink" title="2.什么情况下使用回调函数?"></a>2.什么情况下使用回调函数?</h2><ul><li>在未命名的情况下去传递函数,从而节省变量名的使用。</li><li>将一个函数调用给另一个函数去执行,可以节省一些代码编写工作。</li><li>在数据量很大的情况下使用回调函数是一个好的选择。</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"> 1 function sum(a,b,c,returnValue) {</span><br><span class="line"> 2 var array = [];</span><br><span class="line"> 3 for(var i = 0;i < 3;i++) {</span><br><span class="line"> 4 array[i] = returnValue(arguments[i] * 2);</span><br><span class="line"> 5 }</span><br><span class="line"> 6 return array;</span><br><span class="line"> 7 }</span><br><span class="line"> 8 </span><br><span class="line"> 9 var result = sum(1,2,3,function(a) {</span><br><span class="line">10 return a + 1;</span><br><span class="line">11 });</span><br><span class="line">12 </span><br><span class="line">13 console.log(result); //[3, 5, 7]</span><br></pre></td></tr></table></figure><h1 id="十、即时函数"><a href="#十、即时函数" class="headerlink" title="十、即时函数"></a>十、即时函数</h1><p> 可以在被定义后<strong>立即调用</strong>的函数是即时函数。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">1 (</span><br><span class="line">2 function() {</span><br><span class="line">3 console.log('JavaScript'); //JavaScript</span><br><span class="line">4 }</span><br><span class="line">5 )();</span><br></pre></td></tr></table></figure><p> <strong>括号也可以放在第二对括号之后。</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">1 (</span><br><span class="line">2 function(message) {</span><br><span class="line">3 console.log('Hello ' + message); //Hello JavaScript</span><br><span class="line">4 }</span><br><span class="line">5 ('JavaScript'));</span><br></pre></td></tr></table></figure><p> 使用匿名函数的好处是不会产生任何全局变量。缺点是在于这样的函数是无法重复执行的,这也使即时函数非常适合于去执行一些一次性的或初始化的任务。</p><h1 id="十一、内部函数"><a href="#十一、内部函数" class="headerlink" title="十一、内部函数"></a>十一、内部函数</h1><h2 id="1-什么是内部函数?"><a href="#1-什么是内部函数?" class="headerlink" title="1.什么是内部函数?"></a>1.什么是内部函数?</h2><p> 在一个函数内部定义另一个函数,内部定义的函数就被称为内部函数,内部函数也叫做私有函数,只能在内部去访问。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">1 function outer(param) {</span><br><span class="line">2 </span><br><span class="line">3 function inner(theinput) {</span><br><span class="line">4 return theinput * 2;</span><br><span class="line">5 }</span><br><span class="line">6 return 'The result is ' + inner(param);</span><br><span class="line">7 }</span><br><span class="line">8 </span><br><span class="line">9 console.log(outer(2)); //The result is 4</span><br></pre></td></tr></table></figure><h2 id="2-私有函数的特点"><a href="#2-私有函数的特点" class="headerlink" title="2.私有函数的特点"></a>2.私有函数的特点</h2><ul><li>确保全局名字空间的唯一性,以免命名冲突。</li><li>确保一些函数的私有性,做到只将一部分必要的函数暴露在外,具有一定的安全性。</li></ul><h1 id="十二、返回函数的函数"><a href="#十二、返回函数的函数" class="headerlink" title="十二、返回函数的函数"></a>十二、返回函数的函数</h1><p> 返回函数的函数听起来有些奇怪,不过细细想一想的话就是在一个函数中的返回值也是一个函数,这就是返回函数的函数。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"> 1 function a() {</span><br><span class="line"> 2 console.log("Hello");</span><br><span class="line"> 3 return function() {</span><br><span class="line"> 4 console.log("JavaScript");</span><br><span class="line"> 5 }</span><br><span class="line"> 6 }</span><br><span class="line"> 7 var result = a(); //Hello</span><br><span class="line"> 8 result(); //JavaScript</span><br><span class="line"> 9 </span><br><span class="line">10 //也可以这样去输出,结果是相同的</span><br><span class="line">11 //a()(); //Hello</span><br><span class="line">12 //JavaScript</span><br></pre></td></tr></table></figure><h1 id="十三、函数可以被重写"><a href="#十三、函数可以被重写" class="headerlink" title="十三、函数可以被重写"></a>十三、函数可以被重写</h1><p> 还是上面的例子,我们可以使用新的函数去覆盖旧的函数,我们在函数内部去重写函数覆盖外部的函数。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">1 function a() {</span><br><span class="line">2 alert("Hello");</span><br><span class="line">3 b = function() {</span><br><span class="line">4 alert("JavaScript");</span><br><span class="line">5 }</span><br><span class="line">6 }</span><br><span class="line">7 a(); //Hello</span><br><span class="line">8 b(); //JavaScript</span><br></pre></td></tr></table></figure><h1 id="十四、闭包"><a href="#十四、闭包" class="headerlink" title="十四、闭包"></a>十四、闭包</h1><p> 在看闭包之前先看一个示例:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"> 1 function sum(number) {</span><br><span class="line"> 2 var all = 0;</span><br><span class="line"> 3 return all += number;</span><br><span class="line"> 4 }</span><br><span class="line"> 5 </span><br><span class="line"> 6 console.log(sum(1)); //1</span><br><span class="line"> 7 console.log(sum(1)); //1</span><br><span class="line"> 8 console.log(sum(1)); //1</span><br><span class="line"> 9 console.log(sum(1)); //1</span><br><span class="line">10 console.log(sum(2)); //2</span><br><span class="line">11 console.log(sum(2)); //2</span><br><span class="line">12 console.log(sum(3)); //3</span><br></pre></td></tr></table></figure><p> 上面的示例中我们如果不改变传入函数的数值无论是调用多少次最终的结果就不会被改变,在某些应用场景下这是极其不方便的,这时候就引入了闭包。在使用闭包的时候,我们可以在反复调用的过程中去不停的进行值的改变。在实际中我们可以以日常多开网站去举例。<br> 我们日常可能会多开好几个网站,每个网站我们可能会在同一个浏览器上打开好几个,在我们打开同一个浏览器好几个页面的时候会占用内存空间,几个页面运行的过程中可以看做是反复调用函数,这个过程中我们在同一个浏览器去打开多个页面的时候每次打开的页面都和我们上次打开的页面不同,这个过程细化过来我们可以将其看做是闭包,是调用函数且还占用内存去执行并变化的过程,变量会一直保留在内存中,所以我们在最小化浏览器页面后浏览器并未被关闭,内存依然会被占用。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"> 1 function sum(number) {</span><br><span class="line"> 2 var all = 0;</span><br><span class="line"> 3 return function() {</span><br><span class="line"> 4 all += 1;</span><br><span class="line"> 5 return all;</span><br><span class="line"> 6 }</span><br><span class="line"> 7 }</span><br><span class="line"> 8 </span><br><span class="line"> 9 var storage = sum();</span><br><span class="line">10 console.log(storage()); //1</span><br><span class="line">11 console.log(storage()); //2</span><br><span class="line">12 console.log(storage()); //3</span><br><span class="line">13 console.log(storage()); //4</span><br></pre></td></tr></table></figure><p> 从上面的示例可以明白闭包是创建一个函数,用一些变量<strong>包装</strong>起来,之后再保存起来去使用,而函数保留对其作用域访问的过程我们就称之为闭包。<br> 当然,每次在定义函数的时候都会为函数创建闭包,所以我们可以说每个函数都有闭包。<strong>但是,只有我们在使用嵌套函数的时候闭包的功能才能真正发挥出来</strong>。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"> 1 var number = 1;</span><br><span class="line"> 2 function sum1() {</span><br><span class="line"> 3 var number = 4; //覆盖了上面的number</span><br><span class="line"> 4 </span><br><span class="line"> 5 function sum2() {</span><br><span class="line"> 6 console.log("这个数字为:" + number); //sum2()函数和其中的语法形成了一个闭包,引用的sum1()中局部声明的number变量。</span><br><span class="line"> 7 }</span><br><span class="line"> 8 return sum2();</span><br><span class="line"> 9 }</span><br><span class="line">10 sum1(); //这个数字为:4</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p> 无论是什么程序设计语言,函数都是重要的一部分内容,在实际开发过程中有很多语法的表达和功能的实现都来源于函数。不过与其它语言不同的是,JavaScript是通过函数来实现面向对象的特性并非通过专门的面向对象语法去实现的,因为JavaScript没有属于自己的专门的面向对象语法,所以函数在JavaScript中更是重中之重。</p></summary>
<category term="前端" scheme="https://codemariosec.github.io/categories/%E5%89%8D%E7%AB%AF/"/>
<category term="JavaScript" scheme="https://codemariosec.github.io/tags/JavaScript/"/>
</entry>
<entry>
<title>Web前端_JavaScript的Day2_基本数据类型、数组、循环及条件表达式</title>
<link href="https://codemariosec.github.io/2022/01/31/Web%E5%89%8D%E7%AB%AF-JavaScript%E7%9A%84Day2-%E5%9F%BA%E6%9C%AC%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E3%80%81%E6%95%B0%E7%BB%84%E3%80%81%E5%BE%AA%E7%8E%AF%E5%8F%8A%E6%9D%A1%E4%BB%B6%E8%A1%A8%E8%BE%BE%E5%BC%8F/"/>
<id>https://codemariosec.github.io/2022/01/31/Web%E5%89%8D%E7%AB%AF-JavaScript%E7%9A%84Day2-%E5%9F%BA%E6%9C%AC%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E3%80%81%E6%95%B0%E7%BB%84%E3%80%81%E5%BE%AA%E7%8E%AF%E5%8F%8A%E6%9D%A1%E4%BB%B6%E8%A1%A8%E8%BE%BE%E5%BC%8F/</id>
<published>2022-01-30T17:55:17.000Z</published>
<updated>2022-06-03T06:53:12.966Z</updated>
<content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>这部分内容主要介绍了JavaScript中基本数据类型、数组的基础知识、循环的常规应用以及表达式。</p><span id="more"></span><h1 id="变量"><a href="#变量" class="headerlink" title="变量"></a>变量</h1><h2 id="1-什么是变量?"><a href="#1-什么是变量?" class="headerlink" title="1.什么是变量?"></a>1.什么是变量?</h2><p>变量是用来存储数据的,是存放具体数值的容器。</p><h2 id="2-变量的命名规范"><a href="#2-变量的命名规范" class="headerlink" title="2.变量的命名规范"></a>2.变量的命名规范</h2><p>变量名可以由字母、数字、下划线及美元符号组成,但是不能以数字开头。</p><h2 id="3-变量的使用"><a href="#3-变量的使用" class="headerlink" title="3.变量的使用"></a>3.变量的使用</h2><ul><li>先声明变量后初始化变量。</li><li>可以声明变量同时并初始化变量。</li></ul><p><strong>注意:变量名是区分大小写的。</strong></p><h1 id="操作符"><a href="#操作符" class="headerlink" title="操作符"></a>操作符</h1><h2 id="1-什么是变量?-1"><a href="#1-什么是变量?-1" class="headerlink" title="1.什么是变量?"></a>1.什么是变量?</h2><p>变量是用来存储数据的,是存放具体数值的容器。</p><h2 id="2-基本的算术运算符"><a href="#2-基本的算术运算符" class="headerlink" title="2.基本的算术运算符"></a>2.基本的算术运算符</h2><p>变量是用来存储数据的,是存放具体数值的容器。</p><table><thead><tr><th><strong>操作符</strong></th><th><strong>相关操作</strong></th><th><strong>代码示例</strong></th></tr></thead><tbody><tr><td>+</td><td>加法操作</td><td>1 + 2</td></tr><tr><td>-</td><td>减法操作</td><td>2 - 1</td></tr><tr><td>*</td><td>乘法操作</td><td>1 * 2</td></tr><tr><td>/</td><td>除法操作</td><td>2 / 1</td></tr><tr><td>%</td><td>取模操作</td><td>2 % 2</td></tr><tr><td>++</td><td>自增1运算</td><td><strong>前置++操作先自增加1再返回加过后的值</strong>var a = 1;var b = ++a;b = 2a = 2<strong>后置++操作先返回原来的值再自增加1</strong>var a = 1;var b = a++;b = 1 a = 2</td></tr><tr><td>–</td><td>自减1运算</td><td><strong>前置–操作先自减减1再返回加过后的值</strong>var a = 2;var b = –a;b = 1a = 1<strong>后置–操作先返回原来的值再自减减1</strong>var a = 2;var b = a–;b = 2a = 1</td></tr></tbody></table><h2 id="3-复合操作运算符"><a href="#3-复合操作运算符" class="headerlink" title="3.复合操作运算符"></a>3.复合操作运算符</h2><table><thead><tr><th>操作符</th><th>代码示例</th><th>代码变形</th></tr></thead><tbody><tr><td>+=</td><td>var a = 1;a += 1;console.log(a); a = 2</td><td>var a = 1;a = a + 1;console.log(a);a = 2</td></tr><tr><td>-=</td><td>var a = 1;a -= 1;console.log(a);a = 0</td><td>var a = 1;a = a - 1;console.log(a);a = 0</td></tr><tr><td>*=</td><td>var a = 1;a *= 2;console.log(a);a = 2</td><td>var a = 1;a = a * 2;console.log(a);a = 2</td></tr><tr><td>/=</td><td>var a = 2;a /= 2;console.log(a);a = 1</td><td>var a = 2;a = a / 2;console.log(a);a = 1</td></tr><tr><td>%=</td><td>var a = 2;a %= 2;console.log(a);a = 0</td><td>var a = 2;a = a % 2;console.log(a);a = 0</td></tr></tbody></table><h1 id="操作符-1"><a href="#操作符-1" class="headerlink" title="操作符"></a>操作符</h1><p>JavaScript中包含以下几大基本数据类型:</p><p>数字型——包括整数和浮点数,例如:1、1.1、3.14。<br>字符串型——包括由任意字符组成的序列,例如:“a”、“one 2 two”。<br>布尔型——只有两种形式,true和false。<br>undefined——没有值的变量,当我们去访问这种并不存在的变量时,会得到这个特殊值undefined。<br>null——表示没有值或空值。在JavaScript中,null的数据类型是对象。</p><h2 id="1-typeof操作符"><a href="#1-typeof操作符" class="headerlink" title="1.typeof操作符"></a>1.typeof操作符</h2><p>使用typeof我们能够知道返回某个变量或值的类型是什么,该操作符的返回结果可能是:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">1 console.log(typeof null); //Object</span><br><span class="line">2 console.log(typeof 10); //number</span><br><span class="line">3 console.log(typeof "a"); //string</span><br><span class="line">4 console.log(typeof '10'); //string</span><br><span class="line">5 console.log(typeof true); //boolean</span><br><span class="line">6 console.log(typeof function(){}); //function</span><br><span class="line">7 console.log(typeof a); //undefined</span><br><span class="line">8 console.log(typeof undefined); //undefined</span><br></pre></td></tr></table></figure><p>所以在JavaScript中使用typeof操作符返回的结果是:</p><ul><li>“number”;</li><li>“string”;</li><li>“boolean”;</li><li>“undefined”;</li><li>“object”;</li><li>“function”</li></ul><p><strong>注意:</strong></p><p>当八进制和十六进制的数字使用typeof操作符时返回的结果是number类型。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">1 console.log(typeof 0377); //八进制返回"number"</span><br><span class="line">2 console.log(typeof 0xff); //十六进制返回"number"</span><br></pre></td></tr></table></figure><p>当使用指数去表示的时候返回的是number类型</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">1 //2e1和2e+1是指数的两种表示方法</span><br><span class="line">2 console.log(typeof 2e1); //number</span><br><span class="line">3 console.log(typeof 2e+1); //number</span><br></pre></td></tr></table></figure><p>使用typeof操作符返回Infinity和-Infinity的结果也是number</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">1 console.log(typeof Infinity); //number</span><br><span class="line">2 console.log(typeof -Infinity); //number</span><br></pre></td></tr></table></figure><p>使用typeof操作符返回NaN的结果也是number</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">1 console.log(typeof NaN);</span><br></pre></td></tr></table></figure><h2 id="2-数字型"><a href="#2-数字型" class="headerlink" title="2.数字型"></a>2.数字型</h2><h3 id="1-Infinity"><a href="#1-Infinity" class="headerlink" title="1.Infinity"></a>1.Infinity</h3><p>在JavaScript中,超出处理范围的数值用Infinity这个特殊值来表示。例如当我们向控制台输出1e308时,返回结果正常,而向控制台再输出1e309的时候就超出范围了,所以会返回Infinity,其中如果超出最大值就是返回Infinity,如果超出最小值就返回-infinity。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">1 console.log(1e308); //1e+308</span><br><span class="line">2 console.log(1e309); //Infinity</span><br><span class="line">3 console.log(-1e309); //-Infinity</span><br></pre></td></tr></table></figure><p><strong>Infinity和-Infinity相加得到的不是0而是NaN,Infinity-Infinity得到的也是NaN而并非0,实际上二者都一样。</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">1 console.log(-Infinity + Infinity); //NaN</span><br><span class="line">2 console.log(Infinity - Infinity); //NaN</span><br></pre></td></tr></table></figure><p><strong>Infinity和数字执行除了取模以外的运算得到的结果都是Infinity,取模运算得到的是NaN。</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">1 console.log(Infinity + 10); //Infinity</span><br><span class="line">2 console.log(Infinity - 10); //Infinity</span><br><span class="line">3 console.log(Infinity * 10); //Infinity</span><br><span class="line">4 console.log(Infinity / 10); //Infinity</span><br><span class="line">5 console.log(Infinity % 10); //NaN</span><br></pre></td></tr></table></figure><h3 id="2-NaN"><a href="#2-NaN" class="headerlink" title="2.NaN"></a>2.NaN</h3><p>虽然NaN代表的是<strong>不是数字</strong>,但是正如我们在上面typeof中使用typeof操作符的时候一样,返回的值的类型也是数字类型,所以NaN是一种特殊的数字。</p><p><strong>注意:</strong></p><ul><li><strong>如果我们计算1 + “a”得到的结果是1a这个拼接后的字符串,但是如果我们使用的是其它的几个算术运算符的话返回的结果是NaN,因为这是错误的运算方式,返回的结果不会是一个数字。</strong></li><li><strong>如果我们在算术运算中将NaN算进去的话,整个运算得到的结果也是NaN。</strong></li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">1 console.log(1 + "a"); //1a</span><br><span class="line">2 console.log(1 - "a"); //NaN</span><br><span class="line">3 console.log(1 * "a"); //NaN</span><br><span class="line">4 console.log(1 / "a"); //NaN</span><br><span class="line">5 console.log(1 % "a"); //NaN</span><br><span class="line">6 console.log(1 + 2 + NaN + 3); //NaN</span><br></pre></td></tr></table></figure><h3 id="3-字符串型"><a href="#3-字符串型" class="headerlink" title="3.字符串型"></a>3.字符串型</h3><p>字符串通常表示的是某段表示文本的字符序列。和某些语言不同的是,JavaScript语言中一对单引号或双引号之间的任何值都是一个字符串,有些编程语言单引号只能是表示字符,双引号表示字符串。所以在JavaScript中,’1’和”1”表示的都是字符串。字符串使用typeof操作符会返回string这个结果。</p><h4 id="1-字符串的表示"><a href="#1-字符串的表示" class="headerlink" title="1.字符串的表示"></a>1.字符串的表示</h4><ul><li>在JavaScript中字符串可以用单引号表示也可以用双引号表示。</li><li>字符串可以是引号中的零个或多个字符。</li><li>字符串可以是带单引号或双引号的任何值。</li><li>字符串之间可以使用加号运算符进行拼接,拼接后得到的新的字符串依然是字符串类型。</li></ul><h4 id="2-字符串类型和其它类型之间的相互转换"><a href="#2-字符串类型和其它类型之间的相互转换" class="headerlink" title="2.字符串类型和其它类型之间的相互转换"></a>2.字符串类型和其它类型之间的相互转换</h4><p>布尔型转字符串型<br><strong>通过a布尔类型与字符串使用加号运算符拼接将a由布尔类型转换为字符串类型。</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">1 var a = true;</span><br><span class="line">2 var b = "";</span><br><span class="line">3 var c = a + b;</span><br><span class="line">4 console.log(c); //true</span><br><span class="line">5 console.log(typeof c); //string</span><br></pre></td></tr></table></figure><p>字符串型转数字型<br><strong>通过字符串类型和数字类型使用乘号运算符拼接得到的是数字类型。</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">1 var a = "";</span><br><span class="line">2 var b = 1;</span><br><span class="line">3 var c = a * b;</span><br><span class="line">4 console.log(c); //1</span><br><span class="line">5 console.log(typeof c); //number</span><br></pre></td></tr></table></figure><p><strong>通过Number()方法返回数字,将字符串类型值转换为数字类型值。</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">1 var a = Number("2021") + 1;</span><br><span class="line">2 console.log(a); //2022</span><br><span class="line">3 console.log(typeof a); //number</span><br></pre></td></tr></table></figure><p><strong>通过parseInt()方法解析一段字符串并返回数值。</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">1 var a = parseInt("5a7b6");</span><br><span class="line">2 console.log(a); //5</span><br><span class="line">3 console.log(typeof a); //number</span><br></pre></td></tr></table></figure><p><strong>注意:parseInt()方法允许空格且只返回首个数字,上面的示例开头数字是5,所以最后返回的数值结果就是5。</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">1 var a = parseInt("1024");</span><br><span class="line">2 console.log(a); //1024</span><br><span class="line">3 console.log(typeof a); //number</span><br></pre></td></tr></table></figure><p><strong>所以说如果parseInt()方法中解析的字符串首字母不是数字的话返回的值就是NaN。</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">1 var a = parseInt("3.14");</span><br><span class="line">2 console.log(a); //3</span><br><span class="line">3 console.log(typeof a); //number</span><br></pre></td></tr></table></figure><p><strong>通过parseFloat()方法解析一段字符串并返回数值。</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">1 var a = parseFloat("3.14a");</span><br><span class="line">2 console.log(a); //3.14</span><br><span class="line">3 console.log(typeof a); //number</span><br></pre></td></tr></table></figure><p><strong>注意:parseFloat()方法允许空格且只返回首个数字,上面的示例开头数字是3.14,所以最后返回的数值结果就是3.14。</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">1 var a = parseFloat("3.14");</span><br><span class="line">2 console.log(a); //3.14</span><br><span class="line">3 console.log(typeof a); //number</span><br></pre></td></tr></table></figure><p><strong>所以说如果parseFloat()方法中解析的字符串首字母不是数字的话返回的值就是NaN。</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">1 var a = parseFloat("ab12c");</span><br><span class="line">2 console.log(a); //NaN</span><br><span class="line">3 console.log(typeof a); //number</span><br></pre></td></tr></table></figure><p>数字型转字符串型<br><strong>通过字符串类型和数字类型进行拼接将数字类型的值转换为字符串类型值。</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">1 var a = '';</span><br><span class="line">2 var b = 1;</span><br><span class="line">3 var c = a + b;</span><br><span class="line">4 console.log(c); //1</span><br><span class="line">5 console.log(typeof c); //string</span><br></pre></td></tr></table></figure><h4 id="3-字符串拼接"><a href="#3-字符串拼接" class="headerlink" title="3.字符串拼接"></a>3.字符串拼接</h4><p><strong>字符串与字符串拼接得到的结果还是字符串类型。</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">1 var a = 'java';</span><br><span class="line">2 var b = "script";</span><br><span class="line">3 var c = a + b;</span><br><span class="line">4 console.log(c); //javascript</span><br><span class="line">5 console.log(typeof c); //string</span><br></pre></td></tr></table></figure><h4 id="4-常用特殊字符串"><a href="#4-常用特殊字符串" class="headerlink" title="4.常用特殊字符串"></a>4.常用特殊字符串</h4><table><thead><tr><th align="center">字符串</th><th align="center">含义</th><th align="center">示例</th></tr></thead><tbody><tr><td align="center">\ ' '‘</td><td align="center">\是转义字符,当我们 想要在字符串中去使用 引号的时候需要用到 这个字符,使用这个字 符对引号进行转义最终 输出的结果才是正常的结 果,否则JavaScript 可能会将相同的引号匹 配错误从而造成值的截断。 当然,我们在字符串中 使用\本身的时候也需要使用另一个\将\本 身进行转义,否则JavaScript 会认为\本体是一个转义字符。</td><td align="center">var a = ‘I don’t konw’;以上的做法是错误的,因为JavaScript会将”I don’t”视为字符串,而其余部分则是无效代码,从而截断了后面的部分,我们应该是这样去做: var a = ‘I don't know’;var a = “I don’t know”;var a = ‘“Hello”,World’;var a = “"Hello",World”;</td></tr><tr><td align="center">\n</td><td align="center">换行符</td><td align="center">var a = ‘\n1\n2\n3\n’;console.log(a);123</td></tr><tr><td align="center">\r</td><td align="center">回车符</td><td align="center">var a = ‘1\r\n2’;console.log(a);”12”</td></tr><tr><td align="center">\t</td><td align="center">制表符</td><td align="center">var a = “1\t2”;console.log(a);”12”</td></tr><tr><td align="center">\u</td><td align="center">\u后面的字符会被视为Unicode码</td><td align="center">下面是作者的名字在保加利亚语中用西里尔字母的拼写:”\u0421\u0442\u043E\u044F\u043D”; “”Стoян””</td></tr></tbody></table><h3 id="4-布尔型"><a href="#4-布尔型" class="headerlink" title="4.布尔型"></a>4.布尔型</h3><p>布尔类型只有true和false两种值,一般作为判断语句去使用。</p><p> 布尔类型在使用typeof操作符的时候返回的值类型是boolean类型。</p><p> 在JavaScript中有三种布尔运算的运算符,分别是:</p><ul><li>!——逻辑非(取反);</li><li>&&——逻辑与;</li><li>||——逻辑或;</li></ul><p>其中,逻辑非代表事物不是真的状态,逻辑与是代表当前事物和操作中所有的一切都是真最终结果才为真,只要有一个不满足就为假,即使是另外的条件满足。逻辑或则是多个条件中其中一个条件满足就为真,只有都为假的时候才能为假。</p><p>以下表列出相应情况</p><table><thead><tr><th align="center">操作</th><th align="center">结果</th></tr></thead><tbody><tr><td align="center">true && true</td><td align="center">true</td></tr><tr><td align="center">true && false</td><td align="center">false</td></tr><tr><td align="center">false && true</td><td align="center">false</td></tr><tr><td align="center">false && false</td><td align="center">false</td></tr><tr><td align="center">true || true</td><td align="center">true</td></tr><tr><td align="center">true || false</td><td align="center">true</td></tr><tr><td align="center">false || true</td><td align="center">true</td></tr><tr><td align="center">false || false</td><td align="center">false</td></tr></tbody></table><p><strong>注意:在或、与、非三个布尔运算符之中优先级为!(非)>&&(或)>||(与)。</strong><br>当然,在JavaScript中,还有另一组以布尔值为返回值类型的操作符,我们称之为比较运算符。</p><table><thead><tr><th align="center">操作符</th><th align="center">操作说明</th><th align="center">代码示例</th></tr></thead><tbody><tr><td align="center">==</td><td align="center">相等运算符,即当两个 操作数相等时返回true, 比较的时候运算符两边 的数值会被自动转换为相同的类型。</td><td align="center">console.log(1 == 1);trueconsole.log(1 == 2);falseconsole.log(1 == ‘1’);true</td></tr><tr><td align="center">===</td><td align="center">严格相等运算符,当两边 的操作数的值和类型都 相同的时候才返回true, 可以说是全等于这类型的。这是一种比较全面可靠的 比较,因为这样的比较 不会出现可能发生的某个操作数 类型转换再比较。</td><td align="center">console.log(1 === 1);trueconsole.log(1 === ‘1’);false</td></tr><tr><td align="center">!=</td><td align="center">不相等运算符,当两边 的操作数不相等的时候 返回true,这种比较是会进行类型转换为 相同类型进行比较。</td><td align="center">console.log(1 != 1);falseconsole.log(1 != ‘1’);falseconsole.log(1 != ‘2’);true</td></tr><tr><td align="center">!==</td><td align="center">严格不相等运算符,当两边 的操作数的值和类型都不相同 的时候才返回true, 可以说是全不等于这类型的。这是一种比较全面可靠的比较, 因为这样的比较不会出现可能发生的某个操作数 类型转换再比较。</td><td align="center">console.log(1 !== 1);falseconsole.log(1 !== ‘1’);true</td></tr><tr><td align="center">></td><td align="center">当符号左边的数大于右边的数的时候返回true。</td><td align="center">1 > 1;false2 > 1;true</td></tr><tr><td align="center">>=</td><td align="center">当符号左边的数大于等于右边的数的时候返回true。</td><td align="center">1 >= 1;true1>= 2;false</td></tr><tr><td align="center"><</td><td align="center">当符号左边的数小于右边的数的时候返回true。</td><td align="center">1 < 1;false1 < 2;true</td></tr><tr><td align="center"><=</td><td align="center">当符号左边的数小于等于右边的数的时候返回true。</td><td align="center">1 <= 1;true2 <= 1;false</td></tr></tbody></table><p><strong>注意:NaN不等于任何东西,哪怕是自己,例如NaN == NaN;返回值也为false。</strong></p><h1 id="数组"><a href="#数组" class="headerlink" title="数组"></a>数组</h1><h2 id="1-什么是数组?"><a href="#1-什么是数组?" class="headerlink" title="1.什么是数组?"></a>1.什么是数组?</h2><p>数组是一个用于存储数据的列表,这个列表可以存放任意数量的元素值。<br><strong>示例:</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">1 var a = [1,2,3];</span><br><span class="line">2 console.log(a); //[1,2,3]</span><br></pre></td></tr></table></figure><p><strong>记住,元素在数组中的索引位置下标是从0开始的,所以数组元素的首个索引值是0,第二个元素索引值是1,以此类推。</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">1 var a = [1,2,3];</span><br><span class="line">2 console.log(a[0]); //1</span><br><span class="line">3 console.log(a[1]); //2</span><br><span class="line">4 console.log(a[2]); //3</span><br></pre></td></tr></table></figure><h2 id="2-数组的特点"><a href="#2-数组的特点" class="headerlink" title="2.数组的特点"></a>2.数组的特点</h2><ul><li>数组是一种数据存储形式。</li><li>数组是可以被索引的。</li><li>数组中的元素索引值是从0开始,按照每个元素的位置去依次递增。</li><li>数组能存储任何类型的数据,包括另一个数组。</li><li>我们可以对数组进行增删改查。</li><li>我们可以通过数组访问的方式去获取字符串中特定位置上的字符。</li></ul><h2 id="3-关于数组元素的增加和更新"><a href="#3-关于数组元素的增加和更新" class="headerlink" title="3.关于数组元素的增加和更新"></a>3.关于数组元素的增加和更新</h2><p>我们可以通过索引去直接增加或者更新数组中的元素,例如:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">1 var a = [1,2,3];</span><br><span class="line">2 a[1] = "two"; //修改元素索引值为1的数</span><br><span class="line">3 a[3] = "four"; //增加元素索引值为3的地方</span><br><span class="line">4 a[5] = "six"; //增加元素索引值为6的地方,索引值为5的地方在控制台上输出的时候是空值</span><br><span class="line">5 console.log(a); //[1, "two", 3, "four", empty, "six"]</span><br></pre></td></tr></table></figure><h2 id="4-关于数组元素的删除"><a href="#4-关于数组元素的删除" class="headerlink" title="4.关于数组元素的删除"></a>4.关于数组元素的删除</h2><p>删除数组中特定的元素我们需要使用delete操作符去实现操作。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">1 var a = [1,2,3];</span><br><span class="line">2 delete a[1];</span><br><span class="line">3 console.log(a); // [1, empty, 3]</span><br></pre></td></tr></table></figure><h2 id="5-利用数组访问字符串"><a href="#5-利用数组访问字符串" class="headerlink" title="5.利用数组访问字符串"></a>5.利用数组访问字符串</h2><p>我们可以通过数组访问的方式去获取字符串中特定位置上的字符。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">1 var a = 'abc';</span><br><span class="line">2 console.log(a[0]); //a</span><br><span class="line">3 console.log(a[1]); //b</span><br><span class="line">4 console.log(a[2]); //c</span><br></pre></td></tr></table></figure><h1 id="条件与循环"><a href="#条件与循环" class="headerlink" title="条件与循环"></a>条件与循环</h1><p>条件与循环是实际开发过程中重要的一部分,通过使用条件我们可以控制一段代码的执行走向,通过循环我们可以重复去执行某段代码。</p><h2 id="1-if条件表达式"><a href="#1-if条件表达式" class="headerlink" title="1.if条件表达式"></a>1.if条件表达式</h2><p>if条件表达式主要由if语句、语句条件、执行的代码块以及代码块内部的执行语句组成。其中语句条件是指逻辑类或者是比较类并返回布尔值类型的操作语句组成。</p><h2 id="2-else语句"><a href="#2-else语句" class="headerlink" title="2.else语句"></a>2.else语句</h2><p>else语句是if语句的可选项,运用于if语句表达式条件返回值为false的时候去执行该部分所包含的语句。</p><p><strong>举个栗子:</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">1 var a = 2;</span><br><span class="line">2 if(a > 2) {</span><br><span class="line">3 console.log("a是一个大于2的数字");</span><br><span class="line">4 } else {</span><br><span class="line">5 console.log("a不是大于2的数字");</span><br><span class="line">6 }</span><br></pre></td></tr></table></figure><p>此外我们还有else if语句,也是if语句的可选项,是分支判断语句,例如:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">1 var a = 2;</span><br><span class="line">2 if(a == 1) {</span><br><span class="line">3 console.log("a = 1");</span><br><span class="line">4 } else if(a == 2) {</span><br><span class="line">5 console.log("a = 2");</span><br><span class="line">6 } else {</span><br><span class="line">7 console.log("a不满足上述条件");</span><br><span class="line">8 }</span><br></pre></td></tr></table></figure><h2 id="3-switch语句"><a href="#3-switch语句" class="headerlink" title="3.switch语句"></a>3.switch语句</h2><p>当if语句中出现过多的else if语句的时候,最好使用switch语句进行条件的判断。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"> 1 var a = 1;</span><br><span class="line"> 2 var result = '';</span><br><span class="line"> 3 switch(a) {</span><br><span class="line"> 4 case 1:</span><br><span class="line"> 5 result = 'Number 1';</span><br><span class="line"> 6 break;</span><br><span class="line"> 7 case 2:</span><br><span class="line"> 8 result = 'Number 2';</span><br><span class="line"> 9 break;</span><br><span class="line">10 default:</span><br><span class="line">11 result = 'Number X';</span><br><span class="line">12 break;</span><br><span class="line">13 }</span><br><span class="line">14 console.log(result);</span><br><span class="line">15 //输出结果:Number 1</span><br></pre></td></tr></table></figure><h3 id="switch语句的组成部分及其作用"><a href="#switch语句的组成部分及其作用" class="headerlink" title="switch语句的组成部分及其作用"></a>switch语句的组成部分及其作用</h3><ul><li>switch子句。</li><li>括号表达式。表达式通常是一个变量,有时候也可以是其它能够提供返回值的东西。</li><li>包含在switch语句大括号中的case序列块。</li><li>每个case语句下的表达式,如果表达式结果与switch语句表达式对比结果为true则case语句冒号之后的代码会被执行。</li><li>break语句是可选的,当代码执行到break语句时,就跳出当前循环结束整个过程的执行。</li><li>default关键字是默认条件代码块,当case条件的语句都不为true的时候,就执行default条件里的语句。</li></ul><h2 id="4-循环"><a href="#4-循环" class="headerlink" title="4.循环"></a>4.循环</h2><p>通过循环语句我们可以使某段代码可以反复执行,便于操作。</p><p>在JavaScript中,循环分为四种类型:</p><ul><li>while循环;</li><li>do-while循环;</li><li>for循环;</li><li>for-in循环。</li></ul><h3 id="1-while循环"><a href="#1-while循环" class="headerlink" title="1.while循环"></a>1.while循环</h3><p>while循环语句分为小括号中的条件和大括号中的代码块,当小括号中的条件为true的时候会执行。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">1 var a = 0;</span><br><span class="line">2 while(a < 10) {</span><br><span class="line">3 a++;</span><br><span class="line">4 }</span><br><span class="line">5 console.log(a);</span><br></pre></td></tr></table></figure><h3 id="2-do-while循环"><a href="#2-do-while循环" class="headerlink" title="2.do-while循环"></a>2.do-while循环</h3><p>do-while循环和while循环没有多大的区别,只不过是do-while循环里的代码块会至少执行一次,先执行,后判断。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">1 var a = 0;</span><br><span class="line">2 do {</span><br><span class="line">3 a++;</span><br><span class="line">4 } while(a < 10);</span><br><span class="line">5 console.log(a);</span><br></pre></td></tr></table></figure><h3 id="3-for循环"><a href="#3-for循环" class="headerlink" title="3.for循环"></a>3.for循环</h3><p>for循环主要包括以下内容:</p><ul><li>初始化部分定义一个循环变量,例如var i = 0;</li><li>条件部分将i与循环边界值进行对比。例如i < 10;</li><li>自增部分将循环变量i自增1,例如i++。</li></ul><p><strong>举个栗子:</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">1 var a = '';</span><br><span class="line">2 for(var i = 0;i < 10;i++) {</span><br><span class="line">3 a = 'Hello World';</span><br><span class="line">4 }</span><br><span class="line">5 console.log("输出" + a);</span><br></pre></td></tr></table></figure><p>可以这样去表示:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">1 for(var i = 0,a = '';i < 10;i++) {</span><br><span class="line">2 a = 'Hello World';</span><br><span class="line">3 }</span><br><span class="line">4 console.log("输出" + a);</span><br></pre></td></tr></table></figure><p>不过这样写的话可读性会变得很差,所以并不建议这样写。<br><strong>for循环彼此之间可以进行嵌套。</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">1 for(var i = 0;i < 10;i++) {</span><br><span class="line">2 for(var j = 0;j < 10;j++) {</span><br><span class="line">3 </span><br><span class="line">4 }</span><br><span class="line">5 }</span><br></pre></td></tr></table></figure><h3 id="4-for-in循环"><a href="#4-for-in循环" class="headerlink" title="4.for-in循环"></a>4.for-in循环</h3><p>for-in循环往往被用来遍历某个数组中的元素。</p><p><strong>示例:</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">1 var a = ['a','b','c','d','e'];</span><br><span class="line">2 var result = '\n';</span><br><span class="line">3 for(var i in a) {</span><br><span class="line">4 result = 'index:' + i +',value:' + a[i] + '\n';</span><br><span class="line">5 console.log(result);</span><br><span class="line">6 }</span><br></pre></td></tr></table></figure><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>这部分内容主要介绍了JavaScript中的基本数据类型、数组、循环以及条件表达式的常规应用,尤其在数组方面并没有介绍全面,在后面的学习中再学到更多的应用时再做补充。</p>]]></content>
<summary type="html"><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>这部分内容主要介绍了JavaScript中基本数据类型、数组的基础知识、循环的常规应用以及表达式。</p></summary>
<category term="前端" scheme="https://codemariosec.github.io/categories/%E5%89%8D%E7%AB%AF/"/>
<category term="JavaScript" scheme="https://codemariosec.github.io/tags/JavaScript/"/>
</entry>
<entry>
<title>Web前端_JavaScript的Day1_面向对象的初步理解</title>
<link href="https://codemariosec.github.io/2022/01/31/Web%E5%89%8D%E7%AB%AF-JavaScript%E7%9A%84Day1-%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%88%9D%E6%AD%A5%E7%90%86%E8%A7%A3/"/>
<id>https://codemariosec.github.io/2022/01/31/Web%E5%89%8D%E7%AB%AF-JavaScript%E7%9A%84Day1-%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%88%9D%E6%AD%A5%E7%90%86%E8%A7%A3/</id>
<published>2022-01-30T17:24:26.000Z</published>
<updated>2022-06-03T06:53:03.646Z</updated>
<content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>JavaScript是一门面向对象的解释型脚本语言,通过利用面向对象的这种特性,实现了代码重用,并构建起了可伸缩的代码框架。作为JavaScript的初学者,因为面向对象是JavaScript的核心部分,所以在开始就略微的去学习了JavaScript的面向对象的基础概念部分,能够对于JavaScript的面向对象积累一些初始概念,并将自己对这些的感悟分享出来与大家交流。 作为初学者,可能有些地方理解不够正确,希望大家能提出自己的见解,欢迎批评指正。</p><span id="more"></span><h1 id="面向对象程序设计最常用到的概念"><a href="#面向对象程序设计最常用到的概念" class="headerlink" title="面向对象程序设计最常用到的概念"></a>面向对象程序设计最常用到的概念</h1><p>面向对象程序设计最常用到的概念如下:</p><ul><li>对象、方法、属性;</li><li>类;</li><li>封装;</li><li>聚合;</li><li>重用与继承;</li><li>多态。</li></ul><h2 id="1-对象"><a href="#1-对象" class="headerlink" title="1.对象"></a>1.对象</h2><p>JavaScript是面向对象的解释型脚本语言,所以面向对象是该编程语言的核心所在。那么什么是对象?对象我们有时候也叫“实例”,实际上就是指事物在程序语言中的表现形式,这类事物可以是人也可以是物,可以是客观存在的具体化对象,也可以是抽象的概念对象。这类事物往往具有其特定的称呼和特征,以及行为等。</p><p> <strong>例如:有一只黑色的猫在床上睡觉。其中,猫代表的是对象,黑色是颜色,代表属性,睡觉是一种动作行为,代表方法,在床上是睡觉的限定条件,限定动作的条件,也可以看做是传递给睡觉这个方法的参数。</strong></p><h2 id="2-类"><a href="#2-类" class="headerlink" title="2.类"></a>2.类</h2><p> 我们知道在现实生活中,相似对象之间往往具有一些共同的组成特征。比如阿拉斯加犬和哈士奇都属于狗类并具有狗类的特征,因此它们属于同一个类。所以类实际上就是一群具有相同特征的对象并同属一个类组成的集合。<strong>阿拉斯加犬是一个实例化对象,哈士奇是一个实例化对象,它们都是由同一个类创造出来的,而这个类还可以创造出其它具有相同特征的实例化对象,所以类也可以当做是一种模板,对象就是在模板上创建出来的实体。</strong></p><p> 当然,JavaScript并不存在类这一说法,它的一切都是基于对象,依靠着一套原型系统。在传统的面向对象语言中我们可以这样描述:我基于Cat类创建了一个叫做BlackCat的对象,而在基于原型的面向对象的语言中则是这样说道:我将现有的Cat对象扩展成一个叫做BlackCat的对象。</p><h2 id="3-封装"><a href="#3-封装" class="headerlink" title="3.封装"></a>3.封装</h2><p> 封装是用来封装对象中的内容,因此封装实际上就是去阐述对象中包含的内容。这些内容可以是属性,也可以是方法。</p><p> <strong>例如:一部手机是一个对象,手机里的处理器、电池、电路板等部件就是属性,我们作为用户通常通过手机的按钮、显示屏一类的接口去使用对应的方法,这等价于OOP(面向对象的程序设计)中的调用方法。但是这些接口的实现过程和手机所具有的属性等都是不可见的,我们并不清楚它们内部是如何工作的,只需要通过接口去使用功能即可。在编译类型的语言中我们也是直接去调用方法实现相应的功能即可,而不是去关心它的实现过程。</strong></p><p> 能够达到以上事例中的内容的封闭性就是封装。<strong>而封装的意义就是方便用户操作,优化用户体验。</strong></p><p> 在某些编程语言中我们可以使用public、private、project、default这些关键字来限定方法和属性的可见性,通过限定分类定义了用户所能访问的层次。<strong>但是在JavaScript中,所有的方法和属性都是public,话是这样说,其实JavaScript中也是提供了一些隐藏数据的方法来保护程序的隐私性。</strong></p><h2 id="4-聚合"><a href="#4-聚合" class="headerlink" title="4.聚合"></a>4.聚合</h2><p> 聚合也被称为组合,就是将几个现有对象合并为一个新对象的过程。这个过程实际上是一种思想,在实际解决问题的过程中我们可以采用这种思想将一个问题分解成多个小的问题,这些多个小的问题相对而言更加容易思考,提高解决问题的效率。</p><p> <strong>例如:在图书管理系统中我们要找《JavaScript高级程序设计》这本书,假若我们不使用检索功能去直接搜寻书,从一个系统包含的成千上万本书中去查找一本书也是一个很费劲的工作。因此我们可以将图书管理系统的功能模块细化,分门别类并有选择有目的的去寻找。《JavaScript高级程序设计》是一本关于前端的书籍,而前端书籍是属于技术类书籍,前端技术类书籍是包含在IT互联网类型中,而IT互联网类型可以在整个管理系统的图书分类中找到,而图书分类这个模块是在进入图书管理系统后比较显眼的功能分类中可以找到。通过将寻找这本书的流程分化成一个个的具体模块的过程再去逐一解决这个问题就是聚合。</strong></p><p> <strong>注意:以上事例要想实现是需要图书管理系统对于图书的分类比较明确而不是单单的将一堆图书直接聚集在一起,所以可以看出并不是在所有复杂情况下都可以使用聚合去解决问题,但是使用聚合可以解决大多数问题。</strong></p><p> 如果以上的示例还是令人感到迷惑的话我们再举一个例子。</p><p> <strong>例如:一个Web开发团队由许多人员组成,这是一个比较复杂的集体,我们如何才能清晰的知道这个集体中包含哪些人,每个人在做什么工作呢?我们需要将这个团队中包含的岗位罗列出来并将我们的对象,也就是开发人员和产品经理一一对应在相应的岗位,其中每一个开发人员或产品经理只是这个Web开发团队对象的一部分,这样划分下来我们就可以解决了这些问题。</strong></p><p> 总的来说聚合在开发过程中的作用是将分开编辑的代码聚合在一起<strong>方便调用</strong>。</p><h2 id="5-继承"><a href="#5-继承" class="headerlink" title="5.继承"></a>5.继承</h2><p> 继承是实际开发过程一种比较便捷的方式,通过继承这种方式可以实现代码的<strong>重复利用</strong>。</p><p> <strong>例如:人这个对象的名称我们可以将其命名为Person,这个对象中应该包含姓名、年龄、出生日期等属性以及走路、跑步、谈话、吃饭、睡觉等方法。这时候我们想要编写一个Student对象,这个对象拥有和Person对象一样的特征,因此我们可以直接继承Person对象,这样我们只需要通过去重用Person对象去编写Student对象的实现代码部分即可。接着我们还想编写一个Teacher对象依然可以这样做。</strong></p><p> 通过以上示例就可以实现了代码的复用避免了不停地重写相同的方法和属性,做到高效利用。</p><p> 在传统的面向对象的程序设计中,继承通常都是指类与类之间的关系,但是JavaScript中并不存在类这样的说法,所以它的继承是发生在对象与对象之间。</p><p> 当一个对象继承另一个对象的时候,可能会继承的基础上在里面加入新的方法,这个过程被称为“继承对象扩展自被继承对象”或者“继承对象继承自被继承对象”。比如A对象继承B对象,那么就是“A扩展自B”或“A继承自B”。此外我们也可以重新定义被继承的对象中的方法,被重新定义后的方法只是改变了当前继承在该对象中的方法,并不会真正改变被继承对象中的方法,而<strong>这种重新定义继承过来的方法的过程叫做方法的覆写</strong>。</p><h2 id="6-多态"><a href="#6-多态" class="headerlink" title="6.多态"></a>6.多态</h2><p> 还是上面的例子,Student对象继承了Person对象中所有的方法,Teacher对象也继承了Person对象中所有的方法,拿方法中的跑步举例,跑步是“run”方法,这时候代码中有一个叫做Jack的变量,我们并不知道Jack是属于Person对象还是属于Student对象还是属于Teachar,在这种情况下我们还是可以去调用对象的“run”方法,实现跑步这一方法,形如这种通过相同的方法调用来实现各自行为的能力的就是多态。如果再通俗来讲,就是<strong>同一个操作作用在不同的对象上产生不同的解释或者是不同的结果就是多态</strong>。</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></pre></td><td class="code"><pre><span class="line"> <span class="number">1</span> <span class="function"><span class="keyword">function</span> <span class="title">Person</span>(<span class="params"></span>) </span>{}</span><br><span class="line"> <span class="number">2</span> Person.prototype.age = <span class="function"><span class="keyword">function</span>(<span class="params">age</span>) </span>{</span><br><span class="line"> <span class="number">3</span> <span class="keyword">return</span> age;</span><br><span class="line"> <span class="number">4</span> }</span><br><span class="line"> <span class="number">5</span> </span><br><span class="line"> <span class="number">6</span> <span class="function"><span class="keyword">function</span> <span class="title">Student</span>(<span class="params"></span>) </span>{}</span><br><span class="line"> <span class="number">7</span> <span class="built_in">Object</span>.setPrototypeOf(Student.prototype,Person.prototype);</span><br><span class="line"> <span class="number">8</span> </span><br><span class="line"> <span class="number">9</span> <span class="function"><span class="keyword">function</span> <span class="title">Teacher</span>(<span class="params"></span>) </span>{}</span><br><span class="line"><span class="number">10</span> <span class="built_in">Object</span>.setPrototypeOf(Teacher.prototype,Person.prototype);</span><br><span class="line"><span class="number">11</span> </span><br><span class="line"><span class="number">12</span> <span class="keyword">var</span> stu = <span class="keyword">new</span> Student();</span><br><span class="line"><span class="number">13</span> <span class="built_in">console</span>.log(stu.age(<span class="number">18</span>));</span><br><span class="line"><span class="number">14</span> </span><br><span class="line"><span class="number">15</span> <span class="keyword">var</span> tea = <span class="keyword">new</span> Teacher();</span><br><span class="line"><span class="number">16</span> <span class="built_in">console</span>.log(tea.age(<span class="number">28</span>));</span><br></pre></td></tr></table></figure><p> 即使后面再加上一个Master对象,依然可以继续调用,不影响其它代码的调用实现</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><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><span class="line"> <span class="number">1</span> <span class="function"><span class="keyword">function</span> <span class="title">Person</span>(<span class="params"></span>) </span>{}</span><br><span class="line"> <span class="number">2</span> Person.prototype.age = <span class="function"><span class="keyword">function</span>(<span class="params">age</span>) </span>{</span><br><span class="line"> <span class="number">3</span> <span class="keyword">return</span> age;</span><br><span class="line"> <span class="number">4</span> }</span><br><span class="line"> <span class="number">5</span> </span><br><span class="line"> <span class="number">6</span> <span class="function"><span class="keyword">function</span> <span class="title">Student</span>(<span class="params"></span>) </span>{}</span><br><span class="line"> <span class="number">7</span> <span class="built_in">Object</span>.setPrototypeOf(Student.prototype,Person.prototype);</span><br><span class="line"> <span class="number">8</span> </span><br><span class="line"> <span class="number">9</span> <span class="function"><span class="keyword">function</span> <span class="title">Teacher</span>(<span class="params"></span>) </span>{}</span><br><span class="line"><span class="number">10</span> <span class="built_in">Object</span>.setPrototypeOf(Teacher.prototype,Person.prototype);</span><br><span class="line"><span class="number">11</span> </span><br><span class="line"><span class="number">12</span> <span class="function"><span class="keyword">function</span> <span class="title">Master</span>(<span class="params"></span>) </span>{}</span><br><span class="line"><span class="number">13</span> <span class="built_in">Object</span>.setPrototypeOf(Master.prototype,Person.prototype);</span><br><span class="line"><span class="number">14</span> </span><br><span class="line"><span class="number">15</span> <span class="keyword">let</span> stu = <span class="keyword">new</span> Student();</span><br><span class="line"><span class="number">16</span> <span class="built_in">console</span>.log(stu.age(<span class="number">18</span>));</span><br><span class="line"><span class="number">17</span> </span><br><span class="line"><span class="number">18</span> <span class="keyword">let</span> tea = <span class="keyword">new</span> Teacher();</span><br><span class="line"><span class="number">19</span> <span class="built_in">console</span>.log(tea.age(<span class="number">28</span>));</span><br><span class="line"><span class="number">20</span> </span><br><span class="line"><span class="number">21</span> <span class="keyword">let</span> mas = <span class="keyword">new</span> Master();</span><br><span class="line"><span class="number">22</span> <span class="built_in">console</span>.log(mas.age(<span class="number">38</span>));</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>JavaScript是一门面向对象的解释型脚本语言,通过利用面向对象的这种特性,实现了代码重用,并构建起了可伸缩的代码框架。作为JavaScript的初学者,因为面向对象是JavaScript的核心部分,所以在开始就略微的去学习了JavaScript的面向对象的基础概念部分,能够对于JavaScript的面向对象积累一些初始概念,并将自己对这些的感悟分享出来与大家交流。 作为初学者,可能有些地方理解不够正确,希望大家能提出自己的见解,欢迎批评指正。</p></summary>
<category term="前端" scheme="https://codemariosec.github.io/categories/%E5%89%8D%E7%AB%AF/"/>
<category term="JavaScript" scheme="https://codemariosec.github.io/tags/JavaScript/"/>
</entry>
</feed>