关于Javascript 深拷贝

关于

Javascript 深拷贝

javascript深拷贝是初学者甚至有经验的开发者,都会经常遇到问题,并不能很好的理解javascript的深拷贝。

深拷贝(deepClone)?

与深拷贝相对的就是浅拷贝,很多

HTML5课程

初学者在接触这个感念的时候,是很懵逼的。

为啥要用深拷贝?

在很多情况下,我们都需要给变量赋值,给内存地址赋予一个值,但是在赋值引用值类型的时候,只是共享一个内存区域,导致赋值的时候,还跟之前的值保持一直性。

看一个具体的例子

JavaScript

// 给test赋值了一个对象

var test = {

a: ‘a‘,

b: ‘b‘

};

// 将test赋值给test2

// 此时test和test2是共享了同一块内存对象,这也就是浅拷贝

var test2 = test;

test2.a = ‘a2‘;

test.a === ‘a2‘// 为true

// 给test赋值了一个对象

var test = {

a: ‘a‘,

b: ‘b‘

};

// 将test赋值给test2

// 此时test和test2是共享了同一块内存对象,这也就是浅拷贝

var test2 = test;

test2.a = ‘a2‘;

test.a === ‘a2‘// 为true

这下就很好理解为什么引用值类型数据相互影响问题。

实现

实现一个深拷贝函数,就不得不说javascript的数值类型。

判断javascript类型

javascript中有以下基本类型

类型

描述

undefinedundefined类型只有一个值undefined,它是变量未被赋值时的值

nullnull类型也只有一个值null, 它是一个空的对象引用

BooleanBoolean有两种取值true和false

String它表示文本信息

Number它表示数字信息

Object它是一系列属性的无序集合, 包括函数Function和数组Array

使用typeof是无法判断function和array的,这里使用Object.prototype.toString方法。 默认情况下,每个对象都会从Object上继承到toString()方法,如果这个方法没有被这个对象自身或者更接近的上层原型上的同名方法覆盖(遮蔽),则调用该对象的toString()方法时会返回”[object type]”,这里的字符串type表示了一个对象类型

JavaScript

function type(obj) {

var toString = Object.prototype.toString;

var map = {

‘[object Boolean]‘  : ‘boolean‘,

‘[object Number]‘   : ‘number‘,

‘[object String]‘   : ‘string‘,

‘[object Function]‘ : ‘function‘,

‘[object Array]‘    : ‘array‘,

‘[object Date]‘     : ‘date‘,

‘[object RegExp]‘   : ‘regExp‘,

‘[object Undefined]‘: ‘undefined‘,

‘[object Null]‘     : ‘null‘,

‘[object Object]‘   : ‘object‘

};

return map[toString.call(obj)];

}

function type(obj) {

var toString = Object.prototype.toString;

var map = {

‘[object Boolean]‘  : ‘boolean‘,

‘[object Number]‘   : ‘number‘,

‘[object String]‘   : ‘string‘,

‘[object Function]‘ : ‘function‘,

‘[object Array]‘    : ‘array‘,

‘[object Date]‘     : ‘date‘,

‘[object RegExp]‘   : ‘regExp‘,

‘[object Undefined]‘: ‘undefined‘,

‘[object Null]‘     : ‘null‘,

‘[object Object]‘   : ‘object‘

};

return map[toString.call(obj)];

}

实现deepClone

对于非引用值类型的数值,直接赋值,而对于引用值类型(object)还需要再次遍历,递归赋值。

JavaScript

function deepClone(data) {

var t = type(data), o, i, ni;

if(t === ‘array‘) {

o = [];

}else if( t === ‘object‘) {

o = {};

}else {

return data;

}

if(t === ‘array‘) {

for (i = 0, ni = data.length; i < ni; i++) {

o.push(deepClone(data[i]));

}

return o;

}else if( t === ‘object‘) {

for( i in data) {

o[i] = deepClone(data[i]);

}

return o;

}

}

