对 JavaScript Object 的一些思考
作者:淮城一只猫
日期:2020.03.13
修改:2020.03.17
本文首发:https://iiong.com/some-thoughts-on-javascript-object/
前言
前几天在做项目的时候遇到一个关于数组的问题,今天抽空来看看这个问题,因为之前也遇到,但是不长记性所有有了该笔记。之前在项目给后端提交一条数据,这个数据是数组类型,但需要改变数组里面的字段又不能改变原来的数组结构,所有我直接赋值新的变量再 Map
遍历修改的时候发现原来的数组结构已经发生改变了。虽然知道其中的原因,所以决定写下笔记,告诫下次不能再犯了。
思考
先看一段简单的例子:
const arr1 = [1, 2, 3];
const arr2 = arr1;
arr2.push(4);
console.log(arr1); // => [1, 2, 3, 4]
console.log(arr2); // => [1, 2, 3, 4]
如果不仔细思考的话,arr1
的结果令人“惊讶”的,学过后端语言的朋友相信都知道这个答案,很显然在 JavaScript
中,数组它是引用传递,所有的对象(Array 也是 对象)也是引用传递。所以意味着在使用等号赋值的时候,俩者引用内存同一个地址值,无论其中一个怎么操作,另一个反馈是同样的结果。
如果换个方式来理解这个引用传递:
const obj1 = {
a: 'test'};
const obj2 = {
a: 'test'};
console.log(obj1 === obj2); // => false
在 MDN
文档对此解释:
当两个操作数都是对象时,JavaScript会比较其内部引用,当且仅当他们的引用指向内存中的相同对象(区域)时才相等,即他们在栈内存中的引用地址相同。
上述声明的 obj1
和 obj2
在声明初始化的时候,在内存中开辟俩个新的地址值,所以在比较的时候,其实是比较俩个地址值是否相等,所以最终会输出 false
结果:
变量名 | 地址值 | 对象 |
---|---|---|
obj1 | #001 | {a: ‘test’} |
obj2 | #002 | {a: ‘test’} |
比较对象
字符串比较
其实这个就是将对象使用 JSON.stringify
转换成静态字符串,然后再比较:
// 使用上例变量
const str1 = JSON.stringify(obj1);
const str2 = JSON.stringify(obj2);
console.log(str1 === str2); // => true
虽然这个是最简单方法,但是使用限制也很大,如果对象里面的键值是乱序的,那么这个对比是没啥意义的,例如:
const obj3 = {
test1: 'test1',
test2: 'test2'
};
const obj4 = {
test2: 'test2',
test1: 'test1'
};
console.log(JSON.stringify(obj3) === JSON.stringify(obj4)); // => false
俩个对象是一样的,但返回结果却是 false
,所以这个对比看情况使用,那么需要做个方法,不受到键值顺序影响对比。
使用对象属性遍历对比
把对象的 key
提取组成数组,然后对应对象中的 value
是否相等:
const isObjectEqual = (obj1, obj2) => {
// 获取对象属性名数组
const getAProperty1 = Object.getOwnPropertyNames(obj1);
const getAProperty2 = Object.getOwnPropertyNames(obj2);
// 如果获取的属性名数组长度不一样,这说明俩者对象内容不一样
if (getAProperty1.length !== getAProperty2.length) {
return false;