Skip to content

Javascript深浅拷贝 #57

Open
Open
@Wscats

Description

@Wscats
Owner

Javascript有六种基本数据类型(也就是简单数据类型),它们分别是:Undefined,Null,Boolean,Symbol,Number和String。还含有一种复杂数据类型,就是对象

注意Undefined和Null的区别,Undefined类型只有一个值,就是undefined,Null类型也只有一个值,也就是null
Undefined其实就是已声明未赋值的变量输出的结果
null其实就是一个不存在的对象的结果

var c;
console.log(c)//undefined

console.log(document.getElementById('wsscat'))//没有id为wsscat的节点,输出null

简单的数据类型和复杂的数据类型有以下重要的区别

对于简单数据类型

它们值在占据了内存中固定大小的空间,并被保存在栈内存中。当一个变量向另一个变量复制基本类型的值,会创建这个值的一个副本,还有就是不能给基本数据类型的值添加属性

var a = 1;
var b = a;
a.attr = 'wsscat';
console.log(a.attr)//undefined

上面代码中a就是简单数据类型(Number),b就是a的副本,它们两者都占有不同位置但相等的内存空间

对于复杂的数据类型

复杂的数据类型即引用类型,它的值是对象,保存在堆内存中,包含引用类型值的变量实际上包含的并不是对象本身,而是一个指向该对象的指针。从一个变量向另一个变量复制引用类型的值,复制的其实是指针,因此两个变量最终都指向同一个对象。

var obj = {
    name:'wsscat',
    age:0
}
var obj2 = obj;
obj2['c'] = 5;
console.log(obj);//Object {name: "wsscat", age: 0, c: 5}
console.log(obj2);////Object {name: "wsscat", age: 0, c: 5}

qq20161016-0

我们可以看到obj赋值给obj2后,当我们更改其中一个对象的属性值,两个对象都发生了改变,究其原因局势因为obj和obj2这两个变量都指向同一个指针,赋值只是复制了指针,所以当我们改变其中一个的值就会影响另外一个变量的值

浅拷贝

其实这段代码就是浅拷贝,有时候我们只是想备份数组,但是只是简单让它赋给一个变量,改变其中一个,另外一个就紧跟着改变,但很多时候这不是我们想要的

var obj = {
    name:'wsscat',
    age:0
}
var obj2 = obj;
obj2['c'] = 5;
console.log(obj);//Object {name: "wsscat", age: 0, c: 5}
console.log(obj2);////Object {name: "wsscat", age: 0, c: 5}

深拷贝

数组
对于数组我们可以使用slice()concat()方法来解决上面的问题
slice

var arr = ['wsscat', 'autumns', 'winds'];
var arrCopy = arr.slice(0);
arrCopy[0] = 'tacssw'
console.log(arr)//['wsscat', 'autumns', 'winds']
console.log(arrCopy)//['tacssw', 'autumns', 'winds']

concat

var arr = ['wsscat', 'autumns', 'winds'];
var arrCopy = arr.concat();
arrCopy[0] = 'tacssw'
console.log(arr)//['wsscat', 'autumns', 'winds']
console.log(arrCopy)//['tacssw', 'autumns', 'winds']

对象
对象我们可以定义一个新的对象并遍历新的属性上去实现深拷贝

var obj = {
    name:'wsscat',
    age:0
}

var obj2 = new Object();
obj2.name = obj.name;
obj2.age = obj.age

obj.name = 'autumns';
console.log(obj);//Object {name: "autumns", age: 0}
console.log(obj2);//Object {name: "wsscat", age: 0}

当然我们可以封装好一个方法来处理对象的深拷贝,代码如下

var obj = {
    name: 'wsscat',
    age: 0
}
var deepCopy = function(source) {
    var result = {};
    for(var key in source) {
        if(typeof source[key] === 'object') {
            result[key] = deepCopy(source[key])
        } else {
            result[key] = source[key]
        }
    }
    return result;
}
var obj3 = deepCopy(obj)
obj.name = 'autumns';
console.log(obj);//Object {name: "autumns", age: 0}
console.log(obj3);//Object {name: "wsscat", age: 0}

