js数组和对象相等判断、拷贝详解(结合几个现象讲解引用数据类型的趣事)
序言
最近遇到几个js引用数据类型造成的bug,今天结合bug详细分析一下,避免以后再犯,也希望能帮大家提个醒,强化js基本功。
目录
1、浅拷贝、深拷贝,解决变量赋值相互影响问题
2、判断2个数组、对象是否相等
现象一
var a=;
var b=a;
b=;
console.log(a) //
console.log(b) // var obj1 = {
id: ,
info: {
name: '张三'
}
};
var obj2 = obj1;
obj2.id = ;
obj2.info.name = '李四'
console.log(obj1) // {id:2, info:{name: '李四'}}
console.log(obj2) // {id:2, info:{name: '李四'}}
1. 现象分析:
数组、对象都是用用数据类型。直接 = 赋值,或者 浅拷贝,这些变量实质上共享一个存储空间的数据。当你修改其中一个对象变量时,
另一个也会变。 2. 深浅拷贝
浅拷贝: 简单说,就是新的变量与原变量公用一个指针,即公用同一份存储空间的数据。改变a,b也会变
深拷贝: 简单说就是把数据全部拔下来,重新存一下。a,b之间没有任何牵连 浅析:
1. 这涉及到计算机原理的一些东西。js基本数据类型存在 栈内存 中, 当 a=b ,相当于新开辟一个存储空间,所以互不影响。
2. 引用数据类型,名 存在栈内存中,值存在堆内存中,栈内存会额外存一个指向堆内存的指针,其实就是 堆内存地址。
3. 我们对象 a=b 时,仅仅将名,即 栈内存中的数据复制了出来,但是栈内存的地址并没有变,所以a,b值会保持一致,互相影响。 3. 几个实现对象拷贝的方法
let obj1 = { name: 11, age: 11, ope: { say: 1, get: 2 }}
let obj2 = { }
(1) let obj2 = { ...obj1 } let obj2 = { ...obj1 ,ope:22}
这个拷贝不彻底,他可以深拷贝基础数据类型,name 等修改不会影响,但是数组、对象不行,ope里面的数据依旧相互影响,但是我们
可以将这些引用数据类型给修改掉,这样依旧可以实现互不影响 (2) let obj2 = Object.assign({ },obj1,...)
原理是一样的,也是只对基本数据类型管用,这个灵活度,还不如上面那个 (3) 通过 json 字符串、对象转换的方式
obj2 = JSON.stringify(obj1) 先转 字符串
obj2 = JSON.parse(obj2) 再转对象 而且转成字符串以后,还方便 网络传输 、 存储。
现象二
var arr1 = [,,];
var arr2 = [,,];
var obj1 = {id:,name:"张三"};
var obj1 = {id:'',name:"张三"};
var arr3 = arr1;
var obj3 = obj1; console.log(arr1 === arr2);//false
console.log(obj1 === obj2);//false
console.log(arr3 === arr1);//true
console.log(obj3 === obj1);//true
1. 现象分析:
因为 数组、对象是引用数据类型,变量存储的是地址,真正是数据在地址指针指向的存储单元,所以arr1、arr2的数据是放在不同存储单元里的。直接比较,地址肯定是不同的。而赋值操作 arr3 = arr1 是将地址指针赋值,数组数据还是只放在一个存储单元里面,arr1、arr2 都存储了这个地址,所以直接比较是相等的
2. 如何实现 数组 对象的相等判断
方法一 转换为字符串再比较
JSON.stringify(a1) == JSON.stringify(a2)
或
a1.toString() == a2.toString() 问题:存在 1 和 '1' ,认为是相同的情况,只能根据自己情况来了
方法二
function equalJudgment(data1,data2) {
var result = true
if (data1 && data2 && data1.constructor === Array && data2.constructor === Array) {
if (data1.length !== data2.length) {
result = false
} else {
for (var i=0;i<data1.length;i++) {
if (data1[i].constructor === Array && data2[i].constructor === Array){
if (!equalJudgment(data1[i], data2[i])) {
result = false
return result
}
} else if (data1[i].constructor === Object && data2[i].constructor === Object){
if (!equalJudgment(data1[i], data2[i])) {
result = false
return result
}
} else {
if (data1[i] !== data2[i]){
result = false
return result
}
}
}
}
} else if (data1 && data2 && data1.constructor === Object && data2.constructor === Object) {
var key1 = Object.getOwnPropertyNames(data1)
var key2 = Object.getOwnPropertyNames(data2)
if (key1.length !== key2.length) {
result = false
} else {
for (var i=0;i<key1.length;i++) {
if (key2.indexOf(key1[i]) === -1) {
result = false
return result
} else if (data1[key1[i]].constructor === Array && data2[key1[i]].constructor === Array) {
if (!equalJudgment(data1[key1[i]], data2[key2[i]])) {
result = false
return result
}
} else if (data1[key1[i]].constructor === Object && data2[key1[i]].constructor === Object) {
if (!equalJudgment(data1[key1[i]], data2[key1[i]])) {
result = false
return result
}
}else {
if (data1[key1[i]] !== data2[key1[i]]){
result = false
return result
}
}
}
}
} else {
result = 'Input error!'
}
return result
}
以上 js 函数是我自己写的,经过测试没有问题 ,网上有很多实现的方法,但是大多都是无法解析多层数组、对象嵌套的情况 (说实话没啥卵用),但是个人觉得这个方法写的有些啰嗦,抛砖引玉,有更好的方法希望大家不吝分享。 ps:顺便帮我测测bug,虽然各种情况都试过,应该是没问题
总结
上述的2个现象在码代码过程中应该会经常遇到,特别是处理像 react、Vue 生命周期函数的时候、state使用修改的时候,经常会遇到引用数据类型带来的问题,不经意间就出问题了,希望这些能帮到大家,若有错误,望指出!!!
js数组和对象相等判断、拷贝详解(结合几个现象讲解引用数据类型的趣事)的更多相关文章
- js对象浅拷贝和深拷贝详解
js对象浅拷贝和深拷贝详解 作者:i10630226 字体:[增加 减小] 类型:转载 时间:2016-09-05我要评论 这篇文章主要为大家详细介绍了JavaScript对象的浅拷贝和深拷贝代码,具 ...
- js 数组、对象转json 以及 json转 数组、对象
let jsonObj = $.parseJSON(jsonStr); //json字符串转化成json对象(jq方法) var jsonObj = JSON.parse(jsonStr); //js ...
- JS DOM对象控制HTML元素详解
JS DOM对象控制HTML元素详解 方法: getElementsByName() 获取name getElementsByTagName() 获取元素 getAttribute() 获取元素 ...
- vue.js循环for(列表渲染)详解
vue.js循环for(列表渲染)详解 一.总结 一句话总结: v-for <ul id="example-1"> <li v-for="item in ...
- JavaScript对象的property属性详解
JavaScript对象的property属性详解:https://www.jb51.net/article/48594.htm JS原型与原型链终极详解_proto_.prototype及const ...
- js正则实现二代身份证号码验证详解
js正则实现二代身份证号码验证详解 根据[中华人民共和国国家标准 GB 11643-1999]中有关公民身份号码的规定,公民身份号码是特征组合码,由十七位数字本体码和一位数字校验码组成.排列顺序从左至 ...
- vue.js选择if(条件渲染)详解
vue.js选择if(条件渲染)详解 一.总结 一句话总结: v-if <!DOCTYPE html> <html lang="en"> <head& ...
- Angular.js中处理页面闪烁的方法详解
Angular.js中处理页面闪烁的方法详解 前言 大家在使用{{}}绑定数据的时候,页面加载会出现满屏尽是{{xxx}}的情况.数据还没响应,但页面已经渲染了.这是因为浏览器和angularjs渲染 ...
- js keyup、keypress和keydown事件 详解
js keyup.keypress和keydown事件 详解 js keyup.keypress和keydown事件都是有关于键盘的事件 当一个按键被pressed 或released在每一个现代浏 ...
随机推荐
- thrift安装及python和c++版本调试
一.安装过程 1.安装依赖库 ]# yum install boost-devel-static libboost-dev libboost-test-dev libboost-program-opt ...
- spring boot集成swagger,自定义注解,拦截器,xss过滤,异步调用,guava限流,定时任务案例, 发邮件
本文介绍spring boot集成swagger,自定义注解,拦截器,xss过滤,异步调用,定时任务案例 集成swagger--对于做前后端分离的项目,后端只需要提供接口访问,swagger提供了接口 ...
- 虚拟机上的centos7链接不上网络: activation of network connection failed
报错: 重启网络也不行: 解决: 1.打开网络配置文件: $vi /etc/sysconfig/network-scripts/ifcfg-ens33 (可以参照这里的描述,找到这个文件https: ...
- D - WE POJ - 3273 (二分法)
Farmer John is an astounding accounting wizard and has realized he might run out of money to run the ...
- 20175226 2018-2019-2《java程序设计》结对编程-四则运算(第二周-阶段总结)
需求分析(描述自己对需求的理解,以及后续扩展的可能性) 实现一个命令行程序,要求: 自动生成小学四则运算题目(加,减,乘,除) 支持整数 支持多运算符(比如生成包含100个运算符的题目) 支持真分数 ...
- Android真机测试,连接到本地服务器的方法
1. 前言 作为一名Android开发者,不管怎么说,都会经历使用Android真机来测试连接本地服务器这样的事情.这里所说的“本地服务器”大多数时候指的是:搭载有某种服务器软件的PC,例如搭载有To ...
- mysql5.7初始化密码报错 ERROR 1820 (HY000): You must reset your password using ALTER USER statement before
mysql初始化密码常见报错问题1,mysql5.6是密码为空直接进入数据库的,但是mysql5.7就需要初始密码 cat /var/log/mysqld.log | grep password1 2 ...
- JS,JQ实现模拟暂停FOR循环,间隔几秒后再继续执行
<!DOCTYPE html><head><script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquer ...
- 《ServerSuperIO Designer IDE使用教程》- 6.增加与阿里云物联网(IOT)对接服务,实现数据交互。发布:v4.2.4 版本
v4.2.4 更新内容:1.增加了对接阿里物联网平台的服务.下载地址:官方下载 6. 增加与阿里云物联网(IOT)对接服务,实现数据交互 6.1 概述 为了满足业务系统数据上云的要求,Se ...
- 数据分析入门——numpy类库基础知识
numpy类库是数据分析的利器,用于高性能的科学计算和数据分析.使用python进行数据分析,numpy这个类库是必须掌握的.numpy并没有提供强大的数据分析功能,而是它提供的ndarray数据结构 ...