One place for hosting & domains

      Objetos

      Cómo configurar un servidor de almacenamiento de objetos con Minio en Ubuntu 18.04


      El autor seleccionó a Open Internet/Free Speech Fund para recibir una donación como parte del programa Write for DOnations.

      Introducción

      Desde las soluciones de copia de seguridad basadas en la nube hasta las redes de entrega de contenido (CDN) de alta disponibilidad, la capacidad de almacenar datos de objetos no estructurados y hacer que sean accesibles a través de API HTTP, lo que se conoce como almacenamiento de objetos, se ha convertido en una parte integral del ámbito de la tecnología moderna.

      Minio es un servidor de almacenamiento de objetos de código abierto compatible con el servicio de almacenamiento en la nube de Amazon-S3. Las aplicaciones configuradas para comunicarse con Amazon S3 también se pueden configurar para hacerlo con Minio, lo cual permite que Minio sea una alternativa viable a S3 cuando se desea obtener más control sobre el servidor de almacenamiento de objetos. El servicio almacena datos no estructurados, como fotos, videos, archivos de registro, copias de seguridad e imágenes de contenedores o VM, e, incluso, puede proporcionar un único servidor de almacenamiento de objetos que agrupa varias unidades de muchos servidores.

      Minio se escribe en Go, cuenta con un cliente de línea de comandos más una interfaz de navegador y admite un servicio de colas simple para objetivos del protocolo avanzado de colas de mensajes (AMQP), Elasticsearch, Redis, NATS y PostgreSQL.  Por todas estas razones, aprender a configurar un servidor de almacenamiento de objetos de Minio puede añadir mucha flexibilidad y utilidad a su proyecto.

      En este tutorial, hará lo siguiente:

      • Instalará el servidor Minio en su servidor de Ubuntu 18.04 y lo configurará como servicio systemd.

      • Configurará un certificado SSL/TLS con Let´s Encrypt para garantizar la comunicación entre el servidor y el cliente.

      • Accederá a la interfaz de navegador de Minio a través de HTTPS para usar y administrar el servidor.

      Requisitos previos

      Para completar este tutorial, necesitará lo siguiente:

      • Un servidor de Ubuntu 18.04 configurado conforme a nuestro tutorial de configuración inicial para servidores de Ubuntu 18.04, un usuario sudo no root y un firewall.

      • Un nombre de dominio registrado por completo. Puede adquirir uno en Namecheap u obtener uno de forma gratuita en Freenom. En este tutorial, su dominio se representará como your_domain.

      • Los siguientes registros de DNS configurados para su servidor Minio. Puede consultar nuestra documentación de registros de DNS para obtener información detallada sobre cómo añadirlos a un Droplet de DigitalOcean.

        • Un registro A con el nombre de su servidor (por ejemplo, minio-server.your_domain) orientado a la dirección de IPv4 de su servidor de objetos.
        • (Opcional) Si desea que sea posible acceder a su servidor mediante IPv6, necesitará un registro AAAA con el nombre de su servidor orientado a la dirección IPv6 de su servidor.

      Paso 1: Instalar y configurar el servidor Minio

      Puede instalar el servidor Minio compilando el código fuente o a través de un archivo binario. Para instalarlo desde la fuente, debe tener, como mínimo, Go 1.12 instalado en su sistema.

      En este paso, instalará el servidor a través del binario previamente compilado y, luego, configurará el servidor Minio.

      Primero, inicie sesión en su servidor y sustituya sammy por su nombre de usuario y your_server_ip por la dirección IP de su servidor de Ubuntu 18.04.

      Si no actualizó la base de datos de paquetes recientemente, hágalo ahora:

      A continuación, descargue el archivo binario del servidor Minio del sitio web oficial:

      • wget https://dl.min.io/server/minio/release/linux-amd64/minio

      Obtendrá un resultado similar al siguiente:

      Output

      --2019-08-27 15:08:49-- https://dl.min.io/server/minio/release/linux-amd64/minio Resolving dl.min.io (dl.min.io)... 178.128.69.202 Connecting to dl.min.io (dl.min.io)|178.128.69.202|:443... connected. HTTP request sent, awaiting response... 200 OK Length: 44511616 (42M) [application/octet-stream] Saving to: ‘minio’ minio 100%[===================>] 42.45M 21.9MB/s in 1.9s 2019-08-27 15:08:51 (21.9 MB/s) - ‘minio’ saved [44511616/44511616]

      Una vez que la descarga haya finalizado, se ubicará un archivo llamado minio en su directorio de trabajo. Utilice el siguiente comando para que se pueda ejecutar:

      Ahora, mueva el archivo al directorio /usr/local/bin, donde la secuencia de comandos de inicio systemd de Minio espera encontrarlo:

      • sudo mv minio /usr/local/bin

      Esto nos permitirá escribir un archivo de unidad de servicio más adelante en este tutorial para ejecutar Minio de forma automática durante el inicio.

      Por motivos de seguridad, es mejor evitar ejecutar el servidor Minio como root. Esto limitará el daño al que su sistema se expondrá si se ve comprometido. Debido a que la secuencia de comandos systemd que usará en el paso 2 busca una cuenta de usuario y un grupo denominado minio-user, se creará un nuevo usuario con este nombre:

      • sudo useradd -r minio-user -s /sbin/nologin

      En este comando, utilizó el indicador -s para establecer /sbin/nologin como shell para minio-user. Este es un shell que no permite el inicio de sesión de usuario, que no es necesario para minio-user.

      A continuación, cambie la propiedad del binario de Minio a minio-user:

      • sudo chown minio-user:minio-user /usr/local/bin/minio

      Luego, creará un directorio donde Minio almacenará archivos. Esta será la ubicación de almacenamiento de los depósitos que usará más adelante para organizar los objetos que almacenará en su servidor Minio. En este tutorial, el directorio recibirá el nombre minio:

      • sudo mkdir /usr/local/share/minio

      Conceda la propiedad de ese directorio a minio-user:

      • sudo chown minio-user:minio-user /usr/local/share/minio

      La mayoría de los archivos de configuración del servidor se almacenan en el directorio /etc. Por ello, debe crear el archivo de configuración de Minio allí:

      Conceda, también, la propiedad de ese directorio a minio-user:

      • sudo chown minio-user:minio-user /etc/minio

      Utilice Nano o el editor de texto que desee para crear el archivo de entorno necesario para modificar la configuración predeterminada:

      • sudo nano /etc/default/minio

      Una vez que el archivo esté abierto, añada las siguientes líneas para establecer algunas variables de entorno importantes en su archivo de entorno:

      /etc/default/minio

      MINIO_ACCESS_KEY="minio"
      MINIO_VOLUMES="/usr/local/share/minio/"
      MINIO_OPTS="-C /etc/minio --address your_server_ip:9000"
      MINIO_SECRET_KEY="miniostorage"
      

      Veamos estas variables y los valores que estableció:

      • MINIO_ACCESS_KEY: establece la clave de acceso que usará para acceder a la interfaz de usuario del navegador de Minio.
      • MINIO_SECRET_KEY: establece la clave privada que usará para completar sus credenciales de inicio de sesión en la interfaz de Minio. En este tutorial, se fijó el valor en miniostorage, pero aconsejamos elegir una contraseña diferente, más compleja, para proteger su servidor.
      • MINIO_VOLUMES: identifica el directorio de almacenamiento que creó para sus depósitos.
      • MINIO_OPTS: cambia el lugar y la manera en que el servidor proporciona los datos. El indicador -C apunta Minio al directorio de configuración que debe usar, y el indicador --address indica a Minio la dirección de IP y el puerto con los que se debe establecer la vinculación. Si no se especifica la dirección IP, Minio se vinculará a cualquier dirección configurada en el servidor, incluso localhost y cualquier dirección IP relacionada con Docker. Por lo tanto, se recomienda especificar la dirección IP directamente aquí. Puede cambiar el puerto predeterminado 9000 si lo desea.

      Por último, guarde y cierre el archivo de entorno cuando haya terminado de realizar cambios.

      Con esto, instaló Minio y estableció algunas variables de entorno importantes. A continuación, configurará el servidor para que se ejecute como servicio de sistema.

      Paso 2: Instalar la secuencia de comandos de inicio Systemd de Minio

      En este paso, configurará el servidor Minio para que se administre como servicio systemd.

      Primero, descargue el archivo descriptor del servicio de Minio oficial con el siguiente comando:

      • curl -O https://raw.githubusercontent.com/minio/minio-service/master/linux-systemd/minio.service

      Obtendrá un resultado similar al siguiente:

      Output

      % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 835 100 835 0 0 6139 0 --:--:-- --:--:-- --:--:-- 6139

      Una vez que la descarga haya finalizado, se ubicará un archivo llamado minio.service en su directorio de trabajo.

      Para verificar el contenido de minio.service antes de aplicarlo, ábralo en un editor de texto para ver su contenido:

      Con esto, se mostrará lo siguiente:

      /etc/systemd/system/minio.service

      [Unit]
      Description=MinIO
      Documentation=https://docs.min.io
      Wants=network-online.target
      After=network-online.target
      AssertFileIsExecutable=/usr/local/bin/minio
      
      [Service]
      WorkingDirectory=/usr/local/
      
      User=minio-user
      Group=minio-user
      
      EnvironmentFile=/etc/default/minio
      ExecStartPre=/bin/bash -c "if [ -z "${MINIO_VOLUMES}" ]; then echo "Variable MINIO_VOLUMES not set in /etc/default/minio"; exit 1; fi"
      
      ExecStart=/usr/local/bin/minio server $MINIO_OPTS $MINIO_VOLUMES
      
      # Let systemd restart this service always
      Restart=always
      
      # Specifies the maximum file descriptor number that can be opened by this process
      LimitNOFILE=65536
      
      # Disable timeout logic and wait until process is stopped
      TimeoutStopSec=infinity
      SendSIGKILL=no
      
      [Install]
      WantedBy=multi-user.target
      
      # Built for ${project.name}-${project.version} (${project.name})
      

      Este archivo de unidad de servicio inicia el servidor Minio con el usuario minio-user que creó anteriormente. También implementa las variables de entorno que estableció en el último paso y hace que el servidor se ejecute automáticamente durante el inicio. Para obtener más información sobre los archivos de unidad systemd, consulte nuestra guía Información sobre unidades Systemd y archivos de unidad.

      Una vez que haya analizado el contenido de la secuencia de comandos, cierre su editor de texto.

      Systemd requiere que los archivos de unidad se almacenen en el directorio de configuración systemd, por lo tanto, mueva minio.service allí:

      • sudo mv minio.service /etc/systemd/system

      Luego, ejecute el siguiente comando para volver a cargar todas las unidades systemd:

      • sudo systemctl daemon-reload

      Por último, habilite Minio para que se inicie en el arranque:

      • sudo systemctl enable minio

      Esto generará el siguiente resultado:

      Output

      Created symlink from /etc/systemd/system/multi-user.target.wants/minio.service to /etc/systemd/system/minio.service.

      Ahora que la secuencia de comandos systemd está instalada y configurada, es el momento de iniciar el servidor.

      Paso 3: Iniciar el servidor Minio

      En este paso, iniciará el servidor y modificará el firewall para permitir el acceso a través de la interfaz del navegador.

      Primero, inicie el servidor Minio:

      • sudo systemctl start minio

      A continuación, verifique el estado de Minio, la dirección IP a la que está vinculado, su consumo de memoria y otros aspectos mediante este comando:

      • sudo systemctl status minio

      Verá el siguiente resultado:

      Output

      ● minio.service - MinIO Loaded: loaded (/etc/systemd/system/minio.service; enabled; vendor preset: enabled) Active: active (running) since Mon 2019-12-09 21:54:02 UTC; 46s ago Docs: https://docs.min.io Process: 3405 ExecStartPre=/bin/bash -c if [ -z "${MINIO_VOLUMES}" ]; then echo "Variable MINIO_VOLUMES not set in /etc/default/minio"; exit 1; fi (code=exited, status=0/SUCCES Main PID: 3407 (minio) Tasks: 7 (limit: 1152) CGroup: /system.slice/minio.service └─3407 /usr/local/bin/minio server -C /etc/minio --address your_server_IP:9000 /usr/local/share/minio/ Dec 09 21:54:02 cart-Minion-Object-1804-1 systemd[1]: Started MinIO. Dec 09 21:54:03 cart-Minion-Object-1804-1 minio[3407]: Endpoint: http://your_server_IP:9000 Dec 09 21:54:03 cart-Minion-Object-1804-1 minio[3407]: Browser Access: Dec 09 21:54:03 cart-Minion-Object-1804-1 minio[3407]: http://your_server_IP:9000 ...

      A continuación, habilite el acceso a través del firewall al servidor Minio en el puerto configurado. En este tutorial, se utiliza el puerto 9000.

      Primero, añada esta regla:

      Luego, habilite el firewall:

      Verá el siguiente mensaje:

      Output

      Command may disrupt existing ssh connections. Proceed with operation (y|n)?

      Pulse y e INTRO para confirmarlo. Obtendrá el siguiente resultado:

      Output

      Firewall is active and enabled on system startup

      Minio está listo para aceptar tráfico, pero antes de establecer conexión con el servidor protegerá la comunicación al instalar un certificado SSL/TLS.

      Paso 4: Proteger el acceso a su servidor Minio con un certificado TLS

      En este paso, protegerá el acceso a su servidor Minio con una clave privada y un certificado público obtenido de una autoridad de certificación (CA); en este caso, Let´s Encrypt. Para obtener un certificado SSL gratuito, usará Certbot.

      Primero, permita el acceso HTTP y HTTPS a través de su firewall. Para hacerlo, abra el puerto 80, que es el puerto para HTTP:

      A continuación, abra el puerto 443 para HTTPS:

      Una vez que haya añadido estas reglas, compruebe el estado de su firewall con el siguiente comando:

      Obtendrá un resultado similar al siguiente:

      Output

      Status: active Logging: on (low) Default: deny (incoming), allow (outgoing), disabled (routed) New profiles: skip To Action From -- ------ ---- 22/tcp (OpenSSH) ALLOW IN Anywhere 9000 ALLOW IN Anywhere 443 ALLOW IN Anywhere 80 ALLOW IN Anywhere 22/tcp (OpenSSH (v6)) ALLOW IN Anywhere (v6) 9000 (v6) ALLOW IN Anywhere (v6) 443 (v6) ALLOW IN Anywhere (v6) 80 (v6) ALLOW IN Anywhere (v6)

      Esto confirma que los puertos 80 y 443 están abiertos, lo cual garantiza que su servidor acepta solicitudes de Internet.

      A continuación, instalará Certbot. Debido a que Certbot mantiene un repositorio PPA independiente, deberá añadirlo a su lista de repositorios antes de instalar Certbot, como se indica a continuación:

      Para prepararse para agregar el repositorio PPA, primero instale software-properties-common, un paquete de administración de PPA:

      • sudo apt install software-properties-common

      Este paquete proporciona algunas secuencias de comandos útiles para añadir y eliminar PPA, y evitar hacer el proceso manualmente.

      Ahora, añada el repositorio Universe:

      • sudo add-apt-repository universe

      Este repositorio contiene software gratuito de código abierto cuyo mantenimiento está a cargo de la comunidad de Ubuntu, aunque esto no se realiza oficialmente a través de Canonical, la empresa desarrolladora de Ubuntu. Aquí es donde encontraremos el repositorio para Certbot.

      A continuación, añada el repositorio de Certbot:

      • sudo add-apt-repository ppa:certbot/certbot

      Recibirá el siguiente resultado:

      Output

      This is the PPA for packages prepared by Debian Let's Encrypt Team and backported for Ubuntu(s). More info: https://launchpad.net/~certbot/+archive/ubuntu/certbot Press [ENTER] to continue or ctrl-c to cancel adding it

      Pulse INTRO para aceptar.

      Luego, actualice la lista de paquetes:

      Por último, instale certbot:

      A continuación, usará certbot para generar un nuevo certificado SSL.

      Debido a que Ubuntu 18.04 todavía no admite la instalación automática, usará los comandos certonly y --standalone para obtener el certificado:

      • sudo certbot certonly --standalone -d minio-server.your_domain

      --standalone significa que este certificado es para un servidor web independiente incorporado. Para obtener más información al respecto, consulte nuestro tutorial Cómo utilizar el modo independiente de Certbot para obtener certificados SSL de Let´s Encrypt en Ubuntu 18.04.

      Recibirá el siguiente resultado:

      Output

      Saving debug log to /var/log/letsencrypt/letsencrypt.log Plugins selected: Authenticator standalone, Installer None Enter email address (used for urgent renewal and security notices) (Enter 'c' to cancel):

      Añada su correo electrónico y presione INTRO.

      Certbot le solicitará registrarse en Let´s Encrypt:

      Output

      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Please read the Terms of Service at https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf. You must agree in order to register with the ACME server at https://acme-v02.api.letsencrypt.org/directory - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - (A)gree/(C)ancel:

      Escriba A y presione ENTER para aceptar.

      A continuación, se le preguntará si está dispuesto a compartir su correo electrónico con Electronic Frontier Foundation:

      Output

      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Would you be willing to share your email address with the Electronic Frontier Foundation, a founding partner of the Let's Encrypt project and the non-profit organization that develops Certbot? We'd like to send you email about our work encrypting the web, EFF news, campaigns, and ways to support digital freedom. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - (Y)es/(N)o:

      Una vez que responda Y o N, se generarán y almacenarán sus claves públicas y privadas en el directorio /etc/letsencrypt/live/minio-server.your_domain_name.

      A continuación, copie estos dos archivos (privkey.pem y fullchain.pem) al directorio certs, en la carpeta de configuración del servidor Minio, que es /etc/minio en este tutorial. Utilice lo siguiente para copiar privkey.pem y cambiar el nombre del archivo private.key.

      • sudo cp /etc/letsencrypt/live/minio-server.your_domain_name/privkey.pem /etc/minio/certs/private.key

      Luego, realice lo mismo para fullchain.pem y asigne el nombre public.crt al resultado:

      • sudo cp /etc/letsencrypt/live/minio-server.your_domain_name/fullchain.pem /etc/minio/certs/public.crt

      Ahora, cambie la propiedad de los archivos a minio-user. Primero, hágalo con private.key:

      • sudo chown minio-user:minio-user /etc/minio/certs/private.key

      Luego, con public.crt:

      • sudo chown minio-user:minio-user /etc/minio/certs/public.crt

      Reinstalará el servidor Minio para que reconozca el certificado y se inicie con HTTPS:

      • sudo systemctl restart minio

      Los certificados de Let’s Encrypt son válidos únicamente por noventa días. El propósito de esto es incentivar a los usuarios a automatizar sus procesos de renovación de certificados. El paquete de Certbot que instaló añade automáticamente una secuencia de comandos de renovación a /etc/cron.d. Esta secuencia de comandos se ejecuta dos veces al día y renovará de forma automática cualquier certificado que caduque en treinta o menos días.

      Con esto, la conexión de Minio ahora estará protegida y el certificado SSL/TLS se renovará automáticamente. En el siguiente paso, establecerá conexión con Minio a través del navegador para usar el servidor.

      Paso 5: Conectarse de forma segura a la interfaz web de Minio con HTTPS

      En este paso, se conectará de forma segura a la interfaz web de Minio a través de HTTPS, y luego creará depósitos en los que cargará objetos.

      Acceda a la interfaz web apuntando su navegador a https://minio-server.your_domain:9000.

      Verá la pantalla de inicio de sesión del servidor Minio:

      Pantalla de inicio de sesión de Minio

      Ahora, inicie sesión en la interfaz principal ingresando sus credenciales. En Acces Key, ingrese la MINIO_ACCESS_KEY que configuró en el archivo de entorno /etc/default/minio, en el paso 1. En Secret Key, ingrese la MINIO_SECRET_KEY que configuró en el mismo archivo. Una vez que haya ingresado las credenciales, haga clic en el botón redondo que tiene la flecha y se halla directamente debajo de los campos de entrada.

      Luego, se le presentará la interfaz de usuario de Minio. Para crear un nuevo depósito en el que pueda almacenar objetos, haga clic en el botón rojo claro + en la parte inferior derecha de la interfaz principal para acceder a dos botones amarillos adicionales.

      Interfaz principal de Minio

      Haga clic en el botón amarillo del medio, ingrese un nombre para su nuevo depósito en el mensaje y pulse la tecla INTRO para guardar su respuesta. Su nuevo depósito está listo para usarse para almacenamiento.

      Nota: Al asignar un nombre a su depósito de Minio, asegúrese de que solo contenga letras minúsculas, números o guiones. Minio limita las convenciones de nomenclatura de los depósitos para que sean compatibles con las normas de AWS S3.

      Cuando desee añadir objetos en su depósito, haga clic en el mismo botón rojo claro de antes y luego en el botón amarillo superior para abrir un mensaje de carga de archivos.

      En este punto, trabajó en toda la interfaz web básica de creación de depósitos y carga objetos.

      Conclusión

      Ahora, dispondrá de su propio servidor de almacenamiento de objetos Minio al que podrá conectarse de forma segura desde la interfaz web con un certificado SSL/TLS de Let´s Encrypt. De forma opcional, posiblemente le convenga considerar los clientes de escritorio de Minio para FreeBSD, Linux, Mac y Windows como alternativas para usar y administrar su servidor de almacenamiento de objetos.

      Además, si desea aumentar la capacidad de almacenamiento de su instalación de Minio más allá de la capacidad de almacenamiento en disco de disco de su servidor, puede usar el servicio de almacenamiento de bloque de DigitalOcean para añadir un volumen a su servidor y ampliar la capacidad de almacenamiento hasta 80 TB.

      Puede encontrar más información sobre Minio en el sitio web de documentación de proyectos. Si desea obtener más información sobre el almacenamiento de objetos, consulte nuestros tutoriales de almacenamiento de objetos.



      Source link

      Entendendo os objetos Map e Conjunto no JavaScript


      O autor selecionou a Open Internet/Free Speech Fund para receber uma doação como parte do programa Write for DOnations.

      No JavaScript, os desenvolvedores geralmente gastam bastante tempo decidindo a estrutura de dados correta a ser usada. Isso acontece porque escolher a estrutura de dados correta pode facilitar a manipulação desses dados mais tarde, economizando tempo e facilitando a compreensão do código. As duas estruturas de dados predominantes para armazenar coleções de dados são Objetos e Matrizes (um tipo de objeto). Os desenvolvedores usam os Obejtos para armazenar pares de chave-valor e Matrizes para armazenar listas indexadas. No entanto, para dar maior flexibilidade aos desenvolvedores, a especificação ECMAScript 2015 introduziu dois novos tipos de objetos iteráveis: Maps, que são coleções ordenadas de pares chave-valor e Conjuntos, que são coleções de valores únicos.

      Neste artigo, você irá analisar os objetos Map e Conjunto, o que os torna semelhantes e diferentes dos Objetos e Matrizes, as propriedades e métodos disponíveis para eles, bem como exemplos de alguns usos práticos.

      Maps

      Um Map é uma coleção de pares chave-valor que pode usar qualquer tipo de dados como uma chave e manter a ordem de suas entradas. Os Maps têm elementos de ambos os Objetos (uma coleção única de pares chave-valor) e Matrizes (uma coleção ordenada). Porém, conceitualmente, eles são mais parecidos aos Objetos. Isso acontece porque, embora o tamanho e a ordem das entradas sejam preservados como em uma Matriz, as entradas – propriamente ditas – são pares chave-valor, como os Objetos.

      Os Maps podem ser inicializados com a sintaxe new Map():

      const map = new Map()
      

      Isso nos dá um Map vazio:

      Output

      Map(0) {}

      Como adicionar valores a um Map

      Você pode adicionar valores a um mapa com o método set(). O primeiro argumento será a chave e o segundo argumento será o valor.

      Isto adiciona três pares chave-valor ao map:

      map.set('firstName', 'Luke')
      map.set('lastName', 'Skywalker')
      map.set('occupation', 'Jedi Knight')
      

      Aqui, começamos a ver como os Maps têm elementos tanto de Objetos como de Matrizes. Assim como acontece com uma Matriz, temos uma coleção com índice zero e podermos ver também quantos itens estão no Map por padrão. Os Maps usam a sintaxe => para representar os pares chave-valor como key => value:

      Output

      Map(3) 0: {"firstName" => "Luke"} 1: {"lastName" => "Skywalker"} 2: {"occupation" => "Jedi Knight"}

      Esse exemplo se assemelha a um objeto regular com chaves baseadas em string, mas podemos usar qualquer tipo de dados como uma chave com os Maps.

      Além de definir manualmente os valores em um Map, podemos também inicializar um Map já com valores. Fazemos isso usando uma Matriz de Matrizes contendo dois elementos, sendo cada um um par chave-valor, que têm a seguinte aparência:

      [ [ 'key1', 'value1'], ['key2', 'value2'] ]
      

      Ao usar a sintaxe a seguir, podemos recriar o mesmo Map:

      const map = new Map([
        ['firstName', 'Luke'],
        ['lastName', 'Skywalker'],
        ['occupation', 'Jedi Knight'],
      ])
      

      Nota: este exemplo usa as vírgulas à direita, também conhecidas como vírgulas pendentes. Trata-se de uma prática de formatação do JavaScript na qual o item final de uma série – ao se declarar uma coleção de dados – tem uma vírgula no final. Embora essa escolha de formatação possa ser usada para obter diferenças de limpeza e uma manipulação de código mais fácil, usar isso ou não é uma questão de preferência. Para obter mais informações sobre as vírgulas à direita, consulte este artigo de Vírgulas à direita dos documentos Web da MDN (Mozilla Developer Network).

      A propósito, essa sintaxe é a mesma do resultado da chamada Object.entries() em um Objeto. Isso proporciona uma maneira pronta de converter um Objeto em um Map, como mostrado no bloco de código a seguir:

      const luke = {
        firstName: 'Luke',
        lastName: 'Skywalker',
        occupation: 'Jedi Knight',
      }
      
      const map = new Map(Object.entries(luke))
      

      Como alternativa, você pode transformar um Map de volta em um Objeto ou uma Matriz com uma única linha de código.

      O seguinte converte um Map em um Objeto:

      const obj = Object.fromEntries(map)
      

      Isso resultará no seguinte valor de obj:

      Output

      {firstName: "Luke", lastName: "Skywalker", occupation: "Jedi Knight"}

      Agora, vamos converter um Map em uma Matriz:

      const arr = Array.from(map)
      

      Isso resultará na seguinte Matriz para arr:

      Output

      [ ['firstName', 'Luke'], ['lastName', 'Skywalker'], ['occupation', 'Jedi Knight'] ]

      Chaves de Map

      Os Maps aceitam qualquer tipo de dados como uma chave e não permitem valores de chave duplicados. Podemos demonstrar isso criando um mapa e usando valores não string como chaves, além de definir dois valores para a mesma chave.

      Primeiro, vamos inicializar um mapa com chaves não string:

      const map = new Map()
      
      map.set('1', 'String one')
      map.set(1, 'This will be overwritten')
      map.set(1, 'Number one')
      map.set(true, 'A Boolean')
      

      Esse exemplo irá sobrepor a primeira chave de 1 com a seguinte e tratará a string '1' e o número 1 como chaves únicas:

      Output

      0: {"1" => "String one"} 1: {1 => "Number one"} 2: {true => "A Boolean"}

      Embora acredite-se que um Objeto regular JavaScript já possa lidar com os Números, os booleanos e outros tipos de dados primitivos como chaves, isso não é, de fato, o caso, já que Objetos transformam todas as chaves em strings.

      Como exemplo, inicialize um objeto com uma chave numérica e compare o valor para a chave numérica 1 e a chave em string "1":

      // Initialize an object with a numerical key
      const obj = { 1: 'One' }
      
      // The key is actually a string
      obj[1] === obj['1']  // true
      

      É por isso que, se você tentar usar um Objeto como uma chave, ele imprimirá a string object Object em vez disso.

      Como exemplo, crie um Objeto e, em seguida, use-o como chave de outro Objeto:

      // Create an object
      const objAsKey = { foo: 'bar' }
      
      // Use this object as the key of another object
      const obj = {
        [objAsKey]: 'What will happen?'
      }
      

      Isso irá resultar no seguinte:

      Output

      {[object Object]: "What will happen?"}

      Isso não acontece com o Map. Tente criar um Objeto e configurá-lo como a chave de um Map:

      // Create an object
      const objAsKey = { foo: 'bar' }
      
      const map = new Map()
      
      // Set this object as the key of a Map
      map.set(objAsKey, 'What will happen?')
      

      Agora, a key do elemento Map é o objeto que criamos.

      Output

      key: {foo: "bar"} value: "What will happen?"

      Existe uma coisa importante a se observar sobre o uso de um Objeto ou Matriz como uma chave: o Map está usando a referência ao Objeto para comparar a igualdade, não o valor literal do Objeto. No JavaScript {} === {} retorna false, uma vez que os dois Objetos não são os mesmos dois Objetos, apesar de terem o mesmo valor (vazio).

      Isso significa que adicionar dois Objetos únicos com o mesmo valor criará um Map com duas entradas:

      // Add two unique but similar objects as keys to a Map
      map.set({}, 'One')
      map.set({}, 'Two')
      

      Isso irá resultar no seguinte:

      Output

      Map(2) {{…} => "One", {…} => "Two"}

      No entanto, usar a mesma referência de Objeto duas vezes criará um Map com uma entrada.

      // Add the same exact object twice as keys to a Map
      const obj = {}
      
      map.set(obj, 'One')
      map.set(obj, 'Two')
      

      O que dará como resultado o seguinte:

      Output

      Map(1) {{…} => "Two"}

      O segundo set() está atualizando exatamente a mesma chave que a primeira, de modo que acabamos com um Map que possui apenas um valor.

      Obtendo e excluindo itens de um Map

      Uma das desvantagens de se trabalhar com Objetos é que pode ser difícil enumerá-los, ou trabalhar com todos as chaves ou valores. A estrutura do Map, ao contrário, possui muitas propriedades embutidas que tornam mais direto o trabalho com seus elementos.

      Podemos inicializar um novo Map para demonstrar os métodos e propriedades a seguir: delete(), has(), get() e size.

      // Initialize a new Map
      const map = new Map([
        ['animal', 'otter'],
        ['shape', 'triangle'],
        ['city', 'New York'],
        ['country', 'Bulgaria'],
      ])
      

      Use o método has() para verificar se existe um item em um mapa. O has() retornará um Booleano.

      // Check if a key exists in a Map
      map.has('shark') // false
      map.has('country') // true
      

      Use o método get() para recuperar um valor pela chave.

      // Get an item from a Map
      map.get('animal') // "otter"
      

      Um benefício em particular que os Maps têm em relação aos Objetos é que você pode descobrir o tamanho de um Map a qualquer momento, assim como com uma Matriz. É possível obter a contagem de itens em um Map com a propriedade size (tamanho). Isso envolve menos passos do que converter um Objeto em uma Matriz para descobrir seu tamanho.

      // Get the count of items in a Map
      map.size // 4
      

      Use o método delete() para remover um item de um Map pela chave. O método retornará um Booleano — true se já houver um item e tiver sido excluído e retornará um false se não corresponder a nenhum item.

      // Delete an item from a Map by key
      map.delete('city') // true
      

      Isso resulta no seguinte Map:

      Output

      Map(3) {"animal" => "otter", "shape" => "triangle", "country" => "Bulgaria"}

      Por fim, é possível limpar todos os valores do Map com o método map.clear().

      // Empty a Map
      map.clear()
      

      Isso produzirá o seguinte resultado:

      Output

      Map(0) {}

      Chaves, valores e entradas para Maps

      Os Objetos podem recuperar chaves, valores e entradas, usando as propriedades do construtor Object. Os Maps, por outro lado, têm métodos protótipos que nos permitem obter diretamente as chaves, valores e entradas da instância Map.

      Os métodos keys(), values() e entries() retornam todos um MapIterator, que se assemelha a uma Matriz na qual você pode usar for...of executar o loop nos valores.

      Apresentamos a seguir outro exemplo de um Map, que podemos usar para demonstrar esses métodos:

      const map = new Map([
        [1970, 'bell bottoms'],
        [1980, 'leg warmers'],
        [1990, 'flannel'],
      ])
      

      O método keys() retorna as chaves:

      map.keys()
      

      Output

      MapIterator {1970, 1980, 1990}

      O método values() retorna os valores:

      map.values()
      

      Output

      MapIterator {"bell bottoms", "leg warmers", "flannel"}

      O método entries() retorna uma matriz de pares chave-valor:

      map.entries()
      

      Output

      MapIterator {1970 => "bell bottoms", 1980 => "leg warmers", 1990 => "flannel"}

      Iteração com Map

      O Map tem um método integrado forEach, similar a uma Matriz, para iteração integrada. No entanto, existe um pouco de diferença quanto ao que eles iteram. O callback (retorno de chamada) do forEach de um Map itera value, key e map, propriamente dito, ao passo que a versão Matriz itera item, index e array, propriamente dito.

      // Map
      Map.prototype.forEach((value, key, map) = () => {})
      
      // Array
      Array.prototype.forEach((item, index, array) = () => {})
      

      Trata-se de uma grande vantagem dos Maps em relação aos Objetos, uma vez que os Objetos precisam ser convertidos com keys(), values(), ou entries() e não há uma maneira simples de recuperar as propriedades de um Objeto sem convertê-lo.

      Para demonstrar isso, vamos iterar nosso Map e registrar os pares chave-valor no console:

      // Log the keys and values of the Map with forEach
      map.forEach((value, key) => {
        console.log(`${key}: ${value}`)
      })
      

      Isso dará:

      Output

      1970: bell bottoms 1980: leg warmers 1990: flannel

      Como um loop for...of itera items iteráveis como Maps e Matrizes, podemos obter exatamente o mesmo resultado por meio da desestruturação da matriz dos itens do Map:

      // Destructure the key and value out of the Map item
      for (const [key, value] of map) {
        // Log the keys and values of the Map with for...of
        console.log(`${key}: ${value}`)
      }
      

      Propriedades e métodos de Map

      A tabela a seguir mostra uma lista de propriedades e métodos de Map, para referência rápida:

      Propriedades/Métodos Descrição Retorna
      set(key, value) Adiciona um par chave-valor a um Map Objeto Map
      delete(key) Remove um par chave-valor de um Map por chave Booleano
      get(key) Retorna um valor por meio da chave valor
      has(key) Verifica quanto à presença de um elemento em um Map por chave Booleano
      clear() Remove todos os itens de um Map N/A
      keys() Retorna todas as chaves em um Map Objeto MapIterator
      values() Retorna todas os valores em um Map Objeto MapIterator
      entries() Retorna todas as chaves e valores em um Map como [key, value] Objeto MapIterator
      forEach() Itera no Map por ordem de inserção N/A
      size Retorna o número de itens em um Map Número

      Quando usar um Map

      Em suma, os Maps são semelhantes aos Objetos no sentido de que têm pares de chave-valor, mas os Maps têm diversas vantagens em relação aos objetos:

      • Tamanho – Os Maps têm uma propriedade size, ao passo que os Objetos não têm uma maneira integrada de descobrir seu tamanho.
      • Iteração – Os Maps podem ser iterados diretamente, ao passo que os Objetos não.
      • Flexibilidade – Os Maps podem ter qualquer tipo de dados (primitivo ou Objeto) como a chave para um valor, enquanto Objetos admitem apenas strings.
      • Ordenados – Os Maps retêm sua ordem de inserção, ao passo que os objetos não têm uma ordem garantida.

      Devido a esses fatores, os Maps são uma estrutura de dados avançada a se considerar. No entanto, os Objetos têm também algumas vantagens importantes:

      • JSON – Os Objetos funcionam de maneira impecável com JSON.parse() e JSON.stringify(), duas funções essenciais para se trabalhar com o JSON, um formato de dados comum com os quais muitas APIs REST lidam.
      • Trabalhar com um único elemento – Ao trabalhar com um valor conhecido em um Objeto, você pode acessá-lo diretamente com a chave, sem a necessidade de usar um método, como o get() do Map.

      Essa lista ajudará você a decidir se um Map ou um Objeto é a estrutura de dados correta para o seu caso de uso.

      Conjunto

      Um Conjunto é uma coleção de valores únicos. Ao contrário de um Map, um Conjunto é conceitualmente mais parecido com uma Matriz do que um com um Objeto, já que é uma lista de valores e não pares chave-valor. No entanto, o Conjunto não é um substituto da Matriz, mas sim um suplemento que provém suporte adicional para se trabalhar com dados duplicados.

      Você pode inicializar os Conjuntos com a sintaxe new Set().

      const set = new Set()
      

      Isso nos dá um Conjunto vazio:

      Output

      Set(0) {}

      Os itens podem ser adicionados a um Conjunto com o método add(). (Isso não deve ser confundido com o método set() disponível para Map, embora sejam semelhantes.)

      // Add items to a Set
      set.add('Beethoven')
      set.add('Mozart')
      set.add('Chopin')
      

      Como os Conjuntos podem conter apenas valores únicos, qualquer tentativa de adicionar um valor que já exista será ignorada.

      set.add('Chopin') // Set will still contain 3 unique values
      

      Nota: a mesma comparação de igualdade que se aplica às chaves do Map se aplica aos itens do Conjunto. Dois objetos que têm o mesmo valor, mas não compartilham a mesma referência não serão considerados iguais.

      Também é possível inicializar os Conjuntos com uma Matriz de valores. Se houver valores duplicados na matriz, eles serão removidos do Conjunto.

      // Initialize a Set from an Array
      const set = new Set(['Beethoven', 'Mozart', 'Chopin', 'Chopin'])
      

      Output

      Set(3) {"Beethoven", "Mozart", "Chopin"}

      Por outro lado, um Conjunto pode ser convertido em uma Matriz com apenas uma linha de código:

      const arr = [...set]
      

      Output

      (3) ["Beethoven", "Mozart", "Chopin"]

      O Conjunto possui muitos dos mesmos métodos e propriedades do Mapa, incluindo delete(), has(), clear() e size.

      // Delete an item
      set.delete('Beethoven') // true
      
      // Check for the existence of an item
      set.has('Beethoven') // false
      
      // Clear a Set
      set.clear()
      
      // Check the size of a Set
      set.size // 0
      

      Observe que o Conjunto não tem um modo de acessar um valor por uma chave ou índice, como Map.get(key) ou arr[index].

      Chaves, valores e entradas para Conjuntos

      Tanto o Map quanto o Conjunto possui os métodos keys(), values() e entries() que retornam um Iterator. No entanto, embora cada um desses métodos tenha um objetivo distinto no Map, os Conjuntos não têm chaves e, portanto, chaves são um alias para os valores. Isso significa que os métodos keys() e values() retornarão o mesmo Iterator e as entries() retornarão o valor duas vezes. Assim, faz todo sentido usar apenas values() com Conjuntos, já que existem outros dois métodos para obter consistência e compatibilidade cruzada com o Map.

      const set = new Set([1, 2, 3])
      // Get the values of a set
      set.values()
      

      Output

      SetIterator {1, 2, 3}

      Iteração com Conjunto

      Assim como o Map, o Conjunto possui o método embutido forEach(). Como os Conjuntos não têm chaves, o primeiro e segundo parâmetros do callback do forEach() retornam o mesmo valor, de modo que não existe um caso de uso para ele além da compatibilidade com o Map. Os parâmetros do forEach() são (value, key, set).

      Tanto forEach() quanto for...of podem ser usado no Conjunto. Primeiro, vamos examinar a iteração forEach():

      const set = new Set(['hi', 'hello', 'good day'])
      
      // Iterate a Set with forEach
      set.forEach((value) => console.log(value))
      

      Depois, podemos escrever a versão for...of:

      // Iterate a Set with for...of
      for (const value of set) {  
          console.log(value);
      }
      

      Ambas essas estratégias resultarão no seguinte:

      Output

      hi hello good day

      Propriedades e métodos do Conjunto

      A tabela a seguir mostra uma lista de propriedades e métodos do Conjunto para referência rápida:

      Propriedades/Métodos Descrição Retorna
      add(value) Adiciona um novo item em um Conjunto Objeto Set
      delete(value) Remove o item especificado de um Conjunto Booleano
      has() Verifica quanto à presença de um item em um Conjunto Booleano
      clear() Remove todos os itens de um Conjunto N/A
      keys() Retorna todos os valores de um Conjunto (o mesmo que values()) Objeto SetIterator
      values() Retorna todos os valores de um Conjunto (o mesmo que keys()) Objeto SetIterator
      entries() Retorna todos os valores de um Conjunto como [value, value] Objeto SetIterator
      forEach() Itera no Conjunto por ordem de inserção N/A
      size Retorna o número de itens em um Conjunto Número

      Quando usar um Conjunto

      O Conjunto é um complemento útil ao seu conjunto de ferramentas do JavaScript, especialmente para trabalhar com valores duplicados de dados.

      Numa única linha, podemos criar uma nova Matriz, sem duplicar valores de uma Matriz que possua valores duplicados.

      const uniqueArray = [ ...new Set([1, 1, 2, 2, 2, 3])] // (3) [1, 2, 3]
      

      Isso dará:

      Output

      (3) [1, 2, 3]

      O Conjunto pode ser usado para encontrar a união, a intersecção e a diferença entre dois conjuntos de dados. No entanto, as Matrizes têm uma vantagem significativa em relação aos Conjuntos para manipulação adicional dos dados, devidos aos métodos sort(), map(), filter() e reduce(), bem como uma compatibilidade direta com os métodos JSON.

      Conclusão

      Neste artigo, você aprendeu que um Map é uma coleção de pares chave-valor ordenados e que um Conjunto é uma coleção de valores únicos. Ambas essas estruturas de dados contribuem com capacidades adicionais ao JavaScript e simplificam tarefas comuns, como descobrir o tamanho de uma coleção de pares chave-valor e remover itens duplicados de um conjunto de dados, respectivamente. Por outro lado, Objetos e Matrizes vem sendo tradicionalmente usados para o armazenamento e manipulação de dados no JavaScript. Eles têm compatibilidade direta com o JSON, fazendo deles as estruturas de dados mais essenciais, especialmente para trabalhar com as APIs REST. Os Maps e Conjuntos são úteis principalmente como estruturas de dados que auxiliam os Objetos e as Matrizes.

      Se quiser aprender mais sobre o JavaScript, confira a página inicial de nossa série sobre Como programar em JavaScript, ou pesquise nossa série sobre Como programar em Node.js para obter artigos sobre o desenvolvimento de back-end.



      Source link

      Información sobre los objetos Map y Set en JavaScript


      El autor seleccionó a Open Internet/Free Speech Fund para recibir una donación como parte del programa Write for DOnations.

      En el ámbito de JavaScript, a menudo los desarrolladores pasan mucho tiempo decidiendo la estructura de datos correcta que se usará. Esto se debe a que elegir la estructura de datos correcta puede facilitar la manipulación de esos datos posteriormente, con lo cual se puede ahorrar tiempo y facilitar la comprensión del código. Las dos estructuras de datos predominantes para almacenar conjuntos de datos son los Object y Array (un tipo de objeto). Los desarrolladores utilizan Object para almacenar pares clave-valor y Array para almacenar listas indexadas. Sin embargo, para dar más flexibilidad a los desarrolladores, en la especificación ECMAScript 2015 se introdujeron dos nuevos tipos de objetos iterables: los Map, que son grupos ordenados de pares clave-valor, y los Set, que son grupos de valores únicos.

      En este artículo, repasará los objetos Map y Set, veremos qué los hace similares o diferentes de los Object y Array, las propiedades y los métodos disponibles para ellos y ejemplos de algunos usos prácticos.

      Map

      Un Map es un grupo de pares clave-valor en el que se puede usar cualquier tipo de datos como clave y que puede mantener el orden de sus entradas. En los Map se incluyen elementos tanto de Object (un grupo único de pares clave-valor) como de Array (un grupo ordenado), pero conceptualmente son más parecidos a los Object. Esto se debe a que, si bien el tamaño y el orden de las entradas se mantiene como en un Array, las propias entradas son pares clave-valor como los Object.

      Los Map se pueden inicializar con la sintaxis new Map():

      const map = new Map()
      

      Esto nos proporciona un Map vacío:

      Output

      Map(0) {}

      Añadir valores a un Map

      Puede añadir valores a un mapa con el método set(). En el primer argumento se representará la clave y en el segundo el valor.

      A continuación, se añaden tres pares clave-valor a map:

      map.set('firstName', 'Luke')
      map.set('lastName', 'Skywalker')
      map.set('occupation', 'Jedi Knight')
      

      Aquí, empezamos a ver cómo en los Map se encuentran elementos tanto de Object como de Array. Como en el caso de un Array, tenemos un grupo con índice cero y también podemos ver la cantidad de elementos disponibles por defecto en el Map. En los Map se utiliza la sintaxis => para indicar los pares clave-valor como key => value:

      Output

      Map(3) 0: {"firstName" => "Luke"} 1: {"lastName" => "Skywalker"} 2: {"occupation" => "Jedi Knight"}

      Este ejemplo se parece a un objeto normal con claves basadas en cadenas, pero con los Map podemos usar cualquier tipo de datos como clave.

      Además de establecer los valores manualmente en un Map, también podemos inicializarlo con estos ya incluidos. Esto se hace utilizando un Array de Array, con dos elementos que son cada uno pares clave-valor, que tiene el siguiente aspecto:

      [ [ 'key1', 'value1'], ['key2', 'value2'] ]
      

      Usando la siguiente sintaxis, podemos volver a crear el mismo Map:

      const map = new Map([
        ['firstName', 'Luke'],
        ['lastName', 'Skywalker'],
        ['occupation', 'Jedi Knight'],
      ])
      

      Nota: En este ejemplo se utilizan las comas al final, también conocidas como comas pendientes. Esta es una práctica de formato de JavaScript en la cual, cuando se declara un grupo de datos, el elemento final de una serie tiene una coma al final. Aunque esta opción de formato puede utilizarse para lograr diferenciales más limpios y facilitar la manipulación del código, su uso está atado a la preferencia. Para obtener más información sobre las comas al final, consulte este artículo de Comas al final de los documentos web de MDN.

      De hecho, esta sintaxis es la misma que la del resultado de la invocación de Object.entries() en un Object. Esto ofrece una alternativa ya creada para convertir un Object en un Map, como se muestra en el siguiente bloque de código:

      const luke = {
        firstName: 'Luke',
        lastName: 'Skywalker',
        occupation: 'Jedi Knight',
      }
      
      const map = new Map(Object.entries(luke))
      

      También puede convertir un Map de nuevo en un Object o Array con una sola línea de código.

      Con lo siguiente convertiremos un Map en un Object:

      const obj = Object.fromEntries(map)
      

      Esto dará como resultado el siguiente valor de obj:

      Output

      {firstName: "Luke", lastName: "Skywalker", occupation: "Jedi Knight"}

      Ahora, convertiremos un Map en un Array:

      const arr = Array.from(map)
      

      Esto dará como resultado el siguiente Array para arr:

      Output

      [ ['firstName', 'Luke'], ['lastName', 'Skywalker'], ['occupation', 'Jedi Knight'] ]

      Claves de Map

      En los Map se acepta cualquier tipo de datos como clave y no se permiten valores de clave duplicados. Podemos demostrarlo creando un mapa y usando valores que no sean de cadena como claves y estableciendo dos valores para la misma clave.

      Primero, iniciaremos un mapa con claves que no sean de cadena:

      const map = new Map()
      
      map.set('1', 'String one')
      map.set(1, 'This will be overwritten')
      map.set(1, 'Number one')
      map.set(true, 'A Boolean')
      

      En este ejemplo, se anulará la primera clave de 1 con la siguiente y se tratarán la cadena '1'​​​ y el número 1 como claves únicas:

      Output

      0: {"1" => "String one"} 1: {1 => "Number one"} 2: {true => "A Boolean"}

      Aunque comúnmente se cree que un Object normal de JavaScript puede usar números de antemano, booleanos y otros tipos de datos primitivos como claves, este realmente no es el caso debido a que los Object cambian todas las claves por cadenas.

      A modo de ejemplo, inicialice un objeto con una clave numérica y compare el valor para una clave numérica 1 y una clave "1" convertida a cadena.

      // Initialize an object with a numerical key
      const obj = { 1: 'One' }
      
      // The key is actually a string
      obj[1] === obj['1']  // true
      

      Es por esto que si intenta usar un Object como clave se imprimirá la cadena object Object en su lugar.

      Como ejemplo, cree un Object y luego utilícelo como clave de otro Object:

      // Create an object
      const objAsKey = { foo: 'bar' }
      
      // Use this object as the key of another object
      const obj = {
        [objAsKey]: 'What will happen?'
      }
      

      Obtendrá el siguiente resultado:

      Output

      {[object Object]: "What will happen?"}

      Este no es el caso de Map. Intente crear un Object y establecerlo como clave de un Map:

      // Create an object
      const objAsKey = { foo: 'bar' }
      
      const map = new Map()
      
      // Set this object as the key of a Map
      map.set(objAsKey, 'What will happen?')
      

      La key del elemento del Map es ahora el objeto que creamos.

      Output

      key: {foo: "bar"} value: "What will happen?"

      Hay algo importante que se debe considerar respecto del uso de un Object o Array como clave: en el Map se utiliza la referencia al Object para comparar la igualdad y no el valor literal del Object. En JavaScript {} == {} muestra false, porque los dos Object no son los mismos, a pesar de tener el mismo valor (vacío).

      Esto significa que al añadir dos Object únicos con el mismo valor se creará un Map con dos entradas:

      // Add two unique but similar objects as keys to a Map
      map.set({}, 'One')
      map.set({}, 'Two')
      

      Obtendrá el siguiente resultado:

      Output

      Map(2) {{…} => "One", {…} => "Two"}

      Sin embargo, si se usa la misma referencia de Object dos veces se creará un Map con una entrada.

      // Add the same exact object twice as keys to a Map
      const obj = {}
      
      map.set(obj, 'One')
      map.set(obj, 'Two')
      

      Esto dará como resultado lo siguiente:

      Output

      Map(1) {{…} => "Two"}

      El segundo set() actualiza exactamente la misma clave que la primera, por lo que finalmente obtenemos un Map que solo tiene un valor.

      Obtener y eliminar elementos de un Map

      Una de las desventajas de trabajar con Object es que puede resultar difícil enumerarlos, así como trabajar con las claves o los valores. En la estructura de Map, en contraste, se incluyen muchas propiedades integradas. Esto hace que pueda trabajar de forma más directa con sus elementos.

      Podemos inicializar un nuevo Map para mostrar los métodos y las propiedades siguientes: delete(), has(), get() y size.

      // Initialize a new Map
      const map = new Map([
        ['animal', 'otter'],
        ['shape', 'triangle'],
        ['city', 'New York'],
        ['country', 'Bulgaria'],
      ])
      

      Utilice el método has() para verificar la existencia de un elemento en un mapa. has() mostrará un booleano.

      // Check if a key exists in a Map
      map.has('shark') // false
      map.has('country') // true
      

      Utilice el método get() para obtener un valor por clave.

      // Get an item from a Map
      map.get('animal') // "otter"
      

      Un beneficio especial de los Map respecto los Object es que pueden encontrar el tamaño de un Map en cualquier momento, como con un Array. Puede obtener el recuento de elementos en un Map con la propiedad size. Para esto se requieren menos pasos que al convertir un Object en un Array para encontrar la longitud.

      // Get the count of items in a Map
      map.size // 4
      

      Utilice el método delete() para eliminar un elemento de un Map por clave. En el método, se mostrará un booleano (true si existió un elemento y se eliminó, y false si no coincidió con ningún elemento).

      // Delete an item from a Map by key
      map.delete('city') // true
      

      Esto dará como resultado el siguiente Map:

      Output

      Map(3) {"animal" => "otter", "shape" => "triangle", "country" => "Bulgaria"}

      Por último, se pueden eliminar todos los valores de un Map con map.clear().

      // Empty a Map
      map.clear()
      

      Verá el siguiente resultado:

      Output

      Map(0) {}

      Claves, valores y entradas para Map

      Los Object pueden recuperar claves, valores y entradas usando las propiedades del constructor Object. Por otro lado, en los Map se incluyen los métodos de prototipo que nos permiten obtener directamente las claves, los valores y las entradas de la instancia del Map.

      En los métodos keys(), values() y entries() se muestra un MapIterator, que es similar a un Array en el sentido que se puede usar for...of para repetir los valores.

      Aquí se muestra otro ejemplo de un Map, que podemos usar para demostrar estos métodos:

      const map = new Map([
        [1970, 'bell bottoms'],
        [1980, 'leg warmers'],
        [1990, 'flannel'],
      ])
      

      El método keys() muestra las claves:

      map.keys()
      

      Output

      MapIterator {1970, 1980, 1990}

      El método values() muestra los valores:

      map.values()
      

      Output

      MapIterator {"bell bottoms", "leg warmers", "flannel"}

      Con el método entries() se muestra una matriz de pares clave-valor:

      map.entries()
      

      Output

      MapIterator {1970 => "bell bottoms", 1980 => "leg warmers", 1990 => "flannel"}

      Iteración con Map

      En el Map se encuentra incorporado un método forEach, similar a un Array para la iteración integrada. Sin embargo, existe cierta diferencia respecto de lo que se itera. La devolución de llamada del forEach de un Map itera value, key y el propio map, mientras que en la versión de Array se iteran item, index y el propio array.

      // Map
      Map.prototype.forEach((value, key, map) = () => {})
      
      // Array
      Array.prototype.forEach((item, index, array) = () => {})
      

      Esta es una gran ventaja de los Map respecto de los Object, ya que estos deben convertirse con keys(), values() o entries() y no existe una forma sencilla de recuperar las propiedades de un Object sin convertirlo.

      Para demostrar esto,iteraremos nuestro Map y registraremos los pares clave-valor en la consola:

      // Log the keys and values of the Map with forEach
      map.forEach((value, key) => {
        console.log(`${key}: ${value}`)
      })
      

      Esto proporcionará lo siguiente:

      Output

      1970: bell bottoms 1980: leg warmers 1990: flannel

      Debido a que en un bucle for...of se iteran elementos iterables como los de Map y Array, podemos obtener exactamente el mismo resultado desestructurando la matriz de elementos de Map:

      // Destructure the key and value out of the Map item
      for (const [key, value] of map) {
        // Log the keys and values of the Map with for...of
        console.log(`${key}: ${value}`)
      }
      

      Propiedades y métodos de Map

      Para una consulta rápida, en la siguiente tabla se muestra una lista de propiedades y métodos de Map:

      Propiedades y métodos Descripción Resultado
      set(key, value) Añade un par clave-valor a un Map. Objeto Map
      delete(key) Elimina un par clave-valor de un Map por clave. Booleano
      get(key) Muestra un valor por clave. Valor
      has(key) Comprueba la presencia de un elemento en un Map por clave. Booleano
      clear() Eliminan todos los elementos de un Map. No es pertinente
      keys() Muestran todas las claves de un Map. Objeto MapIterator
      values() Muestra todos los valores de un Map. Objeto MapIterator
      entries() Muestra las claves y los valores de un Map como [key, value]. Objeto MapIterator
      forEach() Itera el Map en el orden de inserción. No es pertinente
      size Muestra el número de elementos de un Map. Número

      Cuando utilizar un Map

      En resumen, los Map son similares a los Object en el sentido de que almacenan pares clave-valor, pero tienen varias ventajas respecto de ellos:

      • Tamaño: los Map tienen una propiedad size, mientras que los Object no cuentan con una forma ya integrada de obtener su tamaño.
      • Iteración: los Map son directamente iterables, mientras que los Objects no.
      • Flexibilidad: los Map pueden tener cualquier tipo de datos (primitivo u Object) como clave para un valor, mientras que los Object solo pueden tener cadenas.
      • Ordenado: los Map retienen el orden de inserción, mientras que los objetos no tienen un orden garantizado.

      Debido a estos factores, los Map son una poderosa estructura de datos que se debe tener en cuenta. Sin embargo, los Object también ofrecen ventajas importantes:

      • JSON: los Object funcionan sin problema con JSON.parse() y JSON.stringify(), dos funciones esenciales para trabajar con JSON, un formato de datos común que utilizan muchas API REST.
      • Funcionamiento con un solo elemento: si trabaja con un valor conocido en un Object, puede acceder a él de forma directa con la clave sin necesidad de usar un método, como el get() de Map.

      Esta lista le servirá de ayuda para decidir si un Map u Object es la estructura de datos correcta para su caso de uso.

      Set

      Un set es un grupo de valores únicos. A diferencia de un Map, un Set es conceptualmente más parecido a un Array que a un Object, ya que es una lista de valores y no de pares clave-valor. Sin embargo, un Set no es un sustituto de los Array, sino un complemento que permite brindar respaldo adicional para trabajar con datos duplicados.

      Puede inicializar Set con la sintaxis new Set().

      const set = new Set()
      

      Esto proporciona un set vacío:

      Output

      Set(0) {}

      Se pueden añadir elementos a un set con el método add(). (Esto no debe confundirse con el método set() disponible para Map, aunque son similares).

      // Add items to a Set
      set.add('Beethoven')
      set.add('Mozart')
      set.add('Chopin')
      

      Debido a que los sets solo pueden contener valores únicos, cualquier intento de añadir un valor ya existente se ignorará.

      set.add('Chopin') // Set will still contain 3 unique values
      

      Nota: La misma comparación de igualdad que se aplica a las claves de Map sirve para elementos de Set. Dos objetos que tengan el mismo valor y no compartan la misma referencia no se considerarán iguales.

      También puede inicializar Sets con un Array de valores. Si hay valores duplicados en la matriz, se eliminarán del Set.

      // Initialize a Set from an Array
      const set = new Set(['Beethoven', 'Mozart', 'Chopin', 'Chopin'])
      

      Output

      Set(3) {"Beethoven", "Mozart", "Chopin"}

      En cambio, un Set se puede convertir en un Array con una línea de código:

      const arr = [...set]
      

      Output

      (3) ["Beethoven", "Mozart", "Chopin"]

      Los sets tienen muchos de los métodos y las propiedades idénticos de los Map, incluidos delete(), has(), clear() y size.

      // Delete an item
      set.delete('Beethoven') // true
      
      // Check for the existence of an item
      set.has('Beethoven') // false
      
      // Clear a Set
      set.clear()
      
      // Check the size of a Set
      set.size // 0
      

      Tenga en cuenta que los sets no tienen una una forma de acceder a un valor por medio de una clave o un índice, como Map.get(key) o arr[index].

      Claves, valores y entradas para los sets

      Los Map y Set cuentan con métodos keys(), values() y entries() que muestran un iterador. Sin embargo, mientras que cada uno de estos métodos tiene un propósito distinto en los Map, en los Set no se incluyen claves y, por lo tanto, estas son un alias para los valores. Esto significa que tanto keys() y values() mostrarán el mismo iterador y entries() mostrará el valor dos veces. Tiene más sentido usar únicamente values() con Set, ya que los otros dos métodos existen para la uniformidad y la compatibilidad cruzada con Map.

      const set = new Set([1, 2, 3])
      // Get the values of a set
      set.values()
      

      Output

      SetIterator {1, 2, 3}

      Iteraciones con sets

      Como en el caso de los Map, los Set cuentan con un método forEach() incorporado. Debido a que los Set no tienen claves, el primer y segundo parámetro de la devolución de llamada forEach() muestran el mismo valor, por lo que no hay un caso de uso para este fuera de la compatibilidad con Map. Los parámetros de forEach() son (value, key, set).

      Tanto forEach() como for...of pueden utilizarse en Set. Primero, veremos la iteración de forEach():

      const set = new Set(['hi', 'hello', 'good day'])
      
      // Iterate a Set with forEach
      set.forEach((value) => console.log(value))
      

      Luego podemos escribir la versión de for...of:

      // Iterate a Set with for...of
      for (const value of set) {  
          console.log(value);
      }
      

      El resultado de ambas estrategias será el siguiente:

      Output

      hi hello good day

      Propiedades y métodos de los Set

      A modo de referencia rápida, en la siguiente tabla se muestra una lista de las propiedades y los métodos de Set:

      Propiedades y métodos Descripción Resultado
      add(value) Añade un nuevo elemento a un Set. Objeto Set
      delete(value) Elimina el elemento especificado de un Set. Booleano
      has() Verifica la presencia de un elemento en un Set. Booleano
      clear() Elimina todos los elementos de un Set. No es pertinente
      keys() Muestra todos los valores de un Set (como values()). Objeto SetIterator
      values() Muestra todos los valores de un Set (como keys()). Objeto SetIterator
      entries() Muestra todos los valores de un Set como [value, value]. Objeto SetIterator
      forEach() Itera el Set en el orden de inserción. No es pertinente
      size Muestra el número de elementos de un Set. Número

      Cuando utilizar un Set

      Los Set son un elemento adicional útil para su juego de herramientas de JavaScript, en particular para trabajar con valores duplicados en los datos.

      En una sola línea, podemos crear un nuevo Array sin los valores duplicados de un Array que sí los tiene.

      const uniqueArray = [ ...new Set([1, 1, 2, 2, 2, 3])] // (3) [1, 2, 3]
      

      Esto proporcionará lo siguiente:

      Output

      (3) [1, 2, 3]

      Un Set se puede usar para encontrar la unión, intersección y diferencia entre dos conjuntos de datos. Sin embargo, los Array tienen una ventaja importante respecto de los Set para la manipulación adicional de los datos debido a los métodos sort(), map(), filter() y reduce(), y también compatibilidad directa con los métodos JSON.

      Conclusión

      A través de este artículo, aprendió que un Map es un grupo de pares clave-valor ordenados y que un Set es un grupo de valores únicos. Ambas estructuras de datos añaden capacidades a JavaScript y simplifican tareas comunes, como encontrar la extensión de un grupo de pares clave-valor y eliminar elementos duplicados de un conjunto de datos, respectivamente. Por otro lado, los Object y Array se han utilizado tradicionalmente para el almacenamiento y la manipulación de datos en JavaScript, y tienen compatibilidad directa con JSON, lo cual sigue haciendo que sean las estructuras de datos más esenciales, sobre todo para trabajar con API de REST. Los Map y los Set son principalmente útiles como estructuras de datos de respaldo para los Object y Array.

      Si desea obtener más información sobre JavaScript, consulte la página de inicio de nuestra serie Cómo producir código en JavaScript o busque nuestra serie Cómo producir código en Node.js para hallar artículos sobre el desarrollo de backend.



      Source link