Skip to content

Commit

Permalink
perf: do not lowercase returned values
Browse files Browse the repository at this point in the history
We're sacrificing a lot of performance just to lowercase the string
values, which is not ideal as it's not always necessary. Here are
some numbers demonstrating the difference in performance:

With `.toLowerCase()`:
```
string literal     x 31,742,089 ops/sec ±6.85% (70 runs sampled)
array literal      x 12,508,545 ops/sec ±3.86% (67 runs sampled)
boolean literal    x 33,502,011 ops/sec ±3.58% (66 runs sampled)
object literal     x 1,178,855 ops/sec ±2.06% (79 runs sampled)
object from null   x 3,356,249 ops/sec ±2.03% (81 runs sampled)
regex literal      x 2,738,477 ops/sec ±1.95% (80 runs sampled)
number literal     x 30,119,855 ops/sec ±2.04% (78 runs sampled)
promise            x 7,260,140 ops/sec ±1.79% (81 runs sampled)
null               x 34,793,675 ops/sec ±1.58% (84 runs sampled)
undefined          x 31,537,228 ops/sec ±1.77% (81 runs sampled)
function           x 35,571,426 ops/sec ±1.69% (82 runs sampled)
buffer             x 5,468,033 ops/sec ±2.19% (83 runs sampled)
date               x 4,402,505 ops/sec ±1.47% (83 runs sampled)
error              x 932,833 ops/sec ±2.16% (80 runs sampled)
map                x 7,298,659 ops/sec ±1.64% (81 runs sampled)
regex constructor  x 3,042,918 ops/sec ±2.28% (80 runs sampled)
set                x 6,075,985 ops/sec ±1.91% (82 runs sampled)
string constructor x 1,077,682 ops/sec ±2.32% (82 runs sampled)
weakmap            x 5,949,120 ops/sec ±1.99% (83 runs sampled)
weakset            x 5,574,794 ops/sec ±1.89% (78 runs sampled)
arguments          x 1,065,249 ops/sec ±1.37% (83 runs sampled)
arrow function     x 28,776,605 ops/sec ±1.61% (81 runs sampled)
generator function x 34,581,601 ops/sec ±2.11% (79 runs sampled)
Float64Array       x 5,306,129 ops/sec ±1.64% (83 runs sampled)
Float32Array       x 5,635,134 ops/sec ±1.37% (84 runs sampled)
Uint32Array        x 5,584,889 ops/sec ±1.72% (83 runs sampled)
Uint16Array        x 5,024,561 ops/sec ±1.40% (85 runs sampled)
Uint8Array         x 5,032,024 ops/sec ±1.93% (81 runs sampled)
Int32Array         x 6,261,825 ops/sec ±2.21% (78 runs sampled)
Int16Array         x 6,380,182 ops/sec ±1.68% (81 runs sampled)
Int8Array          x 6,156,981 ops/sec ±2.27% (78 runs sampled)
Uint8ClampedArray  x 5,911,482 ops/sec ±1.85% (80 runs sampled)
DataView           x 7,308,534 ops/sec ±1.83% (78 runs sampled)
```

