Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JavaScript函数式编程之副作用 #17

Open
zhuanyongxigua opened this issue Jun 14, 2018 · 0 comments
Open

JavaScript函数式编程之副作用 #17

zhuanyongxigua opened this issue Jun 14, 2018 · 0 comments

Comments

@zhuanyongxigua
Copy link
Owner

zhuanyongxigua commented Jun 14, 2018

更多相关内容见博客 https://github.com/zhuanyongxigua/blog

概念:

副作用是在计算结果的过程中,系统状态的一种变化,或者与外部世界进行的可观察的交互

上文中的纯函数的概念很严格,这个副作用的概念也是。它的要求很高,概括的讲,只要是跟函数外部环境发生的交互就都是副作用。从“副作用”这个词语来看,它更多的情况在于“改变系统状态”。

教程中列举的一些副作用:

  • 更改文件系统
  • 往数据库插入记录
  • 发送一个http请求
  • 可变数据
  • 打印/log
  • 获取用户输入
  • DOM查询
  • 访问系统状态

如果完全没有副作用,那我们的代码就是单纯的跑一遍浪费了一点电而已,除此之外什么都没有发生,这样的话我们写代码就没有意义了。所以,在JS中,我们的目的不是完全消除副作用注1,而是避免那些不应该出现的副作用。

JS原生的方法中,map就很函数式,他会返回一个新的数组,不会改变原数组。而pop这种方法就很不好,它在操作了数组之后,也改变数组本身。

所以当我们要使用那些有副作用的方法写纯函数的时候,记得做一次深拷贝:

例一

const myPop = x => {
  let [...y] = x;
  return y.pop();
}

使用一个固定的共享状态或者调用一个纯函数不算是副作用,例子如下:

例二

const a = 5;
function A(b) {
  return a + b;
}
A(5);

调用纯函数的例子:

例三

function foo(x) {
  return bar(x);
}

function bar(y) {
  return y + 1;
}

foo(1);

虽然不算是副作用,可更加推荐的方式是把函数bar用参数的方式传进来,这样就做到了解耦,用起来更加的方便:

例四

function foo(fn, x) {
  return fn(x);
}

function bar(y) {
  return y + 1;
}

foo(bar, 1);

如果使用柯里化的方式,会更加的清爽和方便:

例五

function foo(fn) {
  return function(x) {
    return fn(x);   
  }
}

function bar(y) {
  return y + 1;
}

foo(bar)(1);

这个例子依然存在一个会令我们感到不安的地方,那就是bar可能会被修改。例如:

例六

function foo(fn, x) {
  return fn(x);
}

function bar(y) {
  return y + 1;
}
bar = undefined;
foo(bar, 1);

当然我们平时很少会大脑抽筋在全局作用域下写出一个bar = undefined来让我们的系统出错,这更可能在某个有副作用的函数内出现这种情况。这就是为什么我们要避免副作用。这个情况在ES6中会得到改善,例如:

例七

const foo = function(fn, x) {
  return fn(x);
}

const bar = function(y) {
  return y + 1;
}
bar = undefined;	// error
foo(bar, 1);

个人建议用const的方式,这样更加的安全,即便出错也可以快速定位。

注释:

  • 注1: 如果继续深入学习,对与上面列出的一些副作用,函数式还有一种延迟执行的方式(IO容器)来使这些操作变纯。

参考资料:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant