很多人觉得jquery、ext等一些开源js源代码 十分的晦涩,读不懂,遇到问题需要调试也很费劲。其实我个人感觉主要是有几个方面的原因:

  • 对一些js不常用的语法、操作符不熟悉
  • 某个function中又嵌套了一些内部的function,使得整个代码的层次结构不像java代码那么清晰。
  • js中允许变量先使用后定义,会造成我们看代码时候忽然冒出来一个变量、function,却找不到是在哪里定义的。

那么今天给大家分享一下我的经验,扫清你的障碍。

一些晦涩的操作符:

(function(){})();

几乎所有的开源js代码开篇都是这样(function(……){……})(……);

下面是Jquery的部分源码:

(function( window, undefined ) {
    var jQuery = function( selector, context ) {
        // The jQuery object is actually just the init constructor 'enhanced'
        return new jQuery.fn.init( selector, context );
    },     // Map over jQuery in case of overwrite
    _jQuery = window.jQuery,     // Map over the $ in case of overwrite
    _$ = window.$,
    ……
    indexOf = Array.prototype.indexOf;     // Expose jQuery to the global object
    window.jQuery = window.$ = jQuery;
})(window);

那么这个操作符(function(){})();到底是什么意思呢?

(function(){})中的定义了一个function,紧接着的()表示立即执行这个function

我们看到Jquery源码第一个()中是定义了一个匿名function( window, undefined ) {};接着末尾有个(window),就表示执行这个匿名function,并传入参数window

在匿名function( window, undefined ) {}中,定义了一个局部变量jQuery;然后在末尾我们看到Jquery末尾有一句window.jQuery = window.$ = jQuery; 这句代码就表示,将此前定义的jQuery导出到window对象。这也是为什么我们可以在代码任何地方直接使用$jQuery 对象,因为在这里已经将$jQuery 对象挂载到window下去了,而window.$window.jQuery 与直接使用$jQuery 是没有区别的。

(注意,这个window对象是传入的参数window,而不是浏览器window对象!!一个形参、一个实参。我们可以在定义function的时候,将参数window取名为其他字符。所以我们看到jquery.min.js中这个匿名function变成了(function(E,B){})(window);)

通常(function(){})()用来封装一些私有成员或者公共成员的导出。

令人迷惑的","

我们知道 , 一般用于一次定义多个变量、定义多个参数等。像上面的jQuery源码中在var jQuery后面,使用,一次定义了很多个变量。 但是,像下面的代码,可能大家就不一定看得懂了:

//html:<input type="hidden" value="king" id="nameHide"/>
jQuery(document).ready(function() {
    var showName=function(){
        var value,nameInput=$("#nameHide");
        return nameInput.show(),value=nameInput.val();
    };
    alert(showName());
});
//结果:弹出king

这里的nameInput.show(),value=nameInput.val()中的,运算符的作用是返回,右侧表达式的值。所以,return 后面如果有多个表达式,且表达式之间由,隔开,整个return表达式返回的是最后一个,右侧的表达式的值。

,在开源代码中常常被用于return表达式中,以及跟下面我们要讲到的()运算符一起使用。

()广义上的代码包装

我们遇到复杂的逻辑表达式时,我们通常会把需要一起运算的表达式用“()”包起来:(a||b)&&(c||d)

其实,我们可以这样理解:()运算符将一个表达式包裹起来作为一个整体进行运算,然后返回这个整体的值。

那么上面的(function(){})()中左侧定义function的()也是这个作用,将这个function给包裹起来,然后返回这个function。我们调用方法一般是a();那么(function(){})的作用就是返回这个function对象,然后(function(){})()右侧的()表示调用这个function

我们再来看其他的用法:

//html:<input value="kings" id="name"/><div id="nameErrorTip">输入错误!</div>
jQuery(document).ready(function() {
    var nameValidate=function(){
        var value,nameInput=$("#name"),nameErrorTip=$("#nameErrorTip"); 
        return (value=nameInput.val(),value=="king")?(nameErrorTip.hide(),"对了,输入为king!"):(nameErrorTip.show(),"请输入king!");
    };
    alert(nameValidate());
}); //结果 nameErrorTip显示,弹出"请输入king!"
//html:<input value="king" id="name"/><div id="nameErrorTip">输入错误!</div>
//结果 nameErrorTip隐藏,弹出"对了,输入为king!"

这里(value=nameInput.val(),value=="king")()将里面的表达式作为一个整体进行运算,而里面的表达式又是由,构成的多个表达式组,所以执行的时候会把这多个表达式都执行一次,并且返回最后一个表达式的值!

所以 (value=nameInput.val(),value=="king")执行时,先运算value的值,再判断是否为"king"。如果为king,会执行(nameErrorTip.hide(),"对了,输入为king!")。这个表达式又先将nameErrorTip隐藏,再返回一个"对了,输入为king!"字符串作为 整个return的值。

