JavaScript 개발자를 위한 10가지 중요한 Lodash 함수
게시 됨: 2021-10-05JavaScript 개발자에게 Lodash는 소개가 필요 없습니다. 그러나 도서관은 방대하고 종종 압도적으로 느껴집니다. 더 이상은 안돼!
로다쉬, 로다쉬, 로다쉬 . . . 나는 어디에서 시작합니까!
JavaScript 생태계가 초기 단계에 있었던 때가 있었습니다. 원한다면 황무지나 정글과 비교할 수 있습니다. 그곳에서는 많은 일이 진행되었지만 일상적인 개발자의 좌절과 생산성에 대한 답변은 거의 없었습니다.
그런 다음 Lodash가 현장에 들어갔고 모든 것을 잠긴 홍수처럼 느껴졌습니다. 정렬과 같은 단순한 일상적 요구에서 복잡한 데이터 구조 변환에 이르기까지 Lodash는 JS 개발자의 삶을 완전한 행복으로 바꿔주는 기능을 탑재했습니다.

그리고 오늘 Lodash는 어디에 있습니까? 글쎄, 그것은 여전히 처음에 제공했던 모든 장점을 가지고 있고 그 다음에는 일부를 제공하지만 JavaScript 커뮤니티에서 마음 점유율을 잃은 것 같습니다. 왜요? 몇 가지 이유를 생각할 수 있습니다.
- Lodash 라이브러리의 일부 기능은 큰 목록에 적용될 때 느렸습니다. 이것이 프로젝트의 95%에 영향을 미치지는 않았을 것이지만, 나머지 5%의 영향력 있는 개발자는 Lodash에 나쁜 평판을 줬고 그 효과는 풀뿌리로 떨어졌습니다.
- 자만심이 필요 이상으로 흔한 JS 생태계(Golang 사람들에 대해서도 같은 말을 할 수도 있음)의 추세가 있습니다. 따라서 Lodash와 같은 것에 의존하는 것은 어리석은 것으로 간주되며 사람들이 그러한 솔루션을 제안할 때 StackOverflow와 같은 포럼에서 격추됩니다("뭐?! 이와 같은 것을 위해 전체 라이브러리를 사용합니까? 나는
filter()와reduce()를 결합하여 달성할 수 있습니다. 간단한 함수에서 같은 것을!”). - 로다시는 늙었다. 적어도 JS 표준에서는. 2012년에 나왔으니 글을 쓰는 시점으로 거의 10년이 되었습니다. API는 안정적이었고 매년 추가할 수 있는 흥미로운 항목은 많지 않습니다(단순히 그럴 필요가 없기 때문에). 이는 평균적으로 지나치게 흥분한 JS 개발자를 지루하게 만듭니다.
제 생각에는 Lodash를 사용하지 않는 것은 JavaScript 코드베이스에 상당한 손실입니다. 우리가 직장에서 겪는 일상적인 문제에 대해 버그가 없고 우아한 솔루션이 입증되었으며 이를 사용하면 코드를 더 읽기 쉽고 유지 관리하기 쉽게 만들 수 있습니다.
그렇긴 하지만 일반적인(또는 그렇지 않은!) Lodash 기능을 살펴보고 이 라이브러리가 얼마나 믿을 수 없을 정도로 유용하고 아름다운지 살펴보겠습니다.
클론 . . . 깊이!
JavaScript에서는 객체가 참조로 전달되기 때문에 새 데이터 세트가 다를 것이라는 희망으로 무언가를 복제하려고 할 때 개발자에게 골칫거리가 됩니다.
let people = [ { name: 'Arnold', specialization: 'C++', }, { name: 'Phil', specialization: 'Python', }, { name: 'Percy', specialization: 'JS', }, ]; // Find people writing in C++ let folksDoingCpp = people.filter((person) => person.specialization == 'C++'); // Convert them to JS! for (person of folksDoingCpp) { person.specialization = 'JS'; } console.log(folksDoingCpp); // [ { name: 'Arnold', specialization: 'JS' } ] console.log(people); /* [ { name: 'Arnold', specialization: 'JS' }, { name: 'Phil', specialization: 'Python' }, { name: 'Percy', specialization: 'JS' } ] */ 우리의 순수한 순수함과 우리의 좋은 의도에도 불구하고 원래 people 배열이 프로세스에서 어떻게 돌연변이되었는지(Arnold의 전문 분야가 C++ 에서 JS 변경됨) 기본 소프트웨어 시스템의 무결성에 큰 타격을 주는 것을 주목하십시오! 실제로 우리는 원본 배열의 진정한(깊은) 복사본을 만드는 방법이 필요합니다.

이것이 JS에서 코딩하는 "어리석은" 방법이라고 주장할 수 있습니다. 그러나 현실은 조금 복잡합니다. 예, 우리는 사용할 수 있는 멋진 구조 해제 연산자를 사용할 수 있지만 복잡한 객체와 배열을 구조화하려고 시도한 사람은 누구나 그 고통을 알고 있습니다. 그런 다음 직렬화 및 역직렬화(아마도 JSON)를 사용하여 깊은 복사를 달성하는 아이디어가 있지만 이는 독자에게 코드를 더 지저분하게 만들 뿐입니다.
대조적으로, Lodash가 사용될 때 솔루션이 얼마나 놀랍도록 우아하고 간결한지 보십시오.
const _ = require('lodash'); let people = [ { name: 'Arnold', specialization: 'C++', }, { name: 'Phil', specialization: 'Python', }, { name: 'Percy', specialization: 'JS', }, ]; let peopleCopy = _.cloneDeep(people); // Find people writing in C++ let folksDoingCpp = peopleCopy.filter( (person) => person.specialization == 'C++' ); // Convert them to JS! for (person of folksDoingCpp) { person.specialization = 'JS'; } console.log(folksDoingCpp); // [ { name: 'Arnold', specialization: 'JS' } ] console.log(people); /* [ { name: 'Arnold', specialization: 'C++' }, { name: 'Phil', specialization: 'Python' }, { name: 'Percy', specialization: 'JS' } ] */ 딥 클로닝 후 people 배열이 어떻게 변경되지 않았는지 확인하십시오(Arnold는 이 경우 여전히 C++ 을 전문으로 합니다). 그러나 더 중요한 것은 코드가 이해하기 쉽습니다.
배열에서 중복 제거
배열에서 중복을 제거하는 것은 훌륭한 인터뷰/화이트보드 문제처럼 들립니다(의심스러울 때는 문제에 해시맵을 던지십시오!). 물론 그렇게 하기 위해 항상 사용자 정의 함수를 작성할 수 있지만 배열을 고유하게 만드는 여러 가지 시나리오가 발생하면 어떻게 될까요? 이를 위해 몇 가지 다른 기능을 작성할 수 있습니다(그리고 미묘한 버그가 발생할 위험이 있음). 또는 Lodash를 사용할 수 있습니다!

고유한 어레이의 첫 번째 예는 다소 사소하지만 여전히 Lodash가 테이블에 제공하는 속도와 안정성을 나타냅니다. 모든 사용자 정의 논리를 직접 작성하여 이 작업을 수행한다고 상상해 보십시오!
const _ = require('lodash'); const userIds = [12, 13, 14, 12, 5, 34, 11, 12]; const uniqueUserIds = _.uniq(userIds); console.log(uniqueUserIds); // [ 12, 13, 14, 5, 34, 11 ]최종 배열이 정렬되지 않았음을 주목하세요. 물론 여기에서는 문제가 되지 않습니다. 하지만 이제 더 복잡한 시나리오를 상상해 보겠습니다. 어딘가에서 가져온 사용자 배열이 있지만 여기에는 고유한 사용자만 포함되어야 합니다. Lodash로 간편하게!
const _ = require('lodash'); const users = [ { id: 10, name: 'Phil', age: 32 }, { id: 8, name: 'Jason', age: 44 }, { id: 11, name: 'Rye', age: 28 }, { id: 10, name: 'Phil', age: 32 }, ]; const uniqueUsers = _.uniqBy(users, 'id'); console.log(uniqueUsers); /* [ { id: 10, name: 'Phil', age: 32 }, { id: 8, name: 'Jason', age: 44 }, { id: 11, name: 'Rye', age: 28 } ] */ 이 예제에서는 uniqBy() 메서드를 사용하여 uniqBy() 에 개체가 id 속성에서 고유한 개체가 되기를 원한다고 알렸습니다. 한 줄로 10-20줄을 사용할 수 있는 내용을 표현하고 더 많은 버그 범위를 도입했습니다!
Lodash에서 고유한 것을 만드는 데 사용할 수 있는 더 많은 항목이 있으며 문서를 살펴보는 것이 좋습니다.
두 배열의 차이
연합, 차이 등은 집합 이론에 대한 지루한 고등학교 강의에서 가장 잘 뒤에 남겨진 용어처럼 들릴지 모르지만 일상적인 연습에서는 그렇지 않은 것보다 더 자주 나타납니다. 목록이 있고 다른 목록을 그 목록과 병합하거나 다른 목록과 비교하여 고유한 요소를 찾으려는 것이 일반적입니다. 이러한 시나리오의 경우 차이 함수는 완벽합니다.