Activity

changed the title [-]Javascript[/-] [+]Javascript基本数据类型[/+] on Oct 13, 2016
changed the title [-]Javascript基本数据类型[/-] [+]Javascript基本数据类型&&深浅拷贝[/+] on Oct 16, 2016
changed the title [-]Javascript基本数据类型&&深浅拷贝[/-] [+]Javascript深浅拷贝[/+] on Oct 16, 2016
Wscats

Wscats commented on Nov 5, 2016

@Wscats
OwnerAuthor

Javascript数组存放函数

在javascript中函数也是一种数据,能够像操作一个对象对它进行操作。并且javascript不进行数据类型检查,数组可以存放任何东西,在下面代码中我们不但在数组中存放了函数,并且也可以在存放一个执行函数的返回值,所以数组前两个数据存放都是函数执行返回值

var funcA = function() {
    console.log("funcA");
    return "hello funA";
}
var funcB = function() {
    console.log("funcB");
    return "hello funB";
}
var funcC = function() {
    console.log("funcC");
    return "hello funC";
}
var arr = [funcA(), funcB(), funcC];
console.log(arr);
arr[2]();

输出的结果如下
qq20161105-0

dcy0701

dcy0701 commented on Dec 16, 2016

@dcy0701

对象中不含有函数的话。JSON解析反解析就行了

ghost

ghost commented on Dec 18, 2016

@ghost

深拷贝

数组
对于数组我们可以使用slice()和concat()方法来解决上面的问题
silce
...

应该是手滑了吧,silce -> slice

Wscats

Wscats commented on Dec 18, 2016

@Wscats
OwnerAuthor

谢谢,已更正~

GreenMelon

GreenMelon commented on Dec 18, 2016

@GreenMelon

ES6中有 Object.assign() 方法,应该也可以解决你对于深克隆的需求吧?

HeftyKoo

HeftyKoo commented on Dec 22, 2016

@HeftyKoo

image
concat 和slice对对象数组没有效果的?

flynntsc

flynntsc commented on Dec 28, 2016

@flynntsc

@GreenMelon Object.assign()方法不适于深拷贝,MDN上有说明

flynntsc

flynntsc commented on Dec 28, 2016

@flynntsc

@yeyuqiudeng concat和slice主要是针对基本数据类型数组的深拷贝,牵涉到多层复杂数据类型即对象的就要再对{a:{b:1}进行深拷贝。有兴趣的话,可对Underscore、Lodash 和 JQuery的源码进行学习,相关文章《深入剖析 JavaScript 的深复制

HeftyKoo

HeftyKoo commented on Dec 28, 2016

@HeftyKoo

@flynntsc 嗯嗯,谢谢

specialCoder

specialCoder commented on Jan 17, 2017

@specialCoder

我这里实现了对象包括数组的深拷贝:

Object.prototype.deepCopy=function(){
    var obj=null;//用于最后返回一个对象,这个对象是深复制的结果
    for(var attr in this){//遍历这个对象的每一个属性
        if(this.hasOwnProperty(attr)){//主要是递归自有属性
            if(typeof (this[attr]==='object')){//如果对象的属性是一个对象,就递归复制它的每一个属性
                if(this[attr]===null){//如果对象为null
                    obj[attr]=null;
                }else if(Object.prototype.toString(this[attr])==='[object Array]'){//如果是个数组
                    obj[attr]=[];
                    for(var i=0;i<this[attr].length;i++){
                        obj[attr].push(this[attr][i].deepCopy());
                    }
                }else{//object
                    obj[attr]=this[attr].deepCopy();
                }
            }else{
                obj[attr]=this[attr];
            }
        }
    }
    return obj;
}

20 remaining items

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @flynntsc@HeftyKoo@dcy0701@GreenMelon@refanbanzhang

        Issue actions

          Javascript深浅拷贝 · Issue #57 · Wscats/articles