js对象赋值问题(对象赋值影响原对象、对象赋值后原对象值随之变化)

问题:

一个对象赋值给另一个对象后,新对象的值更改原对象的参数值随之变化(即改变新对象的值会影响原对象值)

直接用 的方式把一个对象赋值给另一个对象,会导致修改新对象时,原对象也发生变化


   
   
  1. let obj1 = { 'name': '小红'};
  2. let obj2 = obj1;
  3. obj2. name = '小明';
  4. console. log(obj1. name); //'小明'

原因:

JavaScript 中对象的赋值是默认引用赋值的(两个对象指向相同的内存地址),所以修改另一个对象时,即修改了内存地址里的对象,其他关联对象也会改变  

解决方法(转换类型法): JSON.parse(JSON.stringify(obj))

obj2=JSON.parse(JSON.stringify(obj1))
   
   

 注:

普通的对象也可以进行深拷贝,但是!!! 当对象内容项为number,string.boolean的时候,是没有什么问题的。但是,如果对象内容项为undefined,null,Date,RegExp,function,error的时候。使用JSON.stringify()进行拷贝就会出问题了。

解决方法(es6之Object.assign()法):obj2=Object.assign({},obj1)

 注:

Object.assign()方法有不足之处,Object.assign()只是让对象里第一层的数据没有了关联性(即修改obj2.name时obj1.name不会发生变化),但是对象内的对象则跟被复制的对象有着关联性的(即当修改更深层的obj2.name的值时,原对象obj1.name也跟着发生了变化)

 解决方法(使用递归的方式进行对象(数组)的深拷贝)


   
   
  1. //已封装的深拷贝函数
  2. function deepClone( obj = {}, hashMap = new WeakMap()) {
  3. //变量先置空
  4. let objClone = null,
  5. hashKey = hashMap. get(obj);
  6. if (obj instanceof RegExp) return new RegExp(obj); //正则表达式的情况
  7. if (obj instanceof Date) return new Date(obj); //日期对象的情况
  8. if (hashKey) return hashKey;
  9. //判断是否需要继续进行递归
  10. if ( typeof obj == "object" && obj !== null) {
  11. objClone = obj instanceof Array ? [] : {};
  12. hashMap. set(obj, objClone);
  13. //进行下一层递归克隆
  14. for ( const i in obj) {
  15. if (obj. hasOwnProperty(i)) {
  16. objClone[i] = deepClone(obj[i], hashMap);
  17. }
  18. }
  19. } else {
  20. //如果不是对象直接赋值
  21. objClone = obj;
  22. }
  23. return objClone;
  24. }

   
   
  1. //模拟数据
  2. let obj = {
  3. name: "xm",
  4. birth: new Date(),
  5. desc: null,
  6. reg: /^123$/,
  7. ss: [ 1, 2, 3],
  8. fn: function ( ) {
  9. console. log( "123");
  10. },
  11. };

   
   
  1. //使用方式
  2. let obj2 = deepClone(obj);
  3. obj. fn() //123
  4. obj2. fn() // 123
  5. console. log(obj, obj2, '深拷贝');

所以推荐使用深拷贝函数这种方法

