您现在的位置: 万盛学电脑网 >> 程序编程 >> 网络编程 >> 编程语言综合 >> 正文

jQuery中extend()和fn.extend()方法详解

作者:佚名    责任编辑:admin    更新时间:2022-06-22

   jQuery自定义了jQuery.extend()和jQuery.fn.extend()方法.其中jQuery.extend()方法能够创建全局函数或者选择器,而jQuery.fn.extend()方法能够创建jQuery对象方法.

  这两个方法用的是相同的代码,一个用于给jQuery对象或者普通对象合并属性和方法一个是针对jQuery对象的实例,对于基本用法举几个例子:

 html代码如下:

 

 代码如下:
<!doctype html>
<html>
<head>
<title></title>
<script src='jquery-1.7.1.js'></script>
</head>
<body>
<img src=''/>
</body>
</html>

  下面写js里面的用法:

  合并两个普通对象

  代码如下:

  //给两个普通对象合并属性

  var obj1={name:'Tom',age:22};

  var obj2={name:'Jack',height:180};

  console.log($.extend(obj1,obj2)); //Object {name: "Jack", age: 22, height: 180}

  给jQuery对象添加属性或者方法

  代码如下:

  $.extend({hehe:function(){alert('hehe');}});

  $.hehe(); //alert('hehe')

  这个用法很重要,是jQuery内部添加实例属性和方法以及原型属性和方法的实现方法也是编写jQuery插件的方法,下面是jQuery1.7.1中使用extend方法扩展自己的方法和属性

   代码如下:

  jQuery.extend({

  noConflict: function( deep ) {

  if ( window.$ === jQuery ) {

  window.$ = _$;

  }

  if ( deep && window.jQuery === jQuery ) {

  window.jQuery = _jQuery;

  }

  return jQuery;

  },

  // Is the DOM ready to be used? Set to true once it occurs.

  isReady: false,

  // A counter to track how many items to wait for before

  // the ready event fires. See #6781

  readyWait: 1,

  .....

  在这个例子中只传入了一个对象参数,那么默认就把this当做待合并修改的对象

  给jQuery对象实例添加属性或者方法

  代码如下:

  //针对jQuery实例扩展合并

  console.log($('img').extend({'title':'img'}));//[img, img#img.img, prevObject: jQuery.fn.jQuery.init[1], context: document, selector: "img", title: "img", constructor: function…]

  只合并不修改待合并对象

   代码如下:

  var obj1={name:'Tom',age:22};

  var obj2={name:'Jack',height:180};

  console.log($.extend(obj1,obj2)); //Object {name: "Jack", age: 22, height: 180}

  console.log(obj1); //Object {name: "Jack", age: 22, height: 180}

  默认情况下,待合并对象跟返回结果一样是被修改了的,如果仅仅想得到一个合并后的对象又不想破坏任何一个原来的对象可以使用此方法

  代码如下:

  var obj1={name:'Tom',age:22};

  var obj2={name:'Jack',height:180};

  var empty={};

  console.log($.extend(empty,obj1,obj2)); //Object {name: "Jack", age: 22, height: 180}

  console.log(obj1); //Object {name: "Tom", age: 22}

  使用则递归合并或者叫深度拷贝

  代码如下:

  var obj1={name:'Tom',love:{drink:'milk',eat:'bread'}};

  var obj2={name:'Jack',love:{drink:'water',sport:'football'}};

  console.log(($.extend(false,obj1,obj2)).love); //Object {drink: "water", sport: "football"}

  console.log(($.extend(true,obj1,obj2)).love); //Object {drink: "water", eat: "bread", sport: "football"}

  详细的使用方法可以看参考手册http://www.w3cschool.cc/manual/jquery/

  下面来分析下1.7.1源码中是怎么实现的:

  代码如下:

  jQuery.extend = jQuery.fn.extend = function() {

  var options, name, src, copy, copyIsArray, clone,

  target = arguments[0] || {},

  i = 1,

  length = arguments.length,

  deep = false;

  ...

  }

  首先是定义了一组变量,因为参数个数不确定所以就直接调用arguments对象访问传递的参数

  变量 options:指向某个源对象。

  ‰ ‰ 变量 name:表示某个源对象的某个属性名。

  ‰ ‰ 变量 src:表示目标对象的某个属性的原始值。

  ‰ ‰ 变量 copy:表示某个源对象的某个属性的值。

  ‰ ‰ 变量 copyIsArray:指示变量 copy 是否是数组。

  ‰ ‰ 变量 clone:表示深度复制时原始值的修正值。

  ‰ ‰ 变量 target:指向目标对象。

  ‰ ‰ 变量 i:表示源对象的起始下标。

  ‰ ‰ 变量 length:表示参数的个数,用于修正变量 target。

  ‰ ‰ 变量 deep:指示是否执行深度复制,默认为 false。

  为了更好地了解代码实现这里以上面举的一个例子作为演示观察源代码执行情况

   代码如下:

  var obj1={name:'Tom',love:{drink:'milk',eat:'bread'}};

  var obj2={name:'Jack',love:{drink:'water',sport:'football'}};

  $.extend(true,obj1,obj2)

  源码分析

  代码如下:

  // Handle a deep copy situation

  if ( typeof target === "boolean" ) {

  deep = target;

  target = arguments[1] || {};

  // skip the boolean and the target

  i = 2;

  }

  判断是不是深度复制,如果第一个参数是布尔值那么就把第一个参数的值给deep,然后把第二个参数作为目标对象,如果第二个参数不存在就赋值为一个空对象,把源对象的下标改为2,在这个例子里面 是走这里的因为第一个参数是ture然后把deep变成了true ,target被修正成了第二个参数也即是obj1,源对象的起始下标为2就是从第三个开始作为源对象也就是本例中的obj2

   代码如下:

  // Handle case when target is a string or something (possible in deep copy)

  if ( typeof target !== "object" && !jQuery.isFunction(target) ) {

  target = {};

  }

  这里对target又进一步进行了处理对于非对象和函数的数据类型而言增加自定义属性是无效的比如字符串自能调用自带的方法和属性

  代码如下:

  // extend jQuery itself if only one argument is passed

  if ( length === i ) {

  target = this;

  --i;

  }

  如果length属性等于i的值那就表示没有目标对象存在,正常情况下length应该是大于i的值的 ,那么这个时候就把this作为目标对象把i值减一实现length值大于i值(比i大1)

  这个就是jQuery给自己扩展属性的方法的实现原理,只要不传入目标对象就可以啦

  两种可能的情况:$.extend(obj) 或者 $.extend(false/true,obj);

  代码如下:

  for ( ; i < length; i++ ) {

  // Only deal with non-null/undefined values

  if ( (options = arguments[ i ]) != null ) {

  // Extend the base object

  for ( name in options ) {

  src = target[ name ];

  copy = options[ name ];

  // Prevent never-ending loop

  if ( target === copy ) {

  continue;

  }

  // Recurse if we're merging plain objects or arrays

  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;

  }

  }

  }

  }

  这个部分就是此方法的核心了,从arguements对象的第i个下标值开始循环操作首先过滤掉源对象是null或者是undefined的情况可以看到其实

  源对象不一定真的就是对像,也可以是其他类型的值比如字符串比如这样写:

  代码如下:

  console.log($.extend({'nam