【问题标题】:Can we set persistent default parameters which remain set until explicitly changed?我们可以设置持久的默认参数,这些参数在明确更改之前一直保持设置?
【发布时间】:2017-09-13 23:12:39
【问题描述】:

以下是函数fn,其中预期结果是abc 在每次调用fn 时定义,无论是否传递对象参数。如果传递了设置属性的对象,则应仅为该对象设置属性。

const fn = (opts = {a:1, b:2, c:3}) => console.log(opts);

当不带参数调用时,结果是

fn() // {a: 1, b: 2, c: 3}

当带参数调用时,例如{b:7},预期的结果是

fn({b:7}) // {a: 1, b: 7, c: 3}

然而,实际结果是

fn({b:7}) // {b: 7}

能够通过在函数外部定义对象并在函数主体内使用Object.assign()来获得预期结果

const settings = {a: 1, b: 2, c: 3};
const fn = opts => {opts = Object.assign({}, settings, opts); console.log(opts)}
fn({b: 7}) // {a: 1, b: 7, c: 3}
fn(); // {a: 1, b: 2, c: 3}
/*
  // does not log error; does not return expected result
  const fn = (opts = Object.assign({}, settings, opts)) => console.log(opts)
 
*/

是否可以仅使用默认参数来实现上述结果,而不定义要在函数参数外部或函数体内部引用的对象?

【问题讨论】:

  • 我不认为。当您说默认参数值时,您指的是 1 个变量。所以当你传递{b:7} 时,JS 引擎会看到接收到的值并且不会使用默认值。您正在尝试设置参数属性的默认值。
  • @Rajesh 使用两个默认参数开发了一个解决方案,请参阅答案。
  • 请注意,在函数内部声明变量绝对没有错。请不要滥用您的答案中的其他参数。
  • 为什么不干脆做const fn = opts => console.log(Object.assign({a: 1, b: 2, c: 3}, opts); - 根本不需要默认参数?我不确定你的actual problem 是什么。
  • @Bergi 问题和赏金在 OP 很明确。定义一个单一的默认参数,该参数是持久的并保持设置直到更改。如果在函数调用时没有传递参数,则返回默认对象。如果传递的参数与默认参数的属性匹配,则设置该属性的值;如果传递的属性和值未设置为默认参数,则该属性和值设置为默认参数。能够使用两个默认参数来实现要求。赏金是确定是否可以使用单个默认参数来实现要求

标签: javascript ecmascript-6


【解决方案1】:

虽然 OP 的代码使用单个默认参数,但在我们找到或开发仅使用单个参数的程序之前,我们可以利用设置两个默认参数来达到预期的效果。

第一个参数默认为普通对象,在第二个默认参数中,我们将参数标识符从第一个参数传递给Object.assign(),遵循问题中的模式。

我们引用函数fn的第二个参数标识符来获取不带参数调用时的默认参数;当使用第一个参数调用时,其属性设置为在第一个参数和默认参数处传递的对象的属性,前者在结果对象处覆盖后者。

const fn = (__ = {}, opts = Object.assign({}, {a: 1, b: 2, c: 3}, __)) => 
             console.log(opts);

fn();

fn({b: 7});

fn({g: 9, x: 10});

【讨论】:

  • 我猜你不需要__不确定)。您可以直接使用.assign({}, {...}, opts)。另外,据我了解,这更像是一种技巧,我更喜欢使用与您问题中的代码类似的代码。我会创建一个函数parseInput 并在那里处理输入并使用返回值。
  • @Rajesh "我猜你不需要__(虽然不确定)。你可以直接使用.assign({}, {...}, opts)"你能不能创建一个jsfiddle或者plnkr来演示?
  • 我错了。我试过了,它不起作用。我的错。我也会使用this 之类的东西。是的,我理解它的客观意见,因此不回答
  • @Rajesh 是的,这是一种选择;在 OP 上发布了类似的模式。本题探讨仅使用默认参数在函数体内获得预期结果。注意,assign() 的第一个参数可以省略Object.assign({a: 1, b: 2, c: 3}, __)。在第二个参数处传递一个普通对象有一个副作用,返回Object {};在第二个参数处传递一个空字符串返回undefined。宁愿使用单个默认参数来避免上述答案中的模式中的错误。虽然Promise.resolve() 也需要单个参数。
  • 省略第一个参数也会覆盖配置对象。在这种情况下,由于它是一个内联对象,因此不会引起问题,但在实际代码中,如果使用变量而不是内联对象,则会引起问题。
