【问题标题】:How to get class object's name as a string in Javascript?如何在Javascript中将类对象的名称作为字符串获取?
【发布时间】:2009-04-25 20:31:09
【问题描述】:

假设我像这样在 Javascript 中实例化一个对象:

var myObj = new someObject();

现在,是否可以从其中一个类方法中以字符串 'myObj' 的形式获取 var 对象的名称?


其他细节(已编辑):

我想获取持有对象引用的变量名称的原因是我的新myObj 将在需要调用函数myObj.someFunction() 的页面上创建一个新的可点击DIV。当我插入新的DIV 时,我需要知道持有对该对象的引用的变量的名称。有没有更好的方法来做到这一点?


你是对的,抱歉术语混淆了。

我想获取持有对象引用的变量名称的原因是我的新 myObj 将在需要调用函数 myObj.someFunction() 的页面上创建一个新的可点击 DIV。当我插入新的 DIV 时,我需要知道持有对该对象的引用的变量的名称。有没有更好的方法来做到这一点?

【问题讨论】:

  • Shog9 是正确的 - 你为什么要这样做?可能有更好的方法来实现您想要做的事情
  • 一些相关的功能请求:Suggestion to add nameof() to TypeScript compiler。如果这真的成功了,你可以做nameof(myObj) // returns the string "myObj"

标签: javascript class


【解决方案1】:

Shog9 是对的,因为一个对象可以被多个变量引用,所以问这个问题并没有多大意义。如果您并不真正关心这一点,而您只想找到引用该对象的全局变量之一的名称,则可以执行以下 hack:

function myClass() { 
  this.myName = function () { 
    // search through the global object for a name that resolves to this object
    for (var name in this.global) 
      if (this.global[name] == this) 
        return name 
  } 
}
// store the global object, which can be referred to as this at the top level, in a
// property on our prototype, so we can refer to it in our object's methods
myClass.prototype.global = this
// create a global variable referring to an object
var myVar = new myClass()
myVar.myName() // returns "myVar"

请注意,这是一个丑陋的 hack,不应在生产代码中使用。如果有多个变量引用一个对象,您将无法确定您将获得哪一个。它只会搜索全局变量,因此如果变量是函数的本地变量,它将不起作用。一般来说,如果你需要命名一些东西,你应该在创建它时将名称传递给构造函数。

编辑:为了回应您的说明,如果您需要能够从事件处理程序中引用某些内容,您不应该通过名称来引用它,而是添加一个函数直接指对象。这是我快速创建的一个简单示例,我认为它与您正在尝试做的事情类似:

function myConstructor () {
  this.count = 0
  this.clickme = function () {
    this.count += 1
    alert(this.count)
  }

  var newDiv = document.createElement("div")
  var contents = document.createTextNode("Click me!")

  // This is the crucial part. We don't construct an onclick handler by creating a
  // string, but instead we pass in a function that does what we want. In order to
  // refer to the object, we can't use this directly (since that will refer to the 
  // div when running event handler), but we create an anonymous function with an 
  // argument and pass this in as that argument.
  newDiv.onclick = (function (obj) { 
    return function () {
      obj.clickme()
    }
  })(this)

  newDiv.appendChild(contents)
  document.getElementById("frobnozzle").appendChild(newDiv)

}
window.onload = function () {
  var myVar = new myConstructor()
}

【讨论】:

  • 将变量的名称传递给构造函数是我迄今为止一直在做的事情,但我想知道是否有不同的方法可以实现同样的事情。
  • 布赖恩,感谢额外的 cmets。正如您在修订后的答案中指出的那样,我最终动态分配了 onclick 处理程序,而不是将其作为字符串传递给 div 的 onclick 属性。
【解决方案2】:

简答:不。myObj 不是对象的名称,它是持有对对象的引用的变量的名称 - 您可以拥有任意数量的其他变量持有对对象的引用同一个对象。

现在,如果它是你的程序,那么你制定规则:如果你想说任何给定的对象永远只能被一个变量引用,并且在你的代码中努力执行它,那么只需在带有变量名称的对象。

