閉包
整個函數(shù)在一個閉包中,避免污染全局變量。
通過傳入this(其實就是window對象)來改變函數(shù)的作用域。
(function(){
...
}.call(this));
原型賦值
var ArrayProto = Array.prototype,
ObjProto = Object.prototype,
FuncProto = Function.prototype;
Array,Object,Function這些本質(zhì)都是函數(shù),獲取函數(shù)原型屬性prototype也是為了便于壓縮。
簡單解釋一下,如果代碼中要擴展屬性,可能這樣寫:
Object.prototype.xxx = ...
而這種代碼是不可壓縮的,Object,prototype這些名字改了瀏覽器就不認得了。
但是上面的代碼中創(chuàng)建了ObjProto之后,源生代碼經(jīng)過壓縮之后,ObjProto就可能命名成a變量,那么原來的代碼就壓縮成:
a.xxx = ...
數(shù)據(jù)判斷
判斷是否為dom,dom的nodeType屬性值為1。這里用!!強轉為boolean值
_.isElement = function(obj) { return !!(obj && obj.nodeType === 1); };
判斷是否為數(shù)組。由于Array.isArray函數(shù)是ECMAScript 5新增函數(shù),所以為了兼容之前的版本,在原生判斷函數(shù)不存在的情況下,后面重寫了一個判斷函數(shù)。用call函數(shù)來改變作用域可以避免當obj沒有toString函數(shù)報錯的情況。
_.isArray = nativeIsArray || function(obj) { return toString.call(obj) === '[object Array]'; };
判斷是否為對象。先用typeof判斷數(shù)據(jù)類型。函數(shù)也屬于對象,但是由于typeof null也是object,所以用!!obj來區(qū)分這種情況。
_.isObject = function(obj) { var type = typeof obj; return type === 'function' || type === 'object' && !!obj; };
判斷是否為arguments,很簡單,arguments有個特有屬性callee。
if (!_.isArguments(arguments)) { _.isArguments = function(obj) { return _.has(obj, 'callee'); }; }
NaN這個值有兩個特點:1.它是一個數(shù);2.不等于它自己。
_.isNaN = function(obj) { return _.isNumber(obj) && obj !== +obj; };
判斷是否是布爾值
_.isBoolean = function(obj) { return obj === true || obj === false || toString.call(obj) === '[object Boolean]'; };
判斷undefined,用void 0來表示undefined
_.isUndefined = function(obj) { return obj === void 0; };