Número de elementos em um objeto javascript

103

Existe uma maneira de obter (de algum lugar) o número de elementos em um objeto javascript? (isto é, complexidade de tempo constante).

Não consigo encontrar uma propriedade ou método que recupere essas informações. Até agora, só consigo pensar em fazer uma iteração por toda a coleção, mas isso é tempo linear.
É estranho que não haja acesso direto ao tamanho do objeto, não acha.

EDIT:
Estou falando sobre o Objectobjeto (não objetos em geral):

var obj = new Object ;
Liberta-te
fonte
5
Já respondido aqui stackoverflow.com/questions/126100/… Object.keys (obj) .length
spats

Respostas:

155

Embora as implementações de JS possam acompanhar esse valor internamente, não há uma maneira padrão de obtê-lo.

No passado, a variante Javascript da Mozilla expôs o não padrão__count__ , mas foi removido com a versão 1.8.5.

Para scripts de navegadores diferentes, você fica preso em iterar explicitamente as propriedades e verificar hasOwnProperty():

function countProperties(obj) {
    var count = 0;

    for(var prop in obj) {
        if(obj.hasOwnProperty(prop))
            ++count;
    }

    return count;
}

No caso de implementações compatíveis com ECMAScript 5, isso também pode ser escrito como (Kudos to Avi Flax )

function countProperties(obj) {
    return Object.keys(obj).length;
}

Lembre-se de que você também perderá propriedades que não são enumeráveis ​​(por exemplo, uma matriz length).

Se você estiver usando um framework como jQuery, Prototype, Mootools, $ Whatever-the-newest-hype, verifique se eles vêm com suas próprias APIs de coleções, o que pode ser uma solução melhor para o seu problema do que usar objetos JS nativos.

Christoph
fonte
11
Droga, sempre esqueço hasOwnProperty. Muito tempo na terra .NET, eu lhe digo. +1
annakata
2
jQuery usa um objeto para suas coleções que obtém de consultas e expõe esse valor com uma propriedade de comprimento.
Nosredna
6
Firefox4 __count__sumiu :(
Timo Huovinen,
1
Existe uma maneira de fazer isso sem for in? Estou no mesmo tipo de ligação, mas gostaria de fazê-lo passar JSLint se possível.
poste de
1
porque precisamos hasOwnProperty()?
suíço
99

Para fazer isso em qualquer ambiente compatível com ES5

Object.keys(obj).length

(Suporte de navegador a partir daqui )
(Doc on Object.keys aqui , inclui o método que você pode adicionar a navegadores não ECMA5)

ZelkiN
fonte
2
Esta não é a pergunta certa para responder. Com isso, você está pegando todas as chaves do objeto, colocando-as em um array recém-criado e recuperando a propriedade length desse novo array.
GetFree
13
Pode não ser o mais programaticamente eficiente, mas é o mais eficiente para o desenvolvedor.
superluminário de
9

se você já estiver usando jQuery em sua construção, faça o seguinte:

$(yourObject).length

Funciona bem para mim em objetos, e eu já tinha o jQuery como dependência.

IndelibleHeff
fonte
5
Estranho ... isso não funciona para mim. Sempre recebo 1. A resposta de ZelkiN funciona para mim.
roedor de microfone de
3
Este código sempre retorna 1. Apenas 1 objeto. Não está contando elementos nele
BeRocket
5
function count(){
    var c= 0;
    for(var p in this) if(this.hasOwnProperty(p))++c;
    return c;
}

var O={a: 1, b: 2, c: 3};

count.call(O);
kennebec
fonte
2

AFAIK, não há como fazer isso de forma confiável, a menos que você mude para um array. O que, honestamente, não parece estranho - parece bastante direto para mim que as matrizes são contáveis, e os objetos não.

Provavelmente, o mais perto que você chegará é algo assim

// Monkey patching on purpose to make a point
Object.prototype.length = function()
{
  var i = 0;
  for ( var p in this ) i++;
  return i;
}

alert( {foo:"bar", bar: "baz"}.length() ); // alerts 3

Mas isso cria problemas, ou pelo menos perguntas. Todas as propriedades criadas pelo usuário são contadas, incluindo a própria função _length! E embora neste exemplo simples você possa evitá-lo usando apenas uma função normal, isso não significa que você pode impedir que outros scripts façam isso. Então, o que você faz? Ignorar propriedades da função?

Object.prototype.length = function()
{
  var i = 0;
  for ( var p in this )
  {
      if ( 'function' == typeof this[p] ) continue;
      i++;
  }
  return i;
}

alert( {foo:"bar", bar: "baz"}.length() ); // alerts 2

No final, acho que você provavelmente deveria abandonar a ideia de tornar seus objetos contáveis ​​e descobrir outra maneira de fazer o que quer que esteja fazendo.

Peter Bailey
fonte
8
O PERIGO ROBINSON! NÃO faça proto contra objeto! Tudo descende do objeto, você vai paralisar o processamento do cliente assim se estiver fazendo uma quantidade considerável de trabalho JS.
annakata
5
Uh ... você não leu a parte onde eu escrevi em um comentário "Monkey patching propositalmente para mostrar um ponto" - vamos lá, eu fiz isso deliberadamente para que as pessoas não se mexessem nem um pouco. Além disso, embora eu não defenda o patching de macacos, você entende mal como a cadeia de protótipos funciona em Javascript se acha que isso causaria problemas de desempenho video.yahoo.com/watch/111585/1027823
Peter Bailey
Então .. isso é fazer ou não?
OscarRyz
Em "Javascript: The Good Parts", ele prototipou o objeto com um método "create ()". Eu acredito que é o livro definitivo sobre Javascript.
Chris Dutrow
1

O conceito de número / comprimento / dimensionalidade não faz sentido para um objeto, e precisar dele sugere que você realmente quer um Array para mim.

Edit: Indicou para mim que você quer um O (1) para isso. Até onde sei, não existe tal forma, receio.

Annakata
fonte
Ele propôs iterar a si mesmo, que é essa solução. Ele precisava de uma maneira O (1) para conseguir isso ...
Thomas Hansen
Você está certo. Realmente deveria ler as perguntas mais detalhadamente.
annakata
Na verdade, os objetos são a coisa mais próxima de um mapa que existe em JS. Os mapas têm comprimento.
Cristian Vrabie