深拷贝的实现

news/2024/7/19 14:48:20 标签: js, javascript, 深拷贝, copy, 递归

正文

Object.prototype.toString()

  • 返回的是`[object Object]`表示数据 类型的字符串
  • 可以利用这一点来确定数据的具体类型
  • [].toString()以及Number.prototype.toString()都不一样,数组和字符串等类型数据都重写了toString()方法。
javascript">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]

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

  • 第一种写法
javascript">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
}
  • 第二种写法
javascript">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引用类型的特点,就是浅拷贝之后,改变一个对象的属性,另一个对象也会改变,且两个对象会相等。如下
javascript">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的指向,直接让它指向了一个新的函数对象。这当然与对象的修改不同,是我想的简单了。
  • 结论就是:函数是引用类型!
javascript">let fn1 = () => {
console.log(111)
}
let fn2 = fn1

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

结语

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


http://www.niftyadmin.cn/n/1257943.html

相关文章

手动实现一些函数的封装

正文 全局对象 node 中的 全局 this指向的是module.exports,而不是全局对象global 在外部函数中的this指向global,匿名函数也是 浏览器环境下全局this就是window 在外部函数中的this指向window,匿名函数也是 reverse - 不改变原数组版&a…

call,apply,bind 实现

正文 Tips:call bind apply对箭头函数来说,会忽略掉第一个参数,也就是this指向参数,所以不会改变箭头函数this的指向 call实现 this指向绑定传参返回值,看了很多的实现例子,都没有写这个。如果缺少返回值…

js 知识点备忘

长期更新… 前言 有太多知识点,其篇幅不值得写一篇博客,那么就把它们汇总吧,干脆做一个备忘。 如果你阅读了这篇博客,请先了解 有些知识点可能是不准确的,甚至是不正确的,因为我随时都会修改&#xff0c…

Promise 模拟实现

前言 最近很想研究一下Promise的原理,通过查阅资料写出了这篇博客,文章有借鉴参考文档。 正文 本文主要实现的是两个点,基本的Promise和then的链式调用。 代码的所有解释都在注释中 定义状态 //定义状态 const FULFILLED fulfilled con…

js错误处理

正文 try catch 在 JavaScript 中进行错误处理,最常见的方式就是使用try catch语句。将容易出错的代码段放入try块中,即可捕获错误,程序便至少不会因为一个错误而崩溃。 1. catch(error) 所有浏览器都支持error.message属性,它…

vue3.x + typeScript 知识点

前言 不知不觉已经记录了这么多的知识点,更新一下吧。 可能比较杂乱,请谅解。 正文 ref()和reactive()函数都是定义响应式数据的函数,ref更倾向于定义简单类型和数组,reactive定义对象es6语法解构reactive所定义的响应式对象&a…

better-scroll 在vue3

前言 最近在vue3中研究了一下移动端常用的插件better-scroll,方便确实是很方便,不过也是踩了不少的坑。共勉。 PS:本文着重说明笔者遇到的坑点 正文 一. 安装 $ npm i better-scroll二. 引入 在你需要的组件进行局部引入 import Bscrol…

nodejs 中 token 的使用

前言 token 验证,在设计登录注册和一些权限接口时发挥作用。以nodejs为例,谈一谈jsonwebtoken的使用。 正文 一. 安装 $ npm i jsonwebtoken二. 使用 首先,需要提供一个密匙,也就是一个字符串,用于token的生成和验…