||、&&、if()逻辑让人头晕

||&&两侧参与运算的是逻辑表达式,if()中也是。但是我们在很多开源代码中看到的||&&参与运算的表达式看起来却好像不是逻辑表达式……

下面节选一段jQuery.tool中的一段源码:

e.circular || (f.onBeforeSeek(function(a, b) {
    setTimeout(function() {
        a.isDefaultPrevented()||(
            n.toggleClass(
                e.disabledClass,
                b <= 0
            ),
            o.toggleClass(
                e.disabledClass,
                b >= f.getSize() - 1
            )
        )
    }, 1)
}),
e.initialIndex || n.addClass(e.disabledClass)),
f.getSize() < 2 && n.add(o).addClass(e.disabledClass),
e.mousewheel && a.fn.mousewheel && b.mousewheel(function(a, b) {
    if (e.mousewheel) {
        f.move(b < 0 ? 1 : -1, e.wheelSpeed || 50);
        return !1
    }
});

这里有多处||&&。但与运算的表达式却是调用某个函数的返回值。

其实,js中的逻辑表达式是按照真值、假值来分的。true是真值;1是真值;一个对象也是真值;false是假值;""0是假值。

在js中&&||不一定都是用来判断一个表达式的逻辑值是truefalse,更多的是用来依据真值或者假值执行相应操作!

我们知道,||运算的时候,会先运算左侧的表达式的值,如果为真值,那么真个表达式就为真值,而同时右侧表达式是真值、假值都不重要,因为右侧表达式都不再继续参与运算了。又如果左侧为假值,则继续运算右侧表达式。

&&则先运算左侧表达式,两侧表达式,一个为假值,则整个表达式为假值。

这里关键是这个真值或者假值的运算过程中,我们可以使用上面介绍的,()将一组表达式串起来执行。也就是说,这个表达式可能会很长很长,我甚至可以定义一个function在里面。这些表达式在执行过程中,有可以进行某些附加操作。比如我们希望这个表达式为真值的时候我们做什么,假值的时候做什么,把这些操作用(),串起来作为一个整体运算。

于是就有了上面的复杂代码。

另外:

if(a){
    b
}

可简写为a&&(b); b可以是一个function调用表达式,或者是多个语句用","串起来。但前提是a已定义,否则会报错。

我们来看个实例吧。是上面例子的升级版。我们加入一个nameInput是否存在的判断:

jQuery(document).ready(function() {
    var nameValidate=function(){
        var value,nameInput=$("#name"),nameErrorTip=$("#nameErrorTip"),msg;
        msg=(value=nameInput.val(),value=="king")?(nameErrorTip.hide(),"对了,输入为king!"):(nameErrorTip.show(),"请输入king!");
        return (nameInput.length&&nameInput.val()&&nameErrorTip.length&&msg)||"没有找到name输入框或者输入框没有值!";
    };
    alert(nameValidate());
});

测试:

//html:<input value="king" id="myName"/>
//结果:弹出“没有找到name输入框或者输入框没有值!” //<input value="king" id="name"/><div id="nameErrorTip">输入错误!</div>
//结果:弹出“对了,输入为king!”,nameErrorTip被隐藏

return表示中 nameInput.length&&nameInput.val()&&nameErrorTip.length&&msg会先运算 nameInput.length的值,如果length0则表达式为假值,如果为1则为真值。val()操作也是如此,如果val()结果为""则表达式也是假值。几个表达式之间为&&运算,则表示依次运算几个表达式的值,如果都未真值则返回最后一个表达式的值,由于整个表达式与 "没有找到name输入框或者输入框没有值!" 表达式之间是||运算,所以前面的表达式其中一个表达式为假值则返回||右侧的表达式的值,也就是整个“没有找到name输入框或者输入框没有值!”字符串。

说到这里,我之前写过一篇文章专门说到了&&||的真值、假值问题。有兴趣的可以去看看。

谈了这些难以理解的运算符后,大家可能会觉得,这个javascript为什么要搞这些晦涩的运算符呢?

我的理解是因为javascript通常在客户端运行,那么从服务器端将js代码传输到客户端肯定需要耗时。上面的这些运算符都是为了减少代码量。再加上使用压缩工具去掉空格,替换变量名,就可以使用压缩率达到最好。

再这里,我也告诉大家,其实我也非常反对在实际应用中采用这种写法的,因为会对初学者造成阅读障碍。我写这篇文章的目的不是为了让大家以后就这样用,而是告诉大家可以这样用,在一些开源代码中遇到了能看懂。不可为了炫耀而故意写一些晦涩的代码。

最后,为了帮助我们更快的找到变量定义、理清代码整体结构,给大家推荐一个eclipse的js插件:Spket,支持jQuery代码提示哦!

