【问题标题】:How to replace closure variables with additional function call arguments to avoid constantly re-creating functions?如何用额外的函数调用参数替换闭包变量以避免不断地重新创建函数?
【发布时间】:2017-10-12 05:40:20
【问题描述】:

给定:

list = [ "one", "something", "other" ];
foo = function () {
    var str = "something", 
        bar = function (el, idx, array) {return el === str;};
    return list.some(bar);
}; 
for (var i = 0; i < 10; i += 1) {
   foo(); // true
}

bar 由 list.some() 调用,带有三个参数。

如果我想在 foo 之外定义 bar ,那么我必须在这样的闭包中给它 str :

list = [ "one", "something", "other" ];
bar = function (str) {
    return function baz(el, idx, array) {return el === str;};
}
foo = function () {
    var str = "something"; 
    return list.some(bar(str));
}; 
for (var i = 0; i < 10; i += 1) {
   foo(); // true
}

因此,每次调用 bar 时,都会在 bar 中创建/定义一个函数 baz。是否可以通过添加额外的来避免闭包和常量函数的重新创建
bar 的 list.some() 调用的参数如下:

list = [ "one", "something", "other" ];
bar = function (el, idx, array, str) {return el === str;};
// Do something to bar's argument list so it's called with more than three arguments?
baz = function (str) {return bar(el, idx, array, str);}; // ????
foo = function () {
    var str = "something";
    return list.some(baz(str));
};
for (var i = 0; i < 10; i += 1) {
   foo(); // true
}

更新:请注意,可以从循环中调用 foo,如上述示例中所示。 是否可以避免重新创建所有函数,使每个函数只创建一次?

我想传递 bar 四个参数(或前三个参数之后的任意数量的参数,比如这个 bar = function (el, idx, array, str, ...)。目标是只创建任何一个函数一次。请不要使用外部库。

【问题讨论】:

  • 顺便说一句,如果在索引零处找到元素,则代码不起作用。
  • 我认为这可以通过函数式编程方法来完成,例如柯里化和函数组合。让我做一些修补,我会告诉你我发现了什么。
  • 请记住,bar 在第二个示例中只调用一次。它返回的函数被一遍又一遍地调用。它只被创建一次。
  • @DonovanM 是的,每次都会重新创建 bar 中的匿名函数。我将帖子编辑为“baz”。这是我想避免的对 baz 的娱乐。
  • @esnm 查看我使用柯里化的解决方案。我想这就是你要找的东西

标签: javascript function arguments


【解决方案1】:

使用 Function.bind 可以将上下文 this 设置为字符串。但是,function.bind 仍然会创建一个新函数。真的,没有函数就没有办法创建闭包。它们相互依赖。

我认为这是最干净的方法:

list = [ "one", "something", "other" ];
bar = function indexAndStringMatch(key) {
    return function (el, idx, array) { return el === key && idx; };
}
foo = (function () {
    var str = "something", 
        foundIt = array.some(bar(str));
}());

【讨论】:

  • 每次调用都创建一个函数。希望避免这种情况(并且不要为此使用“this”)。
  • esnm,绑定也是如此。我是说你不能避免创建一个函数并使用一个闭包。它们本质上是一样的。
  • 这导致了我的要求。是否可以避免闭包,而只需将变量直接添加到函数调用中?
  • 我觉得我在对着墙说话......不不不,他们基本上是平等的。闭包 === 函数。游戏结束 man¯_(ツ)_/¯
  • 相同。关键是不要使用闭包(=== 函数)。而是将所需的变量直接传递给函数。所以不需要关闭。 ;-)
【解决方案2】:

可能是:

var list = [ "one", "something", "other" ];
var bar = function (el, idx, array) { return el === this.str; };
var foo = (function () {
    var str = "something"; 
    return list.some(bar.bind({str}));
}()); 
console.log(foo)

但我不知道我是否真的了解你。

【讨论】:

  • 有效,但取决于“this”。可以添加一个额外的参数吗?
  • 解释为什么这样做。解释传递this 上下文。为什么它需要是一个对象?还能怎么用?等等。
  • @esnm 您可以根据需要向传递到this 上下文的对象添加任意数量的属性。 .bind({str: str, str2: str2 ... etc.})
  • @mhodges。没错,但我想避免“这个”,因为我可能想在另一个上下文中使用它。
  • @esnm 这是我的想法,为什么我没有在 15 分钟前发布这个解决方案哈哈
【解决方案3】:

因此,您可以使用称为Currying (Helpful article) 的函数式编程方法来完成此操作。我认为您可以从技术上说 ramda 在幕后创建另一个函数,这是真的,但是,它定义并返回函数 1 次,而不是每次迭代,我相信这是您的目标。

代码如下所示:

var ramda = R; // alias ramda library from default R for clarity
list = [ "one", "something", "other" ];
var bar = ramda.curry(function (str, el, idx, array) {
    return el === str;
});
var foo = (function (array) {
    var str = "something", 
    // bar(str) creates a function one time that is passed to .some(),
    // rather than for each iteration
    foundIt = array.some(bar(str)); 
    return foundIt;
}(list));

console.log(foo);
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.23.0/ramda.js"&gt;&lt;/script&gt;

请记住,没有必要专门使用 ramda 库,因为您可以使用 vanilla JS 或其他常用库(如 lodash)自己实现柯里化。

根据请求 - 自己在 JS 中 curry 一个函数,它看起来像下面这样:(Copied from this article)

function curry(fx) {
  var arity = fx.length;

  return function f1() {
    var args = Array.prototype.slice.call(arguments, 0);
    if (args.length >= arity) {
      return fx.apply(null, args);
    }
    else {
      return function f2() {
        var args2 = Array.prototype.slice.call(arguments, 0);
        return f1.apply(null, args.concat(args2)); 
      }
    }
  };
}

【讨论】:

  • 如何用 vanilla JS 做到这一点?研究 ramda 如何做到这一点,但更愿意避免使用外部库。此外,创建另一个函数也没问题,只要它只创建一次,而不是每次调用另一个函数。
  • @esnm 为你添加了香草 JS 咖喱 =)
  • @esnm 不完全是。是的,使用了 f1.apply(),但不是您认为的那样。您应该阅读我在帖子中链接的文章(我的网址有误,但我刚刚修复了它),它会很好地解释它。这个想法是它将返回一个新函数,直到满足原始参数长度要求。在这种情况下,它以一个有 4 个参数的函数开始,我们传递给它 1,它返回一个现在需要 3 个参数的函数,然后.some() 传递给它 3,然后它就满足了,所以它继续运行该函数。 ..如果这有意义大声笑
  • @esnm 以下是一些可能有助于理解的示例:repl.it/Hvoa/0
  • 还没有时间完全弄清楚这一点,但我有足够的信心相信这是正确的方法。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-10
  • 2020-10-02
  • 2017-09-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多