Website: http://web.jobbole.com/83872/
Underscore source version 1.8.2
Cause
Many people recommend to me to study JS, you can look at some third-party JS class library source code, and the best source of interpretation is also the shortest is underscore, it is also my usual favorite of a library, because it cost-effective: small size, strong ability. Open a look, only 1000 lines, try to read a bit, it is really worth a look, so the wonderful part did a bit of finishing.
Closed Package
The entire function is in a closure to avoid polluting global variables. Change the scope of the function by passing in this, which is actually the window object. And jquery's self-executing functions are actually the same thing. This way of passing in global variables is beneficial to code reading, on the other hand, convenient compression.
Underscore notation:
(function() { ...}. Call (this));
jquery notation:
(function(window, undefined) { ...}) (window);
Prototype assignment
var Arrayproto = array.prototype, Objproto = object.prototype, Funcproto = Function.prototype;
Array,object,function These essence are functions, get function prototype properties prototype is also for ease of compression. Simply explain that if you want to extend the property in your code, you might write
Object.prototype.xxx = ...
And this code is incompressible, Object
prototype
These names changed to the browser will not recognize.
However, after the code has been created ObjProto
, the source code is compressed, ObjProto
it may be named a variable, then the original code is compressed into
A.xxx = ...
A small suggestion is that a code is used more than two times it is recommended to define variables (functions), which facilitates the modification and compression of code.
Format
var nativeisarray = Array.isarray,nativekeys = object.keys,nativebind = funcproto.bind,nativecreate = Object.create;
This definition of the way omitted redundant VAR, format is also beautiful, let me think of a sublime in a plugin alignment.
Data judgment
Determines whether the NodeType property value for Dom,dom is 1. This is a !!
strong conversion to a Boolean value
function (obj) { return !! (obj && Obj.nodetype = = = 1); };
Determines whether or not the array is set. Since the Array.isarray function is a new function for ECMAScript 5, in order to be compatible with the previous version, a judgment function is rewritten after the original judgment function does not exist. Changing the scope with the call function avoids the case where obj does not have an error with the ToString function.
function (obj) { return tostring.call (obj) = = = ' [Object Array] '; };
Determines whether it is an object. Use typeof to determine the data type first. Functions also belong to objects, but because typeof null is also an object, so use!! Obj to differentiate this situation.
function (obj) { vartypeof obj; return Type = = = ' function ' | | Type = = = ' object ' &&!! obj;};
Judging whether it is arguments, very simple, arguments has a unique attribute callee.
if (! function(obj) { return _.has (obj, ' callee ');};}
Nan This value has two features: 1. It is a number; 2. Not equal to its own.
' + ' in front of the variable is the general effect of turning the subsequent variable into a number, where it has been judged that a number is still added ' + ', in order to var num = new Number()
classify this number of values that are not valued as Nan.
function (obj) {return _.isnumber (obj) && obj!== +obj; };
Do you think that if the Boolean value is not true or false? There is also a 3rd situation var b = new Boolean()
. B is also a Boolean value.
function (obj) {returntruefalse | | tostring.call (OBJ) = = = ' [Object Boolean] ';};
It's a very interesting little trick to show undefined with void. However, the usual way is if (XXX) to determine whether it is undefined.
function (obj) {returnvoid 0;};
eq
is a built-in function of underscore, the code is too long, not pasted. IsEmpty called this function. The whole idea from easy to difficult, first use = = = Comparison of simple data, and then use ToString to determine whether it is equal, and finally recursive processing complex array, function and object objects.
if return a!== 0 | | 1/a = = = 1/b;
Here in order to differentiate between ' +0 ' and '-0 ', because these two numbers have an effect on the calculated results.
varClassName =Tostring.call (a);if(ClassName!== Tostring.call (b))return false;Switch(className) {//Strings, numbers, regular expressions, dates, and booleans is compared by value. Case' [Object RegExp] ': //Regexps is coerced to strings for comparison (note: ' +/a/i = = = '/a/i ') Case' [Object String] ': //primitives and their corresponding object wrappers is equivalent; thus, ' 5 ' is //equivalent to ' New String ("5") '. return' + A = = = ' +b; Case' [Object number] ': //' NaN ' is equivalent, but non-reflexive. //Object (NaN) is equivalent to NaN if(+a!== +a)return+b!== +b; //An ' Egal ' comparison are performed for the 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 is compared by their //millisecond representations. Note that invalid dates with millisecond representations //of ' NaN ' is not equivalent. return+a = = = +b;}
Here is a simple object to judge, divided into two categories, a kind of is String
and RegExp
, this data directly toString
then judge. Another kind is Number
, Date
and Boolean
, by converting to digital judgment.
Astack.push (a); Bstack.push (b);if(arearrays) {length=a.length; if(Length!== b.length)return false; while(length--) { if(!eq (A[length], b[length], Astack, Bstack))return false; }} Else { varKeys =_.keys (a), key; Length=keys.length; if(_.keys (b). length!== length)return false; while(length--) {Key=Keys[length]; if(! (_.has (b, key) && eq (A[key], B[key], Astack, Bstack)))return false; }}astack.pop (); Bstack.pop ();
Only recursion is used for arrays and objects, and Astack and Bstack are used to stage sub-objects in recursion. One trick here is to judge the length of the array/attribute first, and if not, the recursion can be reduced effectively.
JS Master Advanced Way: Underscore source Classic (ii)