js对象简单、深度克隆(复制)
2016-02-20 19:38
896 查看
javascript的一切实例都是对象,只是对象之间稍有不同,分为原始类型和合成类型。原始类型对象指的是字符串(String)、数值(Number)、布尔值(Boolean),合成类型对象指的是数组(Array)、对象(Object)、函数(Function)。
既然对象分为这两类,他们之间的最大差别是复制克隆的差别。普通对象存储的是对象的实际数据,而引用对象存储的是对象的引用地址,而把对象的实际内容单独存放,因为引用对象通常比较庞大,这是数据开销和内存开销优化的手段。通常初学者很难理解这部分内容,就像对象的原型一样,也是同一个概念。对象的原型也是引用对象,把原型的方法和属性放在单独内存当中,而对象的原型链则指向这个内存地址。尽管这部分内容比较拗口复杂,那其中的原理都是一致的,目的也一致。
var y=x;
y="2";
// "1"
alert(x);
// "2"
alert(y);
var y=x;
y=2;
// 1
alert(x);
// 2
alert(y);
var y=x;
y=false;
// true
alert(x);
// false
alert(y);
var x=[1,2];
var y=x;
y.push(3);
// 1,2,3
alert(x);
// 1,2,3
alert(y);
由上可知,原始数组x,克隆数组y,修改了克隆数组y,但也同时修改了原始数组x,这就是引用对象的特点。那么如何才能达到完整的数组克隆呢?
var x=[1,2];
var y=[];
var i=0;
var j=x.length;
for(;i<j;i++)
{
y[i]=x[i];
}
y.push(3);
// 1,2
alert(x);
// 1,2,3
alert(y);
这样,克隆数组y,原始数组x,两个数组互补干扰,实现了完整的数组克隆。
var x={1:2,3:4};
var y={};
var i;
for(i in x)
{
y[i]=x[i];
}
y[5]=6;
// Object {1: 2, 3: 4}
console.log(x);
// Object {1: 2, 3: 4, 5: 6}
console.log(y);
函数的克隆,使用“=”符号就可以了,并且在改变克隆后的对象,不会影响克隆之前的对象,因为克隆之后的对象会单独复制一次并存储实际数据的,是真实的克隆。
完整的对象克隆又称为深度对象克隆、对象的深度克隆、对象的深度复制等等。
function clone(obj)
{
var o,i,j,k;
if(typeof(obj)!="object" || obj===null)return obj;
if(obj instanceof(Array))
{
o=[];
i=0;j=obj.length;
for(;i<j;i++)
{
if(typeof(obj[i])=="object" && obj[i]!=null)
{
o[i]=arguments.callee(obj[i]);
}
else
{
o[i]=obj[i];
}
}
}
else
{
o={};
for(i in obj)
{
if(typeof(obj[i])=="object" && obj[i]!=null)
{
o[i]=arguments.callee(obj[i]);
}
else
{
o[i]=obj[i];
}
}
}
return o;
}
既然对象分为这两类,他们之间的最大差别是复制克隆的差别。普通对象存储的是对象的实际数据,而引用对象存储的是对象的引用地址,而把对象的实际内容单独存放,因为引用对象通常比较庞大,这是数据开销和内存开销优化的手段。通常初学者很难理解这部分内容,就像对象的原型一样,也是同一个概念。对象的原型也是引用对象,把原型的方法和属性放在单独内存当中,而对象的原型链则指向这个内存地址。尽管这部分内容比较拗口复杂,那其中的原理都是一致的,目的也一致。
1、原始类型对象的克隆
1.1、字符串的克隆
var x="1";var y=x;
y="2";
// "1"
alert(x);
// "2"
alert(y);
1.2、数值的克隆
var x=1;var y=x;
y=2;
// 1
alert(x);
// 2
alert(y);
1.3、布尔值的克隆
var x=true;var y=x;
y=false;
// true
alert(x);
// false
alert(y);
2、合成类型对象的克隆
2.1、数组的克隆
如果采用普通克隆:var x=[1,2];
var y=x;
y.push(3);
// 1,2,3
alert(x);
// 1,2,3
alert(y);
由上可知,原始数组x,克隆数组y,修改了克隆数组y,但也同时修改了原始数组x,这就是引用对象的特点。那么如何才能达到完整的数组克隆呢?
var x=[1,2];
var y=[];
var i=0;
var j=x.length;
for(;i<j;i++)
{
y[i]=x[i];
}
y.push(3);
// 1,2
alert(x);
// 1,2,3
alert(y);
这样,克隆数组y,原始数组x,两个数组互补干扰,实现了完整的数组克隆。
2.2、对象的克隆
和数组的克隆同理,对象的完整克隆如下:var x={1:2,3:4};
var y={};
var i;
for(i in x)
{
y[i]=x[i];
}
y[5]=6;
// Object {1: 2, 3: 4}
console.log(x);
// Object {1: 2, 3: 4, 5: 6}
console.log(y);
2.3、函数的克隆
var x=function(){alert(1);}; var y=x; y=function(){alert(2);}; // function(){alert(1);}; alert(x); // y=function(){alert(2);}; alert(y);
函数的克隆,使用“=”符号就可以了,并且在改变克隆后的对象,不会影响克隆之前的对象,因为克隆之后的对象会单独复制一次并存储实际数据的,是真实的克隆。
3、完整的对象克隆
根据1和2,总结一下完整的对象克隆,包括克隆普通对象、引用对象。在写这个方法之前,我们必须想到的是,克隆引用对象必须采用完整克隆(深度克隆),包括对象的值也是一个对象也要进行完整克隆(深度克隆)。完整的对象克隆又称为深度对象克隆、对象的深度克隆、对象的深度复制等等。
function clone(obj)
{
var o,i,j,k;
if(typeof(obj)!="object" || obj===null)return obj;
if(obj instanceof(Array))
{
o=[];
i=0;j=obj.length;
for(;i<j;i++)
{
if(typeof(obj[i])=="object" && obj[i]!=null)
{
o[i]=arguments.callee(obj[i]);
}
else
{
o[i]=obj[i];
}
}
}
else
{
o={};
for(i in obj)
{
if(typeof(obj[i])=="object" && obj[i]!=null)
{
o[i]=arguments.callee(obj[i]);
}
else
{
o[i]=obj[i];
}
}
}
return o;
}
4、参考资料
http://javascript.ruanyifeng.com/grammar/basic.html#toc9相关文章推荐
- JavaScript-JS优化与惰性载入函数
- js 作为属性的变量
- jstack_查看当前进程及所属线程执行情况
- [Cycle.js] Hyperscript as our alternative to template languages
- 如何判断js中的数据类型
- JavaScript数据类型
- 2、JavaScript常用互动方法
- JavaScript中异步编程
- javascript变量声明提升(hoisting)
- JSON.parse()和JSON.stringify()
- 1、JavaScript入门篇
- [BZOJ1031][JSOI2007]字符加密Cipher 做题笔记
- 自己动手丰衣足食之Easyform表单验证插件&validate.js实时验证
- JS触发<a>,JS事件模拟
- js 不可变的原始值和可变的对象引用
- JavaScript基本语法、Console用法和Up&Going书籍总结
- Javascript作用域和变量提升
- XML,JSON文件解析
- javascript Date()
- JavaScript 实现Map