Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

underscore中optimizeCb优化函数 #4

Open
xlshen opened this issue Mar 15, 2018 · 0 comments
Open

underscore中optimizeCb优化函数 #4

xlshen opened this issue Mar 15, 2018 · 0 comments
Assignees
Labels
enhancement New feature or request

Comments

@xlshen
Copy link
Owner

xlshen commented Mar 15, 2018

underscore中optimizeCb优化函数

optimizeCb内部优化函数接收参数:原始函数、执行上下文、参数个数。
【注:为什么说是内部优化函数,具体可以参考最下方参考文献详解:Why is call so much faster than apply?
简而言之就是callapply快的原因就是在call内部执行中,内部处理所需要的参数都是格式化好的参数,不用特殊处理。
optimizeCb源码:

  // Internal function that returns an efficient (for current engines) version
  // of the passed-in callback, to be repeatedly applied in other Underscore
  // functions.
  // 内部优化方法,参数:函数,执行上下文,参数个数
  // 返回根据传入函数在不同执行上下文,不同参数个数的情况下执行的函数
  var optimizeCb = function(func, context, argCount) {
      // 如果没有指定执行上下文,返回该函数
      if (context === void 0) return func;
      switch (argCount) {
          case 1:
              return function(value) {
                  return func.call(context, value);
              };
              // The 2-parameter case has been omitted only because no current consumers made use of it.
              // 针对下面的null的问题,已经在github提交了pull request(https://github.com/jashkenas/underscore/pull/2732),我认为应该是undefined而非null,具体在下面分析中会提到
          // case void 0:
          case null:
              // 在执行上下文中,没有参数个数,执行下面
              // 在undefined情况下_.each(), _.map()内部用到
          case 3:
              return function(value, index, collection) {
                  return func.call(context, value, index, collection);
              };
              // _.reduce(), _.reduceRight()
          case 4:
              return function(accumulator, value, index, collection) {
                  return func.call(context, accumulator, value, index, collection);
              };
      }
      // 其实不用上面的 switch-case 语句,直接执行下面的 return 函数就行了
      // 理由就是充分利用了call的参数格式化优化
      return function() {
          return func.apply(context, arguments);
      };
  };

实例:

  // _.each()方法在内部调用时首先进行的就是optimizeCb()方法的优化,把_.each()方法源码放到下面
  _.each([1, 2, 3], function(value, index){
    console.log(value, index); // 1, 2, 3
  }, this);
  // _.each()方法源码
  _.each = _.forEach = function(obj, iteratee, context) {
      // 执行函数分发优化策略,即前面的optimizeCb函数,赋值给局部变量iteratee进行代理执行
      iteratee = optimizeCb(iteratee, context);
      // 执行闭包iteratee方法
      var i, length;
      if (isArrayLike(obj)) {
          // 如果是类数组对象
          for (i = 0, length = obj.length; i < length; i++) {
              iteratee(obj[i], i, obj);
          }
      } else {
          // 普通对象
          var keys = _.keys(obj);
          for (i = 0, length = keys.length; i < length; i++) {
              iteratee(obj[keys[i]], keys[i], obj);
          }
      }
      // 返回该对象,链式操作使用
      return obj;
  };

解析:

对于_.each()方法,案例中的contextwindow对象,argCountundefined,如果此处按照null的话则直接执行最后通用返回调用,不会进入case 3的情况,但按照该优化函数设立目的应该是要进入该条件执行,可以参考1.8.2版本[optimizeCb] Combine null and 3 as multi-case for argCount switch statement #2613,已提交pull requestundefined【大家觉得呢???】
按这样理解则执行

  // iteratee(obj[i], i, obj);
  return function(value, index, collection) {
      // context == window,value是每个值,index是索引,collection是传入的数组本身,返回函数执行结果
      return func.call(context, value, index, collection);
  };

总结一下:optimizeCb是针对underscore内部参数确定方法的分类优化函数,原理就是call && apply执行调用

【参考文献】

@xlshen xlshen self-assigned this Mar 15, 2018
@xlshen xlshen added the enhancement New feature or request label Mar 15, 2018
@xlshen xlshen assigned xlshen and unassigned xlshen Mar 15, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant