iteratee值在哪里/如何实际执行?

时间:2014-10-01 15:26:54

标签: javascript underscore.js

我正在使用Underscore.js扩展我对更复杂的javascript概念的知识和理解,并希望有人可以帮助我理解_.iteratee函数在特定示例中的执行方式。

这是一个例子,到目前为止对我的理解有评论。

我正在使用_.map函数:

_.map({one: 1, two: 2, three: 3}, function(num, key){ return num * 3; });
=> [3, 6, 9]

最底层是正在使用的相关功能,其中一些无关紧要的功能如_.keys被遗漏。

我的理解是:

  1. 在_.map函数中,函数体内iteratee的第一个实例的设置如下:iteratee = _.iteratee(iteratee, context);基于_.iteratee函数(因为函数被传递到_.map)应该评估为createCallback(value, context, argCount)

  2. 下次{_ 1}}变量(现在应该是回调函数)在_.map函数中使用时:iteratee

  3. 这是我迷路的地方。

    问题:

    1. 假设我上面的#1假设确实是正确的,当我们到达循环内的_.map函数的这一行时:results[index] = iteratee(obj[currentKey], currentKey, obj);我们实际调用的是results[index] = iteratee(obj[currentKey], currentKey, obj);。那么createCallback(obj[currentKey], currentKey, obj)是否会传递给createCallback中的obj[currentKey]参数? (似乎没有意义)。

    2. 如果上述情况属实,我在迷失的地方是,func评估createCallback obj的{​​{1}}是createCallback的值argCount }。我不明白createCallback中switch语句的哪一部分被引用。

    3. 在这种情况下调用哪个switch语句?

      如果我有,我应该能够完成对createCallback内部闭包的追踪。我们非常感谢您提供的任何其他信息以指导我。

      感谢。

      功能

      _。地图

        _.map = _.collect = function(obj, iteratee, context) {
          if (obj == null) return [];
          iteratee = _.iteratee(iteratee, context);
          var keys = obj.length !== +obj.length && _.keys(obj),
              length = (keys || obj).length,
              results = Array(length),
              currentKey;
          for (var index = 0; index < length; index++) {
            currentKey = keys ? keys[index] : index;
            results[index] = iteratee(obj[currentKey], currentKey, obj);
          }
          return results;
        };
      

      createCallback的

        var createCallback = function(func, context, argCount) {
          if (context === void 0) return func;
          switch (argCount == null ? 3 : argCount) {
            case 1: return function(value) {
              return func.call(context, value);
            };
            case 2: return function(value, other) {
              return func.call(context, value, other);
            };
            case 3: return function(value, index, collection) {
              return func.call(context, value, index, collection);
            };
            case 4: return function(accumulator, value, index, collection) {
              return func.call(context, accumulator, value, index, collection);
            };
          }
          return function() {
            return func.apply(context, arguments);
          };
        };
      

      _。iteratee

        _.iteratee = function(value, context, argCount) {
          if (value == null) return _.identity;
          if (_.isFunction(value)) return createCallback(value, context, argCount);
          if (_.isObject(value)) return _.matches(value);
          return _.property(value);
        };
      

1 个答案:

答案 0 :(得分:0)

在这一特定行中,

results[index] = iteratee(obj[currentKey], currentKey, obj);

iteratee实际上会像这样被调用

iteratee(<actual value of obj[currentKey]>, currentKey, obj);

因此,obj不会传递给iteratee函数。

在您的情况下,由于您将对象作为第一个参数传递,因此在每次迭代时,results累积行将评估与此类似的内容

results[0] = iteratee(1, "one", obj);
results[1] = iteratee(2, "two", obj);
results[2] = iteratee(3, "three", obj);

iteratee = 当执行此行时,

_.iteratee(iteratee, context);

iteratee实际上是您作为_.map的参数之一传递的函数。由于您未明确传递context对象,因此默认情况下该值为undefined。所以,

if (context === void 0) return func;

签入createCallback函数将评估为true(自undefined == void 0起),您实际传递给_.map的函数将用作回调函数。