JS中数据的分类及深浅copy

JS的数据分类

JS的数据分为两大类型:
一、 基本数据类型 或者说原始数据类型(以下统称基本数据类型)
Undefined – 变量声明但未赋值,或者函数没有返回值
Null – 空
Boolean – 布尔值 true false
Number – 数值型
(JS是弱类型语言,并没有具体到整型浮点型这些 所有的数值 都是Number 包括NaN(数值非法运算的结果))

String – 串
Symbol – ES6新增的 基本数据类型 “symbol类型通常被用作一个对象属性的键值——当你想让它是私有的时候”
这里不详细介绍symbol 类型
简单了解symbol --> 推荐链接
深入了解symbol --> symbol官方介绍

注:值得一提的是 null 的typeof 返回值是object 这也是JS 历史遗留的之一(刚开始设计JS的时候,所有以0开头表示的数据均为Object,似乎是这样的,不太确定,感兴趣可以自行百度)

二、引用数据类型

  • Object 对象:数据的无序集合
  • Array 数组: 数据的有序集合
  • Function 函数
    (Object 是所有引用类型数据 在原型链中的根 这也是“万物皆对象”说法的来源)
基本数据类型和引用数据类型的区别

说到这里就不得不说一下计算机中**栈(stack)堆(heap)**两种数据结构的定义

stack是计算机自动分配的空间,它由系统自动释放。而heap则是动态分配的内存。

借鉴:JS基本数据类型和引用数据类型的区别及深浅拷贝
这里总结一下:
简单来说,基本类型是指被存在于栈中的简单数据段,它们是直接按值存放的,所以可以直接按值访问
栈内存

所以两个基本类型copy后,在重新被赋值时,是不会受影响的,因为b拿到的是a的值,也叫传值

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

但是引用类型却不一样,引用类型是被存放在堆内存的对象,而变量保存的只是栈内存中的指针,这个指针指向堆内存中该对象真正的值,使用这个变量时,计算机通过变量中保存的地址快速找到堆内存中该变量的值。
栈内存和堆内存之间的关系
那么这就造成了引用类型数据在直接copy时的现象(浅拷贝):

var obj1 = new Object();

var obj2 = obj1;

obj2.name = "我有名字了";

console.log(obj1.name); // 我有名字了

obj1 “赋值” 给obj2 后,我们改变obj2的属性和属性值,obj1也跟着改变了,原因就是赋值的时候obj2拿到的只是obj1中保存的指向对象的值的地址,也叫传址,对于引用类型的数据来说,传址就会造成“浅拷贝”。

如何实现深copy?

实现深copy(也就是像基本类型数据那样,达到复制后不会相互影响的目的),首先我们可以遍历传值:

let people1 = {
      name: "林志颖",
      age: 46,
    };
    let people2 = {};
    for (let i in people1) {
      people2[i] = people1[i];
    }
    console.log(people2); // {name: "林志颖", age: 46,}
    people2.name = "郭德纲";
    console.log(people2); // {name: "郭德纲", age: 46,}
    console.log(people1); // {name: "林志颖", age: 46,}

但是,这种只能实现一层的深拷贝,也就是当引用类型数据的元素或者属性值依旧是个引用类型数据时,比如[1, 2, ["a", "b"]] ,这样我们就需要封装一下,利用递归来实现:

function deepCopy(obj, newObj) {
      var newObj = newObj || {};
      for (var i in obj) {
        if (typeof obj[i] === "object") {
          newObj[i] = obj[i].constructor === Array ? [] : {};
          deepCopy(obj[i], newObj[i]);
        } else {
          newObj[i] = obj[i];
        }
      }
      return newObj;
    }
let people1 = {
      name: "林志颖",
      age: 46,
      grade: {
        sing: 99,
        xiangsheng: 60,
      },
    };
    let people2 = {};
deepCopy(people1, people2);
people2.name = "郭德纲";
people2.grade.xiangsheng = 99;
console.log(people1);
console.log(people2);

结果:
在这里插入图片描述
当然,深copy 还有更加粗暴的方式··· 那就是利用JSON的转换:

function deepCopy_JSON(obj) {
      let newObj = obj.constructor === Array ? [] : {};
      newObj = JSON.parse(JSON.stringify(obj));
      return newObj;
    }
    let arr1 = [1, 2, ["a", "b", "c"], { name: "林志颖" }];
    let arr2 = deepCopy_JSON(arr1);
    arr2[2][2] = "d";
    arr2[3].name = "郭德纲";
    console.log(arr1);
    console.log(arr2);

结果:
利用JSON转换深copy结果

补充:关于obj.assign() 是深拷贝还是浅拷贝:(视情况而定)

首先:obj.assign 方法 拷贝的是属性值
也就是说,对于Object.assign()而言, 如果对象的属性值为简单类型(string, number),通过Object.assign({},srcObj);得到的新对象为‘深拷贝’;如果属性值为对象或其它引用类型,那对于这个对象而言其实是浅拷贝的。这是Object.assign()特别值得注意的地方。
补充来源:JS-object.assign

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值