Add _.isMap, _.isSet, _.isWeakMap, & _.isWeakSet.

This commit is contained in:
John-David Dalton
2016-02-06 16:19:48 -08:00
parent e00d9821a8
commit 6752d75ad0
2 changed files with 361 additions and 33 deletions

107
lodash.js
View File

@@ -81,7 +81,8 @@
setTag = '[object Set]', setTag = '[object Set]',
stringTag = '[object String]', stringTag = '[object String]',
symbolTag = '[object Symbol]', symbolTag = '[object Symbol]',
weakMapTag = '[object WeakMap]'; weakMapTag = '[object WeakMap]',
weakSetTag = '[object WeakSet]';
var arrayBufferTag = '[object ArrayBuffer]', var arrayBufferTag = '[object ArrayBuffer]',
float32Tag = '[object Float32Array]', float32Tag = '[object Float32Array]',
@@ -1339,9 +1340,10 @@
/** Used to store function metadata. */ /** Used to store function metadata. */
var metaMap = WeakMap && new WeakMap; var metaMap = WeakMap && new WeakMap;
/** Used to detect maps and sets. */ /** Used to detect maps, sets, and weakmaps. */
var mapCtorString = Map ? funcToString.call(Map) : '', var mapCtorString = Map ? funcToString.call(Map) : '',
setCtorString = Set ? funcToString.call(Set) : ''; setCtorString = Set ? funcToString.call(Set) : '',
weakMapCtorString = WeakMap ? funcToString.call(WeakMap) : '';
/** Used to convert symbols to primitives and strings. */ /** Used to convert symbols to primitives and strings. */
var symbolProto = Symbol ? Symbol.prototype : undefined, var symbolProto = Symbol ? Symbol.prototype : undefined,
@@ -4875,19 +4877,20 @@
return objectToString.call(value); return objectToString.call(value);
} }
// Fallback for IE 11 providing `toStringTag` values for maps and sets. // Fallback for IE 11 providing `toStringTag` values for maps, sets, and weakmaps.
if ((Map && getTag(new Map) != mapTag) || (Set && getTag(new Set) != setTag)) { if ((Map && getTag(new Map) != mapTag) ||
(Set && getTag(new Set) != setTag) ||
(WeakMap && getTag(new WeakMap) != weakMapTag)) {
getTag = function(value) { getTag = function(value) {
var result = objectToString.call(value), var result = objectToString.call(value),
Ctor = result == objectTag ? value.constructor : null, Ctor = result == objectTag ? value.constructor : null,
ctorString = typeof Ctor == 'function' ? funcToString.call(Ctor) : ''; ctorString = typeof Ctor == 'function' ? funcToString.call(Ctor) : '';
if (ctorString) { if (ctorString) {
if (ctorString == mapCtorString) { switch (ctorString) {
return mapTag; case mapCtorString: return mapTag;
} case setCtorString: return setTag;
if (ctorString == setCtorString) { case weakMapCtorString: return weakMapTag;
return setTag;
} }
} }
return result; return result;
@@ -9901,6 +9904,26 @@
return !!value && typeof value == 'object'; return !!value && typeof value == 'object';
} }
/**
* Checks if `value` is classified as a `Map` object.
*
* @static
* @memberOf _
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
* @example
*
* _.isMap(new Map);
* // => true
*
* _.isMap(new WeakMap);
* // => false
*/
function isMap(value) {
return isObjectLike(value) && getTag(value) == mapTag;
}
/** /**
* Performs a deep comparison between `object` and `source` to determine if * Performs a deep comparison between `object` and `source` to determine if
* `object` contains equivalent property values. * `object` contains equivalent property values.
@@ -10186,6 +10209,26 @@
return isInteger(value) && value >= -MAX_SAFE_INTEGER && value <= MAX_SAFE_INTEGER; return isInteger(value) && value >= -MAX_SAFE_INTEGER && value <= MAX_SAFE_INTEGER;
} }
/**
* Checks if `value` is classified as a `Set` object.
*
* @static
* @memberOf _
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
* @example
*
* _.isSet(new Set);
* // => true
*
* _.isSet(new WeakSet);
* // => false
*/
function isSet(value) {
return isObjectLike(value) && getTag(value) == setTag;
}
/** /**
* Checks if `value` is classified as a `String` primitive or object. * Checks if `value` is classified as a `String` primitive or object.
* *
@@ -10268,6 +10311,46 @@
return value === undefined; return value === undefined;
} }
/**
* Checks if `value` is classified as a `WeakMap` object.
*
* @static
* @memberOf _
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
* @example
*
* _.isWeakMap(new WeakMap);
* // => true
*
* _.isWeakMap(new Map);
* // => false
*/
function isWeakMap(value) {
return isObjectLike(value) && getTag(value) == weakMapTag;
}
/**
* Checks if `value` is classified as a `WeakSet` object.
*
* @static
* @memberOf _
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
* @example
*
* _.isWeakSet(new WeakSet);
* // => true
*
* _.isWeakSet(new Set);
* // => false
*/
function isWeakSet(value) {
return isObjectLike(value) && objectToString.call(value) == weakSetTag;
}
/** /**
* Checks if `value` is less than `other`. * Checks if `value` is less than `other`.
* *
@@ -14290,6 +14373,7 @@
lodash.isFunction = isFunction; lodash.isFunction = isFunction;
lodash.isInteger = isInteger; lodash.isInteger = isInteger;
lodash.isLength = isLength; lodash.isLength = isLength;
lodash.isMap = isMap;
lodash.isMatch = isMatch; lodash.isMatch = isMatch;
lodash.isMatchWith = isMatchWith; lodash.isMatchWith = isMatchWith;
lodash.isNaN = isNaN; lodash.isNaN = isNaN;
@@ -14302,10 +14386,13 @@
lodash.isPlainObject = isPlainObject; lodash.isPlainObject = isPlainObject;
lodash.isRegExp = isRegExp; lodash.isRegExp = isRegExp;
lodash.isSafeInteger = isSafeInteger; lodash.isSafeInteger = isSafeInteger;
lodash.isSet = isSet;
lodash.isString = isString; lodash.isString = isString;
lodash.isSymbol = isSymbol; lodash.isSymbol = isSymbol;
lodash.isTypedArray = isTypedArray; lodash.isTypedArray = isTypedArray;
lodash.isUndefined = isUndefined; lodash.isUndefined = isUndefined;
lodash.isWeakMap = isWeakMap;
lodash.isWeakSet = isWeakSet;
lodash.join = join; lodash.join = join;
lodash.kebabCase = kebabCase; lodash.kebabCase = kebabCase;
lodash.last = last; lodash.last = last;

View File

@@ -43,8 +43,6 @@
var phantom = root.phantom, var phantom = root.phantom,
amd = root.define && define.amd, amd = root.define && define.amd,
argv = root.process && process.argv, argv = root.process && process.argv,
ArrayBuffer = root.ArrayBuffer,
Buffer = root.Buffer,
defineProperty = Object.defineProperty, defineProperty = Object.defineProperty,
document = !phantom && root.document, document = !phantom && root.document,
body = root.document && root.document.body, body = root.document && root.document.body,
@@ -53,18 +51,28 @@
freeze = Object.freeze, freeze = Object.freeze,
identity = function(value) { return value; }, identity = function(value) { return value; },
JSON = root.JSON, JSON = root.JSON,
Map = root.Map,
noop = function() {}, noop = function() {},
objToString = objectProto.toString, objToString = objectProto.toString,
params = argv, params = argv,
push = arrayProto.push, push = arrayProto.push,
realm = {}, realm = {},
slice = arrayProto.slice;
var ArrayBuffer = root.ArrayBuffer,
Buffer = root.Buffer,
Map = root.Map,
Set = root.Set, Set = root.Set,
slice = arrayProto.slice,
Symbol = root.Symbol, Symbol = root.Symbol,
symbol = Symbol ? Symbol('a') : undefined,
Uint8Array = root.Uint8Array, Uint8Array = root.Uint8Array,
WeakMap = root.WeakMap; WeakMap = root.WeakMap,
WeakSet = root.WeakSet;
var arrayBuffer = ArrayBuffer ? new ArrayBuffer(2) : undefined,
map = Map ? new Map : undefined,
set = Set ? new Set : undefined,
symbol = Symbol ? Symbol('a') : undefined,
weakMap = WeakMap ? new WeakMap : undefined,
weakSet = WeakSet ? new WeakSet : undefined;
/** Math helpers. */ /** Math helpers. */
var add = function(x, y) { return x + y; }, var add = function(x, y) { return x + y; },
@@ -540,7 +548,9 @@
" 'set': root.Set ? new root.Set : undefined,", " 'set': root.Set ? new root.Set : undefined,",
" 'string': Object('a'),", " 'string': Object('a'),",
" 'symbol': root.Symbol ? root.Symbol() : undefined,", " 'symbol': root.Symbol ? root.Symbol() : undefined,",
" 'undefined': undefined", " 'undefined': undefined,",
" 'weakMap': root.WeakMap ? new root.WeakMap : undefined,",
" 'weakSet': root.WeakSet ? new root.WeakSet : undefined",
' };', ' };',
'', '',
" ['" + typedArrays.join("', '") + "'].forEach(function(type) {", " ['" + typedArrays.join("', '") + "'].forEach(function(type) {",
@@ -586,7 +596,9 @@
" 'set': root.Set ? new root.Set : undefined,", " 'set': root.Set ? new root.Set : undefined,",
" 'string': Object('a'),", " 'string': Object('a'),",
" 'symbol': root.Symbol ? root.Symbol() : undefined,", " 'symbol': root.Symbol ? root.Symbol() : undefined,",
" 'undefined': undefined", " 'undefined': undefined,",
" 'weakMap': root.WeakMap ? new root.WeakMap : undefined,",
" 'weakSet': root.WeakSet ? new root.WeakSet : undefined",
'};', '};',
'', '',
"_.each(['" + typedArrays.join("', '") + "'], function(type) {", "_.each(['" + typedArrays.join("', '") + "'], function(type) {",
@@ -2503,11 +2515,9 @@
assert.expect(2); assert.expect(2);
if (ArrayBuffer) { if (ArrayBuffer) {
var buffer = new ArrayBuffer(10), var actual = func(arrayBuffer);
actual = func(buffer); assert.strictEqual(actual.byteLength, arrayBuffer.byteLength);
assert.notStrictEqual(actual, arrayBuffer);
assert.strictEqual(actual.byteLength, buffer.byteLength);
assert.notStrictEqual(actual, buffer);
} }
else { else {
skipTest(assert, 2); skipTest(assert, 2);
@@ -7896,18 +7906,18 @@
(function() { (function() {
var args = arguments; var args = arguments;
QUnit.test('should return `true` for buffers', function(assert) { QUnit.test('should return `true` for array buffers', function(assert) {
assert.expect(1); assert.expect(1);
if (Buffer) { if (ArrayBuffer) {
assert.strictEqual(_.isArrayBuffer(new ArrayBuffer(2)), true); assert.strictEqual(_.isArrayBuffer(arrayBuffer), true);
} }
else { else {
skipTest(assert); skipTest(assert);
} }
}); });
QUnit.test('should return `false` for non buffers', function(assert) { QUnit.test('should return `false` for non array buffers', function(assert) {
assert.expect(13); assert.expect(13);
var expected = lodashStable.map(falsey, alwaysFalse); var expected = lodashStable.map(falsey, alwaysFalse);
@@ -9432,6 +9442,62 @@
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
QUnit.module('lodash.isMap');
(function() {
var args = arguments;
QUnit.test('should return `true` for maps', function(assert) {
assert.expect(1);
if (Map) {
assert.strictEqual(_.isMap(map), true);
}
else {
skipTest(assert);
}
});
QUnit.test('should return `false` for non maps', function(assert) {
assert.expect(14);
var expected = lodashStable.map(falsey, alwaysFalse);
var actual = lodashStable.map(falsey, function(value, index) {
return index ? _.isMap(value) : _.isMap();
});
assert.deepEqual(actual, expected);
assert.strictEqual(_.isMap(args), false);
assert.strictEqual(_.isMap([1, 2, 3]), false);
assert.strictEqual(_.isMap(true), false);
assert.strictEqual(_.isMap(new Date), false);
assert.strictEqual(_.isMap(new Error), false);
assert.strictEqual(_.isMap(_), false);
assert.strictEqual(_.isMap(slice), false);
assert.strictEqual(_.isMap({ 'a': 1 }), false);
assert.strictEqual(_.isMap(1), false);
assert.strictEqual(_.isMap(/x/), false);
assert.strictEqual(_.isMap('a'), false);
assert.strictEqual(_.isMap(symbol), false);
assert.strictEqual(_.isMap(weakMap), false);
});
QUnit.test('should work with maps from another realm', function(assert) {
assert.expect(1);
if (realm.map) {
assert.strictEqual(_.isMap(realm.map), true);
}
else {
skipTest(assert);
}
});
}(1, 2, 3));
/*--------------------------------------------------------------------------*/
QUnit.module('lodash.isMatch'); QUnit.module('lodash.isMatch');
(function() { (function() {
@@ -10480,6 +10546,62 @@
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
QUnit.module('lodash.isSet');
(function() {
var args = arguments;
QUnit.test('should return `true` for sets', function(assert) {
assert.expect(1);
if (Set) {
assert.strictEqual(_.isSet(set), true);
}
else {
skipTest(assert);
}
});
QUnit.test('should return `false` for non sets', function(assert) {
assert.expect(14);
var expected = lodashStable.map(falsey, alwaysFalse);
var actual = lodashStable.map(falsey, function(value, index) {
return index ? _.isSet(value) : _.isSet();
});
assert.deepEqual(actual, expected);
assert.strictEqual(_.isSet(args), false);
assert.strictEqual(_.isSet([1, 2, 3]), false);
assert.strictEqual(_.isSet(true), false);
assert.strictEqual(_.isSet(new Date), false);
assert.strictEqual(_.isSet(new Error), false);
assert.strictEqual(_.isSet(_), false);
assert.strictEqual(_.isSet(slice), false);
assert.strictEqual(_.isSet({ 'a': 1 }), false);
assert.strictEqual(_.isSet(1), false);
assert.strictEqual(_.isSet(/x/), false);
assert.strictEqual(_.isSet('a'), false);
assert.strictEqual(_.isSet(symbol), false);
assert.strictEqual(_.isSet(weakSet), false);
});
QUnit.test('should work with weak sets from another realm', function(assert) {
assert.expect(1);
if (realm.set) {
assert.strictEqual(_.isSet(realm.set), true);
}
else {
skipTest(assert);
}
});
}(1, 2, 3));
/*--------------------------------------------------------------------------*/
QUnit.module('lodash.isString'); QUnit.module('lodash.isString');
(function() { (function() {
@@ -10717,6 +10839,118 @@
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
QUnit.module('lodash.isWeakMap');
(function() {
var args = arguments;
QUnit.test('should return `true` for weak maps', function(assert) {
assert.expect(1);
if (WeakMap) {
assert.strictEqual(_.isWeakMap(weakMap), true);
}
else {
skipTest(assert);
}
});
QUnit.test('should return `false` for non weak maps', function(assert) {
assert.expect(14);
var expected = lodashStable.map(falsey, alwaysFalse);
var actual = lodashStable.map(falsey, function(value, index) {
return index ? _.isWeakMap(value) : _.isWeakMap();
});
assert.deepEqual(actual, expected);
assert.strictEqual(_.isWeakMap(args), false);
assert.strictEqual(_.isWeakMap([1, 2, 3]), false);
assert.strictEqual(_.isWeakMap(true), false);
assert.strictEqual(_.isWeakMap(new Date), false);
assert.strictEqual(_.isWeakMap(new Error), false);
assert.strictEqual(_.isWeakMap(_), false);
assert.strictEqual(_.isWeakMap(slice), false);
assert.strictEqual(_.isWeakMap({ 'a': 1 }), false);
assert.strictEqual(_.isWeakMap(map), false);
assert.strictEqual(_.isWeakMap(1), false);
assert.strictEqual(_.isWeakMap(/x/), false);
assert.strictEqual(_.isWeakMap('a'), false);
assert.strictEqual(_.isWeakMap(symbol), false);
});
QUnit.test('should work with weak maps from another realm', function(assert) {
assert.expect(1);
if (realm.weakMap) {
assert.strictEqual(_.isWeakMap(realm.weakMap), true);
}
else {
skipTest(assert);
}
});
}(1, 2, 3));
/*--------------------------------------------------------------------------*/
QUnit.module('lodash.isWeakSet');
(function() {
var args = arguments;
QUnit.test('should return `true` for weak sets', function(assert) {
assert.expect(1);
if (WeakSet) {
assert.strictEqual(_.isWeakSet(weakSet), true);
}
else {
skipTest(assert);
}
});
QUnit.test('should return `false` for non weak sets', function(assert) {
assert.expect(14);
var expected = lodashStable.map(falsey, alwaysFalse);
var actual = lodashStable.map(falsey, function(value, index) {
return index ? _.isWeakSet(value) : _.isWeakSet();
});
assert.deepEqual(actual, expected);
assert.strictEqual(_.isWeakSet(args), false);
assert.strictEqual(_.isWeakSet([1, 2, 3]), false);
assert.strictEqual(_.isWeakSet(true), false);
assert.strictEqual(_.isWeakSet(new Date), false);
assert.strictEqual(_.isWeakSet(new Error), false);
assert.strictEqual(_.isWeakSet(_), false);
assert.strictEqual(_.isWeakSet(slice), false);
assert.strictEqual(_.isWeakSet({ 'a': 1 }), false);
assert.strictEqual(_.isWeakSet(1), false);
assert.strictEqual(_.isWeakSet(/x/), false);
assert.strictEqual(_.isWeakSet('a'), false);
assert.strictEqual(_.isWeakSet(set), false);
assert.strictEqual(_.isWeakSet(symbol), false);
});
QUnit.test('should work with weak sets from another realm', function(assert) {
assert.expect(1);
if (realm.weakSet) {
assert.strictEqual(_.isWeakSet(realm.weakSet), true);
}
else {
skipTest(assert);
}
});
}(1, 2, 3));
/*--------------------------------------------------------------------------*/
QUnit.module('isType checks'); QUnit.module('isType checks');
(function() { (function() {
@@ -10742,13 +10976,14 @@
}); });
QUnit.test('should not error on host objects (test in IE)', function(assert) { QUnit.test('should not error on host objects (test in IE)', function(assert) {
assert.expect(20); assert.expect(26);
var funcs = [ var funcs = [
'isArguments', 'isArray', 'isArrayLike', 'isBoolean', 'isDate', 'isArguments', 'isArray', 'isArrayBuffer', 'isArrayLike', 'isBoolean',
'isElement', 'isError', 'isFinite', 'isFunction', 'isInteger', 'isNaN', 'isBuffer', 'isDate', 'isElement', 'isError', 'isFinite', 'isFunction',
'isNil', 'isNull', 'isNumber', 'isObject', 'isObjectLike', 'isRegExp', 'isInteger', 'isMap', 'isNaN', 'isNil', 'isNull', 'isNumber', 'isObject',
'isSafeInteger', 'isString', 'isUndefined' 'isObjectLike', 'isRegExp', 'isSet', 'isSafeInteger', 'isString',
'isUndefined', 'isWeakMap', 'isWeakSet'
]; ];
lodashStable.each(funcs, function(methodName) { lodashStable.each(funcs, function(methodName) {
@@ -23410,8 +23645,10 @@
'includes', 'includes',
'isArguments', 'isArguments',
'isArray', 'isArray',
'isArrayBuffer',
'isArrayLike', 'isArrayLike',
'isBoolean', 'isBoolean',
'isBuffer',
'isDate', 'isDate',
'isElement', 'isElement',
'isEmpty', 'isEmpty',
@@ -23420,6 +23657,7 @@
'isFinite', 'isFinite',
'isFunction', 'isFunction',
'isInteger', 'isInteger',
'isMap',
'isNaN', 'isNaN',
'isNative', 'isNative',
'isNil', 'isNil',
@@ -23430,8 +23668,11 @@
'isPlainObject', 'isPlainObject',
'isRegExp', 'isRegExp',
'isSafeInteger', 'isSafeInteger',
'isSet',
'isString', 'isString',
'isUndefined', 'isUndefined',
'isWeakMap',
'isWeakSet',
'join', 'join',
'kebabCase', 'kebabCase',
'last', 'last',
@@ -23721,7 +23962,7 @@
var acceptFalsey = lodashStable.difference(allMethods, rejectFalsey); var acceptFalsey = lodashStable.difference(allMethods, rejectFalsey);
QUnit.test('should accept falsey arguments', function(assert) { QUnit.test('should accept falsey arguments', function(assert) {
assert.expect(291); assert.expect(295);
var emptyArrays = lodashStable.map(falsey, alwaysEmptyArray); var emptyArrays = lodashStable.map(falsey, alwaysEmptyArray);