jQuery的extend方法仅仅是字面意思上的扩展吗?

  jQuery中extend的使用方式大多是这样的:

    jQuery.extend({// Unique for each copy of jQuery on the pageexpando: "jQuery" + (version + Math.random()).replace(/\D/g, ""),// Assume jQuery is ready without the ready moduleisReady: true,error: function (msg) {throw new Error(msg);},})

  jQuery几乎在每一部分模块代码的下方,都会加上这样的一段代码,来添加操作该模块的属性和方法。

  如果去搜索jQuery.extend会发现,这个函数还可以这么用:

 var udataCur = jQuery.extend({}, udataOld);var anim = Animation(this, jQuery.extend({}, prop), optall);

  这样的使用方法,可不太像是添加扩展了。一个函数不只能实现一个功能?不如去看看,函数内部是怎么实现的,以及这个函数到底能用来干什么。

.extend源码:

    jQuery.extend = jQuery.fn.extend = function () {var options, name, src, copy, copyIsArray, clone,target = arguments[0] || {},i = 1,length = arguments.length,deep = false;// Handle a deep copy situationif (typeof target === "boolean") {deep = target;// Skip the boolean and the targettarget = arguments[i] || {};i++;}// Handle case when target is a string or something (possible in deep copy)if (typeof target !== "object" && !isFunction(target)) {target = {};}// Extend jQuery itself if only one argument is passedif (i === length) {target = this;i--;}for (; i < length; i++) {// Only deal with non-null/undefined valuesif ((options = arguments[i]) != null) {// Extend the base objectfor (name in options) {copy = options[name];// Prevent Object.prototype pollution// Prevent never-ending loopif (name === "__proto__" || target === copy) {debuggercontinue;}// Recurse if we're merging plain objects or arraysif (deep && copy && (jQuery.isPlainObject(copy) ||(copyIsArray = Array.isArray(copy)))) {src = target[name];// Ensure proper type for the source valueif (copyIsArray && !Array.isArray(src)) {clone = [];} else if (!copyIsArray && !jQuery.isPlainObject(src)) {clone = {};} else {// clone = src = 1clone = src;}copyIsArray = false;// Never move original objects, clone themtarget[name] = jQuery.extend(deep, clone, copy);// Don't bring in undefined values} else if (copy !== undefined) {target[name] = copy;}}}}// Return the modified objectreturn target;};

  好家伙,72行代码实现了一个函数,看看里面都写了点儿啥。

  首先,这个函数并没有指定入参,而是通过arguments加下标的形式,来动态取参数,从函数内部的注解中也能看出些端倪,注释中有提到 Handle a deep copy situation 即 处理深拷贝的场景,那么目前可知,这个函数,除了能为jQuery本身提供相应模块的扩展, 还可以对对象进行拷贝

   代码最开始部分定义了函数中用到的变量:

        var options, name, src, copy, copyIsArray, clone,// 传入的第一个参数,如果不存在,则默认为{}target = arguments[0] || {},i = 1,// 传参个数length = arguments.length,// 是否为深拷贝操作,默认为falsedeep = false;

   接下来是一些容错和函数应用何种场景的判断

        // 如果首个参数为boolean类型,则代表该函数用于对象的深拷贝if (typeof target === "boolean") {deep = target;// 直接取第二个参数,作为拷贝操作的目标对象target = arguments[i] || {};// 指针后移一位i++;}// 处理传参不符合要求的情况if (typeof target !== "object" && !isFunction(target)) {target = {};}// 如果只传递了一个参数,则视为扩展jQueryif (i === length) {target = this;i--;}w

   再往下,就是函数处理拷贝的相关操作了:

        for (; i < length; i++) {// 跳过为空的情况if ((options = arguments[i]) != null) {// Extend the base objectfor (name in options) {copy = options[name];//源码里说是防止污染原型链同时规避调用自身造成的死循环,但是// 打上debugger后,这里并没有被执行过,可能是出于严谨考虑吧if (name === "__proto__" || target === copy) {continue;}// Recurse if we're merging plain objects or arraysif (deep && copy && (jQuery.isPlainObject(copy) ||(copyIsArray = Array.isArray(copy)))) {src = target[name];// Ensure proper type for the source valueif (copyIsArray && !Array.isArray(src)) {clone = [];} else if (!copyIsArray && !jQuery.isPlainObject(src)) {clone = {};} else {clone = src;}copyIsArray = false;// Never move original objects, clone themtarget[name] = jQuery.extend(deep, clone, copy);// Don't bring in undefined values} else if (copy !== undefined) {// 这里说一下,如果是扩展的应用场景,那么,之前已经将// this指向了target,所以,这一步在扩展中就相当于// jQuery[name] = copytarget[name] = copy;}}}}

   说一下有关深浅拷贝的概念:
    浅拷贝,只复制对象内部的基本类型数据,如果对象内部还有对象,则新旧对象共享同一个对象引用
    深拷贝,是完全复制一个新对象出来,两个对象间没有任何联系。
     写个例子对比一下:

//浅拷贝
let obj1 = {a: 1, b: {c: 2}};  
let obj2 = Object.assign({}, obj1); obj2.a = 'k'
obj2.b.c = 3
console.log(obj1) //{a: 1, b: {c: 3}}// obj1经由 Object.assign 生成了一个自身的浅拷贝对象 obj2
// 当修改obj2的a属性时,原对象obj1的a属性不会受到影响,但是
// 修改obj2的b.c属性时,obj1的b.c属性也相应的发生了变化。
// 这就是浅拷贝只能复制基础属性,无法复制对象内引用的含义
//深拷贝let obj1 = {a: 1, b: {c: 2}};let clone = function () {let src = arguments[0]let target = {}for (const name in src) {if (typeof src[name] === 'object') {src = src[name]target[name] = clone(src)} else {target[name] = src[name]}}return target}let obj2 = clone(obj1)obj2.a = 'k'obj2.b.c = 3console.log(obj1) //{a: 1, b: {c: 2}}// 最终的运行结果,可以看到,修改深拷贝后的对象基础数据和引用
// 都不会对原始数据产生影响

   了解深浅拷贝的概念后,继续回到源代码,在处理拷贝的开始,有一个for循环,执行条件为 i<length 这样设计,可以确保无论是扩展还是拷贝的哪一种场景,最终的处理逻辑都放在这个循环中去执行,保证代码的逻辑统一,如果后续这个函数的参数继续增加,这样处理也就留出了可扩展的空间。

    // 判断当前是否为深拷贝场景,同时参数需要满足条件:纯对象或数组if (deep && copy && (jQuery.isPlainObject(copy) ||(copyIsArray = Array.isArray(copy)))) {src = target[name];// Ensure proper type for the source valueif (copyIsArray && !Array.isArray(src)) {clone = [];;} else if (!copyIsArray && !jQuery.isPlainObject(src)) {clone = {};} else {clone = src}copyIsArray = false;// Never move original objects, clone them// 递归处理,直到需要拷贝的属性不再是对象或数组target[name] = jQuery.extend(deep, clone, copy);// Don't bring in undefined values} else if (copy !== undefined) {target[name] = copy;}

   jQuery设计的这个extend函数,通过arguments动态获取参数以及对不同传参类型的判断,来实现了对扩展和拷贝这两种应用场景的重载,其实也不应该算两种情况,因为本身扩展就是一种拷贝行为。

   上面代码中有两个jQuery提供的工具函数,正好也看看这两个函数是如何实现的

isFunction

    var isFunction = function isFunction(obj) {// Support: Chrome <=57, Firefox <=52// In some browsers, typeof returns "function" for HTML <object> elements// (i.e., `typeof document.createElement( "object" ) === "function"`).// We don't want to classify *any* DOM node as a function.// Support: QtWeb <=3.8.5, WebKit <=534.34, wkhtmltopdf tool <=0.12.5// Plus for old WebKit, typeof returns "function" for HTML collections// (e.g., `typeof document.getElementsByTagName("div") === "function"`). (gh-4756)return typeof obj === "function" && typeof obj.nodeType !== "number" &&typeof obj.item !== "function";};// jQuery判断传参是否为一个function类型的工具函数,在这里框架做了很多的兼容,例如
// 在有些浏览器中 <object> 元素 会被当成一个function
// 老旧版本的WebKit内核会将HTML元素集合当成function

isPlainObject

        isPlainObject: function (obj) {var proto, Ctor;// Detect obvious negatives// Use toString instead of jQuery.type to catch host objectsif (!obj || toString.call(obj) !== "[object Object]") {return false;}proto = getProto(obj);// Objects with no prototype (e.g., `Object.create( null )`) are plainif (!proto) {return true;}// Objects with prototype are plain iff they were constructed by a global Object functionCtor = hasOwn.call(proto, "constructor") && proto.constructor;return typeof Ctor === "function" && fnToString.call(Ctor) === ObjectFunctionString;},

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/36954.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

存储管理(三):分区表

什么是分区表 假设存在表t&#xff1a; CREATETABLE t (ftimedatetime NOT NULL,c int(11) DEFAULT NULL,KEY (ftime) )ENGINEInnoDB DEFAULT CHARSETlatin1 PARTITION BY RANGE (YEAR(ftime)) (PARTITION p_2017 VALUES LESS THAN (2017) ENGINE InnoDB,PARTITION p_2018 VA…

golang 获取系统的主机 CPU 内存 磁盘等信息

golang 获取系统的主机 CPU 内存 磁盘等信息 要求 需要go1.18或更高版本 官方地址&#xff1a;https://github.com/shirou/gopsutil 使用 #下载包 go get github.com/shirou/gopsutil/v3/cpu go get github.com/shirou/gopsutil/v3/disk go get github.com/shirou/gopsuti…

tr、cut、split、grep -E

目录 tr命令&#xff1a;替换和删除 cut命令&#xff1a;快速裁剪 split命令&#xff1a;文件拆分 文件合并 面试题 1.现在有一个日志文件&#xff0c;有5个G&#xff0c;能不能快速的打开 2.cat合并和paste合并之间的区别&#xff1f; 3.统计当前主机的连接状态&#…

Hadoop3:MapReduce中的Reduce Join和Map Join

一、概念说明 学过MySQL的都知道&#xff0c;join和left join 这里的join含义和MySQL的join含义一样 就是对两张表的数据&#xff0c;进行关联查询 Hadoop的MapReduce阶段&#xff0c;分为2个阶段 一个Map&#xff0c;一个Reduce 那么&#xff0c;join逻辑&#xff0c;就可以…

前端开发的工厂设计模式

在前端开发中&#xff0c;工厂设计模式&#xff08;Factory Pattern&#xff09;是一种非常有用的设计模式&#xff0c;能够帮助我们在创建对象时减少代码的重复性和复杂性。 一、工厂设计模式概述 工厂设计模式是一种创建型设计模式&#xff0c;主要目的是定义一个用于创建对…

2024年建筑八大员(资料员)考试题库,省心高效,轻松通过!

1.插入的图片无法显示&#xff0c;或者显示失真&#xff0c;正确做法是&#xff08;&#xff09;。 A.插人图片是应选中【自动调整图片大小】 B.在下拉【菜单】中选中【按单元格式大小】插入 C.在【格式】下拉中【图片】处打钩 D.在【属性】下拉中选中【工具显示】 答案&a…

机械培训元宇宙:开启未来教育与职业培训的新篇章

随着科技的飞速发展&#xff0c;特别是虚拟现实&#xff08;VR&#xff09;、增强现实&#xff08;AR&#xff09;和人工智能&#xff08;AI&#xff09;等先进技术的广泛应用&#xff0c;我们正逐渐步入一个全新的时代——元宇宙。在这个虚拟的、由无数个并行宇宙组成的世界中…

两张图片怎样拼在一起?将两张图片拼在一起的几种方法介绍

两张图片怎样拼在一起&#xff1f;拼接两张图片是一种常见的编辑技巧&#xff0c;能够将不同的视觉元素融合成一个整体&#xff0c;从而创造出更加生动和丰富的图像效果。无论是为了设计创意作品、制作社交媒体内容&#xff0c;还是简单地为个人相册增添趣味&#xff0c;掌握如…

Java锁

乐观锁 什么是乐观锁 每次去拿数据的时候都认为别人不会修改&#xff0c;更新的时候会判断别人是否更新过数据&#xff0c;通过版本来判断&#xff0c;如果数据被修改了就拒绝更新Java里面大量使用CAS&#xff0c;CAS就是属于乐观锁&#xff0c;性能较悲观锁有很大的提高。Atom…

Element-UI 并排显示多个 disabled按钮的时候, 不生效问题解决

目录 Element-UI 并排显示多个 disabled按钮的时候&#xff0c; 不生效问题解决 解决方法&#xff1a; 运行结果&#xff1a; Element-UI 并排显示多个 disabled按钮的时候&#xff0c; 不生效问题解决 解决方法&#xff1a; Element-UI 并排显示多个 disabled按钮的时候&a…

LeetCode.4寻找两个正序数组的中位数

问题描述 给定两个大小分别为 m 和 n 的正序&#xff08;从小到大&#xff09;数组 nums1 和 nums2。请你找出并返回这两个正序数组的中位数。 算法的时间复杂度应该为 O(log (mn)) 。 解题思路1 理解问题的关键是要意识到&#xff0c;对于一个已排序的数组或两个数组的合并…

hbase 优化节点进程停止方式

一、命令 /usr/local/fqlhadoop/hbase/bin/graceful_stop.sh 4.hadoop3.com日志&#xff1a; [biadmin4 ~]$ /usr/local/fqlhadoop/hbase/bin/graceful_stop.sh 4.hadoop3.com 2024-06-24T09:42:27 Disabling load balancer log4j:WARN No such property [maxBackupIndex] in…

spring boot 3.0.1多模块项目使用nacos动态配置

根pom文件增加&#xff0c;spring-cloud-alibaba包管理&#xff0c;注意版本spring-boot 3.0.3&#xff0c;spring-cloud-alibaba 2022.0.0.0-RC1 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0…

学习笔记——交通安全分析10

目录 前言 当天学习笔记整理 4信控交叉口交通安全分析 结束语 前言 #随着上一轮SPSS学习完成之后&#xff0c;本人又开始了新教材《交通安全分析》的学习 #整理过程不易&#xff0c;喜欢UP就点个免费的关注趴 #本期内容接上一期09笔记 当天学习笔记整理 4信控交叉口交…

我的创作纪念日学期总结

&#x1f525;个人主页&#xff1a; Forcible Bug Maker &#x1f525;专栏&#xff1a; 关于博主 目录 &#x1f308;前言&#x1f525;我的期末考试&#x1f525;我的学期总结&#x1f525;对未来的展望&#x1f308;结语 &#x1f308;前言 本篇博客主要内容&#xff1a;博…

归并排序和计数排序

目录 1.归并排序1.1递归1.1基本思想1.2算法描述1.3画图解释1.4代码实现 1.2非递归 2.计数排序2.1基本思想2.2算法描述3.画图解释 1.归并排序 1.1递归 1.1基本思想 归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法&#xff08;Divide and Conquer&#xf…

【C++】动态内存管理new和delete

文章目录 一、C的内存管理方式二、new和delete的用法1.操作内置类型2.操作自定义内置类型 三、new和delete的底层实现1.operator new和operator delete函数2.new和delete的实现原理 四、定位new表达式五、malloc/free和new/delete的区别 一、C的内存管理方式 之前在C语言的动态…

kafka(四)消息类型

一、同步消息 1、生产者 同步发送的意思就是&#xff0c;一条消息发送之后&#xff0c;会阻塞当前线程&#xff0c;直至返回 ack。 由于 send 方法返回的是一个 Future 对象&#xff0c;根据 Futrue 对象的特点&#xff0c;我们也可以实现同 步发送的效果&#xff0c;只需在调…

【数据结构】计数排序等排序

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &#x1f4e2;本文由 JohnKi 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f4e2;未来很长&#…

C 语言实例 - 查找数组中最大的元素值

查找数组中最大的元素值。 实例 1 #include <stdio.h>int main() {int array[10] {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};int loop, largest;largest array[0];for(loop 1; loop < 10; loop) {if( largest < array[loop] ) largest array[loop];}printf("最大…