jQuery 源码解析二:jQuery.fn.extend=jQuery.extend 方法探究

时间:2022-12-10 11:16:50

终于动笔开始 jQuery 源码解析第二篇,写文章还真是有难度,要把自已懂的表述清楚,要让别人听懂真的不是一见易事。

在 jQuery 源码解析一:jQuery 类库整体架构设计解析 一文,大致描述了 jQuery 源码整体大致架构,主要分为以下几个点:

  A 通过自执行函数,在内部将 jQuery (jQuery 为一个函数,同时,在 JS 中,函数也为对象)以 window.jQuery=window.$ 引入,供用户直接便可使用 $、jQuery 调用。

      B 以 C#、Java 为例,可知存在静态方法、对象方法区别,该原理类比 jQuery ,jQuery.xxx 相当于给为其增加静态方法,而 jQuery.fn.xxx 则可类比于相当于给其增加对象方法。

      C 在 jQuery 源码内部,巧妙运用原型,直接上代码:

jQuery = function( selector, context ) {
// 用户调用 jQuery 方法,即是以 jQuer.fn.init 为构造函数所创建的对象
return new jQuery.fn.init( selector, context, rootjQuery );
}; // 在 JS 中,所有函数对象默认将有 prototype 属性
// 为 jQuery.prototype 另起一个简单的别名,即 jQuery.fn
// 其中 jQuery.fn 内部包含 constructor 属性(重新将该函数指向 jQuery)、init 函数
jQuery.fn = jQuery.prototype = {
constructor: jQuery,
init: function( selector, context, rootjQuery ){
.....
},
// Start with an empty selector
selector: "", // The current version of jQuery being used
jquery: "1.8.3",
.....
}; // 关键一步,将 jQuery.fn.init 函数的 prototype属性 指向 jQuery.fn ,这一步相当重要
jQuery.fn.init.prototype = jQuery.fn; JS 中通过原型实现继承,其中使用最简单的介绍,JS 中对象的 __proto__ 属性===该对象 constructor 的 prototype 属性,
在调用方法以及获取属性,首先在自身查找,然后,即沿着 __proto__ 属性查找(而其等于 该对象 constructor 的 prototype 属性),
如果还没找到,继续沿着对象的 __proto__ 的 __proto__ 一步一步往上查找,最终查找到 Object.prototype.__proto__ 为止,没有即返回 undefined.

在 jQuery 源码中,同时,还大量包括扩展 jQuery 对象自身属性方法,以及扩展 jQuery.fn (jQuery.prototype)属性方法,而该些扩展功能,即通过 jQuery.fn.extend=jQuery.extend=function(){} 实现,

具体分析,请查看下述代码部分.

jQuery.extend = jQuery.fn.extend = function () {
// arguments 在 JS 可获取函数实际传入参数,其包含 length 属性
var src, copyIsArray, copy, name, options, clone,
// 可获取 arguments 类数组首个实参
target = arguments[] || {},
i = ,
length = arguments.length,
deep = false; // 若传入首个实参为 boolean 值,则做相关逻辑处理
if ( typeof target === "boolean" ) {
deep = target; // 将 target 重新赋值,如若首个实参为 boolean 值
target = arguments[i] || {};
// 同时,将 i 的值加 一,则为 i=2
i++;
} // Handle case when target is a string or something (possible in deep copy)
// 首个实参类型不等于 object 并且不等于 function 类型,则做相关逻辑处理
if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
target = {};
} // extend jQuery itself if only one argument is passed
// 如若传入实参仅为一个,则做下方逻辑处理
if (i === length) {
// 将 target 重新赋值,如若 jQuery.extend 则此时 this =jQuery,
// 如若 jQuery.fn.extend ,则此时 this =jQuery.fn=jQuery.prototype
target = this;
// 同时,将 i 的值减一,则 i=0
i--;
} // 如传入实参参数为 1 ,此时,扩展对象属性 this =jQuery,this=jQuery.fn=jQuery.prototype
// 如传入实参参数个数不为1,此时,将分为首个实参为 boolean 值,以及相关情况
for ( ; i < length; i++ ) {
// 首先,判断传入实际值是否为 undefined 、null
if ( (options = arguments[ i ]) != null ) {
// 再对传入实参值进行遍历操作,扩展对象属性
for (name in options) {
// 参考上方逻辑,如实参个数为1,则 target指向 this
// 如若实参个数不为1 ,则 target 指向 argument[0]
// 如若实参个数为 bool 值,则 target 指向 argument [1]
src = target[ name ];
copy = options[ name ]; // 判断需扩展对象与此时扩展属性进行比较,以防扩展对象与扩展属性相等,出现循环引用
if ( target === copy ) {
continue;
} // 如若首个参数值 boolean 值为 true 且扩展属性为 true 且 扩展属性为数组或者纯对象,进入深度复制逻辑处理
if (deep && copy && (jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)))) {
// 如若是数组
  //  jQuery.fn.extend(true,  { Name: "jack", age: 20, {Physics:30}}  ,{ Name: "jack",  {Math:40,English:100,Chinese:76}})
// jQuery.fn.extend( { Name: "jack", age: 20, {Physics:30}} ,{ Name: "jack", {Math:40,English:100,Chinese:76}})
             if (copyIsArray) {
copyIsArray = false; // 若此时需扩展对象 target[name] 属性(数组)进行扩展
clone = src && jQuery.isArray(src) ? src : [];
}
// 如若扩展属性为纯对象 else {
clone = src && jQuery.isPlainObject(src) ? src : {};
} // 进行递归调用,进行属性扩展
target[ name ] = jQuery.extend( deep, clone, copy ); // 直接扩展对象属性 ,如果扩展属性不为 undefined ,target[name]=copy,直接扩展对象属性 } else if (copy !== undefined) { // jQuery.fn.extend({ Name: "jack", age: 20, {Math:30}} ,{ Name: "jack", age: 20, {Math:40,English:100,Chinese:76}})
target[ name ] = copy;
} } } } // 最后,返回 target 对象 return target;
};

在 jQuery 源码中,可大量发现 jQuery.extend、jQuery.fn.extend 使用,而此时,为 jQuery对象、jQuery.fn ( jQuery.fn ) 进行方法属性扩展。

最后,有一个问题,在 jQuery 大量的链式调用,实现原理如何?大家可联想一下,在 java、C# 中要实现这种调用,在一个类中,如何实现该种功能?在 Java、C# 中,在一个类中,每个方法逻辑写完后,最终都返回 this,是不是就可以实现该功能。当然,在 C# 中,现在已有扩展方法可实现该功能。

参考资料:http://www.cnblogs.com/chyingp/archive/2013/06/03/3115210.html