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 相关文章推荐
extjs 初始化checkboxgroup值的代码
Sep 21 Javascript
jQuery获取浏览器中的分辨率实现代码
Apr 23 Javascript
jquery实现的Banner广告收缩效果代码
Sep 02 Javascript
深入探讨前端框架react
Dec 09 Javascript
原生js编写autoComplete插件
Apr 13 Javascript
jQuery用noConflict代替$的实现方法
Apr 12 jQuery
Node.js 基础教程之全局对象
Aug 06 Javascript
Angular中响应式表单的三种更新值方法详析
Aug 22 Javascript
vue组件间通信子与父详解(二)
Nov 07 Javascript
javascript原生封装一个淡入淡出效果的函数测试实例代码
Mar 19 Javascript
浅谈layer的Icon样式以及一些常用的layer窗口使用方法
Sep 11 Javascript
vue如何实现关闭对话框后刷新列表
Apr 08 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
ajax缓存问题解决途径
2006/12/06 PHP
浅析PHP绘图技术
2013/07/03 PHP
thinkphp Apache配置重启Apache1 restart 出错解决办法
2017/02/15 PHP
PHP fprintf()函数用法讲解
2019/02/16 PHP
Laravel框架运行出错提示RuntimeException No application encryption key has been specified.解决方法
2019/04/02 PHP
js几个不错的函数 $$()
2006/10/09 Javascript
用javascript替换URL中的参数值示例代码
2014/01/27 Javascript
node.js WEB开发中图片验证码的实现方法
2014/06/03 Javascript
详解JavaScript中|单竖杠运算符的使用方法
2016/05/23 Javascript
巧方法 JavaScript获取超链接的绝对URL地址
2016/06/14 Javascript
Dropzone.js实现文件拖拽上传功能(附源码下载)
2016/11/22 Javascript
Vue.js组件tree实现省市多级联动
2016/12/02 Javascript
详解ES6 export default 和 import语句中的解构赋值
2019/05/28 Javascript
javascript使用链接跨域下载图片
2019/11/01 Javascript
javascript跳转与返回和刷新页面的实例代码
2019/11/20 Javascript
Vue+webpack实现懒加载过程解析
2020/02/17 Javascript
[04:46]2018年度玩家喜爱的电竞媒体-完美盛典
2018/12/16 DOTA
[02:49:21]2019完美盛典全程录像
2019/12/08 DOTA
[42:32]完美世界DOTA2联赛循环赛 Magma vs PXG BO2第二场 10.28
2020/10/28 DOTA
python字符串的常用操作方法小结
2016/05/21 Python
python解决pandas处理缺失值为空字符串的问题
2018/04/08 Python
Python中使用遍历在列表中添加字典遇到的坑
2019/02/27 Python
python 带时区的日期格式化操作
2020/10/23 Python
CSS3实现跳动的动画效果
2016/09/12 HTML / CSS
使用css3和jquery实现可伸缩搜索框
2014/02/12 HTML / CSS
html5标记文字_动力节点Java学院整理
2017/07/11 HTML / CSS
HTML5拖拽功能实现的拼图游戏
2018/07/31 HTML / CSS
蔻驰法国官网:COACH法国
2018/11/14 全球购物
浅谈react路由传参的几种方式
2021/03/23 Javascript
模具专业自荐信
2014/05/29 职场文书
公安个人四风问题对照检查及整改措施
2014/10/28 职场文书
2014-2015学年工作总结
2014/11/27 职场文书
西安大雁塔导游词
2015/02/10 职场文书
2015年加油站工作总结
2015/05/13 职场文书
Python Pytorch查询图像的特征从集合或数据库中查找图像
2022/04/09 Python
python热力图实现的完整实例
2022/06/25 Python