Articulo de referencia

Underscore.js

Underscore.js es una biblioteca de JavaScript que proporciona funciones de utilidad para tareas de programación comunes. [ 3 ] Es comparable a las características que ofrecen Pr...

Underscore.js es una biblioteca de JavaScript que proporciona funciones de utilidad para tareas de programación comunes. [ 3 ] Es comparable a las características que ofrecen Prototype.js y el lenguaje Ruby , pero opta por un diseño de programación funcional en lugar de extender prototipos de objetos . La documentación se refiere a Underscore.js como "la corbata que acompaña al esmoquin de jQuery y a los tirantes de Backbone.js ". Underscore.js fue creado por Jeremy Ashkenas , conocido también por Backbone.js y CoffeeScript . [ 4 ]

Historia

Jeremy Ashkenas creó Underscore a finales de 2009 como un proyecto derivado de DocumentCloud , junto con Backbone.js . Fue una de las primeras bibliotecas de JavaScript en proporcionar utilidades generales de programación funcional, inspirándose en Prototype.js , Functional JavaScript de Oliver Steele y Micro-Templating de John Resig. [ 5 ]

En 2012, John-David Dalton creó una bifurcación de Underscore, llamada Lo-Dash (ahora Lodash ). Inicialmente, Lo-Dash se promocionó como una alternativa directa a Underscore con "consistencia, personalización, rendimiento y extras". [ 6 ] Sin embargo, Lodash ya se apartó de la interfaz original de Underscore en una etapa temprana [ 7 ] y comenzó a realizar cambios más drásticos con el lanzamiento de la versión 3.0.0, lo que obligó a los usuarios de Lodash a modificar su código. [ 8 ]

En mayo de 2015, Jeremy Ashkenas anunció que John-David Dalton se había puesto en contacto con él para fusionar las bibliotecas. A pesar de las preocupaciones sobre el estilo y el tamaño del código, Ashkenas no se opuso a fusionar algunas de las extensiones de Lodash en Underscore. [ 9 ] En ese momento, varios desarrolladores contribuían a Underscore y Lodash en paralelo; este grupo de colaboradores comenzó a realizar cambios en Underscore para que se pareciera más a Lodash. [ 10 ]

Sin embargo, paralelamente a este esfuerzo, Dalton realizó cambios más drásticos en la interfaz de Lodash. En junio de 2015, anunció la versión 4.0.0 de Lodash, que la distanció aún más de la interfaz de Underscore, a la vez que marcó una diferencia significativa con respecto a la serie de versiones 3.x de Lodash. [ 11 ] [ 12 ] Esto impulsó a algunos proyectos que dependían de Lodash a crear sus propias distribuciones de Lodash 3. [ 13 ]

En febrero de 2016, Dalton anunció que consideraba que el esfuerzo de fusión estaba completo. Sugirió que los usuarios cambiaran de Underscore a Lodash, justificando esto con estadísticas de participación de uso. [ 14 ] Sin embargo, un mantenedor de Underscore dejó claro que no había intención de dejar de desarrollar Underscore como una biblioteca separada. [ 15 ] Ambas bibliotecas entraron en un estado de baja actividad de desarrollo después de 2016. [ 16 ] [ 17 ]

Con el tiempo, las versiones más recientes del estándar ECMAScript han añadido funciones integradas al lenguaje que replican algunas de las funcionalidades de Underscore, como Object.assigny Array.prototype.map. Sin embargo, las funciones integradas a veces son menos potentes que sus equivalentes de Underscore; en particular, los métodos de iteración de matrices integrados, como map, filtery , forEachno pueden iterar sobre objetos simples y no admiten abreviaturas de iteración . [ 18 ] [ 19 ] [ 20 ] [ 21 ] [ 22 ] [ 23 ]

A marzo de 2021, Underscore está siendo desarrollado activamente por Julian Gonggrijp, quien comenzó a hacer contribuciones importantes en marzo de 2020. [ 16 ] La biblioteca sigue siendo ampliamente utilizada y se descarga de npm varios millones de veces cada semana. [ 24 ]

