【问题标题】:Function parameter definitions in ES6ES6 中的函数参数定义
【发布时间】:2015-09-01 00:00:47
【问题描述】:

我确信这相对简单,而且我缺少一些明显的东西。我正在阅读 ES6 上的 Mozilla's tutorials,他们的 chapter on destructuring 包含以下模式:

功能参数定义

作为开发人员,我们通常可以通过接受 具有多个属性的单个对象作为参数而不是 迫使我们的 API 消费者记住许多个人的顺序 参数。我们可以使用解构来避免重复这个单一的 每当我们想要引用其属性之一时,参数对象:

function removeBreakpoint({ url, line, column }) {   
    // ... 
}

这是来自 Firefox DevTools 的真实世界代码的简化 sn-p JavaScript 调试器(也在 JavaScript 中实现——yo dawg)。 我们发现这种模式特别令人愉悦。

我不明白这与解构有何关系。您是否允许将对象传递给此函数,只要它包含所有项目,即{ line: 10, column: 20, url: 'localhost' },它就可以按任意顺序传递?

如果是这样,与类似的东西相比有什么好处

 function removeBreakpoint(params) {   
     // ... 
 }

其中 params 是具有 urllinecolumn 的对象?这个想法是否只是通过显式定义它们来强制 Javascript 在解构上下文中使用时验证函数的参数?

【问题讨论】:

  • "一个对象……只要它包含所有项目,就可以按任意顺序排列" 对象没有顺序,您不必拥有所有项目。不进行验证或处理。好处是可以直接引用urllinecolumn,而不是函数体引用params.urlparams.lineparams.column
  • @Barney:ES5 中的对象属性没有顺序。 They do in ES6.
  • @T.J.Crowder 这在所有迭代方法中都实现了吗?
  • @Barney:如果不是这样,那就太疯狂了。 :-) 我认为枚举对象属性的所有内容最终都会调用[[OwnPropertyKeys]][[Enumerate]]。前者是明确的顺序,后者是根据前者定义的。当然,获取键数组的各种方法for-infor-of 都使用它们。
  • @Barney:对不起,我应该说以上适用于不覆盖其迭代器的对象(相对于for-of)。例如,数组确实定义条目将按其索引的数字顺序访问,并且跳过非条目属性。

标签: javascript ecmascript-6 ecmascript-harmony


【解决方案1】:

我不明白这与解构有何关系。

removeBreakpoint内,您可以直接使用urllinecolumn。当使用选项对象调用removeBreakpoint 时会发生解构;该对象的匹配属性被分解为单独的参数。

你是否允许将一个对象传递给这个函数,只要它包含所有项目,就可以任意顺序,即{ line: 10, column: 20, url: 'localhost' }?

是的,但它不必包含所有项目;如果不是,那么由于参数是从不存在的对象属性初始化的,所以参数是undefined(除非指定了默认值)。

演示解构的简单示例(Babel 的 REPL 上的Live Copy with ES5 translation):

"use strict";
function removeBreakpoint({ url, line, column }) {   
    console.log("removeBreakpoint:");
    console.log("url: " + url);
    console.log("line: " + line);
    console.log("column: " + column);
}
removeBreakpoint({
  url: "the url",
  line: "the line",
  column: "the column"
});
removeBreakpoint({
  url: "the url",
  line: "the line"
});

输出:

删除断点: 网址:网址 线:线 列:列 删除断点: 网址:网址 线:线 列:未定义

如果是这样,比之类的有什么好处

function removeBreakpoint(params) {   
   // ... 
}

params 是一个包含 url、line 和 column 的对象?

语法糖。接受选项对象的新语法更加简洁和声明性,自动化了一个常见的模式。当您将其与默认值 (Live Copy) 结合使用时,这一点尤其明显:

"use strict";
function removeBreakpoint(
    {                               // <= { starts destructuring arg
        url = "url default",        // <= Default for `url`
        line = "line default",      // <= ...for `line`
        column = "column default"   // <= ...for `column`
    }                               // <= } ends destructuring arg
    = {}                            // <= Default for the options object iself
) {                                 //    (see notes after the code block)
    console.log("removeBreakpoint:");
    console.log(url);
    console.log(line);
    console.log(column);
}
removeBreakpoint({
  url: "the url",
  line: "the line",
  column: "the column"
});
removeBreakpoint({
  url: "the url",
  line: "the line"
});
removeBreakpoint();

输出:

删除断点: 网址 线 列 删除断点: 网址 线 列默认值 删除断点: 网址默认 线路默认 列默认值

在上面,甚至选项对象本身都是可选的,这就是最后一次调用有效的原因:

removeBreakpoint();

如果我们没有为选项对象本身提供默认值,那么该调用将失败,因为我们将尝试读取 undefined 的属性 url。有时你想要这样,所以你会放弃整体选项。其他时候你不这样做。


旁注:默认选项对象的部分以及单独的整个选项对象的能力会导致一个有趣的情况,您可以根据是否给出选项对象来拥有不同的默认值但没有特定的选项与根本没有给出选项对象,所有这些都是以声明方式完成的:Live Copy

"use strict";
function test(
    num,
    {
        foo = "foo default",
        bar = "options given without bar"
    } = {bar: "options not given at all"}
) {
    console.log(num + ": foo = " + foo + ", bar = " + bar);
}
test(1, {foo: "foo value", bar: "options given with bar"});
test(2, {bar: "options given with bar"});
test(3, {});
test(4);

输出:

1: foo = foo 值,bar = 用 bar 给出的选项 2: foo = foo 默认值,bar = bar 给出的选项 3: foo = foo 默认值,bar = 不带 bar 的选项 4: foo = foo 默认值,bar = 根本没有给出选项

【讨论】:

    猜你喜欢
    • 2021-12-11
    • 1970-01-01
    • 2017-03-26
    • 1970-01-01
    • 1970-01-01
    • 2019-08-07
    • 2016-05-24
    • 2011-09-25
    • 2017-09-14
    相关资源
    最近更新 更多