1. 背景
现有两个对象或值,需要实现如下代码效果(本文均以第一个参数称为A参数
,第二个参数称为B参数
,下文同)
- 若 B 对象中的键都存在于
obj
中,且值能一一对应,则返回 true(见下代码第一行) - 若 B 对象中有一个键不存在于
obj
中,则返回 false(见下代码第二行)
console.log(isMatch({ aa: 11, bb: 22 }, { bb: 22 })) // true -> bb 存在且值能对应,返回 true
console.log(isMatch({ bb: 22 }, { aa: 11, bb: 22 })) // false -> aa 不存在于第一个参数中,返回 false
console.log(isMatch({ aa: 11, bb: 22 }, { bb: 33 })) // false -> bb 存在于第一个参数中,但值不对应,返回 false
console.log(isMatch([1], { 0: 1 })) // true
2. 源码解析
实现的过程注意点如下:
- 一旦A参数中存在,但B参数中不存在的键,则直接返回 false
- 数组也有键值对,需考虑数组与对象比较的情况
源码中会有一些我们未讲过的函数的封装,如果你觉得过于复杂,可以直接阅读 2.2
中笔者以相同思路 简化过的代码,其中包含每个步骤的详细注释,可学习到的思路基本一致。
2.1 xe-utils 源码实现 isMatch
var keys = require("./keys");
var findIndexOf = require("./findIndexOf");
var isEqual = require("./isEqual");
var some = require("./some");
var includeArrays = require("./includeArrays");
/**
* 判断属性中的键和值是否包含在对象中
*
* @param {Object/Array} obj 对象
* @param {Object} source 值
* @return {Boolean}
*/
function isMatch(obj, source) {
var objKeys = keys(obj);
var sourceKeys = keys(source);
if (sourceKeys.length) {
if (includeArrays(objKeys, sourceKeys)) {
return some(sourceKeys, function (key2) {
return (
findIndexOf(objKeys, function (key1) {
return key1 === key2 && isEqual(obj[key1], source[key2]);
}) > -1
);
});
}
} else {
return true;
}
return isEqual(obj, source);
}
module.exports = isMatch;
2.2 简化代码
注意:
isEqual
:该 深度比较函数 已在上期讲解过源码,还未读过的同学请务必前往复习一下 【源码阅读 | xe-utils源码 | 06】isEqual 深度比较两个值是否相等includeArrays
:该函数用于判断一个数组 是否完全包含另一个数组,实现源码会在下面2.3
讲解
var isEqual = require('./isEqual')
var includeArrays = require('../Array/includeArrays')
// obj 为较大的集合,source 为被比对的子集
function isMatch(obj, source) {
// 1.获取对象的 key
const k1 = Object.keys(obj)
const k2 = Object.keys(source)
// 2.若source无值,则直接返回true
if (!k2.length) return true
// 3.若待匹配项中存在key值与被匹配项对应,则说明键对应得上(说明k1包含k2)
if (includeArrays(k1, k2)) {
return k2.some((key) => {
// 4.匹配键值,只要有一个键值对应得上,则返回true
return isEqual(obj[key], source[key])
})
}
// 5.除对象和数组之外的特殊情况判断
return isEqual(obj, source)
}
module.exports = isMatch
2.3 includeArrays
注意点如下:
includes
:本文不讨论该函数源码,可以理解为是对Array.includes
的封装,内加了一些对兼容性的判断isArray
:该函数的源码在前面文章已讲解,还未读过的同学请务必前往复习一下 【源码阅读 | xe-utils源码 | 02】判断Array类型- 需要判断传入的参数 是否为数组,
避免
非 Array 型使用Array.includes
方法会报错
实现思路非常简单:
遍历两个数组元素,一旦 keyA 数组中不包含 keyB 的任一 key 值,直接返回 false;否则返回 true。
举例:keyA = [1, 2, 3] keyB = [2, 3, 4],4就是 keyA 中不存在的 key,因此返回 false
includeArrays.js
源码实现
var isArray = require("./isArray");
var includes = require("./includes");
/**
* 判断数组是否包含另一数组
*
* @param {Array} array1 数组
* @param {Array} array2 被包含数组
* @return {Boolean}
*/
function includeArrays(array1, array2) {
var len;
var index = 0;
if (isArray(array1) && isArray(array2)) {
for (len = array2.length; index < len; index++) {
if (!includes(array1, array2[index])) {
return false;
}
}
return true;
}
return includes(array1, array2);
}
module.exports = includeArrays;