diff --git a/lodash.js b/lodash.js index c3ab49e2a..3dc6b18fc 100644 --- a/lodash.js +++ b/lodash.js @@ -121,7 +121,8 @@ 'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Math', 'Number', 'Object', 'RegExp', 'Set', 'String', '_', 'clearTimeout', 'document', 'isFinite', 'parseInt', 'setTimeout', 'TypeError', 'Uint8Array', - 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'window', 'WinRTError' + 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap', + 'window', 'WinRTError' ]; /** Used to fix the JScript `[[DontEnum]]` bug */ @@ -693,7 +694,8 @@ setTimeout = context.setTimeout, splice = arrayProto.splice, Uint8Array = isNative(Uint8Array = context.Uint8Array) && Uint8Array, - unshift = arrayProto.unshift; + unshift = arrayProto.unshift, + WeakMap = isNative(WeakMap = context.WeakMap) && WeakMap; /** Used to clone array buffers */ var Float64Array = (function() { @@ -733,6 +735,9 @@ /** Used as the size, in bytes, of each Float64Array element */ var FLOAT64_BYTES_PER_ELEMENT = Float64Array ? Float64Array.BYTES_PER_ELEMENT : 0; + /** Used to store function metadata */ + var metaMap = WeakMap && new WeakMap; + /** Used to lookup a built-in constructor by [[Class]] */ var ctorByClass = {}; ctorByClass[float32Class] = context.Float32Array; @@ -1360,7 +1365,7 @@ if (typeof thisArg == 'undefined') { return func; } - var data = func[EXPANDO]; + var data = getData(func); if (typeof data == 'undefined') { if (support.funcNames) { data = !func.name; @@ -2130,7 +2135,7 @@ */ function basePartial(func, bitmask, args, holders, thisArg) { if (func) { - var data = func[EXPANDO], + var data = getData(func), arity = data ? data[2] : func.length; arity -= args.length; @@ -2718,7 +2723,7 @@ isPartialRight = false; partialRightArgs = partialRightHolders = null; } - var data = !isBindKey && func[EXPANDO]; + var data = !isBindKey && getData(func); if (data && data !== true) { var funcBitmask = data[1], funcIsBind = funcBitmask & BIND_FLAG, @@ -2783,6 +2788,23 @@ return argCount ? result(func, thisArg, argCount) : result; } + /** + * Gets metadata for `func`. + * + * @private + * @param {Function} func The function to query. + * @returns {*} Returns the metadata for `func`. + */ + function getData(func) { + return metaMap.get(func); + } + // fallback for environments without `WeakMap` + if (!WeakMap) { + getData = !defineProperty ? noop : function(func) { + return func[EXPANDO]; + }; + } + /** * Gets the appropriate "indexOf" function. If the `_.indexOf` method is * customized this function returns the custom method, otherwise it returns @@ -2986,19 +3008,26 @@ } /** - * Sets wrapper metadata on a given function. + * Sets metadata for `func`. * * @private - * @param {Function} func The function to set data on. - * @param {Array} value The data array to set. + * @param {Function} func The function to associate metadata with. + * @param {*} data The metadata. * @returns {Function} Returns `func`. */ - var setData = !defineProperty ? identity : function(func, value) { - descriptor.value = value; - defineProperty(func, EXPANDO, descriptor); - descriptor.value = null; + function setData(func, data) { + metaMap.set(func, data); return func; - }; + } + // fallback for environments without `WeakMap` + if (!WeakMap) { + setData = !defineProperty ? identity : function(func, value) { + descriptor.value = value; + defineProperty(func, EXPANDO, descriptor); + descriptor.value = null; + return func; + }; + } /** * A fallback implementation of `_.isPlainObject` which checks if `value` diff --git a/test/index.html b/test/index.html index a65a4fe9b..9efa47dc2 100644 --- a/test/index.html +++ b/test/index.html @@ -54,7 +54,7 @@ var hasOwnProperty = objectProto.hasOwnProperty, fnToString = funcProto.toString, nativeString = fnToString.call(objectProto.toString), - noop = function() {}, + noop = function() { }, propertyIsEnumerable = objectProto.propertyIsEnumerable, reToString = /toString/g, whitespace = ' \t\x0B\f\xA0\ufeff\n\r\u2028\u2029\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000'; @@ -154,6 +154,9 @@ return Float64Array; }()); } + setProperty(window, '_WeakMap', window.WeakMap); + setProperty(window, 'WeakMap', noop); + setProperty(window, '_parseInt', parseInt); setProperty(window, 'parseInt', (function(_parseInt) { var checkStr = whitespace + '08', @@ -235,6 +238,11 @@ } setProperty(window, '_ArrayBuffer', undefined); + if (window._WeakMap) { + WeakMap = _WeakMap; + } + setProperty(window, '_WeakMap', undefined); + setProperty(window, 'parseInt', window._parseInt); setProperty(window, '_parseInt', undefined); diff --git a/test/test.js b/test/test.js index cc8fc9022..3becd5f6c 100644 --- a/test/test.js +++ b/test/test.js @@ -38,7 +38,8 @@ slice = arrayProto.slice, system = root.system, toString = objectProto.toString, - Uint8Array = root.Uint8Array; + Uint8Array = root.Uint8Array, + WeakMap = root.WeakMap; /** The file path of the Lo-Dash file to test */ var filePath = (function() { @@ -2179,7 +2180,7 @@ var object = {}; - if (defineProperty && _.support.funcDecomp) { + if ((defineProperty && !WeakMap) && _.support.funcDecomp) { _.callback(a, object); ok(EXPANDO in a); @@ -2205,7 +2206,7 @@ test('should not write metadata when `_.support.funcDecomp` is `false`', 1, function() { function a() {}; - if (defineProperty && lodashBizarro) { + if ((defineProperty && !WeakMap) && lodashBizarro) { lodashBizarro.callback(a, {}); ok(!(EXPANDO in a)); }