前言

最近看了两遍jQuery源码,感觉只是看懂了jQuery的小部分小部分,不过仅此,就已经对john resig佩服的五体投地咯。。

下面附上这位帅哥的靓照,记住吧,是他改变了世界。


看的大多是实现的细节、技巧,整体的架构还是没有看出来。功力不够呀,还得慢慢修炼。jQuery真的是值得去读无数次的东西,每读一次,都会有不一样的收获。以后有空就多看看吧~

研读优秀框架的源码,是从初级jser进阶到中级jser的捷径,可以学到好多优秀代码的风格。从代码可以看出一个程序员的水平呀~

现在把自己看出来的一些帅呆了的技巧,细节记录下来,一起分享。

jQuery的细节技巧

巧用条件运算符

    trim: trim ?
            function( text ) {
                return text == null ?
                    "" :
                    trim.call( text );
            } :
            function( text ) {
                return text == null ?
                    "" :
                    text.toString().replace( trimLeft, "" ).replace( trimRight, "" );
        }

这里用了一个条件运算符,如果String.trim存在的话就用,不存在就用自己实现的trim函数。在jQuery的源码中,用了大量的这种技巧,比如:

data = data === "true" ? true :
    data === "false" ? false :
    data === "null" ? null :
    !jQuery.isNaN( data ) ? parseFloat( data ) :
        rbrace.test( data ) ? jQuery.parseJSON( data ) : data;
for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {} 

多用点这种技巧,就不用满屏幕都是if & else 了。代码会变得简洁,轻巧。

jQuery的循环遍历技巧

下面列出一些自己看出的、常见的、平时代码中常用的循环技巧

1、

    
    // 简单的for-in(事件) 
    for ( type in events ) {      }

2、

    // 缓存length属性,避免每次都去查找length属性,稍微提升遍历速度 
    for ( var j = 0, l = arrow.length; j < l; j++ ) {      }

3、

    // 不比较下标,直接判断元素是否为true(强制类型转换) 
    var elem; 
    for ( var i = 0; elems[i]; i++ ) { 
        elem = elems[i]; 
        // ... 
    }

4、

    
    // 遍历动态数组(事件),不能缓存length属性,j++之前先执行j--
    for ( j = 0; j < eventType.length; j++ ) { 
        eventType.splice( j--, 1 ); 
    } 
    for ( var i = 1; i < results.length; i++ ) { 
        if ( results[i] === results[ i - 1 ] ) { 
            results.splice( i--, 1 ); 
        } 
    }

这个细节要注意哈,稍不注意就会在这里折腾很久。动态数组不能缓存!

5、

    // 迭代过程中尽可能减少遍历次数(事件),从pos开始
    for ( j = pos || 0; j < eventType.length; j++ ) {      }

6、

    //倒序遍历,有利于浏览器优化,稍微提升遍历速度 
    for ( var i = this.props.length, prop; i; ) { 
        prop = this.props[ --i ]; 
        event[ prop ] = originalEvent[ prop ]; 
    }

7、

    
    // while检查下标i 
    var i = arr.length; 
    while( i-- ) { 
        obj[ arr[i] ] = deferred[ arr[i] ]; 
    }

通过闭包,返回前一作用域的参数

    // 闭包。返回的函数保持对guid的引用。
    function a(){
        var guid = 1;
        return function(){
            return guid++;
        }
    }
    var defer = a();

一次实现多种方法

    if ( rfxtypes.test(val) ) {
        // 如果是toggle,则判断当前是否hidden,如果hidden则show,否则hide
        // 如果不是toggle,说明val是hide/show之一
        val === "toggle" ? (hidden ? "show" : "hide") : val ;     } else { ... }

条件运算符 + 关联数组 一次实现三种方法,帅呆了!不过貌似这种方法平时用的不多。

同样的思想还有一处:

    jQuery.each(["live", "die"], function( i, name ) {
        jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) {
            if ( name === "die" && !types &&
                        origSelector && origSelector.charAt(0) === "." ) {
                context.unbind( origSelector );
                return this;
            }
            //....
            return this;
        };
    }); 

一次性实现两个方法:

    jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
        "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
        "change select submit keydown keypress keyup error").split(" "), function( i, name ) {
        // Handle event binding
        jQuery.fn[ name ] = function( data, fn ) {
           return arguments.length > 0 ?
               this.bind( name, data, fn ) :
               this.trigger( name );
        };
        // 将事件名注册(添加)到jQuery.attrFn,当遇到对同名属性的操作时,转换为对事件接口的调用
        if ( jQuery.attrFn ) {
           jQuery.attrFn[ name ] = true;
        }
   });

通过each方法,实现n多方法。到此,除了惊叹还是惊叹。

实例化jQuery对象

先看代码:

    jQuery = function( selector, context ) {
        return new jQuery.fn.init( selector, context, rootjQuery );
    }

这里jQuery对象就是jQuery.fn.init对象

如果执行new jQeury(),生成的jQuery对象会被抛弃,最后返回 jQuery.fn.init对象;

因此可以直接调用jQuery( selector, context ),没有必要使用new关键字
还有一行代码如下:

    jQuery.fn.init.prototype = jQuery.fn = jQuery.prototype

所有挂载到jQuery.fn的方法,相当于挂载到了jQuery.prototype,即挂载到了jQuery 函数上(一开始的 jQuery = function( selector, context ) ),但是最后都相当于挂载到了 jQuery.fn.init.prototype,即相当于挂载到了一开始的jQuery 函数返回的对象上,即挂载到了我们最终使用的jQuery对象上。

