JS 基本数据类型和引用数据类型的区别及浅拷贝和深拷贝

JS基本数据类型和引用数据类型

再讲 js 的基本数据类型和引用数据类型之前,我们先说一下栈和堆的概念

1、栈(stack)和堆(heap)
  • 栈(stack):
    栈会自动分配内存空间,会自动释放,存放基本类型,简单的数据段,占据固定大小的空间。
  • 堆(heap):
    动态分配的内存,大小不定也不会自动释放,存放引用类型,指那些可能由多个值构成的对象,保存在堆内存中,包含引用类型的变量,实际上保存的不是变量本身,而是指向该对象的指针。
2、基本数据类型和引用数据类型

1. 基本数据类型NumberStringBooleanNullUndefinedSymbol(ES6),这些类型可以直接操作保存在变量中的实际值

1.1 基本数据类型特点:

  1. 占用空间固定,保存在栈中
    (当一个方法执行时,每个方法都会建立自己的内存栈,在这个方法内定义的变量将会逐个放入这块栈内存里,随着方法的执行结束,
    这个方法的内存栈也将自然销毁了。因此,所有在方法中定义的变量都是放在栈内存中的;栈中存储的是基础变量以及一些对象的引用变量,
    基础变量的值是存储在栈中,而引用变量存储在栈中的是指向堆中的数组或者对象的地址,这就是为何修改引用类型总会影响到其他指向这个地址
    的引用变量)

  2. 保存与复制的是值本身

  3. 使用typeof检测数据的类型

  4. 基本类型数据是值类型

2. 引用数据类型Object(在JS中除了基本数据类型以外的都是对象,数据是对象,函数是对象,正则表达式是对象)

2.1 引用数据类型特点:
6. 占用空间不固定,保存在堆中
(当我们在程序中创建一个对象时,这个对象将被保存到运行时数据区中,以便反复利用(因为对象的创建成本通常较大)
,这个运行时数据区就是堆内存。堆内存中的对象不会随方法的结束而销毁,即使方法结束后,这个对象还可能被另一个引用变量所引用(方法的参数传递时很常见),
则这个对象依然不会被销毁,只有当一个对象没有任何引用变量引用它时,系统的垃圾回收机制才会在核实的时候回收它。)

  1. 保存与复制的是指向对象的一个指针

  2. 使用instanceof检测数据类型

  3. 使用new()方法构造出的对象是引用型

3、基本数据类型(NumberStringBooleanNullUndefinedSymbol(ES6))存放在
  • 基本数据类型是指存放在栈中的简单数据段,数据大小确定,内存空间大小可以分配,它们是直接按值存放的,所以可以直接按值访问
var a = 1;
var b = a;
b = 2;
console.log(a); // 1
console.log(b); // 2

栈内存
在这里插入图片描述

4、引用数据类型(Object)存放在
  • 引用类型是存放在堆内存中的对象,变量其实是保存的在栈内存中的一个指针(保存的是堆内存中的引用地址),这个指针指向堆内存
  • 引用类型数据在栈内存中保存的实际上是对象在堆内存中的引用地址。通过这个引用地址可以快速查找到保存中堆内存中的对象
  var a = {
    name: 'lily',
    age: '16'
  }

  var b = a;
  b.name = 'lokka';

  console.log(a); // {name: "lokka", age: "16"}

把 a 赋值给 b ,就相当于把 a 的内存地址指向 b ,即 a 和 b 指向同一内存地址, 改变了 b 就相当于改变了 a
在这里插入图片描述

浅拷贝和深拷贝

深拷贝和浅拷贝是只针对Object和Array这样的引用数据类型的。
1、概念

浅拷贝:只拷贝一层,深层次的对象级别只拷贝引用。
深拷贝:拷贝多层,每一级别的数据都会被拷贝出来。

2、浅拷贝的实现方式
  1. 方法一:通用循环
function shallowCopy(obj) {
  if (typeof obj !== 'object') return;

  const newObj = obj instanceof Array ? [] : {};

  for(let key in obj) {
    if (obj.hasOwnProperty(key)) {
      newObj[key] = obj[key];
    }
  }

  return newObj;
}
  1. 方法二:Object.assign
const newObj = Object.assign({}, oldObj);

注:对象只有一层是深拷贝

let obj = {
   name: 'lokka'
};
let obj2 = Object.assign({},obj);
obj2.name = 'cola';
console.log(obj);//{username: "lokka"}
  1. 方法三:Array.slice
const newArray = oldArray.slice();
  1. 方法四:Array.concat
const newArray = oldArray.concat();
  1. 方法五:es6
const newObj = { ...oldObj };
const newArray = [ ...oldArray ];
3、深拷贝的实现方式
1. 方法一:通用循环
function deepCopy(obj) {
  if (typeof obj !== 'object') return;

  const newObj = obj instanceof Array ? [] : {};

  for(let key in obj) {
    if (obj.hasOwnProperty(key)) {
      newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];
    }
  }

  return newObj;
}
2. 方法二:JSON.parse、JSON.stringify
const newObj = JSON.parse(JSON.stringify(oldObj));

缺点:
JSON.stringify 只能处理基本对象、数组和基本类型,而其他类型的值在转换之后都可能出现出乎意料的结果,例如 Date 会转化为字符串, Set 会转化为 {}。JSON.stringify甚至完全忽略某些内容,比如undefined或函数。

3. 方法三:structuredClone
const newObj = structuredClone(oldObj);

优点:

  1. 拷贝无限嵌套的对象和数组;
  2. 拷贝循环引用;
  3. 拷贝各种 JavaScript 类型,例如Date、Set、Map、Error、RegExp、ArrayBuffer, Blob、File、ImageData等;
  4. 拷贝同样,所使用的结构化克隆算法也structuredClone()不能克隆 DOM 元素。将 HTMLElement 对象传递给structuredClone()将导致如上所示的错误。
  5. 任何可转移的对象。

不能拷贝:

  1. 函数或方法
  2. DOM 节点
  3. 属性描述符、setter 和 getter
  4. 对象原型
4. 使用第三方库,比如 lodash、jquery 等

import lodash from 'lodash';
 
const newObj = lodash.cloneDeep(oldObj);

  • 5
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值