是否有 Java 的
class.getName()
的 JavaScript 等价物?
不 。
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()
函数,该函数将构造函数的名称作为字符串返回。我在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() {
}
};
通过new Thingy
构造的Objects
将具有指向Object
的constructor
属性,而不是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
属性还有其他用途,其中一些是有趣的,另一些则不是很多; 目前我们不会深入研究这些用途,因为它与此讨论无关。
不会跨框架和跨窗口工作
当您想要检查来自不同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
例如,文字需要包装在Object
中,以便instanceof
工作
new Number(3) instanceof Number // true
.constructor
检查适用于文字,因为.
方法调用隐式地将文字包装在它们各自的对象类型中
3..constructor === Number // true
'abc'.constructor === String // true
true.constructor === Boolean // true
为什么两个点为 3?因为 Javascript 将第一个点解释为小数点;)
instanceof
也不会在不同的窗口中工作,原因与constructor
属性检查相同。
constructor
属性的name
属性... 再次,见上文; constructor
完全错误和无用是很常见的。
使用myObjectInstance.constructor.name
将为您提供一个字符串,其中包含所使用的constructor
函数的名称,但需要遵守前面提到的constructor
属性的警告。
对于 IE9 及更高版本,您可以支持 Monkey-patch :
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
- 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
运营商可能似乎是一个明显的遗漏,但它确实是不是在帮助识别是否有用的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"