当前位置:  开发笔记 > 编程语言 > 正文

获取对象类型的名称

如何解决《获取对象类型的名称》经验,为你挑选了10个好方法。

是否有Java的JavaScript等价物class.getName()



1> Jason Buntin..:

是否有Java的JavaScript等价物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财产......

每个object都有它的constructor属性值,但是根据它的object构造方式以及你想用这个值做什么,它可能有用也可能没用.

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

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

因此,这对大多数需求都足够好.那说......

注意事项

在许多情况下无法全部工作

这种模式虽然破碎,却很常见:

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

Objects通过构建new 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或弹出式窗口.这是因为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财产检查相同的原因,也不会在不同的窗口工作.


使用name酒店的constructor财产......

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

再次,见上文; 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

事实证明,正如这篇帖子的详细信息,您可以使用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有用很重要,但我目前不认为它与这个讨论非常相关.我的思想可以改变.:)


嗯,我想我也可能 - Stack Overflow的观点有点像维基,我认为这更符合这个意图.无论如何,我只是想要有点彻底.
重要的是要注意任何检查对象的`constructor`方法(使用`.toString()`或`.name`)的技术如果使用像uglify或Rails资产这样的工具缩小Javascript,将无法工作管道.缩小重命名构造函数,因此最终会出现不正确的类名,如`n`.如果您在这种情况下,您可能只想手动**在对象上定义`className`属性并使用它.
现在,这就是StackOverflow上大多数答案的方式.(不要把答案的长度作为定义参数,但是要全面)
如果你像这个函数那样工作a(){this.a = 1;} function b(){this.b = 2; b.prototype = new a(); // b继承自b.prototype.constructor = b; //正确的原型继承方式var f = new b(); //使用b构造函数创建新对象(f.constructor == b); // TRUE(f.constructor == a); // FALSE

2> Ewen Cartwri..:

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

<>.constructor.name


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

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

myInstance.constructor.name会回来的"MyObject".


为了完整起见,值得一提的是,使用constructor.name只有在使用命名函数作为构造函数而不是分配给变量的匿名函数时才有效.
为了完整起见,值得一提的是它在IE浏览器中不起作用 - 它们不支持函数的"name"属性.
@Eugene - 我忘记了......我想我花了太多时间在浏览器之外做javascript.
`function getType(o){return o && o.constructor && o.constructor.name}`

3> Daniel Szabo..:

我用的一个小技巧:

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

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


@pimvdb:我认为它比修改对象的原型更清晰,这是接受的答案.
我不是特别喜欢这个.这更像是一种肮脏的伎俩.另一方面,如果你没有太多的构造函数,它可能会工作得很好.
@DanielSzabo如果一个属性在原型的所有实例之间应该具有相同的值,我肯定更喜欢将它放在原型上 - 将它放在每个实例上是超冗余的,并且原型本身缺少元数据.也就是说,ES6采用了最明智的解决方案:如果你有`class Square`,那么名称是`Square.name` /`MySquare.constructor.name`而不是`Square.prototype.name`; 通过在构造函数上放置`name`,它不会污染原型或任何实例,但可以从任何一个实例访问.

4> Saul..:

更新

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


很好,但我们再次命名:JS没有类.
@Matt - 当然.只是拥有一个对象方法更简洁:`test.getClassName()`vs`getClassName.apply(test)`.

5> Gaurav Raman..:

使用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);`

6> 小智..:

这是我提出的一个解决方案,它解决了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.



7> Mahdi..:

我实际上是在寻找类似的东西并遇到了这个问题.以下是我如何获得类型: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);
}



8> defrex..:

尽可能使用constructor.name,当我不能使用时使用正则表达式.

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



9> mikemaccana..:

Agave.JS的kind()函数将返回:

继承树中最接近的原型

对于始终原始类型,如'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'

为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'

空值

kind(null) === 'null'



10> Greg..:

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


@greg当然可是`instanceof`只检查一个对象是否继承自另一个对象.例如,一个简单的`[]`继承自Array,但Array也继承自Object.由于大多数对象具有多个级别的继承,因此找到**最接近的原型**是一种更好的技术.请参阅我的答案.
推荐阅读
吻过彩虹的脸_378
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有