咱们须要注意的 immutable 操做

做者简介:hustcc 蚂蚁金服·数据体验技术团队javascript

immutable 是什么?不变的、一成不变的。在 Javascript 中通常指一个变量在通过一个 function 处理以后,能够保持入参数据不变。java

1、什么是 immutable?

举个真实平常例子:前两天,在业务代码中,须要得到数据的中位数,并使用 echarts 绘制出中位线,辅助分析。写代码以前,先找了一下中位线的定义。react

对于有限的数集,能够经过把全部观察值高低排序后找出正中间的一个做为中位数。若是观察值有偶数个,一般取最中间的两个数值的平均值做为中位数。git

哦,挺简单,因而奋笔疾书(实际上是 github 上的代码片断github

/** * 求取数组中的中位数 * [1, 2, 3, 4, 4] -> 3 * [1, 2, 3, 4, 5, 6] -> 3.5 */
const calculateMedian(arr) => {
  // 1. 排序
  arr.sort((a, b) => a - b);

  const half = Math.floor(arr.length / 2);

  // 2. 按照中位数定义计算
  // 奇数长度则中间值,偶数长度则中间两个数的平均值
  return arr.length % 2 !== 0 ?
    arr[half] :
    (arr[half - 1] + arr[half]) / 2.0;
}
复制代码

这段代码的问题在于函数是 mutable 的:npm

当通过函数 calculateMedian 求取数组 [5, 4, 3, 2, 1] 的中位数的时候,致使入参数组变成了 [1, 2, 3, 4, 5]。致使后续的代码拿到的数组,都是通过排序的,数据都是混乱的。redux

上述代码只须要修改一个地方便可:数组

const newArr = [].concat(arr).sort((a, b) => a - b);
复制代码

其中 [].concat(arr) 达到的效果就是代码的 immutable。数据结构

经过这样的一个实际例子,我想应该很容易理解 mutable 代码形成的影响是什么?架构

  • 数据污染:通过一个方法,数据就变化了,多么可怕。
  • 数据不可控:数据不只仅是被修改,并且咱们无法控制数据被修改的规律。
  • debug 黑洞:通常的 bug,若是了解业务,可能不用 debugger 就能定位一二;mutable 产生的 bug,没办法,新增代码一句句 F10 吧。

2、常见的缘由

不少状况下,道理咱们都懂,可是仍是会不经意写出 mutable 的代码。分为几种状况,看起来清晰一些吧!

1. 意识不清晰

不少开发者在写代码的时候,没有从全局胜寒意识到函数必须保证 immutable,只在意本身的函数输入输出符合要求。

开发者须要有时刻警戒的意识,一旦涉及到 object 的操做,先提醒本身注意不可变。特别是对于公共模块的开发,开源项目的开发,养成“变道就打转向灯的好习惯”。

2. 函数理解不清晰

Array 常见的函数 push、pop、shift 等,通常都能理解它们是会修改原数组数据,是 mutable 的函数。

可是对于上述例子中的 sort 函数应该就是理解上容易产生歧义(本身以前一直觉得是生成一个新的数组,写完这篇,我去搜索了整个业务代码)。一样的,容易产生歧义的函数包括:

  • sort
  • reverse
  • fill
  • splice
  • delete

注意:Array 中 immutable 函数不少,以上几个函数是功能上容易误解的。

3. 使用“不靠谱”的开源库

GitHub 真是个好东西,只要你能想到的代码,基本都有参考的,特别是 JavaScript 语言的。

可是你永远不知道你使用的轮子是否是仅仅是一个课堂做业练手的。在使用一个开源模块的时候,须要观察:

  • 单测是否完善:不是指单测是否是绿色(pass),而是看单测代码是否靠谱

在完善的单测能够看到:

  1. 项目实际的使用方式,这些极可能是 README 中没法完整写出来的东西。
  2. 理解项目的模块划分,组织架构。
  3. 开发者在项目代码中扣住的开发细节点。

好比,若是 immutable 是项目的一个重要特性之一,那么在单测代码中必定会反映出来。

  • npm 下载量

就像在网上购物同样,比较懒的购物者,直接买订单数最多的爆款。

  • issues

能够关注在 issue 处理速度、issue 中搜索关键字,能够大概知道是否存在这些问题。

  • 何妨 review 一下

若是代码简单,能够简单 review 一下,抓住代码实现的关键点。

3、如何写 immutable 的代码

既然要写 immutable 的代码,那咱们应该怎么作?

1. 靠谱开源项目

  1. immutability-helper:基于原始 Array 和 Object 的 immutable 操做,很好用。
  2. js-joda:日期 Date immutable 方法。
  3. immutable-js:Facebook 的 immutable 模块,定义了新的数据结构,使用成本相对高一点点。
  4. immutability-helper-x:包装 immutable-helper,使用更友好。
  5. immu:基于 Proxy 的 immutable 模块,思路新颖,可是兼容性差一点。

2. 单测约束

针对开头的 calculateMedian 函数,写一个单测:

describe('calculateMedian', () => {
  test('immutable', () => {
    const a = [5, 4, 3, 2, 1];
    const aClone = a.slice();
    expect(calculateMedian(a)).toBe(3);
    // 保证不能被修改!
    expect(a).toEqual(aClone);
  });
});
复制代码

单测约束以后,之后其余人修改这么代码致使 mutable 的时候,也会 ci 报错的,保证这个方法的长治久安。

除此以外,开启 Eslint 工具,也能够对 Object 的 mutable 自动告警。

3. 解构和 spread 语法

解构是 spread 语法是 ES6 中的新语法,也是我我的用的很是多的,通常代码的 immutable 写法,均可以知足。

  • Object 解构与 spread

好比咱们有一个用户信息 A(几十项信息),而后须要建立一个用户信息 userB,除 id、name 不同以外,其余都和 userA 一致。

const userA = {
  id: 1,
  name: 'hustcc',
  addr: 'Hangzhou',
  birth: '1992-08-01',
  // ...
  // 不少的数据不列出了
};

// 结构和 spread 写法建立 userB
const userB = {
  ...userA,
  id: 2,
  name: 'ProtoTeam',
};
复制代码
  • 数组 immutable 操做
const arr = [1, 2, 3, 4, 5];

// push 操做
const arrPush = [
  ...arr,
  6,
];

// shift 操做
const [e, ...arrShift] = arr;

// concat

const arrConcat = [...arr, ...arr];
复制代码

4、最后

在 react + redux 技术栈下,不可变数据结构是你们都提倡的作法,因此又不少框架层面的东西帮咱们处理了这些事情。

可是实际上,咱们在平时的业务代码开发中,就须要有 immutable 的意识,善用 ES6 语法,就能够解决咱们大部分的场景。

对咱们团队感兴趣的能够关注专栏,关注github或者发送简历至'tao.qit####alibaba-inc.com'.replace('####', '@'),欢迎有志之士加入~

原文地址:github.com/ProtoTeam/b…

相关文章
相关标签/搜索