解决方法(使用自定义工具库之深克隆):创建utils.js


   
   
  1. /*
  2. * 获取所有私有属性,包含Symbol私有属性
  3. */
  4. const getOwnProperties = obj => {
  5. if (obj === null) return []
  6. return [
  7. ... Object. keys(obj), // 同 ...Object.getOwnPropertyNames(obj) 获取实例的私有属性
  8. ... Object. getOwnPropertySymbols(obj)
  9. ]
  10. }
  11. /*
  12. * 浅克隆
  13. */
  14. const shallowClone = obj => {
  15. let type = toType(obj)
  16. if ( /^(string|number|boolean|null|undefined|symbol|bigint)$/. test(type)) return obj
  17. if ( /^function$/. test(type)) {
  18. return function proxy( ) {
  19. return obj()
  20. }
  21. }
  22. if ( /^date|regexp$/. test(type)) return new obj. constructor( obj)
  23. if ( /^error$/. test(type)) return new obj. constructor( obj.message)
  24. // 只处理数组(最后返回的是数组)和对象(普通对象/类数组对象等=》最后返回的都是普通对象)
  25. let keys = getOwnProperties(obj),
  26. clone = {}
  27. //clone = new obj.constructor(); // 类数组的时候会有问题
  28. Array. isArray(obj) ? (clone = []) : null
  29. keys. forEach( key => {
  30. clone[key] = obj[key]
  31. })
  32. return clone
  33. }
  34. /*
  35. * 深克隆
  36. */
  37. const deepClone = ( obj, cache = new Set()) => {
  38. // Set是一种存储结构,值的集合,保存非重复项,即Set中的元素是唯一的
  39. // 只有数组和对象才处理深拷贝,其余的情况直接按照浅克隆处理即可
  40. let type = toType(obj)
  41. if (! /^(array|object)$/. test(type)) return shallowClone(obj)
  42. // 避免自己套用自己导致无限递归
  43. if (cache. has(obj)) return shallowClone(obj)
  44. cache. add(obj)
  45. let keys = getOwnProperties(obj),
  46. clone = {}
  47. type === 'array' ? (clone = []) : null
  48. keys. forEach( key => {
  49. clone[key] = deepClone(obj[key], cache)
  50. })
  51. return clone
  52. }
  53. /*
  54. * 实现两个对象的深合并(Object.assign(obj1,obj2)为浅合并)
  55. * + obj1对象 obj2对象 -> 依次遍历obj2,把obj2中的每一项替换obj1中的每一项
  56. * + obj1对象 obj2不是对象 -> 不进行任何处理
  57. * + obj1不是对象 obj2对象 -> obj2直接替换obj1
  58. * + obj1不是对象 obj2也不是对象 -> obj2直接替换obj1
  59. */
  60. const merge = ( obj1, obj2) => {
  61. let isPlain1 = isPlainObject(obj1),
  62. isPlain2 = isPlainObject(obj2)
  63. if (!isPlain1) return obj2
  64. if (!isPlain2) return obj1
  65. // 遍历obj2中的每一项,让其替换obj1中的每一项
  66. let obj2Arr = getOwnProperties(obj2)
  67. obj2Arr. forEach( key => {
  68. obj1[key] = merge(obj1[key], obj2[key])
  69. })
  70. return obj1
  71. }
  72. //===========================================================
  73. // 数据类型检测通用方法
  74. let getProto = Object. getPrototypeOf, // 获取实例的原型对象
  75. class2type = {},
  76. toString = class2type. toString, // 取Object.prototype.toString
  77. hasOwn = class2type. hasOwnProperty, // 取Object.prototype.hasOwnProperty
  78. fnToString = hasOwn. toString, // 取Function.prototype.toString 转换字符串用
  79. ObjectFunctionString = fnToString. call( Object) // 同Object.toString() 把Object函数转成字符串 "function Object() {[native code]}"
  80. /*
  81. * 循环数据中的每一项:建立数据类型检测的映射表
  82. * + [object String]/[object Number]/[object Boolean]都是为了处理基于构造函数创建的基本数据值的引用类型值,最后期许检测出来的结果依然是"string/number/boolean"
  83. * + typeof new Number(10) => "object"
  84. * + toString.call(new Number(10)) => "[object Number]"
  85. */
  86. let assembleKeys = [
  87. 'String',
  88. 'Number',
  89. 'Boolean',
  90. 'Symbol',
  91. 'Function',
  92. 'Array',
  93. 'Object',
  94. 'Date',
  95. 'RegExp',
  96. 'Error',
  97. 'GeneratorFunction'
  98. ]
  99. assembleKeys. forEach( name => (class2type[ `[object ${name}]`] = name. toLowerCase()))
  100. /*
  101. * 检测数据类型的公共方法
  102. */
  103. const toType = obj => {
  104. // '=='判断null或者undefined,+""转成字符串 "null"或者"undefined"
  105. if (obj == null) return obj + ''
  106. // 如果是引用数据类型(包含:new Number(10)这种),则基于Object.prototype.toString检测(拿检测的结果到之前建立的映射表中去匹配查找,找到对象的小写数据类型,找不到则返回"object");而基本数据类型,之前排除了null/undefined,剩下的基于typof即可解决
  107. return typeof obj === 'object' || typeof obj === 'function'
  108. ? class2type[toString. call(obj)] || 'object'
  109. : typeof obj
  110. }
  111. /*
  112. * 检测是否为一个纯粹对象
  113. */
  114. const isPlainObject = obj => {
  115. let proto = null,
  116. Ctor,
  117. type = toType(obj);
  118. if (obj === undefined) return false
  119. // 不存在或者检测数据类型的结果都不是object,则一定不是纯粹对象
  120. if (!obj || type !== 'object') return false;
  121. // 不存在原型的情况:Object.create(null),相当于创建空对象{}
  122. proto = getProto(obj)
  123. if (!proto) return true;
  124. // 获取当前值原型对象上的constructor(即获取它的构造函数)
  125. Ctor = hasOwn. call(proto, 'constructor') && proto. constructor;
  126. // 有构造函数,并且构造函数需要直接是Object才可以(这样排除了NodeList等子类/自定义类的实例)
  127. // ObjectFunctionString === fnToString.call(Object)
  128. return typeof Ctor === 'function' && fnToString. call( Ctor) === ObjectFunctionString
  129. }
  130. export default {
  131. getOwnProperties,
  132. shallowClone,
  133. deepClone,
  134. toType,
  135. isPlainObject,
  136. merge
  137. }

工具库使用方法


   
   
  1. import utils from '@/libs/utils' // vue文件引入utils.js
  2. obj2 = utils. deepClone(obj1) // deepClone() 深克隆方法

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值