最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Passing additional arguments to function call (lodash) - Stack Overflow

programmeradmin2浏览0评论

Relating to the following mock code (_ relates to the lodash library):

var containerFunction = function () {
    var opts = {data: value};
    _.map(lines, functionForEach);
}

var functionForEach = function (line) {
  Do something for each line passed in from the maps function.
  Need to access opts in this scope.
  return value;
}

The argument line is received from the map function, but what would be the best way of passing the opts argument to the functionForEach function while keeping the rough pattern above (if possible).

I thought something like:

_.map(lines, functionForEach(opts))

or something similar might work but obviously doesn't.

Any suggestions?

Relating to the following mock code (_ relates to the lodash library):

var containerFunction = function () {
    var opts = {data: value};
    _.map(lines, functionForEach);
}

var functionForEach = function (line) {
  Do something for each line passed in from the maps function.
  Need to access opts in this scope.
  return value;
}

The argument line is received from the map function, but what would be the best way of passing the opts argument to the functionForEach function while keeping the rough pattern above (if possible).

I thought something like:

_.map(lines, functionForEach(opts))

or something similar might work but obviously doesn't.

Any suggestions?

Share Improve this question asked Dec 22, 2015 at 16:57 SeonixxSeonixx 4685 silver badges17 bronze badges 6
  • Put functionForEach inside containerFunction. If you must, pass opts as the third context (thisArg) argument to _.map and access it using this inside functionForEach. – user663031 Commented Dec 22, 2015 at 17:00
  • I didn't want to nest the function as I get the impression its frowned upon from a performance and memory perspective. – Seonixx Commented Dec 22, 2015 at 17:06
  • 1 Where did you get such an impression? Even if that were the case, which it's not, the first priority should be getting nice clean code working, then worry about performance. – user663031 Commented Dec 22, 2015 at 17:09
  • I was reading about this earlier. Correct me if I'm wrong, but nested functions result in each nested function being created and destroyed every time the parent function is called. I know it probably doesn't make a lot of difference unless the code is being run on a large scale system, but I'm trying to factor in as many considerations as I go... – Seonixx Commented Dec 22, 2015 at 17:20
  • Today's engine optimizations mean you don't have to worry about such things if in fact they were ever an issue. It's always puzzled me why folks relatively early in their JS learning curve spend so much time worrying about performance questions, most of which are based on urban myths. – user663031 Commented Dec 22, 2015 at 17:21
 |  Show 1 more ment

3 Answers 3

Reset to default 7

You have three alternatives:

  1. Put functionForEach inside containerFunction. If you are not going to use functionForEach elsewhere, this makes the most sense.

  2. Write it as:

    var containerFunction = function () {
      var opts = {data: value};
      _.map(lines, function(elt) { return functionForEach(elt, opts); });
    }
    
    var functionForEach = function (line, opts) {
      Do something for each line passed in from the maps function.
      Need to access opts in this scope.
      return value;
    }  
    
  1. If you must, pass opts as the third (thisArg) argument to _.map and access it using this inside functionForEachvar.

Lodash has good utilities for function position, including partially-applying arguments. However, this isn't actually so straightforward. Let's say we want to use partialRight():

function functionForEach(item, i) { return item * i; }

_.map([1, 2, 3], _.partialRight(functionForEach, 2));
// → [0, 2, 6]

Oops. That's not correct. The reason is that we're not getting the arguments passed to functionForEach() as we expect them. We want the i argument to always have a value of 2 and the item is the mapped collection value.

Let's try something else:

_.map([1, 2, 3], _.ary(_.partialRight(functionForEach, 2), 1));
// → [2, 4, 6]

That's better. The problem is that map() passes the item as the first argument, along with 2 other arguments (the index and the collection itself). Since we don't care about these latter two arguments, we can use ary() to pose a new function that ignores them.

Here's another approach:

_.map([1, 2, 3], _.partial(_.rearg(functionForEach, 1, 0), 2));
// → [2, 4, 6]

This time, we're using rearg() to change the order of our partial() function arguments. This approach I find to be less intuitive than simple going right for partialRight().

One final example:

_.map([1, 2, 3], _.flow(_.identity, _.partialRight(functionForEach, 2)));
// → [2, 4, 6]

Here, we're using the flow() higher-order function to pose our callback. This function takes the arguments supplied to it, and chains together the functions we pass to it - the output of the last function is the input to the next. We're using the identity() function here because it simply returns the first argument passed to it, which is exactly what we want.

This last approach is similar to the ary() approach - it's doing the same thing. The flow() approach is superior if we ever wanted to build on this behavior by passing in more functions, before or after functionForEach().

Take a look at _.partial. Docs:

partial

var containerFunction = function() {
  var opts = { data: value };
  _.map(lines, _.partial(functionForEach, opts));
};

var functionForEach = function (opts, line) { ... };

_.partial returns a new function with the arguments prepended to the functionForEach. In the example above, _.partial returns the following function signature:

function (line) { ... }

Calling the return function with a line calls functionForEach with line and opts defaulted to whatever you passed in as the argument in _.partial.

发布评论

评论列表(0)

  1. 暂无评论