jQuery源码阅读(八)---jQuery中的继承extend

2024-05-04 14:18

本文主要是介绍jQuery源码阅读(八)---jQuery中的继承extend,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

今天看了jQuery源码中关于extend函数的部分,这部分就相当于jQuery继承,后面在整理的过程中说明如何继承。
还是跟之前的分析方法一样,要分析一个函数的实现,首先得知道函数是干什么的,它的功能是啥。

extend方法应用

扩展插件

在jQuery的学习当中,我们学过如何去写一个插件,而且插件分全局插件和实例插件,即一种是直接挂载在jQuery上的,另一种是挂载在jQuery实例对象上的。
比如下面两种实现:
扩展全局插件:

$.extend({add: function(a, b){return a + b;}
});
$.add(4,9);           //返回13

对象插件:

$.fn.extend({add : function(a, b){return a + b;}
})
$().add(2,8)            //返回10

扩展对象

这也可以算是jQuery中实现继承的一种方式。

a = {name : 'liu'
}
b = {name: 'yang'
}
var res = $.extend(a, b)  
//res可以说是继承了a和b的属性和方法
默认浅拷贝,改变a.name不会影响b.nameaa = {name: {age: 20}
}
bb = {name: {age: 15}
}
$.extend(aa, bb)
//浅拷贝,只拷贝对象,不会把内部具体的属性也拷贝
//所以修改a.name.age会改变b.name.age
aa.name.age = 30;
//此时bb.name.age也是30//如果改用深拷贝的话
$.extend(true, aa, bb)
//aa和bb中的name是不同的对象,指向不同的内存区域
//因此改变aa.name.age不会影响bb.name.age

extend方法在扩展对象时,最前面可以传一个布尔值的参数true,表示扩展对象时使用深拷贝,即将所有层级的对象属性都进行拷贝。而不加布尔值的参数,则默认是浅拷贝,即不会复制内层级的属性和方法。

extend源码分析

jQuery.extend = jQuery.fn.extend = function() {};

首先,我想说的是 jQuery.extend和jQuery.fn.extend是同一份代码,也就是说 实现思路是一样的.那如何才能确定是在jQuery上扩展的,还是在jQuery实例对象上扩展的?

JS中有个this的概念,即指向当前的上下文。具体点来说.

//直接调用函数时
function a(){return this;
}a();                //返回的是window对象

这里写图片描述

//如果通过对象调函数
var obj = {b: function(){return this;}
}
obj.b();            //返回的是Object对象

这里写图片描述

所以如果$.extend(),this指向的是jQuery;,如果$.fn.extend()this指向jQuery.fn也就是jQuery.prototype,那么在原型上扩展一个方法,就相当于在jQuery实例中可以调用该方法,从而实现扩展的目的。

接着下面的源码:

    var options, name, src, copy, copyIsArray, clone,//从这块可以学习到,如果不确定函数中有多少个参数时,可以用arguments来访问。target = arguments[0] || {},//如果是深拷贝,target此时为true;//如果不是,target此时是要扩展的第一个参数;i = 1,length = arguments.length,deep = false;// 深拷贝的情况if ( typeof target === "boolean" ) {deep = target;target = arguments[1] || {};// 跳过true和要扩展的第一个参数i = 2;}//如果不是对象,不是函数,target设为空对象,以便和后面对象能够合并if ( typeof target !== "object" && !jQuery.isFunction(target) ) {target = {};}//如果只有一个参数,那么就认为这是扩展插件,所以target就是this对象。前面也讲了什么情况下,this是jQuery,什么情况下this是jQuery.fnif ( length === i ) {target = this;--i;     //这个时候就从第一个参数开始处理}for ( ; i < length; i++ ) {//如果是对象扩展并且是浅拷贝,那么i从1开始//如果是对象扩展并且是深拷贝,那么i从2开始//如果是插件扩展,那么i从0开始//前面已经处理好了if ( (options = arguments[ i ]) != null ) {for ( name in options ) {src = target[ name ];copy = options[ name ];//注意这部分,下面会讲到if ( target === copy ) {continue;}//如果是深拷贝,那么对象内层的每一级属性都要拷贝,所以是一个递归的过程if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {if ( copyIsArray ) {copyIsArray = false;clone = src && jQuery.isArray(src) ? src : [];} else {clone = src && jQuery.isPlainObject(src) ? src : {};}// Never move original objects, clone themtarget[ name ] = jQuery.extend( deep, clone, copy );} else if ( copy !== undefined ) {//如果不是深拷贝,就直接将name属性加到target对象里面了target[ name ] = copy;}}}}//最后返回扩展后的target对象;或者返回jQuery或者返回jQuery.fnreturn target;

下来缕一缕上面提到的

if ( target === copy ) {continue;
}

比如这么一种情况:

var obj = {age : 20
}
var obj1 = {age: obj
}
var res = $.extend(obj, obj1);

