underscore 源码版本 1.8.2
起因
很多人向我推荐研究js,可以看看一些第三方js类库的源码,而源码之中最好解读也最简短的就是underscore,它也是我平常比较喜欢的一个库,因为它性价比高:体积小、能力强。打开一看,才1000多行,试着读了一下,确实很值得一看,所以对精彩部分做了一下整理。
闭包
整个函数在一个闭包中,避免污染全局变量。通过传入this(其实就是window对象)来改变函数的作用域。和jquery的自执行函数其实是异曲同工之妙。这种传入全局变量的方式一方面有利于代码阅读,另一方面方便压缩。
underscore写法:
1 2 3 |
(function(){ ... }.call(this)); |
jquery写法:
1 2 3 |
(function(window, undefined) { ... })(window); |
原型赋值
1 |
var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; |
Array,Object,Function这些本质都是函数,获取函数原型属性prototype也是为了便于压缩。简单解释一下,如果代码中要扩展属性,可能这样写
1 |
Object.prototype.xxx = ... |
而这种代码是不可压缩的,Object
,prototype
这些名字改了浏览器就不认得了。
但是上面的代码中创建了ObjProto
之后,源生代码经过压缩之后,ObjProto
就可能命名成a变量,那么原来的代码就压缩成
1 |
a.xxx = ... |
一个小建议就是凡事一段代码被使用两次以上都建议定义变量(函数),有利于修改和压缩代码。
格式
1 2 3 4 |
var nativeIsArray = Array.isArray, nativeKeys = Object.keys, nativeBind = FuncProto.bind, nativeCreate = Object.create; |
这种定义的方式省略了多余的var,格式也美观,让我想到了sublime中的一个插件alignment。
数据判断
1 2 3 |
_.isElement = function(obj) { return !!(obj && obj.nodeType === 1); }; |
判断是否为dom,dom的nodeType属性值为1。这里用!!
强转为boolean值
1 2 3 |
_.isArray = nativeIsArray || function(obj) { return toString.call(obj) === '[object Array]'; }; |
判断是否为数组。由于Array.isArray函数是ECMAScript 5新增函数,所以为了兼容之前的版本,在原生判断函数不存在的情况下,后面重写了一个判断函数。用call函数来改变作用域可以避免当obj没有toString函数报错的情况。
1 2 3 4 |
_.isObject = function(obj) { var type = typeof span class="crayon-h"> { var type = typeof derscore,它也是我平常比较喜欢的一个库,因为它性价比高:体积小、能力强。打开一看,才1000多行,试着读了一下,确实很值得一看,所以对精彩部分做了一下整理。
闭包整个函数在一个闭包中,避免污染全局变量。通过传入this(其实就是window对象)来改变函数的作用域。和jquery的自执行函数其实是异曲同工之妙。这种传入全局变量的方式一方面有利于代码阅读,另一方面方便压缩。
jquery写法:
原型赋值
Array,Object,Function这些本质都是函数,获取函数原型属性prototype也是为了便于压缩。简单解释一下,如果代码中要扩展属性,可能这样写
而这种代码是不可压缩的, 但是上面的代码中创建了
一个小建议就是凡事一段代码被使用两次以上都建议定义变量(函数),有利于修改和压缩代码。 格式
这种定义的方式省略了多余的var,格式也美观,让我想到了sublime中的一个插件alignment。 数据判断
判断是否为dom,dom的nodeType属性值为1。这里用
判断是否为数组。由于Array.isArray函数是ECMAScript 5新增函数,所以为了兼容之前的版本,在原生判断函数不存在的情况下,后面重写了一个判断函数。用call函数来改变作用域可以避免当obj没有toString函数报错的情况。
|