复制代码 代码如下:
<script type="text/javascript" src="/UploadFiles/2021-04-02/jquery-1.5.2.js"><script>
obj1 = { a : 'a', b : 'b' };
obj2 = { x : { xxx : 'xxx', yyy : 'yyy' }, y : 'y' };
$.extend(true, obj1, obj2);
alert(obj1.x.xxx); // 得到"xxx"
obj2.x.xxx = 'zzz';
alert(obj2.x.xxx); // 得到"zzz"
alert(obj1.x.xxx); // 得带"xxx"
</script>
$.extend(true, obj1, obj2)表示以obj2中的属性扩展对象obj1,第一个参数设为true表示深复制。
虽然obj1中原来没有"x"属性,但经过扩展后,obj1不但具有了"x"属性,而且对obj2中的"x"属性的修改也不会影响到obj1中"x"属性的值,这就是所谓的“深复制”了。
浅复制的实现
如果仅仅需要实现浅复制,可以采用类似下面的写法:
复制代码 代码如下:
$ = {
extend : function(target, options) {
for (name in options) {
target[name] = options[name];
}
return target;
}
};
也就是简单地将options中的属性复制到target中。我们仍然可以用类似的代码进行测试,但得到的结果有所不同(假设我们的js命名为“jquery-extend.js”):
复制代码 代码如下:
<script type="text/javascript" src="/UploadFiles/2021-04-02/jquery-extend.js"><script>
obj1 = { a : 'a', b : 'b' };
obj2 = { x : { xxx : 'xxx', yyy : 'yyy' }, y : 'y' };
$.extend(obj1, obj2);
alert(obj1.x.xxx); // 得到"xxx"
obj2.x.xxx = 'zzz';
alert(obj2.x.xxx); // 得到"zzz"
alert(obj1.x.xxx); // 得带"zzz"
</script>
obj1中具有了"x"属性,但这个属性是一个对象,对obj2中的"x"的修改也会影响到obj1,这可能会带来难以发现的错误。
深复制的实现
如果我们希望实现“深复制”,当所复制的对象是数组或者对象时,就应该递归调用extend。如下代码是“深复制”的简单实现:
复制代码 代码如下:
$ = {
extend : function(deep, target, options) {
for (name in options) {
copy = options[name];
if (deep && copy instanceof Array) {
target[name] = $.extend(deep, [], copy);
} else if (deep && copy instanceof Object) {
target[name] = $.extend(deep, {}, copy);
} else {
target[name] = options[name];
}
}
return target;
}
};
具体分为三种情况:
1. 属性是数组时,则将target[name]初始化为空数组,然后递归调用extend;
2. 属性是对象时,则将target[name]初始化为空对象,然后递归调用extend;
3. 否则,直接复制属性。
测试代码如下:
复制代码 代码如下:
<script type="text/javascript" src="/UploadFiles/2021-04-02/jquery-extend.js"><script>
obj1 = { a : 'a', b : 'b' };
obj2 = { x : { xxx : 'xxx', yyy : 'yyy' }, y : 'y' };
$.extend(true, obj1, obj2);
alert(obj1.x.xxx); // 得到"xxx"
obj2.x.xxx = 'zzz';
alert(obj2.x.xxx); // 得到"zzz"
alert(obj1.x.xxx); // 得到"xxx"
</script>
现在如果指定为深复制的话,对obj2的修改将不会对obj1产生影响了;不过这个代码还存在一些问题,比如“instanceof Array”在IE5中可能存在不兼容的情况。jQuery中的实现实际上会更复杂一些。
更完整的实现
下面的实现与jQuery中的extend()会更接近一些:
复制代码 代码如下:
$ = function() {
var copyIsArray,
toString = Object.prototype.toString,
hasOwn = Object.prototype.hasOwnProperty;
class2type = {
'[object Boolean]' : 'boolean',
'[object Number]' : 'number',
'[object String]' : 'string',
'[object Function]' : 'function',
'[object Array]' : 'array',
'[object Date]' : 'date',
'[object RegExp]' : 'regExp',
'[object Object]' : 'object'
},
type = function(obj) {
return obj == null ? String(obj) : class2type[toString.call(obj)] || "object";
},
isWindow = function(obj) {
return obj && typeof obj === "object" && "setInterval" in obj;
},
isArray = Array.isArray || function(obj) {
return type(obj) === "array";
},
isPlainObject = function(obj) {
if (!obj || type(obj) !== "object" || obj.nodeType || isWindow(obj)) {
return false;
}
if (obj.constructor && !hasOwn.call(obj, "constructor")
&& !hasOwn.call(obj.constructor.prototype, "isPrototypeOf")) {
return false;
}
var key;
for (key in obj) {
}
return key === undefined || hasOwn.call(obj, key);
},
extend = function(deep, target, options) {
for (name in options) {
src = target[name];
copy = options[name];
if (target === copy) { continue; }
if (deep && copy
&& (isPlainObject(copy) || (copyIsArray = isArray(copy)))) {
if (copyIsArray) {
copyIsArray = false;
clone = src && isArray(src) ? src : [];
} else {
clone = src && isPlainObject(src) ? src : {};
}
target[name] = extend(deep, clone, copy);
} else if (copy !== undefined) {
target[name] = copy;
}
}
return target;
};
return { extend : extend };
}();
首先是 $ = function(){...}();这种写法,可以理解为与下面的写法类似:
复制代码 代码如下:
func = function(){...};
$ = func();
也就是立即执行函数,并将结果赋给$。这种写法可以利用function来管理作用域,避免局部变量或局部函数影响全局域。另外,我们只希望使用者调用$.extend(),而将内部实现的函数隐藏,因此最终返回的对象中只包含extend:
复制代码 代码如下:
return { extend : extend };
接下来,我们看看extend函数与之前的区别,首先是多了这句话:
复制代码 代码如下:
if (target === copy) { continue; }
这是为了避免无限循环,要复制的属性copy与target相同的话,也就是将“自己”复制为“自己的属性”,可能导致不可预料的循环。
然后是判断对象是否为数组的方式:
复制代码 代码如下:
type = function(obj) {
return obj == null ? String(obj) : class2type[toString.call(obj)] || "object";
},
isArray = Array.isArray || function(obj) {
return type(obj) === "array";
}
如果浏览器有内置的Array.isArray 实现,就使用浏览器自身的实现方式,否则将对象转为String,看是否为"[object Array]"。
最后逐句地看看isPlainObject的实现:
复制代码 代码如下:
if (!obj || type(obj) !== "object" || obj.nodeType || isWindow(obj)) {
return false;
}
如果定义了obj.nodeType,表示这是一个DOM元素;这句代码表示以下四种情况不进行深复制:
1. 对象为undefined;
2. 转为String时不是"[object Object]";
3. obj是一个DOM元素;
4. obj是window。
之所以不对DOM元素和window进行深复制,可能是因为它们包含的属性太多了;尤其是window对象,所有在全局域声明的变量都会是其属性,更不用说内置的属性了。
接下来是与构造函数相关的测试:
复制代码 代码如下:
if (obj.constructor && !hasOwn.call(obj, "constructor")
&& !hasOwn.call(obj.constructor.prototype, "isPrototypeOf")) {
return false;
}
如果对象具有构造函数,但却不是自身的属性,说明这个构造函数是通过prototye继承来的,这种情况也不进行深复制。这一点可以结合下面的代码结合进行理解:
复制代码 代码如下:
var key;
for (key in obj) {
}
return key === undefined || hasOwn.call(obj, key);
这几句代码是用于检查对象的属性是否都是自身的,因为遍历对象属性时,会先从自身的属性开始遍历,所以只需要检查最后的属性是否是自身的就可以了。
这说明如果对象是通过prototype方式继承了构造函数或者属性,则不对该对象进行深复制;这可能也是考虑到这类对象可能比较复杂,为了避免引入不确定的因素或者为复制大量属性而花费大量时间而进行的处理,从函数名也可以看出来,进行深复制的只有"PlainObject"。
如果我们用如下代码进行测试:
复制代码 代码如下:
<script type="text/javascript" src="/UploadFiles/2021-04-02/jquery-1.5.2.js"><script>
function O() {
this.yyy = 'yyy';
}
function X() {
this.xxx = 'xxx';
}
X.prototype = new O();
x = new X();
obj1 = { a : 'a', b : 'b' };
obj2 = { x : x };
$.extend(true, obj1, obj2);
alert(obj1.x.yyy); // 得到"xxx"
obj2.x.yyy = 'zzz';
alert(obj1.x.yyy); // 得到"zzz"
</script>
可以看到,这种情况是不进行深复制的。
总之,jQuery中的extend()的实现方式,考虑了兼容浏览器的兼容,避免性能过低,和避免引入不可预料的错误等因素。
jQuery.extend
P70系列延期,华为新旗舰将在下月发布
3月20日消息,近期博主@数码闲聊站 透露,原定三月份发布的华为新旗舰P70系列延期发布,预计4月份上市。
而博主@定焦数码 爆料,华为的P70系列在定位上已经超过了Mate60,成为了重要的旗舰系列之一。它肩负着重返影像领域顶尖的使命。那么这次P70会带来哪些令人惊艳的创新呢?
根据目前爆料的消息来看,华为P70系列将推出三个版本,其中P70和P70 Pro采用了三角形的摄像头模组设计,而P70 Art则采用了与上一代P60 Art相似的不规则形状设计。这样的外观是否好看见仁见智,但辨识度绝对拉满。
更新动态
- 魔兽世界wlk暗牧一键输出宏是什么 wlk暗牧一键输出宏介绍
- 群星.1996-红不让台语原唱2辑【福和唱片】【WAV+CUE】
- 郭书瑶.2009-爱的抱抱(EP)【种子音乐】【FLAC分轨】
- 郑瑞芬.1989-BE.MY.BABY【现代】【WAV+CUE】
- 花钱请人每周放30万只不咬人的蚊子 防治登革热传播
- 饭制《第一后裔》丧尸版弗蕾娜
- 贝克汉姆亲临!2024FC品类游戏嘉年华圆满落幕
- 「命轨爻错之翼」风之翼发放说明
- 《原神》前瞻特别节目回顾长图
- 米游币抽抽乐-原神专场现已开启!
- 黑鸭子2001《风情中国HQCD》[日本版][WAV+CUE]
- 陈杰洲1990-成人礼[滚石][WAV+CUE]
- MarkAanderud-HandsFree(2024)[24-44,1]FLAC
- 孙露《观心》1:1母盘直刻限量版[低速原抓WAV+CUE][361M]
- 钟志刚《汽车DJ玩主》[低速原抓WAV+CUE][1G]