-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
474 lines (259 loc) · 213 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
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Lazzzis</title>
<link href="https://blog.lazzzis.com/atom.xml" rel="self"/>
<link href="https://blog.lazzzis.com/"/>
<updated>2024-06-03T01:50:08.386Z</updated>
<id>https://blog.lazzzis.com/</id>
<author>
<name>lazzzis</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>近况及又双叒叕一次折腾主页</title>
<link href="https://blog.lazzzis.com/post/recent-updates-at-jun-2024/"/>
<id>https://blog.lazzzis.com/post/recent-updates-at-jun-2024/</id>
<published>2024-06-02T05:50:00.000Z</published>
<updated>2024-06-03T01:50:08.386Z</updated>
<content type="html"><![CDATA[<p>好久没更新了。<del>因为懒</del></p><p>最近把域名给续费了,为了假装它没吃灰,所以顺便把主页也更新一下。而且 23 年的总结也没写,一并附上。</p><span id="more"></span><h2 id="23-年总结"><a href="#23-年总结" class="headerlink" title="23 年总结"></a>23 年总结</h2><p>虽然没有写总结,但我自己还是在 notion 里尽量保持写周记的习惯,尽管有时候会拖延成月记。翻看记录,拖延的原因不外乎以下几点:</p><ol><li>无聊的一周</li><li>害怕记录无聊的一周</li></ol><p>第一不难理解,我出去玩的次数不是很多,也没整多少活,所以就没写什么。可话又说回来,想起了日常里那句经典的话:</p><p><img src="https://as2.bitinn.net/uploads/yw/ckncwzlfm000tjb8hb3ki2vyw.1080p.jpg" alt="我们每天度过的日常生活 其实也许是奇迹的连续"><span class="image-caption">我们每天度过的日常生活 其实也许是奇迹的连续</span></p><p>无聊的,更多的是我自己,即便我身上没有发生什么事,但周遭的事物确实一直变化的,无论是同事还是朋友,抑或是新闻,抑或是一条推特。现在回首看这些事物,即便我没有很多参与,但也有一种特殊的感觉,就是阅读一本故事书一样。或许当我回头看这些的时候,我是从一个上帝视角看待,就像看戏剧一样。但无论如何,除了我做的,我所见到的,也在悄然间改变了,构成了 “我” 的一部分。</p><p>第二点,或许是来自于一种自卑。当别人在外面游玩,在整活的时候,我似乎没有值得聊的话题。所以不想去思考,不想去面对,不想去理解,就没有去写,避免问自己为什么又度过了无聊的一周。</p><!-- ![they-dont-know](they-dont-know.png) --><h3 id="番剧"><a href="#番剧" class="headerlink" title="番剧"></a>番剧</h3><p><a href="https://bgm.xiadong.info/report/lazzzis?year=2023">番剧报告</a></p><p>看得有点少。当然有一部分原因是时间花到其它地方去了。</p><h3 id="音乐"><a href="#音乐" class="headerlink" title="音乐"></a>音乐</h3><p>原先用于看番的时间一部分是在练习木吉他。如 22 年的总结所说,木吉他的资源确实挺多,平均每个月都能学下一首曲子,自己也在 B 站和 Youtube 上传了一些视频,作为一种目标和激励。</p><div class="video-container"><iframe src="https://www.youtube.com/embed/kazZ6tlYU0Q" frameborder="0" loading="lazy" allowfullscreen></iframe></div><p>也想过试着作曲,下载 Vocaloid 6 和 Synthesizer V,想先从调教开始的。这里不得不说 SV 的 AI 效果真地吊打 Vocaloid 6 的 AI,更智能,更强大,可玩性更多。不过调教也算是较为后期的步骤了,即便是翻唱,先想好怎么扒谱更为实际。所以基本完了几周,就没有继续玩了。</p><p>后来还是下了 FL studio 学习,同样是一个很受欢迎的软件,资源很多,但到头来也只是学了学软件怎么用。一方面,有很多资源是讲电子音乐的,其实我这方面听得不多,并没有很多灵感,需要多听听大佬的增加点灵感;另一方面,也是最重要的,我的耳朵还不够敏感,缺少对和弦色彩的感知:我现在很多时候还是遵从理论,虽然保险,但很多时候听上去会很无聊,没有变化,因为我不知道我接下来想要怎样的音响效果,而即便知道了,为了这样的音响效果,我又该用什么和弦呢?我对属七,增七等和弦色彩的熟悉程度还远远不够。我还是需要在弹奏的时候,多尝试,多听才行。</p><h3 id="读书"><a href="#读书" class="headerlink" title="读书"></a>读书</h3><p><a href="https://neodb.social/users/lazzzis_10516/complete/book/">读书记录</a> 也不能说没读吧,但确实不多,而且有很多还是漫画,我并没有在这里标注出来。藤本树的《电锯人》但是一直在追,基本一本单行本出来就会去看。</p><h3 id="工作"><a href="#工作" class="headerlink" title="工作"></a>工作</h3><p>挺不想说这事的,因为工作就是工作,工作愈来愈细化,我也只负责一小部分,虽然在功能上线的时候,还能有点小小的喜悦,但终究不想在工作上花太多的时间。在上班时间把事情抓紧做完,然后下班折腾自己的爱好去,这一年大抵是这么过来的。</p><h3 id="旅行"><a href="#旅行" class="headerlink" title="旅行"></a>旅行</h3><p>印象比较深的两次是去温哥华和去中国。前者是为了后者做准备。</p><p>去温哥华主要是把 H1B 办出来,这样我能在离境的时候能再度踏上美国的领土。在温哥华一个旅行,没有车,但好在公共交通还不错,还去了 Victoria 玩了两天,好好的放松了一会。</p><p><img src="vancouver.jpg" alt="Vancouver"><span class="image-caption">Vancouver</span></p><p><img src="victoria.jpg" alt="Victoria"><span class="image-caption">Victoria</span></p><p>回到中国了几周,已经很不习惯了,无论是观念还是行为。尤其是见到以前的小伙伴大多也成家了,也有孩子了,相比之下,我成了被调侃的对象。大部分时间感觉并不自在,总感觉是在应酬,有一种莫名的疏远感。</p><h2 id="域名与博客"><a href="#域名与博客" class="headerlink" title="域名与博客"></a>域名与博客</h2><p>把域名续费了,顺便把主页重新设计了一下。去搜了一些主页,东拼西凑,加上自己的一些灵感,成了现在的样子。<a href="https://lazzzis.com/">链接</a>。</p><p>博客也好久没更了。说实话,现在更博客和看博客的人已经少很多了。现在获取信息的方式太快太碎片化了,我想要说点什么的话,发条推特就好了,没必要写文章。即使是长一点的内容,多几条推特连成一起就好了,哪用得着写成文章。所以我感觉,能写成文章的内容并不多了,所以即便更新,更新频率会是一个迷。当然,这里也涉及到上面所说的,可能因为是我很无聊,所以我才写不出什么(</p><p>总而言之,把博客的主题也换了。其实我这两天折腾了几个主题,目前用的这个还挺喜欢的,简洁但不失优雅。</p><h2 id="下次更新"><a href="#下次更新" class="headerlink" title="下次更新"></a>下次更新</h2><p>可以保证最晚是年底,因为年终总结还是要写写的。</p><p><img src="https://as2.bitinn.net/uploads/legacy/6r/cin2i0e4r00d1wjs5tat1ma6r.1200.jpg" alt="下次见"><span class="image-caption">下次见</span></p>]]></content>
<summary type="html"><p>好久没更新了。<del>因为懒</del></p>
<p>最近把域名给续费了,为了假装它没吃灰,所以顺便把主页也更新一下。而且 23 年的总结也没写,一并附上。</p></summary>
<category term="技术与工作" scheme="https://blog.lazzzis.com/categories/%E6%8A%80%E6%9C%AF%E4%B8%8E%E5%B7%A5%E4%BD%9C/"/>
<category term="近况及总结" scheme="https://blog.lazzzis.com/categories/%E8%BF%91%E5%86%B5%E5%8F%8A%E6%80%BB%E7%BB%93/"/>
</entry>
<entry>
<title>Clear 2022</title>
<link href="https://blog.lazzzis.com/post/the-end-of-2022/"/>
<id>https://blog.lazzzis.com/post/the-end-of-2022/</id>
<published>2022-12-30T18:01:30.000Z</published>
<updated>2024-06-02T05:48:26.003Z</updated>
<content type="html"><![CDATA[<blockquote><p>立ち上がるだけ 立ち上がるだけ 「LIVEWELL/椎名もた」</p></blockquote><span id="more"></span><p>今年比去年少了很多烦恼,总体上过得还挺舒畅。</p><h2 id="工作"><a href="#工作" class="headerlink" title="工作"></a>工作</h2><p>去年升了 L4 后,加上今年改成 GRAD,并且手上的项目没有 fully launch,所以今年就没考虑过升级的事。</p><p>去年开始就一直做一个升级一个基础 UI 组件的项目,因为这个组件被许多 feature team 使用,所以要先在一些 feature 上试验,接着根据反馈,优化 UI,继续在那些 feature 试验,如此反复,再将这个组件用于其它 feature。鉴于 Chrome 已经 4 周发布一个大版本,所以相较于以前的 6 周,能更快地获得用户的反馈,以及及早发现一些 bug。可即便如此,来来回回依旧是一年也没弄完。</p><p>另一件就是 Android 13 的发布,因为一些 API 被 deprecated 了,而恰好这个 API 我们非常依赖且被许多 feature 使用,所以花了点时间去 migrate 到新的 API 上。这个是年中开始的,且也进行了 A/B test。不过这过程没有一帆风顺,中间还是发现了些 bug,在修复后继续在后续几个大版本上重复试验。</p><p>可能对工作开始感到厌倦,有时候还是挺想逃避问题的,在一些摸不清头绪的 bug 面前,会想要摸鱼耗时间到下班后把问题丢到第二天。「逃避可耻且没用」,一方面 bug 就在那里,不去修就不会消失,另一方面,几年搬砖下来,也渐渐意识到 「The monster you are facing is actually toothless」。其实大部分我能搞出的莫名其妙的问题,最后发现也不过如此。</p><p>今年下半年有一波裁员潮,因为自己这边暂时没影响,所以也没太放在心上。但照这经济情况下去,多少还是对明年有些担忧。</p><h2 id="生活"><a href="#生活" class="headerlink" title="生活"></a>生活</h2><h3 id="设备"><a href="#设备" class="headerlink" title="设备"></a>设备</h3><p>本来今年没想要换电脑的,但万万没想到偏偏在三年之期时,电脑变砖了。我清楚记得这个设备是 2019 的黑五期间买的,而现在因为它变砖了,我也只能借着这个黑五继续入一个 mbp。其实以前还想过换 PC 的,但因为坏得太突然,数据以 Time Machine 的形式存在硬盘里,所以只能作罢,继续用 Mac。</p><blockquote class="twitter-tweet"><p lang="zh" dir="ltr">完了,蠢材吧说这台机器变砖了</p>— lazzzis (@lazzzis) <a href="https://twitter.com/lazzzis/status/1594132872905883648?ref_src=twsrc%5Etfw">November 20, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script><h3 id="动漫"><a href="#动漫" class="headerlink" title="动漫"></a>动漫</h3><p><a href="http://bgm.xiadong.info/report/lazzzis?year=2022">总结</a>。12 月因为假期所以看得多了点。但印象最深的是以下几部。</p><p><strong>白箱</strong></p><p>对于动漫制作的感兴趣的人不得不补的神作。几年前就知道这部剧,但当时动漫制作不感兴趣,所以没看。想补这部的契机是因为多次在 nbht 的视频里出现(</p><p><img src="shirobako.jpg" alt="いま、私、少しだけ夢に近づきました"><span class="image-caption">いま、私、少しだけ夢に近づきました</span></p><p>这个画面加上这句台词,着实让我泪崩。</p><p><strong>路人女主的养成方法</strong></p><p>虽然是后宫,但其中对作为 “创作者” 的她们的描写,更加令我印象深刻。印象最深的就是英梨梨被紅坂朱音怒斥 “你水平压根不够” 的情节。</p><p><img src="eriri.jpg" alt="你水平压根不够"><span class="image-caption">你水平压根不够</span></p><p>即便是自以为是突破了瓶颈期的天才画家,竟也有被碾压和怀疑人生的时候。“天赋,努力,瓶颈期” 是三个老生常谈的问题了,这些到底是原因,还是结果,抑或是借口?</p><p><strong>四叠半时光机布鲁斯</strong></p><p>有趣!</p><h3 id="阅读"><a href="#阅读" class="headerlink" title="阅读"></a>阅读</h3><p><strong>藤本タツキ</strong></p><p>在电锯人开播前,补完了电锯人第一部和他的另外两部单行本《Look Back》和《再见绘梨》。</p><p>关于《再见绘梨》的解读,我推荐 松野小路的动画笔记 的<a href="https://www.bilibili.com/video/BV1r34y1Y77X">解读</a>。</p><p>《再见绘梨》里有一句台词 “在结尾加上一句奇幻色彩”。看到这句话时,我其实想到的是我在 2020 年看的且也在年终总结里提到的「月曜日の友達」。这部作品虽然故事内容和画风上和《再见绘梨》截然不同,但都在一个看似正常的故事里加入了一个魔幻又美妙的结尾。同样值得推荐!</p><p><strong>其它</strong></p><p>今年阅读量相对偏少了点,能讲出来总共就四本《克拉拉与太阳》《牧羊少年奇幻之旅》《When Panic Attacks》《存在主义咖啡馆》。</p><p>前两部是小说,《克拉拉与太阳》非常值得推荐。《牧羊少年奇幻之旅》则因为其中莫名其妙的宗教部分而不是很喜欢。《When Panic Attacks》是心理调节的,里面列举了很多方法,其中有一些确实管用,但有一些则见仁见智了。《存在主义咖啡馆》这部有点像传记,读完后印象不深,不做评价。</p><h3 id="游戏"><a href="#游戏" class="headerlink" title="游戏"></a>游戏</h3><p>玩得最多的依旧是 Splatoon。不过 3 代现在还是有点失望。虽然肉眼可见在 UI 等细节上有很多提升,但核心部分的 PVP 现在很糟糕:看似武器数量很多,但大多是外表时髦的垃圾,能用的并不多,反倒不如 2 代末期的平衡。新增的 Big Run 则是大型内卷现场。</p><h2 id="兴趣"><a href="#兴趣" class="headerlink" title="兴趣"></a>兴趣</h2><h3 id="音乐"><a href="#音乐" class="headerlink" title="音乐"></a>音乐</h3><p>我特地翻了我以前的年终总结,发现早在 2016 年末就非常骄傲地说要学习音乐。现在在看当时的文章,那语气实在是太中二了!</p><p>就结果而言,从 2017 年开始到现在,我</p><ul><li>买了两次布鲁斯口琴(2018 年 和 2021 年)。但学了几个月后就没下文了,原因未知</li><li>买了一次电吉他(2017 年),还是 Fender Squier Stratocaster Pack。但不知学了多久也没下文了,大概是因为学业和找工作的关系。反正最后是在毕业时送人了</li><li>买了一把 Acoustic Bass(2019 年)。我还挺中意 Bass 的,尤其是听了 T-Square 和 Casiopea 为首的日本 Fusion Jazz 后。但这个甚至在一首曲子都没学会的情况下就放弃了。原因好像是当时心情抑郁,啥都不想干</li></ul><p>而今年,基于某些巧合(或是良机?),我又入了一把 Acoustic Guitar。但这次真的感觉到和前几次质的不同。</p><p>虽然总有人调侃有些流行的吉他民谣很没技术含量,翻来覆去就是 1645,但是在我看来,这些曲子恰好是很好的入门材料。它们简单易上手,随便学几下就能弹个段子,对提升自信心来说,是非常的有帮助。同样是简单的曲子,我觉得 Bass 的一个问题就是在这些曲子里,Bass 只能弹根音。虽然说把握好节奏弹好根音确实也需要点功夫,但相比之下,对初学者的我来说,Bass 初学时的乐趣真的少很多 – 简单的无聊,难的又太难。</p><p>另一方面,吉他真地有好多人玩呀!因为基数大,相对应的,教程是真地丰富,即便抛开 YTB,仅 B 站上每天就有很多曲子的教程和零基础的教程。就好比当初学编程,大部分人都是从 C/Java/Python 开始的,一方面确实简单,另一方面,资料也确实多呀!遇到什么问题,把报错放到网上,能搜到答案的概率也大很多。你硬要说,有人是从 Closure 和 Erlang 入门的,当然有,但大部分人还是会选择资料多的入手。当然,和选择具体哪个编程语言还会考虑实用性一样,吉他的实用性也确实多,弹唱有很多风格曲子可以选,指弹也是,以押尾为首的日系指弹也是很多人的入门原因。</p><p>虽然今年学的过程中磕磕绊绊有时候能因为一两个和弦转换磕上个三四天,,而且自己五音不全还要想办法学习一下唱歌,但却依旧觉得很有意思。即便有些真的很简单,可这就如同初学编程时敲出 “Hello World!” 一样,让人感觉神奇和欲罢不能。</p><p>木吉他也算是对成人非常友好的乐器了,相比于一些需要吃 “童子功” 的乐器来说,真的很容易上手了。</p><p>顺便推荐,今年听的比较多的曲目。首先是 Ryosuke Watanabe/渡辺良介 的专辑《Clear》。这是他的第一张专辑。此人是 2017 年的日本指弹冠军。这张专辑中的曲子我也是来回听了很多次,包括工作中也是很好的 BGM。</p><div class="video-container"><iframe src="https://www.youtube.com/embed/CHJSYmqA0a8" frameborder="0" loading="lazy" allowfullscreen></iframe></div><p>另一首是玉腰向輝的曲目。虽然没有在 2018 年拿到冠军,但我觉得这首曲子的完成度很高,是可以拿冠军的,但可惜失误有点多,尤其开篇时频繁打品,或许正是因此而错失冠军。即便如此,他在弹奏时沉浸于曲目中的表情和神态,仿佛在说:弹吉他真他妈开心!</p><div class="video-container"><iframe src="https://www.youtube.com/embed/-JUY5m--qWo" frameborder="0" loading="lazy" allowfullscreen></iframe></div><h3 id="画画"><a href="#画画" class="headerlink" title="画画"></a>画画</h3><p>感觉时间不够用了 —— 搁置。以后再入门一次。</p><h3 id="日语"><a href="#日语" class="headerlink" title="日语"></a>日语</h3><p>错过了 N2 报名时间。准备明年直接冲击 N1 试试。</p><h3 id="前端"><a href="#前端" class="headerlink" title="前端"></a>前端</h3><p>在 6 月和 7 月的时候发现自己有段时间没弄前端了,于是去读了一些开源项目的代码,并成功提交了一些 pr。不过之后就又没怎么弄了。</p><h2 id="それから"><a href="#それから" class="headerlink" title="それから"></a>それから</h2><p>明年的话,把今年错过的补上,以及把现在手头的坚持下去,我想就不错了。至于更细节的目标,慢慢规划吧。</p>]]></content>
<summary type="html"><blockquote>
<p>立ち上がるだけ 立ち上がるだけ 「LIVEWELL/椎名もた」</p>
</blockquote></summary>
<category term="近况及总结" scheme="https://blog.lazzzis.com/categories/%E8%BF%91%E5%86%B5%E5%8F%8A%E6%80%BB%E7%BB%93/"/>
<category term="自言自语" scheme="https://blog.lazzzis.com/tags/%E8%87%AA%E8%A8%80%E8%87%AA%E8%AF%AD/"/>
</entry>
<entry>
<title>さようなら、2021の全て</title>
<link href="https://blog.lazzzis.com/post/the-end-of-2021/"/>
<id>https://blog.lazzzis.com/post/the-end-of-2021/</id>
<published>2021-12-31T03:01:30.000Z</published>
<updated>2024-06-03T01:53:36.385Z</updated>
<content type="html"><![CDATA[<blockquote><p>笑ってよ 笑ってよ<br>この写真みたく<br>笑ってよ 笑ってよ<br>飾りつけてあげる<br>笑ってよ 笑ってよ<br>【sayonarawoiwazuni/椎名もた】</p></blockquote><span id="more"></span><h2 id="动漫"><a href="#动漫" class="headerlink" title="动漫"></a>动漫</h2><p>印象最深的是两部作品,一部是《Bojack Horseman》,另一部是《EVA》新剧场版终。</p><p>先讲前者,我单独写过一篇文章 (<a href="/post/exist-and-nihil/" title="咸鱼与存在">咸鱼与存在</a>) 讲这部作品对我的影响。简而言之,看这部作品的时候,我处于 Bojack Horseman 的那种状态,怀疑自己的存在价值,对这个世界失去了一点兴趣。是这部作品打开了我对存在主义这个观念的大门,让我有幸开始了解一点 20 世纪以来的一些思想。写完那篇文章后,已经半年过去了,我有变好吗?当然有一点,至少不是 Bojack Horseman 以前那种虚无的状态了。但有时候还是走入另一个极端 – Todd 那样的状态:尽管对生活的态度好了很多,可有时候真不知道该干些什么。应该说,我之前怀疑自己的存在也是因为自己不知道该做什么,认为一切没有价值,只不过现在态度变得积极了一点,愿意接受这个事实了:而对自己该干什么这件事仍然不清楚。</p><p>在第二季的第 5 集里,Todd 这么问 Princess Carolyn: “Princess Carolyn, I need something to do. A job, a task, or a direction in life…You’re my agent. Can you give my life meaning? … Princess Carolyn, do I have a purpose?”</p><p><img src="todd.jpeg" alt="Todd"><span class="image-caption">Todd</span></p><p>对于有时自己不知道自己该干些什么这件事,我有时候会感到些许羞愧。毕竟再过几年都要成为大魔法师了,而我还像个小孩子一样不成熟。现在想着,不管怎样,至少也该培养点兴趣,就像碇真嗣,即便他一度擅长逃避,也会在空闲时间拉一下大提琴,不至于无所事事。</p><p>说到 EVA,在看完那部终之后,我也写了一篇文章 – <a href="/post/shin-eva-end/" title="关于 EVA 终的感想">关于 EVA 终的感想</a>。我其实也才去年开始看 EVA,几乎是在一年内把 TV,旧剧场版,新剧场版看完了。面对三个结局,我心里其实更偏爱一点 TV 版的结局。当然,旧剧场版和新剧场版的结局也是很好的结局,至少这两者都真的把故事讲下去了,把故事讲完了,只不过前者表现得阴暗和消极了一点,应该算一个 Bad Ending,而后者则非常的明朗和积极,是一个非常棒的 Good Ending。与一些人的想法相反,我觉得 TV 版的结局反到十分直白,直白到直接把大道理都摆出来了:“現実を悪く嫌だと捉えているのは、君の心だ。”、“人の顔色ばかり うかがう必要なんてないのよ”、“自分が嫌いな人は他人を好きに信頼するようになれないわ”。配上结尾的 BGM《Good, or Don’t Be.》,我觉得制作组,尤其是庵野秀明,是真心希望那些厌恶自己,不敢面对世界的人能够喜欢自己,能够乐观地面对世界。</p><p>这个结尾,成为了这一年常常刷的一个片段。另一个经常刷的片段则是 TV 版里第 19 集里加持良治在西瓜田与真嗣的对话:</p><blockquote><p>シンジ君、俺はここで水をまくことしかできない、だが 君には 君にしかできない 君にならできることがあるはずだ、誰も君に強要はしない、自分で考え、自分で決めろ、自分が今何をすべくなのか、まあ 後悔のないようにな。<br>真嗣,我只能在这里浇水。不过有一件只有你才能做到,而且是你一定能做到的事。没有人强迫你,自己思考,自己决定,自己现在应该做什么。总之,别让自己后悔。</p></blockquote><p>在我看来,这是真嗣第一次自己思考并得出结论为什么要驾驶 EVA。在这之前,美里带他去看第三新东京市的升起,告诉他是为了保护这座城市而驾驶 EVA;而司令什么也没告诉。他询问其他驾驶员并试图得出答案,但这都是她们自己的想法,终究不是碇真嗣自己思考出来的结论,不能对真嗣有任何的帮助。</p><p>同时,在破里,没有加持在西瓜田边与真嗣的对话,取而代之的是美里对真嗣说:不是为了别人,而是为了自己。</p><p>当看 “破” 这部剧场版的时候,正好也在看 Escape from Freedom (逃避自由) 和 Courage to be disliked (被讨厌的勇气) 这两本书,恰好也讲到 “选择” 这个问题。与加持对话时,这更明显一点:选择逃避,那么就要承担全人类毁灭的后果,毁灭之后也不会有人指责他;选择战斗,承担起一个 EVA 驾驶员的责任。加持的这段话就妙在没有像司令或美里那样强迫他,而是告诉了真嗣两种后果,让真嗣自己选择,让真嗣在那一瞬间拥有了一种选择的自由。换做其他人,比如美里,大概率会像在旧剧场版里一样直接要求真嗣去驾驶 EVA。</p><p><img src="e19.jpeg" alt="E19"><span class="image-caption">E19</span></p><h2 id="工作"><a href="#工作" class="headerlink" title="工作"></a>工作</h2><p>升了一级。从 L3 变成了 L4,不过这算不上什么值得惊喜或高兴的事。我已经工作两年了,今年不升的话,明年也会升。从 L3 到 L4 这一级的变化,我感觉不是什么意料外的事,如果早两年做的项目足够难和有影响力,那么就会早点升,不然 3 年时间做那么多东西,影响力也足够到 L4。</p><p>去年在总结里也谈到了对工作的想法。今年相较去年,一个变化是组员变多了,组内的内容以及随着项目推进,和组内以及组外的沟通更多了,写会议文档和设计文档的时间也更多了。对于写代码时候变少这件事,我倒没什么担忧,算是意料之内的事。如果写代码时间减少是因为把设计和沟通做好,减少了返工,那自然最好的。</p><h2 id="生活"><a href="#生活" class="headerlink" title="生活"></a>生活</h2><p><strong>搬了一次家</strong> <a href="/post/moving-house/" title="搬家可太累了">搬家可太累了</a></p><p>一位室友因换办公室而退租,本来三个人变成两个人。于是和剩下的室友换了一个 apartment。新的住处虽然比以前稍显朴素,但空间上似乎更加得当了。本来就不常用的客厅和厨房占地面积小了,把足够的空间留给了卧室。</p><p><strong>去旅游</strong></p><p>一是去了国家公园。<a href="/post/yosemite-kings-canyon-trip/" title="Yosemite, Sequoia & Kings Canyon 打卡式两日游">Yosemite, Sequoia & Kings Canyon 打卡式两日游</a>。<br>二是去了 Los Angelas 和 San Diego。本来写了篇文章,不过感觉这次旅游体验一般,文章也没国家公园那篇写得好,于是就没发。<br>三是去了 Santa Curz。花了一个下午和朋友们钓螃蟹,可惜没有钓到。第一次看到了码头的<a href="https://www.instagram.com/p/CWsDaHeL5vw/">加州海狮</a>。</p><p>没想到自己会在今年出去旅行。我虽然不讨厌旅游,但一般极少主动花几天甚至一天旅游。总体上这几次旅游都挺满意的。</p><h2 id="其它"><a href="#其它" class="headerlink" title="其它"></a>其它</h2><p><strong>文章</strong></p><p>恢复一点更新。大部分是书评和一些生活记录。也就一篇关于标点符号的文章勉强算是技术相关的文章。</p><p><strong>日语</strong></p><p>去年说今年考 N2。但没怎么刻意准备,平时也就积累一点看漫画看到的词汇。SF 的考场也取消了。关于 JLPT,就暂时放放吧。</p><p><strong>游戏</strong></p><p>和前两年差不多,主要还是 《Splatoon 2》,《塞尔达传说 – 旷野之息》以及《动物森友会》。</p><p>《Splatoon 2》目前最佳成绩是鱼模式 2349.9 分,排位预估 8124 名,使用的武器是<a href="https://splatoonwiki.org/wiki/Custom_Explosher">贴牌重桶</a>。希望《Splatoon 3》里还保留这款武器。</p><p><img src="https://pbs.twimg.com/media/FDd1TysVEAAP4zy?format=jpg&name=large" alt="排位"><span class="image-caption">排位</span></p><hr><h2 id="それから"><a href="#それから" class="headerlink" title="それから"></a>それから</h2><p>相比去年,今年过的还挺平稳,总体上也比去年舒坦很多,少有的超过上一年的预期了,也少有的没有留下什么遗憾。</p><p>挺好的,没什么留念,进入下一年吧。</p><p><img src="eva-end.jpeg" alt="さあ 行こう"><span class="image-caption">さあ 行こう</span></p>]]></content>
<summary type="html"><blockquote>
<p>笑ってよ 笑ってよ<br>この写真みたく<br>笑ってよ 笑ってよ<br>飾りつけてあげる<br>笑ってよ 笑ってよ<br>【sayonarawoiwazuni/椎名もた】</p>
</blockquote></summary>
<category term="近况及总结" scheme="https://blog.lazzzis.com/categories/%E8%BF%91%E5%86%B5%E5%8F%8A%E6%80%BB%E7%BB%93/"/>
<category term="自言自语" scheme="https://blog.lazzzis.com/tags/%E8%87%AA%E8%A8%80%E8%87%AA%E8%AF%AD/"/>
</entry>
<entry>
<title>关于 "..." 与 "…"</title>
<link href="https://blog.lazzzis.com/post/punctuation-ellipsis/"/>
<id>https://blog.lazzzis.com/post/punctuation-ellipsis/</id>
<published>2021-10-10T03:15:26.000Z</published>
<updated>2024-06-02T05:08:09.900Z</updated>
<content type="html"><![CDATA[<p>UX: 这次我们把按钮的文字改一下,从 “Continue” 改成 “Save…”.</p><p>我:OK。简单,三个点而已。</p><p>Reviewer: 不,那可不只是三个点</p><span id="more"></span><p>我:三个点还能有不一样!?</p><p>Reviewer:对,我们应该用 “…” 而不是 “…”。</p><p>我:嗯?听说一席话,如听一席话。</p><p>Reviewer:不,你仔细看看。<code>"…"</code> 是一个字符,而 <code>"..."</code> 是三个。</p><p>我:这是什么奇怪的编码吗?</p><p>Reviewer:但也说不上奇怪,前者是 “U+2026”,而后者是三个 “U+002E”。</p><p>我(查了查 unicode-table.com):还真是。但有必要计较这个问题吗,难道我们要为了省两个字符?我们搞前端的,不缺那么点内存吧</p><p>Reviewer:对,但说起来简单。这涉及到排版。</p><p>我:哦?</p><p>Reviewer:如我前面所说,三个点都在一个字符内,所以这三个点是不会断开的。但如果用三个标点的话,那么就可能因为屏幕空间的变化,为了适配网页尺寸,会出现第一个点在第一行,第二第三个点在第二行的情况。</p><p>我:哦,原来是这样,是为了美观呀!</p><p>Reviewer:对。实际应用中,可不止这个,还有 “I don’t know” 中的单引号。如果你直接在编辑器中,比如 vscode 中,你会看到 <code>'</code> <code>′</code> 长得很类似。同样是用键盘回车键左边的按键敲出来的,但实际会因为编辑器的不同而有不同效果,有些会是 <code>'</code> (U+0027),而有些则是 <code>′</code> (U+2032)。</p><p>我:还真是。那我怎么知道该用哪个?</p><p>Reviewer:一般会有一个 UXW(UX writer)对这方面比较熟悉,可以问他们。但话说回来,有些工程师看着这个字符串简单,就没有用复制,而是直接手敲了,比如刚刚讲到的三个点。这反而导致了实际的 UI 效果是有隐患的。另外,<a href="https://material.io/archive/guidelines/style/writing.html#writing-capitalization-punctuation">https://material.io/archive/guidelines/style/writing.html#writing-capitalization-punctuation</a> 恰好讲了一些标点的例子,你可以去看看。</p><p>我:好!那我们有没有 linter 之类的可以使用。</p><p>Reviewer:你可以在我们项目里加一个 presubmit script。这样,它能在提交代码时警告工程师。要不你去实现检测 <code>…</code> 和 <code>...</code> 吧。</p><p>我:好!</p><p>聊完后,我开始写起这个脚本。项目里用的是 python,那么用 python 的话,正则表达式就是 <code>\u002e\u002e\u002e</code>,也就是这个样子了:</p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> re</span><br><span class="line"></span><br><span class="line">p = re.<span class="built_in">compile</span>(<span class="string">'\u002e\u002e\u002e'</span>)</span><br><span class="line"><span class="built_in">print</span>(p.search(<span class="string">"downloading..."</span>).group())</span><br></pre></td></tr></table></figure><p>看一下输出,是这个样子:<code>dow</code></p><p>嗯?怎么回事,为什么不是 <code>...</code>。难道我哪里打错了?但仔细看了不下十遍,也没发现啥疑点。把字符换成 <code>Saving...</code> 试试,但也没有正确匹配。</p><p>用其他语言试试:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">> <span class="string">"downloading..."</span>.match(<span class="regexp">/\u002e\u002e\u002e/</span>)</span><br><span class="line">[ <span class="string">'...'</span>, <span class="attr">index</span>: <span class="number">11</span>, <span class="attr">input</span>: <span class="string">'downloading...'</span>, <span class="attr">groups</span>: <span class="literal">undefined</span> ]</span><br></pre></td></tr></table></figure><p>为什么用 js 就可以?</p><p>折腾了半个多小时,无奈去问了问擅长 Python 的同事。</p><p>同事:你用 <code>p = re.compile('[\u002e]{3}')</code> 试试?</p><p>我试了试,发现还真可以!真是怪了,这两者不是应该没区别的吗!?</p><p>同事:不,有区别。我不知道 js 里是怎么处理的,但在 python 里,<code>'\u002e\u002e\u002e'</code> 就是 <code>'...'</code>。你相当于拿了三个通配符去匹配,当然不管怎么匹配,也只能匹配到字符串最开头的三个字母!</p><p>我:哎,原来是踩了一个坑!</p>]]></content>
<summary type="html"><p>UX: 这次我们把按钮的文字改一下,从 “Continue” 改成 “Save…”.</p>
<p>我:OK。简单,三个点而已。</p>
<p>Reviewer: 不,那可不只是三个点</p></summary>
<category term="技术与工作" scheme="https://blog.lazzzis.com/categories/%E6%8A%80%E6%9C%AF%E4%B8%8E%E5%B7%A5%E4%BD%9C/"/>
</entry>
<entry>
<title>关于 EVA 终的感想</title>
<link href="https://blog.lazzzis.com/post/shin-eva-end/"/>
<id>https://blog.lazzzis.com/post/shin-eva-end/</id>
<published>2021-08-14T06:53:51.000Z</published>
<updated>2024-06-02T05:08:09.902Z</updated>
<content type="html"><![CDATA[<p>只要庵野秀明满足以及真嗣有一个 Happy Ending 就足够了</p><span id="more"></span><p>以上就是我对 EVA 终的一句话总结。</p><p>时代变了,庵野秀明也变了。EOE 里那个压抑的,令人自闭的结局,很难在这个时候展现了。</p><p>一方面,在《行家本色 特别篇》里,庵野秀明也坦诚现在不能像以前一样做一部过于晦涩难懂的动画了,庵野秀明想要让作品变得有趣。虽然他没有对 “有趣” (面白い)这个概念进一步阐释,但我觉得这里的 “有趣” 多少会让神秘感消失,让观众更加易懂。</p><p>另一方面,同样在这部纪录片里,庵野也多次提到要有创新,不想像以前那样。如果开始直接画分镜,那画出来也只是他能想到的。为了突破,他才为此在摄影棚里拍动捕。从这一点来说,庵野在刻意回避以前的创作习惯和手法,这必然会让再想看一次 EOE 的人失望。</p><p>再者,必须要考虑到庵野秀明自己的性格,尤其是他现在似乎已经与这个世界和解了。当初做 TV 版和 EOE 的那个庵野,是一个抑郁的,受到死亡威胁的,暴躁到会踹文件柜的,甚至想要自杀的,极度压抑的庵野。很大程度上,他当时的境况影响了他当时的创作方向。现在的庵野,是开了个公司,有了自己喜欢的人,可以拍自己喜欢的特摄(新哥斯拉,新奥特曼)的庵野了,估计他很难回到 20 多年前的那个状态去创作 EOE 那样的故事了。</p><p>所以,在看这部作品前,我最不希望看到的,是一部和 EOE 很像的作品。</p><p>我希望看到的,是真嗣和这个世界达成和解。其实不只是希望真嗣,也希望创作了 EVA 的庵野秀明,更重要地,是希望在观看这部作品的我自己与这个无意义的世界达成和解。所以,这就是我的期望,至于他们是怎么达成和解的,我其实并不在乎。在看作品前,我想过如果结局即使像 TV 结尾的那段想象一样,所有人都过上了普通高中生的生活,这也足够了。至于真嗣最后和谁走在一起,只要真嗣快乐就够了。就算庵野安排的结局里,真嗣没有和谁走在一起,而是和一群朋友高高兴兴的上学,对我来说,那么足够了。和前面的故事相比,真嗣已经经历了太多痛苦,而这些痛苦,使得普通平凡的生活,看起来都是那么幸福。</p><p><img src="comment.jpg" alt="https://youtu.be/USKzAj1dOq4 下的一条评论"><span class="image-caption">https://youtu.be/USKzAj1dOq4 下的一条评论</span></p><p>这部作品完美吗?当然不完美,初号机和 13 号机的战斗时的动作就显得有点僵硬不自然;对于玛丽的身世,尤其是为什么是背信者,也没有展开说明,显然还有很多坑没有填。</p><p>达到了他们自己在纪录片透露的期望了吗?见仁见智。意识流的那一段,尤其是碇源堂的独白,是故意这么表现的吗,这段太有 TV 和旧剧场版的味道,反而不是我想看到的 “新” 的表现形式和内容。但 Q 和 终本身,将时间线调整至 14 年后,本身就是他们对创新的探索了。纪录片提到的通过动捕寻找分镜,也是制作组努力寻找创新的铁证。这个问题似乎也只有制作组能回答,但作为观众的我,至少认可和倾佩他们这么多年来对创作的努力。</p><p>这部作品能够上映,我就很欣慰了。我至今还沉浸在这 “终剧” 所带来的仪式感。</p><p>EVA 结束了,生活还要继续,“新世纪圈钱计划” 也会继续,期待庵野秀明所带领的 Khara 能为我们带来更多的优秀作品。</p><p><img src="finale.jpg"></p><hr><p>推荐观看和收听:</p><ol><li><a href="https://www.youtube.com/watch?v=Jp9xzEaJ7Ks">《行家本色 特别篇 庵野秀明特辑》的在线英文版</a></li><li><a href="https://www.bilibili.com/bangumi/play/ss39205?from=search&seid=9862079337629426880">再见了所有的福音战士!庵野秀明的1214日</a></li><li><a href="https://www.bilibili.com/video/BV1W64y1i746/">“作品比命更重要”——庵野秀明与《EVA》制作之路【银屏系漫游指南】丨机核</a></li><li><a href="https://www.bilibili.com/video/BV1ms411w7sS">很抱歉我没能拯救世界——“奇迹少年”庵野秀明【大师之路】</a></li><li><a href="https://www.youtube.com/watch?v=USKzAj1dOq4">The Loneliest Anime – The Philosophy of Neon Genesis Evangelion – Wisecrack Edition</a></li><li><a href="https://podcasts.apple.com/us/podcast/%E8%B0%88%E7%8E%A9%E8%AE%BA%E7%A0%B4vol-10-%E6%96%B0-%E7%A6%8F%E9%9F%B3%E6%88%98%E5%A3%AB%E5%89%A7%E5%9C%BA%E7%89%88-%E7%BB%88-%E8%A7%82%E5%90%8E%E6%84%9F/id983248986?i=1000531936882">【谈玩论破VOL.10】「新·福音战士剧场版:终」观后感</a></li></ol>]]></content>
<summary type="html"><p>只要庵野秀明满足以及真嗣有一个 Happy Ending 就足够了</p></summary>
<category term="读书看剧" scheme="https://blog.lazzzis.com/categories/%E8%AF%BB%E4%B9%A6%E7%9C%8B%E5%89%A7/"/>
<category term="思考" scheme="https://blog.lazzzis.com/categories/%E6%80%9D%E8%80%83/"/>
<category term="影评" scheme="https://blog.lazzzis.com/tags/%E5%BD%B1%E8%AF%84/"/>
</entry>
<entry>
<title>Yosemite, Sequoia & Kings Canyon 打卡式两日游</title>
<link href="https://blog.lazzzis.com/post/yosemite-kings-canyon-trip/"/>
<id>https://blog.lazzzis.com/post/yosemite-kings-canyon-trip/</id>
<published>2021-06-14T06:11:05.000Z</published>
<updated>2024-06-02T05:08:09.915Z</updated>
<content type="html"><![CDATA[<p>在搬完家休息了几天之后,按照计划,决定和一起搬家的小伙伴们去周边的国家公园游览一下。请假了周四周五,连上周六三天两夜,没有爬长 trail 的打算,仅仅想把主要景点打个卡。</p><span id="more"></span><h2 id="准备工作"><a href="#准备工作" class="headerlink" title="准备工作"></a>准备工作</h2><p>国家公园都有对应的官网,官网里有详细和简略的地图,可以先下载规划下路线。景区内的路线一般都相对简单,但问题是因为就那么一两条道,有时错过了一个岔路口,可能要开五六分钟才能到下一个岔口才能调头回去,所以尽量先确定要预先参观的景点,避免把大量的时间花在开车上。</p><p><a href="https://www.nps.gov/seki/index.htm">Sequoia & Kings Canyon</a><br><a href="https://www.nps.gov/yose/planyourvisit/maps.htm">Yosemite National Park</a></p><p>宾馆的话,虽然景区内和景区门口的小镇也有旅馆,但听说价格偏高且设施都挺一般的,所以把两天的宾馆都定在了 Fresno 市区内。而且在市区内的话,吃饭的地方也能多点,也可以买买水补充物资。</p><h2 id="Yosemite"><a href="#Yosemite" class="headerlink" title="Yosemite"></a>Yosemite</h2><p>听说 120 公路都是山路,所以是走 140 上去的。140 的路也就弯道多一点,其他方面都不差。中间会有个桥只允许一辆车通过,所以有个红绿灯调度。沿途有条溪流,也算不错。</p><p><img src="bridge.jpeg" alt="桥"><span class="image-caption">桥</span></p><p>开进景区不久,看到第一个瀑布是 Bridalveil Fall。这时一些游客已经在路边停了车,纷纷举起手机和相机拍照了。还算运气,因为这次来这个瀑布水流还算清晰,之前听说可能会因为缺水而看不清这瀑布。不过一个遗憾是,目前走近这个瀑布的 trail 在修建中,所以也只能在路边远远望去了。</p><p><img src="Bridalveil-Fall.jpeg" alt="Bridalveil Fall"><span class="image-caption">Bridalveil Fall</span></p><p>再开几分钟,就算进入景区的一个主要地带了,两边各种建筑都多了起来。进入游客中心和停车场前,有一个很大的草坪,在那可以清晰看见远处的 Half Dome。</p><p><img src="half-dome.jpeg" alt="Half Dome"><span class="image-caption">Half Dome</span></p><p>据说有条 trail 可以走得更近点,但这条 trail 据说比较抖,而且也要一两小时,我和随行的伙伴们都没有那么大精力也没有足够的时间去参观,所以作罢。</p><p>当时我们在那草坪上研究酋长岩在哪,因为我们一路开过来,并没有看到作为 Mac 系统壁纸的酋长岩。虽然按理说应该在来的路上就能看到,可就是谁也没注意到。我们临时查了 Google Map,才发现往回开车大概 5 分钟的地方有个拍照点,在那里是可以拍到酋长岩的,于是马上又开车驾去。到了之后才发现,原来作为壁纸的酋长岩是在夕阳(也可能是日出)拍的,所以看上去偏红,但实际的酋长岩在正午十分的时候是灰白色的。</p><p><img src="el-capitan.jpeg" alt="👈左边的酋长岩"><span class="image-caption">👈左边的酋长岩</span></p><p>看完酋长岩后,就在景区内的礼品店逛了逛,在里面的星巴克买了个 Been There 系列的马克杯,然后顺着溪流走了走。本来有个地方,是要过桥的,可是走在前面的人突然调头,露出惊恐的表情:“Bear!”。原来桥的另一头走过来一只熊!我们也惊恐地往回跑,在离它大概五十米处观望,发现那熊耳朵边有个吊牌,看来是个常客了。那熊也没看正眼瞧我们,朝另一条道径直走去了。</p><p>简单吃了点提前准备的食物后,我们便往 Tunnel View 和 Glacier Point 驶去了。这两个是顺路的,而且都会离游客中心越来越远。</p><p>这两个景点都是极好的观景点,可以在以一个比之前较高的视角观察酋长岩和 Half Dome。顺便一提,在 Glacier Point 这个景点,还遇到一对新人在那举办婚礼。这对新人在优美壮观的景色里和众人的见证下,许下了郑重的誓言。</p><p><img src="tunnel-view.jpeg" alt="Tunnel View 视角的酋长岩"><span class="image-caption">Tunnel View 视角的酋长岩</span></p><p><img src="glacier-point.jpeg" alt="Glacier Point 视角的 Half Dome"><span class="image-caption">Glacier Point 视角的 Half Dome</span></p><h2 id="Sequoia-amp-Kings-Canyon"><a href="#Sequoia-amp-Kings-Canyon" class="headerlink" title="Sequoia & Kings Canyon"></a>Sequoia & Kings Canyon</h2><p>第一天回宾馆后,再次研究了一下第二天的行程。因为怕又出现与打卡点擦肩而过的情形,所以就特意 YouTube 上搜了一些 Vlog,比如 <a href="https://youtu.be/2XxV_IHbSQA">离优胜美地最近的国家公园—自驾国王峡谷国家公园kings canyon national park</a> 和 <a href="https://youtu.be/2WeVns_tAm0">自驾美国加州美洲杉国家公园Sequoia National Park</a>。决定在 Kings canyon national park 拜访过 General Grant Tree 后,就直接前往 Sequoia natonal park。这两个公园有点特殊,虽然算两个,但实际游玩起来,又可以当做一个:这两个景区直接相连,进入其中一个景区后,可以无需再次购票直接进入下一个公园。</p><p>这两个景区都有不少的红杉树,尤其是 Sequoia 公园。虽然理论上 General Grant Tree 和 General Sherman Tree 是世界上最大的几棵红杉树,但坐落在其附近的一些红杉树看上去也并没小上多少。所以,如果是拍照的话,并没必要揪着这两棵树不放,可以去和附近游客较少的其它树合影,或许会有更好的摄影体验。</p><p><img src="sequoia.jpeg" alt="Sequoia"><span class="image-caption">Sequoia</span></p><p>看完几棵大红杉后,下一个目的地就是 Moro Rock。Moro Rock 是一颗可以攀登的大石头,共几百级台阶。在 Moro Rock 可以眺望到远处的众多雪峰。虽然几片云朵遮住了部分山尖,但其巅峰的白雪也依旧依稀可见。</p><p><img src="moro-rock.jpeg" alt="Moro Rock"><span class="image-caption">Moro Rock</span></p><h2 id="其它"><a href="#其它" class="headerlink" title="其它"></a>其它</h2><p>上面的图片都是用自己的手机 Pixel 3 拍的。但镜头似乎有点问题,自动对焦好之后过个几秒就会焦点就移动了,图片中的部分就变得略微模糊。</p><p>大部分移动还是靠开车的,还好有随行的小伙伴可以代驾,不然一个人驾驶的话可真要筋疲力尽。</p><p>其实还有很多的一些景色需要几小时的 hiking,如果要欣赏全部的话,还是应该多几天时间。光一天时间,还是只能主要景点打打卡。</p><p>湾区开过去的话,大概要 4 小时左右,所以虽然是三天两夜,但其实第三天就没去其它景点,在起床后就动身回家了。</p>]]></content>
<summary type="html"><p>在搬完家休息了几天之后,按照计划,决定和一起搬家的小伙伴们去周边的国家公园游览一下。请假了周四周五,连上周六三天两夜,没有爬长 trail 的打算,仅仅想把主要景点打个卡。</p></summary>
<category term="旅行" scheme="https://blog.lazzzis.com/categories/%E6%97%85%E8%A1%8C/"/>
<category term="旅行" scheme="https://blog.lazzzis.com/tags/%E6%97%85%E8%A1%8C/"/>
</entry>
<entry>
<title>搬家可太累了</title>
<link href="https://blog.lazzzis.com/post/moving-house/"/>
<id>https://blog.lazzzis.com/post/moving-house/</id>
<published>2021-06-03T03:28:01.000Z</published>
<updated>2024-06-02T05:08:09.896Z</updated>
<content type="html"><![CDATA[<p>本来和另外两个室友住在一起的,但其中一个室友因为办公室要 relocate 了,所以只能和另一个室友重新找一个 Apartment。</p><span id="more"></span><h1 id="开-U-Haul"><a href="#开-U-Haul" class="headerlink" title="开 U-Haul"></a>开 U-Haul</h1><p>主要升降桌和床垫是很难装进自己的车里的,所以只能找 U-Haul 租一辆小卡车了。</p><p>本来考虑找搬家公司,可打电话问了报价,至少 $200 了,实际算上小费什么的,应该要 $300。而租一辆小卡车的话,应该能在 $150 以内,而且我只有床垫和升降桌是必须要帮忙的,其它都可以装进自己的车的后备箱里一点点搬。再加上,搬家前一个星期才问,搬家时间刚好也在 Memorial Day 假期,最后被搬家公司以人手不足为由拒绝了。</p><p><strong>教训一:应该两周前就打电话向搬家公司咨询</strong></p><h2 id="选车"><a href="#选车" class="headerlink" title="选车"></a>选车</h2><p><img src="truck.jpg" alt="大面包车和小卡车"><span class="image-caption">大面包车和小卡车</span></p><p>有意向的是图片上的这两种。从容量上讲,后者确实更大点。可仔细比较下官网提供的参数可以发现,前者和后者在长度和宽度上是几乎相同的,仅仅后者在高度上略微高一点。</p><p>考虑到我没有很多很高的东西,本来是想租前者的,但来帮忙的朋友说以防万一,还是租后者吧,反正价钱差不了多少。所以最后租了后者。</p><p>但实际搬家的时候,我发现我错了 – 我忘记了地下车库大门的限高。</p><p>本来计划是,将家具搬进门口很近的电梯,然后到地下车库,而货车可以停在地下车库的电梯旁,这样马上就能将家具搬进车里。但实际是,小卡车的高度是 9”, 而地下车库的限高是 7”, 所以这个方案泡汤了。如果当初换成面包车的话,就不会有这问题了。没办法,只能临时换方案,从电梯将家具多搬了近 50 米才到车上。考虑到沉重的升降桌,这滋味可不好受。</p><p><strong>教训二:应该事先确定车库的限高</strong></p><h2 id="损失"><a href="#损失" class="headerlink" title="损失"></a>损失</h2><p><img src="mirror.jpeg" alt="镜子"><span class="image-caption">镜子</span></p><p>放这枚镜子的时候,没有将其保护好,而路上刚好有几个坎,在震动下不幸碎裂。</p><p><strong>教训三:应该格外保护好易碎品</strong></p><h2 id="费用"><a href="#费用" class="headerlink" title="费用"></a>费用</h2><p>用了大约 3 小时,实际费用是 $130,在预算内。</p><h1 id="箱子📦"><a href="#箱子📦" class="headerlink" title="箱子📦"></a>箱子📦</h1><p><img src="boxes.jpeg" alt="一部分箱子"><span class="image-caption">一部分箱子</span></p><p>其它的物品,比如衣物,可以打包在纸箱内。而显示屏这类,需要用原包装好好装好。我没有特地去买新的纸箱子,因为储物室里就有大量的亚马逊快递的不同大小的纸盒。当初存这些纸盒也就是考虑到哪天搬家会用到。实际用的箱子,比存的箱子要少得多,大量的纸箱子还是扔进可回收的垃圾箱里了。</p><h1 id="搬运"><a href="#搬运" class="headerlink" title="搬运"></a>搬运</h1><p>搬家说简单也简单,也就三步:1. 打包 2. 搬运 3. 解包</p><p>但细看又很麻烦。在打包上,需要把所有东西按一定规则分类,不然全放进箱子之后,很快就忘了箱子里有啥了。搬运又是个体力活,即使上货和卸货的地方还比较近,那么还要考虑到多次把箱子搬上车和卸下车,如果没有电梯,爬个楼梯就更麻烦了。如果打包分类做得好,最后的解包可能是最轻松的了,只需要把物品摆好。</p><p>算下来,四天假期里,这三个步骤各花了一天,只留下最后一天给自己躺平休息。</p>]]></content>
<summary type="html"><p>本来和另外两个室友住在一起的,但其中一个室友因为办公室要 relocate 了,所以只能和另一个室友重新找一个 Apartment。</p></summary>
<category term="近况及总结" scheme="https://blog.lazzzis.com/categories/%E8%BF%91%E5%86%B5%E5%8F%8A%E6%80%BB%E7%BB%93/"/>
<category term="生活杂记" scheme="https://blog.lazzzis.com/tags/%E7%94%9F%E6%B4%BB%E6%9D%82%E8%AE%B0/"/>
</entry>
<entry>
<title>咸鱼与存在</title>
<link href="https://blog.lazzzis.com/post/exist-and-nihil/"/>
<id>https://blog.lazzzis.com/post/exist-and-nihil/</id>
<published>2021-05-01T06:48:34.000Z</published>
<updated>2024-06-02T05:08:09.885Z</updated>
<content type="html"><![CDATA[<blockquote><p>It happens that the stage sets collapse. Rising, streetcar, four hours in the office or the factory, meal, streetcar, four hours of work, meal, sleep, and Monday Tuesday Wednesday Thursday Friday and Saturday according to the same rhythm — this path is easily followed most of the time. But one day the “why” arises and everything begins in that weariness tinged with amazement. “Begins” — this is important.<br><em>by</em> Albert Camus</p></blockquote><p>一次存在主义危机</p><span id="more"></span><h2 id="Part-1-牧师"><a href="#Part-1-牧师" class="headerlink" title="Part 1: 牧师"></a>Part 1: 牧师</h2><p>“我在 25 岁的时候陷入了虚无主义”,他说,“是神拯救了我。”</p><p>这是一个牧师跟我说的。刚踏上美利坚这片土地的我,人生地不熟,被一位学长拉去了一个校园的团契,虽然我对基督教也不反感,但也不排斥,并且本着还能免费吃一段饭的想法,就跟着去了。于是就听到了刚才那句话。</p><p>无论是前半句还是后半句,我都不怎么理解。但我也没有想理解,毕竟受了这么多年的无神论教育,自然也觉得这是一句拉人入教的说辞。我没有多想这句话,继续吃他们提供免费晚饭。直到几年后,我才明白他说的 “虚无主义” 是怎么一种心态,以及为什么说是宗教拯救了他。</p><h2 id="Part-2-Happy-Ending"><a href="#Part-2-Happy-Ending" class="headerlink" title="Part 2: Happy Ending"></a>Part 2: Happy Ending</h2><p>“等你考上大学了,你就自由了,想怎么玩就怎么玩!”直到现在,这句话依旧被无数的高中老师所重复。但显而易见地,如果不在意绩点,这句话可以是真的。但大部分人都很清楚,为了毕业后找到一份理想的工作或进一步升学,不得不牺牲手头的时间去备考,刷题,实习,投简历。</p><p>“等找到一份好工作,生活就轻松了。” 这句话的逻辑和上面是一样的,很明显,现实不可能那么好,因为找到工作后,还有结婚和买房在等着。</p><p>不过立志当“咸鱼”的我,把这句话当真了:找到工作,养活自己就够了,想干嘛就干嘛,多自由啊!</p><p>后来,我真的找到了一份理想的工作。这份工作,对他人来说,或许并不够好,但对我这种十几年来混迹于各种非一流学校的人来说,太好了。这种感觉,就像游戏里的 Happy Ending。</p><h2 id="Part-3-入职"><a href="#Part-3-入职" class="headerlink" title="Part 3: 入职"></a>Part 3: 入职</h2><p>入职后,我入手了一台 Switch,开始了咸鱼的第一步 ———— 玩游戏。玩游戏是快乐的,但对我来说,这份快乐却是有限的 ———— 我开始感到了无聊。我内心还是想做点什么。游戏对我来说终究只是一种消遣,我还是得把大部分时间花在有意义的正事上。</p><p>可是,什么是<strong>有意义的正事</strong>?</p><p>仔细想想,“有意义的正事” 这个说法有点奇怪,因为对我来说 “有意义的事”,不就是 “正事” 吗?</p><p>那什么是 “有意义” 呢? </p><p><img src="meaning.jpeg"></p><p>对工作有帮助的事,是有意义的吗?这个听上去有点道理,可是工作一天 8 小时,咸鱼的我为什么要在工作之外去忙它呢?而且,工作是一个无奈的选择,是为了要养活自己。</p><p>等等,为什么要养活自己?我脑内突然冒出了一个可怕的想法 ———— 我为什么要活着?</p><p>当冒出这个想法的时候,我其实笑了笑:我怎么会问出这么傻的问题?活着的意义,不是从小到大一直都思考过了的吗?小学的时候,是为了考上重点中学;中学的时候,是为了考上重点大学;大学的时候,是为了取得理想的工作。</p><p>可是,现在呢?</p><p>刚才也说了,我拿到了我现在认为满意的工作,我突然对未来没有期许了!我不知道我该做什么了!</p><p>如果什么都不做,这个世界也不会有任何影响,这个世界少了我也不会怎样。那…我真的可以不存在这世上?</p><p>不行不行,还是继续工作吧,想这么多干嘛,我好蠢!</p><h2 id="Part-4-WFH"><a href="#Part-4-WFH" class="headerlink" title="Part 4: WFH"></a>Part 4: WFH</h2><p>因为疫情的影响,开始在家工作。虽然我真的很讨厌疫情,但是我并不讨厌 WFH。居家工作后,空闲时间多了很多。</p><p>上下班更加灵活了了,而且也没有通勤的苦恼,工作累了还可以去沙发上小憩一会 ———— 作为咸鱼的我,更加自由了。</p><p>虽然空闲时间增多了,但因为是疫情下的 WFH,我不能随心所欲的出去玩了。更多的时候,还是躺在家里无所事事。</p><p>无聊的时候,我开始胡思乱想,又回到了刚才的问题。</p><p>本以为,等过一两个月回到 office 之后,投入工作和社交后,就不会想那么多了。可没想到,我想了快一年了。而且越想越不对劲 ———— 我开始认为这世上的一切都是没有意义的了。</p><h2 id="Part-5-Bojack-Horseman-and-Oscar"><a href="#Part-5-Bojack-Horseman-and-Oscar" class="headerlink" title="Part 5: Bojack Horseman and Oscar"></a>Part 5: Bojack Horseman and Oscar</h2><p><em>Bojack Horseman</em>,是一部电视剧的名字,也是这部电视剧主人公的名字。</p><p>虽然是过气明星,但 Bojack Horseman 就像个国王一样,没有金钱和工作的烦恼。可奇怪的是,他仍然不快乐。</p><p>第一季,他的自传出版了。可是他依旧不快乐。<br>第二季,他出演了梦寐以求的电影并饰演了从小就敬佩的英雄,可是他发现这仍旧没有使他快乐。<br>第三季,他争取奥斯卡,这次失败了。当然,没有变化,他还是不快乐。</p><h2 id="Part-6-None-of-this-matters"><a href="#Part-6-None-of-this-matters" class="headerlink" title="Part 6: None of this matters"></a>Part 6: None of this matters</h2><p><img src="none-of-this-matters.png"><br>“None of this matters”</p><p>这是 Mr. Peanutbutter 安慰 Bojack 落选时的话,出现在第三季的第十集。可我没有明白,为什么不重要呢?</p><p>再把进度条倒回去看看,发现他还说了这么一段话:</p><blockquote><p>You come to work, clock in. You put sugar in your coffee and watch it slowly disappear into nothingness. But the sugar doesn’t know why. Sugar didn’t ask to be born.</p></blockquote><p>是呀,Sugar didn’t ask to be born. And neither did I!</p><p>这中间发生了什么吗?可是仔细看看,这中间只有一个 Mr. Peanutbutter 编造奥斯卡获奖名单的搞笑桥段。难道我在最开始就忽视了什么吗?</p><h2 id="Part-7-Existential-Crisis"><a href="#Part-7-Existential-Crisis" class="headerlink" title="Part 7: Existential Crisis"></a>Part 7: Existential Crisis</h2><p>因为不知道发生了什么,于是我去搜了点影评,然后在 YouTube 上发现了这个 <a href="https://www.youtube.com/watch?v=rORIDYHOFTQ">The Philosophy of BOJACK HORSEMAN – Wisecrack Edition</a>。很巧,B 站上也有个中文搬运 <a href="https://www.bilibili.com/video/BV1Vx41117p9?share_source=copy_web">【哲思趣谈】马男波杰克的哲学 @柚子木字幕组</a>。</p><p>虽然我前面思考了这么久,甚至花了一年,甚至中间以为自己心理出问题了。可是,我的问题,却在视频的几分钟里就被描绘清楚了。</p><p><strong>我经历了一次存在主义危机。</strong></p><p>我一直不知道这就是存在主义危机,也不知道原来在我眼里,世界渐渐变得虚无。</p><p>如 Sartre 所说,我太自由了。去年的时间里,我得到了前所未有的自由,而这种极强的自由,却没有带来我所期望的快乐。归根结底,是当时的我渴望寻找新的意义,但却又发现宇宙的一切都可以没有任何意义。</p><h2 id="Part-8-Embrace-the-absurd"><a href="#Part-8-Embrace-the-absurd" class="headerlink" title="Part 8: Embrace the absurd"></a>Part 8: Embrace the absurd</h2><p>知道是什么问题之后,解决方案就变得明了了。毕竟这个话题在百年前就有众多哲学家探讨过了,当然,现在也有。</p><p>先回过头再看看那位牧师,他的解决方法就是在宗教中寻求自己存在的意义。几乎所有的宗教都给了人们存在的意义,尤其在基督教里,人从出生到死亡,都是为了神的荣耀而活。</p><p>可是,尼采说过 “god is dead”。在人们逐渐回归理性和人本之后,神的概念已经渐渐淡出了部分人,包括我自己,的视野。</p><p>就如 <a href="https://www.youtube.com/watch?v=rORIDYHOFTQ">The Philosophy of BOJACK HORSEMAN – Wisecrack Edition</a> 讲得一样,我们也可以选择让自己忙于生活或沉浸于娱乐之中而无暇去思考这个问题。但终究要面对的时候,我们可以选择像 Camus 所描述的西西弗斯一样 “Embrace the absurd”,承认这个世界就是没有意义的,但依旧选择继续活下去,并且,意义不是外界所赋予的,更多地,是自己赋予自己的。</p><h2 id="Part-9-After-the-crisis"><a href="#Part-9-After-the-crisis" class="headerlink" title="Part 9: After the crisis"></a>Part 9: After the crisis</h2><p>Quara 上的一个问题 <a href="https://www.quora.com/Does-everyone-go-through-existential-crisis">Does everyone go through existential crisis?</a> 提到,并不是每个人都会经历一次存在主义危机。而且,这种危机,有时候会很严重,有时候会很轻,它可能只出现一次,也可能在未来继续出现。</p><p>但无论如何,我至少跨过了这一次的危机,至少,经历过这次的危机,我有了成长:对这个世界有了新的审视,对自己有了新的理解。如果还有下一次的话,那就再写一片文章吧 ^_^</p><hr><p>Reference:</p><ol><li><a href="https://www.netflix.com/title/70300800">Bojack Horseman</a></li><li><a href="https://www.youtube.com/watch?v=rORIDYHOFTQ">The Philosophy of BOJACK HORSEMAN – Wisecrack Edition</a></li><li><a href="https://www.bilibili.com/video/BV1Vx41117p9?share_source=copy_web">【哲思趣谈】马男波杰克的哲学 @柚子木字幕组</a></li><li><a href="https://books.apple.com/us/book/the-complete-works-of-albert-camus/id1509782856">The Complete Works of Albert Camus</a></li><li><a href="https://www.healthline.com/health/existential-crisis">What Is an Existential Crisis, and How Do I Break Through It?</a></li><li><a href="https://www.quora.com/Does-everyone-go-through-existential-crisis">Does everyone go through existential crisis?</a></li></ol>]]></content>
<summary type="html"><blockquote>
<p>It happens that the stage sets collapse. Rising, streetcar, four hours in the office or the factory, meal, streetcar, four hours of work, meal, sleep, and Monday Tuesday Wednesday Thursday Friday and Saturday according to the same rhythm — this path is easily followed most of the time. But one day the “why” arises and everything begins in that weariness tinged with amazement. “Begins” — this is important.<br><em>by</em> Albert Camus</p>
</blockquote>
<p>一次存在主义危机</p></summary>
<category term="思考" scheme="https://blog.lazzzis.com/categories/%E6%80%9D%E8%80%83/"/>
<category term="思考" scheme="https://blog.lazzzis.com/tags/%E6%80%9D%E8%80%83/"/>
</entry>
<entry>
<title>You are (not) Secretariat</title>
<link href="https://blog.lazzzis.com/post/bojack-secretariat/"/>
<id>https://blog.lazzzis.com/post/bojack-secretariat/</id>
<published>2021-03-12T04:53:34.000Z</published>
<updated>2024-06-02T05:08:09.882Z</updated>
<content type="html"><![CDATA[<p>本文为补完 Bojack Horseman 前三季之后的<strong>胡言乱语</strong>,内含部分<strong>剧透</strong>。</p><span id="more"></span><h2 id="Sarah-Lynn"><a href="#Sarah-Lynn" class="headerlink" title="Sarah Lynn"></a>Sarah Lynn</h2><p>Bojack 在最后一刻才想起她,她也是他最后的救命稻草 —— 在所有人都离他而去时,唯一能联系的朋友。但疯疯癫癫之后,SL 也最终还是离去。SL 在剧中的离去,情理之中,意料之外。SL 早就失去了活着的意义,她吸毒,醉酒,危险驾驶,已经没有把自己的生命放在眼里了,也只是浑浑噩噩的活着。SL 离去的时候,表现的很安详,似乎有来自内心的快乐,这种快乐不同于毒品带给她的快乐。在生命的最后一刻,听她的声音,似乎很快乐,她仍旧想成为建筑家。Bojack 似乎是 SL 最后的安慰,SL 也是 Bojack 那时唯一的安慰。</p><p>但这里给我留下了一个疑问:为什么 Sarah 没有去成为一个建筑家呢?她有时间,有金钱,却依旧选择沉沦。或许下一季会解释更多。</p><h2 id="雪豹"><a href="#雪豹" class="headerlink" title="雪豹"></a>雪豹</h2><p>雪豹 (<a href="https://bojackhorseman.fandom.com/wiki/Sebastian_St._Clair">Sebastian St. Clair</a>) 在剧中至少起到了三个作用:第一是让 Diane 离开推动剧情,第二是与 Bojack 形成一个对比,第三是嘲讽了现实里某些借慈善炒作的人。</p><p>雪豹和 Bojack 两者都是虚无的人,这两人都已经过上了不需要担心财力的生活,但都是在精神上面则极度空虚和欠缺。在 Bojack 浑浑噩噩漫无目的之时,雪豹则尝试给自己的生命赋予更多的意义。他前往第三世界救助难民这个行为,让他的形象看上去更像是一个关心民众疾苦的正人君子。</p><p>可当 Diane 走近之后才明白,雪豹的行为本质上是在满足自己虚无缥缈的私欲:他想让更多的人知道他,从而更多人可以向他的基金会捐款,但他在营地的表现看来,他压根不关心孩子们的生活,甚至对部分难民见死不救。雪豹的样子形似现实里某些借捐款之名,靠着收割群众的同情心,实现敛财或炒作的名人,政客和机构。</p><h2 id="Secretariat"><a href="#Secretariat" class="headerlink" title="Secretariat"></a>Secretariat</h2><p>Secretariat 代表着什么?</p><p>这个多次出现的意象,似乎是 Bojack 的精神支柱。Secretariat 教导 Bojack 不顾一切的一直向前冲,可是,Secretariat 没有指明的是,前方在哪?</p><p>Secretariat 可以一直在赛道上跑,可当失去了比赛资格之后,他也失去了方向,从而离开了世界。对比之下,Bojack 也是类似的,在他自己参与的情景剧结束之前,他可以忙于剧集的拍摄,生活还有事可干,可一旦结束,他与 Secretariat 一样陷入了迷茫,只不过 Bojack 用纸醉金迷的方式脱离现实而已。</p><p>在第三季的最后,Bojack 所见的那一群野马,似乎是在指代 Secretariat —- 不要思考,奔向前方。</p><h2 id="虚无主义"><a href="#虚无主义" class="headerlink" title="虚无主义"></a>虚无主义</h2><p>这部作品里的很多角色,都过着空虚的生活:</p><ol><li>Horseman,Sarah Lynn 和 雪豹都已经不再为金钱发愁,显得无所事事</li><li>Princess Carolyn 将自己陷于工作之中,工作外的她也显得空虚</li></ol><p>关于这一点,Wisecrack 对此做了哲学上的分析:此处贴一个字幕组的翻译版 (<a href="https://www.bilibili.com/video/BV1Vx41117p9">link</a>)</p><iframe src="//player.bilibili.com/player.html?aid=8905391&bvid=BV1Vx41117p9&cid=14697326&page=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"> </iframe><h2 id="后续"><a href="#后续" class="headerlink" title="后续"></a>后续</h2><p>一个看点自然是 Bojack 如何面对自己空虚的人生。</p><p>但我最关注的,其实是 Diane 的发展。与 SL 和 Bojack 相比,Diane 也有一个很糟糕的家庭,童年也不快乐,也没有得到父母的关心。但不同的是,Diane 却没有陷入 SL 和 Bojack 那样空虚的生活,似乎是主角团里少有的正常人。我很想看到剧组接下来如何展现 Diane 与其他人的不同。</p>]]></content>
<summary type="html"><p>本文为补完 Bojack Horseman 前三季之后的<strong>胡言乱语</strong>,内含部分<strong>剧透</strong>。</p></summary>
<category term="读书看剧" scheme="https://blog.lazzzis.com/tags/%E8%AF%BB%E4%B9%A6%E7%9C%8B%E5%89%A7/"/>
<category term="思考" scheme="https://blog.lazzzis.com/tags/%E6%80%9D%E8%80%83/"/>
</entry>
<entry>
<title>Splatoon 2 —— 我的一些常用武器</title>
<link href="https://blog.lazzzis.com/post/splatoon-2-weapons/"/>
<id>https://blog.lazzzis.com/post/splatoon-2-weapons/</id>
<published>2021-02-15T01:02:14.000Z</published>
<updated>2024-06-02T05:08:09.905Z</updated>
<content type="html"><![CDATA[<p>玩《Splatoon 2》这款游戏快有一年半了,也快 1000 小时了。在其中的数十款武器中,渐渐地有了那么几把常用的武器。这篇文章就写一点我自己对这些武器的使用感受。</p><span id="more"></span><h2 id="无印中刷"><a href="#无印中刷" class="headerlink" title="无印中刷"></a>无印中刷</h2><p><img src="S2_Splat_Roller_promo_render.jpg" alt="无印中刷 (图片来自 Splatoon Wiki)"><span class="image-caption">无印中刷 (图片来自 Splatoon Wiki)</span></p><p>这把武器是带我进入 X 段的武器。我对这把武器的打法是最经典也最粗暴的打法:冰壶隐游偷袭。</p><p>不得不说,冰壶对中刷太重要了。中刷只要能接近敌人到射程范围内,那么就有 99.9% 的机率一个横拍秒杀对面。同时,借助冰壶,靠近高台,从而一个跳横拍击杀站在高台上的后排武器或者偷袭刚刚复活的敌人,真是百试不厌。而其它刷子的话,重刷前摇太长,敌人可能及时发现并逃跑或反杀;碳刷伤害低,横拍并不一定能拍死,竖拍需要较高的准度和预判,不如横拍击杀范围大。对于其它具有冰壶的武器,比如金双,不具备躲在高台下击杀敌人的能力,而且也不是一确武器,需要四发子弹才能带走敌人。</p><p>虽然套路简单,但反套路也简单。因为冰壶太过明显,所以如果看见对面一个冰壶划过来了,那么对着冰壶的轨迹开几枪,十有八九能发现一个潜行于其中的中刷。这时,如果射程够长,将其反杀也是很简单的。既然冰壶那么明显,如果不靠冰壶呢?那么,这就需要优秀的地板环境,也就是场地上有足够多的己方墨水。一般情况下,场地上有足够多的己方墨水的话,那就是顺风局了。在顺风局下,中刷四处潜行,偷袭敌人,乘其不备,让顺风局更加顺风。但是反之,逆风局,也就是地板坏境很差的情况下,那就是另一番景象了。</p><p>玩家间有这么一句对中刷的评价:“顺风成神,逆风成鬼”。因为逆风下,墨水环境很差,很难靠近对方的敌人偷袭(除非对面送上来)。丢一个冰壶等于直接暴露了中刷的位置。所以,中刷如何在逆风局下打开局面,是一个非常值得研究的话题。</p><p>另外,冰壶中刷的另一个问题是大招。砸地这个大招在低分段挺有用的,但到了高分段,真是人见人打,难怪这个大招又被称为 “自曝开关”(流泪)。这里放一个网友做的砸地被击杀的集锦:<a href="https://www.bilibili.com/video/BV1tZ4y1G7Bq">link</a>。</p><p>我感觉很难受的一点是<strong>薛定谔的一确距离</strong>,因为中刷的墨水打出去是一片。而这些墨水的伤害不是固定值,越远的伤害越低。因为最近的距离是能一拍子击杀敌人的,所以从最近到最远就会有一个分界点,超过分界点就不能够一拍子击杀敌人了。而游戏里,是不可能提示这个距离的,所以这个距离要自己把控。这个需要非常好的判断,不然容易出现我觉得能击杀敌人的距离实际却并不能。因为如果不能一拍子击杀的话,就很有可能会被反杀。再加上,如果技能里有主强的话,那么这个距离又会有微小的变动,需要重新训练手感。所以判断一确的击杀距离,是每个中刷的必修课。</p><h2 id="贴牌针管"><a href="#贴牌针管" class="headerlink" title="贴牌针管"></a>贴牌针管</h2><p><img src="S2_Neo_Splash-o-matic_promo_render.jpg" alt="贴牌针管 (图片来自 Splatoon Wiki)"><span class="image-caption">贴牌针管 (图片来自 Splatoon Wiki)</span></p><p>这把武器是通过 <a href="https://www.bilibili.com/video/BV1j7411c7hw">这个视频</a> 看到的,因为拿这把武器练习,所以也在比赛中使用了。这把武器一个特点是<strong>没有偏移</strong>!这一点非常重要,其它小枪,多多少少是有偏移的,也就是说在跳跃,或者长时间射击的话,子弹就会有概率偏离准心。但这把没有,所以如果如这把枪和对面对枪输了,我就不能找借口说:“是我运气不好,子弹偏移了,不然我肯定反杀了”。所以,用了这把枪,打不中就是打不中,没有借口。</p><p>这把武器可能是我使用时间最长的武器,这把武器比较能涂地,虽然不是最能涂的,但绝对是很能涂的一类了。涂地能帮助队友攒大招,巩固地板环境,将阵线前移等。别忘了,这个游戏的本质,很大程度上是涂地游戏。如果己方涂不了地,而对方很能涂地的话,那么己方很可能走位受限,被压倒家门口。</p><p>如果这把武器配上 2.4 的主强,那么还能做到伪三确 ———— 三枪能造成 99.9 的伤害。如果对方踩到己方墨水,或者血量稍有不满,就会被三枪带走,而不是原来所需的四枪。这在实战中,非常有用,因为实战中,对手,尤其是前排,保持满血是有点困难的:一方面,雨,水枪等大招多少带来一点伤害;其次,各种副武器的暴风伤害也是常有的事;再者,对于经常在敌方墨水上漂的双枪,更是非常容易踩上敌方墨水受伤。</p><p>贴牌针管的副武器是水球,实战中可以先用水球限制一下对方走位,还能造成点伤害,非常管用。</p><p>但一个小问题是,这把武器的射程不是很长。环境主流武器,比如精英枪,红双,射程都比它长,所以这就比较考验走位和如何靠近的问题。因此,也有一些玩家会给针管配上隐游,比如 Hanjou 的<a href="https://www.youtube.com/watch?v=VFZ0a2xwSqo">这一期</a>,<br>ツトッキー 的<a href="https://www.youtube.com/watch?v=hJU1Ya0sZjA">这一期</a>。不过毕竟精英枪和红双的定位也可以是中排,所以拿中排和前排比也不是很公平。和其它前排的话,比如喇叭,牙刷,那射程其实也能接受。毕竟,已经是小枪了,游速和走速都已经有加成了,而且涂地能力也不错,副武器和大招也挺实用,再加上已经没有弹道偏移了,如果要是在给它增加射程的话,这绝对会是 imba 的武器。所以,为了平衡性,只能限制射程了,就像圆珠笔这武器就因为太强而被官方缩短了射程。</p><h2 id="黑白开尔文"><a href="#黑白开尔文" class="headerlink" title="黑白开尔文"></a>黑白开尔文</h2><p><img src="S2_Kensa_Glooga_Dualies_Promo_Image.jpg" alt="黑白开尔文 (图片来自 Splatoon Wiki)"><span class="image-caption">黑白开尔文 (图片来自 Splatoon Wiki)</span></p><p>也叫开尔文别注,黑白 525.</p><p>好看!这是这把武器给我的第一印象。这也是我使用这把武器的原因。</p><p>这把武器有着和红双类似的定位。与红双相比,射程相近,但攻击力大多了,一枪有 52.5,可以两枪击杀敌人,是它相比于红双的优势。但劣势也非常明显,如果不翻滚,攻击力就没有 52.5,需要 3 枪才能击杀敌人,而且翻滚前的弹道偏移比翻滚后大很多,而红双即使不翻滚,也能有较好的准心。其次,它的涂地性能很弱,属于不能指望它来涂地的那种,而红双虽然也不算优秀,但相比黑白开尔文可好太多了。另外,虽然翻滚也带来一定的灵活性,但连续翻滚后的硬直也比红双大多了,连续翻滚后很可能被敌方趁机击杀。再者,翻滚前的射击时,走速也是很慢的,对枪上不占优。</p><p>但尽管如此,4 格的射程已经很不错了,超过所有小枪了,而且两枪即可带走对面,非常优秀了。也是双枪中唯一可以做到如下操作的:第一次翻滚击中第一枪,如果对面没有发现,直接第二枪,带走敌人,如果敌人发现,第二次翻滚,打中第二发,带走敌人。其它双枪都要三枪或四枪,所以很难实现这样的操作。</p><p><img src="Fizzy_Bomb.jpg" alt="扔出碳酸炸弹之后的墨水"><span class="image-caption">扔出碳酸炸弹之后的墨水</span></p><p>副武器和大招也很实用。副武器的碳酸炸弹虽然伤害不及三角雷和粘弹,但可投掷的距离较长,而且在投掷过程中也会留下墨水,这简直是另一种意义上的冰壶,可以在必要时开路,方便突进和逃跑。而且碳酸炸弹耗墨量相对较低,搭配副武器省墨技能,可以实现连续扔两个碳酸炸弹。这在很大程度上弥补了黑白开尔文不能涂地的缺点。大招的墨甲也是非常实用,在必要时为队友和自己提供保护。</p><p>另外,开尔文也有另外两把,一把蓝开尔文和一把黄开尔文。对于蓝开尔文,我不是很熟悉;对于黄开尔文,可以参考 <a href="https://www.youtube.com/channel/UCGsLewe5pUfNozxgQ4mqwbg">ティラミス</a>.</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>这是目前我用的比较多的武器,其它武器用得挺少的,如果以后再尝试其它武器的话,再另外写一篇记录和分享吧</p><h2 id="Links"><a href="#Links" class="headerlink" title="Links"></a>Links</h2><ul><li><a href="https://splatoonwiki.org/wiki/Main_Page">Splatoon Wiki</a></li><li><a href="https://www.youtube.com/channel/UCGsLewe5pUfNozxgQ4mqwbg">ティラミスちゃんねる</a></li><li><a href="https://space.bilibili.com/7170054">Boo★冬瓜</a>: 刚开始玩的时候看了很多这位 UP 主的教程</li><li><a href="https://www.bilibili.com/video/BV1Fx411J7jf">【Oct】[Splatoon2] 完全向中刷新手进阶教程</a>: 中刷启蒙</li></ul>]]></content>
<summary type="html"><p>玩《Splatoon 2》这款游戏快有一年半了,也快 1000 小时了。在其中的数十款武器中,渐渐地有了那么几把常用的武器。这篇文章就写一点我自己对这些武器的使用感受。</p></summary>
<category term="ACG" scheme="https://blog.lazzzis.com/categories/ACG/"/>
<category term="游玩" scheme="https://blog.lazzzis.com/categories/%E6%B8%B8%E7%8E%A9/"/>
<category term="Games" scheme="https://blog.lazzzis.com/tags/Games/"/>
<category term="Splatoon" scheme="https://blog.lazzzis.com/tags/Splatoon/"/>
</entry>
<entry>
<title>Sanders 眼下的社会问题及解决方案 — 读《Bernie Sanders' Guide to Political Revolution》</title>
<link href="https://blog.lazzzis.com/post/bernie-sanders/"/>
<id>https://blog.lazzzis.com/post/bernie-sanders/</id>
<published>2021-02-02T18:16:05.000Z</published>
<updated>2024-06-02T05:08:09.881Z</updated>
<content type="html"><![CDATA[<p>前阵子就职典礼上,Sanders 穿着大棉衣端坐在椅子上的照片突然在互联网上流行。这张照片再次引起了我对这位 80 岁的高龄参议员的注意。之所以是再次,是因为在 2016 和 2020 的总统选举上,Sanders 都宣布了竞选,但都失败了。其次,他经常自称为 democratic socialist(民主社会主义),尽管有这概念的支持者,但也有反对者对 “democratic” 和 “socialist” 提出了质疑。</p><p>最令我感兴趣的是,这位 80 岁高龄的参议员意外地在年轻人中有一众的支持者,这和其它政治家带来的印象特别地不同。</p><p><a href="https://www.goodreads.com/book/show/34275230-bernie-sanders-guide-to-political-revolution">《Bernie Sanders’ Guide to Political Revolution》</a>是他在 2017 年发表的著作,或许可以作为一本指引了解一下这位很受欢迎但也有不少质疑的参议员(似乎只要是政治家,都少不了大量的质疑)。</p><span id="more"></span><h2 id="教育问题"><a href="#教育问题" class="headerlink" title="教育问题"></a>教育问题</h2><p>教育问题,这个问题不仅仅是美国公民能感受到,而且对于我这种国际留学生,也是头痛的问题。一方面,是优秀的教育资源 —— 大量世界顶级的优秀学府,世界各地都有人挤破头地去申请。另一方面,是连年攀升的学费 —— 动则一年几万美金的学费,尤其是众多私立大学,5 万美金已经不是稀有的数字,更何况对于本科生来说,要准备好四年的学费。如果是公立大学,而且是该州的美国公民时,那学费才能在相对之下便宜一点,但一年也要近两万美金。</p><p><img src="tuition.jpg" alt="Tuition"><span class="image-caption">Tuition</span></p><p>学费已经是一个非常大的支出,其次是书本。我在读 Master 学位期间,每个开学的第一个星期都在头疼教材的问题。一本教材动辄 100 刀甚至更高,如果买新书,一年下来也要 1000 刀。所以大部分人都会寻求旧书或电子版。但出版社似乎也明白了学生的手段,一方面,隔几年就出新版,另一方面,要么不出电子版,就算出了电子版,那也只能租一段时间,而不能买。所以,我在学校期间,就不得不要么不用教材,只借助教授的 PPT(有些教授知道教材贵,所以大部分内容都在 PPT 上了),要么和别人共用一本教材,再或者就是寻求网络资源了。</p><p>这里不能称赞一下一位我在校期间遇到的使用了开源教材的教授。这位教授使用的是开源免费,同时也可以选择花一点费用支持纸质版的 <a href="%5Bhttps://eloquentjavascript.net/%5D(https://eloquentjavascript.net/)">Eloquent JavaScript</a> 作为教材,这对于学生来说是为之欣慰的大好消息。</p><p><img src="textbook.jpg" alt="Textbook"><span class="image-caption">Textbook</span></p><p>当然,尽管有 Financial Aids 和 Student Loans 等渠道,但对 Sanders 来说,这远远不能解决问题。因为他的目标是:<strong>TUITION FREE</strong>!</p><p>在 Sanders 看来,美国应该像丹麦,冰岛,挪威等国一样,提供免费的教育资源,甚至还应该像德国一样,还要对国际留学生实施减免政策。一个数字就是,只要 200 刀一个学期,一个美国学生就能在一所欧洲的顶级大学攻读完一份学位。</p><p>而至于政府支付的费用,虽然看上去较大,但 Sanders 认为,只要国民素质提高了,那么国民的收入和因此带来的经济收益都会提高,国家财政收入自然会跟着水涨船高的。这会是一个良性的正循环。</p><h2 id="税收和华尔街"><a href="#税收和华尔街" class="headerlink" title="税收和华尔街"></a>税收和华尔街</h2><p>读这本书时,刚好也是 WSB 与 Wall Street 空头们对战的期间。这次对战,也许侧面说明了人们对于华尔街巨头们的痛恨。</p><p>Sanders 在书中就点名指责一些大公司,像 Johnson Controls, IMB, XEROX 等,借助离岸避税天堂而逃脱了大量的缴税。这些行为在他眼中是不能接受的,必须采用法律行为弥补漏洞。通过避税等手段,这些巨头们已经获得了大量的收益,这些收益只会使得国民间的财富差距变得更加巨大。因此,Sanders 坚持要对这些巨头们收取更高的税。</p><p><img src="pay.jpg" alt="Pay"><span class="image-caption">Pay</span></p><p>在书中,也提到了巴菲特所应缴纳的税率是比他的秘书还低的,因为巴菲特的收入来源于分红,而他的秘书的收入是工资。这两者的税率不同,从而导致了巨头们的税率反而比员工还低的怪象。Sanders 也坚持认为这些税率应该保持一致。</p><p>同样这些华尔街巨头们,尤其是像标普公司等评级机构,是 Sanders 认为的 2008 金融危机的罪魁祸首。一方面,Sanders 指出,评级机构应该是中立的,非盈利的,应该被监管,从而避免再次出现金融灾难。另一方面,Sanders 也认为,他们所受到的惩罚远远不够。这里面,一个原因就是他们的体量太大,“大到不能倒”(Too big to jail),甚至政府担心对他们实施的惩罚举措会对国民经济产生负面影响。而 Sanders 则采取另一看法,“大到不能出现” (Too big to exist):就是因为他们体量过于庞大,所以他们就不应该出现在市场上。过大的体量本身就是对自由市场的潜在威胁。</p><h2 id="最低工资"><a href="#最低工资" class="headerlink" title="最低工资"></a>最低工资</h2><p>Sanders 的观点是调整最低工资到至少 $15 每小时。</p><p>首先是对现在最低工资的不满。现有的最低工资甚至不能满足一户家庭选择一个市场均价的 1b1b 的租金。这极大地影响了人们的生活质量。</p><p>其次是回应一些对此政策的批判。一个常见的批评意见是:如果最低工资提高,那么佣金增加,企业势必会减少招工。但 Sanders 表示,早在 2013 年,San Jose 就提高了最低工资标准到 $10 每小时,到了 2014 年,其就业率增长确明显超越了其它城市。也在 2014 年初,华盛顿州的 SeaTac 把最低工资提高到 $15 每小时。尽管起初也遭到大量警告说会影响就业率,但事实证明,餐馆等设施的生意明显变好,反而招了更多的工人,所以整体上最低工资反而提高了就业率。</p><h2 id="还有更多的矛盾和问题"><a href="#还有更多的矛盾和问题" class="headerlink" title="还有更多的矛盾和问题"></a>还有更多的矛盾和问题</h2><p>因为篇幅有限,这里只列举了以上三个具有代表性的问题。但书中提到了更多的问题:</p><ul><li>医疗和医保:相较于其它国家,惊人的费用和保费让民众苦不堪言。</li><li>移民</li><li>环境问题:作者提倡新能源和发展公共交通</li><li>还有更多</li></ul><h2 id="作为书籍的一些问题"><a href="#作为书籍的一些问题" class="headerlink" title="作为书籍的一些问题"></a>作为书籍的一些问题</h2><p>这本书,比较简短,基本就是就阐述问题(抱怨现状)之后提出自己的解决方案。所以作为 Sanders 本人的一本理念宣传手册来说,自然是合格的。但如果从学术严谨性上来说,就有比较大的问题了。</p><h3 id="引用"><a href="#引用" class="headerlink" title="引用"></a>引用</h3><p>这本书里确实有很多例子,也提到了一些机构发表的报告。但这些例子和报告,只有极少数在每篇章节的最后标注了来源。大部分的例子和报告,比如某某机构发表的报告,只提了机构的名字,而没有注明报告的标题或者链接。作为读者,我很怀疑数字的来源可不可靠。对于引用,我目前的态度就是,尽管大部分引用我不会去看,但没有引用会让我对文中的数字和结论抱有强烈的怀疑。</p><h3 id="论证"><a href="#论证" class="headerlink" title="论证"></a>论证</h3><p>这本书开篇提到的就是最低工资的问题,并开始就提到了要提高到 $15 的标准。尽管后文解释了提高最低工资的必要性及积极影响,但始终没有解释为什么是 15 而不是更多。我希望看到的是,就算文章没有篇幅论证数字 15 的正确性,也应该要有相关的引用来说明 15 是足够的,是合理的,是能支持作者观点的。缺乏这些论证,我在阅读时就在好奇:为什么作者不说 15 是怎么来的?为什么 15 就够了?万一 15 不够,要提高到 20 才行呢?</p><h3 id="还有讨论的空间"><a href="#还有讨论的空间" class="headerlink" title="还有讨论的空间"></a>还有讨论的空间</h3><p>大概受限于文章篇幅,其实还有一些问题没有讨论,比如枪支问题。</p><h2 id="简评"><a href="#简评" class="headerlink" title="简评"></a>简评</h2><p>读完全书,Sanders 大部分的政策给我的感觉是需要政府大量的财政支出用于教育,医疗等。而这些财政的支出是为了国民素质的整体发展,而国民素质的集体发展,自然会带来可观的,可持续的长期收益。这个长期收益,是远远大于政府的财政支出的。另一方面,现在的财政政策也具有巨大的提升空间,比如现在有一些补贴是给传统石油公司的,Sanders 坚持这些钱应该投资到新能源和国民福利上。</p><p>因此,Sanders 的政策整体上,是在向北欧学习,试图建立一个高福利的国家。确实,这个世界上,已经有采取类似政策并成功执行的国家,但对于美国先进但有无比复杂的国家,这些政策能不能平稳实施,我只能保持怀疑。</p><p>总的来说,如果是对于想了解 Sanders 政见的读者,本书不妨一读,而且篇幅不长,写作风格读起来也不费力。但只是在读文章时,记得对一些数字和结论保持批评态度,因为作者没有提供足够的引用来证明自己的观点。</p><h2 id="Links"><a href="#Links" class="headerlink" title="Links"></a>Links</h2><ul><li><a href="https://www.goodreads.com/book/show/34275230-bernie-sanders-guide-to-political-revolution">Bernie Sanders’ Guide to Political Revolution</a></li><li><a href="https://youtu.be/S5vOKKMipSA">Bernie Sanders: The Vox Conversation</a></li></ul>]]></content>
<summary type="html"><p>前阵子就职典礼上,Sanders 穿着大棉衣端坐在椅子上的照片突然在互联网上流行。这张照片再次引起了我对这位 80 岁的高龄参议员的注意。之所以是再次,是因为在 2016 和 2020 的总统选举上,Sanders 都宣布了竞选,但都失败了。其次,他经常自称为 democratic socialist(民主社会主义),尽管有这概念的支持者,但也有反对者对 “democratic” 和 “socialist” 提出了质疑。</p>
<p>最令我感兴趣的是,这位 80 岁高龄的参议员意外地在年轻人中有一众的支持者,这和其它政治家带来的印象特别地不同。</p>
<p><a href="https://www.goodreads.com/book/show/34275230-bernie-sanders-guide-to-political-revolution">《Bernie Sanders’ Guide to Political Revolution》</a>是他在 2017 年发表的著作,或许可以作为一本指引了解一下这位很受欢迎但也有不少质疑的参议员(似乎只要是政治家,都少不了大量的质疑)。</p></summary>
<category term="读书看剧" scheme="https://blog.lazzzis.com/categories/%E8%AF%BB%E4%B9%A6%E7%9C%8B%E5%89%A7/"/>
<category term="书评" scheme="https://blog.lazzzis.com/tags/%E4%B9%A6%E8%AF%84/"/>
<category term="SocialScience" scheme="https://blog.lazzzis.com/tags/SocialScience/"/>
</entry>
<entry>
<title>认识社会心理学 ——《Not by Chance Alone》与《The Social Animal》小记</title>
<link href="https://blog.lazzzis.com/post/the-social-animal/"/>
<id>https://blog.lazzzis.com/post/the-social-animal/</id>
<published>2021-01-17T23:46:21.000Z</published>
<updated>2024-06-02T05:08:09.912Z</updated>
<content type="html"><![CDATA[<p>《Not by Chance Alone》(中译:<a href="https://book.douban.com/subject/19949881/">绝非偶然</a>)以及《The Social Animal》(中译:<a href="https://book.douban.com/subject/2328458/">社会性动物</a>) 均为社会心理学家 Elliot Aronson (埃利奥特·阿伦森) 的著作。前者,为 Aronson 的自传;而后者,则是由 Aronson 编写的社会心理学入门教材。</p><span id="more"></span><p>阅读的动机是偶然在豆瓣上看到了《绝非偶然》这本书,读完后就又对《社会性动物》产生了兴趣,所以一口气就把两本读完了。我确实以前也没读过心理学相关的书籍,凭着好奇心翻开书籍,被里面提到的有趣的例子和作者深入浅出的讲述方式而深深吸引。</p><h2 id="对心理学的改观"><a href="#对心理学的改观" class="headerlink" title="对心理学的改观"></a>对心理学的改观</h2><p>现代网络已经逐渐揭开了心理学的面纱,像电视剧里 “读心” 这样的理解已经逐渐被抛弃。取而代之的,是更接近科学的看法,尽管这其中仍有一些不充分的认知。</p><p>最初,心理学之于我,有点 “哲学” 的意味。我最早接触的心理学文章,颇有一种思考人生的意图,例如,在试图解读人为什么孤独的文章里会有作者对人生意义的解读,从而帮助读者理解孤独的成因和解决方法。但后来了解到,心理学和物理学,化学一样,依托于包含了假设,实验,和分析等在内的科学方法论。因此,现在说起心理学,有些人会优先想到一个人被连接了仪器测试脑电波的场景。这其实可以理解,因为有些心理问题确实可以归结为病理问题,这方面的研究,更多被称为精神病学或神经科学。精神病学更多是在生物层面分析,医学层面分析,必要时辅以药物。</p><p>而《The Social Animal》主要介绍的,是心理学的一个分支 —— 社会心理学,一个研究社会坏境对人行为影响的心理学。<strong>科学实验</strong>在社会心理学里扮演着不可或缺的角色。在这本书中出现的所有理论和结论,除了现实世界的观察以外,更多是通过实验得出的。而这个做实验的基本方法论,和医学里常说的 “双盲实验” 是非常相似的 —— 将志愿者尽可能随机分配为控制组和实验组,这两组的任何条件,除了要实验的要素,其它的任何条件都是相同的。但这里有一点和药物测试的实验截然不同,药物测试里,患者虽然不知道自己吃的是安慰剂还是待测试药物,但仍然知道实验的目的是测试药物。而在社会心理学的实验里,却不会这么做,因为如果提前告诉了测试者实验的目的,那么测试者会有意纠正自己接下来的行为,使其行为不自然,比如如果告诉测试者接下来的实验将测试人是否会服从权威,那么测试者接下来很可能会特别注意这点,从而避免出现服从权威的行为。为了让测试者更接近自然状态,实验设计者通常会设计一个封面故事(Cover Story)。以著名的 <a href="https://www.wikiwand.com/zh-hans/%E7%B1%B3%E7%88%BE%E6%A0%BC%E5%80%AB%E5%AF%A6%E9%A9%97">“米尔格拉姆实验”(Milgram experiment)</a> 为例,实验设计者为了掩盖真正的意图,在招募志愿者时的说辞是要测试 “记忆力”。</p><p>这么做的目的,就是为了增强其科学性。这里的科学性,也包含了可重复性。仍以刚才提到的米尔格拉姆实验为例,后来的实验者多次重复了这个实验从而验证了原实验的结论,同时也改进了一些实验条件,比如,实验中的指导者是以电话方式发出指令,这种情景下的被测试者有多少不一样的反应。因为可重复性,后来的实验者,可以发现更多的问题,也可以指出原实验中得出的结论有更严格的限定条件。</p><p>实验是如此的重要,因此在总共 9 篇章节的《社会性动物》中,作者用单独的一章来解释实验的重要性,如何设计一个合理的实验等。同时,作者也对目前主流社会对社会心理学中的实验的批评做了回应,包括实验中的欺骗是否道德等。类似地,在另一本广泛应用的社会心理学教材<a href="https://book.douban.com/subject/26701760/">《社会心理学》(Social Psychology)</a> 里,也在开篇就详细阐述了实验的方法及重要性。这部分的内容,很大程度上涉及到了辩证性思维的思想,比如,相关性不代表因果性,第三者潜在因素的存在对实验的影响。了解这些思想,也有助于人们面对当今网络上各种流行的心理学段子时,能有更严谨的态度和辩证的思维去看待。也难怪,作者在提到网络上一些流行的心理学段子时也说,“我们应该先问问,‘这是否可以重现?’”.</p><blockquote><p>Today, unfortunately, there have been many pop social psychology “findings” that get public attention and then don’t pass the test of replication. But that does not mean that the basic methods of social-psychological experimentation are at fault — it means that science is moving along as it should, correcting its mistakes and advancing the findings that hold up. <strong>It also means, however, that the public should be wary of sensational, improbable, or simplistic findings and ask, “But have they been replicated?”</strong></p></blockquote><h2 id="作者成为社会心理学家的契机"><a href="#作者成为社会心理学家的契机" class="headerlink" title="作者成为社会心理学家的契机"></a>作者成为社会心理学家的契机</h2><p>作者最初是并不打算选择心理学的,因为经济问题一直困扰着他。作者的父亲在经济大萧条后失去了经营的店铺,经济变得困难,甚至作者本来也没准备读大学。是在他哥哥的劝说下,加上他哥哥就读的大学 <a href="https://www.wikiwand.com/en/Brandeis_University">Brandeis University</a> 愿意为作者提供一年学费和一份兼职才同意进入大学。但可惜的是,在大二那年,学校又突然因为资金不足而不能继续为他提供经济资助,作者只能打工挣学费,却仍旧没有足够的钱用来租房。所以,那一段时间,作者基本是睡在室外,比如树林里,没有锁的汽车的后座里。</p><p>在这样的背景下,他其实是想选择来钱更快的经济学专业的,直到偶然一次机会上了一节心理学导论课。这节课本来是作者在和一位女同学约会后,想一起陪着上课的,但这节课是由提出了著名的 “马斯洛需求理论” 的<a href="https://www.wikiwand.com/zh/%E4%BA%9A%E4%BC%AF%E6%8B%89%E7%BD%95%C2%B7%E9%A9%AC%E6%96%AF%E6%B4%9B">马斯洛</a>教授的课。这节课中提到的关于偏见的内容激发了他对童年的回忆,也触发了他更多的思考,以至于他忙于笔记而忘记了走进这间教室的原本目的。作者因为发现自己对这门学科如此地感兴趣,所以才想成为心理学家,也就在第二天把专业志愿从经济学换成了心理学。</p><p>作者在自传的序言中就提到了一个对新生的建议:比起思考 “Who am I?”,更应该思考 “Who do I want to become?”。我想,在选定心理学专业的那一刻,作者已经清楚地回答了自己的这个问题。</p><blockquote><p>For the past fifty years as a teacher, I have tried to impart this way of looking at things to my students. Early in my career I came to understand that this was the single most precious gift I could ever give them. Students are continually asking themselves, “Who am I?” My goal was to get them to reframe the question into <strong>“Who do I want to become?”</strong> Once they arrive at their own answer, they must also learn that getting there won’t come by chance alone.</p></blockquote><h2 id="优秀的入门教材"><a href="#优秀的入门教材" class="headerlink" title="优秀的入门教材"></a>优秀的入门教材</h2><h3 id="大量的例子"><a href="#大量的例子" class="headerlink" title="大量的例子"></a>大量的例子</h3><p>这本教材和其它学科的美国经典教材有一个共同显著的特点,就是富含大量生动且贴近生活的例子。比如在我阅读的第十二版里,就有多处以 2016 年美国总统大选为例解释偏见和冲动行为的发生原因。除此之外,也有发生在作者自己身边的例子,比如在解释旁观者效应这一节中,就提到了作者在野营中的一次经历:在这次野营的晚上,附近一个帐篷里发出了一声惨叫,而当作者走出一探究竟时,发现已经有很多附近帐篷的人提着灯围在那儿了。如果用旁观者效应解释的话,大家应该都害怕得或冷漠得呆在自己的帐篷里才对,但作者借这次亲生经历来提醒读者,旁观者效应有着更为苛刻的条件,同时存在其它潜在因素可以打破这个效应,但仍需大量实验证明。</p><h3 id="带着疑问阅读"><a href="#带着疑问阅读" class="headerlink" title="带着疑问阅读"></a>带着疑问阅读</h3><p>“带着疑问阅读”,是备受推崇的一种阅读方法。这本教材,为了激起读者的疑问,在教材的第一章便列举了 11 个真实发生的小故事,而读者要想解释这 11 个小故事,明白其中的缘由,就需要一节一节地阅读和思考。在每个章节的第一篇,作者也依旧举一个例子作为引子,带出主题。当阅读完一章之后,再回看之前的例子,便能豁然开朗:看上去荒谬的现象背后,也存在合理的解释。</p><h3 id="主题"><a href="#主题" class="headerlink" title="主题"></a>主题</h3><p>《社会性动物》包含了比较流行的,对初学者比较感兴趣的话题:自我辩解,大众交流,从众性,偏见等。因为作者 Aronson 致力于认知失调(Cognitive Dissonance)的研究,所以其中的一章 “自我辩解” 其实就是围绕着这一理论展开的。在之后的其它章节中,作者也多次用认知失调来解释现象和实验结果。</p><h2 id="推荐"><a href="#推荐" class="headerlink" title="推荐"></a>推荐</h2><p>因为这两本书包含了太多的内容,但这些内容又是那么地生动有趣,我想我这么一篇小结,也仅仅分享了我在阅读过程的感想的一部分而已。把这本书推荐给没有了解过心理学但又想要了解的读者。这两本书籍,不仅可以帮助我们进一步理解社会中的一些奇怪现象,同时通过这些现象,我们又能反窥我们自己,了解我们为什么有时能做出另自己事后愧疚懊悔和疑惑的,与自己预期不符的行为。</p>]]></content>
<summary type="html"><p>《Not by Chance Alone》(中译:<a href="https://book.douban.com/subject/19949881/">绝非偶然</a>)以及《The Social Animal》(中译:<a href="https://book.douban.com/subject/2328458/">社会性动物</a>) 均为社会心理学家 Elliot Aronson (埃利奥特·阿伦森) 的著作。前者,为 Aronson 的自传;而后者,则是由 Aronson 编写的社会心理学入门教材。</p></summary>
<category term="读书看剧" scheme="https://blog.lazzzis.com/categories/%E8%AF%BB%E4%B9%A6%E7%9C%8B%E5%89%A7/"/>
<category term="书评" scheme="https://blog.lazzzis.com/tags/%E4%B9%A6%E8%AF%84/"/>
<category term="SocialScience" scheme="https://blog.lazzzis.com/tags/SocialScience/"/>
<category term="Psychology" scheme="https://blog.lazzzis.com/tags/Psychology/"/>
</entry>
<entry>
<title>工作,生活,以及其它,在 2019 与 2020</title>
<link href="https://blog.lazzzis.com/post/the-end-of-2020/"/>
<id>https://blog.lazzzis.com/post/the-end-of-2020/</id>
<published>2021-01-01T03:15:30.000Z</published>
<updated>2024-06-02T05:08:09.909Z</updated>
<content type="html"><![CDATA[<blockquote><p>「明日も明後日も 明々後日も来年も 君を想って言葉を描くだろう」ー 椎名もた「アイケアビコーズ」</p></blockquote><span id="more"></span><h2 id="工作"><a href="#工作" class="headerlink" title="工作"></a>工作</h2><p>现实很残酷,根本不会管我做好心理准备了没有。</p><p><img src="https://as2.bitinn.net/uploads/cq/cjn9z685e0000428he9lwuccq.1440p.jpg" alt="工作工作"><span class="image-caption">工作工作</span></p><h3 id="接到-offer-后的喜悦"><a href="#接到-offer-后的喜悦" class="headerlink" title="接到 offer 后的喜悦"></a>接到 offer 后的喜悦</h3><p>就像在上一篇文章里说的那样,我因为在小公司实习待得不开心后,格外想去流程规范,技术先进的大公司。而在这种期待之下,我拿到了一个大公司的 offer。自然是喜悦的不行,于是 2019 年的前半年几乎都在玩,中间也只是去看了点 Angular 相关的技术而已。</p><h3 id="选组的将就"><a href="#选组的将就" class="headerlink" title="选组的将就"></a>选组的将就</h3><p>因为我一直做前端相关的工作,自然也会倾向于选择一个做前端的组,尤其是 web 前端。而 google 一个重要产品就是 chrome,我想当然地与 hr 说想去 chrome 组。而事实很意外,hr 给了三个组都是 Android app 开发的,而我和这三个组的 manager 联系了后,都被拒绝了。而下一个组是 Chrome on Android,经历了前三次的失败后,我心理自然放低了点要求,没多问什么。不出意外地,对面的 manager 很中意。</p><p>那问题来了,我该不该去这个组?</p><p>我当时考虑的是:</p><ol><li>具体技术不重要,重要的是处理问题的能力。</li><li>小组容易晋升。这是我问了几个在 Google 工作几年的朋友告诉我的。我选择相信。另一方面,就像小班教育会比大班教育有优势一样,我也相信小组会比大组好。</li><li>相比于一些开发 Google 内部独有工具的组来说,开发 Android 的经验好歹以后能在其它公司的 App 开发上有用处。</li></ol><p>虽然和最初的 web 前端不一样,但想着以后也早晚走出舒适圈,学习新事物。我就决定选了这个组,虽然心里还是有一点将就的感觉。</p><h3 id="入职"><a href="#入职" class="headerlink" title="入职"></a>入职</h3><p>2019 年下半年开始入职后,我开始反思当初考虑的是不是正确:</p><p>第一点到没什么问题。写一份优秀的设计文档,编写可测试的代码等等,这些能力确实与具体技术关系不大</p><p>第二点的话,容不容易晋升我得不出结论,但小组的优势确实体会到了。现在包括我和 manager 在内,也总共就 6 个组员。比起其它 10 多个组员的组来说,开组会的沟通有效很多。而且 manager 至今坚持一周至少一次的 1:1。我起初认为这没什么,后来了解了几位朋友的情况:实际上,不同组之间在这一点上差异也很大,有的才两周一次。我的 manager 在 WFH 开始期间,还主张一周两次,来询问我们的近况,提供帮助。另一方面是,这个组给我的工作氛围很好,几乎(虽然偶尔还是有例外)没人会在周六或晚上发邮件和交 CL。我也没有感觉到有办公室政治的倾向。所以,总体来说,组内的氛围我目前还是比较喜欢的。</p><p>第三点的话,和我预期完全相反。首先就是现在 Kotlin 已经是 Android 的第一开发语言了,但现在我们还在用 Java 8,同时也是因为 Android 只支持到 Java 8。类似地,也有历史原因的缘故,我们这个组至今没有使用任何 Jetpack 相关的开发组件,也没有 guice 等依赖注入是的管理(虽然没有依赖注入是好事也说不定)。总的来说,和主流是相差甚远了。这里,也打破我当初一个纯粹的假设:既然是自家的东西,自家的技术,当时应该是用自家最新的了咯,不然怎么起带头示范作用?我想错了,事实远比想象复杂。</p><h3 id="关于-Career-Path"><a href="#关于-Career-Path" class="headerlink" title="关于 Career Path"></a>关于 Career Path</h3><p>其实我一直没想好未来几年努力的方向,现在姑且是朝着晋升去的,目标从 L3 升到 L4,然后以此类推。但我还是想找一点更多的意义。</p><p>一方面,当别人已经在一年两年里升级到 L4 了。而我自己总觉得自己的 impact 很小:相比于别人动不动就是多少多少 revenue 的项目,我自己的 UI 组件似乎很难寻找一个量化的,体现自己 impact 的指标。这一点似乎是在量化 UI 效果方面的一个通病。</p><p>另一方面,体会不到自己的成长。似乎每一年的总结里,总上面有这句话,真不清楚是自己不知道自己的成长,还是真的没有成长。</p><p>我猜想,大概是缺少一种正反馈吧,一种看的到自己成长的正反馈吧。</p><h2 id="生活"><a href="#生活" class="headerlink" title="生活"></a>生活</h2><h3 id="最后的校园生活"><a href="#最后的校园生活" class="headerlink" title="最后的校园生活"></a>最后的校园生活</h3><p>2019 年上半年是最后一个学期,只有一节课,加上已经确定工作了,真是自在得不行。可惜因为钱大多拿去交学费了,口袋里的钱并不多,不足以支撑我四处游玩。</p><p>唯一的长途旅行是在春假,先后去了 Boston 和 Boise 拜访了几个小伙伴。</p><p><img src="https://i.loli.net/2021/01/01/pj2Ugr4LinPcYWJ.jpg" alt="在 Boston"><span class="image-caption">在 Boston</span></p><p>然后就是经常去对岸的 NYC 了。这大概最没压力的一段时间了吧。</p><h3 id="游戏"><a href="#游戏" class="headerlink" title="游戏"></a>游戏</h3><p>入职后就买了 Switch。沉迷于动森, Splatoon 2 和塞尔达。这大概是我的第一部游戏机。</p><p><img src="https://i.loli.net/2021/01/01/POKDF7aLuGqW4Ce.jpg" alt="Switch 上的游戏"><span class="image-caption">Switch 上的游戏</span></p><h3 id="动漫"><a href="#动漫" class="headerlink" title="动漫"></a>动漫</h3><p><a href="http://bgm.xiadong.info/report/lazzzis?year=2020">2020 年的番剧</a></p><p>总体上惊喜不是很多</p><ul><li>把 EVA 给补了:其实我小时候没看过《天鹰战士》</li><li>《欢迎来到 NHK》:代入感太强,因为感觉自己曾经差点会变成一个 hikkimori。</li></ul><h3 id="漫画"><a href="#漫画" class="headerlink" title="漫画"></a>漫画</h3><p><a href="http://bgm.tv/subject/214942">月曜日の友達</a></p><p>满分神作。像诗一样优美的对话与独白,精美的分镜,恰到好处的涂黑和留白,童话般的结局 — 一个关于成长与朋友的故事,并不复杂,但在阿部共実老师的创作下,却能直击我的内心。很久没有遇见能令我这么心动的作品了。</p><p>我甚至无法用言语表达对这部作品的喜爱,这简直是我理想中的故事。</p><h2 id="其它"><a href="#其它" class="headerlink" title="其它"></a>其它</h2><ul><li>开始阅读与技术无关的,社会人文类的,非文学的书籍,如 <a href="https://www.goodreads.com/book/show/71730.Nonviolent_Communication">Nonviolent Communication: A Language of Life</a>, <a href="https://www.goodreads.com/book/show/6934913-the-shortest-history-of-europe">The Shortest History of Europe</a></li><li>有一段时间,大概长达半年多,因为白天工作,晚上沉迷游戏,并没怎么做和学习开源项目</li><li>把日语过了 N3,算是回应了 18 年总结末尾关于 “学习新语言” 的目标。只是本来可以考 N2 的,但可惜北美考场被取消了。</li><li><del>这两年间除了总结,没有写新文章</del></li></ul><hr><h2 id="Flag"><a href="#Flag" class="headerlink" title="Flag"></a>Flag</h2><p>2020 年年中的时候看了心理医生,谈了两次话。导火索是和一位非常要好的朋友的巨大争执。但深层原因其实是恰好当时的我因为对未来的迷茫以及对自我的极度否定而陷入了深深的低谷和自责,再加上缺少倾诉烦恼的对象,导致了一次内心的极度抑郁。平时 12 点就睡觉的我在那两周每天晚上都熬到 4 点甚至 5 点左右,白天工作也精神恍惚。不过还好,也不是什么疾病,在引导下,很轻松地解决了。更简单地说,这其实是自己对自己的压迫而产生的巨大的焦虑感和挫败感导致了自己内心的一次奔溃。所以现在的话,我会尝试适当放低对自己的要求,避免无意义的比较,因此大概率是不会重蹈覆辙了。</p><p>至此,我也不想立什么奇怪的 flag。仅希望自己能寻找到让自己开心的事情就好,同时祝阅读此文的各位生活愉快!</p>]]></content>
<summary type="html"><blockquote>
<p>「明日も明後日も 明々後日も来年も 君を想って言葉を描くだろう」ー 椎名もた「アイケアビコーズ」</p>
</blockquote></summary>
<category term="近况及总结" scheme="https://blog.lazzzis.com/categories/%E8%BF%91%E5%86%B5%E5%8F%8A%E6%80%BB%E7%BB%93/"/>
<category term="自言自语" scheme="https://blog.lazzzis.com/tags/%E8%87%AA%E8%A8%80%E8%87%AA%E8%AF%AD/"/>
</entry>
<entry>
<title>我的 2018</title>
<link href="https://blog.lazzzis.com/post/the-end-of-2018/"/>
<id>https://blog.lazzzis.com/post/the-end-of-2018/</id>
<published>2019-02-14T05:31:23.000Z</published>
<updated>2024-06-02T05:08:09.909Z</updated>
<content type="html"><![CDATA[<blockquote><p>「すべて 夢見ることから」ー 椎名もた「夢の値段」</p></blockquote><span id="more"></span><h1 id="动机"><a href="#动机" class="headerlink" title="动机"></a>动机</h1><p>我最初是想把这篇年终总结给鸽了的。</p><p>与前两年一样,又是不算满意的一年,似乎没什么好写的,于是就想:不写了吧!</p><p>也是就这样拖了一个月。</p><p>后来想想,2018 年也是过来了,也得留下点什么。就算不满意,这也是过来了,也是不可否认的事实。</p><p>于是趁着农历新年的尾巴,写了这篇总结。</p><h1 id="夏天"><a href="#夏天" class="headerlink" title="夏天"></a>夏天</h1><p>夏天的暑假是在一个小公司度过的。这是一个在 Brooklyn, NYC 的小公司,小到只有一个办公室。找到这份实习完全是因为机缘巧合认识了一个在这公司的一个中国人。而且他是这公司唯一的前端工程师,因此他有很大的话语权能决定招怎样的前端程序员。因为我的背景比较符合该公司的业务需求,而且该公司也确实在找前端工程师,加上当时很快就暑假了,剩下的机会不多,所以我就去这家公司实习了。</p><p>我在这公司学到了什么嘛?很可惜,并没有。</p><p>我想来想去,收获大概就是:</p><ul><li>简历丰富了一点</li><li>赚了点钱</li><li>让我更想去大公司了</li></ul><p>这个小公司的前端仅仅停留在完成需求上面,没有追求代码的美观,可维护性,运行效率等等方面。可以说,该公司的项目代码里存在各种反模式的设计,就连常说的 DRY 也做不到。举个最简单的例子,这公司的项目里,有很多复制粘贴的代码,这些代码之间仅仅之间仅仅是多一个标签或少一个标签而已。在这明显可以封装成组件的情况下,项目也没有对此进行优化。导致的结果就是,一旦这一部分有一丁点需求改动,就必须找到所有类似代码进行修改,非常费时费力。</p><p><img src="https://as2.bitinn.net/uploads/legacy/yg/cjb04lrij01qdxz5njuy4xcyg.1200.jpg"></p><p>所以想在小公司学到东西,还是得先保证能有何大公司一样的流程,并且有经验丰富从业人员的指导。而这公司明显不符合以上两点。所以这让我对小公司的选择变得更加谨慎,而对大公司更多了一份向往之情。</p><p><img src="https://as2.bitinn.net/uploads/legacy/qj/cjb04g22l01q5xz5nxxpvnoqj.1200.jpg"></p><h1 id="秋天"><a href="#秋天" class="headerlink" title="秋天"></a>秋天</h1><p>紧跟在夏天的实习之后的是紧张的秋招。在 9 月初投了很多大公司。其中报比较大期望的是 Amazon。即使该公司去年(2017)缩招了,今年的流行论调也依旧认为,相比其它大公司而言, Amazon 是招 New Grad 比较多。</p><p>但很失望的是,仅仅几天时间,很多大公司就把我拒了,包括 FaceBook 和 Amazon。而出乎意料地,Google 给了我一次机会,在我完成 OA 后,马上就邀请我去 Onsite。我很吃惊,因为正常情况下,OA 之后是电面才对,而这次电面被 skip 了。</p><p>“这是良机!” 我这么认为。</p><p><img src="https://as2.bitinn.net/uploads/ce/cjs45z370003b1t8h680kjxce.1080p.jpg" alt="不要犹豫 去抓住良机吧"><span class="image-caption">不要犹豫 去抓住良机吧</span></p><p>距离 Onsite 一个月,我开始疯狂刷题。期间也找了很多人帮我 Mock。一直到 Onsite 为止。</p><p>而在这一个月的疯狂刷题间,我不知不觉地下了一个赌注 —— 我几乎放弃了很多中小公司的申请机会。因为这一个月间,我把 Google 的面试看得极其重要,在忙于面经与算法题之间,几乎没有去搜集任何其它公司的招聘信息。那时的我把这次机会看得太重了,因为其它大公司已经把我拒了,我只有这么一个机会去大公司了,失去这次机会的话,我只能怀着不甘的心情去小公司甚至是 ICC 了。</p><p>我清楚地记得在暑假实习时的小公司的痛苦时光。实在不想去流程不规范的,没有大牛的小公司了。而优秀的小公司实在是少,而且招人又少。还有,糟糕地是,一些中小公司的学历筛选,尽管他们没有写在 Job Description 上,但公司内给我内推的人就善意地提醒我不要报太大希望 —— 我就读的学校在美国百名徘徊,离他们期望的前 50 相去甚远。在这种不利情况下,我只能看好只有招人多且相对不存在学历鄙视的大公司了。</p><p>怀着这种心情,我在 10 月底进行了 Onsite。题目也是算法题,中规中矩,不算太难。在 Mountain View 呆了 2 天整,后来就回美东了。</p><p>大概过了几周,结果也出来了。最后是在感恩节前一天签下了 Offer。一切也算是圆满。</p><p>签好之后的第一感觉就是松了一口气,至少未来几年的生活算是有个着落了。</p><p>说起来也确实是幸运,后来知道今年 Google 扩招了不少,很多人借机踏上了这条船,这其中也包括我。换作前几年的话,我想我应该没有这么幸运的吧!</p><h1 id="下一年"><a href="#下一年" class="headerlink" title="下一年"></a>下一年</h1><p>确定了工作了之后,生活似乎轻松了许多。最后一学期的课程也极其轻松。看着空空的时间表,“尝试一些没有过的事情吧” 我这么对自己说。“无论是什么都可以,除了敲代码!”。</p><p>已经花了很多的时间在代码上了,这确实也是我兴趣的一部分。但这似乎太单调了 —— 我的生活还是太宅了,除了敲代码,似乎就是看番了。</p><p>所以走出去吧,跨出这“四叠半”的房间。去哪儿旅行一会,或许是一个不错的选择,不用太远,就算是附近的城市也好,只要不是一直宅着。</p><p>即使是在家的时间,也学点除了代码的东西吧,包括学一门新语言也好。毕竟,等以后工作了,似乎就很难了花大量时间学了。</p><hr><p><img src="https://i.loli.net/2019/02/14/5c64fb2d67b53.jpg" alt="对岸 -- 摄于 2018 年 2 月 13 日"><span class="image-caption">对岸 -- 摄于 2018 年 2 月 13 日</span></p>]]></content>
<summary type="html"><blockquote>
<p>「すべて 夢見ることから」ー 椎名もた「夢の値段」</p>
</blockquote></summary>
<category term="近况及总结" scheme="https://blog.lazzzis.com/categories/%E8%BF%91%E5%86%B5%E5%8F%8A%E6%80%BB%E7%BB%93/"/>
<category term="自言自语" scheme="https://blog.lazzzis.com/tags/%E8%87%AA%E8%A8%80%E8%87%AA%E8%AF%AD/"/>
</entry>
<entry>
<title>参加初音 2018 纽约演唱会</title>
<link href="https://blog.lazzzis.com/post/miku-2018-expo-in-nyc/"/>
<id>https://blog.lazzzis.com/post/miku-2018-expo-in-nyc/</id>
<published>2018-07-19T04:46:34.000Z</published>
<updated>2024-06-02T05:08:09.895Z</updated>
<content type="html"><![CDATA[<p>上周六,7 月 14 日,miku 在纽约城举办了一场演唱会,而这也是我第一次参加 miku 的演唱会。在这里分享一些经历,感悟及收获吧。</p><span id="more"></span><h1 id="关于购票"><a href="#关于购票" class="headerlink" title="关于购票"></a>关于购票</h1><p>很偶然在推特上看到了初音演唱会的消息。纽约演唱会的购票由 ticketmaster 支持,支持网上购票和现场通过手机 APP 入场,所以非常方便。不过购票时注意一下,官方会提供一个保险,价值大约 7 刀。这个保险主要是用于保障你购票和参加演唱会时的安全。当时我没有注意,就把保险一起买下来。所以如果觉得保险没用的话,记得购票时取消购买保险的选项。</p><h1 id="关于预售"><a href="#关于预售" class="headerlink" title="关于预售"></a>关于预售</h1><p>演唱会前,官方在 <a href="https://mikumerch.com/">mikumerch.com</a> 有部分商品的预售。因为是预售,我自然认为这些商品都应该是这对 2018 年演唱会而设计的。但买来后发现,一些衣服和帽子上清楚地印着 <code>miku expo 2016</code>(所以这些应该就是当年的余货了)。</p><p>不过我买的那一根应援棒上面写的倒还是 <code>2018</code>。</p><p>除了上面提供的网站,官方还提供了另一个网站 <a href="https://www.forfansbyfans.com/feature/miku-expo-challenge-designs-from-the-fan-forge.html">miku expo from the fan forge</a>。这些商品全是粉丝设计,但质量一点也不差,在演唱会当天我穿着的衣服就是从这网站购买的(其实是因为只有这里能买到 S 码的衣服了。。)。</p><h1 id="关于排队"><a href="#关于排队" class="headerlink" title="关于排队"></a>关于排队</h1><p>按照时刻表,应该是 8 点开始,7 点入场。当我觉得入场前应该有场贩之类的,所以提早了 2 个半小时到达,也就是 4 点半到达。计划是在入场前好好逛逛场馆。</p><p>然而事实是场馆前已经排起了近以百米的长队。而且他们都不是在等场贩,而全是在等待场馆开门。</p><p>于是在 7 点入场前,我足足等了近 2 个小时。当时太阳还没下山,队伍也都在排街道上,于是这两个小时我也一直在晒太阳。啊,纽约的太阳啊。</p><p>排队的时候,跟旁边几个人尬聊了一会,发现周围几个人里就只有我一个是第一次参加,其他人全部都已经至少参加过一次了。</p><p>队伍越来越长,发现全家出动的不在少数,有很多全家 cos 的前来排队。</p><p><img src="https://i.loli.net/2018/07/20/5b5148b6d5898.jpg" alt="长队"><span class="image-caption">长队</span></p><h1 id="关于入场"><a href="#关于入场" class="headerlink" title="关于入场"></a>关于入场</h1><p>入场检查东西是还被保安拦下了。。原因是我带了 iPad,被要求寄存。我只好乖乖拿去寄存了,寄存还收了我 6 刀。</p><p>不过好处是我不用背着包听演唱会了 – 我可以毫无顾及地跳了。所以我入场时就只拿着一个应援棒了。</p><p>入场后,因为一层全是站的,并没有座位分配,所以需要尽可能往前排,否则只能挤到最后面。</p><p>而且欧美人普遍身高较高,注意选一个视线好一点的位置。或者干脆去购买二层的一些票(有座位分配,保证能看到,但有点距离)。</p><h1 id="关于开场"><a href="#关于开场" class="headerlink" title="关于开场"></a>关于开场</h1><p>时间一到,我就把手机调成飞行模式了,不想被任何人和事打扰。</p><p>在全息影像打开前,一直处于放一些歌曲的状态。计划时间是 8 点整开始,所以 8 点一到,底下的人就已经躁动了。但事实是 8 点之后仍然没有开始,包括机器也还没打开。</p><p>但底下的人仍然耐心等待,很多人已经开始挥动应援棒了。中间不止一次一起喊 “miku miku”。甚至还有一群人喊起了 “USA USA” (这应该是美国特色了把。。)。</p><p>大概 8 点半,机器打开,全场疯狂。</p><p><img src="https://i.loli.net/2018/07/20/5b5148cf16be7.jpg" alt="开场前的呼唤"><span class="image-caption">开场前的呼唤</span></p><h1 id="关于歌单"><a href="#关于歌单" class="headerlink" title="关于歌单"></a>关于歌单</h1><p>歌单其实我在演唱会前一个星期就知道了。因为此处美国巡演中,nyc 是最后一场,而之前的场次的歌单已经在网上有信息了,比如这里 <a href="http://vocaloid.wikia.com/wiki/HATSUNE_MIKU_EXPO_2018_USA_%26_MEXICO">link</a>。只要知道前几场的歌单,基本就能猜到当天的歌单了。</p><h1 id="关于打-CALL"><a href="#关于打-CALL" class="headerlink" title="关于打 CALL"></a>关于打 CALL</h1><p>因为这是我第一次参加日系的演唱会(甚至可能是人生中参加的第一场演唱会),所以知道会有打 CALL,提前就把应援棒准备好了。</p><p>而且非常幸运地是,边上几个亚裔小哥,非常会打 CALL,完全带动了周围的人,所以我当时只要跟着打 CALL 就好了。</p><p>不过,我对打 CALL 仍然准备不充分,并不明白一些打 CALL 的节奏和方式。在演唱会第二天,在知乎推荐下发现了这么一个 B 站的 UP 主,<a href="https://space.bilibili.com/700631/#/">H.Mos</a>。这位 UP 主有一些关于打 CALL 的理论和实践教程,很值得推荐。</p><p>值得一提的是 ルカルカ★ナイトフィーバー (Luka Luka★Night Fever) 这首曲子的打 CALL。这算是全场最好的打 CALL 了(个人感觉)。在刚才推荐的视频教程里也用了这首歌讲例子(要是我能提前看这视频就能在当天更好地打 CALL 了)。</p><p>话说我当时跟跳的时候还踩到了后面小哥的脚 😥。</p><h1 id="关于场贩"><a href="#关于场贩" class="headerlink" title="关于场贩"></a>关于场贩</h1><p>场贩就两个小摊位,人很多,要排队。不过比入场要好多了。排个 5 分钟就好。</p><p>很残念的是轮到我的时候,帽子卖完了。</p><p><img src="https://i.loli.net/2018/07/20/5b514a1f732c8.jpg" alt="现场购买的一张 CD"><span class="image-caption">现场购买的一张 CD</span></p><h1 id="关于-encore"><a href="#关于-encore" class="headerlink" title="关于 encore"></a>关于 encore</h1><p>Encore 有点乱。。因为大家喊的都不同,无法统一起来,喊啥的都有:”miku miku”,”Encore”, “もう一回”,甚至还有 “USA”。</p><h1 id="关于演唱会后"><a href="#关于演唱会后" class="headerlink" title="关于演唱会后"></a>关于演唱会后</h1><p>结束时已经快 11 点了。除了兴奋之余,还感觉到特别的饿。。因为我只吃过午饭。。</p><p>结束后跟几个大佬们去吃饭,找了几家店都发现要不是关门,要么就是人满为患,最后还是在某个麦当劳吃了一餐。</p><p><img src="https://i.loli.net/2018/07/20/5b5148f92332e.jpeg" alt="Thank you, New York City"><span class="image-caption">Thank you, New York City</span></p><h1 id="整体评价"><a href="#整体评价" class="headerlink" title="整体评价"></a>整体评价</h1><p>非常棒,无法用言语表达。整场演唱会都沉浸于氛围当中,你能做到的就是欣赏和打 CALL,你甚至没有时间拿出手机拍照。</p><p>如果有机会参加,千万不要错过。</p><h1 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h1><p>但其实这本来可以是第二次的。初音曾在 2015 年的时候,在上海举办过为期两天的演唱会。</p><p>当时的我其实非常适合去参加这次演唱会:一是当时我在杭州读本科,具体上海很近,可以很方便地在两地往返,而是我票价可以接受,虽然不一定负得起 VIP 票,但普通的票是完全没问题的。</p><p>但是很遗憾的是当时太保守了(认识那天会有事去不了),以及其它一些个人原因,没有买票。到演唱会的第二天,我通过网络直播看完了全场。从看完的那一刻起,我发誓如果还有下次机会,绝对不会再让她溜走了。</p><p>于是,在今年 5 月初的时候,我偶然在 twitter 上看到了 miku 北美演唱会的消息,所以当时的我毫不犹豫地买下了 nyc 那场的票 – 兑现自己曾经的诺言。</p>]]></content>
<summary type="html"><p>上周六,7 月 14 日,miku 在纽约城举办了一场演唱会,而这也是我第一次参加 miku 的演唱会。在这里分享一些经历,感悟及收获吧。</p></summary>
<category term="ACG" scheme="https://blog.lazzzis.com/categories/ACG/"/>
<category term="游玩" scheme="https://blog.lazzzis.com/categories/%E6%B8%B8%E7%8E%A9/"/>
<category term="ACG" scheme="https://blog.lazzzis.com/tags/ACG/"/>
</entry>
<entry>
<title>Putong OJ v2.0 开发过程中的踩坑记录</title>
<link href="https://blog.lazzzis.com/post/issues-in-the-development-of-putongoj-v2/"/>
<id>https://blog.lazzzis.com/post/issues-in-the-development-of-putongoj-v2/</id>
<published>2018-05-28T00:54:46.000Z</published>
<updated>2024-06-02T05:08:09.893Z</updated>
<content type="html"><![CDATA[<p>在学校指导老师的要求下,同时 <a href="https://github.com/Kerminate">Kerminate</a> 想把写 OJ 作为毕业设计的情况下,我和 Kerminate 决定开发 2.0 版本。具体的特性已经在项目地址 <a href="https://github.com/acm309/PutongOJ">PutongOJ</a> 说明。这里主要说一下这次开发中的坑。</p><span id="more"></span><h1 id="项目文件结构"><a href="#项目文件结构" class="headerlink" title="项目文件结构"></a>项目文件结构</h1><p>在后端结构上,直接采用了之前的项目文件结构,结果可以看到,几乎所有文件夹都放在项目一级目录下,包括 <code>controller</code>, <code>model</code> 文件夹等。现在看来,应该都把它们放在一个 <code>src</code> 文件夹下的。因为如果采用这种方式,那么使用 <code>babel</code>, <code>tsc</code>, <code>eslint</code> 等工具时,可以更方便的指定需要操作的文件夹。不然现在,如果我要使用这些工具,我需要指定一些需要被工具 <code>ignore</code> 的文件夹,比如 <code>public</code> (里面可能包含一些编译好的前端 js 文件)。</p><h1 id="i18n"><a href="#i18n" class="headerlink" title="i18n"></a>i18n</h1><p>原先计划是全用英文的,因为觉得大多数单词都很常见,比如: <code>Problem</code>, <code>Status</code>, <code>Wrong Answer</code> 等。而且,正式比赛里,题面都是英文的,因此正常情况下,使用者对英文是不会排斥的。</p><p>但是这里我想错了。有很多使用者其实会排斥英文界面。究其原因,一是因为指导老师除了在 acm 教学上会使用 OJ,在平时其它授课,比如 C 语言等,仍然会使用这个 OJ:在这个情况下,这些使用者,也就是学生,大多不会参加 ACM,也觉得做英文界面是多次一举。另外就是,很多使用者是大一学生,大部分英文水平还没经过四六级的磨练,而且有些高考英语也不怎么好,因此在英语水平上可能并不是特别理想。</p><p>就像有些人,一看到书上密密麻麻的数学公式时就会选择直接跳过不读一样,一些学生看到英语也会直接跳过不读。</p><p>在这个要求下,我觉得加上 i18n 支持是必要的。而且现在几乎所有现代网站都有 i18n 支持,实现这个功能对增加用户体验也是挺有好处的。如果未来有机会,再实现这个功能吧。</p><h1 id="docker-中允许-ptrace-操作"><a href="#docker-中允许-ptrace-操作" class="headerlink" title="docker 中允许 ptrace 操作"></a>docker 中允许 ptrace 操作</h1><p>OJ 判题端使用到 ptrace 对子进程进行跟踪控制。但是在默认情况下,在 docker 容器内,这项特性是不被支持的。</p><p>起初我注意到了判题端总是 ptrace 失败的问题,但我一直猜测原因出在判题端本身的实现上。直至我偶然情况下,没有在 docker 容器内测试,而是在一台 linux 服务器上测试时,才发现此时判题端并不会出现 ptrace 失败的问题。之后也猜测了是否是 docker 容器的 linux 版本的问题,不过幸运的是,直接在 google 上以 docker ptrace 为关键字搜索就能知道问题原因。</p><p>解决方案就是开启 docker 对 ptrace 的支持。如果是 docker-compose file 的话,只需加上</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">cap_add:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">SYS_PTRACE</span></span><br></pre></td></tr></table></figure><h1 id="前端-UI-库的选择"><a href="#前端-UI-库的选择" class="headerlink" title="前端 UI 库的选择"></a>前端 UI 库的选择</h1><p>在最开始挑选 UI 库的时候,我首先把 Material 风格的给排除了。原因是个人认为 Material 风格不适合 OJ。</p><p>而主要负责前端编写的 Kerminate 首先使用的是 ElementUI,但 Kerminate 反应这个并不好用,因此又选择了 iView (虽然采用了 iView 了后,也抱怨过 iView 有些组件也不好用)。</p><p>记得当时可选范围限定在了 <a href="https://github.com/vuejs/awesome-vue#frameworks">awesome-vue</a> 列表上出现的 UI 库。与当时相比,现在比以前增加了 5 个左右,而且现在增加了 <code>vue-antd-ui</code>。</p><p>目前 UI 库使用的是 iView,至于如果有 v3.0 的话,要不要换 UI 库,就看那时候的 OJ 维护者了。</p><h1 id="未来计划"><a href="#未来计划" class="headerlink" title="未来计划"></a>未来计划</h1><h2 id="i18n-1"><a href="#i18n-1" class="headerlink" title="i18n"></a>i18n</h2><p>这个上面提过,个人认为有必要支持。</p><h2 id="TypeScript-与-egg-js"><a href="#TypeScript-与-egg-js" class="headerlink" title="TypeScript 与 egg.js"></a>TypeScript 与 egg.js</h2><p>其实 v2.0 就可以用上 TypeScript。只是当时觉得好像这个项目这么小,用不用也无所谓。但现在想想,为后来的维护者们考虑,使用 TypeScript 可能对他们理解和维护项目能有所帮助。</p><p>至于 egg.js 么,虽然我是随意了,不过有很多人向我推荐啦。如果我觉得确实好的话,就考虑未来用上吧。</p>]]></content>
<summary type="html"><p>在学校指导老师的要求下,同时 <a href="https://github.com/Kerminate">Kerminate</a> 想把写 OJ 作为毕业设计的情况下,我和 Kerminate 决定开发 2.0 版本。具体的特性已经在项目地址 <a href="https://github.com/acm309/PutongOJ">PutongOJ</a> 说明。这里主要说一下这次开发中的坑。</p></summary>
<category term="技术与工作" scheme="https://blog.lazzzis.com/categories/%E6%8A%80%E6%9C%AF%E4%B8%8E%E5%B7%A5%E4%BD%9C/"/>
<category term="JavaScript" scheme="https://blog.lazzzis.com/tags/JavaScript/"/>
<category term="Projects" scheme="https://blog.lazzzis.com/tags/Projects/"/>
</entry>
<entry>
<title>解析 JavaScript Error 中的 stack 信息</title>
<link href="https://blog.lazzzis.com/post/parse-error-stack-in-js/"/>
<id>https://blog.lazzzis.com/post/parse-error-stack-in-js/</id>
<published>2018-05-27T06:51:08.000Z</published>
<updated>2024-06-02T05:08:09.899Z</updated>
<content type="html"><![CDATA[<h1 id="需求描述"><a href="#需求描述" class="headerlink" title="需求描述"></a>需求描述</h1><p>对于任意的 Error 对象,如果将其输出,我们可以看见这个异常的堆栈信息。例如:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">Error</span><br><span class="line"> at Object.<anonymous> (/Users/lazzzis/Documents/Projects/Test/test.js:10:12)</span><br><span class="line"> at Module._compile (internal/modules/cjs/loader.js:702:30)</span><br><span class="line"> at Object.Module._extensions..js (internal/modules/cjs/loader.js:713:10)</span><br><span class="line"> at Module.load (internal/modules/cjs/loader.js:612:32)</span><br><span class="line"> at tryModuleLoad (internal/modules/cjs/loader.js:551:12)</span><br><span class="line"> at Function.Module._load (internal/modules/cjs/loader.js:543:3)</span><br><span class="line"> at Function.Module.runMain (internal/modules/cjs/loader.js:744:10)</span><br><span class="line"> at startup (internal/bootstrap/node.js:238:19)</span><br><span class="line"> at bootstrapNodeJSCore (internal/bootstrap/node.js:572:3)</span><br></pre></td></tr></table></figure><p>可以看到这个异常来自: <code>test.js</code> 的第 10 行。但现在的需求是要用 <strong>代码</strong> 捕捉报错的来源文件以及行数。</p><span id="more"></span><h1 id="解决方法"><a href="#解决方法" class="headerlink" title="解决方法"></a>解决方法</h1><h2 id="方法一-RegExp"><a href="#方法一-RegExp" class="headerlink" title="方法一: RegExp"></a>方法一: RegExp</h2><p>因为堆栈信息是字符串形式,所以正则表达式在这个场合就非常合适。</p><p>以 <code>at Object.<anonymous> (/Users/lazzzis/Documents/Projects/Test/test.js:10:12)</code> 为例,我们首先需要捕捉的是后面括号内的信息。那么 <code>/at\s+(.*)\s+\((.*)\)/i</code>,中第一个的第一个匹配项为行数的方法,第二个匹配项为括号的信息。</p><p>对上述例子执行改正则,可以得到:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> info = <span class="string">`at Object.<anonymous> (/Users/lazzzis/Documents/Projects/Test/test.js:10:12)`</span></span><br><span class="line"><span class="keyword">const</span> res = <span class="regexp">/at\s+(.*)\s+\((.*)\)/i</span>.exec(info)</span><br><span class="line"><span class="built_in">console</span>.log(res)</span><br><span class="line">[ <span class="string">'at Object.<anonymous> (/Users/lazzzis/Documents/Projects/Test/test.js:10:12)'</span>,</span><br><span class="line"> <span class="string">'Object.<anonymous>'</span>,</span><br><span class="line"> <span class="string">'/Users/lazzzis/Documents/Projects/Test/test.js:10:12'</span>,</span><br><span class="line"> <span class="attr">index</span>: <span class="number">0</span>,</span><br><span class="line"> <span class="attr">input</span>: <span class="string">'at Object.<anonymous> (/Users/lazzzis/Documents/Projects/Test/test.js:10:12)'</span>,</span><br><span class="line"> <span class="attr">groups</span>: <span class="literal">undefined</span> ]</span><br><span class="line"><span class="comment">// res[1] 为函数信息,res[2] 为括号的内的信息</span></span><br></pre></td></tr></table></figure><p>而括号的内信息以 <code>:</code> 为分隔符,那么通过 <code>:</code> 又可以的到报错的文件地址,行数,列数。可以用正则表达式: <code>/at\s+(.*)\s+\((.*):(\d*):(\d*)\)/i</code></p><p>执行可以得到:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> info = <span class="string">`at Object.<anonymous> (/Users/lazzzis/Documents/Projects/Test/test.js:10:12)`</span></span><br><span class="line"><span class="keyword">const</span> res = <span class="regexp">/at\s+(.*)\s+\((.*):(\d*):(\d*)\)/i</span>.exec(info)</span><br><span class="line"><span class="built_in">console</span>.log(res)</span><br><span class="line">[ <span class="string">'at Object.<anonymous> (/Users/lazzzis/Documents/Projects/Test/test.js:10:12)'</span>,</span><br><span class="line"> <span class="string">'Object.<anonymous>'</span>,</span><br><span class="line"> <span class="string">'/Users/lazzzis/Documents/Projects/Test/test.js'</span>,</span><br><span class="line"> <span class="string">'10'</span>,</span><br><span class="line"> <span class="string">'12'</span>,</span><br><span class="line"> <span class="attr">index</span>: <span class="number">0</span>,</span><br><span class="line"> <span class="attr">input</span>: <span class="string">'at Object.<anonymous> (/Users/lazzzis/Documents/Projects/Test/test.js:10:12)'</span>,</span><br><span class="line"> <span class="attr">groups</span>: <span class="literal">undefined</span> ]</span><br><span class="line"><span class="comment">// res[1] 和 res [2] 已再之前讲过,不重复</span></span><br><span class="line"><span class="comment">// res[3] 为 行数,res[4] 为列数。</span></span><br></pre></td></tr></table></figure><p>通过上述方法,已经可以拿到该有的基本信息。</p><h2 id="方法二-Error-prepareStackTrace-方法"><a href="#方法二-Error-prepareStackTrace-方法" class="headerlink" title="方法二: Error.prepareStackTrace 方法"></a>方法二: Error.prepareStackTrace 方法</h2><p>node 是基于 v8 实现的,而 v8 给 Error 暴露了一个 prepareStackTrace 方法,因此可以借由这个方法实现我们所需的功能。</p><p>在 v8 中,堆栈信息并不是一开始就是字符串。在变成字符串前,其中一个状态是以一个数组形式存储的,而数组的每个元素是一个 CallSite 对象。简单理解,CallSite 包含了函数名,行数,错误类型等信息,可以简单把每一个 CallSite 对象看作堆栈信息中的每一行。</p><p>在每次将 Error 对象输出到 console 时,Error 会用 prepareStackTrace 方法将其变成字符串。如果我们覆盖此方法,就可以改变其默认行为,让它输出成其它东西。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">Error</span>.prepareStackTrace = <span class="function">(<span class="params">error, structuredStackTrace</span>) =></span> {</span><br><span class="line"> <span class="keyword">return</span> structuredStackTrace</span><br><span class="line"> .map(<span class="function">(<span class="params">item</span>) =></span> item.getFileName() + <span class="string">', '</span> + item.getFunctionName())</span><br><span class="line"> .join(<span class="string">'\n'</span>)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(<span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">'test'</span>))</span><br><span class="line"><span class="comment">// output:</span></span><br><span class="line"><span class="comment">// [/Users/lazzzis/Documents/Projects/Test/test.js, null</span></span><br><span class="line"><span class="comment">// internal/modules/cjs/loader.js, Module._compile</span></span><br><span class="line"><span class="comment">// internal/modules/cjs/loader.js, Module._extensions..js</span></span><br><span class="line"><span class="comment">// internal/modules/cjs/loader.js, Module.load</span></span><br><span class="line"><span class="comment">// internal/modules/cjs/loader.js, tryModuleLoad</span></span><br><span class="line"><span class="comment">// internal/modules/cjs/loader.js, Module._load</span></span><br><span class="line"><span class="comment">// internal/modules/cjs/loader.js, Module.runMain</span></span><br><span class="line"><span class="comment">// internal/bootstrap/node.js, startup</span></span><br><span class="line"><span class="comment">// internal/bootstrap/node.js, bootstrapNodeJSCore]</span></span><br></pre></td></tr></table></figure><p>可以看到我们通过了另一种方法拿到了堆栈信息中每一个文件和每一个函数名。</p><p>除了 <code>getFileName</code> 和 <code>getFunctionName</code> 方法外,还有 <code>isToplevel</code> 等更多方法。参考 <a href="https://github.com/v8/v8/wiki/Stack-Trace-API">Stack Trace API</a> 可以看到更多。</p><h1 id="应用"><a href="#应用" class="headerlink" title="应用"></a>应用</h1><p>那么解析这个堆栈信息可以干嘛呢?目前我所了解到的,主要有两种使用场景: logger 和 test</p><h2 id="logger"><a href="#logger" class="headerlink" title="logger"></a>logger</h2><p>有些 logger,比如 <a href="https://github.com/baryon/tracer/blob/master/lib/console.js">baryon/tracer</a> 在输出 logger 信息的同时还能告诉你发出这条信息的文件地址和函数。</p><p>比如:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> logger = <span class="built_in">require</span>(<span class="string">'tracer'</span>).console()</span><br><span class="line"></span><br><span class="line">logger.log(<span class="string">'hello'</span>)</span><br><span class="line"><span class="comment">// output: 2018-05-26T22:59:36-0400 <log> test.js:3 (Object.<anonymous>) hello</span></span><br></pre></td></tr></table></figure><p>而这个 log 方法的实现其实就基于 Error 信息的堆栈信息捕捉。可以从项目源码看出,tracer 在 log 方法调用的时声明一个异常(注意,并不是抛出了一个异常)。通过这个异常,使用正则表达式的方式对其捕捉,可以得到报错的函数及方法。</p><p>如果我们自己实现一个 log 方法,可以这么写:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// test.js</span></span><br><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">'path'</span>)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">log</span> (<span class="params">message</span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> info = <span class="keyword">new</span> <span class="built_in">Error</span>().stack.split(<span class="string">'\n'</span>)[<span class="number">2</span>]</span><br><span class="line"> <span class="keyword">const</span> res = <span class="regexp">/at\s+(.*)\s+\((.*):(\d*):(\d*)\)/i</span>.exec(info)</span><br><span class="line"> <span class="keyword">const</span> [</span><br><span class="line"> functionName,</span><br><span class="line"> filepath,</span><br><span class="line"> linenum,</span><br><span class="line"> colnum</span><br><span class="line"> ] = res.slice(<span class="number">1</span>)</span><br><span class="line"> <span class="keyword">const</span> filename = path.basename(filepath)</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">console</span>.log(<span class="string">`<span class="subst">${<span class="keyword">new</span> <span class="built_in">Date</span>().toLocaleString()}</span> <log> <span class="subst">${filename}</span>:<span class="subst">${linenum}</span>:<span class="subst">${colnum}</span> (<span class="subst">${functionName}</span>) <span class="subst">${message}</span>`</span>)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">pleaseLogThis</span> (<span class="params"></span>) </span>{</span><br><span class="line"> log(<span class="string">'this is a message'</span>)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">pleaseLogThis()</span><br><span class="line"><span class="comment">// output: 5/26/2018, 11:14:39 PM <log> test.js:17:3 (pleaseLogThis) this is a message</span></span><br></pre></td></tr></table></figure><p>其中 <code>log</code> 方法就是 tracer 的 log 的简化版了。其中代码中的 <code>new Error().stack.split('\n')[2]</code> 之所以取第三个元素,是因为第一个元素是错误的类型,例如是 <code>Error</code> 还是 <code>TypeError</code> 之类的,第二个元素是 <code>log</code> 方法本身的信息,也就是 Error 被声明的那一行的信息,这是我们不关心的内容。而第三个元素才是 <code>log</code> 方法被调用那一行的信息。</p><p>tracer 使用的正则表达式,而 <a href="https://github.com/klauscfhq/signale/blob/master/signale.js">klauscfhq/signale</a> 使用的则是 <code>Error.prepareStackTrace</code> 方法。同样如果我们自己实现一个 demo 的话,可以这么写:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">log</span> (<span class="params">message</span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> orig = <span class="built_in">Error</span>.prepareStackTrace</span><br><span class="line"> <span class="built_in">Error</span>.prepareStackTrace = <span class="function">(<span class="params">_, stack</span>) =></span> stack</span><br><span class="line"> <span class="keyword">const</span> { stack } = <span class="keyword">new</span> <span class="built_in">Error</span>()</span><br><span class="line"> <span class="built_in">Error</span>.prepareStackTrace = orig</span><br><span class="line"> <span class="keyword">const</span> info = stack[<span class="number">1</span>]</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">console</span>.log(</span><br><span class="line"> <span class="string">`<span class="subst">${<span class="keyword">new</span> <span class="built_in">Date</span>().toLocaleString()}</span> <log> <span class="subst">${path.basename(info.getFileName())}</span>:<span class="subst">${info.getLineNumber()}</span>:<span class="subst">${info.getColumnNumber()}</span> (<span class="subst">${info.getFunctionName()}</span>) <span class="subst">${message}</span>`</span></span><br><span class="line"> )</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>其它不变,即可得到同样的效果。其中 <code>const orig = Error.prepareStackTrace</code> 是将原先的方法保存下来,使用后复原,避免对其它可能抛出异常的代码产生负面影响。</p><h2 id="test"><a href="#test" class="headerlink" title="test"></a>test</h2><p>以 <a href="https://github.com/avajs/ava">ava</a> 为例,它能在测试报告中表明具体测试代码中不通过的那一个测试所在的行,并高亮。</p><p>通过源代码 <a href="https://github.com/avajs/ava/blob/master/lib/beautify-stack.js">lib/beautify-stack.js</a> 可以看到,ava 知道具体哪一行和哪一个文件也是通过对 Error 对象的堆栈信息进行解析,而且使用的是正则表达式匹配的方法。实现基本和 tracer 相似,因此就不多讲了。</p><h1 id="对比"><a href="#对比" class="headerlink" title="对比"></a>对比</h1><p>Error.prepareStackTrace 相比于 正则表达式方法有一个致命缺点,就是它仅对 v8 有效。如果说只在 node 环境使用,那没什么问题。但如果也需要在浏览器环境使用的话,那么这个方法也仅在 chrome 上有效,在 Firefox 上会抛出异常。</p><p>因此如果不需要考虑浏览器环境,那么请随意选择一个喜欢的。反之,只能考虑借助正则表达式。</p><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><ol><li><a href="https://github.com/v8/v8/wiki/Stack-Trace-API">Stack Trace API</a></li><li><a href="https://github.com/avajs/ava">avajs/ava</a></li><li><a href="https://github.com/klauscfhq/signale">klauscfhq/signale</a></li><li><a href="https://github.com/baryon/tracer">baryon/tracer</a></li></ol>]]></content>
<summary type="html"><h1 id="需求描述"><a href="#需求描述" class="headerlink" title="需求描述"></a>需求描述</h1><p>对于任意的 Error 对象,如果将其输出,我们可以看见这个异常的堆栈信息。例如:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">Error</span><br><span class="line"> at Object.&lt;anonymous&gt; (/Users/lazzzis/Documents/Projects/Test/test.js:10:12)</span><br><span class="line"> at Module._compile (internal/modules/cjs/loader.js:702:30)</span><br><span class="line"> at Object.Module._extensions..js (internal/modules/cjs/loader.js:713:10)</span><br><span class="line"> at Module.load (internal/modules/cjs/loader.js:612:32)</span><br><span class="line"> at tryModuleLoad (internal/modules/cjs/loader.js:551:12)</span><br><span class="line"> at Function.Module._load (internal/modules/cjs/loader.js:543:3)</span><br><span class="line"> at Function.Module.runMain (internal/modules/cjs/loader.js:744:10)</span><br><span class="line"> at startup (internal/bootstrap/node.js:238:19)</span><br><span class="line"> at bootstrapNodeJSCore (internal/bootstrap/node.js:572:3)</span><br></pre></td></tr></table></figure>
<p>可以看到这个异常来自: <code>test.js</code> 的第 10 行。但现在的需求是要用 <strong>代码</strong> 捕捉报错的来源文件以及行数。</p></summary>
<category term="技术与工作" scheme="https://blog.lazzzis.com/categories/%E6%8A%80%E6%9C%AF%E4%B8%8E%E5%B7%A5%E4%BD%9C/"/>
<category term="JavaScript" scheme="https://blog.lazzzis.com/tags/JavaScript/"/>
</entry>
<entry>
<title>为什么 Vue 组件需要一个 name</title>
<link href="https://blog.lazzzis.com/post/name-attribute-in-vue-component/"/>
<id>https://blog.lazzzis.com/post/name-attribute-in-vue-component/</id>
<published>2018-04-11T04:37:58.000Z</published>
<updated>2024-06-02T05:08:09.897Z</updated>
<content type="html"><![CDATA[<p>无论是通过 <code>Vue.component</code> 的方式,还是在写 <code>.vue</code> 文件的方式,官方都会推荐你写一个 <code>name</code> 属性。但是好像这个 name 在渲染时又几乎用不到,那么它实际能干嘛呢?</p><span id="more"></span><h1 id="方便调试"><a href="#方便调试" class="headerlink" title="方便调试"></a>方便调试</h1><p>Vue 有一款官方强力推荐的浏览器上的调试插件: <a href="https://github.com/vuejs/vue-devtools">vue-devtools</a>。通过打开调试工具,我们可以很轻松的看到已经渲染到页面上的各个组件,以及对应的组件的内部状态。</p><p>例如以下组件:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">script</span>></span><span class="javascript"></span></span><br><span class="line"><span class="javascript"> <span class="comment">// Demo.vue</span></span></span><br><span class="line"><span class="javascript"> <span class="keyword">export</span> <span class="keyword">default</span> {</span></span><br><span class="line"><span class="javascript"> <span class="attr">name</span>: <span class="string">'Kawaii'</span>,</span></span><br><span class="line"><span class="javascript"> <span class="attr">props</span>: [<span class="string">'val'</span>],</span></span><br><span class="line"><span class="javascript"> render (h) {</span></span><br><span class="line"><span class="javascript"> <span class="keyword">return</span> (</span></span><br><span class="line"><span class="javascript"> <span class="xml"><span class="tag"><<span class="name">div</span>></span></span></span></span><br><span class="line"><span class="xml"><span class="javascript"> { this.val }</span></span></span><br><span class="line"><span class="xml"><span class="javascript"> <span class="tag"></<span class="name">div</span>></span></span></span></span><br><span class="line"><span class="javascript"> )</span></span><br><span class="line"><span class="javascript"> }</span></span><br><span class="line"><span class="javascript"> }</span></span><br><span class="line"><span class="javascript"></span><span class="tag"></<span class="name">script</span>></span></span><br></pre></td></tr></table></figure><p>如果在 App.vue 里引用的话:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">template</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">Demo</span> <span class="attr">val</span>=<span class="string">"foo"</span> /></span></span><br><span class="line"><span class="tag"></<span class="name">template</span>></span></span><br><span class="line"></span><br><span class="line"><span class="tag"><<span class="name">script</span>></span><span class="javascript"></span></span><br><span class="line"><span class="javascript"><span class="keyword">import</span> Demo <span class="keyword">from</span> <span class="string">'./components/Demo'</span></span></span><br><span class="line"><span class="javascript"></span></span><br><span class="line"><span class="javascript"><span class="keyword">export</span> <span class="keyword">default</span> {</span></span><br><span class="line"><span class="javascript"> <span class="attr">name</span>: <span class="string">'app'</span>,</span></span><br><span class="line"><span class="javascript"> <span class="attr">components</span>: {</span></span><br><span class="line"><span class="javascript"> Demo</span></span><br><span class="line"><span class="javascript"> }</span></span><br><span class="line"><span class="javascript">}</span></span><br><span class="line"><span class="javascript"></span><span class="tag"></<span class="name">script</span>></span></span><br></pre></td></tr></table></figure><p>那么可以在 chrome 的调试界面可以看到:</p><p><img src="https://i.loli.net/2018/04/11/5acd8954c11de.png"></p><p>其中 <code>Kawaii</code> 就是刚才起了名字的组件,如果将其改名为 <code>看不见看不见</code></p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">script</span>></span><span class="javascript"></span></span><br><span class="line"><span class="javascript"> <span class="comment">// Demo.vue</span></span></span><br><span class="line"><span class="javascript"> <span class="keyword">export</span> <span class="keyword">default</span> {</span></span><br><span class="line"><span class="javascript"> <span class="attr">name</span>: <span class="string">'看不见看不见'</span>,</span></span><br><span class="line"><span class="javascript"> <span class="comment">// ...</span></span></span><br><span class="line"><span class="javascript"> }</span></span><br><span class="line"><span class="javascript"></span><span class="tag"></<span class="name">script</span>></span></span><br></pre></td></tr></table></figure><p>那么在 chrome 界面则可以直接看到其显示名字就变为 <code>看不见看不见</code> 了。</p><p><img src="https://i.loli.net/2018/04/11/5acd895501f79.png"></p><p>但如果不设置名字,那么 Vue.js 默认会用 tag 名称,也就是这个组件在 <code>template</code> 或者 <code>jsx</code> 里的名字。比如:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">script</span>></span><span class="javascript"></span></span><br><span class="line"><span class="javascript"> <span class="comment">// Demo.vue</span></span></span><br><span class="line"><span class="javascript"> <span class="keyword">export</span> <span class="keyword">default</span> {</span></span><br><span class="line"><span class="javascript"> <span class="comment">// 不设置名字</span></span></span><br><span class="line"><span class="javascript"> <span class="comment">// name: '看不见看不见',</span></span></span><br><span class="line"><span class="javascript"> <span class="comment">// ...</span></span></span><br><span class="line"><span class="javascript"> }</span></span><br><span class="line"><span class="javascript"></span><span class="tag"></<span class="name">script</span>></span></span><br></pre></td></tr></table></figure><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">template</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">D</span> <span class="attr">val</span>=<span class="string">"foo"</span> /></span></span><br><span class="line"><span class="tag"></<span class="name">template</span>></span></span><br><span class="line"></span><br><span class="line"><span class="tag"><<span class="name">script</span>></span><span class="javascript"></span></span><br><span class="line"><span class="javascript"><span class="keyword">import</span> Demo <span class="keyword">from</span> <span class="string">'./components/Demo'</span></span></span><br><span class="line"><span class="javascript"></span></span><br><span class="line"><span class="javascript"><span class="keyword">export</span> <span class="keyword">default</span> {</span></span><br><span class="line"><span class="javascript"> <span class="attr">name</span>: <span class="string">'app'</span>,</span></span><br><span class="line"><span class="javascript"> <span class="attr">components</span>: {</span></span><br><span class="line"><span class="javascript"> <span class="string">'D'</span>: Demo</span></span><br><span class="line"><span class="javascript"> }</span></span><br><span class="line"><span class="javascript">}</span></span><br><span class="line"><span class="javascript"></span><span class="tag"></<span class="name">script</span>></span></span><br></pre></td></tr></table></figure><p>那么此时就会显示为 <code>D</code>:</p><p><img src="https://i.loli.net/2018/04/11/5acd895531d51.png"></p><blockquote><p>Note: functional 组件不会显示在 devtools 中,因为 vue 并不会为 functional component 创建实例</p></blockquote><h1 id="递归应用"><a href="#递归应用" class="headerlink" title="递归应用"></a>递归应用</h1><p>在有些时候,我们可以会递归使用自身组件,比如:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">template</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span>></span></span><br><span class="line"> {{ val }}</span><br><span class="line"> <span class="tag"><<span class="name">Recursive</span> <span class="attr">v-if</span>=<span class="string">"val"</span> <span class="attr">:val</span>=<span class="string">"val - 1"</span> /></span></span><br><span class="line"> <span class="tag"></<span class="name">div</span>></span></span><br><span class="line"><span class="tag"></<span class="name">template</span>></span></span><br><span class="line"></span><br><span class="line"><span class="tag"><<span class="name">script</span>></span><span class="javascript"></span></span><br><span class="line"><span class="javascript"> <span class="comment">// Recursive.vue</span></span></span><br><span class="line"><span class="javascript"> <span class="keyword">export</span> <span class="keyword">default</span> {</span></span><br><span class="line"><span class="javascript"> <span class="attr">name</span>: <span class="string">'Recursive'</span>,</span></span><br><span class="line"><span class="javascript"> <span class="attr">props</span>: {</span></span><br><span class="line"><span class="javascript"> <span class="attr">val</span>: {</span></span><br><span class="line"><span class="javascript"> <span class="attr">required</span>: <span class="literal">true</span>,</span></span><br><span class="line"><span class="javascript"> <span class="attr">type</span>: <span class="built_in">Number</span>,</span></span><br><span class="line"><span class="javascript"> <span class="attr">default</span>: <span class="number">5</span></span></span><br><span class="line"><span class="javascript"> }</span></span><br><span class="line"><span class="javascript"> }</span></span><br><span class="line"><span class="javascript"> }</span></span><br><span class="line"><span class="javascript"></span><span class="tag"></<span class="name">script</span>></span></span><br></pre></td></tr></table></figure><p>在这种情况下,如果不设置 name,那么 console 就会报错,提示在 Recursive.vue 中找不到名为 <code>Recursive</code> 的组件。因此,如果想要递归应用自身组件的话,就必须设置 name 属性。</p><h1 id="keep-alive"><a href="#keep-alive" class="headerlink" title="keep-alive"></a>keep-alive</h1><p>keep-alive 是 Vue 内置的组件,可以将 keep-alive 的子组件运行缓存,用于保存切换 (例如 v-if 的切换) 过程前的状态。</p><p>而 keep-alive 有两个 props 是 <code>include</code> 以及 <code>exclude</code>。前者指明需要缓存的组件的名字。而后者则指明不需要缓存的组件的名字。</p><p>下述例子中,Foo, Bar 两个组件的名字分别为 <code>vue-foo</code>, <code>vue-bar</code>, 且组件均包含一个 input。因为通过 input 可以很轻松的观察到切换前后的状态是否有保存:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">template</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span>></span></span><br><span class="line"> {{ val }} <span class="tag"><<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> <span class="attr">v-model</span>=<span class="string">"m"</span> /></span></span><br><span class="line"> <span class="tag"></<span class="name">div</span>></span></span><br><span class="line"><span class="tag"></<span class="name">template</span>></span></span><br><span class="line"></span><br><span class="line"><span class="tag"><<span class="name">script</span>></span><span class="javascript"></span></span><br><span class="line"><span class="javascript"><span class="comment">// Foo.vue</span></span></span><br><span class="line"><span class="javascript"> <span class="keyword">export</span> <span class="keyword">default</span> {</span></span><br><span class="line"><span class="javascript"> <span class="attr">name</span>: <span class="string">'vue-foo'</span>,</span></span><br><span class="line"><span class="javascript"> data () {</span></span><br><span class="line"><span class="javascript"> <span class="keyword">return</span> {</span></span><br><span class="line"><span class="javascript"> <span class="attr">val</span>: <span class="string">'vue-foo'</span>,</span></span><br><span class="line"><span class="javascript"> <span class="attr">m</span>: <span class="string">'vue-foo'</span></span></span><br><span class="line"><span class="javascript"> }</span></span><br><span class="line"><span class="javascript"> }</span></span><br><span class="line"><span class="javascript"> }</span></span><br><span class="line"><span class="javascript"></span><span class="tag"></<span class="name">script</span>></span></span><br></pre></td></tr></table></figure><p>Bar.vue 跟 Foo.vue 内容几乎一样,除了名字,因此这里就不贴 Bar.vue 的代码了。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">template</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">keep-alive</span> <span class="attr">include</span>=<span class="string">"vue-foo"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">Foo</span> <span class="attr">v-if</span>=<span class="string">"visible"</span> /></span></span><br><span class="line"> <span class="tag"><<span class="name">Bar</span> <span class="attr">v-else</span> /></span></span><br><span class="line"> <span class="tag"></<span class="name">keep-alive</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">Button</span> @<span class="attr">click</span>=<span class="string">"visible = !visible"</span>></span></span><br><span class="line"> Visible {{ visible }}</span><br><span class="line"> <span class="tag"></<span class="name">Button</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">div</span>></span></span><br><span class="line"></span><br><span class="line"><span class="tag"></<span class="name">template</span>></span></span><br><span class="line"></span><br><span class="line"><span class="tag"><<span class="name">script</span>></span><span class="javascript"></span></span><br><span class="line"><span class="javascript"><span class="keyword">import</span> Foo <span class="keyword">from</span> <span class="string">'./components/Foo'</span></span></span><br><span class="line"><span class="javascript"><span class="keyword">import</span> Bar <span class="keyword">from</span> <span class="string">'./components/Bar'</span></span></span><br><span class="line"><span class="javascript"></span></span><br><span class="line"><span class="javascript"><span class="keyword">export</span> <span class="keyword">default</span> {</span></span><br><span class="line"><span class="javascript"> <span class="attr">name</span>: <span class="string">'app'</span>,</span></span><br><span class="line"><span class="javascript"> data () {</span></span><br><span class="line"><span class="javascript"> <span class="keyword">return</span> {</span></span><br><span class="line"><span class="javascript"> <span class="attr">visible</span>: <span class="literal">true</span></span></span><br><span class="line"><span class="javascript"> }</span></span><br><span class="line"><span class="javascript"> },</span></span><br><span class="line"><span class="javascript"> <span class="attr">components</span>: {</span></span><br><span class="line"><span class="javascript"> Foo,</span></span><br><span class="line"><span class="javascript"> Bar</span></span><br><span class="line"><span class="javascript"> }</span></span><br><span class="line"><span class="javascript">}</span></span><br><span class="line"><span class="javascript"></span><span class="tag"></<span class="name">script</span>></span></span><br></pre></td></tr></table></figure><p>通过点击 button 来切换。因为设置了 <code>include</code> 指令,那么只有 <code>Foo</code> 的状态才会被保存:</p><p><img src="https://i.loli.net/2018/04/11/5acd8955d055b.gif"></p><p>通过这张效果图可以看到,在切换过程中,<code>Foo</code> 的状态被保存了,而 <code>Bar</code> 则没有,而是重新生成。</p><p>如果使用 <code>exclude</code> 指令:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">template</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">keep-alive</span> <span class="attr">exclude</span>=<span class="string">"vue-foo"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">Foo</span> <span class="attr">v-if</span>=<span class="string">"visible"</span> /></span></span><br><span class="line"> <span class="tag"><<span class="name">Bar</span> <span class="attr">v-else</span> /></span></span><br><span class="line"> <span class="tag"></<span class="name">keep-alive</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">Button</span> @<span class="attr">click</span>=<span class="string">"visible = !visible"</span>></span></span><br><span class="line"> Visible {{ visible }}</span><br><span class="line"> <span class="tag"></<span class="name">Button</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">div</span>></span></span><br><span class="line"></span><br><span class="line"><span class="tag"></<span class="name">template</span>></span></span><br></pre></td></tr></table></figure><p>那么就会得到一个完全相反的结果: 即 <code>Bar</code> 的状态被保存了,而 <code>Foo</code> 则没有,而是重新生成。</p><h1 id="References"><a href="#References" class="headerlink" title="References"></a>References</h1><ol><li><a href="https://vuejs.org/v2/api/#keep-alive">api/#keep-alive</a></li><li><a href="https://vuejs.org/v2/api/#name">api/#name</a></li><li><a href="https://github.com/vuejs/vue-devtools/issues/280">vue-devtools/issues/280</a></li></ol>]]></content>
<summary type="html"><p>无论是通过 <code>Vue.component</code> 的方式,还是在写 <code>.vue</code> 文件的方式,官方都会推荐你写一个 <code>name</code> 属性。但是好像这个 name 在渲染时又几乎用不到,那么它实际能干嘛呢?</p></summary>
<category term="技术与工作" scheme="https://blog.lazzzis.com/categories/%E6%8A%80%E6%9C%AF%E4%B8%8E%E5%B7%A5%E4%BD%9C/"/>
<category term="JavaScript" scheme="https://blog.lazzzis.com/tags/JavaScript/"/>
</entry>
<entry>
<title>用 vue 写一个单页的 hexo 主题</title>
<link href="https://blog.lazzzis.com/post/hexo-theme-of-spa-in-vue/"/>
<id>https://blog.lazzzis.com/post/hexo-theme-of-spa-in-vue/</id>
<published>2018-04-06T04:51:32.000Z</published>
<updated>2024-06-02T05:08:09.889Z</updated>
<content type="html"><![CDATA[<p><strong>2018 年 5 月 5 日更新:</strong> 因为我突然发现如果采用单页的话,就很难处理 SEO 的问题,所以我现在已经基本不再考虑在 hexo 的基础上考虑这个主题。所以我现在也已经在使用别的主题。在未来,我会考虑采用 <a href="https://vuepress.vuejs.org/">vuepress</a> 或者 <a href="https://github.com/egojump/peco">peco</a> 搭建我的博客。</p><hr><p>大概一年以前,我发布过一个主题,名为 <a href="https://github.com/lazzzis/hexo-theme-mls">hexo-theme-mls</a>。这个主题是我当时在学完如何写一个 hexo 主题后完成的。后来在学了 vue 之后,构思着再写一个主题。我非常想把它写成一个单页应用,可是一直没有思绪。直到后来看到了 <a href="https://github.com/EYHN/hexo-theme-one">hexo-theme-one</a>,我才有了思绪,于是开始写一个单页的主题。</p><span id="more"></span><h1 id="restful"><a href="#restful" class="headerlink" title="restful"></a>restful</h1><p>首先一个问题就是,如何生成 json 文件,用于前端的异步数据请求。<a href="https://github.com/yscoder/hexo-generator-restful">hexo-generator-restful</a> 提供了很好的思路,hexo 在执行的时候,会载入主题文件夹下的 scripts 下的文件并执行。而 hexo 提供了一个接口,可以用于在读取所有博客内容之后,生成所有文件之前,添加需要生成的文件。</p><p><a href="https://hexo.io/api/generator.html">generator</a> 接口即是需要的接口。注册一个函数,这个函数可以在执行完后返回一个数组,数组每一个元素即是一个将要生成的文件的信息,这个信息包括:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">path</span>: post.path, <span class="comment">// 路径</span></span><br><span class="line"> <span class="attr">data</span>: post, <span class="comment">// 这个文件的内容</span></span><br><span class="line"> <span class="attr">layout</span>: <span class="string">'post'</span> <span class="comment">// 布局</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>一般文件生成后会在 public 文件夹下,那么这个路径只要是相对 public 即可,比如 <code>api/posts.json</code>,则会在 <code>public/api/posts.json</code>。至于文件内容,因为这个 data 一般要求是字符串或流 (stream),所以我选择用 JSON.stringify() 将需要的数据 (对象) 转化为字符串。</p><h2 id="那么最终需要生成哪些-json-文件呢"><a href="#那么最终需要生成哪些-json-文件呢" class="headerlink" title="那么最终需要生成哪些 json 文件呢?"></a>那么最终需要生成哪些 json 文件呢?</h2><h3 id="所有的-posts-数据"><a href="#所有的-posts-数据" class="headerlink" title="所有的 posts 数据"></a>所有的 posts 数据</h3><p>一个 <code>posts.json</code> 记录了这个博客所有的博客大概信息 (每篇博客的标题,包含的标签,发布日期等),但不包含博客文章的具体内容,因为如果将所有文章内容放进一个文件的话,那么这个文件可能非常大。因而,准备再生成一个 <code>post/</code> 文件夹,下面存放了各个博客文章的具体信息。如果一篇博文标题为 <code>Foo</code>。那么请求 <code>api/post/Foo.json</code> 可以拿到这篇博文的具体信息。</p><h3 id="所有的-tags-数据"><a href="#所有的-tags-数据" class="headerlink" title="所有的 tags 数据"></a>所有的 tags 数据</h3><p>类似于 posts 数据,一个 <code>tags</code> 用于说明这个博文下所有的 tag,一个 <code>tag/</code> 文件夹包含每一个 tag 的具体信息(这个 tag 下有哪一些文章)。</p><h3 id="其它"><a href="#其它" class="headerlink" title="其它"></a>其它</h3><p>一些配置信息,比如 siteConfig,和 themeConfig。另外如果有自定义 page 的话,再放一些信息于 <code>page/</code> 文件夹下。</p><h1 id="404-处理"><a href="#404-处理" class="headerlink" title="404 处理"></a>404 处理</h1><p>这个是我当时最头疼的一个问题,毕竟 hexo 当初又不是为单页设计的,估计也考虑不到这个问题。</p><p>我有一个路由是 <code>/posts</code>。但在 <code>hexo g</code> 运行完后,在 <code>public</code> 目录下面是没有 <code>posts/index.html</code> 这个文件的。因此如果运行 <code>hexo s</code> 的时候,如果直接访问 <code>localhost:4000</code>。那么 hexo 会直接报错,提示 <code>Can not get /posts</code>。如果要解决这个问题,那么我必须在所有可能的路由下生成 <code>index.html</code>。如果我有 100 个路由,那么我需要生成在 100 个文件夹下生成共计 100 个 <code>index.html</code>。</p><p>可是这很明显不符合我对 <code>SPA</code> 的预期。按照最初的想法,我只需要一个 <code>index.html</code>。无论浏览器访问哪个路由,后端都能返回同一个 <code>index.html</code>。这一点可以参考 <code>vue-router</code> 官网上对 404 重定向的一个说明 – <a href="https://router.vuejs.org/zh-cn/essentials/history-mode.html">HTML5 History 模式</a>。</p><p>当然我上面这么说的自然原因是我采用了 <code>HTML5 History</code> 模式。我当然可以选择放弃这种模式,采用 URL hash 的方式。也就是说,我的博客地址会变成 <code>/#/post/foo</code> 的样子。但这里又出现了另外一个问题,disqus 对评论的获取是不考虑 <code>#</code> 之后的内容。换句话说,如果用户访问 <code>/#/post/foo</code> 和 <code>/#/post/bar</code> 时,disqus 都会去拿 <code>/</code> 路由对应的评论,所有的页面评论就全部一样了!</p><p>因此我不得不再继续思考如何采用上 <code>HTML5 History</code> 模式。如果只考虑部署的话,GitHub Pages 有 404 重定向的方式 (建立 404.html) 以及 nginx 也有类似功能。所有在部署之后是不会有这问题,我需要做的,是对 <code>hexo s</code> 的扩充。</p><p><code>hexo</code> 确实开放了对 <code>hexo s</code> 的扩充的接口,结合这个 ISSUE: <a href="https://github.com/hexojs/hexo/issues/1030">https://github.com/hexojs/hexo/issues/1030</a>。我可以在 <code>hexo s</code> 中实现在 404 时的重定向了。但有两种方案:</p><h2 id="方案一"><a href="#方案一" class="headerlink" title="方案一:"></a>方案一:</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">hexo.extend.filter.register(<span class="string">'server_middleware'</span>, <span class="function"><span class="keyword">function</span> <span class="title">_404middleware</span> (<span class="params">app</span>) </span>{</span><br><span class="line"> app.use(<span class="function"><span class="keyword">function</span> <span class="title">handle404</span>(<span class="params">req, res, next</span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> s = fs.createReadStream(</span><br><span class="line"> path.resolve(__dirname, <span class="string">'../../../'</span>, hexo.config.public_dir, <span class="string">'./index.html'</span>)</span><br><span class="line"> )</span><br><span class="line"> s.pipe(res)</span><br><span class="line"> }, <span class="number">99</span>)</span><br><span class="line">})</span><br></pre></td></tr></table></figure><p>这种方法,就是直接读取生成好的 index.html 返回。这种方案在大部分情况下可行。</p><h2 id="方案二"><a href="#方案二" class="headerlink" title="方案二:"></a>方案二:</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">hexo.extend.filter.register(<span class="string">'server_middleware'</span>, <span class="function"><span class="keyword">function</span> <span class="title">_404middleware</span> (<span class="params">app</span>) </span>{</span><br><span class="line"> app.use(<span class="function"><span class="keyword">function</span> <span class="title">handle404</span>(<span class="params">req, res, next</span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> { pathname } = url.parse(req.url)</span><br><span class="line"> <span class="keyword">if</span> (!pathname.endsWith(<span class="string">'.json'</span>)) {</span><br><span class="line"> res.writeHead(<span class="number">302</span>, {</span><br><span class="line"> <span class="string">'Location'</span>: url.resolve(hexo.config.root, <span class="string">'404.html?redirect='</span> + req.url)</span><br><span class="line"> })</span><br><span class="line"> res.end()</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> next()</span><br><span class="line"> }</span><br><span class="line"> }, <span class="number">99</span>)</span><br><span class="line">})</span><br></pre></td></tr></table></figure><p>其中 99 代表 priority。默认 server 的值为 10。priority 越小越先执行。让默认服务先运行,如果出现 404,那么上面的代码才会执行,进行重定向。注意我增加了一个 <code>redirect</code> 的请求参数,专门用于在前端继续跳转一次。如果不跳转,前端 url 就变成了 <code>/404.html</code>。但我想在当前 URL 下也能显示 404 页面,比如在 <code>/post/xx</code> 页面下显示 404 的内容,而不是跳转到 <code>/404.html</code> 显示。其中注意不要对 <code>json</code> 文件进行处理,仅对一般请求处理即可。</p><p>方案二,和方案一相比,两者都不算美观,并不能说是我最满意的方案。但相比之下,方案二,还好一点,原因是方案一一个明显的问题就是,它的成功运行是基于 public 目录下存在 <code>index.html</code> 的前提下。如果这个前提不满足,那么就无法继续。因此我暂时采用了方案二。</p><h1 id="页面设计"><a href="#页面设计" class="headerlink" title="页面设计"></a>页面设计</h1><p>上面讲的,其实大多是 hexo 相关内容。至于页面设计就简单多了,因为后端路由已经解决了。前端实际上只是样式的问题。因为当时想做的简单一点,于是才用了 <a href="https://milligram.io/">milligram</a> 这么一个纯 css 的极简框架。</p><p>加上 vue 全家桶,以及 axios 用作异步请求工具,前端开发似乎并没有遇到什么大困难。</p><p>唯一可能算的上问题的或许是字体问题吧。原本字体用的是 google fonts 的链接,而总所周知,这在国内体验很不好,因此花了点时间,把字体从网上下载,并写成 css 引用的方式,打包成为主题的一部分。</p><h1 id="其它-1"><a href="#其它-1" class="headerlink" title="其它"></a>其它</h1><p>我考虑过要不要加上多语言支持,也就是 <code>i18n</code>。不过感觉没什么必要,并没有那么多需要翻译的。所以这个坑就先留着吧。</p><p>在我写这篇文章的时候,<a href="https://hexo.io/themes">hexo.io/themes</a> 也有了一些其它单页应用的主题,或许未来应该有更多的吧。可能 hexo 未来会对单页应用的博客做一些相关的支持,也可能会出现一款为单页应用博客而定制的博客生成器吧。</p><p>另外,记得刚把这个发布并用在自己博客上的时候,有伙伴吐槽 “有点丑呀”。或许吧,和其它主题比起来,确实“朴素”了太多。不过不知道为什么,现在的我确实喜欢这样的“朴素”了呢。</p><p>顺便贴一下项目地址,<a href="https://github.com/lazzzis/hexo-theme-only">hexo-theme-only</a>。欢迎使用和提供批评意见。</p><hr><p><img src="https://i.loli.net/2018/05/27/5b0a2ad2e3d1f.png" alt="散华礼弥"><span class="image-caption">散华礼弥</span></p>]]></content>
<summary type="html"><p><strong>2018 年 5 月 5 日更新:</strong> 因为我突然发现如果采用单页的话,就很难处理 SEO 的问题,所以我现在已经基本不再考虑在 hexo 的基础上考虑这个主题。所以我现在也已经在使用别的主题。在未来,我会考虑采用 <a href="https://vuepress.vuejs.org/">vuepress</a> 或者 <a href="https://github.com/egojump/peco">peco</a> 搭建我的博客。</p>
<hr>
<p>大概一年以前,我发布过一个主题,名为 <a href="https://github.com/lazzzis/hexo-theme-mls">hexo-theme-mls</a>。这个主题是我当时在学完如何写一个 hexo 主题后完成的。后来在学了 vue 之后,构思着再写一个主题。我非常想把它写成一个单页应用,可是一直没有思绪。直到后来看到了 <a href="https://github.com/EYHN/hexo-theme-one">hexo-theme-one</a>,我才有了思绪,于是开始写一个单页的主题。</p></summary>
<category term="技术与工作" scheme="https://blog.lazzzis.com/categories/%E6%8A%80%E6%9C%AF%E4%B8%8E%E5%B7%A5%E4%BD%9C/"/>
<category term="JavaScript" scheme="https://blog.lazzzis.com/tags/JavaScript/"/>
</entry>
<entry>
<title>联系 Koa.js 和 requests 看 HTTP 协议中的重定向</title>
<link href="https://blog.lazzzis.com/post/http-protocol-redirecting/"/>
<id>https://blog.lazzzis.com/post/http-protocol-redirecting/</id>
<published>2018-01-05T00:29:09.000Z</published>
<updated>2024-06-02T05:08:09.891Z</updated>
<content type="html"><![CDATA[<p>在 HTTP 协议中,一般 3 开头的状态码,都用于表示 <code>重定向</code>:因为某些原因,例如目标网页已经存在其它网站,服务器会通知客户端访问另一个网页。</p><span id="more"></span><h1 id="Location"><a href="#Location" class="headerlink" title="Location"></a>Location</h1><p>为了告诉客户端应改前往哪一个页面,服务器在返回的响应 (response) 的 headers 中用 <code>Location</code> 字段标明具体应该访问的页面。</p><p>例如,访问 <code>http://example.com</code> 时,如果服务器想让浏览器跳转到 <code>http://google.com</code>,可以在 response 中写:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">HTTP/1.0 302 Redirect</span><br><span class="line">Location: http://google.com</span><br></pre></td></tr></table></figure><p>一般浏览器收到后,会自动跳转。</p><p>另外,URL 也可以标明为相对路径,比如,在上个例子中,如果跳转到 <code>http://example.com/hello.html</code>,则可以标记为:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">HTTP/1.0 302 Redirect</span><br><span class="line">Location: hello.html</span><br></pre></td></tr></table></figure><h1 id="Koa-js"><a href="#Koa-js" class="headerlink" title="Koa.js"></a>Koa.js</h1><p>在 Koa.js 中,context 有一个方法为 <code>redirect</code>,专门用于定向,而这个方法实际委托给了 <code>lib/response.js</code>。</p><p>其具体代码为:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="title">redirect</span>(<span class="params">url, alt</span>)</span> {</span><br><span class="line"> <span class="comment">// location</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="string">'back'</span> == url) url = <span class="built_in">this</span>.ctx.get(<span class="string">'Referrer'</span>) || alt || <span class="string">'/'</span>;</span><br><span class="line"> <span class="built_in">this</span>.set(<span class="string">'Location'</span>, url);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// status</span></span><br><span class="line"> <span class="keyword">if</span> (!statuses.redirect[<span class="built_in">this</span>.status]) <span class="built_in">this</span>.status = <span class="number">302</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// html</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">this</span>.ctx.accepts(<span class="string">'html'</span>)) {</span><br><span class="line"> url = <span class="built_in">escape</span>(url);</span><br><span class="line"> <span class="built_in">this</span>.type = <span class="string">'text/html; charset=utf-8'</span>;</span><br><span class="line"> <span class="built_in">this</span>.body = <span class="string">`Redirecting to <a href="<span class="subst">${url}</span>"><span class="subst">${url}</span></a>.`</span>;</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// text</span></span><br><span class="line"> <span class="built_in">this</span>.type = <span class="string">'text/plain; charset=utf-8'</span>;</span><br><span class="line"> <span class="built_in">this</span>.body = <span class="string">`Redirecting to <span class="subst">${url}</span>.`</span>;</span><br><span class="line">},</span><br></pre></td></tr></table></figure><p>如果 URL 为 <code>back</code>,那么会跳转回请求来源的方向,比如你在 <code>http://github.com/lazzzis</code> 点击了 <code>lazzzis.github.io</code>,那么在请求 <code>lazzzis.github.io</code> 的 request 的头部中,字段为 <code>Referrer: http://github.com/lazzzis</code>。换句话说,<code>back</code> 的意思就是 “从哪里来,就回哪里去”。</p><p>而 <code>this.set('Location', url)</code> 作用则就是之前说的,将头部 headers 中 <code>Location</code> 设置为客户端应该去访问的那个 URL。之后,便是将状态码设置为 302。</p><p>这边,Koa.js 怕浏览器不会自动跳转,因此将也设置了消息主体部分,通知用户应该跳转。</p><h1 id="requests"><a href="#requests" class="headerlink" title="requests"></a>requests</h1><p>接下来用 Python 的 requests 做实验。我们先用 Koa.js 写一个简单的服务端:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> Koa = <span class="built_in">require</span>(<span class="string">'koa'</span>)</span><br><span class="line"><span class="keyword">const</span> koaLogger = <span class="built_in">require</span>(<span class="string">'koa-logger'</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> app = <span class="keyword">new</span> Koa()</span><br><span class="line"></span><br><span class="line">app.use(koaLogger())</span><br><span class="line"></span><br><span class="line">app.use(<span class="keyword">async</span> (ctx, next) => {</span><br><span class="line"> ctx.redirect(<span class="string">'http://lazzzis.github.io'</span>)</span><br><span class="line">})</span><br><span class="line"></span><br><span class="line">app.listen(<span class="number">5000</span>)</span><br></pre></td></tr></table></figure><p>然后发起请求:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> requests</span><br><span class="line"></span><br><span class="line">r = requests.post(<span class="string">"http://localhost:5000"</span>)</span><br><span class="line"><span class="built_in">print</span>(r.url)</span><br><span class="line"><span class="comment"># http://lazzzis.github.io</span></span><br></pre></td></tr></table></figure><p>可以发现,requests 已经帮我们做了自动跳转。如果不想让它跳转的话,可以设置 <code>allow_redirects</code> 参数(默认为 True):</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">r = requests.post(<span class="string">"http://localhost:5000"</span>, allow_redirects=<span class="literal">False</span>)</span><br><span class="line"><span class="built_in">print</span>(r.url)</span><br><span class="line"><span class="comment"># http://localhost:5000/</span></span><br><span class="line"><span class="built_in">print</span>(r.text)</span><br><span class="line"><span class="comment"># Redirecting to <a href="http://lazzzis.github.io">http://lazzzis.github.io</a>.</span></span><br></pre></td></tr></table></figure><p>取消跳转后,可以看到它这次停止了跳转。关于限制跳转的相关源码在 <a href="https://github.com/requests/requests/blob/8982efa9e46172b42c8cf6cdcc1a3f4c75e670ce/requests/sessions.py">requests.py</a> (代码太长,所以就不粘贴了)。</p><p>在 653 行: <code>yield_requests=True</code> 使得在 resolve_redirects 中时,不会进入下一步的 send:在 206 - 225 的分支可以看到, 如果 <code>yield_requests=True</code>,那么 requests 会做接下来的请求。</p><h2 id="获取下一个请求的-URL"><a href="#获取下一个请求的-URL" class="headerlink" title="获取下一个请求的 URL"></a>获取下一个请求的 URL</h2><p>在 <a href="https://github.com/requests/requests/blob/8982efa9e46172b42c8cf6cdcc1a3f4c75e670ce/requests/sessions.py">requests.py</a> 的 98 行的 get_redirect_target 的实现中,<code>location = resp.headers['location']</code> 表明了这里的处理和 <code>Koa.js</code> 是一样的,也是从 <code>location</code> 字段获取。</p><h2 id="更改请求方式"><a href="#更改请求方式" class="headerlink" title="更改请求方式"></a>更改请求方式</h2><p>另外,还有一个有意思的事情,我在请求的时候,发的是 <code>POST</code> 请求,可是 GitHub Pages 不支持 POST 的呀,那么 requests 一定换了另一种方法:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">r = requests.post(<span class="string">"http://localhost:5000"</span>)</span><br><span class="line"><span class="built_in">print</span>(r.request.method)</span><br><span class="line"><span class="comment"># GET</span></span><br></pre></td></tr></table></figure><p>看的出来,requests 使其变为了 GET。这里的实现在于: <a href="https://github.com/requests/requests/blob/8982efa9e46172b42c8cf6cdcc1a3f4c75e670ce/requests/sessions.py">requests.py</a> 的 164 行 <code>self.rebuild_method(prepared_request, resp)</code> 和 292 行开始的 <code>rebuild_method</code> 的实现。尤其是 304 行和 309 行,将请求方法改为了 <code>GET</code>。</p><h2 id="递归请求"><a href="#递归请求" class="headerlink" title="递归请求"></a>递归请求</h2><p>这里想象两种极端情况。</p><p>一是如果服务端 A 实现出错,使得要求客户端依旧跳到 A。那么,requests 请求 A, 而之后有继续请求 A。这样,陷入了一个死循环。</p><p>第二种,类似,但不只一个服务器出错: A 要求跳转到 B,而 B 要求跳转到 C,可是 C 又要求跳转到 A,那么,这里也同样陷入了一个死循环。</p><p>requests 考虑到了这点,做了限制,避免一直跳转:</p><p>先对上面的服务端做一点修改:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">app.use(<span class="keyword">async</span> (ctx, next) => {</span><br><span class="line"> ctx.redirect(<span class="string">'http://localhost:5000'</span>)</span><br><span class="line">})</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">r = requests.post(<span class="string">"http://localhost:5000"</span>)</span><br><span class="line"><span class="comment"># requests.exceptions.TooManyRedirects: Exceeded 30 redirects.</span></span><br></pre></td></tr></table></figure><p>python 自定义了一个异常,用于说明引起的原因是过多的重定向,并且说明了 requests 最先跳转次数为 30 次。</p><p>可以看到在 <a href="https://github.com/requests/requests/blob/8982efa9e46172b42c8cf6cdcc1a3f4c75e670ce/requests/sessions.py">requests.py</a> 的第 139 行处,requests 本身记录了请求的历史,如果历史条数,也就是请求的次数,大于限制时会抛出异常。</p><h1 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h1><ol><li><a href="http://shop.oreilly.com/product/9781565925090.do">HTTP: The Definitive Guide</a></li><li><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Redirections">Redirections in HTTP</a></li></ol>]]></content>
<summary type="html"><p>在 HTTP 协议中,一般 3 开头的状态码,都用于表示 <code>重定向</code>:因为某些原因,例如目标网页已经存在其它网站,服务器会通知客户端访问另一个网页。</p></summary>
<category term="技术与工作" scheme="https://blog.lazzzis.com/categories/%E6%8A%80%E6%9C%AF%E4%B8%8E%E5%B7%A5%E4%BD%9C/"/>
<category term="HTTP" scheme="https://blog.lazzzis.com/tags/HTTP/"/>
</entry>
</feed>