如何最好地在 JavaScript 中实现参数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3175687/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How best to implement out params in JavaScript?
提问by Nick Heiner
I'm using Javascript with jQuery. I'd like to implement out params. In C#, it would look something like this:
我在 jQuery 中使用 Javascript。我想实现参数。在 C# 中,它看起来像这样:
/*
* odp the object to test
* error a string that will be filled with the error message if odp is illegal. Undefined otherwise.
*
* Returns true if odp is legal.
*/
bool isLegal(odp, out error);
What is the best way to do something like this in JS? Objects?
在 JS 中做这样的事情的最好方法是什么?对象?
function isLegal(odp, errorObj)
{
// ...
errorObj.val = "ODP failed test foo";
return false;
}
Firebug tells me that the above approach would work, but is there a better way?
Firebug 告诉我上述方法可行,但有更好的方法吗?
回答by Pointy
The callback approach mentioned by @Felix Kling is probably the best idea, but I've also found that sometimes it's easy to leverage Javascript object literal syntax and just have your function return an object on error:
@Felix Kling 提到的回调方法可能是最好的主意,但我也发现有时很容易利用 Javascript 对象文字语法,只需让您的函数在出错时返回一个对象:
function mightFail(param) {
// ...
return didThisFail ? { error: true, msg: "Did not work" } : realResult;
}
then when you call the function:
然后当你调用函数时:
var result = mightFail("something");
if (result.error) alert("It failed: " + result.msg);
Not fancy and hardly bulletproof, but certainly it's OK for some simple situations.
不花哨,也很难防弹,但对于一些简单的情况肯定是可以的。
回答by Felix Kling
I think this is pretty much the only way (but I am not a hardcore JavaScript programmer ;)).
我认为这几乎是唯一的方法(但我不是一个铁杆 JavaScript 程序员;))。
What you could also consider is to use a callback function:
您还可以考虑使用回调函数:
function onError(data) {
// do stuff
}
function isLegal(odp, cb) {
//...
if(error) cb(error);
return false;
}
isLegal(value, onError);
回答by casablanca
Yes, as you yourself mentioned, objects are the best and only way to pass data by reference in JavaScript. I would keep your isLegalfunction as such and simply call it like this:
是的,正如你自己提到的,对象是在 JavaScript 中通过引用传递数据的最好也是唯一的方式。我会保留您的isLegal功能,并简单地这样称呼它:
var error = {};
isLegal("something", error);
alert(error.val);
回答by Matt
The answers I have seen so far aren't implementing out parameters in JavaScript, as they are used in C# (the outkeyword). They are merely a workaround that returns an object in case of an error.
到目前为止,我看到的答案并没有在 JavaScript 中实现参数,因为它们在 C#(out关键字)中使用。它们只是一种在发生错误时返回对象的解决方法。
But what do you do if you really need out parameters?
但是如果你真的需要参数,你会怎么做?
Because Javascript doesn't directly support it, you need to build something that is close to C#'s out parameters. Take a look at this approach, I am emulating C#s DateTime.TryParse function in JavaScript. The out parameter is result, and because JavaScript doesn't provide an out keyword, I am using .valueinside the function to pass the value outside the function (as inspired by MDN suggestion):
因为 Javascript 不直接支持它,所以你需要构建一些接近 C# 的输出参数的东西。看看这个方法,我在 JavaScript 中模拟 C#s DateTime.TryParse 函数。out 参数是结果,因为 JavaScript 没有提供 out 关键字,所以我.value在函数内部使用 将值传递到函数外部(受MDN 建议的启发):
// create a function similar to C#'s DateTime.TryParse
var DateTime = [];
DateTime.TryParse = function(str, result) {
result.value = new Date(str); // out value
return (result.value != "Invalid Date");
};
// now invoke it
var result = [];
if (DateTime.TryParse("05.01.2018", result)) {
alert(result.value);
} else {
alert("no date");
};
Run the snippet and you'll see it works: It parses the strparameter into a Date and returns it in the resultparameter. Note that resultneeds to be initialized as empty array [], beforeyou call the function. This is required because inside the function you "inject" the .valueproperty.
运行代码片段,您将看到它的工作原理:它将str参数解析为 Date 并在result参数中返回它。请注意,在调用该函数之前,result需要将其初始化为空数组[]。这是必需的,因为在函数内部您“注入”了该属性。.value
Now you can use the pattern above to write a function as the one in your question (this also shows you how to emulate the new discardparameter known as out _in C#: In JavaScript we're passing []as shown below):
现在,您可以使用上面的模式编写一个函数作为您问题中的函数(这也向您展示了如何模拟C# 中已知的新丢弃参数out _:在 JavaScript 中,我们传递[]如下所示):
// create a function similar to C#'s DateTime.TryParse
var DateTime = [];
DateTime.TryParse = function(str, result) {
result.value = new Date(str); // out value
return (result.value != "Invalid Date");
};
// returns false, if odb is no date, otherwise true
function isLegal(odp, errorObj) {
if (DateTime.TryParse(odp, [])) { // discard result here by passing []
// all OK: leave errorObj.value undefined and return true
return true;
} else {
errorObj.value = "ODP failed test foo"; // return error
return false;
}
}
// now test the function
var odp = "xxx01.12.2018xx"; // invalid date
var errorObj = [];
if (!isLegal(odp, errorObj)) alert(errorObj.value); else alert("OK!");
What this example does is it uses the resultparameter to pass an error message as follows:
此示例的作用是使用result参数传递错误消息,如下所示:
errorObj.value = "ODP failed test foo"; // return error
errorObj.value = "ODP 测试失败 foo"; // 返回错误
If you run the example it will display this message in a popup dialog.
如果您运行该示例,它将在弹出对话框中显示此消息。
Note:Instead of using a discard parameter as shown above, in JavaScript you could also use a check for undefined, i.e. inside the function check for
注意:除了使用上面显示的丢弃参数,在 JavaScript 中你还可以使用检查 for undefined,即在函数内部检查
if (result === undefined) {
// do the check without passing back a value, i.e. just return true or false
};
Then it is possible to omit resultas a parameter completely if not needed, so you could invoke it like
result如果不需要,则可以完全省略作为参数,因此您可以像这样调用它
if (DateTime.TryParse(odp)) {
// ... same code as in the snippet above ...
};
回答by Humilulo -- Shawn Kovac
there is another way JS can pass 'out' parameters. but i believe the best ones for your situation were already mentioned.
JS 可以通过另一种方式传递“输出”参数。但我相信已经提到了最适合您的情况。
Arrays are also passed by reference, not value. thus just as you can pass an object to a function, and then set a property of the object in the function, and then return, and access that object's property, you can similarly pass an Array to a function, set some values of the array inside the function, and return and access those values outside the array.
数组也是通过引用传递的,而不是值传递。因此,就像您可以将对象传递给函数,然后在函数中设置对象的属性,然后返回并访问该对象的属性一样,您也可以类似地将数组传递给函数,设置数组的一些值在函数内部,并返回和访问数组外部的这些值。
so in each situation you can ask yourself, "is an array or an object better?"
因此,在每种情况下,您都可以问自己,“数组或对象哪个更好?”
回答by Gooseberry
I am using a callback method (similar to Felix Kling's approach) to simulate the behavior of out parameters. My answer differs from Kling's in that the callback function acts as a reference-capturing closure rather than a handler.
我正在使用回调方法(类似于Felix Kling 的方法)来模拟输出参数的行为。我的回答与 Kling 的不同之处在于回调函数充当引用捕获闭包而不是处理程序。
This approach suffers from JavaScript's verbose anonymous function syntax, but closely reproduces out parameter semantics from other languages.
这种方法受到 JavaScript 冗长的匿名函数语法的影响,但从其他语言中复制了参数语义。
function isLegal(odp, out_error) {
//...
out_error("ODP failed test foo"); // Assign to out parameter.
return false;
}
var error;
var success = isLegal(null, function (e) { error = e; });
// Invariant: error === "ODP failed test foo".
回答by Gooseberry
I'm not going to post any codebut what fails to be done here in these answers is to put rhyme to reason. I'm working in the native JS arena and the problem arose that some native API callsneed to be transformed because we can't write to the parameters without ugly shameful hacks.
我不会发布任何内容,code但在这些答案中未能完成的是将押韵合理化。我在原生 JS 领域工作,出现了一些native API calls需要转换的问题,因为我们无法在没有丑陋可耻的黑客的情况下写入参数。
This is my solution:
这是我的解决方案:
// Functions that return parameter data should be modified to return
// an array whose zeroeth member is the return value, all other values
// are their respective 1-based parameter index.
That doesn't mean define and return every parameter. Only the parameters that recieve output.
这并不意味着定义并返回每个参数。只有接收输出的参数。
The reason for this approach is thus: Multiple return valuesmay be needed for any number of procedures. This creates a situation where objects with named values (that ultimately will not be in sync with the lexical context of all operations), constantlyneed to be memorized in order to appropriately work with the procedure(s).
这种方法的原因是:Multiple return values可能需要任何数量的程序。这产生了(最终不会在所有业务的词汇范围内同步),以命名值对象的情况经常需要为了被记忆与程序(一个或多个)适当的工作。
Using the prescribed method, you only have to know what you called, and where you should be lookingrather than having to know what you are looking for.
使用规定的方法,您只需要知道what you called,where you should be looking而不必知道您在寻找什么。
There is also the advantage that "robust and stupid" alogrithms can be written to wrap around the desired procedure calls to make this operation "more transparent".
还有一个优点是可以编写“健壮和愚蠢”的算法来环绕所需的过程调用,从而使此操作“更加透明”。
It would be wise to use an object, function, or an array(all of which are objects) as a "write-back-output" parameter, but I believe that if any extraneous work must be done, it should be done by the one writing the toolkit to make things easier, or broaden functionality.
使用 an object, function, or an array(所有这些都是对象)作为“回写输出”参数是明智的,但我相信如果必须完成任何无关的工作,应该由编写工具包使事情变得更容易,或扩大功能。
This is a one for all answer for every occaision, that keeps APIslooking the way the should at first look, rather than appearing to be and having every resemblence of a hobble-cobbled weave of spaghetti code tapestry that cannot figure out if it is a definitionor data.
这是一个适用于每个场合的所有答案,它一直APIs在寻找第一眼应该的样子,而不是看起来像意大利面代码挂毯的鹅卵石编织的每一个相似之处,无法弄清楚它是否是一个定义或数据。
Congratulations, and good luck.
恭喜你,祝你好运。
I'm using the webkitgtk3 and interfaceing some native C Library procs. so this proven code sample might at least serve the purpose of illustration.
我正在使用 webkitgtk3 并连接一些本机 C 库过程。所以这个经过验证的代码示例至少可以起到说明的作用。
// ssize_t read(int filedes, void *buf, size_t nbyte)
SeedValue libc_native_io_read (SeedContext ctx, SeedObject function, SeedObject this_object, gsize argument_count, const SeedValue arguments[], SeedException *exception) {
// NOTE: caller is completely responsible for buffering!
/* C CODING LOOK AND FEEL */
if (argument_count != 3) {
seed_make_exception (ctx, exception, xXx_native_params_invalid,
"read expects 3 arguments: filedes, buffer, nbyte: see `man 3 read' for details",
argument_count
); return seed_make_undefined (ctx);
}
gint filedes = seed_value_to_int(ctx, arguments[0], exception);
void *buf = seed_value_to_string(ctx, arguments[1], exception);
size_t nbyte = seed_value_to_ulong(ctx, arguments[2], exception);
SeedValue result[3];
result[0] = seed_value_from_long(ctx, read(filedes, buf, nbyte), exception);
result[2] = seed_value_from_binary_string(ctx, buf, nbyte, exception);
g_free(buf);
return seed_make_array(ctx, result, 3, exception);
}
回答by Dominik Lebar
The following is approach i am using. And this is answer for this question. However code has not been tested.
以下是我正在使用的方法。这是这个问题的答案。但是代码还没有经过测试。
function mineCoords( an_x1, an_y1 ) {
this.x1 = an_x1;
this.y1 = an_y1;
}
function mineTest( an_in_param1, an_in_param2 ) {
// local variables
var lo1 = an_in_param1;
var lo2 = an_in_param2;
// process here lo1 and lo2 and
// store result in lo1, lo2
// set result object
var lo_result = new mineCoords( lo1, lo2 );
return lo_result;
}
var lo_test = mineTest( 16.7, 22.4 );
alert( 'x1 = ' + lo_test.x1.toString() + ', y1 = ' + lo_test.y1.toString() );
回答by Chuck Bajax
The usual approach to the specific use case you outlined in Javascript, and in fact most high level languages, is to rely on Errors (aka exceptions) to let you know when something out of the ordinary has occurred. There's no way to pass a value type (strings, numbers etc) by reference in Javascript.
您在 Javascript 中概述的特定用例的常用方法,实际上是大多数高级语言,是依靠错误(也称为异常)来让您知道何时发生了异常情况。在 Javascript 中无法通过引用传递值类型(字符串、数字等)。
I would just do that. If you really need to feed custom data back to the calling function you can subclass Error.
我会那样做。如果您确实需要将自定义数据反馈给调用函数,您可以将 Error 子类化。
var MyError = function (message, some_other_param)
{
this.message = message;
this.some_other_param = some_other_param;
}
//I don't think you even need to do this, but it makes it nice and official
MyError.prototype = Error;
...
if (something_is_wrong)
throw new MyError('It failed', /* here's a number I made up */ 150);
Catching exceptions is a pain, I know, but then again so is keeping track of references.
我知道,捕捉异常是一件痛苦的事情,但是跟踪引用也是如此。
If you really really need something that approaches the behavior of outvariables, objects are passed by reference by default, and can handily capture data from other scopes--
如果你真的需要一些接近输出变量行为的东西,默认情况下对象是通过引用传递的,并且可以轻松地从其他范围捕获数据——
function use_out (outvar)
{
outvar.message = 'This is my failure';
return false;
}
var container = { message : '' };
var result = use_out(container );
console.log(container.message); ///gives the string above
console.log(result); //false
I think this goes a some ways towards answering your question, but I think your entire approach is broken from the start. Javascript supports so many much more elegant and powerful ways to get multiple values out of a function. Do some reading about generators, closures, hell even callbacks can be nice in certain situations-- look up continuation passing style.
我认为这在某种程度上可以回答您的问题,但我认为您的整个方法从一开始就被打破了。Javascript 支持许多更优雅、更强大的方法来从函数中获取多个值。阅读一些关于生成器、闭包、地狱甚至回调在某些情况下可能很好的阅读——查找延续传递风格。
My point with this whole rant is to encourage anyone reading this to adapt their programming style to the limitations and capabilities of the language they're using, rather than trying to force what they learned from other languages into it.
我对整个咆哮的观点是鼓励任何阅读本文的人根据他们使用的语言的局限性和功能调整他们的编程风格,而不是试图将他们从其他语言中学到的东西强加给它。
(BTW some people strongly recommend against closures because they cause evil side-effects, but I wouldn't listen to them. They're purists. Side effects are almost unavoidable in a lot of applications without a lot of tedious backtracking and stepping around cant-get-there-from-here obstacles. If you need them, keeping them all together in a neat lexical scope rather than scattered across a hellscape of obscure pointers and references sounds a lot better to me)
(顺便说一句,有些人强烈建议不要使用闭包,因为它们会导致邪恶的副作用,但我不会听他们的。他们是纯粹主义者。在许多应用程序中副作用几乎是不可避免的,而无需进行大量繁琐的回溯和踩踏-get-the-from-here 障碍。如果你需要它们,把它们放在一个整洁的词法范围内,而不是分散在晦涩的指针和引用的地狱中,对我来说听起来好多了)

