-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
629 lines (345 loc) · 217 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
617
618
619
620
621
622
623
624
625
626
627
628
629
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>csskr</title>
<subtitle>csskr。</subtitle>
<link href="/atom.xml" rel="self"/>
<link href="https://csskr.js.org/"/>
<updated>2018-05-28T09:58:41.126Z</updated>
<id>https://csskr.js.org/</id>
<author>
<name>csskr</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>前端算法之排序之数制转换</title>
<link href="https://csskr.js.org/2018/05/28/js-Number-System-Conversion/"/>
<id>https://csskr.js.org/2018/05/28/js-Number-System-Conversion/</id>
<published>2018-05-28T04:00:00.000Z</published>
<updated>2018-05-28T09:58:41.126Z</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://csskr.js.org/categories/%E5%89%8D%E7%AB%AF/"/>
<category term="前端算法" scheme="https://csskr.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://csskr.js.org/tags/javascript/"/>
<category term="数制转换" scheme="https://csskr.js.org/tags/%E6%95%B0%E5%88%B6%E8%BD%AC%E6%8D%A2/"/>
</entry>
<entry>
<title>前端算法之排序</title>
<link href="https://csskr.js.org/2018/05/28/js-sort/"/>
<id>https://csskr.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://csskr.js.org/categories/%E5%89%8D%E7%AB%AF/"/>
<category term="前端算法" scheme="https://csskr.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://csskr.js.org/tags/javascript/"/>
<category term="排序" scheme="https://csskr.js.org/tags/%E6%8E%92%E5%BA%8F/"/>
<category term="冒泡排序" scheme="https://csskr.js.org/tags/%E5%86%92%E6%B3%A1%E6%8E%92%E5%BA%8F/"/>
<category term="选择排序" scheme="https://csskr.js.org/tags/%E9%80%89%E6%8B%A9%E6%8E%92%E5%BA%8F/"/>
<category term="插入排序" scheme="https://csskr.js.org/tags/%E6%8F%92%E5%85%A5%E6%8E%92%E5%BA%8F/"/>
<category term="希尔排序" scheme="https://csskr.js.org/tags/%E5%B8%8C%E5%B0%94%E6%8E%92%E5%BA%8F/"/>
<category term="快速排序" scheme="https://csskr.js.org/tags/%E5%BF%AB%E9%80%9F%E6%8E%92%E5%BA%8F/"/>
<category term="归并排序" scheme="https://csskr.js.org/tags/%E5%BD%92%E5%B9%B6%E6%8E%92%E5%BA%8F/"/>
<category term="堆排序" scheme="https://csskr.js.org/tags/%E5%A0%86%E6%8E%92%E5%BA%8F/"/>
</entry>
<entry>
<title>前端算法之查找算法</title>
<link href="https://csskr.js.org/2018/05/28/js-lookup/"/>
<id>https://csskr.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://csskr.js.org/categories/%E5%89%8D%E7%AB%AF/"/>
<category term="前端算法" scheme="https://csskr.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://csskr.js.org/tags/javascript/"/>
<category term="查找算法-线性查找" scheme="https://csskr.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://csskr.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://csskr.js.org/2018/05/27/fibonacci/"/>
<id>https://csskr.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://csskr.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://csskr.js.org/tags/javascript/"/>
<category term="fibonacci" scheme="https://csskr.js.org/tags/fibonacci/"/>
<category term="斐波那契数列" scheme="https://csskr.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://csskr.js.org/2018/05/27/js-unfor...in/"/>
<id>https://csskr.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://csskr.js.org/categories/%E5%89%8D%E7%AB%AF/"/>
<category term="javascript" scheme="https://csskr.js.org/tags/javascript/"/>
<category term="javascript-循环" scheme="https://csskr.js.org/tags/javascript-%E5%BE%AA%E7%8E%AF/"/>
</entry>
<entry>
<title>前端知识点总结之javascript-严格模式</title>
<link href="https://csskr.js.org/2018/05/27/js-strict/"/>
<id>https://csskr.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://csskr.js.org/categories/%E5%89%8D%E7%AB%AF/"/>
<category term="javascript" scheme="https://csskr.js.org/tags/javascript/"/>
<category term="javascript-严格模式" scheme="https://csskr.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://csskr.js.org/2018/05/27/js-new/"/>
<id>https://csskr.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://csskr.js.org/tags/javascript/"/>
<category term="javascript-new" scheme="https://csskr.js.org/tags/javascript-new/"/>
</entry>
<entry>
<title>前端知识点总结之javascript-null和undefined的区别?</title>
<link href="https://csskr.js.org/2018/05/27/js-null&&js-undefined/"/>
<id>https://csskr.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://csskr.js.org/tags/javascript/"/>
<category term="javascript-null" scheme="https://csskr.js.org/tags/javascript-null/"/>
<category term="javascript-undefined" scheme="https://csskr.js.org/tags/javascript-undefined/"/>
</entry>
<entry>
<title>前端知识点总结之javascript-ready && javascript-onload</title>
<link href="https://csskr.js.org/2018/05/27/js-ready&&js-onload/"/>
<id>https://csskr.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://csskr.js.org/tags/javascript/"/>
<category term="javascript-ready" scheme="https://csskr.js.org/tags/javascript-ready/"/>
<category term="javascript-onload" scheme="https://csskr.js.org/tags/javascript-onload/"/>
</entry>
<entry>
<title>前端知识点总结之javascript-attribute && javascript-property</title>
<link href="https://csskr.js.org/2018/05/27/js-attribute&&js-property/"/>
<id>https://csskr.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://csskr.js.org/tags/javascript/"/>
<category term="javascript-attribute" scheme="https://csskr.js.org/tags/javascript-attribute/"/>
<category term="javascript-property" scheme="https://csskr.js.org/tags/javascript-property/"/>
</entry>
<entry>
<title>前端知识点总结之javascript-XSS &&javascript-csrf</title>
<link href="https://csskr.js.org/2018/05/27/js-xss&&ja-csrf/"/>
<id>https://csskr.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://csskr.js.org/tags/javascript/"/>
<category term="javascript-xss" scheme="https://csskr.js.org/tags/javascript-xss/"/>
<category term="javascript-csrf" scheme="https://csskr.js.org/tags/javascript-csrf/"/>
</entry>
<entry>
<title>前端知识点总结之javascript-缓存</title>
<link href="https://csskr.js.org/2018/05/27/js-cache/"/>
<id>https://csskr.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://csskr.js.org/categories/%E5%89%8D%E7%AB%AF/"/>
<category term="javascript" scheme="https://csskr.js.org/tags/javascript/"/>
<category term="javascript-缓存" scheme="https://csskr.js.org/tags/javascript-%E7%BC%93%E5%AD%98/"/>
</entry>
<entry>
<title>前端知识点总结之javascript-性能优化</title>
<link href="https://csskr.js.org/2018/05/27/js-optimization/"/>
<id>https://csskr.js.org/2018/05/27/js-optimization/</id>
<published>2018-05-27T00:00:00.000Z</published>
<updated>2018-05-27T03:14:26.146Z</updated>
<content type="html"><![CDATA[<h4 id="1-JavaScript-压缩和模块打包"><a href="#1-JavaScript-压缩和模块打包" class="headerlink" title="1. JavaScript 压缩和模块打包"></a>1. JavaScript 压缩和模块打包</h4><p>JavaScript 应用是以源码形式进行分发的,而源码解析的效率是要比字节码低的。对于一小段脚本来说,区别可以忽略不计。<br>但是对于更大型的应用,脚本的大小会对应用启动时间有着负面的影响。事实上,寄期望于使用 WebAssembly 而获得最大程度的改善,<br>其中之一就是可以得到更快的启动时间。<br>另一方面,模块打包则用于将不同脚本打包在一起并放进同一文件。更少的 HTTP 请求和单个文件解析都可以减少加载时间。<br>通常情况下,单独一种工具就可以处理打包和压缩。Webpack 就是其中之一。</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></pre></td><td class="code"><pre><span class="line">function insert(i) {</span><br><span class="line"> document.write("Sample " + i);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">for(var i = 0; i < 30; ++i) {</span><br><span class="line"> insert(i);</span><br><span class="line">}</span><br><span class="line">结果如下:</span><br><span class="line">!function(r){function t(o){if(e[o])return e[o].exports;var n=e[o]={exports:{},id:o,loaded:!1};return r[o].call(n.exports,n,n.exports,t),n.loaded=!0,n.exports}var e={};return t.m=r,t.c=e,t.p="",t(0)}([function(r,t){function e(r){document.write("Sample "+r)}for(var o=0;30>o;++o)e(o)}]);</span><br><span class="line">//# sourceMappingURL=bundle.min.js.map</span><br><span class="line">进一步打包</span><br><span class="line">你也可以使用 Webpack 打包 CSS 文件以及合并图片。这些特性都可以有助于改善启动时间。</span><br></pre></td></tr></table></figure></p><h4 id="2-按需加载资源"><a href="#2-按需加载资源" class="headerlink" title="2. 按需加载资源"></a>2. 按需加载资源</h4><p>资源(特别是图片)的按需加载或者说惰性加载,可以有助于你的 Web 应用在整体上获得更好的性能。<br>对于使用大量图片的页面来说惰性加载有着显著的三个好处:</p><ul><li>减少向服务器发出的并发请求数量(这就使得页面的其他部分获得更快的加载时间)</li><li>减少浏览器的内存使用率(更少的图片,更少的内存)</li><li>减少服务器端的负载<br>大体上的理念就是只在必要的时候才去加载图片或资源(如视频),比如在第一次被显示的时候,或者是在将要显示的时候对其进行加载。<br>由于这种方式跟你建站的方式密切相关,惰性加载的解决方案通常需要借助其他库的插件或者扩展来实现。<br>举个例子,react-lazy-load 就是一个用于处理 React 惰性加载图片的插件:<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">const MyComponent = () => (</span><br><span class="line"> <div></span><br><span class="line"> Scroll to load images.</span><br><span class="line"> <div className="filler" /></span><br><span class="line"> <LazyLoad height={762} offsetVertical={300}></span><br><span class="line"> <img src='http://apod.nasa.gov/apod/image/1502/HDR_MVMQ20Feb2015ouellet1024.jpg' /></span><br><span class="line"> </LazyLoad></span><br><span class="line"> (...)</span><br><span class="line">一个非常好的实践范例就像 Goggle Images 的搜索工具一样。点击前面的链接并且滑动页面滚动条就可以看到效果了。</span><br></pre></td></tr></table></figure></li></ul><h4 id="3-在使用-DOM-操作库时用上-array-ids"><a href="#3-在使用-DOM-操作库时用上-array-ids" class="headerlink" title="3. 在使用 DOM 操作库时用上 array-ids"></a>3. 在使用 DOM 操作库时用上 array-ids</h4><p>如果你正在使用 React,Ember,Angular 或者其他 DOM 操作库,使用 array-ids(或者 Angular 1.x 中的 track-by 特性)<br>非常有助于实现高性能,对于动态网页尤其如此。</p><p>此特性背后的主要概念就是尽可能多地重用已有的节点。Array ids 使得 DOM 操作引擎可以「知道」在什么时候某个节点可以<br>被映射到数组当中的某个元素。没有 array-ids 或者 track-by 的话,大部分库都会进行重新排序而摧毁已有的节点并重新创建新的。<br>这就非常损耗性能了。</p><h4 id="4-缓存"><a href="#4-缓存" class="headerlink" title="4. 缓存"></a>4. 缓存</h4><p>Caches 是用于存储那些被频繁存取的静态数据的组件,便于随后对于这个数据的请求可以更快地被响应,或者说请求方式更加高效。<br>由于 Web 应用是由很多可拆卸的部件组合而成,缓存就可以存在于架构中的很多部分。举例来说,缓存可以被放在动态内容服务器和客户端之间<br>,就可以避免公共请求以减少服务器的负载,与此同时改善响应时间。其他缓存可能被放置在代码里,以优化某些用于脚本存取的通用模式,<br>还有些缓存可能被放置在数据库或者是长运行进程之前。</p><p>简而言之,在 Web 应用中使用缓存是一种改善响应时间和减少 CPU 使用的绝佳方式。难点就在于搞清楚哪里才是在架构中存放缓存的地方。<br>再一次,答案就是性能分析:常见的瓶颈在哪里?数据或者结果可缓存吗?他们都太容易失效吗?这都是一些棘手的问题,需要从原理上来一点一点回答。</p><p>缓存的使用在 Web 环境中富有创造性。比如,basket.js 就是一个使用Local Storage 来缓存应用脚本的库。<br>所以你的 Web 应用在第二次运行脚本的时候就可以几乎瞬间加载了。</p><h4 id="5-启用-HTTP-2"><a href="#5-启用-HTTP-2" class="headerlink" title="5. 启用 HTTP/2"></a>5. 启用 HTTP/2</h4><p>越来越多的浏览器都开始支持 HTTP/2。这可能听起来没有必要,但是 HTTP/2 为同一服务器的并发连接问题带来了很多好处。<br>换句话说,如果有很多小型资源需要加载(如果你打包过的话就没有必要了),在延迟和性能方面 HTTP/2 秒杀 HTTP/1。</p><h4 id="6-应用性能分析"><a href="#6-应用性能分析" class="headerlink" title="6. 应用性能分析"></a>6. 应用性能分析</h4><p>性能分析是优化任何应用程序时的重要一步。就像介绍中所提到的那样,盲目尝试优化应用经常会导致效率的浪费,微不足道的收益和更差的可维护性。<br>执行性能分析是识别你的应用问题所在的一个重要步骤。</p><p>对于 Web 应用来说,延迟时间是最大的抱怨之一,所以你需要确保数据的加载和显示都尽可能得快。<br>Chrome 提供了非常棒的性能分析工具。特别是 Chrome Dev Tools 中的时间线和网络视图都对于定位延迟问题有着很大的帮助:</p><p>时间线视图可以帮忙找到运行时间较长的操作。</p><p>网络视图可以帮助识别出额外的由缓慢请求导致的延迟或对于某一端点的串行访问。</p><p>正确分析的话,内存则是另一块可能获得收益的部分。如果你正在运行着一个拥有很多虚拟元素的页面(庞大的动态表格)或者可交互式的元素(比如游戏),<br>内存优化可以获得更少的卡顿和更高的帧率。</p><p>CPU 性能分析也可以在 Chrome Dev Tools 中找到。找到性能损耗的中心可以让你有效率地达到优化的目标。</p><p>对后端的性能分析会更加困难。通常情况下,确认一个耗费较多时间的请求可以让你明确应该优先分析哪一个服务。<br>对于后端的分析工具来说,则取决于所构建的技术栈。</p><p>一个关于算法的注意事项</p><p>在大多数情况下,选择一个更优的算法,比围绕着小成本中心所实现的具体优化策略能够获得更大的收益。<br>在某种程度上,CPU 和内存分析应该可以帮你找到大的性能瓶颈。当这些瓶颈跟编码问题并不相关时,则是时候考虑考虑不同的算法了。</p><h4 id="7-使用负载均衡方案"><a href="#7-使用负载均衡方案" class="headerlink" title="7. 使用负载均衡方案"></a>7. 使用负载均衡方案</h4><p>把负载分配到不同的服务器(甚至于不同的地理区域)可以给你的用户提供更好的延迟时间,但是这条路还很漫长,特别是在处理很多的并发连接的时候。</p><p>负载均衡就跟使用某个 round-robin(循环)解决方案一样简单,可以基于一个 nginx 反向代理 ,或者基于一个成熟的分布式网络。</p><p>为了使负载均衡真正有效,动态内容和静态内容都应该被拆分成易于并发访问的。<br>换句话说,元素的串形访问会削弱负载均衡器以最佳形式进行分流的能力。与此同时,对于资源的并发访问可以改善启动时间。</p><p>虽然负载均衡可能会很复杂。对最终一致性算法不友好的数据模型,或者缓存都会让事情更加困难。<br>幸运的是,大多数应用对于已简化的数据集都只需要保证高层次的一致性即可。如果你的应用程序没有这样设计的话,就有必要重构一下了。</p><h4 id="8-为了更快的启动时间考虑一下同构-JavaScript"><a href="#8-为了更快的启动时间考虑一下同构-JavaScript" class="headerlink" title="8. 为了更快的启动时间考虑一下同构 JavaScript"></a>8. 为了更快的启动时间考虑一下同构 JavaScript</h4><p>改善 Web 应用程序观感的方式之一,就是减少启动时间或者减少首页渲染时间。<br>这对于新兴的单页面应用尤为重要,其需要在客户端执行大量任务。在客户端做更多事情通常就意味着,在第一次渲染被执行之前就需要下载更多的信息。<br>同构 JavaScript 可以解决这个问题:自从 JavaScript 可以同时运行在客户端和服务器端,这就让在服务器端来执行页面的首次渲染成为可能,<br>先把已渲染的页面发送出去然后再由客户端的脚本接管。这限制了所使用的后端(必须使用支持该特性的 JavaScript 框架),但却能获得更好的用户体验。<br>举例来说,React 就很适合于做这个,就像以下代码所示:<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></pre></td><td class="code"><pre><span class="line">var React = require('react/addons');</span><br><span class="line">var ReactApp = React.createFactory(require('../components/ReactApp').ReactApp);</span><br><span class="line"></span><br><span class="line">module.exports = function(app) {</span><br><span class="line"></span><br><span class="line"> app.get('/', function(req, res){</span><br><span class="line"> // React.renderToString takes your component</span><br><span class="line"> // and generates the markup</span><br><span class="line"> var reactHtml = React.renderToString(ReactApp({}));</span><br><span class="line"> // Output html rendered by react</span><br><span class="line"> // console.log(myAppHtml);</span><br><span class="line"> res.render('index.ejs', {reactOutput: reactHtml});</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line">};</span><br></pre></td></tr></table></figure></p><p>Meteor.js 对于客户端和服务器端的 JavaScript 混用有着非常棒的支持。<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">if (Meteor.isClient) {</span><br><span class="line"> Template.hello.greeting = function () {</span><br><span class="line"> return "Welcome to myapp.";</span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"> Template.hello.events({</span><br><span class="line"> 'click input': function () {</span><br><span class="line"> // template data, if any, is available in 'this'</span><br><span class="line"> if (typeof console !== 'undefined')</span><br><span class="line"> console.log("You pressed the button");</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">if (Meteor.isServer) {</span><br><span class="line"> Meteor.startup(function () {</span><br><span class="line"> // code to run on server at startup</span><br><span class="line"> });</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>但是,为了支持服务器端渲染,需要像 meteor-ssr 这样的插件。</p><p>如果你有复杂的或者中等大小的应用需要支持同构部署,试试这个,你可能会感到惊讶的。</p><h4 id="9-使用索引加速数据库查询"><a href="#9-使用索引加速数据库查询" class="headerlink" title="9. 使用索引加速数据库查询"></a>9. 使用索引加速数据库查询</h4><p>如果你需要解决数据库查询耗费大量时间的问题(分析你的应用看看是否是这种情况!),是时候找出加速数据库的方法了。<br>每个数据库和数据模型都有自己的权衡。数据库优化在每一方面都是一个主题:数据模型,数据库类型,具体实现方案,等等。<br>提速可能不是那么的简单。但是这儿有个建议,可能可以对某些数据库有所帮助:索引。<br>索引是一个过程,即数据库所创建的快速访问数据结构,从内部映射到键(在关系数据库中的列),可以提高检索相关数据的速度。<br>大多数现代数据库都支持索引。索引并不是文档型数据库(比如 MongoDB)所独有的,也包括关系型数据库(比如PostgreSQL)。</p><p>为了使用索引来优化你的查询,你将需要研究一下应用程序的访问模式:什么是最常见的查询,在哪个键或列中执行搜索,等等。</p><h4 id="10-使用更快的转译方案"><a href="#10-使用更快的转译方案" class="headerlink" title="10. 使用更快的转译方案"></a>10. 使用更快的转译方案</h4><p>JavaScript 软件技术栈一如既往的复杂。而改善语言本身的需求则又增加了复杂度。<br>不幸地是,JavaScript 作为目标平台又会被用户的运行时所限制。尽管很多改进已经以 ECMAScript 2015(2016正在进行)的形式实现了,<br>但是通常情况下,对客户端代码来说又不可能依赖于这个版本。<br>这种趋势促使了一系列的转译器:用于处理 ECMAScript 2015 代码的工具和只使用 ECMAScript 5 结构实现其中所缺失的特性。<br>与此同时,模块绑定和压缩处理也已经被集成到这个生产过程中,被称为为发布而构建的代码版本。这些工具可以转化代码,<br>并且能够以有限的方式影响到最终代码的性能。</p><h4 id="11-避免或最小化-JavaScript-和-CSS-的使用而阻塞渲染"><a href="#11-避免或最小化-JavaScript-和-CSS-的使用而阻塞渲染" class="headerlink" title="11. 避免或最小化 JavaScript 和 CSS 的使用而阻塞渲染"></a>11. 避免或最小化 JavaScript 和 CSS 的使用而阻塞渲染</h4><p>JavaScript 和 CSS 资源都会阻塞页面的渲染。通过采取某些的规则,你可以保证你的脚本和 CSS 被尽可能快速地处理,<br>以便于浏览器能够显示你的网站内容。</p><p>在 CSS 的情况下这是非常重要的,所有的 CSS 规则都不能与特定媒体直接相关,规则只用于处理你准备在页面上所显示内容的优先级。<br>这可以通过使用 CSS 媒体查询来实现。媒体查询告诉浏览器,哪些 CSS 样式表应用在某个特定的显示媒体上。<br>举个例子,用于打印的某些规则可以被赋予比用于屏幕显示更低的优先级。</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></pre></td><td class="code"><pre><span class="line"><link rel="stylesheet" type="text/css" media="only screen and (max-device-width: 480px)" href="mobile-device.css" /></span><br><span class="line">轮到 JavaScript 了,关键就在于遵循某些用于内联 JavaScript 的规则(比如内联在 HTML 文件当中的代码)。内联 JavaScript 应该尽可能短,并将其放在不会阻塞页面剩余部分解析的地方。换句话说,被放在 HTML 树中间的内联 JavaScript 将会在这个地方阻塞解析器,并强制其等待直到脚本被执行完毕。如果在 HTML 文件中随意放了一些大的代码块或者很多小的代码块,对于性能来说这会成为性能杀手。内联可以有效减少额外对于某些特定脚本的网络请求。但是对于重复使用的脚本或者大的代码块来说,这个好处就可以忽略不计了。</span><br></pre></td></tr></table></figure></p><p>防止 JavaScript 阻塞解析器和渲染器的一种方法就是将 <code><script></code> 标签标记为异步的。<br>这限制了我们对于 DOM 的访问但是可以让浏览器不管脚本的执行状态而继续解析和渲染页面。<br>换句话说,为了获得最佳的启动时间,确保那些对于渲染不重要的脚本已经通过异步属性的方式标记成异步的了。<br><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"><script src="async.js" async></script></span><br></pre></td></tr></table></figure></p><h4 id="12-用于未来的一个建议:使用-service-workers-流"><a href="#12-用于未来的一个建议:使用-service-workers-流" class="headerlink" title="12. 用于未来的一个建议:使用 service workers + 流"></a>12. 用于未来的一个建议:使用 service workers + 流</h4><p>Jake Archibald 最近的一篇博文详细描述了一种有趣的技术,可以用于加速渲染时间:将 service workers 和流结合起来。结果非常令人叹服:</p><p>不幸的是这个技术所需要的 APIs 都还不稳定,这也是为什么这是一种有趣的概念但现在还没有真正被应用的原因。<br>这个想法的主旨就是在网站和客户端之间放置一个 service worker。<br>这个 service worker 可以在获取缺失信息的同时缓存某些数据(比如 header 和一些不会经常改变的东西)。<br>缺失的内容就可以尽可能快速地流向被渲染的页面。</p><p><a href="https://www.youtube.com/watch?v=Cjo9iq8k-bc" target="_blank" rel="noopener">https://www.youtube.com/watch?v=Cjo9iq8k-bc</a></p><h4 id="13-图片编码优化"><a href="#13-图片编码优化" class="headerlink" title="13. 图片编码优化"></a>13. 图片编码优化</h4><p>PNGs 和 JPGs 在 Web 发布时都会使用次优的设置进行编码。通过改变编码器和它的设置,对于需要大量图片的网站来说可以获得有效的改善。<br>流行的解决方案包括 OptiPNG 和jpegtran。</p>]]></content>
<summary type="html">
<h4 id="1-JavaScript-压缩和模块打包"><a href="#1-JavaScript-压缩和模块打包" class="headerlink" title="1. JavaScript 压缩和模块打包"></a>1. JavaScript 压缩和模块打包</h4
</summary>
<category term="前端" scheme="https://csskr.js.org/categories/%E5%89%8D%E7%AB%AF/"/>
<category term="javascript" scheme="https://csskr.js.org/tags/javascript/"/>
<category term="javascript-性能优化" scheme="https://csskr.js.org/tags/javascript-%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96/"/>
</entry>
<entry>
<title>javascript-跨域方式总结</title>
<link href="https://csskr.js.org/2018/05/26/js-cross-domain/"/>
<id>https://csskr.js.org/2018/05/26/js-cross-domain/</id>
<published>2018-05-26T09:40:00.000Z</published>
<updated>2018-05-26T09:47:52.892Z</updated>
<content type="html"><![CDATA[<h4 id="1-跨域资源共享-CORS"><a href="#1-跨域资源共享-CORS" class="headerlink" title="1. 跨域资源共享 CORS"></a>1. 跨域资源共享 CORS</h4><p>对于web开发来讲,由于浏览器的同源策略,我们需要经常使用一些hack的方法去跨域获取资源,但是hack的方法总归是hack。<br>直到W3C出了一个标准-CORS-”跨域资源共享”(Cross-origin resource sharing)。<br>它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。<br>首先来说 CORS 需要浏览器和服务端同时支持的,对于兼容性来说主要是ie10+,其它现代浏览器都是支持的。<br>使用 CORS 跨域的时候其实和普通的 ajax 过程是一样的,只是浏览器在发现这是一个跨域请求的时候会自动帮我们处理一些事,<br>比如验证等等,所以说只要服务端提供支持,前端是不需要做额外的事情的。</p><p>两种请求<br>CORS 的请求分两种,这也是浏览器为了安全做的一些处理,不同情况下浏览器执行的操作也是不一样的,主要分为两种请求,<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><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><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br></pre></td><td class="code"><pre><span class="line">1. 简单请求(simple request)</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">1) 请求方法是以下三种方法中的一个:</span><br><span class="line">HEAD</span><br><span class="line">GET</span><br><span class="line">POST</span><br><span class="line">2)HTTP的头信息不超出以下几种字段:</span><br><span class="line">Accept</span><br><span class="line">Accept-Language</span><br><span class="line">Content-Language</span><br><span class="line">Last-Event-ID</span><br><span class="line">Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain</span><br><span class="line">过程</span><br><span class="line"></span><br><span class="line">对于简单的跨域请求,浏览器会自动在请求的头信息加上 Origin 字段,表示本次请求来自哪个源(协议 + 域名 + 端口),</span><br><span class="line">服务端会获取到这个值,然后判断是否同意这次请求并返回。</span><br><span class="line"></span><br><span class="line">// 请求</span><br><span class="line">GET /cors HTTP/1.1</span><br><span class="line">Origin: http://api.qiutc.me</span><br><span class="line">Host: api.alice.com</span><br><span class="line">Accept-Language: en-US</span><br><span class="line">Connection: keep-alive</span><br><span class="line">User-Agent: Mozilla/5.0...</span><br><span class="line">1.服务端允许</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">Access-Control-Allow-Origin: http://api.qiutc.me</span><br><span class="line">Access-Control-Allow-Credentials: true</span><br><span class="line">Access-Control-Expose-Headers: Info</span><br><span class="line">Content-Type: text/html; charset=utf-8</span><br><span class="line">这三个带有 Access-Control 开头的字段分别表示:</span><br><span class="line"></span><br><span class="line">Access-Control-Allow-Origin</span><br><span class="line">必须。它的值是请求时Origin字段的值或者 *,表示接受任意域名的请求。</span><br><span class="line">Access-Control-Allow-Credentials;</span><br><span class="line">可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。</span><br><span class="line">设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。</span><br><span class="line">再需要发送cookie的时候还需要注意要在AJAX请求中打开withCredentials属性:</span><br><span class="line">var xhr = new XMLHttpRequest(); </span><br><span class="line">xhr.withCredentials = true;</span><br><span class="line">需要注意的是,如果要发送Cookie,Access-Control-Allow-Origin就不能设为*,必须指定明确的、与请求网页一致的域名。</span><br><span class="line">同时,Cookie依然遵循同源政策,只有用服务器域名设置的Cookie才会上传,其他域名的Cookie并不会上传,</span><br><span class="line">且原网页代码中的document.cookie也无法读取服务器域名下的Cookie。</span><br><span class="line"></span><br><span class="line">Access-Control-Expose-Headers</span><br><span class="line">可选。CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:</span><br><span class="line">Cache-Control、</span><br><span class="line">Content-Language、</span><br><span class="line">Content-Type、</span><br><span class="line">Expires、</span><br><span class="line">Last-Modified、</span><br><span class="line">Pragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。</span><br><span class="line">上面的例子指定,getResponseHeader('Info')可以返回Info字段的值。</span><br><span class="line">2.服务端拒绝</span><br><span class="line"></span><br><span class="line">当然我们为了防止接口被乱调用,需要限制源,对于不允许的源,服务端还是会返回一个正常的HTTP回应,</span><br><span class="line">但是不会带上 Access-Control-Allow-Origin 字段,浏览器发现这个跨域请求的返回头信息没有该字段,</span><br><span class="line">就会抛出一个错误,会被 XMLHttpRequest 的 onerror 回调捕获到。</span><br><span class="line">这种错误无法通过 HTTP 状态码判断,因为回应的状态码有可能是200</span><br><span class="line"></span><br><span class="line">2.非简单请求</span><br><span class="line">条件</span><br><span class="line"></span><br><span class="line">出了简单请求以外的CORS请求。</span><br><span class="line">非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUT或DELETE,或者Content-Type字段的类型是application/json。</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"></span><br><span class="line">非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)。</span><br><span class="line">浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。</span><br><span class="line">只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。</span><br><span class="line">预检请求的发送请求:</span><br><span class="line"></span><br><span class="line">OPTIONS /cors HTTP/1.1</span><br><span class="line">Origin: http://api.qiutc.me</span><br><span class="line">Access-Control-Request-Method: PUT</span><br><span class="line">Access-Control-Request-Headers: X-Custom-Header</span><br><span class="line">Host: api.qiutc.com</span><br><span class="line">Accept-Language: en-US</span><br><span class="line">Connection: keep-alive</span><br><span class="line">User-Agent: Mozilla/5.0...</span><br><span class="line">"预检"请求用的请求方法是OPTIONS,表示这个请求是用来询问的。头信息里面,关键字段是Origin,表示请求来自哪个源。</span><br><span class="line">除了Origin字段,"预检"请求的头信息包括两个特殊字段。</span><br><span class="line"></span><br><span class="line">Access-Control-Request-Method</span><br><span class="line">该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法,上例是PUT。</span><br><span class="line">Access-Control-Request-Headers</span><br><span class="line">该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段,上例是X-Custom-Header。</span><br><span class="line">预检请求的返回:</span><br><span class="line"></span><br><span class="line">HTTP/1.1 200 OK</span><br><span class="line">Date: Mon, 01 Dec 2008 01:15:39 GMT</span><br><span class="line">Server: Apache/2.0.61 (Unix)</span><br><span class="line">Access-Control-Allow-Origin: http://api.qiutc.me</span><br><span class="line">Access-Control-Allow-Methods: GET, POST, PUT</span><br><span class="line">Access-Control-Allow-Headers: X-Custom-Header</span><br><span class="line">Content-Type: text/html; charset=utf-8</span><br><span class="line">Content-Encoding: gzip</span><br><span class="line">Content-Length: 0</span><br><span class="line">Keep-Alive: timeout=2, max=100</span><br><span class="line">Connection: Keep-Alive</span><br><span class="line">Content-Type: text/plain</span><br><span class="line">Access-Control-Allow-Methods</span><br><span class="line">必需,它的值是逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法。注意,返回的是所有支持的方法,</span><br><span class="line">而不单是浏览器请求的那个方法。这是为了避免多次"预检"请求。</span><br><span class="line">Access-Control-Allow-Headers</span><br><span class="line">如果浏览器请求包括Access-Control-Request-Headers字段,则Access-Control-Allow-Headers字段是必需的。</span><br><span class="line">它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段,不限于浏览器在"预检"中请求的字段。</span><br><span class="line">Access-Control-Max-Age</span><br><span class="line">该字段可选,用来指定本次预检请求的有效期,单位为秒。上面结果中,有效期是20天(1728000秒),</span><br><span class="line">即允许缓存该条回应1728000秒(即20天),在此期间,不用发出另一条预检请求。</span><br><span class="line">2)浏览器的正常请求和回应</span><br><span class="line"></span><br><span class="line">一旦服务器通过了"预检"请求,以后每次浏览器正常的CORS请求,就都跟简单请求一样,会有一个Origin头信息字段。</span><br><span class="line">服务器的回应,也都会有一个Access-Control-Allow-Origin头信息字段。</span><br><span class="line"></span><br><span class="line">参考:[《跨域资源共享 CORS 详解》]()http://www.ruanyifeng.com/blog/2016/04/cors.html</span><br><span class="line">)</span><br><span class="line">阮大神的文章,复制粘贴了不少。</span><br></pre></td></tr></table></figure></p><h4 id="2-jsonp"><a href="#2-jsonp" class="headerlink" title="2. jsonp"></a>2. jsonp</h4><p>jsonp = json + padding<br>其实对于常用性来说,jsonp应该是使用最经常的一种跨域方式了,他不受浏览器兼容性的限制。但是他也有他的局限性,<code>只能发送 GET 请求</code>,<br>需要服务端和前端规定好,写法丑陋。<br>它的原理在于浏览器请求 script 资源不受同源策略限制,并且请求到 script 资源后立即执行。<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><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">在浏览器端:</span><br><span class="line">首先全局注册一个callback回调函数,记住这个函数名字(比如:resolveJson),这个函数接受一个参数,参数是期望的到的服务端返回数据,</span><br><span class="line">函数的具体内容是处理这个数据。然后动态生成一个 script 标签,src 为:请求资源的地址+获取函数的字段名+回调函数名称,</span><br><span class="line">这里的获取函数的字段名是要和服务端约定好的,是为了让服务端拿到回调函数名称。(如:www.qiute.com?callbackName=resolveJson)。</span><br><span class="line"></span><br><span class="line">function resolveJosn(result) {</span><br><span class="line"> console.log(result.name);</span><br><span class="line">}</span><br><span class="line">var jsonpScript= document.createElement("script");</span><br><span class="line">jsonpScript.type = "text/javascript";</span><br><span class="line">jsonpScript.src = "http://www.qiute.com?callbackName=resolveJson";</span><br><span class="line">document.getElementsByTagName("head")[0].appendChild(jsonpScript);</span><br><span class="line"></span><br><span class="line">服务端</span><br><span class="line">在接受到浏览器端 script 的请求之后,从url的query的callbackName获取到回调函数的名字,例子中是resolveJson。</span><br><span class="line">然后动态生成一段javascript片段去给这个函数传入参数执行这个函数。比如:</span><br><span class="line"></span><br><span class="line">resolveJson({name: 'qiutc'});</span><br><span class="line">执行</span><br><span class="line">服务端返回这个 script 之后,浏览器端获取到 script 资源,然后会立即执行这个 javascript,也就是上面那个片段。</span><br><span class="line">这样就能根据之前写好的回调函数处理这些数据了。</span><br><span class="line">在一些第三方库往往都会封装jsonp的操作,比如 jQuery 的$.getJSON。</span><br></pre></td></tr></table></figure></p><h4 id="3-document-domain"><a href="#3-document-domain" class="headerlink" title="3. document.domain"></a>3. document.domain</h4><p>一个页面框架(iframe/frame)之间(父子或同辈),是能够获取到彼此的window对象的,<br>但是这个 window 不能拿到方法和属性(尼玛这有什么用,甩脸)。<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><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line">// 当前页面域名 http://blog.qiutc.me/a.html</span><br><span class="line"><script></span><br><span class="line">function onLoad() {</span><br><span class="line"> var iframe =document.getElementById('iframe');</span><br><span class="line"> var iframeWindow = iframe.contentWindow; // 这里可以获取 iframe 里面 window 对象,但是几乎没用</span><br><span class="line"> var doc = iframeWindow.document; // 获取不到</span><br><span class="line">}</span><br><span class="line"></script></span><br><span class="line"><iframe src="http://21cm.github.io/b.html" onload="onLoad()"</iframe></span><br><span class="line">这个时候,document.domain 就可以派上用场了,我们只要把 http://blog.qiutc.me/a.html 和 http://21cm.github.io/b.html </span><br><span class="line">这两个页面的 document.domain 都设成相同的域名就可以了。</span><br><span class="line">前提条件:这两个域名必须属于同一个基础域名!而且所用的协议,端口都要一致。</span><br><span class="line">但要注意的是,document.domain 的设置是有限制的,我们只能把 document.domain 设置成自身或更高一级的父域,且主域必须相同。</span><br><span class="line">例如:a.b.example.com 中某个文档的 document.domain 可以设成a.b.example.com、b.example.com 、example.com中的任意一个,</span><br><span class="line">但是不可以设成 c.a.b.example.com,因为这是当前域的子域,也不可以设成baidu.com,因为主域已经不相同了。</span><br><span class="line">这样我们就可以通过js访问到iframe中的各种属性和对象了。</span><br><span class="line"></span><br><span class="line">// 主页面:http://21cm.github.io/a.html</span><br><span class="line"><script></span><br><span class="line">document.domain = 'qiutc.me';</span><br><span class="line">function onLoad() {</span><br><span class="line"> var iframe =document.getElementById('iframe');</span><br><span class="line"> var iframeWindow = iframe.contentWindow; // 这里可以获取 iframe 里面 window 对象并且能得到方法和属性</span><br><span class="line"> var doc = iframeWindow.document; // 获取到</span><br><span class="line">}</span><br><span class="line"></script></span><br><span class="line"><iframe src="http://21cm.github.io/b.html" onload="onLoad()"</iframe></span><br><span class="line">// iframe 里面的页面</span><br><span class="line"><script></span><br><span class="line">document.domain = 'qiutc.me';</span><br><span class="line"></script></span><br></pre></td></tr></table></figure></p><h4 id="4-window-name"><a href="#4-window-name" class="headerlink" title="4. window.name"></a>4. window.name</h4><p>window对象有个name属性,该属性有个特征:即在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个 window.name 的,<br>每个页面对 window.name 都有读写的权限,window.name 是持久存在一个窗口载入过的所有页面中的,并不会因新页面的载入而进行重置。<br>比如有一个21cm.github.io/a.html页面,需要通过a.html页面里的js来获取另一个位于不同域上的页面21cm.github.io/data.html里的数据。<br>data.html页面里的代码很简单,就是给当前的window.name设置一个a.html页面想要得到的数据值。data.html里的代码:<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><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><script></span><br><span class="line">window.name = '我是被期望得到的数据';</span><br><span class="line"></script></span><br><span class="line">那么在 a.html 页面中,我们怎么把 data.html 页面载入进来呢?显然我们不能直接在 a.html 页面中通过改变 window.location </span><br><span class="line">来载入data.html页面(这简直扯蛋)因为我们想要即使 a.html 页面不跳转也能得到 data.html 里的数据。</span><br><span class="line">答案就是在 a.html 页面中使用一个隐藏的 iframe 来充当一个中间人角色,由 iframe 去获取 data.html 的数据,</span><br><span class="line">然后 a.html 再去得到 iframe 获取到的数据。</span><br><span class="line">充当中间人的 iframe 想要获取到data.html的通过window.name设置的数据,只需要把这个iframe的src设为</span><br><span class="line">www.qiutc.com/data.html就行了。然后a.html想要得到iframe所获取到的数据,也就是想要得到iframe的window.name的值,</span><br><span class="line">还必须把这个iframe的src设成跟a.html页面同一个域才行,不然根据前面讲的同源策略,</span><br><span class="line">a.html是不能访问到iframe里的window.name属性的。这就是整个跨域过程。</span><br><span class="line"></span><br><span class="line">// a.html</span><br><span class="line"><!DOCTYPE html></span><br><span class="line"><html lang="en"></span><br><span class="line"><head></span><br><span class="line"> <meta charset="UTF-8"></span><br><span class="line"> <title>Document</title></span><br><span class="line"> <script></span><br><span class="line"> function getData() {</span><br><span class="line"> var iframe =document.getElementById('iframe');</span><br><span class="line"> iframe.onload = function() {</span><br><span class="line"> var data = iframe.contentWindow.name; // 得到</span><br><span class="line"> }</span><br><span class="line"> iframe.src = 'b.html'; // 这里b和a同源</span><br><span class="line"> }</span><br><span class="line"> </script></span><br><span class="line"></head></span><br><span class="line"><body></span><br><span class="line"> <iframe src="http://www.qiutc.com/data.html" style="display:none" onload="getData()"</iframe></span><br><span class="line"></body></span><br><span class="line"></html></span><br></pre></td></tr></table></figure></p><h4 id="5-HTML5中新引进的window-postMessage"><a href="#5-HTML5中新引进的window-postMessage" class="headerlink" title="5. HTML5中新引进的window.postMessage"></a>5. HTML5中新引进的window.postMessage</h4><p>window.postMessage(message, targetOrigin) 方法是html5新引进的特性,可以使用它来向其它的window对象发送消息,<br>无论这个window对象是属于同源或不同源。<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">调用postMessage方法的window对象是指要接收消息的那一个window对象,该方法的第一个参数message为要发送的消息,</span><br><span class="line">类型只能为字符串;第二个参数targetOrigin用来限定接收消息的那个window对象所在的域,如果不想限定域,可以使用通配符 * 。</span><br><span class="line">需要接收消息的window对象,可是通过监听自身的message事件来获取传过来的消息,消息内容储存在该事件对象的data属性中。</span><br><span class="line">上面所说的向其他window对象发送消息,其实就是指一个页面有几个框架的那种情况,因为每一个框架都有一个window对象。</span><br><span class="line">在讨论第种方法的时候,我们说过,不同域的框架间是可以获取到对方的window对象的,虽然没什么用,</span><br><span class="line">但是有一个方法是可用的-window.postMessage。下面看一个简单的示例,有两个页面:</span><br><span class="line"></span><br><span class="line">// 主页面 blog.qiutc.com</span><br><span class="line"><script></span><br><span class="line">function onLoad() {</span><br><span class="line"> var iframe =document.getElementById('iframe');</span><br><span class="line"> var iframeWindow = iframe.contentWindow;</span><br><span class="line"> iframeWindow.postMessage("I'm message from main page.");</span><br><span class="line">}</span><br><span class="line"></script></span><br><span class="line"><iframe src="http://21cm.github.io/b.html" onload="onLoad()"</iframe></span><br><span class="line">// b 页面</span><br><span class="line"><script></span><br><span class="line">window.onmessage = function(e) {</span><br><span class="line"> e = e || event;</span><br><span class="line"> console.log(e.data);</span><br><span class="line">}</span><br><span class="line"></script></span><br></pre></td></tr></table></figure></p><h4 id="6-CSST-CSS-Text-Transformation"><a href="#6-CSST-CSS-Text-Transformation" class="headerlink" title="6.CSST (CSS Text Transformation)"></a>6.CSST (CSS Text Transformation)</h4><p>一种用 CSS 跨域传输文本的方案。<br>优点:相比 JSONP 更为安全,不需要执行跨站脚本。<br>缺点:没有 JSONP 适配广,CSST 依赖支持 CSS3 的浏览器。<br>原理:通过读取 CSS3 content 属性获取传送内容。<br>具体可以参考:CSST (CSS Text Transformation)</p><h4 id="如何解决跨域问题"><a href="#如何解决跨域问题" class="headerlink" title="如何解决跨域问题"></a>如何解决跨域问题</h4><h4 id="1-JSONP:"><a href="#1-JSONP:" class="headerlink" title="1.JSONP:"></a>1.JSONP:</h4><p><code>原理是:动态插入script标签,通过script标签引入一个js文件,这个js文件载入成功后会执行我们在url参数中指定的函数,并且会把我们需要的json数据作为参数传入。</code><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></pre></td><td class="code"><pre><span class="line">由于同源策略的限制,XmlHttpRequest只允许请求当前源(域名、协议、端口)的资源,为了实现跨域请求,可以通过script标签实现跨域请求,然后在服务端输出JSON数据并执行回调函数,从而解决了跨域的数据请求。</span><br><span class="line">优点是兼容性好,简单易用,支持浏览器与服务器双向通信。缺点是只支持GET请求。</span><br><span class="line">JSONP:json+padding(内填充),顾名思义,就是把JSON填充到一个盒子里</span><br><span class="line"><script></span><br><span class="line"> function createJs(sUrl){</span><br><span class="line"> var oScript = document.createElement('script');</span><br><span class="line"> oScript.type = 'text/javascript';</span><br><span class="line"> oScript.src = sUrl;</span><br><span class="line"> document.getElementsByTagName('head')[0].appendChild(oScript);</span><br><span class="line"> }</span><br><span class="line"> createJs('jsonp.js');</span><br><span class="line"> box({</span><br><span class="line"> 'name': 'test'</span><br><span class="line"> });</span><br><span class="line"> function box(json){</span><br><span class="line"> alert(json.name);</span><br><span class="line"> }</span><br><span class="line"></script></span><br></pre></td></tr></table></figure></p><h4 id="2-CORS"><a href="#2-CORS" class="headerlink" title="2.CORS"></a>2.CORS</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">服务器端对于CORS的支持,主要就是通过设置Access-Control-Allow-Origin来进行的。</span><br><span class="line">如果浏览器检测到相应的设置,就可以允许Ajax进行跨域的访问。</span><br></pre></td></tr></table></figure><h4 id="3-通过修改document-domain来跨子域"><a href="#3-通过修改document-domain来跨子域" class="headerlink" title="3.通过修改document.domain来跨子域"></a>3.通过修改document.domain来跨子域</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">将子域和主域的document.domain设为同一个主域.前提条件:这两个域名必须属于同一个基础域名!而且所用的协议,端口都要一致,</span><br><span class="line">否则无法利用document.domain进行跨域,主域相同的使用document.domain</span><br></pre></td></tr></table></figure><h4 id="4-使用window-name来进行跨域"><a href="#4-使用window-name来进行跨域" class="headerlink" title="4.使用window.name来进行跨域"></a>4.使用window.name来进行跨域</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对象有个name属性,该属性有个特征:即在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个window.name的,</span><br><span class="line">每个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的所有页面中的</span><br></pre></td></tr></table></figure><h4 id="5-使用HTML5中新引进的window-postMessage方法来跨域传送数据"><a href="#5-使用HTML5中新引进的window-postMessage方法来跨域传送数据" class="headerlink" title="5.使用HTML5中新引进的window.postMessage方法来跨域传送数据"></a>5.使用HTML5中新引进的window.postMessage方法来跨域传送数据</h4><h4 id="6-还有flash、在服务器上设置代理页面等跨域方式。"><a href="#6-还有flash、在服务器上设置代理页面等跨域方式。" class="headerlink" title="6.还有flash、在服务器上设置代理页面等跨域方式。"></a>6.还有flash、在服务器上设置代理页面等跨域方式。</h4><p><code>window.name的方法既不复杂,也能兼容到几乎所有浏览器,这真是极好的一种跨域方法。</code></p>]]></content>
<summary type="html">
<h4 id="1-跨域资源共享-CORS"><a href="#1-跨域资源共享-CORS" class="headerlink" title="1. 跨域资源共享 CORS"></a>1. 跨域资源共享 CORS</h4><p>对于web开发来讲,由于浏览器的同源策略,我们需
</summary>
<category term="前端" scheme="https://csskr.js.org/categories/%E5%89%8D%E7%AB%AF/"/>
<category term="javascript" scheme="https://csskr.js.org/tags/javascript/"/>
<category term="javascript-跨域" scheme="https://csskr.js.org/tags/javascript-%E8%B7%A8%E5%9F%9F/"/>
<category term="javascript-跨域方式" scheme="https://csskr.js.org/tags/javascript-%E8%B7%A8%E5%9F%9F%E6%96%B9%E5%BC%8F/"/>
</entry>
<entry>
<title>前端知识点总结之javascript-ajax</title>
<link href="https://csskr.js.org/2018/05/26/js-ajax/"/>
<id>https://csskr.js.org/2018/05/26/js-ajax/</id>
<published>2018-05-26T09:00:00.000Z</published>
<updated>2018-05-26T09:20:53.763Z</updated>
<content type="html"><![CDATA[<h4 id="Ajax工作原理"><a href="#Ajax工作原理" class="headerlink" title="Ajax工作原理"></a>Ajax工作原理</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></pre></td><td class="code"><pre><span class="line">1.使用CSS和XHTML来表示。</span><br><span class="line">2. 使用DOM模型来交互和动态显示。</span><br><span class="line">3.使用XMLHttpRequest来和服务器进行异步通信。</span><br><span class="line">4.使用javascript来绑定和调用。</span><br></pre></td></tr></table></figure><h4 id="ajax原理和XmlHttpRequest对象"><a href="#ajax原理和XmlHttpRequest对象" class="headerlink" title="ajax原理和XmlHttpRequest对象"></a>ajax原理和XmlHttpRequest对象</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></pre></td><td class="code"><pre><span class="line">Ajax的原理简单来说通过XmlHttpRequest对象来向服务器发异步请求,从服务器获得数据,然后用javascript来操作DOM而更新页面。</span><br><span class="line">这其中最关键的一步就是从服务器获得请求数据。要清楚这个过程和原理,我们必须对 XMLHttpRequest有所了解。</span><br><span class="line">XMLHttpRequest是ajax的核心机制,它是在IE5中首先引入的,是一种支持异步请求的技术。简单的说,也就是javascript可以及时向服务器提出请求和处理响应,</span><br><span class="line">而不阻塞用户。达到无刷新的效果。</span><br></pre></td></tr></table></figure><p> 首先,我们先来看看XMLHttpRequest这个对象的属性。<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></pre></td><td class="code"><pre><span class="line"> onreadystatechange 每次状态改变所触发事件的事件处理程序。</span><br><span class="line"> responseText 从服务器进程返回数据的字符串形式。</span><br><span class="line"> responseXML 从服务器进程返回的DOM兼容的文档数据对象。</span><br><span class="line"> status 从服务器返回的数字代码,比如常见的404(未找到)和200(已就绪)</span><br><span class="line"> status Text 伴随状态码的字符串信息</span><br><span class="line"> readyState 对象状态值</span><br><span class="line"> 0 (未初始化) 对象已建立,但是尚未初始化(尚未调用open方法)</span><br><span class="line"> 1 (初始化) 对象已建立,尚未调用send方法</span><br><span class="line"> 2 (发送数据) send方法已调用,但是当前的状态及http头未知</span><br><span class="line"> 3 (数据传送中) 已接收部分数据,因为响应及http头不全,这时通过responseBody和responseText获取部分数据会出现错误,</span><br><span class="line"> 4 (完成) 数据接收完毕,此时可以通过通过responseXml和responseText获取完整的回应数据</span><br></pre></td></tr></table></figure></p><p>但是,由于各浏览器之间存在差异,所以创建一个XMLHttpRequest对象可能需要不同的方法。这个差异主要体现在IE和其它浏览器之间。<br>下面是一个比较标准的创建XMLHttpRequest对象的方法。</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></pre></td><td class="code"><pre><span class="line">function CreateXmlHttp() {</span><br><span class="line"></span><br><span class="line"> //非IE浏览器创建XmlHttpRequest对象</span><br><span class="line"> if (window.XmlHttpRequest) {</span><br><span class="line"> xmlhttp = new XmlHttpRequest();</span><br><span class="line"> }</span><br><span class="line"> //IE浏览器创建XmlHttpRequest对象</span><br><span class="line"> if (window.ActiveXObject) {</span><br><span class="line"> try {</span><br><span class="line"> xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");</span><br><span class="line"> }</span><br><span class="line"> catch (e) {</span><br><span class="line"> try {</span><br><span class="line"> xmlhttp = new ActiveXObject("msxml2.XMLHTTP");</span><br><span class="line"> }</span><br><span class="line"> catch (ex) { }</span><br><span class="line"> }</span><br><span class="line"> }</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></pre></td><td class="code"><pre><span class="line">function ajax() {</span><br><span class="line"> var data = document.getElementById("username").value;</span><br><span class="line"> CreateXmlHttp();</span><br><span class="line"> if (!xmlhttp) {</span><br><span class="line"> alert("创建xmlhttp对象异常!");</span><br><span class="line"> return false;</span><br><span class="line"> }</span><br><span class="line"> xmlhttp.open("POST", url, false);</span><br><span class="line"> xmlhttp.onreadystatechange = function () {</span><br><span class="line"> if (xmlhttp.readyState == 4) {</span><br><span class="line"> document.getElementById("user1").innerHTML = "数据正在加载...";</span><br><span class="line"> if (xmlhttp.status == 200) {</span><br><span class="line"> document.write(xmlhttp.responseText);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> xmlhttp.send();</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>如上所示,函数首先检查XMLHttpRequest的整体状态并且保证它已经完成(readyStatus=4),即数据已经发送完毕。<br>然后根据服务器的设定询问请求状态,如果一切已经就绪(status=200),那么就执行下面需要的操作。<br>对于XmlHttpRequest的两个方法,open和send,其中:<br>open方法指定了:<br>a、向服务器提交数据的类型,即post还是get。<br>b、请求的url地址和传递的参数。<br>c、传输方式,false为同步,true为异步。默认为true。如果是异步通信方式(true),客户机就不等待服务器的响应;<br>如果是同步方式(false),客户机就要等到服务器返回消息后才去执行其他操作。我们需要根据实际需要来指定同步方式,在某些页面中,<br>可能会发出多个请求,甚至是有组织有计划有队形大规模的高强度的request,而后一个是会覆盖前一个的,这个时候当然要指定同步方式。</p><p>Send方法用来发送请求。</p><p>知道了XMLHttpRequest的工作流程,我们可以看出,XMLHttpRequest是完全用来向服务器发出一个请求的,它的作用也局限于此,<br>但它的作用是整个ajax实现的关键,因为ajax无非是两个过程,发出请求和响应请求。并且它完全是一种客户端的技术。<br>而XMLHttpRequest正是处理了服务器端和客户端通信的问题所以才会如此的重要。<br>现在,我们对ajax的原理大概可以有一个了解了。我们可以把服务器端看成一个数据接口,它返回的是一个纯文本流,当然,这个文本流可以是XML格式,<br>可以是Html,可以是Javascript代码,也可以只是一个字符串。<br>这时候,XMLHttpRequest向服务器端请求这个页面,服务器端将文本的结果写入页面,这和普通的web开发流程是一样的,不同的是,<br>客户端在异步获取这个结果后,不是直接显示在页面,而是先由javascript来处理,然后再显示在页面。至于现在流行的很多ajax控件,<br>比如magicajax等,可以返回DataSet等其它数据类型,只是将这个过程封装了的结果,本质上他们并没有什么太大的区别。</p><h4 id="ajax的优点"><a href="#ajax的优点" class="headerlink" title="ajax的优点"></a>ajax的优点</h4><p> Ajax的给我们带来的好处大家基本上都深有体会,在这里我只简单的讲几点:<br> 1、最大的一点是页面无刷新,在页面内与服务器通信,给用户的体验非常好。<br> 2、使用异步方式与服务器通信,不需要打断用户的操作,具有更加迅速的响应能力。<br> 3、可以把以前一些服务器负担的工作转嫁到客户端,利用客户端闲置的能力来处理,减轻服务器和带宽的负担,节约空间和宽带租用成本。并且减轻服务器的负担,ajax的原则是“按需取数据”,可以最大程度的减少冗余请求,和响应对服务器造成的负担。<br> 4、基于标准化的并被广泛支持的技术,不需要下载插件或者小程序。</p><h4 id="ajax的缺点"><a href="#ajax的缺点" class="headerlink" title="ajax的缺点"></a>ajax的缺点</h4><p>下面所阐述的ajax的缺陷都是它先天所产生的。<br>1、ajax干掉了back按钮,即对浏览器后退机制的破坏。后退按钮是一个标准的web站点的重要功能,但是它没法和js进行很好的合作。<br> 这是ajax所带来的一个比较严重的问题,因为用户往往是希望能够通过后退来取消前一次操作的。那么对于这个问题有没有办法?<br> 答案是肯定的,用过Gmail的知道,Gmail下面采用的ajax技术解决了这个问题,在Gmail下面是可以后退的,但是,它也并不能改变ajax的机制,<br> 它只是采用的一个比较笨但是有效的办法,即用户单击后退按钮访问历史记录时,通过创建或使用一个隐藏的IFRAME来重现页面上的变更。<br> (例如,当用户在Google Maps中单击后退时,它在一个隐藏的IFRAME中进行搜索,然后将搜索结果反映到Ajax元素上,以便将应用程序状态恢复到当时的状态。)<br>但是,虽然说这个问题是可以解决的,但是它所带来的开发成本是非常高的,和ajax框架所要求的快速开发是相背离的。这是ajax所带来的一个非常严重的问题。<br> 2、安全问题。技术同时也对IT企业带来了新的安全威胁,ajax技术就如同对企业数据建立了一个直接通道。这使得开发者在不经意间会暴露比以前更多的数据<br> 和服务器逻辑。ajax的逻辑可以对客户端的安全扫描技术隐藏起来,允许黑客从远端服务器上建立新的攻击。<br> 还有ajax也难以避免一些已知的安全弱点,诸如跨站点脚步攻击、SQL注入攻击和基于credentials的安全漏洞等。<br> 3、对搜索引擎的支持比较弱。<br> 4、破坏了程序的异常机制。至少从目前看来,像ajax.dll,ajaxpro.dll这些ajax框架是会破坏程序的异常机制的。<br> 5、另外,像其他方面的一些问题,比如说违背了url和资源定位的初衷。<br> 例如,我给你一个url地址,如果采用了ajax技术,也许你在该url地址下面看到的和我在这个url地址下看到的内容是不同的。这个和资源定位的初衷是相背离的。<br> 6、一些手持设备(如手机、PDA等)现在还不能很好的支持ajax,比如说我们在手机的浏览器上打开采用ajax技术的网站时,<br> 它目前是不支持的,当然,这个问题和我们没太多关系。</p><p> 使用jsonp有数据返回,但是success不执行的解决办法。</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></pre></td><td class="code"><pre><span class="line">$.ajax({</span><br><span class="line"> type:"get", //请求方式</span><br><span class="line"> async:true, //是否异步</span><br><span class="line"> url:"http://www.domain.net/url",</span><br><span class="line"> dataType:"jsonp", //跨域json请求一定是jsonp</span><br><span class="line"> jsonp: "callbackparam", //跨域请求的参数名,默认是callback</span><br><span class="line"> //jsonpCallback:"successCallback", //自定义跨域参数值,回调函数名也是一样,默认为jQuery自动生成的字符串</span><br><span class="line"> data:{"query":"civilnews"}, //请求参数</span><br><span class="line"> beforeSend: function() {</span><br><span class="line"> //请求前的处理</span><br><span class="line"> },</span><br><span class="line"> success: function(data) {</span><br><span class="line"> //请求成功处理,和本地回调完全一样</span><br><span class="line"> },</span><br><span class="line"> complete: function() {</span><br><span class="line"> //请求完成的处理</span><br><span class="line"> },</span><br><span class="line"> error: function() {</span><br><span class="line"> //请求出错处理</span><br><span class="line"> }</span><br><span class="line">});</span><br></pre></td></tr></table></figure><p>参考文档:<br><a href="https://www.cnblogs.com/freeweb/p/4908832.html" title="jQuery ajax跨域请求的解决方法" target="_blank" rel="noopener">jQuery ajax跨域请求的解决方法</a><br><a href="https://blog.csdn.net/erica_1230/article/details/43983801" title="关于jsonp没有调用success回调方法" target="_blank" rel="noopener">关于jsonp没有调用success回调方法</a><br><a href="https://www.cnblogs.com/ChenChunChang/p/6695411.html" title="JSONP跨域访问数据传输" target="_blank" rel="noopener">JSONP跨域访问数据传输</a></p>]]></content>
<summary type="html">
<h4 id="Ajax工作原理"><a href="#Ajax工作原理" class="headerlink" title="Ajax工作原理"></a>Ajax工作原理</h4><figure class="highlight plain"><table><tr><td cl
</summary>
<category term="前端" scheme="https://csskr.js.org/categories/%E5%89%8D%E7%AB%AF/"/>
<category term="javascript" scheme="https://csskr.js.org/tags/javascript/"/>
<category term="ajax" scheme="https://csskr.js.org/tags/ajax/"/>
<category term="javascript-ajax" scheme="https://csskr.js.org/tags/javascript-ajax/"/>
</entry>
<entry>
<title>javascript高级函数实现AOP</title>
<link href="https://csskr.js.org/2018/05/26/js-AOP/"/>
<id>https://csskr.js.org/2018/05/26/js-AOP/</id>
<published>2018-05-26T01:10:00.000Z</published>
<updated>2018-05-26T01:31:34.924Z</updated>
<content type="html"><![CDATA[<ul><li>高阶函数是指满足如下两个条件之一或者两个的函数:</li><li>1.函数作为参数传递给其它函数</li><li>2.函数作为返回值返回</li></ul><ul><li>使用高阶函数实现AOP</li><li>使用AOP动态给函数添加功能,这在js中非常方便,特别适用于装饰者模式!<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">function.prototype.before = function (beforeFn) {</span><br><span class="line"> var self = this;</span><br><span class="line"> return function () { //返回包含了原函数和新函数的"代理函数"</span><br><span class="line"> // beforeFn(arguments);</span><br><span class="line"> // self(arguments);</span><br><span class="line"> beforeFn.apply(this, arguments);</span><br><span class="line"> return self.apply(this, arguments);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line">function.prototype.after = function (afterFn) {</span><br><span class="line"> var self = this;</span><br><span class="line"> return function () {</span><br><span class="line"> var result = self.apply(this, arguments);</span><br><span class="line"> afterFn.apply(this, arguments);</span><br><span class="line"> return result;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line">var func = function () {</span><br><span class="line"> console.log('业务逻辑处理...');</span><br><span class="line">}</span><br><span class="line">func = func.before(function () {</span><br><span class="line"> console.log('调用前记录日志...');</span><br><span class="line">}).after(function () {</span><br><span class="line"> console.log('调用后执行清理工作...');</span><br><span class="line">});</span><br><span class="line">func();</span><br></pre></td></tr></table></figure></li></ul>]]></content>
<summary type="html">
<ul>
<li>高阶函数是指满足如下两个条件之一或者两个的函数:</li>
<li>1.函数作为参数传递给其它函数</li>
<li>2.函数作为返回值返回</li>
</ul>
<ul>
<li>使用高阶函数实现AOP</li>
<li>使用AOP动态给函数添加功能,这在js
</summary>
<category term="前端" scheme="https://csskr.js.org/categories/%E5%89%8D%E7%AB%AF/"/>
<category term="javascript" scheme="https://csskr.js.org/tags/javascript/"/>
<category term="javascript高级函数" scheme="https://csskr.js.org/tags/javascript%E9%AB%98%E7%BA%A7%E5%87%BD%E6%95%B0/"/>
<category term="javascript-AOP" scheme="https://csskr.js.org/tags/javascript-AOP/"/>
</entry>
<entry>
<title>javascript高级函数与颗粒化</title>
<link href="https://csskr.js.org/2018/05/26/js-Granulation-of-advanced-functions/"/>
<id>https://csskr.js.org/2018/05/26/js-Granulation-of-advanced-functions/</id>
<published>2018-05-26T01:00:00.000Z</published>
<updated>2018-05-26T01:24:13.095Z</updated>
<content type="html"><![CDATA[<ul><li>currying又称为部分求值。</li><li>一个currying函数接受了一些参数后,并不会立即求值,而是继续返回另外一个函数,并利用闭包将刚才传入的参数保存起来。</li><li><p>等到函数需要真正求值的时候,之前传入的参数会被一次性用于求值。</p></li><li><p>例子1:加入要编写一个函数,计算每个月的开销。每天需要将当天的花销也保存下来。</p></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></pre></td><td class="code"><pre><span class="line">var monthCost = 0;</span><br><span class="line">var cost = function (dayCost) {</span><br><span class="line"> monthCost += dayCost;</span><br><span class="line">}</span><br><span class="line">cost(100); //第一天开销</span><br><span class="line">cost(80); //第二天开销</span><br><span class="line">cost(120); //第三天开销</span><br><span class="line">cost(200); //当月最后一天开销</span><br><span class="line">console.log(monthCost); //总共500</span><br></pre></td></tr></table></figure><ul><li>cost柯里化的简陋实现</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></pre></td><td class="code"><pre><span class="line">var cost = (function () {</span><br><span class="line"> var args = []; //使用闭包来记录每次传入的参数</span><br><span class="line"> return function () {</span><br><span class="line"> if (arguments.length === 0) { //没有传递参数时,求值</span><br><span class="line"> var total = 0;</span><br><span class="line"> for (var i = 0; i < args.length; i++) {</span><br><span class="line"> total += args[i];</span><br><span class="line"> }</span><br><span class="line"> return total;</span><br><span class="line"> } else {</span><br><span class="line"> [].push.apply(args, arguments);</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">cost(100); //未求值</span><br><span class="line">cost(200); //未求值</span><br><span class="line">cost(300, 400, 500); //未求值</span><br><span class="line">console.log(cost()); //求值! 1500</span><br></pre></td></tr></table></figure><ul><li>通用的currying函数,接受一个函数作为参数,并将该函数柯里化</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 currying = function (fn) {</span><br><span class="line"> var args = [];</span><br><span class="line"> return function () {</span><br><span class="line"> if (arguments.length === 0) {</span><br><span class="line"> return fn.apply(this, args);</span><br><span class="line"> } else {</span><br><span class="line"> [].push.apply(args, arguments);</span><br><span class="line"> return arguments.callee;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line">var cost = (function () {</span><br><span class="line"> var money = 0;</span><br><span class="line"> return function () {</span><br><span class="line"> for (var i = 0, l = arguments.length; i < l; i++) {</span><br><span class="line"> money += arguments[i];</span><br><span class="line"> }</span><br><span class="line"> return money;</span><br><span class="line"> }</span><br><span class="line">})();</span><br><span class="line"></span><br><span class="line">var cost = currying(cost); //柯里化cost函数</span><br><span class="line">cost(100);</span><br><span class="line">cost(200);</span><br><span class="line">cost(300, 400);</span><br><span class="line">console.log(cost()); //1000</span><br></pre></td></tr></table></figure><ul><li>反柯里化uncurrying:</li><li>使用call和apply时,能够把任意对象当做this传入某个方法,这样,方法中用到的this就不再局限于原来规定的对象,</li><li>而是加以泛化而得到更广的适用性。</li><li>有没有办法把泛化this的过程提取出来? 这就是uncurrying要做的事情!</li><li>下面是uncurrying的一种实现:</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></pre></td><td class="code"><pre><span class="line">function.prototype.uncurrying = function () {</span><br><span class="line"> var self = this;</span><br><span class="line"> return function () {</span><br><span class="line"> var context = Array.prototype.shift.call(arguments);</span><br><span class="line"> return self.apply(context, arguments);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>下面就可以将<code>Array.prototype.push.call</code>转换成一个泛化得函数<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">var push = Array.prototype.push.uncurrying();</span><br><span class="line">var slice = Array.prototype.slice.uncurrying();</span><br><span class="line">(function () {</span><br><span class="line"> push(arguments, 4);</span><br><span class="line"> console.log(slice(arguments));</span><br><span class="line">})(1, 2, 3);</span><br></pre></td></tr></table></figure></p><ul><li>下面是uncurrying的另一种实现</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">function.prototype.uncurrying2 = function () {</span><br><span class="line"> var self = this;</span><br><span class="line"> return function () {</span><br><span class="line"> return Function.prototype.call.apply(self, arguments);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<ul>
<li>currying又称为部分求值。</li>
<li>一个currying函数接受了一些参数后,并不会立即求值,而是继续返回另外一个函数,并利用闭包将刚才传入的参数保存起来。</li>
<li><p>等到函数需要真正求值的时候,之前传入的参数会被一次性用于求值。<
</summary>
<category term="前端" scheme="https://csskr.js.org/categories/%E5%89%8D%E7%AB%AF/"/>
<category term="javascript" scheme="https://csskr.js.org/tags/javascript/"/>
<category term="javascript高级函数" scheme="https://csskr.js.org/tags/javascript%E9%AB%98%E7%BA%A7%E5%87%BD%E6%95%B0/"/>
<category term="javascript颗粒化" scheme="https://csskr.js.org/tags/javascript%E9%A2%97%E7%B2%92%E5%8C%96/"/>
</entry>
<entry>
<title>javascript-闭包</title>
<link href="https://csskr.js.org/2018/05/24/js-closure/"/>
<id>https://csskr.js.org/2018/05/24/js-closure/</id>
<published>2018-05-24T12:30:00.000Z</published>
<updated>2018-05-24T13:56:58.891Z</updated>
<content type="html"><![CDATA[<ul><li>闭包的作用:</li><li>1.封装变量</li><li>2.延续局部变量的寿命</li><li>3.闭包和面向对象设计:实现私有数据和方法的封装(本质还是1,封装变量)</li><li>闭包能使局部变量的生命期延长,这点与全局作用域的变量是一致的,不能算是内存泄漏!</li><li>闭包与内存泄漏有关的部分是:</li><li>使用闭包容易造成循环引用,如果闭包的作用域中保存着一些DOM节点,这时候有可能造成内存泄漏(互相引用导致内存无法释放)</li><li><p>例1</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></pre></td><td class="code"><pre><span class="line">var increment = function () {</span><br><span class="line"> var count = 1;</span><br><span class="line"> return {</span><br><span class="line"> inc: function () {</span><br><span class="line"> return count++;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line">console.log(increment.count); //undefined</span><br><span class="line">var counter = increment();</span><br><span class="line">console.log(counter.inc());</span><br><span class="line">console.log(counter.inc());</span><br><span class="line">console.log(counter.inc());</span><br><span class="line"></span><br><span class="line">var counter2 = increment();</span><br><span class="line">console.log(counter2.inc());</span><br><span class="line">console.log(counter == counter2); //false,注:闭包每次返回的对象都不一样!</span><br></pre></td></tr></table></figure></li><li><p>例2</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></pre></td><td class="code"><pre><span class="line">var getTypeChecker = function () {</span><br><span class="line"> var types = {};</span><br><span class="line"></span><br><span class="line"> for (var i = 0, type; type = ['String', 'Number', 'Array'][i++];) {</span><br><span class="line"> //使用闭包来封闭每次循环的变量</span><br><span class="line"> (function (type) {</span><br><span class="line"> types['is' + type] = function (obj) {</span><br><span class="line"> return Object.prototype.toString.call(obj) === '[object ' + type + ']';</span><br><span class="line"> }</span><br><span class="line"> })(type);</span><br><span class="line"> }</span><br><span class="line"> return types;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">var checker = getTypeChecker();</span><br><span class="line">console.log(checker.isArray([])); // true</span><br><span class="line">console.log(checker.isString([])); //false</span><br><span class="line">console.log(checker.isString('hello')); //true</span><br></pre></td></tr></table></figure></li></ul>]]></content>
<summary type="html">
<ul>
<li>闭包的作用:</li>
<li>1.封装变量</li>
<li>2.延续局部变量的寿命</li>
<li>3.闭包和面向对象设计:实现私有数据和方法的封装(本质还是1,封装变量)</li>
<li>闭包能使局部变量的生命期延长,这点与全局作用域的变量是一致的,不
</summary>
<category term="前端" scheme="https://csskr.js.org/categories/%E5%89%8D%E7%AB%AF/"/>
<category term="javascript" scheme="https://csskr.js.org/tags/javascript/"/>
<category term="javascript-闭包" scheme="https://csskr.js.org/tags/javascript-%E9%97%AD%E5%8C%85/"/>
</entry>
<entry>
<title>javascript-call和javascript-apply的用法,实现javascript-bind</title>
<link href="https://csskr.js.org/2018/05/24/js-call&&apply&&bind/"/>
<id>https://csskr.js.org/2018/05/24/js-call&&apply&&bind/</id>
<published>2018-05-24T12:20:00.000Z</published>
<updated>2018-05-24T13:06:44.601Z</updated>
<content type="html"><![CDATA[<ul><li>function.prototype.call和 function.prototype.apply的作用:</li><li><ol><li>改变this指向</li></ol></li><li><ol start="2"><li>借用借他对象的方法</li></ol></li><li><p>function.prototype.bind 函数用于指定函数内部this的指向</p></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></pre></td><td class="code"><pre><span class="line">function.prototype.bind = function () {</span><br><span class="line"> var self = this; //保存原函数</span><br><span class="line"> var args = [].slice.call(arguments);</span><br><span class="line"> var context = args.shift();</span><br><span class="line"> return function () {</span><br><span class="line"> var argsArr = [].slice.call(arguments);</span><br><span class="line"> return self.apply(context, args.concat(argsArr));</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line">var bindTest = function (age, grade) {</span><br><span class="line"> console.log(this.name);</span><br><span class="line"> console.log([age, grade]);</span><br><span class="line">}.bind({name: 'Jack'}, 22);</span><br><span class="line">bindTest(95.0);</span><br></pre></td></tr></table></figure></li></ul>]]></content>
<summary type="html">
<ul>
<li>function.prototype.call和 function.prototype.apply的作用:</li>
<li><ol>
<li>改变this指向</li>
</ol>
</li>
<li><ol start="2">
<li>借用借他对象的方法<
</summary>
<category term="前端" scheme="https://csskr.js.org/categories/%E5%89%8D%E7%AB%AF/"/>
<category term="javascript" scheme="https://csskr.js.org/tags/javascript/"/>
<category term="javascript-call" scheme="https://csskr.js.org/tags/javascript-call/"/>
<category term="javascript-apply" scheme="https://csskr.js.org/tags/javascript-apply/"/>
<category term="javascript-bind" scheme="https://csskr.js.org/tags/javascript-bind/"/>
</entry>
<entry>
<title>javascript原型式继承与object.create</title>
<link href="https://csskr.js.org/2018/05/24/js-bject.create/"/>
<id>https://csskr.js.org/2018/05/24/js-bject.create/</id>
<published>2018-05-24T12:10:00.000Z</published>
<updated>2018-05-24T12:44:18.603Z</updated>
<content type="html"><![CDATA[<ul><li>动态类型语言的缺点是无法在编译期间保证变量的类型,而只能在运行时才能确定。</li><li><p>就像在商店买了一包牛肉味辣条,等到真正吃到嘴里才知道它到底是不是牛肉味。O(∩_∩)O</p></li><li><p>原型式继承: 对象是通过克隆另一个对象而来的</p></li><li>javascript得到一个对象,就是要找到一个对象,然后克隆它。</li><li>只不过引擎内部屏蔽了细节,暴露给我们的是一个 new Object() 或 var obj={} 指令</li></ul><p>模拟Object.create方法的实现:</p><pre><code>var clone = function (obj) { var F = function () { }; F.prototype = obj; return new F();}var obj = {name: 'jack', age: 22};var obj2 = clone(obj);console.log(obj2.name + '-' + obj2.age);</code></pre>]]></content>
<summary type="html">
<ul>
<li>动态类型语言的缺点是无法在编译期间保证变量的类型,而只能在运行时才能确定。</li>
<li><p>就像在商店买了一包牛肉味辣条,等到真正吃到嘴里才知道它到底是不是牛肉味。O(∩_∩)O</p>
</li>
<li><p>原型式继承: 对象是通过克隆另一个对象而
</summary>
<category term="前端" scheme="https://csskr.js.org/categories/%E5%89%8D%E7%AB%AF/"/>
<category term="javascript" scheme="https://csskr.js.org/tags/javascript/"/>
<category term="javascript原型式继承" scheme="https://csskr.js.org/tags/javascript%E5%8E%9F%E5%9E%8B%E5%BC%8F%E7%BB%A7%E6%89%BF/"/>
<category term="object.create" scheme="https://csskr.js.org/tags/object-create/"/>
</entry>
</feed>