Contenido

En esencia, Underscore ofrece tres cosas:

  1. Una colección de más de 100 funciones reutilizables, diseñadas para ser prácticamente útiles en aplicaciones cotidianas. La documentación distingue varias categorías:
    • Las funciones de colección, como find, map, min/ max, groupByy shuffleprocesan colecciones de datos. Estas funciones pueden operar sobre los elementos de secuencias tipo array, así como sobre las propiedades de los objetos.
    • Las funciones de matriz como first/ last, flatten, chunky zipoperan exclusivamente en objetos similares a matrices.
    • Las funciones tales como bind, memoize, partialy debouncetoman una función como argumento y devuelven una nueva función con propiedades alteradas ( funciones de orden superior ).
    • Las funciones de objeto son una categoría más fundamental, que contiene muchas funciones que también se reutilizan internamente en Underscore. [ 25 ] Se puede dividir aproximadamente en dos subcategorías:
      • Funciones de prueba de tipos como isNumber, isElementy isDataView.
      • Funciones como keys, extend, pick/ omit, pairsy invert, que manipulan objetos (planos) como datos.
    • Las funciones de utilidad son una categoría de descanso. Entre otras, incluye las funciones triviales identityy noopy las funciones de manipulación de cadenas escape, unescapey template. Esta categoría también incluye las funciones iterateey mixin, que podrían considerarse instalaciones especiales como en el punto 2.
  2. Funcionalidades especiales, como chainy iteratee, que se combinan con las funciones del punto 1 para permitir una sintaxis más corta y limpia. La función especial _, que da nombre a la biblioteca, es fundamental para estas funcionalidades.
  3. Código fuente legible , diseñado para facilitar la comprensión de la implementación de la biblioteca. La documentación incluye una versión renderizada del código fuente, donde los comentarios se encuentran a la izquierda y la lógica a la derecha. Los comentarios están formateados con Markdown y la lógica cuenta con resaltado de sintaxis . Desde la versión 1.11, Underscore es modular . Por este motivo, la documentación ahora incluye una versión modular del código fuente anotado, donde cada función se encuentra en una página independiente y las importreferencias son hipervínculos clicables , y una versión de lectura única , donde todas las funciones se encuentran en una sola página según su orden de dependencia .

Descripción general y ejemplos de funciones

Underscore promueve un estilo funcional , donde se pueden combinar varias funciones en una sola expresión para obtener nuevas funcionalidades. Por ejemplo, la siguiente expresión utiliza dos funciones de Underscore para agrupar palabras por sus primeros caracteres:

import { groupBy , first } from 'underscore' ;groupBy ([ 'aguacate' , 'albaricoque' , 'cereza' , 'dátil' , 'durian' ], first );// resultado:// { a: ['aguacate', 'albaricoque'],// c: ['cereza'],// d: ['fecha', 'durian']// }

Las funciones de Underscore no se diferencian en absoluto de las funciones definidas por el usuario. Si el usuario hubiera implementado su propia firstfunción, la expresión anterior habría funcionado igual de bien:

import { groupBy } from 'underscore' ;const first = array => array [ 0 ];groupBy ([ 'aguacate' , 'albaricoque' , 'cereza' , 'dátil' , 'durian' ], first );

Sin embargo, el conjunto de funciones que ofrece Underscore se ha elegido específicamente para minimizar dicho esfuerzo, de modo que el usuario pueda componer la funcionalidad a partir de funciones existentes en lugar de escribir las suyas propias.

Las funciones que iteran sobre el contenido de una matriz u objeto generalmente toman los datos como primer parámetro y una función iteradora o iterador como segundo parámetro. En el ejemplo anterior, firstes el iterador que se pasa a groupBy.

Aunque el iterador no está obligado a utilizarlos, en la mayoría de los casos recibe tres argumentos: (1) el valor en la posición actual de la colección, (2) la clave o índice de este valor y (3) la colección completa. En el siguiente ejemplo, el segundo argumento se utiliza en un iterador para pickseleccionar únicamente las propiedades de un objeto cuya clave comienza con una letra mayúscula:

