对于操作 DOM 来说,jQuery 是非常方便的一个库,虽然如今随着 React, Vue 之类框架的流行,jQuery 用得越来越少了,但是其中很多思想还是非常值得我们学习的,这篇文章将介绍如何从零开始实现一个简化版 jQuery。

在这里,我把这个库命名为 Clus(class 的谐音),下面以 $ 符号代替。

首先需要声明一个构造函数并做一些初始化操作:

function $(selector) { return new $.fn.init(selector);}$.fn = $.prototype = { contructor: $, init,};

可以看到,该构造函数返回一个 $.fn.init 的实例,这样做的好处就是在使用的时候不要每次都 new 一个构造函数就可以创建一个新的实例了,可以看出来,整个核心都在 init 函数上了:

function init(selector) { const fragmentRE = /^s*]*>/; const selectorType = $.type(selector); const elementTypes = [1, 9, 11]; let dom; if (!selector) { dom = [], dom.selector = selector; } else if (elementTypes.indexOf(selector.nodeType) !== -1 || selector === window) { dom = [selector], selector = null; } else if (selectorType === 'function') { return $(document).ready(selector); } else if (selectorType === 'array') { dom = selector; } else if (selectorType === 'object') { dom = [selector], selector = null; } else if (selectorType === 'string') { if (selector[0] === '

可以很清楚的看到,根据传入的参数类型的不同进行一些不同的操作,比如传入的是函数的话,则该函数里的操作的都是 DOM Ready 之后的操作了;再比如传入的是字符串的话,并且如果是标签的话,则会把这段标签字符串解析成 DOM Fragment,如果是普通字符串,则会调用 document.querySelectorAll() 方法来查找 DOM。

相信大家都能很容易的看明白上面的代码,不过有一点值得一提的是 $.extend(dom, $.fn); 这段代码,其含义是把实例上的所有方法都添加到 dom 这个数组对象中,这样做的目的就是为了可以直接链式调用某个实例的方法,比如 $('.clus').addClass('hello'),这个 addClass() 方法就是在 $.fn 上实现的。因此所有在 $.fn 实现的方法都可以通过 $(selector).method() 这种方式来调用了。

至于 extend() 方法我认为是除了 init() 方法以外,整个库中最核心的一个方法了,代码如下:

export default function extend() { let options, name, clone, copy, source, copyIsArray, target = arguments[0] || {}, i = 1, length = arguments.length, deep = false; if (typeof target === 'boolean') { deep = target; target = arguments[i] || {}; i++; } if (typeof target !== 'object' && $.type(target) !== 'function') { target = {}; } if (i === length) { target = this; i--; } for (; i < length; i++) { // if ((options = arguments[i]) !== null) { // for in source object for (name in options) { source = target[name]; copy = options[name]; if (target == copy) { continue; } // deep clone if (deep && copy && ($.isPlainObject(copy) || (copyIsArray = Array.isArray(copy)))) { // if copy is array if (copyIsArray) { copyIsArray = false; // if is not array, set it to array clone = source && Array.isArray(source) ? source : []; } else { // if copy is not a object, set it to object clone = source && $.isPlainObject(source) ? source : {}; } target[name] = extend(deep, clone, copy); } else if (copy !== undefined) { target[name] = copy; } } } } return target;}

可以看到,和 jQuery 的实现一毛一样,没错就是从那儿 copy 过来的当然一样。

下面以 addClass() 方法为例介绍如何操作 DOM 的:

function addClass(cls) { let classes, clazz, el, cur, curValue, finalValue, j, i = 0; if (typeof cls === 'string' && cls) { classes = cls.match(rnotwhite) || []; while((el = this[i++])) { curValue = getClass(el); cur = (el.nodeType === 1) && ` ${curValue} `.replace(rclass, ' '); if (cur) { j = 0; while((clazz = classes[j++])) { // to determine whether the class that to add has already existed if (cur.indexOf(` ${clazz} `) == -1) { cur += clazz + ' '; } finalValue = $.trim(cur); if ( curValue !== finalValue ) { el.setAttribute('class', finalValue); } } } } } return this;}$.fn.addClass = addClass;

值得一提的就是在实例方法中,this 关键字可以访问到根据选择器所查询到的所有元素的集合,在这里是通过 while 循环来对每个元素进行操作。要实现类似 $(selector).addClass().removeClass() 这样的链式操作,只需要在每个实例方法中返回一个 this 即可。要实现其他实例方法比如 hasClass() 之类的也是类似的方法。

其实每个实例方法都是通过 this 关键字来获取查询到的元素,然后遍历这些元素来针对每个元素进行具体的操作,在举一个栗子:

function append(DOMString) { let el, i = 0, fregmentCollection = $.parseHTML(DOMString), fregments = Array.prototype.slice.apply(fregmentCollection); while((el = this[i++])) { fregments.map(fregment => { el.appendChild(fregment); }); } return this;}$.fn.append = append;

上面是 append() 的实现,首先先解析 DOMString 为 fregment,然后就是遍历查询到的元素(通过 this 关键字)并针对每个元素去进行 appendChild() 的操作,从而把 DOM 插入到匹配到的所有元素中。

其他实例方法也是通过类似的方式实现的,这里就不一一细说了,想更详细的查看其他方法的实现可以直接到 Clus 中查看源码。

jquery 数组indexof_如何实现一个简化版的 jQuery相关推荐

  1. [c#]解决方案:需要“jquery”ScriptResourceMapping。请添加一个名为 jquery (区分大小写)的 ScriptResourceMapping。

    [c#]解决方案:需要"jquery"ScriptResourceMapping.请添加一个名为 jquery (区分大小写)的 ScriptResourceMapping. 参考 ...

  2. 需要“jquery”ScriptResourceMapping。请添加一个名为 jquery (区分大小写)的 ScriptResourceMapping。

    问题详情 如下图所示(部分): 出现该错误,是因为应用程序中需要使用到jquery(现在的web应用程序哪个能离开jquery呢),而目前程序目录中并没有jquery文件,或者有jquery文件但是程 ...

  3. Web Form要“jquery”ScriptResourceMapping。请添加一个名为 jquery (区分大小写)的 ScriptResourceMapping。”的解决办法。...

    1.先将aspnet.scriptmanager.jquery.dl  复制到bin  (网站根目录下的bin文件夹找不到,看看下面的图片中点击[显示所有文档])  文件夹下. 2.在网站根目录下sc ...

  4. jQuery数组处理详解(含实例演示)

    jQuery的数组处理,便捷,功能齐全. 最近的项目中用到的比较多,深感实用,一步到位的封装了很多原生js数组不能企及的功能. 最近时间紧迫,今天抽了些时间回过头来看 jQuery中文文档 中对数组的 ...

  5. jQuery:从零开始,DIY一个jQuery(2)

    在上篇文章我们简单实现了一个 jQuery 的基础结构,不过为了顺应潮流,这次咱把它改为模块化的写法,此举得以有效提升项目的可维护性,因此在后续也将以模块化形式进行持续开发. 模块化开发和编译需要用上 ...

  6. jq数组赋值 java_js,jquery,数组操作小结

    详解jQuery之数组处理: jQuery的数组处理,便捷,功能齐全. 最近的项目中用到的比较多,深感实用,一步到位的封装了很多原生js数组不能企及的功能. 最近时间紧迫,今天抽了些时间回过头来看 j ...

  7. jquery 数组操作(超全)

    1.数组的创建 var arrayObj = new Array(); //创建一个数组 var arrayObj = new Array([size]); //创建一个数组并指定长度,注意不是上限, ...

  8. jQuery数组处理详解

    jQuery的数组处理,便捷,功能齐全. 最近的项目中用到的比较多,深感实用,一步到位的封装了很多原生js数组不能企及的功能. 最近时间紧迫,今天抽了些时间回过头来看 jQuery中文文档 中对数组的 ...

  9. jQuery数组处理完全详解

    jQuery的数组处理.便捷.功能齐全.最近的项目中用到的比较多,深感实用,一步到位的封装了很多原生JavaScript数组不能企及的功能.最近时间紧迫,今天抽了些时间回过头来看jQuery中文文档中 ...

最新文章

  1. CStopwatch的C++实现
  2. [LeetCode 题解]: Rotate List
  3. Python实现行转列?!超简单,赶快get起来
  4. PHP的几种排序算法的比较
  5. go编译成c语言,Go语言是怎么完成编译的
  6. 8.12模拟:dp递推
  7. [WCF] - 使用 [DataMember] 标记的数据契约需要声明 Set 方法
  8. Guava入门~CharMatcher
  9. hive相关操作语句
  10. windows下手动安装composer并配置环境变量
  11. Centos下oracle11g R2的启动与关闭监听、数据库
  12. 计算机会计u8实验报告,会计信息系统实验报告 用友u8
  13. ssh 连接访问被拒绝
  14. 住得越高越安静? 中间楼层噪音最大
  15. 32.ES中什么是fuzzy(模糊)查询?如何进行fuzzy查询?java如何进行fuzzy查询?嘻哈的简写笔记——Elastic Search
  16. Cocos2d-x 2.0变速动画深入分析
  17. Rust基础-Vec用法
  18. 使用 matplotlib处理彩色图像
  19. 如果生活中有什么结解不开,那就打个蝴蝶结吧
  20. 华科计算机博导刘云生论文,AAAI 2020线上分享 | 华科Oral论文:点云中3D目标检测的鲁棒性...

热门文章

  1. ES6一些常用的基本语法
  2. Ext中namespace的作用
  3. 【转】asp仿百度文库、豆丁doc转换(flashpaper)
  4. dhtmlxTree 10分钟做一个树
  5. asp.net架构之请求处理过程:HttpModule,HttpHandler
  6. eq linux_《Linux设备驱动程序》(十二)——时间操作(一)
  7. Linux和Windows下计算文件的Hash值
  8. virtual lab motion对连杆载荷进行扫速瀑布图及阶次切片分析
  9. Ubuntu下设置环境变量的三种方法
  10. P1395 会议[链式前向星板](树的最小重心点+所有点到重心距离的和)