function deepClone(data) {

var t = type(data), o, i, ni;

if(t === ‘array‘) {

o = [];

}else if( t === ‘object‘) {

o = {};

}else {

return data;

}

if(t === ‘array‘) {

for (i = 0, ni = data.length; i < ni; i++) {

o.push(deepClone(data[i]));

}

return o;

}else if( t === ‘object‘) {

for( i in data) {

o[i] = deepClone(data[i]);

}

return o;

}

}

这里有个点大家要注意下,对于function类型,博主这里是直接赋值的,还是共享一个内存值。这是因为函数更多的是完成某些功能,有个输入值和返回值,而且对于上层业务而言更多的是完成业务功能,并不需要真正将函数深拷贝。

但是function类型要怎么拷贝呢?

其实博主只想到了用new来操作一下,但是function就会执行一遍,不敢想象会有什么执行结果哦!其它暂时还没有什么好的想法,欢迎大家指导哦!

到这里差不多也就实现完了深拷贝,又有人觉的怎么没有实现浅拷贝呢?

浅拷贝?

对于浅拷贝而言,可以理解为只操作一个共同的内存区域!这里会存在危险!。

如果直接操作这个共享的数据,不做控制的话,会经常出现数据异常,被其它部分更改。所以应该不要直接操作数据源,给数据源封装一些方法,来对数据来进行CURD操作。

到这里估计就差不多了,但是作为一个前端,不仅仅考虑javascript本身,还得考虑到dom、浏览器等。

Element类型

来看下面代码,结果会返回啥呢?

JavaScript

Object.prototype.toString.call(document.getElementsByTagName(‘div‘)[0])

1

Object.prototype.toString.call(document.getElementsByTagName(‘div‘)[0])

答案是[object HTMLDivElement]

有时候保存了dom元素, 一不小心进行深拷贝,上面的深拷贝函数就缺少了对Element元素的判断。而判断Element元素要使用instanceof来判断。因为对于不同的标签,tostring会返回对应不同的标签的构造函数。

JavaScript

function type(obj) {

var toString = Object.prototype.toString;

var map = {

‘[object Boolean]‘  : ‘boolean‘,

‘[object Number]‘   : ‘number‘,

‘[object String]‘   : ‘string‘,

‘[object Function]‘ : ‘function‘,

‘[object Array]‘    : ‘array‘,

‘[object Date]‘     : ‘date‘,

‘[object RegExp]‘   : ‘regExp‘,

‘[object Undefined]‘: ‘undefined‘,

‘[object Null]‘     : ‘null‘,

‘[object Object]‘   : ‘object‘

};

if(obj instanceof Element) {

return ‘element‘;

}

return map[toString.call(obj)];

}

function type(obj) {

var toString = Object.prototype.toString;

var map = {

‘[object Boolean]‘  : ‘boolean‘,

‘[object Number]‘   : ‘number‘,

‘[object String]‘   : ‘string‘,

‘[object Function]‘ : ‘function‘,

‘[object Array]‘    : ‘array‘,

‘[object Date]‘     : ‘date‘,

‘[object RegExp]‘   : ‘regExp‘,

‘[object Undefined]‘: ‘undefined‘,

‘[object Null]‘     : ‘null‘,

‘[object Object]‘   : ‘object‘

};

if(obj instanceof Element) {

return ‘element‘;

}

return map[toString.call(obj)];

}

时间: 2024-08-28 06:51:10

关于Javascript 深拷贝的相关文章

一个简单的javascript深拷贝

