闭包
整个函数在一个闭包中,避免污染全局变量。
通过传入this(其实就是window对象)来改变函数的作用域。
(function(){
...
}.call(this));
原型赋值
var ArrayProto = Array.prototype,
ObjProto = Object.prototype,
FuncProto = Function.prototype;
Array,Object,Function这些本质都是函数,获取函数原型属性prototype也是为了便于压缩。
简单解释一下,如果代码中要扩展属性,可能这样写:
Object.prototype.xxx = ...
而这种代码是不可压缩的,Object,prototype这些名字改了浏览器就不认得了。
但是上面的代码中创建了ObjProto之后,源生代码经过压缩之后,ObjProto就可能命名成a变量,那么原来的代码就压缩成:
a.xxx = ...
数据判断
判断是否为dom,dom的nodeType属性值为1。这里用!!强转为boolean值
_.isElement = function(obj) { return !!(obj && obj.nodeType === 1); };
判断是否为数组。由于Array.isArray函数是ECMAScript 5新增函数,所以为了兼容之前的版本,在原生判断函数不存在的情况下,后面重写了一个判断函数。用call函数来改变作用域可以避免当obj没有toString函数报错的情况。
_.isArray = nativeIsArray || function(obj) { return toString.call(obj) === '[object Array]'; };
判断是否为对象。先用typeof判断数据类型。函数也属于对象,但是由于typeof null也是object,所以用!!obj来区分这种情况。
_.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.它是一个数;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; };