Acabei de descobrir chromestatus.com e, depois de perder várias horas do meu dia, encontrei esta entrada de recurso :
Mapa: objetos de mapa são simples mapas de chave / valor.
Isso me confundiu. Objetos regulares do JavaScript são dicionários, então como é Map
diferente de um dicionário? Conceitualmente, eles são idênticos (de acordo com Qual é a diferença entre um Mapa e um Dicionário? )
As referências da documentação chromestatus também não ajudam:
Objetos de mapa são coleções de pares de chave / valor em que as chaves e os valores podem ser valores arbitrários da linguagem ECMAScript. Um valor-chave distinto pode ocorrer apenas em um par de chave / valor na coleção do Mapa. Valores-chave distintos conforme discriminados usando o algoritmo a de comparação selecionado quando o Mapa é criado.
Um objeto Map pode iterar seus elementos na ordem de inserção. O objeto de mapa deve ser implementado usando tabelas de hash ou outros mecanismos que, em média, fornecem tempos de acesso sublineares no número de elementos na coleção. As estruturas de dados usadas nesta especificação de objetos de Mapa destinam-se apenas a descrever a semântica observável necessária dos objetos de Mapa. Não se destina a ser um modelo de implementação viável.
... ainda soa como um objeto para mim, tão claramente eu perdi alguma coisa.
Por que o JavaScript está ganhando um Map
objeto (com suporte) ? O que isso faz?
Respostas:
De acordo com o mozilla:
e
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
A iterabilidade em ordem é um recurso que há muito é desejado pelos desenvolvedores, em parte porque garante o mesmo desempenho em todos os navegadores. Então, para mim, isso é grande.
O
myMap.has(key)
método será especialmente útil e também amyMap.size
propriedadefonte
map = Object.create(null)
. O que são chaves padrão? Como as chaves estão relacionadasObject.prototype
?new
operador seja usado com oMap
símbolo, ou sejanew Map
, para criar um objeto de mapa.var a = {}
é abreviada para (ou seja, equivalente a)var a = Object.create(Object.prototype)
A principal diferença é que os objetos suportam apenas chaves de cadeia de caracteres, enquanto o Maps suporta mais ou menos qualquer tipo de chave.
Se eu fizer
obj[123] = true
eObject.keys(obj)
então eu vou conseguir, em["123"]
vez de[123]
. Um mapa preservaria o tipo de chave e retornaria, o[123]
que é ótimo. Os mapas também permitem usar objetos como chaves. Tradicionalmente, para fazer isso, você teria que dar aos objetos algum tipo de identificador exclusivo para hash-los (acho que nunca vi nada parecidogetObjectId
em JS como parte do padrão). Os mapas também garantem a preservação da ordem, por isso são melhores para a preservação e às vezes podem poupar a necessidade de fazer alguns tipos.Entre mapas e objetos na prática, existem vários prós e contras. Os objetos obtêm vantagens e desvantagens, sendo fortemente integrados ao núcleo do JavaScript, o que os diferencia de um Mapa significativamente além da diferença no suporte principal.
Uma vantagem imediata é que você tem suporte sintático para objetos, facilitando o acesso a elementos. Você também tem suporte direto para isso com JSON. Quando usado como hash, é irritante obter um objeto sem nenhuma propriedade. Por padrão, se você deseja usar Objetos como uma tabela de hash, eles serão poluídos e você precisará frequentemente
hasOwnProperty
acessá-los ao acessar propriedades. Você pode ver aqui como, por padrão, os objetos são poluídos e como criar objetos esperançosamente não poluídos para uso como hashes:A poluição nos objetos não é apenas algo que torna o código mais irritante, mais lento etc., mas também pode ter conseqüências potenciais para a segurança.
Os objetos não são tabelas de hash puro, mas estão tentando fazer mais. Você tem dores de cabeça
hasOwnProperty
, como não conseguir obter o comprimento facilmente (Object.keys(obj).length
) e assim por diante. Os objetos não devem ser usados apenas como mapas de hash, mas também como objetos dinâmicos extensíveis e, portanto, quando você os usa como puro problema de tabelas de hash, surgem.Comparação / Lista de várias operações comuns:
Existem algumas outras opções, abordagens, metodologias, etc. com altos e baixos (desempenho, conciso, portátil, extensível etc.). Os objetos são um pouco estranhos, sendo o núcleo da linguagem, então você tem muitos métodos estáticos para trabalhar com eles.
Além da vantagem do Google Maps preservar os tipos de chave, além de poder oferecer suporte a objetos como objetos, eles são isolados dos efeitos colaterais que muitos objetos têm. Um mapa é um puro hash, não há confusão sobre tentar ser um objeto ao mesmo tempo. Os mapas também podem ser facilmente estendidos com funções de proxy. Os objetos atualmente têm uma classe Proxy, no entanto, o desempenho e o uso da memória são desagradáveis, na verdade, criar seu próprio proxy que se parece com o Map for Objects atualmente tem um desempenho melhor que o Proxy.
Uma desvantagem substancial para o Maps é que eles não são suportados diretamente pelo JSON. A análise é possível, mas tem vários problemas:
O exemplo acima apresentará um sério impacto no desempenho e também não suportará nenhuma chave de string. A codificação JSON é ainda mais difícil e problemática (essa é uma das muitas abordagens):
Isso não é tão ruim se você estiver usando o Maps apenas, mas terá problemas quando estiver misturando tipos ou usando valores não escalares como chaves (não que o JSON seja perfeito com esse tipo de problema, pois é, referência a objetos circulares do IE). Eu não testei, mas é provável que isso prejudique gravemente o desempenho em comparação com o stringify.
Outras linguagens de script geralmente não apresentam problemas, pois possuem tipos não escalares explícitos para Map, Object e Array. O desenvolvimento da Web costuma ser um problema para tipos não escalares, nos quais você precisa lidar com coisas como o PHP mescla Matriz / Mapa com Objeto usando A / M para propriedades e JS mescla Mapa / Objeto com Matriz que estende M / O. A fusão de tipos complexos é o banimento do diabo de linguagens de script de alto nível.
Até o momento, essas questões são amplamente relacionadas à implementação, mas o desempenho das operações básicas também é importante. O desempenho também é complexo porque depende do mecanismo e do uso. Faça meus testes com um grão de sal, pois não posso descartar nenhum erro (tenho que me apressar). Você também deve executar seus próprios testes para confirmar, pois o meu examina apenas cenários simples muito específicos para fornecer apenas uma indicação aproximada. De acordo com testes no Chrome para objetos / mapas muito grandes, o desempenho dos objetos é pior por causa da exclusão, que é aparentemente de alguma forma proporcional ao número de chaves em vez de O (1):
O Chrome claramente tem uma grande vantagem em obter e atualizar, mas o desempenho da exclusão é horrível. Os mapas usam um pouco mais de memória nesse caso (sobrecarga), mas com apenas um objeto / mapa sendo testado com milhões de chaves, o impacto da sobrecarga nos mapas não é expresso bem. Com o gerenciamento de memória, os objetos também parecem liberar mais cedo se estou lendo o perfil corretamente, o que pode ser um benefício a favor dos objetos.
No Firefox, para esse benchmark específico, é uma história diferente:
Devo salientar imediatamente que, neste benchmark em particular, a exclusão de objetos no Firefox não está causando problemas; no entanto, em outros benchmarks, ele causou problemas, especialmente quando existem muitas chaves, como no Chrome. Os mapas são claramente superiores no Firefox para grandes coleções.
No entanto, esse não é o fim da história, e muitos objetos ou mapas pequenos? Fiz uma referência rápida disso, mas não exaustiva (configuração / obtenção), com melhor desempenho com um pequeno número de chaves nas operações acima. Este teste é mais sobre memória e inicialização.
Novamente, esses números variam, mas basicamente o Object tem uma boa vantagem. Em alguns casos, a vantagem dos objetos sobre os mapas é extrema (~ 10 vezes melhor), mas, em média, foi cerca de 2-3 vezes melhor. Parece que picos extremos de desempenho podem funcionar nos dois sentidos. Eu só testei isso no Chrome e na criação para analisar o uso e a sobrecarga de memória. Fiquei surpreso ao ver que, no Chrome, parece que o Maps com uma tecla usa cerca de 30 vezes mais memória do que os objetos com uma tecla.
Para testar muitos objetos pequenos com todas as operações acima (4 teclas):
Em termos de alocação de memória, eles se comportaram da mesma forma em termos de liberação / GC, mas o Map usou 5 vezes mais memória. Este teste utilizou 4 teclas, onde, como no último teste, apenas defini uma chave, o que explicaria a redução na sobrecarga de memória. Eu executei esse teste algumas vezes e o Mapa / Objeto é mais ou menos igual para o Chrome em termos de velocidade geral. No Firefox para objetos pequenos, há uma vantagem de desempenho definida sobre os mapas em geral.
Obviamente, isso não inclui as opções individuais que podem variar bastante. Eu não aconselharia micro-otimizar com esses números. O que você pode obter disso é que, como regra geral, considere o Maps com mais força para grandes armazenamentos de valores-chave e objetos para pequenos armazenamentos de valores-chave.
Além disso, a melhor estratégia com esses dois é implementá-lo e fazê-lo funcionar primeiro. Ao criar um perfil, é importante ter em mente que, às vezes, as coisas que você não acha que seriam lentas ao olhá-las podem ser incrivelmente lentas, devido às peculiaridades do mecanismo, como visto no caso de exclusão da chave do objeto.
fonte
Não creio que os pontos a seguir tenham sido mencionados nas respostas até agora, e pensei que valeria a pena mencionar.
Os mapas podem ser maiores
No chrome, posso obter 16,7 milhões de pares de chave / valor com
Map
vs. 11,1 milhões com um objeto comum. Quase exatamente 50% mais pares com aMap
. Os dois ocupam cerca de 2 GB de memória antes de travar, e acho que isso pode estar relacionado à limitação de memória pelo chrome ( Edit : Sim, tente preencher 2Maps
e você só tem 8,3 milhões de pares cada antes de travar). Você pode testá-lo você mesmo com este código (execute-os separadamente e não ao mesmo tempo, obviamente):Os objetos já possuem algumas propriedades / chaves
Este já me tropeçou antes. Objetos regulares têm
toString
,constructor
,valueOf
,hasOwnProperty
,isPrototypeOf
e um monte de outras propriedades pré-existentes. Isso pode não ser um grande problema para a maioria dos casos de uso, mas já causou problemas para mim antes.Os mapas podem ser mais lentos:
Devido à
.get
sobrecarga da chamada de função e à falta de otimização interna, o Map pode ser consideravelmente mais lento que um objeto JavaScript antigo comum para algumas tarefas.fonte
toString
,constructor
, etc. (ou seja, suas chaves são extremamente improvável que colidem com eles). Eles são mais fáceis de trabalhar - por exemplo, o incremento éobj[i] = (obj[i] || 0) + 1
, enquantoMap
omap.set(i, (map.get(i) || 0) + 1)
que ainda não é ruim, mas mostra como as coisas podem ficar desnecessariamente bagunçadas. Os mapas definitivamente têm seus casos de uso, mas geralmente um objeto simples funciona.toString
,constructor
(etc.) propriedades do objeto por escritoobj = Object.create(null)
em vez deobj = {}
.Os objetos podem se comportar como dicionários porque o Javascript é digitado dinamicamente, permitindo adicionar ou remover propriedades em um objeto a qualquer momento.
Mas a nova
Map()
funcionalidade é muito melhor porque:get
,set
,has
, edelete
métodos.for-of
uso e mantém a ordem dos resultados.99% do tempo você deve apenas usar a
Map()
. No entanto, se você estiver usando apenas chaves baseadas em string e precisar de desempenho máximo de leitura, os objetos poderão ser uma escolha melhor.O detalhe é que (quase todos) os mecanismos javascript compilam objetos até as classes C ++ em segundo plano. Esses tipos são armazenados em cache e reutilizados por seus "contornos"; portanto, quando você cria um novo objeto com as mesmas propriedades exatas, o mecanismo reutiliza uma classe de plano de fundo existente. O caminho de acesso para propriedades nessas classes é muito otimizado e muito mais rápido que a pesquisa de a
Map()
.Adicionar ou remover uma propriedade faz com que a classe de backup em cache seja recompilada, e é por isso que o uso de um objeto como um dicionário com muitas adições e exclusões de chave é muito lento, mas a leitura e a atribuição de chaves existentes sem alterar o objeto são muito rápidas.
Portanto, se você tiver uma carga de trabalho de gravação pesada e leitura com chaves de seqüência de caracteres, use o
object
como um dicionário especializado de alto desempenho, mas, para todo o resto, use aMap()
.fonte
get set has delete
funcionalidade etc., mas não é tão elegante (mas também não é ruim). De que maneira éMap
mais fácil usar para iterar? Não tenho certeza se posso concordar.Além das outras respostas, descobri que o Maps é mais pesado e detalhado para operar do que os objetos.
Isso é importante, porque o código mais curto é mais rápido de ler, mais expressivo e melhor mantido na cabeça do programador .
Outro aspecto: como set () retorna o mapa, não o valor, é impossível encadear atribuições.
Depurar mapas também é mais doloroso. Abaixo, você não pode realmente ver quais chaves estão no mapa. Você teria que escrever um código para fazer isso.
Os objetos podem ser avaliados por qualquer IDE:
fonte
Resumo:
Object
: Uma estrutura de dados na qual os dados são armazenados como pares de valores-chave. Em um objeto, a chave deve ser um número, sequência ou símbolo. O valor pode ser qualquer coisa, assim como outros objetos, funções etc. Um objeto é uma estrutura de dados não ordenada , ou seja, a sequência de inserção de pares de valores-chave não é lembrada.ES6 Map
: Uma estrutura de dados na qual os dados são armazenados como pares de valores-chave. Na qual uma chave exclusiva é mapeada para um valor . A chave e o valor podem estar em qualquer tipo de dados . Um mapa é uma estrutura de dados iterável, isso significa que a sequência de inserção é lembrada e que podemos acessar os elementos em, por exemplo, umfor..of
loopPrincipais diferenças:
UMA
Map
é ordenado e iterável, enquanto um objeto não é ordenado e não iterávelPodemos colocar qualquer tipo de dados como um
Map
chave, enquanto os objetos podem ter apenas um número, sequência ou símbolo como chave.A
Map
herda deMap.prototype
. Isso oferece todos os tipos de funções e propriedades utilitárias, o que facilita o trabalho comMap
objetos.Exemplo:
objeto:
Mapa:
fonte: MDN
fonte
Além de ser iterável em uma ordem bem definida, e a capacidade de usar valores arbitrários como chaves (exceto
-0
), os mapas podem ser úteis devido aos seguintes motivos:As especificações fazem com que as operações do mapa sejam sublineares em média.
Qualquer implementação não estúpida de objeto usará uma tabela de hash ou similar, portanto, as pesquisas de propriedades provavelmente serão constantes, em média. Os objetos podem ser ainda mais rápidos que os mapas. Mas isso não é exigido pelas especificações.
Objetos podem ter comportamentos inesperados desagradáveis.
Por exemplo, digamos que você não definiu nenhuma
foo
propriedade para um objeto recém-criadoobj
, portanto, espereobj.foo
retornar indefinido. Masfoo
poderia ser uma propriedade interna herdadaObject.prototype
. Ou você tenta criarobj.foo
usando uma atribuição, mas algum setterObject.prototype
é executado em vez de armazenar seu valor.Os mapas impedem esse tipo de coisa. Bem, a menos que algum script atrapalhe
Map.prototype
. EObject.create(null)
também funcionaria, mas você perde a sintaxe do inicializador de objetos simples.fonte
Quando usar o Google Maps em vez de objetos JavaScript simples?
O objeto JavaScript simples {key: 'value'} contém dados estruturados. Mas o objeto JS simples tem suas limitações:
Somente cadeias e símbolos podem ser usados como chaves de objetos. Se usarmos outras coisas, digamos, números como chaves de um objeto, durante o acesso a essas chaves, veremos que essas chaves serão convertidas em cadeias implicitamente, causando perda de consistência de tipos. nomes de const = {1: 'um', 2: 'dois'}; Object.keys (nomes); // ['1', '2']
Há chances de sobrescrever acidentalmente propriedades herdadas de protótipos, escrevendo identificadores JS como nomes-chave de um objeto (por exemplo, toString, construtor etc.)
Outro objeto não pode ser usado como chave de um objeto; portanto, nenhuma informação extra pode ser gravada para um objeto, escrevendo esse objeto como chave de outro objeto e o valor desse outro objeto conterá as informações extras.
Objetos não são iteradores
O tamanho de um objeto não pode ser determinado diretamente
Essas limitações de objetos são resolvidas pelo Google Maps, mas devemos considerar o Google Maps como complemento para objetos, em vez de substituição. Basicamente, o Mapa é apenas uma matriz de matrizes, mas devemos passar essa matriz para o objeto Map como argumento com nova palavra-chave, caso contrário, somente para a matriz de matrizes, as propriedades e métodos úteis do Mapa não estão disponíveis. E lembre-se de pares de valores-chave dentro da matriz de matrizes ou o Mapa deve ser separado apenas por vírgulas, sem dois pontos como em objetos simples.
3 dicas para decidir se deve usar um mapa ou um objeto:
Use mapas sobre objetos quando as chaves forem desconhecidas até o tempo de execução, porque as chaves formadas pela entrada do usuário ou inconscientemente podem quebrar o código que usa o objeto se essas chaves sobrescreverem as propriedades herdadas do objeto, para que o mapa seja mais seguro nesses casos. Também use mapas quando todas as chaves forem do mesmo tipo e todos os mapas forem do mesmo tipo.
Use mapas se houver necessidade de armazenar valores primitivos como chaves.
Use objetos se precisarmos operar em elementos individuais.
Os benefícios do uso do Maps são:
1. O mapa aceita qualquer tipo de chave e preserva o tipo de chave:
Sabemos que, se a chave do objeto não é uma sequência ou símbolo, o JS a transforma implicitamente em uma sequência. Pelo contrário, o Map aceita qualquer tipo de chave: string, número, booleano, símbolo etc. e o Map preserva o tipo de chave original. Aqui usaremos o número como chave dentro de um mapa e ele permanecerá um número:
Dentro de um mapa, podemos até usar um objeto inteiro como chave. Pode haver momentos em que desejamos armazenar alguns dados relacionados ao objeto, sem anexá-los ao próprio objeto, para que possamos trabalhar com objetos enxutos, mas queremos armazenar algumas informações sobre o objeto. Nesses casos, precisamos usar o Mapa para que possamos transformar Objeto como chave e dados relacionados ao objeto como valor.
Mas a desvantagem dessa abordagem é a complexidade de acessar o valor por chave, pois precisamos percorrer toda a matriz para obter o valor desejado.
Podemos resolver esse problema de não obter acesso direto ao valor usando um mapa adequado.
Poderíamos ter feito isso usando o WeakMap, basta escrever, const myMap = new WeakMap (). As diferenças entre o Map e o WeakMap são que o WeakMap permite a coleta de lixo de chaves (objetos aqui), para evitar vazamentos de memória, o WeakMap aceita apenas objetos como chaves e o WeakMap reduziu o conjunto de métodos.
2. O mapa não tem restrições sobre os nomes das chaves:
Para objetos JS simples, podemos substituir acidentalmente a propriedade herdada do protótipo e isso pode ser perigoso. Aqui, sobrescreveremos a propriedade toString () do objeto ator:
Agora vamos definir um fn isPlainObject () para determinar se o argumento fornecido é um objeto simples e esse fn usa o método toString () para verificá-lo:
O Mapa não possui restrições quanto aos nomes das chaves, podemos usar nomes de chave como toString, construtor etc. Aqui, embora o objeto actorMap tenha uma propriedade chamada toString, o método toString () herdado do protótipo do objeto actorMap funciona perfeitamente.
Se tivermos uma situação em que a entrada do usuário cria chaves, devemos levá-las dentro de um mapa, em vez de um objeto simples. Isso ocorre porque o usuário pode escolher um nome de campo personalizado como toString, construtor etc., e esses nomes de chave em um objeto simples podem potencialmente quebrar o código que mais tarde usa esse objeto. Portanto, a solução certa é vincular o estado da interface do usuário a um mapa, não há como quebrar o mapa:
3. Mapa é iterável:
Para iterar as propriedades de um objeto simples, precisamos de Object.entries () ou Object.keys (). O Object.entries (plainObject) retorna uma matriz de pares de valores-chave extraídos do objeto, podemos então desestruturar essas chaves e valores e obter saída normal de chaves e valores.
Como o Maps é iterável, é por isso que não precisamos de métodos de entradas () para iterar sobre um mapa e destruir a chave, a matriz de valores pode ser feita diretamente no mapa, pois dentro de um mapa cada elemento vive como uma matriz de pares de valores de chaves separados por vírgulas .
Também map.keys () retorna um iterador sobre as teclas e map.values () retorna um iterador sobre os valores.
4. Podemos saber facilmente o tamanho de um mapa
Não podemos determinar diretamente o número de propriedades em um objeto simples. Precisamos de um auxiliar fn como, Object.keys () que retorna uma matriz com as chaves do objeto e, usando a propriedade length, podemos obter o número de chaves ou o tamanho do objeto simples.
Mas no caso do Maps, podemos ter acesso direto ao tamanho do mapa usando a propriedade map.size.
fonte
Essas duas dicas podem ajudar você a decidir se deseja usar um mapa ou um objeto:
Use mapas sobre objetos quando as chaves forem desconhecidas até o tempo de execução e quando todas as chaves forem do mesmo tipo e todos os valores forem do mesmo tipo.
Use mapas no caso de haver necessidade de armazenar valores primitivos como chaves, pois o objeto trata cada chave como uma sequência, seja um valor numérico, booleano ou qualquer outro valor primitivo.
Use objetos quando houver lógica que opere em elementos individuais.
Fonte: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Keyed_Collections#Object_and_Map_compared
fonte
Esta é uma maneira curta de me lembrar: KOI
NaN
etc. Eles são usados===
para distinguir as chaves, com uma exceção,NaN !== NaN
mas você pode usarNaN
como chave.[...map]
ou[...map.keys()]
tem uma ordem específica.obj[key]
ouobj.a
(em algum idioma[]
e[]=
realmente faz parte da interface). Mapa temget()
,set()
,has()
,delete()
etc. Note que você pode usarmap[123]
, mas que está a usá-lo como um objeto JS simples.fonte
De acordo com a Mozilla
Objeto vs Mapa em JavaScript de maneira resumida, com exemplos.
Objeto - segue o mesmo conceito do mapa, isto é, usando o par de valores-chave para armazenar dados. Mas há pequenas diferenças que tornam o mapa um melhor desempenho em determinadas situações.
Mapa- é uma estrutura de dados que ajuda a armazenar os dados na forma de pares. O par consiste em uma chave exclusiva e um valor mapeado para a chave. Ajuda a evitar duplicidade.
Principais diferenças
fonte