实际输出参数的主要优点是直接修改调用者范围内的一个或多个标量变量。在其他答案中提出的方法中,只有回调满足此要求:
function tryparse_int_1(s, cb)
{ var res = parseInt(s);
cb(res);
return !isNaN( res );
}
function test_1(s)
{ var /* inreger */ i;
if( tryparse_int_1( s, x=>i=x ) )
console.log(`String "${s}" is parsed as integer ${i}.`); else
console.log(`String "${s}" does not start with an integer.`);
}
test_1("47");
test_1("forty-seven");
在这种情况下,传递每个输出参数需要五个额外的字符来将其标识符包装到匿名 setter 函数中。它既不可读也不容易频繁输入,因此人们可以求助于脚本语言最有趣的一个特性——它们做魔术的能力,例如将字符串作为代码执行。
下面的例子实现了上面整数解析函数的扩展版本,它现在有两个输出参数:结果整数和一个指示它是否为正的标志:
/* ------------ General emulator of output parameters ------------ */
function out_lit(v)
{ var res;
if( typeof(v) === "string" )
res = '"' + v.split('\"').join('\\\"') + '"'; else
res = `${v}`;
return res;
}
function out_setpar(col, name, value)
{ if( col.outs == undefined ) col.outs = [];
col.outs[name] = value;
}
function out_setret(col, value)
{ col.ret = value; }
function out_ret( col )
{ var s;
for(e in col.outs)
{ s = s + "," + e + "=" + out_lit( col.outs[e] ); }
if( col.ret != undefined )
{ s = s + "," + out_lit( col.ret ); }
return s;
}
/* -------- An intger-parsing function using the emulator -------- */
function tryparse_int_2 // parse the prefix of a string as an integer
( /* string */ s, // in: input string
/* integer */ int, // out: parsed integer value
/* boolean */ pos // out: whether the result is positive
)
{ var /* integer */ res; // function result
var /* array */ col; // collection of out parameters
res = parseInt(s);
col = [];
out_setpar( col, int, res );
out_setpar( col, pos, res > 0 );
out_setret( col, !isNaN( res ) );
return out_ret( col );
}
在这个版本中,传递每个输出参数需要在其标识符周围添加两个额外的字符以将其嵌入到字符串文字中,每次调用加上六个字符来评估结果:
function test_2(s)
{ var /* integer */ int;
var /* boolean */ pos;
if( !eval( tryparse_int_2( s, "int", "pos" ) ) )
{ console.log(`String "${s}" does not start with an integer.`); }
else
{ if( pos ) adj = "positive";
else adj = "non-positive";
console.log(`String "${s}" is parsed as a ${adj} integer ${int}.`);
}
}
test_2( "55 parrots" );
test_2( "-7 thoughts" );
test_2( "several balls" );
上面测试代码的输出是:
String "55 parrots" is parsed as a positive integer 55.
String "-7 thoughts" is parsed as a non-positive integer -7.
String "several balls" does not start with an integer.
然而,这个解决方案有一个缺陷:它不能处理非基本类型的返回。
也许更简洁的方法是模拟指针:
// Returns JavaScript for the defintion of a "pointer" to a variable named `v':
// The identifier of the pointer is that of the variable prepended by a $.
function makeref(v)
{ return `var $${v} = {set _(val){${v}=val;},get _() {return ${v};}}`; }
// Calcualtes the square root of `value` and puts it into `$root`.
// Returns whether the operation has succeeded.
// In case of an error, stores error message in `$errmsg`.
function sqrt2
( /* in number */ value, /* value to take the root of */
/* out number */ $root , /* "pointer" to result */
/* out string */ $errmsg /* "pointer" to error message */
)
{ if( typeof( value ) !== "number" )
{ $errmsg._ = "value is not a number.";
return false;
}
if( value < 0 )
{ $errmsg._ = "value is negative.";
return false;
}
$root._ = Math.sqrt(value);
return true;
}
以下测试代码:
function test(v)
{ var /* string */ resmsg;
var /* number */ root ; eval( makeref( "root" ) );
var /* string */ errmsg; eval( makeref( "errmsg" ) );
if( sqrt2(v, $root, $errmsg) ) resmsg = `Success: ${root}`;
else resmsg = `Error: ${errmsg}`;
console.log(`Square root of ${v}: ` + resmsg );
}
test("s" );
test(-5 );
test( 1.44);
印刷:
Square root of s: Error: value is not a number.
Square root of -5: Error: value is negative.
Square root of 1.44: Success: 1.2
此方法创建的“指针”可在其他函数和同一函数的后续调用中重用。例如,您可以定义一个附加字符串的函数:
// Append string `sep' to a string pointed to by $s, using `sep` as separator:
// $s shall not point to an undefined value.
function append($s, sep, val)
{ if( $s._ != '' ) $s._ += sep;
$s._ += val;
}
并这样使用它:
const sep = ", "
var s; eval( makeref("s") );
s = '';
append( $s, sep, "one" );
append( $s, sep, "two" );
append( $s, sep, "three" );
console.log( s );
它将打印:
one, two, three