这里的init函数里面执行了,我们平时接触具多的选择器。简单分析如下:

    
    //如果传入一个DOM元素。。包装成jQuery对象,直接返回。
    if ( selector.nodeType ) {
        this.context = this[0] = selector;
        this.length = 1;
        return this;
    }
    //如果传入一个字符串
        //如果字符串时一个类似"<a>hello</a>"样子的,直接生成。
        //传入ID,直接document.getElementById(),然后包装成jQuery对象。
    //选择器表达式,find...
    //如果传入函数,则为ready开始 

jQuery 巧妙避免ReferenceError

在源码中,经常看到这样的代码:

args = args || [];

这样可以确保args可用,一个避免null,underfined造成的ReferenceError的常见技巧。

比如我们还可以看到这样的:

    isArray: Array.isArray || function( obj ) {
        return jQuery.type(obj) === "array";
    }//这里和上面的条件运算符效果差不多。     name = jQuery.cssProps[ origName ] || origName;

在很多需要传入选项对象的函数中,如果用户自己传入,就用用户传进的;如果用户没有传值,则用开发者默认的参数。这样的代码很帅气有木有!

jQuery的实现框架

    (function( window, undefined ) {

        // 构造jQuery对象
        var jQuery = function( selector, context ) {
                return new jQuery.fn.init( selector, context, rootjQuery );
            }
        // 工具函数 Utilities
        // 异步队列 Deferred
        // 浏览器测试 Support
        // 数据缓存 Data
        // 队列 queue
        // 属性操作 Attribute
        // 事件处理 Event
        // 选择器 Sizzle
        // DOM遍历
        // DOM操作
        // CSS操作
        // 异步请求 Ajax
        // 动画 FX
        // 坐标和大小
        window.jQuery = window.$ = jQuery;  })(window); 

结语

以上分析,都只是jQuery的一些皮毛,还有很多很多没有发现,以后有时间,有机会再研究咯~

总之每看一次,都会有很大的收获,成长。

最近状态不好,做事效率很低。以后看书码代码的时候,要关了qq,微博,河畔。。。
离开用心,新的开始。虽然很多不舍,但必须面对,做出选择。对于有些人,应该就是永远不见,有些人,真舍不得。

做喜欢的事,做好喜欢的事。

从jQuery学细节的更多相关文章

  1. jQuery基础细节

    使用CDN版的jQuery         用托管在公共CDN(Content Delivery Network,内容分发网络)上的jQuery库,CDN是一种内容分发网络,当用户请求其数据时,CDN ...

  2. jquery冲突细节

    使用jquery报一个错误,之前也遇到过,今天记录下来,方便以后使用 Uncaught TypeError: Object #<Object> has no method 'test' 这 ...

  3. JQuery选择器细节-遁地龙卷风

    1.层次选择器-子元素选择器 <body> <div> <p>lol</p> <div> <p></p> </ ...

  4. 【深入浅出jQuery】源码浅析--整体架构

    最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...

  5. jQuery整体架构源码解析(转载)

    jQuery整体架构源码解析 最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性, ...

  6. jQuery整体架构源码解析

    最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...

  7. 【深入浅出jQuery】源码浅析--整体架构(转)

    最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...

  8. jquery源码解读

    最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐进增强)优雅的处理能 ...

  9. JavaScript和jQuery的学习

    还有12天就要回学校了,我的假期计划还能实现吗?在这12天里,需要把JavaScript和jQuery学完.我知道这两个技术对于前端网页开发非常重要.前期把HTML和CSS学完了,学的不是特别深,只是 ...

随机推荐

  1. ZFI_VENDOR_CREATE

    创建供应商函数, 需要考虑是 G_TASK = I /U /M FUNCTION zfyj_vendor_create. *"-------------------------------- ...

  2. 递归函数(Day15)

    一.递归的定义 在一个函数里面再调用这个函数本身 递归特性 1.必须有一个明确的结束条件 2.每次进入更深一层递归时,问题规模相比于上一次的递归有所减少 二.递归的应用 1.递归函数与三层菜单 men ...

  3. python中的标识符长度能有多长

    在python中,标识符可以还是任意长度.此外,我们在命名标识符时还必须遵守以下规则 1 只能以下划线或者A-Z/a-z中字母开头 2 其余部分可以使用A-Z/a-z/0-9 3 区分大小写 4 关键 ...

  4. php……流程

    流程:由两个及以上的业务步骤,完成一个完整的业务行为的过程,可称之为流程:注意是两个及以上的业务步骤.事物进行过程中的次序或顺序的布置和安排. 创建页面: 登录页面(login.php): <h ...

  5. 转:MFC中屏蔽ESC和回车关闭对话框

    解决方法是在 CDialog::PreTranslateMessage() 的重载函数中将ESC和回车按键的消息处理掉. 直接上代码: CResultCollectorDlg::PreTranslat ...

  6. third application :Directions widget

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

  7. Linux文件系统管理 fdisk分区命令

    概述 我们在安装操作系统的过程中已经对系统硬盘进行了分区,但是如果我新添加了一块硬盘,想要正常使用时,在Linux中有专门的分区命令 fdisk 和 parted.其中 fdisk 命令较为常用,但不 ...

  8. python的语法错误总结

    1.keyerror一般是你使用字典里不存在的key产生的错误. 2.TypeError一般是使用的数据类型不符合要求 join函数要求a都是string

  9. android开发之如何将一般应用变身系统级应用【转】

    本文转载自:https://blog.csdn.net/zanelove/article/details/43953743 前提: ROOT过的手机 1,把代码编写好后,打包导出apk,copy到手机 ...

  10. linux下java unrecognized class file version错误的解决

    root@Mr javaPC]# java HelloWorldException in thread “main” java.lang.ClassFormatError: HelloWorld (u ...