Movatterモバイル変換


[0]ホーム

URL:


Jump to content
WikipediaThe Free Encyclopedia
Search

Underscore.js

From Wikipedia, the free encyclopedia
Javascript library
Underscore.js
DevelopersJeremy Ashkenas, Julian Gonggrijp
Initial releaseOctober 28, 2009; 16 years ago (2009-10-28)[1]
Stable release
1.13.7[2] Edit this on Wikidata / 24 July 2024; 18 months ago (24 July 2024)
Written inJavaScript
Size7.5 KB production
68 KB development
TypeJavaScript library
LicenseMIT
Websiteunderscorejs.org
Repository

Underscore.js is aJavaScript library which provides utility functions for common programming tasks.[3] It is comparable to features provided byPrototype.js and theRuby language, but opts for afunctional programming design instead of extending objectprototypes. The documentation refers to Underscore.js as "the tie to go along withjQuery's tux, andBackbone.js' suspenders." Underscore.js was created byJeremy Ashkenas, who is also known forBackbone.js andCoffeeScript.[4]

History

[edit]

Jeremy Ashkenas created Underscore by the end of 2009 as a spin-off from theDocumentCloud project, together withBackbone.js. It was one of the earliest libraries for JavaScript to provide general functional programming utilities, taking inspiration fromPrototype.js, Oliver Steele's Functional JavaScript, and John Resig's Micro-Templating.[5]

In 2012, John-David Dalton created afork of Underscore, named Lo-Dash (nowLodash). Lo-Dash was initially promoted as a drop-in alternative for Underscore with "consistency, customization, performance, & extras".[6] Nevertheless, Lodash already departed from the original Underscore interface at an early stage[7] and started making more drastic changes with the 3.0.0 release, making it necessary for Lodash users to change their code.[8]

In May 2015, Jeremy Ashkenas announced that John-David Dalton had contacted him about merging the libraries back together. Despite concerns about code style and code size, Ashkenas was not opposed to merging some of Lodash's extensions into Underscore.[9] At the time, there were several developers contributing to Underscore and Lodash in parallel; this group of contributors started making changes to Underscore in order to make it more like Lodash.[10]

In parallel to this effort, however, Dalton made more drastic changes to the Lodash interface. In June 2015, he announced Lodash version 4.0.0, which distanced Lodash even further from the Underscore interface, while making a significant departure from the version 3.x series of Lodash itself as well.[11][12] This prompted some projects that depended on Lodash to create their own distributions of Lodash 3.[13]

In February 2016, Dalton announced that he considered the merge effort to be complete. He suggested that users switch from Underscore to Lodash, motivating this with usage share statistics.[14] A maintainer of Underscore however made clear that there was no intention to stop developing Underscore as a separate library.[15] Both libraries entered a state of low development activity after 2016.[16][17]

Over time, newer versions of theECMAScript standard have added built-in functions to the language that replicate some of the functionality of Underscore, such asObject.assign andArray.prototype.map. However, the built-in functions are sometimes less powerful than their Underscore equivalents; in particular, built-in array iteration methods such asmap,filter andforEach cannot iterate over plain objects and do not supportiteratee shorthands.[18][19][20][21][22][23]

As of March 2021, Underscore is being actively developed by Julian Gonggrijp, who started making major contributions in March 2020.[16] The library is still widely depended upon and is being downloaded fromnpm several million times every week.[24]

Content

[edit]

In essence, Underscore provides three things:

  1. A collection of more than 100 reusable functions, which are meant to be practically useful in everyday applications. Thedocumentation distinguishes several categories:
    • Collection functions such asfind,map,min/max,groupBy andshuffle process collections of data. These functions can operate on the elements of array-like sequences as well as on the properties of objects.
    • Array functions such asfirst/last,flatten,chunk andzip operate exclusively on array-like objects.
    • Function functions such asbind,memoize,partial anddebounce take a function as argument and return a new function with altered properties (higher-order functions).
    • Object functions is a more foundational category, containing many functions that are also reused internally in Underscore.[25] It can be roughly divided in two subcategories:
      • Type testing functions such asisNumber,isElement andisDataView.
      • Functions such askeys,extend,pick/omit,pairs andinvert, which manipulate (plain) objects as data.
    • Utility functions is a rest category. Among others, it includes the trivial functionsidentity andnoop and the string manipulating functionsescape,unescape andtemplate. This category also includes the functionsiteratee andmixin, which could be considered special facilities as in point 2.
  2. Special facilities, such aschain anditeratee, which combine with the functions under point 1 in order to enable a shorter, cleaner syntax. The special function_, which the library is named after, is central to these facilities.
  3. Literate source code that is meant to be read, so that it is easy to follow how the library is implemented. The documentation includes arendered version of the source code, where the comments are on the left and the logic is on the right. The comments are formatted usingMarkdown and the logic hassyntax highlighting. Since version 1.11, Underscore ismodular. For this reason, the documentation now includes both amodular version of the annotated source, in which each function is on a separate page and theimport references are clickablehyperlinks, and asingle read version, where all functions are on a single page byorder of dependency.

