zoukankan      html  css  js  c++  java
  • underscore源码了解

    参考资料

    js高手进阶之路:underscore源码经典

    underscore源码英文注释文档

    闭包

    整个函数在一个闭包里

    (function() {
    	...
    }).call(this)
    

    jQuery的异曲同工

    (function(window, undefined) {
    	...
    })(window);
    

    原型赋值

    18 var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
    

    将原型赋值给变量有两个好处:

    1、提高性能,减少作用域链长度

    2、便于压缩。变量名压缩时是可以换名字的,但像Array.prototype这样的如果压缩时变名字的话,浏览器就不认识了。

    变量声明格式

    20 var
    nativeIsArray      = Array.isArray,
    nativeKeys         = Object.keys,
    nativeBind         = FuncProto.bind,
    nativeCreate       = Object.create;
    

    这样,省去了多余的var,格式也美观

    数据判断

    _.isElement

    1185 _.isElement = function(obj) {
        return !!(obj && obj.nodeType === 1);
      };
    

    判断是否是domdomnodeType值为1,用!!强制转为boolean值。

    _.isArray

    1200 _.isArray = nativeIsArray || function(obj) {
        return toString.call(obj) === '[object Array]';
      };
    

    判断是否是数组,优先判断是否存在原生函数Array.isArray,这个函数是ES5新增函数,如果没有,则自定义一个函数

    _.isObject

    1194 _.isObject = function(obj) {
        var type = typeof obj;
        return type === 'function' || type === 'object' && !!obj;
    };
    

    判断是否为对象。函数也是对象,需要包含在内;但null也是对象,需要排除,用!!obj区分。

    _.isArguments

    1219 if (!_.isArguments(arguments)) {
    	_.isArguments = function(obj) {
      		return _.has(obj, 'callee');
    	};
    }
    

    判断arguments很简单,arguments对象有个特殊属性callee

    _.isNaN

    1239 _.isNaN = function(obj) {
    	return _.isNumber(obj) && obj !== +obj;
    };
    

    NaN这个值有两个特点:1、它是一个数;2、它不等于自己

    另外,var num = new Number()这种没有值的对象(数字)也归为NaN+obj是为了把var num = new Number()先转为数字(+(new Number())0+{}NaN

    _.isBoolean

    1244   _.isBoolean = function(obj) {
    	return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
    };
    

    判断是否是布尔值,除了truefalse外,也把new Boolean()认为是布尔值

    _.isUndefined

    1254   _.isUndefined = function(obj) {
    	return obj === void 0;
    };
    

    小技巧:用void 0返回undefined

    _.eq

    暂略

    内部函数optimizeCb

    暂略

    _.each_.map

    131 _.each = _.forEach = function(obj, iteratee, context) {
        iteratee = optimizeCb(iteratee, context);
        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;
      };
    
      // Return the results of applying the iteratee to each element.
      _.map = _.collect = function(obj, iteratee, context) {
        iteratee = cb(iteratee, context);
        var keys = !isArrayLike(obj) && _.keys(obj),
            length = (keys || obj).length,
            results = Array(length);
        for (var index = 0; index < length; index++) {
          var currentKey = keys ? keys[index] : index;
          results[index] = iteratee(obj[currentKey], currentKey, obj);
        }
        return results;
      };
    

    能够看出,_.each是“遍历”数组/对象,返回原对象;_.map是“操作”数组/对象,以数组的形式返回结果。

    内部函数createReduce

    161 function createReduce(dir) {
        // Optimized iterator function as using arguments.length
        // in the main function will deoptimize the, see #1991.
        function iterator(obj, iteratee, memo, keys, index, length) {
          for (; index >= 0 && index < length; index += dir) {
            var currentKey = keys ? keys[index] : index;
            memo = iteratee(memo, obj[currentKey], currentKey, obj);
          }
          return memo;
        }
    
        return function(obj, iteratee, memo, context) {
          iteratee = optimizeCb(iteratee, context, 4);
          var keys = !isArrayLike(obj) && _.keys(obj),
              length = (keys || obj).length,
              index = dir > 0 ? 0 : length - 1;
          // Determine the initial value if none is provided.
          if (arguments.length < 3) {
            memo = obj[keys ? keys[index] : index];
            index += dir;
          }
          return iterator(obj, iteratee, memo, keys, index, length);
        };
      }
    

    先不谈功能,这段代码里有几个点可以说下:

    1、 用闭包定义函数。闭包的好处有:避免命名冲突、私有化变量、延长变量生命周期。这里的作用就是“延长变量生命周期”,继续调用函数的时候就不用重新定义函数了。

    2、 两层闭包。目的就是“延长变量生命周期”

    3、 用slice.call(arguments, 2)截取后后面的不定参数。

    254 _.invoke = function(obj, method) {
    
    var args = slice.call(arguments, 2);
    var isFunc = _.isFunction(method);
    return _.map(obj, function(value) {
      var func = isFunc ? method : value[method];
      return func == null ? func : func.apply(value, args);
    });
    };
    

    _.delay

    749 _.delay = function(func, wait) {
        var args = slice.call(arguments, 2);
        return setTimeout(function(){
          return func.apply(null, args);
        }, wait);
      };
    

    把参数缓存起来供延迟函数加载,很好的技巧

    _.after

    861 _.after = function(times, func) {
        return function() {
          if (--times < 1) {
            return func.apply(this, arguments);
          }
        };
      };
    

    同样缓存次数变量,函数多次执行都会访问闭包里的times变量,直到到达上限,再执行闭包里缓存的函数。这个在处理异步请求的时候还是很有用的。

  • 相关阅读:
    ThinkPHP框架基础知识
    ajax分页练习
    实例练习:购物车
    事件
    ajax基础
    jQuery事件
    jQuery基础
    PHP制作登录注册页面
    iview里tree组件改造
    Vue CLI及其vue.config.js(一)
  • 原文地址:https://www.cnblogs.com/yiyang/p/4933006.html
Copyright © 2011-2022 走看看