JavaScript에서 모든 메서드를 연결 가능하게 만드는 방법

TLDR;


  • jQuery가 웹과 JavaScript를 앞으로 밀었지만 해당 메서드 연결이 크게 누락되었습니다.

  • 이것을 되돌릴 수 있는 방법이 있다고 말하면 어떻게 될까요?
  • 이것은 제가 여기에서 이야기하려고 하지 않은 것을 나타내는 것일 수 있습니다 👀

  • 왜 누군가가 이것에 관심을 가져야 합니까?



    JavaScript에 대한 경험과 상관없이 jQuery에 대해 들어본 적이 있을 것입니다. 2000년대 초중반 동안 웹은 개발자가 웹 페이지 모음에 비해 유동적인 사용자 경험을 만들 수 있는 성숙도 수준에 도달했습니다.

    하지만 자바스크립트와 웹 브라우저 API가 다른 프로그래밍 언어와 비교했을 때 이 작업은 지루한 작업이었습니다. fetch 또는 document.querySelector 가 없다고 상상해보십시오. 꽤 거칠죠? 글쎄요, jQuery는 모든 공백을 채웠고 그 다음에는 일부를 채웠습니다. 일부에게 jQuery는 클라이언트 측 웹 개발의 표준 라이브러리였습니다. 그러나 그것은 그때였습니다. JavaScript and the web has evolved .

    그러나 JavaScript 및 웹 API를 향상시키는 모든 중요한 개선 사항과 함께 jQuery's method chaining was largely left behind . 그리고 이것 때문에 jQuery isn't leaving the tool-belt of some developers . 그들을 비난할 수 있습니까? jQuery는 깨끗한 개발자 경험을 제공하면서 유사하게 깨끗한 사용자 경험을 구축하기 위한 도구를 제공했습니다. 이것을 되돌릴 수 있는 비교적 빠르고 고통 없는 방법은 무엇입니까?

    메소드 체이닝이란?




    $("#p1").css("color", "red").slideUp(2000).slideDown(2000);
    

    .css , .slideUp , slideDown 와 같은 연결 방법은 표현력이 뛰어나고 간결합니다. jQuery's implementation represents a Fluent Interface , 코드가 거의 일반 영어처럼 읽히는 expressiveness 수준을 제공합니다.

    네이티브 메소드 체이닝은 깔끔하지 않을까요?




    document.querySelector("#p1")
      .setCss({ transition: 'height 2s', height: '0px' })
      .setCss({ height: '100px' });
    


    이것은 달성할 수 있지만 one would need to know and care about implementation details between the DOM and one's app 대부분의 사용 사례에 필요한 것보다 훨씬 더 복잡할 수 있습니다.

    상자를 사용한 일반 메서드 체이닝 소개




    Box(document.getElementById('p1'))
        .modifyContents(slideUp(2000))
        .modifyContents(slideDown(2000, '100px'));
    


    목표는 원하는 것을 상자 안에 넣는 것입니다. 두 가지 방법replaceContents과 modifyContents를 사용하면 일시적으로 항목을 상자 외부로 가져와 작업을 수행하고 다른 상자에 넣을 수 있습니다.

    이 접근 방식을 사용하면 원하는 것(메서드 연결)과 이미 작성 중인 것(DOM 조작)을 명확하게 구분할 수 있습니다. 또한 고도로 모듈화된 독립적인 코드를 작성하고 테스트하기가 더 쉽습니다.

    import { Box } from './box' // highly modular
    import { slideUp, slideDown } from './dom' // bring your own implementation details
    


    이 메서드 체인 형식이 정말 일반적입니까?



    번호




    const four = Box(4);
    const eight = four
      .replaceContents((num) => num * 2)
      .modifyContents(console.log); // 8
    
    const ten = eight
      .replaceContents((num) => num + 2)
      .modifyContents(console.log); // 10
    


    배열




    const nums = Box([1, 2, 3, 4, 5]);
    const evens = nums
      .replaceContents((numArr) => numArr.map((x) => x + 2))
      .modifyContents(console.log) // [3, 4, 5, 6, 7]
      .replaceContents((sums) => sums.filter((x) => x % 2 === 0))
      .modifyContents(console.log); // [4, 6]
    


    혼합 유형(맵, 배열)




    const gteTo2 = Box(new Map([["a", 1], ["b", 2], ["c", 3]]))
      .replaceContents((table) => [...table.entries()])
      .replaceContents((arr) => arr.filter(([, value]) => value >= 2))
      .replaceContents((arr) => new Map(arr))
      .modifyContents(console.log); // Map { 'b' => 2, 'c' => 3 }
    


    예!

    상자는 모든 유형에서 작동합니다. 두 가지 방법replaceContents과 modifyContents에는 단일 매개변수가 있으며, 이는 상자 안에 있는 항목이 무엇이든 상관없습니다.

    상자는 프리미티브 또는 객체를 포함할 수 있습니다. 두 메서드의 차이점은 replaceContents는 값을 반환해야 하고 modifyContents는 반환하지 않는다는 것입니다. 즉, replaceContents는 불변성을 보장하는데 좋습니다.

    TypeScript 또는 다른 언어에 대한 인터페이스는 다음과 같습니다.

    interface IBox<T> {
      replaceContents: <V>(fn: (item: T) => V) => IBox<V>;
      modifyContents: (fn: (item: T) => void) => IBox<T>;
    }
    


    Box는 Fluent Interfaces와 어떻게 비교됩니까?





    상자
    유창한 인터페이스


    메소드 체이닝
    ✅
    ✅

    높은 표현력
    ✅
    ✅

    불변성 지원
    ✅
    ✅

    디버거 친화적
    ✅
    ❌

    로깅 친화적
    ✅
    ❌

    모든 데이터 유형에서 작동
    ✅
    ❌

    모듈 친화적
    ✅
    ❌


    판매된? 상자의 모양은 다음과 같습니다.




    function Box(item) {
        const replaceContents = (fn) => Box(fn(item));
        const modifyContents = (fn) => {
            fn(item);
            return Box(item);
        };
        return { replaceContents, modifyContents };
    };
    


    잠깐만, 상자는 당신이 알고 있는 것입니까?



    👀

    좋은 웹페이지 즐겨찾기