Javascript中数据类型&深浅拷贝二

数据类型:

Javascript中有5种基本数据类型(简单数据类型),分别为:Undefined, Null, Boolean, Number和String; 同时还含有一种复杂数据类型,即对象(虽然js中一切皆为对象)

其中Undefined和Null的区别为:

Undefined: 其实是已申明,但是并未赋值的变量,输出的结构就是undefined
Null:是一个不存在的对象的结果

例如:

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

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

数据的存储

* 简单数据类型的存储

简单数据类型的值占据了内存中固定的存储空间,并被保存在栈内存中;

当复制一个简单数据类型的值时,会创建这个值的一个副本,该副本会另行开辟一块栈内存空间,改变该副本的值,不会影响原始变量的值。

var a = 'name';
var b = a;    // 将a的值赋给变量b
b = 'age';    // 改变b的值
console.log(a);   // name
console.log(b);   // age;

: 简单数据类型的变量,不能给其添加属性

var str = 'javascript';
str.attr ='cat';         // 给基本数据类型添加属性
console.log(str.attr);   // undefined
* 复杂数据类型的存储

复杂数据类型即引用数据类型,它的值是对象,保存在堆内存中,包含引用数据类型的变量实际上包含的并不是对象本身,而是一个指向该对象的指针。

所以直接将一个复杂数据类型的变量,赋给另一个变量,实际上只是复制了该变量的指针,因此,两个变量实际上都指向同一个对象

当修改其中一个变量的值时,原始的变量也会跟着改变。

var obj = {
    name:'dby',
    age: 20
};
var objCopy = obj;  // 复制obj给objCopy
objCopy.name = 'mxd';  // 改变复制的变量的属性
console.log(obj);   // Object{name:'mxd',age:20}
console.log(objCopy);   // Object{name:'mxd',age:20}

深浅拷贝

浅拷贝

其实直接赋值就算是一种浅拷贝,对于基本数据类型的简单赋值,是在栈内存中另行开辟了一片存储空间,对拷贝过来的值进行改变,不会改变原始数据的值。

但是复杂数据类型的值赋值,只是复制了指向该值的指针,当赋值后的值改变时,原始数据的值也会跟随改变,在实际工程中,这是我们不希望的

var obj = {
    name:'dby',
    age: 20
};
var objCopy = obj;  // 复制obj给objCopy
objCopy.name = 'mxd';  // 改变复制的变量的属性
console.log(obj);   // Object{name:'mxd',age:20}
console.log(objCopy);   // Object{name:'mxd',age:20}

slice实现数组的拷贝

const arr = [1,3,4,5,6];
const arr1 = arr.slice(arr);
arr1[1] = 22; // 修改arr1的某个元素
console.log(arr);   // [1,3,4,5,6]
console.log(arr1); // [1,22,4,5,6]

note: 由上面可以看到我们可以使用数组的原生方法进行数组的拷贝,但这个拷贝是不是深拷贝呢?,进一步实验一下:

const arr = [1,3,4,5,[1,3]];
const arr1 = arr.slice(arr);
arr1[4][0] = 222;
console.log(arr);  // [1,3,4,5,[222,3]] 原始数组被更改了
console.log(arr1);  // [1,3,4,5,[222,3]] 

由这个小实验可知,slice只能实现一维数组的深拷贝,不能实现多维数组的深拷贝

Object.assign()实现对象的拷贝

const obj = {
    x: 1,
    y: 2
};
const obj1 = Object.assign({}, obj);
console.log(obj1);  // { x: 1, y: 2}
obj1.x = 222;
console.log(obj);  // { x: 1, y: 2 }
console.log(obj1); // {x: 222, y: 2 } 实现了对象的深拷贝,没有改变原对象

const obj2 = {
    x: 1,
    y: {
        m: 2
    }
};
const obj3 = Object.assign({}, obj2);
console.log(obj3); // { x: 1, y: { m: 2 } }
obj3.y.m = 222; // 修改obj3的属性值
console.log(obj2); // { x: 1, y: { m: 222 } }   // 将原对象也更改了
console.log(obj3); // { x: 1, y: { m: 222 } }

由此可见,Object.assign()方法也只能实现一维对象的深拷贝,不能实现多维对象的深拷贝

深拷贝
数组
数组的深拷贝,可是借用数组的方法slice()和concat()来解决,有局限性,只能实现一维数组的深拷贝

slice

var arr = ['cat','dog','mouse'];
var arrCopy = arr.slice(0);   // 返回arr中0-(length-1)长度的数组,不会改变原数组
arrCopy[0] = 'tigger';    // 改变arrCopy第一项为tigger
console.log(arr);   // ['cat','dog','mouse']
console.log(arrCopy);      // ['tigger','dog','mouse']

concat

var arr = ['cat','dog','mouse'];
var arrCopy = arr.concat();       // arrCopy = ['cat','dog','mouse'];
arrCopy[0] = 'tigger';            // 改变arrCopy第一项为tigger
console.log(arr);                 // ['cat','dog','mouse']
console.log(arrCopy);            // ['tigger','dog','mouse']

对象
方法一:通过定义一个新的对象,并遍历原对象,将属性逐一拷贝上去。

var obj = {
            name:'dby',
            age:20
        };
var objCopy = new Object();
objCopy.name = obj.name;
objCopy.age = obj.age;

objCopy.name = 'chris';
console.log(obj);         // Object{name:'dby',age:20}
console.log(objCopy);       // Object{name:'chris',age:20}

方法二:封装一个方法来处理对象的深拷贝

var obj = {
            name:'dby',
            age:20
        };
var deepCopy = function(source){     // 对象深拷贝函数
    var result = {};
    for(var key in source){
        if(typeof source[key] === 'object'){    
            // 如果属性为object类型,则递归调用深拷贝函数
            result[key] = deepCopy(source[key]);  
        }else{
            result[key] = source[key];
        }
    }
    return result;
}

var objCopy = deepCopy(obj);
objCopy.name = 'chris';

console.log(obj);         // Object{name:'dby',age:20}
console.log(objCopy);       // Object{name:'chris',age:20}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值