-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathatom.xml
More file actions
4714 lines (3284 loc) · 301 KB
/
atom.xml
File metadata and controls
4714 lines (3284 loc) · 301 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
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><![CDATA[netwjx]]></title>
<link href="http://netwjx.github.com/atom.xml" rel="self"/>
<link href="http://netwjx.github.com/"/>
<updated>2013-02-02T16:35:44+08:00</updated>
<id>http://netwjx.github.com/</id>
<author>
<name><![CDATA[netwjx]]></name>
<email><![CDATA[netwjx@mail.com]]></email>
<uri>http://netwjx.github.com/</uri>
</author>
<generator uri="http://octopress.org/">Octopress</generator>
<icon>/favicon.png</icon>
<subtitle><![CDATA[混乱与有序]]></subtitle>
<entry>
<title type="html"><![CDATA[滑雪备忘]]></title>
<category term="Live" />
<category term="Memo" />
<link href="http://netwjx.github.com/blog/2013/01/27/skiing-memo/"/>
<author>
<name><![CDATA[netwjx]]></name>
<uri>http://netwjx.github.com/</uri>
</author>
<published>2013-01-27T19:40:00+08:00</published>
<updated>2013-01-27T19:40:00+08:00</updated>
<id>http://netwjx.github.com/blog/2013/01/27/skiing-memo</id>
<content type="html"><![CDATA[<p>前阵子去滑雪, 提前在网上找了一些滑雪的注意事项和准备, 但是等自己亲身体验后感觉还缺点, 这里整理了一些注意事项和准备.</p>
<h2>行程</h2>
<p>一般滑雪场都在郊区, 从起床到进入雪场, 一般需要至少3小时, 雪场开始营业的时间是早8点左右, 结束是一般下午4 5点种, 中间可能需要在雪场用餐. 这个时间要计算好, 免得玩的不够尽兴.</p>
<p>滑雪多数时间是在上山, 途径拖牵, 缆车, 传送带(也叫魔毯). 滑下速度很快, 没有太多消耗体力的地方, 一般体能也能持续很长时间, 只要休息好了.</p>
<p>如果赶到人流多的时候, 在进入, 领服装, 雪鞋, 雪板, 换服装也会消耗很多时间.</p>
<h2>吃喝拉撒</h2>
<p>雪场一般都有餐厅, 价格不算很便宜, 不过附近一般也没什么地方有卖吃的, 有条件的话自己带吃喝.</p>
<p>不能吃太饱, 差不多吃吃就行了, 运动前的常识, 吃完不宜立即剧烈运动.</p>
<p>带上一些高能量食品, 如巧克力, 如果饿了可以先垫点.</p>
<p>带上水杯, 雪场有温水, 也可以自己带水. 水喝多了没事, 雪场应该有卫生间, 一般在雪道底部一侧. 刚进雪场的时候可以先踩踩点, 熟悉周边设施.</p>
<h2>穿着</h2>
<h3>贴身衣物</h3>
<p>内衣最好是透湿, 有弹性, 保暖还行的内衣, 滑雪是持续运动中, 只要吃够了, 外套防风 防水, 基本不会有冷的感觉, 滑完之后可以加件保暖夹层. 贴身不要穿纯棉的, 吸汗之后会湿, 容易着凉.</p>
<p>我穿的是 迪卡依Equarea面料的<a href="http://detail.tmall.com/item.htm?id=12651330117">上身</a>和<a href="http://detail.tmall.com/item.htm?id=12652566120">下身</a>, 保暖一般, 滑雪不感觉到冷, 不活动的时候再加件抓绒上衣, 我穿的是 迪卡依Stratermic面料的<a href="http://detail.tmall.com/item.htm?id=7129791687">抓绒衣</a>.</p>
<h3>保暖夹层</h3>
<p>中间夹层一般建议穿背心, 不会影响到手臂的活动, 温度合适的话, 可以不用加背心. 背心一般是填充的羽绒.</p>
<p>也可以是类似冲锋衣内胆哪种抓绒衣物, 保暖程度主要考虑当天的气温如何.</p>
<h3>防风防雨外套</h3>
<p>外套主要是要防风和防水, 能保暖也行, 就可以少穿一件保暖夹层, 如果自己有冲锋衣裤也可以, 手脚和腰是缩口的最好, 防止摔倒之后进雪. <strong>雪场也有滑雪服租用</strong>, 一般团购的票里面就带有滑雪服租用费.</p>
<p>不建议在日常外套外面穿滑雪服, 会十分影响四肢活动, 而且还可能太热.</p>
<p>一般滑雪服都使用尼龙魔术贴固定的, 租用的可能魔术贴老化而贴不牢, 可以考虑带条腰带, 比较宽, 有一些弹性, 对运动影响小最好. 如果有战术腰带也可, 方便下文要说的腰包. 衣服口袋都是拉链, 可以看看口袋是不是完好, 必要的话可以要求调换.</p>
<h3>袜子</h3>
<p>雪靴一般都比较硬, 加上持续的活动, 建议至少穿两双袜子.</p>
<ul>
<li>里面是加厚的线袜, 能防止脚魔伤, 线袜空隙大, 透湿效果也挺好.</li>
<li>外套吸汗的袜子, 比如纯棉的, 还因为租用的鞋子可能有气味.</li>
</ul>
<h3>帽子</h3>
<p>即使在无风的天气, 下滑的速度也会产生挺大的风, <strong>最好能对耳朵保护下</strong>, 还能有一定的保暖, 可以减少大量的热量消耗.</p>
<p>一般如抓绒帽, 线帽都可以, 防风 不吸水的为主.</p>
<p>我的是这个<a href="http://detail.tmall.com/item.htm?id=6948230189">围脖</a>, 将收缩绳拉上就是个帽子了, 有长发的女孩子还可以把长发从缩口中拉出来, 滑行中更有型.</p>
<h3>手套</h3>
<p>不带手套的话, 手会很快冻僵, 摔倒沾到雪, 湿了之后<strong>就更容易冻伤</strong>, 所以最好有手套, 依旧是防水 防风的, 毛线手套空隙太大的不行, 会透风, 下滑时风会进入手套. 手套最好能方便挂到手上或脖子上, 避免丢失. 我的是<a href="http://detail.tmall.com/item.htm?id=13348736509">这个手套</a>.</p>
<h3>滑雪镜</h3>
<p>如果是初级滑道, 当天也没有风的话是没必要考虑眼镜, 后面的中级滑道就需要眼镜了, 主要是挡风, 不然滑下时风太大, 会流眼泪, 影响视野. 滑雪镜和前面几个的不太一样的是, 基本没什么别的场合可以使用(除非在东北, 大风下雪天气), 可以考虑租用滑雪镜. 如果有畏光, 雪盲, 看到大量雪会难受则一定要找个滑雪镜. 不建议传统太阳镜, 摔倒脱落的话有可能伤到眼睛. 滑雪镜不是潜水镜, 周围是海绵垫着的, 不会对眼球产生负压.</p>
<h3>口罩/围巾</h3>
<p>如果受不了迎风直接吸冷风, 则还需要口罩, 或者是围巾, 能对直接刮来的冷风有点削减的就行.</p>
<h3>穿着总结</h3>
<p>总结起来就是:</p>
<ul>
<li>贴身衣物 透湿, 弹性好, 不吸汗的.</li>
<li>夹层根据天气情况穿件保暖的背心, 可以不穿保暖裤.</li>
<li>外穿的都需要防风 防水.
<ul>
<li>外套可以在雪场租用, 自备可以用冲锋衣.</li>
<li>外套颜色不要白色的, 选择其它鲜艳点的颜色, 方便雪地中辨识.</li>
<li>手套和帽子可以防止冻伤, 建议准备上.</li>
</ul>
</li>
<li>透湿的厚袜子.</li>
</ul>
<h3>随身物品</h3>
<p>建议把平时多数随身物品都存上, 免得滑雪中掉落, <strong>可以随身携带的有</strong>:</p>
<ul>
<li>手机(充满电的), 雪场比较大, 方便联系同伴.
<ul>
<li>领到的储物柜钥匙很可能不在一起, 换完服装如果先不和同伴碰头, 进了雪场空间太大就很难找到了, 所以最好大家随身带手机.</li>
</ul>
</li>
<li>滑雪场寄存柜的钥匙, 计费卡, 没这个就回不了家啦.</li>
<li>巧克力(高能量食品, 感觉冷或饿的时候可以先垫点), 不能放太热的地方, 会化掉.</li>
</ul>
<p>水可以放寄存柜, 需要的话回来开柜取出来.</p>
<p>最简单的就是把所有东西都放到滑雪服的拉链口袋, 切记用完后要拉好拉链, 防止掉落.</p>
<p>如果东西多可以考虑用一个贴身的小双肩背包, 防水, 能在腰间绑一圈固定的最好.</p>
<p>如果对滑雪服的拉链口袋不满意, 可以用腰包, 一般军品店哪种战术腰带也行, 可以根据需要挂接腰包模块, 足够放手机和钥匙就行, 腰包一定要可靠, 不能中途物品掉落.</p>
<h2>取雪鞋 雪板 雪杖</h2>
<p>雪板和雪鞋可能会不匹配, 拿到之后建议在原地试试, 是否能卡紧, 卡不紧可以要求调整或者调换. 顺便了解下怎么脱离雪板, 然后在进入雪场.</p>
<p>一般雪板都是可以摔倒自动脱离, 正常的脱离是用雪杖扎到卡住雪鞋后跟哪个机关的小凹坑上, 使劲压, 可能需要双手压, 脚后跟就能起来了. 如果有同伴就让同伴用雪鞋帮踩压哪个机关.</p>
<p>领取这些东西一般会有一个领用凭据之类的, 这个要保存好, 最好随身携带. 雪板和雪杖不要丢失, 会扣钱的. 有些雪杖前面的帽会脱落, 能换个好点的就换吧.</p>
<p>雪场一般有雪板和雪杖的寄存处, 应该是免费的, 需要休息, 去卫生间等可以把雪板和雪杖先寄存. 或者是同伴帮看着.</p>
<h2>用雪杖推行</h2>
<p>不要把雪杖扎到自己的脚前面, 那样十分费劲, 雪杖最多扎到和脚后跟平行, 不要想着能一次把自己推多远, 少量多次就可以了, 后面可以学习脚怎么配合一些滑行的动作, 能省力很多.</p>
<p>不推荐新手只在平地上滑行, 极其消耗体力, 还会玩的很痛苦.</p>
<h2>滑道中滑行</h2>
<p>滑道会有难度标识, 建议新人从练习道和初级道开始, 这两个的坡度很小, 速度会慢一些.</p>
<p>上滑道一般是三种途径:</p>
<ul>
<li>拖牵 拖牵是有一根垂直下来, 能伸缩的金属杆, 末端一个橡胶盘, 双腿夹住金属杆, 不用太紧, 然后橡胶盘会推着屁股前行. 这个是事实上山速度最快的途径, 就是需要滑到有点高的地方才有拖牵, 拖行中因为雪面会有轻微的起伏, 所以会有速度变化, 需要自己控制一点左右防止摔倒. 拖牵可以随时从拖牵道出来滑下.</li>
<li>魔毯 我觉得就是传送带, 比较简单, 可以穿或者不穿雪板, 因为是传送带哪种, 所以速度比拖牵慢.</li>
<li>缆车 缆车应该是很快的, 但是因为太多人都想乘缆车, 所以排队十分长, 如果队伍短可以用缆车.</li>
</ul>
<p>还有雪地摩托, 但是好像这个只能进入专用滑雪道, 它上山是直接在滑雪道上逆行的.</p>
<p>雪场有教练服务, 费用还是很贵的, 建议找同伴中比较熟悉的人学习, 或者是在教练附近蹭学, 不要蹭太久了, 可以远处看着也行.</p>
<p>水平横在雪道下坡就可以停住, 实在停不住可以向左右一侧倒, 但要注意后面有没有跟随的人, 避免被后面的人撞上, 人多的时候就不建议这样做.</p>
<p>雪杖不要脱手, 会造成其它人摔倒.</p>
<h2>本次去的滑雪场软硬件设施</h2>
<p>这次去的是<a href="http://www.yuyangski.com.cn/">平谷渔阳滑雪场</a>.</p>
<ul>
<li>面积很大, 高级滑道没有上去过, 主要是乘缆车人太多了.</li>
<li>雪场随处都能看到有工作人员, 或者雪场的教练, 有什么麻烦可以找他们. 一般有统一独特的服装, 很好认.</li>
<li>大厅和雪场都有卫生间, 雪场的卫生间过去比较方便.</li>
<li>最底部有儿童乐园类似的地方, 会有小孩用的哪种比较安全的滑雪圈, 不过是额外收费的.
<ul>
<li>其它还有拍照, 冰面碰碰车好像.</li>
</ul>
</li>
<li>有餐厅, 如果是自助餐要赶早, 不然就没什么好东西吃了, 可以看看团购卷里面是否包含, 正价是58/每人, 提前问好用餐时间.</li>
<li>有卖小吃的地方, 我没仔细看, 不知道价格, 味道估计不会特别的好.</li>
<li>生态餐厅就是内部有大量的植被, 人工河(好像是不动的, 但是里面有鱼).</li>
<li>雪场有自己的班车, 早上7:30发车,16:00集合,16:30返程, 40/每人, 团购会便宜点.</li>
</ul>
<h3>酒店</h3>
<p>雪场的酒店, 是别墅木屋哪种, 两层, 三室, 全部独立卫生间 淋浴, 如果是很多人会比较划算, 最近房子刚刚装修, 气味比较重.</p>
<p>其它就只能住附近了, 当然最后行程是当天, 不过夜.</p>
<h2>后记</h2>
<ul>
<li>去雪场切记不要落下东西, 我这次去就把东西给忘在雪场了.
<ul>
<li>后来抱着希望给雪场打电话, 想不到他们帮找到了, 过段时间找快递发回来.</li>
</ul>
</li>
</ul>
<p><a href="http://netwjx.github.com/blog/2013/01/27/skiing-memo/#comments">查看评论</a></p>]]></content>
</entry>
<entry>
<title type="html"><![CDATA[函数的Currying (Javascript 和 Scala)]]></title>
<category term="Javascript" />
<category term="Memo" />
<category term="Scala" />
<link href="http://netwjx.github.com/blog/2012/12/05/function-currying-in-javascript-and-scala/"/>
<author>
<name><![CDATA[netwjx]]></name>
<uri>http://netwjx.github.com/</uri>
</author>
<published>2012-12-05T13:52:00+08:00</published>
<updated>2012-12-05T13:52:00+08:00</updated>
<id>http://netwjx.github.com/blog/2012/12/05/function-currying-in-javascript-and-scala</id>
<content type="html"><![CDATA[<p>Currying或者Curry, 中文有翻译成<a href="http://book.51cto.com/art/200806/77578.htm">科里化</a>. 我最早了解它是在一篇讲<a href="http://www.ibm.com/developerworks/cn/java/j-pg08235/">Groovy中函数式编程</a>的文章中, 之后又在<a href="http://www.python.org/">Python</a>中<a href="http://code.activestate.com/recipes/52549/">遇到同样的东西</a>. 最近在看<a href="http://www.scala-lang.org/">Scala</a>的介绍时<a href="http://www.scala-lang.org/node/135">又看到了</a>, 而且发现<a href="http://www.scala-lang.org/">Scala</a>设计的明显更好, 然后就成了这篇文章, 使用Javascript作为主要语言是因为我使用Javascript的时间更长, 并且Javascript这门语言的表达能力<a href="http://www.nafine.com/Work_View.php?id=271">奇强</a>^-^.</p>
<p>我不确定把Currying记作<a href="http://book.51cto.com/art/200806/77578.htm">科里化</a>是否更容易理解, 所以下文还是依旧使用Currying吧.</p>
<p>Currying是<a href="http://www.ibm.com/developerworks/cn/java/j-cb12196/">函数式编程</a>中一种<a href="http://zh.wikipedia.org/wiki/%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0">高阶函数</a>的典型应用, 如果非要把它对应到传统OO中的话, 那么它类似<a href="https://www.google.com/search?q=builder+pattern">Builder模式</a>, 一般译作构建器模式 建造者模式.</p>
<p>Builder模式可以简单理解为创建一个复杂的对象需要依赖多个参数, 要提供的参数又依赖于不同的方法, 使用Builder模式让每个方法只关注自己提供的参数, 最终根据全部参数创建出对象来. 对象实例最终是拿来调用的, 可以把这个过程想象成调用一个参数很多的函数.</p>
<p>Javascript中完全可以按照传统OO的方式实现Builder模式, 但使用Currying更轻量级 简单, 考虑下面的代码:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="kd">function</span> <span class="nx">filter</span><span class="p">(</span><span class="nx">list</span><span class="p">,</span> <span class="nx">func</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="kd">var</span> <span class="nx">ret</span> <span class="o">=</span> <span class="p">[];</span>
</span><span class='line'> <span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o"><</span> <span class="nx">list</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="kd">var</span> <span class="nx">v</span> <span class="o">=</span> <span class="nx">list</span><span class="p">[</span><span class="nx">i</span><span class="p">];</span>
</span><span class='line'> <span class="k">if</span> <span class="p">(</span><span class="nx">func</span><span class="p">(</span><span class="nx">v</span><span class="p">))</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">ret</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">v</span><span class="p">);</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'> <span class="k">return</span> <span class="nx">ret</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kd">function</span> <span class="nx">modN</span><span class="p">(</span><span class="nx">n</span><span class="p">,</span> <span class="nx">x</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="k">return</span> <span class="nx">x</span> <span class="o">%</span> <span class="nx">n</span> <span class="o">===</span> <span class="mi">0</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kd">var</span> <span class="nx">nums</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">8</span><span class="p">];</span>
</span><span class='line'>
</span><span class='line'><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">filter</span><span class="p">(</span><span class="nx">nums</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">x</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="k">return</span> <span class="nx">modN</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="nx">x</span><span class="p">);</span>
</span><span class='line'><span class="p">}));</span>
</span><span class='line'>
</span><span class='line'><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">filter</span><span class="p">(</span><span class="nx">nums</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">x</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="k">return</span> <span class="nx">modN</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="nx">x</span><span class="p">);</span>
</span><span class='line'><span class="p">}));</span>
</span></code></pre></td></tr></table></div></figure>
<!-- more -->
<p>执行输出</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="mi">2</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">6</span><span class="p">,</span><span class="mi">8</span>
</span><span class='line'><span class="mi">3</span><span class="p">,</span><span class="mi">6</span>
</span></code></pre></td></tr></table></div></figure>
<p>modN函数有2个参数, 示例中可以同时提供所有的参数, 当然这是相当理想的情况. 实际可能不同的参数在不同的阶段提供:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="kd">var</span> <span class="nx">p</span> <span class="o">=</span> <span class="p">[</span><span class="mi">2</span><span class="p">];</span> <span class="c1">// 提供相关参数</span>
</span><span class='line'><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">filter</span><span class="p">(</span><span class="nx">nums</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">x</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">p</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">x</span><span class="p">;</span>
</span><span class='line'> <span class="k">return</span> <span class="nx">modN</span><span class="p">.</span><span class="nx">apply</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="nx">p</span><span class="p">);</span>
</span><span class='line'><span class="p">}));</span>
</span><span class='line'>
</span><span class='line'><span class="nx">p</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span> <span class="c1">// 提供相关参数</span>
</span><span class='line'><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">filter</span><span class="p">(</span><span class="nx">nums</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">x</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">p</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">x</span>
</span><span class='line'> <span class="k">return</span> <span class="nx">modN</span><span class="p">.</span><span class="nx">apply</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="nx">p</span><span class="p">);</span>
</span><span class='line'><span class="p">}));</span>
</span></code></pre></td></tr></table></div></figure>
<p>这种方式需要有一个变量用来保存参数, 而如果使用Currying可以这样:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">filter</span><span class="p">(</span><span class="nx">nums</span><span class="p">,</span> <span class="nx">modN</span><span class="p">.</span><span class="nx">curry</span><span class="p">(</span><span class="mi">2</span><span class="p">)));</span>
</span><span class='line'><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">filter</span><span class="p">(</span><span class="nx">nums</span><span class="p">,</span> <span class="nx">modN</span><span class="p">.</span><span class="nx">curry</span><span class="p">(</span><span class="mi">3</span><span class="p">)));</span>
</span></code></pre></td></tr></table></div></figure>
<p>根据需要可以<code>curry()</code>多个参数或<code>curry()</code>多次. 上文中使用的<code>curry</code>函数的实现:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="nb">Function</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">curry</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="kd">var</span> <span class="nx">func</span> <span class="o">=</span> <span class="k">this</span><span class="p">,</span>
</span><span class='line'> <span class="nx">p</span> <span class="o">=</span> <span class="nb">Array</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">slice</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="nx">arguments</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</span><span class='line'> <span class="k">return</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="k">return</span> <span class="nx">func</span><span class="p">.</span><span class="nx">apply</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="nx">p</span><span class="p">.</span><span class="nx">concat</span><span class="p">.</span><span class="nx">apply</span><span class="p">(</span><span class="nx">p</span><span class="p">,</span> <span class="nx">arguments</span><span class="p">));</span>
</span><span class='line'> <span class="p">};</span>
</span><span class='line'><span class="p">};</span>
</span></code></pre></td></tr></table></div></figure>
<p>这是最轻量级 最简单的实现方式, 深入挖掘Javascript语言的表达力应该还会出现更巧妙的设计.</p>
<h2>Currying的来由</h2>
<p>考虑体积计算公式<code>体积 = 长 x 宽 x 高</code>, 假设已知长为10, 那么这个公式就变成了<code>体积 = 10 x 宽 x 高</code>, 进一步已知宽为7, 那么公式就变为<code>体积 = 10 x 7 x 高</code>, 这种转换即Currying.</p>
<p>这是最通俗的描述, 比较正式的可以参考<a href="http://www.wikipedia.org/">维基百科</a>的<a href="http://en.wikipedia.org/wiki/Currying">Currying</a>词条.</p>
<h2>Scala语言中的Currying</h2>
<p>之所以要额外提<a href="http://www.scala-lang.org/">Scala</a>, 是因为它是原生支持Currying的语言, 相对比通过类库支持能提供更巧妙的语法, 参见下面的代码:</p>
<figure class='code'><figcaption><span>A Tour of Scala: Currying </span><a href='http://www.scala-lang.org/node/135'>来源</a></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
</pre></td><td class='code'><pre><code class='scala'><span class='line'><span class="k">object</span> <span class="nc">CurryTest</span> <span class="k">extends</span> <span class="nc">Application</span> <span class="o">{</span>
</span><span class='line'>
</span><span class='line'> <span class="c1">// 这种声明就是支持Currying的函数, 每个参数用 ( ) 分隔开</span>
</span><span class='line'> <span class="k">def</span> <span class="n">modN</span><span class="o">(</span><span class="n">n</span><span class="k">:</span> <span class="kt">Int</span><span class="o">)(</span><span class="n">x</span><span class="k">:</span> <span class="kt">Int</span><span class="o">)</span> <span class="k">=</span> <span class="o">((</span><span class="n">x</span> <span class="o">%</span> <span class="n">n</span><span class="o">)</span> <span class="o">==</span> <span class="mi">0</span><span class="o">)</span>
</span><span class='line'>
</span><span class='line'> <span class="c1">// 参数p是有1个Int类型参数的函数, 返回Boolean类型</span>
</span><span class='line'> <span class="k">def</span> <span class="n">filter</span><span class="o">(</span><span class="n">xs</span><span class="k">:</span> <span class="kt">List</span><span class="o">[</span><span class="kt">Int</span><span class="o">],</span> <span class="n">p</span><span class="k">:</span> <span class="kt">Int</span> <span class="o">=></span> <span class="nc">Boolean</span><span class="o">)</span><span class="k">:</span> <span class="kt">List</span><span class="o">[</span><span class="kt">Int</span><span class="o">]</span> <span class="k">=</span>
</span><span class='line'> <span class="k">if</span> <span class="o">(</span><span class="n">xs</span><span class="o">.</span><span class="n">isEmpty</span><span class="o">)</span> <span class="n">xs</span>
</span><span class='line'> <span class="k">else</span> <span class="k">if</span> <span class="o">(</span><span class="n">p</span><span class="o">(</span><span class="n">xs</span><span class="o">.</span><span class="n">head</span><span class="o">))</span> <span class="n">xs</span><span class="o">.</span><span class="n">head</span> <span class="o">::</span> <span class="n">filter</span><span class="o">(</span><span class="n">xs</span><span class="o">.</span><span class="n">tail</span><span class="o">,</span> <span class="n">p</span><span class="o">)</span>
</span><span class='line'> <span class="k">else</span> <span class="n">filter</span><span class="o">(</span><span class="n">xs</span><span class="o">.</span><span class="n">tail</span><span class="o">,</span> <span class="n">p</span><span class="o">)</span>
</span><span class='line'>
</span><span class='line'> <span class="k">val</span> <span class="n">nums</span> <span class="k">=</span> <span class="nc">List</span><span class="o">(</span><span class="mi">1</span><span class="o">,</span> <span class="mi">2</span><span class="o">,</span> <span class="mi">3</span><span class="o">,</span> <span class="mi">4</span><span class="o">,</span> <span class="mi">5</span><span class="o">,</span> <span class="mi">6</span><span class="o">,</span> <span class="mi">7</span><span class="o">,</span> <span class="mi">8</span><span class="o">)</span>
</span><span class='line'>
</span><span class='line'> <span class="c1">// modN2引用的是包含1个Int类型参数, 并返回Boolean类型的函数, 结尾的下划线是Scala中的语法</span>
</span><span class='line'> <span class="k">val</span> <span class="n">modN2</span> <span class="k">=</span> <span class="n">modN</span><span class="o">(</span><span class="mi">2</span><span class="o">)</span><span class="k">_</span>
</span><span class='line'> <span class="n">println</span><span class="o">(</span><span class="n">filter</span><span class="o">(</span><span class="n">nums</span><span class="o">,</span> <span class="n">modN2</span><span class="o">))</span>
</span><span class='line'>
</span><span class='line'> <span class="c1">// 不需要赋值的就不需要结尾的下划线了</span>
</span><span class='line'> <span class="n">println</span><span class="o">(</span><span class="n">filter</span><span class="o">(</span><span class="n">nums</span><span class="o">,</span> <span class="n">modN</span><span class="o">(</span><span class="mi">3</span><span class="o">)))</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>
<p>上述代码只是加了额外的注释, 调整了下顺序, 和来源中的代码等价.</p>
<p>最重要的, <a href="http://www.scala-lang.org/">Scala</a>是静态类型语言, 开发环境可以提供每次<code>Currying</code>之后的<strong>函数提示信息</strong>, 并能够做<strong>编译时检查</strong>, 而<a href="http://groovy.codehaus.org/">Groovy</a>, <a href="http://www.python.org/">Python</a>, Javascript只能依赖约定, 错误会在运行时发生, 必须有其它的措施确保同步修改关联的代码.</p>
<h2>偏函数 Partial function</h2>
<p>可以译作偏函数, 即提供部分参数值的函数, 和Currying很像, 只是另外一种更灵活的语法, 可以不按照参数顺序提供参数.</p>
<p>在<a href="http://ejohn.org/blog/">John Resig</a>的Blog有一篇<a href="http://ejohn.org/blog/partial-functions-in-javascript/">介绍Partial function和Currying的文章</a>, 贴个简单的代码片段:</p>
<figure class='code'><figcaption><span>Partial Application in JavaScript </span><a href='http://ejohn.org/blog/partial-functions-in-javascript/'>代码来源</a></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'> <span class="kd">var</span> <span class="nx">delay</span> <span class="o">=</span> <span class="nx">setTimeout</span><span class="p">.</span><span class="nx">partial</span><span class="p">(</span><span class="kc">undefined</span><span class="p">,</span> <span class="mi">10</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">delay</span><span class="p">(</span><span class="kd">function</span><span class="p">(){</span>
</span><span class='line'> <span class="nx">alert</span><span class="p">(</span> <span class="s2">"A call to this function will be temporarily delayed."</span> <span class="p">);</span>
</span><span class='line'> <span class="p">});</span>
</span></code></pre></td></tr></table></div></figure>
<p><code>partial()</code>的实现:</p>
<figure class='code'><figcaption><span>Partial Application in JavaScript </span><a href='http://ejohn.org/blog/partial-functions-in-javascript/'>代码来源</a></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="nb">Function</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">partial</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(){</span>
</span><span class='line'> <span class="kd">var</span> <span class="nx">fn</span> <span class="o">=</span> <span class="k">this</span><span class="p">,</span> <span class="nx">args</span> <span class="o">=</span> <span class="nb">Array</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">slice</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="nx">arguments</span><span class="p">);</span>
</span><span class='line'> <span class="k">return</span> <span class="kd">function</span><span class="p">(){</span>
</span><span class='line'> <span class="kd">var</span> <span class="nx">arg</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span><span class='line'> <span class="k">for</span> <span class="p">(</span> <span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o"><</span> <span class="nx">args</span><span class="p">.</span><span class="nx">length</span> <span class="o">&&</span> <span class="nx">arg</span> <span class="o"><</span> <span class="nx">arguments</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span> <span class="p">)</span>
</span><span class='line'> <span class="k">if</span> <span class="p">(</span> <span class="nx">args</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="o">===</span> <span class="kc">undefined</span> <span class="p">)</span>
</span><span class='line'> <span class="nx">args</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="o">=</span> <span class="nx">arguments</span><span class="p">[</span><span class="nx">arg</span><span class="o">++</span><span class="p">];</span>
</span><span class='line'> <span class="k">return</span> <span class="nx">fn</span><span class="p">.</span><span class="nx">apply</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="nx">args</span><span class="p">);</span>
</span><span class='line'> <span class="p">};</span>
</span><span class='line'><span class="p">};</span>
</span></code></pre></td></tr></table></div></figure>
<p>里面还有一个<code>curry</code>函数, 基本和上文中的差不多, 有兴趣的可以点<a href="http://ejohn.org/blog/partial-functions-in-javascript/">Partial Application in JavaScript</a></p>
<p><a href="http://www.scala-lang.org/">Scala</a>也有Partial function的实现, 依旧是静态类型, 示例代码:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='scala'><span class='line'><span class="k">def</span> <span class="n">add</span><span class="o">(</span><span class="n">i</span><span class="k">:</span> <span class="kt">Int</span><span class="o">,</span> <span class="n">j</span><span class="k">:</span> <span class="kt">Int</span><span class="o">)</span> <span class="k">=</span> <span class="n">i</span> <span class="o">+</span> <span class="n">j</span>
</span><span class='line'><span class="k">val</span> <span class="n">add5</span> <span class="k">=</span> <span class="n">add</span><span class="o">(</span><span class="k">_:</span> <span class="kt">Int</span><span class="o">,</span> <span class="mi">5</span><span class="o">)</span>
</span><span class='line'><span class="n">println</span><span class="o">(</span><span class="n">add5</span><span class="o">(</span><span class="mi">2</span><span class="o">))</span>
</span></code></pre></td></tr></table></div></figure>
<p>参考[Wikipedia][]的<a href="http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application">Contrast with partial function application</a> 和 <a href="http://en.wikipedia.org/wiki/Partial_function">Partial function</a></p>
<h2>Javascript中更常见的传递大量参数的方式</h2>
<p>Javascript是动态语言, 开发环境无法提供太多提示信息, 上文提到的Currying更适合一些比较稳定的, 不经常变动的API.</p>
<p>实际项目中如果函数参数很多, 并且可能在不同的地方提供参数, 则会使用参数对象的方式:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="kd">function</span> <span class="nx">modN</span><span class="p">(</span><span class="nx">opt</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">opt</span><span class="p">.</span><span class="nx">num</span> <span class="o">=</span> <span class="nx">opt</span><span class="p">.</span><span class="nx">num</span> <span class="o">||</span> <span class="mi">1</span><span class="p">;</span>
</span><span class='line'> <span class="nx">opt</span><span class="p">.</span><span class="nx">x</span> <span class="o">=</span> <span class="nx">opt</span><span class="p">.</span><span class="nx">x</span> <span class="o">||</span> <span class="mi">1</span><span class="p">;</span>
</span><span class='line'> <span class="k">return</span> <span class="nx">opt</span><span class="p">.</span><span class="nx">x</span> <span class="o">%</span> <span class="nx">opt</span><span class="p">.</span><span class="nx">num</span> <span class="o">===</span> <span class="mi">0</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="kd">var</span> <span class="nx">opt2</span> <span class="o">=</span> <span class="p">{</span> <span class="nx">num</span><span class="o">:</span> <span class="mi">2</span> <span class="p">},</span>
</span><span class='line'> <span class="nx">opt3</span> <span class="o">=</span> <span class="p">{</span> <span class="nx">num</span><span class="o">:</span> <span class="mi">3</span> <span class="p">};</span>
</span><span class='line'>
</span><span class='line'><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">filter</span><span class="p">(</span><span class="nx">nums</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">x</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">opt2</span><span class="p">.</span><span class="nx">x</span> <span class="o">=</span> <span class="nx">x</span><span class="p">;</span>
</span><span class='line'> <span class="k">return</span> <span class="nx">modN</span><span class="p">(</span><span class="nx">opt2</span><span class="p">);</span>
</span><span class='line'><span class="p">}));</span>
</span><span class='line'>
</span><span class='line'><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">filter</span><span class="p">(</span><span class="nx">nums</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">x</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">opt3</span><span class="p">.</span><span class="nx">x</span> <span class="o">=</span> <span class="nx">x</span><span class="p">;</span>
</span><span class='line'> <span class="k">return</span> <span class="nx">modN</span><span class="p">(</span><span class="nx">opt3</span><span class="p">);</span>
</span><span class='line'><span class="p">}));</span>
</span></code></pre></td></tr></table></div></figure>
<p>这个看起来和Builder模式十分相像, 参数都提供有默认值, <code>num</code>和<code>x</code>可以使用更有意义的名称以使阅读性更好一些, 但也付出了不少编码工作.</p>
<p>从<a href="http://www.mozilla.org/en-US/firefox/fx/#desktop">Firefox 2.0</a>开始支持<strong>解构赋值</strong><a href="https://developer.mozilla.org/en-US/docs/JavaScript/New_in_JavaScript/1.7#Destructuring_assignment_%28Merge_into_own_page.2Fsection%29">New in JavaScript 1.7: Destructuring assignment</a>, 这个特性可以让实现<code>modN</code>少了一些纠结:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="kd">function</span> <span class="nx">modN</span><span class="p">(</span><span class="nx">opt</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="kd">var</span> <span class="p">{</span> <span class="nx">num</span><span class="p">,</span> <span class="nx">x</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">opt</span><span class="p">;</span>
</span><span class='line'> <span class="nx">num</span> <span class="o">=</span> <span class="nx">num</span> <span class="o">||</span> <span class="mi">1</span><span class="p">;</span>
</span><span class='line'> <span class="nx">x</span> <span class="o">=</span> <span class="nx">x</span> <span class="o">||</span> <span class="mi">1</span><span class="p">;</span>
</span><span class='line'> <span class="k">return</span> <span class="nx">x</span> <span class="o">%</span> <span class="nx">num</span> <span class="o">===</span> <span class="mi">0</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>
<p>原文中还有解构赋值的很多<a href="https://developer.mozilla.org/en-US/docs/JavaScript/New_in_JavaScript/1.7#Looping_across_values_in_an_array_of_objects">高级用法</a>, 但是到目前为之还没看到其它浏览器提供支持, 也没有进入ECMAScript标准, 只能在比如Firefox扩展开发时爽爽.</p>
<h2>参考资料</h2>
<ul>
<li><a href="http://www.cnblogs.com/fox23/archive/2009/10/22/intro-to-Lambda-calculus-and-currying.html">Lambda演算与科里化(Currying)</a></li>
<li><a href="http://book.51cto.com/art/200806/77578.htm">《JavaScript王者归来》第二十二章 科里化(Currying)小节</a></li>
<li><a href="http://www.ibm.com/developerworks/cn/java/j-pg08235/">实战 Groovy: 用 curry 过的闭包进行函数式编程</a></li>
<li><a href="http://code.activestate.com/recipes/52549/">curry – associating parameters with a function (Python recipe)</a></li>
<li><a href="http://www.scala-lang.org/node/135">A Tour of Scala: Currying</a></li>
<li><a href="http://www.ibm.com/developerworks/cn/java/j-cb12196/">跨越边界: JavaScript 语言特性</a></li>
<li><a href="http://zh.wikipedia.org/wiki/%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0">维基百科 高阶函数 词条</a></li>
<li><a href="http://en.wikipedia.org/wiki/Currying">维基百科 Currying 词条</a></li>
<li><a href="http://en.wikipedia.org/wiki/Partial_function">维基百科 Partial function 词条</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/JavaScript/New_in_JavaScript/1.7#Destructuring_assignment_%28Merge_into_own_page.2Fsection%29">New in JavaScript 1.7 : Destructuring assignment 解构赋值</a></li>
</ul>
<p><a href="http://netwjx.github.com/blog/2012/12/05/function-currying-in-javascript-and-scala/#comments">查看评论</a></p>]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Dropbox, Stack Overflow 和 Ruby on Rails 杂念]]></title>
<category term="Book" />
<category term="IT" />
<category term="Memo" />
<category term="Saas" />
<link href="http://netwjx.github.com/blog/2012/11/24/dropbox-stack-overflow-and-ruby-on-rails/"/>
<author>
<name><![CDATA[netwjx]]></name>
<uri>http://netwjx.github.com/</uri>
</author>
<published>2012-11-24T21:08:00+08:00</published>
<updated>2012-11-24T21:08:00+08:00</updated>
<id>http://netwjx.github.com/blog/2012/11/24/dropbox-stack-overflow-and-ruby-on-rails</id>
<content type="html"><![CDATA[<p>它们有什么联系? 其实没什么特别的联系, 所以是杂念, 没什么头绪, 就是想到了, 我一个个说来.</p>
<h2>Dropbox的故事</h2>
<p><a href="http://dropbox.com/">Dropbox</a>是很出名的网盘服务, 也可以叫它云端存储服务, 它的客户端能够自动同步多个电脑间的文件夹, 当然这个功能在现在十分常见了, 只是在他出现之前, 多数网盘服务都是以Web形式为主的. 它给免费用户提供2G空间, 通过邀请其它用户可以扩容空间, 基本上后来的网盘都是这种套路. 额外还有根据订购的套餐按月付费.</p>
<p><a href="http://ycombinator.com/">Y Combinator</a>是一家很有意思的风险投资公司, 它只向最早期的创业团队投资. 而<a href="http://dropbox.com/">Dropbox</a>是它最成功的投资之一.</p>
<p><img class="right" src="http://www.ruanyifeng.com/images/hnp_cover_b.jpg" width="318" title="Hackers and Painters" ></p>
<p><a href="http://ycombinator.com/">Y Combinator</a>的创始人是<a href="http://www.paulgraham.com/">Paul Grahm</a>, 被誉为<a href="http://www.programmer.com.cn/11408/">硅谷创业之父</a>, 他曾经从事过程序员的工作. <a href="http://www.ruanyifeng.com/blog/">阮一峰的网络日志</a> <a href="http://www.ruanyifeng.com/blog/2009/12/i_will_translate_paul_graham.html">我要翻译Paul Graham了</a>上面介绍的很不错, 引用首段:</p>
<blockquote><p>下面,我就告诉你,我为什么那么想翻译Paul Graham。</p><p>他1964年出生于英国,在康奈尔大学读完本科,然后在哈佛大学获得计算机科学博士学位。1995年,他创办了Viaweb,帮助个人用户在网上开店,这是世界上第一个互联网应用程序。1998年夏天,Yahoo!公司收购了Viaweb,收购价约为5000万美元。</p><p>此后,他架起了个人网站paulgraham.com,在上面撰写了许许多多关于软件和创业的文章,以深刻的见解和清晰的表达而著称,迅速引起了轰动。2005年,他身体力行,创建了风险投资公司Y Combinator,将自己的理论转化为实践,目前已经资助了80多家创业公司。现在,他是公认的互联网创业权威。</p><footer><strong>阮一峰</strong> <cite><a href='http://www.ruanyifeng.com/blog/2009/12/i_will_translate_paul_graham.html'>我要翻译Paul Graham了</a></cite></footer></blockquote>
<!-- more -->
<p>这就引出了<a href="http://www.paulgraham.com/">Paul Grahm</a>写的书<a href="http://www.amazon.com/exec/obidos/tg/detail/-/0596006624">Hackers and Painters: Big Ideas from the Computer Age</a>, 注意英文副标题, 可以直译为<strong>计算机时代的伟大想法</strong>. 这本书的中译版是<a href="http://www.ruanyifeng.com/docs/pg/">黑客与画家</a>, 译者是上面提到的<a href="http://www.ruanyifeng.com/blog/">阮一峰</a>.</p>
<p>这里有一个有趣的故事, <a href="http://www.syncoo.com/why-dropbox-is-more-popular-than-similar-tools.htm">为什么 Dropbox 比其它同类产品更受欢迎?</a> 有趣的在于其中回答这个问题的人中有<a href="http://dropbox.com/">Dropbox</a>的竞争产品 - <a href="http://www.syncplicity.com/">Syncplicity</a>的联合创始人, 其中不乏他的多年思考总结, 以及一些行业的内幕轶事.</p>
<p>这是<a href="http://dropbox.com/">Dropbox</a>的故事.</p>
<h2>Stack Overflow的故事</h2>
<p><a href="http://stackoverflow.com/">Stack Overflow</a>是一个免费的问答网站, 很类似国内的<a href="http://zhidao.baidu.com/">百度知道</a>, 不过它有浓郁的Geek和技术文化, <code>Stack Overflow</code>在程序中是堆栈溢出错误, 这是软件开发工作中一种很棘手, 很不容易处理的严重错误, <a href="http://stackoverflow.com/">Stack Overflow</a>还有相关的其它领域的一系列问答网站, 如体育, 各种外语, 电影电视, 个人理财等.</p>
<p>对我来说, 我日常工作中Google搜索问题时, 能在<a href="http://stackoverflow.com/">Stack Overflow</a>上得到十分有价值的答案, 甚至可以将工作分为<a href="http://heikezhi.com/2011/05/12/does-stackoverflow-make-us-lazy/">有Stack Overflow前和有了Stack Overflow之后</a>.</p>
<p><a href="http://stackoverflow.com/">Stack Overflow</a>属于<a href="http://stackexchange.com/">Stack Exchange</a>公司的产品, <a href="http://stackexchange.com/">Stack Exchange</a>下的一系列问答网站全都没有广告, 也没有向用户收费的服务, <a href="http://stackexchange.com/">Stack Exchange</a>也获得了风险投资, 不过这里要说的是在哪之前.</p>
<p><a href="http://www.joelonsoftware.com/">Joel Spolsky</a>是<a href="http://stackexchange.com/about/team">Stack Exchange的联合创始人</a>, 可以看到<a href="http://stackexchange.com/">Stack Exchange</a>团队很多人耍宝的GIF动画, <a href="http://www.joelonsoftware.com/">Joel Spolsky</a>同时也是<a href="http://www.fogcreek.com/">Fog Creek</a>的创始人, <a href="http://www.fogcreek.com/">Fog Creek</a>有一些不错的团队协作产品:</p>
<ul>
<li><a href="https://trello.com/">Trello</a> 在线协作工具, 在一个界面上组织多个项目, 实时沟通, 分派任务等.</li>
<li><a href="http://www.fogcreek.com/fogbugz/">FogBugz</a> Bug跟踪工具, 在线申请立即开通, 可以和第三方工具和服务集成.</li>
<li><a href="http://www.fogcreek.com/kiln/">Kiln</a> 分布式版本控制系统(基于<a href="http://mercurial.selenic.com/">Mercurial</a>), 代码审查工具, 仍然是在线申请开通, 可以和FogBugz集成.</li>
<li><a href="https://www.copilot.com/">Copilot</a> 提供在线技术支持, 主要是修正电脑使用中的一些问题.</li>
</ul>
<p>除了<a href="https://trello.com/">Trello</a>是免费的外(无广告), 其它的都是免费试用 + 根据套餐按月付费, 提供基于Web和移动平台的客户端.</p>
<p><img class="right" src="http://i260.photobucket.com/albums/ii7/ruanyf/blog/bg2009120201.jpg" width="318" title="软件随想录" ></p>
<p><a href="http://www.joelonsoftware.com/">Joel Spolsky</a>的个人Blog名字叫<a href="http://www.joelonsoftware.com/">Joel on Software</a>, 他将自己Blog上的一些文章整理到一起, 出了本书叫<a href="http://www.amazon.com/More-Joel-Software-Occasionally-Developers/dp/1430209879">More Joel on Software</a>, 国内有出中文翻译<a href="http://www.ruanyifeng.com/mjos/">软件随想录</a>, 译者还是上文提到的<a href="http://www.ruanyifeng.com/blog/">阮一峰</a>, <a href="http://www.ruanyifeng.com/mjos/">点击这里</a>进去可以看到部分篇章, 里面讨论了软件开发中很多有趣的话题.</p>
<p>这里引用一段<a href="http://www.joelonsoftware.com/">Joel Spolsky</a>的介绍:</p>
<blockquote><p>Joel Spolsky(乔尔•斯波尔斯基)是一个世界闻名的软件开发流程专家。</p><p>他的网站“Joel谈软件”在全世界程序员中非常流行,被译成了30多种语言。</p><p>作为纽约的Fog Creek Software公司的创始人,他开发了FogBugz软件,这是一个在软件开发团队中非常流行的项目管理系统。</p><p>Joel曾经在微软公司工作,是Excel开发团队的一员,他设计了VBA(Excel的宏语言)。他还曾在Juno Online Services公司工作,开发了几百万用户使用的互联网客户端。</p><p>他已经出版了三本书:User Interface Design for Programmers(《程序员之用户界面设计》,Apress, 2001),《Joel谈软件》(Joel on Software, Apress, 2004),以及Smart and Gets Things Done(《巧妙完成工作》,Apress, 2007)。</p><p>他还是The Best Software Writing I(《最佳软件文选(第一辑)》,Apress, 2005)的编辑。</p><p>Joel从耶鲁大学获得计算机科学本科学位。</p><p>他曾在以色列国防军(Israeli Defense Forces)中服伞兵役,并且是以色列哈纳顿集体农场(Kibbutz Hanaton)的共同创始人之一。</p><footer><strong>阮一峰</strong> <cite><a href='http://www.ruanyifeng.com/blog/2008/10/i_will_translate_more_joel_on_software.html'>我要翻译《Joel on Software》了!</a></cite></footer></blockquote>
<p>这是<a href="http://stackoverflow.com/">Stack Overflow</a>的故事.</p>
<h2>Ruby on Rails的故事</h2>
<p><a href="http://rubyonrails.org/">Ruby on Rails</a>是我在做Java工程师时接触到的, 感叹它巧妙的设计, 在当时给Java世界带来了巨大的震撼, 原来Web应用也可以这样开发! 时至今日, <a href="http://rubyonrails.org/">Ruby on Rails</a>依然是<a href="http://www.ruby-lang.org/en/">Ruby</a>社区中的明星项目.</p>
<p>在之后的多年中我还陆续接触过<a href="http://groovy.codehaus.org/">Groovy</a> <a href="http://www.djangoproject.com/">Django</a> <a href="http://www.web2py.com/">web2py</a> <a href="http://www.playframework.org/">Apache Play</a> <a href="http://www.asp.net/mvc">ASP.Net MVC</a>, 它们或多或少都能看到<a href="http://rubyonrails.org/">Ruby on Rails</a>的影子.</p>
<p><img class="right" src="http://37signals.com/images/front-cover.png" width="318" title="REWORK: The new business book from 37signals." ></p>
<p><a href="http://rubyonrails.org/">Ruby on Rails</a>的作者是<a href="http://david.heinemeierhansson.com/">David Heinemeier Hansson</a>, 以下是他自己的简介, 我简单翻译成中文:</p>
<blockquote><p>我是Ruby on Rails的作者, 37signals的合伙人, 纽约时报(NYT)畅销书作家, 公开演说家, 业余摄影师, 和赛车手.</p><footer><strong>David Heinemeier Hansson</strong> <cite><a href='http://david.heinemeierhansson.com/'>David Heinemeier Hansson</a></cite></footer></blockquote>
<p>这里畅销书指的是<a href="http://37signals.com/rework">Rework</a>, 除了<a href="http://www.nytimes.com/">纽约时报(NYT)</a>外还有<a href="http://wsj.com/">华尔街日报(WSJ)</a>和<a href="http://www.thesundaytimes.co.uk/">The Sunday Times</a>, 由<a href="http://37signals.com/svn/writers/jf">Jason Fried</a>和<a href="http://david.heinemeierhansson.com/">David Heinemeier Hansson</a>合著, 封面是个揉了的纸团, 豆瓣网有<a href="http://book.douban.com/subject/5320866/">Rework</a>的中文简介.</p>
<p>还有一本<a href="http://gettingreal.37signals.com/">Getting Real</a>, 副标题是: 小规模,更快速,更高质量的软件构建方法, 翻译引用自<a href="http://cnborn.net/docs/getting_real/index.html">CNBorn</a>. 这是一本更多讲软件开发, 非技术方面的东西.</p>
<p>上面这两本书都可以<strong>免费</strong>从作者网站上下载的, 但是它们的实体书同样销售的不错, 也确实, 这种书需要反复的来回看, 领悟.</p>
<p><a href="http://37signals.com/">37signals</a>这家公司同样很有意思, 他们有几个在线协作产品:</p>
<ul>
<li><a href="http://basecamp.com/">Basecamp</a> 项目管理工具, 跟踪项目的讨论, 相关文件, 事件.</li>
<li><a href="http://highrisehq.com/">Highrise</a> 简单的CRM系统, 保存整理便笺和Email会话, 跟踪客户反馈和交易, 在公司 部门 团队中共享信息.</li>
<li><a href="http://campfirenow.com/">Campfire</a> 实时沟通, 类似IM, 但是专门设计用于小组.</li>
</ul>
<p>这些产品都是基于Web, 以及提供移动平台客户端, 并根据套餐按月付费.</p>
<p>他们有与众不同的内部工作方式, <a href="http://www.aqee.net/jason-fried-why-i-run-a-flat-company/">为什么我要把公司做成扁平型</a>, 作者是<a href="http://37signals.com/">37signals</a>的创始人<a href="http://37signals.com/svn/writers/jf">Jason Fried</a>.</p>
<p>在<a href="http://37signals.com/about">关于</a>还可以看到<a href="http://en.wikipedia.org/wiki/Jeff_Bezos">Jeff Bezos</a>, 他是作为<a href="http://37signals.com/">37signals</a>的顾问, 当然他更出名的是作为<a href="http://www.amazon.com/">亚马逊 Amazon.com</a>的创始人和CEO.</p>
<p>这是<a href="http://rubyonrails.org/">Ruby on Rails</a>的故事.</p>
<h2>末尾</h2>
<p>上面提到的网站和产品多数是英文的, 还有受限于我国的网络问题而无法访问.</p>
<p>上面提及的书基本都不涉及技术细节, 都很适合IT从业者反复阅读, 而<a href="http://37signals.com/rework">Rework</a>更是适合各种人群阅读.</p>
<p>即使未来不打算从事创业, 但是也很有助于辨别优秀的创业者, 合作方, 投资目标, 抑或是改善自己的日常工作</p>
<p>我仍旧无法用概括性的文字来描述我为什么要写上面的文字, 暂且作为对一些有趣资料的介绍吧.</p>
<p><a href="http://netwjx.github.com/blog/2012/11/24/dropbox-stack-overflow-and-ruby-on-rails/#comments">查看评论</a></p>]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Javascript异步加载]]></title>
<category term="Javascript" />
<link href="http://netwjx.github.com/blog/2012/11/04/javascript-async-load/"/>
<author>
<name><![CDATA[netwjx]]></name>
<uri>http://netwjx.github.com/</uri>
</author>
<published>2012-11-04T17:50:00+08:00</published>
<updated>2012-11-04T17:50:00+08:00</updated>
<id>http://netwjx.github.com/blog/2012/11/04/javascript-async-load</id>
<content type="html"><![CDATA[<p>这是8月份写了一份草稿, 但是一直都觉得这个主题组织起来比较纠结, 现在觉得不该再拖了, 先把之前的理解都整理出来吧.</p>
<p>异步加载这个名称不是很贴切, 实际上有三部分, 非阻塞(不暂停页面渲染) 下载 执行. 只是叫异步加载字数少点, 请不要完全从这个字面理解其意义.</p>
<p>主要用于外链的js文件, 会带来下面的好处:</p>
<ul>
<li>页面内容显示更快, 特别对于定义在<code><head></code>和文档开始处的外链js.</li>
<li>使用第三方Javascript时, 如果第三方无法访问, 也不会使页面很长时间是空白.</li>
<li>使用一些手法可以控制页面内容的显示顺序, 比如重要的先显示.</li>
<li>模块化Javascript, 使用<a href="#jsloader">Javascript模块加载器</a>管理大量相互依赖的Javascript.</li>
</ul>
<p>如果仅仅想页面内容显示的更快, 可以简单的把脚本放置在文档结尾, 比如<code></body></code>标签前.</p>
<p>异步加载的js文件有一个限制的:</p>
<ul>
<li>不能使用<code>document.write()</code>, 因为页面已经加载完成, 再调用会覆盖现有页面的内容.</li>
</ul>
<p>下面是异步加载的一些实现方式.</p>
<h2>使用script标签的defer属性</h2>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='html'><span class='line'><span class="nt"><script </span><span class="na">type=</span><span class="s">"text/javascript"</span> <span class="na">defer</span> <span class="na">src=</span><span class="s">"javascript.js"</span><span class="nt">></script></span>
</span></code></pre></td></tr></table></div></figure>
<p>使用了<code>defer</code>属性的<code><script></code>标签下载时不会暂停页面渲染, 当页面解析完后执行, 即常说的<code>DOM Ready</code>之后, <code>window load</code>之前.</p>
<p>如果有多个<code><script defer></code>将会按照DOM中的顺序执行, 多个前后依赖的脚本可以放心使用.</p>
<!-- more -->
<p><code>defer</code>属性在html 4中就定义了, 各浏览器兼容性如下:</p>
<ul>
<li>Chrome, Safari支持.</li>
<li>Firefox 3.5开始支持, 从3.6开始对行内脚本忽略<code>defer</code>属性, 将会立即执行.</li>
<li>IE 4开始支持, 对于行内脚本的<code>defer</code>属性IE6会有一些特殊的规则.</li>
<li>Opera 不支持.</li>
</ul>
<p>行内脚本(inline script)是指相对于使用<code>src</code>属性外链的脚本来说的, 即下面的代码:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='html'><span class='line'><span class="nt"><script </span><span class="na">type=</span><span class="s">"text/javascript"</span><span class="nt">></span>
</span><span class='line'> <span class="nx">alert</span><span class="p">(</span><span class="s1">'inline script'</span><span class="p">);</span>
</span><span class='line'><span class="nt"></script></span>
</span></code></pre></td></tr></table></div></figure>
<p>IE6中外链脚本的<code>defer</code>属性符合上文描述的规则, 但是行内脚本遵循下面的规则.</p>
<ul>
<li><code><head></code>中定义的会在<code><head></code>标签解析完成执行.</li>
<li><code><body></code>中定义的会在<code><body></code>标签解析完成执行.</li>
</ul>
<h2>使用script标签的async属性</h2>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='html'><span class='line'><span class="nt"><script </span><span class="na">type=</span><span class="s">"text/javascript"</span> <span class="na">async</span> <span class="na">src=</span><span class="s">"javascript.js"</span><span class="nt">></script></span>
</span></code></pre></td></tr></table></div></figure>
<p>使用了<code>async</code>属性的脚本下载时同样不会暂停页面渲染, 但是它会在下载完成时就执行, 在多个外链脚本时, 可能会有无法控制的执行顺序, 前后依赖的多个脚本不能使用这种方式加载.</p>
<p><code>async</code>属性在html 5中定义, 各浏览器兼容性如下:</p>
<ul>
<li>Chrome, Safari支持.</li>
<li>Firefox 3.6开始支持.</li>
<li>IE 10开始支持.</li>
<li>Opera不支持.</li>
</ul>
<h3>async和defer的异同</h3>
<ul>
<li>同样都可以在下载时不暂停页面渲染.</li>
<li>下载完<code>async</code>会立即执行, 而<code>defer</code>会在页面解析完按照DOM树中的顺序执行.</li>
</ul>
<p>如果浏览器支持的话, <code>async</code>的优先级比<code>defer</code>高, 即如果<code>async</code>为<code>true</code>的话, 会忽略<code>defer</code>属性.</p>
<h2>使用Javascript编码方式</h2>
<p>上述拥有<code>defer</code> <code>async</code>属性的<code><script></code>标签都可以通过Javascript编码方式插入到DOM树中, 代码如下:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class='html'><span class='line'><span class="nt"><script </span><span class="na">type=</span><span class="s">"text/javascript"</span><span class="nt">></span>
</span><span class='line'><span class="p">(</span><span class="kd">function</span><span class="p">(){</span>
</span><span class='line'> <span class="kd">var</span> <span class="nx">node</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="s1">'script'</span><span class="p">);</span>
</span><span class='line'> <span class="nx">node</span><span class="p">.</span><span class="nx">type</span> <span class="o">=</span> <span class="s1">'text/javascript'</span><span class="p">;</span>
</span><span class='line'> <span class="nx">node</span><span class="p">.</span><span class="nx">async</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span> <span class="c1">// 使用async, 请根据实际需要修改</span>
</span><span class='line'> <span class="nx">node</span><span class="p">.</span><span class="nx">defer</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span> <span class="c1">// 使用defer, 请根据实际需要修改</span>
</span><span class='line'> <span class="nx">node</span><span class="p">.</span><span class="nx">src</span> <span class="o">=</span> <span class="s1">'javascript.js'</span><span class="p">;</span>
</span><span class='line'> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementsByTagName</span><span class="p">(</span><span class="s1">'head'</span><span class="p">)[</span><span class="mi">0</span><span class="p">].</span><span class="nx">appendChild</span><span class="p">(</span><span class="nx">node</span><span class="p">);</span>
</span><span class='line'><span class="p">}());</span>
</span><span class='line'><span class="nt"></script></span>
</span></code></pre></td></tr></table></div></figure>
<p>上述代码适合放到<code><body></code>中, 因为<code><head></code>标签未解析完成的情况下不能插入元素.</p>
<p>也可以在页面加载后(<code>window.onload</code>)插入, 代码如下:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
</pre></td><td class='code'><pre><code class='html'><span class='line'><span class="nt"><script </span><span class="na">type=</span><span class="s">"text/javascript"</span><span class="nt">></span>
</span><span class='line'><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">w</span><span class="p">,</span> <span class="nx">d</span><span class="p">){</span>
</span><span class='line'> <span class="k">if</span> <span class="p">(</span><span class="nx">w</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">w</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s1">'load'</span><span class="p">,</span> <span class="nx">onLoad</span><span class="p">,</span> <span class="kc">false</span><span class="p">);</span>
</span><span class='line'> <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">w</span><span class="p">.</span><span class="nx">attachEvent</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">w</span><span class="p">.</span><span class="nx">attachEvent</span><span class="p">(</span><span class="s1">'onload'</span><span class="p">,</span> <span class="nx">onLoad</span><span class="p">);</span>
</span><span class='line'> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">w</span><span class="p">.</span><span class="nx">onload</span> <span class="o">=</span> <span class="nx">onLoad</span><span class="p">;</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'> <span class="kd">function</span> <span class="nx">onLoad</span><span class="p">(){</span>
</span><span class='line'> <span class="kd">var</span> <span class="nx">node</span> <span class="o">=</span> <span class="nx">d</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="s1">'script'</span><span class="p">);</span>
</span><span class='line'> <span class="nx">node</span><span class="p">.</span><span class="nx">type</span> <span class="o">=</span> <span class="s1">'text/javascript'</span><span class="p">;</span>
</span><span class='line'> <span class="nx">node</span><span class="p">.</span><span class="nx">src</span> <span class="o">=</span> <span class="s1">'javascript.js'</span><span class="p">;</span>
</span><span class='line'> <span class="nx">d</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">appendChild</span><span class="p">(</span><span class="nx">node</span><span class="p">);</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'><span class="p">}(</span><span class="nb">window</span><span class="p">,</span> <span class="nb">document</span><span class="p">));</span>
</span><span class='line'><span class="nt"></script></span>
</span></code></pre></td></tr></table></div></figure>
<p>更常用的是<code>DOM Ready</code>之后插入, 相对会更早点, 鉴于完整的<code>DOM Ready</code>代码量比较多, 下面例子使用jQuery的<code>DOM Ready</code>实现:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='html'><span class='line'><span class="nt"><script </span><span class="na">type=</span><span class="s">"text/javascript"</span><span class="nt">></span>
</span><span class='line'><span class="nx">jQuery</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">$</span><span class="p">){</span>
</span><span class='line'> <span class="kd">var</span> <span class="nx">file</span> <span class="o">=</span> <span class="s1">'javascript.js'</span><span class="p">;</span>
</span><span class='line'> <span class="nx">$</span><span class="p">(</span><span class="s1">'<script type="text/javascript">'</span><span class="p">).</span><span class="nx">attr</span><span class="p">(</span><span class="s1">'src'</span><span class="p">,</span> <span class="nx">file</span><span class="p">).</span><span class="nx">appendTo</span><span class="p">(</span><span class="s1">'head'</span><span class="p">);</span>
</span><span class='line'><span class="p">});</span>
</span><span class='line'><span class="nt"></script></span>
</span></code></pre></td></tr></table></div></figure>
<p>Javascript编码方式也是<a href="#jsloader">Javascript模块加载器</a>基本原理.</p>
<p><a name="jsloader"></a></p>
<h2>使用Javascript模块加载器</h2>
<p>这是更重量级的做法, 适用于大量互相依赖的Javascript的异步加载, 一般需要遵循模块加载器的规则编写自己的模块以用于异步加载.</p>
<p>下面是常见Javascript模块加载器和简单的使用代码.</p>
<h3>RequireJS</h3>
<p><a href="http://requirejs.org/">RequireJS</a></p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='html'><span class='line'><span class="nt"><head></span>
</span><span class='line'><span class="nt"><script </span><span class="na">data-main=</span><span class="s">"scripts/main"</span> <span class="na">src=</span><span class="s">"scripts/require.js"</span><span class="nt">></script></span>
</span><span class='line'><span class="c"><!-- RequireJS加载完成后会加载 scripts/main.js, 其内容见下面的代码 --></span>
</span><span class='line'><span class="nt"></head></span>
</span></code></pre></td></tr></table></div></figure>
<figure class='code'><figcaption><span>scripts/main.js</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="nx">require</span><span class="p">([</span><span class="s2">"helper/util"</span><span class="p">],</span> <span class="kd">function</span><span class="p">(</span><span class="nx">util</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="c1">// 这个函数会在 scripts/helper/util.js 加载后调用.</span>
</span><span class='line'> <span class="c1">// 参数 util 是 helper/util 模块, 其包括 helper/util.js 中使用 define() 定义的值和函数.</span>
</span><span class='line'><span class="p">});</span>
</span></code></pre></td></tr></table></div></figure>
<h3>Head JS</h3>
<p><a href="http://headjs.com/">Head JS</a> 除了提供加载js之外还可以加载css, css js和浏览器特性检测等. 这里只贴加载js的示例代码.</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='html'><span class='line'><span class="nt"><script </span><span class="na">type=</span><span class="s">"text/javascript"</span><span class="nt">></span>
</span><span class='line'><span class="nx">head</span><span class="p">.</span><span class="nx">js</span><span class="p">(</span><span class="s2">"/path/to/jquery.js"</span><span class="p">,</span> <span class="s2">"/google/analytics.js"</span><span class="p">,</span> <span class="s2">"/js/site.js"</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="c1">// all done</span>
</span><span class='line'><span class="p">});</span>
</span><span class='line'><span class="nt"></script></span>
</span></code></pre></td></tr></table></div></figure>
<h3>SeaJS</h3>
<p><a href="http://seajs.org">SeaJS</a> 是 <a href="https://github.com/lifesinger">lifesinger</a> 发起的项目, 提供有完整的中文文档和相关预编译, 打包部署工具. 并且其模块化API遵循<a href="http://www.commonjs.org/" title="CommonJS">CommonJS</a>的标准.</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='html'><span class='line'><span class="nt"><script </span><span class="na">src=</span><span class="s">"assets/sea-modules/seajs/1.3.0/sea.js"</span><span class="nt">></script></span>
</span><span class='line'><span class="nt"><script </span><span class="na">type=</span><span class="s">"text/javascript"</span><span class="nt">></span>
</span><span class='line'><span class="c1">// 加载入口模块</span>
</span><span class='line'><span class="nx">seajs</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="s1">'./assets/src/hello.js'</span><span class="p">);</span>
</span><span class='line'><span class="nt"></script></span>
</span></code></pre></td></tr></table></div></figure>
<figure class='code'><figcaption><span>/assets/src/hello.js</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="nx">define</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">require</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="c1">// 得到 Spinning 函数类</span>
</span><span class='line'> <span class="kd">var</span> <span class="nx">Spinning</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'./spinning'</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'> <span class="c1">// 初始化</span>
</span><span class='line'> <span class="kd">var</span> <span class="nx">s</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Spinning</span><span class="p">(</span><span class="s1">'#container'</span><span class="p">);</span>
</span><span class='line'> <span class="nx">s</span><span class="p">.</span><span class="nx">render</span><span class="p">();</span>
</span><span class='line'><span class="p">})</span>
</span></code></pre></td></tr></table></div></figure>
<p>使用spm打包部署</p>
<figure class='code'><figcaption><span>/assets/src/hello.js</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="nx">$</span> <span class="nx">cd</span> <span class="nx">hello</span><span class="o">-</span><span class="nx">seajs</span><span class="o">/</span><span class="nx">assets</span>
</span><span class='line'><span class="nx">$</span> <span class="nx">spm</span> <span class="nx">build</span>