๐พtypeName()
JS โฉ value โฉ type โฉ name โฉ typeName()
printPrototypeChain() - print the prototype chain of an object.
replit๏ผtypeName() (v.2)
typeof base type expr value
--------------------------------------------------------------------------
objectโญ๏ธ Null Null null null
--------------------------------------------------------------------------
undefined Undefined Undefined undefined undefined
--------------------------------------------------------------------------
number Number Number 37 37
number Number Number 3.14 3.14
number Number Number Math.LN2 0.6931471805599453
number Number Number Infinity Infinity
number Number Number NaN NaN
number Number Number Number('1') 1
number Number Number Number('ab') NaN
--------------------------------------------------------------------------
bigint BigInt BigInt 42 42n
--------------------------------------------------------------------------
string String String 'bla' bla
string String String `x = ${1+2}` x = 3
string String String typeof 1 number
string String String String({}) [object Object]
string String String typeof xxx undefined
--------------------------------------------------------------------------
boolean Boolean Boolean true true
boolean Boolean Boolean Boolean(1) true
boolean Boolean Boolean !!(1) true
--------------------------------------------------------------------------
symbol Symbol Symbol Symbol() Symbol()
symbol Symbol Symbol Symbol.iterator Symbol(Symbol.iterator)
--------------------------------------------------------------------------
object Object Object {a:1} { a: 1 }
objectโญ๏ธ User User user User { name: 'JohnDoe' }
objectโญ๏ธ Array Array [1, 2] [ 1, 2 ]
objectโญ๏ธ Date Date new Date() 2022-09-13T01:26:32.214Z
objectโญ๏ธ RegExp RegExp /regex/ /regex/
--------------------------------------------------------------------------
function Function Function function(){} [Function (anonymous)]
function Function Function Math.sin [Function: sin]
function Function Function () => {} [Function (anonymous)]
functionโญ๏ธโ Function class class {} [class (anonymous)]
functionโญ๏ธโ Function class User [class User]
functionโญ๏ธ GeneratorFunction GeneratorFunction function*(){} [GeneratorFunction (anonymous)]
--------------------------------------------------------------------------
โข โญ๏ธ types not all the same โข โ base !== type
replit๏ผtypeName() (v.2)
require๏ผ isClass(), baseTypeName()
// โญ๏ธ type name
// - require:
// โข baseTypeName()
// โข isClass()
function typeName(value) {
if (isClass(value)) return "class"; // class
return baseTypeName(value); // other cases
}
๐ module (copy and paste this file to use it)
// โญ base type name
function baseTypeName(value) {
// --------------
// โ โฑ -1 (index of last character)
// 0123456789012
// โญโโโฎ
// "[object XXXX]" โญโโโโฎ
// ^^^^ <---- slice(8, -1)
return Object.prototype.toString.call(value).slice(8, -1);
}
/**
* โญ๏ธ content of function's definition
*
* @throws {TypeError} will throw a TypeError if value is not a function
* @return {string}
*/
function functionDefinition(value) {
// ---------------------------------------------------------------------
// โญ๏ธ will throw a TypeError if value is not a function:
// โ TypeError:
// Function.prototype.toString requires that 'this' be a Function
// ---------------------------------------------------------------------
return Function.prototype.toString.call(value);
}
// โญ๏ธ check if value is a function
// - require: baseTypeName()
function isFunction(value) {
return baseTypeName(value) === "Function";
}
// โญ๏ธ check if value is a "class"
// - require:
// โข isFunction()
// โข functionDefinition()
function isClass(value) {
return (
// `value` is a function
isFunction(value) &&
// `value` is a "class" definition
functionDefinition(value).startsWith("class")
);
}
// โญ๏ธ type name
// - require:
// โข baseTypeName()
// โข isClass()
function typeName(value) {
if (isClass(value)) return "class"; // class
return baseTypeName(value); // other cases
}
// node exports
module.exports = {
baseTypeName,
isFunction,
functionDefinition,
isClass,
typeName,
}
replit๏ผtypeName() (v.2)
๐ index.js
// โญ import (functions for type name)
const { typeName, baseTypeName } = require('./typeNames.js');
const { testCases } = require('./testCases.js');
// table settings
const header = ['typeof', 'base', 'type', 'expr', 'value'];
const cols = header.length;
const [width, pad, ext] = [12, 1, 10];
const line = '-'.repeat(width*cols + pad*(cols-1) + ext);
// header
console.log(...header.map(s => s.padEnd(width, ' ')));
console.log(line);
// rows
for (const testCase of testCases) {
// separator
if (testCase === '---') {
console.log(line);
continue;
}
// test cases
const value = testCase[0];
const expr = testCase[1] || String(testCase[0]);
const types = [typeof value, baseTypeName(value), typeName(value)];
const numberOfDifferentTypes = new Set(types.map(s => s.toLowerCase())).size;
if (numberOfDifferentTypes > 1) types[0] += 'โญ๏ธ';
if (baseTypeName(value) !== typeName(value)) types[0] += 'โ';
console.log(
...[...types, expr].map(s => s.padEnd(width, ' ')),
value,
)
}
console.log(line);
// legend
console.log(`โข โญ๏ธ types not all the same โข โ base !== type`);
๐ testCases.js
// custom class
class User {
// โญ class field
name = 'JohnDoe';
// โญ custom class name
get [Symbol.toStringTag]() { return 'User' }
}
// instance
let user = new User();
// test values: [expr, expr string]
const testCases = [
// โญ๏ธ null
[null, ],
'---',
// โญ๏ธ undefined --------------------------------------
[undefined, ],
'---',
// โญ๏ธ Number --------------------------------------
[37, ],
[3.14, ],
[Math.LN2, 'Math.LN2'],
[Infinity, ],
[NaN, ],
[Number('1'), `Number('1')`], // 1
[Number('abc'), `Number('ab')`], // NaNโ
'---',
// โญ๏ธ bigInt --------------------------------------
[42n, ],
'---',
// โญ๏ธ String --------------------------------------
['bla', `'bla'`],
[`x = ${1+2}`, '`x = ${1+2}`'], //
[typeof 1, 'typeof 1'], // always returns a string
[String({}), 'String({})'], // [object]โ
[typeof xxx, 'typeof xxx'], // 'undefined'โ (string)
'---',
// โญ๏ธ Boolean --------------------------------------
[true, ],
[Boolean(1), 'Boolean(1)'], // true
[!!(1), '!!(1)'], // true
'---',
// โญ๏ธ Symbol --------------------------------------
[Symbol(), ],
[Symbol.iterator, 'Symbol.iterator'],
'---',
// โญ๏ธ objects --------------------------------------
[{ a: 1 }, '{a:1}'], // object literal
[user, 'user'], // instance of User
[[1, 2], '[1, 2]'], // Array
[new Date(), 'new Date()'], // Date
[/regex/, ], // RegExp
'---',
// โญ๏ธ Functions --------------------------------------
[function(){}, 'function(){}'], // "normal" function
[Math.sin, 'Math.sin'], // method
[() => {}, '() => {}'], // arrow function
[class {}, 'class {}'], // class โญ๏ธ
[User, 'User'], // class โญ๏ธ
[function*(){}, 'function*(){}'], // generator functions
];
// export
module.exports = { User, testCases };
objects can change the behavior of Object.prototype.toString()
by defining a Symbol.toStringTag
property, leading to unexpected results:
const date = new Date();
date[Symbol.toStringTag] = 'XXX';
Date.prototype[Symbol.toStringTag] = 'prototype polluted';
const toString = Object.prototype.toString; // keep it short
toString.call(date); // [object XXX]
toString.call(new Date()); // [object prototype polluted]
Last updated