我是新来的,我正在尝试将递归函数转换为迭代函数。
我已经读了几天这个主题了,我找到了一些很好的网站给了我尝试的想法。但到目前为止我找不到合适的解决方案。
这是我要转换的代码:
function dump(value, recursionLevel) {
if(!recursionLevel) recursionLevel = 0;
var vType = typeof value;
var out = vType;
switch (vType) {
case "number":
case "boolean":
out += ": " + value;
break;
case "string":
out += "(" + value.length + '): "' + value + '"';
break;
case "object":
if (value === null) {
out = "null";
}
else if(Array.isArray(value)) {
out = 'array(' + value.length + '): {\n';
for(var i = 0; i < value.length; i++) {
out += ' '.repeat(recursionLevel) + " [" + i + "]: " + dump(value[i], recursionLevel + 1) + "\n";
}
out += ' '.repeat(recursionLevel) + "}";
}
break;
}
return out;
}
我无法找到转换它的方法,主要是因为for循环。任何形式的帮助将不胜感激。
非常感谢你!
修改
这是代码的最终结果:
递归版:
function varDumpR(value, indentationLevel) {
// CONFIGURABLE.
indentationSpaces = ' ';
indentationLevel = indentationLevel || 0;
// https://javascriptweblog.wordpress.com/2011/08/08/fixing-the-javascript-typeof-operator/
var valueType = ({}).toString.call(value).match(/\s([a-zA-Z]+)/)[1];
var output = '';
if(valueType === 'Null' || valueType === 'Undefined') {
output += valueType.toLowerCase();
}
else {
// This variable is used to distinguish between "primitive" and "object" String/Boolean/Number.
var isObject = true;
switch(valueType) {
case 'Function':
output += 'Object(' + '\n' + indentationSpaces.repeat(indentationLevel + 1) + valueType + '(';
var functionLines = value.toString().split('\n');
for(var i = 0, functionLinesLength = functionLines.length; i < functionLinesLength; i++) {
// Don't indent the first line. Indent all lines with 2 additional levels except the last one, which is indented with 1 additional level.
output += (i != 0 ? '\n' + indentationSpaces.repeat(indentationLevel + 1 + (+(i > 0 && i < functionLinesLength - 1))) : '') + functionLines[i].trim();
}
output += ')\n' + indentationSpaces.repeat(indentationLevel) + ') ';
break;
case 'Arguments':
case 'Array':
output += valueType + '(' + value.length + ') {\n';
break;
case 'String':
isObject = value instanceof String;
if(isObject) {
output += 'Object(' + '\n' + indentationSpaces.repeat(indentationLevel + 1) + valueType + '(' + value.length + ') "' + value + '"\n' + indentationSpaces.repeat(indentationLevel) + ') ';
}
else {
output += valueType + '(' + value.length + ') "' + value + '"'; // Beware of Strings containing "s.
}
break;
case 'Boolean':
isObject = value instanceof Boolean;
if(isObject) {
output += 'Object(' + '\n' + indentationSpaces.repeat(indentationLevel + 1) + valueType + '(' + value.toString() + ')\n' + indentationSpaces.repeat(indentationLevel) + ') ';
}
else {
output += valueType + '(' + value.toString() + ')';
}
break;
case 'Number':
isObject = value instanceof Number;
// http://cwestblog.com/2014/02/25/javascript-testing-for-negative-zero/
var number = value.valueOf();
var isNegative = (((number = +number) || 1 / number) < 0);
number = number < 0 ? -number : number;
var numberValue = '';
// Integer.
if(parseInt(number, 10) == parseFloat(number)) {
numberValue = 'Integer';
}
// NaN, Infinity, -Infinity.
else if(!isFinite(number)) {
numberValue = 'Number';
}
// Float.
else {
numberValue = 'Float';
}
numberValue += '(' + (isNegative ? '-' : '') + number + ')';
if(isObject) {
output += 'Object(' + '\n' + indentationSpaces.repeat(indentationLevel + 1) + numberValue + '\n' + indentationSpaces.repeat(indentationLevel) + ') ';
}
else {
output += numberValue;
}
break;
case 'Date':
case 'RegExp':
output += 'Object(' + '\n' + indentationSpaces.repeat(indentationLevel + 1) + valueType + ' "' + value.toString() + '"\n' + indentationSpaces.repeat(indentationLevel) + ') ';
break;
// 'Object'
// 'Error'
// 'Math'
// 'JSON'
default:
output += (valueType === 'Object' ? 'Object': 'Object(' + valueType + ') ');
break;
}
if(isObject) {
if(valueType == 'Arguments' || valueType == 'Array') {
for(var i = 0, valueLength = value.length; i < valueLength; i++) {
output += indentationSpaces.repeat(indentationLevel) + ' [' + i + ']=>\n ' + indentationSpaces.repeat(indentationLevel) + varDumpR(value[i], indentationLevel + 1) + '\n';
}
}
else {
var objectProperties = [];
for(var property in value) {
objectProperties.push(property);
}
output += '(' + objectProperties.length + ') {\n';
for(var i = 0, objectPropertiesLength = objectProperties.length; i < objectPropertiesLength; i++) {
output += indentationSpaces.repeat(indentationLevel) + ' ["' + objectProperties[i] + '"]=>\n ' + indentationSpaces.repeat(indentationLevel) + varDumpR(value[objectProperties[i]], indentationLevel + 1) + '\n';
}
}
output += indentationSpaces.repeat(indentationLevel) + '}';
}
}
return output;
}
迭代版本:
function varDumpI(value) {
// CONFIGURABLE.
indentationSpaces = ' ';
var output = '';
var recursionStack = [{value: value, indentationLevel: 0, output: null}];
while(recursionStack.length > 0) {
var entry = recursionStack.pop();
if(entry.output) {
output += entry.output;
}
else {
value = entry.value;
indentationLevel = entry.indentationLevel;
// https://javascriptweblog.wordpress.com/2011/08/08/fixing-the-javascript-typeof-operator/
var valueType = ({}).toString.call(value).match(/\s([a-zA-Z]+)/)[1];
if(valueType === 'Null' || valueType === 'Undefined') {
output += valueType.toLowerCase();
}
else {
// This variable is used to distinguish between "primitive" and "object" String/Boolean/Number.
var isObject = true;
switch(valueType) {
case 'Function':
output += 'Object(' + '\n' + indentationSpaces.repeat(indentationLevel + 1) + valueType + '(';
var functionLines = value.toString().split('\n');
for(var i = 0, functionLinesLength = functionLines.length; i < functionLinesLength; i++) {
// Don't indent the first line. Indent all lines with 2 additional levels except the last one, which is indented with 1 additional level.
output += (i != 0 ? '\n' + indentationSpaces.repeat(indentationLevel + 1 + (+(i > 0 && i < functionLinesLength - 1))) : '') + functionLines[i].trim();
}
output += ')\n' + indentationSpaces.repeat(indentationLevel) + ') ';
break;
case 'Arguments':
case 'Array':
output += valueType + '(' + value.length + ') {\n';
break;
case 'String':
isObject = value instanceof String;
if(isObject) {
output += 'Object(' + '\n' + indentationSpaces.repeat(indentationLevel + 1) + valueType + '(' + value.length + ') "' + value + '"\n' + indentationSpaces.repeat(indentationLevel) + ') ';
}
else {
output += valueType + '(' + value.length + ') "' + value + '"'; // Beware of Strings containing "s.
}
break;
case 'Boolean':
isObject = value instanceof Boolean;
if(isObject) {
output += 'Object(' + '\n' + indentationSpaces.repeat(indentationLevel + 1) + valueType + '(' + value.toString() + ')\n' + indentationSpaces.repeat(indentationLevel) + ') ';
}
else {
output += valueType + '(' + value.toString() + ')';
}
break;
case 'Number':
isObject = value instanceof Number;
// http://cwestblog.com/2014/02/25/javascript-testing-for-negative-zero/
var number = value.valueOf();
var isNegative = (((number = +number) || 1 / number) < 0);
number = number < 0 ? -number : number;
var numberValue = '';
// Integer.
if(parseInt(number, 10) == parseFloat(number)) {
numberValue = 'Integer';
}
// NaN, Infinity, -Infinity.
else if(!isFinite(number)) {
numberValue = 'Number';
}
// Float.
else {
numberValue = 'Float';
}
numberValue += '(' + (isNegative ? '-' : '') + number + ')';
if(isObject) {
output += 'Object(' + '\n' + indentationSpaces.repeat(indentationLevel + 1) + numberValue + '\n' + indentationSpaces.repeat(indentationLevel) + ') ';
}
else {
output += numberValue;
}
break;
case 'Date':
case 'RegExp':
output += 'Object(' + '\n' + indentationSpaces.repeat(indentationLevel + 1) + valueType + ' "' + value.toString() + '"\n' + indentationSpaces.repeat(indentationLevel) + ') ';
break;
// 'Object'
// 'Error'
// 'Math'
// 'JSON'
default:
output += (valueType === 'Object' ? 'Object': 'Object(' + valueType + ') ');
break;
}
if(isObject) {
recursionStack.push({output: indentationSpaces.repeat(indentationLevel) + '}'});
if(valueType == 'Arguments' || valueType == 'Array') {
// Loop through the array in reverse order to maintain the consistency with the recursive function.
for(var i = value.length - 1; i >= 0; i--) {
recursionStack.push({output: '\n'});
recursionStack.push({value: value[i], indentationLevel: indentationLevel + 1});
recursionStack.push({output: indentationSpaces.repeat(indentationLevel) + ' [' + i + ']=>\n ' + indentationSpaces.repeat(indentationLevel)});
}
}
else {
var objectProperties = [];
for(var property in value) {
objectProperties.push(property);
}
output += '(' + objectProperties.length + ') {\n';
// Loop through the object in reverse order to maintain the consistency with the recursive function.
for(var i = objectProperties.length - 1; i >= 0; i--) {
recursionStack.push({output: '\n'});
recursionStack.push({value: value[objectProperties[i]], indentationLevel: indentationLevel + 1});
recursionStack.push({output: indentationSpaces.repeat(indentationLevel) + ' ["' + objectProperties[i] + '"]=>\n ' + indentationSpaces.repeat(indentationLevel)});
}
}
}
}
}
}
return output;
}
接受多个参数的迭代版本:
function varDump() {
// CONFIGURABLE.
indentationSpaces = ' ';
var output = '';
for(arg = 0, argumentsLength = arguments.length; arg < argumentsLength; arg++) {
value = arguments[arg];
var recursionStack = [{value: value, indentationLevel: 0, output: null}];
var seenObjects = [];
if(arg > 0) {
output += '\n';
}
while(recursionStack.length > 0) {
var entry = recursionStack.pop();
if(entry.output) {
output += entry.output;
}
else {
value = entry.value;
indentationLevel = entry.indentationLevel;
// https://javascriptweblog.wordpress.com/2011/08/08/fixing-the-javascript-typeof-operator/
var valueType = ({}).toString.call(value).match(/\s([a-zA-Z]+)/)[1];
if(seenObjects.indexOf(value) !== -1) {
output += '*RECURSION*';
}
else if(valueType === 'Null' || valueType === 'Undefined') {
output += valueType.toLowerCase();
}
else {
// This variable is used to distinguish between "primitive" and "object" String/Boolean/Number.
var isObject = true;
switch(valueType) {
case 'Function':
output += 'Object(' + '\n' + indentationSpaces.repeat(indentationLevel + 1) + valueType + '(';
var functionLines = value.toString().split('\n');
for(var i = 0, functionLinesLength = functionLines.length; i < functionLinesLength; i++) {
// Don't indent the first line. Indent all lines with 2 additional levels except the last one, which is indented with 1 additional level.
output += (i != 0 ? '\n' + indentationSpaces.repeat(indentationLevel + 1 + (+(i > 0 && i < functionLinesLength - 1))) : '') + functionLines[i].trim();
}
output += ')\n' + indentationSpaces.repeat(indentationLevel) + ') ';
break;
case 'Arguments':
case 'Array':
output += valueType + '(' + value.length + ') {\n';
break;
case 'String':
isObject = value instanceof String;
if(isObject) {
output += 'Object(' + '\n' + indentationSpaces.repeat(indentationLevel + 1) + valueType + '(' + value.length + ') "' + value + '"\n' + indentationSpaces.repeat(indentationLevel) + ') ';
}
else {
output += valueType + '(' + value.length + ') "' + value + '"'; // Beware of Strings containing "s.
}
break;
case 'Boolean':
isObject = value instanceof Boolean;
if(isObject) {
output += 'Object(' + '\n' + indentationSpaces.repeat(indentationLevel + 1) + valueType + '(' + value.toString() + ')\n' + indentationSpaces.repeat(indentationLevel) + ') ';
}
else {
output += valueType + '(' + value.toString() + ')';
}
break;
case 'Number':
isObject = value instanceof Number;
// http://cwestblog.com/2014/02/25/javascript-testing-for-negative-zero/
var number = value.valueOf();
var isNegative = (((number = +number) || 1 / number) < 0);
number = number < 0 ? -number : number;
var numberValue = '';
// Integer.
if(parseInt(number, 10) == parseFloat(number)) {
numberValue = 'Integer';
}
// NaN, Infinity, -Infinity.
else if(!isFinite(number)) {
numberValue = 'Number';
}
// Float.
else {
numberValue = 'Float';
}
numberValue += '(' + (isNegative ? '-' : '') + number + ')';
if(isObject) {
output += 'Object(' + '\n' + indentationSpaces.repeat(indentationLevel + 1) + numberValue + '\n' + indentationSpaces.repeat(indentationLevel) + ') ';
}
else {
output += numberValue;
}
break;
case 'Date':
case 'RegExp':
output += 'Object(' + '\n' + indentationSpaces.repeat(indentationLevel + 1) + valueType + ' "' + value.toString() + '"\n' + indentationSpaces.repeat(indentationLevel) + ') ';
break;
// 'Object'
// 'Error'
// 'Math'
// 'JSON'
default:
output += (valueType === 'Object' ? 'Object': 'Object(' + valueType + ') ');
break;
}
if(isObject) {
if(valueType !== 'Math' && valueType !== 'JSON') {
seenObjects.push(value);
}
recursionStack.push({output: indentationSpaces.repeat(indentationLevel) + '}'});
if(valueType == 'Arguments' || valueType == 'Array') {
// Loop through the array in reverse order to maintain the consistency with the recursive function.
for(var i = value.length - 1; i >= 0; i--) {
recursionStack.push({output: '\n'});
recursionStack.push({value: value[i], indentationLevel: indentationLevel + 1});
recursionStack.push({output: indentationSpaces.repeat(indentationLevel) + ' [' + i + ']=>\n ' + indentationSpaces.repeat(indentationLevel)});
}
}
else {
var objectProperties = [];
for(var property in value) {
objectProperties.push(property);
}
output += '(' + objectProperties.length + ') {\n';
// Loop through the object in reverse order to maintain the consistency with the recursive function.
for(var i = objectProperties.length - 1; i >= 0; i--) {
recursionStack.push({output: '\n'});
recursionStack.push({value: value[objectProperties[i]], indentationLevel: indentationLevel + 1});
recursionStack.push({output: indentationSpaces.repeat(indentationLevel) + ' ["' + objectProperties[i] + '"]=>\n ' + indentationSpaces.repeat(indentationLevel)});
}
}
}
}
}
}
}
return output;
}
测试代码:
(function testVarDump() {
var func1 = function(par1, par2) {
var sum;
sum = par1 + par2;
return sum;
}
function func2(par1, par2) {
var sum;
sum = par1 + par2;
return sum;
}
var date = new Date(2016, 1, 21);
date.prop = 'date';
var regex = new RegExp(/a/);
regex.prop = 'regex';
var error = new Error('ERROR');
error.prop = 'error';
var math = Math;
math.prop = 'math';
var json = JSON;
json.prop = 'json';
var circular = [];
circular[0] = 0;
circular[1] = circular;
var test = [
'a', String('a'), new String('a'),
true, Boolean(true), new Boolean(true),
12, 12.6, 0, -0, NaN, Infinity, -Infinity,
Number(12), Number(12.6), Number(0), Number(-0), Number(NaN), Number(Infinity), Number(-Infinity),
new Number(12), new Number(12.6), new Number(0), new Number(-0), new Number(NaN), new Number(Infinity), new Number(-Infinity),
null, undefined,
['a', String('a'), new String('a'),
true, Boolean(true), new Boolean(true),
12, 12.6, 0, -0, NaN, Infinity, -Infinity,
Number(12), Number(12.6), Number(0), Number(-0), Number(NaN), Number(Infinity), Number(-Infinity),
new Number(12), new Number(12.6), new Number(0), new Number(-0), new Number(NaN), new Number(Infinity), new Number(-Infinity),
null, undefined],
{
a: [{aa: 1, bb: 2}, Object(), new Object()],
b: [func1, func2, new Function, function() { return false; }, Function(), new Function()],
c: [arguments],
d: [date, Date(), new Date(2016, 1, 21)],
e: [regex, /a/, RegExp(/a/), new RegExp(/a/)],
f: [error, Error('ERROR'), new Error('ERROR')],
g: [math, Math],
h: [json, JSON]
},
]
console.log(varDumpR(test));
console.log(varDumpI(test));
console.log(varDump(test, circular));
})('arg1', 'arg2');
备注:
原始代码来自这里:
它最终与此类似(我没有复制它,但两者都非常相似):
答案 0 :(得分:1)
这听起来很像你必须为家庭作业做的那种问题。要解决这个问题,您将需要一个堆栈。在JavaScript中,堆栈由数组实现 - 它们已经具有您需要的push()和pop()方法。
这是一个用JavaScript概念进行转储的小程序(不完全是JSON,但类似) - 将输出格式更改为您的需要留作练习。
function dump(value) {
var stack=[{value:value}];
var out = "";
while (stack.length>0) {
var entry = stack.pop();
if (entry.output) {
out+=entry.output;
}
else {
value = entry.value;
switch(typeof value) {
case "number":
case "boolean":
out += value;
break;
case "string":
out += '"'+value+'"'; // beware of Strings containing "s
break;
case "object":
if (value === null) {
out += "null";
}
else if (Array.isArray(value)) {
out += "[";
stack.push({output:"]"});
for (var i=value.length-1; i>=0; i--) {
stack.push({value: value[i]});
if (i>0) {
stack.push({output:","});
}
}
}
else {
out += "{";
stack.push({output:"}"});
var s = "";
var f;
for (f in value ) {
if (s) {
stack.push({output: s});
}
stack.push({value: value[f]});
stack.push({output: f+":"});
s = ",";
}
}
break;
}
}
}
return out;
}