1.关于 const 的使用
const 的表明意思常常会让人产生误解, 让人觉得变量一旦声明就不能再被改变, 而实际上const的作用是: 变量不能再被赋值(a variable that cannot be reassigned) 。
比如:
// 例子1
const x = 2;
x = 3; // error
const arr = [1];
// 这第一眼感觉arr不能再改变,一直是[1]
// 而实际上
arr[0] = 12; // ok
arr; // [12]
对于使用const
- 如果一个变量你有意去改变,应当使用let, var来声明变量,这比使用 const 意图更加清晰;
- const 没有想象中的那么有用,它会造成不必要的混乱,限制我们的使用某些功能。
一般const使用:多用于常量的声明
const PI = 3.141592;
使用Object.freeze()代替const
Object.freeze()工具函数能够将 对象/数组 的 属性/索引 变为只读, 同时使得属性non-reconfiguable, 实际上这个方法只能使最外层的对象immutable。
var x = Object.freeze( [ 1, 2, [3, 4] ] );
x[0] = 42; // 不允许改变外层的属性
x[2][0] = 43; // 允许
x; // [ 1, 2, [43, 4] ]
对比 const让你觉得你的数据不可变,而实际上没什么用处, Object.freeze()提供一个 shallow, naive immutablity, 这个还是比较有用的。
比如:
var arr = Object.freeze([1, 2, 3]);
foo( arr );
// 无论foo()对数组进行何种操作
// 我们都能保证
arr[0] === 1 // true
2.性能考虑
对于 immutability 我们需要对 数组/对象 进行一份拷贝, 然后对拷贝的变量进行操作,这势必会引起性能的问题,但是抛开使用环境来谈性能是耍流氓。
如果我们需要操作的对象,拷贝后操作的次数很少,这对性能来讲毫无意义;如果这个操作出现十分频繁,而且在应用的主要路径上,这个时候就需要考虑性能优化的问题了。
自己自定义一套性能优化方案是十分困难的,我们可以使用 immutable.js 这类已经做了很多优化的库,对数据进行操作,比如:
var state = Immutable.List.of(1, 2, 3, 4);
var newState = state.set(42, "meaning of life");
state === newState; // false
state.get(2); // 3
state.get(42); undefined
newState.get(2); // 3
newState.get(42); // "meaning of life"
newState.toArray().slice(1, 3); //[2, 3, 4]
3.数组中的方法
数组中的方法 concat, map(), filter(), reduce(), reduceRight(), slice()都是纯函数, 对原数组不会进行改变;
而 splice()
, pop()
, push()
, shift()
, unshift()
, reverse()
, sort()
, fill()
由于历史和性能优化考虑等原因,都会对原数组进行更改, 使用时要注意。
总结
不可变数据对于代码的可读性以及 代码的维护性都有很大的提升,在书写代码时应当考虑这些因素,使用 immutable.js
这类库都数据进行操作, 使用Object.freeze()
代替具有迷惑性的 const
关键词。另外数据不可变假设,在不知道数据结构时, 不论值是否可变,我们都应当把它当作不可变来处理,这会带来很多的好处。