Как получить имя объекта класса в виде строки в Javascript? - PullRequest
40 голосов
/ 26 апреля 2009

Допустим, я создаю экземпляр объекта в Javascript следующим образом:

var myObj = new someObject();

Теперь можно ли получить имя объекта var в виде строки 'myObj' из одного из методов класса?


Дополнительные сведения (отредактировано):

Причина, по которой я хотел бы получить имя переменной, содержащей ссылку на объект, заключается в том, что мой новый myObj создал бы новый кликабельный DIV на странице, который должен был бы вызвать функцию myObj.someFunction(). Когда я вставляю новый DIV, мне нужно знать имя переменной, содержащей ссылку на объект. Может быть, есть лучший способ сделать это?


Вы правы, извините за путаницу в терминологии.

Причина, по которой я хотел бы получить имя переменной, содержащей ссылку на объект, заключается в том, что мой новый myObj создал бы новый интерактивный DIV на странице, который должен был бы вызвать функцию myObj.someFunction (). Когда я вставляю новый DIV, мне нужно знать имя переменной, содержащей ссылку на объект. Может быть, есть лучший способ сделать это?

Ответы [ 9 ]

43 голосов
/ 26 апреля 2009

Shog9 прав в том, что спрашивать не имеет особого смысла, так как на объект могут ссылаться несколько переменных. Если вас это не волнует, и все, что вам нужно, - это найти имя одной из глобальных переменных, которая ссылается на этот объект, вы можете сделать следующее:

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"

Обратите внимание, что это уродливый хак, и его не следует использовать в рабочем коде. Если существует несколько переменных, ссылающихся на объект, вы не можете сказать, какую из них вы получите. Он будет искать только глобальные переменные, поэтому он не будет работать, если переменная является локальной для функции. В общем, если вам нужно что-то назвать, вы должны передать имя конструктору при его создании.

edit : Чтобы ответить на ваше разъяснение, если вам нужно иметь возможность ссылаться на что-то из обработчика событий, вам не следует ссылаться на него по имени, вместо этого добавьте функцию, которая ссылается на к объекту напрямую. Вот краткий пример, который я привел, который показывает нечто похожее на то, что вы пытаетесь сделать:

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()
}
19 голосов
/ 26 апреля 2009

Краткий ответ: Нет. MyObj - это не имя объекта, это имя переменной, содержащей ссылку на объект - у вас может быть любое количество других переменных, содержащих ссылку на тот же объект.

Теперь, если это ваша программа, тогда вы устанавливаете правила: если вы хотите сказать, что на любой данный объект будет ссылаться только одна переменная, когда-либо, и усердно применять это в своем коде, то просто установите свойство в объект с именем переменной.

Тем не менее, я сомневаюсь, что то, что вы просите, на самом деле то, что вы действительно хотите. Может быть, опишите вашу проблему немного подробнее ...?


Pedantry: JavaScript не имеет классов. someObject является функцией конструктора. Имея ссылку на объект, вы можете получить ссылку на функцию, которая его создала, используя свойство конструктора .


В ответ на предоставленные вами дополнительные сведения:

Ответ, который вы ищете, можно найти здесь: Область обратного вызова JavaScript (и в ответ на многочисленные другие вопросы по SO - это обычная путаница для новичков в JS). Вам просто нужно обернуть вызов члена объекта в замыкание, которое сохраняет доступ к объекту контекста.

11 голосов
/ 26 апреля 2009

Вы можете сделать это с помощью конструктора в строку, используя .toString () :

function getObjectClass(obj){
   if (typeof obj != "object" || obj === null) return false;
   else return /(\w+)\(/.exec(obj.constructor.toString())[1];}
4 голосов
/ 19 января 2010

Вы можете достичь своей цели, используя ее в функции, а затем исследуя источник функции с помощью 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';
2 голосов
/ 18 марта 2013

Сразу после того, как объект инстанцируется, вы можете прикрепить свойство, скажем, 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);
2 голосов
/ 11 июля 2011

Если вы не хотите использовать конструктор функции, как в ответе Брайана, вы можете использовать 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()
    }
}
2 голосов
/ 13 мая 2011

В качестве более элементарной ситуации было бы неплохо, если бы this имел свойство, которое могло ссылаться на ссылающуюся переменную (heads или tails), но, к сожалению, оно ссылается только на создание экземпляра нового объекта 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#}

Конечно, в этом примере для разрешения #1 и, следовательно, toss достаточно просто протестировать toss==heads и toss==tails. Этот вопрос, который действительно задает, имеет ли javascript механизм call-by-name, мотивирует рассмотрение аналога, существует ли механизм call-by-value для определения фактического значения переменной? Пример демонстрирует, что «значения» как heads, так и tails идентичны, но alert(heads==tails) равно false.

Самостоятельная ссылка может быть приведена следующим образом:
(избегая поиска пространства объектов и возможных неоднозначностей, как отмечено в Как получить имя объекта класса в виде строки в 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);

для отображения heads или tails.

Возможно, это анафема сущности языкового дизайна 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);

Есть ли лучший способ ...?

"лучше" как по проще? Проще программировать? Легче понять? Проще как в быстром исполнении? Или это как в " ... а теперь что-то совершенно другое "?

0 голосов
/ 24 ноября 2014

Это довольно старый, но я столкнулся с этим вопросом через Google, так что, возможно, это решение может быть полезным для других.

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

Он просто использует JSON-анализатор и регулярные выражения браузера, не перегружая DOM или ваш объект.

0 голосов
/ 22 января 2014

Некоторое время назад я использовал это.

Возможно, вы могли бы попробовать:

+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".

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...