Overview and examples of functions

[edit]

Underscore promotes afunctional style, where multiple functions can be combined in a singleexpression in order to obtain new functionality. For example, the following expression uses two Underscore functions to group words by their first characters:

import{groupBy,first}from'underscore';groupBy(['avocado','apricot','cherry','date','durian'],first);// result:// { a: ['avocado', 'apricot'],//   c: ['cherry'],//   d: ['date', 'durian']// }

Underscore functions are not in any way set apart from user-defined functions. Had the user implemented her ownfirst function, the above expression would have worked equally well:

import{groupBy}from'underscore';constfirst=array=>array[0];groupBy(['avocado','apricot','cherry','date','durian'],first);

The set of functions provided by Underscore is however specifically chosen to minimize such effort, so that the user can compose functionality out of existing functions rather than writing her own.

Functions that iterate over the contents of an array or object usually take the data as the first parameter and an iterating function oriteratee as the second parameter. In the example above,first is the iteratee passed togroupBy.

Although the iteratee is not required to use them, it receives three arguments in most cases: (1) the value at the current position in the collection, (2) the key or index of this value and (3) the whole collection. In the following example, the second argument is used in an iteratee topick in order to select only the properties of an object of which the key starts with an uppercase letter:

import{pick}from'underscore';constdetails={Official:'Wolfgang Amadeus Mozart',informal:'Wolfie'};constkeyIsUpper=(value,key)=>key[0]===key[0].toUpperCase();pick(details,keyIsUpper);// {Official: 'Wolfgang Amadeus Mozart'}

Many Underscore functions can be used as an iteratee, as previously illustrated withfirst. Apart from that, there are several common cases where the user can avoid writing an iteratee function, by using aniteratee shorthand instead. In the following example, the string'name' is used as an iteratee shorthand in order to extract all thename properties from an array of objects:

import{map}from'underscore';constpeople=[{name:'Lily',age:44,occupation:'librarian'},{name:'Harold',age:10,occupation:'dreamer'},{name:'Sasha',age:68,occupation:'library developer'}];map(people,'name');// ['Lily', 'Harold', 'Sasha']

All functions in the "collection" category, including thegroupBy andmap functions demonstrated above, can iterate both over the indices of an array and over the keys of an object. This is illustrated below withreduce:

import{reduce}from'underscore';constadd=(a,b)=>a+b;constsum=numbers=>reduce(numbers,add,0);sum([11,12,13]);// 36sum({Alice:9,Bob:9,Clair:7});// 25

Besides functions that iterate over arrays or objects, Underscore provides a wide range of other reusable functions. For example,throttle limits the frequency with which a function is evaluated:

import{throttle}from'underscore';// The scroll event triggers very often, so the following line may// slow down the browser.document.body.addEventListener('scroll',expensiveUpdateFunction);// Limit evaluation to once every 100 milliseconds.constthrottledUpdateFunction=throttle(expensiveUpdateFunction,100);// Much smoother user experience!document.body.addEventListener('scroll',throttledUpdateFunction);

Another example isdefaults, which assigns object properties only if not already set:

import{defaults}from'underscore';constrequestData={url:'wikipedia.org',method:'POST',body:'article text'};constdefaultFields={method:'GET',headers:{'X-Requested-With':'XMLHttpRequest'}};defaults(requestData,defaultFields);// {//     url: 'wikipedia.org',//     method: 'POST',//     body: 'article text',//     headers: {'X-Requested-With': 'XMLHttpRequest'}// }

The_ function

[edit]

Underscore derives its name from the function_, which serves multiple purposes.

Wrapper function

[edit]

As a function,_ returns a wrapped version of any value that is passed as its first argument. This special object has all Underscore functions as methods, thus enabling a different notation that is referred to as "OOP style":

import_,{last}from'underscore';// "Normal" or "functional" stylelast([1,2,3]);// 3// "OOP style"_([1,2,3]).last()// 3

This feature is used inchaining (next section). The value can be unwrapped again with the.value() method in order to further process it outside of Underscore. Values also unwrap automatically in some cases.

