对象属性类型
数据属性文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/20919.html
数据属性包含一个数据值的位置,在这个位置可以读取和写入值,数据属性有4个描述其行为的特性:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/20919.html
- Configurable: 表示是否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。默认值是true
- Enumerable: 表示能否通过for-in循环返回属性。默认值是true
- Writable: 表述能否修改属性。默认值是true
- Value: 包含这个属性的数据值。默认值是true
访问器属性文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/20919.html
函数式编程
函数式编程是一种编程范式,是一种构建计算机程序结构和元素的风格,它把计算看作是对数学函数的评估,避免了状态的变化和数据的可变。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/20919.html
纯函数文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/20919.html
纯函数是稳定的、一致的和可预测的。给定相同的参数,纯函数总是返回相同的结果。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/20919.html
纯函数有一个非常严格的定义:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/20919.html
- 如果给定相同的参数,则返回相同的结果(也称为确定性)。
- 它不会引起任何副作用。
纯函数特性
- 如果给定相同的参数,则得到相同的结果
我们想要实现一个计算圆的面积的函数。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/20919.html
不是纯函数会这样做:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/20919.html
let PI = 3.14;
const calculateArea = (radius) => radius * radius * PI;
// 它使用了一个没有作为参数传递给函数的全局对象
calculateArea(10); // returns 314.0
纯函数:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/20919.html
let PI = 3.14;
const calculateArea = (radius, pi) => radius * radius * pi;
// 现在把 PI 的值作为参数传递给函数,这样就没有外部对象引入。
calculateArea(10, PI); // returns 314.0
- 无明显副作用
纯函数不会引起任何可观察到的副作用。可见副作用的例子包括修改全局对象或通过引用传递的参数。
现在,实现一个函数,接收一个整数并返对该整数进行加1
操作且返回。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/20919.html
let counter = 1;
function increaseCounter(value) {
counter = value + 1;
}
increaseCounter(counter);
console.log(counter); // 2
该非纯函数接收该值并重新分配counter
,使其值增加1
。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/20919.html
函数式编程不鼓励可变性(修改全局对象)。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/20919.html
let counter = 1;
const increaseCounter = (value) => value + 1; // 函数返回递增的值,而不改变变量的值
increaseCounter(counter); // 2
console.log(counter); // 1
纯函数的好处
纯函数代码肯定更容易测试,不需要 mock 任何东西,因此,我们可以使用不同的上下文对纯函数进行单元测试:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/20919.html
一个简单的例子是接收一组数字,并对每个数进行加 1
文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/20919.html
let list = [1, 2, 3, 4, 5];
const incrementNumbers = (list) => list.map(number => number + 1);
incrementNumbers(list); // [2, 3, 4, 5, 6]
对于输入[1,2,3,4,5]
,预期输出是[2,3,4,5,6]
。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/20919.html
引用透明性
实现一个square
函数:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/20919.html
const square = (n) => n * n;
square(2); // 4 将2作为square函数的参数传递始终会返回4
可以把square(2)
换成4
,我们的函数就是引用透明的。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/20919.html
如果一个函数对于相同的输入始终产生相同的结果,那么它可以看作透明的。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/20919.html
函数也可以被看作成值并用作数据使用。
- 从常量和变量中引用它。
- 将其作为参数传递给其他函数。
- 作为其他函数的结果返回它。
其思想是将函数视为值,并将函数作为数据传递。通过这种方式,我们可以组合不同的函数来创建具有新行为的新函数。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/20919.html
假如我们有一个函数,它对两个值求和,然后将值加倍,如下所示:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/20919.html
const doubleSum = (a, b) => (a + b) * 2;
对应两个值求差,然后将值加倍:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/20919.html
const doubleSubtraction = (a, b) => (a - b) * 2
这些函数具有相似的逻辑,但区别在于运算符的功能。如果我们可以将函数视为值并将它们作为参数传递,我们可以构建一个接收运算符函数并在函数内部使用它的函数。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/20919.html
const sum = (a, b) => a + b;
const subtraction = (a, b) => a - b;
const doubleOperator = (f, a, b) => f(a, b) * 2;
doubleOperator(sum, 3, 1); // 8
doubleOperator(subtraction, 3, 1); // 4
文章源自菜鸟学院-https://www.cainiaoxueyuan.com/gcs/20919.html