underscore方法使用

underscore中template的用法

可以传对象 data 作为第二个参数给模板 template 来直接呈现, 这样页面会立即呈现而不是返回一个模板函数.

var T = $('#T').html();
b.html(_.template(T, res.result))

当要给模板函数赋值的时候,可以传递一个含有与模板对应属性的data对象 。

template: {
    relation: _.template($('#JT_Relation').html())
}
this.template.relation({relations : res.userRelation})

underscore中判断变量相等源码

  var ObjProto = Object.prototype;
  var nativeKeys = Object.keys;
  var hasEnumBug = !{toString:null}.propertyIsEnumerable('toString');

  //判断类数组
  var isArrayLike = function(collection) {
      var length = getLength(collection);
      return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
  };

  //判断函数
  _.isFunction = function(obj) {
      return typeof obj == 'function' || false;
  };

  // 判断对象
  _.isObject = function(obj) {
      var type = typeof obj;
      return type === 'function' || type === 'object' && !!obj;
  };

  //返回一个包装后的对象
  var _ = function(obj) {
      if (obj instanceof _) return obj;
      if (!(this instanceof _)) return new _(obj);
      this._wrapped = obj;
  };

这里放一个this相关的点

var a= {value:"随意"}
undefined
  var t = function(obj) {
      if (obj instanceof t) {
          console.log("obj instanceof t",this);
      }
      if (!(this instanceof t)) {
          console.log("!(this instanceof t)", this);
      }
      this._wrapped = obj;
      console.log("wrapped", this);
  };

输出的结果是

->t(a)
!(this instanceof t) Window {stop: function, open: function, alert: function, confirm: function, prompt: function…}
wrapped t {_wrapped: Object}

重回主干,继续看判断变量相等用到的方法

  // Shortcut function for checking if an object has a given property directly
  // on itself (in other words, not on a prototype).
  _.has = function(obj, key) {
      return obj != null && hasOwnProperty.call(obj, key);
  };
  _.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex);

为什么不直接使用原生的indexOf呢?createIndexFinder这一层做了什么?一起带着问题往下看


  // Generator function to create the indexOf and lastIndexOf functions
  function createIndexFinder(dir, predicateFind, sortedIndex) {
      return function(array, item, idx) {
          var i = 0,
              length = getLength(array);
          if (typeof idx == 'number') {
              if (dir > 0) {
                  i = idx >= 0 ? idx : Math.max(idx + length, i);
              } else {
                  length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1;
              }
          } else if (sortedIndex && idx && length) {
              idx = sortedIndex(array, item);
              return array[idx] === item ? idx : -1;
          }
          if (item !== item) {
              idx = predicateFind(slice.call(array, i, length), _.isNaN);
              return idx >= 0 ? idx + i : -1;
          }
          for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) {
              if (array[idx] === item) return idx;
          }
          return -1;
      };
  }

可以看到通过createIndexFinder的包装,是的indexOf兼容了,封装后调用更加方便。



  // Retrieve the names of an object's own properties.
  // Delegates to **ECMAScript 5**'s native `Object.keys`
  _.keys = function(obj) {
      if (!_.isObject(obj)) return [];
      if (nativeKeys) return nativeKeys(obj);
      var keys = [];
      for (var key in obj)
          if (_.has(obj, key)) keys.push(key);
          // Ahem, IE < 9.
      if (hasEnumBug) collectNonEnumProps(obj, keys);
      return keys;
  };

    // Retrieve the values of an object's properties.
  _.values = function(obj) {
      var keys = _.keys(obj);
      var length = keys.length;
      var values = Array(length);
      for (var i = 0; i < length; i++) {
          values[i] = obj[keys[i]];
      }
      return values;
  };

  // Determine if the array or object contains a given item (using `===`).
  // Aliased as `includes` and `include`.
  _.contains = _.includes = _.include = function(obj, item, fromIndex, guard) {
      if (!isArrayLike(obj)) obj = _.values(obj);
      if (typeof fromIndex != 'number' || guard) fromIndex = 0;
      return _.indexOf(obj, item, fromIndex) >= 0;
  };


