Get the name of an object's type

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

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

相关标签:
20条回答
  • 2020-11-21 22:39

    You can use the "instanceof" operator to determine if an object is an instance of a certain class or not. If you do not know the name of an object's type, you can use its constructor property. The constructor property of objects, is a reference to the function that is used to initialize them. Example:

    function Circle (x,y,radius) {
        this._x = x;
        this._y = y;
        this._radius = raduius;
    }
    var c1 = new Circle(10,20,5);
    

    Now c1.constructor is a reference to the Circle() function. You can alsow use the typeof operator, but the typeof operator shows limited information. One solution is to use the toString() method of the Object global object. For example if you have an object, say myObject, you can use the toString() method of the global Object to determine the type of the class of myObject. Use this:

    Object.prototype.toString.apply(myObject);
    
    0 讨论(0)
  • 2020-11-21 22:39

    Lodash has many isMethods so if you're using Lodash maybe a mixin like this can be useful:

      // Mixin for identifying a Javascript Object
    
      _.mixin({
          'identify' : function(object) {
            var output;
              var isMethods = ['isArguments', 'isArray', 'isArguments', 'isBoolean', 'isDate', 'isArguments', 
                  'isElement', 'isError', 'isFunction', 'isNaN', 'isNull', 'isNumber', 
                  'isPlainObject', 'isRegExp', 'isString', 'isTypedArray', 'isUndefined', 'isEmpty', 'isObject']
    
              this.each(isMethods, function (method) {
                  if (this[method](object)) {
                    output = method;
                    return false;
                  }
              }.bind(this));
          return output;
          }
      });
    

    It adds a method to lodash called "identify" which works as follow:

    console.log(_.identify('hello friend'));       // isString
    

    Plunker: http://plnkr.co/edit/Zdr0KDtQt76Ul3KTEDSN

    0 讨论(0)
  • 2020-11-21 22:43

    Here is an implementation based on the accepted answer:

    /**
     * Returns the name of an object's type.
     *
     * If the input is undefined, returns "Undefined".
     * If the input is null, returns "Null".
     * If the input is a boolean, returns "Boolean".
     * If the input is a number, returns "Number".
     * If the input is a string, returns "String".
     * If the input is a named function or a class constructor, returns "Function".
     * If the input is an anonymous function, returns "AnonymousFunction".
     * If the input is an arrow function, returns "ArrowFunction".
     * If the input is a class instance, returns "Object".
     *
     * @param {Object} object an object
     * @return {String} the name of the object's class
     * @see <a href="https://stackoverflow.com/a/332429/14731">https://stackoverflow.com/a/332429/14731</a>
     * @see getFunctionName
     * @see getObjectClass 
     */
    function getTypeName(object)
    {
      const objectToString = Object.prototype.toString.call(object).slice(8, -1);
      if (objectToString === "Function")
      {
        const instanceToString = object.toString();
        if (instanceToString.indexOf(" => ") != -1)
          return "ArrowFunction";
        const getFunctionName = /^function ([^(]+)\(/;
        const match = instanceToString.match(getFunctionName);
        if (match === null)
          return "AnonymousFunction";
        return "Function";
      }
      // Built-in types (e.g. String) or class instances
      return objectToString;
    };
    
    /**
     * Returns the name of a function.
     *
     * If the input is an anonymous function, returns "".
     * If the input is an arrow function, returns "=>".
     *
     * @param {Function} fn a function
     * @return {String} the name of the function
     * @throws {TypeError} if {@code fn} is not a function
     * @see getTypeName
     */
    function getFunctionName(fn)
    {
      try
      {
        const instanceToString = fn.toString();
        if (instanceToString.indexOf(" => ") != -1)
          return "=>";
        const getFunctionName = /^function ([^(]+)\(/;
        const match = instanceToString.match(getFunctionName);
        if (match === null)
        {
          const objectToString = Object.prototype.toString.call(fn).slice(8, -1);
          if (objectToString === "Function")
            return "";
          throw TypeError("object must be a Function.\n" +
            "Actual: " + getTypeName(fn));
        }
        return match[1];
      }
      catch (e)
      {
        throw TypeError("object must be a Function.\n" +
          "Actual: " + getTypeName(fn));
      }
    };
    
    /**
     * @param {Object} object an object
     * @return {String} the name of the object's class
     * @throws {TypeError} if {@code object} is not an Object
     * @see getTypeName
     */
    function getObjectClass(object)
    {
      const getFunctionName = /^function ([^(]+)\(/;
      const result = object.constructor.toString().match(getFunctionName)[1];
      if (result === "Function")
      {
        throw TypeError("object must be an Object.\n" +
          "Actual: " + getTypeName(object));
      }
      return result;
    };
    
    
    function UserFunction()
    {
    }
    
    function UserClass()
    {
    }
    
    let anonymousFunction = function()
    {
    };
    
    let arrowFunction = i => i + 1;
    
    console.log("getTypeName(undefined): " + getTypeName(undefined));
    console.log("getTypeName(null): " + getTypeName(null));
    console.log("getTypeName(true): " + getTypeName(true));
    console.log("getTypeName(5): " + getTypeName(5));
    console.log("getTypeName(\"text\"): " + getTypeName("text"));
    console.log("getTypeName(userFunction): " + getTypeName(UserFunction));
    console.log("getFunctionName(userFunction): " + getFunctionName(UserFunction));
    console.log("getTypeName(anonymousFunction): " + getTypeName(anonymousFunction));
    console.log("getFunctionName(anonymousFunction): " + getFunctionName(anonymousFunction));
    console.log("getTypeName(arrowFunction): " + getTypeName(arrowFunction));
    console.log("getFunctionName(arrowFunction): " + getFunctionName(arrowFunction));
    //console.log("getFunctionName(userClass): " + getFunctionName(new UserClass()));
    console.log("getTypeName(userClass): " + getTypeName(new UserClass()));
    console.log("getObjectClass(userClass): " + getObjectClass(new UserClass()));
    //console.log("getObjectClass(userFunction): " + getObjectClass(UserFunction));
    //console.log("getObjectClass(userFunction): " + getObjectClass(anonymousFunction));
    //console.log("getObjectClass(arrowFunction): " + getObjectClass(arrowFunction));
    console.log("getTypeName(nativeObject): " + getTypeName(navigator.mediaDevices.getUserMedia));
    console.log("getFunctionName(nativeObject): " + getFunctionName(navigator.mediaDevices.getUserMedia));

    We only use the constructor property when we have no other choice.

    0 讨论(0)
  • 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.

    0 讨论(0)
  • 2020-11-21 22:46

    Use class.name. This also works with function.name.

    class TestA {}
    console.log(TestA.name); // "TestA"
    
    function TestB() {}
    console.log(TestB.name); // "TestB"
    
    0 讨论(0)
  • 2020-11-21 22:47

    The kind() function from Agave.JS will return:

    • the closest prototype in the inheritance tree
    • for always-primitive types like 'null' and 'undefined', the primitive name.

    It works on all JS objects and primitives, regardless of how they were created, and doesn't have any surprises. Examples:

    Numbers

    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'
    

    Strings

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

    Booleans

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

    Arrays

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

    Objects

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

    Dates

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

    Functions

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

    undefined

    kind(undefined) === 'undefined'
    

    null

    kind(null) === 'null'
    
    0 讨论(0)
提交回复
热议问题