`
nuysoft
  • 浏览: 516671 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
91bd5d30-bd1e-3b00-9210-87db1cca0016
jQuery技术内幕
浏览量:198735
社区版块
存档分类
最新评论

[原创] jQuery源码分析-01总体架构

阅读更多

1. 总体架构

1.1        自调用匿名函数 self-invoking anonymous function

打开jQuery源码,首先你会看到这样的代码结构:

(function( window, undefined ) {

    // jquery code

})(window);

1.     这是一个自调用匿名函数。什么东东呢?在第一个括号内,创建一个匿名函数;第二个括号,立即执行

2.     为什么要创建这样一个“自调用匿名函数”呢?

通过定义一个匿名函数,创建了一个“私有”的命名空间,该命名空间的变量和方法,不会破坏全局的命名空间。这点非常有用也是一个JS框架必须支持的功能,jQuery被应用在成千上万的JavaScript程序中,必须确保jQuery创建的变量不能和导入他的程序所使用的变量发生冲突。

3.     匿名函数从语法上叫函数直接量,JavaScript语法需要包围匿名函数的括号,事实上自调用匿名函数有两种写法(注意标红了的右括号):

(function() {

    console.info( this );

    console.info( arguments );

}( window ) );

(function() {

    console.info( this );

    console.info( arguments );

})( window );

4.     为什么要传入window呢?

通过传入window变量,使得window由全局变量变为局部变量,当在jQuery代码块中访问window时,不需要将作用域链回退到顶层作用域,这样可以更快的访问window;这还不是关键所在,更重要的是,将window作为参数传入,可以在压缩代码时进行优化,看看jquery-1.6.1.min.js

(function(a,b){})(window); // window 被优化为 a   

5.     为什么要在在参数列表中增加undefined呢?

自调用匿名函数 的作用域内,确保undefined是真的未定义。因为undefined能够被重写,赋予新的值。

undefined = "now it's defined";

alert( undefined );

浏览器测试结果:

浏览器

测试结果

结论

ie

now it's defined

可以改变

firefox

undefined

不能改变

chrome

now it's defined

可以改变

opera

now it's defined

可以改变

6.     注意到源码最后的分号了吗?

分号是可选的,但省略分号并不是一个好的编程习惯;为了更好的兼容性和健壮性,请在每行代码后加上分号并养成习惯。

1.2        总体架构

接下来看看在 自调用匿名函数 中都实现了什么功能,按照代码顺序排列:

(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的源码结构相当清晰、条理,不像代码那般晦涩和让人纠结。

后边的章节基本将以这个顺序展开。

1.3        下节预告

如果你看过jQuery源码,很快就会发现这里到处充斥着正则表达式,而很多JavaScript开发人员又疏于正则基础知识,为了扫清这个障碍,下一章将先温习JavaScript正则表达式的基础知识,再详细剖析jQuery中的正则表达式。

在正式开始分析源码之前,还有没有要准备的基础知识呢?

当然有。比如JavaScript API中的类和对象,如果你不熟练的话,至少手头要有一本参考手册。

除了正则,其他的知识点会在分析过程中穿插讲解,不计划辟出新的章节。

60
0
分享到:
评论
45 楼 青春依旧 2017-12-14  
学习html5哪里好?当然华清远见是首选!
44 楼 levinqdl 2014-06-19  
viewsoft 写道
“// fail”均调用不到fn test,向楼主请教一下原因或者分析一下jquery在函数作用域链中如何处理window的?
	<script>
		$(function(){
		 	window.test = function(){
		 		alert('test');
		 	};
		});
		// ok
		$(function(){
		 	test();
		});
		
		// fail 
		(function(){
		 	window.test();
		})();
				
		// fail 
		$(function(w){
		 	w.test();
		}(window));
		
		// fail 
		(function(w){
		 	w.test();
		})(window);

	</script>

三个fail是因为它们执行时,window.test = function(){...}还没有执行,如果这句先执行过了,就都正常执行了
43 楼 perwarz 2014-01-16  
为什么$("")返回的会是一个数组?搞了好久没搞明白
init: function( selector, context, rootjQuery ) {
		var match, elem;

		// HANDLE: $(""), $(null), $(undefined), $(false)
		if ( !selector ) {
			return this;
		}
}
这不应该是个对象么
42 楼 disanxian 2014-01-13  
javatozhang 写道
willwen 写道
万能的楼主,自调用匿名函数中的成员变量在函数外是不是都不可访问的?
如:var module1 = (function(){
    _count = 0;
    var m1 = function(){
      //...
    };
    var m2 = function(){
      //...
    };
    return {
      m1 : m1,
      m2 : m2
    };
  })();
    alert(module1._count);---输出undefined

可不可以这样理解。因为你的module1是自执行函数为其赋的值。而这个自执行函数执行后返回值为仅仅包含m1、m2变量的对象。你使用 alert出 module1这个已经赋值过的对象中找_count当然不能找到了。不知道可不可以这样理解……

刚刚引错了。。应该是这个。。_count是全局变量吧。。。
41 楼 disanxian 2014-01-13  
yuenkin 写道
hanazawakana 写道
nuysoft 写道
chenyi056 写道
JS中参数不是按值传递的么?那传进去的window参数应该只是window对象的拷贝吧?在函数内部对window对象做修改,会影响到全局的window对象么?

基本类型按值传递,对象传入引用,函数内部的 window 即全局 window。


看这样一个例子

<script type="text/javascript">
function setName(obj){
    obj.name = "xiaobai";
    obj = new Object();
    obj.name = "xiaohei";
}
var dog = new Object();
setName(dog);
console.log(dog.name);
/*输出
*xiaobai
*/
</script>


JS的函数传参应该都是传值吧,即使是一个对象作为参数,也只是传递的这个对象的引用的一个复制。难道我理解错了??




你传递的obj指针是按值传递的,函数调用结束后obj还指向调用前的obj

是不是因为_count成为了全局变量啊。。。console.log(_count)就可以。。
40 楼 yongjian1092 2013-10-22  
这几个问题,每一个问题都问的恰到好处!! 
39 楼 javatozhang 2013-05-25  
447214075 写道
hanazawakana 写道
nuysoft 写道
chenyi056 写道
JS中参数不是按值传递的么?那传进去的window参数应该只是window对象的拷贝吧?在函数内部对window对象做修改,会影响到全局的window对象么?

基本类型按值传递,对象传入引用,函数内部的 window 即全局 window。

看这样一个例子
<script type="text/javascript">
function setName(obj){
    obj.name = "xiaobai";
    obj = new Object();
    obj.name = "xiaohei";
}
var dog = new Object();
setName(dog);
console.log(dog.name);
/*输出
*xiaobai
*/
</script>

JS的函数传参应该都是传值吧,即使是一个对象作为参数,也只是传递的这个对象的引用的一个复制。难道我理解错了??

var dog = new Object(); dog 是一个引用,指向一块内存,将dog传入setName,在setName中修改name属性,能直接反应到dog中,对传入的引用重新赋值,让它重新指向另外一个区域,然后修改name属性,因为引用重置了,这个修改只会对内部那个新对象有用,对外部的dog已无影响。

引用《javascript高级程序设计》书中的一句话回答:当在函数内部重写引用对象obj时,这个变量引用的就是一个局部对象了。而这个局部对象会在函数执行完毕后立即销毁。
可以把ECMAScript函数的参数想想成局部变量。
38 楼 447214075 2013-05-24  
hanazawakana 写道
nuysoft 写道
chenyi056 写道
JS中参数不是按值传递的么?那传进去的window参数应该只是window对象的拷贝吧?在函数内部对window对象做修改,会影响到全局的window对象么?

基本类型按值传递,对象传入引用,函数内部的 window 即全局 window。


看这样一个例子

<script type="text/javascript">
function setName(obj){
    obj.name = "xiaobai";
    obj = new Object();
    obj.name = "xiaohei";
}
var dog = new Object();
setName(dog);
console.log(dog.name);
/*输出
*xiaobai
*/
</script>


JS的函数传参应该都是传值吧,即使是一个对象作为参数,也只是传递的这个对象的引用的一个复制。难道我理解错了??



var dog = new Object(); dog 是一个引用,指向一块内存,将dog传入setName,在setName中修改name属性,能直接反应到dog中,对传入的引用重新赋值,让它重新指向另外一个区域,然后修改name属性,因为引用重置了,这个修改只会对内部那个新对象有用,对外部的dog已无影响。
37 楼 anole1982 2013-05-16  
javatozhang 写道
anole1982 写道
辛苦了博主!
请教个问题 jquery $(selector)方法 $.trim()
jquery 即使方法也是对象
怎么做到的?

这块很不理解 劳烦 博主解答!

查看jQuery1.6.4源代码如下:
(function( window, undefined ) {
// Use the correct document accordingly with window argument (sandbox)
var document = window.document,
navigator = window.navigator,
location = window.location;
.......
该trim函数是通过jQuery的extend方法实现继承的。这就需要你理解jQuery.extend的功能了。
不知道说的这么多你理解否?


多谢楼主解答,醍醐灌顶呀
36 楼 viewsoft 2013-05-03  
“// fail”均调用不到fn test,向楼主请教一下原因或者分析一下jquery在函数作用域链中如何处理window的?
	<script>
		$(function(){
		 	window.test = function(){
		 		alert('test');
		 	};
		});
		// ok
		$(function(){
		 	test();
		});
		
		// fail 
		(function(){
		 	window.test();
		})();
				
		// fail 
		$(function(w){
		 	w.test();
		}(window));
		
		// fail 
		(function(w){
		 	w.test();
		})(window);

	</script>
35 楼 javatozhang 2013-05-03  
anole1982 写道
辛苦了博主!
请教个问题 jquery $(selector)方法 $.trim()
jquery 即使方法也是对象
怎么做到的?

这块很不理解 劳烦 博主解答!

查看jQuery1.6.4源代码如下:
(function( window, undefined ) {
// Use the correct document accordingly with window argument (sandbox)
var document = window.document,
navigator = window.navigator,
location = window.location;

var jQuery = (function() {
// Define a local copy of jQuery
   var jQuery = function( selector, context ) {
      // The jQuery object is actually just the init constructor 'enhanced'
return new jQuery.fn.init( selector, context, rootjQuery );
},
     ......

    return jQuery;//返回的这个就是var jQuery = function( selector, context ) {}
})();
......
window.jQuery = window.$ = jQuery;
})(window);
//解决你的问题1.   $(selector)
调用的是如下代码:
var jQuery = function( selector, context ) {
      // The jQuery object is actually just the init constructor 'enhanced'
      return new jQuery.fn.init( selector, context, rootjQuery );
}//说到最后还是 new 了jQuery.fn.init的一个实例,使用selector作为参数。
//解决你的问题2.   $.trim()
// Use native String.trim function wherever possible
jQuery.extend({
......
trim: trim ?
function( text ) {
return text == null ?
"" :
trim.call( text );
} :
// Otherwise use our own trimming functionality
function( text ) {
return text == null ?
"" :
text.toString().replace( trimLeft, "").replace( trimRight, "" );
},
......});
该trim函数是通过jQuery的extend方法实现继承的。这就需要你理解jQuery.extend的功能了。
不知道说的这么多你理解否?
34 楼 javatozhang 2013-05-03  
yuenkin 写道
hanazawakana 写道
nuysoft 写道
chenyi056 写道
JS中参数不是按值传递的么?那传进去的window参数应该只是window对象的拷贝吧?在函数内部对window对象做修改,会影响到全局的window对象么?

基本类型按值传递,对象传入引用,函数内部的 window 即全局 window。


看这样一个例子

<script type="text/javascript">
function setName(obj){
    obj.name = "xiaobai";
    obj = new Object();
    obj.name = "xiaohei";
}
var dog = new Object();
setName(dog);
console.log(dog.name);
/*输出
*xiaobai
*/
</script>


JS的函数传参应该都是传值吧,即使是一个对象作为参数,也只是传递的这个对象的引用的一个复制。难道我理解错了??




你传递的obj指针是按值传递的,函数调用结束后obj还指向调用前的obj

在函数setName内部给obj参数添加了一个属性name、然后将引用变量obj重新赋值为空对象。这个obj的重新定义只是在函数内部起到效果、函数之外obj还是指向原来的地址。所以输出:xiaobai。我可以这样解释吗?
33 楼 anole1982 2013-04-23  
辛苦了博主!
请教个问题 jquery $(selector)方法 $.trim()
jquery 即使方法也是对象
怎么做到的?

这块很不理解 劳烦 博主解答!
32 楼 yuenkin 2013-04-19  
hanazawakana 写道
nuysoft 写道
chenyi056 写道
JS中参数不是按值传递的么?那传进去的window参数应该只是window对象的拷贝吧?在函数内部对window对象做修改,会影响到全局的window对象么?

基本类型按值传递,对象传入引用,函数内部的 window 即全局 window。


看这样一个例子

<script type="text/javascript">
function setName(obj){
    obj.name = "xiaobai";
    obj = new Object();
    obj.name = "xiaohei";
}
var dog = new Object();
setName(dog);
console.log(dog.name);
/*输出
*xiaobai
*/
</script>


JS的函数传参应该都是传值吧,即使是一个对象作为参数,也只是传递的这个对象的引用的一个复制。难道我理解错了??




你传递的obj指针是按值传递的,函数调用结束后obj还指向调用前的obj
31 楼 javatozhang 2013-03-30  
willwen 写道
万能的楼主,自调用匿名函数中的成员变量在函数外是不是都不可访问的?
如:var module1 = (function(){
    _count = 0;
    var m1 = function(){
      //...
    };
    var m2 = function(){
      //...
    };
    return {
      m1 : m1,
      m2 : m2
    };
  })();
    alert(module1._count);---输出undefined

可不可以这样理解。因为你的module1是自执行函数为其赋的值。而这个自执行函数执行后返回值为仅仅包含m1、m2变量的对象。你使用 alert出 module1这个已经赋值过的对象中找_count当然不能找到了。不知道可不可以这样理解……
30 楼 willwen 2013-03-29  
万能的楼主,自调用匿名函数中的成员变量在函数外是不是都不可访问的?
如:var module1 = (function(){
    _count = 0;
    var m1 = function(){
      //...
    };
    var m2 = function(){
      //...
    };
    return {
      m1 : m1,
      m2 : m2
    };
  })();
    alert(module1._count);---输出undefined
29 楼 zjf_sdnu 2013-03-27  
hanazawakana 写道


看这样一个例子

<script type="text/javascript">
function setName(obj){
    obj.name = "xiaobai";
    obj = new Object();
    obj.name = "xiaohei";
}
var dog = new Object();
setName(dog);
console.log(dog.name);
/*输出
*xiaobai
*/
</script>


JS的函数传参应该都是传值吧,即使是一个对象作为参数,也只是传递的这个对象的引用的一个复制。难道我理解错了??



obj是dog的一个复制,所以修改obj指向别的对象对dog没影响。
28 楼 hanazawakana 2013-03-19  
nuysoft 写道
chenyi056 写道
JS中参数不是按值传递的么?那传进去的window参数应该只是window对象的拷贝吧?在函数内部对window对象做修改,会影响到全局的window对象么?

基本类型按值传递,对象传入引用,函数内部的 window 即全局 window。


看这样一个例子

<script type="text/javascript">
function setName(obj){
    obj.name = "xiaobai";
    obj = new Object();
    obj.name = "xiaohei";
}
var dog = new Object();
setName(dog);
console.log(dog.name);
/*输出
*xiaobai
*/
</script>


JS的函数传参应该都是传值吧,即使是一个对象作为参数,也只是传递的这个对象的引用的一个复制。难道我理解错了??


27 楼 cctvsdlkno1 2013-03-10  
tdwyx 写道
引用
将window作为参数传入,可以在压缩代码时进行优化


这个还真没想到 

26 楼 javatozhang 2013-03-01  
无论是js语言还是java语言参数的传递无论是基本类型参数还是对象类型参数都是值传递呀!楼主的回答不对吧?

相关推荐

Global site tag (gtag.js) - Google Analytics