for(;;) and for a in b var divs = document.querySelectorAll('div'); for (var i = 0, c = divs.length; i < c; i++) { console.log(divs[i].innerHTML); } var obj = {a: 1, b: 2, c: 3}; for (var i in obj) { console.log(i, obj[i]); } map(), filter() elements. var numbers = [1, 2, 3, 4, 5]; var doubled = numbers.map(function (item) { return item * 2; }); console.log(doubled); var numbers = [1, 2, 3, 4]; var doubled = [i * 2 for each (i in numbers)]; console.log(doubled); // [2, 4, 6, 8] for in and encapsulate the process of getting the next item in the list of objects. var object = [1,2,3]; for (var i in object) { console.log(i, object[i]); } var object = {a:1, b:2, c:3}; for (var i in object) { console.log(i, object[i]); } var object = 'abc'; for (var i in object) { console.log(i, object[i]); } var object = document.querySelectorAll('div'); for (var i in object) { if (object.hasOwnProperty(i)) { console.log(i, object[i]); } } next() method that returns the next object in the sequence. This method can cause a StopIteration exception when the sequence has ended.next() method or using for...in or for each (FF) constructs. var lang = { name: 'JavaScript', birthYear: 1995 }; var it = Iterator(lang); // <<< it object can be iterated using next() var pair = it.next(); // ["name", "JavaScript"] pair = it.next(); // ["birthYear", 1995] pair = it.next(); // StopIteration for...in or for each . The traversal will be stopped as soon as the exception StopIteration is thrown: var it = Iterator(lang); for (var pair in it) { console.log(pair); // 2 [key, value] } Iterator() is that it bypasses only its own properties (remember the example of traversing querySelectorAll ) while traversing you do not need to check object.hasOwnProperty .Iterator() can also be used for an array: var langs = ['JavaScript', 'Python', 'C++']; var it = Iterator(langs); for (var pair in it) { console.log(pair); // [index, language] } Iterator function Iterator second argument, then only the indices will be iterated: var langs = ['JavaScript', 'Python', 'C++']; var it = Iterator(langs, true); for (var pair in it) { console.log(pair); // 0, 1, 2 } let and destructive assignment (FF only): var langs = ['JavaScript', 'Python', 'C++']; var it = Iterator(langs); for (let [i, lang] in it) { // FF console.log(i + ': ' + lang); // "0: JavaScript" . } for in without Iterator . function Range(low, high){ this.low = low; this.high = high; } next() method that will return an element of the sequence and throw a StopIteration exception at the end. function RangeIterator(range){ this.range = range; this.current = this.range.low; } RangeIterator.prototype.next = function(){ if (this.current > this.range.high) throw StopIteration; else return this.current++; }; var ri = new RangeIterator(new Range(1, 10)); ri.next(); // ... ri.next(); // StopIteration RangeIterator constructor, RangeIterator will use the __iterator__ method __iterator__ the Range object. This method will be called when trying to iterate over the elements of a Range object. This method should return a RangeIterator that includes the iterator logic. Range.prototype.__iterator__ = function(){ return new RangeIterator(this); }; var range = new Range(3, 5); for (var i in range) { console.log(i); // 3, 4, 5 } yield becomes a generator.<script type="application/javascript;version=1.7">next() will perform the function body until a yield is returned that returns a result. If the function ends with return or the function body ends, the StopIteration exception is StopIteration and the iterator stops its operation. function simpleGenerator(){ yield "first"; yield "second"; yield "third"; for (var i = 0; i < 3; i++) { yield i; } } var g = simpleGenerator(); console.log(g.next()); // "first" console.log(g.next()); // "second" console.log(g.next()); // "third" console.log(g.next()); // 0 console.log(g.next()); // 1 console.log(g.next()); // 2 console.log(g.next()); // StopIteration __iterator__ method of an __iterator__ object. This will significantly reduce the amount of code. Let's rewrite the example from Range using generators: function Range(low, high){ this.low = low; this.high = high; } Range.prototype.__iterator__ = function(){ for (var i = this.low; i <= this.high; i++) { yield i; } }; var range = new Range(3, 5); for (var i in range) { console.log(i); // 3, 4, 5 } function fibonacci(){ var fn1 = 1; var fn2 = 1; while (1){ var current = fn2; fn2 = fn1; fn1 = fn1 + current; yield current; } } var sequence = fibonacci(); console.log(sequence.next()); // 1 console.log(sequence.next()); // 1 console.log(sequence.next()); // 2 console.log(sequence.next()); // 3 console.log(sequence.next()); // 5 console.log(sequence.next()); // 8 // ... StopIteration or return . Rewrite the Fibonacci example using the limit argument. function fibonacci(limit){ var fn1 = 1; var fn2 = 1; while (1) { var current = fn2; fn2 = fn1; fn1 = fn1 + current; if (limit && current > limit) { return; } yield current; } } var sequence = fibonacci(7); console.log(sequence.next()); // 1 console.log(sequence.next()); // 1 console.log(sequence.next()); // 2 console.log(sequence.next()); // 3 console.log(sequence.next()); // 5 console.log(sequence.next()); // StopIteration next() method, the Iterator-Generator has a send() method that allows you to change the internal state of the generator. The value passed to send() will be perceived as the result of the last yield that stopped the generator. You must start the generator with next() before calling send() .send() to restart the sequence: function fibonacci(){ var fn1 = 1; var fn2 = 1; while (1){ var current = fn2; fn2 = fn1; fn1 = fn1 + current; var reset = yield current; if (reset){ fn1 = 1; fn2 = 1; } } } var sequence = fibonacci(); print(sequence.next()); // 1 print(sequence.next()); // 1 print(sequence.next()); // 2 print(sequence.next()); // 3 print(sequence.next()); // 5 print(sequence.send(true)); // 1 print(sequence.next()); // 1 print(sequence.next()); // 2 print(sequence.next()); // 3 throw() method. This method takes one argument, which will throw the generator ( throw value; ). This exception will be thrown from the current stopped generator context (in the place where the last yield ).next() method), then throw() will call next() and throw an exception at the yield .close() method:finally blocks will be executed.finally block throws an exception other than StopIteration , then the exception will be thrown into the context from which the close() method was called var doubles = [i * 2 for (i in it)]; var it2 = (i * 2 for (i in it)); print(it2.next()); // print(it2.next()); // var result = doSomething(i * 2 for (i in it)); innerHTML and if innerHTML matches the domain, output the domain to the console. <a href="http://ya.ru/"> </a> <a href="http://google.ru/"></a> <a href="http://habrahabr.ru/"></a> <a href="http://twitter.com/">twitter.com</a> var aList = document.querySelectorAll('a'); for (var i = 0, c = aList.length, a, content, domain; i < c; i++) { a = aList[i]; content = a.innerHTML; domain = a.getAttribute('href').replace('http://', '').split('/').shift(); if (content === domain) { console.log(domain); } } // type="application/javascript;version=1.7" var aDomainContentGenerator = function () { var aList = document.querySelectorAll('a'); for (var i = 0, c = aList.length, a, content, domain; i < c; i++) { a = aList[i]; content = a.innerHTML; domain = a.getAttribute('href').replace('http://', '').split('/').shift(); yield {domain: domain, content: content}; } }; var ancors = aDomainContentGenerator(); // - // for c if, . , var ancorsWithSameContentAndDomain = (item for (item in ancors) if (item.content === item.domain)); for (item in ancorsWithSameContentAndDomain) { console.log(item.domain); } aDomainContentGenerator() generator for other purposes. function Tree(left, label, right) { this.left = left; this.label = label; this.right = right; } // function inorder(t) { if (t) { for (var item in inorder(t.left)) { yield item; } yield t.label; for (var item in inorder(t.right)) { yield item; } } } // function make(array) { // : if (array.length == 1) return new Tree(null, array[0], null); return new Tree(make(array[0]), array[1], make(array[2])); } var tree = make([[['a'], 'b', ['c']], 'd', [['e'], 'f', ['g']]]); // for (var node in inorder(tree)) { console.log(node); // a, b, c, d, ... } for (var item in inorder(t.right)) { yield item; } yield for inorder(t.right); for (var node in inorder(tree)) { console.log(node); // a, b, c, d, ... } for (let node : inorder(tree)) { console.log(node); // a, b, c, d, ... } Function#bind , Object.defineProperty so the compiled version only works in the TC creator’s browser, Google Chrome :). The compiled code of the generator is obtained monstrous with the use of a finite state machine and dances around try catch and other perversions. It turns out this "code": function Tree(left, label, right) { this.left = left; this.label = label; this.right = right; } function inorder(t) { var $that = this; return { __traceurIterator__: function() { var $state = 20; var $storedException; var $finallyFallThrough; var $__1; var $__2; var $__3; var $__4; var $result = { moveNext:(function() { while(true) try { switch($state) { case 20: if(t) { $state = 7; break; } else { $state = 15; break; } case 7: $__2 = inorder(t.left).__traceurIterator__(); $state = 8; break; case 8: if($__2.moveNext()) { $state = 2; break; } else { $state = 5; $finallyFallThrough = 4; break; } case 2: $__1 = $__2.current; $state = 3; break; case 3: $result.current = $__1; $state = 8; return true; case 5: { if($__2.close) $__2.close(); } $state = 6; break; case 4: $result.current = t.label; $state = 10; return true; case 10: $__4 = inorder(t.right).__traceurIterator__(); $state = 19; break; case 19: if($__4.moveNext()) { $state = 13; break; } else { $state = 16; $finallyFallThrough = 15; break; } case 13: $__3 = $__4.current; $state = 14; break; case 14: $result.current = $__3; $state = 19; return true; case 16: { if($__4.close) $__4.close(); } $state = 17; break; case 6: $state = $finallyFallThrough; break; case 17: $state = $finallyFallThrough; break; case 15: $state = 22; case 22: return false; case 21: throw $storedException; default: throw "traceur compiler bug: invalid state in state machine" + $state; } } catch($caughtException) { $storedException = $caughtException; switch($state) { case 8: $state = 5; $finallyFallThrough = 21; break; case 2: $state = 5; $finallyFallThrough = 21; break; case 3: $state = 5; $finallyFallThrough = 21; break; case 19: $state = 16; $finallyFallThrough = 21; break; case 13: $state = 16; $finallyFallThrough = 21; break; case 14: $state = 16; $finallyFallThrough = 21; break; default: throw $storedException; } } }).bind($that) }; return $result; } }; } function make(array) { if(array.length == 1) return new Tree(null, array[0], null); return new Tree(make(array[0]), array[1], make(array[2])); } var tree = make([[['a'], 'b',['c']], 'd',[['e'], 'f',['g']]]); { var $__0 = inorder(tree).__traceurIterator__(); try { while($__0.moveNext()) { try { throw undefined; } catch(node) { node = $__0.current; { console.log(node); } } } } finally { if($__0.close) $__0.close(); } } Code for half the article - left to show that everything is bad with him ...Function#bind and Object.defineProperty , in any case, TC turns the code into a brake monster and therefore its use is questionable.Source: https://habr.com/ru/post/122620/
All Articles