// Explicit unwrap_([1,2,3]).value()// [1, 2, 3]// Automatic unwrap when coerced to number1+_(2)// 3// Automatic unwrap when coerced to string'abc'+_('def')// 'abcdef'// Automatic unwrap when formatted as JSONJSON.stringify({a:_([1,2])})// '{"a":[1,2]}'

Partial application placeholder

[edit]

_ also acts as a placeholder for thepartial function.partial creates apartially applied version of a function and_ can be used to leave some parameters "open" so that these can be supplied later. For example, thegroupBy example from theoverview can be extended as follows to turn the expression into a reusable function:

import_,{partial,groupBy,first}from'underscore';constgroupByFirstChar=partial(groupBy,_,first);groupByFirstChar(['avocado','apricot','cherry','date','durian']);// { a: ['avocado', 'apricot'],//   c: ['cherry'],//   d: ['date', 'durian']// }groupByFirstChar(['chestnut','pistache','walnut','cashew']);// { c: ['chestnut', 'cashew'],//   p: ['pistache'],//   w: ['walnut]// }

Customization point

[edit]

Furthermore,_ serves as a centralcustomization point where users can adjust the behavior of Underscore functions to their needs. Specifically, users can override_.iteratee in order to create newiteratee shorthands, and_.templateSettings in order to customize thetemplate function.

Namespace handle

[edit]

More generally,all Underscore functions are present as properties on_, for example also_.map and_.debounce. This makes it possible to use_ as anamespace handle. With the arrival ofmodules inES6, having such a namespace handle is no longer strictly necessary, but the practice is still commonly found in code using older module systems such asAMD andCommonJS:

var_=require('underscore');_.groupBy(['avocado','apricot','cherry','date','durian'],_.first);

Given the existing practice, it can also be a convenient notation to clarify that one means a function specifically from the Underscore library and not a function with the same name from another library. For example, both Underscore andAsync provide a function namedeach; to distinguish between them, one may write_.each andasync.each, respectively.

Chaining

[edit]

The functionchain can be used to create a modified version of the wrapper produced bythe_ function. When invoked on such achained wrapper, each method returns a new wrapper so that the user can continue to process intermediate results with Underscore functions:

import{chain}from'underscore';constsquare=x=>x*x;constisOdd=x=>x%2;chain([1,2,3,4]).filter(isOdd).map(square).last()// returns a wrapper of 9

It is not uncommon for a function implemented with Underscore to consist entirely of areturn statement with a chain ending in.value():

constadd=(x,y)=>x+y;// Given an array of numbers, return the sum of the squares of// those numbers. This could be used in a statistics library.functionsumOfSquares(numbers){returnchain(numbers).map(square).reduce(add).value();}

Chaining is not exclusive to the functions that ship with Underscore. Users can enable chaining for their own functions as well by passing them to themixin function:

import{reduce,mixin}from'underscore';constsum=numbers=>reduce(numbers,add,0);mixin({sum,square});chain([1,2,3]).map(square).sum().value();// 14chain([1,2,3]).sum().square().value();// 36

In fact, this is exactly how chaining is enabled for Underscore's own functions as well. All Underscore functions are written as regular standalone functions, without any special preparations for chaining, and then "mixed into" the_ function afterwards.[26]

Iteratee shorthands

[edit]

As previously mentioned in theoverview, most Underscore functions that iterate over arrays or objects accept a shorthand notation as iteratee instead of a function. Repeating the example from that section here:

import{map}from'underscore';constpeople=[{name:'Lily',details:{age:44,occupation:'fire fighter'}},{name:'Harold',details:{age:10,occupation:'dreamer'}},{name:'Sasha',details:{age:68,occupation:'library developer'}}];map(people,'name');// ['Lily', 'Harold', 'Sasha']

Under the hood, this notation is enabled by passing the shorthand value through_.iteratee in order to obtain a function._.iteratee defaults to theiteratee function that ships with Underscore, which, depending on the value, returns a function as follows.

Paths

[edit]

When the value is a string,iteratee forwards the value toproperty, which interprets the string as a property key. It returns a function that attempts to extract the property with the given key from its argument. The following expressions are all equivalent:

import{iteratee,property}from'underscore';map(people,'name');map(people,iteratee('name'));map(people,property('name'));map(people,obj=>obj&&obj['name']);// ['Lily', 'Harold', 'Sasha']

Arrays and numbers are also passed toproperty. Arrays can be used to retrieve nested properties:

map(people,['details','occupation']);// ['fire fighter', 'dreamer', 'library developer']

Numbers can be used as array and string indices. Combining all of this, we can use the following expression to count how many times letters of the alphabet occur as the second character of a person's occupation:

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

