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

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

1、对一些js不常用的语法、操作符不熟悉

2、某个function中又嵌套了一些内部的function,使得整个代码的层次结构不像java代码那么清晰。

3、js中允许变量先使用后定义,会造成我们看代码时候忽然冒出来一个变量、function,却找不到是在哪里定义的。

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

一、一些晦涩的操作符:

1、(function(){})();

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

下面是Jquery的部分源码:

Js代码 
 

  1. (function( window, undefined ) {

  2. var jQuery = function( selector, context ) {

  3. // The jQuery object is actually just the init constructor ‘enhanced‘

  4. return new jQuery.fn.init( selector, context );

  5. },
  6. // Map over jQuery in case of overwrite

  7. _jQuery = window.jQuery,
  8. // Map over the $ in case of overwrite

  9. _$ = window.$,

  10. ……

  11. indexOf = Array.prototype.indexOf;
  12. // Expose jQuery to the global object

  13. window.jQuery = window.$ = jQuery;

  14. })(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(){})()用来封装一些私有成员或者公共成员的导出。

2、令人迷惑的","

我们知道“,”一般用于一次定义多个变量、定义多个参数等。像上面的jQuery源码中在var
jQuery后面,使用“,”一次定义了很多个变量。

但是,像下面的代码,可能大家就不一定看得懂了:

Js代码 
 

  1. //html:<input type="hidden" value="king" id="nameHide"/>

  2. jQuery(document).ready(function() {

  3. var showName=function(){

  4. var value,nameInput=$("#nameHide");

  5. return nameInput.show(),value=nameInput.val();

  6. };

  7. alert(showName());

  8. });

  9. //结果:弹出king

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

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

3、“()”广义上的代码包装

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

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

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

我们再来看其他的用法:

Js代码 
 

  1. //html:<input value="kings" id="name"/><div id="nameErrorTip">输入错误!</div>

  2. jQuery(document).ready(function() {

  3. var nameValidate=function(){

  4. var value,nameInput=$("#name"),nameErrorTip=$("#nameErrorTip");

  5. return (value=nameInput.val(),value=="king")?(nameErrorTip.hide(),"对了,输入为king!"):(nameErrorTip.show(),"请输入king!");

  6. };

  7. alert(nameValidate());

  8. });
  9. //结果 nameErrorTip显示,弹出"请输入king!"
  10. //html:<input value="king" id="name"/><div id="nameErrorTip">输入错误!</div>

  11. //结果 nameErrorTip隐藏,弹出"对了,输入为king!"

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

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

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

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

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

Js代码 
 

  1. e.circular || (f.onBeforeSeek(function(a, b) {

  2. setTimeout(function() {

  3. a.isDefaultPrevented()

  4. || (n.toggleClass(e.disabledClass,

  5. b <= 0), o.toggleClass(

  6. e.disabledClass, b >= f

  7. .getSize()

  8. - 1))

  9. }, 1)

  10. }), e.initialIndex || n.addClass(e.disabledClass)), f.getSize() < 2

  11. && n.add(o).addClass(e.disabledClass), e.mousewheel

  12. && a.fn.mousewheel && b.mousewheel(function(a, b) {

  13. if (e.mousewheel) {

  14. f.move(b < 0 ? 1 : -1, e.wheelSpeed || 50);

  15. return !1

  16. }

  17. });

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

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

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

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

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

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

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

另外,大家注意:下面的写法是等价的:

Js代码 
 

  1. if(a){

  2. b

  3. }

  4. //等价于

  5. a&&(b)

  6. //b可以是一个function调用表达式,或者是多个语句用","串起来

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

Js代码 
 

  1. jQuery(document).ready(function() {

  2. var nameValidate=function(){

  3. var value,nameInput=$("#name"),nameErrorTip=$("#nameErrorTip"),msg;

  4. msg=(value=nameInput.val(),value=="king")?(nameErrorTip.hide(),"对了,输入为king!"):(nameErrorTip.show(),"请输入king!");

  5. return (nameInput.length&&nameInput.val()&&nameErrorTip.length&&msg)||"没有找到name输入框或者输入框没有值!";

  6. };

  7. alert(nameValidate());

  8. });

测试:

Js代码 
 

  1. //html:<input value="king" id="myName"/>

  2. //结果:弹出“没有找到name输入框或者输入框没有值!”
  3. //<input value="king" id="name"/><div id="nameErrorTip">输入错误!</div>

  4. //结果:弹出“对了,输入为king!”,nameErrorTip被隐藏

return表示中 nameInput.length&&nameInput.val()&&nameErrorTip.length&&msg会先运算 nameInput.length的值,如果length为0则表达式为假值,如果为1则为真值。val()操作也是如此,如果val()结果为""则表达式也是假值。几个表达式之间为&&运算,则表示依次运算几个表达式的值,如果都未真值则返回最后一个表达式的值,由于整个表达式与

"没有找到name输入框或者输入框没有值!"

表达式之间是||运算,所以前面的表达式其中一个表达式为假值则返回||右侧的表达式的值,也就是整个“没有找到name输入框或者输入框没有值!”字符串。

说到这里,我之前写过一篇文章专门说到了&&、||的真值、假值问题。有兴趣的可以去看看。http://my249645546.iteye.com/blog/1553202

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

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

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

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

时间: 2024-09-29 16:20:49

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

[转]看了这个才发现jQuery源代码不是那么晦涩

