首页 > 编程语言 >JavaScript深浅拷贝

JavaScript深浅拷贝

时间:2022-12-05 15:22:19浏览次数:44  
标签:foo console log JavaScript 深浅 obj 拷贝 let

基本类型 & 引用类型

ECMAScript中的数据类型可分为两种:

  • 基本类型:undefined,null,Boolean,String,Number,Symbol
  • 引用类型:Object,Array,Date,Function,RegExp等

不同类型的存储方式:

  • 基本类型:基本类型值在内存中占据固定大小,保存在栈内存
  • 引用类型:引用类型的值是对象,保存在堆内存中,而栈内存存储的是对象的变量标识符以及对象在堆内存中的存储地址

不同类型的复制方式:

  • 基本类型:从一个变量向另外一个新变量复制基本类型的值,会创建这个值的一个副本,并将该副本复制给新变量
let foo = 1;
let bar = foo;
console.log(foo === bar); // -> true

// 修改foo变量的值并不会影响bar变量的值
let foo = 233;
console.log(foo); // -> 233
console.log(bar); // -> 1
复制代码
  • 引用类型:从一个变量向另一个新变量复制引用类型的值,其实复制的是指针,最终两个变量最终都指向同一个对象
let foo = {
  name: 'leeper',
  age: 20
}
let bar = foo;
console.log(foo === bar); // -> true

// 改变foo变量的值会影响bar变量的值
foo.age = 19;
console.log(foo); // -> {name: 'leeper', age: 19}
console.log(bar); // -> {name: 'leeper', age: 19}
复制代码

深拷贝 & 浅拷贝

  • 浅拷贝:仅仅是复制了引用,彼此之间的操作会互相影响
  • 深拷贝:在堆中重新分配内存,不同的地址,相同的值,互不影响

总的来说,深浅拷贝的主要区别就是:复制的是引用还是复制的是实例

深浅拷贝的实现

看一看原生JavaScript中提供的一些复制方法究竟是深拷贝还是浅拷贝以及动手实现深拷贝。

浅拷贝

  • Array.prototype.slice()
let a = [1, 2, 3, 4];
let b = a.slice();
console.log(a === b); // -> false

a[0] = 5;
console.log(a); // -> [5, 2, 3, 4]
console.log(b); // -> [1, 2, 3, 4]
复制代码
  • Array.prototype.concat()
let a = [1, 2, 3, 4];
let b = a.concat();
console.log(a === b); // -> false

a[0] = 5;
console.log(a); // -> [5, 2, 3, 4]
console.log(b); // -> [1, 2, 3, 4]
复制代码

看起来Array的slice(),concat()似乎是深拷贝,再接着看就知道它们究竟是深拷贝还是浅拷贝:

let a = [[1, 2], 3, 4];
let b = a.slice();
console.log(a === b); // -> false

a[0][0] = 0;
console.log(a); // -> [[0, 2], 3, 4]
console.log(b); // -> [[0, 2], 3, 4]
复制代码

 

slice()

 

同样,对于concat()也进行验证:

let a = [[1, 2], 3, 4];
let b = a.concat();
console.log(a === b); // -> false

a[0][0] = 0;
console.log(a); // -> [[0, 2], 3, 4]
console.log(b); // -> [[0, 2], 3, 4]
复制代码

综上, Array的slice和concat方法并不是真正的深拷贝,对于Array的第一层的元素是深拷贝,而Array的第二层 slice和concat方法是复制引用。所以,Array的slice和concat方法都是浅拷贝

深拷贝

  • JSON.parse()和JSON.stringify()
  1. JSON.stringify():把一个js对象序列化为一个JSON字符串
  2. JSON.parse():把JSON字符串反序列化为一个js对象
let obj = {
  name: 'leeper',
  age: 20,
  friend: {
    name: 'lee',
    age: 19
  }
};
let copyObj = JSON.parse(JSON.stringify(obj));
obj.name = 'Sandman';
obj.friend.name = 'Jerry';
console.log(obj);
// -> {name: "Sandman", age: 20, friend: {age: 19,name: 'Jerry'}}
console.log(copyObj);
// -> {name: "leeper", age: 20, friend: {age: 19,name: 'lee'}}
复制代码

 

