jquery源码学习
来源:互联网 发布:宏观经济指标数据 编辑:程序博客网 时间:2024/06/15 23:00
源码架构
- 变量正则初始化
- $.fn
- $.ready()
- 复杂选择器sizzle
- $.callback()
- $.defferred()
- $.data
- 队列方法:queue()|dequeue()
- 对元素属性的操作:attr() prop() val()
- 事件操作方法:on trigger
- window,jQuery = window.$ = jQuery
无new构造原理
正常使用:
$('test').text('Test')
相当于:
var test = new $('#test');test.text('Test');
内部实现源码:
(function(window, undefined) { var // ... jQuery = function(selector, context) { // The jQuery object is actually just the init constructor 'enhanced' // 看这里,实例化方法 jQuery() 实际上是调用了其拓展的原型方法 jQuery.fn.init return new jQuery.fn.init(selector, context, rootjQuery); }, // jQuery.prototype 即是 jQuery 的原型,挂载在上面的方法,即可让所有生成的 jQuery 对象使用 jQuery.fn = jQuery.prototype = { // 实例化化方法,这个方法可以称作 jQuery 对象构造器 init: function(selector, context, rootjQuery) { // ... } } // 这一句很关键,也很绕 // jQuery 没有使用 new 运算符将 jQuery 实例化,而是直接调用其函数 // 要实现这样,那么 jQuery 就要看成一个类,且返回一个正确的实例 // 且实例还要能正确访问 jQuery 类原型上的属性与方法 // jQuery 的方式是通过原型传递解决问题,把 jQuery 的原型传递给jQuery.prototype.init.prototype // 所以通过这个方法生成的实例 this 所指向的仍然是 jQuery.fn,所以能正确访问 jQuery 类原型上的属性与方法 jQuery.fn.init.prototype = jQuery.fn;})(window);
解析:
jQuery.fn.init.prototype = jQuery.fn = jQuery.prototype ;new jQuery.fn.init() 相当于 new jQuery() ;
jQuery.fn.extend 与 jQuery.extend
- jQuery.extend() :把两个或者更多的对象合并到第一个当中,$.xxx()
var settings = { validate: false, limit: 5, name: "foo" }; var options = { validate: true, name: "bar" }; jQuery.extend(settings, options); 结果:settings == { validate: true, limit: 5, name: "bar" }
第一个参数为true为深拷贝,false为浅拷贝
- jQuery.fn.extend():把对象挂载到 jQuery 的 prototype 属性,来扩展一个新的 jQuery 实例方法。
.().xxx, .fn.extend({ hello:function(){alert(‘hello’);} });
$.fn.extend({ alertWhileClick:function() { $(this).click(function(){ alert($(this).val()); }); } }); $("#input1").alertWhileClick();
源码:
// 扩展合并函数// 合并两个或更多对象的属性到第一个对象中,jQuery 后续的大部分功能都通过该函数扩展// 虽然实现方式一样,但是要注意区分用法的不一样,那么为什么两个方法指向同一个函数实现,但是却实现不同的功能呢,// 阅读源码就能发现这归功于 this 的强大力量// 如果传入两个或多个对象,所有对象的属性会被添加到第一个对象 target// 如果只传入一个对象,则将对象的属性添加到 jQuery 对象中,也就是添加静态方法// 用这种方式,我们可以为 jQuery 命名空间增加新的方法,可以用于编写 jQuery 插件// 如果不想改变传入的对象,可以传入一个空对象:$.extend({}, object1, object2);// 默认合并操作是不迭代的,即便 target 的某个属性是对象或属性,也会被完全覆盖而不是合并// 如果第一个参数是 true,则是深拷贝// 从 object 原型继承的属性会被拷贝,值为 undefined 的属性不会被拷贝// 因为性能原因,JavaScript 自带类型的属性不会合并jQuery.extend = jQuery.fn.extend = function() { var src, copyIsArray, copy, name, options, clone, target = arguments[0] || {}, i = 1, length = arguments.length, deep = false; // Handle a deep copy situation // target 是传入的第一个参数 // 如果第一个参数是布尔类型,则表示是否要深递归, if (typeof target === "boolean") { deep = target; target = arguments[1] || {}; // skip the boolean and the target // 如果传了类型为 boolean 的第一个参数,i 则从 2 开始 i = 2; } // Handle case when target is a string or something (possible in deep copy) // 如果传入的第一个参数是 字符串或者其他 if (typeof target !== "object" && !jQuery.isFunction(target)) { target = {}; } // extend jQuery itself if only one argument is passed // 如果参数的长度为 1 ,表示是 jQuery 静态方法 if (length === i) { target = this; --i; } // 可以传入多个复制源 // i 是从 1或2 开始的 for (; i < length; i++) { // Only deal with non-null/undefined values // 将每个源的属性全部复制到 target 上 if ((options = arguments[i]) != null) { // Extend the base object for (name in options) { // src 是源(即本身)的值 // copy 是即将要复制过去的值 src = target[name]; copy = options[name]; // Prevent never-ending loop // 防止有环,例如 extend(true, target, {'target':target}); if (target === copy) { continue; } // Recurse if we're merging plain objects or arrays // 这里是递归调用,最终都会到下面的 else if 分支 // jQuery.isPlainObject 用于测试是否为纯粹的对象 // 纯粹的对象指的是 通过 "{}" 或者 "new Object" 创建的 // 如果是深复制 if (deep && copy && (jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)))) { // 数组 if (copyIsArray) { copyIsArray = false; clone = src && jQuery.isArray(src) ? src : []; // 对象 } else { clone = src && jQuery.isPlainObject(src) ? src : {}; } // Never move original objects, clone them // 递归 target[name] = jQuery.extend(deep, clone, copy); // Don't bring in undefined values // 最终都会到这条分支 // 简单的值覆盖 } else if (copy !== undefined) { target[name] = copy; } } } } // Return the modified object // 返回新的 target // 如果 i < length ,是直接返回没经过处理的 target,也就是 arguments[0] // 也就是如果不传需要覆盖的源,调用 $.extend 其实是增加 jQuery 的静态方法 return target;};
链式调用及回溯
源码:
jQuery.fn = jQuery.prototype = { // 将一个 DOM 元素集合加入到 jQuery 栈 // 此方法在 jQuery 的 DOM 操作中被频繁的使用, 如在 parent(), find(), filter() 中 // pushStack() 方法通过改变一个 jQuery 对象的 prevObject 属性来跟踪链式调用中前一个方法返回的 DOM 结果集合 // 当我们在链式调用 end() 方法后, 内部就返回当前 jQuery 对象的 prevObject 属性 pushStack: function(elems) { // 构建一个新的jQuery对象,无参的 this.constructor(),只是返回引用this // jQuery.merge 把 elems 节点合并到新的 jQuery 对象 // this.constructor 就是 jQuery 的构造函数 jQuery.fn.init,所以 this.constructor() 返回一个 jQuery 对象 // 由于 jQuery.merge 函数返回的对象是第二个函数附加到第一个上面,所以 ret 也是一个 jQuery 对象,这里可以解释为什么 pushStack 出入的 DOM 对象也可以用 CSS 方法进行操作 var ret = jQuery.merge(this.constructor(), elems); // 给返回的新 jQuery 对象添加属性 prevObject // 所以也就是为什么通过 prevObject 能取到上一个合集的引用了 ret.prevObject = this; ret.context = this.context; // Return the newly-formed element set return ret; }, // 回溯链式调用的上一个对象 end: function() { // 回溯的关键是返回 prevObject 属性 // 而 prevObject 属性保存了上一步操作的 jQuery 对象集合 return this.prevObject || this.constructor(null); }, // 取当前 jQuery 对象的第 i 个 eq: function(i) { // jQuery 对象集合的长度 var len = this.length, j = +i + (i < 0 ? len : 0); // 利用 pushStack 返回 return this.pushStack(j >= 0 && j < len ? [this[j]] : []); }, }
end()
end() 方法结束当前链条中的最近的筛选操作,并将匹配元素集还原为之前的状态。
大多数 jQuery 的遍历方法会操作一个 jQuery 对象实例,并生成一个匹配不同 DOM 元素集的新对象。当发生这种情况时,应该会把新的元素集推入维持在对象中的堆栈内。每次成功的筛选方法调用都会把新元素推入堆栈中。如果我们需要老的元素集,可以使用 end() 从堆栈中弹出新集合。
列子:
<div></div><div></div><script src="jquery-3.1.1.js"></script><script> console.log($('div').eq(0)); // 第二个div元素 console.log($('div').eq(0).end()); // $('div)</script>
而end()的作用就是返回当前jQuery对象(在本例中就是$(‘div’).eq(0))的prevObject对象。
正则
exec和match
这两个返回值虽然都是数组,但是区别很大。完整地址:https://segmentfault.com/a/1190000003497780
零宽断言 。。。
阅读全文
1 0
- Jquery 源码学习
- jQuery源码学习
- jquery源码学习
- jquery源码学习1
- jquery源码学习3
- jquery源码学习1
- jquery源码学习2
- jQuery源码学习(一)
- jQuery源码学习
- jQuery源码学习(二)
- jQuery源码学习(三)
- jQuery源码学习(四)
- JQuery源码学习
- jquery源码学习
- jquery源码学习
- jquery 源码学习
- jQuery源码学习笔记一
- jquery源码分析学习地址
- 如何从业余爱好者自学进阶成专业开发者
- 转:问题解决:The project cannot be built until build path errors are resolved
- FineReport中如何制作树数据集来实现组织树报表
- XML约束
- 回调
- jquery源码学习
- 模拟(HDU 5319,Painter)
- 100. Same Tree
- 2017.5
- Eclipse快捷键
- _winapi Createprocess FileNotFoundError: [WinError 2] 系统找不到指定的文件
- 验证RT9742是否做的防倒灌处理 磁珠 电感 三位数码管
- 初学者如何选择合适的机器学习算法
- Android Studio使用ButterKnife 8.6.0无效的问题