목차
서문
북마크 애플리케이션
서비스서버측 집계" >서비스서버측 집계
클라이언트 측 집계
更进一步
웹 프론트엔드 JS 튜토리얼 JavaScript 함수형 프로그래밍 튜토리얼에 대한 간략한 토론(그림)

JavaScript 함수형 프로그래밍 튜토리얼에 대한 간략한 토론(그림)

Mar 13, 2017 pm 05:12 PM

서문

4월 초 베이징에 갔을 때 동급생 Xu Hao가 우리 회사 동료들이 쓴 기사가 너무 단순하고 세부 사항에 너무 많은 관심을 기울였다고 말했습니다. 그리고 수박을 잃어버려서 다시 블로그 업데이트를 하지 않았습니다(사실 프로젝트가 너무 바쁜 것이 근본 원인입니다). 지난 주에는 동료 여러 명과 함께 "Martin Fowler Shenzhen Tour" 이벤트에 참가했습니다. 동료 Tashi와 저는 Yang Yun(Jianghu의 Big Devil으로 알려짐)과 함께 "FullStack Language JavaScript"를 기고했습니다. ) )의 주제는 " 기능적 프로그래밍 및 제어 시스템 복잡성 마스터하기"이고, Li Xin(Jianghu에서는 Xin Ye로 알려짐)의 주제는 "동시성: 과거와 사후 세계"입니다.

다른 동료들과 리허설을 하다가 갑자기 제가 이야기한 부분이 이벤트 기반 동시성 메커니즘과 함수형 프로그래밍과도 관련이 있다는 것을 깨달았습니다. 잘 생각해 보면 JavaScript 자체의 특성과 관련이 있어야 합니다.

  1. Event-Based Node.js는 동시성에서 매우 일반적인 모델입니다.

  2. 함수형 프로그래밍으로 자연스럽게 콜백을 지원하므로 비동기/이벤트 메커니즘에 매우 적합합니다.

  3. 함수형 프로그래밍으로 글쓰기에 매우 적합합니다. DSL

회의 다음날 갑자기 프로젝트 코드에서 함수형 프로그래밍을 사용하여 집계 모델을 다시 작성하고 싶었는데 그 아이디어가 막연하게 관련되어 있는 것으로 나타났습니다. NoSQL을 사용하면서 더 나아가 나에게 많은 단점이 있다는 것을 발견했습니다.

다음 예는 실제 프로젝트의 한 장면에서 나온 것인데, 도메인이 전환되었지만 그 뒤에 있는 메커니즘을 읽고 이해하는 데에는 전혀 영향을 미치지 않습니다.

북마크 애플리케이션

사용자가 구독한 RSS 목록을 볼 수 있는 애플리케이션을 상상해 보세요. 목록(피드라고 함)의 각 항목에는 id, 기사 제목 title 및 기사 링크 url가 포함되어 있습니다.

데이터 모델은 다음과 같습니다.

var feeds = [
    {
        'id': 1,
        'url': 'http://abruzzi.github.com/2015/03/list-comprehension-in-python/',
        'title': 'Python中的 list comprehension 以及 generator'
    },
    {
        'id': 2,
        'url': 'http://abruzzi.github.com/2015/03/build-monitor-script-based-on-inotify/',
        'title': '使用inotify/fswatch构建自动监控脚本'
    },
    {
        'id': 3,
        'url': 'http://abruzzi.github.com/2015/02/build-sample-application-by-using-underscore-and-jquery/',
        'title': '使用underscore.js构建前端应用'
    }
];
로그인 후 복사

이 간단한 애플리케이션에 사용자 관련 정보가 없으면 모델은 매우 간단합니다. 하지만 곧 독립 실행형 버전에서 웹 버전으로 애플리케이션을 확장해야 했습니다. 즉, 사용자라는 개념을 도입했습니다. 모든 사용자는 그러한 목록을 하나 볼 수 있습니다. 또한 사용자는 피드를 수집할 수도 있습니다. 물론 수집 후 사용자는 수집된 피드 목록을 볼 수도 있습니다.

feed and user

각 사용자가 여러 개의 피드를 수집할 수 있고, 각 피드는 여러 사용자가 수집할 수도 있으므로 이들 사이의 다대다 관계는 위 그림과 같습니다. .

$ curl http://www.php.cn/:9999/user/1/feeds
로그인 후 복사

를 사용하여 1 사용자의 feed을 모두 가져오는 등의 작업을 생각할 수도 있지만 실제 문제는 모든 피드를 얻은 후 UI, 각 피드에 속성makred을 추가해야 합니다. 이 속성은 피드가 수집되었는지 여부를 나타내는 데 사용됩니다. 인터페이스에 따라 노란색 별일 수도 있고 빨간색 하트일 수도 있습니다.

