由js深拷贝引起的对内存空间的一些思考

    技术2025-02-16  22

    数据类型

    js常用数据类型分为基本类型和引用类型

    基本类型:null、undefined、数值型、字符串型、布尔型引用类型:数组、对象

    内存空间

    var a = [1, 2, 3]; var b = a; b[2] = 4; a; // ??

    我们都知道结果是[1, 2, 4],因为b和a指向了同一个引用对象所以都可以改变该对象的值,我们用内存空间来深入理解一下。

    我们知道在内存中存在两块区域,一个是栈stack,一个是堆heap。 通常我们的基本数据类型存储在栈中,而我们的引用数据类型存于堆中。栈中会有一个指针指向存在于堆中的数据以便于引用。

    var arr = [1, 2, 3];

    内存图应该是这样:

    arr是一个基本类型的变量,该变量内部存储着数组的地址/指针,通过该地址可以找到存在于heap中的Array对象。通常我们说arr是一个引用类型我觉得是不严谨的,应该说:变量arr指向一个引用类型。

     

    这时候会出现一个问题:允许两个指针指向同一个堆数据,这意味着通过其中一个指针篡改了数值那么会影响另一个指针。

    var a = [1, 2, 3]; var b = a;

    以上变量在内存中的图是这样的:

    解决该问题的方法就是重新在heap中创建一个与a指向的引用对象一模一样的对象,然后让b指向它, 像这样: 这样一个b改变了就不会影响a了。

     

    说个题外话:了解这一机制对理解prototype是有很大好处的

    function Person(name) { this.name = name; } Person.prototype = { sayHi() { console.log("hi, " + this.name); } }; var p1 = new Person('lan'); p1.sayHi(); // 'hi, lan'

    内存图如下,可以自己理解一下,找一找哪些存在于stack哪些存在于heap:

     

    接上述,直接将a赋值为b这样为浅拷贝,而上上图中则为深拷贝。

    js实现深拷贝思路:

    先判断所赋值的类型,如果为基本类型则直接拷贝,若为对象类型则在heap中重新生成一个对象,再递归的将值赋值过去。 function deepCopy(obj) { var result = ''; // 为基本类型 if(obj == null || obj == undefined || typeof obj != 'object') return obj; // 为引用类型,判断为数组还是为对象 if(obj instanceof Array) result = []; else result = {}; for(var key in obj) { var current = obj[key]; if(current == null || current == undefined || typeof current != 'object') result[key] = current; else // 不直接调用deepCopy而用arguments.callee // 以避免函数被赋值给其他变量而出现错误 result[key] = arguments.callee(current); } return result; } var a = { name: 'lan', age: 20, birth: [1,2,3,4], like: { food: 'fruit', color: ['pink', 'blue'] } }; var b = deepCopy(a); b.birth[2] = 5; a.birth; // [1, 2, 3, 4]

    以上为自己对于指针的一点思考,欢迎指正与扩展。

    Processed: 0.009, SQL: 9