谈谈面向接口编程理解
Most of what I will discuss in this article is knowledge accumulated from reading, “Functional Programming in JavaScript”, by Luis Atencio. Let’s dig right in…
我将在本文中讨论的大部分内容是Luis Atencio所著的 “ JavaScript中的函数编程 ”一书所积累的知识。 让我们直接在...
什么是函数式编程? (What is functional programming?)
In simple terms, functional programming is a software development style that places a major emphasis on the use of functions. You might say, “Well, I already use functions daily, what’s the difference?” Well, it’s not a matter of just applying functions to come up with a result. The goal, rather, is to abstract control flows and operations on data with functions in order to avoid side effects and reduce mutation of state in your application.
简而言之,函数式编程是一种软件开发风格,主要强调函数的使用。 您可能会说:“嗯,我已经每天使用函数了,有什么区别?” 好吧,这不仅仅是应用函数来得出结果的问题。 相反,目标是通过功能抽象数据上的控制流和操作 ,以避免产生副作用并减少应用程序中的状态 突变 。
抽象控制流 (Abstract Control Flows)
To understand what abstract control flows means, we need to first look at a model of programming called Imperative or Procedural Programming. Imperative programming treats a computer program as merely a sequence of top-to-bottom statements that change the state of the system in order to compute a result.
要了解抽象控制流的含义,我们首先需要研究一种称为命令式或过程式编程的编程模型 。 命令式编程将计算机程序仅视为一系列从上至下的语句,这些语句会更改系统的状态以计算结果。
Imperative programming tells the computer, in great detail, how to perform a certain task (looping through and applying a given formula to each item in an array for instance). This is the most common way of writing code. Here is an example.
命令式编程非常详细地告诉计算机如何执行特定任务(例如,遍历并将给定公式应用于数组中的每个项目)。 这是编写代码的最常见方式。 这是一个例子。
var array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
for(let i = 0; i < array.length; i++) {
array[i]= Math.pow(array[i], 2);
}
array;//-> [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Functional programming, on the other hand, falls under the umbrella of Declarative Programming: it’s a type of programming that expresses a set of operations without revealing how they’re implemented or how data flows through them.
另一方面,函数式编程属于声明式编程的范畴 :这是一种编程类型,它表达一组操作而不显示其实现方式或数据如何通过这些操作。
Declarative programming separates program description from evaluation. It focuses on the use of expressions to describe what the logic of a program is without necessarily specifying its control flow or state changes.
声明式编程将程序描述与评估分开。 它着重于使用表达式来描述程序的逻辑,而不必指定其控制流或状态更改。
You only need to be concerned with applying the right behavior at each element and give-up control of looping to other parts of the system. For example, letting Array.map() do most of the heavy lifting in the task we did earlier, would be considered a more functional approach.
您只需要关心在每个元素上应用正确的行为,并放弃对循环到系统其他部分的控制。 例如,让Array.map()完成我们之前完成的任务中的大部分繁重工作,将被认为是一种更具功能性的方法。
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(num => Math.pow(num, 2));//-> [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
With this approach, we abstract our loops with functions, and compared to the previous example, you see that this code frees you from the responsibility of properly managing a loop counter and array index access. Put simply, the more code you have, the more places there are for bugs to occur. Also, standard loops aren’t reusable artifacts unless they’re abstracted with functions.
使用这种方法,我们将循环与函数进行了抽象,并且与前面的示例相比,您会发现此代码使您摆脱了正确管理循环计数器和数组索引访问的责任。 简而言之,您拥有的代码越多,发生错误的地方就越多。 同样,除非使用函数将它们抽象化 ,否则标准循环将不可重用。
Ideally, manual loops should be removed completely from your code in favor of first-class, higher-order functions like map, reduce and filter, which accept functions as parameters so that your code is more reusable, extensible, and declarative.
理想情况下,应该从代码中完全删除手动循环,而采用一流的 , 高阶函数(例如map , reduce和filter) ,这些函数接受函数作为参数,以使您的代码更具可重用性,可扩展性和声明性。
避免副作用 (Avoid Side Effects)
Functional programming is based on the premise that you use Pure Functions (functions with no side-effects) as building blocks when building your programs. Pure functions have the following characteristics:
函数式编程的前提是您在构建程序时使用Pure Functions (无副作用的函数)作为构建块。 纯函数具有以下特征:
- They depend only on the input provided and not on any hidden or external input. 它们仅取决于提供的输入,而不取决于任何隐藏或外部输入。
- They don’t inflict changes beyond their scope, such as modifying a global object. 它们不会造成超出其范围的更改,例如修改全局对象。
Intuitively, any function that doesn’t meet these requirements is “impure.” Consider the following function:
直观地讲,任何不满足这些要求的功能都是“不纯的”。 考虑以下功能:
var counter = 0;
function increment() {
return ++counter;
}
This function is impure because it reads/modifies an external variable, counter, which isn’t local to the function’s scope. Generally, functions have side effects when reading from or writing to external resources, as shown in the example above. Its result is unpredictable because the counter variable can change at any time between calls.
该函数是不纯的,因为它读取/修改了外部变量 counter,该变量不在函数范围内。 通常, 在读取或写入外部资源时 , 功能会产生副作用 ,如上面的示例所示。 其结果是不可预测的,因为计数器变量可以在两次调用之间随时更改。
One might ask, “If you’re unable to create and modify objects or print to the console, what practical value would you get from a program like this?”, Indeed, pure functions can be hard to use in a world full of dynamic behavior and mutation. But practical functional programming doesn’t restrict all changes of state; it just provides a framework to help you manage and reduce them while allowing you to separate the pure from the impure. Impure code produces externally visible side effects.
有人可能会问:“如果无法创建和修改对象或无法打印到控制台,那么从这样的程序中可以获得什么实际价值?”,确实,在充满动态的世界中,纯函数可能很难使用。行为和突变。 但是实用的函数式编程并不能限制状态的所有改变; 它只是提供了一个框架来帮助您管理和减少它们,同时允许您将纯净与不纯净分开。 不纯净的代码会产生外部可见的副作用。
减少状态突变 (Reduce Mutation of State)
Immutable data is data that can’t be changed after it’s been created. In JavaScript, as with many other languages, all primitive types ( String, Number, and so on) are inherently immutable. But other objects, like arrays, aren’t immutable.
不变数据是指创建后无法更改的数据。 与许多其他语言一样,在JavaScript中,所有基本类型(字符串,数字等)本质上都是不可变的。 但是其他对象(例如数组)不是不可变的。
The state of a program can be defined as a snapshot of the data stored in all of its objects at any moment in time. Sadly, JavaScript is one of the worst languages when it comes to securing an object’s state. A JavaScript object is highly dynamic, and you can modify, add, or delete its properties at any point in time. Although this may give you the liberty to do many slick things, it can also lead to code that’s extremely difficult to maintain.
程序的状态可以定义为随时存储在其所有对象中的数据的快照。 可悲的是,在保护对象状态方面,JavaScript是最糟糕的语言之一。 JavaScript对象是高度动态的,您可以随时修改,添加或删除其属性。 尽管这可以让您自由地进行许多有趣的事情,但它也可能导致代码极难维护。
To step back a bit, you might ask why its recommended you always remove manual loops from your code? Well, a manual loop is an imperative control structure that’s hard to reuse and difficult to plug into other operations. In addition, it implies code that’s constantly changing or mutating in response to new iterations.
要退后一步,您可能会问为什么它建议您始终从代码中删除手动循环? 好吧,手动循环是一种必要的控制结构,它很难重用,也很难插入其他操作中。 另外, 它意味着代码会随着新的迭代而不断变化或变异。
functional programs aim for statelessness and immutability as much as possible.
功能程序旨在尽可能实现无状态和不变性。
Stateless code has zero chance of changing or breaking global state. To achieve this, you’ll use functions that avoid side effects and changes of state, known as pure functions.
无状态代码更改或破坏全局状态的机会为零。 为此,您将使用避免副作用和状态变化的 函数 (称为纯函数) 。
ES6 uses the const keyword to create constant references. This moves the needle in the right direction because constants can’t be reassigned or re-declared. In practical functional programming, you can use const as a means to bring simple configuration data ( URL strings, database names, and so on) into your functional program. But this doesn’t solve the problems of mutability to the level that FP requires. You can prevent a variable from being reassigned, but how can you prevent an object’s internal state from changing? For example, this code would be perfectly acceptable:
ES6使用const关键字创建常量引用 。 因为不能重新分配或声明常量,所以可以使针向正确的方向移动。 在实际的函数式编程中,可以使用const作为将简单的配置数据(URL字符串,数据库名称等)带入函数式程序的一种方式。 但这并不能解决FP所要求的可变性问题 。 您可以防止重新分配变量,但是如何防止对象的内部状态改变? 例如,此代码完全可以接受:
const student = new Student('Alonzo', 'Church', '666-66-6666', 'Princeton');
student.lastname = 'Mourning';
What you need is a stricter policy for immutability of which, Encapsulation is a good strategy to protect against mutations. For simple object structures, a good alternative is to adopt the Value Object pattern also referred to as the Module pattern. A value object is one whose equality doesn’t depend on identity or reference, just on its value; once declared, its state may not change.
您需要一个更严格的不变性策略, 封装是防止突变的好策略。 对于简单的对象结构,一个不错的选择是采用“ 值对象”模式,也称为“ 模块”模式 。 值对象是其相等性不依赖于标识或引用的对象,而仅取决于其值。 声明后,其状态可能不会更改。
function zipCode(code, location) {
let _code = code;
let _location = location || '';
return {code: function () {
return _code;
},location: function () {
return _location;
},fromString: function (str) {
let parts = str.split('-');
return zipCode(parts[0], parts[1]);
},toString: function () {
return _code + '-' + _location;
}
};
}
In JavaScript, you can use functions and guard access to a function’s internal state by returning an object literal that exposes a small set of methods to the caller and treats its encapsulated properties as pseudo-private variables. These variables are only accessible in the object literal via closures, as you can see in the example above.
在JavaScript中,您可以使用函数并通过返回一个对象常量来保护对函数内部状态的访问 ,该对象常量向调用者公开了一小组方法,并将其封装的属性视为伪私有变量 。 如上例所示,这些变量只能通过闭包在对象文字中访问。
The returned object effectively behaves like a primitive type that has no mutating methods. Hence, the toString method, although not a pure function, behaves like one and is a pure string representation of this object. Value objects are lightweight and easy to work within both functional and object-oriented programming.
返回的对象有效地表现为没有变异方法的原始类型。 因此, toString方法虽然不是纯函数,但其行为类似于一个函数,并且是此对象的纯字符串表示形式。 值对象轻巧,易于在功能和面向对象的编程中使用。
结论… (In Conclusion…)
When thinking about your application’s design, ask yourself the following questions:* Do I constantly change my code to support additional functionality?* If I change one file or function, will another be affected?* Is there a lot of repetition in my code?* Is my code unstructured or hard to follow?
在考虑应用程序的设计时,请问自己以下问题:*是否不断更改代码以支持其他功能?*如果更改一个文件或功能,是否会影响另一个文件或功能?*代码中是否存在很多重复? *我的代码是非结构化的还是很难遵循的?
If you answer yes to any of these questions, then, by all means, make functional programming your friend. Just remember,
如果您对上述任何一个问题的回答为“是”,则一定要使函数式编程成为您的朋友。 只记得,
In functional programming, functions are the basic units of work, which means everything centers around them.
在函数式编程中,函数是基本的工作单元,这意味着一切都围绕它们。
A function is any callable expression that can be evaluated by applying the () operator to it. Functions can return either a computed value or undefined (void function) back to the caller. Because FP works a lot like math, functions are meaningful only when they produce a usable result (not null or undefined ) otherwise, the assumption is that they modify external data and cause side effects to occur.
函数是可以通过将()运算符应用于该函数的任何可调用表达式。 函数可以将计算值或未定义的(void函数)返回给调用者。 因为FP的工作原理很像数学,所以函数只有在它们产生可用结果(不是null或undefined)时才有意义,否则假设是它们会修改外部数据并引起副作用。
In order to benefit from functional programming, you must learn to think functionally and as a result, develop your functional awareness — the instinct of looking at problems as a combination of simple functions that together provide a complete solution.
为了从函数式编程中受益,您必须学习函数式思考,结果是增强您的函数式意识 -将问题看作是简单函数的组合,它们共同提供了完整的解决方案。
At a high level, functional programming is effectively the interplay between decomposition (breaking programs into small pieces) and composition (joining the pieces back together). It’s this duality that makes functional programs modular and so effective.
在较高的级别上,函数式编程实际上是分解(将程序分解成小块)和组合(将各块重新组合在一起)之间的相互作用。 正是这种双重性使功能程序模块化并如此有效。
翻译自: https://medium.com/swlh/lets-talk-functional-programming-bc12d66d604d
谈谈面向接口编程理解