JavaScript Object的extend是一个常用的功能


Posted in Javascript onDecember 02, 2009

通常在函数里面给了参数对象的默认值,这个时候就需要通过extend来把传入的参数覆盖进默认参数,如:
代码:

giant.ui.imageshow = function(options) { 
this.opts = $.extend({}, giant.ui.imageshow.defaults, options); 
} 
giant.ui.imageshow.defaults = { 
id:"imageshow", 
isAuto:true, 
speed:3000 
};

Jquery 的框架中给了一个extend工具:
jQuery.extend(target,obj1,[objN])
用一个或多个其他对象来扩展一个对象,返回被扩展的对象。
用于简化继承。
Extend one object with one or more others, returning the original, modified, object.
This is a great utility for simple inheritance.
返回值--Object
参数
target (Object) : 待修改对象。
object1 (Object) : 待合并到第一个对象的对象。
objectN (Object) : (可选) 待合并到第一个对象的对象。
但框架中内置的这个extend有明显的缺陷,那就是不能继承对象中的对象。还是举一个例子来说明:
代码:
var obj1 = {}, 
var obj2={name:"karry",email:"karry@a.com",tel:{homeTel:"158255",officeTel:"02112585"}} 
obj1 = $.extend({},obj1 ,obj2 );

结果obj1 只有name 和email属性,而有与tel本身就是一个对象,tel里面的homeTel和officeTel没有继承过去。
我的目标就是实现这种对子对象的子属性也一起复制(继承)的功能,不管他嵌套有多深。
首先我们看看这个方法的参数,有三个参数,target 目标对象,source 源对象,deep 是否复制(继承)对象中的对象,如果deep为true则继承所有,为false则和jquery的实现方式一样,不会继承子对象。
代码:
Object.extend = function(target, /*optional*/source, /*optional*/deep) {}

我只把第一个参数target设为必选参数,而source 和deep都设为可选参数。这样就会遇到一个问题,如果使用的时候只传如两个参数,怎么确认第二个参数是 对应的source还是deep?所以我需要判断传入的第二个参数的类型。
代码:
target = target || {}; //target默认为空 
var sType = typeof source; 
//如果第二个参数的类型为未定义或者为布尔值 
if( sType === 'undefined' || sType === 'boolean' ) { 
deep = sType === 'boolean' ? source : false; 
source = target; //把target赋值给source, 
target = this; //这里的this指的是Object 
}

有人可能对最后面的两行代码有疑问,我的处理方式是这样的。如果target和source两个参数都存在,且source不是布尔值,那么,就把source对象的内容复制给target.否则,把target对象复制给Object对象。deep默认为false.
为了安全起见,我们还需要判断一下,如果souce满足了上面的条件,但它不是Object对象,或者它是一个Function对象(这涉及到一些其他的问题),我们也没办法对其进行复制的。这个时候我们把souce设为空的Object,也就是并不进行复制操作。
代码:
if( typeof source !== 'object' && Object.prototype.toString.call(source) !== '[object Function]' ) 
source = {};

注:Function对象在执行typeof 操作时 也会返回“object”,但我们没办法对其进行正确的复制(至少在我这个方法里面不行),所以我必须剔除出来。
下面就是循环进行复制了。这里利用了递归。
代码:
var i=1,option; 
// 外层循环就是为了把依次修改options,先设为target,后设为source 
while(i <= 2) { 
options = i === 1 ? target : source; 
if( options != null ) { 
//内层循环复制对应的属性 
for( var name in options ) { 
var src = target[name], copy = options[name]; 
if(target === copy) 
continue; 
//如果deep设为true,且该属性是一个对象 
if(deep && copy && typeof copy === 'object' && !copy.nodeType) 
//递归 
target[name] = this.extend(src ||(copy.length != null ? [] : {}), copy, deep); 
else if(copy !== undefined) 
target[name] = copy; 
} 
} 
i++; 
}

这里利用了递归的方式,依次复制对象里面的对象。这个功能就做完了。全部代码如下:
代码:
/* 
* @param {Object} target 目标对象。 
* @param {Object} source 源对象。 
* @param {boolean} deep 是否复制(继承)对象中的对象。 
* @returns {Object} 返回继承了source对象属性的新对象。 
*/ 
Object.extend = function(target, /*optional*/source, /*optional*/deep) { 
target = target || {}; 
var sType = typeof source, i = 1, options; 
if( sType === 'undefined' || sType === 'boolean' ) { 
deep = sType === 'boolean' ? source : false; 
source = target; 
target = this; 
} 
if( typeof source !== 'object' && Object.prototype.toString.call(source) !== '[object Function]' ) 
source = {}; 
while(i <= 2) { 
options = i === 1 ? target : source; 
if( options != null ) { 
for( var name in options ) { 
var src = target[name], copy = options[name]; 
if(target === copy) 
continue; 
if(deep && copy && typeof copy === 'object' && !copy.nodeType) 
target[name] = this.extend(src || 
(copy.length != null ? [] : {}), copy, deep); 
else if(copy !== undefined) 
target[name] = copy; 
} 
} 
i++; 
} 
return target; 
};

