先看看他的框架吧,了解了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大神!!!