先看看他的框架吧,了解了jquery的最小系统最小框架,大家等下就发现,他其实什么都没有做,这个就只是一个初始的骨架而已,当然,了解一下,对于我们应用他,还有扩展他应该是有所助益的.
另,本人js纯菜鸟一枚,生怕误导了和我一样的菜鸟阶级朋友,所以请大家在看的同时多动手,呵呵,也希望路过的大牛们顺手指正.非常感谢.
最小框架
(function(window, undefined) { var rootjQuery, core_version = "1.9.1", _jQuery = window.jQuery, _$ = window.$, jQuery = function(selector, context) { return new jQuery.fn.init(selector, context, rootjQuery); }; jQuery.fn = jQuery.prototype = { jquery: core_version, constructor: jQuery, init: function(selector, context, rootjQuery) { return this; } }; jQuery.fn.init.prototype = jQuery.fn; jQuery.extend = jQuery.fn.extend = function(dest, src) { for (var p in src) { dest[p] = src[p]; } return dest; } jQuery.extend(jQuery, { noConflict: function(deep) { if (window.$ === jQuery) { window.$ = _$; } if (deep && window.jQuery === jQuery) { window.jQuery = _jQuery; } return jQuery; } }); jQuery.extend(jQuery.fn, { method1: function(msg) { alert(msg); return this; } ,method2: function(msg) { alert(msg); return this; } }); window.jQuery = window.$ = jQuery; })(window);
jQuery.extend这个方法被我简写了,仅仅为了最小系统少几行代码,显得稍微清晰点而已.
调用示例
$().method1("Hello").method2("World!");
链式调用风格,很方便的.
如何扩展它?
(function(jQuery, undefined) { jQuery.fn.extend(jQuery.fn, { method3: function(msg) { alert("method2:" + msg); return this; } }); })(jQuery)
经过这么扩展,我们就有method3这个新的方法了,和method1等方法的调用什么都是一样的.
他是如何工作的?
首先,所有的工作都是在一个函数里面完成的(不包括扩展的部分),这是一个自运行函数,如果您对什么是自运行函数不太了解,可以参考一下函数声明,函数表达式等的资料.
先附上带代码注释吧,错漏的地方肯定不少,请大家批评指正.
/*! * jQuery 最小系统 * Date: 2013-04-25 */ //一个自运行的函数. (function(window, undefined) { var //到jQuery(document)的一个引用,所有的jquery对象都将引用到他 rootjQuery, //定义自己的版本号 core_version = "1.9.1", //通过局部变量保存可能会被覆盖的window属性 //如果用户调用jQuery.noConflict(deep)方法 //则会恢复window.jQuery和window.$的值 //目的是为了和别人和平共处互不冲突 _jQuery = window.jQuery, _$ = window.$, //我个人的理解是按jQuery().m1().m2()这种调用方式导致这么处理? //这意味着jQuery()返回的对象与m1,m2应该有相同的prototype?this? //从而,假设返回的是new init() //那么init.prototype===jQuery.prototype //那么... jQuery = function(selector, context) { //注释掉的这个有什么区别,有什么不妥吗? //如果使用了new的话,那么init函数中即使不return this应该也是可以的. //可见,new是在背后做了一些额外工作的 //详情在本文的后面有说明 //不过,刚查看到有人说了,这里用new,还有个隔离作用域的作用,表示不怎么明白,回去思考去,呵呵 //关于这个隔离作用域,在文章后面有说明. //很多不该有的注释保留,是因为这个记录了本人的思考过程,嗯,由完全不明白,到明白一些些了,呵呵 //return jQuery.fn.init(selector, context, rootjQuery); return new jQuery.fn.init(selector, context, rootjQuery); }; jQuery.fn = jQuery.prototype = { jquery: core_version, constructor: jQuery,//注释掉的话,有什么后果?在本例中倒是没什么 init: function(selector, context, rootjQuery) { return this; } }; //要让jquery()能复用jquery.fn的属性? jQuery.fn.init.prototype = jQuery.fn; //扩展对象,这个已经简化了,所以他的调用方式也就面目全非了 jQuery.extend = jQuery.fn.extend = function(dest, src) { for (var p in src) { dest[p] = src[p]; } return dest; } jQuery.extend(jQuery, { //避免冲突 noConflict: function(deep) { if (window.$ === jQuery) { window.$ = _$; } if (deep && window.jQuery === jQuery) { window.jQuery = _jQuery; } return jQuery; } }); jQuery.extend(jQuery.fn, { //定义自己的方法,没啥用 method1: function(msg) { alert("method1:" + msg); //都记得要返回,从而实现链式调用 return this; } , method2: function(msg) { alert("method2:" + msg); return this; } }); //最顶级的jquery对象,所有其他jquery都将引用到他 rootjQuery = jQuery(document); //不管这两属性是否会冲突,用了再说 //等用户自己调用noConflict吧,如果冲突的话 window.jQuery = window.$ = jQuery; })(window);
补充一点,本人一直迷糊的地方,就是,看看一个对象是如何new出来的?
最好当然是看ECMA文档了,下面的这个请在FF,Chrome下测试哦,IE就自动忽略吧.
var JSEngine = function(fn) { var This = this; this.constructor = fn; //伪代码 this.newObject = function() { var o = {}//创建一个原生对象 , _constructor = This.constructor; //查看构造函数的prototype类型是否为object //是则将对象的内部属性Prototype应用到它 //否则此属性指向Object.prototype if (typeof _constructor.prototype === "object") { o.__proto__ = _constructor.prototype; } else { o.__proto__ = Object.prototype; //{}? } //调用构造函数 var o2 = _constructor.apply(o, arguments); //如果返回的是对象,则返回这个o2,否则返回o if (typeof o2 === "object") { return o2; } else { return o; } } }
从上面的代码可以看出,当使用new构建一个对象的时候,总是会返回一个object,这也是为什么前面使用:
return
new
jQuery.fn.init(selector, context, rootjQuery);
而不是return
jQuery.fn.init(selector, context, rootjQuery);
的原因(我个人猜想的啊,主要是我没有看出有别的不妥的地方,请过路的大牛指点啊!!!后来才明白,其实应该是后面说道的隔离作用域的原因啊)
补充,刚从有些资料上看到,说此处用new是为了隔离作用域,哎,还得学习啊!!!
测试代码如下:
function fn1() { this.name = "AAA"; } var js = new JSEngine(fn1); var o1 = js.newObject(); var o2 = new fn1(); alert(o1.name); //AAA alert(o2.name); //AAA alert(o1 instanceof fn1); //true alert(o2 instanceof fn1); //true
那么,正常的函数调用会是什么样子呢?正常的函数调用的话看看下面的伪代码:
function callFunction(fn, caller) { caller = caller || window; fn.apply(caller); }
这里的caller与arguments.callee.caller是两码事.
由上面的伪代码看出,fn函数体内部的this,指向的就是caller. 那么,这个caller是什么?就是函数的调用者,常见有如下形式:
fn();//caller 默认就是全局对象 x.y.fn();//caller就是x.y
其实一般的场景都是这么简单的.那么,我们应该能够理解内部构造函数jQuery内部为什么是:
return new jQuery.fn.init(selector, context, rootjQuery);
而非
return jQuery.fn.init(selector, context, rootjQuery);
了吧? 前者得到的都是一个全新的对象(那么,作用域隔离的目的).后者的话,在init内部return this的话,总是得到同一个对象,那就是jQuery.fn, 这个意味着$()在任何地方都得到了一个唯一的相同的对象,这个就不能实现我们的目标了.
强烈推荐大家看《深入理解JavaScript系列》
最后,感谢John大神!!!