간단한 시나리오를 통해 차이 여행을 시작해 보겠습니다. 시스템의 모든 사용자 ID 목록과 계정이 활성화된 사용자 ID 목록을 받았습니다. 비활성 ID는 어떻게 찾나요? 간단하죠?
const _ = require('lodash'); const allUserIds = [1, 3, 4, 2, 10, 22, 11, 8]; const activeUserIds = [1, 4, 22, 11, 8]; const inactiveUserIds = _.difference(allUserIds, activeUserIds); console.log(inactiveUserIds); // [ 3, 2, 10 ] 그리고 더 현실적인 설정에서 발생하는 것처럼 일반 기본 요소 대신 객체 배열로 작업해야 한다면 어떻게 될까요? 글쎄요, Lodash에는 이를 위한 좋은 differenceBy() 메서드가 있습니다!
const allUsers = [ { id: 1, name: 'Phil' }, { id: 2, name: 'John' }, { id: 3, name: 'Rogg' }, ]; const activeUsers = [ { id: 1, name: 'Phil' }, { id: 2, name: 'John' }, ]; const inactiveUsers = _.differenceBy(allUsers, activeUsers, 'id'); console.log(inactiveUsers); // [ { id: 3, name: 'Rogg' } ]깔끔하죠?!
차이점과 마찬가지로 Lodash에는 공용 집합 연산에 대한 다른 메서드가 있습니다: 합집합, 교집합 등.
배열 병합
어레이를 병합해야 하는 경우가 종종 있습니다. 한 가지 사용 사례는 API 응답을 받았고 중첩된 객체/배열의 복잡한 목록에 일부 map() 및 filter() 콤보를 적용하여 예를 들어 사용자 ID를 뽑아야 하는 경우입니다. 배열의 배열. 다음은 이 상황을 나타내는 코드 스니펫입니다.
const orderData = { internal: [ { userId: 1, date: '2021-09-09', amount: 230.0, type: 'prepaid' }, { userId: 2, date: '2021-07-07', amount: 130.0, type: 'prepaid' }, ], external: [ { userId: 3, date: '2021-08-08', amount: 30.0, type: 'postpaid' }, { userId: 4, date: '2021-06-06', amount: 330.0, type: 'postpaid' }, ], }; // find user ids that placed postpaid orders (internal or external) const postpaidUserIds = []; for (const [orderType, orders] of Object.entries(orderData)) { postpaidUserIds.push(orders.filter((order) => order.type === 'postpaid')); } console.log(postpaidUserIds); 이제 postPaidUserIds 어떻게 postPaidUserIds 짐작할 수 있습니까? 힌트: 역겹다!
[ [], [ { userId: 3, date: '2021-08-08', amount: 30, type: 'postpaid' }, { userId: 4, date: '2021-06-06', amount: 330, type: 'postpaid' } ] ] 이제 당신이 현명한 사람이라면 주문 개체를 추출하고 배열 내부의 행에 멋지게 배치하는 사용자 정의 논리를 작성하고 싶지 않을 것입니다. flatten() 메서드를 사용하고 포도를 즐기십시오.
const flatUserIds = _.flatten(postpaidUserIds); console.log(flatUserIds); /* [ { userId: 3, date: '2021-08-08', amount: 30, type: 'postpaid' }, { userId: 4, date: '2021-06-06', amount: 330, type: 'postpaid' } ] */ flatten() 은 한 단계만 진행한다는 점에 유의하십시오. 즉, 객체가 2, 3 또는 그 이상의 수준으로 갇힌 경우 flatten() 실망할 것입니다. 이러한 경우 Lodash에는 flattenDeep() 메서드가 있지만 매우 큰 구조에 이 메서드를 적용하면 작업 속도가 느려질 수 있습니다(뒤에서 재귀 연산이 작동함).

