【问题标题】:Getting the property key from within a property's value从属性值中获取属性键
【发布时间】:2016-03-04 00:18:50
【问题描述】:

给定以下 javascript 对象:

var commands = {
    back:{
        command: "b",
        aliases: ["back","go back","backwards"],
        action: function(){
            return this.key; //I want this to return "back" (the prop name)
        },
        desc: "goes back"
    }
}

如何从action() 中访问“返回”的属性名称?

我认为它应该很简单,但如果它不是简单的东西,我会添加更多细节。

  • 注意:aliases[0] 是偶然持有该名称,并且不承诺在未来或其他命令中持有它。

编辑: 有时我们会变得复杂,但我们可以很快解决问题。 在这种情况下,我可以继续并返回字符串“back”

如果有这样的解决方案,我会留下问题并接受解决我问题的答案。

【问题讨论】:

  • 向对象添加多余的name: "back" 属性是否适合您?或者如果它总是名称,也许只使用this.aliases[0]
  • 唯一的方法是迭代commands的属性并检查this的值是否相等。但这实际上取决于 commands 在闭包内是否始终可用。
  • @FrédéricHamidi aliases[0] 未承诺保留该名称

标签: javascript javascript-objects


【解决方案1】:

如您所述返回字符串绝对是最简单的方法。但我可以看到有人可能希望能够使用动态创建的对象获得类似功能的情况,其中键直到运行时才知道。

在这种情况下可行的解决方案是将 commands 对象暴露给子对象,以便它们可以自行查找:

var commands = {
    back:{
        command: "b",
        aliases: ["back","go back","backwards"],
        action: function(){
            var commandKeys = Object.keys(commands);
            for(var i=0; i < commandKeys.length; i++){
                if(commands[commandKeys[i]] === this){
                    return commandKeys[i];
                }
            }
        },
        desc: "goes back"
    }
};

在这种情况下,在所有这些操作对象之间共享函数也可能更有意义:

var commands = {
    back:{
        command: "b",
        aliases: ["back","go back","backwards"],
        action: getAction,
        desc: "goes back"
    },
    forward: {
        //...
        action: getAction,
        //...
    }
};

function getAction() {
    var commandKeys = Object.keys(commands);
    for(var i=0; i < commandKeys.length; i++){
        if(commands[commandKeys[i]] === this){
            return commandKeys[i];
        }
    }
}

除非您需要为每个子对象执行一些特定的逻辑。


编辑:为了提高效率,我们可以在每次调用时不执行getAction 函数并添加一个属性来存储名称。这样查找只会在第一次发生。

var commands = {
    back:{
        command: "b",
        aliases: ["back","go back","backwards"],
        action: getAction,
        desc: "goes back"
    },
    forward: {
        //...
        action: getAction,
        //...
    }
};
// Only needs to getKey the first time called.
function getAction() {
    if(!this.key) this.key = getKey(this);
    return this.key;
}
function getKey(obj) {
    var commandKeys = Object.keys(commands);
    for(var i=0; i < commandKeys.length; i++){
        if(commands[commandKeys[i]] === obj){
            return commandKeys[i];
        }
    }
}

【讨论】:

  • 不是最有效的答案,但绝对是唯一能回答我问题的答案:)
  • @TBE,我​​刚刚添加了一个编辑,希望 NanoWizard 会批准它应该提高这个非常好的解决方案中代码的效率:)
  • @tkellehe 我没有拒绝它......也许它超时了?我刚刚重新上线,没有看到您的编辑。我假设它正在缓存/排序commandKeys?
  • 它没有在我的手机上显示为什么它被拒绝了。我现在明白为什么了。我不会发表评论,而是重新提交编辑,以便您可以看到它,然后您可以拒绝它并选择是否更新答案:)
  • 为了清晰起见,我对其进行了一些更改,但这是一个很好的效率改进。谢谢:)
【解决方案2】:

当您拨打action如下:

commands.back.action();

action 的范围是back。遗憾的是,分配给commands.back 的对象的创建并不知道action 内部的this 被称为"back"。据我了解,这样做是因为我们可以将分配给commands.back 的对象分配给另一个名称的对象。如:

var foo = { f: function(){console.log(this) } };
var bar = foo;
bar.f();

或者更接近你所拥有的......

