Use WeakMaps if available to store function metadata.

This commit is contained in:
John-David Dalton
2014-08-14 09:37:15 -07:00
parent c139a0d9ed
commit d6850ab358
3 changed files with 55 additions and 17 deletions

View File

@@ -121,7 +121,8 @@
'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Math', 'Number', 'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Math', 'Number',
'Object', 'RegExp', 'Set', 'String', '_', 'clearTimeout', 'document', 'Object', 'RegExp', 'Set', 'String', '_', 'clearTimeout', 'document',
'isFinite', 'parseInt', 'setTimeout', 'TypeError', 'Uint8Array', 'isFinite', 'parseInt', 'setTimeout', 'TypeError', 'Uint8Array',
'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'window', 'WinRTError' 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap',
'window', 'WinRTError'
]; ];
/** Used to fix the JScript `[[DontEnum]]` bug */ /** Used to fix the JScript `[[DontEnum]]` bug */
@@ -693,7 +694,8 @@
setTimeout = context.setTimeout, setTimeout = context.setTimeout,
splice = arrayProto.splice, splice = arrayProto.splice,
Uint8Array = isNative(Uint8Array = context.Uint8Array) && Uint8Array, Uint8Array = isNative(Uint8Array = context.Uint8Array) && Uint8Array,
unshift = arrayProto.unshift; unshift = arrayProto.unshift,
WeakMap = isNative(WeakMap = context.WeakMap) && WeakMap;
/** Used to clone array buffers */ /** Used to clone array buffers */
var Float64Array = (function() { var Float64Array = (function() {
@@ -733,6 +735,9 @@
/** Used as the size, in bytes, of each Float64Array element */ /** Used as the size, in bytes, of each Float64Array element */
var FLOAT64_BYTES_PER_ELEMENT = Float64Array ? Float64Array.BYTES_PER_ELEMENT : 0; 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]] */ /** Used to lookup a built-in constructor by [[Class]] */
var ctorByClass = {}; var ctorByClass = {};
ctorByClass[float32Class] = context.Float32Array; ctorByClass[float32Class] = context.Float32Array;
@@ -1360,7 +1365,7 @@
if (typeof thisArg == 'undefined') { if (typeof thisArg == 'undefined') {
return func; return func;
} }
var data = func[EXPANDO]; var data = getData(func);
if (typeof data == 'undefined') { if (typeof data == 'undefined') {
if (support.funcNames) { if (support.funcNames) {
data = !func.name; data = !func.name;
@@ -2130,7 +2135,7 @@
*/ */
function basePartial(func, bitmask, args, holders, thisArg) { function basePartial(func, bitmask, args, holders, thisArg) {
if (func) { if (func) {
var data = func[EXPANDO], var data = getData(func),
arity = data ? data[2] : func.length; arity = data ? data[2] : func.length;
arity -= args.length; arity -= args.length;
@@ -2718,7 +2723,7 @@
isPartialRight = false; isPartialRight = false;
partialRightArgs = partialRightHolders = null; partialRightArgs = partialRightHolders = null;
} }
var data = !isBindKey && func[EXPANDO]; var data = !isBindKey && getData(func);
if (data && data !== true) { if (data && data !== true) {
var funcBitmask = data[1], var funcBitmask = data[1],
funcIsBind = funcBitmask & BIND_FLAG, funcIsBind = funcBitmask & BIND_FLAG,
@@ -2783,6 +2788,23 @@
return argCount ? result(func, thisArg, argCount) : result; 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 * Gets the appropriate "indexOf" function. If the `_.indexOf` method is
* customized this function returns the custom method, otherwise it returns * 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 * @private
* @param {Function} func The function to set data on. * @param {Function} func The function to associate metadata with.
* @param {Array} value The data array to set. * @param {*} data The metadata.
* @returns {Function} Returns `func`. * @returns {Function} Returns `func`.
*/ */
var setData = !defineProperty ? identity : function(func, value) { function setData(func, data) {
descriptor.value = value; metaMap.set(func, data);
defineProperty(func, EXPANDO, descriptor);
descriptor.value = null;
return func; 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` * A fallback implementation of `_.isPlainObject` which checks if `value`

View File

@@ -54,7 +54,7 @@
var hasOwnProperty = objectProto.hasOwnProperty, var hasOwnProperty = objectProto.hasOwnProperty,
fnToString = funcProto.toString, fnToString = funcProto.toString,
nativeString = fnToString.call(objectProto.toString), nativeString = fnToString.call(objectProto.toString),
noop = function() {}, noop = function() { },
propertyIsEnumerable = objectProto.propertyIsEnumerable, propertyIsEnumerable = objectProto.propertyIsEnumerable,
reToString = /toString/g, 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'; 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; return Float64Array;
}()); }());
} }
setProperty(window, '_WeakMap', window.WeakMap);
setProperty(window, 'WeakMap', noop);
setProperty(window, '_parseInt', parseInt); setProperty(window, '_parseInt', parseInt);
setProperty(window, 'parseInt', (function(_parseInt) { setProperty(window, 'parseInt', (function(_parseInt) {
var checkStr = whitespace + '08', var checkStr = whitespace + '08',
@@ -235,6 +238,11 @@
} }
setProperty(window, '_ArrayBuffer', undefined); setProperty(window, '_ArrayBuffer', undefined);
if (window._WeakMap) {
WeakMap = _WeakMap;
}
setProperty(window, '_WeakMap', undefined);
setProperty(window, 'parseInt', window._parseInt); setProperty(window, 'parseInt', window._parseInt);
setProperty(window, '_parseInt', undefined); setProperty(window, '_parseInt', undefined);

View File

@@ -38,7 +38,8 @@
slice = arrayProto.slice, slice = arrayProto.slice,
system = root.system, system = root.system,
toString = objectProto.toString, toString = objectProto.toString,
Uint8Array = root.Uint8Array; Uint8Array = root.Uint8Array,
WeakMap = root.WeakMap;
/** The file path of the Lo-Dash file to test */ /** The file path of the Lo-Dash file to test */
var filePath = (function() { var filePath = (function() {
@@ -2179,7 +2180,7 @@
var object = {}; var object = {};
if (defineProperty && _.support.funcDecomp) { if ((defineProperty && !WeakMap) && _.support.funcDecomp) {
_.callback(a, object); _.callback(a, object);
ok(EXPANDO in a); ok(EXPANDO in a);
@@ -2205,7 +2206,7 @@
test('should not write metadata when `_.support.funcDecomp` is `false`', 1, function() { test('should not write metadata when `_.support.funcDecomp` is `false`', 1, function() {
function a() {}; function a() {};
if (defineProperty && lodashBizarro) { if ((defineProperty && !WeakMap) && lodashBizarro) {
lodashBizarro.callback(a, {}); lodashBizarro.callback(a, {});
ok(!(EXPANDO in a)); ok(!(EXPANDO in a));
} }