JavaScript里,所有的文字列,数字,Boolean,null,undefined都为不可变对象(immutable)。 数组,Object,function为可变对象(mutable)。
简单来说,不可变现象一个值只存在一个指针,可变对象每个都存在自己的指针。
例如:
var a=1
var b=1
a==1 // output:true
var a={x:1}
var b={x:1}
a===b // output:false
a.x===b.x // output:true
当一个不可变对象被重新赋值时,从内存上来说,原来的值和原来的值的指针还存在,新赋予的值将会创造一个新的指针和对应的值,然后将该新指针赋予对象。
var a=1
var obj={b:a} // 看起来把a赋予了b,但是a是不可变对象,b的指针指向1而不是a,今后a的值怎么变化与b无关
a=2
var newObj=obj
obj.b=3 // obj和newObj是同一个指针,所以obj内部指针变化也会反映在newObj上
从上可见,当想要复制一个list或Object时,如果希望新的list不被之前的list影响,就应该循环复制list里的不可变对象。
不可变对象的优点:因为一个值只有一个指针,重复利用可以节省内存。不会出现被覆盖的风险。
现在有很多library可以将object,list也变成不可变对象,就是为了规避对象复制时的风险和享有上述的优点。
不可变对象的缺点:可能在循环中产生大量无用内存。
比较少见的情况,比如下面的例子:
String str="test"
for(int i=0;i<100000L;i++){
s+="test" // 会产生100000L的无用内存
}
解决方法:使用可变Object(Java的话,可以使用StringBuilder;ts可以使用大写的String)
p.s.关于TypeScript,虽然String,Number,Boolean都是可变对象,但是官方文档已经建议大家不要使用这些对象了。 所以不到万不得已还是不建议使用。
p.s.另外,Java有StringBuffer和StringBuilder,前者有线程锁,多线程使用时比较安全,但是效率不如后者