bookmarkds design

서비스서버측 집계

관계형 데이터베이스의 한계로 인해 서버측에서 집계를 수행해야 합니다. 개체 를 래핑하여 FeedWrapper:

public class FeedWrapper {
    private Feed feed;
    private boolean marked;

    public boolean isMarked() {
        return marked;
    }

    public void setMarked(boolean marked) {
        this.marked = marked;
    }

    public FeedWrapper(Feed feed, boolean marked) {
        this.feed = feed;
        this.marked = marked;
    }
}
로그인 후 복사

와 같은 개체를 생성한 다음 FeedService:

public ArrayList<FeedWrapper> wrapFeed(List<Feed> markedFeeds, List<Feed> feeds) {
    return newArrayList(transform(feeds, new Function<Feed, FeedWrapper>() {
        @Override
        public FeedWrapper apply(Feed feed) {
            if (markedFeeds.contains(feed)) {
                return new FeedWrapper(feed, true);
            } else {
                return new FeedWrapper(feed, false);
            }
        }
    }));
}
로그인 후 복사

와 같은 서비스 개체를 정의합니다. 좋습니다. 통과 가능한 구현으로 간주될 수 있지만 정적강력한 유형의 Java는 이를 수행하는 것을 약간 꺼려하며 일단 새로운 변경 사항이 발생하면(거의 확실하게 발생함) 이 로직 부분을 JavaScript에 넣습니다. , 이 프로세스가 어떻게 단순화되는지 살펴보겠습니다.

클라이언트 측 집계

본 기사에서는 lodash를 함수형 프로그래밍 라이브러리로 사용하여 코드 작성을 단순화하겠습니다. JavaScript는 동적으로 약한 유형의 언어이므로 언제든지 객체에 속성을 추가할 수 있습니다. 이러한 방식으로 간단한 map 작업으로 위의 Java 해당 코드인

_.map(feeds, function(item) {
    return _.extend(item, {marked: isMarked(item.id)});
});
로그인 후 복사

를 완성할 수 있습니다. > isMarked

var userMarkedIds = [1, 2];
function isMarked(id) {
    return _.includes(userMarkedIds, id);
}
로그인 후 복사

와 같은 작업을 수행합니다. 즉, 들어오는 매개변수가

목록에 있는지 확인합니다. 이 목록은 다음 요청으로 얻을 수 있습니다. All of userMarkedIds

$ curl http://www.php.cn/:9999/user/1/marked-feed-ids
로그인 후 복사

만 획득됩니다. ID는 네트워크 전송의 데이터 크기를 줄이기 위한 것입니다. 물론 모든

