web-dev-qa-db-fra.com

Comment obtenir le nom de l'objet de classe sous forme de chaîne en Javascript?

Disons que j'instancie un objet en Javascript comme ceci:

var myObj = new someObject();

Maintenant, est-il possible d'obtenir le nom de l'objet var en tant que chaîne 'myObj' à partir de l'une des méthodes de classe?


Détails supplémentaires (édités):

La raison pour laquelle je voudrais obtenir le nom de la variable contenant la référence à l'objet est que ma nouvelle myObj créerait une nouvelle DIV cliquable sur la page qui devrait appeler une fonction myObj.someFunction(). Lorsque j'insère la nouvelle DIV, j'ai besoin de connaître le nom de la variable contenant la référence à l'objet. Y a-t-il peut-être une meilleure façon de faire cela?


Vous avez raison, désolé pour la confusion dans la terminologie.

La raison pour laquelle je voudrais obtenir le nom de la variable contenant la référence à l'objet est que mon nouveau myObj créerait un nouveau DIV cliquable sur la page qui aurait besoin d'appeler une fonction myObj.someFunction (). Lorsque j'insère le nouveau DIV, j'ai besoin de connaître le nom de la variable contenant la référence à l'objet. Y a-t-il peut-être une meilleure façon de faire cela?

40
Miro Solanka

Shog9 a raison de dire que cela n'a pas beaucoup de sens de demander, puisqu'un objet peut être référé par plusieurs variables. Si vous ne vous en souciez pas vraiment et si vous souhaitez simplement trouver le nom d'une des variables globales qui fait référence à cet objet, vous pouvez procéder comme suit:

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"

Notez que ceci est un bidouillage laid, et ne devrait pas être utilisé dans le code de production. S'il y a plus d'une variable faisant référence à un objet, vous ne pouvez pas dire laquelle vous obtiendrez. Il ne cherchera que les variables globales, donc cela ne fonctionnera pas si une variable est locale à une fonction. En général, si vous devez nommer quelque chose, vous devez le transmettre au constructeur lorsque vous le créez.

edit : Pour répondre à votre clarification, si vous devez pouvoir faire référence à quelque chose provenant d'un gestionnaire d'événements, vous ne devriez pas y faire référence par nom, mais plutôt ajouter une fonction qui fait directement référence à l'objet. Voici un exemple rapide que j'ai préparé qui montre quelque chose de similaire à ce que vous essayez de faire:

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()
}
43
Brian Campbell

Réponse courte: Non. MyObj n'est pas le nom de l'objet, mais le nom d'une variable contenant une référence à l'objet. Vous pouvez avoir un nombre quelconque de variables contenant une référence au même objet.

Maintenant, si c'est votre programme, alors vous établissez les règles: si vous voulez dire qu'un objet donné ne sera référencé que par une variable, et l'appliquera avec diligence dans votre code, définissez simplement une propriété sur l'objet avec le paramètre nom de la variable. 

Cela dit, je doute que ce que vous demandez, c’est ce que vous voulez vraiment. Peut-être décrire votre problème un peu plus en détail ...?


Pedantry: JavaScript n'a pas de classes. someObject est une fonction constructeur. Étant donné une référence à un objet, vous pouvez obtenir une référence à la fonction qui l’a créé à l’aide de la propriété constructeur .


En réponse aux détails supplémentaires que vous avez fournis:

La réponse à votre question se trouve ici: Étendue de rappel JavaScript (et en réponse à de nombreuses autres questions sur SO - il s'agit d'un point de confusion courant pour les débutants en JS). Vous devez simplement encapsuler l'appel au membre de l'objet dans une fermeture préservant l'accès à l'objet de contexte.

19
Shog9

Vous pouvez le faire en convertissant le constructeur en chaîne en utilisant .toString () :

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

Vous pourrez peut-être atteindre votre objectif en l'utilisant dans une fonction, puis en examinant le source de la fonction avec 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';
4
Vidar S. Ramdal

En tant que situation plus élémentaire, cela serait Nice si this avait une propriété pouvant référencer sa variable de référence (heads ou tails), mais malheureusement, elle ne fait référence qu'à l'instanciation du nouvel objet 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()])

qui affiche toujours

[object Object]

et le moteur Gecko de Firefox montre:

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

Bien sûr, dans cet exemple, pour résoudre #1, et donc toss, il est assez simple de tester toss==heads et toss==tails. Cette question, qui demande réellement si javascript a un mécanisme call-by-name, motive la prise en compte de la contrepartie. Existe-t-il un mécanisme call-by-value pour déterminer la valeur ACTUAL d'une variable? L'exemple montre que les "valeurs" de heads et tails sont identiques, mais que alert(heads==tails) est false.

L'auto-référence peut être contrainte comme suit:
(éviter la chasse à l’espace objet et les ambiguïtés possibles comme indiqué dans Comment obtenir le nom de l’objet de la classe sous forme de chaîne en Javascript? solution)

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);

pour afficher heads ou tails.

C’est peut-être un anathème à l’essence de la conception du langage Javascript, en tant que langage fonctionnel de prototypage interprété, d’avoir des capacités telles que les primitives.

Une dernière considération:

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

alors, comme stipulé ...

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);

Y a-t-il un meilleur moyen ...?

"mieux" comme dans plus facile? Plus facile à programmer? Plus facile à comprendre? Plus facile que dans une exécution plus rapide? Ou est-ce comme dans "... et maintenant pour quelque chose de complètement différent"?

2
Ekim

Si vous ne voulez pas utiliser un constructeur de fonction comme dans la réponse de Brian, vous pouvez utiliser Object.create () à la place: -

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

Étrangement, je ne pouvais pas obtenir ce qui précède avec newDiv.onClick, mais cela fonctionne avec newDiv.addEventListener/newDiv.attachEvent.

Puisque Object.create est nouveau, incluez le code suivant de Douglas Crockford pour les navigateurs plus anciens, y compris IE8.

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

Immédiatement après que l'objet soit instancié, vous pouvez attacher une propriété, disons name, à l'objet et lui affecter la valeur de chaîne que vous attendez:

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

document.write(myObj.name);

En variante, l’affectation peut être effectuée à l’intérieur des codes de la classe, c.-à-d.

var someClass = function(P)
{ this.name=P;
  // rest of the class definition...
};

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

Il y a quelque temps, j'ai utilisé cela. 

Peut-être pourriez-vous essayer:

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

Pop an Alert : "I get_this_name".

0
funnynico

C'est assez vieux, mais j'ai rencontré cette question via Google, alors peut-être que cette solution pourrait être utile à d'autres.

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

Il utilise simplement l'analyseur JSON et les expressions régulières du navigateur, sans trop encombrer le DOM ou votre objet.

0
longestwayround