underscore源碼學習(三)

函數

  1. 首先是不少地方用到的原型繼承。
var baseCreate = function(prototype) {
    if (!_.isObject(prototype)) return {};
    if (nativeCreate) return nativeCreate(prototype);
    Ctor.prototype = prototype;
    var result = new Ctor;
    Ctor.prototype = null;
    return result;
};

首先檢測原生的Object.create是否存在,不存在就借用一個空的構造函數來實現原型繼承。app

  1. 函數綁定
// 執行綁定函數
var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) {
    if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args);
    var self = baseCreate(sourceFunc.prototype);
    var result = sourceFunc.apply(self, args);
    if (_.isObject(result)) return result;
    return self;
};

sourceFunc是須要綁定的函數,boundFunc是綁定函數,context是綁定的做用域,callingContext是函數的現有做用域。首先判斷現有做用域是不是綁定函數的實例,若是不是的話,就用普通的apply實現綁定便可,不然則把函數綁定在原型做用域中。函數

  1. 函數節流
_.throttle = function(func, wait, options) {
  var context, args, result;
  var timeout = null;
  var previous = 0;
  if (!options) options = {};
  var later = function() {
    previous = options.leading === false ? 0 : _.now();
    // 清除timeout
    timeout = null;
    // 執行函數
    result = func.apply(context, args);
    if (!timeout) context = args = null;
  };
  return function() {
    var now = _.now();
    // 若是不是第一次執行,或者leading爲true,則previous與Now不相等,則計算剩餘時間
    // 若是leading爲false,且第一次執行,此時(previous == 0),則reamaining等於wait,第一次執行func,必須在wait時間後。
    if (!previous && options.leading === false) previous = now;
    var remaining = wait - (now - previous);
    context = this;
    args = arguments;
    // 若是剩餘時間小於0,或者大於傳入的等待時間,則當即執行func
    if (remaining <= 0 || remaining > wait) {
      if (timeout) {
        clearTimeout(timeout);
        timeout = null;
      }
      previous = now;
      result = func.apply(context, args);
      if (!timeout) context = args = null;
      // 不然若是trailing爲true時則等待remaining後執行func,
      // 若是trailling爲false,則最後一次不會被執行。
    } else if (!timeout && options.trailing !== false) {
      timeout = setTimeout(later, remaining);
    }
    return result;
  };
};

該函數用於一個函數頻繁觸發時(如scroll事件函數,mousemove函數),對函數進行節流控制,至少每隔 wait毫秒調用一次該函數。有兩個能夠配置的參數,若是你想禁用第一次首先執行的話,傳遞{leading: false},還有若是你想禁用最後一次執行的話,傳遞{trailing: false}。this

  1. 防反跳函數----debounce函數
_.debounce = function(func, wait, immediate) {
    var timeout, args, context, timestamp, result;

    var later = function() {
      // 計算持續的時間
      var last = _.now() - timestamp;
      // 若是持續的事件小於wait的時間,則計算剩餘時間後執行本函數
      if (last < wait && last >= 0) {
        timeout = setTimeout(later, wait - last);
      } else {
      // 不然情空timeout
        timeout = null;
        if (!immediate) {
          result = func.apply(context, args);
          if (!timeout) context = args = null;
        }
      }
    };

    return function() {
      context = this;
      args = arguments;
      timestamp = _.now();
      // 若是傳入了當即執行,則callNow爲true,當即執行func
      var callNow = immediate && !timeout;
      // 設置wait後執行Later函數
      if (!timeout) timeout = setTimeout(later, wait);
      // 當即執行func
      if (callNow) {
        result = func.apply(context, args);
        context = args = null;
      }

      return result;
    };
};

該函數經常使用避免用戶頻繁改變操做時,函數的運行次數過多,致使用戶中止操做時,函數任然在運行。例如window.resize觸發執行對元素的位置的從新計算,運用debounce函數能夠再用戶徹底中止操做後(函數的最後一次調用時刻的wait毫秒以後),在真正的執行該函數。prototype

相關文章
相關標籤/搜索