forked from damonare/damonare.github.io
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
3088 lines (2875 loc) · 617 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
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Damonare的个人博客</title>
<subtitle>不念过去,不畏将来</subtitle>
<link href="/atom.xml" rel="self"/>
<link href="http://damonare.github.io/"/>
<updated>2017-05-22T15:45:12.000Z</updated>
<id>http://damonare.github.io/</id>
<author>
<name>Damonare</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>我的前端进阶之路</title>
<link href="http://damonare.github.io/2017/04/24/%E6%88%91%E7%9A%84%E5%89%8D%E7%AB%AF%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/"/>
<id>http://damonare.github.io/2017/04/24/我的前端进阶之路/</id>
<published>2017-04-24T12:57:34.000Z</published>
<updated>2017-05-22T15:45:12.000Z</updated>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p><strong>总括:</strong> 包含这三个月来碰到的一些觉得比较好的面试题,三个月没怎么写博客着实有些手痒,哈哈哈。</p>
<ul>
<li><p>原文地址:<a href="http://damonare.github.io/2017/04/24/%E6%88%91%E7%9A%84%E5%89%8D%E7%AB%AF%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/#more">我的前端进阶之路</a></p>
</li>
<li><p>知乎专栏&&简书专题:<a href="https://zhuanlan.zhihu.com/damonare" target="_blank" rel="external">前端进击者(知乎)</a>&&<a href="http://www.jianshu.com/collection/bbaa63e264f5" target="_blank" rel="external">前端进击者(简书)</a></p>
</li>
<li><p>博主博客地址:<a href="http://damonare.cn" target="_blank" rel="external">Damonare的个人博客</a></p>
</li>
</ul>
<p><strong>烈火试真金,逆境试强者</strong></p>
<a id="more"></a>
<h2 id="正文"><a href="#正文" class="headerlink" title="正文"></a>正文</h2><h4 id="React和Vue对比"><a href="#React和Vue对比" class="headerlink" title="React和Vue对比"></a>React和Vue对比</h4><p>相同点:</p>
<ol>
<li>数据驱动视图,提供响应式的视图组件</li>
<li>都有Virtual DOM,组件化开发,通过props参数进行父子组件数据的传递,都实现webComponents规范</li>
<li>数据流动单向</li>
<li>都支持服务端渲染</li>
<li>都有支持native的方案,React的<code>React native</code>,Vue的<code>weex</code></li>
</ol>
<p>不同点:</p>
<ol>
<li><p>社区:React社区还是要比vue大很多;</p>
</li>
<li><p>开发模式:React在view层侵入性还是要比Vue大很多的,React严格上只针对MVC的view层,Vue则是MVVM模式的一种实现;</p>
</li>
<li><p>数据绑定:Vue有实现了双向数据绑定,React数据流动是单向的</p>
</li>
<li><p>数据渲染:对于大规模数据渲染,React要比Vue更快,渲染机制启动时候要做的工作比较多;</p>
</li>
<li><p>数据更新方面:Vue 由于采用依赖追踪,默认就是优化状态:你动了多少数据,就触发多少更新,不多也不少。React在复杂的应用里有两个选择:</p>
<p>(1). 手动添加 shouldComponentUpdate 来避免不需要的 vdom re-render。 (2).Components 尽可能都用 pureRenderMixin,然后采用 redux 结构 + Immutable.js;</p>
</li>
<li><p>开发风格的偏好:React 推荐的做法是 JSX + inline style,也就是把 HTML 和 CSS 全都写进 JavaScript 了,即”all in js”;Vue进阶之后推荐的是使用 webpack + vue-loader 的单文件组件格式,即html,css,js写在同一个文件;</p>
</li>
<li><p>使用场景:React配合Redux架构适合超大规模多人协作的复杂项目;Vue则适合小快灵的项目。对于需要对 DOM 进行很多自定义操作的项目,Vue 的灵活性优于 React;</p>
</li>
<li><p>Vue要比React更好上手,具体可能体现在很多人不熟悉React的JSX语法和函数式编程的思想,以及想要发挥出React的最大威力需要学习它一系列生态的缘故;</p>
</li>
<li><p>Vue着重提高开发效率,让前端程序员更快速方便的开发应用。React着重于变革开发思想,提升前端程序员编程的深度与创造力,让前端工程师成为真正的程序员而不是UI的构建者;</p>
</li>
</ol>
<h4 id="gulp和webpack区别"><a href="#gulp和webpack区别" class="headerlink" title="gulp和webpack区别"></a>gulp和webpack区别</h4><ol>
<li>gulp是一种工具,我们可以用它来优化前端的工作流程,比如自动刷新页面、combo、压缩css、js、编译less等等。具体体现为:在gulp的配置文件中书写一个个的task,webpack则是一种打包工具,或者说是一种模块化解决方案,实际上很大一部分人刚开始使用webpack的方式就是通过gulp-webpack这个插件,写好task来使用webpack对前端的一些文件进行打包;</li>
<li>gulp的处理任务需要自己去写,webpack则有现成的解决方案,只需要在webpack.config.js配置好即可;</li>
</ol>
<h4 id="防止重复发送Ajax请求"><a href="#防止重复发送Ajax请求" class="headerlink" title="防止重复发送Ajax请求"></a>防止重复发送Ajax请求</h4><ol>
<li>用户点击之后按钮disabled;</li>
<li>函数节流</li>
<li>abort掉上一个请求。</li>
</ol>
<h4 id="事件模型"><a href="#事件模型" class="headerlink" title="事件模型"></a>事件模型</h4><ul>
<li>事件捕获阶段(capturing phase)。事件从document一直向下传播到目标元素, 依次检查经过的节点是否绑定了事件监听函数,如果有则执行。</li>
<li>事件处理阶段(target phase)。事件到达目标元素, 触发目标元素的监听函数。</li>
<li>事件冒泡阶段(bubbling phase)。事件从目标元素冒泡到document, 依次检查经过的节点是否绑定了事件监听函数,如果有则执行。</li>
</ul>
<h4 id="浏览器缓存机制"><a href="#浏览器缓存机制" class="headerlink" title="浏览器缓存机制"></a>浏览器缓存机制</h4><ol>
<li>Expires策略</li>
</ol>
<p>Expires是Web服务器响应消息头字段,在响应http请求时告诉<strong>浏览器在过期时间前</strong>浏览器可以直接从浏览器缓存取数据,而无需再次请求。Expires 是HTTP 1.0的东西,现在默认浏览器均默认使用HTTP 1.1,所以它的作用基本忽略。</p>
<ol>
<li>Cache-Control策略</li>
</ol>
<p>Cache-Control与Expires的作用一致,都是指明当前资源的<strong>有效期</strong>,控制浏览器是否直接从浏览器缓读取数据还是重新发请求到服务器取数据。只不过Cache-Control的<strong>选择更多,设置更细致</strong>,如果同时设置的话,其<strong>优先级高于Expires</strong>。</p>
<p>以上是设置缓存时间的两种方法。那么当缓存时间过了咋整呢?有人肯定说了,那就再次发起请求啊,这是对的。问题是如果服务器资源并没有更新呢?比如说我有一个<code>jQuery.js</code>文件已经缓存了,当它的缓存时间到了之后服务器的<code>jQuery.js</code>文件也没有更新,那实际上我们直接使用本地缓存的文件就可以啊!没必要浪费带宽和时间去重新请求一个新的文件啊!这时候我们就需要再进一步看一下HTTP协议里这几个参数的作用了。</p>
<ol>
<li>Last-Modified/If-Modified-Since</li>
</ol>
<p>首先Last-Modified/If-Modified-Since要配合Cache-Control使用。</p>
<ul>
<li>Last-Modified:标示这个响应资源的最后修改时间。web服务器在响应请求时,告诉浏览器资源的最后修改时间(这个参数是和Cache-Control一起过来的)。</li>
<li>If-Modified-Since:当资源过期时(使用Cache-Control标识的max-age),发现资源具有Last-Modified声明,则再次向web服务器请求时带上头 <strong>If-Modified-Since</strong>,表示请求时间。<strong>web服务器收到请求后发现有头If-Modified-Since ,则与被请求资源的最后修改时间进行比对</strong>。若最后修改时间较新,说明资源又被改动过,则响应整片资源内容(写在响应消息包体内),HTTP 200;若最后修改时间较旧,说明资源无新修改,则响应HTTP 304 (无需包体,节省浏览),告知浏览器继续使用所保存的cache。</li>
</ul>
<ol>
<li>ETag/If-None-Match</li>
</ol>
<p>Etag/If-None-Match也要配合Cache-Control使用。</p>
<ul>
<li>Etag:web服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器觉得)。<em>Apache</em>中,ETag的值,<strong>默认是对文件的索引节(INode),大小(Size)和最后修改时间(MTime</strong>)进行<em>Hash</em>后得到的。</li>
<li>If-None-Match:当资源过期时(使用Cache-Control标识的max-age),发现资源具有Etage声明,则再次向web服务器请求时带上头If-None-Match(Etag的值)。<strong>web服务器收到请求后发现有头If-None-Match 则与被请求资源的相应校验串进行比对</strong>,决定返回200或304。</li>
</ul>
<ol>
<li>ETag和Last-Modified</li>
</ol>
<p>HTTP1.1中Etag的出现主要是为了解决几个Last-Modified比较难解决的问题:</p>
<ul>
<li>Last-Modified标注的最后修改只能精确到秒级,如果某些文件在1秒钟以内,被修改多次的话,它将不能准确标注文件的修改时间</li>
<li>如果某些文件会被定期生成,当有时内容并没有任何变化,但Last-Modified却改变了,导致文件没法使用缓存</li>
<li>有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形</li>
</ul>
<p>Etag是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符,能够更加准确的控制缓存。<strong>Last-Modified</strong>与ETag是可以一起使用的,服务器会优先验证ETag<strong>,一致的情况下,才会继续比对Last-Modified</strong>,最后才决定是否返回304。</p>
<h4 id="Ajax的状态值与HTTP状态码"><a href="#Ajax的状态值与HTTP状态码" class="headerlink" title="Ajax的状态值与HTTP状态码"></a>Ajax的状态值与HTTP状态码</h4><ul>
<li><p>Ajax的状态值</p>
<p> 0: (未初始化)还没有调用open()方法;<br> 1: (载入)已经调用open()方法,正在派发请求,send()方法还未被调用;<br> 2: (载入完成)send()已经调用,响应头和响应状态已经返回;<br> 3: (交互)响应体下载中; responseText中已经获取了部分数据;<br> 4: (完成)响应内容已经解析完成,用户可以调用。</p>
</li>
<li><p>HTTP状态码</p>
<p>200 & OK: 请求成功;</p>
<p>204 & No Content: 请求处理成功,但没有资源可以返回;</p>
<p>206 & Partial Content: 对资源某一部分进行请求(比如对于只加载了一般的图片剩余部分的请求);</p>
<p>301 & Move Permanently: 永久性重定向;</p>
<p>302 & Found: 临时性重定向;</p>
<p>303 & See Other: 请求资源存在另一个URI,应使用get方法请求;</p>
<p>304 & Not Modified: 服务器判断本地缓存未更新,可以直接使用本地的缓存;</p>
<p>307 & Temporary Redirect: 临时重定向;</p>
<p>400 & Bad Request: 请求报文存在语法错误;</p>
<p>401 & Unauthorized: 请求需要通过HTTP认证;</p>
<p>403 & Forbidden: 请求资源被服务器拒绝,访问权限的问题;</p>
<p>404 & Not Found: 服务器上没有请求的资源;</p>
<p>500 & Internal Server Error: 服务器执行请求时出现错误;</p>
<p>502 & Bad Gateway: 错误的网关;</p>
<p>503 & Service Unavailable: 服务器超载或正在维护,无法处理请求;</p>
<p>504 & Gateway timeout: 网关超时;</p>
</li>
</ul>
<h4 id="React-router原理"><a href="#React-router原理" class="headerlink" title="React-router原理"></a>React-router原理</h4><p>1.<strong>History</strong></p>
<ul>
<li>老浏览器的history: 主要通过hash来实现,对应<code>createHashHistory</code></li>
<li>高版本浏览器: 通过html5里面的history,对应<code>createBrowserHistory</code></li>
<li>node环境下: 主要存储在memeory里面,对应<code>createMemoryHistory</code></li>
</ul>
<p>内部<code>createHistory</code>实现:</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 内部的抽象实现</span></div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">createHistory</span>(<span class="params">options={}</span>) </span>{</div><div class="line"> ...</div><div class="line"> return {</div><div class="line"> listenBefore, <span class="comment">// 内部的hook机制,可以在location发生变化前执行某些行为,AOP的实现</span></div><div class="line"> listen, <span class="comment">// location发生改变时触发回调</span></div><div class="line"> transitionTo, <span class="comment">// 执行location的改变</span></div><div class="line"> push, <span class="comment">// 改变location</span></div><div class="line"> replace,</div><div class="line"> go,</div><div class="line"> goBack,</div><div class="line"> goForward,</div><div class="line"> createKey, <span class="comment">// 创建location的key,用于唯一标示该location,是随机生成的</span></div><div class="line"> createPath,</div><div class="line"> createHref,</div><div class="line"> createLocation, <span class="comment">// 创建location</span></div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p><code>createLocation</code>方法:</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">createLocation</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="keyword">return</span> {</div><div class="line"> pathname, <span class="comment">// url的基本路径</span></div><div class="line"> search, <span class="comment">// 查询字段</span></div><div class="line"> hash, <span class="comment">// url中的hash值</span></div><div class="line"> state, <span class="comment">// url对应的state字段</span></div><div class="line"> action, <span class="comment">// 分为push、replace、pop三种</span></div><div class="line"> key <span class="comment">// 生成方法为: Math.random().toString(36).substr(2, length)</span></div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>三种方法各自执行<code>URL</code>前进的方式:</p>
<ul>
<li><code>createBrowserHistory</code>: pushState、replaceState</li>
<li><code>createHashHistory</code>: <code>location.hash=***</code> <code>location.replace()</code></li>
<li><code>createMemoryHistory</code>: 在内存中进行历史记录的存储</li>
</ul>
<p>伪代码实现:</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// createBrowserHistory(HTML5)中的前进实现</span></div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">finishTransition</span>(<span class="params">location</span>) </span>{</div><div class="line"> ...</div><div class="line"> const historyState = { key };</div><div class="line"> ...</div><div class="line"> if (location.action === <span class="string">'PUSH'</span>) ) {</div><div class="line"> <span class="built_in">window</span>.history.pushState(historyState, <span class="literal">null</span>, path);</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> <span class="built_in">window</span>.history.replaceState(historyState, <span class="literal">null</span>, path)</div><div class="line"> }</div><div class="line">}</div><div class="line"><span class="comment">// createHashHistory的内部实现</span></div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">finishTransition</span>(<span class="params">location</span>) </span>{</div><div class="line"> ...</div><div class="line"> if (location.action === <span class="string">'PUSH'</span>) ) {</div><div class="line"> <span class="built_in">window</span>.location.hash = path;</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> <span class="built_in">window</span>.location.replace(</div><div class="line"> <span class="built_in">window</span>.location.pathname + <span class="built_in">window</span>.location.search + <span class="string">'#'</span> + path</div><div class="line"> );</div><div class="line"> }</div><div class="line">}</div><div class="line"><span class="comment">// createMemoryHistory的内部实现</span></div><div class="line">entries = [];</div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">finishTransition</span>(<span class="params">location</span>) </span>{</div><div class="line"> ...</div><div class="line"> switch (location.action) {</div><div class="line"> <span class="keyword">case</span> <span class="string">'PUSH'</span>:</div><div class="line"> entries.push(location);</div><div class="line"> <span class="keyword">break</span>;</div><div class="line"> <span class="keyword">case</span> <span class="string">'REPLACE'</span>:</div><div class="line"> entries[current] = location;</div><div class="line"> <span class="keyword">break</span>;</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<ol>
<li><strong>React-router的基本原理</strong></li>
</ol>
<p><code>URL</code>对应<code>Location</code>对象,而<code>UI</code>是由react的 <code>components</code>来决定的,这样就转变成<code>location</code>与<code>components</code>之间的同步问题。</p>
<h4 id="什么是原型链"><a href="#什么是原型链" class="headerlink" title="什么是原型链"></a>什么是原型链</h4><p>每一个对象都会在内部链接到另一个对象(该对象的原型对象),该对象有一个原型<code>prototype</code>,当访问对象的属性或是方法的时候,不仅仅会在原对象上查找,还会顺着原型链在原型对象的原型链上查找,直到查到<code>null</code>(所有原型链的顶层)为止。原型是JavaScript实现继承的基础,<code>new</code>关键字做的主要的事情就是将实例对象的<code>__proto__</code>属性指向原型对象的prototype。</p>
<h4 id="什么是闭包"><a href="#什么是闭包" class="headerlink" title="什么是闭包"></a>什么是闭包</h4><ul>
<li><p>闭包是javascript支持<a href="https://zh.wikipedia.org/wiki/%E5%A4%B4%E7%AD%89%E5%87%BD%E6%95%B0" target="_blank" rel="external">头等函数</a>的一种方式,它是一个能够引用其内部作用域变量(在本作用域第一次声明的变量)的表达式,这个表达式可以赋值给某个变量,可以作为参数传递给函数,也可以作为一个函数返回值返回。</p>
</li>
<li><p>闭包是函数开始执行的时候被分配的一个<a href="http://baike.baidu.com/link?url=x9za8fl-K8Gsdc0IFBbC5fTininX3H8qVBuSPsChIJd8bmzTRXvd8scDL1uCYKLS26m6GMbXgHFC5K8yXz7nZ3eImibufpfwiBWzlBDAyT_" target="_blank" rel="external">栈帧</a>,在函数执行结束返回后仍不会被释放(就好像一个栈帧被分配在堆里而不是栈里!)</p>
</li>
<li><p>闭包的应用:</p>
<ul>
<li>比如写柯里化函数的时候利用闭包,保存参数在内存中;</li>
</ul>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> currying = <span class="function"><span class="keyword">function</span>(<span class="params">fun</span>) </span>{</div><div class="line"> <span class="comment">//格式化arguments</span></div><div class="line"> <span class="keyword">var</span> args = <span class="built_in">Array</span>.prototype.slice.call(<span class="built_in">arguments</span>, <span class="number">1</span>);</div><div class="line"> <span class="keyword">return</span> <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="comment">//收集所有的参数在同一个数组中,进行计算</span></div><div class="line"> <span class="keyword">var</span> _args = args.concat(<span class="built_in">Array</span>.prototype.slice.call(<span class="built_in">arguments</span>));</div><div class="line"> <span class="keyword">return</span> fun.apply(<span class="literal">null</span>, _args);</div><div class="line"> };</div><div class="line">}</div></pre></td></tr></table></figure>
<p></p>
<ul>
<li>模拟私有变量或是私有方法;</li>
</ul>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">const</span> people = <span class="function">(<span class="params">num</span>) =></span> {</div><div class="line"> <span class="keyword">var</span> num = num;</div><div class="line"> <span class="keyword">return</span> {</div><div class="line"> <span class="attr">increase</span>: <span class="function"><span class="params">()</span> =></span> {</div><div class="line"> num++;</div><div class="line"> },</div><div class="line"> <span class="attr">get</span>: <span class="function"><span class="params">()</span> =></span> {</div><div class="line"> <span class="keyword">return</span> num;</div><div class="line"> }</div><div class="line"> }</div><div class="line">}</div><div class="line"><span class="keyword">const</span> man = people(<span class="number">4</span>);</div><div class="line">man.increase();</div><div class="line">man.get();</div></pre></td></tr></table></figure>
<ul>
<li>避免引用错误</li>
</ul>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i < <span class="number">4</span>; i++) {</div><div class="line"> (<span class="function"><span class="keyword">function</span>(<span class="params">_i</span>) </span>{</div><div class="line"> setTimeout(<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="built_in">console</span>.log(_i)</div><div class="line"> }, <span class="number">1000</span>)</div><div class="line"> })(i)</div><div class="line">}</div></pre></td></tr></table></figure>
<p></p>
</li>
</ul>
<h4 id="图片懒加载与预加载"><a href="#图片懒加载与预加载" class="headerlink" title="图片懒加载与预加载"></a>图片懒加载与预加载</h4><ul>
<li><p>图片懒加载的原理就是暂时不设置图片的<code>src</code>属性,而是将图片的<code>url</code>隐藏起来,比如先写在<code>data-src</code>里面,等某些事件触发的时候(比如滚动到底部,点击加载图片)再将图片真实的<code>url</code>放进<code>src</code>属性里面,从而实现图片的延迟加载</p>
</li>
<li><p>图片预加载,是指在一些需要展示大量图片的网站,实现图片的提前加载。从而提升用户体验。常用的方式有两种,一种是隐藏在css的background的url属性里面,一种是通过javascript的Image对象设置实例对象的src属性实现图片的预加载。相关代码如下:</p>
</li>
<li><ol>
<li>CSS预加载图片方式:</li>
</ol>
<figure class="highlight css"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="selector-id">#preload-01</span> { <span class="attribute">background</span>: <span class="built_in">url</span>(http://domain.tld/image-01.png) no-repeat -<span class="number">9999px</span> -<span class="number">9999px</span>; } </div><div class="line"><span class="selector-id">#preload-02</span> { <span class="attribute">background</span>: <span class="built_in">url</span>(http://domain.tld/image-02.png) no-repeat -<span class="number">9999px</span> -<span class="number">9999px</span>; } </div><div class="line"><span class="selector-id">#preload-03</span> { <span class="attribute">background</span>: <span class="built_in">url</span>(http://domain.tld/image-03.png) no-repeat -<span class="number">9999px</span> -<span class="number">9999px</span>; }</div></pre></td></tr></table></figure>
</li>
<li><ol>
<li>Javascript预加载图片的方式:</li>
</ol>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">preloadImg</span>(<span class="params">url</span>) </span>{</div><div class="line"> <span class="keyword">var</span> img = <span class="keyword">new</span> Image();</div><div class="line"> img.src = url;</div><div class="line"> <span class="keyword">if</span>(img.complete) {</div><div class="line"> <span class="comment">//接下来可以使用图片了</span></div><div class="line"> <span class="comment">//do something here</span></div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> img.onload = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="comment">//接下来可以使用图片了</span></div><div class="line"> <span class="comment">//do something here</span></div><div class="line"> };</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
</li>
</ul>
<h4 id="类型数组"><a href="#类型数组" class="headerlink" title="类型数组"></a>类型数组</h4><p>JavaScript 是一种提供了访问原始二进制数据机制的类似数组的对象。</p>
<p>为了最大的灵活性和效率(mdn这么说的,不明觉厉),JavaScript类型化数组提供了两部分来实现,一种是缓冲(ArrayBuffer),一种是视图(TypedArray和DataView)。</p>
<p>所谓的<strong>缓冲</strong>其实是一种数据类型,表示一个通用的、固定长度的二进制数据缓冲区。该对象没法直接访问具体的数据,仅仅提供’缓冲’作用,要访问具体的数据,必须通过视图;</p>
<p>所谓的<strong>视图</strong>分为两种:<strong>TypedArray</strong>和<strong>DataView</strong>:</p>
<p><strong>TypedArray</strong>:</p>
<p>共包括9种类型的视图,比如<code>Uint8Array</code>(无符号8位整数)数组视图, <code>Int16Array</code>(16位整数)数组视图, <code>Float32Array</code>(32位浮点数)数组视图等等。</p>
<table>
<thead>
<tr>
<th>数据类型</th>
<th>字节长度</th>
<th>含义</th>
<th>对应的C语言类型</th>
</tr>
</thead>
<tbody>
<tr>
<td>Int8</td>
<td>1</td>
<td>8位带符号整数</td>
<td>signed char</td>
</tr>
<tr>
<td>Uint8</td>
<td>1</td>
<td>8位不带符号整数</td>
<td>unsigned char</td>
</tr>
<tr>
<td>Uint8C</td>
<td>1</td>
<td>8位不带符号整数(自动过滤溢出)</td>
<td>unsigned char</td>
</tr>
<tr>
<td>Int16</td>
<td>2</td>
<td>16位带符号整数</td>
<td>short</td>
</tr>
<tr>
<td>Uint16</td>
<td>2</td>
<td>16位不带符号整数</td>
<td>unsigned short</td>
</tr>
<tr>
<td>Int32</td>
<td>4</td>
<td>32位带符号整数</td>
<td>int</td>
</tr>
<tr>
<td>Uint32</td>
<td>4</td>
<td>32位不带符号的整数</td>
<td>unsigned int</td>
</tr>
<tr>
<td>Float32</td>
<td>4</td>
<td>32位浮点数</td>
<td>float</td>
</tr>
<tr>
<td>Float64</td>
<td>8</td>
<td>64位浮点数</td>
<td>double</td>
</tr>
</tbody>
</table>
<p><strong>DataView</strong>:</p>
<p>DataView提供可以操作缓冲区中任意数据的读写接口。这对操作不同类型数据的场景很有帮助。而不再像TypedArray一样局限于某一种类型数据。</p>
<p><strong>应用</strong>:</p>
<ul>
<li>FileReader API(readAsArrayBuffer方法)</li>
<li>XMlHttpRequest的send方法(支持类型数组作为参数)</li>
<li>Canvas</li>
</ul>
<p>说明:类型数组并不是支持所有的原生数组的API(比如push和pop就不可用,因为ArrayBuffer给定了字节数,TypedArray视图自然无法调用)。</p>
<h4 id="跨域"><a href="#跨域" class="headerlink" title="跨域"></a>跨域</h4><p>跨域的方式有很多种,最常用的是<code>jsonp</code>主要利用了<code>script</code>的开放策略:通过script标签引入一个js或者是一个其他后缀形式(如php,jsp等)的文件,此文件返回一个js函数的调用。缺点在于只支持get请求而且存在安全问题。</p>
<p>CORS跨域,关键在于服务器,如果服务器实现了CORS跨域的接口,那么就可以使用ajax(请求路径为绝对路径)进行跨域请求。CORS请求分为两种,一种是简单请求,一种是非简单请求。简单请求是指请求方法在<code>HEAD</code>,<code>GET</code>,<code>POST</code>三者之间并且请求头信息局限在</p>
<ul>
<li>Accept</li>
<li>Accept-Language</li>
<li>Content-Language</li>
</ul>
<ul>
<li>Content-Type:只限于三个值<code>application/x-www-form-urlencoded</code>、<code>multipart/form-data</code>、<code>text/plain</code></li>
</ul>
<p>非简单请求请求头:</p>
<p><strong>(1)Access-Control-Request-Method</strong></p>
<p>该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法</p>
<p><strong>(2)Access-Control-Request-Headers</strong></p>
<p>该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段</p>
<p>执行简单请求的时候,浏览器会在请求头信息增加<code>origin</code>字段,服务器据此来判断请求域名是否在许可范围之内,来决定是否返回<code>Access-Control-Allow-Origin</code>字段。响应头有以下几种:</p>
<p><strong>(1)Access-Control-Allow-Origin</strong></p>
<p>该字段是必须的。它的值要么是请求时<code>Origin</code>字段的值,要么是一个<code>*</code>,表示接受任意域名的请求。</p>
<p><strong>(2)Access-Control-Allow-Credentials</strong></p>
<p>该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为<code>true</code>,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。这个值也只能设为<code>true</code>,如果服务器不要浏览器发送Cookie,删除该字段即可。</p>
<p><strong>(3)Access-Control-Expose-Headers</strong></p>
<p>该字段可选。CORS请求时,<code>XMLHttpRequest</code>对象的<code>getResponseHeader()</code>方法只能拿到6个基本字段:<code>Cache-Control</code>、<code>Content-Language</code>、<code>Content-Type</code>、<code>Expires</code>、<code>Last-Modified</code>、<code>Pragma</code>。如果想拿到其他字段,就必须在<code>Access-Control-Expose-Headers</code>里面指定。</p>
<p> <strong>(4)Access-Control-Max-Age</strong></p>
<p><code>Access-Control-Max-Age</code> 首部字段指明了预检请求的响应的有效时间。</p>
<p> <strong>(5)Access-Control-Allow-Methods</strong></p>
<p><code>Access-Control-Allow-Methods</code> 首部字段用于预检请求的响应。其指明了实际请求所允许使用的 HTTP 方法。</p>
<p> <strong>(6)Access-Control-Allow-Headers</strong></p>
<p><code>Access-Control-Allow-Headers</code>首部字段用于预检请求的响应。其指明了实际请求中允许携带的首部字段。</p>
<p>其他方法:<code>document.domin</code>,html5的<code>postMessage</code>,<code>window.name</code>等</p>
<h4 id="函数节流和函数防抖"><a href="#函数节流和函数防抖" class="headerlink" title="函数节流和函数防抖"></a>函数节流和函数防抖</h4><p>函数节流让指函数有规律的进行调用,应用场景:window.resize,游戏中子弹发射(1s只能发射一颗子弹)等;</p>
<p>函数防抖让函数在”调用’’之后的一段时间后生效,应用场景:输入框(例:在用户停止输入的500ms后再处理用户数据)。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//函数节流</span></div><div class="line"><span class="comment">/*</span></div><div class="line">* @params {Function} fun 调用函数</div><div class="line">* @params {delay} number 延迟时间</div><div class="line">*/</div><div class="line"><span class="keyword">const</span> throttle = <span class="function">(<span class="params">fun, delay, ...rest</span>) =></span> {</div><div class="line"> <span class="keyword">let</span> last = <span class="literal">null</span>;</div><div class="line"> <span class="keyword">return</span> <span class="function"><span class="params">()</span> =></span> {</div><div class="line"> <span class="keyword">const</span> now = + <span class="keyword">new</span> <span class="built_in">Date</span>();</div><div class="line"> <span class="keyword">if</span> (now - last > delay) {</div><div class="line"> fun(rest);</div><div class="line"> last = now;</div><div class="line"> }</div><div class="line"> }</div><div class="line">}</div><div class="line"><span class="comment">//实例</span></div><div class="line"><span class="keyword">const</span> throttleExample = throttle(<span class="function"><span class="params">()</span> =></span> <span class="built_in">console</span>.log(<span class="number">1</span>), <span class="number">1000</span>);</div><div class="line"><span class="comment">//调用</span></div><div class="line">throttleExample();</div><div class="line">throttleExample();</div><div class="line">throttleExample();</div><div class="line"><span class="comment">//函数防抖</span></div><div class="line"><span class="keyword">const</span> debouce = <span class="function">(<span class="params">fun, delay, ...rest</span>) =></span> {</div><div class="line"> <span class="keyword">let</span> timer = <span class="literal">null</span>;</div><div class="line"> <span class="keyword">return</span> <span class="function"><span class="params">()</span> =></span> {</div><div class="line"> clearTimeout(timer);</div><div class="line"> timer = setTimeout(<span class="function"><span class="params">()</span> =></span> {</div><div class="line"> fun(rest);</div><div class="line"> }, delay);</div><div class="line"> }</div><div class="line">}</div><div class="line"><span class="comment">//实例</span></div><div class="line"><span class="keyword">const</span> debouceExample = debouce(<span class="function"><span class="params">()</span> =></span> <span class="built_in">console</span>.log(<span class="number">1</span>), <span class="number">1000</span>);</div><div class="line"><span class="comment">//调用</span></div><div class="line">debouceExample();</div><div class="line">debouceExample();</div><div class="line">debouceExample();</div></pre></td></tr></table></figure>
<h4 id="快速排序"><a href="#快速排序" class="headerlink" title="快速排序"></a>快速排序</h4><ol>
<li>从数列中挑出一个元素,称为”基准”(pivot),</li>
<li>重新排序数列,所有比基准值小的元素摆放在基准前面,所有比基准值大的元素摆在基准后面(相同的数可以到任一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为<strong>分区(partition)</strong>操作。</li>
<li><a href="https://zh.wikipedia.org/wiki/%E9%80%92%E5%BD%92" target="_blank" rel="external">递归</a>地(recursively)把小于基准值元素的子数列和大于基准值元素的子数列排序。</li>
</ol>
<p>时间复杂度平均情况:O(n\log n) 最快:O(n^{2}) 空间复杂度: O(\log n)</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> quickSort = <span class="function"><span class="keyword">function</span>(<span class="params">arr</span>) </span>{</div><div class="line"> <span class="built_in">console</span>.time(<span class="string">'2.快速排序耗时'</span>);</div><div class="line"> <span class="keyword">if</span> (arr.length <= <span class="number">1</span>) { <span class="keyword">return</span> arr; }</div><div class="line"> <span class="keyword">var</span> pivot = arr.splice(<span class="number">0</span>, <span class="number">1</span>)[<span class="number">0</span>];</div><div class="line"> <span class="keyword">var</span> left = [];</div><div class="line"> <span class="keyword">var</span> right = [];</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i < arr.length; i++){</div><div class="line"> <span class="keyword">if</span> (arr[i] < pivot) {</div><div class="line"> left.push(arr[i]);</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> right.push(arr[i]);</div><div class="line"> }</div><div class="line"> }</div><div class="line"><span class="built_in">console</span>.timeEnd(<span class="string">'2.快速排序耗时'</span>);</div><div class="line"> <span class="keyword">return</span> quickSort(left).concat([pivot], quickSort(right));</div><div class="line">};</div><div class="line"><span class="keyword">var</span> arr=[<span class="number">3</span>,<span class="number">44</span>,<span class="number">38</span>,<span class="number">5</span>,<span class="number">47</span>,<span class="number">15</span>,<span class="number">36</span>,<span class="number">26</span>,<span class="number">27</span>,<span class="number">2</span>,<span class="number">46</span>,<span class="number">4</span>,<span class="number">19</span>,<span class="number">50</span>,<span class="number">48</span>];</div><div class="line"><span class="built_in">console</span>.log(quickSort(arr));<span class="comment">//[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]</span></div></pre></td></tr></table></figure>
<h4 id="AMD和CMD的区别"><a href="#AMD和CMD的区别" class="headerlink" title="AMD和CMD的区别"></a>AMD和CMD的区别</h4><p>AMD 是 RequireJS 在推广过程中对模块定义的规范化产出。<br>CMD 是 SeaJS 在推广过程中对模块定义的规范化产出。</p>
<ol>
<li>对于依赖的模块,AMD 是<strong>提前执行</strong>,CMD 是<strong>延迟执行</strong>。不过 RequireJS 从 2.0 开始,也改成可以延迟执行(根据写法不同,处理方式不同)。CMD 推崇 as lazy as possible.</li>
<li>CMD 推崇<strong>依赖就近</strong>,AMD 推崇<strong>依赖前置</strong>。</li>
<li>AMD 的 API 默认是<strong>一个当多个用</strong>,CMD 的 API 严格区分,推崇<strong>职责单一</strong>。比如 AMD 里,require 分全局 require 和局部 require,都叫 require。CMD 里,没有全局 require,而是根据模块系统的完备性,提供 seajs.use 来实现模块系统的加载启动。CMD 里,每个 API 都<strong>简单纯粹</strong>。</li>
</ol>
<h4 id="Web-worker"><a href="#Web-worker" class="headerlink" title="Web worker"></a>Web worker</h4><p>Web Workers是一种机制,通过它可以使一个脚本操作在与Web应用程序的主执行线程分离的后台线程中运行。这样做的优点是可以在单独的线程中执行繁琐的处理,让主(通常是UI)线程运行而不被阻塞/减慢。</p>
<p>Web Worker 规范中定义了两类工作线程,分别是专用线程Dedicated Worker和共享线程 Shared Worker,其中,Dedicated Worker只能为一个页面所使用,而Shared Worker则可以被多个页面所共享。</p>
<p>——来自<a href="http://www.alloyteam.com/2015/11/deep-in-web-worker/" target="_blank" rel="external">深入理解web worker</a></p>
<h4 id="JavaScript内存泄露的原因以及如何去手动释放内存"><a href="#JavaScript内存泄露的原因以及如何去手动释放内存" class="headerlink" title="JavaScript内存泄露的原因以及如何去手动释放内存"></a>JavaScript内存泄露的原因以及如何去手动释放内存</h4><p><strong>易出现泄露的场景</strong></p>
<ul>
<li>XMLHttpRequest 泄漏发生在IE7-8,释放方法,将XMLHttpRequest实例对象设置为Null;</li>
<li>DOM&BOM等COM对象循环绑定 泄漏发生在IE6-8,释放方法,切断循环引用,将对对象的应用设置为Null;</li>
<li>定时器(严格上说不能算是泄露,是被闭包持有了,是正常的表现),对于闭包中无用的变量可以使用delete操作符进行释放;</li>
</ul>
<p><strong>JavaScript垃圾回收机制</strong></p>
<ul>
<li>引用计数</li>
</ul>
<p>此算法把“对象是否不再需要”简化定义为“对象有没有其他对象引用到它”。如果没有引用指向该对象(零引用),对象将被垃圾回收机制回收。</p>
<p>限制:无法处理循环引用。在下面的例子中,两个对象被创建,并互相引用,形成了一个循环。它们被调用之后不会离开函数作用域,所以它们已经没有用了,可以被回收了。然而,引用计数算法考虑到它们互相都有至少一次引用,所以它们不会被回收。</p>
<ul>
<li>标记清除</li>
</ul>
<p>当变量进入环境时,例如,在函数中声明一个变量,就将这个变量标记为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到它们。而当变量离开环境时,则将其标记为“离开环境”。</p>
<p>垃圾回收器在运行的时候会给存储在内存中的所有变量都加上标记(当然,可以使用任何标记方式)。然后,它会去掉环境中的变量以及被环境中的变量引用的变量的标记(<strong>闭包</strong>)。而在此之后再被加上标记的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了。最后,垃圾回收器完成内存清除工作,销毁那些带标记的值并回收它们所占用的内存空间。</p>
<h4 id="柯里化函数"><a href="#柯里化函数" class="headerlink" title="柯里化函数"></a>柯里化函数</h4><p>所谓的柯里化函数简单的说就是将本来接受多个参数的函数变为只接受一个参数的函数。柯里化函数的模板和实例如下:</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> currying = <span class="function"><span class="keyword">function</span>(<span class="params">fun</span>) </span>{</div><div class="line"> <span class="comment">//格式化arguments</span></div><div class="line"> <span class="keyword">var</span> args = <span class="built_in">Array</span>.prototype.slice.call(<span class="built_in">arguments</span>, <span class="number">1</span>);</div><div class="line"> <span class="keyword">return</span> <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="comment">//收集所有的参数在同一个数组中,进行计算</span></div><div class="line"> <span class="keyword">var</span> _args = args.concat(<span class="built_in">Array</span>.prototype.slice.call(<span class="built_in">arguments</span>));</div><div class="line"> <span class="keyword">return</span> fun.apply(<span class="literal">null</span>, _args);</div><div class="line"> };</div><div class="line">}</div><div class="line"><span class="keyword">var</span> add = currying(<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="keyword">var</span> args = <span class="built_in">Array</span>.prototype.slice.call(<span class="built_in">arguments</span>);</div><div class="line"> <span class="keyword">return</span> args.reduce(<span class="function"><span class="keyword">function</span>(<span class="params">a, b</span>) </span>{</div><div class="line"> <span class="keyword">return</span> a + b;</div><div class="line"> });</div><div class="line">})</div><div class="line">add(<span class="number">1</span>, <span class="number">2</span>, <span class="number">4</span>)</div><div class="line"><span class="comment">/*</span></div><div class="line"> * 经典面试题</div><div class="line"> * 函数参数不定回调函数数目不定</div><div class="line"> * 编写函数实现:</div><div class="line"> * add(1,2,3,4,5)==15</div><div class="line"> * add(1,2)(3,4)(5)==15</div><div class="line"> */</div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">add</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="comment">// 第一次执行时,定义一个数组专门用来存储所有的参数</span></div><div class="line"> <span class="keyword">var</span> _args = [].slice.call(<span class="built_in">arguments</span>);</div><div class="line"> <span class="comment">// 在内部声明一个函数,利用闭包的特性保存_args并收集所有的参数值</span></div><div class="line"> <span class="keyword">var</span> adder = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</div><div class="line"> <span class="keyword">var</span> _adder = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</div><div class="line"> [].push.apply(_args, [].slice.call(<span class="built_in">arguments</span>));</div><div class="line"> <span class="keyword">return</span> _adder;</div><div class="line"> };</div><div class="line"></div><div class="line"> <span class="comment">// 利用隐式转换的特性,当最后执行时隐式转换,并计算最终的值返回</span></div><div class="line"> _adder.toString = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</div><div class="line"> <span class="keyword">return</span> _args.reduce(<span class="function"><span class="keyword">function</span> (<span class="params">a, b</span>) </span>{</div><div class="line"> <span class="keyword">return</span> a + b;</div><div class="line"> });</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">return</span> _adder;</div><div class="line"> }</div><div class="line"> <span class="keyword">return</span> adder.apply(<span class="literal">null</span>, _args);</div><div class="line">}</div><div class="line"><span class="comment">// 输出结果,可自由组合的参数</span></div><div class="line"><span class="built_in">console</span>.log(add(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>)); <span class="comment">// 15</span></div><div class="line"><span class="built_in">console</span>.log(add(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>)(<span class="number">5</span>)); <span class="comment">// 15</span></div><div class="line"><span class="built_in">console</span>.log(add(<span class="number">1</span>)(<span class="number">2</span>)(<span class="number">3</span>)(<span class="number">4</span>)(<span class="number">5</span>)); <span class="comment">// 15</span></div></pre></td></tr></table></figure>
<h4 id="Less常用特性"><a href="#Less常用特性" class="headerlink" title="Less常用特性"></a>Less常用特性</h4><ul>
<li>变量(@color = #fff)</li>
<li>混合(Mixin)</li>
<li>内置函数(颜色,字符串,类型判断,数学)</li>
<li>循环</li>
<li>嵌套</li>
<li>运算</li>
<li>导入(@import)</li>
</ul>
<h4 id="ES6常用特性"><a href="#ES6常用特性" class="headerlink" title="ES6常用特性"></a>ES6常用特性</h4><ul>
<li>变量定义(let和const,可变与不可变,const定义对象的特殊情况)</li>
<li>解构赋值</li>
<li>模板字符串</li>
<li>数组新API(例:Array.from(),entries(),values(),keys())</li>
<li>箭头函数(rest参数,扩展运算符,::绑定this)</li>
<li>Set和Map数据结构(set实例成员值唯一存储key值,map实例存储键值对(key-value))</li>
<li>Promise对象(前端异步解决方案进化史,generator函数,async函数)</li>
<li>Class语法糖(super关键字)</li>
</ul>
<h4 id="react中setState的原理"><a href="#react中setState的原理" class="headerlink" title="react中setState的原理"></a>react中setState的原理</h4><p><strong>题目:</strong></p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">import</span> React <span class="keyword">from</span> <span class="string">'react'</span></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">App</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span> </span>{</div><div class="line"> <span class="keyword">constructor</span>() {</div><div class="line"> <span class="keyword">super</span>();</div><div class="line"> <span class="keyword">this</span>.state = {</div><div class="line"> <span class="attr">value</span>: <span class="number">0</span></div><div class="line"> }</div><div class="line"> }</div><div class="line"> componentDidMount() {</div><div class="line"> <span class="keyword">this</span>.setState({<span class="attr">value</span>: <span class="keyword">this</span>.state.value + <span class="number">1</span>});</div><div class="line"> <span class="built_in">console</span>.log(<span class="keyword">this</span>.state.value);</div><div class="line"> <span class="keyword">this</span>.setState({<span class="attr">value</span>: <span class="keyword">this</span>.state.value + <span class="number">1</span>});</div><div class="line"> <span class="built_in">console</span>.log(<span class="keyword">this</span>.state.value);</div><div class="line"> <span class="keyword">this</span>.setState({<span class="attr">value</span>: <span class="keyword">this</span>.state.value + <span class="number">1</span>});</div><div class="line"> <span class="built_in">console</span>.log(<span class="keyword">this</span>.state.value);</div><div class="line"> setTimeout(<span class="function"><span class="params">()</span> =></span> {</div><div class="line"> <span class="keyword">this</span>.setState({<span class="attr">value</span>: <span class="keyword">this</span>.state.value + <span class="number">1</span>});</div><div class="line"> <span class="built_in">console</span>.log(<span class="keyword">this</span>.state.value);</div><div class="line"> <span class="keyword">this</span>.setState({<span class="attr">value</span>: <span class="keyword">this</span>.state.value + <span class="number">1</span>});</div><div class="line"> <span class="built_in">console</span>.log(<span class="keyword">this</span>.state.value);</div><div class="line"> }, <span class="number">0</span>)</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p><strong>答案:</strong> 0、0、0、2、3;</p>
<p><strong>分析:</strong></p>
<p>当<code>setState</code>方法调用的时候<code>React</code>就会重新调用<code>render</code>方法来重新渲染组件;<code>setState</code>通过一个队列来更新<code>state</code>,当调用<code>setState</code>方法的时候会将需要更新的state放入这个状态队列中,这个队列会高效的批量更新<code>state</code>;</p>
<p><img src="http://7xsssj.com2.z0.glb.qiniucdn.com/setState%E7%AE%80%E5%8C%96%E8%B0%83%E7%94%A8%E6%A0%88.svg" alt="setState简化调用栈"></p>
<p>源码地址:<a href="https://github.com/facebook/react/blob/35962a00084382b49d1f9e3bd36612925f360e5b/src/renderers/shared/reconciler/ReactUpdates.js" target="_blank" rel="external">enqueueUpdate</a></p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">enqueueUpdate</span>(<span class="params">component</span>) </span>{</div><div class="line"> ensureInjected();</div><div class="line"> <span class="comment">//判断是否处于批量更新模式</span></div><div class="line"> <span class="keyword">if</span> (!batchingStrategy.isBatchingUpdates) {</div><div class="line"> <span class="comment">//关键!下面的代码片段是这个方法的源码</span></div><div class="line"> batchingStrategy.batchedUpdates(enqueueUpdate, component);</div><div class="line"> <span class="keyword">return</span>;</div><div class="line"> }</div><div class="line"> <span class="comment">//如果处于批量更新模式,则将这个组件保存在dirtyComponents</span></div><div class="line"> dirtyComponents.push(component);</div><div class="line">}</div></pre></td></tr></table></figure>
<p>源码地址:<a href="https://github.com/facebook/react/blob/35962a00084382b49d1f9e3bd36612925f360e5b/src/renderers/shared/reconciler/ReactDefaultBatchingStrategy.js" target="_blank" rel="external">ReactDefaultBatchingStrategy</a></p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//batchingStrategy对象</span></div><div class="line"><span class="keyword">var</span> ReactDefaultBatchingStrategy = {</div><div class="line"> <span class="comment">//注意默认为false</span></div><div class="line"> isBatchingUpdates: <span class="literal">false</span>,</div><div class="line"> <span class="attr">batchedUpdates</span>: <span class="function"><span class="keyword">function</span>(<span class="params">callback, a, b, c, d, e</span>) </span>{</div><div class="line"> <span class="keyword">var</span> alreadyBatchingUpdates = ReactDefaultBatchingStrategy.isBatchingUpdates;</div><div class="line"> ReactDefaultBatchingStrategy.isBatchingUpdates = <span class="literal">true</span>;</div><div class="line"> <span class="keyword">if</span> (alreadyBatchingUpdates) {</div><div class="line"> callback(a, b, c, d, e);</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> <span class="comment">//关键!!!事务的理解</span></div><div class="line"> transaction.perform(callback, <span class="literal">null</span>, a, b, c, d, e);</div><div class="line"> }</div><div class="line"> },</div><div class="line">};</div></pre></td></tr></table></figure>
<p>源码地址:<a href="https://github.com/facebook/react/blob/401e6f10587b09d4e725763984957cf309dfdc30/src/shared/utils/Transaction.js" target="_blank" rel="external">Transaction</a></p>
<p><img src="http://7xsssj.com2.z0.glb.qiniucdn.com/%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7%202017-05-15%2021.55.30.png" alt="事务流程图"></p>
<p>如图:事务会将所需要执行的方法(图中的anyMethod)使用<code>wrapper</code>封装起来,再通过<code>perform</code>方法执行该方法,但在<code>perform</code>执行之前会先执行所有<code>wrapper</code>中的<code>initialize</code>方法,<code>perform</code>方法执行结束后,再执行所有的<code>close</code>方法;</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> Transaction = <span class="built_in">require</span>(<span class="string">'./Transaction'</span>);</div><div class="line"><span class="comment">// 我们自己定义的</span></div><div class="line"><span class="keyword">var</span> MyTransaction = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{ </div><div class="line"> <span class="comment">//do something</span></div><div class="line">};</div><div class="line"><span class="built_in">Object</span>.assign(MyTransaction.prototype, Transaction.Mixin, {</div><div class="line"> <span class="comment">//需要自定义一个getTransactionWrappers对象,获取所有需要封装的initialize方法和close方法</span></div><div class="line"> getTransactionWrappers: <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{ </div><div class="line"> <span class="keyword">return</span> [{ </div><div class="line"> <span class="attr">initialize</span>: <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{ </div><div class="line"> <span class="built_in">console</span>.log(<span class="string">'before method perform'</span>); </div><div class="line"> }, </div><div class="line"> <span class="attr">close</span>: <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{ </div><div class="line"> <span class="built_in">console</span>.log(<span class="string">'after method perform'</span>); </div><div class="line"> } </div><div class="line"> }]; </div><div class="line"> };</div><div class="line">});</div><div class="line"><span class="comment">//实例化一个transaction</span></div><div class="line"><span class="keyword">var</span> transaction = <span class="keyword">new</span> MyTransaction();</div><div class="line"><span class="comment">//需要调用的方法</span></div><div class="line"><span class="keyword">var</span> testMethod = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="built_in">console</span>.log(<span class="string">'test'</span>);</div><div class="line">}</div><div class="line">transaction.perform(testMethod);</div><div class="line"><span class="comment">//before method perform</span></div><div class="line"><span class="comment">//test</span></div><div class="line"><span class="comment">//after method perform</span></div></pre></td></tr></table></figure>
<p>理解题目的关键是,整个组件渲染到DOM中的过程就已经处于一次大的事务中了,因此在<code>componentDidMount</code>方法中调用<code>setState</code>的时候<code>ReactDefaultBatchingStrategy.isBatchingUpdates = true;</code>这句代码已经执行过了,所以<code>setState</code>的结果并没有立即生效,而是扔进了<code>dirtyComponent</code>;因此执行三次setState的结果this.state.value的值依然是0,而setTimeout中的两次setState由于没有调用过<code>batchedUpdates</code>方法(<code>isBatchingUpdates</code>默认为<code>false</code>),所以<code>setState</code>方法立即生效,第二次<code>setSState</code>同理</p>
<h4 id="XSS与CSRF介绍"><a href="#XSS与CSRF介绍" class="headerlink" title="XSS与CSRF介绍"></a>XSS与CSRF介绍</h4><p>XSS是一种跨站脚本攻击,是属于代码注入的一种,攻击者通过将代码注入网页中,其他用户看到会受到影响(代码内容有请求外部服务器);</p>
<p>CSRF是一种跨站请求伪造,冒充用户发起请求,完成一些违背用户请求的行为(删帖,改密码,发邮件,发帖等)</p>
<p>防御方法举例:</p>
<ol>
<li>对一些关键字和特殊字符进行过滤(<>,?,script等),或对用户输入内容进行URL编码(encodeURIComponent);</li>
<li>Cookie不要存放用户名和密码,对cookie信息进行MD5等算法散列存放,必要时可以将IP和cookie绑定;</li>
</ol>
<h4 id="new关键字的过程"><a href="#new关键字的过程" class="headerlink" title="new关键字的过程"></a>new关键字的过程</h4><ol>
<li>创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。</li>
<li>属性和方法被加入到 this 引用的对象中。</li>
<li>新创建的对象由 this 所引用,并且最后隐式的返回 this 。</li>
</ol>
<p>伪代码如下:</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> obj = {};</div><div class="line">obj.__proto__ = Base.prototype;<span class="comment">//Base为构造函数</span></div><div class="line">Base.call(obj);</div><div class="line"><span class="keyword">return</span> obj</div></pre></td></tr></table></figure>
<h4 id="外边距合并"><a href="#外边距合并" class="headerlink" title="外边距合并"></a>外边距合并</h4><ol>
<li>相邻的兄弟姐妹元素</li>
</ol>
<figure class="highlight"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><p style="margin-bottom: 30px;">这个段落的下外边距被合并...</p></div><div class="line"><p style="margin-top: 20px;">...这个段落的上外边距被合并。</p></div></pre></td></tr></table></figure>
<p>如上,两个P元素之间的间隔并不会是想象中的50px,而会是两者之间的最大值30px;</p>
<ol>
<li>块级父元素与其第一个/最后一个子元素</li>
</ol>
<p>块级父元素的 margin-bottom/margin-top与它的最后一个子元素的margin-bottom/margin-top之间没有父元素的 <code>border</code>、<code>padding</code>、inline content、<strong>height</strong>、<strong><em>min-height</em></strong>、 <strong>max-height</strong> 分隔时,就会发生下/上外边距合并现象</p>
<ol>
<li>空块元素</li>
</ol>
<figure class="highlight"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><p style="margin-bottom: 0px;">这个段落的和下面段落的距离将为20px</p></div><div class="line"><div style="margin-top: 20px; margin-bottom: 20px;"></div></div><div class="line"><p style="margin-top: 0px;">这个段落的和上面段落的距离将为20px</p></div></pre></td></tr></table></figure>
<p><a href="https://developer.mozilla.org/zh-CN/docs/CSS/float" target="_blank" rel="external">浮动</a> 及 <a href="https://developer.mozilla.org/zh-CN/docs/CSS/position" target="_blank" rel="external">绝对定位</a> 元素外边距不会合并。—来自MDN</p>
<h4 id="BFC"><a href="#BFC" class="headerlink" title="BFC"></a>BFC</h4><p>浮动元素和绝对定位元素,非块级盒子的块级容器(例如 inline-blocks, table-cells, 和 table-captions),以及overflow值不为“visiable”的块级盒子,都会为他们的内容创建新的BFC(块级格式上下文)。</p>
<p>块格式化上下文由以下之一创建:</p>
<ul>
<li>根元素或其它包含它的元素</li>
<li>浮动 (元素的<code>float</code>不是 <code>none</code>)</li>
<li>绝对定位的元素 (元素具有 <code>position</code> 为 <code>absolute</code> 或 <code>fixed</code>)</li>
<li>内联块 inline-blocks (元素具有 <code>display</code>: inline-block)</li>
<li>表格单元格 (元素具有 <code>display</code>: table-cell,HTML表格单元格默认属性)</li>
<li>表格标题 (元素具有 <code>display</code>: table-caption, HTML表格标题默认属性)</li>
<li>块元素具有<code>overflow</code> ,且值不是 <code>visible</code></li>
<li><code>display</code>: flow-root;—来自MDN</li>
</ul>
<p>用处:</p>
<ol>
<li>设置父元素为BFC清除子元素浮动;</li>
<li>解决上面的margin合并问题;</li>
<li>用于布局</li>
</ol>
<h4 id="CSS3动画"><a href="#CSS3动画" class="headerlink" title="CSS3动画"></a>CSS3动画</h4><p>关键属性:<code>animation</code>和<code>transition</code>(过渡),该属性现在已经被绝大多数浏览器支持,使用频率也越来越高。顾名思义,该属性允许我们使用css来写动画,所谓写:</p>
<figure class="highlight"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div></pre></td><td class="code"><pre><div class="line">// HTML</div><div class="line"><div id="animate">233</div></div><div class="line">// CSS</div><div class="line">#animate {</div><div class="line"> width: 200px;</div><div class="line"> height: 200px;</div><div class="line"> background: #233;</div><div class="line"> animation: anim 5s ease;</div><div class="line">}</div><div class="line">@keyframes anim {</div><div class="line"> from {</div><div class="line"> width: 100px</div><div class="line"> }</div><div class="line"> to {</div><div class="line"> width: 200px;</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>以上就是一个简单的动画,核心是ease运动曲线(本质是贝塞尔曲线),这个运用比较广泛,svg,canvas等都有用到它;关于贝塞尔曲线(核心四个点:起点,重点和两个中间点)有时间再深究。</p>
<h4 id="CSS原生变量"><a href="#CSS原生变量" class="headerlink" title="CSS原生变量"></a>CSS原生变量</h4><p>变量定义形式:<code>--</code>,我想大概应为@,$都被用掉了吧(less,scss无辜躺枪),变量对大小写敏感,比如–color和–Color是两个变量;</p>
<p>var():var函数用来都读取变量;</p>
<p><strong>示例:</strong></p>
<figure class="highlight css"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="selector-pseudo">:root</span> {</div><div class="line"> <span class="attribute">--color</span>: <span class="number">#333</span>;</div><div class="line">}</div><div class="line"><span class="selector-tag">body</span> {</div><div class="line"> <span class="attribute">background</span>: <span class="built_in">var</span>(--color);</div><div class="line">}</div></pre></td></tr></table></figure>
<h4 id="移动端click事件300ms延迟问题"><a href="#移动端click事件300ms延迟问题" class="headerlink" title="移动端click事件300ms延迟问题"></a>移动端click事件300ms延迟问题</h4><p>追溯到早期苹果厂商给iPhone设置的双击缩放功能,浏览器需要300ms时间判断用户是否会有下一次点击(以此触发缩放或是双击666等功能)。</p>
<p>解决方案:</p>
<ul>
<li><strong>禁用缩放</strong></li>
</ul>
<figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="tag"><<span class="name">meta</span> <span class="attr">name</span>=<span class="string">"viewport"</span> <span class="attr">content</span>=<span class="string">"user-scalable=no"</span>></span></div><div class="line"><span class="tag"><<span class="name">meta</span> <span class="attr">name</span>=<span class="string">"viewport"</span> <span class="attr">content</span>=<span class="string">"initial-scale=1,maximum-scale=1"</span>></span></div></pre></td></tr></table></figure>
<ul>
<li><strong>更改默认的视口宽度(width=device-width)</strong></li>
</ul>
<figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="tag"><<span class="name">meta</span> <span class="attr">name</span>=<span class="string">"viewport"</span> <span class="attr">content</span>=<span class="string">"width=device-width"</span>></span></div></pre></td></tr></table></figure>
<ul>
<li><strong>指针事件 (Pointer Events)</strong></li>
</ul>
<p>根据<a href="https://dvcs.w3.org/hg/pointerevents/raw-file/tip/pointerEvents.html#the-touch-action-css-property" target="_blank" rel="external">规范</a>,<code>touch-action</code> 属性决定 <em>“是否触摸操作会触发用户代理的默认行为。这包括但不限于双指缩放等行为”</em>。</p>
<h4 id="域名发散和域名收敛"><a href="#域名发散和域名收敛" class="headerlink" title="域名发散和域名收敛"></a>域名发散和域名收敛</h4><p><strong>域名发散:</strong>所谓域名发散是为了突破浏览器的并发限制。因此遵循这么一条定律:</p>
<blockquote>
<p>http 静态资源采用多个子域名</p>
</blockquote>
<p>比如:如果有大量图片会通过多个域名进行请求。</p>
<p><img src="https://camo.githubusercontent.com/e8881588de4903a30904e30de1fc6548ff906136/687474703a2f2f696d61676573323031352e636e626c6f67732e636f6d2f626c6f672f3630383738322f3230313630342f3630383738322d32303136303430373139353130363632352d313235343234383232362e6a7067" alt="各浏览器同一域名的请求并发数"></p>
<p>浏览器同一域名并发数存在的原因:</p>
<ul>
<li>减轻服务器压力,防止服务器崩溃。</li>
<li>出于安全的考虑,防止DDOS攻击。因为一般DDOS攻击就是通过合理的请求加大服务器压力从而搞垮服务器,有了这个并发限制,DDOS起码没有那么简单了。</li>
</ul>
<p><strong>域名收敛:</strong>这个是和域名发散相反的(手动滑稽),发散是说将资源分散为多个域名进行请求,以避开浏览器的并发限制。而域名收敛则是说将资源放在同一个域名下进行请求。那么实际上这是两种应用场景的解决方案罢了。域名发散是为了解决PC端浏览器并发请求限制。而域名收敛则是针对的移动端的(2G,3G网络环境不容忽视)。</p>
<p>域名收敛的原因很简单,<strong>减少不必要的域名解析</strong>,充分利用缓存,从而加快页面打开的速度。</p>
<p>关于域名收敛可以看这篇:<a href="http://taobaofed.org/blog/2015/12/16/h5-performance-optimization-and-domain-convergence/" target="_blank" rel="external">无线性能优化:域名收敛</a></p>
<h2 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h2><p>时隔三个月,终于迎来了博文的更新,有看到博友在评论留言:<br><img src="http://7xsssj.com2.z0.glb.qiniucdn.com/%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7%202017-05-14%2018.37.36.png" alt=""><br>心里很温暖,这篇不算博文的博文就当是回归之作吧,接下来的时间会尽量保持在一周一更,实习结束有的是时间了,哈哈哈。</p>
]]></content>
<summary type="html">
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p><strong>总括:</strong> 包含这三个月来碰到的一些觉得比较好的面试题,三个月没怎么写博客着实有些手痒,哈哈哈。</p>
<ul>
<li><p>原文地址:<a href="http://damonare.github.io/2017/04/24/%E6%88%91%E7%9A%84%E5%89%8D%E7%AB%AF%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/#more">我的前端进阶之路</a></p>
</li>
<li><p>知乎专栏&amp;&amp;简书专题:<a href="https://zhuanlan.zhihu.com/damonare" target="_blank" rel="external">前端进击者(知乎)</a>&amp;&amp;<a href="http://www.jianshu.com/collection/bbaa63e264f5" target="_blank" rel="external">前端进击者(简书)</a></p>
</li>
<li><p>博主博客地址:<a href="http://damonare.cn" target="_blank" rel="external">Damonare的个人博客</a></p>
</li>
</ul>
<p><strong>烈火试真金,逆境试强者</strong></p>
</summary>
<category term="学习" scheme="http://damonare.github.io/categories/learn/"/>
<category term="CSS" scheme="http://damonare.github.io/tags/CSS/"/>
<category term="JavaScript" scheme="http://damonare.github.io/tags/JavaScript/"/>
<category term="HTML" scheme="http://damonare.github.io/tags/HTML/"/>
</entry>
<entry>
<title>理解Node.js的事件轮询</title>
<link href="http://damonare.github.io/2017/02/08/%E7%90%86%E8%A7%A3Node.js%E7%9A%84%E4%BA%8B%E4%BB%B6%E8%BD%AE%E8%AF%A2/"/>
<id>http://damonare.github.io/2017/02/08/理解Node.js的事件轮询/</id>
<published>2017-02-08T14:54:02.000Z</published>
<updated>2017-02-08T14:54:02.000Z</updated>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p><strong>总括</strong> :</p>
<ul>
<li>原文地址:<a href="https://damonare.github.io/2017/02/08/%E7%90%86%E8%A7%A3Node.js%E7%9A%84%E4%BA%8B%E4%BB%B6%E8%BD%AE%E8%AF%A2/#more">理解Node.js的事件轮询</a></li>
<li>Node小应用:<a href="https://github.com/damonare/node-sample" target="_blank" rel="external">Node-sample</a></li>
</ul>
<p><strong>智者阅读群书,亦阅历人生</strong></p>
<a id="more"></a>
<h2 id="正文"><a href="#正文" class="headerlink" title="正文"></a>正文</h2><h4 id="Node-js的两个基本概念"><a href="#Node-js的两个基本概念" class="headerlink" title="Node.js的两个基本概念"></a>Node.js的两个基本概念</h4><p>Node.js的第一个基本概念就是I/O操作开销是巨大的:</p>
<p><img src="http://7xsssj.com2.z0.glb.qiniucdn.com/io-cost.png" alt=""></p>
<p>所以,当前变成技术中最大的浪费来自于等待I/O操作的完成。有几种方法可以解决性能的影响:</p>
<ul>
<li><strong>同步方式</strong>:按次序一个一个的处理请求。<em>利</em>:简单;<em>弊</em>:任何一个请求都可以阻塞其他所有请求。</li>
<li><strong>开启新进程</strong>:每个请求都开启一个新进程。<em>利</em>:简单;<em>弊</em>:大量的链接意味着大量的进程。</li>
<li><strong>开启新线程</strong>:每个请求都开启一个新线程。<em>利</em>:简单,而且跟进程比,对系统内核更加友好,因为线程比进程轻的多;<em>弊</em>:不是所有的机器都支持线程,而且对于要处理共享资源的情况,多线程编程会很快变得太过于复杂。</li>
</ul>
<p>第二个基本概念是每个连接都创建一个新线程是很消耗内存的(例如:你可以对比Nginx回想一下Apache内存耗尽的情景)。</p>
<p>Apache是多线程的:它为每个请求开启一个新的线程(或者是进程,这取决于你的配置),当并发连接增多时,你可以看看它是怎么一点一点耗尽内存的。Nginx和Node.js不是多线程的,因为线程的消耗太“重”了。它们两个是单线程、基于事件的,这就把处理众多连接所产生的线程/进程消耗给消除了。</p>
<h4 id="单线程"><a href="#单线程" class="headerlink" title="单线程"></a>单线程</h4><p>确实只有一个线程:你不能并行执行任何代码,比如:下面的“sleep”将会阻塞sever1秒钟:</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">sleep</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="keyword">var</span> now = <span class="keyword">new</span> Data().getTime();</div><div class="line"> <span class="keyword">while</span> (<span class="keyword">new</span> <span class="built_in">Date</span>().getTime() < now + <span class="number">1000</span>) {</div><div class="line"> <span class="comment">// do nothing</span></div><div class="line"> }</div><div class="line">}</div><div class="line">sleep();</div></pre></td></tr></table></figure>
<p>但就我目前学习阶段而言,我觉得好多人对于所谓的node单线程是有误解的。实际上官方给出的“单线程”是具有误导性的。所谓的单线程是指你的代码只运行在一个线程上(好多地方都叫它主线程,实际上Javascript的浏览器运行环境不也是这么处理我们写的Javascript代码的嘛),而诸多任务的并行处理,就需要多线程了,如下图:</p>
<p><img src="http://7xsssj.com2.z0.glb.qiniucdn.com/104032-20150917140900539-1845886135.png" alt=""></p>
<p>如上图,Node.js中的单线程之说指的就是这个主线程,这个主线程有一个循环结构,保持着整个程序(你写的代码)的运转。</p>
<h4 id="事件轮询"><a href="#事件轮询" class="headerlink" title="事件轮询"></a>事件轮询</h4><p>其实上面我们所说的<strong>维持主线程运行的循环</strong>这部分就是”事件轮询”,它存在于主线程中,负责不停地调用开发者编写的代码。但对开发者是不可见的。so…开发者编写的代码是怎样被调用的呢?看下图:</p>
<p><img src="http://7xsssj.com2.z0.glb.qiniucdn.com/104032-20150917141055570-1948801510.png" alt=""></p>
<p>如上图,异步函数在执行结束后,会在事件队列中添加一个事件(遵循先进先出原则),主线程中的代码执行完毕后(即一次循环结束),下一次循环开始就在事件队列中”读取”事件,然后调用它所对应的回调函数(所以回调函数的执行顺序是不一定的)。如果开发者在回调函数中调用了阻塞方法(比如上文中的sleep函数),那么整个事件轮询就会阻塞,事件队列中的事件得不到及时处理。正因为这样,nodejs中的一些库方法均是异步的,也提倡用户调用异步方法。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> fs = <span class="built_in">require</span>(<span class="string">'fs'</span>);</div><div class="line">fs.readFile(<span class="string">'hello.txt'</span>, <span class="function"><span class="keyword">function</span> (<span class="params">err, data</span>) </span>{ <span class="comment">//异步读取文件</span></div><div class="line"> <span class="built_in">console</span>.log(<span class="string">"read file end"</span>);</div><div class="line">});</div><div class="line"><span class="keyword">while</span>(<span class="number">1</span>)</div><div class="line">{</div><div class="line"> <span class="built_in">console</span>.log(<span class="string">"call readFile over"</span>);</div><div class="line">}</div></pre></td></tr></table></figure>
<p>如上代码,我们虽然使用了异步方法readfile读取文件,但<code>read file end</code>永远不会输出,因为代码始终在while循环中,下一次事件轮询始终没法开始,也就没法’读取’事件队列调用相应的回调函数了。</p>
<p>最后有一个<a href="https://github.com/damonare/node-sample" target="_blank" rel="external">Node-sample</a>是博主平时积累的一些代码,包含注释,汇总成了一个小应用,还是可以看到学习的蛛丝马迹的。感兴趣的您可以看看。</p>
<h2 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h2><p>参考文章:</p>
<ul>
<li><a href="http://blog.mixu.net/2011/02/01/understanding-the-node-js-event-loop" target="_blank" rel="external">Understanding the node.js event loop</a></li>
<li><a href="http://www.cnblogs.com/xiaozhi_5638/p/4816265.html" target="_blank" rel="external">nodejs事件轮询详述</a></li>
</ul>
]]></content>
<summary type="html">
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p><strong>总括</strong> :</p>
<ul>
<li>原文地址:<a href="https://damonare.github.io/2017/02/08/%E7%90%86%E8%A7%A3Node.js%E7%9A%84%E4%BA%8B%E4%BB%B6%E8%BD%AE%E8%AF%A2/#more">理解Node.js的事件轮询</a></li>
<li>Node小应用:<a href="https://github.com/damonare/node-sample" target="_blank" rel="external">Node-sample</a></li>
</ul>
<p><strong>智者阅读群书,亦阅历人生</strong></p>
</summary>
<category term="学习" scheme="http://damonare.github.io/categories/learn/"/>
<category term="JavaScript" scheme="http://damonare.github.io/tags/JavaScript/"/>
<category term="Node.js" scheme="http://damonare.github.io/tags/Node-js/"/>
</entry>
<entry>
<title>理解Node.js(译文)</title>
<link href="http://damonare.github.io/2017/02/08/%E7%90%86%E8%A7%A3Node.js(%E8%AF%91%E6%96%87)/"/>
<id>http://damonare.github.io/2017/02/08/理解Node.js(译文)/</id>
<published>2017-02-08T11:58:58.000Z</published>
<updated>2017-02-08T11:58:58.000Z</updated>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p><strong>总括</strong> :这篇文章十分生动形象的的介绍了Node,满足了读者想去了解Node的需求。作者是Node的第一批贡献者之一,德国前端大神。译者觉得作者的比喻很适合初学者理解Node,特此翻译。</p>
<p><strong>译者</strong> :原文网址里有只小蚂蚁的效果很有意思(多次鼠标悬浮会有惊喜),哈哈哈,可以去看一下哦。</p>
<ul>
<li>原文地址:<a href="http://debuggable.com/posts/understanding-node-js:4bd98440-45e4-4a9a-8ef7-0f7ecbdd56cb" target="_blank" rel="external">Understanding node.js</a></li>
<li>原文作者:<a href="http://felixge.de/" target="_blank" rel="external">Felix Geisendörfer</a></li>
<li>Node小应用:<a href="https://github.com/damonare/node-sample" target="_blank" rel="external">Node-sample</a></li>
<li>译者:<a href="http://damonare.cn" target="_blank" rel="external">Damonare</a></li>
</ul>
<p><strong>本文属于译文</strong> </p>
<a id="more"></a>
<h2 id="正文"><a href="#正文" class="headerlink" title="正文"></a>正文</h2><p>当我向别人介绍<a href="http://nodejs.org/" target="_blank" rel="external">Node.js</a> 的时候一般会有两种反应,要么是立马就弄明白它是个什么玩意儿,要么是被它搞的很糊涂。</p>
<p>如果你现在还处于后者,下面就是我对于<code>node</code>的解释:</p>
<ul>
<li>它是一个命令行工具,你可以下载一个tarball文件,编译然后安装源文件;</li>
<li>它可以让你在你的终端输入<code>node my_app.js</code>来运行Javascript程序;</li>
<li>Node的JS代码是由 <a href="http://code.google.com/p/v8/" target="_blank" rel="external">V8 javascript 引擎</a>(就是那个使得Chrome如此之快的东西)所执行的;</li>
<li>Node提供了诸如访问网络或是操作文件系统的<code>Javascript API</code></li>
</ul>
<h4 id="“但我也可以用-Ruby-Python-Php-Java-…等语言来做我想要做的事啊”"><a href="#“但我也可以用-Ruby-Python-Php-Java-…等语言来做我想要做的事啊”" class="headerlink" title="“但我也可以用 Ruby, Python, Php,Java, …等语言来做我想要做的事啊”"></a>“但我也可以用 Ruby, Python, Php,Java, …等语言来做我想要做的事啊”</h4><p>我听到你说的话了,你是对的。<code>Node</code>不是狡猾的独角兽,这点很抱歉,它不会帮你做你该做的事。它仅仅是一个工具,而且他也不会替代你现在所常用的一些工具,至少现在不会。</p>
<h4 id="“说重点!!!”"><a href="#“说重点!!!”" class="headerlink" title="“说重点!!!”"></a>“说重点!!!”</h4><p>好的,我会的,当你需要同时做好几件事的时候<code>Node</code>会表现的十分优秀。你有写了一段代码然后对他说”我想你可以并行运行!”的体验吗?哈哈哈,在Node中除了你的代码所有的东西都是并行运行的。</p>
<h4 id="“啊?!”"><a href="#“啊?!”" class="headerlink" title="“啊?!”"></a>“啊?!”</h4><p>是的,没错,除了你的代码之外所有的代码都是并行运行的。为了理解这一点,你可以把你自己的代码想象成一个国王,而<code>Node</code>就是他的仆人军队。</p>
<p>新的一天是这样开始的:某个仆人叫醒了国王,然后问他是否需要什么。国王给了这个仆人一个任务清单然后就回去继续睡觉了。然后这个仆人就把任务清单上的任务分发下去,仆人们开始工作了。</p>
<p>当一个仆人完成了他的任务的时候,他就跑到国王寝宫外面排队等候报告。国王一次只能听取一个仆人报告任务,有的时候国王会在仆人报告结束的时候给他更多的任务。(看你代码咋写咯)</p>
<p>生活是美好的,因为国王的诸多仆人同时执行多个任务,但报告结果的时候是一个一个来的,所以国王能够很专注。</p>
<h4 id="“那确实很美好,但你能结束这个愚蠢的比喻用更加geek的方式来告诉我吗?”"><a href="#“那确实很美好,但你能结束这个愚蠢的比喻用更加geek的方式来告诉我吗?”" class="headerlink" title="“那确实很美好,但你能结束这个愚蠢的比喻用更加geek的方式来告诉我吗?”"></a>“那确实很美好,但你能结束这个愚蠢的比喻用更加geek的方式来告诉我吗?”</h4><p>好的,一个<code>node</code>程序或许是下面这样的:</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> fs = <span class="built_in">require</span>(<span class="string">'fs'</span>)</div><div class="line"> , sys = <span class="built_in">require</span>(<span class="string">'sys'</span>);</div><div class="line"><span class="comment">//译者注:sys is deprecated. Use util instead.这里我们直接用console.log即可</span></div><div class="line">fs.readFile(<span class="string">'treasure-chamber-report.txt'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">report</span>) </span>{</div><div class="line"> <span class="comment">//sys.puts("oh, look at all my money: "+report);</span></div><div class="line"> <span class="built_in">console</span>.log(<span class="string">"oh, look at all my money: "</span>+report)</div><div class="line">});</div><div class="line"></div><div class="line">fs.writeFile(<span class="string">'letter-to-princess.txt'</span>, <span class="string">'...'</span>, <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="comment">//sys.puts("can't wait to hear back from her!");</span></div><div class="line"> <span class="built_in">console</span>.log(<span class="string">"can't wait to hear back from her!"</span>)</div><div class="line">});</div></pre></td></tr></table></figure>
<p>你的代码(国王)给了<code>node</code>(仆人)两个任务即读(readFile)和写(writeFile)文件,然后就去睡大觉了。一旦node完成了某个任务,跟这个任务对应的回调就会触发。但同一时间只能有一个回调被触发,在那个回调执行完成之前,所有其它的回调都得排队等待。进一步说,回调触发的顺序是不能被保证的。</p>
<h4 id="“所以我不必担心代码在同一时间访问同一个数据结构?”"><a href="#“所以我不必担心代码在同一时间访问同一个数据结构?”" class="headerlink" title="“所以我不必担心代码在同一时间访问同一个数据结构?”"></a>“所以我不必担心代码在同一时间访问同一个数据结构?”</h4><p>你确实理解了,这就是JavaScript的单进程/事件循环设计美丽的地方。</p>
<h4 id="“好棒,但我为什么应该用它呢?”"><a href="#“好棒,但我为什么应该用它呢?”" class="headerlink" title="“好棒,但我为什么应该用它呢?”"></a>“好棒,但我为什么应该用它呢?”</h4><p>一个原因是效率。在一个web应用中,响应时间主要是花在了执行数据库查询上面,而用<code>node</code>,你可以一次性执行所有的数据库查询。将响应时间减少到了执行最慢的数据库查询所用的时间。</p>
<p>另一个原因是<code>Javascript</code>。你可以使用<code>Node</code>让你的浏览器和后端共享代码。Javascript也在渐渐成为一门真正的通用语言。不管你在过去是用Python, Ruby, Java, PHP, …等等,你都或多或少的使用过Javasctipt,对吗?</p>
<p>最后一个原因是原生速度。V8正在不断的推进作为地球上最快的动态语言编译器之一的边界,我也想不到有任何其它的语言在速度上能够像Javascript一样不断的高歌猛进。再进一步说,<code>node</code>的I/O设备真的十分的轻量,能够让你尽可能最大程度的利用系统的I/O容量。</p>
<h4 id="“所以你是说从现在开始我应该用Node写我所有的应用么?”"><a href="#“所以你是说从现在开始我应该用Node写我所有的应用么?”" class="headerlink" title="“所以你是说从现在开始我应该用Node写我所有的应用么?”"></a>“所以你是说从现在开始我应该用Node写我所有的应用么?”</h4><p>是也不是,一旦你开始舞弄<code>node</code>这柄锤子,所有的东西都会开始变得像钉子。但如果你当前的工作有一个deadline,你可以参考下面的几点来做决定用不用<code>node</code>:</p>
<ul>
<li>低响应时间/高并发是否重要?Node真的很擅长处理这俩问题;</li>
<li>项目有多大?小项目没问题,如果是大项目就应该认真评估了(可用的库,修复一个bug所需的资源或者two upstream等等)</li>
</ul>
<h4 id="“我能在Node中访问DOM吗?”"><a href="#“我能在Node中访问DOM吗?”" class="headerlink" title="“我能在Node中访问DOM吗?”"></a>“我能在Node中访问DOM吗?”</h4><p>这是一个好问题!答案是不行,DOM是浏览器的东西吗,不过幸好node的JS引擎(V8)跟那些混乱的东西是完全分离的。不过,有人在以node模块的形式来实现DOM,或许带来令人兴奋的可能性比如对客户端代码进行单元测试。(译者注:现在已经有人实现了这个模块,详情查看<a href="https://www.npmjs.com/package/node-dom" target="_blank" rel="external">Node-dom</a>)。</p>
<h4 id="“难道事件驱动编程真的很难吗?”"><a href="#“难道事件驱动编程真的很难吗?”" class="headerlink" title="“难道事件驱动编程真的很难吗?”"></a>“难道事件驱动编程真的很难吗?”</h4><p>这取决于你自己,如果你已经学会了如何在浏览器里调用Ajax或是调用某个事件,那么学习node对你不会是什么难题。</p>
<p>同时,测试驱动开发能够真正的帮助你从做一个可维护的设计开始学习node。</p>
<h4 id="“我应该从哪里学到更多?”"><a href="#“我应该从哪里学到更多?”" class="headerlink" title="“我应该从哪里学到更多?”"></a>“我应该从哪里学到更多?”</h4><p>Tim Caswell正在运作优秀的<a href="http://howtonode.org/" target="_blank" rel="external">How To Node</a>博客。在twitter上Follow <a href="https://twitter.com/search?q=node.js&src=typd" target="_blank" rel="external">nodejs</a>。订阅<a href="http://groups.google.com/group/nodejs" target="_blank" rel="external">邮件列表</a>。(译者注:也可以结合<a href="http://nodejs.cn/api/" target="_blank" rel="external">Node.js 6.9.5 文档</a>进行学习,另外,译者写了一个node的小应用<a href="https://github.com/damonare/node-sample" target="_blank" rel="external">node-sample</a>可以clone下来看下)</p>
<h2 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h2><p>本篇文章的比如讲真是有些简单了,但从现实事物中找到真正相对应的也是在太难。,另外,由于时间原因,本文一些不妥之处或是当时还处在实验性阶段的东西译者或删或改。能力有限,水平一般,翻译不妥之处,还望指正。感谢。</p>
]]></content>
<summary type="html">
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p><strong>总括</strong> :这篇文章十分生动形象的的介绍了Node,满足了读者想去了解Node的需求。作者是Node的第一批贡献者之一,德国前端大神。译者觉得作者的比喻很适合初学者理解Node,特此翻译。</p>
<p><strong>译者</strong> :原文网址里有只小蚂蚁的效果很有意思(多次鼠标悬浮会有惊喜),哈哈哈,可以去看一下哦。</p>
<ul>
<li>原文地址:<a href="http://debuggable.com/posts/understanding-node-js:4bd98440-45e4-4a9a-8ef7-0f7ecbdd56cb" target="_blank" rel="external">Understanding node.js</a></li>
<li>原文作者:<a href="http://felixge.de/" target="_blank" rel="external">Felix Geisendörfer</a></li>
<li>Node小应用:<a href="https://github.com/damonare/node-sample" target="_blank" rel="external">Node-sample</a></li>
<li>译者:<a href="http://damonare.cn" target="_blank" rel="external">Damonare</a></li>
</ul>
<p><strong>本文属于译文</strong> </p>
</summary>
<category term="学习" scheme="http://damonare.github.io/categories/learn/"/>
<category term="JavaScript" scheme="http://damonare.github.io/tags/JavaScript/"/>
<category term="译文" scheme="http://damonare.github.io/tags/%E8%AF%91%E6%96%87/"/>
<category term="Node.js" scheme="http://damonare.github.io/tags/Node-js/"/>
</entry>
<entry>
<title>Javascript闭包入门(译文)</title>
<link href="http://damonare.github.io/2017/01/21/Javascript%E9%97%AD%E5%8C%85%E5%85%A5%E9%97%A8(%E8%AF%91%E6%96%87)/"/>
<id>http://damonare.github.io/2017/01/21/Javascript闭包入门(译文)/</id>
<published>2017-01-21T10:01:30.000Z</published>
<updated>2017-01-21T10:01:30.000Z</updated>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p><strong>总括</strong> :这篇文章使用有效的javascript代码向程序员们解释了闭包,大牛和功能型程序员请自行忽略。</p>
<p><strong>译者</strong> :文章写在2006年,可直到翻译的21小时之前作者还在完善这篇文章,在Stackoverflow的<a href="http://stackoverflow.com/questions/111102/how-do-javascript-closures-work" target="_blank" rel="external">How do JavaScript closures work?</a>这个问题里更是得到了4000+的赞同,文章内容质量自然不必多说。</p>
<ul>
<li>原文地址:<a href="http://web.archive.org/web/20080209105120/http:/blog.morrisjohns.com/javascript_closures_for_dummies" target="_blank" rel="external">JavaScript Closures for Beginners</a></li>
<li>原文作者:Morris </li>
<li>译者:Damonare</li>
<li>译者博客地址:<a href="http://damonare.cn" target="_blank" rel="external">Damonare的个人博客</a></li>
</ul>
<p><strong>本文属于译文</strong> </p>
<a id="more"></a>
<h2 id="正文"><a href="#正文" class="headerlink" title="正文"></a>正文</h2><h3 id="闭包并不是魔法"><a href="#闭包并不是魔法" class="headerlink" title="闭包并不是魔法"></a>闭包并不是魔法</h3><p>这篇文章使用有效的javascript代码向程序员们解释了闭包,大牛和功能型程序员请自行忽略。</p>
<p>实际上一旦你对闭包的核心概念心领神会了,闭包就不难理解了,但如果你想通过读那些学术性文章或是学院派的论文来理解闭包那基本是不可能的。</p>
<p>本文主要是面向那些有主流程序语言开发经验或是能看懂下面这段代码的程序员:</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">sayHello</span>(<span class="params">name</span>) </span>{</div><div class="line"> <span class="keyword">var</span> text = <span class="string">'Hello '</span> + name;</div><div class="line"> <span class="keyword">var</span> say = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{ <span class="built_in">console</span>.log(text); }</div><div class="line"> say();</div><div class="line">}</div><div class="line">sayHello(<span class="string">'Joe'</span>);</div></pre></td></tr></table></figure>
<h3 id="一个闭包小案例"><a href="#一个闭包小案例" class="headerlink" title="一个闭包小案例"></a>一个闭包小案例</h3><p><strong>两种方式概括:</strong></p>
<ul>
<li>闭包是javascript支持<a href="https://zh.wikipedia.org/wiki/%E5%A4%B4%E7%AD%89%E5%87%BD%E6%95%B0" target="_blank" rel="external">头等函数</a>的一种方式,它是一个能够引用其内部作用域变量(在本作用域第一次声明的变量)的表达式,这个表达式可以赋值给某个变量,可以作为参数传递给函数,也可以作为一个函数返回值返回。</li>
</ul>
<p>或是</p>
<ul>
<li>闭包是函数开始执行的时候被分配的一个<a href="http://baike.baidu.com/link?url=x9za8fl-K8Gsdc0IFBbC5fTininX3H8qVBuSPsChIJd8bmzTRXvd8scDL1uCYKLS26m6GMbXgHFC5K8yXz7nZ3eImibufpfwiBWzlBDAyT_" target="_blank" rel="external">栈帧</a>,在函数执行结束返回后仍不会被释放(就好像一个栈帧被分配在堆里而不是栈里!)</li>
</ul>
<p>下面这段代码返回了一个指向这个函数的引用:</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">sayHello2</span>(<span class="params">name</span>) </span>{</div><div class="line"> <span class="keyword">var</span> text = <span class="string">'Hello '</span> + name; <span class="comment">// 局部变量text</span></div><div class="line"> <span class="keyword">var</span> say = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{ <span class="built_in">console</span>.log(text); }</div><div class="line"> <span class="keyword">return</span> say;</div><div class="line">}</div><div class="line"><span class="keyword">var</span> say2 = sayHello2(<span class="string">'Bob'</span>);</div><div class="line">say2(); <span class="comment">// 打印日志: "Hello Bob"</span></div></pre></td></tr></table></figure>
<p>绝大部分Javascript程序员能够理解上面代码中的一个函数引用是如何返回赋值给变量<code>say2</code>的,如果你不理解,那么你需要理解之后再来学习闭包。C语言程序员会认为这个函数返回一个指向某函数的指针,变量<code>say</code>和<code>say2</code>都是指向某个函数的指针。</p>
<p>Javascript的函数引用和C语言指针相比还有一个关键性的不同之处,在Javascript中,一个引用函数的变量可以看做是有两个指针,一个是指向函数的指针,一个是指向闭包的隐藏指针。</p>
<p>上面代码中就有一个闭包,为什么呢?因为匿名函数<code>function() { console.log(text); }</code>是在另一个函数(在本例中就是<code>sayHello2()</code>函数)声明的。在Javascript中,如果你在另一个函数中使用了<code>function</code>关键字,那么你就创建了一个闭包。</p>
<p>在C语言和大多数常用程序语言中,当一个函数返回后,函数内声明的局部变量就不能再被访问了,因为该函数对应的栈帧已经被销毁了。</p>
<p>在Javscript中,如果你在一个函数中声明了另一个函数,那么在你调用这个函数返回后里面的局部变量仍然是可以访问的。这个已经在上面的代码中演示过了,即我们在函数<code>sayHello()</code>返回后仍然可以调用函数<code>say2()</code>。<strong>注意:我们在代码中引用的变量<code>text</code>是我们在函数<code>sayHello2()</code>中声明的局部变量。</strong></p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{ <span class="built_in">console</span>.log(text); } <span class="comment">// 输出say2.toString();</span></div></pre></td></tr></table></figure>
<p>观察<code>say2.toString()</code>的输出,我们可以看到确实引用了<code>text</code>变量。匿名函数之所以可以引用包含<code>'Hello Bob'</code>的<code>text</code>变量就是因为<code>sayhello2()</code>的局部变量被保存在了闭包中。</p>
<p>神奇的是,在JavaScript中,函数引用还有一个对于它所创建的闭包的秘密引用,类似于事件委托是一个方法指针加上对于某个对象的秘密引用。</p>
<h3 id="更多例子"><a href="#更多例子" class="headerlink" title="更多例子"></a>更多例子</h3><p>出于某种不得而知的原因,当你去阅读一些关于闭包的文章的时候,闭包看起来真的是难以理解的。但如果你看到一些你能够去操作的闭包小案例(这花费了我一段时间),闭包就容易理解了。推荐好好推敲下这几个小案例直到你彻底理解了它们到底是如何工作的。如果你没完全弄明白闭包是如何工作的就去盲目使用闭包,会搞出很多神奇的bug的!</p>
<h4 id="例3"><a href="#例3" class="headerlink" title="例3"></a>例3</h4><p>局部变量虽然没有被复制,但可以通过被引用而被保留下来。这就好像外部函数退出后,但栈帧依旧保存在内存中一样。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">say667</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="comment">// 局部变量num最后会保存在闭包中</span></div><div class="line"> <span class="keyword">var</span> num = <span class="number">42</span>;</div><div class="line"> <span class="keyword">var</span> say = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{ <span class="built_in">console</span>.log(num); }</div><div class="line"> num++;</div><div class="line"> <span class="keyword">return</span> say;</div><div class="line">}</div><div class="line"><span class="keyword">var</span> sayNumber = say667();</div><div class="line">sayNumber(); <span class="comment">// 输出 43</span></div></pre></td></tr></table></figure>
<h4 id="例4"><a href="#例4" class="headerlink" title="例4"></a>例4</h4><p>下面三个全局函数对同一个闭包有一个共同的引用,因为他们都是在调用函数<code>setupSomeGlobals()</code>时声明的。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> gLogNumber, gIncreaseNumber, gSetNumber;</div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">setupSomeGlobals</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="comment">// 局部变量num最后会保存在闭包中</span></div><div class="line"> <span class="keyword">var</span> num = <span class="number">42</span>;</div><div class="line"> <span class="comment">// 将一些对于函数的引用存储为全局变量</span></div><div class="line"> gLogNumber = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{ <span class="built_in">console</span>.log(num); }</div><div class="line"> gIncreaseNumber = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{ num++; }</div><div class="line"> gSetNumber = <span class="function"><span class="keyword">function</span>(<span class="params">x</span>) </span>{ num = x; }</div><div class="line">}</div><div class="line">setupSomeGlobals();</div><div class="line">gIncreaseNumber();</div><div class="line">gLogNumber(); <span class="comment">// 43</span></div><div class="line">gSetNumber(<span class="number">5</span>);</div><div class="line">gLogNumber(); <span class="comment">// 5</span></div><div class="line"><span class="keyword">var</span> oldLog = gLogNumber;</div><div class="line">setupSomeGlobals();</div><div class="line">gLogNumber(); <span class="comment">// 42</span></div><div class="line">oldLog() <span class="comment">// 5</span></div></pre></td></tr></table></figure>
<p>这三个函数具有对同一个闭包的共享访问权限——这个闭包是指当三个函数定义时<code>setupSomeGlobals()</code>的局部变量。</p>
<p><strong>注意:在上述示例中,当你再次调用<code>setupSomeGlobals()</code>时,一个新的闭包(栈帧)就被创建了。</strong>旧变量<code>gLogNumber</code>, <code>gIncreaseNumber</code>, <code>gSetNumber</code> 被有新闭包的函数覆盖(在JavaScript中,如果你在一个函数中声明了一个新的函数,那么当外部函数被调用时,内部函数会被重新创建)。</p>
<h4 id="例5"><a href="#例5" class="headerlink" title="例5"></a>例5</h4><p> 这个示例对于很多人来说都是一个挑战,所以希望你能弄懂它。<strong>注意:当你在一个循环里面定义一个函数的时候,闭包里的局部变量可能不会像你想的那样。</strong></p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">buildList</span>(<span class="params">list</span>) </span>{</div><div class="line"> <span class="keyword">var</span> result = [];</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i < list.length; i++) {</div><div class="line"> <span class="keyword">var</span> item = <span class="string">'item'</span> + i;</div><div class="line"> result.push( <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{<span class="built_in">console</span>.log(item + <span class="string">' '</span> + list[i])} );</div><div class="line"> }</div><div class="line"> <span class="keyword">return</span> result;</div><div class="line">}</div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">testList</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="keyword">var</span> fnlist = buildList([<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>]);</div><div class="line"> <span class="comment">// 使用j是为了防止搞混---可以使用i</span></div><div class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> j = <span class="number">0</span>; j < fnlist.length; j++) {</div><div class="line"> fnlist[j]();</div><div class="line"> }</div><div class="line">}</div><div class="line"> testList() <span class="comment">//输出 "item2 undefined" 3 次</span></div></pre></td></tr></table></figure>
<p><code>result.push( function() {console.log(item + ' ' + list[i])}</code>这一行给<code>result</code>数组添加了三次函数匿名引用。如果你不熟悉匿名函数可以想象成下面代码:</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">pointer = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{<span class="built_in">console</span>.log(item + <span class="string">' '</span> + list[i])};</div><div class="line">result.push(pointer);</div></pre></td></tr></table></figure>
<p>注意,当你运行上述代码的时候会打印<code>"item2 undefined"</code>三次!和前面的示例一样,和<code>buildList</code>的局部变量对应的闭包只有一个。当匿名函数在<code>fnlist[j]()</code>这一行调用的时候,他们使用同一个闭包,而且是使用的这个闭包里<code>i</code>和<code>item</code>现在的值(循环结束后<code>i</code>的值为3,<code>item</code>的值为<code>'item2'</code>)。<strong>注意:我们从索引<code>0</code>开始,所以<code>item</code>最后的值为<code>item2'</code>,<code>i</code>的值会被<code>i++</code>增加到<code>3</code> 。</strong></p>
<h4 id="例6"><a href="#例6" class="headerlink" title="例6"></a>例6</h4><p>这个例子表明了闭包会保存函数退出之前内部定义的所有的局部变量。<strong>注意:变量<code>alice</code>是在匿名函数之前创建的。</strong> 匿名函数先被声明,然后当它被调用的时候之所以能够访问<code>alice</code>是因为他们在同一个作用域内(JavaScript做了<a href="http://stackoverflow.com/questions/3725546/variable-hoisting/3725763#3725763" target="_blank" rel="external">变量提升</a>),<code>sayAlice()()</code>直接调用了从<code>sayAlice()</code>中返回的函数引用——这个和前面的完全一样,只是少了临时的变量【译者注:存储sayAlice()返回的函数引用的变量】</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">sayAlice</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="keyword">var</span> say = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{ <span class="built_in">console</span>.log(alice); }</div><div class="line"> <span class="comment">// 局部变量最后保存在闭包中</span></div><div class="line"> <span class="keyword">var</span> alice = <span class="string">'Hello Alice'</span>;</div><div class="line"> <span class="keyword">return</span> say;</div><div class="line">}</div><div class="line">sayAlice()();<span class="comment">// 输出"Hello Alice"</span></div></pre></td></tr></table></figure>
<p><strong>技巧:需要注意变量<code>say</code>也是在闭包内部,也能被在<code>sayAlice()</code>内部声明的其它函数访问,或者也可以在函数内部递归访问它。</strong></p>
<h4 id="例7"><a href="#例7" class="headerlink" title="例7"></a>例7</h4><p>最后一个例子说明了每次调用函数都会为局部变量创建一个闭包。实际上每次函数声明并不会创建一个单独的闭包,但每次调用函数都会创建一个独立的闭包。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">newClosure</span>(<span class="params">someNum, someRef</span>) </span>{</div><div class="line"> <span class="comment">// 局部变量最终保存在闭包中</span></div><div class="line"> <span class="keyword">var</span> num = someNum;</div><div class="line"> <span class="keyword">var</span> anArray = [<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>];</div><div class="line"> <span class="keyword">var</span> ref = someRef;</div><div class="line"> <span class="keyword">return</span> <span class="function"><span class="keyword">function</span>(<span class="params">x</span>) </span>{</div><div class="line"> num += x;</div><div class="line"> anArray.push(num);</div><div class="line"> <span class="built_in">console</span>.log(<span class="string">'num: '</span> + num +</div><div class="line"> <span class="string">'\nanArray '</span> + anArray.toString() +</div><div class="line"> <span class="string">'\nref.someVar '</span> + ref.someVar);</div><div class="line"> }</div><div class="line">}</div><div class="line">obj = {<span class="attr">someVar</span>: <span class="number">4</span>};</div><div class="line">fn1 = newClosure(<span class="number">4</span>, obj);</div><div class="line">fn2 = newClosure(<span class="number">5</span>, obj);</div><div class="line">fn1(<span class="number">1</span>); <span class="comment">// num: 5; anArray: 1,2,3,5; ref.someVar: 4;</span></div><div class="line">fn2(<span class="number">1</span>); <span class="comment">// num: 6; anArray: 1,2,3,6; ref.someVar: 4;</span></div><div class="line">obj.someVar++;</div><div class="line">fn1(<span class="number">2</span>); <span class="comment">// num: 7; anArray: 1,2,3,5,7; ref.someVar: 5;</span></div><div class="line">fn2(<span class="number">2</span>); <span class="comment">// num: 8; anArray: 1,2,3,6,8; ref.someVar: 5;</span></div></pre></td></tr></table></figure>
<h4 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h4><p>如果任何不太明白的地方最好的方式就是把玩这几个例子,去机械地阅读一些文章远比去做这些实例难得多。我关于闭包的说明、栈框体(stack-frame)的说明等等,严格理论上讲并不是完全正确的——它们只是为了理解而简化处理过的。当基础的概念心领神会之后,就可以轻松地理解这些细节了。</p>
<h3 id="最终总结"><a href="#最终总结" class="headerlink" title="最终总结"></a>最终总结</h3><ul>
<li>每当你在另一个函数里使用了关键字<code>function</code>,一个闭包就被创建了</li>
<li>每当你在一个函数内部使用了<code>eval()</code>,一个闭包就被创建了。在<code>eval</code>内部你可以引用外部函数定义的局部变量,同样的,在<code>eval</code>内部也可以通过<code>eval('var foo = …')</code>来创建新的局部变量。</li>
<li>当你在一个函数内部使用<code>new function(...)</code>(即<a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function" target="_blank" rel="external">构造函数</a>)时,它不会创建闭包(新函数不能引用外部函数的局部变量)。</li>
<li>JavaScript中的闭包,就像一个副本,将某函数在退出时候的所有局部变量复制保存其中。</li>
<li>也许最好的理解是闭包总是在进入某个函数的时候被创建,而局部变量是被加入到这个闭包中。</li>
<li>闭包函数每次被调用的时候都会创建一组新的局部变量存储。(前提是这个函数包含一个内部的函数声明,并且这个函数的引用被返回或者用某种方法被存储到一个外部的引用中)</li>
<li>两个函数或许从源代码文本上看起来一样,但因为隐藏闭包的存在会让两个函数具有不同的行为。我认为Javascript代码实际上并不能找出一个函数引用是否有闭包。</li>
<li>如果你正尝试做一些动态源代码的修改(例如:<code>myFunction = Function(myFunction.toString().replace(/Hello/,'Hola'));</code>),如果<code>myFunction</code>是一个闭包的话,那么这并不会生效(当然,你甚至可能从来都没有在运行的时候考虑过修改源代码字符串,但是。。。)。</li>
<li>在函数内部的函数的内部声明函数是可以的——可以获得不止一个层级的闭包。</li>
<li>通常我认为闭包是一个同时包含函数和被捕捉的变量的术语,但是请注意我并没有在本文中使用这个定义。</li>
<li>我觉得JavaScript中的闭包跟其它函数式编程语言中的闭包是有不同之处的。</li>
</ul>
<h3 id="感谢"><a href="#感谢" class="headerlink" title="感谢"></a>感谢</h3><p>如果你正好在学习闭包(在这里或是其他地方),期待您对本文的任何反馈,您的任何建议都可能会使本文更加清晰易懂。请联系<a href="mailto:[email protected]" target="_blank" rel="external">[email protected] 【译者注:这是译者的邮箱,欢迎交流学习】</a></p>
<h2 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h2><p>这是译者翻译的第一篇文章,收获良多,感觉上并不比自己写一篇文章省事,相反熟悉内容了解代码的同时还得去揣摩作者表达的意图,难度的确要比自己单独写一篇高。能力有限,水平一般,有翻译不到位的地方,欢迎批评指正。感谢!</p>
]]></content>
<summary type="html">
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p><strong>总括</strong> :这篇文章使用有效的javascript代码向程序员们解释了闭包,大牛和功能型程序员请自行忽略。</p>
<p><strong>译者</strong> :文章写在2006年,可直到翻译的21小时之前作者还在完善这篇文章,在Stackoverflow的<a href="http://stackoverflow.com/questions/111102/how-do-javascript-closures-work" target="_blank" rel="external">How do JavaScript closures work?</a>这个问题里更是得到了4000+的赞同,文章内容质量自然不必多说。</p>
<ul>
<li>原文地址:<a href="http://web.archive.org/web/20080209105120/http:/blog.morrisjohns.com/javascript_closures_for_dummies" target="_blank" rel="external">JavaScript Closures for Beginners</a></li>
<li>原文作者:Morris </li>
<li>译者:Damonare</li>
<li>译者博客地址:<a href="http://damonare.cn" target="_blank" rel="external">Damonare的个人博客</a></li>
</ul>
<p><strong>本文属于译文</strong> </p>
</summary>
<category term="学习" scheme="http://damonare.github.io/categories/learn/"/>
<category term="JavaScript" scheme="http://damonare.github.io/tags/JavaScript/"/>
<category term="译文" scheme="http://damonare.github.io/tags/%E8%AF%91%E6%96%87/"/>
</entry>
<entry>
<title>Ajax入门</title>
<link href="http://damonare.github.io/2017/01/20/Ajax%E5%85%A5%E9%97%A8/"/>
<id>http://damonare.github.io/2017/01/20/Ajax入门/</id>
<published>2017-01-20T13:21:20.000Z</published>
<updated>2017-05-13T06:58:58.000Z</updated>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p><strong>总括:</strong> 本文讲述了ajax的历史,工作原理以及优缺点,对XMLHttpRequest对象进行了详细的讲解,并使用原生js实现了一个ajax对象以方便日常开始使用。</p>
<ul>
<li><p>damonare的ajax库:<a href="https://github.com/damonare/ajax/tree/master" target="_blank" rel="external">damonare的ajax库</a></p>
</li>
<li><p>原文博客地址:<a href="https://damonare.github.io/2017/01/18/%E4%BD%A0%E7%9C%9F%E7%9A%84%E6%87%82ajax%E5%90%97%EF%BC%9F/#more">你真的懂ajax吗?</a></p>
</li>
<li>知乎专栏&&简书专题:<a href="https://zhuanlan.zhihu.com/damonare" target="_blank" rel="external">前端进击者(知乎)</a>&&<a href="http://www.jianshu.com/collection/bbaa63e264f5" target="_blank" rel="external">前端进击者(简书)</a></li>
<li>博主博客地址:<a href="http://damonare.cn" target="_blank" rel="external">Damonare的个人博客</a></li>
</ul>
<p><strong>古之立大事者,不惟有超世之才,亦必有坚忍不拔之志。</strong></p>
<a id="more"></a>
<h2 id="正文"><a href="#正文" class="headerlink" title="正文"></a>正文</h2><p>相信每个前端程序员日常工作中都避免不了的工作就是和后端联调,联调自然就避免不了使用<code>ajax</code>,但我相信,不管是使用jquery封装的<code>ajax</code>方法还是使用vue的插件<code>vue-resource</code>的程序员,真正对于<code>ajax</code>有过深入探究的并不多,我们更多的是为了使用而使用,至于它的原理往往因为即使不了解依旧能做出东西而懒得去看,我们都被轮子们惯坏了。根据<a href="https://zh.wikipedia.org/wiki/%E5%B8%95%E9%9B%B7%E6%89%98%E6%B3%95%E5%88%99" target="_blank" rel="external">二八定律</a>,即任何一组东西中,最重要的只占其中一小部分,约20%,其余80%的尽管是多数,却是次要的。因 此,如果想挤进那20%的行列,就要学到一般人学不到的深度,学到一般人学不了的东西。</p>
<p>好的,现在我们从头来说一下<code>ajax</code>。</p>
<h3 id="Ajax简介"><a href="#Ajax简介" class="headerlink" title="Ajax简介"></a>Ajax简介</h3><p>在上世纪90年代,几乎所有的网站都由HTML页面实现,服务器处理每一个用户请求都需要重新加载网页。形式是怎样的呢?就比如说你在浏览器上登录自己的微博账号,填完了表单,点击登录按钮,一次”完整”的HTTP请求就此触发,服务器发现你的登录密码不对头,立马把网页原原本本的返回给你,在用户看来呢,就是一次重新加载的过程!用户体验极差!而且这个做法浪费了许多带宽,因为在前后两个页面中的大部分HTML码往往是相同的。由于每次应用的沟通都需要向服务器发送请求,应用的回应时间依赖于服务器的回应时间。这导致了用户界面的回应比本机应用慢得多。</p>
<p>到了2005年,google率先在它的应用(诸如google地图、gmail)里使用了<code>ajax</code>技术,这才让这项技术正式风靡开来。</p>
<p>如今它的应用已经十分广泛:</p>
<ul>
<li>运用<a href="https://zh.wikipedia.org/wiki/XHTML" target="_blank" rel="external">XHTML</a>+<a href="https://zh.wikipedia.org/wiki/CSS" target="_blank" rel="external">CSS</a>来表达信息;</li>
<li>运用<a href="https://zh.wikipedia.org/wiki/JavaScript" target="_blank" rel="external">JavaScript</a>操作<a href="https://zh.wikipedia.org/wiki/%E6%96%87%E4%BB%B6%E7%89%A9%E4%BB%B6%E6%A8%A1%E5%9E%8B" target="_blank" rel="external">DOM</a>(Document Object Model)来运行动态效果;</li>
<li>运用<a href="https://zh.wikipedia.org/wiki/XML" target="_blank" rel="external">XML</a>和<a href="https://zh.wikipedia.org/wiki/XSLT" target="_blank" rel="external">XSLT</a>操作数据;</li>
<li>运用<a href="https://zh.wikipedia.org/wiki/XMLHttpRequest" target="_blank" rel="external">XMLHttpRequest</a>或新的Fetch API与<a href="https://zh.wikipedia.org/wiki/%E7%B6%B2%E9%A0%81%E4%BC%BA%E6%9C%8D%E5%99%A8" target="_blank" rel="external">网页服务器</a>进行异步数据交换;</li>
<li>注意:AJAX与<a href="https://zh.wikipedia.org/wiki/Flash" target="_blank" rel="external">Flash</a>、<a href="https://zh.wikipedia.org/wiki/Silverlight" target="_blank" rel="external">Silverlight</a>和<a href="https://zh.wikipedia.org/wiki/Java_Applet" target="_blank" rel="external">Java Applet</a>等<a href="https://zh.wikipedia.org/wiki/RIA" target="_blank" rel="external">RIA</a>技术是有区分的。</li>
</ul>
<h3 id="Ajax工作原理"><a href="#Ajax工作原理" class="headerlink" title="Ajax工作原理"></a>Ajax工作原理</h3><p> Ajax的工作原理相当于在用户和服务器之间加了一个中间层(ajax引擎),使用户操作与服务器响应异步化。并不是所有的用户请求都提交给服务器,像—些数据验证(比如判断用户是否输入了数据)和数据处理(比如判断用户输入数据是否是数字)等都交给Ajax引擎自己来做, 只有确定需要从服务器读取新数据时再由Ajax引擎代为向服务器提交请求。把这些交给了Ajax引擎,用户操作起来也就感觉更加流畅了。</p>
<h3 id="Ajax优缺点"><a href="#Ajax优缺点" class="headerlink" title="Ajax优缺点"></a>Ajax优缺点</h3><h4 id="Ajax的优点"><a href="#Ajax的优点" class="headerlink" title="Ajax的优点"></a>Ajax的优点</h4><ol>
<li>无刷新更新数据。</li>
</ol>
<p>AJAX最大优点就是能在不刷新整个页面的前提下与服务器通信维护数据。这使得Web应用程序更为迅捷地响应用户交互,并避免了在网络上发送那些没有改变的信息,减少用户等待时间,带来非常好的用户体验。</p>
<ol>
<li>异步与服务器通信。</li>
</ol>
<p>AJAX使用异步方式与服务器通信,不需要打断用户的操作,具有更加迅速的响应能力。优化了Browser和Server之间的沟通,减少不必要的数据传输、时间及降低网络上数据流量。</p>
<ol>
<li>前端和后端负载平衡。</li>
</ol>
<p>AJAX可以把以前一些服务器负担的工作转嫁到客户端,利用客户端闲置的能力来处理,减轻服务器和带宽的负担,节约空间和宽带租用成本。并且减轻服务器的负担,AJAX的原则是“按需取数据”,可以最大程度的减少冗余请求和响应对服务器造成的负担,提升站点性能。</p>
<ol>
<li>基于标准被广泛支持。</li>
</ol>
<p>AJAX基于标准化的并被广泛支持的技术,不需要下载浏览器插件或者小程序,但需要客户允许JavaScript在浏览器上执行。随着Ajax的成熟,一些简化Ajax使用方法的程序库也相继问世。同样,也出现了另一种辅助程序设计的技术,为那些不支持JavaScript的用户提供替代功能。</p>
<ol>
<li>界面与应用分离。</li>
</ol>
<p>Ajax使WEB中的界面与应用分离(也可以说是数据与呈现分离),有利于分工合作、减少非技术人员对页面的修改造成的WEB应用程序错误、提高效率、也更加适用于现在的发布系统。</p>
<h4 id="Ajax缺点"><a href="#Ajax缺点" class="headerlink" title="Ajax缺点"></a>Ajax缺点</h4><ol>
<li>AjAX干掉了Back和加入收藏书签功能,即对浏览器机制的破坏。</li>
</ol>
<blockquote>
<p> 对应用Ajax最主要的批评就是,它可能破坏浏览器的后退与加入收藏书签功能。在动态更新页面的情况下,用户无法回到前一个页面状态,这是因为浏览器仅能记下历史记录中的<a href="https://zh.wikipedia.org/w/index.php?title=%E9%9D%99%E6%80%81%E9%A1%B5%E9%9D%A2&action=edit&redlink=1" target="_blank" rel="external">静态页面</a>。一个被完整读入的页面与一个已经被动态修改过的页面之间的可能差别非常微妙;用户通常都希望单击后退按钮,就能够取消他们的前一次操作,但是在Ajax应用程序中,却无法这样做。不过开发者已想出了种种办法来解决这个问题,<a href="https://zh.wikipedia.org/wiki/HTML5" target="_blank" rel="external">HTML5</a> 之前的方法大多是在用户单击后退按钮访问历史记录时,通过创建或使用一个隐藏的IFRAME来重现页面上的变更。(例如,当用户在Google Maps中单击后退时,它在一个隐藏的<a href="https://zh.wikipedia.org/w/index.php?title=IFRAME&action=edit&redlink=1" target="_blank" rel="external">IFRAME</a>中进行搜索,然后将搜索结果反映到Ajax元素上,以便将应用程序状态恢复到当时的状态)。</p>
<p>关于无法将状态加入收藏或书签的问题,<a href="https://zh.wikipedia.org/wiki/HTML5" target="_blank" rel="external">HTML5</a>之前的一种方式是使用<a href="https://zh.wikipedia.org/wiki/URL" target="_blank" rel="external">URL</a>片断标识符(通常被称为<a href="https://zh.wikipedia.org/wiki/%E9%94%9A%E7%82%B9" target="_blank" rel="external">锚点</a>,即URL中#后面的部分)来保持追踪,允许用户回到指定的某个应用程序状态。(许多浏览器允许JavaScript动态更新锚点,这使得Ajax应用程序能够在更新显示内容的同时更新锚点。)<a href="https://zh.wikipedia.org/wiki/HTML5" target="_blank" rel="external">HTML5</a> 以后可以直接操作浏览历史,并以字符串形式存储网页状态,将网页加入网页收藏夹或书签时状态会被隐形地保留。上述两个方法也可以同时解决无法后退的问题。</p>
</blockquote>
<ol>
<li>AJAX的安全问题。</li>
</ol>
<p>AJAX技术给用户带来很好的用户体验的同时也对IT企业带来了新的安全威胁,Ajax技术就如同对企业数据建立了一个直接通道。这使得开发者在不经意间会暴露比以前更多的数据和服务器逻辑。Ajax的逻辑可以对客户端的安全扫描技术隐藏起来,允许黑客从远端服务器上建立新的攻击。还有Ajax也难以避免一些已知的安全弱点,诸如跨站点脚步攻击、SQL注入攻击和基于Credentials的安全漏洞等等。</p>
<ol>
<li>因为网络延迟需要给用户提供必要提示</li>
</ol>
<p>进行Ajax开发时,网络延迟——即用户发出请求到服务器发出响应之间的间隔——需要慎重考虑。如果不给予用户明确的回应,没有恰当的预读数据,或者对XMLHttpRequest的不恰当处理,都会使用户感到厌烦。通常的解决方案是,使用一个可视化的组件来告诉用户系统正在进行后台操作并且正在读取数据和内容。</p>
<h3 id="XMLhttpRequest介绍"><a href="#XMLhttpRequest介绍" class="headerlink" title="XMLhttpRequest介绍"></a>XMLhttpRequest介绍</h3><p>Ajax(Asynchronous JavaScript and XML)不是指一种单一的技术,而是有机地利用了一系列相关的技术。虽然其名称包含XML,但实际上数据格式可以由<a href="https://zh.wikipedia.org/wiki/JSON" target="_blank" rel="external">JSON</a>代替,进一步减少数据量,形成所谓的AJAJ。为了使用JavaScript向服务器发出 <a href="https://developer.mozilla.org/en/HTTP" target="_blank" rel="external">HTTP</a> 请求,需要一个提供此功能的类的实例。这就是XMLHttpRequest的由来。这样的类最初是在Internet Explorer中作为一个名为XMLHTTP的ActiveX对象引入的。然后,Mozilla,Safari和其他浏览器,实现一个XMLHttpRequest类,支持Microsoft的原始ActiveX对象的方法和属性。同时微软也实现了XMLHttpRequest。</p>
<p>显而易见XMLHttpRequest类是重中之重了。</p>
<h4 id="XMLhttpRequest属性"><a href="#XMLhttpRequest属性" class="headerlink" title="XMLhttpRequest属性"></a>XMLhttpRequest属性</h4><h5 id="onreadystatechange"><a href="#onreadystatechange" class="headerlink" title="onreadystatechange"></a>onreadystatechange</h5><p>一个JavaScript函数对象,当readyState属性改变时会调用它。回调函数会在user interface线程中调用。</p>
<h5 id="readyState"><a href="#readyState" class="headerlink" title="readyState"></a>readyState</h5><p>HTTP 请求的状态.当一个 XMLHttpRequest 初次创建时,这个属性的值从 0 开始,直到接收到完整的 HTTP 响应,这个值增加到 4。</p>
<p>5 个状态中每一个都有一个相关联的非正式的名称,下表列出了状态、名称和含义:</p>
<table>
<thead>
<tr>
<th>状态</th>
<th>名称</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td>0</td>
<td>Uninitialized</td>
<td>初始化状态。XMLHttpRequest 对象已创建或已被 abort() 方法重置。</td>
</tr>
<tr>
<td>1</td>
<td>Open</td>
<td>open() 方法已调用,但是 send() 方法未调用。请求还没有被发送。</td>
</tr>
<tr>
<td>2</td>
<td>Sent</td>
<td>Send() 方法已调用,HTTP 请求已发送到 Web 服务器。未接收到响应。</td>
</tr>
<tr>
<td>3</td>
<td>Receiving</td>
<td>所有响应头部都已经接收到。响应体开始接收但未完成。</td>
</tr>
<tr>
<td>4</td>
<td>Loaded</td>
<td>HTTP 响应已经完全接收。</td>
</tr>
</tbody>
</table>
<p>readyState 的值不会递减,除非当一个请求在处理过程中的时候调用了 abort() 或 open() 方法。每次这个属性的值增加的时候,都会触发 onreadystatechange 事件句柄。</p>
<h5 id="responseText"><a href="#responseText" class="headerlink" title="responseText"></a>responseText</h5><p>目前为止为服务器接收到的响应体(不包括头部),或者如果还没有接收到数据的话,就是空字符串。</p>
<p>如果 readyState 小于 3,这个属性就是一个空字符串。当 readyState 为 3,这个属性返回目前已经接收的响应部分。如果 readyState 为 4,这个属性保存了完整的响应体。</p>
<p>如果响应包含了为响应体指定字符编码的头部,就使用该编码。否则,假定使用 Unicode UTF-8。</p>
<h5 id="responseXML"><a href="#responseXML" class="headerlink" title="responseXML"></a>responseXML</h5><p>对请求的响应,解析为 XML 并作为 Document 对象返回。</p>
<h5 id="status"><a href="#status" class="headerlink" title="status"></a>status</h5><p>由服务器返回的 HTTP 状态代码,如 200 表示成功,而 404 表示 “Not Found” 错误。当 readyState 小于 3 的时候读取这一属性会导致一个异常。</p>
<h5 id="statusText"><a href="#statusText" class="headerlink" title="statusText"></a>statusText</h5><p>这个属性用名称而不是数字指定了请求的 HTTP 的状态代码。也就是说,当状态为 200 的时候它是 “OK”,当状态为 404 的时候它是 “Not Found”。和 status 属性一样,当 readyState 小于 3 的时候读取这一属性会导致一个异常。</p>
<h4 id="XMLHttpRequest方法"><a href="#XMLHttpRequest方法" class="headerlink" title="XMLHttpRequest方法"></a>XMLHttpRequest方法</h4><h5 id="abort"><a href="#abort" class="headerlink" title="abort()"></a>abort()</h5><p>取消当前响应,关闭连接并且结束任何未决的网络活动。</p>
<p>这个方法把 XMLHttpRequest 对象重置为 readyState 为 0 的状态,并且取消所有未决的网络活动。例如,如果请求用了太长时间,而且响应不再必要的时候,可以调用这个方法。</p>
<h5 id="getAllResponseHeaders"><a href="#getAllResponseHeaders" class="headerlink" title="getAllResponseHeaders()"></a>getAllResponseHeaders()</h5><p>把 HTTP 响应头部作为未解析的字符串返回。</p>
<p>如果 readyState 小于 3,这个方法返回 null。否则,它返回服务器发送的所有 HTTP 响应的头部。头部作为单个的字符串返回,一行一个头部。每行用换行符 “\r\n” 隔开。</p>
<h5 id="getResponseHeader"><a href="#getResponseHeader" class="headerlink" title="getResponseHeader()"></a>getResponseHeader()</h5><p>返回指定的 HTTP 响应头部的值。其参数是要返回的 HTTP 响应头部的名称。可以使用任何大小写来制定这个头部名字,和响应头部的比较是不区分大小写的。</p>
<p>该方法的返回值是指定的 HTTP 响应头部的值,如果没有接收到这个头部或者 readyState 小于 3 则为空字符串。如果接收到多个有指定名称的头部,这个头部的值被连接起来并返回,使用逗号和空格分隔开各个头部的值。</p>
<h5 id="open"><a href="#open" class="headerlink" title="open()"></a>open()</h5><p>初始化一个请求. 该方法用于JavaScript代码中;如果是本地代码, 使用 <a href="https://developer.mozilla.org/zh-cn/nsIXMLHttpRequest#openRequest(" target="_blank" rel="external"><code>openRequest()</code></a>)方法代替.</p>
<blockquote>
<p> <strong>注意:</strong> 在一个已经激活的request下(已经调用open()或者openRequest()方法的request)再次调用这个方法相当于调用了abort()方法。</p>
</blockquote>
<p>参数</p>
<ul>
<li><p><code>method</code></p>
<p>请求所使用的HTTP方法; 例如 “GET”, “POST”, “PUT”, “DELETE”等. 如果下个参数是非HTTP(S)的URL,则忽略该参数.</p>
</li>
<li><p><code>url</code></p>
<p>该请求所要访问的URL</p>
</li>
<li><p><code>async</code></p>
<p>一个可选的布尔值参数,默认为true,意味着是否执行异步操作,如果值为false,则send()方法不会返回任何东西,直到接受到了服务器的返回数据。如果为值为true,一个对开发者透明的通知会发送到相关的事件监听者。这个值必须是true,如果multipart 属性是true,否则将会出现一个意外。</p>
</li>
<li><p><code>user</code></p>
<p>用户名,可选参数,为授权使用;默认参数为空string.</p>
</li>
<li><p><code>password</code></p>
<p>密码,可选参数,为授权使用;默认参数为空string.</p>
</li>
</ul>
<h5 id="send"><a href="#send" class="headerlink" title="send()"></a>send()</h5><p>发送 HTTP 请求,使用传递给 open() 方法的参数,以及传递给该方法的可选请求体。</p>
<h5 id="setRequestHeader"><a href="#setRequestHeader" class="headerlink" title="setRequestHeader()"></a>setRequestHeader()</h5><p>向一个打开但未发送的请求设置或添加一个 HTTP 请求(设置请求头)。</p>
<p>参数</p>
<ul>
<li><p><code>header</code></p>
<p>将要被赋值的请求头名称</p>
</li>
<li><p><code>value</code></p>
<p>给指定的请求头赋的值</p>
</li>
</ul>
<h3 id="Ajax原生js实现"><a href="#Ajax原生js实现" class="headerlink" title="Ajax原生js实现"></a>Ajax原生js实现</h3><p>下面是使用原生js写的ajax:</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> ajax = {};</div><div class="line">ajax.httpRequest = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</div><div class="line"> <span class="comment">//判断是否支持XMLHttpRequest对象</span></div><div class="line"> <span class="keyword">if</span> (<span class="built_in">window</span>.XMLHttpRequest) {</div><div class="line"> <span class="keyword">return</span> <span class="keyword">new</span> XMLHttpRequest();</div><div class="line"> }</div><div class="line"> <span class="comment">//兼容IE浏览器</span></div><div class="line"> <span class="keyword">var</span> versions = [</div><div class="line"> <span class="string">"MSXML2.XmlHttp.6.0"</span>,</div><div class="line"> <span class="string">"MSXML2.XmlHttp.5.0"</span>,</div><div class="line"> <span class="string">"MSXML2.XmlHttp.4.0"</span>,</div><div class="line"> <span class="string">"MSXML2.XmlHttp.3.0"</span>,</div><div class="line"> <span class="string">"MSXML2.XmlHttp.2.0"</span>,</div><div class="line"> <span class="string">"Microsoft.XmlHttp"</span></div><div class="line"> ];</div><div class="line"> <span class="comment">//定义局部变量xhr,储存IE浏览器的ActiveXObject对象</span></div><div class="line"> <span class="keyword">var</span> xhr;</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i < versions.length; i++) {</div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> xhr = <span class="keyword">new</span> ActiveXObject(versions[i]);</div><div class="line"> <span class="keyword">break</span>;</div><div class="line"> } <span class="keyword">catch</span> (e) {</div><div class="line"> }</div><div class="line"> }</div><div class="line"> <span class="keyword">return</span> xhr;</div><div class="line">};</div><div class="line"></div><div class="line">ajax.send = <span class="function"><span class="keyword">function</span> (<span class="params">url, callback, method, data, async</span>) </span>{</div><div class="line"> <span class="comment">//默认异步</span></div><div class="line"> <span class="keyword">if</span> (<span class="keyword">async</span> === <span class="literal">undefined</span>) {</div><div class="line"> <span class="keyword">async</span> = <span class="literal">true</span>;</div><div class="line"> }</div><div class="line"> <span class="keyword">var</span> httpRequest = ajax.httpRequest();</div><div class="line"> <span class="comment">//初始化HTTP请求</span></div><div class="line"> httpRequest.open(method, url, <span class="keyword">async</span>);</div><div class="line"> <span class="comment">//onreadystatechange函数对象</span></div><div class="line"> httpRequest.onreadystatechange = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</div><div class="line"> <span class="comment">//readyState 的值等于4,从服务器拿到了数据</span></div><div class="line"> <span class="keyword">if</span> (httpRequest.readyState == <span class="number">4</span>) {</div><div class="line"> <span class="comment">//回调服务器响应数据</span></div><div class="line"> callback(httpRequest.responseText)</div><div class="line"> }</div><div class="line"> };</div><div class="line"> <span class="keyword">if</span> (method == <span class="string">'POST'</span>) {</div><div class="line"> <span class="comment">//给指定的HTTP请求头赋值</span></div><div class="line"> httpRequest.setRequestHeader(<span class="string">'Content-type'</span>, <span class="string">'application/x-www-form-urlencoded'</span>);</div><div class="line"> }</div><div class="line"> <span class="comment">//发送HTTP请求</span></div><div class="line"> httpRequest.send(data);</div><div class="line">};</div><div class="line"><span class="comment">//实现GET请求</span></div><div class="line">ajax.get = <span class="function"><span class="keyword">function</span> (<span class="params">url, data, callback, async</span>) </span>{</div><div class="line"> <span class="keyword">var</span> query = [];</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> key <span class="keyword">in</span> data) {</div><div class="line"> query.push(<span class="built_in">encodeURIComponent</span>(key) + <span class="string">'='</span> + <span class="built_in">encodeURIComponent</span>(data[key]));</div><div class="line"> }</div><div class="line"> ajax.send(url + (query.length ? <span class="string">'?'</span> + query.join(<span class="string">'&'</span>) : <span class="string">''</span>), callback, <span class="string">'GET'</span>, <span class="literal">null</span>, <span class="keyword">async</span>)</div><div class="line">};</div><div class="line"><span class="comment">//实现POST请求</span></div><div class="line">ajax.post = <span class="function"><span class="keyword">function</span> (<span class="params">url, data, callback, async</span>) </span>{</div><div class="line"> <span class="keyword">var</span> query = [];</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> key <span class="keyword">in</span> data) {</div><div class="line"> query.push(<span class="built_in">encodeURIComponent</span>(key) + <span class="string">'='</span> + <span class="built_in">encodeURIComponent</span>(data[key]));</div><div class="line"> }</div><div class="line"> ajax.send(url, callback, <span class="string">'POST'</span>, query.join(<span class="string">'&'</span>), <span class="keyword">async</span>)</div><div class="line">};</div></pre></td></tr></table></figure>
<p>如果你使用jquery或是zepto很大部分是因为它的ajax兼容性高的缘故,不妨试试这个:<a href="https://github.com/damonare/ajax/tree/master" target="_blank" rel="external">damonare的ajax库</a>,喜欢给个star也是可以的。</p>
<h2 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h2><p>ajax技术对于整个web应用意义都是非凡的,仅以此篇致敬那些曾经奋斗在一线为了ajax技术的实现和普及做出工作的前辈们。</p>
<h3 id="参考文章"><a href="#参考文章" class="headerlink" title="参考文章"></a>参考文章</h3><ul>
<li><a href="http://www.cnblogs.com/SanMaoSpace/archive/2013/06/15/3137180.html" target="_blank" rel="external">Ajax工作原理记优缺点</a></li>
<li><a href="https://zh.wikipedia.org/wiki/AJAX" target="_blank" rel="external">Ajax</a></li>
</ul>
]]></content>
<summary type="html">
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p><strong>总括:</strong> 本文讲述了ajax的历史,工作原理以及优缺点,对XMLHttpRequest对象进行了详细的讲解,并使用原生js实现了一个ajax对象以方便日常开始使用。</p>
<ul>
<li><p>damonare的ajax库:<a href="https://github.com/damonare/ajax/tree/master" target="_blank" rel="external">damonare的ajax库</a></p>
</li>
<li><p>原文博客地址:<a href="https://damonare.github.io/2017/01/18/%E4%BD%A0%E7%9C%9F%E7%9A%84%E6%87%82ajax%E5%90%97%EF%BC%9F/#more">你真的懂ajax吗?</a></p>
</li>
<li>知乎专栏&amp;&amp;简书专题:<a href="https://zhuanlan.zhihu.com/damonare" target="_blank" rel="external">前端进击者(知乎)</a>&amp;&amp;<a href="http://www.jianshu.com/collection/bbaa63e264f5" target="_blank" rel="external">前端进击者(简书)</a></li>
<li>博主博客地址:<a href="http://damonare.cn" target="_blank" rel="external">Damonare的个人博客</a></li>
</ul>
<p><strong>古之立大事者,不惟有超世之才,亦必有坚忍不拔之志。</strong></p>
</summary>
<category term="学习" scheme="http://damonare.github.io/categories/learn/"/>
<category term="javascript" scheme="http://damonare.github.io/tags/javascript/"/>
</entry>
<entry>
<title>学习Javascript数据结构(四)——树</title>
<link href="http://damonare.github.io/2017/01/16/%E5%AD%A6%E4%B9%A0javascript%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%EF%BC%88%E5%9B%9B%EF%BC%89%E2%80%94%E2%80%94%E6%A0%91/"/>
<id>http://damonare.github.io/2017/01/16/学习javascript数据结构(四)——树/</id>
<published>2017-01-16T13:41:32.000Z</published>
<updated>2017-01-16T13:41:32.000Z</updated>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p><strong>总括:</strong> 本文讲解了数据结构中的[树]的概念,尽可能通俗易懂的解释树这种数据结构的概念,使用javascript实现了树,如有纰漏,欢迎批评指正。</p>
<ul>
<li>原文博客地址:<a href="https://damonare.github.io/2017/01/14/%E5%AD%A6%E4%B9%A0javascript%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%EF%BC%88%E5%9B%9B%EF%BC%89%E2%80%94%E2%80%94%E6%A0%91/#more">学习javascript数据结构(四)——树</a></li>
<li>知乎专栏&&简书专题:<a href="https://zhuanlan.zhihu.com/damonare" target="_blank" rel="external">前端进击者(知乎)</a>&&<a href="http://www.jianshu.com/collection/bbaa63e264f5" target="_blank" rel="external">前端进击者(简书)</a></li>
<li>博主博客地址:<a href="http://damonare.cn" target="_blank" rel="external">Damonare的个人博客</a></li>
</ul>
<p><strong>人之所能,不能兼备,弃其所短,取其所长。</strong></p>
<a id="more"></a>
<h2 id="正文"><a href="#正文" class="headerlink" title="正文"></a>正文</h2><h3 id="树简介"><a href="#树简介" class="headerlink" title="树简介"></a>树简介</h3><p>在上一篇<a href="http://damonare.github.io/2016/11/26/%E5%AD%A6%E4%B9%A0javascript%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%EF%BC%88%E4%B8%89%EF%BC%89%E2%80%94%E2%80%94%E9%9B%86%E5%90%88/#more">学习javascript数据结构(三)——集合</a>中我们说了集合这种数据结构,在<a href="http://damonare.github.io/2016/11/01/%E5%AD%A6%E4%B9%A0javascript%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%EF%BC%88%E4%B8%80%EF%BC%89%E2%80%94%E2%80%94%E6%A0%88%E5%92%8C%E9%98%9F%E5%88%97/#more">学习javascript数据结构(一)——栈和队列</a>和<a href="http://damonare.github.io/2016/11/09/%E5%AD%A6%E4%B9%A0javascript%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%EF%BC%88%E4%BA%8C%EF%BC%89%E2%80%94%E2%80%94%E9%93%BE%E8%A1%A8/#more">学习javascript数据结构(二)——链表</a>说了栈和队列以及链表这类线性表数据结构。接下来这一篇说的是<code>树</code>这种数据结构。首先想让大家明白的是数据结构是个什么玩意儿,数据结构可以分为数据的逻辑结构和数据的物理结构,所谓的数据逻辑结构在我理解就是计算机对于数据的组织方式的研究。也就是说研究的是数据和数据之间的关系。而数据的物理结构是数据的逻辑结构在计算机中的具体实现,也就是说一种逻辑结构可能会有多种存储结构与之相对应。</p>
<p>那么我们这一篇所说的<code>树</code>就是一种数据逻辑结构,即研究的是数据和数据之间的关系。之前所说的<code>栈</code>、<code>队列</code>、<code>链表</code>都是一种线性结构,相信大家也能发现这种线性结构的数据关系有一个共同点,就是数据都是一对一的,而上一篇说到的集合这种数据结构,数据是散乱的,他们之间的关系就是隶属于同一个集合,如上一篇例子所说,这些小孩子都是同一个幼儿园的,但是这些小孩子之间的关系我们并不知道。线性表(栈、队列、链表)就是对这些小孩子关系的一种表达(一对一)。而集合也是对于这些小孩子关系的一种表达。和线性表不同的是,树这种数据结构是一对多的,也就是说他所描述的是某个小孩子和其它小孩子之间的关系。</p>
<p>树这种结构实际上我们平时也有见到,比如下图这种简单的思维导图:</p>
<p><img src="http://7xsssj.com2.z0.glb.qiniucdn.com/4e4a20a4462309f7b9c58b78720e0cf3d7cad635.jpg" alt="思维导图"></p>
<p>如下也是一棵树:</p>
<p><img src="http://7xsssj.com2.z0.glb.qiniucdn.com/2009072216345191.jpg" alt="树"></p>
<p>关于树概念总结如下:</p>
<p> 1)树形结构是一对多的非线性结构。<br> 2)树形结构有树和二叉树两种,树的操作实现比较复杂,但树可以转换为二叉树进行处理。<br> 3)树的定义:树(Tree)是 n(n≥0)个相同类型的数据元素的有限集合。<br> 4)树中的数据元素叫节点(Node)。<br> 5)n=0 的树称为空树(Empty Tree);<br> 6)对于 n>0 的任意非空树 T 有:<br> (1)有且仅有一个特殊的节点称为树的根(Root)节点,根没有前驱节点;<br> (2)若n>1,则除根节点外,其余节点被分成了m(m>0)个互不相交的集合<br> T1,T2,。。。,Tm,其中每一个集合Ti(1≤i≤m)本身又是一棵树。树T1,T2,。。。,Tm称为这棵树的子树(Subtree)。<br> 7)树的定义是递归的,用树来定义树。因此,树(以及二叉树)的许多算法都使用了递归。 </p>
<p>参看维基百科对于<code>树</code>的定义:</p>
<blockquote>
<p>在计算机科学中,<strong>树</strong>(英语:tree)是一种<a href="https://zh.wikipedia.org/wiki/%E6%8A%BD%E8%B1%A1%E8%B3%87%E6%96%99%E5%9E%8B%E5%88%A5" target="_blank" rel="external">抽象数据类型</a>(ADT)或是实作这种抽象数据类型的<a href="https://zh.wikipedia.org/wiki/%E8%B3%87%E6%96%99%E7%B5%90%E6%A7%8B" target="_blank" rel="external">数据结构</a>,用来模拟具<a href="https://zh.wikipedia.org/wiki/%E6%A8%B9%E7%8B%80%E7%B5%90%E6%A7%8B" target="_blank" rel="external">有树状结构</a>性质的数据集合。它是由n(n>=1)个有限节点组成一个具有层次关系的<a href="https://zh.wikipedia.org/wiki/%E9%9B%86%E5%90%88" target="_blank" rel="external">集合</a>。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:</p>
<ul>
<li>每个节点有零个或多个子节点;</li>
<li>没有父节点的节点称为根节点;</li>
<li>每一个非根节点有且只有一个父节点;</li>
<li>除了根节点外,每个子节点可以分为多个不相交的子树;</li>
</ul>
</blockquote>
<p>树的种类:</p>
<blockquote>
<ul>
<li>无序树:树中任意节点的子节点之间没有顺序关系,这种树称为无序树,也称为<a href="https://zh.wikipedia.org/wiki/%E8%87%AA%E7%94%B1%E6%A0%91" target="_blank" rel="external">自由树</a>;</li>
<li>有序树:树中任意节点的子节点之间有顺序关系,这种树称为有序树;<ul>
<li><a href="https://zh.wikipedia.org/wiki/%E4%BA%8C%E5%8F%89%E6%A0%91" target="_blank" rel="external">二叉树</a>:每个节点最多含有两个子树的树称为二叉树;<a href="https://zh.wikipedia.org/wiki/%E5%AE%8C%E5%85%A8%E4%BA%8C%E5%8F%89%E6%A0%91" target="_blank" rel="external">完全二叉树</a>:对于一颗二叉树,假设其深度为d(d>1)。除了第d层外,其它各层的节点数目均已达最大值,且第d层所有节点从左向右连续地紧密排列,这样的二叉树被称为完全二叉树;<a href="https://zh.wikipedia.org/w/index.php?title=%E6%BB%A1%E4%BA%8C%E5%8F%89%E6%A0%91&action=edit&redlink=1" target="_blank" rel="external">满二叉树</a>:所有叶节点都在最底层的完全二叉树;<a href="https://zh.wikipedia.org/wiki/%E5%B9%B3%E8%A1%A1%E4%BA%8C%E5%8F%89%E6%A0%91" target="_blank" rel="external">平衡二叉树</a>(<a href="https://zh.wikipedia.org/wiki/AVL%E6%A0%91" target="_blank" rel="external">AVL树</a>):当且仅当任何节点的两棵子树的高度差不大于1的二叉树;<a href="https://zh.wikipedia.org/w/index.php?title=%E6%8E%92%E5%BA%8F%E4%BA%8C%E5%8F%89%E6%A0%91&action=edit&redlink=1" target="_blank" rel="external">排序二叉树</a>(二叉查找树(英语:Binary Search Tree),也称二叉搜索树、有序二叉树);</li>
<li><a href="https://zh.wikipedia.org/wiki/%E9%9C%8D%E5%A4%AB%E6%9B%BC%E6%A0%91" target="_blank" rel="external">霍夫曼树</a>:<a href="https://zh.wikipedia.org/w/index.php?title=%E5%B8%A6%E6%9D%83%E8%B7%AF%E5%BE%84&action=edit&redlink=1" target="_blank" rel="external">带权路径</a>最短的二叉树称为哈夫曼树或最优二叉树;</li>
<li><a href="https://zh.wikipedia.org/wiki/B%E6%A0%91" target="_blank" rel="external">B树</a>:一种对读写操作进行优化的自平衡的二叉查找树,能够保持数据有序,拥有多余两个子树。</li>
</ul>
</li>
</ul>
</blockquote>
<p>有关树的术语:</p>
<blockquote>
<ol>
<li><strong>节点的度</strong>:一个节点含有的子树的个数称为该节点的度;</li>
<li><strong>树的度</strong>:一棵树中,最大的节点的度称为树的度;</li>
<li><strong>叶节点</strong>或<strong>终端节点</strong>:度为零的节点;</li>
<li><strong>非终端节点</strong>或<strong>分支节点</strong>:度不为零的节点;</li>
<li><strong>父亲节点</strong>或<strong>父节点</strong>:若一个节点含有子节点,则这个节点称为其子节点的父节点;</li>
<li><strong>孩子节点</strong>或<strong>子节点</strong>:一个节点含有的子树的根节点称为该节点的子节点;</li>
<li><strong>兄弟节点</strong>:具有相同父节点的节点互称为兄弟节点;</li>
<li>节点的<strong>层次</strong>:从根开始定义起,根为第1层,根的子节点为第2层,以此类推;</li>
<li>树的<strong>高度</strong>或<strong>深度</strong>:树中节点的最大层次;</li>
<li><strong>堂兄弟节点</strong>:父节点在同一层的节点互为堂兄弟;</li>
<li><strong>节点的祖先</strong>:从根到该节点所经分支上的所有节点;</li>
<li><strong>子孙</strong>:以某节点为根的子树中任一节点都称为该节点的子孙。</li>
<li><strong>森林</strong>:由m(m>=0)棵互不相交的树的集合称为森林;</li>
</ol>
</blockquote>
<p>(我是维基百科搬运工,哈哈哈)</p>
<h3 id="二叉树"><a href="#二叉树" class="headerlink" title="二叉树"></a>二叉树</h3><blockquote>
<p> <strong>二叉树</strong>(英语:Binary tree)是每个节点最多有两个子树的<a href="https://zh.wikipedia.org/wiki/%E6%A0%91%E7%BB%93%E6%9E%84" target="_blank" rel="external">树结构</a>。通常子树被称作“左子树”(<em>left subtree</em>)和“右子树”(<em>right subtree</em>)。<a href="https://zh.wikipedia.org/wiki/%E4%BA%8C%E5%85%83%E6%A8%B9" target="_blank" rel="external">二叉树</a>常被用于实现<a href="https://zh.wikipedia.org/wiki/%E4%BA%8C%E5%85%83%E6%90%9C%E5%B0%8B%E6%A8%B9" target="_blank" rel="external">二叉查找树</a>和<a href="https://zh.wikipedia.org/wiki/%E4%BA%8C%E5%85%83%E5%A0%86%E7%A9%8D" target="_blank" rel="external">二元堆积</a>。</p>
</blockquote>
<p>我们主要研究的就是二叉树,也就是数据为一对二的关系。那么在二叉树中又有些分类;</p>
<p><img src="http://7xsssj.com2.z0.glb.qiniucdn.com/2329205432280906653.jpg" alt="二叉树"></p>
<p>二叉树分类:</p>
<ul>
<li>一棵深度为k,且有<img src="https://wikimedia.org/api/rest_v1/media/math/render/svg/f24729d4eae59094b7ed114e09dcbf142f32cde8" alt="{\displaystyle 2^{\begin{aligned}k+1\end{aligned}}-1}">个节点称之为<strong>满二叉树</strong>;</li>
<li>深度为k,有n个节点的<a href="https://zh.wikipedia.org/wiki/%E4%BA%8C%E5%85%83%E6%A8%B9" target="_blank" rel="external">二叉树</a>,当且仅当其每一个节点都与深度为k的<a href="https://zh.wikipedia.org/w/index.php?title=%E6%BB%BF%E4%BA%8C%E5%85%83%E6%A8%B9&action=edit&redlink=1" target="_blank" rel="external">满二叉树</a>中,序号为1至n的节点对应时,称之为<strong>完全二叉树</strong>。</li>
<li>平衡二叉树又被称为AVL树(区别于AVL算法),它是一棵二叉排序树,且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵<strong>平衡二叉树</strong>。</li>
</ul>
<h3 id="二叉树的遍历"><a href="#二叉树的遍历" class="headerlink" title="二叉树的遍历"></a>二叉树的遍历</h3><p>1)一棵二叉树由根结点、左子树和右子树三部分组成,<br>2) D、L、R 分别代表遍历根结点、遍历左子树、遍历右子树,则二叉树的<br>3) 遍历方式有6 种:DLR、DRL、LDR、LRD、RDL、RLD。先左或先右算法基本一样,所以就剩下三种DLR(先序或是前序)、LDR(中序)、LRD(后序)。</p>
<ul>
<li><strong>前序遍历</strong>:首先访问根节点,然后遍历左子树,最后遍历右子树,可记录为根—左—右;</li>
</ul>
<ul>
<li><strong>中序遍历</strong>:首先访问左子树,然后访问根节点,最后遍历右子树,可记录为左—根—右;</li>
</ul>
<ul>
<li><strong>后序遍历</strong>:首先遍历左子树,然后遍历右子树,最后遍历根节点,可记录为左—右—根。</li>
</ul>
<p><img src="http://7xsssj.com2.z0.glb.qiniucdn.com/BINTREE2.jpg" alt="二叉树的遍历"></p>
<p><img src="http://7xsssj.com2.z0.glb.qiniucdn.com/2017-01-16_173441.png" alt="二叉树遍历"></p>
<p>以上图1为例解释前序遍历:</p>
<p>首先访问根节点<code>a</code>=>然后遍历左子树<code>b</code>=>左子树<code>b</code>的左子树<code>d</code>=><code>d</code>的右孩子<code>e</code>>此时<code>b</code>的左子树遍历完,遍历<code>b</code>的右子树<code>f</code>=><code>f</code>的左孩子<code>g</code>=>左子树<code>b</code>遍历完,遍历根节点的右孩子<code>c</code>,完成=><code>abdefgc</code></p>
<p>中序遍历,后序遍历就不多说了,不同的只是访问的顺序。</p>
<p>注意:</p>