ES6筆記三
阿新 • • 發佈:2017-07-02
es6
yield*語句
如果yield命令後面跟的是一個遍歷器,需要在yield命令後面加上星號,表明它返回的是一個遍歷器。這被稱為yield*語句
Generator是一個普通函數,但是有兩個特征。一是,function命令與函數名之間有一個星號;二是,函數體內部使用yield語句,定義遍歷器的每個成員,即不同的內部狀態(yield語句在英語裏的意思就是“產出”)。
ES6的Promise對象是一個構造函數,用來生成Promise實例。下面是Promise對象的基本用法。
var promise = new Promise(function(resolve, reject) { if (/* 異步操作成功 */){ resolve(value); } else { reject(error); }}); promise.then(function(value) { // success}, function(value) { // failure});
var getJSON = function(url) { var promise = new Promise(function(resolve, reject){ var client = new XMLHttpRequest(); client.open("GET", url); client.onreadystatechange = handler; client.responseType = "json"; client.setRequestHeader("Accept", "application/json"); client.send(); function handler() { if (this.status === 200) { resolve(this.response); } else { reject(new Error(this.statusText)); } }; }); return promise; }; getJSON("/posts.json").then(function(json) { console.log(‘Contents: ‘ + json); }, function(error) { console.error(‘出錯了‘, error);});
generator
function* helloWorldGenerator() { yield ‘hello‘; yield ‘world‘; return ‘ending‘; } var hw = helloWorldGenerator(); hw.next() // { value: ‘hello‘, done: false } hw.next() // { value: ‘world‘, done: false } hw.next() // { value: ‘ending‘, done: true } hw.next() // { value: undefined, done: true }
function* foo(x) { var y = 2 * (yield (x + 1)); var z = yield (y / 3); return (x + y + z); } var it = foo(5); it.next()// { value:6, done:false } it.next(12)// { value:8, done:false } it.next(13)// { value:42, done:true } 由於next方法的參數表示上一個yield語句的返回值,所以第一次使用next方法時,不能帶有參數
function *foo() { yield 1; yield 2; yield 3; yield 4; yield 5; return 6;} for (let v of foo()) { console.log(v); } // 1 2 3 4 5
function* fibonacci() { let [prev, curr] = [0, 1]; for (;;) { [prev, curr] = [curr, prev + curr]; yield curr; } } for (let n of fibonacci()) { if (n > 1000) break; console.log(n); }
var g = function* () { while (true) { try { yield; } catch (e) { if (e != ‘a‘) { throw e; } console.log(‘內部捕獲‘, e); } } }; var i = g(); i.next(); try { i.throw(‘a‘); i.throw(‘b‘); } catch (e) { console.log(‘外部捕獲‘, e); } // 內部捕獲 a // 外部捕獲 b
foo(‘a‘, function (a) { if (a.error) { throw new Error(a.error); } foo(‘b‘, function (b) { if (b.error) { throw new Error(b.error); } foo(‘c‘, function (c) { if (c.error) { throw new Error(c.error); } console.log(a, b, c); }); });});
使用Generator函數可以大大簡化上面的代碼。
function* g(){ try { var a = yield foo(‘a‘); var b = yield foo(‘b‘); var c = yield foo(‘c‘); } catch (e) { console.log(e); } console.log(a, b, c);}
let delegatedIterator = (function* () { yield ‘Hello!‘; yield ‘Bye!‘;}()); let delegatingIterator = (function* () { yield ‘Greetings!‘; yield* delegatedIterator; yield ‘Ok, bye.‘;}()); for(let value of delegatingIterator) { console.log(value);} // "Greetings! // "Hello!" // "Bye!" // "Ok, bye."
如果yield*
後面跟著一個數組,就表示該數組會返回一個遍歷器,因此就會遍歷數組成員。
function* gen(){ yield* ["a", "b", "c"];} gen().next() // { value:"a", done:false }
上面代碼中,yield命令後面如果不加星號,返回的是整個數組,加了星號就表示返回的是數組的遍歷器。
yield*
命令可以很方便地取出嵌套數組的所有成員。
function* iterTree(tree) { if (Array.isArray(tree)) { for(let i=0; i < tree.length; i++) { yield* iterTree(tree[i]); } } else { yield tree; } } const tree = [ ‘a‘, [‘b‘, ‘c‘], [‘d‘, ‘e‘] ]; for(let x of iterTree(tree)) { console.log(x); } // a // b // c // d // e
下面是一個稍微復雜的例子,使用yield*語句遍歷完全二叉樹。
// 下面是二叉樹的構造函數, // 三個參數分別是左樹、當前節點和右樹 function Tree(left, label, right) { this.left = left; this.label = label; this.right = right; } // 下面是中序(inorder)遍歷函數。 // 由於返回的是一個遍歷器,所以要用generator函數。 // 函數體內采用遞歸算法,所以左樹和右樹要用yield*遍歷 function* inorder(t) { if (t) { yield* inorder(t.left); yield t.label; yield* inorder(t.right); } } // 下面生成二叉樹 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])); } let tree = make([[[‘a‘], ‘b‘, [‘c‘]], ‘d‘, [[‘e‘], ‘f‘, [‘g‘]]]); // 遍歷二叉樹 var result = []; for (let node of inorder(tree)) { result.push(node); } result // [‘a‘, ‘b‘, ‘c‘, ‘d‘, ‘e‘, ‘f‘, ‘g‘]
ES6筆記三