代码之家  ›  专栏  ›  技术社区  ›  Nick Heiner

如何在JavaScript中最好地实现out参数?

  •  31
  • Nick Heiner  · 技术社区  · 14 年前

    我在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);
    

    在JS中做这种事情的最佳方法是什么?物体?

    function isLegal(odp, errorObj)
    {
        // ...
        errorObj.val = "ODP failed test foo";
        return false;
    }
    

    Firebug告诉我上面的方法是可行的,但是有更好的方法吗?

    9 回复  |  直到 14 年前
        1
  •  42
  •   Pointy    14 年前

    @Felix Kling提到的回调方法可能是最好的主意,但我也发现有时候很容易利用Javascript对象文本语法,让函数返回一个出错的对象:

    function mightFail(param) {
      // ...
      return didThisFail ? { error: true, msg: "Did not work" } : realResult;
    }
    

    然后当您调用函数时:

    var result = mightFail("something");
    if (result.error) alert("It failed: " + result.msg);
    

    不花哨,几乎不防弹,但它当然可以在一些简单的情况下。

        2
  •  16
  •   casablanca    14 年前

    isLegal 就其本身而言,只需这样调用它:

    var error = {};
    isLegal("something", error);
    alert(error.val);
    
        3
  •  15
  •   Felix Kling    14 年前

    我认为这几乎是唯一的方法(但我不是一个铁杆的JavaScript程序员)。

    您还可以考虑使用回调函数:

    function onError(data) {
        // do stuff
    }
    
    
    function isLegal(odp, cb) {
        //...
        if(error) cb(error);
        return false;
    }
    
    isLegal(value, onError);
    
        4
  •  5
  •   Matt    5 年前

    out 关键字)。它们只是一种在出错时返回对象的解决方法。

    但如果你真的需要参数,你会怎么做?

    因为Javascript不直接支持它,所以需要构建一些接近C#out参数的东西。看看这个方法,我在JavaScript中模拟C的DateTime.TryParse函数。out参数是result,因为JavaScript没有提供out关键字,所以我使用 .value MDN suggestion ):

    // 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");
    };

    str 参数,并在 result 参数。请注意 需要初始化为 空数组 [] 之前 你调用函数。这是必需的,因为在函数内部“注入”了 .价值 财产。


    丢弃 参数称为 out _ [] 如下图所示:

    // 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!");

    这个例子使用 结果 传递错误消息的参数如下:

    errorObj.value=“ODP failed test foo”;//返回错误

    注: undefined ,即在功能检查中

    if (result === undefined) { 
       // do the check without passing back a value, i.e. just return true or false 
    };
    

    那么可以省略 结果 作为一个参数,如果不需要的话,可以完全调用它

    if (DateTime.TryParse(odp)) { 
        // ... same code as in the snippet above ...
    };
    
        5
  •  3
  •   Humilulo -- Shawn Kovac    12 年前

    JS还有另一种传递“out”参数的方法。但我相信对你来说最好的已经提到了。

    所以在每一种情况下,你都可以问自己,“一个数组还是一个对象更好?”

        6
  •  2
  •   Community Jaime Torres    7 年前

    我正在使用回调方法(类似于 Felix Kling's approach )以模拟输出参数的行为。我的答案与Kling的不同之处在于,回调函数充当的是引用捕获闭包,而不是处理程序。

    这种方法受到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".
    
        7
  •  1
  •   user735796 user735796    12 年前

    我不会发任何邮件 code 但在这些答案中,我们不能做的是 合情合理 . 我在本地JS竞技场工作,问题是 native API calls 需要改变,因为我们不能写的参数没有丑陋可耻的黑客。

        // 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.
    

    这并不意味着定义并返回每个参数。只有

    因此,采取这种做法的原因是: Multiple return values 可能需要任何数量的程序。这就产生了一个情况,即具有命名值的对象(最终将不会与所有操作的词汇上下文同步), 需要记住,以便适当地使用程序。

    使用规定的方法,你只需要知道 what you called ,和 where you should be looking 必须知道你在找什么 .

    强壮又愚蠢 “可以编写alogrithms来包装所需的过程调用,以使此操作“更透明”。

    使用 object , function ,或 array

    这是一个一劳永逸的答案 APIs 定义 数据 .

    恭喜你,祝你好运。

    我正在使用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);
    
    }
    
        8
  •  1
  •   Dominik Lebar    11 年前

    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() );
    
        9
  •  0
  •   Chuck Bajax    8 年前

    对于您在Javascript中概述的特定用例,以及实际上大多数高级语言,通常的方法是依赖错误(也称为异常)来让您知道何时发生了异常情况。在Javascript中无法通过引用传递值类型(字符串、数字等)。

    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); 
    

    捕捉异常是一件痛苦的事,我知道,但是同样的,跟踪引用也是一件痛苦的事。

    如果你真的需要一些接近 外面的

    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
    

    我认为这有助于回答你的问题,但我认为你的整个方法从一开始就被打破了。Javascript支持许多更加优雅和强大的方法来从函数中获取多个值。阅读一些关于生成器、闭包、hell甚至回调的内容,在某些情况下都是不错的——查看continuation passing样式。

    我的观点是鼓励阅读本文的人根据他们所使用语言的局限性和能力来调整他们的编程风格,而不是试图将他们从其他语言中学到的东西强加于此。

    (顺便说一句,有些人强烈建议不要关闭,因为它们会导致邪恶 副作用