import { pick } from 'underscore' ;const detalles = {Oficial : 'Wolfgang Amadeus Mozart' ,informal : 'Wolfie'};const keyIsUpper = ( value , key ) => key [ 0 ] === key [ 0 ]. toUpperCase ();seleccionar ( detalles , keyIsUpper );// {Oficial: 'Wolfgang Amadeus Mozart'}

Muchas funciones de Underscore pueden usarse como iteradores, como se ilustró anteriormente con first. Además, existen varios casos comunes en los que el usuario puede evitar escribir una función iteradora, utilizando en su lugar una notación abreviada . En el siguiente ejemplo, la cadena 'name'se usa como notación abreviada para iterar con el fin de extraer todas las namepropiedades de una matriz de objetos:

import { map } from 'underscore' ;const personas = [{ nombre : 'Lily' , edad : 44 , ocupación : 'bibliotecaria' },{ nombre : 'Harold' , edad : 10 , ocupación : 'soñador' },{ nombre : 'Sasha' , edad : 68 , ocupación : 'desarrolladora de bibliotecas' }];mapa ( personas , 'nombre' ); // ['Lily', 'Harold', 'Sasha']

Todas las funciones de la categoría "colección", incluidas las groupByfunciones mapmostradas anteriormente, pueden iterar tanto sobre los índices de una matriz como sobre las claves de un objeto. Esto se ilustra a continuación con reduce:

import { reduce } from 'underscore' ;const add = ( a , b ) => a + b ;const suma = números => reducir ( números , sumar , 0 );suma ([ 11 , 12 , 13 ]); // 36suma ({ Alice : 9 , Bob : 9 , Clair : 7 }); // 25

Además de las funciones que iteran sobre matrices u objetos, Underscore proporciona una amplia gama de otras funciones reutilizables. Por ejemplo, throttlelimita la frecuencia con la que se evalúa una función:

import { throttle } from 'underscore' ;// El evento de desplazamiento se activa muy a menudo, por lo que la siguiente línea puede// Ralentiza el navegador.document.body.addEventListener ( ' scroll ' , expensiveUpdateFunction ) ;// Limitar la evaluación a una vez cada 100 milisegundos.const throttledUpdateFunction = throttle ( expensiveUpdateFunction , 100 );// ¡Una experiencia de usuario mucho más fluida!document.body.addEventListener ( ' scroll ' , throttledUpdateFunction ) ;

Otro ejemplo es defaults, que asigna propiedades de objeto solo si no están ya establecidas:

import { defaults } from 'underscore' ;const requestData = {URL : 'wikipedia.org' ,método : 'POST' ,cuerpo : 'texto del artículo'};const defaultFields = {método : 'GET' ,encabezados : { 'X-Requested-With' : 'XMLHttpRequest' }};valores predeterminados ( requestData , defaultFields );// {// url: 'wikipedia.org',// método: 'POST',// cuerpo: 'texto del artículo',// encabezados: {'X-Requested-With': 'XMLHttpRequest'}// }

La _función

Underscore deriva su nombre de la función _, que cumple múltiples funciones.

Función de envoltura

Como función, _devuelve una versión encapsulada de cualquier valor que se pase como primer argumento. Este objeto especial tiene todas las funciones de Underscore como métodos, lo que permite una notación diferente que se conoce como "estilo OOP":

import _ , { last } from 'underscore' ;// Estilo "normal" o "funcional"último ([ 1 , 2 , 3 ]); // 3// "Estilo OOP"_ ([ 1 , 2 , 3 ]). último () // 3

Esta función se utiliza en el encadenamiento ( siguiente sección ). El valor se puede desenvolver de nuevo con el .value()método para procesarlo posteriormente fuera de Underscore. En algunos casos, los valores también se desenvuelven automáticamente.

// Desempaquetado explícito_ ([ 1 , 2 , 3 ]). valor () // [1, 2, 3]// Desempaquetado automático cuando se convierte a número1 + _ ( 2 ) // 3// Desempaquetado automático cuando se convierte a cadena'abc' + _ ( 'def' ) // 'abcdef'// Desempaquetado automático cuando se formatea como JSONJSON.stringify ({ a: _ ( [ 1 , 2 ] ) } ) // '{"a":[1,2]}'

