问题 ES6中的函数参数定义


我确信这是相对简单的,我错过了一些明显的东西。我正在读书 Mozilla的教程 在ES6和他们的 关于解构的章节 包含以下模式:

功能参数定义

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

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

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

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

如果是这样,那么有什么好处呢

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

params是一个对象 urlline,和 column?想法只是强制Javascript在通过显式定义它们时在析构化的上下文中使用时验证函数的参数吗?


1332
2018-06-16 08:56


起源

“一个对象......只要包含所有项目,就可以按任意顺序排列”对象没有订单,并且您不必拥有所有项目。不进行验证或处理。好处是,而不是功能体参考 params.url, params.line, params.column,你可以参考 url, line 和 column 直。 - Barney
@Barney:对象属性没有订单 ES5。 他们 做 在ES6中。 - T.J. Crowder
@ T.J.Crowder是在所有迭代方法中实现的吗? - Barney
@Barney:如果不是,那就太疯狂了。 :-)我认为枚举对象属性的所有内容最终都会调用 [[OwnPropertyKeys]] 要么 [[Enumerate]]。前者是关于秩序的明确的,而后者是根据前者来定义的。当然,获取密钥数组的各种方法, for-in,和 for-of 使用它们。 - T.J. Crowder
@Barney:对不起,我应该说上面的内容适用于没有覆盖迭代器的对象(vis-a-vis) for-of)。例如,数组确定将以索引的数字顺序访问条目,并跳过非条目属性。 - T.J. Crowder


答案:


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

removeBreakpoint, 您可以使用 urlline,和 column 直。解构发生在 removeBreakpoint 用选项对象调用;该对象的匹配属性被解构为单个参数。

是否允许将对象传递给此函数的想法,只要它包含所有项目,即{line:10,column:20,url:'localhost'},该函数可以按任意顺序排列?

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

证明解构的简单例子(实时复制 与ES5翻译 上 巴别塔的REPL):

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

输出:

removeBreakpoint:
网址:网址
行:行
列:列
removeBreakpoint:
网址:网址
行:行
列:未定义

如果是这样,那么有什么好处呢

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

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

句法糖。接受选项对象的新语法更简洁,更具说明性,可自动化常见模式。将它与默认值组合时尤其明显(实时复制):

"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:
网址
这条线
专栏
removeBreakpoint:
网址
这条线
列默认
removeBreakpoint:
网址默认
行默认
列默认

在上面,即使options对象本身也是可选的,这就是最后一次调用的工作原理:

removeBreakpoint();

如果我们没有为options对象本身提供默认值,那么该调用将失败,因为我们正在尝试读取该属性 url 的 undefined。有时候你想要那个,所以你要把整个选项关掉。其他时候你没有。


附注:默认部分选项对象以及单独的整个选项对象的能力导致一个有趣的情况,你可以有 不同 默认值取决于是否给出了选项对象但没有特定选项而没有给出任何选项对象,所有都以声明方式完成: 实时复制

"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 default,bar =用bar给出的选项
3:foo = foo默认值,bar =没有条形的选项
4:foo = foo默认值,bar =根本没有给出选项

15
2018-06-16 09:01