在了解zepto.Z函数之前,有必要了解一下原型链,继承等方面的知识。推荐阅读下以下博客:深入理解JavaScript原型和闭包
每个函数都有一个prototype(原型),这个函数的原型的constructor属性指向它自己。通过new操作符出来的实例都有一个__proto__(我们可以称之为隐式原型),指向创建它的函数的prototype(原型)。
下面是成立的:
var obj = new Function();
obj.prototype.constructor === obj; //true
obj.__proto__ === Function.prototype // true
查找obj的属性时,会先从自身去查找,如果有就返回该属性,然后结束查找。如果没有就沿着obj的原型链查找,有则返回。所有通过new操作符生成的实例函数都能继承来自obj.__proto__中的属性。
可对比以下两段代码:
var obj = new Function();
obj.__proto__ === Function.prototype // true
obj.info // undefined
obj.info = "李厚春";
obj.info // "李厚春"
obj.__proto__.info = "前端攻城狮";
obj.info //"李厚春"
var obj= new Function();
obj.__proto__ === Function.prototype // true
obj.info // undefined
obj.__proto__.info = "前端攻城狮";
obj.info //"前端攻城狮"
这样就实现了继承:obj本身没有info属性,它继承了来自obj.__proto__中的属性。
zepto.Z()函数在源码(指的是带注释的zepto.js)172行中是这样定义的:
zepto.Z = function(dom, selector) {
return new Z(dom, selector)
}
它返回了一个由Z()函数通过new操作符生成的构造函数。
即:
zepto.Z.__proto__ === Z.prototype
源码408行:
$.fn = {
constructor: zepto.Z,
//....
}
指定了$.fn的constructor属性值:zepto.Z。
即:
$.fn.constructor = zepto.Z
结合源码的938行(zepto.Z.prototype = Z.prototype = $.fn):
//拆开看
zepto.Z.prototype = $.fn
把zepto.Z的原型指定为:$.fn。
即:
zepto.Z.prototype.constructor === zepto.Z
(这就实现了zepto.Z的原型的constructor属性指向它自己: zepto.Z)。
下面代码:
Z.prototype = $.fn
Z.prototype = $.fn 把Z的原型修改为 $.fn
因为zepto.Z是由Z通过new操作符生成的实例。
(这里就实现了zepto.Z的隐式原型(__proto__)就指向创建它的函数的原型(Z.prototype),即指向了 $.fn。)
即:
zepto.Z.__proto__ = == $.fn。
红字部分的逻辑就保证了zepto.Z符合JavaScript原型和继承关系的逻辑。
由上: zepto.Z就继承了$.fn的属性和方法。
源码的408-849行定义了$.fn的属性和方法。
回头缕一下思路:
var Zepto = (function(){
var $,
zepto = {};
function Z(dom, selector) {
var i, len = dom ? dom.length : 0
for (i = 0; i < len; i++) this[i] = dom[i]
this.length = len
this.selector = selector || ''
}
// ...
zepto.Z = function(dom, selector) {
return new Z(dom, selector)
}
zepto.init = function(selector, context) {
var dom
//分情况对dom赋值,
//并返回zepto.Z的值
return zepto.Z(dom, selector)
}
$ = function(selector, context){
return zepto.init(selector, context)
}
$.fn = {
constructor: zepto.Z,
// $.fn的属性和方法
}
//...
zepto.Z.prototype = Z.prototype = $.fn
return $
})()
window.Zepto = Zepto
window.$ === undefined && (window.$ = Zepto)
我们在用$(‘div’)初始化一个zepto对象的时候:
为了保持思维的连贯性,上面没有说到Z这个函数:
function Z(dom, selector) {
var i, len = dom ? dom.length : 0
for (i = 0; i < len; i++) this[i] = dom[i]
this.length = len
this.selector = selector || ''
}
可以看到 通过传入 dom和selector,生成了一个类数组对象: Z。
这样它的实例对象(zepto.Z)也是一个类数组对象,zepto.Z的length属性就是传入dom的length属性,zepto.Z的selector就是传入的selector。