Marcador de posición de solicitud parcial

_También actúa como marcador de posición para la partialfunción. partialCrea una versión parcialmente aplicada_ de una función y puede usarse para dejar algunos parámetros "abiertos" para que puedan proporcionarse posteriormente. Por ejemplo, el groupByejemplo de la descripción general puede ampliarse de la siguiente manera para convertir la expresión en una función reutilizable:

import _ , { partial , groupBy , first } from 'underscore' ;const groupByFirstChar = partial ( groupBy , _ , first );groupByFirstChar ([ 'aguacate' , 'albaricoque' , 'cereza' , 'dátil' , 'durian' ]);// { a: ['aguacate', 'albaricoque'],// c: ['cereza'],// d: ['fecha', 'durian']// }groupByFirstChar ([ 'castaño' , 'pistacho' , 'nuez' , 'anacardo' ]);// { c: ['castaño', 'anacardo'],// p: ['pistacho'],// w: ['nuez]// }

Punto de personalización

Además, _sirve como punto central de personalización donde los usuarios pueden ajustar el comportamiento de las funciones de Underscore según sus necesidades. Específicamente, los usuarios pueden sobrescribir _.iterateepara crear nuevas abreviaturas de iteración y _.templateSettingspara personalizar la templatefunción.

identificador de espacio de nombres

En términos más generales, todas las funciones de Underscore están presentes como propiedades en _, por ejemplo también _.mapy _.debounce. Esto permite usar _como identificador de espacio de nombres . Con la llegada de los módulos en ES6 , tener dicho identificador de espacio de nombres ya no es estrictamente necesario, pero la práctica todavía se encuentra comúnmente en código que utiliza sistemas de módulos más antiguos como AMD y CommonJS :

var _ = require ( 'underscore' );_ . groupBy ([ 'aguacate' , 'albaricoque' , 'cereza' , 'dátil' , 'durian' ], _ . first );

Dada la práctica actual, también puede ser una notación conveniente para aclarar que se hace referencia a una función específica de la biblioteca Underscore y no a una función con el mismo nombre de otra biblioteca. Por ejemplo, tanto Underscore como Async proporcionan una función llamada each; para distinguirlas, se puede escribir _.eachy async.each, respectivamente.

Encadenamiento

La función chainse puede utilizar para crear una versión modificada del envoltorio producido por la _función . Cuando se invoca en dicho envoltorio encadenado , cada método devuelve un nuevo envoltorio para que el usuario pueda seguir procesando los resultados intermedios con las funciones de Underscore:

import { chain } from 'underscore' ;const cuadrado = x => x * x ;const isOdd = x => x % 2 ;cadena ([ 1 , 2 , 3 , 4 ]). filtro ( esImpar ). mapeo ( cuadrado ). último ()// devuelve un contenedor de 9

No es raro que una función implementada con Underscore consista enteramente en una returninstrucción con una cadena que termina en .value():

const add = ( x , y ) => x + y ;// Dado un array de números, devuelve la suma de los cuadrados de// esos números. Esto podría usarse en una biblioteca de estadísticas.función sumaDeCuadrados ( números ) {cadena de retorno ( números ). mapa ( cuadrado ). reducir ( agregar ). valor ();}

El encadenamiento no es exclusivo de las funciones que vienen con Underscore. Los usuarios también pueden habilitar el encadenamiento para sus propias funciones pasándolas a la mixinfunción:

import { reduce , mixin } from 'underscore' ;const suma = números => reducir ( números , sumar , 0 );mixin ({ suma , cuadrado });cadena ([ 1 , 2 , 3 ]). map ( cuadrado ). suma (). valor (); // 14cadena ([ 1 , 2 , 3 ]). suma (). cuadrado (). valor (); // 36