使用示例:
代码:
var source = {id:1, name:'Jack Source'}, target = {name:'Jack Target', gender:1,tel:{homeTel:"158255",officeTel:"02112585"}}; 
var newObj1 = Object.extend(target, source);
Javascript 相关文章推荐
锋利的jQuery 要点归纳(二) jQuery中的DOM操作(下)
Mar 23 Javascript
javascript向后台传送相同属性的参数即数组参数
Feb 17 Javascript
jquery自动补齐功能插件flexselect用法示例
Aug 06 Javascript
基于BootStrap的Metronic框架实现页面链接收藏夹功能按钮移动收藏记录(使用Sortable进行拖动排序)
Aug 29 Javascript
详解浏览器渲染页面过程
Feb 09 Javascript
如何使用angularJs
May 08 Javascript
基于jquery的on和click的区别详解
Jan 15 jQuery
webpack打包node.js后端项目的方法
Mar 10 Javascript
解决Mac node版本升级失败的问题
May 16 Javascript
对Vue beforeRouteEnter 的next执行时机详解
Aug 25 Javascript
vue中引入mxGraph的步骤详解
May 17 Javascript
JavaScript实现tab栏切换效果
Mar 16 Javascript
JS类的封装及实现代码
Dec 02 #Javascript
Jquery选择器 $实现原理
Dec 02 #Javascript
js 表格隔行颜色
Dec 02 #Javascript
让FireFox支持innerText的实现代码
Dec 01 #Javascript
JavaScript 直接操作本地文件的实现代码
Dec 01 #Javascript
js 变量类型转换常用函数与代码[比较全]
Dec 01 #Javascript
Jquery 快速构建可拖曳的购物车DragDrop
Nov 30 #Javascript
You might like
php shell超强免杀、减少体积工具实现代码
2012/10/16 PHP
PHP实现懒加载的方法
2015/03/07 PHP
php中使用sftp教程
2015/03/30 PHP
php计算title标题相似比的方法
2015/07/29 PHP
解决在Laravel 中处理OPTIONS请求的问题
2019/10/11 PHP
php的无刷新操作实现方法分析
2020/02/28 PHP
使用jscript实现二进制读写脚本代码
2008/06/09 Javascript
JS判断是否为数字,是否为整数,是否为浮点数的代码
2010/04/24 Javascript
JavaScript使用IEEE 标准进行二进制浮点运算产生莫名错误的解决方法
2011/05/28 Javascript
JavaScript面向对象知识串结(读JavaScript高级程序设计(第三版))
2012/07/17 Javascript
循环 vs 递归浅谈
2013/02/28 Javascript
简单的ajax连接库分享(不用jquery的ajax)
2014/01/19 Javascript
JS实现弹性漂浮效果的广告代码
2015/09/02 Javascript
学JavaScript七大注意事项【必看】
2016/05/04 Javascript
AngularJs bootstrap搭载前台框架——准备工作
2016/09/01 Javascript
Node.js复制文件的方法示例
2016/12/29 Javascript
Swiper实现轮播图效果
2017/07/03 Javascript
JS中Object对象的原型概念基础
2018/01/29 Javascript
layui自定义插件citySelect实现省市区三级联动选择
2019/07/26 Javascript
基于vue--key值的特殊用处详解
2020/07/31 Javascript
python实现分析apache和nginx日志文件并输出访客ip列表的方法
2015/04/04 Python
Python线程指南详细介绍
2017/01/05 Python
浅谈python函数之作用域(python3.5)
2017/10/27 Python
基于python cut和qcut的用法及区别详解
2019/11/22 Python
Tensorflow矩阵运算实例(矩阵相乘,点乘,行/列累加)
2020/02/05 Python
宝塔面板成功部署Django项目流程(图文)
2020/06/22 Python
面向新手解析python Beautiful Soup基本用法
2020/07/11 Python
深入解析HTML5使用SVG图像时的viewBox属性用法
2015/09/02 HTML / CSS
土耳其玩具商店:Toyzz Shop
2019/08/02 全球购物
人力资源管理专业应届生求职信
2014/04/24 职场文书
2014年社会实践活动总结范文
2014/04/29 职场文书
事业单位工作人员年度考核个人总结
2015/02/12 职场文书
大学生自荐信范文
2015/03/05 职场文书
2015年安全员工作总结范文
2015/04/22 职场文书
食品安全责任书范本
2015/05/09 职场文书
pandas 实现将NaN转换为None
2021/05/14 Python