很多人觉得jquery.ext等一些开源js源代码 十分的晦涩,读不懂,遇到问题需要调试也很费劲.其实我个人感觉主要是有几个方面的原因: 对一些js不常用的语法.操作符不熟悉 某个function中又嵌套了一些内部的function,使得整个代码的层次结构不像java代码那么清晰. js中允许变量先使用后定义,会造成我们看代码时候忽然冒出来一个变量.function,却找不到是在哪里定义的. 那么今天给大家分享一下我的经验,扫清你的障碍. 一些晦涩的操作符: (function(){})();

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

一.jQuery数据缓存基本原理 jQuery数据缓存就两个全局Data对象,data_user以及data_priv; 这两个对象分别用于缓存用户自定义数据和内部数据: 以data_user为例,所有用户自定义数据都被保存在这个对象的cache属性下,cache在此姑且称之为自定义数据缓存: 自定义数据缓存和DOM元素/javascript对象通过id建立关联,id的查找通过DOM元素/javascript元素下挂载的expando属性获得 话不多说,直接上代码.相关思路在代码注释中都有讲解

我上了985,211,才发现自己一无所有 | 或者,也不能这么说

我是在很久以后才意识到原来那些看起来光鲜亮丽的人心里也是在自卑的. 这个发现很偶然,是有一次我的学霸舍友回来,非常非常不开心,趴在桌子上很久很久没有起来. 我打着炉石呢,觉得不对劲回过头说你怎么了.她抬起头来说,哎,我才发现人与人的差距这么大.你不知道我今天参加讨论课,有个女生全英文演讲多精彩,那么流利,轮到我就磕磕巴巴的. 我说没事你也挺厉害,天天回来就学习,演讲不行,咱考试还考不了高分吗? 我那很厉害的舍友说,不是这样的,你知道吗,不光英文,那个女生长得也特别好看,妆容也精致,站在台上那么的

我以为我学懂了数据结构,看到这张导图,我才发现我错了

一个人对人民的服务不一定要站在大会上讲演或是做什么惊天动地的大事业,随时随地,点点滴滴地把自己知道的想到的告诉人家,无形中就是替国家播种垦植. -- 傅雷 本文已经收录至我的GitHub,欢迎大家踊跃star 和 issues. https://github.com/midou-tech/articles 点关注,不迷路?????? ?下面的数据结构知识点都掌握了,那说明你复习的很不错了.图片看不清可以加我微信,给你私发pdf文件.(偷偷告诉你,微信搜索 龙跃十二 关注公众号,点击联系作者即可获

好烦啊,最后才发现布局有错误

word天,费尽心思敲了那么多内容,前前后后忙活了差不多一个星期,最后才发现有毛病,啊啊啊啊啊啊啊!气死我了,偏偏能力还不够,脑子又乱,根本就找不到解决的方法--真特么的--阿弥陀佛,老夫又说脏话了,无量天尊. 坑爹! 还有,天猫好好的搞什么双十二,页面啥的都不一样了有木有! ╭(╯^╰)╮,sinatensie!几欲疯狂--前几天绝对是脑子抽风了,绝对是脑子抽风了,好好的搞甚个天喵,喵了个咪!

关于 iOS 的 StoryBoard,接受的那一刻才发现她的美 - 当然美的事物都需要业心照料

关于 iOS 的 StoryBoard,接受的那一刻才发现她的美 - 当然美的事物都需要业心照料 太阳火神的美丽人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转载请保留此句:太阳火神的美丽人生 -  本博客专注于 敏捷开发及移动和物联设备研究:iOS.Android.Html5.Arduino.pcDuino,否则,出自本博客的文章拒绝转载或再转载,谢谢合作. 先来点儿粗的,StoryBoard 你是从哪儿来

阅读jQuery源代码带给我们的18个惊喜

相信大家都非常熟悉jQuery类库,绝对最受欢迎的JS框架,如果你也有兴趣阅读v源代码的话,或者你也会有同感. 以下便是阅读jQuery源代码后挖掘的18条令人惊奇的信息: 原文:阅读jQuery源代码带给我们的18个惊喜 1. sizzle的大小 Sizzle是用来帮助jQuery实现DOM查询操作的引擎,可能你不知道它占用了jQuery源代码的22%. 其次最大的特性是$.ajax,占用了jQuery源代码中的8%. 2. $.grep 这个方法类似underscore中的_.filter方

Python爬虫开发的3大难题,别上了贼船才发现,水有多深

写爬虫,是一个非常考验综合实力的活儿.有时候,你轻而易举地就抓取到了想要的数据:有时候,你费尽心思却毫无所获. 好多Python爬虫的入门教程都是一行代码就把你骗上了"贼船",等上了贼船才发现,水好深-比如爬取一个网页可以是很简单的一行代码: r = requests.get('http://news.baidu.com') 非常的简单,但它的作用也仅仅是爬取一个网页,而一个有用的爬虫远远不止于爬取一个网页. 一个有用的爬虫,只需两个词来衡量: 数量:能否抓全所有该类数据 效率:抓完所

jQuery源代码解析(3)—— ready载入、queue队列

ready.queue放在一块写,没有特殊的意思,仅仅是相对来说它俩可能源代码是最简单的了.ready是在dom载入完毕后.以最高速度触发,非常实用. queue是队列.比方动画的顺序触发就是通过默认队列'fx'处理的. (本文採用 1.12.0 版本号进行解说,用 #number 来标注行号) ready 非常多时候,我们须要尽快的载入一个函数,假设里面含有操作dom的逻辑,那么最好在dom刚刚载入完毕时调用.window的load事件会在页面中的一切都载入完毕时(图像.js文件.css文件.