type-detect.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  3. typeof define === 'function' && define.amd ? define(factory) :
  4. (global.typeDetect = factory());
  5. }(this, (function () { 'use strict';
  6. /* !
  7. * type-detect
  8. * Copyright(c) 2013 jake luer <jake@alogicalparadox.com>
  9. * MIT Licensed
  10. */
  11. var promiseExists = typeof Promise === 'function';
  12. /* eslint-disable no-undef */
  13. var globalObject = typeof self === 'object' ? self : global; // eslint-disable-line id-blacklist
  14. var symbolExists = typeof Symbol !== 'undefined';
  15. var mapExists = typeof Map !== 'undefined';
  16. var setExists = typeof Set !== 'undefined';
  17. var weakMapExists = typeof WeakMap !== 'undefined';
  18. var weakSetExists = typeof WeakSet !== 'undefined';
  19. var dataViewExists = typeof DataView !== 'undefined';
  20. var symbolIteratorExists = symbolExists && typeof Symbol.iterator !== 'undefined';
  21. var symbolToStringTagExists = symbolExists && typeof Symbol.toStringTag !== 'undefined';
  22. var setEntriesExists = setExists && typeof Set.prototype.entries === 'function';
  23. var mapEntriesExists = mapExists && typeof Map.prototype.entries === 'function';
  24. var setIteratorPrototype = setEntriesExists && Object.getPrototypeOf(new Set().entries());
  25. var mapIteratorPrototype = mapEntriesExists && Object.getPrototypeOf(new Map().entries());
  26. var arrayIteratorExists = symbolIteratorExists && typeof Array.prototype[Symbol.iterator] === 'function';
  27. var arrayIteratorPrototype = arrayIteratorExists && Object.getPrototypeOf([][Symbol.iterator]());
  28. var stringIteratorExists = symbolIteratorExists && typeof String.prototype[Symbol.iterator] === 'function';
  29. var stringIteratorPrototype = stringIteratorExists && Object.getPrototypeOf(''[Symbol.iterator]());
  30. var toStringLeftSliceLength = 8;
  31. var toStringRightSliceLength = -1;
  32. /**
  33. * ### typeOf (obj)
  34. *
  35. * Uses `Object.prototype.toString` to determine the type of an object,
  36. * normalising behaviour across engine versions & well optimised.
  37. *
  38. * @param {Mixed} object
  39. * @return {String} object type
  40. * @api public
  41. */
  42. function typeDetect(obj) {
  43. /* ! Speed optimisation
  44. * Pre:
  45. * string literal x 3,039,035 ops/sec ±1.62% (78 runs sampled)
  46. * boolean literal x 1,424,138 ops/sec ±4.54% (75 runs sampled)
  47. * number literal x 1,653,153 ops/sec ±1.91% (82 runs sampled)
  48. * undefined x 9,978,660 ops/sec ±1.92% (75 runs sampled)
  49. * function x 2,556,769 ops/sec ±1.73% (77 runs sampled)
  50. * Post:
  51. * string literal x 38,564,796 ops/sec ±1.15% (79 runs sampled)
  52. * boolean literal x 31,148,940 ops/sec ±1.10% (79 runs sampled)
  53. * number literal x 32,679,330 ops/sec ±1.90% (78 runs sampled)
  54. * undefined x 32,363,368 ops/sec ±1.07% (82 runs sampled)
  55. * function x 31,296,870 ops/sec ±0.96% (83 runs sampled)
  56. */
  57. var typeofObj = typeof obj;
  58. if (typeofObj !== 'object') {
  59. return typeofObj;
  60. }
  61. /* ! Speed optimisation
  62. * Pre:
  63. * null x 28,645,765 ops/sec ±1.17% (82 runs sampled)
  64. * Post:
  65. * null x 36,428,962 ops/sec ±1.37% (84 runs sampled)
  66. */
  67. if (obj === null) {
  68. return 'null';
  69. }
  70. /* ! Spec Conformance
  71. * Test: `Object.prototype.toString.call(window)``
  72. * - Node === "[object global]"
  73. * - Chrome === "[object global]"
  74. * - Firefox === "[object Window]"
  75. * - PhantomJS === "[object Window]"
  76. * - Safari === "[object Window]"
  77. * - IE 11 === "[object Window]"
  78. * - IE Edge === "[object Window]"
  79. * Test: `Object.prototype.toString.call(this)``
  80. * - Chrome Worker === "[object global]"
  81. * - Firefox Worker === "[object DedicatedWorkerGlobalScope]"
  82. * - Safari Worker === "[object DedicatedWorkerGlobalScope]"
  83. * - IE 11 Worker === "[object WorkerGlobalScope]"
  84. * - IE Edge Worker === "[object WorkerGlobalScope]"
  85. */
  86. if (obj === globalObject) {
  87. return 'global';
  88. }
  89. /* ! Speed optimisation
  90. * Pre:
  91. * array literal x 2,888,352 ops/sec ±0.67% (82 runs sampled)
  92. * Post:
  93. * array literal x 22,479,650 ops/sec ±0.96% (81 runs sampled)
  94. */
  95. if (
  96. Array.isArray(obj) &&
  97. (symbolToStringTagExists === false || !(Symbol.toStringTag in obj))
  98. ) {
  99. return 'Array';
  100. }
  101. // Not caching existence of `window` and related properties due to potential
  102. // for `window` to be unset before tests in quasi-browser environments.
  103. if (typeof window === 'object' && window !== null) {
  104. /* ! Spec Conformance
  105. * (https://html.spec.whatwg.org/multipage/browsers.html#location)
  106. * WhatWG HTML$7.7.3 - The `Location` interface
  107. * Test: `Object.prototype.toString.call(window.location)``
  108. * - IE <=11 === "[object Object]"
  109. * - IE Edge <=13 === "[object Object]"
  110. */
  111. if (typeof window.location === 'object' && obj === window.location) {
  112. return 'Location';
  113. }
  114. /* ! Spec Conformance
  115. * (https://html.spec.whatwg.org/#document)
  116. * WhatWG HTML$3.1.1 - The `Document` object
  117. * Note: Most browsers currently adher to the W3C DOM Level 2 spec
  118. * (https://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-26809268)
  119. * which suggests that browsers should use HTMLTableCellElement for
  120. * both TD and TH elements. WhatWG separates these.
  121. * WhatWG HTML states:
  122. * > For historical reasons, Window objects must also have a
  123. * > writable, configurable, non-enumerable property named
  124. * > HTMLDocument whose value is the Document interface object.
  125. * Test: `Object.prototype.toString.call(document)``
  126. * - Chrome === "[object HTMLDocument]"
  127. * - Firefox === "[object HTMLDocument]"
  128. * - Safari === "[object HTMLDocument]"
  129. * - IE <=10 === "[object Document]"
  130. * - IE 11 === "[object HTMLDocument]"
  131. * - IE Edge <=13 === "[object HTMLDocument]"
  132. */
  133. if (typeof window.document === 'object' && obj === window.document) {
  134. return 'Document';
  135. }
  136. if (typeof window.navigator === 'object') {
  137. /* ! Spec Conformance
  138. * (https://html.spec.whatwg.org/multipage/webappapis.html#mimetypearray)
  139. * WhatWG HTML$8.6.1.5 - Plugins - Interface MimeTypeArray
  140. * Test: `Object.prototype.toString.call(navigator.mimeTypes)``
  141. * - IE <=10 === "[object MSMimeTypesCollection]"
  142. */
  143. if (typeof window.navigator.mimeTypes === 'object' &&
  144. obj === window.navigator.mimeTypes) {
  145. return 'MimeTypeArray';
  146. }
  147. /* ! Spec Conformance
  148. * (https://html.spec.whatwg.org/multipage/webappapis.html#pluginarray)
  149. * WhatWG HTML$8.6.1.5 - Plugins - Interface PluginArray
  150. * Test: `Object.prototype.toString.call(navigator.plugins)``
  151. * - IE <=10 === "[object MSPluginsCollection]"
  152. */
  153. if (typeof window.navigator.plugins === 'object' &&
  154. obj === window.navigator.plugins) {
  155. return 'PluginArray';
  156. }
  157. }
  158. if ((typeof window.HTMLElement === 'function' ||
  159. typeof window.HTMLElement === 'object') &&
  160. obj instanceof window.HTMLElement) {
  161. /* ! Spec Conformance
  162. * (https://html.spec.whatwg.org/multipage/webappapis.html#pluginarray)
  163. * WhatWG HTML$4.4.4 - The `blockquote` element - Interface `HTMLQuoteElement`
  164. * Test: `Object.prototype.toString.call(document.createElement('blockquote'))``
  165. * - IE <=10 === "[object HTMLBlockElement]"
  166. */
  167. if (obj.tagName === 'BLOCKQUOTE') {
  168. return 'HTMLQuoteElement';
  169. }
  170. /* ! Spec Conformance
  171. * (https://html.spec.whatwg.org/#htmltabledatacellelement)
  172. * WhatWG HTML$4.9.9 - The `td` element - Interface `HTMLTableDataCellElement`
  173. * Note: Most browsers currently adher to the W3C DOM Level 2 spec
  174. * (https://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-82915075)
  175. * which suggests that browsers should use HTMLTableCellElement for
  176. * both TD and TH elements. WhatWG separates these.
  177. * Test: Object.prototype.toString.call(document.createElement('td'))
  178. * - Chrome === "[object HTMLTableCellElement]"
  179. * - Firefox === "[object HTMLTableCellElement]"
  180. * - Safari === "[object HTMLTableCellElement]"
  181. */
  182. if (obj.tagName === 'TD') {
  183. return 'HTMLTableDataCellElement';
  184. }
  185. /* ! Spec Conformance
  186. * (https://html.spec.whatwg.org/#htmltableheadercellelement)
  187. * WhatWG HTML$4.9.9 - The `td` element - Interface `HTMLTableHeaderCellElement`
  188. * Note: Most browsers currently adher to the W3C DOM Level 2 spec
  189. * (https://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-82915075)
  190. * which suggests that browsers should use HTMLTableCellElement for
  191. * both TD and TH elements. WhatWG separates these.
  192. * Test: Object.prototype.toString.call(document.createElement('th'))
  193. * - Chrome === "[object HTMLTableCellElement]"
  194. * - Firefox === "[object HTMLTableCellElement]"
  195. * - Safari === "[object HTMLTableCellElement]"
  196. */
  197. if (obj.tagName === 'TH') {
  198. return 'HTMLTableHeaderCellElement';
  199. }
  200. }
  201. }
  202. /* ! Speed optimisation
  203. * Pre:
  204. * Float64Array x 625,644 ops/sec ±1.58% (80 runs sampled)
  205. * Float32Array x 1,279,852 ops/sec ±2.91% (77 runs sampled)
  206. * Uint32Array x 1,178,185 ops/sec ±1.95% (83 runs sampled)
  207. * Uint16Array x 1,008,380 ops/sec ±2.25% (80 runs sampled)
  208. * Uint8Array x 1,128,040 ops/sec ±2.11% (81 runs sampled)
  209. * Int32Array x 1,170,119 ops/sec ±2.88% (80 runs sampled)
  210. * Int16Array x 1,176,348 ops/sec ±5.79% (86 runs sampled)
  211. * Int8Array x 1,058,707 ops/sec ±4.94% (77 runs sampled)
  212. * Uint8ClampedArray x 1,110,633 ops/sec ±4.20% (80 runs sampled)
  213. * Post:
  214. * Float64Array x 7,105,671 ops/sec ±13.47% (64 runs sampled)
  215. * Float32Array x 5,887,912 ops/sec ±1.46% (82 runs sampled)
  216. * Uint32Array x 6,491,661 ops/sec ±1.76% (79 runs sampled)
  217. * Uint16Array x 6,559,795 ops/sec ±1.67% (82 runs sampled)
  218. * Uint8Array x 6,463,966 ops/sec ±1.43% (85 runs sampled)
  219. * Int32Array x 5,641,841 ops/sec ±3.49% (81 runs sampled)
  220. * Int16Array x 6,583,511 ops/sec ±1.98% (80 runs sampled)
  221. * Int8Array x 6,606,078 ops/sec ±1.74% (81 runs sampled)
  222. * Uint8ClampedArray x 6,602,224 ops/sec ±1.77% (83 runs sampled)
  223. */
  224. var stringTag = (symbolToStringTagExists && obj[Symbol.toStringTag]);
  225. if (typeof stringTag === 'string') {
  226. return stringTag;
  227. }
  228. var objPrototype = Object.getPrototypeOf(obj);
  229. /* ! Speed optimisation
  230. * Pre:
  231. * regex literal x 1,772,385 ops/sec ±1.85% (77 runs sampled)
  232. * regex constructor x 2,143,634 ops/sec ±2.46% (78 runs sampled)
  233. * Post:
  234. * regex literal x 3,928,009 ops/sec ±0.65% (78 runs sampled)
  235. * regex constructor x 3,931,108 ops/sec ±0.58% (84 runs sampled)
  236. */
  237. if (objPrototype === RegExp.prototype) {
  238. return 'RegExp';
  239. }
  240. /* ! Speed optimisation
  241. * Pre:
  242. * date x 2,130,074 ops/sec ±4.42% (68 runs sampled)
  243. * Post:
  244. * date x 3,953,779 ops/sec ±1.35% (77 runs sampled)
  245. */
  246. if (objPrototype === Date.prototype) {
  247. return 'Date';
  248. }
  249. /* ! Spec Conformance
  250. * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-promise.prototype-@@tostringtag)
  251. * ES6$25.4.5.4 - Promise.prototype[@@toStringTag] should be "Promise":
  252. * Test: `Object.prototype.toString.call(Promise.resolve())``
  253. * - Chrome <=47 === "[object Object]"
  254. * - Edge <=20 === "[object Object]"
  255. * - Firefox 29-Latest === "[object Promise]"
  256. * - Safari 7.1-Latest === "[object Promise]"
  257. */
  258. if (promiseExists && objPrototype === Promise.prototype) {
  259. return 'Promise';
  260. }
  261. /* ! Speed optimisation
  262. * Pre:
  263. * set x 2,222,186 ops/sec ±1.31% (82 runs sampled)
  264. * Post:
  265. * set x 4,545,879 ops/sec ±1.13% (83 runs sampled)
  266. */
  267. if (setExists && objPrototype === Set.prototype) {
  268. return 'Set';
  269. }
  270. /* ! Speed optimisation
  271. * Pre:
  272. * map x 2,396,842 ops/sec ±1.59% (81 runs sampled)
  273. * Post:
  274. * map x 4,183,945 ops/sec ±6.59% (82 runs sampled)
  275. */
  276. if (mapExists && objPrototype === Map.prototype) {
  277. return 'Map';
  278. }
  279. /* ! Speed optimisation
  280. * Pre:
  281. * weakset x 1,323,220 ops/sec ±2.17% (76 runs sampled)
  282. * Post:
  283. * weakset x 4,237,510 ops/sec ±2.01% (77 runs sampled)
  284. */
  285. if (weakSetExists && objPrototype === WeakSet.prototype) {
  286. return 'WeakSet';
  287. }
  288. /* ! Speed optimisation
  289. * Pre:
  290. * weakmap x 1,500,260 ops/sec ±2.02% (78 runs sampled)
  291. * Post:
  292. * weakmap x 3,881,384 ops/sec ±1.45% (82 runs sampled)
  293. */
  294. if (weakMapExists && objPrototype === WeakMap.prototype) {
  295. return 'WeakMap';
  296. }
  297. /* ! Spec Conformance
  298. * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-dataview.prototype-@@tostringtag)
  299. * ES6$24.2.4.21 - DataView.prototype[@@toStringTag] should be "DataView":
  300. * Test: `Object.prototype.toString.call(new DataView(new ArrayBuffer(1)))``
  301. * - Edge <=13 === "[object Object]"
  302. */
  303. if (dataViewExists && objPrototype === DataView.prototype) {
  304. return 'DataView';
  305. }
  306. /* ! Spec Conformance
  307. * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%mapiteratorprototype%-@@tostringtag)
  308. * ES6$23.1.5.2.2 - %MapIteratorPrototype%[@@toStringTag] should be "Map Iterator":
  309. * Test: `Object.prototype.toString.call(new Map().entries())``
  310. * - Edge <=13 === "[object Object]"
  311. */
  312. if (mapExists && objPrototype === mapIteratorPrototype) {
  313. return 'Map Iterator';
  314. }
  315. /* ! Spec Conformance
  316. * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%setiteratorprototype%-@@tostringtag)
  317. * ES6$23.2.5.2.2 - %SetIteratorPrototype%[@@toStringTag] should be "Set Iterator":
  318. * Test: `Object.prototype.toString.call(new Set().entries())``
  319. * - Edge <=13 === "[object Object]"
  320. */
  321. if (setExists && objPrototype === setIteratorPrototype) {
  322. return 'Set Iterator';
  323. }
  324. /* ! Spec Conformance
  325. * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%arrayiteratorprototype%-@@tostringtag)
  326. * ES6$22.1.5.2.2 - %ArrayIteratorPrototype%[@@toStringTag] should be "Array Iterator":
  327. * Test: `Object.prototype.toString.call([][Symbol.iterator]())``
  328. * - Edge <=13 === "[object Object]"
  329. */
  330. if (arrayIteratorExists && objPrototype === arrayIteratorPrototype) {
  331. return 'Array Iterator';
  332. }
  333. /* ! Spec Conformance
  334. * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%stringiteratorprototype%-@@tostringtag)
  335. * ES6$21.1.5.2.2 - %StringIteratorPrototype%[@@toStringTag] should be "String Iterator":
  336. * Test: `Object.prototype.toString.call(''[Symbol.iterator]())``
  337. * - Edge <=13 === "[object Object]"
  338. */
  339. if (stringIteratorExists && objPrototype === stringIteratorPrototype) {
  340. return 'String Iterator';
  341. }
  342. /* ! Speed optimisation
  343. * Pre:
  344. * object from null x 2,424,320 ops/sec ±1.67% (76 runs sampled)
  345. * Post:
  346. * object from null x 5,838,000 ops/sec ±0.99% (84 runs sampled)
  347. */
  348. if (objPrototype === null) {
  349. return 'Object';
  350. }
  351. return Object
  352. .prototype
  353. .toString
  354. .call(obj)
  355. .slice(toStringLeftSliceLength, toStringRightSliceLength);
  356. }
  357. return typeDetect;
  358. })));