jQuery中extend函数的实现原理详解


Posted in Javascript onFebruary 03, 2015

extend()是jQuery中一个重要的函数,作用是实现对对象的扩展, 它经常用于jQuery插件的开发,jQuery内部也使用它来扩展属性方法,如上篇文章中讲到的noConflict方法,就是用extend方法来扩展的。

jQuery中extend函数的实现原理详解

在jQuery的API手册中,我们看到,extend实际上是挂载在jQuery和jQuery.fn上的两个不同方法,尽管在jQuery内部jQuery.extend()和jQuery.fn.extend()是用相同的代码实现的,但是它们的功能却不太一样。来看一下官方API对extend的解释:

jQuery.extend(): Merge the contents of two or more objects together into the first object.(把两个或者更多的对象合并到第一个当中)

jQuery.fn.extend():Merge the contents of an object onto the jQuery prototype to provide new jQuery instance methods.(把对象挂载到jQuery的prototype属性,来扩展一个新的jQuery实例方法)

我们知道,jQuery有静态方法和实例方法之分, 那么jQuery.extend()和jQuery.fn.extend()的第一个区别就是一个用来扩展静态方法,一个用来扩展实例方法。用法如下:

jQuery.extend({
 sayhello:function(){
 console.log("Hello,This is jQuery Library");
 }
})
$.sayhello(); //Hello, This is jQuery Library
jQuery.fn.extend({
 check: function() {
 return this.each(function() {
 this.checked = true;
 });
 },
 uncheck: function() {
 return this.each(function() {
 this.checked = false;
 });
 }
})
$( "input[type='checkbox']" ).check(); //所有的checkbox都会被选择

注意两种调用插件的方式,一种是直接用$调用,另外一种是用$()调用,另外jQuery.extend()接收多个对象作为参数,如果只有一个参数,则把这个对象的属性方法附加到jQuery上,如果含有多个参数,则把后面的对象的属性和方法附加到第一个对象上。jQuery extend的实现源码:

jQuery.extend = jQuery.fn.extend = function() {
 var options, name, src, copy, copyIsArray, clone,
 target = arguments[0] || {},
 i = 1,
 length = arguments.length,
 deep = false;
 // Handle a deep copy situation
 if ( typeof target === "boolean" ) {
 deep = target;
 target = arguments[1] || {};
 // skip the boolean and the target
 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
 if ( length === i ) {
 target = this;
 --i;
 }
 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;
 }
 }
 }
 }
 // Return the modified object
 return target;
};

很大一堆代码,乍看起来难以理解,其实代码的大部分都是用来实现jQuery.extend()中有多个参数时的对象合并,深度拷贝问题,如果去掉这些功能,让extend只有扩展静态和实例方法的功能,那么代码如下:

jQuery.extend = jQuery.fn.extend = function(obj){
 //obj是传递过来扩展到this上的对象
 var target=this;
 for (var name in obj){
 //name为对象属性
 //copy为属性值
 copy=obj[name];
 //防止循环调用
 if(target === copy) continue;
 //防止附加未定义值
 if(typeof copy === 'undefined') continue;
 //赋值
 target[name]=copy;
 }
 return target;
}

下面再来对extend方法进行注释解释:

jQuery.extend = jQuery.fn.extend = function() {
 // 定义默认参数和变量
 // 对象分为扩展对象和被扩展的对象 
 //options 代表扩展的对象中的方法
 //name 代表扩展对象的方法名
 //i 为扩展对象参数起始值
 //deep 默认为浅复制
 var options, name, src, copy, copyIsArray, clone,
 target = arguments[0] || {},
 i = 1,
 length = arguments.length,
 deep = false;
 //当第一个参数为布尔类型是,次参数定义是否为深拷贝
 //对接下来的参数进行处理
 if ( typeof target === "boolean" ) {
 deep = target;
 target = arguments[1] || {};
 // 当定义是否深拷贝时,参数往后移动一位
 i = 2;
 }
 // 如果要扩展的不是对象或者函数,则定义要扩展的对象为空
 if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
 target = {};
 }
 // 当只含有一个参数时,被扩展的对象是jQuery或jQuery.fn
 if ( length === i ) {
 target = this;
 --i;
 }
 //对从i开始的多个参数进行遍历
 for ( ; i < length; i++ ) {
 // 只处理有定义的值
 if ( (options = arguments[ i ]) != null ) {
 // 展开扩展对象
 for ( name in options ) {
 src = target[ name ];
 copy = options[ name ];
 // 防止循环引用
 if ( target === copy ) {
  continue;
 }
 // 递归处理深拷贝
 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 : {};
  }
  target[ name ] = jQuery.extend( deep, clone, copy );
 // 不处理未定义值
 } else if ( copy !== undefined ) {
  //给target增加属性或方法
  target[ name ] = copy;
 }
 }
 }
 }
 //返回
 return target;
};

