Get the name of an object's type

前端 未结 20 2252
忘掉有多难
忘掉有多难 2020-11-21 22:37

Is there a JavaScript equivalent of Java\'s class.getName()?

20条回答
  •  礼貌的吻别
    2020-11-21 22:45

    Here is a solution that I have come up with that solves the shortcomings of instanceof. It can check an object's types from cross-windows and cross-frames and doesn't have problems with primitive types.

    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 requires two parameters: an object and a type. The real trick to how it works is that it checks if the object is from the same window and if not gets the object's window.

    Examples:

    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
    

    The type argument can also be a callback function which returns a constructor. The callback function will receive one parameter which is the window of the provided object.

    Examples:

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

    One thing to keep in mind is that IE < 9 does not provide the constructor on all objects so the above test for NodeList would return false and also a isInstance(alert, "Function") would return false.

提交回复
热议问题