JavaScript反射:如何获取变量的名称?

5

我有几个变量被分配给相同的函数。由于此函数是匿名的,属性'name'为空字符串;

同时没有涉及到函数调用,因此也没有被调用者。

在JS中是否有一种通过自己实现的反射算法来获取变量名称的方法?

例如:

var x = function(){}
var myUnknownNamedVar1 = myUnknownNamedVar2 = x;

背景:

为了节省空间,数千个变量名被分配给同一个“静态”函数作为懒加载的树桩,这些树桩在首次调用时解析为各个函数。(变量名还包含命名空间)。

替代方案:

我提出的替代方案是使用对象,例如{_name:myUnknownNamedVar1,_fn:x}

解决此问题将会很有趣。一个特别的问题是区分脚本中指向同一对象的不同名称的变量。


我不确定你在问什么。您想查找指向 x 的变量的字符串名称吗? - Dave Newton
fnmap.remoteNotYetMappedFunc(1,2,3,4)
  1. 将参数存储在队列中
  2. 加载远程信息并创建一个独立的函数,然后重新分配给fnmap.remoteNotYetMappedFunc
- Lorenz Lo Sauer
如果你的问题是能否获取指向对象的变量名称,答案是否定的。如果你的情况不同(例如,你可以遍历命名空间并检查引用),那么可能是有可能的,但我没有理解你的任何解释。 - davin
请告诉我是否我正确理解了你的问题。我已经发布了一个答案。 - vol7ron
5个回答

10

可以使用对象反射来实现,例如:

const getVarName = obj => Object.keys(obj)[0];
const varToGetTheNameOf = "Value!";
getVarName({ varToGetTheNameOf }) // => "varToGetTheNameOf"

3

没有。不存在。

简单地说(强调了帖子中的要点),变量(或属性)不是值/对象,而是值/对象的“名称”。同一个对象可以有多个名称。

想象一下这个例子,并考虑它如何映射到给人们起的“名称”上:

var fred = function Fred () {}
fred.name // "Fred"

// An unknown number of nicknames can exist...
var francisco = fred
var frankyTheFiveFingers = fred
someOtherRegion.theGoodPerson = fred

// But sometimes nicknames are known; note that this is
// a locatable (e.g. "known") iterable set.
// (While properties can be iterated, variables cannot.
//  However, iterating *every* object is not feasible, hence
//  it must be a locatable set.)
fred.nicknames = ["Freddy", "FD"]

mary.nicknamesFor(fred) // who knows :-)     

愉快的编码。


非常可行,例如通过代码塑形/反射。一些简单的诡计会很不错。我将采用个别调用委托闭包,并承担轻微的加载时间和内存开销。顺便说一句,谢谢。 - Lorenz Lo Sauer

2

1. 您可以尝试解析脚本文本。

JSFiddle示例

var x = function(){}
var myUnknownNamedVar1 = myUnknownNamedVar2 = x;

var txt  = (document.currentScript && document.currentScript.textContent) ||
           (document.scripts       && document.scripts[1]
                                   && document.scripts[1].textContent);
var arr  = txt.match(/var\s*(.*)\s*=\s*x\b/);
arr[1]   = arr[1].replace(/\s+$/,"");
var vars = arr[1].split(/\s*=\s*/);

// vars: ["myUnknownNamedVar1", "myUnknownNamedVar2"]

2. 您可以尝试比较数值

JSFiddle示例

var x = function(){}
var myUnknownNamedVar1 = myUnknownNamedVar2 = x;

var vars = [];
for (var prop in window){
    if (window[prop] == x)
      vars.push(prop);
}

// vars: ["x", "myUnknownNamedVar1", "myUnknownNamedVar2"]

注意:这两种方法都需要进一步完善(例如递归、更好/更多的匹配模式)。第二种方法只查看全局变量,而闭包中的某些变量可能不会暴露给全局命名空间。此外,还有对象的对象。

一个有创意的解决方案,尽管不是非常健壮。首先它只匹配 var 和已定义的变量。所以如果我做了 var a; 然后稍后进行赋值,它就不会捕捉到它。也不会捕捉到其他赋值方法,比如返回值,或者简单的 a=x;b=a; 等等。此外,它太贪心了,因为有 .* 所以匹配的内容比应该匹配的多得多。它也很容易被字符串字面量欺骗。正则表达式绝对不足以解析语言,更不用说分析它了。 - davin
一个“反射”解决方案。干得好!(PS:currentScript是非标准/Gecko引擎)。你能让它跨浏览器兼容吗?我会采纳你的答案。 - Lorenz Lo Sauer
@davin:你的所有观点都是正确的。正如我所说,需要一些递归以及更多的模式匹配。但是考虑到OP的示例,它可以工作。如果他没有告诉/展示我语法(特别是如果他使用了框架),我就不可能神奇地知道。在上面的答案中,“.*”有意贪婪,以便在“a = b = c = d = x”情况下稍后分割。 - vol7ron
@Lo-lsauer.com 我曾经认为我已经通过使用 document.scriptsdocument.currentScript 修改了代码。请注意,代码不一定在 scripts[1] 中,因此您可能还需要遍历整个脚本数组。 - vol7ron
你知道如何以跨浏览器的方式访问“正在运行的脚本”,而不是DOM脚本标签的内容吗? - Lorenz Lo Sauer
@Lo-lsauer.com 我不知道有任何方法,而且我认为这可能很困难,因为您将访问浏览器本身的内存/进程,这是一个安全问题。当脚本被加载时,它们会被解析并相应地添加到DOM中,其中window.document.scripts数组包含它们。虽然,您也可以通过遍历document.headdocument.body来获取它们,具体取决于脚本定义的位置。 - vol7ron

0

你可以尝试的一个技巧是这样的:

    
let myVariable = 1;
console.log((()=>myVariable).toString().replace('()=>', '')) 


0

你可以使用装饰器来检测必须的变量名称:

(a)- 类

(b)- 类或实例的属性

(c)- 类或实例的方法


装饰器提供有关被装饰对象的3个信息:

  1. 目标
  2. 描述符

因此:

  • (a)的名称是target.name
  • (b)或(c)的名称直接为key

     function logName(target, key) {
       console.log(!key ? target.name : key);
     }
    

示例(尝试Fiddle

  @logName
  class Person {

     @logName
     firstname="Someone";

     @logName
     fullName() {
       return this.firstname+' '+this.lastname;
     }

  }

尝试Fiddle


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接