웹 프론트엔드 JS 튜토리얼 새로운 JavaScript 데이터 구조 스트림

새로운 JavaScript 데이터 구조 스트림

Nov 28, 2016 pm 03:33 PM
javascript

최근 인터넷에서 새로운 자바스크립트 애플릿인 Streams를 봤습니다. 처음에는 평범한 자바스크립트 클래스 라이브러리인 줄 알았는데, 소개를 읽어보니 단순한 클래스 라이브러리가 아니라는 걸 알게 됐습니다. 초점은 이 클래스 라이브러리의 기능에 있지 않지만 - 기사의 한 구절을 빌리자면: 이 기사를 10분만 투자하여 읽으신다면 프로그래밍에 대한 이해가 완전히 바뀔 수 있습니다(함수형 프로그래밍 경험이 없는 한!). ).

또한: 스트림은 사실 새로운 아이디어가 아닙니다. 많은 함수형 프로그래밍 언어가 이 기능을 지원합니다. 소위 '스트림'은 Scheme 언어의 이름이고 Scheme은 LISP 언어의 방언입니다. Haskell 언어는 무한히 큰 목록도 지원합니다. 'take', 'tail', 'head', 'map' 및 'filter'라는 이름은 모두 Haskell 언어에서 유래되었습니다. 이 다르지만 유사한 개념은 Python과 다른 많은 중국어에도 존재합니다. 이들은 모두 "생성기"라고 합니다. 이러한 아이디어는 함수형 프로그래밍 커뮤니티에서 오랫동안 순환되어 왔습니다. 그러나 이는 대부분의 Javascript 프로그래머, 특히 함수형 프로그래밍 경험이 없는 프로그래머에게는 매우 새로운 개념입니다.

stream.js

stream.js는 작고 완전히 독립적인 Javascript 라이브러리(단지 2k)로, 새로운 Javascript 데이터 구조인 streams를 제공합니다.

<script src=&#39;stream-min.js&#39;></script>
로그인 후 복사

스트림이란 무엇인가요? 스트림은 배열이나 연결 목록과 매우 유사하지만 몇 가지 추가적인 특별한 기능을 갖춘 간단한 데이터 구조입니다.

그들의 특별한 점은 무엇인가요? 배열과 달리 스트림은 마법 같은 데이터 구조입니다. 무한한 수의 요소를 보유할 수 있습니다. 네, 당신이 들은 게 맞습니다. 그의 마법은 느리게 실행하는 능력에서 비롯됩니다. 이 간단한 용어는 무한한 수의 요소를 로드할 수 있다는 것을 완벽하게 이해합니다.

다운로드 스트림

시작하기

이 기사를 10분만 투자해 읽으신다면 프로그래밍에 대한 이해가 완전히 바뀔 수 있습니다(함수형 프로그래밍 경험이 없는 경우). !). 인내심을 갖고 배열이나 연결 목록과 매우 유사한 스트림이 지원하는 기본 기능 작업을 먼저 소개하겠습니다. 그런 다음 매우 흥미로운 기능 중 일부를 소개하겠습니다.

스트림은 컨테이너입니다. 요소를 보유하고 있습니다. Stream.make를 사용하여 스트림이 일부 요소를 로드하도록 할 수 있습니다. 원하는 요소를 매개변수로 전달하기만 하면 됩니다.

// s is now a stream containing 10, 20, and 30
var s = Stream.make( 10, 20, 30 );
로그인 후 복사

충분히 간단합니다. 이제 s는 10, 20, 30의 3개 요소가 순서대로 포함된 스트림입니다. s.length()를 사용하여 이 스트림의 길이를 확인하고 s.item(i)을 사용하여 인덱스별로 내부 요소를 검색할 수 있습니다. s.head()를 호출하여 이 스트림의 첫 번째 요소를 가져올 수도 있습니다. 실제로 해봅시다:

var s = Stream.make( 10, 20, 30 );  
console.log( s.length() );  // outputs 3  
console.log( s.head() );    // outputs 10  
console.log( s.item( 0 ) ); // exactly equivalent to the line above  
console.log( s.item( 1 ) ); // outputs 20  
console.log( s.item( 2 ) ); // outputs 30
로그인 후 복사