【解决方案2】:

没有

可以做的最好的就是你自己的答案或者这个:

const fn = (default_parameters) => { 
  default_parameters = Object.assign({}, {a: 1, b: 2, c: 3},default_parameters);
  console.log('These are the parameters:');
  console.log(default_parameters);
}

    fn();

    fn({b: 7});

    fn({g: 9, x: 10});

默认参数块仅在未设置值时执行,因此您自己的答案是提供的最佳答案,即使用两个参数

您可以通过创建一个如果执行将失败的代码块并测试传递参数有效(以表明代码块未执行)和测试不传递参数失败(表明代码块只在不传参数时执行)。

这应该清楚地表明任何传递的参数都会阻止默认参数被评估。

    const fn = (default_parameters = (default_parameters = Object.assign({}, {a: 1, b: 2, c: 3},default_parameters))) => { 
      
      console.log('These are the parameters:');
      console.log(default_parameters);
    }

        fn({b: 7});
        
        fn();

        fn({g: 9, x: 10});

【讨论】:

【解决方案3】:

也许我误解了这个问题,但您似乎正在为每个单独的属性寻找默认初始化程序。为此,您必须使用解构:

const fn = ({a = 1, b = 2, c = 3} = {}) => console.log({a, b, c});

如果您想保留任意属性,而不仅仅是您预先知道的属性,您可能会对允许您编写的object rest/spread properties proposal 感兴趣

const fn = ({a = 1, b = 2, c = 3, ...opts} = {}) => console.log({a, b, c, ...opts});

能否将opts 变量作为单个对象引用仅使用默认参数来实现,而无需定义要在函数参数外部或函数体内部引用的对象?

没有。参数声明只能使用(部分)参数初始化变量,并且可能(作为语法糖)在没有或undefined 参数(部分)被传递时使用默认值。他们无法执行无条件计算并创建从结果初始化的变量 - 这是您在此处尝试实现的目标。

你应该为此使用函数体。

【讨论】:

  • 方法未返回预期结果。 fn({b:7, g:9}) // ReferenceError: g is not defined。要求是定义一个包含所有传递参数的变量。如果传递了未在默认参数中定义的属性,则在结果对象中设置该属性;如果定义了属性,则将值设置为传递的值;与 stackoverflow.com/a/43468095 相同,但使用单个默认参数,而不是 Answer 实现的两个参数
  • “否”是一个答案,如果我们找不到使用单个默认参数的可行选项。
  • 你可以继续尝试,也可以把我的回答当成本案专家的意见
  • 我很高兴看到有人不同意我的观点并了解它是如何可能的。在那之前,我坚持我有根据的猜测。
  • @guest271314 使用fn({opts: "busted"}) 调用时不起作用。这也是一个语法错误,因为其余属性必须是模式的最后一个组件
【解决方案4】:

我们可以将fn 设置为一个返回箭头函数表达式的变量。当调用 set abc 和其余参数时,使用新对象的扩展元素引用,调用函数时返回。

const fn = ((...opts) => ({a:1,b:2,c:3, ...opts.pop()}));

let opts = fn();

console.log(opts);

opts = fn({b: 7});

console.log(opts);

opts = fn({g: 9, x: 10});

console.log(opts);

使用剩余元素Object.assign(),展开元素Array.prototype.map(),将不是对象的元素设置为反映数组中元素索引的属性值。

const fn = ((...opts) => Object.assign({a:1,b:2,c:3}, ...opts.map((prop, index) =>
             prop && typeof prop === "object" && !Array.isArray(prop) 
             ? prop 
             : {[index]:prop})) 
           );

let opts = fn([2,3], ...[44, "a", {b:7}, {g:8, z: 9}, null, void 0]);

console.log(opts);

【讨论】:

  • @spacepickle 您在哪个浏览器上尝试javascript at stacksn-ps?
  • @spacepickle 在 chromium 57 上尝试 stacksn-ps,并设置了 --javascript-harmony 标志。
猜你喜欢
  • 2010-12-25
  • 2012-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多