浅复制
var extend = function(target,source){
for(var key in source){
target[key] = source[key]
}
}
这个复制只能处理一些的值类型的的数据, 因为引用类型的话,复制过去的只是一个指针,源数据和目标数据属性里面的指针都指向同一个数据,牵一发而动全身。没法使用修改。
深复制
大概就是上图所示,对于复制引用类型的数据,我们需要先再target(目标对象上)创建一个空对象 或者数组。然后复制过去。
var source = {
a:{
b:{
c:"深复制"
}
}
}
上面的source源对象的属性的值下面还有对象,所以利用要递归处理一下。
基本逻辑如下所示
- 判断是不是 对象 或者 数组 (利用
Object.prototype.toString.call()
) - 是 对象或者 数组 ,就在目标对象创建空数组或者空对象;不是,就直接 target[key] = source[key]复制
- source源对象属性下面可能还有对象,要采用递归处理
第一步判断数据类型
var _classType = {};
var types = "Undefined Null Boolean Number String Function Array Date RegExp Object Error".split(" ");
for(var i = 0 ;i<types.length ;i++){
_classType[ "[object " + types[i] + "]" ] = types[i].toLowerCase()
}
function type(obj) {
return _classType[Object.prototype.toString.call(obj)]
}
/*纯对象{}, */
function isObject(obj){
return type(obj) === 'object'
}
/*纯数组[]*/
function isArray(obj){
return type(obj) === 'array'
}
第二步分支处理
var _extend = function(target,source,deep){
//遍历 源对象的属性
for(key in source){
/*源对象的属性值 是纯数组 或者纯对象*/
if(deep && isObject(source[key]) || isArray(source[key])){
//....目标对象创建空对象或者空数组,然后递归...........//
}
/*如果是值类型,直接复制*/
else if (source[key] !== undefined){
target[key] = source[key]
}
}
return target
}
第三步递归处理
var _extend = function(target,source,deep){
//遍历 源对象的属性
for(key in source){
/*源对象的属性值 是纯数组 或者纯对象*/
if(deep && isObject(source[key]) || isArray(source[key])){
/*如果源对象的属性是 纯对象,目标对象的属性就也是 纯对象 */
if (isObject(source[key]) &&!isObject(target[key])){
/*!isObject(target[key] 如果目标属性也是对象,就不用创建空对象了,直接用本身的对象属性*/
target[key] = {}
}
/*如果源对象的属性是纯数组,目标对象的属性也是 纯数组 */
if (isArray(source[key]) && !isArray(target[key]) ){
/*!isObject(target[key] 如果目标属性也是数组,就不用创建空数组了,直接用本身的数组属性*/
target[key] = []
}
/*因为前面的判断,所有递归把属性当成对象继续深复制*/
extend(target[key], source[key], deep)
}
/*如果是值类型,直接复制*/
else if (source[key] !== undefined){
target[key] = source[key]
}
}
return target
}
这样就可以了,最后附上无注释的封装代码
function extend(t,s,d){
var _classType = {};
var types = "Undefined Null Boolean Number String Function Array Date RegExp Object Error".split(" ");
for(var i = 0 ;i<types.length ;i++){
_classType[ "[object " + types[i] + "]" ] = types[i].toLowerCase()
}
function type(obj) {return _classType[Object.prototype.toString.call(obj)]}
function isObject(obj){return type(obj) === 'object'}
function isArray(obj){return type(obj) === 'array' }
var _extend = function(target,source,deep){
for(key in source){
if(deep && isObject(source[key]) || isArray(source[key])){
if (isObject(source[key]) &&!isObject(target[key])){
target[key] = {}
}
if (isArray(source[key]) && !isArray(target[key]) ){
target[key] = []
}
extend(target[key], source[key], deep)
}
else if (source[key] !== undefined){
target[key] = source[key]
}
}
return target
}
return _extend(t,s,d)
}