$()可以说是jquery的精华了,为dom操作带来了极大的灵活和方便。zepto号称“移动版的jquery”,那么它是怎么来实现这个核心函数呢?我们来详细探讨下。

1、首先,我们看下zepto中它是怎么定义的:

$ = function(selector, context) {
return zepto.init(selector, context)
}

  这里很明显,如果你试图通过S(“”)来获取一个dom元素,zept会将其封装为一个zepto对象返回给你,那么zepto.init是如何实现的呢?

2、zepto.init

zepto.init = function(selector, context) {
// If nothing given, return an empty Zepto collection
if (!selector) return zepto.Z() //没有参数,返回空数组
//如果selector是个函数,则在DOM ready的时候执行它
else if (isFunction(selector)) return $(document).ready(selector)
//如果selector是一个zepto.Z实例,则直接返回它自己
else if (zepto.isZ(selector)) return selector
else {
var dom
//如果selector是一个数组,则将其里面的null,undefined去掉
if (isArray(selector)) dom = compact(selector)
//如果selector是个对象,注意DOM节点的typeof值也是object,所以在里面还要再进行一次判断
else if (isObject(selector))
//如果是申明的对象,如{}, 则将selector属性copy到一个新对象,并将结果放入数组
//如果是该对象是DOM,则直接放到数组中
dom = [isPlainObject(selector) ? $.extend({}, selector) : selector], selector = null
//如果selector是一段HTML代码片断,则将其转换成DOM节点
else if (fragmentRE.test(selector)) dom = zepto.fragment(selector.trim(), RegExp.$1, context), selector = null
//如果存在上下文context,则在上下文中查找selector,此时的selector为普通的CSS选择器
else if (context !== undefined) return $(context).find(selector)
//如果没有给定上下文,则在document中查找selector,此时的selector为普通的CSS选择器
else dom = zepto.qsa(document, selector)
//最后将查询结果转换成zepto集合
return zepto.Z(dom, selector)
}
}

  在这里zepto.innit函数根据输入参数的情况来进行不同的操作,如果你输入的参数是标准的(selector,context)的形式,其会调用zepto.qsa也就是dom查询函数,最后最后将得到的元素数组用zepto.z()函数包装成zepto对象数组返回。所以这个函数的包括两个过程:一、查找生成满足条件dom元素数组;二、将dom元素包装成zepto对象,这样返回的对象就具有了zepto的方法。ok,我们继续分解这两个过程:

3、zepto.qua()

  

zepto.qsa = function(element, selector) {
var found
//当element为document,且selector为ID选择器时
return (isDocument(element) && idSelectorRE.test(selector)) ?
//直接返回document.getElementById,RegExp.$1为ID的值,当没有找节点时返回[]
((found = element.getElementById(RegExp.$1)) ? [found] : []) :
//当element不为元素节点或者document时,返回[]
(element.nodeType !== 1 && element.nodeType !== 9) ? [] :
//否则将获取到的结果转成数组并返回
slice.call(
//如果selector是标签名,直接调用getElementsByClassName
classSelectorRE.test(selector) ? element.getElementsByClassName(RegExp.$1) :
//如果selector是标签名,直接调用getElementsByTagName
tagSelectorRE.test(selector) ? element.getElementsByTagName(selector) :
//否则调用querySelectorAll
element.querySelectorAll(selector))
}

  ok,你没看错,这就是zepto的核心dom查找函数,其思想是先用正则表达式判断selector的类型,然后调用相应的方法。对于不是单一类型的选择符,最后用querySelectorAll()函数来进行查询,并且用slice将得到的元素集合转化为数组。这里因为面向移动端,所以也没有考虑queryselectall的兼容性。在这里附带一点,在ie6,7中是不支持queryselectorall方法的,有人提出了一种补充的方法来解决兼容性:

if (!document.querySelectorAll) {
document.querySelectorAll = function (selectors) {
var style = document.createElement('style'), elements = [], element;
document.documentElement.firstChild.appendChild(style);
document._qsa = []; style.styleSheet.cssText = selectors + '{x-qsa:expression(document._qsa && document._qsa.push(this))}';
window.scrollBy(0, 0);
style.parentNode.removeChild(style); while (document._qsa.length) {
element = document._qsa.shift();
element.style.removeAttribute('x-qsa');
elements.push(element);
}
document._qsa = null;
return elements;
};
} if (!document.querySelector) {
document.querySelector = function (selectors) {
var elements = document.querySelectorAll(selectors);
return (elements.length) ? elements[0] : null;
};
} // 用于在IE6和IE7浏览器中,支持Element.querySelectorAll方法
var qsaWorker = (function () {
var idAllocator = 10000; function qsaWorkerShim(element, selector) {
var needsID = element.id === "";
if (needsID) {
++idAllocator;
element.id = "__qsa" + idAllocator;
}
try {
return document.querySelectorAll("#" + element.id + " " + selector);
}
finally {
if (needsID) {
element.id = "";
}
}
} function qsaWorkerWrap(element, selector) {
return element.querySelectorAll(selector);
} // Return the one this browser wants to use
return document.createElement('div').querySelectorAll ? qsaWorkerWrap : qsaWorkerShim;
})();

  4、zepto.z()

  在找到dom元素数组后,剩下的就是将其封装成zepto对像。

