本人毕业一所专科院校,所学专业是计算机应用技术,在大学时对前端有了一定的了解之后,觉得自己对前端的兴趣十分强烈,开始自学前端,一路上也是坎坎坷坷,也有想要放弃的时候,还好坚持了下来,并且从事前端开发已将近三年,接下来就是谈谈我对深浅拷贝的理解和使用,望平台上的前辈给于关照和支持,若有不恰当之处请您及时指正。


一、js 数据类型

   javaScritp的数据类型有:数值类型、字符串类型、布尔类型、null、undefined、对象(数组、正则表达式、日期、函数),大致分成两种:基本数据类型和引用数据类型。

(1)基本数据类型:数值、字符串、布尔、null、undefined (值类型)、symbol(ES6新增)

(2)复杂(复合)数据类型:对象 (引用类型);

   基本数据类型保存在栈内存引用类型保存在堆内存中。根本原因在于保存在栈内存的必须是大小固定的数据,引用类型的大小不固定,只能保存在堆内存中,但是可以把它的地址写在栈内存中以供我们访问

  如果是基本数据类型,则按值访问,操作的就是变量保存的值;如果是引用类型的值,我们只是通过保存在变量中的引用类型的地址来操作实际对象。

1、复制基本类型数据

var a = 1;

var b = a;//复制

console.log(b)//1;

a = 2;//改变a的值

console.log(b)//1

赋值的时候,在栈内存中重新开辟内存,存放变量b,所以在栈内存中分别存放着变量a、b各自的值,修改时互不影响。

2、复制复杂类型的数据

var color1 = ['red','green'];

var color2 = color1;//复制

console.log(color2)//['red','green'];

color1.push('black') ;//改变color1的值

console.log(color2)//['red','green','black']

color1与color2指向堆内存中同一地址的同一对象,复制的只是引用地址

所以,对于引用类型的复制,简单赋值无用,需要拷贝。拷贝存在两种类型:深拷贝与浅拷贝

二、深浅拷贝的应用

  1. 浅拷贝的实现方式

    (1) Object.assign()

    可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。

    (2) lodash的clone方法

    (3)...操作符

    let obj1 = { name: 'Kobei', address:{x:100,y:100}}
    let obj2= {... obj1}
    obj1.address.x = 200;
    obj1.name = 'wade'
    console.log('obj2',obj2) // obj2 { name: 'Kobe', address: { x: 200, y: 100 } }
    复制代码

    (4) Array.prototype.concat

    let arr = [1,2,3]; let arr2 = [4,5,6];let arr3 = arr.concat(arr2)

    let arr = [1, 3, {
    username: 'kobe'
    }];
    let arr2 = arr.concat();
    arr2[2].username = 'wade';
    console.log(arr);
    复制代码

    (5) Array.prototype.slice

    let arr = [1, 3, {2
    username: ' kobe'
    }];
    let arr3 = arr.slice();
    arr3[2].username = 'wade'
    console.log(arr); // [ 1, 3, { username: 'wade' } ]
    复制代码
  2. 深拷贝的实现方式

    (1) JSON.parse(JSON.stringify())

    可以处理数组和对象的深拷贝,但是不能处理函数和正则,因为这两者基于这两个函数处理后得到的结果不再是正则/函数

    缺点:

     1. 会忽略undefined
    
      	2. 会忽略symbol
    3. 不能序列化函数
    4. 不能解决循环引用的对象
    复制代码

(2) lodash的cloneDeep函数

(3) jQuery.extend函数

(4) 如果所拷贝的对象含有内置对象,但是不包含函数,可以使用messagechannel,可以拷贝undefined和循环引用的对象

  ```javascript
function structuralClone(obj) {
return new Promise(resolve => {
const { port1, port2 } = new MessageChannel()
port2.onmessage = ev => resolve(ev.data)
port1.postMessage(obj)
})
} var obj = {
a: 1,
b: {
c: 2
}
} obj.b.d = obj.b // 注意该方法是异步的
// 可以处理 undefined 和循环引用对象
const test = async () => {
const clone = await structuralClone(obj)
console.log(clone)
}
test()

三、 手写浅拷贝:遍历=>直接等号赋值

// 浅拷贝
let obj1 = {
name : '深深地',
arr : [1,[2,3],4],
};
let obj3=shallowClone(obj1) obj3.name = "春娇";
obj3.arr[1] = [5,6,7] ; // 新旧对象还是共享同一块内存 // 这是个浅拷贝的方法
function shallowClone(source) {
var target = {};
for(var i in source) {
if (source.hasOwnProperty(i)) {
target[i] = source[i];
}
}
return target;
}
console.log('obj1',obj1) // obj1 { name: '深深地', arr: [ 1, [ 5, 6, 7 ], 4 ] }
console.log('obj3',obj3) // obj3 { name: '春娇', arr: [ 1, [ 5, 6, 7 ], 4 ] }
obj.hasOwnProperty,返回值是一个布尔值,即是否是obj的属性(原型上的是false)

最新文章

  1. linux 用户管理
  2. bmp图片的有关操作
  3. Android学习笔记之如何使用圆形菜单实现旋转效果...
  4. java Timer(定时调用、实现固定时间执行)
  5. nginx https
  6. ThinkPHP 自动验证与自动填充无效可能的原因(转)
  7. javascript之值传递与引用传递
  8. Linux 线程优先级
  9. iOS nav加角标
  10. [LeetCode]题解(python):106-Construct Binary Tree from Inorder and Postorder Traversal
  11. 在myeclipse中修改svn帐户
  12. 深入解析java乱码
  13. zTree 勾选checkbox
  14. Linux下全局安装composer
  15. c# linq lambda 去重,排序,取最高纪录。
  16. JMETER-02
  17. Sitecore CMS中更改项目的模板
  18. Linux硬盘分区满,但没有找到占用文件
  19. Sharepoint 2013 多服务器域的目录服务器和搜索服务的配置
  20. 【洛谷】P4207 [NOI2005]月下柠檬树

热门文章

  1. 在Linux下的安装mysql-5.7.28 心得总结
  2. mysql之binlog和各类日志介绍
  3. linux之DNS服务
  4. Spring MVC——项目的开发流程
  5. ctf-工具-binwalk
  6. addslashes()
  7. 几分钟看懂EasyRecovery数据恢复原理,比我想象的简单易懂得多
  8. 如何将各种音频视频素材导入Vegas?
  9. 苹果电脑怎么给浏览器安装Folx扩展程序
  10. ABBYY FineReader 15 中保存和导出PDF文档的小细节