function collectNonEnumProps(obj, keys) {
     var nonEnumIdx = nonEnumerableProps.length;
     var constructor = obj.constructor;
     var proto = (_.isFunction(constructor) && constructor.prototype) || ObjProto;

     // Constructor is a special case.
     var prop = 'constructor';
     if (_.has(obj, prop) && !_.contains(keys, prop)) keys.push(prop);

     while (nonEnumIdx--) {
         prop = nonEnumerableProps[nonEnumIdx];
         if (prop in obj && obj[prop] !== proto[prop] && !_.contains(keys, prop)) {
             keys.push(prop);
         }
     }
 }



  // Internal recursive comparison function for `isEqual`.
  var eq = function(a, b, aStack, bStack) {
      // Identical objects are equal. `0 === -0`, but they aren't identical.
      // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
      if (a === b) return a !== 0 || 1 / a === 1 / b;
      // A strict comparison is necessary because `null == undefined`.
      if (a == null || b == null) return a === b;
      // Unwrap any wrapped objects.
      if (a instanceof _) a = a._wrapped;
      if (b instanceof _) b = b._wrapped;
      // Compare `[[Class]]` names.
      var className = toString.call(a);
      if (className !== toString.call(b)) return false;
      switch (className) {
          // Strings, numbers, regular expressions, dates, and booleans are compared by value.
          case '[object RegExp]':
              // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i')
          case '[object String]':
              // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
              // equivalent to `new String("5")`.
              return '' + a === '' + b;
          case '[object Number]':
              // `NaN`s are equivalent, but non-reflexive.
              // Object(NaN) is equivalent to NaN
              if (+a !== +a) return +b !== +b;
              // An `egal` comparison is performed for other numeric values.
              return +a === 0 ? 1 / +a === 1 / b : +a === +b;
          case '[object Date]':
          case '[object Boolean]':
              // Coerce dates and booleans to numeric primitive values. Dates are compared by their
              // millisecond representations. Note that invalid dates with millisecond representations
              // of `NaN` are not equivalent.
              return +a === +b;
      }

      var areArrays = className === '[object Array]';
      if (!areArrays) {
          if (typeof a != 'object' || typeof b != 'object') return false;

          // Objects with different constructors are not equivalent, but `Object`s or `Array`s
          // from different frames are.
          var aCtor = a.constructor,
              bCtor = b.constructor;
          if (aCtor !== bCtor && !(_.isFunction(aCtor) && aCtor instanceof aCtor &&
                  _.isFunction(bCtor) && bCtor instanceof bCtor) && ('constructor' in a && 'constructor' in b)) {
              return false;
          }
      }
      // Assume equality for cyclic structures. The algorithm for detecting cyclic
      // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.

      // Initializing stack of traversed objects.
      // It's done here since we only need them for objects and arrays comparison.
      aStack = aStack || [];
      bStack = bStack || [];
      var length = aStack.length;
      while (length--) {
          // Linear search. Performance is inversely proportional to the number of
          // unique nested structures.
          if (aStack[length] === a) return bStack[length] === b;
      }

      // Add the first object to the stack of traversed objects.
      aStack.push(a);
      bStack.push(b);

      // Recursively compare objects and arrays.
      if (areArrays) {
          // Compare array lengths to determine if a deep comparison is necessary.
          length = a.length;
          if (length !== b.length) return false;
          // Deep compare the contents, ignoring non-numeric properties.
          while (length--) {
              if (!eq(a[length], b[length], aStack, bStack)) return false;
          }
      } else {
          // Deep compare objects.
          var keys = _.keys(a),
              key;
          length = keys.length;
          // Ensure that both objects contain the same number of properties before comparing deep equality.
          if (_.keys(b).length !== length) return false;
          while (length--) {
              // Deep compare each member
              key = keys[length];
              if (!(_.has(b, key) && eq(a[key], b[key], aStack, bStack))) return false;
          }
      }
      // Remove the first object from the stack of traversed objects.
      aStack.pop();
      bStack.pop();
      return true;
  };

  // Perform a deep comparison to check if two objects are equal.
  export function isEqual(a, b) {
      return eq(a, b);
  };
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值