Como encontrar as chaves de um hash?

192

Eu sei que em javascript objetos funcionam como hashes, mas não consegui encontrar uma função incorporada para obter as chaves

var h = {a:'b',c:'d'};

Eu quero algo como

var k = h.keys() ; // k = ['a','c'];

É simples escrever uma função para iterar sobre os itens e adicionar as chaves a uma matriz que retorno, mas existe uma maneira mais limpa de fazer isso?

Eu continuo sentindo que deve ser uma função simples que perdi, mas não consigo encontrá-la!

Pat
fonte
Estou apenas pulando em javascript, mas este post pode ajudá-lo. dean.edwards.name/weblog/2006/07/enum
jason saldo
Possível duplicata da matriz Get das chaves do objeto
blo0p3r 02/02
1
Que tal obter os valores das chaves? Além disso, obtendo o número de chaves em um hash.
zero_cool
2017 resposta: Object.keys (h) Object.values (h)
Losty

Respostas:

274

Há uma função no JavaScript moderno (ECMAScript 5) chamado Object.keysexecutando esta operação:

var obj = { "a" : 1, "b" : 2, "c" : 3};
alert(Object.keys(obj)); // will output ["a", "b", "c"]

Detalhes de compatibilidade podem ser encontrados aqui .

No site da Mozilla , também há um trecho de compatibilidade com versões anteriores:

if(!Object.keys) Object.keys = function(o){
   if (o !== Object(o))
      throw new TypeError('Object.keys called on non-object');
   var ret=[],p;
   for(p in o) if(Object.prototype.hasOwnProperty.call(o,p)) ret.push(p);
   return ret;
}
Ivan Nevostruev
fonte
isso não teria sido mais natural? if(!Object.prototype.keys) Object.prototype.keys = function() { if (this !== Object(this)) throw new TypeError('Object.keys called on non-object'); var ret = [], p; for (p in this) if (Object.prototype.hasOwnProperty.call(this, p)) ret.push(p); return ret; } var x = { a: { A: 1, B: 2, C: 3 }, b: { A: 10, B: 20 } }; alert(x.a.keys());
ekkis
2
Como eu entendo isso Object.prototype.keysfará keysdisponível para todas as sub-classes de objeto, portanto, para todos os objetos. O que provavelmente você deseja se estiver tentando usar o OOP. De qualquer forma, isso realmente depende de suas necessidades.
Ivan Nevostruev
1
Se você usar o mootools, Object.keys () deverá estar disponível em todos os navegadores.
thepeer
Existe algo para usar isso em modelos angulares? Não está funcionando lá dentro de parciais.
Jay Shukla
Eu acho que você deve fazer isso como uma pergunta separada com amostra de código.
Ivan Nevostruev 7/12
80

Para código de produção que requer uma grande compatibilidade com navegadores clientes, ainda sugiro a resposta de Ivan Nevostruev acima com shim para garantir Object.keysem navegadores mais antigos. No entanto, é possível obter a funcionalidade exata solicitada usando o novo definePropertyrecurso da ECMA .

No ECMAScript 5 - Object.defineProperty

No ECMA5, você pode usar Object.defineProperty()para definir propriedades não enumeráveis. A compatibilidade atual ainda tem muito a desejar, mas isso deve se tornar utilizável em todos os navegadores. (Observe especificamente a incompatibilidade atual com o IE8!)

Object.defineProperty(Object.prototype, 'keys', {
  value: function keys() {
    var keys = [];
    for(var i in this) if (this.hasOwnProperty(i)) {
      keys.push(i);
    }
    return keys;
  },
  enumerable: false
});

var o = {
    'a': 1,
    'b': 2
}

for (var k in o) {
    console.log(k, o[k])
}

console.log(o.keys())

# OUTPUT
# > a 1
# > b 2
# > ["a", "b"]

No entanto, como o ECMA5 já foi adicionado, Object.keysvocê também pode usar:

Object.defineProperty(Object.prototype, 'keys', {
  value: function keys() {
    return Object.keys(this);
  },
  enumerable: false
});

Resposta original

Object.prototype.keys = function ()
{
  var keys = [];
  for(var i in this) if (this.hasOwnProperty(i))
  {
    keys.push(i);
  }
  return keys;
}

Edit: Uma vez que esta resposta existe há algum tempo, deixarei o acima exposto intocado. Quem estiver lendo isso também deve ler a resposta de Ivan Nevostruev abaixo.