De hecho, así es precisamente como se habilita el encadenamiento también para las propias funciones de Underscore. Todas las funciones de Underscore están escritas como funciones independientes regulares, sin ninguna preparación especial para el encadenamiento, y luego se "mezclan" con la _función posteriormente. [ 26 ]

Abreviaturas de iteración

Como se mencionó anteriormente en la descripción general , la mayoría de las funciones de Underscore que iteran sobre matrices u objetos aceptan una notación abreviada como iterado en lugar de una función. Repitiendo el ejemplo de esa sección aquí:

import { map } from 'underscore' ;const personas = [{ nombre : 'Lily' , detalles : { edad : 44 , ocupación : 'bombera' }},{ nombre : 'Harold' , detalles : { edad : 10 , ocupación : 'soñador' }},{ nombre : 'Sasha' , detalles : { edad : 68 , ocupación : 'desarrolladora de bibliotecas' }}];mapa ( personas , 'nombre' ); // ['Lily', 'Harold', 'Sasha']

Internamente, esta notación se habilita pasando el valor abreviado _.iterateepara obtener una función. Por _.iterateedefecto, se utiliza la iterateefunción que viene con Underscore, la cual, dependiendo del valor, devuelve una función como sigue.

Caminos

Cuando el valor es una cadena, iterateese reenvía a property, que interpreta la cadena como una clave de propiedad. Devuelve una función que intenta extraer la propiedad con la clave dada de su argumento. Las siguientes expresiones son todas equivalentes:

import { iteratee , property } from 'underscore' ;mapa ( personas , 'nombre' );mapa ( personas , iterador ( 'nombre' ));mapa ( personas , propiedad ( 'nombre' ));mapa ( personas , obj => obj && obj [ 'nombre' ]);// ['Lily', 'Harold', 'Sasha']

También se pasan matrices y números property. Las matrices se pueden usar para recuperar propiedades anidadas:

mapa ( personas , [ 'detalles' , 'ocupación' ]);// ['bombero', 'soñador', 'desarrollador de bibliotecas']

Los números se pueden usar como índices de matrices y cadenas de caracteres. Combinando todo esto, podemos usar la siguiente expresión para contar cuántas veces aparecen letras del alfabeto como segundo carácter de la ocupación de una persona:

import { countBy } from 'underscore' ;countBy ( people , [ 'details' , 'occupation' , 1 ]); // {i: 2, r: 1}

Hashes de atributos

Cuando el valor es un objeto, iterateelo reenvía a matcher, que interpreta el objeto como un conjunto de atributos que deben coincidir. Devuelve una función que devolverá trueo falsedependiendo de si su argumento tiene este mismo conjunto de atributos.

import { find } from 'underscore' ;encontrar ( personas , { nombre : 'Sasha' });// {nombre: 'Sasha', detalles: {edad: 68, ocupación: 'desarrolladora de bibliotecas'}}encontrar ( personas , { nombre : 'Walter' });// indefinido

nullyundefined

Cuando el valor es nullo undefined, iterateedevuelve la función identidad que Underscore exporta como identity. Esto se puede usar para filtrar los valores verdaderos de una colección:

import { filter , iteratee , identity } from 'underscore' ;const example = [ 0 , 1 , '' , 'abc' , true , false , {}];// Las siguientes expresiones son todas equivalentes.filtro ( ejemplo );filtro ( ejemplo , indefinido );filtro ( ejemplo , iterador ( indefinido ));filtro ( ejemplo , identidad );// [1, 'abc', verdadero, {}]

Primordial_.iteratee

Los usuarios pueden sobrescribir _.iteratee para crear abreviaturas personalizadas. El siguiente ejemplo ilustra cómo se puede usar esto para implementar el filtrado mediante expresiones regulares:

importar {iterado como iterado original ,esRegExp ,mezcla ,filtro ,} de 'underscore' ;función iterar ( valor , contexto ) {si ( esRegExp ( valor )) {devolver cadena = > valor.prueba ( cadena ) ;} demás {devolver originalIteratee ( valor , contexto );}}mixin ({ iterar });filtro ([ 'absolutamente' , 'increíble' , 'fabuloso' , 'pantalones' ], /ab/ );// ['absolutamente', 'fabuloso']

