讀underscore

最近在拜讀只有1700行(含註釋)代碼的Underscore.js 1.9.1,記錄一些東西node

(參考https://underscorejs.org/underscore.jshttps://github.com/hanzichi/underscore-analysisgit

  1. void 0替代了undefined;由於在低版本ie中undefined能夠被從新賦值,或者在局部做用域中也能夠被從新賦值;因此undefined顯得不那麼靠譜,因而就用void 0替代了undefined,void運算符對錶達式求值都會返回undefined;
  2. 數據類型判斷,先看原聲方法支持與否,不支持再用Object.prototype.toString.call方法進行判斷;不過在 IE < 9 下對 arguments 調用 Object.prototype.toString.call,結果是 [object Object],這時能夠用arguments.callee是否存在來判斷;dom元素判斷方法爲存在且nodeType爲1;
  3. 若是在對象中重寫了原型上的不可枚舉屬性,那麼for in是能夠取到這個屬性的;可是在低版本ie中是不會取到的,它們會被認定爲不可枚舉屬性;能夠用obj.propertyIsEnumerable(prop)來肯定對象中指定的屬性是否能夠被for in循環枚舉,可是經過原型鏈繼承的屬性除外;
  4. createAssigner(補)
  5. 判斷是否相同(注意0 === -0,但不相同)
    /* 1 */
    if (a === b) return a !== 0 || 1 / a === 1 / b;
    
    /* 2 null undefined */
    if (a == null || b == null) return false;
    
    /* 3 NaN */
    if (a !== a) return b !== b;
    
    /* 4 primitive */
    var type = typeof a;
    if (type !== 'function' && type !== 'object' && typeof b != 'object') return false;
    
    /* 5 正則 和 String */
    return '' + a === '' + b;
    
    /* 6 Number */
    if (+a !== +a) return +b !== +b;
    return +a === 0 ? 1 / +a === 1 / b : +a === +b;
    
    /* 7 Date Boolean */
    return +a === +b;
    
    /* 8 Symbol */
    var SymbolProto = typeof Symbol !== 'undefined' ? Symbol.prototype : null;
    return SymbolProto.valueOf.call(a) === SymbolProto.valueOf.call(b);
  6. Object Functions(補)github

  7. 位運算符&換算成二進制後按位與計算;不一樣於&&;
    // 判斷偶數
    var isEven = function(num) {
      return !(num & 1);
    };
  8. 數組去重數組

    /* 1 一一比較 */
    function removeSame(arr){
      return arr.filter(function(item, index, arr){
        return arr.indexOf(item) === index;
      });
    }
    
    /* 2 */
    [...new Set(arr)]
    
    /* 3 */
    Array.from(new Set(arr));
  9. flatten
    // shallow爲false深度展開,當shallow strict都爲true可忽略非數組元素
    
    var flatten = function(input, shallow, strict, output) {
      output = output || [];
      var idx = output.length;
      for (var i = 0, length = getLength(input); i < length; i++) {
        var value = input[i];
        if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) {
          if (shallow) {
            var j = 0, len = value.length;
            while (j < len) output[idx++] = value[j++];
          } else {
            flatten(value, shallow, strict, output);
            idx = output.length;
          }
        } else if (!strict) {
          output[idx++] = value;
        }
      }
      return output;
    };
  10. _.compact _.difference  _.without(補)app

  11. NaN和Number.NaN是同樣的;只有Number.isNaN(NaN)才返回true,isNaN()會將參數現轉換爲數字類型;
    isNaN = function(obj) {
        Number.isNaN(Number(obj));
    }
    
    Number.isNaN = Number.isNaN || function(obj) {
        return typeof obj === "number" && isNaN(obj);
    }
    
    _.isNaN = function(obj) {
      return _.isNumber(obj) && isNaN(obj);
    };
  12. 類數組轉爲數組
    Array.prototype.slice.call(obj) 或 Array.from(obj)
    // 優化(傳遞arguments給任何參數,將致使Chrome和Node中使用的V8引擎跳過對其的優化,這也將使性能至關慢)
    
    var args = new Array(arguments.length);
    for(var i = 0; i < args.length; ++i) {
      args[i] = arguments[i];
    }
  13. 數組亂序
    /* 1 O(n^2)*/
    function shuffle(arr) {
      var result = [];
      while (arr.length) {
        var index = ~~(Math.random() * arr.length); // 兩次按位取反,不管正負,去掉小數點後面的數
        result.push(arr[index]);
        arr.splice(index, 1);
      }
      return result;
    }
    
    /* 2 O(nlogn)*/
    function shuffle(arr) {
      return arr.sort(function(a, b) {
        return Math.random() - 0.5;
      });
    }
    
    /* 3 Fisher–Yates Shuffle 遍歷數組 將其與以前的元素交換 O(n)*/
    function shuffle(arr){
      var len = arr.length;
      var shuffled = Array(len);
      for(var i=0, rand; i < len; i++){
        rand = ~~(Math.random()*(i+1));
        if(rand !== i){
          shuffled[i] = shuffled[rand];
        }
        shuffled[rand] = arr[i];
      }
      return shuffled;
    }
  14. Group(補)
  15. bind polyfill
    if (!Function.prototype.bind) {
      Function.prototype.bind = function(oThis) {
        if (typeof this !== 'function') {
          // closest thing possible to the ECMAScript 5
          // internal IsCallable function
          throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
        }
        var aArgs   = Array.prototype.slice.call(arguments, 1),
            fToBind = this,
            fNOP    = function() {},
            fBound  = function() {
              return fToBind.apply(this instanceof fNOP
                     ? this
                     : oThis,
                     // 獲取調用時(fBound)的傳參.bind 返回的函數入參每每是這麼傳遞的
                     aArgs.concat(Array.prototype.slice.call(arguments)));
            };
        // 維護原型關係
        if (this.prototype) {
          // Function.prototype doesn't have a prototype property
          fNOP.prototype = this.prototype; 
        }
        fBound.prototype = new fNOP();
        return fBound;
      };
    }
  16. 節流
    _.throttle = function(func, wait, options) {
        var timeout, context, args, result;
        var previous = 0;
        if (!options) options = {};
    
        var later = function() {
          previous = options.leading === false ? 0 : _.now();
          timeout = null;
          result = func.apply(context, args);
          if (!timeout) context = args = null;
        };
    
        var throttled = function() {
          var now = _.now();
          if (!previous && options.leading === false) previous = now;
          var remaining = wait - (now - previous);
          context = this;
          args = arguments;
          if (remaining <= 0 || remaining > wait) {
            if (timeout) {
              clearTimeout(timeout);
              timeout = null;
            }
            previous = now;
            result = func.apply(context, args);
            if (!timeout) context = args = null;
          } else if (!timeout && options.trailing !== false) {
            timeout = setTimeout(later, remaining);
          }
          return result;
        };
    
        throttled.cancel = function() {
          clearTimeout(timeout);
          previous = 0;
          timeout = context = args = null;
        };
    
        return throttled;
      };
  17. 防抖
     _.debounce = function(func, wait, immediate) {
        var timeout, result;
    
        var later = function(context, args) {
          timeout = null;
          if (args) result = func.apply(context, args);
        };
    
        var debounced = restArguments(function(args) {
          if (timeout) clearTimeout(timeout);
          if (immediate) {
            var callNow = !timeout;
            timeout = setTimeout(later, wait);
            if (callNow) result = func.apply(this, args);
          } else {
            timeout = _.delay(later, wait, this, args);
          }
    
          return result;
        });
    
        debounced.cancel = function() {
          clearTimeout(timeout);
          timeout = null;
        };
    
        return debounced;
      };
相關文章
相關標籤/搜索