获取对象类型的名称

IT技术 javascript
2021-01-24 06:25:18

是否有一个JavaScript的等效的Javaclass.getName()

6个回答

是否有相当于 Java 的 JavaScript class.getName()

没有

ES2015 更新名称class Foo {}Foo.name. thing无论thing的类型如何, 的类的名称都是thing.constructor.nameES2015 环境中的内置构造函数具有正确的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物业...

每个object都有其constructor属性的值,但取决于它的object构造方式以及您想用该值做什么,它可能有用也可能没用。

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

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

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

注意事项

将无法正常工作在所有在许多情况下,

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

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

Objects构造 vianew Thingy将有一个constructor属性指向Object,而不是Thingy所以我们一开始就摔倒了;您根本无法信任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财产还有其他用途,其中一些很有趣,另一些则没有那么多;现在我们不会深入研究这些用途,因为它与本次讨论无关。

不能跨框架和跨窗口工作

.constructor当您想要检查来自不同window对象的对象类型时,例如 iframe 或弹出窗口的类型,使用for 类型检查将中断这是因为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

文字需要包裹在 anObject中才能instanceof工作,例如

new Number(3) instanceof Number // true

.constructor检查适用于文字,因为.方法调用隐式地将文字包装在它们各自的对象类型中

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

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

不能跨框架和跨窗口工作

instanceof也不会跨不同窗口工作,原因与constructor属性检查相同


使用name物业的constructor财产...

不工作在所有在许多情况下,

再次,见上文;constructor完全错误和无用的情况是很常见的

在 <IE9 中不起作用

UsingmyObjectInstance.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);
}

删除 cruft 并获得类型名称

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操作符的讨论似乎是一个明显的遗漏,但它在帮助确定 a 是否object是给定类型方面确实没有用,因为它非常简单。了解哪里typeof有用很重要,但我目前认为它与本次讨论没有太大关系。不过,我愿意改变。:)

请务必注意,如果您的 Javascript 已使用 uglify 或 Rails 资产管道之类的工具缩小,则任何检查对象constructor方法(使用.toString().name)的技术都将无法工作。缩小会重命名构造函数,因此您最终会得到不正确的类名,例如n. 如果您处于这种情况下,您可能只想手动定义className对象属性并改用它。
2021-03-14 06:25:18
好吧,我想我也可以 - Stack Overflow 的重点是有点像 wiki,我认为这更符合这一意图。无论如何,我只是想说的彻底一些。
2021-04-06 06:25:18

Jason Bunting 的回答给了我足够的线索来找到我需要的东西:

<<Object instance>>.constructor.name

因此,例如,在以下代码段中:

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

myInstance.constructor.name会回来"MyObject"

为了完整起见,可能值得一提的是,使用 constructor.name 仅在您使用命名函数作为构造函数而不是分配给变量的匿名函数时才有效。
2021-03-26 06:25:18
为了完整起见,值得一提的是它在 IE 浏览器中不起作用——它们不支持函数的“名称”属性。
2021-04-08 06:25:18

我使用的一个小技巧:

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

var MySquare = new Square();
console.log(MySquare.className); // "Square"
@pimvdb:我认为这比修改对象的原型更清晰,这是公认的答案。
2021-03-14 06:25:18
@DanielSzabo 如果一个属性在原型的所有实例之间应该具有相同的值,我绝对更喜欢将它放在原型上——将它放在每个实例上是超级冗余的,并且原型本身缺少元数据。也就是说,在 ES6 中采用了最明智的解决方案:如果有class Square,则名称是Square.name/MySquare.constructor.name而不是Square.prototype.name; 通过放置name构造函数,它不会污染原型或任何实例,但可以从中访问。
2021-03-20 06:25:18
我不是特别喜欢这个。这更像是一种肮脏的把戏。另一方面,如果你没有太多的构造函数,它可能工作得很好。
2021-03-22 06:25:18

更新

准确地说,我认为 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"

 


注意:以下示例已弃用。

一个博客帖子的链接基督教Sciberras包含有关如何做一个很好的例子。即,通过扩展 Object 原型:

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
您不需要使用正则表达式来解析对象名称。只需使用.slice()Object.prototype.toString.call(obj).slice( 8, -1 );
2021-04-08 06:25:18