zepto.Z = function(dom, selector) {
dom = dom || []
dom.__proto__ = $.fn //通过给dom设置__proto__属性指向$.fn来达到继承$.fn上所有方法的目的
dom.selector = selector || ''
return dom
}

  没错,这个Z函数就是包装函数,短小而强悍。zepto处理的方法及其剪短,通过将$.fn赋给dom的__proto__属性,来继承fn的属性,这也就意味着这一步后,你同过$()方法得到的元素都拥有了fn中的方法。进而链式调用也就实现了。。。

zepto学习之路--核心函数$()的实现的更多相关文章

  1. zepto学习之路--数组去重和原生reduce

    好吧开始读zepto的源代码,最前面给处理trim和reduce的原生实现,感觉写的很紧凑,其中reduce写的有点晦涩,个人感觉还不错.主要zepto的作者是无分号党,看起了有点不习惯. 3 if ...

  2. zepto学习之路--源代码提取

    最近在看zepto的源代码,把一些有用的函数摘出来,看看zepto是怎么实现的,自己做的时候也可以用.说实话,zepto的实现有一些看起来还是很晦涩的,可能是自己的水平不够,看不透作者的真正的意图. ...

  3. MySql 学习之路-Date函数

    MySQL中重要的内建函数 函数 描述 NOW() 返回当前的日期和时间 NOW() 返回当前的日期和时间. 语法 NOW() -- 实例 -- 下面是 SELECT 语句: SELECT NOW() ...

  4. MySql 学习之路-聚合函数

    下面是mysql 数据库中经常用到的聚合函数的简单实例 -- 创建学生表 create table student ( id int primary key auto_increment commen ...

  5. Python学习之路5 - 函数

    函数 定义方式: def func(): "这里面写函数的描述" 这里写代码 return x #如果没有返回值就叫"过程",函数和过程的区别就是有无返回值 实 ...

  6. Webwork 学习之路【03】核心类 ServletDispatcher 的初始化

    1. Webwork 与 Xwork 搭建环境需要的的jar 为:webwork-core-1.0.jar,xwork-1.0.jar,搭建webwork 需要xwork 的jar呢?原因是这样的,W ...

  7. jQuery学习之路(1)-选择器

    ▓▓▓▓▓▓ 大致介绍 终于开始了我的jQuery学习之路!感觉不能再拖了,要边学习原生JavaScript边学习jQuery jQuery是什么? jQuery是一个快速.简洁的JavaScript ...

  8. spring源码学习之路---AOP初探(六)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 最近工作很忙,但当初打算学习 ...

  9. [EntLib]微软企业库5.0 学习之路——第一步、基本入门

    话说在大学的时候帮老师做项目的时候就已经接触过企业库了但是当初一直没明白为什么要用这个,只觉得好麻烦啊,竟然有那么多的乱七八糟的配置(原来我不知道有配置工具可以进行配置,请原谅我的小白). 直到去年在 ...

随机推荐

  1. 移动UI

    UI设计需要关注:色彩,信息布局,交互流程,用户体验,尺寸等

  2. SourceTree基础

    克隆(clone):从远程仓库URL加载创建一个与远程仓库一样的本地仓库 提交(commit):将暂存文件上传到本地仓库(我们在Finder中对本地仓库做修改后一般都得先提交一次,再推送) 检出(ch ...

  3. git变基--rebase

    变基过程: 两个分支 先考虑不用变基的合并: $ git checkout master $ git merge experiment 合并后: 如果变基:(以下为变基过程) $ git checko ...

  4. 构造DataTable

    手动构造一个DataTable: DataTable dt = new DataTable(); dt.Columns.Add("ID", typeof(string)); dt. ...

  5. find the majority element

    Runtime: O(n) — Moore voting algorithm: We maintain a current candidate and a counter initialized to ...

  6. crontab如何设置秒级别的定时【转载】

    * * * * * date > /home/gamester88/test/nihao.txt * * * * * (sleep 10 && date >> /ho ...

  7. psy 2

    PSY,心理线,顾名思义,庄家要洗筹必须打破市场尤其是散户的心理防线,才能让大家乖乖的交出筹码.月线的心理线尤其重要,PSY有几个数值,16,25,33,41,50,66,75.PSY的运用也是抓大黑 ...

  8. MSSQL存储过程接收另一个存储过程返回列表

    CREATE TABLE #tmp(m_Meter_ID varchar(20),low_Voltage int,num_Attack int,num_DER int,company_id int,a ...

  9. MongoDB用户

    MongoDB  增加用户 删除用户  修改用户  读写权限 只读权限,   MongoDB用户权限分配的操作是针对某个库来说的.--这句话很重要.   1. 进入ljc 数据库:       use ...

  10. android全屏和取消全屏 旋转屏幕

    全屏 getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); 取消全屏 getWindow().clearFlags(Win ...