Véase también

Referencias

  1. ^ Versión 0.1.0 , jashkenas/underscore, GitHub
  2. ^ "Versión 1.13.8" . 3 de marzo de 2026. Consultado el 4 de abril de 2026 .
  3. ^ "Underscore.js: un marco pequeño con enfoque" . entwickler.de (en alemán). 20 de junio de 2018 . Consultado el 9 de julio de 2020 .
  4. ^ "JavaScript Meetup City" , Abierto , The New York Times , 4 de abril de 2012
  5. ^ Ashkenas, Jeremy. "Underscore 0.4.0 source" . cdn.rawgit.com . Consultado el 1 de marzo de 2021 .
  6. ^ "Lo-Dash v2.2.1" . lodash.com . Archivado del original el 6 de noviembre de 2013. Consultado el 1 de marzo de 2021 .
  7. ^ "Registro de cambios de Lodash - 1.0.0 rc1" . github.com . 4 de diciembre de 2012 . Consultado el 1 de marzo de 2021 .
  8. ^ "Registro de cambios de Lodash - 3.0.0" . github.com . 26 de enero de 2015. Consultado el 1 de marzo de 2021 .
  9. ^ Ashkenas, Jeremy (21 de mayo de 2015). "The Big Kahuna: Underscore + Lodash Merge Thread" . github.com . Consultado el 1 de marzo de 2021 .
  10. ^ "Subrayado: solicitudes de extracción fusionadas con cambios incompatibles entre el 21 de mayo y el 1 de octubre de 2015" . github.com . Consultado el 1 de marzo de 2021 .
  11. ^ Dalton, John-David (8 de junio de 2015). "Comentario sobre 'Core API'"" . github.com . Consultado el 1 de marzo de 2021 .
  12. ^ "Registro de cambios de Lodash 4.0.0" . github.com . 12 de enero de 2016. Consultado el 1 de marzo de 2021 .
  13. ^ "@sailshq/lodash" . npmjs.com . Consultado el 1 de marzo de 2021 .
  14. ^ Dalton, John-David (13 de febrero de 2016). "Actualización de fusión" . github.com . Consultado el 1 de marzo de 2021 .
  15. ^ Krebs, Adam (17 de febrero de 2016). "Comentario sobre 'Actualización de fusión'."" . github.com . Consultado el 1 de marzo de 2021 .
  16. ^ a b "jashkenas/underscore Insights: Contributors" . github.com . Consultado el 1 de marzo de 2021 .
  17. ^ "lodash/lodash Insight: Colaboradores" . github.com . Consultado el 1 de marzo de 2021 .
  18. ^ "Array.prototype.map" . developer.mozilla.org . Consultado el 1 de marzo de 2021 .
  19. ^ "Array.prototype.filter" . developer.mozilla.org . Consultado el 1 de marzo de 2021 .
  20. ^ "Array.prototype.forEach" . developer.mozilla.org . Consultado el 1 de marzo de 2021 .
  21. ^ "_.map" . underscorejs.org . Consultado el 1 de marzo de 2021 .
  22. ^ "_.filter" . underscorejs.org . Consultado el 1 de marzo de 2021 .
  23. ^ "_.each" . underscorejs.org . Consultado el 1 de marzo de 2021 .
  24. ^ "guion bajo" . npmjs.com . Consultado el 1 de marzo de 2021 .
  25. ^ Gonggrijp, Julian. "modules/index.js" . underscorejs.org . Consultado el 5 de marzo de 2021 .
  26. ^ Gonggrijp, Julian. "modules/index-default.js" . underscorejs.org . Consultado el 4 de marzo de 2021 .
  • Sitio web oficialEdita esto en Wikidata
  • JavaScript funcional por Oliver Steele (archivo de Internet; osteele.com solo conserva una captura de pantalla ).
  • Microplantillas JavaScript de John Resig, la inspiración original para_.template
Obtenido de " https://en.wikipedia.org/w/index.php?title=Underscore.js&oldid=1358966675 "