Gibt es eine JavaScript Äquivalent von Java 's class.getName()
?
Antworten
Zu viele Anzeigen?Verwendung von Object.prototype.toString
Wie in diesem Beitrag beschrieben, können Sie Object.prototype.toString - die einfache und generische Implementierung von toString - verwenden, um den Typ für alle integrierten Typen zu ermitteln
Object.prototype.toString.call('abc') // [object String]
Object.prototype.toString.call(/abc/) // [object RegExp]
Object.prototype.toString.call([1,2,3]) // [object Array]
Man könnte eine kurze Hilfsfunktion schreiben wie
function type(obj){
return Object.prototype.toString.call(obj]).match(/\s\w+/)[0].trim()
}
return [object String] as String
return [object Number] as Number
return [object Object] as Object
return [object Undefined] as Undefined
return [object Function] as Function
Hier ist eine Lösung, die ich mir ausgedacht habe und die die Unzulänglichkeiten von instanceof behebt. Sie kann die Typen eines Objekts fenster- und rahmenübergreifend prüfen und hat keine Probleme mit primitiven Typen.
function getType(o) {
return Object.prototype.toString.call(o).match(/^\[object\s(.*)\]$/)[1];
}
function isInstance(obj, type) {
var ret = false,
isTypeAString = getType(type) == "String",
functionConstructor, i, l, typeArray, context;
if (!isTypeAString && getType(type) != "Function") {
throw new TypeError("type argument must be a string or function");
}
if (obj !== undefined && obj !== null && obj.constructor) {
//get the Function constructor
functionConstructor = obj.constructor;
while (functionConstructor != functionConstructor.constructor) {
functionConstructor = functionConstructor.constructor;
}
//get the object's window
context = functionConstructor == Function ? self : functionConstructor("return window")();
//get the constructor for the type
if (isTypeAString) {
//type is a string so we'll build the context (window.Array or window.some.Type)
for (typeArray = type.split("."), i = 0, l = typeArray.length; i < l && context; i++) {
context = context[typeArray[i]];
}
} else {
//type is a function so execute the function passing in the object's window
//the return should be a constructor
context = type(context);
}
//check if the object is an instance of the constructor
if (context) {
ret = obj instanceof context;
if (!ret && (type == "Number" || type == "String" || type == "Boolean")) {
ret = obj.constructor == context
}
}
}
return ret;
}
isInstance benötigt zwei Parameter: ein Objekt und einen Typ. Der eigentliche Trick ist, dass geprüft wird, ob das Objekt aus demselben Fenster stammt, und wenn nicht, das Fenster des Objekts abgerufen wird.
Beispiele:
isInstance([], "Array"); //true
isInstance("some string", "String"); //true
isInstance(new Object(), "Object"); //true
function Animal() {}
function Dog() {}
Dog.prototype = new Animal();
isInstance(new Dog(), "Dog"); //true
isInstance(new Dog(), "Animal"); //true
isInstance(new Dog(), "Object"); //true
isInstance(new Animal(), "Dog"); //false
Das Typ-Argument kann auch eine Callback-Funktion sein, die einen Konstruktor zurückgibt. Die Callback-Funktion erhält einen Parameter, nämlich das Fenster des angegebenen Objekts.
Beispiele:
//"Arguments" type check
var args = (function() {
return arguments;
}());
isInstance(args, function(w) {
return w.Function("return arguments.constructor")();
}); //true
//"NodeList" type check
var nl = document.getElementsByTagName("*");
isInstance(nl, function(w) {
return w.document.getElementsByTagName("bs").constructor;
}); //true
Eine Sache, die zu beachten ist, ist, dass IE < 9 nicht den Konstruktor auf allen Objekten zur Verfügung stellt, so dass der obige Test für NodeList falsch zurückgeben würde und auch ein isInstance(alert, "Function") würde falsch zurückgeben.
Ich war gerade auf der Suche nach einem ähnlichen Thema und bin auf diese Frage gestoßen. Hier ist, wie ich Typen bekommen: jsfiddle
var TypeOf = function ( thing ) {
var typeOfThing = typeof thing;
if ( 'object' === typeOfThing ) {
typeOfThing = Object.prototype.toString.call( thing );
if ( '[object Object]' === typeOfThing ) {
if ( thing.constructor.name ) {
return thing.constructor.name;
}
else if ( '[' === thing.constructor.toString().charAt(0) ) {
typeOfThing = typeOfThing.substring( 8,typeOfThing.length - 1 );
}
else {
typeOfThing = thing.constructor.toString().match( /function\s*(\w+)/ );
if ( typeOfThing ) {
return typeOfThing[1];
}
else {
return 'Function';
}
}
}
else {
typeOfThing = typeOfThing.substring( 8,typeOfThing.length - 1 );
}
}
return typeOfThing.charAt(0).toUpperCase() + typeOfThing.slice(1);
}
Hier ist eine Implementierung, die auf die akzeptierte Antwort :
/**
* Describes the type of a variable.
*/
class VariableType
{
type;
name;
/**
* Creates a new VariableType.
*
* @param {"undefined" | "null" | "boolean" | "number" | "bigint" | "array" | "string" | "symbol" |
* "function" | "class" | "object"} type the name of the type
* @param {null | string} [name = null] the name of the type (the function or class name)
* @throws {RangeError} if neither <code>type</code> or <code>name</code> are set. If <code>type</code>
* does not have a name (e.g. "number" or "array") but <code>name</code> is set.
*/
constructor(type, name = null)
{
switch (type)
{
case "undefined":
case "null":
case "boolean" :
case "number" :
case "bigint":
case "array":
case "string":
case "symbol":
if (name !== null)
throw new RangeError(type + " may not have a name");
}
this.type = type;
this.name = name;
}
/**
* @return {string} the string representation of this object
*/
toString()
{
let result;
switch (this.type)
{
case "function":
case "class":
{
result = "a ";
break;
}
case "object":
{
result = "an ";
break;
}
default:
return this.type;
}
result += this.type;
if (this.name !== null)
result += " named " + this.name;
return result;
}
}
const functionNamePattern = /^function\s+([^(]+)?\(/;
const classNamePattern = /^class(\s+[^{]+)?{/;
/**
* Returns the type information of a value.
*
* <ul>
* <li>If the input is undefined, returns <code>(type="undefined", name=null)</code>.</li>
* <li>If the input is null, returns <code>(type="null", name=null)</code>.</li>
* <li>If the input is a primitive boolean, returns <code>(type="boolean", name=null)</code>.</li>
* <li>If the input is a primitive number, returns <code>(type="number", name=null)</code>.</li>
* <li>If the input is a primitive or wrapper bigint, returns
* <code>(type="bigint", name=null)</code>.</li>
* <li>If the input is an array, returns <code>(type="array", name=null)</code>.</li>
* <li>If the input is a primitive string, returns <code>(type="string", name=null)</code>.</li>
* <li>If the input is a primitive symbol, returns <code>(type="symbol", null)</code>.</li>
* <li>If the input is a function, returns <code>(type="function", name=the function name)</code>. If the
* input is an arrow or anonymous function, its name is <code>null</code>.</li>
* <li>If the input is a function, returns <code>(type="function", name=the function name)</code>.</li>
* <li>If the input is a class, returns <code>(type="class", name=the name of the class)</code>.
* <li>If the input is an object, returns
* <code>(type="object", name=the name of the object's class)</code>.
* </li>
* </ul>
*
* Please note that built-in types (such as <code>Object</code>, <code>String</code> or <code>Number</code>)
* may return type <code>function</code> instead of <code>class</code>.
*
* @param {object} value a value
* @return {VariableType} <code>value</code>'s type
* @see <a href="http://stackoverflow.com/a/332429/14731">http://stackoverflow.com/a/332429/14731</a>
* @see isPrimitive
*/
function getTypeInfo(value)
{
if (value === null)
return new VariableType("null");
const typeOfValue = typeof (value);
const isPrimitive = typeOfValue !== "function" && typeOfValue !== "object";
if (isPrimitive)
return new VariableType(typeOfValue);
const objectToString = Object.prototype.toString.call(value).slice(8, -1);
// eslint-disable-next-line @typescript-eslint/ban-types
const valueToString = value.toString();
if (objectToString === "Function")
{
// A function or a constructor
const indexOfArrow = valueToString.indexOf("=>");
const indexOfBody = valueToString.indexOf("{");
if (indexOfArrow !== -1 && (indexOfBody === -1 || indexOfArrow < indexOfBody))
{
// Arrow function
return new VariableType("function");
}
// Anonymous and named functions
const functionName = functionNamePattern.exec(valueToString);
if (functionName !== null && typeof (functionName[1]) !== "undefined")
{
// Found a named function or class constructor
return new VariableType("function", functionName[1].trim());
}
const className = classNamePattern.exec(valueToString);
if (className !== null && typeof (className[1]) !== "undefined")
{
// When running under ES6+
return new VariableType("class", className[1].trim());
}
// Anonymous function
return new VariableType("function");
}
if (objectToString === "Array")
return new VariableType("array");
const classInfo = getTypeInfo(value.constructor);
return new VariableType("object", classInfo.name);
}
function UserFunction()
{
}
function UserClass()
{
}
let anonymousFunction = function()
{
};
let arrowFunction = i => i + 1;
console.log("getTypeInfo(undefined): " + getTypeInfo(undefined));
console.log("getTypeInfo(null): " + getTypeInfo(null));
console.log("getTypeInfo(true): " + getTypeInfo(true));
console.log("getTypeInfo(5): " + getTypeInfo(5));
console.log("getTypeInfo(\"text\"): " + getTypeInfo("text"));
console.log("getTypeInfo(userFunction): " + getTypeInfo(UserFunction));
console.log("getTypeInfo(anonymousFunction): " + getTypeInfo(anonymousFunction));
console.log("getTypeInfo(arrowFunction): " + getTypeInfo(arrowFunction));
console.log("getTypeInfo(userObject): " + getTypeInfo(new UserClass()));
console.log("getTypeInfo(nativeObject): " + getTypeInfo(navigator.mediaDevices.getUserMedia));
Wir verwenden die Konstruktoreigenschaft nur, wenn wir keine andere Wahl haben.