deep copy

 

综上,JSON.parse()和JSON.stringify()是完全的深拷贝

  • 动手实现深拷贝 利用递归来实现对对象或数组的深拷贝。递归思路:对属性中所有引用类型的值进行遍历,直到是基本类型值为止。
function deepCopy(obj) {
  if (!obj && typeof obj !== 'object') {
    throw new Error('error arguments');
  }
  // const targetObj = obj.constructor === Array ? [] : {};
  const targetObj = Array.isArray(obj) ? [] : {};
  for (let key in obj) {
    
    //只对对象自有属性进行拷贝
    if (obj.hasOwnProperty(key)) {
      if (obj[key] && typeof obj[key] === 'object') {
        targetObj[key] = deepCopy(obj[key]);
      } else {
        targetObj[key] = obj[key];
      }
    }
  }
  return targetObj;
}

原文链接:https://juejin.cn/post/6844903608010407944

标签:foo,console,log,JavaScript,深浅,obj,拷贝,let
From: https://www.cnblogs.com/xiaoeshuang/p/16952396.html

相关文章

  • 前端基础-03-JavaScript
    JavaScript概述ECMAScript和JavaScript的关系1996年11月,JavaScript的创造者--Netscape公司,决定将JavaScript提交给国际标准化组织ECMA,希望这门语言能够成为国际标准。次......
  • (收藏)javascript变量提升
    函数和变量的声明总是会被解析器悄悄地被“提升”到方法体的最顶部上面是javascript变量提升的概念。为了更好地理解“变量提升”,我们先来看一段代码:(function(){cons......
  • JAVASCRIPT数组小结
    ​数组是值的有序集合。每个值叫做一个元素,而每个元素在数组中有一个位置,以数字表示,称为索引。JavaScript数组是无类型的,数组元素可以是任意类型,并......
  • JavaScript入门⑤-欲罢不能的对象原型与继承-全网一般图文版
    JavaScript入门系列目录JavaScript入门①-基础知识筑基JavaScript入门②-函数(1)基础{浅出}JavaScript入门③-函数(2)原理{深入}执行上下文JavaScript入门④-万物皆......
  • javascript中屏蔽esc键
     今天有客户说网页输入时,不小心按ESC键,结果把结果清除了,想屏蔽,其实是可以的,虽然要求怪怪,JAVASCRIPT可以实现:<scripttype="text/javascr......
  • Web入门:JavaScript文字动画
    欢迎来的我的小院,恭喜你今天又要涨知识了!案例内容利用JavaScript实现文字逐步展现的动画效果。演示学习<!DOCTYPEhtml><htmllang="en"><head><metach......
  • 快来领取,33个常用JavaScript功能已封装成方法,拿来即用
    在实际开发中,为了提高开发的效率,我们会把常用到的功能封装成方法,这样后期开发需要,拿来即用。 这里分享33个在实际开发中经常需要用到的功能(已封装成方法),分享给到大家......
  • 20个既简单又实用的JavaScript小技巧
    原文地址:https://docs.qq.com/doc/DWXBUdGFsZllVcUhZ 1.滚动到页面顶部我们可以使用window.scrollTo()平滑滚动到页面顶部。  const scrollToTop = () =......
  • 7.C++拷贝构造函数
    拷贝构造函数我们经常会用一个变量去初始化一个同类型的变量,那么对于自定义的类型也应该有类似的操作,那么创建对象时如何使用一个已经存在的对象去创建另一个与之相同的对......
  • 前端之JavaScript(Js)基础
    JavaScript,简称JsHTML三把利剑之一,浏览器可解析Js,看着和Java像,实则和Java并无关系,和Python、Go、C++等都是一门独立的语言。一、Js基础引入JavaScript代码,类似于Python......