这种情况下,在extend函数内部,target为 obj = { age : 20 }, copy = options[‘age’] = obj = { age : 20 }
所以判断target和copy相等,就会continue,跳过该次循环,那为什么要这样做呢?
我们先把if ( target === copy ) { continue; }注释掉,看结果是什么?
这里写图片描述
可以看到,返回的是一个含有一个name属性的对象,而name属性又指向该对象,这样无限循环下去了。为什么会出现这种情况呢?
因为如果去掉continue的话,会继续后面的执行,即

target[ name ] = copy;

在这句执行之前,target指向一个Object对象,copy也是指向该对象,那么对target的修改也会影响copy对象,所以target.name修改为copy,相当于copy.name也修改为copy,这样就形成了无限循环的对象,这样实际上没有什么意义,所以jQuery避免了这种情况。可见,jQuery各方面的考虑是非常全面。希望能学到更多,理解更深刻!

这篇关于jQuery源码阅读(八)---jQuery中的继承extend的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/959397

相关文章

Python实现无痛修改第三方库源码的方法详解

《Python实现无痛修改第三方库源码的方法详解》很多时候,我们下载的第三方库是不会有需求不满足的情况,但也有极少的情况,第三方库没有兼顾到需求,本文将介绍几个修改源码的操作,大家可以根据需求进行选择... 目录需求不符合模拟示例 1. 修改源文件2. 继承修改3. 猴子补丁4. 追踪局部变量需求不符合很

Vue中组件之间传值的六种方式(完整版)

《Vue中组件之间传值的六种方式(完整版)》组件是vue.js最强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用,针对不同的使用场景,如何选择行之有效的通信方式... 目录前言方法一、props/$emit1.父组件向子组件传值2.子组件向父组件传值(通过事件形式)方

css中的 vertical-align与line-height作用详解

《css中的vertical-align与line-height作用详解》:本文主要介绍了CSS中的`vertical-align`和`line-height`属性,包括它们的作用、适用元素、属性值、常见使用场景、常见问题及解决方案,详细内容请阅读本文,希望能对你有所帮助... 目录vertical-ali

浅析CSS 中z - index属性的作用及在什么情况下会失效

《浅析CSS中z-index属性的作用及在什么情况下会失效》z-index属性用于控制元素的堆叠顺序,值越大,元素越显示在上层,它需要元素具有定位属性(如relative、absolute、fi... 目录1. z-index 属性的作用2. z-index 失效的情况2.1 元素没有定位属性2.2 元素处

Python实现html转png的完美方案介绍

《Python实现html转png的完美方案介绍》这篇文章主要为大家详细介绍了如何使用Python实现html转png功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 1.增强稳定性与错误处理建议使用三层异常捕获结构:try: with sync_playwright(

Vue 调用摄像头扫描条码功能实现代码

《Vue调用摄像头扫描条码功能实现代码》本文介绍了如何使用Vue.js和jsQR库来实现调用摄像头并扫描条码的功能,通过安装依赖、获取摄像头视频流、解析条码等步骤,实现了从开始扫描到停止扫描的完整流... 目录实现步骤:代码实现1. 安装依赖2. vue 页面代码功能说明注意事项以下是一个基于 Vue.js

CSS @media print 使用详解

《CSS@mediaprint使用详解》:本文主要介绍了CSS中的打印媒体查询@mediaprint包括基本语法、常见使用场景和代码示例,如隐藏非必要元素、调整字体和颜色、处理链接的URL显示、分页控制、调整边距和背景等,还提供了测试方法和关键注意事项,并分享了进阶技巧,详细内容请阅读本文,希望能对你有所帮助...

Spring 中 BeanFactoryPostProcessor 的作用和示例源码分析

《Spring中BeanFactoryPostProcessor的作用和示例源码分析》Spring的BeanFactoryPostProcessor是容器初始化的扩展接口,允许在Bean实例化前... 目录一、概览1. 核心定位2. 核心功能详解3. 关键特性二、Spring 内置的 BeanFactory

Nginx实现前端灰度发布

《Nginx实现前端灰度发布》灰度发布是一种重要的策略,它允许我们在不影响所有用户的情况下,逐步推出新功能或更新,通过灰度发布,我们可以测试新版本的稳定性和性能,下面就来介绍一下前端灰度发布的使用,感... 目录前言一、基于权重的流量分配二、基于 Cookie 的分流三、基于请求头的分流四、基于请求参数的分

基于Canvas的Html5多时区动态时钟实战代码

《基于Canvas的Html5多时区动态时钟实战代码》:本文主要介绍了如何使用Canvas在HTML5上实现一个多时区动态时钟的web展示,通过Canvas的API,可以绘制出6个不同城市的时钟,并且这些时钟可以动态转动,每个时钟上都会标注出对应的24小时制时间,详细内容请阅读本文,希望能对你有所帮助...