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


当前回答

您可以使用instanceof操作符来查看一个对象是否是另一个对象的实例,但由于没有类,因此无法获得类名。

其他回答

Lodash有很多isMethods,所以如果你在使用Lodash,可能像这样的mixin会很有用:

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

它为lodash添加了一个名为“identify”的方法,其工作原理如下:

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

砰砰作响: http://plnkr.co/edit/Zdr0KDtQt76Ul3KTEDSN

我用了一个小技巧:

function Square(){
    this.className = "Square";
    this.corners = 4;
}

var MySquare = new Square();
console.log(MySquare.className); // "Square"

您可以使用“instanceof”操作符来确定一个对象是否是某个类的实例。如果不知道对象类型的名称,可以使用它的构造函数属性。对象的构造函数属性是对用于初始化对象的函数的引用。例子:

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

现在c1。构造函数是Circle()函数的引用。 也可以使用typeof操作符,但typeof操作符显示的信息有限。一种解决方案是使用Object全局对象的toString()方法。例如,如果你有一个对象,比如myObject,你可以使用全局对象的toString()方法来确定myObject类的类型。用这个:

Object.prototype.toString.apply(myObject);

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'

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

No.

ES2015更新:类Foo{}的名字是Foo.name。对象的类名,不管它的类型是什么,都是thing。constructor。name。ES2015环境中的内置构造函数具有正确的name属性;例如(2).constructor.name为“Number”。


但这里有各种各样的技巧,都以这样或那样的方式失败了:

这里有一个hack,可以做你所需要的-注意它修改对象的原型,这是人们不喜欢的(通常有很好的理由)

Object.prototype.getName = function() { 
   var funcNameRegex = /function (.{1,})\(/;
   var results = (funcNameRegex).exec((this).constructor.toString());
   return (results && results.length > 1) ? results[1] : "";
};

现在,所有对象都将具有getName()函数,该函数将以字符串形式返回构造函数的名称。我已经在FF3和IE7中测试了这个功能,我不能说其他的实现。

如果你不想这样做,这里有一个关于JavaScript中确定类型的各种方法的讨论……


我最近更新了这篇文章,使之更加详尽,尽管它还远远不够。修正欢迎…

使用构造函数属性…

每个对象的构造函数属性都有一个值,但它可能有用,也可能没用,这取决于该对象是如何构造的,以及您想对该值做什么。

一般来说,你可以使用constructor属性来测试对象的类型,如下所示:

var myArray = [1,2,3];
(myArray.constructor == Array); // true

所以,这足以满足大多数需求。也就是说……

警告

在很多情况下根本不起作用

这种模式虽然被打破了,但很常见:

function Thingy() {
}
Thingy.prototype = {
    method1: function() {
    },
    method2: function() {
    }
};

通过new Thingy构造的对象将有一个指向Object的构造函数属性,而不是指向Thingy。所以我们从一开始就堕落了;您根本不能信任您无法控制的代码库中的构造函数。

多重继承

一个不那么明显的例子是使用多重继承:

function a() { this.foo = 1;}
function b() { this.bar = 2; }
b.prototype = new a(); // b inherits from a

现在的事情并不像你想象的那样:

var f = new b(); // instantiate a new object with the b constructor
(f.constructor == b); // false
(f.constructor == a); // true

因此,如果您测试的对象有一个不同的对象集作为原型,您可能会得到意想不到的结果。在本文讨论的范围之外,还有一些方法可以解决这个问题。

构造函数属性还有其他用途,其中一些很有趣,另一些就不那么重要了;现在我们将不深入研究这些用途,因为它与本文的讨论无关。

将不会工作交叉框架和交叉窗口

当你想检查来自不同窗口对象(比如iframe或弹出窗口)的对象类型时,使用.constructor进行类型检查将会失效。这是因为在每个“窗口”中,每个核心类型构造函数都有不同的版本。

iframe.contentWindow.Array === Array // false

使用instanceof操作符…

instanceof操作符也是一种简洁的测试对象类型的方法,但它也有自己的潜在问题,就像构造函数属性一样。

var myArray = [1,2,3];
(myArray instanceof Array); // true
(myArray instanceof Object); // true

但是instanceof对文字值不起作用(因为文字不是对象)

3 instanceof Number // false
'abc' instanceof String // false
true instanceof Boolean // false

例如,为了使instanceof工作,字面量需要包装在Object中

new Number(3) instanceof Number // true

.constructor检查可以很好地检查字面量,因为。方法调用隐式地将字面量包装在各自的对象类型中

3..constructor === Number // true
'abc'.constructor === String // true
true.constructor === Boolean // true

为什么3是两个点?因为Javascript将第一个点解释为小数点;)

