JavaScript中是否有类似Java的class.getName()?


当前回答

好吧,伙计们,我一直在慢慢地建立一个catch all方法,这已经有几年了,哈哈!诀窍是:

有一个创建类的机制。 有一种机制来检查所有用户创建的类、原语和由本地构造函数创建/生成的值。 有一种机制可以将用户创建的类扩展为新的类,这样上述功能就可以渗透到你的代码/应用程序/库等中。

举个例子(或者看看我是如何处理这个问题的),看看github上的以下代码:https://github.com/elycruz/sjljs/blob/master/src/sjl/sjl.js并搜索:

名为= classOf class sofis =,和或 defineSubClass =(不带反撇号('))。

As you can see I have some mechanisms in place to force classOf to always give me the classes/constructors type name regardless of whether it is a primitive, a user defined class, a value created using a native constructor, Null, NaN, etc.. For every single javascript value I will get it's unique type name from the classOf function. In addition I can pass in actual constructors into sjl.classOfIs to check a value's type in addition to being able to pass in it's type name as well! So for example:

' ' ' //请原谅长命名空间!直到用了一段时间后,我才知道它的影响(它们太糟糕了,哈哈)

var SomeCustomClass = sjl.package.stdlib.Extendable.extend({
    constructor: function SomeCustomClass () {},
    // ...
}),

HelloIterator = sjl.ns.stdlib.Iterator.extend( 
    function HelloIterator () {}, 
    { /* ... methods here ... */ },
    { /* ... static props/methods here ... */ }
),

helloIt = new HelloIterator();

sjl.classOfIs(new SomeCustomClass(), SomeCustomClass) === true; // `true`
sjl.classOfIs(helloIt, HelloIterator) === true; // `true`

var someString = 'helloworld';

sjl.classOfIs(someString, String) === true; // `true`

sjl.classOfIs(99, Number) === true; // true

sjl.classOf(NaN) === 'NaN'; // true

sjl.classOf(new Map()) === 'Map';
sjl.classOf(new Set()) === 'Set';
sjl.classOfIs([1, 2, 4], Array) === true; // `true`

// etc..

// Also optionally the type you want to check against could be the type's name
sjl.classOfIs(['a', 'b', 'c'], 'Array') === true; // `true`!
sjl.classOfIs(helloIt, 'HelloIterator') === true; // `true`!

```

如果您有兴趣阅读更多关于我如何使用上面提到的设置,请查看repo: https://github.com/elycruz/sjljs

还有关于这个主题的书籍: - Stoyan Stefanov的《JavaScript模式》 - David Flanagan的《Javascript - The Definitive Guide》 ——还有其他很多人…(搜索le’web)。

你也可以快速测试我在这里谈论的功能: - http://sjljs.elycruz.com/0.5.18/tests/for-browser/ (url中的0.5.18路径也有来自github的源代码,减去node_modules等)。

编码快乐!

其他回答

其实我也在找类似的东西,然后遇到了这个问题。下面是我如何获得类型: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);
}

下面是我提出的解决instanceof缺点的解决方案。它可以从跨窗口和跨框架检查对象的类型,并且在基本类型方面没有问题。

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需要两个参数:一个对象和一个类型。它工作的真正技巧是检查对象是否来自同一个窗口,如果不是,则获取对象的窗口。

例子:

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

type参数也可以是返回构造函数的回调函数。回调函数将接收一个参数,该参数是所提供对象的窗口。

例子:

//"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

需要记住的一件事是IE < 9没有提供所有对象的构造函数,因此上面的NodeList测试将返回false,而且isInstance(alert,“Function”)也将返回false。

比如你有var obj;

如果你只想知道obj的类型名称,比如“Object”、“Array”或“String”, 你可以用这个:

Object.prototype.toString.call(obj).split(' ')[1].replace(']', '');

Agave.JS中的kind()函数将返回:

继承树中最接近的原型 对于'null'和'undefined'等始终为原始类型的类型,则为原始名称。

它适用于所有JS对象和原语,不管它们是如何创建的,并且没有任何惊喜。

var kind = function(item) {
        var getPrototype = function(item) {
            return Object.prototype.toString.call(item).slice(8, -1);
        };
        var kind, Undefined;
        if (item === null ) {
            kind = 'null';
        } else {
            if ( item === Undefined ) {
                kind = 'undefined';
            } else {
                var prototype = getPrototype(item);
                if ( ( prototype === 'Number' ) && isNaN(item) ) {
                    kind = 'NaN';
                } else {
                    kind = prototype;
                }
            }
        }
        return kind;
    };

例子:

数字

kind(37) === 'Number'
kind(3.14) === 'Number'
kind(Math.LN2) === 'Number'
kind(Infinity) === 'Number'
kind(Number(1)) === 'Number'
kind(new Number(1)) === 'Number'

NaN

kind(NaN) === 'NaN'

字符串

kind('') === 'String'
kind('bla') === 'String'
kind(String("abc")) === 'String'
kind(new String("abc")) === 'String'

布尔值

kind(true) === 'Boolean'
kind(false) === 'Boolean'
kind(new Boolean(true)) === 'Boolean'

数组

kind([1, 2, 4]) === 'Array'
kind(new Array(1, 2, 3)) === 'Array'

对象

kind({a:1}) === 'Object'
kind(new Object()) === 'Object'

日期

kind(new Date()) === 'Date'

功能

kind(function(){}) === 'Function'
kind(new Function("console.log(arguments)")) === 'Function'
kind(Math.sin) === 'Function'

未定义的

kind(undefined) === 'undefined'

null

kind(null) === 'null'

下面是一个基于公认答案的实现:

/** * 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));

只有在别无选择时才使用构造函数属性。