转载

js高手进阶之路:underscore源码经典(三)

后面的代码真是越看越难理解,经常需要结合内部/接口函数一起,所以采用跳读的方式解析,基本按照模块由易到难的顺序解析。

456  _.initial = function(array, n, guard) {     return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));   }; 

这个guard参数说是保证默认返回第一个值,不过我看了很久觉得意义不大,猜测可能是以前的接口。这里的 slice = Array.prototype.slice 。这里有两个地方比较好,一是用Array的原型函数来处理array参数,这样可以避免判断array是否数组,二是用max来避免超出数组长度。

671 _.range = function(start, stop, step) {  if (arguments.length <= 1) {    stop = start || 0;    start = 0;  }  step = step || 1;  var length = Math.max(Math.ceil((stop - start) / step), 0);  var range = Array(length);  for (var idx = 0; idx < length; idx++, start += step) {    range[idx] = start;  }  return range;   };  

这个函数本什没有什么特别的,只不过我在调用的时候将step赋值为小数,就出现了javascript著名的精度问题。网上应该有不少的解决方案,这里提供一种目前我在项目中用到的解决方法:将数字转为字符串在去小数点之后转为整数进行计算,计算完成后转字符串加上小数点再转成小数,举个例子

1.11 ==> "1.11" ==> "111" ==> 111 2.2 ==> "2.2" ==> "220" ==> 220 111+220 ==> 331 ==> "331" ==> "3.31" ==> 3.31 

数组代码看得累了,从后面的看起吧~

1269 _.noConflict = function() {   root._ = previousUnderscore;   return this; }; 

这个让渡函数其实原理比较简单,就是初始化underscore前 previousUnderscore=window._ 对原有对象进行储存,如果需要让渡避免冲突,则进行还原同时返回当前underscore对象。再来看看JQuery的实现原理:

noConflict: function( deep ) {   if ( window.$ === jQuery ) {     window.$ = _$;   }    if ( deep && window.jQuery === jQuery ) {     window.jQuery = _jQuery;   }    return jQuery; } 

刚开始看的时候犯2了,函数可以用 === 来比较?不是只能比较简单的数据对象?呵呵,其实这个是通过引用地址来判断的,因为之前初始化的时候 window.$=JQuery 所以$会指向JQuery的地址,所以可以这样判断。后面一个if考虑到JQuery这个变量名也被占用的时候,也进行让渡,最后返回JQuery对象。可能是考虑多版本的情况吧~

1487  _.mixin = function(obj) {   _.each(_.functions(obj), function(name) {     var func = _[name] = obj[name];     _.prototype[name] = function() {       var args = [this._wrapped];       push.apply(args, arguments);       return result(this, func.apply(_, args));     };   }); };  // Add all of the Underscore functions to the wrapper object. _.mixin(_); 

这个用于扩展underscore自身的接口函数,通过循环遍历对象来浅拷贝对象属性。这里考虑到函数的实例化,所以一方面将函数作为内部函数使用,同时扩展到prototype属性上。考虑得比较周全。

1469  _.chain = function(obj) {   var instance = _(obj);   instance._chain = true;   return instance; }; 

这个函数让underscore支持链式调用,链式调用写起来很美观,但是调试略显不方便。结合之前的代码来看,underscore实现链式调用的基本原理是:将参数缓存在内部属性_wrapped中,调用函数时传入该属性值,执行后返回当前this指针。直到执行value函数时返回_wraped中的值。

博客: http://yalishizhude.github.io

作者:亚里士朱德

正文到此结束
Loading...