Stream.js a very small, completely independent JavaScript class library _javascript tips

Source: Internet
Author: User
<script src= ' stream-min.js ' ></script>
Download Stream.js
2Kb minified

What is streams?
Streams is a simple data structure, much like an array or linked table, but with some extraordinary capabilities attached.

What's so special about them?
Unlike arrays, streams is a magical data structure. It can load an infinite number of elements. Yes, you heard me right. His magic comes from the ability to postpone (lazily) execution. This simple term is a complete indication that they can load infinitely many elements.

Entry
If you are willing to spend 10 minutes reading this article, your knowledge of programming is likely to be completely changed (unless you have a functional programming experience!). )。 Please have a little patience, let me first introduce the streams supported basic functions similar to arrays or linked tables. Then I'll introduce you to some of the very interesting features that it has.

A Stream is a container. It can hold elements. You can use Stream.make to let a Stream load some elements. You just need to pass the elements you want as parameters:

var s = stream.make (10, 20, 30); S is now a stream containing, and 30
Simple enough, now S is a 3-element stream:10, and 30; In a sequential order. We can use S.length () to look at the length of this stream, and use S.item (i) to retrieve an element from it by index. You can also get the first element of the stream by calling S.head (). Let's actually do the following:
Copy Code code as follows:

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

This stream.js class library has been loaded on this page. If you want to run these examples or write yourself a few sentences, open your browser's JavaScript console and run directly.

As we proceed, we can also use the new stream () or use Stream.make () directly to construct an empty stream. You can use the S.tail () method to get all the remaining elements except the first element in the stream. If you raise an empty stream with the S.head () or S.tail () method, an exception is thrown. You can use S.empty () to check whether a stream is empty, and it returns TRUE or false.
Copy Code code as follows:

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

This will print out all the elements in a stream:
Copy Code code as follows:

var s = stream.make (10, 20, 30);
while (!s.empty ()) {
Console.log (S.head ());
s = S.tail ();
}

We have an easy way to do this: S.print () will print out all the elements in the stream.

What else can you do with them?
Another handy feature is the Stream.range (min, max) function. It returns a stream that contains a natural number from min to Max.
Copy Code code as follows:

var s = stream.range (10, 20);
S.print (); Prints the numbers from ten to 20
On this stream, you can use maps, filter, and walk functions. S.map (f) accepts an argument F, which is a function, all elements of the stream will be processed by F, and its return value is the stream that has been processed by this function. So, for example, you can use it to double the number of digits in your stream:

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

It's cool, isn't it? Similarly, S.filter (f) also accepts an argument F, a function in which all elements of the stream are processed by this function; its return value is also a stream, but contains only elements that allow the F function to return true. So, you can use it to filter out certain elements in your stream. Let's use this method to build a new stream that contains only odd numbers based on the previous stream:
Copy Code code as follows:

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

It works, doesn't it? The last S.walk (f) method, which accepts a parameter F, is a function that all elements in the stream are processed by this function, but it does not affect the stream any more. The idea that we print all the elements in the stream has a new way of implementing it:
Copy Code code as follows:

function Printitem (x) {
Console.log (' The element is: ' + x);
}
var numbers = Stream.range (10, 12);
Prints:
The element is:10
The element is:11
The element is:12
Numbers.walk (Printitem);

There is also a useful function: S.take (n), which returns the stream containing only the first n elements in the original stream. This is useful when you are using to intercept a stream:
Copy Code code as follows:

var numbers = Stream.range (10, 100); Numbers 10...100
var fewernumbers = Numbers.take (10); Numbers 10...19
Fewernumbers.print ();

Other useful things: S.scale (factor) multiplies all the elements in the stream by using factor (factor), and S.add (t) adds each element of the stream s to the corresponding element in the stream T, and returns the result of the addition. Let's take a look at a few examples:
Copy Code code as follows:

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

Although all we see now is manipulating numbers, the stream can load anything: strings, Booleans, functions, objects, and even other arrays or stream. However, please be aware that the stream cannot load special values: null and undefined.

Want me to show you the magic!
Now, let's deal with infinity. You don't need to add infinitely many elements to the stream. For example, in Stream.range (Low, high) This method, you can ignore its second parameter, write Stream.range (Low), in which case the data is not capped, so the Stream is loaded with all the natural numbers from low to infinity. You can also ignore the low parameter and the default value of this parameter is 1. In this case, Stream.range () returns all the natural numbers.

