diff --git a/dist/lodash.compat.js b/dist/lodash.compat.js index 219d9ccab..28c377f5a 100644 --- a/dist/lodash.compat.js +++ b/dist/lodash.compat.js @@ -1430,51 +1430,54 @@ // recursively compare objects and arrays (susceptible to call stack limits) if (isArr) { + // compare lengths to determine if a deep comparison is necessary length = a.length; size = b.length; + result = size == length; - // compare lengths to determine if a deep comparison is necessary - result = size == a.length; - if (!result && !isWhere) { - return result; - } - // deep compare the contents, ignoring non-numeric properties - while (size--) { - var index = length, - value = b[size]; + if (result || isWhere) { + // deep compare the contents, ignoring non-numeric properties + while (size--) { + var index = length, + value = b[size]; - if (isWhere) { - while (index--) { - if ((result = baseIsEqual(a[index], value, callback, isWhere, stackA, stackB))) { - break; + if (isWhere) { + while (index--) { + if ((result = baseIsEqual(a[index], value, callback, isWhere, stackA, stackB))) { + break; + } } + } else if (!(result = baseIsEqual(a[size], value, callback, isWhere, stackA, stackB))) { + break; } - } else if (!(result = baseIsEqual(a[size], value, callback, isWhere, stackA, stackB))) { - break; } } - return result; } - // deep compare objects using `forIn`, instead of `forOwn`, to avoid `Object.keys` - // which, in this case, is more costly - forIn(b, function(value, key, b) { - if (hasOwnProperty.call(b, key)) { - // count the number of properties. - size++; - // deep compare each property value. - return (result = hasOwnProperty.call(a, key) && baseIsEqual(a[key], value, callback, isWhere, stackA, stackB)); - } - }); - - if (result && !isWhere) { - // ensure both objects have the same number of properties - forIn(a, function(value, key, a) { - if (hasOwnProperty.call(a, key)) { - // `size` will be `-1` if `a` has more properties than `b` - return (result = --size > -1); + else { + // deep compare objects using `forIn`, instead of `forOwn`, to avoid `Object.keys` + // which, in this case, is more costly + forIn(b, function(value, key, b) { + if (hasOwnProperty.call(b, key)) { + // count the number of properties. + size++; + // deep compare each property value. + return (result = hasOwnProperty.call(a, key) && baseIsEqual(a[key], value, callback, isWhere, stackA, stackB)); } }); + + if (result && !isWhere) { + // ensure both objects have the same number of properties + forIn(a, function(value, key, a) { + if (hasOwnProperty.call(a, key)) { + // `size` will be `-1` if `a` has more properties than `b` + return (result = --size > -1); + } + }); + } } + stackA.pop(); + stackB.pop(); + if (initedStack) { releaseArray(stackA); releaseArray(stackB); diff --git a/dist/lodash.compat.min.js b/dist/lodash.compat.min.js index 7ec183e5e..01582f876 100644 --- a/dist/lodash.compat.min.js +++ b/dist/lodash.compat.min.js @@ -11,8 +11,8 @@ var l=Te[a];switch(a){case L:case z:return new l(+n);case W:case M:return new l( if(typeof t=="undefined"||!("prototype"in n))return n;var r=n.__bindData__;if(typeof r=="undefined"&&(Le.funcNames&&(r=!n.name),r=r||!Le.funcDecomp,!r)){var u=be.call(n);Le.funcNames||(r=!A.test(u)),r||(r=B.test(u),ze(n,r))}if(false===r||true!==r&&1&r[1])return n;switch(e){case 1:return function(e){return n.call(t,e)};case 2:return function(e,r){return n.call(t,e,r)};case 3:return function(e,r,u){return n.call(t,e,r,u)};case 4:return function(e,r,u,o){return n.call(t,e,r,u,o)}}return Mt(n,t)}function et(n){function t(){var n=l?a:this; if(u){var h=s(u);je.apply(h,arguments)}return(o||c)&&(h||(h=s(arguments)),o&&je.apply(h,o),c&&h.length=_&&a===n,f=[];if(l){var c=o(r);c?(a=t,r=c):l=false}for(;++ua(r,c)&&f.push(c);return l&&p(r),f}function ot(n,t,e,r){r=(r||0)-1; for(var u=n?n.length:0,o=[];++r=_&&l===n,h=u||g?i():s;for(g&&(h=o(h),l=t);++al(h,y))&&((u||g)&&h.push(y),s.push(v))}return g?(c(h.k),p(h)):u&&c(h),s}function ct(n){return function(t,e,r){var u={}; if(e=v.createCallback(e,r,3),qe(t)){r=-1;for(var o=t.length;++r -1); + else { + // deep compare objects using `forIn`, instead of `forOwn`, to avoid `Object.keys` + // which, in this case, is more costly + forIn(b, function(value, key, b) { + if (hasOwnProperty.call(b, key)) { + // count the number of properties. + size++; + // deep compare each property value. + return (result = hasOwnProperty.call(a, key) && baseIsEqual(a[key], value, callback, isWhere, stackA, stackB)); } }); + + if (result && !isWhere) { + // ensure both objects have the same number of properties + forIn(a, function(value, key, a) { + if (hasOwnProperty.call(a, key)) { + // `size` will be `-1` if `a` has more properties than `b` + return (result = --size > -1); + } + }); + } } + stackA.pop(); + stackB.pop(); + if (initedStack) { releaseArray(stackA); releaseArray(stackB); diff --git a/dist/lodash.min.js b/dist/lodash.min.js index 030c39751..5873f4e5f 100644 --- a/dist/lodash.min.js +++ b/dist/lodash.min.js @@ -13,8 +13,8 @@ return o}function U(n,t,e){var r,u=n,o=u;if(!u)return o;var i=arguments,a=0,f=ty De.funcNames||(r=!O.test(u)),r||(r=E.test(u),$e(n,r))}if(false===r||true!==r&&1&r[1])return n;switch(e){case 1:return function(e){return n.call(t,e)};case 2:return function(e,r){return n.call(t,e,r)};case 3:return function(e,r,u){return n.call(t,e,r,u)};case 4:return function(e,r,u,o){return n.call(t,e,r,u,o)}}return Mt(n,t)}function et(n){function t(){var n=f?i:this;if(u){var h=p(u);be.apply(h,arguments)}return(o||c)&&(h||(h=p(arguments)),o&&be.apply(h,o),c&&h.length=b&&i===n,l=[];if(f){var p=o(r);p?(i=t,r=p):f=false}for(;++ui(r,p)&&l.push(p);return f&&c(r),l}function ut(n,t,e,r){r=(r||0)-1;for(var u=n?n.length:0,o=[];++r=b&&f===n,h=u||v?a():s; +if(f!=q)return false;if(f=n.constructor,p=t.constructor,f!=p&&!(dt(f)&&f instanceof f&&dt(p)&&p instanceof p)&&"constructor"in n&&"constructor"in t)return false}for(f=!u,u||(u=a()),o||(o=a()),p=u.length;p--;)if(u[p]==n)return o[p]==t;var v=0,i=true;if(u.push(n),o.push(t),c){if(p=n.length,v=t.length,(i=v==p)||r)for(;v--;)if(c=p,s=t[v],r)for(;c--&&!(i=ot(n[c],s,e,r,u,o)););else if(!(i=ot(n[v],s,e,r,u,o)))break}else g(t,function(t,a,f){return me.call(f,a)?(v++,i=me.call(n,a)&&ot(n[a],t,e,r,u,o)):void 0}),i&&!r&&g(n,function(n,t,e){return me.call(e,t)?i=-1<--v:void 0 +});return u.pop(),o.pop(),f&&(l(u),l(o)),i}function it(n,t,e,r,u){(Te(t)?St:h)(t,function(t,o){var i,a,f=t,l=n[o];if(t&&((a=Te(t))||Pe(t))){for(f=r.length;f--;)if(i=r[f]==t){l=u[f];break}if(!i){var c;e&&(f=e(l,t),c=typeof f!="undefined")&&(l=f),c||(l=a?Te(l)?l:[]:Pe(l)?l:{}),r.push(t),u.push(l),c||it(l,t,e,r,u)}}else e&&(f=e(l,t),typeof f=="undefined"&&(f=t)),typeof f!="undefined"&&(l=f);n[o]=l})}function at(n,t){return n+he(Re()*(t-n+1))}function ft(e,r,u){var i=-1,f=st(),p=e?e.length:0,s=[],v=!r&&p>=b&&f===n,h=u||v?a():s; for(v&&(h=o(h),f=t);++if(h,y))&&((u||v)&&h.push(y),s.push(g))}return v?(l(h.k),c(h)):u&&l(h),s}function lt(n){return function(t,e,r){var u={};e=J.createCallback(e,r,3),r=-1;var o=t?t.length:0;if(typeof o=="number")for(;++r -1) && indicatorObject; + else { + forIn(b, function(value, key, b) { + if (hasOwnProperty.call(b, key)) { + size++; + return !(result = hasOwnProperty.call(a, key) && baseIsEqual(a[key], value, stackA, stackB)) && indicatorObject; } }); + + if (result) { + forIn(a, function(value, key, a) { + if (hasOwnProperty.call(a, key)) { + return !(result = --size > -1) && indicatorObject; + } + }); + } } + stackA.pop(); + stackB.pop(); return result; } diff --git a/dist/lodash.underscore.min.js b/dist/lodash.underscore.min.js index c8b02197d..2f9c06a12 100644 --- a/dist/lodash.underscore.min.js +++ b/dist/lodash.underscore.min.js @@ -7,11 +7,11 @@ }function i(n){function r(){if(u){var n=e(u);Rr.apply(n,arguments)}if(this instanceof r){var i=f(t.prototype),n=t.apply(i,n||arguments);return O(n)?n:i}return t.apply(o,n||arguments)}var t=n[0],u=n[2],o=n[4];return r}function f(n){return O(n)?Br(n):{}}function a(n,r,t){if(typeof n!="function")return Y;if(typeof r=="undefined"||!("prototype"in n))return n;switch(t){case 1:return function(t){return n.call(r,t)};case 2:return function(t,e){return n.call(r,t,e)};case 3:return function(t,e,u){return n.call(r,t,e,u) };case 4:return function(t,e,u,o){return n.call(r,t,e,u,o)}}return L(n,r)}function l(n){function r(){var n=p?a:this;if(o){var y=e(o);Rr.apply(y,arguments)}return(i||g)&&(y||(y=e(arguments)),i&&Rr.apply(y,i),g&&y.lengthe(r,i)&&o.push(i)}return o}function p(n,r,t,e){e=(e||0)-1;for(var u=n?n.length:0,o=[];++eu(f,l))&&(t&&f.push(l),i.push(a))}return i}function h(n){return function(r,t,e){var u={};t=X(t,e,3),e=-1;var o=r?r.length:0;if(typeof o=="number")for(;++eu(f,l))&&(t&&f.push(l),i.push(a))}return i}function h(n){return function(r,t,e){var u={};t=X(t,e,3),e=-1;var o=r?r.length:0;if(typeof o=="number")for(;++eu&&(u=t); else r=X(r,t,3),D(n,function(n,t,o){t=r(n,t,o),t>e&&(e=t,u=n)});return u}function W(n,r,t,e){if(!n)return t;var u=3>arguments.length;r=X(r,e,4);var o=-1,i=n.length;if(typeof i=="number")for(u&&(t=n[++o]);++oarguments.length;return r=X(r,e,4),I(n,function(n,e,o){t=u?(u=false,n):r(t,n,e,o)}),t}function C(n){var r=-1,t=n?n.length:0,e=Array(typeof t=="number"?t:0);return D(n,function(n){var t;t=++r,t=0+Sr(Wr()*(t-0+1)),e[r]=e[t],e[t]=n diff --git a/lodash.js b/lodash.js index 4b2c0042c..f57b1db08 100644 --- a/lodash.js +++ b/lodash.js @@ -1446,51 +1446,54 @@ // recursively compare objects and arrays (susceptible to call stack limits) if (isArr) { + // compare lengths to determine if a deep comparison is necessary length = a.length; size = b.length; + result = size == length; - // compare lengths to determine if a deep comparison is necessary - result = size == a.length; - if (!result && !isWhere) { - return result; - } - // deep compare the contents, ignoring non-numeric properties - while (size--) { - var index = length, - value = b[size]; + if (result || isWhere) { + // deep compare the contents, ignoring non-numeric properties + while (size--) { + var index = length, + value = b[size]; - if (isWhere) { - while (index--) { - if ((result = baseIsEqual(a[index], value, callback, isWhere, stackA, stackB))) { - break; + if (isWhere) { + while (index--) { + if ((result = baseIsEqual(a[index], value, callback, isWhere, stackA, stackB))) { + break; + } } + } else if (!(result = baseIsEqual(a[size], value, callback, isWhere, stackA, stackB))) { + break; } - } else if (!(result = baseIsEqual(a[size], value, callback, isWhere, stackA, stackB))) { - break; } } - return result; } - // deep compare objects using `forIn`, instead of `forOwn`, to avoid `Object.keys` - // which, in this case, is more costly - forIn(b, function(value, key, b) { - if (hasOwnProperty.call(b, key)) { - // count the number of properties. - size++; - // deep compare each property value. - return (result = hasOwnProperty.call(a, key) && baseIsEqual(a[key], value, callback, isWhere, stackA, stackB)); - } - }); - - if (result && !isWhere) { - // ensure both objects have the same number of properties - forIn(a, function(value, key, a) { - if (hasOwnProperty.call(a, key)) { - // `size` will be `-1` if `a` has more properties than `b` - return (result = --size > -1); + else { + // deep compare objects using `forIn`, instead of `forOwn`, to avoid `Object.keys` + // which, in this case, is more costly + forIn(b, function(value, key, b) { + if (hasOwnProperty.call(b, key)) { + // count the number of properties. + size++; + // deep compare each property value. + return (result = hasOwnProperty.call(a, key) && baseIsEqual(a[key], value, callback, isWhere, stackA, stackB)); } }); + + if (result && !isWhere) { + // ensure both objects have the same number of properties + forIn(a, function(value, key, a) { + if (hasOwnProperty.call(a, key)) { + // `size` will be `-1` if `a` has more properties than `b` + return (result = --size > -1); + } + }); + } } + stackA.pop(); + stackB.pop(); + if (initedStack) { releaseArray(stackA); releaseArray(stackB); diff --git a/test/test.js b/test/test.js index 6fb1a73cf..f7d722665 100644 --- a/test/test.js +++ b/test/test.js @@ -3836,9 +3836,9 @@ strictEqual(_.isEqual(array1, array2), false); - array1 = ['a','b', 'c']; + array1 = ['a', 'b', 'c']; array1[1] = array1; - array2 = ['a', ['b', 'b'], 'c']; + array2 = ['a', ['a', 'b', 'c'], 'c']; strictEqual(_.isEqual(array1, array2), false); }); @@ -3864,7 +3864,7 @@ object1 = { 'a': 1, 'b': 2, 'c': 3 }; object1.b = object1; - object2 = { 'a': 1, 'b': { 'b': 2 }, 'c': 3 }; + object2 = { 'a': 1, 'b': { 'a': 1, 'b': 2, 'c': 3 }, 'c': 3 }; strictEqual(_.isEqual(object1, object2), false); }); @@ -3909,17 +3909,19 @@ strictEqual(_.isEqual(object1, object2), true); }); - test('should return `false` when comparing values with circular references to unlike values', 2, function() { - var array1 = ['a', null, 'c'], - array2 = ['a', [], 'c'], - object1 = { 'a': 1, 'b': null, 'c': 3 }, - object2 = { 'a': 1, 'b': {}, 'c': 3 }; + test('should perform comparisons between objects with shared property values', function() { + var object1 = { + 'a': [1, 2] + }; - array1[1] = array1; - strictEqual(_.isEqual(array1, array2), false); + var object2 = { + 'a': [1, 2], + 'b': [1, 2] + }; - object1.b = object1; - strictEqual(_.isEqual(object1, object2), false); + object1.b = object1.a; + + strictEqual(_.isEqual(object1, object2), true); }); test('should pass the correct `callback` arguments', 1, function() {