如何在JavaScript中获取对象types的名称?
有没有Java的class.getName()
的JavaScript等价物?
有没有Java的
class.getName()
的JavaScript等价物?
没有 。
ES2015更新 : class Foo {}
的名称是Foo.name
。 无论thing
的types如何, thing
类的名字都是thing.constructor.name
。 ES2015环境中的内build构造函数具有正确的name
属性; 例如(2).constructor.name
是"Number"
。
但是,这里有各种各样的黑客以各种方式倒下:
这里有一个黑客会做你所需要的 – 要知道,它修改了对象的原型,人们皱眉(通常是出于很好的理由)
Object.prototype.getName = function() { var funcNameRegex = /function (.{1,})\(/; var results = (funcNameRegex).exec((this).constructor.toString()); return (results && results.length > 1) ? results[1] : ""; };
现在,所有的对象都会有函数getName()
,它将以string的forms返回构造函数的名字。 我已经在FF3
和IE7
testing过了,我不能说其他的实现。
如果你不想这样做,下面是关于在JavaScript中确定types的各种方法的讨论…
我最近更新了这个更详尽一点,虽然它几乎没有。 更正欢迎…
使用constructor
属性…
每个object
都有其constructor
属性的值,但取决于该object
构造方式以及要使用该值执行的操作,可能有用也可能无用。
一般来说,您可以使用constructor
属性来testing对象的types,如下所示:
var myArray = [1,2,3]; (myArray.constructor == Array); // true
所以,对于大多数需求来说,这样做足够好。 那说…
注意事项
在许多情况下都不能工作
这种模式虽然被打破,但却是相当普遍的:
function Thingy() { } Thingy.prototype = { method1: function() { }, method2: function() { } };
通过new Thingy
构造的Objects
将具有指向Object
的constructor
属性,而不是Thingy
。 所以我们一开始就落伍了。 你不能信任你不能控制的代码库中的constructor
。
多重inheritance
一个不太明显的例子是使用多重inheritance:
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
所以,如果你的testingobject
有一个不同的object
集作为它的prototype
,你可能会得到意想不到的结果。 这个讨论的范围之外有办法。
还有其他用途的constructor
属性,其中有些是有趣的,其他不是很多; 现在我们不会深入研究这些用途,因为它与这个讨论无关。
不会跨越框架和跨窗口工作
当你想检查来自不同window
对象的对象的types时,使用.constructor
进行types检查将会中断,比如iframe或popup窗口。 这是因为每个`window'中的每个核心typesconstructor
都有不同的版本,
iframe.contentWindow.Array === Array // false
使用instanceof
操作符…
instanceof
运算符也是testingobject
types的一种干净的方式,但是它有自己的潜在问题,就像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
检查工作正常的文字,因为.
方法调用隐式地将文字包装在它们各自的对象types中
3..constructor === Number // true 'abc'.constructor === String // true true.constructor === Boolean // true
为什么两个点为3? 因为Javascript将第一个点解释为小数点;)
不会跨越框架和跨窗口工作
instanceof
也不会在不同的窗口中工作,出于与constructor
属性检查相同的原因。
使用constructor
属性的name
属性…
在许多情况下都不起作用
再次,见上面; constructor
完全错误和无用是很常见的。
在<IE9中不起作用
使用myObjectInstance.constructor.name
将为您提供一个string,其中包含所使用的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
事实certificate,作为这篇文章的细节 ,您可以使用Object.prototype.toString
( toString
的低级别和通用实现)来获取所有内置types的types
Object.prototype.toString.call('abc') // [object String] Object.prototype.toString.call(/abc/) // [object RegExp] Object.prototype.toString.call([1,2,3]) // [object Array]
人们可以写一个简短的帮助function,如
function type(obj){ return Object.prototype.toString.call(obj).slice(8, -1); }
删除cruft和得到只是types的名称
type('abc') // String
但是,它将为所有用户定义的types返回Object
。
所有的注意事项…
所有这些都有一个潜在的问题,那就是这个问题是如何构build的。 以下是构build对象的各种方法以及types检查的不同方法将返回的值:
// 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
虽然并不是所有的排列都出现在这个例子中,但是希望能给你一个关于如何根据你的需要得到混乱的东西的想法。 不要假设任何事情,如果你不能完全理解你以后的事情,你最终可能会因为缺乏对细节的不满而不期望的代码破解。
注意:
对操作符types的讨论似乎是一个明显的漏掉,但是在帮助识别一个object
是否是给定types方面是没有用的,因为它非常简单。 了解typeof
的用处很重要,但是我目前并不觉得这与这个讨论非常相关。 尽pipe我的想法可以改变。 🙂
杰森·邦廷的回答给了我足够的线索,find我所需要的:
<<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
没有一个types,但本身就是一种types。 但是,不同的对象可以有不同的构造函数 。
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连接的博客文章包含了一个很好的例子。 也就是说,通过扩展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
这是我提出的一个解决scheme,它解决了instanceof的缺点。 它可以从跨窗口和跨框架检查对象的types,并且不存在原始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需要两个参数:一个对象和一个types。 它如何工作的真正诀窍是它检查对象是否来自同一个窗口,如果没有获取对象的窗口。
例子:
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参数也可以是一个返回构造函数的callback函数。 callback函数将接收一个参数,它是提供的对象的窗口。
例子:
//"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不提供所有对象的构造函数,所以上面的NodeListtesting将返回false,并且isInstance(alert,“Function”)将返回false。
您可以使用instanceof
运算符来查看对象是否是另一个对象的实例,但由于没有类,因此无法获取类名称。
使用Object.prototype.toString
事实certificate,作为这篇文章的细节,您可以使用Object.prototype.toString(toString的低级别和通用实现)来获取所有内置types的types
Object.prototype.toString.call('abc') // [object String] Object.prototype.toString.call(/abc/) // [object RegExp] Object.prototype.toString.call([1,2,3]) // [object Array]
人们可以写一个简短的帮助function,如
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
Agave.JS的kind()函数将返回:
- inheritance树中最接近的原型
- 对于总是原始types,如“null”和“undefined”,原始名称。
它适用于所有JS对象和原语, 而不pipe它们是如何创build的 ,并且没有任何意外。 例子:
数字
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'
string
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'
date
kind(new Date()) === 'Date'
function
kind(function(){}) === 'Function' kind(new Function("console.log(arguments)")) === 'Function' kind(Math.sin) === 'Function'
未定义
kind(undefined) === 'undefined'
空值
kind(null) === 'null'
可以的时候使用constructor.name
,当我不能的时候使用regex函数。
Function.prototype.getName = function(){ if (typeof this.name != 'undefined') return this.name; else return /function (.+)\(/.exec(this.toString())[1]; };
我其实是在寻找类似的东西,并且遇到了这个问题。 这里是我如何获得types: 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); }
您可以使用“instanceof”运算符来确定对象是否是某个类的实例。 如果您不知道对象types的名称,则可以使用其构造函数属性。 对象的构造函数属性是对用于初始化它们的函数的引用。 例:
function Circle (x,y,radius) { this._x = x; this._y = y; this._radius = raduius; } var c1 = new Circle(10,20,5);
现在c1.constructor是对Circle()
函数的引用。 您可以使用typeof
运算符,但typeof
运算符显示有限的信息。 一个解决scheme是使用Object全局对象的toString()
方法。 例如,如果有一个对象,比如说myObject,则可以使用全局对象的toString()
方法来确定myObject类的types。 用这个:
Object.prototype.toString.apply(myObject);
你可以得到最接近的是typeof
,但它只返回任何types的自定义types的“对象”。 对于这些,请参阅杰森·邦廷 。
编辑,贾森删除他的职位出于某种原因,所以只需使用对象的constructor
属性。
这是一个基于接受的答案的实现 :
/** * 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 (eg 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));
如果有人正在寻找一个与jQuery合作的解决scheme,这里是调整后的wiki代码(原始的jQuery)。
Object.defineProperty(Object.prototype, "getClassName", { value: function() { var funcNameRegex = /function (.{1,})\(/; var results = (funcNameRegex).exec((this).constructor.toString()); return (results && results.length > 1) ? results[1] : ""; } });
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; } });
它增加了一个叫做“识别”的方法,其工作原理如下:
console.log(_.identify('hello friend')); // isString
Plunker: http ://plnkr.co/edit/Zdr0KDtQt76Ul3KTEDSN
好吧,我一直在慢慢build立一个所有的方法这几年哈哈! 诀窍是:
- 有一个创build类的机制。
- 有一个机制来检查所有用户创build的类,由原生构造函数创build/生成的基元和值。
- 有一个机制来将用户创build的类扩展为新的类,以便上述function渗透到代码/应用程序/库/等等中。
举一个例子(或者看看我是如何处理这个问题的),请看github上的以下代码: https : //github.com/elycruz/sjljs/blob/master/src/sjl/sjl.js并search:
classOf =
, classOfIs =
和/或defineSubClass =
(没有反引号(`))。
正如你所看到的,我有一些机制强制classOf
总是给我类/构造函数的types名称,无论它是基元,用户定义的类,使用本地构造函数创build的值,Null,NaN等等。 。对于每个单独的javascript值,我将从classOf
函数中获取它的唯一types名称。 另外,我可以将实际的构造函数传入sjl.classOfIs
中,除了可以传入types名称之外,还可以检查值的types。 举个例子:
“//请原谅长的命名空间! 我不知道这些影响,直到使用它们一段时间(他们吸haha)
var SomeCustomClass = sjl.package.stdlib.Extendable.extend({ constructor: function SomeCustomClass () {}, // ... }), HelloIterator = sjl.ns.stdlib.Iterator.extend( function HelloIterator () {}, { /* ... methods here ... */ }, { /* ... static props/methods here ... */ } ), helloIt = new HelloIterator(); sjl.classOfIs(new SomeCustomClass(), SomeCustomClass) === true; // `true` sjl.classOfIs(helloIt, HelloIterator) === true; // `true` var someString = 'helloworld'; sjl.classOfIs(someString, String) === true; // `true` sjl.classOfIs(99, Number) === true; // true sjl.classOf(NaN) === 'NaN'; // true sjl.classOf(new Map()) === 'Map'; sjl.classOf(new Set()) === 'Set'; sjl.classOfIs([1, 2, 4], Array) === true; // `true` // etc.. // Also optionally the type you want to check against could be the type's name sjl.classOfIs(['a', 'b', 'c'], 'Array') === true; // `true`! sjl.classOfIs(helloIt, 'HelloIterator') === true; // `true`!
“`
如果你有兴趣阅读更多关于如何使用上面提到的安装程序,请查看repo: https : //github.com/elycruz/sjljs
还有关于这个主题的内容的书籍: – 斯托扬·斯特凡诺夫的“JavaScript模式”。 – “Javascript – 权威指南” 由大卫弗拉纳根。 – 和其他许多..(searchnetworking)。
您也可以快速testing我在这里讨论的function: – http://sjljs.elycruz.com/0.5.18/tests/for-browser/ (同时在url中的0.5.18path有来自github在那里减去node_modules等)。
快乐编码!
说你有var obj;
如果你只是想要obj的types的名称,如“对象”,“数组”或“string”,你可以使用这个:
Object.prototype.toString.call(obj).split(' ')[1].replace(']', '');