深入理解jquery中extend的实现
发布时间 - 2026-01-10 22:00:38 点击率:次Jquery的扩展方法extend是我们在写插件的过程中常用的方法,该方法有一些重载原型,下面来看看详细的介绍吧。

通常我们使用jquery的extend时,大都是为了实现默认字段的覆盖,即若传入某个字段的值,则使用传入值,否则使用默认值。
如下面的代码:
function getOpt(option){
var _default = {
name : 'wenzi',
age : '25',
sex : 'male'
}
$.extend(_default, option);
return _default;
}
getOpt(); // {name: "wenzi", age: "25", sex: "male"}
getOpt({name:'bing'}); // {name: "bing", age: "25", sex: "male"}
getOpt({name:'bing', age:36, sex:'female'}); // {name: "bing", age: 36, sex: "female"}
那现在我们就得需要知道这个extend具体是怎么实现的了,除了实现上面的功能,还有其他作用么?那肯定是有的啦,否则我也不会问那句话了((⊙﹏⊙)b)。我们先来看看extend主要有哪些功能,然后再看实现这些功能的原理。
1. extend能实现的功能
其实从extend的含义里,我们就能知道extend是做什么的了。extend翻译成汉语后就是:延伸、扩展、推广。
1.1 将两个或更多对象的内容合并到第一个对象
我们来看看$.extend()提供的参数:jQuery.extend( target [, object1 ] [, objectN ] ),extend方法需要至少传入一个参数,第一个必需,后面的都是可选参数。若传给extend是两个或两个以上的参数都是对象类型,那么就会把后面所有对象的内容合并给target(第一个对象)上。
我们再来看看上面的例子:
function getOpt(option){
var _default = {
name : 'wenzi',
age : '25',
sex : 'male'
}
`$.extend(_default, option);`
return _default;
}
$.extend()中接收了两个参数_default和option,那么extend方法执行时,就会把option对象上字段的值全给了_default。于是_default上设置的默认值就会被option上的值覆盖。当然,若option上没有这个字段,就不会覆盖_default上字段的值。
上面函数中的extend,只是传入了两个参数,那传的参数再更多一些呢:
function getOpt(target, obj1, obj2, obj3){
$.extend(target, obj1, obj2, obj3);
return target;
}
var _default = {
name : 'wenzi',
age : '25',
sex : 'male'
}
var obj1 = {
name : 'obj1'
}
var obj2 = {
name : 'obj2',
age : '36'
}
var obj3 = {
age : '67',
sex : {'error':'sorry, I dont\'t kown'}
}
getOpt(_default, obj1, obj2, obj3); // {name: "obj2", age: "67", sex: {error: "sorry, I dont't kown"}}
这里我们传入了4个参数,然后getOpt()返回第一个参数的值。从运行的得到结果我们可以看到,属性值永远是最后一个属性的值。
还有很重要的一点,$.extend()其实是有返回值的,返回的就是修改后的第一个参数的值。如我们可以把上面的函数修改成这样:
function getOpt(target, obj1, obj2, obj3){
var result = $.extend(target, obj1, obj2, obj3);
return result; // // result即修改后的target值
}
若我们传入的参数不想被修改,我们可以用一个空对象来作为第一个参数,然后获取$.extend()的返回值:
function getOpt(target, obj1, obj2, obj3){
var result = $.extend({}, target, obj1, obj2, obj3);
return result; // // result即为{}修改后的值
}
1.2 为JQUERY扩展方法或属性
刚才我们在1.1中讲的$.extend()的例子都是传了两个或两个以上的参数,但其实只有一个参数是必须的。若只传一个参数会怎样呢。
如果只有一个参数提供给$.extend() ,这意味着目标参数被省略。在这种情况下,jQuery对象本身被默认为目标对象。这样,我们可以在jQuery的命名空间下添加新的功能。这对于插件开发者希望向 jQuery 中添加新函数时是很有用的。
$.extend({
_name : 'wenzi',
_getName : function(){
return this._name;
}
})
$._name; // wenzi
$._getName(); // wenzi
这样我们就为jQuery扩展了_name属性和_getName方法。
1.3 深度拷贝和浅度拷贝
针对什么是深度拷贝,什么是浅度拷贝,我们先来看一个简单的例子。
var obj = {name:'wenzi', sex:'male'};
var obj1 = obj; // 赋值
obj1.name = 'bing';
console.log(obj.name); // bing
我们修改了obj1中的name值,结果obj中的值也跟着发生了变化,这是为什么呢。其实这就是浅度拷贝:这仅仅是将obj对象的引用地址简单的复制了一份给予变量 obj1,而并不是将真正的对象克隆了一份,因此obj和obj1指向的都是同一个地址。当修改obj1的属性或给obj1添加新属性时,obj都会受到影响。
可是如果变量的值不是对象和数组,修改后面的变量是不会影响到前面的变量:
var s = 'hello'; var t = s; t = 'world'; console.log(s); // hello
那么深度拷贝就不是拷贝引用地址,而是实实在在的复制一份新对象给新的变量。 在上面使用$.extend()中,都是使用的浅度拷贝,因此若后面的参数值是object类型或array类型,修改_default(target)的值,就会影响后面参数的值。
如我们使用getOpt(_default, obj1, obj2, obj3);得到的_default值是{name: “obj2”, age: “67”, sex: {error: “sorry, I dont't kown”}},可是若:
_default.sex.error = 'hello world';
那么obj3.sex.error也会跟着修改,因为obj3.sex是一个object类型。
不过$.extend()也提供了深度拷贝的方法:jQuery.extend( [deep ], target, object1 [, objectN ] ) 。若第一个参数是boolean类型,且值是true,那么就会把第二个参数作为目标参数进行合并。
var obj = {name:'wenzi', score:80};
var obj1 = {score:{english:80, math:90}}
$.extend(true, obj, obj1);
obj.score.english = 10;
console.log(obj.score.english); // 10
console.log(obj1.score.english); // 80
执行后我们发现,无论怎么修改obj.score里的值,都不会影响到obj1.score了。
2. jQuery中extend实现原理
其实不看源码,对extend大致的过程应该也是了解的:对后一个参数进行循环,然后把后面参数上所有的字段都给了第一个字段,若第一个参数里有相同的字段,则进行覆盖操作,否则就添加一个新的字段。
下面是jQuery中关于extend的源码,我就在源码上进行注释讲解了,随后再在后面进行总结:
// 为与源码的下标对应上,我们把第一个参数称为`第0个参数`,依次类推
jQuery.extend = jQuery.fn.extend = function() {
var options, name, src, copy, copyIsArray, clone,
target = arguments[0] || {}, // 默认第0个参数为目标参数
i = 1, // i表示从第几个参数凯斯想目标参数进行合并,默认从第1个参数开始向第0个参数进行合并
length = arguments.length,
deep = false; // 默认为浅度拷贝
// 判断第0个参数的类型,若第0个参数是boolean类型,则获取其为true还是false
// 同时将第1个参数作为目标参数,i从当前目标参数的下一个
// Handle a deep copy situation
if ( typeof target === "boolean" ) {
deep = target;
// Skip the boolean and the target
target = arguments[ i ] || {};
i++;
}
// 判断目标参数的类型,若目标参数既不是object类型,也不是function类型,则为目标参数重新赋值
// Handle case when target is a string or something (possible in deep copy)
if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
target = {};
}
// 若目标参数后面没有参数了,如$.extend({_name:'wenzi'}), $.extend(true, {_name:'wenzi'})
// 则目标参数即为jQuery本身,而target表示的参数不再为目标参数
// Extend jQuery itself if only one argument is passed
if ( i === length ) {
target = this;
i--;
}
// 从第i个参数开始
for ( ; i < length; i++ ) {
// 获取第i个参数,且该参数不为null和undefind,在js中null和undefined,如果不区分类型,是相等的,null==undefined为true,
// 因此可以用null来同时过滤掉null和undefind
// 比如$.extend(target, {}, null);中的第2个参数null是不参与合并的
// Only deal with non-null/undefined values
if ( (options = arguments[ i ]) != null ) {
// 使用for~in获取该参数中所有的字段
// Extend the base object
for ( name in options ) {
src = target[ name ]; // 目标参数中name字段的值
copy = options[ name ]; // 当前参数中name字段的值
// 若参数中字段的值就是目标参数,停止赋值,进行下一个字段的赋值
// 这是为了防止无限的循环嵌套,我们把这个称为,在下面进行比较详细的讲解
// Prevent never-ending loop
if ( target === copy ) {
continue;
}
// 若deep为true,且当前参数中name字段的值存在且为object类型或Array类型,则进行深度赋值
// Recurse if we're merging plain objects or arrays
if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
// 若当前参数中name字段的值为Array类型
// 判断目标参数中name字段的值是否存在,若存在则使用原来的,否则进行初始化
if ( copyIsArray ) {
copyIsArray = false;
clone = src && jQuery.isArray(src) ? src : [];
} else {
// 若原对象存在,则直接进行使用,而不是创建
clone = src && jQuery.isPlainObject(src) ? src : {};
}
// 递归处理,此处为2.2
// Never move original objects, clone them
target[ name ] = jQuery.extend( deep, clone, copy );
// deep为false,则表示浅度拷贝,直接进行赋值
// 若copy是简单的类型且存在值,则直接进行赋值
// Don't bring in undefined values
} else if ( copy !== undefined ) {
// 若原对象存在name属性,则直接覆盖掉;若不存在,则创建新的属性
target[ name ] = copy;
}
}
}
}
// 返回修改后的目标参数
// Return the modified object
return target;
};
源码分析完了,下面我们来讲解下源码中存在的几个难点和重点。
2.1 若参数中字段的值就是目标参数,停止赋值
在源码中进行了一下这样的判断:
// Prevent never-ending loop
if ( target === copy ) {
continue;
}
为什么要有这样的判断,我们来看一个简单的例子,如果没有这个判断会怎么样:
var _default = {name : 'wenzi'};
var obj = {name : _default}
$.extend(_default, obj);
console.log(_default);
输出的_default是什么呢:
_default = {name : _default};
_default是object类型,里面有个字段name,值是_default,而_default是object类型,里面有个字段name,值是_default……,无限的循环下去。于是jQuery中直接不进行操作,跳过这个字段,进行下一个字段的操作。
2.2 深度拷贝时进行递归处理
我们在前面稍微的讲解了一下,变量值为简单类型(如number, string, boolean)进行赋值时是不会影响上一个变量的值的,因此,如果当前字段的值为Object或Array类型,需要对其进行拆分,直到字段的值为简单类型(如number, string, boolean)时才进行赋值操作。
3. $.extend()与$.fn.extend()
上面讲解的全都是$.extend(),根本就没讲$.fn.extend() 。可是,你有没有发现一个细节,在这段代码的第一行是怎么写的:
jQuery.extend = jQuery.fn.extend = function(){}
也就是说$.extend()与$.fn.extend()共用的是同一个函数体,所有的操作都是一样的,只不过两个extend使用的对象不同罢了:$.extend()是在jQuery($)上进行操作的;而$.fn.extend()是在jQuery对象上进行操作的,如$(‘div').extend()
4. 总结
这就是jQuery中extend的实现,以后若我们需要用到上面的功能时,除了使用$.extend() ,我们也可以在不引入jQuery框架的情况下,自己写一个简单的extend()来实现上面的功能。
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。
# jquery
# extend
# 实现
# extend方法
# jquery中extend
# jQuery插件开发的两种方法及$.fn.extend的详解
# jQuery中extend()和fn.extend()方法详解
# 浅谈jquery.fn.extend与jquery.extend区别
# jQuery $.extend()用法总结
# jquery的extend和fn.extend的使用说明
# 深入理解jquery的$.extend()、$.fn和$.fn.extend()
# 第一个
# 都是
# 递归
# 值为
# 会把
# 这是
# 几个
# 就会
# 是在
# 有个
# 这就是
# 是怎么
# 可以用
# 我们可以
# 给了
# 来看看
# 只有一个
# 什么呢
# 影响到
# 即为
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
Laravel如何发送邮件_Laravel Mailables构建与发送邮件的简明教程
网站设计制作书签怎么做,怎样将网页添加到书签/主页书签/桌面?
齐河建站公司:营销型网站建设与SEO优化双核驱动策略
Claude怎样写约束型提示词_Claude约束提示词写法【教程】
Laravel如何实现模型的全局作用域?(Global Scope示例)
如何快速配置高效服务器建站软件?
Laravel PHP版本要求一览_Laravel各版本环境要求对照
如何基于云服务器快速搭建网站及云盘系统?
高性能网站服务器部署指南:稳定运行与安全配置优化方案
Laravel如何配置.env文件管理环境变量_Laravel环境变量使用与安全管理
1688铺货到淘宝怎么操作 1688一键铺货到自己店铺详细步骤
浅析上传头像示例及其注意事项
Laravel怎么实现验证码功能_Laravel集成验证码库防止机器人注册
百度浏览器网页无法复制文字怎么办 百度浏览器复制修复
猎豹浏览器开发者工具怎么打开 猎豹浏览器F12调试工具使用【前端必备】
edge浏览器无法安装扩展 edge浏览器插件安装失败【解决方法】
如何快速辨别茅台真假?关键步骤解析
网站制作大概要多少钱一个,做一个平台网站大概多少钱?
详解Android——蓝牙技术 带你实现终端间数据传输
高防服务器租用如何选择配置与防御等级?
网站制作价目表怎么做,珍爱网婚介费用多少?
在centOS 7安装mysql 5.7的详细教程
谷歌浏览器下载文件时中断怎么办 Google Chrome下载管理修复
uc浏览器二维码扫描入口_uc浏览器扫码功能使用地址
Laravel Docker环境搭建教程_Laravel Sail使用指南
Midjourney怎样加参数调细节_Midjourney参数调整技巧【指南】
Edge浏览器怎么启用睡眠标签页_节省电脑内存占用优化技巧
Laravel如何理解并使用服务容器(Service Container)_Laravel依赖注入与容器绑定说明
JavaScript如何实现类型判断_typeof和instanceof有什么区别
Laravel如何处理表单验证?(Requests代码示例)
UC浏览器如何切换小说阅读源_UC浏览器阅读源切换【方法】
php嵌入式断网后怎么恢复_php检测网络重连并恢复硬件控制【操作】
手机软键盘弹出时影响布局的解决方法
Laravel如何为API编写文档_Laravel API文档生成与维护方法
详解阿里云nginx服务器多站点的配置
Laravel怎么生成二维码图片_Laravel集成Simple-QrCode扩展包与参数设置【实战】
Laravel如何处理文件下载请求?(Response示例)
详解jQuery中的事件
JavaScript 输出显示内容(document.write、alert、innerHTML、console.log)
Laravel模型关联查询教程_Laravel Eloquent一对多关联写法
佛山企业网站制作公司有哪些,沟通100网上服务官网?
DeepSeek是免费使用的吗 DeepSeek收费模式与Pro版本功能详解
如何实现建站之星域名转发设置?
如何在IIS中新建站点并解决端口绑定冲突?
在线制作视频网站免费,都有哪些好的动漫网站?
Laravel如何优化应用性能?(缓存和优化命令)
如何快速搭建个人网站并优化SEO?
如何用西部建站助手快速创建专业网站?
WordPress 子目录安装中正确处理脚本路径的完整指南
Android使用GridView实现日历的简单功能

