揭秘现代前端术语
1.纯函数
2. 非纯函数
3. 副作用
4. 有状态 vs. 无状态
5. 命令式与声明式范式
6. 响应式编程与可观察对象
7. 摇树
8. 编译:JIT 与 AOT
9. Reducer
10. 砰
前端编程的世界充满了令人困惑的专业术语,我们经常看到这些术语被随意使用。本文旨在通过有限的代码示例,将其中一些术语或概念分解成更简单的术语。
1.纯函数
如果一个函数的返回值仅由其自身的参数决定,则该函数被称为纯函数。当输入相同的参数时,结果始终相同。
function twice(num) {
return num * 2;
}
如果我们传递4
给这个函数,它将总是返回8
。
要点:
- 纯函数提供引用透明性。这意味着当调用纯函数时,它可以被其自身的结果替换。我们可以用它替换
twice(4)
而8
不会影响结果。 - 纯函数不能引用其外部作用域的变量。如果任何函数这样做,那么它就不是纯函数。
// NOT a pure function
let num = 8; // can be mutated from anywhere else
function impureTwice() {
return num * 2;
}
- 纯函数不能调用非纯函数。
- 纯函数不会产生副作用(见下文)。
2. 非纯函数
非纯函数会在其作用域之外改变状态。任何具有副作用的函数都是非纯函数。
let count = 0; // can be mutated from anywhere else
function increment() {
return ++count;
}
// alerts and dialogs also cause side effect
function showAlert() {
alert('oh hey! this is a side effect!');
}
// Beware! might seem like a pure function, but its not
function getRandomRange(min, max) {
return Math.random() * (max - min) + min;
}
3. 副作用
如果操作、函数或表达式修改了其局部环境之外的某些状态变量值,则称其具有副作用。
当函数或表达式在其自身上下文之外修改状态时,结果就是副作用。例如,操作 DOM、进行 API 调用、修改数据库、创建警报和对话框等。
4. 有状态 vs. 无状态
有状态的程序或组件将当前状态的数据存储在内存中。它们可以修改状态并访问其历史记录。
无状态程序或组件仅依赖于其参数,不访问甚至不需要其作用域之外的任何信息。它们在执行过程中不会引用任何先前的信息。纯函数是无状态的。正是这种无状态性使得纯函数具有引用透明性。
5. 命令式与声明式范式
JavaScript 可以支持这两种编程范式。
命令式代码会给出指令,告知计算机如何实现期望的结果,例如for
循环。
声明式代码会告诉计算机你想要实现什么,而不是如何实现,计算机会负责如何实现最终结果,例如Array.map
。
6. 响应式编程与可观察对象
响应式编程的理念是,只需定义不同的流以及在这些流上执行的操作,即可创建整个程序。
流只不过是随时间变化的值序列。
打个比方:把响应式编程想象成管道。我们决定应用程序中需要哪些管道,我们决定如何连接这些管道,然后我们打开水龙头,坐下来休息。
可观察对象是我们创建流、订阅流、响应新发出的值以及组合流以构建新流的蓝图。JavaScript 可观察对象是观察者模式的一种实现。
有两种类型的可观察量 -
- 冷可观察对象:只有我们订阅它时才会开始推送。如果我们再次订阅,推送将重新开始。
- 热门可观察对象:即使我们没有通过订阅对它们做出具体反应,它们也会一直推送。
RxMarbles是一个很好的资源,可以直观地展示所有操作的发生方式。
7. 摇树
Tree Shaking 是一个用于 JavaScript 模块打包的术语。它指的是对所有导入的代码进行静态分析,并排除所有未使用的代码。Tree
Shaking 背后的概念是实时代码包含。这意味着我们从一开始就包含需要的部分,而不是在后期移除不需要的部分。
8. 编译:JIT 与 AOT
即时 (JIT)编译是指在运行时(程序或应用程序执行期间)将编程语言代码转换为机器码的过程。运行时会获取某些动态信息,例如类型标识。JIT 编译器会监控并检测多次运行的函数或代码循环。然后,这些代码片段会被编译。如果它们被频繁执行,JIT 会对其进行优化,并存储优化后的编译代码以供执行。浏览器使用 JIT 编译来运行 JavaScript。
提前 (AOT)编译是指在执行之前(而不是在运行时)将编程语言编写的代码转换为机器码的过程。这样做可以减少运行时开销,并将所有文件一起编译,而不是单独编译。
AOT 的一些好处:
- 由于评估已经完成,因此安全性更高。
- 模板和样式与 JS 内联,因此异步调用更少。
- 下载大小较小,因为应用程序已预编译,因此无需下载编译器。
- AOT 还支持摇树。
9. Reducer
如果你用过 Redux 或函数式编程,你很可能已经非常了解这一点了。但如果撇开这些不谈,Reducer 本身到底是什么意思呢?简单来说,Reducer 提供了组合事物的指令。
通常,Reducer 函数接受一个累加器,它是我们组合过程中持续得到的结果,以及我们希望组合的事物列表。
这里有一个(不太实用😂)制作 cookie 的示例——
reduce(mix, ["flour", "butter", "sugar", "eggs"]) // result ➡️ ["cookie dough"]
我们把配料清单组合起来,
得到了想要的结果!🍪 这里mix
是我们的累加器,包含了我们目前为止组合的持续结果。所以,如果我们在配料清单中添加其他东西,累加器就会发生变化。
reduce(mix, ["flour", "butter", "sugar", "eggs", "chocolate chip"]) // result ➡️ ["chocolate chip cookie dough"]
reduce(mix, ["flour", "butter", "sugar", "eggs", "blueberry"]) // result ➡️ ["blueberry cookie dough"]
正如我们所见,我们已经将原料制成了完全成型的饼干面团!
10. 砰
在计算机编程中,thunk 只是函数的另一种说法。但它指的是由另一个函数返回且不接受参数的函数。thunk
用于延迟或推迟计算,直到需要其结果为止,或者在其他计算的开头或结尾插入操作。然后,当调用该 thunk 时,它会执行可能开销很大的计算和/或导致某些副作用。
例如 -
假设你想对数字进行一些数学运算。现在,创建一个 thunk 意味着不直接进行计算,而是创建一个不带参数的函数,当需要实际值时再进行计算。
function add(x, y) {
// this is a thunk because it defers work for later
return function() { // it can be named, or anonymous
return x + y;
};
}
const thunk = add(1,2); // we can store the returned function to a variable
// OR use it directly like ➡️ add(1,2)()
// we can pass the thunk to different places
checkIfEven(thunk);
// we can use it in other calculations
const twice = thunk() * 2;
在这里,无论使用什么thunk()
都会返回,除非我们通过使用不同的参数再次3
调用来改变它的值。add
这只是我解释事物的天真方法,但如果您对其中任何一个有更好的解释,请在下面评论,我很想知道 🙂
此外,如果您知道任何与前端相关的术语,请告诉我,我可能会做第 2 部分!