js常用数据类型分为基本类型和引用类型
- 基本类型:null、undefined、数值型、字符串型、布尔型
- 引用类型:数组、对象
内存空间
var a = [1, 2, 3];var b = a;b[2] = 4;a; ?// ??
我们都知道结果是[1, 2, 4],因为b和a指向了同一个引用对象所以都可以改变该对象的值,我们用内存空间来深入理解一下。
我们知道在内存中存在两块区域,一个是栈stack,一个是堆heap。 通常我们的基本数据类型存储在栈中,而我们的引用数据类型存于堆中。栈中会有一个指针指向存在于堆中的数据以便于引用。
内存图应该是这样:
arr是一个基本类型的变量,该变量内部存储着数组的地址/指针,通过该地址可以找到存在于heap中的Array对象。通常我们说arr是一个引用类型我觉得是不严谨的,应该说:变量arr指向一个引用类型。
这时候会出现一个问题:允许两个指针指向同一个堆数据,这意味着通过其中一个指针篡改了数值那么会影响另一个指针。
var a = [1, 2, 3];var b = a;
以上变量在内存中的图是这样的:
这样一个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]
以上为自己对于指针的一点思考,欢迎指正与扩展。