var foo = {
    bar: {
        f:function(){console.log(this)}
    }
};
var other = { another: (foo.bar) };

我知道对象在哪里知道它在其中创建的名称的唯一方法是函数。因此,我们可以创建一个名为 back 的临时函数,它将根据需要创建一个对象。

var commands = {
    back:(new function back(){
        // I prefer to assign to a variable to assist with the readability as to what "this" is:)
        var self     = this;
        self.command = "b";
        self.aliases = ["back","go back","backwards"];
        self.action  = function(){
            // Can leave as "this" or change to "self".
            return this.key;
        };
        self.desc = "goes back";
        self.key  = self.prototype.constructor.name;
    })
}

最简单的解决方案

但此时还不如添加一个已经具有名称的属性。我建议创建一个名为 keyname 的属性,而不是将名称直接放入 action 函数中,以便更容易在多个位置使用该名称。此外,如果需要,允许在一个地方更改对象内的名称。

var commands = {
    back:{
        command: "b",
        aliases: ["back","go back","backwards"],
        action: function(){
            return this.key;
        },
        desc: "goes back",
        key: "back"
    }
}

编辑:将此编辑添加为另一种方法,但我仍会使用以前的方法。我们可以利用Object.keys 来获取属性的名称,因为back 被添加为commands 的可枚举属性。

var i        = 0,
    commands = { back: {
        key: (function(id){return function(){return Object.keys(commands)[id]}})(i++)
    }}

然后可以通过以下方式获取key

commands.back.key();

或在action 函数内为:

this.key();

可以将key 添加到back 作为get,如下所示:

var i        = 0,
    commands = { back: { 
        id: (i++),
        get key() {return Object.keys(commands)[this.id]}
    }}

这将允许您以commands.back.key 的身份访问该属性,并在action 函数中以this.key 的身份访问该属性。

还可以预先定义所有内容,然后可以执行以下操作:

var i = 0, commands = { back: undefined };
commands.back = { key: Object.keys(commands)[i++] };

【讨论】:

  • upVoted,只是添加一个带有名称的属性或者只是将名称作为字符串返回可能是最简单和最简单的方法。
【解决方案3】:

你可以为你的每一个对象添加一个toString 方法,像这样。

var commands = {
back:{
    command: "b",
    name : "back",
    aliases: ["back","go back","backwards"],
    action: function(){
        return this.toString(); 
    },
    desc: "goes back",
    toString : function(){
      return this.name;
    }
 }
}
console.log(commands.back.action()); // back
console.log(commands.back.toString()); // back

【讨论】:

  • upVoted,只是添加一个带有名称的属性或者只是将名称作为字符串返回可能是最简单和最简单的方法。
【解决方案4】:

您在这里拥有的是一个嵌套对象,它保存在对象的属性上。

您无法手动获取该属性 - 除非您正在做一些奇怪的元编程工作,例如获取 AST 父节点并尝试确定对象所持有的属性等。最简单的方法是保存属性名称使用字符串,即:“back”。

简单来说,就是把对象放到一个var上

var obj = {/*....*/};

您正试图从对象中获取 var 名称。

请记住,尽管在 JavaScript 中,您可以使用字符串和索引表示法访问对象属性,因此也可以使用 commands['back'] 调用 commands.back。如果我猜对了,你正在尝试进行某种调度,所以这个符号对你很有用。

【讨论】:

  • 这里没有构造函数,OP使用的唯一函数没有名字。
  • @NickL。我的需要是使用该名称从属性文件中获取常量字符串,但正如你提到的以及我在第一次编辑中所写的那样,这里最简单的事情就是返回字符串“back”
【解决方案5】:

如果您有该对象(文字对象),则不能使用 this 关键字。您有两种解决方案:

   return commands.back.aliases[0]

否则,您可以将对象构造为原型对象而不是文字对象:

var commands = function() {

  this.back = function() {
    this.command = "b";
    this.aliases = ["back","go back","backwards"];
    this.action = function() {
      return this.aliases[0];
    };
    this.desc = "goes back";
  };
};

然后像这样初始化

var instance = new commands();
instance.action(); // it returns "back" string

【讨论】:

  • aliases[0] 未承诺持有该属性的名称。
  • 对不起,我误解了这个问题。我将删除答案
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-05
  • 2013-05-07
相关资源
最近更新 更多