Without `.toLowerCase()`:
```
string literal     x 47,522,814 ops/sec ±1.93% (80 runs sampled)
array literal      x 18,729,054 ops/sec ±1.88% (81 runs sampled)
boolean literal    x 33,037,749 ops/sec ±2.17% (83 runs sampled)
object literal     x 1,536,749 ops/sec ±2.99% (80 runs sampled)
object from null   x 3,148,007 ops/sec ±2.39% (83 runs sampled)
regex literal      x 3,373,384 ops/sec ±1.82% (82 runs sampled)
number literal     x 33,096,650 ops/sec ±1.43% (85 runs sampled)
promise            x 13,416,347 ops/sec ±1.62% (80 runs sampled)
null               x 32,376,000 ops/sec ±1.70% (82 runs sampled)
undefined          x 30,734,992 ops/sec ±1.60% (82 runs sampled)
function           x 35,044,726 ops/sec ±1.87% (81 runs sampled)
buffer             x 10,831,858 ops/sec ±1.93% (82 runs sampled)
date               x 4,511,245 ops/sec ±1.99% (81 runs sampled)
error              x 836,481 ops/sec ±2.31% (79 runs sampled)
map                x 14,289,403 ops/sec ±1.72% (83 runs sampled)
regex constructor  x 3,764,635 ops/sec ±2.69% (78 runs sampled)
set                x 12,494,254 ops/sec ±1.95% (82 runs sampled)
string constructor x 1,282,794 ops/sec ±1.92% (80 runs sampled)
weakmap            x 15,418,935 ops/sec ±1.84% (79 runs sampled)
weakset            x 14,768,545 ops/sec ±1.60% (82 runs sampled)
arguments          x 993,064 ops/sec ±1.88% (81 runs sampled)
arrow function     x 30,511,620 ops/sec ±2.07% (79 runs sampled)
generator function x 35,487,241 ops/sec ±1.53% (81 runs sampled)
Float64Array       x 9,666,668 ops/sec ±1.75% (79 runs sampled)
Float32Array       x 9,286,265 ops/sec ±1.66% (81 runs sampled)
Uint32Array        x 9,352,490 ops/sec ±1.37% (82 runs sampled)
Uint16Array        x 8,404,961 ops/sec ±2.03% (80 runs sampled)
Uint8Array         x 8,635,152 ops/sec ±1.81% (80 runs sampled)
Int32Array         x 10,569,543 ops/sec ±1.67% (82 runs sampled)
Int16Array         x 9,444,358 ops/sec ±1.53% (80 runs sampled)
Int8Array          x 7,235,174 ops/sec ±2.43% (76 runs sampled)
Uint8ClampedArray  x 8,055,645 ops/sec ±1.67% (82 runs sampled)
DataView           x 15,014,475 ops/sec ±2.08% (79 runs sampled)
```

BREAKING CHANGE:

All strings will no longer be lowercase. If you want them in lowercase,
simply add `.toLowerCase()` to the return value.
  • Loading branch information
keithamus committed Oct 8, 2016
1 parent 97e785b commit 48c8108
Show file tree
Hide file tree
Showing 5 changed files with 217 additions and 209 deletions.
56 changes: 28 additions & 28 deletions README.md
Expand Up @@ -104,15 +104,15 @@ var type = require('type-detect');
#### array

```js
assert(type([]) === 'array');
assert(type(new Array()) === 'array');
assert(type([]) === 'Array');
assert(type(new Array()) === 'Array');
```

#### regexp

```js
assert(type(/a-z/gi) === 'regexp');
assert(type(new RegExp('a-z')) === 'regexp');
assert(type(/a-z/gi) === 'RegExp');
assert(type(new RegExp('a-z')) === 'RegExp');
```

#### function
Expand All @@ -132,7 +132,7 @@ assert(type(function () {}) === 'function');
#### date

```js
assert(type(new Date) === 'date');
assert(type(new Date) === 'Date');
```

