_.isEqual 比較二者的值是否相等。
_.isEqualWith(value, other, [customizer]),也是比較二者的值是否相等。它還接受一個customizer
咱們須要比較的類型有許多。 對象,數組,字符串,布爾,Date,正則,Symbool等。javascript
/** * Performs a deep comparison between two values to determine if they are * equivalent. * * **Note:** This method supports comparing arrays, array buffers, booleans, * date objects, error objects, maps, numbers, `Object` objects, regexes, * sets, strings, symbols, and typed arrays. `Object` objects are compared * by their own, not inherited, enumerable properties. Functions and DOM * nodes are **not** supported. * var object = { 'a': 1 }; * var other = { 'a': 1 }; * * _.isEqual(object, other); * // => true * * object === other; * // => false */ function isEqual(value, other) { return baseIsEqual(value, other); }
isEqual方法提供了一個很深的比較來決定兩個值是否相等。該方法支持array,array buffers,booleans,data objects,error objects,maps,numbers,等等等等
java
對於稍複雜一點的對象,支持比較自身的屬性,可是不包括繼承和可枚舉的屬性。node
不支持函數和dom節點的比較。數組
/** * @param {Function} [customizer] The function to customize comparisons. * @param {boolean} [bitmask] The bitmask of comparison flags. * The bitmask may be composed of the following flags: * 1 - Unordered comparison 無序的比較 * 2 - Partial comparison 部分比較。 * @param {Object} [stack] Tracks traversed `value` and `other` objects. 跟蹤 傳入的value和other * @returns {boolean} 是否相等 */ function baseIsEqual(value, other, customizer, bitmask, stack) { if (value === other) { return true; } if (value == null || other == null || (!isObject(value) && !isObjectLike(other))) { return value !== value && other !== other; //NaN } return baseIsEqualDeep(value, other, baseIsEqual, customizer, bitmask, stack); }
_.isEqual
的基本實現,支持部分比較和跟蹤遍歷對象。app
看了幾個參數,有幾點須要注意
/** * A specialized version of `baseIsEqual` for arrays and objects which performs * deep comparisons and tracks traversed objects enabling objects with circular * references to be compared. * * @private * @param {Object} object The object to compare. * @param {Object} other The other object to compare. * @param {Function} equalFunc The function to determine equivalents of values. * @param {Function} [customizer] The function to customize comparisons. * @param {number} [bitmask] The bitmask of comparison flags. See `baseIsEqual` * for more details. * @param {Object} [stack] Tracks traversed `object` and `other` objects. * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. */ function baseIsEqualDeep(object, other, equalFunc, customizer, bitmask, stack) { var objIsArr = isArray(object),//數組? othIsArr = isArray(other),//數組 objTag = arrayTag,//[object Array] othTag = arrayTag;//[object Array] if (!objIsArr) { objTag = getTag(object); objTag = objTag == argsTag ? objectTag : objTag;// '[object Arguments]' ? } if (!othIsArr) { othTag = getTag(other); othTag = othTag == argsTag ? objectTag : othTag; } var objIsObj = objTag == objectTag && !isHostObject(object),// obj是不是obj othIsObj = othTag == objectTag && !isHostObject(other),// oth是不是obj isSameTag = objTag == othTag; // obj 和 oth是不是統一類型 if (isSameTag && !objIsObj) { stack || (stack = new Stack); return (objIsArr || isTypedArray(object)) ? equalArrays(object, other, equalFunc, customizer, bitmask, stack)// 數組比較 : equalByTag(object, other, objTag, equalFunc, customizer, bitmask, stack);// 對象比較 } if (!(bitmask & PARTIAL_COMPARE_FLAG)) { var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'), //被包裝對象 othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__'); // 被包裝的。 if (objIsWrapped || othIsWrapped) { var objUnwrapped = objIsWrapped ? object.value() : object, othUnwrapped = othIsWrapped ? other.value() : other; stack || (stack = new Stack); return equalFunc(objUnwrapped, othUnwrapped, customizer, bitmask, stack); } } if (!isSameTag) { // 不是相同的標籤 return false; } stack || (stack = new Stack); return equalObjects(object, other, equalFunc, customizer, bitmask, stack); }
equalArrays
equalObjects
equa
equalFunc
,暫時不解釋相關調用邏輯dom
equalArrays
equalByTag
equalObjects
baseIsEqualDeep
的專門版本用來比較相同tag的對象。它僅支持Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String
函數
function equalByTag(object, other, tag, equalFunc, customizer, bitmask, stack) { switch (tag) { case dataViewTag: //'[object DataView]' if ((object.byteLength != other.byteLength) || (object.byteOffset != other.byteOffset)) { return false; } object = object.buffer; other = other.buffer; case arrayBufferTag: // '[object ArrayBuffer]' if ((object.byteLength != other.byteLength) || !equalFunc(new Uint8Array(object), new Uint8Array(other))) { return false; } return true; case boolTag: case dateTag: case numberTag: // Coerce booleans to `1` or `0` and dates to milliseconds. 布爾值會轉成"1"或者"0";日期會被轉換成毫秒。 // Invalid dates are coerced to `NaN`.無效的dates會被轉成NaN return eq(+object, +other);// eq是淺比較判斷相等 case errorTag: // => new Error return object.name == other.name && object.message == other.message; case regexpTag: // 正則 => new Rexg case stringTag: // 字符串 => new String // Coerce regexes to strings and treat strings, primitives and objects, 將regexes強制轉換爲字符串,若是轉換的字符串相等,則原對象也相等。 // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring // for more details. return object == (other + ''); case mapTag: var convert = mapToArray; // 將map轉成數組 case setTag: var isPartial = bitmask & PARTIAL_COMPARE_FLAG; convert || (convert = setToArray); if (object.size != other.size && !isPartial) { return false; } // Assume cyclic values are equal.// 循環引用 var stacked = stack.get(object); if (stacked) { // 存在直接判斷返回 return stacked == other; } bitmask |= UNORDERED_COMPARE_FLAG; // Recursively compare objects (susceptible to call stack limits). stack.set(object, other); // 調用的是數組比較方法,object和other爲set或者map,將之轉換成數組。再去比較。 var result = equalArrays(convert(object), convert(other), equalFunc, customizer, bitmask, stack); stack['delete'](object);// 刪除掉對應的object return result; case symbolTag: if (symbolValueOf) { //symbolProto=>symbolProto.valueOf return symbolValueOf.call(object) == symbolValueOf.call(other); // 相等條件是比較二者的valueof。 } } return false; }
一個特殊版本的baseIsEqualDeep方法,用來比較對象。學習
/** * A specialized version of `baseIsEqualDeep` for objects with support for * partial deep comparisons */ function equalObjects(object, other, equalFunc, customizer, bitmask, stack) { var isPartial = bitmask & PARTIAL_COMPARE_FLAG, objProps = keys(object),// object.keys(object) => [keyName0] objLength = objProps.length, // obj長度 othProps = keys(other),//other keys數組 othLength = othProps.length;// other的長度 if (objLength != othLength && !isPartial) { return false; } var index = objLength; while (index--) { // 這裏判斷,若是 object的屬性名在other中不存在,直接返回 var key = objProps[index];// obj中的屬性名 if (!(isPartial ? key in other : /* other中有這個keyname**/hasOwnProperty.call(other, key))) { //object自由屬性中沒有key這個屬性,就不想等 return false; } } // Assume cyclic values are equal. var stacked = stack.get(object); if (stacked && stack.get(other)) { return stacked == other; } var result = true; stack.set(object, other); stack.set(other, object); var skipCtor = isPartial; while (++index < objLength) { key = objProps[index]; var objValue = object[key], othValue = other[key]; if (customizer) { var compared = isPartial ? customizer(othValue, objValue, key, other, object, stack) : customizer(objValue, othValue, key, object, other, stack); } // Recursively compare objects (susceptible to call stack limits). // 這裏是判斷對應key的value是否相等。直接返回false。固然即使相等,這裏的邏輯也不足夠嚴謹,還要往下走,比對constructor。這裏使用`equalFunc`比較,是由於咱們沒法判斷value的類型,此時的equalFunc 還是`baseIsEqual` if (!(compared === undefined ? (objValue === othValue || equalFunc(objValue, othValue, customizer, bitmask, stack)) : compared )) { result = false; break; } skipCtor || (skipCtor = key == 'constructor'); } if (result && !skipCtor) { // result爲true,是經過上邊的比較以後,仍然相等,那麼就要去比對對象的constructor。即使key和value相等,可是constructor不相同,那麼仍然不相等。 var objCtor = object.constructor, othCtor = other.constructor; // Non `Object` object instances with different constructors are not equal. if (objCtor != othCtor && ('constructor' in object && 'constructor' in other) && !(typeof objCtor == 'function' && objCtor instanceof objCtor && typeof othCtor == 'function' && othCtor instanceof othCtor)) { result = false; } } stack['delete'](object); stack['delete'](other); return result; }
equalObjects
先去判斷object
和other
的屬性名是否相同,不相同直接返回。知足以上3個條件,對象纔是相等的。ui
/** * A specialized version of `baseIsEqualDeep` for arrays with support for * partial deep comparisons. */ function equalArrays(array, other, equalFunc, customizer, bitmask, stack) { var isPartial = bitmask & PARTIAL_COMPARE_FLAG, arrLength = array.length,//array的長度 othLength = other.length;// other的長度 if (arrLength != othLength && !(isPartial && othLength > arrLength)) { // 數組長度不相等,直接返回false return false; } // Assume cyclic values are equal. 假設循環值相等。 var stacked = stack.get(array); // 若是stacked不是undefined,咱們當前看的 _.isEqual 是不存在這個判斷的 if (stacked && stack.get(other)) { return stacked == other; } var index = -1, result = true, seen = (bitmask & UNORDERED_COMPARE_FLAG) ? new SetCache : undefined; stack.set(array, other); // array 和 other作了關聯 , stack.set(other, array); // Ignore non-index properties. 忽略沒有index的屬性 while (++index < arrLength) { var arrValue = array[index], othValue = other[index]; if (customizer) { var compared = isPartial ? customizer(othValue, arrValue, index, other, array, stack) : customizer(arrValue, othValue, index, array, other, stack); } if (compared !== undefined) { if (compared) { continue; } result = false; break; } // Recursively compare arrays (susceptible to call stack limits). if (seen) { if (!arraySome(other, function(othValue, othIndex) { if (!seen.has(othIndex) && (arrValue === othValue || equalFunc(arrValue, othValue, customizer, bitmask, stack))) { return seen.add(othIndex); } })) { result = false; break; } } else if (!( arrValue === othValue || equalFunc(arrValue, othValue, customizer, bitmask, stack) // 若是不相等,直接跳走。 )) { result = false; break; } } stack['delete'](array); stack['delete'](other); return result; }
bitmask 按位操做符.
1&0=>0,undefined &1 =>0,1&1=>1
https://developer.mozilla.org...