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更改class和id的方法
Oct 10 Javascript
jquery中通过过滤器获取表单元素的实现代码
Jul 05 Javascript
js控制CSS样式属性语法对照表
Dec 11 Javascript
Three.js源码阅读笔记(物体是如何组织的)
Dec 27 Javascript
页面右下角弹出提示框示例代码js版
Aug 02 Javascript
javascript实现Emrips反质数枚举的示例代码
Dec 06 Javascript
javascript异步处理与Jquery deferred对象用法总结
Jun 04 jQuery
javascript设计模式 ? 中介者模式原理与用法实例分析
Apr 20 Javascript
Vue执行方法,方法获取data值,设置data值,方法传值操作
Aug 05 Javascript
Vue this.$router.push(参数)实现页面跳转操作
Sep 09 Javascript
浅谈JavaScript浅拷贝和深拷贝
Nov 07 Javascript
vue 数字翻牌器动态加载数据
Apr 20 Vue.js
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 快速生成 Flash 动画的方法
2007/03/06 PHP
php中用数组的方法设置cookies
2011/04/21 PHP
php处理restful请求的路由类分享
2014/02/27 PHP
PHP使用pear自带的mail类库发邮件的方法
2015/07/08 PHP
PHP-FPM之Chroot执行环境详解
2015/08/03 PHP
php封装的连接Mysql类及用法分析
2015/12/10 PHP
PHP中array_keys和array_unique函数源码的分析
2016/02/26 PHP
PHP 与 UTF-8 的最佳实践详细介绍
2017/01/04 PHP
PHP序列化的四种实现方法与横向对比
2018/11/29 PHP
PHP检查URL包含特定字符串实例方法
2019/02/11 PHP
html 锁定页面(js遮罩层弹出div效果)
2009/10/27 Javascript
javascript 判断数组是否已包含了某个元素的函数
2010/05/30 Javascript
JavaScript instanceof 的使用方法示例介绍
2013/10/23 Javascript
JavaScript中合并数组的N种方法
2014/09/16 Javascript
JavaScript实现横向滑出的多级菜单效果
2015/10/09 Javascript
JS中showModalDialog关闭子窗口刷新主窗口用法详解
2017/03/25 Javascript
详解基于webpack和vue.js搭建开发环境
2017/04/05 Javascript
Vue中封装input组件的实例详解
2017/10/17 Javascript
Bootstrap实现的表格合并单元格示例
2018/02/06 Javascript
JS+HTML实现自定义上传图片按钮并显示图片功能的方法分析
2020/02/12 Javascript
小程序实现列表倒计时功能
2021/01/29 Javascript
[15:56]Heroes18_暗影萨满(完美)
2014/10/31 DOTA
深入理解Python中的*重复运算符
2017/10/28 Python
Python中的单行、多行、中文注释方法
2018/07/19 Python
python中import与from方法总结(推荐)
2019/03/21 Python
树莓派采用socket方式文件传输(python)
2019/06/22 Python
django之状态保持-使用redis存储session的例子
2019/07/28 Python
H5最强接口之canvas实现动态图形功能
2019/05/31 HTML / CSS
HTML5 FileReader对象的具体使用方法
2020/05/22 HTML / CSS
匡威荷兰官方网站:Converse荷兰
2018/10/24 全球购物
驾驶员培训方案
2014/05/01 职场文书
校车安全管理责任书
2015/05/11 职场文书
员工担保书范本
2015/09/22 职场文书
关于战胜挫折的名言警句大全!
2019/07/05 职场文书
如何利用pygame实现打飞机小游戏
2021/05/30 Python
浅谈python中的多态
2021/06/15 Python