개체/배열이 비어 있습니까?
JavaScript에서 "falsy" 값과 유형이 작동하는 방식 덕분에 때로는 비어 있는지 확인하는 것과 같은 간단한 작업이 실존적 공포를 초래합니다.

배열이 비어 있는지 어떻게 확인합니까? length 가 0 인지 아닌지 확인할 수 있습니다. 이제 객체가 비어 있는지 어떻게 확인합니까? 음...잠깐만요! 여기서 그 불안한 감정이 시작되고 [] == false 및 {} == false 와 같은 항목이 포함된 JavaScript 예제가 머리를 맴돌기 시작합니다. 기능을 제공해야 한다는 압박을 받을 때 이와 같은 지뢰는 마지막으로 필요한 것입니다. 지뢰는 코드를 이해하기 어렵게 만들고 테스트 제품군에 불확실성을 야기합니다.
누락된 데이터 작업
현실 세계에서 데이터는 우리의 말을 듣습니다. 우리가 아무리 간절히 원하더라도 간소화되고 제정신이 아닌 경우는 거의 없습니다. 한 가지 일반적인 예는 API 응답으로 수신된 대규모 데이터 구조에서 null 객체/배열이 누락된 것입니다.

다음 객체를 API 응답으로 받았다고 가정합니다.
const apiResponse = { id: 33467, paymentRefernce: 'AEE3356T68', // `order` object missing processedAt: `2021-10-10 00:00:00`, }; 표시된 것처럼 일반적으로 API의 응답에서 order 개체를 가져오지만 항상 그런 것은 아닙니다. 그렇다면 이 객체에 의존하는 코드가 있다면 어떨까요? 한 가지 방법은 방어적으로 코딩하는 것이지만 order 객체가 얼마나 중첩되었는지에 따라 런타임 오류를 피하려면 곧 매우 못생긴 코드를 작성하게 될 것입니다.
if ( apiResponse.order && apiResponse.order.payee && apiResponse.order.payee.address ) { console.log( 'The order was sent to the zip code: ' + apiResponse.order.payee.address.zipCode ); }예, 쓰기에 매우 보기 흉하고, 읽기에 매우 보기 흉하고, 유지하기가 매우 보기 흉합니다. 고맙게도 Lodash는 이러한 상황을 처리하는 간단한 방법을 가지고 있습니다.
const zipCode = _.get(apiResponse, 'order.payee.address.zipCode'); console.log('The order was sent to the zip code: ' + zipCode); // The order was sent to the zip code: undefined 누락된 항목에 대해 undefined 대신 기본값을 제공하는 환상적인 옵션도 있습니다.
const zipCode2 = _.get(apiResponse, 'order.payee.address.zipCode', 'NA'); console.log('The order was sent to the zip code: ' + zipCode2); // The order was sent to the zip code: NA 나는 당신에 대해 모르지만 get() 은 내 눈에 행복의 눈물을 가져다주는 것들 중 하나입니다. 화려하지 않습니다. 암기할 구문이나 옵션은 없지만 이것이 완화할 수 있는 집단적 고통의 양을 보십시오!
디바운싱
익숙하지 않은 경우를 대비하여 디바운싱은 프론트엔드 개발의 일반적인 주제입니다. 아이디어는 때때로 즉시가 아니라 일정 시간(일반적으로 몇 밀리초) 후에 작업을 시작하는 것이 유리하다는 것입니다. 그게 무슨 뜻이야? 여기 예가 있습니다.

검색 표시줄이 있는 전자 상거래 웹사이트를 상상해 보십시오(요즘 모든 웹사이트/웹 앱!). 더 나은 UX를 위해 사용자가 검색어를 기반으로 제안/미리보기를 표시하기 위해 Enter 키를 누르거나 더 나쁘게는 "검색" 버튼을 누르는 것을 원하지 않습니다. 그러나 분명한 대답은 약간 로드되어 있습니다. 검색 표시줄에 대해 onChange() 에 이벤트 리스너를 추가하고 모든 키 입력에 대해 API 호출을 실행하면 백엔드에 악몽이 생겼을 것입니다. 불필요한 호출이 너무 많으며(예: "흰색 카펫 브러시"를 검색하면 총 18개의 요청이 있을 것입니다!) 사용자 입력이 완료되지 않았기 때문에 거의 모두 관련이 없습니다.
답은 디바운싱에 있으며 아이디어는 다음과 같습니다. 텍스트가 변경되자마자 API 호출을 보내지 마십시오. 일정 시간(예: 200밀리초) 동안 기다렸다가 그 때까지 다른 키 입력이 있으면 이전 시간 계산을 취소하고 다시 대기를 시작합니다. 결과적으로, 우리는 백엔드에 API 요청을 보내는 것은 사용자가 일시 중지할 때만(생각을 하고 있기 때문에 또는 완료하고 일부 응답을 기대하기 때문입니다.)
내가 설명한 전체 전략은 복잡하며 타이머 관리와 취소의 동기화에 대해 자세히 설명하지 않겠습니다. 그러나 Lodash를 사용하는 경우 실제 디바운싱 프로세스는 매우 간단합니다.
const _ = require('lodash'); const axios = require('axios'); // This is a real dogs' API, by the way! const fetchDogBreeds = () => axios .get('https://dog.ceo/api/breeds/list/all') .then((res) => console.log(res.data)); const debouncedFetchDogBreeds = _.debounce(fetchDogBreeds, 1000); // after one second debouncedFetchDogBreeds(); // shows data after some time setTimeout() 생각하고 있다면 같은 작업을 수행했을 것입니다. 글쎄, 더 많은 것이 있습니다! Lodash의 디바운스에는 많은 강력한 기능이 포함되어 있습니다. 예를 들어, 디바운스가 무기한이 아닌지 확인하고 싶을 수 있습니다. 즉, 함수가 시작될 때마다 키 입력이 있더라도(따라서 전체 프로세스가 취소됨) 2초 후에 어쨌든 API 호출이 이루어지도록 해야 할 수 있습니다. 이를 위해 Lodash debounce() 에는 maxWait 옵션이 있습니다.
const debouncedFetchDogBreeds = _.debounce(fetchDogBreeds, 150, { maxWait: 2000 }); // debounce for 250ms, but send the API request after 2 seconds anyway더 자세한 내용은 공식 문서를 확인하세요. 그들은 매우 중요한 것들로 가득 차 있습니다!
배열에서 값 제거
나는 당신에 대해 모르지만 배열에서 항목을 제거하는 코드를 작성하는 것을 싫어합니다. 먼저 항목의 인덱스를 가져와서 인덱스가 실제로 유효한지 확인하고 유효하다면 splice() 메서드를 호출하는 등의 작업을 수행해야 합니다. 구문이 기억나지 않아 항상 찾아봐야 하고, 마지막에는 어리석은 버그가 들어왔다는 잔소리만 남습니다.

const greetings = ['hello', 'hi', 'hey', 'wave', 'hi']; _.pull(greetings, 'wave', 'hi'); console.log(greetings); // [ 'hello', 'hey' ]두 가지 사항에 유의하십시오.
- 이 과정에서 원래 배열이 변경되었습니다.
-
pull()메서드는 중복이 있더라도 모든 인스턴스를 제거합니다.
한 번에 여러 항목을 쉽게 제거할 수 있도록 두 번째 매개변수로 배열을 받아들이는 pullAll() 이라는 또 다른 관련 메서드가 있습니다. 스프레드 연산자와 함께 pull() 을 사용할 수 있다는 것은 인정하지만, Lodash는 스프레드 연산자가 언어에서 제안조차 하지 않았을 때 등장했다는 것을 기억하십시오!
const greetings2 = ['hello', 'hi', 'hey', 'wave', 'hi']; _.pullAll(greetings2, ['wave', 'hi']); console.log(greetings2); // [ 'hello', 'hey' ]요소의 마지막 인덱스
반대 방향에서 배열을 스캔하는 데 관심이 있는 경우를 제외하고 JavsScript의 기본 indexOf() 메서드는 훌륭합니다! 그리고 다시, 예, 감소 루프를 작성하고 요소를 찾을 수 있지만 훨씬 더 우아한 기술을 사용하지 않는 이유는 무엇입니까?

다음은 lastIndexOf() 메서드를 사용하는 빠른 Lodash 솔루션입니다.
const integers = [2, 4, 1, 6, -1, 10, 3, -1, 7]; const index = _.lastIndexOf(integers, -1); console.log(index); // 7불행히도, 복잡한 객체를 조회하거나 사용자 정의 조회 기능을 전달할 수 있는 이 방법의 변형은 없습니다.
지퍼. 압축을 푼다!

Python에서 작업한 적이 없다면 zip/unzip은 JavaScript 개발자로서의 전체 경력에서 결코 눈치채거나 상상할 수 없는 유틸리티입니다. 그리고 아마도 그럴만한 이유가 있습니다: filter() 등의 경우처럼 zip/unzip이 필사적으로 필요한 경우는 거의 없습니다. 그러나 이것은 가장 잘 알려지지 않은 유틸리티 중 하나이며 어떤 상황에서는 간결한 코드를 만드는 데 도움이 될 수 있습니다. .
소리와 달리 zip/unzip은 압축과 관련이 없습니다. 대신, 동일한 길이의 배열을 동일한 위치에 있는 요소가 함께 묶인( zip() ) 다시( unzip() ) 배열의 단일 배열로 변환할 수 있는 그룹화 작업입니다. 예, 알아요. 단어를 사용하려고 하면 흐릿해집니다. 따라서 몇 가지 코드를 살펴보겠습니다.
const animals = ['duck', 'sheep']; const sizes = ['small', 'large']; const weight = ['less', 'more']; const groupedAnimals = _.zip(animals, sizes, weight); console.log(groupedAnimals); // [ [ 'duck', 'small', 'less' ], [ 'sheep', 'large', 'more' ] ] 원래 3개의 어레이는 2개의 어레이만 있는 단일 어레이로 변환되었습니다. 그리고 이 새로운 배열 각각은 한 곳에 모든 것이 들어 있는 단일 동물을 나타냅니다. 따라서 인덱스 0 은 동물의 유형을 알려주고 인덱스 1 은 크기를, 인덱스 2 는 무게를 알려줍니다. 결과적으로 데이터 작업이 더 쉬워졌습니다. 데이터에 필요한 작업을 모두 적용했으면 unzip() 사용하여 데이터를 다시 unzip() 하고 원래 소스로 다시 보낼 수 있습니다.
const animalData = _.unzip(groupedAnimals); console.log(animalData); // [ [ 'duck', 'sheep' ], [ 'small', 'large' ], [ 'less', 'more' ] ]zip/unzip 유틸리티는 하룻밤 사이에 당신의 삶을 바꾸는 것이 아니지만 언젠가는 당신의 삶을 바꿀 것입니다!
결론
(이 기사에 사용된 모든 소스 코드는 브라우저에서 직접 시도할 수 있도록 여기에 넣었습니다!)
Lodash 문서는 당신의 마음을 사로잡을 예제와 기능으로 가득 차 있습니다. JS 생태계에서 마조히즘이 증가하는 것처럼 보이는 시대에 Lodash는 신선한 공기와도 같으며 프로젝트에서 이 라이브러리를 사용하는 것이 좋습니다!
