>  기사  >  웹 프론트엔드  >  stream.js는 작고 완전히 독립적인 Javascript library_javascript 기술입니다.

stream.js는 작고 완전히 독립적인 Javascript library_javascript 기술입니다.

WBOY
WBOY원래의
2016-05-16 18:00:171161검색


stream.js 다운로드
2Kb 축소

스트림이란 무엇인가요?
스트림은 배열이나 연결 목록과 마찬가지로 조작이 간단하지만 몇 가지 추가 기능을 갖춘 데이터 구조입니다.

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

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

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

var s = Stream.make( 10, 20, 30 ) // s는 이제 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() ); // 3개 출력
console.log( s.head() ) // 10개 출력
console.log ( s.item( 0 ) ); // 위의 줄과 정확히 동일합니다.
console.log( s.item( 1 ) ) // 20을 출력합니다.
console.log( s.item ( 2 ) ) ; // 출력 30

이 페이지는 stream.js 클래스 라이브러리를 로드했습니다. 이러한 예제를 실행하거나 자신만의 문장 몇 개를 작성하려면 브라우저의 Javascript 콘솔을 열고 직접 실행하세요.

계속하겠습니다. 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(); // 20과 30의 두 항목을 포함하는 스트림을 반환합니다.
console.log( t.head() ) // 20을 출력합니다. >var u = t.tail(); // 하나의 항목을 포함하는 스트림을 반환합니다: 30
console.log( u.head() ) // 출력 30
var v = u.tail() ; // 빈 스트림을 반환합니다.
console.log( v.empty() ); // 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(); // 10부터 20까지의 숫자를 출력합니다.
이 스트림에서는 맵, 필터, 걷기 등의 기능을 사용할 수 있습니다. s.map( f )는 함수인 f 매개변수를 허용합니다. 스트림의 모든 요소는 f에 의해 처리됩니다. 반환 값은 이 함수에 의해 처리되는 스트림입니다. 예를 들어 이를 사용하여 스트림의 숫자를 두 배로 늘릴 수 있습니다.

function doubleNumber( x ) {
return 2 * x
}

varnumbers = Stream.range( 10, 15 );
numbers.print(); // 10, 11, 12, 13, 14, 15를 인쇄합니다.
var doubles = number.map( doubleNumber ); print(); // 20, 22, 24, 26, 28, 30을 인쇄합니다


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

function checkIfOdd( x ) {
if ( x % 2 == 0 ) {
// 짝수
return false
}
else {
// 홀수
return true;
}
}
varnumbers = Stream.range( 10, 15 ); // 숫자를 인쇄합니다. 10, 11, 12, 13, 14, 15
var onlyOdds = number.filter( checkIfOdd );
onlyOdds.print() // 11, 13, 15를 인쇄합니다.

매우 효과적이지 않나요? 마지막 s.walk(f) 메서드는 함수인 매개변수 f도 허용합니다. 스트림의 모든 요소는 이 함수에 의해 처리되어야 하지만 스트림에 아무런 영향을 미치지 않습니다. 스트림의 모든 요소를 ​​인쇄한다는 우리의 아이디어에는 새로운 구현 방법이 있습니다.

코드 복사 코드는 다음과 같습니다. 🎜>
function printItem( x ) {
console.log( '요소는 ' x )
}
var number = Stream.range( 10, 12 ); 🎜>// 인쇄:
// 요소: 10
// 요소: 11
// 요소: 12
numbers.walk( printItem )


또한 매우 유용한 함수인 s.take(n)도 있습니다. 이 함수는 원래 스트림의 처음 n 요소만 포함하는 스트림을 반환합니다. 이는 스트림을 가로채는 데 사용할 때 유용합니다.


코드 복사 코드는 다음과 같습니다. var number = Stream.range( 10, 100 ); // 숫자 10...100
var lessNumbers = number.take( 10 ); // 숫자 10...19
fewerNumbers.print();


다른 유용한 것들: s.scale(factor)는 스트림의 모든 요소를 ​​인수(factor)로 곱합니다. s.add(t)는 스트림 s와 스트림 t의 각 요소를 해당 요소로 만듭니다. 의 요소가 추가되고 추가 결과가 반환됩니다. 몇 가지 예를 살펴보겠습니다.


코드 복사 코드는 다음과 같습니다. var 숫자 = Stream .range( 1, 3 );
var multiplesOfTen = number.scale( 10 );
multiplesOfTen.print(); // 10, 20, 30을 인쇄합니다
numbersOfTen ). print( ); // 11, 22, 33을 인쇄합니다.


