获取对象类型的名称

有 JavaScript 相当于 Java 的class.getName()吗?

答案

有 JavaScript 相当于 Java 的class.getName()吗?

不行

ES2015 更新class Foo {}的名称为Foo.name 。名称thing的类,不管thing的类型,是thing.constructor.name 。 ES2015 环境中的内置构造函数具有正确的name属性;例如(2).constructor.name"Number"


但是,这里有各种各样的骇客,它们都以一种或另一种方式下降:

这是一种可以满足您需要的技巧 - 请注意,它会修改 Object 的原型,而人们对此并不满意(通常是出于充分的理由)

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

现在,所有对象都将具有getName()函数,该函数将以字符串形式返回构造函数的名称。我已经在FF3IE7对此进行了测试,我不能说其他实现。

如果您不想这样做,这里将讨论确定 JavaScript 中类型的各种方法...


我最近将其更新为更加详尽,尽管并非如此。欢迎更正...

使用constructor属性...

每个objectconstructor属性都有一个值,但是取决于该object构造方式以及您要对该值进行的操作,它可能有用也可能没有用。

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

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

因此,这足以满足大多数需求。那个...

注意事项

会不会在很多情况下, 在所有的工作

这种模式虽然很复杂,但却很常见:

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

通过new Thingy构造的Objects将具有指向Object而不是Thingyconstructor属性。因此,我们一开始就陷入困境;您根本无法信任您无法控制的代码库中的constructor

多重继承

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

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

所以,你可能会得到意想不到的结果,如果object您的测试有不同的object设置为其prototype 。在此讨论范围之外,还有其他解决方法。

constructor属性还有其他用途,其中一些很有趣,而其他则不是很多。目前我们不会深入研究这些用途,因为它与本次讨论无关。

无法跨框架和跨窗口工作

当您要检查来自不同window对象(例如 iframe 或弹出窗口)的对象的类型时,使用.constructor进行类型检查会中断。这是因为每个 “窗口” 中每个核心类型constructor都有不同的版本,即

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

使用instanceof运算子...

instanceof运算符也是一种测试object类型的干净方法,但是与constructor属性一样,它也有其自身的潜在问题。

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

但是instanceof不能用于文字值(因为文字不是Objects

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 将第一个点解释为小数点;)

无法跨框架和跨窗口工作

出于与constructor属性检查相同的原因, instanceof也无法在不同的窗口中运行。


使用constructor属性的name属性...

没有在很多情况下, 在所有的工作

同样,见上文; constructor完全完全错误且无用的情况非常普遍。

在 < IE9 中不起作用

使用myObjectInstance.constructor.name将为您提供一个字符串,其中包含所使用的constructor函数的名称,但是要遵守前面提到的有关constructor属性的注意事项。

对于 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运算符的讨论似乎是一个明显的遗漏,但由于它非常简单,因此在帮助识别object是否为给定类型方面确实没有用。了解typeof在哪里有用很重要,但是我目前不认为它与本次讨论非常相关。我的想法是开放的。 :)

杰森邦廷(Jason Bunting)的答案给了我足够的线索来找到我需要的东西:

<<Object instance>>.constructor.name

因此,例如,在下面的代码中:

function MyObject() {}
var myInstance = new MyObject();

myInstance.constructor.name将返回"MyObject"

我使用的一些小技巧:

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

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

更新资料

确切地说,我认为 OP 要求一个函数来检索特定对象的构造函数名称。在 Javascript 方面, object没有一个类型,但是是一个类型的和本身 。但是,不同的对象可以具有不同的构造函数

Object.prototype.getConstructorName = function () {
   var str = (this.prototype ? this.prototype.constructor : this.constructor).toString();
   var cname = str.match(/function\s(\w*)/)[1];
   var aliases = ["", "anonymous", "Anonymous"];
   return aliases.indexOf(cname) > -1 ? "Function" : cname;
}

new Array().getConstructorName();  // returns "Array"
(function () {})().getConstructorName(); // returns "Function"


注意:以下示例已弃用。

Christian Sciberras链接的博客文章中有一个很好的例子。即,通过扩展对象原型:

if (!Object.prototype.getClassName) {
    Object.prototype.getClassName = function () {
        return Object.prototype.toString.call(this).match(/^\[object\s(.*)\]$/)[1];
    }
}

var test = [1,2,3,4,5];

alert(test.getClassName()); // returns Array

使用 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]).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

这是我想出的解决方案,它解决了 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。

我实际上正在寻找类似的东西,并遇到了这个问题。这是我获取类型的方法: 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);
}

如果可以的话,使用constructor.name函数名。当我不能的时候,使用正则表达式函数。

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

Agave.JSkind()函数将返回:

  • 继承树中最接近的原型
  • 对于总是原始类型(例如 “null” 和 “undefined”)的原始名称。

无论它们如何创建 ,它都适用于所有 JS 对象和基元,并且没有任何惊喜。例子:

号码

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

N

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'

空值

kind(null) === 'null'

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