JavaScript基礎概念之----淺拷貝/深拷貝

淺拷貝:就是簡單的值的傳遞。jquery

深拷貝:達到了真正意義上的拷貝,很好的解決了引用類型的拷貝問題,採用遞歸的方法去複製拷貝對象,從而解決淺拷貝的弊端。數據結構

在JS中,基本類型(Number,String,Boolean等)和 對象(Array,Object等)最大的不一樣在於它們的傳值方式。基本類型是按值傳遞,對象按引用傳值。函數

var a = 1
var b = 2
b = 3
console.log(a) //1
console.log(b) //3
//修改了b不會影響到a的值

var oa = {a:1,b:2,c:3}
var ob = oa;
ob.a = 4
console.log(oa) //{a:4,b:2,c:3} 被修改了
console.log(ob) //{a:4,b:2,c:3}
//修改了ob中屬性的值,也會把oa中相同屬性的值一塊兒修改,由於它們根本就是同一個對象,這就是所謂的淺拷貝

var o1 = {a:1,b:2,c:3}
var o2 = {a:o1.a,b:o1.b,c:o1.c}
o2.a = 4
console.log(o1) //{a:1,b:2,c:3} 沒有被修改
console.log(o2) //{a:4,b:2,c:3}
//這就是基本的深拷貝

淺拷貝只複製指向某個對象的指針,而不復制對象自己,新舊對象仍是共享同一塊內存。但深拷貝會另外創造一個如出一轍的對象,新對象跟原對象不共享內存,修改新對象不會改到原對象。ui

淺拷貝的實現方式

一、簡單的複製語句spa

function copy(source){
    var target = {}
    for(var i in source){
        target [i] = source[i]
    }
    return target;
}

var o = {
    a:1,
    b:{ x:1,y:'hello'},
    c:[1,2,3],
    d:function(){
        console.log('hello')
    }
}

var clone = copy(o);
console.log(clone) //輸出clone對象

clone.b.x = 2;
clone.c = [4,5,6]
clone.d = function(){console.log('world')}
console.log(o) //輸出o對象,o對象也被修改

二、Object.assign()指針

該方法能夠把任意多個的源對象自身的可枚舉屬性拷貝給目標對象,返回目標對象。code

var source = {
    a:{
        b:'hello',
        c:23
    }
}

var copy = Object.assign({},source )

copy.a.b = 'world'
console.log(source.a.b) // world source對象被修改

注意:該方法能夠處理一層的深度拷貝,以下:對象

var source = {a:1,b:2,c:3}
var target = Object.assign({},source)
 target.b = 100;

console.log(source) //{a:1,b:2,c:3}
console.log(target) //{a:1,b:100,c:3}

三、slice()和concat()

 

var a = [1,{a:2},3]
var b = a.slice(1,2)

console.log(a) // [1,{a:2},3]
console.log(b) // [{a:2}]

b[0].a = 100;
console.log(a) // [1,{a:100},3] 被修改了
console.log(b) // [{a:100}]

 

 

var a = [1,{a:2},3]
var b = a.concat(4,5)

console.log(a) // [1,{a:2},3]
console.log(b) // [1,{a:2},3,4,5]

b[1].a = 100;
console.log(a) // [1,{a:100},3] 被修改了
console.log(b) // [1,{a:100},3,4,5]

 

 

 

深拷貝的實現方式

一、手動複製blog

即把一個對象的屬性 複製 到另外一個對象的屬性上。遞歸

要一個一個複製,很麻煩。而且這也不能算是真正的深拷貝,由於對象裏面並未包含複雜類型(對象)

var o1 = {a:1,b:2,c:3}
var o2 = {a:o1.a,b:o1.b,c:o1.c}
o2.a = 4
console.log(o1) //{a:1,b:2,c:3} 沒有被修改
console.log(o2) //{a:4,b:2,c:3}
var source = { a: { b:1 } }
var copy = { a: source.a }

copy.a.b = 2
console.log(source.a.b) // 2 被修改了
console.log(source === copy) //false
console.log(source.a === copy.a) //true

二、Object.assign()方法,對象只有一層深度時可使用

三、轉成JSON再轉回來

JSON.stringify把對象轉成字符串,再用JSON.parse把字符串轉成新的對象。

var source = { a: { b:1} }
var copy = JSON.parse(JSON.stringify(source))

copy.a.b = 2;

console.log(source.a.b) //1 未被修改
console.log(source === copy) //false
console.log(source.a === copy.a) //false

該方法缺點:

  • 會拋棄對象的constructor。不論對象原來的構造函數是什麼,在深拷貝後都會變成Object。
  • 能正確處理的對象只有Number,String,Boolean,Array,扁平對象,即能被JSON直接表示的數據結構
  • RegExp對象沒法經過這種方式深拷貝,即只有轉成JSON格式的對象纔可使用,function沒法轉成JSON
var source = {func:function(){}}
var copy = JSON.parse(JSON.stringify(source))

console.log(typeof source.func) //function
console.log(typeof copy.func) //undefined

四、遞歸拷貝

function deepCopy(target,source){
    var o = target || {}
    for(var i in source){
        if(typeof source[i] === 'object'){
            o[i] = (source[i].constructor === Array) ? [] : {}
            arguments.callee(o[i],source[i])
        }else{
            o[i] = source[i]
        }
    }
    return o;
}

var target= {}
var source = {a: { b:'hello',c:23 }}
deepCopy(target,source)

五、Object.create()

function deepCopy(target,source){
    var o = target || {}
    for(var i in source){
        if(typeof source[i] === 'object'){
            o[i] = (source[i].constructor === Array) ? [] : Object.create(source[i])
       arguments.callee(o[i],source[i]) }
else{ o[i] = source[i] } } return o; } var target= {} var source = {a: { b:'hello',c:23 }} deepCopy(target,source)

六、jQuery 的 $.extend()

var $ = require('jquery');
var source = {
    a: 1,
    b: {x: { y: 1 } },
    c: [1, 2, 3]
};
var copy= $.extend(true, {}, source);

console.log(source.b.x === copy.b.x);// false

七、lodash 的 _.cloneDeep()

var _ = require('lodash');
var source= {
    a: 1,
    b: { x: { y: 1 } },
    c: [1, 2, 3]
};
var copy = _.cloneDeep(source);

console.log(source.b.x=== copy.b.x);// false
相關文章
相關標籤/搜索