#### number
Expand All @@ -144,14 +144,14 @@ assert(type(-1) === 'number');
assert(type(-1.234) === 'number');
assert(type(Infinity) === 'number');
assert(type(NaN) === 'number');
assert(type(new Number(1)) === 'number');
assert(type(new Number(1)) === 'Number'); // note - the object version has a capital N
```

#### string

```js
assert(type('hello world') === 'string');
assert(type(new String('hello')) === 'string');
assert(type(new String('hello')) === 'String'); // note - the object version has a capital S
```

#### null
Expand All @@ -172,34 +172,34 @@ assert(type(null) !== 'undefined');

```js
var Noop = function () {};
assert(type({}) === 'object');
assert(type(Noop) !== 'object');
assert(type(new Noop) === 'object');
assert(type(new Object) === 'object');
assert(type({}) === 'Object');
assert(type(Noop) !== 'Object');
assert(type(new Noop) === 'Object');
assert(type(new Object) === 'Object');
```

#### ECMA6 Types

All new ECMAScript 2015 objects are also supported, such as Promises and Symbols:

```js
assert(type(new Map() === 'map');
assert(type(new WeakMap()) === 'weakmap');
assert(type(new Set()) === 'set');
assert(type(new WeakSet()) === 'weakset');
assert(type(Symbol()) === 'symbol');
assert(type(new Promise(callback) === 'promise');
assert(type(new Int8Array()) === 'int8array');
assert(type(new Uint8Array()) === 'uint8array');
assert(type(new UInt8ClampedArray()) === 'uint8clampedarray');
assert(type(new Int16Array()) === 'int16array');
assert(type(new Uint16Array()) === 'uint16array');
assert(type(new Int32Array()) === 'int32array');
assert(type(new UInt32Array()) === 'uint32array');
assert(type(new Float32Array()) === 'float32array');
assert(type(new Float64Array()) === 'float64array');
assert(type(new ArrayBuffer()) === 'arraybuffer');
assert(type(new DataView(arrayBuffer)) === 'dataview');
assert(type(new Map() === 'Map');
assert(type(new WeakMap()) === 'WeakMap');
assert(type(new Set()) === 'Set');
assert(type(new WeakSet()) === 'WeakSet');
assert(type(Symbol()) === 'Symbol');
assert(type(new Promise(callback) === 'Promise');
assert(type(new Int8Array()) === 'Int8Array');
assert(type(new Uint8Array()) === 'Uint8Array');
assert(type(new UInt8ClampedArray()) === 'Uint8ClampedArray');
assert(type(new Int16Array()) === 'Int16Array');
assert(type(new Uint16Array()) === 'Uint16Array');
assert(type(new Int32Array()) === 'Int32Array');
assert(type(new UInt32Array()) === 'Uint32Array');
assert(type(new Float32Array()) === 'Float32Array');
assert(type(new Float64Array()) === 'Float64Array');
assert(type(new ArrayBuffer()) === 'ArrayBuffer');
assert(type(new DataView(arrayBuffer)) === 'DataView');
```
Also, if you use `Symbol.toStringTag` to change an Objects return value of the `toString()` Method, `type()` will return this value, e.g:
Expand Down
47 changes: 23 additions & 24 deletions index.js
Expand Up @@ -95,7 +95,7 @@ module.exports = function typeDetect(obj) {
* array literal x 22,479,650 ops/sec ±0.96% (81 runs sampled)
*/
if (isArrayExists && Array.isArray(obj)) {
return 'array';
return 'Array';
}

if (isDom) {
Expand All @@ -107,7 +107,7 @@ module.exports = function typeDetect(obj) {
* - IE Edge <=13 === "[object Object]"
*/
if (obj === globalObject.location) {
return 'location';
return 'Location';
}

/* ! Spec Conformance
Expand All @@ -130,7 +130,7 @@ module.exports = function typeDetect(obj) {
* - IE Edge <=13 === "[object HTMLDocument]"
*/
if (obj === globalObject.document) {
return 'document';
return 'Document';
}

/* ! Spec Conformance
Expand All @@ -140,7 +140,7 @@ module.exports = function typeDetect(obj) {
* - IE <=10 === "[object MSMimeTypesCollection]"
*/
if (obj === (globalObject.navigator || {}).mimeTypes) {
return 'mimetypearray';
return 'MimeTypeArray';
}

/* ! Spec Conformance
Expand All @@ -150,7 +150,7 @@ module.exports = function typeDetect(obj) {
* - IE <=10 === "[object MSPluginsCollection]"
*/
if (obj === (globalObject.navigator || {}).plugins) {
return 'pluginarray';
return 'PluginArray';
}

/* ! Spec Conformance
Expand All @@ -160,7 +160,7 @@ module.exports = function typeDetect(obj) {
* - IE <=10 === "[object HTMLBlockElement]"
*/
if (htmlElementExists && obj instanceof HTMLElement && obj.tagName === 'BLOCKQUOTE') {
return 'htmlquoteelement';
return 'HTMLQuoteElement';
}

/* ! Spec Conformance
Expand All @@ -176,7 +176,7 @@ module.exports = function typeDetect(obj) {
* - Safari === "[object HTMLTableCellElement]"
*/
if (htmlElementExists && obj instanceof HTMLElement && obj.tagName === 'TD') {
return 'htmltabledatacellelement';
return 'HTMLTableDataCellElement';
}

/* ! Spec Conformance
Expand All @@ -192,7 +192,7 @@ module.exports = function typeDetect(obj) {
* - Safari === "[object HTMLTableCellElement]"
*/
if (htmlElementExists && obj instanceof HTMLElement && obj.tagName === 'TH') {
return 'htmltableheadercellelement';
return 'HTMLTableHeaderCellElement';
}
}

Expand Down Expand Up @@ -220,7 +220,7 @@ module.exports = function typeDetect(obj) {
*/
var stringTag = (symbolToStringTagExists && obj[Symbol.toStringTag]);
if (typeof stringTag === 'string') {
return stringTag.toLowerCase();
return stringTag;
}

if (getPrototypeOfExists) {
Expand All @@ -234,7 +234,7 @@ module.exports = function typeDetect(obj) {
* regex constructor x 3,931,108 ops/sec ±0.58% (84 runs sampled)
*/
if (objPrototype === RegExp.prototype) {
return 'regexp';
return 'RegExp';
}

/* ! Speed optimisation
Expand All @@ -244,7 +244,7 @@ module.exports = function typeDetect(obj) {
* date x 3,953,779 ops/sec ±1.35% (77 runs sampled)
*/
if (objPrototype === Date.prototype) {
return 'date';
return 'Date';
}

/* ! Spec Conformance
Expand All @@ -257,7 +257,7 @@ module.exports = function typeDetect(obj) {
* - Safari 7.1-Latest === "[object Promise]"
*/
if (promiseExists && objPrototype === Promise.prototype) {
return 'promise';
return 'Promise';
}

/* ! Speed optimisation
Expand All @@ -267,7 +267,7 @@ module.exports = function typeDetect(obj) {
* set x 4,545,879 ops/sec ±1.13% (83 runs sampled)
*/
if (setExists && objPrototype === Set.prototype) {
return 'set';
return 'Set';
}

/* ! Speed optimisation
Expand All @@ -277,7 +277,7 @@ module.exports = function typeDetect(obj) {
* map x 4,183,945 ops/sec ±6.59% (82 runs sampled)
*/
if (mapExists && objPrototype === Map.prototype) {
return 'map';
return 'Map';
}

/* ! Speed optimisation
Expand All @@ -287,7 +287,7 @@ module.exports = function typeDetect(obj) {
* weakset x 4,237,510 ops/sec ±2.01% (77 runs sampled)
*/
if (weakSetExists && objPrototype === WeakSet.prototype) {
return 'weakset';
return 'WeakSet';
}

/* ! Speed optimisation
Expand All @@ -297,7 +297,7 @@ module.exports = function typeDetect(obj) {
* weakmap x 3,881,384 ops/sec ±1.45% (82 runs sampled)
*/
if (weakMapExists && objPrototype === WeakMap.prototype) {
return 'weakmap';
return 'WeakMap';
}

/* ! Spec Conformance
Expand All @@ -307,7 +307,7 @@ module.exports = function typeDetect(obj) {
* - Edge <=13 === "[object Object]"
*/
if (dataViewExists && objPrototype === DataView.prototype) {
return 'dataview';
return 'DataView';
}

/* ! Spec Conformance
Expand All @@ -317,7 +317,7 @@ module.exports = function typeDetect(obj) {
* - Edge <=13 === "[object Object]"
*/
if (mapExists && objPrototype === mapIteratorPrototype) {
return 'map iterator';
return 'Map Iterator';
}

/* ! Spec Conformance
Expand All @@ -327,7 +327,7 @@ module.exports = function typeDetect(obj) {
* - Edge <=13 === "[object Object]"
*/
if (setExists && objPrototype === setIteratorPrototype) {
return 'set iterator';
return 'Set Iterator';
}

/* ! Spec Conformance
Expand All @@ -337,7 +337,7 @@ module.exports = function typeDetect(obj) {
* - Edge <=13 === "[object Object]"
*/
if (arrayIteratorExists && objPrototype === arrayIteratorPrototype) {
return 'array iterator';
return 'Array Iterator';
}

/* ! Spec Conformance
Expand All @@ -347,7 +347,7 @@ module.exports = function typeDetect(obj) {
* - Edge <=13 === "[object Object]"
*/
if (stringIteratorExists && objPrototype === stringIteratorPrototype) {
return 'string iterator';
return 'String Iterator';
}

/* ! Speed optimisation
Expand All @@ -357,16 +357,15 @@ module.exports = function typeDetect(obj) {
* object from null x 5,838,000 ops/sec ±0.99% (84 runs sampled)
*/
if (objPrototype === null) {
return 'object';
return 'Object';
}
}

return Object
.prototype
.toString
.call(obj)
.slice(toStringLeftSliceLength, toStringRightSliceLength)
.toLowerCase();
.slice(toStringLeftSliceLength, toStringRightSliceLength);
};

module.exports.typeDetect = module.exports;

0 comments on commit 48c8108

Please sign in to comment.