弄懂了jQuery扩展的原理,相信以后再也不用为编写jQuery插件而烦恼了。

Javascript 相关文章推荐
jQuery 中关于CSS操作部分使用说明
Jun 10 Javascript
javascripit实现密码强度检测代码分享
Dec 12 Javascript
Query常用DIV操作获取和设置长度宽度的实现方法
Sep 19 Javascript
jQuery设置和获取select、checkbox、radio的选中值方法
Jan 01 Javascript
React快速入门教程
Jan 17 Javascript
JQuery 获取Dom元素的实例讲解
Jul 08 jQuery
基于vue.js快速搭建图书管理平台
Oct 29 Javascript
vue滚动固定顶部及修改样式的实例代码
May 30 Javascript
vue点击当前路由高亮小案例
Sep 26 Javascript
Nautil 中使用双向数据绑定的实现
Oct 02 Javascript
Vue中Table组件行内右键菜单实现方法(基于 vue + AntDesign)
Nov 21 Javascript
微信小程序实现轨迹回放的示例代码
Dec 13 Javascript
jQuery中noconflict函数的实现原理分解
Feb 03 #Javascript
jQuery中的pushStack实现原理和应用实例
Feb 03 #Javascript
JavaScript闭包详解
Feb 02 #Javascript
js实现浏览器窗口大小被改变时触发事件的方法
Feb 02 #Javascript
javascript的switch用法注意事项分析
Feb 02 #Javascript
jQuery实现长按按钮触发事件的方法
Feb 02 #Javascript
jQuery实现跟随鼠标运动图层效果的方法
Feb 02 #Javascript
You might like
PHP新手上路(十一)
2006/10/09 PHP
php 中include()与require()的对比
2006/10/09 PHP
PHP中的cookie
2006/11/26 PHP
php cache类代码(php数据缓存类)
2010/04/15 PHP
php radio 单选框获取与保持值的实现代码
2010/05/15 PHP
腾讯CMEM的PHP扩展编译安装方法
2015/09/25 PHP
PHP实现的oracle分页函数实例
2016/01/25 PHP
PHP中SQL查询语句的id=%d解释(推荐)
2016/12/10 PHP
PHP针对中英文混合字符串长度判断及截取方法示例
2017/03/31 PHP
javascript css在IE和Firefox中区别分析
2009/02/18 Javascript
JavaScript的null和undefined区别示例介绍
2014/09/15 Javascript
jquery表单验证实例仿Toast提示效果
2017/03/03 Javascript
d3.js实现立体柱图的方法详解
2017/04/28 Javascript
详解JS获取HTML DOM元素的8种方法
2017/06/17 Javascript
layui结合form,table的全选、反选v1.0示例讲解
2018/08/15 Javascript
详解html-webpack-plugin插件(用法总结)
2018/09/12 Javascript
three.js 利用uv和ThreeBSP制作一个快递柜功能
2020/08/18 Javascript
[04:04]显微镜下的DOTA2第六期——电影级别的华丽团战
2014/06/20 DOTA
python模拟鼠标拖动操作的方法
2015/03/11 Python
利用Tkinter和matplotlib两种方式画饼状图的实例
2017/11/06 Python
python入门前的第一课 python怎样入门
2018/03/06 Python
彻彻底底地理解Python中的编码问题
2018/10/15 Python
基于Python的图像数据增强Data Augmentation解析
2019/08/13 Python
python-序列解包(对可迭代元素的快速取值方法)
2019/08/24 Python
解决c++调用python中文乱码问题
2020/07/29 Python
canvas烟花特效锦集
2018/01/17 HTML / CSS
使用canvas压缩图片上传的方法示例
2020/02/07 HTML / CSS
技术总监的工作职责
2013/11/13 职场文书
建筑总经理岗位职责
2014/02/02 职场文书
电子信息工程专业推荐信
2014/02/14 职场文书
开学典礼演讲稿
2014/05/23 职场文书
模具设计与制造专业求职信
2014/07/19 职场文书
班子群众路线教育实践个人对照检查材料思想汇报
2014/09/30 职场文书
2015年公司后勤管理工作总结
2015/05/13 职场文书
2015年度企业工作总结
2015/05/21 职场文书
解决springboot druid数据库连接失败后一直重连的方法
2022/04/19 Java/Android