【问题标题】:How to get a JavaScript object's class?如何获取 JavaScript 对象的类?
【发布时间】:2010-11-17 23:36:56
【问题描述】:

我创建了一个 JavaScript 对象,但如何确定该对象的类?

我想要类似于 Java 的 .getClass() 方法的东西。

【问题讨论】:

  • 例如,我创建了一个这样的人: var p = new Person();我有一个名为“p”的人对象,如何使用“p”来取回类名:“Person”。
  • 更新:从 ECMAScript 6 开始,JavaScript 仍然没有 class 类型。它确实有一个class 关键字和class 语法来创建原型,其中方法可以更轻松地访问super
  • Object.className 怎么样?
  • @Paul-Basenko : "className" 不会告诉你对象的类,但会返回 HTML 元素的 "class" 属性的内容,它指的是 CSS 类。您还想使用“classList”轻松管理它们,但这与OP的问题无关。

标签: javascript oop


【解决方案1】:

在 JavaScript 中没有与 Java 的 getClass() 完全对应的东西。这主要是因为 JavaScript 是 prototype-based language,而 Java 是 class-based

根据您需要 getClass() 的用途,JavaScript 中有几个选项:

几个例子:

function Foo() {}
var foo = new Foo();

typeof Foo;             // == "function"
typeof foo;             // == "object"

foo instanceof Foo;     // == true
foo.constructor.name;   // == "Foo"
Foo.name                // == "Foo"    

Foo.prototype.isPrototypeOf(foo);   // == true

Foo.prototype.bar = function (x) {return x+x;};
foo.bar(21);            // == 42

注意:如果您使用 Uglify 编译代码,它将更改非全局类名。为了防止这种情况,Uglify 有一个 --mangle 参数,你可以设置为 false 使用 gulpgrunt

【讨论】:

  • 应该是func.prototype(是的,函数是对象,但prototype 属性只与函数对象相关)。
  • 您可能还想提及instanceof/isPrototypeOf() 和非标准的__proto__
  • ES5 还有 Object.getPrototypeOf()
  • 警告:如果您的代码正在缩小,请不要依赖 constructor.name。函数名会随意改变。
  • @igorsantos07,至少在 2019 年; “在线 javascript minifier”的前 5-10 个 google 结果将 construction.name 识别为要忽略/不最小化的令牌。此外,大多数(如果不是全部)缩小器软件都提供异常规则。
【解决方案2】:

Javascript 是一种无类语言:没有类可以像在 Java 中那样静态定义类的行为。 JavaScript 使用原型而不是类来定义对象属性,包括方法和继承。可以使用 JavaScript 中的原型来模拟许多基于类的功能。

【讨论】:

  • 更新:从 ECMAScript 6 开始,JavaScript 仍然没有 class 类型。它确实有一个class 关键字和class 语法来创建原型,其中方法可以更容易地访问super
【解决方案3】:

您可以使用constructor property获取对创建对象的构造函数的引用:

function MyObject(){
}

var obj = new MyObject();
obj.constructor; // MyObject

如果您需要在运行时确认对象的类型,您可以使用instanceof 运算符:

obj instanceof MyObject // true

【讨论】:

  • 不是返回构造函数本身吗,比如,你可以再次调用它并创建一个该类型的新对象?
  • @SparK 是的,尽管您仍然可以使用它进行比较,只要您在同一个 DOM 上(您正在比较函数对象)。然而,将构造函数转换为字符串并进行比较是更好的做法,特别是因为在使用 iframe 时它可以跨 DOM 边界工作。
  • 此答案返回“类”(或至少一个句柄可用于创建类实例的对象 - 与“类”相同)。以上回答了所有与“类对象”不同的返回字符串(原样)。
【解决方案4】:

在 javascript 中,没有类,但我认为您需要构造函数名称,obj.constructor.toString() 会告诉您您需要什么。

【讨论】:

  • 这会将构造函数的整个定义作为字符串返回。你真正想要的是.name
  • 但即使在 IE 9 上也没有定义 .name