将不会工作交叉框架和交叉窗口

Instanceof也不能跨不同的窗口工作,原因与构造函数属性检查相同。


使用构造函数属性的name属性…

在许多情况下根本不工作

再次,见上文;构造函数完全错误和无用是很常见的。

不工作在<IE9

使用myObjectInstance.constructor.name将为您提供一个包含所使用的构造函数名称的字符串,但要遵守前面提到的关于构造函数属性的警告。

对于IE9及以上版本,你可以通过猴子补丁来支持:

if (Function.prototype.name === undefined && Object.defineProperty !== undefined) {
    Object.defineProperty(Function.prototype, 'name', {
        get: function() {
            var funcNameRegex = /function\s+([^\s(]+)\s*\(/;
            var results = (funcNameRegex).exec((this).toString());
            return (results && results.length > 1) ? results[1] : "";
        },
        set: function(value) {}
    });
}

文章的更新版本。这是在文章发表3个月后添加的,这是文章作者Matthew Scharley推荐使用的版本。这一更改的灵感来自于指出先前代码中潜在缺陷的注释。

if (Function.prototype.name === undefined && Object.defineProperty !== undefined) {
    Object.defineProperty(Function.prototype, 'name', {
        get: function() {
            var funcNameRegex = /function\s([^(]{1,})\(/;
            var results = (funcNameRegex).exec((this).toString());
            return (results && results.length > 1) ? results[1].trim() : "";
        },
        set: function(value) {}
    });
}

使用Object.prototype.toString

正如这篇文章所详述的那样,你可以使用Object.prototype.toString——toString的低级通用实现——来获取所有内置类型的类型

Object.prototype.toString.call('abc') // [object String]
Object.prototype.toString.call(/abc/) // [object RegExp]
Object.prototype.toString.call([1,2,3]) // [object Array]

可以编写一个简短的辅助函数,例如

function type(obj){
    return Object.prototype.toString.call(obj).slice(8, -1);
}

来删除杂项,只得到类型名

type('abc') // String

但是,对于所有用户定义的类型,它将返回Object。


警告所有人…

所有这些都受制于一个潜在的问题,那就是问题中的物体是如何构造的。下面是构建对象的各种方法,以及不同类型检查方法将返回的值:

// using a named function:
function Foo() { this.a = 1; }
var obj = new Foo();
(obj instanceof Object);          // true
(obj instanceof Foo);             // true
(obj.constructor == Foo);         // true
(obj.constructor.name == "Foo");  // true

// let's add some prototypical inheritance
function Bar() { this.b = 2; }
Foo.prototype = new Bar();
obj = new Foo();
(obj instanceof Object);          // true
(obj instanceof Foo);             // true
(obj.constructor == Foo);         // false
(obj.constructor.name == "Foo");  // false


// using an anonymous function:
obj = new (function() { this.a = 1; })();
(obj instanceof Object);              // true
(obj.constructor == obj.constructor); // true
(obj.constructor.name == "");         // true


// using an anonymous function assigned to a variable
var Foo = function() { this.a = 1; };
obj = new Foo();
(obj instanceof Object);      // true
(obj instanceof Foo);         // true
(obj.constructor == Foo);     // true
(obj.constructor.name == ""); // true


// using object literal syntax
obj = { foo : 1 };
(obj instanceof Object);            // true
(obj.constructor == Object);        // true
(obj.constructor.name == "Object"); // true

虽然在这组示例中并不是所有的排列都有,但希望这些排列足以让您了解根据您的需要,事情可能会变得多么混乱。不要做任何假设,如果你不能确切地理解你想要的是什么,你可能会在你意想不到的地方导致代码崩溃,因为你没有发现其中的微妙之处。

注意:

对typeof操作符的讨论似乎是一个明显的遗漏,但它在帮助确定对象是否为给定类型方面确实没有用处,因为它非常简单。理解typeof在什么地方有用是很重要的,但我目前不觉得它与这个讨论有多大关系。不过,我的思想是开放的。:)