Home >Web Front-end >JS Tutorial >Underscore.js 1.3.3 Chinese annotation translation instructions_Basic knowledge

Underscore.js 1.3.3 Chinese annotation translation instructions_Basic knowledge

WBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWB
WBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOriginal
2016-05-16 15:52:541449browse
// Underscore.js 1.3.3

// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.

// Underscore is freely distributable under the MIT license.

// Portions of Underscore are inspired or borrowed from Prototype,

// Oliver Steele's Functional, and John Resig's Micro-Templating.

// For all details and documentation:

// http://documentcloud.github.com/underscore

(function() {

 

  // Create a global object, represented as a window object in the browser and a global object in Node.js

  var root = this;

 

  //Save the value before "_" (underscore variable) is overwritten

  // If there is a naming conflict or considering the specification, the _.noConflict() method can be used to restore the value of "_" before it was occupied by Underscore, and return the Underscore object for renaming

  var previousUnderscore = root._;

 

  //Create an empty object constant for internal sharing and use

  var breaker = {};

 

  //Cache the prototype chain of the built-in object in a local variable to facilitate quick calling

  var ArrayProto = Array.prototype, //

  ObjProto = Object.prototype, //

  FuncProto = Function.prototype;

 

  //Cache common methods in built-in object prototypes in local variables for quick calling

  var slice = ArrayProto.slice, //

  unshift = ArrayProto.unshift, //

  toString = ObjProto.toString, //

  hasOwnProperty = ObjProto.hasOwnProperty;

 

  // This defines some new methods provided by JavaScript 1.6

  // If the host environment supports these methods, they will be called first. If the host environment does not provide them, they will be implemented by Underscore.

  var nativeForEach = ArrayProto.forEach, //

  nativeMap = ArrayProto.map, //

  nativeReduce = ArrayProto.reduce, //

  nativeReduceRight = ArrayProto.reduceRight, //

  nativeFilter = ArrayProto.filter, //

  nativeEvery = ArrayProto.every, //

  nativeSome = ArrayProto.some, //

  nativeIndexOf = ArrayProto.indexOf, //

  nativeLastIndexOf = ArrayProto.lastIndexOf, //

  nativeIsArray = Array.isArray, //

  nativeKeys = Object.keys, //

  nativeBind = FuncProto.bind;

 

  // Create an object-style calling method, which will return an Underscore wrapper. The prototype of the wrapper object contains all methods of Underscore (similar to wrapping a DOM object into a jQuery object)

  var _ = function(obj) {

    // All Underscore objects are constructed internally through wrapper objects

    return new wrapper(obj);

  };

  // For different host environments, store Undersocre's named variables in different objects.

  if( typeof exports !== 'undefined') {// Node.js environment

    if( typeof module !== 'undefined' && module.exports) {

      exports = module.exports = _;

    }

    exports._ = _;

  } else {//The named variable of Underscore in the browser environment is hung in the window object

    root['_'] = _;

  }

 

  // version statement

  _.VERSION = '1.3.3';

 

  // Collection-related methods (general processing methods for data and objects)

  //--------------------

 

  // Iterate the processor and execute the processor method on each element in the collection

  var each = _.each = _.forEach = function(obj, iterator, context) {

    //Do not handle null values

    if(obj == null)

      return;

    if(nativeForEach && obj.forEach === nativeForEach) {

      // If the host environment supports it, the forEach method provided by JavaScript 1.6 will be called first.

      obj.forEach(iterator, context);

    } else if(obj.length === obj.length) {

      //Execute the processor method for each element in the <array>

      for(var i = 0, l = obj.length; i 

      for(var key in obj) {

        if(_.has(obj, key)) {

          if(iterator.call(context, obj[key], key, obj) === breaker)

            return;

        }

      }

    }

  };

  // Iteration processor, the difference from each method is that map will store the return value of each iteration and return it as a new array

  _.map = _.collect = function(obj, iterator, context) {

    //Array used to store return values

    var results = [];

    if(obj == null)

      return results;

    // Prioritize calling the map method provided by the host environment

    if(nativeMap && obj.map === nativeMap)

      return obj.map(iterator, context);

    // Iterate through the elements in the collection

    each(obj, function(value, index, list) {

      // Store the return value of each iteration into the results array

      results[results.length] = iterator.call(context, value, index, list);

    });

    //Return processing results

    if(obj.length === obj.length)

      results.length = obj.length;

    return results;

  };

  // Put each element in the collection into the iteration processor, and pass the return value of this iteration as "memo" to the next iteration, generally used to accumulate results or connect data

  _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {

    // Check whether there is an initial value by the number of parameters

    var initial = arguments.length > 2;

    if(obj == null)

      obj = [];

    // Prioritize calling the reduce method provided by the host environment

    if(nativeReduce && obj.reduce === nativeReduce && false) {

      if(context)

        iterator = _.bind(iterator, context);

      return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);

    }

    // Iterate through the elements in the collection

    each(obj, function(value, index, list) {

      if(!initial) {

        // If there is no initial value, the first element is used as the initial value; if the object collection is processed, the default value is the value of the first attribute

        memo = value;

        initial = true;

      } else {

        // Record the processing results and pass the results to the next iteration

        memo = iterator.call(context, memo, value, index, list);

      }

    });

    if(!initial)

      throw new TypeError('Reduce of empty array with no initial value');

    return memo;

  };

  // Similar to reduce, it will iterate the elements in the collection in reverse direction (that is, starting from the last element to the first element)

  _.reduceRight = _.foldr = function(obj, iterator, memo, context) {

    var initial = arguments.length > 2;

    if(obj == null)

      obj = [];

    // Prioritize calling the reduceRight method provided by the host environment

    if(nativeReduceRight && obj.reduceRight === nativeReduceRight) {

      if(context)

        iterator = _.bind(iterator, context);

      return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);

    }

    //Reverse the order of elements in the collection

    var reversed = _.toArray(obj).reverse();

    if(context && !initial)

      iterator = _.bind(iterator, context);

    //Process data through reduce method

    return initial ? _.reduce(reversed, iterator, memo, context) : _.reduce(reversed, iterator);

  };

  // Traverse the elements in the collection and return the first element that can pass the processor verification

  _.find = _.detect = function(obj, iterator, context) {

    // result stores the first element that can pass verification

    var result;

    // Traverse the data through the any method and record the elements that pass verification

    // (If you are checking the processor return status during iteration, it would be more appropriate to use the each method here)

    any(obj, function(value, index, list) {

      // If the result returned by the processor is converted to Boolean type and the value is true, then the current element is recorded and returned

      if(iterator.call(context, value, index, list)) {

        result = value;

        return true;

      }

    });

    return result;

  };

  // Similar to the find method, but the filter method will record all verified elements in the collection

  _.filter = _.select = function(obj, iterator, context) {

    // Used to store an array of elements that pass validation

    var results = [];

    if(obj == null)

      return results;

    // Give priority to calling the filter method provided by the host environment

    if(nativeFilter && obj.filter === nativeFilter)

      return obj.filter(iterator, context);

    // Iterate over the elements in the collection and put the elements verified by the processor into the array and return

    each(obj, function(value, index, list) {

      if(iterator.call(context, value, index, list))

        results[results.length] = value;

    });

    return results;

  };

  // The opposite effect of the filter method, that is, returning a list of elements that have not passed the processor verification

  _.reject = function(obj, iterator, context) {

    var results = [];

    if(obj == null)

      return results;

    each(obj, function(value, index, list) {

      if(!iterator.call(context, value, index, list))

        results[results.length] = value;

    });

    return results;

  };

  //If all elements in the collection can pass the processor verification, return true

  _.every = _.all = function(obj, iterator, context) {

    var result = true;

    if(obj == null)

      return result;

    // Give priority to calling every method provided by the host environment

    if(nativeEvery && obj.every === nativeEvery)

      return obj.every(iterator, context);

    //Iterate over the elements in the collection

    each(obj, function(value, index, list) {

      // This is understood as result = (result && iterator.call(context, value, index, list))

      // Verify whether the result of the processor is a true value after being converted to Boolean type

      if(!( result = result && iterator.call(context, value, index, list)))

        return breaker;

    });

    return !!result;

  };

  // Check whether any element in the collection has a true value when it is converted to a Boolean type? Or whether it has a true value after being processed by the processor?

  var any = _.some = _.any = function(obj, iterator, context) {

    // If no processor parameters are specified, the default processor function will return the element itself, and determine whether it is a true value by converting the element to a Boolean type during iteration

    iterator || ( iterator = _.identity);

    var result = false;

    if(obj == null)

      return result;

    // Give priority to calling some methods provided by the host environment

    if(nativeSome && obj.some === nativeSome)

      return obj.some(iterator, context);

    //Iterate over the elements in the collection

    each(obj, function(value, index, list) {

      if(result || ( result = iterator.call(context, value, index, list)))

        return breaker;

    });

    return !!result;

  };

  // Check if there is a value in the collection that exactly matches the target parameter (the data type will also be matched)

  _.include = _.contains = function(obj, target) {

    var found = false;

    if(obj == null)

      return found;

    // Prioritize calling the Array.prototype.indexOf method provided by the host environment

    if(nativeIndexOf && obj.indexOf === nativeIndexOf)

      return obj.indexOf(target) != -1;

    // Iterate over the elements in the collection through the any method and verify whether the value and type of the element completely match the target.

    found = any(obj, function(value) {

      return value === target;

    });

    return found;

  };

  // Call the same-named methods of all elements in the collection in sequence, starting from the third parameter, which will be passed into the calling method of the element.

  // Return an array that stores the processing results of all methods

  _.invoke = function(obj, method) {

    // Parameters passed when calling the method with the same name (starting from the 3rd parameter)

    var args = slice.call(arguments, 2);

    // Call the method of each element in turn and put the result into the array and return it

    return _.map(obj, function(value) {

      return (_.isFunction(method) ? method || value : value[method]).apply(value, args);

    });

  };

  // Traverse an array consisting of a list of objects and return a list of values ​​​​for the specified attribute in each object

  _.pluck = function(obj, key) {

    // If the property does not exist in an object, return undefined

    return _.map(obj, function(value) {

      return value[key];

    });

  };

  //Return the maximum value in the collection, if there is no comparable value, return undefined

  _.max = function(obj, iterator, context) {

    // If the collection is an array and no processor is used, use Math.max to get the maximum value

    // Generally, a series of Number type data is stored in an array.

    if(!iterator && _.isArray(obj) && obj[0] === obj[0])

      return Math.max.apply(Math, obj);

    // For null values, return negative infinity directly

    if(!iterator && _.isEmpty(obj))

      return -Infinity;

    // A temporary object, computed is used to store the maximum value during the comparison process (temporary)

    var result = {

      computed : -Infinity

    };

    //Iterate over the elements in the collection

    each(obj, function(value, index, list) {

      // If the processor parameter is specified, the compared data is the value returned by the processor, otherwise the default value during each traversal is used directly.

      var computed = iterator ? iterator.call(context, value, index, list) : value;

      // If the comparison value is greater than the previous value, put the current value into result.value

      computed >= result.computed && ( result = {

        value: value,

        computed : computed

      });

    });

    // Return the maximum value

    return result.value;

  };

  //Return the minimum value in the set, the processing process is consistent with the max method

  _.min = function(obj, iterator, context) {

    if(!iterator && _.isArray(obj) && obj[0] === obj[0])

      return Math.min.apply(Math, obj);

    if(!iterator && _.isEmpty(obj))

      return Infinity;

    var result = {

      computed: Infinity

    };

    each(obj, function(value, index, list) {

      var computed = iterator ? iterator.call(context, value, index, list) : value;

      computed 

      rand = Math.floor(Math.random() * (index 1));

      // Put the randomly obtained elements at the end of the shuffled array

      shuffled[index] = shuffled[rand];

      //Insert the latest value at the position of the previously obtained random number

      shuffled[rand] = value;

    });

    // Return an array that stores randomly shuffled collection elements.

    return shuffled;

  };

  // Arrange the elements in the collection according to specific fields or values

  // Compared to the Array.prototype.sort method, the sortBy method supports sorting objects.

  _.sortBy = function(obj, val, context) {

    // val should be a property of the object, or a processor function. If it is a processor, it should return the data that needs to be compared.

    var iterator = _.isFunction(val) ? val : function(obj) {

      return obj[val];

    };

    // Calling sequence: _.pluck(_.map().sort());

    // Call the _.map() method to traverse the collection, put the elements in the collection into the value node, and put the data that needs to be compared in the elements into the criteria attribute

    //Call the sort() method to sort the elements in the collection according to the data in the criteria attribute.

    // Call pluck to obtain the sorted object collection and return it

    return _.pluck(_.map(obj, function(value, index, list) {

      return {

        value: value,

        criteria: iterator.call(context, value, index, list)

      };

    }).sort(function(left, right) {

      var a = left.criteria, b = right.criteria;

      if(a ===

        void 0)

        return 1;

      if(b ===

        void 0)

        return -1;

      return a  b ? 1 : 0;

    }), 'value');

  };

  // Divide the elements in the collection into multiple arrays according to the keys returned by the processor

  _.groupBy = function(obj, val) {

    var result = {};

    // val will be converted into a processor function for grouping. If val is not a Function type data, it will be used as the key value when filtering elements.

    var iterator = _.isFunction(val) ? val : function(obj) {

      return obj[val];

    };

    //Iterate over the elements in the collection

    each(obj, function(value, index) {

      // Use the return value of the processor as the key, and put the same key elements into a new array

      var key = iterator(value, index);

      (result[key] || (result[key] = [])).push(value);

    });

    // Return grouped data

    return result;

  };

  _.sortedIndex = function(array, obj, iterator) {

    iterator || ( iterator = _.identity);

    var low = 0, high = array.length;

    while(low > 1;

      iterator(array[mid]) = 0;

      });

    });

  };

  // Filter and return the difference data in the current array that is not equal to the specified data

  // This function is generally used to delete the specified data in the array and get the new array after deletion

  // The function of this method is equivalent to without. The without method parameter does not allow data to be included in an array, while the difference method parameter is recommended to be an array (you can also use the same parameters as without).

  _.difference = function(array) {

    // Merge all parameters starting from the second parameter as an array (only merge the first level, not deep merge)

    // The rest variable stores the verification data, which is used in this method to compare with the original data.

    var rest = _.flatten(slice.call(arguments, 1), true);

    // Filter the merged array data. The filter condition is that the current array does not contain the verification data specified by the parameter.

    // Combine the data that meets the filter conditions into a new array and return it

    return _.filter(array, function(value) {

      return !_.include(rest, value);

    });

  };

  //Return the data at the same position of each array as a new two-dimensional array. The length of the returned array is based on the maximum array length in the passed parameters. The blank positions of other arrays are filled with undefined.

  // The zip method should contain multiple parameters, and each parameter should be an array

  _.zip = function() {

    //Convert the parameters into an array, at this time args is a two-dimensional array

    var args = slice.call(arguments);

    // Calculate the length of each array and return the maximum length value

    var length = _.max(_.pluck(args, 'length'));

    //Create a new empty array according to the maximum length value, which is used to store the processing results

    var results = new Array(length);

    //The maximum length of the loop, in each loop the pluck method will be called to obtain the data at the same position in each array (from 0 to the last position in sequence)

    // Store the obtained data in a new array, put it into results and return

    for(var i = 0; i = 0; i--) {

        args = [funcs[i].apply(this, args)];

      }

      //Return the return value of the last function call

      return args[0];

    };

  };

  // Return a function that serves as a call counter. When the function is called times times (or exceeds times times), the func function will be executed.

  // The after method is generally used as an asynchronous counter. For example, if you need to execute a function after multiple AJAX requests are completed, you can use after to call it after each AJAX request is completed.

  _.after = function(times, func) {

    // If no or invalid times are specified, func is called directly

    if(times  " '

  _.escape = function(string) {

    return ('' string).replace(/&/g, '&').replace(/, '/g, '>').replace(/ "/g, '"').replace(/'/g, ''').replace(///g, '/');

  };

  //Specify the attribute of an object and return the value corresponding to the attribute. If the attribute corresponds to a function, the function will be executed and the result will be returned.

  _.result = function(object, property) {

    if(object == null)

      return null;

    // Get the value of the object

    var value = object[property];

    // If the value is a function, execute it and return it, otherwise it will return directly

    return _.isFunction(value) ? value.call(object) : value;

  };

  //Add a series of custom methods to the Underscore object to extend the Underscore plug-in

  _.mixin = function(obj) {

    //obj is an object that collects a series of custom methods. Here, the method of traversing the object is through each

    each(_.functions(obj), function(name) {

      //Add custom methods to objects built by Underscore through the addToWrapper function to support object-based calling

      // Also add methods to _ itself to support functional calls

      addToWrapper(name, _[name] = obj[name]);

    });

  };

  // Get a globally unique identifier, the identifier starts from 0 and accumulates

  var idCounter = 0;

  // prefix represents the prefix of the identifier. If no prefix is ​​specified, the identifier will be returned directly. It is generally used to create a unique ID for an object or DOM.

  _.uniqueId = function(prefix) {

    var id = idCounter;

    return prefix ? prefix id : id;

  };

  // Define the delimiting symbol of the template, used in the template method

  _.templateSettings = {

    //Delimiter of JavaScript executable code

    evaluate : //g,

    // Directly output the delimiter of the variable

    interpolate : //g,

    //Delimiter required to output HTML as a string (convert special symbols into string form)

    escape : //g

  };

 

  var noMatch = /.^/;

 

  // The escapes object records the correspondence between special symbols and string forms that need to be converted to each other, and is used as an index when the two are converted to each other.

  // First define special characters according to string form

  var escapes = {

    '\' : '\',

    "'" : "'",

    'r' : 'r',

    'n' : 'n',

    't' : 't',

    'u2028' : 'u2028',

    'u2029' : 'u2029'

  };

  // Traverse all special character strings and record the string form using special characters as keys

  for(var p in escapes)

  escapes[escapes[p]] = p;

  // Define the special symbols that need to be replaced in the template, including backslash, single quote, carriage return, line feed, tab, line separator, paragraph separator

  // Used when converting special symbols in a string to string form

  var escaper = /\|'|r|n|t|u2028|u2029/g;

  // Used when reversing (replacing) special symbols in string form

  var unescaper = /\(\|'|r|n|t|u2028|u2029)/g;

 

  //Reverse special symbols in string

  // The JavaScript source code that needs to be executed in the template needs to be reversed with special symbols, otherwise if it appears in the form of HTML entities or strings, a syntax error will be thrown

  var unescape = function(code) {

    return code.replace(unescaper, function(match, escape) {

      return escapes[escape];

    });

  };

  // Underscore template parsing method, used to fill data into a template string

  // Template parsing process:

  // 1. Convert special symbols in the template to strings

  // 2. Parse the escape form tag and parse the content into HTML entities

  // 3. Parse interpolate form tags and output variables

  // 4. Parse the evaluate form tag and create executable JavaScript code

  // 5. Generate a processing function that can directly fill in the template after getting the data and return the filled string

  // 6. Return the filled string or the handle of the processing function according to the parameters

  //------------------

  //In the template body, two parameters can be obtained through argments, namely the filling data (named obj) and the Underscore object (named _)

  _.template = function(text, data, settings) {

    // Template configuration, if no configuration item is specified, the configuration item specified in templateSettings is used.

    settings = _.defaults(settings || {}, _.templateSettings);

 

    // Start parsing the template into executable source code

    var source = "__p ='" text.replace(escaper, function(match) {

      //Convert special symbols to string form

      return '\' escapes[match];

    }).replace(settings.escape || noMatch, function(match, code) {

      // Parse the escape form tag , convert the HTML contained in the variable into an HTML entity through the _.escape function

      return "' n_.escape(" unescape(code) ") n'";

    }).replace(settings.interpolate || noMatch, function(match, code) {

      // Parse the interpolate form tag , connect the template content as a variable with other strings, and it will be output as a variable

      return "' n(" unescape(code) ") n'";

    }).replace(settings.evaluate || noMatch, function(match, code) {

      // Parse the evaluate form tag . The JavaScript code that needs to be executed is stored in the evaluate tag. The current string splicing ends here and is executed as JavaScript syntax in a new line, and the following content is used as characters again. The beginning of the string, so the JavaScript code in the evaluate tag can be executed normally.

      return "';n" unescape(code) "n;__p ='";

    }) "';n";

    if(!settings.variable)

      source = 'with(obj||{}){n' source '}n';

    source = "var __p='';" "var print=function(){__p =Array.prototype.join.call(arguments, '')};n" source "return __p;n";

 

    // Create a function, use the source code as the function execution body, and pass obj and Underscore as parameters to the function

    var render = new Function(settings.variable || 'obj', '_', source);

    // If the fill data of the template is specified, replace the template content and return the replaced result

    if(data)

      return render(data, _);

    // If no fill data is specified, returns a function that replaces the received data into the template

    // If the same template will be filled multiple times in the program, it is recommended not to specify the filling data in the first call. After obtaining the reference of the processing function, calling it directly will improve the operating efficiency.

    var template = function(data) {

      return render.call(this, data, _);

    };

    //Add the created source code string to the function object, generally used for debugging and testing

    template.source = 'function(' (settings.variable || 'obj') '){n' source '}';

    //채우는 데이터가 지정되지 않은 경우 처리 함수 핸들을 반환합니다.

    반환 템플릿;

  };

  // Underscore 객체의 메소드 체인 작업을 지원합니다. Wrapper.prototype.chain을 참조하세요.

  _.체인 = 함수(obj) {

    return _(obj).chain();

  };

  // Underscore 객체는 관련 메소드를 캡슐화합니다.

  // ---------------

 

  //원시 데이터를 래핑하기 위한 래퍼 생성

  // 모든 undersocre 객체는 래퍼 함수를 ​​통해 내부적으로 생성되고 캡슐화됩니다.

  //Underscore와 래퍼 사이의 내부 관계:

  // - 내부적으로 _ 변수를 정의하고, _에 Underscore 관련 메소드를 추가하여 _.bind() 등의 함수 호출을 지원할 수 있도록 합니다.

  // - 래퍼 클래스를 내부적으로 정의하고 _의 프로토타입 객체가 래퍼 클래스의 프로토타입을 가리키도록 합니다.

  // - 래퍼 프로토타입에 Underscore 관련 메서드를 추가하면 생성된 _ 객체에 Underscore 메서드가 포함됩니다.

  // - 래퍼 프로토타입에 Array.prototype 관련 메서드를 추가하면 생성된 _ 객체는 Array.prototype의 메서드를 갖게 됩니다.

  // -new _()는 실제로 래퍼() 객체를 생성 및 반환하고, 원래 배열을 _wrapped 변수에 저장하고, 원래 값을 첫 번째 매개변수로 사용하여 해당 메서드를 호출합니다.

  var 래퍼 = function(obj) {

    //원래 데이터는 래핑된 객체의 _wrapped 속성에 저장됩니다.

    this._wrapped = obj;

  };

  // Underscore의 프로토타입 개체가 래퍼의 프로토타입을 가리키도록 하므로 래퍼 프로토타입과 같은 메서드를 추가하면 Underscore 개체도 동일한 메서드를 갖게 됩니다.

  _.prototype = 래퍼.프로토타입;

 

  //객체를 반환합니다. 현재 Underscore가 chain() 메서드를 호출하면(즉, _chain 속성이 true) 래핑된 Underscore 객체가 반환되고, 그렇지 않으면 객체 자체가 반환됩니다.

  // 결과 함수</array>
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