지금까지 본 것은 숫자에 대한 연산이지만 스트림에는 문자열, 부울 값, 함수, 객체 등 무엇이든 로드할 수 있습니다. 다른 배열이나 스트림도 가능합니다. 그러나 스트림은 일부 특수 값(null 및 정의되지 않음)을 로드할 수 없다는 점에 유의하십시오.
당신의 마법을 보여주세요!
이제 무한대를 다루겠습니다. 스트림에 무한한 요소를 추가할 필요가 없습니다. 예를 들어 Stream.range(low, high) 메서드에서는 두 번째 매개 변수를 무시하고 Stream.range(low)를 쓸 수 있습니다. 이 경우 데이터에 대한 상한이 없으므로 스트림은 All로 로드됩니다. 낮은 것부터 무한대까지의 자연수. low 매개변수를 무시할 수도 있습니다. 이 매개변수의 기본값은 1입니다. 이 경우 Stream.range()는 모든 자연수를 반환합니다.

무한한 메모리/시간/처리 능력이 필요합니까?
아니요, 그렇지 않습니다. 이것이 가장 좋은 부분입니다. 이 코드를 실행하면 일반 배열처럼 매우 빠르게 실행됩니다. 다음은 1부터 10까지 인쇄하는 예입니다.



코드 복사 코드는 다음과 같습니다. var naturalNumbers = Stream.range(); // 1 이상의 모든 자연수를 포함하는 스트림을 반환합니다.
var oneToTen = naturalNumbers.take( 10 ) // 숫자 1을 포함하는 스트림을 반환합니다. 10
oneToTen.print()


당신은 거짓말을 하고 있습니다
네, 저는 거짓말을 하고 있습니다. 핵심은 이러한 구조를 무한대로 생각할 수 있다는 것입니다. 이는 단순성을 추구하는 새로운 프로그래밍 패러다임을 도입하여 코드를 일반적인 명령형 프로그래밍보다 이해하기 쉽고 자연 수학에 더 가깝게 만듭니다. Javascript 라이브러리 자체는 매우 짧습니다. 이 프로그래밍 패러다임에 따라 설계되었습니다. 더 많이 활용해 보겠습니다. 우리는 두 개의 스트림을 구성합니다. 하나는 모든 홀수에 대한 것이고 다른 하나는 모든 짝수에 대한 것입니다.
코드 복사 코드는 다음과 같습니다.

var naturalNumbers = Stream.range(); // naturalNumbers는 이제 1, 2, 3, ...
var evenNumbers = naturalNumbers.map( function ( x ) {
return 2 * x;
} ) // evenNumbers는 이제 2입니다. 4, 6 , ...
varododNumbers = naturalNumbers.filter( function ( x ) {
return x % 2 != 0;
} ) //oddNumbers는 이제 1, 3, 5, ...
evenNumbers.take( 3 ).print(); // 2, 4, 6을 인쇄합니다.
oddNumbers.take( 3 ).print() // 1, 3, 5를 인쇄합니다.

멋지죠? 과장하는 것이 아닙니다. 스트림은 배열보다 더 강력합니다. 이제 잠시만 기다려 주시고 스트림에 대해 조금 더 말씀드리겠습니다. new Stream()을 사용하여 빈 스트림을 생성하고 new Stream( head, functionReturningTail )을 사용하여 비어 있지 않은 스트림을 생성할 수 있습니다. 비어 있지 않은 이 스트림의 경우 전달하는 첫 번째 매개변수는 스트림의 헤드 요소가 되고, 두 번째 매개변수는 스트림(나머지 모든 요소를 ​​포함하는 스트림)의 테일을 반환하는 함수입니다. 빈 스트림일 가능성이 높습니다. . 혼란스러운? 예를 살펴보겠습니다.
코드 복사 코드는 다음과 같습니다.

