JS对比两个对象键值全等

478 阅读4分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第3天,点击查看活动详情

比较两个对象的键值是否全等,说的就是字面上的相等,也就是看起来的一模一样的,举个栗子

	let o1 = {                      let o2 = {
		name: 'joe',                    name: 'joe'  
		isOld: false,                   isOld: false,
		age: 24,                        age: 24,
		blank: null,                    blank: null,
		what: undefined,                what: undefined,
		fun: function() {               fun: function() {
			return 'test';                      return 'test';
		},                              },
		strange: NaN,                  strange: NaN,
		newType: Symbol('symbol')       newType: Symbol('symbol')
	}                                    }

上面这两个对象你说相等不相等,肯定不相等,但是键值是否全等,那的确就是全等的,我们就是要写个函数来检查两个函数是否键值全等 (键的顺序是不分的),那我们就来理清一下写这个函数的思路: 我们肯定是要遍历键去对比,所以我们先保证长度是一致的

1. 获取两个对象的键数组,然后对比长度
2. 不同得类型的属性你得用不同得方法判断属性值是否相等,这里并不是指基本类型,而是我们要做不同方法判断时候分成4种
  1. Number , Boolean, String, Null, Undefined 这5种基本类型我们可以直接对比,
	Object.is(params1, params2); // 为什么不用 ===, 因为Number类型会有NaN
  1. Symbol和Function,这种基本类型我们直接对比不了,只能转为字符串对比
	(String(params1) === String(params2)) // 为什么不用toString(), 因为Function没有toString()
  1. Object,这个我们无法直接对比,因为你不知道它里面还包含多少的东西,所以这个要递归分解成其他的数据类型在对比,后面就是用递归来解决Object的对比
  2. ,函数这个就比较特殊了,这个只能是转成字符串去对比一下
	(String(function() {let aa= 1}) === String(function() {let aa= 1}))
3. 我们还要知道怎么去判断值是属于哪种类型,我们就使用 typeof 去判断,对于null值,typeof 会返回 object,所以如果是object 类型还要判断一下是否是恒等于null
	if (typeof val === 'object' && val !== null) // 这是object类型了
	if (typeof val === 'symbol') // Symbol类型
	if (typeof val === 'function') // Function类型
	else // 剩下得类型就是 Number , Boolean, String, Null, Undefined

好了说了一大堆,我们要开始写代码了,还有记住es6获取所有键得方法,Object.keys()会返回一个键得数组,上代码

    /**
     * @Description 比较两个对象键值全等
     * @author joe
     * @date 2020-11-15 14:59:03
     * @param {Object} objOne 对象1
     * @param {Object} objTwo 对象2
     * @return {Boolean} 是否键值全等
     **/
    function objKeyValueIsSame(objOne, objTwo) {
        let keysOne = Object.keys(objOne); // 获取对象1所有键数组
        let keysTwo = Object.keys(objTwo); // 获取对象1所有键数组
        if (keysOne.length !== keysTwo.length) return false; // 对比一下键得长度是否相等,如果不等则直接返回true
        // 开始遍历键去获取对象值对比,我们思路是值不匹配则返回false,但是如果匹配则则什么都不要,继续循环,直到循环结束,没有返回false就行了
        for (let key of keysOne) {
            if (typeof objOne[key] === 'object' && objOne[key] !== null) {  // 如果是对象,则再递归对比,如果递归返回false,则直接方法也直接返回false
                if (!objKeyValueIsSame(objOne[key], objTwo[key])) return false;
            } else if (typeof objOne[key] === 'function' || typeof objOne[key] === 'symbol') { // 如果是function或symbol,转字符串再对比,不匹配则直接返回false
                if (String(objOne[key]) !== String(objTwo[key])) return false;
            } else {  // 最后其他类型用es6得Object.is()来比较,不匹配直接返回false
                if (!Object.is(objOne[key], objTwo[key])) return false;
            }
        }
        return true;  // 遍历结束了没有返回false,说明没有问题,这里直接返回true,表示键值全等了
    }

    let aa = {
        age: 24,
        blank: null,
        what: undefined,
        fun: function () {
            return 'test';
        },
        strange: NaN,
        newType: Symbol('symbol')
    }
    let bb = {
        age: 24,
        blank: null,
        what: undefined,
        fun: function () {
            return 'test';
        },
        strange: NaN,
        newType: Symbol('symbol')
    }

    console.log(objKeyValueIsSame(aa, bb))

上面得代码两个重点

  1. 你得明白递归
  2. 思路是如果遍历时候有不匹配就返回false直接结束整个函数,但是匹配得不要返回true,因为遍历的时候你不知道有没有遍历完,所以再for循环下面再返回ture

总结

最后总结一下,你要知道一个object里面的属性可以有多少种类型,然后每种类型应该用什么的对比方法