From 31e86a36f87822e1a3c72a79ede8d44a832ca0fb Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 17 Oct 2013 22:53:40 -0700 Subject: [PATCH] Ensure `_.isEqual` works with objects created by `Object.create(null)`. --- dist/lodash.compat.js | 40 +++++++++++++----------- dist/lodash.compat.min.js | 8 ++--- dist/lodash.js | 40 +++++++++++++----------- dist/lodash.min.js | 59 ++++++++++++++++++----------------- dist/lodash.underscore.js | 36 +++++++++++---------- dist/lodash.underscore.min.js | 6 ++-- lodash.js | 8 ++--- test/test.js | 21 +++++++++++-- 8 files changed, 124 insertions(+), 94 deletions(-) diff --git a/dist/lodash.compat.js b/dist/lodash.compat.js index 941f4dfcd..e0828ed4e 100644 --- a/dist/lodash.compat.js +++ b/dist/lodash.compat.js @@ -1261,10 +1261,10 @@ ctorB = !support.argsObject && isArguments(b) ? Object : b.constructor; // non `Object` object instances with different constructors are not equal - if (ctorA != ctorB && !( - isFunction(ctorA) && ctorA instanceof ctorA && - isFunction(ctorB) && ctorB instanceof ctorB - )) { + if (ctorA != ctorB && + !(isFunction(ctorA) && ctorA instanceof ctorA && isFunction(ctorB) && ctorB instanceof ctorB) && + (!nativeCreate || ('constructor' in a && 'constructor' in b)) + ) { return false; } } @@ -1956,15 +1956,15 @@ * @returns {Object} Returns the destination object. * @example * - * _.assign({ 'name': 'fred' }, { 'age': 40 }); - * // => { 'name': 'fred', 'age': 40 } + * _.assign({ 'name': 'fred' }, { 'employer': 'slate' }); + * // => { 'name': 'fred', 'employer': 'slate' } * * var defaults = _.partialRight(_.assign, function(a, b) { * return typeof a == 'undefined' ? b : a; * }); * - * var person = { 'name': 'barney' }; - * defaults(person, { 'name': 'fred', 'employer': 'slate' }); + * var object = { 'name': 'barney' }; + * defaults(object, { 'name': 'fred', 'employer': 'slate' }); * // => { 'name': 'barney', 'employer': 'slate' } */ var assign = createIterator(defaultsIteratorOptions, { @@ -2092,8 +2092,8 @@ * @returns {Object} Returns the destination object. * @example * - * var person = { 'name': 'barney' }; - * _.defaults(person, { 'name': 'fred', 'employer': 'slate' }); + * var object = { 'name': 'barney' }; + * _.defaults(object, { 'name': 'fred', 'employer': 'slate' }); * // => { 'name': 'barney', 'employer': 'slate' } */ var defaults = createIterator(defaultsIteratorOptions); @@ -2513,13 +2513,13 @@ * @returns {boolean} Returns `true` if the values are equivalent, else `false`. * @example * - * var fred = { 'name': 'fred', 'age': 40 }; - * var copy = { 'name': 'fred', 'age': 40 }; + * var object = { 'name': 'fred' }; + * var copy = { 'name': 'fred' }; * - * fred == copy; + * object == copy; * // => false * - * _.isEqual(fred, copy); + * _.isEqual(object, copy); * // => true * * var words = ['hello', 'goodbye']; @@ -3417,6 +3417,10 @@ * (value, index|key, collection). Callbacks may exit iteration early by * explicitly returning `false`. * + * Note: As with other "Collections" methods, objects with a `length` property + * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn` + * may be used for object iteration. + * * @static * @memberOf _ * @alias each @@ -5342,11 +5346,11 @@ * // => 'hi fred' * * object.greet = function(greeting) { - * return greeting + ', ' + this.name + '!'; + * return greeting + 'ya ' + this.name + '!'; * }; * * func(); - * // => 'hi, fred!' + * // => 'hiya fred!' */ function bindKey(object, key) { return arguments.length > 2 @@ -5940,8 +5944,8 @@ * @returns {*} Returns `value`. * @example * - * var fred = { 'name': 'fred' }; - * fred === _.identity(fred); + * var object = { 'name': 'fred' }; + * object === _.identity(object); * // => true */ function identity(value) { diff --git a/dist/lodash.compat.min.js b/dist/lodash.compat.min.js index 38bacc987..c2b891cf4 100644 --- a/dist/lodash.compat.min.js +++ b/dist/lodash.compat.min.js @@ -9,10 +9,10 @@ }function j(n,t,e,r,u){if(e){var o=e(n);if(typeof o!="undefined")return o}if(!wt(n))return n;var a=ke.call(n);if(!U[a]||!We.nodeClass&&f(n))return n;var l=qe[a];switch(a){case z:case q:return new l(+n);case G:case H:return new l(n);case M:return o=l(n.source,I.exec(n)),o.lastIndex=n.lastIndex,o}if(a=Je(n),t){var c=!r;r||(r=i()),u||(u=i());for(var s=r.length;s--;)if(r[s]==n)return u[s];o=a?l(n.length):{}}else o=a?g(n):er({},n);return a&&(de.call(n,"index")&&(o.index=n.index),de.call(n,"input")&&(o.input=n.input)),t?(r.push(n),u.push(o),(a?tr:or)(n,function(n,a){o[a]=j(n,t,e,r,u) }),c&&(p(r),p(u)),o):o}function Z(n,t,e){if(typeof n!="function")return Ut;if(typeof t=="undefined"||!("prototype"in n))return n;var r=n.__bindData__;if(typeof r=="undefined"&&(We.funcNames&&(r=!n.name),r=r||!We.funcDecomp,!r)){var u=ye.call(n);We.funcNames||(r=!A.test(u)),r||(r=P.test(u),Ge(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 Jt(n,t)}function tt(n,t,e,r){r=(r||0)-1;for(var u=n?n.length:0,o=[];++r=w&&l===n,h=u||g?i():c;if(g){var v=o(h);v?(l=t,h=v):(g=!1,h=u?h:(p(h),c))}for(;++al(h,y))&&((u||g)&&h.push(y),c.push(v)) -}return g?(p(h.k),s(h)):u&&p(h),c}function lt(n){return function(t,e,r){var u={};if(e=y.createCallback(e,r,3),Je(t)){r=-1;for(var o=t.length;++r=w&&l===n,h=u||g?i():c;if(g){var v=o(h);v?(l=t,h=v):(g=!1,h=u?h:(p(h),c))}for(;++al(h,y))&&((u||g)&&h.push(y),c.push(v))}return g?(p(h.k),s(h)):u&&p(h),c}function lt(n){return function(t,e,r){var u={};if(e=y.createCallback(e,r,3),Je(t)){r=-1;for(var o=t.length;++rk;k++)r+="n='"+e.h[k]+"';if((!(r&&x[n])&&m.call(t,n))",e.j||(r+="||(!x[n]&&t[n]!==A[n])"),r+="){"+e.g+"}";r+="}"}return(e.b||We.nonEnumArgs)&&(r+="}"),r+=e.c+";return E",n("d,j,k,m,o,p,q,s,v,A,B,y,I,J,L",t+r+"}")(Z,K,le,de,_,yt,Je,xt,X.f,fe,Y,Ke,H,ce,ke) diff --git a/dist/lodash.js b/dist/lodash.js index 249960fe1..98e712937 100644 --- a/dist/lodash.js +++ b/dist/lodash.js @@ -985,10 +985,10 @@ ctorB = b.constructor; // non `Object` object instances with different constructors are not equal - if (ctorA != ctorB && !( - isFunction(ctorA) && ctorA instanceof ctorA && - isFunction(ctorB) && ctorB instanceof ctorB - )) { + if (ctorA != ctorB && + !(isFunction(ctorA) && ctorA instanceof ctorA && isFunction(ctorB) && ctorB instanceof ctorB) && + (!nativeCreate || ('constructor' in a && 'constructor' in b)) + ) { return false; } } @@ -1568,15 +1568,15 @@ * @returns {Object} Returns the destination object. * @example * - * _.assign({ 'name': 'fred' }, { 'age': 40 }); - * // => { 'name': 'fred', 'age': 40 } + * _.assign({ 'name': 'fred' }, { 'employer': 'slate' }); + * // => { 'name': 'fred', 'employer': 'slate' } * * var defaults = _.partialRight(_.assign, function(a, b) { * return typeof a == 'undefined' ? b : a; * }); * - * var person = { 'name': 'barney' }; - * defaults(person, { 'name': 'fred', 'employer': 'slate' }); + * var object = { 'name': 'barney' }; + * defaults(object, { 'name': 'fred', 'employer': 'slate' }); * // => { 'name': 'barney', 'employer': 'slate' } */ var assign = function(object, source, guard) { @@ -1718,8 +1718,8 @@ * @returns {Object} Returns the destination object. * @example * - * var person = { 'name': 'barney' }; - * _.defaults(person, { 'name': 'fred', 'employer': 'slate' }); + * var object = { 'name': 'barney' }; + * _.defaults(object, { 'name': 'fred', 'employer': 'slate' }); * // => { 'name': 'barney', 'employer': 'slate' } */ var defaults = function(object, source, guard) { @@ -2179,13 +2179,13 @@ * @returns {boolean} Returns `true` if the values are equivalent, else `false`. * @example * - * var fred = { 'name': 'fred', 'age': 40 }; - * var copy = { 'name': 'fred', 'age': 40 }; + * var object = { 'name': 'fred' }; + * var copy = { 'name': 'fred' }; * - * fred == copy; + * object == copy; * // => false * - * _.isEqual(fred, copy); + * _.isEqual(object, copy); * // => true * * var words = ['hello', 'goodbye']; @@ -3074,6 +3074,10 @@ * (value, index|key, collection). Callbacks may exit iteration early by * explicitly returning `false`. * + * Note: As with other "Collections" methods, objects with a `length` property + * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn` + * may be used for object iteration. + * * @static * @memberOf _ * @alias each @@ -5003,11 +5007,11 @@ * // => 'hi fred' * * object.greet = function(greeting) { - * return greeting + ', ' + this.name + '!'; + * return greeting + 'ya ' + this.name + '!'; * }; * * func(); - * // => 'hi, fred!' + * // => 'hiya fred!' */ function bindKey(object, key) { return arguments.length > 2 @@ -5601,8 +5605,8 @@ * @returns {*} Returns `value`. * @example * - * var fred = { 'name': 'fred' }; - * fred === _.identity(fred); + * var object = { 'name': 'fred' }; + * object === _.identity(object); * // => true */ function identity(value) { diff --git a/dist/lodash.min.js b/dist/lodash.min.js index ca8f8395c..8f46ae211 100644 --- a/dist/lodash.min.js +++ b/dist/lodash.min.js @@ -11,35 +11,36 @@ if(!u)return o;var a=arguments,i=0,f=typeof e=="number"?2:a.length;if(3=b&&f===n,v=u||h?i():s;if(h){var g=o(v);g?(f=t,v=g):(h=!1,v=u?v:(c(v),s))}for(;++af(v,y))&&((u||h)&&v.push(y),s.push(g))}return h?(c(v.k),p(v)):u&&c(v),s}function ft(n){return function(t,e,r){var u={};e=Y.createCallback(e,r,3),r=-1;var o=t?t.length:0; -if(typeof o=="number")for(;++re?Re(0,o+e):e)||0,Pe(n)?a=-1o&&(o=i)}}else t=!t&&jt(n)?r:Y.createCallback(t,e,3),Nt(n,function(n,e,r){e=t(n,e,r),e>u&&(u=e,o=n)});return o}function At(n,t){var e=-1,r=n?n.length:0;if(typeof r=="number")for(var u=Xt(r);++earguments.length;t=et(t,r,4);var o=-1,a=n.length;if(typeof a=="number")for(u&&(e=n[++o]);++oarguments.length;return t=et(t,r,4),Et(n,function(n,r,o){e=u?(u=!1,n):t(e,n,r,o) -}),e}function $t(n){var t=-1,e=n?n.length:0,r=Xt(typeof e=="number"?e:0);return Nt(n,function(n){var e=at(0,++t);r[t]=r[e],r[e]=n}),r}function Ft(n,t,e){var r;t=Y.createCallback(t,e,3),e=-1;var u=n?n.length:0;if(typeof u=="number")for(;++e=b&&u===n;if(l){var c=o(i);c?(u=t,i=c):l=!1}for(;++ru(i,c)&&f.push(c);return l&&p(i),f}function Wt(n,t,e){var r=0,u=n?n.length:0; -if(typeof t!="number"&&null!=t){var o=-1;for(t=Y.createCallback(t,e,3);++or?Re(0,u+r):r||0}else if(r)return r=Pt(t,e),t[r]===e?r:-1;return n(t,e,r)}function zt(n,t,e){if(typeof t!="number"&&null!=t){var r=0,u=-1,o=n?n.length:0;for(t=Y.createCallback(t,e,3);++u>>1,e(n[r])e?0:e);++t/g,evaluate:/<%([\s\S]+?)%>/g,interpolate:N,variable:"",imports:{_:Y}},Oe||(ct=function(n){if(dt(n)){l.prototype=n; -var t=new l;l.prototype=null}return t||{}});var ze=xe?function(n,t){U.value=t,xe(n,"__bindData__",U)}:l,Pe=Ie||function(n){return n&&typeof n=="object"&&typeof n.length=="number"&&je.call(n)==$||!1},Ke=Se?function(n){return dt(n)?Se(n):[]}:Q,Le={"&":"&","<":"<",">":">",'"':""","'":"'"},Me=_t(Le),Ue=ue("("+Ke(Me).join("|")+")","g"),Ve=ue("["+Ke(Le).join("")+"]","g"),Ge=ft(function(n,t,e){ye.call(n,e)?n[e]++:n[e]=1}),He=ft(function(n,t,e){(ye.call(n,e)?n[e]:n[e]=[]).push(t)}),Je=ft(function(n,t,e){n[e]=t -});Te&&X&&typeof be=="function"&&(Gt=function(n){if(!bt(n))throw new ae;return be.apply(e,arguments)});var Qe=8==De(w+"08")?De:function(n,t){return De(jt(n)?n.replace(E,""):n,t||0)};return Y.after=function(n,t){if(!bt(t))throw new ae;return function(){return 1>--n?t.apply(this,arguments):void 0}},Y.assign=J,Y.at=function(n){for(var t=arguments,e=-1,r=rt(t,!0,!1,1),t=t[2]&&t[2][t[1]]===n?1:r.length,u=Xt(t);++e=b&&o(a?r[a]:g)}n:for(;++l(m?t(m,y):s(g,y))){for(a=u,(m||g).push(y);--a;)if(m=f[a],0>(m?t(m,y):s(r[a],y)))continue n;v.push(y)}}for(;u--;)(m=f[u])&&p(m);return c(f),c(g),v},Y.invert=_t,Y.invoke=function(n,t){var e=$e.call(arguments,2),r=-1,u=typeof t=="function",o=n?n.length:0,a=Xt(typeof o=="number"?o:0); -return Nt(n,function(n){a[++r]=(u?t:n[t]).apply(n,e)}),a},Y.keys=Ke,Y.map=St,Y.max=Rt,Y.memoize=function(n,t){function e(){var r=e.cache,u=t?t.apply(this,arguments):_+arguments[0];return ye.call(r,u)?r[u]:r[u]=n.apply(this,arguments)}if(!bt(n))throw new ae;return e.cache={},e},Y.merge=function(n){var t=arguments,e=2;if(!dt(n))return n;if("number"!=typeof t[2]&&(e=t.length),3r(a,e))&&(o[e]=n)}),o},Y.once=function(n){var t,e;if(!bt(n))throw new ae;return function(){return t?e:(t=!0,e=n.apply(this,arguments),n=null,e) -}},Y.pairs=function(n){for(var t=-1,e=Ke(n),r=e.length,u=Xt(r);++t=b&&f===n,v=u||h?i():s;if(h){var g=o(v);g?(f=t,v=g):(h=!1,v=u?v:(c(v),s))}for(;++af(v,y))&&((u||h)&&v.push(y),s.push(g)) +}return h?(c(v.k),p(v)):u&&c(v),s}function ft(n){return function(t,e,r){var u={};e=Y.createCallback(e,r,3),r=-1;var o=t?t.length:0;if(typeof o=="number")for(;++re?Re(0,o+e):e)||0,Pe(n)?a=-1o&&(o=i)}}else t=!t&&jt(n)?r:Y.createCallback(t,e,3),Nt(n,function(n,e,r){e=t(n,e,r),e>u&&(u=e,o=n)});return o}function At(n,t){var e=-1,r=n?n.length:0;if(typeof r=="number")for(var u=Xt(r);++earguments.length;t=et(t,r,4);var o=-1,a=n.length;if(typeof a=="number")for(u&&(e=n[++o]);++oarguments.length;return t=et(t,r,4),Et(n,function(n,r,o){e=u?(u=!1,n):t(e,n,r,o)}),e}function $t(n){var t=-1,e=n?n.length:0,r=Xt(typeof e=="number"?e:0);return Nt(n,function(n){var e=at(0,++t);r[t]=r[e],r[e]=n}),r}function Ft(n,t,e){var r;t=Y.createCallback(t,e,3),e=-1;var u=n?n.length:0;if(typeof u=="number")for(;++e=b&&u===n; +if(l){var c=o(i);c?(u=t,i=c):l=!1}for(;++ru(i,c)&&f.push(c);return l&&p(i),f}function Wt(n,t,e){var r=0,u=n?n.length:0;if(typeof t!="number"&&null!=t){var o=-1;for(t=Y.createCallback(t,e,3);++or?Re(0,u+r):r||0}else if(r)return r=Pt(t,e),t[r]===e?r:-1;return n(t,e,r)}function zt(n,t,e){if(typeof t!="number"&&null!=t){var r=0,u=-1,o=n?n.length:0; +for(t=Y.createCallback(t,e,3);++u>>1,e(n[r])e?0:e);++t/g,evaluate:/<%([\s\S]+?)%>/g,interpolate:N,variable:"",imports:{_:Y}},Oe||(ct=function(n){if(dt(n)){l.prototype=n;var t=new l;l.prototype=null}return t||{}});var ze=xe?function(n,t){U.value=t,xe(n,"__bindData__",U)}:l,Pe=Ie||function(n){return n&&typeof n=="object"&&typeof n.length=="number"&&je.call(n)==$||!1},Ke=Se?function(n){return dt(n)?Se(n):[] +}:Q,Le={"&":"&","<":"<",">":">",'"':""","'":"'"},Me=_t(Le),Ue=ue("("+Ke(Me).join("|")+")","g"),Ve=ue("["+Ke(Le).join("")+"]","g"),Ge=ft(function(n,t,e){ye.call(n,e)?n[e]++:n[e]=1}),He=ft(function(n,t,e){(ye.call(n,e)?n[e]:n[e]=[]).push(t)}),Je=ft(function(n,t,e){n[e]=t});Te&&X&&typeof be=="function"&&(Gt=function(n){if(!bt(n))throw new ae;return be.apply(e,arguments)});var Qe=8==De(w+"08")?De:function(n,t){return De(jt(n)?n.replace(E,""):n,t||0)};return Y.after=function(n,t){if(!bt(t))throw new ae; +return function(){return 1>--n?t.apply(this,arguments):void 0}},Y.assign=J,Y.at=function(n){for(var t=arguments,e=-1,r=rt(t,!0,!1,1),t=t[2]&&t[2][t[1]]===n?1:r.length,u=Xt(t);++e=b&&o(a?r[a]:g) +}n:for(;++l(m?t(m,y):s(g,y))){for(a=u,(m||g).push(y);--a;)if(m=f[a],0>(m?t(m,y):s(r[a],y)))continue n;v.push(y)}}for(;u--;)(m=f[u])&&p(m);return c(f),c(g),v},Y.invert=_t,Y.invoke=function(n,t){var e=$e.call(arguments,2),r=-1,u=typeof t=="function",o=n?n.length:0,a=Xt(typeof o=="number"?o:0);return Nt(n,function(n){a[++r]=(u?t:n[t]).apply(n,e)}),a},Y.keys=Ke,Y.map=St,Y.max=Rt,Y.memoize=function(n,t){function e(){var r=e.cache,u=t?t.apply(this,arguments):_+arguments[0];return ye.call(r,u)?r[u]:r[u]=n.apply(this,arguments) +}if(!bt(n))throw new ae;return e.cache={},e},Y.merge=function(n){var t=arguments,e=2;if(!dt(n))return n;if("number"!=typeof t[2]&&(e=t.length),3r(a,e))&&(o[e]=n)}),o},Y.once=function(n){var t,e;if(!bt(n))throw new ae;return function(){return t?e:(t=!0,e=n.apply(this,arguments),n=null,e)}},Y.pairs=function(n){for(var t=-1,e=Ke(n),r=e.length,u=Xt(r);++t { 'name': 'fred', 'age': 40 } + * _.assign({ 'name': 'fred' }, { 'employer': 'slate' }); + * // => { 'name': 'fred', 'employer': 'slate' } * * var defaults = _.partialRight(_.assign, function(a, b) { * return typeof a == 'undefined' ? b : a; * }); * - * var person = { 'name': 'barney' }; - * defaults(person, { 'name': 'fred', 'employer': 'slate' }); + * var object = { 'name': 'barney' }; + * defaults(object, { 'name': 'fred', 'employer': 'slate' }); * // => { 'name': 'barney', 'employer': 'slate' } */ function assign(object) { @@ -1010,8 +1010,8 @@ * @returns {Object} Returns the destination object. * @example * - * var person = { 'name': 'barney' }; - * _.defaults(person, { 'name': 'fred', 'employer': 'slate' }); + * var object = { 'name': 'barney' }; + * _.defaults(object, { 'name': 'fred', 'employer': 'slate' }); * // => { 'name': 'barney', 'employer': 'slate' } */ function defaults(object) { @@ -1277,13 +1277,13 @@ * @returns {boolean} Returns `true` if the values are equivalent, else `false`. * @example * - * var fred = { 'name': 'fred', 'age': 40 }; - * var copy = { 'name': 'fred', 'age': 40 }; + * var object = { 'name': 'fred' }; + * var copy = { 'name': 'fred' }; * - * fred == copy; + * object == copy; * // => false * - * _.isEqual(fred, copy); + * _.isEqual(object, copy); * // => true * * var words = ['hello', 'goodbye']; @@ -1947,6 +1947,10 @@ * (value, index|key, collection). Callbacks may exit iteration early by * explicitly returning `false`. * + * Note: As with other "Collections" methods, objects with a `length` property + * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn` + * may be used for object iteration. + * * @static * @memberOf _ * @alias each @@ -4107,8 +4111,8 @@ * @returns {*} Returns `value`. * @example * - * var fred = { 'name': 'fred' }; - * fred === _.identity(fred); + * var object = { 'name': 'fred' }; + * object === _.identity(object); * // => true */ function identity(value) { diff --git a/dist/lodash.underscore.min.js b/dist/lodash.underscore.min.js index b5c662ce5..e99c5d5db 100644 --- a/dist/lodash.underscore.min.js +++ b/dist/lodash.underscore.min.js @@ -5,9 +5,9 @@ */ ;(function(){function n(n,r,t){t=(t||0)-1;for(var e=n?n.length:0;++te||typeof t=="undefined")return 1;if(tu(f,l))&&(t&&f.push(l),i.push(a))}return i}function c(n){return function(r,t,e){var u={};t=K(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 c(n){return function(r,t,e){var u={};t=K(t,e,3),e=-1; +var o=r?r.length:0;if(typeof o=="number")for(;++e