深拷贝的实现

正文

Object.prototype.toString()

  • 返回的是`[object Object]`表示数据 类型的字符串
  • 可以利用这一点来确定数据的具体类型
  • [].toString()以及Number.prototype.toString()都不一样,数组和字符串等类型数据都重写了toString()方法。
function type(val) {
 return {}.toString.call(val)
}

console.log(type([])); //[object Array]
console.log(type(null)); //[object Null]
console.log(type(undefined)); //[object Undefined]
console.log(type('')); //[object String]
console.log(type(new Set())); //[object Set]
console.log(type(false)); //[object Boolean]

注意: 拷贝之后,两个对象中的函数是一个函数,也就是说两个函数名都指向一个函数对象

  • 第一种写法
function deepClone(sourceObj, resultObj) {
resultObj = resultObj ? resultObj : {}
for (let key in sourceObj) {
   //这是属性得是自己有的,不是继承过来的
   if (sourceObj.hasOwnProperty(key)) {
       //得是个引用类型的数据,才去递归啊,也不能是空
       if (typeof sourceObj[key] === 'object' && sourceObj[key]) {
           if (Object.prototype.toString.call(sourceObj[key]) === '[object Object]') {
               //是对象
               resultObj[key] = {}
           } else {
               //是数组
               resultObj[key] = []
           }
           //递归
           deepClone(sourceObj[key], resultObj[key])
       } else {
           //简单数据类型或者是函数就直接赋值了
           resultObj[key] = sourceObj[key]
       }
   }
}
return resultObj
}
  • 第二种写法
function deepClone(target) {        
//传入的数据类型不是对象,或在递归对象属性时,如果属性不是对象,则直接返回,不需要深拷贝
if (typeof target !== 'object') {
   return target
}

let result

if ({}.toString.call(target) === '[object Object]') {
   //是对象
   result = {}
} else {
   //是数组
   result = []
}

for (let key in target) {
   //只处理自己的属性,不处理继承过来的共有的属性
   if (target.hasOwnProperty(key)) {
       result[key] = deepClone(target[key])
   }
}

return result
}
  • 这里有个小插曲,Function类型我知道是引用类型数据,于是想验证一下函数是否也深拷贝了
    • 我同理了Object引用类型的特点,就是浅拷贝之后,改变一个对象的属性,另一个对象也会改变,且两个对象会相等。如下
const obj1 = {
name: 'zed'
}
const obj2 = obj1

console.log(obj1 === obj2)  //true

obj2.name = '111'
console.log(obj1)   //111
console.log(obj2)   //111
  • 但是我很惊讶的发现,结果是两个函数互不影响,也就是意味着函数不是引用类型?(是!!)。这直接让我怀疑人生,甚至去查函数是否是引用类型。
  • 不过当我细心观察代码时,发现其实这不过就是一场闹剧:我在改变fn1函数时,改变的不是它所指向的函数对象,而是改变了fn1的指向,直接让它指向了一个新的函数对象。这当然与对象的修改不同,是我想的简单了。
  • 结论就是:函数是引用类型!
let fn1 = () => {
console.log(111)
}
let fn2 = fn1

console.log(fn1 === fn2)    //true
fn1 = () => {       
console.log(222)
}
fn1()   //222
fn2()   //111
结语

如果对你有帮助的话,请点一个赞吧

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值