js数据类型以及深拷贝浅拷贝总结

一、js数据类型

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

基本数据类型包括:String Number Boolean Undefined Null Symbol   其特点为:存储在栈内存中

PS:Null与Undefined区别:
当声明的变量还未被初始化时,变量的默认值为Undefined;typeof Undefined 返回值为Undefined

Null 用来表示尚未存在的对象,表示空对象指针,常用来表示函数企图返回一个不存在的对象。typeof null 返回值为object

引用类型包括:array object function   其特点:值为对象,保存在堆内存中。复制时创建指针的副本,指向的是同一对象

注:为什么基础数据类型存在栈中,而引用数据类型存在堆中呢?

  1. 堆比栈大,栈比对速度快。
  2. 基础数据类型比较稳定,而且相对来说占用的内存小。
  3. 引用数据类型大小是动态的,而且是无限的。
  4. 堆内存是无序存储,可以根据引用直接获取。

在参数传递方式上,值类型是按值传递,引用类型是按共享传递。

var a=10;
var b=a;
b=20;
console.log(a);//10
console.log(b);//20

两者之间赋值没有影响
var a={x:10,y:20};
var b=a;
b.x=30;
console.log(b.x);//30
console.log(a.x);//30
因为a和b都是引用类型,指向了同一个内存地址,即两者引用的是同一个值,因此b修改属性时,a的值随之改动。
function foo(a){ a = a * 10; }
 function bar(b){ b.value = 'new'; } 
var a = 1; 
var b = {value: 'old'};
foo(a); 
bar(b); 
console.log(a); // 1 
console.log(b); // value: new 

通过代码执行,会发现: a的值没有发生改变 而b的值发生了改变 这就是因为Number类型的a是按值传递的,而Object类型的b是按共享传递的。

另外:

 var obj = { a: 1, b: [1,2,3] } 
var a = obj.a 
var b = obj.b
 a = 2
 b.push(4)
 console.log(obj, a, b) 

结果为:{ a: 1, b: [ 1, 2, 3, 4 ] } 2 [ 1, 2, 3, 4 ]

因为虽然obj本身是个引用类型的变量(对象),但是内部的a和b一个是值类型一个是引用类型,a的赋值不会改变obj.a,但是b的操作却会反映到obj对象上。

 

二、深拷贝与浅拷贝

如何区分深拷贝与浅拷贝,简单点来说,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,拿人手短,如果B没变,那就是深拷贝。

浅拷贝实现方式:

1.简单的赋值语句

2.Object.assign()

Object.assign是ES6的新函数。Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。但是 Object.assign() 进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象本身。

Object.assign(target, ...sources)

参数:

target:目标对象。
sources:任意多个源对象。
返回值:目标对象会被返回。

var obj = { a: {a: "hello", b: 21} };
var initalObj = Object.assign({}, obj);

initalObj.a.a = "changed";
console.log(obj.a.a); // "changed"

需要注意的是:

Object.assign()可以处理一层的深度拷贝,如下
var obj1 = { a: 10, b: 20, c: 30 };
var obj2 = Object.assign({}, obj1);
obj2.b = 100;
console.log(obj1);
// { a: 10, b: 20, c: 30 } <-- 沒被改到
console.log(obj2);
// { a: 10, b: 100, c: 30 }

深拷贝实现方式:

  1. 利用 JSON 对象中的 parse 和 stringify

     用JSON.stringify把对象转成字符串,再用JSON.parse把字符串转成新的对象。

var obj1 = { body: { a: 10 } };
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.body.a = 20;
console.log(obj1);
// { body: { a: 10 } } <-- 沒被改到
console.log(obj2);
// { body: { a: 20 } }
console.log(obj1 === obj2);
// false
console.log(obj1.body === obj2.body);
// false

 

这样做是真正的Deep Copy,这种方法简单易用。

但是这种方法也有不少坏处,譬如它会抛弃对象的constructor。也就是深拷贝之后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成Object。

这种方法能正确处理的对象只有 Number, String, Boolean, Array, 扁平对象,即那些能够被 json 直接表示的数据结构。RegExp对象是无法通过这种方式深拷贝。

也就是说,只有可以转成JSON格式的对象才可以这样用,像function没办法转成JSON。

var obj1 = { fun: function(){ console.log(123) } };
var obj2 = JSON.parse(JSON.stringify(obj1));
console.log(typeof obj1.fun);
// 'function'
console.log(typeof obj2.fun);
// 'undefined' <-- 没复制

    2.利用递归来实现每一层都重新创建对象并赋值

function deepClone(initalObj, finalObj) {    
  var obj = finalObj || {};    
  for (var i in initalObj) {        
    if (typeof initalObj[i] === 'object') {
      obj[i] = (initalObj[i].constructor === Array) ? [] : {};            
      arguments.callee(initalObj[i], obj[i]);
    } else {
      obj[i] = initalObj[i];
    }
  }    
  return obj;
}
var str = {};
var obj = { a: {a: "hello", b: 21} };
deepClone(obj, str);
console.log(str.a);

 

  3.对象只有一层的话可以使用上面的:Object.assign()函数

Object.assign({}, obj1)的意思是先建立一个空对象{},接着把obj1中所有的属性复制过去,所以obj2会长得跟obj1一样,这时候再修改obj2.b也不会影响obj1。

 

参考链接:https://www.cnblogs.com/Chen-XiaoJun/p/6217373.html

                  https://www.jb51.net/article/135921.htm

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值