ES7 comprehensions
Resume
This commit is contained in:
		
							
								
								
									
										
											BIN
										
									
								
								Resume.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Resume.pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										146
									
								
								_posts/2015-06-06-array-generator-comprehensions.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								_posts/2015-06-06-array-generator-comprehensions.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,146 @@ | ||||
| --- | ||||
| layout: post | ||||
| title:  "ES7 Array and Generator comprehensions" | ||||
| date:   2015-06-06 13:47:00 | ||||
| permalink: es7-array-generator-comprehensions | ||||
| categories: es7, generator, array | ||||
| --- | ||||
|  | ||||
| Array comprehension is a new feature proposed for ES7, with a new syntax | ||||
| to create new arrays from existing [iterables](http://www.2ality.com/2015/02/es6-iteration.html), | ||||
| comprehensions can replace `map`, `filter`. | ||||
|  | ||||
| Generator comprehension brings the same feature to generators, this is a more | ||||
| significant change as it removes the need to write new generators for simple map / filter operations. | ||||
|  | ||||
| Comprehensions are currently only supported by Firefox, use Firefox 30+ or [Babel](https://babeljs.io/repl/) to run the examples. The Node.js version using generator `function* ()`s is available at the [repository](https://github.com/mdibaiee/array-vs-generator) (doesn't require transpilation, use latest node). | ||||
|  | ||||
| #Syntax | ||||
|  | ||||
| The syntax is pretty simple, you can use only `for of` and `if` inside comprehensions. | ||||
|  | ||||
| Array comprehensions: | ||||
| {% highlight javascript %} | ||||
| let numbers = [1,2,3,4,5]; | ||||
|  | ||||
| let even = [ for (n of numbers) if (n % 2 === 0) n ]; | ||||
| // equivalent: | ||||
| // let even = numbers.map(n => { if (n % 2 === 0) return n }); | ||||
|  | ||||
| console.log(...even); // 2 4 | ||||
| {% endhighlight %} | ||||
|  | ||||
| Generator comprehensions: | ||||
| {% highlight javascript %} | ||||
| // yield 0...5 | ||||
| let generator = function* () { | ||||
|   for (let i = 0; i < 6; i++) { | ||||
|     yield i; | ||||
|   } | ||||
| } | ||||
|  | ||||
| let squared = ( for (n of generator()) n * n ); | ||||
| // equivalent (not lazy): | ||||
| // let squared = Array.from(generator()).map(n => n * n); | ||||
|  | ||||
| console.log(...squared); // 0 1 4 9 16 25 | ||||
| {% endhighlight %} | ||||
|  | ||||
| You can also nest comprehensions: | ||||
|  | ||||
| {% highlight javascript %} | ||||
| // yield 0...5 | ||||
| let generator = function* () { | ||||
|   for (let i = 0; i < 6; i++) { | ||||
|     yield i; | ||||
|   } | ||||
| } | ||||
|  | ||||
| // yield three numbers after number | ||||
| let after = function* (number) { | ||||
|   for (let i = 1; i < 4; i++) { | ||||
|     yield number + i; | ||||
|   } | ||||
| } | ||||
|  | ||||
| // for each number of 0...5, yield an array of 3 numbers after it | ||||
| let nested = ( for (n of generator()) | ||||
|                [ for (i of after(n)) i ] | ||||
|              ) | ||||
|  | ||||
| console.table(Array.from(nested)); | ||||
| // 1, 2, 3 | ||||
| // 2, 3, 4 | ||||
| // 3, 4, 5 | ||||
| // 4, 5, 6 | ||||
| // 5, 6, 7 | ||||
| // 6, 7, 8 | ||||
| {% endhighlight %} | ||||
|  | ||||
| #Lazy | ||||
| This is one of the most important advantages of generators over arrays and things alike. | ||||
| The reason why I'm including this here is to give you a good reason to write generators instead of arrays | ||||
|  while generator comprehensions make it extremely easy to write them — this is a proof of their usefulness. | ||||
|  | ||||
| In programming, laziness means doing nothing until the results are requested or in simpler terms, avoiding unnecessary work. | ||||
| For example, when you create an array and map it, the result will be evaluated no matter you need it now or not, you need the whole thing or a part of it, etc. | ||||
|  | ||||
| Take this example: | ||||
|  | ||||
| {% highlight javascript %} | ||||
| let bigArray = new Array(100000); | ||||
| for (let i = 0; i < 100000; i++) { | ||||
|   bigArray[i] = i; | ||||
| } | ||||
|  | ||||
| let first = bigArray.map(n => n * n)[0]; | ||||
| console.log(first); | ||||
| {% endhighlight %} | ||||
|  | ||||
| You know what happens here, first, map is evaluated, returning thousands of squared numbers, then | ||||
| the first element is returned. We must allocate and evaluate the whole squared array to be able to know about it's first or second element. | ||||
|  | ||||
| Think of optimizing it, is it possible to get the desired result without storing | ||||
| temporary arrays in memory? Can we get the first number directly without consuming a big chunk of memory? | ||||
|  | ||||
| Yes, using generators, Look at this: | ||||
|  | ||||
| {% highlight javascript %} | ||||
| let bigArray = function* () { | ||||
|   for (let i = 0; i < 100000; i++) { | ||||
|     yield i; | ||||
|   } | ||||
| } | ||||
|  | ||||
| let squared = ( for (n of bigArray()) n * n ); | ||||
|  | ||||
| console.log(squared.next()); | ||||
| {% endhighlight %} | ||||
|  | ||||
| Let's see what happens in this case. | ||||
| Here, we create a generator which will yield numbers 0...100000, nothing is actually allocated or evaluated, we just have a generator which will return a new number every time we call `next()`. | ||||
| Then we use generator comprehension to create another generator which squares the numbers our `bigArray()` generator yields, again, we don't evaluate or allocate anything, we just create a generator which will call another generator's `next()` method, square the results, and yield it. | ||||
|  | ||||
| Now when we call `squared.next()`, the `squared` generator calls `bigArray().next()`, squares the results and yields it, it doesn't do any unnecessary work, it's lazy. | ||||
|  | ||||
| If you profile heap/memory usage and running time, you will see the difference. | ||||
|  | ||||
| I have prepared a Node.js version of the test case. With the help of [`process.memoryUsage()`](https://nodejs.org/api/process.html#process_process_memoryusage) and [`console.time`](https://developer.mozilla.org/en-US/docs/Web/API/Console/time) we can easily see the difference. | ||||
| It's about ten times faster with two times less space used, isn't that awesome? | ||||
|  | ||||
| [Repository: mdibaiee/array-vs-generator](https://github.com/mdibaiee/array-vs-generator) | ||||
|  | ||||
|  | ||||
|  | ||||
| If you want to know more about lazy iterators, I recommend raganwald's [Lazy Iterables in JavaScript](http://raganwald.com/2015/02/17/lazy-iteratables-in-javascript.html). | ||||
|  | ||||
| More: | ||||
| [MDN: Array Comprehensions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Array_comprehensions) | ||||
|  | ||||
| [MDN: Generator Comprehensions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Generator_comprehensions) | ||||
|  | ||||
| [MDN: for...of](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of) | ||||
|  | ||||
| [MDN: Iterators and Generators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators?redirectlocale=en-US&redirectslug=JavaScript%2FGuide%2FIterators_and_Generators) | ||||
|  | ||||
| [ES6 in Depth: Generators](https://hacks.mozilla.org/2015/05/es6-in-depth-generators/?utm_source=javascriptweekly&utm_medium=email) | ||||
							
								
								
									
										
											BIN
										
									
								
								img/array-vs-generator.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								img/array-vs-generator.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 70 KiB | 
		Reference in New Issue
	
	Block a user