js 中对象的拷贝很常见, 特别是在面试中很常见
一: 对象浅拷贝与深拷贝和对象引用的区别
- var a= {name:'anikin'}
- var b = jsons
- a == b // true
- b.name == 'jack'
- a.name // 'jack'
上述代码中, 使用了 = 进行赋值, 于是 b 指向了 a 所指向的栈的对象, 也就是 a 与 b 指向了同一个栈对象, 所以在对 b.name 赋值时, a.name 也发生了变化.
为了避免上面的情况, 可以对对象进行拷贝, 代码如下:
- var a = {name:'wanger'}
- var b = Object.assign({}, a)
- a===b // false
- b.name = 'zhangsan'
- a.name //'wanger'
上面代码将原始对象拷贝到一个空对象, 就得到了原始对象的克隆, 这时候 a 与 b 指向的是不同的栈对象, 所以对 b.name 重新复制也不会影响到 a.name.
但是如果 a.name 是一个对象的引用, 而不是一个字符串, 那么上面的代码也会遇到一些问题, 参考如下代码:
- var a = {name:{firstName:'wang',lastName:'er'}}
- var b = Object.assign({}, a)
- a===b // false
- b.name.firstName = 'zhang'
- a.name.firstName //'zhang'
b.name.firstName 又影响到了 a.name.firstName, 这是因为 Object.assign() 方法只是浅层拷贝, a.name 是一个栈对象的引用, 赋值给 b 时, b.name 也同样是这个栈对象的引用, 很多时候, 我们不想让这种事情发生, 所以我们就需要用到对象的深拷贝.
二, 使用 JSON.parse() 与 JSON.stringify() 对对象进行拷贝
var b = JSON.parse(JSON.stringify(a))
这种方法只适用于纯数据 json 对象的深度克隆, 因为有些时候, 这种方法也有缺陷, 参考如下代码:
- var clone = function (obj) {
- return JSON.parse(JSON.stringify(obj));
- }
- var a = {
- a:function(){console.log('hello world')},
- b:{c:1},
- c:[1,2,3],
- d:"wanger",
- e:new Date(),
- f:null,
- g:undefined
- }
- var b = clone(a)
我们发现, 上述的方法会忽略值为 function 以及 undefied 的字段, 而且对 date 类型的支持也不太友好.
更要紧的是, 上述方法只能克隆原始对象自身的值, 不能克隆它继承的值. 因此在用这个方法的时候小心使用.
三, 一般写法
- function myextends(t,c){ // 用后面的覆盖前面的
- var t = t||{};
- for( var attr in c ){
- if( c.hasOwnProperty(attr) ){
- if( typeof c[attr] == 'object'){
- //console.log(c[attr],c[attr].Contructor )
- t[attr] = (c[attr].constructor === Array)[]:{}
- arguments.callee(t[attr],c[attr])
- }else{
- t[attr] = c[attr]
- }
- }
- }
- return t
- }
来源: https://www.2cto.com/kf/201809/777954.html