-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
616 lines (337 loc) · 176 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>21cm</title>
<subtitle>愿用三生烟火,换你一世迷离。</subtitle>
<link href="/atom.xml" rel="self"/>
<link href="https://21cm.js.org/"/>
<updated>2018-09-18T06:48:27.406Z</updated>
<id>https://21cm.js.org/</id>
<author>
<name>21cm</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>javascript速查表</title>
<link href="https://21cm.js.org/2018/09/18/javascript-Quick-check-list/"/>
<id>https://21cm.js.org/2018/09/18/javascript-Quick-check-list/</id>
<published>2018-09-18T06:37:03.160Z</published>
<updated>2018-09-18T06:48:27.406Z</updated>
<content type="html"><![CDATA[<ul><li>数组</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">concat()连接两个或更多的数组,并返回结果。</span><br><span class="line">join() 把数组的所有元素放入一个字符串。元素通过指定的分隔符进行分隔。</span><br><span class="line">pop() 删除并返回数组的最后一个元素</span><br><span class="line">push() 向数组的末尾添加一个或更多元素,并返回新的长度。</span><br><span class="line">reverse()颠倒数组中元素的顺序。</span><br><span class="line">shift() 删除并返回数组的第一个元素</span><br><span class="line">slice() 从某个已有的数组返回选定的元素 </span><br><span class="line">sort() 对数组的元素进行排序</span><br><span class="line">splice()删除元素,并向数组添加新元素。</span><br><span class="line">toString()把数组转换为字符串,并返回结果。</span><br><span class="line">unshift()向数组的开头添加一个或更多元素,并返回新的长度。</span><br><span class="line">valueOf()返回数组对象的原始值</span><br></pre></td></tr></table></figure><ul><li><p>String 对象方法</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">concat()连接字符串。。</span><br><span class="line">indexOf()检索字符串。</span><br><span class="line">lastIndexOf()从后向前搜索字符串。</span><br><span class="line">slice() 提取字符串的片断,并在新的字符串中返回被提取的部分。</span><br><span class="line">split() 把字符串分割为字符串数组。</span><br><span class="line">toString()返回字符串。</span><br><span class="line">valueOf()返回某个字符串对象的原始值。</span><br><span class="line">length 字符串的长度</span><br></pre></td></tr></table></figure></li><li><p>History</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">back()加载 history 列表中的前一个 URL。</span><br><span class="line">forward()加载 history 列表中的下一个 URL。</span><br><span class="line">go()加载 history 列表中的某个具体页面。</span><br><span class="line">Location</span><br><span class="line">hash设置或返回从井号 (#) 开始的 URL(锚)。</span><br><span class="line">host设置或返回主机名和当前 URL 的端口号。</span><br><span class="line">hostname设置或返回当前 URL 的主机名。</span><br><span class="line">href设置或返回完整的 URL。</span><br><span class="line">pathname设置或返回当前 URL 的路径部分。</span><br><span class="line">search设置或返回从问号 (?) 开始的 URL(查询部分)。</span><br><span class="line">assign()加载新的文档。</span><br><span class="line">reload()重新加载当前文档。</span><br><span class="line">replace()用新的文档替换当前文档。</span><br></pre></td></tr></table></figure></li><li><p>Document</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">document.cookie设置或返回与当前文档有关的所有 cookie。</span><br><span class="line">document.referrer返回载入当前文档的文档的 URL。</span><br><span class="line">document.title返回当前文档的标题。</span><br><span class="line">document.links 返回文档中所有的Area和Link对象引用</span><br><span class="line">document.getElementById()返回对拥有指定 id 的第一个对象的引用。</span><br><span class="line">document.querySelector() CSS 选择器 语法跟jquery一样</span><br></pre></td></tr></table></figure></li></ul><p>document.body 网页宽、高、偏移属性<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">网页可见区域宽: document.body.clientWidth </span><br><span class="line">网页可见区域高: document.body.clientHeight </span><br><span class="line">网页可见区域宽: document.body.offsetWidth (包括边线的宽) </span><br><span class="line">网页可见区域高: document.body.offsetHeight (包括边线的高) </span><br><span class="line">网页正文全文宽: document.body.scrollWidth (不包括边线的宽) </span><br><span class="line">网页正文全文高: document.body.scrollHeight (不包括边线的高) </span><br><span class="line">网页被卷去的高: document.body.scrollTop </span><br><span class="line">网页被卷去的左: document.body.scrollLeft</span><br></pre></td></tr></table></figure></p><ul><li><p>操作文档对象</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><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">document.createElement('div') 创建并返回一个元素</span><br><span class="line">document.createTextNode('title') 创建并返回一个文本节点</span><br><span class="line">document.createAttribute('title')创建并返回一个属性节点</span><br><span class="line">document.createComment('comment') 创建并返回一个注释节点</span><br><span class="line">document.createDocumentFragment() 创建并返回一个文档片段</span><br><span class="line">document.getElementById('idName') 返回指定id的元素</span><br><span class="line">document.querySelector('#id .className') 返回文档中匹配指定的css选择器的第一元素</span><br><span class="line">document.querySelectorAll() 返回文档中匹配的css选择器的所有元素节点列表</span><br><span class="line">document.getElementsByClassName('className') 返回指定className的NodeList集合</span><br><span class="line">document.images 返回文档中所有Image对象引用</span><br></pre></td></tr></table></figure></li><li><p>Element</p></li><li><ul><li>element 方法<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">element.getElementsByTagName() 获取元素内的所有指定标签的子元素</span><br><span class="line">element.insertBefore() 在指定的已有的子节点之前插入新节点。</span><br><span class="line">element.appendChild() 向元素添加新的子节点,作为最后一个子节点。</span><br><span class="line">element.getAttribute() 返回元素节点的指定属性值。</span><br><span class="line">element.getAttributeNode() 返回指定的属性节点。</span><br><span class="line">element.setAttribute() 设置元素节点指定属性与值</span><br><span class="line">element.removeChild() 从元素中移除子节点</span><br><span class="line">element.replaceChild(newnode,oldnode) 用一个新元素替换列表中的某个元素 </span><br><span class="line">element.removeAttribute() 从元素中移除指定属性</span><br><span class="line">element.removeAttributeNode() 移除指定属性节点,并返回被移除的节点</span><br><span class="line">element.hasAttribute() 判断元素是否拥有指定属性</span><br><span class="line">element.hasAttributes() 判断元素是否拥有属性</span><br><span class="line">element.hasChildNodes() 判断元素是否拥有子元素</span><br><span class="line">element.isEqualNode(node) 判断两个元素是否相等</span><br><span class="line">element.normalize() 移除空的文本节点,并连接相邻的文本节点</span><br><span class="line">element.childNodes.item(0) 返回NodeList中位于指定下标的节点</span><br><span class="line">element.cloneNode(deep) 克隆节点,deep默认为false,为false克隆节点,为true克隆节点及后代</span><br><span class="line">element.compareDocumentPosition() 比较两个元素的文档位置,1:没有关系,两个节点不属于同一文档。2:第一节点位于第二节点后。4:第一节点定位在第二节点前。8:第一节点位于第二节点内。16:第二节点位于第一节点内。32:没有关系,或是两个节点是同一元素的两个属性,返回值可以是值的组合,例如,返回20意味着第二节点在第一节点内部(16),并且第二节点在第一节点之后(4)</span><br></pre></td></tr></table></figure></li></ul></li><li><ul><li>element 属性<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line">element.id 设置或返回元素的 id。</span><br><span class="line">element.tagName 获取元素的标签名(大写)</span><br><span class="line">element.className元素所有的 class 逗号分隔。</span><br><span class="line">element.classList 元素所有的 class 数组形式。</span><br><span class="line">element.style 设置或返回元素的style属性</span><br><span class="line">element.innerText 设置或返回元素的内容</span><br><span class="line">element.innerHTML设置或返回元素的HTML内容。</span><br><span class="line">element.textContent 设置或返回节点及其后代的文本内容</span><br><span class="line">element.nodeName 获取元素的名称</span><br><span class="line">element.nodeValue 设置或返回元素值</span><br><span class="line">element.nodeType 获取节点类型(共12中类型 1:Element,2:Attr,3:Text,8:注释,9:根节点,11:DocumentFragment)</span><br><span class="line">element.attributes返回元素属性的 NamedNodeMap。</span><br><span class="line">element.parentNode 返回元素父节点</span><br><span class="line">element.childNodes 获取元素直接后代的HTML元素和TextNode对象的集合</span><br><span class="line">element.firstChild获取元素首个子元素</span><br><span class="line">element.lastChild获取元素最后一个子元素</span><br><span class="line">element.previousSibling 获取上一个同级节点</span><br><span class="line">element.nextSibling 获取下一个同级节点</span><br><span class="line">element.accessKey 设置或返回元素的快捷键</span><br><span class="line">element.title 设置或返回元素的title </span><br><span class="line">element.isContentEditable 返回元素是否可编辑</span><br><span class="line">element.ownerDocument 返回根元素document</span><br><span class="line">element.childNodes.length 返回NodeList中节点数</span><br><span class="line">element.offsetXX 节点宽、高、偏移(包括滚动条、边框)</span><br><span class="line">element.offsetWidth 元素的宽度(包括padding、border、width)</span><br><span class="line">element.offsetHeight 元素的高度(包括padding、border、width)</span><br><span class="line">element.offsetLeft 元素的左偏移位置</span><br><span class="line">element.offsetTop 元素的上偏移位置</span><br><span class="line">element.offsetParent 元素的偏移容器</span><br><span class="line">elment.scrollXX 节点宽、高、卷边(padding加元素内容的宽高)</span><br><span class="line">element.scrollHeight 元素的完整高度(padding+内容高,不含边框)</span><br><span class="line">element.scrollWidth 元素的整体宽度(padding+内容宽,不含边框)</span><br><span class="line">element.scrollLeft 元素左边卷去的距离</span><br><span class="line">element.scrollTop 元素上边卷去的距离</span><br><span class="line">element.clientXX 节点宽、高、边框(padding加元素内容的宽高)</span><br><span class="line">element.clientHeight 元素的高度(padding+内容高,不含边框)</span><br><span class="line">element.clientWidth 元素的宽度(padding+内容宽,不含边框)</span><br><span class="line">element.clientLeft 元素的左边框宽度</span><br><span class="line">element.clientTop 元素的上边框宽度</span><br></pre></td></tr></table></figure></li></ul></li><li><p>获取网页屏幕宽高</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><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">网页正文部分上: window.screenTop </span><br><span class="line">网页正文部分左: window.screenLeft </span><br><span class="line">屏幕分辨率的高: window.screen.height </span><br><span class="line">屏幕分辨率的宽: window.screen.width </span><br><span class="line">屏幕可用工作区高度: window.screen.availHeight </span><br><span class="line">屏幕可用工作区宽度: window.screen.availWidth</span><br><span class="line">屏幕可视区域的宽度:window.innerWidth (包括边框、边距、滚动条,不包括工具条)</span><br><span class="line">屏幕可视区域的高度:window.innerHeight(包括边框、边距、滚动条,不包括工具条)</span><br><span class="line">屏幕可视区域的宽度:window.outerWidth (包括边框、边距、滚动条、工具条)</span><br><span class="line">屏幕可视区域的高度:window.outerHeight (包括边框、边距、滚动条、工具条)</span><br></pre></td></tr></table></figure></li><li><p>事件</p><figure class="highlight plain"><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">element.addEventListener(event,handler,useCapture) 向文档添加事件句柄,useCapture为true为捕获型事件,为false为冒泡型事件,默认为false,捕获型事件从外向内冒泡且无法停止,冒泡型事件从内向外冒泡,使用`stopPropagation()`停止冒泡</span><br><span class="line">element.removeEventListener(event,handler,userCapture) 移除由addEventListener添加的事件,参数必须与添加时一致</span><br></pre></td></tr></table></figure></li><li><p>JSON</p><figure class="highlight plain"><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">JSON.parse用于从一个字符串中解析出json对象</span><br><span class="line">JSON.stringify()用于从一个对象解析出字符串</span><br></pre></td></tr></table></figure></li><li><p>Window</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">clearInterval()取消由 setInterval() 设置的 timeout。</span><br><span class="line">clearTimeout()取消由 setTimeout() 方法设置的 timeout。</span><br><span class="line">scroll() </span><br><span class="line">scrollTo()把内容滚动到指定的坐标。</span><br><span class="line">setInterval()按照指定的周期(以毫秒计)来调用函数或计算表达式。</span><br><span class="line">setTimeout()在指定的毫秒数后调用函数或计算表达式。</span><br></pre></td></tr></table></figure></li><li><p>Math 对象方法</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">abs(x)返回数的绝对值。</span><br><span class="line">ceil(x)对数进行上舍入。</span><br><span class="line">floor(x)对数进行下舍入。</span><br><span class="line">max(x,y)返回 x 和 y 中的最高值。</span><br><span class="line">min(x,y)返回 x 和 y 中的最低值。</span><br><span class="line">random()返回 0 ~ 1 之间的随机数。</span><br><span class="line">round(x)把数四舍五入为最接近的整数。</span><br></pre></td></tr></table></figure></li><li><p>Number 对象方法</p><figure class="highlight plain"><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">toString把数字转换为字符串,使用指定的基数。</span><br><span class="line">valueOf返回一个 Number 对象的基本数字值。</span><br></pre></td></tr></table></figure></li><li><p>Date 对象方法</p><figure class="highlight plain"><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">new Date() 获取当前时间对象</span><br><span class="line">Date.now() 获取当前时间戳</span><br></pre></td></tr></table></figure></li><li><p>Object 对象方法</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Object.keys(obj)获取对象的所有key到数组</span><br><span class="line">Object.values(obj) 获取对象的所有值到数组</span><br><span class="line">Object.assign(obj1,obj2,objn,....) 合并多个对象,key相同后面覆盖前面</span><br><span class="line">Object.create(obj) 以obj为原型生成一个新对象</span><br></pre></td></tr></table></figure></li></ul>]]></content>
<summary type="html">
<ul>
<li>数组</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">
</summary>
<category term="前端" scheme="https://21cm.js.org/categories/%E5%89%8D%E7%AB%AF/"/>
<category term="javascript" scheme="https://21cm.js.org/tags/javascript/"/>
<category term="javascript速查表" scheme="https://21cm.js.org/tags/javascript%E9%80%9F%E6%9F%A5%E8%A1%A8/"/>
</entry>
<entry>
<title>函数节流与防抖</title>
<link href="https://21cm.js.org/2018/06/15/function.prototype.bind/"/>
<id>https://21cm.js.org/2018/06/15/function.prototype.bind/</id>
<published>2018-06-15T11:00:00.000Z</published>
<updated>2018-06-15T11:00:41.118Z</updated>
<content type="html"><![CDATA[<p>假设浏览器窗口滚动条滚动时会调用一个方法fn,下面一步步实现一个节流函数.</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br></pre></td><td class="code"><pre><span class="line"> * 第一个版本</span><br><span class="line"> * 缺点:产生了全局变量</span><br><span class="line"><script></span><br><span class="line"> var timer;</span><br><span class="line"> window.onscroll = function () {</span><br><span class="line"> clearTimeout(timer);</span><br><span class="line"> timer = setTimeout(function () {</span><br><span class="line"> console.log('window scroll...');</span><br><span class="line"> }, 200);</span><br><span class="line"> }</span><br><span class="line"></script></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> * 第二个版本,使用闭包来封装全局变量</span><br><span class="line"> * 缺点:如果用户不停的滚动滚动条,那么延时函数一次都不会触发</span><br><span class="line"><script></span><br><span class="line"> var throttle = function (fn, delay) {</span><br><span class="line"> var timer = null;</span><br><span class="line"> return function () {</span><br><span class="line"> clearTimeout(timer);</span><br><span class="line"> timer = setTimeout(function () {</span><br><span class="line"> fn();</span><br><span class="line"> }, delay);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> var f = throttle(testFn, 200);</span><br><span class="line"> window.onscroll = function () {</span><br><span class="line"> f();</span><br><span class="line"> };</span><br><span class="line"></script></span><br><span class="line"></span><br><span class="line"> * 于是我们又要添加一个功能:当用户触发 scroll 的时候应该 在某段时间 内至少触发一次,既然是在某段时间内,</span><br><span class="line"> * 那么这个判断条件就可以取当前的时间毫秒数,每次函数调用把当前的时间和上一次调用时间相减,然后判断差值如果大于 某段时间 就直接触发,</span><br><span class="line"> * 否则还是走 timeout 的延迟逻辑。</span><br><span class="line"> 下面的代码里面需要指出的是:</span><br><span class="line"> 1. previous 变量的作用和 timer 类似,都是记录上一次的标识,必须是相对的全局变量</span><br><span class="line"> 2. 如果逻辑流程走的是“至少触发一次”的逻辑,那么函数调用完成需要把 previous 重置成当前时间,简单来说就是:相对于下一次的上一次其实就是当前</span><br><span class="line"> </span><br><span class="line"><script></span><br><span class="line"></span><br><span class="line"> var COUNT = 0, demo = document.getElementById('demo');</span><br><span class="line"> function testFn() {</span><br><span class="line"> demo.innerHTML += 'testFN 被调用了 ' + ++COUNT + '次<br>';</span><br><span class="line"> }</span><br><span class="line"> var throttle = function (fn, delay, atleast) {</span><br><span class="line"> var timer = null;</span><br><span class="line"> var previous = null;</span><br><span class="line"> return function () {</span><br><span class="line"> var now = +new Date();</span><br><span class="line"> if (!previous) previous = now;</span><br><span class="line"> if (atleast && now - previous > atleast) {</span><br><span class="line"> fn();</span><br><span class="line"> // 重置上一次开始时间为本次结束时间</span><br><span class="line"> previous = now;</span><br><span class="line"> clearTimeout(timer);</span><br><span class="line"> } else {</span><br><span class="line"> clearTimeout(timer);</span><br><span class="line"> timer = setTimeout(function () {</span><br><span class="line"> fn();</span><br><span class="line"> previous = null;</span><br><span class="line"> }, delay);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> };</span><br><span class="line"> window.onscroll = throttle(testFn, 200);</span><br><span class="line"> // window.onscroll = throttle(testFn, 500, 1000);</span><br><span class="line"></script></span><br><span class="line"></span><br><span class="line"><script></span><br><span class="line"> document.getElementById("btn").onclick = throttle(function () {</span><br><span class="line"> console.log("button click...");</span><br><span class="line"> }, 2000);</span><br><span class="line"></span><br><span class="line"> //debounce用于将相同的操作积累到一起再触发,节省性能</span><br><span class="line"> function debounce(fn, delay) {</span><br><span class="line"> var timer = null;</span><br><span class="line"> return function () {</span><br><span class="line"> clearTimeout(timer);</span><br><span class="line"> timer = setTimeout(function () {</span><br><span class="line"> return fn.apply(this, arguments);</span><br><span class="line"> }, delay);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></script></span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>假设浏览器窗口滚动条滚动时会调用一个方法fn,下面一步步实现一个节流函数.</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><
</summary>
<category term="函数节流与防抖" scheme="https://21cm.js.org/categories/%E5%87%BD%E6%95%B0%E8%8A%82%E6%B5%81%E4%B8%8E%E9%98%B2%E6%8A%96/"/>
<category term="前端" scheme="https://21cm.js.org/tags/%E5%89%8D%E7%AB%AF/"/>
</entry>
<entry>
<title>this的四种用法</title>
<link href="https://21cm.js.org/2018/05/30/js-this/"/>
<id>https://21cm.js.org/2018/05/30/js-this/</id>
<published>2018-05-30T02:00:00.000Z</published>
<updated>2018-05-30T10:05:55.094Z</updated>
<content type="html"><![CDATA[<ul><li>javascript中this的指向有4种情况:</li><li>1.作为普通函数调用: <code>this</code>指向全局对象</li><li>2.作为对象方法调用: <code>this`</code>指向该对象</li><li>3.构造器调用: this指向构造器返回的对象</li><li>4.<code>Function.prototype.call</code> 和 <code>Function.prototype.apply</code>调用: <code>this</code>指向动态传入的对象</li></ul><ul><li>丢失的this</li><li>例子:</li><li><code>document.getElementById</code>这个函数名字太长,可以使用一个短点的函数来代替,例如prototype.js做法:</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">var getId = function (id) {</span><br><span class="line"> return document.getElementById(id);</span><br><span class="line">}</span><br><span class="line">getId('div1');</span><br></pre></td></tr></table></figure><ul><li>注意: 使用下面的方式是错误的!!!!!!!</li><li><code>var getId=document.getElementById;</code> 错误做法!!!</li><li>因为<code>document.getElementById</code>这个方法的实现需要使用this指针,this指针期望指向document对象,</li><li>而这种做法作为普通函数调用,this指向了全局对象,即window,所以会出错!!<br>可以使用apply传入document来帮助修正this:</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">document.getElementById = (function (func) {</span><br><span class="line"> return function () {</span><br><span class="line"> return func.apply(document, arguments);</span><br><span class="line"> }</span><br><span class="line">})(document.getElementById);</span><br><span class="line">var getId = document.getElementById; //这样就不会再报错</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<ul>
<li>javascript中this的指向有4种情况:</li>
<li>1.作为普通函数调用: <code>this</code>指向全局对象</li>
<li>2.作为对象方法调用: <code>this`</code>指向该对象</li>
<li>3.构造器调用
</summary>
<category term="javascript设计模式" scheme="https://21cm.js.org/categories/javascript%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
<category term="this" scheme="https://21cm.js.org/tags/this/"/>
</entry>
<entry>
<title>变量的作用域和闭包</title>
<link href="https://21cm.js.org/2018/05/29/field&&closure/"/>
<id>https://21cm.js.org/2018/05/29/field&&closure/</id>
<published>2018-05-29T11:00:00.000Z</published>
<updated>2018-05-30T01:38:36.056Z</updated>
<content type="html"><![CDATA[<ul><li>什么是闭包?</li><li><p>闭包是一个函数,用于捕获作用域内的外部绑定。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><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">// * @param FACTOR</span><br><span class="line">// * @returns {Function}</span><br><span class="line">//factor是createScaleFunction函数内的变量,却能在该函数返回后仍然使用</span><br><span class="line">//它从高阶函数中return实现"越狱"</span><br><span class="line">function createScaleFunction(FACTOR) {</span><br><span class="line"> var factor = FACTOR;</span><br><span class="line"> return function (array) {</span><br><span class="line"> return array.map(function (item) {</span><br><span class="line"> return item * factor;</span><br><span class="line"> })</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line">var scale10 = createScaleFunction(10);</span><br><span class="line">console.log(scale10([1, 2, 3, 4, 5])); //10, 20, 30, 40, 50</span><br><span class="line">var scale2 = createScaleFunction(2);</span><br><span class="line">console.log(scale2([1, 2, 3, 4, 5])); //2,4,6,8,10</span><br></pre></td></tr></table></figure><p>// * @returns {Function}</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">//利用闭包封装私有数据</span><br><span class="line">//实现一个自增计数器</span><br><span class="line">function increment() {</span><br><span class="line"> var counter = 0;</span><br><span class="line"> return function () {</span><br><span class="line"> return ++counter;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line">// console.log(counter); //error,访问不到</span><br><span class="line">var counter = increment();</span><br><span class="line">console.log(counter()); //1</span><br><span class="line">console.log(counter()); //2</span><br><span class="line">console.log(counter()); //3</span><br></pre></td></tr></table></figure><p>// * 实现bind函数</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">function.prototype.bind = function () {</span><br><span class="line"> var args = [].slice.apply(arguments);</span><br><span class="line"> var context = args.shift();</span><br><span class="line"> var self = this; //保存原函数</span><br><span class="line"> return function () {</span><br><span class="line"> var args2 = args.concat([].slice.apply(arguments));</span><br><span class="line"> return self.apply(context, args2);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line">var func = function (a, b, c, d) {</span><br><span class="line"> console.log(this.name); //21cm</span><br><span class="line"> console.log([a, b, c, d]); //3,4,1,2</span><br><span class="line">}.bind({name: '21cm'}, 3, 4);</span><br><span class="line">func(1, 2);</span><br></pre></td></tr></table></figure></li></ul>]]></content>
<summary type="html">
<ul>
<li>什么是闭包?</li>
<li><p>闭包是一个函数,用于捕获作用域内的外部绑定。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line"
</summary>
<category term="函数式编程" scheme="https://21cm.js.org/categories/%E5%87%BD%E6%95%B0%E5%BC%8F%E7%BC%96%E7%A8%8B/"/>
<category term="javascript" scheme="https://21cm.js.org/tags/javascript/"/>
<category term="变量作用域" scheme="https://21cm.js.org/tags/%E5%8F%98%E9%87%8F%E4%BD%9C%E7%94%A8%E5%9F%9F/"/>
<category term="闭包" scheme="https://21cm.js.org/tags/%E9%97%AD%E5%8C%85/"/>
</entry>
<entry>
<title>函数式编程之 Applicative编程</title>
<link href="https://21cm.js.org/2018/05/29/applicative/"/>
<id>https://21cm.js.org/2018/05/29/applicative/</id>
<published>2018-05-29T10:10:00.000Z</published>
<updated>2018-05-29T11:51:49.872Z</updated>
<content type="html"><![CDATA[<h3 id="Applicative编程-将函数作为参数传递给另外一个函数-并且调用它。"><a href="#Applicative编程-将函数作为参数传递给另外一个函数-并且调用它。" class="headerlink" title="Applicative编程: 将函数作为参数传递给另外一个函数,并且调用它。"></a>Applicative编程: 将函数作为参数传递给另外一个函数,并且调用它。</h3><p>最常见的有数组的 map、reduce、filter函数等。</p><ul><li>例一: 实现一个函数,查找出某个数组中所有数字,可能实现一个findNumber方法,<br>那如果后面又有查找字母、查找大于10的数字…这些需求呢? 难道每个需求都要添加一个函数?<br>可以使用高阶函数,将一个条件判断的函数当做参数传递到一个通用的find函数中!</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">function find(array, pred/!*function*!/) {</span><br><span class="line"> var result = [];</span><br><span class="line"> array.forEach(function (item, index) {</span><br><span class="line"> if (pred(item)) {</span><br><span class="line"> result.push(item);</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line"> return result;</span><br><span class="line"> }</span><br><span class="line">var result = find([1, 2, 3, 4, 'a', 'c', 5], function (item) {</span><br><span class="line"> // return item >= 0 && item <= 9; //查找数字 1,2,3,4,5</span><br><span class="line"> return item >= 'a' && item <= 'c'; //查找字母 a,c</span><br><span class="line"> });</span><br><span class="line">console.log(result); 1,2,3,4</span><br></pre></td></tr></table></figure><ul><li>例一的代码还可以写成如下形式,通过返回函数来定制不同行为</li><li>@param pred</li><li>@returns {Function}</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line">function find(pred) {</span><br><span class="line"> return function (array) {</span><br><span class="line"> var result = [];</span><br><span class="line"> array.forEach(function (item, index) {</span><br><span class="line"> if (pred(item)) {</span><br><span class="line"> result.push(item);</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line"> return result;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"> // * 1.查找数组中的数字</span><br><span class="line">var findNumber = find(function (x) {</span><br><span class="line"> return x >= 0 && x <= 9</span><br><span class="line">});</span><br><span class="line">console.log(findNumber([1, 2, 3, 'a', 'v', 'b', 4, 'kkk', 'rrr'])); //1,2,3,4</span><br><span class="line"></span><br><span class="line">// * 2.查找数组中除数字外的元素</span><br><span class="line">var findNotNumber = find(function (x) {</span><br><span class="line"> return !(x >= 0 && x <= 9);</span><br><span class="line">})</span><br><span class="line">console.log(findNotNumber([1, 2, 3, 'a', 'v', 'b', 4, 'kkk', 'rrr'])); // a,v,b,kkk,rrr</span><br><span class="line"></span><br><span class="line">// * 3.查找数组中的小写字母</span><br><span class="line"></span><br><span class="line">var findLowerCaseLetters = find(function (x) {</span><br><span class="line"> return x >= 'a' && x <= 'z'</span><br><span class="line">});</span><br><span class="line">console.log(findLowerCaseLetters([1, 2, 3, 'a', 'v', 'b', 4])); a,v,b</span><br></pre></td></tr></table></figure><ul><li>例二: 写一个函数,来判断传入的参数是不是某种类型的数据<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">var isType = function (Type) {</span><br><span class="line"> return function (data) {</span><br><span class="line"> return Object.prototype.toString.call(data) === '[object ' + Type + ']';</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line">// * 1.判断是不是Number类型数据</span><br><span class="line">var isNumber = isType('Number');</span><br><span class="line">console.log(isNumber(0)); //true</span><br><span class="line">// * 2.判断数据是不是字符串类型</span><br><span class="line">var isString = isType('String'); //true</span><br><span class="line">console.log(isString('123')); //true</span><br><span class="line">console.log(isString(123)); //false</span><br></pre></td></tr></table></figure></li></ul>]]></content>
<summary type="html">
<h3 id="Applicative编程-将函数作为参数传递给另外一个函数-并且调用它。"><a href="#Applicative编程-将函数作为参数传递给另外一个函数-并且调用它。" class="headerlink" title="Applicative编程: 将函数
</summary>
<category term="函数式编程" scheme="https://21cm.js.org/categories/%E5%87%BD%E6%95%B0%E5%BC%8F%E7%BC%96%E7%A8%8B/"/>
<category term="javascript" scheme="https://21cm.js.org/tags/javascript/"/>
<category term="函数式编程" scheme="https://21cm.js.org/tags/%E5%87%BD%E6%95%B0%E5%BC%8F%E7%BC%96%E7%A8%8B/"/>
<category term="Applicative编程" scheme="https://21cm.js.org/tags/Applicative%E7%BC%96%E7%A8%8B/"/>
</entry>
<entry>
<title>函数式编程</title>
<link href="https://21cm.js.org/2018/05/29/Functional-programming/"/>
<id>https://21cm.js.org/2018/05/29/Functional-programming/</id>
<published>2018-05-29T10:00:00.000Z</published>
<updated>2018-05-29T10:37:37.930Z</updated>
<content type="html"><![CDATA[<ul><li><p>函数式编程:<br>1.确定抽象,将其构建为函数。<br>2.利用已有的函数来构建更复杂的抽象。<br>3.通过将现有函数传递给其它函数来构建更复杂的抽象。</p></li><li><p>面向对象编程是将问题分解为多组”名词”或叫对象,而函数式编程是将问题分解为多组”动词”或叫方法</p></li><li><p>与面向对象编程类似,函数式编程通过”组合”或”黏结”其他函数来构建更大的函数。</p><ul><li><p>例一: 函数作为参数</p><pre><code>["hello","hi"].forEach(function (item, i) { console.log(item); // hello hi})</code></pre></li><li><p>例二: 返回函数的函数</p><pre><code>function splat(func) { return function (array) { return func.apply(null, array); }}var result = (splat(function (x, y) { return x + y;}))([1, 2]);console.log(result); //3</code></pre></li></ul></li></ul>]]></content>
<summary type="html">
<ul>
<li><p>函数式编程:<br>1.确定抽象,将其构建为函数。<br>2.利用已有的函数来构建更复杂的抽象。<br>3.通过将现有函数传递给其它函数来构建更复杂的抽象。</p>
</li>
<li><p>面向对象编程是将问题分解为多组”名词”或叫对象,而函数式编程是将
</summary>
<category term="函数式编程" scheme="https://21cm.js.org/categories/%E5%87%BD%E6%95%B0%E5%BC%8F%E7%BC%96%E7%A8%8B/"/>
<category term="javascript" scheme="https://21cm.js.org/tags/javascript/"/>
<category term="函数式编程" scheme="https://21cm.js.org/tags/%E5%87%BD%E6%95%B0%E5%BC%8F%E7%BC%96%E7%A8%8B/"/>
</entry>
<entry>
<title>前端算法排序之两个栈实现队列</title>
<link href="https://21cm.js.org/2018/05/29/Two-stacks/"/>
<id>https://21cm.js.org/2018/05/29/Two-stacks/</id>
<published>2018-05-29T05:00:00.000Z</published>
<updated>2018-05-29T09:40:45.371Z</updated>
<content type="html"><![CDATA[<ul><li>利用2个栈实现一个队列, 只需要实现先进先出的功能</li><li>@constructor</li></ul> <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line">var Stack = require('https://21cm.js.org/lib/stack');</span><br><span class="line">var Queue = function () {</span><br><span class="line"> this.stack1 = new Stack();</span><br><span class="line"> this.stack2 = new Stack();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">Queue.prototype.enqueue = function (ele) {</span><br><span class="line"> this.stack1.push(ele); //入队操作都压入栈1</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">Queue.prototype.dequeue = function () {</span><br><span class="line"> if (this.stack2.length()) { //栈2不空,直接pop</span><br><span class="line"> return this.stack2.pop();</span><br><span class="line"> } else { //若第二个栈不空,则将第一个栈中的所有元素出栈并压入栈2,并pop一次</span><br><span class="line"> while (this.stack1.length()) {</span><br><span class="line"> this.stack2.push(this.stack1.pop());</span><br><span class="line"> }</span><br><span class="line"> return this.stack2.pop();</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">var q = new Queue();</span><br><span class="line">q.enqueue(1);</span><br><span class="line">q.enqueue(2);</span><br><span class="line">q.enqueue(3);</span><br><span class="line"></span><br><span class="line">console.log(q.dequeue());</span><br><span class="line">console.log(q.dequeue());</span><br><span class="line">console.log(q.stack1);</span><br><span class="line">console.log(q.stack2);</span><br><span class="line"></span><br><span class="line">console.log('----------------------------');</span><br><span class="line"></span><br><span class="line">q.enqueue(4);</span><br><span class="line">q.enqueue(5);</span><br><span class="line">console.log(q.dequeue());</span><br><span class="line">console.log(q.stack1);</span><br><span class="line">console.log(q.stack2);</span><br><span class="line"></span><br><span class="line">console.log('----------------------------');</span><br><span class="line"></span><br><span class="line">console.log(q.dequeue());</span><br><span class="line">console.log(q.dequeue());</span><br><span class="line">console.log(q.stack1);</span><br><span class="line">console.log(q.stack2);</span><br><span class="line"></span><br><span class="line">console.log('----------------------------');</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<ul>
<li>利用2个栈实现一个队列, 只需要实现先进先出的功能</li>
<li>@constructor</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><spa
</summary>
<category term="前端" scheme="https://21cm.js.org/categories/%E5%89%8D%E7%AB%AF/"/>
<category term="前端算法" scheme="https://21cm.js.org/categories/%E5%89%8D%E7%AB%AF/%E5%89%8D%E7%AB%AF%E7%AE%97%E6%B3%95/"/>
<category term="javascript" scheme="https://21cm.js.org/tags/javascript/"/>
<category term="多队列" scheme="https://21cm.js.org/tags/%E5%A4%9A%E9%98%9F%E5%88%97/"/>
</entry>
<entry>
<title>前端算法排序之判断回文数</title>
<link href="https://21cm.js.org/2018/05/29/Palindrome/"/>
<id>https://21cm.js.org/2018/05/29/Palindrome/</id>
<published>2018-05-29T04:00:00.000Z</published>
<updated>2018-05-29T08:04:20.437Z</updated>
<content type="html"><![CDATA[<ul><li>使用栈来判断一个数是否为回文数</li><li>@param number</li><li>@returns {boolean}</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">var Stack = require('https://21cm.js.org/lib/stack');</span><br><span class="line">var isPalindromic = function (number) {</span><br><span class="line"> if (!number || number < 0) {</span><br><span class="line"> return false;</span><br><span class="line"> }</span><br><span class="line"> if (typeof number !== 'number') {</span><br><span class="line"> console.warn('expect a number!');</span><br><span class="line"> return false;</span><br><span class="line"> }</span><br><span class="line"> var stack = new Stack();</span><br><span class="line"> var str = number + '';</span><br><span class="line"> for (var i = 0, l = str.length; i < l; i++) {</span><br><span class="line"> stack.push(str[i]);</span><br><span class="line"> }</span><br><span class="line"> var destStr = '';</span><br><span class="line"> while (stack.length()) {</span><br><span class="line"> destStr += stack.pop();</span><br><span class="line"> }</span><br><span class="line"> if (destStr === str) {</span><br><span class="line"> return true;</span><br><span class="line"> }</span><br><span class="line"> return false;</span><br><span class="line">}</span><br><span class="line">console.log(isPalindromic(-125));</span><br><span class="line">console.log(isPalindromic('12321'));</span><br><span class="line">console.log(isPalindromic(12321));</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<ul>
<li>使用栈来判断一个数是否为回文数</li>
<li>@param number</li>
<li>@returns {boolean}</li>
</ul>
<figure class="highlight plain"><table><tr><td class=
</summary>
<category term="前端" scheme="https://21cm.js.org/categories/%E5%89%8D%E7%AB%AF/"/>
<category term="前端算法" scheme="https://21cm.js.org/categories/%E5%89%8D%E7%AB%AF/%E5%89%8D%E7%AB%AF%E7%AE%97%E6%B3%95/"/>
<category term="javascript" scheme="https://21cm.js.org/tags/javascript/"/>
<category term="判断回文数" scheme="https://21cm.js.org/tags/%E5%88%A4%E6%96%AD%E5%9B%9E%E6%96%87%E6%95%B0/"/>
</entry>
<entry>
<title>前端算法排序之数制转换</title>
<link href="https://21cm.js.org/2018/05/28/js-Number-System-Conversion/"/>
<id>https://21cm.js.org/2018/05/28/js-Number-System-Conversion/</id>
<published>2018-05-28T04:00:00.000Z</published>
<updated>2018-05-29T08:04:26.357Z</updated>
<content type="html"><![CDATA[<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">* 利用栈来做数制转换</span><br><span class="line">* @param number 待转换的数字,十进制数</span><br><span class="line">* @param base 要转换成的进制(10进制以内)</span><br><span class="line"></span><br><span class="line">var Stack = require('https://21cm.js.org/lib/stack');</span><br><span class="line">var numericalTransform = function (number, base) {</span><br><span class="line"> if (typeof number !== 'number' || typeof base !== 'number') {</span><br><span class="line"> console.log('Parameter error!');</span><br><span class="line"> return -1;</span><br><span class="line"> }</span><br><span class="line"> var stack = new Stack();</span><br><span class="line"> do {</span><br><span class="line"> stack.push(number % base);</span><br><span class="line"> number = Math.floor(number / base);</span><br><span class="line"> } while (number !== 0)</span><br><span class="line"> //依次出栈,得到结果</span><br><span class="line"> var result = '';</span><br><span class="line"> while (stack.length()) {</span><br><span class="line"> result += stack.pop();</span><br><span class="line"> }</span><br><span class="line"> return result;</span><br><span class="line">}</span><br><span class="line">console.log(numericalTransform(231, 8));</span><br><span class="line">console.log(numericalTransform(65, 2));</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class
</summary>
<category term="前端" scheme="https://21cm.js.org/categories/%E5%89%8D%E7%AB%AF/"/>
<category term="前端算法" scheme="https://21cm.js.org/categories/%E5%89%8D%E7%AB%AF/%E5%89%8D%E7%AB%AF%E7%AE%97%E6%B3%95/"/>
<category term="javascript" scheme="https://21cm.js.org/tags/javascript/"/>
<category term="数制转换" scheme="https://21cm.js.org/tags/%E6%95%B0%E5%88%B6%E8%BD%AC%E6%8D%A2/"/>
</entry>
<entry>
<title>前端算法之排序</title>
<link href="https://21cm.js.org/2018/05/28/js-sort/"/>
<id>https://21cm.js.org/2018/05/28/js-sort/</id>
<published>2018-05-28T02:00:00.000Z</published>
<updated>2018-05-28T09:57:00.461Z</updated>
<content type="html"><![CDATA[<ul><li>排序算法分析比较</li></ul><h4 id="1-快速排序(QuickSort)"><a href="#1-快速排序(QuickSort)" class="headerlink" title="1 快速排序(QuickSort)"></a>1 快速排序(QuickSort)</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">快速排序是一个就地排序,分而治之,大规模递归的算法。从本质上来说,它是归并排序的就地版本。快速排序可以由下面四步组成。</span><br><span class="line"></span><br><span class="line">(1) 如果不多于1个数据,直接返回。</span><br><span class="line">(2) 一般选择序列最左边的值作为支点数据。</span><br><span class="line">(3) 将序列分成2部分,一部分都大于支点数据,另外一部分都小于支点数据。</span><br><span class="line">(4) 对两边利用递归排序数列。</span><br><span class="line"></span><br><span class="line">快速排序比大部分排序算法都要快。尽管我们可以在某些特殊的情况下写出比快速排序快的算法,但是就通常情况而言,没有比它更快的了。</span><br><span class="line">快速排序是递归的,对于内存非常有限的机器来说,它不是一个好的选择。</span><br></pre></td></tr></table></figure><h4 id="2-归并排序(MergeSort)"><a href="#2-归并排序(MergeSort)" class="headerlink" title="2 归并排序(MergeSort)"></a>2 归并排序(MergeSort)</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">归并排序先分解要排序的序列,从1分成2,2分成4,依次分解,当分解到只有1个一组的时候,就可以排序这些分组,</span><br><span class="line">然后依次合并回原来的序列中,这样就可以排序所有数据。合并排序比堆排序稍微快一点,但是需要比堆排序多一倍的内存空间,</span><br><span class="line">因为它需要一个额外的数组。</span><br></pre></td></tr></table></figure><h4 id="3-堆排序(HeapSort)"><a href="#3-堆排序(HeapSort)" class="headerlink" title="3 堆排序(HeapSort)"></a>3 堆排序(HeapSort)</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">堆排序适合于数据量非常大的场合(百万数据)。</span><br><span class="line"></span><br><span class="line">堆排序不需要大量的递归或者多维的暂存数组。这对于数据量非常巨大的序列是合适的。</span><br><span class="line">比如超过数百万条记录,因为快速排序,归并排序都使用递归来设计算法,在数据量非常大的时候,可能会发生堆栈溢出错误。</span><br><span class="line"></span><br><span class="line">堆排序会将所有的数据建成一个堆,最大的数据在堆顶,然后将堆顶数据和序列的最后一个数据交换。</span><br><span class="line">接下来再次重建堆,交换数据,依次下去,就可以排序所有的数据。</span><br></pre></td></tr></table></figure><h4 id="4-Shell排序(ShellSort)"><a href="#4-Shell排序(ShellSort)" class="headerlink" title="4 Shell排序(ShellSort)"></a>4 Shell排序(ShellSort)</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Shell排序通过将数据分成不同的组,先对每一组进行排序,然后再对所有的元素进行一次插入排序,以减少数据交换和移动的次数。</span><br><span class="line">平均效率是O(nlogn)。其中分组的合理性会对算法产生重要的影响。现在多用D.E.Knuth的分组方法。</span><br><span class="line"></span><br><span class="line">Shell排序比冒泡排序快5倍,比插入排序大致快2倍。Shell排序比起QuickSort,MergeSort,HeapSort慢很多。</span><br><span class="line">但是它相对比较简单,它适合于数据量在5000以下并且速度并不是特别重要的场合。它对于数据量较小的数列重复排序是非常好的。</span><br></pre></td></tr></table></figure><h4 id="5-插入排序(InsertSort)"><a href="#5-插入排序(InsertSort)" class="headerlink" title="5 插入排序(InsertSort)"></a>5 插入排序(InsertSort)</h4><figure class="highlight plain"><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">插入排序通过把序列中的值插入一个已经排序好的序列中,直到该序列的结束。插入排序是对冒泡排序的改进。它比冒泡排序快2倍。</span><br><span class="line">一般不用在数据大于1000的场合下使用插入排序,或者重复排序超过200数据项的序列。</span><br></pre></td></tr></table></figure><h4 id="6-冒泡排序(BubbleSort)"><a href="#6-冒泡排序(BubbleSort)" class="headerlink" title="6 冒泡排序(BubbleSort)"></a>6 冒泡排序(BubbleSort)</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">冒泡排序是最慢的排序算法。在实际运用中它是效率最低的算法。它通过一趟又一趟地比较数组中的每一个元素,使较大的数据下沉,</span><br><span class="line">较小的数据上升。它是O(n^2)的算法。</span><br></pre></td></tr></table></figure><h4 id="7-选择排序(SelectSort)"><a href="#7-选择排序(SelectSort)" class="headerlink" title="7 选择排序(SelectSort)"></a>7 选择排序(SelectSort)</h4><figure class="highlight plain"><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">这两种排序方法都是交换方法的排序算法,效率都是 O(n2)。在实际应用中处于和冒泡排序基本相同的地位。</span><br><span class="line">它们只是排序算法发展的初级阶段,在实际中使用较少。</span><br></pre></td></tr></table></figure><h4 id="8-基数排序(RadixSort)"><a href="#8-基数排序(RadixSort)" class="headerlink" title="8 基数排序(RadixSort)"></a>8 基数排序(RadixSort)</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">基数排序和通常的排序算法并不走同样的路线。它是一种比较新颖的算法,但是它只能用于整数的排序,</span><br><span class="line">如果我们要把同样的办法运用到浮点数上,我们必须了解浮点数的存储格式,并通过特殊的方式将浮点数映射到整数上,</span><br><span class="line">然后再映射回去,这是非常麻烦的事情,因此,它的使用同样也不多。而且,最重要的是,这样算法也需要较多的存储空间。</span><br></pre></td></tr></table></figure><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><table><thead><tr><th style="text-align:center">排序法</th><th style="text-align:center">平均时间</th><th style="text-align:center">最差情形</th><th style="text-align:center">稳定度</th><th style="text-align:center">额外空间</th><th style="text-align:center">备注</th></tr></thead><tbody><tr><td style="text-align:center">冒泡排序</td><td style="text-align:center">O(nlogn)</td><td style="text-align:center">O(n2)</td><td style="text-align:center">稳定</td><td style="text-align:center">O(1)</td><td style="text-align:center">效率最低,n很小时可以使用,一般不用</td></tr><tr><td style="text-align:center">选择排序</td><td style="text-align:center">O(nlogn)</td><td style="text-align:center">O(n2)</td><td style="text-align:center">不稳定</td><td style="text-align:center">O(1)</td><td style="text-align:center">效率很低,n很小时可以使用,一般不用</td></tr><tr><td style="text-align:center">插入排序</td><td style="text-align:center">O(nlogn)</td><td style="text-align:center">O(n2)</td><td style="text-align:center">稳定</td><td style="text-align:center">O(1)</td><td style="text-align:center">大部分已排序时比较好</td></tr><tr><td style="text-align:center">希尔排序</td><td style="text-align:center">O(nlogn)</td><td style="text-align:center">O(n的s次方)</td><td style="text-align:center">不稳定</td><td style="text-align:center">O(1)</td><td style="text-align:center">1<s<2</td></tr><tr><td style="text-align:center">快速排序</td><td style="text-align:center">O(nlogn)</td><td style="text-align:center">O(n2)</td><td style="text-align:center">不稳定</td><td style="text-align:center">O(nlogn)</td><td style="text-align:center">数据量很大时好,平均效率最高的算法</td></tr><tr><td style="text-align:center">归并排序</td><td style="text-align:center">O(nlogn)</td><td style="text-align:center">O(nlogn)</td><td style="text-align:center">稳定</td><td style="text-align:center">O(1)</td><td style="text-align:center">数据量很大时好</td></tr><tr><td style="text-align:center">堆排序</td><td style="text-align:center">O(nlogn)</td><td style="text-align:center">O(nlogn)</td><td style="text-align:center">不稳定</td><td style="text-align:center">O(1)</td><td style="text-align:center">数据量很大时好</td></tr></tbody></table><ul><li>冒泡排序: 最慢的排序算法,基本上用不着!!!</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line">var generateTestData = require('https://21cm.js.org/lib/TestDataGenerator');</span><br><span class="line"></span><br><span class="line">var bubbleSort = function (data) {</span><br><span class="line"> var l = data.length;</span><br><span class="line"> for (var i = 0; i <= l - 1; i++) { //外层循环表示要进行length趟排序</span><br><span class="line"> //内层循环表示在每一趟中两两交换进行排序</span><br><span class="line"> for (var j = 1; j <= l; j++) {</span><br><span class="line"> if (data[j] < data[j - 1]) {</span><br><span class="line"> var tmp = data[j];</span><br><span class="line"> data[j] = data[j - 1];</span><br><span class="line"> data[j - 1] = tmp;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> return data;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">var data = generateTestData(20000);</span><br><span class="line"></span><br><span class="line">var start = new Date().getTime();</span><br><span class="line">console.log('start sorting....');</span><br><span class="line"></span><br><span class="line">var result = bubbleSort(data);</span><br><span class="line"></span><br><span class="line">var end = new Date().getTime();</span><br><span class="line">console.log('耗时: ' + (end - start) + ' ms');</span><br><span class="line"></span><br><span class="line">// console.log(result);</span><br></pre></td></tr></table></figure><ul><li>选择排序</li><li>选择排序是先找到起始数组中最小的元素,将它交换到i=0;</li><li>然后寻找剩下元素中最小的元素,将它交换到i=1的位置…… 直到找到第二大的元素,将它交换到n-2的位置。</li><li>这时,整个数组的排序完成。</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line">var generateTestData = require('https://21cm.js.org/lib/TestDataGenerator')</span><br><span class="line">var selectionSort = function (data) {</span><br><span class="line"> // var l = data.length;</span><br><span class="line"> // for (var i = 0; i <= l - 2; i++) {</span><br><span class="line"> // for (var j = i + 1; j <= l - 1; j++) {</span><br><span class="line"> // if (data[j] < data[i]) {</span><br><span class="line"> // var tmp = data[i];</span><br><span class="line"> // data[i] = data[j];</span><br><span class="line"> // data[j] = tmp;</span><br><span class="line"> // }</span><br><span class="line"> // }</span><br><span class="line"> // }</span><br><span class="line"> var l = data.length,</span><br><span class="line"> min_index;</span><br><span class="line"> for (var i = 0; i <= l - 2; i++) {</span><br><span class="line"> min_index = i;</span><br><span class="line"> //在后面的部分中找到最小值得index</span><br><span class="line"> for (var j = i + 1; j <= l - 1; j++) {</span><br><span class="line"> if (data[j] < data[min_index]) {</span><br><span class="line"> min_index = j;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> //将最小值交换到未排序部分的头部</span><br><span class="line"> var tmp = data[i];</span><br><span class="line"> data[i] = data[min_index];</span><br><span class="line"> data[min_index] = tmp;</span><br><span class="line"> }</span><br><span class="line"> return data;</span><br><span class="line">}</span><br><span class="line">var data = generateTestData(100000);</span><br><span class="line">// console.log(data);</span><br><span class="line">var start = new Date().getTime();</span><br><span class="line">console.log('start sorting....');</span><br><span class="line">var result = selectionSort(data);</span><br><span class="line">var end = new Date().getTime();</span><br><span class="line">console.log('耗时: ' + (end - start) + ' ms');</span><br><span class="line">// console.log(result);</span><br></pre></td></tr></table></figure><ul><li>插入排序:将整个数据集看作两个部分,前面已排序的部分和后面未排序的部分。</li><li>每次从未排序的部分中选择第一个数,插入到前面已排序部分的合适位置。</li><li>速度很慢!一般在数据集不超过1000的情况下使用。。</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">var generateTestData = require('https://21cm.js.org/lib/TestDataGenerator');</span><br><span class="line">var insertSort = function (data) {</span><br><span class="line"> var l = data.length;</span><br><span class="line"> for (var i = 1; i <= l; i++) {</span><br><span class="line"> var j = i - 1;</span><br><span class="line"> while ((j >= 0) && (data[j] < data[j - 1])) {</span><br><span class="line"> //交换</span><br><span class="line"> var tmp = data[j];</span><br><span class="line"> data[j] = data[j - 1];</span><br><span class="line"> data[j - 1] = tmp;</span><br><span class="line"> j--; //j--</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> return data;</span><br><span class="line">}</span><br><span class="line">var data = generateTestData(20000);</span><br><span class="line">// console.log(data);</span><br><span class="line">var start = new Date().getTime();</span><br><span class="line">console.log('start sorting....');</span><br><span class="line">var result = insertSort(data);</span><br><span class="line">var end = new Date().getTime();</span><br><span class="line">console.log('耗时: ' + (end - start) + ' ms');</span><br><span class="line">// console.log(result);</span><br></pre></td></tr></table></figure><ul><li>希尔排序</li><li>Shell Sorting依赖于间隔(step)的选取。</li><li>希尔排序的核心理念和插入排序不同,它会首先比较距离较远的元素,而非相邻元素。</li><li>使用这种方案可以使离正确位置很远的元素能够快速回到更合适的位置。</li><li>可以动态定义每次排序的间隔,但在应用中,通常会提前定义好间隔序列。</li><li>希尔排序可以和其他排序算法配合使用,本例使用插入排序。</li><li>分组间隔的合理性会对希尔排序的性能造成较大的影响!!!</li><li>希尔排序比冒泡排序平均快5倍,比插入排序大致快2倍,但是比快排、归并、堆排序慢的多!!!!</li><li>但是比较简单实现,通常适用于数据量在5000以下的场景。。</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line">var generateTestData = require('https://21cm.js.org/lib/TestDataGenerator');</span><br><span class="line">var shellSort = function (data, gaps /*array of numbers*/) {</span><br><span class="line"> var l = data.length;</span><br><span class="line"> for (var k = 0; k < gaps.length; k++) { //最外层循环取得每次的step</span><br><span class="line"> var step = gaps[k];</span><br><span class="line"> //内部使用插入排序算法!</span><br><span class="line"> for (var i = step; i <= l; i += step) {</span><br><span class="line"> var j = i - step;</span><br><span class="line"> while ((j >= 0) && (data[j] < data[j - step])) {</span><br><span class="line"> //交换</span><br><span class="line"> var tmp = data[j];</span><br><span class="line"> data[j] = data[j - step];</span><br><span class="line"> data[j - step] = tmp;</span><br><span class="line"> j -= step; //j-step</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> return data;</span><br><span class="line">}</span><br><span class="line">var data = generateTestData(50000);</span><br><span class="line">// console.log(data);</span><br><span class="line">var start = new Date().getTime();</span><br><span class="line">console.log('start sorting....');</span><br><span class="line">var result = shellSort(data, [10, 4, 1]);</span><br><span class="line">// var result = shellSort(data, [701, 301, 132, 57, 23, 10, 4, 1]);</span><br><span class="line">var end = new Date().getTime();</span><br><span class="line">console.log('耗时: ' + (end - start) + ' ms');</span><br><span class="line">// console.log(result);</span><br></pre></td></tr></table></figure><ul><li>快速排序: 快速排序通常被认为是高效,快速等特点是使用V8引擎的实现Array.prototype.sort()上有超过23个项目的数组。</li><li>对于少于23个项目,V8采用插入排序法。</li><li>快排是处理大数据集最快的算法之一。它是一种分而治之的算法,通过递归的方式将数据集依次分解为包含较小元素和包含</li><li>较大元素的不同子序列。不断重复这个步骤直至所有数据有序。</li><li>这个算法首先要在数据集中选择一个基准值(pivot),数据排序围绕基准值进行。</li><li>将列表中小于基准值的数据移动到一侧,将大于基准值的数据移动到另一侧。</li><li>快速排序非常适用于大数据集,处理小数据集反而性能下降。</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line">var generateTestData = require('https://21cm.js.org/lib/TestDataGenerator');</span><br><span class="line">function quickSort(data, l, r) {</span><br><span class="line"> {</span><br><span class="line"> if (l < r) {</span><br><span class="line"> //Swap(s[l], s[(l + r) / 2]); //如果以数组中间的数作为基准值,将中间的这个数和第一个数交换即可</span><br><span class="line"> var i = l, j = r,</span><br><span class="line"> pivot = data[l]; //以数组第一个数作为基准值来分区</span><br><span class="line"> while (i < j) {</span><br><span class="line"> // 从右向左找第一个小于x的数</span><br><span class="line"> while (i < j && data[j] >= pivot) {</span><br><span class="line"> j--;</span><br><span class="line"> }</span><br><span class="line"> if (i < j) {</span><br><span class="line"> data[i++] = data[j];</span><br><span class="line"> }</span><br><span class="line"> // 从左向右找第一个大于等于x的数</span><br><span class="line"> while (i < j && data[i] < pivot) {</span><br><span class="line"> i++;</span><br><span class="line"> }</span><br><span class="line"> if (i < j) {</span><br><span class="line"> data[j--] = data[i];</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> data[i] = pivot; //将pivot放入正确位置</span><br><span class="line"> // 对左右两边递归调用</span><br><span class="line"> quickSort(data, l, i - 1);</span><br><span class="line"> quickSort(data, i + 1, r);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> return data;</span><br><span class="line">}</span><br><span class="line">var data = generateTestData(20000000);</span><br><span class="line">// console.log(data);</span><br><span class="line">var start = new Date().getTime();</span><br><span class="line">console.log('start sorting....');</span><br><span class="line">var result = quickSort(data, 0, data.length - 1);</span><br><span class="line">var end = new Date().getTime();</span><br><span class="line">console.log('耗时: ' + (end - start) + ' ms');</span><br><span class="line">// console.log(result);</span><br></pre></td></tr></table></figure><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line">var generateTestData = require('https://21cm.js.org/lib/TestDataGenerator');</span><br><span class="line"> * 交换两个数</span><br><span class="line">function swap(items, firstIndex, secondIndex) {</span><br><span class="line"> var temp = items[firstIndex];</span><br><span class="line"> items[firstIndex] = items[secondIndex];</span><br><span class="line"> items[secondIndex] = temp;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"> * 分区操作: 以数组的中位数为基准值!</span><br><span class="line">function partition(items, left, right) {</span><br><span class="line"> var pivot = items[Math.floor((right + left) / 2)],</span><br><span class="line"> i = left,</span><br><span class="line"> j = right;</span><br><span class="line"> while (i <= j) {</span><br><span class="line"> while (items[i] < pivot) {</span><br><span class="line"> i++;</span><br><span class="line"> }</span><br><span class="line"> while (items[j] > pivot) {</span><br><span class="line"> j--;</span><br><span class="line"> }</span><br><span class="line"> if (i <= j) {</span><br><span class="line"> swap(items, i, j);</span><br><span class="line"> i++;</span><br><span class="line"> j--;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> return i;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"> * 快速排序</span><br><span class="line">function quickSort(items, left, right) {</span><br><span class="line"> var index;</span><br><span class="line"> if (items.length > 1) {</span><br><span class="line"> index = partition(items, left, right);</span><br><span class="line"> if (left < index - 1) {</span><br><span class="line"> quickSort(items, left, index - 1);</span><br><span class="line"> }</span><br><span class="line"> if (index < right) {</span><br><span class="line"> quickSort(items, index, right);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> return items;</span><br><span class="line">}</span><br><span class="line">var data = generateTestData(500000);</span><br><span class="line">// console.log(data);</span><br><span class="line">var start = new Date().getTime();</span><br><span class="line">console.log('start sorting....');</span><br><span class="line">var result = quickSort(data, 0, data.length - 1);</span><br><span class="line">var end = new Date().getTime();</span><br><span class="line">console.log('耗时: ' + (end - start) + ' ms');</span><br><span class="line">// console.log(result);</span><br></pre></td></tr></table></figure><h4 id="快速排序详解"><a href="#快速排序详解" class="headerlink" title="快速排序详解"></a>快速排序详解</h4><figure class="highlight plain"><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">快速排序由于排序效率在同为O(N*logN)的几种排序方法中效率较高,因此经常被采用,而且快速排序思想----分治法也确实实用!</span><br><span class="line">必须要熟练掌握快排,弄清原理后,能够默写出快排算法!!!</span><br></pre></td></tr></table></figure><p><code>快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序。它采用了一种分治的策略,通常称其为分治法(Divide-and-ConquerMethod)。</code></p><p>该方法的基本思想是:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">1.先从数列中取出一个数作为基准数。</span><br><span class="line"></span><br><span class="line">2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。</span><br><span class="line"></span><br><span class="line">3.再对左右区间重复第二步,直到各区间只有一个数。</span><br></pre></td></tr></table></figure></p><p>虽然快速排序称为分治法,但分治法这三个字显然无法很好的概括快速排序的全部步骤。<br>对快速排序作了进一步的说明:<code>挖坑填数</code>+<code>分治法</code>:</p><table><thead><tr><th style="text-align:center">index</th><th style="text-align:center">0</th><th style="text-align:center">1</th><th style="text-align:center">2</th><th style="text-align:center">3</th><th style="text-align:center">4</th><th style="text-align:center">5</th><th style="text-align:center">6</th><th style="text-align:center">7</th><th style="text-align:center">8</th><th style="text-align:center">9</th></tr></thead><tbody><tr><td style="text-align:center"></td><td style="text-align:center">72</td><td style="text-align:center">6</td><td style="text-align:center">57</td><td style="text-align:center">88</td><td style="text-align:center">60</td><td style="text-align:center">42</td><td style="text-align:center">83</td><td style="text-align:center">73</td><td style="text-align:center">48</td><td style="text-align:center">85</td></tr></tbody></table><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">以一个数组作为示例,取区间第一个数为基准数。</span><br><span class="line">初始时,i = 0; j = 9; X = a[i] = 72</span><br><span class="line"></span><br><span class="line">由于已经将a[0]中的数保存到X中,可以理解成在数组a[0]上挖了个坑,可以将其它数据填充到这来。</span><br><span class="line"></span><br><span class="line">从j开始向前找一个比X小或等于X的数。当j=8,符合条件,将a[8]挖出再填到上一个坑a[0]中。a[0]=a[8]; i++; </span><br><span class="line">这样一个坑a[0]就被搞定了,但又形成了一个新坑a[8],这怎么办了?简单,再找数字来填a[8]这个坑。</span><br><span class="line">这次从i开始向后找一个大于X的数,当i=3,符合条件,将a[3]挖出再填到上一个坑中a[8]=a[3]; j--;</span><br></pre></td></tr></table></figure><table><thead><tr><th style="text-align:center">index</th><th style="text-align:center">0</th><th style="text-align:center">1</th><th style="text-align:center">2</th><th style="text-align:center">3</th><th style="text-align:center">4</th><th style="text-align:center">5</th><th style="text-align:center">6</th><th style="text-align:center">7</th><th style="text-align:center">8</th><th style="text-align:center">9</th></tr></thead><tbody><tr><td style="text-align:center"></td><td style="text-align:center">48</td><td style="text-align:center">6</td><td style="text-align:center">57</td><td style="text-align:center">88</td><td style="text-align:center">60</td><td style="text-align:center">42</td><td style="text-align:center">83</td><td style="text-align:center">73</td><td style="text-align:center">88</td><td style="text-align:center">85</td></tr></tbody></table><p>数组变为上述这样。 i = 3; j = 7; X=72</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">再重复上面的步骤,先从后向前找,再从前向后找。</span><br><span class="line"></span><br><span class="line">从j开始向前找,当j=5,符合条件,将a[5]挖出填到上一个坑中,a[3] = a[5]; i++;</span><br><span class="line"></span><br><span class="line">从i开始向后找,当i=5时,由于i==j退出。</span><br><span class="line"></span><br><span class="line">此时,i = j = 5,而a[5]刚好又是上次挖的坑,因此将X填入a[5]。</span><br></pre></td></tr></table></figure><table><thead><tr><th style="text-align:center">index</th><th style="text-align:center">0</th><th style="text-align:center">1</th><th style="text-align:center">2</th><th style="text-align:center">3</th><th style="text-align:center">4</th><th style="text-align:center">5</th><th style="text-align:center">6</th><th style="text-align:center">7</th><th style="text-align:center">8</th><th style="text-align:center">9</th></tr></thead><tbody><tr><td style="text-align:center"></td><td style="text-align:center">48</td><td style="text-align:center">6</td><td style="text-align:center">57</td><td style="text-align:center">42</td><td style="text-align:center">60</td><td style="text-align:center">72</td><td style="text-align:center">83</td><td style="text-align:center">73</td><td style="text-align:center">88</td><td style="text-align:center">85</td></tr></tbody></table><p>可以看出a[5]前面的数字都小于它,a[5]后面的数字都大于它。因此再对a[0…4]和a[6…9]这二个子区间重复上述步骤就可以了。</p><h4 id="对挖坑填数进行总结"><a href="#对挖坑填数进行总结" class="headerlink" title="对挖坑填数进行总结"></a>对挖坑填数进行总结</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">1.i =L; j = R; 将基准数挖出形成第一个坑a[i]。</span><br><span class="line"></span><br><span class="line">2.j--由后向前找比它小的数,找到后挖出此数填前一个坑a[i]中。</span><br><span class="line"></span><br><span class="line">3.i++由前向后找比它大的数,找到后也挖出此数填到前一个坑a[j]中。</span><br><span class="line"></span><br><span class="line">4.再重复执行2,3二步,直到i==j,将基准数填入a[i]中。</span><br></pre></td></tr></table></figure><p>照着这个总结很容易实现挖坑填数的代码:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">int AdjustArray(int s[], int l, int r) //返回调整后基准数的位置 </span><br><span class="line">{ </span><br><span class="line"> int i = l, j = r; </span><br><span class="line"> int x = s[l]; //s[l]即s[i]就是第一个坑 </span><br><span class="line"> while (i < j) </span><br><span class="line"> { // 从右向左找小于x的数来填s[i] </span><br><span class="line"> while(i < j && s[j] >= x) </span><br><span class="line"> j--; </span><br><span class="line"> if(i < j) </span><br><span class="line"> { </span><br><span class="line"> s[i] = s[j]; //将s[j]填到s[i]中,s[j]就形成了一个新的坑 </span><br><span class="line"> i++; </span><br><span class="line"> } </span><br><span class="line"> // 从左向右找大于或等于x的数来填s[j] </span><br><span class="line"> while(i < j && s[i] < x) </span><br><span class="line"> i++; </span><br><span class="line"> if(i < j) </span><br><span class="line"> { </span><br><span class="line"> s[j] = s[i]; //将s[i]填到s[j]中,s[i]就形成了一个新的坑 </span><br><span class="line"> j--; </span><br><span class="line"> } </span><br><span class="line"> } </span><br><span class="line"> //退出时,i等于j。将x填到这个坑中。 </span><br><span class="line"> s[i] = x; </span><br><span class="line"> return i; </span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>再写分治法的代码:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">void quick_sort1(int s[], int l, int r) </span><br><span class="line">{ </span><br><span class="line"> if (l < r) </span><br><span class="line"> { </span><br><span class="line"> int i = AdjustArray(s, l, r);//先成挖坑填数法调整s[] </span><br><span class="line"> quick_sort1(s, l, i - 1); // 递归调用 </span><br><span class="line"> quick_sort1(s, i + 1, r); </span><br><span class="line"> } </span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>这样的代码显然不够简洁,对其组合整理下:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">void quick_sort(int s[], int l, int r) </span><br><span class="line">{ </span><br><span class="line"> if (l < r) </span><br><span class="line"> { </span><br><span class="line"> //Swap(s[l], s[(l + r) / 2]); //将中间的这个数和第一个数交换(以数组中间的数作为基准值!!) </span><br><span class="line"> int i = l, j = r, x = s[l]; </span><br><span class="line"> while (i < j) </span><br><span class="line"> { </span><br><span class="line"> while(i < j && s[j] >= x) // 从右向左找第一个小于x的数 </span><br><span class="line"> j--; </span><br><span class="line"> if(i < j) </span><br><span class="line"> s[i++] = s[j]; </span><br><span class="line"> </span><br><span class="line"> while(i < j && s[i] < x) // 从左向右找第一个大于等于x的数 </span><br><span class="line"> i++; </span><br><span class="line"> if(i < j) </span><br><span class="line"> s[j--] = s[i]; </span><br><span class="line"> } </span><br><span class="line"> s[i] = x; </span><br><span class="line"> quick_sort(s, l, i - 1); // 递归调用 </span><br><span class="line"> quick_sort(s, i + 1, r); </span><br><span class="line"> } </span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p><strong>快速排序还有很多改进版本,如随机选择基准数,区间内数据较少时直接用另的方法排序以减小递归深度。</strong></p><p><code>注1,有的书上是以中间的数作为基准数的,要实现这个方便非常方便,直接将中间的数和第一个数进行交换就可以了。</code></p><ul><li>归并排序</li><li>如果我们要将一副扑克按照数字大小排序。此前已经有两个人分别将其中的一半排好顺序。</li><li>那么我们可以将这两堆扑克向上放好,假设小的牌在上面。此时,我们将看到牌堆中最上的两张牌。</li><li>我们取两张牌中小的那张取出放在手中。两个牌堆中又是两张牌暴露在最上面,继续取小的那张放在手中……</li><li>直到所有的牌都放入手中,那么整副牌就排好顺序了。这就是归并排序。</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><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">var generateTestData = require('https://21cm.js.org/lib/TestDataGenerator');</span><br><span class="line"> * js数组方法实现merge非常简洁,但是效率不高,见通用版本的merge方法!!!</span><br><span class="line">function merge(left, right) {</span><br><span class="line"> var result = [];</span><br><span class="line"> while (left.length > 0 && right.length > 0) {</span><br><span class="line"> if (left[0] < right[0]) {</span><br><span class="line"> result.push(left.shift());</span><br><span class="line"> } else {</span><br><span class="line"> result.push(right.shift());</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> return result.concat(left).concat(right);</span><br><span class="line">}</span><br><span class="line">function mergeSort(items) {</span><br><span class="line"> * 此句为递归结束条件,绝对不能遗漏!!!!</span><br><span class="line"> if (items.length == 1) {</span><br><span class="line"> return items;</span><br><span class="line"> }</span><br><span class="line"> var middle = Math.floor(items.length / 2),</span><br><span class="line"> left = items.slice(0, middle),</span><br><span class="line"> right = items.slice(middle);</span><br><span class="line"> return merge(mergeSort(left), mergeSort(right));</span><br><span class="line">}</span><br><span class="line">var data = generateTestData(300000);</span><br><span class="line">// console.log(data);</span><br><span class="line">var start = new Date().getTime();</span><br><span class="line">console.log('start sorting....');</span><br><span class="line">var result = mergeSort(data);</span><br><span class="line">var end = new Date().getTime();</span><br><span class="line">console.log('耗时: ' + (end - start) + ' ms');</span><br><span class="line">// console.log(result);</span><br></pre></td></tr></table></figure><ul><li>归并排序通用版本</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line">var generateTestData = require('https://21cm.js.org/lib/TestDataGenerator');</span><br><span class="line">function merge(a1, a2) {</span><br><span class="line"> var result = [];</span><br><span class="line"> var i = 0,</span><br><span class="line"> j = 0,</span><br><span class="line"> l1 = a1.length,</span><br><span class="line"> l2 = a2.length;</span><br><span class="line"> while (i < l1 && j < l2) {</span><br><span class="line"> if (a1[i] < a2[j]) {</span><br><span class="line"> result.push(a1[i++]);</span><br><span class="line"> } else {</span><br><span class="line"> result.push(a2[j++]);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> if (i < l1) {</span><br><span class="line"> for (; i < l1; i++) {</span><br><span class="line"> result.push(a1[i]);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> if (j < l2) {</span><br><span class="line"> for (; j < l2; j++) {</span><br><span class="line"> result.push(a2[j]);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> return result;</span><br><span class="line">}</span><br><span class="line">function mergeSort(data) {</span><br><span class="line"> /***</span><br><span class="line"> * 此句为递归结束条件,绝对不能遗漏!!!!</span><br><span class="line"> */</span><br><span class="line"> if (data.length === 1) {</span><br><span class="line"> return data;</span><br><span class="line"> }</span><br><span class="line"> var middle = Math.floor(data.length / 2);</span><br><span class="line"> var left = data.slice(0, middle),</span><br><span class="line"> right = data.slice(middle);</span><br><span class="line"> return merge(mergeSort(left), mergeSort(right));</span><br><span class="line">}</span><br><span class="line">var data = generateTestData(3000000);</span><br><span class="line">// console.log(data);</span><br><span class="line">var start = new Date().getTime();</span><br><span class="line">console.log('start sorting....');</span><br><span class="line">var result = mergeSort(data);</span><br><span class="line">var end = new Date().getTime();</span><br><span class="line">console.log('耗时: ' + (end - start) + ' ms');</span><br><span class="line">// console.log(result);</span><br></pre></td></tr></table></figure><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。</span><br></pre></td></tr></table></figure><p>首先考虑下如何将将二个有序数列合并。这个非常简单,只要从比较二个数列的第一个数,谁小就先取谁,<br>取了后就在对应数列中删除这个数。然后再进行比较,如果有数列为空,那直接将另一个数列的数据依次取出即可。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">//将有序数组a[]和b[]合并到c[]中 </span><br><span class="line">void MemeryArray(int a[], int n, int b[], int m, int c[]) </span><br><span class="line">{ </span><br><span class="line"> int i, j, k; </span><br><span class="line"> i = j = k = 0; </span><br><span class="line"> while (i < n && j < m) </span><br><span class="line"> { </span><br><span class="line"> if (a[i] < b[j]) </span><br><span class="line"> c[k++] = a[i++]; </span><br><span class="line"> else </span><br><span class="line"> c[k++] = b[j++]; </span><br><span class="line"> } </span><br><span class="line"> </span><br><span class="line"> while (i < n) </span><br><span class="line"> c[k++] = a[i++]; </span><br><span class="line"> </span><br><span class="line"> while (j < m) </span><br><span class="line"> c[k++] = b[j++]; </span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>可以看出合并有序数列的效率是比较高的,可以达到O(n)。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">解决了上面的合并有序数列问题,再来看归并排序,其的基本思路就是将数组分成二组A,B,如果这二组组内的数据都是有序的,</span><br><span class="line">那么就可以很方便的将这二组数据进行排序。如何让这二组组内数据有序了?</span><br><span class="line"></span><br><span class="line">可以将A,B组各自再分成二组。依次类推,当分出来的小组只有一个数据时,可以认为这个小组组内已经达到了有序,</span><br><span class="line">然后再合并相邻的二个小组就可以了。这样通过先递归的分解数列,再合并数列就完成了归并排序。</span><br></pre></td></tr></table></figure><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line">//将有二个有序数列a[first...mid]和a[mid...last]合并。 </span><br><span class="line">void mergearray(int a[], int first, int mid, int last, int temp[]) </span><br><span class="line">{ </span><br><span class="line"> int i = first, j = mid + 1; </span><br><span class="line"> int m = mid, n = last; </span><br><span class="line"> int k = 0; </span><br><span class="line"> </span><br><span class="line"> while (i <= m && j <= n) </span><br><span class="line"> { </span><br><span class="line"> if (a[i] <= a[j]) </span><br><span class="line"> temp[k++] = a[i++]; </span><br><span class="line"> else </span><br><span class="line"> temp[k++] = a[j++]; </span><br><span class="line"> } </span><br><span class="line"> </span><br><span class="line"> while (i <= m) </span><br><span class="line"> temp[k++] = a[i++]; </span><br><span class="line"> </span><br><span class="line"> while (j <= n) </span><br><span class="line"> temp[k++] = a[j++]; </span><br><span class="line"> </span><br><span class="line"> for (i = 0; i < k; i++) </span><br><span class="line"> a[first + i] = temp[i]; </span><br><span class="line">} </span><br><span class="line"></span><br><span class="line">void mergesort(int a[], int first, int last, int temp[]) </span><br><span class="line">{ </span><br><span class="line"> if (first < last) </span><br><span class="line"> { </span><br><span class="line"> int mid = (first + last) / 2; </span><br><span class="line"> mergesort(a, first, mid, temp); //左边有序 </span><br><span class="line"> mergesort(a, mid + 1, last, temp); //右边有序 </span><br><span class="line"> mergearray(a, first, mid, last, temp); //再将二个有序数列合并 </span><br><span class="line"> } </span><br><span class="line">} </span><br><span class="line"> </span><br><span class="line">bool MergeSort(int a[], int n) </span><br><span class="line">{ </span><br><span class="line"> int *p = new int[n]; </span><br><span class="line"> if (p == NULL) </span><br><span class="line"> return false; </span><br><span class="line"> mergesort(a, 0, n - 1, p); </span><br><span class="line"> delete[] p; </span><br><span class="line"> return true; </span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">归并排序的效率是比较高的,设数列长为N,将数列分开成小数列一共要logN步,每步都是一个合并有序数列的过程,</span><br><span class="line">时间复杂度可以记为O(N),故一共为O(N*logN)。因为归并排序每次都是在相邻的数据中进行操作,</span><br><span class="line">所以归并排序在O(N*logN)的几种排序方法(快速排序,归并排序,希尔排序,堆排序)也是效率比较高的。</span><br></pre></td></tr></table></figure><ul><li>堆排序<br>1.堆<br>堆实际上是一棵完全二叉树,其任何一非叶节点满足性质:<br><code>Key[i]<=key[2i+1]&&Key[i]<=key[2i+2]或者Key[i]>=Key[2i+1]&&key>=key[2i+2]</code><br>即任何一非叶节点的关键字不大于或者不小于其左右孩子节点的关键字。<br>堆分为大顶堆和小顶堆,满足<code>Key[i]>=Key[2i+1]&&key>=key[2i+2]</code>称为大顶堆,<br>满足<code>Key[i]<=key[2i+1]&&Key[i]<=key[2i+2]</code>称为小顶堆。<br>由上述性质可知大顶堆的堆顶的关键字肯定是所有关键字中最大的,小顶堆的堆顶的关键字是所有关键字中最小的。<br>2.堆排序的思想<br>利用大顶堆(小顶堆)堆顶记录的是最大关键字(最小关键字)这一特性,使得每次从无序中选择最大记录(最小记录)变得简单。<br>其基本思想为(大顶堆):<br>1)将初始待排序关键字序列(R1,R2….Rn)构建成大顶堆,此堆为初始的无须区;<br>2)将堆顶元素<code>R[1]</code>与最后一个元素<code>R[n]</code>交换,此时得到新的无序区<code>(R1,R2,......Rn-1)</code>和新的有序区<code>(Rn)</code>,<br>且满足<code>R[1,2...n-1]<=R[n]</code>;<br>3)由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区<code>(R1,R2,......Rn-1)</code>调整为新堆,<br>然后再次将<code>R[1]</code>与无序区最后一个元素交换,得到新的无序区<code>(R1,R2....Rn-2)</code>和新的有序区<code>(Rn-1,Rn)</code>。<br>不断重复此过程直到有序区的元素个数为<code>n-1</code>,则整个排序过程完成。<br>操作过程如下:<br>1)初始化堆:将<code>R[1..n]</code>构造为堆;<br>2)将当前无序区的堆顶元素<code>R[1]</code>同该区间的最后一个记录交换,然后将新的无序区调整为新的堆。<br>因此对于堆排序,最重要的两个操作就是构造初始堆和调整堆,其实构造初始堆事实上也是调整堆的过程, 只不过构造初始堆是对所有的非叶节点都进行调整。</li><li>堆排序</li><li>堆排序适合于数据量非常大的场合(百万数据)。</li><li>堆排序不需要大量的递归或者多维的暂存数组。这对于数据量非常巨大的序列是合适的。</li><li>比如超过数百万条记录,因为快速排序,归并排序都使用递归来设计算法,在数据量非常大的时候,可能会发生堆栈溢出错误。</li><li>堆排序会将所有的数据建成一个堆,最大的数据在堆顶,然后将堆顶数据和序列的最后一个数据交换。</li><li>接下来再次重建堆,交换数据,依次下去,就可以排序所有的数据。</li><li>若在输出堆顶的最小值之后,使得剩余n-1个元素的序列重又建成一个堆,则得到n个元素的次小值。</li><li>如此反复执行,便能得到一个有序序列,这个过程称之为堆排序。</li><li>实现堆排序需要解决两个问题:<br> 1.如何由一个无序序列建成一个堆?<br> 2.如何在输出堆顶元素之后,调整剩余元素成为一个新的堆?<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">var generateTestData = require('https://21cm.js.org/lib/TestDataGenerator');</span><br><span class="line">/*方法说明:调整堆,维护堆的性质</span><br><span class="line"> @param arr 数组</span><br><span class="line"> @param x 数组下标</span><br><span class="line"> @param len 堆大小*/</span><br><span class="line">function adjustHeap(arr, x, len) {</span><br><span class="line"> var l = 2 * x, r = 2 * x + 1, largest = x, temp;</span><br><span class="line"> if (l < len && arr[l] > arr[largest]) {</span><br><span class="line"> largest = l;</span><br><span class="line"> }</span><br><span class="line"> if (r < len && arr[r] > arr[largest]) {</span><br><span class="line"> largest = r;</span><br><span class="line"> }</span><br><span class="line"> if (largest != x) {</span><br><span class="line"> temp = arr[x];</span><br><span class="line"> arr[x] = arr[largest];</span><br><span class="line"> arr[largest] = temp;</span><br><span class="line"> adjustHeap(arr, largest, len);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ul><p>/*方法说明:堆排序<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">function heapSort(array) {</span><br><span class="line"> //建堆</span><br><span class="line"> var heapSize = array.length, temp;</span><br><span class="line"> for (var i = Math.floor(heapSize / 2); i >= 0; i--) {</span><br><span class="line"> adjustHeap(array, i, heapSize);</span><br><span class="line"> }</span><br><span class="line"> //堆排序</span><br><span class="line"> for (var j = heapSize - 1; j >= 1; j--) {</span><br><span class="line"> temp = array[0];</span><br><span class="line"> array[0] = array[j];</span><br><span class="line"> array[j] = temp;</span><br><span class="line"> adjustHeap(array, 0, --heapSize);</span><br><span class="line"> }</span><br><span class="line"> return array;</span><br><span class="line">}</span><br><span class="line">var data = generateTestData(20000);</span><br><span class="line">// console.log(data);</span><br><span class="line">var start = new Date().getTime();</span><br><span class="line">console.log('start sorting....');</span><br><span class="line">var result = heapSort(data);</span><br><span class="line">var end = new Date().getTime();</span><br><span class="line">console.log('耗时: ' + (end - start) + ' ms');</span><br><span class="line">// console.log(result);</span><br></pre></td></tr></table></figure></p>]]></content>
<summary type="html">
<ul>
<li>排序算法分析比较</li>
</ul>
<h4 id="1-快速排序(QuickSort)"><a href="#1-快速排序(QuickSort)" class="headerlink" title="1 快速排序(QuickSort)"></a>1 快速排序
</summary>
<category term="前端" scheme="https://21cm.js.org/categories/%E5%89%8D%E7%AB%AF/"/>
<category term="前端算法" scheme="https://21cm.js.org/categories/%E5%89%8D%E7%AB%AF/%E5%89%8D%E7%AB%AF%E7%AE%97%E6%B3%95/"/>
<category term="javascript" scheme="https://21cm.js.org/tags/javascript/"/>
<category term="排序" scheme="https://21cm.js.org/tags/%E6%8E%92%E5%BA%8F/"/>
<category term="冒泡排序" scheme="https://21cm.js.org/tags/%E5%86%92%E6%B3%A1%E6%8E%92%E5%BA%8F/"/>
<category term="选择排序" scheme="https://21cm.js.org/tags/%E9%80%89%E6%8B%A9%E6%8E%92%E5%BA%8F/"/>
<category term="插入排序" scheme="https://21cm.js.org/tags/%E6%8F%92%E5%85%A5%E6%8E%92%E5%BA%8F/"/>
<category term="希尔排序" scheme="https://21cm.js.org/tags/%E5%B8%8C%E5%B0%94%E6%8E%92%E5%BA%8F/"/>
<category term="快速排序" scheme="https://21cm.js.org/tags/%E5%BF%AB%E9%80%9F%E6%8E%92%E5%BA%8F/"/>
<category term="归并排序" scheme="https://21cm.js.org/tags/%E5%BD%92%E5%B9%B6%E6%8E%92%E5%BA%8F/"/>
<category term="堆排序" scheme="https://21cm.js.org/tags/%E5%A0%86%E6%8E%92%E5%BA%8F/"/>
</entry>
<entry>
<title>前端算法之查找算法</title>
<link href="https://21cm.js.org/2018/05/28/js-lookup/"/>
<id>https://21cm.js.org/2018/05/28/js-lookup/</id>
<published>2018-05-27T16:00:00.000Z</published>
<updated>2018-05-27T17:05:07.307Z</updated>
<content type="html"><![CDATA[<ul><li>顺序查找</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 23, 45, 55, 44, 22, 33];</span><br><span class="line">function find(array, data) {</span><br><span class="line"> var length = array.length;</span><br><span class="line"> for (var i = 0; i < length; i++) {</span><br><span class="line"> if (data === array[i]) {</span><br><span class="line"> return i;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> if (i === length) {</span><br><span class="line"> return -1;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line">console.log(find(arr, 2)); //1 </span><br><span class="line">console.log(find(arr, 33)); //14</span><br><span class="line">console.log(find(arr, 100)); //-1</span><br></pre></td></tr></table></figure><ul><li>二分法查找:适用于有序的数据</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">var arr = [];</span><br><span class="line">for (var m = 1; m <= 5; m++) {</span><br><span class="line"> arr.push(m);</span><br><span class="line">}</span><br><span class="line">console.log(arr); //1,2,3,4,5</span><br><span class="line"></span><br><span class="line">function binarySearch(array, data) {</span><br><span class="line"> var l = array.length;</span><br><span class="line"> var low = 0,</span><br><span class="line"> high = l - 1;</span><br><span class="line"> while (low <= high) {</span><br><span class="line"> var middle = Math.floor((low + high) / 2);</span><br><span class="line"> if (data < array[middle]) {</span><br><span class="line"> high = middle - 1;</span><br><span class="line"> } else if (data > array[middle]) {</span><br><span class="line"> low = middle + 1;</span><br><span class="line"> } else {</span><br><span class="line"> return middle;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> return -1;</span><br><span class="line">}</span><br><span class="line">console.log(binarySearch(arr, 50)); //49</span><br><span class="line">console.log(binarySearch(arr, 33)); //32</span><br><span class="line">console.log(binarySearch(arr, 1)); //0</span><br><span class="line">console.log(binarySearch(arr, 100)); //99</span><br><span class="line">console.log(binarySearch(arr, 1000)); //-1</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<ul>
<li>顺序查找</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line
</summary>
<category term="前端" scheme="https://21cm.js.org/categories/%E5%89%8D%E7%AB%AF/"/>
<category term="前端算法" scheme="https://21cm.js.org/categories/%E5%89%8D%E7%AB%AF/%E5%89%8D%E7%AB%AF%E7%AE%97%E6%B3%95/"/>
<category term="javascript" scheme="https://21cm.js.org/tags/javascript/"/>
<category term="查找算法-线性查找" scheme="https://21cm.js.org/tags/%E6%9F%A5%E6%89%BE%E7%AE%97%E6%B3%95-%E7%BA%BF%E6%80%A7%E6%9F%A5%E6%89%BE/"/>
<category term="查找算法-二分查找" scheme="https://21cm.js.org/tags/%E6%9F%A5%E6%89%BE%E7%AE%97%E6%B3%95-%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE/"/>
</entry>
<entry>
<title>数据结构与算法之斐波那契数列</title>
<link href="https://21cm.js.org/2018/05/27/fibonacci/"/>
<id>https://21cm.js.org/2018/05/27/fibonacci/</id>
<published>2018-05-27T05:00:00.000Z</published>
<updated>2018-05-27T16:15:22.222Z</updated>
<content type="html"><![CDATA[<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"> function fibonacci(n) {</span><br><span class="line"> //递归,速度慢的不行,n到50几乎就无法算出,可能栈溢出!!!</span><br><span class="line">// if (n <= 0) {</span><br><span class="line">// return 0;</span><br><span class="line">// }</span><br><span class="line">//</span><br><span class="line">// if (n == 1) {</span><br><span class="line">// return 1;</span><br><span class="line">// }</span><br><span class="line"></span><br><span class="line">// return fibonacci(n - 1) + fibonacci(n - 2);</span><br><span class="line"></span><br><span class="line"> if (n <= 0) {</span><br><span class="line"> return 0;</span><br><span class="line"> }</span><br><span class="line"> if (n == 1) {</span><br><span class="line"> return 1;</span><br><span class="line"> }</span><br><span class="line"> var n1 = 0, n2 = 1, result;</span><br><span class="line"> for (var i = 2; i <= n; i++) {</span><br><span class="line"> result = n1 + n2;</span><br><span class="line"> n1 = n2;</span><br><span class="line"> n2 = result;</span><br><span class="line"> }</span><br><span class="line"> return result;</span><br><span class="line"> }</span><br><span class="line"> console.log(fibonacci(200));</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class
</summary>
<category term="数据结构与算法" scheme="https://21cm.js.org/categories/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/"/>
<category term="javascript" scheme="https://21cm.js.org/tags/javascript/"/>
<category term="fibonacci" scheme="https://21cm.js.org/tags/fibonacci/"/>
<category term="斐波那契数列" scheme="https://21cm.js.org/tags/%E6%96%90%E6%B3%A2%E9%82%A3%E5%A5%91%E6%95%B0%E5%88%97/"/>
</entry>
<entry>
<title>前端知识点总结之javascript-循环建议</title>
<link href="https://21cm.js.org/2018/05/27/js-unfor...in/"/>
<id>https://21cm.js.org/2018/05/27/js-unfor...in/</id>
<published>2018-05-27T04:10:00.000Z</published>
<updated>2018-05-27T04:12:11.803Z</updated>
<content type="html"><![CDATA[<h4 id="不要对数组使用for…in循环"><a href="#不要对数组使用for…in循环" class="headerlink" title="不要对数组使用for…in循环!!!"></a>不要对数组使用for…in循环!!!</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">for (var index in myArray) { // 千万别这样做</span><br><span class="line"> console.log(myArray[index]);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这绝对是一个糟糕的选择,为什么呢?</p><ul><li>在这段代码中,赋给index的值不是实际的数字,而是字符串“0”、“1”、“2”,此时很可能在无意之间进行字符串算数计算,例如:“2” + 1 == “21”,这给编码过程带来极大的不便。</li><li>作用于数组的for-in循环体除了遍历数组元素外,还会遍历自定义属性。举个例子,如果你的数组中有一个可枚举属性myArray.name,循环将额外执行一次,遍历到名为“name”的索引。就连数组原型链上的属性都能被访问到。</li><li>最让人震惊的是,在某些情况下,这段代码可能按照随机顺序遍历数组元素。</li></ul><p><code>简而言之,for-in是为普通对象设计的,你可以遍历得到字符串类型的键,因此不适用于数组遍历。</code></p>]]></content>
<summary type="html">
<h4 id="不要对数组使用for…in循环"><a href="#不要对数组使用for…in循环" class="headerlink" title="不要对数组使用for…in循环!!!"></a>不要对数组使用for…in循环!!!</h4><figure class="
</summary>
<category term="前端" scheme="https://21cm.js.org/categories/%E5%89%8D%E7%AB%AF/"/>
<category term="javascript" scheme="https://21cm.js.org/tags/javascript/"/>
<category term="javascript-循环" scheme="https://21cm.js.org/tags/javascript-%E5%BE%AA%E7%8E%AF/"/>
</entry>
<entry>
<title>前端知识点总结之javascript-严格模式</title>
<link href="https://21cm.js.org/2018/05/27/js-strict/"/>
<id>https://21cm.js.org/2018/05/27/js-strict/</id>
<published>2018-05-27T04:00:00.000Z</published>
<updated>2018-05-27T04:10:01.427Z</updated>
<content type="html"><![CDATA[<h4 id="说说严格模式的限制"><a href="#说说严格模式的限制" class="headerlink" title="说说严格模式的限制"></a>说说严格模式的限制</h4><p>严格模式主要有以下限制:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line">变量必须声明后再使用</span><br><span class="line"></span><br><span class="line">函数的参数不能有同名属性,否则报错</span><br><span class="line"></span><br><span class="line">不能使用with语句</span><br><span class="line"></span><br><span class="line">不能对只读属性赋值,否则报错</span><br><span class="line"></span><br><span class="line">不能使用前缀0表示八进制数,否则报错</span><br><span class="line"></span><br><span class="line">不能删除不可删除的属性,否则报错</span><br><span class="line"></span><br><span class="line">不能删除变量delete prop,会报错,只能删除属性delete global[prop]</span><br><span class="line"></span><br><span class="line">eval不会在它的外层作用域引入变量</span><br><span class="line"></span><br><span class="line">eval和arguments不能被重新赋值</span><br><span class="line"></span><br><span class="line">arguments不会自动反映函数参数的变化</span><br><span class="line"></span><br><span class="line">不能使用arguments.callee</span><br><span class="line"></span><br><span class="line">不能使用arguments.caller</span><br><span class="line"></span><br><span class="line">禁止this指向全局对象</span><br><span class="line"></span><br><span class="line">不能使用fn.caller和fn.arguments获取函数调用的堆栈</span><br><span class="line"></span><br><span class="line">增加了保留字(比如protected、static和interface)</span><br></pre></td></tr></table></figure></p><p>设立”严格模式”的目的,主要有以下几个:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为;</span><br><span class="line"></span><br><span class="line">消除代码运行的一些不安全之处,保证代码运行的安全;</span><br><span class="line"></span><br><span class="line">提高编译器效率,增加运行速度;</span><br><span class="line"></span><br><span class="line">为未来新版本的Javascript做好铺垫。</span><br></pre></td></tr></table></figure></p><p><code>注:经过测试IE6,7,8,9均不支持严格模式。</code></p>]]></content>
<summary type="html">
<h4 id="说说严格模式的限制"><a href="#说说严格模式的限制" class="headerlink" title="说说严格模式的限制"></a>说说严格模式的限制</h4><p>严格模式主要有以下限制:<br><figure class="highlight p
</summary>
<category term="前端" scheme="https://21cm.js.org/categories/%E5%89%8D%E7%AB%AF/"/>
<category term="javascript" scheme="https://21cm.js.org/tags/javascript/"/>
<category term="javascript-严格模式" scheme="https://21cm.js.org/tags/javascript-%E4%B8%A5%E6%A0%BC%E6%A8%A1%E5%BC%8F/"/>
</entry>
<entry>
<title>前端知识点总结之javascript-new操作符</title>
<link href="https://21cm.js.org/2018/05/27/js-new/"/>
<id>https://21cm.js.org/2018/05/27/js-new/</id>
<published>2018-05-27T02:50:00.000Z</published>
<updated>2018-05-27T04:08:01.384Z</updated>
<content type="html"><![CDATA[<h4 id="new操作符具体干了什么呢"><a href="#new操作符具体干了什么呢" class="headerlink" title="new操作符具体干了什么呢?"></a>new操作符具体干了什么呢?</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"> 1、创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。</span><br><span class="line"></span><br><span class="line"> 2、属性和方法被加入到 this 引用的对象中。</span><br><span class="line"></span><br><span class="line"> 3、新创建的对象由 this 所引用,并且最后隐式的返回 this 。</span><br><span class="line"></span><br><span class="line">var obj = {};</span><br><span class="line"></span><br><span class="line">obj.__proto__ = Base.prototype;</span><br><span class="line"></span><br><span class="line">Base.call(obj);</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<h4 id="new操作符具体干了什么呢"><a href="#new操作符具体干了什么呢" class="headerlink" title="new操作符具体干了什么呢?"></a>new操作符具体干了什么呢?</h4><figure class="highlight pl
</summary>
<category term="javascript" scheme="https://21cm.js.org/tags/javascript/"/>
<category term="javascript-new" scheme="https://21cm.js.org/tags/javascript-new/"/>
</entry>
<entry>
<title>前端知识点总结之javascript-null和undefined的区别?</title>
<link href="https://21cm.js.org/2018/05/27/js-null&&js-undefined/"/>
<id>https://21cm.js.org/2018/05/27/js-null&&js-undefined/</id>
<published>2018-05-27T02:40:00.000Z</published>
<updated>2018-05-27T04:06:49.001Z</updated>
<content type="html"><![CDATA[<h4 id="null和undefined的区别?"><a href="#null和undefined的区别?" class="headerlink" title="null和undefined的区别?"></a>null和undefined的区别?</h4><p>null是一个表示”无”的对象,转为数值时为0;undefined是一个表示”无”的原始值,转为数值时为NaN。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">当声明的变量还未被初始化时,变量的默认值为undefined。</span><br><span class="line"></span><br><span class="line">null用来表示尚未存在的对象,常用来表示函数企图返回一个不存在的对象。</span><br><span class="line"></span><br><span class="line">undefined表示"缺少值",就是此处应该有一个值,但是还没有定义。典型用法是:</span><br><span class="line"></span><br><span class="line">(1)变量被声明了,但没有赋值时,就等于undefined。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">(2) 调用函数时,应该提供的参数没有提供,该参数等于undefined。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">(3)对象没有赋值的属性,该属性的值为undefined。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">(4)函数没有返回值时,默认返回undefined。</span><br></pre></td></tr></table></figure></p><p>null表示”没有对象”,即该处不应该有值。典型用法是:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">(1) 作为函数的参数,表示该函数的参数不是对象。</span><br><span class="line"></span><br><span class="line">(2) 作为对象原型链的终点。</span><br></pre></td></tr></table></figure></p>]]></content>
<summary type="html">
<h4 id="null和undefined的区别?"><a href="#null和undefined的区别?" class="headerlink" title="null和undefined的区别?"></a>null和undefined的区别?</h4><p>null是一
</summary>
<category term="javascript" scheme="https://21cm.js.org/tags/javascript/"/>
<category term="javascript-null" scheme="https://21cm.js.org/tags/javascript-null/"/>
<category term="javascript-undefined" scheme="https://21cm.js.org/tags/javascript-undefined/"/>
</entry>
<entry>
<title>前端知识点总结之javascript-ready && javascript-onload</title>
<link href="https://21cm.js.org/2018/05/27/js-ready&&js-onload/"/>
<id>https://21cm.js.org/2018/05/27/js-ready&&js-onload/</id>
<published>2018-05-27T02:30:00.000Z</published>
<updated>2018-05-27T04:05:15.807Z</updated>
<content type="html"><![CDATA[<figure class="highlight plain"><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">jquery中$(document).ready()的作用类似于传统JavaScript中的window.onload方法,</span><br><span class="line">不过与window.onload方法还是有区别的。</span><br></pre></td></tr></table></figure><h4 id="1-执行时间"><a href="#1-执行时间" class="headerlink" title="1.执行时间"></a>1.执行时间</h4><figure class="highlight plain"><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">window.onload必须等到页面内包括图片的所有元素加载完毕后才能执行。 </span><br><span class="line">$(document).ready()是DOM结构绘制完毕后就执行,不必等到加载完毕。</span><br></pre></td></tr></table></figure><h4 id="2-编写个数不同"><a href="#2-编写个数不同" class="headerlink" title="2.编写个数不同"></a>2.编写个数不同</h4><figure class="highlight plain"><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">window.onload不能同时编写多个,如果有多个window.onload方法,只会执行一个 </span><br><span class="line">$(document).ready()可以同时编写多个,并且都可以得到执行</span><br></pre></td></tr></table></figure><h4 id="3-简化写法-针对jquery"><a href="#3-简化写法-针对jquery" class="headerlink" title="3.简化写法(针对jquery)"></a>3.简化写法(针对jquery)</h4><figure class="highlight plain"><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">window.onload没有简化写法 </span><br><span class="line">$(document).ready(function(){})可以简写成$(function(){});</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td>
</summary>
<category term="javascript" scheme="https://21cm.js.org/tags/javascript/"/>
<category term="javascript-ready" scheme="https://21cm.js.org/tags/javascript-ready/"/>
<category term="javascript-onload" scheme="https://21cm.js.org/tags/javascript-onload/"/>
</entry>
<entry>
<title>前端知识点总结之javascript-attribute && javascript-property</title>
<link href="https://21cm.js.org/2018/05/27/js-attribute&&js-property/"/>
<id>https://21cm.js.org/2018/05/27/js-attribute&&js-property/</id>
<published>2018-05-27T02:10:00.000Z</published>
<updated>2018-05-27T04:01:16.029Z</updated>
<content type="html"><![CDATA[<h4 id="attribute和property的区别是什么?"><a href="#attribute和property的区别是什么?" class="headerlink" title="attribute和property的区别是什么?"></a>attribute和property的区别是什么?</h4><figure class="highlight plain"><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">attribute是dom元素在文档中作为html标签拥有的属性;</span><br><span class="line">property就是dom元素在js中作为对象拥有的属性。</span><br></pre></td></tr></table></figure><p>所以:<br><figure class="highlight plain"><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">对于html的标准属性来说,attribute和property是同步的,是会自动更新的,</span><br><span class="line">但是对于自定义的属性来说,他们是不同步的.</span><br></pre></td></tr></table></figure></p>]]></content>
<summary type="html">
<h4 id="attribute和property的区别是什么?"><a href="#attribute和property的区别是什么?" class="headerlink" title="attribute和property的区别是什么?"></a>attribute和p
</summary>
<category term="javascript" scheme="https://21cm.js.org/tags/javascript/"/>
<category term="javascript-attribute" scheme="https://21cm.js.org/tags/javascript-attribute/"/>
<category term="javascript-property" scheme="https://21cm.js.org/tags/javascript-property/"/>
</entry>
<entry>
<title>前端知识点总结之javascript-XSS &&javascript-csrf</title>
<link href="https://21cm.js.org/2018/05/27/js-xss&&ja-csrf/"/>
<id>https://21cm.js.org/2018/05/27/js-xss&&ja-csrf/</id>
<published>2018-05-27T02:00:00.000Z</published>
<updated>2018-05-27T03:56:27.545Z</updated>
<content type="html"><![CDATA[<h4 id="XSS原理及防范"><a href="#XSS原理及防范" class="headerlink" title="XSS原理及防范"></a>XSS原理及防范</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">Xss(cross-site scripting)攻击指的是攻击者往Web页面里插入恶意 html标签或者javascript代码。</span><br><span class="line">比如:攻击者在论坛中放一个看似安全的链接,骗取用户点击后,窃取cookie中的用户私密信息;或者攻击者在论坛中加一个恶意表单,</span><br><span class="line">当用户提交表单的时候,却把信息传送到攻击者的服务器中,而不是用户原本以为的信任站点。</span><br><span class="line"></span><br><span class="line">XSS防范方法</span><br><span class="line">首先代码里对用户输入的地方和变量都需要仔细检查长度和对”<”,”>”,”;”,”’”等字符做过滤;</span><br><span class="line">其次任何内容写到页面之前都必须加以encode,避免不小心把html tag 弄出来。这一个层面做好,至少可以堵住超过一半的XSS 攻击。</span><br><span class="line">首先,避免直接在cookie 中泄露用户隐私,例如email、密码等等。</span><br><span class="line">其次,通过使cookie 和系统ip 绑定来降低cookie 泄露后的危险。这样攻击者得到的cookie 没有实际价值,不可能拿来重放。</span><br><span class="line">如果网站不需要再浏览器端对cookie 进行操作,可以在Set-Cookie 末尾加上HttpOnly 来防止javascript 代码直接获取cookie 。</span><br><span class="line">尽量采用POST 而非GET 提交表单</span><br></pre></td></tr></table></figure><h4 id="XSS与CSRF有什么区别吗?"><a href="#XSS与CSRF有什么区别吗?" class="headerlink" title="XSS与CSRF有什么区别吗?"></a>XSS与CSRF有什么区别吗?</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">XSS是获取信息,不需要提前知道其他用户页面的代码和数据包。CSRF是代替用户完成指定的动作,需要知道其他用户页面的代码和数据包。</span><br></pre></td></tr></table></figure><h5 id="要完成一次CSRF攻击,受害者必须依次完成两个步骤:"><a href="#要完成一次CSRF攻击,受害者必须依次完成两个步骤:" class="headerlink" title="要完成一次CSRF攻击,受害者必须依次完成两个步骤:"></a>要完成一次CSRF攻击,受害者必须依次完成两个步骤:</h5><figure class="highlight plain"><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">登录受信任网站A,并在本地生成Cookie。</span><br><span class="line">在不登出A的情况下,访问危险网站B。</span><br></pre></td></tr></table></figure><h4 id="CSRF的防御"><a href="#CSRF的防御" class="headerlink" title="CSRF的防御"></a>CSRF的防御</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">服务端的CSRF方式方法很多样,但总的思想都是一致的,就是</span><br><span class="line">1. 在客户端页面增加伪随机数。</span><br><span class="line">2. 通过验证码的方法</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<h4 id="XSS原理及防范"><a href="#XSS原理及防范" class="headerlink" title="XSS原理及防范"></a>XSS原理及防范</h4><figure class="highlight plain"><table><tr><td cl
</summary>
<category term="javascript" scheme="https://21cm.js.org/tags/javascript/"/>
<category term="javascript-xss" scheme="https://21cm.js.org/tags/javascript-xss/"/>
<category term="javascript-csrf" scheme="https://21cm.js.org/tags/javascript-csrf/"/>
</entry>
<entry>
<title>前端知识点总结之javascript-缓存</title>
<link href="https://21cm.js.org/2018/05/27/js-cache/"/>
<id>https://21cm.js.org/2018/05/27/js-cache/</id>
<published>2018-05-27T01:00:00.000Z</published>
<updated>2018-05-27T03:32:30.450Z</updated>
<content type="html"><![CDATA[<h4 id="浏览器缓存的优点有:"><a href="#浏览器缓存的优点有:" class="headerlink" title="浏览器缓存的优点有:"></a>浏览器缓存的优点有:</h4><ul><li>减少了冗余的数据传输,节省了网费</li><li>减少了服务器的负担,大大提升了网站的性能</li><li>加快了客户端加载网页的速度<br>在前端开发面试中,浏览器缓存是web性能优化面试题中很重要的一个知识点,从而说明浏览器缓存是提升web性能的一大利器,<br>但是浏览器缓存如果使用不当,也会产生很多问题,正所谓是,想说爱你,并不是很容易的事。</li></ul><h4 id="浏览器缓存的分类"><a href="#浏览器缓存的分类" class="headerlink" title="浏览器缓存的分类"></a>浏览器缓存的分类</h4><p>浏览器缓存主要有两类:<code>协商缓存</code>和<code>强缓存</code>。</p><p>浏览器在第一次请求发生后,再次请求时:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">浏览器会先获取该资源缓存的header信息,根据其中的expires和cahe-control判断是否命中强缓存,若命中则直接从缓存中获取资源,</span><br><span class="line">包括缓存的header信息,本次请求不会与服务器进行通信;</span><br><span class="line">如果没有命中强缓存,浏览器会发送请求到服务器,该请求会携带第一次请求返回的有关缓存的header字段信息</span><br><span class="line">(Last-Modified/IF-Modified-Since、Etag/IF-None-Match),由服务器根据请求中的相关header信息来对比结果是否命中协商缓存,</span><br><span class="line">若命中,则服务器返回新的响应header信息更新缓存中的对应header信息,但是并不返回资源内容,它会告知浏览器可以直接从缓存获取;</span><br><span class="line">否则返回最新的资源内容。</span><br></pre></td></tr></table></figure></p><h4 id="强缓存-强缓存是利用http的返回头中的Expires或者Cache-Control两个字段来控制的,用来表示资源的缓存时间。"><a href="#强缓存-强缓存是利用http的返回头中的Expires或者Cache-Control两个字段来控制的,用来表示资源的缓存时间。" class="headerlink" title="强缓存: 强缓存是利用http的返回头中的Expires或者Cache-Control两个字段来控制的,用来表示资源的缓存时间。"></a>强缓存: 强缓存是利用http的返回头中的<code>Expires</code>或者<code>Cache-Control</code>两个字段来控制的,用来表示资源的缓存时间。</h4><p><strong>Expires</strong><br>该字段是http1.0时的规范,它的值为一个绝对时间的GMT格式的时间字符串,比如Expires:Mon,18 Oct 2066 23:59:59 GMT。<br>这个时间代表着这个资源的失效时间,在此时间之前,即命中缓存。这种方式有一个明显的缺点,由于失效时间是一个绝对时间,<br>所以当服务器与客户端时间偏差较大时,就会导致缓存混乱。</p><p><strong>Cache-Control</strong><br>Cache-Control是http1.1时出现的header信息,主要是利用该字段的max-age值来进行判断,它是一个相对时间,<br>例如Cache-Control:max-age=3600,代表着资源的有效期是3600秒。cache-control除了该字段外,还有下面几个比较常用的设置值:</p><ul><li>no-cache:不使用本地缓存。需要使用缓存协商,先与服务器确认返回的响应是否被更改,如果之前的响应中存在ETag,<br>那么请求的时候会与服务端验证,如果资源未被更改,则可以避免重新下载。</li><li>no-store:直接禁止游览器缓存数据,每次用户请求该资源,都会向服务器发送一个请求,每次都会下载完整的资源。</li><li>public:可以被所有的用户缓存,包括终端用户和CDN等中间代理服务器。</li><li>private:只能被终端用户的浏览器缓存,不允许CDN等中继缓存服务器对其缓存。</li></ul><p><code>Cache-Control与Expires可以在服务端配置同时启用,同时启用的时候Cache-Control优先级高。</code></p><h4 id="协商缓存-协商缓存就是由服务器来确定缓存资源是否可用,所以客户端与服务器端要通过某种标识来进行通信,"><a href="#协商缓存-协商缓存就是由服务器来确定缓存资源是否可用,所以客户端与服务器端要通过某种标识来进行通信," class="headerlink" title="协商缓存: 协商缓存就是由服务器来确定缓存资源是否可用,所以客户端与服务器端要通过某种标识来进行通信,"></a>协商缓存: 协商缓存就是由服务器来确定缓存资源是否可用,所以客户端与服务器端要通过某种标识来进行通信,</h4><p>从而让服务器判断请求资源是否可以缓存访问,这主要涉及到下面两组header字段,这两组搭档都是成对出现的,<br>即第一次请求的响应头带上某个字段(Last-Modified或者Etag),<br>则后续请求则会带上对应的请求字段(If-Modified-Since或者If-None-Match),<br>若响应头没有Last-Modified或者Etag字段,则请求头也不会有对应的字段。</p><p><strong>Last-Modified/If-Modify-Since</strong></p><p>浏览器第一次请求一个资源的时候,服务器返回的header中会加上Last-Modified,Last-modified是一个时间标识该资源的最后修改时间,<br>例如Last-Modified: Thu,31 Dec 2037 23:59:59 GMT。</p><p>当浏览器再次请求该资源时,request的请求头中会包含If-Modify-Since,该值为缓存之前返回的Last-Modified。<br>服务器收到If-Modify-Since后,根据资源的最后修改时间判断是否命中缓存。</p><p>如果命中缓存,则返回304,并且不会返回资源内容,并且不会返回Last-Modified。</p><p><strong>ETag/If-None-Match</strong></p><p>与Last-Modify/If-Modify-Since不同的是,Etag/If-None-Match返回的是一个校验码。<br>ETag可以保证每一个资源是唯一的,资源变化都会导致ETag变化。服务器根据浏览器上送的If-None-Match值来判断是否命中缓存。</p><p>与Last-Modified不一样的是,当服务器返回304 Not Modified的响应时,由于ETag重新生成过,response header中还会把这个ETag返回,<br>即使这个ETag跟之前的没有变化。</p><p><code>为什么要有Etag</code></p><p>你可能会觉得使用Last-Modified已经足以让浏览器知道本地的缓存副本是否足够新,为什么还需要Etag呢?<br>HTTP1.1中Etag的出现主要是为了解决几个Last-Modified比较难解决的问题:</p><ul><li>一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新GET;</li><li>某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since能检查到的粒度是s级的,<br>这种修改无法判断(或者说UNIX记录MTIME只能精确到秒);</li><li>某些服务器不能精确的得到文件的最后修改时间。</li></ul><p><code>Last-Modified与ETag是可以一起使用的,服务器会优先验证ETag,一致的情况下,才会继续比对Last-Modified,最后才决定是否返回304。</code></p><h4 id="代码更新到线上后用户浏览器不能自行更新,我们不能要求客户在系统更新后都进行一次缓存清理的操作。到底该如何解决呢?"><a href="#代码更新到线上后用户浏览器不能自行更新,我们不能要求客户在系统更新后都进行一次缓存清理的操作。到底该如何解决呢?" class="headerlink" title="代码更新到线上后用户浏览器不能自行更新,我们不能要求客户在系统更新后都进行一次缓存清理的操作。到底该如何解决呢?"></a>代码更新到线上后用户浏览器不能自行更新,我们不能要求客户在系统更新后都进行一次缓存清理的操作。到底该如何解决呢?</h4><figure class="highlight plain"><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">在资源请求的URL中增加一个参数,比如:JS/mian.js?ver=0.7.1。这个参数是一个版本号,每一次部署的时候变更一下,</span><br><span class="line">当这个参数变化的时候,强缓存都会失效并重新加载。这样一来,静态资源,部署以后就需要重新加载。这样就比较完美的解决了问题。</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<h4 id="浏览器缓存的优点有:"><a href="#浏览器缓存的优点有:" class="headerlink" title="浏览器缓存的优点有:"></a>浏览器缓存的优点有:</h4><ul>
<li>减少了冗余的数据传输,节省了网费</li>
<li>减少了服务器
</summary>
<category term="前端" scheme="https://21cm.js.org/categories/%E5%89%8D%E7%AB%AF/"/>
<category term="javascript" scheme="https://21cm.js.org/tags/javascript/"/>
<category term="javascript-缓存" scheme="https://21cm.js.org/tags/javascript-%E7%BC%93%E5%AD%98/"/>
</entry>
</feed>