new Stream()을 사용하거나 Stream.make()를 직접 사용하여 빈 스트림을 구성할 수도 있습니다. s.tail() 메서드를 사용하여 첫 번째 요소를 제외한 스트림의 나머지 모든 요소를 ​​가져올 수 있습니다. 빈 스트림에서 s.head() 또는 s.tail() 메서드를 호출하면 예외가 발생합니다. true 또는 false를 반환하는 s.empty()를 사용하여 스트림이 비어 있는지 확인할 수 있습니다.

var s = Stream.make( 10, 20, 30 );  
var t = s.tail();         // returns the stream that contains two items: 20 and 30  
console.log( t.head() );  // outputs 20  
var u = t.tail();         // returns the stream that contains one item: 30  
console.log( u.head() );  // outputs 30  
var v = u.tail();         // returns the empty stream  
console.log( v.empty() ); // prints true
로그인 후 복사

이렇게 하면 스트림의 모든 요소가 인쇄됩니다.

var s = Stream.make( 10, 20, 30 );  
while ( !s.empty() ) {  
    console.log( s.head() );  
    s = s.tail();  
}
로그인 후 복사

이를 수행하는 간단한 방법이 있습니다. s.print()는 스트림의 모든 요소를 ​​인쇄합니다. 그 안에 있는 요소들.

또 어떤 용도로 사용할 수 있나요?

또 다른 편리한 기능은 Stream.range( min, max ) 기능입니다. 최소부터 최대까지의 자연수가 포함된 스트림을 반환합니다.

var s = Stream.range( 10, 20 );  
s.print(); // prints the numbers from 10 to 20
로그인 후 복사

본 스트림에서는 지도, 필터, 걷기 등의 기능을 사용할 수 있습니다. s.map( f )는 함수인 f 매개변수를 허용합니다. 스트림의 모든 요소는 f에 의해 처리됩니다. 반환 값은 이 함수에 의해 처리되는 스트림입니다. 예를 들어 이를 사용하여 스트림의 숫자를 두 배로 늘릴 수 있습니다.

function doubleNumber( x ) {  
    return 2 * x;  
}  
   
var numbers = Stream.range( 10, 15 );  
numbers.print(); // prints 10, 11, 12, 13, 14, 15  
var doubles = numbers.map( doubleNumber );  
doubles.print(); // prints 20, 22, 24, 26, 28, 30
로그인 후 복사

멋지죠? 마찬가지로 s.filter( f )도 함수인 매개변수 f를 허용합니다. 스트림의 모든 요소는 이 함수에 의해 처리되지만 반환 값도 스트림이지만 f 함수가 허용하는 요소만 포함됩니다. 사실을 반환합니다. 따라서 이를 사용하여 스트림의 특정 요소를 필터링할 수 있습니다. 이 방법을 사용하여 이전 스트림을 기반으로 홀수만 포함하는 새 스트림을 만들어 보겠습니다.

function checkIfOdd( x ) {  
    if ( x % 2 == 0 ) {  
        // even number  
        return false;  
    }  
    else {  
        // odd number  
        return true;  
    }  
}  
var numbers = Stream.range( 10, 15 );  
numbers.print();  // prints 10, 11, 12, 13, 14, 15  
var onlyOdds = numbers.filter( checkIfOdd );  
onlyOdds.print(); // prints 11, 13, 15
로그인 후 복사

很有效,不是吗?最后的一个s.walk( f )方法,也是接受一个参数f,是一个函数,stream里的所有元素都要经过这个函数处理,但它并不会对这个stream做任何的影响。我们打印stream里所有元素的想法有了新的实现方法:

function printItem( x ) {  
    console.log( &#39;The element is: &#39; + x );  
}  
var numbers = Stream.range( 10, 12 );  
// prints:  
// The element is: 10  
// The element is: 11  
// The element is: 12  
numbers.walk( printItem );
로그인 후 복사

还有一个很有用的函数: s.take( n ),它返回的stream只包含原始stream里第前n个元素。当用来截取stream时,这很有用:

var numbers = Stream.range( 10, 100 ); // numbers 10...100  
var fewerNumbers = numbers.take( 10 ); // numbers 10...19  
fewerNumbers.print();
로그인 후 복사

另外一些有用的东西:s.scale( factor ) 会用factor(因子)乘以stream里的所有元素; s.add( t ) 会让 stream s 每个元素和stream t里对应的元素相加,返回的是相加后的结果。让我们来看几个例子:

var numbers = Stream.range( 1, 3 );  
var multiplesOfTen = numbers.scale( 10 );  
multiplesOfTen.print(); // prints 10, 20, 30  
numbers.add( multiplesOfTen ).print(); // prints 11, 22, 33
로그인 후 복사

尽管我们目前看到的都是对数字进行操作,但stream里可以装载任何的东西:字符串,布尔值,函数,对象;甚至其它的数组或stream。然而,请注意一定,stream里不能装载一些特殊的值:null 和 undefined。

想我展示你的魔力!

现在,让我们来处理无穷多。你不需要往stream添加无穷多的元素。例如,在Stream.range( low, high )这个方法中,你可以忽略掉它的第二个参数,写成 Stream.range( low ), 这种情况下,数据没有了上限,于是这个stream里就装载了所有从 low 到无穷大的自然数。你也可以把low参数也忽略掉,这个参数的缺省值是1。这种情况中,Stream.range()返回的是所有的自然数。

这需要用上你无穷多的内存/时间/处理能力吗?不,不会。这是最精彩的部分。你可以运行这些代码,它们跑的非常快,就像一个普通的数组。下面是一个打印从 1 到 10 的例子:

var naturalNumbers = Stream.range(); // returns the stream containing all natural numbers from 1 and up  
var oneToTen = naturalNumbers.take( 10 ); // returns the stream containing the numbers 1...10  
oneToTen.print();
로그인 후 복사

关键是你可以把这些结构想成无穷大,这就引入了一种新的编程范式,一种致力于简洁的代码,让你的代码比通常的命令式编程更容易理解、更贴近自然数学的编程范式。这个Javascript类库本身就很短小;它是按照这种编程范式设计出来的。让我们来多用一用它;我们构造两个stream,分别装载所有的奇数和所有的偶数。

var naturalNumbers = Stream.range(); // naturalNumbers is now 1, 2, 3, ...  
var evenNumbers = naturalNumbers.map( function ( x ) {  
    return 2 * x;  
} ); // evenNumbers is now 2, 4, 6, ...  
var oddNumbers = naturalNumbers.filter( function ( x ) {  
    return x % 2 != 0;  
} ); // oddNumbers is now 1, 3, 5, ...  
evenNumbers.take( 3 ).print(); // prints 2, 4, 6  
oddNumbers.take( 3 ).print(); // prints 1, 3, 5
로그인 후 복사

很酷,不是吗?我没说大话,stream比数组的功能更强大。现在,请容忍我几分钟,让我来多介绍一点关于stream的事情。你可以使用 new Stream() 来创建一个空的stream,用 new Stream( head, functionReturningTail ) 来创建一个非空的stream。对于这个非空的stream,你传入的第一个参数成为这个stream的头元素,而第二个参数是一个函数,它返回stream的尾部(一个包含有余下所有元素的stream),很可能是一个空的stream。困惑吗?让我们来看一个例子:

var s = new Stream( 10, function () {  
    return new Stream();  
} );  
// the head of the s stream is 10; the tail of the s stream is the empty stream  
s.print(); // prints 10  
var t = new Stream( 10, function () {  
    return new Stream( 20, function () {  
        return new Stream( 30, function () {  
            return new Stream();  
        } );  
    } );  
} );  
// the head of the t stream is 10; its tail has a head which is 20 and a tail which  
// has a head which is 30 and a tail which is the empty stream.  
t.print(); // prints 10, 20, 30
로그인 후 복사

没事找事吗?直接用Stream.make( 10, 20, 30 )就可以做这个。但是,请注意,这种方式我们可以轻松的构建我们的无穷大stream。让我们来做一个能够无穷无尽的stream:

function ones() {  
    return new Stream(  
        // the first element of the stream of ones is 1...  
        1,  
        // and the rest of the elements of this stream are given by calling the function ones() (this same function!)  
        ones  
    );  
}  
   
var s = ones();      // now s contains 1, 1, 1, 1, ...  
s.take( 3 ).print(); // prints 1, 1, 1
로그인 후 복사

请注意,如果你在一个无限大的stream上使用 s.print(),它会无休无止的打印下去,最终耗尽你的内存。所以,你最好在使用s.print()前先s.take( n )。在一个无穷大的stream上使用s.length()也是无意义的,所有,不要做这些操作;它会导致一个无尽的循环(试图到达一个无尽的stream的尽头)。但是对于无穷大stream,你可以使用s.map( f ) 和 s.filter( f )。然而,s.walk( f )对于无穷大stream也是不好用。所有,有些事情你要记住; 对于无穷大的stream,一定要使用s.take( n )取出有限的部分。

让我们看看能不能做一些更有趣的事情。还有一个有趣的能创建包含自然数的stream方式:

function ones() {  
    return new Stream( 1, ones );  
}  
function naturalNumbers() {  
    return new Stream(  
        // the natural numbers are the stream whose first element is 1...  
        1,  
        function () {  
            // and the rest are the natural numbers all incremented by one  
            // which is obtained by adding the stream of natural numbers...  
            // 1, 2, 3, 4, 5, ...  
            // to the infinite stream of ones...  
            // 1, 1, 1, 1, 1, ...  
            // yielding...  
            // 2, 3, 4, 5, 6, ...  
            // which indeed are the REST of the natural numbers after one  
            return ones().add( naturalNumbers() );  
        }   
    );  
}  
naturalNumbers().take( 5 ).print(); // prints 1, 2, 3, 4, 5
로그인 후 복사

细心的读者会发现为什么新构造的stream的第二参数是一个返回尾部的函数、而不是尾部本身的原因了。这种方式可以通过延迟尾部截取的操作来防止进行进入无穷尽的执行周期。

让我们来看一个更复杂的例子。下面的是给读者留下的一个练习,请指出下面这段代码是做什么的?

function sieve( s ) {  
    var h = s.head();  
    return new Stream( h, function () {  
        return sieve( s.tail().filter( function( x ) {  
            return x % h != 0;  
        } ) );  
    } );  
}  
sieve( Stream.range( 2 ) ).take( 10 ).print();
로그인 후 복사

请一定要花些时间能清楚这段代码的用途。除非有函数式编程经验,大多数的程序员都会发现这段代码很难理解,所以,如果你不能立刻看出来,不要觉得沮丧。给你一点提示:找出被打印的stream的头元素是什么。然后找出第二个元素是什么(余下的元素的头元素);然后第三个元素,然后第四个。这个函数的名称也能给你一些提示。如果你对这种难题感兴趣,这儿还有一些:

var sequence = new Stream( 1, function() {
    return new Stream( 1, function() {
        return sequence.add( sequence.tail() );
    } );
} ); 
 
sequence.take( 10 ).print();
로그인 후 복사

如果你真的想不出这段代码是做什么的,你就运行一下它,自己看一看!这样你就很容易理解它是怎么做的了。

致敬

Streams 实际上不是一个新的想法。很多的函数式的编程语言都支持这种特征。所谓‘stream’是Scheme语言里的叫法,Scheme是LISP语言的一种方言。Haskell语言也支持无限大列表(list)。这些'take', 'tail', 'head', 'map' 和 'filter' 名字都来自于Haskell语言。Python和其它很多中语言中也存在虽然不同但很相似的这种概念,它们都被称作"发生器(generators)"。

这些思想来函数式编程社区里已经流传了很久了。然而,对于大多数的Javascript程序员来说却是一个很新的概念,特别是那些没有函数式编程经验的人。这里很多的例子和创意都是来自Structure and Interpretation of Computer Programs这本数。如果你喜欢这些想法,我高度推荐你读一读它;这本书可以在网上免费获得。它也是我开发这个Javascript类库的创意来源。

如果你喜欢其它语法形式的stream,你可以试一下linq.js,或者,如果你使用 node.js, node-lazy 也许更适合你。如果你要是喜欢 CoffeeScript 的话, Michael Blume 正在把 stream.js 移植到 CoffeeScript 上,创造出 coffeestream。


본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 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 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

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

SublimeText3 중국어 버전

SublimeText3 중국어 버전

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

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

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

WebSocket과 JavaScript를 사용하여 온라인 음성 인식 시스템을 구현하는 방법 WebSocket과 JavaScript를 사용하여 온라인 음성 인식 시스템을 구현하는 방법 Dec 17, 2023 pm 02:54 PM

WebSocket 및 JavaScript를 사용하여 온라인 음성 인식 시스템을 구현하는 방법 소개: 지속적인 기술 개발로 음성 인식 기술은 인공 지능 분야의 중요한 부분이 되었습니다. WebSocket과 JavaScript를 기반으로 한 온라인 음성 인식 시스템은 낮은 대기 시간, 실시간, 크로스 플랫폼이라는 특징을 갖고 있으며 널리 사용되는 솔루션이 되었습니다. 이 기사에서는 WebSocket과 JavaScript를 사용하여 온라인 음성 인식 시스템을 구현하는 방법을 소개합니다.

WebSocket 및 JavaScript: 실시간 모니터링 시스템 구현을 위한 핵심 기술 WebSocket 및 JavaScript: 실시간 모니터링 시스템 구현을 위한 핵심 기술 Dec 17, 2023 pm 05:30 PM

WebSocket과 JavaScript: 실시간 모니터링 시스템 구현을 위한 핵심 기술 서론: 인터넷 기술의 급속한 발전과 함께 실시간 모니터링 시스템이 다양한 분야에서 널리 활용되고 있다. 실시간 모니터링을 구현하는 핵심 기술 중 하나는 WebSocket과 JavaScript의 조합입니다. 이 기사에서는 실시간 모니터링 시스템에서 WebSocket 및 JavaScript의 적용을 소개하고 코드 예제를 제공하며 구현 원칙을 자세히 설명합니다. 1. 웹소켓 기술

WebSocket과 JavaScript를 사용하여 온라인 예약 시스템을 구현하는 방법 WebSocket과 JavaScript를 사용하여 온라인 예약 시스템을 구현하는 방법 Dec 17, 2023 am 09:39 AM

WebSocket과 JavaScript를 사용하여 온라인 예약 시스템을 구현하는 방법 오늘날의 디지털 시대에는 점점 더 많은 기업과 서비스에서 온라인 예약 기능을 제공해야 합니다. 효율적인 실시간 온라인 예약 시스템을 구현하는 것이 중요합니다. 이 기사에서는 WebSocket과 JavaScript를 사용하여 온라인 예약 시스템을 구현하는 방법을 소개하고 구체적인 코드 예제를 제공합니다. 1. WebSocket이란 무엇입니까? WebSocket은 단일 TCP 연결의 전이중 방식입니다.

JavaScript 및 WebSocket을 사용하여 실시간 온라인 주문 시스템을 구현하는 방법 JavaScript 및 WebSocket을 사용하여 실시간 온라인 주문 시스템을 구현하는 방법 Dec 17, 2023 pm 12:09 PM

JavaScript 및 WebSocket을 사용하여 실시간 온라인 주문 시스템을 구현하는 방법 소개: 인터넷의 대중화와 기술의 발전으로 점점 더 많은 레스토랑에서 온라인 주문 서비스를 제공하기 시작했습니다. 실시간 온라인 주문 시스템을 구현하기 위해 JavaScript 및 WebSocket 기술을 사용할 수 있습니다. WebSocket은 TCP 프로토콜을 기반으로 하는 전이중 통신 프로토콜로 클라이언트와 서버 간의 실시간 양방향 통신을 실현할 수 있습니다. 실시간 온라인 주문 시스템에서는 사용자가 요리를 선택하고 주문을 하면

JavaScript와 WebSocket: 효율적인 실시간 일기예보 시스템 구축 JavaScript와 WebSocket: 효율적인 실시간 일기예보 시스템 구축 Dec 17, 2023 pm 05:13 PM

JavaScript 및 WebSocket: 효율적인 실시간 일기 예보 시스템 구축 소개: 오늘날 일기 예보의 정확성은 일상 생활과 의사 결정에 매우 중요합니다. 기술이 발전함에 따라 우리는 날씨 데이터를 실시간으로 획득함으로써 보다 정확하고 신뢰할 수 있는 일기예보를 제공할 수 있습니다. 이 기사에서는 JavaScript 및 WebSocket 기술을 사용하여 효율적인 실시간 일기 예보 시스템을 구축하는 방법을 알아봅니다. 이 문서에서는 특정 코드 예제를 통해 구현 프로세스를 보여줍니다. 우리

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

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

자바스크립트에서 insertBefore를 사용하는 방법 자바스크립트에서 insertBefore를 사용하는 방법 Nov 24, 2023 am 11:56 AM

사용법: JavaScript에서 insertBefore() 메서드는 DOM 트리에 새 노드를 삽입하는 데 사용됩니다. 이 방법에는 삽입할 새 노드와 참조 노드(즉, 새 노드가 삽입될 노드)라는 두 가지 매개 변수가 필요합니다.

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

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

See all articles