을 요청한 다음 로컬에서 /marked-feeds을 수행하여 모든 _.pluck(feeds, &#39;id&#39;) 속성을 ​​추출할 수도 있습니다. id

嗯,代码是精简了许多。但是如果仅仅能做到这一步的话,也没有多大的好处嘛。现在需求又有了变化,我们需要在另一个页面上展示当前用户的收藏夹(用以展示用户所有收藏的feed)。作为程序员,我们可不愿意重新写一套界面,如果能复用同一套逻辑当然最好了。

比如对于上面这个列表,我们已经有了对应的模板:

{{#each feeds}}
<li class="list-item">
    <p class="section" data-feed-id="{{this.id}}">
        {{#if this.marked}}
            <span class="marked icon-favorite"></span>
        {{else}}
            <span class="unmarked icon-favorite"></span>
        {{/if}}
        <a href="/feeds/{{this.url}}">
            <p class="detail">
                <h3>{{this.title}}</h3>
            </p>
        </a>
    </p>
</li>
{{/each}}
로그인 후 복사

事实上,这段代码在收藏夹页面上完全可以复用,我们只需要把所有的marked属性都设置为true就行了!简单,很快我们就可以写出对应的代码:

_.map(feeds, function(item) {
    return _.extend(item, {marked: true});
});
로그인 후 복사

漂亮!而且重要的是,它还可以如正常工作!但是作为程序员,你很快就发现了两处代码的相似性:

_.map(feeds, function(item) {
    return _.extend(item, {marked: isMarked(item.id)});
});

_.map(feeds, function(item) {
    return _.extend(item, {marked: true});
});
로그인 후 복사

消除重复是一个有追求的程序员的基本素养,不过要消除这两处貌似有点困难:位于marked:后边的,一个是函数调用,另一个是值!如果要简化,我们不得不做一个匿名函数,然后以回调的方式来简化:

function wrapFeeds(feeds, predicate) {
    return _.map(feeds, function(item) {
        return _.extend(item, {marked: predicate(item.id)});
    });
}
로그인 후 복사

对于feed列表,我们要调用:

wrapFeeds(feeds, isMarked);
로그인 후 복사

而对于收藏夹,则需要传入一个匿名函数:

wrapFeeds(feeds, function(item) {return true});
로그인 후 복사

lodash中,这样的匿名函数可以用_.wrap来简化:

wrapFeeds(feeds, _.wrap(true));
로그인 후 복사

好了,目前来看,简化的还不错,代码缩减了,而且也好读了一些(当然前提是你已经熟悉了函数式编程的读法)。

更进一步

如果仔细审视isMarked函数,会发现它对外部的依赖不是很漂亮(而且这个外部依赖是从网络异步请求来的),也就是说,我们需要在请求到markedIds的地方才能定义isMarked函数,这样就把函数定义绑定到了一个固定的地方,如果该函数的逻辑比较复杂,那么势必会影响代码的可维护性(或者更糟糕的是,多出维护)。

要将这部分代码隔离出去,我们需要将ids作为参数传递出去,并得到一个可以当做谓词(判断一个id是否在列表中的谓词)的函数。

简而言之,我们需要:

var predicate = createFunc(ids);
wrapFeeds(feeds, predicate);
로그인 후 복사

这里的createFunc函数接受一个列表作为参数,并返回了一个谓词函数。而这个谓词函数就是上边说的isMarked。这个神奇的过程被称为柯里化currying,或者偏函数partial。在lodash中,这个很容易实现:

function isMarkedIn(ids) {
    return _.partial(_.includes, ids);
}
로그인 후 복사

这个函数会将ids保存起来,当被调用时,它会被展开为:_.includes(ids, <id>)。只不过这个<id>会在实际迭代的时候才传入:

$(&#39;/marked-feed-ids&#39;).done(function(ids) {
    var wrappedFeeds = wrapFeeds(feeds, isMarkedIn(ids));
    console.log(wrappedFeeds);
});
로그인 후 복사

这样我们的代码就被简化成了:

$(&#39;/marked-feed-ids&#39;).done(function(ids) {
    var wrappedFeeds = wrapFeeds(feeds, isMarkedIn(ids));
    var markedFeeds = wrapFeeds(feeds, _.wrap(true));

    allFeedList.html(template({feeds: wrappedFeeds}));
    markedFeedList.html(template({feeds: markedFeeds}));
});
로그인 후 복사













위 내용은 JavaScript 함수형 프로그래밍 튜토리얼에 대한 간략한 토론(그림)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

Video Face Swap

Video Face Swap

완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

간단한 JavaScript 튜토리얼: HTTP 상태 코드를 얻는 방법 간단한 JavaScript 튜토리얼: HTTP 상태 코드를 얻는 방법 Jan 05, 2024 pm 06:08 PM

JavaScript 튜토리얼: HTTP 상태 코드를 얻는 방법, 특정 코드 예제가 필요합니다. 서문: 웹 개발에서는 서버와의 데이터 상호 작용이 종종 포함됩니다. 서버와 통신할 때 반환된 HTTP 상태 코드를 가져와서 작업의 성공 여부를 확인하고 다양한 상태 코드에 따라 해당 처리를 수행해야 하는 경우가 많습니다. 이 기사에서는 JavaScript를 사용하여 HTTP 상태 코드를 얻는 방법과 몇 가지 실용적인 코드 예제를 제공합니다. XMLHttpRequest 사용

JavaScript에서 HTTP 상태 코드를 쉽게 얻는 방법 JavaScript에서 HTTP 상태 코드를 쉽게 얻는 방법 Jan 05, 2024 pm 01:37 PM

JavaScript에서 HTTP 상태 코드를 얻는 방법 소개: 프런트 엔드 개발에서 우리는 종종 백엔드 인터페이스와의 상호 작용을 처리해야 하며 HTTP 상태 코드는 매우 중요한 부분입니다. HTTP 상태 코드를 이해하고 얻는 것은 인터페이스에서 반환된 데이터를 더 잘 처리하는 데 도움이 됩니다. 이 기사에서는 JavaScript를 사용하여 HTTP 상태 코드를 얻는 방법을 소개하고 구체적인 코드 예제를 제공합니다. 1. HTTP 상태 코드란 무엇입니까? HTTP 상태 코드는 브라우저가 서버에 요청을 시작할 때 서비스가

함수형 프로그래밍에 C++ 람다 표현식을 사용하면 어떤 이점이 있나요? 함수형 프로그래밍에 C++ 람다 표현식을 사용하면 어떤 이점이 있나요? Apr 17, 2024 am 10:18 AM

C++ 람다 식은 다음을 포함하여 함수형 프로그래밍에 이점을 제공합니다. 단순성: 익명 인라인 함수는 코드 가독성을 향상시킵니다. 코드 재사용: 코드 재사용을 용이하게 하기 위해 람다 표현식을 전달하거나 저장할 수 있습니다. 캡슐화: 별도의 함수를 만들지 않고도 코드 조각을 캡슐화하는 방법을 제공합니다. 실제 사례: 목록에서 홀수를 필터링합니다. 목록의 요소 합계를 계산합니다. 람다 표현식은 함수형 프로그래밍의 단순성, 재사용성 및 캡슐화를 달성합니다.

지연 평가를 사용하여 Golang 기능 프로그램을 최적화하는 방법은 무엇입니까? 지연 평가를 사용하여 Golang 기능 프로그램을 최적화하는 방법은 무엇입니까? Apr 16, 2024 am 09:33 AM

게으른 평가는 게으른 데이터 구조를 사용하여 Go에서 구현할 수 있습니다. 즉, 실제 값을 캡슐화하고 필요할 때만 평가하는 래퍼 유형을 생성합니다. 실제로 필요할 때까지 중간 값 계산을 연기하여 기능적 프로그램에서 피보나치 수열 계산을 최적화합니다. 이는 불필요한 오버헤드를 제거하고 기능적 프로그램의 성능을 향상시킬 수 있습니다.

golang 함수형 프로그래밍의 일반적인 실수와 함정 golang 함수형 프로그래밍의 일반적인 실수와 함정 Apr 30, 2024 pm 12:36 PM

Go에서 함수형 프로그래밍을 사용할 때 주의해야 할 5가지 일반적인 실수와 함정이 있습니다. 실수로 참조를 수정하지 말고 새로 생성된 변수가 반환되는지 확인하세요. 동시성 문제를 해결하려면 동기화 메커니즘을 사용하거나 외부 변경 가능 상태 캡처를 피하세요. 코드 가독성과 유지 관리성을 향상하려면 부분 기능화를 아껴서 사용하세요. 애플리케이션의 견고성을 보장하기 위해 항상 함수의 오류를 처리하십시오. 인라인 함수, 평면화된 데이터 구조 및 작업 일괄 처리를 사용하여 성능에 미치는 영향을 고려하고 코드를 최적화하세요.

Python 람다 표현식: 축약형, 간결함, 강력함 Python 람다 표현식: 축약형, 간결함, 강력함 Feb 19, 2024 pm 08:10 PM

pythonLambda 표현식은 간결하고 읽기 쉽고 사용하기 쉬운 코드를 생성하기 위한 강력하고 유연한 도구입니다. 다른 함수에 인수로 전달되거나 변수에 저장될 수 있는 익명 함수를 빠르게 생성하는 데 유용합니다. Lambda 표현식의 기본 구문은 다음과 같습니다.lambdaarguments:expression예를 들어 다음 Lambda 표현식은 두 개의 숫자를 추가합니다.lambdax,y:x+y 이 Lambda 표현식은 다음과 같이 다른 함수에 인수로 전달될 수 있습니다. defsum( x ,y):returnx+yresult=sum(lambdax,y:x+y,1,2)이 예에서는

Python Lambda 표현식: 익명 함수의 힘 알아보기 Python Lambda 표현식: 익명 함수의 힘 알아보기 Feb 24, 2024 am 09:01 AM

Python의 람다 표현식은 익명 함수의 또 다른 구문 형태입니다. 프로그램 어디에서나 정의할 수 있는 작은 익명 함수입니다. 람다 식은 매개변수 목록과 유효한 Python 식일 수 있는 식으로 구성됩니다. Lambda 표현식의 구문은 다음과 같습니다:lambdaargument_list:expression.예를 들어 다음 Lambda 표현식은 두 숫자의 합계를 반환합니다:lambdax,y:x+y 이 Lambda 표현식은 맵과 같은 다른 함수에 전달될 수 있습니다. () 함수: 숫자=[ 1,2,3,4,5]결과=맵(람다

다른 함수형 프로그래밍 언어에 비해 Java 함수의 장점과 단점은 무엇입니까? 다른 함수형 프로그래밍 언어에 비해 Java 함수의 장점과 단점은 무엇입니까? Apr 24, 2024 pm 02:51 PM

Java 함수형 프로그래밍의 장점에는 단순성, 구성성, 동시성, 테스트 친화성 및 성능이 포함됩니다. 단점으로는 학습 곡선, 디버깅의 어려움, 제한된 유연성, 성능 오버헤드 등이 있습니다. 주요 기능에는 부작용이 없는 순수한 기능, 데이터 처리 파이프라인, 상태 비저장 코드 및 효율적인 스트리밍 API가 포함됩니다.

See all articles