2015-11-30 22 views
7

Biorąc pod uwagę następujące javascript obiektu:Uzyskanie klucza nieruchomości od wewnątrz wartości nieruchomości

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" 
    } 
} 

Jak mogę uzyskać dostęp do nazwy właściwości, która jest „do tyłu” od wewnątrz action()?

Myślę, że powinno być całkiem proste, ale jeśli nie jest to coś prostszego, to dodam więcej szczegółów.

  • UWAGA: aliases[0] trzyma nazwisko przez przypadek i nie jest obiecane, że będzie go posiadał w przyszłości lub w innych poleceniach.

EDYCJA: EDYCJA: Czasami dochodzimy do komplikacji, a my możemy szybko rozwiązać problem. W tym przypadku mogę po prostu wrócić i zwrócić ciąg "wstecz"

Zostawię pytanie i przyjmuję odpowiedź, która rozwiązuje moje pytanie, czy istnieje takie rozwiązanie.

+0

Dodanie do obiektu nadmiarowej nazwy: "wstecz" właściwość odpowiednia dla ciebie? A może po prostu używając 'this.aliases [0]' jeśli to zawsze jest nazwa? –

+0

Jedynym sposobem byłoby powtórzenie właściwości 'commands' i sprawdzenie równości wartości za pomocą' this'. Ale to naprawdę zależy od tego, czy "komendy" są zawsze dostępne w zamknięciu. – Yoshi

+0

@ FrédéricHamidi aliasy [0] nie ma obietnicy posiadania nazwy – TBE

Odpowiedz

2

Wracając ciąg jak wspomniano jest to zdecydowanie najprostszy sposób. Ale widziałem przypadki, w których ktoś mógłby chcieć uzyskać podobną funkcjonalność z dynamicznie tworzonym obiektem, w którym klucze nie są znane do czasu wykonania.

Rozwiązanie, które będzie działać w tym przypadku jest wystawienie przedmiotu do obiektów podrzędnych commands, dzięki czemu mogą one wyglądać prowadzenie:

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" 
    } 
}; 

W tym przypadku może to również uczynić więcej sensu dzielić funkcję w poprzek wszystkie te obiekty akcji:

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]; 
     } 
    } 
} 

Chyba że musisz wykonać określoną logikę dla każdego obiektu podrzędnego.


EDIT: Aby poprawić wydajność, możemy to zrobić gdzie funkcja getAction nie jest wykonywany każdą rozmowę i dodać właściwość, która będzie przechowywać nazwę. W ten sposób wyszukiwanie następuje tylko za pierwszym razem.

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]; 
     } 
    } 
} 
+0

nie jest to najskuteczniejsza odpowiedź, ale zdecydowanie jedyna, która odpowiada na moje pytanie :) – TBE

+1

@TBE, właśnie dodałem edycję, która, mam nadzieję, że NanoWizard to zarekomenduje, powinna zwiększyć efektywność kodu w tym bardzo fajnym rozwiązaniu :) – tkellehe

+0

@NanoWizard, Dlaczego edycja została odrzucona? – tkellehe

0

Jeśli masz ten obiekt (obiekt literalny), nie możesz użyć słowa kluczowego this. Masz dwa rozwiązania:

return commands.back.aliases[0] 

lub w inny sposób, można skonstruować obiektu jako obiektu prototypu, a nie dosłowne obiektu:

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"; 
    }; 
}; 

i zainicjować jak ten

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

aliasów [0] nie jest obiecany, aby posiadać nazwę nieruchomości. – TBE

+0

Niestety, nie rozumiem tego pytania. Ja usunę odpowiedź –

1

Możesz dodać a także wskazane jest dodanie metody toString dla każdego takiego obiektu.

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 
+0

Miałeś na myśli 'this.name', prawda? – Bergi

+0

@Bergi tak. dzięki. Zmienię to. –

+1

upVoted, wystarczy dodać właściwość o nazwie lub po prostu zwrócić nazwę jako ciąg jest prawdopodobnie najprostszy i najprostszy sposób. – TBE

1

To, co tu masz, jest obiektem zagnieżdżonym, przechowywanym na własności przedmiotu.

Nie możesz pobrać tej własności ręcznie - chyba że robisz jakieś dziwne metaprogramowanie, takie jak pobranie węzła nadrzędnego AST i próba określenia właściwości obiektu, który się odbywa itd. Najprostszym sposobem jest zatrzymanie własności nazwa za pomocą ciągu znaków, np .: "powrót".

W prostych słowach, to jest jak trzyma obiekt do var

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

i próbujesz uzyskać nazwę var od wewnątrz obiektu.

Pamiętaj jednak, że w JavaScript można uzyskać dostęp do właściwości obiektu, używając zarówno notacji łańcuchowej, jak i indeksu, więc commands.back można również wywołać za pomocą commands['back']. Jeśli zgaduję, że masz rację, próbujesz dokonać pewnego rodzaju wysyłki, więc ta notacja może ci się przydać.

+0

W tym miejscu nie ma konstruktorów, a jedyna funkcja używana przez OP nie ma nazwy. – Bergi

+0

@NickL. Moją potrzebą było użycie tej nazwy, aby uzyskać stały ciąg z pliku właściwości, ale jak wspomniałem i jak napisałem w mojej pierwszej EDYCJI, najprostszą rzeczą tutaj jest po prostu zwrócenie ciągu "wstecz" – TBE

2

Po wywołaniu action jak:

commands.back.action(); 

zakres action jest back. Niestety, utworzenie obiektu przypisanego do commands.back nie wie, że this wewnątrz action jest nazywane "back".Z mojego rozumowania wynika, że ​​możemy przypisać obiekt przypisany do commands.back do innego obiektu o innej nazwie. Jak w:

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

lub bliżej, co masz ...

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

Jedynym sposobem, wiem, gdzie obiekt zna nazwę to, co zostało stworzone w ciągu są funkcjami. Możemy więc utworzyć funkcję tymczasową o nazwie back, która utworzy obiekt zgodnie z potrzebami.

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

Najprostszym rozwiązaniem

Ale w tym punkcie może równie dobrze dodać obiekt, który ma już nazwę. Polecam raczej wykonanie właściwości o nazwie key lub name zamiast umieszczania nazwy bezpośrednio w funkcji action, aby ułatwić korzystanie z wielu miejsc, w których nazwa jest używana. Pozwala także na jedno miejsce do zmiany nazwy w obiekcie, jeśli zajdzie taka potrzeba.

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

EDIT: Dodany to edit jako inny sposób to zrobić, ale nadal będzie robić poprzednią stronę. Możemy użyć Object.keys, aby uzyskać nazwę nieruchomości, ponieważ back jest dodawana jako właściwość wyliczalna commands.

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

Następnie można uzyskać key brzmienie:

commands.back.key(); 

lub wewnątrz action funkcji jak:

this.key(); 

można dodać key do back jako get który wyglądałby następująco:

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

Umożliwi to dostęp do nieruchomości jako commands.back.key oraz do funkcji action jako this.key.

Można również wstępnie określić wszystko to można wykonać następujące czynności:

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

upVoted, po prostu dodanie właściwości z nazwą lub po prostu zwróć nazwę jako ciąg jest prawdopodobnie najprostszym i najłatwiejszym sposobem. – TBE

Powiązane problemy