基础类型与引用类型
五大基础类型
- Underfied
- Null
- Boolean
- Number
- String
他们是固定大小的数据, 存在栈中, 按值传递.
- let a = 1
- let b = a // b 拷贝 a
- console.log(b) // 1
- a = 2 // a 值变了
- console.log(b) // 1,b 值没有变
对基本类型来说, 拷贝就是复制一份同样的值给对方, 双方不会被影响.
而引用类型存的是对象的引用地址, 对象的大小不确定, 存在堆中, 普通的赋值拷贝只会复制一遍引用地址, 实质上两者还是指向同一个对象.
- let a = {x : 1}
- let b = a // b 拷贝 a
- console.log(b) // {x : 1}
- a = {x : 2} // a 值变了
- console.log(b) // {x : 2},b 也变了
浅拷贝与深拷贝
上面的例子是普通的赋值拷贝, 证明了对引用类型来说赋值拷贝是无效的, 所以我们又想到了遍历一遍对象里的值, 那不就搞定了吗? 这就是我们说的浅拷贝啦. 确实, 对一个只有一层属性且属性均为基本属性的对象来说, 遍历了一遍之后会拷贝成功, 互不影响. 但是一旦存在有属性又是引用类型的话, 还是会出现一样的问题.
所以深拷贝的直观理解就是, 对引用类型中每个属性进行遍历拷贝, 直到遇到基本类型为止.
深浅拷贝的方案
浅拷贝方案
- Object.assign() (兼容性不好)
- Underscore -- _.clone()
- lodash -- _.clone()
数组中 concat 和 slice 方法
深拷贝方案
JSON.parse(JSON.stringify(obj))
简单粗暴又有点 dirty, 但是能满足日常需求, 只能处理 json 能理解的数据格式, 当然不包括函数了, 性能也没有特别好
lodash -- _.cloneDeep()
很好地兼容了 ES6 的新引用类型, 而且处理了环型对象的情况
jQuery -- $.clone() / $.extend()
源码适合初学者学习, 比较好理解
假如说到要来一个万能的完美的深拷贝方案, 哦? 不存在的. 深拷贝本来就没有一个明确的定义, 如何处理 DOM 节点的拷贝, 如何拷贝原型的属性, RegExp 怎么处理, 函数怎么处理... 在知乎上有人这样问
来源: http://www.jianshu.com/p/48b36a788ed0