jQuery.extend
语法格式:
jQuery.extend([deep], target, object1, [objectN])
概述:
用一个或多个其他对象来扩展一个对象,返回被扩展的对象。
如果不指定target,则给jQuery命名空间本身进行扩展,这有助于插件作者为jQuery增加新方法具体可以看②的解析。 如果第一个参数设置为true,则jQuery返回一个深层次的副本,递归地复制找到的任何对象。否则的话,副本会与原对象共享结构。 未定义的属性将不会被复制,然而从对象的原型继承的属性将会被复制具体可以看④的解析。
扩展特点:
假设target和object1这两个参数齐全的话,extend之后,如果target里的对象键名和object1里的存在相同时,object1将覆盖target的对象键名索对应的值,而各自中有不同的对象键名的话,最后extend扩展的对象将拥有这些不同的键值对,特别注意:当为浅拷贝时如果对象里存在引用类型,那扩展出来的引用类型只存在最后一个objectN里的引用类型键值对具体可以看③的解析。
参数说明:
target,[object1],[objectN]
target
:一个对象,如果附加的对象被传递给这个方法将那么它将接收新的属性,如果它是唯一的参数将扩展jQuery的命名空间object1
:待合并到第一个对象的对象objectN
:待合并到第N个对象的对象
[deep],target,object1,[objectN]
deep
:如果设为true,则递归合并深拷贝;设为false则为浅拷贝,不写默认为falsetarget
:待修改对象object1
:待合并到第一个对象的对象objectN
:待合并到第N个对象的对象
看了一下概述有点懵懵的,那就看看代码一步步分析:
① 首先对比一下这两个写法:
var obj1 = {
name: "蔡徐坤",
age: 24,
sex: "男",
pet:{
name: "小鸡",
age: 3,
hobby: "打篮球"
}
};
var obj2 = {
name:"老蔡",
age: 24,
pet:{
name: "小美",
age: 5,
color: "绿色"
}
};
var obj = $.extend("扩展结果:",obj1,obj2); // 将obj1作为target参数
console.log(obj,obj1);
var obj1 = {
name: "蔡徐坤",
age: 24,
sex: "男",
pet:{
name: "小鸡",
age: 3,
hobby: "打篮球"
}
};
var obj2 = {
name:"老蔡",
age: 24,
pet:{
name: "小美",
age: 5,
color: "绿色"
}
};
var obj = $.extend("扩展结果:",{},obj1,obj2); // 将{}空对象作为target参数
console.log(obj,obj1);
看两者代码,不同的就是$.extend
里谁作为target参数,第一段代码输出的结果发现,obj1对象尽然被修改了,跟扩展后的obj一样;而第二段代码obj1没有被修改,因为target参数对应的不是obj1而是空对象{ },看图:
结论:一般写的话最后使用extend({}, obj, obj1)
这种让{ }作为target参数,避免修改到原有的对象里的键值对;
② 解释一下 "如果不指定target,则给jQuery命名空间本身进行扩展"
其实这句话的意思,如果你参数只有一个时,$.extend(param)
,jQuery会认为你没有指定target这个参数,那是报错吗?答案是不是的,看代码:
$.extend({
hello:function(){alert('hello jQuery');}
});
console.log("全局对象jQuery:",$.hello( ));
从代码可以知道,此时它符合$.extend(param)
这种情况,但不是报错,而是给jQuery命名空间本身进行扩展,通俗说就是在jQuery的原型链上增加了一个hello的方法,此时直接去用jQuery.hello()
调用就会执行里面的函数体;注意这种定义是全局的,一般是不会这样去扩展一个方法的,而应该定义到jQuery的实例对象中,看代码:
$.fn.extend({
hello:function(){alert('hello jQuery.fn');}
});
console.log("实例对象jQuery.fn:",$.fn.hello( ));
$.fn.extend(param)
就是提供给开发者去扩展 jQuery 元素集来提供新的方法(通常用来制作插件);
结论:原来extend为指定target时,就成了开发者在jQuery实例中扩展自己方法插件的"利器"呢
③ 解释一下 [deep]这个参数为true/false时,深拷贝和浅拷贝对应拷贝的是[基本类型]还是[引用类型]
extend这个单词就是继承的意思,一提到继承当然少不了深浅拷贝啦,因此jQuery就提供了这个[deep]参数来诠释这个深浅拷贝,浅拷贝只复制基本类型,而引用类型是只是拷贝了一个指针,指向同一个引用类型,而深拷贝不仅复制一份基本类型,还在堆内存空间中重新拷贝出一份引用类型,并使用指针指向这个引用类型 >>> 如果不清楚深浅拷贝的可以看这篇文章;
那什么是基本类型,什么是引用类型呢?这里就简单说一下,基本类型有undefinded,null,number,string,boolean,symbol(ECMAScript 2016新增)
;引用类型:Object,Array,Function,Date,RegExp
【需要详细了解的看这篇文章
js的基本类型和引用类型】
现在我们来看代码,看看深浅拷贝拷贝了什么:
/* [deep]参数为false时为浅拷贝 */
var obj1 = {
name: "蔡徐坤",
age: 24,
sex: "男",
pet:{
name: "小鸡",
age: 3,
hobby: "打篮球"
}
};
var obj2 = {
name:"老蔡",
age: 24,
pet:{
name: "小美",
age: 5,
color: "绿色"
}
};
var obj = $.extend(false,{},obj1,obj2);
console.log("扩展结果:",obj,obj1,obj2);
/* [deep]参数为true时为深拷贝 */
var obj1 = {
name: "蔡徐坤",
age: 24,
sex: "男",
pet:{
name: "小鸡",
age: 3,
hobby: "打篮球"
}
};
var obj2 = {
name:"老蔡",
age: 24,
pet:{
name: "小美",
age: 5,
color: "绿色"
}
};
var obj = $.extend(true,{},obj1,obj2);
console.log("扩展结果:",obj,obj1,obj2);
简述一下上图的两个对象,他们各自都有自己的基本类型和引用类型pet
,并且两个引用类型pet都有特有的键值对hobby
和color
,那我们看看[deep]参数不同时输出的扩展对象obj结果图:
从对比图可以知道,[deep]为true时它会拷贝被拷贝对象里不同的引用类型键值对,obj拥有了obj1,obj2特有的键值对hobby
和color
,而[deep]为false时是不会这样的,最终的obj拷贝的是以最后一个被拷贝对象obj2里面的引用类型;
结论:[deep]为true时,会递归复制参与拷贝对象的引用类型;而为false就为扩展对象与最后一个被拷贝对象共享引用类型;
④ 既然知道深浅拷贝拷贝对应的类型结果,那还可不可以再证明一下扩展对象就是深/浅拷贝出来的结果?
这里就简要说明一下,首先深浅拷贝,对基本类型(值类型)的复制都是在栈内存建立一个新的内存空间,并且这两者互不干扰,都为独立空间;而对引用类型的复制,两者都会在栈内存中开辟引用变量存储在栈中的是指向堆中的数组或者对象的指针地址,而唯一的区别就是,浅拷贝在复制引用变量时不会再堆中开辟空间,而是用栈中复制出来的指针去指向同一个引用变量;而深拷贝则会在堆内存中开辟一个空间存放复制的引用变量,并将栈中的指针指向这个新开辟的空间;
那两者会导致什么不同的后果呢?我们来看代码(说明一下,代码对象obj1,obj2都不变,跟③中的一样,所以这里就写出新增的代码,小伙伴要试验的话,就直接把代码分别粘贴到③中代码段下面即可):
var obj = $.extend(false,{},obj1,obj2);
console.log("扩展结果:",obj,obj1,obj2);
obj2.name = "徐坤";
obj2.pet.sex = "雌性";
obj2.pet.name = "佩奇";
console.log("浅拷贝:",obj,obj2);
var obj = $.extend(true,{},obj1,obj2);
console.log("扩展结果:",obj,obj1,obj2);
obj2.name = "徐坤";
obj2.pet.sex = "雌性";
obj2.pet.name = "佩奇";
console.log("深拷贝:",obj,obj2);
简述一下上面的代码,就是修改最后一个被拷贝对象obj2中的基本类型name
,在引用类型pet
中添加一个pet.sex
键值对,和修改pet.name
的值,最后来对比一下扩展后的obj内部是怎样的:
从上图可知道,首先无论深浅拷贝,修改了obj2的基本类型name
,是不会影响obj的,这就是上面说的基本类型的复制是两者互不干扰,都为独立空间
;而不同的是,浅拷贝修改的引用类型也会修改obj里面的引用类型,这是为什么?这不就是上面说的浅拷贝只是复制了指向这个堆中引用变量的指针地址,但obj2,obj的指针指向还是堆内存中同一个引用变量,那么无论两者谁动了这个引用变量,两者都会变;但深拷贝不同,它在堆中开辟了一个新的空间内存储存了这个复制出来的引用变量,并且将栈中的指针地址指向这个新的引用变量,所以即使obj2修改了引用变量里面的内容也是修改obj2的,是不会影响obj的引用变量;
结论:浅拷贝只是复制了指针地址,但指向不变;深拷贝复制的引用变量储存为一个新的堆空间,并且更改了指针指向;这也是深浅拷贝的重要区别特点
结语
好了,$.extend这个方法就告一段落了,文中涉及到的基本类型和引用类型
和js的深浅拷贝
感兴趣的可以看看哈,希望可以帮助到你,本人小菜,文中如果有错误的描述,欢迎指正,谢谢~
【如转载本文内容 请注明本文地址】:https://blog.csdn.net/Umbrella_Um/article/details/97622019