看了 http://my249645546.iteye.com/blog/1716629 上的这篇文章感觉挺好的,所以决定转过来,谢谢这位博主。

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

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

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

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

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

一、一些晦涩的操作符:

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

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

下面是Jquery的部分源码:

  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后面,使用“,”一次定义了很多个变量。

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

  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。

我们再来看其他的用法:

  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中的一段源码:

  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在里面。这些表达式在执行过程中,有可以进行某些附加操作。比如我们希望这个表达式为真值的时候我们做什么,假值的时候做什么,把这些操作用"()"、","串起来作为一个整体运算。

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

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

  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. });

测试:

  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输入框或者输入框没有值!”字符串。

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

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

学会读JQuery等JS插件源码的更多相关文章

  1. cookie操作(jquery的cookie插件源码)

    cookie : function (key, value, options) { var days, time, result, decode; // A key and value were gi ...

  2. jquery.autocomplete.js 插件的自定义搜索规则

    这二天开始用jquery.autocomplete这个自动完成插件.功能基本比较强大,但自己在实际需求中发现还是有一处不足!问题是这样:当我定义了一个本地数据JS文件时,格式为JSON式的数组.如下: ...

  3. 在网站开发中很有用的8个 jQuery 效果【附源码】

    jQuery 作为最优秀 JavaScript 库之一,改变了很多人编写 JavaScript 的方式.它简化了 HTML 文档遍历,事件处理,动画和 Ajax 交互,而且有成千上万的成熟 jQuer ...

  4. 分享一组很赞的 jQuery 特效【附源码下载】

    作为最优秀的 JavaScript 库之一,jQuery 不仅使用简单灵活,同时还有许多成熟的插件可供选择,它可以帮助你在项目中加入漂亮的效果.这篇文章挑选了8个优秀的 jQuery 实例教程,这些  ...

  5. 第二十五课:jQuery.event.trigger的源码解读

    本课主要来讲解jQuery.event.trigger的源码解读. trigger = function(event, data, elem, onlyHandlers){ if(elem & ...

  6. 如何查看google chrome 插件源码

    常用浏览器google chrome 有很多优秀的插件,寂寞的时候想看看人家是怎么实现的,说是快那就动手吧 插件代码位置 本人mac笔记本,chrome 插件位置如下 $ cd  /Users/vin ...

  7. jquery中的 parseJSON() 源码分析

    parseJSON: function( data ) { // Attempt to parse using the native JSON parser first if ( window.JSO ...

  8. jquery.validate.js插件的使用方法

    近期做项目.须要用到 jQuery.validate.js插件,于是记录一下工作中的一些经验,以便日后学习. [样例例如以下] 1.前台页面 <form id="form1" ...

  9. vue打包时,assets目录 和static目录下文件的处理区别(nodeModule中插件源码修改后,打包后的文件应放在static目录)

    为了回答这个问题,我们首先需要了解Webpack如何处理静态资产.在 *.vue 组件中,所有模板和CSS都会被 vue-html-loader 及 css-loader 解析,并查找资源URL.例如 ...

随机推荐

  1. Android小技术知识(多用于面试)

    Android Dev Doc Android 开发 多使用内部类 使用方便且效率高 UI方面的知识 一.在编写layout的xml文件时,一定要仔细!如果在报错的时候,如何解决? 解决:将xml仔细 ...

  2. win7 配置IIS + php 环境

    一:开启win7 的IIS功能:并开启 CGI 二:下载php5 for windows 解压 三:打开IIS --->>处理程序映射- 参考:http://php.net/manual/ ...

  3. taro 填坑之路(二)taro 通过事件监听 实现组件间传值

    1.组件传值的方式 2.事件监听原理 3.事件管理器 utils/event.js /** * 事件池(事件管理器) * 通过事件监听传值 */ class Event { constructor() ...

  4. 参数依赖查找(ADL,Argument-dependent lookup)

    参数依赖查找(Argument-dependent lookup),又称 ADL 或 Koenig 查找,是一组于函数调用表达式查找非限定函数名的规则,包含对重载运算符的隐式函数调用.在通常非限定名称 ...

  5. Android Bluetooth模块学习笔记

    一.蓝牙基础知识 1.蓝牙( Bluetooth )是一种无线技术标准,可实现固定设备.移动设备和楼宇个人域网之间的短距离数据交换.蓝牙基于设备低成本的收发器芯片,传输距离近.低功耗. 2.微波频段: ...

  6. 查看IE浏览器安装的插件

      请移步至文章:http://blog.sina.com.cn/u/6452627072  

  7. 名词解释:alpha版、beta版、rc版的意思(转)

    很多软件在正式发布前都会发布一些预览版或者测试版,一般都叫“beta版”或者 “rc版”,特别是开源软件,甚至有“alpha版”,下面来解释一下各个版本的意思. alpha版:内部测试版.α是希腊字母 ...

  8. 【CI3.1】CI框架简单使用方法

    CI框架简单使用方法 1.回忆MVC 1.1.M:模型,提供数据,保存数据 1.2.V:视图,只负责显示,表单form 1.3.C:控制器,协调模型和视图 1.4.action:动作,是控制器中的方法 ...

  9. Python 字符串与数字拼接报错

    Python 不像 JS 或者 PHP 这种弱类型语言里在字符串连接时会自动转换类型,而是直接报错. 如: 上述是Python 字符串与数字拼接报错,解决办法是:使用bytes函数把int型转换为st ...

  10. FFMPEG音视频解码

    文章转自:https://www.cnblogs.com/CoderTian/p/6791638.html 1.播放多媒体文件步骤 通常情况下,我们下载的视频文件如MP4,MKV.FLV等都属于封装格 ...