-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
2510 lines (2193 loc) · 151 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>FanWalker's blog</title>
<subtitle>成功,唯有积累,没有奇迹</subtitle>
<link href="/atom.xml" rel="self"/>
<link href="http://fanwalker.com/"/>
<updated>2017-11-18T07:42:23.416Z</updated>
<id>http://fanwalker.com/</id>
<author>
<name>FanWalker</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>高性能网站建设指南学习总结</title>
<link href="http://fanwalker.com/2017/10/30/%E9%AB%98%E6%80%A7%E8%83%BD%E7%BD%91%E7%AB%99%E5%BB%BA%E8%AE%BE%E5%AD%A6%E4%B9%A0/"/>
<id>http://fanwalker.com/2017/10/30/高性能网站建设学习/</id>
<published>2017-10-30T12:08:36.000Z</published>
<updated>2017-11-18T07:42:23.416Z</updated>
<content type="html"><![CDATA[<p>这篇总结是对高性能网站建设指南书籍做出的,以巩固所学知识。书中共介绍了14条提升性能的规则,在介绍这14条规则前,书本还提到了一种法则,叫做</p>
<p>性能黄金法则。</p>
<h2 id="性能黄金法则"><a href="#性能黄金法则" class="headerlink" title="性能黄金法则"></a>性能黄金法则</h2><p>只有10%~20%的最终用户响应时间花在了下载html文档上,其余的80%~90%时间花在了下载页面中的所有组件上。</p>
<h2 id="规则1—–-减少HTTP请求"><a href="#规则1—–-减少HTTP请求" class="headerlink" title="规则1—– 减少HTTP请求"></a>规则1—– 减少HTTP请求</h2><p>性能黄金法则中说到最终用户响应时间的80%~90%是花在HTML文档所引用的所有组件(图片、脚本、样式表、Flash等)的HTTP请求上,因此减少HTTP</p>
<p>请求数量是提升性能的最简单途径。减少HTTP请求的方法有:</p>
<a id="more"></a>
<h4 id="图片地图"><a href="#图片地图" class="headerlink" title="图片地图"></a>图片地图</h4><p>使用<strong>图片地图</strong>(Image Map)在一个图片上关联多个url,目标url的选择取决于用户点击了图片上的哪个位置,比如,本来五个图片关联五个url,现在将这五个</p>
<p>图片合并成一张图片上,这样就减少了四个HTTP请求。</p>
<p>缺点:</p>
<ul>
<li>手工很难定义图片地图上的区域坐标;</li>
<li>除了矩形之外几乎无法定义其他形状;</li>
<li>通过DHTML创建的图片地图在Internet Explorer中无法工作</li>
</ul>
<h4 id="CSS-Sprites"><a href="#CSS-Sprites" class="headerlink" title="CSS Sprites"></a>CSS Sprites</h4><p>CSS Sprites将多幅图片合并为一幅单独的图片,然后利用background-position进行定位显示特定图片,原理是借由减少下载图像文件数量,提高网页的显</p>
<p>示性能。</p>
<p>优点:</p>
<ul>
<li>通过合并图片减少HTTP请求,比图片地图更灵活,因为CSS Sprites没有限制图片必须是连续的;</li>
<li>降低了下载量,合并的图片比分离的图片的总和要小,因为它降低了图片自身的开销(颜色表、格式信息、等等);</li>
</ul>
<p>缺点:</p>
<ul>
<li>后期修改麻烦,难以维护,牵一发动全身,没有之前改一个图片就好了容易</li>
</ul>
<h4 id="内联图片(Inline-Images)"><a href="#内联图片(Inline-Images)" class="headerlink" title="内联图片(Inline Images)"></a>内联图片(Inline Images)</h4><p>通过使用 <code>data:url</code> 模式 是web页面中包含图片,无需额外的HTTP请求。但Internet Explorer不支持这种方式。</p>
<blockquote>
<p>格式: <code>data:[<mediatype][;base64],<data></code></p>
<p>一般的写法:<code><img src="http://blog.xmaoseo.com/images/xmaoseo.jpg"/></code></p>
<p>内联图片写法: <code><img src="data:image/png;base64,iVBOR....></code></p>
</blockquote>
<p>这里的<code>iVBOR....</code>是base64编码,还有<code>data:url</code>模式的缺陷是IE不支持,另一个可能存在数据大小上的限制,Firefox1.5可以支持高达100kb的内联图片。<br>Base64编码会增加图片的大小,因此整体下载量会增加。</p>
<p>这种模式下,在跨越不同页面时不会被缓存,不要去内联较大的图片,因为编码后会导致页面变大。好的做法是使用CSS并将内联图片作为背景。将该<br>CSS规则放在外部样式表中,数据可以缓存在样式表内部</p>
<p>使用PHP函数可以获取图片的base64编码,例子:</p>
<pre><code>.home{background-image: url(data:image/gif;base64,
<?php echo base64_encode(file_get_contents("../image/home.gif")) ?>)}
</code></pre><h4 id="合并脚本和样式表"><a href="#合并脚本和样式表" class="headerlink" title="合并脚本和样式表"></a>合并脚本和样式表</h4><p>根据模块化原则, 我们应该将代码放到多个小文件中,但是这样会降低性能,因为每个文件都会导致一个额外的http请求。理想情况,一个页面不应该使用</p>
<p>多余一个的脚本和样式表。建议多个脚本合并为一个脚本,多个样式表也应该合并为一个样式表。</p>
<h2 id="规则2-—–-使用内容发布网络-(Use-a-Content-Delivery-Network)"><a href="#规则2-—–-使用内容发布网络-(Use-a-Content-Delivery-Network)" class="headerlink" title="规则2 —– 使用内容发布网络 (Use a Content Delivery Network)"></a>规则2 —– 使用内容发布网络 (Use a Content Delivery Network)</h2><p>内容分发网络(conten delivery network)是一组分布在多个不同地理位置的Web服务器。用于更加有效地向用户发布网络。</p>
<p>CDN优点:</p>
<blockquote>
<p>缩短相应时间,备份扩展存储能力和进行缓存,缓和WEB流量峰值压力(获取天气,娱乐体育新闻等等)</p>
</blockquote>
<p>CDN缺点:</p>
<blockquote>
<p>你的响应时间会受到其他网站——甚至是竞争对手的流量的影响。无法控制组件服务器所带来的特殊麻烦。比如,修改HHTP表头必须由服务提供商来完成。</p>
</blockquote>
<p>CDN用于发布静态图片(将所有静态组件转移到CDN),图片,脚本样式表,Flash,静态文件更易存储,有较少的依赖性。</p>
<h2 id="规则3-—–-添加Expires头"><a href="#规则3-—–-添加Expires头" class="headerlink" title="规则3 —– 添加Expires头"></a>规则3 —– 添加Expires头</h2><p>web页面都包含了大量的组件,并且其数量在不断增长,页面的初访者会进行很多HTTP请求,但通过使用一个长久的Expires头,可以使这些组件被缓存。</p>
<p>这会在后续的页面浏览中避免不必要的HTTP请求。长久的Expires头常用于图片,但应将其用在包括脚本、样式表和Flash等所有组件上。</p>
<h4 id="Expires头"><a href="#Expires头" class="headerlink" title="Expires头"></a>Expires头</h4><p>Web服务器使用Expires头来告诉web客服端它可以使用一个组件的当前副本,直到指定的时间为止。例子:</p>
<pre><code>Expires: Mon, 15 Apr 2024 20:00:00 GMT
</code></pre><p>它告诉浏览器该响应的有效期持续到2024年4月15日为止。</p>
<h4 id="Max-Age-和-mod-expires"><a href="#Max-Age-和-mod-expires" class="headerlink" title="Max-Age 和 mod_expires"></a>Max-Age 和 mod_expires</h4><p>Expires头的使用要求服务器和客户端的时钟要严格同步,另外,过期日期需要经常检查,并且一旦未来这一天到来了,还需要在服务器配置中提供一个新的<br>日期。HTTP1.1引入了Cache-Control头来克服这个限制。</p>
<p>Cache-Control使用max-age指令指定组件被缓存多久。以秒为单位定义一个更新窗。</p>
<p>Expires和Cache-Control max-age两者同时出现,max-age指令将重写Expires头。</p>
<p>mod_expires Apache模块可以使你通过ExpirsDefault指令以相对方式设置日期。</p>
<blockquote>
<p>ExpirsDefault ‘access plus 10 years’</p>
</blockquote>
<p>时间可以设置为年月日时分秒。它同时向响应中发送Expires头和max-age头。实际过期日期根据何时得到请求而变,但是max-age有优先权。时钟同步问题<br>和固定日期更新不用担心了。</p>
<h4 id="空缓存vs完整缓存"><a href="#空缓存vs完整缓存" class="headerlink" title="空缓存vs完整缓存"></a>空缓存vs完整缓存</h4><p>用户第一次访问你的网站时,它不会对HTTP请求的熟练产生任何影响。此时浏览器的缓存是空的。因此,其性能的改进取决于用户在访问你的页面时是否有<br>完整的缓存,使你的组件可缓存可以改善这些用户的响应时间。</p>
<p>在那些每日一次一更新的网站,带有完整缓存的页面浏览百分比很少。旅游网站,email网站中每个用户会话可能产生多次页面浏览,百分比就高。<br>只要用户每个月至少访问一次,或者每次会话产生多次页面浏览,完整缓存就很有用,使用长久Expires就很有必要。</p>
<h4 id="不仅仅是图片"><a href="#不仅仅是图片" class="headerlink" title="不仅仅是图片"></a>不仅仅是图片</h4><p>为图片使用长久的Expires头非常之普遍,但不仅限于图片,长久的Expires头应该包含任何不经常变化的组件,包括脚本、样式表和Flash组件。但是HTML<br>文档不应该使用,因为包含动态内容,每次都要更新。</p>
<p>大型网站,图片,样式表,脚本大部分都要缓存30天以上。但是经常需要变化的新闻图片等等,不应该使用。我们可以查看Last-Modifed中的值来看改变时<br>间以及频率。</p>
<h4 id="修订文件名"><a href="#修订文件名" class="headerlink" title="修订文件名"></a>修订文件名</h4><blockquote>
<p>使用长久的Expires缺点是 :浏览器不会检查任何更新,直到过了过期日期。即使在服务器上更新了组件,浏览器因为缓存也不能获得最新组件。</p>
</blockquote>
<p>为了确保用户能获得更新过的组件,需要在所有HTML页面中修改组件的文件名。最有效的解决方案是修改其所有链接,这样。全新的请求将从原始服务器<br>下载最新的内容。</p>
<p>使用php等动态语言生成HTML页将很简单,为所有组件的文件名使用变量,使用这种方法,在页面中更新文件名只需要简单地在某个地方修改变量。Yahoo<br>经常将这一步作为生成过程的一部分——版本号嵌入在组件的文件名中(例如yahoo_2.0.6.js),而且在全局映射中修订过的文件名会自动更新。嵌入版本<br>号不仅可以改变文件名,还能在调试中更容易找到准确的源代码文件。</p>
<h2 id="规则4-—–-压缩组件"><a href="#规则4-—–-压缩组件" class="headerlink" title="规则4 —– 压缩组件"></a>规则4 —– 压缩组件</h2><p>规则1–3都是限制不必要的HTTP请求来减少响应时间,现在我们通过减少响应大小来减少响应时间。</p>
<h4 id="压缩是如何工作的"><a href="#压缩是如何工作的" class="headerlink" title="压缩是如何工作的"></a>压缩是如何工作的</h4><p>Web客户端可以通过HTTP请求中的Accept-Encoding头来表示对压缩的支持</p>
<blockquote>
<p>Accept-Encoding: gzip,deflate</p>
</blockquote>
<p>Web服务器看到请求中有这个头,就会使用客户端列出来的方法中的一种来压缩响应。Web服务器通过响应中的Content-Encoding头来通知Web客户端</p>
<blockquote>
<p>Content-Encoding: gzip</p>
</blockquote>
<p>gzip是目前最有效,最流行的压缩方法,免费模式,并被标准化为RFC 1952.(90%使用)</p>
<h4 id="压缩什么"><a href="#压缩什么" class="headerlink" title="压缩什么"></a>压缩什么</h4><p>很多网站会压缩HTML文档,值得压缩的内容包括脚本、样式表、XML和JSON在内的任何文本响应。图片和PDF不应该解压缩,因为已经被压缩了。再压缩<br>只会浪费CPU资源,还有可能会增加文件大小。</p>
<p>压缩的成本:服务器会花费额外的CPU周期来完成压缩,客户端要对压缩文件进行解压缩。要检测受益是否大于开销,需要考虑响应的大小,连接的带宽和<br>客户端服务器之间的Internet距离。</p>
<p>根据经验,通常对大于1KB或2KB的文件进行压缩。mod_gzip_minimum_file_size指令控制着希望压缩文件的最小值,默认值是500B。</p>
<h4 id="节省"><a href="#节省" class="headerlink" title="节省"></a>节省</h4><p>压缩之后能将响应数据量减少将近70%</p>
<h2 id="规则5-—–-将样式表放在顶部"><a href="#规则5-—–-将样式表放在顶部" class="headerlink" title="规则5 —– 将样式表放在顶部"></a>规则5 —– 将样式表放在顶部</h2><p>使用link标签将样式表放在文档head中</p>
<h4 id="白屏"><a href="#白屏" class="headerlink" title="白屏"></a>白屏</h4><p>将样式表放在文档底部会导致在浏览器中阻止内容逐步呈现。为避免当样式变化时重绘页面中的元素,浏览器会阻塞内容逐步呈现。在浏览器和用户等待位<br>于底部的样式表时,浏览器会延迟显示任何可视化组件,这一现象称为“白屏”</p>
<p>它只发生在Internet Explorer中,并且依赖于页面是如何加载的。当发生这种现象时,页面会完全空白,直到页面的所有内容同时涌上屏幕。</p>
<p>白屏现象源自于浏览器的行为</p>
<h4 id="无样式内容的闪烁(Flash-of-Unstyled-Content)"><a href="#无样式内容的闪烁(Flash-of-Unstyled-Content)" class="headerlink" title="无样式内容的闪烁(Flash of Unstyled Content)"></a>无样式内容的闪烁(Flash of Unstyled Content)</h4><p>无样式内容的闪烁简称FOUC,当样式被放在了底部,页面逐步加载时,文字首先显示,然后是图片,最后样式表被正确地下载并解析之后,已经呈现的文<br>字和图片要用新的样式重绘,这就是“无样式内容的闪烁”。</p>
<p>白屏是对FOUC问题的弥补,浏览器可以延迟呈现,直到所有的样式表都下载完成后,这就导致了白屏,反之,浏览器可以逐步呈现,但要承担闪烁的风险。</p>
<p>使用样式表时,页面逐步呈现会被阻止,直到所有样式表下载完成后,这就是将样式表移动文档HEAD中的原因。</p>
<h2 id="规则6-—–-将脚本放在底部"><a href="#规则6-—–-将脚本放在底部" class="headerlink" title="规则6 —– 将脚本放在底部"></a>规则6 —– 将脚本放在底部</h2><p>在使用脚本时,在脚本以下的内容,逐步呈现都被阻塞了。将脚本放在页面越靠下的地方,意味着越多的内容能够逐步呈现</p>
<p>脚本阻塞并行下载的原因:</p>
<ul>
<li>脚本可能使用doucument.write来修改页面内容,因此浏览器会等待,以确保页面能够恰当地布局;</li>
<li>保证脚本能够按照正确的顺序执行,如果脚本之间有依赖关系,不按照执行顺序会导致JavaScript错误</li>
</ul>
<h2 id="规则7-—–-避免CSS表达式"><a href="#规则7-—–-避免CSS表达式" class="headerlink" title="规则7 —– 避免CSS表达式"></a>规则7 —– 避免CSS表达式</h2><p>css表达式 expression方法被其他浏览器忽略,IE支持,这种方法虽然强大但是非常危险。<br>表达式求之的频率远高于人们的期望,不仅在页面呈现和大小改变时求值,鼠标拖拽,页面滚动时候都会求值。所以要避开css表达式,用事件处理器来为特定的事件提供所期望的动态行为。</p>
<h2 id="规则8-—–-使用外部JavaScript和CSS"><a href="#规则8-—–-使用外部JavaScript和CSS" class="headerlink" title="规则8 —– 使用外部JavaScript和CSS"></a>规则8 —– 使用外部JavaScript和CSS</h2><p>纯粹而言,内联JavaScript和CSS是比外置更快一些,因为外置的示例需要承担多个HTTP请求带来的开销。</p>
<h4 id="页面浏览量"><a href="#页面浏览量" class="headerlink" title="页面浏览量"></a>页面浏览量</h4><p>页面浏览量越多,外置实例越有优势,因为浏览器会缓存外部文件,这样就减少了HTTP请求,反之则内联更好</p>
<h4 id="组件重用"><a href="#组件重用" class="headerlink" title="组件重用"></a>组件重用</h4><p>如果使用相同的JavaScript和CSS,外部文件可以提高这些组件的重用率</p>
<h2 id="减少DNS查找"><a href="#减少DNS查找" class="headerlink" title="减少DNS查找"></a>减少DNS查找</h2><p>DNS的开销:通常浏览器查找一个给定主机名的IP地址要话费20-120毫秒,在DNS查找完成前,浏览器不能从主机名那里下载到任何东西,响应时间依赖于<br>DNS解析器(通常有你的ISP提供)、它所承担的请求压力、你与它之间的距离和你的带宽速度。</p>
<h4 id="DNS缓存和TTL"><a href="#DNS缓存和TTL" class="headerlink" title="DNS缓存和TTL"></a>DNS缓存和TTL</h4><p>DNS查找可以被你的ISP或局域网中一台特殊的缓存服务器、用户计算机缓存起来,用户请求了一个主机名后,DNS信息会留在操作系统的DNS缓存中。<br>浏览器也拥有其缓存,和操作系统的缓存分离,DNS的查找顺序是:浏览器 ——> 操作系统 ——> 远程服务器</p>
<p>TTL(Time to live):存活时间,服务器返回的DNS记录包含了一个存活时间,告诉客户端可以对该记录缓存多久</p>
<p>在HTTP请求中使用 Connection:keep-alive 来保持持久连接,持久连接的引入使得浏览器可以在一个单独的连接上进行多个请求,从而减少DNS查找。</p>
<h2 id="规则10-—–-精简JavaScript"><a href="#规则10-—–-精简JavaScript" class="headerlink" title="规则10 —– 精简JavaScript"></a>规则10 —– 精简JavaScript</h2><h4 id="精简"><a href="#精简" class="headerlink" title="精简"></a>精简</h4><p>从代码中减少不必要的字符包括空白字符、注释来减小js文件的大小,进而改善加载时间</p>
<h4 id="混淆"><a href="#混淆" class="headerlink" title="混淆"></a>混淆</h4><p>混淆是可以应用在源代码上的另外一种优化方式,和精简一样,也会移除注释和空白,作为改写的一部分,函数和变量的名字将被转换为更短的字符串。</p>
<ul>
<li>缺陷:混淆更加复杂,混淆过程本身很有可能引入错误。</li>
<li>维护: 由于混淆会改变js符号,因此需要对任何不能改变的符号(例如API函数)进行标记,防止混淆修改他们。</li>
<li>调试:很难阅读,调试更加困难。</li>
</ul>
<p>实际经过gzip压缩之后,精简和混淆差别很小。精简脚本可以降低响应时间,但不会带来混淆的风险。</p>
<h4 id="精简css"><a href="#精简css" class="headerlink" title="精简css"></a>精简css</h4><p>精简css带来的节省通常小于js,因为注释和空白比较少。最大的潜在节省来自于优化css——合并相同的类,移除不使用的类等。css依赖顺序的本质(成为层<br>叠样式表的原因)决定了这是一个复杂的问题。这个领域还需要进一步的研究和工具开发。</p>
<p>通常解决方案有使用颜色缩写,用“0”代替“0px”,用“#606”代替“#660066”。</p>
<h2 id="规则11-—–-避免重定向"><a href="#规则11-—–-避免重定向" class="headerlink" title="规则11 —– 避免重定向"></a>规则11 —– 避免重定向</h2><p>重定向用于将用户从一个URL重新路由到另一个URL,最常见的重定向为301和302,html文档、图片、脚本、样式表等都可以进行重定向,重定向会使你的<br>页面变慢。</p>
<p>重定向原因:</p>
<ul>
<li>网站重新设计</li>
<li>跟踪流量</li>
<li>记录广告点击</li>
<li>建立易于记忆的URL</li>
</ul>
<h4 id="重定向类型"><a href="#重定向类型" class="headerlink" title="重定向类型"></a>重定向类型</h4><p>web服务器向浏览器返回一个重定向时,响应中会有一个范围在3xx的状态码。</p>
<p>document.location可以设置期望的url实现重定向,还有meta refresh标签可以在content属性所指定的描述之后重定向用户-</p>
<pre><code><meta http-equiv="refresh" content="0";url=http://stevesouders.com/newuri">
</code></pre><h4 id="重定向如何损伤性能"><a href="#重定向如何损伤性能" class="headerlink" title="重定向如何损伤性能"></a>重定向如何损伤性能</h4><p>重定向延迟了整个HTML文档的传输,在HTML文档到达之前,页面中不会呈现出任何东西,也没有任何组件会被下载。</p>
<h4 id="重定向之外的其他选择"><a href="#重定向之外的其他选择" class="headerlink" title="重定向之外的其他选择"></a>重定向之外的其他选择</h4><ol>
<li>缺少结尾的斜线/:这是最为浪费和频繁的,也是web开发人员没注意的。没有/时会导致301响应,这是很多web服务器的默认行为,所以很简单,url后面加一个/</li>
<li>跟踪内部流量:分析离开网页首页之后的流量去向。使用referer。难处在于只能分析内部,自己公司的,如果目标网站属于其他公司则不可能分析referer日志了。</li>
<li>跟踪出站流量:用信标(beacon)——一个hppt请求,其URL中包含有跟踪信息。跟踪信息可以从信标web服务器的访问日志中提取出来。</li>
</ol>
<h2 id="规则12-—–-删除重复的脚本"><a href="#规则12-—–-删除重复的脚本" class="headerlink" title="规则12 —– 删除重复的脚本"></a>规则12 —– 删除重复的脚本</h2><p>来自不同团队的很多人都要向页面中添加HTML,有可能相同的脚本会被添加两次。</p>
<h4 id="重复脚本危害"><a href="#重复脚本危害" class="headerlink" title="重复脚本危害"></a>重复脚本危害</h4><p>不必要的HTTP请求和执行JavaScript所浪费的时间。</p>
<h2 id="规则13-—–-配置ETag"><a href="#规则13-—–-配置ETag" class="headerlink" title="规则13 —– 配置ETag"></a>规则13 —– 配置ETag</h2><p>ETag(Entity Tag)是Web服务器和浏览器用于确认缓存组件有效性的一种机制。ETag是一个字符串,它唯一标识了一个组件的特定版本。</p>
<p>原始服务器使用ETag响应头来指定组件的ETag,第一次请求:</p>
<pre><code>//请求:
GET /i/xx.jpg HTTP 1.1
HOST www.xxx.com
//响应:
HTTP 1.1 20 OK
Last-Modified:true .12 dec 2015 03:03:09 GMT
ETag:"10c34ba-8ba-abds3b3"
Content-Length:1024
</code></pre><p>第二次请求,验证组件是否有效,会使用If-None-Match头将ETag传回原始服务器。</p>
<pre><code>//请求:
GET /i/xx.jpg HTTP 1.1
HOST www.xxx.com
If-Modified-Since:True,12 dec 2015 03:03:09 GMT
If-None-Match:"10c34ba-8ba-abds3b3"
//响应:
HTTP 1.1 304 not modifed
</code></pre><h4 id="ETag带来的问题"><a href="#ETag带来的问题" class="headerlink" title="ETag带来的问题"></a>ETag带来的问题</h4><p>对于使用服务器集群来处理请求的网站,匹配次数会大大降低。此时etag就降低了缓存效率,导致了不必要的请求。If-None-Match的优先级比If-Modified-Since的优先级更高。</p>
<h4 id="ETag的使用"><a href="#ETag的使用" class="headerlink" title="ETag的使用"></a>ETag的使用</h4><p>一种选择对ETag进行配置,以利用其灵活的验证能力,可以使用php等脚本语言配置ETag头。</p>
<p>如果你的组件必须通过最新修改日期之外的一些东西来验证,使用ETag。</p>
<p>你还可以将ETag头安全移除在apache配置文件中,减少它的坏处。<br>从ETag中移除ChangeNumber或者完全移除ETag可以避免当数据已经位于浏览器缓存中时进行不必要的和低效的下载。</p>
<h2 id="规则14-—–-使Ajax可缓存"><a href="#规则14-—–-使Ajax可缓存" class="headerlink" title="规则14 —– 使Ajax可缓存"></a>规则14 —– 使Ajax可缓存</h2><blockquote>
<p>被动Ajax请求:是为了将来使用而预先发起的。</p>
<p>主动Ajax请求:基于用户当前的操作而引起的。</p>
</blockquote>
<p>主动请求对用户体验的影响更大,改善这些主动Ajax请求最重要的方式就是使响应可缓存。</p>
<p>使用一个长久的Expires头,将响应的个性化和动态本质反映到缓存中(可供采用的最好方式是使用查询字符串参数)</p>
<p>有的响应中因为数据隐私原因而不能缓存,当数据被认为是私有的时候,大多会在响应中使用 <code>Cache-Control:no-store</code>。<br>处理数据隐私的更好方法是使用安全通信协议如安全套接字层(Secure Socket Layer,SSL)。SSL响应式可以缓存的。</p>
<p><strong>到此高性能建站建设学习指南14大规则基本总结完</strong></p>
]]></content>
<summary type="html">
<p>这篇总结是对高性能网站建设指南书籍做出的,以巩固所学知识。书中共介绍了14条提升性能的规则,在介绍这14条规则前,书本还提到了一种法则,叫做</p>
<p>性能黄金法则。</p>
<h2 id="性能黄金法则"><a href="#性能黄金法则" class="headerlink" title="性能黄金法则"></a>性能黄金法则</h2><p>只有10%~20%的最终用户响应时间花在了下载html文档上,其余的80%~90%时间花在了下载页面中的所有组件上。</p>
<h2 id="规则1—–-减少HTTP请求"><a href="#规则1—–-减少HTTP请求" class="headerlink" title="规则1—– 减少HTTP请求"></a>规则1—– 减少HTTP请求</h2><p>性能黄金法则中说到最终用户响应时间的80%~90%是花在HTML文档所引用的所有组件(图片、脚本、样式表、Flash等)的HTTP请求上,因此减少HTTP</p>
<p>请求数量是提升性能的最简单途径。减少HTTP请求的方法有:</p>
</summary>
</entry>
<entry>
<title>JavaScript之正则表达式</title>
<link href="http://fanwalker.com/2017/10/21/JavaScript%E4%B9%8B%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F/"/>
<id>http://fanwalker.com/2017/10/21/JavaScript之正则表达式/</id>
<published>2017-10-21T14:33:11.000Z</published>
<updated>2017-11-18T08:19:52.336Z</updated>
<content type="html"><![CDATA[<p>正则表达式(英语:Regular Expression,在代码中常简写为regex、regexp或RE)使用单个字符串来描述、匹配一系列符合某个句法规则的字符串搜索模式。</p>
<h3 id="语法"><a href="#语法" class="headerlink" title="语法"></a>语法</h3><pre><code>/正则表达式主体/修饰符(可选)
</code></pre><p>实例:</p>
<pre><code>var patt = /runoob/i
</code></pre><p>/runoob/i 是一个正则表达式。runoob 是一个正则表达式主体 (用于检索)。i 是一个修饰符 (表示搜索不区分大小写)。</p>
<a id="more"></a>
<h3 id="创建一个正则表达式"><a href="#创建一个正则表达式" class="headerlink" title="创建一个正则表达式"></a>创建一个正则表达式</h3><p>1、使用一个正则表达式字面量:</p>
<pre><code>/*
pattern/flags
*/
const regex = /ab+c/;
const regex = /^[a-zA-Z]+[0-9]*\W?_$/gi;/
</code></pre><p>在加载脚本后,正则表达式字面值提供正则表达式的编译。当正则表达式保持不变时,使用此方法可获得更好的性能。</p>
<p>2、调用RegExp对象的构造函数:</p>
<pre><code>/*
new RegExp(pattern , modifiers)
//pattern(模式) 描述了表达式的模式,modifiers(修饰符) 用于指定全局匹配、区分大小写的匹配和多行匹配
*/
let regex = new RegExp("ab+c");
let regex = new RegExp(/^[a-zA-Z]+[0-9]*\W?_$/, "gi");
let regex = new RegExp("^[a-zA-Z]+[0-9]*\\W?_$", "gi"); //注意:当使用构造函数创造正则对象时,需要常规的字符转义规则(在前面加反斜杠 \)
</code></pre><h3 id="编写一个正则表达式的模式"><a href="#编写一个正则表达式的模式" class="headerlink" title="编写一个正则表达式的模式"></a>编写一个正则表达式的模式</h3><h4 id="使用简单的模式"><a href="#使用简单的模式" class="headerlink" title="使用简单的模式"></a>使用简单的模式</h4><p>简单的模式是由简单字符串所构成的。比如,/abc/这个模式就匹配了在一个字符串中,仅仅字符 ‘abc’ 同时出现并按照这个顺序。</p>
<h4 id="使用特殊字符"><a href="#使用特殊字符" class="headerlink" title="使用特殊字符"></a>使用特殊字符</h4><p>当你需要搜索一个比直接匹配需要更多条件的匹配时,比如寻找一个或多个 ‘b’,或者寻找空格,那么这时模式将要包含特殊字符。比如, 模式/ab*c/匹配了</p>
<p>一个单独的 ‘a’ 后面跟了零个或者多个 ‘b’(*的意思是前面一项出现了零个或者多个),且后面跟着 ‘c’ 的任何字符组合。在字符串 “cbbabbbbcdebc” 中,这</p>
<p>个模式匹配了子字符串 “abbbbc”。</p>
<h4 id="使用正则表达式"><a href="#使用正则表达式" class="headerlink" title="使用正则表达式"></a>使用正则表达式</h4><p>正则表达式可以被用于RegExp的exec和test方法以及 String的match、replace、search和split方法。</p>
<p>exec():搜索符合规则的内容,并返回内容,格式为数组。</p>
<pre><code>var testStr = "now test001 test002";
var re = /test(\d+)/; //只匹配一次
var r = "";
var r = re.exec(testStr)
alert(r);// test001 001 返回匹配结果,以及子项
alert(r.length); //2 返回内容的长度
alert(r.input); //now test001 test002 代表每次匹配成功的字符串
alert(r[0]); //test001
alert(r[1]); //001 代表每次匹配成功字符串中的第一个子项 (\d+)
alert(r.index ); // 4 每次匹配成功的字符串中的第一个字符的位置
</code></pre><p>全局匹配,可以通过while循环 找到每次匹配到的字符串,以及子项。每次匹配都接着上次的位置开始匹配:</p>
<pre><code> var testStr = "now test001 test002";
var re = /test(\d+)/g;
var r = "";
//匹配两次 每次匹配都接着上一次的位置开始匹配,一直匹配到最后r就为false,就停止匹配了 匹配到test001 test002
while(r = re.exec(testStr)){
alert(r);//返回每次匹配成功的字符串,以及子项,分别弹出 :test001 001,test002 002
alert(r.input); //分别弹出: now test001 test002 now test001 test002
alert(r[0]); //代表每次匹配成功的字符串 分别弹出: test001 test002
alert(r[1]); //代表每次匹配成功字符串中的第一个子项 (\d+) 分别弹出:001 002
alert(r.index ); // 每次匹配成功的字符串中的第一个字符的位置,分别弹出:4 12
alert(r.length); //分别弹出:2 2
}
</code></pre><p>test() :在字符串中查找符合正则的内容,若查找到返回true,反之返回false。</p>
<pre><code>var str = '374829348791';
var re = /\D/; // \D代表非数字
if( re.test(str) ){ // 返回true,代表在字符串中找到了非数字。
alert('不全是数字');
}else{
alert('全是数字');
}
</code></pre><p>match():在字符串中搜索复合规则的内容,搜索成功就返回内容,格式为数组,失败就返回null。</p>
<pre><code>var str = 'abc';
var re = /(a)(b)(c)/;
alert( str.match(re) ); //[abc,a,b,c]( 返回的是匹配结果 以及每个子项 当match不加g的时候才可以获取到子项的集合)
</code></pre><p>replace():查找符合正则的字符串,替换掉匹配的子字符串。返回替换后的内容。</p>
<pre><code>var str = "我爱北京天安门,天安门上太阳升。";
var re = /北京|天安门/g; // 找到北京 或者天安门 全局匹配
var str2 = str.replace(re,'*');
alert(str2) //我爱**,*上太阳升
</code></pre><p>search():在字符串搜索符合正则的内容,搜索到就返回出现的位置(从0开始,如果匹配的不只是一个字母,那只会返回第一个字母的位置),如果搜索失败就返回 -1 </p>
<pre><code>var str = 'abcdef';
var re = /B/i;
//var re = new RegExp('B','i'); 也可以这样写
alert( str.search(re) ); // 1
</code></pre><h4 id="正则表达式中的特殊字符"><a href="#正则表达式中的特殊字符" class="headerlink" title="正则表达式中的特殊字符"></a>正则表达式中的特殊字符</h4><pre><code>[] : 表示某个集合中的任意一个,比如 [abc] 整体代表一个字符 匹配 a b c 中的任意一个,也可以是范围,[0-9] 范围必须从小到大 。
[^a] :^写在[]里面的话,就代表排除的意思
\s : 空格
\S : 非空格
\d : 数字
\D : 非数字
\w : 字符 ( 字母 ,数字,下划线_ )
\W : 非字符
. : 任意字符
\. : 真正的点
\b : 匹配一个词的边界,独立的部分 ( 起始,结束,空格 ),如:/\bm/匹配“moon”中得‘m’,/oo\b/并不匹配"moon"中得'oo',因为'oo'被一个词汇字符'n'紧跟着。
\B : 非独立的部分
\a : 表示重复的某个子项。比如:\1 : 重复的第一个子项;\2 : 重复的第二个子项。
</code></pre><p>例子(笔试题经常出现):找重复项最多的字符个数</p>
<pre><code>var str = 'assssjdssskssalsssdkjsssdss';
var arr = str.split(''); //把字符串转换为数组
str = arr.sort().join(''); //首先进行排序,这样结果会把相同的字符放在一起,然后再转换为字符串
//alert(str); // aaddjjkklsssssssssssssssss
var value = '';
var index = 0;
var re = /(\w)\1+/g; //匹配字符,且重复这个字符,重复次数至少一次。
str.replace(re,function($0,$1){
console.log($0); //代表每次匹配成功的结果 : aa dd jj kk l sssssssssssssssss
//alert($1); 代表每次匹配成功的第一个子项,也就是\w: a d j k l S
if(index<$0.length){ //如果index保存的值小于$0的长度就进行下面的操作
index = $0.length; // 这样index一直保存的就在最大的长度
value = $1; //value保存的是出现最多的这个字符
}
});
console.log('最多的字符:'+value+',重复的次数:'+index); // s 17
</code></pre><h5 id="量词:代表出现的次数"><a href="#量词:代表出现的次数" class="headerlink" title="量词:代表出现的次数"></a>量词:代表出现的次数</h5><pre><code>{n,m}:至少出现n次,最多m次
{n,} :至少n次
* :任意次 相当于{0,}
? :零次或一次 相当于{0,1}
+ :一次或任意次相当于 {1,}
{n} :正好n次
^ :放在正则的最开始位置,就代表起始的意思,注意 /[^a] / 和 /^[a]/是不一样的,前者是排除的意思,后者是代表首位。
$ :正则的最后位置 , 就代表结束的意思
</code></pre><p>例子:判断是不是QQ号</p>
<pre><code>/*首先想QQ号的规则
1 首位不能是0
2 必须是 5-12位的数字
*/
var aInput = document.getElementsByTagName('input');
var re = /^[1-9]\d{4,11}$/;
//123456abc为了防止出现这样的情况,所以必须限制最后
//首位是0-9,接着是4-11位的数字类型。
aInput[1].onclick = function(){
if( re.test(aInput[0].value) ){
alert('是QQ号');
}else{
alert('不是QQ号');
}
};
</code></pre><p>例子:去掉前后空格</p>
<pre><code>var str = ' hello ';
alert( '('+trim(str)+')' );//为了看出区别所以加的括号。 (hello)
function trim(str){
var re = /^\s+|\s+$/g; // |代表或者 \s代表空格 +至少一个 前面有至少一个空格 或者后面有至少一个空格 且全局匹配
return str.replace(re,''); //把空格替换成空
}
</code></pre><h4 id="常用的一些表单校验"><a href="#常用的一些表单校验" class="headerlink" title="常用的一些表单校验"></a>常用的一些表单校验</h4><pre><code>匹配中文:[\u4e00-\u9fa5] //中文ACALL码的范围
行首行尾空格:^\s*|\s*$ //首行出现任意个空格或者尾行出现任意个空格(任意表示也可以没有空格)
Email:^\w+@[a-z0-9]+(\.[a-z]+){1,3}$
/*起始至少为一个字符(\w字母,数字或者下划线),然后匹配@,接着为任意个字母或者数字,\.代表真正的点,.后面为至少一个的字符(a-z),
同时这个(比如.com)整体为一个子项作为结束,可以出现1-3次。因为有的邮箱是这样的.cn.net。([email protected] [email protected] [email protected] )*/
网址:[a-zA-z]+://[^\s]* http://......
//匹配不分大小写的任意字母,接着是//,后面是非空格的任意字符
邮政编码:[1-9]\d{5} //起始数字不能为0,然后是5个数字
身份证:[1-9]\d{14}|[1-9]\d{17}|[1-9]\d{16}x
</code></pre><h4 id="学习参考:"><a href="#学习参考:" class="headerlink" title="学习参考:"></a>学习参考:</h4><p><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions" target="_blank" rel="external">正则表达式 - JavaScript | MDN</a></p>
<p><a href="http://www.cnblogs.com/moqing/archive/2016/07/13/5665126.html" target="_blank" rel="external">过目不忘JS正则表达式</a> <em>by 沫晴的前端世界</em></p>
]]></content>
<summary type="html">
<p>正则表达式(英语:Regular Expression,在代码中常简写为regex、regexp或RE)使用单个字符串来描述、匹配一系列符合某个句法规则的字符串搜索模式。</p>
<h3 id="语法"><a href="#语法" class="headerlink" title="语法"></a>语法</h3><pre><code>/正则表达式主体/修饰符(可选)
</code></pre><p>实例:</p>
<pre><code>var patt = /runoob/i
</code></pre><p>/runoob/i 是一个正则表达式。runoob 是一个正则表达式主体 (用于检索)。i 是一个修饰符 (表示搜索不区分大小写)。</p>
</summary>
<category term="JavaScript" scheme="http://fanwalker.com/tags/JavaScript/"/>
</entry>
<entry>
<title>自适应网页设计</title>
<link href="http://fanwalker.com/2017/09/20/%E8%87%AA%E9%80%82%E5%BA%94%E7%BD%91%E9%A1%B5%E8%AE%BE%E8%AE%A1/"/>
<id>http://fanwalker.com/2017/09/20/自适应网页设计/</id>
<published>2017-09-20T13:24:59.000Z</published>
<updated>2017-11-18T08:21:38.974Z</updated>
<content type="html"><![CDATA[<p>自适应网页设计:让同一张网页自动适应不同大小的屏幕,根据屏幕宽度,自动调整布局的设计。</p>
<h2 id="一、viewport元标签"><a href="#一、viewport元标签" class="headerlink" title="一、viewport元标签"></a>一、viewport元标签</h2><p>在网页代码的头部,加入一行viewport元标签。</p>
<pre><code><meta name="viewport" content="width=device-width, initial-scale=1" />
</code></pre><p>代码意思是网页宽度默认等于设备的屏幕宽度,原始缩放比例为1.0,即网页的初始大小占屏幕的100%。</p>
<a id="more"></a>
<p>viewport设置属性如下:</p>
<blockquote>
<p>width:网页宽度,可设定数值或指定为device-width;</p>
<p>height:网页高度,可设定数值或指定为device-height;</p>
<p>initial-scale:第一次进入页面的初始比例;</p>
<p>minimum-scale:允许缩小最小比例;</p>
<p>maximum-scale:允许放大最大比例;</p>
<p>user-scalable:是否允许使用者缩放,值为1或0(yes or no)</p>
</blockquote>
<p>编译过程中会转化成如下语义:</p>
<pre><code>@viewport {
width: device-width;
initial-scale: 1.0
}
</code></pre><p>对于老式浏览器(IE6、7、8):</p>
<pre><code><!--[if lt IE 9]>
<script src="http://css3-mediaqueries-js.googlecode.com/svn/trunk/css3-mediaqueries.js"></script>
<![endif]-->
</code></pre><h2 id="二、不要使用绝对宽度"><a href="#二、不要使用绝对宽度" class="headerlink" title="二、不要使用绝对宽度"></a>二、不要使用绝对宽度</h2><p>为了让网页根据屏幕宽度调整布局,不要使用绝对宽度的元素,如:</p>
<pre><code>width: 100px;
</code></pre><p>使用百分比宽度,如:</p>
<pre><code>width: 50% (或 width: auto)
</code></pre><h2 id="三、相对大小的字体"><a href="#三、相对大小的字体" class="headerlink" title="三、相对大小的字体"></a>三、相对大小的字体</h2><p>字体使用相对大小(em)。</p>
<pre><code>body{
font: normal 100% Helvetica, Arial, sans-serif;
}
</code></pre><p>上面代码指定,字体大小是页面默认大小的100%,即16像素。</p>
<pre><code>h1 {
font-size: 1.5em;
}
</code></pre><p>h1的大小是默认大小的1.5倍,即16*1.5=24像素</p>
<pre><code>small {
font-size: 0.875em;
}
</code></pre><p>small元素的大小是默认大小的0.875倍,即14像素(16*0.875)。</p>
<p><strong>这里顺便补一下CSS单位px、pt、em、rem、vh、vw、vmin、vmax,因为在今年欢聚时代的校招笔试中也考到了</strong></p>
<h3 id="px"><a href="#px" class="headerlink" title="px"></a>px</h3><p>为像素单位。是屏幕上显示数据的最基本的点。</p>
<h3 id="pt"><a href="#pt" class="headerlink" title="pt"></a>pt</h3><p>pt是point,是印刷行业常用单位,等于1/72英寸。</p>
<h3 id="em"><a href="#em" class="headerlink" title="em"></a>em</h3><p>相对单位,基准点为父节点字体的大小,如果自身定义了font-size按自身来计算(浏览器默认字体是16px)。如当前对行内文本的字体尺寸未被人为设置,</p>
<p>则相对于浏览器的默认字体尺寸。所有未经调整的浏览器都符合: 1em=16px。那么12px=0.75em,10px=0.625em。</p>
<p><strong>简化font-size的换算</strong>:需要在css中的body选择器中声明Font-size=62.5%,这就使em值变为 16px*62.5%=10px, 这样12px=1.2em, 10px=1em, 也就是说</p>
<p>只需要将你的原来的px数值除以10,然后换上em作为单位就行了。</p>
<h3 id="rem"><a href="#rem" class="headerlink" title="rem"></a>rem</h3><p>相对单位,可理解为“root em”, 相对根节点html的字体大小来计算,CSS3新加属性,chrome/firefox/IE9+支持。相对于当前对象内文本的字体尺寸。</p>
<pre><code><body>
<div class="div1">
<div class="div2">
<div class="div3">div3</div>
</div>
</div>
</body>
</code></pre><p>样式:</p>
<pre><code>.div3{
font-size:1.5rem;
}
</code></pre><p>此时div3的font-size = 1.5 * (html的font-size)</p>
<h3 id="vh和vw"><a href="#vh和vw" class="headerlink" title="vh和vw"></a>vh和vw</h3><p>vw:viewpoint width,视窗宽度,1vw等于视窗宽度的1%。</p>
<p>vh:viewpoint height,视窗高度,1vh等于视窗高度的1%。</p>
<p>如:</p>
<pre><code>浏览器高度900px,宽度为750px
1 vh = 900px * 1% = 9 px,1vw = 750px * 1% = 7.5 px。
</code></pre><p>这样就很容易实现与同屏幕等高的框:</p>
<pre><code>.slide { height: 100vh;}
</code></pre><p>设置一个和屏幕同宽的标题,</p>
<pre><code>h1{font-size:100vw}
</code></pre><p>那标题的字体大小就会自动根据浏览器的宽度进行缩放,以达到字体和viewport大小同步的效果。</p>
<h3 id="vmin-和-vmax"><a href="#vmin-和-vmax" class="headerlink" title="vmin 和 vmax"></a>vmin 和 vmax</h3><p>vmin:vw和vh中较小的那个。</p>
<p>vmax:vw和vh中较大的那个。</p>
<p>比如,浏览器的宽度设置为</p>
<pre><code>width:1200px;
height:800px;
1vmax = 1200/100px = 12px;
1vmin = 800/100px = 8px;
</code></pre><p>如果:</p>
<pre><code>width:600px;
height:1080px;
1vmin就等于6px, 1vmax则为10.8px。
</code></pre><p>有一个元素,你需要让它始终在屏幕上可见:</p>
<pre><code>.box {
height: 100vmin;
width: 100vmin;
}
</code></pre><p>如果你要让这个元素始终铺满整个视口的可见区域:</p>
<pre><code>.box {
height: 100vmax;
width: 100vmax;
}
</code></pre><h2 id="四、流动布局"><a href="#四、流动布局" class="headerlink" title="四、流动布局"></a>四、流动布局</h2><p>流动布局中各个区块的位置都是浮动的。</p>
<pre><code>.main { float: right; width: 70%; }
.leftBar { float: left; width: 25%; }
</code></pre><p>如果宽度太小,放不下两个元素,后面的元素会自动滚动到前面元素的下方,不会在水平方向overflow(溢出),避免了水平滚动条的出现。</p>
<h2 id="五、选择加载CSS"><a href="#五、选择加载CSS" class="headerlink" title="五、选择加载CSS"></a>五、选择加载CSS</h2><p>运用 Css3 <a href="https://www.w3.org/TR/CSS21/media.html" target="_blank" rel="external">Media Queries</a>,根据不同的屏幕分辨率,选择应用不同的CSS规则:</p>
<pre><code><link rel="stylesheet" type="text/css"
media="screen and (max-device-width: 400px)"
href="tinyScreen.css" />
}
</code></pre><p>上面的代码意思是,如果屏幕宽度小于400像素(max-device-width: 400px),就加载tinyScreen.css文件,</p>
<pre><code><link rel="stylesheet" type="text/css"
media="screen and (min-width: 400px) and (max-device-width: 600px)"
href="smallScreen.css" />
</code></pre><p>如果屏幕宽度在400像素到600像素之间,则加载smallScreen.css文件。</p>
<p>除了用html标签加载CSS文件,还可以在现有CSS文件中加载。</p>
<pre><code>@import url("tinyScreen.css") screen and (max-device-width: 400px);
</code></pre><h2 id="六、CSS的-media规则"><a href="#六、CSS的-media规则" class="headerlink" title="六、CSS的@media规则"></a>六、CSS的@media规则</h2><p>同一个CSS文件中,也可以根据不同的屏幕分辨率,选择应用不同的CSS规则。</p>
<pre><code>@media screen and (max-device-width: 400px) {
.column {
float: none;
width:auto;
}
#sidebar {
display:none;
}
}
</code></pre><p>如果屏幕宽度小于400像素,则column块取消浮动(float:none)、宽度自动调节(width:auto),sidebar块不显示(display:none)。</p>
<h2 id="七、图片自适应"><a href="#七、图片自适应" class="headerlink" title="七、图片自适应"></a>七、图片自适应</h2><pre><code>img { max-width: 100%;}
</code></pre><p>老版本的IE</p>
<pre><code>img { width: 100%;}
</code></pre><h2 id="学习参考文章:"><a href="#学习参考文章:" class="headerlink" title="学习参考文章:"></a>学习参考文章:</h2><p><a href="http://www.ruanyifeng.com/blog/2012/05/responsive_web_design.html" target="_blank" rel="external">自适应网页设计(Responsive Web Design)</a></p>
<p><a href="http://www.alloyteam.com/2015/04/zi-shi-ying-she-ji-yu-xiang-ying-shi-wang-ye-she-ji-qian-tan/" target="_blank" rel="external">自适应设计与响应式网页设计</a></p>
<p><a href="http://blog.csdn.net/javaloveiphone/article/details/51120476" target="_blank" rel="external">搞清楚CSS单位px、em、rem、vh、vw、vmin、vmax</a></p>
<p><a href="https://banyaner.github.io/h5/html5/2015/08/05/Rem.html" target="_blank" rel="external">px,em,rem,vh,vw,vmin,vmax的区别及移动端字体自适应问题</a></p>
]]></content>
<summary type="html">
<p>自适应网页设计:让同一张网页自动适应不同大小的屏幕,根据屏幕宽度,自动调整布局的设计。</p>
<h2 id="一、viewport元标签"><a href="#一、viewport元标签" class="headerlink" title="一、viewport元标签"></a>一、viewport元标签</h2><p>在网页代码的头部,加入一行viewport元标签。</p>
<pre><code>&lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot; /&gt;
</code></pre><p>代码意思是网页宽度默认等于设备的屏幕宽度,原始缩放比例为1.0,即网页的初始大小占屏幕的100%。</p>
</summary>
<category term="css" scheme="http://fanwalker.com/tags/css/"/>
</entry>
<entry>
<title>浅谈CORS跨域资源共享</title>
<link href="http://fanwalker.com/2017/09/10/%E6%B5%85%E8%B0%88CORS%E8%B7%A8%E5%9F%9F%E8%B5%84%E6%BA%90%E5%85%B1%E4%BA%AB/"/>
<id>http://fanwalker.com/2017/09/10/浅谈CORS跨域资源共享/</id>
<published>2017-09-10T14:30:18.000Z</published>
<updated>2017-11-18T08:21:34.706Z</updated>
<content type="html"><![CDATA[<p><strong>AJAX(Asynchronous JavaScript And Xml) 是JavaScript执行异步网络请求</strong></p>
<p>用户点击“Submit”按钮,表单开始提交,浏览器就会刷新页面,web的运作原理:一次HTTP请求对应一个页面<br>要让用户留在当前页面,同时发送请求,要用JavaScript实现,接收到数据后,再用JavaScript更新页面</p>
<p>实现AJAX主要依靠XMLHttpRequest对象:</p>
<pre><code>function success(text){
var textarea = document.getElementById('response-text');
textarea.value = text;
}
function fail(err){
var textarea = document.getElementById('response-text');
text.value = 'Error:' + err;
}
var xhr = new XMLHttpRequest(); //创建XMLHttpRequest对象
</code></pre><a id="more"></a>
<p>必须在调用open之前指定onreadystatechange事件处理程序才能确保跨浏览器兼容性</p>
<pre><code>xhr.onreadystatechange = function(){ //监测状态变化
if(xhr.readyState == 4){ //状态为4时代表请求完成
if(xhr.status === 200){ //响应已经成功返回
return success(xhr.responseText);
}else{
return fail(xhr.status);
}
}
else{
console.log('HTTP请求还在继续');
}
}
xhr.open('get',url);
xhr.send();
</code></pre><p>IE以及低版本IE,XMR对象是通过MSXML库中的一个ActiveX对象实现的。<br>所以在IE中可能会遇到三种不同的XHR对象:<br>MSXML2.XMLHttp、MSXML2.XMLHttp.3.0、MSXML2.XMLHttp.6.0<br>所以封装一个函数来创建XHR对象,兼容IE版本</p>
<pre><code>function createXHR(){
if(typeof XMLHttpRequest != "undefined"){
return new XMLHttpRequest();
}else if(typeof ActiveXObject != "undefined"){
if(typeof arguments.callee.activeXString != "string"){
var versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp"],
i, len;
for(i=0, len=versions.length; i<len; i++){
try{
new ActiveXObject(versions[i]);
arguments.callee.activeXString = versions[i];
break;
}catch(ex){
console.log(ex);
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
}
}
var xhr = createXHR();
</code></pre><h3 id="CORS-Cross-Origin-Resource-Sharing-跨域资源共享"><a href="#CORS-Cross-Origin-Resource-Sharing-跨域资源共享" class="headerlink" title="CORS(Cross-Origin Resource Sharing)跨域资源共享"></a>CORS(Cross-Origin Resource Sharing)跨域资源共享</h3><p>Ajax同信限制:跨域安全策略;<br>XHR对象只能访问与包含它的页面位于同一个域中的资源:<br>1、域名要相同(www.example.com和example.com不同),<br>2、协议要相同(http和https不同),<br>3、端口号要相同(默认是:80端口,它和:8080就不同)。<br>CORS定义了在访问跨域资源时,浏览器和服务器应该怎样沟通,CORS的思想是使用自定义的HTTP头部让浏览器与服务区进行沟通,从而决定响应是成功还是失败<br> 比如一个简单的GET或POST请求,它没有自定义的头部,而主题内容是text/plain。在发送该请求时需要给它加一个额外的头部,包含请求页面的源信息(协议、域名和端口),服务器根据该头部信息决定是否给予响应,Origin头部示例:<br><code>Origin : http://www.fanwalker.com</code><br>如果服务器接收该请求,会在Access-Control-Allow-Origin头部中回发相同的源信息。例如:<br><code>Acess-Control-Allow-Origin: http://www.fanwalker.com</code><br>如果没有这个头部或不匹配源信息,浏览器会驳回请求。这里注意请求和响应都不包含cookie信息</p>
<h3 id="IE对CORS的实现"><a href="#IE对CORS的实现" class="headerlink" title="IE对CORS的实现"></a>IE对CORS的实现</h3><p>IE8中引入了XDR(XDomainRequest)类型,可以实现安全的跨域通信,XDR对象的使用方法与XHR对象相似:</p>
<p>GET请求</p>
<pre><code>var xdr = new XDomainRequest();
xdr.onload = function(){
alert(xdr.responseText); //xdr.responseText保存着响应数据
}
xdr.onerror = function(){ //失败后出发error事件
alert("an error occurred.");
}
xdr.timeout = 1000; //支持timeout属性和ontimeout事件处理程序,1秒钟后超时并调用ontimeout方法
xdr.ontimeout = function(){
alert("Request took too long");
}
xdr.open("get", "http://www.fanwalker.com/page/");
xdr.send(null);
</code></pre><p>POST请求</p>
<pre><code>var xdr = new XDomainRequest();
xdr.onload = function(){
alert(xdr.responseText); //xdr.responseText保存着响应数据
}
xdr.onerror = function(){ //失败后出发error事件
alert("an error occurred.");
}
xdr.timeout = 1000; //支持timeout属性和ontimeout事件处理程序,1秒钟后超时并调用ontimeout方法
xdr.ontimeout = function(){
alert("Request took too long");
}
xdr.open("post", "http://www.fanwalker.com/page/");
xdr.contentType = "application/x-www-form-urlencoded": //设置contentType属性表示发送数据的格式
xdr.send(null);
</code></pre><p>更多详细的介绍:<a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS" target="_blank" rel="external">HTTP访问控制(CORS)</a></p>
]]></content>
<summary type="html">
<p><strong>AJAX(Asynchronous JavaScript And Xml) 是JavaScript执行异步网络请求</strong></p>
<p>用户点击“Submit”按钮,表单开始提交,浏览器就会刷新页面,web的运作原理:一次HTTP请求对应一个页面<br>要让用户留在当前页面,同时发送请求,要用JavaScript实现,接收到数据后,再用JavaScript更新页面</p>
<p>实现AJAX主要依靠XMLHttpRequest对象:</p>
<pre><code>function success(text){
var textarea = document.getElementById(&apos;response-text&apos;);
textarea.value = text;
}
function fail(err){
var textarea = document.getElementById(&apos;response-text&apos;);
text.value = &apos;Error:&apos; + err;
}
var xhr = new XMLHttpRequest(); //创建XMLHttpRequest对象
</code></pre>
</summary>
<category term="ajax" scheme="http://fanwalker.com/tags/ajax/"/>
</entry>
<entry>
<title>JavaScript之命名函数表达式</title>
<link href="http://fanwalker.com/2017/08/30/JavaScript%E4%B9%8B%E5%91%BD%E5%90%8D%E5%87%BD%E6%95%B0%E8%A1%A8%E8%BE%BE%E5%BC%8F/"/>
<id>http://fanwalker.com/2017/08/30/JavaScript之命名函数表达式/</id>
<published>2017-08-30T12:03:03.000Z</published>
<updated>2017-11-18T08:20:52.249Z</updated>
<content type="html"><![CDATA[<p>所谓命名函数表达式就是被赋予了名字的函数表达式,和它相对的是匿名函数,从简单的角度来看,命名函数表达式可以在调试器或性能分析程序中描述函</p>
<p>数的名称,在调试过程中有着不小的作用,因为通常在跨浏览器开发中都会出现一些小毛病,命名函数表达式可以帮助我们解决它们。</p>
<p>先来看一下函数表达式与函数声明以及现代调试器如何处理它们之类的内容。</p>
<h2 id="函数表达式与函数声明"><a href="#函数表达式与函数声明" class="headerlink" title="函数表达式与函数声明"></a>函数表达式与函数声明</h2><p>通常,我们可以通过函数表达式与函数声明来创建函数对象的方法。但是具体来说什么是函数表达式、什么是函数声明呢?在ECMA规范中明确了一点,函</p>
<p>数声明必须始终带有标志符——即函数名,而函数表达式可以省略这个标识符,如:<br><a id="more"></a></p>
<pre><code>//函数声明
function 函数名称(参数:可选){ 函数体 }
//函数表达式
function 函数名称(可选)(参数:可选){ 函数体 }
</code></pre><p>但是如果函数表达式没有省略函数名,这时候函数声明与函数表达式就容易混淆。这时候ECMAScript是通过上下文来区分两者。比如,function foo(){} 是一</p>
<p>个赋值表达式的一部分,则认为它是一个函数表达式,如果 function foo(){} 被包含在一个函数体内,或者位于程序(的最上层)中,则将它作为一个函数声</p>
<p>明来解析:</p>
<pre><code>function foo(){}; // 声明,因为它是程序的一部分
var bar = function foo(){}; // 表达式,因为它是赋值表达式(AssignmentExpression)的一部分
new function bar(){}; // 表达式,因为它是New表达式(NewExpression)的一部分
(function(){
function bar(){}; // 声明,因为它是函数体(FunctionBody)的一部分
})();
</code></pre><p>还有一种就是被包含在一对圆括号中的函数—— (function foo(){})。将这种形式看成表达式同样是因为上下文的关系:’(‘ 和 ‘)’构成一个分组操作符,而分组</p>
<p>操作符只能包含表达式:</p>
<pre><code>function foo(){}; // 函数声明
(function foo(){}); // 函数表达式:注意它被包含在分组操作符中
try {
(var x = 5); // 分组操作符只能包含表达式,不能包含语句(这里的var就是语句)
} catch(err) {
// SyntaxError
}
</code></pre><p>在使用eval对JSON进行执行的时候,JSON字符串通常被包含在一个圆括号里:eval(‘(‘ + json + ‘)’),这样做的原因就是因为分组操作符,也就是这对括号,</p>
<p>‘(‘ 和 ‘)’会让解析器强制将JSON的花括号解析成表达式而不是代码块。</p>
<pre><code>try {
{ "x": 5 }; // "{" 和 "}" 会被解析成代码块
} catch(err) {
// SyntaxError
}
({ "x": 5 }); // 分组操作符强制将"{" 和 "}"作为对象字面量来解析
</code></pre><p>声明和表达式的行为存在着十分微妙而又十分重要的差别。首先,函数声明会在任何表达式被解析和求值之前先行被解析和求值。即使声明位于源代码中的</p>
<p>最后一行,它也会先于同一作用域中位于最前面的表达式被求值。还是看个例子更容易理解。在下面这个例子中,函数 fn 是在 alert 后面声明的。但是,在 </p>
<p>alert 执行的时候,fn已经有定义了:</p>
<pre><code>alert(fn());
function fn() {
return 'Hello world!';
}
</code></pre><p><strong>函数声明有一个重要的注意事项</strong>:就是千万不要在条件语句中使用函数声明,而要使用函数表达式。因为通过条件语句控制函数声明的行为并未标准化,</p>
<p>因此不同环境下可能会得到不同的结果。</p>
<pre><code>// 千万不要这样做!
// 有的浏览器会把foo声明为返回first的那个函数
// 而有的浏览器则会让foo返回second
if (true) {
function foo() {
return 'first';
}
}
else {
function foo() {
return 'second';
}
}
foo();
// 这种情况下要使用函数表达式:
var foo;
if (true) {
foo = function() {
return 'first';
};
}
else {
foo = function() {
return 'second';
};
}
foo();
</code></pre><p>函数声明的实际规则如下:</p>
<p>FunctionDeclaration(函数声明)只能出现在Program(程序)或FunctionBody(函数体)内。</p>
<p>从句法上讲,它们 不能出现在Block(块)({ … })中,例如不能出现在 if、while 或 for 语句中。因为 Block(块) 中只能包含Statement(语句), 而不能包含FunctionDeclaration(函数声明)这样的SourceElement(源元素)。</p>
<p>另一方面,唯一可能让Expression(表达式)出现在Block(块)中情形,就是让它作为ExpressionStatement(表达式语句)的一部分。但是,规范明确规定了ExpressionStatement(表达式语句)不能以关键字function开头。而这实际上就是说,FunctionExpression(函数表达式)同样也不能出现在Statement(语句)或Block(块)中(别忘了Block(块)就是由Statement(语句)构成的)。</p>
<h2 id="命名函数表达式"><a href="#命名函数表达式" class="headerlink" title="命名函数表达式"></a>命名函数表达式</h2><p>函数表达式实际上还是很常见的。Web开发中有一个常用的模式,即基于对某种特性的测试来“伪装”函数定义,从而实现性能最优化。由于这种伪装通常都</p>
<p>出现在相同的作用域中,因此基本上一定要使用函数表达式。毕竟,如前所述,不应该根据条件来执行函数声明:</p>
<pre><code>var contains = (function() {
var docEl = document.documentElement;
if (typeof docEl.compareDocumentPosition != 'undefined') {
return function(el, b) {
return (el.compareDocumentPosition(b) & 16) !== 0;
}
}
else if (typeof docEl.contains != 'undefined') {
return function(el, b) {
return el !== b && el.contains(b);
}
}
return function(el, b) {
if (el === b) return false;
while (el != b && (b = b.parentNode) != null);
return el === b;
}
})();
</code></pre><p>提到命名函数表达式,很显然,指的就是有名字(技术上称为标识符)的函数表达式。在最前面的例子中,var bar = function foo(){};实际上就是一个以foo</p>
<p>作为函数名字的函数表达式。对此,有一个细节特别重要,请大家一定要记住,即这个名字只在新定义的函数的作用域中有效——规范要求标识符不能在外</p>
<p>围的作用域中有效:</p>
<pre><code>var f = function foo(){
return typeof foo; // foo只在内部作用域中有效
};
// foo在“外部”永远是不可见的
typeof foo; // "undefined"
f(); // "function"
</code></pre><p>有名字的函数可以让调试过程更加方便。在调试应用程序时,如果调用栈中的项都有各自描述性的名字,那么调试过程带给人的就是另一种完全不同的感</p>
<p>受。</p>
<h2 id="调试器中的函数名"><a href="#调试器中的函数名" class="headerlink" title="调试器中的函数名"></a>调试器中的函数名</h2><p>在函数有相应标识符的情况下,调试器会将该标识符作为函数的名字显示在调用栈中。有的调试器(例如Firebug)甚至会为匿名函数起个名字并显示出来,</p>
<p>让它们与那些引用函数的变量具有相同的角色。可遗憾的是,这些调试器通常只使用简单的解析规则,而依据简单的解析规则提取出来的“名字”有时候没有</p>
<p>多大价值,甚至会得到错误结果。</p>
<p>下面我们来看一个简单的例子:</p>
<pre><code>function foo(){
return bar();
}
function bar(){
return baz();
}
function baz(){
debugger;
}
foo();
// 这里使用函数声明定义了3个函数
// 当调试器停止在debugger语句时,
// Firgbug的调用栈看起来非常清晰:
baz
bar
foo
expr_test.html()
</code></pre><p>我们可以清晰地知道foo调用了bar,而后者接着又调用了baz(而foo本身又在expr_test.html文档的全局作用域中被调用)。但真正值得称道的,则是</p>
<p>Firebug会在我们使用匿名表达式的情况下,替我们解析函数的“名字”:</p>
<pre><code>function foo(){
return bar();
}
var bar = function(){
return baz();
}
function baz(){
debugger;
}
foo();
// 调用栈:
baz
bar()
foo
expr_test.html()
</code></pre><p>相反,不那么令人满意的情况是,当函数表达式复杂一些时(现实中差不多总是如此),调试器再如何尽力也不会起多大的作用。结果,我们只能在调用栈中</p>
<p>显示函数名字的位置上赫然看到一个问号:</p>
<pre><code>function foo(){
return bar();
}
var bar = (function(){
if (window.addEventListener) {
return function(){
return baz();
}
}
else if (window.attachEvent) {
return function() {
return baz();
}
}
})();
function baz(){
debugger;
}
foo();
// 调用栈:
baz
(?)()
foo
expr_test.html()
</code></pre><p>此外,当把一个函数赋值给多个变量时,还会出现一个令人困惑的问题:</p>
<pre><code>function foo(){
return baz();
}
var bar = function(){
debugger;
};
var baz = bar;
bar = function() {
alert('spoofed');
}
foo();
// 调用栈:
bar()
foo
expr_test.html()
</code></pre><p>可见,调用栈中显示的是foo调用了bar。但实际情况显然并非如此。之所以会造成这种困惑,完全是因为baz与另一个函数——包含代码alert(‘spoofed’);的函</p>
<p>数——“交换了”引用所致。实事求是地说,这种解析方式在简单的情况下固然好,但对于不那么简单的大多数情况而言就没有什么用处了。</p>
<p>归根结底,只有命名函数表达式才是产生可靠的栈调用信息的唯一途径。下面我们有意使用命名函数表达式来重写前面的例子。请大家注意,从自执行包装</p>
<p>块中返回的两个函数都被命名为了bar:</p>
<pre><code>function foo(){
return bar();
}
var bar = (function(){
if (window.addEventListener) {
return function bar(){
return baz();
}
}
else if (window.attachEvent) {
return function bar() {
return baz();
}
}
})();
function baz(){
debugger;
}
foo();
// 这样,我们就又可以看到清晰的调用栈信息了!
baz
bar
foo
expr_test.html()
</code></pre><p>OK,我们又学到了一招。</p>
<p>参考文章:<a href="http://www.jb51.net/onlineread/named-function-expressions-demystified/" target="_blank" rel="external">命名函数表达式探秘</a></p>
]]></content>
<summary type="html">
<p>所谓命名函数表达式就是被赋予了名字的函数表达式,和它相对的是匿名函数,从简单的角度来看,命名函数表达式可以在调试器或性能分析程序中描述函</p>
<p>数的名称,在调试过程中有着不小的作用,因为通常在跨浏览器开发中都会出现一些小毛病,命名函数表达式可以帮助我们解决它们。</p>
<p>先来看一下函数表达式与函数声明以及现代调试器如何处理它们之类的内容。</p>
<h2 id="函数表达式与函数声明"><a href="#函数表达式与函数声明" class="headerlink" title="函数表达式与函数声明"></a>函数表达式与函数声明</h2><p>通常,我们可以通过函数表达式与函数声明来创建函数对象的方法。但是具体来说什么是函数表达式、什么是函数声明呢?在ECMA规范中明确了一点,函</p>
<p>数声明必须始终带有标志符——即函数名,而函数表达式可以省略这个标识符,如:<br>
</summary>
<category term="JavaScript" scheme="http://fanwalker.com/tags/JavaScript/"/>
</entry>
<entry>
<title>JavaScript之原型和原型链</title>
<link href="http://fanwalker.com/2017/08/25/JavaScript%E4%B9%8B%E5%8E%9F%E5%9E%8B%E5%92%8C%E5%8E%9F%E5%9E%8B%E9%93%BE/"/>
<id>http://fanwalker.com/2017/08/25/JavaScript之原型和原型链/</id>
<published>2017-08-25T13:23:51.000Z</published>
<updated>2017-11-18T08:20:55.725Z</updated>
<content type="html"><![CDATA[<p>JavaScript不包含传统的类继承模型,使用的是prototypal模型即原型模型,虽然这经常被当作是 JavaScript 的缺点被提及,其实基于原型的继承模型比传统</p>
<p>的类继承还要强大。实现传统的类继承模型是很简单,但是实现 JavaScript 中的原型继承则要困难的多。</p>
<h2 id="原型"><a href="#原型" class="headerlink" title="原型"></a>原型</h2><p>先来了解什么是原型(prototype):javascript中的每个对象都有prototype属性,Javascript中对象的prototype属性的解释是:返回对象类型原型的引用。</p>
<p>如:<br><a id="more"></a></p>
<pre><code>A.prototype = new B();
</code></pre><p>理解prototype不应把它和继承混淆。A的prototype为B的一个实例,可以理解A将B中的方法和属性全部克隆了一遍。A能使用B的方法和属性。这里强调的是</p>
<p>克隆而不是继承。可以出现这种情况:A的prototype是B的实例,同时B的prototype也是A的实例。简单说了一下原型的概念,接下来看一下原型是怎么应用</p>
<p>的。一开始学JavaScript的时候,一般会如下面一样写代码:</p>
<pre><code>var decimalDigits = 2,
tax = 5;
function add(x, y) {
return x + y;
}
function subtract(x, y) {
return x - y;
}
//alert(add(1, 3));
</code></pre><p>通过执行各个function来得到结果,学习了原型之后,我们可以使用如下方式来美化一下代码:</p>
<h3 id="原型使用方式1:"><a href="#原型使用方式1:" class="headerlink" title="原型使用方式1:"></a>原型使用方式1:</h3><p>在使用原型之前,我们需要先将代码做一下小修改:</p>
<pre><code>var Calculator = function (decimalDigits, tax) {
this.decimalDigits = decimalDigits;
this.tax = tax;
};
</code></pre><p>然后,通过给Calculator对象的prototype属性赋值对象字面量来设定Calculator对象的原型</p>
<pre><code>Calculator.prototype = {
add: function (x, y) {
return x + y;
},
subtract: function (x, y) {
return x - y;
}
};
//alert((new Calculator()).add(1, 3));
</code></pre><p>这样,我们就可以new Calculator对象以后,就可以调用add方法来计算结果了。</p>
<h3 id="原型使用方式2"><a href="#原型使用方式2" class="headerlink" title="原型使用方式2"></a>原型使用方式2</h3><p>第二种方式是,在赋值原型prototype的时候使用function立即执行的表达式来赋值,即如下格式:</p>
<pre><code>Calculator.prototype = function () { } ();
</code></pre><p>它可以封装私有的function,通过return的形式暴露出简单的使用名称,以达到public/private的效果,修改后的代码如下:</p>
<pre><code>Calculator.prototype = function () {
add = function (x, y) {
return x + y;
},
subtract = function (x, y) {
return x - y;
}
return {
add: add,
subtract: subtract
}
} ();
//alert((new Calculator()).add(11, 3));
</code></pre><p>同样的方式,我们可以new Calculator对象以后调用add方法来计算结果了。</p>
<h3 id="分步声明:"><a href="#分步声明:" class="headerlink" title="分步声明:"></a>分步声明:</h3><p>上述使用原型的时候,有一个限制就是一次性设置了原型对象,我们再来说一下如何分开设置原型的每个属性吧。</p>
<pre><code>var BaseCalculator = function () {
//为每个实例都声明一个小数位数
this.decimalDigits = 2;