浅拷贝 与 深拷贝

目录

[1、JavaScript 中存在两⼤数据类型:](#1、JavaScript 中存在两⼤数据类型:)

[2、 浅拷贝方法:](#2、 浅拷贝方法:)

[2.1 Object.assign](#2.1 Object.assign)

[2.2 slice()](#2.2 slice())

[2.3 concat()](#2.3 concat())

[2.4 拓展运算符](#2.4 拓展运算符)

3、深拷贝方法

[3.1 _.cloneDeep()](#3.1 _.cloneDeep())

[3.2 jQuery.extend()](#3.2 jQuery.extend())

[3.3 JSON.stringify()](#3.3 JSON.stringify())

[3.4 循环递归](#3.4 循环递归)

4、浅拷贝和深拷贝的区别


1、JavaScript 中存在两⼤数据类型:

• 基本类型

• 引⽤类型

基本类型数据保存在在栈内存中

引⽤类型数据保存在堆内存中,引⽤数据类型的变量是⼀个指向堆内存中实际对象的引⽤,存在栈中

2、 浅拷贝方法:

在 JavaScript 中,存在浅拷⻉的现象有:

• Object.assign

• Array.prototype.slice() , Array.prototype.concat()

• 使⽤拓展运算符实现的复制

javascript 复制代码
function shallowClone(obj) { 
    const newObj = {}; 
    for(let prop in obj) { 
         if(obj.hasOwnProperty(prop)){ // 仅检查对象自身是否包含指定属性,不追溯原型链
            newObj[prop] = obj[prop]; 
         } 
     } 
    return newObj; 
}
2.1 Object.assign
javascript 复制代码
var obj = { 
     age: 18, 
     nature: ['smart', 'good'], 
     names: { 
         name1: 'fx', 
        name2: 'xka' 
     }, 
    love: function () { 
        console.log('fx is a great girl') 
     } 
} 
var newObj = Object.assign({}, fxObj);
2.2 slice()
javascript 复制代码
const fxArr = ["One", "Two", "Three"] 
const fxArrs = fxArr.slice(0)
fxArrs[1] = "love";
console.log(fxArr) // ["One", "Two", "Three"]
console.log(fxArrs) // ["One", "love", "Three"]
2.3 concat()
javascript 复制代码
const fxArr = ["One", "Two", "Three"]
const fxArrs = fxArr.concat()
fxArrs[1] = "love";
console.log(fxArr) // ["One", "Two", "Three"]
console.log(fxArrs) // ["One", "love", "Three"]
2.4 拓展运算符
javascript 复制代码
const fxArr = ["One", "Two", "Three"]
const fxArrs = [...fxArr]
fxArrs[1] = "love";
console.log(fxArr) // ["One", "Two", "Three"]
console.log(fxArrs) // ["One", "love", "Three"]

3、深拷贝方法

深拷⻉开辟⼀个新的栈,两个对象属完成相同,但是对应两个不同的地址,修改⼀个对象的属性,不 会改变另⼀个对象的属性

常⻅的深拷⻉⽅式有:

• _.cloneDeep()

• jQuery.extend()

• JSON.stringify()

• ⼿写循环递归

3.1 _.cloneDeep()
javascript 复制代码
const _ = require('lodash');
const obj1 = { 
    a: 1, 
    b: { f: { g: 1 } }, 
    c: [1, 2, 3] 
}; 
const obj2 = _.cloneDeep(obj1); 
console.log(obj1.b.f === obj2.b.f);// false
3.2 jQuery.extend()
javascript 复制代码
const 
$ = require('jquery'); 
const obj1 = { 
    a: 1, 
    b: { f: { g: 1 } }, 
    c: [1, 2, 3] 
};
const obj2 = $
.extend(true, {}, obj1); 
console.log(obj1.b.f === obj2.b.f); // false
3.3 JSON.stringify()
javascript 复制代码
const obj2=JSON.parse(JSON.stringify(obj1));

// 但是这种⽅式存在弊端,会忽略 undefined 、 symbol 和 函数

const obj = { 
    name: 'A', 
    name1: undefined, 
    name3: function() {}, 
    name4: Symbol('A') 
} 
const obj2 = JSON.parse(JSON.stringify(obj)); 
console.log(obj2); // {name: "A"}

**但有局限,**无法实现对象中方法的深拷贝、值为undefined的key等。

javascript 复制代码
// 无法对 对象中的方法 进行深拷贝
const obj = { fn: () => console.log('test') };
const copy = JSON.parse(JSON.stringify(obj)); // { }


// undefined 和 Symbol 类型属性会消失
// NaN 和 Infinity 会被转为 null
const obj = { a: undefined, b: Symbol(), c: NaN };
const copy = JSON.parse(JSON.stringify(obj)); // { c: null }
3.4 循环递归

思路步骤:

  1. 处理基本值‌:当传入值为null或非object类型时直接返回原值。不拷贝(对基本类型直接返回,引用类型才进行拷贝操作)
  2. ‌检查循环引用‌:用WeakMap缓存已拷贝对象,遇到直接返回
  3. ‌特殊对象处理‌:单独拷贝日期和正则对象
  4. ‌初始化容器‌:区分数组和普通对象创建空结构
  5. ‌递归拷贝属性‌:遍历每个属性并递归调用自身

// 使用 WeakMap 存储已拷贝对象,遇到重复引用直接返回

// hash.has(obj) 是哈希表结构中用于检测键是否存在的核心方法

// hash.get(obj) 是哈希表结构中通过键获取对应值的核心操作

// hash.set(obj, clone) 是哈希表存储键值对的核心操作

// 仅检查对象自身是否包含指定属性,不追溯原型链

javascript 复制代码
function deepClone(obj, hash = new WeakMap()) {
    // 基础类型直接返回
  if (obj === null || typeof obj !== 'object') return obj; // 当传入值为null或非object类型时直接返回原值
    // 用WeakMap缓存已拷贝对象,遇到直接返回
  if (hash.has(obj)) return hash.get(obj); // 处理循环引用

    // 特殊对象处理
  if (obj instanceof Date) return new Date(obj);
  if (obj instanceof RegExp) return new RegExp(obj);
  
    // 初始化容器
  const clone = Array.isArray(obj) ? [] : {};
  hash.set(obj, clone);
  
    // 递归拷贝
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      clone[key] = deepClone(obj[key], hash);
    }
  }
  return clone;
}

4、浅拷贝和深拷贝的区别

前提为拷⻉类型为引⽤类型的情况下:

• 浅拷⻉是拷⻉⼀层,属性为对象时,浅拷⻉是复制,两个对象指向同⼀个地址

• 深拷⻉是递归拷⻉深层次,属性为对象时,深拷⻉是新开栈,两个对象指向不同的地址

声明变量时:

◦ 简单类型的值存放在栈中,在栈中存放的是对应的值

◦ 引⽤类型对应的值存储在堆中,在栈中存放的是指向堆内存的地址

赋值变量时:

◦ 简单类型赋值,是⽣成相同的值,两个对象对应不同的地址

◦ 复杂类型赋值,是将保存对象的内存地址赋值给另⼀个变量。也就是两个变量指向堆内存中同⼀个对象

相关推荐
zwjapple3 小时前
docker-compose一键部署全栈项目。springboot后端,react前端
前端·spring boot·docker
像风一样自由20205 小时前
HTML与JavaScript:构建动态交互式Web页面的基石
前端·javascript·html
aiprtem5 小时前
基于Flutter的web登录设计
前端·flutter
浪裡遊6 小时前
React Hooks全面解析:从基础到高级的实用指南
开发语言·前端·javascript·react.js·node.js·ecmascript·php
why技术6 小时前
Stack Overflow,轰然倒下!
前端·人工智能·后端
GISer_Jing6 小时前
0704-0706上海,又聚上了
前端·新浪微博
止观止6 小时前
深入探索 pnpm:高效磁盘利用与灵活的包管理解决方案
前端·pnpm·前端工程化·包管理器
whale fall6 小时前
npm install安装的node_modules是什么
前端·npm·node.js
烛阴6 小时前
简单入门Python装饰器
前端·python
袁煦丞7 小时前
数据库设计神器DrawDB:cpolar内网穿透实验室第595个成功挑战
前端·程序员·远程工作