【解决方案5】:

此 getNativeClass() 函数对于未定义的值返回 "undefined",对于空值返回 "null"
对于所有其他值,CLASSNAME 部分是从 [object CLASSNAME] 中提取的,这是使用 @ 的结果987654325@.

getAnyClass() 的行为与 getNativeClass() 相同,但也支持自定义构造函数

function getNativeClass(obj) {
  if (typeof obj === "undefined") return "undefined";
  if (obj === null) return "null";
  return Object.prototype.toString.call(obj).match(/^\[object\s(.*)\]$/)[1];
}

function getAnyClass(obj) {
  if (typeof obj === "undefined") return "undefined";
  if (obj === null) return "null";
  return obj.constructor.name;
}

getClass("")   === "String";
getClass(true) === "Boolean";
getClass(0)    === "Number";
getClass([])   === "Array";
getClass({})   === "Object";
getClass(null) === "null";

getAnyClass(new (function Foo(){})) === "Foo";
getAnyClass(new class Foo{}) === "Foo";

// etc...

【讨论】:

  • Object.prototype.getClass = function(){ 使用 'this' 而不是 obj 会很好
  • 当然 null 和 undefined 将是不可检查的,因为只有 Object 会有 getClass 方法
  • 这只适用于原生对象。如果你有某种继承,你将永远得到"Object"
  • 是的,函数的最后一行应该是return obj.constructor.name。这给出了相同的结果,而且还处理非本地对象。
【解决方案6】:
obj.constructor.name

在现代浏览器中是一种可靠的方法。 Function.name 被正式添加到 ES6 的标准中,使其成为一种以字符串形式获取 JavaScript 对象的“类”的符合标准的方法。如果对象是用var obj = new MyClass() 实例化的,它将返回“MyClass”。

它将返回数字的“Number”,数组的“Array”和函数的“Function”等。它通常按预期运行。唯一失败的情况是,如果通过Object.create( null ) 创建的对象没有原型,或者对象是从匿名定义(未命名)的函数中实例化的。

另请注意,如果您要缩小代码,则与硬编码的类型字符串进行比较是不安全的。例如,不检查是否为obj.constructor.name == "MyType",而是检查obj.constructor.name == MyType.name。或者只是比较构造函数本身,但这不会跨越 DOM 边界,因为每个 DOM 上有不同的构造函数实例,因此对它们的构造函数进行对象比较是行不通的。

【讨论】:

  • Function.name 还不是 JavaScript 标准的一部分。目前在 Chrome 和 Firefox 中支持,但在 IE(10) 中不支持。
  • Object.create(something).constructor === something.constructor,这也不太正确。所以 obj.constructor 对于所有用 Object.create 制作的对象都是不可靠的,不管有没有原型。
  • 警告:如果您的代码正在缩小,请不要依赖 constructor.name。函数名会随意改变。
  • Function.name 是 ES6 的一部分,参见 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
  • @adalbertpl 这与 ES6 之前的手动链接原型有关。很高兴知道 constructor.name 在 ES6 中的新类支持下的行为符合预期。
【解决方案7】:

要获取“伪类”,可以获取构造函数,通过

obj.constructor

假设 constructor 在您进行继承时设置正确 - 类似于:

Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;

这两行,连同:

var woofie = new Dog()

将使woofie.constructor 指向Dog。注意Dog 是一个构造函数,是一个Function 对象。但是你可以if (woofie.constructor === Dog) { ... }

如果您想将类名作为字符串获取,我发现以下方法效果很好:

http://blog.magnetiq.com/post/514962277/finding-out-class-names-of-javascript-objects

function getObjectClass(obj) {
    if (obj && obj.constructor && obj.constructor.toString) {
        var arr = obj.constructor.toString().match(
            /function\s*(\w+)/);

        if (arr && arr.length == 2) {
            return arr[1];
        }
    }

    return undefined;
}

它获取构造函数,将其转换为字符串,并提取构造函数的名称。

请注意,obj.constructor.name 本来可以很好地工作,但它不是标准的。它在 Chrome 和 Firefox 上,但不在 IE 上,包括 IE 9 或 IE 10 RTM。

【讨论】:

  • woofie 获得积分。
【解决方案8】:

我在 IE 中找到 object.constructor.toString() 返回 [object objectClass],而不是在 chome 中返回 function objectClass () {}。因此,我认为http://blog.magnetiq.com/post/514962277/finding-out-class-names-of-javascript-objects 中的代码在 IE 中可能无法正常运行。我将代码修复如下:

代码:

var getObjectClass = function (obj) {
        if (obj && obj.constructor && obj.constructor.toString()) {
            
                /*
                 *  for browsers which have name property in the constructor
                 *  of the object,such as chrome 
                 */
                if(obj.constructor.name) {
                    return obj.constructor.name;
                }
                var str = obj.constructor.toString();
                /*
                 * executed if the return of object.constructor.toString() is 
                 * "[object objectClass]"
                 */
                 
                if(str.charAt(0) == '[')
                {
                        var arr = str.match(/\[\w+\s*(\w+)\]/);
                } else {
                        /*
                         * executed if the return of object.constructor.toString() is 
                         * "function objectClass () {}"
                         * for IE Firefox
                         */
                        var arr = str.match(/function\s*(\w+)/);
                }
                if (arr && arr.length == 2) {
                            return arr[1];
                        }
          }
          return undefined; 
    };
    

【讨论】:

    【解决方案9】:

    同意dfa,这就是为什么我在找不到命名类时将原型视为类

    这是 Eli Grey 发布的功能的升级功能,以符合我的想法

    function what(obj){
        if(typeof(obj)==="undefined")return "undefined";
        if(obj===null)return "Null";
        var res = Object.prototype.toString.call(obj).match(/^\[object\s(.*)\]$/)[1];
        if(res==="Object"){
            res = obj.constructor.name;
            if(typeof(res)!='string' || res.length==0){
                if(obj instanceof jQuery)return "jQuery";// jQuery build stranges Objects
                if(obj instanceof Array)return "Array";// Array prototype is very sneaky
                return "Object";
            }
        }
        return res;
    }
    

    【讨论】:

      【解决方案10】:

      这是getClass()getInstance() 的实现

      您可以使用this.constructor 获取对象类的引用。

      从实例上下文:

      function A() {
        this.getClass = function() {
          return this.constructor;
        }
      
        this.getNewInstance = function() {
          return new this.constructor;
        }
      }
      
      var a = new A();
      console.log(a.getClass());  //  function A { // etc... }
      
      // you can even:
      var b = new (a.getClass());
      console.log(b instanceof A); // true
      var c = a.getNewInstance();
      console.log(c instanceof A); // true
      

      来自静态上下文:

      function A() {};
      
      A.getClass = function() {
        return this;
      }
      
      A.getInstance() {
        return new this;
      }
      

      【讨论】:

      • 为什么不只是this.constructor
      • 我不知道,但如果它更好,你肯定可以编辑答案以改进它,因为你发现更好,毕竟这是一个社区。​​span>
      【解决方案11】:

      对于 ES6 中的 Javascript 类,您可以使用 object.constructor。在下面的示例类中,getClass() 方法如您所愿返回 ES6 类:

      var Cat = class {
      
          meow() {
      
              console.log("meow!");
      
          }
      
          getClass() {
      
              return this.constructor;
      
          }
      
      }
      
      var fluffy = new Cat();
      
      ...
      
      var AlsoCat = fluffy.getClass();
      var ruffles = new AlsoCat();
      
      ruffles.meow();    // "meow!"
      

      如果您从 getClass 方法实例化该类,请确保将其包裹在括号中,例如ruffles = new ( fluffy.getClass() )( args... );

      【讨论】:

        【解决方案12】:

        为了保持其向后兼容的完整记录,ECMAScript 6,JavaScript 仍然没有class 类型(尽管不是每个人都理解这一点)。它确实有一个 class 关键字作为其用于创建原型的 class 语法的一部分,但 仍然没有称为类的东西。 JavaScript 现在不是,并且从来都不是经典的 OOP 语言。从类的角度谈 JS 要么是误导,要么是尚未理解原型继承的标志(只是保持真实)。

        这意味着this.constructor 仍然是获取constructor 函数引用的好方法。而this.constructor.prototype 是访问原型本身的方式。因为这不是 Java,所以它不是一个类。它是您的实例被实例化的原型对象。下面是一个使用 ES6 语法糖创建原型链的示例:

        class Foo {
          get foo () {
            console.info(this.constructor, this.constructor.name)
            return 'foo'
          }
        }
        
        class Bar extends Foo {
          get foo () {
            console.info('[THIS]', this.constructor, this.constructor.name, Object.getOwnPropertyNames(this.constructor.prototype))
            console.info('[SUPER]', super.constructor, super.constructor.name, Object.getOwnPropertyNames(super.constructor.prototype))
        
            return `${super.foo} + bar`
          }
        }
        
        const bar = new Bar()
        console.dir(bar.foo)
        

        这是使用babel-node 输出的内容:

        > $ babel-node ./foo.js                                                                                                                   ⬡ 6.2.0 [±master ●]
        [THIS] [Function: Bar] 'Bar' [ 'constructor', 'foo' ]
        [SUPER] [Function: Foo] 'Foo' [ 'constructor', 'foo' ]
        [Function: Bar] 'Bar'
        'foo + bar'
        

        你有它!在 2016 年,JavaScript 中有一个 class 关键字,但仍然没有类类型。 this.constructor 是获取构造函数的最佳方式,this.constructor.prototype 是获取原型本身的最佳方式。

        【讨论】:

          【解决方案13】:

          问题似乎已经得到解答,但 OP 想要访问对象的类和对象,就像我们在 Java 中所做的那样,选择的答案还不够(恕我直言)。

          通过下面的解释,我们可以得到一个对象的一个​​类(在javascript中实际上叫做prototype)。

          var arr = new Array('red', 'green', 'blue');
          var arr2 = new Array('white', 'black', 'orange');
          

          你可以像这样添加一个属性:

          Object.defineProperty(arr,'last', {
            get: function(){
              return this[this.length -1];
            }
          });
          console.log(arr.last) // blue
          

          .last 属性仅可用于从 Array 原型实例化的“arr”对象。因此,为了让所有从 Array 原型实例化的对象都可以使用 .last 属性,我们必须为 Array 原型定义 .last 属性:

          Object.defineProperty(Array.prototype,'last', {
            get: function(){
              return this[this.length -1];
            }
          });
          console.log(arr.last) // blue
          console.log(arr2.last) // orange
          

          这里的问题是,你必须知道'arr'和'arr2'变量属于哪个对象类型(原型)!换句话说,如果您不知道“arr”对象的类类型(原型),那么您将无法为它们定义属性。在上面的示例中,我们知道 arr 是 Array 对象的实例,这就是我们使用 Array.prototype 为 Array 定义属性的原因。但是如果我们不知道 'arr' 的类(原型)怎么办?

          Object.defineProperty(arr.__proto__,'last2', {
            get: function(){
              return this[this.length -1];
            }
          });
          console.log(arr.last) // blue
          console.log(arr2.last) // orange
          

          如您所见,在不知道 'arr' 是一个数组的情况下,我们可以通过使用 'arr.__proto__' 来添加一个新属性,仅引用 'arr' 的类。

          我们在不知道它是 Array 实例的情况下访问了“arr”的原型,我认为这就是 OP 所要求的。

          【讨论】:

          • __proto__ 属性已被弃用,与prototype 属性相比几乎没有优势。
          【解决方案14】:

          我现在有一种情况可以通用并使用它:

          class Test {
            // your class definition
          }
          
          nameByType = function(type){
            return type.prototype["constructor"]["name"];
          };
          
          console.log(nameByType(Test));
          

          如果您没有对象的实例,这是我发现通过类型输入获取类名的唯一方法。

          (用 ES2017 编写)

          点符号也可以正常工作

          console.log(Test.prototype.constructor.name); // returns "Test" 
          

          【讨论】:

          • 啊,这就是我要找的。如果它没有被实例化,你必须使用'prototype'来获取类名。非常感谢!
          【解决方案15】:

          我建议使用Object.prototype.constructor.name:

          Object.defineProperty(Object.prototype, "getClass", {
              value: function() {
                return this.constructor.name;
              }
          });
          
          var x = new DOMParser();
          console.log(x.getClass()); // `DOMParser'
          
          var y = new Error("");
          console.log(y.getClass()); // `Error'
          

          【讨论】:

            【解决方案16】:

            你也可以这样做

             class Hello {
                 constructor(){
                 }
                }
                
                  function isClass (func) {
                    return typeof func === 'function' && /^class\s/.test(Function.prototype.toString.call(func))
                }
                
               console.log(isClass(Hello))

            这会告诉你输入是否是类

            【讨论】:

              【解决方案17】:

              如果您不仅需要 GET 类,还需要 EXTEND 从只有一个实例,请编写:

              让我们来

               class A{ 
                 constructor(name){ 
                   this.name = name
                 }
               };
              
               const a1 = new A('hello a1');
              

              所以要扩展仅具有实例的 A 使用:

              const a2 = new (Object.getPrototypeOf(a1)).constructor('hello from a2')
              // the analog of const a2 = new A()
              
              console.log(a2.name)//'hello from a2'
              

              【讨论】:

                【解决方案18】:

                还有另一种技术可以识别您的班级 您可以将 ref 存储到您的类中,如下所示。

                class MyClass {
                    static myStaticProperty = 'default';
                    constructor() {
                        this.__class__ = new.target;
                        this.showStaticProperty = function() {
                            console.log(this.__class__.myStaticProperty);
                        }
                    }
                }
                
                class MyChildClass extends MyClass {
                    static myStaticProperty = 'custom';
                }
                
                let myClass = new MyClass();
                let child = new MyChildClass();
                
                myClass.showStaticProperty(); // default
                child.showStaticProperty(); // custom
                
                myClass.__class__ === MyClass; // true
                child.__class__ === MyClass; // false
                child.__class__ === MyChildClass; // true
                

                【讨论】:

                  【解决方案19】:

                  我们可以通过像本例中那样执行“instance.constructor.name”来读取类的实例名称:

                  class Person {
                    type = "developer";
                  }
                  let p = new Person();
                  
                  p.constructor.name // Person
                  

                  【讨论】:

                    【解决方案20】:

                    getClass() 函数使用 constructor.prototype.name

                    我找到了一种访问class 的方法,它比上面的一些解决方案更干净;在这里。

                    function getClass(obj) {
                    
                       // if the type is not an object return the type
                       if((let type = typeof obj) !== 'object') return type; 
                        
                       //otherwise, access the class using obj.constructor.name
                       else return obj.constructor.name;   
                    }
                    

                    工作原理

                    构造函数有一个名为name 的属性,它会为您提供类名。

                    更简洁的代码版本:

                    function getClass(obj) {
                    
                       // if the type is not an object return the type
                       let type = typeof obj
                       if((type !== 'object')) { 
                          return type; 
                       } else { //otherwise, access the class using obj.constructor.name
                          return obj.constructor.name; 
                       }   
                    }
                    

                    【讨论】:

                    • 来自上面的评论:“警告:如果您的代码正在被缩小,请不要依赖 constructor.name。函数名称将任意更改。”
                    猜你喜欢
                    • 2010-11-17
                    • 1970-01-01
                    • 1970-01-01
                    • 2014-01-07
                    相关资源
                    最近更新 更多