UNPKG

ut2

Version:

一个现代 JavaScript 实用工具库。[点击查看在线文档]。

181 lines (177 loc) 6.16 kB
'use strict'; var allKeys = require('../allKeys.js'); var eq = require('../eq.js'); var getTagWithBugfix = require('./getTagWithBugfix.js'); var native = require('./native.js'); var isBuffer = require('../isBuffer.js'); var isFunction = require('../isFunction.js'); var isNil = require('../isNil.js'); var isObjectLike = require('../isObjectLike.js'); var isTypedArray = require('../isTypedArray.js'); var orderBy = require('../orderBy.js'); var symbolValueOf = native.symbolProto ? native.symbolProto.valueOf : native.nativeUndefined; function mapToArray(map) { var result = []; map.forEach(function (value, key) { result.push([key, value]); }); return orderBy(result, [0, 1]); } function setToArray(set) { var result = []; set.forEach(function (value) { result.push(value); }); return orderBy(result); } function argToArray(arg) { return native.arrayProtoSlice.call(arg); } function toBufferView(bufferSource) { return new Uint8Array(bufferSource.buffer || bufferSource, bufferSource.byteOffset || 0, bufferSource.byteLength); } function isDomNode(obj) { return isObjectLike(obj) && typeof obj.nodeType === 'number' && typeof obj.nodeName === 'string' && typeof obj.isEqualNode === 'function'; } function isEqualDeep(value, other, customizer, strictCheck, valueStack, otherStack) { if (eq(value, other, strictCheck)) { return true; } var valType = typeof value; var othType = typeof other; if (strictCheck && valType !== othType) { return false; } if (isNil(value) || isNil(other) || (valType !== 'object' && othType !== 'object')) { return false; } var tag = getTagWithBugfix(value); if (tag !== getTagWithBugfix(other)) { return false; } var convert; switch (tag) { case native.numberTag: return eq(+value, +other, strictCheck); case native.booleanTag: case native.dateTag: return strictCheck ? +value === +other : eq(+value, +other); case native.stringTag: case native.regExpTag: return '' + value === '' + other; case native.symbolTag: return symbolValueOf ? symbolValueOf.call(value) === symbolValueOf.call(other) : false; case native.errorTag: return value.name === other.name && value.message === other.message; case native.dataViewTag: case native.arrayBufferTag: if (value.byteLength !== other.byteLength || (value.byteOffset && value.byteOffset !== other.byteOffset)) { return false; } convert = toBufferView; break; case native.mapTag: convert = mapToArray; break; case native.setTag: convert = setToArray; break; case native.argumentsTag: convert = argToArray; break; } if (convert) { return isEqualDeep(convert(value), convert(other), customizer, strictCheck, valueStack, otherStack); } if (isDomNode(value) && isDomNode(other)) { return value.isEqualNode(other); } var areArrays = tag === native.arrayTag; if (!areArrays && isTypedArray(value)) { if (value.byteLength !== other.byteLength) { return false; } if (value.buffer === other.buffer && value.byteOffset === other.byteOffset) { return true; } areArrays = true; } if (isBuffer(value)) { if (!isBuffer(other)) { return false; } areArrays = true; } valueStack = valueStack || []; otherStack = otherStack || []; var length = valueStack.length; while (length--) { if (valueStack[length] === value) { return otherStack[length] === other; } } valueStack.push(value); otherStack.push(other); var result = true; var hasCustomizer = typeof customizer === 'function'; if (areArrays) { length = value.length; if (length !== other.length) { return false; } while (length--) { if (hasCustomizer) { var compared = customizer(value[length], other[length], length, value, other, valueStack, otherStack); if (compared !== native.nativeUndefined) { if (!compared) { return false; } continue; } } if (!isEqualDeep(value[length], other[length], customizer, strictCheck, valueStack, otherStack)) { return false; } } } else if (tag === native.objectTag) { var keys = allKeys(value); length = keys.length; if (allKeys(other).length !== length) { return false; } var skipCtor = false; while (length--) { var key = keys[length]; if (hasCustomizer) { var compared = customizer(value[key], other[key], key, value, other, valueStack, otherStack); if (compared !== native.nativeUndefined) { if (!compared) { return false; } continue; } } if (!(native.objectProtoHasOwnProperty.call(other, key) && isEqualDeep(value[key], other[key], customizer, strictCheck, valueStack, otherStack))) { return false; } if (!skipCtor && key === 'constructor') { skipCtor = true; } } if (!skipCtor) { var valCtor = value.constructor; var othCtor = other.constructor; if (valCtor !== othCtor && !(isFunction(valCtor) && valCtor instanceof valCtor && isFunction(othCtor) && othCtor instanceof othCtor) && 'constructor' in value && 'constructor' in other) { return false; } } } else { result = false; } valueStack.pop(); otherStack.pop(); return result; } module.exports = isEqualDeep;