jQuery源码个人心得(1)

jquery版本v1.8.3

首先整体看jQuery的代码组织结构

(function( window, undefined ) {
......
window.jQuery = window.$ = jQuery;
})( window );

通过执行匿名函数,将jQuery引入到全局作用域window名下。

关于这里为何要将window对象传入,个人觉得:

1.就是要绑定jQuery对象到window对象(要将jQuery对象暴露到全局作用域,以执行匿名函数的方式,可以不用传递window对象就将其暴露到全局作用域吗?)

通过函数返回jQuery对象应该也可以实现此功能,代码如下:

var jQuery =
(function(  ) {
......
return jQuery;
})( );

var $ = jQuery;

作者传递window对象肯定还另有其他原因。下面是参考网上的帖子:

[url]http://hi.baidu.com/tang_guangyao/item/8aaae79d88454c9b82d2950d

[/url]

2.将window对象作为匿名函数的形参,当在jQuery代码块中访问window时,不需要将作用域链回退到顶层作用域,这样可以更快的访问window考虑如果jQuery中对window对象的属性访问很频繁,这个开销就必须考虑了。

3.另外,由于window作为函数的形参,所有在代码压缩的时候就能够得到进一步的优化,例如,将window用a代替

(function( a, undefined ) {
......
a.jQuery = a.$ = jQuery;
})( window );

天晓得作者当时是否考虑到代码压缩这一点!

另外一个让人奇怪的地方就是,匿名函数定义了一个undefined形参,估计很多和我一样的新人在开始看源码时心情一样的,这是在干嘛呀!

引用

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

这个是网上找到的解释。

上面的原因很费解,运行下面的代码你发现undefined依然被改变了。

function test(undefined) { 
	console.log(undefined);
	undefined='a'; 
	console.log(undefined);
	console.log(typeof undefined);
	console.log(window.undefined === undefined);
}
test();

这里其实作者的意思是undefined这个全局属性没法保证正确。如果直接使用undefined。有可能undefined的值已经被修改过了。

这里给匿名函数定义一个不会传递实参的形参。目的是确保这个undefined变量是真的未定义。至于匿名函数内部,作者确保不会修改函数的形参undefined就是了。

undefined能够修改的根源在于undefined是一个全局属性,在ECMASCRIPT3中undefined时可读写的,导致undefined有可能在使用前被认为修改。但是在ECMASCRIPT5规范中undefined已经定义为只读了。[P44javascript权威指南]

曾经看过一篇文章,里面有一句话“倘若JohnResig个人不再维护jQuery,还有谁能够看懂他的这一坨坨”;

JohnResig大牛的世界岂能被一般人看穿,不过jQuery的代码的却很晦涩.

jQuery对象从何而来,见下面

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

我们每次$('xxx')的时候其实都在newjQuery.fn.init。

接下来

jQuery.fn = jQuery.prototype = {
	constructor: jQuery,
	init: function( selector, context, rootjQuery ) {
	......
	}
	......
}

这里要补充一下,是函数都会有一个prototype属性,是对象都会有一个__init__属性,指向构建该对象的对象的原型,比较绕

再往下看

jQuery.fn.init.prototype = jQuery.fn;

三段代码,真要看明白,必须对js的基础概念有一定的理解。

首先就是原型式继承的理解,关于原型式继承的详细介绍可以参考网上更专业的文章,原型式继承核心的一个东西就是prototype属性,

前文说过,函数就会有一个prototype属性,通过在prototype属性上添加属性和方法,就可以为以该函数为构造函数的对象扩充属性和方法。

returnnewjQuery.fn.init(selector,context,rootjQuery);这一句代码就有很大的迷惑性。千万别掉进这个代码中。

第一段代码中其实就是定义了一个变量jQuery变量,并将一个函数赋予这个变量

你可以在解释器中执行如下代码:

varj=function(){returnnewj.fn.init();}

你会看到j仅仅一个函数,并且也不存在语法错误。

接着看第二段代码,是函数就会有prototype属性,这里对jQuery这个函数的prototype属性进行了扩充,如同大家扩充String对象的indexOf方法一样

这里的扩充是希望达到类似的效果

vars=newString('abc');s.indexOf('a');

同理

varj=newjQuery();j.xxx();

但一般我们不这么用,我们这样用$('id');对应到代码一中就是newjQuery.fn.init('id');

别急这里就有另外一个问题啦,那就是如何给jQuery对象自我扩充的能力呢?

请看第三段代码。

这里我们将jQuery的属性fn赋予了jQuery.fn.init.prototype,而jQuery.fn.init就是我们调用jQuery对象时new的那个对象,

这样,我们在扩充jQuery的fn属性时就间接地扩充了jQuery对象的能力。

相关推荐