[转]看了这个才发现jQuery源代码不是那么晦涩
很多人觉得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中&&
、||
不一定都是用来判断一个表达式的逻辑值是true
、false
,更多的是用来依据真值或者假值执行相应操作!
我们知道,||
运算的时候,会先运算左侧的表达式的值,如果为真值,那么真个表达式就为真值,而同时右侧表达式是真值、假值都不重要,因为右侧表达式都不再继续参与运算了。又如果左侧为假值,则继续运算右侧表达式。
&&
则先运算左侧表达式,两侧表达式,一个为假值,则整个表达式为假值。
这里关键是这个真值或者假值的运算过程中,我们可以使用上面介绍的,
、()
将一组表达式串起来执行。也就是说,这个表达式可能会很长很长,我甚至可以定义一个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
的值,如果length
为0
则表达式为假值,如果为1
则为真值。val()
操作也是如此,如果val()
结果为""
则表达式也是假值。几个表达式之间为&&
运算,则表示依次运算几个表达式的值,如果都未真值则返回最后一个表达式的值,由于整个表达式与 "没有找到name输入框或者输入框没有值!"
表达式之间是||
运算,所以前面的表达式其中一个表达式为假值则返回||
右侧的表达式的值,也就是整个“没有找到name输入框或者输入框没有值!”
字符串。
说到这里,我之前写过一篇文章专门说到了&&
、||
的真值、假值问题。有兴趣的可以去看看。
谈了这些难以理解的运算符后,大家可能会觉得,这个javascript为什么要搞这些晦涩的运算符呢?
我的理解是因为javascript通常在客户端运行,那么从服务器端将js代码传输到客户端肯定需要耗时。上面的这些运算符都是为了减少代码量。再加上使用压缩工具去掉空格,替换变量名,就可以使用压缩率达到最好。
再这里,我也告诉大家,其实我也非常反对在实际应用中采用这种写法的,因为会对初学者造成阅读障碍。我写这篇文章的目的不是为了让大家以后就这样用,而是告诉大家可以这样用,在一些开源代码中遇到了能看懂。不可为了炫耀而故意写一些晦涩的代码。
最后,为了帮助我们更快的找到变量定义、理清代码整体结构,给大家推荐一个eclipse的js插件:Spket,支持jQuery代码提示哦!
[转]看了这个才发现jQuery源代码不是那么晦涩的更多相关文章
- 看了这个才发现jQuery源代码不是那么晦涩
很多人觉得jquery.ext等一些开源js源代码 十分的晦涩,读不懂,遇到问题需要调试也很费劲.其实我个人感觉主要是有几个方面的原因: 1.对一些js不常用的语法.操作符不熟悉 2.某个functi ...
- iPhone不为人知的功能常用技巧,看完后才发现很多用iPhone的人实在是愧对乔布斯! - imsoft.cnblogs
很多人花了四五千买部苹果,结果只用到四五百块钱的普通手机功能. iPhone不为人知的功能,常用技巧: 网上搜集整理的iPhone快捷键操作,虽然表面上iPhone按键只有一个HOME键,大部分操作都 ...
- jQuery源代码学习之九—jQuery事件模块
jQuery事件系统并没有将事件坚挺函数直接绑定在DOM元素上,而是基于事件缓存模块来管理监听函数的. 二.jQuery事件模块的代码结构 //定义了一些正则 // // //jQuery事件对象 j ...
- jQuery源代码学习之八——jQuery属性操作模块
一.jQuery属性模块整体介绍 jQuery的属性操作模块分四个部分:html属性操作,dom属性操作,类样式操作,和值操作. html属性操作(setAttribute/getAttribute) ...
- jQuery源代码学习之七—队列模块queue
一.jQuery种的队列模块 jQuery的队列模块主要是为动画模块EFFECTS提供支持,(不过到现在为了支持动画队列的inprogress的出入队还是搞不太清楚),单独抽取出一个命名空间是为了使程 ...
- jQuery源代码学习之六——jQuery数据缓存Data
一.jQuery数据缓存基本原理 jQuery数据缓存就两个全局Data对象,data_user以及data_priv; 这两个对象分别用于缓存用户自定义数据和内部数据: 以data_user为例,所 ...
- jQuery源代码学习之五——jQuery.when
jQuery.when提供了基于一个或多个对象的状态来执行回调函数的功能,通常是基于具有异步事件的异步队列. 如果传入多个异步队列,jQuery.when会返回一个新的主异步队列的只读副本(promi ...
- jQuery源代码学习之四——jQuery.callbacks
自己实现的callbacks模块相较于jquery源代码中的callbacks模块有所简化,表面上看没有考虑firing这个参数,没有对之进行任何处理,即没有考虑在函数执行过程中,再次调用add,re ...
- jQuery源代码阅读之三——jQuery实例方法和属性
jQuery实例方法及属性相关的代码结构如下 jQuery.fn=jQuery.prototype={ jQuery:core_version, constructor:jQuery, selecto ...
随机推荐
- 二项分布和Beta分布
原文为: 二项分布和Beta分布 二项分布和Beta分布 In [15]: %pylab inline import pylab as pl import numpy as np from scipy ...
- Mysql学习笔记(五)数据查询之测试sql部分。
正文之前,介绍mysql一些很有趣的命令. 快速的创建表,并填充表数据. create table test like 已经有的表名: inset into test select * from f ...
- SPOJ:ABCDEF
传送门 废话不说,这道题暴力枚举是$O(N^6)$,显然无法承受. 推导一下 $(x_1*x_2+x_3)/x_4-x_5=x_6$ $x_1*x_2+x_3=x_4*(x_5+x_6)$ 等式左边和 ...
- 9 HTML&JS等前端知识系列之Ajax post请求带有token向Django请求
我们 在母板上写入这段代码: <script type="text/javascript"> // 个人定义大函数,不是重点,可以忽略 $(document).read ...
- ObjectInputStream类和ObjectInputStream类的使用
版权声明:本文为博主原创文章,未经博主允许不得转载. ObjectInputStream和ObjectInputStream类创建的对象被称为对象输入流和对象输出流. 创建文件输出流代码: FileO ...
- ioctlsocket()
ioctlsocket()是控制套接口的模式. 外文名 ioctlsocket() 含 义 控制套接口的模式 头文件 #include <winsock.h> 性 质 函数 目 ...
- git config --global core.autocrlf false
git config --global core.autocrlf false warning: LF will be replaced by CRLF in .idea/vcs.xml.The f ...
- mysql主从复制 转
mysql服务器的主从配置,这样可以实现读写分离,也可以在主库挂掉后从备用库中恢复.需要两台机器,安装mysql,两台机器要在相通的局域网内,可以分布在不同的服务器上,也可以在一台服务器上启动多个服务 ...
- Maven打包可执行jar
参考文献:http://blog.csdn.net/xiao__gui/article/details/47341385 方法:使用assembly插件,生成的jar包名为xxx-jar-with-d ...
- spring 容器技术入门
官方文档 翻译 https://waylau.gitbooks.io/spring-framework-4-reference/content/III.%20Core%20Technologies/C ...