var extendDeep = function(parent,child){ var i, toStr = Object.prototype.toString, astr = '[object Array]'; child = child || {}; for( i in parent){ if(parent.hasOwnProperty(i)){ if(typeof parent[i] === 'object'){ child[i] = toStr.call(parent[i])=== a

JavaScript深拷贝实现原理简析

原文:http://www.cnblogs.com/xie-zhan/p/6020954.html JavaScript实现继承的时候,需要进行对象的拷贝:而为了不影响拷贝后的数据对原数据造成影响,也就是存在共享关系的时候,我们就需要进行深拷贝: 这里就做一个简单的分析其实现原理 先上代码: var obj1 = { name : 'Awen', song : { auther : '小明', title : '广州' }, hobby: ['吃','吃吃','吃吃吃'] }; var obj2

JavaScript深拷贝和浅拷贝

1. 基本类型 和 对象类型 他们最大的区别就是在于他们的传值方式. 基本类型是传值 对象类型就是传引用. 这里复制一份obj叫做obj2, 这里修改了obj2的b为100 同时也修改了obj1.b. 因为他们本来就是一个对象 这就是所谓的浅拷贝. 避免这样的情况 我们这样写 这就是深拷贝 不会改到原来的obj1. 浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存.但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象. 2. Obj

JavaScript深拷贝与浅拷贝

1.先看一个例子:从中可以看出,obj1拷贝了obj的值,但只是进行了地址的引用,修改obj1的值也影响到了obj的值,没有创建新对象. 浅拷贝:对基本数据类型进行值传递,对引用数据类型进行引用传递般的拷贝. 深拷贝:对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容 obj2= {name: 'LiLei',school: 'HBUT',age: {age: '3'},run: function aa () {console.log(this.name)}}父对象的属性等

JS JavaScript深拷贝、浅拷贝

浅拷贝:浅拷贝只是复制了内存地址,如果原地址中的对象改变了,浅复制出来的对象也会相应改变. 深拷贝:开辟了一块新的内存存放地址和地址指向的对象. 深拷贝数组(只拷贝第一级数组): 1.直接遍历 var arr = [1,2,3,4]; function copy(arg){ var newArr = []; for(var i = 0; i < arr.length; i++) { newArr.push(arr[i]); } return newArr; } var newArry = cop

javascript 深拷贝

1 //isActiveClone防止循环引用 2 function clone(obj) { 3 if (obj === null || typeof obj !== 'object' || 'isActiveClone' in obj) { 4 return obj; 5 } 6 7 var temp = obj.constructor(); //使temp的prototype与obj的相同 8 9 for (var key in obj) { 10 if (Object.prototype

你不知道的javascript

一.对象 JavaScript简单类型有数字.字符串.布尔值.null.undefined,其他所有的值都是对象(数组.函数.正则表达式都是对象). 数字.字符串.布尔值虽然拥有方法(包装对象),但并不是对象. 包装对象: 每当读取一个基本类型值的时候,后台会创建一个对象的基本包装类型的对象,从而能够调用一些方法来操作这些数据. var s1 = 'abcdefg' ; var s2 = s1.substring(2) ; 后台自动完成下列处理: 创建String类型的一个实例 在实例上调用指定

深拷贝与浅拷贝js,方法

在使用JavaScript对数组进行操作的时候,我们经常需要将数组进行备份,事实证明如果只是简单的将它赋予其他变量,那么我们只要更改其中的任何一个,然后其他的也会跟着改变,这就导致了问题的发生. 参考Object.assign():https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/assign <!DOCTYPE html> <html> <head&

司徒正美文章列表

由于本人对司徒正美文章的喜欢,特此整理文章列表如下. 一个带完整的RBAC授权系统的rails应用(第一部分)(司徒正美, 3年前, 12/6549) 一个带完整的RBAC授权系统的rails应用(第二部分)(司徒正美, 3年前, 1/1135) 随机生成十六进制颜色(司徒正美, 3年前, 0/340) ruby中的类变量与实例变量(司徒正美, 3年前, 0/231) ruby模拟多个构造器(司徒正美, 3年前, 0/153) ruby的实例方法(写方法,读方法与读写方法)(司徒正美, 3年前,