Does this need to use your infinite amount of memory/time/processing power?
No, not at all. This is the most exciting part. You can run the code, they run very fast, just like an ordinary array. Here is an example of printing from 1 to 10:
Copy Code code as follows:

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 ();

You're a liar.
Yes, I'm lying. The point is that you can think of these structures as infinity, which introduces a new programming paradigm, a code that works on simplicity, making your code easier to understand than the usual imperative programming, and closer to the programming paradigm of natural mathematics. The JavaScript class library itself is short; it is designed in accordance with this programming paradigm. Let's use it more; we construct two stream, loading all the odd numbers and all the even numbers.
Copy Code code as follows:

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

It's cool, isn't it? I'm not bluffing. The stream is more powerful than the array. Now, please tolerate me a few minutes, let me introduce a little more about the stream thing. You can use the new stream () to create an empty stream, with the new stream (head, Functionreturningtail) to create a non-empty stream. For this non-empty stream, the first argument you pass into is the head element of the stream, and the second parameter is a function that returns the tail of the stream (a stream that contains all the remaining elements), most likely an empty stream. Are you confused? Let's take a look at an example:
Copy Code code as follows:

var s = new Stream (ten, 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 (ten, function () {
return new Stream (function () {
return new Stream (function () {
return new Stream ();
} );
} );
} );
The head of the T-stream is 10; Its tail has a-head which is and a tail which
Has a head which are and a tail which is the empty stream.
T.print (); Prints 10, 20, 30

Nothing to do? This can be done directly with Stream.make (10, 20, 30). However, please note that this way we can easily build our infinite stream. Let's do a stream that can be infinite:
Copy Code code as follows:

function ones () {
return new Stream (
The "a" 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

Note that if you use S.print () on an infinitely large stream, it will print endlessly and eventually deplete your memory. So, you'd better S.take (n) before using S.print (). Using S.length () on an infinite stream is meaningless, all, do not do these things; it causes an endless loop (trying to reach the end of an endless stream). But for the Infinity stream, you can use S.map (f) and S.filter (f). However, S.walk (f) is also bad for the infinite stream. All, some things you have to remember; For an infinite stream, be sure to use S.take (n) to take out a limited portion.

Let's see if we can do something more interesting. There's also an interesting way to create a stream that contains natural numbers:

Copy Code code as follows:

function ones () {
return new Stream (1, ones);
}
function Naturalnumbers () {
return new Stream (
The natural numbers are the stream whose-a-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

A careful reader will find out why the second parameter of the newly constructed stream is a function that returns the tail, not the tail itself. This method can be used to prevent the execution cycle from entering infinity by delaying the tail intercept operation.

Let's look at a more complicated example. The following is an exercise for the reader, please indicate what the following code is for?
Copy Code code as follows:

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 (a). Print ();

Please be sure to take some time to understand the purpose of this code. Unless you have functional programming experience, most programmers will find this code difficult to understand, so don't feel frustrated if you can't see it right away. Here's a hint: Find out what the head element of the printed stream is. Then find out what the second element is (the head element of the remaining element), then the third element, and then the fourth. The name of this function can also give you some hints.

If you are interested in this kind of problem, here are some.

If you really can't figure out what this code is for, you can run it and look at it yourself! So you can easily understand how it is done.

Salute
Streams is not really a new idea. Many functional programming languages support this feature. The so-called ' stream ' is the name of the scheme language, and scheme is a dialect of the Lisp language. The Haskell language also supports an infinite list. These ' take ', ' tail ', ' head ', ' map ' and ' filter ' names all come from the Haskell language. Python and many other Chinese languages also have different but very similar concepts, which are called "generators" (generators).

These ideas have been around for a long time in the community of functional programming. However, it is a new concept for most JavaScript programmers, especially those who do not have functional programming experience.

Here are a lot of examples and ideas from Structure and interpretation of the Computer Programs this book. If you like these ideas, I highly recommend you read it; This book is available free of charge online. It's also my creative source for developing this JavaScript class library.

If you like other grammatical forms of the stream, you can try Linq.js, or, if you use Node.js, Node-lazy may be more suitable for you.

If you like Coffeescript, Michael Blume is transplanting stream.js to Coffeescript to create Coffeestream.

Thank you for reading!
I hope you can gain something and enjoy stream.js. This class library is free, so if you like it, or it can help in some way, you might consider buying me a hot chocolate drink (I don't drink coffee) or write to me. If you are going to do this, please write down where you are and what you are doing. I like to collect pictures from all over the world, so please enclose the photos you took in your city!

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.