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学习笔记之五 一个小细节renderTo和applyTo的区别
Jan 07 Javascript
js post方式传递提交的实现代码
May 31 Javascript
js二级地域选择的实现方法
Jun 17 Javascript
jQuery学习笔记之jQuery动画效果
Sep 09 Javascript
JavaScript实现复制文章自动添加版权
Aug 02 Javascript
Vue.js快速入门实例教程
Oct 15 Javascript
浅谈JS中String()与 .toString()的区别
Oct 20 Javascript
基于Vue2x的图片预览插件的示例代码
May 14 Javascript
vue.js通过路由实现经典的三栏布局实例代码
Jul 08 Javascript
微信小程序利用swiper+css实现购物车商品删除功能
Mar 06 Javascript
JavaScript解析机制与闭包原理实例详解
Mar 08 Javascript
微信小程序之滑动页面隐藏和显示组件功能的实现代码
Jun 19 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 从指定数字中获取随机组合的简单方法(推荐)
2017/04/05 PHP
javascript 必知必会之closure
2009/09/21 Javascript
Jquery 滑入滑出效果实现代码
2010/03/27 Javascript
jQuery获取css z-index在各种浏览器中的返回值
2010/09/15 Javascript
浅谈js的setInterval事件
2014/12/05 Javascript
JS自动倒计时30秒后按钮才可用(两种场景)
2015/08/31 Javascript
jQuery仿京东商城楼梯式导航定位菜单
2016/07/25 Javascript
Vue.js每天必学之计算属性computed与$watch
2016/09/05 Javascript
javascript数组常用方法汇总
2016/09/10 Javascript
js 定位到某个锚点的方法
2016/11/19 Javascript
js格式化时间的简单实例
2016/11/27 Javascript
详解JS数值Number类型
2018/02/07 Javascript
详解Webpack + ES6 最新环境搭建与配置
2018/06/04 Javascript
Vuejs2 + Webpack框架里,模拟下载的实例讲解
2018/09/05 Javascript
[03:49]DOTA2英雄基础教程 光之守卫
2014/01/14 DOTA
Python基于sftp及rsa密匙实现远程拷贝文件的方法
2016/09/21 Python
python中执行shell的两种方法总结
2017/01/10 Python
解决phantomjs截图失败,phantom.exit位置的问题
2018/05/17 Python
python 统计数组中元素出现次数并进行排序的实例
2018/07/02 Python
python MNIST手写识别数据调用API的方法
2018/08/08 Python
使用Python实现将list中的每一项的首字母大写
2019/06/11 Python
解决python3 安装不了PIL的问题
2019/08/16 Python
详解Python time库的使用
2019/10/10 Python
python调用接口的4种方式代码实例
2019/11/19 Python
python实现堆排序的实例讲解
2020/02/21 Python
python3 xpath和requests应用详解
2020/03/06 Python
Python中使用socks5设置全局代理的方法示例
2020/04/15 Python
Python如何向SQLServer存储二进制图片
2020/06/08 Python
会计实习生工作总结的自我评价
2013/10/07 职场文书
会计电算化实训报告
2014/11/04 职场文书
搭讪开场白台词大全
2015/05/28 职场文书
护士岗位竞聘书
2015/09/15 职场文书
企业内部管理控制:采购授权审批制度范本
2020/01/19 职场文书
解决hive中导入text文件遇到的坑
2021/04/07 Python
《异世界四重奏》剧场版6月10日上映 PV视觉图原创角色发表
2022/03/20 日漫