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 相关文章推荐
window.name代替cookie的实现代码
Nov 28 Javascript
js判断60秒以及倒计时示例代码
Jan 24 Javascript
js身份证判断方法支持15位和18位
Mar 18 Javascript
深入理解JavaScript内置函数
Jun 03 Javascript
JavaScript中Number对象的toFixed() 方法详解
Sep 02 Javascript
原生JS实现九宫格抽奖效果
Apr 01 Javascript
JS实现的模仿QQ头像资料卡显示与隐藏效果
Apr 07 Javascript
浅谈Vue.js路由管理器 Vue Router
Aug 16 Javascript
值得收藏的八个常用的js正则表达式
Oct 19 Javascript
atom-design(Vue.js移动端组件库)手势组件使用教程
May 16 Javascript
webpack常用构建优化策略小结
Nov 21 Javascript
JS Array.from()将伪数组转换成数组的方法示例
Mar 23 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网页游戏学习之Xnova(ogame)源码解读(六)
2014/06/23 PHP
PHP输出日历表代码实例
2015/03/27 PHP
php使用ftp实现文件上传与下载功能
2017/07/21 PHP
Prototype使用指南之form.js
2007/01/10 Javascript
用Greasemonkey 脚本收藏网站会员信息到本地
2009/10/26 Javascript
js怎么终止程序return不行换jfslk
2013/05/30 Javascript
js实现拉伸拖动iframe的具体代码
2013/08/03 Javascript
详解JavaScript表单验证(E-mail 验证)
2016/03/31 Javascript
javascript中错误使用var造成undefined
2016/03/31 Javascript
jquery ajax局部加载方法详解(实现代码)
2016/05/12 Javascript
JavaScript无阻塞加载和defer、async详解
2017/02/26 Javascript
bootstrap轮播图示例代码分享
2017/05/17 Javascript
Vue监听滚动实现锚点定位(双向)示例
2019/11/13 Javascript
[31:33]2014 DOTA2国际邀请赛中国区预选赛 TongFu VS DT 第一场
2014/05/23 DOTA
[03:54]Ehome出征西雅图 回顾2016国际邀请赛晋级之路
2016/08/02 DOTA
[05:00]第二届DOTA2亚洲邀请赛主赛事第三天比赛集锦.mp4
2017/04/04 DOTA
Python的ORM框架SQLAlchemy入门教程
2014/04/28 Python
python分析nignx访问日志脚本分享
2015/02/26 Python
Django中几种重定向方法
2015/04/28 Python
Python使用reportlab将目录下所有的文本文件打印成pdf的方法
2015/05/20 Python
Python多进程与服务器并发原理及用法实例分析
2018/08/21 Python
python中单下划线(_)和双下划线(__)的特殊用法
2019/08/29 Python
html5仿支付宝密码框的实现代码
2017/09/06 HTML / CSS
90后毕业生的求职信范文
2013/09/21 职场文书
教师师德教育的自我评价
2013/10/31 职场文书
技术经理的自我评价范文
2013/12/03 职场文书
医院门卫岗位职责
2013/12/30 职场文书
护士思想汇报
2014/01/12 职场文书
消防安全宣传口号
2014/06/10 职场文书
幼儿园2014年度工作总结
2014/11/10 职场文书
办公室主任岗位职责
2015/01/31 职场文书
房地产财务经理岗位职责
2015/04/08 职场文书
未中标通知书
2015/04/17 职场文书
运动会广播稿200字
2015/08/19 职场文书
如何写好开幕词?
2019/06/24 职场文书
Golang 正则匹配效率详解
2021/04/25 Golang