ut2
Version:
一个现代 JavaScript 实用工具库。[点击查看在线文档]。
181 lines (177 loc) • 6.16 kB
JavaScript
'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;