如何在JavaScript中确定哪个按键调用了一个函数

6
如果我有一个含有多个键的对象,在其调用外部函数时,如何确定是哪个键调用了该函数?例如:
function tellYourAge() {
   return function()
   {
       // I already know here that this refers to Population
       // For example, console.log(this) will print the Population object
   }
}

{
   let Population = {
     Mahdi: tellYourAge(),
     Samuel: tellYourAge(),
     Jon: tellYourAge()
   };

   Population.Mahdi(); // It should log 18
   Population.Samuel(); // It should log 20
   Population.Jon(); // It should log 21
}

4
将密钥作为参数传递,例如:Mahdi: tellYourAge('Mahdi') - imvain2
8
为什么我想在不传递参数的情况下执行它? - Mosh Feu
1
年龄存储在哪里?这似乎应该是个体对象上的一个方法。 - Mark
4
键与值之间没有任何链接。你要么必须传递它,要么必须重新考虑它的设置方式。 - epascarello
2
你不能按照描述的方式完全实现这个。你可以尝试使用块作用域或Function.prototype.bind来实现类似的功能。 - AlexMA
显示剩余6条评论
4个回答

9

有可能实现

function tellYourAge() {
   return function()
   {
       var f = arguments.callee;
       var key = Object.keys(this).filter(key => this[key] === f)[0];
       console.log(key);
   }
}

{
   let Population = {
     Mahdi: tellYourAge(),
     Samuel: tellYourAge(),
     Jon: tellYourAge()
   };

   Population.Mahdi(); // prints Mahdi
   Population.Samuel(); // prints Samuel
   Population.Jon(); // prints Jon
}

解释: arguments.callee 是对所属 arguments 对象的函数的引用。而 this 基本上是在函数调用时“点号之前的东西”,因此是您的 Population 对象。现在你所要做的就是在对象中查找被调用的函数实例,然后你就完成了。


1
好提示!一些被调用者需要考虑的事项:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/arguments/callee - Ronald Korze
我建议使用 .find(...) 代替 .filter(...)[0] - 3limin4t0r

2
function tellYourAge() {
   return function()
   {
      var s = new Error().stack;
      if(s.includes('Mahdi')){
        console.log('Age is 18');
      }

      else if(s.includes('Samuel')){
        console.log('Age is 20');
      }

      else if(s.includes('Jon')){
        console.log('Age is 21');
      } 
   }
}

{
   let Population = {
     Mahdi: tellYourAge(),
     Samuel: tellYourAge(),
     Jon: tellYourAge()
   };

   Population.Mahdi(); // It should log 18
   Population.Samuel(); // It should log 20
   Population.Jon(); // It should log 21
}

Output:
Age is 18
Age is 20
Age is 21

提供信息,new Error().stack 将会给你以下类似的堆栈跟踪信息:

最初的回答:

Error
    at Object.Samuel (<anonymous>:4:20)
    at <anonymous>:1:19

这怎么回答我的问题了? - Mahdi Jaber
检查我的更新代码。我认为我们可以仅从堆栈跟踪中找出关键信息。 - Vardaman PK
1
@MahdiJaber...根据你提供的示例和不想以任何形式提供任何函数参数的要求,这正是满足所有这些要求的唯一方法。 - Peter Seliger
1
希望 OP 实际上不会这样做,但我点赞是因为这是一个合法的回答。在被迫的情况下,我也曾经检查过堆栈代码。我想这里特别令人无法容忍的是:A:它是主程序流程的一部分,而不是记录器或错误处理程序。B:它正在创建一个错误。(有没有一种方法可以在没有错误的情况下请求堆栈?)和 C:它将堆栈解析为字符串,这显然是容易出错的。 - ShapeOfMatter

1
我理解你的问题是如何将一个人的年龄与他们的名字关联起来。我会创建描述人的对象来实现这一点。每个对象将有两个属性,一个是名字,另一个是年龄。
然后,这些对象(人)将存储在一个数组中,即人口普查。

// Create a constructor function which defines a Person
function Person(name, age) {
  this.name = name;
  this.age = age;
}

// Create an array of Population to store the Persons (people)
var Population = [];
Population.push(new Person('Mahdi', 18));
Population.push(new Person('Samuel', 20));
Population.push(new Person('John', 21));

// Counter and limit variables
var i, l;

// Loop through the Population and display the information about the people
l = Population.length;
for (i = 0; i < l; i++) {
  let person = Population[i];
  console.log(person.name + " is " + person.age);
}


0

你没有解释为什么不想“传递参数”,或者不传递参数的具体要求是什么。我猜测你想以某种特定于你上下文的方式保持返回的整数(或其他值)动态。

这是我建议的方法,尽管还不清楚它是否是一个好主意:

function tellYourAge() {
  return function(name)
  {
    let ages = {
      Mahdi: 18,
      Samuel: 20,
      Jon: 21,
    };
    return ages[name];
  }
}

{
  let makePopulation = function(names){
    let pop = {};
    names.forEach(function(n){
      pop[n] = tellYourAge().bind(pop, n);
    });
    return pop;
  };

  let Population = makePopulation("Mahdi", "Samuel", "Jon");

  Population.Mahdi(); // It should log 18
  Population.Samuel(); // It should log 20
  Population.Jon(); // It should log 21
}

新函数makePopulation的引入只是为了风格上的考虑。我不喜欢看到变量被改变,就像上面的pop一样。有时在设置所需值时这是必要的;在这些情况下,我喜欢将变化/初始化封装起来,以便可以将其视为程序流程之外的部分。 - ShapeOfMatter

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