一、问题暴露
有一个全局的变量 a,是个 Json 对象,需求就是在很多方法中都会去使用它,但是不允许更改 a 的值。
在使用的时候,仅仅是 var b = a;
但是发现每次改变 b 中的值得时候,a 中 的值也被改变了,原来 JS 也是对象的引用,专业一点的术语,这种复制叫做:浅复制。
二、问题解决
问题总该解决,研究发现,使用一种讨巧的方式,便可以实现:
var b= JSON.parse(JSON.stringify(a));
即,将 a 先反序列化成 js 对象,再序列化成 json 对象,完美解决。
三、再谈
问题虽然解决了,但是碰到了总要稍微深入研究下。
在 JS 的世界里,关于复制,有两种,称为浅复制和深复制(其实浅复制就是 Java 里面对象引用的时候引用了其内存地址,相同概念而已)。
浅复制:复制引用,指向同一个对象实例。
深复制:不是复制引用,而是重新分配了一块内存,并将原来的对象所有的属性都复制到该内存中,即是一个新的对象,和原来的对象相隔离。
其实,关于深、浅复制的概念讨论,都是针对的“对象”,即 Object、Array 等,基本引用类型并不涉及,因为这些值本身就是存储在堆内存中的,不存在引用地址,如:null、undefined、string、number和boolean(JS 中 string 也在基本类型的范畴)。
四、再挖掘
其实在深、浅复制的相关讨论中,还有一个概念叫“粒度”,就是说,深复制是指对象的递归复制,即如果对象内部包含对象,那么深复制的概念是递归完全复制。
那么有一种状态是处于深复制和浅复制之间的,即“粒度”不够细的时候,意思就是,外层对象确实是有了新的内存分配,但是内层对象并没有完全隔离。
比如 JQuery 中的 extend 方法,当给它的 deep传递参数 true 时,就进行了递归复制,即深复制,当传递 false 时,就是上面所提到的“中间态”,即仅仅是复制了外面的一层,但是其内部的对象,还是没有隔离开,相互之间还是会有影响。
文章评论