[转]看了这个才发现jQuery源代码不是那么晦涩的更多相关文章

  1. 看了这个才发现jQuery源代码不是那么晦涩

    很多人觉得jquery.ext等一些开源js源代码 十分的晦涩,读不懂,遇到问题需要调试也很费劲.其实我个人感觉主要是有几个方面的原因: 1.对一些js不常用的语法.操作符不熟悉 2.某个functi ...

  2. iPhone不为人知的功能常用技巧,看完后才发现很多用iPhone的人实在是愧对乔布斯! - imsoft.cnblogs

    很多人花了四五千买部苹果,结果只用到四五百块钱的普通手机功能. iPhone不为人知的功能,常用技巧: 网上搜集整理的iPhone快捷键操作,虽然表面上iPhone按键只有一个HOME键,大部分操作都 ...

  3. jQuery源代码学习之九—jQuery事件模块

    jQuery事件系统并没有将事件坚挺函数直接绑定在DOM元素上,而是基于事件缓存模块来管理监听函数的. 二.jQuery事件模块的代码结构 //定义了一些正则 // // //jQuery事件对象 j ...

  4. jQuery源代码学习之八——jQuery属性操作模块

    一.jQuery属性模块整体介绍 jQuery的属性操作模块分四个部分:html属性操作,dom属性操作,类样式操作,和值操作. html属性操作(setAttribute/getAttribute) ...

  5. jQuery源代码学习之七—队列模块queue

    一.jQuery种的队列模块 jQuery的队列模块主要是为动画模块EFFECTS提供支持,(不过到现在为了支持动画队列的inprogress的出入队还是搞不太清楚),单独抽取出一个命名空间是为了使程 ...

  6. jQuery源代码学习之六——jQuery数据缓存Data

    一.jQuery数据缓存基本原理 jQuery数据缓存就两个全局Data对象,data_user以及data_priv; 这两个对象分别用于缓存用户自定义数据和内部数据: 以data_user为例,所 ...

  7. jQuery源代码学习之五——jQuery.when

    jQuery.when提供了基于一个或多个对象的状态来执行回调函数的功能,通常是基于具有异步事件的异步队列. 如果传入多个异步队列,jQuery.when会返回一个新的主异步队列的只读副本(promi ...

  8. jQuery源代码学习之四——jQuery.callbacks

    自己实现的callbacks模块相较于jquery源代码中的callbacks模块有所简化,表面上看没有考虑firing这个参数,没有对之进行任何处理,即没有考虑在函数执行过程中,再次调用add,re ...

  9. jQuery源代码阅读之三——jQuery实例方法和属性

    jQuery实例方法及属性相关的代码结构如下 jQuery.fn=jQuery.prototype={ jQuery:core_version, constructor:jQuery, selecto ...

随机推荐

  1. Code笔记之:CSS块级元素、内联元素概念

    文档流 将窗体自上而下分成一行行, 并在每行中按从左至右的顺序排放元素,即为文档流. 每个非浮动块级元素都独占一行, 浮动元素则按规定浮在行的一端. 若当前行容不下, 则另起新行再浮动. 内联元素也不 ...

  2. 今天接触枚举类型,感觉是C里面应该才有的东西

    遍历枚类型的方法: public static EActChannel getEnumByCode(int code) { for (EActChannel enm : EActChannel.val ...

  3. vimium Keyboard Bindings

    Modifier keys are specified as `<c-x>`, `<m-x>`, and `<a-x>` for ctrl+x, meta+x, a ...

  4. 记录s标签范例

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding= ...

  5. linux系统判断是否重启、关机、查询登录诊断分析简介

    Last reboot这个命令是查看每次系统重启的信息 [root@dg01 log]# last rebootreboot system boot 2.6.32-300.10.1. Thu May  ...

  6. python中配置文件写法

    import os BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) print(BASE_DIR) USE ...

  7. RGB to HSI, HSI to RGB Conversion Calculator

    The RGB color model is an additive system in which each color is defined by the amount of red, green ...

  8. LaTeX Software & Manuals

    LaTeX Software & Manuals How to Typeset Equations in LaTeX LaTeX is a very powerful tool for typ ...

  9. VIM自动补全插件 - YouCompleteMe--"大神级vim补全插件"

    VIM自动补全插件 - YouCompleteMe 序言 vim 之所以被称为编辑器之神多半归功于其丰富的可DIY的灵活插件功能,( 例如vim下的这款神级般的代码补全插件YouCompleteMe) ...

  10. Quartz.NET总结(三)Quartz 配置

    前两篇文章,已经介绍了Quartz.NET的使用和Cron表达式表达式的写法,今天说一说Quartz的配置,Quartz相关的配置有三个quartz.config.quartz_jobs.xml.lo ...