Attribute hashes

[edit]

When the value is an object,iteratee forwards it tomatcher, which interprets the object as a set of attributes that must be matched. It returns a function that will returntrue orfalse depending on whether its argument has this same set of attributes.

import{find}from'underscore';find(people,{name:'Sasha'});// {name: 'Sasha', details: {age: 68, occupation: 'library developer'}}find(people,{name:'Walter'});// undefined

null andundefined

[edit]

When the value isnull orundefined,iteratee returns theidentity function that Underscore exports asidentity. This can be used to filter out the truthy values from a collection:

import{filter,iteratee,identity}from'underscore';constexample=[0,1,'','abc',true,false,{}];// The following expressions are all equivalent.filter(example);filter(example,undefined);filter(example,iteratee(undefined));filter(example,identity);// [1, 'abc', true, {}]

Overriding_.iteratee

[edit]

Users can override _.iteratee in order to create custom shorthands. The following example illustrates how one may use this to implement regular expression filtering:

import{iterateeasoriginalIteratee,isRegExp,mixin,filter,}from'underscore';functioniteratee(value,context){if(isRegExp(value)){returnstring=>value.test(string);}else{returnoriginalIteratee(value,context);}}mixin({iteratee});filter(['absolutely','amazing','fabulous','trousers'],/ab/);// ['absolutely', 'fabulous']

See also

[edit]

References

[edit]
  1. ^Release 0.1.0, jashkenas/underscore, GitHub
  2. ^"Release 1.13.7". 24 July 2024. Retrieved28 July 2024.
  3. ^"Underscore.js – ein kleines Framework mit Fokus".entwickler.de (in German). 20 June 2018. Retrieved9 July 2020.
  4. ^"JavaScript Meetup City",Open,The New York Times, April 4, 2012
  5. ^Ashkenas, Jeremy."Underscore 0.4.0 source".cdn.rawgit.com. Retrieved1 March 2021.
  6. ^"Lo-Dash v2.2.1".lodash.com. Archived from the original on 6 November 2013. Retrieved1 March 2021.
  7. ^"Lodash Changelog - 1.0.0 rc1".github.com. 4 December 2012. Retrieved1 March 2021.
  8. ^"Lodash Changelog - 3.0.0".github.com. 26 January 2015. Retrieved1 March 2021.
  9. ^Ashkenas, Jeremy (21 May 2015)."The Big Kahuna: Underscore + Lodash Merge Thread".github.com. Retrieved1 March 2021.
  10. ^"Underscore: merged pull requests with breaking changes between 21 May and 1 October 2015".github.com. Retrieved1 March 2021.
  11. ^Dalton, John-David (8 June 2015)."comment on 'Core API'".github.com. Retrieved1 March 2021.
  12. ^"Lodash changelog 4.0.0".github.com. 12 January 2016. Retrieved1 March 2021.
  13. ^"@sailshq/lodash".npmjs.com. Retrieved1 March 2021.
  14. ^Dalton, John-David (13 February 2016)."Merge update".github.com. Retrieved1 March 2021.
  15. ^Krebs, Adam (17 February 2016)."comment on 'Merge update.'".github.com. Retrieved1 March 2021.
  16. ^ab"jashkenas/underscore Insights: Contributors".github.com. Retrieved1 March 2021.
  17. ^"lodash/lodash Insight: Contributors".github.com. Retrieved1 March 2021.
  18. ^"Array.prototype.map".developer.mozilla.org. Retrieved1 March 2021.
  19. ^"Array.prototype.filter".developer.mozilla.org. Retrieved1 March 2021.
  20. ^"Array.prototype.forEach".developer.mozilla.org. Retrieved1 March 2021.
  21. ^"_.map".underscorejs.org. Retrieved1 March 2021.
  22. ^"_.filter".underscorejs.org. Retrieved1 March 2021.
  23. ^"_.each".underscorejs.org. Retrieved1 March 2021.
  24. ^"underscore".npmjs.com. Retrieved1 March 2021.
  25. ^Gonggrijp, Julian."modules/index.js".underscorejs.org. Retrieved5 March 2021.
  26. ^Gonggrijp, Julian."modules/index-default.js".underscorejs.org. Retrieved4 March 2021.

External links

[edit]
Libraries
Concepts
Platform
Packaging
Frameworks
Libraries
Languages
Retrieved from "https://en.wikipedia.org/w/index.php?title=Underscore.js&oldid=1337136483"
Categories:
Hidden categories:

[8]ページ先頭

©2009-2026 Movatter.jp