本文实例为大家分享了使用js实现复制功能的具体代码,供大家参考,具体内容如下
复制1.遍历复制(for in)
特征:不修改引用关系(原来的属性还在),仅能复制字符属性,Symbol不能复制,不可枚举属性不能复制,原型链不能复制。浅复制
2.JOSN.parse(JSON.stringify(obj)) 转换复制
特征:修改引用关系(相当于创建一个新的对象,不再拥有原来的属性),仅能复制字符属性,Symbol不能复制,不可枚举属性不能复制,原型链不能复制,函数和其他类型不能复制。深复制
3.{…obj}解构赋值复制
特征:修改引用关系,Symbol和函数都能复制,不可枚举属性和原型链都不能复制。浅复制
4.Object.assign()对象复制
特征:不修改引用关系,可以复制属性、方法、Symbol类型,不可枚举属性和原型链都不能复制。浅复制
深复制**1.使用defineProperty***
function cloneObject(source,target){
if(source === null||source === undefined) return source;
if(source===document) return;
//判断target是不是继承对象的实例,是不是引用类型(null,undefined,Boolean,string,number都不是引用类型)
if(!Object.prototype.isPrototypeOf(target)){
//判断源对象是不是dom元素
if(HTMLElement.prototype.isPrototypeOf(source)){
//创建dom元素
target = document.createElement(source.nodeName);
}else if(source.constructor === RegExp){
// 任何正则表达式都有source和flags,source是正则内容,flags是正则修饰符
// 因为这两个属性都是只读属性,不能写入,必须通过构造函数创建时带入
target = new RegExp(source.source,source.flags);
}else if(source.constructor === Date){
// 日期对象在创建的对象中将原有的日期对象放入,可以让当前日期对象变为原有日期对象的值,但是没有引用关系
targer = new Date(source);
}else if(source.constructor === Function){
// 复制函数,通过正则表达式将函数中的参数以及函数体内容提取到数组中,然后通过new Function()创建
var arr = source.toString().replace(/\n|\r/g,"").trim().match(/\((.*?)\)\s*\{(.*)\}/).slice(1);
target = new Function(arr[0].trim(),arr[1]);
}else if(source.constructor === Set){
// set类型,在处理时,new Set时可以带入数组,因此我们将原有set的列表强转为数组,并且将这个强转后的数组复制给新数组
target = new Set(cloneObject(Array.from(source.values())));
}else if(source.constructor === Map){
target = new Map();
// 如果是map类型,遍历map中每个元素
for(var [key,value] of source.entries()){
// 如果key是引用类型,
if(Object.prototype.isPrototypeOf(key)){
// 如果value引用类型,则将key和value分别做复制,并且将返回的结果放在map中
if(Object.prototype.isPrototypeOf(value)){
target.set(cloneObject(key),cloneObject(value));
}else{
//如果value不是引用类型,只将key复制,并且放入map
target.set(cloneObject(key),value);
}
}else{
// 这是key不是引用类型时
if(Object.prototype.isPrototyeOf(value)){
target.set(key,cloneObject(value));
}else{
target.set(key,value);
}
}
}
}
else{
//除了null和undefined,其他类型都有constructor。任何对象的constructor都是它的类型,利用其constructor创建对象
//通过对象类型的反射创建新的同类型对象
target = new source.constructor();
}
}
//获取对象的所有字符属性名和Symbol属性名的数组
var names = Object.getOwnPropertyName(source).concat(Object.getOwnPropertySymbols(source));
for(var i = 0;i < names.lenght; i++){
// 如果当前复制的是函数,并且这个函数的属性是prototype,那么这个属性不复制,否则会死循环
if(source.constructor === Function&&names[i] === "prototype")
continue;
// 获取当前属性名的描述对象
var desc = Object.getOwnPropertyDescriptor(source,names[i]);
// 这个描述对象的值如果是引用类型
if(Object.prototype.isPrototypeOf(desc.value)){
// 根据需要将源对象的描述内容设置给当前目标对象相同属性名的描述内容,及值付为刚才创建相同类型的对象
Object.defineProperty(target,names[i],{
enumerable:desc.enumerable,
configurable:desc.configurable,
writable:desc.writable,
value:cloneObject(desc.value)
});
}else{
//如果描述的对象的值不是引用类型,直接将描述对象设置给目标对象的这个属性
Object.defineProperty(target,names.desc);
}
}
return target;
}
//原型.isPrototypeOf(对象)。对象里面是不是拥有xx的原型
//反射:通过对象
2.使用JSON对象实现深复制
使用**JSON.parse(str)**可以将字符串转换成对象;
使用**JSON.stringify(obj)**将对象转换成对象形式的字符串,其中无法转换对象中的方法,可以考虑先将对象中的方法使用toString()转为字符串,然后再转换使用JSON.stringify(obj);
*使用**JSON.parse(str)**可以将字符串转换成对象
var obj={
a:1,
b:3, //ab复制不会随其中一个的变化而变化
c:{ //c复制会随其中一个的变化而变化,因为c属于对象的地址引用关系
d:10,
e:20
}
};
var o1 = JSON.parse(JSON.stringify(obj)); //将obj复制给o1
3.使用递归实现深复制
结构仅限于对象。如果存在数组、正则、日期对象、dom对象则不能使用。
var obj = {
a:1,
b:2,
c:{
a:1,
b:2,
c:{
a:1,
b:2,
}
}
}
//函数定义参数时,注意必要参数写在前面,非必要参数写在后面
function cloneObj(source,target){
if(target === undefined) target = {};
for(var prop in source){
//如果
if(typeof source[prop] === "object" && source[prop] != null){
target[prop] = {};
cloneObj(source[prop],target[prop]);
}else{
target[prop] = source[prop];
}
}
return target;
}