From 19ebd9616df134dc75772f98efc5b0f05f5f6a45 Mon Sep 17 00:00:00 2001
From: zhouzihanntu
Date: Fri, 24 Mar 2017 21:32:28 +0800
Subject: [PATCH 001/638] update
---
...odules-in-node-js-everything-you-need-to-know.md | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/TODO/requiring-modules-in-node-js-everything-you-need-to-know.md b/TODO/requiring-modules-in-node-js-everything-you-need-to-know.md
index fce6fbc0359..5618ebc6fd9 100644
--- a/TODO/requiring-modules-in-node-js-everything-you-need-to-know.md
+++ b/TODO/requiring-modules-in-node-js-everything-you-need-to-know.md
@@ -1,23 +1,30 @@
> * 原文地址:[Requiring modules in Node.js: Everything you need to know](https://medium.freecodecamp.com/requiring-modules-in-node-js-everything-you-need-to-know-e7fbd119be8#.wcrwm9c81)
> * 原文作者:[Samer Buna](https://medium.freecodecamp.com/@samerbuna?source=post_header_lockup)
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
-> * 译者:
+> * 译者:[zhouzihanntu](https://github.com/zhouzihanntu)
> * 校对者:
# Requiring modules in Node.js: Everything you need to know #
+# 在 Node.js 中加载模块 #
## How modularity works in Node.js ##
+## 模块化在 Node.js 中的应用##
Node uses two core modules for managing module dependencies:
+Node 提供了两个核心模块来管理模块依赖:
- The `require` module, which appears to be available on the global scope — no need to `require('require')`.
+- `require` 模块在全局范围内可用,不需要 `require('require')`.
- The `module` module, which also appears to be available on the global scope — no need to `require('module')`.
+- `module` 模块同样在全局范围内可用,不需要 `require('module')`.
You can think of the `require` module as the command and the `module` module as the organizer of all required modules.
+你可以把 `require` 模块当做命令 `module` 模块 所有需加载模块的
Requiring a module in Node isn’t that complicated of a concept.
+在 Node 中加载一个模块其实没有概念那么复杂。
```
const config = require('/path/to/file');
@@ -108,7 +115,7 @@ Error: Cannot find module 'find-me'
If you now create a local `node_modules` directory and put a `find-me.js` in there, the `require('find-me')` line will find it.
```
-~/learn-node $ mkdir node_modules
+~/learn-node $ mkdir node_modules
~/learn-node $ echo "console.log('I am not lost');" > node_modules/find-me.js
@@ -302,7 +309,7 @@ In util Module {
I’ve removed some attributes in the above output to keep it brief, but note how the `exports` object now has the attributes we defined in each module. You can put as many attributes as you want on that exports object, and you can actually change the whole object to be something else. For example, to change the exports object to be a function instead of an object, we do the following:
```
-// Add the following line in index.js before the console.log
+// Add the following line in index.js before the console.log
module.exports = function() {};
```
From 312d6c3e62c36f666027f9008fe1081f8a5e4cea Mon Sep 17 00:00:00 2001
From: xiaoyusilen
Date: Mon, 27 Mar 2017 17:37:50 +0800
Subject: [PATCH 002/638] complete translation
---
TODO/go-function-calls-redux.md | 56 ++++++++++++++++-----------------
1 file changed, 28 insertions(+), 28 deletions(-)
diff --git a/TODO/go-function-calls-redux.md b/TODO/go-function-calls-redux.md
index 3ee8548a7b9..2e8b6efa515 100644
--- a/TODO/go-function-calls-redux.md
+++ b/TODO/go-function-calls-redux.md
@@ -1,18 +1,18 @@
> * 原文地址:[Go Function Calls Redux](https://hackernoon.com/go-function-calls-redux-609fdd1c90fd#.jsh5r78wp)
> * 原文作者:[Phil Pearl](https://hackernoon.com/@philpearl?source=post_header_lockup)
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
-> * 译者:
+> * 译者:[xiaoyusilen](http://xiaoyu.world)
> * 校对者:
-# Go Function Calls Redux #
+# Go 函数调用 Redux #
-Some time ago in a [previous post](https://syslog.ravelin.com/anatomy-of-a-function-call-in-go-f6fc81b80ecc#.gpqsgzmjc) I promised to take a further look at how function calls and call stacks in Go work. I’ve think found a neat way to make good on that promise, so here goes.
+前段时间在一篇[文章](https://syslog.ravelin.com/anatomy-of-a-function-call-in-go-f6fc81b80ecc#.gpqsgzmjc)中我答应写一篇进一步分析 Go 中如何进行函数调用和调用堆栈在 Go 中如何工作的文章。现在我找到了一种简洁的方式来向大家展示上述内容,所以有了现在这篇文章。
-So what is a call stack? Well, it’s an area of memory used to hold local variables and call parameters, and to track where functions should return to. Each goroutine has it’s own stack. You could almost say a goroutine is its stack.
+什么是调用堆栈?它是一个用于保存局部变量和调用参数的内存区域,并且跟踪每个函数应该返回到哪里去。每个 goroutine 都有它自己的堆栈。你甚至可以说每个 goroutine 就是它自己的堆栈。
-Here’s the code I’m going to use to show the stack in action. It’s just a sequence of simple function calls. main() calls [f1(0xdeadbeef)](https://en.wikipedia.org/wiki/Hexspeak) , which then calls `f2(0xabad1dea)`, which calls `f3(0xbaddcafe)`. `f3()` then adds one to it’s parameter, and stores it in a local variable called `local`. It then takes the address of `local` and prints out memory starting at that address. Because `local` is on the stack, this prints the stack.
+下面是我用于演示堆栈的代码。就是一系列简单的函数调用,main() 函数调用 [f1(0xdeadbeef)](https://en.wikipedia.org/wiki/Hexspeak),然后调用 `f2(0xabad1dea)`,再调用 `f3(0xbaddcafe)`。然后 f3() 将其中一个作为它的参数,并且将它存储在名为 `local` 的本地变量中。然后获取 `local` 的内存地址并且从那里开始输出。因为 `loacl` 在栈内,所以输出的就是栈。
-```
+```go
package main
import (
@@ -59,9 +59,9 @@ func showFunc(at uintptr) {
}
```
-Here’s the output of the program. It is a dump of memory starting at the address of `local`, shown as a list of 8-byte integers in hex. The address of each integer is on the left, and the int at the address is on the right.
+下面是上述代码的输出结果。它是从 `local` 的地址开始的内存转储,是以十六进制形式展示的8字节列表。左边是每个整数的存储地址,右边是地址内存储的整数。
-We know `local` should equal 0xBADDCAFE + 1, or 0xBADDCAFF, and this is indeed what we see at the start of the dump.
+我们知道 `local` 应该等于 0xBADDCAFE + 1,或者 0xBADDCAFF,这确实是我们转储开始时看到的。
```
C42003FF28: BADDCAFF
@@ -94,13 +94,13 @@ C42003FFC0: C4200001A0
102752A is runtime.main /usr/local/Cellar/go/1.8/libexec/src/runtime/proc.go 194
```
-- The next number is 0xC42003FF48, which is the address of the 5th line of the dump.
-- After that we have 0x1088BEB. It turns out this is an address of executable code, and if we feed it into `runtime.FuncForPC` we see it is the address of line 19 of main.go, which is the last line of `f2()`. This is the address we return to when `f3()` returns.
-- Next we have 0xBADDCAFE, the parameter to our call to `f3()`
+- 下一个数字是 0xC42003FF48,它是转储的第五行的地址。
+- 然后我们可以得到 0x1088BEB。事实上这是一个可执行代码的地址,如果我们将它作为 `runtime.FuncForPC` 的参数,我们知道它是 main.go 的第19行代码的地址,也是 f2() 的最后一行代码。这是 f3() 返回时我们得到的地址。
+- 接下来我们得到 0xBADDCAFE,这是我们调用 `f3()` 时的参数。
-If we carry on we continue to see this pattern. Below I’ve marked up the memory dump showing how the stack pointers track back through the dump and where the function parameters and return addresses sit.
+如果继续我们将看到类似上面的输出结果。下面我已经标记了内存转储,显示堆栈指针如何跟踪转储,参数和返回地址在哪里。
-```
+```go
C42003FF28: BADDCAFF Local variable in f3()
+-C42003FF30: C42003FF48
| C42003FF38: 1088BEB return to f2() main.go line 19
@@ -113,18 +113,18 @@ If we carry on we continue to see this pattern. Below I’ve marked up the memor
| C42003FF70: DEADBEEF f1() parameter
+-C42003FF78: C42003FFD0
C42003FF80: 102752A return to runtime.main()
-
```
-From this we can see many things.
+通过这些我们可以看出:
-- First, the stack starts at a high address, and the stack address reduces as function calls are made.
-- When a function call is made, the caller pushes the parameters onto the stack, then the return address (the address of the next instruction in the calling function), then a pointer to a higher point in the stack.
-- This pointer is used to find the previous function call on the stack when unwinding the stack when the call returns.
-- Local variables are stored after the stack pointer.
+- 首先,堆栈从高地址开始,堆栈地址随着函数调用变小。
+- 当进行函数调用时,调用者将参数放入栈内,然后返回地址(调用函数中的下一条指令的地址),接着指向堆栈中较高的指针。
+- 当调用返回时,这个指针用于在堆栈中查找先前调用的函数。
+- 局部变量存储在堆栈指针之后。
-We can use the same technique to look at some slightly more complicated function calls. I’ve added more parameters, and some return values to `f2()` in this version.
-```
+我们可以使用相同的技巧来分析一些稍微复杂的函数调用。这次,我添加了更多的参数,`f2()` 函数也返回了更多的值。
+
+```go
package main
import (
@@ -153,9 +153,9 @@ func f3(val int) {
}
```
-This time I’ve jumped straight to the marked-up output.
+这次我们直接看被我标记好的输出结果。
-```
+```go
C42003FF10: BADDCAFF local variable in f3()
+-C42003FF18: C42003FF30
| C42003FF20: 1088BFB return to f2()
@@ -173,11 +173,11 @@ This time I’ve jumped straight to the marked-up output.
C42003FF80: 102752A return to runtime.main()
```
-From this we can see that
+从结果中我们可以看出:
-- the calling function makes space for the return values of the called function before the function parameters. (Note the values are uninitialised because the function hasn’t returned yet!)
-- parameters are pushed onto the stack in reverse order.
+- 调用函数在函数参数之前为被调用函数的返回值提供空间。(注意这些值是没有初始化的,因为这个函数还没有返回!)
+- 参数在栈内的顺序与入栈顺序相反。
-Hopefully all that made sense! If you got this far and enjoyed it or learned something, please hit that heart-button. I can’t earn internet points without you.
+希望我都讲清楚了。既然你已经看到这儿了,如果喜欢我的这篇文章或者可以从中学到一点什么的话,那么请给我点个赞。不然我就没办法获得积分。
-*By day, Phil fights crime at* [*ravelin.com*](https://ravelin.com) *. You can join him:* [*https://angel.co/ravelin/jobs*](https://angel.co/ravelin/jobs) .
+**Phil 白天在 [ravelin.com](https://ravelin.com) 的工作主要是防止网上欺诈,你可以加入他 https://angel.co/ravelin/jobs。**
\ No newline at end of file
From 4c3b930b904ff06b37997f0fa0ea873bf11b5fd1 Mon Sep 17 00:00:00 2001
From: zhouzihanntu
Date: Tue, 28 Mar 2017 19:05:01 +0800
Subject: [PATCH 003/638] update file
---
...-in-node-js-everything-you-need-to-know.md | 21 +++++++++++++++----
1 file changed, 17 insertions(+), 4 deletions(-)
diff --git a/TODO/requiring-modules-in-node-js-everything-you-need-to-know.md b/TODO/requiring-modules-in-node-js-everything-you-need-to-know.md
index 5618ebc6fd9..fef57b8f8e0 100644
--- a/TODO/requiring-modules-in-node-js-everything-you-need-to-know.md
+++ b/TODO/requiring-modules-in-node-js-everything-you-need-to-know.md
@@ -16,41 +16,52 @@ Node uses two core modules for managing module dependencies:
Node 提供了两个核心模块来管理模块依赖:
- The `require` module, which appears to be available on the global scope — no need to `require('require')`.
-- `require` 模块在全局范围内可用,不需要 `require('require')`.
+- `require` 模块在全局范围内可用,不需要 `require('require')`.
- The `module` module, which also appears to be available on the global scope — no need to `require('module')`.
- `module` 模块同样在全局范围内可用,不需要 `require('module')`.
You can think of the `require` module as the command and the `module` module as the organizer of all required modules.
-你可以把 `require` 模块当做命令 `module` 模块 所有需加载模块的
+你可以将 `require` 模块理解为命令,将 `module` 模块理解为组织所有需加载模块的工具。
Requiring a module in Node isn’t that complicated of a concept.
-在 Node 中加载一个模块其实没有概念那么复杂。
+在 Node 中加载一个模块其实不像概念那么复杂。
```
const config = require('/path/to/file');
```
The main object exported by the `require` module is a function (as used in the above example). When Node invokes that `require()` function with a local file path as the function’s only argument, Node goes through the following sequence of steps:
+`require` 模块导出的主对象是一个函数(如上例)。当 Node 将本地文件路径作为唯一参数调用 `require()` 时,Node 将执行以下步骤:
- **Resolving**: To find the absolute path of the file.
+- **解析**:找到该文件的绝对路径。
- **Loading**: To determine the type of the file content.
+- **加载**:确定文件内容的类型。
- **Wrapping**: To give the file its private scope. This is what makes both the `require` and `module` objects local to every file we require.
+- **打包**:为文件划分私有作用域,这样 `require` 和 `module` 两个对象对于我们要加载的每个模块来说就都是本地的。
- **Evaluating**: This is what the VM eventually does with the loaded code.
+- **评估**:最后由虚拟机对加载得到的代码做评估。
- **Caching**: So that when we require this file again, we don’t go over all the steps another time.
+- **缓存**:当再次加载该文件时,无需再重复以上所有步骤。
In this article, I’ll attempt to explain with examples these different stages and how the affect the way we write modules in Node.
+在本文中,我将试着用示例说明这些不同阶段,以及它们如何影响我们在 Node 中编写模块的方式。
Let me first create a directory to host all the examples using my terminal:
+我先使用终端创建一个目录来托管本文中的所有示例:
```
mkdir ~/learn-node && cd ~/learn-node
```
All the commands in the rest of this article will be run from within `~/learn-node`.
+本文余下部分的所有命令都将在 `~/learn-node` 目录下运行。
#### Resolving a local path ####
+#### 解析本地路径 ####
Let me introduce you to the `module` object. You can check it out in a simple REPL session:
+首先,让我来介绍一下 `module` 对象。你可以通过一个简单的 REPL 会话查看它:
```
~/learn-node $ node
@@ -62,10 +73,12 @@ Module {
filename: null,
loaded: false,
children: [],
- paths: [ ... ] }
+ paths: [ ... ]
+}
```
Every module object gets an `id` property to identify it. This `id` is usually the full path to the file, but in a REPL session it’s simply `.`
+每个模块对象都有一个用于识别该对象的 `id` 属性。这个 `id` 通常是该文件的完整路径,但在 REPL 会话中 `.`
Node modules have a one-to-one relation with files on the file-system. We require a module by loading the content of a file into memory.
From e5e391827b3716c10ba3d4e3ec1d339747604168 Mon Sep 17 00:00:00 2001
From: tanglie
Date: Wed, 29 Mar 2017 00:40:19 +0800
Subject: [PATCH 004/638] Update Dependency-Injection-with-Dagger-2.md
---
TODO/Dependency-Injection-with-Dagger-2.md | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/TODO/Dependency-Injection-with-Dagger-2.md b/TODO/Dependency-Injection-with-Dagger-2.md
index 803b9ce7a84..453d660e042 100644
--- a/TODO/Dependency-Injection-with-Dagger-2.md
+++ b/TODO/Dependency-Injection-with-Dagger-2.md
@@ -4,21 +4,21 @@
> * 译者:
> * 校对者:
-# Dependency Injection with Dagger 2
+# 用 Dagger 2 实现依赖注入
-## Overview
+## 概要
-Many Android apps rely on instantiating objects that often require other dependencies. For instance, a Twitter API client may be built using a networking library such as [[Retrofit|Consuming-APIs-with-Retrofit]]. To use this library, you might also need to add parsing libraries such as [[Gson|Leveraging-the-Gson-Library]]. In addition, classes that implement authentication or caching may require accessing [[shared preferences|Storing-and-Accessing-SharedPreferences]] or other common storage, requiring instantiating them first and creating an inherent dependency chain.
+很多 Android 应用依赖于一些含有其它依赖的对象。例如,一个 Twitter API 客户端可能需要通过 [Retrofit](https://github.com/codepath/android_guides/wiki/Consuming-APIs-with-Retrofit) 之类的网络库被构建。要使用这个库,你可能还需要添加 [Gson](https://github.com/codepath/android_guides/wiki/Leveraging-the-Gson-Library) 这样的解析库。另外,实现认证或缓存的库可能需要使用 [shared preferences](https://github.com/codepath/android_guides/wiki/Storing-and-Accessing-SharedPreferences)或其它通用存储方式。这就需要先把它们实例化,并创建一个隐含的依赖链。
-If you're not familiar with Dependency Injection, watch [this](https://www.youtube.com/watch?v=IKD2-MAkXyQ) quick video.
+如果你不熟悉依赖注入,看看[这个](https://www.youtube.com/watch?v=IKD2-MAkXyQ) 短视频。
-Dagger 2 analyzes these dependencies for you and generates code to help wire them together. While there are other Java dependency injection frameworks, many of them suffered limitations in relying on XML, required validating dependency issues at run-time, or incurred performance penalties during startup. [Dagger 2](http://google.github.io/dagger/) relies purely on using Java [annotation processors](https://www.youtube.com/watch?v=dOcs-NKK-RA) and compile-time checks to analyze and verify dependencies. It is considered to be one of the most efficient dependency injection frameworks built to date.
+Dagger 2 为你解析这些依赖,并生成把它们绑定在一起的代码。也有很多其它的 Java 依赖注入框架,但它们中很多个是有缺陷的,比如依赖 XML,需要在运行时验证依赖,或者在起始时造成性能负担。 [Dagger 2](http://google.github.io/dagger/) 纯粹依赖于 Java [annotation processors](https://www.youtube.com/watch?v=dOcs-NKK-RA) 以及编译时检查来分析并验证依赖。它被认为是目前最高效的依赖注入框架之一。
-### Advantages
+### 优点
-Here is a list of other advantages for using Dagger 2:
+这是使用 Dagger 2 的一系列其它优势:
- * **Simplifies access to shared instances**. Just as the [[ButterKnife|Reducing-View-Boilerplate-with-Butterknife]] library makes it easier to define references to Views, event handlers, and resources, Dagger 2 provides a simple way to obtain references to shared instances. For instance, once we declare in Dagger our singleton instances such as `MyTwitterApiClient` or `SharedPreferences`, we can declare fields with a simple `@Inject` annotation:
+ * **简化共享实例访问**。就像 [ButterKnife](https://github.com/codepath/android_guides/wiki/Reducing-View-Boilerplate-with-Butterknife) 库简化了引用View, event handler 和 resources 的方式一样,Dagger 2 提供了一个简单的方式获取对共享对象的引用。例如,一旦我们在 Dagger 中声明了 `MyTwitterApiClient` 或 `SharedPreferences` 的单例,就可以用一个简单的 `@Inject` 标注来声明域:
```java
public class MainActivity extends Activity {
@@ -31,11 +31,11 @@ public class MainActivity extends Activity {
}
```
- * **Easy configuration of complex dependencies**. There is an implicit order in which your objects are often created. Dagger 2 walks through the dependency graph and [[generates code|Dependency-Injection-with-Dagger-2#code-generation]] that is both easy to understand and trace, while also saving you from writing the large amount of boilerplate code you would normally need to write by hand to obtain references and pass them to other objects as dependencies. It also helps simplify refactoring, since you can focus on what modules to build rather than focusing on the order in which they need to be created.
+ * **容易配置复杂的依赖**。 对象创建是有隐含顺序的。Dagger 2 浏览依赖图,并且[生成易于理解和追踪的代码](https://github.com/codepath/android_guides/wiki/Dependency-Injection-with-Dagger-2#code-generation)。而且,它可以节约大量的样板代码,使你不再需要手写,手动获取引用并把它们传递给其他对象作为依赖。它也简化了重构,因为你可以聚焦于构建模块本身,而不是它们被创建的顺序。
- * **Easier unit and integration testing** Because the dependency graph is created for us, we can easily swap out modules that make network responses and mock out this behavior.
+ * **更简单的单元和集成测试** 因为依赖图是为我们创建的,我们可以轻易换出用于创建网络响应的模块,并模拟这种行为。
- * **Scoped instances** Not only can you easily manage instances that can last the entire application lifecycle, you can also leverage Dagger 2 to define instances with shorter lifetimes (i.e. bound to a user session, activity lifecycle, etc.).
+ * **实例范围** 你不仅可以轻易地管理持续整个应用生命周期的实例,也可以利用 Dagger 2 来定义生命周期更短(比如和一个用户 session 或 Activity 生命周期相绑定)的实例。
### Setup
From 22d75b762801bf962d8a5864d46e6ffb96f856de Mon Sep 17 00:00:00 2001
From: tanglie
Date: Wed, 29 Mar 2017 01:00:13 +0800
Subject: [PATCH 005/638] Update Dependency-Injection-with-Dagger-2.md
---
TODO/Dependency-Injection-with-Dagger-2.md | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/TODO/Dependency-Injection-with-Dagger-2.md b/TODO/Dependency-Injection-with-Dagger-2.md
index 453d660e042..199a78c5438 100644
--- a/TODO/Dependency-Injection-with-Dagger-2.md
+++ b/TODO/Dependency-Injection-with-Dagger-2.md
@@ -37,11 +37,11 @@ public class MainActivity extends Activity {
* **实例范围** 你不仅可以轻易地管理持续整个应用生命周期的实例,也可以利用 Dagger 2 来定义生命周期更短(比如和一个用户 session 或 Activity 生命周期相绑定)的实例。
-### Setup
+### 设置
-Android Studio by default will not allow you to navigate to generated Dagger 2 code as legitimate classes because they are not normally added to the source path but adding the `android-apt` plugin will add these files into the IDE classpath and enable you to have more visibility.
+默认的 Android Studio 不把生成的 Dagger 2 代码视作合法的类,因为它们通常并不被加入 source 路径。但引入 `android-apt` 插件后,它会把这些文件加入 IDE classpath,从而提供更好的可见性。
-Make sure to [[upgrade|Getting-Started-with-Gradle#upgrading-gradle]] to the latest Gradle version to use the `annotationProcessor` syntax:
+确保[升级](https://github.com/codepath/android_guides/wiki/Getting-Started-with-Gradle#upgrading-gradle) 到最迟的 Gradle 版本以使用最新的 `annotationProcessor` 语法:
```gradle
dependencies {
@@ -52,12 +52,12 @@ dependencies {
}
```
-Note that the `provided` keyword refers to dependencies that are only needed at compilation. The Dagger compiler generates code that is used to create the dependency graph of the classes defined in your source code. These classes are added to the IDE class path during compilation. The `annotationProcessor` keyword, which is understood by the Android Gradle plugin, does not add these classes to the class path, they are used only for annotation processing, which prevents accidentally referencing them.
+注意 `provided` 关键词是指只在编译时需要的依赖。Dagger 编译器生成了用于生成依赖图的类,而这个依赖图是在你的源代码中定义的。这些类在编译过程中被添加到你的IDE classpath。`annotationProcessor` 关键字可以被 Android Gradle 插件理解。它不把这些类添加到 classpath 中,而只是把它们用于处理注解。这可以避免不小心引用它们。
-### Creating Singletons
-![Dagger Injections Overview](https://raw.githubusercontent.com/codepath/android_guides/master/images/dagger_general.png)
+### 创建单例
+![Dagger 注入概要](https://raw.githubusercontent.com/codepath/android_guides/master/images/dagger_general.png)
-The simplest example is to show how to centralize all your singleton creation with Dagger 2. Suppose you weren't using any type of dependency injection framework and wrote code in your Twitter client similar to the following:
+最简单的例子是用 Dagger 2 集中管理所有的单例。假设你不用任何依赖注入框架,在你的 Twitter 客户端中写下类似这些的东西:
```java
OkHttpClient client = new OkHttpClient();
@@ -82,9 +82,9 @@ Retrofit retrofit = new Retrofit.Builder()
.build();
```
-#### Declare your singletons
+#### 声明你的单例
-You need to define what objects should be included as part of the dependency chain by creating a Dagger 2 **module**. For instance, if we wish to make a single `Retrofit` instance tied to the application lifecycle and available to all our activities and fragments, we first need to make Dagger aware that a `Retrofit` instance can be provided.
+你需要通过创建 Dagger 2 **模块**定义哪些对象应该作为依赖链的一部分。例如,假设我们想要创建一个 `Retrofit` 单例,使它绑定到应用生命周期,对所有的 Activity 和 Fragment 都可用,我们首先需要使 Dagger 意识到他可以提供 `Retrofit` 的实例。
Because we wish to setup caching, we need an Application context. Our first Dagger module, `AppModule.java`, will be used to provide this reference. We will define a method annotated with `@Provides` that denotes to Dagger that this method is the constructor for the `Application` return type:
From fa775fb725f0617c96a42d856d69c9e754846c71 Mon Sep 17 00:00:00 2001
From: zhouzihanntu
Date: Wed, 29 Mar 2017 19:14:06 +0800
Subject: [PATCH 006/638] update file
---
...-in-node-js-everything-you-need-to-know.md | 133 ++++++++----------
1 file changed, 60 insertions(+), 73 deletions(-)
diff --git a/TODO/requiring-modules-in-node-js-everything-you-need-to-know.md b/TODO/requiring-modules-in-node-js-everything-you-need-to-know.md
index fef57b8f8e0..0f35c99a5d3 100644
--- a/TODO/requiring-modules-in-node-js-everything-you-need-to-know.md
+++ b/TODO/requiring-modules-in-node-js-everything-you-need-to-know.md
@@ -5,63 +5,46 @@
> * 校对者:
# Requiring modules in Node.js: Everything you need to know #
-# 在 Node.js 中加载模块 #
+# 在 Node.js 中引用模块 #
-## How modularity works in Node.js ##
-## 模块化在 Node.js 中的应用##
+## Node.js 中模块化的工作原理 ##
-Node uses two core modules for managing module dependencies:
Node 提供了两个核心模块来管理模块依赖:
-- The `require` module, which appears to be available on the global scope — no need to `require('require')`.
-- `require` 模块在全局范围内可用,不需要 `require('require')`.
-- The `module` module, which also appears to be available on the global scope — no need to `require('module')`.
-- `module` 模块同样在全局范围内可用,不需要 `require('module')`.
+- `require` 模块在全局范围内可用,不需要写 `require('require')`.
+- `module` 模块同样在全局范围内可用,不需要写 `require('module')`.
-You can think of the `require` module as the command and the `module` module as the organizer of all required modules.
-你可以将 `require` 模块理解为命令,将 `module` 模块理解为组织所有需加载模块的工具。
+你可以将 `require` 模块理解为命令,将 `module` 模块理解为组织所有被引用模块的工具。
-Requiring a module in Node isn’t that complicated of a concept.
-在 Node 中加载一个模块其实不像概念那么复杂。
+在 Node 中引入一个模块其实不像概念那么复杂。
```
const config = require('/path/to/file');
```
-The main object exported by the `require` module is a function (as used in the above example). When Node invokes that `require()` function with a local file path as the function’s only argument, Node goes through the following sequence of steps:
`require` 模块导出的主对象是一个函数(如上例)。当 Node 将本地文件路径作为唯一参数调用 `require()` 时,Node 将执行以下步骤:
-- **Resolving**: To find the absolute path of the file.
- **解析**:找到该文件的绝对路径。
-- **Loading**: To determine the type of the file content.
- **加载**:确定文件内容的类型。
-- **Wrapping**: To give the file its private scope. This is what makes both the `require` and `module` objects local to every file we require.
-- **打包**:为文件划分私有作用域,这样 `require` 和 `module` 两个对象对于我们要加载的每个模块来说就都是本地的。
-- **Evaluating**: This is what the VM eventually does with the loaded code.
+- **打包**:为文件划分私有作用域,这样 `require` 和 `module` 两个对象对于我们要引入的每个模块来说就都是本地的。
- **评估**:最后由虚拟机对加载得到的代码做评估。
-- **Caching**: So that when we require this file again, we don’t go over all the steps another time.
-- **缓存**:当再次加载该文件时,无需再重复以上所有步骤。
+- **缓存**:当再次引用该文件时,无需再重复以上所有步骤。
-In this article, I’ll attempt to explain with examples these different stages and how the affect the way we write modules in Node.
-在本文中,我将试着用示例说明这些不同阶段,以及它们如何影响我们在 Node 中编写模块的方式。
+在本文中,我将试着用示例说明这些不同阶段的运行原理,以及它们如何影响我们在 Node 中编写模块的方式。
-Let me first create a directory to host all the examples using my terminal:
我先使用终端创建一个目录来托管本文中的所有示例:
```
mkdir ~/learn-node && cd ~/learn-node
```
-All the commands in the rest of this article will be run from within `~/learn-node`.
本文余下部分的所有命令都将在 `~/learn-node` 目录下运行。
-#### Resolving a local path ####
#### 解析本地路径 ####
-Let me introduce you to the `module` object. You can check it out in a simple REPL session:
-首先,让我来介绍一下 `module` 对象。你可以通过一个简单的 REPL 会话查看它:
+首先,让我来介绍一下 `module` 对象。你可以在一个简单的 REPL 会话中查看该对象:
```
~/learn-node $ node
@@ -77,20 +60,19 @@ Module {
}
```
-Every module object gets an `id` property to identify it. This `id` is usually the full path to the file, but in a REPL session it’s simply `.`
-每个模块对象都有一个用于识别该对象的 `id` 属性。这个 `id` 通常是该文件的完整路径,但在 REPL 会话中 `.`
+每个模块对象都有一个用于识别该对象的 `id` 属性。这个 `id` 通常是该文件的完整路径,但在 REPL 会话中只会显示为 ``。
-Node modules have a one-to-one relation with files on the file-system. We require a module by loading the content of a file into memory.
+Node 模块与文件系统中的文件有着一一对应的关系。我们通过加载模块对应的文件内容到内存中来实现模块引用。
-However, since Node allows many ways to require a file (for example, with a relative path or a pre-configured path), before we can load the content of a file into the memory we need to find the absolute location of that file.
+然而,由于 Node 允许使用许多方式引入文件(例如,使用相对路径或预先配置的路径),我们需要在将文件的内容加载到内存前找到该文件的绝对位置。
-When we require a `'find-me'` module, without specifying a path:
+例如,我们不声明路径,直接引入一个 `'find-me'` 模块时:
```
require('find-me');
```
-Node will look for `find-me.js` in all the paths specified by `module.paths` — in order.
+Node 会在 `module.paths` 声明的所有路径中依次查找 `find-me.js` 。
```
~/learn-node $ node
@@ -105,9 +87,9 @@ Node will look for `find-me.js` in all the paths specified by `module.paths`
'/usr/local/Cellar/node/7.7.1/lib/node' ]
```
-The paths list is basically a list of node_modules directories under every directory from the current directory to the root directory. It also includes a few legacy directories whose use is not recommended.
+Node 从当前目录开始一级级向上寻找 node_modules 目录,这个数组大致就是当前目录到所有 node_modules 目录的相对路径。其中还包括一些为了兼容性保留的目录,不推荐使用。
-If Node can’t find `find-me.js` in any of these paths, it will throw a “cannot find module error.”
+如果 Node 在以上路径中都无法找到 `find-me.js` ,将抛出一个 “找不到该模块” 错误。
```
~/learn-node $ node
@@ -125,7 +107,7 @@ Error: Cannot find module 'find-me'
at REPLServer.onLine (repl.js:533:10)
```
-If you now create a local `node_modules` directory and put a `find-me.js` in there, the `require('find-me')` line will find it.
+如果你现在创建一个本地的 `node_modules` 目录,并向目录中添加一个 `find-me.js` 文件,就能通过 `require('find-me')` 找到它了。
```
~/learn-node $ mkdir node_modules
@@ -139,14 +121,14 @@ I am not lost
>
```
-If another `find-me.js` file existed in any of the other paths, for example, if we have a `node_modules` directory under the home directory and we have a different `find-me.js` file in there:
+如果在其他路径下也有 `find-me.js` 文件呢?例如,我们在主目录下的 `node_modules` 目录中放置一个不同的 `find-me.js` 文件:
```
$ mkdir ~/node_modules
$ echo "console.log('I am the root of all problems');" > ~/node_modules/find-me.js
```
-When we `require('find-me')` from within the `learn-node` directory — which has its own `node_modules/find-me.js`, the `find-me.js` file under the home directory will not be loaded at all:
+当我们在 `learn-node` 目录下执行 `require('find-me')` 时,`learn-node` 目录会加载自己的 `node_modules/find-me.js`,主目录下的 `find-me.js` 文件并不会被加载:
```
~/learn-node $ node
@@ -156,7 +138,7 @@ I am not lost
>
```
-If we remove the local `node_modules` directory under `~/learn-node` and try to require `find-me` one more time, the file under the home’s `node_modules` directory would be used:
+此时,如果我们将 `~/learn-node` 下的 `node_modules` 移除,再一次引入 `find-me` 模块,那么主目录下的 `node_modules` 将会被加载:
```
~/learn-node $ rm -r node_modules/
@@ -168,9 +150,9 @@ I am the root of all problems
>
```
-#### Requiring a folder ####
+#### 引入文件夹 ####
-Modules don’t have to be files. We can also create a `find-me` folder under `node_modules` and place an `index.js` file in there. The same `require('find-me')` line will use that folder’s `index.js` file:
+模块不一定是单个文件。我们也可以在 `node_modules` 目录下创建一个 `find-me` 文件夹,然后向其中添加一个 `index.js` 文件。`require('find-me')` 会引用该文件夹下的 `index.js` 文件:
```
~/learn-node $ mkdir -p node_modules/find-me
@@ -184,9 +166,9 @@ Found again.
>
```
-Note how it ignored the home directory’s `node_modules` path again since we have a local one now.
+>注意,由于我们现在有一个本地目录,它再次忽略了主目录的 `node_modules` 路径。
-An `index.js` file will be used by default when we require a folder, but we can control what file name to start with under the folder using the `main` property in `package.json`. For example, to make the `require('find-me')` line resolve to a different file under the `find-me` folder, all we need to do is add a `package.json` file in there and specify which file should be used to resolve this folder:
+当我们引入一个文件夹时,将默认执行 `index.js` 文件,但是我们可以通过 `package.json` 中的 `main` 属性指定主入口文件。例如,要令 `require('find-me')` 解析到 `find-me` 文件夹下的另一个文件,我们只需要在该文件夹下添加一个 `package.json` 文件来声明解析该文件夹时引用的文件:
```
~/learn-node $ echo "console.log('I rule');" > node_modules/find-me/start.js
@@ -200,9 +182,9 @@ I rule
>
```
-#### require.resolve ####
+#### require.resolve 方法 ####
-If you want to only resolve the module and not execute it, you can use the `require.resolve` function. This behaves exactly the same as the main `require` function, but does not load the file. It will still throw an error if the file does not exist and it will return the full path to the file when found.
+如果你只想解析模块而不运行,此时可以使用 `require.resolve` 函数。这个方法与 `require` 的主要功能完全相同,但是不加载文件。如果文件不存在,它仍会抛出错误,并在找到文件时返回文件的完整路径。
```
> require.resolve('find-me');
@@ -222,34 +204,34 @@ Error: Cannot find module 'not-there'
>
```
-This can be used, for example, to check whether an optional package is installed or not and only use it when it’s available.
+这个方法可以用于检查一个可选安装包是否安装,并仅在该包可用时使用。
-#### Relative and absolute paths ####
+#### 相对路径和绝对路径 ####
-Besides resolving modules from within the `node_modules` directories, we can also place the module anywhere we want and require it with either relative paths (`./` and `../`) or with absolute paths starting with `/`.
+除了从 `node_modules` 目录中解析模块以外,我们还可以将模块放置在任意位置,使用相对路径( `./` 和 `../` )或以 `/` 开头的绝对路径引入。
-If, for example, the `find-me.js` file was under a `lib` folder instead of the `node_modules` folder, we can require it with:
+举个例子,如果 `find-me.js` 文件并不在 `node_modules` 中,而在 `lib` 文件夹中。我们可以使用以下代码引入它:
```
require('./lib/find-me');
```
-#### Parent-child relation between files ####
+#### 文件间的父子关系 ####
-Create a `lib/util.js` file and add a `console.log` line there to identify it. Also, `console.log` the `module` object itself:
+现在我们来创建一个 `lib/util.js` 文件,向文件添加一行 `console.log` 代码作为标识。打印出 `module` 对象本身:
```
~/learn-node $ mkdir lib
~/learn-node $ echo "console.log('In util', module);" > lib/util.js
```
-Do the same for an `index.js` file, which is what we’ll be executing with the node command. Make this `index.js` file require `lib/util.js`:
+同样的,向 `index.js` 文件中也添加一行打印 `module` 对象的代码,并在文件中引入 `lib/util.js`,我们将使用 node 命令运行该文件:
```
~/learn-node $ echo "console.log('In index', module); require('./lib/util');" > index.js
```
-Now execute the `index.js` file with node:
+用 node 运行 `index.js` 文件:
```
~/learn-node $ node index.js
@@ -279,25 +261,27 @@ In util Module {
paths: [...] }
```
-Note how the main `index` module `(id: '.')` is now listed as the parent for the `lib/util` module. However, the `lib/util` module was not listed as a child of the `index` module. Instead, we have the `[Circular]` value there because this is a circular reference. If Node prints the `lib/util` module object, it will go into an infinite loop. That’s why it simply replaces the `lib/util` reference with `[Circular]`.
+>注意:`index` 主模块 `(id: '.')` 现在被列为 `lib/util` 模块的父类。但 `lib/util` 模块并没有被列为 `index` 模块的子目录。相反,我们在这里得到的值是 `[Circular]`,因为这是一个循环引用。如果 Node 打印 `lib/util` 模块对象,将进入一个无限循环。这就是为什么 Node 使用 `[Circular]` 代替了 `lib/util` 引用。
-More importantly now, what happens if the `lib/util` module required the main `index` module? This is where we get into what’s known as the circular modular dependency, which is allowed in Node.
+
+重点来了,如果我们在 `lib/util` 模块中引入 `index` 主模块会发生什么?这就是 Node 中所支持的循环模块依赖关系。
To understand it better, let’s first understand a few other concepts on the module object.
+为了更好理解循环模块依赖,我们先来了解一些关于 module 对象的概念。
-#### exports, module.exports, and synchronous loading of modules ####
+#### exports、module.exports 和模块异步加载 ####
-In any module, exports is a special object. If you’ve noticed above, every time we’ve printed a module object, it had an exports property which has been an empty object so far. We can add any attribute to this special exports object. For example, let’s export an id attribute for `index.js` and `lib/util.js`:
+在所有模块中,exports 都是一个特殊对象。你可能注意到了,以上我们每打印一个 module 对象时,它都有一个空的 exports 属性。我们可以向这个特殊的 exports 对象添加任意属性。例如,我们现在为 `index.js` 和 `lib/util.js` 的 exports 对象添加一个 id 属性:
```
-// Add the following line at the top of lib/util.js
+// 在 lib/util.js 顶部添加以下代码
exports.id = 'lib/util';
-// Add the following line at the top of index.js
+// 在 index.js 顶部添加以下代码
exports.id = 'index';
```
-When we now execute `index.js`, we’ll see these attributes as managed on each file’s `module` object:
+然后运行 `index.js`,我们将看到:
```
~/learn-node $ node index.js
@@ -319,15 +303,15 @@ In util Module {
... }
```
-I’ve removed some attributes in the above output to keep it brief, but note how the `exports` object now has the attributes we defined in each module. You can put as many attributes as you want on that exports object, and you can actually change the whole object to be something else. For example, to change the exports object to be a function instead of an object, we do the following:
+为了保持示例简短,我删除了以上输出中的一些属性,但请注意:`exports` 对象现在拥有我们在各模块中定义的属性。你可以向 exports 对象添加任意多的属性,也可以直接将整个对象改为其它对象。例如,我们可以通过以下方式将 exports 对象更改为一个函数:
```
-// Add the following line in index.js before the console.log
+// 将以下代码添加在 index.js 中的 console.log 语句前
module.exports = function() {};
```
-When you run `index.js` now, you’ll see how the `exports` object is a function:
+再次运行 `index.js`,你将看到 `exports` 对象是一个函数:
```
~/learn-node $ node index.js
@@ -338,9 +322,9 @@ In index Module {
... }
```
-Note how we did not do `exports = function() {}` to make the `exports` object into a function. We can’t actually do that because the `exports` variable inside each module is just a reference to `module.exports` which manages the exported properties. When we reassign the `exports` variable, that reference is lost and we would be introducing a new variable instead of changing the `module.exports` object.
+>注意:我们并没有使用 `exports = function() {}` 来将 `exports` 对象更改为函数。实际上,由于各模块中的 `exports` 变量仅仅是对管理输出属性的 `module.exports` 的引用,当我们对 `exports` 变量重新赋值时,引用就会丢失,此时我们只是引入了一个新的变量,而没有对 `module.exports` 做修改。
-The `module.exports` object in every module is what the `require` function returns when we require that module. For example, change the `require('./lib/util')` line in `index.js` into:
+各模块中的 `module.exports` 对象就是我们在引入该模块时 `require` 函数的返回值。例如,我们将 `index.js` 中的 `require('./lib/util')` 改为:
```
const UTIL = require('./lib/util');
@@ -348,24 +332,24 @@ const UTIL = require('./lib/util');
console.log('UTIL:', UTIL);
```
-The above will capture the properties exported in `lib/util` into the `UTIL` constant. When we run `index.js` now, the very last line will output:
+以上代码会将 `lib/util` 输出的属性赋值给 `UTIL` 常量。我们现在运行 `index.js`,最后一行将输出以下结果:
```
UTIL: { id: 'lib/util' }
```
-Let’s also talk about the `loaded` attribute on every module. So far, every time we printed a module object, we saw a `loaded` attribute on that object with a value of `false`.
+我们再来谈谈各模块中的 `loaded` 属性。到目前为止我们打印的所有 module 对象中都有一个值为 `false` 的 `loaded` 属性。
-The `module` module uses the `loaded` attribute to track which modules have been loaded (true value) and which modules are still being loaded (false value). We can, for example, see the `index.js` module fully loaded if we print its `module` object on the next cycle of the event loop using a `setImmediate` call:
+`module` 模块使用 `loaded` 属性对模块的加载状态进行跟踪,判断哪些模块已经加载完成(值为 true)以及哪些模块仍在加载(值为 false)。例如,要判断 `index.js` 模块是否已完全加载,我们可以在下一个事件循环中使用一个 `setImmediate` 回调打印出他的 `module` 对象。
```
-// In index.js
+// index.js 中
setImmediate(() => {
console.log('The index.js module object is now loaded!', module)
});
```
-The output of that would be:
+以上输出将得到:
```
The index.js module object is now loaded! Module {
@@ -390,23 +374,26 @@ The index.js module object is now loaded! Module {
'/node_modules' ] }
```
-Note how in this delayed `console.log` output both `lib/util.js` and `index.js` are fully loaded.
+>注意:这个延迟的 `console.log` 的输出显示了 `lib/util.js` 和 `index.js` 都已完全加载。
The `exports` object becomes complete when Node finishes loading the module (and labels it so). The whole process of requiring/loading a module is *synchronous.* That’s why we were able to see the modules fully loaded after one cycle of the event loop.
+`exports` 对象在 Node 完成引入/加载所有模块并标记时(becomes complete……构建完成??)。引入一个模块的整个过程是 **同步的**,因此我们才能在一个事件循环结束后看见模块被完全加载。
-This also means that we cannot change the `exports` object asynchronously. We can’t, for example, do the following in any module:
+这也意味着我们无法异步地更改 `exports` 对象。例如,我们在任何模块中都无法执行以下操作:
```
fs.readFile('/etc/passwd', (err, data) => {
if (err) throw err;
- exports.data = data; // Will not work.
+ exports.data = data; // 无效
});
```
#### Circular module dependency ####
+#### 循环模块依赖 ####
Let’s now try to answer the important question about circular dependency in Node: What happens when module 1 requires module 2, and module 2 requires module 1?
+我们现在来回答关于 Node 中循环依赖的重要问题:当模块1
To find out, let’s create the following two files under `lib/`, `module1.js` and `module.js` and have them require each other:
From 25b93838b268f4ba80d9fd573ff5a3ab465baf4c Mon Sep 17 00:00:00 2001
From: zhouzihanntu
Date: Thu, 30 Mar 2017 22:13:50 +0800
Subject: [PATCH 007/638] update file
---
...-in-node-js-everything-you-need-to-know.md | 57 ++++++++++---------
1 file changed, 29 insertions(+), 28 deletions(-)
diff --git a/TODO/requiring-modules-in-node-js-everything-you-need-to-know.md b/TODO/requiring-modules-in-node-js-everything-you-need-to-know.md
index 0f35c99a5d3..4074986cbae 100644
--- a/TODO/requiring-modules-in-node-js-everything-you-need-to-know.md
+++ b/TODO/requiring-modules-in-node-js-everything-you-need-to-know.md
@@ -266,7 +266,6 @@ In util Module {
重点来了,如果我们在 `lib/util` 模块中引入 `index` 主模块会发生什么?这就是 Node 中所支持的循环模块依赖关系。
-To understand it better, let’s first understand a few other concepts on the module object.
为了更好理解循环模块依赖,我们先来了解一些关于 module 对象的概念。
#### exports、module.exports 和模块异步加载 ####
@@ -389,13 +388,11 @@ fs.readFile('/etc/passwd', (err, data) => {
});
```
-#### Circular module dependency ####
#### 循环模块依赖 ####
-Let’s now try to answer the important question about circular dependency in Node: What happens when module 1 requires module 2, and module 2 requires module 1?
-我们现在来回答关于 Node 中循环依赖的重要问题:当模块1
+我们现在来回答关于 Node 中循环依赖的重要问题:当我们在模块1中引用模块2,在模块2中引用模块1时会发生什么?
-To find out, let’s create the following two files under `lib/`, `module1.js` and `module.js` and have them require each other:
+为了找到答案,我们在 `lib/` 下创建 `module1.js` 和 `module.js` 两个文件并让它们互相引用:
```
// lib/module1.js
@@ -413,24 +410,25 @@ const Module1 = require('./module1');
console.log('Module1 is partially loaded here', Module1);
```
-When we run `module1.js` we see the following:
+执行 `module1.js` 后,我们将看到:
```
~/learn-node $ node lib/module1.js
Module1 is partially loaded here { a: 1 }
```
-We required `module2` before `module1` was fully loaded, and since `module2` required `module1` while it wasn’t fully loaded, what we get from the `exports` object at that point are all the properties exported prior to the circular dependency. Only the `a` property was reported because both `b` and `c` were exported after `module2` required and printed `module1`.
+我们在 `module1` 加载完成前引用了 `module2`,而此时 `module1` 尚未加载完,我们从当前的 `exports` 对象中得到的是在循环依赖之前导出的所有属性。这里只列出的只有属性 `a`,因为属性 `b` 和 `c` 都是在 `module2` 引入并打印了 `module1` 后导出的。
-Node keeps this really simple. During the loading of a module, it builds the `exports` object. You can require the module before it’s done loading and you’ll just get a partial exports object with whatever was defined so far.
+Node 使这个过程变得非常简单。它在模块加载时构建 `exports` 对象。你可以在该模块完成加载前引用它,而你将得到此时已定义的部分导出对象。
#### JSON and C/C++ addons ####
+#### 使用 JSON 和 C/C++ 插件 ####
-We can natively require JSON files and C++ addon files with the require function. You don’t even need to specify a file extension to do so.
+我们可以使用自带的 require 函数引用 JSON 文件和 C++ 插件。你甚至不需要为此去指定一个文件扩展。
-If a file extension was not specified, the first thing Node will try to resolve is a `.js` file. If it can’t find a `.js` file, it will try a `.json` file and it will parse the `.json` file if found as a JSON text file. After that, it will try to find a binary `.node` file. However, to remove ambiguity, you should probably specify a file extension when requiring anything other than `.js` files.
+如果一个文件扩展未被声明,Node 会在第一时间解析 `.js` 文件。如果没有找到 `.js` 文件,它将继续寻找 `.json` 文件并在找到一个 JSON 文本文件后将其解析为 `.json` 文件。随后,Node 将会查找二进制的 `.node` 文件。但是为了避免歧义,你最好在引用除 `.js` 文件以外的文件类型时声明文件扩展。
-Requiring JSON files is useful if, for example, everything you need to manage in that file is some static configuration values, or some values that you periodically read from an external source. For example, if we had the following `config.json` file:
+如果你需要在文件中放置的内容都是一些静态的配置信息,或定期从外部来源读取的一些值,那么使用 JSON 文件非常有用。例如,我们有以下 `config.json` 文件:
```
{
@@ -439,28 +437,29 @@ Requiring JSON files is useful if, for example, everything you need to manage in
}
```
-We can require it directly like this:
+我们可以这样直接引用它:
```
const { host, port } = require('./config');
-```
-
-console.log(`Server will run at [http://${host}:${port}`](http://$%7Bhost%7D:$%7Bport%7D`));
+console.log(`Server will run at [http://${host}:${port}](http://$%7Bhost%7D:$%7Bport%7D`));
-Running the above code will have this output:
+```
+执行以上代码将输出以下结果:
+```
Server will run at [http://localhost:8080](http://localhost:8080)
+```
-If Node can’t find a `.js` or a `.json` file, it will look for a `.node` file and it would interpret the file as a compiled addon module.
+如果 Node 找不到 `.js` 或 `.json` 文件,它将查找一个 `.node` 文件并将其解释为一个编译后的插件模块。
-The Node documentation site has a [sample addon file](https://nodejs.org/api/addons.html#addons_hello_world) which is written in C++. It’s a simple module that exposes a `hello()` function and the hello function outputs “world.”
+Node 文档站点有一个用 C++ 编写的[插件示例](https://nodejs.org/api/addons.html#addons_hello_world),该示例模块提供了一个输出 “world” 的 `hello()` 函数。
-You can use the `node-gyp` package to compile and build the `.cc` file into a `.addon` file. You just need to configure a [binding.gyp](https://nodejs.org/api/addons.html#addons_building) file to tell `node-gyp` what to do.
+你可以使用 `node-gyp` 插件将 `.cc` 文件编译成 `.addon` 文件。只需要配置一个 [binding.gyp](https://nodejs.org/api/addons.html#addons_building) 文件来告诉 `node-gyp` 要做什么。
-Once you have the `addon.node` file (or whatever name you specify in `binding.gyp`) then you can natively require it just like any other module:
+有了 `addon.node` 文件(你可以在 `binding.gyp` 中声明任意文件名),你就可以像引用其他模块一样引用它了。
```
const addon = require('./addon');
@@ -468,29 +467,31 @@ const addon = require('./addon');
console.log(addon.hello());
```
-We can actually see the support of the three extensions by looking at `require.extensions`.
+我们可以通过 `require.extensions` 查看 Node 对这三类扩展的支持。
-Looking at the functions for each extension, you can clearly see what Node will do with each. It uses `module._compile` for `.js` files, `JSON.parse` for `.json` files, and `process.dlopen` for `.node` files.
+你可以从各个扩展对应的函数中清楚了解 Node 对它们分别所做的操作:对 `.js` 文件使用 `module._compile`,对 `.json` 文件使用 `JSON.parse`,对 `.node` 文件使用 `process.dlopen`。
#### All code you write in Node will be wrapped in functions ####
+#### 你在 Node 中写的所有代码都将被包装成函数 ####
-Node’s wrapping of modules is often misunderstood. To understand it, let me remind you about the `exports`/`module.exports` relation.
+Node 的模块打包经常被误解。要了解它的原理,请回忆一下 `exports` 与 `module.exports` 的关系。
-We can use the `exports` object to export properties, but we cannot replace the `exports` object directly because it’s just a reference to `module.exports`
+我们可以使用 `exports` 对象导出属性,但是由于 `exports` 对象仅仅是对 `module.exports` 的一个引用,我们无法直接对其执行替换操作。
```
-exports.id = 42; // This is ok.
+exports.id = 42; // 有效
-exports = { id: 42 }; // This will not work.
+exports = { id: 42 }; // 无效
-module.exports = { id: 42 }; // This is ok.
+module.exports = { id: 42 }; // 有效
```
-How exactly does this `exports` object, which appears to be global for every module, get defined as a reference on the `module` object?
+这个 `exports` 对象看起来对所有模块都是全局的,它是如何被定义成 `module` 对象的引用的呢?
Let me ask one more question before explaining Node’s wrapping process.
+在解释 Node 的打包进程前,再
In a browser, when we declare a variable in a script like this:
From 656d9cbcd89d61778c2c2675c4e9b9156c5c3347 Mon Sep 17 00:00:00 2001
From: tanglie
Date: Sat, 1 Apr 2017 18:05:07 +0800
Subject: [PATCH 008/638] Update Dependency-Injection-with-Dagger-2.md
---
TODO/Dependency-Injection-with-Dagger-2.md | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/TODO/Dependency-Injection-with-Dagger-2.md b/TODO/Dependency-Injection-with-Dagger-2.md
index 199a78c5438..f33534c9171 100644
--- a/TODO/Dependency-Injection-with-Dagger-2.md
+++ b/TODO/Dependency-Injection-with-Dagger-2.md
@@ -86,7 +86,7 @@ Retrofit retrofit = new Retrofit.Builder()
你需要通过创建 Dagger 2 **模块**定义哪些对象应该作为依赖链的一部分。例如,假设我们想要创建一个 `Retrofit` 单例,使它绑定到应用生命周期,对所有的 Activity 和 Fragment 都可用,我们首先需要使 Dagger 意识到他可以提供 `Retrofit` 的实例。
-Because we wish to setup caching, we need an Application context. Our first Dagger module, `AppModule.java`, will be used to provide this reference. We will define a method annotated with `@Provides` that denotes to Dagger that this method is the constructor for the `Application` return type:
+因为需要设置缓存,我们需要一个 Application context。我们的第一个 Dagger 模块,`AppModule.java`,被用于提供这个依赖。我们将定义一个 `@Provides` 注解,标注带有 `Application` 的构造方法:
```java
@Module
@@ -106,9 +106,9 @@ public class AppModule {
}
```
-We create a class called `NetModule.java` and annotate it with `@Module` to signal to Dagger to search within the available methods for possible instance providers.
+我们创建了一个名为 `NetModule.java` 的类,并用 `@Module` 来通知 Dagger,在这里查找提供实例的方法。
-The methods that will actually expose available return types should also be annotated with `@Provides` decorator. The `Singleton` annotation also signals to the Dagger compiler that the instance should be created only once in the application. In the following example, we are specifying `SharedPreferences`, `Gson`, `Cache`, `OkHttpClient`, and `Retrofit` as the return types that can be used as part of the dependency list.
+返回实例的方法也应当用 `@Provides` 标注。`Singleton` 标注通知 Dagger 编译器,实例在应用中只应被创建一次。在下面的例子中,我们把 `SharedPreferences`, `Gson`, `Cache`, `OkHttpClient`, 和 `Retrofit` 设置为在依赖列表中可用的类型。
```java
@Module
@@ -166,7 +166,7 @@ public class NetModule {
}
```
-Note that the method names (i.e. `provideGson()`, `provideRetrofit()`, etc) do not matter and can be named anything. The return type annotated with a `@Provides` decorator is used to associate this instantiation with any other modules of the same type. The `@Singleton` annotation is used to declare to Dagger to be only initialized only once during the entire lifecycle of the application.
+注意,方法名称(比如 `provideGson()`, `provideRetrofit()` 等)是没关系的,可以任意设置。 用 `@Provides` decorator is used to associate this instantiation with any other modules of the same type. The `@Singleton` annotation is used to declare to Dagger to be only initialized only once during the entire lifecycle of the application.
A `Retrofit` instance depends both on a `Gson` and `OkHttpClient` instance, so we can define another method within the same class that takes these two types. The `@Provides` annotation and these two parameters in the method will cause Dagger to recognize that there is a dependency on `Gson` and `OkHttpClient` to build a `Retrofit` instance.
From 1d7b8ca3579b0e402f04c76d8340454fb04027bc Mon Sep 17 00:00:00 2001
From: xiaoyusilen
Date: Sat, 1 Apr 2017 23:49:40 +0800
Subject: [PATCH 009/638] First translation
---
TODO/go-function-calls-redux.md | 51 +++++++++++++++++++++++++++------
1 file changed, 42 insertions(+), 9 deletions(-)
diff --git a/TODO/go-function-calls-redux.md b/TODO/go-function-calls-redux.md
index 2e8b6efa515..5e57a42f892 100644
--- a/TODO/go-function-calls-redux.md
+++ b/TODO/go-function-calls-redux.md
@@ -4,11 +4,17 @@
> * 译者:[xiaoyusilen](http://xiaoyu.world)
> * 校对者:
-# Go 函数调用 Redux #
+# Go Function Calls Redux Go 方法调用 Redux #
+
+Some time ago in a [previous post](https://syslog.ravelin.com/anatomy-of-a-function-call-in-go-f6fc81b80ecc#.gpqsgzmjc) I promised to take a further look at how function calls and call stacks in Go work. I’ve think found a neat way to make good on that promise, so here goes.
前段时间在一篇[文章](https://syslog.ravelin.com/anatomy-of-a-function-call-in-go-f6fc81b80ecc#.gpqsgzmjc)中我答应写一篇进一步分析 Go 中如何进行函数调用和调用堆栈在 Go 中如何工作的文章。现在我找到了一种简洁的方式来向大家展示上述内容,所以有了现在这篇文章。
-什么是调用堆栈?它是一个用于保存局部变量和调用参数的内存区域,并且跟踪每个函数应该返回到哪里去。每个 goroutine 都有它自己的堆栈。你甚至可以说每个 goroutine 就是它自己的堆栈。
+So what is a call stack? Well, it’s an area of memory used to hold local variables and call parameters, and to track where functions should return to. Each goroutine has it’s own stack. You could almost say a goroutine is its stack.
+
+什么是调用堆栈?它是一个用于保存局部变量和调用参数的内存区域,并且跟踪每个方法应该返回到哪里去。每个 goroutine 都有它自己的堆栈。你甚至可以说每个 goroutine 就是它自己的堆栈。
+
+Here’s the code I’m going to use to show the stack in action. It’s just a sequence of simple function calls. main() calls [f1(0xdeadbeef)](https://en.wikipedia.org/wiki/Hexspeak) , which then calls `f2(0xabad1dea)`, which calls `f3(0xbaddcafe)`. `f3()` then adds one to it’s parameter, and stores it in a local variable called `local`. It then takes the address of `local` and prints out memory starting at that address. Because `local` is on the stack, this prints the stack.
下面是我用于演示堆栈的代码。就是一系列简单的函数调用,main() 函数调用 [f1(0xdeadbeef)](https://en.wikipedia.org/wiki/Hexspeak),然后调用 `f2(0xabad1dea)`,再调用 `f3(0xbaddcafe)`。然后 f3() 将其中一个作为它的参数,并且将它存储在名为 `local` 的本地变量中。然后获取 `local` 的内存地址并且从那里开始输出。因为 `loacl` 在栈内,所以输出的就是栈。
@@ -59,8 +65,12 @@ func showFunc(at uintptr) {
}
```
+Here’s the output of the program. It is a dump of memory starting at the address of `local`, shown as a list of 8-byte integers in hex. The address of each integer is on the left, and the int at the address is on the right.
+
下面是上述代码的输出结果。它是从 `local` 的地址开始的内存转储,是以十六进制形式展示的8字节列表。左边是每个整数的存储地址,右边是地址内存储的整数。
+We know `local` should equal 0xBADDCAFE + 1, or 0xBADDCAFF, and this is indeed what we see at the start of the dump.
+
我们知道 `local` 应该等于 0xBADDCAFE + 1,或者 0xBADDCAFF,这确实是我们转储开始时看到的。
```
@@ -94,11 +104,16 @@ C42003FFC0: C4200001A0
102752A is runtime.main /usr/local/Cellar/go/1.8/libexec/src/runtime/proc.go 194
```
+- The next number is 0xC42003FF48, which is the address of the 5th line of the dump.
- 下一个数字是 0xC42003FF48,它是转储的第五行的地址。
+- After that we have 0x1088BEB. It turns out this is an address of executable code, and if we feed it into `runtime.FuncForPC` we see it is the address of line 19 of main.go, which is the last line of `f2()`. This is the address we return to when `f3()` returns.
- 然后我们可以得到 0x1088BEB。事实上这是一个可执行代码的地址,如果我们将它作为 `runtime.FuncForPC` 的参数,我们知道它是 main.go 的第19行代码的地址,也是 f2() 的最后一行代码。这是 f3() 返回时我们得到的地址。
+- Next we have 0xBADDCAFE, the parameter to our call to `f3()`
- 接下来我们得到 0xBADDCAFE,这是我们调用 `f3()` 时的参数。
-如果继续我们将看到类似上面的输出结果。下面我已经标记了内存转储,显示堆栈指针如何跟踪转储,参数和返回地址在哪里。
+If we carry on we continue to see this pattern. Below I’ve marked up the memory dump showing how the stack pointers track back through the dump and where the function parameters and return addresses sit.
+
+如果继续我们将继续看到这种模式。下面我已经标记了内存转储,显示堆栈指针如何跟踪转储,参数和返回地址在哪里。
```go
C42003FF28: BADDCAFF Local variable in f3()
@@ -115,14 +130,22 @@ C42003FFC0: C4200001A0
C42003FF80: 102752A return to runtime.main()
```
-通过这些我们可以看出:
+From this we can see many things.
+通过这些我们可以明白很多。
+
+- First, the stack starts at a high address, and the stack address reduces as function calls are made.
- 首先,堆栈从高地址开始,堆栈地址随着函数调用变小。
-- 当进行函数调用时,调用者将参数放入栈内,然后返回地址(调用函数中的下一条指令的地址),接着指向堆栈中较高的指针。
+- When a function call is made, the caller pushes the parameters onto the stack, then the return address (the address of the next instruction in the calling function), then a pointer to a higher point in the stack.
+- 当进行函数调用时,调用者将参数放入栈内,然后返回地址(调用函数中的下一条指令的地址),然后指向堆栈中较高的指针。
+- This pointer is used to find the previous function call on the stack when unwinding the stack when the call returns.
- 当调用返回时,这个指针用于在堆栈中查找先前调用的函数。
+- Local variables are stored after the stack pointer.
- 局部变量存储在堆栈指针之后。
-我们可以使用相同的技巧来分析一些稍微复杂的函数调用。这次,我添加了更多的参数,`f2()` 函数也返回了更多的值。
+We can use the same technique to look at some slightly more complicated function calls. I’ve added more parameters, and some return values to `f2()` in this version.
+
+我们可以使用相同的技巧来分析一些稍微复杂的函数调用。这次,我添加了更多的参数,`f2()` 方法也返回了更多的值。
```go
package main
@@ -153,6 +176,8 @@ func f3(val int) {
}
```
+This time I’ve jumped straight to the marked-up output.
+
这次我们直接看被我标记好的输出结果。
```go
@@ -173,11 +198,19 @@ func f3(val int) {
C42003FF80: 102752A return to runtime.main()
```
-从结果中我们可以看出:
+From this we can see that
-- 调用函数在函数参数之前为被调用函数的返回值提供空间。(注意这些值是没有初始化的,因为这个函数还没有返回!)
+从结果中我们可以看出
+
+- the calling function makes space for the return values of the called function before the function parameters. (Note the values are uninitialised because the function hasn’t returned yet!)
+- 调用函数在函数参数之前为被调用函数的返回值提供空间。(注意这些值是没有初始化的,因为这个方法还没有返回!)
+- parameters are pushed onto the stack in reverse order.
- 参数在栈内的顺序与入栈顺序相反。
-希望我都讲清楚了。既然你已经看到这儿了,如果喜欢我的这篇文章或者可以从中学到一点什么的话,那么请给我点个赞。不然我就没办法获得积分。
+Hopefully all that made sense! If you got this far and enjoyed it or learned something, please hit that heart-button. I can’t earn internet points without you.
+
+希望上面所写的这些没什么问题!既然你已经看到这儿了,如果喜欢我的这篇文章或者可以从中学到一点什么的话,那么请给我点个赞。不然我就没办法获得积分。
+
+*By day, Phil fights crime at* [*ravelin.com*](https://ravelin.com) *. You can join him:* [*https://angel.co/ravelin/jobs*
**Phil 白天在 [ravelin.com](https://ravelin.com) 的工作主要是防止网上欺诈,你可以加入他 https://angel.co/ravelin/jobs。**
\ No newline at end of file
From a5d5bae6fc2fceca0c14d8acce080944cf044862 Mon Sep 17 00:00:00 2001
From: xiaoyusilen
Date: Sat, 1 Apr 2017 23:57:27 +0800
Subject: [PATCH 010/638] Modify details
---
TODO/anatomy-of-a-function-call-in-go.md | 108 +++++++++++------------
TODO/go-function-calls-redux.md | 51 ++---------
2 files changed, 63 insertions(+), 96 deletions(-)
diff --git a/TODO/anatomy-of-a-function-call-in-go.md b/TODO/anatomy-of-a-function-call-in-go.md
index e03a90ccad1..b4baa299cb1 100644
--- a/TODO/anatomy-of-a-function-call-in-go.md
+++ b/TODO/anatomy-of-a-function-call-in-go.md
@@ -1,18 +1,18 @@
> * 原文地址:[Anatomy of a function call in Go](https://syslog.ravelin.com/anatomy-of-a-function-call-in-go-f6fc81b80ecc#.povigaliw)
> * 原文作者:[Phil Pearl](https://syslog.ravelin.com/@philpearl?source=post_header_lockup)
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
-> * 译者:
+> * 译者:[xiaoyusilen](http://xiaoyu.world)
> * 校对者:
-# Anatomy of a function call in Go #
+# 解析 Go 中的函数调用 #
-Let’s take a look at a couple of simple Go functions and see if we can see how function calls work. We’ll do this by looking at the assembly language the Go compiler generates for the functions. This might be a little ambitious for a small blog post, but don’t worry, assembly language is simple. Even a CPU can understand it.
+让我们来看一些简单的 Go 的函数,然后看看我们能否明白函数调用是怎么回事。我们将通过分析 Go 编译器根据函数生成的汇编语言来完成这件事。对于一个小小的博客来说这可能有一点野心,但是别担心,汇编语言很简单。哪怕是 CPU 都能读懂。
-By Rob Baines [https://github.com/telecoda/inktober-2016](https://github.com/telecoda/inktober-2016)
+图片来自 Rob Baines [https://github.com/telecoda/inktober-2016](https://github.com/telecoda/inktober-2016)
-Here’s our first function. Yep, we’re just adding two numbers.
+这是我们的第一个函数。对,我们只是让两个数相加。
```
func add(a, b int) int {
@@ -20,9 +20,9 @@ func add(a, b int) int {
}
```
-We’ll build it with optimisations disabled to make the assembly easier to follow. We do this with `go build -gcflags ‘-N -l’`. We can then dump out the assembly for our function with `go tool objdump -s main.add func` (func is the name of our package and the executable we just built with go build).
+我们编译的时候需要关闭优化这样方便跟踪每个部分。我们用 `go build -gcflags 'N -l'` 这个命令来完成上述操作。然后我们可以用 `go tool objdump -s main.add func` 输出我们函数的具体细节(这里的 func 是我们的包名,也就是我们刚刚用 go build 编译出的可执行文件)。
-If you’ve never looked at assembly language before, then, well, congratulations, this is a new thing for you today. I’ve done this on a Mac, so the assembly is Intel 64-bit.
+如果你以前从来没有看过汇编语言,那么恭喜啦,你今天看到的内容对你来说是全新的。我将在 Mac 上完成这些事情,所以配置是 Intel 64位。
```
main.go:20 0x22c0 48c744241800000000 MOVQ $0x0, 0x18(SP)
@@ -33,43 +33,43 @@ If you’ve never looked at assembly language before, then, well, congratulation
main.go:21 0x22db c3 RET
```
-What are we looking at here? Each line breaks down into 4 sections as follows.
+我们看到了什么?每一行如下所示被分为了4部分:
-- The source file name and line number (main.go:15). The source code at this line is translated to the instructions marked with that line number. One line of Go is likely translated to multiple lines of assembly.
-- the offset into the object file (e.g. 0x22C0).
-- The machine code (e.g. 48c744241800000000). This is the actual binary machine code the CPU executes. We’re not going to look at this! Almost nobody ever does.
-- The assembly language representation of the machine code. This is the bit we can hope to understand.
+- 源文件的名称和行号(main.go:15)。这行的源代码会被转换为标有代码行号的说明。Go 的一行可能被转换成多行程序集。
+- 对象的偏移量(例如 0x22C0)。
+- 机器码(例如 48c744241800000000)。这是 CPU 实际执行的二进制机器码。我们不需要看这个,几乎没有人看这玩意。
+- 机器码的汇编表示形式,这也是我们想要理解的部分。
-Let’s focus in on that last section, the assembly code.
+让我们将注意力集中在最后一部分,汇编语言。
-- MOVQ, ADDQ and RET are instructions. They tell the CPU what operation to perform. They are followed by parameters telling the CPU what to perform the operation on.
-- SP, AX and CX are CPU registers. These are places where the CPU can store working values. There are several other registers the CPU can use.
-- SP is a special purpose register and is used to store the current stack pointer. The stack is an area of memory where the local variables, function parameters and function calls are recorded. There’s one stack per goroutine. As one function calls another, then another, each gets its own area on the stack. Areas are created during the function call by reducing the value of SP by the size of the area needed.
-- 0x8(SP) refers to the memory location that is 8 bytes past the memory location that SP points to.
+- MOVQ,ADDQ 和 RET 是说明。它们告诉 CPU 需要执行的操作。后面的参数告诉 CPU 对什么执行该操作。
+- SP,AX 和 CX 是 CPU 寄存器。寄存器是 CPU 用于存储值的地方,CPU 有多个寄存器可以使用。
+- SP 是一个专用寄存器,用于存储当前堆栈指针。堆栈是记录局部变量,参数和函数调用的寄存器。每个 goroutine 都有一个堆栈。当一个函数调用另一个函数,然后另一个函数再调用其他函数,每个函数在堆栈上获得自己的存储区域。在函数调用期间创建存储区域,将 SP 的大小中减去所需的存储大小。
+- 0x8(SP)是指超过 SP 指向的内存位置的 8 个字节的内存位置。
-So, our ingredients are memory locations, CPU registers, instructions to move values between memory and registers, and operations on registers. And that’s pretty much all a CPU does.
+因此,我们的工作的内容包含存储器位置,CPU 寄存器,用于在存储器和寄存器之间移动值的指令以及寄存器上的操作。 这几乎就是一个 CPU 所完成的事情了。
-Now lets look at the assembly in detail, starting with the first instruction. Remember we have two parameters `a` & `b` which we need to load from memory somewhere, add together, then return to the caller somehow.
+现在让我们从第一条指令开始看每一条内容。别忘了我们需要从内存中加载两个参数 `a` 和 `b`,把它们相加,然后返回至调用函数。
-1. `MOVQ $0x0, 0x18(SP)` puts 0 in the memory location SP+0x18. This is a bit mysterious.
-2. `MOVQ 0x8(SP), AX` puts the contents of memory location SP+0x8 in CPU register AX. Perhaps this is loading one of our parameters from memory?
-3. `MOVQ 0x10(SP), CX` puts the contents of memory location SP+0x10 in CPU register CX. This could be our other parameter.
-4. `ADDQ CX, AX` adds CX to AX, leaving the result in AX. Well, that’s adding the two parameters surely.
-5. `MOVQ AX, 0x18(SP)` stores the contents of register AX at the memory location SP+0x18. And that’s saving the result of the addition.
-6. `RET` returns to the calling function.
+1. `MOVQ $0x0, 0x18(SP)` 将 0 置于存储单元 SP+0x18 中。 这句看起来有点神秘。
+2. `MOVQ 0x8(SP), AX` 将存储单元 SP+0x8 中的内容放到 CPU 寄存器 AX 中。也许这就是从内存中加载的我们的参数之一?
+3. `MOVQ 0x10(SP), CX` 将存储单元 SP+0x10 的内容置于 CPU 寄存器 CX 中。 这可能就是我们所需的另一个参数。
+4. `ADDQ CX, AX` 将 CX 与 AX 相加,将结果存到 AX 中。好,现在已经把两个参数相加了。
+5. `MOVQ AX, 0x18(sp)` 将寄存器 AX 的内容存储在存储单元 SP+0x18 中。这就是在存储相加的结果。
+6. `RET` 将结果返回至调用函数。
-Remember our function has two parameters `a` & `b`, and it calculates `a+b` and returns the result. `MOVQ 0x8(SP), AX` is moving parameter `a` to AX. `a` is passed into the function on the stack at SP+0x8. `MOVQ 0x10(SP), CX` moves parameter `b` to CX. Parameter `b` is passed into the function on the stack at SP+0x10. `ADDQ CX, AX` adds `a` & `b`. `MOVQ AX, 0x18(SP)` stores the result at SP+0x18. The result is passed out of the function by placing it on the stack at SP+0x18. When the function returns the calling function can read the result off the stack.
+记住我们的函数有两个参数 `a` 和 `b`,它计算了 `a+b` 并且返回了结果。`MOVQ 0x8(SP), AX` 将参数 `a` 移到 AX 中,在 SP+0x8 的堆栈中 `a` 将被传给函数。`MOVQ 0x10(SP), CX` 将参数 `b` 移到 CX 中,在 SP+0x10 的堆栈中 `b` 将被传给函数。`ADDQ CX, AX` 使 `a` 和 `b` 相加。`MOVQ AX, 0x18(SP)` 将结果存储到 SP+0x18 中。 现在相加的结果被存储在 SP+0x18 的堆栈中,当函数返回调用函数时,可以从栈中读取结果。
-[I’ve assumed `a` is the first parameter and `b` is the second. I’m not sure that’s right. We’d need to play around a bit to work that out, but this post is getting pretty long already]
+我假设 `a` 是第一个参数,`b` 是第二个参数。我不确定是不是这样。我们需要花一点时间来完成这件事,但是这篇文章已经很长了。
-So what’s that mysterious first line doing? `MOVQ $0x0, 0x18(SP)` is storing 0 in location SP+0x18, which is where our result is finally stored. We can guess that this is because Go sets uninitialised values to zero, and we’ve turned off optimisations so the compiler still does this even if it’s unnecessary.
+那么有点神秘的第一行代码究竟是做什么用的?`MOVQ $0X0, 0X18(SP)` 将 0 存储至 SP+0x18 中,而 SP+0x18 是我们存储相加结果的地方。我们可以猜测,这是因为 Go 把没有初始化的值设置为 0 ,我们已经关闭了优化,即使没有必要,编译器也会执行这个操作。
-So what have we learnt.
+所以我们从中明白了什么:
-- Well, it looks like parameters are stored on the stack, with the first at SP+0x8, and the others at following at higher-numbered addresses.
-- And it looks like returned values are stored after the parameters, at yet-higher still addresses.
+- 好,看起来参数都存在堆栈中,第一个参数存储在 SP+0x8 中,另一个在更高编号的地址中。
+- 并且看上去返回的结果存储在参数后边,一个更高编号的已知地址中。
-Let’s now look at another function. This one has a local variable, but we’ve still kept it simple.
+现在让我们看另一个函数。这个函数有一个全局变量,不过我们依然会让它看起来很简单。
```
func add3(a int) int {
@@ -78,7 +78,7 @@ func add3(a int) int {
}
```
-We use the same procedure to get an assembly listing.
+我们用和刚才一样的过程来获取程序集列表。
```
TEXT main.add3(SB)
@@ -98,37 +98,37 @@ TEXT main.add3(SB)
main.go:17 0x22b6 c3 RET
```
-Oh! That looks quite a bit more complicated. Let’s try to work it out.
+喔!看起来有点复杂。让我们来试试。
-The first 4 instructions are listed against source code line 15. Here is that line:
+前4条指令是根据源代码中的第15行列出的。这行代码是这样的:
```
func add3(a int) int {
```
-That line doesn’t seem to do much. So perhaps this is some kind of function preamble. Let’s break it down.
+这一行代码似乎没有做什么。所以这可能是一种声明函数的方法。让我们分析一下。
-- `SUBQ $0x10, SP` subtracts 0x10=16 from SP. This gives us 16 bytes more space on the stack
-- `MOVQ BP, 0x8(SP)` stores the value of the register BP at SP+8, then `LEAQ 0x8(SP), BP` loads the address SP+8 into BP. So we’ve made a space to store the old value of BP, then loaded BP with the address of that space. This helps establish the chain of stack areas (or *stack frames*). This is a bit mysterious, and I’m afraid we won’t solve this in this post.
-- Finally in this section we have `MOVQ $0x0, 0x20(SP)` which, similar to the last function we considered, initialises the return value to 0.
+- `SUBQ $0x10, SP` 从 SP 减去 0x10=16。这个操作为我们分类了 16 字节的堆栈空间。
+- `MOVQ BP, 0x8(SP)` 将寄存器 BP 中的值存储至 SP+8 中,然后 `LEAQ 0x8(SP), BP` 将地址 SP+8 中的内容加载到 BP 中。现在我们已经有空间可以存储 BP 中之前所存的内容,然后将 BP 中的内容存储至刚刚分配的存储空间中,这有助于建立堆栈区域链(或者堆栈框架)。这有点神秘,不过在这篇文章中我们恐怕不会解决这个问题。
+- 在这一部分的最后是 `MOVQ $ 0x0, 0x20 (SP)`,它和我们刚刚分析的最后一句类似,就是将返回值初始化为0。
-The next line of the assembly corresponds to `b := 3` in the source code. The instruction is `MOVQ $0x3, 0(SP)`, which puts the value 3 into memory at SP+0. This solves one mystery. When we subtracted 0x10=16 from SP we made room for 2 8-byte values: our local variable `b` stored at SP+0, and the old value of BP stored at SP+0x08.
+下一行对应的是源码中的 `b := 3`,`MOVQ $03x, 0(SP)` 把 3 放到 SP+0 中。这解决了我们的一个疑惑。当我们从 SP 中减去 0x10 = 16 时,我们得到了可以存储两个 8 字节值的空间:我们的局部变量 `b` 存储在 SP+0 中,而 BP 之前的值存储在 SP+0x08 中。
-The next 6 lines of assembly correspond to `return a + b`. This needs to cover loading `a` & `b` from memory, adding them, and returning the result. Let’s look at each line in turn.
+接下来的 6 行程序集对应于 `return a + b`。这需要从内存中加载 `a` 和 `b`,然后将它们相加,并且返回结果。让我们依次看看每一行。
-- `MOVQ 0x18(SP), AX` moves the function parameter `a` stored at SP+0x18 into register AX
-- `ADDQ $0x3, AX` adds 3 to AX (for some reason it doesn’t use our local variable `b` at SP+0, even though optimisations are turned off)
-- `MOVQ AX, 0x20(SP)` stores the result of `a+b` at SP+0x20, which is where our return value is stored.
-- Next we have `MOVQ 0x8(SP), BP` and `ADDQ $0x10, SP`. These restore the old value of BP, then adds 0x10 to SP, setting it back to the value it was at the start of the function.
-- Finally we have `RET`, which returns to the caller.
+- `MOVQ 0x18(SP), AX` 将存储在 SP+0x18 的参数 `a` 移动到寄存器 AX 中
+- `ADDQ $0x3, AX` 将 3 加到 AX(由于某些原因,它不使用我们存储在 SP+0 的局部变量 `b`,尽管编译时优化被关闭了)
+- `MOVQ AX, 0x20(SP)` 将 `a+b` 的结果存储到 SP+0x20 中,也就是我们返回结果所存的地方。
+- 接下来我们得到的是 `MOVQ 0x8(SP), BP` 以及 `ADDQ $0x10, SP`,这些将恢复BP的旧值,然后将 0x10 添加到 SP,将其设置为该函数开始时的值。
+- 最后我们得到了 `RET`,将要返回给调用函数的。
-So what have we learnt?
+所以我们从中学到了什么呢?
-- The calling function makes space on the stack for the returned values and function parameters. The space for returned values is higher up the stack than the parameters.
-- If the called function has local variables it makes room for them by decreasing the value of the stack pointer SP. It also does something mysterious with the register BP.
-- When the function returns any manipulations of SP & BP are reversed.
+- 调用函数在堆栈中为返回值和参数分配空间。返回值的存储地址比参数的存储地址高。
+- 如果被调用函数有局部变量,则通过减少堆栈指针 SP 的值为它们分配空间。它也和寄存器 BP 做了一些神秘的事情。
+- 当函数返回任何 SP&BP 的操作都会相反。
-Let’s map out how the stack was used in the add3() function:
+让我们看看堆栈在 add3() 方法中如何使用:
```
SP+0x20: the return value
@@ -145,8 +145,8 @@ SP+0x08: the old value of BP
SP+0x0: the local variable b
```
-If you look we didn’t see any mention of SP+0x10, so we don’t *know* what this is used for. But I can tell you that this is where the return address is stored. This is how the `RET` instruction knows where to return to.
+如果你觉得我们对于 SP+0x10 没有任何说明,所以不知道这是干什么用的。我可以告诉你,这是存储返回地址的地方。这是为了让 `RET` 指令知道返回到哪里去。
-Well, that’s enough for one post. Hopefully if you didn’t know how this stuff worked you now feel you understand it a little more, and if you were intimidated by assembly it’s perhaps a little less opaque. If you’d like any more detail on this stuff please write a comment and I’ll consider it for a future post.
+这篇文章已经足够了。 希望如果以前你不知道这些东西如何工作,但是现在你觉得你已经有了一些了解,或者如果你被汇编吓倒了,那么它可能不那么清晰。 如果你想了解有关汇编的更多信息,请在评论中告诉我,我会考虑在之后的文章中写出来。
-If you got this far and enjoyed it or learned something, please hit that heart-button so other people can find it.
+既然你已经看到这儿了,如果喜欢我的这篇文章或者可以从中学到一点什么的话,那么请给我点个赞这样这篇文章就可以被更多人看到了。
\ No newline at end of file
diff --git a/TODO/go-function-calls-redux.md b/TODO/go-function-calls-redux.md
index 5e57a42f892..2e8b6efa515 100644
--- a/TODO/go-function-calls-redux.md
+++ b/TODO/go-function-calls-redux.md
@@ -4,17 +4,11 @@
> * 译者:[xiaoyusilen](http://xiaoyu.world)
> * 校对者:
-# Go Function Calls Redux Go 方法调用 Redux #
-
-Some time ago in a [previous post](https://syslog.ravelin.com/anatomy-of-a-function-call-in-go-f6fc81b80ecc#.gpqsgzmjc) I promised to take a further look at how function calls and call stacks in Go work. I’ve think found a neat way to make good on that promise, so here goes.
+# Go 函数调用 Redux #
前段时间在一篇[文章](https://syslog.ravelin.com/anatomy-of-a-function-call-in-go-f6fc81b80ecc#.gpqsgzmjc)中我答应写一篇进一步分析 Go 中如何进行函数调用和调用堆栈在 Go 中如何工作的文章。现在我找到了一种简洁的方式来向大家展示上述内容,所以有了现在这篇文章。
-So what is a call stack? Well, it’s an area of memory used to hold local variables and call parameters, and to track where functions should return to. Each goroutine has it’s own stack. You could almost say a goroutine is its stack.
-
-什么是调用堆栈?它是一个用于保存局部变量和调用参数的内存区域,并且跟踪每个方法应该返回到哪里去。每个 goroutine 都有它自己的堆栈。你甚至可以说每个 goroutine 就是它自己的堆栈。
-
-Here’s the code I’m going to use to show the stack in action. It’s just a sequence of simple function calls. main() calls [f1(0xdeadbeef)](https://en.wikipedia.org/wiki/Hexspeak) , which then calls `f2(0xabad1dea)`, which calls `f3(0xbaddcafe)`. `f3()` then adds one to it’s parameter, and stores it in a local variable called `local`. It then takes the address of `local` and prints out memory starting at that address. Because `local` is on the stack, this prints the stack.
+什么是调用堆栈?它是一个用于保存局部变量和调用参数的内存区域,并且跟踪每个函数应该返回到哪里去。每个 goroutine 都有它自己的堆栈。你甚至可以说每个 goroutine 就是它自己的堆栈。
下面是我用于演示堆栈的代码。就是一系列简单的函数调用,main() 函数调用 [f1(0xdeadbeef)](https://en.wikipedia.org/wiki/Hexspeak),然后调用 `f2(0xabad1dea)`,再调用 `f3(0xbaddcafe)`。然后 f3() 将其中一个作为它的参数,并且将它存储在名为 `local` 的本地变量中。然后获取 `local` 的内存地址并且从那里开始输出。因为 `loacl` 在栈内,所以输出的就是栈。
@@ -65,12 +59,8 @@ func showFunc(at uintptr) {
}
```
-Here’s the output of the program. It is a dump of memory starting at the address of `local`, shown as a list of 8-byte integers in hex. The address of each integer is on the left, and the int at the address is on the right.
-
下面是上述代码的输出结果。它是从 `local` 的地址开始的内存转储,是以十六进制形式展示的8字节列表。左边是每个整数的存储地址,右边是地址内存储的整数。
-We know `local` should equal 0xBADDCAFE + 1, or 0xBADDCAFF, and this is indeed what we see at the start of the dump.
-
我们知道 `local` 应该等于 0xBADDCAFE + 1,或者 0xBADDCAFF,这确实是我们转储开始时看到的。
```
@@ -104,16 +94,11 @@ C42003FFC0: C4200001A0
102752A is runtime.main /usr/local/Cellar/go/1.8/libexec/src/runtime/proc.go 194
```
-- The next number is 0xC42003FF48, which is the address of the 5th line of the dump.
- 下一个数字是 0xC42003FF48,它是转储的第五行的地址。
-- After that we have 0x1088BEB. It turns out this is an address of executable code, and if we feed it into `runtime.FuncForPC` we see it is the address of line 19 of main.go, which is the last line of `f2()`. This is the address we return to when `f3()` returns.
- 然后我们可以得到 0x1088BEB。事实上这是一个可执行代码的地址,如果我们将它作为 `runtime.FuncForPC` 的参数,我们知道它是 main.go 的第19行代码的地址,也是 f2() 的最后一行代码。这是 f3() 返回时我们得到的地址。
-- Next we have 0xBADDCAFE, the parameter to our call to `f3()`
- 接下来我们得到 0xBADDCAFE,这是我们调用 `f3()` 时的参数。
-If we carry on we continue to see this pattern. Below I’ve marked up the memory dump showing how the stack pointers track back through the dump and where the function parameters and return addresses sit.
-
-如果继续我们将继续看到这种模式。下面我已经标记了内存转储,显示堆栈指针如何跟踪转储,参数和返回地址在哪里。
+如果继续我们将看到类似上面的输出结果。下面我已经标记了内存转储,显示堆栈指针如何跟踪转储,参数和返回地址在哪里。
```go
C42003FF28: BADDCAFF Local variable in f3()
@@ -130,22 +115,14 @@ If we carry on we continue to see this pattern. Below I’ve marked up the memor
C42003FF80: 102752A return to runtime.main()
```
-From this we can see many things.
+通过这些我们可以看出:
-通过这些我们可以明白很多。
-
-- First, the stack starts at a high address, and the stack address reduces as function calls are made.
- 首先,堆栈从高地址开始,堆栈地址随着函数调用变小。
-- When a function call is made, the caller pushes the parameters onto the stack, then the return address (the address of the next instruction in the calling function), then a pointer to a higher point in the stack.
-- 当进行函数调用时,调用者将参数放入栈内,然后返回地址(调用函数中的下一条指令的地址),然后指向堆栈中较高的指针。
-- This pointer is used to find the previous function call on the stack when unwinding the stack when the call returns.
+- 当进行函数调用时,调用者将参数放入栈内,然后返回地址(调用函数中的下一条指令的地址),接着指向堆栈中较高的指针。
- 当调用返回时,这个指针用于在堆栈中查找先前调用的函数。
-- Local variables are stored after the stack pointer.
- 局部变量存储在堆栈指针之后。
-We can use the same technique to look at some slightly more complicated function calls. I’ve added more parameters, and some return values to `f2()` in this version.
-
-我们可以使用相同的技巧来分析一些稍微复杂的函数调用。这次,我添加了更多的参数,`f2()` 方法也返回了更多的值。
+我们可以使用相同的技巧来分析一些稍微复杂的函数调用。这次,我添加了更多的参数,`f2()` 函数也返回了更多的值。
```go
package main
@@ -176,8 +153,6 @@ func f3(val int) {
}
```
-This time I’ve jumped straight to the marked-up output.
-
这次我们直接看被我标记好的输出结果。
```go
@@ -198,19 +173,11 @@ This time I’ve jumped straight to the marked-up output.
C42003FF80: 102752A return to runtime.main()
```
-From this we can see that
+从结果中我们可以看出:
-从结果中我们可以看出
-
-- the calling function makes space for the return values of the called function before the function parameters. (Note the values are uninitialised because the function hasn’t returned yet!)
-- 调用函数在函数参数之前为被调用函数的返回值提供空间。(注意这些值是没有初始化的,因为这个方法还没有返回!)
-- parameters are pushed onto the stack in reverse order.
+- 调用函数在函数参数之前为被调用函数的返回值提供空间。(注意这些值是没有初始化的,因为这个函数还没有返回!)
- 参数在栈内的顺序与入栈顺序相反。
-Hopefully all that made sense! If you got this far and enjoyed it or learned something, please hit that heart-button. I can’t earn internet points without you.
-
-希望上面所写的这些没什么问题!既然你已经看到这儿了,如果喜欢我的这篇文章或者可以从中学到一点什么的话,那么请给我点个赞。不然我就没办法获得积分。
-
-*By day, Phil fights crime at* [*ravelin.com*](https://ravelin.com) *. You can join him:* [*https://angel.co/ravelin/jobs*
+希望我都讲清楚了。既然你已经看到这儿了,如果喜欢我的这篇文章或者可以从中学到一点什么的话,那么请给我点个赞。不然我就没办法获得积分。
**Phil 白天在 [ravelin.com](https://ravelin.com) 的工作主要是防止网上欺诈,你可以加入他 https://angel.co/ravelin/jobs。**
\ No newline at end of file
From cb6799660a7a9feae5598380fd5e43009b9b8b96 Mon Sep 17 00:00:00 2001
From: xiaoyusilen
Date: Sat, 1 Apr 2017 23:59:45 +0800
Subject: [PATCH 011/638] Modify details
---
TODO/anatomy-of-a-function-call-in-go.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/TODO/anatomy-of-a-function-call-in-go.md b/TODO/anatomy-of-a-function-call-in-go.md
index b4baa299cb1..f6141663c05 100644
--- a/TODO/anatomy-of-a-function-call-in-go.md
+++ b/TODO/anatomy-of-a-function-call-in-go.md
@@ -145,7 +145,7 @@ SP+0x08: the old value of BP
SP+0x0: the local variable b
```
-如果你觉得我们对于 SP+0x10 没有任何说明,所以不知道这是干什么用的。我可以告诉你,这是存储返回地址的地方。这是为了让 `RET` 指令知道返回到哪里去。
+如果你觉得文章中没有提到 SP+0x10,所以不知道这是干什么用的。我可以告诉你,这是存储返回地址的地方。这是为了让 `RET` 指令知道返回到哪里去。
这篇文章已经足够了。 希望如果以前你不知道这些东西如何工作,但是现在你觉得你已经有了一些了解,或者如果你被汇编吓倒了,那么它可能不那么清晰。 如果你想了解有关汇编的更多信息,请在评论中告诉我,我会考虑在之后的文章中写出来。
From 96b15b70ae9c88af6f594c11b3c80a2454821c49 Mon Sep 17 00:00:00 2001
From: zhuzi
Date: Sun, 2 Apr 2017 02:02:36 +0800
Subject: [PATCH 012/638] translation first half
---
TODO/beyond-browser-web-desktop-apps.md | 222 +++++++++++++++++-------
1 file changed, 161 insertions(+), 61 deletions(-)
diff --git a/TODO/beyond-browser-web-desktop-apps.md b/TODO/beyond-browser-web-desktop-apps.md
index 57d1a9da13e..a0dfb366c18 100644
--- a/TODO/beyond-browser-web-desktop-apps.md
+++ b/TODO/beyond-browser-web-desktop-apps.md
@@ -1,55 +1,83 @@
> * 原文地址:[Beyond The Browser: From Web Apps To Desktop Apps](https://www.smashingmagazine.com/2017/03/beyond-browser-web-desktop-apps/)
> * 原文作者:[Adam Lynch](https://www.smashingmagazine.com/author/adamlynch/)
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
-> * 译者:
+> * 译者: [bambooom](https://github.com/bambooom)
> * 校对者:
-## Beyond The Browser: From Web Apps To Desktop Apps
+> ## Beyond The Browser: From Web Apps To Desktop Apps
-I started out as a web developer, and that’s now one part of what I do as a full-stack developer, but never had I imagined I’d create things for the desktop. I love the web. I love how altruistic our community is, how it embraces open-source, testing and pushing the envelope. I love discovering beautiful websites and powerful apps. When I was first tasked with creating a desktop app, I was apprehensive and intimidated. It seemed like it would be difficult, or at least… different.
+## 超越浏览器:从 web 应用到桌面应用
-It’s not an attractive prospect, right? Would you have to learn a new language or three? Imagine an archaic, alien workflow, with ancient tooling, and none of those things you love about the web. How would your career be affected?
+> I started out as a web developer, and that’s now one part of what I do as a full-stack developer, but never had I imagined I’d create things for the desktop. I love the web. I love how altruistic our community is, how it embraces open-source, testing and pushing the envelope. I love discovering beautiful websites and powerful apps. When I was first tasked with creating a desktop app, I was apprehensive and intimidated. It seemed like it would be difficult, or at least… different.
-OK, take a breath. The reality is that, as a web developer, not only do you already possess all of the skills to make great modern desktop apps, but thanks to powerful new APIs at your disposal, the desktop is actually where your skills can be leveraged the most.
+一开始我是个 web 开发者,现在我是个全栈开发者,但从未想过在桌面上有所作为。我喜欢 web,我热爱这个无私的社区,热爱它对于开源的友好,测试并推向更远的地方?我喜欢发现好看的网站和强大的应用。当我被指派做桌面应用的任务的时候,我f非常忧虑和害怕,因为那看起来很难,或者至少非常不同。
-In this article, we’ll look at the development of desktop applications using [NW.js](http://nwjs.io/) and [Electron](http://electron.atom.io/), the ups and downs of building one and living with one, using one code base for the desktop and the web, and more.
+> It’s not an attractive prospect, right? Would you have to learn a new language or three? Imagine an archaic, alien workflow, with ancient tooling, and none of those things you love about the web. How would your career be affected?
-#### Further Reading on SmashingMag:
+这并不吸引人,对吧?你需要学一门新的语言,甚至三种?想象一下过时的工作流,古旧的工具,没有任何你喜欢的有关 web 的一切。你的职业会怎样被影响呢?
-- [Pixel-Perfect Specifications Without The Headaches](https://www.smashingmagazine.com/2016/08/pixel-perfect-specifications-without-the-headaches/)
-- [Building A First-Class App That Leverages Your Website](https://www.smashingmagazine.com/2016/02/building-first-class-app-leverages-website-case-study/)
-- [Mobile Considerations in UX Design: “Web or Native?”](https://www.smashingmagazine.com/2012/06/mobile-considerations-in-user-experience-design-web-or-native/)
-- [A Beginner’s Guide To Progressive Web Apps](https://www.smashingmagazine.com/2016/08/a-beginners-guide-to-progressive-web-apps/)
+> OK, take a breath. The reality is that, as a web developer, not only do you already possess all of the skills to make great modern desktop apps, but thanks to powerful new APIs at your disposal, the desktop is actually where your skills can be leveraged the most.
-### Why?
+别慌,深呼吸,现实情况是,作为 web 开发者,你已经拥有一切开发现代桌面应用所需的一切技能,甚至感谢新的强大的 API,你可以在桌面应用中发挥你最大的潜能。
-First of all, why would anyone create a desktop app? Any existing web app (as opposed to a website, if you believe in the distinction) is probably suited to becoming a desktop app. You could build a desktop app around any web app that would benefit from integration in the user’s system; think native notifications, launching on startup, interacting with files, etc. Some users simply prefer having certain apps there permanently on their machine, accessible whether they have a connection or not.
+> In this article, we’ll look at the development of desktop applications using [NW.js](http://nwjs.io/) and [Electron](http://electron.atom.io/), the ups and downs of building one and living with one, using one code base for the desktop and the web, and more.
-Maybe you’ve an idea that would only work as a desktop app; some things simply aren’t possible with a web app (at least yet, but more about that in a little bit). You could create a self-contained utility app for internal company use, without requiring anyone to install anything other than your app (because Node.js in built-in). Maybe you’ve an idea for the Mac App Store. Maybe it would simply be a fun side project.
+本文将会介绍使用 [NW.js](http://nwjs.io/) 和 [Electron](https://electron.atom.io/) 开发桌面应用,它们的优劣,使用同一套基准代码给桌面、web,甚至更多。
-It’s hard to sum up why you should consider creating a desktop app because there are so many kinds of apps you could create. It really depends on what you’d like to achieve, how advantageous you find the additional APIs, and how much offline usage would enhance the experience for your users. For my team, it was a no-brainer because we were building a [chat application](https://teamwork.com/chat). On the other hand, a connection-dependent desktop app that doesn’t really have any desktop integration should be a web app and a web app alone. It wouldn’t be fair to expect a user to download your app (which includes a browser of its own and Node.js) when they wouldn’t get any more value from it than from visiting a URL of yours in their favorite browser.
+> ### Why?
+### 为什么?
-Instead of describing the desktop app you personally should build and why, I’m hoping to spark an idea or at least spark your interest in this article. Read on to see just how easy it is to create powerful desktop apps using web technology and what that can afford you over (or alongside of) creating a web app.
+> First of all, why would anyone create a desktop app? Any existing web app (as opposed to a website, if you believe in the distinction) is probably suited to becoming a desktop app. You could build a desktop app around any web app that would benefit from integration in the user’s system; think native notifications, launching on startup, interacting with files, etc. Some users simply prefer having certain apps there permanently on their machine, accessible whether they have a connection or not.
+
+首先,为什么会有人开发桌面应用?任何现有的 web 应用(不同于网站,如果你认为它们是不同的)都可能适合变成一个桌面应用。你可以为任何可以受益于与用户系统整合的 web 应用制作桌面应用;例如本地通知,开机启动,与文件的交互等。有些用户单纯更喜欢在自己的电脑中永久拥有一些 app,无论是否联网都可以使用。
+
+> Maybe you’ve an idea that would only work as a desktop app; some things simply aren’t possible with a web app (at least yet, but more about that in a little bit). You could create a self-contained utility app for internal company use, without requiring anyone to install anything other than your app (because Node.js in built-in). Maybe you’ve an idea for the Mac App Store. Maybe it would simply be a fun side project.
+
+也许你有个想法,但只能在桌面应用上有意义,有些事情只是在 web 应用中不可能(至少是这样,但也可能更多一点(译注:没太懂这一句))。你可能想要创建一个独立的多功能应用,只给公司内部使用,除了你的 app 不需要安装其他东西(因为内置 Node.js )。也许你有个有关 Mac 应用商店的想法,也许只是你的一个个人兴趣的小项目。
+
+> It’s hard to sum up why you should consider creating a desktop app because there are so many kinds of apps you could create. It really depends on what you’d like to achieve, how advantageous you find the additional APIs, and how much offline usage would enhance the experience for your users. For my team, it was a no-brainer because we were building a [chat application](https://teamwork.com/chat). On the other hand, a connection-dependent desktop app that doesn’t really have any desktop integration should be a web app and a web app alone. It wouldn’t be fair to expect a user to download your app (which includes a browser of its own and Node.js) when they wouldn’t get any more value from it than from visiting a URL of yours in their favorite browser.
+
+很难概括你应该考虑开发桌面应用的原因,因为真的有很多很多东西你可以做。这非常取决于你想要达到什么,API 是否足够有利于开发,离线使用将多大程度上改进用户体验。在我的团队,这些都是毋庸置疑的,因为我们在开发一个[即时通讯应用](https://teamwork.com/chat)。另一方面来说,一个依赖于网络而没有任何与系统整合的桌面应用应该是一个 web 应用,并且仅仅是一个 web 应用。当用户并不能从桌面应用中获得比在浏览器中访问一个网址更多的价值的时候,期待用户下载你的应用(其中自带浏览器以及 Node.js)是不公平的。
+
+> Instead of describing the desktop app you personally should build and why, I’m hoping to spark an idea or at least spark your interest in this article. Read on to see just how easy it is to create powerful desktop apps using web technology and what that can afford you over (or alongside of) creating a web app.
+
+比起描述你个人应该建造的桌面应用以及为什么建造,我更希望的是激发一个想法,或者只是激发你对这篇文章的兴趣。继续往下读来看看用 web 技术构造一个强大的桌面应用是多么简单,以及它将给予你的超过(或者相同)创造一个 web 应用。
### NW.js
-Desktop applications have been around a long time but you don’t have all day, so let’s skip some history and begin in Shanghai, 2011. Roger Wang, of Intel’s Open Source Technology Center, created node-webkit; a proof-of-concept Node.js module that allowed the user to spawn a WebKit browser window and use Node.js modules within `
+```
+
+As you may realize, this URL will make the browser run the injected script and send the user’s cookies, potentially including confidential session cookies, to evil.com!
+
+To help protect users against reflective XSS attacks, some browsers have implemented protection mechanisms. These mechanisms try to identify these attacks by looking for matching code patterns in the HTTP request and response. Internet Explorer was the first browser to introduce such a mechanism with its XSS filter, introduced in Internet Explorer 8 back in 2008, and WebKit later introduced XSS Auditor, available today in Chrome and Safari. (Firefox has no similar mechanism built in, but users can use add-ons to gain this functionality.) These various protection mechanisms are not perfect: They may fail to detect a real XSS attack (a false negative), and in other cases may block legitimate code (a false positive). Due to the latter, browsers allow users to disable the XSS filter via the settings. Unfortunately, this is typically a global setting, which turns off this security feature completely for all web apps loaded by the browser.
+
+Luckily, there is a way for a web app to override this configuration and ensure that the XSS filter is turned on for the web app being loaded by the browser. This is done via the `X-XSS-Protection` header. This header, supported by Internet Explorer (from version 8), Edge, Chrome and Safari, instructs the browser to turn on or off the browser’s built-in protection mechanism and to override the browser’s local configuration.
+
+`X-XSS-Protection` directives include these:
+
+- `1` or `0`
+
+This enables or disables the filter.
+- `mode=block`
+
+This instructs the browser to prevent the entire page from rendering when an XSS attack is detected.
+
+I recommend always turning on the XSS filter, as well as block mode, to maximize user protection. Such a response header looks like this:
+
+```
+X-XSS-Protection: 1; mode=block
+```
+
+Here’s how you would configure this response header in Node.js:
+
+```
+functionrequestHandler(req, res){
+ res.setHeader('X-XSS-Protection','1;mode=block');}
+```
+
+### Controlling Framing ###
+
+An iframe (or HTML inline frame element, if you want to be more formal) is a DOM element that allows a web app to be nested within a parent web app. This powerful element enables some important web use cases, such as embedding third-party content into web apps, but it also has significant drawbacks, such as not being SEO-friendly and not playing nice with browser navigation — the list goes on.
+
+One of the caveats of iframes is that it makes clickjacking easier. Clickjacking is an attack that tricks the user into clicking something different than what they think they’re clicking. To understand a simple implementation of clickjacking, consider the HTML markup below, which tries to trick the user into buying a toaster when they think they are clicking to win a prize!
+
+```
+
+
+
+
+
+
+```
+
+Clickjacking has many malicious applications, such as tricking the user into confirming a Facebook like, purchasing an item online and even submitting confidential information. Malicious web apps can leverage iframes for clickjacking by embedding a legitimate web app inside their malicious web app, rendering the iframe invisible with the `opacity: 0` CSS rule, and placing the iframe’s click target directly on top of an innocent-looking button rendered by the malicious web app. A user who clicks the innocent-looking button will trigger a click on the embedded web app — without at all knowing the effect of their click.
+
+An effective way to block this attack is by restricting your web app from being framed. `X-Frame-Options`, specified in [RFC 7034](https://www.ietf.org/rfc/rfc7034.txt), is designed to do exactly that! This header instructs the browser to apply limitations on whether your web app can be embedded within another web page, thus blocking a malicious web page from tricking users into invoking various transactions on your web app. You can either block framing completely using the `DENY` directive, whitelist specific domains using the `ALLOW-FROM` directive, or whitelist only the web app’s origin using the `SAMEORIGIN` directive.
+
+My recommendation is to use the `SAMEORIGIN` directive, which enables iframes to be leveraged for apps on the same domain — which may be useful at times — and which maintains security. This recommended header looks like this:
+
+```
+X-Frame-Options: SAMEORIGIN
+```
+
+Here’s an example of a configuration of this header to enable framing on the same origin in Node.js:
+
+```
+functionrequestHandler(req, res){
+ res.setHeader('X-Frame-Options','SAMEORIGIN');}
+```
+
+### Explicitly Whitelisting Sources ###
+
+As we’ve noted earlier, you can add in-depth security to your web app by enabling the browser’s XSS filter. However, note that this mechanism is limited, is not supported by all browsers (Firefox, for instance, does not have an XSS filter) and relies on pattern-matching techniques that can be tricked.
+
+Another layer of in-depth protection against XSS and other attacks can be achieved by explicitly whitelisting trusted sources and operations — which is what Content Security Policy (CSP) enables web app developers to do.
+
+CSP is a [W3C specification](https://www.w3.org/TR/2016/WD-CSP3-20160901/) that defines a powerful browser-based security mechanism, enabling granular control over resource-loading and script execution in a web app. With CSP, you can whitelist specific domains for operations such as script-loading, AJAX calls, image-loading and style sheet-loading. You can enable or disable inline scripts or dynamic scripts (the notorious `eval`) and control framing by whitelisting specific domains for framing. Another cool feature of CSP is that it allows you to configure a real-time reporting target, so that you can monitor your app in real time for CSP blocking operations.
+
+This explicit whitelisting of resource loading and execution provides in-depth security that in many cases will fend off attacks. For example, by using CSP to disallow inline scripts, you can fend off many of the reflective XSS attack variants that rely on injecting inline scripts into the DOM.
+
+CSP is a relatively complex header, with a lot of directives, and I won’t go into the details of the various directives. HTML5 Rocks has a [great tutorial](https://www.html5rocks.com/en/tutorials/security/content-security-policy/) that provides an overview of CSP, and I highly recommend reading it and learning how to use CSP in your web app.
+
+Here’s a simple example of a CSP configuration to allow script-loading from the app’s origin only and to block dynamic script execution (`eval`) and inline scripts (as usual, on Node.js):
+
+```
+functionrequestHandler(req, res){
+ res.setHeader('Content-Security-Policy',"script-src 'self'");}
+```
+
+### Preventing Content-Type Sniffing ###
+
+In an effort to make the user experience as seamless as possible, many browsers have implemented a feature called content-type sniffing, or MIME sniffing. This feature enables the browser to detect the type of a resource provided as part of an HTTP response by “sniffing” the actual resource bits, regardless of the resource type declared through the `Content-Type` response header. While this feature is indeed useful in some cases, it introduces a vulnerability and an attack vector known as a MIME confusion attack. A MIME-sniffing vulnerability enables an attacker to inject a malicious resource, such as a malicious executable script, masquerading as an innocent resource, such as an image. With MIME sniffing, the browser will ignore the declared image content type, and instead of rendering an image will execute the malicious script.
+
+Luckily, the `X-Content-Type-Options` response header mitigates this vulnerability! This header, introduced in Internet Explorer 8 back in 2008 and currently supported by most major browsers (Safari is the only major browser not to support it), instructs the browser not to use sniffing when handling fetched resources. Because `X-Content-Type-Options` was only formally specified as part of the [“Fetch” specification](https://fetch.spec.whatwg.org/#x-content-type-options-header), the actual implementation varies across browsers; some (Internet Explorer and Edge) completely avoid MIME sniffing, whereas others (Firefox) still MIME sniff but rather block executable resources (JavaScript and CSS) when an inconsistency between declared and actual types is detected. The latter is in line with the latest Fetch specification.
+
+`X-Content-Type-Options` is a simple response header, with only one directive: `nosniff`. This header looks like this: `X-Content-Type-Options: nosniff`. Here’s an example of a configuration of the header:
+
+```
+functionrequestHandler(req, res){
+ res.setHeader('X-Content-Type-Options','nosniff');}
+```
+
+### Summary ###
+
+In this article, we have seen how to leverage HTTP headers to reinforce the security of your web app, to fend off attacks and to mitigate vulnerabilities.
+
+#### Takeaways ####
+
+- Disable caching for confidential information using the `Cache-Control` header.
+- Enforce HTTPS using the `Strict-Transport-Security` header, and add your domain to Chrome’s preload list.
+- Make your web app more robust against XSS by leveraging the `X-XSS-Protection` header.
+- Block clickjacking using the `X-Frame-Options` header.
+- Leverage `Content-Security-Policy` to whitelist specific sources and endpoints.
+- Prevent MIME-sniffing attacks using the `X-Content-Type-Options` header.
+
+Remember that for the web to be truly awesome and engaging, it has to be secure. Leverage HTTP headers to build a more secure web!
+
+
+
+(**Disclaimer:** The content of this post is my own and doesn’t represent my past or current employers in any way whatsoever.)
+
+*Front page image credits: [Pexels.com](https://www.pexels.com/photo/coffee-writing-computer-blogging-34600/).*
+
+
+---
+
+> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[React](https://github.com/xitu/gold-miner#react)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计) 等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)。
From 70b8b484b9c34c825b0ca589e98fd852646ecb93 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=A0=B9=E5=8F=B7=E4=B8=89?=
Date: Fri, 7 Apr 2017 20:54:36 +0800
Subject: [PATCH 058/638] Create webpack-and-rollup-the-same-but-different.md
---
...bpack-and-rollup-the-same-but-different.md | 58 +++++++++++++++++++
1 file changed, 58 insertions(+)
create mode 100644 TODO/webpack-and-rollup-the-same-but-different.md
diff --git a/TODO/webpack-and-rollup-the-same-but-different.md b/TODO/webpack-and-rollup-the-same-but-different.md
new file mode 100644
index 00000000000..7bc3f470f12
--- /dev/null
+++ b/TODO/webpack-and-rollup-the-same-but-different.md
@@ -0,0 +1,58 @@
+> * 原文地址:[Webpack and Rollup: the same but different](https://medium.com/webpack/webpack-and-rollup-the-same-but-different-a41ad427058c)
+> * 原文作者:[Rich Harris](https://medium.com/@Rich_Harris?source=post_header_lockup)
+> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
+> * 译者:
+> * 校对者:
+
+# Webpack and Rollup: the same but different #
+
+![](https://cdn-images-1.medium.com/max/1000/1*rtjClMZ8sq3cLFT9Aq8Xyg.png)
+
+This week, Facebook merged a [monster pull request](https://github.com/facebook/react/pull/9327) into React that replaced its existing build process with one based on [Rollup](https://rollupjs.org/) , [prompting](https://twitter.com/stanlemon/status/849366789825994752) [several](https://twitter.com/MrMohtas/status/849362334988595201) [people](https://twitter.com/kyleholzinger/status/849683292760797184) to ask ‘why did you choose Rollup over webpack’?
+
+Which is a completely reasonable question. [Webpack](https://webpack.js.org/) is one of the modern JavaScript community’s greatest success stories, with millions of downloads every month powering tens of thousands of websites and applications. It has a large ecosystem, dozens of contributors, and — unusually for a community open source project — [meaningful financial support](https://opencollective.com/webpack) .
+
+By comparison, Rollup is a minnow. But React isn’t alone — Vue, Ember, Preact, D3, Three.js, Moment, and dozens of other well-known libraries also use Rollup. So what’s going on? Why can’t we have just one JavaScript module bundler that everyone agrees on?
+
+### A tale of two bundlers ###
+
+webpack was started in 2012 by [Tobias Koppers](https://medium.com/@sokra) to solve a hard problem that existing tools didn’t address: building complex single-page applications (SPAs). Two features in particular changed everything:
+
+1. **Code-splitting** makes it possible to break your app apart into manageable chunks that can be loaded on-demand, meaning your users get an interactive site much faster than if they had to wait for the whole application to download and parse. You *can* do this manually, but, well… good luck.
+2. **Static assets** such as images and CSS can be imported into your app and treated as just another node in the dependency graph. No more carefully placing your files in the right folders and hacked-together scripts for adding hashes to file URLs — webpack can take care of it for you.
+
+Rollup was created for a different reason: to build flat distributables of JavaScript libraries as efficiently as possible, taking advantage of the ingenious design of ES2015 modules. Other module bundlers — webpack included — work by wrapping each module in a function, putting them in a bundle with a browser-friendly implementation of `require`, and evaluating them one-by-one. That’s great if you need things like on-demand loading, but otherwise it’s a bit of a waste, and it [gets worse if you have lots of modules](https://nolanlawson.com/2016/08/15/the-cost-of-small-modules/).
+
+ES2015 modules enable a different approach, which Rollup uses. All your code is put in the same place and evaluates in one go, resulting in leaner, simpler code that starts up faster. You can [see it for yourself with the Rollup REPL](https://rollupjs.org/repl).
+
+But there’s a trade-off: code-splitting is a much hairier problem, and at the time of writing Rollup doesn’t support it. Similarly, Rollup doesn’t do hot module replacement (HMR). And perhaps the biggest pain point for people coming to Rollup — while it handles most CommonJS files (via a [plugin](https://github.com/rollup/rollup-plugin-commonjs) ), some things just don’t translate to ES2015, whereas webpack handles everything you throw at it with aplomb.
+
+### So which should I use? ###
+
+By now, hopefully it’s clear why both tools coexist and support each other — they serve different purposes. The tl;dr is this:
+
+> Use webpack for apps, and Rollup for libraries
+
+That’s not a hard and fast rule — lots of sites and apps are built with Rollup, and lots of libraries are built with webpack. But it’s a good rule of thumb.
+
+If you need code-splitting, or you have lots of static assets, or you’re building something with lots of CommonJS dependencies, Webpack is a better choice. If your codebase is ES2015 modules and you’re making something to be used by other people, you probably want Rollup.
+
+### Package authors: use `pkg.module!` ###
+
+For a long time, using JavaScript libraries was a bit of a crapshoot, because you and the library author effectively had to agree on a module system. If you were using Browserify but she preferred AMD, you would have to duct tape things together before you could actually build anything. The [Universal Module Definition](https://github.com/umdjs/umd) (UMD) format *sort of* fixed that, but because it wasn’t enforced anywhere you never knew quite what you were going to get.
+
+ES2015 changes all that, because `import` and `export` are part of the language. In the future, there’ll be no ambiguity, and things will work a lot more seamlessly. Unfortunately, because browsers (mostly) and Node don’t yet support `import` and `export`, we still need to ship UMD files (or CommonJS, if you’re building something Node-only).
+
+By adding a `"module": "dist/my-library.es.js"` entry to your library’s package.json file (aka `pkg.module`), it’s possible to serve UMD and ES2015 at the same time, right now. **That’s important because Webpack and Rollup can both use** `pkg.module` **to generate the most efficient code possible** — in some cases, they can even both [tree-shake](https://webpack.js.org/guides/tree-shaking/) unused parts of your library away.
+
+*Learn more about`pkg.module` on the [*Rollup wiki*](https://github.com/rollup/rollup/wiki/pkg.module) .*
+
+Hopefully this article makes the relationship between the two projects a bit clearer. If you still have questions, find us on Twitter at [rich_harris](https://twitter.com/rich_harris)/[rollupjs](https://twitter.com/rollupjs) and [thelarkinn](https://twitter.com/thelarkinn) . Happy bundling!
+
+Our thanks to Rich Harris for writing this article. We believe that collaboration in open source is incredibly vital to ensure we push technology and the web forward together.
+
+No time to help contribute? Want to give back in other ways? Become a Backer or Sponsor to webpack by [donating to our open collective](https://opencollective.com/webpack). Open Collective not only helps support the Core Team, but also supports contributors who have spent significant time improving our organization on their free time! ❤
+
+---
+
+> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[React](https://github.com/xitu/gold-miner#react)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计) 等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)。
From 0f630d62fc21721b39491c8886c93e1f933480ce Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=A0=B9=E5=8F=B7=E4=B8=89?=
Date: Fri, 7 Apr 2017 21:25:48 +0800
Subject: [PATCH 059/638] Create
the-time-i-had-to-crack-my-own-reddit-password.md
---
...e-i-had-to-crack-my-own-reddit-password.md | 564 ++++++++++++++++++
1 file changed, 564 insertions(+)
create mode 100644 TODO/the-time-i-had-to-crack-my-own-reddit-password.md
diff --git a/TODO/the-time-i-had-to-crack-my-own-reddit-password.md b/TODO/the-time-i-had-to-crack-my-own-reddit-password.md
new file mode 100644
index 00000000000..a7cd6da89cd
--- /dev/null
+++ b/TODO/the-time-i-had-to-crack-my-own-reddit-password.md
@@ -0,0 +1,564 @@
+> * 原文地址:[That time I had to crack my own Reddit password](https://medium.freecodecamp.com/the-time-i-had-to-crack-my-own-reddit-password-a6077c0a13b4)
+> * 原文作者:[Haseeb Qureshi](https://medium.freecodecamp.com/@hosseeb?source=post_header_lockup)
+> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
+> * 译者:
+> * 校对者:
+
+# That time I had to crack my own Reddit password #
+
+
+
+Hack the planet, everybody.
+
+I have no self-control.
+
+Luckily, I know this about myself. This allows me to consciously engineer my life so that despite having the emotional maturity of a heroin-addicted lab rat, I’m occasionally able to get things done.
+
+![](https://media.giphy.com/media/gOH54eiriYIwM/giphy.gif)
+
+
+Mm, a waste of time!
+
+I waste a lot of time on Reddit. If I want to procrastinate on something, I’ll often open a new tab and dive down a Reddit-hole. But sometimes you need to turn on the blinders and dial down distractions. 2015 was one of these times — I was singularly focused on improving as a programmer, and Redditing was becoming a liability.
+
+I needed an abstinence plan.
+
+So it occurred to me: how about I lock myself out of my account?
+
+**Here’s what I did:**
+
+
+
+I set a random password on my account. Then I asked a friend to e-mail me this password on a certain date. With that, I’d have a foolproof way to lock myself out of Reddit. (Also changed the e-mail for password recovery to cover all the bases.)
+
+This should have worked.
+
+Unfortunately it turns out, friends are very susceptible to social engineering. The technical terminology for this is that they are “nice to you” and will give you back your password if you “beg them.”
+
+![](https://media.giphy.com/media/uB6rsQFg5yPzW/giphy.gif)
+
+Don’t look at me like that.
+
+After a few rounds of this failure mode, I needed a more robust solution. A little Google searching, and I came across this:
+
+
+
+
+
+Looks legit.
+
+Perfect — an automated, friend-less solution! (I’d alienated most of them by now, so that was a big selling point.)
+
+A bit sketchy looking, but hey, any port in a storm.
+
+
+
+For a while I set this up this routine — during the week I’d e-mail myself my password, on the weekends I’d receive the password, load up on internet junk food, and then lock myself out again once the week began. It worked quite well from what I remember.
+
+Eventually I got so busy with programming stuff, I completely forgot about it.
+
+### **Cut to two years later.** ###
+
+I’m now gainfully employed at Airbnb. And Airbnb, it so happens, has a large test suite. This means waiting, and waiting of course means internet rabbit holes.
+
+I decide to scrounge up my old account and find my Reddit password.
+
+
+
+Oh no.That’s not good.
+
+I didn’t remember doing this, but I must have gotten so fed up with myself that** I locked myself out until 2018**. I also set it to “hide,” so I couldn’t view the contents of the e-mail until it’s sent.
+
+What do I do? Do I just have to create a new Reddit account and start from scratch? But that’s *so much work.*
+
+I could write in to LetterMeLater and explain that I didn’t mean to do this. But they would probably take a while to get back to me. We’ve already established I’m wildly impatient. Plus this site doesn’t look like it has a support team. Not to mention it would be an embarrassing e-mail exchange. I started brainstorming elaborate explanations involving dead relatives about why I needed access to the e-mail…
+
+All of my options were messy. I was walking home that night from the office pondering my predicament, when suddenly it hit me.
+
+**The search bar.**
+
+I pulled up the app on my mobile phone and tried it:
+
+
+
+Hmm.
+
+Okay. So it’s indexing the subject for sure. What about the body?
+
+
+
+I try a few letters, and voila. It’s definitely got the body indexed. Remember: the body consisted entirely of my password.
+
+*Essentially, I’ve been given an interface to perform substring queries.* By entering in a string into the search bar, the search results will confirm whether my password contains this substring.
+
+**We’re in business.**
+
+I hurry into my apartment, drop my bag, and pull out my laptop.
+
+Algorithms problem: you are given a function `substring?(str)`, which returns true or false depending on whether a password contains any given substring. *Given this function, write an algorithm that can deduce the hidden password.*
+
+### The Algorithm ###
+
+So let’s think about this. A few things I know about my password: I know it was a long string with some random characters, probably something along the lines of `asgoihej2409g`. I *probably* didn’t include any upper-case characters (and Reddit doesn’t enforce that as a password constraint) so let’s assume for now that I didn’t — in case I did, we can just expand the search space later if the initial algorithm fails.
+
+We also have a subject line as part of the string we’re querying. And we know the subject is “password”.
+
+
+
+Let’s pretend the body is 6 characters long. So we’ve got six slots of characters, some of which may appear in the subject line, some of which certainly don’t. So if we take all of the characters that aren’t in the subject and try searching for each of them, we know for sure we’ll hit a unique letter that’s in the password. Think like a game of Wheel of Fortune.
+
+![](https://cdn-images-1.medium.com/max/800/1*LOzh--_Ujutrh_OKhjfNaw.png)
+
+We keep trying letters one by one until we hit a match for something that’s not in our subject line. Say we hit it.
+
+
+
+Once I’ve found my first letter, I don’t actually know where in this string I am. But I know I can start building out a bigger substring by appending different characters to the end of this until I hit another substring match.
+
+We’ll potentially have to iterate through every character in our alphabet to find it. Any of those characters could be correct, so on average it’ll hit somewhere around the middle, so given an alphabet of size `A`, it should average out to `A/2` guesses per letter (let’s assume the subject is small and there are no repeating patterns of 2+ characters).
+
+
+
+I’ll keep building this substring until it eventually hits the end and no characters can extend it further.
+
+
+
+But that’s not enough — most likely, there will be a prefix to the string that I missed, because I started in a random place. Easy enough: all I have to do is now repeat the process, except going backwards.
+
+
+
+Once the process terminates, I should be able to reconstruct the password. In total, I’ll need to figure out`L` characters(where `L` is the length), and need to expend on average `A/2` guesses per character (where `A` is the alphabet size), so total guesses = `A/2 * L`.
+
+To be precise, I also have to add another `2A` to the number of guesses for ascertaining that the string has terminated on each end. So the total is `A/2 * L + 2A`, which we can factor as `A(L/2 + 2)`.
+
+Let’s assume we have 20 characters in our password, and an alphabet consisting of `a-z` (26) and `0–9` (10), so a total alphabet size of 36. So we’re looking at an average of `36 * (20/2 + 2) = 36 * 12 = 432` iterations.
+
+Damn.
+
+This is actually doable.
+
+![](https://media.giphy.com/media/119cVU19ICcAKc/giphy.gif)
+
+Programming IRL
+
+### The Implementation ###
+
+First things first: I need to write a client that can programmatically query the search box. This will serve as my substring oracle. Obviously this site has no API, so I’ll need to scrape the website directly.
+
+Looks like the URL format for searching is just a simple query string, `www.lettermelater.com/account.php?**qe=#{query_here}**`. That’s easy enough.
+
+Let’s start writing this script. I’m going to use the Faraday gem for making web requests, since it has a simple interface that I know well.
+
+I’ll start by making an API class.
+
+```
+require 'faraday'
+
+class Api
+ BASE_URL = 'http://www.lettermelater.com/account.php'
+
+ def self.get(query)
+ Faraday.get(BASE_URL, qe: query)
+ end
+end
+```
+
+Of course, we don’t expect this to work yet, as our script won’t be authenticated into any account. As we can see, the response returns a 302 redirect with an error message provided in the cookie.
+
+```
+[10] pry(main)> Api.get(“foo”)
+=> #”Tue, 04 Apr 2017 15:35:07 GMT”,
+“server”=>”Apache”,
+“x-powered-by”=>”PHP/5.2.17",
+“set-cookie”=>”msg_error=You+must+be+signed+in+to+see+this+page.”,
+“location”=>”.?pg=account.php”,
+“content-length”=>”0",
+“connection”=>”close”,
+“content-type”=>”text/html; charset=utf-8"},
+status=302>
+```
+
+So how do we sign in? We need to send in our [cookies](http://stackoverflow.com/questions/17769011/how-does-cookie-based-authentication-work) in the header, of course. Using Chrome inspector we can trivially grab them.
+
+
+
+(Not going to show my real cookie here, obviously. Interestingly, looks like it’s storing `user_id` client-side which is always a great sign.)
+
+Through process of elimination, I realize that it needs both `code` and `user_id` to authenticate me… sigh.
+
+So I add these to the script. (This is a fake cookie, just for illustration.)
+
+```
+
+require 'faraday'
+
+class Api
+ BASE_URL = 'http://www.lettermelater.com/account.php'
+ COOKIE = 'code=13fa1fa011169ab29007fcad17b2ae; user_id=279789'
+
+ def self.get(query)
+ Faraday.get(BASE_URL, { qe: query }, Cookie: COOKIE).body
+ end
+end
+```
+
+```
+[29] pry(main)> Api.get(“foo”)
+=> “\n\n\n\n\t\n\t\n\t\n\tLetterMeLater.com — Account Information…
+
+[30] pry(main)> _.include?(“Haseeb”)
+=> true
+```
+
+It’s got my name in there, so we’re definitely logged in!
+
+We’ve got the scraping down, now we just have to parse the result. Luckily, this pretty easy — we know it’s a hit if the e-mail result shows up on the page, so we just need to look for any string that’s unique when the result is present. The string “password” appears nowhere else, so that will do just nicely.
+
+
+
+```
+def self.include?(substring)
+ get(substring).include?(‘password’)
+end
+```
+
+That’s all we need for our API class. We can now do substring queries entirely in Ruby.
+
+```
+[31] pry(main)> Api.include?('password')
+=> true
+[32] pry(main)> Api.include?('f')
+=> false
+[33] pry(main)> Api.include?('g')
+=> true
+```
+
+Now that we know that works, let’s stub out the API while we develop our algorithm. Making HTTP requests is going to be really slow and we might trigger some rate-limiting as we’re experimenting. If we assume our API is correct, once we get the rest of the algorithm working, everything should just work once we swap the real API back in.
+
+So here’s the stubbed API, with a random secret string:
+
+```
+class ApiStub
+ SECRET_PASSWORD = 'g420hpfjpefoj490rjgsd'
+
+ def self.include?(substring)
+ SECRET_PASSWORD.include?(substring)
+ end
+end
+```
+
+We’ll inject the stubbed API into the class while we’re testing. Then for the final run, we’ll use the real API to query for the real password.
+
+So let’s get started with this class. From a high level, recalling my algorithm diagram, it goes in three steps:
+
+1. First, find the first letter that’s not in the subject but exists in the password. This is our starting off point.
+2. Build those letters forward until we fall off the end of the string.
+3. Build that substring backwards until we hit the beginning of the string.
+
+Then we’re done!
+
+Let’s start with initialization. We’ll inject the API, and other than that we just need to initialize the current password chunk to be an empty string.
+
+```
+class PasswordCracker
+ def initialize(api)
+ @api = api
+ @password = ''
+ end
+end
+```
+
+Now let’s write three methods, following the steps we outlined.
+
+```
+ def crack!
+ find_starting_letter!
+ build_forward!
+ build_backward!
+ @password
+ end
+```
+
+
+Perfect. Now the rest of the implementation can take place in private methods.
+
+For finding the first letter, we need to iterate over each character in the alphabet that’s not contained in the subject. To construct this alphabet, we’re going to use `a-z` and `0–9`. Ruby allows us to do this pretty easily with ranges:
+
+```
+ALPHABET = ((‘a’..’z’).to_a + (‘0’..’9').to_a).shuffle
+```
+
+I prefer to shuffle this to remove any bias in the password’s letter distribution. This will make our algorithm query A/2 times on average per character, even if the password is non-randomly distributed.
+
+We also want to set the subject as a constant:
+
+```
+SUBJECT = ‘password’
+```
+
+That’s all the setup we need. Now time to write `find_starting_letter`. This needs to iterate through each candidate letter (in the alphabet but not in the subject) until it finds a match.
+
+```
+ private
+
+ def find_starting_letter!
+ candidate_letters = ALPHABET - SUBJECT.chars
+ @password = candidate_letters.find { |char| @api.include?(char) }
+ end
+```
+
+In testing, looks like this works perfectly:
+
+```
+PasswordCracker.new(ApiStub).send(:find_starting_letter!) # => 'f'
+```
+
+Now for the heavy lifting.
+
+I’m going to do this recursively, because it makes the structure very elegant.
+
+```
+def build_forward!
+ puts "Current password: #{@password}"
+ ALPHABET.each do |char|
+ guess = @password + char
+
+ if @api.include?(guess)
+ @password = guess
+ build_forward!
+ # once I'm done building forward, jump out of all stack frames
+ return
+ end
+ end
+ end
+```
+
+The code is surprisingly straightforward. Let’s see if it works with our stub API.
+
+```
+[63] pry(main)> PasswordCracker.new(ApiStub).crack!
+f
+fj
+fjp
+fjpe
+fjpef
+fjpefo
+fjpefoj
+fjpefoj4
+fjpefoj49
+fjpefoj490
+fjpefoj490r
+fjpefoj490rj
+fjpefoj490rjg
+fjpefoj490rjgs
+fjpefoj490rjgsd
+=> “fjpefoj490rjgsd”
+```
+
+Awesome. We’ve got a suffix, now just to build backward and complete the string. This should look very similar.
+
+```
+def build_backward!
+ puts "Current password: #{@password}"
+ ALPHABET.each do |char|
+ guess = char + @password
+
+ if @api.include?(guess)
+ @password = guess
+ build_backward!
+ return
+ end
+ end
+```
+
+
+In fact, there’s only two lines of difference here: how we construct the `guess`, and the name of the recursive call. There’s an obvious refactoring here, so let’s do it.
+
+```
+def build!(forward:)
+ puts "Current password: #{@password}"
+ ALPHABET.each do |char|
+ guess = forward ? @password + char : char + @password
+
+ if @api.include?(guess)
+ @password = guess
+ build!(forward: forward)
+ return
+ end
+ end
+ end
+```
+
+Now these other calls simply reduce to:
+
+```
+ def build_forward!
+ build!(forward: true)
+ end
+
+ def build_backward!
+ build!(forward: false)
+ end
+```
+
+And let’s see how it works in action:
+
+
+```
+Apps-MacBook:password-recovery haseeb$ ruby letter_me_now.rb
+Current password: 9
+Current password: 90
+Current password: 90r
+Current password: 90rj
+Current password: 90rjg
+Current password: 90rjgs
+Current password: 90rjgsd
+Current password: 90rjgsd
+Current password: 490rjgsd
+Current password: j490rjgsd
+Current password: oj490rjgsd
+Current password: foj490rjgsd
+Current password: efoj490rjgsd
+Current password: pefoj490rjgsd
+Current password: jpefoj490rjgsd
+Current password: fjpefoj490rjgsd
+Current password: pfjpefoj490rjgsd
+Current password: hpfjpefoj490rjgsd
+Current password: 0hpfjpefoj490rjgsd
+Current password: 20hpfjpefoj490rjgsd
+Current password: 420hpfjpefoj490rjgsd
+Current password: g420hpfjpefoj490rjgsd
+g420hpfjpefoj490rjgsd
+```
+
+Beautiful. Now let’s just add some more print statements and a bit of extra logging, and we’ll have our finished `PasswordCracker`.
+
+```
+require 'faraday'
+
+class PasswordCracker
+ ALPHABET = (('a'..'z').to_a + ('0'..'9').to_a).shuffle
+ SUBJECT = 'password'
+
+ def initialize(api)
+ @api = api
+ @password = ''
+ end
+
+ def crack!
+ find_starting_letter!
+ puts "Found first letter: #{@password}"
+ puts "\nBuilding forward!\n"
+ build_forward!
+ puts "\nBuilding backward!\n"
+ build_backward!
+ puts "Done! The result is #{@password}."
+ puts "We found it in #{@api.iterations} iterations"
+ @password
+ end
+
+ private
+
+ def find_starting_letter!
+ candidate_letters = ALPHABET - SUBJECT.chars
+ @password = candidate_letters.find { |char| @api.include?(char) }
+ end
+
+ def build_forward!
+ build!(forward: true)
+ end
+
+ def build_backward!
+ build!(forward: false)
+ end
+
+ def build!(forward:)
+ puts "Current password: #{@password}"
+ ALPHABET.each do |char|
+ guess = forward ? @password + char : char + @password
+
+ if @api.include?(guess)
+ @password = guess
+ build!(forward: forward)
+ return
+ end
+ end
+ end
+end
+
+class Api
+ BASE_URL = 'http://www.lettermelater.com/account.php'
+ COOKIE = 'code=13fa1fa011169ab29007fcad17b2ae; user_id=279789'
+ @iterations = 0
+
+ def self.get(query)
+ @iterations += 1
+ Faraday.get(BASE_URL, { qe: query }, Cookie: COOKIE).body
+ end
+
+ def self.include?(substring)
+ get(substring).include?('password')
+ end
+
+ def self.iterations
+ @iterations
+ end
+end
+
+class ApiStub
+ SECRET_PASSWORD = 'g420hpfjpefoj490rjgsd'
+ @iterations = 0
+
+ def self.include?(substring)
+ @iterations += 1
+ SECRET_PASSWORD.include?(substring)
+ end
+
+ def self.iterations
+ @iterations
+ end
+end
+```
+
+And now… the magic moment. Let’s swap the stub with the real API and see what happens.
+
+### The Moment of Truth ###
+
+Cross your fingers…
+
+`PasswordCracker.new(Api).crack!`
+
+
+
+(Sped up 3x)
+
+Boom. 443 iterations.
+
+Tried it out on Reddit, and login was successful.
+
+Wow.
+
+It… actually worked.
+
+Recall our original formula for the number of iterations: `A(N/2 + 2)`. The true password was 22 characters, so our formula would estimate `36 * (22/2 + 2) = 36 * 13 = 468` iterations. Our real password took 443 iterations, so our estimate was within 5% of the observed runtime.
+
+**Math.**
+
+![](https://media.giphy.com/media/26xBI73gWquCBBCDe/giphy.gif)
+
+tfw wtf ftw
+
+**It works.**
+
+Embarrassing support e-mail averted. Reddit rabbit-holing restored. It’s now confirmed: programming is, indeed, magic.
+
+(The downside is I am now going to have to find a new technique to lock myself out of my accounts.)
+
+And with that, I’m gonna get back to my internet rabbit-holes. Thanks for reading, and give it a like if you enjoyed this!
+
+*—Haseeb*
+---
+
+> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[React](https://github.com/xitu/gold-miner#react)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计) 等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)。
From 8b1ccb184fbd2898c18da673889fa2466202e965 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=A0=B9=E5=8F=B7=E4=B8=89?=
Date: Fri, 7 Apr 2017 21:48:45 +0800
Subject: [PATCH 060/638] Create
creating-usability-with-motion-the-ux-in-motion-manifesto.md
---
...-with-motion-the-ux-in-motion-manifesto.md | 452 ++++++++++++++++++
1 file changed, 452 insertions(+)
create mode 100644 TODO/creating-usability-with-motion-the-ux-in-motion-manifesto.md
diff --git a/TODO/creating-usability-with-motion-the-ux-in-motion-manifesto.md b/TODO/creating-usability-with-motion-the-ux-in-motion-manifesto.md
new file mode 100644
index 00000000000..b7982b9da14
--- /dev/null
+++ b/TODO/creating-usability-with-motion-the-ux-in-motion-manifesto.md
@@ -0,0 +1,452 @@
+> * 原文地址:[Creating Usability with Motion: The UX in Motion Manifesto](https://medium.com/@ux_in_motion/creating-usability-with-motion-the-ux-in-motion-manifesto-a87a4584ddc)
+> * 原文作者:[Issara Willenskomer](https://medium.com/@ux_in_motion?source=post_header_lockup)
+> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
+> * 译者:
+> * 校对者:
+
+
+
+# Creating Usability with Motion: The UX in Motion Manifesto #
+
+The following manifesto represents my answer to the question — “As a UX or UI, designer, how do I know when and where to implement motion to support usability?”
+
+Over the last 5 years, it has been my privilege to coach and mentor UX & UI designers in over 40 countries, and at hundreds of the top brands and design consultancies through my workshops and tutorials on UI Animation.
+
+After over fifteen years studying motion in user interfaces, I have come to the conclusion that there are 12 specific opportunities to support usability in your UX projects using motion.
+
+I call these opportunities ‘The 12 Principles of UX in Motion,’ and they can be stacked and combined synergistically in a myriad of innovative ways.
+
+I’ve broken the manifesto into 5 parts:
+
+1. Addressing the topic of UI Animation — it’s not what you think
+2. Realtime vs non-realtime interactions
+3. Four ways that motion supports usability
+4. Principles, Techniques, Properties and Values
+5. The 12 Principles of UX in Motion
+
+As a quick plug, if you want me to speak at your conference or lead an onsite workshop for your team on the exciting topic of motion and usability, go [here](https://uxinmotion.net/workshops-and-speaking/) . If you want to attend a class in your city go [here](https://uxinmotion.net/workshops-and-speaking/#classes) . Finally, if you want me to consult on your project, you can go [here](https://uxinmotion.net/consulting/) . To get added to my list, go [here](http://uxinmotion.net/joinnow)
+
+### It’s not about UI Animation ###
+
+Because the topic of motion in user interfaces is mostly understood by designers to be ‘UI Animation’—which it is not — I feel like I need to create a bit of context before we jump into the 12 Principles.
+
+‘UI Animation’ is typically thought of by designers as something that makes the user experience more delightful, but overall doesn’t add much value. Thus, UI Animation is often treated like the red-headed stepchild of UX (apologies to red-headed stepchildren everywhere). If at all, it usually comes at the end, as a final lipstick pass.
+
+Additionally, motion in the context of user interfaces has understandably been held to be under the domain of Disney’s 12 Principles of Animation, something I argue against in my article ‘[UI Animation Principles — Disney is Dead](https://medium.com/@ux_in_motion/ui-animation-principles-disney-is-dead-8bf6c66207f9) .’
+
+In my manifesto, I will be making the case that UI Animation is to the ‘12 UX in Motion Principles’ as construction is to architecture.
+
+By this I mean, that while a structure needs to be physically built to exist (requiring construction), the guiding hand which determines *what* gets built comes from the domain of Principles.
+
+Animation is all about tools. Principles are the practical application of ideas that guide the usage of tools and as such, Principles provide high leverage opportunities for designers.
+
+What most designers think of as ‘UI Animation’ is in fact the execution of a higher modality of design: the temporal behavior of interface objects during realtime and non-realtime events.
+
+
+### Realtime vs non-realtime interactions ###
+
+At this juncture, it is important to distinguish between ‘state’ and ‘act.’ The *state* of something in UX is fundamentally static, like a design comp. The *act *of something in UX is fundamentally temporal, and motion based. An object can be in the *state *of being masked or it can be in the *act* of being masked. If it is the latter, we know that motion is involved and in a way that could support usability.
+
+Additionally, all temporal aspects of interaction can be thought of as happening in realtime or non-realtime. Realtime means that the user is directly interacting with the objects in the user interface. Non-realtime means that the object behavior is post-interactive: it occurs *after *a user action, and is transitional.
+
+
+
+
+
+This is an important distinction.
+
+Realtime interactions can also be though of as ‘direct manipulation,’ in that the user is interacting with the interface objects directly and *immediately*. The behavior of the interface is happening *as the user is using it.*
+
+Non-realtime interactions happen only *after *input from the user and have the effect of briefly locking the user out of the user experience until the transition completes.
+
+These distinctions will give us leverage as we continue our journey into the world of the 12 Principles of UX in Motion.
+
+
+### Motion supports usability in four ways ###
+
+These four pillars represent the four ways where the temporal behavior of user experiences supports usability.
+
+#### Expectation ####
+
+Expectation fall into two areas — how users perceive what an object *is*, and how it *behaves*. Another way of saying this is that as designers, we want to minimize the gap between what the user expects, and what they experience.
+
+#### Continuity ####
+
+Continuity speaks both to the user flow and to the ‘consistency’ of the user experience. Continuity can be thought of in terms of ‘intra-continuity’ — the continuity within a scene, and ‘inter-continuity’ — the continuity within a series of scenes that make up the total user experience.
+
+#### Narrative ####
+
+Narrative is the linear progression of events in the user experience that results in a temporal/spatial framework. This can be thought of as the series of discreet moments and events that connect together throughout the user experience.
+
+#### Relationship ####
+
+Relationship refers to the spatial, temporal, and hierarchal representations between interface objects that guide user understanding and decision making.
+
+### Principles, Techniques, Properties, and Values ###
+
+[Tyler Waye](http://tylerwaye.com/learning-to-learn-principles-vs-techniques/) says it as good as any when he writes, “Principles… are the underlying premises and rules of function giving rise to any number of techniques. These elements remain consistent, no matter what is happening.” It bears repeating that Principles are agnostic of design.
+
+From there, we can imagine a hierarchy with Principles at the top, Techniques further down, Properties below that, and Values at the bottom.
+
+**Techniques** can be thought of as the various and unlimited executions of Principles and/or combination of Principles. I think of technique as akin to ‘style.’
+
+**Properties** are the specific object parameters that are being animated to create the technique. These include (and are not limited to) position, opacity, scale, rotation, anchor point, color, stroke-width, shape, etc.
+
+**Values** are the actual numeric property values that vary over time to create what we call ‘animation.’
+
+So to land the plane here (and jumping ahead a bit), we could say that a hypothetical UI animation reference is using the Obscuration Principle with a ‘blurred glass’ Technique that affects the Blur and Opacity Properties at a Value of 25px and 70% respectively.
+
+Now we have some tools to work with. And more importantly, these linguistic tools are agnostic of any specific prototyping tool.
+
+
+### The 12 Principles of UX in Motion ###
+
+Easing and Offset & Delay relate to *timing*. Parenting relates to *object relationship*. Transformation, Value Change, Masking, Overlay, and Cloning all relate to *object continuity*. Parallax relate to *temporal hierarchy*. Obscuration, Dimensionality and Dolly & Zoom both relate to *spatial continuity*.
+
+
+
+#### **Principle 1: Easing** ####
+
+*Object behavior aligns with user expectations when temporal events occur.*
+
+
+
+All interface objects exhibiting temporal behavior (whether realtime or non-realtime), ease. Easing creates and reinforces the ‘naturalism’ inherent in the seamlessness of user experiences, and creates a sense of continuity when objects behave *as users expect them to. *Incidentally*, *Disney refers to this as ‘[Slow In and Slow Out](https://en.wikipedia.org/wiki/12_basic_principles_of_animation#Slow_In_and_Slow_Out).’
+
+
+
+
+
+The example on the left has linear motion and looks ‘bad.’ The first example up top has *eased* motion and looks ‘good.’ All three above examples have the exact number of frames and take place over the exact same amount of time. The only difference is in their easing.
+
+As designers concerned with usability, we need to require of ourselves rigor and inquire, aside from aesthetics, which example supports usability more?
+
+The case I am presenting here is that a certain degree of skeuomorphism is inherent in easing. You can imagine an ‘easing gradient’ wherein behaviors that fall outside user expectations result in less usable interactions. In the case of properly eased motion, users experience the motion itself as seamless and largely invisible — which is a good thing in that it is *non-distracting*. Linear motion is visibly obvious and feels somehow off, unfinished, and jarring, and distracting.
+
+Now I’m going to completely contradict myself here and talk about the example on the right. The motion *isn’t* seamless. In fact, it has a ‘designed’ feel to it. We notice how the object lands. It feels different, yet it still feels more ‘correct’ than the example with linear motion.
+
+Can you employ easing and still have it not support (or worse case undermine) usability? The answer is yes, and there are several ways. One way is timing. If your timing is too slow (mushy to borrow from [Pasquele](https://medium.com/@pasql) ), or too fast, you can break expectation and distract user attention. Similarly, if your easing is misaligned with the brand or overall experience, this can also negatively impact expectation and seamlessness.
+
+What I want to open you to is a world of opportunity when it comes to eased motion. There are literally an infinite number of ‘easings’ that you as a designer can create and implement in your projects. All of these easings have their own expectation response they trigger in users.
+
+To summarize: when to use easing? Always.
+
+#### Principle 2: Offset & Delay ####
+
+*Defines object relationships and hierarchies when introducing new elements and scenes.*
+
+
+
+Offset & Delay is the second of only two UX in Motion Principles that is influenced by Disney’s Animation Principles, in this case from ‘[Follow Through and Overlapping Action](https://en.wikipedia.org/wiki/12_basic_principles_of_animation#Follow_Through_and_Overlapping_Action).’
+
+It is important to note, however, that the implementation, while similar in execution, differs in purpose and outcome. While Disney’s Principles result in ‘more appealing animations,’ the UI Animation Principles result in more usable experiences.
+
+The utility of this principle is that it pre-consciously sets the user up for success by ‘telling’ the user something about the nature of the objects in the interface. The narrative in the above reference is that the top two objects are united and the bottom object is separate. Perhaps the top two objects could be a non-interactive image and text, while the bottom object is a button.
+
+Even before the user registers what these objects *are, *the designer has already communicated to her—through motion — that the objects are somehow ‘separate.’ This is extremely powerful.
+
+
+
+Credit: [InVision](https://dribbble.com/InVisionApp)
+
+In the above example, the floating action button (FAB) transforms into header navigation elements comprised of three buttons. Because the buttons are ‘offset’ from each other temporally, they end up supporting usability through their ‘separateness.’ Said differently, the designer is using time itself to say — even before the user registers what the objects are — that the objects are separate. This has the effect of telling the user, completely independent from the visual design, part of the nature of the objects in the interface.
+
+To better show you how this works, I’ll show you an example that breaks the Offset & Delay Principle.
+
+
+
+Credit: [Jordi Verdu](https://dribbble.com/jordiverdu) (
+
+In the above example, the static visual design tells us that there are icons over a background. The presumption is that the icons are all separate from each other and do different things. However, the motion contradicts this.
+
+Temporally, the icons are grouped into rows and behave like a single object. Their titles are likewise grouped into rows, and also behave like a single object. The motion is telling the user something other than what her eyes see. In this case, we can say that the temporal behavior of the objects in the interface are not supporting usability.
+
+#### Principle 3: Parenting ####
+
+*Creates spatial and temporal hierarchal relationships when interacting with multiple objects.*
+
+
+
+Parenting is a powerful Principle that ‘relates’ objects in the user interface. In the above example, the ‘scale’ and ‘position’ property of the top or ‘child’ object is parented to the ‘position’ property of the bottom or ‘parent’ object.
+
+Parenting is the linking of object properties to other object properties. This creates object relationships and hierarchies in ways that support usability.
+
+Parenting also allows designers to better coordinate temporal events in the user interface, while communicating to users the nature of the object relationships.
+
+Recall that object Properties include the following — Scale, Opacity, Position, Rotation, Shape, Color, Value, etc. Any of these Properties can be linked to any other Properties to create synergistic moments in the User Experience.
+
+
+
+
+
+Credit: [Andrew J Lee](https://dribbble.com/lee_aj) , [Frank Rapacciuolo](https://dribbble.com/frankiefreesbie)
+
+In this above left example, the ‘y-axis’ Property of the ‘face’ element is the ‘child’ to the ‘x-axis’ Property of the round indicator parent. When the round indicator element moves along the horizontal axis, its ‘child’ element moves along with it horizontally *and* vertically (while being Masked — another Principle).
+
+The result is a hierarchal temporal narrative framework that occurs all at the same time. Of note is that the ‘faces’ object works as a series of ‘lockups’ in that, at each number, the ‘face’ is fully and not partially visible. The user experiences this seamlessly, though we can make the claim there is a subtle ‘usability cheat’ in this example.
+
+Parenting functions best as a ‘realtime’ interaction. As the user directly manipulates the interface objects, the designer communicates to the user — via motion — how the objects are linked, and the relationship between them.
+
+Parenting occurs in 3 forms: ‘direct parenting’ (see above two examples, ‘delayed parenting,’ and ‘inverse parenting,’ see below).
+
+
+
+
+
+Delayed Parenting (Credit: [AgenceMe](https://dribbble.com/AgenceMe) ) & Inverse Parenting (Credit: [AgenceMe](https://dribbble.com/AgenceMe) )
+
+#### Principle 4: Transformation ####
+
+*Creates a continuous state of narrative flow when object utility changes.*
+
+
+
+Much has already been written about the UX in Motion Principle ‘transformation.’ In some ways, it is the most obvious and penetrable of the animation principles.
+
+Transformation is the most discernible, largely because it stands out. A ‘submit’ button changing shape to become a radial progress bar and finally changing shape again to become a confirmation check mark is something that we notice. It grabs our attention, tells a story, and has completion.
+
+
+
+Credit: [Colin Garven](https://dribbble.com/ColinGarven)
+
+What Transformation does is seamlessly transition the user through the different UX states or ‘is’s’ (as in this *is* a button, this *is* a radial progress bar, this *is* a check mark) which eventually result in a desired outcome. The user has been drawn through these functional spaces to the ultimate destination.
+
+Transformation has the effect of ‘chunking’ cognitively separate key moments in the user experience into a seamless and continuous series of events. This seamlessness results in better user awareness, retention, and followthrough.
+
+#### Principle 5: Value change ####
+*Creates a dynamic and continuous narrative relationship when value subject changes.*
+
+
+
+Text based interface objects, that is to say numbers and text, can change their values. This is one of those ‘elusive obvious’ concepts.
+
+Text and number changes are so common that they pass us by without us bringing to them distinction and rigor to assess their role in supporting usability
+
+So what is the user experiencing when values change? In user experiences, the 12 UX in Motion Principles are opportunities to support usability. The three opportunities here are to connect the user to the *reality* behind the data, the concept of *agency,* and to the dynamic nature of the values themselves.
+
+Let’s look at the example of a user dashboard.
+
+
+
+
+
+When value based interface objects load with no ‘value change,’ what this conveys to the user is that the numbers are static objects. They’re like painted signs displaying a speed limit of 55 mph.
+
+The numbers and values are representations of things that are happening *in reality.* That reality could be time, income, game scores, business metrics, fitness tracking, etc. What we are distinguishing through motion is that the ‘value subject’ is dynamic and the values are reflecting something from that dynamic value set.
+
+Not only does this relationship get lost with static objects comprised visually of values, but another deeper opportunity is also lost.
+
+When we employ representations of dynamic systems in the form of motion based values, it activates a sort of ‘neurofeedback.’ Users, grasping the dynamic nature of their data can now be cause in altering those values and are empowered to become *agents*. When the values are static, there is less connection to the reality behind the values, and users lose their *agency*.
+
+
+
+
+
+
+
+Credit: [Barthelemy Chalvet](https://dribbble.com/BarthelemyChalvet), [Gal Shir](https://dribbble.com/galshir) , Unknown
+
+The Value Change Principle can occur both in realtime and non-realtime events. In realtime events, the user is interacting with the objects to change values. In non-realtime events, such as loaders and transitions, the values change without user input to reflect a dynamic narrative.
+
+#### Principle 6: Masking ####
+
+*Creates continuity in an interface object or object group when utility is determined by which part of the object or group is revealed or concealed.*
+
+
+
+The *act* of masking asking can be thought of as a relationship between the shape of the object and it’s utility.
+
+Because designers are familiar with ‘masking’ in the context of static design, it behooves us to bring distinction to the UX in Motion Principle ‘Masking’ as it occurs in time, *as an* act, and not as a *state*.
+
+Through the temporal use of revealing and concealing regions of an object, utility transitions in a continuous and seamless way. This also has the effect of preserving narrative flow.
+
+
+
+Credit: [Anish Chandran](https://dribbble.com/anish_chandran)
+
+In the above example, the header image changes bounding shape and position but not the content, and becomes an album. This has the effect of changing what the object *is,while preserving the content within the mask — a fairly neat trick*. *This occurs in non-realtime, as a transition, that is activated after a user takes an action.
+
+Remember, UI Animation Principles occur temporally and support usability through continuity, narrative, relationship, and expectation. In the above reference, while the object itself remains unchanged, it also has boundary and location, and these two factors determine what the object is.
+
+#### Principle 7: Overlay ####
+
+*Creates narrative and object spatial relationship in visual flatland when layered objects are location dependent.*
+
+
+
+Overlay supports usability by allowing users to utilize flatland ordering properties to overcome a lack of non-spatial hierarchies.
+
+To land the plane a bit, Overlay allows designers to use motion to communicate location dependent objects that exist behind or in front of others in non 3D space.
+
+
+
+
+
+Credit: [Bady](https://dribbble.com/bady), [Javi Pérez](https://dribbble.com/javiperez)
+
+In the example on the left, the foreground object slides to the right to reveal the location of additional background objects. In the example on the right, the entire scene slides down to reveal additional content and options (while using the Offset & Delay Principle to communicate the individuality of the photo objects).
+
+To a certain degree, as designers, the idea of ‘layers’ is so obvious as to be self-evident. We design with layers and the concept of layers are deeply internalized. However, we must be careful to distinguish between the process of ‘making’ verses ‘using.’
+
+As designers who are continually engaged in the process of ‘making,’ we are intimately familiar with all of the pieces of the object (including the hidden pieces) we are designing. As a user, however, those non visible pieces are by definition and practice, hidden both visually and cognitively.
+
+The Overlay Principle allows designers to communicate relationship between ‘z-axis’ positioned layers and in so doing, promote spatial orientation to their users.
+
+#### Principle 8: Cloning ####
+
+*Creates continuity, relationship and narrative, when new objects originate and depart.*
+
+
+
+When new objects are created in current scenes (and from current objects), it is important to narratively account for their appearance. In this manifesto, I argue forcefully for the importance of creating a narrative framework for object origin and departure. Simple opacity fades tend to not achieve this result. Masking, Cloning, and Dimensionality are three usability based approaches to produce strong narratives.
+
+
+
+
+
+
+
+Credit: [Jakub Antalík](https://dribbble.com/antalik) , [Jakub Antalík](https://dribbble.com/antalik) , Unknown
+
+In the above three examples, new objects are created from existing hero objects during the time the user’s attention is focused on those objects. This two fold approach — the directing of attention, and then leading the eye through the creation of a cloned new object — has the strong effect of communicating a clear and unambiguous chain of events: that action ‘x’ has the result ‘y’ of the creation of new child objects.
+
+#### Principle 9: Obscuration ####
+
+*Allows users to spatially orient themselves in relationship to objects or scenes not in the primary visual hierarchy.*
+
+
+
+Similar to the UX in Motion Principles of Masking, Obscuration lives as both a static and temporal phenomena.
+
+This can be confusing to designers who don’t have experience thinking temporally — that is, the moments *between* moments. Designers typically design screen to screen or task to task. Think of Obscuration as the *act* of being obscured and not the *state* of being obscured. A static design represents the state of being obscured. Introducing time gives us the *act* of an object being obscured.
+
+
+
+
+
+Credit: [Virgil Pana](https://dribbble.com/virgilpana), [Apple](http://www.apple.com/)
+
+From the above two examples, we can see that obscuration, which *looks like* transparent objects or overlays, is also a temporal interaction involving multiple properties in time.
+
+Various common techniques of this involve blur effects and a lessoning of overall object transparency. The user is made aware of an additional non primary context that she is operating in — that there is another world, as it were, ‘behind’ her primary object hierarchy.
+
+Obscuration allows designers to compensate for a single unified field of view, or ‘objective view,’ in user experiences.
+
+#### Principle 10: Parallax ####
+
+*Creates spatial hierarchy in visual flatland when users scroll.*
+
+
+
+‘Parallax,’ as a UX in Motion Principle describes different interface objects moving at different rates.
+
+Parallax allows user to focus on primary actions and content while maintaining design integrity. Background elements ‘recede’ perceptually and cognitively for the user during a Parallax event. Designers can use Parallax to separate out immediacy content from ambient or supportive content.
+
+
+
+
+
+Credit: [Austin Neill](https://dribbble.com/austinneill), [Michael Sevilla](https://dribbble.com/SVLA)
+
+The effect this has on the user, is to clearly define *for the duration of the interaction,* the various object relationships. Foreground objects, or objects that move ‘quicker’ appear to the user as ‘closer.’ Likewise, background objects or objects that move ‘slower’ are perceived as being ‘further away.’
+
+Designers can create these relationships, using time itself, to tell the user what objects in the interface are higher priority. Therefore it makes sense to push background or non-interactive elements further ‘back.’
+
+Not only does the user perceive the interface objects as now having a hierarchy beyond that which is determined in the visual design, but this hierarchy can now be leveraged into having the user grasp *the nature* of the user experience before being consciously aware of the design/content.
+
+#### Principle 11: Dimensionality ####
+
+*Provides a spatial narrative framework when new objects originate and depart.*
+
+
+
+Critical to User Experiences is the phenomenon of continuity as well as the sense of location.
+
+Dimensionality provides a powerful way to overcome the flatland non-logic of User Experiences.
+
+Humans are remarkably adept at using spatial frameworks to navigate both in the real world and in digital experiences. Providing spatial origin and departure references helps reinforce mental models of where users are in the UX.
+
+Additionally, the Dimensionality Principle overcomes the layering paradox in visual flatland wherein objects lacking depth exist on the same plane but occur as ‘in front of’ or ‘behind’ other objects.
+
+Dimensionality presents itself in three ways — Origami Dimensionality, Floating Dimensionality, and Object Dimensionality.
+
+**Origami Dimensionality** can be thought of in terms of ‘folding’ or ‘hinged’ three dimensional interface objects.
+
+
+
+
+
+Examples of Origami Dimensionality (Credit: [Eddie Lobanovskiy](https://dribbble.com/lobanovskiy) , [Virgil Pana](https://dribbble.com/virgilpana))
+
+Because multiple objects are combined into ‘origami’ structures, the hidden objects still can be said to ‘exist,’ spatially even though they are not visible. This effectively renders the User Experience as a continuous spatial event that the user navigates and creates an operating context both in the interaction model itself, and in the temporal behavior of the interface objects themselves.
+
+**Floating Dimensionality** gives interface objects a spatial origin and departure, making the interaction models intuitive and highly narrative.
+
+
+
+Example of Floating Dimensionality (Credit: [Virgil Pana](https://dribbble.com/virgilpana) )
+
+In the above example, Dimensionality is achieved through the use of 3D ‘cards.’ This provides a strong narrative framework that supports the visual design. The narrative is extended by ‘flipping’ the cards to access additional content and interactivity. Dimensionality can be a powerful way to introduce new elements in ways that minimize abruptness.
+
+**Object Dimensionality **results in dimensional objects with true depth and form.
+
+
+
+
+
+Examples of Object Dimensionality (Credit: [Issara Willenskomer](https://uxinmotion.net/) , [Creativedash](https://dribbble.com/Creativedash) )
+
+Here, multiple 2D layers are arranged in 3D space to form true dimensional objects. Their dimensionality is revealed during realtime and non-realtime transitional moments. The utility of Object Dimensionality is that users develop a keen awareness of object utility based on non-visible spatial locations.
+
+#### Principle 12: Dolly & Zoom ####
+
+*Preserves continuity and spatial narrative when navigating interface objects and spaces.*
+
+
+
+Dolly and Zoom are filmic concepts referring to the movement of objects relevant to the camera, and the size of the image itself in the frame smoothly changing from a long shot to a close up shot (or vice versa).
+
+In certain contexts, it is impossible to tell if an object is zooming, if it is moving towards the camera in 3D space, or if the camera is moving towards the object in 3D space (see below references). The below three examples illustrate the possible scenarios.
+
+![](https://cdn-images-1.medium.com/max/800/1*R9wPWQUu26wjibaTBUstqQ.gif)
+
+Is the layer dollying, zooming, or is the camera moving?
+As such, it is appropriate to treat the instances of ‘dollying’ and ‘zooming’ as separate but similar in that they involve continuous element and scenic transformations, and meet the requirements of the UX in Motion Principles: they support usability through motion.
+
+![](https://cdn-images-1.medium.com/max/400/1*I4yZ2k1zeo3qc9qrbn0LDw.gif)
+
+![](https://cdn-images-1.medium.com/max/400/1*XVtnYMrp8LhGJzcsF0Lw7Q.gif)
+
+![](https://cdn-images-1.medium.com/max/400/1*o2ellGNN8CTJbwUoJ0ts8Q.gif)
+
+The two images on the left are dollying, while the image on the right is zooming
+
+**Dolly** is a film term and applies to camera movement either toward or away from a subject (it also applies to horizontal ‘tracking’ movement as well, but is less relevant in a usability context).
+
+![](https://cdn-images-1.medium.com/max/800/1*8TYALn5P87i2OuuZfhfELg.gif)
+
+Credit: [Apple](http://www.apple.com/)
+
+Spatially in UX, this motion could refer either to a change in the viewers perspective, or to the perspective remaining static while the object changes position. The Dolly Principle supports usability through continuity and narrative, seamlessly transitioning between interface objects and destinations. Dolly can also incorporate the Dimensionality Principle, resulting in a more spatial experience, more depth, and communicating to the user additional areas or content that is ‘in front’ or ‘behind’ the current view.
+
+**Zoom** refers to events where neither the perspective nor the object is moving spatially, but rather the object itself is scaling (or our view of it is decreasing, resulting in the image enlarging). This communicates to the viewer that additional interface objects are ‘inside’ other objects or scenes.
+
+![](https://cdn-images-1.medium.com/max/800/1*I6-dXGCq9cXjAZGyVOkXrA.gif)
+
+Credit: [Apple](http://www.apple.com/)
+
+This allows for seamless transitions — both realtime and non-realtime — that support usability. This seamlessness employed in the Dolly & Zoom Principle is quite powerful when it comes to creating spatial mental models.
+
+If you made it this far, congratulations! That was a beast of a manifesto. I hope all the gifs loaded for you and didn’t kill your browser. I also really hope you got some value for yourself and some new tools and leverage in your interactive projects.
+
+I encourage you to learn more about how you can begin using motion as a design tool to support usability.
+
+Again, the final plug, if you want me to speak at your conference or lead an onsite workshop for your team on the exciting topic of motion and usability, go [here](https://uxinmotion.net/workshops-and-speaking/) . If you want to attend a class in your city go [here](https://uxinmotion.net/workshops-and-speaking/#classes) . Finally, if you want me to consult on your project, you can go [here](https://uxinmotion.net/consulting/) . To get added to my list, go [here](http://uxinmotion.net/joinnow) .
+
+This manifesto would not have been possible without the generous and patient contribution and constant feedback of [Kateryna Sitner](https://www.linkedin.com/in/katerynasitner/) from Amazon — thank you! Special thanks to [Alex Chang](https://www.linkedin.com/in/alexychang/) for his brainstorming and insistence that I land the plane, [Bryan Mamaril](http://ficuscreative.com/) at Microsoft for his eagle eye, Jeremey Hanson for his editing notes, [Eric Braff](https://www.linkedin.com/in/eric-braff-276504b) for being the insane UI motion guru he is, Rob Girling at [Artefact](http://artefactgroup.com/) for his belief in me all those years ago, [Matt Silverman](http://www.swordfish-sf.com/) for his inspiring talk on UI motion at the After Effects conference, [Bradley Munkowitz](http://gmunk.com/) for being an awesome roommate and getting me inspired in UI, [Pasquale D’Silva](https://medium.com/@pasql) for his incredible articles on motion, [Rebecca Ussai Henderson](https://medium.freecodecamp.com/@becca_u) for her awesome article on UI Choreography, [Adrian Zumbrunnen](https://medium.com/@azumbrunnen) for his awesome contributions to the topic of UI and motion, [Wayne Greenfield](http://www.seattlekombucha.com/) and [Christian Brodin](http://www.theapartmentinvestor.com/author/christian-brodin/) for being my mastermind brothers and always pushing me to level up, and all you thousands of UI Animators who keep cranking out inspiring gifs.
+
+
+
+---
+
+> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[React](https://github.com/xitu/gold-miner#react)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计) 等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)。
From 50a020d04b8ae6c32b5c5a02a0ef2b86cc16bdbf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=A0=B9=E5=8F=B7=E4=B8=89?=
Date: Fri, 7 Apr 2017 22:00:19 +0800
Subject: [PATCH 061/638] Create swift-lazy-initialization-with-closures.md
---
...swift-lazy-initialization-with-closures.md | 362 ++++++++++++++++++
1 file changed, 362 insertions(+)
create mode 100644 TODO/swift-lazy-initialization-with-closures.md
diff --git a/TODO/swift-lazy-initialization-with-closures.md b/TODO/swift-lazy-initialization-with-closures.md
new file mode 100644
index 00000000000..00d175ee6b5
--- /dev/null
+++ b/TODO/swift-lazy-initialization-with-closures.md
@@ -0,0 +1,362 @@
+> * 原文地址:[Swift Lazy Initialization with Closures](https://blog.bobthedeveloper.io/swift-lazy-initialization-with-closures-a9ef6f6312c)
+> * 原文作者:[Bob Lee](https://blog.bobthedeveloper.io/@bobthedev?source=post_header_lockup)
+> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
+> * 译者:
+> * 校对者:
+
+
+# Swift Lazy Initialization with Closures #
+
+## Learn how to create objects with modularity and readability ##
+
+![](https://cdn-images-1.medium.com/max/2000/1*KNmIy5QAOeokXPW86TtVyA.png)
+
+Magic Keyboard 2 and Magic Mouse 2
+
+*Welcome my lovely readers. Good to see you here today. For those who are new, I’m Bob. Just for real quick, if you wish to be on my mailing list, you can sign up* [*here*](https://boblee.typeform.com/to/oR9Nt2) *and get more value for your learning with iOS development :)*
+
+### Motivation ###
+
+In the beginning of my iOS journey, I followed tutorials on YouTube. I saw a few using something like below to create UI objects.
+
+```
+let makeBox: UIView = {
+ let view = UIView()
+ return view
+}()
+```
+
+As a learner, I copied the practice and used it. One day, however, one of my readers asked me, “why do you add `{}` and why does `()` exist at the end? Is it a computed property?” I could not answer. I was a zombie.
+
+I wrote this tutorial for my younger self. Yet, some may find it useful.
+
+### Objectives ###
+
+There are three objectives. First, understand how to initialize an object using the unconventional way as shown above. Second, learn when to use `lazy var` in Swift. Last, join my mailing list.
+
+#### Prerequisites ####
+
+To fully enjoy the ride with me, I highly recommend you to be familiar with the topics below.
+
+1. [*Closures*](https://blog.bobthedeveloper.io/no-fear-closure-in-swift-3-with-bob-72a10577c564)
+2. [*Capture List and retention cycle [weak self]*](https://blog.bobthedeveloper.io/swift-retention-cycle-in-closures-and-delegate-836c469ef128)
+3. *Descent Object Oriented Programming*
+
+### Create UI Components ###
+
+Before I explain the unconventional method above, let’s look into your past. In order to create a button in Swift, you probably have done something like this,
+
+```
+// Determine Size
+let buttonSize = CGRect(x: 0, y: 0, width: 100, height: 100)
+
+// Create Instance
+let bobButton = UIButton(frame: buttonSize)
+bobButton.backgroundColor = .black
+bobButton.titleLabel?.text = "Bob"
+bobButton.titleLabel?.textColor = .white
+```
+
+This is *Okay.*
+
+Assume, you have to create three other buttons, you probably have to copy the code above and then change the name from `bobButton` to `bobbyButton`.
+
+It’s quite tedious.
+
+```
+// New Button
+let bobbyButton = UIButton(frame: buttonSize)
+bobbyButton.backgroundColor = .black
+bobbyButton.titleLabel?.text = "Bob"
+bobbyButton.titleLabel?.textColor = .white
+```
+
+To make things just a bit easier, you may
+
+![](https://cdn-images-1.medium.com/max/800/1*oDIPy0i4YzUnKVR4XYI4kg.gif)
+
+This works too with the keyboard shortcut: ctrl-cmd-e
+
+If you don’t wish to repeat yourself, you may create a function instead.
+
+```
+func createButton(enterTitle: String) -> UIButton {
+ let button = UIButton(frame: buttonSize)
+ button.backgroundColor = .black
+ button.titleLabel?.text = enterTitle
+ return button
+}
+
+createButton(enterTitle: "Yoyo") // 👍
+```
+
+However, in iOS development, it is rare that custom buttons look similar. Therefore, a function may require a lot more parameters including background color, title, border radius, shadow, and so on. You function may end up looking like,
+
+```
+func createButton(title: String, borderWidth: Double, backgrounColor, ...) -> Button
+```
+
+The code above is not ideal even if you add default parameters to the function. It decreases readability. Therefore, it’s better to stay with the tedious method above.
+
+But, is there any way we can make it less tedious and more organized? Of course. We’ve looked into your past — It’s time to step up and look into your future.
+
+### Introducing the Unconventional Way ###
+
+Before we create UI components with the unconventional way, let’s first answer the initial questions my reader asked. What does `{}` mean, and is it a `computed property`?
+
+*Nope, it’s just a* ***closure block***.
+
+First, let’s demonstrate how to create an object using a closure. We will design a struct called `Human`.
+
+```
+struct Human {
+ init() {
+ print("Born 1996")
+ }
+}
+```
+
+Now, this is how you create an object with a closure
+
+```
+let createBob = { () -> Human in
+ let human = Human()
+ return human
+}
+
+let babyBob = createBob() // "Born 1996"
+```
+
+*If the syntax above doesn’t look familiar to you, you may stop reading now, and go to* [*Fear No Closure with Bob*](https://blog.bobthedeveloper.io/no-fear-closure-in-swift-3-with-bob-72a10577c564) *, and bring some bullets.*
+
+Just to explain, `createBob` is a closure whose type is `() -> Human`. You’ve created an instance called, `babyBob` by calling `createBob()` .
+
+However, you had to create two constants: `createBob` and `babyBob`. What if you want to do everything in a single statement? Here you go.
+
+```
+let bobby = { () -> Human in
+ let human = Human()
+ return human
+}()
+```
+
+Now, the closure block executes itself through adding `()` at the end and `bobby` now has a `Human` object attached. Pretty good stuff.
+
+**You’ve learned how to initialize an object with a closure block.**
+
+Now, let’s apply to creating an UI object which should be similar to the example right above.
+
+```
+let bobView = { () -> UIView in
+ let view = UIView()
+ view.backgroundColor = .black
+ return view
+}()
+```
+
+Great, we can make it shorter. In fact, we don’t need to specify the type of the closure block. Instead, all we have to do is specify the type of the instance, `bobView`, for example.
+
+```
+let bobbyView: **UIView** = {
+ let view = UIView()
+ view.backgroundColor = .black
+ return view
+}()
+```
+
+Swift is able to infer that the closure block is `() -> UIView` based on the keyword, `return`.
+
+Now, take a look. The example right above should look identical to the “unconventional way” I feared.
+
+### Benefits of Init with Closures ###
+
+We discussed the tediousness of creating objects and the problem that arises from using a function. In your head, you must be thinking, “why should I use a closure block instead?”
+
+#### Easy to Duplicate ####
+
+I don’t like to use Storyboard, I love copy and pasting UI objects. In fact, I’ve a “library” of code in my computer. Let us assume that there is a button as shown below in the library.
+
+```
+let myButton: UIButton = {
+ let button = UIButton(frame: buttonSize)
+ button.backgroundColor = .black
+ button.titleLabel?.text = "Button"
+ button.titleLabel?.textColor = .white
+ button.layer.cornerRadius =
+ button.layer.masksToBounds = true
+return button
+}()
+```
+
+All I have to do is copy the entire lines, and then just change the name of `myButton` to `newButton` for the usage. Had I not used the closure method, I probably had to change the name of `button` to `newButton` 7–8 times. We could use the Xcode shortcut above, but why not make it just simpler.
+
+#### Look Cleaner ####
+
+Since objects are grouped together, it feels cleaner based on my eyes. Let’s compare
+
+```
+// Init with Closure
+let leftCornerButton: UIButton = {
+ let button = UIButton(frame: buttonSize)
+ button.backgroundColor = .black
+ button.titleLabel?.text = "Button"
+ button.titleLabel?.textColor = .white
+ button.layer.cornerRadius =
+ button.layer.masksToBounds = true
+return button
+}()
+
+let rightCornerButton: UIButton = {
+ let button = UIButton(frame: buttonSize)
+ button.backgroundColor = .black
+ button.titleLabel?.text = "Button"
+ button.titleLabel?.textColor = .white
+ button.layer.cornerRadius =
+ button.layer.masksToBounds = true
+return button
+}()
+```
+
+vs
+
+```
+// Init With Fingers
+let leftCornerButton = UIButton(frame: buttonSize)
+leftCornerButton.backgroundColor = .black
+leftCornerButton.titleLabel?.text = "Button"
+leftCornerButton.titleLabel?.textColor = .white
+leftCornerButton.layer.cornerRadius =
+leftCornerButton.layer.masksToBounds = true
+
+let rightCornerButton = UIButton(frame: buttonSize)
+rightCornerButton.backgroundColor = .black
+rightCornerButton.titleLabel?.text = "Button"
+rightCornerButton.titleLabel?.textColor = .white
+rightCornerButton.layer.cornerRadius =
+rightCornerButton.layer.masksToBounds = true
+```
+
+Although creating an object with the closure add a couple lines more, I feel less overwhelmed since I only have to add attributes to `button` rather than `rightCornerButton` or `leftCornerButton`.
+
+*In fact, if the name of a button gets more descriptive, often times it requires fewer lines to create an object with a closure block.*
+
+**You’ve accomplished the first objective. Congratulations**
+
+### Lazy Init Application ###
+
+You’ve come a long way. It’s time to meet the second objective of this tutorial.
+
+You might have seen something like this below
+
+```
+class IntenseMathProblem {
+ lazyvar complexNumber: Int = {
+ // imagine it requires a lot of CPU
+ 1 * 1
+ }()
+}
+```
+
+What `lazy` allows you to do is, the `complexNumber` property will be only calculated when you try to access it. For example,
+
+```
+let problem = IntenseMathProblem
+problem() // No value for complexNumber
+```
+
+Currently, there is no value for `complexNumber`. However, once you access the property,
+
+```
+problem().complexNumber // Now returns 1
+```
+
+The `lazy var` is often used to sort database and fetch data from any backend services because you definitely don’t want to calculate and sort everything when you create an object.
+
+*In fact, your phone will crash since the object is super bloated and the RAM can’t handle.*
+
+### Application ###
+
+Below is just an application of `lazy var`.
+
+#### Sorting ####
+
+```
+class SortManager {
+ lazy var sortNumberFromDatabase: [Int] = {
+ // Sorting logic
+ return [1, 2, 3, 4]
+ }()
+}
+```
+
+#### Image Compression ####
+
+```
+class CompressionManager {
+ lazy var compressedImage: UIImage = {
+ let image = UIImage()
+ // Compress the image
+ // Logic
+ return image
+ }()
+}
+```
+
+### Rules with `Lazy` ###
+
+1. You can’t use `lazy` with `let` since there is no initial value, and it is attained later when it is accessed.
+2. You can’t use it with a `computed property` since computed property is always recalculated (requires CPU) when you modify any of the variables that has a relationship with the `lazy` property.
+3. `Lazy` is only valid for members of a struct or class
+
+### Does Lazy Capture? ###
+
+So, if you’ve read the previous article on [Retention Cycle in Closures and Delegate](https://blog.bobthedeveloper.io/swift-retention-cycle-in-closures-and-delegate-836c469ef128) , you might wonder. Let’s test it out. Create a class called `BobGreet`. It has two properties: `name` whose type is `String` and `greeting` whose type is also `String` but initialized with a closure block.
+
+```
+class BobGreet {
+ var name = "Bob the Developer"
+ lazy var greeting: String = {
+ return "Hello, \(self.name)"
+ }()
+
+deinit {
+ print("I'm gone, bruh 🙆")}
+ }
+}
+```
+
+The closure block *might* have a strong reference to `BobGuest` but let’s attempt to deallocate.
+
+```
+var bobGreet: BobGreet? = BobClass()
+bobGreet?.greeting
+bobClass = nil // I'm gone, bruh 🙆
+```
+
+No need to worry about `[unowned self]` The closure block does not have a reference to the object. Instead, it just copies `self` within the closure block. If you are confused by the previous statement, feel free to read [Swift Capture Lists](https://blog.bobthedeveloper.io/swift-capture-list-in-closures-e28282c71b95) to learn more. 👍
+
+### Last Remarks ###
+
+I learned a quite a bit while preparing for this tutorial. I hope you did as well. I’d appreciate your genuine fat ❤️. But, there is just one more. As the last objective, if you wish to on my mailing list and receive greater value from me, you can sign up right [**here**](https://boblee.typeform.com/to/oR9Nt2) .
+
+As you can see by the cover photo, I recently bought Magic Keyboard and Mouse. They are pretty good and increase my productivity a lot. You can get the mouse [here](http://amzn.to/2noHxgl) or the keyboard [here](http://amzn.to/2noHxgl). I never regret despite the price. 😓
+
+> [Source Code](https://github.com/bobthedev/Blog_Lazy_Init_with_Closures)
+
+### Swift Conference I Will Join ###
+
+I will be joining my first conference @[SwiftAveir](https://twitter.com/SwiftAveiro) o from June 1–2. A friend of mine, [Joao](https://twitter.com/NSMyself) , is helping organize the conference, so I’m super excited. You can learn more about the event [here](http://swiftaveiro.xyz) !
+
+#### Recommended Articles ####
+
+> Intro to Functional Programming ([Blog](https://blog.bobthedeveloper.io/intro-to-swift-functional-programming-with-bob-9c503ca14f13))
+
+> My Favorite Xcode Shortcuts ([Blog](https://blog.bobthedeveloper.io/intro-to-swift-functional-programming-with-bob-9c503ca14f13) )
+
+### Bob the Developer ###
+
+I’m an iOS instructor from Seoul, 🇰🇷. Feel free to get to know me on [Instagram](https://instagram.com/bobthedev) . I post regular updates on [Facebook Page](https://facebook.com/bobthedeveloper) and 🖨 on Sat 8pm EST.
+
+---
+
+> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[React](https://github.com/xitu/gold-miner#react)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计) 等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)。
From 360e4e55dce24e687e9b1d80344131a2b70d5f58 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=A0=B9=E5=8F=B7=E4=B8=89?=
Date: Fri, 7 Apr 2017 22:03:19 +0800
Subject: [PATCH 062/638] Update secure-web-app-http-headers.md
---
TODO/secure-web-app-http-headers.md | 6 ------
1 file changed, 6 deletions(-)
diff --git a/TODO/secure-web-app-http-headers.md b/TODO/secure-web-app-http-headers.md
index 4514e6c4c2a..e2f1066fd33 100644
--- a/TODO/secure-web-app-http-headers.md
+++ b/TODO/secure-web-app-http-headers.md
@@ -6,12 +6,6 @@
## [How To Secure Your Web App With HTTP Headers](https://www.smashingmagazine.com/2017/04/secure-web-app-http-headers/) ##
-
-Today, too many websites are still inaccessible. In our new book *Inclusive Design Patterns*, we explore how to craft **flexible front-end design patterns** and make **future-proof and accessible interfaces without extra effort**. Hardcover, 312 pages. [Get the book now!](https://shop.smashingmagazine.com/products/inclusive-design-patterns?utm_source=magazine&utm_campaign=inclusive-design-patterns&utm_medium=html-ad-content-1)
-
-[![](https://www.smashingmagazine.com/wp-content/uploads/2016/10/inclusive-design-pattners-250px.png)](https://shop.smashingmagazine.com/products/inclusive-design-patterns?utm_source=magazine&utm_campaign=inclusive-design-patterns&utm_medium=html-ad-content-1)
-
-
Web applications, be they thin websites or thick single-page apps, are notorious targets for cyber-attacks. In 2016, approximately [40% of data breaches](http://www.verizonenterprise.com/verizon-insights-lab/dbir/2016/) originated from attacks on web apps — the leading attack pattern. Indeed, these days, understanding cyber-security is not a luxury but rather **a necessity for web developers**, especially for developers who build consumer-facing applications.
HTTP response headers can be leveraged to tighten up the security of web apps, typically just by adding a few lines of code. In this article, we’ll show how web developers can use HTTP headers to build secure apps. While the code examples are for Node.js, setting HTTP response headers is supported across all major server-side-rendering platforms and is typically simple to set up.
From 3a3a9df00e43ef7a88fb8d62a78c464ce9d0d44a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=A0=B9=E5=8F=B7=E4=B8=89?=
Date: Fri, 7 Apr 2017 22:15:05 +0800
Subject: [PATCH 063/638] Create on-loser-experience-design.md
---
TODO/on-loser-experience-design.md | 70 ++++++++++++++++++++++++++++++
1 file changed, 70 insertions(+)
create mode 100644 TODO/on-loser-experience-design.md
diff --git a/TODO/on-loser-experience-design.md b/TODO/on-loser-experience-design.md
new file mode 100644
index 00000000000..733b4435aba
--- /dev/null
+++ b/TODO/on-loser-experience-design.md
@@ -0,0 +1,70 @@
+> * 原文地址:[On Loser Experience Design](https://medium.com/on-human-centric-systems/on-loser-experience-design-1916629c36fc)
+> * 原文作者:[Matt LeMay](https://medium.com/@mattlemay?source=post_header_lockup)
+> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
+> * 译者:
+> * 校对者:
+
+# On Loser Experience Design #
+
+## Designing platforms and products that aren’t just for winners, “influencers,” and “thought leaders.” ##
+
+![](https://cdn-images-1.medium.com/max/800/1*kVOEiUv3YK8tcYEa5QKmLA.jpeg)
+
+Turntable.fm, a Great Lesson in Loser Experience Design
+
+Do you remember turntable.fm? The idea behind the product was simple and brilliant: you join a virtual “room” with friends and/or strangers, and take turns DJing for each other. Like a lot of products that experience meteoric early-stage growth, it took a real-world behavior — social listening — and created a digital proxy that could instantly connect people across geographic and cultural divides. I was super-excited when turntable.fm launched, and I was not alone.
+
+But the more I used turntable.fm, the more I started to feel like — well, a *loser*. I was primarily interested in discovering new music, not in becoming a **star virtual DJ**. But the platform seemed to offer no encouragement or incentives for being a good listener, no shiny prizes for thoughtfully engaging in conversation with my virtual roommates. My avatar remained puny and plain, while others grew mighty, adorned with jewels, and outfitted with cool animal costumes. Eventually, I just gave up.
+
+**Turntable.fm suffered from bad loser experience design: making casual users feel like unwitting competitors in a game they cannot win.**
+
+In the absence of good loser experience design, products and platforms turn into ghost towns inhabited by thirsty would-be “influencers,” howling desperately into a void that was once occupied by curious, casual users. And in a world obsessed with performance metrics and status markers, bad loser experience design is all around us.
+
+#### The Patterns of Bad Loser Experience Design ####
+
+Here are a few signs that your product may be suffering from **bad loser experience design:**
+
+![](https://cdn-images-1.medium.com/max/600/1*k_ZpnygG7JhLUteHxZOJyQ.png)
+
+Illustration by [Joan LeMay](http://joanlemay.com)
+
+- **You have a “leaderboard” or a points system.**
+
+Yes, in the short-term, people may engage with a product for an abstract reward such as “points” or “[coins](https://techcrunch.com/2015/12/09/swarm-now-lets-you-spend-those-coins-on-upgraded-stickers/) .” But watch what happens as your users see themselves fall to the bottom of that “leaderboard” or fail to get any real value out of the time they’ve invested in earning those shiny trinkets. Competing for something only to realize that it’s worthless is embarrassing, frustrating, and makes you feel *like a huge loser*. Gratuitous “gamification” is one of the most odious and lazy patterns of bad loser experience design — and in the long term, it [doesn’t work](http://www.gartner.com/newsroom/id/2251015) .
+
+- **You visually distinguish the winners from the losers.**
+
+Twitter’s verification system was designed to foster trust by “verifying” that people are who they say they are. But in its early days, “verification” felt like a [badge of honor for “important” people](http://anildash.com/2013/03/what-its-like-being-verified-on-twitter.html) and an [aspirational delineator between the haves and have-nots](http://www.xojane.com/tech/how-to-get-verified-on-twitter) . Twitter took a great step towards mitigating this bad loser experience design when they bulk-verified journalists, making it clear that there was a functional *purpose* to this distinction and conferring it on people who are not high-status celebrities.
+
+- **You over-index on popularity metrics.**
+
+This is perhaps the most widespread pattern of bad loser experience design. Trying to decide what content to surface? How about the most popular content! Trying to find some “interesting” users? Look for the ones who have the most followers! This is the “rich get richer” problem of bad loser experience design — by building platforms that reward the people who are already succeeding, you create a permanent and inaccessible overclass that tends to reward the people who are the most ruthless and aggressive about increasing their own status — even if it means gaming the system.
+
+- **You treat casual users like failed power users.**
+
+Zach Holman’s “[Don’t Give Your Users the Shit Work](https://zachholman.com/posts/shit-work/) ” does a great job of describing this bad loser experience pattern in action: a new user gets onboarded, and is immediately presented with a barrage of “power user” features that will help them get the *most* out of this product. If they neglect to use these features, they find themselves stuck in a kind of permanent limbo, nagged by reminders to use features they don’t need and unable to derive immediate value from the product. If you treat casual users like failed power users, they will start to *feel *like failures — and they will leave.
+
+#### Tips for Good Loser Experience Design ####
+
+While bad loser experience design can significantly harm a product, *good* loser experience design can help foster a broad, engaged, and self-sustaining user base. Here are a few tips for good loser experience design:
+
+- **Help people find *their* people, not the most popular people.**
+
+When platforms focus on shared interests and social bonds over “likes” and “favorites,” they help everybody find a place where they belong. Instagram has done a great job doing this with their discovery features, consistently surfacing people who are adjacent to *your* people, not people with the most likes or followers. Their new discovery features have helped me find my [guitar](https://www.instagram.com/leoleoband/) [people](https://www.instagram.com/lostincrystalcanyons/) , my [cat](https://www.instagram.com/scruffles_fatcat/)[people](https://www.instagram.com/12catslady/) , and even to discover a whole new community of [prairie](https://www.instagram.com/rinran032/) [dog](https://www.instagram.com/prairiedogpack/) [people](https://www.instagram.com/pimpa_wan/) . As I’ve used these discovery features more, I’ve started to pay *less attention to how many “follows” and “likes” I get, and more attention to the people with whom I interact* — which is a surefire signal of great loser experience design.
+
+- **Give “passive” users meaningful ways to engage.**
+
+Tumblr’s reblog feature is a great example of good loser experience design. If somebody sees something they like, they can *share it to their entire network*, rather than just leaving a comment or a “like.” This helps people engage with each other more deeply, and means that a post written by somebody with a small number of followers can find a wide audience as it makes its way through networks and communities of people. It also gives people who don’t want to “write” a post a meaningful way to contribute and engage.
+
+- **Test your product with people who are not “power users.”**
+
+Finally, and perhaps most importantly, break out of the design and testing patterns that lead to equating “power users” with “good users.” Over-reliance on internal “dogfooding,” where new products and features are tested primarily with a company’s own employees, is a one-way ticket to bad loser experience design. Dismissing user testing candidates who are not over the moon for your product is another surefire road to bad loser experience design. Think through the needs and behaviors of casual users as extensively as you think through those of “power users” — and ask yourself, “if I only use this product a few times a week, will it make me feel like a *loser*?”
+
+#### Loser Experience Design in the Wild ####
+
+Has your day-to-day usage of a product or platform been affected by bad loser experience design? Leave a response and let me know your thoughts. And be sure to hit that “like” button, so that I can feel like a high-status *winner* right here on medium dot com.
+
+
+---
+
+> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[React](https://github.com/xitu/gold-miner#react)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计) 等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)。
From c7230b4ac0ba734d2c4062851c97149fcf7a2270 Mon Sep 17 00:00:00 2001
From: sqrtthree
Date: Fri, 7 Apr 2017 22:22:00 +0800
Subject: [PATCH 064/638] update link
---
TODO/swift-lazy-initialization-with-closures.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/TODO/swift-lazy-initialization-with-closures.md b/TODO/swift-lazy-initialization-with-closures.md
index 00d175ee6b5..051ab41f287 100644
--- a/TODO/swift-lazy-initialization-with-closures.md
+++ b/TODO/swift-lazy-initialization-with-closures.md
@@ -1,5 +1,5 @@
> * 原文地址:[Swift Lazy Initialization with Closures](https://blog.bobthedeveloper.io/swift-lazy-initialization-with-closures-a9ef6f6312c)
-> * 原文作者:[Bob Lee](https://blog.bobthedeveloper.io/@bobthedev?source=post_header_lockup)
+> * 原文作者:[Bob Lee](https://blog.bobthedeveloper.io/@bobthedev)
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
> * 译者:
> * 校对者:
From de20c171c428fc387c46314efd0266f8710ce9bb Mon Sep 17 00:00:00 2001
From: zhuzi
Date: Sat, 8 Apr 2017 00:22:18 +0800
Subject: [PATCH 065/638] update according to proof-reading
---
TODO/beyond-browser-web-desktop-apps.md | 140 ++++++++++++------------
1 file changed, 69 insertions(+), 71 deletions(-)
diff --git a/TODO/beyond-browser-web-desktop-apps.md b/TODO/beyond-browser-web-desktop-apps.md
index 7b4f8ffcec8..9803dd3b2c6 100644
--- a/TODO/beyond-browser-web-desktop-apps.md
+++ b/TODO/beyond-browser-web-desktop-apps.md
@@ -2,31 +2,31 @@
> * 原文作者:本文已获原作者 [Adam Lynch](https://www.smashingmagazine.com/author/adamlynch/) 授权
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
> * 译者: [bambooom](https://github.com/bambooom)/[imink](https://github.com/imink)
-> * 校对者:
+> * 校对者:[bambooom](https://github.com/bambooom)/[sunui](https://github.com/sunui)
## 超越浏览器:从 web 应用到桌面应用
-一开始我是个 web 开发者,现在我是个全栈开发者,但从未想过在桌面上有所作为。我热爱 web 技术,热爱这个无私的社区,热爱它对于开源的友好,尝试挑战极限。我热爱探索好看的网站和强大的应用。当我被指派做桌面应用的任务的时候,我非常忧虑和害怕,因为那看起来很难,或者至少非常不同。
+一开始我是个 web 开发者,现在我是个全栈开发者,但从未想过在桌面上有所作为。我热爱 web 技术,热爱这个无私的社区,热爱它对于开源的友好,尝试挑战极限。我热爱探索好看的网站和强大的应用。当我被指派做桌面应用任务的时候,我非常忧虑和害怕,因为那看起来很难,或者至少不一样。
这并不吸引人,对吧?你需要学一门新的语言,甚至三门?想象一下过时的工作流,古旧的工具,没有任何你喜欢的有关 web 的一切。你的职业发展会被怎样影响呢?
-别慌,深呼吸,现实情况是,作为 web 开发者,你已经拥有一切开发现代桌面应用所需的一切技能,感谢新的强大的 API,你甚至可以在桌面应用中发挥你最大的潜能。
+别慌,深呼吸,现实情况是,作为 web 开发者,你已经拥有开发现代桌面应用所需的一切技能,得益于新的强大的 API,你甚至可以在桌面应用中发挥你最大的潜能。
本文将会介绍使用 [NW.js](http://nwjs.io/) 和 [Electron](https://electron.atom.io/) 开发桌面应用,它们的优劣,使用同一套代码库给桌面、web,甚至更多。
### 为什么?
-首先,为什么会有人开发桌面应用?任何现有的 web 应用(不同于网站,如果你认为它们是不同的)都可能适合变成一个桌面应用。你可以围绕任何可以从与用户系统集中中获益的 web 应用构建桌面应用;例如本地通知,开机启动,与文件的交互等。有些用户单纯更喜欢在自己的电脑中永久保存一些 app,无论是否联网都可以访问。
+首先,为什么会有人开发桌面应用?任何现有的 web 应用(不同于网站,如果你认为它们是不同的)都可能适合变成一个桌面应用。你可以围绕任何可以从与用户系统集成中获益的 web 应用构建桌面应用;例如本地通知,开机启动,与文件的交互等。有些用户单纯更喜欢在自己的电脑中永久保存一些 app,无论是否联网都可以访问。
也许你有个想法,但只能用作桌面应用,有些事情只是在 web 应用中不可能实现(至少还有一点,但更多的是这一点)。你可能想要为公司内部创建一个独立的功能性应用程序,而不需要任何人安装除了你的 app 之外的任何内容(因为内置 Node.js )。也许你有个有关 Mac 应用商店的想法,也许只是你的一个个人兴趣的小项目。
-很难总结为什么你应该考虑开发桌面应用,因为真的有很多类型的应用你可以创建。这非常取决于你想要达到什么目的,API 是否足够有利于开发,离线使用将多大程度上增强用户体验。在我的团队,这些都是毋庸置疑的,因为我们在开发一个[聊天应用程序](https://teamwork.com/chat)。另一方面来说,一个依赖于网络而没有任何与系统集成的桌面应用应该是一个 web 应用,并且只是 web 应用。当用户并不能从桌面应用中获得比在浏览器中访问一个网址更多的价值的时候,期待用户下载你的应用(其中自带浏览器以及 Node.js)是不公平的。
+很难总结为什么你应该考虑开发桌面应用,因为真的有很多类型的应用你可以创建。这非常取决于你想要达到什么目的,API 是否足够有利于开发,离线使用将多大程度上增强用户体验。在我的团队,这些都是毋庸置疑的,因为我们在开发一个[聊天应用程序](https://teamwork.com/chat)。另一方面来说,一个依赖于网络而没有任何与系统集成的桌面应用应该做成一个 web 应用,并且只做 web 应用。当用户并不能从桌面应用中获得比在浏览器中访问一个网址更多的价值的时候,期待用户下载你的应用(其中自带浏览器以及 Node.js)是不公平的。
-比起描述你个人应该建造的桌面应用以及为什么建造,我更希望的是激发一个想法,或者只是激发你对这篇文章的兴趣。继续往下读来看看用 web 技术构造一个强大的桌面应用是多么简单,以及需要承受的困难超过(或者相同)创造一个 web 应用。
+比起描述你个人应该建造的桌面应用及其原因,我更希望的是激发一个想法,或者只是激发你对这篇文章的兴趣。继续往下读来看看用 web 技术构造一个强大的桌面应用是多么简单,以及创建完成(或者在这过程中)一个 web 应用你需要承受什么。。
### NW.js
-桌面应用已经有很长一段时间了,我知道你没有很多时间,所以我们跳过一些历史,从2011年的上海开始。来自 Intel 开源技术中心的 Roger Wang 创造了 node-webkit,一个概念验证的 Node.js 模块,这个模块可以让用户生成一个自带 WebKit 内核的浏览器窗口并直接在 `
+
+
+
+
+
+
+
+
+ You signed in with another tab or window. Reload to refresh your session.
+ You signed out in another tab or window. Reload to refresh your session.
+
+
+
+
+
+
+
+
+
+
+
+
-> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[React](https://github.com/xitu/gold-miner#react)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计) 等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)。
From dea537b873dcacec4bc5b2ea99a122b7767799dc Mon Sep 17 00:00:00 2001
From: Wenlin Ou
Date: Fri, 7 Apr 2017 22:02:31 -0400
Subject: [PATCH 071/638] ...
---
...ng-will-change-until-you-start-building.md | 807 +-----------------
1 file changed, 47 insertions(+), 760 deletions(-)
diff --git a/TODO/nothing-will-change-until-you-start-building.md b/TODO/nothing-will-change-until-you-start-building.md
index 46f78f0efb5..0d57984107d 100644
--- a/TODO/nothing-will-change-until-you-start-building.md
+++ b/TODO/nothing-will-change-until-you-start-building.md
@@ -1,803 +1,90 @@
+> * 原文地址:[Nothing will change until you start building.](https://medium.freecodecamp.com/nothing-will-change-until-you-start-building-2681e85e7bdc)
+> * 原文作者:[Jonathan Z. White](https://medium.freecodecamp.com/@JonathanZWhite?source=post_header_lockup)
+> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
+> * 译者:
+> * 校对者:
+---
+![](https://cdn-images-1.medium.com/max/1000/1*EwHpnCZ70FtJMi-lNSl-9Q.png)
+# Nothing will change until you start building.
+This past week, I was in a Lyft. My driver was telling me about all of her ideas for side projects. She had ideas for a children’s book, an app that helps people find parking, and a more efficient way to package gifts. The problem was she was frozen by indecision. She had the ideas but she didn’t know where to start.
+This is what I told her. **Start by building. Pick one project and do whatever you have to do to ship it.** If you want to write a book, start with writing a page a day. If you want to build an app, start with some sketches. Anyone can do it.
-
-
-
-
+This advice applies to all creators. Once you start building and launching your projects, you won’t be able to stop. Building will become part of your identity. And even if your project fails, you’ll keep at it.
+The steps you take today will compound over time. Look at great product makers like [Drew Wilson](https://twitter.com/drewwilson), [Pieter Levels](https://twitter.com/levelsio?), and [Sebastian Dobrincu](https://twitter.com/Sebyddd). **They don’t wait for the right opportunity.** They build and ship weekly.
+In an interview on [IndieHackers](https://www.indiehackers.com/podcast/006-josh-pigford-of-baremetrics), [Josh Pigford](https://twitter.com/Shpigford) disclosed that before he built Baremetrics, he had iterated through a *hundred* failed ideas. Today, Baremetrics makes over 60,000 in monthly recurring revenue.
-
-
-
-
-
-
-
-
- gold-miner/nothing-will-change-until-you-start-building.md at translate · owenlyn/gold-miner
-
-
-
+![](https://cdn-images-1.medium.com/max/800/1*BzmVaqAKEzNRybUmMYOxdA.png)
-
-
+With that in mind, here are some tactics I’ve compiled from friends and acquaintances who are successful product makers.
-
-
-
-
-
-
+---
-
+### 1. Define your goal
-
-
-
+Early on, figure out the main goal of your project. If you want to break out of your usual design style, focus on the design. If you want to test a new framework for your front-end, focus on the code. If you want to acquire a hundred users, focus on selling.
-
-
+**Define your goal early so you don’t get distracted and end up not achieving what you set out to do.** Perhaps your project doesn’t become the next Snapchat, but by working towards your goal you will have honed the tools in your product-making arsenal. Little by little, you’ll be able to design, code, and sell faster and more efficiently.
+### 2. Stay on track
+Sometimes product makers fail to ship because they lose motivation. **Set small goals; meeting those goals will help you build momentum.** Small wins will compound.
+![](https://cdn-images-1.medium.com/max/800/1*ESildSVTSSOnFXGDxD-l9w.png)
-
+Another thing you can do to stay on track is to be more public about your work. Share your progress online and with your peers. People love to see things like wireframes and will often times provide valuable input.
+One trick that I find particularly motivating is making bets with friends. I tell them, if I don’t complete a task by a deadline, I’ll give them a hundred dollars. For example, I might set my task to getting twenty people to pay me within two weeks of launching a project.
-
+### 3. Solve a problem
-
-
+Start by solving a problem. If you have experienced the problem yourself, even better. Ask your friends what kind of problems they experience.
-
-
+For example, I built [YC Careers](http://jonathanzwhite.github.io/yc-careers/) and [AtomSpace](https://atomspace.co/) to address the needs of one my friends who was having trouble applying to jobs and interviewing as a product designer. Overnight, YC Careers made it to the top of [ProductHunt](https://www.producthunt.com/posts/yc-careers) and AtomSpace booked $100 dollars from strangers within 6 hours of going live.
+**The bigger the pain point you’re trying to solve, the easier it will be to find users.**
-
+Also, analyze problem-solutions from multiple perspectives. Some successful ideas might seem like a solution without a problem. For example, Instagram doesn’t seem to solve any immediate problem. But it does. Instagram solves the need for friends to stay updated on one another. If this need is not met, then it becomes a problem.
-
-
+For further reading, [John Carmack on Idea Generation](https://amasad.me/carmack) and [How to Get Startup Ideas](http://paulgraham.com/startupideas.html) are two great essays to get you started.
-
-
-
+### 4. Ditch the “good idea / bad idea” mindset
-
-
+Once you’ve identified a problem and come up with a solution, you’ll probably ask yourself if your idea is good.
+**Plenty of seemingly bad ideas have turned out to be great businesses.** For example, no one wanted to invest in Airbnb. Brian Chesky, one of the co-founders of Airbnb, detailed their rejections in his essay [7 Rejections](https://medium.com/@bchesky/7-rejections-7d894cbaa084#.l8fdqlasz).
-
+![](https://cdn-images-1.medium.com/max/800/1*WpxUxMCO-7NXr-o1yo023g.png)
+The only way to know for sure if your idea will work is to formulate a product hypothesis and run an experiment to test it. Talk to people and ask if they are interested in your solution. If you can get them to pay you before you’ve built anything, even better.
-
+### 5. Ask for help
-
+When working on a project, reach out to people and ask for their help. **You will be surprised at how many people are willing to pay it forward and help a complete stranger.**
-
-
+Some of the best advice and feedback I have received came from reaching out to people with an email or a DM on Twitter.
-
+Also, when asking for help, be specific and prepare your questions. If you want feedback on a design, send the mockup. If you want feedback on your marketing strategy, detail what you have tried so far. Context is key. And if you don’t get a response, follow up politely. Sometimes the person you’re reaching out to might have genuinely missed your message.
+---
-
+Build and launch your side projects. Use this process as a way to hone your craft so that when opportunity presents itself, you’re ready to take full advantage of it. Luck always favors the prepared.
-
+So next time you come up with an idea, act on it. Identify a problem, define your goal, stay on track, and ask for help.
-
-
+What are you working on right now? How can I help you? Leave me a note here or [tweet](https://twitter.com/jonathanzwhite) them to me on Twitter.
+You can find me on Medium where I publish every week. Or you can follow me on [Twitter](https://twitter.com/JonathanZWhite), where I post non-sensical ramblings about design, front-end development, and virtual reality.
-
-
-
- You can't perform that action at this time.
-
-
-
-
-
-
-
-
-
-
-
-
- You signed in with another tab or window. Reload to refresh your session.
- You signed out in another tab or window. Reload to refresh your session.
-
-
-
-
-
-
-
-
-
-
-
-
+---
+> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[React](https://github.com/xitu/gold-miner#react)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计) 等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)。
\ No newline at end of file
From b3a1f53af854a7ca405d5e19b9343feb4195b227 Mon Sep 17 00:00:00 2001
From: Wenlin Ou
Date: Fri, 7 Apr 2017 22:04:58 -0400
Subject: [PATCH 072/638] ready for proofreading
---
...ng-will-change-until-you-start-building.md | 70 +++++++++----------
1 file changed, 35 insertions(+), 35 deletions(-)
diff --git a/TODO/nothing-will-change-until-you-start-building.md b/TODO/nothing-will-change-until-you-start-building.md
index 0d57984107d..26cc605b437 100644
--- a/TODO/nothing-will-change-until-you-start-building.md
+++ b/TODO/nothing-will-change-until-you-start-building.md
@@ -1,90 +1,90 @@
> * 原文地址:[Nothing will change until you start building.](https://medium.freecodecamp.com/nothing-will-change-until-you-start-building-2681e85e7bdc)
> * 原文作者:[Jonathan Z. White](https://medium.freecodecamp.com/@JonathanZWhite?source=post_header_lockup)
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
-> * 译者:
+> * 译者:[owenlyn](https://github.com/owenlyn)
> * 校对者:
---
![](https://cdn-images-1.medium.com/max/1000/1*EwHpnCZ70FtJMi-lNSl-9Q.png)
-# Nothing will change until you start building.
+# Nothing will change until you start building. 真正行动之前 你将一无所成
-This past week, I was in a Lyft. My driver was telling me about all of her ideas for side projects. She had ideas for a children’s book, an app that helps people find parking, and a more efficient way to package gifts. The problem was she was frozen by indecision. She had the ideas but she didn’t know where to start.
+This past week, I was in a Lyft. My driver was telling me about all of her ideas for side projects. She had ideas for a children’s book, an app that helps people find parking, and a more efficient way to package gifts. The problem was she was frozen by indecision. She had the ideas but she didn’t know where to start.上周我打了一辆 Lyft 出租车,司机跟我聊了很多关于她的天花乱坠的想法。她的想法里,有一个关于儿童的书籍,有帮助人们停车的APP、有一个更高效的打包礼物的方法,但问题是她总是犹豫不决:她又想法但却不知道从何开始。
-This is what I told her. **Start by building. Pick one project and do whatever you have to do to ship it.** If you want to write a book, start with writing a page a day. If you want to build an app, start with some sketches. Anyone can do it.
+This is what I told her. **Start by building. Pick one project and do whatever you have to do to ship it.** If you want to write a book, start with writing a page a day. If you want to build an app, start with some sketches. Anyone can do it. 接下来这段话是我对她说的:**开始一些实际行动吧。选一个项目然后尽可能的去完成它。** 如果你想写一本书,那么从每天写一页开始;如果你像做一个APP,那就从草稿开始。任何人都可以做到这些。
-This advice applies to all creators. Once you start building and launching your projects, you won’t be able to stop. Building will become part of your identity. And even if your project fails, you’ll keep at it.
+This advice applies to all creators. Once you start building and launching your projects, you won’t be able to stop. Building will become part of your identity. And even if your project fails, you’ll keep at it. 这些建议对所有创新者都适用。一旦你开始着手在你的项目上,你将会不由自主的继续做下去。创新将会成为你人格的一部分 —— 即使你的项目失败了。
-The steps you take today will compound over time. Look at great product makers like [Drew Wilson](https://twitter.com/drewwilson), [Pieter Levels](https://twitter.com/levelsio?), and [Sebastian Dobrincu](https://twitter.com/Sebyddd). **They don’t wait for the right opportunity.** They build and ship weekly.
+The steps you take today will compound over time. Look at great product makers like [Drew Wilson](https://twitter.com/drewwilson), [Pieter Levels](https://twitter.com/levelsio?), and [Sebastian Dobrincu](https://twitter.com/Sebyddd). **They don’t wait for the right opportunity.** They build and ship weekly. 你今天迈出的一小步将会是你人生的一大步。看看那些伟大的产品创造者吧,比如 [Drew Wilson](https://twitter.com/drewwilson), [Pieter Levels](https://twitter.com/levelsio?), 和 [Sebastian Dobrincu](https://twitter.com/Sebyddd)。**他们不仅仅是等待合适的时机。** 他们每周都在更新他们的产品。
-In an interview on [IndieHackers](https://www.indiehackers.com/podcast/006-josh-pigford-of-baremetrics), [Josh Pigford](https://twitter.com/Shpigford) disclosed that before he built Baremetrics, he had iterated through a *hundred* failed ideas. Today, Baremetrics makes over 60,000 in monthly recurring revenue.
+In an interview on [IndieHackers](https://www.indiehackers.com/podcast/006-josh-pigford-of-baremetrics), [Josh Pigford](https://twitter.com/Shpigford) disclosed that before he built Baremetrics, he had iterated through a *hundred* failed ideas. Today, Baremetrics makes over 60,000 in monthly recurring revenue. 在一个 [IndieHackers](https://www.indiehackers.com/podcast/006-josh-pigford-of-baremetrics) 的节目中, [Josh Pigford](https://twitter.com/Shpigford) 透露,在做 Baremetrics 之前,他已经尝试过 *一百个* 失败的点子。 现在, Baremetrics 每个月都会有 60,000 美金进账。
![](https://cdn-images-1.medium.com/max/800/1*BzmVaqAKEzNRybUmMYOxdA.png)
-With that in mind, here are some tactics I’ve compiled from friends and acquaintances who are successful product makers.
+With that in mind, here are some tactics I’ve compiled from friends and acquaintances who are successful product makers.记住这些,接下来的要说的,是我总结的一些来自成功的产品创作者朋友们的策略。
---
-### 1. Define your goal
+### 1. Define your goal确定目标
-Early on, figure out the main goal of your project. If you want to break out of your usual design style, focus on the design. If you want to test a new framework for your front-end, focus on the code. If you want to acquire a hundred users, focus on selling.
+Early on, figure out the main goal of your project. If you want to break out of your usual design style, focus on the design. If you want to test a new framework for your front-end, focus on the code. If you want to acquire a hundred users, focus on selling.在开始的时候,确定你的项目要实现的主要目标。如果你想打破你以往的设计风格,那就把心思花在设计上;如果你测试一个新的前端框架,那就把钻研代码;如果你想获得上百个用户(”大量用户“ 会不会好点),就把精力用在销售上。
-**Define your goal early so you don’t get distracted and end up not achieving what you set out to do.** Perhaps your project doesn’t become the next Snapchat, but by working towards your goal you will have honed the tools in your product-making arsenal. Little by little, you’ll be able to design, code, and sell faster and more efficiently.
+**Define your goal early so you don’t get distracted and end up not achieving what you set out to do.** Perhaps your project doesn’t become the next Snapchat, but by working towards your goal you will have honed the tools in your product-making arsenal. Little by little, you’ll be able to design, code, and sell faster and more efficiently. **尽早确定目标可以帮助你摆脱诱惑,防止你到最后忘记初心。** 也许你的项目并不能成为下一个 Snapchat, 但是在通往你目标的道路上,你会更加的熟练运用各种做产品的工具。渐渐地,你会拥有越来越强大的设计、代码、销售等的能力。
-### 2. Stay on track
+### 2. Stay on track执行计划
-Sometimes product makers fail to ship because they lose motivation. **Set small goals; meeting those goals will help you build momentum.** Small wins will compound.
+Sometimes product makers fail to ship because they lose motivation. **Set small goals; meeting those goals will help you build momentum.** Small wins will compound. 有一些产品没能完的原因是作者在半路失去了动力。 **设定一些小目标(比如先赚一个亿);完成这些目标会让你获得前进的动力。** 小的成就累计起来也是很了不起的。
![](https://cdn-images-1.medium.com/max/800/1*ESildSVTSSOnFXGDxD-l9w.png)
-Another thing you can do to stay on track is to be more public about your work. Share your progress online and with your peers. People love to see things like wireframes and will often times provide valuable input.
+Another thing you can do to stay on track is to be more public about your work. Share your progress online and with your peers. People love to see things like wireframes and will often times provide valuable input.另一个让你保持动力的建议就是让你的项目更加公开。在网上和你的同行们分享你的进展。人们很喜欢看到线框(wireframe 翻译成 ”框架“ 会不会好一点?)类的东西,并常常带来有价值的投入。
-One trick that I find particularly motivating is making bets with friends. I tell them, if I don’t complete a task by a deadline, I’ll give them a hundred dollars. For example, I might set my task to getting twenty people to pay me within two weeks of launching a project.
+One trick that I find particularly motivating is making bets with friends. I tell them, if I don’t complete a task by a deadline, I’ll give them a hundred dollars. For example, I might set my task to getting twenty people to pay me within two weeks of launching a project.我自己找到的一个非常有用的保持动力的小秘诀是和朋友打赌。我对他们说,如果我在截止日期前没有完成某个任务,我就给他们一百刀。比如,我会在一个项目开始的两周内找到二十个人打赌。
-### 3. Solve a problem
+### 3. Solve a problem 解决一个问题
-Start by solving a problem. If you have experienced the problem yourself, even better. Ask your friends what kind of problems they experience.
+Start by solving a problem. If you have experienced the problem yourself, even better. Ask your friends what kind of problems they experience.解决一个问题。如果你自己也经历了这个问题那就再好不过了。问问你的朋友们他们都有哪些问题需要解决。
-For example, I built [YC Careers](http://jonathanzwhite.github.io/yc-careers/) and [AtomSpace](https://atomspace.co/) to address the needs of one my friends who was having trouble applying to jobs and interviewing as a product designer. Overnight, YC Careers made it to the top of [ProductHunt](https://www.producthunt.com/posts/yc-careers) and AtomSpace booked $100 dollars from strangers within 6 hours of going live.
+For example, I built [YC Careers](http://jonathanzwhite.github.io/yc-careers/) and [AtomSpace](https://atomspace.co/) to address the needs of one my friends who was having trouble applying to jobs and interviewing as a product designer. Overnight, YC Careers made it to the top of [ProductHunt](https://www.producthunt.com/posts/yc-careers) and AtomSpace booked $100 dollars from strangers within 6 hours of going live.比如,我做了 [YC Careers](http://jonathanzwhite.github.io/yc-careers/) 和 [AtomSpace](https://atomspace.co/) 来解决一个产品设计师朋友找工作和面试的烦恼。一夜之间,YC Careers 一下子爬到了 [ProductHunt](https://www.producthunt.com/posts/yc-careers) 的榜首,AtomSpace 在上线6个小时就拿到了来自陌生人的一百美元订单。
-**The bigger the pain point you’re trying to solve, the easier it will be to find users.**
+**The bigger the pain point you’re trying to solve, the easier it will be to find users.你尝试解决多大的痛点,找用户就有多容易。**
-Also, analyze problem-solutions from multiple perspectives. Some successful ideas might seem like a solution without a problem. For example, Instagram doesn’t seem to solve any immediate problem. But it does. Instagram solves the need for friends to stay updated on one another. If this need is not met, then it becomes a problem.
+Also, analyze problem-solutions from multiple perspectives. Some successful ideas might seem like a solution without a problem. For example, Instagram doesn’t seem to solve any immediate problem. But it does. Instagram solves the need for friends to stay updated on one another. If this need is not met, then it becomes a problem. 同时,尝试从过个角度分析问题和解决方案。有些成功的点子看起来并没有解决任何问题,但其实不然。比如,Instagram 看起来没有直接解决任何问题。其实不是。Instagram 满足了朋友之间实时社交的需求。如果这个需求不能得到满足,那才是个问题。
-For further reading, [John Carmack on Idea Generation](https://amasad.me/carmack) and [How to Get Startup Ideas](http://paulgraham.com/startupideas.html) are two great essays to get you started.
+For further reading, [John Carmack on Idea Generation](https://amasad.me/carmack) and [How to Get Startup Ideas](http://paulgraham.com/startupideas.html) are two great essays to get you started. 想要了解更多的话,[John Carmack on Idea Generation](https://amasad.me/carmack) 和 [How to Get Startup Ideas](http://paulgraham.com/startupideas.html) 这两篇文章是非常好的开始。
-### 4. Ditch the “good idea / bad idea” mindset
+### 4. Ditch the “good idea / bad idea” mindset 放弃”好主意/坏主意“的想法
-Once you’ve identified a problem and come up with a solution, you’ll probably ask yourself if your idea is good.
+Once you’ve identified a problem and come up with a solution, you’ll probably ask yourself if your idea is good.当你明确了你想要解决的问题并有了一个解决方案的时候,你可能会问自己这是不是一个好的点子。
-**Plenty of seemingly bad ideas have turned out to be great businesses.** For example, no one wanted to invest in Airbnb. Brian Chesky, one of the co-founders of Airbnb, detailed their rejections in his essay [7 Rejections](https://medium.com/@bchesky/7-rejections-7d894cbaa084#.l8fdqlasz).
+**Plenty of seemingly bad ideas have turned out to be great businesses.** For example, no one wanted to invest in Airbnb. Brian Chesky, one of the co-founders of Airbnb, detailed their rejections in his essay [7 Rejections](https://medium.com/@bchesky/7-rejections-7d894cbaa084#.l8fdqlasz). **相当一部分看起来很糟糕的点子最后被证明是超级棒的生意。** 比如,多年没人想投资 Airbnb。 Brian Chesky, Airbnb 的创始人之一,在他的文章 [7 Rejections](https://medium.com/@bchesky/7-rejections-7d894cbaa084#.l8fdqlasz) 里详细讲述了被投资人拒绝的故事。
![](https://cdn-images-1.medium.com/max/800/1*WpxUxMCO-7NXr-o1yo023g.png)
-The only way to know for sure if your idea will work is to formulate a product hypothesis and run an experiment to test it. Talk to people and ask if they are interested in your solution. If you can get them to pay you before you’ve built anything, even better.
+The only way to know for sure if your idea will work is to formulate a product hypothesis and run an experiment to test it. Talk to people and ask if they are interested in your solution. If you can get them to pay you before you’ve built anything, even better. 唯一验证你想法的办法就是做出一个产品来测试它。 找人聊聊,看看他们对你的解决方案是不是感兴趣。如果在你做出任何产品之前就有人原意为之付费那就再棒不过了。
-### 5. Ask for help
+### 5. Ask for help寻求帮助
-When working on a project, reach out to people and ask for their help. **You will be surprised at how many people are willing to pay it forward and help a complete stranger.**
+When working on a project, reach out to people and ask for their help. **You will be surprised at how many people are willing to pay it forward and help a complete stranger.** 当你在你的项目上埋头苦干的时候,记得寻求别人的帮助。 **你会很惊喜的发现竟然有这么多人原意去帮助一个陌生人(对,就是你)。**
-Some of the best advice and feedback I have received came from reaching out to people with an email or a DM on Twitter.
+Some of the best advice and feedback I have received came from reaching out to people with an email or a DM on Twitter. 我获得的最好的一部分建议就是来自于给别人发邮件或是推特(微博)私信。
-Also, when asking for help, be specific and prepare your questions. If you want feedback on a design, send the mockup. If you want feedback on your marketing strategy, detail what you have tried so far. Context is key. And if you don’t get a response, follow up politely. Sometimes the person you’re reaching out to might have genuinely missed your message.
+Also, when asking for help, be specific and prepare your questions. If you want feedback on a design, send the mockup. If you want feedback on your marketing strategy, detail what you have tried so far. Context is key. And if you don’t get a response, follow up politely. Sometimes the person you’re reaching out to might have genuinely missed your message. 在寻求帮助的时候,请提一些精确、有价值的问题。如果你需要关于设计的一些反馈,就把草稿发给别人;如果你需要营销方面的建议,就详细的列出你尝试过的方法。内容才是关键。如果别人没有回复你,请礼貌的再次询问 —— 有时候别人只是没注意到你的消息而已。
---
-Build and launch your side projects. Use this process as a way to hone your craft so that when opportunity presents itself, you’re ready to take full advantage of it. Luck always favors the prepared.
+Build and launch your side projects. Use this process as a way to hone your craft so that when opportunity presents itself, you’re ready to take full advantage of it. Luck always favors the prepared.开始你的兴趣项目吧。利用这个过程磨练自己,这样当机会来临的时候,你才能紧紧抓住。记住,机会总是青睐有准备的人。
-So next time you come up with an idea, act on it. Identify a problem, define your goal, stay on track, and ask for help.
+So next time you come up with an idea, act on it. Identify a problem, define your goal, stay on track, and ask for help.所以下次你有一个想法的时候,采取行动吧。找到一个问题,确定你的目标,坚持下去,别忘了学会寻求帮助。
-What are you working on right now? How can I help you? Leave me a note here or [tweet](https://twitter.com/jonathanzwhite) them to me on Twitter.
+What are you working on right now? How can I help you? Leave me a note here or [tweet](https://twitter.com/jonathanzwhite) them to me on Twitter.你现在在做神马项目呢?有什么是我能帮到你的吗?可以在这里或者我的 [tweet](https://twitter.com/jonathanzwhite) 下面留言。
-You can find me on Medium where I publish every week. Or you can follow me on [Twitter](https://twitter.com/JonathanZWhite), where I post non-sensical ramblings about design, front-end development, and virtual reality.
+You can find me on Medium where I publish every week. Or you can follow me on [Twitter](https://twitter.com/JonathanZWhite), where I post non-sensical ramblings about design, front-end development, and virtual reality. 我在 Medium 上每周都会发文。也可以关注我的 [Twitter](https://twitter.com/JonathanZWhite),我会发一些关于设计、前端开发和虚拟现实的杂想。
-*P.S. If you enjoyed this article, it would mean a lot if you click the 💚 and share with friends.*
+*P.S. If you enjoyed this article, it would mean a lot if you click the 💚 and share with friends.*(可删?)
---
-> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[React](https://github.com/xitu/gold-miner#react)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计) 等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)。
\ No newline at end of file
+> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[React](https://github.com/xitu/gold-miner#react)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计) 等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)。
From 784732d642d3393d58ce677312cb0e1f3854a8d8 Mon Sep 17 00:00:00 2001
From: Wenlin Ou
Date: Fri, 7 Apr 2017 22:06:28 -0400
Subject: [PATCH 073/638] ...
---
...ng-will-change-until-you-start-building.md | 780 ++++++++++++++++--
1 file changed, 733 insertions(+), 47 deletions(-)
diff --git a/TODO/nothing-will-change-until-you-start-building.md b/TODO/nothing-will-change-until-you-start-building.md
index 26cc605b437..df8d0872aa7 100644
--- a/TODO/nothing-will-change-until-you-start-building.md
+++ b/TODO/nothing-will-change-until-you-start-building.md
@@ -1,90 +1,776 @@
-> * 原文地址:[Nothing will change until you start building.](https://medium.freecodecamp.com/nothing-will-change-until-you-start-building-2681e85e7bdc)
-> * 原文作者:[Jonathan Z. White](https://medium.freecodecamp.com/@JonathanZWhite?source=post_header_lockup)
-> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
-> * 译者:[owenlyn](https://github.com/owenlyn)
-> * 校对者:
----
-![](https://cdn-images-1.medium.com/max/1000/1*EwHpnCZ70FtJMi-lNSl-9Q.png)
-# Nothing will change until you start building. 真正行动之前 你将一无所成
-This past week, I was in a Lyft. My driver was telling me about all of her ideas for side projects. She had ideas for a children’s book, an app that helps people find parking, and a more efficient way to package gifts. The problem was she was frozen by indecision. She had the ideas but she didn’t know where to start.上周我打了一辆 Lyft 出租车,司机跟我聊了很多关于她的天花乱坠的想法。她的想法里,有一个关于儿童的书籍,有帮助人们停车的APP、有一个更高效的打包礼物的方法,但问题是她总是犹豫不决:她又想法但却不知道从何开始。
-This is what I told her. **Start by building. Pick one project and do whatever you have to do to ship it.** If you want to write a book, start with writing a page a day. If you want to build an app, start with some sketches. Anyone can do it. 接下来这段话是我对她说的:**开始一些实际行动吧。选一个项目然后尽可能的去完成它。** 如果你想写一本书,那么从每天写一页开始;如果你像做一个APP,那就从草稿开始。任何人都可以做到这些。
-This advice applies to all creators. Once you start building and launching your projects, you won’t be able to stop. Building will become part of your identity. And even if your project fails, you’ll keep at it. 这些建议对所有创新者都适用。一旦你开始着手在你的项目上,你将会不由自主的继续做下去。创新将会成为你人格的一部分 —— 即使你的项目失败了。
+
+
+
+
-The steps you take today will compound over time. Look at great product makers like [Drew Wilson](https://twitter.com/drewwilson), [Pieter Levels](https://twitter.com/levelsio?), and [Sebastian Dobrincu](https://twitter.com/Sebyddd). **They don’t wait for the right opportunity.** They build and ship weekly. 你今天迈出的一小步将会是你人生的一大步。看看那些伟大的产品创造者吧,比如 [Drew Wilson](https://twitter.com/drewwilson), [Pieter Levels](https://twitter.com/levelsio?), 和 [Sebastian Dobrincu](https://twitter.com/Sebyddd)。**他们不仅仅是等待合适的时机。** 他们每周都在更新他们的产品。
-In an interview on [IndieHackers](https://www.indiehackers.com/podcast/006-josh-pigford-of-baremetrics), [Josh Pigford](https://twitter.com/Shpigford) disclosed that before he built Baremetrics, he had iterated through a *hundred* failed ideas. Today, Baremetrics makes over 60,000 in monthly recurring revenue. 在一个 [IndieHackers](https://www.indiehackers.com/podcast/006-josh-pigford-of-baremetrics) 的节目中, [Josh Pigford](https://twitter.com/Shpigford) 透露,在做 Baremetrics 之前,他已经尝试过 *一百个* 失败的点子。 现在, Baremetrics 每个月都会有 60,000 美金进账。
+
+
+
+
+
+
-![](https://cdn-images-1.medium.com/max/800/1*BzmVaqAKEzNRybUmMYOxdA.png)
+
+
+ gold-miner/nothing-will-change-until-you-start-building.md at master · xitu/gold-miner
+
+
+
-With that in mind, here are some tactics I’ve compiled from friends and acquaintances who are successful product makers.记住这些,接下来的要说的,是我总结的一些来自成功的产品创作者朋友们的策略。
+
+
----
+
+
+
+
+
+
-### 1. Define your goal确定目标
+
-Early on, figure out the main goal of your project. If you want to break out of your usual design style, focus on the design. If you want to test a new framework for your front-end, focus on the code. If you want to acquire a hundred users, focus on selling.在开始的时候,确定你的项目要实现的主要目标。如果你想打破你以往的设计风格,那就把心思花在设计上;如果你测试一个新的前端框架,那就把钻研代码;如果你想获得上百个用户(”大量用户“ 会不会好点),就把精力用在销售上。
+
+
+
-**Define your goal early so you don’t get distracted and end up not achieving what you set out to do.** Perhaps your project doesn’t become the next Snapchat, but by working towards your goal you will have honed the tools in your product-making arsenal. Little by little, you’ll be able to design, code, and sell faster and more efficiently. **尽早确定目标可以帮助你摆脱诱惑,防止你到最后忘记初心。** 也许你的项目并不能成为下一个 Snapchat, 但是在通往你目标的道路上,你会更加的熟练运用各种做产品的工具。渐渐地,你会拥有越来越强大的设计、代码、销售等的能力。
+
+
-### 2. Stay on track执行计划
-Sometimes product makers fail to ship because they lose motivation. **Set small goals; meeting those goals will help you build momentum.** Small wins will compound. 有一些产品没能完的原因是作者在半路失去了动力。 **设定一些小目标(比如先赚一个亿);完成这些目标会让你获得前进的动力。** 小的成就累计起来也是很了不起的。
-![](https://cdn-images-1.medium.com/max/800/1*ESildSVTSSOnFXGDxD-l9w.png)
-Another thing you can do to stay on track is to be more public about your work. Share your progress online and with your peers. People love to see things like wireframes and will often times provide valuable input.另一个让你保持动力的建议就是让你的项目更加公开。在网上和你的同行们分享你的进展。人们很喜欢看到线框(wireframe 翻译成 ”框架“ 会不会好一点?)类的东西,并常常带来有价值的投入。
+
-One trick that I find particularly motivating is making bets with friends. I tell them, if I don’t complete a task by a deadline, I’ll give them a hundred dollars. For example, I might set my task to getting twenty people to pay me within two weeks of launching a project.我自己找到的一个非常有用的保持动力的小秘诀是和朋友打赌。我对他们说,如果我在截止日期前没有完成某个任务,我就给他们一百刀。比如,我会在一个项目开始的两周内找到二十个人打赌。
-### 3. Solve a problem 解决一个问题
+
-Start by solving a problem. If you have experienced the problem yourself, even better. Ask your friends what kind of problems they experience.解决一个问题。如果你自己也经历了这个问题那就再好不过了。问问你的朋友们他们都有哪些问题需要解决。
+
+
-For example, I built [YC Careers](http://jonathanzwhite.github.io/yc-careers/) and [AtomSpace](https://atomspace.co/) to address the needs of one my friends who was having trouble applying to jobs and interviewing as a product designer. Overnight, YC Careers made it to the top of [ProductHunt](https://www.producthunt.com/posts/yc-careers) and AtomSpace booked $100 dollars from strangers within 6 hours of going live.比如,我做了 [YC Careers](http://jonathanzwhite.github.io/yc-careers/) 和 [AtomSpace](https://atomspace.co/) 来解决一个产品设计师朋友找工作和面试的烦恼。一夜之间,YC Careers 一下子爬到了 [ProductHunt](https://www.producthunt.com/posts/yc-careers) 的榜首,AtomSpace 在上线6个小时就拿到了来自陌生人的一百美元订单。
+
+
-**The bigger the pain point you’re trying to solve, the easier it will be to find users.你尝试解决多大的痛点,找用户就有多容易。**
-Also, analyze problem-solutions from multiple perspectives. Some successful ideas might seem like a solution without a problem. For example, Instagram doesn’t seem to solve any immediate problem. But it does. Instagram solves the need for friends to stay updated on one another. If this need is not met, then it becomes a problem. 同时,尝试从过个角度分析问题和解决方案。有些成功的点子看起来并没有解决任何问题,但其实不然。比如,Instagram 看起来没有直接解决任何问题。其实不是。Instagram 满足了朋友之间实时社交的需求。如果这个需求不能得到满足,那才是个问题。
+
-For further reading, [John Carmack on Idea Generation](https://amasad.me/carmack) and [How to Get Startup Ideas](http://paulgraham.com/startupideas.html) are two great essays to get you started. 想要了解更多的话,[John Carmack on Idea Generation](https://amasad.me/carmack) 和 [How to Get Startup Ideas](http://paulgraham.com/startupideas.html) 这两篇文章是非常好的开始。
+
+
-### 4. Ditch the “good idea / bad idea” mindset 放弃”好主意/坏主意“的想法
+
+
+
-Once you’ve identified a problem and come up with a solution, you’ll probably ask yourself if your idea is good.当你明确了你想要解决的问题并有了一个解决方案的时候,你可能会问自己这是不是一个好的点子。
+
+
-**Plenty of seemingly bad ideas have turned out to be great businesses.** For example, no one wanted to invest in Airbnb. Brian Chesky, one of the co-founders of Airbnb, detailed their rejections in his essay [7 Rejections](https://medium.com/@bchesky/7-rejections-7d894cbaa084#.l8fdqlasz). **相当一部分看起来很糟糕的点子最后被证明是超级棒的生意。** 比如,多年没人想投资 Airbnb。 Brian Chesky, Airbnb 的创始人之一,在他的文章 [7 Rejections](https://medium.com/@bchesky/7-rejections-7d894cbaa084#.l8fdqlasz) 里详细讲述了被投资人拒绝的故事。
-![](https://cdn-images-1.medium.com/max/800/1*WpxUxMCO-7NXr-o1yo023g.png)
+
-The only way to know for sure if your idea will work is to formulate a product hypothesis and run an experiment to test it. Talk to people and ask if they are interested in your solution. If you can get them to pay you before you’ve built anything, even better. 唯一验证你想法的办法就是做出一个产品来测试它。 找人聊聊,看看他们对你的解决方案是不是感兴趣。如果在你做出任何产品之前就有人原意为之付费那就再棒不过了。
-### 5. Ask for help寻求帮助
+
-When working on a project, reach out to people and ask for their help. **You will be surprised at how many people are willing to pay it forward and help a complete stranger.** 当你在你的项目上埋头苦干的时候,记得寻求别人的帮助。 **你会很惊喜的发现竟然有这么多人原意去帮助一个陌生人(对,就是你)。**
+
-Some of the best advice and feedback I have received came from reaching out to people with an email or a DM on Twitter. 我获得的最好的一部分建议就是来自于给别人发邮件或是推特(微博)私信。
+
+
-Also, when asking for help, be specific and prepare your questions. If you want feedback on a design, send the mockup. If you want feedback on your marketing strategy, detail what you have tried so far. Context is key. And if you don’t get a response, follow up politely. Sometimes the person you’re reaching out to might have genuinely missed your message. 在寻求帮助的时候,请提一些精确、有价值的问题。如果你需要关于设计的一些反馈,就把草稿发给别人;如果你需要营销方面的建议,就详细的列出你尝试过的方法。内容才是关键。如果别人没有回复你,请礼貌的再次询问 —— 有时候别人只是没注意到你的消息而已。
+
----
-Build and launch your side projects. Use this process as a way to hone your craft so that when opportunity presents itself, you’re ready to take full advantage of it. Luck always favors the prepared.开始你的兴趣项目吧。利用这个过程磨练自己,这样当机会来临的时候,你才能紧紧抓住。记住,机会总是青睐有准备的人。
+
-So next time you come up with an idea, act on it. Identify a problem, define your goal, stay on track, and ask for help.所以下次你有一个想法的时候,采取行动吧。找到一个问题,确定你的目标,坚持下去,别忘了学会寻求帮助。
+
-What are you working on right now? How can I help you? Leave me a note here or [tweet](https://twitter.com/jonathanzwhite) them to me on Twitter.你现在在做神马项目呢?有什么是我能帮到你的吗?可以在这里或者我的 [tweet](https://twitter.com/jonathanzwhite) 下面留言。
+
+
-You can find me on Medium where I publish every week. Or you can follow me on [Twitter](https://twitter.com/JonathanZWhite), where I post non-sensical ramblings about design, front-end development, and virtual reality. 我在 Medium 上每周都会发文。也可以关注我的 [Twitter](https://twitter.com/JonathanZWhite),我会发一些关于设计、前端开发和虚拟现实的杂想。
-*P.S. If you enjoyed this article, it would mean a lot if you click the 💚 and share with friends.*(可删?)
+
This past week, I was in a Lyft. My driver was telling me about all of her ideas for side projects. She had ideas for a children’s book, an app that helps people find parking, and a more efficient way to package gifts. The problem was she was frozen by indecision. She had the ideas but she didn’t know where to start.
+
This is what I told her. Start by building. Pick one project and do whatever you have to do to ship it. If you want to write a book, start with writing a page a day. If you want to build an app, start with some sketches. Anyone can do it.
+
This advice applies to all creators. Once you start building and launching your projects, you won’t be able to stop. Building will become part of your identity. And even if your project fails, you’ll keep at it.
+
The steps you take today will compound over time. Look at great product makers like Drew Wilson, Pieter Levels, and Sebastian Dobrincu. They don’t wait for the right opportunity. They build and ship weekly.
+
In an interview on IndieHackers, Josh Pigford disclosed that before he built Baremetrics, he had iterated through a hundred failed ideas. Today, Baremetrics makes over 60,000 in monthly recurring revenue.
+
+
With that in mind, here are some tactics I’ve compiled from friends and acquaintances who are successful product makers.
+
+
1. Define your goal
+
Early on, figure out the main goal of your project. If you want to break out of your usual design style, focus on the design. If you want to test a new framework for your front-end, focus on the code. If you want to acquire a hundred users, focus on selling.
+
Define your goal early so you don’t get distracted and end up not achieving what you set out to do. Perhaps your project doesn’t become the next Snapchat, but by working towards your goal you will have honed the tools in your product-making arsenal. Little by little, you’ll be able to design, code, and sell faster and more efficiently.
+
2. Stay on track
+
Sometimes product makers fail to ship because they lose motivation. Set small goals; meeting those goals will help you build momentum. Small wins will compound.
+
+
Another thing you can do to stay on track is to be more public about your work. Share your progress online and with your peers. People love to see things like wireframes and will often times provide valuable input.
+
One trick that I find particularly motivating is making bets with friends. I tell them, if I don’t complete a task by a deadline, I’ll give them a hundred dollars. For example, I might set my task to getting twenty people to pay me within two weeks of launching a project.
+
3. Solve a problem
+
Start by solving a problem. If you have experienced the problem yourself, even better. Ask your friends what kind of problems they experience.
+
For example, I built YC Careers and AtomSpace to address the needs of one my friends who was having trouble applying to jobs and interviewing as a product designer. Overnight, YC Careers made it to the top of ProductHunt and AtomSpace booked $100 dollars from strangers within 6 hours of going live.
+
The bigger the pain point you’re trying to solve, the easier it will be to find users.
+
Also, analyze problem-solutions from multiple perspectives. Some successful ideas might seem like a solution without a problem. For example, Instagram doesn’t seem to solve any immediate problem. But it does. Instagram solves the need for friends to stay updated on one another. If this need is not met, then it becomes a problem.
Once you’ve identified a problem and come up with a solution, you’ll probably ask yourself if your idea is good.
+
Plenty of seemingly bad ideas have turned out to be great businesses. For example, no one wanted to invest in Airbnb. Brian Chesky, one of the co-founders of Airbnb, detailed their rejections in his essay 7 Rejections.
+
+
The only way to know for sure if your idea will work is to formulate a product hypothesis and run an experiment to test it. Talk to people and ask if they are interested in your solution. If you can get them to pay you before you’ve built anything, even better.
+
5. Ask for help
+
When working on a project, reach out to people and ask for their help. You will be surprised at how many people are willing to pay it forward and help a complete stranger.
+
Some of the best advice and feedback I have received came from reaching out to people with an email or a DM on Twitter.
+
Also, when asking for help, be specific and prepare your questions. If you want feedback on a design, send the mockup. If you want feedback on your marketing strategy, detail what you have tried so far. Context is key. And if you don’t get a response, follow up politely. Sometimes the person you’re reaching out to might have genuinely missed your message.
+
+
Build and launch your side projects. Use this process as a way to hone your craft so that when opportunity presents itself, you’re ready to take full advantage of it. Luck always favors the prepared.
+
So next time you come up with an idea, act on it. Identify a problem, define your goal, stay on track, and ask for help.
+
What are you working on right now? How can I help you? Leave me a note here or tweet them to me on Twitter.
+
You can find me on Medium where I publish every week. Or you can follow me on Twitter, where I post non-sensical ramblings about design, front-end development, and virtual reality.
+
P.S. If you enjoyed this article, it would mean a lot if you click the 💚 and share with friends.
+
+
+ You can't perform that action at this time.
+
+
+
+
+
+
+
+
+
+
+
+
+ You signed in with another tab or window. Reload to refresh your session.
+ You signed out in another tab or window. Reload to refresh your session.
+
+
+
+
+
+
+
+
+
+
+
+
-> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[React](https://github.com/xitu/gold-miner#react)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计) 等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)。
From c61a1606f3499108f7170f24c3937f5428968021 Mon Sep 17 00:00:00 2001
From: Wenlin Ou
Date: Fri, 7 Apr 2017 22:07:53 -0400
Subject: [PATCH 074/638] ...
---
...ng-will-change-until-you-start-building.md | 780 ++----------------
1 file changed, 47 insertions(+), 733 deletions(-)
diff --git a/TODO/nothing-will-change-until-you-start-building.md b/TODO/nothing-will-change-until-you-start-building.md
index df8d0872aa7..0d57984107d 100644
--- a/TODO/nothing-will-change-until-you-start-building.md
+++ b/TODO/nothing-will-change-until-you-start-building.md
@@ -1,776 +1,90 @@
+> * 原文地址:[Nothing will change until you start building.](https://medium.freecodecamp.com/nothing-will-change-until-you-start-building-2681e85e7bdc)
+> * 原文作者:[Jonathan Z. White](https://medium.freecodecamp.com/@JonathanZWhite?source=post_header_lockup)
+> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
+> * 译者:
+> * 校对者:
+---
+![](https://cdn-images-1.medium.com/max/1000/1*EwHpnCZ70FtJMi-lNSl-9Q.png)
+# Nothing will change until you start building.
+This past week, I was in a Lyft. My driver was telling me about all of her ideas for side projects. She had ideas for a children’s book, an app that helps people find parking, and a more efficient way to package gifts. The problem was she was frozen by indecision. She had the ideas but she didn’t know where to start.
+This is what I told her. **Start by building. Pick one project and do whatever you have to do to ship it.** If you want to write a book, start with writing a page a day. If you want to build an app, start with some sketches. Anyone can do it.
-
-
-
-
+This advice applies to all creators. Once you start building and launching your projects, you won’t be able to stop. Building will become part of your identity. And even if your project fails, you’ll keep at it.
+The steps you take today will compound over time. Look at great product makers like [Drew Wilson](https://twitter.com/drewwilson), [Pieter Levels](https://twitter.com/levelsio?), and [Sebastian Dobrincu](https://twitter.com/Sebyddd). **They don’t wait for the right opportunity.** They build and ship weekly.
+In an interview on [IndieHackers](https://www.indiehackers.com/podcast/006-josh-pigford-of-baremetrics), [Josh Pigford](https://twitter.com/Shpigford) disclosed that before he built Baremetrics, he had iterated through a *hundred* failed ideas. Today, Baremetrics makes over 60,000 in monthly recurring revenue.
-
-
-
-
-
-
-
-
- gold-miner/nothing-will-change-until-you-start-building.md at master · xitu/gold-miner
-
-
-
+![](https://cdn-images-1.medium.com/max/800/1*BzmVaqAKEzNRybUmMYOxdA.png)
-
-
+With that in mind, here are some tactics I’ve compiled from friends and acquaintances who are successful product makers.
-
-
-
-
-
-
+---
-
+### 1. Define your goal
-
-
-
+Early on, figure out the main goal of your project. If you want to break out of your usual design style, focus on the design. If you want to test a new framework for your front-end, focus on the code. If you want to acquire a hundred users, focus on selling.
-
-
+**Define your goal early so you don’t get distracted and end up not achieving what you set out to do.** Perhaps your project doesn’t become the next Snapchat, but by working towards your goal you will have honed the tools in your product-making arsenal. Little by little, you’ll be able to design, code, and sell faster and more efficiently.
+### 2. Stay on track
+Sometimes product makers fail to ship because they lose motivation. **Set small goals; meeting those goals will help you build momentum.** Small wins will compound.
+![](https://cdn-images-1.medium.com/max/800/1*ESildSVTSSOnFXGDxD-l9w.png)
-
+Another thing you can do to stay on track is to be more public about your work. Share your progress online and with your peers. People love to see things like wireframes and will often times provide valuable input.
+One trick that I find particularly motivating is making bets with friends. I tell them, if I don’t complete a task by a deadline, I’ll give them a hundred dollars. For example, I might set my task to getting twenty people to pay me within two weeks of launching a project.
-
+### 3. Solve a problem
-
-
+Start by solving a problem. If you have experienced the problem yourself, even better. Ask your friends what kind of problems they experience.
-
-
+For example, I built [YC Careers](http://jonathanzwhite.github.io/yc-careers/) and [AtomSpace](https://atomspace.co/) to address the needs of one my friends who was having trouble applying to jobs and interviewing as a product designer. Overnight, YC Careers made it to the top of [ProductHunt](https://www.producthunt.com/posts/yc-careers) and AtomSpace booked $100 dollars from strangers within 6 hours of going live.
+**The bigger the pain point you’re trying to solve, the easier it will be to find users.**
-
+Also, analyze problem-solutions from multiple perspectives. Some successful ideas might seem like a solution without a problem. For example, Instagram doesn’t seem to solve any immediate problem. But it does. Instagram solves the need for friends to stay updated on one another. If this need is not met, then it becomes a problem.
-
-
+For further reading, [John Carmack on Idea Generation](https://amasad.me/carmack) and [How to Get Startup Ideas](http://paulgraham.com/startupideas.html) are two great essays to get you started.
-
-
-
+### 4. Ditch the “good idea / bad idea” mindset
-
-
+Once you’ve identified a problem and come up with a solution, you’ll probably ask yourself if your idea is good.
+**Plenty of seemingly bad ideas have turned out to be great businesses.** For example, no one wanted to invest in Airbnb. Brian Chesky, one of the co-founders of Airbnb, detailed their rejections in his essay [7 Rejections](https://medium.com/@bchesky/7-rejections-7d894cbaa084#.l8fdqlasz).
-
+![](https://cdn-images-1.medium.com/max/800/1*WpxUxMCO-7NXr-o1yo023g.png)
+The only way to know for sure if your idea will work is to formulate a product hypothesis and run an experiment to test it. Talk to people and ask if they are interested in your solution. If you can get them to pay you before you’ve built anything, even better.
-
+### 5. Ask for help
-
+When working on a project, reach out to people and ask for their help. **You will be surprised at how many people are willing to pay it forward and help a complete stranger.**
-
-
+Some of the best advice and feedback I have received came from reaching out to people with an email or a DM on Twitter.
-
+Also, when asking for help, be specific and prepare your questions. If you want feedback on a design, send the mockup. If you want feedback on your marketing strategy, detail what you have tried so far. Context is key. And if you don’t get a response, follow up politely. Sometimes the person you’re reaching out to might have genuinely missed your message.
+---
-
+Build and launch your side projects. Use this process as a way to hone your craft so that when opportunity presents itself, you’re ready to take full advantage of it. Luck always favors the prepared.
-
+So next time you come up with an idea, act on it. Identify a problem, define your goal, stay on track, and ask for help.
-
-
+What are you working on right now? How can I help you? Leave me a note here or [tweet](https://twitter.com/jonathanzwhite) them to me on Twitter.
+You can find me on Medium where I publish every week. Or you can follow me on [Twitter](https://twitter.com/JonathanZWhite), where I post non-sensical ramblings about design, front-end development, and virtual reality.
-
This past week, I was in a Lyft. My driver was telling me about all of her ideas for side projects. She had ideas for a children’s book, an app that helps people find parking, and a more efficient way to package gifts. The problem was she was frozen by indecision. She had the ideas but she didn’t know where to start.
-
This is what I told her. Start by building. Pick one project and do whatever you have to do to ship it. If you want to write a book, start with writing a page a day. If you want to build an app, start with some sketches. Anyone can do it.
-
This advice applies to all creators. Once you start building and launching your projects, you won’t be able to stop. Building will become part of your identity. And even if your project fails, you’ll keep at it.
-
The steps you take today will compound over time. Look at great product makers like Drew Wilson, Pieter Levels, and Sebastian Dobrincu. They don’t wait for the right opportunity. They build and ship weekly.
-
In an interview on IndieHackers, Josh Pigford disclosed that before he built Baremetrics, he had iterated through a hundred failed ideas. Today, Baremetrics makes over 60,000 in monthly recurring revenue.
-
-
With that in mind, here are some tactics I’ve compiled from friends and acquaintances who are successful product makers.
-
-
1. Define your goal
-
Early on, figure out the main goal of your project. If you want to break out of your usual design style, focus on the design. If you want to test a new framework for your front-end, focus on the code. If you want to acquire a hundred users, focus on selling.
-
Define your goal early so you don’t get distracted and end up not achieving what you set out to do. Perhaps your project doesn’t become the next Snapchat, but by working towards your goal you will have honed the tools in your product-making arsenal. Little by little, you’ll be able to design, code, and sell faster and more efficiently.
-
2. Stay on track
-
Sometimes product makers fail to ship because they lose motivation. Set small goals; meeting those goals will help you build momentum. Small wins will compound.
-
-
Another thing you can do to stay on track is to be more public about your work. Share your progress online and with your peers. People love to see things like wireframes and will often times provide valuable input.
-
One trick that I find particularly motivating is making bets with friends. I tell them, if I don’t complete a task by a deadline, I’ll give them a hundred dollars. For example, I might set my task to getting twenty people to pay me within two weeks of launching a project.
-
3. Solve a problem
-
Start by solving a problem. If you have experienced the problem yourself, even better. Ask your friends what kind of problems they experience.
-
For example, I built YC Careers and AtomSpace to address the needs of one my friends who was having trouble applying to jobs and interviewing as a product designer. Overnight, YC Careers made it to the top of ProductHunt and AtomSpace booked $100 dollars from strangers within 6 hours of going live.
-
The bigger the pain point you’re trying to solve, the easier it will be to find users.
-
Also, analyze problem-solutions from multiple perspectives. Some successful ideas might seem like a solution without a problem. For example, Instagram doesn’t seem to solve any immediate problem. But it does. Instagram solves the need for friends to stay updated on one another. If this need is not met, then it becomes a problem.
Once you’ve identified a problem and come up with a solution, you’ll probably ask yourself if your idea is good.
-
Plenty of seemingly bad ideas have turned out to be great businesses. For example, no one wanted to invest in Airbnb. Brian Chesky, one of the co-founders of Airbnb, detailed their rejections in his essay 7 Rejections.
-
-
The only way to know for sure if your idea will work is to formulate a product hypothesis and run an experiment to test it. Talk to people and ask if they are interested in your solution. If you can get them to pay you before you’ve built anything, even better.
-
5. Ask for help
-
When working on a project, reach out to people and ask for their help. You will be surprised at how many people are willing to pay it forward and help a complete stranger.
-
Some of the best advice and feedback I have received came from reaching out to people with an email or a DM on Twitter.
-
Also, when asking for help, be specific and prepare your questions. If you want feedback on a design, send the mockup. If you want feedback on your marketing strategy, detail what you have tried so far. Context is key. And if you don’t get a response, follow up politely. Sometimes the person you’re reaching out to might have genuinely missed your message.
-
-
Build and launch your side projects. Use this process as a way to hone your craft so that when opportunity presents itself, you’re ready to take full advantage of it. Luck always favors the prepared.
-
So next time you come up with an idea, act on it. Identify a problem, define your goal, stay on track, and ask for help.
-
What are you working on right now? How can I help you? Leave me a note here or tweet them to me on Twitter.
-
You can find me on Medium where I publish every week. Or you can follow me on Twitter, where I post non-sensical ramblings about design, front-end development, and virtual reality.
-
P.S. If you enjoyed this article, it would mean a lot if you click the 💚 and share with friends.
-
-
- You can't perform that action at this time.
-
-
-
-
-
-
-
-
-
-
-
-
- You signed in with another tab or window. Reload to refresh your session.
- You signed out in another tab or window. Reload to refresh your session.
-
-
-
-
-
-
-
-
-
-
-
-
+---
+> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[React](https://github.com/xitu/gold-miner#react)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计) 等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)。
\ No newline at end of file
From f4857dd5c82e2387af2c9ffbd88d767f974a0866 Mon Sep 17 00:00:00 2001
From: Wenlin Ou
Date: Fri, 7 Apr 2017 22:15:49 -0400
Subject: [PATCH 075/638] get ready for proofreading
---
...ng-will-change-until-you-start-building.md | 70 +++++++++----------
1 file changed, 35 insertions(+), 35 deletions(-)
diff --git a/TODO/nothing-will-change-until-you-start-building.md b/TODO/nothing-will-change-until-you-start-building.md
index 0d57984107d..7d9880eb6ba 100644
--- a/TODO/nothing-will-change-until-you-start-building.md
+++ b/TODO/nothing-will-change-until-you-start-building.md
@@ -1,90 +1,90 @@
> * 原文地址:[Nothing will change until you start building.](https://medium.freecodecamp.com/nothing-will-change-until-you-start-building-2681e85e7bdc)
> * 原文作者:[Jonathan Z. White](https://medium.freecodecamp.com/@JonathanZWhite?source=post_header_lockup)
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
-> * 译者:
+> * 译者:[owenlyn](https://github.com/owenlyn)
> * 校对者:
---
![](https://cdn-images-1.medium.com/max/1000/1*EwHpnCZ70FtJMi-lNSl-9Q.png)
-# Nothing will change until you start building.
+# 真正行动之前 你将一无所成
-This past week, I was in a Lyft. My driver was telling me about all of her ideas for side projects. She had ideas for a children’s book, an app that helps people find parking, and a more efficient way to package gifts. The problem was she was frozen by indecision. She had the ideas but she didn’t know where to start.
+就在上周我打了一辆 Lyft 出租车,司机跟我聊了很多关于她的天花乱坠的想法。她的想法里,有一个关于儿童的书籍,有帮助人们停车的APP、有一个更高效的打包礼物的方法,但问题是她总是犹豫不决:她又想法但却不知道从何开始。
-This is what I told her. **Start by building. Pick one project and do whatever you have to do to ship it.** If you want to write a book, start with writing a page a day. If you want to build an app, start with some sketches. Anyone can do it.
+接下来这段话是我对她说的:**开始一些实际行动吧。选一个项目然后尽可能的去完成它。** 如果你想写一本书,那么从每天写一页开始;如果你像做一个APP,那就从草稿开始。任何人都可以做到这些。
-This advice applies to all creators. Once you start building and launching your projects, you won’t be able to stop. Building will become part of your identity. And even if your project fails, you’ll keep at it.
+这些建议对所有创新者都适用。一旦你开始着手在你的项目上,你将会不由自主的继续做下去。创新将会成为你人格的一部分 —— 即使你的项目失败了。
-The steps you take today will compound over time. Look at great product makers like [Drew Wilson](https://twitter.com/drewwilson), [Pieter Levels](https://twitter.com/levelsio?), and [Sebastian Dobrincu](https://twitter.com/Sebyddd). **They don’t wait for the right opportunity.** They build and ship weekly.
+你今天迈出的一小步将会是你人生的一大步。看看那些伟大的产品创造者吧,比如 [Drew Wilson](https://twitter.com/drewwilson), [Pieter Levels](https://twitter.com/levelsio?), 和 [Sebastian Dobrincu](https://twitter.com/Sebyddd)。**他们不仅仅是等待合适的时机。** 他们每周都在更新他们的产品。
-In an interview on [IndieHackers](https://www.indiehackers.com/podcast/006-josh-pigford-of-baremetrics), [Josh Pigford](https://twitter.com/Shpigford) disclosed that before he built Baremetrics, he had iterated through a *hundred* failed ideas. Today, Baremetrics makes over 60,000 in monthly recurring revenue.
+在一个 [IndieHackers](https://www.indiehackers.com/podcast/006-josh-pigford-of-baremetrics) 的节目中, [Josh Pigford](https://twitter.com/Shpigford) 透露,在做 Baremetrics 之前,他已经尝试过 *一百个* 失败的点子。 现在, Baremetrics 每个月都会有 60,000 美金进账。
![](https://cdn-images-1.medium.com/max/800/1*BzmVaqAKEzNRybUmMYOxdA.png)
-With that in mind, here are some tactics I’ve compiled from friends and acquaintances who are successful product makers.
+记住这些,接下来的要说的,是我总结的一些来自成功的产品创作者朋友们的策略。
---
-### 1. Define your goal
+### 1. 确定目标
-Early on, figure out the main goal of your project. If you want to break out of your usual design style, focus on the design. If you want to test a new framework for your front-end, focus on the code. If you want to acquire a hundred users, focus on selling.
+在开始的时候,确定你的项目要实现的主要目标。如果你想打破你以往的设计风格,那就把心思花在设计上;如果你测试一个新的前端框架,那就把钻研代码;如果你想获得上百个用户(”大量用户“ 会不会好点),就把精力用在销售上。
-**Define your goal early so you don’t get distracted and end up not achieving what you set out to do.** Perhaps your project doesn’t become the next Snapchat, but by working towards your goal you will have honed the tools in your product-making arsenal. Little by little, you’ll be able to design, code, and sell faster and more efficiently.
+**尽早确定目标可以帮助你摆脱诱惑,防止你到最后忘记初心。** 也许你的项目并不能成为下一个 Snapchat, 但是在通往你目标的道路上,你会更加的熟练运用各种做产品的工具。渐渐地,你会拥有越来越强大的设计、代码、销售等的能力。
-### 2. Stay on track
+### 2. 执行计划
-Sometimes product makers fail to ship because they lose motivation. **Set small goals; meeting those goals will help you build momentum.** Small wins will compound.
+有一些产品没能完的原因是作者在半路失去了动力。 **设定一些小目标(比如先赚一个亿);完成这些目标会让你获得前进的动力。** 小的成就累计起来也是很了不起的。
![](https://cdn-images-1.medium.com/max/800/1*ESildSVTSSOnFXGDxD-l9w.png)
-Another thing you can do to stay on track is to be more public about your work. Share your progress online and with your peers. People love to see things like wireframes and will often times provide valuable input.
+另一个让你保持动力的建议就是让你的项目更加公开。在网上和你的同行们分享你的进展。人们很喜欢看到线框(wireframe 翻译成 ”框架“ 会不会好一点?)类的东西,并常常带来有价值的投入。
-One trick that I find particularly motivating is making bets with friends. I tell them, if I don’t complete a task by a deadline, I’ll give them a hundred dollars. For example, I might set my task to getting twenty people to pay me within two weeks of launching a project.
+我自己找到的一个非常有用的保持动力的小秘诀是和朋友打赌。我对他们说,如果我在截止日期前没有完成某个任务,我就给他们一百刀。比如,我会在一个项目开始的两周内找到二十个人打赌。
-### 3. Solve a problem
+### 3. 解决一个问题
-Start by solving a problem. If you have experienced the problem yourself, even better. Ask your friends what kind of problems they experience.
+解决一个问题。如果你自己也经历了这个问题那就再好不过了。问问你的朋友们他们都有哪些问题需要解决。
-For example, I built [YC Careers](http://jonathanzwhite.github.io/yc-careers/) and [AtomSpace](https://atomspace.co/) to address the needs of one my friends who was having trouble applying to jobs and interviewing as a product designer. Overnight, YC Careers made it to the top of [ProductHunt](https://www.producthunt.com/posts/yc-careers) and AtomSpace booked $100 dollars from strangers within 6 hours of going live.
+比如,我做了 [YC Careers](http://jonathanzwhite.github.io/yc-careers/) 和 [AtomSpace](https://atomspace.co/) 来解决一个产品设计师朋友找工作和面试的烦恼。一夜之间,YC Careers 一下子爬到了 [ProductHunt](https://www.producthunt.com/posts/yc-careers) 的榜首,AtomSpace 在上线6个小时就拿到了来自陌生人的一百美元订单。
-**The bigger the pain point you’re trying to solve, the easier it will be to find users.**
+**你解决越大的痛点,就越容易找到用户。**
-Also, analyze problem-solutions from multiple perspectives. Some successful ideas might seem like a solution without a problem. For example, Instagram doesn’t seem to solve any immediate problem. But it does. Instagram solves the need for friends to stay updated on one another. If this need is not met, then it becomes a problem.
+同时,尝试从过个角度分析问题和解决方案。有些成功的点子看起来并没有解决任何问题,但其实不然。比如,Instagram 看起来没有直接解决任何问题。其实不是。Instagram 满足了朋友之间实时社交的需求。如果这个需求不能得到满足,那才是个问题。
-For further reading, [John Carmack on Idea Generation](https://amasad.me/carmack) and [How to Get Startup Ideas](http://paulgraham.com/startupideas.html) are two great essays to get you started.
+想要了解更多的话,[John Carmack on Idea Generation](https://amasad.me/carmack) 和 [How to Get Startup Ideas](http://paulgraham.com/startupideas.html) 这两篇文章是非常好的开始。
-### 4. Ditch the “good idea / bad idea” mindset
+### 4. 放弃”好主意/坏主意“的想法
-Once you’ve identified a problem and come up with a solution, you’ll probably ask yourself if your idea is good.
+当你明确了你想要解决的问题并有了一个解决方案的时候,你可能会问自己这是不是一个好的点子。
-**Plenty of seemingly bad ideas have turned out to be great businesses.** For example, no one wanted to invest in Airbnb. Brian Chesky, one of the co-founders of Airbnb, detailed their rejections in his essay [7 Rejections](https://medium.com/@bchesky/7-rejections-7d894cbaa084#.l8fdqlasz).
+**相当一部分看起来很糟糕的点子最后被证明是超级棒的生意。** 比如,多年没人想投资 Airbnb。 Brian Chesky, Airbnb 的创始人之一,在他的文章 [7 Rejections](https://medium.com/@bchesky/7-rejections-7d894cbaa084#.l8fdqlasz) 里详细讲述了被投资人拒绝的故事。
![](https://cdn-images-1.medium.com/max/800/1*WpxUxMCO-7NXr-o1yo023g.png)
-The only way to know for sure if your idea will work is to formulate a product hypothesis and run an experiment to test it. Talk to people and ask if they are interested in your solution. If you can get them to pay you before you’ve built anything, even better.
+唯一验证你想法的办法就是做出一个产品来测试它。 找人聊聊,看看他们对你的解决方案是不是感兴趣。如果在你做出任何产品之前就有人原意为之付费那就再棒不过了。
-### 5. Ask for help
+### 5. 寻求帮助
-When working on a project, reach out to people and ask for their help. **You will be surprised at how many people are willing to pay it forward and help a complete stranger.**
+当你在你的项目上埋头苦干的时候,记得寻求别人的帮助。 **你会很惊喜的发现竟然有这么多人原意去帮助一个陌生人(对,就是你)。**
-Some of the best advice and feedback I have received came from reaching out to people with an email or a DM on Twitter.
+我获得的最好的一部分建议就是来自于给别人发邮件或是推特(微博)私信。
-Also, when asking for help, be specific and prepare your questions. If you want feedback on a design, send the mockup. If you want feedback on your marketing strategy, detail what you have tried so far. Context is key. And if you don’t get a response, follow up politely. Sometimes the person you’re reaching out to might have genuinely missed your message.
+在寻求帮助的时候,请提一些精确、有价值的问题。如果你需要关于设计的一些反馈,就把草稿发给别人;如果你需要营销方面的建议,就详细的列出你尝试过的方法。内容才是关键。如果别人没有回复你,请礼貌的再次询问 —— 有时候别人只是没注意到你的消息而已。
---
-Build and launch your side projects. Use this process as a way to hone your craft so that when opportunity presents itself, you’re ready to take full advantage of it. Luck always favors the prepared.
+开始你的兴趣项目吧。利用这个过程磨练自己,这样当机会来临的时候,你才能紧紧抓住。记住,机会总是青睐有准备的人。
-So next time you come up with an idea, act on it. Identify a problem, define your goal, stay on track, and ask for help.
+所以下次你有一个想法的时候,采取行动吧。找到一个问题,确定你的目标,坚持下去,别忘了学会寻求帮助。
-What are you working on right now? How can I help you? Leave me a note here or [tweet](https://twitter.com/jonathanzwhite) them to me on Twitter.
+你现在在做什么项目呢?有什么是我能帮到你的吗?可以在这里或者我的 [tweet](https://twitter.com/jonathanzwhite) 下面留言。
-You can find me on Medium where I publish every week. Or you can follow me on [Twitter](https://twitter.com/JonathanZWhite), where I post non-sensical ramblings about design, front-end development, and virtual reality.
+我在 Medium 上每周都会发文。也可以关注我的 [Twitter](https://twitter.com/JonathanZWhite),我会发一些关于设计、前端开发和虚拟现实的杂想。
-*P.S. If you enjoyed this article, it would mean a lot if you click the 💚 and share with friends.*
+*P.S. If you enjoyed this article, it would mean a lot if you click the 💚 and share with friends.*(可删?)
---
-> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[React](https://github.com/xitu/gold-miner#react)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计) 等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)。
\ No newline at end of file
+> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[React](https://github.com/xitu/gold-miner#react)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计) 等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)。
From 9df8dac2357ba3070b08880809c050cd61dad0f4 Mon Sep 17 00:00:00 2001
From: Wenlin Ou
Date: Fri, 7 Apr 2017 22:25:45 -0400
Subject: [PATCH 076/638] typo fix
---
...ing-will-change-until-you-start-building.md | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/TODO/nothing-will-change-until-you-start-building.md b/TODO/nothing-will-change-until-you-start-building.md
index 7d9880eb6ba..111ebd58e1e 100644
--- a/TODO/nothing-will-change-until-you-start-building.md
+++ b/TODO/nothing-will-change-until-you-start-building.md
@@ -10,15 +10,15 @@
# 真正行动之前 你将一无所成
-就在上周我打了一辆 Lyft 出租车,司机跟我聊了很多关于她的天花乱坠的想法。她的想法里,有一个关于儿童的书籍,有帮助人们停车的APP、有一个更高效的打包礼物的方法,但问题是她总是犹豫不决:她又想法但却不知道从何开始。
+就在上周我打了一辆 Lyft 出租车,司机跟我聊了很多关于她的天花乱坠的想法。她的想法里,有一个关于儿童书籍,有帮助人们停车的APP、有一个更高效的打包礼物的方法,但问题是她总是犹豫不决:她很有想法但却不知道从何开始。
-接下来这段话是我对她说的:**开始一些实际行动吧。选一个项目然后尽可能的去完成它。** 如果你想写一本书,那么从每天写一页开始;如果你像做一个APP,那就从草稿开始。任何人都可以做到这些。
+接下来这段话是我对她说的:**开始一些实际行动吧。选一个项目然后尽可能的去完成它。** 如果你想写一本书,那么从每天写一页开始;如果你想做一个APP,那就从草稿开始。任何人都可以做到这些。
这些建议对所有创新者都适用。一旦你开始着手在你的项目上,你将会不由自主的继续做下去。创新将会成为你人格的一部分 —— 即使你的项目失败了。
-你今天迈出的一小步将会是你人生的一大步。看看那些伟大的产品创造者吧,比如 [Drew Wilson](https://twitter.com/drewwilson), [Pieter Levels](https://twitter.com/levelsio?), 和 [Sebastian Dobrincu](https://twitter.com/Sebyddd)。**他们不仅仅是等待合适的时机。** 他们每周都在更新他们的产品。
+你今天迈出的一小步将会是你人生的一大步。看看那些伟大的产品缔造者吧,比如 [Drew Wilson](https://twitter.com/drewwilson), [Pieter Levels](https://twitter.com/levelsio?), 和 [Sebastian Dobrincu](https://twitter.com/Sebyddd)。**他们不仅仅是等待合适的时机。** 他们每周都在更新他们的产品。
-在一个 [IndieHackers](https://www.indiehackers.com/podcast/006-josh-pigford-of-baremetrics) 的节目中, [Josh Pigford](https://twitter.com/Shpigford) 透露,在做 Baremetrics 之前,他已经尝试过 *一百个* 失败的点子。 现在, Baremetrics 每个月都会有 60,000 美金进账。
+在一个 [IndieHackers](https://www.indiehackers.com/podcast/006-josh-pigford-of-baremetrics) 的节目中, [Josh Pigford](https://twitter.com/Shpigford) 透露,在做 Baremetrics 之前,他已经尝试过 *一百个* 失败的点子。 然而现在, Baremetrics 每个月都会有 60,000 美金进账。
![](https://cdn-images-1.medium.com/max/800/1*BzmVaqAKEzNRybUmMYOxdA.png)
@@ -31,11 +31,11 @@
在开始的时候,确定你的项目要实现的主要目标。如果你想打破你以往的设计风格,那就把心思花在设计上;如果你测试一个新的前端框架,那就把钻研代码;如果你想获得上百个用户(”大量用户“ 会不会好点),就把精力用在销售上。
-**尽早确定目标可以帮助你摆脱诱惑,防止你到最后忘记初心。** 也许你的项目并不能成为下一个 Snapchat, 但是在通往你目标的道路上,你会更加的熟练运用各种做产品的工具。渐渐地,你会拥有越来越强大的设计、代码、销售等的能力。
+**尽早确定目标可以帮助你摆脱诱惑,防止你到最后忘记初心。** 也许你的项目并不能成为下一个 Snapchat, 但是在通往你目标的道路上,你会更加的熟练运用各种做产品的工具。渐渐地,你会拥有越来越强大的设计、代码、销售等能力。
### 2. 执行计划
-有一些产品没能完的原因是作者在半路失去了动力。 **设定一些小目标(比如先赚一个亿);完成这些目标会让你获得前进的动力。** 小的成就累计起来也是很了不起的。
+有一些产品没能完成的原因是作者在半路失去了动力。 **设定一些小目标(比如先赚一个亿);完成这些目标会让你获得前进的动力。** 小的成就累计起来也是很了不起的。
![](https://cdn-images-1.medium.com/max/800/1*ESildSVTSSOnFXGDxD-l9w.png)
@@ -47,19 +47,19 @@
解决一个问题。如果你自己也经历了这个问题那就再好不过了。问问你的朋友们他们都有哪些问题需要解决。
-比如,我做了 [YC Careers](http://jonathanzwhite.github.io/yc-careers/) 和 [AtomSpace](https://atomspace.co/) 来解决一个产品设计师朋友找工作和面试的烦恼。一夜之间,YC Careers 一下子爬到了 [ProductHunt](https://www.producthunt.com/posts/yc-careers) 的榜首,AtomSpace 在上线6个小时就拿到了来自陌生人的一百美元订单。
+比如,我做了 [YC Careers](http://jonathanzwhite.github.io/yc-careers/) 和 [AtomSpace](https://atomspace.co/) 来解决一个产品设计师朋友找工作和面试的烦恼。一夜之间,YC Careers 占领了 [ProductHunt](https://www.producthunt.com/posts/yc-careers) 的榜首,AtomSpace 在上线6个小时之内就拿到了来自陌生人的一百美元订单。
**你解决越大的痛点,就越容易找到用户。**
同时,尝试从过个角度分析问题和解决方案。有些成功的点子看起来并没有解决任何问题,但其实不然。比如,Instagram 看起来没有直接解决任何问题。其实不是。Instagram 满足了朋友之间实时社交的需求。如果这个需求不能得到满足,那才是个问题。
-想要了解更多的话,[John Carmack on Idea Generation](https://amasad.me/carmack) 和 [How to Get Startup Ideas](http://paulgraham.com/startupideas.html) 这两篇文章是非常好的开始。
+想要了解更多关于这方面内容的话,[John Carmack on Idea Generation](https://amasad.me/carmack) 和 [How to Get Startup Ideas](http://paulgraham.com/startupideas.html) 这两篇文章是非常好的起点。
### 4. 放弃”好主意/坏主意“的想法
当你明确了你想要解决的问题并有了一个解决方案的时候,你可能会问自己这是不是一个好的点子。
-**相当一部分看起来很糟糕的点子最后被证明是超级棒的生意。** 比如,多年没人想投资 Airbnb。 Brian Chesky, Airbnb 的创始人之一,在他的文章 [7 Rejections](https://medium.com/@bchesky/7-rejections-7d894cbaa084#.l8fdqlasz) 里详细讲述了被投资人拒绝的故事。
+**相当一部分看起来很糟糕的点子最后被证明是超级棒的生意。** 比如,当年没人想投资 Airbnb。 Brian Chesky, Airbnb 的创始人之一,在他的文章 [7 Rejections](https://medium.com/@bchesky/7-rejections-7d894cbaa084#.l8fdqlasz) 里详细讲述了被投资人拒绝的故事。
![](https://cdn-images-1.medium.com/max/800/1*WpxUxMCO-7NXr-o1yo023g.png)
From 40c655106da805551994c8c586db94b6267adb63 Mon Sep 17 00:00:00 2001
From: sqrtthree
Date: Sat, 8 Apr 2017 11:33:32 +0800
Subject: [PATCH 077/638] fix typos
---
TODO/preload-prefetch-and-priorities-in-chrome.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/TODO/preload-prefetch-and-priorities-in-chrome.md b/TODO/preload-prefetch-and-priorities-in-chrome.md
index 150d1401a6a..5f13ea73d2b 100644
--- a/TODO/preload-prefetch-and-priorities-in-chrome.md
+++ b/TODO/preload-prefetch-and-priorities-in-chrome.md
@@ -107,7 +107,7 @@ preload 使用 “as” 属性加载的资源将会获得与资源 “type”
### 这将会浪费用户的带宽吗?
-**用“preload”和“prefetch”情况下,如果资源不能被缓存,那么都有可能浪费一部分带宽。
+**用“preload”和“prefetch”情况下,如果资源不能被缓存,那么都有可能浪费一部分带宽。**
没有用到的 preload 资源在 Chrome 的 console 里会在 *onload* 事件 3s 后发生警告。
From d9add60f9fca9a897e37485caead9529c889380c Mon Sep 17 00:00:00 2001
From: ZhangFe
Date: Sat, 8 Apr 2017 15:46:41 +0800
Subject: [PATCH 078/638] fix **
---
TODO/css-is-fine-its-just-really-hard.md | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/TODO/css-is-fine-its-just-really-hard.md b/TODO/css-is-fine-its-just-really-hard.md
index 692e3cca856..3160c7e1bab 100644
--- a/TODO/css-is-fine-its-just-really-hard.md
+++ b/TODO/css-is-fine-its-just-really-hard.md
@@ -18,7 +18,7 @@ CSS 很棒。它只是太难了,所以我对它进行了一些编译。
![](https://cdn-images-1.medium.com/max/1600/1*ioYNZ-FgsSpoos6b3iKblg.png)
-很长一段时间以来, 我在电脑和手机上画了很多很多的矩形。我写了很多糟糕的 CSS,成千上万行差劲的 Less 代码和大量可怕的 Sass。他们已经融入我的血液了。
+很长一段时间以来,我在电脑和手机上画了很多很多的矩形。我写了很多糟糕的 CSS,成千上万行差劲的 Less 代码和大量可怕的 Sass。他们已经融入我的血液了。
但是我也写过很多很棒的 CSS!我使用 borders 画过三角形,使用 CSS transforms 绘制贝塞尔曲线,制作 60fps 的滚动动画,以及会让你大吃一惊的工具提示。
@@ -30,12 +30,12 @@ CSS性能极高。长久以来,很多人都在为了让 CSS 更快速,可调
—
-当我年轻的时候,我发现每当我想让边框和超链接文本是同一个颜色的时候我都需要在两三个不同的地方去修改,这真是太可怕了。然后我发现了 LESS。现在我可以定义一个 `@wonderfulBlue` 并且在任何地方去使用它。*喂,Jordan,现在的 CSS 也有变量了...*
+当我年轻的时候,我发现每当我想让边框和超链接文本是同一个颜色的时候我都需要在两三个不同的地方去修改,这真是太可怕了。然后我发现了 LESS。现在我可以定义一个 `@wonderfulBlue` 并且在任何地方去使用它。**喂,Jordan,现在的 CSS 也有变量了...**
-然后我开始考虑为什么要为解释 `#left-section` 的宽度是546px(250 * 2 + 23 * 2)留下很长的注释?我开始使用 Less 写我的数学表达式:`2 * @sectionWidth + 2 * @sectionPadding`。*我猜测你不熟悉 calc(),因为它浏览器兼容性不好*
+然后我开始考虑为什么要为解释 `#left-section` 的宽度是546px(250 * 2 + 23 * 2)留下很长的注释?我开始使用 Less 写我的数学表达式:`2 * @sectionWidth + 2 * @sectionPadding`。**我猜测你不熟悉 calc(),因为它浏览器兼容性不好**
-当年 `border-radius` 需要被 polyfill 时,我在所有使用到的地方添加前缀。后来我使用了 `border-radius()` mixin,这样只要在我需要使用的时候把代码添加上就可以了。*好吧如果你只用到了组件分类呢 —*。伙计你能停一停么?让我完成我的文章先。*我错了—*。没事,别担心,继续听下去。
+当年 `border-radius` 需要被 polyfill 时,我在所有使用到的地方添加前缀。后来我使用了 `border-radius()` mixin,这样只要在我需要使用的时候把代码添加上就可以了。**好吧如果你只用到了组件分类呢 — **。伙计你能停一停么?让我完成我的文章先。**我错了 — **。没事,别担心,继续听下去。
当 CSS 解决不了我的问题时,我开始写 Less。它们会被编译成 CSS,并且它在我的用户的设备上工作的非常棒。只是我比原来忙了 10 倍,我无法单独去编写它了。
@@ -45,7 +45,7 @@ CSS性能极高。长久以来,很多人都在为了让 CSS 更快速,可调
他们中的某些页面已经很庞大了,因此通常我们会将我们的 CSS (好吧,Less)和 JavaScript 分割成独立的文件,这样用户就不必下载练习页面的代码来观看视频。
-有些时候,我们移除了很多代码后样式看起来就不对了。因为我们的主页菜单可能希望有一个 `.left-arrow` 类,但是现在这个 class 的样式在 `exercise.css` 文件里。通常我们注意不到这点,因为导航条被鼠标点击几次后 `.left-arrow` 会被整齐地卷起来。*这么看来你应该有截图测试或更严格的 QA 过程*,我刚才说了什么来着?
+有些时候,我们移除了很多代码后样式看起来就不对了。因为我们的主页菜单可能希望有一个 `.left-arrow` 类,但是现在这个 class 的样式在 `exercise.css` 文件里。通常我们注意不到这点,因为导航条被鼠标点击几次后 `.left-arrow` 会被整齐地卷起来。**这么看来你应该有截图测试或更严格的 QA 过程**,我刚才说了什么来着?
唉,这是很辛苦的工作!但是代码就是偶尔会出 bug,修复它们并且继续前进,这是件很酷的事。
@@ -68,7 +68,7 @@ CSS性能极高。长久以来,很多人都在为了让 CSS 更快速,可调
CSS很好,速度很快,它已经发展了有20多年了,并且适用于各种应用程序。
-但是我真的不喜欢写 CSS。很多人也不喜欢,所以我们开发了这些很棒的模式去写 CSS。但是我也不喜欢以这些模式去写,我有更好的事情要去做。并且 JavaScript 也很酷。*实际上 JavaScript 有更多的可能性*。[所以我用 JavaScript 去编写我的 CSS](https://github.com/khan/aphrodite).
+但是我真的不喜欢写 CSS。很多人也不喜欢,所以我们开发了这些很棒的模式去写 CSS。但是我也不喜欢以这些模式去写,我有更好的事情要去做。并且 JavaScript 也很酷。**实际上 JavaScript 有更多的可能性**。[所以我用 JavaScript 去编写我的 CSS](https://github.com/khan/aphrodite).
把这样的代码:
From 01ef70394f6f662541c7f6f9eac0996902a9b094 Mon Sep 17 00:00:00 2001
From: ZhangFe
Date: Sat, 8 Apr 2017 15:53:25 +0800
Subject: [PATCH 079/638] =?UTF-8?q?fix=E8=BD=AC=E6=8D=A2=E6=A0=BC=E5=BC=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
TODO/css-is-fine-its-just-really-hard.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/TODO/css-is-fine-its-just-really-hard.md b/TODO/css-is-fine-its-just-really-hard.md
index 3160c7e1bab..423250fcfb8 100644
--- a/TODO/css-is-fine-its-just-really-hard.md
+++ b/TODO/css-is-fine-its-just-really-hard.md
@@ -35,7 +35,7 @@ CSS性能极高。长久以来,很多人都在为了让 CSS 更快速,可调
然后我开始考虑为什么要为解释 `#left-section` 的宽度是546px(250 * 2 + 23 * 2)留下很长的注释?我开始使用 Less 写我的数学表达式:`2 * @sectionWidth + 2 * @sectionPadding`。**我猜测你不熟悉 calc(),因为它浏览器兼容性不好**
-当年 `border-radius` 需要被 polyfill 时,我在所有使用到的地方添加前缀。后来我使用了 `border-radius()` mixin,这样只要在我需要使用的时候把代码添加上就可以了。**好吧如果你只用到了组件分类呢 — **。伙计你能停一停么?让我完成我的文章先。**我错了 — **。没事,别担心,继续听下去。
+当年 `border-radius` 需要被 polyfill 时,我在所有使用到的地方添加前缀。后来我使用了 `border-radius()` mixin,这样只要在我需要使用的时候把代码添加上就可以了。**好吧如果你只用到了组件分类呢 —**。伙计你能停一停么?让我完成我的文章先。**我错了 —**。没事,别担心,继续听下去。
当 CSS 解决不了我的问题时,我开始写 Less。它们会被编译成 CSS,并且它在我的用户的设备上工作的非常棒。只是我比原来忙了 10 倍,我无法单独去编写它了。
From 9886d460d18b7e1f4d32fd86d87814861034d315 Mon Sep 17 00:00:00 2001
From: reid
Date: Sat, 8 Apr 2017 17:26:48 +0800
Subject: [PATCH 080/638] =?UTF-8?q?=E4=BA=8C=E6=A0=A1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
...k-bits-getting-the-most-out-of-the-commonschunkplugin.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/TODO/webpack-bits-getting-the-most-out-of-the-commonschunkplugin.md b/TODO/webpack-bits-getting-the-most-out-of-the-commonschunkplugin.md
index 1d88f590d61..cd003ab1e9f 100644
--- a/TODO/webpack-bits-getting-the-most-out-of-the-commonschunkplugin.md
+++ b/TODO/webpack-bits-getting-the-most-out-of-the-commonschunkplugin.md
@@ -91,7 +91,7 @@ webpack 核心团队隔三差五地就会在 Twitter 上作一些寓教于乐的
filename: "commonlazy.js"
});
-类似地 —— webpack 会扫描所有 chunks 并检查公共模块。由于设置了 `async: true`,只有代码拆分的 bundles 会被扫描。因为我们并没有指明 `minChunks` 的值,所有 webpack 会取其默认值 3。综上,上述代码的含义是:
+类似地 —— webpack 会扫描所有 chunks 并检查公共模块。由于设置了 `async: true`,只有代码拆分的 bundles 会被扫描。因为我们并没有指明 `minChunks` 的值,所以 webpack 会取其默认值 3。综上,上述代码的含义是:
> **嘿 webpack,请检查所有的普通(即懒加载的)chunks,如果某个模块出现在了 3 个或 3 个以上的 chunks 中,就将其分离到一个独立的异步公共 chunk 中去。**
@@ -99,7 +99,7 @@ webpack 核心团队隔三差五地就会在 Twitter 上作一些寓教于乐的
![Markdown](http://i4.buimg.com/1949/626cbab70072f442.png)
-现在异步 chunks 都非常的小,并且所有代码都被聚合到 `commonlazy.js` 文件中去了。因为这些 bundles 本来就很小了, 首次访问可能都察觉不到代码体积的变化。现在,每一个代码拆分的 bundle 所需携带的数据更少了;而且,通过将这些公共模块放到一个独立可缓存的 chunk 中,我们节省了用户加载时间,降低了数据消费量(data consumption)。
+现在异步 chunks 都非常的小,并且所有代码都被聚合到 `commonlazy.js` 文件中去了。因为这些 bundles 本来就很小了, 首次访问可能都察觉不到代码体积的变化。现在,每一个代码拆分的 bundle 所需携带的数据更少了;而且,通过将这些公共模块放到一个独立可缓存的 chunk 中,我们节省了用户加载时间,减少了需要传输的数据量(data consumption)。
#### 更多控制:minChunks 函数 ####
@@ -129,7 +129,7 @@ webpack 核心团队隔三差五地就会在 Twitter 上作一些寓教于乐的
function lodashMomentModuleFilter(module, count) {
return module.resource && /lodash|moment/.test(module.resource) && count >= 2;
}
-
+
function immutableReactModuleFilter(module, count) {
return module.resource && /immutable|react/.test(module.resource) && count >=4
}
From 719e846484632c4e1d2ca7b654644ee4d1987a76 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=94=85=E7=82=89=E5=B7=A5?=
Date: Sat, 8 Apr 2017 18:14:32 +0800
Subject: [PATCH 081/638] modified according to @Vivienmm's revision
---
...-java-2-java-8-stream-android-rxjava2-hell-part4.md | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/TODO/war-learning-curve-rx-java-2-java-8-stream-android-rxjava2-hell-part4.md b/TODO/war-learning-curve-rx-java-2-java-8-stream-android-rxjava2-hell-part4.md
index bdc42075a07..b0b63eeb7c5 100644
--- a/TODO/war-learning-curve-rx-java-2-java-8-stream-android-rxjava2-hell-part4.md
+++ b/TODO/war-learning-curve-rx-java-2-java-8-stream-android-rxjava2-hell-part4.md
@@ -11,13 +11,13 @@
又是新的一天,如果学点新东西,这一天一定会很酷炫。
-小伙伴们一切顺利啊,这是我们的 RxJava2 Android 系列的第四部分 [ [第一部分](https://github.com/xitu/gold-miner/blob/master/TODO/pull-vs-push-imperative-vs-reactive-reactive-programming-android-rxjava2-hell-part2.md), [第二部分](http://www.uwanttolearn.com/android/pull-vs-push-imperative-vs-reactive-reactive-programming-android-rxjava2-hell-part2/), [第三部分](https://github.com/xitu/gold-miner/blob/master/TODO/functional-interfaces-functional-programming-and-lambda-expressions-reactive-programming-android-rxjava2-what-the-hell-is-this-part3.md) ]。 好消息是我们已经满足了一些先决条件,已经准备好用 Rx 来工作了。在使用 RxJava2 Android Observable 之前,我会先用 Java8 的 Stream 来做响应式编程。我认为我们应该了解 Java8,我还感觉通过使用 Java8 的流式 API 会让 RxJava2 Android 的学习曲线更简单。
+小伙伴们一切顺利啊,这是我们的 RxJava2 Android 系列的第四部分 [ [第一部分](https://github.com/xitu/gold-miner/blob/master/TODO/pull-vs-push-imperative-vs-reactive-reactive-programming-android-rxjava2-hell-part2.md), [第二部分](http://www.uwanttolearn.com/android/pull-vs-push-imperative-vs-reactive-reactive-programming-android-rxjava2-hell-part2/), [第三部分](https://github.com/xitu/gold-miner/blob/master/TODO/functional-interfaces-functional-programming-and-lambda-expressions-reactive-programming-android-rxjava2-what-the-hell-is-this-part3.md) ]。 好消息是我们已经做好准备,可以开始使用 Rx 了。在使用 RxJava2 Android Observable 之前,我会先用 Java8 的 Stream 来做响应式编程。我认为我们应该了解 Java8,我还感觉通过使用 Java8 的流式 API 会让 RxJava2 Android 的学习曲线更简单。
**动机:**
动机跟我在 [第一部分](https://github.com/xitu/gold-miner/blob/master/TODO/pull-vs-push-imperative-vs-reactive-reactive-programming-android-rxjava2-hell-part2.md) 和大家分享过的一样。在我开始学习 RxJava2 Android 的时候,我并不知道我该怎样使用、在什么地方使用它。
-现在我们知道学习这个需要一些先决条件,但当初我对此一无所知。在我刚刚开始的时候,该如何从任何数据或对象上创建一个 Observable 呢。然后我知道当 Observable 上的数据发生了一些事件的时候,有接口或者可以叫做“回调”会被调用。这在理论上很棒,但是当我付诸实践的时候,GG了。我发现很多理论上应该成立的模式在我去用的时候完全不起作用。对我来说最大的问题,是不能用响应或者函数式响应的思维思考问题。我有命令式编程和面向对象编程的背景,由于先入为主,所以对我来说理解会有些难。我一直在问这些问题:我该在哪里实现?我应该怎么实现?如果你跟着这篇文章看下来,我可以 100% 保证你会知道怎样把命令式代码转换到 Rx 代码,虽然写出来的 Rx 代码可能不是很好,但是你起码知道怎么开始。
+现在我们已经学会了一些预备知识,但当时我什么都不知道。我那时从学习如何从数据或对象创建 Observable 开始。然后学会当 Observable 数据上发生变化时,去调用哪些接口(或者可以叫做“回调”)。这在理论上很棒,但是当我付诸实践的时候,GG了。我发现很多理论上应该成立的模式在我去用的时候完全不起作用。对我来说最大的问题,是不能用响应或者函数式响应的思维思考问题。我有命令式编程和面向对象编程的背景,由于先入为主,所以对我来说理解会有些难。我一直在问这些问题:我该在哪里实现?我应该怎么实现?如果你跟着这篇文章看下来,我可以 100% 保证你会知道怎样把命令式代码转换到 Rx 代码,虽然写出来的 Rx 代码可能不是很好,但是你起码知道怎么开始。
**回顾:**
@@ -50,7 +50,7 @@
Stream:
- 用来支持在元素形成的流上进行函数式操作(比如在集合上进行的 map-reduce 变换)的类(*docs.oracle*)。
+支持在元素形成的流上进行函数式操作(比如在集合上进行的 map-reduce 变换)的类(*docs.oracle*)。
第一个问题:在英语中 Stream 是什么意思?
@@ -156,7 +156,7 @@ public static void main(String[] args) {
同志们这里需要注意下!
-在 Java8 Stream 中有个叫做 Predicate(谓词,可以判断真假,详情见线性代数中的相关定义——译注)的函数式接口。所以,如果我想进行过滤的话需要把这个函数式接口送到流的过滤器函数里面。现在,我给大家展示在我们的代码中如何创建“大石子过滤器”。
+在 Java8 Stream 中有个叫做 Predicate(谓词,可以判断真假,详情见离散数学中的相关定义——译注)的函数式接口。所以,如果我想进行过滤的话,可以用这个函数式接口实现流的过滤功能。现在,我给大家展示在我们的代码中如何创建“大石子过滤器”。
```
private static Predicate BigStoneFilter = new Predicate() {
@@ -767,7 +767,7 @@ Observable.range(0, 10)
**总结:**
-同志们干得好!今天我们学 Rx Android 学得很开心。我们从图画开始,然后使用了 Java8 的流(Stream)。之后将 Java8 的流转换到 RxJava 2 Android 的 Observable。再之后,我们看到了真实项目中的示例并且展示了在现有的项目中如何开始使用 Rx,把 if 换成 filter,用 map 进行数据转化,用 flatmap 代替嵌套的循环。下篇文章: [Dialogue between Rx Observable and a Developer (Me) [ Android RxJava2 ] ( What the hell is this ) Part5](http://www.uwanttolearn.com/android/dialogue-rx-observable-developer-android-rxjava2-hell-part5/).
+同志们干得好!今天我们学 Rx Android 学得很开心。我们从图画开始,然后使用了 Java8 的流(Stream)。之后将 Java8 的流转换到 RxJava 2 Android 的 Observable。再之后,我们看到了真实项目中的示例并且展示了在现有的项目中如何开始使用 Rx。最后,我展示了一些转换到 Rx 的技巧:把循环用 forEach 替换,把 if 换成 filter,用 map 进行数据转化,用 flatmap 代替嵌套的循环。下篇文章: [Dialogue between Rx Observable and a Developer (Me) [ Android RxJava2 ] ( What the hell is this ) Part5](http://www.uwanttolearn.com/android/dialogue-rx-observable-developer-android-rxjava2-hell-part5/).
希望你们开心,同志们再见!
From a57c45737bc90135aac4b4343880fc81159f1b0e Mon Sep 17 00:00:00 2001
From: zhuzi
Date: Sat, 8 Apr 2017 20:12:00 +0800
Subject: [PATCH 082/638] add proofreader info
---
TODO/using-devtools-tweak-designs-browser.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/TODO/using-devtools-tweak-designs-browser.md b/TODO/using-devtools-tweak-designs-browser.md
index fe280545985..9fc7266025c 100644
--- a/TODO/using-devtools-tweak-designs-browser.md
+++ b/TODO/using-devtools-tweak-designs-browser.md
@@ -2,7 +2,7 @@
> * 原文作者:[AHMAD SHADEED](https://css-tricks.com/author/shadeed9/)
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
> * 译者:[bambooom](https://github.com/bambooom)
-> * 校对者:
+> * 校对者:[gy134340](https://github.com/gy134340) / [avocadowang](https://github.com/avocadowang)
# 使用开发者工具在浏览器中调整设计
From 411b25901dc1d966ea0c32cfecfc26b40d05c9eb Mon Sep 17 00:00:00 2001
From: gy134340
Date: Sat, 8 Apr 2017 22:57:16 +0800
Subject: [PATCH 083/638] =?UTF-8?q?=E8=B7=8C=E5=AE=95=E8=B5=B7=E4=BC=8F?=
=?UTF-8?q?=E7=9A=84=E5=87=BD=E6=95=B0=E5=BC=8F=E7=BC=96=E7=A8=8B=EF=BC=88?=
=?UTF-8?q?=E7=BB=84=E6=88=90=E5=8C=96=E8=BD=AF=E4=BB=B6=EF=BC=89?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
...ctional-programming-composable-software.md | 124 +++++++++---------
1 file changed, 62 insertions(+), 62 deletions(-)
diff --git a/TODO/the-rise-and-fall-and-rise-of-functional-programming-composable-software.md b/TODO/the-rise-and-fall-and-rise-of-functional-programming-composable-software.md
index fda67ce9863..463b3cbdc66 100644
--- a/TODO/the-rise-and-fall-and-rise-of-functional-programming-composable-software.md
+++ b/TODO/the-rise-and-fall-and-rise-of-functional-programming-composable-software.md
@@ -4,117 +4,117 @@
> * 译者:
> * 校对者:
-# The Rise and Fall and Rise of Functional Programming (Composing Software)
+# 跌宕起伏的函数式编程(组成化软件)
-Smoke Art Cubes to Smoke — MattysFlicks — (CC BY 2.0)
+烟雾的方块艺术 —MattysFlicks —(CC BY 2.0)
-> Note: This is part 1 of the “Composing Software” series on learning functional programming and compositional software techniques in JavaScript ES6+ from the ground up. Stay tuned. There’s a lot more of this to come!
+> 注意:这是从基础学习函数式编程和使用 JavaScript ES6+ 组成软件的第一部分。保持关注,接下来还有很多!
-When I was about 6 years old, I spent a lot of time playing computer games with my best friend. His family had a room full of computers. To me, they were irresistible. Magic. I spent many hours exploring all the games. One day I asked my friend, “how do we make a game?”
+当我 6 岁时,我花了很多时间跟我的小伙伴玩电脑游戏,他家里有一整房间的电脑。对于我说,那是及其不可抗拒的魔力。我花了很多时间探索所有的游戏。一天我问他,“我们怎样做一个游戏?”
-He didn’t know, so we asked his dad, who reached up on a high shelf and pulled down a book of games written in Basic. So began my journey with programming. By the time public school got around to teaching algebra, I already knew the topic well, because programming is basically algebra. It can be, anyway.
+他不知道,所以我们问了他的老爸,他的老爸爬上一个很高的架子拿下来一本使用 Basic 编写的游戏书籍。就那样开始了我的编程之路。当公立学校开始教授代数时,我已经熟稔其中的概念了,因为编程基本上是代数。无论如何,它都是。
-### The Rise of Composable Software
+### 软件组成化的兴起
-In the beginning of computer science, before most of computer science was actually done on computers, there lived two great computer scientists: Alonzo Church, and Alan Turing. They produced two different, but equivalent universal models of computation. Both models could compute anything that can be computed (hence, “universal”).
+在计算机科学的起步阶段,在大多数的计算机科学在电脑上完成之前,有两位伟大的计算机科学家:阿隆佐·邱奇和艾伦·图灵。他们发明了两种不同、但是普遍通用的计算模型。两种都可以计算所有可被计算的东西(因此,“普遍”)。
-Alonzo Church invented lambda calculus. Lambda calculus is a universal model of computation based on function application. Alan Turing is known for the turing machine. A turing machine is a universal model of computation that defines a theoretical device that manipulates symbols on a strip of tape.
+阿隆佐·邱奇发明了 lambda 表达式。lambda 表达式是基于函数应用的通用计算模型。艾伦·图灵因为图灵机而知名。图灵机使用定义一个在磁带上操作符号的理论装置来计算的通用模型。
-Together, they collaborated to show that lambda calculus and the turing machine are functionally equivalent.
+总的说,他们共同说明了 lambda 表达式和图灵机功能上是相等的。
-Lambda calculus is all about function composition. Thinking in terms of function composition is a remarkably expressive and eloquent way to compose software. In this text, we’re going to discuss the importance of function composition in software design.
+lambda 表达式全是函数组成,依靠函数来编写软件是非常高效和有意义的。本文中,我们将会讨论软件设计中函数的组成的重要性。
-There are three important points that make lambda calculus special:
+有三点造就了 lambda 表达式的特别之处:
-1. Functions are always anonymous. In JavaScript, the right side of `const sum = (x, y) => x + y` is the *anonymous* function expression `(x, y) => x + y`.
-2. Functions in lambda calculus only accept a single input. They’re unary. If you need more than one parameter, the function will take one input and return a new function that takes the next, and so on. The n-ary function `(x, y) => x + y` can be expressed as a unary function like: `x => y => x + y`. This transformation from an n-ary function to a unary function is known as currying.
-3. Functions are first-class, meaning that functions can be used as inputs to other functions, and functions can return functions.
+1. 函数都是匿名的,在 JavaScript 中,右边的 `const sum = (x, y) => x + y` 等同于匿名函数 `(x, y) => x + y`.
+2. lambda 表达式中的函数只接收一个参数。他们是一元的,如果你需要多个参数,函数将会接受一个输入返回一个调用下一个函数的函数,然后继续这样。非一元函数 `(x, y) => x + y` 可以被表示为一个像 `x => y => x + y` 的一元函数。这个把多元函数转换成一元函数的过程叫做柯里化。
+3. 函数是一级的,意味着函数可以作为参数传递给其他函数,同时函数可以返回函数。
-Together, these features form a simple, yet expressive vocabulary for composing software using functions as the primary building block. In JavaScript, anonymous functions and curried functions are optional features. While JavaScript supports important features of lambda calculus, it does not enforce them.
+总的说来,这些特性形成使用函数作为初始模块的一个简单且具有表达性的方法来构造软件。在 JavaScript 中,函数的匿名和柯里化都是可选的特性。虽然 JavaScript 支持这些 lambda 表达式的重要属性,它却并不强制使用这些。
-The classic function composition takes the output from one function and uses it as the input for another function. For example, the composition:
+这些经典的函数组成方法用一个函数的输出来作为另一个函数的输入,例如,对于组合:
- f . g
+ f . g
+
+也可以写做:
-Can be written as:
+ compose2 = f => g => x => f(g(x))
+
+这里是你使用它的方法:
+
+ double = n => n * 2
+ inc = n => n + 1
+
+ compose2(double)(inc)(3)
- compose2 = f => g => x => f(g(x))
+`compose2()` 函数使用 `double` 函数作为第一个参数,使用 `inc` 函数作为第二个参数,同时对于两个函数的组合传入参数 `3`。再看一下 `compose2()` 函数所写的,`f` 是 `double()`,`g` 是 `inc()`,同时 `x` 是 `3`。函数 `compose2(double)(inc)(3)` 的调用,实际上是三个不同函数的调用:
-Here’s how you’d use it:
+1. 首先传入 `double` 同时返回一个新的函数。
+2. 返回的函数传入 `inc` 同时再返回一个新的函数。
+3. 再返回的函数传入 `3` 同时计算 `f(g(x))`,最后实际上是 `double(inc(3))`。
+4. `x` 等于 `3` 同时传给 `inc()`。
+5. `inc(3)` 等于 `4`。
+6. `double(4)` 等于 `8`。
+7. 函数返回 `8`。
- double = n => n * 2
- inc = n => n + 1
+组成软件时,可以被看作一个由函数组成的图。看一下下面:
+
+ append = s1 => s2 => s1 + s2
+ append('Hello, ')('world!')
- compose2(double)(inc)(3)
-
-The `compose2()` function takes the `double` function as the first argument, the `inc` function as the second, and then applies the composition of those two functions to the argument `3`. Looking at the signature of `compose2()` again, `f` is `double()`, `g` is `inc()`, and `x` is `3`. The function call, `compose2(double)(inc)(3)`, is actually 3 different function invocations:
-
-1. The first passes `double` and returns a new function.
-2. The returned function takes `inc` and returns a new function.
-3. The next returned function takes `3` and evaluates `f(g(x))`, which is now `double(inc(3))`.
-4. `x` evaluates to `3` and gets passed into `inc()`.
-5. `inc(3)` evaluates to `4`.
-6. `double(4)` evaluates to `8`.
-7. `8` gets returned from the function.
-
-When software is composed, it can be represented by a graph of function compositions. Consider the following:
-
- append = s1 => s2 => s1 + s2
- append('Hello, ')('world!')
-
-You could represent it visually:
+你可以想象成这样:
-Lambda calculus was hugely influential on software design, and prior to about 1980, many very influential icons of computer science were building software using function composition. Lisp was created in 1958, and was heavily influenced by lambda calculus. Today, Lisp is the second-oldest language that’s still in popular use.
+lambda 表达式对软件设计产生了很大的影响,在 1980 年之前,计算机科学领域很多有影响的东西使用函数来构造软件。Lisp 在 1958 年被创作出来,很大程度上受到了 lambda 表达式的影响。如今,Lisp 是广泛使用的第二老的语言了。
-I was introduced to it through AutoLISP: the scripting language used in the most popular Computer Aided Design (CAD) software: AutoCAD. AutoCAD is so popular, virtually every other CAD application supports AutoLISP so that they can be compatible. Lisp is also a popular teaching language in computer science curriculum for three reasons:
+我通过 AutoLISP:一个作为脚本语言被用于最流行的计算机辅助设计(CAD)软件:AutoCAD,接触到它。AutoCAD 很流行,实际上所有其他的 CAD 软件都兼容支持 AutoLISP。Lisp 因为以下三点原因被广泛作为计算机科学的课程:
-1. Its simplicity makes it easy to learn the basic syntax and semantics of Lisp in about a day.
-2. Lisp is all about function composition, and function composition is an elegant way to structure applications.
-3. The best computer science text book I know of uses Lisp: [Structure and Interpretation of Computer Programs](https://www.amazon.com/Structure-Interpretation-Computer-Programs-Engineering/dp/0262510871/ref=as_li_ss_tl?ie=UTF8&linkCode=ll1&tag=eejs-20&linkId=4896ed63eee8657b6379c2acd99dd3f3).
+1. 可以很容易的在一天左右学习 Lisp 基础的词法和语法。
+2. Lisp 全是由函数组成,函数组合是构造应用非常优雅的方式。
+3. 我知道的使用 Lisp 的最棒的计算机科学书籍:[计算机程序的结构与解释](https://www.amazon.com/Structure-Interpretation-Computer-Programs-Engineering/dp/0262510871/ref=as_li_ss_tl?ie=UTF8&linkCode=ll1&tag=eejs-20&linkId=4896ed63eee8657b6379c2acd99dd3f3)。
-### The Fall of Composable Software
+### 组合型软件的衰落
-Somewhere between 1970 and 1980, the way that software was created drifted away from simple compositions, and became a list of linear instructions for the computer to follow. Then came object-oriented programming — a great idea about component encapsulation and message passing that got distorted by popular languages into a horrible idea about inheritance hierarchies and **is-a** relationships for feature reuse.
+在 1970 到 1980 中间的某段时间,软件的构造开始偏离简单的组合,成为一串线性的让计算机执行的指令。然后面向对象编程 — 一个伟大的关于组件的封装和信息传递的思想被流行的编程语言扭曲成为了特性的重用而采取的糟糕的继承层次和 *is-a* 关系。
-Functional programming was relegated to the sidelines and academia: The blissful obsession of the geekiest of programming geeks, professors in their ivy league towers, and some lucky students who escaped the Java force-feeding obsession of the 1990’s — 2010's.
+函数式编程语言退居二线:只有编程极客的痴迷、常春藤盟校的教授和一些幸运的学生可以在 1990 — 2010 年间逃离 Java 的强迫性学习。
-For most of us, creating software was a bit of a nightmare for 30 years. Dark times.
+对于我们的大多数人来说,已经经历了大约 30 年的软件编写噩梦和黑暗时期。
-### The Rise of Composable Software
+### 组合型软件的兴起
-Around 2010, something great began to happen: JavaScript exploded. Before about 2006, JavaScript was widely considered a toy language used to make cute animations happen in web browsers, but it had some powerful features hidden in it. Namely, the most important features of lambda calculus. People started whispering in the shadows about this cool new thing called “functional programming”.
+在 2010 年左右,一些有趣的事情发生了:JavaScript 的崛起。在 2006 年左右,JavaScript 被广泛的看作玩具语言和被用制作浏览器中好玩的动画,但是它有一些隐藏饿及其强大的属性。即 lambda 表达式中最重要的特性。人们开始暗中讨论一个叫做 “函数式编程的” 酷东西。
[![](https://i.embed.ly/1/display/resize?url=https%3A%2F%2Fpbs.twimg.com%2Fprofile_images%2F3722564505%2Fb8030b8f3990875e8f38ed877fdf8d25_bigger.png&key=4fce0568f2ce49e8b54624ef71a8a5bd&width=40)](https://video.twimg.com/tweet_video/CmectVVVUAAsvpo.mp4)
-I keep telling you [#JavaScript](https://twitter.com/hashtag/JavaScript?src=hash) is not a toy language. Now I have to show you. [#StarWars](https://twitter.com/hashtag/StarWars?src=hash) [@BrendanEich](https://twitter.com/BrendanEich)
+我一直在告诉大家 [JavaScript] 并不是一门玩具语言。现在我需要展示它。[#StarWars](https://twitter.com/hashtag/StarWars?src=hash) [@BrendanEich](https://twitter.com/BrendanEich)
-By 2015, the idea of building software with function composition was popular again. To make it simpler, the JavaScript specification got its first major upgrade of the decade and added arrow functions, which made it easier to create and read functions, currying, and lambda expressions.
+在 2015 年,使用函数的组合来编写软件又开始流行起来。为了更简单化,JavaScript 规范获得的数十年来第一次主要的更新并且添加了箭头函数,为了更简单的编写和读取函数、柯里化,和 lambda 语句。
-Arrow functions were like rocket fuel for the functional programming explosion in JavaScript. Today it’s rare to see a large application which doesn’t use a lot of functional programming techniques.
+箭头函数像是 JavaScript 函数式编程飞升的燃料。现在很少看见不使用很多函数式编程技术的大型应用了。
-Composition is a simple, elegant, and expressive way to clearly model the behavior of software. The process of composing small, deterministic functions to create larger software components and functionality produces software that is easier to organize, understand, debug, extend, test, and maintain.
+组合型可以简单、优雅的表达软件的模型和行为。通过把小的、确定的函数组成稍大的组件并构成软件的过程,可以更为简单的组织、理解、调试、扩展、测试和掌控。
-As you read the following text, please experiment with the examples. Remember what it was like as a child to pick things apart, explore, and play while you learn. Rediscover the childhood joy of discovery. Let’s make some magic.
+你在阅读下一部分时,可以使用实例实验,记住要把你自己当孩子一样把其他的思想扔在一边在学习中去探索和玩耍。重新发现孩童时发现新事物的欣喜。让我们来做一些魔术吧。
-[Continued in part 2: “Why Learn Functional Programming in JavaScript?”](https://medium.com/javascript-scene/why-learn-functional-programming-in-javascript-composing-software-ea13afc7a257#.i6vf0q8uy)
+[接下来的第二部分:“为什么要用 JavaScript 学习函数式编程?”]
-### Next Steps
+### 下一步
-Want to learn more about functional programming in JavaScript?
+想更多的学习 JavaScript 的函数式编程?
-[Learn JavaScript with Eric Elliott](http://ericelliottjs.com/product/lifetime-access-pass/). If you’re not a member, you’re missing out!
+[Learn JavaScript with Eric Elliott](http://ericelliottjs.com/product/lifetime-access-pass/),什么,你还不是其中之一,out 了!
[![](https://cdn-images-1.medium.com/freeze/max/30/1*3njisYUeHOdyLCGZ8czt_w.jpeg?q=20)![](https://cdn-images-1.medium.com/max/800/1*3njisYUeHOdyLCGZ8czt_w.jpeg)](https://ericelliottjs.com/product/lifetime-access-pass/)
-***Eric Elliott*** is the author of [*“Programming JavaScript Applications”*](http://pjabook.com) (O’Reilly), and [*“Learn JavaScript with Eric Elliott”*](http://ericelliottjs.com/product/lifetime-access-pass/). He has contributed to software experiences for **Adobe Systems, Zumba Fitness, he Wall Street Journal, ESPN, BBC, and top recording artists including Usher, Frank Ocean, Metallica**, and many more.
+*Eric Elliott* 是 [*“Programming JavaScript Applications”*](http://pjabook.com) (O’Reilly) 和 “Learn JavaScript with Eric Elliott” 的作者。他曾效力于 *Adobe Systems, Zumba Fitness, he Wall Street Journal, ESPN, BBC, and top recording artists including Usher, Frank Ocean, Metallica* 和其他一些公司。
-*He spends most of his time in the San Francisco Bay Area with the most beautiful woman in the world.*
+*他和她的老婆(很漂亮)大部分时间都在旧金山湾区里。*
---
From 4479517a81c541ddd708327ce6e127ca1190575c Mon Sep 17 00:00:00 2001
From: Wenlin Ou
Date: Sun, 9 Apr 2017 00:45:08 -0400
Subject: [PATCH 084/638] fix errors according proofreader
---
...ng-will-change-until-you-start-building.md | 20 +++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/TODO/nothing-will-change-until-you-start-building.md b/TODO/nothing-will-change-until-you-start-building.md
index 111ebd58e1e..034e8ae1484 100644
--- a/TODO/nothing-will-change-until-you-start-building.md
+++ b/TODO/nothing-will-change-until-you-start-building.md
@@ -10,11 +10,11 @@
# 真正行动之前 你将一无所成
-就在上周我打了一辆 Lyft 出租车,司机跟我聊了很多关于她的天花乱坠的想法。她的想法里,有一个关于儿童书籍,有帮助人们停车的APP、有一个更高效的打包礼物的方法,但问题是她总是犹豫不决:她很有想法但却不知道从何开始。
+就在上周我打了一辆 Lyft 出租车,司机跟我聊了很多关于她的天花乱坠的想法。她的想法里,她有写一本儿童书籍的想法,有开发一个帮助人们找到停车位置的软件的想法,有寻找到一种更高效打包礼物的想法,但问题是她总是犹豫不决:她有很多想法但却不知道从何开始。
-接下来这段话是我对她说的:**开始一些实际行动吧。选一个项目然后尽可能的去完成它。** 如果你想写一本书,那么从每天写一页开始;如果你想做一个APP,那就从草稿开始。任何人都可以做到这些。
+接下来这段话是我对她说的:**开始一些实际行动吧。选一个项目然后尽可能的去完成它。** 如果你想写一本书,那么从每天写一页开始;如果你想做一个APP,那就从构建草图开始。任何人都可以做到这些。
-这些建议对所有创新者都适用。一旦你开始着手在你的项目上,你将会不由自主的继续做下去。创新将会成为你人格的一部分 —— 即使你的项目失败了。
+这个建议适用于所有的创作者。一旦你开始着手在你的项目上,你将会不由自主的继续做下去。创新将会成为你人格的一部分 —— 即使你的项目失败了。
你今天迈出的一小步将会是你人生的一大步。看看那些伟大的产品缔造者吧,比如 [Drew Wilson](https://twitter.com/drewwilson), [Pieter Levels](https://twitter.com/levelsio?), 和 [Sebastian Dobrincu](https://twitter.com/Sebyddd)。**他们不仅仅是等待合适的时机。** 他们每周都在更新他们的产品。
@@ -29,11 +29,11 @@
### 1. 确定目标
-在开始的时候,确定你的项目要实现的主要目标。如果你想打破你以往的设计风格,那就把心思花在设计上;如果你测试一个新的前端框架,那就把钻研代码;如果你想获得上百个用户(”大量用户“ 会不会好点),就把精力用在销售上。
+在开始的时候,确定你的项目要实现的主要目标。如果你想打破你以往的设计风格,那就把心思花在设计上;如果你测试一个新的前端框架,那就钻研代码;如果你想获得大量用户,就把精力用在销售上。
-**尽早确定目标可以帮助你摆脱诱惑,防止你到最后忘记初心。** 也许你的项目并不能成为下一个 Snapchat, 但是在通往你目标的道路上,你会更加的熟练运用各种做产品的工具。渐渐地,你会拥有越来越强大的设计、代码、销售等能力。
+**尽早确定目标可以帮助你摆脱诱惑,防止你到最后忘记初心。** 也许你的项目并不能成为下一个 Snapchat, 但是在通往你目标的道路上,你会更加的熟练运用各种做产品的工具。渐渐地,你会拥有越来越强大的设计、编码、销售等能力。
-### 2. 执行计划
+### 2. 保持进展
有一些产品没能完成的原因是作者在半路失去了动力。 **设定一些小目标(比如先赚一个亿);完成这些目标会让你获得前进的动力。** 小的成就累计起来也是很了不起的。
@@ -49,9 +49,9 @@
比如,我做了 [YC Careers](http://jonathanzwhite.github.io/yc-careers/) 和 [AtomSpace](https://atomspace.co/) 来解决一个产品设计师朋友找工作和面试的烦恼。一夜之间,YC Careers 占领了 [ProductHunt](https://www.producthunt.com/posts/yc-careers) 的榜首,AtomSpace 在上线6个小时之内就拿到了来自陌生人的一百美元订单。
-**你解决越大的痛点,就越容易找到用户。**
+**你解决的痛点越大,就越容易找到用户。**
-同时,尝试从过个角度分析问题和解决方案。有些成功的点子看起来并没有解决任何问题,但其实不然。比如,Instagram 看起来没有直接解决任何问题。其实不是。Instagram 满足了朋友之间实时社交的需求。如果这个需求不能得到满足,那才是个问题。
+同时,尝试从各个不同的角度寻找解决方案。有些成功的点子看起来并没有解决任何问题,但其实不然。比如,Instagram 看起来没有直接解决任何问题。其实不是。Instagram 满足了朋友之间实时社交的需求。如果这个需求不能得到满足,那才是个问题。
想要了解更多关于这方面内容的话,[John Carmack on Idea Generation](https://amasad.me/carmack) 和 [How to Get Startup Ideas](http://paulgraham.com/startupideas.html) 这两篇文章是非常好的起点。
@@ -67,11 +67,11 @@
### 5. 寻求帮助
-当你在你的项目上埋头苦干的时候,记得寻求别人的帮助。 **你会很惊喜的发现竟然有这么多人原意去帮助一个陌生人(对,就是你)。**
+当你在你的项目上埋头苦干的时候,记得寻求别人的帮助。 **你会很惊喜的发现竟然有这么多人愿意去帮助一个陌生人(对,就是你)。**
我获得的最好的一部分建议就是来自于给别人发邮件或是推特(微博)私信。
-在寻求帮助的时候,请提一些精确、有价值的问题。如果你需要关于设计的一些反馈,就把草稿发给别人;如果你需要营销方面的建议,就详细的列出你尝试过的方法。内容才是关键。如果别人没有回复你,请礼貌的再次询问 —— 有时候别人只是没注意到你的消息而已。
+在寻求帮助的时候,请准备好的你的问题,并尽可能具体。如果你需要关于设计的一些反馈,就把草稿发给别人;如果你需要营销方面的建议,就详细的列出你尝试过的方法。内容才是关键。如果别人没有回复你,请礼貌的再次询问 —— 有时候别人只是没注意到你的消息而已。
---
From b29686077845eda6b54570ae44c68eb629006026 Mon Sep 17 00:00:00 2001
From: xiaoyusilen
Date: Sun, 9 Apr 2017 13:03:50 +0800
Subject: [PATCH 085/638] Modify translation
---
TODO/anatomy-of-a-function-call-in-go.md | 22 +++++++++++-----------
TODO/go-function-calls-redux.md | 6 +++---
2 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/TODO/anatomy-of-a-function-call-in-go.md b/TODO/anatomy-of-a-function-call-in-go.md
index f6141663c05..baca272576d 100644
--- a/TODO/anatomy-of-a-function-call-in-go.md
+++ b/TODO/anatomy-of-a-function-call-in-go.md
@@ -20,7 +20,7 @@ func add(a, b int) int {
}
```
-我们编译的时候需要关闭优化这样方便跟踪每个部分。我们用 `go build -gcflags 'N -l'` 这个命令来完成上述操作。然后我们可以用 `go tool objdump -s main.add func` 输出我们函数的具体细节(这里的 func 是我们的包名,也就是我们刚刚用 go build 编译出的可执行文件)。
+我们编译的时候需要关闭优化,这样方便理解每个部分。我们用 `go build -gcflags 'N -l'` 这个命令来完成上述操作。然后我们可以用 `go tool objdump -s main.add func` 输出我们函数的具体细节(这里的 func 是我们的包名,也就是我们刚刚用 go build 编译出的可执行文件)。
如果你以前从来没有看过汇编语言,那么恭喜啦,你今天看到的内容对你来说是全新的。我将在 Mac 上完成这些事情,所以配置是 Intel 64位。
@@ -36,18 +36,18 @@ func add(a, b int) int {
我们看到了什么?每一行如下所示被分为了4部分:
- 源文件的名称和行号(main.go:15)。这行的源代码会被转换为标有代码行号的说明。Go 的一行可能被转换成多行程序集。
-- 对象的偏移量(例如 0x22C0)。
+- 目标文件中的偏移量(例如 0x22C0)。
- 机器码(例如 48c744241800000000)。这是 CPU 实际执行的二进制机器码。我们不需要看这个,几乎没有人看这玩意。
- 机器码的汇编表示形式,这也是我们想要理解的部分。
让我们将注意力集中在最后一部分,汇编语言。
-- MOVQ,ADDQ 和 RET 是说明。它们告诉 CPU 需要执行的操作。后面的参数告诉 CPU 对什么执行该操作。
+- MOVQ,ADDQ 和 RET 是指令。它们告诉 CPU 需要执行的操作。后面的参数告诉 CPU 对什么执行该操作。
- SP,AX 和 CX 是 CPU 寄存器。寄存器是 CPU 用于存储值的地方,CPU 有多个寄存器可以使用。
- SP 是一个专用寄存器,用于存储当前堆栈指针。堆栈是记录局部变量,参数和函数调用的寄存器。每个 goroutine 都有一个堆栈。当一个函数调用另一个函数,然后另一个函数再调用其他函数,每个函数在堆栈上获得自己的存储区域。在函数调用期间创建存储区域,将 SP 的大小中减去所需的存储大小。
-- 0x8(SP)是指超过 SP 指向的内存位置的 8 个字节的内存位置。
+- 0x8(SP)是指超过 SP 指向的存储单元的 8 个字节的存储单元。
-因此,我们的工作的内容包含存储器位置,CPU 寄存器,用于在存储器和寄存器之间移动值的指令以及寄存器上的操作。 这几乎就是一个 CPU 所完成的事情了。
+因此,我们的工作的内容包含存储单元,CPU 寄存器,用于在存储器和寄存器之间移动值的指令以及寄存器上的操作。 这几乎就是一个 CPU 所完成的事情了。
现在让我们从第一条指令开始看每一条内容。别忘了我们需要从内存中加载两个参数 `a` 和 `b`,把它们相加,然后返回至调用函数。
@@ -67,9 +67,9 @@ func add(a, b int) int {
所以我们从中明白了什么:
- 好,看起来参数都存在堆栈中,第一个参数存储在 SP+0x8 中,另一个在更高编号的地址中。
-- 并且看上去返回的结果存储在参数后边,一个更高编号的已知地址中。
+- 并且看上去返回的结果存储在参数后边,一个更高编号的地址中。
-现在让我们看另一个函数。这个函数有一个全局变量,不过我们依然会让它看起来很简单。
+现在让我们看另一个函数。这个函数有一个局部变量,不过我们依然会让它看起来很简单。
```
func add3(a int) int {
@@ -108,7 +108,7 @@ func add3(a int) int {
这一行代码似乎没有做什么。所以这可能是一种声明函数的方法。让我们分析一下。
-- `SUBQ $0x10, SP` 从 SP 减去 0x10=16。这个操作为我们分类了 16 字节的堆栈空间。
+- `SUBQ $0x10, SP` 从 SP 减去 0x10=16。这个操作为我们释放了 16 字节的堆栈空间
- `MOVQ BP, 0x8(SP)` 将寄存器 BP 中的值存储至 SP+8 中,然后 `LEAQ 0x8(SP), BP` 将地址 SP+8 中的内容加载到 BP 中。现在我们已经有空间可以存储 BP 中之前所存的内容,然后将 BP 中的内容存储至刚刚分配的存储空间中,这有助于建立堆栈区域链(或者堆栈框架)。这有点神秘,不过在这篇文章中我们恐怕不会解决这个问题。
- 在这一部分的最后是 `MOVQ $ 0x0, 0x20 (SP)`,它和我们刚刚分析的最后一句类似,就是将返回值初始化为0。
@@ -126,7 +126,7 @@ func add3(a int) int {
- 调用函数在堆栈中为返回值和参数分配空间。返回值的存储地址比参数的存储地址高。
- 如果被调用函数有局部变量,则通过减少堆栈指针 SP 的值为它们分配空间。它也和寄存器 BP 做了一些神秘的事情。
-- 当函数返回任何 SP&BP 的操作都会相反。
+- 当函数返回任何对 SP 和 BP 的操作都会相反。
让我们看看堆栈在 add3() 方法中如何使用:
@@ -145,8 +145,8 @@ SP+0x08: the old value of BP
SP+0x0: the local variable b
```
-如果你觉得文章中没有提到 SP+0x10,所以不知道这是干什么用的。我可以告诉你,这是存储返回地址的地方。这是为了让 `RET` 指令知道返回到哪里去。
+如果你觉得文章中没有提到 SP+0x10,所以不*知道*这是干什么用的。我可以告诉你,这是存储返回地址的地方。这是为了让 `RET` 指令知道返回到哪里去。
-这篇文章已经足够了。 希望如果以前你不知道这些东西如何工作,但是现在你觉得你已经有了一些了解,或者如果你被汇编吓倒了,那么它可能不那么清晰。 如果你想了解有关汇编的更多信息,请在评论中告诉我,我会考虑在之后的文章中写出来。
+这篇文章已经足够了。 希望如果以前你不知道这些东西如何工作,但是现在你觉得你已经有了一些了解,或者如果你被汇编吓倒了,那么也许它不那么晦涩难懂了。 如果你想了解有关汇编的更多信息,请在评论中告诉我,我会考虑在之后的文章中写出来。
既然你已经看到这儿了,如果喜欢我的这篇文章或者可以从中学到一点什么的话,那么请给我点个赞这样这篇文章就可以被更多人看到了。
\ No newline at end of file
diff --git a/TODO/go-function-calls-redux.md b/TODO/go-function-calls-redux.md
index 2e8b6efa515..0fefbdda247 100644
--- a/TODO/go-function-calls-redux.md
+++ b/TODO/go-function-calls-redux.md
@@ -10,7 +10,7 @@
什么是调用堆栈?它是一个用于保存局部变量和调用参数的内存区域,并且跟踪每个函数应该返回到哪里去。每个 goroutine 都有它自己的堆栈。你甚至可以说每个 goroutine 就是它自己的堆栈。
-下面是我用于演示堆栈的代码。就是一系列简单的函数调用,main() 函数调用 [f1(0xdeadbeef)](https://en.wikipedia.org/wiki/Hexspeak),然后调用 `f2(0xabad1dea)`,再调用 `f3(0xbaddcafe)`。然后 f3() 将其中一个作为它的参数,并且将它存储在名为 `local` 的本地变量中。然后获取 `local` 的内存地址并且从那里开始输出。因为 `loacl` 在栈内,所以输出的就是栈。
+下面是我用于演示堆栈的代码。就是一系列简单的函数调用,main() 函数调用 [f1(0xdeadbeef)](https://en.wikipedia.org/wiki/Hexspeak),然后调用 `f2(0xabad1dea)`,再调用 `f3(0xbaddcafe)`。然后 `f3()` 将其中一个作为它的参数,并且将它存储在名为 `local` 的本地变量中。然后获取 `local` 的内存地址并且从那里开始输出。因为 `local` 在栈内,所以输出的就是栈。
```go
package main
@@ -59,7 +59,7 @@ func showFunc(at uintptr) {
}
```
-下面是上述代码的输出结果。它是从 `local` 的地址开始的内存转储,是以十六进制形式展示的8字节列表。左边是每个整数的存储地址,右边是地址内存储的整数。
+下面是上述代码的输出结果。它是从 `local` 的地址开始的内存转储,是以十六进制形式展示的 8 字节列表。左边是每个整数的存储地址,右边是地址内存储的整数。
我们知道 `local` 应该等于 0xBADDCAFE + 1,或者 0xBADDCAFF,这确实是我们转储开始时看到的。
@@ -118,7 +118,7 @@ C42003FFC0: C4200001A0
通过这些我们可以看出:
- 首先,堆栈从高地址开始,堆栈地址随着函数调用变小。
-- 当进行函数调用时,调用者将参数放入栈内,然后返回地址(调用函数中的下一条指令的地址),接着指向堆栈中较高的指针。
+- 当进行函数调用时,调用者将参数放入栈内,然后是返回地址(调用函数中的下一条指令的地址),接着是指向堆栈中较高的指针。
- 当调用返回时,这个指针用于在堆栈中查找先前调用的函数。
- 局部变量存储在堆栈指针之后。
From 2668d72d4ad6e182aebb2ba64c3d21c11f69a186 Mon Sep 17 00:00:00 2001
From: xiaoyusilen
Date: Sun, 9 Apr 2017 13:07:56 +0800
Subject: [PATCH 086/638] add msg
---
TODO/anatomy-of-a-function-call-in-go.md | 2 +-
TODO/go-function-calls-redux.md | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/TODO/anatomy-of-a-function-call-in-go.md b/TODO/anatomy-of-a-function-call-in-go.md
index baca272576d..4fa70afdb03 100644
--- a/TODO/anatomy-of-a-function-call-in-go.md
+++ b/TODO/anatomy-of-a-function-call-in-go.md
@@ -2,7 +2,7 @@
> * 原文作者:[Phil Pearl](https://syslog.ravelin.com/@philpearl?source=post_header_lockup)
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
> * 译者:[xiaoyusilen](http://xiaoyu.world)
-> * 校对者:
+> * 校对者:[1992chenlu](https://github.com/1992chenlu)
# 解析 Go 中的函数调用 #
diff --git a/TODO/go-function-calls-redux.md b/TODO/go-function-calls-redux.md
index 0fefbdda247..b8717411ff1 100644
--- a/TODO/go-function-calls-redux.md
+++ b/TODO/go-function-calls-redux.md
@@ -2,7 +2,7 @@
> * 原文作者:[Phil Pearl](https://hackernoon.com/@philpearl?source=post_header_lockup)
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
> * 译者:[xiaoyusilen](http://xiaoyu.world)
-> * 校对者:
+> * 校对者:[1992chenlu](https://github.com/1992chenlu)
# Go 函数调用 Redux #
From 297bd3774a9a46e74b85a6806a36117486b9bf37 Mon Sep 17 00:00:00 2001
From: Tuccuay
Date: Sun, 9 Apr 2017 01:56:00 +0800
Subject: [PATCH 087/638] translated mastering swift essential details about
string
---
...g-swift-essential-details-about-strings.md | 548 +++++++++---------
1 file changed, 277 insertions(+), 271 deletions(-)
diff --git a/TODO/mastering-swift-essential-details-about-strings.md b/TODO/mastering-swift-essential-details-about-strings.md
index b223e0726ef..322df4619dc 100644
--- a/TODO/mastering-swift-essential-details-about-strings.md
+++ b/TODO/mastering-swift-essential-details-about-strings.md
@@ -1,270 +1,271 @@
> * 原文地址:[Mastering Swift: essential details about strings](https://rainsoft.io/mastering-swift-essential-details-about-strings/)
* 原文作者:[Dmitri Pavlutin](https://rainsoft.io/author/dmitri-pavlutin/)
* 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
-* 译者:
+* 译者:[Tuccuay](https://www.tuccuay.com)
* 校对者:
-# Mastering Swift: essential details about strings #
+# 掌握 Swift 的字符串细节
-String type is an important component of any programming language. The most useful information that user reads from the window of an iOS application is pure text.
+String 类型在任何编程语言中都是一个重要的组成部分。而用户从 iOS 应用的屏幕上能读取到最有效的信息也来自文本。
-To reach a higher number of users, the iOS application must be internationalised and support a lot of modern languages. The Unicode standard solves this problem, but creates additional complexity when working with strings.
+为了触及更多的用户,iOS 应用必须国际化以支持大量现代语言。Unicode 标准解决了这个问题,不过这也给我们使用 string 类型带来了额外的挑战性。
-On one hand, the language should provide a good balance between the Unicode complexity and the performance when processing strings. On the other hand, it should provide developer with comfortable structures to handle strings.
+从一方面来说,编程语言应该在平衡处理字符串时应该在 Unicode 复杂性和性能之间取得平衡。而另一方面,它需要为开发者提供一个舒适的结构来处理字符串。
-In my opinion, Swift does a great job on both hands.
+而在我看来,Swift 在这两方面都做的不错。
-Fortunately Swift's string is not a simple sequence of UTF-16 code units, like in JavaScript or Java.
+幸运的是 Swift 的 string 类型并不是像 JavaScript 或者 Java 那样简单的 UTF-16 序列。
-In case of a sequence of UTF-16 code units it's a pain to do Unicode-aware string manipulations: you might break a surrogate pair or combining character sequence.
+对一个 UTF-16 码单元序列执行 Unicode 感知的字符串操作是很痛苦的:你可能会打破代理对或组合字符序列。
-Swift implements a better approach. The string itself is not a collection, instead it provides views over the string content that may be applied according to situation. And one particular view, `String.CharacterView`, is fully Unicode-aware.
+Swift 对此有着更好的实现方式。字符串本身不再是集合,而是能够根据不同情况为内容提供不同的 view。其中一个特殊的 view: `String.CharacterView` 则是完全支持 Unicode 的。
-For `let myStr = "Hello, world"` you can access the following string views:
+对于 `let myStr = "Hello, world"` 来说,你可以访问到下面这些 view:
-- `myStr.characters` is `String.CharacterView`. Valuable to access graphemes, that visually are rendered as a single symbol. The most used view.
-- `myStr.unicodeScalars` is `String.UnicodeScalarView`. Valuable to access the Unicode code point numbers as 21-bit integers
-- `myStr.utf16` is `String.UTF16View`. Useful to access the code unit values encoded in UTF16
-- `myStr.utf8` is `String.UTF8View`. Valuable to access the code unit values encoded in UTF8
+- `myStr.characters` 即 `String.CharacterView`。可以获取字形的值,视觉上呈现为单一的符号。是最常用的试图
+- `myStr.unicodeScalars` 即 `String.UnicodeScalarView`。可以获取 21 整数表示的 Unicode 码位。
+- `myStr.utf16` 即 `String.UTF16View`。用于获取 UTF16 编码的代码单元。
+- `myStr.utf8` 即 `String.UTF8View`。能够获取 UTF8 编码的代码单一。
-![CharacterView, UnicodeScalarView, UTF16View, UTF8View of strings in Swift](https://rainsoft.io/content/images/2016/10/Swift-strings--3-.png)
+![Swift 中的 CharacterView, UnicodeScalarView, UTF16View 和 UTF8View](https://rainsoft.io/content/images/2016/10/Swift-strings--3-.png)
-Most of the time developer deals with simple string characters, without diving into details like encoding or code units.
+在大多数时候开发者都在处理简单的字符串字符,而不是深入到编码或者码位这样的细节中。
-`CharacterView` works nice for most of the string related tasks: iteration over the characters, counting the number of characters, verify substring existence, access by index, different manipulations and so on.
+`CharacterView` 能很好的完成大多数任务:迭代字符串、字符计数、验证是否包含字符串、通过索引访问和比较操作等。
-Let's see in more details how these tasks are accomplished in Swift.
+让我们看看如何用 Swift 来完成这些任务。
-# 1. Character and CharacterView structures #
+# 1. Character 和 CharterView 的结构
-`String.CharacterView` structure is a view over string content that is a collection of `Character`.
+`String.CharacterView` 的结构是一个字符内容的视图,它是 `Character` 的集合。
-To access the view from a string, use `characters` string property:
+要从字符串访问视图,使用字符的 `characters` 属性:
[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57ff7e018ef62b25bcea2ab1)
-```
-let message ="Hello, world"
-let characters = message.characters
-print(type(of: characters))// => "CharacterView"
+```swift
+let message = "Hello, world"
+let characters = message.characters
+print(type(of: characters))// => "CharacterView"
```
-`message.characters` returns the `CharacterView` structure.
+`message.characters` 返回了 `CharacterView` 结构.
-The character view is a collection of `Character` structures. For example, let's access the first character in a string view:
+字符视图是 `Character` 结构的集合。例如我们可以这样来访问字符视图里的第一个字符:
[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57ff7e188ef62b25bcea2ab2)
-```
-let message = "Hello, world"
-let firstCharacter = message.characters.first!
-print(firstCharacter) // => "H"
+```swift
+let message = "Hello, world"
+let firstCharacter = message.characters.first!
+print(firstCharacter) // => "H"
print(type(of: firstCharacter)) // => "Character"
-let capitalHCharacter: Character = "H"
+let capitalHCharacter: Character = "H"
print(capitalHCharacter == firstCharacter) // => true
```
-`message.characters.first` returns an optional that is the first character `"H"`.
+`message.characters.first` 返回了一个可选类型,内容是它的第一个字符 `"H"`.
-The character instance represents a single symbol `H`.
+这个字符实例代表了单个符号 `H`。
-In Unicode terms `H` is *Latin Capital letter H*, `U+0048` code point.
+在 Unicode 标准中,`H` 代表 *Latin Capital letter H*,码位是 `U+0048`。
-Let's go beyond ASCII and see how Swift handles composite symbols. Such characters are rendered as a single visual symbol, but are composed from a sequence of two or more [Unicode scalars](http://unicode.org/glossary/#unicode_scalar_value). Strictly such characters are named **grapheme clusters**.
+让我们掠过 ASCII 看看 Swift 如何处理更复杂的符号。这些字符被渲染成单个视觉符号,但实际上是由两个或更多个 Unicode 标量](http://unicode.org/glossary/#unicode_scalar_value) 组成。严格来说这些字符被称为 **字形簇**
-*Important*: `CharacterView` is a collection of grapheme clusters of the string.
+*Important*: `CharacterView` is a collection of grapheme clusters of the string.
+**重点**: `CharacterView` 是字符串的字形簇集合。
-Let's take a closer look at `ç` grapheme. It may be represented in two ways:
+让我们看看 `ç` 的字形。他可以有两种表现形式:
-- Using `U+00E7` *LATIN SMALL LETTER C WITH CEDILLA*: rendered as `ç`
-- Or using a combining character sequence: `U+0063`*LATIN SMALL LETTER C* plus the combining mark `U+0327` *COMBINING CEDILLA*. The grapheme is composite: `c` + `◌̧` = `ç`
+- 使用 `U+00E7` *LATIN SMALL LETTER C WITH CEDILLA*:被渲染为 `ç`
+- 或者使用组合字符序列:`U+0063`*LATIN SMALL LETTER C* 加上 组合标记 `U + 0327` *COMBINING CEDILLA* 组成复合字形:`c` + `◌̧` = `ç`
-Let's pick the second option and see how Swift handles it:
+我们看看在第二个选项中 Swift 是如何处理它的:
[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f3466012fc531b0551b918)
-```
-let message = "c\u{0327}a va bien" // => "ça va bien"
-let firstCharacter = message.characters.first!
+```swift
+let message = "c\u{0327}a va bien" // => "ça va bien"
+let firstCharacter = message.characters.first!
print(firstCharacter) // => "ç"
-let combiningCharacter: Character = "c\u{0327}"
-print(combiningCharacter == firstCharacter) // => true
+let combiningCharacter: Character = "c\u{0327}"
+print(combiningCharacter == firstCharacter) // => true
```
-`firstCharacter` contains a single grapheme `ç` that is rendered using two Unicode scalars `U+0063` and `U+0327`.
+`firstCharacter` 包含了一个字形 `ç`,它是由两个 Unicode 标量 `U+0063` and `U+0327` 组合渲染出来的。
-`Character` structure accepts multiple Unicode scalars as long as they create a single grapheme. If you try to add more graphemes into a single `Character`, Swift triggers an error:
+`Character` 结构接受多个 Unicode 标量来创建一个单一的字形。如果你尝试在单个 `Character` 中添加更多的字形,Swift 将会出发错误:
-[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f3510212fc531b0551b91c)
+[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f3510212fc531b0551b91c)
-```
-let singleGrapheme: Character = "c\u{0327}\u{0301}" // Works
+```swift
+let singleGrapheme: Character = "c\u{0327}\u{0301}" // Works
print(singleGrapheme) // => "ḉ"
-let multipleGraphemes: Character = "ab" // Error!
+let multipleGraphemes: Character = "ab" // Error!
```
-Even if `singleGrapheme` is composed of 3 Unicode scalars, it creates a single grapheme `ḉ`.
-`multipleGraphemes` tries to create a `Character` from 2 Unicode scalars. This creates 2 separated graphemes `a` and `b` in a single `Character` structure, which is not allowed.
+即使 `singleGrapheme` 由 3 个 Unicode 标量组成,它创建了一个字形 `ḉ`。
+而 `multipleGraphemes` 则是从两个 Unicode 标量创建一个 `Character`,这将在单个 `Character` 结构中创建两个分离的字母 `a` 和 `b`,这不是被允许的操作。
-# 2. Iterating over characters in a string #
+# 2. 迭代字符串中的字符
-`CharacterView` collection conforms to `Sequence` protocol. This allows to iterate over the view characters in a `for-in` loop:
+`CharacterView` 集合遵循了 `Sequence` 协议。这将允许在 `for-in` 循环中便利字符视图:
[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4bc8f27a61152fe7c7410)
-```
+```swift
let weather ="rain"for char in weather.characters {print(char)}// => "r" // => "a" // => "i" // => "n"
```
-Each character from `weather.characters` is accessed using `for-in` loop. On every iteration `char` variable is assigned with a character from `weather` string: `"r"`, `"a"`, `"i"` and `"n"`.
+我们可以在 `for-in` 循环中访问到 `weather.characters` 中的每个字符。`char` 变量将会在迭代中依次分配给 `weather` 中的 `"r"`, `"a"`, `"i"` 和 `"n"` 字符。
-As an alternative, you can iterate over the characters using `forEach(_:)` method, indicating a closure as the first argument:
+当然你也可以用 `forEach(_:)` 方法来迭代字符,指定一个闭包作为第一个参数:
[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4bca927a61152fe7c7411)
-```
-let weather = "rain"
-for char in weather.characters {
+```swift
+let weather = "rain"
+for char in weather.characters {
print(char)
}
-// => "r"
-// => "a"
-// => "i"
+// => "r"
+// => "a"
+// => "i"
// => "n"
```
-The iteration using `forEach(_:)` method is almost the same as `for-in`, only that you cannot use `continue` or `break` statements.
+使用 `forEach(_:)` 的方式与 `for-in` 相似,唯一的不同是你不能使用 `continue` 或者 `break` 语句。
-To access the index of the current character in the loop, `CharacterView` provides the `enumerated()` method. The method returns a sequence of tuples `(index, character)`:
+要在循环中访问当前字符串的索引可以通过 `CharacterView` 提供的 `enumerated()` 方法。这个方法将会返回一个元组序列 `(index, character)`:
[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4bcd127a61152fe7c7412)
-```
-let weather = "rain"
-for (index, char) in weather.characters.enumerated() {
+```swift
+let weather = "rain"
+for (index, char) in weather.characters.enumerated() {
print("index: \(index), char: \(char)")
}
-// => "index: 0, char: r"
-// => "index: 1, char: a"
-// => "index: 2, char: i"
-// => "index: 3, char: n"
+// => "index: 0, char: r"
+// => "index: 1, char: a"
+// => "index: 2, char: i"
+// => "index: 3, char: n"
```
-`enumerated()` method on each iteration returns tuples `(index, char)`.
-`index` variable contains the character index at the current loop step. Correspondingly `char` variable contains the character.
+`enumerated()` 方法在每次迭代时返回元组 `(index, char)`。
+`index` 变量即为循环中当前字符的索引,而 `char` 变量则是循环中当前的字符。
-# 3. Counting characters #
+# 3. 统计字符
-Simply use `count` property of the `CharacterView` to get the number of characters:
+只需要访问 `CharacterView` 的 `counter` 属性就可以获得字符串中字符的个数:
-[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4bcf327a61152fe7c7413)
+[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4bcf327a61152fe7c7413)
-```
-let weather ="sunny"print(weather.characters.count)// => 5
+```swift
+let weather ="sunny"print(weather.characters.count)// => 5
```
-`weather.characters.count` contains the number of characters in the string.
+`weather.characters.count` 是字符串中字符的个数。
-Each character in the view holds a grapheme. When an adjacent character (for example a [combining mark](http://unicode.org/glossary/#combining_character)) is appended to string, you may find that `count` property is not increased.
+视图中的每一个字符都拥有一个字形。当相邻字符(比如 [组合标记](http://unicode.org/glossary/#combining_character) )被添加到字符串时,你可能发现 `count` 属性没有没有变大。
-It happens because an adjacent character does not create a new grapheme in the string, instead it modifies an existing [base Unicode character](http://unicode.org/glossary/#base_character). Let's see an example:
+这是因为相邻字符并没有在字符串中创建一个新的字形,而是附加到了已经存在的 [基本 Unicode 字形](http://unicode.org/glossary/#base_character) 中。让我们看一个例子:
[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4bd0927a61152fe7c7414)
-```
-var drink = "cafe"
-print(drink.characters.count) // => 4
-drink += "\u{0301}"
-print(drink) // => "café"
-print(drink.characters.count) // => 4
+```swift
+var drink = "cafe"
+print(drink.characters.count) // => 4
+drink += "\u{0301}"
+print(drink) // => "café"
+print(drink.characters.count) // => 4
```
-Initially `drink` has 4 characters.
+一开始 `drink` 含有四个字符。
-When the combining mark `U+0301`*COMBINING ACUTE ACCENT* is appended to string, it modifies the previous base character `e` and creates a new grapheme `é`. The property `count` is not increased, because the number of graphemes is still the same.
+当组合标记 `U+0301`*COMBINING ACUTE ACCENT* 被添加到字符串中,它改变了上一个基本字符 `e` 并创建了新的字形 `é`。这时属性 `count` 并没有变大,因为字形数量仍然相同。
-# 4. Accessing character by index #
+# 4. 按索引访问字符
-Swift doesn't know about the characters count in the string view until it actually evaluates the graphemes in it. As result a subscript that allows to access the character by an integer index directly does not exist.
+因为 Swift 直到它实际评估字符视图中的字形之前都不知道字符串中的字符个数。结果就造成了无法通过通过下标的方式访问字符串索引。
-You can access the characters by a special type `String.Index`.
+你可以通过特殊的类型 `String.Index` 访问字符。
-If you need to access the first or last characters in the string, the character view structure has `first` and `last` properties:
+如果你需要访问字符串中的第一个或者最好一个字符,字符视图结构提供了 `first` 和 `last` 属性:
-[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4bd2027a61152fe7c7415)
+[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4bd2027a61152fe7c7415)
-```
-let season = "summer"
-print(season.characters.first!) // => "s"
-print(season.characters.last!) // => "r"
-let empty = ""
-print(empty.characters.first == nil) // => true
-print(empty.characters.last == nil) // => true
+```swift
+let season = "summer"
+print(season.characters.first!) // => "s"
+print(season.characters.last!) // => "r"
+let empty = ""
+print(empty.characters.first == nil) // => true
+print(empty.characters.last == nil) // => true
```
-Notice that `first` and `last` properties are optional type `Character?`.
+注意 `first` 和 `last` 属性将会返回可选类型 `Character?`。
-In the empty string `empty` these properties are `nil`.
+在空字符串 `empty` 这些属性将会是 `nil`。
![String indexes in Swift](https://rainsoft.io/content/images/2016/10/Swift-strings--2--1.png)
-To get a character at specific position, you have to use `String.Index` type (actually an alias of `String.CharacterView.Index`). String offers a subscript that accepts `String.Index` to access the character, as well as pre-defined indexes `myString.startIndex` and `myString.endIndex`.
+要获取特定位置的字符,你必须使用 `String.Index` 类型(实际上是 `String.CharacterView.Index`的别名)。字符提供了一个接受 `String.Index` 下标访问字符的方法,以及预定义的索引 `myString.startIndex` 和 `myString.endIndex`。
-Using string index type, let's access the first and last characters:
+让我们使用字符串索引来访问第一个和最后一个字符:
[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4bd3627a61152fe7c7416)
-```
-let color = "green"
-let startIndex = color.startIndex
-let beforeEndIndex = color.index(before: color.endIndex)
-print(color[startIndex]) // => "g"
-print(color[beforeEndIndex]) // => "n"
+```swift
+let color = "green"
+let startIndex = color.startIndex
+let beforeEndIndex = color.index(before: color.endIndex)
+print(color[startIndex]) // => "g"
+print(color[beforeEndIndex]) // => "n"
```
-`color.startIndex` is the first character index, so `color[startIndex]` evaluates to `g`.
-`color.endIndex` indicates the *past the end* position, or simply the position one greater than the last valid subscript argument. To access the last character, you must calculate the index right before string's end index: `color.index(before: color.endIndex)`.
+`color.startIndex` 是第一个字符的索引,所以 `color[startIndex]` 表示为 `g`。
+`color.endIndex` 表示**结束**位置,或者简单的说是比最后一个有效小标参数大的位置。要访问最后一个字符,你必须计算它的前一个索引:`color.index(before: color.endIndex)`
-To access characters at position by an offset, use the `offsetBy` argument of `index(theIndex, offsetBy: theOffset)` method:
+要通过偏移访问字符的位置, 在 `index(theIndex, offsetBy: theOffset)` 方法中使用 `offsetBy` 参数:
-[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4bd4d27a61152fe7c7417)
+[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4bd4d27a61152fe7c7417)
-```
-let color = "green"
-let secondCharIndex = color.index(color.startIndex, offsetBy: 1)
-let thirdCharIndex = color.index(color.startIndex, offsetBy: 2)
-print(color[secondCharIndex]) // => "r"
-print(color[thirdCharIndex]) // => "e"
+```swift
+let color = "green"
+let secondCharIndex = color.index(color.startIndex, offsetBy: 1)
+let thirdCharIndex = color.index(color.startIndex, offsetBy: 2)
+print(color[secondCharIndex]) // => "r"
+print(color[thirdCharIndex]) // => "e"
```
-Indicating the `offsetBy` argument, you can access the character at specific offset.
+指定 `offsetBy` 参数,你将可以放特定偏移量位置的字符。
-Of course `offsetBy` argument is jumping over string graphemes, i.e. the offset applies over `Character` instances of string's `CharacterView`.
+当然,`offsetBy` 参数是的步进是字符串的字形。即偏移量适用于 `ChacterView` 中的 `Chacter` 实例。
-If the index is out of range, Swift generates an error:
+如果索引超出范围,Swift 会触发错误。
-[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4bd7227a61152fe7c7418)
+[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4bd7227a61152fe7c7418)
-```
+```swift
let color ="green"
-let oops = color.index(color.startIndex, offsetBy:100)// Error!
+let oops = color.index(color.startIndex, offsetBy:100) // Error!
```
-To prevent such situations, indicate an additional argument `limitedBy` to limit the offset: `index(theIndex, offsetBy: theOffset, limitedBy: theLimit)`. The function returns an optional, which is `nil` for out of bounds index:
+为了防止这种情况,可以指定一个 `limitedBy` 参数来限制最大偏移量:`index(theIndex, offsetBy: theOffset, limitedBy: theLimit)`。这个函数将会返回一个可选类型,当索引超出范围时将会返回 `nil`:
-[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4bd8d27a61152fe7c7419)
+[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4bd8d27a61152fe7c7419)
-```
-let color = "green"
-let oops = color.index(color.startIndex, offsetBy: 100,
+```swift
+let color = "green"
+let oops = color.index(color.startIndex, offsetBy: 100,
limitedBy: color.endIndex)
-if let charIndex = oops {
+if let charIndex = oops {
print("Correct index")
} else {
print("Incorrect index")
@@ -272,269 +273,274 @@ if let charIndex = oops {
// => "Incorrect index"
```
-`oops` is an optional `String.Index?`. The optional unwrap verifies whether the index didn't jump out of the string.
+`oops` 是一个可选类型 `String.Index?`。展开可选类型可以验证索引是否超出了字符串的范围。
-# 5. Checking substring existence #
+# 5. 检查子串是否存在
-The simplest way to verify the substring existence is to call `contains(_ other: String)` string method:
+验证子串是否存在的最简单方法是调用 `contains(_ other: String)` 方法:
[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4bda427a61152fe7c741a)
-```
-importFoundationlet animal ="white rabbit"print(animal.contains("rabbit"))// => true print(animal.contains("cat"))// => false
+```swift
+import Foundation
+let animal = "white rabbit"
+print(animal.contains("rabbit")) // => true
+print(animal.contains("cat")) // => false
```
-`animal.contains("rabbit")` returns `true` because `animal` contains `"rabbit"` substring.
+`animal.contains("rabbit")` 将返回 `true` 因为 `animal` 包含了 `"rabbit"` 字符串。
-Correspondingly `animal.contains("cat")` evaluates to `false` for a non-existing substring.
+那么当子字串不存在的时候 `animal.contains("cat")` 的值将为 `false`。
-To verify whether the string has specific prefix or suffix, the methods `hasPrefix(_:)` and `hasSuffix(_:)` are available. Let's use them in an example:
+要验证字符串是否具有特定的前缀或后缀,可以使用 `hasPrefix(_:)` 和 `hasSuffix(_:)` 方法。我们来看一个例子:
-[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4bdb627a61152fe7c741b)
+[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4bdb627a61152fe7c741b)
-```
-importFoundationlet
-animal ="white rabbit"
-print(animal.hasPrefix("white"))// => true print(animal.hasSuffix("rabbit"))// => true
+```swift
+importFoundationlet
+animal = "white rabbit"
+print(animal.hasPrefix("white")) // => true
+print(animal.hasSuffix("rabbit")) // => true
```
-`"white"` is a prefix and `"rabbit"` is a suffix of `"white rabbit"`. So the corresponding method calls `animal.hasPrefix("white")` and `animal.hasSuffix("rabbit")` return `true`.
+`"white rabbit"` 以 `"white"` 开头并以 `"rabbit"` 结尾。所以我们调用 `animal.hasPrefix("white")` 和 `animal.hasSuffix("rabbit")` 方法都将返回 `true`。
-When you need to search for a particular character, it makes sense to query directly the character view. For example:
+当你想搜索字符串时,直接查询字符视图是就可以了。比如:
-[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4bdc827a61152fe7c741c)
+[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4bdc827a61152fe7c741c)
-```
-let animal = "white rabbit"
-let aChar: Character = "a"
-let bChar: Character = "b"
-print(animal.characters.contains(aChar)) // => true
-print(animal.characters.contains {
+```swift
+let animal = "white rabbit"
+let aChar: Character = "a"
+let bChar: Character = "b"
+print(animal.characters.contains(aChar)) // => true
+print(animal.characters.contains {
$0 == aChar || $0 == bChar
}) // => true
```
-`contains(_:)` verifies whether the character view has a particular character.
+`contains(_:)` 将验证字符视图是否包含指定视图。
-The second function form accepts a closure: `contains(where predicate: (Character) -> Bool)` and performs the same verification.
+而第二个函数 `contains(where predicate: (Character) -> Bool)` 则是接受一个闭包并执行验证。
-# 6. String manipulation #
+# 6. 字符串操作
-The string in Swift is a *value type*. Whether you pass a string as an argument on function call, assign it to a variable or constant - every time a *copy* of the original string is created.
+字符串在 Swift 中是 *value type*(值类型)。无论你是将它作为参数进行函数调用还是将它分配给一个变量或者常量——每次复制都将会创建一个全新的**拷贝**。
-A mutating method call changes the string in place.
+所有的可变方法都是在空间内将字符串改变。
-This chapter covers the common manipulations over strings.
+本节涵盖了对字符串的常见操作。
-#### Append to string a character or another string ####
+#### 附加字符串到另一个字符串
-The simplest way to append to string is `+=` operator. You can append an entire string to original one:
+附加字符串较为简便的方法是直接使用 `+=` 操作符。你可以直接将整个字符串附加到原始字符串:
-[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4bddf27a61152fe7c741d)
+[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4bddf27a61152fe7c741d)
-```
-var bird ="pigeon"
+```swift
+var bird ="pigeon"
bird +=" sparrow"
-print(bird)// => "pigeon sparrow"
+print(bird) // => "pigeon sparrow"
```
-String structure provides a mutating method `append()`. The method accepts a string, a character or even a sequence of characters, and appends it to the original string. For instance:
+字符串结构提供了一个可变方法 `append()`。该方法接受字符串、字符甚至字符序列,并将其附加到原始字符串。例如
-[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4bdff27a61152fe7c741e)
+[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4bdff27a61152fe7c741e)
-```
-var bird = "pigeon"
-let sChar: Character = "s"
-bird.append(sChar)
-print(bird) // => "pigeons"
-bird.append(" and sparrows")
-print(bird) // => "pigeons and sparrows"
-bird.append(contentsOf: " fly".characters)
-print(bird) // => "pigeons and sparrows fly"
+```swift
+var bird = "pigeon"
+let sChar: Character = "s"
+bird.append(sChar)
+print(bird) // => "pigeons"
+bird.append(" and sparrows")
+print(bird) // => "pigeons and sparrows"
+bird.append(contentsOf: " fly".characters)
+print(bird) // => "pigeons and sparrows fly"
```
-#### Extract a substring from string ####
+#### 从字符串中截取字符串
-The method `substring()` allows to extract substrings:
+使用 `substring()` 方法可以截取字符串:
-- from a specific index up to the end of string
-- from the the start up to a specific index
-- or based on a range of indexes.
+- 从特定索引到字符串的末尾
+- 从开头到特定索引
+- 或者基于一个索引区间
-Let's see how it works:
+让我们来看看它是如何工作的
-[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4be1527a61152fe7c741f)
+[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4be1527a61152fe7c741f)
-```
-
-let plant = "red flower"
-let strIndex = plant.index(plant.startIndex, offsetBy: 4)
-print(plant.substring(from: strIndex)) // => "flower"
+```swift
+let plant = "red flower"
+let strIndex = plant.index(plant.startIndex, offsetBy: 4)
+print(plant.substring(from: strIndex)) // => "flower"
print(plant.substring(to: strIndex)) // => "red "
-if let index = plant.characters.index(of: "f") {
+if let index = plant.characters.index(of: "f") {
let flowerRange = index.. "flower"
+ print(plant.substring(with: flowerRange)) // => "flower"
}
```
-The string subscript accepts a range or closed range of string indexes. This helps extracting substrings based on ranges of indexes:
+字符串下标接受一个区间或者封闭区间作为字符索引。这有助于根据范围截取子串:
[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4be3127a61152fe7c7420) (target=undefined)
-```
-let plant ="green tree"let excludeFirstRange =
+```swift
+let plant ="green tree"let excludeFirstRange =
plant.index(plant.startIndex, offsetBy:1).. "reen tree" let lastTwoRange =
- plant.index(plant.endIndex, offsetBy:-2).. "ee"
+print(plant[excludeFirstRange]) // => "reen tree"
+let lastTwoRange = plant.index(plant.endIndex, offsetBy:-2).. "ee"
```
-#### Insert into string ####
+#### 插入字符串
-The string type provides the mutating method `insert()`. The method allows to insert a character or a sequence of characters at specific index.
+字符串类型提供了可变方法 `insert()`。此方法可以在特定索引处插入一个字符或者一个字符序列。
-The new character or sequence is inserted before the element currently at the specified index.
+新的字符将被插入到指定索引的元素之前。
-See the following sample:
+来看一个例子:
[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4be4a27a61152fe7c7421)
-```
-var plant = "green tree"
-plant.insert("s", at: plant.endIndex)
-print(plant) // => "green trees"
-plant.insert(contentsOf: "nice ".characters, at: plant.startIndex)
-print(plant) // => "nice green trees"
+```swift
+var plant = "green tree"
+plant.insert("s", at: plant.endIndex)
+print(plant) // => "green trees"
+plant.insert(contentsOf: "nice ".characters, at: plant.startIndex)
+print(plant) // => "nice green trees"
```
-#### Remove from string ####
+#### 移除字符
-The mutating method `remove(at:)` removes the character at an index:
+可变方法 `remove(at:)` 可以删除指定索引处的字符:
[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4be6527a61152fe7c7422)
-```
-var weather = "sunny day"
-if let index = weather.characters.index(of: " ") {
+```swift
+var weather = "sunny day"
+if let index = weather.characters.index(of: " ") {
weather.remove(at: index)
print(weather) // => "sunnyday"
}
```
-You can remove characters in the string that are in a range of indexes using `removeSubrange(_:)`:
+你也可以使用 `removeSubrange(_:)` 来从字符串中移除一个索引区间内的全部字符:
[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4be7b27a61152fe7c7423)
-```
-var weather = "sunny day"
-let index = weather.index(weather.startIndex, offsetBy: 6)
-let range = index.. "sunny"
+```swift
+var weather = "sunny day"
+let index = weather.index(weather.startIndex, offsetBy: 6)
+let range = index.. "sunny"
```
-#### Replace in string ####
+#### 替换字符串
-The method `replaceSubrange(_:with:)` accepts a range of indexes that should be replaced with a particular string. The method is mutating the string.
+`replaceSubrange(_:with:)` 方法接受一个索引区间并可以将区间内的字符串替换为特定字符串。这是字符串的一个可变方法。
-Let's see a sample:
+一个简单的例子:
[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4be9327a61152fe7c7424)
-```
-var weather = "sunny day"
-if let index = weather.characters.index(of: " ") {
+```swift
+var weather = "sunny day"
+if let index = weather.characters.index(of: " ") {
let range = weather.startIndex.. "rainy day"
}
```
-#### The character view mutation alternative ####
+#### 另一些关于字符串的可变操作
-Many of string manipulations described above may be applied directly on string's character view.
+上面描述的许多字符串操作都是直接应用于字符串中的字符视图。
-It is a good alternative if you find more comfortable to work directly with a collection of characters.
+而更方便的直接使用一个字符序列可能是更好的选择。
-For example you can remove characters at specific index, or directly the first or last characters:
+比如你可以删除特定索引出的字符,或者直接删除第一个或者最好一个字符:
[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4bea927a61152fe7c7425)
-```
-var fruit = "apple"
-fruit.characters.remove(at: fruit.startIndex)
-print(fruit) // => "pple"
-fruit.characters.removeFirst()
-print(fruit) // => "ple"
-fruit.characters.removeLast()
-print(fruit) // => "pl"
+```swift
+var fruit = "apple"
+fruit.characters.remove(at: fruit.startIndex)
+print(fruit) // => "pple"
+fruit.characters.removeFirst()
+print(fruit) // => "ple"
+fruit.characters.removeLast()
+print(fruit) // => "pl"
```
-To reverse a word use `reversed()` method of the character view:
+使用字符视图中的 `reversed()` 方法来翻转字符视图:
[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4bebf27a61152fe7c7426)
-```
+
+```swift
var fruit ="peach"
var reversed =String(fruit.characters.reversed())
-print(reversed)// => "hcaep"
+print(reversed)// => "hcaep"
```
-You can easily filter the string:
+ 你可以很简单得过滤字符串:
-[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4beea27a61152fe7c7427)
+[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4beea27a61152fe7c7427)
-```
-let fruit = "or*an*ge"
-let filtered = fruit.characters.filter { char in
+```swift
+let fruit = "or*an*ge"
+let filtered = fruit.characters.filter { char in
return char != "*"
}
-print(String(filtered)) // => "orange"
+print(String(filtered)) // => "orange"
```
-Map the string content by applying a transformer closure:
+Map 可以接受一个闭包来对字符串进行变换:
-[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4befd27a61152fe7c7428)
+[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4befd27a61152fe7c7428)
-```
-let fruit = "or*an*ge"
-let mapped = fruit.characters.map { char -> Character in
+```swift
+let fruit = "or*an*ge"
+let mapped = fruit.characters.map { char -> Character in
if char == "*" {
return "+"
}
return char
}
-print(String(mapped)) // => "or+an+ge"
+print(String(mapped)) // => "or+an+ge"
```
-Or reduce the string content to an accumulator value:
+或者使用 reduce 来对字符串来进行一些累加操作:
-[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4bf1d27a61152fe7c7429) (target=undefined)
+[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4bf1d27a61152fe7c7429)
-```
-let fruit = "or*an*ge"
-let numberOfStars = fruit.characters.reduce(0) { countStars, char in
+```swift
+let fruit = "or*an*ge"
+let numberOfStars = fruit.characters.reduce(0) { countStars, char in
if (char == "*") {
return countStarts + 1
}
return countStars
-}
-print(numberOfStars) // => 2
+}
+print(numberOfStars) // => 2
```
-# 7. Final words #
+# 7. 说在最后
-At first sight, the idea of different types of views over string's content may seem overcomplicated.
+首先要说,大家对于字符串内容持有的不同观点看起来似乎过于复杂。
-In my opinion it is a great implementation. Strings can be viewed in different angles: as a collection of graphemes, UTF-8 or UTF-16 code units or simple Unicode scalars.
+而在我看来这是一个很好的实现。字符串可以从不同的角度来例假:昨晚字形集合、UTF-8 或 UTF-16 码位和简单是 Unicode 标量。
-Just pick the view depending on your task. In most of the cases it is `CharacterView`.
+根据你的任务来选择合适的视图。在大多数情况下,`CharacterView` 都很合适。
-The character view deals with graphemes that may be compound from one or more Unicode scalars. As result the string cannot be integer indexed (like arrays). Instead a special type of index is applicable: `String.Index`.
+因为字符视图中可能包含来自一个或多个 Unicode 标量组成的字形。因此字符串并不能像数组那样直接被整数索引。不过可以用特殊的 `String.Index` 来索引字符串。
-Special index type adds a bit of complexity when accessing individual characters or manipulating strings. I agree to pay this price, because having truly Unicode-aware operations on strings is awesome!
+虽然特殊的索引类型导致在访问单个字符串或者操作字符串时增加了一些难度。我接受这个成本,因为在字符串上进行诊治的 Unicode 感知操作真的很棒!
*Do you find string views comfortable to use? Write a comment bellow and let's discuss!*
+*您是否发现使用舒适的字符串视图? 写下评论,让我们讨论一下!
+**对于字符操作你有没有找到更舒适的方法?写下评论我们一起来讨论一些吧!**
-**P.S.** You might be interested to read my [detailed overview of array and dictionary literals in Swift](https://rainsoft.io/concise-initialization-of-collections-in-swift/).
-
+**P.S.** 不知道你有没有兴趣阅读我的另一篇文章:[detailed overview of array and dictionary literals in Swift](https://rainsoft.io/concise-initialization-of-collections-in-swift/)
\ No newline at end of file
From fff51d3ef8a59fb7d27b3141addd5df9f0801668 Mon Sep 17 00:00:00 2001
From: Tuccuay
Date: Sun, 9 Apr 2017 15:16:14 +0800
Subject: [PATCH 088/638] fix typo
---
TODO/mastering-swift-essential-details-about-strings.md | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/TODO/mastering-swift-essential-details-about-strings.md b/TODO/mastering-swift-essential-details-about-strings.md
index 322df4619dc..325223b5681 100644
--- a/TODO/mastering-swift-essential-details-about-strings.md
+++ b/TODO/mastering-swift-essential-details-about-strings.md
@@ -537,10 +537,8 @@ print(numberOfStars) // => 2
因为字符视图中可能包含来自一个或多个 Unicode 标量组成的字形。因此字符串并不能像数组那样直接被整数索引。不过可以用特殊的 `String.Index` 来索引字符串。
-虽然特殊的索引类型导致在访问单个字符串或者操作字符串时增加了一些难度。我接受这个成本,因为在字符串上进行诊治的 Unicode 感知操作真的很棒!
+虽然特殊的索引类型导致在访问单个字符串或者操作字符串时增加了一些难度。我接受这个成本,因为在字符串上进行真正的 Unicode 感知操作真的很棒!
-*Do you find string views comfortable to use? Write a comment bellow and let's discuss!*
-*您是否发现使用舒适的字符串视图? 写下评论,让我们讨论一下!
**对于字符操作你有没有找到更舒适的方法?写下评论我们一起来讨论一些吧!**
**P.S.** 不知道你有没有兴趣阅读我的另一篇文章:[detailed overview of array and dictionary literals in Swift](https://rainsoft.io/concise-initialization-of-collections-in-swift/)
\ No newline at end of file
From fc3e9aa67f16aee91eade3e94fc777ce289cd439 Mon Sep 17 00:00:00 2001
From: lsvih
Date: Sun, 9 Apr 2017 18:04:08 +0800
Subject: [PATCH 089/638] Webpack and Rollup: the same but different
---
...bpack-and-rollup-the-same-but-different.md | 50 +++++++++----------
1 file changed, 25 insertions(+), 25 deletions(-)
diff --git a/TODO/webpack-and-rollup-the-same-but-different.md b/TODO/webpack-and-rollup-the-same-but-different.md
index 7bc3f470f12..4e286f35689 100644
--- a/TODO/webpack-and-rollup-the-same-but-different.md
+++ b/TODO/webpack-and-rollup-the-same-but-different.md
@@ -1,57 +1,57 @@
> * 原文地址:[Webpack and Rollup: the same but different](https://medium.com/webpack/webpack-and-rollup-the-same-but-different-a41ad427058c)
> * 原文作者:[Rich Harris](https://medium.com/@Rich_Harris?source=post_header_lockup)
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
-> * 译者:
+> * 译者:[lsvih](https://github.com/lsvih)
> * 校对者:
-# Webpack and Rollup: the same but different #
+# 同中有异的 Webpack 与 Rollup #
![](https://cdn-images-1.medium.com/max/1000/1*rtjClMZ8sq3cLFT9Aq8Xyg.png)
-This week, Facebook merged a [monster pull request](https://github.com/facebook/react/pull/9327) into React that replaced its existing build process with one based on [Rollup](https://rollupjs.org/) , [prompting](https://twitter.com/stanlemon/status/849366789825994752) [several](https://twitter.com/MrMohtas/status/849362334988595201) [people](https://twitter.com/kyleholzinger/status/849683292760797184) to ask ‘why did you choose Rollup over webpack’?
+本周,Facebook 将一个[非常大的 pull request](https://github.com/facebook/react/pull/9327) 合并到了 React 主分支。这个 PR 将 React 以前使用的构建工具替换成了 [Rollup](https://rollupjs.org/)。这让许多人感到不解,纷纷在推特上提问:“为什么你们选择 Rollup 而不选择 Webpack 呢?”[1](https://twitter.com/stanlemon/status/849366789825994752)[2](https://twitter.com/MrMohtas/status/849362334988595201)[3](https://twitter.com/kyleholzinger/status/849683292760797184)
-Which is a completely reasonable question. [Webpack](https://webpack.js.org/) is one of the modern JavaScript community’s greatest success stories, with millions of downloads every month powering tens of thousands of websites and applications. It has a large ecosystem, dozens of contributors, and — unusually for a community open source project — [meaningful financial support](https://opencollective.com/webpack) .
+有人问这个问题是很正常的。[Webpack](https://webpack.js.org/) 是现在 JavaScript 社区中最伟大的成功传奇之一,它有着数百万/月的下载量,驱动了成千上万的网站与应用。它有着巨大的生态系统、众多的贡献者,并且它与一般的社区开源项目不同——它有着[意义非凡的经济支持](https://opencollective.com/webpack)。
-By comparison, Rollup is a minnow. But React isn’t alone — Vue, Ember, Preact, D3, Three.js, Moment, and dozens of other well-known libraries also use Rollup. So what’s going on? Why can’t we have just one JavaScript module bundler that everyone agrees on?
+相比之下,Rollup 是那么的微不足道。但是,除了 React 之外,Vue、Ember、Preact、D3、Three.js、Moment 等众多知名项目都使用了 Rollup。为什么会这样呢?为什么这些项目不使用大家一致认可的 JavaScript 模块打包工具呢?
-### A tale of two bundlers ###
+### 这两个打包工具的优缺点 ###
-webpack was started in 2012 by [Tobias Koppers](https://medium.com/@sokra) to solve a hard problem that existing tools didn’t address: building complex single-page applications (SPAs). Two features in particular changed everything:
+Webpack 由 [Tobias Koppers](https://medium.com/@sokra) 在 2012 年创建,用于解决当时的工具不能处理的问题:构建复杂的单页应用(SPA)。它的两个特点改变了一切:
-1. **Code-splitting** makes it possible to break your app apart into manageable chunks that can be loaded on-demand, meaning your users get an interactive site much faster than if they had to wait for the whole application to download and parse. You *can* do this manually, but, well… good luck.
-2. **Static assets** such as images and CSS can be imported into your app and treated as just another node in the dependency graph. No more carefully placing your files in the right folders and hacked-together scripts for adding hashes to file URLs — webpack can take care of it for you.
+1. **代码分割**可以将你的 app 分割成许多个容易管理的分块,这些分块能够在用户使用你的 app 时按需加载。这意味着你的网站可以比那些没有使用此技术的网站要快上很多。因为访问那些网站必须要等待整个应用都被下载并解析完成。当然,你**也可以**自己手动去进行代码分割,但是……总之,祝你好运。
+2. **静态资源**的导入:图片、CSS 等静态资源可以直接导入到你的 app 中,就和其它的模块、节点一样能够进行依赖管理。因此,我们再也不用小心翼翼地将各个静态文件放在特定的文件夹中,然后再去用脚本给文件 URL 加上哈希串了。Webpack 已经帮你完成了这一切。
-Rollup was created for a different reason: to build flat distributables of JavaScript libraries as efficiently as possible, taking advantage of the ingenious design of ES2015 modules. Other module bundlers — webpack included — work by wrapping each module in a function, putting them in a bundle with a browser-friendly implementation of `require`, and evaluating them one-by-one. That’s great if you need things like on-demand loading, but otherwise it’s a bit of a waste, and it [gets worse if you have lots of modules](https://nolanlawson.com/2016/08/15/the-cost-of-small-modules/).
+而 Rollup 的开发理念则不同:它利用 ES2015 模块的巧妙设计,尽可能高效地构建精简且易分发的 JavaScript 库。而其它的模块打包器(包括 Webpack在内)都是通过将模块分别封装进函数中,然将这些函数通过能在浏览器中实现的 `require` 方法打包,最后依次处理这些函数。在你需要实现按需加载的时候,这种做法非常的方便,但是这样做引入了很多无关代码,比较浪费资源。当[你有很多模块要打包的时候,这种情况会变得更糟糕](https://nolanlawson.com/2016/08/15/the-cost-of-small-modules/)。
-ES2015 modules enable a different approach, which Rollup uses. All your code is put in the same place and evaluates in one go, resulting in leaner, simpler code that starts up faster. You can [see it for yourself with the Rollup REPL](https://rollupjs.org/repl).
+ES2015 模块则启用了一种不同的实现方法,Rollup 用的也就是这种方法。所有代码都将被放置在同一个地方,并且会在一起进行处理。因此得到的最终代码相较而言会更加的精简,运行起来自然也就更快。你可以[点击这儿亲自试试 Rollup 交互式解释器(REPL)](https://rollupjs.org/repl)。
-But there’s a trade-off: code-splitting is a much hairier problem, and at the time of writing Rollup doesn’t support it. Similarly, Rollup doesn’t do hot module replacement (HMR). And perhaps the biggest pain point for people coming to Rollup — while it handles most CommonJS files (via a [plugin](https://github.com/rollup/rollup-plugin-commonjs) ), some things just don’t translate to ES2015, whereas webpack handles everything you throw at it with aplomb.
+但这儿也存在一些需要权衡的点:代码分割是一个很棘手的问题,而 Rollup 并不能做到这一点。同样的,Rollup 也不支持模块热替换(HMR)。而且对于打算使用 Rollup 的人来说,还有一个最大的痛点:它通过[插件](https://github.com/rollup/rollup-plugin-commonjs)处理大多数 CommonJS 文件的时候,一些代码将无法被翻译回 ES2015。而与之相反,你可以把这一切的事全部放心交给 Webpack 去处理。
-### So which should I use? ###
+### 那么我到底应该选用哪一个呢? ###
-By now, hopefully it’s clear why both tools coexist and support each other — they serve different purposes. The tl;dr is this:
+回答这个问题之前,我们已经了解了这两个工具各自的优缺点,它们同时存在并相互支持的原因正是因为它们解决的问题不同。那么,现在这个问题的答案简单来说就是:
-> Use webpack for apps, and Rollup for libraries
+> 在开发应用时使用 Webpack,开发库时使用 Rollup
-That’s not a hard and fast rule — lots of sites and apps are built with Rollup, and lots of libraries are built with webpack. But it’s a good rule of thumb.
+当然这不是什么严格的规定——有很多的网站和 app 一样是使用 Rollup 构建的,同时也有很多的库使用 Webpack。不过,这是个很值得参考的经验之谈。
-If you need code-splitting, or you have lots of static assets, or you’re building something with lots of CommonJS dependencies, Webpack is a better choice. If your codebase is ES2015 modules and you’re making something to be used by other people, you probably want Rollup.
+如果你需要进行代码分割,或者你有很多的静态资源,再或者你做的东西深度依赖 CommonJS,毫无疑问 Webpack 是你的最佳选择。如果你的代码基于 ES2015 模块编写,并且你做的东西是准备给他人使用的,你应该更适合用 Rollup。
-### Package authors: use `pkg.module!` ###
+### 对于包作者的建议:请使用 `pkg.module`! ###
-For a long time, using JavaScript libraries was a bit of a crapshoot, because you and the library author effectively had to agree on a module system. If you were using Browserify but she preferred AMD, you would have to duct tape things together before you could actually build anything. The [Universal Module Definition](https://github.com/umdjs/umd) (UMD) format *sort of* fixed that, but because it wasn’t enforced anywhere you never knew quite what you were going to get.
+在很长一段时间里,使用 JavaScript 库是一件相当有风险的事,因为这意味着你必须和库的作者在模块系统上的意见保持一致。如果你使用 Browserify 而他更喜欢 AMD,你就不得不在 build 之前先强行将两者粘起来。[通用模块定义(UMD)](https://github.com/umdjs/umd)格式对这个问题进行了 *部分* 的修复,但是它没有强制要求所有的人都用它,最后反而会让你更加不知所措。
-ES2015 changes all that, because `import` and `export` are part of the language. In the future, there’ll be no ambiguity, and things will work a lot more seamlessly. Unfortunately, because browsers (mostly) and Node don’t yet support `import` and `export`, we still need to ship UMD files (or CommonJS, if you’re building something Node-only).
+ES2015 改变了这一切,因为 `import` 与 `export` 就是语言规范本身的一部分。在未来,不再会有现在这种模棱两可的情况,所有东西都将更加无缝地配合工作。不幸的是,由于大多数浏览器和 Node 还不支持 `import` 和 `export`,我们仍然需要依靠 UMD 规范(如果你只写 Node 的话也可以用 CommonJS)。
-By adding a `"module": "dist/my-library.es.js"` entry to your library’s package.json file (aka `pkg.module`), it’s possible to serve UMD and ES2015 at the same time, right now. **That’s important because Webpack and Rollup can both use** `pkg.module` **to generate the most efficient code possible** — in some cases, they can even both [tree-shake](https://webpack.js.org/guides/tree-shaking/) unused parts of your library away.
+现在给你的库的 package.json 文件增加一个 `"module": "dist/my-library.es.js"` 入口,可以让你的库同时支持 UMD 与 ES2015。**这很重要,因为 Webpack 和 Rollup 都使用了 ** `pkg.module` ** 来尽可能的生成效率更高的代码**——在一些情况下,它们都能使用 [tree-shake](https://webpack.js.org/guides/tree-shaking/) 来精简掉你的库中未使用的部分。
-*Learn more about`pkg.module` on the [*Rollup wiki*](https://github.com/rollup/rollup/wiki/pkg.module) .*
+*了解更多有关 `pkg.module` 的内容请访问 [Rollup wiki](https://github.com/rollup/rollup/wiki/pkg.module) 。*
-Hopefully this article makes the relationship between the two projects a bit clearer. If you still have questions, find us on Twitter at [rich_harris](https://twitter.com/rich_harris)/[rollupjs](https://twitter.com/rollupjs) and [thelarkinn](https://twitter.com/thelarkinn) . Happy bundling!
+希望这篇文章能让你理清这两个开源项目之间的关系。如果你还有问题,可以在推特联系[rich_harris](https://twitter.com/rich_harris)、[rollupjs](https://twitter.com/rollupjs)、[thelarkinn](https://twitter.com/thelarkinn)。祝你打包快乐!
-Our thanks to Rich Harris for writing this article. We believe that collaboration in open source is incredibly vital to ensure we push technology and the web forward together.
+感谢 Rich Harris 写了这篇文章。我们坚信开源协作是共同促进 web 技术前进的重要动力。
-No time to help contribute? Want to give back in other ways? Become a Backer or Sponsor to webpack by [donating to our open collective](https://opencollective.com/webpack). Open Collective not only helps support the Core Team, but also supports contributors who have spent significant time improving our organization on their free time! ❤
+没有时间为开源项目做贡献?想要以其它方式回馈吗?欢迎通过 [Open Collective 进行捐赠](https://opencollective.com/webpack),成为 Webpack 的支持者或赞助商。Open Collective 不仅会资助核心团队,而且还会资助那些贡献出空闲时间帮助我们改进项目的贡献者们。
---
From 117db55d80428317dd5efa2f50cb612546f5a361 Mon Sep 17 00:00:00 2001
From: gy134340
Date: Sun, 9 Apr 2017 18:05:38 +0800
Subject: [PATCH 090/638] =?UTF-8?q?=E4=B8=BA=E4=BB=80=E4=B9=88=E7=94=A8=20?=
=?UTF-8?q?JavaScript=20=E5=AD=A6=E4=B9=A0=E5=87=BD=E6=95=B0=E5=BC=8F?=
=?UTF-8?q?=E7=BC=96=E7=A8=8B=EF=BC=9F=EF=BC=88=E7=BB=84=E6=88=90=E5=8C=96?=
=?UTF-8?q?=E8=BD=AF=E4=BB=B6=EF=BC=89=EF=BC=88=E7=AC=AC=E4=BA=8C=E9=83=A8?=
=?UTF-8?q?=E5=88=86=EF=BC=89?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
...amming-in-javascript-composing-software.md | 157 +++++++++---------
1 file changed, 78 insertions(+), 79 deletions(-)
diff --git a/TODO/why-learn-functional-programming-in-javascript-composing-software.md b/TODO/why-learn-functional-programming-in-javascript-composing-software.md
index dd82cf42a4a..3203cee2ce5 100644
--- a/TODO/why-learn-functional-programming-in-javascript-composing-software.md
+++ b/TODO/why-learn-functional-programming-in-javascript-composing-software.md
@@ -4,152 +4,151 @@
> * 译者:
> * 校对者:
-# Why Learn Functional Programming in JavaScript? (Composing Software)
+# 为什么用 JavaScript 学习函数式编程?(组成化软件)(第二部分)
-Smoke Art Cubes to Smoke — MattysFlicks — (CC BY 2.0)
-> Note: This is part of the “Composing Software” series on learning functional programming and compositional software techniques in JavaScript ES6+ from the ground up. Stay tuned. There’s a lot more of this to come!
-> [Start over at Part 1](https://medium.com/javascript-scene/the-rise-and-fall-and-rise-of-functional-programming-composable-software-c2d91b424c8c#.2dfd6n6qe) | [Next >](https://medium.com/javascript-scene/a-functional-programmers-introduction-to-javascript-composing-software-d670d14ede30#.2e4youss2)
+烟雾的方块艺术 —MattysFlicks —(CC BY 2.0)
+> 注意:这是从基础学习函数式编程和使用 JavaScript ES6+ 组成软件的第一部分。保持关注,接下来还有很多!
+> [从第一部分开始](https://medium.com/javascript-scene/the-rise-and-fall-and-rise-of-functional-programming-composable-software-c2d91b424c8c#.2dfd6n6qe) | [接下来的 >](https://medium.com/javascript-scene/a-functional-programmers-introduction-to-javascript-composing-software-d670d14ede30#.2e4youss2)
-Forget whatever you think you know about JavaScript, and approach this material with a beginner’s mind. To help you do that, we’re going to review the JavaScript basics from the ground up, as if you’ve never seen JavaScript before. If you’re a beginner, you’re in luck. Finally something exploring ES6 and functional programming from scratch! Hopefully all the new concepts are explained along the way — but don’t count on too much pampering.
+忘了你认为知道的关于 JavaScript 的一切,用初学者的眼光去看待它。为了帮助你做到这一点,我们将会从头复习一下 JavaScript 的基础,就像你与其尚未谋面一样。如果你是初学者,那你就很幸运了。最终从零开始探索 ES6 和函数式编程!希望所有的概念都被解释清楚 — 但不要太依赖于此。
-If you’re a seasoned developer already familiar with JavaScript, or a pure functional language, maybe you’re thinking that JavaScript is a funny choice for an exploration of functional programming. Set those thoughts aside, and try to approach the material with an open mind. You may find that there is another level to JavaScript programming. One you never knew existed.
+如果你是已经熟悉 JavaScript 或者纯函数式语言的老开发者了,也许你会认为 JavaScript 是探索函数式编程有趣的选择。把这些想法放在一边,用更开放的思想接触它,你会发现 JavaScript 编程更高层次的东西。一些你从来不知道的东西。
-Since this text is called “Composing Software”, and functional programming is the obvious way to compose software (using function composition, higher order functions, etc…), you may be wondering why I’m not talking about Haskell, ClojureScript, or Elm, instead of JavaScript.
+由于这个被称为“组成式软件”,同时函数式编程是明显的组成软件的方法(使用函数组合,高阶函数等等),你也许想知道为什么我不用 Haskell, ClojureScript,或者 Elm,而是 JavaScript。
-JavaScript has the most important features needed for functional programming:
+JavaScript 有函数式编程所需要的最重要的特性:
-1. **First class functions:** The ability to use functions as data values: pass functions as arguments, return functions, and assign functions to variables and object properties. This property allows for higher order functions, which enable partial application, currying, and composition.
-2. **Anonymous functions and concise lambda syntax:**`x => x * 2` is a valid function expression in JavaScript. Concise lambdas make it easier to work with higher-order functions.
-3. **Closures:** A closure is the bundling of a function with its lexical environment. Closures are created at function creation time. When a function is defined inside another function, it has access to the variable bindings in the outer function, even after the outer function exits. Closures are how partial applications get their fixed arguments. A fixed argument is an argument bound in the closure scope of a returned function. In `add2(1)(2)`, `1` is a fixed argument in the function returned by `add2(1)`.
+1. **一级函数:**使用函数作为数据值的能力:用函数传参,返回函数,用函数做变量和对象属性。这个属性允许更高级别的函数,使局部应用、柯里化和组合成为可能。
+2. **匿名函数和简介的 lambda 语法:**`x => x * 2` 是 JavaScript 中有效的函数表达式。简介的 lambda 语法使得它更好的跟高阶函数合作。
+3. **闭包:**闭包是一个有着自己独立作用域的捆绑函数。闭包在函数被创建时被创建。当一个函数在另一个函数内部被创建,它可以访问外部函数的变量,即使在外部函数退出后。闭包时使局部应用或者固定的参数。固定的参数时绑定在返回函数的作用域范围内的参数。在 `add2(1)(2)` 中,`1` 是 `add2(1)` 返回的函数中的固定参数。
-### What JavaScript is Missing
+### JavaScript 缺少了什么
-JavaScript is a multi-paradigm language, meaning that it supports programming in many different styles. Other styles supported by JavaScript include procedural (imperative) programming (like C), where functions represent a subroutine of instructions that can be called repeatedly for reuse and organization, object-oriented programming, where objects — not functions — are the primary building blocks, and of course, functional programming. The disadvantage of a multi-paradigm language is that imperative and object-oriented programming tend to imply that almost everything needs to be mutable.
+JavaScript 是多范式语言,意味着它支持多种风格的编程。其他被 JavaScript 支持的风格包括过程式的(命令式)编程(比如 C),把函数看作可以被重复调用和组织的子程序指令;面向对象编程,对象 — 而不是函数 — 作为初始构造块;当然,还有函数式编程。多范式编程语言的劣性在于命令式和面向对象往往意味着所有东西都是可变的。
-Mutation is a change to data structure that happens in-place. For example:
+可变性指的是数据结构上的变化。比如:
+
+ const foo = {
+ bar: 'baz'
+ };
- const foo = {
- bar: 'baz'
- };
+ foo.bar = 'qux'; // mutation
- foo.bar = 'qux'; // mutation
+对象通常需要可变性以便于被方法更新值,在命令式的语言中,大部分的数据结构可变以便于数组和对象的高效操作。
-Objects usually need to be mutable so that their properties can be updated by methods. In imperative programming, most data structures are mutable to enable efficient in-place manipulation of objects and arrays.
+下面是一些函数式语言拥有但是 JavaScript 没有的特性:
-Here are some features that some functional languages have, that JavaScript does not have:
+1. **纯粹性:**在一些函数式语言中,纯粹性是强制的,有副作用的表达式是不被允许的。
+2. **不可变性:**一些函数式语言不允许转变,采用表达式来产生新的数据结构来代替更改一个已存的数据结构,比如说数组或者对象。这样看起来可能不够搞笑,但是大多数函数式语言在引擎下使用 trie 数据结构,具有结构共享的特点:意味着旧的对象和新的对象是对相同数据的引用。
+3. **递归:**递归是函数引用自身来进行迭代的能力。在大多数函数式语言中,递归是迭代的唯一方式,它们没有像 `for` 、`while`、`do` 这类循环语句。
-1. **Purity:** In some FP languages, purity is enforced by the language. Expressions with side-effects are not allowed.
-2. **Immutability:** Some FP languages disable mutations. Instead of mutating an existing data structure, such as an array or object, expressions evaluate to new data structures. This may sound inefficient, but most functional languages use trie data structures under the hood, which feature structural sharing: meaning that the old object and new object share references to the data that is the same.
-3. **Recursion:** Recursion is the ability for a function to reference itself for the purpose of iteration. In many FP languages, recursion is the only way to iterate. There are no loop statements like `for`, `while`, or `do` loops.
+**纯粹性:**在 JavaScript 中,纯粹性由约定来达成,如果你不是使用纯函数来构成你的大多数应用,那么你就不是在进行函数式风格的编程。很不幸,在 JavaScript 中,你很容易就会不小心创建和使用一些不纯的函数。
-**Purity:** In JavaScript, purity must be achieved by convention. If you’re not building most of your application by composing pure functions, you’re not programming using the functional style. It’s unfortunately easy in JavaScript to get off track by accidentally creating and using impure functions.
+**不可变性:**在纯函数式语言中,可变性通常是强制的,JavaScript 缺少函数式语言中高效的、基于 trie 树的数据结构,但是又一些你可以使用的库,包括 [Immutable.js](https://facebook.github.io/immutable-js/) 和 [Mori](https://github.com/swannodette/mori),真是期望未来的 ECMAScript 规范版本可以拥抱不可变数据结构。
-**Immutability:** In pure functional languages, immutability is often enforced. JavaScript lacks efficient, immutable trie-based data structures used by most functional languages, but there are libraries that help, including [Immutable.js](https://facebook.github.io/immutable-js/) and [Mori](https://github.com/swannodette/mori). I’m hoping that future versions of the ECMAScript spec will embrace immutable data structures.
+有一些未来的迹象,比如说在 ES6 中添加了 `const` 关键字,`const` 声明的变量不能被重新赋值,知道 `const` 并不实际代表不可改变的值也很重要。
-There are signs that offer hope, like the addition of the `const` keyword in ES6. A name binding defined with `const` can't be reassigned to refer to a different value. It's important to understand that `const` does not represent an immutable *value.*
+`const` 声明的对象不能被重新声明为新的对象,但是对象的属性却是可变的,JavaScript 有 `freeze()` 对象的能力,但是这些对象只能在根实例上被冻结,意味着嵌套着的对象还是可以改变它的属性。换句话说,在 JavaScript 规范中看到真正的不可变还有很多路要走。
-A `const` object can't be reassigned to refer to a completely different object, but the object it refers to *can have its properties mutated*. JavaScript also has the ability to `freeze()` objects, but those objects are only frozen at the root level, meaning that a nested object can still have properties of its properties mutated. In other words, there's still a long road ahead before we see true composite immutables in the JavaScript specification.
+**递归:**JavaScript 支持递归,但是大多数函数式语言都有尾部调用优化的特性,尾部调用优化是一个允许递归的函数重用堆栈帧来递归调用的特性。
-**Recursion:** JavaScript technically supports recursion, but most functional languages have a feature called tail call optimization. Tail call optimization is a feature which allows recursive functions to reuse stack frames for recursive calls.
+没有尾部调用优化,一个调用的栈很可能没有边界导致堆栈溢出。JavaScript 在 ES6 规范中有一个有限的尾部调用优化。不幸的是,只有一个主要的浏览器引擎支持它,这个优化被部分应用随后从 Babel(最流行的 JavaScript 编译器,在旧的浏览器中被用来把 ES6 编译到 ES5)。
-Without tail call optimization, a call stack can grow without bounds and cause a stack overflow. JavaScript technically got a limited form of tail call optimization in the ES6 specification. Unfortunately, only one of the major browser engines implemented it, and the optimization was partially implemented and then subsequently removed from Babel (the most popular standard JavaScript compiler, used to compile ES6 to ES5 for use in older browsers).
+最后一行:现在使用递归来作为大的迭代还不是很安全 — 即使你很小心的调用尾部的函数。
-Bottom line: It still isn’t safe to use recursion for large iterations — even if you’re careful to call the function in the tail position.
+### 什么又是 JavaScript 所有但是纯函数式语言没有的
-### What JavaScript Has that Pure Functional Languages Lack
+一个纯粹主义者会告诉你 JavaScript 的可变性是它的重要缺点,这是事实。但是,引起的副作用和改变有时候很有用。事实上,不可能在规避所有副作用的情况下开发有用的现代应用。纯函数式语言比如说 Haskell 使用副作用,但是使用 monads 包来伪装纯函数,从而使程序保持纯净,尽管用 monads 所带来的副作用是不纯净的。
-A purist will tell you that JavaScript’s mutability is its major disadvantage, which is true. However, side effects and mutation are sometimes beneficial. In fact, it’s impossible to create most useful modern applications without side effects. Pure functional languages like Haskell use side-effects, but camouflage them from pure functions using boxes called monads, allowing the program to remain pure even though the side effects represented by the monads are impure.
+monads 的问题是,尽管它的使用很简单,但是对一个不是很熟悉它的人解释清楚它有点像对牛谈琴。
-The trouble with monads is that, even though their use is quite simple, explaining what a monad is to somebody unfamiliar with lots of examples is a bit like explaining what the color “blue” looks like to a blind person.
+> “monad 是 endofunctor 范畴的幺半群,有什么问题?” ~James Iry 所引用 Philip Wadler的话,解释一个 Saunders Mac Lane 说过的名言。[*“A Brief, Incomplete, and Mostly Wrong History of Programming Languages”*](http://james-iry.blogspot.com/2009/05/brief-incomplete-and-mostly-wrong.html)
-> “A monad is a monoid in the category of endofunctors, what’s the problem?” ~ James Iry, fictionally quoting Philip Wadler, paraphrasing a real quote by Saunders Mac Lane.[*“A Brief, Incomplete, and Mostly Wrong History of Programming Languages”*](http://james-iry.blogspot.com/2009/05/brief-incomplete-and-mostly-wrong.html)
+典型的,这是在调侃这有趣的一点。在上面的引用中,关于 monads 的解释相比最初的有了很大的简化,原来是下面这样:
-Typically, parody exaggerates things to make a funny point funnier. In the quote above, the explanation of monads is actually *simplified* from the original quote, which goes like this:
+> “`X` 中的 monad 是其 endofunctor 范畴的幺半群,生成 endofunctor 和被 endofunctor 单位 set 组合所代替的 `X` ” ~ Saunders Mac Lane。 [*"Categories for the Working Mathematician"*](https://www.amazon.com/Categories-Working-Mathematician-Graduate-Mathematics/dp/0387984038//ref=as_li_ss_tl?ie=UTF8&linkCode=ll1&tag=eejs-20&linkId=de6f23899da4b5892f562413173be4f0)
-> “A monad in `X` is just a monoid in the category of endofunctors of `X`, with product `×` replaced by composition of endofunctors and unit set by the identity endofunctor." ~ Saunders Mac Lane. [*"Categories for the Working Mathematician"*](https://www.amazon.com/Categories-Working-Mathematician-Graduate-Mathematics/dp/0387984038//ref=as_li_ss_tl?ie=UTF8&linkCode=ll1&tag=eejs-20&linkId=de6f23899da4b5892f562413173be4f0)
+尽管这样,在我的观点看来,害怕 monads 是没有必要的,学习 monads 最好的方法不是去读关于它的一堆书和博客,而是立刻去使用它。对于大部分的函数式编程语言来说,晦涩的学术词汇比它实际概念难的多,相信我,你不必通过了解 Saunders Mac Lane 来了解函数式编程。
-Even so, in my opinion, fear of monads is weak reasoning. The best way to learn monads is not to read a bunch of books and blog posts on the subject, but to jump in and start using them. As with most things in functional programming, the impenetrable academic vocabulary is much harder to understand than the concepts. Trust me, you don’t have to understand Saunders Mac Lane to understand functional programming.
+尽管它不是对所有的编程风格都完全的理想,JavaScript 无疑是作为适应各种编程风格和背景的人的通用编程语言被设计出来的。
-While it may not be absolutely ideal for every programmming style, JavaScript is unapologetically a general-purpose language designed to be usable by various people with various programming styles and backgrounds.
+根据 [Brendan Eric](https://brendaneich.com/2008/04/popularity/) 所言,在一开始的时候,网景公司就有意适应两类开发者:
-[According to Brendan Eich](https://brendaneich.com/2008/04/popularity/), this was intentional from the beginning. Netscape had to support two kinds of programmers:
+> “...写组件的,比如说 C++ 或者 Java;写脚本的、业余的和爱好者,比如直接写嵌在 HTML 里的代码的。”
-> *“…the component authors, who wrote in C++ or (we hoped) Java; and the ‘scripters’, amateur or pro, who would write code directly embedded in HTML.”*
+最初,网景公司的意向是支持两种不同的语言,同时脚本语言大致要像 Scheme (一个 Lisp 的方言),而且,Brendan Eich:
-Originally, the intent was that Netscape would support two different languages, and the scripting language would probably resemble Scheme (a dialect of Lisp). Again, Brendan Eich:
+> “我被招聘到网景公司,目的是在浏览器中 **做一些 Scheme**”。
-> *“I was recruited to Netscape with the promise of ‘doing Scheme’ in the browser.”*
+JavaScript 应当是一门新的语言:
-JavaScript had to be a new language:
+> “上面工程管理的命令是这门语言**应当像 Java**,这就排除了 Perl,Python,和 Tcl,以及 Scheme。”
-> *“The *diktat* from upper engineering management was that the language must ‘look like Java’. That ruled out Perl, Python, and Tcl, along with Scheme.”*
+所以,Brendan Eich 最初脑子里的想法是:
-So, the ideas in Brendan Eich’s head from the beginning were:
+1. 浏览器中的 Scheme。
+2. 看起来像 Java。
-1. Scheme in the browser.
-2. Look like Java.
+最终的结果稍微有点复杂:
-It ended up being even more of a mish-mash:
+>“我不骄傲,但我很高兴我选择了 Scheme 的一类函数和 Self(尽管奇怪)的原型作为主要的元素。”由于 Java 的影响,特别是 y2k 的 Date 问题以及对象的区别(比如string 和 String),就不幸了。”
-> *“I’m not proud, but I’m happy that I chose Scheme-ish first-class functions and Self-ish (albeit singular) prototypes as the main ingredients. The Java influences, especially y2k Date bugs but also the primitive vs. object distinction (e.g., string vs. String), were unfortunate.”*
+我列出了这些 “不好的” 的类 Java 特性,最后转换成 JavaScript:
-I’d add to the list of “unfortunate” Java-like features that eventually made their way into JavaScript:
+* 构造函数和 `new` 关键子,跟工厂函数有着不同的调用和使用语义。
+* `class` 的关键字和单一父类 `extends` 作为最初的继承机制。
+* 用户更习惯于把 `class` 看作是它的静态类型(实际并非如此)。
-- Constructor functions and the `new` keyword, with different calling and usage semantics from factory functions.
-- A `class` keyword with single-ancestor `extends` as the primary inheritance mechanism.
-- The user’s tendency to think of a `class` as if it's a static type (it's not).
+我的意见:永远避免使用这些东西。
-My advice: Avoid those whenever you can.
+很幸运 JavaScript 成为了这样厉害的语言,因为事实上证明脚本的方式赢了那些建立在“组件”上的方式(现在,Java、Flash、和 ActiveX 扩展已经不被大部分安装的浏览器支持)。
-We’re lucky that JavaScript ended up being such a capable language, because it turns out that the scripting approach won over the “component” approach (today, Java, Flash, and ActiveX extensions are unsupported in huge numbers of installed browsers).
+我们最终创作了一个直接被浏览器支持的语言:JavaScript。
-What we eventually ended up with was one language directly supported by the browser: JavaScript.
+那意味着浏览器可以减少臃肿和问题,因为它们现在只需要支持一种语言:JavaScript。你也许认为 WebAssembly 是异常,但是 WebAssembly 设计之初的目的是使用兼容的抽象语法树来共享JavaScript的语言绑定(AST)。事实上,最早的把 WebAssembly 编译成 JavaScript 的子集的示范是 ASM.js。
-That means that browsers are less bloated and less buggy, because they only need to support a single set of language bindings: JavaScript’s. You might be thinking that WebAssembly is an exception, but one of the design goals of WebAssembly is to share JavaScript’s language bindings using a compatible Abstract Syntax Tree (AST). In fact, the first demonstrations compiled WebAssembly to a subset of JavaScript known as ASM.js.
+作为 web 平台唯一的通用标准编程语言,JavaScript 在软件历史潮流中乘风直上:
-The position as the only standard general purpose programming language for the web platform allowed JavaScript to ride the biggest language popularity wave in the history of software:
+App 吞食世界, web 吞食 app, 同时 JavaScript 吞食 web。
-Apps ate the world, the web ate apps, and JavaScript ate the web.
+根据[各方](http://redmonk.com/sogrady/2016/07/20/language-rankings-6-16/)[调查](http://stackoverflow.com/research/developer-survey-2016),[JavaScript](https://octoverse.github.com/)是目前世界上最流行的语言。
-By [multiple](http://redmonk.com/sogrady/2016/07/20/language-rankings-6-16/)[measures](http://stackoverflow.com/research/developer-survey-2016), [JavaScript](https://octoverse.github.com/) is now the most popular programming language in the world.
+JavaScript 并不是函数式编程的理想化工具,但是它却是为大型的分布式的团队开发大型应用的好工具,因为不同的团队也许有不同建立应用的想法。
-JavaScript is not the ideal tool for functional programming, but it’s a great tool for building large applications on very large, distributed teams, where different teams may have different ideas about how to build an application.
+一些团队致力于脚本化,那么命令式的编程就特别有用,另外一些更精于抽象架构,那么一点保留的面向对象方法也许不失为坏。还有一些拥抱函数式编程,使用纯函数来确保稳定性、可测试性和项目状态管理以便减少用户的反馈。团队里的这些人可以使用相同的语言,意味着他们可以更好的交换想法,互相学习和在其他人的基础上更进一步的开发。
-Some teams may concentrate on scripting glue, where imperative programming is particularly useful. Others may concentrate on building architectural abstractions, where a bit of (restrained, careful) OO thinking may not be a bad idea. Still others may embrace functional programming, reducing over user actions using pure functions for deterministic, testable management of application state. Members on these teams are all using the same language, meaning that they can more easily exchange ideas, learn from each other, and build on each other’s work.
+在 JavaScript 中,所有这些想法可以共存,这样就让更多的人开始拥抱 JavaScript,然后就产生了[世界上最大的开源包管理器](http://www.modulecounts.com/) (2017 年 2 月),[npm](https://www.npmjs.com/)。
-In JavaScript, all of these ideas can co-exist, which allows more people to embrace JavaScript, which has led to the [largest open-source package registry in the world](http://www.modulecounts.com/) (as of February, 2017), [npm](https://www.npmjs.com/).
+JavaScript 的真正优势在于其生态系统中的思想和用户的多样性。它也许不是纯函数式编程的理想语言,但它是你可以想象的工作在不同平台的人共同合作的理想语言,比如说 Java、Lisp 或者 C。JavaScript 也许对这些有这些背景的用户完全友好,但是这些人很乐意学习这门语言并迅速投入生产。
-The true strength of JavaScript is diversity of thought and users in the ecosystem. It may not be absolutely the ideal language for functional programming purists, but it may be the ideal language for working together using one language that works on just about every platform you can imagine — familiar to people coming from other popular languages such as Java, Lisp, or C. JavaScript won’t feel ideally comfortable to users with any of those backgrounds, but they may feel *comfortable enough* to learn the language and become productive quickly.
+我同意 JavaScript 并不是函数式编程着最好的语言。但是,没有任何其他语言可以声称他们可以被所有人使用,同时正如 ES6 所述:JavaScript 可以满足到更与喜欢函数式编程的人的需要,同时也越来越好。相比于抛弃 JavaScript 和它不可思议的被世界上所有公司使用的生态系统,为什么不拥抱它,把它变成一个更适合软件组成化的语言?
-I agree that JavaScript is not the best language for functional programmers. However, no other functional language can claim that it is a language that everybody can use and embrace, and as demonstrated by ES6: JavaScript can and does get better at serving the needs of users interested in functional programming. Instead of abandoning JavaScript and its incredible ecosystem used by virtually every company in the world, why not embrace it, and make it a better language for software composition incrementally?
+现在,JavaScript 已经是一门足够优秀的函数式编程语言,意味着人们可以使用 JavaScript 的函数式编程方法来构造所有有趣的和有用的东西。Netflix(和其他使用 Angular 2+ 的应用)使用基于 RxJS 的函数式功能。[Facebook](https://github.com/facebook/react/wiki/sites-using-react)在 React 中使用纯函数、高阶函数和高级组件来开发 Facebook 和 Instagram,[PayPal, KhanAcademy, and Flipkart](https://github.com/reactjs/redux/issues/310)使用 Redux 来进行状态管理。
-As-is, JavaScript is already a *good enough* functional programming language, meaning that people are building all kinds of useful and interesting things in JavaScript, using functional programming techniques. Netflix (and every app built with Angular 2+) uses functional utilities based on RxJS. [Facebook](https://github.com/facebook/react/wiki/sites-using-react) uses the concepts of pure functions, higher-order functions, and higher order components in React to build Facebook and Instagram. [PayPal, KhanAcademy, and Flipkart](https://github.com/reactjs/redux/issues/310) use Redux for state management.
+它们并不孤单:Angular、React、Redux 和 Lodash 是 JavaScript 生态系统中主要的框架和库,同时它们都被函数式编程很深的影响到 — 或者在 Lodash 和 Redux中,明确的表达是为了在实际的 JavaScript 应用中使用函数式编程模式。
-They’re not alone: Angular, React, Redux, and Lodash are the leading frameworks and libraries in the JavaScript application ecosystem, and all of them are heavily influenced by functional programming — or in the cases of Lodash and Redux, built for the express purpose of enabling functional programming patterns in real JavaScript applications.
+“为什么是 JavaScript?”因为实际上所有的软件呢公司用来开发软件的语言。无论如何,JavaScript 从 Lisp 这个数十年来的标志头上偷取了 “最受欢迎的函数式编程语言” 的头衔。事实上,Haskell 更适合当今函数式编程概念的标准,但是人们并不使用它来开发实际应用。
-“Why JavaScript?” Because JavaScript is the language that most real companies are using to build real software. Love it or hate it, JavaScript has stolen the title of “most popular functional programming language” from Lisp, which was the standard bearer for decades. True, Haskell is a much more suitable standard bearer for functional programming concepts today, but people just aren’t building as many real applications in Haskell.
+在任何时候,在美国都有一百万的 JavaScript 工作需求,世界其他地方也有数百万的量。学习 Haskell 可以帮助你很好的学习函数式编程,但学习 JavaScript 将会教会你在实际工作中开发应用。
-At any given moment, there are close to a hundred thousand JavaScript job openings in the United States, and hundreds of thousands more world-wide. Learning Haskell will teach you a lot about functional programming, but learning JavaScript will teach you a lot about building production apps for real jobs.
+App 正在吞食世界, web 正在吞食 app, 同时 JavaScript 正在吞食 web。
-Apps ate the world, the web ate apps, and JavaScript ate the web.
+[**接下来的第三部分: 函数式开发者的 JavScript 介绍…**](https://medium.com/javascript-scene/a-functional-programmers-introduction-to-javascript-composing-software-d670d14ede30#.zdpw16p65)
-[**Continued in Part 3: A Functional Programmer’s Introduction to JavaScript…**](https://medium.com/javascript-scene/a-functional-programmers-introduction-to-javascript-composing-software-d670d14ede30#.zdpw16p65)
+### 下一步
-### Next Steps
+想更多的学习 JavaScript 的函数式编程?
-Want to learn more about functional programming in JavaScript?
+[Learn JavaScript with Eric Elliott](http://ericelliottjs.com/product/lifetime-access-pass/),什么,你还不是其中之一,out 了!
-[Learn JavaScript with Eric Elliott](http://ericelliottjs.com/product/lifetime-access-pass/). If you’re not a member, you’re missing out!
+[![](https://cdn-images-1.medium.com/freeze/max/30/1*3njisYUeHOdyLCGZ8czt_w.jpeg?q=20)![](https://cdn-images-1.medium.com/max/800/1*3njisYUeHOdyLCGZ8czt_w.jpeg)](https://ericelliottjs.com/product/lifetime-access-pass/)
-[
-](https://ericelliottjs.com/product/lifetime-access-pass/)
+*Eric Elliott* 是 [*“Programming JavaScript Applications”*](http://pjabook.com) (O’Reilly) 和 “Learn JavaScript with Eric Elliott” 的作者。他曾效力于 *Adobe Systems, Zumba Fitness, he Wall Street Journal, ESPN, BBC, and top recording artists including Usher, Frank Ocean, Metallica* 和其他一些公司。
-***Eric Elliott*** is the author of [*“Programming JavaScript Applications”*](http://pjabook.com) (O’Reilly), and [*“Learn JavaScript with Eric Elliott”*](http://ericelliottjs.com/product/lifetime-access-pass/). He has contributed to software experiences for **Adobe Systems, Zumba Fitness, The Wall Street Journal, ESPN, BBC, and top recording artists including Usher, Frank Ocean**, Metallica, and many more.
-
-*He spends most of his time in the San Francisco Bay Area with the most beautiful woman in the world.*
+*他和她的老婆(很漂亮)大部分时间都在旧金山湾区里。*
---
From b029545ce7db113488a20a0722eb40027cff9f44 Mon Sep 17 00:00:00 2001
From: sunxinlei
Date: Sun, 9 Apr 2017 18:41:57 +0800
Subject: [PATCH 091/638] =?UTF-8?q?=E6=A0=B9=E6=8D=AE=20sqrthree=20?=
=?UTF-8?q?=E6=A0=A1=E5=AF=B9=E6=84=8F=E8=A7=81=E6=9B=B4=E6=94=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
TODO/modern-javascript-for-ancient-web-developers.md | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/TODO/modern-javascript-for-ancient-web-developers.md b/TODO/modern-javascript-for-ancient-web-developers.md
index d62d526e6a9..f4cbf50cb77 100644
--- a/TODO/modern-javascript-for-ancient-web-developers.md
+++ b/TODO/modern-javascript-for-ancient-web-developers.md
@@ -26,13 +26,13 @@ Hi.我是一个正在学习现代 JavaScript 的“老派” web 开发者。我
这种情况下,就有必要向你身边的 JavaScript 工程师朋友伸手求助了,和他们聊一聊你的技术路线。我很荣幸在 Postlight 得到了工程师朋友(特别是 [Jeremy Mack](https://medium.com/@mutewinter))的精湛指导,感谢他们容忍我无穷无尽的问题。
-我要说的是,学习现代的 JavaScript 需要人为干预。事物还在不断发展变化,各种教程尚未成熟和定型,所谓最佳实践也未形成正式规范。如果你身边没有大牛,那么至少也得检查 Medium 上文章或教程的日期,或 Github 仓库的最近一次提交时间。如果时间超过了一年,基本上可以确定已经过时。
+我要说的是,学习现代的 JavaScript 需要人为干预。事物还在不断发展变化,各种教程尚未成熟和定型,所谓最佳实践也未形成正式规范。如果你身边没有大牛,那么至少也得检查 Medium 上文章或教程的日期,或 GitHub 仓库的最近一次提交时间。如果时间超过了一年,基本上可以确定已经过时。
### 新的问题,而不是已经确定的解决方案 ###
走类似这样的路线:当你在学习现代 JavaScript 时,你遇到的问题的解决方案还在渐渐得到解决,这正是一个好机会。事实上,很可能仅仅差一次 code review,你在使用这个包时就可以修复问题。
-当你在使用一种像 PHP 这样的古老的语言的时候,你可以 Google 一个提问或者问题,几乎百分之百能找到一个5年前的 Stack Overflow 回答来解决它,或者你能在(详尽的,大量评论的,无与伦比的)[文档](http://docs.php.net/docs.php)里找到整个描述。
+当你在使用一种像 PHP 这样的古老的语言的时候,你可以 Google 一个提问或者问题,几乎百分之百能找到一个 5 年前的 Stack Overflow 回答来解决它,或者你能在(详尽的、大量评论的、无与伦比的)[文档](http://docs.php.net/docs.php)里找到整个描述。
现代 JavaScript 就并非如此了。 我曾经徜徉在 GitHub issues 和源码的时候不止一次找到的都是一些过时的文档。剖析 GitHub 版本库是学习和使用各种包的一部分,而且对于我这样的“老派人”,差之毫厘的学习总是令人迷惑。
@@ -42,7 +42,7 @@ Hi.我是一个正在学习现代 JavaScript 的“老派” web 开发者。我
[![Markdown](http://i4.buimg.com/1949/adafb30475d3d36a.png)](https://twitter.com/capndesign/status/832638513048850433/photo/1)
-**不要因此止步不前**。我不得不放手去做,从起步到正确配置,允许自己的不完美甚至一些业余,只为舒适地使用自己的工具。(我不会告诉你我曾用[nodemon](https://nodemon.io/)做代码检查)随后我会找到更好的方法并且在每个新项目中纳入进来。
+**不要因此止步不前**。我不得不放手去做,从起步到正确配置,允许自己的不完美甚至一些业余,只为舒适地使用自己的工具。(我不会告诉你我曾用 [nodemon](https://nodemon.io/) 做代码检查)随后我会找到更好的方法并且在每个新项目中纳入进来。
这方面 JS 还有大量的工作要做。现代 JavaScript 领域依然是不断变化的,但我一个现代 JS 工程师亲友告诉我,[这份来自 Jonathan Verrecchia 的教程](https://github.com/verekia/js-stack-from-scratch)是目前构建一个当代 JavaScript 栈的不二之选。对,就是现在。
@@ -54,17 +54,17 @@ Hi.我是一个正在学习现代 JavaScript 的“老派” web 开发者。我
这是迄今为止我在这个过程中经历过的一些研讨会和教程的不完整列表。
-- [HOW-TO-NPM](https://github.com/workshopper/how-to-npm) —— npm 是 JavaScript 的包管理器。即使在学习这个教程之前我已经敲打过上千次 “npm install”,但是知道学完这个我才知道 npm 做的所有事情。(在很多项目中我已经转移使用[yarn](https://github.com/yarnpkg/yarn),而不是 npm,但所有的概念都是相通的)
+- [HOW-TO-NPM](https://github.com/workshopper/how-to-npm) —— npm 是 JavaScript 的包管理器。即使在学习这个教程之前我已经敲打过上千次 “npm install”,但是知道学完这个我才知道 npm 做的所有事情。(在很多项目中我已经转移使用[yarn](https://github.com/yarnpkg/yarn),而不是 npm,但所有的概念都是相通的)
`npm i -g how-to-npm`
-- [learnyounode](https://github.com/workshopper/learnyounode)——我打算专注于服务端 JavaScript,因为那有令我安逸的东西,那就是 Node.js。Learnyounode 是一个交互式教程,结构上类似 how-to-npm。
+- [learnyounode](https://github.com/workshopper/learnyounode)——我打算专注于服务端 JavaScript,因为那有令我安逸的东西,那就是 Node.js。Learnyounode 是一个交互式教程,结构上类似 how-to-npm。
- [expressworks](https://github.com/azat-co/expressworks) —— 和前面两个项目类似,Expressworks 是 Express.js 的介绍,一个 Node.js 的 web 框架。在 Postlight 公司 Express 没有得到广泛使用,但对于初学者,它值得学习去上手构建一个简单的 web 应用。
- 现在是时候做点真东西了。我发现 Tomomi Imura 的一篇教程 [Creating a Slack Command Bot from Scratch with Node.js](http://www.girliemac.com/blog/2016/10/24/slack-command-bot-nodejs/) 已经可以学到足够的 Node 和 Express 的新技能来应对工作。因为我专注于后端,使用 Slack 创建一个 “/” 命令是一个很好的开始,因为没有前端演示(Slack 帮你做好了)
-- 在构建这个命令的过程中,我不使用演练中所推荐的 ngrok 或者 Heroku,而是使用 [Zeit Now](https://zeit.co/now),这是任何人可用的,创建快速一次性的 JS 应用的宝贵工具。
+- 在构建这个命令的过程中,我不使用演练中所推荐的 ngrok 或者 Heroku,而是使用 [Zeit Now](https://zeit.co/now),这是任何人可用的、创建快速一次性的 JS 应用的宝贵工具。
- 一旦开始写真正意义的代码,我也开始掉下工具无底洞了,安装 Sublime 插件,获取正确的 [Node 版本](https://github.com/postlight/lux/blob/master/CONTRIBUTING.md#nodejs-version-requirements),配置 ESLint,使用 [Airbnb 的代码规范 (Postlight 公司的偏好)](https://github.com/airbnb/javascript) —— 这些事情拖了我的后退,但也都是有价值的初始化投资。对于这方面我还在坑里,例如 Webpack 对我来说依然美妙又神秘,不过[这个视频是个很不错的介绍](https://www.youtube.com/watch?v=WQue1AN93YU)*.*
- 某些时候 JS 的异步执行(特别是[回调地狱](http://callbackhell.com/))开始困扰我,[Promise It Won’t Hurt](https://github.com/stevekane/promise-it-wont-hurt) 是另一个教你怎样使用 Promise 书写优雅异步逻辑的教程。Promise 是用于解决异步执行的 JS 新概念。说实话 Promise 令我耳目一新,他们是巧妙的范式转变。感谢 [Mariko Kosaka](http://kosamari.com/notes/the-promise-of-a-burger-party),现在我每次买汉堡的时候都能想起这些。
From be832cc766613663cdf57b56822961647907101b Mon Sep 17 00:00:00 2001
From: sunxinlei
Date: Sun, 9 Apr 2017 18:47:15 +0800
Subject: [PATCH 092/638] =?UTF-8?q?=E4=B8=A4=E5=A4=84=E8=8B=B1=E6=96=87?=
=?UTF-8?q?=E7=A9=BA=E6=A0=BC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
TODO/modern-javascript-for-ancient-web-developers.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/TODO/modern-javascript-for-ancient-web-developers.md b/TODO/modern-javascript-for-ancient-web-developers.md
index f4cbf50cb77..844e8f62cdf 100644
--- a/TODO/modern-javascript-for-ancient-web-developers.md
+++ b/TODO/modern-javascript-for-ancient-web-developers.md
@@ -22,7 +22,7 @@ Hi.我是一个正在学习现代 JavaScript 的“老派” web 开发者。我
### 转移目标 (.jS)
-现代 JS 的特点就是朝气蓬勃和发展迅速,所以很容易就选择了过时的框架、模板引擎、构建工具、 教程或者已经不是最佳实践的技术。( 如果真有一个被广泛接受的最佳实践的概念的话)
+现代 JS 的特点就是朝气蓬勃和发展迅速,所以很容易就选择了过时的框架、模板引擎、构建工具、 教程或者已经不是最佳实践的技术。(如果真有一个被广泛接受的最佳实践的概念的话)
这种情况下,就有必要向你身边的 JavaScript 工程师朋友伸手求助了,和他们聊一聊你的技术路线。我很荣幸在 Postlight 得到了工程师朋友(特别是 [Jeremy Mack](https://medium.com/@mutewinter))的精湛指导,感谢他们容忍我无穷无尽的问题。
@@ -54,7 +54,7 @@ Hi.我是一个正在学习现代 JavaScript 的“老派” web 开发者。我
这是迄今为止我在这个过程中经历过的一些研讨会和教程的不完整列表。
-- [HOW-TO-NPM](https://github.com/workshopper/how-to-npm) —— npm 是 JavaScript 的包管理器。即使在学习这个教程之前我已经敲打过上千次 “npm install”,但是知道学完这个我才知道 npm 做的所有事情。(在很多项目中我已经转移使用[yarn](https://github.com/yarnpkg/yarn),而不是 npm,但所有的概念都是相通的)
+- [HOW-TO-NPM](https://github.com/workshopper/how-to-npm) —— npm 是 JavaScript 的包管理器。即使在学习这个教程之前我已经敲打过上千次 “npm install”,但是知道学完这个我才知道 npm 做的所有事情。(在很多项目中我已经转移使用 [yarn](https://github.com/yarnpkg/yarn),而不是 npm,但所有的概念都是相通的)
From 3fc96b46eccefccbe0c2f147247c63484c942f48 Mon Sep 17 00:00:00 2001
From: lsvih
Date: Sun, 9 Apr 2017 20:51:55 +0800
Subject: [PATCH 093/638] =?UTF-8?q?=E4=BA=8C=E6=A0=A1=E6=84=8F=E8=A7=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
TODO/modules-vs-microservices.md | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/TODO/modules-vs-microservices.md b/TODO/modules-vs-microservices.md
index 743f181583e..fcac5d43e3b 100644
--- a/TODO/modules-vs-microservices.md
+++ b/TODO/modules-vs-microservices.md
@@ -6,11 +6,11 @@
# 模块化 vs. 微服务
-在避免微服务复杂性的同时,应用模块化系统设计设计原则。
+使用模块化系统设计原则来避免微服务的复杂性。
![](https://d3tdunqjn7n0wj.cloudfront.net/360x240/container-227877_1920-0db52b796e6b80d98f6df2d01a6ee4fb.jpg)
-从单体式应用向微服务架构迁移已经是老生常谈的话题了。除了过过嘴瘾,似乎真的动手将单体式应用拆分成微服务也不是什么很困难的事。但是这种做法真的是你们团队的最佳选择吗?维护一个凌乱的单体式应用的确很伤脑筋,但是还有另一种强有力但常常被人忽视的替代方案:模块化应用开发。本文将探讨这种替代方案,并展现其与构建微服务的关系。
+从单体式应用向微服务架构迁移已经是老生常谈的话题了。除了过过嘴瘾,似乎真的动手将单体式应用拆分成微服务也不是什么很困难的事。但是这种做法真的是你们团队的最佳选择吗?维护一个凌乱的单体式应用的确很伤脑筋,但是还有另一种优秀但常常被人忽视的替代方案:模块化应用开发。本文将探讨这种替代方案,并展现其与构建微服务的关系。
## 模块化微服务
@@ -40,9 +40,9 @@
例如在 Java 中,有几个可以帮助你构建应用的模块系统。OSGi 是其中最著名的一个,不过随着 Java 9 的发布,Java 平台将加入一个原生的模块系统。现在模块作为一等结构(first-class construct),成为了语言和平台的一部分。Java 模块可以表明对其它模块的依赖,以及在强封装实现类的时候公开暴露接口。甚至 Java 平台本身(一个庞大的代码库)已经使用了新的 Java 模块系统进行模块化。你可以在我即将出版的书[Java 9 Modularity](https://www.safaribooksonline.com/library/view/java-9-modularity/9781491954157/?utm_source=newsite&utm_medium=content&utm_campaign=lgen&utm_content=modules-vs-microservices-inline)中了解有关 Java 9 模块化开发的更多信息。(现早期版本已经发布)
-其它的语言也提供了类似的机制。例如,JavaScript 在 ES2015 规范中提供了一个[模块系统](http://exploringjs.com/es6/ch_modules.html)。在此之前,Node.js 也为 JavaScript 后端提供了一个非标准的模块系统。然而 JavaScript 作为一种动态语言,对于强制接口(类型)与模块封装的支持还是较弱。你可以考虑在 JavaScript 的基础上使用 TypeScript 来重新获得这些优点。微软的 .Net 框架与 Java 一样都有着强类型,但就强封装以及程序集(Assemblies)间的显式依赖而言,它与 Java 即将推出的模块系统并不相同。尽管如此,你可以通过使用 [.Net Core](https://msdn.microsoft.com/en-us/magazine/mt707534.aspx) 中标准化的反转控制模式(IOC)以及创建逻辑相关的程序集来实现良好的模块化架构。即使是 C++ 也在以后的版本中[考虑添加](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4610.pdf)模块系统。许多语言现在都对模块化表现出了欣赏之情,这本身就是一个显著的进步。
+其它的语言也提供了类似的机制。例如,JavaScript 在 ES2015 规范中提供了一个[模块系统](http://exploringjs.com/es6/ch_modules.html)。在此之前,Node.js 也为 JavaScript 后端提供了一个非标准的模块系统。然而 JavaScript 作为一种动态语言,对于强制接口(类型)与模块封装的支持还是较弱。你可以考虑在 JavaScript 的基础上使用 TypeScript 来重新获得这些优点。微软的 .Net 框架与 Java 一样都有着强类型,但就强封装以及程序集(Assemblies)间的显式依赖而言,它与 Java 即将推出的模块系统并不相同。尽管如此,你可以通过使用 [.Net Core](https://msdn.microsoft.com/en-us/magazine/mt707534.aspx) 中标准化的反转控制模式(IOC)以及创建逻辑相关的程序集来实现良好的模块化架构。即使是 C++ 也在以后的版本中[考虑添加](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4610.pdf)模块系统。许多语言都在向模块化靠近,这本身就是一个显著的进步。
-当你有意识地使用你的开发平台的模块化特性时,你就可以实现之前提及的微服务的模块化优势。基本上模块系统越好,你在开发过程中获得的帮助就越多。只要在不同团队间的接触点定义好明确的接口,不同的团队也可以独立进行不同部分的工作。当然,在部署时还是要将模块在一个单独的部署单元中组合起来。这样可以防止过大的复杂度,以及迁移到微服务所需要的开发与管理成本。诚然,这也意味着你不能使用不同的技术栈来构建不同的模块,但你的团队应该不会真的这么做吧?
+当你有意识地使用你的开发平台的模块化特性时,你就可以实现之前提及的微服务的模块化优势。基本上模块系统越好,你在开发过程中获得的帮助就越多。只要在不同团队间的接触点定义好明确的接口,不同的团队也可以独立进行不同部分的工作。当然,在部署时还是要将模块在一个单独的部署单元中组合起来。这样可以防止过于复杂,以及减少迁移到微服务所需要的开发与管理成本。诚然,这也意味着你不能使用不同的技术栈来构建不同的模块,但你的团队应该不会真的这么做吧?
## 模块设计
@@ -68,7 +68,7 @@
## 总结
-总之,最好的方案就是找到一个折中的点。这两种方案都有可取之处,需要根据实际环境、组织和应用本身进行选择。既然你可以在之后迁移成微服务架构,那为什么最开始不直接使用模块化应用呢?如果你之前就已经划分好了模块边界,那也就不需要再去拆分你的单体式应用了。甚至你还可以在模块内部搭建微服务架构。那么问题就变成了:为什么微服务一定要是”微“的呢?
+总之,最好的方案就是找到一个折中的点。这两种方案都有可取之处,需要根据实际环境、组织和应用本身进行选择。既然你可以在之后迁移成微服务架构,那为什么最开始不直接使用模块化应用呢?如果你之前就已经划分好了模块边界,那也就不需要再去拆分你的单体式应用了。甚至你还可以在模块内部搭建微服务架构。那么问题就变成了:为什么微服务一定要是“微”的呢?
即使你的应用刚从模块化应用转成微服务架构,服务也不必非得很“微”才具备可维护性。在服务中应用模块化原则能让它们在复杂度的可扩展性上超越通常的微服务。现在这份蓝图中既有微服务也有模块,减少架构中的服务的数量可以节约成本;而其中的模块可以像构建单体式应用一样,构建和扩展服务。
From b20456939ffc66de053d0857be6fd3294e961dcc Mon Sep 17 00:00:00 2001
From: ivyxuan
Date: Sun, 9 Apr 2017 20:59:48 +0800
Subject: [PATCH 094/638] =?UTF-8?q?=E6=A0=B9=E6=8D=AE=20ylq167=20=E5=92=8C?=
=?UTF-8?q?=20gaozp=20=E7=9A=84=E6=84=8F=E8=A7=81=E8=BF=9B=E8=A1=8C?=
=?UTF-8?q?=E4=BF=AE=E6=94=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
TODO/the-details-that-matter.md | 90 ++++++---------------------------
1 file changed, 15 insertions(+), 75 deletions(-)
diff --git a/TODO/the-details-that-matter.md b/TODO/the-details-that-matter.md
index 401d203b9d2..fce6047f6df 100644
--- a/TODO/the-details-that-matter.md
+++ b/TODO/the-details-that-matter.md
@@ -1,215 +1,155 @@
> * 原文地址:[The Details That Matter](https://uxplanet.org/the-details-that-matter-8b962ca58b49#.ypigeruoq)
> * 原文作者:[Nick Babich](https://uxplanet.org/@101?source=post_header_lockup)
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
-> * 译者:
-> * 校对者:
+> * 译者:[ivyxuan](https://github.com/iloveivyxuan)
+> * 校对者:[ylq167](http://www.11167.xyz)、[gaozp](https://github.com/gaozp)
-# The Details That Matter #
# 细节是产品设计的重中之重 #
-Your product’s success is based on a combination of factors, but the overall user experience tops them all. When it comes down to designing a new app or a site, sticking to best practices is a solid way to go, but during the creation of the big picture, it’s fairly easy to skimp over design elements that feel like nice to have but not necessary. However, the difference between good and bad experiences often comes down to how thoughtful we can design these small details.
一个产品的成功是由各种因素共同造就的,而其中最重要的因素,就是整体的用户体验。在设计一款新的应用或是网站的时候,坚持最佳的实践规范是一个可靠的方法,但是在创造宏伟蓝图的时候,人们很容易就会省略掉那些能让人有更好的体验但却并非必要的设计元素。然而,设计的优劣往往在于我们能设计出多么体贴的细节。
-In this article, I’ll focus on *visual feedback*, *microcopy* and *whitespace* and you’ll see why these *little big details* are just as important as the more obvious elements of your design, and how they help determine the success of your product.
-在这篇文章中,我将会关注可视化反馈、小的提示信息还有留白这几个方面,你会发现为什么这些不起眼的细节和那些显眼的设计元素相比同样重要,而这些细节又是怎样决定你产品成败的。
+在这篇文章中,我将会重点关注**可视化反馈**、**小的文字信息**还有**留白**这几个方面,你将会发现为什么这些不起眼的细节和那些显眼的设计元素相比同样重要,而这些细节又是怎样决定你产品成败的。
-### Visual Feedback ###
### 可视化反馈 ###
-Visual feedback might be easily overlooked in the greater design scheme, but it actually hold the entire experience together. When there’s no feedback there’s no proper interaction. Imagine talking to someone who doesn’t respond in any way — you can’t communicate at all. Same goes for your app.
可视化反馈在较大的设计方案里很容易就会被忽视掉,但它实际上贯穿整体的用户体验流程。可以说,如果没有反馈就没有所谓的交互,你能想象和一个人聊天,可他一点反应也不给你吗 —— 你根本就聊不下去。而对于你的应用也是同样的道理。
-> *Lack of visual feedback is able to confuse users.*
> **缺乏可视化的反馈会让用户感到困惑。**
-You must ensure that there is always some feedback for user actions, because it makes users feel in control. Visual feedback
-你必须要确保对于用户的每个动作都有相应的反应,因为这会让用户会感觉他在控制着一切。可视化反馈
+你必须要确保对于用户的每个动作都有相应的反馈,因为这会让用户感觉应用运行一切正常。可视化反馈
-- Acknowledges that the app has received a user’s action.
-- Communicates the results of interaction, making it both *visible* and *understandable*. Gives the user a signal that they (or the app) have succeeded or failed at performing a task.
-- 首先表明这个应用了解了用户的操作。
+- 首先表明这个应用接受到了用户的操作。
- 然后它通过一种可视化而且易于理解的方式告诉用户这次交互的结果是什么,通过给用户一个信号,来告诉用户自己对于这个任务的执行是成功还是失败。
-#### Make buttons and other controls tangible ####
-#### 让按钮或是其他开关看起来是可以碰的 ####
+#### 让按钮或是其他开关看起来是可触摸的 ####
-In real life, buttons, controls and objects respond to our interaction, and this is how people expect things to work. People expect a similar level of responsiveness from app elements.
在现实生活中,按钮、开关还有其他东西都会对我们的动作有所回应,人们觉得世界就是这样运转的。而同样,人们也会期待应用里的元素能有类似的回应。
-Image credits: [Ramotion](https://dribbble.com/shots/1749645-Contact-Sync)
图片来源:[Ramotion](https://dribbble.com/shots/1749645-Contact-Sync)
-#### Result of operation ####
#### 操作的结果 ####
-Visual feedback is also helpful when you need to inform users about results of an operation. You can use existing elements to deliver a feedback.
-当你需要告诉用户他的操作结果是什么的时候,可视化反馈就很有用了。你可以利用现有的元素去传递反馈信息。
+当你需要告诉用户他的操作结果是什么的时候,可视化反馈就很有用了,你可以利用现有的元素去传递反馈信息。
-Image credits: [Colin Garven](https://dribbble.com/ColinGarven)
图片来源:[Colin Garven](https://dribbble.com/ColinGarven)
-#### **System should tell users its state** ####
-#### **系统需要告诉用户他的状态是什么** ####
+#### **系统需要告诉用户他当前的状态是什么** ####
-Users want to know their current context in a system at any given time and apps shouldn’t keep them guessing — they should tell the user what’s happening via appropriate visual feedback. For frequent and minor actions, the response can be modest, while for infrequent and major actions, the response should be more substantial.
-在系统中,用户任何时候都会想知道他此刻的状态是什么,而这不应该让用户自己去猜 —— 所以系统应该通过恰当的可视化反馈告诉用户此刻正在发生什么。对于一些常见而且次要的操作,适当的反馈就可以了,而对于不寻常而且重要的操作,反馈就需要更明显一点。
+在系统中,用户任何时候都会想知道他此刻的状态是什么,而这不应该让用户自己去猜 —— 所以系统应该通过恰当的可视化反馈告诉用户此刻正在发生什么。对于一些常见而且次要的操作,简单的反馈就可以了,而对于不寻常而且重要的操作,反馈就需要更明显一点。
-- [Animated notification](https://uxplanet.org/3-key-uses-for-animation-in-mobile-ui-design-4d7c482dd84b#.x07lyyazb) makes it possible for a user to quickly understand the current status.
- [动态提醒](https://uxplanet.org/3-key-uses-for-animation-in-mobile-ui-design-4d7c482dd84b#.x07lyyazb)可以让用户立刻明白此时的状态。
-Image credits: [Eddy Gann](https://dribbble.com/SMSeddy)
图片来源:[Eddy Gann](https://dribbble.com/SMSeddy)
-- [Loading animations](https://uxplanet.org/progress-indicators-in-mobile-ux-design-a141e22f3ea0#.etoavwmbw) provides real-time notification of app’s process status, enabling the user to quickly understand what is going on.
- [加载动画](https://uxplanet.org/progress-indicators-in-mobile-ux-design-a141e22f3ea0#.etoavwmbw)是对于应用进程的实时提醒,可以让用户立刻明白现在加载到哪里了。
-A loading bar engages the user and prevents confusion when app is busy loading data. Image credits: [Mark](https://dribbble.com/milkycookie)
-图片来源:[Mark](https://dribbble.com/milkycookie)
-应用无法快速加载信息的时候,进度条可以避免让用户感到困惑。图片来源:[Mark](https://dribbble.com/milkycookie)
+应用加载信息的时候,进度条可以避免让用户感到困惑。图片来源:[Mark](https://dribbble.com/milkycookie)
-### Microcopy ###
### 少量的文字信息 ###
-Microcopy is the little bits of text that guide users through an experience. Microcopy examples are error messages, button labels, hint text. At a glance, these tiny clusters of words seem insignificant when compared to the overall app design. But surprisingly, they have a huge impact on conversions.
少量的文字信息是一些用来是指导用户行为的一点点文字。举一些例子就是,错误信息、按钮对应的标签、提示信息。乍看之下,这么少的文字和整个应用设计比起来一点也不重要,但出人意料的是,它们对转化率有着极为重要的影响。
-> Writing good microcopy in your app is just as important as having the app work correctly and the user interface being easy and efficient to use.
> 在应用里写出好的文字信息,和让应用正常运行、用户界面易于使用一样重要。
-#### Show that you’re human ####
#### 让应用看起来像一个有血有肉的人 ####
-A quick way to make your UI warmer and less mechanical is a human tone in the copy. If your product sounds human, it’s easier for people to trust you.
有一个快速的方法能让你的 UI 变得温暖而不呆板,就是用人说话的口吻去描述内容。如果你的产品听起来好像是一个人,用户就会更加的信任你。
-Yelp shows they have real humans in charge.
Yelp 表现得好像他们是真人在负责这件事情。
-Airbnb sound human and conversational
Airbnb 的提示听起来像人说的话而且语气还很随和。
-#### Use friendly and helpful copy in a moment of failure ####
#### 报错的方式要友好而且有效 ####
-How errors are communicated can have a huge impact on the way someone experiences your product. Often overlooked, an ill-constructed error message can fill users with frustration.
-表达错误信息的方式会严重影响产品的用户体验。通常来说,省略错误信息或是没有正确描述错误信息都会让用户感到失望。
+表达错误信息的方式会严重影响产品的用户体验。通常来说,省略错误信息或是没有正确描述错误信息都会让用户受挫。
-*An alert message such as “An error occurred” is mystifying to all users and is likely to annoy experienced users.*
**像“出错啦”这种警告对所有的用户都会造成困扰,而且还会惹恼专家级用户。**
-A well-crafted error message, on the other hand, can turn a moment of frustration into a moment of delight. Thus, make error messages human, not technical, and suited to your audience.
但是,一个精心设计过的错误信息,会顿时化失望为欣喜。所以,把报错变得人性化、不用技术性的语言并且适合你的用户群体。
-Error states must incorporate concise, friendly, and instructive copy as to what to do next.
错误状态一定要具体、友好而且有用,要告诉用户下一步怎么做。
-#### Alleviate users concerns ####
#### 减少用户的担忧 ####
-Microcopy is extremely contextual. That’s why it’s so valuable. It answers a very specific question people have and speaks to their concerns right on the spot. For example, microcopy can be fundamental in reassuring your users at the point of subscribing or sharing details. Whilst ‘not to spam/auto-tweet’ might be taken for granted by good marketers when asking for email address/access to the social network account connections, the user is less than sure. Thus, when people add their emails or connect their Twitter accounts, say “we hate spam as much as you do.”
这些少量的文字信息是很情景化的,这也是为什么它很重要的一个原因。它可以解答用户具体情况下的问题,并针对他们所担忧的事情进行直接地交流。举例来说,当用户选择订阅或是提供了具体信息的时候,一些文字信息对于消除用户担忧会起到相当关键的作用。对于优秀的营销人员来说,“不会有群发消息或是自动关注”是理所当然的事情,但用户自己会存疑。因此,当用户添加了他们的邮箱地址或者绑定了 Twitter 账号的时候,一定要明确表态“我们和你一样讨厌垃圾消息”。
-This microcopy covers all the potential user concerns in one tight little sentence.
这只是一小段紧凑的文字,却涵盖了用户所有潜在的担忧。
-### Whitespace ###
### 留白 ###
-Whitespace (or negative space) is the areas of a design where there is no element placed by a designer. Elements of whitespace are space around images, margins, paddings, line-spacing and letter-spacing within text content. Although many may consider it a waste of valuable screen estate, whitespace is an essential element in user interface design.
-留白(或者说是负空间)是设计师没有摆放设计元素的地方。而设计元素间的留白是指处在图片间、内填充(margin)、外填充(padding)和行间、字间的空白。虽然很多人觉得这些空白浪费了宝贵的界面位置,但其实,留白是用户界面设计的一个重要元素。
+留白(或者说是负空间)是设计师没有摆放设计元素的地方。而设计元素间的留白是指处在图片间距、内边距、外边距、行间距和字间距的空白。虽然很多人觉得这些空白浪费了宝贵的界面位置,但其实,留白是用户界面设计的一个重要元素。
-#### Improve UI comprehension ####
#### 让用户界面更容易理解 ####
-*Clutter is bad.* Cluttering your interface overloads your user with too much information: every added button, image, and line of text make the screen more complicated. If you don’t think any part of your design should be intentionally blank, take a look at example below and you’ll see what happens when too many objects competing for your attention.
**杂乱的堆砌是很糟糕的一件事情。**在界面上杂乱堆砌元素会给用户带来过多的信息:每一个被添加的按钮、图片和文字都会让界面显得更加复杂。如果你不想你的设计有任何刻意的留白的话,下面这个例子就能很明白的告诉你,有太多东西一起吸引你的注意力是多么可怕的事情。
-A cluttered UI is unattractive and doesn’t make users want to scan it, especially when there’s no visual hierarchy within the view.
-杂乱堆砌的 UI 尤其是没有视觉层次的 UI 会让用户没有拥有一点想要审视的欲望。
+杂乱堆砌的 UI 尤其是没有视觉层次的 UI 会让用户没有一点想要审视的欲望。
-The power of white space comes from the limits of human attention and memory. Our short-term memory can hold a small amount of information (typically [around 7 items or even less](http://www.human-memory.net/types_short.html)) in mind in an active, readily-available state for a short period of time (typically from 10 to 15 seconds, or sometimes up to a minute).
-留白之所以很重要,是因为用户的注意力还有记忆里是有限的。我们的短期记忆只可以在短时间内(通常来说是 10 到 15 秒钟、或者是 1 分钟以内)记住一点有效的既有信息(通常来说[是 7 个事物或者比这个更少](http://www.human-memory.net/types_short.html))。
+留白之所以很重要,是因为用户的注意力还有记忆是很有限的。我们的短期记忆只可以在短时间内(通常来说是 10 到 15 秒钟、或者是 1 分钟以内)记住一点有效的既有信息(通常来说[是 7 个事物或者比这个更少](http://www.human-memory.net/types_short.html))。
-> User attention is a precious resource, and should be allocated accordingly.
> 用户的注意力是很珍贵的资源,所以必须合理的分配。
-If cluttering your interface overloads your user with too much information, then reducing the clutter will improve comprehension. Generous whitespace can make some of the messiest interfaces look inviting and simple. Whitespace reduces the amount of elements users see all at once and makes scanning much easier. The skill of using whitespace lies in providing your users with a digestible amount of content ([chunks of content](https://uxplanet.org/best-practices-for-cards-fa45e3ad94dd#.by8pzk56q)), then stripping away extraneous details.
如果因为你界面上的胡乱堆砌使得用户接收过多的信息,那么减少一些杂物就能改善用户的理解。大方地使用留白可以让凌乱的界面变得简单而有吸引力,留白削减了用户乍看之下接收到的元素数量,这使得浏览信息变得更加容易。留白的使用技巧在于只给用户提供能让他消化的数量的内容([一定数量的内容](https://uxplanet.org/best-practices-for-cards-fa45e3ad94dd#.by8pzk56q)),然后去掉不必要的细节。
-Medium is a great example of using whitespace to improve content and UI comprehension.
Medium 是一个典型的例子,它善于使用留白来改善用户对内容和 UI 的理解。
-#### Draw attention to elements ####
#### 让元素更具有吸引力 ####
-Whitespace creates the spaces around elements in the design to help them stand out or separate from the other elements. It helps communicate what’s most important and needs attention.
留白在设计中是通过在元素周围留出空白,以让元素更加突出或是和其他元素以进行区分。它可以告诉用户什么是最重要而且是需要格外注意的。
-> The more space you provide around the element, the more focused it becomes.
> 元素周围的留白越多,元素就会越引人注目。
-Google Search homepage is a great example of using whitespace. The layout immediately facilitates the user goal by placing primary interaction element (search box) in front and center, with plenty of white space on either side to add emphasis.
谷歌搜索的首页就是一个使用留白的典型例子,它通过在正中央摆放其最重要的交互元素(搜索框),并且在周围留出足够的空白以凸显其重要性的布局,直接实现了用户目标。
-The lack of other elements will make existing elements stand out more.
去掉其他的元素可以更加凸显留下来的元素。
-#### Clarifying relationships ####
#### 明确关系 ####
-The [law of proximity](https://www.interaction-design.org/literature/article/laws-of-proximity-uniform-connectedness-and-continuation-gestalt-principles-2) describes how the human eye perceives connections between visual elements. It states that objects near to each other appear similar. We can use whitespace to build perceived relationships between different elements. Take a look at this picture. Almost everyone sees two groups of dots, rather than simply 16 dots.
[接近法则](https://www.interaction-design.org/literature/article/laws-of-proximity-uniform-connectedness-and-continuation-gestalt-principles-2)描述了人的眼睛是如何划分视觉元素的,它阐述说距离更近的物体看起来更相似。我们可以利用留白,在不同的元素间产生视觉联系。你看下面这幅图片,几乎所有人都会说看到了两组点,而不是16个点。
-Breaking the information up into appropriate groups can help make it feel more scannable and readable. In the form on the right, categorising the 15 fields into three groups makes the process feel easier. The amount of content is the same, but the impression on users is much different.
将信息拆分成合适的组别可以让信息更好的被识别和阅读。右边的表单将 15 栏拆分成 3 组,这样填写表单也变得相对容易了。虽然内容的数量仍然相同,但是给用户的感觉却完全不同。
-Image credits: NNGroup
图片来源:NNGroup
-### Conclusion ###
### 总结 ###
-*Design with care.* Each minor detail in your app’s UI deserves close attention because UX is the sum of all details working harmoniously:
**用心设计,应用界面上的每一个小的细节都值得细心揣摩,因为用户体验就是由这些小的细节相互协调作用而成的:
-> “The details are not the details. They make the design.” ―Charles Eames
-> “细节不只是细节,细节成就了设计。”
+> “细节不只是细节,细节成就了设计。” —— Charles Eames
-Thank you!
谢谢!
-*Follow UX Planet:* [*Twitter*](https://twitter.com/101babich)[*Facebook*](https://www.facebook.com/uxplanet/)
**关注 UX Planet:** [*Twitter*](https://twitter.com/101babich)[*Facebook*](https://www.facebook.com/uxplanet/)
---
From 1004922aa7b7e87efced13f6b71a75d06f353a8b Mon Sep 17 00:00:00 2001
From: ivyxuan
Date: Sun, 9 Apr 2017 21:14:26 +0800
Subject: [PATCH 095/638] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=B8=80=E7=82=B9?=
=?UTF-8?q?=E9=94=99=E8=AF=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
TODO/the-details-that-matter.md | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/TODO/the-details-that-matter.md b/TODO/the-details-that-matter.md
index fce6047f6df..b4ccfb5d9f8 100644
--- a/TODO/the-details-that-matter.md
+++ b/TODO/the-details-that-matter.md
@@ -62,7 +62,7 @@
> 在应用里写出好的文字信息,和让应用正常运行、用户界面易于使用一样重要。
-#### 让应用看起来像一个有血有肉的人 ####
+#### 让应用看起来像是一个人 ####
有一个快速的方法能让你的 UI 变得温暖而不呆板,就是用人说话的口吻去描述内容。如果你的产品听起来好像是一个人,用户就会更加的信任你。
@@ -80,9 +80,7 @@ Airbnb 的提示听起来像人说的话而且语气还很随和。
-**像“出错啦”这种警告对所有的用户都会造成困扰,而且还会惹恼专家级用户。**
-
-但是,一个精心设计过的错误信息,会顿时化失望为欣喜。所以,把报错变得人性化、不用技术性的语言并且适合你的用户群体。
+**像“出错啦”这种警告对所有的用户都会造成困扰,而且还会惹恼专家级用户。**但是,一个精心设计过的错误信息,会顿时化失望为欣喜。所以,把报错变得人性化、不用技术性的语言并且适合你的用户群体。
@@ -144,13 +142,13 @@ Medium 是一个典型的例子,它善于使用留白来改善用户对内容
### 总结 ###
-**用心设计,应用界面上的每一个小的细节都值得细心揣摩,因为用户体验就是由这些小的细节相互协调作用而成的:
+**用心设计**,应用界面上的每一个小的细节都值得细心揣摩,因为用户体验就是由这些小的细节相互协调作用而成的:
> “细节不只是细节,细节成就了设计。” —— Charles Eames
谢谢!
-**关注 UX Planet:** [*Twitter*](https://twitter.com/101babich)[*Facebook*](https://www.facebook.com/uxplanet/)
+**关注 UX Planet:** [*Twitter*](https://twitter.com/101babich) | [*Facebook*](https://www.facebook.com/uxplanet/)
---
> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[React](https://github.com/xitu/gold-miner#react)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计) 等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)。
From d8e709c9c21142931a6e1e91b87c1971f8d4ccaa Mon Sep 17 00:00:00 2001
From: Ruixi
Date: Sun, 9 Apr 2017 22:47:28 +0800
Subject: [PATCH 096/638] =?UTF-8?q?=E7=BF=BB=E8=AF=91=E5=88=9D=E7=A8=BF040?=
=?UTF-8?q?9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
...ion-our-thoughts-on-design-are-changing.md | 66 +++++++++----------
1 file changed, 33 insertions(+), 33 deletions(-)
diff --git a/TODO/from-form-to-function-our-thoughts-on-design-are-changing.md b/TODO/from-form-to-function-our-thoughts-on-design-are-changing.md
index f2bce0a9d4d..3ed924e8fd9 100644
--- a/TODO/from-form-to-function-our-thoughts-on-design-are-changing.md
+++ b/TODO/from-form-to-function-our-thoughts-on-design-are-changing.md
@@ -1,96 +1,96 @@
> * 原文地址:[From Form to Function, Our Thoughts On Design Are Changing](https://medium.com/thinking-design/from-form-to-function-our-thoughts-on-design-are-changing-ed556d8f2b58)
> * 原文作者:[Adobe Creative Cloud](https://medium.com/@creativecloud)
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
-> * 译者:
+> * 译者:[Ruixi](https://github.com/ruixi)
> * 校对者:
-# From Form to Function, Our Thoughts On Design Are Changing
+# 从形式到功能,设计思维的改变
![](https://cdn-images-1.medium.com/max/1600/1*bImmCpF6MPs9JslB21eAVQ.jpeg)
-Design is more important to business than ever before, because it’s an essential driver of user engagement. Looking at the recent evolution of user interface design might give you a sense of how user expectations have been changing and what’s coming next. But before we dive into details we need to find an answer to one important question — *what is design?*
+设计作为用户参与的基本驱动力,对商业而言比以往任何时候都更加重要。留意一下最近的用户界面设计趋势,这可能让你感受到用户的期待以往的变化,以及未来的趋势。但在我们深入讨论之前,有个问题需要回答—— **设计是什么?**
-### What is Design?
+### 设计是什么?
-Most people (even some designers) perceive design as visual elements that are added to a product after it’s done; a process that comes at the end of a product’s development, and is treated like a decoration that the designers slapped onto the real work of the engineers. While design is visual aesthetics, it is also much more. As Steve Jobs once said, “Design is not just what it looks like and feels like. *Design is how it works.*” Design is both how product ***looks*** and how it ***works*** .
+大多数人(甚至包括一些设计师)都将设计视作在产品完成之后所添加的视觉点缀,在产品开发结束之后的工艺流程,就像是设计师们强加在工程师的真实工作之上的。设计的确是视觉美学,但不仅如此。就像史蒂夫·乔布斯曾经说过的:“设计不只关乎视觉和感官。**设计关乎(产品)如何运作**。(Design is not just what it looks like and feels like. Design is how it works.)” 设计既包括产品的**视觉体验**,也包括产品的**运作原理**。
-### The Evolution of Graphical User Interface (GUI) Design
+### 图形用户界面(GUI)设计的演化
-Computers and humans don’t speak the same language. To make interaction possible, designers rely on *graphical* user interfaces. The recent evolution of GUI makes it clear that *design trends are evolving for users.* In order to prove this point let’s examine the GUI changes in the last decade.
+计算机和人类说着不同的语言。设计师们依靠**图形**用户界面使交互成为可能。最近的 GUI 设计演化清晰地表明:**设计趋势就是用户的不断变化。** 为了证明这一点,我们来看看最近十年的 GUI 设计变化。
-#### From Complexity to Simplicity
+#### 从复杂到简单
-Towards the end of the 2000’s GUI design started to change significantly due to the rise in popularity of mobile devices. This huge shift in device preference led to designers having to rethink interfaces from scratch, which in turn led to global changes in GUI design.
+由于移动设备的普及,2000 年底的 GUI 设计开始产生了明显的变化。设备配置的极大变化迫使设计师们不得不界面进行重新思考,而这又反过来引起了全球的 GUI 设计的变化。
-Looking at the history of the web, we can see that a decade ago websites were rudimentary in terms of design. But visual appearance wasn’t the only problem in this approach to design. Websites tried to provide *as many options as possible* : all the information a site contained seemed to be available; everything included on a site was ‘equally’ important. Designers thought that it would make websites more valuable to users. Unfortunately this often led to a cluttered interface. In the example below, you can see how distracting a cluttered interface can be from a usability standpoint.
+看看 Web 的历史,我们就会发现十年前的网站设计是不成熟的。但视觉并不是这种设计方式唯一的问题所在。网站试图提供**尽可能多的选择**:一个站点所包含的所有信息似乎都是可用的,页面上的每个元素都“同等”重要。(那时的)设计师们觉得这样会让网站对用户来说更有价值。不幸的是,这往往导致页面的杂乱无章。在下方的案例中,你可以看出,从可用性的角度出发,一个乱七八糟的界面能凌乱到什么程度。
![](https://cdn-images-1.medium.com/max/1600/1*MgAzj4RVV2zFTQKQCmfSRw.jpeg)
-With the rise of mobile devices designers began to realize that user attention is a precious resource and should be treated accordingly. This lead to the *highly focused* and *very prioritized interfaces*. Such interfaces have just the right amount of information available at the exactly right time users need it.
+随着移动设备的兴起,设计师们开始意识到,用户的注意力是一种需要被合理利用的珍贵资源。这就促使了**高度集中**和**按优先级处理界面**的出现。这样的界面能在用户最需要的时候提供最恰当数量的可用信息。
![](https://cdn-images-1.medium.com/max/1600/1*IMwAqnMVH2peTtdNtwPPhQ.jpeg)
-#### From Skeuomorphism to Flat Design
+#### 从拟物化到扁平化
-Do you remember when all touch screen apps looked very physical? At one point in time, almost all apps used a skeuomorphic design style which was based on symbols borrowed from the real world.
+你还记得触屏上的所有应用程序看起来都像真的一样的时候吗?那个时候,几乎所有应用程序都在使用拟物化设计风格,而这种风格又是对现实世界中符号的借用。
![](https://cdn-images-1.medium.com/max/1600/1*Mrt--PeX7t5qPmnmwzDUAg.png)
-Skeuomorphism wasn’t just a pure design trend, it played an important role in usability. When touch screen devices were fairly new to many users, designers had to make sure users would understand how apps worked. Skeuomorphic designs help users understand how to use a new interface works by making the design familiar. That’s why the iOS Newsstand app in the example above looks like a physical bookshelf. As users progressively became more familiar with touch screens, such design metaphors weren’t needed and this style went away.
+拟物化并不是一种纯粹的设计趋势,它在可用性方面也扮演了重要的角色。当很多用户都对触屏设备知之甚少的时候,设计师们必须确保用户能够明白这些应用程序是做什么的。拟物化设计通过让设计更加贴近(现实生活)来帮助人们理解新页面的运作方式。这就是上方的 iOS 报刊亭应用看上去就像是一个真实的书架(的原因)。随着用户渐渐的熟悉了触屏,这种设计隐喻显得鸡肋,而这种设计风格也逐渐退出了历史舞台。
![](https://cdn-images-1.medium.com/max/1600/1*TxE-vVFUv_61nYtdml78Kw.jpeg)
-With the quick adoption of new technologies, there was a movement towards a pure digital look, called flat design. This new style relies mainly on flat textures and icons, typography, spacing, and color to bring order to the digital canvas.
+随着新技术的使用,一种纯粹的数字化外观出现了:扁平化。这种新的设计风格主要依靠平面质感、图标、排版、间距和色彩来营造数字界面的秩序。
-#### From a Single Channel to Seamless Experience Across All Channels
+#### 从单一终端到跨终端
-Ten years ago a major design challenge was to make sure designs worked in every browser. Today, the major design challenge is to *make sure your designworks on the devices your users use*. There’s no such thing as mobile user and desktop user any more. There are users who may want to use your product in the same way, regardless of the device. That’s why *continuity across multiple devices* — creating a seamless experience across mobile, desktop, tablet and wearables — is so important. The goal is to put users at the center of your multi-channel design, [offering an omnichannel approach](https://uxmag.com/articles/5-elements-of-omni-channel-user-experiences) that lets users efficiently use product regardless of the device.
+十年前,一个主要的设计挑战就是保证设计能够在每一个浏览器下正常运行。今天,主要的设计挑战是**保证你的设计在用户所使用的设备上正常运行**。不再有移动用户和桌面端用户这种说法了。只有无论在什么设备上都可能想要照常使用你的产品的用户。这就是为什么**跨终端体验**(在移动端、桌面端、平板和可穿戴设备上的无缝体验)如此重要。目标就是将用户放在你的设计(包括多种终端)之中,[提供一个全方位的解决方案](https://uxmag.com/articles/5-elements-of-omni-channel-user-experiences) ,能够让用户无论在何种设备上都能够高效地使用产品。
![](https://cdn-images-1.medium.com/max/1600/1*j5kqBjTpLFS5e1J3wkmvgw.jpeg)
-### From Pixels to People
+### 从像素到人
-Modern apps and sites are more than just the graphical representation of a solution — they are complex systems focused on solving user problems and generating valuable outcome. Despite all advantages, these systems have a serious natural barrier — graphical user interface. No matter how good a GUI is, people still have to learn to use it. In order to solve this problem modern UX goes beyond on-screen design and into a world of UI-less interactions.
+现代应用程序和网站不只是解决方案的视觉表现,更是专注于解决用户问题并提供有价值结果的复杂系统。尽管这些系统有种种优点,但它还是有一个严重的天然障碍——图形用户界面。无论 GUI 如何优秀,人们都不得不去学习如何使用它。为了解决这个问题,现代 UX 走得更远——屏幕设计,以及融入没有用户界面的交互之中。
-#### Time-Saving Design
+#### 节省时间的设计
-Today, users expect more user-devoted, frictionless experiences from their interactions with technology. They want to use products designed to save their time. Since time-saving design is all about respecting a user’s time, it’s clear why it’s on the rise. Modern apps strive to follow this trend by:
+今天,用户期望从他们与科技的交互中的用户投入更多,以及经验的无需磨合。他们想要使用被设计来节省他们的时间的产品。节约时间的设计完全是对用户时间的慎重对待,这也清楚地解释了它们崛起的原因。当代应用程序设计力求追随如下趋势:
-- **Anticipating user needs** Take Dark Sky weather app for instance. Some users might still prefer to open a weather app to check the forecast, but the most useful thing the weather app can do is to alert user about suddenly changed weather conditions (e.g. notify user that it’ll be snowing soon).
+- **预见用户需求。** 这里用 Dark Sky weather 举个例子。一些用户可能仍然喜欢打开天气应用来查看天气预报,但天气应用最有用的举动是提醒用户突然变化的天气状况(比如通知用户很快就要下雪了)。
![](https://cdn-images-1.medium.com/max/1600/1*79Wbi92BeDyVaDPEEQjMLQ.jpeg)
-- **Interpreting user actions and goals.** When you open the Uber app for Apple Watch, it goes straight to a screen showing how long it’ll be until a car can come get you — no pulling out your phone to drop pins required.
+- **理解用户行为和目标。** 当你打开 Apple Watch 的优步应用时,它会直接在屏幕上显示车辆能够到达的时间——不需要拿出手机选择定位。
![](https://cdn-images-1.medium.com/max/1600/0*0ouzEuTHaORKAryP.jpg)
-#### Self-learning systems (SLS)
+#### 自学习系统(Self-learning systems ,SLS)
-Self learning systems (SLS) powered software anticipates tasks that need to be done and simply auto-completes them for the user, or at least gets the user several steps closer to finishing the tasks. Software that functions more autonomously has a major benefit for the users — it requires *much less attention*. The basic building block of self-learning software is the ability for a system to learn based on experience, analyse incoming data, and take action in response to new events. The challenge with SLS is to design behaviours based on the fewest possible interactions, while focusing on people’s behavior. Why is it a challenge? Because you need to find a balance between saving your user’s time and providing just enough options so users feel that they have control over a system.
+自学习系统控制软件预见一些简单的、需要被自动代替用户完成的任务,或者至少让用户更接近任务完成的步骤。功能更为自主的软件对用户来说有个很重大的益处——不需要**太多注意力**。 自学习软件的基本构件是基于经验的系统学习能力,分析传入数据,以及对新的事件作出反应。自学习系统面临的挑战是在控制交互行为数量的基础上设计行为,关注人的行为。为什么这是个挑战?因为你需要在节约用户时间和为用户提供足够多的选项(让用户感受到自己对系统的控制)找到一个平衡点
![](https://cdn-images-1.medium.com/max/1600/1*_yiHy0NAU1xANCf6HYxMDA.jpeg)
-[Nest](https://nest.com/) is great example of SLS. It’s a semi-intelligent thermostat that can program itself around user’s life. Each time a user changes the settings, Nest remembers temperature adjustments, and after a few days users will be adjusting Nest less, because it pulls all it has learned into a schedule for the home. Yes, Nest has a lot of downsides (the most critical one is that [the system often lives its own way](https://www.nngroup.com/articles/emotional-design-fail/)), but still it’s a great example of the next wave of product. Looking ahead, self-learning software will be the one thing that distinguishes legacy apps from modern ones.
+[Nest](https://nest.com/) 就是个很好的自学习系统的例子。它是一个可以围绕用户的生活来制定计划的半智能恒温器。每当用户更改系统设置的时候,Nest 都会记得调整温度,并且在几天之后用户对 Nest 的调整会减少,因为它把它学到的一切都变成家庭的时间表。是的,Nest 有很多缺点(最严重的是[系统总是采用自己的方式](https://www.nngroup.com/articles/emotional-design-fail/)),但它依然是下一代产品的绝好示例。展望未来,自学习软件将会是区别传统应用和现代应用的一个重要因素。
-#### Conversational Interfaces
+#### 会话界面
-With the advent of iPhone Messages, Slack or WhatsApp, the way we exchange information changed irreversibly. Text messages have become an extremely natural way of communicating.
+随着 iPhone 消息, Slack 以及 WhatsApp 的出现,我们交换信息的方式被完全改变。 短信已经成为一种极其自然的交流方式。
![](https://cdn-images-1.medium.com/max/1600/1*ZMmEYOSW_mZttqHXIEqDpw.png)
-This trend led to the popularization of conversational interfaces. Essentially, a conversational interface is any user interface that mimics chatting with a real human. “Chatbot” is one of the hottest terms in our industry right now. More and more apps are leaving behind the GUI in favor of personal chat. Why? Because conversation feels natural for us and this property makes the use of chatbots much more intuitive than tapping on a bunch of buttons in traditional user interfaces. Another benefit of conversational interfaces is in detalization: GUI can only have a finite amount of options in practice, but speaking to a chatbot can in theory (if designed well) allow open ended discovery and interaction.
+这一趋势导致了会话界面的普及。从本质上讲,会话界面就是是模仿真实人类聊天的用户界面。“聊天机器人(Chatbot)”是目前我们行业最热门的术语之一。越来越多的应用程序的 GUI 支持个人聊天。为什么?因为交谈对我们来说感觉很自然,这种特性使聊天机器人的使用比在传统用户界面中敲击一堆按钮更加直观。另一个会话界面的优势在于细节程度(这个词我不太确定——译者注):GUI 在实际中只有有限的选项,但和聊天机器人交谈在理论上(如果设计得好)允许开放式的发现和交互。
![](https://cdn-images-1.medium.com/max/1600/1*odt0dGAYbEau2LXZo8EF3A.gif)
-Last but not least, teens and millennials — who represent the bulk of tomorrow’s market — spend more time on messaging apps than on any other apps or sites, creating a huge opportunity for businesses who want to reach this audience.
+最后但同样重要,青少年和千禧一代——未来市场的主要代表——在短信应用程序中花的时间比任何其他应用程序或网站都要多,为想要接触到这个群体的(人/企业)创造了一个巨大的商业机会。
-But chatbots aren’t a final step of conversational interface evolution. Voice interfaces will be a natural next step for chatbots. In the not too distant future, voice interaction will make up a large part of how we interact with the technology around us. The experience of using voice commands to control computers has already been transformed by a new generation of voice-interaction systems such as Apple’s Siri, Google Now and Amazon Echo. The latter doesn’t use a traditional GUI as a means of interaction. But the biggest challenge is to understand how people will interact with voice interfaces. This requires a better understanding of humans — not only the topics they are interested in talking about, but *how* they are going to talk about the topics.
+但聊天机器人不是会话界面进化的最终形态。语音界面将会是聊天机器人的下一步。在不远的将来,语音交互将会在我们与技术的互动中占据很大部分。使用语音命令来控制计算机已经由新一代语音交互软件,比如 Siri,Google Now 和 Amazon Echo 实现了。它们不使用传统的 GUI 作为交互手段。但最大的挑战是了解人们将如何与语音界面进行交互。这需要更好地了解人类——不仅是他们感兴趣的话题,还包括他们将**如何**谈论这些话题。
![](https://cdn-images-1.medium.com/max/1600/1*coZE_xgldZTEQyI7SCdkvg.jpeg)
-### Conclusion
+### 结语
-With technology continuously evolving, we are on a path that could make interaction with digital services more intuitive, more accessible, and more efficient. Next generation platforms continue to develop much more like human-to-human conversation. The interface of the future might not always be made of pixels.
+随着技术的不断发展,我们正在使互动与数字服务更直观,更便捷,更高效的道路上不断前行。下一代平台继续发展得更接近人与人之间的对话。未来的界面不一定是由像素组成的。
---
From 0075d9a6d2d3a1f1cfad38b54f0f4f7a51015e3e Mon Sep 17 00:00:00 2001
From: ace
Date: Mon, 10 Apr 2017 10:06:48 +0800
Subject: [PATCH 097/638] =?UTF-8?q?update:=20=E4=B8=89=E6=A0=A1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
TODO/react-is-slow-react-is-fast.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/TODO/react-is-slow-react-is-fast.md b/TODO/react-is-slow-react-is-fast.md
index f2c44574c00..2188b60bd4d 100644
--- a/TODO/react-is-slow-react-is-fast.md
+++ b/TODO/react-is-slow-react-is-fast.md
@@ -171,7 +171,7 @@ class DatagridBody extends Component {
export default DatagridBody;
```
-**小提示**:相比手工实现 `shouldComponentUpdate()` 方法,我可以继承 React 的 `PureComponent` 而不是 `Component`。这个组件会用严格对等(`===`)对比所有的 props,并且仅当 **任一** props 变更时重绘。但是我知道在例子的上下文中 `resource` 和 `children` 不不会变更,所以无需检查他们的对等性。
+**小提示**:相比手工实现 `shouldComponentUpdate()` 方法,我可以继承 React 的 `PureComponent` 而不是 `Component`。这个组件会用严格对等(`===`)对比所有的 props,并且仅当 **任一** props 变更时重绘。但是我知道在例子的上下文中 `resource` 和 `children` 不会变更,所以无需检查他们的对等性。
有了这一优化,点击表头后,`` 组件的重绘会跳过表体及其全部 231 个组件。这会将 500ms 的更新时间减少到 60ms。网络性能提高超过 400ms!
@@ -488,7 +488,7 @@ export default onlyUpdateForKeys(['basePath', 'refresh'])(Toolbar);
## 结论
-还有许多可以使 React 应用更快的方法(使用 keys,懒加载重路由,`react-addons-perf` 包,使用 ServiceWorkers 缓存应用状态,使用同构等等),但正确实现 `shouldComponentUpdate` 是第一步 - 也是最有用的。
+还有许多可以使 React 应用更快的方法(使用 keys、懒加载重路由、`react-addons-perf` 包、使用 ServiceWorkers 缓存应用状态、使用同构等等),但正确实现 `shouldComponentUpdate` 是第一步 - 也是最有用的。
React 默认是不快的,但是无论是什么规模的应用,它都提供了许多工具来加速。这也许是违反直觉的,尤其自从许多框架提供了 React 的替代品,它们声称比 React 快 n 倍。但 React 把开发者的体验放在了性能之前。这也是为什么用 React 开发大型应用是个愉快的体验,没有惊吓,只有不变的实现速度。
From 41b103a78d20e01e81aa9013b816cab4180785c0 Mon Sep 17 00:00:00 2001
From: lsvih
Date: Mon, 10 Apr 2017 13:44:43 +0800
Subject: [PATCH 098/638] =?UTF-8?q?=E4=B8=80=E6=A0=A1=E4=BF=AE=E6=94=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
TODO/webpack-and-rollup-the-same-but-different.md | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/TODO/webpack-and-rollup-the-same-but-different.md b/TODO/webpack-and-rollup-the-same-but-different.md
index 4e286f35689..b80a7886547 100644
--- a/TODO/webpack-and-rollup-the-same-but-different.md
+++ b/TODO/webpack-and-rollup-the-same-but-different.md
@@ -8,7 +8,7 @@
![](https://cdn-images-1.medium.com/max/1000/1*rtjClMZ8sq3cLFT9Aq8Xyg.png)
-本周,Facebook 将一个[非常大的 pull request](https://github.com/facebook/react/pull/9327) 合并到了 React 主分支。这个 PR 将 React 以前使用的构建工具替换成了 [Rollup](https://rollupjs.org/)。这让许多人感到不解,纷纷在推特上提问:“为什么你们选择 Rollup 而不选择 Webpack 呢?”[1](https://twitter.com/stanlemon/status/849366789825994752)[2](https://twitter.com/MrMohtas/status/849362334988595201)[3](https://twitter.com/kyleholzinger/status/849683292760797184)
+本周,Facebook 将一个[非常大的 pull request](https://github.com/facebook/react/pull/9327) 合并到了 React 主分支。这个 PR 将 React 当前使用的构建工具替换成了 [Rollup](https://rollupjs.org/)。这让许多人感到不解,纷纷在推特上提问:“为什么你们选择 Rollup 而不选择 Webpack 呢?”[1](https://twitter.com/stanlemon/status/849366789825994752)[2](https://twitter.com/MrMohtas/status/849362334988595201)[3](https://twitter.com/kyleholzinger/status/849683292760797184)
有人问这个问题是很正常的。[Webpack](https://webpack.js.org/) 是现在 JavaScript 社区中最伟大的成功传奇之一,它有着数百万/月的下载量,驱动了成千上万的网站与应用。它有着巨大的生态系统、众多的贡献者,并且它与一般的社区开源项目不同——它有着[意义非凡的经济支持](https://opencollective.com/webpack)。
@@ -16,9 +16,9 @@
### 这两个打包工具的优缺点 ###
-Webpack 由 [Tobias Koppers](https://medium.com/@sokra) 在 2012 年创建,用于解决当时的工具不能处理的问题:构建复杂的单页应用(SPA)。它的两个特点改变了一切:
+Webpack 由 [Tobias Koppers](https://medium.com/@sokra) 在 2012 年创建,用于解决当时的工具不能处理的问题:构建复杂的单页应用(SPA)。尤其是它的两个特点改变了一切:
-1. **代码分割**可以将你的 app 分割成许多个容易管理的分块,这些分块能够在用户使用你的 app 时按需加载。这意味着你的网站可以比那些没有使用此技术的网站要快上很多。因为访问那些网站必须要等待整个应用都被下载并解析完成。当然,你**也可以**自己手动去进行代码分割,但是……总之,祝你好运。
+1. **代码分割**可以将你的 app 分割成许多个容易管理的分块,这些分块能够在用户使用你的 app 时按需加载。这意味着你的用户可以有更快的交互体验。因为访问那些网站必须要等待整个应用都被下载并解析完成。当然,你**也可以**自己手动去进行代码分割,但是……总之,祝你好运。
2. **静态资源**的导入:图片、CSS 等静态资源可以直接导入到你的 app 中,就和其它的模块、节点一样能够进行依赖管理。因此,我们再也不用小心翼翼地将各个静态文件放在特定的文件夹中,然后再去用脚本给文件 URL 加上哈希串了。Webpack 已经帮你完成了这一切。
而 Rollup 的开发理念则不同:它利用 ES2015 模块的巧妙设计,尽可能高效地构建精简且易分发的 JavaScript 库。而其它的模块打包器(包括 Webpack在内)都是通过将模块分别封装进函数中,然将这些函数通过能在浏览器中实现的 `require` 方法打包,最后依次处理这些函数。在你需要实现按需加载的时候,这种做法非常的方便,但是这样做引入了很多无关代码,比较浪费资源。当[你有很多模块要打包的时候,这种情况会变得更糟糕](https://nolanlawson.com/2016/08/15/the-cost-of-small-modules/)。
@@ -29,21 +29,21 @@ ES2015 模块则启用了一种不同的实现方法,Rollup 用的也就是这
### 那么我到底应该选用哪一个呢? ###
-回答这个问题之前,我们已经了解了这两个工具各自的优缺点,它们同时存在并相互支持的原因正是因为它们解决的问题不同。那么,现在这个问题的答案简单来说就是:
+到目前为止,我们已经清晰地了解了这两个工具共存并且相互支撑的原因 — 它们应用于不同的场景。那么,现在这个问题的答案简单来说就是:
> 在开发应用时使用 Webpack,开发库时使用 Rollup
当然这不是什么严格的规定——有很多的网站和 app 一样是使用 Rollup 构建的,同时也有很多的库使用 Webpack。不过,这是个很值得参考的经验之谈。
-如果你需要进行代码分割,或者你有很多的静态资源,再或者你做的东西深度依赖 CommonJS,毫无疑问 Webpack 是你的最佳选择。如果你的代码基于 ES2015 模块编写,并且你做的东西是准备给他人使用的,你应该更适合用 Rollup。
+如果你需要进行代码分割,或者你有很多的静态资源,再或者你做的东西深度依赖 CommonJS,毫无疑问 Webpack 是你的最佳选择。如果你的代码基于 ES2015 模块编写,并且你做的东西是准备给他人使用的,你或许可以考虑使用 Rollup。
### 对于包作者的建议:请使用 `pkg.module`! ###
-在很长一段时间里,使用 JavaScript 库是一件相当有风险的事,因为这意味着你必须和库的作者在模块系统上的意见保持一致。如果你使用 Browserify 而他更喜欢 AMD,你就不得不在 build 之前先强行将两者粘起来。[通用模块定义(UMD)](https://github.com/umdjs/umd)格式对这个问题进行了 *部分* 的修复,但是它没有强制要求所有的人都用它,最后反而会让你更加不知所措。
+在很长一段时间里,使用 JavaScript 库是一件有点风险的事,因为这意味着你必须和库的作者在模块系统上的意见保持一致。如果你使用 Browserify 而他更喜欢 AMD,你就不得不在 build 之前先强行将两者粘起来。[通用模块定义(UMD)](https://github.com/umdjs/umd)格式对这个问题进行了 **部分** 的修复,但是它没有强制要求在任何场景下都使用它,因此你无法预料你将会遇到什么坑。
ES2015 改变了这一切,因为 `import` 与 `export` 就是语言规范本身的一部分。在未来,不再会有现在这种模棱两可的情况,所有东西都将更加无缝地配合工作。不幸的是,由于大多数浏览器和 Node 还不支持 `import` 和 `export`,我们仍然需要依靠 UMD 规范(如果你只写 Node 的话也可以用 CommonJS)。
-现在给你的库的 package.json 文件增加一个 `"module": "dist/my-library.es.js"` 入口,可以让你的库同时支持 UMD 与 ES2015。**这很重要,因为 Webpack 和 Rollup 都使用了 ** `pkg.module` ** 来尽可能的生成效率更高的代码**——在一些情况下,它们都能使用 [tree-shake](https://webpack.js.org/guides/tree-shaking/) 来精简掉你的库中未使用的部分。
+现在给你的库的 package.json 文件增加一个 `"module": "dist/my-library.es.js"` 入口,可以让你的库同时支持 UMD 与 ES2015。**这很重要,因为 Webpack 和 Rollup 都使用了 `pkg.module` 来尽可能的生成效率更高的代码**——在一些情况下,它们都能使用 [tree-shake](https://webpack.js.org/guides/tree-shaking/) 来精简掉你的库中未使用的部分。
*了解更多有关 `pkg.module` 的内容请访问 [Rollup wiki](https://github.com/rollup/rollup/wiki/pkg.module) 。*
From b4d215686cd9c950fd952a64b27468bc6a75d4b8 Mon Sep 17 00:00:00 2001
From: zhouzihanntu
Date: Mon, 10 Apr 2017 15:09:31 +0800
Subject: [PATCH 099/638] =?UTF-8?q?=E6=A0=B9=E6=8D=AE=E7=AC=AC=E4=BA=8C?=
=?UTF-8?q?=E4=BD=8D=E6=A0=A1=E5=AF=B9=E8=80=85=E6=84=8F=E8=A7=81=E4=BF=AE?=
=?UTF-8?q?=E6=94=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
...modules-in-node-js-everything-you-need-to-know.md | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/TODO/requiring-modules-in-node-js-everything-you-need-to-know.md b/TODO/requiring-modules-in-node-js-everything-you-need-to-know.md
index d48fe1071ac..afdf951dfad 100644
--- a/TODO/requiring-modules-in-node-js-everything-you-need-to-know.md
+++ b/TODO/requiring-modules-in-node-js-everything-you-need-to-know.md
@@ -15,9 +15,9 @@ Node 提供了两个核心模块来管理模块依赖:
- `require` 模块在全局范围内可用,不需要写 `require('require')`.
- `module` 模块同样在全局范围内可用,不需要写 `require('module')`.
-你可以将 `require` 模块理解为命令,将 `module` 模块理解为所有必要模块的组织者。
+你可以将 `require` 模块理解为命令,将 `module` 模块理解为所有引入模块的组织者。
-在 Node 中引入一个模块其实并没有想象中的那么复杂。
+在 Node 中引入一个模块其实并不是个多么复杂的概念。
```
const config = require('/path/to/file');
@@ -29,7 +29,7 @@ const config = require('/path/to/file');
- **加载**:确定文件内容的类型。
- **打包**:为文件划分私有作用域,这样 `require` 和 `module` 两个对象对于我们要引入的每个模块来说就都是本地的。
- **评估**:最后由虚拟机对加载得到的代码做评估。
-- **缓存**:当再次引用该文件时,无需再重复以上所有步骤。
+- **缓存**:当再次引用该文件时,无需再重复以上步骤。
在本文中,我将尝试举例说明这些不同阶段的工作原理,以及它们是如何影响我们在 Node 中编写模块的方式的。
@@ -62,7 +62,7 @@ Module {
Node 模块与文件系统中的文件有着一对一的关系。我们通过加载模块对应的文件内容到内存中来实现模块引用。
-然而,由于 Node 允许使用许多方式引入文件(例如,使用相对路径或预先配置的路径),我们需要在将文件的内容加载到内存前找到该文件的绝对位置。
+然而,由于 Node 允许使用多种方式引入文件(例如,使用相对路径或预先配置的路径),我们需要在将文件的内容加载到内存前找到该文件的绝对位置。
例如,我们不声明路径,直接引入一个 `'find-me'` 模块时:
@@ -389,7 +389,7 @@ fs.readFile('/etc/passwd', (err, data) => {
我们现在来回答关于 Node 中循环依赖的重要问题:当我们在模块1中引用模块2,在模块2中引用模块1时会发生什么?
-为了找到答案,我们在 `lib/` 下创建 `module1.js` 和 `module.js` 两个文件并让它们互相引用:
+为了找到答案,我们在 `lib/` 下创建 `module1.js` 和 `module2.js` 两个文件并让它们互相引用:
```
// lib/module1.js
@@ -643,7 +643,7 @@ if (require.main === module) {
}
```
-所以我们可以使用这个条件来满足以上的使用需求,通过不同的方式调用 printInFrame 函数。
+所以我们可以使用该条件判断来满足上述使用需求,通过不同的方式调用 printInFrame 函数。
```
// 在 print-in-frame.js 中
From 63a5a48054b1f5fcaf5cce5c283d554209bd2b19 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=A0=B9=E5=8F=B7=E4=B8=89?=
Date: Mon, 10 Apr 2017 15:15:42 +0800
Subject: [PATCH 100/638] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=8E=88=E6=9D=83?=
=?UTF-8?q?=E4=BF=A1=E6=81=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
...bpack-bits-getting-the-most-out-of-the-commonschunkplugin.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/TODO/webpack-bits-getting-the-most-out-of-the-commonschunkplugin.md b/TODO/webpack-bits-getting-the-most-out-of-the-commonschunkplugin.md
index cd003ab1e9f..21e2cff04aa 100644
--- a/TODO/webpack-bits-getting-the-most-out-of-the-commonschunkplugin.md
+++ b/TODO/webpack-bits-getting-the-most-out-of-the-commonschunkplugin.md
@@ -1,5 +1,5 @@
> * 原文地址:[webpack bits: Getting the most out of the CommonsChunkPlugin()](https://medium.com/webpack/webpack-bits-getting-the-most-out-of-the-commonschunkplugin-ab389e5f318#.hn8v7ul1f)
-> * 原文作者:[Sean T. Larkin](https://medium.com/@TheLarkInn?source=post_header_lockup)
+> * 原文作者:本文已获原作者 [Sean T. Larkin](https://medium.com/@TheLarkInn) 授权
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
> * 译者:[reid3290](https://github.com/reid3290)
> * 校对者:
From 2421f9334d1b28b4b0232bca842b3a35542d943b Mon Sep 17 00:00:00 2001
From: zhouzihanntu
Date: Mon, 10 Apr 2017 15:37:42 +0800
Subject: [PATCH 101/638] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=A0=A1=E5=AF=B9?=
=?UTF-8?q?=E8=80=85=E4=BF=A1=E6=81=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../requiring-modules-in-node-js-everything-you-need-to-know.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/TODO/requiring-modules-in-node-js-everything-you-need-to-know.md b/TODO/requiring-modules-in-node-js-everything-you-need-to-know.md
index afdf951dfad..d160796cd96 100644
--- a/TODO/requiring-modules-in-node-js-everything-you-need-to-know.md
+++ b/TODO/requiring-modules-in-node-js-everything-you-need-to-know.md
@@ -2,7 +2,7 @@
> * 原文作者:[Samer Buna](https://medium.freecodecamp.com/@samerbuna?source=post_header_lockup)
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
> * 译者:[zhouzihanntu](https://github.com/zhouzihanntu)
-> * 校对者:[lsvih](https://github.com/lsvih)
+> * 校对者:[lsvih](https://github.com/lsvih), [reid3290](https://github.com/reid3290)
# 关于在 Node.js 中引用模块,知道这些就够了 #
From 9fb579dbd77e063247690279625b8b49a0b3367a Mon Sep 17 00:00:00 2001
From: DeepMissea <398752853@qq.com>
Date: Mon, 10 Apr 2017 15:53:10 +0700
Subject: [PATCH 102/638] =?UTF-8?q?=E6=A0=B9=E6=8D=AE=E4=B8=A4=E4=BD=8D?=
=?UTF-8?q?=E6=A0=A1=E5=AF=B9=E8=80=85=E7=9A=84=E6=84=8F=E8=A7=81=E4=BF=AE?=
=?UTF-8?q?=E6=94=B9=E3=80=82?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
TODO/mvvmc-with-swift.md | 38 +++++++++++++++++++-------------------
1 file changed, 19 insertions(+), 19 deletions(-)
diff --git a/TODO/mvvmc-with-swift.md b/TODO/mvvmc-with-swift.md
index 0e68011078c..01134ab233a 100644
--- a/TODO/mvvmc-with-swift.md
+++ b/TODO/mvvmc-with-swift.md
@@ -12,18 +12,18 @@
# 简介
-现今,iOS 开发者面临的最大挑战是构建一个健壮应用程序,它必须易于维护、测试和扩展。
+现今,iOS 开发者面临的最大挑战是构建一个健壮的应用程序,它必须易于维护、测试和扩展。
在这篇文章里,你会学到一种可靠的方法来达到目的。
-首先,需要简介一下你即将学习的内容:
+首先,简要介绍下你即将学习的内容:
**架构模式**.
# 架构模式
## 它是什么
-> 架构模式是给定上下文中软件体系结构中常见的,可重用的解决方案。架构与软件设计模式相似,但作用范围更广。架构解决了软件工程中的各种问题,如计算机硬件性能限制,高可用性和最小化业务风险。一些架构模式已经在软件框架内实现。
+> 架构模式是给定上下文中软件体系结构中常见的,可重用的解决方案。架构与软件设计模式相似,但涉及的范围更广。架构解决了软件工程中的各种问题,如计算机硬件性能限制,高可用性和最小化业务风险。一些架构模式已经在软件框架内实现。
摘自 [Wikipedia](https://en.wikipedia.org/wiki/Architectural_pattern)。
@@ -31,31 +31,31 @@
## 主要的模式
-在项目中,有几种可用的架构模式,并且你可以在项目中使用多个,因为每个模式都能高好的适应特定的场景。
+在项目中,有几种可用的架构模式,并且你可以在项目中使用多个,因为每个模式都能更好地适应特定的场景。
-当你阅读关于这几种模式时,主要会遇到这种:
+当你阅读这几种模式时,主要会遇到:
### [Model-View-Controller](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller)
![](https://marcosantadev.com/wp-content/uploads/mvc_2.jpg)
-这是最常见的,也许在你的第一个 iOS 应用中已经使用过。不幸地是,这也是最糟糕的模式,因为 `Controller` 不得不管理每一个依赖(API、数据库等等),包括你应用的业务逻辑,而且与 `UIKit` 的耦合度很高,这意味着测试异常的艰难。
+这是最常见的,也许在你的第一个 iOS 应用中已经使用过。不幸地是,这也是最糟糕的模式,因为 `Controller` 不得不管理每一个依赖(API、数据库等等),包括你应用的业务逻辑,而且与 `UIKit` 的耦合度很高,这意味着很难去测试。
-你通常会避免这种模式,用下面的某种来代替它。
+你应该避免这种模式,用下面的某种来代替它。
### [Model-View-Presenter](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93presenter)
![](https://marcosantadev.com/wp-content/uploads/mvp.jpg)
-这是第一个 MVC 的替代方案之一,一次对 `Controller` 和 `View` 之间解耦的很好的尝试。
+这是第一个 MVC 模式的备选方案之一,一次对 `Controller` 和 `View` 之间解耦的很好的尝试。
-在 MVP 中,你有一层叫做 `Presenter` 的新结构来处理业务逻辑。而 `View` —— 你的 `UIViewController` 以及任何 `UIKit` 组件,都是一个笨的对象,他们只通过 `Presenter` 更新,并在触发 UI 事件的时候,负责通知 `Presenter`。由于 `Presenter` 没有任何 `UIKit` 的引用,所以非常容易测试。
+在 MVP 中,你有一层叫做 `Presenter` 的新结构来处理业务逻辑。而 `View` —— 你的 `UIViewController` 以及任何 `UIKit` 组件,都是一个笨的对象,他们只通过 `Presenter` 更新,并在 UI 事件被触发的时候,负责通知 `Presenter`。由于 `Presenter` 没有任何 `UIKit` 的引用,所以非常容易测试。
### [Viper](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93presenter)
[![](https://www.objc.io/images/issue-13/2014-06-07-viper-intro-0a53d9f8.jpg)](https://www.objc.io/issues/13-architecture/viper/)
-这是 [Bob 叔叔清晰架构](https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-architecture.html)的代表。
+这是 [Bob 叔叔的清晰架构](https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-architecture.html)的代表。
这种模式的强大之处在于,它合理分配了不同层次之间的职责。通过这种方式,你的每个层次做的的事变得很少,易于测试,并且具备单一职责。这种模式的问题是,在大多数场合里,它过于复杂。你需要管理很多层,这会让你感到混乱,难于管理。
@@ -65,7 +65,7 @@
![](https://marcosantadev.com/wp-content/uploads/mvvm.jpg)
-最后但也是最重要的,MVVM 是一个类似于 MVP 的框架,因为层次看几乎相同。你可以认为 MVVM 是 MVP 版本的一个进化,而这得益于 UI 绑定。
+最后但也是最重要的,MVVM 是一个类似于 MVP 的框架,因为层级结构几乎相同。你可以认为 MVVM 是 MVP 版本的一个进化,而这得益于 UI 绑定。
UI 绑定是在 `View` 和 `ViewModel` 之间建立一座单向或双向的桥梁,并且两者之间以一种非常透明地方式进行沟通。
@@ -73,7 +73,7 @@ UI 绑定是在 `View` 和 `ViewModel` 之间建立一座单向或双向的桥
在 Swift 里有多种方式实现 UI 绑定:
-#### RxSwift (or ReactiveCocoa)
+#### RxSwift (或 ReactiveCocoa)
[RxSwift](https://github.com/ReactiveX/RxSwift) 是 [ReactiveX](http://reactivex.io/) 家族的一个 Swift 版本的实现。一旦你掌握了它,你就能很轻松地切换到 RxJava、RxJavascript 等等。
@@ -97,7 +97,7 @@ class ViewController: UIViewController {
我不会解释如何彻底地使用 RxSwift,因为这超出本文的目标,它自己会有文章来解释。
-FRP 让你学习到了一种新的方式来开发,你可能对它或爱或恨。如果你没用过 FRP 开发,那你不得不花费几小时的时间来使用,并理解如何正确的使用,因为它是一个完全不同的编程概念。
+FRP 让你学习到了一种新的方式来开发,你可能对它或爱或恨。如果你没用过 FRP 开发,那你需要花费几个小时来熟悉和理解如何正确地使用它,因为它是一个完全不同的编程概念。
另一个类似于 RxSwift 的框架是 [ReactiveCocoa](https://github.com/ReactiveCocoa/ReactiveCocoa),如果你想了解他们之间主要的区别的话,你可以看看[这篇文章](https://www.raywenderlich.com/126522/reactivecocoa-vs-rxswift)。
@@ -211,7 +211,7 @@ class ViewModel {
## 抉择: MVVM-C
-在你不得不选择一个架构模式时,你需要理解哪一种更适合你的需求。在这些模式里,MVVM 是最好的选择,因为它强大的同时,也易于使用。
+在你不得不选择一个架构模式时,你需要理解哪一种更适合你的需求。在这些模式里,MVVM 是最好的选择之一,因为它强大的同时,也易于使用。
不幸地是这种模式并不完美,主要的缺陷是 MVVM 没有路由管理。
@@ -225,7 +225,7 @@ class ViewModel {
你可以在[这里](https://github.com/MarcoSantarossa/MVVM-C_with_Swift)下载项目源码。
-这些类被简化了,以便于你可以专注于 MVVM-C 是如何工作的,因此 GitHub 上的类可能会有轻微出入。
+这个例子被简化了,以便于你可以专注于 MVVM-C 是如何工作的,因此 GitHub 上的类可能会有轻微出入。
示例应用是一个普通的仪表盘应用,它从公共 API 获取数据,一旦数据准备就绪,用户就可以通过 ID 查找实体,如下面的截图:
@@ -294,7 +294,7 @@ final class DashboardContainerCoordinator: Coordinator {
}
```
-你一定能注意到在 `Coordinator` 里,一个父类 `UIViewController` 对象或者子类对象,类似于 `UINavigationController`,被注入到构造器之中。因为 `Coordinator` 有责任添加 `View` 到视图层级之中,它必须知道那个父类添加了 `View`。
+你一定能注意到在 `Coordinator` 里,一个父类 `UIViewController` 对象或者子类对象,比如 `UINavigationController`,被注入到构造器之中。因为 `Coordinator` 有责任添加 `View` 到视图层级之中,它必须知道那个父类添加了 `View`。
在上面的例子里,`DashboardContainerCoordinator` 实现了协议 `Coordinator`:
@@ -337,7 +337,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
在 `AppDelegate` 里,我们实例化一个新的 `DashboardContainerCoordinator`,通过 `start` 方法,我们把新的视图推入 `navigationController` 里。
-**你可以看到 GitHub 项目如何注入一个 `UINavigationController` 类型的对象,并去除 `UIKit` 和 `Coordinator` 之间的耦合。**
+**你可以看到在 GitHub 上的项目是如何注入一个 `UINavigationController` 类型的对象,并去除 `UIKit` 和 `Coordinator` 之间的耦合。**
### Model
@@ -450,7 +450,7 @@ final class UsersViewModel {
MVVM-C 有很多优点,可以提高应用程序的质量。你应该注意使用哪种方式来进行 UI 绑定,因为 RxSwift 不容易掌握,而且如果你不明白你做的是什么,调试和测试有时可能会有点棘手。
-我的建议是一点点地开始使用这种架构模式,这样你可以对不同的层次得到使用,并且能保证层次之间的良好的分离,易于测试。
+我的建议是一点点地开始使用这种架构模式,这样你可以学习不同层次的使用,并且能保证层次之间的良好的分离,易于测试。
# FAQ
@@ -466,7 +466,7 @@ MVVM-C 有很多优点,可以提高应用程序的质量。你应该注意使
这取决于你要开新项目,还是要维护旧代码。在有遗留代码的项目中,你可能无法使用 RxSwift,因为你需要重构很多的类。如果你有时间和资源来做,我建议你新开一项目一点一点的做,否则还是尝试其他的方法来解决 UI 绑定的问题。
-需要考虑的一个重要事情是,RxSwift 会一直是你项目中的另一个依赖,你可能会因为 RxSwift 的突破性改动而导致浪费时间的风险,或者缺少要在边缘案例中实现功能的文档。
+需要考虑的一个重要事情是,RxSwift 最终会成为你项目中的另一个依赖,你可能会因为 RxSwift 的破坏性改动而导致浪费时间的风险,或者缺少要在边缘案例中实现功能的文档。
---
From 575abaa19e6fc5bf58452a64699a00e0d62bf6fa Mon Sep 17 00:00:00 2001
From: DeepMissea <398752853@qq.com>
Date: Mon, 10 Apr 2017 15:55:20 +0700
Subject: [PATCH 103/638] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=A0=A1=E5=AF=B9?=
=?UTF-8?q?=E8=80=85=E3=80=82?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
TODO/mvvmc-with-swift.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/TODO/mvvmc-with-swift.md b/TODO/mvvmc-with-swift.md
index 01134ab233a..eb77db7fd87 100644
--- a/TODO/mvvmc-with-swift.md
+++ b/TODO/mvvmc-with-swift.md
@@ -2,7 +2,7 @@
> * 原文作者:[Marco Santarossa](https://marcosantadev.com/)
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
> * 译者:[Deepmissea](http://deepmissea.blue)
-> * 校对者:
+> * 校对者:[atuooo](http://atuo.xyz),[1992chenlu](https://github.com/1992chenlu)
---
From 59b306ee920a7a4ffa66bb66396b88012751398f Mon Sep 17 00:00:00 2001
From: reid
Date: Mon, 10 Apr 2017 17:45:38 +0800
Subject: [PATCH 104/638] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=A0=A1=E5=AF=B9?=
=?UTF-8?q?=E8=80=85=E4=BF=A1=E6=81=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
...bpack-bits-getting-the-most-out-of-the-commonschunkplugin.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/TODO/webpack-bits-getting-the-most-out-of-the-commonschunkplugin.md b/TODO/webpack-bits-getting-the-most-out-of-the-commonschunkplugin.md
index cd003ab1e9f..e9b092a47c2 100644
--- a/TODO/webpack-bits-getting-the-most-out-of-the-commonschunkplugin.md
+++ b/TODO/webpack-bits-getting-the-most-out-of-the-commonschunkplugin.md
@@ -2,7 +2,7 @@
> * 原文作者:[Sean T. Larkin](https://medium.com/@TheLarkInn?source=post_header_lockup)
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
> * 译者:[reid3290](https://github.com/reid3290)
-> * 校对者:
+> * 校对者:[avocadowang](https://github.com/avocadowang),[Aladdin-ADD](https://github.com/Aladdin-ADD)
# webpack 拾翠:充分利用 CommonsChunkPlugin() #
From 961859c7975344537dd677404afe6b0a67fb74b1 Mon Sep 17 00:00:00 2001
From: tanglie
Date: Mon, 10 Apr 2017 22:07:05 +0800
Subject: [PATCH 105/638] Update Dependency-Injection-with-Dagger-2.md
---
TODO/Dependency-Injection-with-Dagger-2.md | 26 +++++++++++-----------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/TODO/Dependency-Injection-with-Dagger-2.md b/TODO/Dependency-Injection-with-Dagger-2.md
index e36788e6667..304ecaf4d00 100644
--- a/TODO/Dependency-Injection-with-Dagger-2.md
+++ b/TODO/Dependency-Injection-with-Dagger-2.md
@@ -2,17 +2,17 @@
> * 原文作者:[CodePath](https://github.com/codepath)
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
> * 译者: [tanglie1993](https://github.com/tanglie1993)
-> * 校对者:
+> * 校对者:[mnikn](https://github.com/mnikn), [Zhiw](https://github.com/Zhiw)
# 用 Dagger 2 实现依赖注入
## 概要
-很多 Android 应用依赖于一些含有其它依赖的对象。例如,一个 Twitter API 客户端可能需要通过 [Retrofit](https://github.com/codepath/android_guides/wiki/Consuming-APIs-with-Retrofit) 之类的网络库被构建。要使用这个库,你可能还需要添加 [Gson](https://github.com/codepath/android_guides/wiki/Leveraging-the-Gson-Library) 这样的解析库。另外,实现认证或缓存的库可能需要使用 [shared preferences](https://github.com/codepath/android_guides/wiki/Storing-and-Accessing-SharedPreferences) 或其它通用存储方式。这就需要先把它们实例化,并创建一个隐含的依赖链。
+很多 Android 应用依赖于一些含有其它依赖的对象。例如,一个 Twitter API 客户端可能需要通过 [Retrofit](https://github.com/codepath/android_guides/wiki/Consuming-APIs-with-Retrofit) 之类的网络库来构建。要使用这个库,你可能还需要添加 [Gson](https://github.com/codepath/android_guides/wiki/Leveraging-the-Gson-Library) 这样的解析库。另外,实现认证或缓存的库可能需要使用 [shared preferences](https://github.com/codepath/android_guides/wiki/Storing-and-Accessing-SharedPreferences) 或其它通用存储方式。这就需要先把它们实例化,并创建一个隐含的依赖链。
如果你不熟悉依赖注入,看看[这个](https://www.youtube.com/watch?v=IKD2-MAkXyQ)短视频。
-Dagger 2 为你解析这些依赖,并生成把它们绑定在一起的代码。也有很多其它的 Java 依赖注入框架,但它们中很多个是有缺陷的,比如依赖 XML,需要在运行时验证依赖,或者在起始时造成性能负担。 [Dagger 2](http://google.github.io/dagger/) 纯粹依赖于 Java [注解解析器](https://www.youtube.com/watch?v=dOcs-NKK-RA)以及编译时检查来分析并验证依赖。它被认为是目前最高效的依赖注入框架之一。
+Dagger 2 为你解析这些依赖,并生成把它们绑定在一起的代码。也有很多其它的 Java 依赖注入框架,但它们中大多数是有缺陷的,比如依赖 XML,需要在运行时验证依赖,或者在起始时造成性能负担。 [Dagger 2](http://google.github.io/dagger/) 纯粹依赖于 Java [注解解析器](https://www.youtube.com/watch?v=dOcs-NKK-RA)以及编译时检查来分析并验证依赖。它被认为是目前最高效的依赖注入框架之一。
### 优点
@@ -31,7 +31,7 @@ public class MainActivity extends Activity {
}
```
- * **容易配置复杂的依赖**。 对象创建是有隐含顺序的。Dagger 2 浏览依赖图,并且[生成易于理解和追踪的代码](https://github.com/codepath/android_guides/wiki/Dependency-Injection-with-Dagger-2#code-generation)。而且,它可以节约大量的样板代码,使你不再需要手写,手动获取引用并把它们传递给其他对象作为依赖。它也简化了重构,因为你可以聚焦于构建模块本身,而不是它们被创建的顺序。
+ * **容易配置复杂的依赖关系**。 对象创建是有隐含顺序的。Dagger 2 遍历依赖关系图,并且[生成易于理解和追踪的代码](https://github.com/codepath/android_guides/wiki/Dependency-Injection-with-Dagger-2#code-generation)。而且,它可以节约大量的样板代码,使你不再需要手写,手动获取引用并把它们传递给其他对象作为依赖。它也简化了重构,因为你可以聚焦于构建模块本身,而不是它们被创建的顺序。
* **更简单的单元和集成测试** 因为依赖图是为我们创建的,我们可以轻易换出用于创建网络响应的模块,并模拟这种行为。
@@ -41,7 +41,7 @@ public class MainActivity extends Activity {
默认的 Android Studio 不把生成的 Dagger 2 代码视作合法的类,因为它们通常并不被加入 source 路径。但引入 `android-apt` 插件后,它会把这些文件加入 IDE classpath,从而提供更好的可见性。
-确保[升级](https://github.com/codepath/android_guides/wiki/Getting-Started-with-Gradle#upgrading-gradle) 到最迟的 Gradle 版本以使用最新的 `annotationProcessor` 语法:
+确保[升级](https://github.com/codepath/android_guides/wiki/Getting-Started-with-Gradle#upgrading-gradle) 到最新的 Gradle 版本以使用最新的 `annotationProcessor` 语法:
```gradle
dependencies {
@@ -202,7 +202,7 @@ public interface NetComponent {
#### 生成代码
-Dagger 2 的一个重要特点是它会为标注 `@Component` 的接口生成类的代码。你可以使用带有 `Dagger` (比如 `DaggerTwitterApiComponent.java`) 前缀的类来为依赖图提供实例,并用它来完成用 `@Inject` 注解的域的注入。 参见[[setup guide|Dependency-Injection-with-Dagger-2#setup]]。
+Dagger 2 的一个重要特点是它会为标注 `@Component` 的接口生成类的代码。你可以使用带有 `Dagger` (比如 `DaggerTwitterApiComponent.java`) 前缀的类来为依赖图提供实例,并用它来完成用 `@Inject` 注解的域的注入。 参见[设置](https://github.com/xitu/gold-miner/pull/1484#%E8%AE%BE%E7%BD%AE)。
### 实例化组件
@@ -382,7 +382,7 @@ public interface GitHubComponent {
}
```
-假定 Github 模块只是把 API 接口返回给 github API:
+假定 Github 模块只是把 API 接口返回给 Github API:
```java
@@ -417,7 +417,7 @@ public interface NetComponent {
}
```
-最终的步骤是用 `GitHubComponent` 进行实例化。这一次,我们需要首先实现 `NetComponent` 并把它传递给 `DaggerGitHubComponent` 建造者的构造方法:
+最终的步骤是用 `GitHubComponent` 进行实例化。这一次,我们需要首先实现 `NetComponent` 并把它传递给 `DaggerGitHubComponent` builder 的构造方法:
```java
NetComponent mNetComponent = DaggerNetComponent.builder()
@@ -498,12 +498,12 @@ public class MyActivity extends Activity {
}
```
-#### 子组件建造者
+#### 子组件 builder
*从 v2.7 版本起可用*
-![Dagger 子组件建造者](https://raw.githubusercontent.com/codepath/android_guides/master/images/subcomponent_builders.png)
+![Dagger 子组件 builder](https://raw.githubusercontent.com/codepath/android_guides/master/images/subcomponent_builders.png)
-子组件建造者使创建子组件的类和子组件的父类解耦。这是通过移除父组件中的子组件工厂方法实现的。
+子组件 builder 使创建子组件的类和子组件的父类解耦。这是通过移除父组件中的子组件工厂方法实现的。
```java
@MyActivityScope
@@ -521,7 +521,7 @@ public interface SubcomponentBuilder {
}
```
-子组件是在子组件接口内部的接口中声明的。它必须含有一个 `build()` 方法,其返回值和子组件相匹配。用这个方法声明一个基接口是很方便的,就像上面的`SubcomponentBuilder` 一样。这个新的**建造者必须被加入父组件的图中**,而这是用一个 "binder" 模块和一个 "subcomponents" 参数实现的:
+子组件是在子组件接口内部的接口中声明的。它必须含有一个 `build()` 方法,其返回值和子组件相匹配。用这个方法声明一个基接口是很方便的,就像上面的`SubcomponentBuilder` 一样。这个新的 **builder 必须被加入父组件的图中**,而这是用一个 "binder" 模块和一个 "subcomponents" 参数实现的:
```java
@Module(subcomponents={ MyActivitySubComponent.class })
@@ -544,7 +544,7 @@ public @interface SubcomponentKey {
}
```
-一旦建造者在出现在组件图中,activity 就可以用它来创建子组件:
+一旦 builder 在出现在组件图中,activity 就可以用它来创建子组件:
```java
public class MyActivity extends Activity {
From b5bc496940ed9f61b97ec13d0c21fd9844045b84 Mon Sep 17 00:00:00 2001
From: Tuccuay
Date: Mon, 10 Apr 2017 22:31:50 +0800
Subject: [PATCH 106/638] quote
---
TODO/mastering-swift-essential-details-about-strings.md | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/TODO/mastering-swift-essential-details-about-strings.md b/TODO/mastering-swift-essential-details-about-strings.md
index 325223b5681..1abd697d093 100644
--- a/TODO/mastering-swift-essential-details-about-strings.md
+++ b/TODO/mastering-swift-essential-details-about-strings.md
@@ -541,4 +541,6 @@ print(numberOfStars) // => 2
**对于字符操作你有没有找到更舒适的方法?写下评论我们一起来讨论一些吧!**
-**P.S.** 不知道你有没有兴趣阅读我的另一篇文章:[detailed overview of array and dictionary literals in Swift](https://rainsoft.io/concise-initialization-of-collections-in-swift/)
\ No newline at end of file
+**P.S.** 不知道你有没有兴趣阅读我的另一篇文章:[detailed overview of array and dictionary literals in Swift](https://rainsoft.io/concise-initialization-of-collections-in-swift/)
+
+>[掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[React](https://github.com/xitu/gold-miner#react)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计) 等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)。
\ No newline at end of file
From 6b3ffdc1a0481ea0e9aa9cde2298129ac52041cf Mon Sep 17 00:00:00 2001
From: zhuzi
Date: Mon, 10 Apr 2017 22:50:34 +0800
Subject: [PATCH 107/638] update according to proof-reading
---
TODO/beyond-browser-web-desktop-apps.md | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/TODO/beyond-browser-web-desktop-apps.md b/TODO/beyond-browser-web-desktop-apps.md
index 9803dd3b2c6..1899ee8f1d9 100644
--- a/TODO/beyond-browser-web-desktop-apps.md
+++ b/TODO/beyond-browser-web-desktop-apps.md
@@ -2,7 +2,7 @@
> * 原文作者:本文已获原作者 [Adam Lynch](https://www.smashingmagazine.com/author/adamlynch/) 授权
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
> * 译者: [bambooom](https://github.com/bambooom)/[imink](https://github.com/imink)
-> * 校对者:[bambooom](https://github.com/bambooom)/[sunui](https://github.com/sunui)
+> * 校对者:[bambooom](https://github.com/bambooom)/[imink](https://github.com/imink)/[sunui](https://github.com/sunui)
## 超越浏览器:从 web 应用到桌面应用
@@ -12,7 +12,7 @@
别慌,深呼吸,现实情况是,作为 web 开发者,你已经拥有开发现代桌面应用所需的一切技能,得益于新的强大的 API,你甚至可以在桌面应用中发挥你最大的潜能。
-本文将会介绍使用 [NW.js](http://nwjs.io/) 和 [Electron](https://electron.atom.io/) 开发桌面应用,它们的优劣,使用同一套代码库给桌面、web,甚至更多。
+本文将会介绍使用 [NW.js](http://nwjs.io/) 和 [Electron](https://electron.atom.io/) 开发桌面应用,包括它们的优劣,以及如何使用同一套代码库来开发桌面、web 应用,甚至更多。
### 为什么?
@@ -22,7 +22,7 @@
很难总结为什么你应该考虑开发桌面应用,因为真的有很多类型的应用你可以创建。这非常取决于你想要达到什么目的,API 是否足够有利于开发,离线使用将多大程度上增强用户体验。在我的团队,这些都是毋庸置疑的,因为我们在开发一个[聊天应用程序](https://teamwork.com/chat)。另一方面来说,一个依赖于网络而没有任何与系统集成的桌面应用应该做成一个 web 应用,并且只做 web 应用。当用户并不能从桌面应用中获得比在浏览器中访问一个网址更多的价值的时候,期待用户下载你的应用(其中自带浏览器以及 Node.js)是不公平的。
-比起描述你个人应该建造的桌面应用及其原因,我更希望的是激发一个想法,或者只是激发你对这篇文章的兴趣。继续往下读来看看用 web 技术构造一个强大的桌面应用是多么简单,以及创建完成(或者在这过程中)一个 web 应用你需要承受什么。。
+比起描述你个人应该建造的桌面应用及其原因,我更希望的是激发一个想法,或者只是激发你对这篇文章的兴趣。继续往下读来看看用 web 技术构造一个强大的桌面应用是多么简单,以及在创建过程中你应该付出什么。
### NW.js
@@ -81,7 +81,7 @@ Chromium 有一个主要的后台进程,每个标签页也会有自己的进
就是这么简单。NW.js 初始化了第一个窗口,加载了你的 HTML 文件,虽然这看起来并没有什么,但接下来就是你来添加标签及样式了,就和在 web 应用中一样。
-你可以凭自己喜好去掉窗口栏,构建自己的框架模板。你可以有半透明或全透明的窗口,可以有隐藏窗口或者更多。我最近试了一下用 NW.js 复活了[回形针](http://engineroom.teamwork.com/resurrecting-clippy/) Office 助手(一般昵称 Clippy)。能看到它同时在 macOS 或者 Windows 10 中复活有种奇妙的满足感。
+你可以凭自己喜好去掉窗口栏,构建自己的框架模板。你可以有半透明或全透明的窗口,可以有隐藏窗口或者更多。我最近尝试使用 NW.js 做了[Clippy](http://engineroom.teamwork.com/resurrecting-clippy/)(Office 助手)。能在 macOS 和 Windows 10 上看到它有种奇妙的满足感。
![Screenshot of clippy.desktop on macOS](https://www.smashingmagazine.com/wp-content/uploads/2017/01/clippy-preview-opt.png)
@@ -217,11 +217,11 @@ NW.js 和 Electron 都支持很多平台,包括 Windows,Mac 和 Linux。Elec
Electron 甚至支持 ARM 版本,所以你的 app 可以在 Chromebook 或者树莓派上运行,最终,Google 可能会[逐步淘汰 Chrome 封装应用 (Packaged App)](https://blog.chromium.org/2016/08/from-chrome-apps-to-web.html),但是 NW.js 仍然支持将应用程序移植到 NW.js 应用,并且仍然可以访问相同的 Chromium API。
-虽然 32 位和 64 位的版本都支持,你也可以使用 64 位的 Mac 和 Windows 应用。但是,为了兼容,32 位和 64 位 Linux 应用程序是都需要的。
+虽然 32 位和 64 位的版本都支持,所以你完全可以使用 64 位的 Mac 和 Windows 应用。但是,为了兼容,32 位和 64 位 Linux 应用程序是都需要的。
假如 Electron 胜出,你想发行一个 Electron 应用。有一个很不错的 Node.js 包叫 [electron-packager](https://github.com/electron-userland/electron-packager) 可以帮你将 app 打包成一个 `.app` 或者 `.exe` 文件。也有其他几个类似的项目,包括交互式的一步一步告诉你该怎么做。不过,你应该用 [electron-builder](https://github.com/electron-userland/electron-builder),它以 electron-packager 为基础,添加了其他几个相关的模块,生成的是 `.dmg` 文件和 Windows 安装包,并且为你处理好了代码签名的问题。这很重要,如果没有这一步,你的应用将会被操作系统认为是不可信的,你的应用程序可能会触发防毒软件的运行,Microsoft SmartScreen 可能会尝试阻止用户启动你的应用。
-关于代码签名的令人讨厌的事情是,你必须在 Mac 上为 Mac 和 Windows 上为 Windows 签署你的应用程序。因此,如果是认真要发行桌面应用的话,就需要为每个发行版本给多种机器构建。
+关于代码签名的令人讨厌的事情是,你必须单独为某个平台签名你的应用程序,比如在 Mac 上签名 Mac 应用,在 Windows 签名 Windows 应用。因此,如果你很在乎发行桌面应用的话,就必须为每个发行版本分别构建适用于不同平台的应用(以及分别签名)。
这可能会感到不够自动化很繁琐,特别是如果你习惯于在 web 上创建。幸运的是,electron-builder 被创造出来完成这些自动化工作。我说的是持续集成工具例如 [Jenkins](https://jenkins.io/),[CodeShip](http://codeship.com/),[Travis-CI](https://travis-ci.org/),[AppVeyor](https://www.appveyor.com/)(Windows 集成)等。这些工具可以让你按一个按钮或者每次更新代码到 GitHub 时重新构建你的桌面应用。
From 0e05d37cf28db7bc0282e66922aa56d1588ce5c7 Mon Sep 17 00:00:00 2001
From: sqrthree
Date: Mon, 10 Apr 2017 23:04:02 +0800
Subject: [PATCH 108/638] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20Preload=EF=BC=8CPr?=
=?UTF-8?q?efetch=20=E5=92=8C=E5=AE=83=E4=BB=AC=E5=9C=A8=20Chrome=20?=
=?UTF-8?q?=E4=B9=8B=E4=B8=AD=E7=9A=84=E4=BC=98=E5=85=88=E7=BA=A7=20?=
=?UTF-8?q?=E7=9A=84=E7=A7=AF=E5=88=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 3 ++-
front-end.md | 1 +
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 066b76a852c..7e89841009a 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
[掘金翻译计划](https://juejin.im/tag/%E6%8E%98%E9%87%91%E7%BF%BB%E8%AF%91%E8%AE%A1%E5%88%92) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](#android)、[iOS](#ios)、[React](#react)、[前端](#前端)、[后端](#后端)、[产品](#产品)、[设计](#设计) 等领域,读者为热爱新技术的新锐开发者。
-掘金翻译计划目前翻译完成 [448](#近期文章列表) 篇文章,共有 [270](https://github.com/xitu/gold-miner/wiki/%E8%AF%91%E8%80%85%E7%A7%AF%E5%88%86%E8%A1%A8) 余名译者贡献翻译。
+掘金翻译计划目前翻译完成 [449](#近期文章列表) 篇文章,共有 [270](https://github.com/xitu/gold-miner/wiki/%E8%AF%91%E8%80%85%E7%A7%AF%E5%88%86%E8%A1%A8) 余名译者贡献翻译。
# 官方指南:
@@ -37,6 +37,7 @@
## 前端
+* [Preload,Prefetch 和它们在 Chrome 之中的优先级](https://juejin.im/post/58e8acf10ce46300585a7a42?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([gy134340](http://gy134340.com/) 翻译)
* [setState() 门事件](https://juejin.im/post/58e5aeccb123db15eb80ecb0?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([reid3290](https://github.com/reid3290) 翻译)
* [如何使用 JavaScript 构建响应式引擎 —— Part 2:计算属性和依赖追踪](https://juejin.im/post/58ddeb1a570c3500579016ef?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([IridescentMia](https://github.com/IridescentMia) 翻译)
* [如何使用 JavaScript 构建响应式引擎 —— Part 1:可观察的对象](https://juejin.im/post/58dc9da661ff4b0061547ca0?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([IridescentMia](https://github.com/IridescentMia) 翻译)
diff --git a/front-end.md b/front-end.md
index e38e54951be..3a2df9cf268 100644
--- a/front-end.md
+++ b/front-end.md
@@ -1,3 +1,4 @@
+* [Preload,Prefetch 和它们在 Chrome 之中的优先级](https://juejin.im/post/58e8acf10ce46300585a7a42?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([gy134340](http://gy134340.com/) 翻译)
* [setState() 门事件](https://juejin.im/post/58e5aeccb123db15eb80ecb0?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([reid3290](https://github.com/reid3290) 翻译)
* [如何使用 JavaScript 构建响应式引擎 —— Part 2:计算属性和依赖追踪](https://juejin.im/post/58ddeb1a570c3500579016ef?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([IridescentMia](https://github.com/IridescentMia) 翻译)
* [如何使用 JavaScript 构建响应式引擎 —— Part 1:可观察的对象](https://juejin.im/post/58dc9da661ff4b0061547ca0?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([IridescentMia](https://github.com/IridescentMia) 翻译)
From 41cb0f72b78d66bde60349afd8257b160f40b9c6 Mon Sep 17 00:00:00 2001
From: sqrthree
Date: Mon, 10 Apr 2017 23:57:52 +0800
Subject: [PATCH 109/638] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20CSS=E5=BE=88?=
=?UTF-8?q?=E6=A3=92=EF=BC=8C=E5=8F=AA=E6=98=AF=E7=9C=9F=E7=9A=84=E5=A4=AA?=
=?UTF-8?q?=E9=9A=BE=E4=BA=86=20=E7=9A=84=E7=A7=AF=E5=88=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 3 ++-
front-end.md | 1 +
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 7e89841009a..c7c8629cecf 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
[掘金翻译计划](https://juejin.im/tag/%E6%8E%98%E9%87%91%E7%BF%BB%E8%AF%91%E8%AE%A1%E5%88%92) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](#android)、[iOS](#ios)、[React](#react)、[前端](#前端)、[后端](#后端)、[产品](#产品)、[设计](#设计) 等领域,读者为热爱新技术的新锐开发者。
-掘金翻译计划目前翻译完成 [449](#近期文章列表) 篇文章,共有 [270](https://github.com/xitu/gold-miner/wiki/%E8%AF%91%E8%80%85%E7%A7%AF%E5%88%86%E8%A1%A8) 余名译者贡献翻译。
+掘金翻译计划目前翻译完成 [450](#近期文章列表) 篇文章,共有 [270](https://github.com/xitu/gold-miner/wiki/%E8%AF%91%E8%80%85%E7%A7%AF%E5%88%86%E8%A1%A8) 余名译者贡献翻译。
# 官方指南:
@@ -37,6 +37,7 @@
## 前端
+* [CSS很棒,只是真的太难了](https://juejin.im/entry/58eae24a61ff4b0061a6a102?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([ZhangFe](https://github.com/ZhangFe) 翻译)
* [Preload,Prefetch 和它们在 Chrome 之中的优先级](https://juejin.im/post/58e8acf10ce46300585a7a42?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([gy134340](http://gy134340.com/) 翻译)
* [setState() 门事件](https://juejin.im/post/58e5aeccb123db15eb80ecb0?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([reid3290](https://github.com/reid3290) 翻译)
* [如何使用 JavaScript 构建响应式引擎 —— Part 2:计算属性和依赖追踪](https://juejin.im/post/58ddeb1a570c3500579016ef?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([IridescentMia](https://github.com/IridescentMia) 翻译)
diff --git a/front-end.md b/front-end.md
index 3a2df9cf268..52e31749ac5 100644
--- a/front-end.md
+++ b/front-end.md
@@ -1,3 +1,4 @@
+* [CSS很棒,只是真的太难了](https://juejin.im/entry/58eae24a61ff4b0061a6a102?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([ZhangFe](https://github.com/ZhangFe) 翻译)
* [Preload,Prefetch 和它们在 Chrome 之中的优先级](https://juejin.im/post/58e8acf10ce46300585a7a42?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([gy134340](http://gy134340.com/) 翻译)
* [setState() 门事件](https://juejin.im/post/58e5aeccb123db15eb80ecb0?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([reid3290](https://github.com/reid3290) 翻译)
* [如何使用 JavaScript 构建响应式引擎 —— Part 2:计算属性和依赖追踪](https://juejin.im/post/58ddeb1a570c3500579016ef?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([IridescentMia](https://github.com/IridescentMia) 翻译)
From 9b8d36b6d710e3bc3411c12a2f9601c984112811 Mon Sep 17 00:00:00 2001
From: sqrthree
Date: Tue, 11 Apr 2017 00:16:25 +0800
Subject: [PATCH 110/638] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20Android=20?=
=?UTF-8?q?=E5=A6=82=E4=BD=95=E5=AE=9E=E7=8E=B0=E6=B0=94=E6=B3=A1=E9=80=89?=
=?UTF-8?q?=E6=8B=A9=E5=8A=A8=E7=94=BB=20=E7=9A=84=E7=A7=AF=E5=88=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 7 +++----
android.md | 1 +
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index c7c8629cecf..dae41fd13fa 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
[掘金翻译计划](https://juejin.im/tag/%E6%8E%98%E9%87%91%E7%BF%BB%E8%AF%91%E8%AE%A1%E5%88%92) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](#android)、[iOS](#ios)、[React](#react)、[前端](#前端)、[后端](#后端)、[产品](#产品)、[设计](#设计) 等领域,读者为热爱新技术的新锐开发者。
-掘金翻译计划目前翻译完成 [450](#近期文章列表) 篇文章,共有 [270](https://github.com/xitu/gold-miner/wiki/%E8%AF%91%E8%80%85%E7%A7%AF%E5%88%86%E8%A1%A8) 余名译者贡献翻译。
+掘金翻译计划目前翻译完成 [451](#近期文章列表) 篇文章,共有 [270](https://github.com/xitu/gold-miner/wiki/%E8%AF%91%E8%80%85%E7%A7%AF%E5%88%86%E8%A1%A8) 余名译者贡献翻译。
# 官方指南:
@@ -20,10 +20,10 @@
## Android
+* [Android 如何实现气泡选择动画](https://juejin.im/post/58e5ec838d6d8100616d82e2/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([skyar2009](https://github.com/skyar2009) 翻译)
* [一个人的 Android 开发](https://juejin.im/entry/58dca515b123db00603887fd/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([BoilerYao](https://github.com/BoilerYao) 翻译)
* [我是如何做到在 5 分钟之内将应用大小减少 60% 的](https://juejin.im/post/58d9b6a1a22b9d0064719f9e/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([jifaxu](https://github.com/jifaxu) 翻译)
* [拉模式和推模式,命令式和响应式 – 响应式编程 [Android RxJava2](这到底是什么):第二部分](https://juejin.im/entry/58d78547a22b9d006465ca57/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([XHShirley](https://github.com/XHShirley) 翻译)
-* [离线支持:不再『稍后重试』](https://juejin.im/post/58d491a8128fe1006cb6e750/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([skyar2009](https://github.com/skyar2009) 翻译)
* [所有 Android 译文>>](https://github.com/xitu/gold-miner/blob/master/android.md)
@@ -41,8 +41,7 @@
* [Preload,Prefetch 和它们在 Chrome 之中的优先级](https://juejin.im/post/58e8acf10ce46300585a7a42?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([gy134340](http://gy134340.com/) 翻译)
* [setState() 门事件](https://juejin.im/post/58e5aeccb123db15eb80ecb0?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([reid3290](https://github.com/reid3290) 翻译)
* [如何使用 JavaScript 构建响应式引擎 —— Part 2:计算属性和依赖追踪](https://juejin.im/post/58ddeb1a570c3500579016ef?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([IridescentMia](https://github.com/IridescentMia) 翻译)
-* [如何使用 JavaScript 构建响应式引擎 —— Part 1:可观察的对象](https://juejin.im/post/58dc9da661ff4b0061547ca0?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([IridescentMia](https://github.com/IridescentMia) 翻译)
-* [生活在 JavaScript 之中:学习第二门语言的好处](https://juejin.im/post/58d908deac502e0058db544b/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([gy134340](http://gy134340.com/) 翻译)
+* [如何使用 JavaScript 构建响应式引擎 —— Part 1:可观察的对象](https://juejin.im/post/58dc9da661ff4b0061547ca0?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)
* [所有前端译文>>](https://github.com/xitu/gold-miner/blob/master/front-end.md)
diff --git a/android.md b/android.md
index 2c1b495bf9d..8b02a079727 100644
--- a/android.md
+++ b/android.md
@@ -1,3 +1,4 @@
+* [Android 如何实现气泡选择动画](https://juejin.im/post/58e5ec838d6d8100616d82e2/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([skyar2009](https://github.com/skyar2009) 翻译)
* [一个人的 Android 开发](https://juejin.im/entry/58dca515b123db00603887fd/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([BoilerYao](https://github.com/BoilerYao) 翻译)
* [我是如何做到在 5 分钟之内将应用大小减少 60% 的](https://juejin.im/post/58d9b6a1a22b9d0064719f9e/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([jifaxu](https://github.com/jifaxu) 翻译)
* [拉模式和推模式,命令式和响应式 – 响应式编程 [Android RxJava2](这到底是什么):第二部分](https://juejin.im/entry/58d78547a22b9d006465ca57/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([XHShirley](https://github.com/XHShirley) 翻译)
From 771a38fa640cf24e5ad6d75ee86e182e6476175b Mon Sep 17 00:00:00 2001
From: sqrthree
Date: Tue, 11 Apr 2017 00:46:50 +0800
Subject: [PATCH 111/638] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20=E5=9C=A8=20Apache?=
=?UTF-8?q?=20=E5=92=8C=20Nginx=20=E6=97=A5=E5=BF=97=E9=87=8C=E6=A3=80?=
=?UTF-8?q?=E6=B5=8B=E7=88=AC=E8=99=AB=E6=9C=BA=E5=99=A8=E4=BA=BA=20?=
=?UTF-8?q?=E7=9A=84=E7=A7=AF=E5=88=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 4 ++--
backend.md | 1 +
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index dae41fd13fa..62a56a84c1f 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
[掘金翻译计划](https://juejin.im/tag/%E6%8E%98%E9%87%91%E7%BF%BB%E8%AF%91%E8%AE%A1%E5%88%92) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](#android)、[iOS](#ios)、[React](#react)、[前端](#前端)、[后端](#后端)、[产品](#产品)、[设计](#设计) 等领域,读者为热爱新技术的新锐开发者。
-掘金翻译计划目前翻译完成 [451](#近期文章列表) 篇文章,共有 [270](https://github.com/xitu/gold-miner/wiki/%E8%AF%91%E8%80%85%E7%A7%AF%E5%88%86%E8%A1%A8) 余名译者贡献翻译。
+掘金翻译计划目前翻译完成 [452](#近期文章列表) 篇文章,共有 [270](https://github.com/xitu/gold-miner/wiki/%E8%AF%91%E8%80%85%E7%A7%AF%E5%88%86%E8%A1%A8) 余名译者贡献翻译。
# 官方指南:
@@ -56,10 +56,10 @@
## 后端
+* [在 Apache 和 Nginx 日志里检测爬虫机器人](https://juejin.im/post/58ea5758ac502e4957c78808/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([luoyaqifei](https://github.com/luoyaqifei) 翻译)
* [如何在 ChromeOS 下用 Go 搭建 Web 服务](https://juejin.im/post/58d9e1711b69e6006bc38b1a/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([xiaoyusilen](https://github.com/xiaoyusilen) 翻译)
* [在你沉迷于包的海洋之前,还是了解一下运行时 Node.js 的本身](https://juejin.im/post/58cf4a3144d90400690b7be7/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([fghpdf](https://github.com/fghpdf) 翻译)
* [Pull request review 的十大错误](https://juejin.im/post/58ce3b3e61ff4b006c988f63/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([luoyaqifei](https://github.com/luoyaqifei) 翻译)
-* [震惊!RxJava 5 个不为人知的小秘密](https://juejin.im/post/58cb833b8ac247218c2632e5/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([skyar2009](https://github.com/skyar2009) 翻译)
* [所有后端译文>>](https://github.com/xitu/gold-miner/blob/master/backend.md)
## 教程
diff --git a/backend.md b/backend.md
index 2e7926a7cba..8b96be0ba3f 100644
--- a/backend.md
+++ b/backend.md
@@ -1,3 +1,4 @@
+* [在 Apache 和 Nginx 日志里检测爬虫机器人](https://juejin.im/post/58ea5758ac502e4957c78808/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([luoyaqifei](https://github.com/luoyaqifei) 翻译)
* [如何在 ChromeOS 下用 Go 搭建 Web 服务](https://juejin.im/post/58d9e1711b69e6006bc38b1a/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([xiaoyusilen](https://github.com/xiaoyusilen) 翻译)
* [在你沉迷于包的海洋之前,还是了解一下运行时 Node.js 的本身](https://juejin.im/post/58cf4a3144d90400690b7be7/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([fghpdf](https://github.com/fghpdf) 翻译)
* [Pull request review 的十大错误](https://juejin.im/post/58ce3b3e61ff4b006c988f63/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([luoyaqifei](https://github.com/luoyaqifei) 翻译)
From 6ea9fa02939c766668d981cb3682c6915e650786 Mon Sep 17 00:00:00 2001
From: sqrthree
Date: Tue, 11 Apr 2017 01:00:14 +0800
Subject: [PATCH 112/638] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20=E6=A8=A1=E5=9D=97?=
=?UTF-8?q?=E5=8C=96=20vs.=20=E5=BE=AE=E6=9C=8D=E5=8A=A1=20=E7=9A=84?=
=?UTF-8?q?=E7=A7=AF=E5=88=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 4 ++--
backend.md | 1 +
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 62a56a84c1f..2df4c508b86 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
[掘金翻译计划](https://juejin.im/tag/%E6%8E%98%E9%87%91%E7%BF%BB%E8%AF%91%E8%AE%A1%E5%88%92) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](#android)、[iOS](#ios)、[React](#react)、[前端](#前端)、[后端](#后端)、[产品](#产品)、[设计](#设计) 等领域,读者为热爱新技术的新锐开发者。
-掘金翻译计划目前翻译完成 [452](#近期文章列表) 篇文章,共有 [270](https://github.com/xitu/gold-miner/wiki/%E8%AF%91%E8%80%85%E7%A7%AF%E5%88%86%E8%A1%A8) 余名译者贡献翻译。
+掘金翻译计划目前翻译完成 [453](#近期文章列表) 篇文章,共有 [270](https://github.com/xitu/gold-miner/wiki/%E8%AF%91%E8%80%85%E7%A7%AF%E5%88%86%E8%A1%A8) 余名译者贡献翻译。
# 官方指南:
@@ -56,10 +56,10 @@
## 后端
+* [模块化 vs. 微服务](https://juejin.im/post/58eb2627da2f60005f0b2d60/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lsvih](https://github.com/lsvih) 翻译)
* [在 Apache 和 Nginx 日志里检测爬虫机器人](https://juejin.im/post/58ea5758ac502e4957c78808/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([luoyaqifei](https://github.com/luoyaqifei) 翻译)
* [如何在 ChromeOS 下用 Go 搭建 Web 服务](https://juejin.im/post/58d9e1711b69e6006bc38b1a/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([xiaoyusilen](https://github.com/xiaoyusilen) 翻译)
* [在你沉迷于包的海洋之前,还是了解一下运行时 Node.js 的本身](https://juejin.im/post/58cf4a3144d90400690b7be7/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([fghpdf](https://github.com/fghpdf) 翻译)
-* [Pull request review 的十大错误](https://juejin.im/post/58ce3b3e61ff4b006c988f63/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([luoyaqifei](https://github.com/luoyaqifei) 翻译)
* [所有后端译文>>](https://github.com/xitu/gold-miner/blob/master/backend.md)
## 教程
diff --git a/backend.md b/backend.md
index 8b96be0ba3f..909e6435309 100644
--- a/backend.md
+++ b/backend.md
@@ -1,3 +1,4 @@
+* [模块化 vs. 微服务](https://juejin.im/post/58eb2627da2f60005f0b2d60/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lsvih](https://github.com/lsvih) 翻译)
* [在 Apache 和 Nginx 日志里检测爬虫机器人](https://juejin.im/post/58ea5758ac502e4957c78808/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([luoyaqifei](https://github.com/luoyaqifei) 翻译)
* [如何在 ChromeOS 下用 Go 搭建 Web 服务](https://juejin.im/post/58d9e1711b69e6006bc38b1a/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([xiaoyusilen](https://github.com/xiaoyusilen) 翻译)
* [在你沉迷于包的海洋之前,还是了解一下运行时 Node.js 的本身](https://juejin.im/post/58cf4a3144d90400690b7be7/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([fghpdf](https://github.com/fghpdf) 翻译)
From 8a4cb26b6b86066a9584e81025c2fe30f17553ef Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=A0=B9=E5=8F=B7=E4=B8=89?=
Date: Tue, 11 Apr 2017 10:12:45 +0800
Subject: [PATCH 113/638] Fix typos.
---
README.md | 1 -
1 file changed, 1 deletion(-)
diff --git a/README.md b/README.md
index 2df4c508b86..d83a7c5e1b9 100644
--- a/README.md
+++ b/README.md
@@ -41,7 +41,6 @@
* [Preload,Prefetch 和它们在 Chrome 之中的优先级](https://juejin.im/post/58e8acf10ce46300585a7a42?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([gy134340](http://gy134340.com/) 翻译)
* [setState() 门事件](https://juejin.im/post/58e5aeccb123db15eb80ecb0?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([reid3290](https://github.com/reid3290) 翻译)
* [如何使用 JavaScript 构建响应式引擎 —— Part 2:计算属性和依赖追踪](https://juejin.im/post/58ddeb1a570c3500579016ef?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([IridescentMia](https://github.com/IridescentMia) 翻译)
-* [如何使用 JavaScript 构建响应式引擎 —— Part 1:可观察的对象](https://juejin.im/post/58dc9da661ff4b0061547ca0?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)
* [所有前端译文>>](https://github.com/xitu/gold-miner/blob/master/front-end.md)
From d57c25645060c19dc1e98f953c2ed33b8656db70 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=A0=B9=E5=8F=B7=E4=B8=89?=
Date: Tue, 11 Apr 2017 10:13:31 +0800
Subject: [PATCH 114/638] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E8=AF=91=E8=80=85?=
=?UTF-8?q?=E4=BA=BA=E6=95=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index d83a7c5e1b9..445c5394d6d 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
[掘金翻译计划](https://juejin.im/tag/%E6%8E%98%E9%87%91%E7%BF%BB%E8%AF%91%E8%AE%A1%E5%88%92) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](#android)、[iOS](#ios)、[React](#react)、[前端](#前端)、[后端](#后端)、[产品](#产品)、[设计](#设计) 等领域,读者为热爱新技术的新锐开发者。
-掘金翻译计划目前翻译完成 [453](#近期文章列表) 篇文章,共有 [270](https://github.com/xitu/gold-miner/wiki/%E8%AF%91%E8%80%85%E7%A7%AF%E5%88%86%E8%A1%A8) 余名译者贡献翻译。
+掘金翻译计划目前翻译完成 [453](#近期文章列表) 篇文章,共有 [300](https://github.com/xitu/gold-miner/wiki/%E8%AF%91%E8%80%85%E7%A7%AF%E5%88%86%E8%A1%A8) 余名译者贡献翻译。
# 官方指南:
From f995c21c858bb1e6a988995537f3583cf6db71ce Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=A0=B9=E5=8F=B7=E4=B8=89?=
Date: Tue, 11 Apr 2017 10:46:48 +0800
Subject: [PATCH 115/638] Update preload-prefetch-and-priorities-in-chrome.md
---
TODO/preload-prefetch-and-priorities-in-chrome.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/TODO/preload-prefetch-and-priorities-in-chrome.md b/TODO/preload-prefetch-and-priorities-in-chrome.md
index 5f13ea73d2b..6fc8912e434 100644
--- a/TODO/preload-prefetch-and-priorities-in-chrome.md
+++ b/TODO/preload-prefetch-and-priorities-in-chrome.md
@@ -1,5 +1,5 @@
> * 原文地址:[Preload, Prefetch And Priorities in Chrome](https://medium.com/reloading/preload-prefetch-and-priorities-in-chrome-776165961bbf)
-> * 原文作者:[Addy Osmani](https://medium.com/@addyosmani?source=post_header_lockup)
+> * 原文作者:本文已获原作者 [Addy Osmani](https://medium.com/@addyosmani) 授权
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
> * 译者:[gy134340](https://github.com/gy134340)
> * 校对者:[IridescentMia](https://github.com/IridescentMia),[vuuihc](https://github.com/vuuihc)
From 48e36d994a282a1d23321bd0a5564386a6871889 Mon Sep 17 00:00:00 2001
From: sqrthree
Date: Tue, 11 Apr 2017 22:55:28 +0800
Subject: [PATCH 116/638] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BD=9C=E8=80=85?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 2df4c508b86..b00acba8e90 100644
--- a/README.md
+++ b/README.md
@@ -41,7 +41,7 @@
* [Preload,Prefetch 和它们在 Chrome 之中的优先级](https://juejin.im/post/58e8acf10ce46300585a7a42?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([gy134340](http://gy134340.com/) 翻译)
* [setState() 门事件](https://juejin.im/post/58e5aeccb123db15eb80ecb0?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([reid3290](https://github.com/reid3290) 翻译)
* [如何使用 JavaScript 构建响应式引擎 —— Part 2:计算属性和依赖追踪](https://juejin.im/post/58ddeb1a570c3500579016ef?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([IridescentMia](https://github.com/IridescentMia) 翻译)
-* [如何使用 JavaScript 构建响应式引擎 —— Part 1:可观察的对象](https://juejin.im/post/58dc9da661ff4b0061547ca0?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)
+* [如何使用 JavaScript 构建响应式引擎 —— Part 1:可观察的对象](https://juejin.im/post/58dc9da661ff4b0061547ca0?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([IridescentMia](https://github.com/IridescentMia) 翻译)
* [所有前端译文>>](https://github.com/xitu/gold-miner/blob/master/front-end.md)
From 422f548bef95305ec1f87d3f48958113f675ff5e Mon Sep 17 00:00:00 2001
From: sqrthree
Date: Tue, 11 Apr 2017 23:04:46 +0800
Subject: [PATCH 117/638] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=94=99=E8=AF=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 3 ---
1 file changed, 3 deletions(-)
diff --git a/README.md b/README.md
index b494634b4e5..54648b75c5d 100644
--- a/README.md
+++ b/README.md
@@ -41,10 +41,7 @@
* [Preload,Prefetch 和它们在 Chrome 之中的优先级](https://juejin.im/post/58e8acf10ce46300585a7a42?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([gy134340](http://gy134340.com/) 翻译)
* [setState() 门事件](https://juejin.im/post/58e5aeccb123db15eb80ecb0?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([reid3290](https://github.com/reid3290) 翻译)
* [如何使用 JavaScript 构建响应式引擎 —— Part 2:计算属性和依赖追踪](https://juejin.im/post/58ddeb1a570c3500579016ef?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([IridescentMia](https://github.com/IridescentMia) 翻译)
-<<<<<<< HEAD
* [如何使用 JavaScript 构建响应式引擎 —— Part 1:可观察的对象](https://juejin.im/post/58dc9da661ff4b0061547ca0?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([IridescentMia](https://github.com/IridescentMia) 翻译)
-=======
->>>>>>> 2ffa1a092c355fc606b7cfc27f14af24d385d679
* [所有前端译文>>](https://github.com/xitu/gold-miner/blob/master/front-end.md)
From 7d63b83df1a22c2082cab44926079a3f08063d2a Mon Sep 17 00:00:00 2001
From: Tuccuay
Date: Tue, 11 Apr 2017 23:47:00 +0800
Subject: [PATCH 118/638] revision for @atuooo
---
...g-swift-essential-details-about-strings.md | 34 +++++++++----------
1 file changed, 17 insertions(+), 17 deletions(-)
diff --git a/TODO/mastering-swift-essential-details-about-strings.md b/TODO/mastering-swift-essential-details-about-strings.md
index 1abd697d093..14cd30aa1a8 100644
--- a/TODO/mastering-swift-essential-details-about-strings.md
+++ b/TODO/mastering-swift-essential-details-about-strings.md
@@ -2,7 +2,7 @@
* 原文作者:[Dmitri Pavlutin](https://rainsoft.io/author/dmitri-pavlutin/)
* 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
* 译者:[Tuccuay](https://www.tuccuay.com)
-* 校对者:
+* 校对者:[oOatuo](https://github.com/atuooo)
# 掌握 Swift 的字符串细节
@@ -11,7 +11,7 @@ String 类型在任何编程语言中都是一个重要的组成部分。而用
为了触及更多的用户,iOS 应用必须国际化以支持大量现代语言。Unicode 标准解决了这个问题,不过这也给我们使用 string 类型带来了额外的挑战性。
-从一方面来说,编程语言应该在平衡处理字符串时应该在 Unicode 复杂性和性能之间取得平衡。而另一方面,它需要为开发者提供一个舒适的结构来处理字符串。
+从一方面来说,编程语言在处理字符串时应该在 Unicode 复杂性和性能之间取得平衡。而另一方面,它需要为开发者提供一个舒适的结构来处理字符串。
而在我看来,Swift 在这两方面都做的不错。
@@ -23,16 +23,16 @@ Swift 对此有着更好的实现方式。字符串本身不再是集合,而
对于 `let myStr = "Hello, world"` 来说,你可以访问到下面这些 view:
-- `myStr.characters` 即 `String.CharacterView`。可以获取字形的值,视觉上呈现为单一的符号。是最常用的试图
+- `myStr.characters` 即 `String.CharacterView`。可以获取字形的值,视觉上呈现为单一的符号,是最常用的视图。
- `myStr.unicodeScalars` 即 `String.UnicodeScalarView`。可以获取 21 整数表示的 Unicode 码位。
- `myStr.utf16` 即 `String.UTF16View`。用于获取 UTF16 编码的代码单元。
-- `myStr.utf8` 即 `String.UTF8View`。能够获取 UTF8 编码的代码单一。
+- `myStr.utf8` 即 `String.UTF8View`。能够获取 UTF8 编码的代码单元。
![Swift 中的 CharacterView, UnicodeScalarView, UTF16View 和 UTF8View](https://rainsoft.io/content/images/2016/10/Swift-strings--3-.png)
在大多数时候开发者都在处理简单的字符串字符,而不是深入到编码或者码位这样的细节中。
-`CharacterView` 能很好的完成大多数任务:迭代字符串、字符计数、验证是否包含字符串、通过索引访问和比较操作等。
+`CharacterView` 能很好地完成大多数任务:迭代字符串、字符计数、验证是否包含字符串、通过索引访问和比较操作等。
让我们看看如何用 Swift 来完成这些任务。
@@ -52,7 +52,7 @@ print(type(of: characters))// => "CharacterView"
`message.characters` 返回了 `CharacterView` 结构.
-字符视图是 `Character` 结构的集合。例如我们可以这样来访问字符视图里的第一个字符:
+字符视图是 `Character` 结构的集合。例如,我们可以这样来访问字符视图里的第一个字符:
[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57ff7e188ef62b25bcea2ab2)
@@ -70,7 +70,7 @@ print(capitalHCharacter == firstCharacter) // => true
这个字符实例代表了单个符号 `H`。
-在 Unicode 标准中,`H` 代表 *Latin Capital letter H*,码位是 `U+0048`。
+在 Unicode 标准中,`H` 代表 *Latin Capital letter H* (拉丁文大写字母 H),码位是 `U+0048`。
让我们掠过 ASCII 看看 Swift 如何处理更复杂的符号。这些字符被渲染成单个视觉符号,但实际上是由两个或更多个 Unicode 标量](http://unicode.org/glossary/#unicode_scalar_value) 组成。严格来说这些字符被称为 **字形簇**
@@ -79,7 +79,7 @@ print(capitalHCharacter == firstCharacter) // => true
让我们看看 `ç` 的字形。他可以有两种表现形式:
-- 使用 `U+00E7` *LATIN SMALL LETTER C WITH CEDILLA*:被渲染为 `ç`
+- 使用 `U+00E7` *LATIN SMALL LETTER C WITH CEDILLA* (拉丁文小写变音字母 C):被渲染为 `ç`
- 或者使用组合字符序列:`U+0063`*LATIN SMALL LETTER C* 加上 组合标记 `U + 0327` *COMBINING CEDILLA* 组成复合字形:`c` + `◌̧` = `ç`
我们看看在第二个选项中 Swift 是如何处理它的:
@@ -111,9 +111,9 @@ let multipleGraphemes: Character = "ab" // Error!
即使 `singleGrapheme` 由 3 个 Unicode 标量组成,它创建了一个字形 `ḉ`。
而 `multipleGraphemes` 则是从两个 Unicode 标量创建一个 `Character`,这将在单个 `Character` 结构中创建两个分离的字母 `a` 和 `b`,这不是被允许的操作。
-# 2. 迭代字符串中的字符
+# 2. 遍历字符串中的字符
-`CharacterView` 集合遵循了 `Sequence` 协议。这将允许在 `for-in` 循环中便利字符视图:
+`CharacterView` 集合遵循了 `Sequence` 协议。这将允许在 `for-in` 循环中遍历字符视图:
[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4bc8f27a61152fe7c7410)
@@ -161,7 +161,7 @@ for (index, char) in weather.characters.enumerated() {
# 3. 统计字符
-只需要访问 `CharacterView` 的 `counter` 属性就可以获得字符串中字符的个数:
+只需要访问 `CharacterView` 的 `count` 属性就可以获得字符串中字符的个数:
[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4bcf327a61152fe7c7413)
@@ -191,11 +191,11 @@ print(drink.characters.count) // => 4
# 4. 按索引访问字符
-因为 Swift 直到它实际评估字符视图中的字形之前都不知道字符串中的字符个数。结果就造成了无法通过通过下标的方式访问字符串索引。
+因为 Swift 直到它实际评估字符视图中的字形之前都不知道字符串中的字符个数,所以无法通过下标的方式访问字符串索引。
你可以通过特殊的类型 `String.Index` 访问字符。
-如果你需要访问字符串中的第一个或者最好一个字符,字符视图结构提供了 `first` 和 `last` 属性:
+如果你需要访问字符串中的第一个或者最后一个字符,字符视图结构提供了 `first` 和 `last` 属性:
[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4bd2027a61152fe7c7415)
@@ -230,7 +230,7 @@ print(color[beforeEndIndex]) // => "n"
```
`color.startIndex` 是第一个字符的索引,所以 `color[startIndex]` 表示为 `g`。
-`color.endIndex` 表示**结束**位置,或者简单的说是比最后一个有效小标参数大的位置。要访问最后一个字符,你必须计算它的前一个索引:`color.index(before: color.endIndex)`
+`color.endIndex` 表示**结束**位置,或者简单的说是比最后一个有效下标参数大的位置。要访问最后一个字符,你必须计算它的前一个索引:`color.index(before: color.endIndex)`
要通过偏移访问字符的位置, 在 `index(theIndex, offsetBy: theOffset)` 方法中使用 `offsetBy` 参数:
@@ -459,9 +459,9 @@ if let index = weather.characters.index(of: " ") {
上面描述的许多字符串操作都是直接应用于字符串中的字符视图。
-而更方便的直接使用一个字符序列可能是更好的选择。
+如果你觉得直接对字符序列进行操作更加方便的话,那也是个不错的选择。
-比如你可以删除特定索引出的字符,或者直接删除第一个或者最好一个字符:
+比如你可以删除特定索引出的字符,或者直接删除第一个或者最后一个字符:
[Try in Swift sandbox](http://swiftlang.ng.bluemix.net/#/repl/57f4bea927a61152fe7c7425)
@@ -531,7 +531,7 @@ print(numberOfStars) // => 2
首先要说,大家对于字符串内容持有的不同观点看起来似乎过于复杂。
-而在我看来这是一个很好的实现。字符串可以从不同的角度来例假:昨晚字形集合、UTF-8 或 UTF-16 码位和简单是 Unicode 标量。
+而在我看来这是一个很好的实现。字符串可以从不同的角度来看待:作为字形集合、UTF-8 / UTF-16 码位或者简单的 Unicode 标量。
根据你的任务来选择合适的视图。在大多数情况下,`CharacterView` 都很合适。
From fccb3e734190d7323c5c224ec48fab9e89d0e646 Mon Sep 17 00:00:00 2001
From: zhuzi
Date: Tue, 11 Apr 2017 23:49:37 +0800
Subject: [PATCH 119/638] translation half finished
---
TODO/secure-web-app-http-headers.md | 119 ++++++++++++++++++----------
1 file changed, 79 insertions(+), 40 deletions(-)
diff --git a/TODO/secure-web-app-http-headers.md b/TODO/secure-web-app-http-headers.md
index e2f1066fd33..17aad2f24b1 100644
--- a/TODO/secure-web-app-http-headers.md
+++ b/TODO/secure-web-app-http-headers.md
@@ -1,29 +1,30 @@
> * 原文地址:[How To Secure Your Web App With HTTP Headers](https://www.smashingmagazine.com/2017/04/secure-web-app-http-headers/)
> * 原文作者:[Hagay Lupesko](https://www.smashingmagazine.com/author/hagaylupesko/)
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
-> * 译者:
+> * 译者:[bambooom](https://github.com/bambooom)
> * 校对者:
-## [How To Secure Your Web App With HTTP Headers](https://www.smashingmagazine.com/2017/04/secure-web-app-http-headers/) ##
+## 如何使用 HTTP Headers 来保护你的 Web 应用 ##
-Web applications, be they thin websites or thick single-page apps, are notorious targets for cyber-attacks. In 2016, approximately [40% of data breaches](http://www.verizonenterprise.com/verizon-insights-lab/dbir/2016/) originated from attacks on web apps — the leading attack pattern. Indeed, these days, understanding cyber-security is not a luxury but rather **a necessity for web developers**, especially for developers who build consumer-facing applications.
+> Web applications, be they thin websites or thick single-page apps, are notorious targets for cyber-attacks. In 2016, approximately [40% of data breaches](http://www.verizonenterprise.com/verizon-insights-lab/dbir/2016/) originated from attacks on web apps — the leading attack pattern. Indeed, these days, understanding cyber-security is not a luxury but rather **a necessity for web developers**, especially for developers who build consumer-facing applications.
-HTTP response headers can be leveraged to tighten up the security of web apps, typically just by adding a few lines of code. In this article, we’ll show how web developers can use HTTP headers to build secure apps. While the code examples are for Node.js, setting HTTP response headers is supported across all major server-side-rendering platforms and is typically simple to set up.
+Web 应用,无论是简单的小网页还是复杂的单页应用,众所周知都是网络攻击的目标。2016年,大约 40% 的数据泄露源自对 Web 应用的攻击,这是主要的攻击模式。事实上,现在来说,了解网络安全并不是锦上添花, 而是 Web 开发者的必需任务,特别对于构建面向消费者的产品的开发人员。
-#### Further Reading on SmashingMag:
+> HTTP response headers can be leveraged to tighten up the security of web apps, typically just by adding a few lines of code. In this article, we’ll show how web developers can use HTTP headers to build secure apps. While the code examples are for Node.js, setting HTTP response headers is supported across all major server-side-rendering platforms and is typically simple to set up.
-- [Facing The Challenge: Building A Responsive Web Application](https://www.smashingmagazine.com/2013/06/building-a-responsive-web-application/)
-- [Getting Ready For HTTP2: A Guide For Web Designers And Developers](https://www.smashingmagazine.com/2016/02/getting-ready-for-http2/)
-- [Common Security Mistakes in Web Applications](https://www.smashingmagazine.com/2010/10/common-security-mistakes-in-web-applications/)
-- [Web Security: Are You Part Of The Problem?](https://www.smashingmagazine.com/2010/01/web-security-primer-are-you-part-of-the-problem/)
+开发者可以利用 HTTP 响应头来加强 Web 应用程序的安全性,通常只需要添加几行代码即可。本文将结束 web 开发者如何利用 HTTP Headers 来构建安全的应用。虽然本文的示例代码是 Node.js,但是设置 HTTP 响应头基本在所有主要的服务端语言都是简单易设置的。
-### About HTTP Headers ###
+### 关于 HTTP Headers ###
-Technically, HTTP headers are simply fields, encoded in clear text, that are part of the HTTP request and response message header. They are designed to enable both the HTTP client and server to send and receive meta data about the connection to be established, the resource being requested, as well as the returned resource itself.
+> Technically, HTTP headers are simply fields, encoded in clear text, that are part of the HTTP request and response message header. They are designed to enable both the HTTP client and server to send and receive meta data about the connection to be established, the resource being requested, as well as the returned resource itself.
-Plain-text HTTP response headers can be examined easily using cURL, with the `--head` option, like so:
+技术上,HTTP 头只是简单的字段,咦明文形式编码,这是 HTTP 请求和响应消息头的一部分。它们旨在使客户端和服务端都能够发送和接受有关要建立的连接元数据、所请求的资源,以及返回的资源本身的元数据。
-```
+> Plain-text HTTP response headers can be examined easily using cURL, with the `--head` option, like so:
+
+可以使用 cURL `--head` 选项轻松检查纯文本 HTTP 响应头,例如:
+
+```sh
$ curl --head https://www.google.com
HTTP/1.1 200 OK
Date: Thu, 05 Jan 2017 08:20:29 GMT
@@ -36,33 +37,51 @@ Vary: Accept-Encoding
…
```
-Today, hundreds of headers are used by web apps, some standardized by the [Internet Engineering Task Force](https://www.ietf.org/) (IETF), the open organization that is behind many of the standards that power the web as we know it today, and some proprietary. HTTP headers provide a flexible and extensible mechanism that enables the rich and varying use cases found on the web today.
+> Today, hundreds of headers are used by web apps, some standardized by the [Internet Engineering Task Force](https://www.ietf.org/) (IETF), the open organization that is behind many of the standards that power the web as we know it today, and some proprietary. HTTP headers provide a flexible and extensible mechanism that enables the rich and varying use cases found on the web today.
+
+现在,数百种响应头正在被 web 应用所使用,其中一部分由[互联网工程任务组, IETF](https://www.ietf.org/)标准化。IETF 是一个开发性组织,今天我们所熟知的许多 web 标准或专利都是由他们进行推进的。HTTP 头提供了一种灵活可扩展的机制,造就了现今的网络各种丰富多变的用例。
+
+### 机密资源禁用缓存 ###
+
+> Caching is a valuable and effective technique for optimizing performance in client-server architectures, and HTTP, which leverages caching extensively, is no exception. However, in cases where the cached resource is confidential, caching can lead to vulnerabilities — and must be avoided. As an example, consider a web app that renders and caches a page with sensitive information and is being used on a shared PC. Anyone can view confidential information rendered by that web app simply by visiting the browser’s cache, or sometimes even as easily as clicking the browser’s “back” button!
+
+缓存是优化客户端-服务端架构性能中有效的技术,广泛利用缓存的 HTTP 也不例外。但是,在缓存的资源是保密的情况下,缓存可能导致漏斗,所以必须避免。假设一个 web 应用对含有敏感信息的网页进行缓存,并且是在一台公用的 PC 上使用。任何人可以通过访问浏览器的缓存看到这个 web 应用上的敏感信息,甚至有时仅仅通过点击浏览器的返回按钮就可以看到。
-### Disabling Caching Of Confidential Resources ###
+> The IETF’s [RFC 7234](https://tools.ietf.org/html/rfc7234), which defines HTTP caching, specifies the default behavior of HTTP clients, both browsers and intermediary Internet proxies, to *always* cache responses to HTTP `GET` requests — unless specified otherwise. While this enables HTTP to boost performance and reduce network congestion, it could also expose end users to theft of personal information, as mentioned above. The good news is that the HTTP specification also defines a pretty simple way to instruct clients not to cache a given response, through the use of — you guessed it! — HTTP response headers.
-Caching is a valuable and effective technique for optimizing performance in client-server architectures, and HTTP, which leverages caching extensively, is no exception. However, in cases where the cached resource is confidential, caching can lead to vulnerabilities — and must be avoided. As an example, consider a web app that renders and caches a page with sensitive information and is being used on a shared PC. Anyone can view confidential information rendered by that web app simply by visiting the browser’s cache, or sometimes even as easily as clicking the browser’s “back” button!
+IETF 的 [RFC 7234](https://tools.ietf.org/html/rfc7234) 上定义了 HTTP 缓存,指定 HTTP 客户端(浏览器以及网络代理)的默认行为,也就是始终缓存对 HTTP GET 请求的相应,除非另行指定。虽然这样可以使 HTTP 提升性能减少网络拥塞,但如上所述,它也有可能使终端用户个人信息被盗。好消息是,HTTP 规范还廷议了一种非常简单的方式来指示客户端对特定响应不进行缓存,通过使用 —— 对,你猜到了 —— HTTP 响应头。
-The IETF’s [RFC 7234](https://tools.ietf.org/html/rfc7234), which defines HTTP caching, specifies the default behavior of HTTP clients, both browsers and intermediary Internet proxies, to *always* cache responses to HTTP `GET` requests — unless specified otherwise. While this enables HTTP to boost performance and reduce network congestion, it could also expose end users to theft of personal information, as mentioned above. The good news is that the HTTP specification also defines a pretty simple way to instruct clients not to cache a given response, through the use of — you guessed it! — HTTP response headers.
+> There are three headers to return when you are returning sensitive information and would like to disable caching by HTTP clients:
-There are three headers to return when you are returning sensitive information and would like to disable caching by HTTP clients:
+当你返回敏感信息并希望禁用 HTTP 客户端的缓存时,有三个头可以返回:
- `Cache-Control`
-This response header, introduced in HTTP 1.1, may contain one or more directives, each carrying a specific caching semantic, and instructing HTTP clients and proxies on how to treat the response being annotated by the header. My recommendation is to format the header as follows: `cache-control: no-cache, no-store, must-revalidate`. These three directives pretty much instruct clients and intermediary proxies not to use a previously cached response, not to store the response, and that even if the response is somehow cached, the cache must be revalidated on the origin server.
+> This response header, introduced in HTTP 1.1, may contain one or more directives, each carrying a specific caching semantic, and instructing HTTP clients and proxies on how to treat the response being annotated by the header. My recommendation is to format the header as follows: `cache-control: no-cache, no-store, must-revalidate`. These three directives pretty much instruct clients and intermediary proxies not to use a previously cached response, not to store the response, and that even if the response is somehow cached, the cache must be revalidated on the origin server.
+
+从 HTTP 1.1 引入的此响应头可能包含一个或多个指令,每个指令带有特定的缓存语义,指示 HTTP 客户端和代理如何处理有此响应头注释的响应。我推荐如下指定响应头,`cache-control: no-cache, no-store, must-revalidate`。这三个指令基本上可以指示客户端和中间代理不可使用之前缓存的响应,不可存储响应,甚至就算响应被缓存,也必须从源服务器上重新验证。
- `Pragma: no-cache`
-
-For backwards-compatibility with HTTP 1.0, you will want to include this header as well. Some HTTP clients, especially intermediary proxies, still might not fully support HTTP 1.1 and so will not correctly handle the `Cache-Control` header mentioned above. Use `Pragma: no-cache` to ensure that these older clients do not cache your response.
+
+> For backwards-compatibility with HTTP 1.0, you will want to include this header as well. Some HTTP clients, especially intermediary proxies, still might not fully support HTTP 1.1 and so will not correctly handle the `Cache-Control` header mentioned above. Use `Pragma: no-cache` to ensure that these older clients do not cache your response.
+
+为了与 HTTP 1.0 的向后兼容性,你还需要包含此响应头。有部分客户端,特别是中间代理,可能仍然没有完全支持 HTTP 1.1,所以不能正确处理前面提到的 `Cache-Control` 响应头,所以使用 `Pragma: no-cache` 确保较旧的客户端不缓存你的响应。
- `Expires: -1`
-This header specifies a timestamp after which the response is considered stale. By specifying `-1`, instead of an actual future time, you ensure that clients immediately treat this response as stale and avoid caching.
+> This header specifies a timestamp after which the response is considered stale. By specifying `-1`, instead of an actual future time, you ensure that clients immediately treat this response as stale and avoid caching.
-Note that, while disabling caching enhances the security of your web app and helps to protect confidential information, is does come at the price of a performance hit. Make sure to disable caching only for resources that actually require confidentiality and not just for any response rendered by your server! For a deeper dive into best practices for caching web resources, I highly recommend reading [Jake Archibald’s post](https://jakearchibald.com/2016/caching-best-practices/) on the subject.
+此标头指定了该响应过时的时间戳。如果不指定为未来某个真实时间而指定为 `-1`,可以保证客户端立即将此响应视为过时并避免缓存。
-Here’s how you would program these headers in Node.js:
+> Note that, while disabling caching enhances the security of your web app and helps to protect confidential information, is does come at the price of a performance hit. Make sure to disable caching only for resources that actually require confidentiality and not just for any response rendered by your server! For a deeper dive into best practices for caching web resources, I highly recommend reading [Jake Archibald’s post](https://jakearchibald.com/2016/caching-best-practices/) on the subject.
-```
+需要注意的是,禁用缓存提高安全性及保护机密资源的同时,也的确会带来性能上的折损。所以确保仅对实际需要保密性的资源禁用缓存,而不是对任何服务器的响应禁用。想要更深入了解 web 资源缓存的最佳实践,我推荐阅读 [Jake Archibald 的文章](https://jakearchibald.com/2016/caching-best-practices/)。
+
+> Here’s how you would program these headers in Node.js:
+
+下面是 Node.js 中设置响应头的示例代码:
+
+```javascript
function requestHandler(req, res) {
res.setHeader('Cache-Control','no-cache,no-store,max-age=0,must-revalidate');
res.setHeader('Pragma','no-cache');
@@ -70,37 +89,58 @@ function requestHandler(req, res) {
}
```
-### Enforcing HTTPS ###
+### 强制 HTTPS ###
-Today, the importance of HTTPS is widely recognized by the tech community. More and more web apps configure secured endpoints and are redirecting unsecure traffic to secured endpoints (i.e. HTTP to HTTPS redirects). Unfortunately, end users have yet to fully comprehend the importance of HTTPS, and this lack of comprehension exposes them to various man-in-the-middle (MitM) attacks. The typical user navigates to a web app without paying much attention to the protocol being used, be it secure (HTTPS) or unsecure (HTTP). Moreover, many users will just click past browser warnings when their browser presents a certificate error or warning!
+> Today, the importance of HTTPS is widely recognized by the tech community. More and more web apps configure secured endpoints and are redirecting unsecure traffic to secured endpoints (i.e. HTTP to HTTPS redirects). Unfortunately, end users have yet to fully comprehend the importance of HTTPS, and this lack of comprehension exposes them to various man-in-the-middle (MitM) attacks. The typical user navigates to a web app without paying much attention to the protocol being used, be it secure (HTTPS) or unsecure (HTTP). Moreover, many users will just click past browser warnings when their browser presents a certificate error or warning!
-The importance of interacting with web apps over a valid HTTPS connection cannot be overstated: An unsecure connection exposes the user to various attacks, which could lead to cookie theft or worse. As an example, it is not very difficult for an attacker to spoof network frames within a public Wi-Fi network and to extract the session cookies of users who are not using HTTPS. To make things even worse, even users interacting with a web app over a secured connection may be exposed to downgrade attacks, which try to force the connection to be downgraded to an unsecure connection, thus exposing the user to MitM attacks.
+今天,HTTPS 的重要性已经得到了科技界的广泛认可。越来越多的 web 应用配置了安全端点,并将不安全网路重定向到安全端点(即 HTTP 重定向至 HTTPS)。不幸的是,终端用户还未完全理解 HTTPS 的重要性,这种缺乏理解使他们面临着各种中间人攻击(MitM)。典型的用户访问到一个 web 应用时,并不会注意到正在使用的网络协议是安全的(HTTPS)还是不安全的(HTTP)。
-How can we help users avoid these attacks and better enforce the usage of HTTPS? Enter the HTTP Strict Transport Security (HSTS) header. Put simply, HSTS makes sure all communications with the origin host are using HTTPS. Specified in [RFC 6797](https://tools.ietf.org/html/rfc6797), HSTS enables a web app to instruct browsers to allow *only* HTTPS connections to the origin host, to internally redirect all unsecure traffic to secured connections, and to automatically upgrade all unsecure resource requests to be secure.
+> The importance of interacting with web apps over a valid HTTPS connection cannot be overstated: An unsecure connection exposes the user to various attacks, which could lead to cookie theft or worse. As an example, it is not very difficult for an attacker to spoof network frames within a public Wi-Fi network and to extract the session cookies of users who are not using HTTPS. To make things even worse, even users interacting with a web app over a secured connection may be exposed to downgrade attacks, which try to force the connection to be downgraded to an unsecure connection, thus exposing the user to MitM attacks.
-HSTS directives include the following:
+通过有效的 HTTPS 连接与 web 应用进行交互的重要性怎么说都不算夸大:不安全的连接将用户暴露给各种攻击,这可能导致 cookie 被盗甚至更糟。举个例子,攻击者可以轻易在公共 Wi-Fi 网络下骗过网络帧并提起不使用 HTTPS 的用户的会话 cookie。更糟的情况是,即使用户通过安全连接与 web 永盈进行交互也可能遭受降级攻击,这种攻击试图强制将连接降级到不安全的连接,从而是用户收到中间人攻击。
+
+> How can we help users avoid these attacks and better enforce the usage of HTTPS? Enter the HTTP Strict Transport Security (HSTS) header. Put simply, HSTS makes sure all communications with the origin host are using HTTPS. Specified in [RFC 6797](https://tools.ietf.org/html/rfc6797), HSTS enables a web app to instruct browsers to allow *only* HTTPS connections to the origin host, to internally redirect all unsecure traffic to secured connections, and to automatically upgrade all unsecure resource requests to be secure.
+
+我们如何帮助用户避免这些攻击,并更好地实施 HTTPS 的使用呢?使用 HTTP 严格传输安全头(HSTS)。简单来说,HSTS 确保与源主机间的所有通信都使用 HTTPS。[RFC 6797](https://tools.ietf.org/html/rfc6797) 中说明了,HSTS可以使 web 应用程序指示浏览器仅允许与源主机之间的 HTTPS 连接,将所有不安全的连接内部重定向到安全连接,并自动将所有不安全的资源请求升级为安全请求。
+
+> HSTS directives include the following:
+
+HSTS 的指令如下:
- `max-age=`
-This instructs the browser to cache this header, for this domain, for the specified number of seconds. This can ensure tightened security for a long duration!
+>This instructs the browser to cache this header, for this domain, for the specified number of seconds. This can ensure tightened security for a long duration!
+
+此项指示浏览器对此域缓存此响应头指定的秒数。这样可以保证长时间的加固安全。
- `includeSubDomains`
-This instructs the browser to apply HSTS for all subdomains of the current domain. This can be useful to cover all current and future subdomains you may have.
+>This instructs the browser to apply HSTS for all subdomains of the current domain. This can be useful to cover all current and future subdomains you may have.
+
+此项指示浏览器对当前域的所有子域应用 HSTS,这可以用于覆盖你可能有的所有当前和未来的子域。
- `preload`
-This is a powerful directive that forces browsers to *always* load your web app securely, even on the first hit, before the response is even received! This works by hardcoding a list of HSTS preload-enabled domains into the browser’s code. To enable the preloading feature, you need to register your domain with [HSTS Preload List Submission](https://hstspreload.org), a website maintained by Google’s Chrome team. Once registered, the domain will be prebuilt into supporting browsers to always enforce HSTS. The preload directive within the HTTP response header is used to confirm registration, indicating that the web app and domain owner are indeed interested in being on the preload list.
+> This is a powerful directive that forces browsers to *always* load your web app securely, even on the first hit, before the response is even received! This works by hardcoding a list of HSTS preload-enabled domains into the browser’s code. To enable the preloading feature, you need to register your domain with [HSTS Preload List Submission](https://hstspreload.org), a website maintained by Google’s Chrome team. Once registered, the domain will be prebuilt into supporting browsers to always enforce HSTS. The preload directive within the HTTP response header is used to confirm registration, indicating that the web app and domain owner are indeed interested in being on the preload list.
-A word of caution: using the `preload` directive also means it cannot be easily undone, and carries an update lead time of months! While preload certainly improves your app’s security, it also means you need to be fully confident your app can support HTTPS-only!
+这是一个强大的指令,强制浏览器始终安全加载你的 web 应用程序,即使是第一次收到响应之前加载!这是通过将启用 HSTS 预加载域的列表硬编码到浏览器的代码中实现的。要启用预加载功能,你需要在 Google Chrome 团队维护的网站 [HSTS 预加载列表提交](https://hstspreload.org)注册你的域。
-My recommendation is to use `Strict-Transport-Security: max-age=31536000; includeSubDomains;` which instructs the browser to enforce a valid HTTPS connection to the origin host and to all subdomains for a year. If you are confident that your app can handle HTTPS-only, I would also recommend adding the `preload` directive, in which case don’t forget to register your website on the preload list as well, as noted above!
+> A word of caution: using the `preload` directive also means it cannot be easily undone, and carries an update lead time of months! While preload certainly improves your app’s security, it also means you need to be fully confident your app can support HTTPS-only!
-Here’s what implementing HSTS looks like in Node.js:
+注意谨慎使用 `preload`,因为这意味着它不能轻易撤销,并带有几个月前的更新。虽然预加载肯定会应用程序的安全性,但也意味着你需要充分确信你的应用程序可以支持仅 HTTPS!
-```
-functionrequestHandler(req, res){
- res.setHeader('Strict-Transport-Security','max-age=31536000; includeSubDomains; preload');}
+> My recommendation is to use `Strict-Transport-Security: max-age=31536000; includeSubDomains;` which instructs the browser to enforce a valid HTTPS connection to the origin host and to all subdomains for a year. If you are confident that your app can handle HTTPS-only, I would also recommend adding the `preload` directive, in which case don’t forget to register your website on the preload list as well, as noted above!
+
+我推荐的用法是 `Strict-Transport-Security: max-age=31536000; includeSubDomains;`,这样指示了浏览器强制通过 HTTPS 连接到源主机并且有效期为一年。如果你对你的 app 处理 HTTPS 限定很有信心,我也推荐加上 `preload` 指令,当然别忘记去前面提到的预加载列表注册你的网站。
+
+> Here’s what implementing HSTS looks like in Node.js:
+
+以下是在 Nodes.js 中实现 HSTS 的方法:
+
+```javascript
+function requestHandler(req, res){
+ res.setHeader('Strict-Transport-Security','max-age=31536000; includeSubDomains; preload');
+}
```
### Enabling XSS Filtering ###
@@ -248,7 +288,6 @@ Remember that for the web to be truly awesome and engaging, it has to be secure.
*Front page image credits: [Pexels.com](https://www.pexels.com/photo/coffee-writing-computer-blogging-34600/).*
-
---
> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[React](https://github.com/xitu/gold-miner#react)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计) 等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)。
From 535f0275fb15aac1dd4b5def4cd27bfc3362d470 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=A0=B9=E5=8F=B7=E4=B8=89?=
Date: Wed, 12 Apr 2017 10:15:25 +0800
Subject: [PATCH 120/638] Update css-is-fine-its-just-really-hard.md
---
TODO/css-is-fine-its-just-really-hard.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/TODO/css-is-fine-its-just-really-hard.md b/TODO/css-is-fine-its-just-really-hard.md
index 423250fcfb8..20cb8558bcd 100644
--- a/TODO/css-is-fine-its-just-really-hard.md
+++ b/TODO/css-is-fine-its-just-really-hard.md
@@ -1,5 +1,5 @@
> * 原文地址:[CSS is Fine, It’s Just Really Hard](https://medium.com/@jdan/css-is-fine-its-just-really-hard-638da7a3dce0)
-> * 原文作者:[Jordan Scales](https://medium.com/@jdan)
+> * 原文作者:该文章已获原作者 [Jordan Scales](https://medium.com/@jdan) 授权
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
> * 译者: [ZhangFe](https://github.com/ZhangFe)
> * 校对者:[bambooom](https://github.com/bambooom),[gy134340](https://github.com/gy134340)
From 88f2c4e5960ea4f8351d8095b3f71418d5346a7e Mon Sep 17 00:00:00 2001
From: ivyxuan
Date: Wed, 12 Apr 2017 10:45:39 +0800
Subject: [PATCH 121/638] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=94=99=E8=AF=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
TODO/the-details-that-matter.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/TODO/the-details-that-matter.md b/TODO/the-details-that-matter.md
index b4ccfb5d9f8..69114a7588b 100644
--- a/TODO/the-details-that-matter.md
+++ b/TODO/the-details-that-matter.md
@@ -80,7 +80,7 @@ Airbnb 的提示听起来像人说的话而且语气还很随和。
-**像“出错啦”这种警告对所有的用户都会造成困扰,而且还会惹恼专家级用户。**但是,一个精心设计过的错误信息,会顿时化失望为欣喜。所以,把报错变得人性化、不用技术性的语言并且适合你的用户群体。
+**像“出错啦”这种警告对所有的用户都会造成困扰,而且还会惹恼专家级用户。** 但是,一个精心设计过的错误信息,会顿时化失望为欣喜。所以,把报错变得人性化、不用技术性的语言并且适合你的用户群体。
@@ -100,7 +100,7 @@ Airbnb 的提示听起来像人说的话而且语气还很随和。
#### 让用户界面更容易理解 ####
-**杂乱的堆砌是很糟糕的一件事情。**在界面上杂乱堆砌元素会给用户带来过多的信息:每一个被添加的按钮、图片和文字都会让界面显得更加复杂。如果你不想你的设计有任何刻意的留白的话,下面这个例子就能很明白的告诉你,有太多东西一起吸引你的注意力是多么可怕的事情。
+**杂乱的堆砌是很糟糕的一件事情。** 在界面上杂乱堆砌元素会给用户带来过多的信息:每一个被添加的按钮、图片和文字都会让界面显得更加复杂。如果你不想你的设计有任何刻意的留白的话,下面这个例子就能很明白的告诉你,有太多东西一起吸引你的注意力是多么可怕的事情。
From 6e460df0aceb6017d65043c6bdcf1042bbce31bc Mon Sep 17 00:00:00 2001
From: reid
Date: Wed, 12 Apr 2017 11:55:31 +0800
Subject: [PATCH 122/638] =?UTF-8?q?=E5=AE=8C=E6=88=90=E7=BF=BB=E8=AF=91?=
=?UTF-8?q?=E5=88=9D=E7=A8=BF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
...gher-order-functions-composing-software.md | 89 +++++++++----------
1 file changed, 44 insertions(+), 45 deletions(-)
diff --git a/TODO/higher-order-functions-composing-software.md b/TODO/higher-order-functions-composing-software.md
index aa432f1141e..67336f3fd47 100644
--- a/TODO/higher-order-functions-composing-software.md
+++ b/TODO/higher-order-functions-composing-software.md
@@ -1,22 +1,22 @@
-> * 原文地址:[Higher Order Functions (Composing Software)(part 4)](https://medium.com/javascript-scene/higher-order-functions-composing-software-5365cf2cbe99)
-> * 原文作者:[Eric Elliott](https://medium.com/@_ericelliott?source=post_header_lockup)
-> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
-> * 译者:
-> * 校对者:
+> * 原文地址:[Higher Order Functions (Composing Software)(part 4)](https://medium.com/javascript-scene/higher-order-functions-composing-software-5365cf2cbe99)
+> * 原文作者:[Eric Elliott](https://medium.com/@_ericelliott?source=post_header_lockup)
+> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
+> * 译者:[reid3290](https://github.com/reid3290)
+> * 校对者:
-# Higher Order Functions (Composing Software) #
+# 高阶函数(软件编写)(第四部分) #
-Smoke Art Cubes to Smoke — MattysFlicks — (CC BY 2.0)
-> Note: This is part of the “Composing Software” series on learning functional programming and compositional software techniques in JavaScript ES6+ from the ground up. Stay tuned. There’s a lot more of this to come!
-> [< Previous](https://medium.com/javascript-scene/a-functional-programmers-introduction-to-javascript-composing-software-d670d14ede30#.gof8dsqh9) | [<< Start over at Part 1](https://medium.com/javascript-scene/the-rise-and-fall-and-rise-of-functional-programming-composable-software-c2d91b424c8c#.2dfd6n6qe) | [Next >](https://medium.com/javascript-scene/reduce-composing-software-fe22f0c39a1d)
+Smoke Art Cubes to Smoke — MattysFlicks — (CC BY 2.0)(译注:该图是用 PS 将烟雾处理成方块状后得到的效果,参见 [flickr](https://www.flickr.com/photos/68397968@N07/11432696204)。)
+> 注意:这是“软件编写”系列文章的第四部分,该系列主要阐述如何在 JavaScript ES6+ 中从零开始学习函数式编程和组合化软件(compositional software)技术(译注:关于软件可组合性的概念,参见维基百科 [Composability](https://en.wikipedia.org/wiki/Composability))。后续还有更多精彩内容,敬请期待!
+> [< 上一篇](https://medium.com/javascript-scene/a-functional-programmers-introduction-to-javascript-composing-software-d670d14ede30#.gof8dsqh9) | [<< 第一篇](https://medium.com/javascript-scene/the-rise-and-fall-and-rise-of-functional-programming-composable-software-c2d91b424c8c#.2dfd6n6qe) | [下一篇 >](https://medium.com/javascript-scene/reduce-composing-software-fe22f0c39a1d)
-A **higher order function** is a function that takes a function as an argument, or returns a function. Higher order function is in contrast to first order functions, which don’t take a function as an argument or return a function as output.
+**高阶函数**是一种接收一个函数作为输入或输出一个函数的函数(译注:参见维基百科[高阶函数](https://zh.wikipedia.org/wiki/%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0)),这是和一阶函数截然不同的。
-Earlier we saw examples of `.map()` and `.filter()`. Both of them take a function as an argument. They're both higher order functions.
+之前我们看到的 `.map()` 和 `.filter()` 都是高阶函数 —— 它们都接受一个函数作为参数,
-Let’s look at an example of a first-order function which filters all the 4-letter words from a list of words:
+先来看个一阶函数的例子,该函数会将单词数组中 4 个字母的单词过滤掉:
```
const censor = words => {
@@ -32,7 +32,7 @@ censor(['oops', 'gasp', 'shout', 'sun']);
// [ 'shout', 'sun' ]
```
-Now what if we want to select all the words that begin with ‘s’? We could create another function:
+如果又要选择出所有以 's' 开头的单词呢?可以再定义一个函数:
```
const startsWithS = words => {
@@ -48,29 +48,29 @@ startsWithS(['oops', 'gasp', 'shout', 'sun']);
// [ 'shout', 'sun' ]
```
-You may already be recognizing a lot of repeated code. There’s a pattern forming here that could be abstracted into a more generalized solution. These two functions have a whole lot in common. They both iterate over a list and filter it on a given condition.
+显然可以看出这里面有很多重复的代码,这两个函数的主体是相同的 —— 都是遍历一个数组并根据给定的条件进行过滤。这便形成了一种特定的模式,可以从中抽象出更为通用的解决方案。
-Both the iteration and the filtering seem like they’re begging to be abstracted so they can be shared and reused to build all sorts of similar functions. After all, selecting things from lists of things is a very common task.
+不难看出, “遍历”和“过滤”都是亟待抽象出来的,以便分享和复用到其他所有类似的函数中去。毕竟,从数组中选取某些特定元素是很常见的需求。
-Luckily for us, JavaScript has first class functions. What does that mean? Just like numbers, strings, or objects, functions can be:
+幸运的是,函数是 JavaScript 中的一等公民,就像数字、字符串和对象一样,函数可以:
-- Assigned as an identifier (variable) value
-- Assigned to object property values
-- Passed as arguments
-- Returned from functions
+- 像变量一样赋值给其他变量
+- 作为对象的属性值
+- 作为参数进行传递
+- 作为函数的返回值
-Basically, we can use functions just like any other bits of data in our programs, and that makes abstraction a lot easier. For instance, we can create a function that abstracts the process of iterating over a list an accumulating a return value by passing in a function that handles *the bits that are different.* We’ll call that function the *reducer:*
+函数基本上可以像其他任何数据类型一样被使用,这点使得“抽象”容易了许多。例如,可以定义一种函数,将遍历数组并累计出一个返回值的过程抽象出来,该函数接收一个函数作为参数来决定具体的**累计**过程,不妨将此函数称为 **reducer**:
```
const reduce = (reducer, initial, arr) => {
- // shared stuff
+ // 共享的
let acc = initial;
for (let i = 0, length = arr.length; i < length; i++) {
- // unique stuff in reducer() call
+ // 独特的
acc = reducer(acc, arr[i]);
- // more shared stuff
+ // 又是共享的
}
return acc;
};
@@ -78,14 +78,14 @@ const reduce = (reducer, initial, arr) => {
reduce((acc, curr) => acc + curr, 0, [1,2,3]); // 6
```
-This `reduce()` implementation takes a reducer function, an initial value for the accumulator, and an array of data to iterate over. For each item in the array, the reducer is called, passing it the accumulator and the current array element. The return value is assigned to the accumulator. When it's finished applying the reducer to all of the values in the list, the accumulated value is returned.
+该 `reduce()` 接受 3 个参数:一个 reducer 函数、一个累计的初始值和一个用于遍历的数组。对数组中的每个元素都会调用 reducer,传入累计器和当前数组元素,返回值又会赋给累计器。对数组中的所有元素都执行过 reducer 之后,返回最终的累计结果。
-In the usage example, we call reduce and pass it the function, `(acc, curr) => acc + curr`, which takes the accumulator and the current value in the list and returns a new accumulated value. Next we pass an initial value, `0`, and finally, the data to iterate over.
+在用例中,调用 `reduce` 并传给它 3 个参数:`reducer` 函数、初始值 0 以及需要遍历的数组。其中 `reducer` 函数以累计器和当前数组元素为参数,返回累计后的结果。
-With the iteration and value accumulation abstracted, now we can implement a more generalized `filter()` function:
+如此将遍历和累计的过程抽象出来之后,便可实现更为通用的 `filter()` 函数:
```
-const filter = (
+ const filter = (
fn, arr
) => reduce((acc, curr) => fn(curr) ?
acc.concat([curr]) :
@@ -93,11 +93,11 @@ const filter = (
);
```
-In the `filter()` function, everything is shared except the `fn()` function that gets passed in as an argument. That `fn()`argument is called a predicate. A **predicate** is a function that returns a boolean value.
+在此 `filter()` 函数中,除了以参数形式传进来的 `fn()` 函数以外,所有代码都是可复用的。其中 `fn()` 参数被称为**断言(predicate)** —— 返回一个布尔值的函数。
-We call `fn()` with the current value, and if the `fn(curr)` test returns `true`, we concat the `curr` value to the accumulator array. Otherwise, we just return the current accumulator value.
+将当前值传给 `fn()`,如果 `fn(curr)` 返回 `true`,则将 `curr` 添加到结果数组中并返回之;否则,直接返回当前数组。
-Now we can implement `censor()` with `filter()` to filter out 4-letter words:
+现在便可借助 `filter()` 函数来实现过滤 4 字母单词的 `censor()` 函数:
```
const censor = words => filter(
@@ -106,20 +106,20 @@ const censor = words => filter(
);
```
-Wow! With all the common stuff abstracted out, `censor()` is a tiny function.
+喔!将所有公共代码抽象出来之后,`censor()` 函数便十分简洁了。
-And so is `startsWithS()`:
+`startsWithS()` 也是如此:
```
-const startsWithS = words => filter(
+ const startsWithS = words => filter(
word => word.startsWith('s'),
words
);
```
-If you’re paying attention, you probably know that JavaScript has already done this abstraction work for us. We have the `Array.prototype` methods, `.reduce()` and `.filter()` and `.map()` and a few more for good measure.
+ 你若稍加留意便会发现 JavaScript 其实已经为我们做了这些抽象,即 `Array.prototype` 的相关方法,例如 `.reduce()`、`.filter()`、`.map()` 等等。
-Higher order functions are also commonly used to abstract how to operate on different data types. For instance, `.filter()` doesn't have to operate on arrays of strings. It could just as easily filter numbers, because you can pass in a function that knows how to deal with a different data type. Remember the `highpass()` example?
+ 高阶函数也常常被用于对不同数据类型的操作进行抽象。例如,`.filter()` 函数不一定非得作用于字符串数组。只需传入一个能够处理不同数据类型的函数,`.filter()` 便能过滤数字了。还记得 `highpass` 的例子吗?
```
const highpass = cutoff => n => n >= cutoff;
@@ -127,22 +127,21 @@ const gt3 = highpass(3);
[1, 2, 3, 4].filter(gt3); // [3, 4];
```
-In other words, you can use higher order functions to make a function polymorphic. As you can see, higher order functions can be a whole lot more reusable and versatile than their first order cousins. Generally speaking, you’ll use higher order functions in combination with very simple first order functions in your real application code.
+换言之,高阶函数可以用来实现函数的多态性。如你所见,相较于一阶函数而言,高阶函数的复用性和通用性非常好。一般来讲,在实际编码中会组合使用高阶函数和一些非常简单的一阶函数。
-[**Continue to “Reduce” >**](https://medium.com/javascript-scene/reduce-composing-software-fe22f0c39a1d)
+[**再续 “Reduce” >**](https://medium.com/javascript-scene/reduce-composing-software-fe22f0c39a1d)
-### Next Steps ###
+### 接下来 ###
-Want to learn more about functional programming in JavaScript?
+想学习更多 JavaScript 函数式编程吗?
-[Learn JavaScript with Eric Elliott](http://ericelliottjs.com/product/lifetime-access-pass/). If you’re not a member, you’re missing out!
+[跟着 Eric Elliott 学 Javacript](http://ericelliottjs.com/product/lifetime-access-pass/),机不可失时不再来!
-[
-](https://ericelliottjs.com/product/lifetime-access-pass/)
+[](https://ericelliottjs.com/product/lifetime-access-pass/)
-***Eric Elliott*** is the author of [*“Programming JavaScript Applications”*](http://pjabook.com) (O’Reilly), and *[*“Learn JavaScript with Eric Elliott”*](http://ericelliottjs.com/product/lifetime-access-pass/). He has contributed to software experiences for **Adobe Systems, Zumba Fitness, The Wall Street Journal, ESPN, BBC, and top recording artists including Usher, Frank Ocean, Metallica**, and many more.
+**Eric Elliott** 是 [**“编写 JavaScript 应用”**](http://pjabook.com) (O’Reilly) 以及 [**“跟着 Eric Elliott 学 Javascript”**](http://ericelliottjs.com/product/lifetime-access-pass/) 两书的作者。他为许多公司和组织作过贡献,例如 **Adobe Systems**、**Zumba Fitness**、**The Wall Street Journal**、**ESPN** 和 **BBC**等 , 也是很多机构的顶级艺术家,包括但不限于 **Usher**、**Frank Ocean** 以及 **Metallica**。
-*He spends most of his time in the San Francisco Bay Area with the most beautiful woman in the world.*
+大多数时间,他都在 San Francisco Bay Area,同这世上最美丽的女子在一起。
---
From c38df1b848dcd5e272debf8e17d3d0d99d7c3452 Mon Sep 17 00:00:00 2001
From: lsvih
Date: Wed, 12 Apr 2017 12:57:17 +0800
Subject: [PATCH 123/638] =?UTF-8?q?=E4=BA=8C=E6=A0=A1=E6=84=8F=E8=A7=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
TODO/webpack-and-rollup-the-same-but-different.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/TODO/webpack-and-rollup-the-same-but-different.md b/TODO/webpack-and-rollup-the-same-but-different.md
index b80a7886547..dd15131dc7b 100644
--- a/TODO/webpack-and-rollup-the-same-but-different.md
+++ b/TODO/webpack-and-rollup-the-same-but-different.md
@@ -2,7 +2,7 @@
> * 原文作者:[Rich Harris](https://medium.com/@Rich_Harris?source=post_header_lockup)
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
> * 译者:[lsvih](https://github.com/lsvih)
-> * 校对者:
+> * 校对者:[avocadowang](https://github.com/avocadowang),[Aladdin-ADD](https://github.com/Aladdin-ADD)
# 同中有异的 Webpack 与 Rollup #
@@ -18,14 +18,14 @@
Webpack 由 [Tobias Koppers](https://medium.com/@sokra) 在 2012 年创建,用于解决当时的工具不能处理的问题:构建复杂的单页应用(SPA)。尤其是它的两个特点改变了一切:
-1. **代码分割**可以将你的 app 分割成许多个容易管理的分块,这些分块能够在用户使用你的 app 时按需加载。这意味着你的用户可以有更快的交互体验。因为访问那些网站必须要等待整个应用都被下载并解析完成。当然,你**也可以**自己手动去进行代码分割,但是……总之,祝你好运。
+1. **代码分割**可以将你的 app 分割成许多个容易管理的分块,这些分块能够在用户使用你的 app 时按需加载。这意味着你的用户可以有更快的交互体验。因为访问那些没有使用代码分割的应用时,必须要等待整个应用都被下载并解析完成。当然,你**也可以**自己手动去进行代码分割,但是……总之,祝你好运。
2. **静态资源**的导入:图片、CSS 等静态资源可以直接导入到你的 app 中,就和其它的模块、节点一样能够进行依赖管理。因此,我们再也不用小心翼翼地将各个静态文件放在特定的文件夹中,然后再去用脚本给文件 URL 加上哈希串了。Webpack 已经帮你完成了这一切。
而 Rollup 的开发理念则不同:它利用 ES2015 模块的巧妙设计,尽可能高效地构建精简且易分发的 JavaScript 库。而其它的模块打包器(包括 Webpack在内)都是通过将模块分别封装进函数中,然将这些函数通过能在浏览器中实现的 `require` 方法打包,最后依次处理这些函数。在你需要实现按需加载的时候,这种做法非常的方便,但是这样做引入了很多无关代码,比较浪费资源。当[你有很多模块要打包的时候,这种情况会变得更糟糕](https://nolanlawson.com/2016/08/15/the-cost-of-small-modules/)。
ES2015 模块则启用了一种不同的实现方法,Rollup 用的也就是这种方法。所有代码都将被放置在同一个地方,并且会在一起进行处理。因此得到的最终代码相较而言会更加的精简,运行起来自然也就更快。你可以[点击这儿亲自试试 Rollup 交互式解释器(REPL)](https://rollupjs.org/repl)。
-但这儿也存在一些需要权衡的点:代码分割是一个很棘手的问题,而 Rollup 并不能做到这一点。同样的,Rollup 也不支持模块热替换(HMR)。而且对于打算使用 Rollup 的人来说,还有一个最大的痛点:它通过[插件](https://github.com/rollup/rollup-plugin-commonjs)处理大多数 CommonJS 文件的时候,一些代码将无法被翻译回 ES2015。而与之相反,你可以把这一切的事全部放心交给 Webpack 去处理。
+但这儿也存在一些需要权衡的点:代码分割是一个很棘手的问题,而 Rollup 并不能做到这一点。同样的,Rollup 也不支持模块热替换(HMR)。而且对于打算使用 Rollup 的人来说,还有一个最大的痛点:它通过[插件](https://github.com/rollup/rollup-plugin-commonjs)处理大多数 CommonJS 文件的时候,一些代码将无法被翻译为 ES2015。而与之相反,你可以把这一切的事全部放心交给 Webpack 去处理。
### 那么我到底应该选用哪一个呢? ###
From 60d29b02c6319a3063e1f9630a741a3f84261cd2 Mon Sep 17 00:00:00 2001
From: lsvih
Date: Wed, 12 Apr 2017 12:57:44 +0800
Subject: [PATCH 124/638] =?UTF-8?q?=E4=BA=8C=E6=A0=A1=E6=84=8F=E8=A7=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
From 6cc14ad5fa43bbcfee01296502a37a1ec1fe999b Mon Sep 17 00:00:00 2001
From: reid
Date: Wed, 12 Apr 2017 15:23:34 +0800
Subject: [PATCH 125/638] fix a typo
---
...bpack-bits-getting-the-most-out-of-the-commonschunkplugin.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/TODO/webpack-bits-getting-the-most-out-of-the-commonschunkplugin.md b/TODO/webpack-bits-getting-the-most-out-of-the-commonschunkplugin.md
index 20692bd6b00..228984136a1 100644
--- a/TODO/webpack-bits-getting-the-most-out-of-the-commonschunkplugin.md
+++ b/TODO/webpack-bits-getting-the-most-out-of-the-commonschunkplugin.md
@@ -10,7 +10,7 @@ webpack 核心团队隔三差五地就会在 Twitter 上作一些寓教于乐的
![Markdown](http://i4.buimg.com/1949/614a949156a09f9e.png)
-这次的“游戏规则”很简单:安装 `webpacl-bundle-analyzer`,生成一张包含所有 bundles 信息的酷炫图片分享给我,然后 webpack 团队会帮忙指出任何潜在的问题。
+这次的“游戏规则”很简单:安装 `webpack-bundle-analyzer`,生成一张包含所有 bundles 信息的酷炫图片分享给我,然后 webpack 团队会帮忙指出任何潜在的问题。
### 我们发现了什么? ###
From ed2b2bf92d3d20a03c69f824b063742d52ea65c8 Mon Sep 17 00:00:00 2001
From: DeepMissea <398752853@qq.com>
Date: Wed, 12 Apr 2017 19:15:35 +0800
Subject: [PATCH 126/638] =?UTF-8?q?=E6=96=9C=20=E2=99=82=20=E4=BD=93?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
TODO/mvvmc-with-swift.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/TODO/mvvmc-with-swift.md b/TODO/mvvmc-with-swift.md
index eb77db7fd87..a4119cbe373 100644
--- a/TODO/mvvmc-with-swift.md
+++ b/TODO/mvvmc-with-swift.md
@@ -454,15 +454,15 @@ MVVM-C 有很多优点,可以提高应用程序的质量。你应该注意使
# FAQ
-***MVVM-C 有什么限制吗?***
+**MVVM-C 有什么限制吗?**
是的,当然有。如果你正做一个复杂的项目,你可能会遇到一些边缘案例,MVVM-C 可能无法使用,或者在一些小功能上使用过度。如果你开始使用 MVVM-C,并不意味着你必须在每个地方都强制的使用它,你应该始终选择更适合你需求的架构。
-***我能用 RxSwift 同时使用函数式和命令式编程吗?***
+**我能用 RxSwift 同时使用函数式和命令式编程吗?**
是的,你可以。但是我建议你在遗留的代码中保持命令式的方式,而在新的实现里使用函数式编程,这样你可以利用 RxSwift 强大的优势。如果你使用 RxSwift 仅仅为了 UI 绑定,你可以轻松使用命令式编写程序,而只用函数响应式编程来设置绑定。
-***我可以在企业项目中使用 RxSwift 吗?***
+**我可以在企业项目中使用 RxSwift 吗?**
这取决于你要开新项目,还是要维护旧代码。在有遗留代码的项目中,你可能无法使用 RxSwift,因为你需要重构很多的类。如果你有时间和资源来做,我建议你新开一项目一点一点的做,否则还是尝试其他的方法来解决 UI 绑定的问题。
From 38d15c20727c6208b97ab4ac9b5ae6b2c3447667 Mon Sep 17 00:00:00 2001
From: zhuzi
Date: Wed, 12 Apr 2017 22:24:57 +0800
Subject: [PATCH 127/638] fix Punctuation
---
TODO/beyond-browser-web-desktop-apps.md | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/TODO/beyond-browser-web-desktop-apps.md b/TODO/beyond-browser-web-desktop-apps.md
index 1899ee8f1d9..f40c59cd68e 100644
--- a/TODO/beyond-browser-web-desktop-apps.md
+++ b/TODO/beyond-browser-web-desktop-apps.md
@@ -16,7 +16,7 @@
### 为什么?
-首先,为什么会有人开发桌面应用?任何现有的 web 应用(不同于网站,如果你认为它们是不同的)都可能适合变成一个桌面应用。你可以围绕任何可以从与用户系统集成中获益的 web 应用构建桌面应用;例如本地通知,开机启动,与文件的交互等。有些用户单纯更喜欢在自己的电脑中永久保存一些 app,无论是否联网都可以访问。
+首先,为什么会有人开发桌面应用?任何现有的 web 应用(不同于网站,如果你认为它们是不同的)都可能适合变成一个桌面应用。你可以围绕任何可以从与用户系统集成中获益的 web 应用构建桌面应用;例如本地通知、开机启动、与文件的交互等。有些用户单纯更喜欢在自己的电脑中永久保存一些 app,无论是否联网都可以访问。
也许你有个想法,但只能用作桌面应用,有些事情只是在 web 应用中不可能实现(至少还有一点,但更多的是这一点)。你可能想要为公司内部创建一个独立的功能性应用程序,而不需要任何人安装除了你的 app 之外的任何内容(因为内置 Node.js )。也许你有个有关 Mac 应用商店的想法,也许只是你的一个个人兴趣的小项目。
@@ -26,23 +26,23 @@
### NW.js
-桌面应用已经有很长一段时间了,我知道你没有很多时间,所以我们跳过一些历史,从2011年的上海开始。来自 Intel 开源技术中心的 Roger Wang 开发了 node-webkit,一个概念验证的 Node.js 模块,这个模块可以让用户创建一个 WebKit 内核的浏览器窗口并直接在 `
```
-As you may realize, this URL will make the browser run the injected script and send the user’s cookies, potentially including confidential session cookies, to evil.com!
+> As you may realize, this URL will make the browser run the injected script and send the user’s cookies, potentially including confidential session cookies, to evil.com!
+
+你可能意识到了,这个 URL 会让浏览器执行注入的脚本,并发送用户的 cookies,极有可能包含机密的会话 cookie,至 evil.com。
-To help protect users against reflective XSS attacks, some browsers have implemented protection mechanisms. These mechanisms try to identify these attacks by looking for matching code patterns in the HTTP request and response. Internet Explorer was the first browser to introduce such a mechanism with its XSS filter, introduced in Internet Explorer 8 back in 2008, and WebKit later introduced XSS Auditor, available today in Chrome and Safari. (Firefox has no similar mechanism built in, but users can use add-ons to gain this functionality.) These various protection mechanisms are not perfect: They may fail to detect a real XSS attack (a false negative), and in other cases may block legitimate code (a false positive). Due to the latter, browsers allow users to disable the XSS filter via the settings. Unfortunately, this is typically a global setting, which turns off this security feature completely for all web apps loaded by the browser.
+> To help protect users against reflective XSS attacks, some browsers have implemented protection mechanisms. These mechanisms try to identify these attacks by looking for matching code patterns in the HTTP request and response. Internet Explorer was the first browser to introduce such a mechanism with its XSS filter, introduced in Internet Explorer 8 back in 2008, and WebKit later introduced XSS Auditor, available today in Chrome and Safari. (Firefox has no similar mechanism built in, but users can use add-ons to gain this functionality.) These various protection mechanisms are not perfect: They may fail to detect a real XSS attack (a false negative), and in other cases may block legitimate code (a false positive). Due to the latter, browsers allow users to disable the XSS filter via the settings. Unfortunately, this is typically a global setting, which turns off this security feature completely for all web apps loaded by the browser.
-Luckily, there is a way for a web app to override this configuration and ensure that the XSS filter is turned on for the web app being loaded by the browser. This is done via the `X-XSS-Protection` header. This header, supported by Internet Explorer (from version 8), Edge, Chrome and Safari, instructs the browser to turn on or off the browser’s built-in protection mechanism and to override the browser’s local configuration.
+为了帮助保护用户抵抗反射型 XSS 攻击,有些浏览器实施了保护机制。这些保护机制尝试通过在 HTTP 请求和响应中寻找匹配的代码模式来辨识这些攻击。Internet Explorer 是第一个推出这种机制的,在 2008 年的 IE 8 中引入了 XSS 过滤器的机制,而 WebKit 后来推出了 XSS 审计,现今在 Chrome 和 Safari 上可用。(Firefox 没有内置类似的机制,但是用户可以使用插件来获得此功能)。这些保护机制并不完美,它们可能无法检测到真正的 XSS 攻击(漏报),在其他情况可能会阻止合法代码(误判)。由于后一种情况的出现,浏览器允许用户可设置禁用 XSS 过滤功能。不幸的是,这通常是一个全局设置,这会完全关闭所有浏览器加载的 web 应用程序的安全功能。
-`X-XSS-Protection` directives include these:
+> Luckily, there is a way for a web app to override this configuration and ensure that the XSS filter is turned on for the web app being loaded by the browser. This is done via the `X-XSS-Protection` header. This header, supported by Internet Explorer (from version 8), Edge, Chrome and Safari, instructs the browser to turn on or off the browser’s built-in protection mechanism and to override the browser’s local configuration.
-- `1` or `0`
+幸运的是,有方法可以让 web 应用程序覆盖此配置,并确保浏览器加载的 web 应用已打开 XSS 过滤器。这是通过设定 `X-XSS-Protection` 响应头来达到的。此响应头支持 Internet Explorer (8以上)、Edge、Chrome 和 Safar,指示浏览器打开或关闭浏览器内置的保护机制,及覆盖浏览器的本地配置。
-This enables or disables the filter.
+`X-XSS-Protection` 指令包括:
+
+- `1` 或者 `0`
+
+使用或禁用 CSS 过滤器。
- `mode=block`
-This instructs the browser to prevent the entire page from rendering when an XSS attack is detected.
+> This instructs the browser to prevent the entire page from rendering when an XSS attack is detected.
+
+当检测到 XSS 攻击时,这会指示浏览器不渲染整个页面。
-I recommend always turning on the XSS filter, as well as block mode, to maximize user protection. Such a response header looks like this:
+> I recommend always turning on the XSS filter, as well as block mode, to maximize user protection. Such a response header looks like this:
+
+我推荐永远打开 XSS 过滤器以及 block 模式,以求最大化保护用户。这样的响应头应该是这样的:
```
X-XSS-Protection: 1; mode=block
```
-Here’s how you would configure this response header in Node.js:
+以下是在 Node.js 中配置此响应头的方法:
-```
+```javascript
functionrequestHandler(req, res){
res.setHeader('X-XSS-Protection','1;mode=block');}
```
From d9d798c63b6ebe5e5b001cdc6323f7d10a4f6440 Mon Sep 17 00:00:00 2001
From: lsvih
Date: Wed, 12 Apr 2017 23:53:12 +0800
Subject: [PATCH 139/638] Update swift-lazy-initialization-with-closures.md
---
...swift-lazy-initialization-with-closures.md | 230 ++++++++++--------
1 file changed, 130 insertions(+), 100 deletions(-)
diff --git a/TODO/swift-lazy-initialization-with-closures.md b/TODO/swift-lazy-initialization-with-closures.md
index 051ab41f287..41885f1449f 100644
--- a/TODO/swift-lazy-initialization-with-closures.md
+++ b/TODO/swift-lazy-initialization-with-closures.md
@@ -1,23 +1,23 @@
-> * 原文地址:[Swift Lazy Initialization with Closures](https://blog.bobthedeveloper.io/swift-lazy-initialization-with-closures-a9ef6f6312c)
-> * 原文作者:[Bob Lee](https://blog.bobthedeveloper.io/@bobthedev)
-> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
-> * 译者:
+> * 原文地址:[Swift Lazy Initialization with Closures][1]
+> * 原文作者:[Bob Lee][2]
+> * 译文出自:[掘金翻译计划][3]
+> * 译者:[lsvih][4]
> * 校对者:
-# Swift Lazy Initialization with Closures #
+# 在 Swift 中使用闭包实现懒加载
-## Learn how to create objects with modularity and readability ##
+## 学习如何兼顾模块化与可读性来创建对象
![](https://cdn-images-1.medium.com/max/2000/1*KNmIy5QAOeokXPW86TtVyA.png)
-Magic Keyboard 2 and Magic Mouse 2
+(图为苹果的 Magic Keyboard 2 与 Magic Mouse 2)
-*Welcome my lovely readers. Good to see you here today. For those who are new, I’m Bob. Just for real quick, if you wish to be on my mailing list, you can sign up* [*here*](https://boblee.typeform.com/to/oR9Nt2) *and get more value for your learning with iOS development :)*
+*亲爱的读者你们好!我是 Bob,很高兴能在这篇文章中与你们相遇!如你想加入我的邮件列表,获取更多学习 iOS 开发的文章,请点击*[*这儿*][5]*注册,很快就能完成的哦 :)*
-### Motivation ###
+### 动机
-In the beginning of my iOS journey, I followed tutorials on YouTube. I saw a few using something like below to create UI objects.
+在我刚开始学习 iOS 开发的时候,我在 YouTube 上找了一个教程。我发现这个教程有时候会用下面这种方式来创建 UI 对象:
```
let makeBox: UIView = {
@@ -26,42 +26,42 @@ let makeBox: UIView = {
}()
```
-As a learner, I copied the practice and used it. One day, however, one of my readers asked me, “why do you add `{}` and why does `()` exist at the end? Is it a computed property?” I could not answer. I was a zombie.
+作为一个初学者,我自然而然地复制并使用了这个例子。直到有一天,我的一个读者问我:“为什么你要加上`{}`呢?最后为什么要加上一对`()`呢?这是一个计算属性吗?”我哑口无言,因为我自己也不知道答案。
-I wrote this tutorial for my younger self. Yet, some may find it useful.
+因此,我为过去年轻的自己写下了这份教程。说不定还能帮上其他人的忙。
-### Objectives ###
+### 目标
-There are three objectives. First, understand how to initialize an object using the unconventional way as shown above. Second, learn when to use `lazy var` in Swift. Last, join my mailing list.
+这篇教程有一下三个目标:第一,了解如何像前面的代码一样,非常规地创建对象;第二,知道编在写 Swfit 代码时,什么时候该使用 `lazy var`;第三,快加入我的邮件列表呀。
-#### Prerequisites ####
+#### 预备知识
-To fully enjoy the ride with me, I highly recommend you to be familiar with the topics below.
+为了让你能轻松愉快地和我一起完成这篇教程,我强烈推荐你先了解下面这几个概念。
-1. [*Closures*](https://blog.bobthedeveloper.io/no-fear-closure-in-swift-3-with-bob-72a10577c564)
-2. [*Capture List and retention cycle [weak self]*](https://blog.bobthedeveloper.io/swift-retention-cycle-in-closures-and-delegate-836c469ef128)
-3. *Descent Object Oriented Programming*
+1. [*闭包*][6]
+2. [*捕获列表与保留周期 \[weak self]*][7]
+3. *面向对象程序设计*
-### Create UI Components ###
+### 创建 UI 组件
-Before I explain the unconventional method above, let’s look into your past. In order to create a button in Swift, you probably have done something like this,
+在我介绍“非常规”方法之前,让我们先复习一下“常规”方法。在 Swift 中,如果你要创建一个按钮,你应该会这么做:
```
-// Determine Size
+// 设定尺寸
let buttonSize = CGRect(x: 0, y: 0, width: 100, height: 100)
-// Create Instance
+// 创建控件
let bobButton = UIButton(frame: buttonSize)
bobButton.backgroundColor = .black
bobButton.titleLabel?.text = "Bob"
bobButton.titleLabel?.textColor = .white
```
-This is *Okay.*
+这样做**没问题**。
-Assume, you have to create three other buttons, you probably have to copy the code above and then change the name from `bobButton` to `bobbyButton`.
+假设现在你要创建另外三个按钮,你很可能会把上面的代码复制,然后把变量名从 `bobButton` 改成 `bobbyButton`。
-It’s quite tedious.
+这未免也太单调了吧。
```
// New Button
@@ -71,13 +71,13 @@ bobbyButton.titleLabel?.text = "Bob"
bobbyButton.titleLabel?.textColor = .white
```
-To make things just a bit easier, you may
+为了方便,你可以:
![](https://cdn-images-1.medium.com/max/800/1*oDIPy0i4YzUnKVR4XYI4kg.gif)
-This works too with the keyboard shortcut: ctrl-cmd-e
+使用快捷键:ctrl-cmd-e 来完成这个工作。
-If you don’t wish to repeat yourself, you may create a function instead.
+如果你不想做重复的工作,你也可以创建一个函数。
```
func createButton(enterTitle: String) -> UIButton {
@@ -86,27 +86,26 @@ func createButton(enterTitle: String) -> UIButton {
button.titleLabel?.text = enterTitle
return button
}
-
createButton(enterTitle: "Yoyo") // 👍
```
-However, in iOS development, it is rare that custom buttons look similar. Therefore, a function may require a lot more parameters including background color, title, border radius, shadow, and so on. You function may end up looking like,
+然而,在 iOS 开发中,很少会看到一堆一模一样的按钮。因此,这个函数需要接受更多的参数,如背景颜色、文字、圆角尺寸、阴影等等。你的函数最后可能会变成这样:
```
func createButton(title: String, borderWidth: Double, backgrounColor, ...) -> Button
```
-The code above is not ideal even if you add default parameters to the function. It decreases readability. Therefore, it’s better to stay with the tedious method above.
+但是,上面的代码并不理想。即使你为这个函数加上了默认参数,它的可读性很差。因此,比起这个方法,我们还是采用上面那个”单调“的方法为妙。
-But, is there any way we can make it less tedious and more organized? Of course. We’ve looked into your past — It’s time to step up and look into your future.
+到底有没有办法让我们既不那么无聊,还能让代码更有条理呢?当然咯。我们现在只是复习你过去的做法——是时候更上一层楼,展望你未来的做法了。
-### Introducing the Unconventional Way ###
+### 介绍”非常规“方法
-Before we create UI components with the unconventional way, let’s first answer the initial questions my reader asked. What does `{}` mean, and is it a `computed property`?
+在我们使用”非常规“方法创建 UI 组件之前,让我们先回答一下最开始那个读者的问题。`{}`是什么意思,它是一个`计算属性`吗?
-*Nope, it’s just a* ***closure block***.
+*当然不是,它只是一个* ***闭包***。
-First, let’s demonstrate how to create an object using a closure. We will design a struct called `Human`.
+首先,让我来示范一下如何用闭包来创建一个对象。我们设计一个名为`Human`的结构:
```
struct Human {
@@ -116,7 +115,7 @@ struct Human {
}
```
-Now, this is how you create an object with a closure
+现在,让你看看怎么用闭包创建对象:
```
let createBob = { () -> Human in
@@ -127,11 +126,11 @@ let createBob = { () -> Human in
let babyBob = createBob() // "Born 1996"
```
-*If the syntax above doesn’t look familiar to you, you may stop reading now, and go to* [*Fear No Closure with Bob*](https://blog.bobthedeveloper.io/no-fear-closure-in-swift-3-with-bob-72a10577c564) *, and bring some bullets.*
+*如果你不熟悉这段语法,请先停止阅读这篇文章,去看看* [*Fear No Closure with Bob*][8] *充充电吧。*
-Just to explain, `createBob` is a closure whose type is `() -> Human`. You’ve created an instance called, `babyBob` by calling `createBob()` .
+解释一下,`createBob` 是一个类型为 `()-> Human` 的闭包。你已经通过调用 `createBob()` 创建好了一个 `babyBob` 实例。
-However, you had to create two constants: `createBob` and `babyBob`. What if you want to do everything in a single statement? Here you go.
+然而,这样做你创建了两个常量:`createBob` 与 `babyBob`。如何把所有的东西都放在一个声明中呢?请看:
```
let bobby = { () -> Human in
@@ -140,11 +139,11 @@ let bobby = { () -> Human in
}()
```
-Now, the closure block executes itself through adding `()` at the end and `bobby` now has a `Human` object attached. Pretty good stuff.
+现在,这个闭包通过在最后加上 `()` 执行了自己,`bobby` 现在附上了一个 `Human` 对象。干的漂亮!
-**You’ve learned how to initialize an object with a closure block.**
+**现在你已经学会了使用闭包来创建一个对象**
-Now, let’s apply to creating an UI object which should be similar to the example right above.
+让我们应用这个方法,模仿上面的例子来创建一个 UI 对象吧。
```
let bobView = { () -> UIView in
@@ -153,8 +152,7 @@ let bobView = { () -> UIView in
return view
}()
```
-
-Great, we can make it shorter. In fact, we don’t need to specify the type of the closure block. Instead, all we have to do is specify the type of the instance, `bobView`, for example.
+很好,我们还能让它更简洁。实际上,我们不需要为闭包指定类型,我们只需要指定 `bobView` 实例的类型就够了。例如:
```
let bobbyView: **UIView** = {
@@ -164,17 +162,17 @@ let bobbyView: **UIView** = {
}()
```
-Swift is able to infer that the closure block is `() -> UIView` based on the keyword, `return`.
+Swift 能够通过关键字 `return` 推导出这个闭包的类型是 `() -> UIView`。
-Now, take a look. The example right above should look identical to the “unconventional way” I feared.
+现在看看,上面的例子已经和我之前害怕的“非常规方式”一样了。
-### Benefits of Init with Closures ###
+### 使用闭包创建的好处
-We discussed the tediousness of creating objects and the problem that arises from using a function. In your head, you must be thinking, “why should I use a closure block instead?”
+我们已经讨论了:直接创建对象是很单调无聊的,使用函数构造是会出现问题的。现在你可能会想“为什么我非得用闭包来创建?”
-#### Easy to Duplicate ####
+#### 重复起来更容易
-I don’t like to use Storyboard, I love copy and pasting UI objects. In fact, I’ve a “library” of code in my computer. Let us assume that there is a button as shown below in the library.
+我不喜欢用 Storyboard,我比较喜欢复制粘贴 UI 对象。实际上,在我电脑里有一个“库”的代码。假设库里有个按钮,代码如下:
```
let myButton: UIButton = {
@@ -188,14 +186,14 @@ return button
}()
```
-All I have to do is copy the entire lines, and then just change the name of `myButton` to `newButton` for the usage. Had I not used the closure method, I probably had to change the name of `button` to `newButton` 7–8 times. We could use the Xcode shortcut above, but why not make it just simpler.
+我只需要把它整个复制,然后把名字从 `myButton` 改成 `newButtom` 就行了。在我用闭包之前,我得重复地把 `myButton` 改成 `newButtom` ,甚至要改上七八遍。我们虽然可以用 Xcode 的快捷键,但为啥不使用闭包,让这件事更简单呢?
-#### Look Cleaner ####
+#### 看起来更干净
-Since objects are grouped together, it feels cleaner based on my eyes. Let’s compare
+由于对象对象会自己编好组,在我看来它更加的干净。让我们对比一下:
```
-// Init with Closure
+// 使用闭包创建
let leftCornerButton: UIButton = {
let button = UIButton(frame: buttonSize)
button.backgroundColor = .black
@@ -220,7 +218,7 @@ return button
vs
```
-// Init With Fingers
+// 使用我的手指创建..
let leftCornerButton = UIButton(frame: buttonSize)
leftCornerButton.backgroundColor = .black
leftCornerButton.titleLabel?.text = "Button"
@@ -236,81 +234,81 @@ rightCornerButton.layer.cornerRadius =
rightCornerButton.layer.masksToBounds = true
```
-Although creating an object with the closure add a couple lines more, I feel less overwhelmed since I only have to add attributes to `button` rather than `rightCornerButton` or `leftCornerButton`.
+虽然使用闭包创建对象甚至还多出了一行,但是比起要在 `rightCornerButton` 或者 `leftCornerButton` 后面狂加属性,我还是更喜欢在 `button` 后面加属性。
-*In fact, if the name of a button gets more descriptive, often times it requires fewer lines to create an object with a closure block.*
+*实际上如果按钮的命名特别详细时,用闭包创建对象还可以少几行。*
-**You’ve accomplished the first objective. Congratulations**
+**恭喜你,你已经完成了我们的第一个目标**
-### Lazy Init Application ###
+### 懒加载的应用
-You’ve come a long way. It’s time to meet the second objective of this tutorial.
+辛苦了!现在让我们来看看这个教程的第二个目标把。
-You might have seen something like this below
+你可能看过与下面类似的代码:
```
class IntenseMathProblem {
- lazyvar complexNumber: Int = {
- // imagine it requires a lot of CPU
+ lazy var complexNumber: Int = {
+ // 请想象这儿要耗费很多CPU资源
1 * 1
}()
}
```
-What `lazy` allows you to do is, the `complexNumber` property will be only calculated when you try to access it. For example,
+`lazy` 的作用是,让 `complexNumber` 属性只有在你试图访问它的时候才会被计算。例如:
```
let problem = IntenseMathProblem
-problem() // No value for complexNumber
+problem() // 此时complexNumber没有值
```
-Currently, there is no value for `complexNumber`. However, once you access the property,
+没错,现在 `complexNumber` 没有值。然而,一旦你访问这个属性:
```
-problem().complexNumber // Now returns 1
+problem().complexNumber // 现在回返回1
```
-The `lazy var` is often used to sort database and fetch data from any backend services because you definitely don’t want to calculate and sort everything when you create an object.
+`lazy var` 经常用于数据库排序或者从后端取数据,因为你并不想在创建对象的时候就把所有东西都计算、排序。
-*In fact, your phone will crash since the object is super bloated and the RAM can’t handle.*
+*实际上,由于对象太大了导致 RAM 撑不住,你的手机就会崩溃。*
-### Application ###
+### 应用
-Below is just an application of `lazy var`.
+以下是 `lazy var` 的应用:
-#### Sorting ####
+#### 排序
```
class SortManager {
lazy var sortNumberFromDatabase: [Int] = {
- // Sorting logic
+ // 排序逻辑
return [1, 2, 3, 4]
}()
}
```
-#### Image Compression ####
+#### 图片压缩
```
class CompressionManager {
lazy var compressedImage: UIImage = {
let image = UIImage()
- // Compress the image
- // Logic
+ // 压缩图片的
+ // 逻辑
return image
}()
}
```
-### Rules with `Lazy` ###
+### `Lazy`的一些规定
-1. You can’t use `lazy` with `let` since there is no initial value, and it is attained later when it is accessed.
-2. You can’t use it with a `computed property` since computed property is always recalculated (requires CPU) when you modify any of the variables that has a relationship with the `lazy` property.
-3. `Lazy` is only valid for members of a struct or class
+1. 你不能把 `lazy` 和 `let` 一起用,因为用 `lazy` 时没有初值,只有当被访问时才会获得值。
+2. 你不能把它和 `计算属性` 一起用,因为在你修改任何与 `lazy` 的计算属性有关的变量时,计算属性都会被重新计算(耗费 CPU 资源)。
+3. `Lazy` 只能是结构或类的成员。
-### Does Lazy Capture? ###
+### Lazy 能被捕获吗?
-So, if you’ve read the previous article on [Retention Cycle in Closures and Delegate](https://blog.bobthedeveloper.io/swift-retention-cycle-in-closures-and-delegate-836c469ef128) , you might wonder. Let’s test it out. Create a class called `BobGreet`. It has two properties: `name` whose type is `String` and `greeting` whose type is also `String` but initialized with a closure block.
+如果你读过我的前一篇文章[《Swift 闭包和代理中的保留周期》][9],你就会明白这个问题。让我们试一试吧。创建一个名叫 `BobGreet` 的类,它有两个属性:一个是类型为 `String` 的 `name`,一个是类型为 `String` 但是使用闭包创建的 `greeting`。
```
class BobGreet {
@@ -320,43 +318,75 @@ class BobGreet {
}()
deinit {
- print("I'm gone, bruh 🙆")}
+ print("I'm gone, bruh 🙆")}
}
}
```
-The closure block *might* have a strong reference to `BobGuest` but let’s attempt to deallocate.
+闭包**可能**对 `BobGuest` 有强引用,让我们尝试着 deallocate 它。
```
var bobGreet: BobGreet? = BobClass()
bobGreet?.greeting
-bobClass = nil // I'm gone, bruh 🙆
+bobClass = nil // I'm gone, bruh 🙆
```
-No need to worry about `[unowned self]` The closure block does not have a reference to the object. Instead, it just copies `self` within the closure block. If you are confused by the previous statement, feel free to read [Swift Capture Lists](https://blog.bobthedeveloper.io/swift-capture-list-in-closures-e28282c71b95) to learn more. 👍
+不用担心 `[unowned self]`,闭包并没有对对象存在引用。相反,它仅仅是在闭包内复制了 `self`。如果你对前面的代码声明有疑问,放松一会儿,读读 [Swift Capture Lists][10] 来了解更多这方面的知识。👍
-### Last Remarks ###
+### 最后的唠叨
-I learned a quite a bit while preparing for this tutorial. I hope you did as well. I’d appreciate your genuine fat ❤️. But, there is just one more. As the last objective, if you wish to on my mailing list and receive greater value from me, you can sign up right [**here**](https://boblee.typeform.com/to/oR9Nt2) .
+我在准备这篇教程的过程中也学到了很多,希望你也一样。感谢你们的热情❤️!不过这篇文章还剩一点:我的最后一个目标。如果你希望加入我的邮件列表以获得更多有价值的信息的话,你可以点 [**这里**][11]注册。
-As you can see by the cover photo, I recently bought Magic Keyboard and Mouse. They are pretty good and increase my productivity a lot. You can get the mouse [here](http://amzn.to/2noHxgl) or the keyboard [here](http://amzn.to/2noHxgl). I never regret despite the price. 😓
+正如封面照片所示,我最近买了 Magic Keyboard 和 Magic Mouse。它们超级棒,帮我提升了很多的效率。你可以在 [这儿][12]买鼠标,在 [这儿][13]买键盘。我才不会因为它们的价格心疼呢。😓
-> [Source Code](https://github.com/bobthedev/Blog_Lazy_Init_with_Closures)
+> [本文的源码][14]
-### Swift Conference I Will Join ###
+### 我将要参加 Swift 讨论会
-I will be joining my first conference @[SwiftAveir](https://twitter.com/SwiftAveiro) o from June 1–2. A friend of mine, [Joao](https://twitter.com/NSMyself) , is helping organize the conference, so I’m super excited. You can learn more about the event [here](http://swiftaveiro.xyz) !
+我将在 6 月 1 日至 6 月 2 日 参加我有生以来的第一次讨论会 @[SwiftAveir][15], 我的朋友 [Joao][16]协助组织了这次会议,所以我非常 excited。你可以点[这儿][17]了解这件事 的详情!
-#### Recommended Articles ####
+#### 文章推荐
-> Intro to Functional Programming ([Blog](https://blog.bobthedeveloper.io/intro-to-swift-functional-programming-with-bob-9c503ca14f13))
+> 函数式编程简介 ([Blog][18])
-> My Favorite Xcode Shortcuts ([Blog](https://blog.bobthedeveloper.io/intro-to-swift-functional-programming-with-bob-9c503ca14f13) )
+> 我最爱的 XCode 快捷键 ([Blog][19] )
-### Bob the Developer ###
+### 关于我
-I’m an iOS instructor from Seoul, 🇰🇷. Feel free to get to know me on [Instagram](https://instagram.com/bobthedev) . I post regular updates on [Facebook Page](https://facebook.com/bobthedeveloper) and 🖨 on Sat 8pm EST.
+我是一名来自首尔的 iOS 课程教师,你可以在 [Instagram][20] 上了解我。我会经常在 [Facebook Page][21] 投稿,投稿时间一般在北京时间上午9点(Sat 8pm EST)。
---
-> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[React](https://github.com/xitu/gold-miner#react)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计) 等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)。
+> [掘金翻译计划][22] 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金][23] 上的英文分享文章。内容覆盖 [Android][24]、[iOS][25]、[React][26]、[前端][27]、[后端][28]、[产品][29]、[设计][30] 等领域,想要查看更多优质译文请持续关注 [掘金翻译计划][31]。
+
+[1]: https://blog.bobthedeveloper.io/swift-lazy-initialization-with-closures-a9ef6f6312c
+[2]: https://blog.bobthedeveloper.io/@bobthedev
+[3]: https://github.com/xitu/gold-miner
+[4]: https://github.com/lsvih
+[5]: https://boblee.typeform.com/to/oR9Nt2
+[6]: https://blog.bobthedeveloper.io/no-fear-closure-in-swift-3-with-bob-72a10577c564
+[7]: https://juejin.im/post/58e4ac5d44d904006d2a9a19
+[8]: https://blog.bobthedeveloper.io/no-fear-closure-in-swift-3-with-bob-72a10577c564
+[9]: https://juejin.im/post/58e4ac5d44d904006d2a9a19
+[10]: https://blog.bobthedeveloper.io/swift-capture-list-in-closures-e28282c71b95
+[11]: https://boblee.typeform.com/to/oR9Nt2
+[12]: http://amzn.to/2noHxgl
+[13]: http://amzn.to/2noHxgl
+[14]: https://github.com/bobthedev/Blog_Lazy_Init_with_Closures
+[15]: https://twitter.com/SwiftAveiro
+[16]: https://twitter.com/NSMyself
+[17]: http://swiftaveiro.xyz
+[18]: https://blog.bobthedeveloper.io/intro-to-swift-functional-programming-with-bob-9c503ca14f13
+[19]: https://blog.bobthedeveloper.io/intro-to-swift-functional-programming-with-bob-9c503ca14f13
+[20]: https://instagram.com/bobthedev
+[21]: https://facebook.com/bobthedeveloper
+[22]: https://github.com/xitu/gold-miner
+[23]: https://juejin.im
+[24]: https://github.com/xitu/gold-miner#android
+[25]: https://github.com/xitu/gold-miner#ios
+[26]: https://github.com/xitu/gold-miner#react
+[27]: https://github.com/xitu/gold-miner#%E5%89%8D%E7%AB%AF
+[28]: https://github.com/xitu/gold-miner#%E5%90%8E%E7%AB%AF
+[29]: https://github.com/xitu/gold-miner#%E4%BA%A7%E5%93%81
+[30]: https://github.com/xitu/gold-miner#%E8%AE%BE%E8%AE%A1
+[31]: https://github.com/xitu/gold-miner
From 69bca85e75f4b99b33c193c21f577db93622ee8b Mon Sep 17 00:00:00 2001
From: gy134340
Date: Thu, 13 Apr 2017 00:20:55 +0800
Subject: [PATCH 140/638] =?UTF-8?q?=E6=A0=A1=E5=AF=B9=E4=BF=AE=E6=94=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
...amming-in-javascript-composing-software.md | 74 +++++++++----------
1 file changed, 37 insertions(+), 37 deletions(-)
diff --git a/TODO/why-learn-functional-programming-in-javascript-composing-software.md b/TODO/why-learn-functional-programming-in-javascript-composing-software.md
index 3203cee2ce5..c260bf55297 100644
--- a/TODO/why-learn-functional-programming-in-javascript-composing-software.md
+++ b/TODO/why-learn-functional-programming-in-javascript-composing-software.md
@@ -4,29 +4,29 @@
> * 译者:
> * 校对者:
-# 为什么用 JavaScript 学习函数式编程?(组成化软件)(第二部分)
+# 为什么用 JavaScript 学习函数式编程?(软件构建)(第二部分)
烟雾的方块艺术 —MattysFlicks —(CC BY 2.0)
-> 注意:这是从基础学习函数式编程和使用 JavaScript ES6+ 组成软件的第一部分。保持关注,接下来还有很多!
+> 注意:这是从基础学习函数式编程和使用 JavaScript ES6+ 撰写软件的第二部分。保持关注,接下来还有很多!
> [从第一部分开始](https://medium.com/javascript-scene/the-rise-and-fall-and-rise-of-functional-programming-composable-software-c2d91b424c8c#.2dfd6n6qe) | [接下来的 >](https://medium.com/javascript-scene/a-functional-programmers-introduction-to-javascript-composing-software-d670d14ede30#.2e4youss2)
-忘了你认为知道的关于 JavaScript 的一切,用初学者的眼光去看待它。为了帮助你做到这一点,我们将会从头复习一下 JavaScript 的基础,就像你与其尚未谋面一样。如果你是初学者,那你就很幸运了。最终从零开始探索 ES6 和函数式编程!希望所有的概念都被解释清楚 — 但不要太依赖于此。
+忘掉你认为知道的关于 JavaScript 的一切,用初学者的眼光去看待它。为了帮助你做到这一点,我们将会从头复习一下 JavaScript 的基础,就像你与其尚未谋面一样。如果你是初学者,那你就很幸运了。最终从零开始探索 ES6 和函数式编程!希望所有的概念都被解释清楚 — 但不要太依赖于此。
如果你是已经熟悉 JavaScript 或者纯函数式语言的老开发者了,也许你会认为 JavaScript 是探索函数式编程有趣的选择。把这些想法放在一边,用更开放的思想接触它,你会发现 JavaScript 编程更高层次的东西。一些你从来不知道的东西。
-由于这个被称为“组成式软件”,同时函数式编程是明显的组成软件的方法(使用函数组合,高阶函数等等),你也许想知道为什么我不用 Haskell, ClojureScript,或者 Elm,而是 JavaScript。
+由于这个被称为“组合式软件”,同时函数式编程是明显的构建软件的方法(使用函数组合,高阶函数等等),你也许想知道为什么我不用 Haskell、ClojureScript,或者 Elm,而是 JavaScript。
JavaScript 有函数式编程所需要的最重要的特性:
-1. **一级函数:**使用函数作为数据值的能力:用函数传参,返回函数,用函数做变量和对象属性。这个属性允许更高级别的函数,使局部应用、柯里化和组合成为可能。
-2. **匿名函数和简介的 lambda 语法:**`x => x * 2` 是 JavaScript 中有效的函数表达式。简介的 lambda 语法使得它更好的跟高阶函数合作。
-3. **闭包:**闭包是一个有着自己独立作用域的捆绑函数。闭包在函数被创建时被创建。当一个函数在另一个函数内部被创建,它可以访问外部函数的变量,即使在外部函数退出后。闭包时使局部应用或者固定的参数。固定的参数时绑定在返回函数的作用域范围内的参数。在 `add2(1)(2)` 中,`1` 是 `add2(1)` 返回的函数中的固定参数。
+1. **一级公民函数:**使用函数作为数据值的能力:用函数传参,返回函数,用函数做变量和对象属性。这个属性允许更高级别的函数,使偏函数应用、柯里化和组合成为可能。
+2. **匿名函数和简洁的 lambda 语法:**`x => x * 2` 是 JavaScript 中有效的函数表达式。简洁的 lambda 语法使得高阶函数变的简单。
+3. **闭包:**闭包是一个有着自己独立作用域的捆绑函数。闭包在函数被创建时被创建。当一个函数在另一个函数内部被创建,它可以访问外部函数的变量,即使在外部函数退出后。通过闭包偏函数应用可以获取内部固定参数。固定的参数时绑定在返回函数的作用域范围内的参数。在 `add2(1)(2)` 中,`1` 是 `add2(1)` 返回的函数中的固定参数。
### JavaScript 缺少了什么
-JavaScript 是多范式语言,意味着它支持多种风格的编程。其他被 JavaScript 支持的风格包括过程式的(命令式)编程(比如 C),把函数看作可以被重复调用和组织的子程序指令;面向对象编程,对象 — 而不是函数 — 作为初始构造块;当然,还有函数式编程。多范式编程语言的劣性在于命令式和面向对象往往意味着所有东西都是可变的。
+JavaScript 是多范式语言,意味着它支持多种风格的编程。其他被 JavaScript 支持的风格包括过程式(命令式)编程(比如 C),把函数看作可以被重复调用和组织的子程序指令;面向对象编程,对象— 而不是函数— 作为初始构造块;当然,还有函数式编程。多范式编程语言的劣性在于命令式和面向对象往往意味着所有东西都是可变的。
可变性指的是数据结构上的变化。比如:
@@ -34,68 +34,68 @@ JavaScript 是多范式语言,意味着它支持多种风格的编程。其他
bar: 'baz'
};
- foo.bar = 'qux'; // mutation
+ foo.bar = 'qux'; // 改变
对象通常需要可变性以便于被方法更新值,在命令式的语言中,大部分的数据结构可变以便于数组和对象的高效操作。
下面是一些函数式语言拥有但是 JavaScript 没有的特性:
1. **纯粹性:**在一些函数式语言中,纯粹性是强制的,有副作用的表达式是不被允许的。
-2. **不可变性:**一些函数式语言不允许转变,采用表达式来产生新的数据结构来代替更改一个已存的数据结构,比如说数组或者对象。这样看起来可能不够搞笑,但是大多数函数式语言在引擎下使用 trie 数据结构,具有结构共享的特点:意味着旧的对象和新的对象是对相同数据的引用。
+2. **不可变性:**一些函数式语言不允许转变,采用表达式来产生新的数据结构来代替更改一个已存的数据结构,比如说数组或者对象。这样看起来可能不够高效,但是大多数函数式语言在引擎下使用 trie 数据结构,具有结构共享的特点:意味着旧的对象和新的对象是对相同数据的引用。
3. **递归:**递归是函数引用自身来进行迭代的能力。在大多数函数式语言中,递归是迭代的唯一方式,它们没有像 `for` 、`while`、`do` 这类循环语句。
**纯粹性:**在 JavaScript 中,纯粹性由约定来达成,如果你不是使用纯函数来构成你的大多数应用,那么你就不是在进行函数式风格的编程。很不幸,在 JavaScript 中,你很容易就会不小心创建和使用一些不纯的函数。
-**不可变性:**在纯函数式语言中,可变性通常是强制的,JavaScript 缺少函数式语言中高效的、基于 trie 树的数据结构,但是又一些你可以使用的库,包括 [Immutable.js](https://facebook.github.io/immutable-js/) 和 [Mori](https://github.com/swannodette/mori),真是期望未来的 ECMAScript 规范版本可以拥抱不可变数据结构。
+**不可变性:**在纯函数式语言中,不可变性通常是强制的,JavaScript 缺少函数式语言中高效的、基于 trie 树的数据结构,但是你可以使用一些库,包括 [Immutable.js](https://facebook.github.io/immutable-js/) 和 [Mori](https://github.com/swannodette/mori),由衷期望未来的 ECMAScript 规范版本可以拥抱不可变数据结构。
-有一些未来的迹象,比如说在 ES6 中添加了 `const` 关键字,`const` 声明的变量不能被重新赋值,知道 `const` 并不实际代表不可改变的值也很重要。
+有一些迹象带来了希望,比如说在 ES6 中添加了 `const` 关键字,`const` 声明的变量不能被重新赋值,重要的是要理解 `const` 所声明的值并不是不可改变的。
-`const` 声明的对象不能被重新声明为新的对象,但是对象的属性却是可变的,JavaScript 有 `freeze()` 对象的能力,但是这些对象只能在根实例上被冻结,意味着嵌套着的对象还是可以改变它的属性。换句话说,在 JavaScript 规范中看到真正的不可变还有很多路要走。
+`const` 声明的对象不能被重新声明为新的对象,但是对象的属性却是可变的,JavaScript 有 `freeze()` 对象的能力,但是这些对象只能在根实例上被冻结,意味着嵌套着的对象还是可以改变它的属性。换句话说,在 JavaScript 规范中看到真正的不可变还有很长的路要走。
-**递归:**JavaScript 支持递归,但是大多数函数式语言都有尾部调用优化的特性,尾部调用优化是一个允许递归的函数重用堆栈帧来递归调用的特性。
+**递归:**JavaScript 技术上支持递归,但是大多数函数式语言都有尾部调用优化的特性,尾部调用优化是一个允许递归的函数重用堆栈帧来递归调用的特性。
-没有尾部调用优化,一个调用的栈很可能没有边界导致堆栈溢出。JavaScript 在 ES6 规范中有一个有限的尾部调用优化。不幸的是,只有一个主要的浏览器引擎支持它,这个优化被部分应用随后从 Babel(最流行的 JavaScript 编译器,在旧的浏览器中被用来把 ES6 编译到 ES5)。
+没有尾部调用优化,一个调用的栈很可能没有边界导致堆栈溢出。JavaScript 在 ES6 规范中有一个有限的尾调用优化。不幸的是,只有一个主要的浏览器引擎支持它,这个优化被部分应用随后从 Babel(最流行的 JavaScript 编译器,在旧的浏览器中被用来把 ES6 编译到 ES5) 中移除。
-最后一行:现在使用递归来作为大的迭代还不是很安全 — 即使你很小心的调用尾部的函数。
+最重要的事实:现在使用递归来作为大的迭代还不是很安全 — 即使你很小心的调用尾部的函数。
-### 什么又是 JavaScript 所有但是纯函数式语言没有的
+### 什么又是 JavaScript 拥有但是纯函数式语言缺乏的
-一个纯粹主义者会告诉你 JavaScript 的可变性是它的重要缺点,这是事实。但是,引起的副作用和改变有时候很有用。事实上,不可能在规避所有副作用的情况下开发有用的现代应用。纯函数式语言比如说 Haskell 使用副作用,但是使用 monads 包来伪装纯函数,从而使程序保持纯净,尽管用 monads 所带来的副作用是不纯净的。
+一个纯粹主义者会告诉你 JavaScript 的可变性是它的重大缺点,这是事实。但是,引起的副作用和改变有时候很有用。事实上,不可能在规避所有副作用的情况下开发有用的现代应用。纯函数式语言比如说 Haskell 使用副作用,使用 monads 包将有副作用的函数伪装成纯函数,从而使程序保持纯净,尽管用 Monads 所带来的副作用是不纯净的。
-monads 的问题是,尽管它的使用很简单,但是对一个不是很熟悉它的人解释清楚它有点像对牛谈琴。
+Monads 的问题是,尽管它的使用很简单,但是对一个不是很熟悉它的人解释清楚它有点像“对牛谈琴”。
-> “monad 是 endofunctor 范畴的幺半群,有什么问题?” ~James Iry 所引用 Philip Wadler的话,解释一个 Saunders Mac Lane 说过的名言。[*“A Brief, Incomplete, and Mostly Wrong History of Programming Languages”*](http://james-iry.blogspot.com/2009/05/brief-incomplete-and-mostly-wrong.html)
+> “Monad说白了不过就是自函子范畴上的一个幺半群而已,这有什么难以理解的?” ~James Iry 所引用 Philip Wadler 的话,解释一个 Saunders Mac Lane 说过的名言。[*“编程语言简要、不完整之黑历史”*](http://james-iry.blogspot.com/2009/05/brief-incomplete-and-mostly-wrong.html)
-典型的,这是在调侃这有趣的一点。在上面的引用中,关于 monads 的解释相比最初的有了很大的简化,原来是下面这样:
+典型的,这是在调侃这有趣的一点。在上面的引用中,关于 Monads 的解释相比最初的有了很大的简化,原来是下面这样:
> “`X` 中的 monad 是其 endofunctor 范畴的幺半群,生成 endofunctor 和被 endofunctor 单位 set 组合所代替的 `X` ” ~ Saunders Mac Lane。 [*"Categories for the Working Mathematician"*](https://www.amazon.com/Categories-Working-Mathematician-Graduate-Mathematics/dp/0387984038//ref=as_li_ss_tl?ie=UTF8&linkCode=ll1&tag=eejs-20&linkId=de6f23899da4b5892f562413173be4f0)
-尽管这样,在我的观点看来,害怕 monads 是没有必要的,学习 monads 最好的方法不是去读关于它的一堆书和博客,而是立刻去使用它。对于大部分的函数式编程语言来说,晦涩的学术词汇比它实际概念难的多,相信我,你不必通过了解 Saunders Mac Lane 来了解函数式编程。
+尽管这样,在我的观点看来,害怕 Monads 是没有必要的,学习 Monads 最好的方法不是去读关于它的一堆书和博客,而是立刻去使用它。对于大部分的函数式编程语言来说,晦涩的学术词汇比它实际概念难的多,相信我,你不必通过了解 Saunders Mac Lane 来了解函数式编程。
-尽管它不是对所有的编程风格都完全的理想,JavaScript 无疑是作为适应各种编程风格和背景的人的通用编程语言被设计出来的。
+尽管它不是对所有的编程风格都绝对完美,JavaScript 无疑是作为适应各种编程风格和背景的人的通用编程语言被设计出来的。
根据 [Brendan Eric](https://brendaneich.com/2008/04/popularity/) 所言,在一开始的时候,网景公司就有意适应两类开发者:
> “...写组件的,比如说 C++ 或者 Java;写脚本的、业余的和爱好者,比如直接写嵌在 HTML 里的代码的。”
-最初,网景公司的意向是支持两种不同的语言,同时脚本语言大致要像 Scheme (一个 Lisp 的方言),而且,Brendan Eich:
+本来,网景公司的意向是支持两种不同的语言,同时脚本语言大致要像 Scheme (一个 Lisp 的方言),而且,Brendan Eich:
> “我被招聘到网景公司,目的是在浏览器中 **做一些 Scheme**”。
JavaScript 应当是一门新的语言:
-> “上面工程管理的命令是这门语言**应当像 Java**,这就排除了 Perl,Python,和 Tcl,以及 Scheme。”
+> “上级工程管理的命令是这门语言**应当像 Java**,这就排除了 Perl,Python,和 Tcl,以及 Scheme。”
所以,Brendan Eich 最初脑子里的想法是:
1. 浏览器中的 Scheme。
2. 看起来像 Java。
-最终的结果稍微有点复杂:
+它最终更像是个大杂烩:
->“我不骄傲,但我很高兴我选择了 Scheme 的一类函数和 Self(尽管奇怪)的原型作为主要的元素。”由于 Java 的影响,特别是 y2k 的 Date 问题以及对象的区别(比如string 和 String),就不幸了。”
+>“我不骄傲,但我很高兴我选择了 Scheme 的一类函数和 Self(尽管奇怪)的原型作为主要的元素。”由于 Java 的影响,特别是 y2k 的 Date 问题以及对象的区别(比如 string 和 String),就不幸了。”
-我列出了这些 “不好的” 的类 Java 特性,最后转换成 JavaScript:
+我列出了这些 “不好的” 的类 Java 特性,最后整理成 JavaScript:
* 构造函数和 `new` 关键子,跟工厂函数有着不同的调用和使用语义。
* `class` 的关键字和单一父类 `extends` 作为最初的继承机制。
@@ -107,31 +107,31 @@ JavaScript 应当是一门新的语言:
我们最终创作了一个直接被浏览器支持的语言:JavaScript。
-那意味着浏览器可以减少臃肿和问题,因为它们现在只需要支持一种语言:JavaScript。你也许认为 WebAssembly 是异常,但是 WebAssembly 设计之初的目的是使用兼容的抽象语法树来共享JavaScript的语言绑定(AST)。事实上,最早的把 WebAssembly 编译成 JavaScript 的子集的示范是 ASM.js。
+那意味着浏览器可以减少臃肿和问题,因为它们现在只需要支持一种语言:JavaScript。你也许认为 WebAssembly 是例外,但是 WebAssembly 设计之初的目的是使用兼容的抽象语法树来共享 JavaScript 的语言绑定(AST)。事实上,最早的把 WebAssembly 编译成 JavaScript 的子集的示范是 ASM.js。
作为 web 平台唯一的通用标准编程语言,JavaScript 在软件历史潮流中乘风直上:
App 吞食世界, web 吞食 app, 同时 JavaScript 吞食 web。
-根据[各方](http://redmonk.com/sogrady/2016/07/20/language-rankings-6-16/)[调查](http://stackoverflow.com/research/developer-survey-2016),[JavaScript](https://octoverse.github.com/)是目前世界上最流行的语言。
+根据[多个平台](http://redmonk.com/sogrady/2016/07/20/language-rankings-6-16/)[调查](http://stackoverflow.com/research/developer-survey-2016),[JavaScript](https://octoverse.github.com/) 是目前世界上最流行的语言。
-JavaScript 并不是函数式编程的理想化工具,但是它却是为大型的分布式的团队开发大型应用的好工具,因为不同的团队也许有不同建立应用的想法。
+JavaScript 并不是函数式编程的理想化工具,但是它却是为大型的分布式的团队开发大型应用的好工具,因为不同的团队对于如何构建一个应用或许有不同的看法。
一些团队致力于脚本化,那么命令式的编程就特别有用,另外一些更精于抽象架构,那么一点保留的面向对象方法也许不失为坏。还有一些拥抱函数式编程,使用纯函数来确保稳定性、可测试性和项目状态管理以便减少用户的反馈。团队里的这些人可以使用相同的语言,意味着他们可以更好的交换想法,互相学习和在其他人的基础上更进一步的开发。
在 JavaScript 中,所有这些想法可以共存,这样就让更多的人开始拥抱 JavaScript,然后就产生了[世界上最大的开源包管理器](http://www.modulecounts.com/) (2017 年 2 月),[npm](https://www.npmjs.com/)。
-JavaScript 的真正优势在于其生态系统中的思想和用户的多样性。它也许不是纯函数式编程的理想语言,但它是你可以想象的工作在不同平台的人共同合作的理想语言,比如说 Java、Lisp 或者 C。JavaScript 也许对这些有这些背景的用户完全友好,但是这些人很乐意学习这门语言并迅速投入生产。
+JavaScript 的真正优势在于其生态系统中的思想和用户的多样性。它也许不是纯函数式编程最理想的语言,但它是你可以想象的工作在不同平台的人共同合作的理想语言,比如说 Java、Lisp 或者 C。JavaScript 也许并不对有这些背景的用户完全友好,但是这些人很乐意学习这门语言并迅速投入生产。
-我同意 JavaScript 并不是函数式编程着最好的语言。但是,没有任何其他语言可以声称他们可以被所有人使用,同时正如 ES6 所述:JavaScript 可以满足到更与喜欢函数式编程的人的需要,同时也越来越好。相比于抛弃 JavaScript 和它不可思议的被世界上所有公司使用的生态系统,为什么不拥抱它,把它变成一个更适合软件组成化的语言?
+我同意 JavaScript 并不是对函数式编程者最好的语言。但是,没有任何其他语言可以声称他们可以被所有人使用,同时正如 ES6 所述:JavaScript 可以满足到更与喜欢函数式编程的人的需要,同时也越来越好。相比于抛弃 JavaScript 和世界上几乎每家公司都使用的令人难以置信的生态系统,为什么不拥抱它,把它变成一个更适合软件组合化的语言?
-现在,JavaScript 已经是一门足够优秀的函数式编程语言,意味着人们可以使用 JavaScript 的函数式编程方法来构造所有有趣的和有用的东西。Netflix(和其他使用 Angular 2+ 的应用)使用基于 RxJS 的函数式功能。[Facebook](https://github.com/facebook/react/wiki/sites-using-react)在 React 中使用纯函数、高阶函数和高级组件来开发 Facebook 和 Instagram,[PayPal, KhanAcademy, and Flipkart](https://github.com/reactjs/redux/issues/310)使用 Redux 来进行状态管理。
+现在,JavaScript 已经是一门**足够优秀**的函数式编程语言,意味着人们可以使用 JavaScript 的函数式编程方法来构造很多有趣的和有用的东西。Netflix(和其他使用 Angular 2+ 的应用)使用基于 RxJS 的函数式功能。[Facebook](https://github.com/facebook/react/wiki/sites-using-react)在 React 中使用纯函数、高阶函数和高级组件来开发 Facebook 和 Instagram,[PayPal、KhanAcademy、和Flipkart](https://github.com/reactjs/redux/issues/310)使用 Redux 来进行状态管理。
-它们并不孤单:Angular、React、Redux 和 Lodash 是 JavaScript 生态系统中主要的框架和库,同时它们都被函数式编程很深的影响到 — 或者在 Lodash 和 Redux中,明确的表达是为了在实际的 JavaScript 应用中使用函数式编程模式。
+它们并不孤单:Angular、React、Redux 和 Lodash 是 JavaScript 生态系统中主要的框架和库,同时它们都被函数式编程很深的影响到— 在 Lodash 和 Redux 中,明确地表达是为了在实际的 JavaScript 应用中使用函数式编程模式。
-“为什么是 JavaScript?”因为实际上所有的软件呢公司用来开发软件的语言。无论如何,JavaScript 从 Lisp 这个数十年来的标志头上偷取了 “最受欢迎的函数式编程语言” 的头衔。事实上,Haskell 更适合当今函数式编程概念的标准,但是人们并不使用它来开发实际应用。
+“为什么是 JavaScript?”因为 JavaScript 是实际上大多数公司开发真实的软件所使用的语言。无论你对它是爱是恨,JavaScript 已经取代了 Lisp 这个数十年来 “最受欢迎的函数式编程语言”。事实上,Haskell 更适合当今函数式编程概念的标准,但是人们并不使用它来开发实际应用。
-在任何时候,在美国都有一百万的 JavaScript 工作需求,世界其他地方也有数百万的量。学习 Haskell 可以帮助你很好的学习函数式编程,但学习 JavaScript 将会教会你在实际工作中开发应用。
+在任何时候,在美国都有近十万的 JavaScript 工作需求,世界其他地方也有数十万的量。学习 Haskell 可以帮助你很好的学习函数式编程,但学习 JavaScript 将会教会你在实际工作中开发应用。
App 正在吞食世界, web 正在吞食 app, 同时 JavaScript 正在吞食 web。
From c019bf6346020a777f1149e030de6607bf819294 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=90=B4=E6=99=93=E5=86=9B?=
Date: Thu, 13 Apr 2017 00:42:01 +0800
Subject: [PATCH 141/638] functors & category
---
TODO/functors-categories.md | 173 ++++++++++++++++++------------------
1 file changed, 88 insertions(+), 85 deletions(-)
diff --git a/TODO/functors-categories.md b/TODO/functors-categories.md
index a5b81f432c4..31ee4219b6f 100644
--- a/TODO/functors-categories.md
+++ b/TODO/functors-categories.md
@@ -1,120 +1,121 @@
> * 原文地址:[Functors & Categories](https://medium.com/javascript-scene/functors-categories-61e031bac53f)
> * 原文作者:[Eric Elliott](https://medium.com/@_ericelliott?source=post_header_lockup)
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
-> * 译者:
+> * 译者:[yoyoyohamapi](https://github.com/yoyoyohamapi) [reid3290](https://github.com/reid3290)
> * 校对者:
-# Functors & Categories #
-
-## Composable Software ##
+# Functor 与 Category (软件编写)(第五部分)#
-Smoke Art Cubes to Smoke — MattysFlicks — (CC BY 2.0)
-> Note: This is part of the “Composing Software” series on learning functional programming and compositional software techniques in JavaScript ES6+ from the ground up. Stay tuned. There’s a lot more of this to come!
-> [< Previous](https://medium.com/javascript-scene/reduce-composing-software-fe22f0c39a1d#.w4y0mlpcs) | [<< Start over at Part 1](https://medium.com/javascript-scene/the-rise-and-fall-and-rise-of-functional-programming-composable-software-c2d91b424c8c#.2dfd6n6qe)
+Smoke Art Cubes to Smoke — MattysFlicks — (CC BY 2.0) (译注:该图是用 PS 将烟雾处理成方块状后得到的效果,参见 [flickr](https://www.flickr.com/photos/68397968@N07/11432696204)。))
+
+> 注意:这是 “软件编写” 系列文章的第四部分,该系列主要阐述如何在 JavaScript ES6+ 中从零开始学习函数式编程和组合化软件(compositional software)技术(译注:关于软件可组合性的概念,参见维基百科 [Composability](https://en.wikipedia.org/wiki/Composability))。后续还有更多精彩内容,敬请期待!
+> [<上一篇](https://medium.com/javascript-scene/reduce-composing-software-fe22f0c39a1d#.w4y0mlpcs) | [<< 返回第一章](https://medium.com/javascript-scene/the-rise-and-fall-and-rise-of-functional-programming-composable-software-c2d91b424c8c#.2dfd6n6qe)
-A **functor** is something that can be mapped over. In other words, it’s a container which has an interface which can be used to apply a function to the values inside it. When you see the word functor, you should think *“mappable”.*
+所谓 **functor(函子)**,是能够对其进行 map 操作的对象。换言之,**functor** 可以被认为是一个容器,该容器容纳了一个值,并且暴露了一个接口(译注:即 map 接口),该接口使得外界的函数能够操纵容器中的值。所以当你见到 **functor**,别被其来自范畴学的名字唬住,简单把他当做个 *“mappable”* 对象就行。
-The term “functor” comes from category theory. In category theory, a functor is a mapping between categories. Loosely, a **category** is a group of things, where each “thing” can be any value. In code, a functor is sometimes represented as an object with a `.map()` method that maps from one set of values to another.
+**“functor”** 一词源于范畴学。在范畴学中,一个 functor 代表了两个范畴(category)间的映射。简单说来,一个 **范畴** 是一系列事物的分组,这里的 “事物” 可以指代一切的值。对于编码来说,一个 functor 通常代表了一个具有 `.map()` 方法的对象,该方法能够将某一集合映射到另一集合。
-A functor supplies a box with zero or more things inside, and a mapping interface. An array is a good example of a functor, but many other kinds of objects can be mapped over as well, including single valued-objects, streams, trees, objects, etc…
+上文说到,一个 functor 可以被看做是一个容器,比如我们将其看做是一个盒子,盒子里面容纳了一些事物,或者空空如也,最重要的是,盒子暴露了一个 mapping(映射)接口。在 JavaScript 中,数组对象就是 functor 的绝佳例子(译注:`[1,2,3].map(x => x + 1)`),但是,其他类型的对象,只要能够被 map 操作,也可以算作是 functor,这些对象包括了单值对象(single valued-objects),流(streams),树(trees),对象(objects)等等。
-For collections (arrays, streams, etc…), `.map()` typically iterates over the collection and applies the given function to each value in the collection, but not all functors iterate.
+对于如数组和流这样的集合(collections)来说,`.map()` 方法指的是,在集合上进行迭代操作,在此过程中,应用一个预先指定的函数对每次迭代到的值进行处理。但是,不是所有的 functor 都可以被迭代。
-In JavaScript, Arrays and Promises are functors (`.then()` obeys the functor laws), but lots of libraries exist that will turn a variety of other things into functors, too.
+在 JavaScript 中,数组和 Promise 对象都是 **functor**(Promise 对象虽然没有 `.map()` 方法,但其 `.then()` 方法也遵从 functor 的定律),除此之外,非常多的第三方库也能够将各种各样的一般事物给转换成 functor(译注:大名鼎鼎的 [Bluebird](https://github.com/petkaantonov/bluebird/) 就能将异步过程封装为 Promise functor)。
-In Haskell, the functor type is defined as:
+在 Haskell 中,functor 类型被定义为如下形式:
```
fmap :: (a -> b) -> f a -> f b
```
-Given a function that takes an `a` and returns a `b` and a functor with zero or more `a`s inside it: `fmap` returns a box with zero or more `b`s inside it. The `f a` and `f b` bits can be read as “a functor of `a`” and “a functor of `b`”, meaning `f a` has `a`s inside the box, and `f b` has `b`s inside the box.
+fmap 接受一个函数参数,该函数接受一个参数 `a`,并返回一个 `b`,最终,fmap 完成了从 `f a` 到 `f b` 的映射。`f a` 及 `f b` 可以被读作 “一个 `a` 的 functor” 和“一个 `b` 的 functor”,亦即 `f a` 这个盒子容纳了 `a`,`f b` 这个盒子容纳了 `b`。
-Using a functor is easy — just call `map()`:
+使用一个 functor 是非常简单的,仅需要调用 `map()` 方法即可:
```
const f = [1, 2, 3];
f.map(double); // [2, 4, 6]
```
-### Functor Laws ###
+### Functor 定律 ###
-Categories have two important properties:
+一个范畴含有两个基本的定律:
-1. Identity
-2. Composition
+1. 同一性(Identity)
+2. 组合性(Composition)
-Since a functor is a mapping between categories, functors must respect identity and composition. Together, they’re known as the functor laws.
+由于 functor 是两个范畴间的映射,其就必须遵守同一性和组合性,二者也构成了 functor 的基本定律。
-### Identity ###
+### 同一性 ###
-If you pass the identity function (`x => x`) into `f.map()`, where `f` is any functor, the result should be equivalent to (have the same meaning as) `f`:
+如果你将函数(`x => x`)传入 `f.map()`,并且,`f` 是任意的一个 functor,那么 `f.map()` 执行结果就等于 `f`。
```
const f = [1, 2, 3];
f.map(x => x); // [1, 2, 3]
```
-### Composition ###
+### 组合性 ###
-Functors must obey the composition law: `F.map(x => f(g(x)))` is equivalent to `F.map(g).map(f)`.
+functor 还必须具有组合性:`F.map(x => f(g(x))) == F.map(g).map(f)`
-Function Composition is the application of one function to the result of another, e.g., given an `x` and the functions, `f` and `g`, the composition `(f ∘ g)(x)` (usually shortened to `f ∘ g` - the `(x)` is implied) means `f(g(x))`.
+函数组合是将一个函数的输出作为另一个函数输入的过程。例如,给定一个值 `x`及函数 `f` 和函数 `g`,函数的组合就是 `(f ∘ g)(x)`(通常简写为 `f ∘ g`,简写形式已经暗示了 `(x)`),其意味着 `f(g(x))`。
-A lot of functional programming terms come from category theory, and the essence of category theory is composition. Category theory is scary at first, but easy. Like jumping off a diving board or riding a roller coaster. Here’s the foundation of category theory in a few bullet points:
+很多函数式编程的术语都源于范畴学,而范畴学的实质即是组合。初看范畴学,就像初次进行高台跳水或者乘坐过山车,慌张,恐惧,但是并不难完成。你只需明确下面几个范畴学基础要点:
-- A category is a collection of objects and arrows between objects (where “object” can mean literally anything).
-- Arrows are known as morphisms. Morphisms can be thought of and represented in code as functions.
-- For any group of connected objects, `a -> b -> c`, there must be a composition which goes directly from `a -> c`.
-- All arrows can be represented as compositions (even if it’s just a composition with the object’s identity arrow). All objects in a category have identity arrows.
+- 一个范畴(category)是一个容纳了一系列对象及对象间箭头(`->`)的集合。
+- 箭头只是形式上的描述,实际上,箭头代表了态射(morphismms)。在编程中,态射可以被认为是函数。
+- 对于任何被箭头相连接的对象,如 `a -> b -> c`,必须存在一个 `a -> c ` 的组合。
+- 所有的箭头表示都代表了组合(即便这个对象间的组合只是一个同一(identity)箭头:`a->c`)。所有的对象都存在一个同一箭头,即存在同一态射(`a -> a`)。
-Say you have a function `g` that takes an `a` and returns a `b`, and another function `f` that takes a `b` and returns a `c`; there must also be a function `h` that represents the composition of `f` and `g`. So, the composition from `a -> c`, is the composition `f ∘ g` (`f`*after*`g`). So, `h(x) = f(g(x))`. Function composition works right to left, not left to right, which is why `f ∘ g` is frequently called `f`*after*`g`.
+如果你有一个函数 `g`,该函数接受一个参数 `a` 并且返回一个 `b`,另一个函数 `f` 接受一个 `b` 并返回一个 `c`。那么,必然存在一个函数 `h`,其代表了 `f` 及 `g` 的组合。而 `a -> c` 的组合,就是 `f ∘ g`(读作`f` **紧接着** `g`),进而,也就知 `h(x)=f(g(x))`。函数组合的方向是由右向左的,这也就是就是 `f ∘ g` 常被叫做 `f` **紧接着** `g` 的原因。
-Composition is associative. Basically that means that when you’re composing multiple functions (morphisms if you’re feeling fancy), you don’t need parenthesis:
+函数组合是满足结合律的,这就意味着你在组合多个函数时,免去了添加括号的烦恼:
```
h∘(g∘f) = (h∘g)∘f = h∘g∘f
```
-Let’s take another look at the composition law in JavaScript:
+让我们再看一眼 JavaScript 中组合律:
-Given a functor, `F`:
+给定一个 functor,`F`:
```
const F = [1, 2, 3];
```
-The following are equivalent:
+下面的两段是等效的:
```
F.map(x => f(g(x)));
-// is equivalent to...
+// 等效于。。。
F.map(g).map(f);
```
-### Endofunctors ###
+> 译注:functor 中函数组合的结合率可以被理解为:对 functor 中保存的值使用组合后的函数进行 map,等效于先后对该值用不同的函数进行 map。
+
+### Endofunctors(自函子) ###
-An endofunctor is a functor that maps from a category back to the same category.
+一个 endofunctor(自函子)是一个能将一个范畴映射回相同范畴的 functor。
-A functor can map from category to category: `F a -> F b`
+一个 functor 能够完成任意范畴间映射: `F a -> F b`
-An endofunctor maps from a category to the same category: `F a -> F a`
+一个 endofunctor 能够完成相同范畴间的映射:`F a -> F a`
-`F` here represents a *functor type* and `a` represents a category variable (meaning it can represent any category, including a set or a category of all possible values in a data type).
+在这里,`F` 代表了一个 **functor 类型**,而 `a` 代表了一个范畴变量(意味着其能够代表任意的范畴,无论是一个集合,还是一个包含了某一数据类型所有可能取值的范畴)。
-A monad is an endofunctor. Remember:
+而一个 monad 则是一个 endofunctor,先记住下面这句话:
-> *“A monad is just a monoid in the category of endofunctors. What’s the problem?”*
+> “monad 是 endofunctor 范畴的 monoids(幺半群),有什么问题?”(译注:这句话的出处在该系列第一篇已有提及)
-Hopefully that quote is starting to make a little more sense. We’ll get to monoids and monads later.
+现在,我们希望第一篇提及的这句话能在之后多一点意义,monoids(幺半群)及 monad 将在之后作介绍。
-### Build Your Own Functor ###
+### 自定义一个 Functor ###
-Here’s a simple example of a functor:
+下面将展示一个简单的 functor 例子:
```
const Identity = value => ({
@@ -122,11 +123,11 @@ const Identity = value => ({
});
```
-As you can see, it satisfies the functor laws:
+显然,其满足了 functor 定律:
```
-// trace() is a utility to let you easily inspect
-// the contents.
+// trace() 是一个简单的工具函数来帮助审查内容
+// 内容
const trace = x => {
console.log(x);
return x;
@@ -134,14 +135,14 @@ const trace = x => {
const u = Identity(2);
-// Identity law
+// 同一性
u.map(trace); // 2
u.map(x => x).map(trace); // 2
const f = n => n + 1;
const g = n => n * 2;
-// Composition law
+// 组合性
const r1 = u.map(x => f(g(x)));
const r2 = u.map(g).map(f);
@@ -149,11 +150,11 @@ r1.map(trace); // 5
r2.map(trace); // 5
```
-Now you can map over any data type, just like you can map over an array. Nice!
+现在,你可以对存在该 functor 中的任何数据类型进行 map 操作,就像你对一个数组进行 map 时那样。这简直太美妙了。
-That’s about as simple as a functor can get in JavaScript, but it’s missing some features we expect from data types in JavaScript. Let’s add them. Wouldn’t it be cool if the `+` operator could work for number and string values?
+上面的代码片展示了 JavaScript 中 functor 的简单实现,但是其缺失了 JavaScript 中常见数据类型的一些特性。现在我们逐个添加它们。首先,我们会想到,假如能够直接通过 `+` 操作符操作我们的 functor 是不是太好了,就像我们在数值或者字符串对象间使用 `+` 号那样。
-To make that work, all we need to do is implement `.valueOf()` -- which also seems like a convenient way to unwrap the value from the functor:
+为了使该想法变现,我们首先要为该 functor 对象添加 `.valueOf()` 方法 —— 这可被看作是提供了一个便捷的渠道来将值从 functor 盒子中取出。
```
const Identity = value => ({
@@ -169,13 +170,13 @@ const hi = (Identity('h') + Identity('i'));
trace(hi); // "hi"
```
-Nice. But what if we want to inspect an `Identity` instance in the console? It would be cool if it would say `"Identity(value)"`, right. Let's add a `.toString()` method:
+现在代码更漂亮了。但是如果我们还想要在控制台审查 `Identity` 实例呢?如果控制台能够输出 `"Identity(value)"` 就太好了,为此,我们只需要添加一个 `.toString()` 方法即可(译注:亦即重载原型链上原有的 `.toString()` 方法):
```
toString: () => `Identity(${value})`,
```
-Cool. We should probably also enable the standard JS iteration protocol. We can do that by adding a custom iterator:
+代码又有所进步。现在,我们可能也想 functor 能够满足标准的 JavaScript 迭代协议(译注:[MDN - 迭代协议](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Iteration_protocols))。为此,我们可以为 `Identity` 添加一个自定义的迭代器:
```
[Symbol.iterator]: () => {
@@ -197,7 +198,7 @@ Cool. We should probably also enable the standard JS iteration protocol. We can
},
```
-Now this will work:
+现在,我们的 functor 还能这样工作:
```
// [Symbol.iterator] enables standard JS iterations:
@@ -205,28 +206,30 @@ const arr = [6, 7, ...Identity(8)];
trace(arr); // [6, 7, 8]
```
-What if you want to take an `Identity(n)` and return an array of Identities containing `n + 1`, `n + 2`, and so on? Easy, right?
+假如你想借助 `Identity(n)` 来返回包含了 `n+1`,`n+2` 等等的 Identity 数组,这非常容易:
```
const fRange = (
start,
end
) => Array.from(
- { length: end - start + 1 },
+ {length: end - start + 1},
(x, i) => Identity(i + start)
);
```
-Ah, but what if you want this to work with any functor? What if we had a spec that said that each instance of a data type must have a reference to its constructor? Then you could do this:
+> 译注:[MDN -- Array.from()](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/from)
+
+但是,如果你想上面的操作方式能够应用于任何 functor,该怎么办?假如我们规定了每种数据类型对应的实例必须有一个关于其构造函数的引用,那么你可以这样改造之前的逻辑:
```
const fRange = (
start,
end
) => Array.from(
- { length: end - start + 1 },
+ {length: end - start + 1},
- // change `Identity` to `start.constructor`
+ // 将 `Identity` 变更为 `start.constructor`
(x, i) => start.constructor(i + start)
);
@@ -234,7 +237,7 @@ const range = fRange(Identity(2), 4);
range.map(x => x.map(trace)); // 2, 3, 4
```
-What if you want to test to see if a value is a functor? We could add a static method on `Identity` to check. We should throw in a static `.toString()` while we're at it:
+假如你还想知道一个值是否在一个 functor 中,又怎么办?我们可以为 `Identity` 添加一个静态方法 `.is()` 来进行检测,另外,我们也顺便添加了一个静态的 `.toString()` 方法来告知这个 functor 的种类:
```
Object.assign(Identity, {
@@ -243,7 +246,8 @@ Object.assign(Identity, {
});
```
-Let’s put all this together:
+
+现在,我们整合一下上面的代码片:
```
const Identity = value => ({
@@ -280,14 +284,14 @@ Object.assign(Identity, {
});
```
-Note you don’t need all this extra stuff for something to qualify as a functor or an endofunctor. It’s strictly for convenience. All you *need* for a functor is a `.map()` interface that satisfies the functor laws.
+注意,无论是 functor,还是 endofunctor,不一定需要上述那么多的条条框框。以上工作只是为了我们在使用 functor 时更加便捷,而非必须。一个 functor 的所有需求只是一个满足了 functor 定律 `.map()` 接口。
-### Why Functors? ###
+### 为什么要使用 functor? ###
-Functors are great for lots of reasons. Most importantly, they’re an abstraction that you can use to implement lots of useful things in a way that works with any data type. For instance, what if you want to kick off a chain of operations, but only if the value inside the functor is not `undefined` or `null`?
+说 functor 多么多么好是不无理由的。最重要的一点是,functor 作为一种抽象,能让开发者以同一种方式实现大量有用的,能够操纵任何数据类型的事物。例如,如果你想要在 functor 中值不为 `null` 或者不为 `undefined` 前提下,构建一串地链式操作:
```
-// Create the predicate
+// 创建一个 predicte
const exists = x => (x.valueOf() !== undefined && x.valueOf() !== null);
const ifExists = x => ({
@@ -297,9 +301,9 @@ const ifExists = x => ({
const add1 = n => n + 1;
const double = n => n * 2;
-// Nothing happens...
+// undefined
ifExists(Identity(undefined)).map(trace);
-// Still nothing...
+// null
ifExists(Identity(null)).map(trace);
// 42
@@ -310,9 +314,9 @@ ifExists(Identity(20))
;
```
-Of course, functional programming is all about composing tiny functions to create higher level abstractions. What if you want a generic map that works with any functor? That way you can partially apply arguments to create new functions.
+函数式编程一直探讨的是将各个小的函数进行组合,以创建出更高层次的抽象。假如你想要一个更通用的,能够工作在任何 functor 上的 `map()` 方法,那么你可以通过参数的部分应用(译注:即 [偏函数](https://en.wikipedia.org/wiki/Partial_application))来完成。
-Easy. Pick your favorite auto-curry, or use this magic spell from before:
+你可以使用自己喜欢的 curry 化方法(译注:Underscore,Lodash,Ramda 等第三方库都提供了 curry 化一个函数的方法),或者使用下面这个之前篇章提到的,基于 ES6 的,充满魅力的 curry 化方法来实现参数的部分应用:
```
const curry = (
@@ -324,7 +328,7 @@ const curry = (
)([...arr, ...args]);
```
-Now we can customize map:
+现在,我们可以自定义 `map()` 方法:
```
const map = curry((fn, F) => F.map(fn));
@@ -335,28 +339,27 @@ const mdouble = map(double);
mdouble(Identity(4)).map(trace); // 8
```
-### Conclusion ###
+### 总结 ###
-Functors are things we can map over. More specifically, a functor is a mapping from category to category. A functor can even map from a category back to the same category (i.e., an *endofunctor*).
+functor 是能够对其进行 map 操作的对象。更进一步地,一个 functor 能够将一个范畴映射到另一个范畴。一个 functor 甚至可以将某一范畴映射回相同范畴(例如 endofunctor)。
-A category is a collection of objects, with arrows between objects. Arrows represent morphisms (aka functions, aka compositions). Each object in a category has an identity morphism (`x => x`). For any chain of objects `A -> B -> C` there must exist a composition `A -> C`.
+一个范畴是一个容纳了对象和对象间箭头的集合。箭头代表了态射(也可理解为函数或者组合)。一个范畴中的每个对象都具有一个同一态射(`x -> x`)。对于任何链接起来的对象 `A -> B -> C`,必存在一个 `A -> C` 的组合。
-Functors are great higher-order abstractions that allow you to create a variety of generic functions that will work for any data type.
+总之,functor 是一个极佳的高阶抽象,能然你创建各种各样的通用函数来操作任何的数据类型。
-**To be continued…**
+**未完待续。。。**
-### Next Steps ###
+### 接下来 ###
-Want to learn more about functional programming in JavaScript?
+想学习更多 JavaScript 函数式编程吗?
-[Learn JavaScript with Eric Elliott](http://ericelliottjs.com/product/lifetime-access-pass/). If you’re not a member, you’re missing out!
+[跟着 Eric Elliott 学 Javacript](http://ericelliottjs.com/product/lifetime-access-pass/),机不可失时不再来!
-[
-](https://ericelliottjs.com/product/lifetime-access-pass/)
+[](https://ericelliottjs.com/product/lifetime-access-pass/)
-***Eric Elliott*** is the author of [*“Programming JavaScript Applications”*](http://pjabook.com) (O’Reilly), and [*“Learn JavaScript with Eric Elliott”*](http://ericelliottjs.com/product/lifetime-access-pass/) . He has contributed to software experiences for **Adobe Systems, Zumba Fitness, The Wall Street Journal, ESPN, BBC**, and top recording artists including **Usher, Frank Ocean, Metallica**, and many more.
+**Eric Elliott** 是 [**“编写 JavaScript 应用”**](http://pjabook.com) (O’Reilly) 以及 [**“跟着 Eric Elliott 学 Javascript”**](http://ericelliottjs.com/product/lifetime-access-pass/) 两书的作者。他为许多公司和组织作过贡献,例如 **Adobe Systems**、**Zumba Fitness**、**The Wall Street Journal**、**ESPN** 和 **BBC** 等 , 也是很多机构的顶级艺术家,包括但不限于 **Usher**、**Frank Ocean** 以及 **Metallica**。
-*He spends most of his time in the San Francisco Bay Area with the most beautiful woman in the world.*
+大多数时间,他都在 San Francisco Bay Area,同这世上最美丽的女子在一起。
---
From 2c3a7a1b733624be4e533cd2b2fda859caa04ddd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=90=B4=E6=99=93=E5=86=9B?=
Date: Thu, 13 Apr 2017 00:50:54 +0800
Subject: [PATCH 142/638] title
---
TODO/functors-categories.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/TODO/functors-categories.md b/TODO/functors-categories.md
index 31ee4219b6f..491a023bc29 100644
--- a/TODO/functors-categories.md
+++ b/TODO/functors-categories.md
@@ -4,7 +4,7 @@
> * 译者:[yoyoyohamapi](https://github.com/yoyoyohamapi) [reid3290](https://github.com/reid3290)
> * 校对者:
-# Functor 与 Category (软件编写)(第五部分)#
+# Functor 与 Category (软件编写)(第六部分)#
From 8e7e318c4a1391a3088eeb6fbab18e5b61807797 Mon Sep 17 00:00:00 2001
From: sunxinlei
Date: Thu, 13 Apr 2017 02:07:57 +0800
Subject: [PATCH 143/638] =?UTF-8?q?=E7=BF=BB=E8=AF=91=E4=B8=80=E8=BF=87?=
=?UTF-8?q?=E5=8D=8A?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
...uction-to-javascript-composing-software.md | 124 +++++++++---------
1 file changed, 63 insertions(+), 61 deletions(-)
diff --git a/TODO/a-functional-programmers-introduction-to-javascript-composing-software.md b/TODO/a-functional-programmers-introduction-to-javascript-composing-software.md
index c831ac252e4..df1ca8810a3 100644
--- a/TODO/a-functional-programmers-introduction-to-javascript-composing-software.md
+++ b/TODO/a-functional-programmers-introduction-to-javascript-composing-software.md
@@ -1,29 +1,30 @@
> * 原文地址:[A Functional Programmer’s Introduction to JavaScript (Composing Software)(part 3)](https://medium.com/javascript-scene/a-functional-programmers-introduction-to-javascript-composing-software-d670d14ede30)
> * 原文作者:[Eric Elliott](https://medium.com/@_ericelliott?source=post_header_lockup)
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
-> * 译者:
+> * 译者:[sun](http://suncafe.cc)
> * 校对者:
-# A Functional Programmer’s Introduction to JavaScript (Composing Software) #
+# 函数式程序员的 JavaScript 简介 (软件构建系列) #
-Smoke Art Cubes to Smoke — MattysFlicks — (CC BY 2.0)
+烟雾艺术模仿 — MattysFlicks — (CC BY 2.0)
> Note: This is part of the “Composing Software” series on learning functional programming and compositional software techniques in JavaScript ES6+ from the ground up. Stay tuned. There’s a lot more of this to come!
-> [< Previous](https://medium.com/javascript-scene/why-learn-functional-programming-in-javascript-composing-software-ea13afc7a257#.ia0aq3fmb) | [<< Start over at Part 1](https://medium.com/javascript-scene/the-rise-and-fall-and-rise-of-functional-programming-composable-software-c2d91b424c8c#.2dfd6n6qe) | [Next >](https://medium.com/javascript-scene/higher-order-functions-composing-software-5365cf2cbe99#.egoxjg6x7)
+> [< Previous](https://medium.com/javascript-scene/why-learn-functional-programming-in-javascript-composing-software-ea13afc7a257#.ia0aq3fmb) | [<< Start over at Part 1](https://medium.com/javascript-scene/the-rise-and-fall-and-rise-of-functional-programming-composable-software-c2d91b424c8c#.2dfd6n6qe) | [Next >](https://medium.com/javascript-scene/higher-order-functions-composing-software-5365cf2cbe99#.egoxjg6x7)
-For those unfamiliar with JavaScript or ES6+, this is intended as a brief introduction. Whether you’re a beginner or experienced JavaScript developer, you may learn something new. The following is only meant to scratch the surface and get you excited. If you want to know more, you’ll just have to explore deeper. There’s a lot more ahead.
+对于不熟悉 JavaScript 或 ES6+ 的同学,这里做一个简短的介绍。无论你是 JavaScript 开发新手还是有经验的老兵,你都可能学到一些新东西。以下内容仅是毛羽鳞鬣,吊吊大家的兴致。如果想知道更多,还需深入学习。敬请期待吧。
-The best way to learn to code is to code. I recommend that you follow along using an interactive JavaScript programming environment such as [CodePen](https://codepen.io/) or the [Babel REPL](https://babeljs.io/repl/) .
-Alternatively, you can get away with using the Node or browser console REPLs.
+学习编程最好的方法就是动手编程。我建议您使用交互式 JavaScript 编程环境(如 [CodePen](https://codepen.io/) 或 [Babel REPL](https://babeljs.io/repl/))。
-### Expressions and Values ###
+或者,您也可以使用 Node 或浏览器控制台 REPL。
-An expression is a chunk of code that evaluates to a value.
+### 表达式和值 ###
-The following are all valid expressions in JavaScript:
+表达式是可以求得数据值的代码块。
+
+下面这些都是 JavaScript 中合法的表达式:
```
7;
@@ -35,42 +36,42 @@ The following are all valid expressions in JavaScript:
'Hello'; // Hello
```
-The value of an expression can be given a name. When you do so, the expression is evaluated first, and the resulting value is assigned to the name. For this, we’ll use the `const` keyword. It's not the only way, but it's the one you'll use most, so we'll stick with `const` for now:
+表达式的值可以被赋予一个名称。执行此操作时,表达式首先被计算,取得的结果值被分配给该名称。对于这一点我们将使用 `const` 关键字。这不是唯一的方式,但这将是你使用最多的,所以目前我们就可以坚持使用 `const`。
```
const hello = 'Hello';
hello; // Hello
```
-### var, let, and const ###
+### var、let 和 const ###
-JavaScript supports two more variable declaration keywords: `var`, and `let`. I like to think of them in terms of order of selection. By default, I select the strictest declaration: `const`. A variable declared with the `const` keyword can't be reassigned. The final value must be assigned at declaration time. This may sound rigid, but the restriction is a good thing. It's a signal that tells you, "the value assigned to this name is not going to change". It helps you fully understand what the name means right away, without needing to read the whole function or block scope.
+JavaScript 支持另外两种变量声明关键字:`var`,还有 `let`。我喜欢根据选择的顺序来考虑它们。默认情况下,我选择最严格的声明方式:`const`。用 `const` 关键字声明的变量不能被重新赋值。最终值必须在声明时分配。这可能听起来很严格,但限制是一件好事。这是个标识在提醒你“赋给这个名称的值将不会改变”。它可以帮你全面了解这个名称的意义,而无需阅读整个函数或块级作用域。
-Sometimes it’s useful to reassign variables. For example, if you’re using manual, imperative iteration rather than a more functional approach, you can iterate a counter assigned with `let`.
+有时,给变量重新赋值很有用。比如,如果你正在写一个手动的强制性迭代,而不是一个更具功能性的方法,你可以迭代一个用 `let` 赋值的计数器。
-Because `var` tells you the least about the variable, it is the weakest signal. Since I started using ES6, I have never intentionally declared a `var` in a real software project.
+因为 `var` 能告诉你很少关于这个变量的信息,所以它是最无力的声明标识。自从开始用 ES6,我就再也没在实际软件项目中有意使用 `var` 作声明了。
-Be aware that once a variable is declared with `let` or `const`, any attempt to declare it again will result in an error. If you prefer more experimental flexibility in the REPL (Read, Eval, Print Loop) environment, you may use `var` instead of `const` to declare variables. Redeclaring `var` is allowed.
+注意一下,一个变量一旦用 `let` 或 `const` 声明,任何再次声明的尝试都将导致报错。如果你在 REPL(读取-求值-输出循环)环境中更喜欢多一些实验性和灵活性,那么建议你使用 `var` 声明变量,而不是 `const`。
-This text will use `const` in order to get you in the habit of defaulting to `const` for actual programs, but feel free to substitute `var` for the purpose of interactive experimentation.
+本文将使用 const 来让您习惯于为实际程序中用 `const`,而出于试验的目的自由切换回 `var`。
-### Types ###
+### 数据类型 ###
-So far we’ve seen two types: numbers and strings. JavaScript also has booleans (`true` or `false`), arrays, objects, and more. We'll get to other types later.
+目前为止我们见到了两种数据类型:数字和字符串。JavaScript 也有布尔值(`true` 或 `false`)、数组、对象等。稍后我们再看其他类型。
-An array is an ordered list of values. Think of it as a box that can hold many items. Here’s the array literal notation:
+数组是一系列值的有序列表。可以把它比作一个能够装很多元素的盒子。这是一个数组字面量:
```
[1, 2, 3];
```
-Of course, that’s an expression which can be given a name:
+当然,它也是一个可被赋予名称的表达式:
```
const arr = [1, 2, 3];
```
-An object in JavaScript is a collection of key: value pairs. It also has a literal notation:
+在 JavaScript 中,对象是一系列键值对的集合。它也有字面量:
```
{
@@ -78,7 +79,7 @@ An object in JavaScript is a collection of key: value pairs. It also has a liter
}
```
-And of course, you can assign an object to a name:
+当然,你也可以给对象赋予名称:
```
const foo = {
@@ -86,40 +87,40 @@ const foo = {
}
```
-If you want to assign existing variables to object property keys of the same name, there’s a shortcut for that. You can just type the variable name instead of providing both a key and a value:
+如果你想将现有变量赋值给同名的对象属性,这有个捷径。你可以仅输入变量名,而不用同时提供一个键和一个值:
```
const a = 'a';
-const oldA = { a: a }; // long, redundant way
-const oA = { a }; // short an sweet!
+const oldA = { a: a }; // 长而冗余的写法
+const oA = { a }; // 短小精悍!
```
-Just for fun, let’s do that again:
+为了好玩而已,让我们再来一次:
```
const b = 'b';
const oB = { b };
```
-Objects can be easily composed together into new objects:
+对象可以轻松合并到新的对象中:
```
const c = {...oA, ...oB}; // { a: 'a', b: 'b' }
```
-Those dots are the object spread operator. It iterates over the properties in `oA` and assigns them to the new object, then does the same for `oB`, overriding any keys that already exist on the new object. As of this writing, object spread is a new, experimental feature that may not be available in all the popular browsers yet, but if it's not working for you, there is a substitute: `Object.assign()`:
+这些点是对象扩展运算符。它迭代 `oA` 的属性并分配到新的对象中,`oB` 也是一样,在新对象中已经存在的键都会被重写。在撰写本文时,对象扩展是一个新的试验特性,可能还没有被所有主流浏览器支持,但如果你那不能用,还可以用 `Object.assign()` 替代:
```
const d = Object.assign({}, oA, oB); // { a: 'a', b: 'b' }
```
-Only a little more typing in the `Object.assign()` example, and if you're composing lots of objects, it may even save you some typing. Note that when you use `Object.assign()`, you must pass a destination object as the first parameter. It is the object that properties will be copied to. If you forget, and omit the destination object, the object you pass in the first argument will be mutated.
+这个 `Object.assign()` 的例子代码很少,如果你想合并很多对象,它甚至可以节省一些打字。注意当你使用 `Object.assign()` 时,你必须传一个目标对象作为第一个参数。它就是那个源对象的属性将被复制过去的对象。如果你忘了传,第一个参数传递的对象将被改变。
-In my experience, mutating an existing object rather than creating a new object is usually a bug. At the very least, it is error-prone. Be careful with `Object.assign()`.
+以我的经验,改变一个已经存在的对象而不创建一个新的对象常常引发 bug。至少至少,它很容易出错。要小心使用 `Object.assign()`。
-### Destructuring ###
+### 解构 ###
-Both objects and arrays support destructuring, meaning that you can extract values from them and assign them to named variables:
+对象和数组都支持解构,这意味着你可以从中提取值分配给命过名的变量:
```
const [t, u] = ['a', 'b'];
@@ -130,19 +131,19 @@ const blep = {
blop: 'blop'
};
-// The following is equivalent to:
+// 下面等同于:
// const blop = blep.blop;
const { blop } = blep;
blop; // 'blop'
```
-As with the array example above, you can destructure to multiple assignments at once. Here’s a line you’ll see in lots of Redux projects:
+和上面数组的例子类似,你可以一次解构多次分配。下面这行你在大量的 Redux 项目中都能见到。
```
const { type, payload } = action;
```
-Here’s how it’s used in the context of a reducer (much more on that topic coming later):
+下面是它在一个 reducer(后面的话题再详细说) 的上下文中的使用方法。
```
const myReducer = (state = {}, action = {}) => {
@@ -154,75 +155,76 @@ const myReducer = (state = {}, action = {}) => {
};
```
-If you don’t want to use a different name for the new binding, you can assign a new name:
+如果不想为新绑定使用不同的名称,你可以分配一个新名称:
```
const { blop: bloop } = blep;
bloop; // 'blop'
```
-Read: Assign `blep.blop` as `bloop`.
+读作:把 `blep.blop` 分配给 `bloop`。
-### Comparisons and Ternaries ###
+### 比较运算符和三元表达式 ###
-You can compare values with the strict equality operator (sometimes called “triple equals”):
+你可以用严格的相等操作符(有时称为“三等于”)来比较数据值:
```
3 + 1 === 4; // true
```
-There’s also a sloppy equality operator. It’s formally known as the “Equal” operator. Informally, “double equals”. Double equals has a valid use-case or two, but it’s almost always better to default to the `===` operator, instead.
+还有另外一种宽松的相等操作符。它正式地被称为“等于”运算符。非正式地可以叫“双等于”。双等于有一两个有效的用例,但大多数时候默认使用 `===` 操作符是更好的选择。
+
-Other comparison operators include:
+其它比较操作符有:
-- `>` Greater than
-- `<` Less than
-- `>=` Greater than or equal to
-- `<=` Less than or equal to
-- `!=` Not equal
-- `!==` Not strict equal
-- `&&` Logical and
-- `||` Logical or
+- `>` 大于
+- `<` 小于
+- `>=` 大于或等于
+- `<=` 小于或等于
+- `!=` 不等于
+- `!==` 严格不等于
+- `&&` 逻辑与
+- `||` 逻辑或
-A ternary expression is an expression that lets you ask a question using a comparator, and evaluates to a different answer depending on whether or not the expression is truthy:
+三元表达式是一个可以让你使用一个比较器来问问题的表达式,运算出的不同答案取决于表达式是否为真:
```
14 - 7 === 7 ? 'Yep!' : 'Nope.'; // Yep!
```
-### Functions ###
+### 函数 ###
-JavaScript has function expressions, which can be assigned to names:
+JavaScript 支持函数表达式,函数可以这样分配名称:
```
const double = x => x * 2;
```
-This means the same thing as the mathematical function `f(x) = 2x`. Spoken out loud, that function reads `f` of `x` equals `2x`. This function is only interesting when you apply it to a specific value of `x`. To use the function in other equations, you'd write `f(2)`, which has the same meaning as `4`.
+这和数学表达式 `f(x) = 2x` 是一个意思。大声说出来,这个函数读作 `x` 的 `f` 等于 `2x`。这个函数只有当你用一个具体的 `x` 的值应用它的时候才有意思。在其它方程式里面你写 `f(2)`,就等同于 `4`。
-In other words, `f(2) = 4`. You can think of a math function as a mapping from inputs to outputs. `f(x)` in this case is a mapping of input values for `x` to corresponding output values equal to the product of the input value and `2`.
+换种说话就是 `f(2) = 4`。您可以将数学函数视为从输入到输出的映射。这个例子里 `f(x)` 是输入数值 `x` 到相应的输出数值的映射,等于输入数值和 `2` 的乘积。
-In JavaScript, the value of a function expression is the function itself:
+在 JavaScript 中,函数表达式的值是函数本身:
```
double; // [Function: double]
```
-You can see the function definition using the `.toString()` method:
+你可以使用 `.toString()` 方法看到这个函数的定义。
```
double.toString(); // 'x => x * 2'
```
-If you want to apply a function to some arguments, you must invoke it with a function call. A function call applies a function to its arguments and evaluates to a return value.
+如果要将函数应用于某些参数,则必须使用函数调用来调用它。函数调用会接收参数并且计算一个返回值。
-You can invoke a function using `(argument1, argument2, ...rest)`. For example, to invoke our double function, just add the parentheses and pass in a value to double:
+你可以使用 `(argument1, argument2, ...rest)` 调用一个函数。比如调用我们的 double 函数,就加一对括号并传进去一个值:
```
double(2); // 4
```
-Unlike some functional languages, those parentheses are meaningful. Without them, the function won’t be called:
+和一些函数式语言不同,这对括号是有意义的。没有它们,函数将不会被调用。
```
double 4; // SyntaxError: Unexpected number
@@ -481,7 +483,7 @@ Want to learn more about functional programming in JavaScript?
[Learn JavaScript with Eric Elliott](http://ericelliottjs.com/product/lifetime-access-pass/). If you’re not a member, you’re missing out!
[
-](https://ericelliottjs.com/product/lifetime-access-pass/)
+](https://ericelliottjs.com/product/lifetime-access-pass/)
***Eric Elliott*** is the author of [*“Programming JavaScript Applications”*](http://pjabook.com) (O’Reilly), and [*“Learn JavaScript with Eric Elliott”*](http://ericelliottjs.com/product/lifetime-access-pass/) . He has contributed to software experiences for **Adobe Systems, Zumba Fitness, The Wall Street Journal, ESPN, BBC and top recording artists including Usher, Frank Ocean, Metallica**, and many more.
From 1656973000dc535edb97f9447f47325a89444f7d Mon Sep 17 00:00:00 2001
From: Wenlin Ou
Date: Wed, 12 Apr 2017 19:19:12 -0400
Subject: [PATCH 144/638] errors fixes
---
TODO/nothing-will-change-until-you-start-building.md | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/TODO/nothing-will-change-until-you-start-building.md b/TODO/nothing-will-change-until-you-start-building.md
index 034e8ae1484..f063274822b 100644
--- a/TODO/nothing-will-change-until-you-start-building.md
+++ b/TODO/nothing-will-change-until-you-start-building.md
@@ -10,15 +10,15 @@
# 真正行动之前 你将一无所成
-就在上周我打了一辆 Lyft 出租车,司机跟我聊了很多关于她的天花乱坠的想法。她的想法里,她有写一本儿童书籍的想法,有开发一个帮助人们找到停车位置的软件的想法,有寻找到一种更高效打包礼物的想法,但问题是她总是犹豫不决:她有很多想法但却不知道从何开始。
+就在上周我打了一辆 Lyft 出租车,司机跟我聊了很多关于她的天花乱坠的想法。她既想写一本儿童书籍,又想开发一个帮助人们找到停车位置的软件,还想找到一种更高效的打包礼物的方式,但问题是她总是犹豫不决:她有很多想法但却不知道从何开始。
-接下来这段话是我对她说的:**开始一些实际行动吧。选一个项目然后尽可能的去完成它。** 如果你想写一本书,那么从每天写一页开始;如果你想做一个APP,那就从构建草图开始。任何人都可以做到这些。
+接下来这段话是我对她说的:**开始一些实际行动吧。选一个项目然后尽可能的去完成它。** 如果你想写一本书,那么从每天写一页开始;如果你想做一个 APP ,那就从构建草图开始。任何人都可以做到这些。
这个建议适用于所有的创作者。一旦你开始着手在你的项目上,你将会不由自主的继续做下去。创新将会成为你人格的一部分 —— 即使你的项目失败了。
你今天迈出的一小步将会是你人生的一大步。看看那些伟大的产品缔造者吧,比如 [Drew Wilson](https://twitter.com/drewwilson), [Pieter Levels](https://twitter.com/levelsio?), 和 [Sebastian Dobrincu](https://twitter.com/Sebyddd)。**他们不仅仅是等待合适的时机。** 他们每周都在更新他们的产品。
-在一个 [IndieHackers](https://www.indiehackers.com/podcast/006-josh-pigford-of-baremetrics) 的节目中, [Josh Pigford](https://twitter.com/Shpigford) 透露,在做 Baremetrics 之前,他已经尝试过 *一百个* 失败的点子。 然而现在, Baremetrics 每个月都会有 60,000 美金进账。
+在一个 [IndieHackers](https://www.indiehackers.com/podcast/006-josh-pigford-of-baremetrics) 的采访中, [Josh Pigford](https://twitter.com/Shpigford) 透露,在做 Baremetrics 之前,他已经尝试过 *一百个* 失败的点子。 然而现在, Baremetrics 每个月都会有 60,000 美金进账。
![](https://cdn-images-1.medium.com/max/800/1*BzmVaqAKEzNRybUmMYOxdA.png)
@@ -39,7 +39,7 @@
![](https://cdn-images-1.medium.com/max/800/1*ESildSVTSSOnFXGDxD-l9w.png)
-另一个让你保持动力的建议就是让你的项目更加公开。在网上和你的同行们分享你的进展。人们很喜欢看到线框(wireframe 翻译成 ”框架“ 会不会好一点?)类的东西,并常常带来有价值的投入。
+另一个让你保持动力的建议就是让你的项目更加公开。在网上和你的同行们分享你的进展。人们很喜欢看到流程图一类的东西,并常常带来有价值的投入。
我自己找到的一个非常有用的保持动力的小秘诀是和朋友打赌。我对他们说,如果我在截止日期前没有完成某个任务,我就给他们一百刀。比如,我会在一个项目开始的两周内找到二十个人打赌。
@@ -83,7 +83,6 @@
我在 Medium 上每周都会发文。也可以关注我的 [Twitter](https://twitter.com/JonathanZWhite),我会发一些关于设计、前端开发和虚拟现实的杂想。
-*P.S. If you enjoyed this article, it would mean a lot if you click the 💚 and share with friends.*(可删?)
---
From 9adaad4fe374f2caf5ea1914f62f9a81d30c60be Mon Sep 17 00:00:00 2001
From: sqrtthree
Date: Thu, 13 Apr 2017 10:05:57 +0800
Subject: [PATCH 145/638] :memo: Adjust the translator's information format
(#1435)
---
TODO/beyond-browser-web-desktop-apps.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/TODO/beyond-browser-web-desktop-apps.md b/TODO/beyond-browser-web-desktop-apps.md
index f40c59cd68e..56eefc24934 100644
--- a/TODO/beyond-browser-web-desktop-apps.md
+++ b/TODO/beyond-browser-web-desktop-apps.md
@@ -1,8 +1,8 @@
> * 原文地址:[Beyond The Browser: From Web Apps To Desktop Apps](https://www.smashingmagazine.com/2017/03/beyond-browser-web-desktop-apps/)
> * 原文作者:本文已获原作者 [Adam Lynch](https://www.smashingmagazine.com/author/adamlynch/) 授权
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
-> * 译者: [bambooom](https://github.com/bambooom)/[imink](https://github.com/imink)
-> * 校对者:[bambooom](https://github.com/bambooom)/[imink](https://github.com/imink)/[sunui](https://github.com/sunui)
+> * 译者: [bambooom](https://github.com/bambooom)、[imink](https://github.com/imink)
+> * 校对者:[bambooom](https://github.com/bambooom)、[imink](https://github.com/imink)、[sunui](https://github.com/sunui)
## 超越浏览器:从 web 应用到桌面应用
From 38ccbc8b663fc62fb2dce80af2bc6d760b3b4dbf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=A0=B9=E5=8F=B7=E4=B8=89?=
Date: Thu, 13 Apr 2017 10:32:35 +0800
Subject: [PATCH 146/638] Add image.
---
...-and-rise-of-functional-programming-composable-software.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/TODO/the-rise-and-fall-and-rise-of-functional-programming-composable-software.md b/TODO/the-rise-and-fall-and-rise-of-functional-programming-composable-software.md
index 608366c3f41..dce44040646 100644
--- a/TODO/the-rise-and-fall-and-rise-of-functional-programming-composable-software.md
+++ b/TODO/the-rise-and-fall-and-rise-of-functional-programming-composable-software.md
@@ -90,8 +90,8 @@ lambda 表达式对软件设计产生了很大的影响,在 1980 年之前,
[![](https://i.embed.ly/1/display/resize?url=https%3A%2F%2Fpbs.twimg.com%2Fprofile_images%2F3722564505%2Fb8030b8f3990875e8f38ed877fdf8d25_bigger.png&key=4fce0568f2ce49e8b54624ef71a8a5bd&width=40)](https://video.twimg.com/tweet_video/CmectVVVUAAsvpo.mp4)
-
-我一直在告诉大家 [JavaScript] 并不是一门玩具语言。现在我需要展示它。[#StarWars](https://twitter.com/hashtag/StarWars?src=hash) [@BrendanEich](https://twitter.com/BrendanEich)
+![](http://ww1.sinaimg.cn/large/006tNbRwgy1fekui0p6i3j30j50hcmyn.jpg)
+我一直在告诉大家 #JavaScript 并不是一门玩具语言。现在我需要展示它。
在 2015 年,使用函数的组合来编写软件又开始流行起来。为了更简单化,JavaScript 规范获得的数十年来第一次主要的更新并且添加了箭头函数,为了更简单的编写和读取函数、柯里化,和 lambda 语句。
From d7bb3d2a8c355b62b64ac5c987746005bde080fd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=A0=B9=E5=8F=B7=E4=B8=89?=
Date: Thu, 13 Apr 2017 10:34:39 +0800
Subject: [PATCH 147/638] Delete unnecessary image.
---
...ll-and-rise-of-functional-programming-composable-software.md | 2 --
1 file changed, 2 deletions(-)
diff --git a/TODO/the-rise-and-fall-and-rise-of-functional-programming-composable-software.md b/TODO/the-rise-and-fall-and-rise-of-functional-programming-composable-software.md
index dce44040646..577d3d97d34 100644
--- a/TODO/the-rise-and-fall-and-rise-of-functional-programming-composable-software.md
+++ b/TODO/the-rise-and-fall-and-rise-of-functional-programming-composable-software.md
@@ -88,8 +88,6 @@ lambda 表达式对软件设计产生了很大的影响,在 1980 年之前,
在 2010 年左右,一些有趣的事情发生了:JavaScript 的崛起。在大概 2006 年以前,JavaScript 被广泛的看作玩具语言和被用制作浏览器中好玩的动画,但是它里面隐藏着一些极其强大的特性。即 lambda 表达式中最重要的特性。人们开始暗中讨论一个叫做 “函数式编程的” 酷东西。
-[![](https://i.embed.ly/1/display/resize?url=https%3A%2F%2Fpbs.twimg.com%2Fprofile_images%2F3722564505%2Fb8030b8f3990875e8f38ed877fdf8d25_bigger.png&key=4fce0568f2ce49e8b54624ef71a8a5bd&width=40)](https://video.twimg.com/tweet_video/CmectVVVUAAsvpo.mp4)
-
![](http://ww1.sinaimg.cn/large/006tNbRwgy1fekui0p6i3j30j50hcmyn.jpg)
我一直在告诉大家 #JavaScript 并不是一门玩具语言。现在我需要展示它。
From 09e5fb0658df415a4da89ce8b0fc8d68d6f5cee6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=A0=B9=E5=8F=B7=E4=B8=89?=
Date: Thu, 13 Apr 2017 10:35:19 +0800
Subject: [PATCH 148/638] Update
the-rise-and-fall-and-rise-of-functional-programming-composable-software.md
---
...all-and-rise-of-functional-programming-composable-software.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/TODO/the-rise-and-fall-and-rise-of-functional-programming-composable-software.md b/TODO/the-rise-and-fall-and-rise-of-functional-programming-composable-software.md
index 577d3d97d34..1b0a3b7c98c 100644
--- a/TODO/the-rise-and-fall-and-rise-of-functional-programming-composable-software.md
+++ b/TODO/the-rise-and-fall-and-rise-of-functional-programming-composable-software.md
@@ -89,6 +89,7 @@ lambda 表达式对软件设计产生了很大的影响,在 1980 年之前,
在 2010 年左右,一些有趣的事情发生了:JavaScript 的崛起。在大概 2006 年以前,JavaScript 被广泛的看作玩具语言和被用制作浏览器中好玩的动画,但是它里面隐藏着一些极其强大的特性。即 lambda 表达式中最重要的特性。人们开始暗中讨论一个叫做 “函数式编程的” 酷东西。
![](http://ww1.sinaimg.cn/large/006tNbRwgy1fekui0p6i3j30j50hcmyn.jpg)
+
我一直在告诉大家 #JavaScript 并不是一门玩具语言。现在我需要展示它。
在 2015 年,使用函数的组合来编写软件又开始流行起来。为了更简单化,JavaScript 规范获得的数十年来第一次主要的更新并且添加了箭头函数,为了更简单的编写和读取函数、柯里化,和 lambda 语句。
From 61ba93b7f49d64895f6a01c150acf9c57f1ff8b1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=A0=B9=E5=8F=B7=E4=B8=89?=
Date: Thu, 13 Apr 2017 10:38:50 +0800
Subject: [PATCH 149/638] Update article link.
---
...ll-and-rise-of-functional-programming-composable-software.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/TODO/the-rise-and-fall-and-rise-of-functional-programming-composable-software.md b/TODO/the-rise-and-fall-and-rise-of-functional-programming-composable-software.md
index 1b0a3b7c98c..a529896a3c1 100644
--- a/TODO/the-rise-and-fall-and-rise-of-functional-programming-composable-software.md
+++ b/TODO/the-rise-and-fall-and-rise-of-functional-programming-composable-software.md
@@ -100,7 +100,7 @@ lambda 表达式对软件设计产生了很大的影响,在 1980 年之前,
你在阅读下一部分时,可以使用实例实验,记住要把你自己当孩子一样把其他的思想扔在一边在学习中去探索和玩耍。重新发现孩童时发现新事物的欣喜。让我们来做一些魔术吧。
-[接下来的第二部分:“为什么要用 JavaScript 学习函数式编程?”]
+[接下来的第二部分:“为什么要用 JavaScript 学习函数式编程?”](https://github.com/xitu/gold-miner/blob/master/TODO/why-learn-functional-programming-in-javascript-composing-software.md)
### 下一步
From 4aa2181333f014def4d8f91742f5381eb0c788fc Mon Sep 17 00:00:00 2001
From: PhxNirvana
Date: Thu, 13 Apr 2017 11:16:51 +0800
Subject: [PATCH 150/638] Update multithreading-with-rxjava-dadddc.md
---
TODO/multithreading-with-rxjava-dadddc.md | 73 ++++++++++++-----------
1 file changed, 37 insertions(+), 36 deletions(-)
diff --git a/TODO/multithreading-with-rxjava-dadddc.md b/TODO/multithreading-with-rxjava-dadddc.md
index f2c11d0df96..d81eb058383 100644
--- a/TODO/multithreading-with-rxjava-dadddc.md
+++ b/TODO/multithreading-with-rxjava-dadddc.md
@@ -1,24 +1,25 @@
+
> * 原文地址:[Multithreading with RxJava](https://android.jlelse.eu/multithreading-with-rxjava-dadddc4f7a63#.yghtx4u43)
> * 原文作者:[Pierce Zaifman](https://android.jlelse.eu/@PierceZaifman?source=post_header_lockup)
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
-> * 译者:
+> * 译者:[PhxNirvana](https://github.com/phxnirvana)
> * 校对者:
-# Multithreading with RxJava #
+# RxJava 中的多线程 #
-Most of the code I’ve ever written for Android is fast enough that speed has never been a concern. Until a few weeks ago when I was working on an app that reads and analyzes large files.
+大多数情况下,我写的 Android 代码都是可以流畅运行的,因此,速度从不是我考虑的问题。但几周前我处理一个读取和分析大文件的 app 时,浮现出了这一问题。
-While I expect users to understand that a larger file will take longer to process, at some point they will give up on my app. Either because they think the app isn’t working, or they simply aren’t willing to wait that long. So if I can cut that time in half or less, it’s certainly worth doing.
+尽管我期望用户明白文件越大,耗时越长的道理,有时候他们仍会放弃我的应用。他们可能认为应用卡住了,也可能是因为他们就不想等那么久。所以如果我能把时间砍一半或更多的话,一定会大有裨意的。
-#### First attempt ####
+#### 初体验 ####
-Since I’ve been using RxJava for all of my background jobs, it made sense to try to do the same for this. Essentially I have some code that looks like this:
+因为我所有后台任务都用 RxJava 重写了,所以继续用 RxJava 来解决这个问题也是自然而然的。尤其是我还有一些如下所示的代码:
```
List dataList;
-//dataList gets populated here
+//这里是数据列表
List result = new ArrayList<>();
for (String data : dataList) {
@@ -26,80 +27,80 @@ for (String data : dataList) {
}
```
-So, I just tried to stick each iteration of the loop into a background thread. You can see what I did below:
+所以我只是想把循环的每个操作放到一个后台线程中。如下所示:
```
List dataList;
-//dataList gets populated here
+//这里是数据列表
List> tasks = new ArrayList<>();
for (String data : dataList) {
tasks.add(Observable.just(data).subscribeOn(Schedulers.io()).map(s -> {
- // returns a DataModel object
+ // 返回一个 DataModel 对象
return DataParser.createData(s);
}));
}
List result = new ArrayList<>();
-// Wait for everything to finish and collect the results
+// 等待运行结束并收集结果
for (DataModel dataModel : Observable.merge(tasks).toBlocking().toIterable()) {
result.add(dataModel);
}
```
-It did speed it up, it was running in about half the time. But, it was causing a lot of garbage collection (GC), which made the UI very stuttery and janky while it was loading. To try to understand what was happening, I added a log to print out `Thread.currentThread().getName()`. This made me realize that I was actually spawning a new thread for each piece of data. As it turns out, spawning thousands of threads is not a good idea.
+的确起作用了,时间减少了近一半。但也导致大量垃圾回收(GC),这使得加载时的 UI 又卡又慢。为了搞清楚问题的原因,我加了一句 log 打印如下信息 `Thread.currentThread().getName()`。 这样我就搞清楚了,我在处理每一段数据时都新建了线程。正如结果所示,创建上千个线程并不是什么好主意。
-#### Second attempt ####
+#### 二进宫 ####
-I’ve already accomplished my goal of speeding up the data processing, but it’s not running very smoothly. I was also wondering if it could run even faster if it didn’t cause so much GC. So instead of spawning a new thread, I created my own limited thread pool for RxJava to use:
+我已经完成了加速数据处理的目标,但运行起来并不那么流畅。我想知道如果不触发这么多 GC 的话还能不能跑得再快点。所以作为直接创建新线程的代替,我建立了我自己的限定线程数量的线程池提供给 RxJava 使用:
```
List dataList;
-//dataList gets populated here
+//这里是数据列表
List> tasks = new ArrayList<>();
-// Get the max number of threads we could have
+// 取得能够使用的最大线程数
int threadCount = Runtime.getRuntime().availableProcessors();
ExecutorService threadPoolExecutor = Executors.newFixedThreadPool(threadCount);
Scheduler scheduler = Schedulers.from(threadPoolExecutor);
for (String data : dataList) {
tasks.add(Observable.just(data).subscribeOn(scheduler).map(s -> {
- // returns a DataModel object
+ // 返回一个 DataModel 对象
return DataParser.createData(s);
}));
}
List result = new ArrayList<>();
-// Wait for everything to finish and collect the results
+// 等待运行结束并收集结果
for (DataModel dataModel : Observable.merge(tasks).toBlocking().toIterable()) {
result.add(dataModel);
}
```
-For a dataset where each piece of data was quite large, this resulted in a further time savings of roughly 10%. However, for a dataset where each piece of data was small, it reduced the processing time by roughly 30%. It also reduced the number of GC calls, but there were still too many.
+对于单个数据都很大的数据集来说,这样减少了约 10% 的数据处理时间。然而,对于单个数据都很小的数据集就减少了约 30% 的时间。这同时也减少了 GC 的数量,但 GC 还是太频繁。
#### Third attempt ####
-I had one more idea — what if the overhead of managing and switching threads was slowing it down? To get around this, I could group my data into one sublist per thread. That way it would still run in parallel, but the management of each thread would be minimal. I adapted the solution [here](https://github.com/ReactiveX/RxJava/issues/3532#issuecomment-157509946) to implement this idea:
+我有一个新想法——如果性能的瓶颈是线程的管理和切换会怎么样?为了克服这个问题,我可以将数据按照线程来拆分。这样虽然仍是并发运行,但对每个线程的管理将大大减小。我尝试使用 [这里](https://github.com/ReactiveX/RxJava/issues/3532#issuecomment-157509946) 的解决方法来实现我的想法:
```
List dataList;
-//dataList gets populated here
+//这里是数据列表
-// Get the max number of threads we could have
+// 取得能够使用的最大线程数
int threadCount = Runtime.getRuntime().availableProcessors();
ExecutorService threadPoolExecutor = Executors.newFixedThreadPool(threadCount);
Scheduler scheduler = Schedulers.from(threadPoolExecutor);
AtomicInteger groupIndex = new AtomicInteger();
-// Split the data into groups by thread number, then process each group on their own thread
+// 以线程数量为依据分组数据,将每组数据放到它们自己的线程中
Iterable> resultGroups =
Observable.from(dataList).groupBy(k -> groupIndex.getAndIncrement() % threadCount)
.flatMap(group -> group.observeOn(scheduler).toList().map(sublist -> {
@@ -112,24 +113,24 @@ Iterable> resultGroups =
List result = new ArrayList<>();
-// Wait for everything to finish and collect the results
+// 等待运行结束并收集结果
for (List dataModels : resultGroups) {
result.addAll(dataModels);
}
```
-Previously I mentioned testing with two datasets. The first had large individual items but fewer total items. The second had many more total items, but each item was smaller. When I ran this solution against the first dataset, the difference was negligible. But, when I ran it on the second, longer dataset, the change was dramatic. With my previous approach it took about 20 seconds to process this dataset. Now, it takes about 5 seconds.
+上文中我提到用两组数据测试,一组单个数据大但总数少,另一组单个数据小但数量多。当我再次测试时,第一组数据几乎没差别,而第二组改变相当大。之前几乎要 20秒,现在只需 5秒。
-The reason the second dataset was sped up so much, is because of the number of data items. For each item, it has to schedule a thread to do the work. Now that I’ve reduced this scheduling work, there’s very little overhead.
+第二组数据运行时间改进如此大的原因是数量的改变。每个数据都需要指定工作线程,而现在减少了指定线程时的工作量,性能也从而提升了。
#### Clean up ####
-There’s a few places in my code where I need to do this parallel work. So I refactored this solution into a util method that can be called anywhere:
+上面的代码要执行并发还有一些地方需要修改,所以我重新用 util 整理了代码,增加了这段代码的通用性:
```
/**
* Will process the data with the callable by splitting the data into the specified number of threads.
- * T is ths type of data being parsed, and U is the type of data being returned.
+ * T 是要被处理的数据类型,U 是返回的数据类型
*/
public static Iterable parseDataInParallel(List data, Func1, U> worker) {
int threadCount = Runtime.getRuntime().availableProcessors();
@@ -161,20 +162,20 @@ for (List dataModels : resultGroups) {
}
```
-Here `T` is the type being processed, in the example that would be `DataModel`. You pass in a `List` to be processed, and expect a result `U`. In my example `U` is `List`, but it could be anything, it doesn’t have to be a list either. The worker function being passed in is what does the processing of each sublist, and returns a result.
+这里 `T` 是被处理的数据类型,样例中是`DataModel`。传入待处理的 `List` 并期望结果是 `U`。在我的样例中 `U` 是 `List`,但它可以是任何东西,并不一定是一个 list。被传入的工作方法处理每个子列表并返回结果。
-#### Can we make it faster? ####
+#### 可以再快点么? ####
-There are many factors at play here that affect how fast this can run. Like how the threads are managed, how many threads are available, what kind of device the app is running on, etc. Most of these I can’t control, but there was something else I didn’t consider with my solution.
+事实上影响运行速度的因素有许多。比如线程管理方式,线程数,设备等。大多数因素我无法控制,但总有一些是我没有考虑到的。
-What if the data isn’t split evenly? For example, if I have 4 threads, what if every data item assigned to the 4th thread is 10 times larger than any other item? Then the 4th thread will end up running roughly 10 times longer than any other thread. In that case I won’t save much time with multithreading. The second approach I had actually solves this problem, since a thread is only assigned as it becomes available. But that solution was too slow.
+如果数据不是平均分配的会怎么样?举个例子,如果有 4 个线程,第四个线程数据量是其他的 10 倍会怎么样?这时第四个线程的耗时就是其他线程的大约 10 倍。这种情况下使用多线程就不会减少多少时间。我的第二次尝试基本解决了这个问题,因为线程只在需要时才初始化。但这个方法太慢了。
-I also tried to change how the data is grouped into sublists. Instead of doing it arbitrarily, I could keep track of the total size of the data in each group. Then, assign each data item to whichever list is the smallest. This way, the amount of work done by each thread is close to being equal. Unfortunately, in testing this solution I found the time it takes to do this extra setup usually costs more time than it saves.
+我也试过改变数据分组方式。作为随意分配的取代,我可以跟踪每一组数据的总量,然后将数据分配给最少的那组。这样每个线程的工作量就接近平均了。倒霉的是,测试之后发现这样做增加的时间远大于它节省的时间。
-Depending on how unevenly you expect your data to be split up, running it this way may actually be faster. But for the most part, it seems like just randomly splitting up the data is faster. Ideally if each thread could be assigned when available, with minimal overhead, it would be the most efficient solution. But, I couldn’t find a way to reduce the overhead enough to make it worth it.
+这么做可能会更快,(结果)取决于原始数据有多不平均。但大多数情况下,随机分配看起来更快些。理想情况下是每个线程一有空就分配任务,同时执行分配所消耗的资源也少,这是最高效的。但我找不到一个足够高效的可以减少分配瓶颈的方法。
#### Final thoughts ####
-So if you need to run some code in parallel, here’s one approach. Let me know what you think, there are many variables at play here. It’s difficult to determine the optimal solution, if there even is one. Also remember, just because you *can* run something in parallel doesn’t mean you *should*.
+所以如果你想要并发运行一些代码,这里提供一种方法。让我知道你的想法,这里还有许多考验控制的变量。得到一个最优解(如果有的话)总是很难的。以及,**能**并发执行并不意味着**必须**用并发。
-### If You Enjoyed Reading, Please Click That Little Heart. If You Want To Read More Like This, Follow Me On [Medium](https://medium.com/@piercezaifman) . Thanks! ###
+### 如果有收获的话,轻轻扎一下小红心吧老铁。想阅读更多,在 [Medium](https://medium.com/@piercezaifman) 关注我。谢谢!(顺便关注一下 [译者](https://juejin.im/user/57a16f4e6be3ff00650682d8) 233) ###
From eb33e6ae1b32c8e99838d3a9195cdeba9759e8ac Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=94=85=E7=82=89=E5=B7=A5?=
Date: Thu, 13 Apr 2017 12:50:46 +0800
Subject: [PATCH 151/638] modified according to @GitFuture 's revison
---
...ava-8-stream-android-rxjava2-hell-part4.md | 92 +++++--------------
1 file changed, 21 insertions(+), 71 deletions(-)
diff --git a/TODO/war-learning-curve-rx-java-2-java-8-stream-android-rxjava2-hell-part4.md b/TODO/war-learning-curve-rx-java-2-java-8-stream-android-rxjava2-hell-part4.md
index b0b63eeb7c5..c496724c8e2 100644
--- a/TODO/war-learning-curve-rx-java-2-java-8-stream-android-rxjava2-hell-part4.md
+++ b/TODO/war-learning-curve-rx-java-2-java-8-stream-android-rxjava2-hell-part4.md
@@ -1,8 +1,8 @@
> * 原文地址:[War against Learning Curve of RxJava2 + Java8 Stream [ Android RxJava2 ] ( What the hell is this ) Part4](http://www.uwanttolearn.com/android/war-learning-curve-rx-java-2-java-8-stream-android-rxjava2-hell-part4/)
> * 原文作者:[Hafiz Waleed Hussain](http://www.uwanttolearn.com/author/admin/)
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
-> * 译者:
-> * 校对者:
+> * 译者: [Boiler Yao](https://github.com/boileryao)
+> * 校对者: [Vivienmm](https://github.com/Vivienmm)、[GitFuture](https://github.com/GitFuture)
## 大战 RxJava2 和 Java8 Stream [ Android RxJava2 ] (这到底是什么) 第四部分 ##
@@ -11,17 +11,16 @@
又是新的一天,如果学点新东西,这一天一定会很酷炫。
-小伙伴们一切顺利啊,这是我们的 RxJava2 Android 系列的第四部分 [ [第一部分](https://github.com/xitu/gold-miner/blob/master/TODO/pull-vs-push-imperative-vs-reactive-reactive-programming-android-rxjava2-hell-part2.md), [第二部分](http://www.uwanttolearn.com/android/pull-vs-push-imperative-vs-reactive-reactive-programming-android-rxjava2-hell-part2/), [第三部分](https://github.com/xitu/gold-miner/blob/master/TODO/functional-interfaces-functional-programming-and-lambda-expressions-reactive-programming-android-rxjava2-what-the-hell-is-this-part3.md) ]。 好消息是我们已经做好准备,可以开始使用 Rx 了。在使用 RxJava2 Android Observable 之前,我会先用 Java8 的 Stream 来做响应式编程。我认为我们应该了解 Java8,我还感觉通过使用 Java8 的流式 API 会让 RxJava2 Android 的学习曲线更简单。
-
+小伙伴们一切顺利啊,这是我们的 RxJava2 Android 系列的第四部分 [ [第一部分](https://github.com/xitu/gold-miner/blob/master/TODO/pull-vs-push-imperative-vs-reactive-reactive-programming-android-rxjava2-hell-part2.md), [第二部分](http://www.uwanttolearn.com/android/pull-vs-push-imperative-vs-reactive-reactive-programming-android-rxjava2-hell-part2/), [第三部分](https://github.com/xitu/gold-miner/blob/master/TODO/functional-interfaces-functional-programming-and-lambda-expressions-reactive-programming-android-rxjava2-what-the-hell-is-this-part3.md) ]。 好消息是我们已经做好准备,可以开始使用 Rx 了。在使用 RxJava2 Android Observable 之前,我会先用 Java8 的 Stream 来做响应式编程。我认为我们应该了解 Java8,而且通过使用 Java8 的 Stream API 让我感觉学习 RxJava2 Android 的过程更简单。
**动机:**
-动机跟我在 [第一部分](https://github.com/xitu/gold-miner/blob/master/TODO/pull-vs-push-imperative-vs-reactive-reactive-programming-android-rxjava2-hell-part2.md) 和大家分享过的一样。在我开始学习 RxJava2 Android 的时候,我并不知道我该怎样使用、在什么地方使用它。
+动机跟我在 [第一部分](https://github.com/xitu/gold-miner/blob/master/TODO/pull-vs-push-imperative-vs-reactive-reactive-programming-android-rxjava2-hell-part2.md) 和大家分享过的一样。在我开始学习 RxJava2 Android 的时候,我并不知道自己会在什么地方,以何种方式使用到它。
-现在我们已经学会了一些预备知识,但当时我什么都不知道。我那时从学习如何从数据或对象创建 Observable 开始。然后学会当 Observable 数据上发生变化时,去调用哪些接口(或者可以叫做“回调”)。这在理论上很棒,但是当我付诸实践的时候,GG了。我发现很多理论上应该成立的模式在我去用的时候完全不起作用。对我来说最大的问题,是不能用响应或者函数式响应的思维思考问题。我有命令式编程和面向对象编程的背景,由于先入为主,所以对我来说理解会有些难。我一直在问这些问题:我该在哪里实现?我应该怎么实现?如果你跟着这篇文章看下来,我可以 100% 保证你会知道怎样把命令式代码转换到 Rx 代码,虽然写出来的 Rx 代码可能不是很好,但是你起码知道怎么开始。
+现在我们已经学会了一些预备知识,但当时我什么都不懂。因此我开始学习如何根据数据或对象创建 Observable 。然后知道了当 Observable 的数据发生变化时,应该调用哪些接口(或者可以叫做“回调”)。这在理论上很好,但是当我付诸实践的时候,却 GG 了。我发现很多理论上应该成立的模式在我去用的时候完全不起作用。对我来说最大的问题,是不能用响应或者函数式响应的思维思考问题。我熟悉命令式编程和面向对象编程,由于先入为主,所以对我来说理解响应式会有些难。我一直在问这些问题:我该在哪里实现?我应该怎么实现?如果你能坚持看完这篇文章,我可以 100% 保证你会知道怎样把命令式代码转换成 Rx 代码,虽然写出来的 Rx 代码不是最好的,但至少你知道该从哪里入手了。
**回顾:**
-我想回顾之前三篇文章中我们提到过的所有概念 [ [第一部分](https://github.com/xitu/gold-miner/blob/master/TODO/pull-vs-push-imperative-vs-reactive-reactive-programming-android-rxjava2-hell-part2.md)、[第二部分](http://www.uwanttolearn.com/android/pull-vs-push-imperative-vs-reactive-reactive-programming-android-rxjava2-hell-part2/)、 [第三部分](https://github.com/xitu/gold-miner/blob/master/TODO/functional-interfaces-functional-programming-and-lambda-expressions-reactive-programming-android-rxjava2-what-the-hell-is-this-part3.md) ]。因为现在我们要用到这些概念了。在 [第一部分](https://github.com/xitu/gold-miner/blob/master/TODO/pull-vs-push-imperative-vs-reactive-reactive-programming-android-rxjava2-hell-part2.md) 我们学习了观察者模式; 在 [第二部分](http://www.uwanttolearn.com/android/pull-vs-push-imperative-vs-reactive-reactive-programming-android-rxjava2-hell-part2/) 学习了拉模式和推模式、命令式和响应式;在 [第三部分](https://github.com/xitu/gold-miner/blob/master/TODO/functional-interfaces-functional-programming-and-lambda-expressions-reactive-programming-android-rxjava2-what-the-hell-is-this-part3.md) 我们学习了函数式接口(Functional Interfaces)、 接口默认方法(Default Methods)、高阶函数(Higher Order Functions)、函数的副作用(Side Effects in Functions)、纯函数(Pure Functions)、Lambda 表达式和函数式编程。我在下面写了一些定义(很无聊的东西)。如果你早就记得的话,可以跳到下一部分。
+我想回顾之前三篇文章中我们提到过的所有概念 [ [第一部分](https://github.com/xitu/gold-miner/blob/master/TODO/pull-vs-push-imperative-vs-reactive-reactive-programming-android-rxjava2-hell-part2.md)、[第二部分](http://www.uwanttolearn.com/android/pull-vs-push-imperative-vs-reactive-reactive-programming-android-rxjava2-hell-part2/)、 [第三部分](https://github.com/xitu/gold-miner/blob/master/TODO/functional-interfaces-functional-programming-and-lambda-expressions-reactive-programming-android-rxjava2-what-the-hell-is-this-part3.md) ]。因为现在我们要用到这些概念了。在 [第一部分](https://github.com/xitu/gold-miner/blob/master/TODO/pull-vs-push-imperative-vs-reactive-reactive-programming-android-rxjava2-hell-part2.md) 我们学习了观察者模式; 在 [第二部分](http://www.uwanttolearn.com/android/pull-vs-push-imperative-vs-reactive-reactive-programming-android-rxjava2-hell-part2/) 学习了拉模式和推模式、命令式和响应式;在 [第三部分](https://github.com/xitu/gold-miner/blob/master/TODO/functional-interfaces-functional-programming-and-lambda-expressions-reactive-programming-android-rxjava2-what-the-hell-is-this-part3.md) 我们学习了函数式接口(Functional Interfaces)、 接口默认方法(Default Methods)、高阶函数(Higher Order Functions)、函数的副作用(Side Effects in Functions)、纯函数(Pure Functions)、Lambda 表达式和函数式编程。我在下面写了一些定义(很无聊的东西)。如果你清楚这些定义,可以跳到下一部分。
**函数式接口是只有一个抽象方法的接口。**
**在 Java8 我们可以在接口中定义方法,这种方法叫做“默认方法”。**
**至少有一个参数是函数的函数和返回类型为函数的函数称为高阶函数。**
@@ -30,7 +29,7 @@
**简介:**
-今天我们将向 RxJava 的学习曲线宣战。我确定在最后我们会取得胜利。
+今天我们将向 RxJava 的学习宣战。我确定在最后我们会取得胜利。
作战策略:
@@ -54,7 +53,7 @@ Stream:
第一个问题:在英语中 Stream 是什么意思?
-答案:一条很窄的小河,或者源源不断流动的液体、空气、气体。在编程的时候把数据转化成“流”的形式,比如我有一个字符串但是我想把它变成“流”来使用我需要干些什么,我需要创建一个机制,使这个字符串满足“源源不断流动的液体、空气、气体 {**或者数据**}”的定义。问题是,我们为什么想要自己的数据变成“流”呢,下面是个简单的例子。
+答案:一条很窄的小河,或者源源不断流动的液体、空气、气体。在编程的时候把数据转化成“流”的形式,比如我有一个字符串,但是我想把它变成“流”来使用的话我需要干些什么,我需要创建一个机制,使这个字符串满足“源源不断流动的液体、空气、气体 {**或者数据**}”的定义。问题是,我们为什么想要自己的数据变成“流”呢,下面是个简单的例子。
就像下面这幅图中画的那样,我有一杯混合着大大小小石子的蓝色的水。
@@ -90,9 +89,9 @@ Stream:
把水转换成水流后,我们做了很多事情。我先用一个过滤器去掉了大石子,然后用另一个过滤器去掉了小石子, 最后用一个转换器(map)把水的颜色从蓝色变成黑色。
-当我将数据转换成流时,我将在编程中得到同样的好处。现在,我将把这个例子转换成代码。我要显示的代码是真正的代码。可能示例代码不能工作,但我将要使用的操作符和API是真实的,我们将在后面的实例中使用。所以,同志们不要把关注点放在编译上。通过这个例子,我有一种感觉,我们将很容易地把握这些概念。在这个例子中,重要的一点是,我使用Java8 的 Stream API 而不是 Rx API。我不想让事情变困难,但稍后我也会使用 Rx。
+当我将数据转换成流时,我将在编程中得到同样的好处。现在,我将把这个例子转换成代码。我要显示的代码是真正的代码。可能示例代码不能工作,但我将要使用的操作符和 API 是真实的,我们将在后面的实例中使用。所以,同志们不要把关注点放在编译上。通过这个例子,我有一种感觉,我们将很容易地把握这些概念。在这个例子中,重要的一点是,我使用 Java8 的 Stream API 而不是 Rx API。我不想让事情变困难,但稍后我也会使用 Rx。
-图像中的水 和 代码中的水:
+图像中的水 & 代码中的水:
[![](http://www.uwanttolearn.com/wp-content/uploads/2017/03/war_against_learning_curve_of_rx_java_2_java_8_stream_1-300x253.jpg)](http://www.uwanttolearn.com/wp-content/uploads/2017/03/war_against_learning_curve_of_rx_java_2_java_8_stream_1.jpg)
@@ -107,36 +106,22 @@ public static void main(String [] args){
```
输出:
-
water
-
water
-
big stone
-
water
-
water
-
small stone
-
water
-
small stone
-
small stone
-
water
-
water
-
water
-
water
-
water
-图像中的水流 和 代码中的水流:
+图像中的水流 & 代码中的水流:
[![](http://www.uwanttolearn.com/wp-content/uploads/2017/03/war_against_learning_curve_of_rx_java_2_java_8_stream_2-237x300.jpg)](http://www.uwanttolearn.com/wp-content/uploads/2017/03/war_against_learning_curve_of_rx_java_2_java_8_stream_2.jpg)
@@ -150,7 +135,7 @@ public static void main(String[] args) {
//输出和上面那个一样
```
-图像中的“大石子过滤器” 和 代码中的“大石子过滤器”:
+图像中的“大石子过滤器” & 代码中的“大石子过滤器”:
[![](http://www.uwanttolearn.com/wp-content/uploads/2017/03/war_against_learning_curve_of_rx_java_2_java_8_stream_3-300x252.jpg)](http://www.uwanttolearn.com/wp-content/uploads/2017/03/war_against_learning_curve_of_rx_java_2_java_8_stream_3.jpg)
@@ -167,13 +152,13 @@ private static Predicate BigStoneFilter = new Predicate() {
};
```
-正如我们在 [第三部分](https://github.com/xitu/gold-miner/blob/master/TODO/functional-interfaces-functional-programming-and-lambda-expressions-reactive-programming-android-rxjava2-what-the-hell-is-this-part3.md) 已经知道的,任何函数式接口都可以转换成 Lambda 表达式。把上面的代码转换成 Lambda 表达式:
+正如我们在 [第三部分](https://github.com/xitu/gold-miner/blob/master/TODO/functional-interfaces-functional-programming-and-lambda-expressions-reactive-programming-android-rxjava2-what-the-hell-is-this-part3.md) 所学到的,任何函数式接口都可以转换成 Lambda 表达式。把上面的代码转换成 Lambda 表达式:
```
private static Predicate BigStoneFilter = s -> !s.equals("big stone");
```
-图像中和代码中作用在水流上的”大石子过滤器“:
+图像和代码中的作用在水流上的“大石子过滤器”:
[![](http://www.uwanttolearn.com/wp-content/uploads/2017/03/war_against_learning_curve_of_rx_java_2_java_8_stream_4-204x300.jpeg)](http://www.uwanttolearn.com/wp-content/uploads/2017/03/war_against_learning_curve_of_rx_java_2_java_8_stream_4.jpeg)
@@ -189,36 +174,23 @@ private static Predicate BigStoneFilter = s -> !s.equals("big stone");
```
这里我使用了 forEach 方法,暂时把这当作流上的 for 循环。用在这里仅仅是为了输出。除去没有这个方法,我们也已经实现了我们在图像中表示的内容。是时候看看输出了:
-
water
-
water
-
water
-
water
-
small stone
-
water
-
small stone
-
small stone
-
water
-
water
-
water
-
water
-
water
没有大石子了,这意味着我们成功过滤了水。
-图像中的“小石子过滤器” 和 代码中的“小石子过滤器”:
+图像中的“小石子过滤器” & 代码中的“小石子过滤器”:
[![](http://www.uwanttolearn.com/wp-content/uploads/2017/03/war_against_learning_curve_of_rx_java_2_java_8_stream_5-300x229.jpg)](http://www.uwanttolearn.com/wp-content/uploads/2017/03/war_against_learning_curve_of_rx_java_2_java_8_stream_5.jpg)
@@ -226,7 +198,7 @@ water
private static Predicate SmallStoneFilter = s -> !s.equals("small stone");
```
-在图像和代码中使用”小石子过滤器“:
+在图像和代码中使用“小石子过滤器”:
[![](http://www.uwanttolearn.com/wp-content/uploads/2017/03/war_against_learning_curve_of_rx_java_2_java_8_stream_6-228x300.png)](http://www.uwanttolearn.com/wp-content/uploads/2017/03/war_against_learning_curve_of_rx_java_2_java_8_stream_6.png)
@@ -246,32 +218,23 @@ private static Predicate SmallStoneFilter = s -> !s.equals("small stone
我不打算解释 **SmallStoneFilter**,它的实现和 **BigStoneFilter** 是一样一样的。这里我只展示输出。
water
-
water
-
water
-
water
-
water
-
water
-
water
-
water
-
water
-
water
-图像中的”水颜色转换器“ 和 代码中的”水颜色转换器“
+图像中的“水颜色转换器” 和 代码中的“水颜色转换器”
[![](http://www.uwanttolearn.com/wp-content/uploads/2017/03/war_against_learning_curve_of_rx_java_2_java_8_stream_7-300x171.jpg)](http://www.uwanttolearn.com/wp-content/uploads/2017/03/war_against_learning_curve_of_rx_java_2_java_8_stream_7.jpg)
同志们这里需要注意!
-在 Java8 Stream 中有个叫做 Function 的函数式接口。所以,当我想进行转换的时候,需要把这个函数式接口送到流的转换(map)函数里面。现在,我给大家展示在我们的代码中如何创建“水颜色过滤器”。
+在 Java8 Stream 中有个叫做 Function 的函数式接口。所以,当我想进行转换的时候,需要把这个函数式接口送到流的转换(map)函数里面。现在,我给大家展示在我们的代码中如何创建“水颜色转换器”。
```
private static Function convertWaterColour = new Function() {
@@ -316,25 +279,15 @@ private static Function convertWaterColour = s -> s + " black";
```
输出:
-
water black
-
water black
-
water black
-
water black
-
water black
-
water black
-
water black
-
water black
-
water black
-
water black
完活!现在我们再次回顾一些内容。
@@ -567,13 +520,9 @@ protected void onCreate(Bundle savedInstanceState) {
```
输出:
-
03-12 16:13:32.432 14918-14918/async.waleed.rx I/Android: 1
-
03-12 16:13:32.432 14918-14918/async.waleed.rx I/Android: 4
-
03-12 16:13:32.432 14918-14918/async.waleed.rx I/Android: 9
-
03-12 16:13:32.432 14918-14918/async.waleed.rx I/Android: 16
```
@@ -605,7 +554,8 @@ Observable.fromArray(data)
我在一个项目中使用了 [OnBoarding](https://www.google.com/search?q=onboarding+ui&) 界面,根据 UI 设计需要在每个 OnBoarding 界面上显示点点,如下图所示:
-[![](http://www.uwanttolearn.com/wp-content/uploads/2017/03/war_against_learning_curve_of_rx_java_2_java_8_stream_15-300x287.jpg)](http://www.uwanttolearn.com/wp-content/uploads/2017/03/war_against_learning_curve_of_rx_java_2_java_8_stream_15.jpg)如果你观察得很仔细的话,可以看到我需要将选定的界面对应的点设置成黑色。
+[![](http://www.uwanttolearn.com/wp-content/uploads/2017/03/war_against_learning_curve_of_rx_java_2_java_8_stream_15-300x287.jpg)](http://www.uwanttolearn.com/wp-content/uploads/2017/03/war_against_learning_curve_of_rx_java_2_java_8_stream_15.jpg)
+如果你观察得很仔细的话,可以看到我需要将选定的界面对应的点设置成黑色。
命令式编程的代码:
@@ -767,7 +717,7 @@ Observable.range(0, 10)
**总结:**
-同志们干得好!今天我们学 Rx Android 学得很开心。我们从图画开始,然后使用了 Java8 的流(Stream)。之后将 Java8 的流转换到 RxJava 2 Android 的 Observable。再之后,我们看到了真实项目中的示例并且展示了在现有的项目中如何开始使用 Rx。最后,我展示了一些转换到 Rx 的技巧:把循环用 forEach 替换,把 if 换成 filter,用 map 进行数据转化,用 flatmap 代替嵌套的循环。下篇文章: [Dialogue between Rx Observable and a Developer (Me) [ Android RxJava2 ] ( What the hell is this ) Part5](http://www.uwanttolearn.com/android/dialogue-rx-observable-developer-android-rxjava2-hell-part5/).
+同志们干得好!今天我们学 Rx Android 学得很开心。我们从图画开始,然后使用了 Java8 的流(Stream)。之后将 Java8 的流转换到 RxJava 2 Android 的 Observable。再之后,我们看到了实际项目中的示例并且展示了在现有的项目中如何开始使用 Rx。最后,我展示了一些转换到 Rx 的技巧:把循环用 forEach 替换,把 if 换成 filter,用 map 进行数据转化,用 flatmap 代替嵌套的循环。下篇文章: [Dialogue between Rx Observable and a Developer (Me) [ Android RxJava2 ] ( What the hell is this ) Part5](http://www.uwanttolearn.com/android/dialogue-rx-observable-developer-android-rxjava2-hell-part5/).
希望你们开心,同志们再见!
From f4f068d917286b48fc9ceb648b99c3a76304fb77 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=90=B4=E6=99=93=E5=86=9B?=
Date: Thu, 13 Apr 2017 14:18:42 +0800
Subject: [PATCH 152/638] reduce
---
TODO/reduce-composing-software.md | 96 ++++++++++++++++---------------
1 file changed, 49 insertions(+), 47 deletions(-)
diff --git a/TODO/reduce-composing-software.md b/TODO/reduce-composing-software.md
index 8baf2c381ad..312cc27ea78 100644
--- a/TODO/reduce-composing-software.md
+++ b/TODO/reduce-composing-software.md
@@ -4,18 +4,18 @@
> * 译者:
> * 校对者:
-# Reduce (Composing Software) #
+# Reduce (软件编写) (第五部分)#
-Smoke Art Cubes to Smoke — MattysFlicks — (CC BY 2.0)
+Smoke Art Cubes to Smoke — MattysFlicks — (CC BY 2.0) (译注:该图是用 PS 将烟雾处理成方块状后得到的效果,参见 [flickr](https://www.flickr.com/photos/68397968@N07/11432696204)。))
-> Note: This is part of the “Composing Software” series on learning functional programming and compositional software techniques in JavaScript ES6+ from the ground up. Stay tuned. There’s a lot more of this to come!
-> [< Previous](https://medium.com/javascript-scene/higher-order-functions-composing-software-5365cf2cbe99#.su6cmn4f7) | [<< Start over at Part 1](https://medium.com/javascript-scene/the-rise-and-fall-and-rise-of-functional-programming-composable-software-c2d91b424c8c#.2dfd6n6qe) | [Next >](https://medium.com/javascript-scene/functors-categories-61e031bac53f#.4hqndcx22)
+> 注意:这是 “软件编写” 系列文章的第四部分,该系列主要阐述如何在 JavaScript ES6+ 中从零开始学习函数式编程和组合化软件(compositional software)技术(译注:关于软件可组合性的概念,参见维基百科 [Composability](https://en.wikipedia.org/wiki/Composability))。后续还有更多精彩内容,敬请期待!
+> [<上一篇](https://medium.com/javascript-scene/reduce-composing-software-fe22f0c39a1d#.w4y0mlpcs) | [<< 返回第一章](https://medium.com/javascript-scene/the-rise-and-fall-and-rise-of-functional-programming-composable-software-c2d91b424c8c#.2dfd6n6qe)
-**Reduce** (aka: fold, accumulate) utility commonly used in functional programming that lets you iterate over a list, applying a function to an accumulated value and the next item in the list, until the iteration is complete and the accumulated value gets returned. Many useful things can be implemented with reduce. Frequently, it’s the most elegant way to do any non-trivial processing on a collection of items.
+在函数式编程中,**reduce**(也称为:fold,ccumulate)允许你在一个序列上迭代,并应用一个函数来处理预先声明的累积值和当前迭代到的元素。当迭代完成时,将返回这个累积值。许多其他有用的事物都可以通过 reduce 实现。多数时候,reduce 可以说是处理集合中元素最优雅的方式。
-Reduce takes a reducer function and an initial value, and returns the accumulated value. For `Array.prototype.reduce()`, the initial list is provided by `this`, so it's not one of the arguments:
+reduce 接受一个 reducer 函数以及一个初始值,最终返回一个累积值。对于 `Array.prototype.reduce()` 来说, 初始列表将由 `this` 指明, 所以列表本身不会作为该函数的参数:
```
array.reduce(
@@ -24,28 +24,28 @@ array.reduce(
) => accumulator: Any
```
-Let’s sum an array:
+我们利用如下方式对一个数组进行求和:
```
[2, 4, 6].reduce((acc, n) => acc + n, 0); // 12
```
-For each element in the array, the reducer is called and passed the accumulator and the current value. The reducer’s job is to “fold” the current value into the accumulated value somehow. How is not specified, and specifying how is the purpose of the reducer function. The reducer returns the new accumulated value, and `reduce()` moves on to the next value in the array. The reducer may need an initial value to start with, so most implementations take an initial value as a parameter.
+对于数组的每步迭代,reducer 函数都会被调用,并且向其传入了累积值和当前迭代到的数组元素。reducer 的职责在于以某种方式将当前迭代的元素 “合拢(fold)” 到累加值中。reducer 规定了 “合拢” 的手段和方式,完成了对当前元素的 “合拢” 后,reducer 将返回新的累加值,然后, `.reduce()` 将开始处理数组中的下一个元素。reducer 需要一个初始值才能开始工作,所以绝大多数的 `.reduce()` 实现都需要接收一个初始值作为参数。
-In the case of this summing reducer, the first time the reducer is called, `acc` starts at `0` (the value we passed to `.reduce()` as the second parameter). The reducer returns `0` + `2` (`2` was the first element in the array), which is `2`. For the next call, `acc = 2, n = 4` and the reducer returns the result of `2 + 4` (`6`). In the last iteration, `acc = 6, n = 6`, and the reducer returns `12`. Since the iteration is finished, `.reduce()` returns the final accumulated value, `12`.
+在求数组元素和一例中,reducer 函数第一次调用时,`acc` 将会以 `0` 值(该值是传入 `.reduce()` 方法的第二个参数)开始。然后,reducer 返回了 `0` + `2`(`2` 是数组的第一个元素), 也就是返回了 `2` 作为新的累积值。下一步,`acc = 2, n = 4` 传入了 reducer,reducer返回了 `2 + 4`(`6`)。在最后一步迭代中,`acc = 6, n = 6`, reducer 返回了 `12`。迭代完成,`.reduce()` 返回了最终的累积值 `12`。
-In this case, we passed in an anonymous reducing function, but we can abstract it and give it a name:
+在这一例子中,我们传入了一个匿名函数作为 reducer,但是我们也可以抽象出每次求和的过程为一个具名函数,这使得我们代码的复用成都更高:
```
const summingReducer = (acc, n) => acc + n;
[2, 4, 6].reduce(summingReducer, 0); // 12
```
-Normally, `reduce()` works left to right. In JavaScript, we also have `[].reduceRight()`, which works right to left. In other words, if you applied `.reduceRight()` to `[2, 4, 6]`, the first iteration would use `6` as the first value for `n`, and it would work its way back and finish with `2`.
+通常,`reduce` 的工作过程为由左向右。在 JavaScript 中,我们也有一个 `[].reduceRight()` (译注:[MDN -- Array.prototype.reduceRight()](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/ReduceRight))方法来让 reduce 由右向左地工作。 具体说来,如果你对数组 `[2, 4, 6]` 应用 `.reduceRight()` ,第一个被迭代到的元素就将是 `6`,最后一个迭代到的元素就是 `2`。
-### Reduce is Versatile ###
+### 无所不能的 reduce ###
-Reduce is versatile. It’s easy to define `map()`, `filter()`, `forEach()` and lots of other interesting things using reduce:
+别吃惊,reduce 确实无所不能,你所熟悉的 `map()`,`filter()`,`forEach()` 以及其他函数都可借助于 reduce 来创建。
**Map:**
@@ -55,7 +55,7 @@ const map = (fn, arr) => arr.reduce((acc, item, index, arr) => {
}, []);
```
-For map, our accumulated value is a new array with a new element for each value in the original array. The new values are generated by applying the passed in mapping function (`fn`) to each element in the `arr` argument. We accumulate the new array by calling `fn` with the current element, and concatenating the result to the accumulator array, `acc`.
+对于 map 来说,我们的累积值就是一个新的数组对象,该数组对象中的每个元素都由原数组对应元素映射得到。累积数组中新的元素由传入 map 的映射函数(`fn`)所确定:对于当前迭代到的元素 `item`,我们通过 `fn` 计算出新的元素,并将其拼接入累加数组 `arr` 中。
**Filter:**
@@ -65,37 +65,37 @@ const filter = (fn, arr) => arr.reduce((newArr, item) => {
}, []);
```
-Filter works in much the same way as map, except that we take a predicate function and *conditionally* append the current value to the new array if the element passes the predicate check (`fn(item)` returns `true`).
+filter 的工作方式与 map 类似,只不过原数组的元素只有通过一个真值检测函数(predicate function)才能被送入新的累积数组中。亦即,相较于 map,filter 是**有条件**地选择元素到累积数组中,并且不会改变元素的值。
-For each of the above examples, you have a list of data, iterate over that data applying some function and folding the results into an accumulated value. Lots of applications spring to mind. But what if *your data is a list of functions?*
+上面几个例子,你处理的数据都是一些数值序列,你在数值序列上应用指定的函数迭代数据,并将结果合拢到累积值中。大多数应用都因此开始雏形初备,但是你想过这个问题没有:**假如你的序列是函数序列呢?**
**Compose:**
-Reduce is also a convenient way to compose functions. Remember function composition: If you want to apply the function `f` to the result of `g` of `x` i.e., the composition, `f . g`, you could use the following JavaScript:
+reduce 也是实现函数组合的便捷渠道。假如你想用将函数 `g` 的输出作为函数 `f` 的输入,即组合这两个函数: `f . g`,那么你可以使用下面的 JavaScript 代码片,它没有任何的抽象:
```
f(g(x))
```
-Reduce lets us abstract that process to work on any number of functions, so you could easily define a function that would represent:
+reduce 让我们能抽象出函数组合过程,从而让你也能轻易地实现更多层次的函数组合:
```
f(g(h(x)))
```
-To make that happen, we’ll need to run reduce in reverse. That is, right-to-left, rather than left-to-right. Thankfully, JavaScript provides a `.reduceRight()` method:
+由于函数组合是由右向左的,我们就要使用上面提到的 `.reduceRight()` 方法来抽象函数组合过程:
```
const compose = (...fns) => x => fns.reduceRight((v, f) => f(v), x);
```
-> Note: If JavaScript had not provided `[].reduceRight()`, you could still implement `reduceRight()` -- using `reduce()`. I'll leave it to adventurous readers to figure out how.
+> 注意:如果 JavaScript 的版本没有提供 `[].reduceRight()`,你可以借助于 `reduce` 实现该方法。该实现留给读者自己思考。
**Pipe:**
-`compose()` is great if you want to represent the composition from the inside-out -- that is, in the math notation sense. But what if you want to think of it as a sequence of events?
+`compose()` 很好地描述了由内至外的组合过程,某种程度上,这是数学上的关于输入输出的组合。如果你想从事件发生顺序上来思考函数组合呢?
-Imagine we want to add `1` to a number and then double it. With `compose(), that would be:
+假设我们想要对一个数值加 `1`,然后对新得到的数值进行翻倍。如果是利用 `compose()`,就需要这么做:
```
const add1 = n => n + 1;
@@ -110,15 +110,15 @@ add1ThenDouble(2); // 6
// ((2 + 1 = 3) * 2 = 6)
```
-See the problem? The first step is listed last, so in order to understand the sequence, you’ll need to start at the bottom of the list and work your way backwards to the top.
+发现问题没有?第一步(加1操作)是 compose 序列上的最后一个元素,所以,`compose` 需要你自底向上地分析流程的执行。
-Or we can reduce left-to-right as you normally would, instead of right-to-left:
+如果我们以由左向右的方式进行 reduce 来创建函数组合,以示区别,我们用 `pipe` 来描述新的组合方式:
```
const pipe = (...fns) => x => fns.reduce((v, f) => f(v), x);
```
-Now you can write `add1ThenDouble()` like this:
+现在,新的流程就可以这么撰写:
```
const add1ThenDouble = pipe(
@@ -130,7 +130,7 @@ add1ThenDouble(2); // 6
// ((2 + 1 = 3) * 2 = 6)
```
-This is important because sometimes if you compose backwards, you get a different result:
+你也看到了,在组合中,顺序是非常重要的,如果你调换了 `double` 和 `add1` 的顺序,你将得到截然不同的结果:
```
const doubleThenAdd1 = pipe(
@@ -141,25 +141,25 @@ const doubleThenAdd1 = pipe(
doubleThenAdd1(2); // 5
```
-We’ll go into more details on `compose()` and `pipe()` later. What you should understand right now is that `reduce()` is a very powerful tool, and you really need to learn it. Just be aware that if you get very tricky with reduce, some people may have a hard time following along.
+之后,我们还会讨论跟多的关于 `compose()` 和 `pipe()` 的细节。现在,你所要知道的只是,`reduce()` 是一个极为强大的工具,因此一定要掌握它。 如果在学习过程中遇到了挫折,也大可不必灰心,很多开发者都花了大量时间在 reduce 的学习上。
-### A Word on Redux ###
+### Redux 中的 reduce ###
-You may have heard the term “reducer” used to describe the important state update bits of Redux. As of this writing, Redux is the most popular state management library/architecture for web applications built using React and Angular (the latter via `ngrx/store`).
+你可能听说过 “reducer” 这个术语被用在了 [Redux](https://github.com/reactjs/redux) 的状态更新中。这篇文章撰写之时,对于使用了 React 或者 Angular 进行构建的 web 应用来说,Redux 是最流行的状态管理库/架构(Angualar 中的类 Redux 管理是 ngrx/store )。
-Redux uses reducer functions to manage application state. A Redux-style reducer takes the current state and an action object and returns the new state:
+Redux 使用了 reducer 函数来管理应用状态。一个 Redux 风格的 reducer 接收一个当前应用状态 `state` 和 和交互对象 `action` 作为参数(译注:当前状态就相当于累积值,而 action 就相当于目前处理的元素),处理完成后,返回一个新的应用状态:
```
reducer(state: Any, action: { type: String, payload: Any}) => newState: Any
```
-Redux has some reducer rules you need to keep in mind:
+Redux 的一些 reducer 规则需要你牢记在心:
-1. A reducer called with no parameters should return its valid initial state.
-2. If the reducer isn’t going to handle the action type, it still needs to return the state.
-3. Redux reducers **must be pure functions.**
+1. 一个 reducer 如果进行了无参调用,它要返回它的初始状态。
+2. 如果 reducer 操纵的 action 没有声明类型,他要返回当前状态。
+3. 最最重要的是,Redux reducer 必须是纯函数。
-Let’s rewrite our summing reducer as a Redux-style reducer that reduces over action objects:
+现在,我们以 Redux 风格重写上面的求和 reducer,该 reducer 的行为将由 action 类型决定:
```
const ADD_VALUE = 'ADD_VALUE';
@@ -175,7 +175,9 @@ const summingReducer = (state = 0, action = {}) => {
};
```
-The cool thing about Redux is that the reducers are just standard reducers that you can plug into any `reduce()` implementation which respects the reducer function signature, including `[].reduce()`. That means you can create an array of action objects and reduce over them to get a snapshot of state representing the same state you'd have if those same actions were dispatched to your store:
+关于 Redux 的一个非常美妙的事儿就是,其 reducer 都是标准的 reducer (译注:即接收 `accumulator` 和 `current` 两个参数的 reducer ),这意味着你将 Redux 中的 reducer 插入到任何现有的 `reduce()` 实现中去,比如最常用的 `[].reduce()`。以此为例,我们可以创建一个 action 对象的数组,并对其进行 reduce 操作,传入 `reduce()` 的将是我们定义好的 `summingReducer`,据此,我们获得一个状态快照。之后,一旦对 Redux 中的状态树(store)分派了同样的 action 序列,那么一定能俘获到相同的状态快照:
+
+The cool thing about Redux is that the reducers are just standard reducers that you can plug into any `reduce()` implementation which respects the reducer function signature, including `[].reduce()`.
```
const actions = [
@@ -187,26 +189,26 @@ const actions = [
actions.reduce(summingReducer, 0); // 3
```
-That makes unit testing Redux-style reducers a breeze.
+这使得对 Redux 风格的 reducer 的单元测试变得极为容易。
+
+### 总结 ###
-### Conclusion ###
+现在,你应该可以瞥见 recude 的强大甚至是无所不能了。它不只能帮助我们定义出 map 或者 filter,还是函数式编程中重要的工具,这个工具强大在它是一个基础工具,能够通过它构建出更多更强大的工具。
-You should be starting to see that reduce is an incredibly useful and versatile abstraction. It’s definitely a little trickier to understand than map or filter, but it is an essential tool in your functional programming utility belt — one you can use to make a lot of other great tools.
+[**下一篇: Functors(函子) & Categories(范畴) >**](https://medium.com/javascript-scene/functors-categories-61e031bac53f#.4hqndcx22)
-[**Next: Functors & Categories >**](https://medium.com/javascript-scene/functors-categories-61e031bac53f#.4hqndcx22)
-### Next Steps ###
+### 接下来 ###
-Want to learn more about functional programming in JavaScript?
+想学习更多 JavaScript 函数式编程吗?
-[Learn JavaScript with Eric Elliott](http://ericelliottjs.com/product/lifetime-access-pass/). If you’re not a member, you’re missing out!
+[跟着 Eric Elliott 学 Javacript](http://ericelliottjs.com/product/lifetime-access-pass/),机不可失时不再来!
-[
-](https://ericelliottjs.com/product/lifetime-access-pass/)
+[](https://ericelliottjs.com/product/lifetime-access-pass/)
-***Eric Elliott*** is the author of [*“Programming JavaScript Applications”*](http://pjabook.com) (O’Reilly), and [*“Learn JavaScript with Eric Elliott”*](http://ericelliottjs.com/product/lifetime-access-pass/) . He has contributed to software experiences for **Adobe Systems, Zumba Fitness, The Wall Street Journal, ESPN, BBC, and top recording artists including Usher, Frank Ocean, Metallica**, and many more.
+**Eric Elliott** 是 [**“编写 JavaScript 应用”**](http://pjabook.com) (O’Reilly) 以及 [**“跟着 Eric Elliott 学 Javascript”**](http://ericelliottjs.com/product/lifetime-access-pass/) 两书的作者。他为许多公司和组织作过贡献,例如 **Adobe Systems**、**Zumba Fitness**、**The Wall Street Journal**、**ESPN** 和 **BBC** 等 , 也是很多机构的顶级艺术家,包括但不限于 **Usher**、**Frank Ocean** 以及 **Metallica**。
-*He spends most of his time in the San Francisco Bay Area with the most beautiful woman in the world.*
+大多数时间,他都在 San Francisco Bay Area,同这世上最美丽的女子在一起。
---
From 76137a1e95bcb09c9a9d061ce0a416e99a756ea9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=90=B4=E6=99=93=E5=86=9B?=
Date: Thu, 13 Apr 2017 14:23:43 +0800
Subject: [PATCH 153/638] reset
---
TODO/reduce-composing-software.md | 96 +++++++++++++++----------------
1 file changed, 47 insertions(+), 49 deletions(-)
diff --git a/TODO/reduce-composing-software.md b/TODO/reduce-composing-software.md
index 312cc27ea78..85591dbfa4e 100644
--- a/TODO/reduce-composing-software.md
+++ b/TODO/reduce-composing-software.md
@@ -4,18 +4,18 @@
> * 译者:
> * 校对者:
-# Reduce (软件编写) (第五部分)#
+# Reduce (Composing Software) #
-Smoke Art Cubes to Smoke — MattysFlicks — (CC BY 2.0) (译注:该图是用 PS 将烟雾处理成方块状后得到的效果,参见 [flickr](https://www.flickr.com/photos/68397968@N07/11432696204)。))
+Smoke Art Cubes to Smoke — MattysFlicks — (CC BY 2.0)
-> 注意:这是 “软件编写” 系列文章的第四部分,该系列主要阐述如何在 JavaScript ES6+ 中从零开始学习函数式编程和组合化软件(compositional software)技术(译注:关于软件可组合性的概念,参见维基百科 [Composability](https://en.wikipedia.org/wiki/Composability))。后续还有更多精彩内容,敬请期待!
-> [<上一篇](https://medium.com/javascript-scene/reduce-composing-software-fe22f0c39a1d#.w4y0mlpcs) | [<< 返回第一章](https://medium.com/javascript-scene/the-rise-and-fall-and-rise-of-functional-programming-composable-software-c2d91b424c8c#.2dfd6n6qe)
+> Note: This is part of the “Composing Software” series on learning functional programming and compositional software techniques in JavaScript ES6+ from the ground up. Stay tuned. There’s a lot more of this to come!
+> [< Previous](https://medium.com/javascript-scene/higher-order-functions-composing-software-5365cf2cbe99#.su6cmn4f7) | [<< Start over at Part 1](https://medium.com/javascript-scene/the-rise-and-fall-and-rise-of-functional-programming-composable-software-c2d91b424c8c#.2dfd6n6qe) | [Next >](https://medium.com/javascript-scene/functors-categories-61e031bac53f#.4hqndcx22)
-在函数式编程中,**reduce**(也称为:fold,ccumulate)允许你在一个序列上迭代,并应用一个函数来处理预先声明的累积值和当前迭代到的元素。当迭代完成时,将返回这个累积值。许多其他有用的事物都可以通过 reduce 实现。多数时候,reduce 可以说是处理集合中元素最优雅的方式。
+**Reduce** (aka: fold, accumulate) utility commonly used in functional programming that lets you iterate over a list, applying a function to an accumulated value and the next item in the list, until the iteration is complete and the accumulated value gets returned. Many useful things can be implemented with reduce. Frequently, it’s the most elegant way to do any non-trivial processing on a collection of items.
-reduce 接受一个 reducer 函数以及一个初始值,最终返回一个累积值。对于 `Array.prototype.reduce()` 来说, 初始列表将由 `this` 指明, 所以列表本身不会作为该函数的参数:
+Reduce takes a reducer function and an initial value, and returns the accumulated value. For `Array.prototype.reduce()`, the initial list is provided by `this`, so it's not one of the arguments:
```
array.reduce(
@@ -24,28 +24,28 @@ array.reduce(
) => accumulator: Any
```
-我们利用如下方式对一个数组进行求和:
+Let’s sum an array:
```
[2, 4, 6].reduce((acc, n) => acc + n, 0); // 12
```
-对于数组的每步迭代,reducer 函数都会被调用,并且向其传入了累积值和当前迭代到的数组元素。reducer 的职责在于以某种方式将当前迭代的元素 “合拢(fold)” 到累加值中。reducer 规定了 “合拢” 的手段和方式,完成了对当前元素的 “合拢” 后,reducer 将返回新的累加值,然后, `.reduce()` 将开始处理数组中的下一个元素。reducer 需要一个初始值才能开始工作,所以绝大多数的 `.reduce()` 实现都需要接收一个初始值作为参数。
+For each element in the array, the reducer is called and passed the accumulator and the current value. The reducer’s job is to “fold” the current value into the accumulated value somehow. How is not specified, and specifying how is the purpose of the reducer function. The reducer returns the new accumulated value, and `reduce()` moves on to the next value in the array. The reducer may need an initial value to start with, so most implementations take an initial value as a parameter.
-在求数组元素和一例中,reducer 函数第一次调用时,`acc` 将会以 `0` 值(该值是传入 `.reduce()` 方法的第二个参数)开始。然后,reducer 返回了 `0` + `2`(`2` 是数组的第一个元素), 也就是返回了 `2` 作为新的累积值。下一步,`acc = 2, n = 4` 传入了 reducer,reducer返回了 `2 + 4`(`6`)。在最后一步迭代中,`acc = 6, n = 6`, reducer 返回了 `12`。迭代完成,`.reduce()` 返回了最终的累积值 `12`。
+In the case of this summing reducer, the first time the reducer is called, `acc` starts at `0` (the value we passed to `.reduce()` as the second parameter). The reducer returns `0` + `2` (`2` was the first element in the array), which is `2`. For the next call, `acc = 2, n = 4` and the reducer returns the result of `2 + 4` (`6`). In the last iteration, `acc = 6, n = 6`, and the reducer returns `12`. Since the iteration is finished, `.reduce()` returns the final accumulated value, `12`.
-在这一例子中,我们传入了一个匿名函数作为 reducer,但是我们也可以抽象出每次求和的过程为一个具名函数,这使得我们代码的复用成都更高:
+In this case, we passed in an anonymous reducing function, but we can abstract it and give it a name:
```
const summingReducer = (acc, n) => acc + n;
[2, 4, 6].reduce(summingReducer, 0); // 12
```
-通常,`reduce` 的工作过程为由左向右。在 JavaScript 中,我们也有一个 `[].reduceRight()` (译注:[MDN -- Array.prototype.reduceRight()](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/ReduceRight))方法来让 reduce 由右向左地工作。 具体说来,如果你对数组 `[2, 4, 6]` 应用 `.reduceRight()` ,第一个被迭代到的元素就将是 `6`,最后一个迭代到的元素就是 `2`。
+Normally, `reduce()` works left to right. In JavaScript, we also have `[].reduceRight()`, which works right to left. In other words, if you applied `.reduceRight()` to `[2, 4, 6]`, the first iteration would use `6` as the first value for `n`, and it would work its way back and finish with `2`.
-### 无所不能的 reduce ###
+### Reduce is Versatile ###
-别吃惊,reduce 确实无所不能,你所熟悉的 `map()`,`filter()`,`forEach()` 以及其他函数都可借助于 reduce 来创建。
+Reduce is versatile. It’s easy to define `map()`, `filter()`, `forEach()` and lots of other interesting things using reduce:
**Map:**
@@ -55,7 +55,7 @@ const map = (fn, arr) => arr.reduce((acc, item, index, arr) => {
}, []);
```
-对于 map 来说,我们的累积值就是一个新的数组对象,该数组对象中的每个元素都由原数组对应元素映射得到。累积数组中新的元素由传入 map 的映射函数(`fn`)所确定:对于当前迭代到的元素 `item`,我们通过 `fn` 计算出新的元素,并将其拼接入累加数组 `arr` 中。
+For map, our accumulated value is a new array with a new element for each value in the original array. The new values are generated by applying the passed in mapping function (`fn`) to each element in the `arr` argument. We accumulate the new array by calling `fn` with the current element, and concatenating the result to the accumulator array, `acc`.
**Filter:**
@@ -65,37 +65,37 @@ const filter = (fn, arr) => arr.reduce((newArr, item) => {
}, []);
```
-filter 的工作方式与 map 类似,只不过原数组的元素只有通过一个真值检测函数(predicate function)才能被送入新的累积数组中。亦即,相较于 map,filter 是**有条件**地选择元素到累积数组中,并且不会改变元素的值。
+Filter works in much the same way as map, except that we take a predicate function and *conditionally* append the current value to the new array if the element passes the predicate check (`fn(item)` returns `true`).
-上面几个例子,你处理的数据都是一些数值序列,你在数值序列上应用指定的函数迭代数据,并将结果合拢到累积值中。大多数应用都因此开始雏形初备,但是你想过这个问题没有:**假如你的序列是函数序列呢?**
+For each of the above examples, you have a list of data, iterate over that data applying some function and folding the results into an accumulated value. Lots of applications spring to mind. But what if *your data is a list of functions?*
**Compose:**
-reduce 也是实现函数组合的便捷渠道。假如你想用将函数 `g` 的输出作为函数 `f` 的输入,即组合这两个函数: `f . g`,那么你可以使用下面的 JavaScript 代码片,它没有任何的抽象:
+Reduce is also a convenient way to compose functions. Remember function composition: If you want to apply the function `f` to the result of `g` of `x` i.e., the composition, `f . g`, you could use the following JavaScript:
```
f(g(x))
```
-reduce 让我们能抽象出函数组合过程,从而让你也能轻易地实现更多层次的函数组合:
+Reduce lets us abstract that process to work on any number of functions, so you could easily define a function that would represent:
```
f(g(h(x)))
```
-由于函数组合是由右向左的,我们就要使用上面提到的 `.reduceRight()` 方法来抽象函数组合过程:
+To make that happen, we’ll need to run reduce in reverse. That is, right-to-left, rather than left-to-right. Thankfully, JavaScript provides a `.reduceRight()` method:
```
const compose = (...fns) => x => fns.reduceRight((v, f) => f(v), x);
```
-> 注意:如果 JavaScript 的版本没有提供 `[].reduceRight()`,你可以借助于 `reduce` 实现该方法。该实现留给读者自己思考。
+> Note: If JavaScript had not provided `[].reduceRight()`, you could still implement `reduceRight()` -- using `reduce()`. I'll leave it to adventurous readers to figure out how.
**Pipe:**
-`compose()` 很好地描述了由内至外的组合过程,某种程度上,这是数学上的关于输入输出的组合。如果你想从事件发生顺序上来思考函数组合呢?
+`compose()` is great if you want to represent the composition from the inside-out -- that is, in the math notation sense. But what if you want to think of it as a sequence of events?
-假设我们想要对一个数值加 `1`,然后对新得到的数值进行翻倍。如果是利用 `compose()`,就需要这么做:
+Imagine we want to add `1` to a number and then double it. With `compose(), that would be:
```
const add1 = n => n + 1;
@@ -110,15 +110,15 @@ add1ThenDouble(2); // 6
// ((2 + 1 = 3) * 2 = 6)
```
-发现问题没有?第一步(加1操作)是 compose 序列上的最后一个元素,所以,`compose` 需要你自底向上地分析流程的执行。
+See the problem? The first step is listed last, so in order to understand the sequence, you’ll need to start at the bottom of the list and work your way backwards to the top.
-如果我们以由左向右的方式进行 reduce 来创建函数组合,以示区别,我们用 `pipe` 来描述新的组合方式:
+Or we can reduce left-to-right as you normally would, instead of right-to-left:
```
const pipe = (...fns) => x => fns.reduce((v, f) => f(v), x);
```
-现在,新的流程就可以这么撰写:
+Now you can write `add1ThenDouble()` like this:
```
const add1ThenDouble = pipe(
@@ -130,7 +130,7 @@ add1ThenDouble(2); // 6
// ((2 + 1 = 3) * 2 = 6)
```
-你也看到了,在组合中,顺序是非常重要的,如果你调换了 `double` 和 `add1` 的顺序,你将得到截然不同的结果:
+This is important because sometimes if you compose backwards, you get a different result:
```
const doubleThenAdd1 = pipe(
@@ -141,25 +141,25 @@ const doubleThenAdd1 = pipe(
doubleThenAdd1(2); // 5
```
-之后,我们还会讨论跟多的关于 `compose()` 和 `pipe()` 的细节。现在,你所要知道的只是,`reduce()` 是一个极为强大的工具,因此一定要掌握它。 如果在学习过程中遇到了挫折,也大可不必灰心,很多开发者都花了大量时间在 reduce 的学习上。
+We’ll go into more details on `compose()` and `pipe()` later. What you should understand right now is that `reduce()` is a very powerful tool, and you really need to learn it. Just be aware that if you get very tricky with reduce, some people may have a hard time following along.
-### Redux 中的 reduce ###
+### A Word on Redux ###
-你可能听说过 “reducer” 这个术语被用在了 [Redux](https://github.com/reactjs/redux) 的状态更新中。这篇文章撰写之时,对于使用了 React 或者 Angular 进行构建的 web 应用来说,Redux 是最流行的状态管理库/架构(Angualar 中的类 Redux 管理是 ngrx/store )。
+You may have heard the term “reducer” used to describe the important state update bits of Redux. As of this writing, Redux is the most popular state management library/architecture for web applications built using React and Angular (the latter via `ngrx/store`).
-Redux 使用了 reducer 函数来管理应用状态。一个 Redux 风格的 reducer 接收一个当前应用状态 `state` 和 和交互对象 `action` 作为参数(译注:当前状态就相当于累积值,而 action 就相当于目前处理的元素),处理完成后,返回一个新的应用状态:
+Redux uses reducer functions to manage application state. A Redux-style reducer takes the current state and an action object and returns the new state:
```
reducer(state: Any, action: { type: String, payload: Any}) => newState: Any
```
-Redux 的一些 reducer 规则需要你牢记在心:
+Redux has some reducer rules you need to keep in mind:
-1. 一个 reducer 如果进行了无参调用,它要返回它的初始状态。
-2. 如果 reducer 操纵的 action 没有声明类型,他要返回当前状态。
-3. 最最重要的是,Redux reducer 必须是纯函数。
+1. A reducer called with no parameters should return its valid initial state.
+2. If the reducer isn’t going to handle the action type, it still needs to return the state.
+3. Redux reducers **must be pure functions.**
-现在,我们以 Redux 风格重写上面的求和 reducer,该 reducer 的行为将由 action 类型决定:
+Let’s rewrite our summing reducer as a Redux-style reducer that reduces over action objects:
```
const ADD_VALUE = 'ADD_VALUE';
@@ -175,9 +175,7 @@ const summingReducer = (state = 0, action = {}) => {
};
```
-关于 Redux 的一个非常美妙的事儿就是,其 reducer 都是标准的 reducer (译注:即接收 `accumulator` 和 `current` 两个参数的 reducer ),这意味着你将 Redux 中的 reducer 插入到任何现有的 `reduce()` 实现中去,比如最常用的 `[].reduce()`。以此为例,我们可以创建一个 action 对象的数组,并对其进行 reduce 操作,传入 `reduce()` 的将是我们定义好的 `summingReducer`,据此,我们获得一个状态快照。之后,一旦对 Redux 中的状态树(store)分派了同样的 action 序列,那么一定能俘获到相同的状态快照:
-
-The cool thing about Redux is that the reducers are just standard reducers that you can plug into any `reduce()` implementation which respects the reducer function signature, including `[].reduce()`.
+The cool thing about Redux is that the reducers are just standard reducers that you can plug into any `reduce()` implementation which respects the reducer function signature, including `[].reduce()`. That means you can create an array of action objects and reduce over them to get a snapshot of state representing the same state you'd have if those same actions were dispatched to your store:
```
const actions = [
@@ -189,26 +187,26 @@ const actions = [
actions.reduce(summingReducer, 0); // 3
```
-这使得对 Redux 风格的 reducer 的单元测试变得极为容易。
-
-### 总结 ###
+That makes unit testing Redux-style reducers a breeze.
-现在,你应该可以瞥见 recude 的强大甚至是无所不能了。它不只能帮助我们定义出 map 或者 filter,还是函数式编程中重要的工具,这个工具强大在它是一个基础工具,能够通过它构建出更多更强大的工具。
+### Conclusion ###
-[**下一篇: Functors(函子) & Categories(范畴) >**](https://medium.com/javascript-scene/functors-categories-61e031bac53f#.4hqndcx22)
+You should be starting to see that reduce is an incredibly useful and versatile abstraction. It’s definitely a little trickier to understand than map or filter, but it is an essential tool in your functional programming utility belt — one you can use to make a lot of other great tools.
+[**Next: Functors & Categories >**](https://medium.com/javascript-scene/functors-categories-61e031bac53f#.4hqndcx22)
-### 接下来 ###
+### Next Steps ###
-想学习更多 JavaScript 函数式编程吗?
+Want to learn more about functional programming in JavaScript?
-[跟着 Eric Elliott 学 Javacript](http://ericelliottjs.com/product/lifetime-access-pass/),机不可失时不再来!
+[Learn JavaScript with Eric Elliott](http://ericelliottjs.com/product/lifetime-access-pass/). If you’re not a member, you’re missing out!
-[](https://ericelliottjs.com/product/lifetime-access-pass/)
+[
+](https://ericelliottjs.com/product/lifetime-access-pass/)
-**Eric Elliott** 是 [**“编写 JavaScript 应用”**](http://pjabook.com) (O’Reilly) 以及 [**“跟着 Eric Elliott 学 Javascript”**](http://ericelliottjs.com/product/lifetime-access-pass/) 两书的作者。他为许多公司和组织作过贡献,例如 **Adobe Systems**、**Zumba Fitness**、**The Wall Street Journal**、**ESPN** 和 **BBC** 等 , 也是很多机构的顶级艺术家,包括但不限于 **Usher**、**Frank Ocean** 以及 **Metallica**。
+***Eric Elliott*** is the author of [*“Programming JavaScript Applications”*](http://pjabook.com) (O’Reilly), and [*“Learn JavaScript with Eric Elliott”*](http://ericelliottjs.com/product/lifetime-access-pass/) . He has contributed to software experiences for **Adobe Systems, Zumba Fitness, The Wall Street Journal, ESPN, BBC, and top recording artists including Usher, Frank Ocean, Metallica**, and many more.
-大多数时间,他都在 San Francisco Bay Area,同这世上最美丽的女子在一起。
+*He spends most of his time in the San Francisco Bay Area with the most beautiful woman in the world.*
---
From ce75287cbd1757f21d6ef2a84961df549a35d6b6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=90=B4=E6=99=93=E5=86=9B?=
Date: Thu, 13 Apr 2017 14:32:12 +0800
Subject: [PATCH 154/638] reduce
---
TODO/reduce-composing-software.md | 98 ++++++++++++++++---------------
1 file changed, 50 insertions(+), 48 deletions(-)
diff --git a/TODO/reduce-composing-software.md b/TODO/reduce-composing-software.md
index 8baf2c381ad..2c42b1116aa 100644
--- a/TODO/reduce-composing-software.md
+++ b/TODO/reduce-composing-software.md
@@ -1,21 +1,21 @@
> * 原文地址:[Reduce (Composing Software)(part 5)](https://medium.com/javascript-scene/reduce-composing-software-fe22f0c39a1d)
> * 原文作者:[Eric Elliott](https://medium.com/@_ericelliott?source=post_header_lockup)
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
-> * 译者:
+> * 译者:[yoyoyohamapi](https://github.com/yoyoyohamapi) [reid3290](https://github.com/reid3290)
> * 校对者:
-# Reduce (Composing Software) #
+# Reduce (软件编写) (第五部分) #
-Smoke Art Cubes to Smoke — MattysFlicks — (CC BY 2.0)
+Smoke Art Cubes to Smoke — MattysFlicks — (CC BY 2.0) (译注:该图是用 PS 将烟雾处理成方块状后得到的效果,参见 [flickr](https://www.flickr.com/photos/68397968@N07/11432696204)。))
-> Note: This is part of the “Composing Software” series on learning functional programming and compositional software techniques in JavaScript ES6+ from the ground up. Stay tuned. There’s a lot more of this to come!
-> [< Previous](https://medium.com/javascript-scene/higher-order-functions-composing-software-5365cf2cbe99#.su6cmn4f7) | [<< Start over at Part 1](https://medium.com/javascript-scene/the-rise-and-fall-and-rise-of-functional-programming-composable-software-c2d91b424c8c#.2dfd6n6qe) | [Next >](https://medium.com/javascript-scene/functors-categories-61e031bac53f#.4hqndcx22)
+> 注意:这是 “软件编写” 系列文章的第四部分,该系列主要阐述如何在 JavaScript ES6+ 中从零开始学习函数式编程和组合化软件(compositional software)技术(译注:关于软件可组合性的概念,参见维基百科 [Composability](https://en.wikipedia.org/wiki/Composability))。后续还有更多精彩内容,敬请期待!
+> [<上一篇](https://medium.com/javascript-scene/reduce-composing-software-fe22f0c39a1d#.w4y0mlpcs) | [<< 返回第一章](https://medium.com/javascript-scene/the-rise-and-fall-and-rise-of-functional-programming-composable-software-c2d91b424c8c#.2dfd6n6qe)
-**Reduce** (aka: fold, accumulate) utility commonly used in functional programming that lets you iterate over a list, applying a function to an accumulated value and the next item in the list, until the iteration is complete and the accumulated value gets returned. Many useful things can be implemented with reduce. Frequently, it’s the most elegant way to do any non-trivial processing on a collection of items.
+在函数式编程中,**reduce**(也称为:fold,ccumulate)允许你在一个序列上迭代,并应用一个函数来处理预先声明的累积值和当前迭代到的元素。当迭代完成时,将返回这个累积值。许多其他有用的事物都可以通过 reduce 实现。多数时候,reduce 可以说是处理集合中元素最优雅的方式。
-Reduce takes a reducer function and an initial value, and returns the accumulated value. For `Array.prototype.reduce()`, the initial list is provided by `this`, so it's not one of the arguments:
+reduce 接受一个 reducer 函数以及一个初始值,最终返回一个累积值。对于 `Array.prototype.reduce()` 来说, 初始列表将由 `this` 指明, 所以列表本身不会作为该函数的参数:
```
array.reduce(
@@ -24,28 +24,28 @@ array.reduce(
) => accumulator: Any
```
-Let’s sum an array:
+我们利用如下方式对一个数组进行求和:
```
[2, 4, 6].reduce((acc, n) => acc + n, 0); // 12
```
-For each element in the array, the reducer is called and passed the accumulator and the current value. The reducer’s job is to “fold” the current value into the accumulated value somehow. How is not specified, and specifying how is the purpose of the reducer function. The reducer returns the new accumulated value, and `reduce()` moves on to the next value in the array. The reducer may need an initial value to start with, so most implementations take an initial value as a parameter.
+对于数组的每步迭代,reducer 函数都会被调用,并且向其传入了累积值和当前迭代到的数组元素。reducer 的职责在于以某种方式将当前迭代的元素 “合拢(fold)” 到累加值中。reducer 规定了 “合拢” 的手段和方式,完成了对当前元素的 “合拢” 后,reducer 将返回新的累加值,然后, `.reduce()` 将开始处理数组中的下一个元素。reducer 需要一个初始值才能开始工作,所以绝大多数的 `.reduce()` 实现都需要接收一个初始值作为参数。
-In the case of this summing reducer, the first time the reducer is called, `acc` starts at `0` (the value we passed to `.reduce()` as the second parameter). The reducer returns `0` + `2` (`2` was the first element in the array), which is `2`. For the next call, `acc = 2, n = 4` and the reducer returns the result of `2 + 4` (`6`). In the last iteration, `acc = 6, n = 6`, and the reducer returns `12`. Since the iteration is finished, `.reduce()` returns the final accumulated value, `12`.
+在求数组元素和一例中,reducer 函数第一次调用时,`acc` 将会以 `0` 值(该值是传入 `.reduce()` 方法的第二个参数)开始。然后,reducer 返回了 `0` + `2`(`2` 是数组的第一个元素), 也就是返回了 `2` 作为新的累积值。下一步,`acc = 2, n = 4` 传入了 reducer,reducer返回了 `2 + 4`(`6`)。在最后一步迭代中,`acc = 6, n = 6`, reducer 返回了 `12`。迭代完成,`.reduce()` 返回了最终的累积值 `12`。
-In this case, we passed in an anonymous reducing function, but we can abstract it and give it a name:
+在这一例子中,我们传入了一个匿名函数作为 reducer,但是我们也可以抽象出每次求和的过程为一个具名函数,这使得我们代码的复用成都更高:
```
const summingReducer = (acc, n) => acc + n;
[2, 4, 6].reduce(summingReducer, 0); // 12
```
-Normally, `reduce()` works left to right. In JavaScript, we also have `[].reduceRight()`, which works right to left. In other words, if you applied `.reduceRight()` to `[2, 4, 6]`, the first iteration would use `6` as the first value for `n`, and it would work its way back and finish with `2`.
+通常,`reduce` 的工作过程为由左向右。在 JavaScript 中,我们也有一个 `[].reduceRight()` (译注:[MDN -- Array.prototype.reduceRight()](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/ReduceRight))方法来让 reduce 由右向左地工作。 具体说来,如果你对数组 `[2, 4, 6]` 应用 `.reduceRight()` ,第一个被迭代到的元素就将是 `6`,最后一个迭代到的元素就是 `2`。
-### Reduce is Versatile ###
+### 无所不能的 reduce ###
-Reduce is versatile. It’s easy to define `map()`, `filter()`, `forEach()` and lots of other interesting things using reduce:
+别吃惊,reduce 确实无所不能,你所熟悉的 `map()`,`filter()`,`forEach()` 以及其他函数都可借助于 reduce 来创建。
**Map:**
@@ -55,7 +55,7 @@ const map = (fn, arr) => arr.reduce((acc, item, index, arr) => {
}, []);
```
-For map, our accumulated value is a new array with a new element for each value in the original array. The new values are generated by applying the passed in mapping function (`fn`) to each element in the `arr` argument. We accumulate the new array by calling `fn` with the current element, and concatenating the result to the accumulator array, `acc`.
+对于 map 来说,我们的累积值就是一个新的数组对象,该数组对象中的每个元素都由原数组对应元素映射得到。累积数组中新的元素由传入 map 的映射函数(`fn`)所确定:对于当前迭代到的元素 `item`,我们通过 `fn` 计算出新的元素,并将其拼接入累加数组 `arr` 中。
**Filter:**
@@ -65,37 +65,37 @@ const filter = (fn, arr) => arr.reduce((newArr, item) => {
}, []);
```
-Filter works in much the same way as map, except that we take a predicate function and *conditionally* append the current value to the new array if the element passes the predicate check (`fn(item)` returns `true`).
+filter 的工作方式与 map 类似,只不过原数组的元素只有通过一个真值检测函数(predicate function)才能被送入新的累积数组中。亦即,相较于 map,filter 是**有条件**地选择元素到累积数组中,并且不会改变元素的值。
-For each of the above examples, you have a list of data, iterate over that data applying some function and folding the results into an accumulated value. Lots of applications spring to mind. But what if *your data is a list of functions?*
+上面几个例子,你处理的数据都是一些数值序列,你在数值序列上应用指定的函数迭代数据,并将结果合拢到累积值中。大多数应用都因此开始雏形初备,但是你想过这个问题没有:**假如你的序列是函数序列呢?**
**Compose:**
-Reduce is also a convenient way to compose functions. Remember function composition: If you want to apply the function `f` to the result of `g` of `x` i.e., the composition, `f . g`, you could use the following JavaScript:
+reduce 也是实现函数组合的便捷渠道。假如你想用将函数 `g` 的输出作为函数 `f` 的输入,即组合这两个函数: `f . g`,那么你可以使用下面的 JavaScript 代码片,它没有任何的抽象:
```
f(g(x))
```
-Reduce lets us abstract that process to work on any number of functions, so you could easily define a function that would represent:
+reduce 让我们能抽象出函数组合过程,从而让你也能轻易地实现更多层次的函数组合:
```
f(g(h(x)))
```
-To make that happen, we’ll need to run reduce in reverse. That is, right-to-left, rather than left-to-right. Thankfully, JavaScript provides a `.reduceRight()` method:
+由于函数组合是由右向左的,我们就要使用上面提到的 `.reduceRight()` 方法来抽象函数组合过程:
```
const compose = (...fns) => x => fns.reduceRight((v, f) => f(v), x);
```
-> Note: If JavaScript had not provided `[].reduceRight()`, you could still implement `reduceRight()` -- using `reduce()`. I'll leave it to adventurous readers to figure out how.
+> 注意:如果 JavaScript 的版本没有提供 `[].reduceRight()`,你可以借助于 `reduce` 实现该方法。该实现留给读者自己思考。
**Pipe:**
-`compose()` is great if you want to represent the composition from the inside-out -- that is, in the math notation sense. But what if you want to think of it as a sequence of events?
+`compose()` 很好地描述了由内至外的组合过程,某种程度上,这是数学上的关于输入输出的组合。如果你想从事件发生顺序上来思考函数组合呢?
-Imagine we want to add `1` to a number and then double it. With `compose(), that would be:
+假设我们想要对一个数值加 `1`,然后对新得到的数值进行翻倍。如果是利用 `compose()`,就需要这么做:
```
const add1 = n => n + 1;
@@ -110,15 +110,15 @@ add1ThenDouble(2); // 6
// ((2 + 1 = 3) * 2 = 6)
```
-See the problem? The first step is listed last, so in order to understand the sequence, you’ll need to start at the bottom of the list and work your way backwards to the top.
+发现问题没有?第一步(加1操作)是 compose 序列上的最后一个元素,所以,`compose` 需要你自底向上地分析流程的执行。
-Or we can reduce left-to-right as you normally would, instead of right-to-left:
+如果我们以由左向右的方式进行 reduce 来创建函数组合,以示区别,我们用 `pipe` 来描述新的组合方式:
```
const pipe = (...fns) => x => fns.reduce((v, f) => f(v), x);
```
-Now you can write `add1ThenDouble()` like this:
+现在,新的流程就可以这么撰写:
```
const add1ThenDouble = pipe(
@@ -130,7 +130,7 @@ add1ThenDouble(2); // 6
// ((2 + 1 = 3) * 2 = 6)
```
-This is important because sometimes if you compose backwards, you get a different result:
+你也看到了,在组合中,顺序是非常重要的,如果你调换了 `double` 和 `add1` 的顺序,你将得到截然不同的结果:
```
const doubleThenAdd1 = pipe(
@@ -141,25 +141,25 @@ const doubleThenAdd1 = pipe(
doubleThenAdd1(2); // 5
```
-We’ll go into more details on `compose()` and `pipe()` later. What you should understand right now is that `reduce()` is a very powerful tool, and you really need to learn it. Just be aware that if you get very tricky with reduce, some people may have a hard time following along.
+之后,我们还会讨论跟多的关于 `compose()` 和 `pipe()` 的细节。现在,你所要知道的只是,`reduce()` 是一个极为强大的工具,因此一定要掌握它。 如果在学习过程中遇到了挫折,也大可不必灰心,很多开发者都花了大量时间在 reduce 的学习上。
-### A Word on Redux ###
+### Redux 中的 reduce ###
-You may have heard the term “reducer” used to describe the important state update bits of Redux. As of this writing, Redux is the most popular state management library/architecture for web applications built using React and Angular (the latter via `ngrx/store`).
+你可能听说过 “reducer” 这个术语被用在了 [Redux](https://github.com/reactjs/redux) 的状态更新中。这篇文章撰写之时,对于使用了 React 或者 Angular 进行构建的 web 应用来说,Redux 是最流行的状态管理库/架构(Angualar 中的类 Redux 管理是 ngrx/store )。
-Redux uses reducer functions to manage application state. A Redux-style reducer takes the current state and an action object and returns the new state:
+Redux 使用了 reducer 函数来管理应用状态。一个 Redux 风格的 reducer 接收一个当前应用状态 `state` 和 和交互对象 `action` 作为参数(译注:当前状态就相当于累积值,而 action 就相当于目前处理的元素),处理完成后,返回一个新的应用状态:
```
reducer(state: Any, action: { type: String, payload: Any}) => newState: Any
```
-Redux has some reducer rules you need to keep in mind:
+Redux 的一些 reducer 规则需要你牢记在心:
-1. A reducer called with no parameters should return its valid initial state.
-2. If the reducer isn’t going to handle the action type, it still needs to return the state.
-3. Redux reducers **must be pure functions.**
+1. 一个 reducer 如果进行了无参调用,它要返回它的初始状态。
+2. 如果 reducer 操纵的 action 没有声明类型,他要返回当前状态。
+3. 最最重要的是,Redux reducer 必须是纯函数。
-Let’s rewrite our summing reducer as a Redux-style reducer that reduces over action objects:
+现在,我们以 Redux 风格重写上面的求和 reducer,该 reducer 的行为将由 action 类型决定:
```
const ADD_VALUE = 'ADD_VALUE';
@@ -175,7 +175,9 @@ const summingReducer = (state = 0, action = {}) => {
};
```
-The cool thing about Redux is that the reducers are just standard reducers that you can plug into any `reduce()` implementation which respects the reducer function signature, including `[].reduce()`. That means you can create an array of action objects and reduce over them to get a snapshot of state representing the same state you'd have if those same actions were dispatched to your store:
+关于 Redux 的一个非常美妙的事儿就是,其 reducer 都是标准的 reducer (译注:即接收 `accumulator` 和 `current` 两个参数的 reducer ),这意味着你将 Redux 中的 reducer 插入到任何现有的 `reduce()` 实现中去,比如最常用的 `[].reduce()`。以此为例,我们可以创建一个 action 对象的数组,并对其进行 reduce 操作,传入 `reduce()` 的将是我们定义好的 `summingReducer`,据此,我们获得一个状态快照。之后,一旦对 Redux 中的状态树(store)分派了同样的 action 序列,那么一定能俘获到相同的状态快照:
+
+The cool thing about Redux is that the reducers are just standard reducers that you can plug into any `reduce()` implementation which respects the reducer function signature, including `[].reduce()`.
```
const actions = [
@@ -187,26 +189,26 @@ const actions = [
actions.reduce(summingReducer, 0); // 3
```
-That makes unit testing Redux-style reducers a breeze.
+这使得对 Redux 风格的 reducer 的单元测试变得极为容易。
+
+### 总结 ###
-### Conclusion ###
+现在,你应该可以瞥见 recude 的强大甚至是无所不能了。它不只能帮助我们定义出 map 或者 filter,还是函数式编程中重要的工具,这个工具强大在它是一个基础工具,能够通过它构建出更多更强大的工具。
-You should be starting to see that reduce is an incredibly useful and versatile abstraction. It’s definitely a little trickier to understand than map or filter, but it is an essential tool in your functional programming utility belt — one you can use to make a lot of other great tools.
+[**下一篇: Functors(函子) & Categories(范畴) >**](https://medium.com/javascript-scene/functors-categories-61e031bac53f#.4hqndcx22)
-[**Next: Functors & Categories >**](https://medium.com/javascript-scene/functors-categories-61e031bac53f#.4hqndcx22)
-### Next Steps ###
+### 接下来 ###
-Want to learn more about functional programming in JavaScript?
+想学习更多 JavaScript 函数式编程吗?
-[Learn JavaScript with Eric Elliott](http://ericelliottjs.com/product/lifetime-access-pass/). If you’re not a member, you’re missing out!
+[跟着 Eric Elliott 学 Javacript](http://ericelliottjs.com/product/lifetime-access-pass/),机不可失时不再来!
-[
-](https://ericelliottjs.com/product/lifetime-access-pass/)
+[](https://ericelliottjs.com/product/lifetime-access-pass/)
-***Eric Elliott*** is the author of [*“Programming JavaScript Applications”*](http://pjabook.com) (O’Reilly), and [*“Learn JavaScript with Eric Elliott”*](http://ericelliottjs.com/product/lifetime-access-pass/) . He has contributed to software experiences for **Adobe Systems, Zumba Fitness, The Wall Street Journal, ESPN, BBC, and top recording artists including Usher, Frank Ocean, Metallica**, and many more.
+**Eric Elliott** 是 [**“编写 JavaScript 应用”**](http://pjabook.com) (O’Reilly) 以及 [**“跟着 Eric Elliott 学 Javascript”**](http://ericelliottjs.com/product/lifetime-access-pass/) 两书的作者。他为许多公司和组织作过贡献,例如 **Adobe Systems**、**Zumba Fitness**、**The Wall Street Journal**、**ESPN** 和 **BBC** 等 , 也是很多机构的顶级艺术家,包括但不限于 **Usher**、**Frank Ocean** 以及 **Metallica**。
-*He spends most of his time in the San Francisco Bay Area with the most beautiful woman in the world.*
+大多数时间,他都在 San Francisco Bay Area,同这世上最美丽的女子在一起。
---
From c273b62d7998d0e0fd49332aa5d841010ded0763 Mon Sep 17 00:00:00 2001
From: sqrthree
Date: Thu, 13 Apr 2017 22:52:38 +0800
Subject: [PATCH 155/638] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20=E5=86=99=E7=BB=99?=
=?UTF-8?q?=E2=80=9C=E8=80=81=E6=B4=BE=E2=80=9D=20Web=20=E5=BC=80=E5=8F=91?=
=?UTF-8?q?=E8=80=85=E7=9A=84=E2=80=9C=E7=8E=B0=E4=BB=A3=E2=80=9D=20JavaSc?=
=?UTF-8?q?ript=20=E6=8C=87=E5=8D=97=20=E7=9A=84=E7=A7=AF=E5=88=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 5 ++---
front-end.md | 1 +
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/README.md b/README.md
index 54648b75c5d..255e14d40e7 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
[掘金翻译计划](https://juejin.im/tag/%E6%8E%98%E9%87%91%E7%BF%BB%E8%AF%91%E8%AE%A1%E5%88%92) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](#android)、[iOS](#ios)、[React](#react)、[前端](#前端)、[后端](#后端)、[产品](#产品)、[设计](#设计) 等领域,读者为热爱新技术的新锐开发者。
-掘金翻译计划目前翻译完成 [453](#近期文章列表) 篇文章,共有 [300](https://github.com/xitu/gold-miner/wiki/%E8%AF%91%E8%80%85%E7%A7%AF%E5%88%86%E8%A1%A8) 余名译者贡献翻译。
+掘金翻译计划目前翻译完成 [454](#近期文章列表) 篇文章,共有 [300](https://github.com/xitu/gold-miner/wiki/%E8%AF%91%E8%80%85%E7%A7%AF%E5%88%86%E8%A1%A8) 余名译者贡献翻译。
# 官方指南:
@@ -37,11 +37,10 @@
## 前端
+* [写给“老派” Web 开发者的“现代” JavaScript 指南](https://juejin.im/post/58ebab0c8d6d81006191376f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([SunCafe](http://suncafe.cc/) 翻译)
* [CSS很棒,只是真的太难了](https://juejin.im/entry/58eae24a61ff4b0061a6a102?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([ZhangFe](https://github.com/ZhangFe) 翻译)
* [Preload,Prefetch 和它们在 Chrome 之中的优先级](https://juejin.im/post/58e8acf10ce46300585a7a42?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([gy134340](http://gy134340.com/) 翻译)
* [setState() 门事件](https://juejin.im/post/58e5aeccb123db15eb80ecb0?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([reid3290](https://github.com/reid3290) 翻译)
-* [如何使用 JavaScript 构建响应式引擎 —— Part 2:计算属性和依赖追踪](https://juejin.im/post/58ddeb1a570c3500579016ef?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([IridescentMia](https://github.com/IridescentMia) 翻译)
-* [如何使用 JavaScript 构建响应式引擎 —— Part 1:可观察的对象](https://juejin.im/post/58dc9da661ff4b0061547ca0?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)([IridescentMia](https://github.com/IridescentMia) 翻译)
* [所有前端译文>>](https://github.com/xitu/gold-miner/blob/master/front-end.md)
diff --git a/front-end.md b/front-end.md
index 52e31749ac5..bcbc316bce0 100644
--- a/front-end.md
+++ b/front-end.md
@@ -1,3 +1,4 @@
+* [写给“老派” Web 开发者的“现代” JavaScript 指南](https://juejin.im/post/58ebab0c8d6d81006191376f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([SunCafe](http://suncafe.cc/) 翻译)
* [CSS很棒,只是真的太难了](https://juejin.im/entry/58eae24a61ff4b0061a6a102?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([ZhangFe](https://github.com/ZhangFe) 翻译)
* [Preload,Prefetch 和它们在 Chrome 之中的优先级](https://juejin.im/post/58e8acf10ce46300585a7a42?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([gy134340](http://gy134340.com/) 翻译)
* [setState() 门事件](https://juejin.im/post/58e5aeccb123db15eb80ecb0?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([reid3290](https://github.com/reid3290) 翻译)
From 30f822f51a7b1b0d7c03045e84f24c87d700d648 Mon Sep 17 00:00:00 2001
From: sqrthree
Date: Thu, 13 Apr 2017 23:01:01 +0800
Subject: [PATCH 156/638] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20webpack=20?=
=?UTF-8?q?=E6=8B=BE=E7=BF=A0=EF=BC=9A=E5=85=85=E5=88=86=E5=88=A9=E7=94=A8?=
=?UTF-8?q?=20CommonsChunkPlugin()=20=E7=9A=84=E7=A7=AF=E5=88=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 4 ++--
front-end.md | 1 +
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 255e14d40e7..0179de489e5 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
[掘金翻译计划](https://juejin.im/tag/%E6%8E%98%E9%87%91%E7%BF%BB%E8%AF%91%E8%AE%A1%E5%88%92) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](#android)、[iOS](#ios)、[React](#react)、[前端](#前端)、[后端](#后端)、[产品](#产品)、[设计](#设计) 等领域,读者为热爱新技术的新锐开发者。
-掘金翻译计划目前翻译完成 [454](#近期文章列表) 篇文章,共有 [300](https://github.com/xitu/gold-miner/wiki/%E8%AF%91%E8%80%85%E7%A7%AF%E5%88%86%E8%A1%A8) 余名译者贡献翻译。
+掘金翻译计划目前翻译完成 [455](#近期文章列表) 篇文章,共有 [300](https://github.com/xitu/gold-miner/wiki/%E8%AF%91%E8%80%85%E7%A7%AF%E5%88%86%E8%A1%A8) 余名译者贡献翻译。
# 官方指南:
@@ -37,10 +37,10 @@
## 前端
+* [webpack 拾翠:充分利用 CommonsChunkPlugin()](https://juejin.im/post/58ec4e3f5c497d0062c470bf?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([reid3290](https://github.com/reid3290) 翻译)
* [写给“老派” Web 开发者的“现代” JavaScript 指南](https://juejin.im/post/58ebab0c8d6d81006191376f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([SunCafe](http://suncafe.cc/) 翻译)
* [CSS很棒,只是真的太难了](https://juejin.im/entry/58eae24a61ff4b0061a6a102?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([ZhangFe](https://github.com/ZhangFe) 翻译)
* [Preload,Prefetch 和它们在 Chrome 之中的优先级](https://juejin.im/post/58e8acf10ce46300585a7a42?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([gy134340](http://gy134340.com/) 翻译)
-* [setState() 门事件](https://juejin.im/post/58e5aeccb123db15eb80ecb0?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([reid3290](https://github.com/reid3290) 翻译)
* [所有前端译文>>](https://github.com/xitu/gold-miner/blob/master/front-end.md)
diff --git a/front-end.md b/front-end.md
index bcbc316bce0..1d501a043c1 100644
--- a/front-end.md
+++ b/front-end.md
@@ -1,3 +1,4 @@
+* [webpack 拾翠:充分利用 CommonsChunkPlugin()](https://juejin.im/post/58ec4e3f5c497d0062c470bf?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([reid3290](https://github.com/reid3290) 翻译)
* [写给“老派” Web 开发者的“现代” JavaScript 指南](https://juejin.im/post/58ebab0c8d6d81006191376f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([SunCafe](http://suncafe.cc/) 翻译)
* [CSS很棒,只是真的太难了](https://juejin.im/entry/58eae24a61ff4b0061a6a102?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([ZhangFe](https://github.com/ZhangFe) 翻译)
* [Preload,Prefetch 和它们在 Chrome 之中的优先级](https://juejin.im/post/58e8acf10ce46300585a7a42?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([gy134340](http://gy134340.com/) 翻译)
From 06127d45b22e9bdd043a5b082064c8354000ef57 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=A0=B9=E5=8F=B7=E4=B8=89?=
Date: Thu, 13 Apr 2017 23:05:54 +0800
Subject: [PATCH 157/638] Create debugging-tips-tricks.md
---
TODO/debugging-tips-tricks.md | 229 ++++++++++++++++++++++++++++++++++
1 file changed, 229 insertions(+)
create mode 100644 TODO/debugging-tips-tricks.md
diff --git a/TODO/debugging-tips-tricks.md b/TODO/debugging-tips-tricks.md
new file mode 100644
index 00000000000..dca2d0b0200
--- /dev/null
+++ b/TODO/debugging-tips-tricks.md
@@ -0,0 +1,229 @@
+> * 原文地址:[Debugging Tips and Tricks](https://css-tricks.com/debugging-tips-tricks/)
+> * 原文作者:[SARAH DRASNER](https://css-tricks.com/author/sdrasner/)
+> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
+> * 译者:
+> * 校对者:
+
+# Debugging Tips and Tricks #
+
+Writing code is only one small piece of being a developer. In order to be efficient and capable at our jobs, we must also excel at debugging. When I dedicate some time to learning new debugging skills, I often find I can move much quicker, and add more value to the teams I work on. I have a few tips and tricks I rely on pretty heavily and found that I give the same advice again and again during workshops, so here’s a compilation of some of them, as well as some from the community. We'll start with some core tenants and then drill down to more specific examples.
+
+[![](https://s3.buysellads.com/1279518/7386844-1491489478.jpg)](https://srv.buysellads.com/ads/click/x/GTND4237CVYDL23JCV74YKQWF67DTKJNCT7DKZ3JCEAI45QUCT7D6K7KC6BDLKJEF67DTK3EHJNCLSIZ)
+
+
+### # Main Concepts ###
+
+#### # Isolate the Problem ####
+
+Isolation is possibly the strongest core tenant in all of debugging. Our codebases can be sprawling, with different libraries, frameworks, and they can include many contributors, even people who aren't working on the project anymore. Isolating the problem helps us slowly whittle away non-essential parts of the problem so that we can singularly focus on a solution.
+
+Some of the benefits of isolation include, but are not limited to:
+
+- Figuring out if it’s actually the root cause we think it is or some sort of conflict
+- For time-based tasks, understanding whether or not there is a race condition
+- Taking a hard look at whether or not our code can be simplified, which can help with both writing it and maintaining it
+- Untangling it and seeing if it’s one issue or perhaps more
+
+It's very important to make the issue reproducible. Without being able to discern exactly what the issue is in a way where you can reproduce it, it’s very difficult to solve for it. This also allows you to compare it to working model that is similar so that you can see what changed or what is different between the two.
+
+I have a lot of different methods of isolation in practice. One is to create a reduced test case on a local instance, or a private CodePen, or a JSBin. Another is to create breakpoints in the code so that I can see it execute bit by bit. There are a few ways to define breakpoints:
+
+You can literally write `debugger;` inline in your code. You can see how this will fire small pieces at a time.
+
+You can take this one step further in Chrome DevTools and even walk through the next events that are fired or choose specific event listeners:
+
+![Step into the next function call](https://cdn.css-tricks.com/wp-content/uploads/2017/04/stepintonextfunctioncall.gif)
+
+Good 'ol `console.log` is a form of isolation. (Or `echo` in PHP, or `print` in python, etc…). You are taking one tiny piece of execution and testing your assumptions, or checking to see if something is altering. This is probably the most time-tested form of debugging, that no matter how advanced you become, still has it's uses. Arrow functions in ES6 have allowed us to step up our console debugging game as well, as it’s now a lot easier to write useful one-liners in the console.
+
+The `console.table` function is also a favorite tool of mine, especially great for when you have a lot of data you need to represent- large arrays, large objects and the like. The `console.dir` function is also a nice alternative. It will log an interactive listing of an object's properties.
+
+![](https://cdn.css-tricks.com/wp-content/uploads/2017/04/dir.png)
+
+console.dir gives an interactive listing
+
+#### #Be Methodical ####
+
+When I teach workshops and help students in my class, the number one thing that I find holds them back as they try to debug a problem is not being methodical enough. This is truly a tortoise-and-the-hare kind of situation. They understandably want to move quickly, so they change a ton of things at once, and then when something stops working, they don’t know which thing they changed is causing the error. Then, to debug, they change many things at once and get a little lost trying to figure out what is working and what isn't.
+
+We all do this to some extent. As we become more proficient with a tool, we can write more and more code without testing an assumption. But if you’re new to a syntax or technology, being slow and careful behooves you. You have a much better shot at backing out of an issue you might have inadvertently created for yourself. And indeed, once you have created an issue, debugging one thing at a time might seem slower, but exposes exactly what changes have happened and where the error lies in a way that a *seemingly* faster pace doesn’t allow. I say seemingly because the time isn’t actually recovered working this way.
+
+**Do you remember when you were a kid and your parents said, "if you get lost, stay where you are?"** My parents did, at least. It's because if they were moving around to find me and I was also moving around to find them, we'd have fewer chances of bumping into one another. Code works the same way. The less moving pieces you have, the better- the more you are returning consistent results, the easier it will be to track things down. So while you’re debugging, try not to also install anything, or put in new dependencies. If you see a different error every time you should be returning a static result, that’s a big red flag you should be headed right for with your sleuth hat on.
+
+### # Choose Good Tools ###
+
+There are a million different tools for solving a variety of problems. I’m going to work through some of the tools I find the most useful and then we’ll link off to a bevy of resources.
+
+#### # Syntax Highlighting ####
+
+Sure, it’s damn fun to pick out the new hotness in colors and flavors for your syntax highlighting theme, but spending some time thinking about clarity here matters. I often pick dark themes where a skip in syntax will turn all of my code a lighter color, I find errors are really easy to see right away. I tend to like Oceanic Next or Panda, but really, to each their own on this one. It’s important to keep in mind that when looking for a good syntax highlighter, awesome-looking is great, but functional for calling out your mistakes is most important, and it's totally possible to do both.
+
+#### # Linting ####
+
+Linting helps flag suspicious code and calls out errors we might have overlooked. Linting is incredibly important, but which linter you choose has so much to do with what language/framework you’re writing in, and then on top of that, what your agreed-upon code style is.
+
+Different companies have different code styles and rules. Personally, I like [AirBnB's](https://github.com/airbnb/javascript), but take care and don't just use any old linter. Your linter enforces patterns that, if you yourself don’t want to enforce, can stall your build process. I had a CSS linter that complained whenever I wrote a browser hack, and ended up having to circumvent it so often that it stopped being useful. But a good linter can shine light on small errors you might have missed that are lurking.
+
+Here are some resources:
+
+- I recently found [this responsive images linter](https://github.com/ausi/respimagelint), that tells you what opportunities you might have to use picture, srcset, or sizes.
+- Here’s a [pretty good breakdown](https://www.sitepoint.com/comparison-javascript-linting-tools/) of some JS linters
+
+#### # Browser Extensions ####
+
+Extensions can be really awesome because they can be enabled and disabled so readily, and they can work with really specific requirements. If you’re working with a particular library or framework, chances are, having their extension for DevTools enabled is going to give you all sorts of clarity that you can’t find otherwise. Take care though- not only can extensions bog a browser down, but they have permissions to execute scripts, so do a little homework into the extension author, ratings, and background. All that said, here are some of my favorites:
+
+- [Accessibility extension](https://chrome.google.com/webstore/detail/axe/lhdoppojpmngadmnindnejefpokejbdd) from Dequeue Systems
+- [React DevTools](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi) really vital, in my opinion, if you're working with React, to see their virtual DOM
+- [Vue DevTools](https://chrome.google.com/webstore/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd) same endorsement as above.
+- [Codopen](https://chrome.google.com/webstore/detail/codopen/agnkphdgffianchpipdbkeaclfbobaak): pops you out of the editor mode into a debug window for CodePen. Full disclosure: my husband made this for me as a present because he was sick of watching me manually opening the debug window (best gift ever!)
+- [Pageruler](https://chrome.google.com/webstore/detail/page-ruler/jlpkojjdgbllmedoapgfodplfhcbnbpn): get pixel dimensions and measure anything on a page. I like this one because I’m super duper anal about my layout. This helps me feed the beast.
+
+### # DevTools ###
+
+This is probably the most obvious of debugging tools, and there are so many things you can do with them. They can have so many packed-in features that can be easy to miss, so in the next section of specific tips, we'll go into a deep dive of some favorites.
+
+Umar Hansa has great materials for learning what the DevTools can do. He has [a weekly newsletter and GIFs](https://umaar.com/dev-tips/), a new course linked in the last section, and [an article on our site](https://css-tricks.com/six-tips-for-chrome-devtools/).
+
+One of my favorite recent ones is this [CSS Tracker Enhancement](https://umaar.com/dev-tips/126-css-tracker/), shown here with permission from Umar. This shows all of the unused CSS so that you can understand the performance impact.
+
+![](https://cdn.css-tricks.com/wp-content/uploads/2017/04/Screen-Shot-2017-04-10-at-10.20.11-AM.png)
+
+The CSS tracker shows color-coded rules for used and unused sets.
+
+#### # Misc Tools ####
+
+- [What input](https://ten1seven.github.io/what-input/) is a global utility for tracking the current input method (mouse, keyboard or touch), as well as the current intent- this can be really good for tracking down accessiblity leaks (hat tip to Marcy Sutton, accessibility expert for this tipoff)
+- [Ghostlabapp](https://www.vanamco.com/ghostlab/) is a pretty snazzy tool if you’re doing responsive development or checking anything deployed across a ton of devices. It offers synchronized web development, testing, and inspection.
+- [Eruda is an awesome tool](http://eruda.liriliri.io/) that helps debug on mobile devices. I really like it because it takes a simulator a step further, gives a console and real devtools to help you gain understanding.
+
+![eruda gives you a mobile console](https://cdn.css-tricks.com/wp-content/uploads/2017/04/Screen-Shot-2017-04-10-at-10.38.57-AM.png)
+
+### # Specific Tips ###
+
+I am always interested in what other people do to debug, so I asked the community through the CSS-Tricks account and my own what they were really into. This list is a mixture of tips I like as well as a roundup of tips from the community.
+
+#### # Accessibility ####
+
+```
+$('body').on('focusin',function(){
+ console.log(document.activeElement);});
+```
+
+> This logs the currently focused element, useful because opening the Devtools blurs the activeElement
+
+-[Marcy Sutton](https://twitter.com/marcysutton)
+
+#### # Debugging CSS ####
+
+We got quite a lot of responses saying that people put red borders on elements to see what they’re doing
+
+> [@sarah_edo](https://twitter.com/sarah_edo) for CSS, I'll usually have a .debug class with a red border that I slap on troublesome elements.
+>
+> — Jeremy Wagner (@malchata) [March 15, 2017](https://twitter.com/malchata/status/842029469246324736)
+
+I do this too, I even have a little CSS file that drops in some classes I can access for different colors easily.
+
+#### # Checking State in React ####
+
+> [@sarah_edo](https://twitter.com/sarah_edo)
{JSON.stringify(this.state, null, 2)}
+>
+> — MICHAEL JACKSON (@mjackson) [March 15, 2017](https://twitter.com/mjackson/status/842041642760646657)
+
+Props to Michael, this is one of the most useful debugging tools I know of. That snippet "pretty prints" the state of the component you're working with onto the component so that you can see what’s going on. You can validate that the state is working the way that you think it should be, and it helps track down any errors between the state and how you're using it.
+
+#### # Animation ####
+
+We got a lot of responses that said they slow the animation way down:
+
+> [@sarah_edo](https://twitter.com/sarah_edo)[@Real_CSS_Tricks](https://twitter.com/Real_CSS_Tricks) * { animation-duration: 10s !important; }
+>
+> — Thomas Fuchs (@thomasfuchs) [March 15, 2017](https://twitter.com/thomasfuchs/status/842029720820695040)
+
+I mentioned this on a post I wrote right here on CSS Tricks about [debugging CSS Keyframe animations](https://css-tricks.com/debugging-css-keyframe-animations/), there are more tips too, like how to hardware accelerate, or work with multiple transforms in different percentages.
+
+I also slow down my animations in JavaScript- in GreenSock that would look like: `timeline.timeScale(0.5)` (you can slow down the whole timeline, not just one thing at a time, which is super useful), in mo.js that would look like `{speed: 0.5}`.
+
+[Val Head has a great screencast](https://www.youtube.com/watch?v=MjRipmP7ffM&feature=youtu.be) going through both chrome and firefox devtools offering on animation.
+
+If you want to use the Chrome Devtools timeline to do performance audits, it's worth mentioning that painting is the most expense of the tasks, so all things being equal, pay a little more attention to a high percentage of that green.
+
+#### # Checking different connection speeds and loads ####
+
+I tend to work on fast connections, so I will throttle my connection to check and see what the performance would look like for people who don’t have my internet speed.
+
+![throttle connection in devtools](https://cdn.css-tricks.com/wp-content/uploads/2017/04/Screen-Shot-2017-04-10-at-9.29.00-AM.png)
+
+This is also useful in conjunction with a hard reload, or with the cache empty
+
+> [@sarah_edo](https://twitter.com/sarah_edo) Not so secret trick. But still many people are unaware. You need DevTools open, and then right click over the refresh button. [pic.twitter.com/FdAfF9Xtxm](https://t.co/FdAfF9Xtxm)
+>
+> — David Corbacho (@dcorbacho) [March 15, 2017](https://twitter.com/dcorbacho/status/842033259664035840)
+
+#### # Set a Timed Debugger ####
+
+This one came from Chris. We have a whole writeup on it [right here](https://css-tricks.com/set-timed-debugger-web-inspect-hard-grab-elements/):
+
+```
+setTimeout(function() {
+ debugger;
+}, 3000);
+```
+
+It’s similar to the debugger; tool I mentioned earlier, except you can put it in a setTimeout function and get even more fine-tuned information
+
+#### # Simulators ####
+
+> [@Real_CSS_Tricks](https://twitter.com/Real_CSS_Tricks) And just in case any Mac users didn't know this, iOS simulator + Safari is sweet. [pic.twitter.com/Uz4XO3e6uD](https://t.co/Uz4XO3e6uD)
+>
+> — Chris Coyier (@chriscoyier) [March 15, 2017](https://twitter.com/chriscoyier/status/842034009060302848)
+
+I mentioned simulators with Eruda before. iOS users also get a pretty sweet simulator. I was going to tell you you have to install XCode first, but this tweet showed another way:
+
+> [@chriscoyier](https://twitter.com/chriscoyier)[@Real_CSS_Tricks](https://twitter.com/Real_CSS_Tricks) Or, you can use this approach if you didn't want to bother with installing xCode: [https://t.co/WtAnZNo718](https://t.co/WtAnZNo718)
+>
+> — Chris Harrison (@cdharrison) [March 15, 2017](https://twitter.com/cdharrison/status/842038887904088065)
+
+Chrome also has a device toggle which is helpful.
+
+#### # Remote Debuggers ####
+
+> [@chriscoyier](https://twitter.com/chriscoyier)[@Real_CSS_Tricks](https://twitter.com/Real_CSS_Tricks)[https://t.co/q3OfWKNlUo](https://t.co/q3OfWKNlUo) is a good tool.
+>
+> — Gilles 💾⚽ (@gfra54) [March 15, 2017](https://twitter.com/gfra54/status/842035375304523777)
+
+I actually didn't know about this tool until seeing this tweet. Pretty useful!
+
+#### # CSS Grid Debugging #### (#article-header-id-18 .has-header-link)
+
+Rachel Andrew gave a presentation at Smashing and mentioned a little waffle thing you can click on in Firefox that will illuminate the gutters in the grid. [Her video](http://gridbyexample.com/learn/2016/12/17/learning-grid-day17/) explains it really eloquently.
+
+![](https://cdn.css-tricks.com/wp-content/uploads/2017/04/Screen-Shot-2017-04-10-at-9.58.14-AM.png)
+
+Rachel Andrew shows how to highlight gutters in Firefox DevTools.
+
+#### # Array Debugging ####
+
+Wes Bos with a really useful tip for searching for a single item in an array:
+
+> If you are just looking for a single item array.find() is 🔥 [https://t.co/AuRtyFwnq7](https://t.co/AuRtyFwnq7)
+>
+> — Wes Bos (@wesbos) [March 15, 2017](https://twitter.com/wesbos/status/842069915158884354)
+
+### # Further Debugging Resources ###
+
+Jon Kuperman has a [Frontend Masters course](https://frontendmasters.com/courses/chrome-dev-tools/) that can help you master devtools it goes along [with this app](https://github.com/jkup/mastering-chrome-devtools).
+
+There’s a small course on code school called [discover devtools](https://www.codeschool.com/courses/discover-devtools).
+
+Umar Hansa has a new online course called [Modern DevTools](https://moderndevtools.com/).
+
+Julia Evans has a great article [about debugging here](http://jvns.ca/blog/2015/11/22/how-i-got-better-at-debugging/), hat tip to Jamison Dance for showing it to me.
+
+Paul Irish does some [advanced performance audits with devtools](https://docs.google.com/document/d/1K-mKOqiUiSjgZTEscBLjtjd6E67oiK8H2ztOiq5tigk/pub) if you're super nerdy like me and want to dig into the timeline.
+
+Finally, I'll put in a bittersweet resource. My friend James Golick who was an excellent programmer and even more excellent human gave this great conference talk about debugging anything many years ago. Sadly James has passed, but we can still honor his memory and learn from him:
+
+---
+
+> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[React](https://github.com/xitu/gold-miner#react)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计) 等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)。
From 863a5bc2e3f1f08165f87df9039e310393325ee6 Mon Sep 17 00:00:00 2001
From: sqrthree
Date: Thu, 13 Apr 2017 23:07:26 +0800
Subject: [PATCH 158/638] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20=E7=BB=86=E8=8A=82?=
=?UTF-8?q?=E6=98=AF=E4=BA=A7=E5=93=81=E8=AE=BE=E8=AE=A1=E7=9A=84=E9=87=8D?=
=?UTF-8?q?=E4=B8=AD=E4=B9=8B=E9=87=8D=20=E7=9A=84=E7=A7=AF=E5=88=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 4 ++--
product.md | 1 +
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 0179de489e5..982f0ed40da 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
[掘金翻译计划](https://juejin.im/tag/%E6%8E%98%E9%87%91%E7%BF%BB%E8%AF%91%E8%AE%A1%E5%88%92) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](#android)、[iOS](#ios)、[React](#react)、[前端](#前端)、[后端](#后端)、[产品](#产品)、[设计](#设计) 等领域,读者为热爱新技术的新锐开发者。
-掘金翻译计划目前翻译完成 [455](#近期文章列表) 篇文章,共有 [300](https://github.com/xitu/gold-miner/wiki/%E8%AF%91%E8%80%85%E7%A7%AF%E5%88%86%E8%A1%A8) 余名译者贡献翻译。
+掘金翻译计划目前翻译完成 [456](#近期文章列表) 篇文章,共有 [300](https://github.com/xitu/gold-miner/wiki/%E8%AF%91%E8%80%85%E7%A7%AF%E5%88%86%E8%A1%A8) 余名译者贡献翻译。
# 官方指南:
@@ -81,8 +81,8 @@
## 产品
+* [细节是产品设计的重中之重](https://juejin.im/post/58ed96aaa22b9d00634732e9/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([iloveivyxuan](https://github.com/iloveivyxuan) 翻译)
* [单元测试,精益创业,以及两者之间的关系](https://juejin.im/post/58d90a3b44d90400694505c4/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([gy134340](http://gy134340.com/) 翻译)
* [你正在阅读的用户体验文章是不是在向你进行推销?](https://juejin.im/post/58d4c501a22b9d00645544d9/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([ylq167](https://github.com/ylq167) 翻译)
* [直观设计 vs. 共享式设计](https://gold.xitu.io/entry/5862650a128fe1006d04d398/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Funtrip](https://www.behance.net/Funtrip) 翻译)
-* [为何而设计?](https://gold.xitu.io/entry/5857969761ff4b00686ad66b/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([王子建](https://github.com/Romeo0906) 翻译)
* [所有产品译文>>](https://github.com/xitu/gold-miner/blob/master/product.md)
diff --git a/product.md b/product.md
index 308a8319f6f..be018fddc3b 100644
--- a/product.md
+++ b/product.md
@@ -1,3 +1,4 @@
+* [细节是产品设计的重中之重](https://juejin.im/post/58ed96aaa22b9d00634732e9/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([iloveivyxuan](https://github.com/iloveivyxuan) 翻译)
* [单元测试,精益创业,以及两者之间的关系](https://juejin.im/post/58d90a3b44d90400694505c4/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([gy134340](http://gy134340.com/) 翻译)
* [你正在阅读的用户体验文章是不是在向你进行推销?](https://juejin.im/post/58d4c501a22b9d00645544d9/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([ylq167](https://github.com/ylq167) 翻译)
* [直观设计 vs. 共享式设计](https://gold.xitu.io/entry/5862650a128fe1006d04d398/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([Funtrip](https://www.behance.net/Funtrip) 翻译)
From 2cfde921be0d1ede43141d9b345f32aed73f45ed Mon Sep 17 00:00:00 2001
From: sqrthree
Date: Thu, 13 Apr 2017 23:13:13 +0800
Subject: [PATCH 159/638] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20=E5=90=8C=E4=B8=AD?=
=?UTF-8?q?=E6=9C=89=E5=BC=82=E7=9A=84=20Webpack=20=E4=B8=8E=20Rollup=20?=
=?UTF-8?q?=E7=9A=84=E7=A7=AF=E5=88=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 4 ++--
front-end.md | 1 +
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 982f0ed40da..8db95c9f37f 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
[掘金翻译计划](https://juejin.im/tag/%E6%8E%98%E9%87%91%E7%BF%BB%E8%AF%91%E8%AE%A1%E5%88%92) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](#android)、[iOS](#ios)、[React](#react)、[前端](#前端)、[后端](#后端)、[产品](#产品)、[设计](#设计) 等领域,读者为热爱新技术的新锐开发者。
-掘金翻译计划目前翻译完成 [456](#近期文章列表) 篇文章,共有 [300](https://github.com/xitu/gold-miner/wiki/%E8%AF%91%E8%80%85%E7%A7%AF%E5%88%86%E8%A1%A8) 余名译者贡献翻译。
+掘金翻译计划目前翻译完成 [457](#近期文章列表) 篇文章,共有 [300](https://github.com/xitu/gold-miner/wiki/%E8%AF%91%E8%80%85%E7%A7%AF%E5%88%86%E8%A1%A8) 余名译者贡献翻译。
# 官方指南:
@@ -37,10 +37,10 @@
## 前端
+* [同中有异的 Webpack 与 Rollup](https://juejin.im/post/58edb865570c350057f199a7?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lsvih](https://github.com/lsvih) 翻译)
* [webpack 拾翠:充分利用 CommonsChunkPlugin()](https://juejin.im/post/58ec4e3f5c497d0062c470bf?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([reid3290](https://github.com/reid3290) 翻译)
* [写给“老派” Web 开发者的“现代” JavaScript 指南](https://juejin.im/post/58ebab0c8d6d81006191376f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([SunCafe](http://suncafe.cc/) 翻译)
* [CSS很棒,只是真的太难了](https://juejin.im/entry/58eae24a61ff4b0061a6a102?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([ZhangFe](https://github.com/ZhangFe) 翻译)
-* [Preload,Prefetch 和它们在 Chrome 之中的优先级](https://juejin.im/post/58e8acf10ce46300585a7a42?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([gy134340](http://gy134340.com/) 翻译)
* [所有前端译文>>](https://github.com/xitu/gold-miner/blob/master/front-end.md)
diff --git a/front-end.md b/front-end.md
index 1d501a043c1..e646fb5aeff 100644
--- a/front-end.md
+++ b/front-end.md
@@ -1,3 +1,4 @@
+* [同中有异的 Webpack 与 Rollup](https://juejin.im/post/58edb865570c350057f199a7?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lsvih](https://github.com/lsvih) 翻译)
* [webpack 拾翠:充分利用 CommonsChunkPlugin()](https://juejin.im/post/58ec4e3f5c497d0062c470bf?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([reid3290](https://github.com/reid3290) 翻译)
* [写给“老派” Web 开发者的“现代” JavaScript 指南](https://juejin.im/post/58ebab0c8d6d81006191376f?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([SunCafe](http://suncafe.cc/) 翻译)
* [CSS很棒,只是真的太难了](https://juejin.im/entry/58eae24a61ff4b0061a6a102?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([ZhangFe](https://github.com/ZhangFe) 翻译)
From 95989982386812d5e814660828cd3a7c0f224f25 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=A0=B9=E5=8F=B7=E4=B8=89?=
Date: Thu, 13 Apr 2017 23:13:54 +0800
Subject: [PATCH 160/638] Update function-as-child-components.md
---
TODO/function-as-child-components.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/TODO/function-as-child-components.md b/TODO/function-as-child-components.md
index 761cef8ecbd..8a7ee9897c7 100644
--- a/TODO/function-as-child-components.md
+++ b/TODO/function-as-child-components.md
@@ -187,7 +187,7 @@ Ratio.defaultProps = {
Alright, so I did a lot there. We added some event listeners to listen for resize events as well as actually computing the width and height using the provided ratio. Neat, so we’ve got a width and height in our internal state, how can we share it with other components?
-This is one of those things that is hard to understand because it is so simple that when you see it you think, “That can’t be all there is to it.” but this ***is***all there is to it.
+This is one of those things that is hard to understand because it is so simple that when you see it you think, “That can’t be all there is to it.” but this is all there is to it.
#### Children is literally just a JavaScript function. ####
From f1201ddf9ef897e77cd6537a7deab9e62d135a42 Mon Sep 17 00:00:00 2001
From: sqrthree
Date: Thu, 13 Apr 2017 23:20:52 +0800
Subject: [PATCH 161/638] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20MVVM-C=20=E4=B8=8E?=
=?UTF-8?q?=20Swift=20=E7=9A=84=E7=A7=AF=E5=88=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 4 ++--
ios.md | 1 +
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 8db95c9f37f..b8e4a9f3caa 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
[掘金翻译计划](https://juejin.im/tag/%E6%8E%98%E9%87%91%E7%BF%BB%E8%AF%91%E8%AE%A1%E5%88%92) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](#android)、[iOS](#ios)、[React](#react)、[前端](#前端)、[后端](#后端)、[产品](#产品)、[设计](#设计) 等领域,读者为热爱新技术的新锐开发者。
-掘金翻译计划目前翻译完成 [457](#近期文章列表) 篇文章,共有 [300](https://github.com/xitu/gold-miner/wiki/%E8%AF%91%E8%80%85%E7%A7%AF%E5%88%86%E8%A1%A8) 余名译者贡献翻译。
+掘金翻译计划目前翻译完成 [458](#近期文章列表) 篇文章,共有 [300](https://github.com/xitu/gold-miner/wiki/%E8%AF%91%E8%80%85%E7%A7%AF%E5%88%86%E8%A1%A8) 余名译者贡献翻译。
# 官方指南:
@@ -29,10 +29,10 @@
## iOS
+* [MVVM-C 与 Swift](https://juejin.im/post/58ef16b8da2f60005d180666/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([DeepMissea](https://github.com/DeepMissea)) 翻译)
* [Swift 闭包和代理中的保留周期](https://juejin.im/post/58e4ac5d44d904006d2a9a19/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([oOatuo](http://atuo.xyz/)) 翻译)
* [一名 iOS 开发者的 React Native 开发经历](https://juejin.im/post/58df4c3fa0bb9f0069e2f2bd/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lsvih](https://github.com/lsvih)) 翻译)
* [优化 Swift 的编译时间](https://juejin.im/post/58df1d75570c35005796966b/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([DeepMissea](https://github.com/DeepMissea)) 翻译)
-* [看!Swift 里竟然有红绿灯 🚦!](https://juejin.im/post/58ddbc612f301e0062fed742/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([DeepMissea](https://github.com/DeepMissea)) 翻译)
* [所有 iOS 译文>>](https://github.com/xitu/gold-miner/blob/master/ios.md)
## 前端
diff --git a/ios.md b/ios.md
index 53fce8c3fce..89d29887e73 100644
--- a/ios.md
+++ b/ios.md
@@ -1,3 +1,4 @@
+* [MVVM-C 与 Swift](https://juejin.im/post/58ef16b8da2f60005d180666/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([DeepMissea](https://github.com/DeepMissea)) 翻译)
* [Swift 闭包和代理中的保留周期](https://juejin.im/post/58e4ac5d44d904006d2a9a19/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([oOatuo](http://atuo.xyz/)) 翻译)
* [一名 iOS 开发者的 React Native 开发经历](https://juejin.im/post/58df4c3fa0bb9f0069e2f2bd/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([lsvih](https://github.com/lsvih)) 翻译)
* [优化 Swift 的编译时间](https://juejin.im/post/58df1d75570c35005796966b/?utm_source=gold-miner&utm_medium=readme&utm_campaign=github) ([DeepMissea](https://github.com/DeepMissea)) 翻译)
From 548991b587ae880f4e24df0ce4c8720472e39781 Mon Sep 17 00:00:00 2001
From: gy134340
Date: Thu, 13 Apr 2017 23:25:29 +0800
Subject: [PATCH 162/638] =?UTF-8?q?=E5=AE=A1=E6=A0=B8=E4=BF=AE=E6=94=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
...amming-in-javascript-composing-software.md | 30 +++++++++----------
1 file changed, 15 insertions(+), 15 deletions(-)
diff --git a/TODO/why-learn-functional-programming-in-javascript-composing-software.md b/TODO/why-learn-functional-programming-in-javascript-composing-software.md
index c260bf55297..76ee8309ca0 100644
--- a/TODO/why-learn-functional-programming-in-javascript-composing-software.md
+++ b/TODO/why-learn-functional-programming-in-javascript-composing-software.md
@@ -1,8 +1,8 @@
> * 原文地址:[Why Learn Functional Programming in JavaScript? (Composing Software)(part 2)](https://medium.com/javascript-scene/why-learn-functional-programming-in-javascript-composing-software-ea13afc7a257)
> * 原文作者:[Eric Elliott](https://medium.com/@_ericelliott?source=post_header_lockup)
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
-> * 译者:
-> * 校对者:
+> * 译者:[gy134340](https://github.com/gy134340)
+> * 校对者:[sunui](https://github.com/sunui),[avocadowang](https://github.com/avocadowang)
# 为什么用 JavaScript 学习函数式编程?(软件构建)(第二部分)
@@ -10,7 +10,7 @@
烟雾的方块艺术 —MattysFlicks —(CC BY 2.0)
> 注意:这是从基础学习函数式编程和使用 JavaScript ES6+ 撰写软件的第二部分。保持关注,接下来还有很多!
-> [从第一部分开始](https://medium.com/javascript-scene/the-rise-and-fall-and-rise-of-functional-programming-composable-software-c2d91b424c8c#.2dfd6n6qe) | [接下来的 >](https://medium.com/javascript-scene/a-functional-programmers-introduction-to-javascript-composing-software-d670d14ede30#.2e4youss2)
+> [从第一部分开始](https://github.com/xitu/gold-miner/blob/master/TODO/the-rise-and-fall-and-rise-of-functional-programming-composable-software.md) | [接下来的 >](https://github.com/xitu/gold-miner/blob/master/TODO/a-functional-programmers-introduction-to-javascript-composing-software.md)
忘掉你认为知道的关于 JavaScript 的一切,用初学者的眼光去看待它。为了帮助你做到这一点,我们将会从头复习一下 JavaScript 的基础,就像你与其尚未谋面一样。如果你是初学者,那你就很幸运了。最终从零开始探索 ES6 和函数式编程!希望所有的概念都被解释清楚 — 但不要太依赖于此。
@@ -20,9 +20,9 @@
JavaScript 有函数式编程所需要的最重要的特性:
-1. **一级公民函数:**使用函数作为数据值的能力:用函数传参,返回函数,用函数做变量和对象属性。这个属性允许更高级别的函数,使偏函数应用、柯里化和组合成为可能。
-2. **匿名函数和简洁的 lambda 语法:**`x => x * 2` 是 JavaScript 中有效的函数表达式。简洁的 lambda 语法使得高阶函数变的简单。
-3. **闭包:**闭包是一个有着自己独立作用域的捆绑函数。闭包在函数被创建时被创建。当一个函数在另一个函数内部被创建,它可以访问外部函数的变量,即使在外部函数退出后。通过闭包偏函数应用可以获取内部固定参数。固定的参数时绑定在返回函数的作用域范围内的参数。在 `add2(1)(2)` 中,`1` 是 `add2(1)` 返回的函数中的固定参数。
+1. **一级公民函数:** 使用函数作为数据值的能力:用函数传参,返回函数,用函数做变量和对象属性。这个属性允许更高级别的函数,使偏函数应用、柯里化和组合成为可能。
+2. **匿名函数和简洁的 lambda 语法:** `x => x * 2` 是 JavaScript 中有效的函数表达式。简洁的 lambda 语法使得高阶函数变的简单。
+3. **闭包:** 闭包是一个有着自己独立作用域的捆绑函数。闭包在函数被创建时被创建。当一个函数在另一个函数内部被创建,它可以访问外部函数的变量,即使在外部函数退出后。通过闭包偏函数应用可以获取内部固定参数。固定的参数时绑定在返回函数的作用域范围内的参数。在 `add2(1)(2)` 中,`1` 是 `add2(1)` 返回的函数中的固定参数。
### JavaScript 缺少了什么
@@ -40,19 +40,19 @@ JavaScript 是多范式语言,意味着它支持多种风格的编程。其他
下面是一些函数式语言拥有但是 JavaScript 没有的特性:
-1. **纯粹性:**在一些函数式语言中,纯粹性是强制的,有副作用的表达式是不被允许的。
-2. **不可变性:**一些函数式语言不允许转变,采用表达式来产生新的数据结构来代替更改一个已存的数据结构,比如说数组或者对象。这样看起来可能不够高效,但是大多数函数式语言在引擎下使用 trie 数据结构,具有结构共享的特点:意味着旧的对象和新的对象是对相同数据的引用。
-3. **递归:**递归是函数引用自身来进行迭代的能力。在大多数函数式语言中,递归是迭代的唯一方式,它们没有像 `for` 、`while`、`do` 这类循环语句。
+1. **纯粹性:** 在一些函数式语言中,纯粹性是强制的,有副作用的表达式是不被允许的。
+2. **不可变性:** 一些函数式语言不允许转变,采用表达式来产生新的数据结构来代替更改一个已存的数据结构,比如说数组或者对象。这样看起来可能不够高效,但是大多数函数式语言在引擎下使用 trie 数据结构,具有结构共享的特点:意味着旧的对象和新的对象是对相同数据的引用。
+3. **递归:** 递归是函数引用自身来进行迭代的能力。在大多数函数式语言中,递归是迭代的唯一方式,它们没有像 `for` 、`while`、`do` 这类循环语句。
-**纯粹性:**在 JavaScript 中,纯粹性由约定来达成,如果你不是使用纯函数来构成你的大多数应用,那么你就不是在进行函数式风格的编程。很不幸,在 JavaScript 中,你很容易就会不小心创建和使用一些不纯的函数。
+**纯粹性:** 在 JavaScript 中,纯粹性由约定来达成,如果你不是使用纯函数来构成你的大多数应用,那么你就不是在进行函数式风格的编程。很不幸,在 JavaScript 中,你很容易就会不小心创建和使用一些不纯的函数。
-**不可变性:**在纯函数式语言中,不可变性通常是强制的,JavaScript 缺少函数式语言中高效的、基于 trie 树的数据结构,但是你可以使用一些库,包括 [Immutable.js](https://facebook.github.io/immutable-js/) 和 [Mori](https://github.com/swannodette/mori),由衷期望未来的 ECMAScript 规范版本可以拥抱不可变数据结构。
+**不可变性:** 在纯函数式语言中,不可变性通常是强制的,JavaScript 缺少函数式语言中高效的、基于 trie 树的数据结构,但是你可以使用一些库,包括 [Immutable.js](https://facebook.github.io/immutable-js/) 和 [Mori](https://github.com/swannodette/mori),由衷期望未来的 ECMAScript 规范版本可以拥抱不可变数据结构。
有一些迹象带来了希望,比如说在 ES6 中添加了 `const` 关键字,`const` 声明的变量不能被重新赋值,重要的是要理解 `const` 所声明的值并不是不可改变的。
`const` 声明的对象不能被重新声明为新的对象,但是对象的属性却是可变的,JavaScript 有 `freeze()` 对象的能力,但是这些对象只能在根实例上被冻结,意味着嵌套着的对象还是可以改变它的属性。换句话说,在 JavaScript 规范中看到真正的不可变还有很长的路要走。
-**递归:**JavaScript 技术上支持递归,但是大多数函数式语言都有尾部调用优化的特性,尾部调用优化是一个允许递归的函数重用堆栈帧来递归调用的特性。
+**递归:** JavaScript 技术上支持递归,但是大多数函数式语言都有尾部调用优化的特性,尾部调用优化是一个允许递归的函数重用堆栈帧来递归调用的特性。
没有尾部调用优化,一个调用的栈很可能没有边界导致堆栈溢出。JavaScript 在 ES6 规范中有一个有限的尾调用优化。不幸的是,只有一个主要的浏览器引擎支持它,这个优化被部分应用随后从 Babel(最流行的 JavaScript 编译器,在旧的浏览器中被用来把 ES6 编译到 ES5) 中移除。
@@ -64,7 +64,7 @@ JavaScript 是多范式语言,意味着它支持多种风格的编程。其他
Monads 的问题是,尽管它的使用很简单,但是对一个不是很熟悉它的人解释清楚它有点像“对牛谈琴”。
-> “Monad说白了不过就是自函子范畴上的一个幺半群而已,这有什么难以理解的?” ~James Iry 所引用 Philip Wadler 的话,解释一个 Saunders Mac Lane 说过的名言。[*“编程语言简要、不完整之黑历史”*](http://james-iry.blogspot.com/2009/05/brief-incomplete-and-mostly-wrong.html)
+> “Monad说白了不过就是自函子范畴上的一个幺半群而已,这有什么难以理解的?” ~James Iry 所引用 Philip Wadler 的话,解释一个 Saunders Mac Lane 说过的名言。[**“编程语言简要、不完整之黑历史”**](http://james-iry.blogspot.com/2009/05/brief-incomplete-and-mostly-wrong.html)
典型的,这是在调侃这有趣的一点。在上面的引用中,关于 Monads 的解释相比最初的有了很大的简化,原来是下面这样:
@@ -135,7 +135,7 @@ JavaScript 的真正优势在于其生态系统中的思想和用户的多样性
App 正在吞食世界, web 正在吞食 app, 同时 JavaScript 正在吞食 web。
-[**接下来的第三部分: 函数式开发者的 JavScript 介绍…**](https://medium.com/javascript-scene/a-functional-programmers-introduction-to-javascript-composing-software-d670d14ede30#.zdpw16p65)
+[**接下来的第三部分: 函数式开发者的 JavScript 介绍…**](https://github.com/xitu/gold-miner/blob/master/TODO/a-functional-programmers-introduction-to-javascript-composing-software.md)
### 下一步
@@ -148,7 +148,7 @@ App 正在吞食世界, web 正在吞食 app, 同时 JavaScript 正在吞食
*Eric Elliott* 是 [*“Programming JavaScript Applications”*](http://pjabook.com) (O’Reilly) 和 “Learn JavaScript with Eric Elliott” 的作者。他曾效力于 *Adobe Systems, Zumba Fitness, he Wall Street Journal, ESPN, BBC, and top recording artists including Usher, Frank Ocean, Metallica* 和其他一些公司。
-*他和她的老婆(很漂亮)大部分时间都在旧金山湾区里。*
+**他和她的老婆(很漂亮)大部分时间都在旧金山湾区里。**
---
From faead526a8bbdb96a5e142a35150f99f78493622 Mon Sep 17 00:00:00 2001
From: gy134340
Date: Thu, 13 Apr 2017 23:29:35 +0800
Subject: [PATCH 163/638] Change name
---
...n-functional-programming-in-javascript-composing-software.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/TODO/why-learn-functional-programming-in-javascript-composing-software.md b/TODO/why-learn-functional-programming-in-javascript-composing-software.md
index 76ee8309ca0..1a9327f182e 100644
--- a/TODO/why-learn-functional-programming-in-javascript-composing-software.md
+++ b/TODO/why-learn-functional-programming-in-javascript-composing-software.md
@@ -4,7 +4,7 @@
> * 译者:[gy134340](https://github.com/gy134340)
> * 校对者:[sunui](https://github.com/sunui),[avocadowang](https://github.com/avocadowang)
-# 为什么用 JavaScript 学习函数式编程?(软件构建)(第二部分)
+# 为什么用 JavaScript 学习函数式编程?(软件编写)(第二部分)
From 5b1b51ebdafc4dff22796cad47f941d7edb82f82 Mon Sep 17 00:00:00 2001
From: gy134340
Date: Thu, 13 Apr 2017 23:31:51 +0800
Subject: [PATCH 164/638] Change title
---
...-and-rise-of-functional-programming-composable-software.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/TODO/the-rise-and-fall-and-rise-of-functional-programming-composable-software.md b/TODO/the-rise-and-fall-and-rise-of-functional-programming-composable-software.md
index a529896a3c1..c02cffb517d 100644
--- a/TODO/the-rise-and-fall-and-rise-of-functional-programming-composable-software.md
+++ b/TODO/the-rise-and-fall-and-rise-of-functional-programming-composable-software.md
@@ -4,13 +4,13 @@
> * 译者:[gy134340](https://github.com/gy134340)
> * 校对者:[avocadowang](https://github.com/avocadowang),[Aladdin-ADD](https://github.com/Aladdin-ADD)
-# 跌宕起伏的函数式编程(软件构建)
+# 跌宕起伏的函数式编程(软件编写)
烟雾的方块艺术 —MattysFlicks —(CC BY 2.0)
-> 注意:这是从基础学习函数式编程和使用 JavaScript ES6+ 构建软件的第一部分。保持关注,接下来还有很多!
+> 注意:这是从基础学习函数式编程和使用 JavaScript ES6+ 编写软件的第一部分。保持关注,接下来还有很多!
当我 6 岁时,我花了很多时间跟我的小伙伴玩电脑游戏,他家有一个装满电脑的房间。对于我说,它们有不可抗拒的魔力。我花了很多时间探索所有的游戏。一天我问他,“我们怎样做一个游戏?”
From e4b0de65a66405a4f0afb4b5c5f897f8ec8efedd Mon Sep 17 00:00:00 2001
From: zhuzi
Date: Fri, 14 Apr 2017 01:05:56 +0800
Subject: [PATCH 165/638] update translation
---
TODO/secure-web-app-http-headers.md | 56 ++++++++++++++++++++---------
1 file changed, 39 insertions(+), 17 deletions(-)
diff --git a/TODO/secure-web-app-http-headers.md b/TODO/secure-web-app-http-headers.md
index af59d9b41f1..d15fe288045 100644
--- a/TODO/secure-web-app-http-headers.md
+++ b/TODO/secure-web-app-http-headers.md
@@ -219,13 +219,17 @@ functionrequestHandler(req, res){
res.setHeader('X-XSS-Protection','1;mode=block');}
```
-### Controlling Framing ###
+### Controlling Framing 控制 iframe ###
-An iframe (or HTML inline frame element, if you want to be more formal) is a DOM element that allows a web app to be nested within a parent web app. This powerful element enables some important web use cases, such as embedding third-party content into web apps, but it also has significant drawbacks, such as not being SEO-friendly and not playing nice with browser navigation — the list goes on.
+> An iframe (or HTML inline frame element, if you want to be more formal) is a DOM element that allows a web app to be nested within a parent web app. This powerful element enables some important web use cases, such as embedding third-party content into web apps, but it also has significant drawbacks, such as not being SEO-friendly and not playing nice with browser navigation — the list goes on.
-One of the caveats of iframes is that it makes clickjacking easier. Clickjacking is an attack that tricks the user into clicking something different than what they think they’re clicking. To understand a simple implementation of clickjacking, consider the HTML markup below, which tries to trick the user into buying a toaster when they think they are clicking to win a prize!
+iframe (正式来说,是一个 HTML 的行内框架元素)是一个 DOM 元素,它允许一个 web 应用嵌套在另一个 web 应用中。这个强大的元素有部分重要的使用场景,比如在 web 应用中嵌入第三方内容, 但它也有重大的缺点,例如对 SEO 不友好,对浏览器导航跳转也不友好,还有很多。
-```
+> One of the caveats of iframes is that it makes clickjacking easier. Clickjacking is an attack that tricks the user into clicking something different than what they think they’re clicking. To understand a simple implementation of clickjacking, consider the HTML markup below, which tries to trick the user into buying a toaster when they think they are clicking to win a prize!
+
+其中一个需要注意的事是它是的点击劫持变得更加容易。点击劫持是一种让用户点击与他们想要点击的不同的攻击。要理解一个简单的劫持实现,参考以下 HTML,当用户认为他们点击可以获得奖品时,实际上是试图欺骗用户购买面包机。
+
+```html
@@ -234,38 +238,56 @@ One of the caveats of iframes is that it makes clickjacking easier. Clickjacking
```
-Clickjacking has many malicious applications, such as tricking the user into confirming a Facebook like, purchasing an item online and even submitting confidential information. Malicious web apps can leverage iframes for clickjacking by embedding a legitimate web app inside their malicious web app, rendering the iframe invisible with the `opacity: 0` CSS rule, and placing the iframe’s click target directly on top of an innocent-looking button rendered by the malicious web app. A user who clicks the innocent-looking button will trigger a click on the embedded web app — without at all knowing the effect of their click.
+> Clickjacking has many malicious applications, such as tricking the user into confirming a Facebook like, purchasing an item online and even submitting confidential information. Malicious web apps can leverage iframes for clickjacking by embedding a legitimate web app inside their malicious web app, rendering the iframe invisible with the `opacity: 0` CSS rule, and placing the iframe’s click target directly on top of an innocent-looking button rendered by the malicious web app. A user who clicks the innocent-looking button will trigger a click on the embedded web app — without at all knowing the effect of their click.
+
+点击劫持有许多恶意应用程序,例如欺骗用户确认 Facebook 点赞,在线购买商品,甚至提交机密信息。恶意 web 应用程序可以通过在其恶意应用中嵌入合法的 web 应用来利用 iframe 进行点击劫持,这可以通过设置 `opacity: 0` 的 CSS 规则将其隐藏,并将 iframe 的点击目标直接放置在看起来无辜的按钮之上。点击了这个无辜按钮的用户会直接点击在嵌入的 web 应用上,并不知道点击后的作用。
-An effective way to block this attack is by restricting your web app from being framed. `X-Frame-Options`, specified in [RFC 7034](https://www.ietf.org/rfc/rfc7034.txt), is designed to do exactly that! This header instructs the browser to apply limitations on whether your web app can be embedded within another web page, thus blocking a malicious web page from tricking users into invoking various transactions on your web app. You can either block framing completely using the `DENY` directive, whitelist specific domains using the `ALLOW-FROM` directive, or whitelist only the web app’s origin using the `SAMEORIGIN` directive.
+> An effective way to block this attack is by restricting your web app from being framed. `X-Frame-Options`, specified in [RFC 7034](https://www.ietf.org/rfc/rfc7034.txt), is designed to do exactly that! This header instructs the browser to apply limitations on whether your web app can be embedded within another web page, thus blocking a malicious web page from tricking users into invoking various transactions on your web app. You can either block framing completely using the `DENY` directive, whitelist specific domains using the `ALLOW-FROM` directive, or whitelist only the web app’s origin using the `SAMEORIGIN` directive.
-My recommendation is to use the `SAMEORIGIN` directive, which enables iframes to be leveraged for apps on the same domain — which may be useful at times — and which maintains security. This recommended header looks like this:
+阻止这种攻击的一种有效的方法是限制你的 web 应用被框架化。`X-Frame-Options`,在 [RFC 7034](https://www.ietf.org/rfc/rfc7034.txt) 中引入,就是设计用来做这件事的。此响应头指示浏览器对你的 web 应用是否可以被嵌入另一个网页进行限制,从而阻止恶意网页欺骗用户调用你的应用程序上的各种事务。你可以使用 `DENY` 完全屏蔽,或者使用 `ALLOW-FROM` 指定将特定域列入白名单,也可以使用 `SAMEORIGIN` 指令将应用的源地址列入白名单。
+
+> My recommendation is to use the `SAMEORIGIN` directive, which enables iframes to be leveraged for apps on the same domain — which may be useful at times — and which maintains security. This recommended header looks like this:
+
+我的建议是使用 `SAMEORIGIN` 指令,因为它允许 iframe 被用于同一域上的可以保证安全性的应用程序,这有时是有用的。
```
X-Frame-Options: SAMEORIGIN
```
-Here’s an example of a configuration of this header to enable framing on the same origin in Node.js:
+以下是在 Node.js 中设置此响应头的示例代码:
-```
+```javascript
functionrequestHandler(req, res){
res.setHeader('X-Frame-Options','SAMEORIGIN');}
```
-### Explicitly Whitelisting Sources ###
+### 指定白名单资源 ###
-As we’ve noted earlier, you can add in-depth security to your web app by enabling the browser’s XSS filter. However, note that this mechanism is limited, is not supported by all browsers (Firefox, for instance, does not have an XSS filter) and relies on pattern-matching techniques that can be tricked.
+> As we’ve noted earlier, you can add in-depth security to your web app by enabling the browser’s XSS filter. However, note that this mechanism is limited, is not supported by all browsers (Firefox, for instance, does not have an XSS filter) and relies on pattern-matching techniques that can be tricked.
-Another layer of in-depth protection against XSS and other attacks can be achieved by explicitly whitelisting trusted sources and operations — which is what Content Security Policy (CSP) enables web app developers to do.
+如前所述,你可以通过启用浏览器的 XSS 过滤器,给你的 web 应用程序增强安全性。然而请注意,这种机制是有局限性的,不是所有浏览器都支持(例如 Firefox 就不支持 XSS 过滤),并且依赖的模式匹配技术可以被欺骗。
-CSP is a [W3C specification](https://www.w3.org/TR/2016/WD-CSP3-20160901/) that defines a powerful browser-based security mechanism, enabling granular control over resource-loading and script execution in a web app. With CSP, you can whitelist specific domains for operations such as script-loading, AJAX calls, image-loading and style sheet-loading. You can enable or disable inline scripts or dynamic scripts (the notorious `eval`) and control framing by whitelisting specific domains for framing. Another cool feature of CSP is that it allows you to configure a real-time reporting target, so that you can monitor your app in real time for CSP blocking operations.
+> Another layer of in-depth protection against XSS and other attacks can be achieved by explicitly whitelisting trusted sources and operations — which is what Content Security Policy (CSP) enables web app developers to do.
-This explicit whitelisting of resource loading and execution provides in-depth security that in many cases will fend off attacks. For example, by using CSP to disallow inline scripts, you can fend off many of the reflective XSS attack variants that rely on injecting inline scripts into the DOM.
+对抗 XSS 和其他攻击的更多一层的保护,可以通过明确列出可信来源和操作来实现 —— 这就是内容安全策略(CSP)。
-CSP is a relatively complex header, with a lot of directives, and I won’t go into the details of the various directives. HTML5 Rocks has a [great tutorial](https://www.html5rocks.com/en/tutorials/security/content-security-policy/) that provides an overview of CSP, and I highly recommend reading it and learning how to use CSP in your web app.
+> CSP is a [W3C specification](https://www.w3.org/TR/2016/WD-CSP3-20160901/) that defines a powerful browser-based security mechanism, enabling granular control over resource-loading and script execution in a web app. With CSP, you can whitelist specific domains for operations such as script-loading, AJAX calls, image-loading and style sheet-loading. You can enable or disable inline scripts or dynamic scripts (the notorious `eval`) and control framing by whitelisting specific domains for framing. Another cool feature of CSP is that it allows you to configure a real-time reporting target, so that you can monitor your app in real time for CSP blocking operations.
-Here’s a simple example of a CSP configuration to allow script-loading from the app’s origin only and to block dynamic script execution (`eval`) and inline scripts (as usual, on Node.js):
+CSP 是一种 W3C 规范,它定义了强大的基于浏览器的安全机制,可以对 web 应用中的资源加载以及脚本执行进行精细的控制。使用 CSP 可以将特定的域加入白名单进行例如脚本加载、AJAX 调用、图像加载和样式加载。你可以启用或禁用内嵌脚本或动态脚本(臭名昭著的 `eval`),并通过将特定域列入白名单来控制 iframe。CSP 的另一个很酷的功能是它允许配置实时报告目标,一遍实时监控应用程序进行 CSP 阻止操作。
-```
+> This explicit whitelisting of resource loading and execution provides in-depth security that in many cases will fend off attacks. For example, by using CSP to disallow inline scripts, you can fend off many of the reflective XSS attack variants that rely on injecting inline scripts into the DOM.
+
+这种对资源加载和脚本执行的明确的白名单提供了很强的安全性,在很多情况下都可以防范攻击。例如,使用 CSP 禁止内嵌脚本,你可以防范很多反射型 XSS 攻击,因为它们依赖于将内嵌脚本注入到 DOM。
+
+> CSP is a relatively complex header, with a lot of directives, and I won’t go into the details of the various directives. HTML5 Rocks has a [great tutorial](https://www.html5rocks.com/en/tutorials/security/content-security-policy/) that provides an overview of CSP, and I highly recommend reading it and learning how to use CSP in your web app.
+
+CSP 是一个相对复杂的响应头,它有很多种指令,在这里我不详细展开了,可以参考 HTML5 Rocks 里一篇很棒的[教程](https://www.html5rocks.com/en/tutorials/security/content-security-policy/),提供了 CSP 的概述,我非常推荐阅读它来学习如何在你的 web 应用中使用 CSP。
+
+> Here’s a simple example of a CSP configuration to allow script-loading from the app’s origin only and to block dynamic script execution (`eval`) and inline scripts (as usual, on Node.js):
+
+以下是一个设置 CSP 的示例代码,它仅允许从应用程序的源域加载脚本,并组织动态脚本的执行(eval)以及内嵌脚本(当然,还是 Node.js):
+
+```javascript
functionrequestHandler(req, res){
res.setHeader('Content-Security-Policy',"script-src 'self'");}
```
From 1d57ea5b8c23304f3943e32de02ca3710c1d0ec7 Mon Sep 17 00:00:00 2001
From: Wenlin Ou
Date: Thu, 13 Apr 2017 18:15:39 -0400
Subject: [PATCH 166/638] added proofreader info and error fixes
---
TODO/nothing-will-change-until-you-start-building.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/TODO/nothing-will-change-until-you-start-building.md b/TODO/nothing-will-change-until-you-start-building.md
index f063274822b..f5c5b91bc89 100644
--- a/TODO/nothing-will-change-until-you-start-building.md
+++ b/TODO/nothing-will-change-until-you-start-building.md
@@ -2,7 +2,7 @@
> * 原文作者:[Jonathan Z. White](https://medium.freecodecamp.com/@JonathanZWhite?source=post_header_lockup)
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
> * 译者:[owenlyn](https://github.com/owenlyn)
-> * 校对者:
+> * 校对者:[luoqiuyu](https://github.com/luoqiuyu),[Tina92](https://github.com/Tina92)
---
@@ -59,7 +59,7 @@
当你明确了你想要解决的问题并有了一个解决方案的时候,你可能会问自己这是不是一个好的点子。
-**相当一部分看起来很糟糕的点子最后被证明是超级棒的生意。** 比如,当年没人想投资 Airbnb。 Brian Chesky, Airbnb 的创始人之一,在他的文章 [7 Rejections](https://medium.com/@bchesky/7-rejections-7d894cbaa084#.l8fdqlasz) 里详细讲述了被投资人拒绝的故事。
+**相当一部分看起来很糟糕的点子最后却造就了一些伟大的公司。** 比如,当年没人想投资 Airbnb。 Brian Chesky, Airbnb 的创始人之一,在他的文章 [7 Rejections](https://medium.com/@bchesky/7-rejections-7d894cbaa084#.l8fdqlasz) 里详细讲述了被投资人拒绝的故事。
![](https://cdn-images-1.medium.com/max/800/1*WpxUxMCO-7NXr-o1yo023g.png)
From b30c68efa9815d4652b09acc573ffbbb3854c38a Mon Sep 17 00:00:00 2001
From: sqrtthree
Date: Fri, 14 Apr 2017 10:33:33 +0800
Subject: [PATCH 167/638] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=97=A0=E7=94=A8?=
=?UTF-8?q?=E7=9A=84=E5=9B=BE=E7=89=87?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
TODO/debugging-tips-tricks.md | 33 +++++++++++++++------------------
1 file changed, 15 insertions(+), 18 deletions(-)
diff --git a/TODO/debugging-tips-tricks.md b/TODO/debugging-tips-tricks.md
index dca2d0b0200..dee46a5eabc 100644
--- a/TODO/debugging-tips-tricks.md
+++ b/TODO/debugging-tips-tricks.md
@@ -4,18 +4,15 @@
> * 译者:
> * 校对者:
-# Debugging Tips and Tricks #
+# Debugging Tips and Tricks #
Writing code is only one small piece of being a developer. In order to be efficient and capable at our jobs, we must also excel at debugging. When I dedicate some time to learning new debugging skills, I often find I can move much quicker, and add more value to the teams I work on. I have a few tips and tricks I rely on pretty heavily and found that I give the same advice again and again during workshops, so here’s a compilation of some of them, as well as some from the community. We'll start with some core tenants and then drill down to more specific examples.
-[![](https://s3.buysellads.com/1279518/7386844-1491489478.jpg)](https://srv.buysellads.com/ads/click/x/GTND4237CVYDL23JCV74YKQWF67DTKJNCT7DKZ3JCEAI45QUCT7D6K7KC6BDLKJEF67DTK3EHJNCLSIZ)
-
-
### # Main Concepts ###
#### # Isolate the Problem ####
-Isolation is possibly the strongest core tenant in all of debugging. Our codebases can be sprawling, with different libraries, frameworks, and they can include many contributors, even people who aren't working on the project anymore. Isolating the problem helps us slowly whittle away non-essential parts of the problem so that we can singularly focus on a solution.
+Isolation is possibly the strongest core tenant in all of debugging. Our codebases can be sprawling, with different libraries, frameworks, and they can include many contributors, even people who aren't working on the project anymore. Isolating the problem helps us slowly whittle away non-essential parts of the problem so that we can singularly focus on a solution.
Some of the benefits of isolation include, but are not limited to:
@@ -36,7 +33,7 @@ You can take this one step further in Chrome DevTools and even walk through the
Good 'ol `console.log` is a form of isolation. (Or `echo` in PHP, or `print` in python, etc…). You are taking one tiny piece of execution and testing your assumptions, or checking to see if something is altering. This is probably the most time-tested form of debugging, that no matter how advanced you become, still has it's uses. Arrow functions in ES6 have allowed us to step up our console debugging game as well, as it’s now a lot easier to write useful one-liners in the console.
-The `console.table` function is also a favorite tool of mine, especially great for when you have a lot of data you need to represent- large arrays, large objects and the like. The `console.dir` function is also a nice alternative. It will log an interactive listing of an object's properties.
+The `console.table` function is also a favorite tool of mine, especially great for when you have a lot of data you need to represent- large arrays, large objects and the like. The `console.dir` function is also a nice alternative. It will log an interactive listing of an object's properties.
![](https://cdn.css-tricks.com/wp-content/uploads/2017/04/dir.png)
@@ -93,11 +90,11 @@ The CSS tracker shows color-coded rules for used and unused sets.
#### # Misc Tools ####
-- [What input](https://ten1seven.github.io/what-input/) is a global utility for tracking the current input method (mouse, keyboard or touch), as well as the current intent- this can be really good for tracking down accessiblity leaks (hat tip to Marcy Sutton, accessibility expert for this tipoff)
+- [What input](https://ten1seven.github.io/what-input/) is a global utility for tracking the current input method (mouse, keyboard or touch), as well as the current intent- this can be really good for tracking down accessiblity leaks (hat tip to Marcy Sutton, accessibility expert for this tipoff)
- [Ghostlabapp](https://www.vanamco.com/ghostlab/) is a pretty snazzy tool if you’re doing responsive development or checking anything deployed across a ton of devices. It offers synchronized web development, testing, and inspection.
- [Eruda is an awesome tool](http://eruda.liriliri.io/) that helps debug on mobile devices. I really like it because it takes a simulator a step further, gives a console and real devtools to help you gain understanding.
-![eruda gives you a mobile console](https://cdn.css-tricks.com/wp-content/uploads/2017/04/Screen-Shot-2017-04-10-at-10.38.57-AM.png)
+![eruda gives you a mobile console](https://cdn.css-tricks.com/wp-content/uploads/2017/04/Screen-Shot-2017-04-10-at-10.38.57-AM.png)
### # Specific Tips ###
@@ -119,7 +116,7 @@ $('body').on('focusin',function(){
We got quite a lot of responses saying that people put red borders on elements to see what they’re doing
> [@sarah_edo](https://twitter.com/sarah_edo) for CSS, I'll usually have a .debug class with a red border that I slap on troublesome elements.
->
+>
> — Jeremy Wagner (@malchata) [March 15, 2017](https://twitter.com/malchata/status/842029469246324736)
I do this too, I even have a little CSS file that drops in some classes I can access for different colors easily.
@@ -127,7 +124,7 @@ I do this too, I even have a little CSS file that drops in some classes I can ac
#### # Checking State in React ####
> [@sarah_edo](https://twitter.com/sarah_edo)
{JSON.stringify(this.state, null, 2)}
->
+>
> — MICHAEL JACKSON (@mjackson) [March 15, 2017](https://twitter.com/mjackson/status/842041642760646657)
Props to Michael, this is one of the most useful debugging tools I know of. That snippet "pretty prints" the state of the component you're working with onto the component so that you can see what’s going on. You can validate that the state is working the way that you think it should be, and it helps track down any errors between the state and how you're using it.
@@ -137,7 +134,7 @@ Props to Michael, this is one of the most useful debugging tools I know of. That
We got a lot of responses that said they slow the animation way down:
> [@sarah_edo](https://twitter.com/sarah_edo)[@Real_CSS_Tricks](https://twitter.com/Real_CSS_Tricks) * { animation-duration: 10s !important; }
->
+>
> — Thomas Fuchs (@thomasfuchs) [March 15, 2017](https://twitter.com/thomasfuchs/status/842029720820695040)
I mentioned this on a post I wrote right here on CSS Tricks about [debugging CSS Keyframe animations](https://css-tricks.com/debugging-css-keyframe-animations/), there are more tips too, like how to hardware accelerate, or work with multiple transforms in different percentages.
@@ -157,7 +154,7 @@ I tend to work on fast connections, so I will throttle my connection to check an
This is also useful in conjunction with a hard reload, or with the cache empty
> [@sarah_edo](https://twitter.com/sarah_edo) Not so secret trick. But still many people are unaware. You need DevTools open, and then right click over the refresh button. [pic.twitter.com/FdAfF9Xtxm](https://t.co/FdAfF9Xtxm)
->
+>
> — David Corbacho (@dcorbacho) [March 15, 2017](https://twitter.com/dcorbacho/status/842033259664035840)
#### # Set a Timed Debugger ####
@@ -175,13 +172,13 @@ It’s similar to the debugger; tool I mentioned earlier, except you can put it
#### # Simulators ####
> [@Real_CSS_Tricks](https://twitter.com/Real_CSS_Tricks) And just in case any Mac users didn't know this, iOS simulator + Safari is sweet. [pic.twitter.com/Uz4XO3e6uD](https://t.co/Uz4XO3e6uD)
->
+>
> — Chris Coyier (@chriscoyier) [March 15, 2017](https://twitter.com/chriscoyier/status/842034009060302848)
I mentioned simulators with Eruda before. iOS users also get a pretty sweet simulator. I was going to tell you you have to install XCode first, but this tweet showed another way:
> [@chriscoyier](https://twitter.com/chriscoyier)[@Real_CSS_Tricks](https://twitter.com/Real_CSS_Tricks) Or, you can use this approach if you didn't want to bother with installing xCode: [https://t.co/WtAnZNo718](https://t.co/WtAnZNo718)
->
+>
> — Chris Harrison (@cdharrison) [March 15, 2017](https://twitter.com/cdharrison/status/842038887904088065)
Chrome also has a device toggle which is helpful.
@@ -189,7 +186,7 @@ Chrome also has a device toggle which is helpful.
#### # Remote Debuggers ####
> [@chriscoyier](https://twitter.com/chriscoyier)[@Real_CSS_Tricks](https://twitter.com/Real_CSS_Tricks)[https://t.co/q3OfWKNlUo](https://t.co/q3OfWKNlUo) is a good tool.
->
+>
> — Gilles 💾⚽ (@gfra54) [March 15, 2017](https://twitter.com/gfra54/status/842035375304523777)
I actually didn't know about this tool until seeing this tweet. Pretty useful!
@@ -198,7 +195,7 @@ I actually didn't know about this tool until seeing this tweet. Pretty useful!
Rachel Andrew gave a presentation at Smashing and mentioned a little waffle thing you can click on in Firefox that will illuminate the gutters in the grid. [Her video](http://gridbyexample.com/learn/2016/12/17/learning-grid-day17/) explains it really eloquently.
-![](https://cdn.css-tricks.com/wp-content/uploads/2017/04/Screen-Shot-2017-04-10-at-9.58.14-AM.png)
+![](https://cdn.css-tricks.com/wp-content/uploads/2017/04/Screen-Shot-2017-04-10-at-9.58.14-AM.png)
Rachel Andrew shows how to highlight gutters in Firefox DevTools.
@@ -207,14 +204,14 @@ Rachel Andrew shows how to highlight gutters in Firefox DevTools.
Wes Bos with a really useful tip for searching for a single item in an array:
> If you are just looking for a single item array.find() is 🔥 [https://t.co/AuRtyFwnq7](https://t.co/AuRtyFwnq7)
->
+>
> — Wes Bos (@wesbos) [March 15, 2017](https://twitter.com/wesbos/status/842069915158884354)
### # Further Debugging Resources ###
Jon Kuperman has a [Frontend Masters course](https://frontendmasters.com/courses/chrome-dev-tools/) that can help you master devtools it goes along [with this app](https://github.com/jkup/mastering-chrome-devtools).
-There’s a small course on code school called [discover devtools](https://www.codeschool.com/courses/discover-devtools).
+There’s a small course on code school called [discover devtools](https://www.codeschool.com/courses/discover-devtools).
Umar Hansa has a new online course called [Modern DevTools](https://moderndevtools.com/).
From d7f45df5a6af8f59194ced27863aa89ceaa8c12b Mon Sep 17 00:00:00 2001
From: reid
Date: Fri, 14 Apr 2017 14:14:05 +0800
Subject: [PATCH 168/638] =?UTF-8?q?=E6=A0=B9=E6=8D=AE=E6=A0=A1=E5=AF=B9?=
=?UTF-8?q?=E6=84=8F=E8=A7=81=E4=BF=AE=E6=94=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
TODO/higher-order-functions-composing-software.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/TODO/higher-order-functions-composing-software.md b/TODO/higher-order-functions-composing-software.md
index 67336f3fd47..0f8e8def2bf 100644
--- a/TODO/higher-order-functions-composing-software.md
+++ b/TODO/higher-order-functions-composing-software.md
@@ -127,7 +127,7 @@ const gt3 = highpass(3);
[1, 2, 3, 4].filter(gt3); // [3, 4];
```
-换言之,高阶函数可以用来实现函数的多态性。如你所见,相较于一阶函数而言,高阶函数的复用性和通用性非常好。一般来讲,在实际编码中会组合使用高阶函数和一些非常简单的一阶函数。
+换言之,高阶函数可以用来实现函数的多态性。如你所见,相对于一阶函数而言,高阶函数的复用性和通用性更好。一般来讲,在实际编码中会组合使用高阶函数和一些非常简单的一阶函数。
[**再续 “Reduce” >**](https://medium.com/javascript-scene/reduce-composing-software-fe22f0c39a1d)
From 966426c87034b8bca35ff74ff6733d14a4149da2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=A0=B9=E5=8F=B7=E4=B8=89?=
Date: Fri, 14 Apr 2017 20:49:01 +0800
Subject: [PATCH 169/638] Update debugging-tips-tricks.md
---
TODO/debugging-tips-tricks.md | 42 +++++++++++++++++------------------
1 file changed, 21 insertions(+), 21 deletions(-)
diff --git a/TODO/debugging-tips-tricks.md b/TODO/debugging-tips-tricks.md
index dee46a5eabc..12b0aec52df 100644
--- a/TODO/debugging-tips-tricks.md
+++ b/TODO/debugging-tips-tricks.md
@@ -8,9 +8,9 @@
Writing code is only one small piece of being a developer. In order to be efficient and capable at our jobs, we must also excel at debugging. When I dedicate some time to learning new debugging skills, I often find I can move much quicker, and add more value to the teams I work on. I have a few tips and tricks I rely on pretty heavily and found that I give the same advice again and again during workshops, so here’s a compilation of some of them, as well as some from the community. We'll start with some core tenants and then drill down to more specific examples.
-### # Main Concepts ###
+### Main Concepts ###
-#### # Isolate the Problem ####
+#### Isolate the Problem ####
Isolation is possibly the strongest core tenant in all of debugging. Our codebases can be sprawling, with different libraries, frameworks, and they can include many contributors, even people who aren't working on the project anymore. Isolating the problem helps us slowly whittle away non-essential parts of the problem so that we can singularly focus on a solution.
@@ -39,7 +39,7 @@ The `console.table` function is also a favorite tool of mine, especially great f
console.dir gives an interactive listing
-#### #Be Methodical ####
+#### Be Methodical ####
When I teach workshops and help students in my class, the number one thing that I find holds them back as they try to debug a problem is not being methodical enough. This is truly a tortoise-and-the-hare kind of situation. They understandably want to move quickly, so they change a ton of things at once, and then when something stops working, they don’t know which thing they changed is causing the error. Then, to debug, they change many things at once and get a little lost trying to figure out what is working and what isn't.
@@ -47,15 +47,15 @@ We all do this to some extent. As we become more proficient with a tool, we can
**Do you remember when you were a kid and your parents said, "if you get lost, stay where you are?"** My parents did, at least. It's because if they were moving around to find me and I was also moving around to find them, we'd have fewer chances of bumping into one another. Code works the same way. The less moving pieces you have, the better- the more you are returning consistent results, the easier it will be to track things down. So while you’re debugging, try not to also install anything, or put in new dependencies. If you see a different error every time you should be returning a static result, that’s a big red flag you should be headed right for with your sleuth hat on.
-### # Choose Good Tools ###
+### Choose Good Tools ###
There are a million different tools for solving a variety of problems. I’m going to work through some of the tools I find the most useful and then we’ll link off to a bevy of resources.
-#### # Syntax Highlighting ####
+#### Syntax Highlighting ####
Sure, it’s damn fun to pick out the new hotness in colors and flavors for your syntax highlighting theme, but spending some time thinking about clarity here matters. I often pick dark themes where a skip in syntax will turn all of my code a lighter color, I find errors are really easy to see right away. I tend to like Oceanic Next or Panda, but really, to each their own on this one. It’s important to keep in mind that when looking for a good syntax highlighter, awesome-looking is great, but functional for calling out your mistakes is most important, and it's totally possible to do both.
-#### # Linting ####
+#### Linting ####
Linting helps flag suspicious code and calls out errors we might have overlooked. Linting is incredibly important, but which linter you choose has so much to do with what language/framework you’re writing in, and then on top of that, what your agreed-upon code style is.
@@ -66,7 +66,7 @@ Here are some resources:
- I recently found [this responsive images linter](https://github.com/ausi/respimagelint), that tells you what opportunities you might have to use picture, srcset, or sizes.
- Here’s a [pretty good breakdown](https://www.sitepoint.com/comparison-javascript-linting-tools/) of some JS linters
-#### # Browser Extensions ####
+#### Browser Extensions ####
Extensions can be really awesome because they can be enabled and disabled so readily, and they can work with really specific requirements. If you’re working with a particular library or framework, chances are, having their extension for DevTools enabled is going to give you all sorts of clarity that you can’t find otherwise. Take care though- not only can extensions bog a browser down, but they have permissions to execute scripts, so do a little homework into the extension author, ratings, and background. All that said, here are some of my favorites:
@@ -76,7 +76,7 @@ Extensions can be really awesome because they can be enabled and disabled so rea
- [Codopen](https://chrome.google.com/webstore/detail/codopen/agnkphdgffianchpipdbkeaclfbobaak): pops you out of the editor mode into a debug window for CodePen. Full disclosure: my husband made this for me as a present because he was sick of watching me manually opening the debug window (best gift ever!)
- [Pageruler](https://chrome.google.com/webstore/detail/page-ruler/jlpkojjdgbllmedoapgfodplfhcbnbpn): get pixel dimensions and measure anything on a page. I like this one because I’m super duper anal about my layout. This helps me feed the beast.
-### # DevTools ###
+### DevTools ###
This is probably the most obvious of debugging tools, and there are so many things you can do with them. They can have so many packed-in features that can be easy to miss, so in the next section of specific tips, we'll go into a deep dive of some favorites.
@@ -88,7 +88,7 @@ One of my favorite recent ones is this [CSS Tracker Enhancement](https://umaar.c
The CSS tracker shows color-coded rules for used and unused sets.
-#### # Misc Tools ####
+#### Misc Tools ####
- [What input](https://ten1seven.github.io/what-input/) is a global utility for tracking the current input method (mouse, keyboard or touch), as well as the current intent- this can be really good for tracking down accessiblity leaks (hat tip to Marcy Sutton, accessibility expert for this tipoff)
- [Ghostlabapp](https://www.vanamco.com/ghostlab/) is a pretty snazzy tool if you’re doing responsive development or checking anything deployed across a ton of devices. It offers synchronized web development, testing, and inspection.
@@ -96,11 +96,11 @@ The CSS tracker shows color-coded rules for used and unused sets.
![eruda gives you a mobile console](https://cdn.css-tricks.com/wp-content/uploads/2017/04/Screen-Shot-2017-04-10-at-10.38.57-AM.png)
-### # Specific Tips ###
+### Specific Tips ###
I am always interested in what other people do to debug, so I asked the community through the CSS-Tricks account and my own what they were really into. This list is a mixture of tips I like as well as a roundup of tips from the community.
-#### # Accessibility ####
+#### Accessibility ####
```
$('body').on('focusin',function(){
@@ -111,7 +111,7 @@ $('body').on('focusin',function(){
-[Marcy Sutton](https://twitter.com/marcysutton)
-#### # Debugging CSS ####
+#### Debugging CSS ####
We got quite a lot of responses saying that people put red borders on elements to see what they’re doing
@@ -121,7 +121,7 @@ We got quite a lot of responses saying that people put red borders on elements t
I do this too, I even have a little CSS file that drops in some classes I can access for different colors easily.
-#### # Checking State in React ####
+#### Checking State in React ####
> [@sarah_edo](https://twitter.com/sarah_edo)
{JSON.stringify(this.state, null, 2)}
>
@@ -129,7 +129,7 @@ I do this too, I even have a little CSS file that drops in some classes I can ac
Props to Michael, this is one of the most useful debugging tools I know of. That snippet "pretty prints" the state of the component you're working with onto the component so that you can see what’s going on. You can validate that the state is working the way that you think it should be, and it helps track down any errors between the state and how you're using it.
-#### # Animation ####
+#### Animation ####
We got a lot of responses that said they slow the animation way down:
@@ -145,7 +145,7 @@ I also slow down my animations in JavaScript- in GreenSock that would look like:
If you want to use the Chrome Devtools timeline to do performance audits, it's worth mentioning that painting is the most expense of the tasks, so all things being equal, pay a little more attention to a high percentage of that green.
-#### # Checking different connection speeds and loads ####
+#### Checking different connection speeds and loads ####
I tend to work on fast connections, so I will throttle my connection to check and see what the performance would look like for people who don’t have my internet speed.
@@ -157,7 +157,7 @@ This is also useful in conjunction with a hard reload, or with the cache empty
>
> — David Corbacho (@dcorbacho) [March 15, 2017](https://twitter.com/dcorbacho/status/842033259664035840)
-#### # Set a Timed Debugger ####
+#### Set a Timed Debugger ####
This one came from Chris. We have a whole writeup on it [right here](https://css-tricks.com/set-timed-debugger-web-inspect-hard-grab-elements/):
@@ -169,7 +169,7 @@ setTimeout(function() {
It’s similar to the debugger; tool I mentioned earlier, except you can put it in a setTimeout function and get even more fine-tuned information
-#### # Simulators ####
+#### Simulators ####
> [@Real_CSS_Tricks](https://twitter.com/Real_CSS_Tricks) And just in case any Mac users didn't know this, iOS simulator + Safari is sweet. [pic.twitter.com/Uz4XO3e6uD](https://t.co/Uz4XO3e6uD)
>
@@ -183,7 +183,7 @@ I mentioned simulators with Eruda before. iOS users also get a pretty sweet simu
Chrome also has a device toggle which is helpful.
-#### # Remote Debuggers ####
+#### Remote Debuggers ####
> [@chriscoyier](https://twitter.com/chriscoyier)[@Real_CSS_Tricks](https://twitter.com/Real_CSS_Tricks)[https://t.co/q3OfWKNlUo](https://t.co/q3OfWKNlUo) is a good tool.
>
@@ -191,7 +191,7 @@ Chrome also has a device toggle which is helpful.
I actually didn't know about this tool until seeing this tweet. Pretty useful!
-#### # CSS Grid Debugging #### (#article-header-id-18 .has-header-link)
+#### CSS Grid Debugging #### (#article-header-id-18 .has-header-link)
Rachel Andrew gave a presentation at Smashing and mentioned a little waffle thing you can click on in Firefox that will illuminate the gutters in the grid. [Her video](http://gridbyexample.com/learn/2016/12/17/learning-grid-day17/) explains it really eloquently.
@@ -199,7 +199,7 @@ Rachel Andrew gave a presentation at Smashing and mentioned a little waffle thin
Rachel Andrew shows how to highlight gutters in Firefox DevTools.
-#### # Array Debugging ####
+#### Array Debugging ####
Wes Bos with a really useful tip for searching for a single item in an array:
@@ -207,7 +207,7 @@ Wes Bos with a really useful tip for searching for a single item in an array:
>
> — Wes Bos (@wesbos) [March 15, 2017](https://twitter.com/wesbos/status/842069915158884354)
-### # Further Debugging Resources ###
+### Further Debugging Resources ###
Jon Kuperman has a [Frontend Masters course](https://frontendmasters.com/courses/chrome-dev-tools/) that can help you master devtools it goes along [with this app](https://github.com/jkup/mastering-chrome-devtools).
From 74a1cd716a7c51e6ed8e88571222cc79905207bc Mon Sep 17 00:00:00 2001
From: zhuzi
Date: Sat, 15 Apr 2017 15:04:50 +0800
Subject: [PATCH 170/638] translation completed
---
TODO/secure-web-app-http-headers.md | 40 +++++++++++++++++------------
1 file changed, 23 insertions(+), 17 deletions(-)
diff --git a/TODO/secure-web-app-http-headers.md b/TODO/secure-web-app-http-headers.md
index d15fe288045..9e1716b7e1f 100644
--- a/TODO/secure-web-app-http-headers.md
+++ b/TODO/secure-web-app-http-headers.md
@@ -292,39 +292,45 @@ functionrequestHandler(req, res){
res.setHeader('Content-Security-Policy',"script-src 'self'");}
```
-### Preventing Content-Type Sniffing ###
+### 防止 Content-Type 嗅探 ###
-In an effort to make the user experience as seamless as possible, many browsers have implemented a feature called content-type sniffing, or MIME sniffing. This feature enables the browser to detect the type of a resource provided as part of an HTTP response by “sniffing” the actual resource bits, regardless of the resource type declared through the `Content-Type` response header. While this feature is indeed useful in some cases, it introduces a vulnerability and an attack vector known as a MIME confusion attack. A MIME-sniffing vulnerability enables an attacker to inject a malicious resource, such as a malicious executable script, masquerading as an innocent resource, such as an image. With MIME sniffing, the browser will ignore the declared image content type, and instead of rendering an image will execute the malicious script.
+> In an effort to make the user experience as seamless as possible, many browsers have implemented a feature called content-type sniffing, or MIME sniffing. This feature enables the browser to detect the type of a resource provided as part of an HTTP response by “sniffing” the actual resource bits, regardless of the resource type declared through the `Content-Type` response header. While this feature is indeed useful in some cases, it introduces a vulnerability and an attack vector known as a MIME confusion attack. A MIME-sniffing vulnerability enables an attacker to inject a malicious resource, such as a malicious executable script, masquerading as an innocent resource, such as an image. With MIME sniffing, the browser will ignore the declared image content type, and instead of rendering an image will execute the malicious script.
-Luckily, the `X-Content-Type-Options` response header mitigates this vulnerability! This header, introduced in Internet Explorer 8 back in 2008 and currently supported by most major browsers (Safari is the only major browser not to support it), instructs the browser not to use sniffing when handling fetched resources. Because `X-Content-Type-Options` was only formally specified as part of the [“Fetch” specification](https://fetch.spec.whatwg.org/#x-content-type-options-header), the actual implementation varies across browsers; some (Internet Explorer and Edge) completely avoid MIME sniffing, whereas others (Firefox) still MIME sniff but rather block executable resources (JavaScript and CSS) when an inconsistency between declared and actual types is detected. The latter is in line with the latest Fetch specification.
+为了使用户体验尽可能无缝连接,许多浏览器实现了一个功能叫 内容类型嗅探,或者 MIME 嗅探。这个功能使得浏览器可以通过「嗅探」实际 HTTP 响应的资源的内容直接检测到资源的类型,无论在响应头中 `Content-Type` 是如何指定资源类型的。虽然这个功能在某些情况下确实是有用的,它引入了一个漏洞以及一种叫 MIME 混乱攻击。MIME 嗅探漏洞使攻击者可以注入恶意资源,例如恶意脚本,伪装成一个无辜的资源,例如一个图片。通过 MIME 嗅探,浏览器将忽略声明的图像内容类型,它不会渲染图片,而是执行恶意脚本。
-`X-Content-Type-Options` is a simple response header, with only one directive: `nosniff`. This header looks like this: `X-Content-Type-Options: nosniff`. Here’s an example of a configuration of the header:
+> Luckily, the `X-Content-Type-Options` response header mitigates this vulnerability! This header, introduced in Internet Explorer 8 back in 2008 and currently supported by most major browsers (Safari is the only major browser not to support it), instructs the browser not to use sniffing when handling fetched resources. Because `X-Content-Type-Options` was only formally specified as part of the [“Fetch” specification](https://fetch.spec.whatwg.org/#x-content-type-options-header), the actual implementation varies across browsers; some (Internet Explorer and Edge) completely avoid MIME sniffing, whereas others (Firefox) still MIME sniff but rather block executable resources (JavaScript and CSS) when an inconsistency between declared and actual types is detected. The latter is in line with the latest Fetch specification.
-```
+幸运的是,`X-Content-Type-Options` 响应头缓解了这个漏洞。此响应头在 2008 年引入 IE8,目前大多数主流浏览器都支持(Safari 是唯一不支持的主流浏览器),它指示浏览器在处理获取的资源时不使用嗅探。因为 `X-Content-Type-Options` 仅在 [「Fetch」规范](https://fetch.spec.whatwg.org/#x-content-type-options-header)中正式指定,实际的实现因浏览器而异。一部分浏览器(IE 和 Edge)完全阻止了 MIME 嗅探,而其他一些(Firefox)仍然会进行 MIME 嗅探,但会屏蔽掉可执行的资源(JavaScript 和 CSS)如果声明的内容类型与实际的类型不一致。后者符合最新的 Fetch 规范。
+
+> `X-Content-Type-Options` is a simple response header, with only one directive: `nosniff`. This header looks like this: `X-Content-Type-Options: nosniff`. Here’s an example of a configuration of the header:
+
+`X-Content-Type-Options` 是一个很简单的响应头,它只有一个指令,`nosniff`。它是这样指定的:`X-Content-Type-Options: nosniff`。以下是示例代码:
+
+```javascript
functionrequestHandler(req, res){
res.setHeader('X-Content-Type-Options','nosniff');}
```
-### Summary ###
+### 总结 ###
-In this article, we have seen how to leverage HTTP headers to reinforce the security of your web app, to fend off attacks and to mitigate vulnerabilities.
+> In this article, we have seen how to leverage HTTP headers to reinforce the security of your web app, to fend off attacks and to mitigate vulnerabilities.
-#### Takeaways ####
+本文中,我们了解了如何利用 HTTP 响应头来加强 web 应用的安全性,防止攻击和减轻漏洞。
-- Disable caching for confidential information using the `Cache-Control` header.
-- Enforce HTTPS using the `Strict-Transport-Security` header, and add your domain to Chrome’s preload list.
-- Make your web app more robust against XSS by leveraging the `X-XSS-Protection` header.
-- Block clickjacking using the `X-Frame-Options` header.
-- Leverage `Content-Security-Policy` to whitelist specific sources and endpoints.
-- Prevent MIME-sniffing attacks using the `X-Content-Type-Options` header.
+#### 要点 ####
-Remember that for the web to be truly awesome and engaging, it has to be secure. Leverage HTTP headers to build a more secure web!
+- 使用 `Cache-Control` 禁用对机密信息的缓存
+- 通过 `Strict-Transport-Security` 强制使用 HTTPS,并将你的域添加到 Chrome 预加载列表
+- 利用 `X-XSS-Protection` 使你的 web 应用更加能抵抗 XSS 攻击
+- 使用 `X-Frame-Options` 阻止点击劫持
+- 利用 `Content-Security-Policy` 将特定来源于端点列入白名单
+- 使用 `X-Content-Type-Options` 防止 MIME 嗅探攻击
+请记住,为了使 web 真正迷人,它必须是安全的。利用 HTTP 响应头构建更加安全的网页吧!
-(**Disclaimer:** The content of this post is my own and doesn’t represent my past or current employers in any way whatsoever.)
-*Front page image credits: [Pexels.com](https://www.pexels.com/photo/coffee-writing-computer-blogging-34600/).*
+(**声明:** 此文内容仅属本人,不代表本人过去或现在的雇主。)
---
From 08853d8784ccbda58465da8b99dac09a020019b6 Mon Sep 17 00:00:00 2001
From: zhuzi
Date: Sat, 15 Apr 2017 16:03:58 +0800
Subject: [PATCH 171/638] reviewed
---
TODO/secure-web-app-http-headers.md | 148 ++++++----------------------
1 file changed, 30 insertions(+), 118 deletions(-)
diff --git a/TODO/secure-web-app-http-headers.md b/TODO/secure-web-app-http-headers.md
index 9e1716b7e1f..7cf3e757680 100644
--- a/TODO/secure-web-app-http-headers.md
+++ b/TODO/secure-web-app-http-headers.md
@@ -6,21 +6,13 @@
## 如何使用 HTTP Headers 来保护你的 Web 应用 ##
-> Web applications, be they thin websites or thick single-page apps, are notorious targets for cyber-attacks. In 2016, approximately [40% of data breaches](http://www.verizonenterprise.com/verizon-insights-lab/dbir/2016/) originated from attacks on web apps — the leading attack pattern. Indeed, these days, understanding cyber-security is not a luxury but rather **a necessity for web developers**, especially for developers who build consumer-facing applications.
+Web 应用,无论是简单的小网页还是复杂的单页应用,众所周知都是网络攻击的目标。2016年,大约 40% 的数据泄露源自对 Web 应用的攻击,这是主要的攻击模式。事实上,现在来说,了解网络安全并不是锦上添花, 而是 **Web 开发者的必需任务**,特别对于构建面向消费者的产品的开发人员。
-Web 应用,无论是简单的小网页还是复杂的单页应用,众所周知都是网络攻击的目标。2016年,大约 40% 的数据泄露源自对 Web 应用的攻击,这是主要的攻击模式。事实上,现在来说,了解网络安全并不是锦上添花, 而是 Web 开发者的必需任务,特别对于构建面向消费者的产品的开发人员。
-
-> HTTP response headers can be leveraged to tighten up the security of web apps, typically just by adding a few lines of code. In this article, we’ll show how web developers can use HTTP headers to build secure apps. While the code examples are for Node.js, setting HTTP response headers is supported across all major server-side-rendering platforms and is typically simple to set up.
-
-开发者可以利用 HTTP 响应头来加强 Web 应用程序的安全性,通常只需要添加几行代码即可。本文将结束 web 开发者如何利用 HTTP Headers 来构建安全的应用。虽然本文的示例代码是 Node.js,但是设置 HTTP 响应头基本在所有主要的服务端语言都是简单易设置的。
+开发者可以利用 HTTP 响应头来加强 Web 应用程序的安全性,通常只需要添加几行代码即可。本文将介绍 web 开发者如何利用 HTTP Headers 来构建安全的应用。虽然本文的示例代码是 Node.js,但是设置 HTTP 响应头基本在所有主要的服务端语言中都是简单易设置的。
### 关于 HTTP Headers ###
-> Technically, HTTP headers are simply fields, encoded in clear text, that are part of the HTTP request and response message header. They are designed to enable both the HTTP client and server to send and receive meta data about the connection to be established, the resource being requested, as well as the returned resource itself.
-
-技术上,HTTP 头只是简单的字段,咦明文形式编码,这是 HTTP 请求和响应消息头的一部分。它们旨在使客户端和服务端都能够发送和接受有关要建立的连接元数据、所请求的资源,以及返回的资源本身的元数据。
-
-> Plain-text HTTP response headers can be examined easily using cURL, with the `--head` option, like so:
+技术上来说,HTTP 头只是简单的字段,以明文形式编码,它是 HTTP 请求和响应消息头的一部分。它们旨在使客户端和服务端都能够发送和接受有关要建立的连接、所请求的资源,以及返回的资源本身的元数据。
可以使用 cURL `--head` 选项轻松检查纯文本 HTTP 响应头,例如:
@@ -37,48 +29,30 @@ Vary: Accept-Encoding
…
```
-> Today, hundreds of headers are used by web apps, some standardized by the [Internet Engineering Task Force](https://www.ietf.org/) (IETF), the open organization that is behind many of the standards that power the web as we know it today, and some proprietary. HTTP headers provide a flexible and extensible mechanism that enables the rich and varying use cases found on the web today.
-
-现在,数百种响应头正在被 web 应用所使用,其中一部分由[互联网工程任务组, IETF](https://www.ietf.org/)标准化。IETF 是一个开发性组织,今天我们所熟知的许多 web 标准或专利都是由他们进行推进的。HTTP 头提供了一种灵活可扩展的机制,造就了现今的网络各种丰富多变的用例。
+现在,数百种响应头正在被 web 应用所使用,其中一部分由[互联网工程任务组(IETF)](https://www.ietf.org/)标准化。IETF 是一个开发性组织,今天我们所熟知的许多 web 标准或专利都是由他们推进的。HTTP 头提供了一种灵活可扩展的机制,造就了现今的网络各种丰富多变的用例。
### 机密资源禁用缓存 ###
-> Caching is a valuable and effective technique for optimizing performance in client-server architectures, and HTTP, which leverages caching extensively, is no exception. However, in cases where the cached resource is confidential, caching can lead to vulnerabilities — and must be avoided. As an example, consider a web app that renders and caches a page with sensitive information and is being used on a shared PC. Anyone can view confidential information rendered by that web app simply by visiting the browser’s cache, or sometimes even as easily as clicking the browser’s “back” button!
-
-缓存是优化客户端-服务端架构性能中有效的技术,广泛利用缓存的 HTTP 也不例外。但是,在缓存的资源是保密的情况下,缓存可能导致漏斗,所以必须避免。假设一个 web 应用对含有敏感信息的网页进行缓存,并且是在一台公用的 PC 上使用。任何人可以通过访问浏览器的缓存看到这个 web 应用上的敏感信息,甚至有时仅仅通过点击浏览器的返回按钮就可以看到。
+缓存是优化客户端-服务端架构性能中有效的技术,广泛利用缓存的 HTTP 并不少见。但是,在缓存的资源是保密的情况下,缓存可能导致漏洞,所以必须避免。假设一个 web 应用对含有敏感信息的网页进行缓存,并且是在一台公用的 PC 上使用,任何人可以通过访问浏览器的缓存看到这个 web 应用上的敏感信息,甚至有时仅仅通过点击浏览器的返回按钮就可以看到。
-> The IETF’s [RFC 7234](https://tools.ietf.org/html/rfc7234), which defines HTTP caching, specifies the default behavior of HTTP clients, both browsers and intermediary Internet proxies, to *always* cache responses to HTTP `GET` requests — unless specified otherwise. While this enables HTTP to boost performance and reduce network congestion, it could also expose end users to theft of personal information, as mentioned above. The good news is that the HTTP specification also defines a pretty simple way to instruct clients not to cache a given response, through the use of — you guessed it! — HTTP response headers.
+IETF [RFC 7234](https://tools.ietf.org/html/rfc7234) 上定义了 HTTP 缓存,指定 HTTP 客户端(浏览器以及网络代理)的默认行为,也就是始终缓存对 HTTP GET 请求的响应,除非另行指定。虽然这样可以使 HTTP 提升性能减少网络拥塞,但如上所述,它也有可能使终端用户个人信息被盗。好消息是,HTTP 规范还定义了一种非常简单的方式来指示客户端对特定响应不进行缓存,通过使用 —— 对,你猜到了 —— HTTP 响应头。
-IETF 的 [RFC 7234](https://tools.ietf.org/html/rfc7234) 上定义了 HTTP 缓存,指定 HTTP 客户端(浏览器以及网络代理)的默认行为,也就是始终缓存对 HTTP GET 请求的相应,除非另行指定。虽然这样可以使 HTTP 提升性能减少网络拥塞,但如上所述,它也有可能使终端用户个人信息被盗。好消息是,HTTP 规范还廷议了一种非常简单的方式来指示客户端对特定响应不进行缓存,通过使用 —— 对,你猜到了 —— HTTP 响应头。
-
-> There are three headers to return when you are returning sensitive information and would like to disable caching by HTTP clients:
-
-当你返回敏感信息并希望禁用 HTTP 客户端的缓存时,有三个头可以返回:
+当你返回敏感信息并希望禁用 HTTP 客户端的缓存时,有三个响应头可以返回:
- `Cache-Control`
-> This response header, introduced in HTTP 1.1, may contain one or more directives, each carrying a specific caching semantic, and instructing HTTP clients and proxies on how to treat the response being annotated by the header. My recommendation is to format the header as follows: `cache-control: no-cache, no-store, must-revalidate`. These three directives pretty much instruct clients and intermediary proxies not to use a previously cached response, not to store the response, and that even if the response is somehow cached, the cache must be revalidated on the origin server.
-
从 HTTP 1.1 引入的此响应头可能包含一个或多个指令,每个指令带有特定的缓存语义,指示 HTTP 客户端和代理如何处理有此响应头注释的响应。我推荐如下指定响应头,`cache-control: no-cache, no-store, must-revalidate`。这三个指令基本上可以指示客户端和中间代理不可使用之前缓存的响应,不可存储响应,甚至就算响应被缓存,也必须从源服务器上重新验证。
- `Pragma: no-cache`
-> For backwards-compatibility with HTTP 1.0, you will want to include this header as well. Some HTTP clients, especially intermediary proxies, still might not fully support HTTP 1.1 and so will not correctly handle the `Cache-Control` header mentioned above. Use `Pragma: no-cache` to ensure that these older clients do not cache your response.
-
-为了与 HTTP 1.0 的向后兼容性,你还需要包含此响应头。有部分客户端,特别是中间代理,可能仍然没有完全支持 HTTP 1.1,所以不能正确处理前面提到的 `Cache-Control` 响应头,所以使用 `Pragma: no-cache` 确保较旧的客户端不缓存你的响应。
+为了向后兼容 HTTP 1.0,你还需要包含此响应头。有部分客户端,特别是中间代理,可能仍然没有完全支持 HTTP 1.1,所以不能正确处理前面提到的 `Cache-Control` 响应头,所以使用 `Pragma: no-cache` 确保较旧的客户端不缓存你的响应。
- `Expires: -1`
-> This header specifies a timestamp after which the response is considered stale. By specifying `-1`, instead of an actual future time, you ensure that clients immediately treat this response as stale and avoid caching.
-
-此标头指定了该响应过时的时间戳。如果不指定为未来某个真实时间而指定为 `-1`,可以保证客户端立即将此响应视为过时并避免缓存。
-
-> Note that, while disabling caching enhances the security of your web app and helps to protect confidential information, is does come at the price of a performance hit. Make sure to disable caching only for resources that actually require confidentiality and not just for any response rendered by your server! For a deeper dive into best practices for caching web resources, I highly recommend reading [Jake Archibald’s post](https://jakearchibald.com/2016/caching-best-practices/) on the subject.
+此响应头指定了该响应过时的时间戳。如果不指定为未来某个真实时间而指定为 `-1`,可以保证客户端立即将此响应视为过期并避免缓存。
需要注意的是,禁用缓存提高安全性及保护机密资源的同时,也的确会带来性能上的折损。所以确保仅对实际需要保密性的资源禁用缓存,而不是对任何服务器的响应禁用。想要更深入了解 web 资源缓存的最佳实践,我推荐阅读 [Jake Archibald 的文章](https://jakearchibald.com/2016/caching-best-practices/)。
-> Here’s how you would program these headers in Node.js:
-
下面是 Node.js 中设置响应头的示例代码:
```javascript
@@ -91,49 +65,29 @@ function requestHandler(req, res) {
### 强制 HTTPS ###
-> Today, the importance of HTTPS is widely recognized by the tech community. More and more web apps configure secured endpoints and are redirecting unsecure traffic to secured endpoints (i.e. HTTP to HTTPS redirects). Unfortunately, end users have yet to fully comprehend the importance of HTTPS, and this lack of comprehension exposes them to various man-in-the-middle (MitM) attacks. The typical user navigates to a web app without paying much attention to the protocol being used, be it secure (HTTPS) or unsecure (HTTP). Moreover, many users will just click past browser warnings when their browser presents a certificate error or warning!
-
-今天,HTTPS 的重要性已经得到了科技界的广泛认可。越来越多的 web 应用配置了安全端点,并将不安全网路重定向到安全端点(即 HTTP 重定向至 HTTPS)。不幸的是,终端用户还未完全理解 HTTPS 的重要性,这种缺乏理解使他们面临着各种中间人攻击(MitM)。典型的用户访问到一个 web 应用时,并不会注意到正在使用的网络协议是安全的(HTTPS)还是不安全的(HTTP)。
-
-> The importance of interacting with web apps over a valid HTTPS connection cannot be overstated: An unsecure connection exposes the user to various attacks, which could lead to cookie theft or worse. As an example, it is not very difficult for an attacker to spoof network frames within a public Wi-Fi network and to extract the session cookies of users who are not using HTTPS. To make things even worse, even users interacting with a web app over a secured connection may be exposed to downgrade attacks, which try to force the connection to be downgraded to an unsecure connection, thus exposing the user to MitM attacks.
-
-通过有效的 HTTPS 连接与 web 应用进行交互的重要性怎么说都不算夸大:不安全的连接将用户暴露给各种攻击,这可能导致 cookie 被盗甚至更糟。举个例子,攻击者可以轻易在公共 Wi-Fi 网络下骗过网络帧并提起不使用 HTTPS 的用户的会话 cookie。更糟的情况是,即使用户通过安全连接与 web 永盈进行交互也可能遭受降级攻击,这种攻击试图强制将连接降级到不安全的连接,从而是用户收到中间人攻击。
-
-> How can we help users avoid these attacks and better enforce the usage of HTTPS? Enter the HTTP Strict Transport Security (HSTS) header. Put simply, HSTS makes sure all communications with the origin host are using HTTPS. Specified in [RFC 6797](https://tools.ietf.org/html/rfc6797), HSTS enables a web app to instruct browsers to allow *only* HTTPS connections to the origin host, to internally redirect all unsecure traffic to secured connections, and to automatically upgrade all unsecure resource requests to be secure.
+今天,HTTPS 的重要性已经得到了科技界的广泛认可。越来越多的 web 应用配置了安全端点,并将不安全网路重定向到安全端点(即 HTTP 重定向至 HTTPS)。不幸的是,终端用户还未完全理解 HTTPS 的重要性,这种缺乏理解使他们面临着各种中间人攻击(MitM)。普通用户访问到一个 web 应用时,并不会注意到正在使用的网络协议是安全的(HTTPS)还是不安全的(HTTP)。
-我们如何帮助用户避免这些攻击,并更好地实施 HTTPS 的使用呢?使用 HTTP 严格传输安全头(HSTS)。简单来说,HSTS 确保与源主机间的所有通信都使用 HTTPS。[RFC 6797](https://tools.ietf.org/html/rfc6797) 中说明了,HSTS可以使 web 应用程序指示浏览器仅允许与源主机之间的 HTTPS 连接,将所有不安全的连接内部重定向到安全连接,并自动将所有不安全的资源请求升级为安全请求。
+通过有效的 HTTPS 连接与 web 应用进行交互的重要性怎么说都不算夸大:不安全的连接将用户暴露给各种攻击,这可能导致 cookie 被盗甚至更糟。举个例子,攻击者可以轻易在公共 Wi-Fi 网络下骗过网络帧并提取不使用 HTTPS 的用户的会话 cookie。更糟的情况是,即使用户通过安全连接与 web 应用进行交互也可能遭受降级攻击,这种攻击试图强制将连接降级到不安全的连接,从而使用户收到中间人攻击。
-> HSTS directives include the following:
+我们如何帮助用户避免这些攻击,并更好地推行 HTTPS 的使用呢?使用 HTTP 严格传输安全头(HSTS)。简单来说,HSTS 确保与源主机间的所有通信都使用 HTTPS。[RFC 6797](https://tools.ietf.org/html/rfc6797) 中说明了,HSTS可以使 web 应用程序指示浏览器仅允许与源主机之间的 HTTPS 连接,将所有不安全的连接内部重定向到安全连接,并自动将所有不安全的资源请求升级为安全请求。
HSTS 的指令如下:
- `max-age=`
->This instructs the browser to cache this header, for this domain, for the specified number of seconds. This can ensure tightened security for a long duration!
-
此项指示浏览器对此域缓存此响应头指定的秒数。这样可以保证长时间的加固安全。
- `includeSubDomains`
->This instructs the browser to apply HSTS for all subdomains of the current domain. This can be useful to cover all current and future subdomains you may have.
-
-此项指示浏览器对当前域的所有子域应用 HSTS,这可以用于覆盖你可能有的所有当前和未来的子域。
+此项指示浏览器对当前域的所有子域应用 HSTS,这可以用于所有当前和未来可能的子域。
- `preload`
-> This is a powerful directive that forces browsers to *always* load your web app securely, even on the first hit, before the response is even received! This works by hardcoding a list of HSTS preload-enabled domains into the browser’s code. To enable the preloading feature, you need to register your domain with [HSTS Preload List Submission](https://hstspreload.org), a website maintained by Google’s Chrome team. Once registered, the domain will be prebuilt into supporting browsers to always enforce HSTS. The preload directive within the HTTP response header is used to confirm registration, indicating that the web app and domain owner are indeed interested in being on the preload list.
-
-这是一个强大的指令,强制浏览器始终安全加载你的 web 应用程序,即使是第一次收到响应之前加载!这是通过将启用 HSTS 预加载域的列表硬编码到浏览器的代码中实现的。要启用预加载功能,你需要在 Google Chrome 团队维护的网站 [HSTS 预加载列表提交](https://hstspreload.org)注册你的域。
-
-> A word of caution: using the `preload` directive also means it cannot be easily undone, and carries an update lead time of months! While preload certainly improves your app’s security, it also means you need to be fully confident your app can support HTTPS-only!
-
-注意谨慎使用 `preload`,因为这意味着它不能轻易撤销,并带有几个月前的更新。虽然预加载肯定会应用程序的安全性,但也意味着你需要充分确信你的应用程序可以支持仅 HTTPS!
+这是一个强大的指令,强制浏览器**始终**安全加载你的 web 应用程序,即使是第一次收到响应之前加载!这是通过将启用 HSTS 预加载域的列表硬编码到浏览器的代码中实现的。要启用预加载功能,你需要在 Google Chrome 团队维护的网站 [HSTS 预加载列表提交](https://hstspreload.org)注册你的域。
-> My recommendation is to use `Strict-Transport-Security: max-age=31536000; includeSubDomains;` which instructs the browser to enforce a valid HTTPS connection to the origin host and to all subdomains for a year. If you are confident that your app can handle HTTPS-only, I would also recommend adding the `preload` directive, in which case don’t forget to register your website on the preload list as well, as noted above!
+注意谨慎使用 `preload`,因为这意味着它不能轻易撤销,并带有几个月前的更新。虽然预加载肯定会加强应用程序的安全性,但也意味着你需要充分确信你的应用程序可以支持仅 HTTPS!
-我推荐的用法是 `Strict-Transport-Security: max-age=31536000; includeSubDomains;`,这样指示了浏览器强制通过 HTTPS 连接到源主机并且有效期为一年。如果你对你的 app 处理 HTTPS 限定很有信心,我也推荐加上 `preload` 指令,当然别忘记去前面提到的预加载列表注册你的网站。
-
-> Here’s what implementing HSTS looks like in Node.js:
+我建议的用法是 `Strict-Transport-Security: max-age=31536000; includeSubDomains;`,这样指示了浏览器强制通过 HTTPS 连接到源主机并且有效期为一年。如果你对你的 app 处理 HTTPS 限定很有信心,我也推荐加上 `preload` 指令,当然别忘记去前面提到的预加载列表注册你的网站。
以下是在 Nodes.js 中实现 HSTS 的方法:
@@ -145,13 +99,9 @@ function requestHandler(req, res){
### 启用 XSS 过滤 ###
-> In a reflected cross-site scripting attack (reflected XSS), an attacker injects malicious JavaScript code into an HTTP request, with the injected code “reflected” in the response and executed by the browser rendering the response, enabling the malicious code to operate within a trusted context, accessing potentially confidential information such as session cookies. Unfortunately, XSS is a pretty common web app attack, and a surprisingly effective one!
-
-在反射型跨站脚本攻击(reflected XSS)中,攻击者将恶意 JavaScript 代码注入到 HTTP 请求,注入的代码「映射」到响应中,并由浏览器执行,从而使恶意代码在可信任的上下文中执行,访问诸如会话 cookie 的潜在机密信息。不幸的是,XSS 是一个很常见的网络应用程序,且令人惊讶地有效!
-
->To understand a reflected XSS attack, consider the Node.js code below, rendering mywebapp.com, a mock and intentionally simple web app that renders search results alongside the search term requested by the user:
+在反射型跨站脚本攻击(reflected XSS)中,攻击者将恶意 JavaScript 代码注入到 HTTP 请求,注入的代码「映射」到响应中,并由浏览器执行,从而使恶意代码在可信任的上下文中执行,访问诸如会话 cookie 中的潜在机密信息。不幸的是,XSS 是一个很常见的网络应用攻击,且令人惊讶地有效!
-为了了解反射型 XSS 攻击,参考以下 Node.js 代码,渲染 `mywebapp.com` 一个模拟并有意简单的 web 应用程序,它将搜索结果以及用户请求的搜索关键词一起呈现:
+为了了解反射型 XSS 攻击,参考以下 Node.js 代码,渲染 `mywebapp.com`,模拟一个简单的 web 应用程序,它将搜索结果以及用户请求的搜索关键词一起呈现:
```javascript
function handleRequest(req, res) {
@@ -173,25 +123,19 @@ function handleRequest(req, res) {
};
```
->Now, consider how will the web app above handle a URL constructed with malicious executable code embedded within the URL, such as this:
-
现在,来考虑一下上面的 web 应用程序会如何处理在 URL 中嵌入的恶意可执行代码,例如:
```
https://mywebapp.com/search?
```
-> As you may realize, this URL will make the browser run the injected script and send the user’s cookies, potentially including confidential session cookies, to evil.com!
-
你可能意识到了,这个 URL 会让浏览器执行注入的脚本,并发送用户的 cookies,极有可能包含机密的会话 cookie,至 evil.com。
-> To help protect users against reflective XSS attacks, some browsers have implemented protection mechanisms. These mechanisms try to identify these attacks by looking for matching code patterns in the HTTP request and response. Internet Explorer was the first browser to introduce such a mechanism with its XSS filter, introduced in Internet Explorer 8 back in 2008, and WebKit later introduced XSS Auditor, available today in Chrome and Safari. (Firefox has no similar mechanism built in, but users can use add-ons to gain this functionality.) These various protection mechanisms are not perfect: They may fail to detect a real XSS attack (a false negative), and in other cases may block legitimate code (a false positive). Due to the latter, browsers allow users to disable the XSS filter via the settings. Unfortunately, this is typically a global setting, which turns off this security feature completely for all web apps loaded by the browser.
-
-为了帮助保护用户抵抗反射型 XSS 攻击,有些浏览器实施了保护机制。这些保护机制尝试通过在 HTTP 请求和响应中寻找匹配的代码模式来辨识这些攻击。Internet Explorer 是第一个推出这种机制的,在 2008 年的 IE 8 中引入了 XSS 过滤器的机制,而 WebKit 后来推出了 XSS 审计,现今在 Chrome 和 Safari 上可用。(Firefox 没有内置类似的机制,但是用户可以使用插件来获得此功能)。这些保护机制并不完美,它们可能无法检测到真正的 XSS 攻击(漏报),在其他情况可能会阻止合法代码(误判)。由于后一种情况的出现,浏览器允许用户可设置禁用 XSS 过滤功能。不幸的是,这通常是一个全局设置,这会完全关闭所有浏览器加载的 web 应用程序的安全功能。
+为了保护用户抵抗反射型 XSS 攻击,有些浏览器实施了保护机制。这些保护机制尝试通过在 HTTP 请求和响应中寻找匹配的代码模式来辨识这些攻击。Internet Explorer 是第一个推出这种机制的,在 2008 年的 IE 8 中引入了 XSS 过滤器的机制,而 WebKit 后来推出了 XSS 审计,现今在 Chrome 和 Safari 上可用(Firefox 没有内置类似的机制,但是用户可以使用插件来获得此功能)。这些保护机制并不完美,它们可能无法检测到真正的 XSS 攻击(漏报),在其他情况可能会阻止合法代码(误判)。由于后一种情况的出现,浏览器允许用户可设置禁用 XSS 过滤功能。不幸的是,这通常是一个全局设置,这会完全关闭所有浏览器加载的 web 应用程序的安全功能。
> Luckily, there is a way for a web app to override this configuration and ensure that the XSS filter is turned on for the web app being loaded by the browser. This is done via the `X-XSS-Protection` header. This header, supported by Internet Explorer (from version 8), Edge, Chrome and Safari, instructs the browser to turn on or off the browser’s built-in protection mechanism and to override the browser’s local configuration.
-幸运的是,有方法可以让 web 应用程序覆盖此配置,并确保浏览器加载的 web 应用已打开 XSS 过滤器。这是通过设定 `X-XSS-Protection` 响应头来达到的。此响应头支持 Internet Explorer (8以上)、Edge、Chrome 和 Safar,指示浏览器打开或关闭浏览器内置的保护机制,及覆盖浏览器的本地配置。
+幸运的是,有方法可以让 web 应用覆盖此配置,并确保浏览器加载的 web 应用已打开 XSS 过滤器。这是通过设定 `X-XSS-Protection` 响应头来达到的。此响应头支持 Internet Explorer (8以上)、Edge、Chrome 和 Safari,指示浏览器打开或关闭内置的保护机制,及覆盖浏览器的本地配置。
`X-XSS-Protection` 指令包括:
@@ -200,13 +144,11 @@ https://mywebapp.com/search?
```
-你可能意识到了,这个 URL 会让浏览器执行注入的脚本,并发送用户的 cookies,极有可能包含机密的会话 cookie,至 evil.com。
+你可能意识到了,这个 URL 会让浏览器执行注入的脚本,并发送极有可能包含机密会话的用户 cookies 到 evil.com。
为了保护用户抵抗反射型 XSS 攻击,有些浏览器实施了保护机制。这些保护机制尝试通过在 HTTP 请求和响应中寻找匹配的代码模式来辨识这些攻击。Internet Explorer 是第一个推出这种机制的,在 2008 年的 IE 8 中引入了 XSS 过滤器的机制,而 WebKit 后来推出了 XSS 审计,现今在 Chrome 和 Safari 上可用(Firefox 没有内置类似的机制,但是用户可以使用插件来获得此功能)。这些保护机制并不完美,它们可能无法检测到真正的 XSS 攻击(漏报),在其他情况可能会阻止合法代码(误判)。由于后一种情况的出现,浏览器允许用户可设置禁用 XSS 过滤功能。不幸的是,这通常是一个全局设置,这会完全关闭所有浏览器加载的 web 应用程序的安全功能。
-> Luckily, there is a way for a web app to override this configuration and ensure that the XSS filter is turned on for the web app being loaded by the browser. This is done via the `X-XSS-Protection` header. This header, supported by Internet Explorer (from version 8), Edge, Chrome and Safari, instructs the browser to turn on or off the browser’s built-in protection mechanism and to override the browser’s local configuration.
-
-幸运的是,有方法可以让 web 应用覆盖此配置,并确保浏览器加载的 web 应用已打开 XSS 过滤器。这是通过设定 `X-XSS-Protection` 响应头来达到的。此响应头支持 Internet Explorer (8以上)、Edge、Chrome 和 Safari,指示浏览器打开或关闭内置的保护机制,及覆盖浏览器的本地配置。
+幸运的是,有方法可以让 web 应用覆盖此配置,并确保浏览器加载的 web 应用已打开 XSS 过滤器。即通过设定 `X-XSS-Protection` 响应头实现。此响应头支持 Internet Explorer (8以上)、Edge、Chrome 和 Safari,指示浏览器打开或关闭内置的保护机制,及覆盖浏览器的本地配置。
`X-XSS-Protection` 指令包括:
- `1` 或者 `0`
-使用或禁用 CSS 过滤器。
+使用或禁用 XSS 过滤器。
- `mode=block`
当检测到 XSS 攻击时,这会指示浏览器不渲染整个页面。
-> I recommend always turning on the XSS filter, as well as block mode, to maximize user protection. Such a response header looks like this:
-
我建议永远打开 XSS 过滤器以及 block 模式,以求最大化保护用户。这样的响应头应该是这样的:
```
@@ -157,13 +153,13 @@ X-XSS-Protection: 1; mode=block
以下是在 Node.js 中配置此响应头的方法:
```javascript
-functionrequestHandler(req, res){
+function requestHandler(req, res){
res.setHeader('X-XSS-Protection','1;mode=block');}
```
### 控制 iframe ###
-iframe (正式来说,是 HTML 内联框架元素)是一个 DOM 元素,它允许一个 web 应用嵌套在另一个 web 应用中。这个强大的元素有部分重要的使用场景,比如在 web 应用中嵌入第三方内容,但它也有重大的缺点,例如对 SEO 不友好,对浏览器导航跳转也不友好,还有很多。
+iframe (正式来说,是 HTML 内联框架元素)是一个 DOM 元素,它允许一个 web 应用嵌套在另一个 web 应用中。这个强大的元素有部分重要的使用场景,比如在 web 应用中嵌入第三方内容,但它也有重大的缺点,例如对 SEO 不友好,对浏览器导航跳转也不友好等等。
其中一个需要注意的事是它使得点击劫持变得更加容易。点击劫持是一种诱使用户点击并非他们想要点击的目标的攻击。要理解一个简单的劫持实现,参考以下 HTML,当用户认为他们点击可以获得奖品时,实际上是试图欺骗用户购买面包机。
@@ -176,11 +172,11 @@ iframe (正式来说,是 HTML 内联框架元素)是一个 DOM 元素,
```
-点击劫持有许多恶意应用程序,例如欺骗用户确认 Facebook 点赞,在线购买商品,甚至提交机密信息。恶意 web 应用程序可以通过在其恶意应用中嵌入合法的 web 应用来利用 iframe 进行点击劫持,这可以通过设置 `opacity: 0` 的 CSS 规则将其隐藏,并将 iframe 的点击目标直接放置在看起来无辜的按钮之上。点击了这个无辜按钮的用户会直接点击在嵌入的 web 应用上,并不知道点击后的作用。
+有许多恶意应用程序都采用了点击劫持,例如诱导用户点赞,在线购买商品,甚至提交机密信息。恶意 web 应用程序可以通过在其恶意应用中嵌入合法的 web 应用来利用 iframe 进行点击劫持,这可以通过设置 `opacity: 0` 的 CSS 规则将其隐藏,并将 iframe 的点击目标直接放置在看起来无辜的按钮之上。点击了这个无害按钮的用户会直接点击在嵌入的 web 应用上,并不知道点击后的后果。
-阻止这种攻击的一种有效的方法是限制你的 web 应用被框架化。`X-Frame-Options`,在 [RFC 7034](https://www.ietf.org/rfc/rfc7034.txt) 中引入,就是设计用来做这件事的。此响应头指示浏览器对你的 web 应用是否可以被嵌入另一个网页进行限制,从而阻止恶意网页欺骗用户调用你的应用程序进行各项操作。你可以使用 `DENY` 完全屏蔽,或者使用 `ALLOW-FROM` 指定将特定域列入白名单,也可以使用 `SAMEORIGIN` 指令将应用的源地址列入白名单。
+阻止这种攻击的一种有效的方法是限制你的 web 应用被框架化。在 [RFC 7034](https://www.ietf.org/rfc/rfc7034.txt) 中引入的 `X-Frame-Options`,就是设计用来做这件事的。此响应头指示浏览器对你的 web 应用是否可以被嵌入另一个网页进行限制,从而阻止恶意网页欺骗用户调用你的应用程序进行各项操作。你可以使用 `DENY` 完全屏蔽,或者使用 `ALLOW-FROM` 指令将特定域列入白名单,也可以使用 `SAMEORIGIN` 指令将应用的源地址列入白名单。
-我的建议是使用 `SAMEORIGIN` 指令,因为它允许 iframe 被用于同一域上的可以保证安全性的应用程序,这有时是有用的。以下是响应头的示例:
+我的建议是使用 `SAMEORIGIN` 指令,因为它允许 iframe 被同域的应用程序所使用,这有时是有用的。以下是响应头的示例:
```
X-Frame-Options: SAMEORIGIN
@@ -189,7 +185,7 @@ X-Frame-Options: SAMEORIGIN
以下是在 Node.js 中设置此响应头的示例代码:
```javascript
-functionrequestHandler(req, res){
+function requestHandler(req, res){
res.setHeader('X-Frame-Options','SAMEORIGIN');}
```
@@ -197,31 +193,31 @@ functionrequestHandler(req, res){
如前所述,你可以通过启用浏览器的 XSS 过滤器,给你的 web 应用程序增强安全性。然而请注意,这种机制是有局限性的,不是所有浏览器都支持(例如 Firefox 就不支持 XSS 过滤),并且依赖的模式匹配技术可以被欺骗。
-对抗 XSS 和其他攻击的更多一层的保护,可以通过明确列出可信来源和操作来实现 —— 这就是内容安全策略(CSP)。
+对抗 XSS 和其他攻击的另一层的保护,可以通过明确列出可信来源和操作来实现 —— 这就是内容安全策略(CSP)。
-CSP 是一种 W3C 规范,它定义了强大的基于浏览器的安全机制,可以对 web 应用中的资源加载以及脚本执行进行精细的控制。使用 CSP 可以将特定的域加入白名单进行例如脚本加载、AJAX 调用、图像加载和样式加载。你可以启用或禁用内联脚本或动态脚本(臭名昭著的 `eval`),并通过将特定域列入白名单来控制框架化。CSP 的另一个很酷的功能是它允许配置实时报告目标,以便实时监控应用程序进行 CSP 阻止操作。
+CSP 是一种 W3C 规范,它定义了强大的基于浏览器的安全机制,可以对 web 应用中的资源加载以及脚本执行进行精细的控制。使用 CSP 可以将特定的域加入白名单进行脚本加载、AJAX 调用、图像加载和样式加载等操作。你可以启用或禁用内联脚本或动态脚本(臭名昭著的 `eval`),并通过将特定域列入白名单来控制框架化。CSP 的另一个很酷的功能是它允许配置实时报告目标,以便实时监控应用程序进行 CSP 阻止操作。
这种对资源加载和脚本执行的明确的白名单提供了很强的安全性,在很多情况下都可以防范攻击。例如,使用 CSP 禁止内联脚本,你可以防范很多反射型 XSS 攻击,因为它们依赖于将内联脚本注入到 DOM。
CSP 是一个相对复杂的响应头,它有很多种指令,在这里我不详细展开了,可以参考 HTML5 Rocks 里一篇很棒的[教程](https://www.html5rocks.com/en/tutorials/security/content-security-policy/),其中提供了 CSP 的概述,我非常推荐阅读它来学习如何在你的 web 应用中使用 CSP。
-以下是一个设置 CSP 的示例代码,它仅允许从应用程序的源域加载脚本,并组织动态脚本的执行(eval)以及内嵌脚本(当然,还是 Node.js):
+以下是一个设置 CSP 的示例代码,它仅允许从应用程序的源域加载脚本,并阻止动态脚本的执行(eval)以及内嵌脚本(当然,还是 Node.js):
```javascript
-functionrequestHandler(req, res){
+function requestHandler(req, res){
res.setHeader('Content-Security-Policy',"script-src 'self'");}
```
### 防止 Content-Type 嗅探 ###
-为了使用户体验尽可能无缝,许多浏览器实现了一个功能叫内容类型嗅探,或者 MIME 嗅探。这个功能使得浏览器可以通过「嗅探」实际 HTTP 响应的资源的内容直接检测到资源的类型,无论在响应头中 `Content-Type` 是如何指定资源类型的。虽然这个功能在某些情况下确实是有用的,它引入了一个漏洞以及一种叫 MIME 混乱攻击的攻击手法。MIME 嗅探漏洞使攻击者可以注入恶意资源,例如恶意脚本,伪装成一个无辜的资源,例如一个图片。通过 MIME 嗅探,浏览器将忽略声明的图像内容类型,它不会渲染图片,而是执行恶意脚本。
+为了使用户体验尽可能无缝,许多浏览器实现了一个功能叫内容类型嗅探,或者 MIME 嗅探。这个功能使得浏览器可以通过「嗅探」实际 HTTP 响应的资源的内容直接检测到资源的类型,无视响应头中 `Content-Type` 指定的资源类型。虽然这个功能在某些情况下确实是有用的,它引入了一个漏洞以及一种叫 MIME 类型混淆攻击的攻击手法。MIME 嗅探漏洞使攻击者可以注入恶意资源,例如恶意脚本,伪装成一个无害的资源,例如一张图片。通过 MIME 嗅探,浏览器将忽略声明的图像内容类型,它不会渲染图片,而是执行恶意脚本。
幸运的是,`X-Content-Type-Options` 响应头缓解了这个漏洞。此响应头在 2008 年引入 IE8,目前大多数主流浏览器都支持(Safari 是唯一不支持的主流浏览器),它指示浏览器在处理获取的资源时不使用嗅探。因为 `X-Content-Type-Options` 仅在 [「Fetch」规范](https://fetch.spec.whatwg.org/#x-content-type-options-header)中正式指定,实际的实现因浏览器而异。一部分浏览器(IE 和 Edge)完全阻止了 MIME 嗅探,而其他一些(Firefox)仍然会进行 MIME 嗅探,但会屏蔽掉可执行的资源(JavaScript 和 CSS)如果声明的内容类型与实际的类型不一致。后者符合最新的 Fetch 规范。
`X-Content-Type-Options` 是一个很简单的响应头,它只有一个指令,`nosniff`。它是这样指定的:`X-Content-Type-Options: nosniff`。以下是示例代码:
```javascript
-functionrequestHandler(req, res){
+function requestHandler(req, res){
res.setHeader('X-Content-Type-Options','nosniff');}
```
@@ -235,14 +231,16 @@ functionrequestHandler(req, res){
- 通过 `Strict-Transport-Security` 强制使用 HTTPS,并将你的域添加到 Chrome 预加载列表
- 利用 `X-XSS-Protection` 使你的 web 应用更加能抵抗 XSS 攻击
- 使用 `X-Frame-Options` 阻止点击劫持
-- 利用 `Content-Security-Policy` 将特定来源于端点列入白名单
+- 利用 `Content-Security-Policy` 将特定来源与端点列入白名单
- 使用 `X-Content-Type-Options` 防止 MIME 嗅探攻击
请记住,为了使 web 真正迷人,它必须是安全的。利用 HTTP 响应头构建更加安全的网页吧!
-(**声明:** 此文内容仅属本人,不代表本人过去或现在的雇主。)
+(**声明:** 此文内容仅属本人,不代表本人过去或现在的雇主。)
+
+(首页图片版权:[Pexels.com](https://www.pexels.com/photo/coffee-writing-computer-blogging-34600/))
---
From ae3e13d882eb36233da4bcedd7ff9eba72ec6c12 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=A0=B9=E5=8F=B7=E4=B8=89?=
Date: Mon, 17 Apr 2017 22:45:12 +0800
Subject: [PATCH 189/638] Create testing-views-in-isolation-with-espresso.md
---
...esting-views-in-isolation-with-espresso.md | 170 ++++++++++++++++++
1 file changed, 170 insertions(+)
create mode 100644 TODO/testing-views-in-isolation-with-espresso.md
diff --git a/TODO/testing-views-in-isolation-with-espresso.md b/TODO/testing-views-in-isolation-with-espresso.md
new file mode 100644
index 00000000000..c746cbfcf68
--- /dev/null
+++ b/TODO/testing-views-in-isolation-with-espresso.md
@@ -0,0 +1,170 @@
+> * 原文地址:[Testing Views in Isolation with Espresso](https://www.novoda.com/blog/testing-views-in-isolation-with-espresso/)
+> * 原文作者:[Ataul Munim](https://www.novoda.com/blog/author/ataulm/)
+> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
+> * 译者:
+> * 校对者:
+
+# Testing Views in Isolation with Espresso #
+
+
+In this post, we'll show you how and why you should use Espresso to test your custom Views on an Android device.
+
+You can use Espresso to test entire screens or flows at once. These tests launch an Activity and perform actions as a user would, including waiting for data to load or navigating to other screens.
+
+They're useful because you need end-to-end tests to validate common user flows. These automated tests should run at regular intervals, enabling you to spend manual QA time performing exploratory tests.
+
+That said, these aren’t tests that you can run frequently. Running the whole suite can take hours (imagine a suite that includes verifying offline sync for media content), so you might choose to run them at night.
+
+It's difficult because these types of tests incorporate multiple points of potential failure. Ideally when a single test fails, you want it to fail because of a single logical assertion.
+
+Most (or a lot) of the regressions you can introduce are in the UI. They might be subtle so we don't notice them when adding new features, but eagle-eyed QA teams often do.
+
+It's such a waste of time.
+
+## What can you do? ##
+
+Let's look at using Espresso to test that you have correctly bound data to Views.
+
+At Novoda, the Views we write are mostly extensions of existing View and ViewGroup classes on Android. They typically only expose one or two extra methods, which are used to bind callbacks and the data object/view model, like this:
+
+```
+public class MovieItemView extends RelativeLayout {
+ private TextView titleTextView;
+ private Callback callback;
+
+ public void attach(Callback callback) {
+ this.callback = callback;
+ }
+
+ public void bind(Movie movie) {
+ titleTextView.setText(movie.name());
+ setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ callback.onClick(movie);
+ }
+ });
+ }
+}
+```
+
+They group logical parts of the UI together and often encompass naming conventions from the business domain. You will rarely see ‘raw’ Android Views in Activity layouts in our work at Novoda.
+
+Let’s write these View tests in a BDD style, like "given MovieItemView is bound to Edward Scissorhands, then title is set as Edward Scissorhands" or "given MovieItemView is bound to Edward Scissorhands, when clicking on view, then onClick(Edward Scissorhands) is called", etc.
+
+## Couldn't you have caught these regressions with unit tests? ##
+
+Why do you need Espresso to run these tests if you’re using a presentation pattern like MVP or MVVM, which can be unit-tested?
+
+First, let’s go over the presentation flow and describe what you can test to see how the Espresso tests can augment it.
+
+- Presenters subscribe to data producers that send events
+- Events can be of type `loading`, `idle` or `error`, and may or may not contain data to display
+- Presenters will forward these events to "displayers" (“View” in MVP) using methods like `display(List)`, `displayCachedDataWhileLoading(List)` or `displayEmptyScreen()`, etc.
+- The implementation of displayers will show/hide Android Views and do things like `moviesView.bind(List)`
+
+You can unit-test the presenters completely, verifying that the correct methods on the displayers are called with the correct arguments.
+
+Can you test the displayers in the same way? Yes, you can mock the Android Views and verify you're calling the correct methods on them. It won't be at the correct granularity though:
+
+- your displayer could create or update the adapter of a RecyclerView or ViewPager, but this gives you no assurances of what the item/page is displaying
+- Android Views are setup in code with attributes inflated from XML (layouts and styles); verifying method calls isn't enough to assert what's displayed
+
+## Setting up for the tests ##
+
+Let’s use the [`espresso-support`](https://github.com/novoda/spikes/tree/master/espresso-support) library to get started.
+
+Add the dependencies to your build.gradle file (available from JCenter):
+
+```
+debugCompile 'com.novoda:espresso-support-extras:0.0.3'
+androidTestCompile 'com.novoda:espresso-support:0.0.3'
+```
+
+The `extras` artifact includes the `ViewActivity`, which needs to be part of your app under test. You can use this Activity to hold a single View, which you can test with Espresso.
+
+The core artifact (containing custom test rules) only needs to be included as part of your `androidTest` dependencies.
+
+The `ViewTestRule` is used in a similar way to the `ActivityTestRule`. Instead of passing the Activity class that you want to launch, you should pass the layout file containing the View you want to test:
+
+```
+@RunWith(AndroidJUnit4.class)publicclassMovieItemViewTest{
+ @Rule
+ public ViewTestRule viewTestRule=newViewTestRule<>(R.layout.test_movie_item_view);
+ ...
+```
+
+You can specify the View type for the root of the layout with `ViewTestRule`.
+
+The `ViewTestRule` extends `ActivityTestRule`, so it'll always open `ViewActivity`. `getActivityIntent()` is overridden so you can pass `R.layout.test_movie_item_view` to `ViewActivity` as an Intent extra.
+
+You can use Mockito in your tests to substitute for the callbacks:
+
+```
+@Rule
+public MockitoRule mockitoRule = MockitoJUnit.rule();
+
+@Mock
+MovieItemView.Listener movieItemListener;
+
+@Before
+publicvoidsetUp(){
+ MovieItemView view = viewTestRule.getView();
+ view.attachListener(movieItemListener);
+ ...
+ }
+```
+
+ViewTestRule has a method `bindViewUsing(Binder)`, which gives you a reference to the View so you can interact with it. While you could access the View directly with `viewTestRule.getView()`, you want to ensure any interaction with the View is performed on the main thread, not the test thread.
+
+```
+@Before
+public void setUp() {
+ MovieItemView view = viewTestRule.getView();
+ view.attachListener(movieItemListener);
+ viewTestRule.bindViewUsing(new ViewTestRule.Binder() {
+ @Override
+ public void bind(MovieItemView view) {
+ view.bind(EDWARD_SCISSORHANDS);
+ }
+ });
+}
+```
+
+## Ready to test ##
+
+Apps only really do two things, from the user's point of view:
+
+- they display information
+- they respond to user actions
+
+To write tests for these two cases, you can start by asserting that the correct information is displayed using standard Espresso ViewMatchers and ViewAssertions:
+
+```
+@Test
+public void titleSetToMovieName() {
+ onView(withId(R.id.movie_item_text_name))
+ .check(matches(withText(EDWARD_SCISSORHANDS.name)));
+}
+```
+
+Next, you should make sure that the user actions correspond to the correct event being fired, with the correct arguments:
+
+```
+@Test
+public void clickMovieItemView() {
+ onView(withClassName(is(MovieItemView.class.getName())))
+ .perform(click());
+
+ verify(movieItemListener)
+ .onClick(eq(EDWARD_SCISSORHANDS));
+}
+```
+
+That's it, I hope you find this useful.
+
+In a future post, I'll cover using Espresso to test your Views for TalkBack support.
+
+---
+
+> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[React](https://github.com/xitu/gold-miner#react)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计) 等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)。
From 0a04324fc5ff3a0e4ab4691953d980144358ff9e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=A0=B9=E5=8F=B7=E4=B8=89?=
Date: Mon, 17 Apr 2017 23:00:36 +0800
Subject: [PATCH 190/638] Create
es6-modules-support-lands-in-browsers-is-it-time-to-rethink-bundling.md
---
...browsers-is-it-time-to-rethink-bundling.md | 335 ++++++++++++++++++
1 file changed, 335 insertions(+)
create mode 100644 TODO/es6-modules-support-lands-in-browsers-is-it-time-to-rethink-bundling.md
diff --git a/TODO/es6-modules-support-lands-in-browsers-is-it-time-to-rethink-bundling.md b/TODO/es6-modules-support-lands-in-browsers-is-it-time-to-rethink-bundling.md
new file mode 100644
index 00000000000..2481f7b2bab
--- /dev/null
+++ b/TODO/es6-modules-support-lands-in-browsers-is-it-time-to-rethink-bundling.md
@@ -0,0 +1,335 @@
+> * 原文地址:[ES6 modules support lands in browsers: is it time to rethink bundling?](https://www.contentful.com/blog/2017/04/04/es6-modules-support-lands-in-browsers-is-it-time-to-rethink-bundling/)
+> * 原文作者:[Stefan Judis](https://www.contentful.com/about-us/)
+> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
+> * 译者:
+> * 校对者:
+
+# ES6 modules support lands in browsers: is it time to rethink bundling? #
+
+![](http://images.contentful.com/256tjdsmm689/3xFvPzCb6wUek00gQAuU6q/0e8221e0e5c673f18d20448a9ba8924a/Contentful_ES6Modules_.png)
+
+Writing performant JavaScript applications is a complex matter these days. Years ago, everything started with script concatenation to save HTTP requests, and then it continued with minification and wrangling of variable names to squeeze out even the last tiny bit of the code we ship.
+
+Today we have [tree shaking](https://blog.engineyard.com/2016/tree-shaking) and module bundlers, and we go back to code splitting to not block the main thread on startup and speed up [the time to interactivity](https://developers.google.com/web/tools/lighthouse/audits/time-to-interactive). We're also transpiling everything: using future features today? No problem – thanks to Babel!
+
+ES6 modules have been defined in the ECMAScript specification [for a while already](http://2ality.com/2014/09/es6-modules-final.html). The community wrote tons of articles on how to use them with Babel and how `import` differs from `require` in Node.js, but it took a while until an actual implementation landed in browsers. I was surprised to see that Safari was the first one shipping ES6 modules in its technology preview channel, and now Edge and Firefox Nightly also ship this feature – even though it's behind a flag. After having used tools like [RequireJS](http://requirejs.org/) and [Browserify](http://browserify.org/) (remember [the AMD and CommonJS discussions](https://addyosmani.com/writing-modular-js/)?) it looks like modules are finally arriving in the browser landscape, so let's see a look what the bright future will bring. 🎉
+
+
+## The traditional setup ##
+
+The usual way to build web applications is to include one single bundle that is produced using Browserify, Rollup or Webpack (or any other tool out there). A classic website that's not a SPA (single page application) consists of server-side generated HTML, which then includes a single JavaScript bundle.
+
+```
+
+
+ ES6 modules tryout
+
+
+
+
+
+
+
+```
+
+The combined file includes three JavaScript files bundled with Webpack. These files make use of ES6 modules:
+
+```
+// app/index.js
+import dep1 from './dep-1';
+
+function getComponent () {
+ var element = document.createElement('div');
+ element.innerHTML = dep1();
+ return element;
+}
+
+document.body.appendChild(getComponent());
+
+// app/dep-1.js
+import dep2 from './dep-2';
+
+export default function() {
+ return dep2();
+}
+
+// app/dep-2.js
+export default function() {
+ return 'Hello World, dependencies loaded!';
+}
+```
+
+The result of this app will be a "Hello world" telling us that all files are loaded.
+
+### Shipping a bundle ###
+
+The Webpack configuration to create this bundle is relatively straightforward. There is not much happening right now except for the bundling and minification of the JavaScript files using UglifyJS.
+
+```
+// webpack.config.js
+
+const path = require('path');
+const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
+
+module.exports = {
+ entry: './app/index.js',
+ output: {
+ filename: 'bundle.js',
+ path: path.resolve(__dirname, 'dist')
+ },
+ plugins: [
+ new UglifyJSPlugin()
+ ]
+};
+```
+
+The three base files are relatively small and have a total size of 347 bytes.
+
+```
+$ ll app
+total 24
+-rw-r--r-- 1 stefanjudis staff 75B Mar 16 19:33 dep-1.js
+-rw-r--r-- 1 stefanjudis staff 75B Mar 7 21:56 dep-2.js
+-rw-r--r-- 1 stefanjudis staff 197B Mar 16 19:33 index.js
+```
+
+When I ran this through Webpack, I got a bundle with the size of 856 bytes, which is roughly 500 bytes boilerplate. These additional bytes are acceptable, as it's nothing compared to the bundles most of us ship in production. Thanks to Webpack, we can already use ES6 modules.
+
+
+```
+$ webpack
+Hash: 4a237b1d69f142c78884
+Version: webpack 2.2.1
+Time: 114ms
+Asset Size Chunks Chunk Names
+bundle.js 856 bytes 0 [emitted] main
+ [0] ./app/dep-1.js 78 bytes {0}[built]
+ [1] ./app/dep-2.js 75 bytes {0}[built]
+ [2] ./app/index.js 202 bytes {0}[built]
+```
+
+## The new setup using native supported ES6 modules ##
+
+Now that we have the "traditional bundle" for all the browsers that don't support ES6 modules yet, we can start playing around with the cool stuff. To do so, let's add in the `index.html` file a new script element pointing to the ES6 module with `type="module"`.
+
+
+```
+ES6 modules tryout
+```
+
+When we take a look at Chrome, we'll see that there is not much more happening.
+
+![image01](http://images.contentful.com/256tjdsmm689/4JHwnbyrssomECAG2GI8se/e8e35adc37bc0627f0902bcc2fdb52df/image01.png)
+
+The bundle is loaded as before, "Hello world!" is shown, but that's it. And that's excellent, because this is how web works: browsers are forgiving, they won't throw errors when they don't understand markup we send down the wire. Chrome just ignores the script element with the type it doesn't know.
+
+Now, let's check the Safari technology preview:
+
+![Bildschirmfoto 2017-03-29 um 17.06.26](http://images.contentful.com/256tjdsmm689/1mefe0J3JKOiAoSguwMkka/0d76c5666300ed0b631a0fe548ac5b52/Bildschirmfoto_2017-03-29_um_17.06.26.png)
+
+Sadly, there is no additional "Hello world" showing up. The reason is the difference between build tools and native ES modules: whereas Webpack figures out which files to include during the build process, when running ES modules in the browser, we need to define concrete file paths.
+
+```
+// app/index.js
+
+// This needs to be changed
+// import dep1 from './dep-1';
+
+// This works
+import dep1 from './dep-1.js';
+```
+
+The adjusted file paths work great, except for the fact that Safari preview now loads the bundle and the three individual modules, meaning that our code will be executed twice.
+
+![image02](http://images.contentful.com/256tjdsmm689/6MeIDF7GuW6gy8om4Ceccc/a0dba00a4e0f301f2a7fd65449d044ab/image02.png)
+
+The solution is the `nomodule` attribute, which we can set on the script element requesting the bundle. This attribute [was added to the spec quite recently](https://github.com/whatwg/html/commit/a828019152213ae72b0ed2ba8e35b1c472091817) and Safari Preview supports it as of the [end of January](https://trac.webkit.org/changeset/211078/webkit). It tells Safari that this script is the "fallback" script for the lack of ES6 modules support, and in this case shouldn't be executed.
+
+```
+
+
+ ES6 modules tryout
+
+
+
+
+
+
+
+
+
+```
+
+![image03](http://images.contentful.com/256tjdsmm689/1YchZEromA2ueKUCoYqMsc/2c68c46ffd2a3ad73d99d17020d56093/image03.png)
+
+That's good. With the combination of `type="module"` and `nomodule`, we can load a classic bundle in not supporting browsers and load JavaScript modules in supporting browsers.
+
+You can check out this state in production at [es-module-on.stefans-playground.rocks](http://es-module-on.stefans-playground.rocks/).
+
+### Differences between modules and scripts ###
+
+There are a few gotchas here, though. First of all, JavaScript running in an ES6 module is not quite the same as in a regular script element. Axel Rauschmayer covers this quite nicely in [his book Exploring ES6](http://exploringjs.com/es6/ch_modules.html#sec_modules-vs-scripts). I highly recommend you check it out but let's just quickly mention the main differences:
+
+- ES6 modules are running in strict mode by default (no need for `'use strict'` anymore).
+- Top-level value of `this` is `undefined`.
+- Top-level variables are local to the module.
+- ES6 modules are loaded and executed asynchronously after the browser finished parsing the HTML.
+
+In my opinion, these are all huge advantages. Modules are local – there is no need for IIFEs around everything, and also we don't have to fear global variable leaking anymore. Also running in strict mode by default means that we can drop a lot of `'use strict'` statements.
+
+And from a performance point of view (probably the most important one) **modules load and execute deferred by default**. So we won't accidentally add blocking scripts to our website and there is no [SPOF](https://www.stevesouders.com/blog/2010/06/01/frontend-spof/) issue when dealing with script `type="module"` elements. We could place an `async` attribute on it, which overwrites the default deferred behavior, but `defer`[is a good choice these days](https://calendar.perfplanet.com/2016/prefer-defer-over-async/).
+
+```
+
+
+
+
+
+
+
+
+```
+
+In case you want to check the details around that, the [script element spec](https://html.spec.whatwg.org/multipage/scripting.html#the-script-element) is an understandable read and includes some examples.
+
+## Minifying of pure ES6 ##
+
+But we're not quite there yet! We serve a minified bundle for Chrome and individual not minified files for Safari Preview now. How can we make these smaller? UglifyJS should do the job just fine, right?
+
+It turns out that UglifyJS is not able to fully deal with ES6 code yet. There is a `harmony` development branch available, but unfortunately it didn't work with my three JavaScript files at the time of writing.
+
+```
+$ uglifyjs dep-1.js -o dep-1.min.js
+Parse error at dep-1.js:3,23
+export default function() {
+ ^
+SyntaxError: Unexpected token: punc (()
+// ..
+FAIL: 1
+```
+
+
+But UglifyJS is in every toolchain today, how does this work for all the projects written in ES6 out there?
+
+The usual flow is that tools like Babel transpile to ES5, and then Uglify comes into play to minify this ES5 code. I want to ignore ES5 transpilation in this article: we're dealing with the future here, Chrome has [97% ES6 coverage](https://kangax.github.io/compat-table/es6/#chrome59) and Safari Preview has already fabulous [100% ES6 coverage since version 10](https://kangax.github.io/compat-table/es6/#safari10_1).
+
+I asked the Twittersphere if there is a minifier available that can deal with ES6, and [Lars Graubner](https://twitter.com/larsgraubner) pointed me towards [Babili](https://github.com/babel/babili). Using Babili, we can easily minify the ES6 modules.
+
+
+```
+// app/dep-2.js
+
+export default function() {
+ return 'Hello World. dependencies loaded.';
+}
+
+// dist/modules/dep-2.js
+export default function(){return 'Hello World. dependencies loaded.'}
+```
+
+With the Babili CLI tool, it's almost too easy to minify all the files separately.
+
+```
+$ babili app -d dist/modules
+app/dep-1.js -> dist/modules/dep-1.js
+app/dep-2.js -> dist/modules/dep-2.js
+app/index.js -> dist/modules/index.js
+```
+
+The result looks then as follows.
+
+```
+$ ll dist
+-rw-r--r-- 1 stefanjudis staff 856B Mar 16 22:32 bundle.js
+
+$ ll dist/modules
+-rw-r--r-- 1 stefanjudis staff 69B Mar 16 22:32 dep-1.js
+-rw-r--r-- 1 stefanjudis staff 68B Mar 16 22:32 dep-2.js
+-rw-r--r-- 1 stefanjudis staff 161B Mar 16 22:32 index.js
+```
+
+The bundle is still roughly around 850B, and all the files are around 300B in total. I'm ignoring GZIP compression here as [it doesn't work well on such small file sizes](http://webmasters.stackexchange.com/questions/31750/what-is-recommended-minimum-object-size-for-gzip-performance-benefits) (we'll get back to that later).
+
+## Speeding up ES6 modules with rel=preload? ##
+
+The minification of the single JS files is a huge success. It's 298B vs. 856B, but we could even go further and speed things up more. Using ES6 modules we are now able to ship less code, but looking at the waterfall again we'll see that the requests are made sequentially because of the defined dependency chain of the modules.
+
+What if we could throw `` elements in the mix which can be used to tell the browser upfront that additionally requests will be made soon? We have build tool plugins like Addy Osmani's [Webpack preload plugin](https://github.com/GoogleChrome/preload-webpack-plugin) for code splitting already – is something like this possible for ES6 modules? In case you don't know how `rel="preload"` works, you should check out the [article on this topic](https://www.smashingmagazine.com/2016/02/preload-what-is-it-good-for/) by Yoav Weiss on Smashing Magazine.
+
+Unfortunately, preloading of ES6 modules is not so easy because they behave differently than normal scripts. The question is how a link element with a set `rel="preload"` attribute should treat an ES6 module? Should it fetch all the dependent files, too? This is an obvious question to answer, but there are more browser internal problems to solve, too, if module treatment should go into the `preload` directive. In case you're interested in this topic [Domenic Denicola](https://twitter.com/domenic) discusses these problems [in a GitHub issue](https://github.com/whatwg/fetch/issues/486), but it turns out that there are too many differences between scripts and modules to implement ES6 module treatment in the `rel="preload"` directive. The solution might be another `rel="modulepreload"` directive to clearly separate functionalities, with [the spec pull request](https://github.com/whatwg/html/pull/2383) pending at the time of writing, so let's see how we'll preload modules in the future.
+
+## Bringing in real dependencies ##
+
+Three files don't make a real app, so let's add a real dependency. Fortunately, [Lodash](https://lodash.com/) offers all of its functionality also in split ES6 modules, which I then minified using Babili. So let's modify the `index.js` file to also include a Lodash method.
+
+
+```
+import dep1 from './dep-1.js';
+import isEmpty from './lodash/isEmpty.js';
+
+function getComponent() {
+ const element = document.createElement('div');
+ element.innerHTML = dep1() + ' ' + isEmpty([]);
+
+ return element;
+}
+
+document.body.appendChild(getComponent());
+```
+
+The use of `isEmpty` is trivial in this case, but let's see what happens now after adding this dependency.
+
+![image07](http://images.contentful.com/256tjdsmm689/13F95Xpl32Mu0MgE0mgS2o/c9dbc002e53bf56ee0eeb0df40b55f9c/image07.png)
+
+The request count went up to over 40, the page load time went up from roughly 100ms to something between 400ms and 800ms on a decent wifi connection, and the shipped overall size increased to approximately 12KB without compression. Unfortunately, Safari Preview is not available on [WebPagetest](https://www.webpagetest.org/) to run some reliable benchmarks.
+
+Chrome receiving the bundled JavaScript, on the other hand, is at a slim ~8KB file size.
+
+![image05](http://images.contentful.com/256tjdsmm689/6xxfWBW9nqAeqQ8ck0MqU/62a74102e9247d785a61a84766356f51/image05.png)
+
+This 4KB difference is definitely something to check. You can find this example at [lodash-module-on.stefans-playground.rocks](https://lodash-module-on.stefans-playground.rocks/).
+
+### Compression works only well on larger files ###
+
+In case you looked closely at the screenshots of the Safari developer tools, you might have noticed that the transferred file size was actually bigger than the source. Especially in a large JavaScript app, including a lot of small chunks makes a big difference and that's because GZIP doesn't play well with small file sizes.
+
+Khan Academy [discovered the same thing](http://engineering.khanacademy.org/posts/js-packaging-http2.htm) a while ago when experimenting with HTTP/2. The idea of shipping smaller files is great to guarantee perfect cache hit ratios, but at the end, it's always a tradeoff and it's depending on several factors. For a large code base splitting the code into several chunks (a *vendor* and an *app* bundle) makes sense, but shipping thousands of tiny files that can't be compressed properly is not the right approach.
+
+### Tree shaking is the cool kid in town ###
+
+Another thing to point out is that thanks to the relatively new tree shaking mechanism, build processes can eliminate code that's not used and imported by any other module. The first build tool that supported this was Rollup, but now Webpack in version 2 supports it as well — [as long as we disable the `module` option in babel](https://medium.freecodecamp.com/tree-shaking-es6-modules-in-webpack-2-1add6672f31b#22c4).
+
+Let's say we changed `dep-2.js` to include things that won't be imported by `dep-1.js`.
+
+```
+export default function() {
+ return 'Hello World. dependencies loaded.';
+}
+
+export const unneededStuff = [
+ 'unneeded stuff'
+];
+```
+
+Babili will simply minify the file and Safari Preview, in this case, would receive several code lines that are not used. A Webpack or Rollup bundle, on the other hand, won't include `unneededStuff`. Tree shaking offers huge savings that definitely should be used in a real production code base.
+
+## The future looks bright, but build processes are here to stay ##
+
+So, ES6 modules are on their way, but it doesn't look like anything will change when they finally arrive in all the major browsers. We won't start shipping thousands of tiny files to guarantee good compression, and we won't abandon build processes to make use of tree shaking and dead code elimination. **Frontend development is and will be as complicated as always**.
+
+**The most important thing to remember is that measuring is the key to succees**. Don't split everything and assume that it will lead to an improvement. Just because we might have support for ES6 modules in browsers soon, it doesn't mean that we can get rid of a build process and a proper "bundle strategy". Here at Contentful we'll stick to our build processes, and continue to ship bundles including our [JavaScript SDKs](https://www.contentful.com/developers/docs/javascript/).
+
+Yet, I have to admit that Frontend development still feels great. JavaScript evolves, and we'll finally have a way to deal with modules baked into the language. I can't wait to see how and if this influences the JavaScript ecosystem and what the best practices will be in a couple of years.
+
+## Additional resources ##
+
+- [Article series on ES6 modules](https://blog.hospodarets.com/native-ecmascript-modules-the-first-overview) by Serg Hospodarets
+- [The modules chapter](http://exploringjs.com/es6/ch_modules.html) in "[Exploring ES6](http://exploringjs.com/)"
+
+---
+
+> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[React](https://github.com/xitu/gold-miner#react)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计) 等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)。
From 2161ad5a7ef2005ccb44401457ae4ea8adbf02be Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=A0=B9=E5=8F=B7=E4=B8=89?=
Date: Mon, 17 Apr 2017 23:12:26 +0800
Subject: [PATCH 191/638] Create everyone-is-a-designer-get-over-it.md
---
TODO/everyone-is-a-designer-get-over-it.md | 85 ++++++++++++++++++++++
1 file changed, 85 insertions(+)
create mode 100644 TODO/everyone-is-a-designer-get-over-it.md
diff --git a/TODO/everyone-is-a-designer-get-over-it.md b/TODO/everyone-is-a-designer-get-over-it.md
new file mode 100644
index 00000000000..aee8b2663cd
--- /dev/null
+++ b/TODO/everyone-is-a-designer-get-over-it.md
@@ -0,0 +1,85 @@
+> * 原文地址:[Everyone is a designer. Get over it.](https://library.gv.com/everyone-is-a-designer-get-over-it-501cc9a2f434)
+> * 原文作者:[Daniel Burka](https://library.gv.com/@dburka)
+> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
+> * 译者:
+> * 校对者:
+
+
+![](https://cdn-images-1.medium.com/max/2000/1*xIoFsnWI_2-1VOy00a2KrQ.jpeg)
+
+Photo by Alice Achterhof [via Unsplash](https://unsplash.com/search/designer-paint?photo=FwF_fKj5tBo)
+
+# Everyone is a designer. Get over it. #
+
+Recently, [Jared Spool](https://www.uie.com/about/) caught my attention with [an article](https://articles.uie.com/signup/) about how Netflix’s performance engineers are *actually designers*. It’s a provocative idea, but it makes sense. His argument is that everyone in your organization (including performance engineers) designs the product, not just the people with “design” in their job titles.
+
+![](https://cdn-images-1.medium.com/max/800/1*qLoczEHONP188zelJbn-6w@2x.png)
+
+From some of the reactions, you might think Jared had kidnapped someone’s baby for ritual sacrifice. What exactly did Jared write?
+
+> The members of this team are performance engineers. They are architecting, engineering, and maintaining the performance of a very complex system. It occupies all their time and then some. In systems engineering, there are few jobs more technical than these.
+
+> And yet, at the very moment that a Netflix viewer’s video stream stops and that spinning animation appears, indicating the player is now awaiting more data, these engineers make a dramatic change. **They become user experience designers.**
+
+I made that last sentence bold — because it’s really important. Some designers are uncomfortable with the idea that an engineer or a salesperson or a CFO could be a *designer*.
+
+![](https://cdn-images-1.medium.com/max/800/1*ErZDaGRy3mJ19jGdWqeJgA@2x.png)
+
+Common reactions
+
+Whether you like it or not, whether you approve it or not, people outside of your design team are making significant *design* choices that affect your customers in important ways. They are *designing* your product. They are *designers*.
+
+This shouldn’t be provocative — it’s just a statement of fact. I work with[ dozens of startups](http://www.gv.com/portfolio/) every year, and I see it happen at every one. A CFO makes a pricing decision and changes the product experience. An engineer makes a performance trade-off. A salesperson writes a script for talking to customers. In my view, people who fundamentally change the customer’s experience are *designers*.
+
+If this is so self-evident, why do Jared and I press the point? I keep beating the drum because I want designers to change the way they think about their role and become better stewards of good design.
+
+For a moment, consider how this shift in perspective could change the way you work.
+
+#### Everyone needs a design mindset ####
+
+When you accept the reality that design decisions are coming from outside your group, by people without “design” in their job titles, you approach your co-workers differently . Now they’re not just your co-workers — they’re your design team.
+
+The companies that produce great design, such as Apple and Airbnb, have learned this. Alex Schleifer, VP of design at Airbnb,[ tells *Wired*](https://www.wired.com/2015/01/airbnbs-new-head-design-believes-design-led-companies-dont-work/) how the company *isn’t* design-led:
+
+> *The solution [at Airbnb] actually deemphasizes the designers. The point… isn’t to create a “design-led culture,” because that tends to tell anyone who isn’t a designer that their insights take a backseat. It puts the entire organization in the position of having to react to one privileged point of view. Instead, Schleifer wants more people to appreciate what typically lies only within the realm of designers — the user viewpoint.*
+
+Does everyone need all the skills of a designer? Of course not. But each person needs to be armed with the tools to understand how their decisions affect the customer experience.
+
+When an engineer takes a shortcut and scrimps on performance, they need to understand how that damages the user experience. Likewise, when a designer pushes an engineer to make a change that affects performance, that engineer should help the designer make the best overall design decision — not just roll over and do what the designer asked. It’s this type of respectful collaboration that makes great design happen.
+
+One of the best ways to encourage empathy is to watch customer research studies with co-workers from across your company. When my colleague Michael Margolis runs a study with a GV company, we insist that the real team — not just the designers — watch those interviews and take notes. If it’s not possible for everyone to watch in real time, you can record the sessions and schedule a “viewing party” for later.
+
+#### Work outside your design team ####
+
+When you accept that design happens almost everywhere in your organization, you have to take responsibility for it. Your app is slow? Go sit with your engineering team. Your marketing team is poorly communicating your product to future customers? You’d better offer to work with them on the problem.
+
+Yes, doing design with everyone at your company is a lot of work. But it’s necessary if you want to be a truly great designer — otherwise, you’re simply papering over bad decisions. For example, imagine that your CEO created a complex pricing structure for your product. You could focus on making the pricing page as clear as possible using your interface and information design skills. But the harder and more important design opportunity is to work with your CEO on repricing your product so it’s clear to customers and compatible with the business goals.
+
+Focusing on the core business is what differentiates real product design from interface design or even user experience design. Fundamental product design is really hard and requires a lot of legwork, but this is what designers at the highest level do — and it’s why their work is better than yours.
+
+![](https://cdn-images-1.medium.com/max/600/1*czW-2nrN_3l50ZzgYQYqlw@2x.png)
+
+“The Disciplines of UX Design” by Dan Saffer and Thomas Gläser
+
+#### Grow your design team to include non-designers ####
+
+Design is a hard job. You’ll need a wide range of skills (look at all of those circles in the[ diagram of UX Disciplines](https://www.fastcodesign.com/1671735/infographic-the-intricate-anatomy-of-ux-design) by Dan Saffer) and years of practice to truly master design.
+
+Maybe that’s why so many designers are offended when non-designers do design work or get called “designers” by Jared and me. You can act offended if you want, but the reality is that other people are making design decisions with or without you. Embrace them . They don’t make your job less valuable. They don’t make your job title less meaningful.
+
+Having more people who *do design* is additive, not competitive. These designers make your team and your product stronger, because they’re contributing from their unique perspectives. Help them bolster their skills, and use their expertise to the advantage of your product and company.
+
+### **Let’s make a better future together** ###
+
+A few years ago, I met an executive from a Fortune 500 company. When I told her I’m a designer, her eyes lit up. “Oh, I love design!” she said. “My group is just down the hall from the design team. They do so much creative work in there.”
+
+My heart sank. The design team was just down the hall from this executive, but they didn’t work together. Instead, they sat behind soundproof glass walls and did special “creative work” in isolation.
+
+This executive made decisions every day that affected her customers. She bears some of the blame for not reaching out to the designers “in there.” But the design team is primarily at fault — for missing an opportunity to reach out and work together on some of the business’s most important challenges.
+
+
+Thanks to [Jared M. Spool](https://medium.com/@jmspool) for writing an excellent article, [John Zeratsky](https://medium.com/@jazer) and [Michael Margolis](https://medium.com/@mmargolis) for editing and suggestions, and [Alex Schleifer](https://medium.com/@alexoid) for the excellent *Wired* article.
+
+---
+
+> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[React](https://github.com/xitu/gold-miner#react)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计) 等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)。
From da5a893d854e280b50844c21b6a86057e9b21e3e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=A0=B9=E5=8F=B7=E4=B8=89?=
Date: Mon, 17 Apr 2017 23:41:34 +0800
Subject: [PATCH 192/638] Create test-driving-away-coupling-in-activities.md
---
...est-driving-away-coupling-in-activities.md | 199 ++++++++++++++++++
1 file changed, 199 insertions(+)
create mode 100644 TODO/test-driving-away-coupling-in-activities.md
diff --git a/TODO/test-driving-away-coupling-in-activities.md b/TODO/test-driving-away-coupling-in-activities.md
new file mode 100644
index 00000000000..346204681d7
--- /dev/null
+++ b/TODO/test-driving-away-coupling-in-activities.md
@@ -0,0 +1,199 @@
+> * 原文地址:[Test Driving away Coupling in Activities](https://www.philosophicalhacker.com/post/test-driving-away-coupling-in-activities/)
+> * 原文作者:[philosohacker](https://twitter.com/philosohacker)
+> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
+> * 译者:
+> * 校对者:
+
+# Test Driving away Coupling in Activities #
+
+`Activity`s and `Fragment`s, perhaps by [some strange historical accidents](/post/why-android-testing-is-so-hard-historical-edition/), have been seen as *the optimal* building blocks upon which we can build our Android applications for much of the time that Android has been around. Let’s call this idea – the idea that `Activity`s and `Fragment`s are the best building blocks for our apps – “android-centric” architecture.
+
+This series of posts is about the connection between the testability of android-centric architecture and the other problems that are now leading Android developers to reject it; it’s about how our unit tests are trying to tell us that `Activity`s and `Fragment`s – like the cracking bricks in the above image – don’t make the best building blocks for our apps because they tempt us to write code with *tight coupling* and *low cohesion*.
+
+
+[Last time](/post/what-unit-tests-are-trying-to-tell-us-about-activities-pt-2/), we saw `Activity`s and `Fragment`s tend to have low cohesion. This time, we’ll see how our tests can tell us that code within `Activity`s have tight coupling. We’ll also see how test driving the functionality leads to a design that has looser coupling, which makes it easier to change the app and also opens up opportunities for removing duplication. As with the the other posts in the series, we’ll be discussing all of this using the Google I/O app as an example.
+
+### The Target Code ###
+
+The code that we want to test, the “target code”, does the following: when the user navigates to the map view that shows where all the Google I/O sessions are, it asks for their location. If they reject the permission, we show a toast notifying the user that they’ve disabled an app permission. Here’s a screenshot of this:
+
+![permission denied toast](http:/images/permission-denied-toast.png)
+
+Here’s the code that accomplishes this:
+
+```
+@Override
+public void onRequestPermissionsResult(final int requestCode,
+ @NonNull final String[] permissions,
+ @NonNull final int[] grantResults) {
+
+ if (requestCode != REQUEST_LOCATION_PERMISSION) {
+ return;
+ }
+
+ if (permissions.length == 1 &&
+ LOCATION_PERMISSION.equals(permissions[0]) &&
+ grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ // Permission has been granted.
+ if (mMapFragment != null) {
+ mMapFragment.setMyLocationEnabled(true);
+ }
+ } else {
+ // Permission was denied. Display error message.
+ Toast.makeText(this, R.string.map_permission_denied,
+ Toast.LENGTH_SHORT).show();
+ }
+ super.onRequestPermissionsResult(requestCode, permissions,
+ grantResults);
+}
+```
+
+### The Test Code ### (#the-test-code)
+
+Let’s take a stab at testing this. Here’s what that would look like:
+
+```
+@Test
+public void showsToastIfPermissionIsRejected()
+ throws Exception {
+ MapActivity mapActivity = new MapActivity();
+
+ mapActivity.onRequestPermissionsResult(
+ MapActivity.REQUEST_LOCATION_PERMISSION,
+ new String[]{MapActivity.LOCATION_PERMISSION}, new int[]{
+ PackageManager.PERMISSION_DENIED});
+
+ assertToastDisplayed();
+}
+```
+
+Hopefully, you’re wondering what the implementation of `assertToastDisplayed()` looks like. Here’s the thing: there isn’t a straight forward implementation of that method. In order to implement without refactoring our code, we’d need to use a combination of roboelectric and powermock.
+
+However, since we are trying to listen to our tests and [change the way we write code, rather than change the way we write tests](/post/why-i-dont-use-roboletric/), we are going to stop for a moment and think about what this test is trying to tell us:
+
+> Our presentation logic that lives inside of `MapActivity` is tightly coupled with `Toast`.
+
+This coupling is what drives us to use roboelectric to give us mocked android behavior and powermock to mock the static `Toast.makeText` method. Instead, let’s listen to our test and remove the coupling.
+
+To guide our refactoring, let’s write our test first. This will ensure that our *new* classes are loosely coupled. We have to create a new class in this particular case in order to avoid Roboelectric, but ordinarily, we could just refactor already existing classes to reduce coupling.
+
+```
+@Test
+public void displaysErrorWhenPermissionRejected() throws Exception {
+
+ OnPermissionResultListener onPermissionResultListener =
+ new OnPermissionResultListener(mPermittedView);
+
+ onPermissionResultListener.onPermissionResult(
+ MapActivity.REQUEST_LOCATION_PERMISSION,
+ new String[]{MapActivity.LOCATION_PERMISSION},
+ new int[]{PackageManager.PERMISSION_DENIED});
+
+ verify(mPermittedView).displayPermissionDenied();
+}
+```
+
+We’ve introduced a `OnPermissionResultListener` whose job is just to handle the result of request permission from a user. Here’s the code for that:
+
+```
+void onPermissionResult(final int requestCode,
+ final String[] permissions, final int[] grantResults) {
+ if (requestCode != MapActivity.REQUEST_LOCATION_PERMISSION) {
+ return;
+ }
+
+ if (permissions.length == 1 &&
+ MapActivity.LOCATION_PERMISSION.equals(permissions[0]) &&
+ grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ // Permission has been granted.
+ mPermittedView.displayPermittedView();
+
+ } else {
+ // Permission was denied. Display error message.
+ mPermittedView.displayPermissionDenied();
+ }
+}
+```
+
+The calls to `MapFragment` and `Toast` have been replaced with method calls on the `PermittedView`, an object that gets passed in through the constructor. `PermittedView` is an interface:
+
+```
+interface PermittedView {
+ void displayPermissionDenied();
+
+ void displayPermittedView();
+}
+```
+
+And it gets implemented by the `MapActivity`:
+
+```
+public class MapActivity extends BaseActivity
+ implements SlideableInfoFragment.Callback, MapFragment.Callbacks,
+ ActivityCompat.OnRequestPermissionsResultCallback,
+ OnPermissionResultListener.PermittedView {
+ @Override
+ public void displayPermissionDenied() {
+ Toast.makeText(MapActivity.this, R.string.map_permission_denied,
+ Toast.LENGTH_SHORT).show();
+ }
+}
+```
+
+This may not the *best* solution, but it gets us to a point where we can test things. This *required* that `OnPermissionResultListener` be loosely coupled with its `PermittedView`. Loose coupling == definitely an improvement.
+
+### Who cares? ###
+
+At this point, some readers might be skeptical. “Is this definitely an improvement?,” they may wonder to themselves. Here are two reasons why this *design* is better.
+
+(Neither reason I give, you’ll notice is “the design is better because its testable.” That would be circular reasoning.)
+
+#### Easier Changes ####
+
+First, its going to be easier to change this code now that it consists of loosely coupled components, and here’s the kicker: the code that we’ve just tested from the Google I/O app *actually did change*, and with the tests that we have in place, making those changes will be easier. The code I tested was from [an older commit](https://github.com/google/iosched/blob/bd31a838ce4ddc123c71025c859959517c7ae178/android/src/main/java/com/google/samples/apps/iosched/map/MapActivity.java). Later on, the folks working on the I/O app decided to replace the `Toast` with a `Snackbar`:
+
+![snackbar permission rejected](http:/images/permission-denied-snackbar.png)
+
+Its a small change, but because we’ve separated `OnPermissionResultListener` from `PermittedView`, we can make the change on the `MapActivity`s implementation of `PermittedView` without having to think at all about the `OnPermissionResultListener`.
+
+Here’s what that change would have looked like, using their little `PermissionUtils` class they wrote for displaying `SnackBar`s.
+
+```
+@Override
+public void displayPermissionDenied() {
+ PermissionsUtils.displayConditionalPermissionDenialSnackbar(this,
+ R.string.map_permission_denied, new String[]{LOCATION_PERMISSION},
+ REQUEST_LOCATION_PERMISSION);
+}
+```
+
+Again, notice that we can make this change without thinking about the `OnPermissionResultListener` at all. This is actually exactly what Larry Constantine was talking about when he first defined the concept of coupling back in the 70s:
+
+> what we are striving for is loosely coupled systems…in which one can study (or debug, or maintain) any one module without having to know very much about any other modules in the system
+>
+> –Edward Yourdon and Larry Constantine, Structured Design
+
+#### Reducing Duplication ####
+
+Here’s another interesting reason to why the fact that our tests have forced us to remove coupling is a good thing: coupling often leads to duplication. Here’s Kent Beck on this:
+
+> Dependency is the key problem in software development at all scales…if dependency is the problem, duplication is the symptom.
+>
+> -Kent Beck, TDD By Example, pg 7.
+
+If this is true, when we remove coupling, we will often see opportunities to reduce duplication. Indeed, this is precisely what we find in this case. It turns out that there is another classes whose `onRequestPermissionsResult` is nearly identical to the one in `MapActivity`: [`AccountFragment`](https://github.com/google/iosched/blob/bd31a838ce4ddc123c71025c859959517c7ae178/android/src/main/java/com/google/samples/apps/iosched/welcome/AccountFragment.java#L139). Our tests drove us to create two classes `OnPermissionResultListener` and `PermittedView` that – without much modification – can be reused in these other classes.
+
+### Conclusion ###
+
+So, when we have a hard time testing our `Activity`s and `Fragment`s, its often because our tests are trying to tell us that our code is tightly coupled. The test’s warning about coupling often come in the form of an inability to make an assertion against the code we’re trying to test.1
+
+When we listen to our tests, instead of changing them by using Roboelectric our powermock, we’re lead to change in our code in a way that makes it less coupled, which makes it easier to make changes and opens up opportunities to reduce duplication.
+
+### Notes ###
+
+1. It could also show up as an inability to get your target code into the right state for testing. That’s what we saw [in this post](in this post), for example.
+
+### We're hiring mid-senior Android developers at [Unikey](http://www.unikey.com/). Email me if you want to work for a Startup in the smart lock space in Orlando ###
+---
+
+> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区,文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[React](https://github.com/xitu/gold-miner#react)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计) 等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)。
From 0dbf71b08bba65f45d36a1af644dfc8018e1a4af Mon Sep 17 00:00:00 2001
From: xiaoyusilen
Date: Mon, 17 Apr 2017 23:41:52 +0800
Subject: [PATCH 193/638] Change translation details and add proofreader
informations
---
TODO/anatomy-of-a-function-call-in-go.md | 14 +++++++-------
TODO/go-function-calls-redux.md | 6 +++---
2 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/TODO/anatomy-of-a-function-call-in-go.md b/TODO/anatomy-of-a-function-call-in-go.md
index 4fa70afdb03..c5df8c95dab 100644
--- a/TODO/anatomy-of-a-function-call-in-go.md
+++ b/TODO/anatomy-of-a-function-call-in-go.md
@@ -2,11 +2,11 @@
> * 原文作者:[Phil Pearl](https://syslog.ravelin.com/@philpearl?source=post_header_lockup)
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
> * 译者:[xiaoyusilen](http://xiaoyu.world)
-> * 校对者:[1992chenlu](https://github.com/1992chenlu)
+> * 校对者:[1992chenlu](https://github.com/1992chenlu),[Zheaoli](https://github.com/Zheaoli)
# 解析 Go 中的函数调用 #
-让我们来看一些简单的 Go 的函数,然后看看我们能否明白函数调用是怎么回事。我们将通过分析 Go 编译器根据函数生成的汇编语言来完成这件事。对于一个小小的博客来说这可能有一点野心,但是别担心,汇编语言很简单。哪怕是 CPU 都能读懂。
+让我们来看一些简单的 Go 的函数,然后看看我们能否明白函数调用是怎么回事。我们将通过分析 Go 编译器根据函数生成的汇编来完成这件事。对于一个小小的博客来讲,这样的目标可能有点不切实际,但是别担心,汇编语言很简单。哪怕是 CPU 都能读懂。
@@ -20,9 +20,9 @@ func add(a, b int) int {
}
```
-我们编译的时候需要关闭优化,这样方便理解每个部分。我们用 `go build -gcflags 'N -l'` 这个命令来完成上述操作。然后我们可以用 `go tool objdump -s main.add func` 输出我们函数的具体细节(这里的 func 是我们的包名,也就是我们刚刚用 go build 编译出的可执行文件)。
+我们编译的时候需要关闭优化,这样方便我们去理解生成的汇编代码。我们用 `go build -gcflags 'N -l'` 这个命令来完成上述操作。然后我们可以用 `go tool objdump -s main.add func` 输出我们函数的具体细节(这里的 func 是我们的包名,也就是我们刚刚用 go build 编译出的可执行文件)。
-如果你以前从来没有看过汇编语言,那么恭喜啦,你今天看到的内容对你来说是全新的。我将在 Mac 上完成这些事情,所以配置是 Intel 64位。
+如果你之前没有学过汇编,那么恭喜你,你将接触到一个全新的事物。另外我会在 Mac 上完成这篇博客的代码,因此所生成的是 Intel 64-bit 汇编。
```
main.go:20 0x22c0 48c744241800000000 MOVQ $0x0, 0x18(SP)
@@ -33,7 +33,7 @@ func add(a, b int) int {
main.go:21 0x22db c3 RET
```
-我们看到了什么?每一行如下所示被分为了4部分:
+现在我们看到了什么?如下所示,每一行被分为了4部分:
- 源文件的名称和行号(main.go:15)。这行的源代码会被转换为标有代码行号的说明。Go 的一行可能被转换成多行程序集。
- 目标文件中的偏移量(例如 0x22C0)。
@@ -51,8 +51,8 @@ func add(a, b int) int {
现在让我们从第一条指令开始看每一条内容。别忘了我们需要从内存中加载两个参数 `a` 和 `b`,把它们相加,然后返回至调用函数。
-1. `MOVQ $0x0, 0x18(SP)` 将 0 置于存储单元 SP+0x18 中。 这句看起来有点神秘。
-2. `MOVQ 0x8(SP), AX` 将存储单元 SP+0x8 中的内容放到 CPU 寄存器 AX 中。也许这就是从内存中加载的我们的参数之一?
+1. `MOVQ $0x0, 0x18(SP)` 将 0 置于存储单元 SP+0x18 中。 这句代码看起来有点抽象。
+2. `MOVQ 0x8(SP), AX` 将存储单元 SP+0x8 中的内容放到 CPU 寄存器 AX 中。也许这就是从内存中加载的我们所使用的参数之一?
3. `MOVQ 0x10(SP), CX` 将存储单元 SP+0x10 的内容置于 CPU 寄存器 CX 中。 这可能就是我们所需的另一个参数。
4. `ADDQ CX, AX` 将 CX 与 AX 相加,将结果存到 AX 中。好,现在已经把两个参数相加了。
5. `MOVQ AX, 0x18(sp)` 将寄存器 AX 的内容存储在存储单元 SP+0x18 中。这就是在存储相加的结果。
diff --git a/TODO/go-function-calls-redux.md b/TODO/go-function-calls-redux.md
index b8717411ff1..dad571a5324 100644
--- a/TODO/go-function-calls-redux.md
+++ b/TODO/go-function-calls-redux.md
@@ -2,13 +2,13 @@
> * 原文作者:[Phil Pearl](https://hackernoon.com/@philpearl?source=post_header_lockup)
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
> * 译者:[xiaoyusilen](http://xiaoyu.world)
-> * 校对者:[1992chenlu](https://github.com/1992chenlu)
+> * 校对者:[1992chenlu](https://github.com/1992chenlu),[Zheaoli](https://github.com/Zheaoli)
# Go 函数调用 Redux #
-前段时间在一篇[文章](https://syslog.ravelin.com/anatomy-of-a-function-call-in-go-f6fc81b80ecc#.gpqsgzmjc)中我答应写一篇进一步分析 Go 中如何进行函数调用和调用堆栈在 Go 中如何工作的文章。现在我找到了一种简洁的方式来向大家展示上述内容,所以有了现在这篇文章。
+前段时间在一篇[文章](https://syslog.ravelin.com/anatomy-of-a-function-call-in-go-f6fc81b80ecc#.gpqsgzmjc)中我答应写一篇进一步分析 Go 中如何进行函数调用和堆栈调用在 Go 中如何工作的文章。现在我找到了一种简洁的方式来向大家展示上述内容,所以有了现在这篇文章。
-什么是调用堆栈?它是一个用于保存局部变量和调用参数的内存区域,并且跟踪每个函数应该返回到哪里去。每个 goroutine 都有它自己的堆栈。你甚至可以说每个 goroutine 就是它自己的堆栈。
+什么是堆栈调用?它是一个用于保存局部变量和调用参数的内存区域,并且跟踪每个函数应该返回到哪里去。每个 goroutine 都有它自己的堆栈。你甚至可以说每个 goroutine 就是它自己的堆栈。
下面是我用于演示堆栈的代码。就是一系列简单的函数调用,main() 函数调用 [f1(0xdeadbeef)](https://en.wikipedia.org/wiki/Hexspeak),然后调用 `f2(0xabad1dea)`,再调用 `f3(0xbaddcafe)`。然后 `f3()` 将其中一个作为它的参数,并且将它存储在名为 `local` 的本地变量中。然后获取 `local` 的内存地址并且从那里开始输出。因为 `local` 在栈内,所以输出的就是栈。
From c0c66b4c26a1b06011085d66adc994db9a6a700d Mon Sep 17 00:00:00 2001
From: zhuzi
Date: Tue, 18 Apr 2017 00:00:52 +0800
Subject: [PATCH 194/638] proofreading
---
TODO/secure-web-app-http-headers.md | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/TODO/secure-web-app-http-headers.md b/TODO/secure-web-app-http-headers.md
index 5311d35ff7a..b707e2397a9 100644
--- a/TODO/secure-web-app-http-headers.md
+++ b/TODO/secure-web-app-http-headers.md
@@ -6,7 +6,7 @@
## 如何使用 HTTP Headers 来保护你的 Web 应用 ##
-众所周知,无论是简单的小网页还是复杂的单页应用,Web 应用都是网络攻击的目标。2016年,这种最主要的攻击模式 —— 攻击 web 应用,造成了大约 [40% 的数据泄露](http://www.verizonenterprise.com/verizon-insights-lab/dbir/2016/)。事实上,现在来说,了解网络安全并不是锦上添花, 而是 **Web 开发者的必需任务**,特别对于构建面向消费者的产品的开发人员。
+众所周知,无论是简单的小网页还是复杂的单页应用,Web 应用都是网络攻击的目标。2016 年,这种最主要的攻击模式 —— 攻击 web 应用,造成了大约 [40% 的数据泄露](http://www.verizonenterprise.com/verizon-insights-lab/dbir/2016/)。事实上,现在来说,了解网络安全并不是锦上添花,而是 **Web 开发者的必需任务**,特别对于构建面向消费者的产品的开发人员。
开发者可以利用 HTTP 响应头来加强 Web 应用程序的安全性,通常只需要添加几行代码即可。本文将介绍 web 开发者如何利用 HTTP Headers 来构建安全的应用。虽然本文的示例代码是 Node.js,但基本所有主流的服务端语言都支持设置 HTTP 响应头,并且都可以简单地对其进行配置。
@@ -85,7 +85,7 @@ HSTS 的指令如下:
这是一个强大的指令,强制浏览器**始终**安全加载你的 web 应用程序,即使是第一次收到响应之前加载!这是通过将启用 HSTS 预加载域的列表硬编码到浏览器的代码中实现的。要启用预加载功能,你需要在 Google Chrome 团队维护的网站 [HSTS 预加载列表提交](https://hstspreload.org)注册你的域。
-注意谨慎使用 `preload`,因为这意味着它不能轻易撤销,并可能更新延迟数个月。虽然预加载肯定会加强应用程序的安全性,但也意味着你需要充分确信你的应用程序可以支持仅 HTTPS!
+注意谨慎使用 `preload`,因为这意味着它不能轻易撤销,并可能更新延迟数个月。虽然预加载肯定会加强应用程序的安全性,但也意味着你需要充分确信你的应用程序仅支持 HTTPS!
我建议的用法是 `Strict-Transport-Security: max-age=31536000; includeSubDomains;`,这样指示了浏览器强制通过 HTTPS 连接到源主机并且有效期为一年。如果你对你的 app 仅处理 HTTPS 很有信心,我也推荐加上 `preload` 指令,当然别忘记去前面提到的预加载列表注册你的网站。
@@ -133,7 +133,7 @@ https://mywebapp.com/search?