私は後世のためにこれに答えるつもりです。
ECMAScript 6 には、yieldステートメントがあります。しかし、あなたが気が狂っていて、今すぐこの機能を使いたいとしましょう。traceur-compilerを使用してプレーンな古い JavaScript にコンパイルすると、次のようになります。
入力:
var iterator = function* (object) {
for(var key in object) {
yield key;
for( k of iterator(object[key]) ) {
yield k;
}
}
};
var o = {
a: 10,
b: 11,
c: {
ca: 12,
cb: 13,
},
d: 14,
};
var res = [];
for( key of iterator(o) ) {
res.push(key);
}
res;
出力
var $__generatorWrap = function(generator) {
return $traceurRuntime.addIterator({
next: function(x) {
switch (generator.GState) {
case 1:
throw new Error('"next" on executing generator');
case 3:
throw new Error('"next" on closed generator');
case 0:
if (x !== undefined) {
throw new TypeError('Sent value to newborn generator');
}
case 2:
generator.GState = 1;
if (generator.moveNext(x, 0)) {
generator.GState = 2;
return {
value: generator.current,
done: false
};
}
generator.GState = 3;
return {
value: generator.yieldReturn,
done: true
};
}
},
'throw': function(x) {
switch (generator.GState) {
case 1:
throw new Error('"throw" on executing generator');
case 3:
throw new Error('"throw" on closed generator');
case 0:
generator.GState = 3;
throw x;
case 2:
generator.GState = 1;
if (generator.moveNext(x, 1)) {
generator.GState = 2;
return {
value: generator.current,
done: false
};
}
generator.GState = 3;
return {
value: generator.yieldReturn,
done: true
};
}
}
});
};
var iterator = function(object) {
var $that = this;
var $arguments = arguments;
var $state = 20;
var $storedException;
var $finallyFallThrough;
var $__0;
var $__1;
var $__2;
var $__3;
var $__4;
var $__5;
var key;
var $G = {
GState: 0,
current: undefined,
yieldReturn: undefined,
innerFunction: function($yieldSent, $yieldAction) {
while (true) switch ($state) {
case 20:
$__2 = [];
$state = 21;
break;
case 21:
$__3 = object;
$state = 23;
break;
case 23:
for (var $__4 in $__3) $__2.push($__4);
$state = 25;
break;
case 25:
$__5 = 0;
$state = 17;
break;
case 17:
if ($__5 < $__2.length) {
$state = 12;
break;
} else {
$state = 19;
break;
}
case 11:
$__5++;
$state = 17;
break;
case 12:
key = $__2[$__5];
$state = 13;
break;
case 13:
if (!(key in $__3)) {
$state = 11;
break;
} else {
$state = 15;
break;
}
case 15:
this.current = key;
$state = 1;
return true;
case 1:
if ($yieldAction == 1) {
$yieldAction = 0;
throw $yieldSent;
}
$state = 3;
break;
case 3:
$__0 = $traceurRuntime.getIterator(iterator(object[key]));
$state = 7;
break;
case 7:
if (!($__1 = $__0.next()).done) {
$state = 8;
break;
} else {
$state = 11;
break;
}
case 8:
k = $__1.value;
$state = 9;
break;
case 9:
this.current = k;
$state = 5;
return true;
case 5:
if ($yieldAction == 1) {
$yieldAction = 0;
throw $yieldSent;
}
$state = 7;
break;
case 19:
$state = -2;
case -2:
return false;
case -3:
throw $storedException;
default:
throw "traceur compiler bug: invalid state in state machine: " + $state;
}
},
moveNext: function($yieldSent, $yieldAction) {
while (true) try {
return this.innerFunction($yieldSent, $yieldAction);
} catch ($caughtException) {
$storedException = $caughtException;
switch ($state) {
default:
this.GState = 3;
$state = -2;
throw $storedException;
}
}
}
};
return $__generatorWrap($G);
};
var o = {
a: 10,
b: 11,
c: {
ca: 12,
cb: 13
},
d: 14
};
var res = [];
for (var $__1 = $traceurRuntime.getIterator(iterator(o)), $__0; !($__0 = $__1.next()).done;) {
key = $__0.value;
{
res.push(key);
}
}
res;
したがってyield
、JavaScript でのステートメントは可能ですが、非常に非現実的です。
実際に使ってみたもの
使用例:
var object = {...};
var callback = function (key, value) {
// Do stuff...
return traverse.CONTINUE;
// or return traverse.STOP if you want the iteration to stop
};
traverse(object, callback);
実装:
var traverse = (function () {
var _traverse = function (object, callback) {
var key, value, command;
for( key in object ) {
value = object[key];
command = callback(key, value);
if( command === _traverse.STOP ) {
return _traverse.STOP;
}
command = _traverse(value, callback);
if( command === _traverse.STOP ) {
return _traverse.STOP;
}
}
};
_traverse.CONTINUE = 1;
_traverse.STOP = 2;
return _traverse;
})();