1319 Stimmen

Den Namen des Typs eines Objekts ermitteln

Gibt es eine JavaScript Äquivalent von Java 's class.getName() ?

14voto

Gaurav Ramanan Punkte 3395

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

10voto

Eli Punkte 421

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.

10voto

Mahdi Punkte 8861

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);
}

7voto

Gili Punkte 80842

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.

7voto

defrex Punkte 14248

Utilisez constructor.name wenn Sie können, und Regex-Funktion, wenn ich nicht kann.

Function.prototype.getName = function(){
  if (typeof this.name != 'undefined')
    return this.name;
  else
    return /function (.+)\(/.exec(this.toString())[1];
};

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X