前言
本文是个人阅读源码、配合查找资料,将自己所见、所想记录下来的一些笔记
而主体是解析如何将部分方法实现,手动打造自己的jQuery
注:文本水平有限,并不谈论兼容性问题
正文
起步
(function (window, undefined) {
var jQuery = function() {
//...
}
//...
window.jQuery = window.$ = jQuery;
})(window);
观察这一段则能知道:
jQuery
本质是一个函数,这一点在导入了jQuery
文件后,使用typeof
检测jQuery
或者$
也能知道- 通过立刻调用函数执行后,将
jQuery
设置为window
的属性,使得可以全局使用jQuery
函数 - 同时给
$
绑定函数引用,使操作更简洁
对参数的说明:
- 减少作用域的查找,提高速度。后续还会多次看到这种操作
- 利用自定义参数名,可以将关键词的长度缩短,在压缩代码时效果更明显
undefined
参数是为了获取一个真实的undefined
,因为undefined
并非保留关键字,可以当作变量名,可以赋值,在低版本浏览器当中赋值会保留
个人的想法:
-
undefined
参数使用场景并不知道在哪,哪个地方会直接用到undefiend
这个值呢 -
函数表示式是否可以直接写成函数声明。从简化的角度看,函数表达式多了
var
和=
-
对于立刻调用的匿名函数,是否可以将换成
!
形式触发-
小括号开头有一定风险,如果上一条语句没有以分号结束,且也是小括号或者方括号结尾,则会发生错误
-
对于这一点,也可以在开头加上分号,不过就比较ugly
!function(window){ function jQuery(){} //... }(window);
-
为了更加简洁,后文无特殊说明的情况下,
$
表示jQuery
调用$()发生的事情
var jQuery = function(selector) {
return new jQuery.fn.init(selector);
}
jQuery.fn = jQuery.prototype = {
constructor: jQuery
}
jQuery.fn.init = function (selector) {
//...
}
jQuery.fn.init.prototype = jQuery.fn;
一步步分析:
- 获取的会是一个对象,此对象来自函数返回值
- 而对象来自
$
原型上的一个函数,使用new
创造的实例对象 - 并不能返回函数本身的实例对象,这会导致无限递归
- 此处就是为了省去手动使用
new
创造实例对象,使操作轻松便捷
其他事情:
-
中间添加了一个
fn
属性,赋值为prototype
,为的是将prototype
关键字缩短,能少写些就少写些 -
而赋值一个对象,是直接重写了
prototype
属性,可以在对象当中写好需要的实例方法与属性,而无需每个方法和属性前都加上prototype
这么笨重的关键字init()
可以写在当中,此处脱离出来方便观察,当然在官方源码当中也是如此
关于原型方法:
-
写在原型上的方法,是提供给构造函数和实例对象使用的。不同的实例对象,共享同一个相同的方法和属性
-
而在
$
当中,比如each
方法,它是既有静态,又有实例。当然两者效果是一致的 -
对此类方法的处理是,只添加一个静态方法,原型上再添加对静态方法的引用,也就是静态和实例共享一个方法
//静态方法 jQuery.each = function() { //..... } //实例方法 jQuery.fn.each = function() { return jQuery.each(); }
-
当然,这里是往
$
的原型上添加方法,而我们获取的并不是$
的实例对象,所以需要将两者的原型关联起来,于是就有这一步//左右顺序可不能颠倒 jQuery.fn.init.prototype = jQuery.fn;
-
因此,在写原型时将
constructor: jQuery
加入其中,将构造函数又指向了jQuery
原型中的方法构造函数和实例对象都能访问,但是构造函数使用就需要加上
prototype
前缀
个人的想法:
- 对于最后一步原型的调整,事实上我不太懂
- 如果说原型方法是通过调用静态方法使用的,那我不是也可以直接通过
init
的prototype
来调用,也可以达到一样的效果。 - 这一点我只能想到,为了简写,且能通过
$
查看prototype
来知道有哪些方法