Não há como tornar as funções de protótipo não enumeráveis, o que as leva a sempre aparecer em loops for-in que não são usados hasOwnProperty. Ainda acho que essa resposta seria ideal se estender o protótipo de Object não fosse tão complicado.

AnnanFay
fonte
9
'hasOwnProperty' exclui propriedades nos protótipos deste objeto, o que é útil saber.
Ijw 13/11/2009
2
Resposta aceita porque foi assim que acabei implementando, mas acho que essa deveria ter sido uma função interna da linguagem.
Pat
5
Observe que você deve usar "for (var i neste) ..." para evitar a criação de uma variável global.
Brad G.
5
Eu evitaria modificar o Object.prototype - como outro comentarista observou abaixo, isso pode facilmente quebrar scripts que não são cuidadosos ao verificar o hasOwnProperty (). Em vez disso, use a maneira menos amigável para OO: defina uma função 'keys' se ela ainda não existir. (Firefox e Chrome ambos implementar um chaves nativos () função que faz exatamente o que o OP quer - ou seja, não)
digitalbath
1
Parece ser uma má idéia adicionar algo ao Object.prototype, pois quebra todos os circuitos normais como: for (var k na matriz) {} ou for (var k no objeto) e esse idioma - embora possa estar com defeito - é extremamente comum. Por exemplo, de acordo com a resposta de Matthew Darwin abaixo, ele quebra o Google Maps.
Sam Watkins
42

você pode usar Object.keys

Object.keys(h)
Leticia Santos
fonte
3
Adicionado em ECMAScript 5, mas deve funcionar na maioria dos principais navegadores até agora
Pat
33

Você pode usar Underscore.js , que é uma biblioteca de utilitários Javascript.

_.keys({one : 1, two : 2, three : 3}); 
// => ["one", "two", "three"]
timotti
fonte
Bem, não é realmente o que foi perguntado, porque @Pat está à procura de um built-in função, mas é uma biblioteca interessante, no entanto, e ele não modificaObject.prototype
fresskoma
2
Hoje em dia, acho muito mais útil usar essas bacanas pequenas bibliotecas do que continuar escrevendo suas próprias implementações ... De qualquer forma, na maioria dos projetos do mundo real, estamos usando Underscore ou bibliotecas equivalentes. Pessoalmente, prefiro ir com o Underscore.
precisa saber é o seguinte
_.keys(obj).lengthpara ver se existem chaves.
chovy 24/09/12
13

É o melhor que você pode fazer, até onde eu sei ...

var keys = [];
for (var k in h)keys.push(k);
danb
fonte
2
Isso também não funciona quando o Object.prototype foi alterado.
26411 Phil
4
Seria melhor usar isso e não "mexer com" o Object.prototype. Parece que tudo quebra se adicionarmos coisas ao Object.prototype: é um idioma extremamente comum fazer um loop nas chaves de um array / objeto.
Sam Watkins
8

Usando o jQuery, você pode obter as chaves assim:

var bobject =  {primary:"red",bg:"maroon",hilite:"green"};
var keys = [];
$.each(bobject, function(key,val){ keys.push(key); });
console.log(keys); // ["primary", "bg", "hilite"]

Ou:

var bobject =  {primary:"red",bg:"maroon",hilite:"green"};
$.map(bobject, function(v,k){return k;});

graças a @pimlottc

chim
fonte
3
Se você quiser seguir esse caminho, use também JQuery.map: $.map(h, function(v,k) { return k; });
pimlottc
6

Eu acredito que você pode percorrer as propriedades do objeto usando for / in, para que você possa fazer algo assim:

function getKeys(h) {
  Array keys = new Array();
  for (var key in h)
    keys.push(key);
  return keys;
}
Palmsey
fonte
4

Eu queria usar a resposta mais bem avaliada acima

Object.prototype.keys = function () ...

No entanto, ao usar em conjunto com a API do Google Maps v3, o Google Maps não funciona.

for (var key in h) ...

funciona bem.

Matthew Darwin
fonte
1

se você está tentando obter apenas os elementos, mas não as funções, esse código pode ajudá-lo

this.getKeys = function() {

var keys = new Array();
for(var key in this) {

    if( typeof this[key] !== 'function') {

        keys.push(key);
    }
}
return keys;

}

isso faz parte da minha implementação do HashMap e eu quero apenas as chaves, thisé o objeto hashmap que contém as chaves

zeacuss
fonte