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 相关文章推荐
【消息提示组件】,兼容IE6/7&amp;&amp;FF2
Sep 04 Javascript
JavaScript学习笔记(十七)js 优化
Feb 04 Javascript
jquery实现的元素的left增加N像素 鼠标移开会慢慢的移动到原来的位置
Mar 21 Javascript
extjs 初始化checkboxgroup值的代码
Sep 21 Javascript
angularjs中的e2e测试实例
Dec 06 Javascript
jquery加载图片时以淡入方式显示的方法
Jan 14 Javascript
jquery实现点击展开列表同时隐藏其他列表
Aug 10 Javascript
微信小程序tabbar不显示解决办法
Jun 08 Javascript
详解HTML5 使用video标签实现选择摄像头功能
Oct 25 Javascript
vue2 前端搜索实现示例
Feb 26 Javascript
Vue数据绑定实例写法
Aug 06 Javascript
Vue3 中的数据侦测的实现
Oct 09 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
sourcesafe管理phpproj文件的补充说明(downmoon)
2009/04/11 PHP
关于php正则匹配汉字的方法介绍
2013/04/25 PHP
PHP解密Unicode及Escape加密字符串
2015/05/17 PHP
PHP单例模式简单用法示例
2017/06/23 PHP
php如何计算两坐标点之间的距离
2018/12/29 PHP
jquery多选项卡效果实例代码(附效果图)
2013/03/23 Javascript
JS加jquery简单实现标签元素的显示或隐藏
2013/09/23 Javascript
jQuery实现仿腾讯视频列表分页效果的方法
2015/08/07 Javascript
HTML页面定时跳转方法解析(2种任选)
2016/12/22 Javascript
从零开始学习Node.js系列教程之SQLite3和MongoDB用法分析
2017/04/13 Javascript
JS动态添加的div点击跳转到另一页面实现代码
2017/09/30 Javascript
Angular简单验证功能示例
2017/12/22 Javascript
JS数组中对象去重操作示例
2019/06/04 Javascript
解决layui表格内文本超出隐藏的问题
2019/09/12 Javascript
vue.js的简单自动求和计算实例
2019/11/08 Javascript
uni-app 组件里面获取元素宽高的实现
2019/12/27 Javascript
vue v-model的用法解析
2020/10/19 Javascript
python3使用tkinter实现ui界面简单实例
2014/01/10 Python
将Emacs打造成强大的Python代码编辑工具
2015/11/20 Python
django利用request id便于定位及给日志加上request_id
2018/08/26 Python
flask的orm框架SQLAlchemy查询实现解析
2019/12/12 Python
简单了解python装饰器原理及使用方法
2019/12/18 Python
python3.6使用SMTP协议发送邮件
2020/05/20 Python
Kickers鞋英国官网:男士、女士和儿童鞋
2021/03/08 全球购物
如何用Lucene索引数据库
2016/02/23 面试题
校园自助餐厅的创业计划书
2013/12/26 职场文书
办公室文员工作职责
2014/01/31 职场文书
渔夫的故事教学反思
2014/02/14 职场文书
酒店员工检讨书
2014/02/18 职场文书
家长对老师的感言
2014/03/11 职场文书
大二学习计划书范文
2014/04/27 职场文书
项目经理任命书范本
2014/06/05 职场文书
公司董事长助理工作职责
2014/07/12 职场文书
整顿机关作风心得体会
2014/09/10 职场文书
2014年教师学期工作总结
2014/11/08 职场文书
原生JS实现飞机大战小游戏
2021/06/09 Javascript