var s = new Stream ( 10, function () {
return new Stream();
} )
// s 스트림의 앞부분은 10입니다.
s .print(); // 10개 인쇄
var t = new Stream( 10, function () {
return new Stream( 20, function () {
return new Stream( 30, function ( ) {
return new Stream();
} );
} )
// t 스트림의 헤드는 10입니다. 20 및
// 머리가 30이고 꼬리가 빈 스트림인
t.print() // 10, 20, 30을 인쇄합니다.

아무것도 문제가 있나요? Stream.make(10, 20, 30)을 사용하여 이 작업을 직접 수행할 수 있습니다. 그러나 이 방법을 사용하면 무한 스트림을 쉽게 구성할 수 있습니다. 끝없는 스트림을 만들어 보겠습니다.

코드 복사 코드는 다음과 같습니다.
함수( ) {
return new Stream(
// 스트림의 첫 번째 요소는 1...
1,
// 이 스트림의 나머지 요소는 다음을 호출하여 제공됩니다. 함수 ones() (이와 동일한 함수!)
ones
)
}

var s = ones(); // 이제 s에는 1, 1, 1, 1이 포함됩니다. ...
s.take( 3 ).print(); // 1, 1, 1을 인쇄합니다.

무한 스트림 .print()에서 s를 사용하는 경우 끝없이 인쇄되어 결국 메모리가 소진됩니다. 따라서 s.print()를 사용하기 전에 s.take(n)을 사용하는 것이 좋습니다. 무한 스트림에서 s.length()를 사용하는 것도 의미가 없으므로 이러한 작업을 수행하지 마십시오. 무한 루프가 발생합니다(무한 스트림의 끝에 도달하려고 시도함). 그러나 무한 스트림의 경우 s.map( f ) 및 s.filter( f )를 사용할 수 있습니다. 그러나 s.walk(f)는 무한 스트림에도 유용하지 않습니다. 전체적으로 기억해야 할 몇 가지 사항이 있습니다. 무한 스트림의 경우 s.take(n)를 사용하여 유한 부분을 제거해야 합니다.

더 흥미로운 일을 할 수 있는지 살펴보겠습니다. 자연수가 포함된 스트림을 생성하는 흥미로운 방법도 있습니다.


코드 복사 코드는 다음과 같습니다.
function ones() {
return new Stream( 1, ones )
}
function naturalNumbers() {
return new Stream(
// 자연수는 첫 번째 요소가 1인 스트림입니다...
1,
function () {
// 나머지는 모두 1씩 증가한 자연수입니다
// 자연수의 흐름을 더함으로써...
// 1, 2, 3, 4, 5, ...
// 1의 무한한 흐름에...
// 1, 1 , 1, 1, 1, ...
// 양보 중...
// 2, 3, 4, 5, 6, ...
// 이는 실제로 자연의 나머지입니다. 1 이후의 숫자
return ones().add( naturalNumbers() );
}
)
naturalNumbers().take( 5 ).print(); 1, 2, 3, 4, 5


주의 깊은 독자라면 새로 구성된 스트림의 두 번째 매개변수가 tail 자체가 아니라 tail을 반환하는 함수인 이유를 알게 될 것입니다. 이 방법은 테일 차단 작업을 지연시켜 끝없는 실행 주기를 방지합니다.

더 복잡한 예를 살펴보겠습니다. 다음은 독자들을 위한 연습 문제입니다. 다음 코드의 기능을 알려주십시오.
코드 복사 코드는 다음과 같습니다.

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(); 잠시 시간을 내어 이 코드의 목적을 이해하시기 바랍니다. 함수형 프로그래밍 경험이 없으면 대부분의 프로그래머는 이 코드를 이해하기 어려울 것이므로 바로 보지 못하더라도 좌절하지 마십시오. 당신을 위한 작은 힌트: 인쇄되는 스트림의 헤더 요소가 무엇인지 알아보세요. 그런 다음 두 번째 요소(나머지 요소의 머리 요소)가 무엇인지 알아낸 다음 세 번째 요소, 네 번째 요소를 찾습니다. 함수 이름을 통해서도 몇 가지 힌트를 얻을 수 있습니다.

이런 퍼즐에 관심이 있으시면
여기
를 더 읽어보세요.

이 코드의 기능을 실제로 알 수 없다면 실행하여 직접 확인해 보세요! 이렇게 하면 어떻게 수행되는지 쉽게 이해할 수 있습니다. 헌정
스트림은 사실 새로운 아이디어가 아닙니다. 많은 함수형 프로그래밍 언어가 이 기능을 지원합니다. 소위 '스트림'은 Scheme 언어의 이름이고 Scheme은 LISP 언어의 방언입니다. Haskell 언어는 무한히 큰 목록도 지원합니다. 'take', 'tail', 'head', 'map' 및 'filter'라는 이름은 모두 Haskell 언어에서 유래되었습니다. 이 개념은 다르지만 매우 유사하며 Python과 다른 많은 중국어에도 존재합니다. 이 개념은 모두 "생성기"라고 합니다.

이러한 아이디어는 오랫동안 함수형 프로그래밍 커뮤니티에서 회자되어 왔습니다. 그러나 이는 대부분의 Javascript 프로그래머, 특히 함수형 프로그래밍 경험이 없는 프로그래머에게는 매우 새로운 개념입니다.

여기에 나온 많은 예와 아이디어는
컴퓨터 프로그램의 구조와 해석
이라는 책에서 따왔습니다. 이러한 아이디어가 마음에 든다면 이 책을 온라인에서 무료로 읽어 보시기를 적극 권장합니다. 이는 또한 이 Javascript 라이브러리를 개발하는 나의 창의성의 원천이기도 합니다.

다른 구문 형식의 스트림을 좋아한다면 linq.js
를 사용해 볼 수 있고, node.js를 사용한다면
node-lazy

가 더 적합할 수 있습니다. CoffeeScript를 좋아하신다면 Michael Blume이 stream.js를 CoffeeScript로 포팅하여 Coffeestream을 만들고 있습니다. 읽어주셔서 감사합니다!
유용한 것을 찾아서 stream.js를 즐겨보시길 바랍니다. 도서관은 무료이므로 마음에 드시거나 어떤 식으로든 도움이 되신다면 저에게 핫초콜릿 음료(저는 커피를 마시지 않습니다)를 사시거나 전화를 걸어주세요. 이 일을 할 계획이라면 어디서 왔고 무슨 일을 하는지 알려주세요. 저는 전 세계의 이미지를 수집하는 것을 좋아하므로 귀하가 거주하는 도시의 사진을 포함해 주세요!

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