也就是说,我怀疑你所要求的实际上是你真正想要的。也许更详细地描述您的问题...?


Pedantry: JavaScript 没有类。 someObject 是一个构造函数。给定一个对象的引用,您可以使用constructor property 获得对创建它的函数的引用。


针对您提供的其他详细信息:

您正在寻找的答案可以在这里找到:JavaScript Callback Scope(以及对许多其他关于 SO 的问题的回应——对于那些刚接触 JS 的人来说,这是一个常见的混淆点)。您只需将对对象成员的调用包装在一个闭包中,该闭包保留对上下文对象的访问。

【讨论】:

  • 不是迂腐,这是理解的关键。
【解决方案3】:

您可以使用 .toString() 将构造函数转换为字符串:

function getObjectClass(obj){
   if (typeof obj != "object" || obj === null) return false;
   else return /(\w+)\(/.exec(obj.constructor.toString())[1];}

【讨论】:

  • 我相信 OP 是在询问变量的名称,而不是构造函数的名称。
  • 还有:obj.constructor.name
【解决方案4】:

您可以通过在函数中使用它来实现您的目标,然后使用toString() 检查函数的源代码:

var whatsMyName;

  // Just do something with the whatsMyName variable, no matter what
function func() {var v = whatsMyName;}

// Now that we're using whatsMyName in a function, we could get the source code of the function as a string:
var source = func.toString();

// Then extract the variable name from the function source:
var result = /var v = (.[^;]*)/.exec(source);

alert(result[1]); // Should alert 'whatsMyName';

【讨论】:

    【解决方案5】:

    如果您不想像 Brian 的回答那样使用函数构造函数,您可以改用 Object.create():-

    var myVar = {
    count: 0
    }
    
    myVar.init = function(n) {
        this.count = n
        this.newDiv()
    }
    
    myVar.newDiv = function() {
        var newDiv = document.createElement("div")
        var contents = document.createTextNode("Click me!")
        var func = myVar.func(this)
        newDiv.addEventListener ? 
            newDiv.addEventListener('click', func, false) : 
            newDiv.attachEvent('onclick', func)
        newDiv.appendChild(contents)
        document.getElementsByTagName("body")[0].appendChild(newDiv)
    }
    
    myVar.func = function (thys) {
       return function() {
          thys.clickme()
       }
    } 
    
    myVar.clickme = function () {
       this.count += 1
       alert(this.count)
    }
    
    myVar.init(2)
    
    var myVar1 = Object.create(myVar)
    myVar1.init(55) 
    
    var myVar2 = Object.create(myVar)
    myVar2.init(150) 
    
    // etc
    

    奇怪的是,我无法使用 newDiv.onClick 实现上述操作,但它可以与 newDiv.addEventListener / newDiv.attachEvent 一起使用。

    由于 Object.create 是新的,请包含来自 Douglas Crockford 的以下代码,用于旧版浏览器,包括 IE8。

    if (typeof Object.create !== 'function') {
        Object.create = function (o) {
            function F() {}
            F.prototype = o
            return new F()
        }
    }
    

    【讨论】:

      【解决方案6】:

      作为一个更基本的情况,如果this 有一个可以引用它的引用变量(headstails)的属性会很好,但不幸的是它只引用了新的coinSide 对象的实例化。

      javascript:  /* it would be nice but ... a solution NOT! */
      function coinSide(){this.ref=this};
      /* can .ref be set so as to identify it's referring variable? (heads or tails) */
      heads = new coinSide();
      tails = new coinSide();
      toss = Math.random()<0.5 ? heads : tails;
      alert(toss.ref);
      alert(["FF's Gecko engine shows:\n\ntoss.toSource()  is  ", toss.toSource()])
      

      总是显示

      [object Object]
      

      和 Firefox 的 Gecko 引擎显示:

      toss.toSource()  is  ,#1={ref:#1#}
      

      当然,在本例中,要解析#1toss,测试toss==headstoss==tails 很简单。这个问题实际上是在询问 javascript 是否具有 call-by-name 机制,引发了对对应方的考虑,是否有 call-by-value 机制来确定变量的 ACTUAL 值?该示例演示了headstails 的“值”是相同的,而alert(heads==tails)false

      自引用可以被强制如下:
      (避免How to get class object's name as a string in Javascript? 解决方案中提到的对象空间搜索和可能的歧义)

      javascript:
      function assign(n,v){ eval( n +"="+ v ); eval( n +".ref='"+ n +"'" ) }
      function coinSide(){};
      assign("heads", "new coinSide()");
      assign("tails", "new coinSide()");
      toss = Math.random()<0.5 ? heads : tails;
      alert(toss.ref);
      

      显示headstails

      作为一种解释型原型功能语言,拥有原语等功能,这可能是对 Javascript 语言设计精髓的一种厌恶。

      最后的考虑:

       javascript:
           item=new Object(); refName="item"; deferAgain="refName";
           alert([deferAgain,eval(deferAgain),eval(eval(deferAgain))].join('\n'));
      

      所以,按照规定……

      javascript:
        function bindDIV(objName){ 
          return eval( objName +'=new someObject("'+objName+'")' )
        };
        function someObject(objName){
          this.div="\n<DIV onclick='window.opener."+   /* window.opener - hiccup!! */
                     objName+
                   ".someFunction()'>clickable DIV</DIV>\n";
          this.someFunction=function(){alert(['my variable object name is ',objName])}
        };
        with(window.open('','test').document){         /*     see above hiccup    */
          write('<html>'+
            bindDIV('DIVobj1').div+
            bindDIV('DIV2').div+
            (alias=bindDIV('multiply')).div+
            'an aliased DIV clone'+multiply.div+
            '</html>');
          close();
        };
        void (0);
      

      有没有更好的方法...?

      “更好”更容易?更容易编程?更容易理解?更容易执行更快?还是像“...现在完全不同的东西”一样?

      【讨论】:

      • ... 'an aliased DIV clone'+multiply.div+ ...... 'an aliased DIV clone'+alias.div+ ... 都生成相同的 HTML 源,但后者不在上述示例中。
      • 无论如何,在 FF 中,可以通过“拖放”到 URL 地址栏来执行示例:突出显示示例代码,将其拖到地址栏,放下它,然后激活 URI (按 Enter 或单击 GO 或 ...)。必须允许创建一个弹出窗口作为生成的html 源的目标。
      • 评论“作为一种解释型原型功能语言,拥有像原语这样的能力可能是对 Javascript 语言设计本质的一种诅咒。”从eval 原语确实存在这一事实可以看出,这有点(很多?)滑稽地不协调! (并且,归功于 FireFox 的 Gecko 引擎,eval 的异常强大的逆函数 .toSource()!)
      【解决方案7】:

      在对象被实例化后,您可以立即为对象附加一个属性,例如 name,并为其分配您期望的字符串值:

      var myObj = new someClass();
      myObj.name="myObj";
      
      document.write(myObj.name);
      

      或者,可以在类的代码中进行分配,即

      var someClass = function(P)
      { this.name=P;
        // rest of the class definition...
      };
      
      var myObj = new someClass("myObj");
      document.write(myObj.name);
      

      【讨论】:

        【解决方案8】:

        前段时间,我用过这个。

        也许你可以试试:

        +function(){
            var my_var = function get_this_name(){
                alert("I " + this.init());
            };
            my_var.prototype.init = function(){
                return my_var.name;
            }
            new my_var();
        }();
        

        弹出警报"I get_this_name"

        【讨论】:

          【解决方案9】:

          这已经很老了,但我通过谷歌遇到了这个问题,所以这个解决方案可能对其他人有用。

          function GetObjectName(myObject){
              var objectName=JSON.stringify(myObject).match(/"(.*?)"/)[1];
              return objectName;
          }
          

          它只使用浏览器的 JSON 解析器和正则表达式,而不会过多地弄乱 DOM 或您的对象。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-11-22
            • 2011-08-04
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-06-04
            • 2022-11-19
            相关资源
            最近更新 更多