Web 前端开发 程序员

因对象深拷贝而思——引用数据类型&基本数据类型

2019-03-11  本文已影响0人  熊猫饲养员文文

先看一个实例

let a = [1,2,3];
let b = a;
console.log(b);          //[1,2,3]
b[0] = 0;
console.log(a);          //[0,1,2]

那么问题来了,在修改了b数组的元素之后,为什么a数组的元素也发生了变化了呢?
在说明这个问题之前我们需要了解JavaScript的数据类型。

基本数据类型&引用数据类型

在学习编程语言时,无论哪种语言都需要先了解该语言环境的数据类型,大多数编程语言中的数据类型都大同小异,在JavaScript中的数据类型大致分为“基本数据类型”和“引用数据类型”两种。

基本数据类型

基本数据类型分为NumberStringBooleanNullUndefined,基本数据类型指的是简单的数据段;

let a = 'hello';
let b = a;
b = 'javascript';

在以上的代码中,我们定义了变量a并且赋值了一个字符串‘string’给他,接着定义一个变量b并且将a赋值给b;那么按照我们正常的理解来说,a和b是等价的,至少值都是‘string’,但是实际在代码的运行环境里呢,他们是毫不相关的两个东西。我们来了解一下以上代码在内存中的表现。


image.png

在创建了一个a的副本b后,由于基本数据类型的原因,a、b两个变量在内存中是两个相互独立的,任意一个的变化都是自己本身的变化,不对其他变量造成影响。

引用数据类型

即对象型类型,如:ObjectArrayFunction等,指的是有多个值构成的对象。和基本数据类型不同的是,引用数据类型不能直接操作内存中的值,而是通过操作数据的引用地址(指针)。

let obj = {name:'xx',age:20};
let obj1 = obj;
obj1.name = 'yy';
console.log(obj);         //{name:'yy',age:20}

改变了obj1对象name属性的值,原始对象obj的name属性值也发生了相同的变化,引起这样的“bug”在于obj和obj1都指向了一个相同的内存地址相同的一个对象,自然在对一个对象引用的属性值操作时,对象本身也会变化。

解决方案

如果有一个需求需要保留原始对象,而操作拷贝出的对象,那么简单的新建变量赋值就不能解决这样的问题。可能在开发过程中或者是面试时,都会听到浅拷贝、深拷贝这样的概念,那么在这篇文章后,相信对于这两个概念应该会是印象深刻。对于深拷贝这样的操作就是为了避免对原始数据的误操作。

/**
 * 引用数据类型的深拷贝
 * @param {*} p : 需要拷贝的原始数据
 * @param {*} c : 拷贝后输出的数据
 */
function deepCopy(p, c) {
    var c = c || {};
    for (var i in p) {
        if (typeof p[i] === "object") {
            c[i] = (p[i].constructor === Array) ? [] : {};
            deepCopy(p[i], c[i])
        } else {
            c[i] = p[i]
        }
    }
    return c;
}
上一篇下一篇

猜你喜欢

热点阅读