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 相关文章推荐
JavaScript性能陷阱小结(附实例说明)
Dec 28 Javascript
Jquery中给animation加更多的运作效果实例
Sep 05 Javascript
JS对象转换为Jquery对象实现代码
Dec 29 Javascript
使用mouse事件实现简单的鼠标经过特效
Jan 30 Javascript
JS显示表格内指定行html代码的方法
Mar 31 Javascript
AngularJs Understanding the Model Component
Sep 02 Javascript
Angular中$state.go页面跳转并传递参数的方法
May 09 Javascript
基于require.js的使用(实例讲解)
Sep 07 Javascript
vue 指定组件缓存实例详解
Apr 01 Javascript
js捆绑TypeScript声明文件的方法教程
Apr 13 Javascript
vue实现图片预览组件封装与使用
Jul 13 Javascript
jQuery编写QQ简易聊天框
Aug 27 jQuery
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边学边教》(01.开篇――准备工作)
2006/12/13 PHP
PHP利用imagick生成组合缩略图
2016/02/19 PHP
PHP输出Excel PHPExcel的方法
2018/07/26 PHP
document.all还是document.getElementsByName?
2006/07/21 Javascript
jQuery 1.8 Release版本发布了
2012/08/14 Javascript
原生JS实现表单checkbook获取已选择的值
2013/07/21 Javascript
sails框架的学习指南
2014/12/22 Javascript
Javascript中String的常用方法实例分析
2015/06/13 Javascript
jQuery增加和删除表格项目及实现表格项目排序的方法
2016/05/30 Javascript
利用jquery禁止外层滚动条的滚动
2017/01/05 Javascript
js中如何完美的解析数据
2018/03/18 Javascript
ES6 fetch函数与后台交互实现
2018/11/14 Javascript
vue 中url 链接左边的小图标更改问题
2019/12/30 Javascript
原生js+css实现tab切换功能
2020/09/17 Javascript
[36:41]完美世界DOTA2联赛循环赛FTD vs Magma第一场 10月30日
2020/10/31 DOTA
python基础教程之面向对象的一些概念
2014/08/29 Python
Python三元运算实现方法
2015/01/12 Python
使用Python设计一个代码统计工具
2018/04/04 Python
python使用requests模块实现爬取电影天堂最新电影信息
2019/04/03 Python
python绘制双Y轴折线图以及单Y轴双变量柱状图的实例
2019/07/08 Python
Python绘制堆叠柱状图的实例
2019/07/09 Python
一行python实现树形结构的方法
2019/08/09 Python
使用selenium和pyquery爬取京东商品列表过程解析
2019/08/15 Python
python numpy 反转 reverse示例
2019/12/04 Python
python内置模块collections知识点总结
2019/12/19 Python
Python文字截图识别OCR工具实例解析
2020/03/05 Python
mac 上配置Pycharm连接远程服务器并实现使用远程服务器Python解释器的方法
2020/03/19 Python
PyCharm Anaconda配置PyQt5开发环境及创建项目的教程详解
2020/03/24 Python
Django form表单与请求的生命周期步骤详解
2020/06/07 Python
Python子进程subpocess原理及用法解析
2020/07/16 Python
PyCharm设置注释字体颜色以及是否倾斜的操作
2020/09/16 Python
Python实现自动整理文件的脚本
2020/12/17 Python
Booking.com西班牙:全球酒店预订
2018/03/30 全球购物
2014年小学生教师节演讲稿范文
2014/09/10 职场文书
工作疏忽、懈怠的检讨书
2014/09/11 职场文书
维稳工作情况汇报
2014/10/27 职场文书