Home  >  Article  >  Web Front-end  >  Underscore source code analysis_javascript skills

Underscore source code analysis_javascript skills

WBOY
WBOYOriginal
2016-05-16 15:22:391425browse

A few years ago, some people said that JavaScript is the most underestimated programming language. Since the emergence of nodejs, the concept of All Stack/Full Stack has become increasingly popular. Now I am afraid no one dares to underestimate it anymore. JavaScript is a C-like language. If you have a C language foundation, you can generally understand the JavaScript code. However, as a scripting language, the flexibility of JavaScript is far less than that of C, which will also cause some difficulties in learning.

1. Gathering

1. The first is several iterative methods.

_.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;
 }; 

ES also adds a native forEach() method to arrays. The difference is that the each(forEach) method here can be used for all collections, and the function accepts three parameters (collection, iteration function, execution environment).

The optimizeCb function binds corresponding execution environments to different iteration methods based on the number of iteration function parameters. The forEach iteration function also accepts three parameters (value, index, set).

The next step is to call the iteration function in the for loop.

A more elegant implementation of isArrayLike judgment in _.map: (only one for loop)

var keys = !isArrayLike(obj) && _.keys(obj),
    length = (keys || obj).length,
    results = Array(length);
  for (var index = 0; index < length; index++) {
   var currentKey = keys &#63; keys[index] : index;
   results[index] = iteratee(obj[currentKey], currentKey, obj);
  }
  return results;
  // 合理使用&&、||、&#63;:可以大大减少代码量 

There are two more special places:

•Divide collections into array-like collections and object collections. The isArrayLike function is used:

// js的最大精确整数
 var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
 var isArrayLike = function(collection) {
var length = collection != null && collection.length;
return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
 }; // 如果集合有Length属性且为数字并且大于0小于最大的精确整数,则判定是类数组

•The _.keys function is used. Object also has a native keys function, which is used to return an array of attributes that can be enumerated by obj. The implementation is relatively simple, for in plus the hasOwnProperty() method.

-------------------------------------------------- ----------------------------------

_.map, _.reduce methods have similar principles.

The _.find function is similar to Array.some(), except that it returns the first element that makes the iteration result true, instead of returning a Boolean value like Array.some().

 _.find = _.detect = function(obj, predicate, context) {
  var key;
  if (isArrayLike(obj)) {
   key = _.findIndex(obj, predicate, context);
  } else {
   key = _.findKey(obj, predicate, context);
  }
  if (key !== void 0 && key !== -1) return obj[key];
 };
function createIndexFinder(dir) {
  return function(array, predicate, context) {
   predicate = cb(predicate, context);
   var length = array != null && array.length;
   // 如果dir为1,index为0,index+=1,index正序循环
   // 如果dir 为-1,index为length-1,index += -1反序循环
   // 判断循环条件则用了index >= 0 && index < length方法兼顾两种循环方式
   var index = dir > 0 &#63; 0 : length - 1;
   for (; index >= 0 && index < length; index += dir) {
    if (predicate(array[index], index, array)) return index;
   }
   return -1;
  };
 }
 _.findIndex = createIndexFinder(1);
 _.findLastIndex = createIndexFinder(-1); 

What is worth learning from is that a for loop here can configure different loop sequences according to different parameters passed in.

1. Other methods in the collection are basically implemented based on iterative methods.

_.max = function(obj, iteratee, context) {
var result = -Infinity, lastComputed = -Infinity,
  value, computed;
if (iteratee == null && obj != null) {
 obj = isArrayLike(obj) &#63; obj : _.values(obj);
 for (var i = 0, length = obj.length; i < length; i++) {
  value = obj[i];
  if (value > result) {
   result = value;
  }
 }
} else {
 iteratee = cb(iteratee, context);
 _.each(obj, function(value, index, list) {
  computed = iteratee(value, index, list);
  if (computed > lastComputed || computed === -Infinity && result === -Infinity) {
   result = value;
   lastComputed = computed;
  }
 });
}
return result;
 }; 

The max method is used to find the maximum value in the set, by looping through all items in the list, and then comparing the current item and the result item. If the current item is greater than the result, it is assigned to the result item, and finally the result item is returned.

2. Convert the collection to an array

 _.toArray = function(obj) {
    if (!obj) return [];
    // 如果是数组,采用了Array.prototype.slice.call(this,obj)这种方法
    if (_.isArray(obj)) return slice.call(obj);
    // 类数组对象,这里没有采用Slice方法,而是利用.map对集合进行迭代,从而返回一个数组。 _.identity该方法传入的值和返回的值相等。(主要用于迭代)
    if (isArrayLike(obj)) return _.map(obj, _.identity);
    // 普通对象,则返回由属性值组成的数组。
    return _.values(obj);
   };

Data Type

STL needs to distinguish vectors, lists, etc. because different data structures require or can be implemented differently, but what is the reason for the separation of Collections and Arrays in underscore? This also starts with the data type of JavaScript, see the picture below.

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn