From afb007d74aad64151c3de22d20e8b8e1c31f2182 Mon Sep 17 00:00:00 2001 From: Galway Chain <50473705+chaingangway@users.noreply.github.com> Date: Mon, 30 Mar 2020 10:05:03 +0800 Subject: [PATCH 01/54] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ate-a-line-chart-in-swiftui-using-paths.md | 69 ++++++++++--------- 1 file changed, 37 insertions(+), 32 deletions(-) diff --git a/TODO1/create-a-line-chart-in-swiftui-using-paths.md b/TODO1/create-a-line-chart-in-swiftui-using-paths.md index 9db7c41812a..1b1036915af 100644 --- a/TODO1/create-a-line-chart-in-swiftui-using-paths.md +++ b/TODO1/create-a-line-chart-in-swiftui-using-paths.md @@ -2,36 +2,37 @@ > * 原文作者:[Anupam Chugh](https://medium.com/@anupamchugh) > * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) > * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/TODO1/create-a-line-chart-in-swiftui-using-paths.md](https://github.com/xitu/gold-miner/blob/master/TODO1/create-a-line-chart-in-swiftui-using-paths.md) -> * 译者: +> * 译者:[chaingangway](https://github.com/chaingangway) > * 校对者: # Create a Line Chart in SwiftUI Using Paths -> Create beautiful stock charts in your iOS application +> 在iOS程序中创建美观的股票图表 ![Photo by [Chris Liverani](https://unsplash.com/@chrisliverani?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral).](https://cdn-images-1.medium.com/max/8064/0*eZh1HfzXfAjD_9ME) -Introduced at WWDC 2019, the SwiftUI framework gave the iOS community a lot to cheer about. An easy-to-use, declarative API written in Swift lets developers quickly build UI prototypes. +SwiftUI 框架在2019年的 WWDC 大会引入后,给了 iOS 社区很多欢呼的理由。一种用 Swift 语言编写,易用的、声明式的 API 让开发者可以快速构建 UI 原型。 -While we can leverage the Shapes protocol to build [Bar Charts](https://medium.com/better-programming/swiftui-bar-charts-274e9fbc8030) from the ground up, the same cannot be said about Line Charts. Thankfully, we’ve got the `Paths` structure to help us with that. +虽然我们能用 Shapes 协议从头开始构建 [条形图](https://medium.com/better-programming/swiftui-bar-charts-274e9fbc8030),但是构建折线图就不一样了。幸运的是,我们有 `Paths` 这个结构体来帮助我们。 -Using SwiftUI paths, which are similar to `CGPaths` from the Core Graphics framework, we can combine lines and curves to build beautiful logos and shapes. +使用 SwiftUI 中的 paths,跟 Core Graphics 框架中的 `CGPaths` 类似,我们可以把线条与曲线结合,来构建美观的标志和形状。 -Being true to the declarative way of writing UI, SwiftUI paths are built with a set of instructions. In the next few sections, we’ll discuss what that means. +SwiftUI 中的 paths 是用一套指令编写的,是真正用声明式的方式来写 UI。在下面的几节中,我们将会讨论它的意义。 -## Our Goal -* Exploring SwiftUI’s Path API and creating simple shapes out of it. -* Using Combine and URLSession to fetch the historical stock data. We’ll be using [Alpha Vantage](https://www.alphavantage.co/)’s API to retrieve the stock information. -* Creating a Line Chart in SwiftUI that displays the stock’s prices over time. +## 我们的目标 +* 探索 SwiftUI 的 Path API,通过它来创建简单的模型。 +* 用 Combine 和 URLSession 来获取历史股票数据。我们将会用 [Alpha Vantage](https://www.alphavantage.co/) 的 API 来取得股票信息。 +* 在 SwiftUI 中创建折线图,来展示根据时间变化的股票价格。 + +读完本文后,你应该能够开发与下面类似的 iOS 程序。 -By the end of this article, you should be able to create an iOS application similar to the one below: ![An NSE India and two US-based stock charts.](https://cdn-images-1.medium.com/max/2000/1*0_IPSWXsxHgGDRk51CAPbw.png) -## Create a Simple SwiftUI Path +## 创建一个简单的 Swift Path -Here’s an example of creating a right-angled triangle using paths in SwiftUI: +下面的例子,是通过在 SwiftUI 中使用 paths 来创建直角三角形: ```Swift var body: some View { @@ -42,22 +43,26 @@ path.addLine(to: CGPoint(x: 300, y: 300)) }.fill(Color.green) } ``` +Path API 有很多函数。`move` 是负责设置路径的起点。`addline` 是负责向特定的目标点,画一条直线。 -The Path API consists of a bunch of functions. `move` is responsible for setting the starting point of the path. `addLine` is responsible for drawing a straight line to the destination point specified. +`addArc`, `addCurve`, `addQuadCurve`, `addRect` 和 `addEllipse` 仅仅是一些其他的方法,它们可以让我们创建圆弧或者贝塞尔曲线。 -`addArc`, `addCurve`, `addQuadCurve`, `addRect`, and `addEllipse` are just a few other methods that let us create circular arcs or Bezier curves among many other things with paths. +用 `addPath` 可以添加两条或者多条路径。 -Appending two or more paths is possible using `addPath`. +下面的插图展示了一个三角形,后面跟着一个圆饼图。 -The following illustration shows a triangle followed by a circular pie: ![](https://cdn-images-1.medium.com/max/2186/1*8XNc1miVjNhzzDCYW44p8g.png) -Now that we’ve got an idea of how to create paths in SwiftUI, let’s jump to Line Charts in SwiftUI. +既然我们已经了解怎样在 SwiftUI 中创建 paths,赶紧来看看 SwiftUI 中的折线图。 + + + +## SwiftUI 折线图 + +下面给出的模型,是用来解析 API 响应返回的 JSON。 -## SwiftUI Line Chart -The model to decode the JSON response from the API is given below: ```Swift struct StockPrice : Codable{ @@ -90,7 +95,8 @@ struct StocksDaily : Codable { } ``` -Let’s create an `ObservableObject` class. We’ll perform the API requests using the URLSession’s Combine Publisher and transform the results using the Combine operators. +创建一个 `ObservableObject` 类。我们用 URLSession 中的 Combine Publisher 来处理 API 请求,然后用 Combine 操作来转换结果。 + ```Swift class Stocks : ObservableObject{ @@ -156,9 +162,9 @@ extension String { } ``` -The API results consist of nested JSON with the key being the dates. These are unordered in the dictionary and we need to sort them. For that, we’ve declared an extension that converts the string to date and does a comparison in the `sort` function. +API 结果中包含用日期作为 key 的内置 JSON。它们在字典中无序的,需要进行排序。因此,我们声明了一个把字符串转换为日期的扩展,然后在 `sort` 函数中进行比较。 -Now that we’ve got the prices and stock data in the `Published` properties, we need to pass them to the `LineView` — a custom SwiftUI view that we will see next: +既然已经在 `Published` 属性中获得了价格和股票数据,我们需要将它们传递给 `LineView` — 下面我们将会看到的一个自定义的 SwiftUI 视图: ```Swift struct LineView: View { @@ -210,8 +216,7 @@ struct LineView: View { } ``` -The view above gets invoked from our SwiftUI ContentView, where the name, price, and an array of price history are passed. Using the GeometryReader, we’ll pass the width and height of the frame to the `Line` struct, where we’ll eventually join the points using SwiftUI paths: - +上面的视图从 SwiftUI 中的 ContentView 唤起,传入了姓名、价格和历史价格的数组。使用 GeometryReader,我们要向 `Line` 结构中的 frame 传入宽和高,这里我们最终会用 SwiftUI 的路径来连接这些点: ```Swift struct Line: View { var data: [(Double)] @@ -264,7 +269,7 @@ struct Line: View { } ``` -`stepWidth` and `stepHeight` are computed for constraining the chart within a given width and height of the frame. They’re then passed to the extension function of the `Path` struct to create the line chart: +计算 `stepWidth` 和 `stepHeight` 是用来在给定 frame 的宽和高的情况下,对图表进行约束。然后,把它们传递给 `Path` 结构体扩展函数,用来创建折线图: ```Swift extension Path { @@ -286,19 +291,19 @@ extension Path { } ``` -Finally, the SwiftUI application displaying the stocks chart in action is ready. The following illustration showcases that: +最后,展示股票折线图的 SwiftUI 程序就绪了。下面的插图进行了展示: ![](https://cdn-images-1.medium.com/max/2186/1*51q3BlLa-XLLKtHn-mgTOA.png) -## Conclusion +## 总结 -In this article, we managed to bring together SwiftUI and Combine once again — this time for fetching stock prices and displaying them in a Line Chart. Knowing the intricacies of SwiftUI paths is a good starting point for working with SwiftUI shapes, which require you to implement the `path` function. +本文中,我们再次将 SwiftUI 和 Combine 成功结合 — 这次是抓取股票价格数据,然后在折线图中展示。通过了解 SwiftUI 中 paths 的错综复杂,实现 `path` 方法,来使用 SwiftUI 中的图形来工作,是一个好的开始。 -You can take the SwiftUI Line Charts above a step further by using gestures to highlight the points and their respective values. To know how to do that and more, refer [to this repository](https://github.com/AppPear/ChartView). +你可以使用手势对点和相应的值进行高亮处理,来进一步了解上文中的 SwiftUI 折线图。想知道怎样实现和更多资料,请参照 [这个仓库](https://github.com/AppPear/ChartView)。 -The full source code of the application above is available in the [GitHub repository](https://github.com/anupamchugh/iowncode/tree/master/SwiftUILineChart). +上文程序中的全部源码都在这个 [GitHub 仓库](https://github.com/anupamchugh/iowncode/tree/master/SwiftUILineChart). -That’s it for this one. Thanks for reading. +文章结束了。感谢阅读。 > 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 From a261e82130e6cd83a5fe0af112b6c8e9daba86ed Mon Sep 17 00:00:00 2001 From: chaingangway Date: Mon, 30 Mar 2020 10:11:39 +0800 Subject: [PATCH 02/54] =?UTF-8?q?Revert=20"=E6=9B=B4=E6=96=B0=E6=B5=8B?= =?UTF-8?q?=E8=AF=95"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit afb007d74aad64151c3de22d20e8b8e1c31f2182. --- ...ate-a-line-chart-in-swiftui-using-paths.md | 69 +++++++++---------- 1 file changed, 32 insertions(+), 37 deletions(-) diff --git a/TODO1/create-a-line-chart-in-swiftui-using-paths.md b/TODO1/create-a-line-chart-in-swiftui-using-paths.md index 1b1036915af..9db7c41812a 100644 --- a/TODO1/create-a-line-chart-in-swiftui-using-paths.md +++ b/TODO1/create-a-line-chart-in-swiftui-using-paths.md @@ -2,37 +2,36 @@ > * 原文作者:[Anupam Chugh](https://medium.com/@anupamchugh) > * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) > * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/TODO1/create-a-line-chart-in-swiftui-using-paths.md](https://github.com/xitu/gold-miner/blob/master/TODO1/create-a-line-chart-in-swiftui-using-paths.md) -> * 译者:[chaingangway](https://github.com/chaingangway) +> * 译者: > * 校对者: # Create a Line Chart in SwiftUI Using Paths -> 在iOS程序中创建美观的股票图表 +> Create beautiful stock charts in your iOS application ![Photo by [Chris Liverani](https://unsplash.com/@chrisliverani?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral).](https://cdn-images-1.medium.com/max/8064/0*eZh1HfzXfAjD_9ME) -SwiftUI 框架在2019年的 WWDC 大会引入后,给了 iOS 社区很多欢呼的理由。一种用 Swift 语言编写,易用的、声明式的 API 让开发者可以快速构建 UI 原型。 +Introduced at WWDC 2019, the SwiftUI framework gave the iOS community a lot to cheer about. An easy-to-use, declarative API written in Swift lets developers quickly build UI prototypes. -虽然我们能用 Shapes 协议从头开始构建 [条形图](https://medium.com/better-programming/swiftui-bar-charts-274e9fbc8030),但是构建折线图就不一样了。幸运的是,我们有 `Paths` 这个结构体来帮助我们。 +While we can leverage the Shapes protocol to build [Bar Charts](https://medium.com/better-programming/swiftui-bar-charts-274e9fbc8030) from the ground up, the same cannot be said about Line Charts. Thankfully, we’ve got the `Paths` structure to help us with that. -使用 SwiftUI 中的 paths,跟 Core Graphics 框架中的 `CGPaths` 类似,我们可以把线条与曲线结合,来构建美观的标志和形状。 +Using SwiftUI paths, which are similar to `CGPaths` from the Core Graphics framework, we can combine lines and curves to build beautiful logos and shapes. -SwiftUI 中的 paths 是用一套指令编写的,是真正用声明式的方式来写 UI。在下面的几节中,我们将会讨论它的意义。 +Being true to the declarative way of writing UI, SwiftUI paths are built with a set of instructions. In the next few sections, we’ll discuss what that means. +## Our Goal -## 我们的目标 -* 探索 SwiftUI 的 Path API,通过它来创建简单的模型。 -* 用 Combine 和 URLSession 来获取历史股票数据。我们将会用 [Alpha Vantage](https://www.alphavantage.co/) 的 API 来取得股票信息。 -* 在 SwiftUI 中创建折线图,来展示根据时间变化的股票价格。 - -读完本文后,你应该能够开发与下面类似的 iOS 程序。 +* Exploring SwiftUI’s Path API and creating simple shapes out of it. +* Using Combine and URLSession to fetch the historical stock data. We’ll be using [Alpha Vantage](https://www.alphavantage.co/)’s API to retrieve the stock information. +* Creating a Line Chart in SwiftUI that displays the stock’s prices over time. +By the end of this article, you should be able to create an iOS application similar to the one below: ![An NSE India and two US-based stock charts.](https://cdn-images-1.medium.com/max/2000/1*0_IPSWXsxHgGDRk51CAPbw.png) -## 创建一个简单的 Swift Path +## Create a Simple SwiftUI Path -下面的例子,是通过在 SwiftUI 中使用 paths 来创建直角三角形: +Here’s an example of creating a right-angled triangle using paths in SwiftUI: ```Swift var body: some View { @@ -43,26 +42,22 @@ path.addLine(to: CGPoint(x: 300, y: 300)) }.fill(Color.green) } ``` -Path API 有很多函数。`move` 是负责设置路径的起点。`addline` 是负责向特定的目标点,画一条直线。 -`addArc`, `addCurve`, `addQuadCurve`, `addRect` 和 `addEllipse` 仅仅是一些其他的方法,它们可以让我们创建圆弧或者贝塞尔曲线。 +The Path API consists of a bunch of functions. `move` is responsible for setting the starting point of the path. `addLine` is responsible for drawing a straight line to the destination point specified. -用 `addPath` 可以添加两条或者多条路径。 +`addArc`, `addCurve`, `addQuadCurve`, `addRect`, and `addEllipse` are just a few other methods that let us create circular arcs or Bezier curves among many other things with paths. -下面的插图展示了一个三角形,后面跟着一个圆饼图。 +Appending two or more paths is possible using `addPath`. +The following illustration shows a triangle followed by a circular pie: ![](https://cdn-images-1.medium.com/max/2186/1*8XNc1miVjNhzzDCYW44p8g.png) -既然我们已经了解怎样在 SwiftUI 中创建 paths,赶紧来看看 SwiftUI 中的折线图。 - - - -## SwiftUI 折线图 - -下面给出的模型,是用来解析 API 响应返回的 JSON。 +Now that we’ve got an idea of how to create paths in SwiftUI, let’s jump to Line Charts in SwiftUI. +## SwiftUI Line Chart +The model to decode the JSON response from the API is given below: ```Swift struct StockPrice : Codable{ @@ -95,8 +90,7 @@ struct StocksDaily : Codable { } ``` -创建一个 `ObservableObject` 类。我们用 URLSession 中的 Combine Publisher 来处理 API 请求,然后用 Combine 操作来转换结果。 - +Let’s create an `ObservableObject` class. We’ll perform the API requests using the URLSession’s Combine Publisher and transform the results using the Combine operators. ```Swift class Stocks : ObservableObject{ @@ -162,9 +156,9 @@ extension String { } ``` -API 结果中包含用日期作为 key 的内置 JSON。它们在字典中无序的,需要进行排序。因此,我们声明了一个把字符串转换为日期的扩展,然后在 `sort` 函数中进行比较。 +The API results consist of nested JSON with the key being the dates. These are unordered in the dictionary and we need to sort them. For that, we’ve declared an extension that converts the string to date and does a comparison in the `sort` function. -既然已经在 `Published` 属性中获得了价格和股票数据,我们需要将它们传递给 `LineView` — 下面我们将会看到的一个自定义的 SwiftUI 视图: +Now that we’ve got the prices and stock data in the `Published` properties, we need to pass them to the `LineView` — a custom SwiftUI view that we will see next: ```Swift struct LineView: View { @@ -216,7 +210,8 @@ struct LineView: View { } ``` -上面的视图从 SwiftUI 中的 ContentView 唤起,传入了姓名、价格和历史价格的数组。使用 GeometryReader,我们要向 `Line` 结构中的 frame 传入宽和高,这里我们最终会用 SwiftUI 的路径来连接这些点: +The view above gets invoked from our SwiftUI ContentView, where the name, price, and an array of price history are passed. Using the GeometryReader, we’ll pass the width and height of the frame to the `Line` struct, where we’ll eventually join the points using SwiftUI paths: + ```Swift struct Line: View { var data: [(Double)] @@ -269,7 +264,7 @@ struct Line: View { } ``` -计算 `stepWidth` 和 `stepHeight` 是用来在给定 frame 的宽和高的情况下,对图表进行约束。然后,把它们传递给 `Path` 结构体扩展函数,用来创建折线图: +`stepWidth` and `stepHeight` are computed for constraining the chart within a given width and height of the frame. They’re then passed to the extension function of the `Path` struct to create the line chart: ```Swift extension Path { @@ -291,19 +286,19 @@ extension Path { } ``` -最后,展示股票折线图的 SwiftUI 程序就绪了。下面的插图进行了展示: +Finally, the SwiftUI application displaying the stocks chart in action is ready. The following illustration showcases that: ![](https://cdn-images-1.medium.com/max/2186/1*51q3BlLa-XLLKtHn-mgTOA.png) -## 总结 +## Conclusion -本文中,我们再次将 SwiftUI 和 Combine 成功结合 — 这次是抓取股票价格数据,然后在折线图中展示。通过了解 SwiftUI 中 paths 的错综复杂,实现 `path` 方法,来使用 SwiftUI 中的图形来工作,是一个好的开始。 +In this article, we managed to bring together SwiftUI and Combine once again — this time for fetching stock prices and displaying them in a Line Chart. Knowing the intricacies of SwiftUI paths is a good starting point for working with SwiftUI shapes, which require you to implement the `path` function. -你可以使用手势对点和相应的值进行高亮处理,来进一步了解上文中的 SwiftUI 折线图。想知道怎样实现和更多资料,请参照 [这个仓库](https://github.com/AppPear/ChartView)。 +You can take the SwiftUI Line Charts above a step further by using gestures to highlight the points and their respective values. To know how to do that and more, refer [to this repository](https://github.com/AppPear/ChartView). -上文程序中的全部源码都在这个 [GitHub 仓库](https://github.com/anupamchugh/iowncode/tree/master/SwiftUILineChart). +The full source code of the application above is available in the [GitHub repository](https://github.com/anupamchugh/iowncode/tree/master/SwiftUILineChart). -文章结束了。感谢阅读。 +That’s it for this one. Thanks for reading. > 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 From 862cc579a6f5022fc43f752ffb19002f043f9600 Mon Sep 17 00:00:00 2001 From: Amberlin1970 <37952468+Amberlin1970@users.noreply.github.com> Date: Fri, 27 Mar 2020 21:11:30 +0800 Subject: [PATCH 03/54] =?UTF-8?q?8=20=E4=B8=AA=E5=80=BC=E5=BE=97=E4=BA=86?= =?UTF-8?q?=E8=A7=A3=E7=9A=84=E6=A0=91=E5=BD=A2=E6=95=B0=E6=8D=AE=E7=BB=93?= =?UTF-8?q?=E6=9E=84=20(#6804)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 8个值得了解的树形数据结构 8个值得了解的树形数据结构 * Update 8-Useful-Tree-Data-Structures-Worth-Knowing.md * Update 8-useful-tree-data-structures-worth-knowing.md Co-authored-by: sun <776766759@qq.com> --- ...eful-tree-data-structures-worth-knowing.md | 243 +++++++++--------- 1 file changed, 122 insertions(+), 121 deletions(-) diff --git a/TODO1/8-useful-tree-data-structures-worth-knowing.md b/TODO1/8-useful-tree-data-structures-worth-knowing.md index 49ec2c965d2..eb4249a0ec8 100644 --- a/TODO1/8-useful-tree-data-structures-worth-knowing.md +++ b/TODO1/8-useful-tree-data-structures-worth-knowing.md @@ -2,201 +2,202 @@ > * 原文作者:[Vijini Mallawaarachchi](https://medium.com/@vijinimallawaarachchi) > * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) > * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/TODO1/8-useful-tree-data-structures-worth-knowing.md](https://github.com/xitu/gold-miner/blob/master/TODO1/8-useful-tree-data-structures-worth-knowing.md) -> * 译者: -> * 校对者: +> * 译者:[Amberlin1970](https://github.com/Amberlin1970) +> * 校对者:[PingHGao](https://github.com/PingHGao), [Jiangzhiqi4551](https://github.com/Jiangzhiqi4551) -# 8 Useful Tree Data Structures Worth Knowing +# 8 个值得了解的树形数据结构 -What comes to your mind when you think of a tree? Roots, branches and leaves? A big oak tree with roots, branches and leaves may come to your mind. Similarly, in computer science, the tree data structure has roots, branches and leaves, but it is drawn upside-down. A tree is a hierarchical data structure which can represent relationships between different nodes. In this article, I will briefly introduce you to 8 types of tree data structures. +对于一棵树你会想到什么呢?树根、分支和树叶?一个有树根、分支和树叶的大橡树可能会在你脑海浮现。相似地,在计算机科学中,树形数据结构有根部、分支和树叶,但它是自上而下的。树是一种层级数据结构,以表达不同节点之间的关系。在这篇文章中,我将会简要地给你介绍 8 种树形数据机构。 -#### Properties of a Tree +#### 树的属性 -* A tree can contain no nodes or it can contain one special node called the **root** with zero or more subtrees. -* Every edge of the tree is directly or indirectly originated from the root. -* Every child has only one parent, but one parent can have many children. +* 树可以没有节点也可以包含一个特殊的节点**根节点**,该根节点可以包含零或多棵子树。 +* 树的每条边都直接或间接地源于根节点。 +* 每个孩子节点只有一个父节点,但每个父节点可以有很多孩子节点。 -![Fig 1. Terminology of trees](https://cdn-images-1.medium.com/max/2000/1*PWJiwTxRdQy8A_Y0hAv5Eg.png) +![Fig 1. 树的相关术语](https://cdn-images-1.medium.com/max/2000/1*PWJiwTxRdQy8A_Y0hAv5Eg.png) -In this article, I will be briefly explaining the following 10 tree data structures with their usage. +在这篇文章中,我将会简要地解释下面 8 种树形数据结构及它们的用途。 -1. General tree -2. Binary tree -3. Binary search tree -4. AVL tree -5. Red-black tree -6. Splay tree -7. Treap -8. B-tree +1. 普通树 +2. 二叉树 +3. 二叉搜索树 +4. AVL树 +5. 红黑树 +6. 伸展树 +7. 树堆 +8. B树 -## 1. General Tree +## 1. 普通树 -A **general tree** is a tree data structure where there are no constraints on the hierarchical structure. +**普通树**是一种在层级结构上无限制的树形数据结构。 -#### Properties +#### 属性 -1. Follow properties of a tree. -2. A node can have any number of children. +1. 遵循树的属性。 +2. 一个节点可以有任意数量的孩子。 -![Fig 2. General tree](https://cdn-images-1.medium.com/max/2000/1*rInucvqb9X8bqM5yE143SQ.png) +![Fig 2. 普通树](https://cdn-images-1.medium.com/max/2000/1*rInucvqb9X8bqM5yE143SQ.png) -#### Usage +#### 用途 -1. Used to store hierarchical data such as folder structures. +1. 用于存储如文件结构类的层级数据。 -## 2. Binary Tree +## 2. 二叉树 -A **binary tree** is a tree data structure where the following properties can be found. +**二叉树**是一种有如下属性的树形数据结构。 -#### Properties +#### 属性 -1. Follow properties of a tree. -2. A node can have at most two child nodes (children). -3. These two child nodes are known as the **left child** and **right child**. +1. 遵循树的属性。 +2. 一个节点至多有两个孩子。 +3. 这两个孩子分别称为**左孩子**和**右孩子**。 -![Fig 3. Binary tree](https://cdn-images-1.medium.com/max/2000/1*abunFFnReygaqVt93xNr2A.png) +![Fig 3. 二叉树](https://cdn-images-1.medium.com/max/2000/1*abunFFnReygaqVt93xNr2A.png) -#### Usage +#### 用途 -1. Used by compilers to build syntax trees. -2. Used to implement expression parsers and expression solvers. -3. Used to store router-tables in routers. +1. 在编译器中用于构造语法树。 +2. 用于执行表达式解析和表达式求解。 +3. 路由器中用于存储路由器表。 -## 3. Binary Search Tree +## 3. 二叉搜索树 -A **binary search tree** is a more constricted extension of a binary tree. +**二叉搜索树**是二叉树的一种更受限的扩展。 -#### Properties +#### 属性 -1. Follow properties of a binary tree. -2. Has a unique property known as the **binary-search-tree property**. This property states that the value (or key) of the left child of a given node should be less than or equal to the parent value and the value of the right child should be greater than or equal to the parent value. +1. 遵循二叉树的属性。 +2. 有一个独特的属性,称作**二叉搜索树属性**。这个属性要求一个给定节点的左孩子的值(或键)应该小于或等于父节点的值,而右孩子的值应该大于或等于父节点的值。 -![Fig 4. Binary search tree](https://cdn-images-1.medium.com/max/2000/1*jBgV9A847f_pHMbO67tcgw.png) +![Fig 4. 二叉搜索树](https://cdn-images-1.medium.com/max/2000/1*jBgV9A847f_pHMbO67tcgw.png) -#### Usage +#### 用途 -1. Used to implement simple sorting algorithms. -2. Can be used as priority queues. -3. Used in many search applications where data are constantly entering and leaving. +1. 用于执行简单的排序算法。 +2. 可以用作优先队列。 +3. 适用于数据持续进出的很多搜索应用中。 -## 4. AVL tree +## 4. AVL树 -An **AVL tree** is a self-balancing binary search tree. This is the first tree introduced which automatically balances its height. +**平衡二叉树**是一种自我平衡的二叉搜索树。这是介绍的第一种自动平衡高度的树。 -#### Properties +#### 属性 -1. Follow properties of binary search trees. -2. Self-balancing. -3. Each node stores a value called a **balance factor** which is the difference in height between its left subtree and right subtree. -4. All the nodes must have a balance factor of -1, 0 or 1. +1. 遵循二叉搜索树的属性。 +2. 自平衡。 +3. 每一个节点储存了一个值,称为一个**平衡因子**,即为其左子树和右子树的高度差。 +4. 所有的节点都必须有一个平衡因子且只能是 -1、0 或 1。 -After performing insertions or deletions, if there is at least one node that does not have a balance factor of -1, 0 or 1 then rotations should be performed to balance the tree (self-balancing). You can read more about the rotation operations in my previous article from [**here**](https://towardsdatascience.com/self-balancing-binary-search-trees-101-fc4f51199e1d). +在进行插入或是删除后,如果有一个节点的平衡因子不是 -1、0 或 1,就必须通过旋转来平衡树(自平衡)。你可以在我前面的文章 [**这里**](https://towardsdatascience.com/self-balancing-binary-search-trees-101-fc4f51199e1d) 阅读到更多的旋转操作。 -![Fig 5. AVL tree](https://cdn-images-1.medium.com/max/2000/1*aI575o1BBE3B4cAFUG73pw.png) +![Fig 5. AVL树](https://cdn-images-1.medium.com/max/2000/1*aI575o1BBE3B4cAFUG73pw.png) -#### Usage +#### 用途 -1. Used in situations where frequent insertions are involved. -2. Used in Memory management subsystem of the Linux kernel to search memory regions of processes during preemption. +1. 用于需要频繁插入的情况。 +2. 在 Linux 内核的内存管理子系统中用于在抢占期间搜索进程的内存区域。 -## 5. Red-black tree +## 5. 红黑树 -A red-black tree is a self-balancing binary search tree, where each node has a colour; red or black. The colours of the nodes are used to make sure that the tree remains approximately balanced during insertions and deletions. +红黑树是一种自平衡的二叉搜索树,每一个节点都有一种颜色:红或黑。节点的颜色用于确保树在插入和删除时保持大致的平衡。 -#### Properties +#### 属性 -1. Follow properties of binary search trees. -2. Self-balancing. -3. Each node is either red or black. -4. The root is black (sometimes omitted). -5. All leaves (denoted as NIL) are black. -6. If a node is red, then both its children are black. -7. Every path from a given node to any of its leaf nodes must go through the same number of black nodes. +1. 遵循二叉搜索树的属性。 +2. 自平衡。 +3. 每个节点或是红色或是黑色。 +4. 根节点是黑色(有时省略)。 +5. 所有叶子(标注为 NIL)是黑色。 +6. 如果一个节点是红色,那它的孩子都是黑色。 +7. 从一个给定的节点到其任意的叶子节点的每条路径都必须经过相同数目的黑色节点。 -![Fig 6. AVL tree](https://cdn-images-1.medium.com/max/2000/1*11zvjUozpAenuez03oUeYA.png) +![Fig 6. 红黑树](https://cdn-images-1.medium.com/max/2000/1*11zvjUozpAenuez03oUeYA.png) -#### Usage +#### 用途 -1. As a base for data structures used in computational geometry. -2. Used in the **Completely Fair Scheduler** used in current Linux kernels. -3. Used in the **epoll** system call implementation of Linux kernel. +1. 在计算几何中作为数据结构的基础。 +2. 用于现在的 Linux 内核的**完全公平调度算法**中。 +3. 用于 Linux 内核的 **epoll** 系统中。 -## 6. Splay tree +## 6. 伸展树 -A **splay tree** is a self-balancing binary search tree. +**伸展树**是一种自平衡的二叉搜索树。 -#### Properties +#### 属性 -1. Follow properties of binary search trees. -2. Self-balancing. -3. Recently accessed elements are quick to access again. +1. 遵循二叉搜索树的属性。 +2. 自平衡。 +3. 近期获取过的元素再次获取时速度更快。 -After performing a search, insertion or deletion, splay trees perform an action called **splaying** where the tree is rearranged (using rotations) so that the particular element is placed at the root of the tree. +在搜索、插入或是删除后,伸展树会执行一个动作,称为**伸展**,在执行伸展动作时,树会被重新排列(使用旋转)将特定元素放置在树的根节点。 -![Fig 7. Splay tree search](https://cdn-images-1.medium.com/max/2000/1*w5MA0XAEk1vX1lef4cUbdA.png) +![Fig 7. 伸展树搜索](https://cdn-images-1.medium.com/max/2000/1*w5MA0XAEk1vX1lef4cUbdA.png) -#### Usage +#### 用途 -1. Used to implement caches -2. Used in garbage collectors. -3. Used in data compression +1. 用于实现缓存。 +2. 用在垃圾收集器中。 +3. 用于数据压缩。 -## 7. Treap +## 7. 树堆 -A **treap** (the name derived from **tree + heap**) is a binary search tree. +**树堆**(名字来源于**树**和**堆**的结合)是一种二叉搜索树。 -#### Properties +#### 属性 -1. Each node has two values; a **key** and a **priority**. -2. The keys follow the binary-search-tree property. -3. The priorities (which are random values) follow the heap property. +1. 每个节点有两个值:一个**键**和一个**优先级**。 +2. 键遵循二叉搜索树的属性。 +3. 优先级(随机值)遵循堆的属性。 -![Fig 8. Treap (red coloured alphabetic keys follow BST property and blue coloured numeric values follow max heap order)](https://cdn-images-1.medium.com/max/2000/1*iH-zgLTHTHYe2E56aa2MWw.png) +![Fig 8. 树堆(红色的字母键遵循 BST 属性而蓝色的数字键遵循最大堆顺序)](https://cdn-images-1.medium.com/max/2000/1*iH-zgLTHTHYe2E56aa2MWw.png) -#### Usage +#### 用途 -1. Used to maintain authorization certificates in public-key cryptosystems. -2. Can be used to perform fast set operations. +1. 用于维护公钥密码系统中的授权证书。 +2. 可以用于执行快速的集合运算。 -## 8. B-tree +## 8. B树 -B tree is a self-balancing search tree and contains multiple nodes which keep data in sorted order. Each node has 2 or more children and consists of multiple keys. +B树是一种自平衡的搜索树,而且包含了多个排过序的节点。每个节点有 2 个或多个孩子且包含多个键。 -#### Properties +#### 属性 -1. Every node x has the following: - * x.n (the number of keys) - * x.keyᵢ (the keys stored in ascending order) - * x.leaf (whether x is a leaf or not) -2. Every node x has (x.n + 1) children. -3. The keys x.keyᵢ separate the ranges of keys stored in each sub-tree. -4. All the leaves have the same depth, which is the tree height. -5. Nodes have lower and upper bounds on the number of keys that can be stored. Here we consider a value t≥2, called **minimum degree** (or **branching factor**) of the B tree. - * The root must have at least one key. - * Every other node must have at least (t-1) keys and at most (2t-1) keys. Hence, every node will have at least t children and at most 2t children. We say the node is **full** if it has (2t-1) keys. +1. 每个节点 x 有如下(属性): + * x.n(键的数量) + * x.keyᵢ(键以升序存储) + * x.leaf(x 是否是一个叶子) +2. 每个节点 x 有(x.n + 1)孩子。 +3. 键 x.keyᵢ 分割了存储在每个子树中键的范围。 +4. 所有的叶子有相等的深度,即为树的高度。 +5. 节点有存储的键的数量的上界和下界。这里我们考虑一个值 t≥2,称为 B树的**最小度**(或**分支因子**)。 + * 根节点必须至少有一个键。 + * 每个其余节点必须有至少(t - 1)个键和至多(2t - 1)个键。因此,每个节点将会有至少 t 个孩子和至多 2t 个孩子。如果一个节点有(2t - 1)个键,我们称这个点是**满的**。 -![Fig 9. B-tree](https://cdn-images-1.medium.com/max/2788/1*GXwr5PFqDNOOk8ae-8W5zA.png) +![Fig 9. B树](https://cdn-images-1.medium.com/max/2788/1*GXwr5PFqDNOOk8ae-8W5zA.png) -#### Usage +#### 用途 -1. Used in database indexing to speed up the search. -2. Used in file systems to implement directories. +1. 用于数据库索引以加速搜索。 +2. 在文件系统中用于实现目录。 -## Final Thoughts +## 最后的思考 -A cheat sheet for the time complexities of the data structure operations can be found in this [link](https://www.bigocheatsheet.com/). +数据结构操作的时间复杂度的备忘录可以在这个[链接](https://www.bigocheatsheet.com/)找到。 -I hope you found this article useful as a simple introduction to tree structures. I would love to hear your thoughts. 😇 +我希望这篇文章作为一个对树形结构的简单介绍对你是有用的。我很乐意听你的想法。😇 -Thanks a lot for reading! +非常感谢阅读! -Cheers! 😃 +祝愉快! 😃 -## References +## 参考 - - [1] Introduction to Algorithms (Third Edition) by Thomas H. Cormen, Charles E. Leiserson, Ronald L. Livest and Clifford Stein. + - [1] 算法导论(第三版),作者:Thomas H.Cormen / Charles E.Leiserson / Ronald L.Rivest / Clifford Stein. - [2] [https://en.wikipedia.org/wiki/List_of_data_structures](https://en.wikipedia.org/wiki/List_of_data_structures) -> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 +*本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 --- From 063284668ade46b7fdeec6bf7492f62ea17fc7ed Mon Sep 17 00:00:00 2001 From: Charlo <49369951+Charlo-O@users.noreply.github.com> Date: Fri, 27 Mar 2020 21:12:55 +0800 Subject: [PATCH 04/54] =?UTF-8?q?=E7=9C=BC=E5=8A=A8=E8=B7=9F=E8=B8=AA?= =?UTF-8?q?=E5=92=8C=E7=A7=BB=E5=8A=A8=E4=B8=96=E7=95=8C=E7=9A=84=E6=9C=80?= =?UTF-8?q?=E4=BD=B3=E7=94=A8=E6=88=B7=E4=BD=93=E9=AA=8C=E5=AE=9E=E8=B7=B5?= =?UTF-8?q?=20(#6806)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 眼动跟踪和移动世界的最佳用户体验实践 翻译完成 * 眼动跟踪和移动世界的最佳用户体验实践 #6806 谢谢指点~@xionglong58 @fanyijihua 根据第一轮校对意见修改完成 * 眼动追踪和移动世界的最佳用户体验实践 * 眼动追踪和移动世界的最佳用户体验实践 --- ...e-best-ux-practices-in-the-mobile-world.md | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/TODO1/eye-tracking-and-the-best-ux-practices-in-the-mobile-world.md b/TODO1/eye-tracking-and-the-best-ux-practices-in-the-mobile-world.md index 708fdf3f76f..c9e4dcfd9d6 100644 --- a/TODO1/eye-tracking-and-the-best-ux-practices-in-the-mobile-world.md +++ b/TODO1/eye-tracking-and-the-best-ux-practices-in-the-mobile-world.md @@ -1,55 +1,55 @@ -> * 原文地址:[Eye Tracking and The Best UX Practices in The Mobile World](https://medium.com/nyc-design/eye-tracking-and-the-best-ux-practices-in-the-mobile-world-a101f67f20dd) +> * 原文地址:[眼动追踪和移动世界的最佳用户体验实践](https://medium.com/nyc-design/eye-tracking-and-the-best-ux-practices-in-the-mobile-world-a101f67f20dd) > * 原文作者:[Naman Sehgal](https://medium.com/@sehgal.naman) > * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) > * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/TODO1/eye-tracking-and-the-best-ux-practices-in-the-mobile-world.md](https://github.com/xitu/gold-miner/blob/master/TODO1/eye-tracking-and-the-best-ux-practices-in-the-mobile-world.md) -> * 译者: -> * 校对者: +> * 译者:[Charlo](https://github.com/Charlo-O?tab=repositories) +> * 校对者:[Long Xiong](https://github.com/xionglong58)、[PingHGao](https://github.com/PingHGao) -# Eye Tracking and The Best UX Practices in The Mobile World +# 眼动追踪和移动世界的最佳用户体验实践 -![](https://cdn-images-1.medium.com/max/2000/1*spEmZXSrMLBkTQFEQY-jVA.jpeg) +![](https://imgkr.cn-bj.ufileos.com/2c668962-2d6a-4f85-96a0-5b3485f64c45.jpeg) -In today’s world, usability testing is critical for designing user-friendly interfaces. These tests take on different forms and methods that help designers identify usability issues. This is critical when analyzing the bridge between design expectations and user behavior. Sensory-based technology, such as eye-tracking, has been revolutionary in gaining deeper insights on how users interact with technology. +在当今世界,可用性测试对于设计用户友好的界面至关重要。这些测试采用不同的形式和方法来帮助设计师发现可用性问题。这在把握设计期望和用户行为之间的关系时至关重要。诸如眼动追踪一类的以传感器为基础的技术,在深入了解用户如何与技术交互方面具有革命性意义。 -Eye Tracking is a usability method and tool that reveals users’ focus points and navigational patterns on a given interface. It provides designers with thorough feedback on which interface elements are visible and attention-grabbing. It also effectively evaluates design/content hierarchy. Eye Tracking is an insightful form of research technique, which determines the user’s focus and attention of the user. +眼动追踪是一种可用方法和工具,它可以在给定的界面上显示用户的焦点和访问模式。它能够为设计者提供详尽反馈,界面哪些元素能够吸引用户的眼球。它还可以有效地评估设计/内容层次结构。眼动追踪是一种很有洞察力的研究技术,它决定了用户的关注焦点和用户的注意力。 -![](https://cdn-images-1.medium.com/max/2000/1*sAtbUAIscKdVhVOoV6J1BA.jpeg) +![](https://imgkr.cn-bj.ufileos.com/56680bdb-32e8-491f-9990-a041a6a7818b.jpeg) -## Eye Tracking for a Mobile-Centric World +## 移动互联网中的眼动追踪 -Considering that more than 80% of the population has access to mobile devices, the percentage of mobile internet usage is surpassing traditional computing platform usage. Today’s world is mobile-centric. Thus, making it important to focus on the usability of mobile devices. +考虑到超过 80% 的人口可以使用移动设备,移动互联网的使用率正在超过传统计算平台。今天的世界是以移动为中心的。因此,关注移动设备的可用性非常重要。 -Jen Romano Bergstrom, a User Experience Specialist conducted a research study to compare the user experience of the same interface across multiple devices using eye tracking. As a result, she uncovered different issues across different devices. Below is the heat map of the data. The red spots are the main focus points, and the green and yellow are the areas which get less attention from the users. It is clearly visible that users have a different area of focus for the same interface on different devices. +用户体验专家珍妮弗·罗曼诺·伯格斯特伦(Jen Romano Bergstrom)进行了一项研究,利用眼动追踪技术,在多个设备之间比较同一界面的用户体验。结果,她在不同的设备上发现了不同的问题。下面是数据的热点图。红点是主要的焦点,绿色和黄色是用户关注较少的区域。很明显,用户在不同的设备上对相同的界面有不同的关注点。 -![**Image from Jen Romano Bergstrom’s eye-tracking research**](https://cdn-images-1.medium.com/max/3924/1*hoCe7meUocl79e7ZairBNg.jpeg) +![**Image from Jen Romano Bergstrom’s eye-tracking research**](https://imgkr.cn-bj.ufileos.com/00330430-8823-4131-ae2f-50f3e6a5954c.jpeg) -## Best UX Practices for Mobile Devices +## 移动设备的最佳用户体验实践 -Steve Krug, an information architect and user experience professional who is best known for his book “Don’t Make Me Think — A Common Sense Approach to Web Usability”, mentioned that designers keep in mind that the users first read before the act. Content is read through before other links are carefully chosen and clicked. The reality is that people don’t read everything, they just read what they want to. This is a big takeaway and reinforces the importance of usability tools such as the eye-tracking device. +史蒂夫·克鲁格(Steve Krug)是一名信息架构师和用户体验专家,以著作《点石成金 —— 访客至上的网页设计秘笈法》闻名。他在书中提到,用户在采取行动前会先看。在仔细选择和点击其他链接之前,会先阅读文本。事实上,人们并不是什么都看,他们只是看他们想看的。这是一个重大突破,它强化了可用性工具(如眼动追踪设备)的重要性。 -![**Image from Steve Krug’s book — “Don’t Make Me Think”**](https://cdn-images-1.medium.com/max/2000/1*YHZz6pAqHABKtVVsrhLwJg.jpeg) +![**图片源自史蒂夫·克鲁格的著作 ——《点石成金 —— 访客至上的网页设计秘笈法》**](https://imgkr.cn-bj.ufileos.com/5fef551e-8671-4dae-9d1d-db1b95243746.jpeg) -Jen Romano Bergstrom explained some key guidelines on the best UX practices that every User Experience professional should follow. These practices were drafted after several eye tracking researches were performed. +珍妮弗·罗曼诺·伯格斯特伦(Jen Romano Bergstrom)解释了一些最佳用户体验实践的关键准则,每个用户体验专家都应该遵循。这些准则是在进行了几次眼动跟踪研究后起草的。 -**1. Functional icons across devices** +**1、跨设备的功能图标** -Icons and images should be clickable across the devices as users expect them to be interactive. Making things clickable on the homepage will help make the page more intuitive. +>图标和图像应该像用户希望的那样,能在不同的设备下被点击,从而产生交互。让主页上的元素可点击将使网页更直观。 -**2. Clear and precise error messages** +**2、清晰而准确的错误信息** -If an error message pops up, it should explain what the error message is all about. Below is an example from one of Jen’s research. On the left side, an error message popped up. However, it was not clear to state which mandatory field was to be filled. On the right side of being the user’s gaze plots. The user is trying to search all over the screen for the mandatory field which is left. So, the error message should clearly point out the problem in order for the user to quickly move forward. +如果出现一个错误消息,它应该解释这个错误消息与什么有关。下面是 Jen 研究中的一个例子。在左侧,弹出一个错误消息。但是,尚不清楚应填写哪个必填字段。右边是用户的注视图。用户试图在整个屏幕上搜索剩下的必填字段。因此,错误消息应该清楚地指出问题所在,便于用户快速进行下一步操作。 -![**Image from Jen Romano Bergstrom’s eye-tracking research**](https://cdn-images-1.medium.com/max/2688/1*D4lUGwQswG5pSr9uwIf-Xg.png) +![**图片源自珍妮弗·罗曼诺·伯格斯特伦的眼动跟踪研究**](https://imgkr.cn-bj.ufileos.com/fd2bac1b-49f5-4b2c-9f18-5027fc434148.png) -**3. Consistent layout across devices** +**3、统一页面布局** -Keeping in mind that the users have access to multiple devices, an interface’s layout should be consistent across various mobile devices. The flow of information should remain the same as good design gives users a consistent mental model throughout all platforms. +请记住,用户可以访问多个设备,一个界面的布局应该在各种移动设备之间保持一致。信息流应该保持不变,因为好的设计可以在所有平台上为用户提供一致的心智模型。 -## Conclusion +## 结论 -Despite the fact that eye-tracking is a time consuming and expensive process, it is a very useful technique to gain deep insights on a particular product. As far as the use of eye tracking in mobile devices is concerned, there is a lot more to explore in this area. Following these suggested UX practices will significantly improve the user’s experience. +尽管眼动追踪是一个耗时且昂贵的过程,但它是一种非常有用的技术,可以让你对特定产品有更深刻的了解。就移动设备中眼球追踪的使用而言,这一领域还有很多值得探索的地方。遵循这些建议的 UX 实践将极大地改善用户体验。 -## References +## 参考文献 [http://bit.ly/2AGPlkz](http://bit.ly/2AGPlkz) From a66e069f95e1710c23af4ef3608670308f6fa48f Mon Sep 17 00:00:00 2001 From: TiaossuP Date: Fri, 27 Mar 2020 21:14:45 +0800 Subject: [PATCH 05/54] =?UTF-8?q?=E6=88=91=E5=B9=B6=E4=B8=8D=E8=AE=A8?= =?UTF-8?q?=E5=8E=8C=E7=AE=AD=E5=A4=B4=E5=87=BD=E6=95=B0(#6610)=20(#6659)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 我并不讨厌箭头函数(#6610) * 我并不讨厌箭头函数(#6610) - 根据校对结果修改 * Update i-dont-hate-arrow-functions.md Co-authored-by: 小添 Co-authored-by: sun <776766759@qq.com> --- TODO1/i-dont-hate-arrow-functions.md | 194 +++++++++++++-------------- 1 file changed, 97 insertions(+), 97 deletions(-) diff --git a/TODO1/i-dont-hate-arrow-functions.md b/TODO1/i-dont-hate-arrow-functions.md index 6a5f7daae5a..9479e73e02c 100644 --- a/TODO1/i-dont-hate-arrow-functions.md +++ b/TODO1/i-dont-hate-arrow-functions.md @@ -2,183 +2,183 @@ > * 原文作者:[Kyle Simpson](https://github.com/getify) > * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) > * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/TODO1/i-dont-hate-arrow-functions.md](https://github.com/xitu/gold-miner/blob/master/TODO1/i-dont-hate-arrow-functions.md) -> * 译者: -> * 校对者: +> * 译者:[TiaossuP](https://github.com/tiaossup) +> * 校对者:[Chorer](https://github.com/Chorer),[scarqin](https://github.com/scarqin) -# I Don’t Hate Arrow Functions +# 我并不讨厌箭头函数 -## TL;DR +## 文章篇幅较长,可以直接看下面的总结 -Arrow functions are fine for certain usages, but they have so many variations that they need to be carefully controlled to not break down the readability of the code. +箭头函数在某些场景下表现很好,但是在很多情况下,仍然有可能降低代码的可读性,因此要谨慎使用。 -While arrow functions clearly have a ubiquitous community consensus (though not unanimous support!), it turns out there's a wide variety of opinions on what makes "good" usage of `=>` and not. +尽管箭头函数显然已经在社区中被普遍接受(虽然并非一致支持),但事实证明,对于如何用好 `=>`,大家有各种各样的看法。 -Configurable linter rules are the best solution to wrangling the variety and disagreement of arrow functions. +可配置的 lint 规则是解决箭头函数的多样性和分歧的最佳解决方案。 -I released [**proper-arrows** ESLint plugin](https://github.com/getify/eslint-plugin-proper-arrows) with several configurable rules to control `=>` arrow functions in your code base. +我发布了带有一些可配置规则的 [**proper-arrows** ESLint 插件](https://github.com/getify/eslint-plugin-proper-arrows),用于控制代码库中的 `=>` 箭头函数。 -## Opinions are like noses... +## 观点总是见仁见智的 -Anyone who's followed me (tweets, books, courses, etc) for very long knows that I have lots of opinions. In fact, that's the only thing I'm an expert on -- my own opinions -- and I'm never at a loss for them! +任何关注我(包括推特、书籍、课程等)很久的人,都知道我总是有很多观点。事实上,这是我唯一擅长的事情(这也是我自己的观点),而且从来不会对它们感到困惑。 -I don't subscribe to the "strong opinions, loosely held" mantra. I don't "loosely hold" my opinions because I don't see any point in having an opinion if there isn't sufficient reason for that opinion. I spend a lot of time researching and tinkering and writing and trying out ideas before I form an opinion that I would share publicly. By that point, my opinion is pretty strongly held, by necessity. +我不赞同「强观点,弱坚持」*(译注:原文 strong opinions, loosely held 当存在若干现有事实时,要自信而强硬地表达观点;而遇到更强有力的论据时,则要懂得妥协让步)*这种信条。我不会「松散地持有」我的观点,因为没有足够理由支持的观点本来就没有任何意义。我花了很多时间研究、修改、写作、尝试各种想法,然后才形成一个可以公开分享的观点。在这一点上,我的观点是非常坚定的,这是必然的。 -What's more, I teach based on these opinions -- thousands of developers in different companies all over the world -- which affords me the opportunity to deeply vet my opinions through myriad discussion and debate. I'm tremendously privleged to be in such a position. +更重要的是,我是基于这些观点去教授来自世界各地不同公司的数千名开发人员的 —— 这让我有机会通过无数的讨论和辩论来深入审视我的观点。能身居教学之位我深感荣幸。 -That doesn't mean I can't or won't change my opinions. As a matter of fact, one of my most strongly held opinions -- that JS types and coercion are useful in JS -- has been shifting lately, to a fairly significant degree. I have a much more rounded and deepened perspective on JS types and why type-aware tooling can be useful. And even my opinion on `=>` arrow functions, the punchline of this article, has evolved and deepened. +这并不意味着我不能或不会改变我的观点。事实上,我曾经最坚定的观点之一 —— 「JS 类型及[强制类型转换](https://developer.mozilla.org/en-US/docs/Glossary/Type_coercion)在 JS 中很有用」最近已经发生了很大程度的变化。我对 JS 类型及类型检测工具为何有用有了更全面和深入的认识。甚至我对 `=>` 箭头函数(本文的主题)的看法也在不断发展和深化。 -But one of the things many people tell me they appreciate about me is, I don't just state opinions, I back those opinions up with careful, thought-out reasoning. Even when people vehemently disagree with my opinions, they often compliment me on at least owning those opinions with backing. +但是很多人告诉我他们欣赏我的一点是,我不仅陈述观点,还用严密的、深思熟虑的推理来支持这些观点。即使当人们强烈反对我的观点时,他们通常也会称赞我至少拥有那些有理有据的观点。 -And I try to inspire the same in others through my speaking, teaching, and writing. I don't care if you agree with me, I only care that you know why you have an technical opinion and can earnestly defend it with your own line of reasoning. To me, that's a healthy relationship with technology. +我试图通过我的演讲、教学和写作来给其他人同样的灵感。我不在乎你是否同意我的观点,我只在乎你能知道自己为什么会在技术上持有这么一个观点,并且可以用你自己的推理来认真地捍卫它。对我来说,这是一种与技术「和谐共处」的方式。 -## Arrow Functions != `function`s +## `=>` 箭头函数 != `function` -It is my sincere belief that the `=>` arrow function is not suitable as a general purpose replacement for all (or even most) `function` functions in your JS code. I genuinely don't find them more readable in most cases. And I'm not alone. Any time I [share an opinion like that](https://twitter.com/getify/status/1105182569824346112) on social media, I often [get dozens](https://twitter.com/bence_a_toth/status/1105185760448311296) of ["me too!" responses](https://twitter.com/joehdodd/status/1105185789942603777) peppered in with [the scores](https://twitter.com/kostitsyn/status/1105229763369680896) of "you're [totally wrong!](https://twitter.com/fardarter/status/1105347990225649664)" responses. +我真心觉得 `=>` 箭头函数并不适合替换 JS 代码中所有(或者至少说大多数)的 `function` 函数代码。我发现在大多数情况下,箭头函数并没有让代码更易读。并非只有我这样想,每当我在社交媒体上分享[类似的观点](https://twitter.com/getify/status/1105182569824346112)时,我经常会收到[几十条](https://twitter.com/bence_a_toth/status/1105185760448311296)「我也是!」的回应,只掺杂着几条「你[完全错了](https://twitter.com/fardarter/status/1105347990225649664)」的[回应](https://twitter.com/kostitsyn/status/1105229763369680896)。 -But I'm not here to rehash the entire debate over `=>` arrow functions. I've written extensively about my opinions on them, including these sections in my books: +但是我并不是想在这里完整地讨论 `=>` 箭头函数。关于它,我已经写了很多篇文章来表达观点,包括我书中的以下部分: -* ["You Don't Know JS: ES6 & Beyond", Ch2, "Arrow Functions"](https://github.com/getify/You-Dont-Know-JS/blob/master/es6%20%26%20beyond/ch2.md#arrow-functions) +* [“你不知道的 JavaScript(下卷)”,第二章,“箭头函数”](https://github.com/getify/You-Dont-Know-JS/blob/master/es6%20%26%20beyond/ch2.md#arrow-functions) * ["Functional-Light JavaScript", Ch2, "Functions Without `function`"](https://github.com/getify/Functional-Light-JS/blob/master/manuscript/ch2.md/#functions-without-function) (and the preceding section on function names). -Whatever your preferences around `=>`, to suggest that it's **only** a **better** `function` is to be plainly reductive. It's a far more nuanced topic than just a one-to-one correspondence. +无论对 `=>` 的偏好如何,把其**仅仅**视为是一个**更好的** `function` 的想法,都有些过于简略了。除了一对一的关系,还有很多细微的差异值得讨论。 -There are things to like about `=>`. You might find that surprising for **me** to say, since most people seem to assume I hate arrow functions. +关于 `=>` 我还是有一些喜爱的,你可能会很惊讶,因为大多数人认为我讨厌箭头函数。 -I don't (hate them). I think there are definitely some important benefits. +我并不讨厌它,我认为箭头函数有一些显而易见且重要的优点。 -It's just that I don't unreservedly endorse them as the new `function`. And these days, most people aren't interested in nuanced opinions in the middle. So since I'm not entirely in the pro-`=>` camp, I must be entirely in the opposition camp. **Not true**. +只是我并不完全地把它们视为颠覆式的 `function`,现如今,大多数人都不在意中间派别细微的意见,所以因为我没有站在支持 => 的阵营,我就站在了反对的阵营。**但其实不是这样的**。 -What I hate is suggesting they're universally more readable, or that they're objectively **better** in basically all cases. +我讨厌的是暗示箭头函数普遍更具可读性,或者,客观来说他们在各种情况下都**更好**的这种行为。 -The reason I reject this stance is because **I REALLY DO STRUGGLE TO READ THEM** in many cases. So that perspective just makes me feel dumb/inferior as a developer. "There must be something wrong with me, since I don't think it's more readable. Why do I suck so much at this?" And I'm not the only one whose impostor syndrome is seriously stoked by such absolutes. +我拒绝这一立场的原因是,在许多情况下,**我阅读这些代码都很吃力**。所以那种观点只会让作为开发人员的我感到愚蠢和自卑 ——「这段代码并没有非常易读,肯定是我有什么问题,为什么我这么菜?」而且,我并不是唯一一个被这种绝对观点严重煽动的[冒名顶替者综合症](https://baike.baidu.com/item/冒名顶替综合症)患者。 -And the cherry on top is when people tell you that the only reason you don't understand or like `=>` is because you haven't learned them or used them enough. Oh, right, thanks for the (condescending) reminder it's due to **my** ignorance and inexperience. SMH. I've written and read literally thousands of `=>`functions. I'm quite certain I know enough about them to hold the opinions I have. +最扯淡的是,人们告诉你,「你不了解或不喜欢 `=>` 的唯一原因是你没有充分地学习和使用它们」。行吧,谢谢(你屈尊的)提醒,我知道这是因为**我的**无知和经验不足了。但其实我内心只想说呵呵。我已经编写并阅读了成千上万个 `=>` 函数。我对它们足够了解,有资格发表意见。 -I'm not in the pro-`=>` camp, but I recognize that some really do prefer them, legitimately. I recognize that some people come to JS from languages that have used `=>` and so they feel and read quite natural. I recognize that some prefer their resemblance to mathematical notation. +我没站在支持 `=>` 的阵营中,但我承认有些人确实喜欢它们,这是合理的。有些人从使用 `=>` 的语言转到 JS,所以他们能非常自然地感知和阅读。有些人还喜欢它们与数学符号的相似性。 -What's problematic IMO is when some in those camps simply cannot understand or empathize with dissenting opinions, as if there must just be something **wrong** with them. +在我看来,有问题的是,某个阵营中的一些人对不同的意见根本无法做到理解或者产生共鸣,就好像提出异议者一定是**有什么东西做得不对**。 -## Readability != Writability +## 好的代码书写体验 != 可读性 -I also don't think **you** know what you're talking about when you talk about code readability. By and large, the vast majority of opinions on code readability, when you break them down, are based on a personal stance about preferences in **writing**concise code. +我也认为**你们**在讨论代码可读性时其实不知道自己在说什么。总的来说,当你把大多数关于代码可读性的观点分解的时候,它们其实都是基于个人对**书写**简洁代码的偏好的看法。 -When I push back in debates about code readability, some just dig in their heels and refuse to support their opinion. Others will waive off the concerns with, "readability is all just subjective anyway". +在关于代码可读性的争论中,当我提出反驳时,有些人只是固执己见,拒绝支持别人的观点。另一些人则会用「可读性只是主观的」来搪塞我的反驳。 -The flimsiness of that response is stunning: two seconds ago they were vehemently claiming `=>` arrow is absolutely and objectively more readable, and then when pressed, they admit, "well, **I** think it's more readable, even if ignorants like you don't." +这种回答之脆弱令人震惊:两秒钟前,他们还在激烈地宣称 `=>` 箭头**绝对地、客观地**更具有可读性,然后当被追问时,他们承认,「行吧,**我**个人认为它更具有可读性,即使像你这样的无知之人不这么认为。」 -Guess what? Readability **is** subjective, **but not entirely so**. It's a really complex topic. And there are some who are undertaking to formally study the topic of code readability, to try to find what parts of it are objective and what parts are subjective. +你猜怎么着?可读性**是**主观的,**但并不完全如此**。这是一个非常复杂的话题。也有一些人开始正式研究代码可读性的话题,试图找出哪些部分是客观的,哪些部分是主观的。 -I have read a fair amount of such research, and I'm convinced that it's a complicated enough topic that it can't be reduced to a slogan on a t-shirt. If you want to read them, I would encourage you doing some google searching and reading of your own. +我读过很多这样的研究,因此我确信这是一个足够复杂的话题,以至于它没法被简化成 T 恤上的 slogan。如果你想了解详情,我建议你自己去谷歌一下。 -While I don't have all the answers myself, one thing I'm certain about is, code is more often read than written, so perspectives on the topic which ultimately come from "it's easier/quicker to write" don't hold much standing. What needs to be considered is, not how much time do you save writing, but how clearly will the reader (future you or someone else on the team) be able to understand? And ideally, can they mostly understand it without pouring over the code with a fine-toothed comb? +虽然我无法完整地回答所有关于可读性的问题,但有一件事我可以肯定的是,代码更多的时候是被阅读而不是被写出来的,所以从「写代码更容易/更快」这个论据出发的论点是站不住脚的。需要考虑的不是你节省了多少写代码的时间,而是读者(未来的你或团队中的其他人)能够多清楚地理解。理想情况下,他们能够在不仔细梳理代码的情况下大致理解代码吗? -Any attempt to justify writability affordances with unsubstantiated claims about readability benefits is a weak argument at best, and in general, nothing but a distraction. +任何试图证明写代码容易就有利于代码可读性的说法都是站不住脚的,总的来说,这只是在混淆视听。 -So I roundly reject that `=>` is always and objectively "more readable". +因此,我坚决反对 `=>` 总是客观地「更具可读性」。 -But I still don't hate arrow functions. I just think to use them effectively, we need to be more disciplined. +但我还是不讨厌箭头函数。我只是认为如果要有效地利用它们,我们需要更加自律。 -## Linters == Discipline +## Linter == 准则 -You might be of the (incorrect) belief that linters tell you objective facts about your code. They **can** do that, but that's not their primary purpose. +您可能(错误地)相信,linter 会告诉您有关代码的客观事实。其实它们**可以**做到这一点,但这不是其主要目的。 -The tool that's best suited to tell you if your code is valid is a compiler (ie, the JS engine). The tool that's best suited to tell you whether your code is "correct" (does what you want it to do) is your test suite. +能告诉您代码是否有效的最佳工具是编译器(即 JS 引擎)。而最适合告诉您代码是否「正确」(满足需求)的工具是测试集。 -But the tool that's best suited to tell you if your code is **appropriate** is a linter. Linters are opinionated collections of rules about how you should style and structure your code, so as to avoid likely problems -- according to the authors of those opinion-based rules. +但是最适合告诉您代码是否**合适**的工具是 linter。根据那些基于观点制订规则的作者的说法,Linter 就是指导你格式化和组织代码的充满主观观点的规则集合,它可以用于避免可能出现的问题。 -That's what they're for: **to apply opinions to your code.** +这就是规则所做的:**在你的代码中应用这些观点。** -That means it's almost certain that these opinions will, at one time or another, "offend" you. If you're like most of us, you fancy yourself pretty good at what you do, and you know that this thing you're doing on this line of code is **right**. And then the linter pops up and says, "Nope, don't do it that way." +几乎可以肯定的是,这些观点会一次又一次地「冒犯」您。如果您像我们大多数人一样,就会出现「幻想自己做得很好,并且认为您在此代码行上所做的事情是**正确**的。然后 linter 跳出来,说:『不,不要那样做。』」的场景。 -If your first instinct is sometimes to disagree, then you're like the rest of us! We get emotionally attached to our own perspectives and abilities, and when a tool tells us we're wrong, we chuff a little bit. +如果有时您的直觉告诉你不要同意 linter 提出的意见,那么您就跟我们其余的人一样了!我们从情感上迷恋自己的观点和能力,并且当某种工具指出我们的错误时,我们就会有点狂躁。 -I don't get mad at the test suite or the JS engine. Those things are all reporting **facts** about my code. But I can definitely get irritated when the linter's **opinion** disagrees with mine. +我不会对测试集或 JS 引擎感到生气。这些东西都是关于我的代码的**事实**。但是当 linter 的**观点**与我的不同时,我就会非常生气。 -I have this one linter rule that I enabled a few weeks ago, because I had an inconsistency in my coding that was annoying me on code re-reads. But now this lint rule is popping up two or three times an hour, nagging me like a stereotypical grandma on a 90's sitcom. Every single time, I ponder (for just a moment) if I should just go disable that rule. I leave it on, but to my chagrin. +我在几周前启用了一个 linter 规则,因为我在重新阅读代码的时候发现有一处让我烦恼的、前后矛盾的地方。但现在,这条 lint 规则每小时会出现两三次,就像 90 年代情景喜剧里典型的老奶奶一样,让我心烦。每一次,我都思考(仅仅是片刻)我是否应该取消这个规则。但最终我让它开着,虽然这令我不爽。 -So why subject ourselves to this torment!? Because linter tools and their opinions are what give us discipline. They help us collaborate with others. +为什么要让我们自己遭受如此痛苦?因为 linter 工具及其观点给我们提供了准则。他们帮助我们更好地与他人协作。 -They ultimately help us communicate more clearly in code. +它们最终帮助我们更清晰地表达代码。 -Why shouldn't we let every developer make their own decisions? Because of our tendency toward emotional attachment. While we're in the trenches working on **our own code**, against unreasonable pressure and deadlines, we're in the least trustable mindset to be making those judgement calls. +我们为什么不让每个开发人员都自己做出决定?因为我们总是倾向于情感依恋。虽然我们写着**自己的代码**,但面对着不合理的压力和期限,我们很可能会以最不值得信赖的心态进行这些判断。 -We should be submitting to tools to help us maintain our discipline. +我们应该听从于帮助我们维护准则的工具。 -It's similar to how TDD advocates submit to the discipline of writing tests first, in a formal set of steps. The discipline and the bigger picture outcome of the process are what we value most, when we're level headed enough to make that analysis. We don't institute that kind of process when our code is hopelessly broken and we have no idea why and we're just resorting to trying random code changes to see if they fix it! +类似于 TDD 倡导的写业务代码前先写测试代码的原则。当我们仔细分析时,会发现我们最看重的是流程的纪律性和全局效果。在代码无法工作、还找不到原因时,我们就只能胡乱挪一挪代码,来看是否能用。在这种情境下,我们是无法建立这样的过程的。 -No. If we're being reasonable, we admit that the **overall good** is best served when we set up reasonable guidelines and then follow the discipline of adhering to them. +讲道理,我们还是要承认,当我们制定了合理的指导方针,然后遵守它们的准则时,**整体利益**会达到最大化。 -## Configurability Is King +## 可配置性为王 -If you're going to knowingly subject yourself to this finger wagging, you (and your team, if applicable) are certainly going to want some say-so in what rules you're required to play by. Arbitrary and unassailable opinions are the worst kind. +如果你有意让自己接受 lint 规则,你(和你的团队,如果有的话)肯定会想要一些发言权 —— 你需要遵守哪些规则。武断和不容置疑的观点是最糟糕的。 -Remember the JSLint days when 98% of the rules were just Crockford's opinions, and you either used the tool or you didn't? He straight up warned you in the README that you were going to be offended, and that you should just get over it. That was fun, right? (Some of you may still be using JSLint, but I think you should consider moving on to a more modern tool!) +还记得 JSLint 么?那里 98% 的规则只是 Crockford 的个人观点,你要么使用这个工具,要么不使用这个工具。他直接在 README 文档中警告你,你会被冒犯,你应该克服它。很有趣,对吧?(有些人可能还在使用 JSLint,但是我认为您应该考虑使用更现代的工具!) -That's why [ESLint is king](https://eslint.org/) of the linters these days. The philosophy is, basically, let everything be configurable. Let developers and teams democratically decide which opinions they all want to submit to, for their own discipline and good. +这就是在当代的 linter 工具中,[ESLint 为王](https://eslint.org/)的原因。其基本思想是,让一切都是可配置的。让开发者和团队从自己的准则和利益出发,自行决定要使用什么样的代码规范。 -That doesn't mean every developer picks their own rules. The purpose of rules is to conform code to a reasonable compromise, a "centralized standard", that has the best chance of communicating most clearly to the most developers on the team. +这不意味着每个开发人员都有自己的规则。规则的目的是使代码符合一个合理的折中方案,即「集中式标准」,这是与团队中大多数开发人员进行最清晰沟通的最佳机会。 -But no rule is ever 100% perfect. There's always exception cases. Which is why having the option to disable or re-configure a rule with an inline comment, for example, is not just a tiny detail but a critical feature. +但是没有任何规则是 100% 完美的。总会有例外情况。所以,使用内联注释来禁用或覆盖规则这一功能不仅仅是一个小特性,还是一个必要功能。 -You don't want a developer to just have their own local ESLint config that overrides rules while they commit code. What you want is for a developer to either follow the established rules (preferred!) **OR** to make an exception to the rules that is clear and obvious right at the point where the exception is being made. +您不希望开发人员通过配置自己本地的 ESLint 规则,来让提交代码时绕过共识规则。您想要的是开发人员要么遵循已建立的规则(首选!),**要么**在破例的地方让这个逃离规则的例外一目了然。 -Ideally, during a code review, that exception can be discussed and debated and vetted. Maybe it was justified, maybe it wasn't. But at least it was obvious, and at least it was possible to be discussed in the first place. +理想情况下,在 code review 期间,可以讨论、审查这些特殊标记。也许这是合理的,也许不是。但至少它是显而易见、可以讨论的。 -Configurability of tools is how we make tools work for us instead of us working for the tools. +工具的可配置性指的是让工具为我们服务,而不是我们为工具服务。 -Some prefer convention-based approaches to tooling, where the rules are pre-determined so there's no discussion or debate. I'm know that works for some developers and for some teams, but I don't think it is a sustainable approach for generalized, broad application. Ultimately, a tool that is inflexible to the changing project needs and DNA of the developer(s) using it, will end up falling into obscurity and eventually replaced. +有些人更喜欢基于约定,而非基于工具,约定的规则是预先确定的,因此没有讨论或辩论。我知道这对一些开发人员和一些团队是有效的,但是我认为这不是一种可以广泛应用、可持续的方法最终,如果一个工具不能灵活地适应不断变化的项目需求、成为开发人员开发过程中重要的一部分,那么它将会变得模糊,并最终被取代。 -## Proper Arrows +## 箭头函数的正当用法 -I fully recognize my usage of the the word "proper" here is going to ruffle some feathers. "Who is getify to say what is proper and not?" +我充分能理解,在这里我使用「正当」这个词会惹怒一些人:「谁有资格说什么是正当的,什么是不正当的?」 -Remember, I'm not trying to tell you what is proper. I'm trying to get you to embrace the idea that opinions about `=>` arrow functions are as varied as all the nuances of their syntax and usage, and that ultimately what is most appropriate is that **some set of opinions**, no matter what they are, should be applicable. +记住,我并不是要告诉你什么是正当的。我想让大家接受这样一个观点,即关于 `=>` 箭头函数的各种观点就像它们的语法和用法的所有细微差别一样,最终最正当的是**一些观点**,不管具体是什么,总归会有一些可应用的观点。 -While I'm a big fan of ESLint, I've been disappointed by the lack of support from built-in ESLint rules for controlling various aspects of `=>` arrow functions. [There](https://eslint.org/docs/rules/arrow-body-style) [are](https://eslint.org/docs/rules/arrow-parens) [a](https://eslint.org/docs/rules/arrow-spacing) [few](https://eslint.org/docs/rules/implicit-arrow-linebreak) built-in rules, but I'm frustrated that they seem to focus mostly on superficial stylistic details like whitespace. +虽然我是 ESLint 的狂热粉丝,但是我对 ESLint 的内置规则无法从各个方面支持 `=>` 箭头函数而感到失望,虽然有[很](https://eslint.org/docs/rules/arrow-body-style)少[的](https://eslint.org/docs/rules/arrow-parens)几[个](https://eslint.org/docs/rules/arrow-spacing)内[置](https://eslint.org/docs/rules/implicit-arrow-linebreak)规则,但我很失望,它们似乎主要关注于表面的风格细节,例如空白符。 -I think there are a number of aspects that can hamper `=>` arrow function readability, issues that go way beyond what the current ESLint ruleset can control. I [asked](https://twitter.com/getify/status/1106902287010709504) around [on twitter](https://twitter.com/getify/status/1106641030273736704), and it seems from the many replies that a lot of people have opinions on this. +我认为有许多方面会妨碍 `=>` 箭头函数的可读性,这些问题远远超出了现有 ESLint 规则集所能控制的范围。我在[推特](https://twitter.com/getify/status/1106641030273736704)上问了[很多人](https://twitter.com/getify/status/1106902287010709504),似乎很多人对此都有看法。 -The ultimate linter would not only let you configure rules to your liking, but build your own rules if something were lacking. Luckily, ESLint supports exactly that! +顶级的 linter 就应该不仅允许您根据自己的喜好配置规则,还可以在缺少某些内容时构造自己的规则。幸运的是,ESLint 完全支持这一点! -So I decided to build an ESLint plugin to define an additional set of rules around `=>` arrow functions: [**proper-arrows**](https://github.com/getify/eslint-plugin-proper-arrows). +因此,我决定开发一个 ESLint 插件来定义一组围绕 `=>` 箭头函数的附加规则:[**proper-arrows**](https://github.com/getify/eslint-plugin-proper-arrows)。 -Before I explain anything about it, let me just point out: it's a set of rules that can be turned on or off, and configured, at your discretion. If you find even one detail of one rule helpful, it would be better to use the rule/plugin than not. +在解释它之前,我要先指出:它是一组规则,您可以自主决定打开或关闭、配置这些规则。如果你发现哪怕有一个规则的一个细节对您有帮助,使用这个规则/插件都是更好的选择。 -I'm fine with you having your own opinions on what makes `=>` arrow functions proper. In fact, that's the whole point. If we all have different opinions on `=>` arrow functions, we should have tooling support to let us pick and configure those different opinions. +我很高兴你对 `=>` 箭头函数有自己的看法。事实上,这才是重点。如果我们都对 `=>` 箭头函数有不同的意见,那么我们应该有工具支持选择和配置这些不同的意见。 -The philosophy of this plugin is that, for each rule, when you turn the rule on, you get all of its reporting modes on by default. But you can of course either not turn the rule on, or turn the rule on and then configure its modes as you see fit. But I don't want you to have to go hunting for rules/modes to turn on, where their obscurity prevents them from even being considered. So **everything comes on per rule.** +这个插件的原理是,对于每个规则,当你打开这个规则时,你会默认打开它的所有报告模式。您可以不打开规则,也可以打开规则,然后根据需要配置它的模式。但我不希望你必须去寻找规则/模式来开启,因为它们的晦涩甚至会阻碍你去考虑它们。所以**每个规则都默认开启**。 -The only exception here is that by default, all rules ignore [trivial `=>` arrow functions](https://github.com/getify/eslint-plugin-proper-arrows#trivial--arrow-functions), like `() => {}`, `x => x`, etc. If you want those to be checked, on a per-rule basis you have to turn on that checking with the `{ "trivial": true }` option. +唯一的例外是,在默认情况下,所有的规则都忽略了[简单的 `=>` 箭头函数](https://github.com/getify/eslint-plugin-proper-arrows#trivial--arrow-functions),比如 `()=> {}`、`x => x`等。如果您想要检查它们,那么您必须在每个规则的基础上使用 `{ "trivial": true }` 选项打开检查。 -### Proper Arrows Rules +### 具体规则 -So what rules are provided? Here's an [excerpt from the project overview](https://github.com/getify/eslint-plugin-proper-arrows/blob/master/README.md#overview): +那么具体提供了哪些规则呢?以下是[对项目概述的摘录](https://github.com/getify/eslint-plugin-proper-arrows/blob/master/README.md#overview): -* [`"params"`](https://github.com/getify/eslint-plugin-proper-arrows/blob/master/README.md#rule-params): controls definitions of `=>` arrow function parameters, such as forbidding unused parameters, forbidding short/unsemantic parameter names, etc. -* [`"name"`](https://github.com/getify/eslint-plugin-proper-arrows/blob/master/README.md#rule-name): requires `=>` arrow functions to only be used in positions where they receive an inferred name (i.e., assigned to a variable or property, etc), to avoid the poor readbility/debuggability of anonymous function expressions. -* [`"where"`](https://github.com/getify/eslint-plugin-proper-arrows/blob/master/README.md#rule-where): restricts where in program structure `=>` arrow functions can be used: forbidding them in the top-level/global scope, object properties, `export` statements, etc. -* [`"return"`](https://github.com/getify/eslint-plugin-proper-arrows/blob/master/README.md#rule-return): restricts the concise return value kind for `=>` arrow functions, such as forbidding object literal concise returns (`x => ({ x })`), forbidding concise returns of conditional/ternary expressions (`x => x ? y : z`), etc. -* [`"this"`](https://github.com/getify/eslint-plugin-proper-arrows/blob/master/README.md#rule-this): requires/disallows `=>` arrow functions using a `this` reference, in the `=>` arrow function itself or in a nested `=>` arrow function. This rule can optionally forbid `this`-containing `=>` arrow functions from the global scope. +* [`"params"`](https://github.com/getify/eslint-plugin-proper-arrows/blob/master/README.md#rule-params):控制 `=>` 箭头函数参数的定义,例如禁止未使用的参数,禁止短/无语义的参数名称等。 +* [`"name"`](https://github.com/getify/eslint-plugin-proper-arrows/blob/master/README.md#rule-name):要求仅在接收到推断名称的位置使用 `=>` 箭头函数(即分配给变量或属性等),以避免匿名函数表达式的不可读/可调试性。 +* [`"where"`](https://github.com/getify/eslint-plugin-proper-arrows/blob/master/README.md#rule-where):限制可以在程序结构中使用 `=>` 箭头函数的位置:禁止在顶级/全局作用域、对象属性、`export` 语句等地方使用。 +* [`"return"`](https://github.com/getify/eslint-plugin-proper-arrows/blob/master/README.md#rule-return):限制 `=>` 箭头函数的简明返回值类型,例如禁止对象文字简明返回(`x => ({ x })`)、禁止条件/三元表达式的简明返回(`x => x ? y : z`)等。 +* [`"this"`](https://github.com/getify/eslint-plugin-proper-arrows/blob/master/README.md#rule-this):要求/禁止 `=>` 箭头函数在 `=>` 箭头函数自身或嵌套 `=>` 箭头函数中使用 `this` 引用,该规则可以有选择地禁止全局作用域使用带 `this` 的 `=>` 箭头函数。 -Remember, each rule has various modes to configure, so none of this is all-or-nothing. Pick what works for you. +请记住,每个规则都有不同的模式可供配置,所以这些并非全有或全无的。选择你需要的即可。 -As an illustration of what the **proper-arrows** rules can check for, let's look at the [`"return"` rule](https://github.com/getify/eslint-plugin-proper-arrows/blob/master/README.md#rule-return), specifically its [`"sequence"` mode](https://github.com/getify/eslint-plugin-proper-arrows/blob/master/README.md#rule-return-configuration-sequence). This mode refers to the concise return expression of `=>` arrow functions being a comma-separated **sequence**, like this: +为了示意 **proper-arrows** 规则可以检查什么,让我们看看 [`"return"` 规则](https://github.com/getify/eslint-plugin-proper-arrows/blob/master/README.md#rule-return),特别是它的 [`"sequence"` 模式](https://github.com/getify/eslint-plugin-proper-arrows/blob/master/README.md#rule-return-configuration-sequence)。这种模式将 `=>` 箭头函数的简洁返回表达式表示为逗号分隔的序列,如下所示: ```JavaScript var myfunc = (x,y) => ( x = 3, y = foo(x + 1), \[x,y\] ); ``` -Sequences are typically used in `=>` arrow function concise returns to string together multiple (expression) statements, without needing to use a full `{ .. }` delimited function body and an explicit `return` statement. +Sequences 通常用于 `=>` 箭头函数的简洁返回结果中,从而将多个(表达式)语句串在一起,而不需要使用完整的 `{ .. }` 分隔函数体和显式的 `return` 语句。 -Some may love this style -- that's OK! -- but a lot of folks think it favors clever terse style coding over readability, and would prefer instead: +有些人可能喜欢这种风格,这没问题!不过还有很多人更倾向于可读性而不是更简洁的代码,他们更喜欢: ```JavaScript var fn2 = (x,y) => { x = 3; y = foo(x + 1); return \[x,y\]; }; ``` -Notice that it's still an `=>` arrow function and it's not even that many more characters. But it's clearer that there are three separate statements in this function body. +请注意,它仍然是一个 `=>` 箭头函数,其实也并没有多出几个字符。但这样可以更清楚的看到,此函数体中包含三个单独的语句。 -Even better: +更好的做法: ```JavaScript var fn2 = (x,y) => { @@ -188,24 +188,24 @@ var fn2 = (x,y) => { }; ``` -To be clear, the **proper-arrows** rules don't enforce trivial styling differences like whitespace/indentation. There are other (built-in) rules if you want to enforce those requirements. **proper-arrows** focuses on what I consider to be more substantive aspects of `=>` function definition. +需要明确的是, **proper-arrows** 规则不会对琐碎的样式差异进行强制,例如空格/缩进。如果要对这类差异进行统一,可以结合使用其它( ESLint 内置)规则。 **proper-arrows** 规则专注于有关于 `=>` 箭头函数的更实质性的内容。 -## [](https://gist.github.com/getify/71680e9b86cd4895874f6a3768bd6eca#concise-summary)Concise Summary +## 简要总结 -You and I almost certainly disagree on what makes **good, proper** `=>` arrow function style. That's a good and healthy thing. +针对「什么才能造就**良好、正确**的 `=>` 箭头函数的样式」这件事,您和我一定有不不同的意见。这是一件正常不过的事情。 -My goal here is two-fold: +我有两个目标: -1. Convince you that opinions on this stuff vary and that's OK. -2. Enable you to make and enforce your own opinions (or team consensus) with configurable tooling. +1. 说服您:对这些东西的看法不同是没关系的。 +2. 使您能够使用可配置的工具来制定并推行自己的观点(或团队共识)。 -There's really nothing to be gained from arguing over opinion-based rules. Take the ones you like, forget the ones you don't. +争论基于意见的规则确实没有任何收获。选择您喜欢的,忘记您不喜欢的就够了。 -I hope you take a look at **[proper-arrows](https://github.com/getify/eslint-plugin-proper-arrows)**[ ](https://github.com/getify/eslint-plugin-proper-arrows)and see if there's anything in there which you could use to ensure your `=>` arrow functions are the best form they can be in your code base. +我希望您看一下 [**proper-arrows**](https://github.com/getify/eslint-plugin-proper-arrows),然后看看有没有哪些规则可以为您所用,让您的 `=>` 箭头函数符合您心目中代码的正确形式。 -And if the plugin is missing some rules that would help define more **proper arrows**, please [file an issue and we can discuss](https://github.com/getify/eslint-plugin-proper-arrows/issues)! It's entirely plausible we may add that rule/mode, ****even if I personally plan to keep it turned off!**** +如果这个插件缺少一些有助于定义更多正确箭头的规则,请[提出 issue,咱们一起讨论](https://github.com/getify/eslint-plugin-proper-arrows/issues)!我们完全有可能添加该规则/模式,尽管我个人并不打算开启该规则! -I don't hate `=>` arrow functions, and you shouldn't either. I just hate uninformed and undisciplined debate. Let's embrace smarter and more configurable tooling and move on to more important topics! +我不讨厌 `=>` 箭头函数,您也不应该。我只是讨厌无知无纪的争辩。让我们拥抱更智能,可配置性更强的工具,然后转向更重要的主题吧! > 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 From 28c79b4bd884bf828947aa869a16b4bbbdb4cb3e Mon Sep 17 00:00:00 2001 From: niayyy Date: Sat, 28 Mar 2020 08:40:50 +0800 Subject: [PATCH 06/54] =?UTF-8?q?=E6=8E=8C=E6=8F=A1=20JavaScript=20?= =?UTF-8?q?=E9=9D=A2=E8=AF=95=EF=BC=9A=E4=BB=80=E4=B9=88=E6=98=AF=E7=BA=AF?= =?UTF-8?q?=E5=87=BD=E6=95=B0=EF=BC=9F=20(#6828)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 掌握 JavaScript 面试:什么是纯函数? 掌握 JavaScript 面试:什么是纯函数? * Update master-the-javascript-interview-what-is-a-pure-function.md * Update master-the-javascript-interview-what-is-a-pure-function.md * Update master-the-javascript-interview-what-is-a-pure-function.md * Update master-the-javascript-interview-what-is-a-pure-function.md * Update master-the-javascript-interview-what-is-a-pure-function.md * Update master-the-javascript-interview-what-is-a-pure-function.md * Update master-the-javascript-interview-what-is-a-pure-function.md Co-authored-by: lsvih --- ...cript-interview-what-is-a-pure-function.md | 201 +++++++++--------- 1 file changed, 97 insertions(+), 104 deletions(-) diff --git a/TODO1/master-the-javascript-interview-what-is-a-pure-function.md b/TODO1/master-the-javascript-interview-what-is-a-pure-function.md index cb94a7cd35f..664f3fa5c4b 100644 --- a/TODO1/master-the-javascript-interview-what-is-a-pure-function.md +++ b/TODO1/master-the-javascript-interview-what-is-a-pure-function.md @@ -2,163 +2,163 @@ > * 原文作者:[Eric Elliott](https://medium.com/@_ericelliott) > * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) > * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/TODO1/master-the-javascript-interview-what-is-a-pure-function.md](https://github.com/xitu/gold-miner/blob/master/TODO1/master-the-javascript-interview-what-is-a-pure-function.md) -> * 译者: -> * 校对者: +> * 译者:[niayyy-S](https://github.com/niayyy-S) +> * 校对者:[chaingangway](https://github.com/chaingangway)、[IAMSHENSH](https://github.com/IAMSHENSH) -# Master the JavaScript Interview: What is a Pure Function? +# 掌握 JavaScript 面试:什么是纯函数? ![Image: Pure — carnagenyc (CC-BY-NC 2.0)](https://cdn-images-1.medium.com/max/2048/1*gF8oCkYNvktBbAAG-nxYrg.jpeg) -Pure functions are essential for a variety of purposes, including functional programming, reliable concurrency, and React+Redux apps. But what does “pure function” mean? +纯函数对于实现各种目的是必不可少的,包括函数式编程,可靠地并发和 React + Redux 构造的应用程序。但是纯函数是什么意思? -We’re going to answer this question with a free lesson from [“Learn JavaScript with Eric Elliott”](http://ericelliottjs.com/product/lifetime-access-pass/): +我们将通过来自 [《跟 Eric Elliott 学习 JavaScript》](http://ericelliottjs.com/product/lifetime-access-pass/) 的免费课程来回答的这个问题: -Before we can tackle what a pure function is, it’s probably a good idea to take a closer look at functions. There may be a different way to look at them that will make functional programming easier to understand. +在我们解决什么是纯函数这个问题之前,仔细研究一下什么是函数可能更好。也许存在一种不一样的看待函数的方式,会让函数式编程更易于理解。 -#### What is a Function? +#### 什么是函数? -A **function** is a process which takes some input, called **arguments**, and produces some output called a **return value**. Functions may serve the following purposes: +**函数**是一个过程:它需要一些叫做**参数**的输入,然后产生一些叫做**返回值**的输出。函数可以用于以下目的: -* **Mapping:** Produce some output based on given inputs. A function **maps** input values to output values. -* **Procedures:** A function may be called to perform a sequence of steps. The sequence is known as a procedure, and programming in this style is known as **procedural programming**. -* **I/O:** Some functions exist to communicate with other parts of the system, such as the screen, storage, system logs, or network. +* **映射:**基于输入值产生一些的输出。函数把输入值**映射到**输出值。 +* **过程化:**可以调用一个函数去执行一系列步骤。该一系列步骤称为过程,而这种方式的编程称为**面向过程编程**。 +* **I/O:**一些函数存在与系统其他部分进行通信,例如屏幕,存储,系统日志或网络。 -#### Mapping +#### 映射 -Pure functions are all about mapping. Functions map input arguments to return values, meaning that for each set of inputs, there exists an output. A function will take the inputs and return the corresponding output. +纯函数都是关于映射的。函数将输入参数映射到返回值,这意味着对于每组输入,都存在对应的输出。函数将获取输入并返回相应的输出。 -**`Math.max()`** takes numbers as arguments and returns the largest number: +**`Math.max()`** 以一组数字作为参数并返回最大数字: -``` +```js Math.max(2, 8, 5); // 8 ``` -In this example, 2, 8, & 5 are **arguments**. They’re values passed into the function. +在此示例中,2,8 和 5 是**参数**。它们是传递给函数的值。 -**`Math.max()`** is a function that takes any number of arguments and returns the largest argument value. In this case, the largest number we passed in was 8, and that’s the number that got returned. +**`Math.max()`** 是一个可以接受任意数量的参数并返回最大参数值的函数。在这个案例中,我们传入的最大数是 8,对应了返回的数字。 -Functions are really important in computing and math. They help us process data in useful ways. Good programmers give functions descriptive names so that when we see the code, we can see the function names and understand what the function does. +函数在计算和数学中非常重要。它们帮助我们用合适的方式处理数据。好的程序员会给函数起描述性的名称,以便当我们查看代码时,我们可以通过函数名了解函数的作用。 -Math has functions, too, and they work a lot like functions in JavaScript. You’ve probably seen functions in algebra. They look something like this: +数学也有函数,它们的工作方式与 JavaScript 中的函数非常相似。您可能见过代数函数。他们看起来像这样: **f**(**x**) = 2**x** -Which means that we’re declaring a function called f and it takes an argument called x and multiplies x by 2. +这意味着我们要声明了一个名为 f 的函数,它接受一个叫 x 的参数并将 x 乘以 2。 -To use this function, we simply provide a value for x: +要使用这个函数,我们只需为 x 提供一个值: **f**(2) -In algebra, this means exactly the same thing as writing: +在代数中,这意味着与下面的写法完全相同: 4 -So any place you see **f**(2) you can substitute 4. +因此,在任何看到 **f**(2) 的地方都可以替换 4。 -Now let’s convert that function to JavaScript: +现在让我们用 JavaScript 来描述这个函数: -``` +```js const double = x => x * 2; ``` -You can examine the function’s output using **`console.log()`**: +你可以使用 **`console.log()`** 检查函数输出: -``` +```js console.log( double(5) ); // 10 ``` -Remember when I said that in math functions, you could replace **`f(2)`** with **`4`**? In this case, the JavaScript engine replaces **`double(5)`** with the answer, **`10`**. +还记得我说过的在数学函数中,你可以替换 **`f(2)`** 为 **`4`** 吗?在这种情况下,JavaScript 引擎用 **`10`** 替换 **`double(5)`**。 -So, **`console.log( double(5) );`** is the same as **`console.log(10);`** +因此, **`console.log( double(5) );`** 与 **`console.log(10);`** 相同 -This is true because **`double()`** is a pure function, but if **`double()`** had side-effects, such as saving the value to disk or logging to the console, you couldn’t simply replace **`double(5)`** with 10 without changing the meaning. +这是真实存在的,因为 **`double()`** 是一个纯函数,但是如果 **`double()`** 有副作用,例如将值保存到磁盘或打印到控制台,用 10 替换 **`double(5)`** 会改变函数的含义。 -If you want referential transparency, you need to use pure functions. +如果想要引用透明,则需要使用纯函数。 -#### Pure Functions +#### 纯函数 -A **pure function** is a function which: +**纯函数**是一个函数,其中: -* Given the same input, will always return the same output. -* Produces no side effects. +* 给定相同的输入,将始终返回相同的输出。 +* 无副作用。 -> A dead giveaway that a function is impure is if it makes sense to call it without using its return value. For pure functions, that’s a noop. +> 如果你合理调用一个函数,而没有使用它的返回值,则毫无疑问不是纯函数。对于纯函数来说,相当于未进行调用。 -I recommend that you favor pure functions. Meaning, if it is practical to implement a program requirement using pure functions, you should use them over other options. Pure functions take some input and return some output based on that input. They are the simplest reusable building blocks of code in a program. Perhaps the most important design principle in computer science is KISS (Keep It Simple, Stupid). I prefer Keep It Stupid Simple. Pure functions are stupid simple in the best possible way. +我建议你偏向于使用纯函数。意思是,如果使用纯函数实现程序需求是可行的,应该优先选择使用。纯函数接受一些输入,并根据输入返回一些输出。它们是程序中最简单的可重用代码块。也许计算机科学中最重要的设计原理是 KISS(保持简单明了)。我更喜欢保持傻瓜式的简单。纯函数是傻瓜式简单的最佳方式。 -Pure functions have many beneficial properties, and form the foundation of **functional programming**. Pure functions are completely independent of outside state, and as such, they are immune to entire classes of bugs that have to do with shared mutable state. Their independent nature also makes them great candidates for parallel processing across many CPUs, and across entire distributed computing clusters, which makes them essential for many types of scientific and resource-intensive computing tasks. +纯函数具有许多有益的特性,并构成了**函数式编程**的基础。纯函数完全独立于外部状态,因此,它们不受所有与共享可变状态有关问题的影响。它们的独立特性也使其成为跨多个 CPU 以及整个分布式计算集群进行并行处理的极佳选择,这使其对许多类型的科学和资源密集型计算任务至关重要。 -Pure functions are also extremely independent — easy to move around, refactor, and reorganize in your code, making your programs more flexible and adaptable to future changes. +纯函数也是非常独立的 —— 在代码中可以轻松移动,重构以及重组,使程序更灵活并能够适应将来的更改。 -#### The Trouble with Shared State +#### 共享状态问题 -Several years ago I was working on an app that allowed users to search a database for musical artists and load the artist’s music playlist into a web player. This was around the time Google Instant landed, which displays instant search results as you type your search query. AJAX-powered autocomplete was suddenly all the rage. +几年前,我正在开发一个应用程序,该程序允许用户搜索音乐艺术家的数据库并将该艺术家的音乐播放列表加载到 web 播放器中。大约在 Google Instant 上线的那个时候,当输入搜索查询时,它会显示即时搜索结果。AJAX 驱动的自动完成功能风靡一时。 -The only problem was that users often type faster than an API autocomplete search response can be returned, which caused some strange bugs. It would trigger race conditions, where newer suggestions would be replaced by outdated suggestions. +唯一的问题是,用户输入的速度通常快于 API 的自动完成搜索并返回响应的速度,从而导致一些奇怪的错误。这将触发竞争条件(race condition),在此情况下,较新的结果可能会被过期的所取代。 -Why did that happen? Because each AJAX success handler was given access to directly update the suggestion list that was displayed to users. The slowest AJAX request would always win the user’s attention by blindly replacing results, even when those replaced results may have been newer. +为什么会这样呢?因为每个 AJAX 成功处理程序都有权直接更新显示给用户的建议列表。最慢的 AJAX 请求总是可以通过盲目替换获得用户的注意,即使这些替换的结果可能是较新的。 -To fix the problem, I created a suggestion manager — a single source of truth to manage the state of the query suggestions. It was aware of a currently pending AJAX request, and when the user typed something new, the pending AJAX request would be canceled before a new request was issued, so only a single response handler at a time would ever be able to trigger a UI state update. +为了解决这个问题,我创建了一个建议管理器 —— 一个单一数据源去管理查询建议的状态。它知道当前有一个待处理的 AJAX 请求,并且当用户输入新内容时,这个待处理的 AJAX 请求将在发出新请求之前被取消,因此一次只有一个响应处理程序将能够触发 UI 状态更新。 -Any sort of asynchronous operation or concurrency could cause similar race conditions. Race conditions happen if output is dependent on the sequence of uncontrollable events (such as network, device latency, user input, randomness, etc…). In fact, if you’re using shared state and that state is reliant on sequences which vary depending on indeterministic factors, for all intents and purposes, the output is impossible to predict, and that means it’s impossible to properly test or fully understand. As Martin Odersky (creator of Scala) puts it: +任何种类的异步操作或并发都可能导致类似的竞争条件。如果输出取决于不可控事件的顺序(例如网络,设备延迟,用户输入,随机性等),则会发生竞争条件。实际上,如果你正在使用共享状态,并且该状态依赖于一系列不确定性因素,总而言之,输出都是无法预测的,这意味着无法正确测试或完全理解。正如 Martin Odersky(Scala 语言的创建者)所说: -> **non-determinism = parallel processing + mutable state** +> **不确定性 = 并行处理 + 可变状态** -Program determinism is usually a desirable property in computing. Maybe you think you’re OK because JS runs in a single thread, and as such, is immune to parallel processing concerns, but as the AJAX example demonstrates, a single threaded JS engine does not imply that there is no concurrency. On the contrary, there are many sources of concurrency in JavaScript. API I/O, event listeners, web workers, iframes, and timeouts can all introduce indeterminism into your program. Combine that with shared state, and you’ve got a recipe for bugs. +程序的确定性通常是计算中的理想属性。可能你认为还好,因为 JS 在单线程中运行,因此不受并行处理问题的影响,但是正如 AJAX 示例所示,单线程JS引擎并不意味着没有并发。相反,JavaScript 中有许多并发来源。API I/O,事件侦听,Web Worker,iframe 和超时都可以将不确定性引入程序中。将其与共享状态结合起来,就可以得出解决 bug 的方法。 -Pure functions can help you avoid those kinds of bugs. +纯函数可以帮助你避免这些 bug。 -#### Given the Same Input, Always Return the Same Output +#### 给定相同的输入,始终返回相同的输出 -With our **`double()`** function, you can replace the function call with the result, and the program will mean the same thing — **`double(5)`** will always mean the same thing as **`10`** in your program, regardless of context, no matter how many times you call it or when. +使用上面的 **`double()`** 函数,你可以用结果替换函数调用,程序仍然具有相同的含义 —— **`double(5)`** 始终与程序中的 **`10`** 具有相同含义,而不管上下文如何,无论调用它多少次或何时调用。 -But you can’t say the same thing about all functions. Some functions rely on information other than the arguments you pass in to produce results. +但是你不能对所有函数都这么认为。某些函数依赖于你传入的参数以外的信息来产生结果。 -Consider this example: +考虑以下示例: -``` +```js Math.random(); // => 0.4011148700956255 Math.random(); // => 0.8533405303023756 Math.random(); // => 0.3550692005082965 ``` -Even though we didn’t pass any arguments into any of the function calls, they all produced different output, meaning that **`Math.random()`** is **not pure**. +尽管我们没有传递任何参数到任何函数调用的,他们都产生了不同的输出,这意味着 **`Math.random()`** 是**不是纯函数**。 -**`Math.random()`** produces a new random number between 0 and 1 every time you run it, so clearly you couldn’t just replace it with 0.4011148700956255 without changing the meaning of the program. +**`Math.random()`** 每次运行时,都会产生一个介于 0 和 1 之间的新随机数,因此很明显,你不能只用 0.4011148700956255 替换它而不改变程序的含义。 -That would produce the same result every time. When we ask the computer for a random number, it usually means that we want a different result than we got the last time. What’s the point of a pair of dice with the same numbers printed on every side? +那将每次都会产生相同的结果。当我们要求计算机产生一个随机数时,通常意味着我们想要一个与上次不同的结果。每一面都印着相同数字的一对骰子有什么意义呢? -Sometimes we have to ask the computer for the current time. We won’t go into the details of how the time functions work. For now, just copy this code: +有时我们必须询问计算机当前时间。我们不会详细地了解时间函数的工作原理。只需复制以下代码: -``` +```js const time = () => new Date().toLocaleTimeString(); time(); // => "5:15:45 PM" ``` -What would happen if you replaced the **`time()`** function call with the current time? +如果用当前时间取代 **`time()`** 函数的调用会发生什么? -It would always say it’s the same time: the time that the function call got replaced. In other words, it could only produce the correct output once per day, and only if you ran the program at the exact moment that the function got replaced. +它总是输出相同的时间:这个函数调用被替换的时间。换句话说,它只能每天产生一次正确的输出,并且仅当你在替换函数的确切时刻运行程序时才可以。 -So clearly, **`time()`** isn’t like our **`double()`** function. +很明显,**`time()`** 不像 **`double()`** 函数。 -**A function is only pure if, given the same input, it will always produce the same output**. You may remember this rule from algebra class: the same input values will always map to the same output value. However, many input values may map to the same output value. For example, the following function **is pure**: +**如果函数在给定相同的输入的情况下始终产生相同的输出,则该函数是纯函数**。你可能还记得代数课上的这个规则:相同的输入值将始终映射到相同的输出值。但是,许多输入值可能会映射到相同的输出值。例如,以下函数是**纯函数**: -``` +```js const highpass = (cutoff, value) => value >= cutoff; ``` -The same input values will always map to the same output value: +相同的输入值将始终映射到相同的输出值: -``` +```js highpass(5, 5); // => true highpass(5, 5); // => true highpass(5, 5); // => true ``` -Many input values may map to the same output value: +许多输入值可能映射到相同的输出值: -``` +```js highpass(5, 123); // true highpass(5, 6); // true highpass(5, 18); // true @@ -168,20 +168,20 @@ highpass(5, 3); // false highpass(5, 4); // false ``` -A pure function must not rely on any external mutable state, because it would no longer be deterministic or referentially transparent. +纯函数一定不能依赖任何外部可变状态,因为它不再是确定性的或引用透明的。 -## Pure Functions Produce No Side Effects +## 纯函数不会产生副作用 -A pure function produces no side effects, which means that it can’t alter any external state. +纯函数不会产生任何副作用,意味着它无法更改任何外部状态。 -## Immutability +## 不变性 -JavaScript’s object arguments are references, which means that if a function were to mutate a property on an object or array parameter, that would mutate state that is accessible outside the function. Pure functions must not mutate external state. +JavaScript 的对象参数是引用的,这意味着如果函数更改对象或数组参数上的属性,则将使该函数外部可访问的状态发生变化。纯函数不得改变外部状态。 -Consider this mutating, **impure** **`addToCart()`** function: +考虑一下这种改变的,**不纯的** **`addToCart()`** 函数: ```JavaScript -// impure addToCart mutates existing cart +// 不纯的 addToCart 函数改变了现有的 cart 对象 const addToCart = (cart, item, quantity) => { cart.items.push({ item, @@ -205,7 +205,7 @@ test('addToCart()', assert => { 1 ); - const expected = 1; // num items in cart + const expected = 1; // cart 中的商品数 const actual = cart.items.length; assert.equal(actual, expected, msg); @@ -216,15 +216,15 @@ test('addToCart()', assert => { ``` -It works by passing in a cart, and item to add to that cart, and an item quantity. The function then returns the same cart, with the item added to it. +这个函数通过传递 cart 对象,添加商品和商品数量到 cart 对象上来调用的。然后,该函数返回相同的 cart 对象,并添加了商品。 -The problem with this is that we’ve just mutated some shared state. Other functions may be relying on that cart object state to be what it was before the function was called, and now that we’ve mutated that shared state, we have to worry about what impact it will have on the program logic if we change the order in which functions have been called. Refactoring the code could result in bugs popping up, which could screw up orders, and result in unhappy customers. +这样做的问题是,我们刚刚改变了一些共享状态。其他函数可能依赖于 cart 对象状态 —— 被该函数调用之前的状态,而现在我们已经更改了这个共享状态,如果我们改变函数调用的顺序,我们不得不担心将会对程序逻辑上产生怎样的影响。重构代码可能会导致 bug 出现,从而可能破坏订单并导致客户不满意。 -Now consider this version: +现在考虑这个版本: ```JavaScript -// Pure addToCart() returns a new cart -// It does not mutate the original. +// 纯 addToCart() 函数返回一个新的 cart 对象 +// 这不会改变原始对象 const addToCart = (cart, item, quantity) => { const newCart = lodash.cloneDeep(cart); @@ -243,8 +243,8 @@ test('addToCart()', assert => { items: [] }; - // deep-freeze on npm - // throws an error if original is mutated + // npm 上的 deep-freeze + // 如果原始对象被改变,则抛出一个错误 deepFreeze(originalCart); const cart = addToCart( @@ -257,7 +257,7 @@ test('addToCart()', assert => { ); - const expected = 1; // num items in cart + const expected = 1; // cart 中的商品数 const actual = cart.items.length; assert.equal(actual, expected, msg); @@ -269,36 +269,29 @@ test('addToCart()', assert => { ``` -In this example, we have an array nested in an object, which is why I reached for a deep clone. This is more complex state than you’ll typically be dealing with. For most things, you can break it down into smaller chunks. - -For example, Redux lets you compose reducers rather than deal with the entire app state inside each reducer. The result is that you don’t have to create a deep clone of the entire app state every time you want to update just a small part of it. Instead, you can use non-destructive array methods, or **`Object.assign()`** to update a small part of the app state. +在此示例中,我们在对象中嵌套了一个数组,这是我要进行深克隆的原因。这比你通常要处理的状态更为复杂。对于大多数事情,你可以将其分解为较小的块。 -Your turn. [Fork this pen](http://codepen.io/ericelliott/pen/MyojLq?editors=0010) and change the impure functions into pure functions. Make the unit tests pass without changing the tests. +例如,Redux 让你可以组成 reducers,而不是在每个 reducers 中的解决整个应用程序状态。结果是,你不必每次更新整个应用程序状态的一小部分时就创建一个深克隆。相反,你可以使用非破坏性数组方法,或 **`Object.assign()`** 更新应用状态的一小部分。 -#### Explore the Series +轮到你了。[Fork 这个 codepen 代码](http://codepen.io/ericelliott/pen/MyojLq?editors=0010),并将非纯函数转换为纯函数。使单元测试通过而不更改测试。 -* [What is a Closure?](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-closure-b2f0d2152b36#.ecfskj935) -* [What is the Difference Between Class and Prototypal Inheritance?](https://medium.com/javascript-scene/master-the-javascript-interview-what-s-the-difference-between-class-prototypal-inheritance-e4cd0a7562e9#.h96dymht1) -* [What is a Pure Function?](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-pure-function-d1c076bec976#.4256pjcfq) -* [What is Function Composition?](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-function-composition-20dfb109a1a0#.i84zm53fb) -* [What is Functional Programming?](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-functional-programming-7f218c68b3a0#.jddz30xy3) -* [What is a Promise?](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-promise-27fc71e77261#.aa7ubggsy) -* [Soft Skills](https://medium.com/javascript-scene/master-the-javascript-interview-soft-skills-a8a5fb02c466) - -> This post was included in the book “Composing Software”.**[ -Buy the Book](https://leanpub.com/composingsoftware) | [Index](https://medium.com/javascript-scene/composing-software-the-book-f31c77fc3ddc) | [\< Previous](https://medium.com/javascript-scene/why-learn-functional-programming-in-javascript-composing-software-ea13afc7a257) | [Next >](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-functional-programming-7f218c68b3a0)** - ---- +#### 探索这个系列 -## Learn More at EricElliottJS.com +* [什么是闭包?](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-closure-b2f0d2152b36#.ecfskj935) +* [类和原型继承有什么区别?](https://medium.com/javascript-scene/master-the-javascript-interview-what-s-the-difference-between-class-prototypal-inheritance-e4cd0a7562e9#.h96dymht1) +* [什么是纯函数?](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-pure-function-d1c076bec976#.4256pjcfq) +* [函数由什么构成?](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-function-composition-20dfb109a1a0#.i84zm53fb) +* [什么是函数式编程?](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-functional-programming-7f218c68b3a0#.jddz30xy3) +* [什么是 Promise ?](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-promise-27fc71e77261#.aa7ubggsy) +* [软技能](https://medium.com/javascript-scene/master-the-javascript-interview-soft-skills-a8a5fb02c466) -Video lessons with interactive code challenges are available for members of EricElliottJS.com. If you’re not a member, [sign up today](https://ericelliottjs.com/). +> 该帖子已包含在《Composing Software》书中。**[ 买这本书](https://leanpub.com/composingsoftware) | [索引](https://medium.com/javascript-scene/composing-software-the-book-f31c77fc3ddc) | [<上一页](https://medium.com/javascript-scene/why-learn-functional-programming-in-javascript-composing-software-ea13afc7a257) | [下一页>](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-functional-programming-7f218c68b3a0)** --- -****Eric Elliott** is a distributed systems expert and author of the books, [“Composing Software”](https://leanpub.com/composingsoftware) and [“Programming JavaScript Applications”](https://ericelliottjs.com/product/programming-javascript-applications-ebook/). As co-founder of [DevAnywhere.io](https://devanywhere.io/), he teaches developers the skills they need to work remotely and embrace work/life balance. He builds and advises development teams for crypto projects, and 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)** 是一名分布式系统专家,并且是[《Composing Software》](https://leanpub.com/composingsoftware)和[《Programming JavaScript Applications》](https://ericelliottjs.com/product/programming-javascript-applications-ebook/)这两本书的作者。作为 [DevAnywhere.io](https://devanywhere.io/) 的联合创始人,他教开发人员远程工作和实现工作 / 生活平衡所需的技能。他建立并为加密项目的开发团队提供咨询,并为 **Adobe 公司、Zumba Fitness、《华尔街日报》、ESPN、BBC** 和包括 **Usher、Frank Ocean、Metallica** 在内的顶级唱片艺术家的软件体验做出了贡献。 -**He enjoys a remote lifestyle with the most beautiful woman in the world.** +**他与世界上最美丽的女人一起享受着远程办公的生活方式。** > 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 From 57bd9bdb9535494efb77b41071b4a068d2cb55d9 Mon Sep 17 00:00:00 2001 From: zoomdong <1344492820@qq.com> Date: Sat, 28 Mar 2020 21:15:59 +0800 Subject: [PATCH 07/54] =?UTF-8?q?fix:=E6=96=87=E7=AB=A0=E7=BF=BB=E8=AF=91?= =?UTF-8?q?=E9=97=AE=E9=A2=98=20(#6833)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TODO/the-hidden-treasures-of-object-composition.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TODO/the-hidden-treasures-of-object-composition.md b/TODO/the-hidden-treasures-of-object-composition.md index b44d69479c6..85dc6336e7a 100644 --- a/TODO/the-hidden-treasures-of-object-composition.md +++ b/TODO/the-hidden-treasures-of-object-composition.md @@ -18,7 +18,7 @@ > > “优先考虑对象组合而不是类继承。” ~ Gang of Four,[《设计模式:可复用面向对象软件的基础》](https://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612//ref=as_li_ss_tl?ie=UTF8&linkCode=ll1&tag=eejs-20&linkId=06ccc4a53e0a9e5ebd65ffeed9755744) -软件开发中最常见的错误之一就是对于类继承的过度使用。类继承是一个代码复用机制,实例对象和基类构成了 **是一个(is-a)**关系。如果你想要使用 is-a 关系来构建应用程序,你将陷入麻烦,因为在面向对象设计中,类继承是最紧的耦合形式,这种耦合会引起下面这些常见问题: +软件开发中最常见的错误之一就是对于类继承的过度使用。类继承是一个代码复用机制,实例对象和基类构成了 **is-a** 关系。如果你想要使用 is-a 关系来构建应用程序,你将陷入麻烦,因为在面向对象设计中,类继承是最紧的耦合形式,这种耦合会引起下面这些常见问题: * 脆弱的基类问题 * 猩猩/香蕉问题 From 95eec4aedb4dfe4391151626dad2142558fc4907 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=9F=E4=B8=8D=E7=9F=A5?= <448300947@qq.com> Date: Sun, 29 Mar 2020 20:18:07 +0800 Subject: [PATCH 08/54] =?UTF-8?q?=E7=94=A8=E4=BE=9D=E8=B5=96=E6=B3=A8?= =?UTF-8?q?=E5=85=A5=E6=9D=A5=E8=A7=A3=E8=80=A6=E4=BD=A0=E7=9A=84=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=20(#6823)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * translate(*): Part.1 * translate(*): Part.2 * translate(*): 完成翻译 * fix(*): 完成校对 --- ...ple-your-code-with-dependency-injection.md | 190 +++++++++--------- 1 file changed, 95 insertions(+), 95 deletions(-) diff --git a/TODO1/decouple-your-code-with-dependency-injection.md b/TODO1/decouple-your-code-with-dependency-injection.md index 1618383ca6f..05ec9d2f7df 100644 --- a/TODO1/decouple-your-code-with-dependency-injection.md +++ b/TODO1/decouple-your-code-with-dependency-injection.md @@ -2,24 +2,24 @@ > * 原文作者:[Ben Weidig](https://medium.com/@benweidig) > * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) > * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/TODO1/decouple-your-code-with-dependency-injection.md](https://github.com/xitu/gold-miner/blob/master/TODO1/decouple-your-code-with-dependency-injection.md) -> * 译者: -> * 校对者: +> * 译者:[江不知](https://juejin.im/user/5ae03306f265da0b702592d1) +> * 校对者:[GJXAIOU](https://github.com/GJXAIOU), [司徒公子](https://github.com/todaycoder001) -# Decouple Your Code With Dependency Injection +# 用依赖注入解耦你的代码 -> No third-party frameworks required +> 无需第三方框架 -![Photo by [Icons8 Team](https://unsplash.com/@icons8?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/ingredients?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)](https://cdn-images-1.medium.com/max/12032/1*PfS1KYIt9IIDZTIyIIfMsQ.jpeg) +![[Icons8 团队](https://unsplash.com/@icons8?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) 摄于 [Unsplash](https://unsplash.com/s/photos/ingredients?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)](https://cdn-images-1.medium.com/max/12032/1*PfS1KYIt9IIDZTIyIIfMsQ.jpeg) -Not many components live on their own, without any dependencies on others. Instead of creating tightly coupled components, we can improve the [separation of concerns](https://en.wikipedia.org/wiki/Separation_of_concerns) by utilizing **dependency injection** (DI). +没有多少组件是能够独立存在而不依赖于其它组件的。除了创建紧密耦合的组件,我们还可以利用**依赖注入**(DI)来改善 [关注点的分离](https://en.wikipedia.org/wiki/Separation_of_concerns)。 -This article will introduce you to the core concept of dependency injection, without the need for third-party frameworks. All code examples will be in Java, but the general principles apply to any other language, too. +这篇文章将会脱离第三方框架向你介绍依赖注入的核心概念。所有的示例代码都将使用 Java,但所介绍的一般原则也适用于其它任何语言。 --- -## Example: DataProcessor +## 示例:数据处理器 -To better visualize how to use dependency injection**,** we start with a simple type: +为了让如何使用依赖注入更加形象化,我们将从一个简单的类型开始: ```Java public class DataProcessor { @@ -37,35 +37,35 @@ public class DataProcessor { } ``` -The `DataProcessor` has two dependencies: `DbManager` and `Calculator`. Creating them directly in our type has several apparent disadvantages: +`DataProcessor` 有两个依赖项:`DbManager` 和 `Calculator`。直接在我们的类型中创建它们有几个明显的缺点: -* The constructor calls can crash. -* Constructor signatures might change. -* Tightly bound to explicit implementation type. +* 调用构造函数时可能发生崩溃 +* 构造函数签名可能会改变 +* 紧密绑定到显式实现类型 -It’s time to improve it! +是时候改进它了! --- -## Dependency Injection +## 依赖注入 -James Shore, the author of [**The Art of Agile Development**](https://www.amazon.com/Art-Agile-Development-Pragmatic-Software/dp/0596527675), [put it quite nicely](https://www.jamesshore.com/Blog/Dependency-Injection-Demystified.html): +[**《敏捷开发的艺术》**](https://www.amazon.com/Art-Agile-Development-Pragmatic-Software/dp/0596527675) 的作者 James Shore [很好地指出](https://www.jamesshore.com/Blog/Dependency-Injection-Demystified.html): -> **“Dependency injection is a 25-dollar term for a 5-cent concept.”** +> **「依赖注入听起来复杂,实际上它的概念却十分简单。」** -The concept is actually really simple: Giving a component all the things it needs to do its job. +依赖注入的概念实际上非常简单:为组件提供完成其工作所需的一切。 -In general, it means decoupling components by providing their dependencies from the outside, instead of creating them directly, which would create adhesion. +通常,这意味着通过从外部提供组件的依赖关系来解耦组件,而非直接在组件内创建依赖,让组件间过度耦合。 -There are different ways how we can provide an instance with its necessary dependencies: +我们可以通过多种方式为实例提供必要的依赖关系: -* Constructor injection -* Property injection -* Method injection +* 构造函数注入 +* 属性注入 +* 方法注入 -#### Constructor injection +#### 构造函数注入 -Constructor, or initializer-based dependency injection, means providing all required dependencies during the initialization of an instance, as constructor arguments: +构造函数注入,或称基于初始化器的依赖注入,意味着在实例初始化期间提供所有必需的依赖项,将其作为构造函数的参数: ```Java public class DataProcessor { @@ -82,24 +82,24 @@ public class DataProcessor { } ``` -Thanks to this simple change, we can offset most of the initial disadvantages: +由于这一简单的改变,我们可以弥补大多数最开始的缺点: -* Easily replaceable: `DbManager` and `Calculator` are no longer bound to the concrete implementations, and are now mockable for unit-testing. -* Already initialized and “ready-to-go”: We don’t need to worry about any sub-dependencies required by our dependencies (e.g., database filename, significant digits), or that they might crash during initialization. -* Mandatory requirements: The caller knows exactly what’s needed to create a `DataProcessor`. -* Immutability: Dependencies are still final. +* 易于替换:`DbManager` 和 `Calculator` 不再被具体的实现所束缚,现在可以模拟单元测试了。 +* 已经初始化并且「准备就绪」:我们不必担心依赖项所需要的任何子依赖项(例如,数据库文件名、[有效数字(译者注)](https://zh.wikipedia.org/wiki/%E6%9C%89%E6%95%88%E6%95%B0%E5%AD%97)等),也不必担心它们可在初始化期间发生崩溃的可能性。 +* 强制要求:调用方确切地知道创建 `DataProcessor` 的所需内容。 +* 不变性:依赖关系始终如初。 -Even though constructor injection is the preferred way of many DI frameworks, it has its obvious disadvantages, too. The most significant one is that all dependencies must be provided at initialization. +尽管构造函数注入是许多依赖注入框架的首选方法,但它也有明显的缺点。其中最大的缺点是:必须在初始化时提供所有依赖项。 -Sometimes, we don’t initialize a component ourselves or we aren’t able to provide all dependencies at that point. Or we need to use another constructor. And once the dependencies are set, they can’t be changed. +有时,我们无法自己初始化一个组件,或者在某个时刻我们无法提供组件的所有依赖关系。或者我们需要使用另外一个构造函数。一旦设置了依赖项,我们就无法再改变它们了。 -But we can mitigate these problems by using one of the other injection types. +但是我们可以使用其它注入类型来缓解这些问题。 -#### Property injection +#### 属性注入 -Sometimes we don’t have access to the actual initialization of type, and only have an already initialized instance. Or the needed dependency is not explicitly known at initialization as it would be later on. +有时,我们无法访问类型实际的初始化方法,只能访问一个已经初始化的实例。或者在初始化时,所需要的依赖关系并不像之后那样明确。 -In these cases, instead of relying on a constructor, we can use **property injection**: +在这些情况下,我们可以使用**属性注入**而不是依赖于构造函数: ```Java public class DataProcessor { @@ -121,19 +121,19 @@ public class DataProcessor { } ``` -No constructor is needed anymore, we can provide the dependencies at any time after initialization. But this way of injection also comes with drawbacks: **Mutability**. +我们不再需要构造函数了,在初始化后我们可以随时提供依赖项。但这种注入方式也有缺点:**易变性**。 -Our `DataProcessor` is no longer guaranteed to be “ready-to-go” after initialization. Being able to change the dependencies at will might give us more flexibility, but also the disadvantage of more runtime-checks. +在初始化后,我们不再保证 `DataProcessor` 是「随时可用」的。能够随意更改依赖关系可能会给我们带来更大的灵活性,但同时也会带来运行时检查过多的缺点。 -We now have to deal with the possibility of a `NullPointerException` when accessing the dependencies. +现在,我们必须在访问依赖项时处理出现 `NullPointerException` 的可能性。 -#### Method injection +#### 方法注入 -Even though we decoupled the dependencies with constructor injection and/or property injection, by doing so, we still only have a single choice. What if we need another `Calculator` in some situations? +即使我们将依赖项与构造函数注入与/或属性注入分离,我们也仍然只有一个选择。如果在某些情况下我们需要另一个 `Calculator` 该怎么办呢? -We don’t want to add additional properties or constructor arguments for a second `Calculator`, because there might be a third one needed in the future. And changing the property every time before we call `calc(...)` isn't feasible either, and will most likely lead to bugs using the wrong one. +我们不想为第二个 `Calculator` 类添加额外的属性或构造函数参数,因为将来可能会出现第三个这样的类。而且在每次调用 `calc(...)` 前更改属性也不可行,并且很可能因为使用错误的属性而导致 bug。 -A better way is to parameterize the method call itself with its dependency: +更好的方法是参数化调用方法本身及其依赖项: ```Java public class DataProcessor { @@ -146,9 +146,9 @@ public class DataProcessor { } ``` -Now the caller of `calc(...)` is responsible for providing an appropriate `Calculator` instance, and `DataProcessor` is completely decoupled from it. +现在,`calc(...)` 的调用者负责提供一个合适的 `Calculator` 实例,并且 `DataProcessor` 类与之完全分离。 -Even more flexibility can be gained by mixing different types of injection, and providing a default `Calculator`: +通过混合使用不同的注入类型来提供一个默认的 `Calculator`,这样可以获得更大的灵活性: ```Java public class DataProcessor { @@ -171,47 +171,47 @@ public class DataProcessor { } ``` -The caller **could** provide a different kind of `Calculator`, but it doesn’t **have to**. We still have a decoupled, ready-to-go `DataProcessor`, with the ability to adapt to specific scenarios. +调用者**可以**提供另一种类型的 `Calculator`,但这不是**必须**的。我们仍然有一个解耦的、随时可用的 `DataProcessor`,它能够适应特定的场景。 -## Which Injection Type to Choose? +## 选择哪种注入方式? -Every type of dependency injection has its own merits, and there isn’t a “right way”. It all depends on your actual requirements and the circumstances. +每种依赖注入类型都有自己的优点,并没有一种「正确的方法」。具体的选择完全取决于你的实际需求和情况。 -#### Constructor injection +#### 构造函数注入 -Constructor injection is my favorite, and often preferred by DI frameworks. +构造函数注入是我的最爱,它也常受依赖注入框架的青睐。 -It clearly tells us all the dependencies needed to create a specific component, and that they are not optional. Those dependencies should be required throughout the component. +它清楚地告诉我们创建特定组件所需的所有依赖关系,并且这些依赖不是可选的,这些依赖关系在整个组件中应该都是必需的。 -#### Property injection +#### 属性注入 -Property injection matches better for optional parameters, like listeners or delegates. Or if we can’t provide the dependencies at initialization time. +属性注入更适合可选参数,例如监听或委托。又或是我们无法在初始化时提供依赖关系。 -Some other languages, like Swift, make heavy use of the [delegation pattern](https://en.wikipedia.org/wiki/Delegation_pattern) with properties. So, using it will make our code more familiar to other developers. +其它编程语言,例如 Swift,大量使用了带属性的 [委托模式](https://en.wikipedia.org/wiki/Delegation_pattern)。因此,使用属性注入将使其它语言的开发人员更熟悉我们的代码。 -#### Method injection +#### 方法注入 -Method injection is a perfect match if the dependency might not be the same for every call. It will decouple the component even more because now, just the method itself has a dependency, not the whole component. +如果在每次调用时依赖项可能不同,那么使用方法注入最好不过了。方法注入进一步解耦组件,它使方法本身持有依赖项,而非整个组件。 -Remember that it’s not either-or. We can freely mix the different types where it’s appropriate. +请记住,这不是非此即彼。我们可以根据需要自由组合各种注入类型。 -## Inversion of Control Containers +## 控制反转容器 -We can cover a lot of use cases with these simple implementations of dependency injection. It’s an excellent tool for decoupling, but we actually still need to create the dependencies at some point. +这些简单的依赖注入实现可以覆盖很多用例。依赖注入是很好的解耦工具,但事实上我们仍然需要在某些时候创建依赖项。 -But as our applications and codebases grow, we might need a more complete solution that simplifies the creation and assembling process, too. +但随着应用程序和代码库的增长,我们可能还需要一个更完整的解决方案来简化依赖注入的创建和组装过程。 -**Inversion of control** (IoC) is an abstract principle of the [flow of control](https://en.wikipedia.org/wiki/Control_flow). And dependency injection is one of its more concrete implementations. +**控制反转**(IoC)是 [控制流](https://en.wikipedia.org/wiki/Control_flow) 的抽象原理。依赖注入是控制反转的具体实现之一。 -An **IoC container** is a special kind of object that knows how to instantiate and configure other objects, including doing the dependency injection for you. +**控制反转容器**是一种特殊类型的对象,它知道如何实例化和配置其它对象,它也知道如何帮助你执行依赖注入。 -Some containers can detect relationships via reflection, others have to be configured manually. Some are runtime-based, others generate all the code needed at compile-time. +有些容器可以通过反射来检测关系,而另一些必须手动配置。有些容器基于运行时,而有些则在编译时生成所需要的所有代码。 -Comparing all the different options is beyond the scope of this article, but let’s check out a small example to get a better understanding of the concept. +比较所有容器的不同之处超出了本文的讨论范围,但是让我通过一个小示例来更好地理解这个概念。 -#### Example: Dagger 2 +#### 示例: Dagger 2 -[Dagger](https://dagger.dev/) is a lightweight, compile-time dependency injection framework. We need to create a `Module` that knows how to build our dependencies, that later can be injected by merely adding an `@Inject` annotation: +[Dagger](https://dagger.dev/) 是一个轻量级、编译时进行依赖注入的框架。我们需要创建一个 `Module`,它就知道如何构建我们的依赖项,稍后我们只要添加 `@Inject` 注释就可以注入这个 `Module`。 ```Java @Module @@ -231,9 +231,9 @@ public class InjectionModule { } ``` -The `@Singleton` ensures that only one instance of a dependency will be created. +`@Singleton` 确保只能创建一个依赖项的实例。 -To get injected with a dependency, we simply add `@Inject` to a constructor, field, or method: +要注入依赖项,我们只需要将 `@Inject` 添加到构造函数、字段或方法中。 ```Java public class DataProcessor { @@ -248,56 +248,56 @@ public class DataProcessor { } ``` -These are just the absolute basics, and might not seem impressive at first. But IoC containers and frameworks allow us to not just decouple our component, but also to maximize the flexibility of dependency creation. +这些仅仅是一些基础知识,乍一看不可能会给人留下深刻的印象。但是控制反转容器和框架不仅解耦了组件,也让创建依赖关系的灵活性得以最大化。 -The creation process becomes more configurable and enables new ways of using the dependencies, thanks to the advanced features provided. +由于提供了高级特性,创建过程的可配置性变得更强,并且支持了使用依赖项的新方法。 -#### Advanced features +#### 高级特性 -The features vary widely between the different kinds of IoC containers and the underlying languages, like: +这些特性在不同类型的控制反转容器和底层语言之间差异很大,比如: -* [Proxy pattern](https://en.wikipedia.org/wiki/Proxy_pattern) and lazy-loading. -* Lifecycle scopes (e.g., singleton vs. one per thread). -* Auto-wiring. -* Multiple implementations for a single type. -* Circular dependencies. +* [代理模式](https://en.wikipedia.org/wiki/Proxy_pattern) 和延迟加载。 +* 生命周期(例如:单例模式与每个线程一个实例)。 +* 自动绑定。 +* 单一类型的多种实现。 +* 循环依赖。 -These features are the real power of IoC containers. You might think features like “circular dependencies” are not a good idea. And you’re right. +这些特性是控制反转容器真正的能力。你可能会认为诸如「循环依赖」这样的特性并非好的主意,确实如此。 -But if we actually need such weird code constructs due to legacy code, or unchangeable bad design decisions in the past, we now have the power to do so. +但是,如果由于遗留代码或是过去不可更改的错误设计而需要这种奇怪的代码构造,那么我们现在有能力可以这样做。 -## Conclusion +## 总结 -We should design our code against abstractions, like interfaces, and not concrete implementations, to reduce adhesion. +我们应该根据抽象(例如接口)而不是具体的实现来设计代码,这样可以帮助我们减少代码耦合。 -The only information our code should need must be available in the interface, we can’t assume anything about the actual implementation. +接口必须提供我们代码所需要的唯一信息,我们不能对实际实现情况做任何假设。 -> **“One should depend upon abstractions, [not] concretions.” -> **— Robert C. Martin (2000), Design Principles and Design Patterns +> **「程序应当依赖抽象,而非具体的实现」** +> —— Robert C. Martin (2000), 《设计原则与设计模式》 -Dependency injection is a great way to do that by decoupling our components. It allows us to write cleaner and more concise code that’s easier to maintain and refactor. +依赖注入是通过解耦组件来实现这一点的好办法。它使我们能够编写更简洁明了、更易于维护和重构的代码。 -Which of the three dependency injection types to choose depends much on the circumstances and requirements, but we can also mix the types to maximize the benefit. +选择三种依赖注入类型中的哪种很大程度上取决于环境和需求,但是我们也可以混合使用三种类型使收益最大化。 -IoC containers can provide another layout of convenience by simplifying the component creation process, sometimes in an almost magical way. +控制反转容器有时几乎以一种神奇的方式通过简化组件创建过程来提供另一种便利的布局。 -Should we use it everywhere? Of course not. +我们应该处处使用它吗?当然不是。 -Just like other patterns and concepts, we should apply them if appropriate, not only because we can. +就像其它模式和概念一样,我们应该在适当的时候应用它们,而不是能用则用。 -Never restrict yourself to a single way of doing things. Maybe the [factory pattern](https://en.wikipedia.org/wiki/Factory_method_pattern) or even the widely-loathed [singleton pattern](https://en.wikipedia.org/wiki/Singleton_pattern) might be a better solution for your requirements. +永远不要把自己局限在一种做事的方式上。也许 [工厂模式](https://en.wikipedia.org/wiki/Factory_method_pattern) 甚至是广为厌恶的 [单例模式](https://en.wikipedia.org/wiki/Singleton_pattern) 是能够满足你需求的更好的解决方案。 --- -## Resources +## 资料 -* [Inversion of Control Containers and the Dependency Injection pattern](https://www.martinfowler.com/articles/injection.html) (Martin Fowler) -* [Dependency Inversion Principle](https://en.wikipedia.org/wiki/Dependency_inversion_principle) (Wikipedia) -* [Inversion of Control](https://en.wikipedia.org/wiki/Inversion_of_control) (Wikipedia) +* [控制反转容器与依赖注入模式](https://www.martinfowler.com/articles/injection.html) (Martin Fowler) +* [依赖反转原则](https://en.wikipedia.org/wiki/Dependency_inversion_principle)(维基百科) +* [控制反转](https://en.wikipedia.org/wiki/Inversion_of_control)(维基百科) --- -## IoC Containers +## 控制反转容器 #### Java From e4c0cac19633f9b356e4e1797fba8c7e5d369859 Mon Sep 17 00:00:00 2001 From: lsvih Date: Tue, 31 Mar 2020 19:49:47 +0800 Subject: [PATCH 09/54] Create generator-functions-in-javascript.md (#6841) * Create generator-functions-in-javascript.md * Update generator-functions-in-javascript.md --- TODO1/generator-functions-in-javascript.md | 153 +++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 TODO1/generator-functions-in-javascript.md diff --git a/TODO1/generator-functions-in-javascript.md b/TODO1/generator-functions-in-javascript.md new file mode 100644 index 00000000000..8da83bf0bed --- /dev/null +++ b/TODO1/generator-functions-in-javascript.md @@ -0,0 +1,153 @@ +> * 原文地址:[Generator Functions in JavaScript](https://medium.com/better-programming/generator-functions-in-javascript-571ba4cda69e) +> * 原文作者:[Sachin Thakur](https://medium.com/@thakursachin467) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/TODO1/generator-functions-in-javascript.md](https://github.com/xitu/gold-miner/blob/master/TODO1/generator-functions-in-javascript.md) +> * 译者: +> * 校对者: + +# Generator Functions in JavaScript + +![Photo by [matthew Feeney](https://unsplash.com/@matt__feeney?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/wait?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)](https://cdn-images-1.medium.com/max/10180/1*T-HFCdKSrA6dhlyN66g1uw.jpeg) + +With ES6, EcmaScript released a new way of working with functions. In this article, we will take a look at them and how and where we can use them + +## What Are Generator Functions? + +Generator functions are a special type of function that allows you to suspend their execution so they are later resumed at any time. + +They have also simplified the creation of iterators but we will get into that later. Let’s start simply by understanding what they are with some examples. + +Creating a generator function is simple. The `function*` declaration (`function` keyword followed by an asterisk) defines a generator function. + +```js +function* generatorFunction() { + yield 1; +} +``` + +Now, in generator functions, we don’t use return statements but rather a `yield` that specifies the value to be returned from the iterator. Now, in the above example, it will return a value of 1. + +When we call generator functions like a normal ES6 function, it does not directly execute the function but rather returns a `Generator` object. + +The `Generator` object contains `next()`, `return`, and `throw` which can be used to interact with our generator functions. It works similarly to an `iterator` but you have more control over it. + +Let’s see, with an example, how we can use the `generatorFunction`. Now, as I told you before, we get `next()`. + +The `next()` method returns an object with two properties, `done` and `value`. You can also provide a parameter to the `next` method to send a value to the generator. Let’s see this with an example. + +```JavaScript +function* generatorFunction() { + yield 1; +} +const iterator = generatorFunction() +const value=iterator.next().value +console.log(value) +``` + +![Output after calling next on generator function](https://cdn-images-1.medium.com/max/2000/1*CuDQhYcZ3xLZKvFTosFFrg.png) + +Now, as I said earlier, we can also pass values to the generator function through `next` and that value can be used inside the `generator` function. Let’s see how that works with another example. + +```JavaScript +function* generatorFunction() { + let value = yield null + yield value+ 2; + yield 3 + value +} +const iterator:Generator = generatorFunction() +const value=iterator.next(10).value // returns null +console.log(iterator.next(11).value) //return 13 +``` + +![Passing Value to generator function through next](https://cdn-images-1.medium.com/max/2000/1*ywIGvmfO_r3j0rTdccplEQ.png) + +Here, when you obtain the generator, you don’t have a `yield` you can push values to. So, first you have to reach a yield by calling the next on the generator initially. It will return `null`, always. + +You can pass arguments or not, it does not matter, it will always return `null`. Once you have done that, you have a `yield` at your disposal and you can push your value via `iterator.next()` which will effectively replace `yield null` with the input passed through `next`. + +Then, when it finds another `yield`, it returns to the consumer of the generator which is our `iterator` here. + +Now, let’s talk a little about the `yield` keyword. It looks like it’s working like return but on steroids because return simply returns a value from a function after a function is called. + +It will also not allow you to do anything after the `return` keyword in a normal function but in our case, `yield` is doing much more than that. It’s returning a value but when you call it again, it will move on to the next `yield` statement. + +The `yield` keyword is used to pause and resume a generator function. The `yield` returns an object and it contains a `value` and `done`. + +The `value` is the result of the evaluating of the generator functions and the `done` indicates whether our generator function has been fully completed or not, its values can be either `true` or `false`. + +We can also use the `return` keyword in the generator function and it will return the same object but it will not go any further than that and the code after `return` will never be reached, even if you have six `yield`s after that. + +So, you need to be very careful using `return` and it should only be used once you are certain the job of the generator function is done. + +```JavaScript +function* generatorFunction() { + yield 2; + return 2; + yield 3; //generator function will never reach here +} +const iterator:Generator = generatorFunction() +``` + +## Uses of the Generator Function + +Now, generator functions can very easily simplify the creation of iterators, implementation of the recursion, and better async functionality. Let’s look at some examples. + +```JavaScript +function* countInfinite(){ + let i=0; + while(true){ + yield i; + i++ + } +} +const iterator= countInfinite() +console.log(iterator.next().value) +console.log(iterator.next().value) +console.log(iterator.next().value) +``` + +![Count infinity example](https://cdn-images-1.medium.com/max/2504/1*YVzFY7yj2GwKBQUKbnhkug.png) + +In the above, it’s an infinite loop but it will only be executed as many times as we call `next` on the iterator since it preserves the previous state of the function it continues to count. + +This is just a very basic example of how it can be used but we can use more complex logic inside the generator functions, giving us more power. + +```JavaScript +function* fibonacci(num1:number, num2:number) { +while (true) { + yield (() => { + num2 = num2 + num1; + num1 = num2 - num1; + return num2; + })(); + } +} +const iterator = fibonacci(0, 1); +for (let i = 0; i < 10; i++) { + console.log(iterator.next().value); +} +``` + +![Fibonacci series Example](https://cdn-images-1.medium.com/max/2700/1*UOMv0GIOFyRWOqhFMSxgMA.png) + +In the above example, we implemented a Fibonacci series without any recursion. The generator functions are really powerful and are only limited by your own imagination. + +Another big advantage of generator functions is that they are really memory efficient. We generate a value that is needed. + +In the case of a normal function, we generate a lot of values without even knowing whether we are going to use them or not. However, in the case of the generator function, we can defer the computation and only use it when needed. + +Before using the generator function, just keep some things in mind. You cannot access a value again if you have already accessed it. + +## Conclusion + +Iterator functions are a great and efficient way to do a lot of things in JavaScript. There are many other possible ways of using a generator function. + +For example, working with asynchronous operations can be made easy. Since a generator function can emit many values over time, it can be used as an observable too. + +I hope this article helped you understand a little about the `generator` function and let me know what else you can do or are doing with the `generator` function. + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](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)、[前端](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#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 From 04656022bfcb8aa330eae3365ade38dcac748abb Mon Sep 17 00:00:00 2001 From: lsvih Date: Tue, 31 Mar 2020 19:54:28 +0800 Subject: [PATCH 10/54] Create how-to-keep-your-dependencies-secure-and-up-to-date.md (#6843) * Create how-to-keep-your-dependencies-secure-and-up-to-date.md * Update how-to-keep-your-dependencies-secure-and-up-to-date.md --- ...your-dependencies-secure-and-up-to-date.md | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 TODO1/how-to-keep-your-dependencies-secure-and-up-to-date.md diff --git a/TODO1/how-to-keep-your-dependencies-secure-and-up-to-date.md b/TODO1/how-to-keep-your-dependencies-secure-and-up-to-date.md new file mode 100644 index 00000000000..9c8114b14d1 --- /dev/null +++ b/TODO1/how-to-keep-your-dependencies-secure-and-up-to-date.md @@ -0,0 +1,108 @@ +> * 原文地址:[How to Keep Your Dependencies Secure and Up to Date](https://medium.com/better-programming/how-to-keep-your-dependencies-secure-and-up-to-date-92578c7f3c9c) +> * 原文作者:[Patrick Kalkman](https://medium.com/@pkalkman) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/TODO1/how-to-keep-your-dependencies-secure-and-up-to-date.md](https://github.com/xitu/gold-miner/blob/master/TODO1/how-to-keep-your-dependencies-secure-and-up-to-date.md) +> * 译者: +> * 校对者: + +# How to Keep Your Dependencies Secure and Up to Date + +![Photo by [Lenin Estrada](https://unsplash.com/@lenin33?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/robot?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)](https://cdn-images-1.medium.com/max/4320/1*dJ1mhPOPA1MVEnUfpaCGjA.jpeg) + +> Automatically update your dependencies using Dependabot + +A couple of weeks ago, I was searching for examples on GitHub for my latest article about the [open-closed principle](https://medium.com/better-programming/do-you-use-the-most-crucial-principle-of-object-oriented-design-9045dbd1321e). When I browsed through the [.NET Core repository](https://github.com/dotnet/core), I saw a folder that I did not recognize. + +This folder, `.dependabot`, contained a single file, `config.yml`. I found out that this was a configuration file for a new service from GitHub called [Dependabot](https://dependabot.com/blog/hello-github/). + +I did not know this service. + +After a little investigation, I found that Dependabot is a service that scans the dependencies of your repositories. After the scan, Dependabot validates if your external dependencies are up to date. + +And the real beauty of this service is: + +**Dependabot automatically creates a pull request to update the dependency.** + +I started using Dependabot for most of my repositories. In this article, I will show you how to use and configure Dependabot. + +## Using Dependabot + +If you have a public repository on GitHub, you probably have seen the following security warning. GitHub automatically scans all public repositories and sends an alert if it detects a security vulnerability. + +![A security alert from Github.com](https://cdn-images-1.medium.com/max/3928/1*0JG50XF4d8nYeLImgp3eoQ.png) + +If you want GitHub to scan your private repositories, you have to opt-in by enabling security notifications. The vulnerabilities that GitHub can detect come from the [GitHub Advisory Database](https://github.com/advisories) and [WhiteSource](https://www.whitesourcesoftware.com/whitesource-for-developers/). + +Together with the alert, GitHub also describes how to remediate it. + +Dependabot takes this process even further and automatically creates a Pull Request (PR) for your repository. This PR solves the security vulnerability. + +#### Starting with Dependabot + +If you want to use Dependabot, first, you need to [sign up](https://app.dependabot.com/auth/sign-up). Since GitHub acquired Dependabot, it is free of charge. + +After sign up, you have to give Dependabot access to your repository. You can do this via the Dependabot user interface or by adding a `config.yml` file to your repository. + +![Give Dependabot access to your repositories](https://cdn-images-1.medium.com/max/3364/1*d3x8R3Zqgrj2LlvJYuzZXQ.png) + +#### Configure Dependabot + +You can configure Dependabot by storing a `config.yml` file in the folder `.dependabot` in the root of your repository. + +#### Required options + +The following configuration file is from one of my repositories. It only contains the required options. + +```YAML +version: 1 +update_configs: + - package_manager: "javascript" + directory: "/WorkflowEngine" + update_schedule: "live" + - package_manager: "javascript" + directory: "/WorkflowEncoder" + update_schedule: "live" +``` + +This configuration file only uses the necessary Dependabot options. Because I have many projects in this repository, I specify two update configs. + +* The `package_manager` specifies which package manager you use. Dependabot supports a lot of different package managers such as JavaScript, [Bundler](https://bundler.io/), [Composer](https://getcomposer.org/), Python, [Maven](https://maven.apache.org/), etc. For a complete list, see the [documentation](https://dependabot.com/docs/config-file/). +* The `directory` specifies the location of your package configuration. Usually, this is the root of your repository. If you have many projects in a repository, as I have in the example above, you can specify a subfolder. +* In `update_schedule`, you can specify how often Dependabot should check for updates. Live means as soon as possible. Other options are daily, weekly, and monthly. + +Dependabot **always** creates security updates as soon as possible. + +#### Optional options + +Dependabot has some extra options for changing things such as the branch, the commit message, and assignees for the pull request. See below for the full list. + +* `target_branch `— Branch to create the pull request against. +* `default_reviewers `— Reviewers to set on the pull requests. +* `default_assignees` — Assignees to place on the pull requests. +* `default_labels` — Labels to put on the pull requests. +* `default_milestone` — Milestone to set on pull requests. +* `allowed_updates` — Limit which updates are allowed. +* `ignored_updates` — Ignore specific dependencies or versions. +* `automerged_updates` — Updates that Dependabot should merge automatically. +* `version_requirement_updates` — How to update the version of your app. +* `commit_message` — Things to add to your commit message. + +#### Validate configuration file + +There is a [page](https://dependabot.com/docs/config-file/validator/) on the Dependabot website that validates your configuration file. Make sure that your configuration file is correct. + +## Conclusion + +I have been using Dependabot for a couple of weeks now. I started with the “live” update schedule but switched to “weekly” as “live” created too many alerts. + +I now merge the pull requests from Dependabot once a week. + +You must keep your dependencies up to date. If you don’t, the delta between the version you use and the latest version increases. This increasing difference makes it more challenging to update the dependencies. + +Thank you for reading. + +> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。 + +--- + +> [掘金翻译计划](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)、[前端](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#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域,想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。 From bc6432870840b5147a9dcd27c955b68b16eba76a Mon Sep 17 00:00:00 2001 From: lsvih Date: Tue, 31 Mar 2020 20:56:23 +0800 Subject: [PATCH 11/54] Create deep-dive-into-react-fiber-internals.md (#6845) * Create deep-dive-into-react-fiber-internals.md * Update deep-dive-into-react-fiber-internals.md * Update deep-dive-into-react-fiber-internals.md --- TODO1/deep-dive-into-react-fiber-internals.md | 432 ++++++++++++++++++ 1 file changed, 432 insertions(+) create mode 100644 TODO1/deep-dive-into-react-fiber-internals.md diff --git a/TODO1/deep-dive-into-react-fiber-internals.md b/TODO1/deep-dive-into-react-fiber-internals.md new file mode 100644 index 00000000000..9c62f4060b1 --- /dev/null +++ b/TODO1/deep-dive-into-react-fiber-internals.md @@ -0,0 +1,432 @@ +> * 原文地址:[https://blog.logrocket.com/deep-dive-into-react-fiber-internals/](https://blog.logrocket.com/deep-dive-into-react-fiber-internals/) +> * 原文作者:[Karthik Kalyanaraman](https://blog.logrocket.com/author/karthikkalyanaraman/) +> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner) +> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/TODO1/deep-dive-into-react-fiber-internals.md](https://github.com/xitu/gold-miner/blob/master/TODO1/deep-dive-into-react-fiber-internals.md) +> * 译者: +> * 校对者: + +# A deep dive into React Fiber internals + +![A Deep Dive Into react Fiber Internals](https://i1.wp.com/blog.logrocket.com/wp-content/uploads/2019/11/deep-dive-react-fiber-internals.jpeg?fit=730%2C486&ssl=1) + +Ever wondered what happens when you call `ReactDOM.render(, document.getElementById('root'))`? + +We know that ReactDOM builds up the DOM tree under the hood and renders the application on the screen. But how does React actually build the DOM tree? And how does it update the tree when the app's state changes? + +In this post, I am going to start by explaining how React built the DOM tree until React 15.0.0, the pitfalls of that model, and how the new model from React 16.0.0 solved those problems. This post will cover a wide range of concepts that are purely internal implementation details and are not strictly necessary for actual frontend development using React. + +## Stack reconciler + +Let's start with our familiar `ReactDOM.render(, document.getElementById('root'))`. + +The ReactDOM module will pass the `` along to the reconciler. There are two questions here: + +1. What does `` refer to? +2. What is the reconciler? + +Let's unpack these two questions. + +`` is a React element, and "elements describe the tree." + +> "An element is a plain object describing a component instance or DOM node and its desired properties." -- [React Blog](https://reactjs.org/blog/2015/12/18/react-components-elements-and-instances.html#elements-describe-the-tree) + +In other words, elements are *not* actual DOM nodes or component instances; they are a way to *describe* to React what kind of elements they are, what properties they hold, and who their children are. + +This is where React's real power lies. React abstracts away all the complex pieces of how to build, render, and manage the lifecycle of the actual DOM tree by itself, effectively making the life of the developer easier. To understand what this really means, let's look at a traditional approach using object-oriented concepts. + +In the typical object-oriented programming world, the developer needs to instantiate and manage the lifecycle of every DOM element. For instance, if you want to create a simple form and a submit button, the state management even for something as simple as this requires some effort from the developer. + +[](https://blog.logrocket.com/deep-dive-into-react-fiber-internals/) + +Let's assume the `Button` component has a state variable, `isSubmitted`. The lifecycle of the `Button` component looks something like the flowchart below, where each state needs to be taken care of by the app: + +![Button Component Lifecycle Flowchart](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2019/11/button-component-lifecycle.png?resize=730%2C465&ssl=1) + +This size of the flowchart and the number of lines of code grow exponentially as the number of states variables increase. + +React has elements precisely to solve this problem. In React, there are two kinds of elements: + +- DOM element: When the element's type is a string, e.g., ` OK ` +- Component element: When the type is a class or a function, e.g., ` OK `, where ` + +``` + +Then React will ask the `
` and ` + + + )} else { + return ( +
+ hello +
+ ) + } + } + } + const container = document.createElement('div'); + const logger = jest.fn(); + ReactDOM.render(, container); + console.log("clicking"); + instance.handleClick(); + console.log("clicked"); + + expect(container.innerHTML).toBe( + '
hello
' + ) + + expect(logger.mock.calls).toEqual( + [["render", "hello"], + ["before-setState", "hello"], + ["render", "hi"], + ["after-setState", "hi"]] + ); + }) + +}); +``` + +In the initial render, React creates a current tree, which is the tree that gets rendered initially. + +`[createFiberFromTypeAndProps()](https://github.com/facebook/react/blob/f6b8d31a76cbbcbbeb2f1d59074dfe72e0c82806/packages/react-reconciler/src/ReactFiber.js#L593)` is the function that creates each React fiber using the data from the specific React element. When we run the test, put a breakpoint at this function, and look at the call stack, it looks something like this: + +![createFiberFromTypeAndProps() Call Stack](https://i1.wp.com/blog.logrocket.com/wp-content/uploads/2019/11/function-call-stack-1.png?resize=730%2C716&ssl=1) + +As we can see, the call stack tracks back to a `render()` call, which eventually goes down to `createFiberFromTypeAndProps()`. There are a few other functions that are of interest to us here: `workLoopSync()`, `performUnitOfWork()`, and `beginWork()`. + +```js +function workLoopSync() { + // Already timed out, so perform work without checking if we need to yield. + while (workInProgress !== null) { + workInProgress = performUnitOfWork(workInProgress); + } +} +``` + +`workLoopSync()` is where React starts building up the tree, starting with the `` node and recursively moving on to `
`, `
`, and ` + ); +} +``` + +Awesome: we can now pass extra props to the underlying ` + +``` + +But, how do we type this correctly? Button’s props can no longer unconditionally extend `React.ButtonHTMLAttributes`, because the extra props might not be passed to a `