直接上代码,验证过确实有效可行!
PS:
1、本人有一个自己积累的工具类,所以直接拷贝出来了,是用ES6的class语法写的。
2、代码中的this.isObject、this.isUndefined等等之类的,可自行实现,都是用于验证数据类型的,好实现,就不列出来了(最底下也已经列出来了)。
3、deepCopy方法需要deppCopyPrototype方法的协助,才能很深很深很深地拷贝对象的层层原型。
/**
* 完整的对象、数组深度拷贝(包括Symbol、get、set、原型)<br />
* PS: <br />
* 1、处理被Vue处理过的对象、数组时,会报错!!!<br />
* 2、this.isObject( obj ) || this.isArray( obj )为true才会执行!!!其他都会被原样返回!!!
*
* @param obj 对象、数组,必需
*
* @returns {Object|Array} 对象、数组,{}|[]
*/
deepCopy( obj ){
if( this.isArray( obj ) ){
let newArr = [];
obj.forEach( c => void ( newArr.push( typeof c !== 'object'
? c
: this.deepCopy( c ) ) ) );
return newArr;
}
else if( this.isObject( obj ) ){
let val,
newObj = 'constructor' in obj
? new obj.constructor()
: {};
for( let tmp of
Reflect.ownKeys( obj ) ){
val = obj[ tmp ];
if( typeof val !== 'object' ){
Object.defineProperty( newObj, tmp, Object.getOwnPropertyDescriptor( obj, tmp ) );
}
else{
newObj[ tmp ] = this.deepCopy( val );
}
}
let objPrototype = this.deppCopyPrototype( obj );
!this.isNull( objPrototype ) && ( Object.setPrototypeOf( newObj, objPrototype ) );
return newObj;
}
else{
return obj;
}
}
/**
* 深度拷贝一个对象的原型(包括原型的原型...N...),返回的是一个对象(已经深度拷贝的原型链)<br />
* PS:<br />
* 拿到这个方法的返回值后,直接使用Object.setPrototypeOf设置到目标对象就行!
*
* @param source 对象(具有原型的对象),必须
*
* @returns {null|Object} null|Objec
*/
deppCopyPrototype( source ){
let arr1 = [],
sourcePrototype = Object.getPrototypeOf( source );
while( sourcePrototype !== null ){
arr1.push( this.deepCopy( sourcePrototype ) );
sourcePrototype = Object.getPrototypeOf( sourcePrototype );
}
arr1.reverse();
if( arr1.length === 0 ){
return null;
}
else{
for(
let i = 0;
i < arr1.length - 1;
++i
){
Object.setPrototypeOf( arr1[ i + 1 ], arr1[ i ] );
}
return arr1[ arr1.length - 1 ];
}
}
PS:数据类型验证
/**
* 判断数据是否为Array类型
*
* @param arg 数据,参数个数为1,必需
*
* @returns {Boolean} boolean,是true,否false
*/
isArray( arg ){
'use strict';
return Array.isArray( arg );
}
/**
* 判断数据是否为Object类型<br />
* PS:<br />
* 1、包括'[object Module]'。
*
* @param arg 数据,参数个数为1,必需
*
* @returns {Boolean} boolean,是true,否false
*/
isObject( arg ){
return IsHandle1.call( this, arg, 'Object' ) || IsHandle1.call( this, arg, 'Module' );
}
function IsHandle1( arg1, arg2 ){
if( 'Element' === arg2 ){
return this.dataT( arg1 )
.includes( arg2 );
}
let str1 = this.dataT( arg1 )
.split( ' ' )[ 1 ];
return str1.slice( 0, str1.length - 1 ) === arg2;
}
/**
* 获取数据类型<br />
* PS:<br />
* 1、如果传入的是被Proxy代理过的对象,会报错!!!
*
* @param arg 任何类型的数据,参数个数为1,必需
*
* @returns {String} string,数据类型的字符串,如'[object HTMLDocument]'
*/
dataT( arg ){
'use strict';
return Object.prototype.toString.call( arg );
}
/**
* 判断数据是否为null值
*
* @param arg 数据,参数个数为1,必需
*
* @returns {Boolean} boolean,是true,否false
*/
isNull( arg ){
'use strict';
return IsHandle1.call( this, arg, 'Null' );
}